diff --git a/main/keychain/src/main/java/org/cryptomator/keychain/KeychainAccess.java b/main/keychain/src/main/java/org/cryptomator/keychain/KeychainAccess.java
index 35e406752..abd7a3ee8 100644
--- a/main/keychain/src/main/java/org/cryptomator/keychain/KeychainAccess.java
+++ b/main/keychain/src/main/java/org/cryptomator/keychain/KeychainAccess.java
@@ -14,7 +14,7 @@ public interface KeychainAccess {
* @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.
*/
- CharSequence loadPassphrase(String key);
+ char[] loadPassphrase(String key);
/**
* Deletes a passphrase with a given key.
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 c8ab83c8c..a80d084ef 100644
--- a/main/keychain/src/main/java/org/cryptomator/keychain/MacSystemKeychainAccess.java
+++ b/main/keychain/src/main/java/org/cryptomator/keychain/MacSystemKeychainAccess.java
@@ -1,7 +1,5 @@
package org.cryptomator.keychain;
-import java.nio.CharBuffer;
-
import javax.inject.Inject;
import javax.inject.Singleton;
@@ -29,8 +27,8 @@ class MacSystemKeychainAccess implements KeychainAccessStrategy {
}
@Override
- public CharSequence loadPassphrase(String key) {
- return CharBuffer.wrap(keychain.loadPassword(key));
+ public char[] loadPassphrase(String key) {
+ return keychain.loadPassword(key);
}
@Override
diff --git a/main/keychain/src/main/java/org/cryptomator/keychain/WindowsSystemKeychainAccess.java b/main/keychain/src/main/java/org/cryptomator/keychain/WindowsSystemKeychainAccess.java
index cf8163141..47d56953c 100644
--- a/main/keychain/src/main/java/org/cryptomator/keychain/WindowsSystemKeychainAccess.java
+++ b/main/keychain/src/main/java/org/cryptomator/keychain/WindowsSystemKeychainAccess.java
@@ -32,7 +32,7 @@ class WindowsSystemKeychainAccess implements KeychainAccessStrategy {
}
@Override
- public CharSequence loadPassphrase(String key) {
+ public char[] loadPassphrase(String key) {
// TODO Auto-generated method stub
return null;
}
diff --git a/main/keychain/src/main/java/org/cryptomator/keychain/KeychainComponent.java b/main/keychain/src/test/java/org/cryptomator/keychain/KeychainComponent.java
similarity index 85%
rename from main/keychain/src/main/java/org/cryptomator/keychain/KeychainComponent.java
rename to main/keychain/src/test/java/org/cryptomator/keychain/KeychainComponent.java
index 0264aa3fc..44301ed7f 100644
--- a/main/keychain/src/main/java/org/cryptomator/keychain/KeychainComponent.java
+++ b/main/keychain/src/test/java/org/cryptomator/keychain/KeychainComponent.java
@@ -8,7 +8,7 @@ import dagger.Component;
@Singleton
@Component(modules = KeychainModule.class)
-public interface KeychainComponent {
+interface KeychainComponent {
Optional keychainAccess();
diff --git a/main/keychain/src/test/java/org/cryptomator/keychain/MapKeychainAccess.java b/main/keychain/src/test/java/org/cryptomator/keychain/MapKeychainAccess.java
index dd06319cd..081a0b0e6 100644
--- a/main/keychain/src/test/java/org/cryptomator/keychain/MapKeychainAccess.java
+++ b/main/keychain/src/test/java/org/cryptomator/keychain/MapKeychainAccess.java
@@ -5,15 +5,19 @@ import java.util.Map;
class MapKeychainAccess implements KeychainAccessStrategy {
- private final Map map = new HashMap<>();
+ private final Map map = new HashMap<>();
@Override
public void storePassphrase(String key, CharSequence passphrase) {
- map.put(key, passphrase);
+ char[] pw = new char[passphrase.length()];
+ for (int i = 0; i < passphrase.length(); i++) {
+ pw[i] = passphrase.charAt(i);
+ }
+ map.put(key, pw);
}
@Override
- public CharSequence loadPassphrase(String key) {
+ public char[] loadPassphrase(String key) {
return map.get(key);
}
diff --git a/main/pom.xml b/main/pom.xml
index bb9d47a8b..1a412a88a 100644
--- a/main/pom.xml
+++ b/main/pom.xml
@@ -58,7 +58,6 @@
${project.version}
test
-
org.cryptomator
filesystem-api
@@ -107,7 +106,6 @@
filesystem-stats
${project.version}
-
org.cryptomator
frontend-api
@@ -118,7 +116,11 @@
frontend-webdav
${project.version}
-
+
+ org.cryptomator
+ keychain
+ ${project.version}
+
org.cryptomator
ui
diff --git a/main/ui/pom.xml b/main/ui/pom.xml
index bf6ab3fec..a0e7a0749 100644
--- a/main/ui/pom.xml
+++ b/main/ui/pom.xml
@@ -58,6 +58,10 @@
org.cryptomator
jni
+
+ org.cryptomator
+ keychain
+
diff --git a/main/ui/src/main/java/org/cryptomator/ui/CryptomatorModule.java b/main/ui/src/main/java/org/cryptomator/ui/CryptomatorModule.java
index 473e213d0..3de672b47 100644
--- a/main/ui/src/main/java/org/cryptomator/ui/CryptomatorModule.java
+++ b/main/ui/src/main/java/org/cryptomator/ui/CryptomatorModule.java
@@ -25,6 +25,7 @@ import org.cryptomator.frontend.webdav.WebDavModule;
import org.cryptomator.frontend.webdav.WebDavServer;
import org.cryptomator.jni.JniModule;
import org.cryptomator.jni.MacFunctions;
+import org.cryptomator.keychain.KeychainModule;
import org.cryptomator.ui.model.Vault;
import org.cryptomator.ui.model.VaultObjectMapperProvider;
import org.cryptomator.ui.model.Vaults;
@@ -42,7 +43,7 @@ import javafx.application.Application;
import javafx.beans.Observable;
import javafx.stage.Stage;
-@Module(includes = {CryptoEngineModule.class, CommonsModule.class, WebDavModule.class})
+@Module(includes = {CryptoEngineModule.class, CommonsModule.class, WebDavModule.class, KeychainModule.class})
class CryptomatorModule {
private static final Logger LOG = LoggerFactory.getLogger(CryptomatorModule.class);
diff --git a/main/ui/src/main/java/org/cryptomator/ui/controllers/ChangePasswordController.java b/main/ui/src/main/java/org/cryptomator/ui/controllers/ChangePasswordController.java
index b1a76529b..c78ac51f0 100644
--- a/main/ui/src/main/java/org/cryptomator/ui/controllers/ChangePasswordController.java
+++ b/main/ui/src/main/java/org/cryptomator/ui/controllers/ChangePasswordController.java
@@ -12,6 +12,7 @@ package org.cryptomator.ui.controllers;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.net.URL;
+import java.util.Objects;
import java.util.Optional;
import javax.inject.Inject;
@@ -31,9 +32,7 @@ import javafx.application.Application;
import javafx.application.Platform;
import javafx.beans.binding.BooleanBinding;
import javafx.beans.property.IntegerProperty;
-import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleIntegerProperty;
-import javafx.beans.property.SimpleObjectProperty;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
@@ -49,9 +48,9 @@ public class ChangePasswordController extends LocalizedFXMLViewController {
private final Application app;
private final PasswordStrengthUtil strengthRater;
- final ObjectProperty vault = new SimpleObjectProperty<>();
- private Optional listener = Optional.empty();
private final IntegerProperty passwordStrength = new SimpleIntegerProperty(); // 0-4
+ private Optional listener = Optional.empty();
+ private Vault vault;
@Inject
public ChangePasswordController(Application app, PasswordStrengthUtil strengthRater, Localization localization) {
@@ -101,7 +100,6 @@ public class ChangePasswordController extends LocalizedFXMLViewController {
BooleanBinding oldPasswordIsEmpty = oldPasswordField.textProperty().isEmpty();
BooleanBinding newPasswordIsEmpty = newPasswordField.textProperty().isEmpty();
BooleanBinding passwordsDiffer = newPasswordField.textProperty().isNotEqualTo(retypePasswordField.textProperty());
- EasyBind.subscribe(vault, this::vaultDidChange);
changePasswordButton.disableProperty().bind(oldPasswordIsEmpty.or(newPasswordIsEmpty.or(passwordsDiffer)));
passwordStrength.bind(EasyBind.map(newPasswordField.textProperty(), strengthRater::computeRate));
@@ -118,10 +116,11 @@ public class ChangePasswordController extends LocalizedFXMLViewController {
return getClass().getResource("/fxml/change_password.fxml");
}
- private void vaultDidChange(Vault newVault) {
- oldPasswordField.clear();
- newPasswordField.clear();
- retypePasswordField.clear();
+ void setVault(Vault vault) {
+ this.vault = Objects.requireNonNull(vault);
+ oldPasswordField.swipe();
+ newPasswordField.swipe();
+ retypePasswordField.swipe();
// trigger "default" change to refresh key bindings:
changePasswordButton.setDefaultButton(false);
changePasswordButton.setDefaultButton(true);
@@ -144,7 +143,7 @@ public class ChangePasswordController extends LocalizedFXMLViewController {
private void didClickChangePasswordButton(ActionEvent event) {
downloadsPageLink.setVisible(false);
try {
- vault.get().changePassphrase(oldPasswordField.getCharacters(), newPasswordField.getCharacters());
+ vault.changePassphrase(oldPasswordField.getCharacters(), newPasswordField.getCharacters());
messageText.setText(localization.getString("changePassword.infoMessage.success"));
listener.ifPresent(this::invokeListenerLater);
} catch (InvalidPassphraseException e) {
diff --git a/main/ui/src/main/java/org/cryptomator/ui/controllers/InitializeController.java b/main/ui/src/main/java/org/cryptomator/ui/controllers/InitializeController.java
index 2989e9eaf..9a61f28c9 100644
--- a/main/ui/src/main/java/org/cryptomator/ui/controllers/InitializeController.java
+++ b/main/ui/src/main/java/org/cryptomator/ui/controllers/InitializeController.java
@@ -13,6 +13,7 @@ import java.io.IOException;
import java.io.UncheckedIOException;
import java.net.URL;
import java.nio.file.FileAlreadyExistsException;
+import java.util.Objects;
import java.util.Optional;
import javax.inject.Inject;
@@ -29,9 +30,7 @@ import org.slf4j.LoggerFactory;
import javafx.application.Platform;
import javafx.beans.binding.BooleanBinding;
import javafx.beans.property.IntegerProperty;
-import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleIntegerProperty;
-import javafx.beans.property.SimpleObjectProperty;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
@@ -44,9 +43,9 @@ public class InitializeController extends LocalizedFXMLViewController {
private static final Logger LOG = LoggerFactory.getLogger(InitializeController.class);
private final PasswordStrengthUtil strengthRater;
- final ObjectProperty vault = new SimpleObjectProperty<>();
- private Optional listener = Optional.empty();
private final IntegerProperty passwordStrength = new SimpleIntegerProperty(); // 0-4
+ private Optional listener = Optional.empty();
+ private Vault vault;
@Inject
public InitializeController(Localization localization, PasswordStrengthUtil strengthRater) {
@@ -88,7 +87,6 @@ public class InitializeController extends LocalizedFXMLViewController {
public void initialize() {
BooleanBinding passwordIsEmpty = passwordField.textProperty().isEmpty();
BooleanBinding passwordsDiffer = passwordField.textProperty().isNotEqualTo(retypePasswordField.textProperty());
- EasyBind.subscribe(vault, this::vaultDidChange);
okButton.disableProperty().bind(passwordIsEmpty.or(passwordsDiffer));
passwordStrength.bind(EasyBind.map(passwordField.textProperty(), strengthRater::computeRate));
@@ -105,9 +103,10 @@ public class InitializeController extends LocalizedFXMLViewController {
return getClass().getResource("/fxml/initialize.fxml");
}
- private void vaultDidChange(Vault newVault) {
- passwordField.clear();
- retypePasswordField.clear();
+ void setVault(Vault vault) {
+ this.vault = Objects.requireNonNull(vault);
+ passwordField.swipe();
+ retypePasswordField.swipe();
// trigger "default" change to refresh key bindings:
okButton.setDefaultButton(false);
okButton.setDefaultButton(true);
@@ -121,7 +120,7 @@ public class InitializeController extends LocalizedFXMLViewController {
protected void initializeVault(ActionEvent event) {
final CharSequence passphrase = passwordField.getCharacters();
try {
- vault.get().create(passphrase);
+ vault.create(passphrase);
listener.ifPresent(this::invokeListenerLater);
} catch (FileAlreadyExistsException ex) {
messageLabel.setText(localization.getString("initialize.messageLabel.alreadyInitialized"));
diff --git a/main/ui/src/main/java/org/cryptomator/ui/controllers/MainController.java b/main/ui/src/main/java/org/cryptomator/ui/controllers/MainController.java
index 478c6be6b..9c9c194ba 100644
--- a/main/ui/src/main/java/org/cryptomator/ui/controllers/MainController.java
+++ b/main/ui/src/main/java/org/cryptomator/ui/controllers/MainController.java
@@ -315,7 +315,8 @@ public class MainController extends LocalizedFXMLViewController {
private void showInitializeView() {
final InitializeController ctrl = initializeController.get();
- ctrl.vault.bind(selectedVault);
+ ctrl.loadFxml();
+ ctrl.setVault(selectedVault.get());
ctrl.setListener(this::didInitialize);
activeController.set(ctrl);
}
@@ -326,7 +327,8 @@ public class MainController extends LocalizedFXMLViewController {
private void showUpgradeView() {
final UpgradeController ctrl = upgradeController.get();
- ctrl.vault.bind(selectedVault);
+ ctrl.loadFxml();
+ ctrl.setVault(selectedVault.get());
ctrl.setListener(this::didUpgrade);
activeController.set(ctrl);
}
@@ -337,7 +339,8 @@ public class MainController extends LocalizedFXMLViewController {
private void showUnlockView() {
final UnlockController ctrl = unlockController.get();
- ctrl.vault.bind(selectedVault);
+ ctrl.loadFxml();
+ ctrl.setVault(selectedVault.get());
ctrl.setListener(this::didUnlock);
activeController.set(ctrl);
}
@@ -353,6 +356,7 @@ public class MainController extends LocalizedFXMLViewController {
final UnlockedController ctrl = unlockedVaults.computeIfAbsent(vault, k -> {
return unlockedControllerProvider.get();
});
+ ctrl.loadFxml();
ctrl.setVault(vault);
ctrl.setListener(this::didLock);
activeController.set(ctrl);
@@ -368,7 +372,8 @@ public class MainController extends LocalizedFXMLViewController {
private void showChangePasswordView() {
final ChangePasswordController ctrl = changePasswordController.get();
- ctrl.vault.bind(selectedVault);
+ ctrl.loadFxml();
+ ctrl.setVault(selectedVault.get());
ctrl.setListener(this::didChangePassword);
activeController.set(ctrl);
}
diff --git a/main/ui/src/main/java/org/cryptomator/ui/controllers/UnlockController.java b/main/ui/src/main/java/org/cryptomator/ui/controllers/UnlockController.java
index d17175dc7..e5fe09fe4 100644
--- a/main/ui/src/main/java/org/cryptomator/ui/controllers/UnlockController.java
+++ b/main/ui/src/main/java/org/cryptomator/ui/controllers/UnlockController.java
@@ -9,7 +9,9 @@
package org.cryptomator.ui.controllers;
import java.net.URL;
+import java.util.Arrays;
import java.util.Comparator;
+import java.util.Objects;
import java.util.Optional;
import javax.inject.Inject;
@@ -22,25 +24,24 @@ import org.cryptomator.frontend.CommandFailedException;
import org.cryptomator.frontend.FrontendCreationFailedException;
import org.cryptomator.frontend.FrontendFactory;
import org.cryptomator.frontend.webdav.mount.WindowsDriveLetters;
+import org.cryptomator.keychain.KeychainAccess;
import org.cryptomator.ui.controls.SecPasswordField;
import org.cryptomator.ui.model.Vault;
import org.cryptomator.ui.settings.Localization;
import org.cryptomator.ui.settings.Settings;
import org.cryptomator.ui.util.AsyncTaskService;
-import org.fxmisc.easybind.EasyBind;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import dagger.Lazy;
import javafx.application.Application;
import javafx.application.Platform;
-import javafx.beans.property.ObjectProperty;
-import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
+import javafx.scene.control.CheckBox;
import javafx.scene.control.ChoiceBox;
import javafx.scene.control.Hyperlink;
import javafx.scene.control.Label;
@@ -61,22 +62,34 @@ public class UnlockController extends LocalizedFXMLViewController {
private final Settings settings;
private final WindowsDriveLetters driveLetters;
private final ChangeListener driveLetterChangeListener = this::winDriveLetterDidChange;
- final ObjectProperty vault = new SimpleObjectProperty<>();
+ private final Optional keychainAccess;
+ private Vault vault;
private Optional listener = Optional.empty();
@Inject
- public UnlockController(Application app, Localization localization, AsyncTaskService asyncTaskService, Lazy frontendFactory, Settings settings, WindowsDriveLetters driveLetters) {
+ public UnlockController(Application app, Localization localization, AsyncTaskService asyncTaskService, Lazy frontendFactory, Settings settings, WindowsDriveLetters driveLetters,
+ Optional keychainAccess) {
super(localization);
this.app = app;
this.asyncTaskService = asyncTaskService;
this.frontendFactory = frontendFactory;
this.settings = settings;
this.driveLetters = driveLetters;
+ this.keychainAccess = keychainAccess;
}
@FXML
private SecPasswordField passwordField;
+ @FXML
+ private Button advancedOptionsButton;
+
+ @FXML
+ private Button unlockButton;
+
+ @FXML
+ private CheckBox savePassword;
+
@FXML
private TextField mountName;
@@ -86,12 +99,6 @@ public class UnlockController extends LocalizedFXMLViewController {
@FXML
private ChoiceBox winDriveLetter;
- @FXML
- private Button advancedOptionsButton;
-
- @FXML
- private Button unlockButton;
-
@FXML
private ProgressIndicator progressIndicator;
@@ -107,8 +114,10 @@ public class UnlockController extends LocalizedFXMLViewController {
@Override
public void initialize() {
advancedOptions.managedProperty().bind(advancedOptions.visibleProperty());
+ unlockButton.disableProperty().bind(passwordField.textProperty().isEmpty());
mountName.addEventFilter(KeyEvent.KEY_TYPED, this::filterAlphanumericKeyEvents);
mountName.textProperty().addListener(this::mountNameDidChange);
+ savePassword.setDisable(!keychainAccess.isPresent());
if (SystemUtils.IS_OS_WINDOWS) {
winDriveLetter.setConverter(new WinDriveLetterLabelConverter());
} else {
@@ -117,9 +126,6 @@ public class UnlockController extends LocalizedFXMLViewController {
winDriveLetter.setVisible(false);
winDriveLetter.setManaged(false);
}
- unlockButton.disableProperty().bind(passwordField.textProperty().isEmpty());
-
- EasyBind.subscribe(vault, this::vaultDidChange);
}
@Override
@@ -127,11 +133,15 @@ public class UnlockController extends LocalizedFXMLViewController {
return getClass().getResource("/fxml/unlock.fxml");
}
- private void vaultDidChange(Vault newVault) {
- if (newVault == null) {
+ void setVault(Vault vault) {
+ // trigger "default" change to refresh key bindings:
+ unlockButton.setDefaultButton(false);
+ unlockButton.setDefaultButton(true);
+ if (vault.equals(this.vault)) {
return;
}
- passwordField.clear();
+ this.vault = Objects.requireNonNull(vault);
+ passwordField.swipe();
advancedOptions.setVisible(false);
advancedOptionsButton.setText(localization.getString("unlock.button.advancedOptions.show"));
progressIndicator.setVisible(false);
@@ -145,13 +155,21 @@ public class UnlockController extends LocalizedFXMLViewController {
}
downloadsPageLink.setVisible(false);
messageText.setText(null);
- mountName.setText(newVault.getMountName());
+ mountName.setText(vault.getMountName());
if (SystemUtils.IS_OS_WINDOWS) {
chooseSelectedDriveLetter();
}
- // trigger "default" change to refresh key bindings:
- unlockButton.setDefaultButton(false);
- unlockButton.setDefaultButton(true);
+ savePassword.setSelected(false);
+ // auto-fill pw from keychain:
+ if (keychainAccess.isPresent()) {
+ char[] storedPw = keychainAccess.get().loadPassphrase(vault.getId());
+ if (storedPw != null) {
+ savePassword.setSelected(true);
+ passwordField.setText(new String(storedPw));
+ passwordField.selectRange(storedPw.length, storedPw.length);
+ Arrays.fill(storedPw, ' ');
+ }
+ }
}
// ****************************************
@@ -188,14 +206,11 @@ public class UnlockController extends LocalizedFXMLViewController {
}
private void mountNameDidChange(ObservableValue extends String> property, String oldValue, String newValue) {
- if (vault.get() == null) {
- return;
- }
// newValue is guaranteed to be a-z0-9_, see #filterAlphanumericKeyEvents
if (newValue.isEmpty()) {
- mountName.setText(vault.get().getMountName());
+ mountName.setText(vault.getMountName());
} else {
- vault.get().setMountName(newValue);
+ vault.setMountName(newValue);
}
}
@@ -242,20 +257,17 @@ public class UnlockController extends LocalizedFXMLViewController {
}
private void winDriveLetterDidChange(ObservableValue extends Character> property, Character oldValue, Character newValue) {
- if (vault.get() == null) {
- return;
- }
- vault.get().setWinDriveLetter(newValue);
+ vault.setWinDriveLetter(newValue);
settings.save();
}
private void chooseSelectedDriveLetter() {
assert SystemUtils.IS_OS_WINDOWS;
// if the vault prefers a drive letter, that is currently occupied, this is our last chance to reset this:
- if (driveLetters.getOccupiedDriveLetters().contains(vault.get().getWinDriveLetter())) {
- vault.get().setWinDriveLetter(null);
+ if (driveLetters.getOccupiedDriveLetters().contains(vault.getWinDriveLetter())) {
+ vault.setWinDriveLetter(null);
}
- final Character letter = vault.get().getWinDriveLetter();
+ final Character letter = vault.getWinDriveLetter();
if (letter == null) {
// first option is known to be 'auto-assign' due to #WinDriveLetterComparator.
this.winDriveLetter.getSelectionModel().selectFirst();
@@ -275,10 +287,10 @@ public class UnlockController extends LocalizedFXMLViewController {
progressIndicator.setVisible(true);
downloadsPageLink.setVisible(false);
CharSequence password = passwordField.getCharacters();
- asyncTaskService.asyncTaskOf(() -> this.unlock(vault.get(), password)).run();
+ asyncTaskService.asyncTaskOf(() -> this.unlock(password)).run();
}
- private void unlock(Vault vault, CharSequence password) {
+ private void unlock(CharSequence password) {
try {
vault.activateFrontend(frontendFactory.get(), settings, password);
vault.reveal();
@@ -286,9 +298,15 @@ public class UnlockController extends LocalizedFXMLViewController {
messageText.setText(null);
listener.ifPresent(lstnr -> lstnr.didUnlock(vault));
});
+ if (keychainAccess.isPresent() && savePassword.isSelected()) {
+ keychainAccess.get().storePassphrase(vault.getId(), password);
+ } else {
+ passwordField.swipe();
+ }
} catch (InvalidPassphraseException e) {
Platform.runLater(() -> {
messageText.setText(localization.getString("unlock.errorMessage.wrongPassword"));
+ passwordField.selectAll();
passwordField.requestFocus();
});
} catch (UnsupportedVaultFormatException e) {
@@ -307,7 +325,6 @@ public class UnlockController extends LocalizedFXMLViewController {
});
} finally {
Platform.runLater(() -> {
- passwordField.swipe();
mountName.setDisable(false);
advancedOptionsButton.setDisable(false);
progressIndicator.setVisible(false);
diff --git a/main/ui/src/main/java/org/cryptomator/ui/controllers/UpgradeController.java b/main/ui/src/main/java/org/cryptomator/ui/controllers/UpgradeController.java
index a34e2aeb6..8e6a4e97f 100644
--- a/main/ui/src/main/java/org/cryptomator/ui/controllers/UpgradeController.java
+++ b/main/ui/src/main/java/org/cryptomator/ui/controllers/UpgradeController.java
@@ -27,11 +27,11 @@ import javafx.scene.control.ProgressIndicator;
public class UpgradeController extends LocalizedFXMLViewController {
- final ObjectProperty vault = new SimpleObjectProperty<>();
- final ObjectProperty> strategy = new SimpleObjectProperty<>();
+ private final ObjectProperty> strategy = new SimpleObjectProperty<>();
private final UpgradeStrategies strategies;
private final AsyncTaskService asyncTaskService;
private Optional listener = Optional.empty();
+ private Vault vault;
@Inject
public UpgradeController(Localization localization, UpgradeStrategies strategies, AsyncTaskService asyncTaskService) {
@@ -67,8 +67,6 @@ public class UpgradeController extends LocalizedFXMLViewController {
BooleanExpression passwordProvided = passwordField.textProperty().isNotEmpty().and(passwordField.disabledProperty().not());
BooleanExpression syncFinished = confirmationCheckbox.selectedProperty();
upgradeButton.disableProperty().bind(passwordProvided.not().or(syncFinished.not()));
-
- EasyBind.subscribe(vault, this::vaultDidChange);
}
@Override
@@ -76,9 +74,10 @@ public class UpgradeController extends LocalizedFXMLViewController {
return getClass().getResource("/fxml/upgrade.fxml");
}
- private void vaultDidChange(Vault newVault) {
+ void setVault(Vault vault) {
+ this.vault = Objects.requireNonNull(vault);
errorLabel.setText(null);
- strategy.set(strategies.getUpgradeStrategy(newVault));
+ strategy.set(strategies.getUpgradeStrategy(vault));
// trigger "default" change to refresh key bindings:
upgradeButton.setDefaultButton(false);
upgradeButton.setDefaultButton(true);
@@ -89,7 +88,7 @@ public class UpgradeController extends LocalizedFXMLViewController {
// ****************************************
private String upgradeNotification(UpgradeStrategy instruction) {
- return instruction.getNotification(vault.get());
+ return instruction.getNotification(vault);
}
// ****************************************
@@ -102,15 +101,14 @@ public class UpgradeController extends LocalizedFXMLViewController {
}
private void upgrade(UpgradeStrategy instruction) {
- Vault v = Objects.requireNonNull(vault.getValue());
passwordField.setDisable(true);
progressIndicator.setVisible(true);
asyncTaskService //
.asyncTaskOf(() -> {
- if (!instruction.isApplicable(v)) {
- throw new IllegalStateException("No ugprade needed for " + v.path().getValue());
+ if (!instruction.isApplicable(vault)) {
+ throw new IllegalStateException("No ugprade needed for " + vault.path().getValue());
}
- instruction.upgrade(v, passwordField.getCharacters());
+ instruction.upgrade(vault, passwordField.getCharacters());
}) //
.onSuccess(this::showNextUpgrade) //
.onError(UpgradeFailedException.class, e -> {
@@ -125,7 +123,7 @@ public class UpgradeController extends LocalizedFXMLViewController {
private void showNextUpgrade() {
errorLabel.setText(null);
- Optional nextStrategy = strategies.getUpgradeStrategy(vault.getValue());
+ Optional nextStrategy = strategies.getUpgradeStrategy(vault);
if (nextStrategy.isPresent()) {
strategy.set(nextStrategy);
} else {
diff --git a/main/ui/src/main/resources/fxml/unlock.fxml b/main/ui/src/main/resources/fxml/unlock.fxml
index 851d33fc9..0a8ea2fb8 100644
--- a/main/ui/src/main/resources/fxml/unlock.fxml
+++ b/main/ui/src/main/resources/fxml/unlock.fxml
@@ -68,12 +68,16 @@
-
-
+
+
-
-
+
+
+
+
+
+
diff --git a/main/ui/src/main/resources/localization/en.txt b/main/ui/src/main/resources/localization/en.txt
index ec6c8f6bf..1e72c083e 100644
--- a/main/ui/src/main/resources/localization/en.txt
+++ b/main/ui/src/main/resources/localization/en.txt
@@ -49,6 +49,7 @@ upgrade.version3to4.err.io=Migration failed due to an I/O Exception. See log fil
# unlock.fxml
unlock.label.password=Password
+unlock.label.savePassword=Save password
unlock.label.mountName=Drive name
unlock.label.winDriveLetter=Drive letter
unlock.label.downloadsPageLink=All Cryptomator versions