mirror of
https://github.com/cryptomator/cryptomator.git
synced 2026-05-22 12:41:27 +00:00
Added first prototyp for recovery key generation
This commit is contained in:
@@ -24,8 +24,7 @@
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
|
||||
<!-- dependency versions -->
|
||||
<cryptomator.cryptolib.version>1.2.2</cryptomator.cryptolib.version>
|
||||
<cryptomator.cryptofs.version>1.9.0-beta1</cryptomator.cryptofs.version>
|
||||
<cryptomator.cryptofs.version>1.9.0-beta2</cryptomator.cryptofs.version>
|
||||
<cryptomator.jni.version>2.2.1</cryptomator.jni.version>
|
||||
<cryptomator.fuse.version>1.2.0</cryptomator.fuse.version>
|
||||
<cryptomator.dokany.version>1.1.11</cryptomator.dokany.version>
|
||||
@@ -82,11 +81,6 @@
|
||||
</dependency>
|
||||
|
||||
<!-- Cryptomator Libs -->
|
||||
<dependency>
|
||||
<groupId>org.cryptomator</groupId>
|
||||
<artifactId>cryptolib</artifactId>
|
||||
<version>${cryptomator.cryptolib.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.cryptomator</groupId>
|
||||
<artifactId>cryptofs</artifactId>
|
||||
|
||||
@@ -22,10 +22,6 @@
|
||||
<groupId>org.cryptomator</groupId>
|
||||
<artifactId>jni</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.cryptomator</groupId>
|
||||
<artifactId>cryptolib</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- JavaFx -->
|
||||
<dependency>
|
||||
|
||||
@@ -15,6 +15,7 @@ public enum FxmlFile {
|
||||
MIGRATION_SUCCESS("/fxml/migration_success.fxml"), //
|
||||
PREFERENCES("/fxml/preferences.fxml"), //
|
||||
QUIT("/fxml/quit.fxml"), //
|
||||
RECOVERYKEY_CREATE("/fxml/recoverykey_create.fxml"), //
|
||||
REMOVE_VAULT("/fxml/remove_vault.fxml"), //
|
||||
UNLOCK("/fxml/unlock.fxml"),
|
||||
UNLOCK_SUCCESS("/fxml/unlock_success.fxml"), //
|
||||
|
||||
@@ -76,6 +76,10 @@ public class NiceSecurePasswordField extends StackPane {
|
||||
return passwordField.getCharacters();
|
||||
}
|
||||
|
||||
public void setPassword(CharSequence password) {
|
||||
passwordField.setPassword(password);
|
||||
}
|
||||
|
||||
public void setPassword(char[] password) {
|
||||
passwordField.setPassword(password);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
package org.cryptomator.ui.recoverykey;
|
||||
|
||||
import dagger.BindsInstance;
|
||||
import dagger.Lazy;
|
||||
import dagger.Subcomponent;
|
||||
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.annotation.Nullable;
|
||||
import javax.inject.Named;
|
||||
import java.util.Optional;
|
||||
|
||||
@RecoveryKeyScoped
|
||||
@Subcomponent(modules = {RecoveryKeyModule.class})
|
||||
public interface RecoveryKeyComponent {
|
||||
|
||||
@RecoveryKeyWindow
|
||||
Stage window();
|
||||
|
||||
@FxmlScene(FxmlFile.RECOVERYKEY_CREATE)
|
||||
Lazy<Scene> scene();
|
||||
|
||||
default void showRecoveryKeyCreationWindow() {
|
||||
Stage stage = window();
|
||||
stage.setScene(scene().get());
|
||||
stage.sizeToScene();
|
||||
stage.show();
|
||||
}
|
||||
|
||||
@Subcomponent.Builder
|
||||
interface Builder {
|
||||
|
||||
@BindsInstance
|
||||
Builder vault(@RecoveryKeyWindow Vault vault);
|
||||
|
||||
@BindsInstance
|
||||
Builder password(@Nullable CharSequence password);
|
||||
|
||||
@BindsInstance
|
||||
Builder owner(@Named("keyRecoveryOwner") Stage owner);
|
||||
|
||||
RecoveryKeyComponent build();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
package org.cryptomator.ui.recoverykey;
|
||||
|
||||
import javafx.beans.property.ReadOnlyStringProperty;
|
||||
import javafx.beans.property.SimpleStringProperty;
|
||||
import javafx.beans.property.StringProperty;
|
||||
import javafx.fxml.FXML;
|
||||
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.Tasks;
|
||||
import org.cryptomator.ui.controls.NiceSecurePasswordField;
|
||||
import org.slf4j.Logger;
|
||||
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
|
||||
public class RecoveryKeyCreationController implements FxController {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(RecoveryKeyCreationController.class);
|
||||
private static final String MASTERKEY_FILENAME = "masterkey.cryptomator"; // TODO: deduplicate constant declared in multiple classes
|
||||
|
||||
private final Stage window;
|
||||
private final Vault vault;
|
||||
private final ExecutorService executor;
|
||||
private final CharSequence prefilledPassword;
|
||||
private final WordEncoder wordEncoder;
|
||||
private final StringProperty recoveryKey;
|
||||
public NiceSecurePasswordField passwordField;
|
||||
|
||||
@Inject
|
||||
public RecoveryKeyCreationController(@RecoveryKeyWindow Stage window, @RecoveryKeyWindow Vault vault, ExecutorService executor, @Nullable CharSequence prefilledPassword) {
|
||||
this.window = window;
|
||||
this.vault = vault;
|
||||
this.executor = executor;
|
||||
this.prefilledPassword = prefilledPassword;
|
||||
this.wordEncoder = new WordEncoder();
|
||||
this.recoveryKey = new SimpleStringProperty();
|
||||
}
|
||||
|
||||
@FXML
|
||||
public void initialize() {
|
||||
if (prefilledPassword != null) {
|
||||
passwordField.setPassword(prefilledPassword);
|
||||
}
|
||||
}
|
||||
|
||||
@FXML
|
||||
public void createRecoveryKey() {
|
||||
Tasks.create(() -> {
|
||||
byte[] rawKey = CryptoFileSystemProvider.exportRawKey(vault.getPath(), MASTERKEY_FILENAME, new byte[0], passwordField.getCharacters());
|
||||
assert rawKey.length == 64;
|
||||
byte[] paddedKey = Arrays.copyOf(rawKey, 66);
|
||||
// TODO add two-byte CRC
|
||||
|
||||
try {
|
||||
return wordEncoder.encodePadded(paddedKey);
|
||||
} finally {
|
||||
Arrays.fill(rawKey, (byte) 0x00);
|
||||
Arrays.fill(paddedKey, (byte) 0x00);
|
||||
}
|
||||
}).onSuccess(result -> {
|
||||
recoveryKey.set(result);
|
||||
}).onError(IOException.class, e -> {
|
||||
LOG.error("Creation of recovery key failed.", e);
|
||||
}).onError(InvalidPassphraseException.class, e -> {
|
||||
// TODO shake animation? :D
|
||||
}).runOnce(executor);
|
||||
}
|
||||
|
||||
@FXML
|
||||
public void close() {
|
||||
window.close();
|
||||
}
|
||||
|
||||
/* Getter/Setter */
|
||||
|
||||
public ReadOnlyStringProperty recoveryKeyProperty() {
|
||||
return recoveryKey;
|
||||
}
|
||||
|
||||
public String getRecoveryKey() {
|
||||
return recoveryKey.get();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
package org.cryptomator.ui.recoverykey;
|
||||
|
||||
import dagger.Binds;
|
||||
import dagger.Module;
|
||||
import dagger.Provides;
|
||||
import dagger.multibindings.IntoMap;
|
||||
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 RecoveryKeyModule {
|
||||
|
||||
@Provides
|
||||
@RecoveryKeyWindow
|
||||
@RecoveryKeyScoped
|
||||
static FXMLLoaderFactory provideFxmlLoaderFactory(Map<Class<? extends FxController>, Provider<FxController>> factories, ResourceBundle resourceBundle) {
|
||||
return new FXMLLoaderFactory(factories, resourceBundle);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@RecoveryKeyWindow
|
||||
@RecoveryKeyScoped
|
||||
static Stage provideStage(ResourceBundle resourceBundle, @Named("windowIcon") Optional<Image> windowIcon, @Named("keyRecoveryOwner") Stage owner) {
|
||||
Stage stage = new Stage();
|
||||
stage.setTitle("TODO keyRecovery.title"); // TODO localize
|
||||
stage.setResizable(false);
|
||||
stage.initModality(Modality.WINDOW_MODAL);
|
||||
stage.initOwner(owner);
|
||||
windowIcon.ifPresent(stage.getIcons()::add);
|
||||
return stage;
|
||||
}
|
||||
|
||||
@Provides
|
||||
@FxmlScene(FxmlFile.RECOVERYKEY_CREATE)
|
||||
@RecoveryKeyScoped
|
||||
static Scene provideRecoveryKeyCreationScene(@RecoveryKeyWindow FXMLLoaderFactory fxmlLoaders, @RecoveryKeyWindow Stage window) {
|
||||
return fxmlLoaders.createScene("/fxml/recoverykey_create.fxml");
|
||||
}
|
||||
|
||||
// ------------------
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@FxControllerKey(RecoveryKeyCreationController.class)
|
||||
abstract FxController bindRecoveryKeyCreationController(RecoveryKeyCreationController controller);
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package org.cryptomator.ui.recoverykey;
|
||||
|
||||
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 RecoveryKeyScoped {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package org.cryptomator.ui.recoverykey;
|
||||
|
||||
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)
|
||||
@interface RecoveryKeyWindow {
|
||||
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package org.cryptomator.ui.keyrecovery;
|
||||
package org.cryptomator.ui.recoverykey;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.base.Splitter;
|
||||
@@ -5,6 +5,7 @@ import javafx.stage.Stage;
|
||||
import org.cryptomator.common.vaults.Vault;
|
||||
import org.cryptomator.ui.changepassword.ChangePasswordComponent;
|
||||
import org.cryptomator.ui.common.FxController;
|
||||
import org.cryptomator.ui.recoverykey.RecoveryKeyComponent;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
@@ -14,12 +15,14 @@ public class GeneralVaultOptionsController implements FxController {
|
||||
private final Vault vault;
|
||||
private final Stage window;
|
||||
private final ChangePasswordComponent.Builder changePasswordWindow;
|
||||
private final RecoveryKeyComponent.Builder recoveryKeyWindow;
|
||||
|
||||
@Inject
|
||||
GeneralVaultOptionsController(@VaultOptionsWindow Vault vault, @VaultOptionsWindow Stage window, ChangePasswordComponent.Builder changePasswordWindow) {
|
||||
GeneralVaultOptionsController(@VaultOptionsWindow Vault vault, @VaultOptionsWindow Stage window, ChangePasswordComponent.Builder changePasswordWindow, RecoveryKeyComponent.Builder recoveryKeyWindow) {
|
||||
this.vault = vault;
|
||||
this.window = window;
|
||||
this.changePasswordWindow = changePasswordWindow;
|
||||
this.recoveryKeyWindow = recoveryKeyWindow;
|
||||
}
|
||||
|
||||
@FXML
|
||||
@@ -27,4 +30,9 @@ public class GeneralVaultOptionsController implements FxController {
|
||||
changePasswordWindow.vault(vault).owner(window).build().showChangePasswordWindow();
|
||||
}
|
||||
|
||||
@FXML
|
||||
public void showRecoveryKey() {
|
||||
recoveryKeyWindow.vault(vault).owner(window).build().showRecoveryKeyCreationWindow();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ import org.cryptomator.ui.common.FxControllerKey;
|
||||
import org.cryptomator.ui.common.FxmlFile;
|
||||
import org.cryptomator.ui.common.FxmlScene;
|
||||
import org.cryptomator.ui.mainwindow.MainWindow;
|
||||
import org.cryptomator.ui.recoverykey.RecoveryKeyComponent;
|
||||
|
||||
import javax.inject.Named;
|
||||
import javax.inject.Provider;
|
||||
@@ -27,7 +28,7 @@ import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
@Module(subcomponents = {ChangePasswordComponent.class})
|
||||
@Module(subcomponents = {ChangePasswordComponent.class, RecoveryKeyComponent.class})
|
||||
abstract class VaultOptionsModule {
|
||||
|
||||
@Provides
|
||||
|
||||
46
main/ui/src/main/resources/fxml/recoverykey_create.fxml
Normal file
46
main/ui/src/main/resources/fxml/recoverykey_create.fxml
Normal file
@@ -0,0 +1,46 @@
|
||||
<?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.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?>
|
||||
<VBox xmlns="http://javafx.com/javafx"
|
||||
xmlns:fx="http://javafx.com/fxml"
|
||||
fx:controller="org.cryptomator.ui.recoverykey.RecoveryKeyCreationController"
|
||||
minWidth="400"
|
||||
maxWidth="400"
|
||||
minHeight="145"
|
||||
spacing="12"
|
||||
alignment="TOP_CENTER">
|
||||
<padding>
|
||||
<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}"/>
|
||||
|
||||
<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>
|
||||
@@ -12,5 +12,6 @@
|
||||
</padding>
|
||||
<children>
|
||||
<Button text="%vaultOptions.general.changePasswordBtn" onAction="#changePassword"/>
|
||||
<Button text="TODO show recovery key" onAction="#showRecoveryKey"/>
|
||||
</children>
|
||||
</VBox>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package org.cryptomator.ui.keyrecovery;
|
||||
package org.cryptomator.ui.recoverykey;
|
||||
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
Reference in New Issue
Block a user