mirror of
https://github.com/cryptomator/cryptomator.git
synced 2026-05-19 11:11:28 +00:00
Added access location readme file
This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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…
|
||||
|
||||
Reference in New Issue
Block a user