|
@@ -3,24 +3,30 @@ package org.cryptomator.ui.addvaultwizard;
|
|
|
import dagger.Lazy;
|
|
|
import javafx.beans.binding.Bindings;
|
|
|
import javafx.beans.binding.BooleanBinding;
|
|
|
+import javafx.beans.binding.ObjectBinding;
|
|
|
+import javafx.beans.property.BooleanProperty;
|
|
|
import javafx.beans.property.IntegerProperty;
|
|
|
import javafx.beans.property.ObjectProperty;
|
|
|
+import javafx.beans.property.SimpleBooleanProperty;
|
|
|
import javafx.beans.property.SimpleIntegerProperty;
|
|
|
import javafx.beans.property.StringProperty;
|
|
|
import javafx.collections.ObservableList;
|
|
|
import javafx.fxml.FXML;
|
|
|
import javafx.scene.Scene;
|
|
|
-import javafx.scene.control.Button;
|
|
|
import javafx.scene.control.CheckBox;
|
|
|
+import javafx.scene.control.ContentDisplay;
|
|
|
import javafx.scene.control.Label;
|
|
|
import javafx.scene.layout.HBox;
|
|
|
import javafx.stage.Stage;
|
|
|
import org.cryptomator.common.settings.VaultSettings;
|
|
|
import org.cryptomator.common.vaults.Vault;
|
|
|
import org.cryptomator.common.vaults.VaultFactory;
|
|
|
+import org.cryptomator.cryptofs.CryptoFileSystemProperties;
|
|
|
+import org.cryptomator.cryptofs.CryptoFileSystemProvider;
|
|
|
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.FontAwesome5IconView;
|
|
|
import org.cryptomator.ui.controls.SecPasswordField;
|
|
|
import org.cryptomator.ui.util.PasswordStrengthUtil;
|
|
@@ -30,23 +36,28 @@ import org.slf4j.LoggerFactory;
|
|
|
|
|
|
import javax.inject.Inject;
|
|
|
import java.io.IOException;
|
|
|
-import java.nio.ByteBuffer;
|
|
|
import java.nio.channels.WritableByteChannel;
|
|
|
-import java.nio.charset.StandardCharsets;
|
|
|
import java.nio.file.FileAlreadyExistsException;
|
|
|
+import java.nio.file.FileSystem;
|
|
|
import java.nio.file.Files;
|
|
|
import java.nio.file.Path;
|
|
|
import java.nio.file.StandardOpenOption;
|
|
|
+import java.util.Collections;
|
|
|
import java.util.ResourceBundle;
|
|
|
+import java.util.concurrent.ExecutorService;
|
|
|
+
|
|
|
+import static java.nio.charset.StandardCharsets.US_ASCII;
|
|
|
|
|
|
@AddVaultWizardScoped
|
|
|
public class CreateNewVaultPasswordController implements FxController {
|
|
|
|
|
|
private static final Logger LOG = LoggerFactory.getLogger(CreateNewVaultPasswordController.class);
|
|
|
+ private static final String MASTERKEY_FILENAME = "masterkey.cryptomator";
|
|
|
|
|
|
private final Stage window;
|
|
|
private final Lazy<Scene> chooseLocationScene;
|
|
|
private final Lazy<Scene> successScene;
|
|
|
+ private final ExecutorService executor;
|
|
|
private final StringProperty vaultName;
|
|
|
private final ObjectProperty<Path> vaultPath;
|
|
|
private final ObservableList<Vault> vaults;
|
|
@@ -56,8 +67,10 @@ public class CreateNewVaultPasswordController implements FxController {
|
|
|
private final PasswordStrengthUtil strengthRater;
|
|
|
private final ReadmeGenerator readmeGenerator;
|
|
|
private final IntegerProperty passwordStrength;
|
|
|
+ private final BooleanProperty processing;
|
|
|
+ private final BooleanProperty readyToCreateVault;
|
|
|
+ private final ObjectBinding<ContentDisplay> createVaultButtonState;
|
|
|
|
|
|
- public Button finishButton;
|
|
|
public SecPasswordField passwordField;
|
|
|
public SecPasswordField reenterField;
|
|
|
public Label passwordStrengthLabel;
|
|
@@ -68,10 +81,11 @@ public class CreateNewVaultPasswordController implements FxController {
|
|
|
public CheckBox finalConfirmationCheckbox;
|
|
|
|
|
|
@Inject
|
|
|
- CreateNewVaultPasswordController(@AddVaultWizard Stage window, @FxmlScene(FxmlFile.ADDVAULT_NEW_LOCATION) Lazy<Scene> chooseLocationScene, @FxmlScene(FxmlFile.ADDVAULT_SUCCESS) Lazy<Scene> successScene, StringProperty vaultName, ObjectProperty<Path> vaultPath, ObservableList<Vault> vaults, @AddVaultWizard ObjectProperty<Vault> vault, VaultFactory vaultFactory, ResourceBundle resourceBundle, PasswordStrengthUtil strengthRater, ReadmeGenerator readmeGenerator) {
|
|
|
+ CreateNewVaultPasswordController(@AddVaultWizard Stage window, @FxmlScene(FxmlFile.ADDVAULT_NEW_LOCATION) Lazy<Scene> chooseLocationScene, @FxmlScene(FxmlFile.ADDVAULT_SUCCESS) Lazy<Scene> successScene, ExecutorService executor, StringProperty vaultName, ObjectProperty<Path> vaultPath, ObservableList<Vault> vaults, @AddVaultWizard ObjectProperty<Vault> vault, VaultFactory vaultFactory, ResourceBundle resourceBundle, PasswordStrengthUtil strengthRater, ReadmeGenerator readmeGenerator) {
|
|
|
this.window = window;
|
|
|
this.chooseLocationScene = chooseLocationScene;
|
|
|
this.successScene = successScene;
|
|
|
+ this.executor = executor;
|
|
|
this.vaultName = vaultName;
|
|
|
this.vaultPath = vaultPath;
|
|
|
this.vaults = vaults;
|
|
@@ -81,6 +95,9 @@ public class CreateNewVaultPasswordController implements FxController {
|
|
|
this.strengthRater = strengthRater;
|
|
|
this.readmeGenerator = readmeGenerator;
|
|
|
this.passwordStrength = new SimpleIntegerProperty(-1);
|
|
|
+ this.processing = new SimpleBooleanProperty();
|
|
|
+ this.readyToCreateVault = new SimpleBooleanProperty();
|
|
|
+ this.createVaultButtonState = Bindings.createObjectBinding(this::getCreateVaultButtonState, processing);
|
|
|
}
|
|
|
|
|
|
@FXML
|
|
@@ -90,8 +107,7 @@ public class CreateNewVaultPasswordController implements FxController {
|
|
|
//binding indicating if the passwords not match
|
|
|
BooleanBinding passwordsMatch = Bindings.createBooleanBinding(() -> CharSequence.compare(passwordField.getCharacters(), reenterField.getCharacters()) == 0, passwordField.textProperty(), reenterField.textProperty());
|
|
|
BooleanBinding reenterFieldNotEmpty = reenterField.textProperty().isNotEmpty();
|
|
|
- //disable the finish button when passwords do not match or one is empty
|
|
|
- finishButton.disableProperty().bind(reenterFieldNotEmpty.not().or(passwordsMatch.not()).or(finalConfirmationCheckbox.selectedProperty().not()));
|
|
|
+ readyToCreateVault.bind(reenterFieldNotEmpty.and(passwordsMatch).and(finalConfirmationCheckbox.selectedProperty()).and(processing.not()));
|
|
|
//make match indicator invisible when passwords do not match or one is empty
|
|
|
passwordMatchBox.visibleProperty().bind(reenterFieldNotEmpty);
|
|
|
checkmark.visibleProperty().bind(passwordsMatch.and(reenterFieldNotEmpty));
|
|
@@ -111,35 +127,53 @@ public class CreateNewVaultPasswordController implements FxController {
|
|
|
|
|
|
@FXML
|
|
|
public void next() {
|
|
|
- VaultSettings vaultSettings = VaultSettings.withRandomId();
|
|
|
- vaultSettings.path().setValue(vaultPath.get());
|
|
|
- Vault newVault = vaultFactory.get(vaultSettings);
|
|
|
try {
|
|
|
- Files.createDirectory(vaultSettings.path().get());
|
|
|
+ Files.createDirectory(vaultPath.get());
|
|
|
} catch (FileAlreadyExistsException e) {
|
|
|
- // TODO show specific error screen
|
|
|
- LOG.error("", e);
|
|
|
+ LOG.error("Vault dir already exists.", e);
|
|
|
+ window.setScene(chooseLocationScene.get());
|
|
|
} catch (IOException e) {
|
|
|
// TODO show generic error screen
|
|
|
LOG.error("", e);
|
|
|
}
|
|
|
- try {
|
|
|
- newVault.create(passwordField.getCharacters());
|
|
|
- LOG.info("Created new vault at path {}", vaultPath.get());
|
|
|
- String readmeFileName = resourceBundle.getString("addvault.new.readme.storageLocation.fileName");
|
|
|
- Path readmeFile = vaultPath.get().resolve(readmeFileName);
|
|
|
- try (WritableByteChannel ch = Files.newByteChannel(readmeFile, StandardOpenOption.CREATE_NEW, StandardOpenOption.WRITE)) {
|
|
|
- ByteBuffer buf = StandardCharsets.US_ASCII.encode(readmeGenerator.createVaultStorageLocationReadmeRtf());
|
|
|
- ch.write(buf);
|
|
|
- }
|
|
|
- LOG.info("Created readme file {}", readmeFile);
|
|
|
+
|
|
|
+ processing.set(true);
|
|
|
+ Tasks.create(() -> {
|
|
|
+ initializeVault(vaultPath.get(), passwordField.getCharacters());
|
|
|
+ }).onSuccess(() -> {
|
|
|
+ VaultSettings vaultSettings = VaultSettings.withRandomId();
|
|
|
+ vaultSettings.path().setValue(vaultPath.get());
|
|
|
+ Vault newVault = vaultFactory.get(vaultSettings);
|
|
|
vault.set(newVault);
|
|
|
vaults.add(newVault);
|
|
|
window.setScene(successScene.get());
|
|
|
- } catch (IOException e) {
|
|
|
+ }).onError(IOException.class, e -> {
|
|
|
// TODO show generic error screen
|
|
|
LOG.error("", e);
|
|
|
+ }).andFinally(() -> {
|
|
|
+ processing.set(false);
|
|
|
+ }).runOnce(executor);
|
|
|
+ }
|
|
|
+
|
|
|
+ private void initializeVault(Path path, CharSequence passphrase) throws IOException {
|
|
|
+ CryptoFileSystemProvider.initialize(path, MASTERKEY_FILENAME, passphrase);
|
|
|
+ CryptoFileSystemProperties fsProps = CryptoFileSystemProperties.cryptoFileSystemProperties() //
|
|
|
+ .withPassphrase(passphrase) //
|
|
|
+ .withFlags(Collections.emptySet()) //
|
|
|
+ .withMasterkeyFilename(MASTERKEY_FILENAME) //
|
|
|
+ .build();
|
|
|
+
|
|
|
+ String vaultReadmeFileName = resourceBundle.getString("addvault.new.readme.accessLocation.fileName");
|
|
|
+ try (FileSystem fs = CryptoFileSystemProvider.newFileSystem(path, fsProps); //
|
|
|
+ WritableByteChannel ch = Files.newByteChannel(fs.getPath("/", vaultReadmeFileName), StandardOpenOption.CREATE_NEW, StandardOpenOption.WRITE)) {
|
|
|
+ ch.write(US_ASCII.encode(readmeGenerator.createVaultAccessLocationReadmeRtf()));
|
|
|
+ }
|
|
|
+
|
|
|
+ String storagePathReadmeFileName = resourceBundle.getString("addvault.new.readme.storageLocation.fileName");
|
|
|
+ try (WritableByteChannel ch = Files.newByteChannel(path.resolve(storagePathReadmeFileName), StandardOpenOption.CREATE_NEW, StandardOpenOption.WRITE)) {
|
|
|
+ ch.write(US_ASCII.encode(readmeGenerator.createVaultStorageLocationReadmeRtf()));
|
|
|
}
|
|
|
+ LOG.info("Created vault at {}", path);
|
|
|
}
|
|
|
|
|
|
/* Getter/Setter */
|
|
@@ -159,4 +193,20 @@ public class CreateNewVaultPasswordController implements FxController {
|
|
|
public int getPasswordStrength() {
|
|
|
return passwordStrength.get();
|
|
|
}
|
|
|
+
|
|
|
+ public BooleanProperty readyToCreateVaultProperty() {
|
|
|
+ return readyToCreateVault;
|
|
|
+ }
|
|
|
+
|
|
|
+ public boolean isReadyToCreateVault() {
|
|
|
+ return readyToCreateVault.get();
|
|
|
+ }
|
|
|
+
|
|
|
+ public ObjectBinding<ContentDisplay> createVaultButtonStateProperty() {
|
|
|
+ return createVaultButtonState;
|
|
|
+ }
|
|
|
+
|
|
|
+ public ContentDisplay getCreateVaultButtonState() {
|
|
|
+ return processing.get() ? ContentDisplay.LEFT : ContentDisplay.TEXT_ONLY;
|
|
|
+ }
|
|
|
}
|