From 2f0de3520af260ce433871a8e43f4a710deab7e0 Mon Sep 17 00:00:00 2001 From: Sebastian Stenzel Date: Wed, 13 May 2020 19:59:32 +0200 Subject: [PATCH 01/21] Refactored KeychainAccess in preparation of #1183, #1182 --- main/keychain/pom.xml | 15 ++- .../cryptomator/keychain/KeychainAccess.java | 38 ------ .../keychain/KeychainAccessStrategy.java | 31 ++++- .../cryptomator/keychain/KeychainManager.java | 117 ++++++++++++++++++ .../cryptomator/keychain/KeychainModule.java | 30 +++-- .../LinuxSecretServiceKeychainAccess.java | 2 + .../keychain/MacSystemKeychainAccess.java | 2 + .../WindowsProtectedKeychainAccess.java | 2 + .../keychain/KeychainManagerTest.java | 55 ++++++++ .../keychain/KeychainModuleTest.java | 24 ---- .../keychain/TestKeychainComponent.java | 19 --- .../keychain/TestKeychainModule.java | 17 --- .../ChangePasswordController.java | 6 +- .../cryptomator/ui/common/VaultService.java | 9 +- .../ForgetPasswordController.java | 12 +- .../ui/migration/MigrationRunController.java | 14 +-- .../ui/unlock/UnlockController.java | 10 +- .../cryptomator/ui/unlock/UnlockModule.java | 12 +- .../cryptomator/ui/unlock/UnlockWorkflow.java | 6 +- 19 files changed, 272 insertions(+), 149 deletions(-) delete mode 100644 main/keychain/src/main/java/org/cryptomator/keychain/KeychainAccess.java create mode 100644 main/keychain/src/main/java/org/cryptomator/keychain/KeychainManager.java create mode 100644 main/keychain/src/test/java/org/cryptomator/keychain/KeychainManagerTest.java delete mode 100644 main/keychain/src/test/java/org/cryptomator/keychain/KeychainModuleTest.java delete mode 100644 main/keychain/src/test/java/org/cryptomator/keychain/TestKeychainComponent.java delete mode 100644 main/keychain/src/test/java/org/cryptomator/keychain/TestKeychainModule.java diff --git a/main/keychain/pom.xml b/main/keychain/pom.xml index 1d09fcd673..fd2b26c3a6 100644 --- a/main/keychain/pom.xml +++ b/main/keychain/pom.xml @@ -15,16 +15,27 @@ commons + + + org.openjfx + javafx-base + + + org.openjfx + javafx-graphics + + + org.apache.commons commons-lang3 + + com.google.code.gson gson - - com.google.guava guava diff --git a/main/keychain/src/main/java/org/cryptomator/keychain/KeychainAccess.java b/main/keychain/src/main/java/org/cryptomator/keychain/KeychainAccess.java deleted file mode 100644 index 563794dc07..0000000000 --- a/main/keychain/src/main/java/org/cryptomator/keychain/KeychainAccess.java +++ /dev/null @@ -1,38 +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 KeychainAccess { - - /** - * Associates a passphrase with a given key. - * - * @param key Key used to retrieve the passphrase via {@link #loadPassphrase(String)}. - * @param passphrase The secret to store in this keychain. - */ - void storePassphrase(String key, CharSequence passphrase) throws KeychainAccessException; - - /** - * @param key Unique key previously used while {@link #storePassphrase(String, CharSequence) storing a passphrase}. - * @return The stored passphrase for the given key or null if no value for the given key could be found. - */ - char[] loadPassphrase(String key) throws KeychainAccessException; - - /** - * Deletes a passphrase with a given key. - * - * @param key Unique key previously used while {@link #storePassphrase(String, CharSequence) storing a passphrase}. - */ - void deletePassphrase(String key) throws KeychainAccessException; - - /** - * Updates a passphrase with a given key. - * - * @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; -} diff --git a/main/keychain/src/main/java/org/cryptomator/keychain/KeychainAccessStrategy.java b/main/keychain/src/main/java/org/cryptomator/keychain/KeychainAccessStrategy.java index a248d08f58..8976e6c554 100644 --- a/main/keychain/src/main/java/org/cryptomator/keychain/KeychainAccessStrategy.java +++ b/main/keychain/src/main/java/org/cryptomator/keychain/KeychainAccessStrategy.java @@ -5,7 +5,36 @@ *******************************************************************************/ package org.cryptomator.keychain; -interface KeychainAccessStrategy extends KeychainAccess { +interface KeychainAccessStrategy { + + /** + * Associates a passphrase with a given key. + * + * @param key Key used to retrieve the passphrase via {@link #loadPassphrase(String)}. + * @param passphrase The secret to store in this keychain. + */ + void storePassphrase(String key, CharSequence passphrase) throws KeychainAccessException; + + /** + * @param key Unique key previously used while {@link #storePassphrase(String, CharSequence) storing a passphrase}. + * @return The stored passphrase for the given key or null if no value for the given key could be found. + */ + char[] loadPassphrase(String key) throws KeychainAccessException; + + /** + * Deletes a passphrase with a given key. + * + * @param key Unique key previously used while {@link #storePassphrase(String, CharSequence) storing a passphrase}. + */ + void deletePassphrase(String key) throws KeychainAccessException; + + /** + * Updates a passphrase with a given key. + * + * @param key Unique key previously used while {@link #storePassphrase(String, CharSequence) storing a passphrase}. + * @param passphrase The secret to be updated in this keychain. + */ + void changePassphrase(String key, CharSequence passphrase) throws KeychainAccessException; /** * @return true if this KeychainAccessStrategy works on the current machine. diff --git a/main/keychain/src/main/java/org/cryptomator/keychain/KeychainManager.java b/main/keychain/src/main/java/org/cryptomator/keychain/KeychainManager.java new file mode 100644 index 0000000000..300b5b0353 --- /dev/null +++ b/main/keychain/src/main/java/org/cryptomator/keychain/KeychainManager.java @@ -0,0 +1,117 @@ +package org.cryptomator.keychain; + +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.CacheLoader; +import com.google.common.cache.LoadingCache; +import javafx.application.Platform; +import javafx.beans.property.BooleanProperty; +import javafx.beans.property.ReadOnlyBooleanProperty; +import javafx.beans.property.SimpleBooleanProperty; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Arrays; + +public class KeychainManager implements KeychainAccessStrategy { + + private static final Logger LOG = LoggerFactory.getLogger(KeychainManager.class); + + private final KeychainAccessStrategy keychain; + private LoadingCache passphraseStoredProperties; + + KeychainManager(KeychainAccessStrategy keychain) { + assert keychain.isSupported(); + this.keychain = keychain; + this.passphraseStoredProperties = CacheBuilder.newBuilder() // + .weakValues() // + .build(CacheLoader.from(this::createStoredPassphraseProperty)); + } + + @Override + public void storePassphrase(String key, CharSequence passphrase) throws KeychainAccessException { + keychain.storePassphrase(key, passphrase); + setPassphraseStored(key, true); + } + + @Override + public char[] loadPassphrase(String key) throws KeychainAccessException { + char[] passphrase = keychain.loadPassphrase(key); + setPassphraseStored(key, passphrase != null); + return passphrase; + } + + @Override + public void deletePassphrase(String key) throws KeychainAccessException { + keychain.deletePassphrase(key); + setPassphraseStored(key, false); + } + + @Override + public void changePassphrase(String key, CharSequence passphrase) throws KeychainAccessException { + keychain.changePassphrase(key, passphrase); + setPassphraseStored(key, true); + } + + @Override + public boolean isSupported() { + return true; + } + + /** + * Checks if the keychain knows a passphrase for the given key. + *

