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}/libslinux,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-accessprepare-packagecopy-dependencies${project.build.directory}/linux-libs
- dbus-java,secret-service,hkdf,java-utils
+ dbus-java,secret-service,kdewallet,hkdf,java-utils
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.tobiasdiezeasybind
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 baf63ce1f..2a90b969b 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,7 +7,10 @@ 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.binding.Bindings;
+import javafx.beans.binding.StringBinding;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.ObjectProperty;
@@ -17,7 +20,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;
@@ -34,7 +36,6 @@ public class VaultSettings {
public static final boolean DEFAULT_USES_INDIVIDUAL_MOUNTPATH = false;
public static final boolean DEFAULT_USES_READONLY_MODE = false;
public static final String DEFAULT_MOUNT_FLAGS = "";
- public static final String DEFAULT_MOUNT_NAME = "Vault";
public static final int DEFAULT_FILENAME_LENGTH_LIMIT = -1;
public static final WhenUnlocked DEFAULT_ACTION_AFTER_UNLOCK = WhenUnlocked.ASK;
@@ -42,7 +43,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);
@@ -53,30 +54,15 @@ 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);
-
- EasyBind.subscribe(path, this::deriveMountNameFromPathOrUseDefault);
+ this.mountName = Bindings.createStringBinding(this::normalizeDisplayName, displayName);
}
Observable[] observables() {
- return new Observable[]{path, mountName, winDriveLetter, unlockAfterStartup, revealAfterMount, useCustomMountPath, customMountPath, usesReadOnlyMode, mountFlags, filenameLengthLimit, actionAfterUnlock};
- }
-
- private void deriveMountNameFromPathOrUseDefault(Path newPath) {
- final boolean mountNameSet = !StringUtils.isBlank(mountName.get());
- final boolean dirnameExists = (newPath != null) && (newPath.getFileName() != null);
-
- if (!mountNameSet && dirnameExists) {
- mountName.set(normalizeMountName(newPath.getFileName().toString()));
- } else if (!mountNameSet && !dirnameExists) {
- 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)
- mountName.set(newPath.getFileName().toString());
- }
- }
+ return new Observable[]{path, displayName, winDriveLetter, unlockAfterStartup, revealAfterMount, useCustomMountPath, customMountPath, usesReadOnlyMode, mountFlags, filenameLengthLimit, actionAfterUnlock};
}
public static VaultSettings withRandomId() {
@@ -89,8 +75,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)) {
@@ -118,7 +105,11 @@ public class VaultSettings {
return path;
}
- public StringProperty mountName() {
+ public StringProperty displayName() {
+ return displayName;
+ }
+
+ public StringBinding mountName() {
return mountName;
}
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..04a352a49 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("displayName").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());
@@ -37,7 +37,8 @@ class VaultSettingsJsonAdapter {
public VaultSettings read(JsonReader in) throws IOException {
String id = null;
String path = null;
- String mountName = null;
+ String mountName = null; //see https://github.com/cryptomator/cryptomator/pull/1318
+ String displayName = null;
String customMountPath = null;
String winDriveLetter = null;
boolean unlockAfterStartup = VaultSettings.DEFAULT_UNLOCK_AFTER_STARTUP;
@@ -54,7 +55,8 @@ class VaultSettingsJsonAdapter {
switch (name) {
case "id" -> id = in.nextString();
case "path" -> path = in.nextString();
- case "mountName" -> mountName = in.nextString();
+ case "mountName" -> mountName = in.nextString(); //see https://github.com/cryptomator/cryptomator/pull/1318
+ case "displayName" -> displayName = in.nextString();
case "winDriveLetter" -> winDriveLetter = in.nextString();
case "unlockAfterStartup" -> unlockAfterStartup = in.nextBoolean();
case "revealAfterMount" -> revealAfterMount = in.nextBoolean();
@@ -73,7 +75,11 @@ class VaultSettingsJsonAdapter {
in.endObject();
VaultSettings vaultSettings = (id == null) ? VaultSettings.withRandomId() : new VaultSettings(id);
- vaultSettings.mountName().set(mountName);
+ if (displayName != null) { //see https://github.com/cryptomator/cryptomator/pull/1318
+ vaultSettings.displayName().set(displayName);
+ } else {
+ 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 e65b3f0f9..20b1e69d3 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
@@ -36,9 +36,9 @@ public class DokanyVolume extends AbstractVolume {
@Override
public void mount(CryptoFileSystem fs, String mountFlags) throws InvalidMountPointException, VolumeException {
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());
+ 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/Vault.java b/main/commons/src/main/java/org/cryptomator/common/vaults/Vault.java
index 34433db0e..d63ab0330 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
@@ -57,7 +57,7 @@ public class Vault {
private final ObjectProperty state;
private final ObjectProperty lastKnownException;
private final VaultStats stats;
- private final StringBinding displayableName;
+ private final StringBinding displayName;
private final StringBinding displayablePath;
private final BooleanBinding locked;
private final BooleanBinding processing;
@@ -79,7 +79,7 @@ public class Vault {
this.state = state;
this.lastKnownException = lastKnownException;
this.stats = stats;
- this.displayableName = Bindings.createStringBinding(this::getDisplayableName, vaultSettings.path());
+ this.displayName = Bindings.createStringBinding(this::getDisplayName, vaultSettings.displayName());
this.displayablePath = Bindings.createStringBinding(this::getDisplayablePath, vaultSettings.path());
this.locked = Bindings.createBooleanBinding(this::isLocked, state);
this.processing = Bindings.createBooleanBinding(this::isProcessing, state);
@@ -223,13 +223,12 @@ public class Vault {
return state.get() == VaultState.ERROR;
}
- public StringBinding displayableNameProperty() {
- return displayableName;
+ public StringBinding displayNameProperty() {
+ return displayName;
}
- public String getDisplayableName() {
- Path p = vaultSettings.path().get();
- return p.getFileName().toString();
+ public String getDisplayName() {
+ return vaultSettings.displayName().get();
}
public StringBinding accessPointProperty() {
diff --git a/main/commons/src/main/java/org/cryptomator/common/vaults/VaultListManager.java b/main/commons/src/main/java/org/cryptomator/common/vaults/VaultListManager.java
index 75a48c6fc..a670acab5 100644
--- a/main/commons/src/main/java/org/cryptomator/common/vaults/VaultListManager.java
+++ b/main/commons/src/main/java/org/cryptomator/common/vaults/VaultListManager.java
@@ -20,11 +20,11 @@ import org.slf4j.LoggerFactory;
import javax.inject.Inject;
import javax.inject.Singleton;
import java.io.IOException;
-import java.nio.file.Files;
import java.nio.file.NoSuchFileException;
import java.nio.file.Path;
import java.util.Collection;
import java.util.Optional;
+import java.util.ResourceBundle;
import java.util.stream.Collectors;
import static org.cryptomator.common.Constants.MASTERKEY_FILENAME;
@@ -36,10 +36,12 @@ public class VaultListManager {
private final VaultComponent.Builder vaultComponentBuilder;
private final ObservableList vaultList;
+ private final String defaultVaultName;
@Inject
- public VaultListManager(VaultComponent.Builder vaultComponentBuilder, Settings settings) {
+ public VaultListManager(VaultComponent.Builder vaultComponentBuilder, ResourceBundle resourceBundle, Settings settings) {
this.vaultComponentBuilder = vaultComponentBuilder;
+ this.defaultVaultName = resourceBundle.getString("defaults.vault.vaultName");
this.vaultList = FXCollections.observableArrayList(Vault::observables);
addAll(settings.getDirectories());
@@ -59,14 +61,23 @@ public class VaultListManager {
if (alreadyExistingVault.isPresent()) {
return alreadyExistingVault.get();
} else {
- VaultSettings vaultSettings = VaultSettings.withRandomId();
- vaultSettings.path().set(normalizedPathToVault);
- Vault newVault = create(vaultSettings);
+ Vault newVault = create(newVaultSettings(normalizedPathToVault));
vaultList.add(newVault);
return newVault;
}
}
+ private VaultSettings newVaultSettings(Path path) {
+ VaultSettings vaultSettings = VaultSettings.withRandomId();
+ vaultSettings.path().set(path);
+ if (path.getFileName() != null) {
+ vaultSettings.displayName().set(path.getFileName().toString());
+ } else {
+ vaultSettings.displayName().set(defaultVaultName);
+ }
+ return vaultSettings;
+ }
+
private void addAll(Collection vaultSettings) {
Collection vaults = vaultSettings.stream().map(this::create).collect(Collectors.toList());
vaultList.addAll(vaults);
@@ -92,7 +103,7 @@ public class VaultListManager {
}
return compBuilder.build().vault();
}
-
+
public static VaultState redetermineVaultState(Vault vault) {
VaultState previousState = vault.getState();
return switch (previousState) {
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 caf347602..28aa7527a 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
@@ -12,9 +12,7 @@ import javafx.beans.binding.StringBinding;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.ReadOnlyBooleanProperty;
-import javafx.beans.property.ReadOnlyStringProperty;
import javafx.beans.property.SimpleObjectProperty;
-import javafx.beans.property.StringProperty;
import org.apache.commons.lang3.SystemUtils;
import org.cryptomator.common.settings.Settings;
import org.cryptomator.common.settings.VaultSettings;
@@ -77,7 +75,7 @@ public class VaultModule {
@DefaultMountFlags
public StringBinding provideDefaultMountFlags(Settings settings, VaultSettings vaultSettings) {
ObjectProperty preferredVolumeImpl = settings.preferredVolumeImpl();
- StringProperty mountName = vaultSettings.mountName();
+ StringBinding mountName = vaultSettings.mountName();
BooleanProperty readOnly = vaultSettings.usesReadOnlyMode();
return Bindings.createStringBinding(() -> {
@@ -97,7 +95,7 @@ public class VaultModule {
}
// see: https://github.com/osxfuse/osxfuse/wiki/Mount-options
- private String getMacFuseDefaultMountFlags(ReadOnlyStringProperty mountName, ReadOnlyBooleanProperty readOnly) {
+ private String getMacFuseDefaultMountFlags(StringBinding mountName, ReadOnlyBooleanProperty readOnly) {
assert SystemUtils.IS_OS_MAC_OSX;
StringBuilder flags = new StringBuilder();
if (readOnly.get()) {
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 ecdb31d88..ddc611649 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
@@ -97,7 +97,7 @@ public class WebDavVolume implements Volume {
@Override
public Optional getMountPoint() {
- return Optional.empty();
+ return Optional.empty(); //TODO
}
@Override
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..a0faee551 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
@@ -23,13 +23,13 @@ public class VaultSettingsJsonAdapterTest {
@Test
public void testDeserialize() throws IOException {
- String json = "{\"id\": \"foo\", \"path\": \"/foo/bar\", \"mountName\": \"test\", \"winDriveLetter\": \"X\", \"shouldBeIgnored\": true, \"individualMountPath\": \"/home/test/crypto\", \"mountFlags\":\"--foo --bar\"}";
+ String json = "{\"id\": \"foo\", \"path\": \"/foo/bar\", \"displayName\": \"test\", \"winDriveLetter\": \"X\", \"shouldBeIgnored\": true, \"individualMountPath\": \"/home/test/crypto\", \"mountFlags\":\"--foo --bar\"}";
JsonReader jsonReader = new JsonReader(new StringReader(json));
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();
@@ -55,7 +55,7 @@ public class VaultSettingsJsonAdapterTest {
} else {
MatcherAssert.assertThat(result, CoreMatchers.containsString("\"path\":\"/foo/bar\""));
}
- MatcherAssert.assertThat(result, CoreMatchers.containsString("\"mountName\":\"mountyMcMountFace\""));
+ MatcherAssert.assertThat(result, CoreMatchers.containsString("\"displayName\":\"mountyMcMountFace\""));
MatcherAssert.assertThat(result, CoreMatchers.containsString("\"mountFlags\":\"--foo --bar\""));
}
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..8ec6dc681 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
@@ -8,19 +8,19 @@
*******************************************************************************/
package org.cryptomator.common.settings;
-import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.CsvSource;
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("汉语"));
+ @ParameterizedTest
+ @CsvSource({"a a,a_a", "ä,a", "Ĉ,C", ":,_", "汉语,_"})
+ public void testNormalize(String test, String expected) {
+ VaultSettings settings = new VaultSettings("id");
+ settings.displayName().setValue(test);
+ assertEquals(expected, settings.normalizeDisplayName());
}
}
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..e4922963b 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
@@ -1,9 +1,9 @@
package org.cryptomator.common.vaults;
+import javafx.beans.binding.Bindings;
import javafx.beans.binding.StringBinding;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleObjectProperty;
-import javafx.beans.property.SimpleStringProperty;
import org.cryptomator.common.settings.Settings;
import org.cryptomator.common.settings.VaultSettings;
import org.cryptomator.common.settings.VolumeImpl;
@@ -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.mountName()).thenReturn(Bindings.createStringBinding(() -> "TEST"));
Mockito.when(vaultSettings.usesReadOnlyMode()).thenReturn(new SimpleBooleanProperty(true));
System.setProperty("user.home", tmpDir.toString());
}
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.openjfxjavafx-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 66%
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..e75d387cb 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 {
+ private static Optional constructKeychainAccess() {
+ 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.LinuxKDEWalletKeychainAccessImpl");
+ 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 0e9dd8a26..8702b89d9 100644
--- a/main/pom.xml
+++ b/main/pom.xml
@@ -34,8 +34,9 @@
143.111.1.0
+ 1.0.13.10.3
- 1.0.3
+ 2.1.029.0-jre2.222.8.6
@@ -168,6 +169,11 @@
secret-service${secret-service.version}
+
+ org.purejava
+ kdewallet
+ ${kdewallet.version}
+
@@ -178,7 +184,7 @@
- org.fxmisc.easybind
+ com.tobiasdiezeasybind${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.tobiasdiezeasybind
diff --git a/main/ui/src/main/java/org/cryptomator/ui/addvaultwizard/CreateNewVaultLocationController.java b/main/ui/src/main/java/org/cryptomator/ui/addvaultwizard/CreateNewVaultLocationController.java
index 5b4549db1..c1f224529 100644
--- a/main/ui/src/main/java/org/cryptomator/ui/addvaultwizard/CreateNewVaultLocationController.java
+++ b/main/ui/src/main/java/org/cryptomator/ui/addvaultwizard/CreateNewVaultLocationController.java
@@ -1,5 +1,6 @@
package org.cryptomator.ui.addvaultwizard;
+import com.tobiasdiez.easybind.EasyBind;
import dagger.Lazy;
import javafx.beans.binding.Bindings;
import javafx.beans.binding.BooleanBinding;
@@ -83,11 +84,11 @@ public class CreateNewVaultLocationController implements FxController {
public void initialize() {
predefinedLocationToggler.selectedToggleProperty().addListener(this::togglePredefinedLocation);
usePresetPath.bind(predefinedLocationToggler.selectedToggleProperty().isNotEqualTo(customRadioButton));
- vaultPath.addListener(this::vaultPathDidChange);
+ EasyBind.subscribe(vaultPath, this::vaultPathDidChange);
}
- private void vaultPathDidChange(@SuppressWarnings("unused") ObservableValue extends Path> observable, @SuppressWarnings("unused") Path oldValue, Path newValue) {
- if (!Files.notExists(newValue)) {
+ private void vaultPathDidChange(Path newValue) {
+ if ( newValue != null && !Files.notExists(newValue)) {
warningText.set(resourceBundle.getString("addvaultwizard.new.fileAlreadyExists"));
} else {
warningText.set(null);
diff --git a/main/ui/src/main/java/org/cryptomator/ui/addvaultwizard/CreateNewVaultPasswordController.java b/main/ui/src/main/java/org/cryptomator/ui/addvaultwizard/CreateNewVaultPasswordController.java
index 2c2f3885a..87152f7b5 100644
--- a/main/ui/src/main/java/org/cryptomator/ui/addvaultwizard/CreateNewVaultPasswordController.java
+++ b/main/ui/src/main/java/org/cryptomator/ui/addvaultwizard/CreateNewVaultPasswordController.java
@@ -32,7 +32,6 @@ import javax.inject.Named;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.nio.channels.WritableByteChannel;
-import java.nio.file.FileAlreadyExistsException;
import java.nio.file.FileSystem;
import java.nio.file.Files;
import java.nio.file.NoSuchFileException;
diff --git a/main/ui/src/main/java/org/cryptomator/ui/changepassword/ChangePasswordController.java b/main/ui/src/main/java/org/cryptomator/ui/changepassword/ChangePasswordController.java
index 2d9998fb1..d357c8451 100644
--- a/main/ui/src/main/java/org/cryptomator/ui/changepassword/ChangePasswordController.java
+++ b/main/ui/src/main/java/org/cryptomator/ui/changepassword/ChangePasswordController.java
@@ -68,7 +68,7 @@ public class ChangePasswordController implements FxController {
public void finish() {
try {
CryptoFileSystemProvider.changePassphrase(vault.getPath(), MASTERKEY_FILENAME, oldPasswordField.getCharacters(), newPassword.get());
- LOG.info("Successfully changed password for {}", vault.getDisplayableName());
+ LOG.info("Successfully changed password for {}", vault.getDisplayName());
window.close();
updatePasswordInSystemkeychain();
} catch (IOException e) {
@@ -85,7 +85,7 @@ public class ChangePasswordController implements FxController {
if (keychain.isPresent()) {
try {
keychain.get().changePassphrase(vault.getId(), CharBuffer.wrap(newPassword.get()));
- LOG.info("Successfully updated password in system keychain for {}", vault.getDisplayableName());
+ LOG.info("Successfully updated password in system keychain for {}", vault.getDisplayName());
} catch (KeychainAccessException e) {
LOG.error("Failed to update password in system keychain.", e);
}
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..310a2379d 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;
@@ -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/java/org/cryptomator/ui/common/VaultService.java b/main/ui/src/main/java/org/cryptomator/ui/common/VaultService.java
index 3e09e1fad..8aadd8c98 100644
--- a/main/ui/src/main/java/org/cryptomator/ui/common/VaultService.java
+++ b/main/ui/src/main/java/org/cryptomator/ui/common/VaultService.java
@@ -44,8 +44,8 @@ public class VaultService {
*/
public Task createRevealTask(Vault vault) {
Task task = new RevealVaultTask(vault);
- task.setOnSucceeded(evt -> LOG.info("Revealed {}", vault.getDisplayableName()));
- task.setOnFailed(evt -> LOG.error("Failed to reveal " + vault.getDisplayableName(), evt.getSource().getException()));
+ task.setOnSucceeded(evt -> LOG.info("Revealed {}", vault.getDisplayName()));
+ task.setOnFailed(evt -> LOG.error("Failed to reveal " + vault.getDisplayName(), evt.getSource().getException()));
return task;
}
@@ -68,8 +68,8 @@ public class VaultService {
*/
public Task createLockTask(Vault vault, boolean forced) {
Task task = new LockVaultTask(vault, forced);
- task.setOnSucceeded(evt -> LOG.info("Locked {}", vault.getDisplayableName()));
- task.setOnFailed(evt -> LOG.error("Failed to lock " + vault.getDisplayableName(), evt.getSource().getException()));
+ task.setOnSucceeded(evt -> LOG.info("Locked {}", vault.getDisplayName()));
+ task.setOnFailed(evt -> LOG.error("Failed to lock " + vault.getDisplayName(), evt.getSource().getException()));
return task;
}
@@ -94,7 +94,7 @@ public class VaultService {
List> lockTasks = vaults.stream().map(v -> new LockVaultTask(v, forced)).collect(Collectors.toUnmodifiableList());
lockTasks.forEach(executorService::execute);
Task> task = new WaitForTasksTask(lockTasks);
- String vaultNames = vaults.stream().map(Vault::getDisplayableName).collect(Collectors.joining(", "));
+ String vaultNames = vaults.stream().map(Vault::getDisplayName).collect(Collectors.joining(", "));
task.setOnSucceeded(evt -> LOG.info("Locked {}", vaultNames));
task.setOnFailed(evt -> LOG.error("Failed to lock vaults " + vaultNames, evt.getSource().getException()));
return task;
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/forgetPassword/ForgetPasswordController.java b/main/ui/src/main/java/org/cryptomator/ui/forgetPassword/ForgetPasswordController.java
index ea1e0530e..008668126 100644
--- a/main/ui/src/main/java/org/cryptomator/ui/forgetPassword/ForgetPasswordController.java
+++ b/main/ui/src/main/java/org/cryptomator/ui/forgetPassword/ForgetPasswordController.java
@@ -41,7 +41,7 @@ public class ForgetPasswordController implements FxController {
if (keychain.isPresent()) {
try {
keychain.get().deletePassphrase(vault.getId());
- LOG.debug("Forgot password for vault {}.", vault.getDisplayableName());
+ LOG.debug("Forgot password for vault {}.", vault.getDisplayName());
confirmedResult.setValue(true);
} catch (KeychainAccessException e) {
LOG.error("Failed to remove entry from system keychain.", e);
diff --git a/main/ui/src/main/java/org/cryptomator/ui/fxapp/FxApplication.java b/main/ui/src/main/java/org/cryptomator/ui/fxapp/FxApplication.java
index 4d80a3451..8402bddf2 100644
--- a/main/ui/src/main/java/org/cryptomator/ui/fxapp/FxApplication.java
+++ b/main/ui/src/main/java/org/cryptomator/ui/fxapp/FxApplication.java
@@ -1,5 +1,6 @@
package org.cryptomator.ui.fxapp;
+import com.tobiasdiez.easybind.EasyBind;
import dagger.Lazy;
import javafx.application.Application;
import javafx.application.Platform;
@@ -64,7 +65,7 @@ public class FxApplication extends Application {
LOG.trace("FxApplication.start()");
Platform.setImplicitExit(false);
- hasVisibleStages.addListener(this::hasVisibleStagesChanged);
+ EasyBind.subscribe(hasVisibleStages, this::hasVisibleStagesChanged);
settings.theme().addListener(this::themeChanged);
loadSelectedStyleSheet(settings.theme().get());
@@ -75,7 +76,7 @@ public class FxApplication extends Application {
throw new UnsupportedOperationException("Use start() instead.");
}
- private void hasVisibleStagesChanged(@SuppressWarnings("unused") ObservableValue extends Boolean> observableValue, @SuppressWarnings("unused") boolean oldValue, boolean newValue) {
+ private void hasVisibleStagesChanged(boolean newValue) {
if (newValue) {
macFunctions.map(MacFunctions::uiState).ifPresent(MacApplicationUiState::transformToForegroundApplication);
} else {
@@ -100,7 +101,7 @@ public class FxApplication extends Application {
public void startUnlockWorkflow(Vault vault, Optional owner) {
Platform.runLater(() -> {
unlockWindowBuilderProvider.get().vault(vault).owner(owner).build().startUnlockWorkflow();
- LOG.debug("Showing UnlockWindow for {}", vault.getDisplayableName());
+ LOG.debug("Showing UnlockWindow for {}", vault.getDisplayName());
});
}
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/java/org/cryptomator/ui/mainwindow/VaultListController.java b/main/ui/src/main/java/org/cryptomator/ui/mainwindow/VaultListController.java
index c0a6c7720..d1aecb19f 100644
--- a/main/ui/src/main/java/org/cryptomator/ui/mainwindow/VaultListController.java
+++ b/main/ui/src/main/java/org/cryptomator/ui/mainwindow/VaultListController.java
@@ -1,16 +1,15 @@
package org.cryptomator.ui.mainwindow;
+import com.tobiasdiez.easybind.EasyBind;
import javafx.beans.binding.Bindings;
import javafx.beans.binding.BooleanBinding;
import javafx.beans.property.ObjectProperty;
-import javafx.beans.value.ObservableValue;
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.scene.control.ListView;
import org.cryptomator.common.vaults.Vault;
import org.cryptomator.common.vaults.VaultListManager;
-import org.cryptomator.common.vaults.VaultState;
import org.cryptomator.ui.addvaultwizard.AddVaultWizardComponent;
import org.cryptomator.ui.common.FxController;
import org.cryptomator.ui.removevault.RemoveVaultComponent;
@@ -18,7 +17,6 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.inject.Inject;
-import java.io.IOException;
@MainWindowScoped
public class VaultListController implements FxController {
@@ -43,7 +41,7 @@ public class VaultListController implements FxController {
this.removeVault = removeVault;
this.noVaultSelected = selectedVault.isNull();
this.emptyVaultList = Bindings.isEmpty(vaults);
- selectedVault.addListener(this::selectedVaultDidChange);
+ EasyBind.subscribe(selectedVault, this::selectedVaultDidChange);
}
public void initialize() {
@@ -60,11 +58,10 @@ public class VaultListController implements FxController {
});
}
- private void selectedVaultDidChange(@SuppressWarnings("unused") ObservableValue extends Vault> observableValue, @SuppressWarnings("unused") Vault oldValue, Vault newValue) {
- if (newValue == null) {
- return;
+ private void selectedVaultDidChange(Vault newValue) {
+ if (newValue != null) {
+ VaultListManager.redetermineVaultState(newValue);
}
- VaultListManager.redetermineVaultState(newValue);
}
@FXML
diff --git a/main/ui/src/main/java/org/cryptomator/ui/migration/MigrationRunController.java b/main/ui/src/main/java/org/cryptomator/ui/migration/MigrationRunController.java
index 3123d4cb2..5233d979b 100644
--- a/main/ui/src/main/java/org/cryptomator/ui/migration/MigrationRunController.java
+++ b/main/ui/src/main/java/org/cryptomator/ui/migration/MigrationRunController.java
@@ -116,10 +116,10 @@ public class MigrationRunController implements FxController {
return migrators.needsMigration(vault.getPath(), MASTERKEY_FILENAME);
}).onSuccess(needsAnotherMigration -> {
if (needsAnotherMigration) {
- LOG.info("Migration of '{}' succeeded, but another migration is required.", vault.getDisplayableName());
+ LOG.info("Migration of '{}' succeeded, but another migration is required.", vault.getDisplayName());
vault.setState(VaultState.NEEDS_MIGRATION);
} else {
- LOG.info("Migration of '{}' succeeded.", vault.getDisplayableName());
+ LOG.info("Migration of '{}' succeeded.", vault.getDisplayName());
vault.setState(VaultState.LOCKED);
passwordField.wipe();
window.setScene(successScene.get());
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..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
@@ -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,7 +13,7 @@ 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) {
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..438c468bd 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
@@ -4,76 +4,185 @@ 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.
+ *
+ * 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 call its methods simultaniously by different 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 boolean activatedUsingFolder;
+ private boolean activatedUsingRegistry;
+
public AutoStartWinStrategy(String exePath) {
this.exePath = exePath;
+ this.activatedUsingFolder = false;
+ this.activatedUsingRegistry = false;
}
@Override
public CompletionStage isAutoStartEnabled() {
+ return isAutoStartEnabledUsingRegistry().thenCombine(isAutoStartEnabledUsingFolder(), (bReg, bFolder) -> bReg || bFolder);
+ }
+
+ private CompletableFuture isAutoStartEnabledUsingFolder() {
+ Path autoStartEntry = Path.of(System.getProperty("user.home") + WINDOWS_START_MENU_ENTRY);
+ this.activatedUsingFolder = Files.exists(autoStartEntry);
+ return CompletableFuture.completedFuture(activatedUsingFolder);
+ }
+
+ 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 -> p.exitValue() == 0);
+ return proc.onExit().thenApply(p -> {
+ this.activatedUsingRegistry = p.exitValue() == 0;
+ return activatedUsingRegistry;
+ });
} 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 {
+ enableAutoStartUsingRegistry().thenAccept((Void v) -> this.activatedUsingRegistry = true).exceptionallyCompose(e -> {
+ LOG.debug("Falling back to using autostart folder.");
+ 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 using registry and auto start folder.");
+ }
+ }
+
+ private CompletableFuture enableAutoStartUsingRegistry() {
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);
- if (finishedInTime) {
+ 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 {
- throw new TogglingAutoStartFailedException("Adding registry value failed.");
+ throw new IOException("Process exited with error code " + proc.exitValue());
}
} catch (IOException e) {
- 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 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);
+ 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 exited 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) {
- LOG.debug("Removed {} from registry key {}.", AUTOSTART_VALUE, HKCU_AUTOSTART_KEY);
- } else {
- throw new TogglingAutoStartFailedException("Removing registry value failed.");
- }
- } catch (IOException e) {
- throw new TogglingAutoStartFailedException("Removing registry value failed. " + command, e);
+ if (activatedUsingRegistry) {
+ disableAutoStartUsingRegistry().whenComplete((voit, ex) -> {
+ if (ex == null) {
+ this.activatedUsingRegistry = false;
+ }
+ });
+ }
+
+ if (activatedUsingFolder) {
+ disableAutoStartUsingFolder().whenComplete((voit, ex) -> {
+ if (ex == null) {
+ this.activatedUsingFolder = false;
+ }
+ });
+ }
+
+ if (activatedUsingRegistry || activatedUsingFolder) {
+ throw new TogglingAutoStartFailedException("Disabling auto start failed using registry and/or auto start folder.");
}
}
- private static boolean waitForProcess(Process proc, int timeout, TimeUnit timeUnit) {
+ public CompletableFuture disableAutoStartUsingRegistry() {
+ 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 exited 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 disableAutoStartUsingFolder() {
+ 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);
@@ -88,4 +197,11 @@ class AutoStartWinStrategy implements AutoStartStrategy {
return finishedInTime;
}
+ private class SystemCommandException extends RuntimeException {
+
+ public SystemCommandException(String msg) {
+ super(msg);
+ }
+ }
+
}
diff --git a/main/ui/src/main/java/org/cryptomator/ui/quit/QuitController.java b/main/ui/src/main/java/org/cryptomator/ui/quit/QuitController.java
index 66dd13ade..7255115ea 100644
--- a/main/ui/src/main/java/org/cryptomator/ui/quit/QuitController.java
+++ b/main/ui/src/main/java/org/cryptomator/ui/quit/QuitController.java
@@ -53,7 +53,7 @@ public class QuitController implements FxController {
Task> lockAllTask = vaultService.createLockAllTask(unlockedVaults, false);
lockAllTask.setOnSucceeded(evt -> {
- LOG.info("Locked {}", lockAllTask.getValue().stream().map(Vault::getDisplayableName).collect(Collectors.joining(", ")));
+ LOG.info("Locked {}", lockAllTask.getValue().stream().map(Vault::getDisplayName).collect(Collectors.joining(", ")));
if (unlockedVaults.isEmpty()) {
window.close();
response.performQuit();
diff --git a/main/ui/src/main/java/org/cryptomator/ui/recoverykey/RecoveryKeyModule.java b/main/ui/src/main/java/org/cryptomator/ui/recoverykey/RecoveryKeyModule.java
index 48e81f3a5..9ad3d73ad 100644
--- a/main/ui/src/main/java/org/cryptomator/ui/recoverykey/RecoveryKeyModule.java
+++ b/main/ui/src/main/java/org/cryptomator/ui/recoverykey/RecoveryKeyModule.java
@@ -9,7 +9,6 @@ import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.scene.Scene;
-import javafx.scene.image.Image;
import javafx.stage.Modality;
import javafx.stage.Stage;
import org.cryptomator.common.vaults.Vault;
@@ -25,7 +24,6 @@ import org.cryptomator.ui.common.StageFactory;
import javax.inject.Named;
import javax.inject.Provider;
-import java.util.List;
import java.util.Map;
import java.util.ResourceBundle;
@@ -107,7 +105,7 @@ abstract class RecoveryKeyModule {
@IntoMap
@FxControllerKey(RecoveryKeyDisplayController.class)
static FxController provideRecoveryKeyDisplayController(@RecoveryKeyWindow Stage window, @RecoveryKeyWindow Vault vault, @RecoveryKeyWindow StringProperty recoveryKey, ResourceBundle localization) {
- return new RecoveryKeyDisplayController(window, vault.getDisplayableName(), recoveryKey.get(), localization);
+ return new RecoveryKeyDisplayController(window, vault.getDisplayName(), recoveryKey.get(), localization);
}
@Binds
diff --git a/main/ui/src/main/java/org/cryptomator/ui/removevault/RemoveVaultController.java b/main/ui/src/main/java/org/cryptomator/ui/removevault/RemoveVaultController.java
index e2d5ec024..836ed519f 100644
--- a/main/ui/src/main/java/org/cryptomator/ui/removevault/RemoveVaultController.java
+++ b/main/ui/src/main/java/org/cryptomator/ui/removevault/RemoveVaultController.java
@@ -34,7 +34,7 @@ public class RemoveVaultController implements FxController {
@FXML
public void finish() {
vaults.remove(vault);
- LOG.debug("Removing vault {}.", vault.getDisplayableName());
+ LOG.debug("Removing vault {}.", vault.getDisplayName());
window.close();
}
}
diff --git a/main/ui/src/main/java/org/cryptomator/ui/traymenu/TrayMenuController.java b/main/ui/src/main/java/org/cryptomator/ui/traymenu/TrayMenuController.java
index af12beebe..1610c6862 100644
--- a/main/ui/src/main/java/org/cryptomator/ui/traymenu/TrayMenuController.java
+++ b/main/ui/src/main/java/org/cryptomator/ui/traymenu/TrayMenuController.java
@@ -80,7 +80,7 @@ class TrayMenuController {
}
private Menu buildSubmenu(Vault vault) {
- Menu submenu = new Menu(vault.getDisplayableName());
+ Menu submenu = new Menu(vault.getDisplayName());
if (vault.isLocked()) {
MenuItem unlockItem = new MenuItem(resourceBundle.getString("traymenu.vault.unlock"));
diff --git a/main/ui/src/main/java/org/cryptomator/ui/unlock/UnlockController.java b/main/ui/src/main/java/org/cryptomator/ui/unlock/UnlockController.java
index 7310a369c..537eba9a8 100644
--- a/main/ui/src/main/java/org/cryptomator/ui/unlock/UnlockController.java
+++ b/main/ui/src/main/java/org/cryptomator/ui/unlock/UnlockController.java
@@ -77,7 +77,7 @@ public class UnlockController implements FxController {
this.unlockButtonContentDisplay = Bindings.createObjectBinding(this::getUnlockButtonContentDisplay, passwordEntryLock.awaitingInteraction());
this.userInteractionDisabled = passwordEntryLock.awaitingInteraction().not();
this.unlockButtonDisabled = new SimpleBooleanProperty();
- this.vaultName = WeakBindings.bindString(vault.displayableNameProperty());
+ this.vaultName = WeakBindings.bindString(vault.displayNameProperty());
this.window.setOnCloseRequest(windowEvent -> cancel());
}
diff --git a/main/ui/src/main/java/org/cryptomator/ui/unlock/UnlockModule.java b/main/ui/src/main/java/org/cryptomator/ui/unlock/UnlockModule.java
index e07583c84..bef612dc1 100644
--- a/main/ui/src/main/java/org/cryptomator/ui/unlock/UnlockModule.java
+++ b/main/ui/src/main/java/org/cryptomator/ui/unlock/UnlockModule.java
@@ -82,7 +82,7 @@ abstract class UnlockModule {
@UnlockScoped
static Stage provideStage(StageFactory factory, @UnlockWindow Vault vault, @Named("unlockWindowOwner") Optional owner) {
Stage stage = factory.create();
- stage.setTitle(vault.getDisplayableName());
+ stage.setTitle(vault.getDisplayName());
stage.setResizable(false);
if (owner.isPresent()) {
stage.initOwner(owner.get());
diff --git a/main/ui/src/main/java/org/cryptomator/ui/unlock/UnlockWorkflow.java b/main/ui/src/main/java/org/cryptomator/ui/unlock/UnlockWorkflow.java
index d216fc12b..ea692f783 100644
--- a/main/ui/src/main/java/org/cryptomator/ui/unlock/UnlockWorkflow.java
+++ b/main/ui/src/main/java/org/cryptomator/ui/unlock/UnlockWorkflow.java
@@ -129,7 +129,7 @@ public class UnlockWorkflow extends Task {
}
private void handleSuccess() {
- LOG.info("Unlock of '{}' succeeded.", vault.getDisplayableName());
+ LOG.info("Unlock of '{}' succeeded.", vault.getDisplayName());
if (savePassword.get()) {
savePasswordToSystemkeychain();
}
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 975f40bf3..df3cf7039 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
@@ -43,7 +43,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;
@@ -70,7 +69,6 @@ public class MountOptionsController implements FxController {
@FXML
public void initialize() {
- driveName.textProperty().bindBidirectional(vault.getVaultSettings().mountName());
// readonly:
readOnlyCheckbox.selectedProperty().bindBidirectional(vault.getVaultSettings().usesReadOnlyMode());
diff --git a/main/ui/src/main/java/org/cryptomator/ui/vaultoptions/VaultOptionsModule.java b/main/ui/src/main/java/org/cryptomator/ui/vaultoptions/VaultOptionsModule.java
index d0aa49281..f39af7e34 100644
--- a/main/ui/src/main/java/org/cryptomator/ui/vaultoptions/VaultOptionsModule.java
+++ b/main/ui/src/main/java/org/cryptomator/ui/vaultoptions/VaultOptionsModule.java
@@ -5,7 +5,6 @@ import dagger.Module;
import dagger.Provides;
import dagger.multibindings.IntoMap;
import javafx.scene.Scene;
-import javafx.scene.image.Image;
import javafx.stage.Modality;
import javafx.stage.Stage;
import org.cryptomator.common.vaults.Vault;
@@ -20,9 +19,7 @@ import org.cryptomator.ui.common.StageFactory;
import org.cryptomator.ui.mainwindow.MainWindow;
import org.cryptomator.ui.recoverykey.RecoveryKeyComponent;
-import javax.inject.Named;
import javax.inject.Provider;
-import java.util.List;
import java.util.Map;
import java.util.ResourceBundle;
@@ -41,7 +38,7 @@ abstract class VaultOptionsModule {
@VaultOptionsScoped
static Stage provideStage(StageFactory factory, @MainWindow Stage owner, @VaultOptionsWindow Vault vault) {
Stage stage = factory.create();
- stage.setTitle(vault.getDisplayableName());
+ stage.setTitle(vault.getDisplayName());
stage.setResizable(true);
stage.setMinWidth(400);
stage.setMinHeight(300);
diff --git a/main/ui/src/main/resources/fxml/addvault_success.fxml b/main/ui/src/main/resources/fxml/addvault_success.fxml
index 6bb4808c5..fd0309450 100644
--- a/main/ui/src/main/resources/fxml/addvault_success.fxml
+++ b/main/ui/src/main/resources/fxml/addvault_success.fxml
@@ -30,7 +30,7 @@
-
+
diff --git a/main/ui/src/main/resources/fxml/changepassword.fxml b/main/ui/src/main/resources/fxml/changepassword.fxml
index 07fe7cbc4..18c1b9383 100644
--- a/main/ui/src/main/resources/fxml/changepassword.fxml
+++ b/main/ui/src/main/resources/fxml/changepassword.fxml
@@ -19,7 +19,7 @@
-
+
diff --git a/main/ui/src/main/resources/fxml/migration_run.fxml b/main/ui/src/main/resources/fxml/migration_run.fxml
index 03be9a140..f70f27ce3 100644
--- a/main/ui/src/main/resources/fxml/migration_run.fxml
+++ b/main/ui/src/main/resources/fxml/migration_run.fxml
@@ -21,7 +21,7 @@
-
+
diff --git a/main/ui/src/main/resources/fxml/migration_start.fxml b/main/ui/src/main/resources/fxml/migration_start.fxml
index c568ae9cb..c836a9393 100644
--- a/main/ui/src/main/resources/fxml/migration_start.fxml
+++ b/main/ui/src/main/resources/fxml/migration_start.fxml
@@ -28,7 +28,7 @@
-
+
diff --git a/main/ui/src/main/resources/fxml/migration_success.fxml b/main/ui/src/main/resources/fxml/migration_success.fxml
index 59e997550..9fd081757 100644
--- a/main/ui/src/main/resources/fxml/migration_success.fxml
+++ b/main/ui/src/main/resources/fxml/migration_success.fxml
@@ -25,7 +25,7 @@
-
+
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">
-
-
-
+
+
+
+
+
diff --git a/main/ui/src/main/resources/fxml/recoverykey_create.fxml b/main/ui/src/main/resources/fxml/recoverykey_create.fxml
index c1c7299a1..73775237f 100644
--- a/main/ui/src/main/resources/fxml/recoverykey_create.fxml
+++ b/main/ui/src/main/resources/fxml/recoverykey_create.fxml
@@ -20,7 +20,7 @@
-
+
diff --git a/main/ui/src/main/resources/fxml/recoverykey_recover.fxml b/main/ui/src/main/resources/fxml/recoverykey_recover.fxml
index c1c161a0d..c12a5e83e 100644
--- a/main/ui/src/main/resources/fxml/recoverykey_recover.fxml
+++ b/main/ui/src/main/resources/fxml/recoverykey_recover.fxml
@@ -21,7 +21,7 @@
-
+
diff --git a/main/ui/src/main/resources/fxml/unlock_success.fxml b/main/ui/src/main/resources/fxml/unlock_success.fxml
index 8fb568d70..5ad817cf6 100644
--- a/main/ui/src/main/resources/fxml/unlock_success.fxml
+++ b/main/ui/src/main/resources/fxml/unlock_success.fxml
@@ -28,7 +28,7 @@
-
+
diff --git a/main/ui/src/main/resources/fxml/vault_detail.fxml b/main/ui/src/main/resources/fxml/vault_detail.fxml
index 625ae1e1f..62be6996f 100644
--- a/main/ui/src/main/resources/fxml/vault_detail.fxml
+++ b/main/ui/src/main/resources/fxml/vault_detail.fxml
@@ -26,9 +26,9 @@
-
-
+
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..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,10 +2,11 @@
-
-
+
+
+
+
+
+
+
+
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 e8c1444da..bf65249a5 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 8dddb7feb..18208a9bb 100644
--- a/main/ui/src/main/resources/i18n/strings.properties
+++ b/main/ui/src/main/resources/i18n/strings.properties
@@ -17,6 +17,9 @@ generic.button.print=Print
generic.error.title=An unexpected error occured
generic.error.instruction=This should not have happened. Please report the error text below and include a description of what steps did lead to this error.
+# Defaults
+defaults.vault.vaultName=Vault
+
# Tray Menu
traymenu.showMainWindow=Show
traymenu.showPreferencesWindow=Preferences
@@ -216,6 +219,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
@@ -224,7 +228,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
diff --git a/main/ui/src/main/resources/license/THIRD-PARTY.txt b/main/ui/src/main/resources/license/THIRD-PARTY.txt
index 58a034c81..6b1d42e05 100644
--- a/main/ui/src/main/resources/license/THIRD-PARTY.txt
+++ b/main/ui/src/main/resources/license/THIRD-PARTY.txt
@@ -11,7 +11,7 @@ GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see http://www.gnu.org/licenses/.
-Cryptomator uses 52 third-party dependencies under the following licenses:
+Cryptomator uses 53 third-party dependencies under the following licenses:
Apache License v2.0:
- HKDF-RFC5869 (at.favre.lib:hkdf:1.1.0 - https://github.com/patrickfav/hkdf)
- jffi (com.github.jnr:jffi:1.2.23 - http://github.com/jnr/jffi)
@@ -82,9 +82,10 @@ Cryptomator uses 52 third-party dependencies under the following licenses:
- zxcvbn4j (com.nulab-inc:zxcvbn:1.3.0 - https://github.com/nulab/zxcvbn4j)
- secret-service (de.swiesend:secret-service:1.1.0 - https://github.com/swiesend/secret-service)
- Checker Qual (org.checkerframework:checker-qual:2.11.1 - https://checkerframework.org)
+ - kdewallet (org.purejava:kdewallet:1.0.1 - https://github.com/purejava/kdewallet)
- 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: