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

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

sonar - fix various recent issues

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