mirror of
https://github.com/cryptomator/cryptomator.git
synced 2026-05-14 08:41:28 +00:00
Merge pull request #1393 from cryptomator/feature/modular-keychains
Modularized Keychain Access, references #1301
This commit is contained in:
16
.github/workflows/build.yml
vendored
16
.github/workflows/build.yml
vendored
@@ -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:
|
||||
|
||||
@@ -43,12 +43,5 @@
|
||||
</includes>
|
||||
<outputDirectory>libs</outputDirectory>
|
||||
</fileSet>
|
||||
<fileSet>
|
||||
<directory>target/linux-libs</directory>
|
||||
<includes>
|
||||
<include>*.jar</include>
|
||||
</includes>
|
||||
<outputDirectory>libs</outputDirectory>
|
||||
</fileSet>
|
||||
</fileSets>
|
||||
</assembly>
|
||||
@@ -43,12 +43,5 @@
|
||||
</includes>
|
||||
<outputDirectory>libs</outputDirectory>
|
||||
</fileSet>
|
||||
<fileSet>
|
||||
<directory>target/mac-libs</directory>
|
||||
<includes>
|
||||
<include>*.jar</include>
|
||||
</includes>
|
||||
<outputDirectory>libs</outputDirectory>
|
||||
</fileSet>
|
||||
</fileSets>
|
||||
</assembly>
|
||||
@@ -43,12 +43,5 @@
|
||||
</includes>
|
||||
<outputDirectory>libs</outputDirectory>
|
||||
</fileSet>
|
||||
<fileSet>
|
||||
<directory>target/win-libs</directory>
|
||||
<includes>
|
||||
<include>*.jar</include>
|
||||
</includes>
|
||||
<outputDirectory>libs</outputDirectory>
|
||||
</fileSet>
|
||||
</fileSets>
|
||||
</assembly>
|
||||
@@ -24,7 +24,6 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-resources-plugin</artifactId>
|
||||
<version>3.1.0</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>copy-resources</id>
|
||||
@@ -55,8 +54,8 @@
|
||||
|
||||
<!-- copy libraries to target/libs/: -->
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-dependency-plugin</artifactId>
|
||||
<version>3.1.1</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>copy-libs</id>
|
||||
@@ -65,110 +64,153 @@
|
||||
<goal>copy-dependencies</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<includeScope>runtime</includeScope>
|
||||
<outputDirectory>${project.build.directory}/libs</outputDirectory>
|
||||
<excludeClassifiers>linux,mac,win</excludeClassifiers>
|
||||
<excludeArtifactIds>dbus-java,secret-service,kdewallet,hkdf,java-utils</excludeArtifactIds>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>copy-linux-libs</id>
|
||||
<phase>prepare-package</phase>
|
||||
<goals>
|
||||
<goal>copy-dependencies</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<outputDirectory>${project.build.directory}/linux-libs</outputDirectory>
|
||||
<includeGroupIds>org.openjfx</includeGroupIds>
|
||||
<classifier>linux</classifier>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>copy-linux-system-keychain-access</id>
|
||||
<phase>prepare-package</phase>
|
||||
<goals>
|
||||
<goal>copy-dependencies</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<outputDirectory>${project.build.directory}/linux-libs</outputDirectory>
|
||||
<includeArtifactIds>dbus-java,secret-service,kdewallet,hkdf,java-utils</includeArtifactIds>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>copy-mac-libs</id>
|
||||
<phase>prepare-package</phase>
|
||||
<goals>
|
||||
<goal>copy-dependencies</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<outputDirectory>${project.build.directory}/mac-libs</outputDirectory>
|
||||
<includeGroupIds>org.openjfx</includeGroupIds>
|
||||
<classifier>mac</classifier>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>copy-win-libs</id>
|
||||
<phase>prepare-package</phase>
|
||||
<goals>
|
||||
<goal>copy-dependencies</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<outputDirectory>${project.build.directory}/win-libs</outputDirectory>
|
||||
<includeGroupIds>org.openjfx</includeGroupIds>
|
||||
<classifier>win</classifier>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
|
||||
<!-- create buildkit.zip: -->
|
||||
<plugin>
|
||||
<artifactId>maven-assembly-plugin</artifactId>
|
||||
<version>3.1.1</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>assemble-linux</id>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>single</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<descriptors>
|
||||
<descriptor>assembly-linux.xml</descriptor>
|
||||
</descriptors>
|
||||
<appendAssemblyId>false</appendAssemblyId>
|
||||
<finalName>buildkit-linux</finalName>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>assemble-mac</id>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>single</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<descriptors>
|
||||
<descriptor>assembly-mac.xml</descriptor>
|
||||
</descriptors>
|
||||
<appendAssemblyId>false</appendAssemblyId>
|
||||
<finalName>buildkit-mac</finalName>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>assemble-win</id>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>single</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<descriptors>
|
||||
<descriptor>assembly-win.xml</descriptor>
|
||||
</descriptors>
|
||||
<appendAssemblyId>false</appendAssemblyId>
|
||||
<finalName>buildkit-win</finalName>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<profiles>
|
||||
<profile>
|
||||
<id>linux</id>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-assembly-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>assemble-linux</id>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>single</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<descriptors>
|
||||
<descriptor>assembly-linux.xml</descriptor>
|
||||
</descriptors>
|
||||
<appendAssemblyId>false</appendAssemblyId>
|
||||
<finalName>buildkit-linux</finalName>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-dependency-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>copy-linux-libs</id>
|
||||
<phase>prepare-package</phase>
|
||||
<goals>
|
||||
<goal>copy-dependencies</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<outputDirectory>${project.build.directory}/libs</outputDirectory>
|
||||
<includeGroupIds>org.openjfx</includeGroupIds>
|
||||
<classifier>linux</classifier>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
|
||||
<profile>
|
||||
<id>mac</id>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-assembly-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>assemble-mac</id>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>single</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<descriptors>
|
||||
<descriptor>assembly-mac.xml</descriptor>
|
||||
</descriptors>
|
||||
<appendAssemblyId>false</appendAssemblyId>
|
||||
<finalName>buildkit-mac</finalName>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-dependency-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>copy-mac-libs</id>
|
||||
<phase>prepare-package</phase>
|
||||
<goals>
|
||||
<goal>copy-dependencies</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<outputDirectory>${project.build.directory}/libs</outputDirectory>
|
||||
<includeGroupIds>org.openjfx</includeGroupIds>
|
||||
<classifier>mac</classifier>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
|
||||
<profile>
|
||||
<id>windows</id>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-assembly-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>assemble-win</id>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>single</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<descriptors>
|
||||
<descriptor>assembly-win.xml</descriptor>
|
||||
</descriptors>
|
||||
<appendAssemblyId>false</appendAssemblyId>
|
||||
<finalName>buildkit-win</finalName>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-dependency-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>copy-win-libs</id>
|
||||
<phase>prepare-package</phase>
|
||||
<goals>
|
||||
<goal>copy-dependencies</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<outputDirectory>${project.build.directory}/libs</outputDirectory>
|
||||
<includeGroupIds>org.openjfx</includeGroupIds>
|
||||
<classifier>win</classifier>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
</profiles>
|
||||
</project>
|
||||
@@ -27,6 +27,10 @@
|
||||
<groupId>org.cryptomator</groupId>
|
||||
<artifactId>webdav-nio-adapter</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.cryptomator</groupId>
|
||||
<artifactId>integrations-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.cryptomator</groupId>
|
||||
<artifactId>jni</artifactId>
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -15,6 +15,7 @@ import javax.inject.Singleton;
|
||||
import java.util.Optional;
|
||||
|
||||
@Module
|
||||
@Deprecated
|
||||
public class JniModule {
|
||||
|
||||
@Provides
|
||||
|
||||
@@ -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<KeychainAccessProvider> keychain;
|
||||
private final LoadingCache<String, BooleanProperty> passphraseStoredProperties;
|
||||
|
||||
private final KeychainAccessStrategy keychain;
|
||||
private LoadingCache<String, BooleanProperty> passphraseStoredProperties;
|
||||
|
||||
KeychainManager(KeychainAccessStrategy keychain) {
|
||||
assert keychain.isSupported();
|
||||
this.keychain = keychain;
|
||||
@Inject
|
||||
KeychainManager(ObjectExpression<KeychainAccessProvider> 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);
|
||||
@@ -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<ServiceLoader.Provider<KeychainAccessProvider>> provideAvailableKeychainAccessProviderFactories() {
|
||||
return ServiceLoader.load(KeychainAccessProvider.class).stream().collect(Collectors.toUnmodifiableSet());
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
static Set<KeychainAccessProvider> provideSupportedKeychainAccessProviders(Set<ServiceLoader.Provider<KeychainAccessProvider>> availableFactories) {
|
||||
return availableFactories.stream() //
|
||||
.map(ServiceLoader.Provider::get) //
|
||||
.filter(KeychainAccessProvider::isSupported) //
|
||||
.collect(Collectors.toUnmodifiableSet());
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
static ObjectExpression<KeychainAccessProvider> provideKeychainAccessProvider(Settings settings, Set<KeychainAccessProvider> 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());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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.");
|
||||
}
|
||||
}
|
||||
@@ -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; }
|
||||
|
||||
}
|
||||
|
||||
@@ -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 = "";
|
||||
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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<String, char[]> map = new HashMap<>();
|
||||
|
||||
@@ -1,69 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.cryptomator</groupId>
|
||||
<artifactId>main</artifactId>
|
||||
<version>1.6.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>keychain</artifactId>
|
||||
<name>System Keychain Access</name>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.cryptomator</groupId>
|
||||
<artifactId>commons</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- JavaFx -->
|
||||
<dependency>
|
||||
<groupId>org.openjfx</groupId>
|
||||
<artifactId>javafx-base</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.openjfx</groupId>
|
||||
<artifactId>javafx-graphics</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Apache -->
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Google -->
|
||||
<dependency>
|
||||
<groupId>com.google.code.gson</groupId>
|
||||
<artifactId>gson</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- DI -->
|
||||
<dependency>
|
||||
<groupId>com.google.dagger</groupId>
|
||||
<artifactId>dagger</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- secret-service lib -->
|
||||
<dependency>
|
||||
<groupId>de.swiesend</groupId>
|
||||
<artifactId>secret-service</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- kdewallet lib -->
|
||||
<dependency>
|
||||
<groupId>org.purejava</groupId>
|
||||
<artifactId>kdewallet</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Logging -->
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-simple</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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 <code>null</code> 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 <code>true</code> if this KeychainAccessStrategy works on the current machine.
|
||||
* @implNote This method must not throw any exceptions and should fail fast
|
||||
* returning <code>false</code> if it can't determine availability of the checked strategy
|
||||
*/
|
||||
boolean isSupported();
|
||||
|
||||
}
|
||||
@@ -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<KeychainAccessStrategy> provideSupportedKeychain(Set<KeychainAccessStrategy> keychainAccessStrategies) {
|
||||
return keychainAccessStrategies.stream().filter(KeychainAccessStrategy::isSupported).findFirst();
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
public static Optional<KeychainManager> provideKeychainManager(Optional<KeychainAccessStrategy> keychainAccess) {
|
||||
return keychainAccess.map(KeychainManager::new);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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<String> 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<String> 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<String> 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<String> 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<String, String> createAttributes(String key) {
|
||||
Map<String, String> attributes = new HashMap();
|
||||
attributes.put("Vault", key);
|
||||
return attributes;
|
||||
}
|
||||
}
|
||||
@@ -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<KeychainAccessStrategy> delegate;
|
||||
private final Settings settings;
|
||||
private static EnumSet<KeychainBackend> 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<KeychainAccessStrategy> 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<KeychainBackend> 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<KeychainBackend> 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);
|
||||
}
|
||||
}
|
||||
@@ -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> macFunctions;
|
||||
|
||||
@Inject
|
||||
public MacSystemKeychainAccess(Optional<MacFunctions> 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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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> winFunctions;
|
||||
private final List<Path> keychainPaths;
|
||||
private Map<String, KeychainEntry> keychainEntries;
|
||||
|
||||
@Inject
|
||||
public WindowsProtectedKeychainAccess(Optional<WinFunctions> 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<Map<String, KeychainEntry>> keychain = loadKeychainEntries(keychainPath);
|
||||
if (keychain.isPresent()) {
|
||||
keychainEntries = keychain.get();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (keychainEntries == null) {
|
||||
LOG.info("Unable to load existing keychain file, creating new keychain.");
|
||||
keychainEntries = new HashMap<>();
|
||||
}
|
||||
}
|
||||
|
||||
private Optional<Map<String, KeychainEntry>> loadKeychainEntries(Path keychainPath) {
|
||||
LOG.debug("Attempting to load keychain from {}", keychainPath);
|
||||
Type type = new TypeToken<Map<String, KeychainEntry>>() {
|
||||
}.getType();
|
||||
try (InputStream in = Files.newInputStream(keychainPath, StandardOpenOption.READ); //
|
||||
Reader reader = new InputStreamReader(in, UTF_8)) {
|
||||
return Optional.of(GSON.fromJson(reader, type));
|
||||
} catch (NoSuchFileException | JsonParseException e) {
|
||||
return Optional.empty();
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException("Could not read keychain from path " + keychainPath, e);
|
||||
}
|
||||
}
|
||||
|
||||
private void saveKeychainEntries() {
|
||||
if (keychainPaths.isEmpty()) {
|
||||
throw new IllegalStateException("Can't save keychain if no keychain path is specified.");
|
||||
}
|
||||
saveKeychainEntries(keychainPaths.get(0));
|
||||
}
|
||||
|
||||
private void saveKeychainEntries(Path keychainPath) {
|
||||
try (OutputStream out = Files.newOutputStream(keychainPath, StandardOpenOption.WRITE, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING); //
|
||||
Writer writer = new OutputStreamWriter(out, UTF_8)) {
|
||||
GSON.toJson(keychainEntries, writer);
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException("Could not read keychain from path " + keychainPath, e);
|
||||
}
|
||||
}
|
||||
|
||||
private static class KeychainEntry {
|
||||
|
||||
@SerializedName("ciphertext")
|
||||
byte[] ciphertext;
|
||||
@SerializedName("salt")
|
||||
byte[] salt;
|
||||
}
|
||||
|
||||
private static class ByteArrayJsonAdapter implements JsonSerializer<byte[]>, JsonDeserializer<byte[]> {
|
||||
|
||||
private static final BaseEncoding BASE64 = BaseEncoding.base64();
|
||||
|
||||
@Override
|
||||
public byte[] deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
|
||||
return BASE64.decode(json.getAsString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonElement serialize(byte[] src, Type typeOfSrc, JsonSerializationContext context) {
|
||||
return new JsonPrimitive(BASE64.encode(src));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,56 +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.cryptomator.common.Environment;
|
||||
import org.cryptomator.jni.WinDataProtection;
|
||||
import org.cryptomator.jni.WinFunctions;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.io.TempDir;
|
||||
import org.mockito.Mockito;
|
||||
import org.mockito.stubbing.Answer;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class WindowsProtectedKeychainAccessTest {
|
||||
|
||||
private WindowsProtectedKeychainAccess keychain;
|
||||
|
||||
@BeforeEach
|
||||
public void setup(@TempDir Path tempDir) {
|
||||
Path keychainPath = tempDir.resolve("keychainfile.tmp");
|
||||
Environment env = Mockito.mock(Environment.class);
|
||||
Mockito.when(env.getKeychainPath()).thenReturn(Stream.of(keychainPath));
|
||||
WinFunctions winFunctions = Mockito.mock(WinFunctions.class);
|
||||
WinDataProtection winDataProtection = Mockito.mock(WinDataProtection.class);
|
||||
Mockito.when(winFunctions.dataProtection()).thenReturn(winDataProtection);
|
||||
Answer<byte[]> answerReturningFirstArg = invocation -> ((byte[]) invocation.getArgument(0)).clone();
|
||||
Mockito.when(winDataProtection.protect(Mockito.any(), Mockito.any())).thenAnswer(answerReturningFirstArg);
|
||||
Mockito.when(winDataProtection.unprotect(Mockito.any(), Mockito.any())).thenAnswer(answerReturningFirstArg);
|
||||
keychain = new WindowsProtectedKeychainAccess(Optional.of(winFunctions), env);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStoreAndLoad() {
|
||||
String storedPw1 = "topSecret";
|
||||
String storedPw2 = "bottomSecret";
|
||||
keychain.storePassphrase("myPassword", storedPw1);
|
||||
keychain.storePassphrase("myOtherPassword", storedPw2);
|
||||
String loadedPw1 = new String(keychain.loadPassphrase("myPassword"));
|
||||
String loadedPw2 = new String(keychain.loadPassphrase("myOtherPassword"));
|
||||
Assertions.assertEquals(storedPw1, loadedPw1);
|
||||
Assertions.assertEquals(storedPw2, loadedPw2);
|
||||
keychain.deletePassphrase("myPassword");
|
||||
Assertions.assertNull(keychain.loadPassphrase("myPassword"));
|
||||
Assertions.assertNotNull(keychain.loadPassphrase("myOtherPassword"));
|
||||
Assertions.assertNull(keychain.loadPassphrase("nonExistingPassword"));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!--
|
||||
Copyright (c) 2014 Markus Kreusch
|
||||
This file is licensed under the terms of the MIT license.
|
||||
See the LICENSE.txt file for more info.
|
||||
|
||||
Contributors:
|
||||
Sebastian Stenzel - log4j config for WebDAV unit tests
|
||||
-->
|
||||
<Configuration status="WARN">
|
||||
|
||||
<Appenders>
|
||||
<Console name="Console" target="SYSTEM_OUT">
|
||||
<PatternLayout pattern="%16d %-5p [%c{1}:%L] %m%n"/>
|
||||
<ThresholdFilter level="WARN" onMatch="DENY" onMismatch="ACCEPT"/>
|
||||
</Console>
|
||||
<Console name="StdErr" target="SYSTEM_ERR">
|
||||
<PatternLayout pattern="%16d %-5p [%c{1}:%L] %m%n"/>
|
||||
<ThresholdFilter level="WARN" onMatch="ACCEPT" onMismatch="DENY"/>
|
||||
</Console>
|
||||
</Appenders>
|
||||
|
||||
<Loggers>
|
||||
<!-- show our own debug messages: -->
|
||||
<Logger name="org.cryptomator" level="DEBUG"/>
|
||||
<!-- mute dependencies: -->
|
||||
<Root level="INFO">
|
||||
<AppenderRef ref="Console"/>
|
||||
<AppenderRef ref="StdErr"/>
|
||||
</Root>
|
||||
</Loggers>
|
||||
|
||||
</Configuration>
|
||||
129
main/pom.xml
129
main/pom.xml
@@ -25,6 +25,10 @@
|
||||
|
||||
<!-- cryptomator dependencies -->
|
||||
<cryptomator.cryptofs.version>1.9.12</cryptomator.cryptofs.version>
|
||||
<cryptomator.integrations.version>0.1.4</cryptomator.integrations.version>
|
||||
<cryptomator.integrations.win.version>0.1.0-beta1</cryptomator.integrations.win.version>
|
||||
<cryptomator.integrations.mac.version>0.1.0-beta1</cryptomator.integrations.mac.version>
|
||||
<cryptomator.integrations.linux.version>0.1.0-beta1</cryptomator.integrations.linux.version>
|
||||
<cryptomator.jni.version>2.2.3</cryptomator.jni.version>
|
||||
<cryptomator.fuse.version>1.2.5</cryptomator.fuse.version>
|
||||
<cryptomator.dokany.version>1.1.15</cryptomator.dokany.version>
|
||||
@@ -64,11 +68,6 @@
|
||||
<artifactId>commons</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.cryptomator</groupId>
|
||||
<artifactId>keychain</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.cryptomator</groupId>
|
||||
<artifactId>ui</artifactId>
|
||||
@@ -107,6 +106,26 @@
|
||||
<version>${cryptomator.webdav.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.cryptomator</groupId>
|
||||
<artifactId>integrations-api</artifactId>
|
||||
<version>${cryptomator.integrations.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.cryptomator</groupId>
|
||||
<artifactId>integrations-win</artifactId>
|
||||
<version>${cryptomator.integrations.win.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.cryptomator</groupId>
|
||||
<artifactId>integrations-mac</artifactId>
|
||||
<version>${cryptomator.integrations.mac.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.cryptomator</groupId>
|
||||
<artifactId>integrations-linux</artifactId>
|
||||
<version>${cryptomator.integrations.linux.version}</version>
|
||||
</dependency>
|
||||
<dependency> <!-- deprecated: will be replaced by integrations-api -->
|
||||
<groupId>org.cryptomator</groupId>
|
||||
<artifactId>jni</artifactId>
|
||||
<version>${cryptomator.jni.version}</version>
|
||||
@@ -163,18 +182,6 @@
|
||||
<version>${commons-lang3.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Linux System Keychain -->
|
||||
<dependency>
|
||||
<groupId>de.swiesend</groupId>
|
||||
<artifactId>secret-service</artifactId>
|
||||
<version>${secret-service.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.purejava</groupId>
|
||||
<artifactId>kdewallet</artifactId>
|
||||
<version>${kdewallet.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- JWT -->
|
||||
<dependency>
|
||||
<groupId>com.auth0</groupId>
|
||||
@@ -256,7 +263,6 @@
|
||||
|
||||
<modules>
|
||||
<module>commons</module>
|
||||
<module>keychain</module>
|
||||
<module>ui</module>
|
||||
<module>launcher</module>
|
||||
</modules>
|
||||
@@ -279,26 +285,87 @@
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
<profile>
|
||||
<id>mac</id>
|
||||
<activation>
|
||||
<os>
|
||||
<family>mac</family>
|
||||
</os>
|
||||
<property>
|
||||
<name>idea.version</name>
|
||||
</property>
|
||||
</activation>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.cryptomator</groupId>
|
||||
<artifactId>integrations-mac</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</profile>
|
||||
<profile>
|
||||
<id>linux</id>
|
||||
<activation>
|
||||
<os>
|
||||
<family>unix</family>
|
||||
<name>Linux</name>
|
||||
</os>
|
||||
<property>
|
||||
<name>idea.version</name>
|
||||
</property>
|
||||
</activation>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.cryptomator</groupId>
|
||||
<artifactId>integrations-linux</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</profile>
|
||||
<profile>
|
||||
<id>windows</id>
|
||||
<activation>
|
||||
<os>
|
||||
<family>windows</family>
|
||||
</os>
|
||||
<property>
|
||||
<name>idea.version</name>
|
||||
</property>
|
||||
</activation>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.cryptomator</groupId>
|
||||
<artifactId>integrations-win</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</profile>
|
||||
</profiles>
|
||||
|
||||
<build>
|
||||
<pluginManagement>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.8.1</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-resources-plugin</artifactId>
|
||||
<version>3.2.0</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-dependency-plugin</artifactId>
|
||||
<version>3.1.2</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>copy-libs</id>
|
||||
<goals>
|
||||
<goal>copy-dependencies</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<outputDirectory>${project.build.directory}/libs</outputDirectory>
|
||||
<includeScope>runtime</includeScope>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-assembly-plugin</artifactId>
|
||||
<version>3.3.0</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<version>2.22.2</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
@@ -348,7 +415,6 @@
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.8.1</version>
|
||||
<configuration>
|
||||
<release>14</release>
|
||||
<annotationProcessorPaths>
|
||||
@@ -363,7 +429,6 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<version>2.22.2</version>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
@@ -10,10 +10,6 @@
|
||||
<name>Cryptomator GUI</name>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.cryptomator</groupId>
|
||||
<artifactId>keychain</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.cryptomator</groupId>
|
||||
<artifactId>commons</artifactId>
|
||||
|
||||
@@ -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<CharSequence> newPassword;
|
||||
private final ErrorComponent.Builder errorComponent;
|
||||
private final Optional<KeychainManager> 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<CharSequence> newPassword, ErrorComponent.Builder errorComponent, Optional<KeychainManager> keychain) {
|
||||
public ChangePasswordController(@ChangePasswordWindow Stage window, @ChangePasswordWindow Vault vault, @Named("newPassword") ObjectProperty<CharSequence> 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);
|
||||
|
||||
@@ -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<KeychainManager> keychain;
|
||||
|
||||
@Inject
|
||||
public VaultService(ExecutorService executorService, Optional<KeychainManager> keychain) {
|
||||
public VaultService(ExecutorService executorService) {
|
||||
this.executorService = executorService;
|
||||
this.keychain = keychain;
|
||||
}
|
||||
|
||||
public void reveal(Vault vault) {
|
||||
|
||||
@@ -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<KeychainManager> keychain;
|
||||
private final KeychainManager keychain;
|
||||
private final BooleanProperty confirmedResult;
|
||||
|
||||
@Inject
|
||||
public ForgetPasswordController(@ForgetPasswordWindow Stage window, @ForgetPasswordWindow Vault vault, Optional<KeychainManager> 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) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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> vault;
|
||||
private final FxApplication application;
|
||||
private final VaultOptionsComponent.Builder vaultOptionsWindow;
|
||||
private final Optional<KeychainManager> keychainManagerOptional;
|
||||
private final KeychainManager keychain;
|
||||
private final Stage mainWindow;
|
||||
private final BooleanExpression passwordSaved;
|
||||
|
||||
@Inject
|
||||
VaultDetailLockedController(ObjectProperty<Vault> vault, FxApplication application, VaultOptionsComponent.Builder vaultOptionsWindow, Optional<KeychainManager> keychainManagerOptional, @MainWindow Stage mainWindow) {
|
||||
VaultDetailLockedController(ObjectProperty<Vault> 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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<KeychainManager> keychain;
|
||||
private final KeychainManager keychain;
|
||||
private final ObjectProperty<FileSystemCapabilityChecker.Capability> missingCapability;
|
||||
private final ErrorComponent.Builder errorComponent;
|
||||
private final Lazy<Scene> 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<KeychainManager> keychain, @Named("capabilityErrorCause") ObjectProperty<FileSystemCapabilityChecker.Capability> missingCapability, @FxmlScene(FxmlFile.MIGRATION_START) Lazy<Scene> startScene, @FxmlScene(FxmlFile.MIGRATION_SUCCESS) Lazy<Scene> successScene, @FxmlScene(FxmlFile.MIGRATION_CAPABILITY_ERROR) Lazy<Scene> capabilityErrorScene, @FxmlScene(FxmlFile.MIGRATION_IMPOSSIBLE) Lazy<Scene> impossibleScene, ErrorComponent.Builder errorComponent) {
|
||||
|
||||
public MigrationRunController(@MigrationWindow Stage window, @MigrationWindow Vault vault, ExecutorService executor, ScheduledExecutorService scheduler, KeychainManager keychain, @Named("capabilityErrorCause") ObjectProperty<FileSystemCapabilityChecker.Capability> missingCapability, @FxmlScene(FxmlFile.MIGRATION_START) Lazy<Scene> startScene, @FxmlScene(FxmlFile.MIGRATION_SUCCESS) Lazy<Scene> successScene, @FxmlScene(FxmlFile.MIGRATION_CAPABILITY_ERROR) Lazy<Scene> capabilityErrorScene, @FxmlScene(FxmlFile.MIGRATION_IMPOSSIBLE) Lazy<Scene> 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);
|
||||
|
||||
@@ -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<KeychainAccessStrategy> keychain;
|
||||
private final Set<KeychainAccessProvider> keychainAccessProviders;
|
||||
public ChoiceBox<UiTheme> themeChoiceBox;
|
||||
public ChoiceBox<KeychainBackend> 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> autoStartStrategy, Optional<KeychainAccessStrategy> keychain, ObjectProperty<SelectedPreferencesTab> selectedTabProperty, LicenseHolder licenseHolder, ExecutorService executor, ResourceBundle resourceBundle, Application application, Environment environment) {
|
||||
GeneralPreferencesController(Settings settings, @Named("trayMenuSupported") boolean trayMenuSupported, Optional<AutoStartStrategy> autoStartStrategy, Set<KeychainAccessProvider> keychainAccessProviders, ObjectProperty<SelectedPreferencesTab> 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<KeychainBackend> backends = LinuxSystemKeychainAccess.getAvailableKeychainBackends();
|
||||
return backends.toArray(KeychainBackend[]::new);
|
||||
}
|
||||
if (SystemUtils.IS_OS_MAC || SystemUtils.IS_OS_WINDOWS) {
|
||||
return KeychainBackend.supportedBackends();
|
||||
}
|
||||
return new KeychainBackend[]{};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<char[]> savedPassword;
|
||||
private final UserInteractionLock<UnlockModule.PasswordEntry> passwordEntryLock;
|
||||
private final ForgetPasswordComponent.Builder forgetPassword;
|
||||
private final Optional<KeychainManager> keychain;
|
||||
private final KeychainManager keychain;
|
||||
private final ObjectBinding<ContentDisplay> 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<char[]> password, @Named("savePassword") AtomicBoolean savePassword, @Named("savedPassword") Optional<char[]> savedPassword, UserInteractionLock<UnlockModule.PasswordEntry> passwordEntryLock, ForgetPasswordComponent.Builder forgetPassword, Optional<KeychainManager> keychain) {
|
||||
public UnlockController(@UnlockWindow Stage window, @UnlockWindow Vault vault, AtomicReference<char[]> password, @Named("savePassword") AtomicBoolean savePassword, @Named("savedPassword") Optional<char[]> savedPassword, UserInteractionLock<UnlockModule.PasswordEntry> 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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<char[]> provideStoredPassword(Optional<KeychainManager> keychain, @UnlockWindow Vault vault) {
|
||||
return keychain.map(k -> {
|
||||
static Optional<char[]> 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
|
||||
|
||||
@@ -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<Boolean> {
|
||||
private final AtomicBoolean savePassword;
|
||||
private final Optional<char[]> savedPassword;
|
||||
private final UserInteractionLock<PasswordEntry> passwordEntryLock;
|
||||
private final Optional<KeychainManager> keychain;
|
||||
private final KeychainManager keychain;
|
||||
private final Lazy<Scene> unlockScene;
|
||||
private final Lazy<Scene> successScene;
|
||||
private final Lazy<Scene> invalidMountPointScene;
|
||||
private final ErrorComponent.Builder errorComponent;
|
||||
|
||||
@Inject
|
||||
UnlockWorkflow(@UnlockWindow Stage window, @UnlockWindow Vault vault, VaultService vaultService, AtomicReference<char[]> password, @Named("savePassword") AtomicBoolean savePassword, @Named("savedPassword") Optional<char[]> savedPassword, UserInteractionLock<PasswordEntry> passwordEntryLock, Optional<KeychainManager> keychain, @FxmlScene(FxmlFile.UNLOCK) Lazy<Scene> unlockScene, @FxmlScene(FxmlFile.UNLOCK_SUCCESS) Lazy<Scene> successScene, @FxmlScene(FxmlFile.UNLOCK_INVALID_MOUNT_POINT) Lazy<Scene> invalidMountPointScene, ErrorComponent.Builder errorComponent) {
|
||||
UnlockWorkflow(@UnlockWindow Stage window, @UnlockWindow Vault vault, VaultService vaultService, AtomicReference<char[]> password, @Named("savePassword") AtomicBoolean savePassword, @Named("savedPassword") Optional<char[]> savedPassword, UserInteractionLock<PasswordEntry> passwordEntryLock, KeychainManager keychain, @FxmlScene(FxmlFile.UNLOCK) Lazy<Scene> unlockScene, @FxmlScene(FxmlFile.UNLOCK_SUCCESS) Lazy<Scene> successScene, @FxmlScene(FxmlFile.UNLOCK_INVALID_MOUNT_POINT) Lazy<Scene> invalidMountPointScene, ErrorComponent.Builder errorComponent) {
|
||||
this.window = window;
|
||||
this.vault = vault;
|
||||
this.vaultService = vaultService;
|
||||
@@ -150,9 +150,9 @@ public class UnlockWorkflow extends Task<Boolean> {
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -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<KeychainManager> keychainManagerOptional;
|
||||
private final KeychainManager keychain;
|
||||
private final BooleanExpression passwordSaved;
|
||||
|
||||
|
||||
@Inject
|
||||
MasterkeyOptionsController(@VaultOptionsWindow Vault vault, @VaultOptionsWindow Stage window, ChangePasswordComponent.Builder changePasswordWindow, RecoveryKeyComponent.Builder recoveryKeyWindow, Optional<KeychainManager> 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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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/)
|
||||
|
||||
Reference in New Issue
Block a user