Ver código fonte

Add readme file to vault storage directory

Sebastian Stenzel 5 anos atrás
pai
commit
4a02bf529d

+ 14 - 1
main/ui/src/main/java/org/cryptomator/ui/addvaultwizard/CreateNewVaultPasswordController.java

@@ -30,9 +30,13 @@ 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.Files;
 import java.nio.file.Path;
+import java.nio.file.StandardOpenOption;
 import java.util.ResourceBundle;
 
 @AddVaultWizardScoped
@@ -50,6 +54,7 @@ public class CreateNewVaultPasswordController implements FxController {
 	private final VaultFactory vaultFactory;
 	private final ResourceBundle resourceBundle;
 	private final PasswordStrengthUtil strengthRater;
+	private final ReadmeGenerator readmeGenerator;
 	private final IntegerProperty passwordStrength;
 
 	public Button finishButton;
@@ -63,7 +68,7 @@ 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) {
+	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) {
 		this.window = window;
 		this.chooseLocationScene = chooseLocationScene;
 		this.successScene = successScene;
@@ -74,6 +79,7 @@ public class CreateNewVaultPasswordController implements FxController {
 		this.vaultFactory = vaultFactory;
 		this.resourceBundle = resourceBundle;
 		this.strengthRater = strengthRater;
+		this.readmeGenerator = readmeGenerator;
 		this.passwordStrength = new SimpleIntegerProperty(-1);
 	}
 
@@ -120,6 +126,13 @@ public class CreateNewVaultPasswordController implements FxController {
 		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);
 			vault.set(newVault);
 			vaults.add(newVault);
 			window.setScene(successScene.get());

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

@@ -0,0 +1,62 @@
+package org.cryptomator.ui.addvaultwizard;
+
+import javax.inject.Inject;
+import java.util.List;
+import java.util.ResourceBundle;
+
+@AddVaultWizardScoped
+public class ReadmeGenerator {
+	
+	// specs: https://web.archive.org/web/20190708132914/http://www.kleinlercher.at/tools/Windows_Protocols/Word2007RTFSpec9.pdf
+	private static final String RTF_HEADER = "{\\rtf1\\fbidis\\ansi\\uc0\\fs32\n";
+	private static final String RTF_FOOTER = "}";
+	private static final String HELP_URL = "{\\field{\\*\\fldinst HYPERLINK \"http://www.google.com/\"}{\\fldrslt google.com}}";
+
+	private final ResourceBundle resourceBundle;
+
+	@Inject
+	public ReadmeGenerator(ResourceBundle resourceBundle){
+		this.resourceBundle = resourceBundle;
+	}
+	
+	public String createVaultStorageLocationReadmeRtf() {
+		return createDocument(List.of( //
+				resourceBundle.getString("addvault.new.readme.storageLocation.1"), //
+				resourceBundle.getString("addvault.new.readme.storageLocation.2"), //
+				resourceBundle.getString("addvault.new.readme.storageLocation.3"),  //
+				String.format(resourceBundle.getString("addvault.new.readme.storageLocation.4"), HELP_URL)  //
+		));
+	}
+
+	// visible for testing
+	String createDocument(Iterable<String> paragraphs) {
+		StringBuilder sb = new StringBuilder(RTF_HEADER);
+		for (String p : paragraphs) {
+			sb.append("\\par {\\sa80 ");
+			appendEscaped(sb, p);
+			sb.append("}\n");
+		}
+		sb.append(RTF_FOOTER);
+		return sb.toString();
+	}
+	
+	// visible for testing
+	String escapeNonAsciiChars(CharSequence input) {
+		StringBuilder sb = new StringBuilder();
+		appendEscaped(sb, input);
+		return sb.toString();
+	}
+	
+	private void appendEscaped(StringBuilder sb, CharSequence input) {
+		input.chars().forEachOrdered(c -> {
+			if (c < 128) {
+				sb.append((char) c);
+			} else if (c < 0xFFFF) {
+				sb.append("\\u").append(c);
+			}
+		});
+	}
+	
+	
+
+}

+ 5 - 0
main/ui/src/main/resources/i18n/strings.properties

@@ -38,6 +38,11 @@ addvaultwizard.new.reenterPassword=Confirm the password
 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.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.
 ## Existing
 addvaultwizard.existing.instruction=Choose the "masterkey.cryptomator" file of your existing vault.
 addvaultwizard.existing.chooseBtn=Choose…

+ 46 - 0
main/ui/src/test/java/org/cryptomator/ui/addvaultwizard/ReadMeGeneratorTest.java

@@ -0,0 +1,46 @@
+package org.cryptomator.ui.addvaultwizard;
+
+import org.hamcrest.CoreMatchers;
+import org.hamcrest.MatcherAssert;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.CsvSource;
+
+import java.util.List;
+
+public class ReadMeGeneratorTest {
+
+	@ParameterizedTest
+	@CsvSource({ //
+			"test,test", //
+			"t\u00E4st,t\\u228st", //
+			"t\uD83D\uDE09st,t\\u55357\\u56841st", //
+	})
+	public void testEscapeNonAsciiChars(String input, String expectedResult) {
+		ReadmeGenerator readmeGenerator = new ReadmeGenerator(null);
+
+		String actualResult = readmeGenerator.escapeNonAsciiChars(input);
+
+		Assertions.assertEquals(expectedResult, actualResult);
+	}
+
+	@Test
+	public void testCreateDocument() {
+		ReadmeGenerator readmeGenerator = new ReadmeGenerator(null);
+		Iterable<String> paragraphs = List.of( //
+				"Dear User,", //
+				"\\b please don't touch the \"d\" directory.", //
+				"Thank you for your cooperation \uD83D\uDE09" //
+		);
+
+		String result = readmeGenerator.createDocument(paragraphs);
+
+		MatcherAssert.assertThat(result, CoreMatchers.startsWith("{\\rtf1\\fbidis\\ansi\\uc0\\fs32"));
+		MatcherAssert.assertThat(result, CoreMatchers.containsString("\\par {\\sa80 Dear User,}"));
+		MatcherAssert.assertThat(result, CoreMatchers.containsString("\\par {\\sa80 \\b please don't touch the \"d\" directory.}"));
+		MatcherAssert.assertThat(result, CoreMatchers.containsString("\\par {\\sa80 Thank you for your cooperation \\u55357\\u56841}"));
+		MatcherAssert.assertThat(result, CoreMatchers.endsWith("}"));
+	}
+
+}