diff --git a/main/buildkit/pom.xml b/main/buildkit/pom.xml index 32fa59d67..4c9dac1ce 100644 --- a/main/buildkit/pom.xml +++ b/main/buildkit/pom.xml @@ -62,6 +62,7 @@ ${project.build.directory}/libs linux,mac,win + dbus-java,secret-service,hkdf,java-utils @@ -76,6 +77,17 @@ linux + + copy-linux-secret-service + prepare-package + + copy-dependencies + + + ${project.build.directory}/linux-libs + dbus-java,secret-service,hkdf,java-utils + + copy-mac-libs prepare-package diff --git a/main/keychain/pom.xml b/main/keychain/pom.xml index 29471ed1d..01e276cc9 100644 --- a/main/keychain/pom.xml +++ b/main/keychain/pom.xml @@ -39,7 +39,14 @@ com.google.dagger dagger - + + + + de.swiesend + secret-service + 1.0.0-RC.3 + + org.slf4j diff --git a/main/keychain/src/main/java/org/cryptomator/keychain/GnomeKeyringAccess.java b/main/keychain/src/main/java/org/cryptomator/keychain/GnomeKeyringAccess.java new file mode 100644 index 000000000..998fdfab7 --- /dev/null +++ b/main/keychain/src/main/java/org/cryptomator/keychain/GnomeKeyringAccess.java @@ -0,0 +1,9 @@ +package org.cryptomator.keychain; + +public interface GnomeKeyringAccess { + public void storePassword(String key, CharSequence passphrase); + + public char[] loadPassword(String key); + + public void deletePassword(String key); +} diff --git a/main/keychain/src/main/java/org/cryptomator/keychain/GnomeKeyringAccessImpl.java b/main/keychain/src/main/java/org/cryptomator/keychain/GnomeKeyringAccessImpl.java new file mode 100644 index 000000000..34dcdb5fa --- /dev/null +++ b/main/keychain/src/main/java/org/cryptomator/keychain/GnomeKeyringAccessImpl.java @@ -0,0 +1,52 @@ +package org.cryptomator.keychain; + +import org.freedesktop.secret.simple.SimpleCollection; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class GnomeKeyringAccessImpl implements GnomeKeyringAccess { + private static final Logger LOG = LoggerFactory.getLogger(GnomeKeyringAccessImpl.class); + private SimpleCollection keyring; + + public GnomeKeyringAccessImpl() { + try { + keyring = new SimpleCollection(); + } catch (IOException e) { + LOG.error("D-Bus reports a problem.", e); + } + } + + public void storePassword(String key, CharSequence passphrase) { + List list = keyring.getItems(createAttributes(key)); + if (list == null) { + keyring.createItem("Cryptomator", passphrase, createAttributes(key)); + } + } + + public char[] loadPassword(String key) { + List list = keyring.getItems(createAttributes(key)); + if (list != null) { + return keyring.getSecret(list.get(0)); + } else { + return null; + } + } + + public void deletePassword(String key) { + List list = keyring.getItems(createAttributes(key)); + if (list != null) { + keyring.deleteItem(list.get(0)); + } + } + + private Map createAttributes(String key) { + Map attributes = new HashMap(); + attributes.put("Vault", key); + return attributes; + } +} diff --git a/main/keychain/src/main/java/org/cryptomator/keychain/KeychainModule.java b/main/keychain/src/main/java/org/cryptomator/keychain/KeychainModule.java index 5db7bc372..f05a90f1f 100644 --- a/main/keychain/src/main/java/org/cryptomator/keychain/KeychainModule.java +++ b/main/keychain/src/main/java/org/cryptomator/keychain/KeychainModule.java @@ -31,8 +31,8 @@ public class KeychainModule { @Provides @ElementsIntoSet - Set provideKeychainAccessStrategies(MacSystemKeychainAccess macKeychain, WindowsProtectedKeychainAccess winKeychain) { - return Sets.newHashSet(macKeychain, winKeychain); + Set provideKeychainAccessStrategies(MacSystemKeychainAccess macKeychain, WindowsProtectedKeychainAccess winKeychain, LinuxSecretServiceAccess linKeychain) { + return Sets.newHashSet(macKeychain, winKeychain, linKeychain); } @Provides diff --git a/main/keychain/src/main/java/org/cryptomator/keychain/LinuxKeychainTester.java b/main/keychain/src/main/java/org/cryptomator/keychain/LinuxKeychainTester.java new file mode 100644 index 000000000..1466e895c --- /dev/null +++ b/main/keychain/src/main/java/org/cryptomator/keychain/LinuxKeychainTester.java @@ -0,0 +1,25 @@ +package org.cryptomator.keychain; + +import java.util.Optional; + +public class LinuxKeychainTester { + public static boolean secretServiceIsAvailable() { + try { + Class.forName("org.freedesktop.secret.simple.SimpleCollection"); + return true; + } catch (ClassNotFoundException e) { + return false; + } + } + + public static Optional getSecretService() { + if (!secretServiceIsAvailable()) return Optional.empty(); + try { + Class clazz = Class.forName("org.cryptomator.keychain.GnomeKeyringAccessImpl"); + GnomeKeyringAccess keyring = (GnomeKeyringAccess) clazz.getDeclaredConstructor().newInstance(); + return Optional.of(keyring); + } catch (Exception e) { + return Optional.empty(); + } + } +} diff --git a/main/keychain/src/main/java/org/cryptomator/keychain/LinuxSecretServiceAccess.java b/main/keychain/src/main/java/org/cryptomator/keychain/LinuxSecretServiceAccess.java new file mode 100644 index 000000000..ef8dcb092 --- /dev/null +++ b/main/keychain/src/main/java/org/cryptomator/keychain/LinuxSecretServiceAccess.java @@ -0,0 +1,39 @@ +package org.cryptomator.keychain; + +import com.google.common.base.Preconditions; +import org.apache.commons.lang3.SystemUtils; + +import javax.inject.Inject; +import java.util.Optional; + +public class LinuxSecretServiceAccess implements KeychainAccessStrategy { + private final Optional gnomeLoginKeyring; + + @Inject + public LinuxSecretServiceAccess() { + gnomeLoginKeyring = LinuxKeychainTester.getSecretService(); + } + + @Override + public boolean isSupported() { + return SystemUtils.IS_OS_LINUX && LinuxKeychainTester.getSecretService().isPresent(); + } + + @Override + public void storePassphrase(String key, CharSequence passphrase) { + Preconditions.checkState(gnomeLoginKeyring.isPresent()); + gnomeLoginKeyring.get().storePassword(key, passphrase); + } + + @Override + public char[] loadPassphrase(String key) { + Preconditions.checkState(gnomeLoginKeyring.isPresent()); + return gnomeLoginKeyring.get().loadPassword(key); + } + + @Override + public void deletePassphrase(String key) { + Preconditions.checkState(gnomeLoginKeyring.isPresent()); + gnomeLoginKeyring.get().deletePassword(key); + } +} diff --git a/main/keychain/src/test/java/org/cryptomator/keychain/TestKeychainModule.java b/main/keychain/src/test/java/org/cryptomator/keychain/TestKeychainModule.java index 66addc62a..80c4e6aa3 100644 --- a/main/keychain/src/test/java/org/cryptomator/keychain/TestKeychainModule.java +++ b/main/keychain/src/test/java/org/cryptomator/keychain/TestKeychainModule.java @@ -7,13 +7,11 @@ package org.cryptomator.keychain; import java.util.Set; -import com.google.common.collect.Sets; - public class TestKeychainModule extends KeychainModule { @Override - Set provideKeychainAccessStrategies(MacSystemKeychainAccess macKeychain, WindowsProtectedKeychainAccess winKeychain) { - return Sets.newHashSet(new MapKeychainAccess()); + Set provideKeychainAccessStrategies(MacSystemKeychainAccess macKeychain, WindowsProtectedKeychainAccess winKeychain, LinuxSecretServiceAccess linKeychain) { + return Set.of(new MapKeychainAccess()); } }