mirror of
https://github.com/cryptomator/cryptomator.git
synced 2026-04-21 10:06:55 -04:00
Merge pull request #2686 from cryptomator/feature/recovery-key-wrong-key
Display message if recovery key is not valid
This commit is contained in:
@@ -4,6 +4,7 @@ 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;
|
||||
@@ -15,9 +16,10 @@ import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javafx.beans.binding.Bindings;
|
||||
import javafx.beans.binding.BooleanBinding;
|
||||
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.Scene;
|
||||
import javafx.scene.control.TextArea;
|
||||
@@ -38,11 +40,16 @@ public class RecoveryKeyRecoverController implements FxController {
|
||||
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 BooleanBinding validRecoveryKey;
|
||||
private final ObjectProperty<RecoveryKeyState> recoveryKeyState;
|
||||
private final Lazy<Scene> resetPasswordScene;
|
||||
private final AutoCompleter autoCompleter;
|
||||
|
||||
private volatile boolean isWrongKey;
|
||||
|
||||
public TextArea textarea;
|
||||
|
||||
@Inject
|
||||
@@ -53,14 +60,18 @@ public class RecoveryKeyRecoverController implements FxController {
|
||||
this.unverifiedVaultConfig = unverifiedVaultConfig;
|
||||
this.recoveryKey = recoveryKey;
|
||||
this.recoveryKeyFactory = recoveryKeyFactory;
|
||||
this.validRecoveryKey = Bindings.createBooleanBinding(this::isValidRecoveryKey, recoveryKey);
|
||||
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) {
|
||||
@@ -107,6 +118,12 @@ 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());
|
||||
@@ -114,6 +131,7 @@ public class RecoveryKeyRecoverController implements FxController {
|
||||
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);
|
||||
@@ -121,25 +139,64 @@ public class RecoveryKeyRecoverController implements FxController {
|
||||
}
|
||||
}
|
||||
|
||||
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 BooleanBinding validRecoveryKeyProperty() {
|
||||
return validRecoveryKey;
|
||||
}
|
||||
|
||||
public boolean isValidRecoveryKey() {
|
||||
if (unverifiedVaultConfig != null) {
|
||||
return recoveryKeyFactory.validateRecoveryKey(recoveryKey.get(), this::checkKeyAgainstVaultConfig);
|
||||
} else {
|
||||
return recoveryKeyFactory.validateRecoveryKey(recoveryKey.get());
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,8 @@
|
||||
<?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"
|
||||
@@ -25,12 +27,28 @@
|
||||
|
||||
<TextArea wrapText="true" prefRowCount="4" fx:id="textarea" textFormatter="${controller.recoveryKeyTextFormatter}" onKeyPressed="#onKeyPressed"/>
|
||||
|
||||
<!-- TODO: add Label when the recovery key is not valid -->
|
||||
<Label text="%recoveryKey.recover.validKey" graphicTextGap="6" contentDisplay="LEFT" visible="${controller.validRecoveryKey}">
|
||||
<graphic>
|
||||
<FontAwesome5IconView glyph="CHECK"/>
|
||||
</graphic>
|
||||
</Label>
|
||||
<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>
|
||||
|
||||
<Region VBox.vgrow="ALWAYS"/>
|
||||
|
||||
@@ -38,7 +56,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.validRecoveryKey}"/>
|
||||
<Button text="%generic.button.next" ButtonBar.buttonData="NEXT_FORWARD" defaultButton="true" onAction="#recover" disable="${!controller.recoveryKeyCorrect}"/>
|
||||
</buttons>
|
||||
</ButtonBar>
|
||||
</VBox>
|
||||
|
||||
@@ -447,7 +447,9 @@ recoveryKey.display.StorageHints=Keep it somewhere very secure, e.g.:\n • Stor
|
||||
### Enter Recovery Key
|
||||
recoveryKey.recover.title=Reset Password
|
||||
recoveryKey.recover.prompt=Enter your recovery key for "%s":
|
||||
recoveryKey.recover.validKey=This is a valid recovery key
|
||||
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
|
||||
recoveryKey.printout.heading=Cryptomator Recovery Key\n"%s"\n
|
||||
### Reset Password
|
||||
recoveryKey.recover.resetBtn=Reset
|
||||
|
||||
Reference in New Issue
Block a user