Made recovery key creation a two-step wizard

This commit is contained in:
Sebastian Stenzel
2019-10-08 19:18:49 +02:00
parent f7630c28d6
commit f82fddc8fe
8 changed files with 125 additions and 48 deletions

View File

@@ -17,6 +17,7 @@ public enum FxmlFile {
PREFERENCES("/fxml/preferences.fxml"), //
QUIT("/fxml/quit.fxml"), //
RECOVERYKEY_CREATE("/fxml/recoverykey_create.fxml"), //
RECOVERYKEY_DISPLAY("/fxml/recoverykey_display.fxml"), //
REMOVE_VAULT("/fxml/remove_vault.fxml"), //
UNLOCK("/fxml/unlock.fxml"),
UNLOCK_SUCCESS("/fxml/unlock_success.fxml"), //

View File

@@ -67,6 +67,10 @@ public class NiceSecurePasswordField extends StackPane {
public void requestFocus() {
passwordField.requestFocus();
}
public String getText() {
return passwordField.getText();
}
public StringProperty textProperty() {
return passwordField.textProperty();

View File

@@ -36,9 +36,6 @@ public interface RecoveryKeyComponent {
@BindsInstance
Builder vault(@RecoveryKeyWindow Vault vault);
@BindsInstance
Builder password(@Nullable CharSequence password);
@BindsInstance
Builder owner(@Named("keyRecoveryOwner") Stage owner);

View File

@@ -1,14 +1,16 @@
package org.cryptomator.ui.recoverykey;
import dagger.Lazy;
import javafx.beans.property.ReadOnlyStringProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.fxml.FXML;
import javafx.scene.Scene;
import javafx.stage.Stage;
import org.cryptomator.common.vaults.Vault;
import org.cryptomator.cryptofs.CryptoFileSystemProvider;
import org.cryptomator.cryptolib.api.InvalidPassphraseException;
import org.cryptomator.ui.common.FxController;
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.slf4j.Logger;
@@ -17,7 +19,6 @@ import org.slf4j.LoggerFactory;
import javax.annotation.Nullable;
import javax.inject.Inject;
import java.io.IOException;
import java.util.Arrays;
import java.util.concurrent.ExecutorService;
@RecoveryKeyScoped
@@ -26,28 +27,21 @@ public class RecoveryKeyCreationController implements FxController {
private static final Logger LOG = LoggerFactory.getLogger(RecoveryKeyCreationController.class);
private final Stage window;
private final Lazy<Scene> successScene;
private final Vault vault;
private final ExecutorService executor;
private final CharSequence prefilledPassword;
private final RecoveryKeyFactory recoveryKeyFactory;
private final StringProperty recoveryKey;
private final StringProperty recoveryKeyProperty;
public NiceSecurePasswordField passwordField;
@Inject
public RecoveryKeyCreationController(@RecoveryKeyWindow Stage window, @RecoveryKeyWindow Vault vault, RecoveryKeyFactory recoveryKeyFactory, ExecutorService executor, @Nullable CharSequence prefilledPassword) {
public RecoveryKeyCreationController(@RecoveryKeyWindow Stage window, @FxmlScene(FxmlFile.RECOVERYKEY_DISPLAY) Lazy<Scene> successScene, @RecoveryKeyWindow Vault vault, RecoveryKeyFactory recoveryKeyFactory, ExecutorService executor, @RecoveryKeyWindow StringProperty recoveryKey) {
this.window = window;
this.successScene = successScene;
this.vault = vault;
this.executor = executor;
this.prefilledPassword = prefilledPassword;
this.recoveryKeyFactory = recoveryKeyFactory;
this.recoveryKey = new SimpleStringProperty();
}
@FXML
public void initialize() {
if (prefilledPassword != null) {
passwordField.setPassword(prefilledPassword);
}
this.recoveryKeyProperty = recoveryKey;
}
@FXML
@@ -55,7 +49,8 @@ public class RecoveryKeyCreationController implements FxController {
Tasks.create(() -> {
return recoveryKeyFactory.createRecoveryKey(vault.getPath(), passwordField.getCharacters());
}).onSuccess(result -> {
recoveryKey.set(result);
recoveryKeyProperty.set(result);
window.setScene(successScene.get());
}).onError(IOException.class, e -> {
LOG.error("Creation of recovery key failed.", e);
}).onError(InvalidPassphraseException.class, e -> {
@@ -67,14 +62,5 @@ public class RecoveryKeyCreationController implements FxController {
public void close() {
window.close();
}
/* Getter/Setter */
public ReadOnlyStringProperty recoveryKeyProperty() {
return recoveryKey;
}
public String getRecoveryKey() {
return recoveryKey.get();
}
}

View File

@@ -0,0 +1,37 @@
package org.cryptomator.ui.recoverykey;
import javafx.beans.property.ReadOnlyStringProperty;
import javafx.beans.property.StringProperty;
import javafx.fxml.FXML;
import javafx.stage.Stage;
import org.cryptomator.ui.common.FxController;
import javax.inject.Inject;
@RecoveryKeyScoped
public class RecoveryKeyDisplayController implements FxController {
private final Stage window;
private final StringProperty recoveryKeyProperty;
@Inject
public RecoveryKeyDisplayController(@RecoveryKeyWindow Stage window, @RecoveryKeyWindow StringProperty recoveryKey) {
this.window = window;
this.recoveryKeyProperty = recoveryKey;
}
@FXML
public void close() {
window.close();
}
/* Getter/Setter */
public ReadOnlyStringProperty recoveryKeyProperty() {
return recoveryKeyProperty;
}
public String getRecoveryKey() {
return recoveryKeyProperty.get();
}
}

View File

@@ -4,6 +4,8 @@ import dagger.Binds;
import dagger.Module;
import dagger.Provides;
import dagger.multibindings.IntoMap;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.stage.Modality;
@@ -43,6 +45,15 @@ abstract class RecoveryKeyModule {
windowIcon.ifPresent(stage.getIcons()::add);
return stage;
}
@Provides
@RecoveryKeyWindow
@RecoveryKeyScoped
static StringProperty provideRecoveryKeyProperty() {
return new SimpleStringProperty();
}
// ------------------
@Provides
@FxmlScene(FxmlFile.RECOVERYKEY_CREATE)
@@ -51,10 +62,23 @@ abstract class RecoveryKeyModule {
return fxmlLoaders.createScene("/fxml/recoverykey_create.fxml");
}
@Provides
@FxmlScene(FxmlFile.RECOVERYKEY_DISPLAY)
@RecoveryKeyScoped
static Scene provideRecoveryKeyDisplayScene(@RecoveryKeyWindow FXMLLoaderFactory fxmlLoaders) {
return fxmlLoaders.createScene("/fxml/recoverykey_display.fxml");
}
// ------------------
@Binds
@IntoMap
@FxControllerKey(RecoveryKeyCreationController.class)
abstract FxController bindRecoveryKeyCreationController(RecoveryKeyCreationController controller);
@Binds
@IntoMap
@FxControllerKey(RecoveryKeyDisplayController.class)
abstract FxController bindRecoveryKeyDisplayController(RecoveryKeyDisplayController controller);
}

View File

@@ -3,13 +3,9 @@
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.ButtonBar?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.layout.StackPane?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.shape.Circle?>
<?import org.cryptomator.ui.controls.FontAwesome5IconView?>
<?import org.cryptomator.ui.controls.NiceSecurePasswordField?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.VBox?>
<?import org.cryptomator.ui.controls.NiceSecurePasswordField?>
<VBox xmlns="http://javafx.com/javafx"
xmlns:fx="http://javafx.com/fxml"
fx:controller="org.cryptomator.ui.recoverykey.RecoveryKeyCreationController"
@@ -22,23 +18,13 @@
<Insets topRightBottomLeft="12"/>
</padding>
<children>
<StackPane alignment="CENTER">
<Circle styleClass="glyph-icon-primary" radius="36"/>
<FontAwesome5IconView styleClass="glyph-icon-white" glyph="CHECK" glyphSize="36"/>
</StackPane>
<HBox>
<NiceSecurePasswordField fx:id="passwordField" HBox.hgrow="ALWAYS"/>
<Button text="TODO create recovery key" onAction="#createRecoveryKey" HBox.hgrow="NEVER"/>
</HBox>
<!-- TODO use TextArea instead -->
<TextField editable="false" text="${controller.recoveryKey}"/>
<NiceSecurePasswordField fx:id="passwordField" HBox.hgrow="ALWAYS"/>
<VBox alignment="BOTTOM_CENTER" VBox.vgrow="ALWAYS">
<ButtonBar buttonMinWidth="120" buttonOrder="+C">
<ButtonBar buttonMinWidth="120" buttonOrder="C+X">
<buttons>
<Button text="%generic.button.done" ButtonBar.buttonData="CANCEL_CLOSE" cancelButton="true" onAction="#close"/>
<Button text="%generic.button.cancel" ButtonBar.buttonData="CANCEL_CLOSE" cancelButton="true" onAction="#close" />
<Button text="%generic.button.next" ButtonBar.buttonData="NEXT_FORWARD" defaultButton="true" onAction="#createRecoveryKey" disable="${passwordField.text.empty}"/>
</buttons>
</ButtonBar>
</VBox>

View File

@@ -0,0 +1,42 @@
<?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.TextField?>
<?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.recoverykey.RecoveryKeyDisplayController"
minWidth="400"
maxWidth="400"
minHeight="145"
spacing="12"
alignment="TOP_CENTER">
<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="CHECK" glyphSize="24"/>
</StackPane>
<!-- TODO use TextArea instead -->
<TextField editable="false" text="${controller.recoveryKey}" HBox.hgrow="ALWAYS"/>
</HBox>
<VBox alignment="BOTTOM_CENTER" VBox.vgrow="ALWAYS">
<ButtonBar buttonMinWidth="120" buttonOrder="+C">
<buttons>
<Button text="%generic.button.done" ButtonBar.buttonData="CANCEL_CLOSE" cancelButton="true" onAction="#close"/>
</buttons>
</ButtonBar>
</VBox>
</children>
</VBox>