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

Last change on this file since 11180 was 11162, checked in by bastiK, 7 years ago

fixed #6664 - use XDG Base Directory Specification on Linux

If existing ~/.josm directory is found, it will be used as before.
Otherwise, ~/.cache/JOSM, ~/.local/share/JOSM and
~/.config/JOSM are used for cache, user data and preferences.

New system property option -Djosm.dir.name=... to change this to
~/.cache/JOSM-latest, etc. for the josm-latest package.

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