From e78155396d4f1aade4847e407e6de2f1215912f8 Mon Sep 17 00:00:00 2001 From: Martin Beyer Date: Wed, 8 Jul 2020 14:01:10 +0200 Subject: [PATCH 01/32] Implementing #1251 --- .../org/cryptomator/common/Environment.java | 3 ++ .../ui/preferences/AutoStartModule.java | 5 +-- .../ui/preferences/AutoStartStrategy.java | 7 ++++ .../ui/preferences/AutoStartWinStrategy.java | 33 ++++++++++++++++++- 4 files changed, 45 insertions(+), 3 deletions(-) diff --git a/main/commons/src/main/java/org/cryptomator/common/Environment.java b/main/commons/src/main/java/org/cryptomator/common/Environment.java index 890840b7d..54e29df8b 100644 --- a/main/commons/src/main/java/org/cryptomator/common/Environment.java +++ b/main/commons/src/main/java/org/cryptomator/common/Environment.java @@ -40,6 +40,7 @@ public class Environment { LOG.debug("cryptomator.mountPointsDir: {}", System.getProperty("cryptomator.mountPointsDir")); LOG.debug("cryptomator.minPwLength: {}", System.getProperty("cryptomator.minPwLength")); LOG.debug("cryptomator.buildNumber: {}", System.getProperty("cryptomator.buildNumber")); + LOG.debug("cryptomator.binaryPath: {}", System.getProperty("cryptomator.binaryPath")); } public boolean useCustomLogbackConfig() { @@ -74,6 +75,8 @@ public class Environment { return getInt("cryptomator.minPwLength", DEFAULT_MIN_PW_LENGTH); } + public Optional getBinaryPath() { return getPath("cryptomator.binaryPath"); } + private int getInt(String propertyName, int defaultValue) { String value = System.getProperty(propertyName); try { diff --git a/main/ui/src/main/java/org/cryptomator/ui/preferences/AutoStartModule.java b/main/ui/src/main/java/org/cryptomator/ui/preferences/AutoStartModule.java index d006d8681..1909b6af2 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/preferences/AutoStartModule.java +++ b/main/ui/src/main/java/org/cryptomator/ui/preferences/AutoStartModule.java @@ -3,6 +3,7 @@ package org.cryptomator.ui.preferences; import dagger.Module; import dagger.Provides; import org.apache.commons.lang3.SystemUtils; +import org.cryptomator.common.Environment; import org.cryptomator.jni.MacFunctions; import java.util.Optional; @@ -12,12 +13,12 @@ abstract class AutoStartModule { @Provides @PreferencesScoped - public static Optional provideAutoStartStrategy(Optional macFunctions) { + public static Optional provideAutoStartStrategy(Optional macFunctions, Environment env) { if (SystemUtils.IS_OS_MAC_OSX && macFunctions.isPresent()) { return Optional.of(new AutoStartMacStrategy(macFunctions.get())); } else if (SystemUtils.IS_OS_WINDOWS) { Optional exeName = ProcessHandle.current().info().command(); - return exeName.map(AutoStartWinStrategy::new); + return exeName.map(x -> new AutoStartWinStrategy(x, env)); } else { return Optional.empty(); } diff --git a/main/ui/src/main/java/org/cryptomator/ui/preferences/AutoStartStrategy.java b/main/ui/src/main/java/org/cryptomator/ui/preferences/AutoStartStrategy.java index 99b21b4cd..10a431e1f 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/preferences/AutoStartStrategy.java +++ b/main/ui/src/main/java/org/cryptomator/ui/preferences/AutoStartStrategy.java @@ -21,4 +21,11 @@ public interface AutoStartStrategy { } } + class TogglingAutoStartWithPowershellFailedException extends TogglingAutoStartFailedException { + + public TogglingAutoStartWithPowershellFailedException(String message, Throwable cause) { + super(message, cause); + } + + } } diff --git a/main/ui/src/main/java/org/cryptomator/ui/preferences/AutoStartWinStrategy.java b/main/ui/src/main/java/org/cryptomator/ui/preferences/AutoStartWinStrategy.java index f4a8b0578..3ffebfc18 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/preferences/AutoStartWinStrategy.java +++ b/main/ui/src/main/java/org/cryptomator/ui/preferences/AutoStartWinStrategy.java @@ -1,5 +1,6 @@ package org.cryptomator.ui.preferences; +import org.cryptomator.common.Environment; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -15,9 +16,12 @@ class AutoStartWinStrategy implements AutoStartStrategy { private static final String HKCU_AUTOSTART_KEY = "\"HKCU\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run\""; private static final String AUTOSTART_VALUE = "Cryptomator"; private final String exePath; + private static final String WINDOWS_START_MENU_FOLDER = "\\AppData\\Roaming\\Microsoft\\Windows\\Start Menu\\Programs"; + private Environment env; - public AutoStartWinStrategy(String exePath) { + public AutoStartWinStrategy(String exePath, Environment env) { this.exePath = exePath; + this.env = env; } @Override @@ -47,9 +51,11 @@ class AutoStartWinStrategy implements AutoStartStrategy { if (finishedInTime) { LOG.debug("Added {} to registry key {}.", AUTOSTART_VALUE, HKCU_AUTOSTART_KEY); } else { + addShortcutOfAppToAutostartFolder(); throw new TogglingAutoStartFailedException("Adding registry value failed."); } } catch (IOException e) { + addShortcutOfAppToAutostartFolder(); throw new TogglingAutoStartFailedException("Adding registry value failed. " + command, e); } } @@ -66,9 +72,11 @@ class AutoStartWinStrategy implements AutoStartStrategy { if (finishedInTime) { LOG.debug("Removed {} from registry key {}.", AUTOSTART_VALUE, HKCU_AUTOSTART_KEY); } else { + removeShortcutOfAppFromAutostartFolder(); throw new TogglingAutoStartFailedException("Removing registry value failed."); } } catch (IOException e) { + removeShortcutOfAppFromAutostartFolder(); throw new TogglingAutoStartFailedException("Removing registry value failed. " + command, e); } } @@ -88,4 +96,27 @@ class AutoStartWinStrategy implements AutoStartStrategy { return finishedInTime; } + private void addShortcutOfAppToAutostartFolder() throws TogglingAutoStartWithPowershellFailedException{ + String startmenueDirectory = System.getProperty("user.home") + WINDOWS_START_MENU_FOLDER + "\\Cryptomator.lnk"; + String cryptomator = env.getBinaryPath().get().toString(); + String createShortcutCommand = "$s=(New-Object -COM WScript.Shell).CreateShortcut('" + startmenueDirectory + "');$s.TargetPath='" + cryptomator + "';$s.Save();"; + ProcessBuilder shortcutAdd = new ProcessBuilder("cmd", "/c", "Start powershell " + createShortcutCommand); + try { + shortcutAdd.start(); + } catch (IOException e) { + throw new TogglingAutoStartWithPowershellFailedException("Adding shortcut to autostart folder failed.", e); + } + } + + private void removeShortcutOfAppFromAutostartFolder() throws TogglingAutoStartWithPowershellFailedException{ + String startmenueDirectory = System.getProperty("user.home") + WINDOWS_START_MENU_FOLDER + "\\Cryptomator.lnk"; + ProcessBuilder shortcutRemove = new ProcessBuilder("cmd", "/c del \"" + startmenueDirectory + "\""); + try { + shortcutRemove.start(); + } catch (IOException e) { + throw new TogglingAutoStartWithPowershellFailedException("Removing shortcut from autostart folder failed.", e); + } + } + + } From dcaa6e81a3868b72ea4c7a01405797aba017501f Mon Sep 17 00:00:00 2001 From: Martin Beyer Date: Wed, 8 Jul 2020 14:53:15 +0200 Subject: [PATCH 02/32] Improving Exception calling and logging --- .../ui/preferences/AutoStartWinStrategy.java | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/main/ui/src/main/java/org/cryptomator/ui/preferences/AutoStartWinStrategy.java b/main/ui/src/main/java/org/cryptomator/ui/preferences/AutoStartWinStrategy.java index 3ffebfc18..f863cec61 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/preferences/AutoStartWinStrategy.java +++ b/main/ui/src/main/java/org/cryptomator/ui/preferences/AutoStartWinStrategy.java @@ -48,9 +48,10 @@ class AutoStartWinStrategy implements AutoStartStrategy { try { Process proc = regAdd.start(); boolean finishedInTime = waitForProcess(proc, 5, TimeUnit.SECONDS); - if (finishedInTime) { + if (finishedInTime && proc.exitValue() == 0) { LOG.debug("Added {} to registry key {}.", AUTOSTART_VALUE, HKCU_AUTOSTART_KEY); } else { + LOG.debug("Registry could not be edited. Error code was {}.", proc.exitValue()); addShortcutOfAppToAutostartFolder(); throw new TogglingAutoStartFailedException("Adding registry value failed."); } @@ -69,9 +70,10 @@ class AutoStartWinStrategy implements AutoStartStrategy { try { Process proc = regRemove.start(); boolean finishedInTime = waitForProcess(proc, 5, TimeUnit.SECONDS); - if (finishedInTime) { + if (finishedInTime && proc.exitValue() == 0) { LOG.debug("Removed {} from registry key {}.", AUTOSTART_VALUE, HKCU_AUTOSTART_KEY); } else { + LOG.debug("Registry could not be edited. Error code was {}.", proc.exitValue()); removeShortcutOfAppFromAutostartFolder(); throw new TogglingAutoStartFailedException("Removing registry value failed."); } @@ -96,7 +98,7 @@ class AutoStartWinStrategy implements AutoStartStrategy { return finishedInTime; } - private void addShortcutOfAppToAutostartFolder() throws TogglingAutoStartWithPowershellFailedException{ + private void addShortcutOfAppToAutostartFolder() throws TogglingAutoStartWithPowershellFailedException { String startmenueDirectory = System.getProperty("user.home") + WINDOWS_START_MENU_FOLDER + "\\Cryptomator.lnk"; String cryptomator = env.getBinaryPath().get().toString(); String createShortcutCommand = "$s=(New-Object -COM WScript.Shell).CreateShortcut('" + startmenueDirectory + "');$s.TargetPath='" + cryptomator + "';$s.Save();"; @@ -108,7 +110,7 @@ class AutoStartWinStrategy implements AutoStartStrategy { } } - private void removeShortcutOfAppFromAutostartFolder() throws TogglingAutoStartWithPowershellFailedException{ + private void removeShortcutOfAppFromAutostartFolder() throws TogglingAutoStartWithPowershellFailedException { String startmenueDirectory = System.getProperty("user.home") + WINDOWS_START_MENU_FOLDER + "\\Cryptomator.lnk"; ProcessBuilder shortcutRemove = new ProcessBuilder("cmd", "/c del \"" + startmenueDirectory + "\""); try { From 526c8328f6192ee41d1540a36033daa1f15a623a Mon Sep 17 00:00:00 2001 From: Martin Beyer Date: Mon, 13 Jul 2020 15:21:24 +0200 Subject: [PATCH 03/32] Refactoring - Removing unnecessary environment variable --- .../java/org/cryptomator/common/Environment.java | 3 --- .../cryptomator/ui/preferences/AutoStartModule.java | 2 +- .../ui/preferences/AutoStartWinStrategy.java | 13 +++++-------- 3 files changed, 6 insertions(+), 12 deletions(-) diff --git a/main/commons/src/main/java/org/cryptomator/common/Environment.java b/main/commons/src/main/java/org/cryptomator/common/Environment.java index 54e29df8b..890840b7d 100644 --- a/main/commons/src/main/java/org/cryptomator/common/Environment.java +++ b/main/commons/src/main/java/org/cryptomator/common/Environment.java @@ -40,7 +40,6 @@ public class Environment { LOG.debug("cryptomator.mountPointsDir: {}", System.getProperty("cryptomator.mountPointsDir")); LOG.debug("cryptomator.minPwLength: {}", System.getProperty("cryptomator.minPwLength")); LOG.debug("cryptomator.buildNumber: {}", System.getProperty("cryptomator.buildNumber")); - LOG.debug("cryptomator.binaryPath: {}", System.getProperty("cryptomator.binaryPath")); } public boolean useCustomLogbackConfig() { @@ -75,8 +74,6 @@ public class Environment { return getInt("cryptomator.minPwLength", DEFAULT_MIN_PW_LENGTH); } - public Optional getBinaryPath() { return getPath("cryptomator.binaryPath"); } - private int getInt(String propertyName, int defaultValue) { String value = System.getProperty(propertyName); try { diff --git a/main/ui/src/main/java/org/cryptomator/ui/preferences/AutoStartModule.java b/main/ui/src/main/java/org/cryptomator/ui/preferences/AutoStartModule.java index 1909b6af2..fa01756ab 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/preferences/AutoStartModule.java +++ b/main/ui/src/main/java/org/cryptomator/ui/preferences/AutoStartModule.java @@ -18,7 +18,7 @@ abstract class AutoStartModule { return Optional.of(new AutoStartMacStrategy(macFunctions.get())); } else if (SystemUtils.IS_OS_WINDOWS) { Optional exeName = ProcessHandle.current().info().command(); - return exeName.map(x -> new AutoStartWinStrategy(x, env)); + return exeName.map(AutoStartWinStrategy::new); } else { return Optional.empty(); } diff --git a/main/ui/src/main/java/org/cryptomator/ui/preferences/AutoStartWinStrategy.java b/main/ui/src/main/java/org/cryptomator/ui/preferences/AutoStartWinStrategy.java index f863cec61..02e4faa26 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/preferences/AutoStartWinStrategy.java +++ b/main/ui/src/main/java/org/cryptomator/ui/preferences/AutoStartWinStrategy.java @@ -17,11 +17,9 @@ class AutoStartWinStrategy implements AutoStartStrategy { private static final String AUTOSTART_VALUE = "Cryptomator"; private final String exePath; private static final String WINDOWS_START_MENU_FOLDER = "\\AppData\\Roaming\\Microsoft\\Windows\\Start Menu\\Programs"; - private Environment env; - public AutoStartWinStrategy(String exePath, Environment env) { + public AutoStartWinStrategy(String exePath) { this.exePath = exePath; - this.env = env; } @Override @@ -99,9 +97,8 @@ class AutoStartWinStrategy implements AutoStartStrategy { } private void addShortcutOfAppToAutostartFolder() throws TogglingAutoStartWithPowershellFailedException { - String startmenueDirectory = System.getProperty("user.home") + WINDOWS_START_MENU_FOLDER + "\\Cryptomator.lnk"; - String cryptomator = env.getBinaryPath().get().toString(); - String createShortcutCommand = "$s=(New-Object -COM WScript.Shell).CreateShortcut('" + startmenueDirectory + "');$s.TargetPath='" + cryptomator + "';$s.Save();"; + String startMenuDirectory = System.getProperty("user.home") + WINDOWS_START_MENU_FOLDER + "\\Cryptomator.lnk"; + String createShortcutCommand = "$s=(New-Object -COM WScript.Shell).CreateShortcut('" + startMenuDirectory + "');$s.TargetPath='" + exePath + "';$s.Save();"; ProcessBuilder shortcutAdd = new ProcessBuilder("cmd", "/c", "Start powershell " + createShortcutCommand); try { shortcutAdd.start(); @@ -111,8 +108,8 @@ class AutoStartWinStrategy implements AutoStartStrategy { } private void removeShortcutOfAppFromAutostartFolder() throws TogglingAutoStartWithPowershellFailedException { - String startmenueDirectory = System.getProperty("user.home") + WINDOWS_START_MENU_FOLDER + "\\Cryptomator.lnk"; - ProcessBuilder shortcutRemove = new ProcessBuilder("cmd", "/c del \"" + startmenueDirectory + "\""); + String startMenuDirectory = System.getProperty("user.home") + WINDOWS_START_MENU_FOLDER + "\\Cryptomator.lnk"; + ProcessBuilder shortcutRemove = new ProcessBuilder("cmd", "/c del \"" + startMenuDirectory + "\""); try { shortcutRemove.start(); } catch (IOException e) { From 7c1d6973ba90f79e802286e8eac03ab0851b0c27 Mon Sep 17 00:00:00 2001 From: Armin Schrenk Date: Thu, 6 Aug 2020 15:18:30 +0200 Subject: [PATCH 04/32] fixes #1289 by decoupling storage path from vault name --- .../java/org/cryptomator/common/settings/VaultSettings.java | 2 +- .../src/main/java/org/cryptomator/common/vaults/Vault.java | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/main/commons/src/main/java/org/cryptomator/common/settings/VaultSettings.java b/main/commons/src/main/java/org/cryptomator/common/settings/VaultSettings.java index 13a0c8eed..395b118dd 100644 --- a/main/commons/src/main/java/org/cryptomator/common/settings/VaultSettings.java +++ b/main/commons/src/main/java/org/cryptomator/common/settings/VaultSettings.java @@ -70,7 +70,7 @@ public class VaultSettings { if (!mountNameSet && dirnameExists) { mountName.set(normalizeMountName(newPath.getFileName().toString())); } else if (!mountNameSet && !dirnameExists) { - mountName.set(DEFAULT_MOUNT_NAME + id); + mountName.set(DEFAULT_MOUNT_NAME + " " + id); } else if (mountNameSet && dirnameExists) { if (mountName.get().equals(DEFAULT_MOUNT_NAME + id)) { //this is okay, since this function is only executed if the path changes (aka, the vault is created or added) diff --git a/main/commons/src/main/java/org/cryptomator/common/vaults/Vault.java b/main/commons/src/main/java/org/cryptomator/common/vaults/Vault.java index bc461c1d9..5ee0ee931 100644 --- a/main/commons/src/main/java/org/cryptomator/common/vaults/Vault.java +++ b/main/commons/src/main/java/org/cryptomator/common/vaults/Vault.java @@ -78,7 +78,7 @@ public class Vault { this.state = state; this.lastKnownException = lastKnownException; this.stats = stats; - this.displayableName = Bindings.createStringBinding(this::getDisplayableName, vaultSettings.path()); + this.displayableName = Bindings.createStringBinding(this::getDisplayableName, vaultSettings.mountName()); this.displayablePath = Bindings.createStringBinding(this::getDisplayablePath, vaultSettings.path()); this.locked = Bindings.createBooleanBinding(this::isLocked, state); this.processing = Bindings.createBooleanBinding(this::isProcessing, state); @@ -230,8 +230,7 @@ public class Vault { } public String getDisplayableName() { - Path p = vaultSettings.path().get(); - return p.getFileName().toString(); + return vaultSettings.mountName().get(); } public StringBinding accessPointProperty() { From ea4c91fb3785466c19017fc3782edd0846d9cb4d Mon Sep 17 00:00:00 2001 From: Armin Schrenk Date: Thu, 6 Aug 2020 15:20:32 +0200 Subject: [PATCH 05/32] change meaning of mount name setting: * it is now considered the gerenal vault name * methods (except parsing) are renamed accordingly --- .../common/settings/VaultSettings.java | 22 +++++++++---------- .../settings/VaultSettingsJsonAdapter.java | 4 ++-- .../common/vaults/DokanyVolume.java | 2 +- .../org/cryptomator/common/vaults/Vault.java | 4 ++-- .../common/vaults/VaultModule.java | 2 +- .../common/vaults/WebDavVolume.java | 2 +- .../common/settings/SettingsTest.java | 2 +- .../VaultSettingsJsonAdapterTest.java | 4 ++-- .../common/vaults/VaultModuleTest.java | 2 +- .../vaultoptions/MountOptionsController.java | 2 +- 10 files changed, 23 insertions(+), 23 deletions(-) diff --git a/main/commons/src/main/java/org/cryptomator/common/settings/VaultSettings.java b/main/commons/src/main/java/org/cryptomator/common/settings/VaultSettings.java index 395b118dd..e31a361ff 100644 --- a/main/commons/src/main/java/org/cryptomator/common/settings/VaultSettings.java +++ b/main/commons/src/main/java/org/cryptomator/common/settings/VaultSettings.java @@ -42,7 +42,7 @@ public class VaultSettings { private final String id; private final ObjectProperty path = new SimpleObjectProperty(); - private final StringProperty mountName = new SimpleStringProperty(); + private final StringProperty displayName = new SimpleStringProperty(); private final StringProperty winDriveLetter = new SimpleStringProperty(); private final BooleanProperty unlockAfterStartup = new SimpleBooleanProperty(DEFAULT_UNLOCK_AFTER_STARTUP); private final BooleanProperty revealAfterMount = new SimpleBooleanProperty(DEFAULT_REAVEAL_AFTER_MOUNT); @@ -56,25 +56,25 @@ public class VaultSettings { public VaultSettings(String id) { this.id = Objects.requireNonNull(id); - EasyBind.subscribe(path, this::deriveMountNameFromPathOrUseDefault); + EasyBind.subscribe(path, this::deriveDisplayNameFromPathOrUseDefault); } Observable[] observables() { - return new Observable[]{path, mountName, winDriveLetter, unlockAfterStartup, revealAfterMount, useCustomMountPath, customMountPath, usesReadOnlyMode, mountFlags, filenameLengthLimit, actionAfterUnlock}; + return new Observable[]{path, displayName, winDriveLetter, unlockAfterStartup, revealAfterMount, useCustomMountPath, customMountPath, usesReadOnlyMode, mountFlags, filenameLengthLimit, actionAfterUnlock}; } - private void deriveMountNameFromPathOrUseDefault(Path newPath) { - final boolean mountNameSet = !StringUtils.isBlank(mountName.get()); + private void deriveDisplayNameFromPathOrUseDefault(Path newPath) { + final boolean mountNameSet = !StringUtils.isBlank(displayName.get()); final boolean dirnameExists = (newPath != null) && (newPath.getFileName() != null); if (!mountNameSet && dirnameExists) { - mountName.set(normalizeMountName(newPath.getFileName().toString())); + displayName.set(normalizeMountName(newPath.getFileName().toString())); } else if (!mountNameSet && !dirnameExists) { - mountName.set(DEFAULT_MOUNT_NAME + " " + id); + displayName.set(DEFAULT_MOUNT_NAME + " " + id); } else if (mountNameSet && dirnameExists) { - if (mountName.get().equals(DEFAULT_MOUNT_NAME + id)) { + if (displayName.get().equals(DEFAULT_MOUNT_NAME + id)) { //this is okay, since this function is only executed if the path changes (aka, the vault is created or added) - mountName.set(newPath.getFileName().toString()); + displayName.set(newPath.getFileName().toString()); } } } @@ -118,8 +118,8 @@ public class VaultSettings { return path; } - public StringProperty mountName() { - return mountName; + public StringProperty displayName() { + return displayName; } public StringProperty winDriveLetter() { diff --git a/main/commons/src/main/java/org/cryptomator/common/settings/VaultSettingsJsonAdapter.java b/main/commons/src/main/java/org/cryptomator/common/settings/VaultSettingsJsonAdapter.java index d136ffaff..a8b940918 100644 --- a/main/commons/src/main/java/org/cryptomator/common/settings/VaultSettingsJsonAdapter.java +++ b/main/commons/src/main/java/org/cryptomator/common/settings/VaultSettingsJsonAdapter.java @@ -21,7 +21,7 @@ class VaultSettingsJsonAdapter { out.beginObject(); out.name("id").value(value.getId()); out.name("path").value(value.path().get().toString()); - out.name("mountName").value(value.mountName().get()); + out.name("mountName").value(value.displayName().get()); out.name("winDriveLetter").value(value.winDriveLetter().get()); out.name("unlockAfterStartup").value(value.unlockAfterStartup().get()); out.name("revealAfterMount").value(value.revealAfterMount().get()); @@ -73,7 +73,7 @@ class VaultSettingsJsonAdapter { in.endObject(); VaultSettings vaultSettings = (id == null) ? VaultSettings.withRandomId() : new VaultSettings(id); - vaultSettings.mountName().set(mountName); + vaultSettings.displayName().set(mountName); vaultSettings.path().set(Paths.get(path)); vaultSettings.winDriveLetter().set(winDriveLetter); vaultSettings.unlockAfterStartup().set(unlockAfterStartup); diff --git a/main/commons/src/main/java/org/cryptomator/common/vaults/DokanyVolume.java b/main/commons/src/main/java/org/cryptomator/common/vaults/DokanyVolume.java index 1bfd813e3..f934bf25f 100644 --- a/main/commons/src/main/java/org/cryptomator/common/vaults/DokanyVolume.java +++ b/main/commons/src/main/java/org/cryptomator/common/vaults/DokanyVolume.java @@ -47,7 +47,7 @@ public class DokanyVolume implements Volume { @Override public void mount(CryptoFileSystem fs, String mountFlags) throws VolumeException, IOException { this.mountPoint = determineMountPoint(); - String mountName = vaultSettings.mountName().get(); + String mountName = vaultSettings.displayName().get(); try { this.mount = mountFactory.mount(fs.getPath("/"), mountPoint, mountName, FS_TYPE_NAME, mountFlags.strip()); } catch (MountFailedException e) { diff --git a/main/commons/src/main/java/org/cryptomator/common/vaults/Vault.java b/main/commons/src/main/java/org/cryptomator/common/vaults/Vault.java index 5ee0ee931..ce49a564e 100644 --- a/main/commons/src/main/java/org/cryptomator/common/vaults/Vault.java +++ b/main/commons/src/main/java/org/cryptomator/common/vaults/Vault.java @@ -78,7 +78,7 @@ public class Vault { this.state = state; this.lastKnownException = lastKnownException; this.stats = stats; - this.displayableName = Bindings.createStringBinding(this::getDisplayableName, vaultSettings.mountName()); + this.displayableName = Bindings.createStringBinding(this::getDisplayableName, vaultSettings.displayName()); this.displayablePath = Bindings.createStringBinding(this::getDisplayablePath, vaultSettings.path()); this.locked = Bindings.createBooleanBinding(this::isLocked, state); this.processing = Bindings.createBooleanBinding(this::isProcessing, state); @@ -230,7 +230,7 @@ public class Vault { } public String getDisplayableName() { - return vaultSettings.mountName().get(); + return vaultSettings.displayName().get(); } public StringBinding accessPointProperty() { diff --git a/main/commons/src/main/java/org/cryptomator/common/vaults/VaultModule.java b/main/commons/src/main/java/org/cryptomator/common/vaults/VaultModule.java index 1afd9d88b..d084be7bd 100644 --- a/main/commons/src/main/java/org/cryptomator/common/vaults/VaultModule.java +++ b/main/commons/src/main/java/org/cryptomator/common/vaults/VaultModule.java @@ -77,7 +77,7 @@ public class VaultModule { @DefaultMountFlags public StringBinding provideDefaultMountFlags(Settings settings, VaultSettings vaultSettings) { ObjectProperty preferredVolumeImpl = settings.preferredVolumeImpl(); - StringProperty mountName = vaultSettings.mountName(); + StringProperty mountName = vaultSettings.displayName(); BooleanProperty readOnly = vaultSettings.usesReadOnlyMode(); return Bindings.createStringBinding(() -> { diff --git a/main/commons/src/main/java/org/cryptomator/common/vaults/WebDavVolume.java b/main/commons/src/main/java/org/cryptomator/common/vaults/WebDavVolume.java index a12236230..5ad63dd7b 100644 --- a/main/commons/src/main/java/org/cryptomator/common/vaults/WebDavVolume.java +++ b/main/commons/src/main/java/org/cryptomator/common/vaults/WebDavVolume.java @@ -44,7 +44,7 @@ public class WebDavVolume implements Volume { if (!server.isRunning()) { server.start(); } - servlet = server.createWebDavServlet(fs.getPath("/"), vaultSettings.getId() + "/" + vaultSettings.mountName().get()); + servlet = server.createWebDavServlet(fs.getPath("/"), vaultSettings.getId() + "/" + vaultSettings.displayName().get()); servlet.start(); mount(); } diff --git a/main/commons/src/test/java/org/cryptomator/common/settings/SettingsTest.java b/main/commons/src/test/java/org/cryptomator/common/settings/SettingsTest.java index 708578763..33d384cf8 100644 --- a/main/commons/src/test/java/org/cryptomator/common/settings/SettingsTest.java +++ b/main/commons/src/test/java/org/cryptomator/common/settings/SettingsTest.java @@ -29,7 +29,7 @@ public class SettingsTest { Mockito.verify(changeListener, Mockito.times(2)).accept(settings); // third change (to property of list item): - vaultSettings.mountName().set("asd"); + vaultSettings.displayName().set("asd"); Mockito.verify(changeListener, Mockito.times(3)).accept(settings); } diff --git a/main/commons/src/test/java/org/cryptomator/common/settings/VaultSettingsJsonAdapterTest.java b/main/commons/src/test/java/org/cryptomator/common/settings/VaultSettingsJsonAdapterTest.java index 237b00904..4c684d5d6 100644 --- a/main/commons/src/test/java/org/cryptomator/common/settings/VaultSettingsJsonAdapterTest.java +++ b/main/commons/src/test/java/org/cryptomator/common/settings/VaultSettingsJsonAdapterTest.java @@ -29,7 +29,7 @@ public class VaultSettingsJsonAdapterTest { VaultSettings vaultSettings = adapter.read(jsonReader); Assertions.assertEquals("foo", vaultSettings.getId()); Assertions.assertEquals(Paths.get("/foo/bar"), vaultSettings.path().get()); - Assertions.assertEquals("test", vaultSettings.mountName().get()); + Assertions.assertEquals("test", vaultSettings.displayName().get()); Assertions.assertEquals("X", vaultSettings.winDriveLetter().get()); Assertions.assertEquals("/home/test/crypto", vaultSettings.customMountPath().get()); Assertions.assertEquals("--foo --bar", vaultSettings.mountFlags().get()); @@ -41,7 +41,7 @@ public class VaultSettingsJsonAdapterTest { public void testSerialize() throws IOException { VaultSettings vaultSettings = new VaultSettings("test"); vaultSettings.path().set(Paths.get("/foo/bar")); - vaultSettings.mountName().set("mountyMcMountFace"); + vaultSettings.displayName().set("mountyMcMountFace"); vaultSettings.mountFlags().set("--foo --bar"); StringWriter buf = new StringWriter(); diff --git a/main/commons/src/test/java/org/cryptomator/common/vaults/VaultModuleTest.java b/main/commons/src/test/java/org/cryptomator/common/vaults/VaultModuleTest.java index 1eb9a9d2f..0f4cbd102 100644 --- a/main/commons/src/test/java/org/cryptomator/common/vaults/VaultModuleTest.java +++ b/main/commons/src/test/java/org/cryptomator/common/vaults/VaultModuleTest.java @@ -28,7 +28,7 @@ public class VaultModuleTest { @BeforeEach public void setup(@TempDir Path tmpDir) { - Mockito.when(vaultSettings.mountName()).thenReturn(new SimpleStringProperty("TEST")); + Mockito.when(vaultSettings.displayName()).thenReturn(new SimpleStringProperty("TEST")); Mockito.when(vaultSettings.usesReadOnlyMode()).thenReturn(new SimpleBooleanProperty(true)); System.setProperty("user.home", tmpDir.toString()); } diff --git a/main/ui/src/main/java/org/cryptomator/ui/vaultoptions/MountOptionsController.java b/main/ui/src/main/java/org/cryptomator/ui/vaultoptions/MountOptionsController.java index 81753d83a..dcff17836 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/vaultoptions/MountOptionsController.java +++ b/main/ui/src/main/java/org/cryptomator/ui/vaultoptions/MountOptionsController.java @@ -63,7 +63,7 @@ public class MountOptionsController implements FxController { @FXML public void initialize() { - driveName.textProperty().bindBidirectional(vault.getVaultSettings().mountName()); + driveName.textProperty().bindBidirectional(vault.getVaultSettings().displayName()); // readonly: readOnlyCheckbox.selectedProperty().bindBidirectional(vault.getVaultSettings().usesReadOnlyMode()); From fb90128b63a191d403c3a5a30b1a24f87397cc92 Mon Sep 17 00:00:00 2001 From: Armin Schrenk Date: Thu, 6 Aug 2020 15:33:28 +0200 Subject: [PATCH 06/32] Move option to change display name of a vault from mount options to general options --- .../ui/vaultoptions/GeneralVaultOptionsController.java | 3 +++ .../cryptomator/ui/vaultoptions/MountOptionsController.java | 2 -- main/ui/src/main/resources/fxml/vault_options_general.fxml | 6 ++++++ main/ui/src/main/resources/fxml/vault_options_mount.fxml | 5 ----- main/ui/src/main/resources/i18n/strings.properties | 2 +- 5 files changed, 10 insertions(+), 8 deletions(-) diff --git a/main/ui/src/main/java/org/cryptomator/ui/vaultoptions/GeneralVaultOptionsController.java b/main/ui/src/main/java/org/cryptomator/ui/vaultoptions/GeneralVaultOptionsController.java index ddb6e0553..9849b0513 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/vaultoptions/GeneralVaultOptionsController.java +++ b/main/ui/src/main/java/org/cryptomator/ui/vaultoptions/GeneralVaultOptionsController.java @@ -3,6 +3,7 @@ package org.cryptomator.ui.vaultoptions; import javafx.fxml.FXML; import javafx.scene.control.CheckBox; import javafx.scene.control.ChoiceBox; +import javafx.scene.control.TextField; import javafx.util.StringConverter; import org.cryptomator.common.settings.UiTheme; import org.cryptomator.common.settings.WhenUnlocked; @@ -18,6 +19,7 @@ public class GeneralVaultOptionsController implements FxController { private final Vault vault; private final ResourceBundle resourceBundle; + public TextField vaultName; public CheckBox unlockOnStartupCheckbox; public ChoiceBox actionAfterUnlockChoiceBox; @@ -29,6 +31,7 @@ public class GeneralVaultOptionsController implements FxController { @FXML public void initialize() { + vaultName.textProperty().bindBidirectional(vault.getVaultSettings().displayName()); unlockOnStartupCheckbox.selectedProperty().bindBidirectional(vault.getVaultSettings().unlockAfterStartup()); actionAfterUnlockChoiceBox.getItems().addAll(WhenUnlocked.values()); actionAfterUnlockChoiceBox.valueProperty().bindBidirectional(vault.getVaultSettings().actionAfterUnlock()); diff --git a/main/ui/src/main/java/org/cryptomator/ui/vaultoptions/MountOptionsController.java b/main/ui/src/main/java/org/cryptomator/ui/vaultoptions/MountOptionsController.java index dcff17836..0d5b631ab 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/vaultoptions/MountOptionsController.java +++ b/main/ui/src/main/java/org/cryptomator/ui/vaultoptions/MountOptionsController.java @@ -42,7 +42,6 @@ public class MountOptionsController implements FxController { private final BooleanBinding webDavAndWindows; private final WindowsDriveLetters windowsDriveLetters; private final ResourceBundle resourceBundle; - public TextField driveName; public CheckBox readOnlyCheckbox; public CheckBox customMountFlagsCheckbox; public TextField mountFlags; @@ -63,7 +62,6 @@ public class MountOptionsController implements FxController { @FXML public void initialize() { - driveName.textProperty().bindBidirectional(vault.getVaultSettings().displayName()); // readonly: readOnlyCheckbox.selectedProperty().bindBidirectional(vault.getVaultSettings().usesReadOnlyMode()); diff --git a/main/ui/src/main/resources/fxml/vault_options_general.fxml b/main/ui/src/main/resources/fxml/vault_options_general.fxml index f6c3c680c..5997191bc 100644 --- a/main/ui/src/main/resources/fxml/vault_options_general.fxml +++ b/main/ui/src/main/resources/fxml/vault_options_general.fxml @@ -6,6 +6,7 @@ + + + + diff --git a/main/ui/src/main/resources/fxml/vault_options_mount.fxml b/main/ui/src/main/resources/fxml/vault_options_mount.fxml index 688e1bb1c..6ee1b84cd 100644 --- a/main/ui/src/main/resources/fxml/vault_options_mount.fxml +++ b/main/ui/src/main/resources/fxml/vault_options_mount.fxml @@ -23,11 +23,6 @@ - - - diff --git a/main/ui/src/main/resources/i18n/strings.properties b/main/ui/src/main/resources/i18n/strings.properties index cd6a2d625..d077d71b3 100644 --- a/main/ui/src/main/resources/i18n/strings.properties +++ b/main/ui/src/main/resources/i18n/strings.properties @@ -213,6 +213,7 @@ wrongFileAlert.link=For further assistance, visit # Vault Options ## General vaultOptions.general=General +vaultOptions.general.vaultName=Vault Name vaultOptions.general.unlockAfterStartup=Unlock vault when starting Cryptomator vaultOptions.general.actionAfterUnlock=After successful unlock vaultOptions.general.actionAfterUnlock.ignore=Do nothing @@ -221,7 +222,6 @@ vaultOptions.general.actionAfterUnlock.ask=Ask ## Mount vaultOptions.mount=Mounting vaultOptions.mount.readonly=Read-Only -vaultOptions.mount.driveName=Drive Name vaultOptions.mount.customMountFlags=Custom Mount Flags vaultOptions.mount.winDriveLetterOccupied=occupied vaultOptions.mount.mountPoint=Mount Point From 817907c25aee7e8b967f9578736a35aaf6c8566e Mon Sep 17 00:00:00 2001 From: Ralph Plawetzki Date: Fri, 7 Aug 2020 18:32:54 +0200 Subject: [PATCH 07/32] Add access functionality for KDE kwallets --- main/keychain/pom.xml | 8 +- .../cryptomator/keychain/KeychainModule.java | 2 +- .../LinuxKDEWalletKeychainAccessImpl.java | 121 ++++++++++++++++++ ...ss.java => LinuxSystemKeychainAccess.java} | 20 +-- main/pom.xml | 8 +- 5 files changed, 148 insertions(+), 11 deletions(-) create mode 100644 main/keychain/src/main/java/org/cryptomator/keychain/LinuxKDEWalletKeychainAccessImpl.java rename main/keychain/src/main/java/org/cryptomator/keychain/{LinuxSecretServiceKeychainAccess.java => LinuxSystemKeychainAccess.java} (64%) diff --git a/main/keychain/pom.xml b/main/keychain/pom.xml index fd2b26c3a..3eaa5c2e7 100644 --- a/main/keychain/pom.xml +++ b/main/keychain/pom.xml @@ -24,7 +24,7 @@ org.openjfx javafx-graphics - + org.apache.commons @@ -53,6 +53,12 @@ secret-service + + + org.purejava + kdewallet + + org.slf4j diff --git a/main/keychain/src/main/java/org/cryptomator/keychain/KeychainModule.java b/main/keychain/src/main/java/org/cryptomator/keychain/KeychainModule.java index 1db94fec6..a6054be2d 100644 --- a/main/keychain/src/main/java/org/cryptomator/keychain/KeychainModule.java +++ b/main/keychain/src/main/java/org/cryptomator/keychain/KeychainModule.java @@ -28,7 +28,7 @@ public abstract class KeychainModule { @Binds @IntoSet - abstract KeychainAccessStrategy bindLinuxSecretServiceKeychainAccess(LinuxSecretServiceKeychainAccess keychainAccessStrategy); + abstract KeychainAccessStrategy bindLinuxSystemKeychainAccess(LinuxSystemKeychainAccess keychainAccessStrategy); @Provides @Singleton diff --git a/main/keychain/src/main/java/org/cryptomator/keychain/LinuxKDEWalletKeychainAccessImpl.java b/main/keychain/src/main/java/org/cryptomator/keychain/LinuxKDEWalletKeychainAccessImpl.java new file mode 100644 index 000000000..120bef435 --- /dev/null +++ b/main/keychain/src/main/java/org/cryptomator/keychain/LinuxKDEWalletKeychainAccessImpl.java @@ -0,0 +1,121 @@ +package org.cryptomator.keychain; + +import org.freedesktop.dbus.connections.impl.DBusConnection; +import org.freedesktop.dbus.exceptions.DBusException; +import org.kde.KWallet; +import org.kde.Static; +import org.purejava.KDEWallet; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class LinuxKDEWalletKeychainAccessImpl implements KeychainAccessStrategy { + + private final Logger log = LoggerFactory.getLogger(LinuxKDEWalletKeychainAccessImpl.class); + + private final String FOLDER_NAME = "Cryptomator"; + private final String APP_NAME = "Cryptomator"; + private DBusConnection connection; + private KDEWallet wallet; + private int handle = -1; + + public LinuxKDEWalletKeychainAccessImpl() { + try { + connection = DBusConnection.getConnection(DBusConnection.DBusBusType.SESSION); + } catch (DBusException e) { + e.printStackTrace(); + } + } + + @Override + public boolean isSupported() { + try { + wallet = new KDEWallet(connection); + return wallet.isEnabled(); + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + + @Override + public void storePassphrase(String key, CharSequence passphrase) throws KeychainAccessException { + try { + if (walletIsOpen() && + !(wallet.hasEntry(handle, FOLDER_NAME, key, APP_NAME) + && wallet.entryType(handle, FOLDER_NAME, key, APP_NAME) == 1) + && wallet.writePassword(handle, FOLDER_NAME, key, passphrase.toString(), APP_NAME) == 0) { + log.debug("Passphrase successfully stored."); + } else { + log.debug("Passphrase was not stored."); + } + } catch (Exception e) { + log.error(e.toString(), e.getCause()); + throw new KeychainAccessException(e); + } + } + + @Override + public char[] loadPassphrase(String key) throws KeychainAccessException { + String password = ""; + try { + if (walletIsOpen()) { + password = wallet.readPassword(handle, FOLDER_NAME, key, APP_NAME); + log.debug("loadPassphrase: wallet is open."); + } else { + log.debug("loadPassphrase: wallet is closed."); + } + return (password.equals("")) ? null : password.toCharArray(); + } catch (Exception e) { + throw new KeychainAccessException(e); + } + } + + @Override + public void deletePassphrase(String key) throws KeychainAccessException { + try { + if (walletIsOpen() + && wallet.hasEntry(handle, FOLDER_NAME, key, APP_NAME) + && wallet.entryType(handle, FOLDER_NAME, key, APP_NAME) == 1 + && wallet.removeEntry(handle, FOLDER_NAME, key, APP_NAME) == 0) { + log.debug("Passphrase successfully deleted."); + } else { + log.debug("Passphrase was not deleted."); + } + } catch (Exception e) { + throw new KeychainAccessException(e); + } + } + + @Override + public void changePassphrase(String key, CharSequence passphrase) throws KeychainAccessException { + try { + if (walletIsOpen() + && wallet.hasEntry(handle, FOLDER_NAME, key, APP_NAME) + && wallet.entryType(handle, FOLDER_NAME, key, APP_NAME) == 1 + && wallet.writePassword(handle, FOLDER_NAME, key, passphrase.toString(), APP_NAME) == 0) { + log.debug("Passphrase successfully changed."); + } else { + log.debug("Passphrase could not be changed."); + } + } catch (Exception e) { + throw new KeychainAccessException(e); + } + } + + private boolean walletIsOpen() throws KeychainAccessException { + try { + if (wallet.isOpen(Static.DEFAULT_WALLET)) { + // This is needed due to KeechainManager loading the passphase directly + if (handle == -1) handle = wallet.open(Static.DEFAULT_WALLET, 0, APP_NAME); + return true; + } + wallet.openAsync(Static.DEFAULT_WALLET, 0, APP_NAME, false); + wallet.getSignalHandler().await(KWallet.walletAsyncOpened.class, Static.ObjectPaths.KWALLETD5, () -> null); + handle = wallet.getSignalHandler().getLastHandledSignal(KWallet.walletAsyncOpened.class, Static.ObjectPaths.KWALLETD5).handle; + log.debug("Wallet successfully initialized."); + return handle != -1; + } catch (Exception e) { + throw new KeychainAccessException(e); + } + } +} diff --git a/main/keychain/src/main/java/org/cryptomator/keychain/LinuxSecretServiceKeychainAccess.java b/main/keychain/src/main/java/org/cryptomator/keychain/LinuxSystemKeychainAccess.java similarity index 64% rename from main/keychain/src/main/java/org/cryptomator/keychain/LinuxSecretServiceKeychainAccess.java rename to main/keychain/src/main/java/org/cryptomator/keychain/LinuxSystemKeychainAccess.java index f11bdbd45..cb2e5ce77 100644 --- a/main/keychain/src/main/java/org/cryptomator/keychain/LinuxSecretServiceKeychainAccess.java +++ b/main/keychain/src/main/java/org/cryptomator/keychain/LinuxSystemKeychainAccess.java @@ -7,24 +7,28 @@ import javax.inject.Singleton; import java.util.Optional; /** - * A facade to LinuxSecretServiceKeychainAccessImpl that doesn't depend on libraries that are unavailable on Mac and Windows. + * A facade to LinuxSecretServiceKeychainAccessImpl and LinuxKDEWalletKeychainAccessImpl + * that depend on libraries that are unavailable on Mac and Windows. */ @Singleton -public class LinuxSecretServiceKeychainAccess implements KeychainAccessStrategy { +public class LinuxSystemKeychainAccess implements KeychainAccessStrategy { - // the actual implementation is hidden in this delegate object which is loaded via reflection, + // the actual implementation is hidden in this delegate objects which are loaded via reflection, // as it depends on libraries that aren't necessarily available: private final Optional delegate; @Inject - public LinuxSecretServiceKeychainAccess() { - this.delegate = constructGnomeKeyringKeychainAccess(); + public LinuxSystemKeychainAccess() { + this.delegate = constructKeychainAccess(); } - private static Optional constructGnomeKeyringKeychainAccess() { - try { - Class clazz = Class.forName("org.cryptomator.keychain.LinuxSecretServiceKeychainAccessImpl"); + private static Optional constructKeychainAccess() { + try { // is kwallet or gnome-keyring installed? + Class clazz = Class.forName("org.cryptomator.keychain.LinuxKDEWalletKeychainAccessImpl"); KeychainAccessStrategy instance = (KeychainAccessStrategy) clazz.getDeclaredConstructor().newInstance(); + if (instance.isSupported()) return Optional.of(instance); + clazz = Class.forName("org.cryptomator.keychain.LinuxSecretServiceKeychainAccessImpl"); + instance = (KeychainAccessStrategy) clazz.getDeclaredConstructor().newInstance(); return Optional.of(instance); } catch (Exception e) { return Optional.empty(); diff --git a/main/pom.xml b/main/pom.xml index 5f0d7e5ea..fdea0eb14 100644 --- a/main/pom.xml +++ b/main/pom.xml @@ -34,6 +34,7 @@ 14 3.10 1.0.0 + 1.0.0 3.10.3 1.0.3 29.0-jre @@ -168,7 +169,12 @@ secret-service ${secret-service.version} - + + org.purejava + kdewallet + ${kdewallet.version} + + com.auth0 From 100b83697990ed7f4b4b5557285cede953bebf8e Mon Sep 17 00:00:00 2001 From: Ralph Plawetzki Date: Fri, 7 Aug 2020 18:49:07 +0200 Subject: [PATCH 08/32] Adjust buildkit to exclude kdewallet for Windows and macOS --- main/buildkit/pom.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/main/buildkit/pom.xml b/main/buildkit/pom.xml index c86927d33..705138204 100644 --- a/main/buildkit/pom.xml +++ b/main/buildkit/pom.xml @@ -67,7 +67,7 @@ ${project.build.directory}/libs linux,mac,win - dbus-java,secret-service,hkdf,java-utils + dbus-java,secret-service,kdewallet,hkdf,java-utils @@ -83,14 +83,14 @@ - copy-linux-secret-service + copy-linux-system-keychain-access prepare-package copy-dependencies ${project.build.directory}/linux-libs - dbus-java,secret-service,hkdf,java-utils + dbus-java,secret-service,kdewallet,hkdf,java-utils From b1c66b181d441dfdd3c996b06dc2defb1d830b92 Mon Sep 17 00:00:00 2001 From: Ralph Plawetzki Date: Sun, 9 Aug 2020 11:18:17 +0200 Subject: [PATCH 09/32] Depend on kdewallet 1.0.1, hence dbus-java 3.2.3 that fixes issues when dealing with multiple signals of the same name but different signatures --- main/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main/pom.xml b/main/pom.xml index fdea0eb14..d4fe8da87 100644 --- a/main/pom.xml +++ b/main/pom.xml @@ -34,7 +34,7 @@ 14 3.10 1.0.0 - 1.0.0 + 1.0.1 3.10.3 1.0.3 29.0-jre From 429098733caabeb5846965603d5804e41d072d8e Mon Sep 17 00:00:00 2001 From: Armin Schrenk Date: Tue, 11 Aug 2020 11:19:54 +0200 Subject: [PATCH 10/32] Improve the vault/mount name system: * fix bug where the default name is not replaced by the actual folder name * introduce new field in settings "mountName" as binding on displayName * change volumes to use mountName instead of displayName --- .../common/settings/VaultSettings.java | 21 ++++++++++++++----- .../common/vaults/DokanyVolume.java | 2 +- .../common/vaults/WebDavVolume.java | 4 ++-- .../common/settings/VaultSettingsTest.java | 19 +++++++++++------ 4 files changed, 32 insertions(+), 14 deletions(-) diff --git a/main/commons/src/main/java/org/cryptomator/common/settings/VaultSettings.java b/main/commons/src/main/java/org/cryptomator/common/settings/VaultSettings.java index e31a361ff..1fdaefebf 100644 --- a/main/commons/src/main/java/org/cryptomator/common/settings/VaultSettings.java +++ b/main/commons/src/main/java/org/cryptomator/common/settings/VaultSettings.java @@ -8,6 +8,8 @@ package org.cryptomator.common.settings; import com.google.common.base.Strings; import com.google.common.io.BaseEncoding; import javafx.beans.Observable; +import javafx.beans.binding.Bindings; +import javafx.beans.binding.StringBinding; import javafx.beans.property.BooleanProperty; import javafx.beans.property.IntegerProperty; import javafx.beans.property.ObjectProperty; @@ -53,8 +55,11 @@ public class VaultSettings { private final IntegerProperty filenameLengthLimit = new SimpleIntegerProperty(DEFAULT_FILENAME_LENGTH_LIMIT); private final ObjectProperty actionAfterUnlock = new SimpleObjectProperty<>(DEFAULT_ACTION_AFTER_UNLOCK); + private final StringBinding mountName; + public VaultSettings(String id) { this.id = Objects.requireNonNull(id); + this.mountName = Bindings.createStringBinding(this::normalizeDisplayName, displayName); EasyBind.subscribe(path, this::deriveDisplayNameFromPathOrUseDefault); } @@ -66,13 +71,14 @@ public class VaultSettings { private void deriveDisplayNameFromPathOrUseDefault(Path newPath) { final boolean mountNameSet = !StringUtils.isBlank(displayName.get()); final boolean dirnameExists = (newPath != null) && (newPath.getFileName() != null); + final String defaultPattern = DEFAULT_MOUNT_NAME + " " + id; if (!mountNameSet && dirnameExists) { - displayName.set(normalizeMountName(newPath.getFileName().toString())); + displayName.set(newPath.getFileName().toString()); } else if (!mountNameSet && !dirnameExists) { - displayName.set(DEFAULT_MOUNT_NAME + " " + id); + displayName.set(defaultPattern); } else if (mountNameSet && dirnameExists) { - if (displayName.get().equals(DEFAULT_MOUNT_NAME + id)) { + if (displayName.get().equals(defaultPattern)) { //this is okay, since this function is only executed if the path changes (aka, the vault is created or added) displayName.set(newPath.getFileName().toString()); } @@ -89,8 +95,9 @@ public class VaultSettings { return BaseEncoding.base64Url().encode(randomBytes); } - public static String normalizeMountName(String mountName) { - String normalizedMountName = StringUtils.stripAccents(mountName); + //visible for testing + String normalizeDisplayName() { + String normalizedMountName = StringUtils.stripAccents(displayName.get()); StringBuilder builder = new StringBuilder(); for (char c : normalizedMountName.toCharArray()) { if (Character.isWhitespace(c)) { @@ -122,6 +129,10 @@ public class VaultSettings { return displayName; } + public StringBinding mountName() { + return mountName; + } + public StringProperty winDriveLetter() { return winDriveLetter; } diff --git a/main/commons/src/main/java/org/cryptomator/common/vaults/DokanyVolume.java b/main/commons/src/main/java/org/cryptomator/common/vaults/DokanyVolume.java index f934bf25f..117f888c9 100644 --- a/main/commons/src/main/java/org/cryptomator/common/vaults/DokanyVolume.java +++ b/main/commons/src/main/java/org/cryptomator/common/vaults/DokanyVolume.java @@ -49,7 +49,7 @@ public class DokanyVolume implements Volume { this.mountPoint = determineMountPoint(); String mountName = vaultSettings.displayName().get(); try { - this.mount = mountFactory.mount(fs.getPath("/"), mountPoint, mountName, FS_TYPE_NAME, mountFlags.strip()); + this.mount = mountFactory.mount(fs.getPath("/"), mountPoint, vaultSettings.mountName().get(), FS_TYPE_NAME, mountFlags.strip()); } catch (MountFailedException e) { if (vaultSettings.getCustomMountPath().isPresent()) { LOG.warn("Failed to mount vault into {}. Is this directory currently accessed by another process (e.g. Windows Explorer)?", mountPoint); diff --git a/main/commons/src/main/java/org/cryptomator/common/vaults/WebDavVolume.java b/main/commons/src/main/java/org/cryptomator/common/vaults/WebDavVolume.java index 5ad63dd7b..9c59790fa 100644 --- a/main/commons/src/main/java/org/cryptomator/common/vaults/WebDavVolume.java +++ b/main/commons/src/main/java/org/cryptomator/common/vaults/WebDavVolume.java @@ -44,7 +44,7 @@ public class WebDavVolume implements Volume { if (!server.isRunning()) { server.start(); } - servlet = server.createWebDavServlet(fs.getPath("/"), vaultSettings.getId() + "/" + vaultSettings.displayName().get()); + servlet = server.createWebDavServlet(fs.getPath("/"), vaultSettings.getId() + "/" + vaultSettings.mountName().get()); servlet.start(); mount(); } @@ -98,7 +98,7 @@ public class WebDavVolume implements Volume { @Override public Optional getMountPoint() { - return Optional.ofNullable(mountPoint); + return Optional.ofNullable(mountPoint); //TODO } private String getLocalhostAliasOrNull() { diff --git a/main/commons/src/test/java/org/cryptomator/common/settings/VaultSettingsTest.java b/main/commons/src/test/java/org/cryptomator/common/settings/VaultSettingsTest.java index 042ff9896..779b017bc 100644 --- a/main/commons/src/test/java/org/cryptomator/common/settings/VaultSettingsTest.java +++ b/main/commons/src/test/java/org/cryptomator/common/settings/VaultSettingsTest.java @@ -15,12 +15,19 @@ import static org.junit.jupiter.api.Assertions.assertEquals; public class VaultSettingsTest { @Test - public void testNormalize() throws Exception { - assertEquals("_", VaultSettings.normalizeMountName(" ")); - assertEquals("a", VaultSettings.normalizeMountName("ä")); - assertEquals("C", VaultSettings.normalizeMountName("Ĉ")); - assertEquals("_", VaultSettings.normalizeMountName(":")); - assertEquals("_", VaultSettings.normalizeMountName("汉语")); + public void testNormalize() { + VaultSettings settings = new VaultSettings("id"); + settings.displayName().setValue(" "); + assertEquals("_", settings.normalizeDisplayName()); + + settings.displayName().setValue("ä"); + assertEquals("a", settings.normalizeDisplayName()); + settings.displayName().setValue("Ĉ"); + assertEquals("C", settings.normalizeDisplayName()); + settings.displayName().setValue(":"); + assertEquals("_", settings.normalizeDisplayName()); + settings.displayName().setValue("汉语"); + assertEquals("_", settings.normalizeDisplayName()); } } From 31d95ae5b06018528259b20f0b5fff9bc7fdf758 Mon Sep 17 00:00:00 2001 From: Armin Schrenk Date: Tue, 11 Aug 2020 12:04:02 +0200 Subject: [PATCH 11/32] Remove restrictions of vault name filed to only contain alpha numeric characters --- .../ui/src/main/resources/fxml/vault_options_general.fxml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/main/ui/src/main/resources/fxml/vault_options_general.fxml b/main/ui/src/main/resources/fxml/vault_options_general.fxml index 5997191bc..0c4caa772 100644 --- a/main/ui/src/main/resources/fxml/vault_options_general.fxml +++ b/main/ui/src/main/resources/fxml/vault_options_general.fxml @@ -2,11 +2,11 @@ - - - + + + From 3bf2b499a7c31022863fcd34e1619aa4f5d18a3f Mon Sep 17 00:00:00 2001 From: Ralph Plawetzki Date: Fri, 14 Aug 2020 07:40:46 +0200 Subject: [PATCH 12/32] Reverse order to initialize backend The GNOME keyring feature was implemented first and we don't want to confuse users who used it before --- .../org/cryptomator/keychain/LinuxSystemKeychainAccess.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/main/keychain/src/main/java/org/cryptomator/keychain/LinuxSystemKeychainAccess.java b/main/keychain/src/main/java/org/cryptomator/keychain/LinuxSystemKeychainAccess.java index cb2e5ce77..e75d387cb 100644 --- a/main/keychain/src/main/java/org/cryptomator/keychain/LinuxSystemKeychainAccess.java +++ b/main/keychain/src/main/java/org/cryptomator/keychain/LinuxSystemKeychainAccess.java @@ -23,11 +23,11 @@ public class LinuxSystemKeychainAccess implements KeychainAccessStrategy { } private static Optional constructKeychainAccess() { - try { // is kwallet or gnome-keyring installed? - Class clazz = Class.forName("org.cryptomator.keychain.LinuxKDEWalletKeychainAccessImpl"); + try { // is gnome-keyring or kwallet installed? + Class clazz = Class.forName("org.cryptomator.keychain.LinuxSecretServiceKeychainAccessImpl"); KeychainAccessStrategy instance = (KeychainAccessStrategy) clazz.getDeclaredConstructor().newInstance(); if (instance.isSupported()) return Optional.of(instance); - clazz = Class.forName("org.cryptomator.keychain.LinuxSecretServiceKeychainAccessImpl"); + clazz = Class.forName("org.cryptomator.keychain.LinuxKDEWalletKeychainAccessImpl"); instance = (KeychainAccessStrategy) clazz.getDeclaredConstructor().newInstance(); return Optional.of(instance); } catch (Exception e) { From 0f56d424da63aee65ed9349ea2cd86739601f9ff Mon Sep 17 00:00:00 2001 From: infeo Date: Thu, 20 Aug 2020 12:18:57 +0200 Subject: [PATCH 13/32] Refactored AutoStartStrategy: * prevented on best effort basis inconsistent states * extracted the registry setting as an own strategy (by methods) * refactored the overriden methods to call the strategies (registry or folder) depending on the different variables * removed Powershell specific ToggleException * added documentation --- .../ui/preferences/AutoStartStrategy.java | 7 - .../ui/preferences/AutoStartWinStrategy.java | 181 +++++++++++++----- 2 files changed, 132 insertions(+), 56 deletions(-) diff --git a/main/ui/src/main/java/org/cryptomator/ui/preferences/AutoStartStrategy.java b/main/ui/src/main/java/org/cryptomator/ui/preferences/AutoStartStrategy.java index 10a431e1f..99b21b4cd 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/preferences/AutoStartStrategy.java +++ b/main/ui/src/main/java/org/cryptomator/ui/preferences/AutoStartStrategy.java @@ -21,11 +21,4 @@ public interface AutoStartStrategy { } } - class TogglingAutoStartWithPowershellFailedException extends TogglingAutoStartFailedException { - - public TogglingAutoStartWithPowershellFailedException(String message, Throwable cause) { - super(message, cause); - } - - } } diff --git a/main/ui/src/main/java/org/cryptomator/ui/preferences/AutoStartWinStrategy.java b/main/ui/src/main/java/org/cryptomator/ui/preferences/AutoStartWinStrategy.java index 02e4faa26..0d2f20536 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/preferences/AutoStartWinStrategy.java +++ b/main/ui/src/main/java/org/cryptomator/ui/preferences/AutoStartWinStrategy.java @@ -1,87 +1,185 @@ package org.cryptomator.ui.preferences; -import org.cryptomator.common.Environment; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.NoSuchFileException; +import java.nio.file.Path; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionStage; +import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; -import java.util.stream.Collectors; +/** + * OS specific class to check, en- and disable the auto start on Windows. + *

