diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 8009aeb06..b847d0b4b 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -7,7 +7,6 @@ jobs:
build:
name: Build and Test
runs-on: ubuntu-latest
- #This check is case insensitive
if: "!contains(github.event.head_commit.message, '[ci skip]') && !contains(github.event.head_commit.message, '[skip ci]')"
steps:
- uses: actions/checkout@v2
@@ -29,28 +28,31 @@ jobs:
run: |
curl -o ~/codacy-coverage-reporter.jar https://repo.maven.apache.org/maven2/com/codacy/codacy-coverage-reporter/7.1.0/codacy-coverage-reporter-7.1.0-assembly.jar
$JAVA_HOME/bin/java -jar ~/codacy-coverage-reporter.jar report -l Java -r main/commons/target/site/jacoco/jacoco.xml --partial
- $JAVA_HOME/bin/java -jar ~/codacy-coverage-reporter.jar report -l Java -r main/keychain/target/site/jacoco/jacoco.xml --partial
$JAVA_HOME/bin/java -jar ~/codacy-coverage-reporter.jar report -l Java -r main/ui/target/site/jacoco/jacoco.xml --partial
$JAVA_HOME/bin/java -jar ~/codacy-coverage-reporter.jar report -l Java -r main/launcher/target/site/jacoco/jacoco.xml --partial
$JAVA_HOME/bin/java -jar ~/codacy-coverage-reporter.jar final
env:
CODACY_PROJECT_TOKEN: ${{ secrets.CODACY_PROJECT_TOKEN }}
- - name: Assemble Buildkit
- run: mvn -B package -DskipTests --file main/pom.xml --resume-from=buildkit -Prelease
+ - name: Assemble buildkit-linux.zip
+ run: mvn -B clean package -DskipTests --file main/pom.xml --resume-from=buildkit -Prelease,linux
- name: Upload buildkit-linux.zip
uses: actions/upload-artifact@v1
with:
- name: buildkit-linux.zip
+ name: buildkit-linux
path: main/buildkit/target/buildkit-linux.zip
+ - name: Assemble buildkit-mac.zip
+ run: mvn -B clean package -DskipTests --file main/pom.xml --resume-from=buildkit -Prelease,mac
- name: Upload buildkit-mac.zip
uses: actions/upload-artifact@v1
with:
- name: buildkit-mac.zip
+ name: buildkit-mac
path: main/buildkit/target/buildkit-mac.zip
+ - name: Assemble buildkit-win.zip
+ run: mvn -B clean package -DskipTests --file main/pom.xml --resume-from=buildkit -Prelease,windows
- name: Upload buildkit-win.zip
uses: actions/upload-artifact@v1
with:
- name: buildkit-win.zip
+ name: buildkit-win
path: main/buildkit/target/buildkit-win.zip
release:
diff --git a/main/buildkit/assembly-linux.xml b/main/buildkit/assembly-linux.xml
index 5d8bfc785..0764ada20 100644
--- a/main/buildkit/assembly-linux.xml
+++ b/main/buildkit/assembly-linux.xml
@@ -43,12 +43,5 @@
libs
-
- target/linux-libs
-
- *.jar
-
- libs
-
\ No newline at end of file
diff --git a/main/buildkit/assembly-mac.xml b/main/buildkit/assembly-mac.xml
index c9057dcdd..c7a10f2ef 100644
--- a/main/buildkit/assembly-mac.xml
+++ b/main/buildkit/assembly-mac.xml
@@ -43,12 +43,5 @@
libs
-
- target/mac-libs
-
- *.jar
-
- libs
-
\ No newline at end of file
diff --git a/main/buildkit/assembly-win.xml b/main/buildkit/assembly-win.xml
index 2e81782b3..e0ff7df4b 100644
--- a/main/buildkit/assembly-win.xml
+++ b/main/buildkit/assembly-win.xml
@@ -43,12 +43,5 @@
libs
-
- target/win-libs
-
- *.jar
-
- libs
-
\ No newline at end of file
diff --git a/main/buildkit/pom.xml b/main/buildkit/pom.xml
index 23059eb4a..4dde902b9 100644
--- a/main/buildkit/pom.xml
+++ b/main/buildkit/pom.xml
@@ -24,7 +24,6 @@
org.apache.maven.plugins
maven-resources-plugin
- 3.1.0
copy-resources
@@ -55,8 +54,8 @@
+ org.apache.maven.plugins
maven-dependency-plugin
- 3.1.1
copy-libs
@@ -65,110 +64,153 @@
copy-dependencies
+ runtime
${project.build.directory}/libs
linux,mac,win
- dbus-java,secret-service,kdewallet,hkdf,java-utils
-
-
-
- copy-linux-libs
- prepare-package
-
- copy-dependencies
-
-
- ${project.build.directory}/linux-libs
- org.openjfx
- linux
-
-
-
- copy-linux-system-keychain-access
- prepare-package
-
- copy-dependencies
-
-
- ${project.build.directory}/linux-libs
- dbus-java,secret-service,kdewallet,hkdf,java-utils
-
-
-
- copy-mac-libs
- prepare-package
-
- copy-dependencies
-
-
- ${project.build.directory}/mac-libs
- org.openjfx
- mac
-
-
-
- copy-win-libs
- prepare-package
-
- copy-dependencies
-
-
- ${project.build.directory}/win-libs
- org.openjfx
- win
-
-
-
-
-
-
-
- maven-assembly-plugin
- 3.1.1
-
-
- assemble-linux
- package
-
- single
-
-
-
- assembly-linux.xml
-
- false
- buildkit-linux
-
-
-
- assemble-mac
- package
-
- single
-
-
-
- assembly-mac.xml
-
- false
- buildkit-mac
-
-
-
- assemble-win
- package
-
- single
-
-
-
- assembly-win.xml
-
- false
- buildkit-win
+
+
+
+ linux
+
+
+
+ org.apache.maven.plugins
+ maven-assembly-plugin
+
+
+ assemble-linux
+ package
+
+ single
+
+
+
+ assembly-linux.xml
+
+ false
+ buildkit-linux
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-dependency-plugin
+
+
+ copy-linux-libs
+ prepare-package
+
+ copy-dependencies
+
+
+ ${project.build.directory}/libs
+ org.openjfx
+ linux
+
+
+
+
+
+
+
+
+
+ mac
+
+
+
+ org.apache.maven.plugins
+ maven-assembly-plugin
+
+
+ assemble-mac
+ package
+
+ single
+
+
+
+ assembly-mac.xml
+
+ false
+ buildkit-mac
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-dependency-plugin
+
+
+ copy-mac-libs
+ prepare-package
+
+ copy-dependencies
+
+
+ ${project.build.directory}/libs
+ org.openjfx
+ mac
+
+
+
+
+
+
+
+
+
+ windows
+
+
+
+ org.apache.maven.plugins
+ maven-assembly-plugin
+
+
+ assemble-win
+ package
+
+ single
+
+
+
+ assembly-win.xml
+
+ false
+ buildkit-win
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-dependency-plugin
+
+
+ copy-win-libs
+ prepare-package
+
+ copy-dependencies
+
+
+ ${project.build.directory}/libs
+ org.openjfx
+ win
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/main/commons/pom.xml b/main/commons/pom.xml
index 1927a4889..7eaccf881 100644
--- a/main/commons/pom.xml
+++ b/main/commons/pom.xml
@@ -27,6 +27,10 @@
org.cryptomator
webdav-nio-adapter
+
+ org.cryptomator
+ integrations-api
+
org.cryptomator
jni
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 5ace6a3e2..ed278e1ab 100644
--- a/main/commons/src/main/java/org/cryptomator/common/CommonsModule.java
+++ b/main/commons/src/main/java/org/cryptomator/common/CommonsModule.java
@@ -9,6 +9,7 @@ import com.tobiasdiez.easybind.EasyBind;
import dagger.Module;
import dagger.Provides;
import org.apache.commons.lang3.SystemUtils;
+import org.cryptomator.common.keychain.KeychainModule;
import org.cryptomator.common.settings.Settings;
import org.cryptomator.common.settings.SettingsProvider;
import org.cryptomator.common.vaults.Vault;
@@ -33,7 +34,7 @@ import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
-@Module(subcomponents = {VaultComponent.class})
+@Module(subcomponents = {VaultComponent.class}, includes = {KeychainModule.class})
public abstract class CommonsModule {
private static final Logger LOG = LoggerFactory.getLogger(CommonsModule.class);
diff --git a/main/commons/src/main/java/org/cryptomator/common/JniModule.java b/main/commons/src/main/java/org/cryptomator/common/JniModule.java
index 180736710..aaeda2964 100644
--- a/main/commons/src/main/java/org/cryptomator/common/JniModule.java
+++ b/main/commons/src/main/java/org/cryptomator/common/JniModule.java
@@ -15,6 +15,7 @@ import javax.inject.Singleton;
import java.util.Optional;
@Module
+@Deprecated
public class JniModule {
@Provides
diff --git a/main/keychain/src/main/java/org/cryptomator/keychain/KeychainManager.java b/main/commons/src/main/java/org/cryptomator/common/keychain/KeychainManager.java
similarity index 70%
rename from main/keychain/src/main/java/org/cryptomator/keychain/KeychainManager.java
rename to main/commons/src/main/java/org/cryptomator/common/keychain/KeychainManager.java
index 515195232..537b83577 100644
--- a/main/keychain/src/main/java/org/cryptomator/keychain/KeychainManager.java
+++ b/main/commons/src/main/java/org/cryptomator/common/keychain/KeychainManager.java
@@ -1,60 +1,71 @@
-package org.cryptomator.keychain;
+package org.cryptomator.common.keychain;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import org.cryptomator.integrations.keychain.KeychainAccessException;
+import org.cryptomator.integrations.keychain.KeychainAccessProvider;
+import javax.inject.Inject;
+import javax.inject.Singleton;
import javafx.application.Platform;
+import javafx.beans.binding.ObjectExpression;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.ReadOnlyBooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
import java.util.Arrays;
-public class KeychainManager implements KeychainAccessStrategy {
+@Singleton
+public class KeychainManager implements KeychainAccessProvider {
- private static final Logger LOG = LoggerFactory.getLogger(KeychainManager.class);
+ private final ObjectExpression keychain;
+ private final LoadingCache passphraseStoredProperties;
- private final KeychainAccessStrategy keychain;
- private LoadingCache passphraseStoredProperties;
-
- KeychainManager(KeychainAccessStrategy keychain) {
- assert keychain.isSupported();
- this.keychain = keychain;
+ @Inject
+ KeychainManager(ObjectExpression selectedKeychain) {
+ this.keychain = selectedKeychain;
this.passphraseStoredProperties = CacheBuilder.newBuilder() //
.weakValues() //
.build(CacheLoader.from(this::createStoredPassphraseProperty));
+ keychain.addListener(ignored -> passphraseStoredProperties.invalidateAll());
+ }
+
+ private KeychainAccessProvider getKeychainOrFail() throws KeychainAccessException {
+ var result = keychain.getValue();
+ if (result == null) {
+ throw new NoKeychainAccessProviderException();
+ }
+ return result;
}
@Override
public void storePassphrase(String key, CharSequence passphrase) throws KeychainAccessException {
- keychain.storePassphrase(key, passphrase);
+ getKeychainOrFail().storePassphrase(key, passphrase);
setPassphraseStored(key, true);
}
@Override
public char[] loadPassphrase(String key) throws KeychainAccessException {
- char[] passphrase = keychain.loadPassphrase(key);
+ char[] passphrase = getKeychainOrFail().loadPassphrase(key);
setPassphraseStored(key, passphrase != null);
return passphrase;
}
@Override
public void deletePassphrase(String key) throws KeychainAccessException {
- keychain.deletePassphrase(key);
+ getKeychainOrFail().deletePassphrase(key);
setPassphraseStored(key, false);
}
@Override
public void changePassphrase(String key, CharSequence passphrase) throws KeychainAccessException {
- keychain.changePassphrase(key, passphrase);
+ getKeychainOrFail().changePassphrase(key, passphrase);
setPassphraseStored(key, true);
}
@Override
public boolean isSupported() {
- return true;
+ return keychain.getValue() != null;
}
/**
@@ -69,7 +80,7 @@ public class KeychainManager implements KeychainAccessStrategy {
public boolean isPassphraseStored(String key) throws KeychainAccessException {
char[] storedPw = null;
try {
- storedPw = keychain.loadPassphrase(key);
+ storedPw = getKeychainOrFail().loadPassphrase(key);
return storedPw != null;
} finally {
if (storedPw != null) {
@@ -84,7 +95,6 @@ public class KeychainManager implements KeychainAccessStrategy {
if (Platform.isFxApplicationThread()) {
property.set(value);
} else {
- LOG.warn("");
Platform.runLater(() -> property.set(value));
}
}
@@ -107,7 +117,6 @@ public class KeychainManager implements KeychainAccessStrategy {
private BooleanProperty createStoredPassphraseProperty(String key) {
try {
- LOG.warn("LOAD"); // TODO remove
return new SimpleBooleanProperty(isPassphraseStored(key));
} catch (KeychainAccessException e) {
return new SimpleBooleanProperty(false);
diff --git a/main/commons/src/main/java/org/cryptomator/common/keychain/KeychainModule.java b/main/commons/src/main/java/org/cryptomator/common/keychain/KeychainModule.java
new file mode 100644
index 000000000..9ac343d36
--- /dev/null
+++ b/main/commons/src/main/java/org/cryptomator/common/keychain/KeychainModule.java
@@ -0,0 +1,44 @@
+package org.cryptomator.common.keychain;
+
+import dagger.Module;
+import dagger.Provides;
+import org.cryptomator.common.settings.Settings;
+import org.cryptomator.integrations.keychain.KeychainAccessProvider;
+
+import javax.inject.Singleton;
+import javafx.beans.binding.Bindings;
+import javafx.beans.binding.ObjectExpression;
+import java.util.ServiceLoader;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+@Module
+public class KeychainModule {
+
+ @Provides
+ @Singleton
+ static Set> provideAvailableKeychainAccessProviderFactories() {
+ return ServiceLoader.load(KeychainAccessProvider.class).stream().collect(Collectors.toUnmodifiableSet());
+ }
+
+ @Provides
+ @Singleton
+ static Set provideSupportedKeychainAccessProviders(Set> availableFactories) {
+ return availableFactories.stream() //
+ .map(ServiceLoader.Provider::get) //
+ .filter(KeychainAccessProvider::isSupported) //
+ .collect(Collectors.toUnmodifiableSet());
+ }
+
+ @Provides
+ @Singleton
+ static ObjectExpression provideKeychainAccessProvider(Settings settings, Set providers) {
+ return Bindings.createObjectBinding(() -> {
+ var selectedProviderClass = settings.keychainBackend().get().getProviderClass();
+ var selectedProvider = providers.stream().filter(provider -> provider.getClass().getName().equals(selectedProviderClass)).findAny();
+ var fallbackProvider = providers.stream().findAny().orElse(null);
+ return selectedProvider.orElse(fallbackProvider);
+ }, settings.keychainBackend());
+ }
+
+}
diff --git a/main/commons/src/main/java/org/cryptomator/common/keychain/NoKeychainAccessProviderException.java b/main/commons/src/main/java/org/cryptomator/common/keychain/NoKeychainAccessProviderException.java
new file mode 100644
index 000000000..c14b81076
--- /dev/null
+++ b/main/commons/src/main/java/org/cryptomator/common/keychain/NoKeychainAccessProviderException.java
@@ -0,0 +1,13 @@
+package org.cryptomator.common.keychain;
+
+import org.cryptomator.integrations.keychain.KeychainAccessException;
+
+/**
+ * Thrown by {@link KeychainManager} if attempted to access a keychain despite no supported keychain access provider being available.
+ */
+public class NoKeychainAccessProviderException extends KeychainAccessException {
+
+ public NoKeychainAccessProviderException() {
+ super("Did not find any supported keychain access provider.");
+ }
+}
diff --git a/main/commons/src/main/java/org/cryptomator/common/settings/KeychainBackend.java b/main/commons/src/main/java/org/cryptomator/common/settings/KeychainBackend.java
index a54c81b08..65f869a12 100644
--- a/main/commons/src/main/java/org/cryptomator/common/settings/KeychainBackend.java
+++ b/main/commons/src/main/java/org/cryptomator/common/settings/KeychainBackend.java
@@ -1,39 +1,19 @@
package org.cryptomator.common.settings;
-import org.apache.commons.lang3.SystemUtils;
-
-import java.util.Arrays;
-
public enum KeychainBackend {
- GNOME("preferences.general.keychainBackend.gnome", SystemUtils.IS_OS_LINUX), //
- KDE("preferences.general.keychainBackend.kde", SystemUtils.IS_OS_LINUX), //
- MAC_SYSTEM_KEYCHAIN("preferences.general.keychainBackend.macSystemKeychain", SystemUtils.IS_OS_MAC), //
- WIN_SYSTEM_KEYCHAIN("preferences.general.keychainBackend.winSystemKeychain", SystemUtils.IS_OS_WINDOWS);
+ GNOME("org.cryptomator.linux.keychain.SecretServiceKeychainAccess"),
+ KDE("org.cryptomator.linux.keychain.KDEWalletKeychainAccess"),
+ MAC_SYSTEM_KEYCHAIN("org.cryptomator.macos.keychain.MacSystemKeychainAccess"),
+ WIN_SYSTEM_KEYCHAIN("org.cryptomator.windows.keychain.WindowsProtectedKeychainAccess");
- public static KeychainBackend[] supportedBackends() {
- return Arrays.stream(values()).filter(KeychainBackend::isSupported).toArray(KeychainBackend[]::new);
+ private final String providerClass;
+
+ KeychainBackend(String providerClass) {
+ this.providerClass = providerClass;
}
- public static KeychainBackend defaultBackend() {
- if (SystemUtils.IS_OS_LINUX) {
- return KeychainBackend.GNOME;
- } else { // SystemUtils.IS_OS_MAC || SystemUtils.IS_OS_WINDOWS
- return Arrays.stream(KeychainBackend.supportedBackends()).findFirst().orElseThrow(IllegalStateException::new);
- }
+ public String getProviderClass() {
+ return providerClass;
}
- private final String configName;
- private final boolean isSupported;
-
- KeychainBackend(String configName, boolean isSupported) {
- this.configName = configName;
- this.isSupported = isSupported;
- }
-
- public String getDisplayName() {
- return configName;
- }
-
- public boolean isSupported() { return isSupported; }
-
}
diff --git a/main/commons/src/main/java/org/cryptomator/common/settings/Settings.java b/main/commons/src/main/java/org/cryptomator/common/settings/Settings.java
index 22b42628d..e50391d2d 100644
--- a/main/commons/src/main/java/org/cryptomator/common/settings/Settings.java
+++ b/main/commons/src/main/java/org/cryptomator/common/settings/Settings.java
@@ -8,6 +8,8 @@
******************************************************************************/
package org.cryptomator.common.settings;
+import org.apache.commons.lang3.SystemUtils;
+
import javafx.beans.Observable;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.IntegerProperty;
@@ -33,9 +35,9 @@ public class Settings {
public static final int DEFAULT_NUM_TRAY_NOTIFICATIONS = 3;
public static final WebDavUrlScheme DEFAULT_GVFS_SCHEME = WebDavUrlScheme.DAV;
public static final boolean DEFAULT_DEBUG_MODE = false;
- public static final VolumeImpl DEFAULT_PREFERRED_VOLUME_IMPL = System.getProperty("os.name").toLowerCase().contains("windows") ? VolumeImpl.DOKANY : VolumeImpl.FUSE;
+ public static final VolumeImpl DEFAULT_PREFERRED_VOLUME_IMPL = SystemUtils.IS_OS_WINDOWS ? VolumeImpl.DOKANY : VolumeImpl.FUSE;
public static final UiTheme DEFAULT_THEME = UiTheme.LIGHT;
- public static final KeychainBackend DEFAULT_KEYCHAIN_BACKEND = KeychainBackend.defaultBackend();
+ public static final KeychainBackend DEFAULT_KEYCHAIN_BACKEND = SystemUtils.IS_OS_WINDOWS ? KeychainBackend.WIN_SYSTEM_KEYCHAIN : SystemUtils.IS_OS_MAC ? KeychainBackend.MAC_SYSTEM_KEYCHAIN : KeychainBackend.GNOME;
public static final NodeOrientation DEFAULT_USER_INTERFACE_ORIENTATION = NodeOrientation.LEFT_TO_RIGHT;
private static final String DEFAULT_LICENSE_KEY = "";
diff --git a/main/keychain/src/test/java/org/cryptomator/keychain/KeychainManagerTest.java b/main/commons/src/test/java/org/cryptomator/common/keychain/KeychainManagerTest.java
similarity index 76%
rename from main/keychain/src/test/java/org/cryptomator/keychain/KeychainManagerTest.java
rename to main/commons/src/test/java/org/cryptomator/common/keychain/KeychainManagerTest.java
index 8577b0977..e82e67e2d 100644
--- a/main/keychain/src/test/java/org/cryptomator/keychain/KeychainManagerTest.java
+++ b/main/commons/src/test/java/org/cryptomator/common/keychain/KeychainManagerTest.java
@@ -1,23 +1,26 @@
-package org.cryptomator.keychain;
+package org.cryptomator.common.keychain;
+import org.cryptomator.integrations.keychain.KeychainAccessException;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import javafx.application.Platform;
import javafx.beans.property.ReadOnlyBooleanProperty;
+import javafx.beans.property.SimpleObjectProperty;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
-class KeychainManagerTest {
+public class KeychainManagerTest {
@Test
public void testStoreAndLoad() throws KeychainAccessException {
- KeychainManager keychainManager = new KeychainManager(new MapKeychainAccess());
+ KeychainManager keychainManager = new KeychainManager(new SimpleObjectProperty<>(new MapKeychainAccess()));
keychainManager.storePassphrase("test", "asd");
Assertions.assertArrayEquals("asd".toCharArray(), keychainManager.loadPassphrase("test"));
}
@@ -34,7 +37,7 @@ class KeychainManagerTest {
@Test
public void testPropertyChangesWhenStoringPassword() throws KeychainAccessException, InterruptedException {
- KeychainManager keychainManager = new KeychainManager(new MapKeychainAccess());
+ KeychainManager keychainManager = new KeychainManager(new SimpleObjectProperty<>(new MapKeychainAccess()));
ReadOnlyBooleanProperty property = keychainManager.getPassphraseStoredProperty("test");
Assertions.assertEquals(false, property.get());
diff --git a/main/keychain/src/test/java/org/cryptomator/keychain/MapKeychainAccess.java b/main/commons/src/test/java/org/cryptomator/common/keychain/MapKeychainAccess.java
similarity index 86%
rename from main/keychain/src/test/java/org/cryptomator/keychain/MapKeychainAccess.java
rename to main/commons/src/test/java/org/cryptomator/common/keychain/MapKeychainAccess.java
index 26b301377..c571ad716 100644
--- a/main/keychain/src/test/java/org/cryptomator/keychain/MapKeychainAccess.java
+++ b/main/commons/src/test/java/org/cryptomator/common/keychain/MapKeychainAccess.java
@@ -3,12 +3,14 @@
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the accompanying LICENSE file.
*******************************************************************************/
-package org.cryptomator.keychain;
+package org.cryptomator.common.keychain;
+
+import org.cryptomator.integrations.keychain.KeychainAccessProvider;
import java.util.HashMap;
import java.util.Map;
-class MapKeychainAccess implements KeychainAccessStrategy {
+class MapKeychainAccess implements KeychainAccessProvider {
private final Map map = new HashMap<>();
diff --git a/main/keychain/pom.xml b/main/keychain/pom.xml
deleted file mode 100644
index c70d7cacb..000000000
--- a/main/keychain/pom.xml
+++ /dev/null
@@ -1,69 +0,0 @@
-
-
- 4.0.0
-
- org.cryptomator
- main
- 1.6.0-SNAPSHOT
-
- keychain
- System Keychain Access
-
-
-
- org.cryptomator
- commons
-
-
-
-
- org.openjfx
- javafx-base
-
-
- org.openjfx
- javafx-graphics
-
-
-
-
- org.apache.commons
- commons-lang3
-
-
-
-
- com.google.code.gson
- gson
-
-
- com.google.guava
- guava
-
-
-
-
- com.google.dagger
- dagger
-
-
-
-
- de.swiesend
- secret-service
-
-
-
-
- org.purejava
- kdewallet
-
-
-
-
- org.slf4j
- slf4j-simple
- test
-
-
-
\ No newline at end of file
diff --git a/main/keychain/src/main/java/org/cryptomator/keychain/KeychainAccessException.java b/main/keychain/src/main/java/org/cryptomator/keychain/KeychainAccessException.java
deleted file mode 100644
index b4f0cf5c8..000000000
--- a/main/keychain/src/main/java/org/cryptomator/keychain/KeychainAccessException.java
+++ /dev/null
@@ -1,12 +0,0 @@
-package org.cryptomator.keychain;
-
-/**
- * Indicates an error during communication with the operating system's keychain.
- */
-public class KeychainAccessException extends Exception {
-
- KeychainAccessException(Throwable cause) {
- super(cause);
- }
-
-}
diff --git a/main/keychain/src/main/java/org/cryptomator/keychain/KeychainAccessStrategy.java b/main/keychain/src/main/java/org/cryptomator/keychain/KeychainAccessStrategy.java
deleted file mode 100644
index 553ce4eab..000000000
--- a/main/keychain/src/main/java/org/cryptomator/keychain/KeychainAccessStrategy.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2017 Skymatic UG (haftungsbeschränkt).
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the accompanying LICENSE file.
- *******************************************************************************/
-package org.cryptomator.keychain;
-
-public interface KeychainAccessStrategy {
-
- /**
- * Associates a passphrase with a given key.
- *
- * @param key Key used to retrieve the passphrase via {@link #loadPassphrase(String)}.
- * @param passphrase The secret to store in this keychain.
- */
- void storePassphrase(String key, CharSequence passphrase) throws KeychainAccessException;
-
- /**
- * @param key Unique key previously used while {@link #storePassphrase(String, CharSequence) storing a passphrase}.
- * @return The stored passphrase for the given key or null if no value for the given key could be found.
- */
- char[] loadPassphrase(String key) throws KeychainAccessException;
-
- /**
- * Deletes a passphrase with a given key.
- *
- * @param key Unique key previously used while {@link #storePassphrase(String, CharSequence) storing a passphrase}.
- */
- void deletePassphrase(String key) throws KeychainAccessException;
-
- /**
- * Updates a passphrase with a given key. Noop, if there is no item for the given key.
- *
- * @param key Unique key previously used while {@link #storePassphrase(String, CharSequence) storing a passphrase}.
- * @param passphrase The secret to be updated in this keychain.
- */
- void changePassphrase(String key, CharSequence passphrase) throws KeychainAccessException;
-
- /**
- * @return true if this KeychainAccessStrategy works on the current machine.
- * @implNote This method must not throw any exceptions and should fail fast
- * returning false if it can't determine availability of the checked strategy
- */
- boolean isSupported();
-
-}
diff --git a/main/keychain/src/main/java/org/cryptomator/keychain/KeychainModule.java b/main/keychain/src/main/java/org/cryptomator/keychain/KeychainModule.java
deleted file mode 100644
index 791eb1dd0..000000000
--- a/main/keychain/src/main/java/org/cryptomator/keychain/KeychainModule.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2017 Skymatic UG (haftungsbeschränkt).
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the accompanying LICENSE file.
- *******************************************************************************/
-package org.cryptomator.keychain;
-
-import dagger.Binds;
-import dagger.Module;
-import dagger.Provides;
-import dagger.multibindings.IntoSet;
-import org.cryptomator.common.JniModule;
-
-import javax.inject.Singleton;
-import java.util.Optional;
-import java.util.Set;
-
-@Module(includes = {JniModule.class})
-public abstract class KeychainModule {
-
- @Binds
- @IntoSet
- abstract KeychainAccessStrategy bindMacSystemKeychainAccess(MacSystemKeychainAccess keychainAccessStrategy);
-
- @Binds
- @IntoSet
- abstract KeychainAccessStrategy bindWindowsProtectedKeychainAccess(WindowsProtectedKeychainAccess keychainAccessStrategy);
-
- @Binds
- @IntoSet
- abstract KeychainAccessStrategy bindLinuxSystemKeychainAccess(LinuxSystemKeychainAccess keychainAccessStrategy);
-
- @Provides
- @Singleton
- static Optional provideSupportedKeychain(Set keychainAccessStrategies) {
- return keychainAccessStrategies.stream().filter(KeychainAccessStrategy::isSupported).findFirst();
- }
-
- @Provides
- @Singleton
- public static Optional provideKeychainManager(Optional keychainAccess) {
- return keychainAccess.map(KeychainManager::new);
- }
-
-}
diff --git a/main/keychain/src/main/java/org/cryptomator/keychain/LinuxKDEWalletKeychainAccessImpl.java b/main/keychain/src/main/java/org/cryptomator/keychain/LinuxKDEWalletKeychainAccessImpl.java
deleted file mode 100644
index 1f74bd18d..000000000
--- a/main/keychain/src/main/java/org/cryptomator/keychain/LinuxKDEWalletKeychainAccessImpl.java
+++ /dev/null
@@ -1,126 +0,0 @@
-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 static 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() throws KeychainAccessException {
- try {
- connection = DBusConnection.getConnection(DBusConnection.DBusBusType.SESSION);
- } catch (DBusException e) {
- LOG.error("Connecting to D-Bus failed:", e);
- throw new KeychainAccessException(e);
- }
- }
-
- @Override
- public boolean isSupported() {
- try {
- wallet = new KDEWallet(connection);
- return wallet.isEnabled();
- } catch (Exception e) {
- LOG.error("A KDEWallet could not be created:", e);
- 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("Storing the passphrase failed:", e);
- 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) {
- LOG.error("Loading the passphrase failed:", 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) {
- LOG.error("Deleting the passphrase failed:", 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) {
- LOG.error("Changing the passphrase failed:", 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) {
- LOG.error("Asynchronous opening the wallet failed:", e);
- throw new KeychainAccessException(e);
- }
- }
-}
diff --git a/main/keychain/src/main/java/org/cryptomator/keychain/LinuxSecretServiceKeychainAccessImpl.java b/main/keychain/src/main/java/org/cryptomator/keychain/LinuxSecretServiceKeychainAccessImpl.java
deleted file mode 100644
index e422fff2e..000000000
--- a/main/keychain/src/main/java/org/cryptomator/keychain/LinuxSecretServiceKeychainAccessImpl.java
+++ /dev/null
@@ -1,81 +0,0 @@
-package org.cryptomator.keychain;
-
-import org.freedesktop.secret.simple.SimpleCollection;
-
-import java.io.IOException;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-class LinuxSecretServiceKeychainAccessImpl implements KeychainAccessStrategy {
-
- private final String LABEL_FOR_SECRET_IN_KEYRING = "Cryptomator";
-
- @Override
- public boolean isSupported() {
- try (@SuppressWarnings("unused") SimpleCollection keyring = new SimpleCollection()) {
- // seems like we're able to access the keyring.
- return true;
- } catch (IOException | RuntimeException e) {
- return false;
- }
- }
-
- @Override
- public void storePassphrase(String key, CharSequence passphrase) throws KeychainAccessException {
- try (SimpleCollection keyring = new SimpleCollection()) {
- List list = keyring.getItems(createAttributes(key));
- if (list == null) {
- keyring.createItem(LABEL_FOR_SECRET_IN_KEYRING, passphrase, createAttributes(key));
- } else {
- changePassphrase(key, passphrase);
- }
- } catch (IOException e) {
- throw new KeychainAccessException(e);
- }
- }
-
- @Override
- public char[] loadPassphrase(String key) throws KeychainAccessException {
- try (SimpleCollection keyring = new SimpleCollection()) {
- List list = keyring.getItems(createAttributes(key));
- if (list != null) {
- return keyring.getSecret(list.get(0));
- } else {
- return null;
- }
- } catch (IOException e) {
- throw new KeychainAccessException(e);
- }
- }
-
- @Override
- public void deletePassphrase(String key) throws KeychainAccessException {
- try (SimpleCollection keyring = new SimpleCollection()) {
- List list = keyring.getItems(createAttributes(key));
- if (list != null) {
- keyring.deleteItem(list.get(0));
- }
- } catch (IOException e) {
- throw new KeychainAccessException(e);
- }
- }
-
- @Override
- public void changePassphrase(String key, CharSequence passphrase) throws KeychainAccessException {
- try (SimpleCollection keyring = new SimpleCollection()) {
- List list = keyring.getItems(createAttributes(key));
- if (list != null) {
- keyring.updateItem(list.get(0), LABEL_FOR_SECRET_IN_KEYRING, passphrase, createAttributes(key));
- }
- } catch (IOException e) {
- throw new KeychainAccessException(e);
- }
- }
-
- private Map createAttributes(String key) {
- Map attributes = new HashMap();
- attributes.put("Vault", key);
- return attributes;
- }
-}
diff --git a/main/keychain/src/main/java/org/cryptomator/keychain/LinuxSystemKeychainAccess.java b/main/keychain/src/main/java/org/cryptomator/keychain/LinuxSystemKeychainAccess.java
deleted file mode 100644
index f49ea5d1d..000000000
--- a/main/keychain/src/main/java/org/cryptomator/keychain/LinuxSystemKeychainAccess.java
+++ /dev/null
@@ -1,106 +0,0 @@
-package org.cryptomator.keychain;
-
-import javafx.beans.property.ObjectProperty;
-import org.apache.commons.lang3.SystemUtils;
-import org.cryptomator.common.settings.KeychainBackend;
-import org.cryptomator.common.settings.Settings;
-
-import javax.inject.Inject;
-import javax.inject.Singleton;
-import java.util.EnumSet;
-import java.util.Optional;
-
-/**
- * A facade to LinuxSecretServiceKeychainAccessImpl and LinuxKDEWalletKeychainAccessImpl
- * that depend on libraries that are unavailable on Mac and Windows.
- */
-@Singleton
-public class LinuxSystemKeychainAccess implements KeychainAccessStrategy {
-
- // 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;
- private final Settings settings;
- private static EnumSet availableKeychainBackends = EnumSet.noneOf(KeychainBackend.class);
- private static KeychainBackend backendActivated = null;
- private static boolean isGnomeKeyringAvailable;
- private static boolean isKdeWalletAvailable;
-
- @Inject
- public LinuxSystemKeychainAccess(Settings settings) {
- this.settings = settings;
- this.delegate = constructKeychainAccess();
- }
-
- private Optional constructKeychainAccess() {
- try { // find out which backends are available
- Class> clazz = Class.forName("org.cryptomator.keychain.LinuxSecretServiceKeychainAccessImpl");
- KeychainAccessStrategy gnomeKeyring = (KeychainAccessStrategy) clazz.getDeclaredConstructor().newInstance();
- if (gnomeKeyring.isSupported()) {
- LinuxSystemKeychainAccess.availableKeychainBackends.add(KeychainBackend.GNOME);
- LinuxSystemKeychainAccess.isGnomeKeyringAvailable = true;
- }
- clazz = Class.forName("org.cryptomator.keychain.LinuxKDEWalletKeychainAccessImpl");
- KeychainAccessStrategy kdeWallet = (KeychainAccessStrategy) clazz.getDeclaredConstructor().newInstance();
- if (kdeWallet.isSupported()) {
- LinuxSystemKeychainAccess.availableKeychainBackends.add(KeychainBackend.KDE);
- LinuxSystemKeychainAccess.isKdeWalletAvailable = true;
- }
-
- // load password backend setting as the preferred backend
- ObjectProperty pwSetting = settings.keychainBackend();
-
- // check for GNOME keyring first, as this gets precedence over
- // KDE wallet as the former was implemented first
- if (isGnomeKeyringAvailable && pwSetting.get().equals(KeychainBackend.GNOME)) {
- pwSetting.setValue(KeychainBackend.GNOME);
- LinuxSystemKeychainAccess.backendActivated = KeychainBackend.GNOME;
- return Optional.of(gnomeKeyring);
- }
-
- if (isKdeWalletAvailable && pwSetting.get().equals(KeychainBackend.KDE)) {
- pwSetting.setValue(KeychainBackend.KDE);
- LinuxSystemKeychainAccess.backendActivated = KeychainBackend.KDE;
- return Optional.of(kdeWallet);
- }
- return Optional.empty();
- } catch (Exception e) {
- return Optional.empty();
- }
- }
-
- /* Getter/Setter */
-
- public static EnumSet getAvailableKeychainBackends() {
- return availableKeychainBackends;
- }
-
- public static KeychainBackend getBackendActivated() {
- return backendActivated;
- }
-
- @Override
- public boolean isSupported() {
- return SystemUtils.IS_OS_LINUX && delegate.map(KeychainAccessStrategy::isSupported).orElse(false);
- }
-
- @Override
- public void storePassphrase(String key, CharSequence passphrase) throws KeychainAccessException {
- delegate.orElseThrow(IllegalStateException::new).storePassphrase(key, passphrase);
- }
-
- @Override
- public char[] loadPassphrase(String key) throws KeychainAccessException {
- return delegate.orElseThrow(IllegalStateException::new).loadPassphrase(key);
- }
-
- @Override
- public void deletePassphrase(String key) throws KeychainAccessException {
- delegate.orElseThrow(IllegalStateException::new).deletePassphrase(key);
- }
-
- @Override
- public void changePassphrase(String key, CharSequence passphrase) throws KeychainAccessException {
- delegate.orElseThrow(IllegalStateException::new).changePassphrase(key, passphrase);
- }
-}
diff --git a/main/keychain/src/main/java/org/cryptomator/keychain/MacSystemKeychainAccess.java b/main/keychain/src/main/java/org/cryptomator/keychain/MacSystemKeychainAccess.java
deleted file mode 100644
index 39a6cd756..000000000
--- a/main/keychain/src/main/java/org/cryptomator/keychain/MacSystemKeychainAccess.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2017 Skymatic UG (haftungsbeschränkt).
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the accompanying LICENSE file.
- *******************************************************************************/
-package org.cryptomator.keychain;
-
-import org.apache.commons.lang3.SystemUtils;
-import org.cryptomator.jni.MacFunctions;
-import org.cryptomator.jni.MacKeychainAccess;
-
-import javax.inject.Inject;
-import javax.inject.Singleton;
-import java.util.Optional;
-
-@Singleton
-class MacSystemKeychainAccess implements KeychainAccessStrategy {
-
- private final Optional macFunctions;
-
- @Inject
- public MacSystemKeychainAccess(Optional macFunctions) {
- this.macFunctions = macFunctions;
- }
-
- private MacKeychainAccess keychain() {
- return macFunctions.orElseThrow(IllegalStateException::new).keychainAccess();
- }
-
- @Override
- public void storePassphrase(String key, CharSequence passphrase) {
- keychain().storePassword(key, passphrase);
- }
-
- @Override
- public char[] loadPassphrase(String key) {
- return keychain().loadPassword(key);
- }
-
- @Override
- public boolean isSupported() {
- return SystemUtils.IS_OS_MAC_OSX && macFunctions.isPresent();
- }
-
- @Override
- public void deletePassphrase(String key) {
- keychain().deletePassword(key);
- }
-
- @Override
- public void changePassphrase(String key, CharSequence passphrase) {
- if (keychain().deletePassword(key)) {
- keychain().storePassword(key, passphrase);
- }
- }
-
-}
diff --git a/main/keychain/src/main/java/org/cryptomator/keychain/WindowsProtectedKeychainAccess.java b/main/keychain/src/main/java/org/cryptomator/keychain/WindowsProtectedKeychainAccess.java
deleted file mode 100644
index 6668104a4..000000000
--- a/main/keychain/src/main/java/org/cryptomator/keychain/WindowsProtectedKeychainAccess.java
+++ /dev/null
@@ -1,209 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2017 Skymatic UG (haftungsbeschränkt).
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the accompanying LICENSE file.
- *******************************************************************************/
-package org.cryptomator.keychain;
-
-import com.google.common.io.BaseEncoding;
-import com.google.gson.Gson;
-import com.google.gson.GsonBuilder;
-import com.google.gson.JsonDeserializationContext;
-import com.google.gson.JsonDeserializer;
-import com.google.gson.JsonElement;
-import com.google.gson.JsonParseException;
-import com.google.gson.JsonPrimitive;
-import com.google.gson.JsonSerializationContext;
-import com.google.gson.JsonSerializer;
-import com.google.gson.annotations.SerializedName;
-import com.google.gson.reflect.TypeToken;
-import org.apache.commons.lang3.SystemUtils;
-import org.cryptomator.common.Environment;
-import org.cryptomator.jni.WinDataProtection;
-import org.cryptomator.jni.WinFunctions;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import javax.inject.Inject;
-import javax.inject.Singleton;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.OutputStream;
-import java.io.OutputStreamWriter;
-import java.io.Reader;
-import java.io.UncheckedIOException;
-import java.io.Writer;
-import java.lang.reflect.Type;
-import java.nio.ByteBuffer;
-import java.nio.CharBuffer;
-import java.nio.file.Files;
-import java.nio.file.NoSuchFileException;
-import java.nio.file.Path;
-import java.nio.file.StandardOpenOption;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Optional;
-import java.util.UUID;
-import java.util.stream.Collectors;
-
-import static java.nio.charset.StandardCharsets.UTF_8;
-
-@Singleton
-class WindowsProtectedKeychainAccess implements KeychainAccessStrategy {
-
- private static final Logger LOG = LoggerFactory.getLogger(WindowsProtectedKeychainAccess.class);
- private static final Gson GSON = new GsonBuilder().setPrettyPrinting() //
- .registerTypeHierarchyAdapter(byte[].class, new ByteArrayJsonAdapter()) //
- .disableHtmlEscaping().create();
-
- private final Optional winFunctions;
- private final List keychainPaths;
- private Map keychainEntries;
-
- @Inject
- public WindowsProtectedKeychainAccess(Optional winFunctions, Environment environment) {
- this.winFunctions = winFunctions;
- this.keychainPaths = environment.getKeychainPath().collect(Collectors.toList());
- }
-
- private WinDataProtection dataProtection() {
- return winFunctions.orElseThrow(IllegalStateException::new).dataProtection();
- }
-
- @Override
- public void storePassphrase(String key, CharSequence passphrase) {
- loadKeychainEntriesIfNeeded();
- ByteBuffer buf = UTF_8.encode(CharBuffer.wrap(passphrase));
- byte[] cleartext = new byte[buf.remaining()];
- buf.get(cleartext);
- KeychainEntry entry = new KeychainEntry();
- entry.salt = generateSalt();
- entry.ciphertext = dataProtection().protect(cleartext, entry.salt);
- Arrays.fill(buf.array(), (byte) 0x00);
- Arrays.fill(cleartext, (byte) 0x00);
- keychainEntries.put(key, entry);
- saveKeychainEntries();
- }
-
- @Override
- public char[] loadPassphrase(String key) {
- loadKeychainEntriesIfNeeded();
- KeychainEntry entry = keychainEntries.get(key);
- if (entry == null) {
- return null;
- }
- byte[] cleartext = dataProtection().unprotect(entry.ciphertext, entry.salt);
- if (cleartext == null) {
- return null;
- }
- CharBuffer buf = UTF_8.decode(ByteBuffer.wrap(cleartext));
- char[] passphrase = new char[buf.remaining()];
- buf.get(passphrase);
- Arrays.fill(cleartext, (byte) 0x00);
- Arrays.fill(buf.array(), (char) 0x00);
- return passphrase;
- }
-
- @Override
- public void deletePassphrase(String key) {
- loadKeychainEntriesIfNeeded();
- keychainEntries.remove(key);
- saveKeychainEntries();
- }
-
- @Override
- public void changePassphrase(String key, CharSequence passphrase) {
- loadKeychainEntriesIfNeeded();
- if (keychainEntries.remove(key) != null) {
- storePassphrase(key, passphrase);
- }
- }
-
- @Override
- public boolean isSupported() {
- return SystemUtils.IS_OS_WINDOWS && winFunctions.isPresent() && !keychainPaths.isEmpty();
- }
-
- private byte[] generateSalt() {
- byte[] result = new byte[2 * Long.BYTES];
- UUID uuid = UUID.randomUUID();
- ByteBuffer buf = ByteBuffer.wrap(result);
- buf.putLong(uuid.getMostSignificantBits());
- buf.putLong(uuid.getLeastSignificantBits());
- return result;
- }
-
- private void loadKeychainEntriesIfNeeded() {
- if (keychainEntries == null) {
- for (Path keychainPath : keychainPaths) {
- Optional
-
- org.cryptomator
- keychain
- ${project.version}
-
org.cryptomator
ui
@@ -107,6 +106,26 @@
${cryptomator.webdav.version}
+ org.cryptomator
+ integrations-api
+ ${cryptomator.integrations.version}
+
+
+ org.cryptomator
+ integrations-win
+ ${cryptomator.integrations.win.version}
+
+
+ org.cryptomator
+ integrations-mac
+ ${cryptomator.integrations.mac.version}
+
+
+ org.cryptomator
+ integrations-linux
+ ${cryptomator.integrations.linux.version}
+
+
org.cryptomator
jni
${cryptomator.jni.version}
@@ -163,18 +182,6 @@
${commons-lang3.version}
-
-
- de.swiesend
- secret-service
- ${secret-service.version}
-
-
- org.purejava
- kdewallet
- ${kdewallet.version}
-
-
com.auth0
@@ -256,7 +263,6 @@
commons
- keychain
ui
launcher
@@ -279,26 +285,87 @@
+
+ mac
+
+
+ mac
+
+
+ idea.version
+
+
+
+
+ org.cryptomator
+ integrations-mac
+
+
+
+
+ linux
+
+
+ unix
+ Linux
+
+
+ idea.version
+
+
+
+
+ org.cryptomator
+ integrations-linux
+
+
+
+
+ windows
+
+
+ windows
+
+
+ idea.version
+
+
+
+
+ org.cryptomator
+ integrations-win
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ 3.8.1
+
+
+ org.apache.maven.plugins
+ maven-resources-plugin
+ 3.2.0
+
+
+ org.apache.maven.plugins
maven-dependency-plugin
3.1.2
-
-
- copy-libs
-
- copy-dependencies
-
-
- ${project.build.directory}/libs
- runtime
-
-
-
+
+
+ org.apache.maven.plugins
+ maven-assembly-plugin
+ 3.3.0
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+ 2.22.2
org.codehaus.mojo
@@ -348,7 +415,6 @@
maven-compiler-plugin
- 3.8.1
14
@@ -363,7 +429,6 @@
org.apache.maven.plugins
maven-surefire-plugin
- 2.22.2
diff --git a/main/ui/pom.xml b/main/ui/pom.xml
index 79b59eeec..7784ee802 100644
--- a/main/ui/pom.xml
+++ b/main/ui/pom.xml
@@ -10,10 +10,6 @@
Cryptomator GUI
-
- org.cryptomator
- keychain
-
org.cryptomator
commons
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 e1fc9c093..52cfe2b81 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
@@ -1,10 +1,10 @@
package org.cryptomator.ui.changepassword;
+import org.cryptomator.common.keychain.KeychainManager;
import org.cryptomator.common.vaults.Vault;
import org.cryptomator.cryptofs.CryptoFileSystemProvider;
import org.cryptomator.cryptolib.api.InvalidPassphraseException;
-import org.cryptomator.keychain.KeychainAccessException;
-import org.cryptomator.keychain.KeychainManager;
+import org.cryptomator.integrations.keychain.KeychainAccessException;
import org.cryptomator.ui.common.Animations;
import org.cryptomator.ui.common.ErrorComponent;
import org.cryptomator.ui.common.FxController;
@@ -36,14 +36,14 @@ public class ChangePasswordController implements FxController {
private final Vault vault;
private final ObjectProperty newPassword;
private final ErrorComponent.Builder errorComponent;
- private final Optional keychain;
+ private final KeychainManager keychain;
public NiceSecurePasswordField oldPasswordField;
public CheckBox finalConfirmationCheckbox;
public Button finishButton;
@Inject
- public ChangePasswordController(@ChangePasswordWindow Stage window, @ChangePasswordWindow Vault vault, @Named("newPassword") ObjectProperty newPassword, ErrorComponent.Builder errorComponent, Optional keychain) {
+ public ChangePasswordController(@ChangePasswordWindow Stage window, @ChangePasswordWindow Vault vault, @Named("newPassword") ObjectProperty newPassword, ErrorComponent.Builder errorComponent, KeychainManager keychain) {
this.window = window;
this.vault = vault;
this.newPassword = newPassword;
@@ -82,9 +82,9 @@ public class ChangePasswordController implements FxController {
}
private void updatePasswordInSystemkeychain() {
- if (keychain.isPresent()) {
+ if (keychain.isSupported()) {
try {
- keychain.get().changePassphrase(vault.getId(), CharBuffer.wrap(newPassword.get()));
+ keychain.changePassphrase(vault.getId(), CharBuffer.wrap(newPassword.get()));
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/VaultService.java b/main/ui/src/main/java/org/cryptomator/ui/common/VaultService.java
index 2631c0f6a..35ed49870 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
@@ -3,7 +3,6 @@ package org.cryptomator.ui.common;
import org.cryptomator.common.vaults.Vault;
import org.cryptomator.common.vaults.VaultState;
import org.cryptomator.common.vaults.Volume;
-import org.cryptomator.keychain.KeychainManager;
import org.cryptomator.ui.fxapp.FxApplicationScoped;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -14,7 +13,6 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
-import java.util.Optional;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.stream.Collectors;
@@ -25,12 +23,10 @@ public class VaultService {
private static final Logger LOG = LoggerFactory.getLogger(VaultService.class);
private final ExecutorService executorService;
- private final Optional keychain;
@Inject
- public VaultService(ExecutorService executorService, Optional keychain) {
+ public VaultService(ExecutorService executorService) {
this.executorService = executorService;
- this.keychain = keychain;
}
public void reveal(Vault vault) {
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 99f8cbc41..81d28f682 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
@@ -1,8 +1,8 @@
package org.cryptomator.ui.forgetPassword;
+import org.cryptomator.common.keychain.KeychainManager;
import org.cryptomator.common.vaults.Vault;
-import org.cryptomator.keychain.KeychainAccessException;
-import org.cryptomator.keychain.KeychainManager;
+import org.cryptomator.integrations.keychain.KeychainAccessException;
import org.cryptomator.ui.common.FxController;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -11,7 +11,6 @@ import javax.inject.Inject;
import javafx.beans.property.BooleanProperty;
import javafx.fxml.FXML;
import javafx.stage.Stage;
-import java.util.Optional;
@ForgetPasswordScoped
public class ForgetPasswordController implements FxController {
@@ -20,11 +19,11 @@ public class ForgetPasswordController implements FxController {
private final Stage window;
private final Vault vault;
- private final Optional keychain;
+ private final KeychainManager keychain;
private final BooleanProperty confirmedResult;
@Inject
- public ForgetPasswordController(@ForgetPasswordWindow Stage window, @ForgetPasswordWindow Vault vault, Optional keychain, @ForgetPasswordWindow BooleanProperty confirmedResult) {
+ public ForgetPasswordController(@ForgetPasswordWindow Stage window, @ForgetPasswordWindow Vault vault, KeychainManager keychain, @ForgetPasswordWindow BooleanProperty confirmedResult) {
this.window = window;
this.vault = vault;
this.keychain = keychain;
@@ -38,9 +37,9 @@ public class ForgetPasswordController implements FxController {
@FXML
public void finish() {
- if (keychain.isPresent()) {
+ if (keychain.isSupported()) {
try {
- keychain.get().deletePassphrase(vault.getId());
+ keychain.deletePassphrase(vault.getId());
LOG.debug("Forgot password for vault {}.", vault.getDisplayName());
confirmedResult.setValue(true);
} catch (KeychainAccessException e) {
diff --git a/main/ui/src/main/java/org/cryptomator/ui/launcher/UiLauncherModule.java b/main/ui/src/main/java/org/cryptomator/ui/launcher/UiLauncherModule.java
index 9b8d6e776..2ac585763 100644
--- a/main/ui/src/main/java/org/cryptomator/ui/launcher/UiLauncherModule.java
+++ b/main/ui/src/main/java/org/cryptomator/ui/launcher/UiLauncherModule.java
@@ -3,7 +3,6 @@ package org.cryptomator.ui.launcher;
import dagger.Module;
import dagger.Provides;
import org.cryptomator.common.JniModule;
-import org.cryptomator.keychain.KeychainModule;
import org.cryptomator.ui.fxapp.FxApplicationComponent;
import org.cryptomator.ui.traymenu.TrayMenuComponent;
@@ -13,7 +12,7 @@ import java.util.ResourceBundle;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
-@Module(includes = {JniModule.class, KeychainModule.class}, subcomponents = {TrayMenuComponent.class, FxApplicationComponent.class})
+@Module(includes = {JniModule.class}, subcomponents = {TrayMenuComponent.class, FxApplicationComponent.class})
public abstract class UiLauncherModule {
@Provides
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 367aacc3a..e7da43938 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,8 +1,8 @@
package org.cryptomator.ui.mainwindow;
import com.tobiasdiez.easybind.EasyBind;
+import org.cryptomator.common.keychain.KeychainManager;
import org.cryptomator.common.vaults.Vault;
-import org.cryptomator.keychain.KeychainManager;
import org.cryptomator.ui.common.FxController;
import org.cryptomator.ui.fxapp.FxApplication;
import org.cryptomator.ui.vaultoptions.VaultOptionsComponent;
@@ -22,19 +22,19 @@ public class VaultDetailLockedController implements FxController {
private final ReadOnlyObjectProperty vault;
private final FxApplication application;
private final VaultOptionsComponent.Builder vaultOptionsWindow;
- private final Optional keychainManagerOptional;
+ private final KeychainManager keychain;
private final Stage mainWindow;
private final BooleanExpression passwordSaved;
@Inject
- VaultDetailLockedController(ObjectProperty vault, FxApplication application, VaultOptionsComponent.Builder vaultOptionsWindow, Optional keychainManagerOptional, @MainWindow Stage mainWindow) {
+ VaultDetailLockedController(ObjectProperty vault, FxApplication application, VaultOptionsComponent.Builder vaultOptionsWindow, KeychainManager keychain, @MainWindow Stage mainWindow) {
this.vault = vault;
this.application = application;
this.vaultOptionsWindow = vaultOptionsWindow;
- this.keychainManagerOptional = keychainManagerOptional;
+ this.keychain = keychain;
this.mainWindow = mainWindow;
- if (keychainManagerOptional.isPresent()) {
- this.passwordSaved = BooleanExpression.booleanExpression(EasyBind.select(vault).selectObject(v -> keychainManagerOptional.get().getPassphraseStoredProperty(v.getId())));
+ if (keychain.isSupported()) {
+ this.passwordSaved = BooleanExpression.booleanExpression(EasyBind.select(vault).selectObject(v -> keychain.getPassphraseStoredProperty(v.getId())));
} else {
this.passwordSaved = new SimpleBooleanProperty(false);
}
@@ -65,8 +65,8 @@ public class VaultDetailLockedController implements FxController {
}
public boolean isPasswordSaved() {
- if (keychainManagerOptional.isPresent() && vault.get() != null) {
- return keychainManagerOptional.get().getPassphraseStoredProperty(vault.get().getId()).get();
+ if (keychain.isSupported() && vault.get() != null) {
+ return keychain.getPassphraseStoredProperty(vault.get().getId()).get();
} else return false;
}
}
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 2bf4f49a1..830e15819 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
@@ -1,6 +1,7 @@
package org.cryptomator.ui.migration;
import dagger.Lazy;
+import org.cryptomator.common.keychain.KeychainManager;
import org.cryptomator.common.vaults.Vault;
import org.cryptomator.common.vaults.VaultState;
import org.cryptomator.cryptofs.FileNameTooLongException;
@@ -9,8 +10,7 @@ import org.cryptomator.cryptofs.migration.Migrators;
import org.cryptomator.cryptofs.migration.api.MigrationContinuationListener;
import org.cryptomator.cryptofs.migration.api.MigrationProgressListener;
import org.cryptomator.cryptolib.api.InvalidPassphraseException;
-import org.cryptomator.keychain.KeychainAccessException;
-import org.cryptomator.keychain.KeychainManager;
+import org.cryptomator.integrations.keychain.KeychainAccessException;
import org.cryptomator.ui.common.Animations;
import org.cryptomator.ui.common.ErrorComponent;
import org.cryptomator.ui.common.FxController;
@@ -37,7 +37,6 @@ import javafx.scene.Scene;
import javafx.scene.control.ContentDisplay;
import javafx.stage.Stage;
import java.util.Arrays;
-import java.util.Optional;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
@@ -55,7 +54,7 @@ public class MigrationRunController implements FxController {
private final Vault vault;
private final ExecutorService executor;
private final ScheduledExecutorService scheduler;
- private final Optional keychain;
+ private final KeychainManager keychain;
private final ObjectProperty missingCapability;
private final ErrorComponent.Builder errorComponent;
private final Lazy startScene;
@@ -69,8 +68,7 @@ public class MigrationRunController implements FxController {
public NiceSecurePasswordField passwordField;
@Inject
- public MigrationRunController(@MigrationWindow Stage window, @MigrationWindow Vault vault, ExecutorService executor, ScheduledExecutorService scheduler, Optional keychain, @Named("capabilityErrorCause") ObjectProperty missingCapability, @FxmlScene(FxmlFile.MIGRATION_START) Lazy startScene, @FxmlScene(FxmlFile.MIGRATION_SUCCESS) Lazy successScene, @FxmlScene(FxmlFile.MIGRATION_CAPABILITY_ERROR) Lazy capabilityErrorScene, @FxmlScene(FxmlFile.MIGRATION_IMPOSSIBLE) Lazy impossibleScene, ErrorComponent.Builder errorComponent) {
-
+ public MigrationRunController(@MigrationWindow Stage window, @MigrationWindow Vault vault, ExecutorService executor, ScheduledExecutorService scheduler, KeychainManager keychain, @Named("capabilityErrorCause") ObjectProperty missingCapability, @FxmlScene(FxmlFile.MIGRATION_START) Lazy startScene, @FxmlScene(FxmlFile.MIGRATION_SUCCESS) Lazy successScene, @FxmlScene(FxmlFile.MIGRATION_CAPABILITY_ERROR) Lazy capabilityErrorScene, @FxmlScene(FxmlFile.MIGRATION_IMPOSSIBLE) Lazy impossibleScene, ErrorComponent.Builder errorComponent) {
this.window = window;
this.vault = vault;
this.executor = executor;
@@ -88,7 +86,7 @@ public class MigrationRunController implements FxController {
}
public void initialize() {
- if (keychain.isPresent()) {
+ if (keychain.isSupported()) {
loadStoredPassword();
}
migrationButtonDisabled.bind(vault.stateProperty().isNotEqualTo(VaultState.NEEDS_MIGRATION).or(passwordField.textProperty().isEmpty()));
@@ -167,10 +165,10 @@ public class MigrationRunController implements FxController {
}
private void loadStoredPassword() {
- assert keychain.isPresent();
+ assert keychain.isSupported();
char[] storedPw = null;
try {
- storedPw = keychain.get().loadPassphrase(vault.getId());
+ storedPw = keychain.loadPassphrase(vault.getId());
if (storedPw != null) {
passwordField.setPassword(storedPw);
passwordField.selectRange(storedPw.length, storedPw.length);
diff --git a/main/ui/src/main/java/org/cryptomator/ui/preferences/GeneralPreferencesController.java b/main/ui/src/main/java/org/cryptomator/ui/preferences/GeneralPreferencesController.java
index 4e4abfbc9..208605f51 100644
--- a/main/ui/src/main/java/org/cryptomator/ui/preferences/GeneralPreferencesController.java
+++ b/main/ui/src/main/java/org/cryptomator/ui/preferences/GeneralPreferencesController.java
@@ -1,13 +1,11 @@
package org.cryptomator.ui.preferences;
-import org.apache.commons.lang3.SystemUtils;
import org.cryptomator.common.Environment;
import org.cryptomator.common.LicenseHolder;
import org.cryptomator.common.settings.KeychainBackend;
import org.cryptomator.common.settings.Settings;
import org.cryptomator.common.settings.UiTheme;
-import org.cryptomator.keychain.KeychainAccessStrategy;
-import org.cryptomator.keychain.LinuxSystemKeychainAccess;
+import org.cryptomator.integrations.keychain.KeychainAccessProvider;
import org.cryptomator.ui.common.FxController;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -27,12 +25,12 @@ import javafx.scene.control.RadioButton;
import javafx.scene.control.Toggle;
import javafx.scene.control.ToggleGroup;
import javafx.util.StringConverter;
-
import java.util.Arrays;
-import java.util.EnumSet;
import java.util.Optional;
import java.util.ResourceBundle;
+import java.util.Set;
import java.util.concurrent.ExecutorService;
+import java.util.stream.Collectors;
@PreferencesScoped
public class GeneralPreferencesController implements FxController {
@@ -48,7 +46,7 @@ public class GeneralPreferencesController implements FxController {
private final ResourceBundle resourceBundle;
private final Application application;
private final Environment environment;
- private Optional keychain;
+ private final Set keychainAccessProviders;
public ChoiceBox themeChoiceBox;
public ChoiceBox keychainBackendChoiceBox;
public CheckBox startHiddenCheckbox;
@@ -59,11 +57,11 @@ public class GeneralPreferencesController implements FxController {
public RadioButton nodeOrientationRtl;
@Inject
- GeneralPreferencesController(Settings settings, @Named("trayMenuSupported") boolean trayMenuSupported, Optional autoStartStrategy, Optional keychain, ObjectProperty selectedTabProperty, LicenseHolder licenseHolder, ExecutorService executor, ResourceBundle resourceBundle, Application application, Environment environment) {
+ GeneralPreferencesController(Settings settings, @Named("trayMenuSupported") boolean trayMenuSupported, Optional autoStartStrategy, Set keychainAccessProviders, ObjectProperty selectedTabProperty, LicenseHolder licenseHolder, ExecutorService executor, ResourceBundle resourceBundle, Application application, Environment environment) {
this.settings = settings;
this.trayMenuSupported = trayMenuSupported;
this.autoStartStrategy = autoStartStrategy;
- this.keychain = keychain;
+ this.keychainAccessProviders = keychainAccessProviders;
this.selectedTabProperty = selectedTabProperty;
this.licenseHolder = licenseHolder;
this.executor = executor;
@@ -96,16 +94,15 @@ public class GeneralPreferencesController implements FxController {
nodeOrientation.selectedToggleProperty().addListener(this::toggleNodeOrientation);
keychainBackendChoiceBox.getItems().addAll(getAvailableBackends());
- if (keychain.isPresent() && SystemUtils.IS_OS_LINUX) {
- keychainBackendChoiceBox.setValue(LinuxSystemKeychainAccess.getBackendActivated());
- }
- if (keychain.isPresent() && (SystemUtils.IS_OS_MAC || SystemUtils.IS_OS_WINDOWS)) {
- keychainBackendChoiceBox.setValue(Arrays.stream(KeychainBackend.supportedBackends()).findFirst().orElseThrow(IllegalStateException::new));
- }
keychainBackendChoiceBox.setConverter(new KeychainBackendConverter(resourceBundle));
keychainBackendChoiceBox.valueProperty().bindBidirectional(settings.keychainBackend());
}
+ private KeychainBackend[] getAvailableBackends() {
+ var namesOfAvailableProviders = keychainAccessProviders.stream().map(KeychainAccessProvider::getClass).map(Class::getName).collect(Collectors.toUnmodifiableSet());
+ return Arrays.stream(KeychainBackend.values()).filter(value -> namesOfAvailableProviders.contains(value.getProviderClass())).toArray(KeychainBackend[]::new);
+ }
+
public boolean isTrayMenuSupported() {
return this.trayMenuSupported;
}
@@ -183,7 +180,7 @@ public class GeneralPreferencesController implements FxController {
@Override
public String toString(KeychainBackend impl) {
- return resourceBundle.getString(impl.getDisplayName());
+ return resourceBundle.getString("preferences.general.keychainBackend." + impl.getProviderClass());
}
@Override
@@ -215,17 +212,4 @@ public class GeneralPreferencesController implements FxController {
}
}
- private KeychainBackend[] getAvailableBackends() {
- if (!keychain.isPresent()) {
- return new KeychainBackend[]{};
- }
- if (SystemUtils.IS_OS_LINUX) {
- EnumSet backends = LinuxSystemKeychainAccess.getAvailableKeychainBackends();
- return backends.toArray(KeychainBackend[]::new);
- }
- if (SystemUtils.IS_OS_MAC || SystemUtils.IS_OS_WINDOWS) {
- return KeychainBackend.supportedBackends();
- }
- return new KeychainBackend[]{};
- }
}
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 b64195d9a..5460cc149 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
@@ -1,7 +1,7 @@
package org.cryptomator.ui.unlock;
+import org.cryptomator.common.keychain.KeychainManager;
import org.cryptomator.common.vaults.Vault;
-import org.cryptomator.keychain.KeychainManager;
import org.cryptomator.ui.common.FxController;
import org.cryptomator.ui.common.UserInteractionLock;
import org.cryptomator.ui.common.WeakBindings;
@@ -49,7 +49,7 @@ public class UnlockController implements FxController {
private final Optional savedPassword;
private final UserInteractionLock passwordEntryLock;
private final ForgetPasswordComponent.Builder forgetPassword;
- private final Optional keychain;
+ private final KeychainManager keychain;
private final ObjectBinding unlockButtonContentDisplay;
private final BooleanBinding userInteractionDisabled;
private final BooleanProperty unlockButtonDisabled;
@@ -65,7 +65,7 @@ public class UnlockController implements FxController {
public Animation unlockAnimation;
@Inject
- public UnlockController(@UnlockWindow Stage window, @UnlockWindow Vault vault, AtomicReference password, @Named("savePassword") AtomicBoolean savePassword, @Named("savedPassword") Optional savedPassword, UserInteractionLock passwordEntryLock, ForgetPasswordComponent.Builder forgetPassword, Optional keychain) {
+ public UnlockController(@UnlockWindow Stage window, @UnlockWindow Vault vault, AtomicReference password, @Named("savePassword") AtomicBoolean savePassword, @Named("savedPassword") Optional savedPassword, UserInteractionLock passwordEntryLock, ForgetPasswordComponent.Builder forgetPassword, KeychainManager keychain) {
this.window = window;
this.vault = vault;
this.password = password;
@@ -214,6 +214,6 @@ public class UnlockController implements FxController {
}
public boolean isKeychainAccessAvailable() {
- return keychain.isPresent();
+ return keychain.isSupported();
}
}
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 102743e7f..da5e2884d 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
@@ -4,9 +4,9 @@ import dagger.Binds;
import dagger.Module;
import dagger.Provides;
import dagger.multibindings.IntoMap;
+import org.cryptomator.common.keychain.KeychainManager;
import org.cryptomator.common.vaults.Vault;
-import org.cryptomator.keychain.KeychainAccessException;
-import org.cryptomator.keychain.KeychainManager;
+import org.cryptomator.integrations.keychain.KeychainAccessException;
import org.cryptomator.ui.common.DefaultSceneFactory;
import org.cryptomator.ui.common.FXMLLoaderFactory;
import org.cryptomator.ui.common.FxController;
@@ -49,15 +49,17 @@ abstract class UnlockModule {
@Provides
@Named("savedPassword")
@UnlockScoped
- static Optional provideStoredPassword(Optional keychain, @UnlockWindow Vault vault) {
- return keychain.map(k -> {
+ static Optional provideStoredPassword(KeychainManager keychain, @UnlockWindow Vault vault) {
+ if (!keychain.isSupported()) {
+ return Optional.empty();
+ } else {
try {
- return k.loadPassphrase(vault.getId());
+ return Optional.ofNullable(keychain.loadPassphrase(vault.getId()));
} catch (KeychainAccessException e) {
LOG.error("Failed to load entry from system keychain.", e);
- return null;
+ return Optional.empty();
}
- });
+ }
}
@Provides
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 bdefb4ad3..9b95103ad 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
@@ -1,14 +1,14 @@
package org.cryptomator.ui.unlock;
import dagger.Lazy;
+import org.cryptomator.common.keychain.KeychainManager;
import org.cryptomator.common.mountpoint.InvalidMountPointException;
import org.cryptomator.common.vaults.MountPointRequirement;
import org.cryptomator.common.vaults.Vault;
import org.cryptomator.common.vaults.VaultState;
import org.cryptomator.common.vaults.Volume.VolumeException;
import org.cryptomator.cryptolib.api.InvalidPassphraseException;
-import org.cryptomator.keychain.KeychainAccessException;
-import org.cryptomator.keychain.KeychainManager;
+import org.cryptomator.integrations.keychain.KeychainAccessException;
import org.cryptomator.ui.common.Animations;
import org.cryptomator.ui.common.ErrorComponent;
import org.cryptomator.ui.common.FxmlFile;
@@ -53,14 +53,14 @@ public class UnlockWorkflow extends Task {
private final AtomicBoolean savePassword;
private final Optional savedPassword;
private final UserInteractionLock passwordEntryLock;
- private final Optional keychain;
+ private final KeychainManager keychain;
private final Lazy unlockScene;
private final Lazy successScene;
private final Lazy invalidMountPointScene;
private final ErrorComponent.Builder errorComponent;
@Inject
- UnlockWorkflow(@UnlockWindow Stage window, @UnlockWindow Vault vault, VaultService vaultService, AtomicReference password, @Named("savePassword") AtomicBoolean savePassword, @Named("savedPassword") Optional savedPassword, UserInteractionLock passwordEntryLock, Optional keychain, @FxmlScene(FxmlFile.UNLOCK) Lazy unlockScene, @FxmlScene(FxmlFile.UNLOCK_SUCCESS) Lazy successScene, @FxmlScene(FxmlFile.UNLOCK_INVALID_MOUNT_POINT) Lazy invalidMountPointScene, ErrorComponent.Builder errorComponent) {
+ UnlockWorkflow(@UnlockWindow Stage window, @UnlockWindow Vault vault, VaultService vaultService, AtomicReference password, @Named("savePassword") AtomicBoolean savePassword, @Named("savedPassword") Optional savedPassword, UserInteractionLock passwordEntryLock, KeychainManager keychain, @FxmlScene(FxmlFile.UNLOCK) Lazy unlockScene, @FxmlScene(FxmlFile.UNLOCK_SUCCESS) Lazy successScene, @FxmlScene(FxmlFile.UNLOCK_INVALID_MOUNT_POINT) Lazy invalidMountPointScene, ErrorComponent.Builder errorComponent) {
this.window = window;
this.vault = vault;
this.vaultService = vaultService;
@@ -150,9 +150,9 @@ public class UnlockWorkflow extends Task {
}
private void savePasswordToSystemkeychain() {
- if (keychain.isPresent()) {
+ if (keychain.isSupported()) {
try {
- keychain.get().storePassphrase(vault.getId(), CharBuffer.wrap(password.get()));
+ keychain.storePassphrase(vault.getId(), CharBuffer.wrap(password.get()));
} catch (KeychainAccessException e) {
LOG.error("Failed to store passphrase in system keychain.", e);
}
diff --git a/main/ui/src/main/java/org/cryptomator/ui/vaultoptions/MasterkeyOptionsController.java b/main/ui/src/main/java/org/cryptomator/ui/vaultoptions/MasterkeyOptionsController.java
index 4c08ad75a..ee38e1f18 100644
--- a/main/ui/src/main/java/org/cryptomator/ui/vaultoptions/MasterkeyOptionsController.java
+++ b/main/ui/src/main/java/org/cryptomator/ui/vaultoptions/MasterkeyOptionsController.java
@@ -1,11 +1,13 @@
package org.cryptomator.ui.vaultoptions;
+import org.cryptomator.common.keychain.KeychainManager;
import org.cryptomator.common.vaults.Vault;
-import org.cryptomator.keychain.KeychainAccessException;
-import org.cryptomator.keychain.KeychainManager;
+import org.cryptomator.integrations.keychain.KeychainAccessException;
import org.cryptomator.ui.changepassword.ChangePasswordComponent;
import org.cryptomator.ui.common.FxController;
import org.cryptomator.ui.recoverykey.RecoveryKeyComponent;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import javax.inject.Inject;
import javafx.beans.binding.Bindings;
@@ -13,29 +15,32 @@ import javafx.beans.binding.BooleanExpression;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.fxml.FXML;
import javafx.stage.Stage;
-import java.util.Optional;
@VaultOptionsScoped
public class MasterkeyOptionsController implements FxController {
+ private static final Logger LOG = LoggerFactory.getLogger(MasterkeyOptionsController.class);
+
private final Vault vault;
private final Stage window;
private final ChangePasswordComponent.Builder changePasswordWindow;
private final RecoveryKeyComponent.Builder recoveryKeyWindow;
- private final Optional keychainManagerOptional;
+ private final KeychainManager keychain;
private final BooleanExpression passwordSaved;
@Inject
- MasterkeyOptionsController(@VaultOptionsWindow Vault vault, @VaultOptionsWindow Stage window, ChangePasswordComponent.Builder changePasswordWindow, RecoveryKeyComponent.Builder recoveryKeyWindow, Optional keychainManagerOptional) {
+ MasterkeyOptionsController(@VaultOptionsWindow Vault vault, @VaultOptionsWindow Stage window, ChangePasswordComponent.Builder changePasswordWindow, RecoveryKeyComponent.Builder recoveryKeyWindow, KeychainManager keychain) {
this.vault = vault;
this.window = window;
this.changePasswordWindow = changePasswordWindow;
this.recoveryKeyWindow = recoveryKeyWindow;
- this.keychainManagerOptional = keychainManagerOptional;
- if (keychainManagerOptional.isPresent()) {
- this.passwordSaved = Bindings.createBooleanBinding(this::isPasswordSaved, keychainManagerOptional.get().getPassphraseStoredProperty(vault.getId()));
- } else this.passwordSaved = new SimpleBooleanProperty(false);
+ this.keychain = keychain;
+ if (keychain.isSupported()) {
+ this.passwordSaved = Bindings.createBooleanBinding(this::isPasswordSaved, keychain.getPassphraseStoredProperty(vault.getId()));
+ } else {
+ this.passwordSaved = new SimpleBooleanProperty(false);
+ }
}
@FXML
@@ -54,8 +59,13 @@ public class MasterkeyOptionsController implements FxController {
}
@FXML
- public void removePasswordFromKeychain() throws KeychainAccessException {
- keychainManagerOptional.get().deletePassphrase(vault.getId());
+ public void removePasswordFromKeychain() {
+ assert keychain.isSupported();
+ try {
+ keychain.deletePassphrase(vault.getId());
+ } catch (KeychainAccessException e) {
+ LOG.error("Failed to delete passphrase from system keychain.", e);
+ }
window.close();
}
@@ -64,8 +74,8 @@ public class MasterkeyOptionsController implements FxController {
}
public boolean isPasswordSaved() {
- if (keychainManagerOptional.isPresent() && vault != null) {
- return keychainManagerOptional.get().getPassphraseStoredProperty(vault.getId()).get();
+ if (keychain.isSupported() && vault != null) {
+ return keychain.getPassphraseStoredProperty(vault.getId()).get();
} else return false;
}
}
diff --git a/main/ui/src/main/resources/i18n/strings.properties b/main/ui/src/main/resources/i18n/strings.properties
index 3805399aa..e391d263a 100644
--- a/main/ui/src/main/resources/i18n/strings.properties
+++ b/main/ui/src/main/resources/i18n/strings.properties
@@ -144,10 +144,10 @@ preferences.general.debugLogging=Enable debug logging
preferences.general.debugDirectory=Reveal log files
preferences.general.autoStart=Launch Cryptomator on system start
preferences.general.keychainBackend=Store passwords with
-preferences.general.keychainBackend.gnome=Gnome Keyring
-preferences.general.keychainBackend.kde=KDE KWallet
-preferences.general.keychainBackend.macSystemKeychain=macOS Keychain Access
-preferences.general.keychainBackend.winSystemKeychain=Windows Data Protection Keychain
+preferences.general.keychainBackend.org.cryptomator.linux.keychain.SecretServiceKeychainAccess=Gnome Keyring
+preferences.general.keychainBackend.org.cryptomator.linux.keychain.KDEWalletKeychainAccess=KDE KWallet
+preferences.general.keychainBackend.org.cryptomator.macos.keychain.MacSystemKeychainAccess=macOS Keychain Access
+preferences.general.keychainBackend.org.cryptomator.windows.keychain.WindowsProtectedKeychainAccess=Windows Data Protection Keychain
preferences.general.interfaceOrientation=Interface Orientation
preferences.general.interfaceOrientation.ltr=Left to Right
preferences.general.interfaceOrientation.rtl=Right to Left
diff --git a/main/ui/src/main/resources/license/THIRD-PARTY.txt b/main/ui/src/main/resources/license/THIRD-PARTY.txt
index 3674e5e05..1389d25a1 100644
--- a/main/ui/src/main/resources/license/THIRD-PARTY.txt
+++ b/main/ui/src/main/resources/license/THIRD-PARTY.txt
@@ -11,82 +11,75 @@ 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 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)
- - jnr-a64asm (com.github.jnr:jnr-a64asm:1.0.0 - http://nexus.sonatype.org/oss-repository-hosting.html/jnr-a64asm)
- - jnr-constants (com.github.jnr:jnr-constants:0.9.15 - http://github.com/jnr/jnr-constants)
- - jnr-enxio (com.github.jnr:jnr-enxio:0.28 - http://github.com/jnr/jnr-enxio)
- - jnr-ffi (com.github.jnr:jnr-ffi:2.1.12 - http://github.com/jnr/jnr-ffi)
- - jnr-unixsocket (com.github.jnr:jnr-unixsocket:0.33 - http://github.com/jnr/jnr-unixsocket)
- - FindBugs-jsr305 (com.google.code.findbugs:jsr305:3.0.2 - http://findbugs.sourceforge.net/)
- - Gson (com.google.code.gson:gson:2.8.6 - https://github.com/google/gson/gson)
- - Dagger (com.google.dagger:dagger:2.22 - https://github.com/google/dagger)
- - error-prone annotations (com.google.errorprone:error_prone_annotations:2.3.4 - http://nexus.sonatype.org/oss-repository-hosting.html/error_prone_parent/error_prone_annotations)
- - Guava InternalFutureFailureAccess and InternalFutures (com.google.guava:failureaccess:1.0.1 - https://github.com/google/guava/failureaccess)
- - Guava: Google Core Libraries for Java (com.google.guava:guava:29.0-jre - https://github.com/google/guava/guava)
- - Guava ListenableFuture only (com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava - https://github.com/google/guava/listenablefuture)
- - J2ObjC Annotations (com.google.j2objc:j2objc-annotations:1.3 - https://github.com/google/j2objc/)
- - Apache Commons CLI (commons-cli:commons-cli:1.4 - http://commons.apache.org/proper/commons-cli/)
- - Apache Commons IO (commons-io:commons-io:2.6 - http://commons.apache.org/proper/commons-io/)
- - javax.inject (javax.inject:javax.inject:1 - http://code.google.com/p/atinject/)
- - Java Native Access (net.java.dev.jna:jna:5.1.0 - https://github.com/java-native-access/jna)
- - Java Native Access Platform (net.java.dev.jna:jna-platform:5.1.0 - https://github.com/java-native-access/jna)
- - Apache Commons Lang (org.apache.commons:commons-lang3:3.11 - https://commons.apache.org/proper/commons-lang/)
- - Apache HttpCore (org.apache.httpcomponents:httpcore:4.4.13 - http://hc.apache.org/httpcomponents-core-ga)
- - Jackrabbit WebDAV Library (org.apache.jackrabbit:jackrabbit-webdav:2.21.3 - http://jackrabbit.apache.org/jackrabbit-webdav/)
- - Jetty :: Http Utility (org.eclipse.jetty:jetty-http:9.4.31.v20200723 - http://www.eclipse.org/jetty)
- - Jetty :: IO Utility (org.eclipse.jetty:jetty-io:9.4.31.v20200723 - http://www.eclipse.org/jetty)
- - Jetty :: Security (org.eclipse.jetty:jetty-security:9.4.31.v20200723 - http://www.eclipse.org/jetty)
- - Jetty :: Server Core (org.eclipse.jetty:jetty-server:9.4.31.v20200723 - http://www.eclipse.org/jetty)
- - Jetty :: Servlet Handling (org.eclipse.jetty:jetty-servlet:9.4.31.v20200723 - http://www.eclipse.org/jetty)
- - Jetty :: Utilities (org.eclipse.jetty:jetty-util:9.4.31.v20200723 - http://www.eclipse.org/jetty)
- - Jetty :: Webapp Application Support (org.eclipse.jetty:jetty-webapp:9.4.31.v20200723 - http://www.eclipse.org/jetty)
- - Jetty :: XML utilities (org.eclipse.jetty:jetty-xml:9.4.31.v20200723 - http://www.eclipse.org/jetty)
- BSD:
- - asm (org.ow2.asm:asm:7.1 - http://asm.ow2.org/)
- - asm-analysis (org.ow2.asm:asm-analysis:7.1 - http://asm.ow2.org/)
- - asm-commons (org.ow2.asm:asm-commons:7.1 - http://asm.ow2.org/)
- - asm-tree (org.ow2.asm:asm-tree:7.1 - http://asm.ow2.org/)
- - asm-util (org.ow2.asm:asm-util:7.1 - http://asm.ow2.org/)
- Eclipse Public License - Version 1.0:
- - Jetty :: Http Utility (org.eclipse.jetty:jetty-http:9.4.31.v20200723 - http://www.eclipse.org/jetty)
- - Jetty :: IO Utility (org.eclipse.jetty:jetty-io:9.4.31.v20200723 - http://www.eclipse.org/jetty)
- - Jetty :: Security (org.eclipse.jetty:jetty-security:9.4.31.v20200723 - http://www.eclipse.org/jetty)
- - Jetty :: Server Core (org.eclipse.jetty:jetty-server:9.4.31.v20200723 - http://www.eclipse.org/jetty)
- - Jetty :: Servlet Handling (org.eclipse.jetty:jetty-servlet:9.4.31.v20200723 - http://www.eclipse.org/jetty)
- - Jetty :: Utilities (org.eclipse.jetty:jetty-util:9.4.31.v20200723 - http://www.eclipse.org/jetty)
- - Jetty :: Webapp Application Support (org.eclipse.jetty:jetty-webapp:9.4.31.v20200723 - http://www.eclipse.org/jetty)
- - Jetty :: XML utilities (org.eclipse.jetty:jetty-xml:9.4.31.v20200723 - http://www.eclipse.org/jetty)
- Eclipse Public License - v 2.0:
- - jnr-posix (com.github.jnr:jnr-posix:3.0.54 - http://nexus.sonatype.org/oss-repository-hosting.html/jnr-posix)
- GPLv2:
- - jnr-posix (com.github.jnr:jnr-posix:3.0.54 - http://nexus.sonatype.org/oss-repository-hosting.html/jnr-posix)
- GPLv2+CE:
- - Java Servlet API (javax.servlet:javax.servlet-api:3.1.0 - http://servlet-spec.java.net)
- - javafx-base (org.openjfx:javafx-base:14 - https://openjdk.java.net/projects/openjfx/javafx-base/)
- - javafx-controls (org.openjfx:javafx-controls:14 - https://openjdk.java.net/projects/openjfx/javafx-controls/)
- - javafx-fxml (org.openjfx:javafx-fxml:14 - https://openjdk.java.net/projects/openjfx/javafx-fxml/)
- - javafx-graphics (org.openjfx:javafx-graphics:14 - https://openjdk.java.net/projects/openjfx/javafx-graphics/)
- LGPL 2.1:
- - dbus-java (com.github.hypfvieh:dbus-java:3.2.3 - https://github.com/hypfvieh/dbus-java/dbus-java)
- - jnr-posix (com.github.jnr:jnr-posix:3.0.54 - http://nexus.sonatype.org/oss-repository-hosting.html/jnr-posix)
- - Java Native Access (net.java.dev.jna:jna:5.1.0 - https://github.com/java-native-access/jna)
- - Java Native Access Platform (net.java.dev.jna:jna-platform:5.1.0 - https://github.com/java-native-access/jna)
- MIT License:
- - java jwt (com.auth0:java-jwt:3.10.3 - https://github.com/auth0/java-jwt)
- - java-utils (com.github.hypfvieh:java-utils:1.0.6 - https://github.com/hypfvieh/java-utils)
- - jnr-x86asm (com.github.jnr:jnr-x86asm:1.0.2 - http://github.com/jnr/jnr-x86asm)
- - jnr-fuse (com.github.serceman:jnr-fuse:0.5.4 - no url defined)
- - 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.1.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 (com.tobiasdiez:easybind:2.1.0 - https://github.com/tobiasdiez/EasyBind)
+Cryptomator uses 46 third-party dependencies under the following licenses:
+ Apache License v2.0:
+ - jffi (com.github.jnr:jffi:1.2.23 - http://github.com/jnr/jffi)
+ - jnr-a64asm (com.github.jnr:jnr-a64asm:1.0.0 - http://nexus.sonatype.org/oss-repository-hosting.html/jnr-a64asm)
+ - jnr-constants (com.github.jnr:jnr-constants:0.9.15 - http://github.com/jnr/jnr-constants)
+ - jnr-ffi (com.github.jnr:jnr-ffi:2.1.12 - http://github.com/jnr/jnr-ffi)
+ - FindBugs-jsr305 (com.google.code.findbugs:jsr305:3.0.2 - http://findbugs.sourceforge.net/)
+ - Gson (com.google.code.gson:gson:2.8.6 - https://github.com/google/gson/gson)
+ - Dagger (com.google.dagger:dagger:2.22 - https://github.com/google/dagger)
+ - error-prone annotations (com.google.errorprone:error_prone_annotations:2.3.4 - http://nexus.sonatype.org/oss-repository-hosting.html/error_prone_parent/error_prone_annotations)
+ - Guava InternalFutureFailureAccess and InternalFutures (com.google.guava:failureaccess:1.0.1 - https://github.com/google/guava/failureaccess)
+ - Guava: Google Core Libraries for Java (com.google.guava:guava:30.0-jre - https://github.com/google/guava/guava)
+ - Guava ListenableFuture only (com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava - https://github.com/google/guava/listenablefuture)
+ - J2ObjC Annotations (com.google.j2objc:j2objc-annotations:1.3 - https://github.com/google/j2objc/)
+ - Apache Commons CLI (commons-cli:commons-cli:1.4 - http://commons.apache.org/proper/commons-cli/)
+ - Apache Commons IO (commons-io:commons-io:2.6 - http://commons.apache.org/proper/commons-io/)
+ - javax.inject (javax.inject:javax.inject:1 - http://code.google.com/p/atinject/)
+ - Java Native Access (net.java.dev.jna:jna:5.1.0 - https://github.com/java-native-access/jna)
+ - Java Native Access Platform (net.java.dev.jna:jna-platform:5.1.0 - https://github.com/java-native-access/jna)
+ - Apache Commons Lang (org.apache.commons:commons-lang3:3.11 - https://commons.apache.org/proper/commons-lang/)
+ - Apache HttpCore (org.apache.httpcomponents:httpcore:4.4.13 - http://hc.apache.org/httpcomponents-core-ga)
+ - Jackrabbit WebDAV Library (org.apache.jackrabbit:jackrabbit-webdav:2.21.3 - http://jackrabbit.apache.org/jackrabbit-webdav/)
+ - Jetty :: Http Utility (org.eclipse.jetty:jetty-http:9.4.31.v20200723 - http://www.eclipse.org/jetty)
+ - Jetty :: IO Utility (org.eclipse.jetty:jetty-io:9.4.31.v20200723 - http://www.eclipse.org/jetty)
+ - Jetty :: Security (org.eclipse.jetty:jetty-security:9.4.31.v20200723 - http://www.eclipse.org/jetty)
+ - Jetty :: Server Core (org.eclipse.jetty:jetty-server:9.4.31.v20200723 - http://www.eclipse.org/jetty)
+ - Jetty :: Servlet Handling (org.eclipse.jetty:jetty-servlet:9.4.31.v20200723 - http://www.eclipse.org/jetty)
+ - Jetty :: Utilities (org.eclipse.jetty:jetty-util:9.4.31.v20200723 - http://www.eclipse.org/jetty)
+ - Jetty :: Webapp Application Support (org.eclipse.jetty:jetty-webapp:9.4.31.v20200723 - http://www.eclipse.org/jetty)
+ - Jetty :: XML utilities (org.eclipse.jetty:jetty-xml:9.4.31.v20200723 - http://www.eclipse.org/jetty)
+ BSD:
+ - asm (org.ow2.asm:asm:7.1 - http://asm.ow2.org/)
+ - asm-analysis (org.ow2.asm:asm-analysis:7.1 - http://asm.ow2.org/)
+ - asm-commons (org.ow2.asm:asm-commons:7.1 - http://asm.ow2.org/)
+ - asm-tree (org.ow2.asm:asm-tree:7.1 - http://asm.ow2.org/)
+ - asm-util (org.ow2.asm:asm-util:7.1 - http://asm.ow2.org/)
+ Eclipse Public License - Version 1.0:
+ - Jetty :: Http Utility (org.eclipse.jetty:jetty-http:9.4.31.v20200723 - http://www.eclipse.org/jetty)
+ - Jetty :: IO Utility (org.eclipse.jetty:jetty-io:9.4.31.v20200723 - http://www.eclipse.org/jetty)
+ - Jetty :: Security (org.eclipse.jetty:jetty-security:9.4.31.v20200723 - http://www.eclipse.org/jetty)
+ - Jetty :: Server Core (org.eclipse.jetty:jetty-server:9.4.31.v20200723 - http://www.eclipse.org/jetty)
+ - Jetty :: Servlet Handling (org.eclipse.jetty:jetty-servlet:9.4.31.v20200723 - http://www.eclipse.org/jetty)
+ - Jetty :: Utilities (org.eclipse.jetty:jetty-util:9.4.31.v20200723 - http://www.eclipse.org/jetty)
+ - Jetty :: Webapp Application Support (org.eclipse.jetty:jetty-webapp:9.4.31.v20200723 - http://www.eclipse.org/jetty)
+ - Jetty :: XML utilities (org.eclipse.jetty:jetty-xml:9.4.31.v20200723 - http://www.eclipse.org/jetty)
+ Eclipse Public License - v 2.0:
+ - jnr-posix (com.github.jnr:jnr-posix:3.0.54 - http://nexus.sonatype.org/oss-repository-hosting.html/jnr-posix)
+ GPLv2:
+ - jnr-posix (com.github.jnr:jnr-posix:3.0.54 - http://nexus.sonatype.org/oss-repository-hosting.html/jnr-posix)
+ GPLv2+CE:
+ - Java Servlet API (javax.servlet:javax.servlet-api:3.1.0 - http://servlet-spec.java.net)
+ - javafx-base (org.openjfx:javafx-base:14 - https://openjdk.java.net/projects/openjfx/javafx-base/)
+ - javafx-controls (org.openjfx:javafx-controls:14 - https://openjdk.java.net/projects/openjfx/javafx-controls/)
+ - javafx-fxml (org.openjfx:javafx-fxml:14 - https://openjdk.java.net/projects/openjfx/javafx-fxml/)
+ - javafx-graphics (org.openjfx:javafx-graphics:14 - https://openjdk.java.net/projects/openjfx/javafx-graphics/)
+ LGPL 2.1:
+ - jnr-posix (com.github.jnr:jnr-posix:3.0.54 - http://nexus.sonatype.org/oss-repository-hosting.html/jnr-posix)
+ - Java Native Access (net.java.dev.jna:jna:5.1.0 - https://github.com/java-native-access/jna)
+ - Java Native Access Platform (net.java.dev.jna:jna-platform:5.1.0 - https://github.com/java-native-access/jna)
+ MIT License:
+ - java jwt (com.auth0:java-jwt:3.10.3 - https://github.com/auth0/java-jwt)
+ - jnr-x86asm (com.github.jnr:jnr-x86asm:1.0.2 - http://github.com/jnr/jnr-x86asm)
+ - jnr-fuse (com.github.serceman:jnr-fuse:0.5.4 - no url defined)
+ - zxcvbn4j (com.nulab-inc:zxcvbn:1.3.0 - https://github.com/nulab/zxcvbn4j)
+ - Checker Qual (org.checkerframework:checker-qual:3.5.0 - https://checkerframework.org)
+ - SLF4J API Module (org.slf4j:slf4j-api:1.7.30 - http://www.slf4j.org)
+ The BSD 2-Clause License:
+ - 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:
- - Font Awesome 5.12.0 (https://fontawesome.com/)
+SIL OFL 1.1 License:
+- Font Awesome 5.12.0 (https://fontawesome.com/)