began implementation of new auto unlocker (references #1044)

This commit is contained in:
Sebastian Stenzel
2020-02-13 17:16:09 +01:00
parent e1f44fb48a
commit 57256d0733
5 changed files with 91 additions and 2 deletions
@@ -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();
}
@@ -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, ' ');
}
}
}
}
@@ -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);
}
@@ -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();
}
}
@@ -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>