Added access location readme file

This commit is contained in:
Sebastian Stenzel
2019-08-30 10:59:37 +02:00
parent 33252c1775
commit 88220cabee
4 changed files with 94 additions and 26 deletions

View File

@@ -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;
}
}

View File

@@ -27,6 +27,14 @@ public class ReadmeGenerator {
String.format(resourceBundle.getString("addvault.new.readme.storageLocation.4"), HELP_URL) //
));
}
public String createVaultAccessLocationReadmeRtf() {
return createDocument(List.of( //
resourceBundle.getString("addvault.new.readme.accessLocation.1"), //
resourceBundle.getString("addvault.new.readme.accessLocation.2"), //
resourceBundle.getString("addvault.new.readme.accessLocation.3") //
));
}
// visible for testing
String createDocument(Iterable<String> paragraphs) {

View File

@@ -11,6 +11,7 @@
<?import org.cryptomator.ui.controls.FontAwesome5IconView?>
<?import org.cryptomator.ui.controls.PasswordStrengthIndicator?>
<?import org.cryptomator.ui.controls.SecPasswordField?>
<?import javafx.scene.control.ProgressIndicator?>
<VBox xmlns="http://javafx.com/javafx"
xmlns:fx="http://javafx.com/fxml"
fx:controller="org.cryptomator.ui.addvaultwizard.CreateNewVaultPasswordController"
@@ -50,7 +51,11 @@
<ButtonBar buttonMinWidth="120" buttonOrder="B+X">
<buttons>
<Button text="%generic.button.back" ButtonBar.buttonData="BACK_PREVIOUS" onAction="#back"/>
<Button fx:id="finishButton" text="%generic.button.next" ButtonBar.buttonData="NEXT_FORWARD" onAction="#next" defaultButton="true"/>
<Button text="%generic.button.next" ButtonBar.buttonData="NEXT_FORWARD" onAction="#next" defaultButton="true" disable="${!controller.readyToCreateVault}" contentDisplay="${controller.createVaultButtonState}" >
<graphic>
<ProgressIndicator progress="-1" prefWidth="12" prefHeight="12"/>
</graphic>
</Button>
</buttons>
</ButtonBar>
</children>

View File

@@ -39,10 +39,15 @@ addvaultwizard.new.passwordsMatch=Passwords match!
addvaultwizard.new.passwordsDoNotMatch=Passwords do not match
addvaultwizard.new.finalConfirmation=I understand that I will not be able to recover my data if I forget my password
addvault.new.readme.storageLocation.fileName=WHAT IS THIS DIRECTORY.rtf
addvault.new.readme.storageLocation.1=\\fs40\\qc ⚠️ VAULT FILES ⚠️
addvault.new.readme.storageLocation.1=\\fs40\\qc ⚠️ VAULT FILES ⚠️
addvault.new.readme.storageLocation.2=This is your vault's storage location. {\\b DO NOT} alter any files within this directory.
addvault.new.readme.storageLocation.3=If you want to encrypt files using Cryptomator, unlock the vault and use the provided drive.
addvault.new.readme.storageLocation.4=If you need help, try %s.
addvault.new.readme.accessLocation.fileName=WELCOME TO YOUR VAULT.rtf
addvault.new.readme.accessLocation.1=\\fs40\\qc 🔐️ ENCRYPTED VOLUME 🔐️
addvault.new.readme.accessLocation.2=This is your vault's access location. Any files added to this volume will be encrypted by Cryptomator. To access this volume at a later point in time, simply unlock it again from within the Cryptomator application.
addvault.new.readme.accessLocation.3=Feel free to remove this file.
## Existing
addvaultwizard.existing.instruction=Choose the "masterkey.cryptomator" file of your existing vault.
addvaultwizard.existing.chooseBtn=Choose…