| 1 | // License: GPL. For details, see LICENSE file.
|
|---|
| 2 | package org.openstreetmap.josm.tools;
|
|---|
| 3 |
|
|---|
| 4 | import static org.openstreetmap.josm.tools.I18n.tr;
|
|---|
| 5 | import static org.openstreetmap.josm.tools.Utils.getSystemEnv;
|
|---|
| 6 | import static org.openstreetmap.josm.tools.Utils.getSystemProperty;
|
|---|
| 7 |
|
|---|
| 8 | import java.awt.Desktop;
|
|---|
| 9 | import java.awt.event.KeyEvent;
|
|---|
| 10 | import java.io.BufferedReader;
|
|---|
| 11 | import java.io.File;
|
|---|
| 12 | import java.io.IOException;
|
|---|
| 13 | import java.io.InputStream;
|
|---|
| 14 | import java.net.URISyntaxException;
|
|---|
| 15 | import java.nio.charset.StandardCharsets;
|
|---|
| 16 | import java.nio.file.Files;
|
|---|
| 17 | import java.nio.file.Path;
|
|---|
| 18 | import java.nio.file.Paths;
|
|---|
| 19 | import java.security.KeyStoreException;
|
|---|
| 20 | import java.security.NoSuchAlgorithmException;
|
|---|
| 21 | import java.security.cert.CertificateException;
|
|---|
| 22 | import java.security.cert.CertificateFactory;
|
|---|
| 23 | import java.security.cert.X509Certificate;
|
|---|
| 24 | import java.util.Arrays;
|
|---|
| 25 | import java.util.Collection;
|
|---|
| 26 | import java.util.HashSet;
|
|---|
| 27 | import java.util.Locale;
|
|---|
| 28 | import java.util.Optional;
|
|---|
| 29 | import java.util.Set;
|
|---|
| 30 | import java.util.concurrent.ExecutionException;
|
|---|
| 31 |
|
|---|
| 32 | import org.openstreetmap.josm.data.Preferences;
|
|---|
| 33 | import org.openstreetmap.josm.io.CertificateAmendment.NativeCertAmend;
|
|---|
| 34 | import org.openstreetmap.josm.spi.preferences.Config;
|
|---|
| 35 |
|
|---|
| 36 | /**
|
|---|
| 37 | * {@code PlatformHook} implementation for Unix systems.
|
|---|
| 38 | * @since 1023
|
|---|
| 39 | */
|
|---|
| 40 | public class PlatformHookUnixoid implements PlatformHook {
|
|---|
| 41 |
|
|---|
| 42 | private String osDescription;
|
|---|
| 43 |
|
|---|
| 44 | @Override
|
|---|
| 45 | public Platform getPlatform() {
|
|---|
| 46 | return Platform.UNIXOID;
|
|---|
| 47 | }
|
|---|
| 48 |
|
|---|
| 49 | @Override
|
|---|
| 50 | public void preStartupHook() {
|
|---|
| 51 | // See #12022, #16666 - Disable GNOME ATK Java wrapper as it causes a lot of serious trouble
|
|---|
| 52 | if (isDebianOrUbuntu()) {
|
|---|
| 53 | if (Utils.getJavaVersion() >= 9) {
|
|---|
| 54 | // TODO: find a way to disable ATK wrapper on Java >= 9
|
|---|
| 55 | // We should probably be able to do that by embedding a no-op AccessibilityProvider in our jar
|
|---|
| 56 | // so that it is loaded by ServiceLoader without error
|
|---|
| 57 | // But this require to compile at least one class with Java 9
|
|---|
| 58 | } else {
|
|---|
| 59 | // Java 8 does a simple Class.newInstance() from system classloader
|
|---|
| 60 | Utils.updateSystemProperty("javax.accessibility.assistive_technologies", "java.lang.Object");
|
|---|
| 61 | }
|
|---|
| 62 | }
|
|---|
| 63 | }
|
|---|
| 64 |
|
|---|
| 65 | @Override
|
|---|
| 66 | public void startupHook(JavaExpirationCallback javaCallback, WebStartMigrationCallback webStartCallback,
|
|---|
| 67 | SanityCheckCallback sanityCheckCallback) {
|
|---|
| 68 | checkWebStartMigration(webStartCallback);
|
|---|
| 69 | PlatformHook.super.startupHook(javaCallback, webStartCallback, sanityCheckCallback);
|
|---|
| 70 | }
|
|---|
| 71 |
|
|---|
| 72 | @Override
|
|---|
| 73 | public void openUrl(String url) throws IOException {
|
|---|
| 74 | for (String program : Config.getPref().getList("browser.unix",
|
|---|
| 75 | Arrays.asList("xdg-open", "#DESKTOP#", "$BROWSER", "gnome-open", "kfmclient openURL", "firefox"))) {
|
|---|
| 76 | try {
|
|---|
| 77 | if ("#DESKTOP#".equals(program)) {
|
|---|
| 78 | Desktop.getDesktop().browse(Utils.urlToURI(url));
|
|---|
| 79 | } else if (program.startsWith("$")) {
|
|---|
| 80 | program = System.getenv().get(program.substring(1));
|
|---|
| 81 | Runtime.getRuntime().exec(new String[]{program, url});
|
|---|
| 82 | } else {
|
|---|
| 83 | Runtime.getRuntime().exec(new String[]{program, url});
|
|---|
| 84 | }
|
|---|
| 85 | return;
|
|---|
| 86 | } catch (IOException | URISyntaxException e) {
|
|---|
| 87 | Logging.warn(e);
|
|---|
| 88 | }
|
|---|
| 89 | }
|
|---|
| 90 | }
|
|---|
| 91 |
|
|---|
| 92 | @Override
|
|---|
| 93 | public void initSystemShortcuts() {
|
|---|
| 94 | // CHECKSTYLE.OFF: LineLength
|
|---|
| 95 | // TODO: Insert system shortcuts here. See Windows and especially OSX to see how to.
|
|---|
| 96 | for (int i = KeyEvent.VK_F1; i <= KeyEvent.VK_F12; ++i) {
|
|---|
| 97 | Shortcut.registerSystemShortcut("screen:toogle"+i, tr("reserved"), i, KeyEvent.CTRL_DOWN_MASK | KeyEvent.ALT_DOWN_MASK)
|
|---|
| 98 | .setAutomatic();
|
|---|
| 99 | }
|
|---|
| 100 | Shortcut.registerSystemShortcut("system:reset", tr("reserved"), KeyEvent.VK_DELETE, KeyEvent.CTRL_DOWN_MASK | KeyEvent.ALT_DOWN_MASK)
|
|---|
| 101 | .setAutomatic();
|
|---|
| 102 | Shortcut.registerSystemShortcut("system:resetX", tr("reserved"), KeyEvent.VK_BACK_SPACE, KeyEvent.CTRL_DOWN_MASK | KeyEvent.ALT_DOWN_MASK)
|
|---|
| 103 | .setAutomatic();
|
|---|
| 104 | // CHECKSTYLE.ON: LineLength
|
|---|
| 105 | }
|
|---|
| 106 |
|
|---|
| 107 | @Override
|
|---|
| 108 | public String getDefaultStyle() {
|
|---|
| 109 | return "javax.swing.plaf.metal.MetalLookAndFeel";
|
|---|
| 110 | }
|
|---|
| 111 |
|
|---|
| 112 | /**
|
|---|
| 113 | * Returns desktop environment based on the environment variable {@code XDG_CURRENT_DESKTOP}.
|
|---|
| 114 | * @return desktop environment.
|
|---|
| 115 | */
|
|---|
| 116 | public Optional<String> getDesktopEnvironment() {
|
|---|
| 117 | return Optional.ofNullable(getSystemEnv("XDG_CURRENT_DESKTOP")).filter(s -> !s.isEmpty());
|
|---|
| 118 | }
|
|---|
| 119 |
|
|---|
| 120 | /**
|
|---|
| 121 | * Determines if the distribution is Debian or Ubuntu, or a derivative.
|
|---|
| 122 | * @return {@code true} if the distribution is Debian, Ubuntu or Mint, {@code false} otherwise
|
|---|
| 123 | */
|
|---|
| 124 | public static boolean isDebianOrUbuntu() {
|
|---|
| 125 | try {
|
|---|
| 126 | String dist = Utils.execOutput(Arrays.asList("lsb_release", "-i", "-s"));
|
|---|
| 127 | return "Debian".equalsIgnoreCase(dist) || "Ubuntu".equalsIgnoreCase(dist) || "Mint".equalsIgnoreCase(dist);
|
|---|
| 128 | } catch (IOException | ExecutionException | InterruptedException e) {
|
|---|
| 129 | // lsb_release is not available on all Linux systems, so don't log at warning level
|
|---|
| 130 | Logging.debug(e);
|
|---|
| 131 | return false;
|
|---|
| 132 | }
|
|---|
| 133 | }
|
|---|
| 134 |
|
|---|
| 135 | /**
|
|---|
| 136 | * Get the package name including detailed version.
|
|---|
| 137 | * @param packageNames The possible package names (when a package can have different names on different distributions)
|
|---|
| 138 | * @return The package name and package version if it can be identified, null otherwise
|
|---|
| 139 | * @since 7314
|
|---|
| 140 | */
|
|---|
| 141 | public static String getPackageDetails(String... packageNames) {
|
|---|
| 142 | try {
|
|---|
| 143 | // CHECKSTYLE.OFF: SingleSpaceSeparator
|
|---|
| 144 | boolean dpkg = Paths.get("/usr/bin/dpkg-query").toFile().exists();
|
|---|
| 145 | boolean eque = Paths.get("/usr/bin/equery").toFile().exists();
|
|---|
| 146 | boolean rpm = Paths.get("/bin/rpm").toFile().exists();
|
|---|
| 147 | // CHECKSTYLE.ON: SingleSpaceSeparator
|
|---|
| 148 | if (dpkg || rpm || eque) {
|
|---|
| 149 | for (String packageName : packageNames) {
|
|---|
| 150 | String[] args;
|
|---|
| 151 | if (dpkg) {
|
|---|
| 152 | args = new String[] {"dpkg-query", "--show", "--showformat", "${Architecture}-${Version}", packageName};
|
|---|
| 153 | } else if (eque) {
|
|---|
| 154 | args = new String[] {"equery", "-q", "list", "-e", "--format=$fullversion", packageName};
|
|---|
| 155 | } else {
|
|---|
| 156 | args = new String[] {"rpm", "-q", "--qf", "%{arch}-%{version}", packageName};
|
|---|
| 157 | }
|
|---|
| 158 | try {
|
|---|
| 159 | String version = Utils.execOutput(Arrays.asList(args));
|
|---|
| 160 | if (!Utils.isEmpty(version)) {
|
|---|
| 161 | return packageName + ':' + version;
|
|---|
| 162 | }
|
|---|
| 163 | } catch (ExecutionException e) {
|
|---|
| 164 | // Package does not exist, continue
|
|---|
| 165 | Logging.trace(e);
|
|---|
| 166 | }
|
|---|
| 167 | }
|
|---|
| 168 | }
|
|---|
| 169 | } catch (IOException | InterruptedException e) {
|
|---|
| 170 | Logging.warn(e);
|
|---|
| 171 | }
|
|---|
| 172 | return null;
|
|---|
| 173 | }
|
|---|
| 174 |
|
|---|
| 175 | /**
|
|---|
| 176 | * Get the Java package name including detailed version.
|
|---|
| 177 | *
|
|---|
| 178 | * Some Java bugs are specific to a certain security update, so in addition
|
|---|
| 179 | * to the Java version, we also need the exact package version.
|
|---|
| 180 | *
|
|---|
| 181 | * @return The package name and package version if it can be identified, null otherwise
|
|---|
| 182 | */
|
|---|
| 183 | public String getJavaPackageDetails() {
|
|---|
| 184 | String home = getSystemProperty("java.home");
|
|---|
| 185 | if (home.contains("java-8-openjdk") || home.contains("java-1.8.0-openjdk")) {
|
|---|
| 186 | return getPackageDetails("openjdk-8-jre", "java-1_8_0-openjdk", "java-1.8.0-openjdk");
|
|---|
| 187 | } else if (home.contains("java-9-openjdk") || home.contains("java-1.9.0-openjdk")) {
|
|---|
| 188 | return getPackageDetails("openjdk-9-jre", "java-1_9_0-openjdk", "java-1.9.0-openjdk", "java-9-openjdk");
|
|---|
| 189 | } else if (home.contains("java-10-openjdk")) {
|
|---|
| 190 | return getPackageDetails("openjdk-10-jre", "java-10-openjdk");
|
|---|
| 191 | } else if (home.contains("java-11-openjdk")) {
|
|---|
| 192 | return getPackageDetails("openjdk-11-jre", "java-11-openjdk");
|
|---|
| 193 | } else if (home.contains("java-17-openjdk")) {
|
|---|
| 194 | return getPackageDetails("openjdk-17-jre", "java-17-openjdk");
|
|---|
| 195 | } else if (home.contains("java-openjdk")) {
|
|---|
| 196 | return getPackageDetails("java-openjdk");
|
|---|
| 197 | } else if (home.contains("icedtea")) {
|
|---|
| 198 | return getPackageDetails("icedtea-bin");
|
|---|
| 199 | } else if (home.contains("oracle")) {
|
|---|
| 200 | return getPackageDetails("oracle-jdk-bin", "oracle-jre-bin");
|
|---|
| 201 | }
|
|---|
| 202 | return null;
|
|---|
| 203 | }
|
|---|
| 204 |
|
|---|
| 205 | /**
|
|---|
| 206 | * Get the Web Start package name including detailed version.
|
|---|
| 207 | *
|
|---|
| 208 | * OpenJDK packages are shipped with icedtea-web package,
|
|---|
| 209 | * but its version generally does not match main java package version.
|
|---|
| 210 | *
|
|---|
| 211 | * Simply return {@code null} if there's no separate package for Java WebStart.
|
|---|
| 212 | *
|
|---|
| 213 | * @return The package name and package version if it can be identified, null otherwise
|
|---|
| 214 | */
|
|---|
| 215 | public String getWebStartPackageDetails() {
|
|---|
| 216 | if (isOpenJDK()) {
|
|---|
| 217 | return getPackageDetails("icedtea-netx", "icedtea-web");
|
|---|
| 218 | }
|
|---|
| 219 | return null;
|
|---|
| 220 | }
|
|---|
| 221 |
|
|---|
| 222 | /**
|
|---|
| 223 | * Get the Gnome ATK wrapper package name including detailed version.
|
|---|
| 224 | *
|
|---|
| 225 | * Debian and Ubuntu derivatives come with a pre-enabled accessibility software
|
|---|
| 226 | * completely buggy that makes Swing crash in a lot of different ways.
|
|---|
| 227 | *
|
|---|
| 228 | * Simply return {@code null} if it's not found.
|
|---|
| 229 | *
|
|---|
| 230 | * @return The package name and package version if it can be identified, null otherwise
|
|---|
| 231 | */
|
|---|
| 232 | public String getAtkWrapperPackageDetails() {
|
|---|
| 233 | if (isOpenJDK() && isDebianOrUbuntu()) {
|
|---|
| 234 | return getPackageDetails("libatk-wrapper-java");
|
|---|
| 235 | }
|
|---|
| 236 | return null;
|
|---|
| 237 | }
|
|---|
| 238 |
|
|---|
| 239 | private String buildOSDescription() {
|
|---|
| 240 | String osName = getSystemProperty("os.name");
|
|---|
| 241 | if ("Linux".equalsIgnoreCase(osName)) {
|
|---|
| 242 | try {
|
|---|
| 243 | // Try lsb_release (only available on LSB-compliant Linux systems,
|
|---|
| 244 | // see https://www.linuxbase.org/lsb-cert/productdir.php?by_prod )
|
|---|
| 245 | String line = exec("lsb_release", "-ds");
|
|---|
| 246 | if (!Utils.isEmpty(line)) {
|
|---|
| 247 | line = line.replaceAll("\"+", "");
|
|---|
| 248 | line = line.replace("NAME=", ""); // strange code for some Gentoo's
|
|---|
| 249 | if (line.startsWith("Linux ")) // e.g. Linux Mint
|
|---|
| 250 | return line;
|
|---|
| 251 | else if (!line.isEmpty())
|
|---|
| 252 | return "Linux " + line;
|
|---|
| 253 | }
|
|---|
| 254 | } catch (IOException e) {
|
|---|
| 255 | Logging.debug(e);
|
|---|
| 256 | // Non LSB-compliant Linux system. List of common fallback release files: http://linuxmafia.com/faq/Admin/release-files.html
|
|---|
| 257 | for (LinuxReleaseInfo info : new LinuxReleaseInfo[]{
|
|---|
| 258 | new LinuxReleaseInfo("/etc/lsb-release", "DISTRIB_DESCRIPTION", "DISTRIB_ID", "DISTRIB_RELEASE"),
|
|---|
| 259 | new LinuxReleaseInfo("/etc/os-release", "PRETTY_NAME", "NAME", "VERSION"),
|
|---|
| 260 | new LinuxReleaseInfo("/etc/arch-release"),
|
|---|
| 261 | new LinuxReleaseInfo("/etc/debian_version", "Debian GNU/Linux "),
|
|---|
| 262 | new LinuxReleaseInfo("/etc/fedora-release"),
|
|---|
| 263 | new LinuxReleaseInfo("/etc/gentoo-release"),
|
|---|
| 264 | new LinuxReleaseInfo("/etc/redhat-release"),
|
|---|
| 265 | new LinuxReleaseInfo("/etc/SuSE-release")
|
|---|
| 266 | }) {
|
|---|
| 267 | String description = info.extractDescription();
|
|---|
| 268 | if (!Utils.isEmpty(description)) {
|
|---|
| 269 | return "Linux " + description;
|
|---|
| 270 | }
|
|---|
| 271 | }
|
|---|
| 272 | }
|
|---|
| 273 | }
|
|---|
| 274 | return osName;
|
|---|
| 275 | }
|
|---|
| 276 |
|
|---|
| 277 | @Override
|
|---|
| 278 | public String getOSDescription() {
|
|---|
| 279 | if (osDescription == null) {
|
|---|
| 280 | osDescription = buildOSDescription();
|
|---|
| 281 | }
|
|---|
| 282 | return osDescription;
|
|---|
| 283 | }
|
|---|
| 284 |
|
|---|
| 285 | private static class LinuxReleaseInfo {
|
|---|
| 286 | private final String path;
|
|---|
| 287 | private final String descriptionField;
|
|---|
| 288 | private final String idField;
|
|---|
| 289 | private final String releaseField;
|
|---|
| 290 | private final boolean plainText;
|
|---|
| 291 | private final String prefix;
|
|---|
| 292 |
|
|---|
| 293 | LinuxReleaseInfo(String path, String descriptionField, String idField, String releaseField) {
|
|---|
| 294 | this(path, descriptionField, idField, releaseField, false, null);
|
|---|
| 295 | }
|
|---|
| 296 |
|
|---|
| 297 | LinuxReleaseInfo(String path) {
|
|---|
| 298 | this(path, null, null, null, true, null);
|
|---|
| 299 | }
|
|---|
| 300 |
|
|---|
| 301 | LinuxReleaseInfo(String path, String prefix) {
|
|---|
| 302 | this(path, null, null, null, true, prefix);
|
|---|
| 303 | }
|
|---|
| 304 |
|
|---|
| 305 | private LinuxReleaseInfo(String path, String descriptionField, String idField, String releaseField, boolean plainText, String prefix) {
|
|---|
| 306 | this.path = path;
|
|---|
| 307 | this.descriptionField = descriptionField;
|
|---|
| 308 | this.idField = idField;
|
|---|
| 309 | this.releaseField = releaseField;
|
|---|
| 310 | this.plainText = plainText;
|
|---|
| 311 | this.prefix = prefix;
|
|---|
| 312 | }
|
|---|
| 313 |
|
|---|
| 314 | @Override
|
|---|
| 315 | public String toString() {
|
|---|
| 316 | return "ReleaseInfo [path=" + path + ", descriptionField=" + descriptionField +
|
|---|
| 317 | ", idField=" + idField + ", releaseField=" + releaseField + ']';
|
|---|
| 318 | }
|
|---|
| 319 |
|
|---|
| 320 | /**
|
|---|
| 321 | * Extracts OS detailed information from a Linux release file (/etc/xxx-release)
|
|---|
| 322 | * @return The OS detailed information, or {@code null}
|
|---|
| 323 | */
|
|---|
| 324 | public String extractDescription() {
|
|---|
| 325 | String result = null;
|
|---|
| 326 | if (path != null) {
|
|---|
| 327 | Path p = Paths.get(path);
|
|---|
| 328 | if (p.toFile().exists()) {
|
|---|
| 329 | try (BufferedReader reader = Files.newBufferedReader(p, StandardCharsets.UTF_8)) {
|
|---|
| 330 | String id = null;
|
|---|
| 331 | String release = null;
|
|---|
| 332 | String line;
|
|---|
| 333 | while (result == null && (line = reader.readLine()) != null) {
|
|---|
| 334 | if (line.contains("=")) {
|
|---|
| 335 | String[] tokens = line.split("=", -1);
|
|---|
| 336 | if (tokens.length >= 2) {
|
|---|
| 337 | // Description, if available, contains exactly what we need
|
|---|
| 338 | if (descriptionField != null && descriptionField.equalsIgnoreCase(tokens[0])) {
|
|---|
| 339 | result = Utils.strip(tokens[1]);
|
|---|
| 340 | } else if (idField != null && idField.equalsIgnoreCase(tokens[0])) {
|
|---|
| 341 | id = Utils.strip(tokens[1]);
|
|---|
| 342 | } else if (releaseField != null && releaseField.equalsIgnoreCase(tokens[0])) {
|
|---|
| 343 | release = Utils.strip(tokens[1]);
|
|---|
| 344 | }
|
|---|
| 345 | }
|
|---|
| 346 | } else if (plainText && !line.isEmpty()) {
|
|---|
| 347 | // Files composed of a single line
|
|---|
| 348 | result = Utils.strip(line);
|
|---|
| 349 | }
|
|---|
| 350 | }
|
|---|
| 351 | // If no description has been found, try to rebuild it with "id" + "release" (i.e. "name" + "version")
|
|---|
| 352 | if (result == null && id != null && release != null) {
|
|---|
| 353 | result = id + ' ' + release;
|
|---|
| 354 | }
|
|---|
| 355 | } catch (IOException e) {
|
|---|
| 356 | // Ignore
|
|---|
| 357 | Logging.trace(e);
|
|---|
| 358 | }
|
|---|
| 359 | }
|
|---|
| 360 | }
|
|---|
| 361 | // Append prefix if any
|
|---|
| 362 | if (!Utils.isEmpty(result) && !Utils.isEmpty(prefix)) {
|
|---|
| 363 | result = prefix + result;
|
|---|
| 364 | }
|
|---|
| 365 | if (result != null)
|
|---|
| 366 | result = result.replaceAll("\"+", "");
|
|---|
| 367 | return result;
|
|---|
| 368 | }
|
|---|
| 369 | }
|
|---|
| 370 |
|
|---|
| 371 | /**
|
|---|
| 372 | * Get the dot directory <code>~/.josm</code>.
|
|---|
| 373 | * @return the dot directory
|
|---|
| 374 | */
|
|---|
| 375 | private static File getDotDirectory() {
|
|---|
| 376 | String dirName = "." + Preferences.getJOSMDirectoryBaseName().toLowerCase(Locale.ENGLISH);
|
|---|
| 377 | return new File(getSystemProperty("user.home"), dirName);
|
|---|
| 378 | }
|
|---|
| 379 |
|
|---|
| 380 | /**
|
|---|
| 381 | * Returns true if the dot directory should be used for storing preferences,
|
|---|
| 382 | * cache and user data.
|
|---|
| 383 | * Currently this is the case, if the dot directory already exists.
|
|---|
| 384 | * @return true if the dot directory should be used
|
|---|
| 385 | */
|
|---|
| 386 | private static boolean useDotDirectory() {
|
|---|
| 387 | return getDotDirectory().exists();
|
|---|
| 388 | }
|
|---|
| 389 |
|
|---|
| 390 | @Override
|
|---|
| 391 | public File getDefaultCacheDirectory() {
|
|---|
| 392 | if (useDotDirectory()) {
|
|---|
| 393 | return new File(getDotDirectory(), "cache");
|
|---|
| 394 | } else {
|
|---|
| 395 | String xdgCacheDir = getSystemEnv("XDG_CACHE_HOME");
|
|---|
| 396 | if (!Utils.isEmpty(xdgCacheDir)) {
|
|---|
| 397 | return new File(xdgCacheDir, Preferences.getJOSMDirectoryBaseName());
|
|---|
| 398 | } else {
|
|---|
| 399 | return new File(getSystemProperty("user.home") + File.separator +
|
|---|
| 400 | ".cache" + File.separator + Preferences.getJOSMDirectoryBaseName());
|
|---|
| 401 | }
|
|---|
| 402 | }
|
|---|
| 403 | }
|
|---|
| 404 |
|
|---|
| 405 | @Override
|
|---|
| 406 | public File getDefaultPrefDirectory() {
|
|---|
| 407 | if (useDotDirectory()) {
|
|---|
| 408 | return getDotDirectory();
|
|---|
| 409 | } else {
|
|---|
| 410 | String xdgConfigDir = getSystemEnv("XDG_CONFIG_HOME");
|
|---|
| 411 | if (!Utils.isEmpty(xdgConfigDir)) {
|
|---|
| 412 | return new File(xdgConfigDir, Preferences.getJOSMDirectoryBaseName());
|
|---|
| 413 | } else {
|
|---|
| 414 | return new File(getSystemProperty("user.home") + File.separator +
|
|---|
| 415 | ".config" + File.separator + Preferences.getJOSMDirectoryBaseName());
|
|---|
| 416 | }
|
|---|
| 417 | }
|
|---|
| 418 | }
|
|---|
| 419 |
|
|---|
| 420 | @Override
|
|---|
| 421 | public File getDefaultUserDataDirectory() {
|
|---|
| 422 | if (useDotDirectory()) {
|
|---|
| 423 | return getDotDirectory();
|
|---|
| 424 | } else {
|
|---|
| 425 | String xdgDataDir = getSystemEnv("XDG_DATA_HOME");
|
|---|
| 426 | if (!Utils.isEmpty(xdgDataDir)) {
|
|---|
| 427 | return new File(xdgDataDir, Preferences.getJOSMDirectoryBaseName());
|
|---|
| 428 | } else {
|
|---|
| 429 | return new File(getSystemProperty("user.home") + File.separator +
|
|---|
| 430 | ".local" + File.separator + "share" + File.separator + Preferences.getJOSMDirectoryBaseName());
|
|---|
| 431 | }
|
|---|
| 432 | }
|
|---|
| 433 | }
|
|---|
| 434 |
|
|---|
| 435 | @Override
|
|---|
| 436 | public X509Certificate getX509Certificate(NativeCertAmend certAmend)
|
|---|
| 437 | throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException {
|
|---|
| 438 | for (String dir : new String[] {"/etc/ssl/certs", "/usr/share/ca-certificates/mozilla"}) {
|
|---|
| 439 | File f = new File(dir, certAmend.getFilename());
|
|---|
| 440 | if (f.exists()) {
|
|---|
| 441 | CertificateFactory fact = CertificateFactory.getInstance("X.509");
|
|---|
| 442 | try (InputStream is = Files.newInputStream(f.toPath())) {
|
|---|
| 443 | return (X509Certificate) fact.generateCertificate(is);
|
|---|
| 444 | }
|
|---|
| 445 | }
|
|---|
| 446 | }
|
|---|
| 447 | return null;
|
|---|
| 448 | }
|
|---|
| 449 |
|
|---|
| 450 | @Override
|
|---|
| 451 | public Collection<String> getPossiblePreferenceDirs() {
|
|---|
| 452 | Set<String> locations = new HashSet<>();
|
|---|
| 453 | locations.add("/usr/local/share/josm/");
|
|---|
| 454 | locations.add("/usr/local/lib/josm/");
|
|---|
| 455 | locations.add("/usr/share/josm/");
|
|---|
| 456 | locations.add("/usr/lib/josm/");
|
|---|
| 457 | return locations;
|
|---|
| 458 | }
|
|---|
| 459 | }
|
|---|