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

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

see #15343 - catch Java 9 exceptions

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