瀏覽代碼

Added access location readme file

Sebastian Stenzel 5 年之前
父節點
當前提交
88220cabee

+ 74 - 24
main/ui/src/main/java/org/cryptomator/ui/addvaultwizard/CreateNewVaultPasswordController.java

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

+ 8 - 0
main/ui/src/main/java/org/cryptomator/ui/addvaultwizard/ReadmeGenerator.java

@@ -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) {

+ 6 - 1
main/ui/src/main/resources/fxml/addvault_new_password.fxml

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

+ 6 - 1
main/ui/src/main/resources/i18n/strings.properties

@@ -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…