+ * Two strategies are implemented for this feature, the first uses the registry and the second one the autostart folder. + *

+ * To check if it is enabled at all, both locations are checked. + * To enable it, first the registry is tried and only on failure the autostart folder is used. + * To disable it, first it is determined, which strategies must be used and in the second step those are executed. + * + * @apiNote This class is not thread safe, hence it should be avoided to be used simultaniously by the same threads. + */ class AutoStartWinStrategy implements AutoStartStrategy { private static final Logger LOG = LoggerFactory.getLogger(AutoStartWinStrategy.class); private static final String HKCU_AUTOSTART_KEY = "\"HKCU\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run\""; private static final String AUTOSTART_VALUE = "Cryptomator"; + private static final String WINDOWS_START_MENU_ENTRY = "\\AppData\\Roaming\\Microsoft\\Windows\\Start Menu\\Programs\\Cryptomator.lnk"; + private final String exePath; - private static final String WINDOWS_START_MENU_FOLDER = "\\AppData\\Roaming\\Microsoft\\Windows\\Start Menu\\Programs"; + + private boolean activatedOverFolder; + private boolean activatedOverRegistry; public AutoStartWinStrategy(String exePath) { this.exePath = exePath; + this.activatedOverFolder = false; + this.activatedOverRegistry = false; } @Override public CompletionStage isAutoStartEnabled() { + return isAutoStartEnabledOverRegistry().thenCombine(isAutoStartEnabledOverFolder(), (bReg, bFolder) -> bReg || bFolder); + } + + private CompletableFuture isAutoStartEnabledOverFolder() { + Path autoStartEntry = Path.of(System.getProperty("user.home") + WINDOWS_START_MENU_ENTRY); + this.activatedOverFolder = Files.exists(autoStartEntry); + return CompletableFuture.completedFuture(activatedOverFolder); + } + + private CompletableFuture isAutoStartEnabledOverRegistry() { ProcessBuilder regQuery = new ProcessBuilder("reg", "query", HKCU_AUTOSTART_KEY, // "/v", AUTOSTART_VALUE); try { Process proc = regQuery.start(); - return proc.onExit().thenApply(p -> p.exitValue() == 0); + return proc.onExit().thenApply(p -> { + this.activatedOverRegistry = p.exitValue() == 0; + return activatedOverRegistry; + }); } catch (IOException e) { - LOG.warn("Failed to query {} from registry key {}", AUTOSTART_VALUE, HKCU_AUTOSTART_KEY); + LOG.debug("Failed to query {} from registry key {}", AUTOSTART_VALUE, HKCU_AUTOSTART_KEY); return CompletableFuture.completedFuture(false); } } @Override public void enableAutoStart() throws TogglingAutoStartFailedException { + try { + enableAutoStartOverRegistry().thenAccept((Void v) -> this.activatedOverRegistry = true).exceptionallyCompose(e -> { + LOG.debug("Falling back to using autostart folder."); + return this.enableAutoStartOverFolder(); + }).thenAccept((Void v) -> this.activatedOverFolder = true).get(); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new TogglingAutoStartFailedException("Execution of enabling auto start setting was interrupted."); + } catch (ExecutionException e) { + throw new TogglingAutoStartFailedException("Enabling auto start failed both over registry and auto start folder."); + } + } + + private CompletableFuture enableAutoStartOverRegistry() { ProcessBuilder regAdd = new ProcessBuilder("reg", "add", HKCU_AUTOSTART_KEY, // "/v", AUTOSTART_VALUE, // "/t", "REG_SZ", // "/d", "\"" + exePath + "\"", // "/f"); - String command = regAdd.command().stream().collect(Collectors.joining(" ")); try { Process proc = regAdd.start(); - boolean finishedInTime = waitForProcess(proc, 5, TimeUnit.SECONDS); + boolean finishedInTime = waitForProcessOrCancel(proc, 5, TimeUnit.SECONDS); if (finishedInTime && proc.exitValue() == 0) { LOG.debug("Added {} to registry key {}.", AUTOSTART_VALUE, HKCU_AUTOSTART_KEY); + return CompletableFuture.completedFuture(null); } else { - LOG.debug("Registry could not be edited. Error code was {}.", proc.exitValue()); - addShortcutOfAppToAutostartFolder(); - throw new TogglingAutoStartFailedException("Adding registry value failed."); + throw new IOException("Process existed with error code " + proc.exitValue()); } } catch (IOException e) { - addShortcutOfAppToAutostartFolder(); - throw new TogglingAutoStartFailedException("Adding registry value failed. " + command, e); + LOG.debug("Registry could not be edited to set auto start.", e); + return CompletableFuture.failedFuture(new SystemCommandException("Adding registry value failed.")); } } + private CompletableFuture enableAutoStartOverFolder() { + String autoStartFolderEntry = System.getProperty("user.home") + WINDOWS_START_MENU_ENTRY; + String createShortcutCommand = "$s=(New-Object -COM WScript.Shell).CreateShortcut('" + autoStartFolderEntry + "');$s.TargetPath='" + exePath + "';$s.Save();"; + ProcessBuilder shortcutAdd = new ProcessBuilder("cmd", "/c", "Start powershell " + createShortcutCommand); + try { + Process proc = shortcutAdd.start(); + boolean finishedInTime = waitForProcessOrCancel(proc, 5, TimeUnit.SECONDS); + if (finishedInTime && proc.exitValue() == 0) { + LOG.debug("Created file {} for auto start.", autoStartFolderEntry); + return CompletableFuture.completedFuture(null); + } else { + throw new IOException("Process existed with error code " + proc.exitValue()); + } + } catch (IOException e) { + LOG.debug("Adding entry to auto start folder failed.", e); + return CompletableFuture.failedFuture(new SystemCommandException("Adding entry to auto start folder failed.")); + } + } + + @Override public void disableAutoStart() throws TogglingAutoStartFailedException { - ProcessBuilder regRemove = new ProcessBuilder("reg", "delete", HKCU_AUTOSTART_KEY, // - "/v", AUTOSTART_VALUE, // - "/f"); - String command = regRemove.command().stream().collect(Collectors.joining(" ")); - try { - Process proc = regRemove.start(); - boolean finishedInTime = waitForProcess(proc, 5, TimeUnit.SECONDS); - if (finishedInTime && proc.exitValue() == 0) { - LOG.debug("Removed {} from registry key {}.", AUTOSTART_VALUE, HKCU_AUTOSTART_KEY); - } else { - LOG.debug("Registry could not be edited. Error code was {}.", proc.exitValue()); - removeShortcutOfAppFromAutostartFolder(); - throw new TogglingAutoStartFailedException("Removing registry value failed."); - } - } catch (IOException e) { - removeShortcutOfAppFromAutostartFolder(); - throw new TogglingAutoStartFailedException("Removing registry value failed. " + command, e); + if (activatedOverRegistry) { + disableAutoStartOverRegistry().whenComplete((voit, ex) -> { + if (ex == null) { + this.activatedOverRegistry = false; + } + }); + } + + if (activatedOverFolder) { + disableAutoStartOverFolder().whenComplete((voit, ex) -> { + if (ex == null) { + this.activatedOverFolder = false; + } + }); + } + + if (activatedOverRegistry || activatedOverFolder) { + throw new TogglingAutoStartFailedException("Disabling auto start failed both over registry and auto start folder."); } } - private static boolean waitForProcess(Process proc, int timeout, TimeUnit timeUnit) { + public CompletableFuture disableAutoStartOverRegistry() { + ProcessBuilder regRemove = new ProcessBuilder("reg", "delete", HKCU_AUTOSTART_KEY, // + "/v", AUTOSTART_VALUE, // + "/f"); + try { + Process proc = regRemove.start(); + boolean finishedInTime = waitForProcessOrCancel(proc, 5, TimeUnit.SECONDS); + if (finishedInTime && proc.exitValue() == 0) { + LOG.debug("Removed {} from registry key {}.", AUTOSTART_VALUE, HKCU_AUTOSTART_KEY); + return CompletableFuture.completedFuture(null); + } else { + throw new IOException("Process existed with error code " + proc.exitValue()); + } + } catch (IOException e) { + LOG.debug("Registry could not be edited to remove auto start.", e); + return CompletableFuture.failedFuture(new SystemCommandException("Removing registry value failed.")); + } + } + + private CompletableFuture disableAutoStartOverFolder() { + try { + Files.delete(Path.of(WINDOWS_START_MENU_ENTRY)); + LOG.debug("Successfully deleted {}.", WINDOWS_START_MENU_ENTRY); + return CompletableFuture.completedFuture(null); + } catch (NoSuchFileException e) { + //that is also okay + return CompletableFuture.completedFuture(null); + } catch (IOException e) { + LOG.debug("Failed to delete entry from auto start folder.", e); + return CompletableFuture.failedFuture(e); + } + } + + private static boolean waitForProcessOrCancel(Process proc, int timeout, TimeUnit timeUnit) { boolean finishedInTime = false; try { finishedInTime = proc.waitFor(timeout, timeUnit); @@ -96,26 +194,11 @@ class AutoStartWinStrategy implements AutoStartStrategy { return finishedInTime; } - private void addShortcutOfAppToAutostartFolder() throws TogglingAutoStartWithPowershellFailedException { - String startMenuDirectory = System.getProperty("user.home") + WINDOWS_START_MENU_FOLDER + "\\Cryptomator.lnk"; - String createShortcutCommand = "$s=(New-Object -COM WScript.Shell).CreateShortcut('" + startMenuDirectory + "');$s.TargetPath='" + exePath + "';$s.Save();"; - ProcessBuilder shortcutAdd = new ProcessBuilder("cmd", "/c", "Start powershell " + createShortcutCommand); - try { - shortcutAdd.start(); - } catch (IOException e) { - throw new TogglingAutoStartWithPowershellFailedException("Adding shortcut to autostart folder failed.", e); + public class SystemCommandException extends RuntimeException { + + public SystemCommandException(String msg) { + super(msg); } } - private void removeShortcutOfAppFromAutostartFolder() throws TogglingAutoStartWithPowershellFailedException { - String startMenuDirectory = System.getProperty("user.home") + WINDOWS_START_MENU_FOLDER + "\\Cryptomator.lnk"; - ProcessBuilder shortcutRemove = new ProcessBuilder("cmd", "/c del \"" + startMenuDirectory + "\""); - try { - shortcutRemove.start(); - } catch (IOException e) { - throw new TogglingAutoStartWithPowershellFailedException("Removing shortcut from autostart folder failed.", e); - } - } - - } From 921b70ebaa21ffa963164a3d56062336ab18082f Mon Sep 17 00:00:00 2001 From: Sebastian Stenzel Date: Tue, 18 Aug 2020 10:36:55 +0200 Subject: [PATCH 14/32] updated webdav dependencies (cherry picked from commit 8c4d35d3db98c190861bfa5420a4f52036d2e510) --- main/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main/pom.xml b/main/pom.xml index 5f0d7e5ea..9a55f782a 100644 --- a/main/pom.xml +++ b/main/pom.xml @@ -28,7 +28,7 @@ 2.2.2 1.2.3 1.1.15 - 1.0.11 + 1.0.12 14 From 1d38ee2fcb620abf8b8d3f60133d740d97c4faab Mon Sep 17 00:00:00 2001 From: infeo Date: Thu, 20 Aug 2020 13:49:31 +0200 Subject: [PATCH 15/32] Further improvements: * corrected bad english * improved documentation * restricted visibility of specific exception --- .../ui/preferences/AutoStartWinStrategy.java | 67 ++++++++++--------- 1 file changed, 35 insertions(+), 32 deletions(-) diff --git a/main/ui/src/main/java/org/cryptomator/ui/preferences/AutoStartWinStrategy.java b/main/ui/src/main/java/org/cryptomator/ui/preferences/AutoStartWinStrategy.java index 0d2f20536..3f51af849 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/preferences/AutoStartWinStrategy.java +++ b/main/ui/src/main/java/org/cryptomator/ui/preferences/AutoStartWinStrategy.java @@ -17,11 +17,14 @@ import java.util.concurrent.TimeUnit; *

* Two strategies are implemented for this feature, the first uses the registry and the second one the autostart folder. *

- * To check if it is enabled at all, both locations are checked. - * To enable it, first the registry is tried and only on failure the autostart folder is used. - * To disable it, first it is determined, which strategies must be used and in the second step those are executed. + * The registry strategy checks/add/removes at the registry key {@value HKCU_AUTOSTART_KEY} an entry for Cryptomator. + * The folder strategy checks/add/removes at the location {@value WINDOWS_START_MENU_ENTRY}. + *

+ * To check if the feature is active, both strategies are applied. + * To enable the feature, first the registry is tried and only on failure the autostart folder is used. + * To disable it, first it is determined by an internal state, which strategies must be used and in the second step those are executed. * - * @apiNote This class is not thread safe, hence it should be avoided to be used simultaniously by the same threads. + * @apiNote This class is not thread safe, hence it should be avoided to call its methods simultaniously by different threads. */ class AutoStartWinStrategy implements AutoStartStrategy { @@ -32,34 +35,34 @@ class AutoStartWinStrategy implements AutoStartStrategy { private final String exePath; - private boolean activatedOverFolder; - private boolean activatedOverRegistry; + private boolean activatedUsingFolder; + private boolean activatedUsingRegistry; public AutoStartWinStrategy(String exePath) { this.exePath = exePath; - this.activatedOverFolder = false; - this.activatedOverRegistry = false; + this.activatedUsingFolder = false; + this.activatedUsingRegistry = false; } @Override public CompletionStage isAutoStartEnabled() { - return isAutoStartEnabledOverRegistry().thenCombine(isAutoStartEnabledOverFolder(), (bReg, bFolder) -> bReg || bFolder); + return isAutoStartEnabledUsingRegistry().thenCombine(isAutoStartEnabledUsingFolder(), (bReg, bFolder) -> bReg || bFolder); } - private CompletableFuture isAutoStartEnabledOverFolder() { + private CompletableFuture isAutoStartEnabledUsingFolder() { Path autoStartEntry = Path.of(System.getProperty("user.home") + WINDOWS_START_MENU_ENTRY); - this.activatedOverFolder = Files.exists(autoStartEntry); - return CompletableFuture.completedFuture(activatedOverFolder); + this.activatedUsingFolder = Files.exists(autoStartEntry); + return CompletableFuture.completedFuture(activatedUsingFolder); } - private CompletableFuture isAutoStartEnabledOverRegistry() { + private CompletableFuture isAutoStartEnabledUsingRegistry() { ProcessBuilder regQuery = new ProcessBuilder("reg", "query", HKCU_AUTOSTART_KEY, // "/v", AUTOSTART_VALUE); try { Process proc = regQuery.start(); return proc.onExit().thenApply(p -> { - this.activatedOverRegistry = p.exitValue() == 0; - return activatedOverRegistry; + this.activatedUsingRegistry = p.exitValue() == 0; + return activatedUsingRegistry; }); } catch (IOException e) { LOG.debug("Failed to query {} from registry key {}", AUTOSTART_VALUE, HKCU_AUTOSTART_KEY); @@ -70,19 +73,19 @@ class AutoStartWinStrategy implements AutoStartStrategy { @Override public void enableAutoStart() throws TogglingAutoStartFailedException { try { - enableAutoStartOverRegistry().thenAccept((Void v) -> this.activatedOverRegistry = true).exceptionallyCompose(e -> { + enableAutoStartUsingRegistry().thenAccept((Void v) -> this.activatedUsingRegistry = true).exceptionallyCompose(e -> { LOG.debug("Falling back to using autostart folder."); - return this.enableAutoStartOverFolder(); - }).thenAccept((Void v) -> this.activatedOverFolder = true).get(); + return this.enableAutoStartUsingFolder(); + }).thenAccept((Void v) -> this.activatedUsingFolder = true).get(); } catch (InterruptedException e) { Thread.currentThread().interrupt(); throw new TogglingAutoStartFailedException("Execution of enabling auto start setting was interrupted."); } catch (ExecutionException e) { - throw new TogglingAutoStartFailedException("Enabling auto start failed both over registry and auto start folder."); + throw new TogglingAutoStartFailedException("Enabling auto start failed both using registry and auto start folder."); } } - private CompletableFuture enableAutoStartOverRegistry() { + private CompletableFuture enableAutoStartUsingRegistry() { ProcessBuilder regAdd = new ProcessBuilder("reg", "add", HKCU_AUTOSTART_KEY, // "/v", AUTOSTART_VALUE, // "/t", "REG_SZ", // @@ -103,7 +106,7 @@ class AutoStartWinStrategy implements AutoStartStrategy { } } - private CompletableFuture enableAutoStartOverFolder() { + private CompletableFuture enableAutoStartUsingFolder() { String autoStartFolderEntry = System.getProperty("user.home") + WINDOWS_START_MENU_ENTRY; String createShortcutCommand = "$s=(New-Object -COM WScript.Shell).CreateShortcut('" + autoStartFolderEntry + "');$s.TargetPath='" + exePath + "';$s.Save();"; ProcessBuilder shortcutAdd = new ProcessBuilder("cmd", "/c", "Start powershell " + createShortcutCommand); @@ -125,28 +128,28 @@ class AutoStartWinStrategy implements AutoStartStrategy { @Override public void disableAutoStart() throws TogglingAutoStartFailedException { - if (activatedOverRegistry) { - disableAutoStartOverRegistry().whenComplete((voit, ex) -> { + if (activatedUsingRegistry) { + disableAutoStartUsingRegistry().whenComplete((voit, ex) -> { if (ex == null) { - this.activatedOverRegistry = false; + this.activatedUsingRegistry = false; } }); } - if (activatedOverFolder) { - disableAutoStartOverFolder().whenComplete((voit, ex) -> { + if (activatedUsingFolder) { + disableAutoStartUsingFolder().whenComplete((voit, ex) -> { if (ex == null) { - this.activatedOverFolder = false; + this.activatedUsingFolder = false; } }); } - if (activatedOverRegistry || activatedOverFolder) { - throw new TogglingAutoStartFailedException("Disabling auto start failed both over registry and auto start folder."); + if (activatedUsingRegistry || activatedUsingFolder) { + throw new TogglingAutoStartFailedException("Disabling auto start failed both using registry and auto start folder."); } } - public CompletableFuture disableAutoStartOverRegistry() { + public CompletableFuture disableAutoStartUsingRegistry() { ProcessBuilder regRemove = new ProcessBuilder("reg", "delete", HKCU_AUTOSTART_KEY, // "/v", AUTOSTART_VALUE, // "/f"); @@ -165,7 +168,7 @@ class AutoStartWinStrategy implements AutoStartStrategy { } } - private CompletableFuture disableAutoStartOverFolder() { + private CompletableFuture disableAutoStartUsingFolder() { try { Files.delete(Path.of(WINDOWS_START_MENU_ENTRY)); LOG.debug("Successfully deleted {}.", WINDOWS_START_MENU_ENTRY); @@ -194,7 +197,7 @@ class AutoStartWinStrategy implements AutoStartStrategy { return finishedInTime; } - public class SystemCommandException extends RuntimeException { + private class SystemCommandException extends RuntimeException { public SystemCommandException(String msg) { super(msg); From 06f4e160d671306b2b360f73c9f05189773db25c Mon Sep 17 00:00:00 2001 From: infeo Date: Thu, 20 Aug 2020 21:25:54 +0200 Subject: [PATCH 16/32] Migrate to easybind fork --- main/commons/pom.xml | 2 +- .../org/cryptomator/common/CommonsModule.java | 2 +- .../common/settings/VaultSettings.java | 2 +- main/pom.xml | 4 ++-- main/ui/pom.xml | 2 +- .../ui/common/NewPasswordController.java | 2 +- .../ui/controls/DraggableListCell.java | 2 +- .../controls/PasswordStrengthIndicator.java | 2 +- .../ui/mainwindow/VaultDetailController.java | 22 ++++++++++++------- .../VaultDetailLockedController.java | 2 +- .../VaultDetailUnknownErrorController.java | 16 +++++++++----- .../mainwindow/VaultListCellController.java | 22 ++++++++++++------- .../main/resources/license/THIRD-PARTY.txt | 2 +- 13 files changed, 50 insertions(+), 32 deletions(-) diff --git a/main/commons/pom.xml b/main/commons/pom.xml index 54e711559..a6d00c2db 100644 --- a/main/commons/pom.xml +++ b/main/commons/pom.xml @@ -44,7 +44,7 @@ - org.fxmisc.easybind + com.tobiasdiez easybind diff --git a/main/commons/src/main/java/org/cryptomator/common/CommonsModule.java b/main/commons/src/main/java/org/cryptomator/common/CommonsModule.java index bac0114da..93e0d3d44 100644 --- a/main/commons/src/main/java/org/cryptomator/common/CommonsModule.java +++ b/main/commons/src/main/java/org/cryptomator/common/CommonsModule.java @@ -5,6 +5,7 @@ *******************************************************************************/ package org.cryptomator.common; +import com.tobiasdiez.easybind.EasyBind; import dagger.Module; import dagger.Provides; import javafx.beans.binding.Binding; @@ -17,7 +18,6 @@ import org.cryptomator.common.vaults.Vault; import org.cryptomator.common.vaults.VaultComponent; import org.cryptomator.common.vaults.VaultListManager; import org.cryptomator.frontend.webdav.WebDavServer; -import org.fxmisc.easybind.EasyBind; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/main/commons/src/main/java/org/cryptomator/common/settings/VaultSettings.java b/main/commons/src/main/java/org/cryptomator/common/settings/VaultSettings.java index 13a0c8eed..a440b2bab 100644 --- a/main/commons/src/main/java/org/cryptomator/common/settings/VaultSettings.java +++ b/main/commons/src/main/java/org/cryptomator/common/settings/VaultSettings.java @@ -7,6 +7,7 @@ package org.cryptomator.common.settings; import com.google.common.base.Strings; import com.google.common.io.BaseEncoding; +import com.tobiasdiez.easybind.EasyBind; import javafx.beans.Observable; import javafx.beans.property.BooleanProperty; import javafx.beans.property.IntegerProperty; @@ -17,7 +18,6 @@ import javafx.beans.property.SimpleObjectProperty; import javafx.beans.property.SimpleStringProperty; import javafx.beans.property.StringProperty; import org.apache.commons.lang3.StringUtils; -import org.fxmisc.easybind.EasyBind; import java.nio.file.Path; import java.util.Objects; diff --git a/main/pom.xml b/main/pom.xml index 0e9dd8a26..e08f71378 100644 --- a/main/pom.xml +++ b/main/pom.xml @@ -35,7 +35,7 @@ 3.11 1.1.0 3.10.3 - 1.0.3 + 2.1.0 29.0-jre 2.22 2.8.6 @@ -178,7 +178,7 @@ - org.fxmisc.easybind + com.tobiasdiez easybind ${easybind.version} diff --git a/main/ui/pom.xml b/main/ui/pom.xml index c27fbb1aa..0991215cc 100644 --- a/main/ui/pom.xml +++ b/main/ui/pom.xml @@ -35,7 +35,7 @@ - org.fxmisc.easybind + com.tobiasdiez easybind diff --git a/main/ui/src/main/java/org/cryptomator/ui/common/NewPasswordController.java b/main/ui/src/main/java/org/cryptomator/ui/common/NewPasswordController.java index 24f3ac8db..6a14272e7 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/common/NewPasswordController.java +++ b/main/ui/src/main/java/org/cryptomator/ui/common/NewPasswordController.java @@ -1,5 +1,6 @@ package org.cryptomator.ui.common; +import com.tobiasdiez.easybind.EasyBind; import javafx.beans.Observable; import javafx.beans.binding.Bindings; import javafx.beans.binding.BooleanBinding; @@ -10,7 +11,6 @@ import javafx.fxml.FXML; import javafx.scene.control.Label; import org.cryptomator.ui.controls.FontAwesome5IconView; import org.cryptomator.ui.controls.NiceSecurePasswordField; -import org.fxmisc.easybind.EasyBind; import java.util.ResourceBundle; diff --git a/main/ui/src/main/java/org/cryptomator/ui/controls/DraggableListCell.java b/main/ui/src/main/java/org/cryptomator/ui/controls/DraggableListCell.java index 62f87c1f4..ca78bcac6 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/controls/DraggableListCell.java +++ b/main/ui/src/main/java/org/cryptomator/ui/controls/DraggableListCell.java @@ -8,6 +8,7 @@ *******************************************************************************/ package org.cryptomator.ui.controls; +import com.tobiasdiez.easybind.EasyBind; import javafx.beans.property.BooleanProperty; import javafx.beans.property.SimpleBooleanProperty; import javafx.scene.SnapshotParameters; @@ -18,7 +19,6 @@ import javafx.scene.input.DragEvent; import javafx.scene.input.Dragboard; import javafx.scene.input.MouseEvent; import javafx.scene.input.TransferMode; -import org.fxmisc.easybind.EasyBind; import java.util.List; diff --git a/main/ui/src/main/java/org/cryptomator/ui/controls/PasswordStrengthIndicator.java b/main/ui/src/main/java/org/cryptomator/ui/controls/PasswordStrengthIndicator.java index a1619968b..156da3b0b 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/controls/PasswordStrengthIndicator.java +++ b/main/ui/src/main/java/org/cryptomator/ui/controls/PasswordStrengthIndicator.java @@ -1,12 +1,12 @@ package org.cryptomator.ui.controls; +import com.tobiasdiez.easybind.EasyBind; import javafx.beans.binding.BooleanBinding; import javafx.beans.property.IntegerProperty; import javafx.beans.property.SimpleIntegerProperty; import javafx.scene.layout.HBox; import javafx.scene.layout.Priority; import javafx.scene.layout.Region; -import org.fxmisc.easybind.EasyBind; public class PasswordStrengthIndicator extends HBox { diff --git a/main/ui/src/main/java/org/cryptomator/ui/mainwindow/VaultDetailController.java b/main/ui/src/main/java/org/cryptomator/ui/mainwindow/VaultDetailController.java index 36a746039..e384a67bc 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/mainwindow/VaultDetailController.java +++ b/main/ui/src/main/java/org/cryptomator/ui/mainwindow/VaultDetailController.java @@ -1,5 +1,6 @@ package org.cryptomator.ui.mainwindow; +import com.tobiasdiez.easybind.EasyBind; import javafx.beans.binding.Binding; import javafx.beans.binding.BooleanBinding; import javafx.beans.property.ObjectProperty; @@ -10,7 +11,6 @@ import org.cryptomator.common.vaults.VaultState; import org.cryptomator.ui.common.FxController; import org.cryptomator.ui.controls.FontAwesome5Icon; import org.cryptomator.ui.fxapp.FxApplication; -import org.fxmisc.easybind.EasyBind; import javax.inject.Inject; @@ -26,17 +26,23 @@ public class VaultDetailController implements FxController { VaultDetailController(ObjectProperty vault, FxApplication application) { this.vault = vault; this.application = application; - this.glyph = EasyBind.select(vault).selectObject(Vault::stateProperty).map(this::getGlyphForVaultState).orElse(FontAwesome5Icon.EXCLAMATION_TRIANGLE); + this.glyph = EasyBind.select(vault) // + .selectObject(Vault::stateProperty) // + .map(this::getGlyphForVaultState); this.anyVaultSelected = vault.isNotNull(); } private FontAwesome5Icon getGlyphForVaultState(VaultState state) { - return switch (state) { - case LOCKED -> FontAwesome5Icon.LOCK; - case PROCESSING -> FontAwesome5Icon.SPINNER; - case UNLOCKED -> FontAwesome5Icon.LOCK_OPEN; - case NEEDS_MIGRATION, MISSING, ERROR -> FontAwesome5Icon.EXCLAMATION_TRIANGLE; - }; + if (state != null) { + return switch (state) { + case LOCKED -> FontAwesome5Icon.LOCK; + case PROCESSING -> FontAwesome5Icon.SPINNER; + case UNLOCKED -> FontAwesome5Icon.LOCK_OPEN; + case NEEDS_MIGRATION, MISSING, ERROR -> FontAwesome5Icon.EXCLAMATION_TRIANGLE; + }; + } else { + return FontAwesome5Icon.EXCLAMATION_TRIANGLE; + } } @FXML diff --git a/main/ui/src/main/java/org/cryptomator/ui/mainwindow/VaultDetailLockedController.java b/main/ui/src/main/java/org/cryptomator/ui/mainwindow/VaultDetailLockedController.java index 55720521b..f615d51ca 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/mainwindow/VaultDetailLockedController.java +++ b/main/ui/src/main/java/org/cryptomator/ui/mainwindow/VaultDetailLockedController.java @@ -1,5 +1,6 @@ package org.cryptomator.ui.mainwindow; +import com.tobiasdiez.easybind.EasyBind; import javafx.beans.binding.BooleanExpression; import javafx.beans.property.ObjectProperty; import javafx.beans.property.ReadOnlyObjectProperty; @@ -11,7 +12,6 @@ import org.cryptomator.keychain.KeychainManager; import org.cryptomator.ui.common.FxController; import org.cryptomator.ui.fxapp.FxApplication; import org.cryptomator.ui.vaultoptions.VaultOptionsComponent; -import org.fxmisc.easybind.EasyBind; import javax.inject.Inject; import java.util.Optional; diff --git a/main/ui/src/main/java/org/cryptomator/ui/mainwindow/VaultDetailUnknownErrorController.java b/main/ui/src/main/java/org/cryptomator/ui/mainwindow/VaultDetailUnknownErrorController.java index 4c23ba4ae..b975174f8 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/mainwindow/VaultDetailUnknownErrorController.java +++ b/main/ui/src/main/java/org/cryptomator/ui/mainwindow/VaultDetailUnknownErrorController.java @@ -1,10 +1,10 @@ package org.cryptomator.ui.mainwindow; +import com.tobiasdiez.easybind.EasyBind; import javafx.beans.binding.Binding; import javafx.beans.property.ObjectProperty; import org.cryptomator.common.vaults.Vault; import org.cryptomator.ui.common.FxController; -import org.fxmisc.easybind.EasyBind; import javax.inject.Inject; import java.io.ByteArrayOutputStream; @@ -18,14 +18,20 @@ public class VaultDetailUnknownErrorController implements FxController { @Inject public VaultDetailUnknownErrorController(ObjectProperty vault) { - this.stackTrace = EasyBind.select(vault).selectObject(Vault::lastKnownExceptionProperty).map(this::provideStackTrace).orElse(""); + this.stackTrace = EasyBind.select(vault) // + .selectObject(Vault::lastKnownExceptionProperty) // + .map(this::provideStackTrace); } private String provideStackTrace(Throwable cause) { // TODO deduplicate ErrorModule.java - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - cause.printStackTrace(new PrintStream(baos)); - return baos.toString(StandardCharsets.UTF_8); + if (cause != null) { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + cause.printStackTrace(new PrintStream(baos)); + return baos.toString(StandardCharsets.UTF_8); + } else { + return ""; + } } /* Getter/Setter */ diff --git a/main/ui/src/main/java/org/cryptomator/ui/mainwindow/VaultListCellController.java b/main/ui/src/main/java/org/cryptomator/ui/mainwindow/VaultListCellController.java index 6703ec674..999afaaf1 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/mainwindow/VaultListCellController.java +++ b/main/ui/src/main/java/org/cryptomator/ui/mainwindow/VaultListCellController.java @@ -1,5 +1,6 @@ package org.cryptomator.ui.mainwindow; +import com.tobiasdiez.easybind.EasyBind; import javafx.beans.binding.Binding; import javafx.beans.property.ObjectProperty; import javafx.beans.property.SimpleObjectProperty; @@ -7,7 +8,6 @@ import org.cryptomator.common.vaults.Vault; import org.cryptomator.common.vaults.VaultState; import org.cryptomator.ui.common.FxController; import org.cryptomator.ui.controls.FontAwesome5Icon; -import org.fxmisc.easybind.EasyBind; import javax.inject.Inject; @@ -19,16 +19,22 @@ public class VaultListCellController implements FxController { @Inject VaultListCellController() { - this.glyph = EasyBind.select(vault).selectObject(Vault::stateProperty).map(this::getGlyphForVaultState).orElse(FontAwesome5Icon.EXCLAMATION_TRIANGLE); + this.glyph = EasyBind.select(vault) // + .selectObject(Vault::stateProperty) // + .map(this::getGlyphForVaultState); } private FontAwesome5Icon getGlyphForVaultState(VaultState state) { - return switch (state) { - case LOCKED -> FontAwesome5Icon.LOCK; - case PROCESSING -> FontAwesome5Icon.SPINNER; - case UNLOCKED -> FontAwesome5Icon.LOCK_OPEN; - case NEEDS_MIGRATION, MISSING, ERROR -> FontAwesome5Icon.EXCLAMATION_TRIANGLE; - }; + if(state != null){ + return switch (state) { + case LOCKED -> FontAwesome5Icon.LOCK; + case PROCESSING -> FontAwesome5Icon.SPINNER; + case UNLOCKED -> FontAwesome5Icon.LOCK_OPEN; + case NEEDS_MIGRATION, MISSING, ERROR -> FontAwesome5Icon.EXCLAMATION_TRIANGLE; + }; + } else { + return FontAwesome5Icon.EXCLAMATION_TRIANGLE; + } } /* Getter/Setter */ diff --git a/main/ui/src/main/resources/license/THIRD-PARTY.txt b/main/ui/src/main/resources/license/THIRD-PARTY.txt index 58a034c81..4fb29473b 100644 --- a/main/ui/src/main/resources/license/THIRD-PARTY.txt +++ b/main/ui/src/main/resources/license/THIRD-PARTY.txt @@ -84,7 +84,7 @@ Cryptomator uses 52 third-party dependencies under the following licenses: - Checker Qual (org.checkerframework:checker-qual:2.11.1 - https://checkerframework.org) - SLF4J API Module (org.slf4j:slf4j-api:1.7.30 - http://www.slf4j.org) The BSD 2-Clause License: - - EasyBind (org.fxmisc.easybind:easybind:1.0.3 - http://www.fxmisc.org/easybind/) + - EasyBind (com.tobiasdiez:easybind:2.1.0 - https://github.com/tobiasdiez/EasyBind) Cryptomator uses other third-party assets under the following licenses: SIL OFL 1.1 License: From 4723416d45464744c877e52d6aaac7cefad602f6 Mon Sep 17 00:00:00 2001 From: Tobias Hagemann Date: Fri, 21 Aug 2020 10:13:45 +0200 Subject: [PATCH 17/32] fixed icon views of labels in new password screen that could only appear once --- .../ui/common/NewPasswordController.java | 16 +++++++++------- .../ui/src/main/resources/fxml/new_password.fxml | 8 +++++--- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/main/ui/src/main/java/org/cryptomator/ui/common/NewPasswordController.java b/main/ui/src/main/java/org/cryptomator/ui/common/NewPasswordController.java index 24f3ac8db..19e33f7c3 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/common/NewPasswordController.java +++ b/main/ui/src/main/java/org/cryptomator/ui/common/NewPasswordController.java @@ -24,10 +24,12 @@ public class NewPasswordController implements FxController { public NiceSecurePasswordField passwordField; public NiceSecurePasswordField reenterField; public Label passwordStrengthLabel; + public FontAwesome5IconView passwordStrengthCheckmark; + public FontAwesome5IconView passwordStrengthWarning; + public FontAwesome5IconView passwordStrengthCross; public Label passwordMatchLabel; - public FontAwesome5IconView checkmark; - public FontAwesome5IconView warning; - public FontAwesome5IconView cross; + public FontAwesome5IconView passwordMatchCheckmark; + public FontAwesome5IconView passwordMatchCross; public NewPasswordController(ResourceBundle resourceBundle, PasswordStrengthUtil strengthRater, ObjectProperty password) { this.resourceBundle = resourceBundle; @@ -45,7 +47,7 @@ public class NewPasswordController implements FxController { BooleanBinding passwordsMatch = Bindings.createBooleanBinding(this::hasSamePasswordInBothFields, passwordField.textProperty(), reenterField.textProperty()); BooleanBinding reenterFieldNotEmpty = reenterField.textProperty().isNotEmpty(); passwordMatchLabel.visibleProperty().bind(reenterFieldNotEmpty); - passwordMatchLabel.graphicProperty().bind(Bindings.when(passwordsMatch.and(reenterFieldNotEmpty)).then(checkmark).otherwise(cross)); + passwordMatchLabel.graphicProperty().bind(Bindings.when(passwordsMatch.and(reenterFieldNotEmpty)).then(passwordMatchCheckmark).otherwise(passwordMatchCross)); passwordMatchLabel.textProperty().bind(Bindings.when(passwordsMatch.and(reenterFieldNotEmpty)).then(resourceBundle.getString("newPassword.passwordsMatch")).otherwise(resourceBundle.getString("newPassword.passwordsDoNotMatch"))); passwordField.textProperty().addListener(this::passwordsDidChange); @@ -56,11 +58,11 @@ public class NewPasswordController implements FxController { if (passwordField.getCharacters().length() == 0) { return null; } else if (passwordStrength.intValue() <= -1) { - return cross; + return passwordStrengthCross; } else if (passwordStrength.intValue() < 3) { - return warning; + return passwordStrengthWarning; } else { - return checkmark; + return passwordStrengthCheckmark; } } diff --git a/main/ui/src/main/resources/fxml/new_password.fxml b/main/ui/src/main/resources/fxml/new_password.fxml index 7593a1ccd..c406b8c70 100644 --- a/main/ui/src/main/resources/fxml/new_password.fxml +++ b/main/ui/src/main/resources/fxml/new_password.fxml @@ -12,9 +12,11 @@ spacing="6" alignment="CENTER_LEFT"> - - - + + + + +