瀏覽代碼

began implementation of new auto unlocker (references #1044)

Sebastian Stenzel 5 年之前
父節點
當前提交
57256d0733

+ 2 - 0
main/keychain/src/main/java/org/cryptomator/keychain/KeychainModule.java

@@ -11,6 +11,7 @@ import dagger.Provides;
 import dagger.multibindings.ElementsIntoSet;
 import org.cryptomator.common.JniModule;
 
+import javax.inject.Singleton;
 import java.util.Optional;
 import java.util.Set;
 
@@ -24,6 +25,7 @@ public class KeychainModule {
 	}
 
 	@Provides
+	@Singleton
 	public Optional<KeychainAccess> provideSupportedKeychain(Set<KeychainAccessStrategy> keychainAccessStrategies) {
 		return keychainAccessStrategies.stream().filter(KeychainAccessStrategy::isSupported).map(KeychainAccess.class::cast).findFirst();
 	}

+ 74 - 0
main/ui/src/main/java/org/cryptomator/ui/launcher/AutoUnlocker.java

@@ -0,0 +1,74 @@
+package org.cryptomator.ui.launcher;
+
+import javafx.application.Platform;
+import javafx.collections.ObservableList;
+import org.cryptomator.common.vaults.Vault;
+import org.cryptomator.common.vaults.VaultState;
+import org.cryptomator.common.vaults.Volume;
+import org.cryptomator.keychain.KeychainAccess;
+import org.cryptomator.keychain.KeychainAccessException;
+import org.cryptomator.keychain.KeychainModule;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+import java.io.IOException;
+import java.nio.CharBuffer;
+import java.util.Arrays;
+import java.util.Optional;
+
+@Singleton
+class AutoUnlocker {
+	
+	private static final Logger LOG = LoggerFactory.getLogger(AutoUnlocker.class);
+
+	private final ObservableList<Vault> vaults;
+	private final Optional<KeychainAccess> keychain;
+
+	@Inject
+	AutoUnlocker(ObservableList<Vault> vaults, Optional<KeychainAccess> keychain) {
+		this.vaults = vaults;
+		this.keychain = keychain;
+	}
+
+	/**
+	 * Attempts to unlock all vaults that have been configured for auto unlock.
+	 * If an attempt fails (i.e. because the stored password is wrong) it will be silently skipped.
+	 */
+	public void autoUnlock() {
+		if (!keychain.isPresent()) {
+			LOG.info("No system keychain found. Skipping auto unlock.");
+			return;
+		}
+		// TODO: do async
+		vaults.filtered(v -> v.getVaultSettings().unlockAfterStartup().get()).forEach(this::autoUnlock);
+	}
+
+	private void autoUnlock(Vault vault) {
+		if (vault.getState() != VaultState.LOCKED) {
+			LOG.warn("Can't unlock vault {} due to its state {}", vault.getDisplayablePath(), vault.getState());
+			return;
+		}
+		assert keychain.isPresent();
+		char[] storedPw = null;
+		try {
+			storedPw = keychain.get().loadPassphrase(vault.getId());
+			if (storedPw == null) {
+				LOG.warn("No passphrase stored in keychain for vault registered for auto unlocking: {}", vault.getPath());
+			} else {
+				vault.unlock(CharBuffer.wrap(storedPw));
+				// TODO
+				// Platform.runLater(() -> vault.setState(VaultState.UNLOCKED));
+				LOG.info("Unlocked vault {}", vault.getDisplayablePath());
+			}
+		} catch (IOException | Volume.VolumeException | KeychainAccessException e) {
+			LOG.error("Auto unlock failed.", e);
+		} finally {
+			if (storedPw != null) {
+				Arrays.fill(storedPw, ' ');
+			}
+		}
+	}
+
+}

+ 6 - 1
main/ui/src/main/java/org/cryptomator/ui/launcher/UiLauncher.java

@@ -27,14 +27,16 @@ public class UiLauncher {
 	private final TrayMenuComponent.Builder trayComponent;
 	private final FxApplicationStarter fxApplicationStarter;
 	private final AppLaunchEventHandler launchEventHandler;
+	private final AutoUnlocker autoUnlocker;
 	private final Optional<MacFunctions> macFunctions;
 
 	@Inject
-	public UiLauncher(Settings settings, TrayMenuComponent.Builder trayComponent, FxApplicationStarter fxApplicationStarter, AppLaunchEventHandler launchEventHandler, Optional<MacFunctions> macFunctions) {
+	public UiLauncher(Settings settings, TrayMenuComponent.Builder trayComponent, FxApplicationStarter fxApplicationStarter, AppLaunchEventHandler launchEventHandler, AutoUnlocker autoUnlocker, Optional<MacFunctions> macFunctions) {
 		this.settings = settings;
 		this.trayComponent = trayComponent;
 		this.fxApplicationStarter = fxApplicationStarter;
 		this.launchEventHandler = launchEventHandler;
+		this.autoUnlocker = autoUnlocker;
 		this.macFunctions = macFunctions;
 	}
 
@@ -57,6 +59,9 @@ public class UiLauncher {
 
 		// register app reopen listener
 		Desktop.getDesktop().addAppEventListener((AppReopenedListener) e -> showMainWindowAsync(hasTrayIcon));
+		
+		// auto unlock - no shit!
+		autoUnlocker.autoUnlock();
 
 		launchEventHandler.startHandlingLaunchEvents(hasTrayIcon);
 	}

+ 7 - 1
main/ui/src/main/java/org/cryptomator/ui/vaultoptions/GeneralVaultOptionsController.java

@@ -1,6 +1,7 @@
 package org.cryptomator.ui.vaultoptions;
 
 import javafx.fxml.FXML;
+import javafx.scene.control.CheckBox;
 import javafx.stage.Stage;
 import org.cryptomator.common.vaults.Vault;
 import org.cryptomator.ui.changepassword.ChangePasswordComponent;
@@ -18,6 +19,7 @@ public class GeneralVaultOptionsController implements FxController {
 	private final ChangePasswordComponent.Builder changePasswordWindow;
 	private final RecoveryKeyComponent.Builder recoveryKeyWindow;
 	private final RecoverVaultComponent.Builder recoverVaultWindow;
+	public CheckBox unlockOnStartupCheckbox;
 
 	@Inject
 	GeneralVaultOptionsController(@VaultOptionsWindow Vault vault, @VaultOptionsWindow Stage window, ChangePasswordComponent.Builder changePasswordWindow, RecoveryKeyComponent.Builder recoveryKeyWindow, RecoverVaultComponent.Builder recoverVaultWindow) {
@@ -27,6 +29,11 @@ public class GeneralVaultOptionsController implements FxController {
 		this.recoveryKeyWindow = recoveryKeyWindow;
 		this.recoverVaultWindow = recoverVaultWindow;
 	}
+	
+	@FXML
+	public void initialize() {
+		unlockOnStartupCheckbox.selectedProperty().bindBidirectional(vault.getVaultSettings().unlockAfterStartup());
+	}
 
 	@FXML
 	public void changePassword() {
@@ -42,5 +49,4 @@ public class GeneralVaultOptionsController implements FxController {
 	public void showRecoverVaultDialogue(){
 		recoverVaultWindow.vault(vault).owner(window).build().showRecoverVaultWindow();
 	}
-
 }

+ 2 - 0
main/ui/src/main/resources/fxml/vault_options_general.fxml

@@ -3,6 +3,7 @@
 <?import javafx.geometry.Insets?>
 <?import javafx.scene.control.Button?>
 <?import javafx.scene.layout.VBox?>
+<?import javafx.scene.control.CheckBox?>
 <VBox xmlns="http://javafx.com/javafx"
 	  xmlns:fx="http://javafx.com/fxml"
 	  fx:controller="org.cryptomator.ui.vaultoptions.GeneralVaultOptionsController"
@@ -14,5 +15,6 @@
 		<Button text="%vaultOptions.general.changePasswordBtn" onAction="#changePassword"/>
 		<Button text="%vaultOptions.general.showRecoveryKeyBtn" onAction="#showRecoveryKey"/>
 		<Button text="TODO recoverVault" onAction="#showRecoverVaultDialogue"/>
+		<CheckBox text="TODO unlock after startup" fx:id="unlockOnStartupCheckbox"/>
 	</children>
 </VBox>