source: josm/trunk/src/org/openstreetmap/josm/tools/PlatformHookWindows.java@ 12162

Last change on this file since 12162 was 12146, checked in by Don-vip, 7 years ago

remove symbol font entry, already defined

  • Property svn:eol-style set to native
File size: 36.5 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.tools;
3
4import static java.awt.event.InputEvent.ALT_DOWN_MASK;
5import static java.awt.event.InputEvent.CTRL_DOWN_MASK;
6import static java.awt.event.InputEvent.SHIFT_DOWN_MASK;
7import static java.awt.event.KeyEvent.VK_A;
8import static java.awt.event.KeyEvent.VK_C;
9import static java.awt.event.KeyEvent.VK_D;
10import static java.awt.event.KeyEvent.VK_DELETE;
11import static java.awt.event.KeyEvent.VK_DOWN;
12import static java.awt.event.KeyEvent.VK_ENTER;
13import static java.awt.event.KeyEvent.VK_ESCAPE;
14import static java.awt.event.KeyEvent.VK_F10;
15import static java.awt.event.KeyEvent.VK_F4;
16import static java.awt.event.KeyEvent.VK_LEFT;
17import static java.awt.event.KeyEvent.VK_NUM_LOCK;
18import static java.awt.event.KeyEvent.VK_PRINTSCREEN;
19import static java.awt.event.KeyEvent.VK_RIGHT;
20import static java.awt.event.KeyEvent.VK_SHIFT;
21import static java.awt.event.KeyEvent.VK_SPACE;
22import static java.awt.event.KeyEvent.VK_TAB;
23import static java.awt.event.KeyEvent.VK_UP;
24import static java.awt.event.KeyEvent.VK_V;
25import static java.awt.event.KeyEvent.VK_X;
26import static java.awt.event.KeyEvent.VK_Y;
27import static java.awt.event.KeyEvent.VK_Z;
28import static org.openstreetmap.josm.tools.I18n.tr;
29
30import java.awt.GraphicsEnvironment;
31import java.io.BufferedWriter;
32import java.io.File;
33import java.io.FileInputStream;
34import java.io.IOException;
35import java.io.OutputStream;
36import java.io.OutputStreamWriter;
37import java.io.Writer;
38import java.nio.charset.StandardCharsets;
39import java.nio.file.DirectoryStream;
40import java.nio.file.FileSystems;
41import java.nio.file.Files;
42import java.nio.file.Path;
43import java.security.InvalidKeyException;
44import java.security.KeyFactory;
45import java.security.KeyStore;
46import java.security.KeyStoreException;
47import java.security.MessageDigest;
48import java.security.NoSuchAlgorithmException;
49import java.security.NoSuchProviderException;
50import java.security.PublicKey;
51import java.security.SignatureException;
52import java.security.cert.Certificate;
53import java.security.cert.CertificateException;
54import java.security.cert.X509Certificate;
55import java.security.spec.InvalidKeySpecException;
56import java.security.spec.X509EncodedKeySpec;
57import java.util.ArrayList;
58import java.util.Arrays;
59import java.util.Collection;
60import java.util.Enumeration;
61import java.util.List;
62import java.util.Locale;
63import java.util.Properties;
64
65import javax.swing.JOptionPane;
66
67import org.openstreetmap.josm.Main;
68import org.openstreetmap.josm.data.Preferences;
69import org.openstreetmap.josm.io.CertificateAmendment.CertAmend;
70
71/**
72 * {@code PlatformHook} implementation for Microsoft Windows systems.
73 * @since 1023
74 */
75public class PlatformHookWindows implements PlatformHook {
76
77 /**
78 * Simple data class to hold information about a font.
79 *
80 * Used for fontconfig.properties files.
81 */
82 public static class FontEntry {
83 /**
84 * The character subset. Basically a free identifier, but should be unique.
85 */
86 @Preferences.pref
87 public String charset;
88
89 /**
90 * Platform font name.
91 */
92 @Preferences.pref
93 @Preferences.writeExplicitly
94 public String name = "";
95
96 /**
97 * File name.
98 */
99 @Preferences.pref
100 @Preferences.writeExplicitly
101 public String file = "";
102
103 /**
104 * Constructs a new {@code FontEntry}.
105 */
106 public FontEntry() {
107 // Default constructor needed for construction by reflection
108 }
109
110 /**
111 * Constructs a new {@code FontEntry}.
112 * @param charset The character subset. Basically a free identifier, but should be unique
113 * @param name Platform font name
114 * @param file File name
115 */
116 public FontEntry(String charset, String name, String file) {
117 this.charset = charset;
118 this.name = name;
119 this.file = file;
120 }
121 }
122
123 private static final byte[] INSECURE_PUBLIC_KEY = new byte[] {
124 0x30, (byte) 0x82, 0x1, 0x22, 0x30, 0xd, 0x6, 0x9, 0x2a, (byte) 0x86, 0x48,
125 (byte) 0x86, (byte) 0xf7, 0xd, 0x1, 0x1, 0x1, 0x5, 0x0, 0x3, (byte) 0x82, 0x1, 0xf, 0x0,
126 0x30, (byte) 0x82, 0x01, 0x0a, 0x02, (byte) 0x82, 0x01, 0x01, 0x00, (byte) 0x95, (byte) 0x95, (byte) 0x88,
127 (byte) 0x84, (byte) 0xc8, (byte) 0xd9, 0x6b, (byte) 0xc5, (byte) 0xda, 0x0b, 0x69, (byte) 0xbf, (byte) 0xfc,
128 0x7e, (byte) 0xb9, (byte) 0x96, 0x2c, (byte) 0xeb, (byte) 0x8f, (byte) 0xbc, 0x6e, 0x40, (byte) 0xe6, (byte) 0xe2,
129 (byte) 0xfc, (byte) 0xf1, 0x7f, 0x73, (byte) 0xa7, (byte) 0x9d, (byte) 0xde, (byte) 0xc7, (byte) 0x88, 0x57, 0x51,
130 (byte) 0x84, (byte) 0xed, (byte) 0x96, (byte) 0xfb, (byte) 0xe1, 0x38, (byte) 0xef, 0x08, 0x2b, (byte) 0xf3,
131 (byte) 0xc7, (byte) 0xc3, 0x5d, (byte) 0xfe, (byte) 0xf9, 0x51, (byte) 0xe6, 0x29, (byte) 0xfc, (byte) 0xe5, 0x0d,
132 (byte) 0xa1, 0x0d, (byte) 0xa8, (byte) 0xb4, (byte) 0xae, 0x26, 0x18, 0x19, 0x4d, 0x6c, 0x0c, 0x3b, 0x12, (byte) 0xba,
133 (byte) 0xbc, 0x5f, 0x32, (byte) 0xb3, (byte) 0xbe, (byte) 0x9d, 0x17, 0x0d, 0x4d, 0x2f, 0x1a, 0x48, (byte) 0xb7,
134 (byte) 0xac, (byte) 0xf7, 0x1a, 0x43, 0x01, (byte) 0x97, (byte) 0xf4, (byte) 0xf8, 0x4c, (byte) 0xbb, 0x6a, (byte) 0xbc,
135 0x33, (byte) 0xe1, 0x73, 0x1e, (byte) 0x86, (byte) 0xfb, 0x2e, (byte) 0xb1, 0x63, 0x75, (byte) 0x85, (byte) 0xdc,
136 (byte) 0x82, 0x6c, 0x28, (byte) 0xf1, (byte) 0xe3, (byte) 0x90, 0x63, (byte) 0x9d, 0x3d, 0x48, (byte) 0x8a, (byte) 0x8c,
137 0x47, (byte) 0xe2, 0x10, 0x0b, (byte) 0xef, (byte) 0x91, (byte) 0x94, (byte) 0xb0, 0x6c, 0x4c, (byte) 0x80, 0x76, 0x03,
138 (byte) 0xe1, (byte) 0xb6, (byte) 0x90, (byte) 0x87, (byte) 0xd9, (byte) 0xae, (byte) 0xf4, (byte) 0x8e, (byte) 0xe0,
139 (byte) 0x9f, (byte) 0xe7, 0x3a, 0x2c, 0x2f, 0x21, (byte) 0xd4, 0x46, (byte) 0xba, (byte) 0x95, 0x70, (byte) 0xa9, 0x5b,
140 0x20, 0x2a, (byte) 0xfa, 0x52, 0x3e, (byte) 0x9d, (byte) 0xd9, (byte) 0xef, 0x28, (byte) 0xc5, (byte) 0xd1, 0x60,
141 (byte) 0x89, 0x68, 0x6e, 0x7f, (byte) 0xd7, (byte) 0x9e, (byte) 0x89, 0x4c, (byte) 0xeb, 0x4d, (byte) 0xd2, (byte) 0xc6,
142 (byte) 0xf4, 0x2d, 0x02, 0x5d, (byte) 0xda, (byte) 0xde, 0x33, (byte) 0xfe, (byte) 0xc1, 0x7e, (byte) 0xde, 0x4f, 0x1f,
143 (byte) 0x9b, 0x6e, 0x6f, 0x0f, 0x66, 0x71, 0x19, (byte) 0xe9, 0x43, 0x3c, (byte) 0x83, 0x0a, 0x0f, 0x28, 0x21, (byte) 0xc8,
144 0x38, (byte) 0xd3, 0x4e, 0x48, (byte) 0xdf, (byte) 0xd4, (byte) 0x99, (byte) 0xb5, (byte) 0xc6, (byte) 0x8d, (byte) 0xd4,
145 (byte) 0xc1, 0x69, 0x58, 0x79, (byte) 0x82, 0x32, (byte) 0x82, (byte) 0xd4, (byte) 0x86, (byte) 0xe2, 0x04, 0x08, 0x63,
146 (byte) 0x87, (byte) 0xf0, 0x2a, (byte) 0xf6, (byte) 0xec, 0x3e, 0x51, 0x0f, (byte) 0xda, (byte) 0xb4, 0x67, 0x19, 0x5e,
147 0x16, 0x02, (byte) 0x9f, (byte) 0xf1, 0x19, 0x0c, 0x3e, (byte) 0xb8, 0x04, 0x49, 0x07, 0x53, 0x02, 0x03, 0x01, 0x00, 0x01
148 };
149
150 private static final String WINDOWS_ROOT = "Windows-ROOT";
151
152 @Override
153 public void afterPrefStartupHook() {
154 extendFontconfig("fontconfig.properties.src");
155 }
156
157 @Override
158 public void openUrl(String url) throws IOException {
159 Runtime.getRuntime().exec("rundll32 url.dll,FileProtocolHandler " + url);
160 }
161
162 @Override
163 public void initSystemShortcuts() {
164 // CHECKSTYLE.OFF: LineLength
165 //Shortcut.registerSystemCut("system:menuexit", tr("reserved"), VK_Q, CTRL_DOWN_MASK);
166 Shortcut.registerSystemShortcut("system:duplicate", tr("reserved"), VK_D, CTRL_DOWN_MASK); // not really system, but to avoid odd results
167
168 // Windows 7 shortcuts: http://windows.microsoft.com/en-US/windows7/Keyboard-shortcuts
169
170 // Shortcuts with setAutomatic(): items with automatic shortcuts will not be added to the menu bar at all
171
172 // Don't know why Ctrl-Alt-Del isn't even listed on official Microsoft support page
173 Shortcut.registerSystemShortcut("system:reset", tr("reserved"), VK_DELETE, CTRL_DOWN_MASK | ALT_DOWN_MASK).setAutomatic();
174
175 // Ease of Access keyboard shortcuts
176 Shortcut.registerSystemShortcut("microsoft-reserved-01", tr("reserved"), VK_PRINTSCREEN, ALT_DOWN_MASK | SHIFT_DOWN_MASK).setAutomatic(); // Turn High Contrast on or off
177 Shortcut.registerSystemShortcut("microsoft-reserved-02", tr("reserved"), VK_NUM_LOCK, ALT_DOWN_MASK | SHIFT_DOWN_MASK).setAutomatic(); // Turn Mouse Keys on or off
178 //Shortcut.registerSystemCut("microsoft-reserved-03", tr("reserved"), VK_U, );// Open the Ease of Access Center (TODO: Windows-U, how to handle it in Java ?)
179
180 // General keyboard shortcuts
181 //Shortcut.registerSystemShortcut("system:help", tr("reserved"), VK_F1, 0); // Display Help
182 Shortcut.registerSystemShortcut("system:copy", tr("reserved"), VK_C, CTRL_DOWN_MASK); // Copy the selected item
183 Shortcut.registerSystemShortcut("system:cut", tr("reserved"), VK_X, CTRL_DOWN_MASK); // Cut the selected item
184 Shortcut.registerSystemShortcut("system:paste", tr("reserved"), VK_V, CTRL_DOWN_MASK); // Paste the selected item
185 Shortcut.registerSystemShortcut("system:undo", tr("reserved"), VK_Z, CTRL_DOWN_MASK); // Undo an action
186 Shortcut.registerSystemShortcut("system:redo", tr("reserved"), VK_Y, CTRL_DOWN_MASK); // Redo an action
187 //Shortcut.registerSystemCut("microsoft-reserved-10", tr("reserved"), VK_DELETE, 0); // Delete the selected item and move it to the Recycle Bin
188 //Shortcut.registerSystemCut("microsoft-reserved-11", tr("reserved"), VK_DELETE, SHIFT_DOWN_MASK); // Delete the selected item without moving it to the Recycle Bin first
189 //Shortcut.registerSystemCut("system:rename", tr("reserved"), VK_F2, 0); // Rename the selected item
190 Shortcut.registerSystemShortcut("system:movefocusright", tr("reserved"), VK_RIGHT, CTRL_DOWN_MASK); // Move the cursor to the beginning of the next word
191 Shortcut.registerSystemShortcut("system:movefocusleft", tr("reserved"), VK_LEFT, CTRL_DOWN_MASK); // Move the cursor to the beginning of the previous word
192 Shortcut.registerSystemShortcut("system:movefocusdown", tr("reserved"), VK_DOWN, CTRL_DOWN_MASK); // Move the cursor to the beginning of the next paragraph
193 Shortcut.registerSystemShortcut("system:movefocusup", tr("reserved"), VK_UP, CTRL_DOWN_MASK); // Move the cursor to the beginning of the previous paragraph
194 //Shortcut.registerSystemCut("microsoft-reserved-17", tr("reserved"), VK_RIGHT, CTRL_DOWN_MASK | SHIFT_DOWN_MASK); // Select a block of text
195 //Shortcut.registerSystemCut("microsoft-reserved-18", tr("reserved"), VK_LEFT, CTRL_DOWN_MASK | SHIFT_DOWN_MASK); // Select a block of text
196 //Shortcut.registerSystemCut("microsoft-reserved-19", tr("reserved"), VK_DOWN, CTRL_DOWN_MASK | SHIFT_DOWN_MASK); // Select a block of text
197 //Shortcut.registerSystemCut("microsoft-reserved-20", tr("reserved"), VK_UP, CTRL_DOWN_MASK | SHIFT_DOWN_MASK); // Select a block of text
198 //Shortcut.registerSystemCut("microsoft-reserved-21", tr("reserved"), VK_RIGHT, SHIFT_DOWN_MASK); // Select more than one item in a window or on the desktop, or select text within a document
199 //Shortcut.registerSystemCut("microsoft-reserved-22", tr("reserved"), VK_LEFT, SHIFT_DOWN_MASK); // Select more than one item in a window or on the desktop, or select text within a document
200 //Shortcut.registerSystemCut("microsoft-reserved-23", tr("reserved"), VK_DOWN, SHIFT_DOWN_MASK); // Select more than one item in a window or on the desktop, or select text within a document
201 //Shortcut.registerSystemCut("microsoft-reserved-24", tr("reserved"), VK_UP, SHIFT_DOWN_MASK); // Select more than one item in a window or on the desktop, or select text within a document
202 //Shortcut.registerSystemCut("microsoft-reserved-25", tr("reserved"), VK_RIGHT+, CTRL_DOWN_MASK); // Select multiple individual items in a window or on the desktop (TODO: ctrl+arrow+spacebar, how to handle it in Java ?)
203 //Shortcut.registerSystemCut("microsoft-reserved-26", tr("reserved"), VK_LEFT+, CTRL_DOWN_MASK); // Select multiple individual items in a window or on the desktop (TODO: ctrl+arrow+spacebar, how to handle it in Java ?)
204 //Shortcut.registerSystemCut("microsoft-reserved-27", tr("reserved"), VK_DOWN+, CTRL_DOWN_MASK); // Select multiple individual items in a window or on the desktop (TODO: ctrl+arrow+spacebar, how to handle it in Java ?)
205 //Shortcut.registerSystemCut("microsoft-reserved-28", tr("reserved"), VK_UP+, CTRL_DOWN_MASK); // Select multiple individual items in a window or on the desktop (TODO: ctrl+arrow+spacebar, how to handle it in Java ?)
206 Shortcut.registerSystemShortcut("system:selectall", tr("reserved"), VK_A, CTRL_DOWN_MASK); // Select all items in a document or window
207 //Shortcut.registerSystemCut("system:search", tr("reserved"), VK_F3, 0); // Search for a file or folder
208 Shortcut.registerSystemShortcut("microsoft-reserved-31", tr("reserved"), VK_ENTER, ALT_DOWN_MASK).setAutomatic(); // Display properties for the selected item
209 Shortcut.registerSystemShortcut("system:exit", tr("reserved"), VK_F4, ALT_DOWN_MASK).setAutomatic(); // Close the active item, or exit the active program
210 Shortcut.registerSystemShortcut("microsoft-reserved-33", tr("reserved"), VK_SPACE, ALT_DOWN_MASK).setAutomatic(); // Open the shortcut menu for the active window
211 //Shortcut.registerSystemCut("microsoft-reserved-34", tr("reserved"), VK_F4, CTRL_DOWN_MASK); // Close the active document (in programs that allow you to have multiple documents open simultaneously)
212 Shortcut.registerSystemShortcut("microsoft-reserved-35", tr("reserved"), VK_TAB, ALT_DOWN_MASK).setAutomatic(); // Switch between open items
213 Shortcut.registerSystemShortcut("microsoft-reserved-36", tr("reserved"), VK_TAB, CTRL_DOWN_MASK | ALT_DOWN_MASK).setAutomatic(); // Use the arrow keys to switch between open items
214 //Shortcut.registerSystemCut("microsoft-reserved-37", tr("reserved"), VK_TAB, ); // Cycle through programs on the taskbar by using Aero Flip 3-D (TODO: Windows-Tab, how to handle it in Java ?)
215 //Shortcut.registerSystemCut("microsoft-reserved-38", tr("reserved"), VK_TAB, CTRL_DOWN_MASK | ); // Use the arrow keys to cycle through programs on the taskbar by using Aero Flip 3-D (TODO: Ctrl-Windows-Tab, how to handle it in Java ?)
216 Shortcut.registerSystemShortcut("microsoft-reserved-39", tr("reserved"), VK_ESCAPE, ALT_DOWN_MASK).setAutomatic(); // Cycle through items in the order in which they were opened
217 //Shortcut.registerSystemCut("microsoft-reserved-40", tr("reserved"), VK_F6, 0); // Cycle through screen elements in a window or on the desktop
218 //Shortcut.registerSystemCut("microsoft-reserved-41", tr("reserved"), VK_F4, 0); // Display the address bar list in Windows Explorer
219 Shortcut.registerSystemShortcut("microsoft-reserved-42", tr("reserved"), VK_F10, SHIFT_DOWN_MASK); // Display the shortcut menu for the selected item
220 Shortcut.registerSystemShortcut("microsoft-reserved-43", tr("reserved"), VK_ESCAPE, CTRL_DOWN_MASK).setAutomatic(); // Open the Start menu
221 //Shortcut.registerSystemShortcut("microsoft-reserved-44", tr("reserved"), VK_F10, 0); // Activate the menu bar in the active program
222 //Shortcut.registerSystemCut("microsoft-reserved-45", tr("reserved"), VK_RIGHT, 0); // Open the next menu to the right, or open a submenu
223 //Shortcut.registerSystemCut("microsoft-reserved-46", tr("reserved"), VK_LEFT, 0); // Open the next menu to the left, or close a submenu
224 //Shortcut.registerSystemCut("microsoft-reserved-47", tr("reserved"), VK_F5, 0); // Refresh the active window
225 //Shortcut.registerSystemCut("microsoft-reserved-48", tr("reserved"), VK_UP, ALT_DOWN_MASK); // View the folder one level up in Windows Explorer
226 //Shortcut.registerSystemCut("microsoft-reserved-49", tr("reserved"), VK_ESCAPE, 0); // Cancel the current task
227 Shortcut.registerSystemShortcut("microsoft-reserved-50", tr("reserved"), VK_ESCAPE, CTRL_DOWN_MASK | SHIFT_DOWN_MASK).setAutomatic(); // Open Task Manager
228 Shortcut.registerSystemShortcut("microsoft-reserved-51", tr("reserved"), VK_SHIFT, ALT_DOWN_MASK).setAutomatic(); // Switch the input language when multiple input languages are enabled
229 Shortcut.registerSystemShortcut("microsoft-reserved-52", tr("reserved"), VK_SHIFT, CTRL_DOWN_MASK).setAutomatic(); // Switch the keyboard layout when multiple keyboard layouts are enabled
230 //Shortcut.registerSystemCut("microsoft-reserved-53", tr("reserved"), ); // Change the reading direction of text in right-to-left reading languages (TODO: unclear)
231 // CHECKSTYLE.ON: LineLength
232 }
233
234 @Override
235 public String getDefaultStyle() {
236 return "com.sun.java.swing.plaf.windows.WindowsLookAndFeel";
237 }
238
239 @Override
240 public boolean rename(File from, File to) {
241 if (to.exists())
242 Utils.deleteFile(to);
243 return from.renameTo(to);
244 }
245
246 @Override
247 public String getOSDescription() {
248 return Utils.strip(System.getProperty("os.name")) + ' ' +
249 ((System.getenv("ProgramFiles(x86)") == null) ? "32" : "64") + "-Bit";
250 }
251
252 /**
253 * Loads Windows-ROOT keystore.
254 * @return Windows-ROOT keystore
255 * @throws NoSuchAlgorithmException if the algorithm used to check the integrity of the keystore cannot be found
256 * @throws CertificateException if any of the certificates in the keystore could not be loaded
257 * @throws IOException if there is an I/O or format problem with the keystore data, if a password is required but not given
258 * @throws KeyStoreException if no Provider supports a KeyStore implementation for the type "Windows-ROOT"
259 * @since 7343
260 */
261 public static KeyStore getRootKeystore() throws NoSuchAlgorithmException, CertificateException, IOException, KeyStoreException {
262 KeyStore ks = KeyStore.getInstance(WINDOWS_ROOT);
263 ks.load(null, null);
264 return ks;
265 }
266
267 /**
268 * Removes potential insecure certificates installed with previous versions of JOSM on Windows.
269 * @throws NoSuchAlgorithmException on unsupported signature algorithms
270 * @throws CertificateException if any of the certificates in the Windows keystore could not be loaded
271 * @throws KeyStoreException if no Provider supports a KeyStoreSpi implementation for the type "Windows-ROOT"
272 * @throws IOException if there is an I/O or format problem with the keystore data, if a password is required but not given
273 * @since 7335
274 */
275 public static void removeInsecureCertificates() throws NoSuchAlgorithmException, CertificateException, KeyStoreException, IOException {
276 // We offered before a public private key we need now to remove from Windows PCs as it might be a huge security risk (see #10230)
277 PublicKey insecurePubKey = null;
278 try {
279 insecurePubKey = KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(INSECURE_PUBLIC_KEY));
280 } catch (InvalidKeySpecException | NoSuchAlgorithmException e) {
281 Main.error(e);
282 return;
283 }
284 KeyStore ks = getRootKeystore();
285 Enumeration<String> en = ks.aliases();
286 Collection<String> insecureCertificates = new ArrayList<>();
287 while (en.hasMoreElements()) {
288 String alias = en.nextElement();
289 // Look for certificates associated with a private key
290 if (ks.isKeyEntry(alias)) {
291 try {
292 ks.getCertificate(alias).verify(insecurePubKey);
293 // If no exception, this is a certificate signed with the insecure key -> remove it
294 insecureCertificates.add(alias);
295 } catch (InvalidKeyException | NoSuchProviderException | SignatureException e) {
296 // If exception this is not a certificate related to JOSM, just trace it
297 Main.trace(alias + " --> " + e.getClass().getName());
298 Main.trace(e);
299 }
300 }
301 }
302 // Remove insecure certificates
303 if (!insecureCertificates.isEmpty()) {
304 StringBuilder message = new StringBuilder("<html>");
305 message.append(tr("A previous version of JOSM has installed a custom certificate "+
306 "in order to provide HTTPS support for Remote Control:"))
307 .append("<br><ul>");
308 for (String alias : insecureCertificates) {
309 message.append("<li>")
310 .append(alias)
311 .append("</li>");
312 }
313 message.append("</ul>")
314 .append(tr("It appears it could be an important <b>security risk</b>.<br><br>"+
315 "You are now going to be prompted by Windows to remove this insecure certificate.<br>"+
316 "For your own safety, <b>please click Yes</b> in next dialog."))
317 .append("</html>");
318 JOptionPane.showMessageDialog(Main.parent, message.toString(), tr("Warning"), JOptionPane.WARNING_MESSAGE);
319 for (String alias : insecureCertificates) {
320 Main.warn(tr("Removing insecure certificate from {0} keystore: {1}", WINDOWS_ROOT, alias));
321 try {
322 ks.deleteEntry(alias);
323 } catch (KeyStoreException e) {
324 Main.error(e, tr("Unable to remove insecure certificate from keystore: {0}", e.getMessage()));
325 }
326 }
327 }
328 }
329
330 @Override
331 public boolean setupHttpsCertificate(String entryAlias, KeyStore.TrustedCertificateEntry trustedCert)
332 throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException {
333 KeyStore ks = getRootKeystore();
334 // Look for certificate to install
335 try {
336 String alias = ks.getCertificateAlias(trustedCert.getTrustedCertificate());
337 if (alias != null) {
338 // JOSM certificate found, return
339 Main.debug(tr("JOSM localhost certificate found in {0} keystore: {1}", WINDOWS_ROOT, alias));
340 return false;
341 }
342 } catch (ArrayIndexOutOfBoundsException e) {
343 // catch error of JDK-8172244 as bug seems to not be fixed anytime soon
344 Main.error(e, "JDK-8172244 occured. Abort HTTPS setup");
345 return false;
346 }
347 if (!GraphicsEnvironment.isHeadless()) {
348 // JOSM certificate not found, warn user
349 StringBuilder message = new StringBuilder("<html>");
350 message.append(tr("Remote Control is configured to provide HTTPS support.<br>"+
351 "This requires to add a custom certificate generated by JOSM to the Windows Root CA store.<br><br>"+
352 "You are now going to be prompted by Windows to confirm this operation.<br>"+
353 "To enable proper HTTPS support, <b>please click Yes</b> in next dialog.<br><br>"+
354 "If unsure, you can also click No then disable HTTPS support in Remote Control preferences."))
355 .append("</html>");
356 JOptionPane.showMessageDialog(Main.parent, message.toString(),
357 tr("HTTPS support in Remote Control"), JOptionPane.INFORMATION_MESSAGE);
358 }
359 // install it to Windows-ROOT keystore, used by IE, Chrome and Safari, but not by Firefox
360 Main.info(tr("Adding JOSM localhost certificate to {0} keystore", WINDOWS_ROOT));
361 ks.setEntry(entryAlias, trustedCert, null);
362 return true;
363 }
364
365 @Override
366 public X509Certificate getX509Certificate(CertAmend certAmend)
367 throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException {
368 KeyStore ks = getRootKeystore();
369 // Search by alias (fast)
370 Certificate result = ks.getCertificate(certAmend.getId());
371 if (result instanceof X509Certificate) {
372 return (X509Certificate) result;
373 }
374 // If not found, search by SHA-256 (slower)
375 MessageDigest md = MessageDigest.getInstance("SHA-256");
376 for (Enumeration<String> aliases = ks.aliases(); aliases.hasMoreElements();) {
377 result = ks.getCertificate(aliases.nextElement());
378 if (result instanceof X509Certificate
379 && certAmend.getSha256().equalsIgnoreCase(Utils.toHexString(md.digest(result.getEncoded())))) {
380 return (X509Certificate) result;
381 }
382 }
383 // Not found
384 return null;
385 }
386
387 @Override
388 public File getDefaultCacheDirectory() {
389 String p = System.getenv("LOCALAPPDATA");
390 if (p == null || p.isEmpty()) {
391 // Fallback for Windows OS earlier than Windows Vista, where the variable is not defined
392 p = System.getenv("APPDATA");
393 }
394 return new File(new File(p, Main.pref.getJOSMDirectoryBaseName()), "cache");
395 }
396
397 @Override
398 public File getDefaultPrefDirectory() {
399 return new File(System.getenv("APPDATA"), Main.pref.getJOSMDirectoryBaseName());
400 }
401
402 @Override
403 public File getDefaultUserDataDirectory() {
404 // Use preferences directory by default
405 return Main.pref.getPreferencesDirectory();
406 }
407
408 /**
409 * <p>Add more fallback fonts to the Java runtime, in order to get
410 * support for more scripts.</p>
411 *
412 * <p>The font configuration in Java doesn't include some Indic scripts,
413 * even though MS Windows ships with fonts that cover these unicode ranges.</p>
414 *
415 * <p>To fix this, the fontconfig.properties template is copied to the JOSM
416 * cache folder. Then, the additional entries are added to the font
417 * configuration. Finally the system property "sun.awt.fontconfig" is set
418 * to the customized fontconfig.properties file.</p>
419 *
420 * <p>This is a crude hack, but better than no font display at all for these languages.
421 * There is no guarantee, that the template file
422 * ($JAVA_HOME/lib/fontconfig.properties.src) matches the default
423 * configuration (which is in a binary format).
424 * Furthermore, the system property "sun.awt.fontconfig" is undocumented and
425 * may no longer work in future versions of Java.</p>
426 *
427 * <p>Related Java bug: <a href="https://bugs.openjdk.java.net/browse/JDK-8008572">JDK-8008572</a></p>
428 *
429 * @param templateFileName file name of the fontconfig.properties template file
430 */
431 protected void extendFontconfig(String templateFileName) {
432 String customFontconfigFile = Main.pref.get("fontconfig.properties", null);
433 if (customFontconfigFile != null) {
434 Utils.updateSystemProperty("sun.awt.fontconfig", customFontconfigFile);
435 return;
436 }
437 if (!Main.pref.getBoolean("font.extended-unicode", true))
438 return;
439
440 String javaLibPath = System.getProperty("java.home") + File.separator + "lib";
441 Path templateFile = FileSystems.getDefault().getPath(javaLibPath, templateFileName);
442 if (!Files.isReadable(templateFile)) {
443 Main.warn("extended font config - unable to find font config template file {0}", templateFile.toString());
444 return;
445 }
446 try (FileInputStream fis = new FileInputStream(templateFile.toFile())) {
447 Properties props = new Properties();
448 props.load(fis);
449 byte[] content = Files.readAllBytes(templateFile);
450 File cachePath = Main.pref.getCacheDirectory();
451 Path fontconfigFile = cachePath.toPath().resolve("fontconfig.properties");
452 OutputStream os = Files.newOutputStream(fontconfigFile);
453 os.write(content);
454 try (Writer w = new BufferedWriter(new OutputStreamWriter(os, StandardCharsets.UTF_8))) {
455 Collection<FontEntry> extrasPref = Main.pref.getListOfStructs(
456 "font.extended-unicode.extra-items", getAdditionalFonts(), FontEntry.class);
457 Collection<FontEntry> extras = new ArrayList<>();
458 w.append("\n\n# Added by JOSM to extend unicode coverage of Java font support:\n\n");
459 List<String> allCharSubsets = new ArrayList<>();
460 for (FontEntry entry: extrasPref) {
461 Collection<String> fontsAvail = getInstalledFonts();
462 if (fontsAvail != null && fontsAvail.contains(entry.file.toUpperCase(Locale.ENGLISH))) {
463 if (!allCharSubsets.contains(entry.charset)) {
464 allCharSubsets.add(entry.charset);
465 extras.add(entry);
466 } else {
467 Main.trace("extended font config - already registered font for charset ''{0}'' - skipping ''{1}''",
468 entry.charset, entry.name);
469 }
470 } else {
471 Main.trace("extended font config - Font ''{0}'' not found on system - skipping", entry.name);
472 }
473 }
474 for (FontEntry entry: extras) {
475 allCharSubsets.add(entry.charset);
476 if ("".equals(entry.name)) {
477 continue;
478 }
479 String key = "allfonts." + entry.charset;
480 String value = entry.name;
481 String prevValue = props.getProperty(key);
482 if (prevValue != null && !prevValue.equals(value)) {
483 Main.warn("extended font config - overriding ''{0}={1}'' with ''{2}''", key, prevValue, value);
484 }
485 w.append(key + '=' + value + '\n');
486 }
487 w.append('\n');
488 for (FontEntry entry: extras) {
489 if ("".equals(entry.name) || "".equals(entry.file)) {
490 continue;
491 }
492 String key = "filename." + entry.name.replace(' ', '_');
493 String value = entry.file;
494 String prevValue = props.getProperty(key);
495 if (prevValue != null && !prevValue.equals(value)) {
496 Main.warn("extended font config - overriding ''{0}={1}'' with ''{2}''", key, prevValue, value);
497 }
498 w.append(key + '=' + value + '\n');
499 }
500 w.append('\n');
501 String fallback = props.getProperty("sequence.fallback");
502 if (fallback != null) {
503 w.append("sequence.fallback=" + fallback + ',' + Utils.join(",", allCharSubsets) + '\n');
504 } else {
505 w.append("sequence.fallback=" + Utils.join(",", allCharSubsets) + '\n');
506 }
507 }
508 Utils.updateSystemProperty("sun.awt.fontconfig", fontconfigFile.toString());
509 } catch (IOException ex) {
510 Main.error(ex);
511 }
512 }
513
514 /**
515 * Get a list of fonts that are installed on the system.
516 *
517 * Must be done without triggering the Java Font initialization.
518 * (See {@link #extendFontconfig(java.lang.String)}, have to set system
519 * property first, which is then read by sun.awt.FontConfiguration upon initialization.)
520 *
521 * @return list of file names
522 */
523 protected Collection<String> getInstalledFonts() {
524 // Cannot use GraphicsEnvironment.getLocalGraphicsEnvironment().getAvailableFontFamilyNames()
525 // because we have to set the system property before Java initializes its fonts.
526 // Use more low-level method to find the installed fonts.
527 List<String> fontsAvail = new ArrayList<>();
528 Path fontPath = FileSystems.getDefault().getPath(System.getenv("SYSTEMROOT"), "Fonts");
529 try (DirectoryStream<Path> ds = Files.newDirectoryStream(fontPath)) {
530 for (Path p : ds) {
531 Path filename = p.getFileName();
532 if (filename != null) {
533 fontsAvail.add(filename.toString().toUpperCase(Locale.ENGLISH));
534 }
535 }
536 fontsAvail.add(""); // for devanagari
537 } catch (IOException ex) {
538 Main.error(ex, false);
539 Main.warn("extended font config - failed to load available Fonts");
540 fontsAvail = null;
541 }
542 return fontsAvail;
543 }
544
545 /**
546 * Get default list of additional fonts to add to the configuration.
547 *
548 * Java will choose thee first font in the list that can render a certain character.
549 *
550 * @return list of FontEntry objects
551 */
552 protected Collection<FontEntry> getAdditionalFonts() {
553 Collection<FontEntry> def = new ArrayList<>(33);
554 def.add(new FontEntry("devanagari", "", "")); // just include in fallback list font already defined in template
555
556 // Windows scripts: https://msdn.microsoft.com/en-us/goglobal/bb688099.aspx
557 // IE default fonts: https://msdn.microsoft.com/en-us/library/ie/dn467844(v=vs.85).aspx
558
559 // Windows 10 and later
560 def.add(new FontEntry("historic", "Segoe UI Historic", "SEGUIHIS.TTF")); // historic charsets
561
562 // Windows 8/8.1 and later
563 def.add(new FontEntry("javanese", "Javanese Text", "JAVATEXT.TTF")); // ISO 639: jv
564 def.add(new FontEntry("leelawadee", "Leelawadee", "LEELAWAD.TTF")); // ISO 639: bug
565 def.add(new FontEntry("myanmar", "Myanmar Text", "MMRTEXT.TTF")); // ISO 639: my
566 def.add(new FontEntry("nirmala", "Nirmala UI", "NIRMALA.TTF")); // ISO 639: sat,srb
567 def.add(new FontEntry("segoeui", "Segoe UI", "SEGOEUI.TTF")); // ISO 639: lis
568 def.add(new FontEntry("emoji", "Segoe UI Emoji", "SEGUIEMJ.TTF")); // emoji symbol characters
569
570 // Windows 7 and later
571 def.add(new FontEntry("nko_tifinagh_vai_osmanya", "Ebrima", "EBRIMA.TTF")); // ISO 639: ber. Nko only since Win 8
572 def.add(new FontEntry("khmer1", "Khmer UI", "KHMERUI.TTF")); // ISO 639: km
573 def.add(new FontEntry("lao1", "Lao UI", "LAOUI.TTF")); // ISO 639: lo
574 def.add(new FontEntry("tai_le", "Microsoft Tai Le", "TAILE.TTF")); // ISO 639: khb
575 def.add(new FontEntry("new_tai_lue", "Microsoft New Tai Lue", "NTHAILU.TTF")); // ISO 639: khb
576
577 // Windows Vista and later:
578 def.add(new FontEntry("ethiopic", "Nyala", "NYALA.TTF")); // ISO 639: am,gez,ti
579 def.add(new FontEntry("tibetan", "Microsoft Himalaya", "HIMALAYA.TTF")); // ISO 639: bo,dz
580 def.add(new FontEntry("cherokee", "Plantagenet Cherokee", "PLANTC.TTF")); // ISO 639: chr
581 def.add(new FontEntry("unified_canadian", "Euphemia", "EUPHEMIA.TTF")); // ISO 639: cr,in
582 def.add(new FontEntry("khmer2", "DaunPenh", "DAUNPENH.TTF")); // ISO 639: km
583 def.add(new FontEntry("khmer3", "MoolBoran", "MOOLBOR.TTF")); // ISO 639: km
584 def.add(new FontEntry("lao_thai", "DokChampa", "DOKCHAMP.TTF")); // ISO 639: lo
585 def.add(new FontEntry("mongolian", "Mongolian Baiti", "MONBAITI.TTF")); // ISO 639: mn
586 def.add(new FontEntry("oriya", "Kalinga", "KALINGA.TTF")); // ISO 639: or
587 def.add(new FontEntry("sinhala", "Iskoola Pota", "ISKPOTA.TTF")); // ISO 639: si
588 def.add(new FontEntry("yi", "Yi Baiti", "MSYI.TTF")); // ISO 639: ii
589
590 // Windows XP and later
591 def.add(new FontEntry("gujarati", "Shruti", "SHRUTI.TTF"));
592 def.add(new FontEntry("kannada", "Tunga", "TUNGA.TTF"));
593 def.add(new FontEntry("gurmukhi", "Raavi", "RAAVI.TTF"));
594 def.add(new FontEntry("telugu", "Gautami", "GAUTAMI.TTF"));
595 def.add(new FontEntry("bengali", "Vrinda", "VRINDA.TTF")); // since XP SP2
596 def.add(new FontEntry("syriac", "Estrangelo Edessa", "ESTRE.TTF")); // ISO 639: arc
597 def.add(new FontEntry("thaana", "MV Boli", "MVBOLI.TTF")); // ISO 639: dv
598 def.add(new FontEntry("malayalam", "Kartika", "KARTIKA.TTF")); // ISO 639: ml; since XP SP2
599
600 // Windows 2000 and later
601 def.add(new FontEntry("tamil", "Latha", "LATHA.TTF"));
602
603 // Comes with MS Office & Outlook 2000. Good unicode coverage, so add if available.
604 def.add(new FontEntry("arialuni", "Arial Unicode MS", "ARIALUNI.TTF"));
605
606 return def;
607 }
608
609 @Override
610 public List<File> getDefaultProj4NadshiftDirectories() {
611 return Arrays.asList(new File("C:\\PROJ\\NAD"));
612 }
613}
Note: See TracBrowser for help on using the repository browser.