refactoring forget password dialog ( when unlocking a vault)

This commit is contained in:
Armin Schrenk
2019-09-18 19:12:01 +02:00
parent c961eb0ca0
commit 200fc1a563
11 changed files with 259 additions and 22 deletions

View File

@@ -8,6 +8,7 @@ public enum FxmlFile {
ADDVAULT_NEW_PASSWORD("/fxml/addvault_new_password.fxml"), //
ADDVAULT_SUCCESS("/fxml/addvault_success.fxml"), //
CHANGEPASSWORD("/fxml/changepassword.fxml"), //
FORGET_PASSWORD("/fxml/forget_password.fxml"), //
MAIN_WINDOW("/fxml/main_window.fxml"), //
MIGRATION_RUN("/fxml/migration_run.fxml"), //
MIGRATION_START("/fxml/migration_start.fxml"), //

View File

@@ -0,0 +1,14 @@
package org.cryptomator.ui.forgetPassword;
import javax.inject.Qualifier;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
@Qualifier
@Documented
@Retention(RUNTIME)
public @interface ForgetPassword {
}

View File

@@ -0,0 +1,51 @@
package org.cryptomator.ui.forgetPassword;
import dagger.BindsInstance;
import dagger.Lazy;
import dagger.Subcomponent;
import javafx.beans.property.ReadOnlyBooleanProperty;
import javafx.scene.Scene;
import javafx.stage.Stage;
import org.cryptomator.common.vaults.Vault;
import org.cryptomator.ui.common.FxmlFile;
import org.cryptomator.ui.common.FxmlScene;
import javax.inject.Named;
import java.util.concurrent.CompletableFuture;
@ForgetPasswordScoped
@Subcomponent(modules = {ForgetPasswordModule.class})
public interface ForgetPasswordComponent {
@ForgetPassword
ReadOnlyBooleanProperty confirmedProperty();
@ForgetPassword
Stage window();
@FxmlScene(FxmlFile.FORGET_PASSWORD)
Lazy<Scene> scene();
default CompletableFuture<Boolean> showForgetPassword() {
CompletableFuture<Boolean> result = new CompletableFuture<>();
Stage stage = window();
stage.setScene(scene().get());
stage.sizeToScene();
stage.show();
stage.setOnHidden(evt -> result.complete(confirmedProperty().get()));
return result;
}
@Subcomponent.Builder
interface Builder {
@BindsInstance
Builder vault(@ForgetPassword Vault vault);
@BindsInstance
Builder owner(@Named("forgetPasswordOwner") Stage owner);
ForgetPasswordComponent build();
}
}

View File

@@ -0,0 +1,53 @@
package org.cryptomator.ui.forgetPassword;
import javafx.beans.property.BooleanProperty;
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.ui.common.FxController;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.inject.Inject;
import java.util.Optional;
@ForgetPasswordScoped
public class ForgetPasswordController implements FxController {
private static final Logger LOG = LoggerFactory.getLogger(ForgetPasswordController.class);
private final Stage window;
private final Vault vault;
private final Optional<KeychainAccess> keychainAccess;
private final BooleanProperty confirmedResult;
@Inject
public ForgetPasswordController(@ForgetPassword Stage window, @ForgetPassword Vault vault, Optional<KeychainAccess> keychainAccess, @ForgetPassword BooleanProperty confirmedResult) {
this.window = window;
this.vault = vault;
this.keychainAccess = keychainAccess;
this.confirmedResult = confirmedResult;
}
@FXML
public void close() {
window.close();
}
@FXML
public void finish() {
if (keychainAccess.isPresent()) {
try {
keychainAccess.get().deletePassphrase(vault.getId());
LOG.debug("Forgot password for vault {}.", vault.getDisplayableName());
confirmedResult.setValue(true);
} catch (KeychainAccessException e) {
LOG.error("Failed to remove entry from system keychain.", e);
confirmedResult.setValue(false);
}
}
window.close();
}
}

View File

@@ -0,0 +1,74 @@
package org.cryptomator.ui.forgetPassword;
import dagger.Binds;
import dagger.Module;
import dagger.Provides;
import dagger.multibindings.IntoMap;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.ReadOnlyBooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.stage.Modality;
import javafx.stage.Stage;
import org.cryptomator.ui.common.FXMLLoaderFactory;
import org.cryptomator.ui.common.FxController;
import org.cryptomator.ui.common.FxControllerKey;
import org.cryptomator.ui.common.FxmlFile;
import org.cryptomator.ui.common.FxmlScene;
import javax.inject.Named;
import javax.inject.Provider;
import java.util.Map;
import java.util.Optional;
import java.util.ResourceBundle;
@Module
abstract class ForgetPasswordModule {
@Provides
@ForgetPassword
@ForgetPasswordScoped
static FXMLLoaderFactory provideFxmlLoaderFactory(Map<Class<? extends FxController>, Provider<FxController>> factories, ResourceBundle resourceBundle) {
return new FXMLLoaderFactory(factories, resourceBundle);
}
@Provides
@ForgetPassword
@ForgetPasswordScoped
static Stage provideStage(ResourceBundle resourceBundle, @Named("windowIcon") Optional<Image> windowIcon, @Named("forgetPasswordOwner") Stage owner) {
Stage stage = new Stage();
stage.setTitle(resourceBundle.getString("forgetPassword.title"));
stage.setResizable(false);
stage.initModality(Modality.WINDOW_MODAL);
stage.initOwner(owner);
windowIcon.ifPresent(stage.getIcons()::add);
return stage;
}
@Provides
@FxmlScene(FxmlFile.FORGET_PASSWORD)
@ForgetPasswordScoped
static Scene provideForgetPasswordScene(@ForgetPassword FXMLLoaderFactory fxmlLoaders, @ForgetPassword Stage window) {
return fxmlLoaders.createScene("/fxml/forget_password.fxml");
}
@Provides
@ForgetPassword
@ForgetPasswordScoped
static BooleanProperty provideConfirmedProperty() {
return new SimpleBooleanProperty(false);
}
@Binds
@ForgetPassword
@ForgetPasswordScoped
abstract ReadOnlyBooleanProperty bindReadOnlyConfirmedProperty(@ForgetPassword BooleanProperty confirmedProperty);
// ------------------
@Binds
@IntoMap
@FxControllerKey(ForgetPasswordController.class)
abstract FxController bindForgetPasswordController(ForgetPasswordController controller);
}

View File

@@ -0,0 +1,13 @@
package org.cryptomator.ui.forgetPassword;
import javax.inject.Scope;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Scope
@Documented
@Retention(RetentionPolicy.RUNTIME)
public @interface ForgetPasswordScoped {
}

View File

@@ -12,13 +12,10 @@ import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.value.WritableValue;
import javafx.fxml.FXML;
import javafx.scene.Scene;
import javafx.scene.control.Alert;
import javafx.scene.control.ButtonType;
import javafx.scene.control.CheckBox;
import javafx.scene.control.ContentDisplay;
import javafx.stage.Stage;
import javafx.util.Duration;
import org.apache.commons.lang3.SystemUtils;
import org.cryptomator.common.vaults.Vault;
import org.cryptomator.common.vaults.VaultState;
import org.cryptomator.cryptolib.api.InvalidPassphraseException;
@@ -30,8 +27,7 @@ import org.cryptomator.ui.common.FxmlFile;
import org.cryptomator.ui.common.FxmlScene;
import org.cryptomator.ui.common.Tasks;
import org.cryptomator.ui.controls.NiceSecurePasswordField;
import org.cryptomator.ui.controls.SecurePasswordField;
import org.cryptomator.ui.util.DialogBuilderUtil;
import org.cryptomator.ui.forgetPassword.ForgetPasswordComponent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -55,12 +51,13 @@ public class UnlockController implements FxController {
private final Optional<KeychainAccess> keychainAccess;
private final ResourceBundle resourceBundle;
private final Lazy<Scene> successScene;
private final ForgetPasswordComponent.Builder forgetPassword;
private final BooleanProperty unlockButtonDisabled;
public NiceSecurePasswordField passwordField;
public CheckBox savePassword;
@Inject
public UnlockController(@UnlockWindow Stage window, @UnlockWindow Vault vault, ExecutorService executor, Optional<KeychainAccess> keychainAccess, ResourceBundle resourceBundle, @FxmlScene(FxmlFile.UNLOCK_SUCCESS) Lazy<Scene> successScene) {
public UnlockController(@UnlockWindow Stage window, @UnlockWindow Vault vault, ExecutorService executor, Optional<KeychainAccess> keychainAccess, ResourceBundle resourceBundle, @FxmlScene(FxmlFile.UNLOCK_SUCCESS) Lazy<Scene> successScene, ForgetPasswordComponent.Builder forgetPassword) {
this.window = window;
this.vault = vault;
this.executor = executor;
@@ -68,6 +65,7 @@ public class UnlockController implements FxController {
this.keychainAccess = keychainAccess;
this.resourceBundle = resourceBundle;
this.successScene = successScene;
this.forgetPassword = forgetPassword;
this.unlockButtonDisabled = new SimpleBooleanProperty();
}
@@ -128,21 +126,7 @@ public class UnlockController implements FxController {
@FXML
private void didClickSavePasswordCheckbox() {
if (!savePassword.isSelected() && hasStoredPassword()) {
Alert confirmDialog = DialogBuilderUtil.buildConfirmationDialog( //
resourceBundle.getString("unlock.deleteSavedPasswordDialog.title"), //
resourceBundle.getString("unlock.deleteSavedPasswordDialog.header"), //
resourceBundle.getString("unlock.deleteSavedPasswordDialog.content"), //
SystemUtils.IS_OS_MAC_OSX ? ButtonType.CANCEL : ButtonType.OK);
Optional<ButtonType> choice = confirmDialog.showAndWait();
if (ButtonType.OK.equals(choice.get())) {
try {
keychainAccess.get().deletePassphrase(vault.getId());
} catch (KeychainAccessException e) {
LOG.error("Failed to remove entry from system keychain.", e);
}
} else if (ButtonType.CANCEL.equals(choice.get())) {
savePassword.setSelected(true);
}
forgetPassword.vault(vault).build().showForgetPassword().thenAccept(forgotten -> savePassword.setSelected(!forgotten));
}
}

View File

@@ -16,6 +16,7 @@ import org.cryptomator.ui.common.FxController;
import org.cryptomator.ui.common.FxControllerKey;
import org.cryptomator.ui.common.FxmlFile;
import org.cryptomator.ui.common.FxmlScene;
import org.cryptomator.ui.forgetPassword.ForgetPasswordComponent;
import javax.inject.Named;
import javax.inject.Provider;
@@ -23,7 +24,7 @@ import java.util.Map;
import java.util.Optional;
import java.util.ResourceBundle;
@Module
@Module(subcomponents={ForgetPasswordComponent.class})
abstract class UnlockModule {
@Provides

View File

@@ -0,0 +1,40 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.ButtonBar?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.StackPane?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.shape.Circle?>
<?import org.cryptomator.ui.controls.FontAwesome5IconView?>
<VBox xmlns="http://javafx.com/javafx"
xmlns:fx="http://javafx.com/fxml"
fx:controller="org.cryptomator.ui.forgetPassword.ForgetPasswordController"
minWidth="400"
maxWidth="400"
minHeight="145"
spacing="12">
<padding>
<Insets topRightBottomLeft="12"/>
</padding>
<children>
<HBox spacing="12" alignment="CENTER_LEFT" VBox.vgrow="ALWAYS">
<StackPane alignment="CENTER" HBox.hgrow="NEVER">
<Circle styleClass="glyph-icon-primary" radius="24"/>
<FontAwesome5IconView styleClass="glyph-icon-white" glyph="QUESTION" glyphSize="24"/>
</StackPane>
<Label text="%forgetPassword.information" wrapText="true" textAlignment="LEFT" HBox.hgrow="ALWAYS"/>
</HBox>
<VBox alignment="BOTTOM_CENTER" VBox.vgrow="ALWAYS">
<ButtonBar buttonMinWidth="120" buttonOrder="+CI">
<buttons>
<Button text="%generic.button.cancel" ButtonBar.buttonData="CANCEL_CLOSE" defaultButton="true" cancelButton="true" onAction="#close"/>
<Button text="%forgetPassword.confirmBtn" ButtonBar.buttonData="FINISH" onAction="#finish"/>
</buttons>
</ButtonBar>
</VBox>
</children>
</VBox>

View File

@@ -68,6 +68,11 @@ changepassword.passwordsMatch=Passwords match!
changepassword.passwordsDoNotMatch=Passwords do not match
changepassword.finalConfirmation=I understand that I will not be able to recover my data if I forget my password
# Forget password
forgetPassword.title=Forget Password
forgetPassword.information=TODO Yalla Yalla
forgetPassword.confirmBtn=Ok, forget
# Unlock
unlock.title=Unlock Vault
unlock.passwordPrompt=Enter password for "%s":

View File

@@ -145,3 +145,4 @@ passwordStrength.messageLabel.4=Sehr stark
# Quit
quit.prompt=Cryptomator beenden? Es sind noch Tresore entsperrt.
quit.lockAndQuit=Sperren und beenden
forgetPassword.information=TODO Yalla Yalla