Bläddra i källkod

Merge pull request #28 from Tillerino/windowsNames

Pretty network drive names on Windows
Sebastian Stenzel 10 år sedan
förälder
incheckning
999285617d

+ 10 - 2
main/core/src/main/java/org/cryptomator/webdav/WebDavServer.java

@@ -15,6 +15,7 @@ import java.util.UUID;
 import java.util.concurrent.BlockingQueue;
 import java.util.concurrent.LinkedBlockingQueue;
 
+import org.apache.commons.lang3.StringUtils;
 import org.cryptomator.crypto.Cryptor;
 import org.cryptomator.webdav.jackrabbit.WebDavServlet;
 import org.eclipse.jetty.server.Connector;
@@ -81,11 +82,18 @@ public final class WebDavServer {
 	/**
 	 * @param workDir Path of encrypted folder.
 	 * @param cryptor A fully initialized cryptor instance ready to en- or decrypt streams.
+	 * @param name The name of the folder. Must be non-empty and only contain any of _ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789
 	 * @return servlet
 	 */
-	public ServletLifeCycleAdapter createServlet(final Path workDir, final boolean checkFileIntegrity, final Cryptor cryptor) {
+	public ServletLifeCycleAdapter createServlet(final Path workDir, final boolean checkFileIntegrity, final Cryptor cryptor, String name) {
 		try {
-			final URI uri = new URI(null, null, localConnector.getHost(), localConnector.getLocalPort(), "/" + UUID.randomUUID().toString(), null, null);
+			if(StringUtils.isEmpty(name)) {
+				throw new IllegalArgumentException("name empty");
+			}
+			if(!StringUtils.containsOnly(name, "_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789")) {
+				throw new IllegalArgumentException("name contains illegal characters: " + name);
+			}
+			final URI uri = new URI(null, null, localConnector.getHost(), localConnector.getLocalPort(), "/" + UUID.randomUUID().toString() + "/" + name, null, null);
 
 			final ServletContextHandler servletContext = new ServletContextHandler(servletCollection, uri.getRawPath(), ServletContextHandler.SESSIONS);
 			final ServletHolder servlet = getWebDavServletHolder(workDir.toString(), checkFileIntegrity, cryptor);

+ 18 - 0
main/ui/src/main/java/org/cryptomator/ui/UnlockController.java

@@ -28,6 +28,7 @@ import javafx.scene.control.CheckBox;
 import javafx.scene.control.ComboBox;
 import javafx.scene.control.Label;
 import javafx.scene.control.ProgressIndicator;
+import javafx.scene.control.TextField;
 
 import org.apache.commons.io.IOUtils;
 import org.apache.commons.lang3.StringUtils;
@@ -39,6 +40,7 @@ import org.cryptomator.ui.controls.SecPasswordField;
 import org.cryptomator.ui.model.Directory;
 import org.cryptomator.ui.util.FXThreads;
 import org.cryptomator.ui.util.MasterKeyFilter;
+import org.cryptomator.webdav.WebDavServer;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -59,6 +61,9 @@ public class UnlockController implements Initializable {
 	@FXML
 	private CheckBox checkIntegrity;
 
+	@FXML
+	private TextField mountName;
+
 	@FXML
 	private Button unlockButton;
 
@@ -73,6 +78,7 @@ public class UnlockController implements Initializable {
 		this.rb = rb;
 
 		usernameBox.valueProperty().addListener(this::didChooseUsername);
+		mountName.textProperty().addListener(this::didTypeMountName);
 	}
 
 	// ****************************************
@@ -167,6 +173,17 @@ public class UnlockController implements Initializable {
 		}
 	}
 
+	private void didTypeMountName(ObservableValue<? extends String> property, String oldValue, String newValue) {
+		try {
+			directory.setMountName(newValue);
+			if (!newValue.equals(directory.getMountName())) {
+				mountName.setText(directory.getMountName());
+			}
+		} catch (IllegalArgumentException e) {
+			mountName.setText(directory.getMountName());
+		}
+	}
+
 	/* Getter/Setter */
 
 	public Directory getDirectory() {
@@ -177,6 +194,7 @@ public class UnlockController implements Initializable {
 		this.directory = directory;
 		this.findExistingUsernames();
 		this.checkIntegrity.setSelected(directory.shouldVerifyFileIntegrity());
+		this.mountName.setText(directory.getMountName());
 	}
 
 	public UnlockListener getListener() {

+ 54 - 1
main/ui/src/main/java/org/cryptomator/ui/model/Directory.java

@@ -4,6 +4,8 @@ import java.io.IOException;
 import java.io.Serializable;
 import java.nio.file.Files;
 import java.nio.file.Path;
+import java.text.Normalizer;
+import java.text.Normalizer.Form;
 
 import javafx.beans.property.ObjectProperty;
 import javafx.beans.property.SimpleObjectProperty;
@@ -36,6 +38,7 @@ public class Directory implements Serializable {
 	private final Runnable shutdownTask = new ShutdownTask();
 	private final Path path;
 	private boolean verifyFileIntegrity;
+	private String mountName = "Cryptomator";
 	private ServletLifeCycleAdapter webDavServlet;
 	private WebDavMount webDavMount;
 
@@ -45,6 +48,11 @@ public class Directory implements Serializable {
 		}
 		this.path = path;
 
+		try {
+			setMountName(getName());
+		} catch (IllegalArgumentException e) {
+
+		}
 	}
 
 	public boolean containsMasterKey() throws IOException {
@@ -55,7 +63,7 @@ public class Directory implements Serializable {
 		if (webDavServlet != null && webDavServlet.isRunning()) {
 			return false;
 		}
-		webDavServlet = WebDavServer.getInstance().createServlet(path, verifyFileIntegrity, cryptor);
+		webDavServlet = WebDavServer.getInstance().createServlet(path, verifyFileIntegrity, cryptor, getMountName());
 		if (webDavServlet.start()) {
 			MainApplication.addShutdownTask(shutdownTask);
 			return true;
@@ -140,6 +148,51 @@ public class Directory implements Serializable {
 		this.unlocked.set(unlocked);
 	}
 
+	public String getMountName() {
+		return mountName;
+	}
+
+	/**
+	 * Tries to form a similar string using the regular latin alphabet.
+	 * 
+	 * @param string
+	 * @return a string composed of a-z, A-Z, 0-9, and _.
+	 */
+	public static String normalize(String string) {
+		String normalized = Normalizer.normalize(string, Form.NFD);
+		StringBuilder builder = new StringBuilder();
+		for (int i = 0; i < normalized.length(); i++) {
+			char c = normalized.charAt(i);
+			if (Character.isWhitespace(c)) {
+				if (builder.length() == 0 || builder.charAt(builder.length() - 1) != '_') {
+					builder.append('_');
+				}
+			} else if (c < 127 && Character.isLetterOrDigit(c)) {
+				builder.append(c);
+			} else if (c < 127) {
+				if (builder.length() == 0 || builder.charAt(builder.length() - 1) != '_') {
+					builder.append('_');
+				}
+			}
+		}
+		return builder.toString();
+	}
+
+	/**
+	 * sets the mount name while normalizing it
+	 * 
+	 * @param mountName
+	 * @throws IllegalArgumentException
+	 *             if the name is empty after normalization
+	 */
+	public void setMountName(String mountName) throws IllegalArgumentException {
+		mountName = normalize(mountName);
+		if (StringUtils.isEmpty(mountName)) {
+			throw new IllegalArgumentException("mount name is empty");
+		}
+		this.mountName = mountName;
+	}
+
 	/* hashcode/equals */
 
 	@Override

+ 3 - 0
main/ui/src/main/java/org/cryptomator/ui/model/DirectoryDeserializer.java

@@ -20,6 +20,9 @@ public class DirectoryDeserializer extends JsonDeserializer<Directory> {
 		final Directory dir = new Directory(path);
 		final boolean verifyFileIntegrity = node.has("checkIntegrity") ? node.get("checkIntegrity").asBoolean() : false;
 		dir.setVerifyFileIntegrity(verifyFileIntegrity);
+		if (node.has("mountName")) {
+			dir.setMountName(node.get("mountName").asText());
+		}
 		return dir;
 	}
 

+ 1 - 0
main/ui/src/main/java/org/cryptomator/ui/model/DirectorySerializer.java

@@ -14,6 +14,7 @@ public class DirectorySerializer extends JsonSerializer<Directory> {
 		jgen.writeStartObject();
 		jgen.writeStringField("path", value.getPath().toString());
 		jgen.writeBooleanField("checkIntegrity", value.shouldVerifyFileIntegrity());
+		jgen.writeStringField("mountName", value.getMountName().toString());
 		jgen.writeEndObject();
 	}
 

+ 9 - 5
main/ui/src/main/resources/fxml/unlock.fxml

@@ -43,13 +43,17 @@
 		<CheckBox fx:id="checkIntegrity" wrapText="true" text="%unlock.checkbox.checkIntegrity" GridPane.rowIndex="2" GridPane.columnIndex="1" GridPane.hgrow="ALWAYS" maxWidth="Infinity" />
 		
 		<!-- Row 3 -->
-		<Button fx:id="unlockButton" text="%unlock.button.unlock" defaultButton="true" GridPane.rowIndex="3" GridPane.columnIndex="0" GridPane.columnSpan="2" GridPane.halignment="RIGHT" prefWidth="150.0" onAction="#didClickUnlockButton"/>
+		<Label text="%unlock.label.mountName" GridPane.rowIndex="3" GridPane.columnIndex="0" />
+		<TextField fx:id="mountName" GridPane.rowIndex="3" GridPane.columnIndex="1" GridPane.hgrow="ALWAYS" maxWidth="Infinity" />
 		
-		<!-- Row 4-->
-		<ProgressIndicator progress="-1" fx:id="progressIndicator" GridPane.rowIndex="4" GridPane.columnIndex="0" GridPane.columnSpan="2" GridPane.halignment="CENTER" visible="false"/>
+		<!-- Row 4 -->
+		<Button fx:id="unlockButton" text="%unlock.button.unlock" defaultButton="true" GridPane.rowIndex="4" GridPane.columnIndex="0" GridPane.columnSpan="2" GridPane.halignment="RIGHT" prefWidth="150.0" onAction="#didClickUnlockButton"/>
 		
-		<!-- Row 5 -->
-		<Label fx:id="messageLabel" GridPane.rowIndex="5" GridPane.columnIndex="0" GridPane.columnSpan="2" />
+		<!-- Row 5-->
+		<ProgressIndicator progress="-1" fx:id="progressIndicator" GridPane.rowIndex="5" GridPane.columnIndex="0" GridPane.columnSpan="2" GridPane.halignment="CENTER" visible="false"/>
+		
+		<!-- Row 6 -->
+		<Label fx:id="messageLabel" GridPane.rowIndex="6" GridPane.columnIndex="0" GridPane.columnSpan="2" />
 	</children>
 </GridPane>
 

+ 1 - 0
main/ui/src/main/resources/localization.properties

@@ -33,6 +33,7 @@ initialize.alert.directoryIsNotEmpty.content=All existing files inside this dire
 unlock.label.username=Username
 unlock.label.password=Password
 unlock.label.checkIntegrity=File integrity
+unlock.label.mountName=Drive name
 unlock.checkbox.checkIntegrity=Verify checksums (slower, but detects manipulation)
 unlock.button.unlock=Unlock vault
 unlock.errorMessage.wrongPassword=Wrong password.

+ 21 - 0
main/ui/src/test/java/org/cryptomator/ui/model/DirectoryTest.java

@@ -0,0 +1,21 @@
+package org.cryptomator.ui.model;
+
+import static org.junit.Assert.*;
+
+import org.cryptomator.ui.model.Directory;
+import org.junit.Test;
+
+public class DirectoryTest {
+	@Test
+	public void testNormalize() throws Exception {
+		assertEquals("_", Directory.normalize(" "));
+
+		assertEquals("a", Directory.normalize("ä"));
+
+		assertEquals("C", Directory.normalize("Ĉ"));
+
+		assertEquals("_", Directory.normalize(":"));
+
+		assertEquals("", Directory.normalize("汉语"));
+	}
+}