Bläddra i källkod

Made masterkey loading strategies reusable

Sebastian Stenzel 4 år sedan
förälder
incheckning
e09bd160b7
18 ändrade filer med 209 tillägg och 152 borttagningar
  1. 2 2
      main/ui/src/main/java/org/cryptomator/ui/unlock/masterkeyfile/MasterkeyFileLoading.java
  2. 28 0
      main/ui/src/main/java/org/cryptomator/ui/keyloading/KeyLoadingComponent.java
  3. 59 0
      main/ui/src/main/java/org/cryptomator/ui/keyloading/KeyLoadingModule.java
  4. 2 2
      main/ui/src/main/java/org/cryptomator/ui/unlock/masterkeyfile/MasterkeyFileLoadingScoped.java
  5. 14 5
      main/ui/src/main/java/org/cryptomator/ui/unlock/KeyLoadingComponent.java
  6. 11 11
      main/ui/src/main/java/org/cryptomator/ui/unlock/masterkeyfile/MasterkeyFileLoadingContext.java
  7. 5 3
      main/ui/src/main/java/org/cryptomator/ui/unlock/masterkeyfile/MasterkeyFileLoadingFinisher.java
  8. 17 23
      main/ui/src/main/java/org/cryptomator/ui/unlock/masterkeyfile/MasterkeyFileLoadingModule.java
  9. 38 0
      main/ui/src/main/java/org/cryptomator/ui/keyloading/masterkeyfile/MasterkeyFileLoadingStrategy.java
  10. 6 4
      main/ui/src/main/java/org/cryptomator/ui/unlock/masterkeyfile/PassphraseEntryController.java
  11. 6 4
      main/ui/src/main/java/org/cryptomator/ui/unlock/masterkeyfile/SelectMasterkeyFileController.java
  12. 0 43
      main/ui/src/main/java/org/cryptomator/ui/unlock/KeyLoadingModule.java
  13. 1 1
      main/ui/src/main/java/org/cryptomator/ui/unlock/UnlockComponent.java
  14. 10 1
      main/ui/src/main/java/org/cryptomator/ui/unlock/UnlockModule.java
  15. 8 6
      main/ui/src/main/java/org/cryptomator/ui/unlock/UnlockWorkflow.java
  16. 0 45
      main/ui/src/main/java/org/cryptomator/ui/unlock/masterkeyfile/MasterkeyFileLoadingComponent.java
  17. 1 1
      main/ui/src/main/resources/fxml/unlock_enter_password.fxml
  18. 1 1
      main/ui/src/main/resources/fxml/unlock_select_masterkeyfile.fxml

+ 2 - 2
main/ui/src/main/java/org/cryptomator/ui/unlock/masterkeyfile/MasterkeyFileLoading.java

@@ -1,4 +1,4 @@
-package org.cryptomator.ui.unlock.masterkeyfile;
+package org.cryptomator.ui.keyloading;
 
 import javax.inject.Qualifier;
 import java.lang.annotation.Documented;
@@ -9,6 +9,6 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
 @Qualifier
 @Documented
 @Retention(RUNTIME)
