mirror of
https://github.com/cryptomator/cryptomator.git
synced 2026-05-18 02:31:27 +00:00
make recovery key ui validation reusable
This commit is contained in:
@@ -140,6 +140,13 @@ abstract class RecoveryKeyModule {
|
||||
@FxControllerKey(RecoveryKeyResetPasswordSuccessController.class)
|
||||
abstract FxController bindRecoveryKeyResetPasswordSuccessController(RecoveryKeyResetPasswordSuccessController controller);
|
||||
|
||||
@Provides
|
||||
@IntoMap
|
||||
@FxControllerKey(RecoveryKeyValidateController.class)
|
||||
static FxController bindRecoveryKeyValidateController(@RecoveryKeyWindow Vault vault, @RecoveryKeyWindow @Nullable VaultConfig.UnverifiedVaultConfig vaultConfig, @RecoveryKeyWindow StringProperty recoveryKey, RecoveryKeyFactory recoveryKeyFactory) {
|
||||
return new RecoveryKeyValidateController(vault, vaultConfig, recoveryKey, recoveryKeyFactory);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@IntoMap
|
||||
@FxControllerKey(NewPasswordController.class)
|
||||
|
||||
@@ -1,14 +1,9 @@
|
||||
package org.cryptomator.ui.recoverykey;
|
||||
|
||||
import com.google.common.base.CharMatcher;
|
||||
import com.google.common.base.Strings;
|
||||
import dagger.Lazy;
|
||||
import org.cryptomator.common.Nullable;
|
||||
import org.cryptomator.common.ObservableUtil;
|
||||
import org.cryptomator.common.vaults.Vault;
|
||||
import org.cryptomator.cryptofs.VaultConfig;
|
||||
import org.cryptomator.cryptofs.VaultConfigLoadException;
|
||||
import org.cryptomator.cryptofs.VaultKeyInvalidException;
|
||||
import org.cryptomator.ui.common.FxController;
|
||||
import org.cryptomator.ui.common.FxmlFile;
|
||||
import org.cryptomator.ui.common.FxmlScene;
|
||||
@@ -16,96 +11,34 @@ import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javafx.beans.property.ObjectProperty;
|
||||
import javafx.beans.property.SimpleObjectProperty;
|
||||
import javafx.beans.Observable;
|
||||
import javafx.beans.property.StringProperty;
|
||||
import javafx.beans.value.ObservableValue;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.scene.control.TextArea;
|
||||
import javafx.scene.control.TextFormatter;
|
||||
import javafx.scene.input.KeyCode;
|
||||
import javafx.scene.input.KeyEvent;
|
||||
import javafx.stage.Stage;
|
||||
import java.util.Optional;
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
@RecoveryKeyScoped
|
||||
public class RecoveryKeyRecoverController implements FxController {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(RecoveryKeyCreationController.class);
|
||||
private static final CharMatcher ALLOWED_CHARS = CharMatcher.inRange('a', 'z').or(CharMatcher.is(' '));
|
||||
|
||||
private final Stage window;
|
||||
private final Vault vault;
|
||||
private final VaultConfig.UnverifiedVaultConfig unverifiedVaultConfig;
|
||||
private final StringProperty recoveryKey;
|
||||
private final ObservableValue<Boolean> recoveryKeyCorrect;
|
||||
private final ObservableValue<Boolean> recoveryKeyWrong;
|
||||
private final ObservableValue<Boolean> recoveryKeyInvalid;
|
||||
private final RecoveryKeyFactory recoveryKeyFactory;
|
||||
private final ObjectProperty<RecoveryKeyState> recoveryKeyState;
|
||||
private final Lazy<Scene> resetPasswordScene;
|
||||
private final AutoCompleter autoCompleter;
|
||||
|
||||
private volatile boolean isWrongKey;
|
||||
|
||||
public TextArea textarea;
|
||||
@FXML
|
||||
RecoveryKeyValidateController recoveryKeyValidateController;
|
||||
|
||||
@Inject
|
||||
public RecoveryKeyRecoverController(@RecoveryKeyWindow Stage window, @RecoveryKeyWindow Vault vault, @RecoveryKeyWindow @Nullable VaultConfig.UnverifiedVaultConfig unverifiedVaultConfig, @RecoveryKeyWindow StringProperty recoveryKey, RecoveryKeyFactory recoveryKeyFactory, @FxmlScene(FxmlFile.RECOVERYKEY_RESET_PASSWORD) Lazy<Scene> resetPasswordScene, ResourceBundle resourceBundle) {
|
||||
public RecoveryKeyRecoverController(@RecoveryKeyWindow Stage window, @RecoveryKeyWindow Vault vault, @RecoveryKeyWindow StringProperty recoveryKey, @FxmlScene(FxmlFile.RECOVERYKEY_RESET_PASSWORD) Lazy<Scene> resetPasswordScene, ResourceBundle resourceBundle) {
|
||||
this.window = window;
|
||||
window.setTitle(resourceBundle.getString("recoveryKey.recover.title"));
|
||||
this.vault = vault;
|
||||
this.unverifiedVaultConfig = unverifiedVaultConfig;
|
||||
this.recoveryKey = recoveryKey;
|
||||
this.recoveryKeyFactory = recoveryKeyFactory;
|
||||
this.resetPasswordScene = resetPasswordScene;
|
||||
this.autoCompleter = new AutoCompleter(recoveryKeyFactory.getDictionary());
|
||||
this.recoveryKeyState = new SimpleObjectProperty<>();
|
||||
this.recoveryKeyCorrect = ObservableUtil.mapWithDefault(recoveryKeyState, RecoveryKeyState.CORRECT::equals, false);
|
||||
this.recoveryKeyWrong = ObservableUtil.mapWithDefault(recoveryKeyState, RecoveryKeyState.WRONG::equals, false);
|
||||
this.recoveryKeyInvalid = ObservableUtil.mapWithDefault(recoveryKeyState, RecoveryKeyState.INVALID::equals, false);
|
||||
}
|
||||
|
||||
@FXML
|
||||
public void initialize() {
|
||||
recoveryKey.bind(textarea.textProperty());
|
||||
textarea.textProperty().addListener(((observable, oldValue, newValue) -> validateRecoveryKey()));
|
||||
}
|
||||
|
||||
private TextFormatter.Change filterTextChange(TextFormatter.Change change) {
|
||||
if (Strings.isNullOrEmpty(change.getText())) {
|
||||
// pass-through caret/selection changes that don't affect the text
|
||||
return change;
|
||||
}
|
||||
if (!ALLOWED_CHARS.matchesAllOf(change.getText())) {
|
||||
return null; // reject change
|
||||
}
|
||||
|
||||
String text = change.getControlNewText();
|
||||
int caretPos = change.getCaretPosition();
|
||||
if (caretPos == text.length() || text.charAt(caretPos) == ' ') { // are we at the end of a word?
|
||||
int beginOfWord = Math.max(text.substring(0, caretPos).lastIndexOf(' ') + 1, 0);
|
||||
String currentWord = text.substring(beginOfWord, caretPos);
|
||||
Optional<String> suggestion = autoCompleter.autocomplete(currentWord);
|
||||
if (suggestion.isPresent()) {
|
||||
String completion = suggestion.get().substring(currentWord.length());
|
||||
change.setText(change.getText() + completion);
|
||||
change.setAnchor(caretPos + completion.length());
|
||||
}
|
||||
}
|
||||
return change;
|
||||
}
|
||||
|
||||
@FXML
|
||||
public void onKeyPressed(KeyEvent keyEvent) {
|
||||
if (keyEvent.getCode() == KeyCode.TAB && textarea.getAnchor() > textarea.getCaretPosition()) {
|
||||
// apply autocompletion:
|
||||
int pos = textarea.getAnchor();
|
||||
textarea.insertText(pos, " ");
|
||||
textarea.positionCaret(pos + 1);
|
||||
}
|
||||
}
|
||||
|
||||
@FXML
|
||||
@@ -118,85 +51,10 @@ public class RecoveryKeyRecoverController implements FxController {
|
||||
window.setScene(resetPasswordScene.get());
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks, if vault config is signed with the given key.
|
||||
*
|
||||
* @param key byte array of possible signing key
|
||||
* @return true, if vault config is signed with this key
|
||||
*/
|
||||
private boolean checkKeyAgainstVaultConfig(byte[] key) {
|
||||
try {
|
||||
var config = unverifiedVaultConfig.verify(key, unverifiedVaultConfig.allegedVaultVersion());
|
||||
LOG.info("Provided recovery key matches vault config signature for vault {}", config.getId());
|
||||
return true;
|
||||
} catch (VaultKeyInvalidException e) {
|
||||
LOG.debug("Provided recovery key does not match vault config signature.");
|
||||
isWrongKey = true;
|
||||
return false;
|
||||
} catch (VaultConfigLoadException e) {
|
||||
LOG.error("Failed to parse vault config", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private void validateRecoveryKey() {
|
||||
isWrongKey = false;
|
||||
var valid = recoveryKeyFactory.validateRecoveryKey(recoveryKey.get(), unverifiedVaultConfig != null ? this::checkKeyAgainstVaultConfig : null);
|
||||
if (valid) {
|
||||
recoveryKeyState.set(RecoveryKeyState.CORRECT);
|
||||
} else if (isWrongKey) { //set via side effect in checkKeyAgainstVaultConfig()
|
||||
recoveryKeyState.set(RecoveryKeyState.WRONG);
|
||||
} else {
|
||||
recoveryKeyState.set(RecoveryKeyState.INVALID);
|
||||
}
|
||||
}
|
||||
|
||||
/* Getter/Setter */
|
||||
|
||||
public Vault getVault() {
|
||||
return vault;
|
||||
public RecoveryKeyValidateController getValidateController() {
|
||||
return recoveryKeyValidateController;
|
||||
}
|
||||
|
||||
public TextFormatter getRecoveryKeyTextFormatter() {
|
||||
return new TextFormatter<>(this::filterTextChange);
|
||||
}
|
||||
|
||||
public ObservableValue<Boolean> recoveryKeyInvalidProperty() {
|
||||
return recoveryKeyInvalid;
|
||||
}
|
||||
|
||||
public boolean isRecoveryKeyInvalid() {
|
||||
return recoveryKeyInvalid.getValue();
|
||||
}
|
||||
|
||||
public ObservableValue<Boolean> recoveryKeyCorrectProperty() {
|
||||
return recoveryKeyCorrect;
|
||||
}
|
||||
|
||||
public boolean isRecoveryKeyCorrect() {
|
||||
return recoveryKeyCorrect.getValue();
|
||||
}
|
||||
|
||||
public ObservableValue<Boolean> recoveryKeyWrongProperty() {
|
||||
return recoveryKeyWrong;
|
||||
}
|
||||
|
||||
public boolean isRecoveryKeyWrong() {
|
||||
return recoveryKeyWrong.getValue();
|
||||
}
|
||||
|
||||
private enum RecoveryKeyState {
|
||||
/**
|
||||
* Recovery key is a valid key and belongs to this vault
|
||||
*/
|
||||
CORRECT,
|
||||
/**
|
||||
* Recovery key is a valid key, but does not belong to this vault
|
||||
*/
|
||||
WRONG,
|
||||
/**
|
||||
* Recovery key is not a valid key.
|
||||
*/
|
||||
INVALID;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,180 @@
|
||||
package org.cryptomator.ui.recoverykey;
|
||||
|
||||
|
||||
import com.google.common.base.CharMatcher;
|
||||
import com.google.common.base.Strings;
|
||||
import org.cryptomator.common.Nullable;
|
||||
import org.cryptomator.common.ObservableUtil;
|
||||
import org.cryptomator.common.vaults.Vault;
|
||||
import org.cryptomator.cryptofs.VaultConfig;
|
||||
import org.cryptomator.cryptofs.VaultConfigLoadException;
|
||||
import org.cryptomator.cryptofs.VaultKeyInvalidException;
|
||||
import org.cryptomator.ui.common.FxController;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javafx.beans.property.ObjectProperty;
|
||||
import javafx.beans.property.SimpleObjectProperty;
|
||||
import javafx.beans.property.StringProperty;
|
||||
import javafx.beans.value.ObservableValue;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.scene.control.TextArea;
|
||||
import javafx.scene.control.TextFormatter;
|
||||
import javafx.scene.input.KeyCode;
|
||||
import javafx.scene.input.KeyEvent;
|
||||
|
||||
public class RecoveryKeyValidateController implements FxController {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(RecoveryKeyCreationController.class);
|
||||
private static final CharMatcher ALLOWED_CHARS = CharMatcher.inRange('a', 'z').or(CharMatcher.is(' '));
|
||||
|
||||
private final Vault vault;
|
||||
private final VaultConfig.UnverifiedVaultConfig unverifiedVaultConfig;
|
||||
private final StringProperty recoveryKey;
|
||||
private final ObservableValue<Boolean> recoveryKeyCorrect;
|
||||
private final ObservableValue<Boolean> recoveryKeyWrong;
|
||||
private final ObservableValue<Boolean> recoveryKeyInvalid;
|
||||
private final RecoveryKeyFactory recoveryKeyFactory;
|
||||
private final ObjectProperty<RecoveryKeyState> recoveryKeyState;
|
||||
private final AutoCompleter autoCompleter;
|
||||
|
||||
private volatile boolean isWrongKey;
|
||||
|
||||
public TextArea textarea;
|
||||
|
||||
public RecoveryKeyValidateController(Vault vault, @Nullable VaultConfig.UnverifiedVaultConfig vaultConfig, StringProperty recoveryKey, RecoveryKeyFactory recoveryKeyFactory) {
|
||||
this.vault = vault;
|
||||
this.unverifiedVaultConfig = vaultConfig;
|
||||
this.recoveryKey = recoveryKey;
|
||||
this.recoveryKeyFactory = recoveryKeyFactory;
|
||||
this.autoCompleter = new AutoCompleter(recoveryKeyFactory.getDictionary());
|
||||
this.recoveryKeyState = new SimpleObjectProperty<>();
|
||||
this.recoveryKeyCorrect = ObservableUtil.mapWithDefault(recoveryKeyState, RecoveryKeyState.CORRECT::equals, false);
|
||||
this.recoveryKeyWrong = ObservableUtil.mapWithDefault(recoveryKeyState, RecoveryKeyState.WRONG::equals, false);
|
||||
this.recoveryKeyInvalid = ObservableUtil.mapWithDefault(recoveryKeyState, RecoveryKeyState.INVALID::equals, false);
|
||||
}
|
||||
|
||||
@FXML
|
||||
public void initialize() {
|
||||
recoveryKey.bind(textarea.textProperty());
|
||||
textarea.textProperty().addListener(((observable, oldValue, newValue) -> validateRecoveryKey()));
|
||||
}
|
||||
|
||||
private TextFormatter.Change filterTextChange(TextFormatter.Change change) {
|
||||
if (Strings.isNullOrEmpty(change.getText())) {
|
||||
// pass-through caret/selection changes that don't affect the text
|
||||
return change;
|
||||
}
|
||||
if (!ALLOWED_CHARS.matchesAllOf(change.getText())) {
|
||||
return null; // reject change
|
||||
}
|
||||
|
||||
String text = change.getControlNewText();
|
||||
int caretPos = change.getCaretPosition();
|
||||
if (caretPos == text.length() || text.charAt(caretPos) == ' ') { // are we at the end of a word?
|
||||
int beginOfWord = Math.max(text.substring(0, caretPos).lastIndexOf(' ') + 1, 0);
|
||||
String currentWord = text.substring(beginOfWord, caretPos);
|
||||
var suggestion = autoCompleter.autocomplete(currentWord);
|
||||
if (suggestion.isPresent()) {
|
||||
String completion = suggestion.get().substring(currentWord.length());
|
||||
change.setText(change.getText() + completion);
|
||||
change.setAnchor(caretPos + completion.length());
|
||||
}
|
||||
}
|
||||
return change;
|
||||
}
|
||||
|
||||
@FXML
|
||||
public void onKeyPressed(KeyEvent keyEvent) {
|
||||
if (keyEvent.getCode() == KeyCode.TAB && textarea.getAnchor() > textarea.getCaretPosition()) {
|
||||
// apply autocompletion:
|
||||
int pos = textarea.getAnchor();
|
||||
textarea.insertText(pos, " ");
|
||||
textarea.positionCaret(pos + 1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks, if vault config is signed with the given key.
|
||||
*
|
||||
* @param key byte array of possible signing key
|
||||
* @return true, if vault config is signed with this key
|
||||
*/
|
||||
private boolean checkKeyAgainstVaultConfig(byte[] key) {
|
||||
assert unverifiedVaultConfig != null;
|
||||
try {
|
||||
var config = unverifiedVaultConfig.verify(key, unverifiedVaultConfig.allegedVaultVersion());
|
||||
LOG.info("Provided recovery key matches vault config signature for vault {}", config.getId());
|
||||
return true;
|
||||
} catch (VaultKeyInvalidException e) {
|
||||
LOG.debug("Provided recovery key does not match vault config signature.");
|
||||
isWrongKey = true;
|
||||
return false;
|
||||
} catch (VaultConfigLoadException e) {
|
||||
LOG.error("Failed to parse vault config", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private void validateRecoveryKey() {
|
||||
isWrongKey = false;
|
||||
var valid = recoveryKeyFactory.validateRecoveryKey(recoveryKey.get(), unverifiedVaultConfig != null ? this::checkKeyAgainstVaultConfig : null);
|
||||
if (valid) {
|
||||
recoveryKeyState.set(RecoveryKeyState.CORRECT);
|
||||
} else if (isWrongKey) { //set via side effect in checkKeyAgainstVaultConfig()
|
||||
recoveryKeyState.set(RecoveryKeyState.WRONG);
|
||||
} else {
|
||||
recoveryKeyState.set(RecoveryKeyState.INVALID);
|
||||
}
|
||||
}
|
||||
|
||||
/* Getter/Setter */
|
||||
|
||||
public Vault getVault() {
|
||||
return vault;
|
||||
}
|
||||
|
||||
public TextFormatter getRecoveryKeyTextFormatter() {
|
||||
return new TextFormatter<>(this::filterTextChange);
|
||||
}
|
||||
|
||||
public ObservableValue<Boolean> recoveryKeyInvalidProperty() {
|
||||
return recoveryKeyInvalid;
|
||||
}
|
||||
|
||||
public boolean isRecoveryKeyInvalid() {
|
||||
return recoveryKeyInvalid.getValue();
|
||||
}
|
||||
|
||||
public ObservableValue<Boolean> recoveryKeyCorrectProperty() {
|
||||
return recoveryKeyCorrect;
|
||||
}
|
||||
|
||||
public boolean isRecoveryKeyCorrect() {
|
||||
return recoveryKeyCorrect.getValue();
|
||||
}
|
||||
|
||||
public ObservableValue<Boolean> recoveryKeyWrongProperty() {
|
||||
return recoveryKeyWrong;
|
||||
}
|
||||
|
||||
public boolean isRecoveryKeyWrong() {
|
||||
return recoveryKeyWrong.getValue();
|
||||
}
|
||||
|
||||
private enum RecoveryKeyState {
|
||||
/**
|
||||
* Recovery key is a valid key and belongs to this vault
|
||||
*/
|
||||
CORRECT,
|
||||
/**
|
||||
* Recovery key is a valid key, but does not belong to this vault
|
||||
*/
|
||||
WRONG,
|
||||
/**
|
||||
* Recovery key is not a valid key.
|
||||
*/
|
||||
INVALID;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,16 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<?import org.cryptomator.ui.controls.FontAwesome5IconView?>
|
||||
<?import org.cryptomator.ui.controls.FormattedLabel?>
|
||||
<?import javafx.geometry.Insets?>
|
||||
<?import javafx.scene.control.Button?>
|
||||
<?import javafx.scene.control.ButtonBar?>
|
||||
<?import javafx.scene.control.Label?>
|
||||
<?import javafx.scene.control.TextArea?>
|
||||
<?import javafx.scene.layout.Region?>
|
||||
<?import javafx.scene.layout.VBox?>
|
||||
<?import javafx.scene.layout.StackPane?>
|
||||
<?import javafx.scene.Group?>
|
||||
<VBox xmlns:fx="http://javafx.com/fxml"
|
||||
xmlns="http://javafx.com/javafx"
|
||||
fx:controller="org.cryptomator.ui.recoverykey.RecoveryKeyRecoverController"
|
||||
@@ -23,32 +17,8 @@
|
||||
<Insets topRightBottomLeft="12"/>
|
||||
</padding>
|
||||
<children>
|
||||
<FormattedLabel format="%recoveryKey.recover.prompt" arg1="${controller.vault.displayName}" wrapText="true"/>
|
||||
|
||||
<TextArea wrapText="true" prefRowCount="4" fx:id="textarea" textFormatter="${controller.recoveryKeyTextFormatter}" onKeyPressed="#onKeyPressed"/>
|
||||
|
||||
<StackPane>
|
||||
<Label text="Just some Filler" visible="false" graphicTextGap="6">
|
||||
<graphic>
|
||||
<FontAwesome5IconView glyph="ANCHOR"/>
|
||||
</graphic>
|
||||
</Label>
|
||||
<Label text="%recoveryKey.recover.correctKey" graphicTextGap="6" contentDisplay="LEFT" visible="${(!textarea.text.empty) && controller.recoveryKeyCorrect}">
|
||||
<graphic>
|
||||
<FontAwesome5IconView glyph="CHECK"/>
|
||||
</graphic>
|
||||
</Label>
|
||||
<Label text="%recoveryKey.recover.wrongKey" graphicTextGap="6" contentDisplay="LEFT" visible="${(!textarea.text.empty) && controller.recoveryKeyWrong}">
|
||||
<graphic>
|
||||
<FontAwesome5IconView glyph="TIMES" styleClass="glyph-icon-red"/>
|
||||
</graphic>
|
||||
</Label>
|
||||
<Label text="%recoveryKey.recover.invalidKey" graphicTextGap="6" contentDisplay="LEFT" visible="${(!textarea.text.empty) && controller.recoveryKeyInvalid}">
|
||||
<graphic>
|
||||
<FontAwesome5IconView glyph="TIMES" styleClass="glyph-icon-red"/>
|
||||
</graphic>
|
||||
</Label>
|
||||
</StackPane>
|
||||
<fx:include fx:id="recoveryKeyValidate" source="recoverykey_validate.fxml"/>
|
||||
|
||||
<Region VBox.vgrow="ALWAYS"/>
|
||||
|
||||
@@ -56,7 +26,7 @@
|
||||
<ButtonBar buttonMinWidth="120" buttonOrder="+CX">
|
||||
<buttons>
|
||||
<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="#recover" disable="${!controller.recoveryKeyCorrect}"/>
|
||||
<Button text="%generic.button.next" ButtonBar.buttonData="NEXT_FORWARD" defaultButton="true" onAction="#recover" disable="${!controller.validateController.recoveryKeyCorrect}"/>
|
||||
</buttons>
|
||||
</ButtonBar>
|
||||
</VBox>
|
||||
|
||||
49
src/main/resources/fxml/recoverykey_validate.fxml
Normal file
49
src/main/resources/fxml/recoverykey_validate.fxml
Normal file
@@ -0,0 +1,49 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<?import org.cryptomator.ui.controls.FontAwesome5IconView?>
|
||||
<?import org.cryptomator.ui.controls.FormattedLabel?>
|
||||
<?import javafx.geometry.Insets?>
|
||||
<?import javafx.scene.control.Label?>
|
||||
<?import javafx.scene.control.TextArea?>
|
||||
<?import javafx.scene.layout.StackPane?>
|
||||
<?import javafx.scene.layout.VBox?>
|
||||
<VBox xmlns:fx="http://javafx.com/fxml"
|
||||
xmlns="http://javafx.com/javafx"
|
||||
fx:controller="org.cryptomator.ui.recoverykey.RecoveryKeyValidateController"
|
||||
minWidth="400"
|
||||
maxWidth="400"
|
||||
minHeight="145"
|
||||
spacing="12"
|
||||
alignment="TOP_CENTER">
|
||||
<padding>
|
||||
<Insets topRightBottomLeft="12"/>
|
||||
</padding>
|
||||
<children>
|
||||
<FormattedLabel format="%recoveryKey.recover.prompt" arg1="${controller.vault.displayName}" wrapText="true"/>
|
||||
|
||||
<TextArea wrapText="true" prefRowCount="4" fx:id="textarea" textFormatter="${controller.recoveryKeyTextFormatter}" onKeyPressed="#onKeyPressed"/>
|
||||
|
||||
<StackPane>
|
||||
<Label text="Just some Filler" visible="false" graphicTextGap="6">
|
||||
<graphic>
|
||||
<FontAwesome5IconView glyph="ANCHOR"/>
|
||||
</graphic>
|
||||
</Label>
|
||||
<Label text="%recoveryKey.recover.correctKey" graphicTextGap="6" contentDisplay="LEFT" visible="${(!textarea.text.empty) && controller.recoveryKeyCorrect}">
|
||||
<graphic>
|
||||
<FontAwesome5IconView glyph="CHECK"/>
|
||||
</graphic>
|
||||
</Label>
|
||||
<Label text="%recoveryKey.recover.wrongKey" graphicTextGap="6" contentDisplay="LEFT" visible="${(!textarea.text.empty) && controller.recoveryKeyWrong}">
|
||||
<graphic>
|
||||
<FontAwesome5IconView glyph="TIMES" styleClass="glyph-icon-red"/>
|
||||
</graphic>
|
||||
</Label>
|
||||
<Label text="%recoveryKey.recover.invalidKey" graphicTextGap="6" contentDisplay="LEFT" visible="${(!textarea.text.empty) && controller.recoveryKeyInvalid}">
|
||||
<graphic>
|
||||
<FontAwesome5IconView glyph="TIMES" styleClass="glyph-icon-red"/>
|
||||
</graphic>
|
||||
</Label>
|
||||
</StackPane>
|
||||
</children>
|
||||
</VBox>
|
||||
@@ -445,7 +445,7 @@ recoveryKey.display.StorageHints=Keep it somewhere very secure, e.g.:\n • Stor
|
||||
## Reset Password
|
||||
### Enter Recovery Key
|
||||
recoveryKey.recover.title=Reset Password
|
||||
recoveryKey.recover.prompt=Enter your recovery key for "%s":
|
||||
recoveryKey.recover.prompt=Enter the recovery key for "%s":
|
||||
recoveryKey.recover.correctKey=This recovery key is correct
|
||||
recoveryKey.recover.wrongKey=This recovery key belongs to a different vault
|
||||
recoveryKey.recover.invalidKey=This recovery key is not valid
|
||||
|
||||
Reference in New Issue
Block a user