+ * Expensive operation. If possible, use {@link #getPassphraseStoredProperty(String)} instead. + * + * @param key The key to look up + * @return true if a password for key is stored. + * @throws KeychainAccessException + */ + public boolean isPassphraseStored(String key) throws KeychainAccessException { + char[] storedPw = null; + try { + storedPw = keychain.loadPassphrase(key); + return storedPw != null; + } finally { + if (storedPw != null) { + Arrays.fill(storedPw, ' '); + } + } + } + + private void setPassphraseStored(String key, boolean value) { + BooleanProperty property = passphraseStoredProperties.getIfPresent(key); + if (property != null) { + if (Platform.isFxApplicationThread()) { + property.set(value); + } else { + LOG.warn(""); + Platform.runLater(() -> property.set(value)); + } + } + } + + /** + * Returns an observable property for use in the UI that tells whether a passphrase is stored for the given key. + *

+ * Assuming that this process is the only process modifying Cryptomator-related items in the system keychain, this + * property stays in memory in an attempt to avoid unnecessary calls to the system keychain. Note that due to this + * fact the value stored in the returned property is not 100% reliable. Code defensively! + * + * @param key The key to look up + * @return An observable property which is true when it almost certain that a password for key is stored. + * @see #isPassphraseStored(String) + */ + public ReadOnlyBooleanProperty getPassphraseStoredProperty(String key) { + return passphraseStoredProperties.getUnchecked(key); + } + + private BooleanProperty createStoredPassphraseProperty(String key) { + try { + LOG.warn("LOAD"); // TODO remove + return new SimpleBooleanProperty(isPassphraseStored(key)); + } catch (KeychainAccessException e) { + return new SimpleBooleanProperty(false); + } + } + +} diff --git a/main/keychain/src/main/java/org/cryptomator/keychain/KeychainModule.java b/main/keychain/src/main/java/org/cryptomator/keychain/KeychainModule.java index d36c8e4b51..1db94fec6b 100644 --- a/main/keychain/src/main/java/org/cryptomator/keychain/KeychainModule.java +++ b/main/keychain/src/main/java/org/cryptomator/keychain/KeychainModule.java @@ -5,10 +5,10 @@ *******************************************************************************/ package org.cryptomator.keychain; -import com.google.common.collect.Sets; +import dagger.Binds; import dagger.Module; import dagger.Provides; -import dagger.multibindings.ElementsIntoSet; +import dagger.multibindings.IntoSet; import org.cryptomator.common.JniModule; import javax.inject.Singleton; @@ -16,18 +16,30 @@ import java.util.Set; @Module(includes = {JniModule.class}) -public class KeychainModule { +public abstract class KeychainModule { + + @Binds + @IntoSet + abstract KeychainAccessStrategy bindMacSystemKeychainAccess(MacSystemKeychainAccess keychainAccessStrategy); + + @Binds + @IntoSet + abstract KeychainAccessStrategy bindWindowsProtectedKeychainAccess(WindowsProtectedKeychainAccess keychainAccessStrategy); + + @Binds + @IntoSet + abstract KeychainAccessStrategy bindLinuxSecretServiceKeychainAccess(LinuxSecretServiceKeychainAccess keychainAccessStrategy); @Provides - @ElementsIntoSet - Set provideKeychainAccessStrategies(MacSystemKeychainAccess macKeychain, WindowsProtectedKeychainAccess winKeychain, LinuxSecretServiceKeychainAccess linKeychain) { - return Sets.newHashSet(macKeychain, winKeychain, linKeychain); + @Singleton + static Optional provideSupportedKeychain(Set keychainAccessStrategies) { + return keychainAccessStrategies.stream().filter(KeychainAccessStrategy::isSupported).findFirst(); } - + @Provides @Singleton - public Optional provideSupportedKeychain(Set keychainAccessStrategies) { - return keychainAccessStrategies.stream().filter(KeychainAccessStrategy::isSupported).map(KeychainAccess.class::cast).findFirst(); + public static Optional provideKeychainManager(Optional keychainAccess) { + return keychainAccess.map(KeychainManager::new); } } diff --git a/main/keychain/src/main/java/org/cryptomator/keychain/LinuxSecretServiceKeychainAccess.java b/main/keychain/src/main/java/org/cryptomator/keychain/LinuxSecretServiceKeychainAccess.java index 7cf0b5e7ba..f11bdbd450 100644 --- a/main/keychain/src/main/java/org/cryptomator/keychain/LinuxSecretServiceKeychainAccess.java +++ b/main/keychain/src/main/java/org/cryptomator/keychain/LinuxSecretServiceKeychainAccess.java @@ -3,11 +3,13 @@ import org.apache.commons.lang3.SystemUtils; import javax.inject.Inject; +import javax.inject.Singleton; import java.util.Optional; /** * A facade to LinuxSecretServiceKeychainAccessImpl that doesn't depend on libraries that are unavailable on Mac and Windows. */ +@Singleton public class LinuxSecretServiceKeychainAccess implements KeychainAccessStrategy { // the actual implementation is hidden in this delegate object which is loaded via reflection, diff --git a/main/keychain/src/main/java/org/cryptomator/keychain/MacSystemKeychainAccess.java b/main/keychain/src/main/java/org/cryptomator/keychain/MacSystemKeychainAccess.java index 382ec0afff..95531b7ae0 100644 --- a/main/keychain/src/main/java/org/cryptomator/keychain/MacSystemKeychainAccess.java +++ b/main/keychain/src/main/java/org/cryptomator/keychain/MacSystemKeychainAccess.java @@ -8,11 +8,13 @@ import java.util.Optional; import javax.inject.Inject; +import javax.inject.Singleton; import org.apache.commons.lang3.SystemUtils; import org.cryptomator.jni.MacFunctions; import org.cryptomator.jni.MacKeychainAccess; +@Singleton class MacSystemKeychainAccess implements KeychainAccessStrategy { private final Optional macFunctions; diff --git a/main/keychain/src/main/java/org/cryptomator/keychain/WindowsProtectedKeychainAccess.java b/main/keychain/src/main/java/org/cryptomator/keychain/WindowsProtectedKeychainAccess.java index 15525aca3e..408d7d6e52 100644 --- a/main/keychain/src/main/java/org/cryptomator/keychain/WindowsProtectedKeychainAccess.java +++ b/main/keychain/src/main/java/org/cryptomator/keychain/WindowsProtectedKeychainAccess.java @@ -25,6 +25,7 @@ import org.slf4j.LoggerFactory; import javax.inject.Inject; +import javax.inject.Singleton; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; @@ -50,6 +51,7 @@ import static java.nio.charset.StandardCharsets.UTF_8; +@Singleton class WindowsProtectedKeychainAccess implements KeychainAccessStrategy { private static final Logger LOG = LoggerFactory.getLogger(WindowsProtectedKeychainAccess.class); diff --git a/main/keychain/src/test/java/org/cryptomator/keychain/KeychainManagerTest.java b/main/keychain/src/test/java/org/cryptomator/keychain/KeychainManagerTest.java new file mode 100644 index 0000000000..67f10e0358 --- /dev/null +++ b/main/keychain/src/test/java/org/cryptomator/keychain/KeychainManagerTest.java @@ -0,0 +1,55 @@ +package org.cryptomator.keychain; + + +import javafx.application.Platform; +import javafx.beans.property.ReadOnlyBooleanProperty; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; + + +class KeychainManagerTest { + + @Test + public void testStoreAndLoad() throws KeychainAccessException { + KeychainManager keychainManager = new KeychainManager(new MapKeychainAccess()); + keychainManager.storePassphrase("test", "asd"); + Assertions.assertArrayEquals("asd".toCharArray(), keychainManager.loadPassphrase("test")); + } + + @Nested + public static class WhenObservingProperties { + + @BeforeAll + public static void startup() throws InterruptedException { + CountDownLatch latch = new CountDownLatch(1); + Platform.startup(latch::countDown); + latch.await(5, TimeUnit.SECONDS); + } + + @Test + public void testPropertyChangesWhenStoringPassword() throws KeychainAccessException, InterruptedException { + KeychainManager keychainManager = new KeychainManager(new MapKeychainAccess()); + ReadOnlyBooleanProperty property = keychainManager.getPassphraseStoredProperty("test"); + Assertions.assertEquals(false, property.get()); + + keychainManager.storePassphrase("test", "bar"); + + AtomicBoolean result = new AtomicBoolean(false); + CountDownLatch latch = new CountDownLatch(1); + Platform.runLater(() -> { + result.set(property.get()); + latch.countDown(); + }); + latch.await(1, TimeUnit.SECONDS); + Assertions.assertEquals(true, result.get()); + } + + } + +} \ No newline at end of file diff --git a/main/keychain/src/test/java/org/cryptomator/keychain/KeychainModuleTest.java b/main/keychain/src/test/java/org/cryptomator/keychain/KeychainModuleTest.java deleted file mode 100644 index 7b3c59899f..0000000000 --- a/main/keychain/src/test/java/org/cryptomator/keychain/KeychainModuleTest.java +++ /dev/null @@ -1,24 +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.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; - -import java.util.Optional; - -public class KeychainModuleTest { - - @Test - public void testGetKeychain() throws KeychainAccessException { - Optional keychainAccess = DaggerTestKeychainComponent.builder().keychainModule(new TestKeychainModule()).build().keychainAccess(); - Assertions.assertTrue(keychainAccess.isPresent()); - Assertions.assertTrue(keychainAccess.get() instanceof MapKeychainAccess); - keychainAccess.get().storePassphrase("test", "asd"); - Assertions.assertArrayEquals("asd".toCharArray(), keychainAccess.get().loadPassphrase("test")); - } - -} diff --git a/main/keychain/src/test/java/org/cryptomator/keychain/TestKeychainComponent.java b/main/keychain/src/test/java/org/cryptomator/keychain/TestKeychainComponent.java deleted file mode 100644 index 82c4b82ae1..0000000000 --- a/main/keychain/src/test/java/org/cryptomator/keychain/TestKeychainComponent.java +++ /dev/null @@ -1,19 +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.Component; - -import javax.inject.Singleton; -import java.util.Optional; - -@Singleton -@Component(modules = KeychainModule.class) -interface TestKeychainComponent { - - Optional keychainAccess(); - -} diff --git a/main/keychain/src/test/java/org/cryptomator/keychain/TestKeychainModule.java b/main/keychain/src/test/java/org/cryptomator/keychain/TestKeychainModule.java deleted file mode 100644 index d6e183a221..0000000000 --- a/main/keychain/src/test/java/org/cryptomator/keychain/TestKeychainModule.java +++ /dev/null @@ -1,17 +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 java.util.Set; - -public class TestKeychainModule extends KeychainModule { - - @Override - Set provideKeychainAccessStrategies(MacSystemKeychainAccess macKeychain, WindowsProtectedKeychainAccess winKeychain, LinuxSecretServiceKeychainAccess linKeychain) { - return Set.of(new MapKeychainAccess()); - } - -} diff --git a/main/ui/src/main/java/org/cryptomator/ui/changepassword/ChangePasswordController.java b/main/ui/src/main/java/org/cryptomator/ui/changepassword/ChangePasswordController.java index acb2fd12d9..7a641b1e7a 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/changepassword/ChangePasswordController.java +++ b/main/ui/src/main/java/org/cryptomator/ui/changepassword/ChangePasswordController.java @@ -10,8 +10,8 @@ import org.cryptomator.common.vaults.Vault; import org.cryptomator.cryptofs.CryptoFileSystemProvider; import org.cryptomator.cryptolib.api.InvalidPassphraseException; -import org.cryptomator.keychain.KeychainAccess; import org.cryptomator.keychain.KeychainAccessException; +import org.cryptomator.keychain.KeychainManager; import org.cryptomator.ui.common.Animations; import org.cryptomator.ui.common.ErrorComponent; import org.cryptomator.ui.common.FxController; @@ -36,14 +36,14 @@ public class ChangePasswordController implements FxController { private final Vault vault; private final ObjectProperty newPassword; private final ErrorComponent.Builder errorComponent; - private final Optional keychain; + private final Optional keychain; public NiceSecurePasswordField oldPasswordField; public CheckBox finalConfirmationCheckbox; public Button finishButton; @Inject - public ChangePasswordController(@ChangePasswordWindow Stage window, @ChangePasswordWindow Vault vault, @Named("newPassword") ObjectProperty newPassword, ErrorComponent.Builder errorComponent, Optional keychain) { + public ChangePasswordController(@ChangePasswordWindow Stage window, @ChangePasswordWindow Vault vault, @Named("newPassword") ObjectProperty newPassword, ErrorComponent.Builder errorComponent, Optional keychain) { this.window = window; this.vault = vault; this.newPassword = newPassword; diff --git a/main/ui/src/main/java/org/cryptomator/ui/common/VaultService.java b/main/ui/src/main/java/org/cryptomator/ui/common/VaultService.java index c96202dda0..3e09e1fad2 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/common/VaultService.java +++ b/main/ui/src/main/java/org/cryptomator/ui/common/VaultService.java @@ -4,16 +4,13 @@ import org.cryptomator.common.vaults.Vault; import org.cryptomator.common.vaults.VaultState; import org.cryptomator.common.vaults.Volume; -import org.cryptomator.cryptolib.api.InvalidPassphraseException; -import org.cryptomator.keychain.KeychainAccess; +import org.cryptomator.keychain.KeychainManager; import org.cryptomator.ui.fxapp.FxApplicationScoped; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.inject.Inject; -import java.nio.CharBuffer; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collection; import java.util.Iterator; import java.util.List; @@ -28,10 +25,10 @@ public class VaultService { private static final Logger LOG = LoggerFactory.getLogger(VaultService.class); private final ExecutorService executorService; - private final Optional keychain; + private final Optional keychain; @Inject - public VaultService(ExecutorService executorService, Optional keychain) { + public VaultService(ExecutorService executorService, Optional keychain) { this.executorService = executorService; this.keychain = keychain; } diff --git a/main/ui/src/main/java/org/cryptomator/ui/forgetPassword/ForgetPasswordController.java b/main/ui/src/main/java/org/cryptomator/ui/forgetPassword/ForgetPasswordController.java index e072840ba4..ea1e0530e5 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/forgetPassword/ForgetPasswordController.java +++ b/main/ui/src/main/java/org/cryptomator/ui/forgetPassword/ForgetPasswordController.java @@ -4,8 +4,8 @@ import javafx.fxml.FXML; import javafx.stage.Stage; import org.cryptomator.common.vaults.Vault; -import org.cryptomator.keychain.KeychainAccess; import org.cryptomator.keychain.KeychainAccessException; +import org.cryptomator.keychain.KeychainManager; import org.cryptomator.ui.common.FxController; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -20,14 +20,14 @@ public class ForgetPasswordController implements FxController { private final Stage window; private final Vault vault; - private final Optional keychainAccess; + private final Optional keychain; private final BooleanProperty confirmedResult; @Inject - public ForgetPasswordController(@ForgetPasswordWindow Stage window, @ForgetPasswordWindow Vault vault, Optional keychainAccess, @ForgetPasswordWindow BooleanProperty confirmedResult) { + public ForgetPasswordController(@ForgetPasswordWindow Stage window, @ForgetPasswordWindow Vault vault, Optional keychain, @ForgetPasswordWindow BooleanProperty confirmedResult) { this.window = window; this.vault = vault; - this.keychainAccess = keychainAccess; + this.keychain = keychain; this.confirmedResult = confirmedResult; } @@ -38,9 +38,9 @@ public void close() { @FXML public void finish() { - if (keychainAccess.isPresent()) { + if (keychain.isPresent()) { try { - keychainAccess.get().deletePassphrase(vault.getId()); + keychain.get().deletePassphrase(vault.getId()); LOG.debug("Forgot password for vault {}.", vault.getDisplayableName()); confirmedResult.setValue(true); } catch (KeychainAccessException e) { diff --git a/main/ui/src/main/java/org/cryptomator/ui/migration/MigrationRunController.java b/main/ui/src/main/java/org/cryptomator/ui/migration/MigrationRunController.java index 05b4603482..3123d4cb20 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/migration/MigrationRunController.java +++ b/main/ui/src/main/java/org/cryptomator/ui/migration/MigrationRunController.java @@ -22,8 +22,8 @@ import org.cryptomator.cryptofs.migration.api.MigrationContinuationListener; import org.cryptomator.cryptofs.migration.api.MigrationProgressListener; import org.cryptomator.cryptolib.api.InvalidPassphraseException; -import org.cryptomator.keychain.KeychainAccess; import org.cryptomator.keychain.KeychainAccessException; +import org.cryptomator.keychain.KeychainManager; import org.cryptomator.ui.common.Animations; import org.cryptomator.ui.common.ErrorComponent; import org.cryptomator.ui.common.FxController; @@ -55,7 +55,7 @@ public class MigrationRunController implements FxController { private final Vault vault; private final ExecutorService executor; private final ScheduledExecutorService scheduler; - private final Optional keychainAccess; + private final Optional keychain; private final ObjectProperty missingCapability; private final ErrorComponent.Builder errorComponent; private final Lazy startScene; @@ -69,13 +69,13 @@ public class MigrationRunController implements FxController { public NiceSecurePasswordField passwordField; @Inject - public MigrationRunController(@MigrationWindow Stage window, @MigrationWindow Vault vault, ExecutorService executor, ScheduledExecutorService scheduler, Optional keychainAccess, @Named("capabilityErrorCause") ObjectProperty missingCapability, @FxmlScene(FxmlFile.MIGRATION_START) Lazy startScene, @FxmlScene(FxmlFile.MIGRATION_SUCCESS) Lazy successScene, @FxmlScene(FxmlFile.MIGRATION_CAPABILITY_ERROR) Lazy capabilityErrorScene, @FxmlScene(FxmlFile.MIGRATION_IMPOSSIBLE) Lazy impossibleScene, ErrorComponent.Builder errorComponent) { + public MigrationRunController(@MigrationWindow Stage window, @MigrationWindow Vault vault, ExecutorService executor, ScheduledExecutorService scheduler, Optional keychain, @Named("capabilityErrorCause") ObjectProperty missingCapability, @FxmlScene(FxmlFile.MIGRATION_START) Lazy startScene, @FxmlScene(FxmlFile.MIGRATION_SUCCESS) Lazy successScene, @FxmlScene(FxmlFile.MIGRATION_CAPABILITY_ERROR) Lazy capabilityErrorScene, @FxmlScene(FxmlFile.MIGRATION_IMPOSSIBLE) Lazy impossibleScene, ErrorComponent.Builder errorComponent) { this.window = window; this.vault = vault; this.executor = executor; this.scheduler = scheduler; - this.keychainAccess = keychainAccess; + this.keychain = keychain; this.missingCapability = missingCapability; this.errorComponent = errorComponent; this.startScene = startScene; @@ -88,7 +88,7 @@ public MigrationRunController(@MigrationWindow Stage window, @MigrationWindow Va } public void initialize() { - if (keychainAccess.isPresent()) { + if (keychain.isPresent()) { loadStoredPassword(); } migrationButtonDisabled.bind(vault.stateProperty().isNotEqualTo(VaultState.NEEDS_MIGRATION).or(passwordField.textProperty().isEmpty())); @@ -167,10 +167,10 @@ private MigrationContinuationListener.ContinuationResult migrationRequiresInput( } private void loadStoredPassword() { - assert keychainAccess.isPresent(); + assert keychain.isPresent(); char[] storedPw = null; try { - storedPw = keychainAccess.get().loadPassphrase(vault.getId()); + storedPw = keychain.get().loadPassphrase(vault.getId()); if (storedPw != null) { passwordField.setPassword(storedPw); passwordField.selectRange(storedPw.length, storedPw.length); diff --git a/main/ui/src/main/java/org/cryptomator/ui/unlock/UnlockController.java b/main/ui/src/main/java/org/cryptomator/ui/unlock/UnlockController.java index 38e41323c6..e081641672 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/unlock/UnlockController.java +++ b/main/ui/src/main/java/org/cryptomator/ui/unlock/UnlockController.java @@ -11,7 +11,7 @@ import javafx.scene.control.ContentDisplay; import javafx.stage.Stage; import org.cryptomator.common.vaults.Vault; -import org.cryptomator.keychain.KeychainAccess; +import org.cryptomator.keychain.KeychainManager; import org.cryptomator.ui.common.FxController; import org.cryptomator.ui.common.UserInteractionLock; import org.cryptomator.ui.controls.NiceSecurePasswordField; @@ -38,7 +38,7 @@ public class UnlockController implements FxController { private final Optional savedPassword; private final UserInteractionLock passwordEntryLock; private final ForgetPasswordComponent.Builder forgetPassword; - private final Optional keychainAccess; + private final Optional keychain; private final ObjectBinding unlockButtonContentDisplay; private final BooleanBinding userInteractionDisabled; private final BooleanProperty unlockButtonDisabled; @@ -46,7 +46,7 @@ public class UnlockController implements FxController { public CheckBox savePasswordCheckbox; @Inject - public UnlockController(@UnlockWindow Stage window, @UnlockWindow Vault vault, AtomicReference password, @Named("savePassword") AtomicBoolean savePassword, @Named("savedPassword") Optional savedPassword, UserInteractionLock passwordEntryLock, ForgetPasswordComponent.Builder forgetPassword, Optional keychainAccess) { + public UnlockController(@UnlockWindow Stage window, @UnlockWindow Vault vault, AtomicReference password, @Named("savePassword") AtomicBoolean savePassword, @Named("savedPassword") Optional savedPassword, UserInteractionLock passwordEntryLock, ForgetPasswordComponent.Builder forgetPassword, Optional keychain) { this.window = window; this.vault = vault; this.password = password; @@ -54,7 +54,7 @@ public UnlockController(@UnlockWindow Stage window, @UnlockWindow Vault vault, A this.savedPassword = savedPassword; this.passwordEntryLock = passwordEntryLock; this.forgetPassword = forgetPassword; - this.keychainAccess = keychainAccess; + this.keychain = keychain; this.unlockButtonContentDisplay = Bindings.createObjectBinding(this::getUnlockButtonContentDisplay, passwordEntryLock.awaitingInteraction()); this.userInteractionDisabled = passwordEntryLock.awaitingInteraction().not(); this.unlockButtonDisabled = new SimpleBooleanProperty(); @@ -131,6 +131,6 @@ public boolean isUnlockButtonDisabled() { } public boolean isKeychainAccessAvailable() { - return keychainAccess.isPresent(); + return keychain.isPresent(); } } diff --git a/main/ui/src/main/java/org/cryptomator/ui/unlock/UnlockModule.java b/main/ui/src/main/java/org/cryptomator/ui/unlock/UnlockModule.java index 4b1ba3cfed..a126f4be37 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/unlock/UnlockModule.java +++ b/main/ui/src/main/java/org/cryptomator/ui/unlock/UnlockModule.java @@ -5,12 +5,11 @@ import dagger.Provides; import dagger.multibindings.IntoMap; import javafx.scene.Scene; -import javafx.scene.image.Image; import javafx.stage.Modality; import javafx.stage.Stage; import org.cryptomator.common.vaults.Vault; -import org.cryptomator.keychain.KeychainAccess; import org.cryptomator.keychain.KeychainAccessException; +import org.cryptomator.keychain.KeychainManager; import org.cryptomator.ui.common.DefaultSceneFactory; import org.cryptomator.ui.common.FXMLLoaderFactory; import org.cryptomator.ui.common.FxController; @@ -25,16 +24,11 @@ import javax.inject.Named; import javax.inject.Provider; -import java.nio.CharBuffer; -import java.util.List; import java.util.Map; import java.util.Optional; import java.util.ResourceBundle; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicReference; -import java.util.concurrent.locks.Condition; -import java.util.concurrent.locks.Lock; -import java.util.concurrent.locks.ReentrantLock; @Module(subcomponents = {ForgetPasswordComponent.class}) abstract class UnlockModule { @@ -52,8 +46,8 @@ static UserInteractionLock providePasswordEntryLock() { @Provides @Named("savedPassword") @UnlockScoped - static Optional provideStoredPassword(Optional keychainAccess, @UnlockWindow Vault vault) { - return keychainAccess.map(k -> { + static Optional provideStoredPassword(Optional keychain, @UnlockWindow Vault vault) { + return keychain.map(k -> { try { return k.loadPassphrase(vault.getId()); } catch (KeychainAccessException e) { diff --git a/main/ui/src/main/java/org/cryptomator/ui/unlock/UnlockWorkflow.java b/main/ui/src/main/java/org/cryptomator/ui/unlock/UnlockWorkflow.java index c2f6e47f42..d9f9affd02 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/unlock/UnlockWorkflow.java +++ b/main/ui/src/main/java/org/cryptomator/ui/unlock/UnlockWorkflow.java @@ -10,8 +10,8 @@ import org.cryptomator.common.vaults.Volume; import org.cryptomator.cryptolib.api.CryptoException; import org.cryptomator.cryptolib.api.InvalidPassphraseException; -import org.cryptomator.keychain.KeychainAccess; import org.cryptomator.keychain.KeychainAccessException; +import org.cryptomator.keychain.KeychainManager; import org.cryptomator.ui.common.Animations; import org.cryptomator.ui.common.ErrorComponent; import org.cryptomator.ui.common.FxmlFile; @@ -51,14 +51,14 @@ public class UnlockWorkflow extends Task { private final AtomicBoolean savePassword; private final Optional savedPassword; private final UserInteractionLock passwordEntryLock; - private final Optional keychain; + private final Optional keychain; private final Lazy unlockScene; private final Lazy successScene; private final Lazy invalidMountPointScene; private final ErrorComponent.Builder errorComponent; @Inject - UnlockWorkflow(@UnlockWindow Stage window, @UnlockWindow Vault vault, VaultService vaultService, AtomicReference password, @Named("savePassword") AtomicBoolean savePassword, @Named("savedPassword") Optional savedPassword, UserInteractionLock passwordEntryLock, Optional keychain, @FxmlScene(FxmlFile.UNLOCK) Lazy unlockScene, @FxmlScene(FxmlFile.UNLOCK_SUCCESS) Lazy successScene, @FxmlScene(FxmlFile.UNLOCK_INVALID_MOUNT_POINT) Lazy invalidMountPointScene, ErrorComponent.Builder errorComponent) { + UnlockWorkflow(@UnlockWindow Stage window, @UnlockWindow Vault vault, VaultService vaultService, AtomicReference password, @Named("savePassword") AtomicBoolean savePassword, @Named("savedPassword") Optional savedPassword, UserInteractionLock passwordEntryLock, Optional keychain, @FxmlScene(FxmlFile.UNLOCK) Lazy unlockScene, @FxmlScene(FxmlFile.UNLOCK_SUCCESS) Lazy successScene, @FxmlScene(FxmlFile.UNLOCK_INVALID_MOUNT_POINT) Lazy invalidMountPointScene, ErrorComponent.Builder errorComponent) { this.window = window; this.vault = vault; this.vaultService = vaultService; From e594bf208daa406f25e45454e6007eed718cc8a8 Mon Sep 17 00:00:00 2001 From: Sebastian Stenzel Date: Thu, 14 May 2020 07:53:51 +0200 Subject: [PATCH 02/21] moved images to subdir --- .../ChooseExistingVaultController.java | 3 +-- .../cryptomator/ui/fxapp/FxApplicationModule.java | 7 ++----- .../cryptomator/ui/traymenu/TrayImageFactory.java | 6 +++--- .../ui/wrongfilealert/WrongFileAlertController.java | 2 +- .../src/main/resources/fxml/addvault_welcome.fxml | 2 +- .../src/main/resources/fxml/preferences_about.fxml | 2 +- .../main/resources/fxml/vault_detail_welcome.fxml | 2 +- main/ui/src/main/resources/{ => img}/bot.png | Bin main/ui/src/main/resources/{ => img}/bot@2x.png | Bin .../resources/{ => img}/select-masterkey-mac.png | Bin .../resources/{ => img}/select-masterkey-win.png | Bin main/ui/src/main/resources/{ => img}/tray_icon.png | Bin .../resources/{ => img}/tray_icon_mac_black.png | Bin .../resources/{ => img}/tray_icon_mac_black@2x.png | Bin .../resources/{ => img}/tray_icon_mac_white.png | Bin .../resources/{ => img}/tray_icon_mac_white@2x.png | Bin .../main/resources/{ => img}/vault-volume-mac.png | Bin .../main/resources/{ => img}/vault-volume-win.png | Bin .../src/main/resources/{ => img}/window_icon_32.png | Bin .../main/resources/{ => img}/window_icon_512.png | Bin 20 files changed, 10 insertions(+), 14 deletions(-) rename main/ui/src/main/resources/{ => img}/bot.png (100%) rename main/ui/src/main/resources/{ => img}/bot@2x.png (100%) rename main/ui/src/main/resources/{ => img}/select-masterkey-mac.png (100%) rename main/ui/src/main/resources/{ => img}/select-masterkey-win.png (100%) rename main/ui/src/main/resources/{ => img}/tray_icon.png (100%) rename main/ui/src/main/resources/{ => img}/tray_icon_mac_black.png (100%) rename main/ui/src/main/resources/{ => img}/tray_icon_mac_black@2x.png (100%) rename main/ui/src/main/resources/{ => img}/tray_icon_mac_white.png (100%) rename main/ui/src/main/resources/{ => img}/tray_icon_mac_white@2x.png (100%) rename main/ui/src/main/resources/{ => img}/vault-volume-mac.png (100%) rename main/ui/src/main/resources/{ => img}/vault-volume-win.png (100%) rename main/ui/src/main/resources/{ => img}/window_icon_32.png (100%) rename main/ui/src/main/resources/{ => img}/window_icon_512.png (100%) diff --git a/main/ui/src/main/java/org/cryptomator/ui/addvaultwizard/ChooseExistingVaultController.java b/main/ui/src/main/java/org/cryptomator/ui/addvaultwizard/ChooseExistingVaultController.java index 3717a844f0..7fc644f0dd 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/addvaultwizard/ChooseExistingVaultController.java +++ b/main/ui/src/main/java/org/cryptomator/ui/addvaultwizard/ChooseExistingVaultController.java @@ -18,7 +18,6 @@ import org.slf4j.LoggerFactory; import javax.inject.Inject; -import javax.inject.Named; import java.io.File; import java.io.IOException; import java.io.InputStream; @@ -57,7 +56,7 @@ public class ChooseExistingVaultController implements FxController { @FXML public void initialize() { - final String resource = SystemUtils.IS_OS_MAC ? "/select-masterkey-mac.png" : "/select-masterkey-win.png"; + final String resource = SystemUtils.IS_OS_MAC ? "/img/select-masterkey-mac.png" : "/img/select-masterkey-win.png"; try (InputStream in = getClass().getResourceAsStream(resource)) { this.screenshot = new Image(in); } catch (IOException e) { diff --git a/main/ui/src/main/java/org/cryptomator/ui/fxapp/FxApplicationModule.java b/main/ui/src/main/java/org/cryptomator/ui/fxapp/FxApplicationModule.java index 9b72548fd6..b52d64ad31 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/fxapp/FxApplicationModule.java +++ b/main/ui/src/main/java/org/cryptomator/ui/fxapp/FxApplicationModule.java @@ -9,14 +9,11 @@ import dagger.Module; import dagger.Provides; import javafx.application.Application; -import javafx.beans.property.ObjectProperty; -import javafx.beans.property.SimpleObjectProperty; import javafx.collections.FXCollections; import javafx.collections.ObservableSet; import javafx.scene.image.Image; import javafx.stage.Stage; import org.apache.commons.lang3.SystemUtils; -import org.cryptomator.common.vaults.Vault; import org.cryptomator.ui.common.ErrorComponent; import org.cryptomator.ui.common.StageFactory; import org.cryptomator.ui.mainwindow.MainWindowComponent; @@ -49,8 +46,8 @@ static List provideWindowIcons() { } try { return List.of( // - createImageFromResource("/window_icon_32.png"), // - createImageFromResource("/window_icon_512.png") // + createImageFromResource("/img/window_icon_32.png"), // + createImageFromResource("/img/window_icon_512.png") // ); } catch (IOException e) { throw new UncheckedIOException("Failed to load embedded resource.", e); diff --git a/main/ui/src/main/java/org/cryptomator/ui/traymenu/TrayImageFactory.java b/main/ui/src/main/java/org/cryptomator/ui/traymenu/TrayImageFactory.java index a76c8b1e3a..cbdf651b4a 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/traymenu/TrayImageFactory.java +++ b/main/ui/src/main/java/org/cryptomator/ui/traymenu/TrayImageFactory.java @@ -30,13 +30,13 @@ private String getMacResourceName() { .map(MacApplicationUiAppearance::getCurrentInterfaceStyle) // .orElse(MacApplicationUiInterfaceStyle.LIGHT); return switch (interfaceStyle) { - case DARK -> "/tray_icon_mac_white.png"; - case LIGHT -> "/tray_icon_mac_black.png"; + case DARK -> "/img/tray_icon_mac_white.png"; + case LIGHT -> "/img/tray_icon_mac_black.png"; }; } private String getWinOrLinuxResourceName() { - return "/tray_icon.png"; + return "/img/tray_icon.png"; } } diff --git a/main/ui/src/main/java/org/cryptomator/ui/wrongfilealert/WrongFileAlertController.java b/main/ui/src/main/java/org/cryptomator/ui/wrongfilealert/WrongFileAlertController.java index 6a11a9eba7..292486a6ab 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/wrongfilealert/WrongFileAlertController.java +++ b/main/ui/src/main/java/org/cryptomator/ui/wrongfilealert/WrongFileAlertController.java @@ -30,7 +30,7 @@ public WrongFileAlertController(@WrongFileAlertWindow Stage window, Application @FXML public void initialize() { - final String resource = SystemUtils.IS_OS_MAC ? "/vault-volume-mac.png" : "/vault-volume-win.png"; + final String resource = SystemUtils.IS_OS_MAC ? "/img/vault-volume-mac.png" : "/img/vault-volume-win.png"; try (InputStream in = getClass().getResourceAsStream(resource)) { this.screenshot = new Image(in); } catch (IOException e) { diff --git a/main/ui/src/main/resources/fxml/addvault_welcome.fxml b/main/ui/src/main/resources/fxml/addvault_welcome.fxml index faa974931d..78fef46476 100644 --- a/main/ui/src/main/resources/fxml/addvault_welcome.fxml +++ b/main/ui/src/main/resources/fxml/addvault_welcome.fxml @@ -21,7 +21,7 @@ - + diff --git a/main/ui/src/main/resources/fxml/preferences_about.fxml b/main/ui/src/main/resources/fxml/preferences_about.fxml index f214f5df20..d388663e5f 100644 --- a/main/ui/src/main/resources/fxml/preferences_about.fxml +++ b/main/ui/src/main/resources/fxml/preferences_about.fxml @@ -18,7 +18,7 @@ - + diff --git a/main/ui/src/main/resources/fxml/vault_detail_welcome.fxml b/main/ui/src/main/resources/fxml/vault_detail_welcome.fxml index 31e5f174c5..50ba0c3c65 100644 --- a/main/ui/src/main/resources/fxml/vault_detail_welcome.fxml +++ b/main/ui/src/main/resources/fxml/vault_detail_welcome.fxml @@ -11,8 +11,8 @@ spacing="24"> - + diff --git a/main/ui/src/main/resources/bot.png b/main/ui/src/main/resources/img/bot.png similarity index 100% rename from main/ui/src/main/resources/bot.png rename to main/ui/src/main/resources/img/bot.png diff --git a/main/ui/src/main/resources/bot@2x.png b/main/ui/src/main/resources/img/bot@2x.png similarity index 100% rename from main/ui/src/main/resources/bot@2x.png rename to main/ui/src/main/resources/img/bot@2x.png diff --git a/main/ui/src/main/resources/select-masterkey-mac.png b/main/ui/src/main/resources/img/select-masterkey-mac.png similarity index 100% rename from main/ui/src/main/resources/select-masterkey-mac.png rename to main/ui/src/main/resources/img/select-masterkey-mac.png diff --git a/main/ui/src/main/resources/select-masterkey-win.png b/main/ui/src/main/resources/img/select-masterkey-win.png similarity index 100% rename from main/ui/src/main/resources/select-masterkey-win.png rename to main/ui/src/main/resources/img/select-masterkey-win.png diff --git a/main/ui/src/main/resources/tray_icon.png b/main/ui/src/main/resources/img/tray_icon.png similarity index 100% rename from main/ui/src/main/resources/tray_icon.png rename to main/ui/src/main/resources/img/tray_icon.png diff --git a/main/ui/src/main/resources/tray_icon_mac_black.png b/main/ui/src/main/resources/img/tray_icon_mac_black.png similarity index 100% rename from main/ui/src/main/resources/tray_icon_mac_black.png rename to main/ui/src/main/resources/img/tray_icon_mac_black.png diff --git a/main/ui/src/main/resources/tray_icon_mac_black@2x.png b/main/ui/src/main/resources/img/tray_icon_mac_black@2x.png similarity index 100% rename from main/ui/src/main/resources/tray_icon_mac_black@2x.png rename to main/ui/src/main/resources/img/tray_icon_mac_black@2x.png diff --git a/main/ui/src/main/resources/tray_icon_mac_white.png b/main/ui/src/main/resources/img/tray_icon_mac_white.png similarity index 100% rename from main/ui/src/main/resources/tray_icon_mac_white.png rename to main/ui/src/main/resources/img/tray_icon_mac_white.png diff --git a/main/ui/src/main/resources/tray_icon_mac_white@2x.png b/main/ui/src/main/resources/img/tray_icon_mac_white@2x.png similarity index 100% rename from main/ui/src/main/resources/tray_icon_mac_white@2x.png rename to main/ui/src/main/resources/img/tray_icon_mac_white@2x.png diff --git a/main/ui/src/main/resources/vault-volume-mac.png b/main/ui/src/main/resources/img/vault-volume-mac.png similarity index 100% rename from main/ui/src/main/resources/vault-volume-mac.png rename to main/ui/src/main/resources/img/vault-volume-mac.png diff --git a/main/ui/src/main/resources/vault-volume-win.png b/main/ui/src/main/resources/img/vault-volume-win.png similarity index 100% rename from main/ui/src/main/resources/vault-volume-win.png rename to main/ui/src/main/resources/img/vault-volume-win.png diff --git a/main/ui/src/main/resources/window_icon_32.png b/main/ui/src/main/resources/img/window_icon_32.png similarity index 100% rename from main/ui/src/main/resources/window_icon_32.png rename to main/ui/src/main/resources/img/window_icon_32.png diff --git a/main/ui/src/main/resources/window_icon_512.png b/main/ui/src/main/resources/img/window_icon_512.png similarity index 100% rename from main/ui/src/main/resources/window_icon_512.png rename to main/ui/src/main/resources/img/window_icon_512.png From 357d63f39856d85f072ae08f232291c97a2db4e3 Mon Sep 17 00:00:00 2001 From: Sebastian Stenzel Date: Thu, 14 May 2020 09:03:13 +0200 Subject: [PATCH 03/21] Added animation to unlock dialog --- .../ui/mainwindow/WelcomeController.java | 1 + .../ui/unlock/UnlockController.java | 72 ++++++++++++++++++ .../main/resources/fxml/addvault_welcome.fxml | 2 +- .../resources/fxml/preferences_about.fxml | 2 +- main/ui/src/main/resources/fxml/unlock.fxml | 37 +++++++-- .../resources/fxml/vault_detail_welcome.fxml | 2 +- main/ui/src/main/resources/img/bot/arm-l.png | Bin 0 -> 568 bytes .../src/main/resources/img/bot/arm-l@2x.png | Bin 0 -> 1122 bytes main/ui/src/main/resources/img/bot/arm-r.png | Bin 0 -> 572 bytes .../src/main/resources/img/bot/arm-r@2x.png | Bin 0 -> 1122 bytes main/ui/src/main/resources/img/bot/body.png | Bin 0 -> 1418 bytes .../ui/src/main/resources/img/bot/body@2x.png | Bin 0 -> 2769 bytes .../src/main/resources/img/{ => bot}/bot.png | Bin .../main/resources/img/{ => bot}/bot@2x.png | Bin main/ui/src/main/resources/img/bot/face.png | Bin 0 -> 508 bytes .../ui/src/main/resources/img/bot/face@2x.png | Bin 0 -> 937 bytes main/ui/src/main/resources/img/bot/legs.png | Bin 0 -> 648 bytes .../ui/src/main/resources/img/bot/legs@2x.png | Bin 0 -> 1164 bytes 18 files changed, 108 insertions(+), 8 deletions(-) create mode 100644 main/ui/src/main/resources/img/bot/arm-l.png create mode 100644 main/ui/src/main/resources/img/bot/arm-l@2x.png create mode 100644 main/ui/src/main/resources/img/bot/arm-r.png create mode 100644 main/ui/src/main/resources/img/bot/arm-r@2x.png create mode 100644 main/ui/src/main/resources/img/bot/body.png create mode 100644 main/ui/src/main/resources/img/bot/body@2x.png rename main/ui/src/main/resources/img/{ => bot}/bot.png (100%) rename main/ui/src/main/resources/img/{ => bot}/bot@2x.png (100%) create mode 100644 main/ui/src/main/resources/img/bot/face.png create mode 100644 main/ui/src/main/resources/img/bot/face@2x.png create mode 100644 main/ui/src/main/resources/img/bot/legs.png create mode 100644 main/ui/src/main/resources/img/bot/legs@2x.png diff --git a/main/ui/src/main/java/org/cryptomator/ui/mainwindow/WelcomeController.java b/main/ui/src/main/java/org/cryptomator/ui/mainwindow/WelcomeController.java index 2646c1a369..95a65f6ace 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/mainwindow/WelcomeController.java +++ b/main/ui/src/main/java/org/cryptomator/ui/mainwindow/WelcomeController.java @@ -42,4 +42,5 @@ public BooleanBinding noVaultPresentProperty() { public boolean isNoVaultPresent() { return noVaultPresent.get(); } + } diff --git a/main/ui/src/main/java/org/cryptomator/ui/unlock/UnlockController.java b/main/ui/src/main/java/org/cryptomator/ui/unlock/UnlockController.java index e081641672..7e887ced4c 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/unlock/UnlockController.java +++ b/main/ui/src/main/java/org/cryptomator/ui/unlock/UnlockController.java @@ -1,5 +1,10 @@ package org.cryptomator.ui.unlock; +import javafx.animation.Animation; +import javafx.animation.Interpolator; +import javafx.animation.KeyFrame; +import javafx.animation.KeyValue; +import javafx.animation.Timeline; import javafx.beans.binding.Bindings; import javafx.beans.binding.BooleanBinding; import javafx.beans.binding.ObjectBinding; @@ -9,7 +14,11 @@ import javafx.fxml.FXML; import javafx.scene.control.CheckBox; import javafx.scene.control.ContentDisplay; +import javafx.scene.image.ImageView; +import javafx.scene.transform.Rotate; +import javafx.scene.transform.Translate; import javafx.stage.Stage; +import javafx.util.Duration; import org.cryptomator.common.vaults.Vault; import org.cryptomator.keychain.KeychainManager; import org.cryptomator.ui.common.FxController; @@ -42,8 +51,15 @@ public class UnlockController implements FxController { private final ObjectBinding unlockButtonContentDisplay; private final BooleanBinding userInteractionDisabled; private final BooleanProperty unlockButtonDisabled; + public NiceSecurePasswordField passwordField; public CheckBox savePasswordCheckbox; + public ImageView face; + public ImageView leftArm; + public ImageView rightArm; + public ImageView legs; + public ImageView body; + public Animation unlockAnimation; @Inject public UnlockController(@UnlockWindow Stage window, @UnlockWindow Vault vault, AtomicReference password, @Named("savePassword") AtomicBoolean savePassword, @Named("savedPassword") Optional savedPassword, UserInteractionLock passwordEntryLock, ForgetPasswordComponent.Builder forgetPassword, Optional keychain) { @@ -60,12 +76,51 @@ public UnlockController(@UnlockWindow Stage window, @UnlockWindow Vault vault, A this.unlockButtonDisabled = new SimpleBooleanProperty(); } + @FXML public void initialize() { savePasswordCheckbox.setSelected(savedPassword.isPresent()); if (password.get() != null) { passwordField.setPassword(password.get()); } unlockButtonDisabled.bind(userInteractionDisabled.or(passwordField.textProperty().isEmpty())); + + var leftArmTranslation = new Translate(24, 0); + var leftArmRotation = new Rotate(60, 16, 30, 0); + var leftArmRetracted = new KeyValue(leftArmTranslation.xProperty(), 24); + var leftArmExtended = new KeyValue(leftArmTranslation.xProperty(), 0.0); + var leftArmHorizontal = new KeyValue(leftArmRotation.angleProperty(), 60, Interpolator.EASE_OUT); + var leftArmHanging = new KeyValue(leftArmRotation.angleProperty(), 0); + leftArm.getTransforms().setAll(leftArmTranslation, leftArmRotation); + + var rightArmTranslation = new Translate(-24, 0); + var rightArmRotation = new Rotate(60, 48, 30, 0); + var rightArmRetracted = new KeyValue(rightArmTranslation.xProperty(), -24); + var rightArmExtended = new KeyValue(rightArmTranslation.xProperty(), 0.0); + var rightArmHorizontal = new KeyValue(rightArmRotation.angleProperty(), -60); + var rightArmHanging = new KeyValue(rightArmRotation.angleProperty(), 0, Interpolator.EASE_OUT); + rightArm.getTransforms().setAll(rightArmTranslation, rightArmRotation); + + var legsRetractedY = new KeyValue(legs.scaleYProperty(), 0); + var legsExtendedY = new KeyValue(legs.scaleYProperty(), 1, Interpolator.EASE_OUT); + var legsRetractedX = new KeyValue(legs.scaleXProperty(), 0); + var legsExtendedX = new KeyValue(legs.scaleXProperty(), 1, Interpolator.EASE_OUT); + legs.setScaleY(0); + legs.setScaleX(0); + + var faceHidden = new KeyValue(face.opacityProperty(), 0.0); + var faceVisible = new KeyValue(face.opacityProperty(), 1.0, Interpolator.LINEAR); + face.setOpacity(0); + + unlockAnimation = new Timeline( + new KeyFrame(Duration.ZERO, leftArmRetracted, leftArmHorizontal, rightArmRetracted, rightArmHorizontal, legsRetractedY, legsRetractedX, faceHidden), + new KeyFrame(Duration.millis(200), leftArmExtended, leftArmHorizontal, rightArmRetracted, rightArmHorizontal), + new KeyFrame(Duration.millis(400), leftArmExtended, leftArmHanging, rightArmExtended, rightArmHorizontal), + new KeyFrame(Duration.millis(600), leftArmExtended, leftArmHanging, rightArmExtended, rightArmHanging), + new KeyFrame(Duration.millis(800), legsExtendedY, legsExtendedX, faceHidden), + new KeyFrame(Duration.millis(1000), faceVisible) + ); + + passwordEntryLock.awaitingInteraction().addListener(observable -> stopUnlockAnimation()); } @FXML @@ -88,6 +143,23 @@ public void unlock() { Arrays.fill(oldPw, ' '); } passwordEntryLock.interacted(UnlockModule.PasswordEntry.PASSWORD_ENTERED); + startUnlockAnimation(); + } + + private void startUnlockAnimation() { + leftArm.setVisible(true); + rightArm.setVisible(true); + legs.setVisible(true); + face.setVisible(true); + unlockAnimation.playFromStart(); + } + + private void stopUnlockAnimation() { + unlockAnimation.stop(); + leftArm.setVisible(false); + rightArm.setVisible(false); + legs.setVisible(false); + face.setVisible(false); } /* Save Password */ diff --git a/main/ui/src/main/resources/fxml/addvault_welcome.fxml b/main/ui/src/main/resources/fxml/addvault_welcome.fxml index 78fef46476..1639beac4d 100644 --- a/main/ui/src/main/resources/fxml/addvault_welcome.fxml +++ b/main/ui/src/main/resources/fxml/addvault_welcome.fxml @@ -21,7 +21,7 @@ - + diff --git a/main/ui/src/main/resources/fxml/preferences_about.fxml b/main/ui/src/main/resources/fxml/preferences_about.fxml index d388663e5f..ba738f25e6 100644 --- a/main/ui/src/main/resources/fxml/preferences_about.fxml +++ b/main/ui/src/main/resources/fxml/preferences_about.fxml @@ -18,7 +18,7 @@ - + diff --git a/main/ui/src/main/resources/fxml/unlock.fxml b/main/ui/src/main/resources/fxml/unlock.fxml index 099a041486..331eeade8f 100644 --- a/main/ui/src/main/resources/fxml/unlock.fxml +++ b/main/ui/src/main/resources/fxml/unlock.fxml @@ -5,6 +5,10 @@ + + + + @@ -19,11 +23,34 @@ - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/main/ui/src/main/resources/fxml/vault_detail_welcome.fxml b/main/ui/src/main/resources/fxml/vault_detail_welcome.fxml index 50ba0c3c65..d9b6ca9fc1 100644 --- a/main/ui/src/main/resources/fxml/vault_detail_welcome.fxml +++ b/main/ui/src/main/resources/fxml/vault_detail_welcome.fxml @@ -11,8 +11,8 @@ spacing="24"> + - diff --git a/main/ui/src/main/resources/img/bot/arm-l.png b/main/ui/src/main/resources/img/bot/arm-l.png new file mode 100644 index 0000000000000000000000000000000000000000..ecaab44f12ca5dad7bfa5c1833aae855d46b931b GIT binary patch literal 568 zcmV-80>}M{P)HXS^nF*8Ndp_JOBUy002PSO>*ScGoTz{90c&#sbi;!?W8Ya+es63xSV{7NibNY{wUO*qhinZ$y6B~=HtSq?QZYcKwh94q2d`?bI--(l_JyiRJ-$tf53JJ7DashV004wR_D^k(4;TOd08n(_5)ueyDt@Q{0000P-rjb7Tds6!no;hgN6!0R zE{ly`y!CCl|FzqDJ#We0v(8VOH|xA*;U){Y{`CjHa>ZU(pSkSjrEPD8Z%$a$oG9U+ zHEWxW2-igMjS)H0T^HJNSDIh@FUZ$k&fz3J$wOt1)4~Fk*}(}86U?ppHZNPYtnJcE zlf+H&L7bB$Zp{1hP@Xf#fql}+6pmn)`%Diiw;SZ2%5C8OAfq7oPDD|t^T#v>?(WYw z7TsZ$U^&tK>eZ_QD;sier*HPGmDqebNL2P?+)$&fn}Lh zxq@@_b~4Eo?JTScU@VCh@B4c*=bNIL#?KFb*Y7Vsld^f^M-9s88W{fQFJR}2oYX0V@lx>$eTvbfscf@z$;50%TbFS__* z-v?9Q=$T$i?UIVKTIv;VaJ+D^`}Zn3>%tbx($`n3ujj?bUSIyWYE5e7`VFS0)Bf}` zuD`PC{)Pu^?+zDiTN?MHyeU(3>eMgq)aU z>NPN)So(j#!Fdn&fBu;M<*WbxJBL83UN)P*U1r05VMQhPcT@Qdrmbuj6XRufmud6e zm;HP)*6zUPy*FoBJ+x=`II_Ypd1c;WwJ+sst*$IA4*$-vVDI_XD~1QyYpohiE!ix^ zwu8Z+!HOp?Ky0_z1vGuisWJeb%2ntIaumBa(4Bd2-lwJf^Mp4>b6c}9WskAx>L z3?CYCe_)fIV*X>Zqwxlw38%&H|9v5MEjH^%rQO5edmrL&h}Q`EMs3kj{iFMU(M&V_ z$NR>&4SQDHUm_WLdt3OA?24`a_ddL5jAmf{_;LFEfZ5+3i-h5^YH#_DS1}&w?N588$?p3e+?e;;2f;WukV|jfxh)!V76%9Oi zoPk5moB7j1E}8ZFWaGRACNeBv4a^k=K>~k_J_uVx)dDTN?2tWy#rDAM2S=34wy_^) m0%iH;KWo!Bt_CxaN`M4G6`vv-gH<2%K!TpGelF{r5}E)Zsr5$y literal 0 HcmV?d00001 diff --git a/main/ui/src/main/resources/img/bot/arm-r.png b/main/ui/src/main/resources/img/bot/arm-r.png new file mode 100644 index 0000000000000000000000000000000000000000..c30d8328f0a61b6dc09ebb0f5c86045bb3a2a51d GIT binary patch literal 572 zcmV-C0>k}@P)fS6qxYn|!Mm{olAuXlUqh*LCkZj`Pg-{rIr3uog;$kBW+_Zrk?TOP4M& z8OyT1#>U2WA}_%6yeo2W!!THUd_2p@$OyO#N|6m86BAQj)3jgVgZJd*WD#D_m#lz@ zh=|^D>to!D&@u}skN>8!fVjB0zX=#idJd2#Kr!}ZzJcnb1z;Eq6Z1fLc=&GucJAGG zzweOY1u5qj68Z(}zpm>nH8qumM?|n?tJg4u59n4vl?y|l?AXcEMhC$KqsLBooSvTE zT^R`oU1-4YQCDRNp+8rLwaQ4?ckob>2tRPdD69^-ljC<#R|x?Kdgb7eqq+0Ig-e<| zF`iOIz_iJ1Z>*2eGBG>4xkWq0gb>1IlOL~tl!WPVs*#? z^{7i|Wm@*Ni<-_hY}p#D2qL`T38+GOPtZsTYlAAF7#ImY^Z)xO3z)}4z6E9T)HaJ= zKv}>hG2Z`D8xB|iWdSpJ$d90Wp4x6+yG>a@ZSa)`O$8l5VP3QO|BciSM@s;cNaFu1 zf+3(3bpZvz6!0?tE>BxT3D6!?{Lvm92mk;800`QjdXXvs003aeD-sBb_qiwl0000< KMNUMnLSTYsl>Kl3 literal 0 HcmV?d00001 diff --git a/main/ui/src/main/resources/img/bot/arm-r@2x.png b/main/ui/src/main/resources/img/bot/arm-r@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..cbcfdf03c963714ec6cf6a5bf9ae56899dd3b073 GIT binary patch literal 1122 zcmV-o1fBbdP)U- zv1<-Mk}Odajc?nwZ3Mn;8*AIPZQE`yx~e&Dt*y}7_S?Je$j$1mnPBF;7jecJxc3yY zrgnI}-aYuddEUHvVZ$(f<%BdI6yMY1@f>qF9At&h=i6qQ<|mw%Mw3dVF7f;Q32EsP zoKEKn!!YV|a+-{Ru~R%Q2NVv6sj#q+5{bkfi1Q4mr}&`IUvNZcJK`x4i4Y1GDFByn ziV6>I?$%{0-{o?hKH^cd6<>0SiVljsJ=@WrpPw%lE;62zRCI7!uav2L(=?@}3oKPP z0p9lY$s|B57PBM3E>2Qi0eWTF?~6sV02=N9{<0FlFbul_EaW5=9qi?A#9h8rfM76a zSAc;EN5JFv`F2+zbwpJpf83la}R2 zqEV_=r(Qo!Pm?iCbE5cA2xkXr`N2?#D%Y$-zx`WgAGk}C2zWxF(7)LJ?K~%d+wCUY zD5jtCY51to^l$k}gyPT9TeBE=umkuWH;1!uAFv#s6N873ptha5(0>)H5DFJL2=381 z4jvRd1&|fZ+q6qzz6Y1gCTLd_?cb_umB@)ohO_L zE-Js@puy7D#q>&m1#p1VZwU1rFo+s8Z%M7%cckevXJvX^{JA~}umA%96_Yr>G^&pP z-vBBBAM23-3vd}&RssQraC-Vk@Vm{@HQf@j0GEQL#T3BH$>}A*&w%VQZN^L|wu*m) z7r|wmp!xz_0+PVS8$&TFU$sX1GlOlQGq{bDR9k|#!I5kNbnMzay?jxGuQ^Hew}pFT z#pf3kP@9gO#nMHNgFiV*wI#UE=V|l=S0;L-~m7aLv5}##I>BLdICHw5umTlwO$rLeF1Kk z2w>V+cL`W0tlObr1U!-=kAr8jta)D|j=^cFDL`LInMrU{hBfUZYieOG33>st;3x=y$I|}(3NRKN2b;lHoTAzSTm|v~WgskBcNwRr zj|4XXzfd~g<(D!EE(0~eHi-aJIib=c!ZqMGFccV|2e^@wIoTc@kN^Mx00{d3x*dTE o0000000000000000001g0q8JtInjJ(Jpcdz07*qoM6N<$g2(UbTmS$7 literal 0 HcmV?d00001 diff --git a/main/ui/src/main/resources/img/bot/body.png b/main/ui/src/main/resources/img/bot/body.png new file mode 100644 index 0000000000000000000000000000000000000000..a473413e6cb80b07b745692156fff124b910c5fc GIT binary patch literal 1418 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 literal 0 HcmV?d00001 diff --git a/main/ui/src/main/resources/img/bot/legs.png b/main/ui/src/main/resources/img/bot/legs.png new file mode 100644 index 0000000000000000000000000000000000000000..e53152382f9e7a45dc0c4af717978ea2ac7de5bd GIT binary patch literal 648 zcmV;30(bq1P)S8rf9kWXl z*RgHenfyC=Jaf)^^Ja3_`mXj``#<{|(<`1UHUv6QU@#BN0gW}t9ROB>A|p2mI{uI0 zTY;lMVi8T}Bwr*(-w%UUD&{&Psq80zG|tGa;2rR5Enp{*P0s4IfTrXn_?Ntad4uEnGvbb3HQW(N>={ZF)st zlif*qJoalPU;{7M6$n)mKZN~A>sma8qGr$~U# z%-&jNhf7j&VhSfS`&s=6e>5QyuuW|Ny@4dU0&oP3uCstt<|tEu_)0)*S6e_QkpP2? z0E^2*^&xf5jHYwDw9q3wQVe z(&QPsf0wBRDrNSFWeb<+aG0ty&;u85`17EZ)(=D(aEr5uFCeXQW*cw}{E*4~3Vv-B isZHQfFbYP&C;$MddQq(D(L?qC0000_;rDX0 zqjm{ECb7Wb{hQg$Jxe@Aj-THqJ2!Vr?(H2j$`9V;J6HbjW>;~xcG)%QbhW74(ZB!Q zlzY9pZt|=3YIC1#pX2qn{(bf3(BRnEoGtq5Mn_H`+0FKI+K_f}Xe6^BL~H&GaPOH?eTXk>K-@M=poW?s(4S{D1qb9k)`} zg_jm}vOKM6`=n(4>2UK!7VggC(%c4diAPETy^A{z+vINS^3XE=@?W~s+UHRv`^H8G zyC*V}Z~M!gQGMttEC0{*$h^Fz++VL%2n!-)?-K=*RbDmWjU2gTomN zS3X+Zm3koScm4QgR*`%!n}Z)NTz{uJ@6E)=!gGJNs*B9i)BpKo;?%>|yVm|?mPw4a z=sM)vefha~tMTjCY-esVALnhY61Ge`^Ga1djhQFOFIMWnu_>Zv+u2)Z3$|akH&I)5 z!_X_CPTBHdb5BgpE|UYZeJ(ESouVkTQ|Z{BH8(!~cG;Ief3+TC+tPmtxuu7f!Z zv46gFbsbimc5-3D-93BkR()`{pP9;afLn5BOyW1TiU!RNvq4#sTN zn=2UiA^FpSo6-l4PUTSzx^&ccx|T$A;FAci>8mbDK4i65TX)jvtMr11gEyur9T$7{ z+T3A3quRpz4E`IwGjP7NJ#gXn(M;Dq%`?{*vsIjW!&{&oF7$qdr&#$5j~gpbT7x5+1sS~hZ39h)EoB~xfC|LW##rRH^^I=bbRTi*;j4eS4sTvoz9kF z?0U4gto>r}frZuO>$S>iL_bT}^43fPg=J-|)B~$WD(=@_a!XYGxL6_-|->A=8y7< z#pmStGz-jH4n{PYMVdY2Yhm%b|Kfh1Q03%Z&psR|V7(*EqiFuA*u3uO&JQ0q*c37Z z`IHHlP2PR0Gj{WXssmGc&uN@_d&Iow^`qAvzfB7FidXLbBJ<+P%Ws$8BFc?zNBk00 bL8XR8fxxnDThF}A0dYKC{an^LB{Ts5y&fl1 literal 0 HcmV?d00001 From 29182156dfceac6407e3eb5be11c42c9d5f0c834 Mon Sep 17 00:00:00 2001 From: Sebastian Stenzel Date: Tue, 19 May 2020 11:21:20 +0200 Subject: [PATCH 04/21] fixes #1196 --- .../java/org/cryptomator/ui/launcher/UiLauncher.java | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/main/ui/src/main/java/org/cryptomator/ui/launcher/UiLauncher.java b/main/ui/src/main/java/org/cryptomator/ui/launcher/UiLauncher.java index 7024de477b..c67f0dfebe 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/launcher/UiLauncher.java +++ b/main/ui/src/main/java/org/cryptomator/ui/launcher/UiLauncher.java @@ -62,10 +62,10 @@ public void launch() { Desktop.getDesktop().addAppEventListener((AppReopenedListener) e -> showMainWindowAsync(hasTrayIcon)); // auto unlock - Collection vaultsWithAutoUnlockEnabled = vaults.filtered(v -> v.getVaultSettings().unlockAfterStartup().get()); - if (!vaultsWithAutoUnlockEnabled.isEmpty()) { + Collection vaultsToAutoUnlock = vaults.filtered(this::shouldAttemptAutoUnlock); + if (!vaultsToAutoUnlock.isEmpty()) { fxApplicationStarter.get(hasTrayIcon).thenAccept(app -> { - for (Vault vault : vaultsWithAutoUnlockEnabled){ + for (Vault vault : vaultsToAutoUnlock){ app.startUnlockWorkflow(vault); } }); @@ -73,6 +73,10 @@ public void launch() { launchEventHandler.startHandlingLaunchEvents(hasTrayIcon); } + + private boolean shouldAttemptAutoUnlock(Vault vault) { + return vault.isLocked() && vault.getVaultSettings().unlockAfterStartup().get(); + } private void showMainWindowAsync(boolean hasTrayIcon) { fxApplicationStarter.get(hasTrayIcon).thenAccept(FxApplication::showMainWindow); From 22859c9ffab566ab3f359c0c097415ebb5da09ab Mon Sep 17 00:00:00 2001 From: Martin Beyer Date: Wed, 20 May 2020 13:02:14 +0200 Subject: [PATCH 05/21] Fixes #1082 Illegal mount options cannot be selected (WebDav + Windows) By adding the visible and managed flags to the corresponding fxml tags, it is no longer possible to select illegal combinations. --- main/ui/src/main/resources/fxml/vault_options_mount.fxml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/main/ui/src/main/resources/fxml/vault_options_mount.fxml b/main/ui/src/main/resources/fxml/vault_options_mount.fxml index b645d3da28..ffa3ddf323 100644 --- a/main/ui/src/main/resources/fxml/vault_options_mount.fxml +++ b/main/ui/src/main/resources/fxml/vault_options_mount.fxml @@ -30,7 +30,7 @@ - + @@ -48,7 +48,7 @@ - + - + From 12dcf0647d9d0573bf602a671648ecfb80e912f9 Mon Sep 17 00:00:00 2001 From: Martin Beyer Date: Wed, 20 May 2020 14:49:12 +0200 Subject: [PATCH 06/21] Reverted small error in 22859c9ffab566ab3f359c0c097415ebb5da09ab to fix#1082 --- main/ui/src/main/resources/fxml/vault_options_mount.fxml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main/ui/src/main/resources/fxml/vault_options_mount.fxml b/main/ui/src/main/resources/fxml/vault_options_mount.fxml index b645d3da28..7bc7402f3d 100644 --- a/main/ui/src/main/resources/fxml/vault_options_mount.fxml +++ b/main/ui/src/main/resources/fxml/vault_options_mount.fxml @@ -56,7 +56,7 @@ - + From 842a0d6ff3f953d132992bec54d38ad3674609cd Mon Sep 17 00:00:00 2001 From: Martin Beyer Date: Wed, 20 May 2020 15:02:53 +0200 Subject: [PATCH 07/21] Implements #1183 Saved Passwords are indicated --- .../VaultDetailLockedController.java | 27 +++++++++++++++++-- .../resources/fxml/vault_detail_locked.fxml | 14 +++++++++- .../main/resources/i18n/strings.properties | 4 ++- 3 files changed, 41 insertions(+), 4 deletions(-) diff --git a/main/ui/src/main/java/org/cryptomator/ui/mainwindow/VaultDetailLockedController.java b/main/ui/src/main/java/org/cryptomator/ui/mainwindow/VaultDetailLockedController.java index 434a5b7ef9..8161d1365c 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/mainwindow/VaultDetailLockedController.java +++ b/main/ui/src/main/java/org/cryptomator/ui/mainwindow/VaultDetailLockedController.java @@ -1,14 +1,19 @@ package org.cryptomator.ui.mainwindow; +import javafx.beans.binding.BooleanExpression; import javafx.beans.property.ObjectProperty; import javafx.beans.property.ReadOnlyObjectProperty; +import javafx.beans.property.SimpleBooleanProperty; import javafx.fxml.FXML; 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; +import org.fxmisc.easybind.EasyBind; import javax.inject.Inject; +import java.util.Optional; @MainWindowScoped public class VaultDetailLockedController implements FxController { @@ -16,12 +21,20 @@ public class VaultDetailLockedController implements FxController { private final ReadOnlyObjectProperty vault; private final FxApplication application; private final VaultOptionsComponent.Builder vaultOptionsWindow; + private final Optional keychainManagerOptional; + private final BooleanExpression passwordSaved; @Inject - VaultDetailLockedController(ObjectProperty vault, FxApplication application, VaultOptionsComponent.Builder vaultOptionsWindow) { + VaultDetailLockedController(ObjectProperty vault, FxApplication application, VaultOptionsComponent.Builder vaultOptionsWindow, Optional keychainManagerOptional) { this.vault = vault; this.application = application; this.vaultOptionsWindow = vaultOptionsWindow; + this.keychainManagerOptional = keychainManagerOptional; + if (keychainManagerOptional.isPresent()) { + this.passwordSaved = BooleanExpression.booleanExpression(EasyBind.select(vault).selectObject(v -> keychainManagerOptional.get().getPassphraseStoredProperty(v.getId()))); + } else { + this.passwordSaved = new SimpleBooleanProperty(false); + } } @FXML @@ -33,7 +46,7 @@ public void unlock() { public void showVaultOptions() { vaultOptionsWindow.vault(vault.get()).build().showVaultOptionsWindow(); } - + /* Getter/Setter */ public ReadOnlyObjectProperty vaultProperty() { @@ -43,4 +56,14 @@ public ReadOnlyObjectProperty vaultProperty() { public Vault getVault() { return vault.get(); } + + public BooleanExpression passwordSavedProperty() { + return passwordSaved; + } + + public boolean isPasswordSaved() { + if (keychainManagerOptional.isPresent() && vault.get() != null) { + return keychainManagerOptional.get().getPassphraseStoredProperty(vault.get().getId()).get(); + } else return false; + } } diff --git a/main/ui/src/main/resources/fxml/vault_detail_locked.fxml b/main/ui/src/main/resources/fxml/vault_detail_locked.fxml index 05c3c74001..ca0c9fdce3 100644 --- a/main/ui/src/main/resources/fxml/vault_detail_locked.fxml +++ b/main/ui/src/main/resources/fxml/vault_detail_locked.fxml @@ -5,6 +5,9 @@ + + + - + - + + + + - + - From f72035210c733cb683d4572ba942878f58da15e6 Mon Sep 17 00:00:00 2001 From: Armin Schrenk Date: Mon, 25 May 2020 13:51:14 +0200 Subject: [PATCH 13/21] fixing error where vault stays in processing state if unlock is canceld via system close button (window decoration bar) --- .../java/org/cryptomator/ui/unlock/UnlockController.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/main/ui/src/main/java/org/cryptomator/ui/unlock/UnlockController.java b/main/ui/src/main/java/org/cryptomator/ui/unlock/UnlockController.java index 7e887ced4c..95a201a835 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/unlock/UnlockController.java +++ b/main/ui/src/main/java/org/cryptomator/ui/unlock/UnlockController.java @@ -74,6 +74,7 @@ public UnlockController(@UnlockWindow Stage window, @UnlockWindow Vault vault, A this.unlockButtonContentDisplay = Bindings.createObjectBinding(this::getUnlockButtonContentDisplay, passwordEntryLock.awaitingInteraction()); this.userInteractionDisabled = passwordEntryLock.awaitingInteraction().not(); this.unlockButtonDisabled = new SimpleBooleanProperty(); + this.window.setOnCloseRequest(windowEvent -> close()); } @FXML @@ -123,13 +124,19 @@ public void initialize() { passwordEntryLock.awaitingInteraction().addListener(observable -> stopUnlockAnimation()); } + @FXML public void cancel() { LOG.debug("Unlock canceled by user."); + close(); + } + + private void close() { window.close(); passwordEntryLock.interacted(UnlockModule.PasswordEntry.CANCELED); } + @FXML public void unlock() { LOG.trace("UnlockController.unlock()"); From c13449c6ad8a85501b49e0ee4b0e3b752046c3f9 Mon Sep 17 00:00:00 2001 From: Sebastian Stenzel Date: Tue, 26 May 2020 09:21:18 +0200 Subject: [PATCH 14/21] fixes #1214 --- .../org/cryptomator/keychain/KeychainAccessStrategy.java | 2 +- .../org/cryptomator/keychain/MacSystemKeychainAccess.java | 6 ++++-- .../keychain/WindowsProtectedKeychainAccess.java | 7 +++++-- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/main/keychain/src/main/java/org/cryptomator/keychain/KeychainAccessStrategy.java b/main/keychain/src/main/java/org/cryptomator/keychain/KeychainAccessStrategy.java index 8976e6c554..abd50287e2 100644 --- a/main/keychain/src/main/java/org/cryptomator/keychain/KeychainAccessStrategy.java +++ b/main/keychain/src/main/java/org/cryptomator/keychain/KeychainAccessStrategy.java @@ -29,7 +29,7 @@ interface KeychainAccessStrategy { void deletePassphrase(String key) throws KeychainAccessException; /** - * Updates a passphrase with a given key. + * 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. diff --git a/main/keychain/src/main/java/org/cryptomator/keychain/MacSystemKeychainAccess.java b/main/keychain/src/main/java/org/cryptomator/keychain/MacSystemKeychainAccess.java index 95531b7ae0..0021cc13d4 100644 --- a/main/keychain/src/main/java/org/cryptomator/keychain/MacSystemKeychainAccess.java +++ b/main/keychain/src/main/java/org/cryptomator/keychain/MacSystemKeychainAccess.java @@ -49,8 +49,10 @@ public void deletePassphrase(String key) { } @Override - public void changePassphrase(String key, CharSequence passphrase) throws KeychainAccessException { - storePassphrase(key, passphrase); + public void changePassphrase(String key, CharSequence passphrase) { + if (keychain().deletePassword(key)) { + keychain().storePassword(key, passphrase); + } } } diff --git a/main/keychain/src/main/java/org/cryptomator/keychain/WindowsProtectedKeychainAccess.java b/main/keychain/src/main/java/org/cryptomator/keychain/WindowsProtectedKeychainAccess.java index 408d7d6e52..6668104a4e 100644 --- a/main/keychain/src/main/java/org/cryptomator/keychain/WindowsProtectedKeychainAccess.java +++ b/main/keychain/src/main/java/org/cryptomator/keychain/WindowsProtectedKeychainAccess.java @@ -115,8 +115,11 @@ public void deletePassphrase(String key) { } @Override - public void changePassphrase(String key, CharSequence passphrase) throws KeychainAccessException { - storePassphrase(key, passphrase); + public void changePassphrase(String key, CharSequence passphrase) { + loadKeychainEntriesIfNeeded(); + if (keychainEntries.remove(key) != null) { + storePassphrase(key, passphrase); + } } @Override From adf76943088ffeb13396e2c228b935a08c15e7a8 Mon Sep 17 00:00:00 2001 From: Sebastian Stenzel Date: Tue, 26 May 2020 10:04:32 +0200 Subject: [PATCH 15/21] fixes #1021, fixes #1170, fixes #1180 --- main/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main/pom.xml b/main/pom.xml index 8ffd63449e..934d676f5c 100644 --- a/main/pom.xml +++ b/main/pom.xml @@ -24,7 +24,7 @@ UTF-8 - 1.9.10 + 1.9.11 2.2.2 1.2.3 1.1.15 From e37f1f914b3cf61380e21af34bf958cb96b21ab9 Mon Sep 17 00:00:00 2001 From: Tobias Hagemann Date: Tue, 26 May 2020 13:20:47 +0200 Subject: [PATCH 16/21] some layout adjustments in vault detail --- .../src/main/resources/fxml/vault_detail.fxml | 2 +- .../resources/fxml/vault_detail_locked.fxml | 22 ++++++++++--------- .../resources/fxml/vault_detail_missing.fxml | 3 --- .../fxml/vault_detail_needsmigration.fxml | 6 +---- .../resources/fxml/vault_detail_unlocked.fxml | 8 +++---- 5 files changed, 18 insertions(+), 23 deletions(-) diff --git a/main/ui/src/main/resources/fxml/vault_detail.fxml b/main/ui/src/main/resources/fxml/vault_detail.fxml index e171e08877..625ae1e1fb 100644 --- a/main/ui/src/main/resources/fxml/vault_detail.fxml +++ b/main/ui/src/main/resources/fxml/vault_detail.fxml @@ -14,7 +14,7 @@ xmlns:fx="http://javafx.com/fxml" fx:controller="org.cryptomator.ui.mainwindow.VaultDetailController" minWidth="300" - spacing="36"> + spacing="60"> diff --git a/main/ui/src/main/resources/fxml/vault_detail_locked.fxml b/main/ui/src/main/resources/fxml/vault_detail_locked.fxml index ca0c9fdce3..12c192db3b 100644 --- a/main/ui/src/main/resources/fxml/vault_detail_locked.fxml +++ b/main/ui/src/main/resources/fxml/vault_detail_locked.fxml @@ -1,28 +1,26 @@ - - - - + + + - - - - -