-@interface MasterkeyFileLoading {
+public @interface KeyLoading {
 
 }

+ 28 - 0
main/ui/src/main/java/org/cryptomator/ui/keyloading/KeyLoadingComponent.java

@@ -0,0 +1,28 @@
+package org.cryptomator.ui.keyloading;
+
+import dagger.BindsInstance;
+import dagger.Subcomponent;
+import org.cryptomator.common.vaults.Vault;
+
+import javafx.stage.Stage;
+
+@KeyLoadingScoped
+@Subcomponent(modules = {KeyLoadingModule.class})
+public interface KeyLoadingComponent {
+
+	@KeyLoading
+	KeyLoadingStrategy keyloadingStrategy();
+
+	@Subcomponent.Builder
+	interface Builder {
+
+		@BindsInstance
+		Builder vault(@KeyLoading Vault vault);
+
+		@BindsInstance
+		Builder window(@KeyLoading Stage window);
+
+		KeyLoadingComponent build();
+	}
+
+}

+ 59 - 0
main/ui/src/main/java/org/cryptomator/ui/keyloading/KeyLoadingModule.java

@@ -0,0 +1,59 @@
+package org.cryptomator.ui.keyloading;
+
+import dagger.Binds;
+import dagger.Module;
+import dagger.Provides;
+import dagger.multibindings.IntoMap;
+import dagger.multibindings.StringKey;
+import org.cryptomator.common.vaults.Vault;
+import org.cryptomator.cryptofs.VaultConfig.UnverifiedVaultConfig;
+import org.cryptomator.ui.common.DefaultSceneFactory;
+import org.cryptomator.ui.common.FxController;
+import org.cryptomator.ui.common.FxControllerKey;
+import org.cryptomator.ui.common.FxmlLoaderFactory;
+import org.cryptomator.ui.keyloading.masterkeyfile.MasterkeyFileLoadingModule;
+import org.cryptomator.ui.keyloading.masterkeyfile.MasterkeyFileLoadingStrategy;
+import org.cryptomator.ui.migration.MigrationStartController;
+
+import javax.inject.Provider;
+import java.net.URI;
+import java.util.Map;
+import java.util.Optional;
+import java.util.ResourceBundle;
+
+@Module(includes = {MasterkeyFileLoadingModule.class})
+abstract class KeyLoadingModule {
+
+	@Provides
+	@KeyLoading
+	@KeyLoadingScoped
+	static FxmlLoaderFactory provideFxmlLoaderFactory(Map<Class<? extends FxController>, Provider<FxController>> factories, DefaultSceneFactory sceneFactory, ResourceBundle resourceBundle) {
+		return new FxmlLoaderFactory(factories, sceneFactory, resourceBundle);
+	}
+
+	@Provides
+	@KeyLoading
+	@KeyLoadingScoped
+	static Optional<URI> provideKeyId(@KeyLoading Vault vault) {
+		return vault.getUnverifiedVaultConfig().map(UnverifiedVaultConfig::getKeyId);
+	}
+
+	@Provides
+	@KeyLoading
+	@KeyLoadingScoped
+	static KeyLoadingStrategy provideKeyLoaderProvider(@KeyLoading Optional<URI> keyId, Map<String, KeyLoadingStrategy> strategies) {
+		if (keyId.isEmpty()) {
+			return KeyLoadingStrategy.failed(new IllegalArgumentException("No key id provided"));
+		} else {
+			String scheme = keyId.get().getScheme();
+			var fallback = KeyLoadingStrategy.failed(new IllegalArgumentException("Unsupported key id " + scheme));
+			return strategies.getOrDefault(scheme, fallback);
+		}
+	}
+
+	@Binds
+	@IntoMap
+	@StringKey("masterkeyfile")
+	abstract KeyLoadingStrategy bindMasterkeyFileLoadingStrategy(MasterkeyFileLoadingStrategy strategy);
+
+}

+ 2 - 2
main/ui/src/main/java/org/cryptomator/ui/unlock/masterkeyfile/MasterkeyFileLoadingScoped.java

@@ -1,4 +1,4 @@
-package org.cryptomator.ui.unlock.masterkeyfile;
+package org.cryptomator.ui.keyloading;
 
 import javax.inject.Scope;
 import java.lang.annotation.Documented;
@@ -8,6 +8,6 @@ import java.lang.annotation.RetentionPolicy;
 @Scope
 @Documented
 @Retention(RetentionPolicy.RUNTIME)
-@interface MasterkeyFileLoadingScoped {
+public @interface KeyLoadingScoped {
 
 }

+ 14 - 5
main/ui/src/main/java/org/cryptomator/ui/unlock/KeyLoadingComponent.java

@@ -1,10 +1,9 @@
-package org.cryptomator.ui.unlock;
+package org.cryptomator.ui.keyloading;
 
 import org.cryptomator.cryptolib.api.MasterkeyLoader;
 import org.cryptomator.cryptolib.api.MasterkeyLoadingFailedException;
 
-@FunctionalInterface
-public interface KeyLoadingComponent {
+public interface KeyLoadingStrategy {
 
 	/**
 	 * @return A reusable masterkey loader, preconfigured with the vault of the current unlock process
@@ -32,9 +31,19 @@ public interface KeyLoadingComponent {
 		// no-op
 	}
 
-	static KeyLoadingComponent exceptional(Exception exception) {
+	/**
+	 * A key loading strategy that will always fail by throwing a {@link MasterkeyLoadingFailedException}.
+	 *
+	 * @param exception The cause of the failure. If not alreay an {@link MasterkeyLoadingFailedException}, it will get wrapped.
+	 * @return A new KeyLoadingStrategy that will always fail with an {@link MasterkeyLoadingFailedException}.
+	 */
+	static KeyLoadingStrategy failed(Exception exception) {
 		return () -> {
-			throw new MasterkeyLoadingFailedException("Can not load key", exception);
+			if (exception instanceof MasterkeyLoadingFailedException e) {
+				throw e;
+			} else {
+				throw new MasterkeyLoadingFailedException("Can not load key", exception);
+			}
 		};
 	}
 

+ 11 - 11
main/ui/src/main/java/org/cryptomator/ui/unlock/masterkeyfile/MasterkeyFileLoadingContext.java

@@ -1,4 +1,4 @@
-package org.cryptomator.ui.unlock.masterkeyfile;
+package org.cryptomator.ui.keyloading.masterkeyfile;
 
 import dagger.Lazy;
 import org.cryptomator.cryptolib.api.InvalidPassphraseException;
@@ -8,9 +8,9 @@ import org.cryptomator.ui.common.Animations;
 import org.cryptomator.ui.common.FxmlFile;
 import org.cryptomator.ui.common.FxmlScene;
 import org.cryptomator.ui.common.UserInteractionLock;
+import org.cryptomator.ui.keyloading.KeyLoading;
+import org.cryptomator.ui.keyloading.KeyLoadingScoped;
 import org.cryptomator.ui.unlock.UnlockCancelledException;
-import org.cryptomator.ui.unlock.masterkeyfile.MasterkeyFileLoadingModule.MasterkeyFileProvision;
-import org.cryptomator.ui.unlock.masterkeyfile.MasterkeyFileLoadingModule.PasswordEntry;
 
 import javax.inject.Inject;
 import javafx.application.Platform;
@@ -21,21 +21,21 @@ import java.nio.CharBuffer;
 import java.nio.file.Path;
 import java.util.concurrent.atomic.AtomicReference;
 
-@MasterkeyFileLoadingScoped
+@KeyLoadingScoped
 public class MasterkeyFileLoadingContext implements MasterkeyFileLoaderContext {
 
 	private final Stage window;
 	private final Lazy<Scene> passphraseEntryScene;
 	private final Lazy<Scene> selectMasterkeyFileScene;
-	private final UserInteractionLock<PasswordEntry> passwordEntryLock;
-	private final UserInteractionLock<MasterkeyFileProvision> masterkeyFileProvisionLock;
+	private final UserInteractionLock<MasterkeyFileLoadingModule.PasswordEntry> passwordEntryLock;
+	private final UserInteractionLock<MasterkeyFileLoadingModule.MasterkeyFileProvision> masterkeyFileProvisionLock;
 	private final AtomicReference<char[]> password;
 	private final AtomicReference<Path> filePath;
 
 	private boolean wrongPassword;
 
 	@Inject
-	public MasterkeyFileLoadingContext(@MasterkeyFileLoading Stage window, @FxmlScene(FxmlFile.UNLOCK_ENTER_PASSWORD) Lazy<Scene> passphraseEntryScene, @FxmlScene(FxmlFile.UNLOCK_SELECT_MASTERKEYFILE) Lazy<Scene> selectMasterkeyFileScene, UserInteractionLock<PasswordEntry> passwordEntryLock, UserInteractionLock<MasterkeyFileProvision> masterkeyFileProvisionLock, AtomicReference<char[]> password, AtomicReference<Path> filePath) {
+	public MasterkeyFileLoadingContext(@KeyLoading Stage window, @FxmlScene(FxmlFile.UNLOCK_ENTER_PASSWORD) Lazy<Scene> passphraseEntryScene, @FxmlScene(FxmlFile.UNLOCK_SELECT_MASTERKEYFILE) Lazy<Scene> selectMasterkeyFileScene, UserInteractionLock<MasterkeyFileLoadingModule.PasswordEntry> passwordEntryLock, UserInteractionLock<MasterkeyFileLoadingModule.MasterkeyFileProvision> masterkeyFileProvisionLock, AtomicReference<char[]> password, AtomicReference<Path> filePath) {
 		this.window = window;
 		this.passphraseEntryScene = passphraseEntryScene;
 		this.selectMasterkeyFileScene = selectMasterkeyFileScene;
@@ -53,7 +53,7 @@ public class MasterkeyFileLoadingContext implements MasterkeyFileLoaderContext {
 
 		assert filePath.get() == null;
 		try {
-			if (askForCorrectMasterkeyFile() == MasterkeyFileProvision.MASTERKEYFILE_PROVIDED) {
+			if (askForCorrectMasterkeyFile() == MasterkeyFileLoadingModule.MasterkeyFileProvision.MASTERKEYFILE_PROVIDED) {
 				return filePath.get();
 			} else {
 				throw new UnlockCancelledException("Choosing masterkey file cancelled.");
@@ -64,7 +64,7 @@ public class MasterkeyFileLoadingContext implements MasterkeyFileLoaderContext {
 		}
 	}
 
-	private MasterkeyFileProvision askForCorrectMasterkeyFile() throws InterruptedException {
+	private MasterkeyFileLoadingModule.MasterkeyFileProvision askForCorrectMasterkeyFile() throws InterruptedException {
 		Platform.runLater(() -> {
 			window.setScene(selectMasterkeyFileScene.get());
 			window.show();
@@ -87,7 +87,7 @@ public class MasterkeyFileLoadingContext implements MasterkeyFileLoaderContext {
 
 		assert password.get() == null;
 		try {
-			if (askForPassphrase() == PasswordEntry.PASSWORD_ENTERED) {
+			if (askForPassphrase() == MasterkeyFileLoadingModule.PasswordEntry.PASSWORD_ENTERED) {
 				assert password.get() != null;
 				return CharBuffer.wrap(password.get());
 			} else {
@@ -99,7 +99,7 @@ public class MasterkeyFileLoadingContext implements MasterkeyFileLoaderContext {
 		}
 	}
 
-	private PasswordEntry askForPassphrase() throws InterruptedException {
+	private MasterkeyFileLoadingModule.PasswordEntry askForPassphrase() throws InterruptedException {
 		Platform.runLater(() -> {
 			window.setScene(passphraseEntryScene.get());
 			window.show();

+ 5 - 3
main/ui/src/main/java/org/cryptomator/ui/unlock/masterkeyfile/MasterkeyFileLoadingFinisher.java

@@ -1,8 +1,10 @@
-package org.cryptomator.ui.unlock.masterkeyfile;
+package org.cryptomator.ui.keyloading.masterkeyfile;
 
 import org.cryptomator.common.keychain.KeychainManager;
 import org.cryptomator.common.vaults.Vault;
 import org.cryptomator.integrations.keychain.KeychainAccessException;
+import org.cryptomator.ui.keyloading.KeyLoading;
+import org.cryptomator.ui.keyloading.KeyLoadingScoped;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -14,7 +16,7 @@ import java.util.Optional;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicReference;
 
-@MasterkeyFileLoadingScoped
+@KeyLoadingScoped
 public class MasterkeyFileLoadingFinisher {
 
 	private static final Logger LOG = LoggerFactory.getLogger(MasterkeyFileLoadingFinisher.class);
@@ -26,7 +28,7 @@ public class MasterkeyFileLoadingFinisher {
 	private final KeychainManager keychain;
 
 	@Inject
-	MasterkeyFileLoadingFinisher(@MasterkeyFileLoading Vault vault, @Named("savedPassword") Optional<char[]> storedPassword, AtomicReference<char[]> enteredPassword, @Named("savePassword")AtomicBoolean shouldSavePassword, KeychainManager keychain) {
+	MasterkeyFileLoadingFinisher(@KeyLoading Vault vault, @Named("savedPassword") Optional<char[]> storedPassword, AtomicReference<char[]> enteredPassword, @Named("savePassword") AtomicBoolean shouldSavePassword, KeychainManager keychain) {
 		this.vault = vault;
 		this.storedPassword = storedPassword;
 		this.enteredPassword = enteredPassword;

+ 17 - 23
main/ui/src/main/java/org/cryptomator/ui/unlock/masterkeyfile/MasterkeyFileLoadingModule.java

@@ -1,4 +1,4 @@
-package org.cryptomator.ui.unlock.masterkeyfile;
+package org.cryptomator.ui.keyloading.masterkeyfile;
 
 import dagger.Binds;
 import dagger.Module;
@@ -17,6 +17,8 @@ import org.cryptomator.ui.common.FxmlLoaderFactory;
 import org.cryptomator.ui.common.FxmlScene;
 import org.cryptomator.ui.common.UserInteractionLock;
 import org.cryptomator.ui.forgetPassword.ForgetPasswordComponent;
+import org.cryptomator.ui.keyloading.KeyLoading;
+import org.cryptomator.ui.keyloading.KeyLoadingScoped;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -31,7 +33,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicReference;
 
 @Module(subcomponents = {ForgetPasswordComponent.class})
-abstract class MasterkeyFileLoadingModule {
+public abstract class MasterkeyFileLoadingModule {
 
 	private static final Logger LOG = LoggerFactory.getLogger(MasterkeyFileLoadingModule.class);
 
@@ -46,27 +48,27 @@ abstract class MasterkeyFileLoadingModule {
 	}
 
 	@Provides
-	@MasterkeyFileLoadingScoped
-	static MasterkeyFileLoader provideMasterkeyFileLoader(MasterkeyFileAccess masterkeyFileAccess, @MasterkeyFileLoading Vault vault, MasterkeyFileLoadingContext context) {
+	@KeyLoadingScoped
+	static MasterkeyFileLoader provideMasterkeyFileLoader(MasterkeyFileAccess masterkeyFileAccess, @KeyLoading Vault vault, MasterkeyFileLoadingContext context) {
 		return masterkeyFileAccess.keyLoader(vault.getPath(), context);
 	}
 
 	@Provides
-	@MasterkeyFileLoadingScoped
+	@KeyLoadingScoped
 	static UserInteractionLock<PasswordEntry> providePasswordEntryLock() {
 		return new UserInteractionLock<>(null);
 	}
 
 	@Provides
-	@MasterkeyFileLoadingScoped
+	@KeyLoadingScoped
 	static UserInteractionLock<MasterkeyFileProvision> provideMasterkeyFileProvisionLock() {
 		return new UserInteractionLock<>(null);
 	}
 
 	@Provides
 	@Named("savedPassword")
-	@MasterkeyFileLoadingScoped
-	static Optional<char[]> provideStoredPassword(KeychainManager keychain, @MasterkeyFileLoading Vault vault) {
+	@KeyLoadingScoped
+	static Optional<char[]> provideStoredPassword(KeychainManager keychain, @KeyLoading Vault vault) {
 		if (!keychain.isSupported()) {
 			return Optional.empty();
 		} else {
@@ -80,42 +82,35 @@ abstract class MasterkeyFileLoadingModule {
 	}
 
 	@Provides
-	@MasterkeyFileLoadingScoped
+	@KeyLoadingScoped
 	static AtomicReference<Path> provideUserProvidedMasterkeyPath() {
 		return new AtomicReference<>();
 	}
 
 	@Provides
-	@MasterkeyFileLoadingScoped
+	@KeyLoadingScoped
 	static AtomicReference<char[]> providePassword(@Named("savedPassword") Optional<char[]> storedPassword) {
 		return new AtomicReference<>(storedPassword.orElse(null));
 	}
 
 	@Provides
 	@Named("savePassword")
-	@MasterkeyFileLoadingScoped
+	@KeyLoadingScoped
 	static AtomicBoolean provideSavePasswordFlag(@Named("savedPassword") Optional<char[]> storedPassword) {
 		return new AtomicBoolean(storedPassword.isPresent());
 	}
 
-	@Provides
-	@MasterkeyFileLoading
-	@MasterkeyFileLoadingScoped
-	static FxmlLoaderFactory provideFxmlLoaderFactory(Map<Class<? extends FxController>, Provider<FxController>> factories, DefaultSceneFactory sceneFactory, ResourceBundle resourceBundle) {
-		return new FxmlLoaderFactory(factories, sceneFactory, resourceBundle);
-	}
-
 	@Provides
 	@FxmlScene(FxmlFile.UNLOCK_ENTER_PASSWORD)
-	@MasterkeyFileLoadingScoped
-	static Scene provideUnlockScene(@MasterkeyFileLoading FxmlLoaderFactory fxmlLoaders) {
+	@KeyLoadingScoped
+	static Scene provideUnlockScene(@KeyLoading FxmlLoaderFactory fxmlLoaders) {
 		return fxmlLoaders.createScene(FxmlFile.UNLOCK_ENTER_PASSWORD);
 	}
 
 	@Provides
 	@FxmlScene(FxmlFile.UNLOCK_SELECT_MASTERKEYFILE)
-	@MasterkeyFileLoadingScoped
-	static Scene provideUnlockSelectMasterkeyFileScene(@MasterkeyFileLoading FxmlLoaderFactory fxmlLoaders) {
+	@KeyLoadingScoped
+	static Scene provideUnlockSelectMasterkeyFileScene(@KeyLoading FxmlLoaderFactory fxmlLoaders) {
 		return fxmlLoaders.createScene(FxmlFile.UNLOCK_SELECT_MASTERKEYFILE);
 	}
 
@@ -129,5 +124,4 @@ abstract class MasterkeyFileLoadingModule {
 	@FxControllerKey(SelectMasterkeyFileController.class)
 	abstract FxController bindUnlockSelectMasterkeyFileController(SelectMasterkeyFileController controller);
 
-
 }

+ 38 - 0
main/ui/src/main/java/org/cryptomator/ui/keyloading/masterkeyfile/MasterkeyFileLoadingStrategy.java

@@ -0,0 +1,38 @@
+package org.cryptomator.ui.keyloading.masterkeyfile;
+
+import org.cryptomator.cryptolib.api.MasterkeyLoadingFailedException;
+import org.cryptomator.cryptolib.common.MasterkeyFileLoader;
+import org.cryptomator.ui.keyloading.KeyLoading;
+import org.cryptomator.ui.keyloading.KeyLoadingStrategy;
+
+import javax.inject.Inject;
+
+@KeyLoading
+public class MasterkeyFileLoadingStrategy implements KeyLoadingStrategy {
+
+	private final MasterkeyFileLoader masterkeyFileLoader;
+	private final MasterkeyFileLoadingContext context;
+	private final MasterkeyFileLoadingFinisher finisher;
+
+	@Inject
+	public MasterkeyFileLoadingStrategy(MasterkeyFileLoader masterkeyFileLoader, MasterkeyFileLoadingContext context, MasterkeyFileLoadingFinisher finisher){
+		this.masterkeyFileLoader = masterkeyFileLoader;
+		this.context = context;
+		this.finisher = finisher;
+	}
+
+	@Override
+	public MasterkeyFileLoader masterkeyLoader() {
+		return masterkeyFileLoader;
+	}
+
+	@Override
+	public boolean recoverFromException(MasterkeyLoadingFailedException exception) {
+		return context.recoverFromException(exception);
+	}
+
+	@Override
+	public void cleanup(boolean unlockedSuccessfully) {
+		finisher.cleanup(unlockedSuccessfully);
+	}
+}

+ 6 - 4
main/ui/src/main/java/org/cryptomator/ui/unlock/masterkeyfile/PassphraseEntryController.java

@@ -1,4 +1,4 @@
-package org.cryptomator.ui.unlock.masterkeyfile;
+package org.cryptomator.ui.keyloading.masterkeyfile;
 
 import org.cryptomator.common.keychain.KeychainManager;
 import org.cryptomator.common.vaults.Vault;
@@ -7,7 +7,9 @@ import org.cryptomator.ui.common.UserInteractionLock;
 import org.cryptomator.ui.common.WeakBindings;
 import org.cryptomator.ui.controls.NiceSecurePasswordField;
 import org.cryptomator.ui.forgetPassword.ForgetPasswordComponent;
-import org.cryptomator.ui.unlock.masterkeyfile.MasterkeyFileLoadingModule.PasswordEntry;
+import org.cryptomator.ui.keyloading.KeyLoading;
+import org.cryptomator.ui.keyloading.KeyLoadingScoped;
+import org.cryptomator.ui.keyloading.masterkeyfile.MasterkeyFileLoadingModule.PasswordEntry;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -39,7 +41,7 @@ import java.util.Optional;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicReference;
 
-@MasterkeyFileLoadingScoped
+@KeyLoadingScoped
 public class PassphraseEntryController implements FxController {
 
 	private static final Logger LOG = LoggerFactory.getLogger(PassphraseEntryController.class);
@@ -67,7 +69,7 @@ public class PassphraseEntryController implements FxController {
 	public Animation unlockAnimation;
 
 	@Inject
-	public PassphraseEntryController(@MasterkeyFileLoading Stage window, @MasterkeyFileLoading Vault vault, AtomicReference<char[]> password, @Named("savePassword") AtomicBoolean savePassword, @Named("savedPassword") Optional<char[]> savedPassword, UserInteractionLock<PasswordEntry> passwordEntryLock, ForgetPasswordComponent.Builder forgetPassword, KeychainManager keychain) {
+	public PassphraseEntryController(@KeyLoading Stage window, @KeyLoading Vault vault, AtomicReference<char[]> password, @Named("savePassword") AtomicBoolean savePassword, @Named("savedPassword") Optional<char[]> savedPassword, UserInteractionLock<PasswordEntry> passwordEntryLock, ForgetPasswordComponent.Builder forgetPassword, KeychainManager keychain) {
 		this.window = window;
 		this.vault = vault;
 		this.password = password;

+ 6 - 4
main/ui/src/main/java/org/cryptomator/ui/unlock/masterkeyfile/SelectMasterkeyFileController.java

@@ -1,8 +1,10 @@
-package org.cryptomator.ui.unlock.masterkeyfile;
+package org.cryptomator.ui.keyloading.masterkeyfile;
 
 import org.cryptomator.ui.common.FxController;
 import org.cryptomator.ui.common.UserInteractionLock;
-import org.cryptomator.ui.unlock.masterkeyfile.MasterkeyFileLoadingModule.MasterkeyFileProvision;
+import org.cryptomator.ui.keyloading.KeyLoading;
+import org.cryptomator.ui.keyloading.KeyLoadingScoped;
+import org.cryptomator.ui.keyloading.masterkeyfile.MasterkeyFileLoadingModule.MasterkeyFileProvision;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -16,7 +18,7 @@ import java.nio.file.Path;
 import java.util.ResourceBundle;
 import java.util.concurrent.atomic.AtomicReference;
 
-@MasterkeyFileLoadingScoped
+@KeyLoadingScoped
 public class SelectMasterkeyFileController implements FxController {
 
 	private static final Logger LOG = LoggerFactory.getLogger(SelectMasterkeyFileController.class);
@@ -27,7 +29,7 @@ public class SelectMasterkeyFileController implements FxController {
 	private final ResourceBundle resourceBundle;
 
 	@Inject
-	public SelectMasterkeyFileController(@MasterkeyFileLoading Stage window, AtomicReference<Path> masterkeyPath, UserInteractionLock<MasterkeyFileProvision> masterkeyFileProvisionLock, ResourceBundle resourceBundle) {
+	public SelectMasterkeyFileController(@KeyLoading Stage window, AtomicReference<Path> masterkeyPath, UserInteractionLock<MasterkeyFileProvision> masterkeyFileProvisionLock, ResourceBundle resourceBundle) {
 		this.window = window;
 		this.masterkeyPath = masterkeyPath;
 		this.masterkeyFileProvisionLock = masterkeyFileProvisionLock;

+ 0 - 43
main/ui/src/main/java/org/cryptomator/ui/unlock/KeyLoadingModule.java

@@ -1,43 +0,0 @@
-package org.cryptomator.ui.unlock;
-
-import dagger.Module;
-import dagger.Provides;
-import dagger.multibindings.IntoMap;
-import dagger.multibindings.StringKey;
-import org.cryptomator.common.vaults.Vault;
-import org.cryptomator.cryptofs.VaultConfig.UnverifiedVaultConfig;
-import org.cryptomator.ui.unlock.masterkeyfile.MasterkeyFileLoadingComponent;
-
-import javafx.stage.Stage;
-import java.net.URI;
-import java.util.Map;
-import java.util.Optional;
-
-@Module(subcomponents = {MasterkeyFileLoadingComponent.class})
-abstract class KeyLoadingModule {
-
-	@Provides
-	@UnlockScoped
-	static Optional<URI> provideKeyId(@UnlockWindow Vault vault) {
-		return vault.getUnverifiedVaultConfig().map(UnverifiedVaultConfig::getKeyId);
-	}
-
-	@Provides
-	@UnlockScoped
-	static KeyLoadingComponent provideKeyLoaderProvider(Optional<URI> keyId, Map<String, KeyLoadingComponent> keyLoaderProviders) {
-		if (keyId.isEmpty()) {
-			return KeyLoadingComponent.exceptional(new IllegalArgumentException("No key id provided"));
-		} else {
-			String scheme = keyId.get().getScheme();
-			return keyLoaderProviders.getOrDefault(scheme, KeyLoadingComponent.exceptional(new IllegalArgumentException("Unsupported key id " + scheme)));
-		}
-	}
-
-	@Provides
-	@IntoMap
-	@StringKey("masterkeyfile")
-	static KeyLoadingComponent provideMasterkeyFileLoadingComponet(MasterkeyFileLoadingComponent.Builder compBuilder, @UnlockWindow Stage window, @UnlockWindow Vault vault) {
-		return compBuilder.unlockWindow(window).vault(vault).build();
-	}
-
-}

+ 1 - 1
main/ui/src/main/java/org/cryptomator/ui/unlock/UnlockComponent.java

@@ -16,7 +16,7 @@ import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Future;
 
 @UnlockScoped
-@Subcomponent(modules = {UnlockModule.class, KeyLoadingModule.class})
+@Subcomponent(modules = {UnlockModule.class})
 public interface UnlockComponent {
 
 	ExecutorService defaultExecutorService();

+ 10 - 1
main/ui/src/main/java/org/cryptomator/ui/unlock/UnlockModule.java

@@ -12,6 +12,8 @@ import org.cryptomator.ui.common.FxmlFile;
 import org.cryptomator.ui.common.FxmlLoaderFactory;
 import org.cryptomator.ui.common.FxmlScene;
 import org.cryptomator.ui.common.StageFactory;
+import org.cryptomator.ui.keyloading.KeyLoadingComponent;
+import org.cryptomator.ui.keyloading.KeyLoadingStrategy;
 
 import javax.inject.Named;
 import javax.inject.Provider;
@@ -22,7 +24,7 @@ import java.util.Map;
 import java.util.Optional;
 import java.util.ResourceBundle;
 
-@Module
+@Module(subcomponents = {KeyLoadingComponent.class})
 abstract class UnlockModule {
 
 	@Provides
@@ -48,6 +50,13 @@ abstract class UnlockModule {
 		return stage;
 	}
 
+	@Provides
+	@UnlockWindow
+	@UnlockScoped
+	static KeyLoadingStrategy provideKeyLoadingStrategy(KeyLoadingComponent.Builder compBuilder, @UnlockWindow Vault vault, @UnlockWindow Stage window) {
+		return compBuilder.vault(vault).window(window).build().keyloadingStrategy();
+	}
+
 	@Provides
 	@FxmlScene(FxmlFile.UNLOCK_SUCCESS)
 	@UnlockScoped

+ 8 - 6
main/ui/src/main/java/org/cryptomator/ui/unlock/UnlockWorkflow.java

@@ -12,6 +12,8 @@ import org.cryptomator.ui.common.ErrorComponent;
 import org.cryptomator.ui.common.FxmlFile;
 import org.cryptomator.ui.common.FxmlScene;
 import org.cryptomator.ui.common.VaultService;
+import org.cryptomator.ui.keyloading.KeyLoadingComponent;
+import org.cryptomator.ui.keyloading.KeyLoadingStrategy;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -41,17 +43,17 @@ public class UnlockWorkflow extends Task<Boolean> {
 	private final Lazy<Scene> successScene;
 	private final Lazy<Scene> invalidMountPointScene;
 	private final ErrorComponent.Builder errorComponent;
-	private final KeyLoadingComponent keyLoadingComp;
+	private final KeyLoadingStrategy keyLoadingStrategy;
 
 	@Inject
-	UnlockWorkflow(@UnlockWindow Stage window, @UnlockWindow Vault vault, VaultService vaultService, @FxmlScene(FxmlFile.UNLOCK_SUCCESS) Lazy<Scene> successScene, @FxmlScene(FxmlFile.UNLOCK_INVALID_MOUNT_POINT) Lazy<Scene> invalidMountPointScene, ErrorComponent.Builder errorComponent, KeyLoadingComponent keyLoadingComp) {
+	UnlockWorkflow(@UnlockWindow Stage window, @UnlockWindow Vault vault, VaultService vaultService, @FxmlScene(FxmlFile.UNLOCK_SUCCESS) Lazy<Scene> successScene, @FxmlScene(FxmlFile.UNLOCK_INVALID_MOUNT_POINT) Lazy<Scene> invalidMountPointScene, ErrorComponent.Builder errorComponent, @UnlockWindow KeyLoadingStrategy keyLoadingStrategy) {
 		this.window = window;
 		this.vault = vault;
 		this.vaultService = vaultService;
 		this.successScene = successScene;
 		this.invalidMountPointScene = invalidMountPointScene;
 		this.errorComponent = errorComponent;
-		this.keyLoadingComp = keyLoadingComp;
+		this.keyLoadingStrategy = keyLoadingStrategy;
 
 		setOnFailed(event -> {
 			Throwable throwable = event.getSource().getException();
@@ -78,17 +80,17 @@ public class UnlockWorkflow extends Task<Boolean> {
 	private void attemptUnlock() throws IOException, VolumeException, InvalidMountPointException, CryptoException {
 		boolean success = false;
 		try {
-			vault.unlock(keyLoadingComp.masterkeyLoader());
+			vault.unlock(keyLoadingStrategy.masterkeyLoader());
 			success = true;
 		} catch (MasterkeyLoadingFailedException e) {
-			if (keyLoadingComp.recoverFromException(e)) {
+			if (keyLoadingStrategy.recoverFromException(e)) {
 				LOG.info("Unlock attempt threw {}. Reattempting...", e.getClass().getSimpleName());
 				attemptUnlock();
 			} else {
 				throw e;
 			}
 		} finally {
-			keyLoadingComp.cleanup(success);
+			keyLoadingStrategy.cleanup(success);
 		}
 	}
 

+ 0 - 45
main/ui/src/main/java/org/cryptomator/ui/unlock/masterkeyfile/MasterkeyFileLoadingComponent.java

@@ -1,45 +0,0 @@
-package org.cryptomator.ui.unlock.masterkeyfile;
-
-import dagger.BindsInstance;
-import dagger.Subcomponent;
-import org.cryptomator.common.vaults.Vault;
-import org.cryptomator.cryptolib.api.MasterkeyLoadingFailedException;
-import org.cryptomator.cryptolib.common.MasterkeyFileLoader;
-import org.cryptomator.ui.unlock.KeyLoadingComponent;
-
-import javafx.stage.Stage;
-
-@MasterkeyFileLoadingScoped
-@Subcomponent(modules = {MasterkeyFileLoadingModule.class})
-public interface MasterkeyFileLoadingComponent extends KeyLoadingComponent {
-
-	MasterkeyFileLoadingFinisher finisher();
-
-	MasterkeyFileLoadingContext context();
-
-	@Override
-	MasterkeyFileLoader masterkeyLoader();
-
-	@Override
-	default boolean recoverFromException(MasterkeyLoadingFailedException exception) {
-		return context().recoverFromException(exception);
-	}
-
-	@Override
-	default void cleanup(boolean unlockedSuccessfully) {
-		finisher().cleanup(unlockedSuccessfully);
-	}
-
-	@Subcomponent.Builder
-	interface Builder {
-
-		@BindsInstance
-		Builder vault(@MasterkeyFileLoading Vault vault);
-
-		@BindsInstance
-		Builder unlockWindow(@MasterkeyFileLoading Stage unlockWindow);
-
-		MasterkeyFileLoadingComponent build();
-	}
-
-}

+ 1 - 1
main/ui/src/main/resources/fxml/unlock_enter_password.fxml

@@ -14,7 +14,7 @@
 <?import javafx.scene.layout.VBox?>
 <VBox xmlns:fx="http://javafx.com/fxml"
 	  xmlns="http://javafx.com/javafx"
-	  fx:controller="org.cryptomator.ui.unlock.masterkeyfile.PassphraseEntryController"
+	  fx:controller="org.cryptomator.ui.keyloading.masterkeyfile.PassphraseEntryController"
 	  minWidth="400"
 	  maxWidth="400"
 	  minHeight="145"

+ 1 - 1
main/ui/src/main/resources/fxml/unlock_select_masterkeyfile.fxml

@@ -11,7 +11,7 @@
 <?import javafx.scene.shape.Circle?>
 <VBox xmlns:fx="http://javafx.com/fxml"
 	  xmlns="http://javafx.com/javafx"
-	  fx:controller="org.cryptomator.ui.unlock.masterkeyfile.SelectMasterkeyFileController"
+	  fx:controller="org.cryptomator.ui.keyloading.masterkeyfile.SelectMasterkeyFileController"
 	  minWidth="400"
 	  maxWidth="400"
 	  minHeight="145"