mirror of
https://github.com/cryptomator/cryptomator.git
synced 2026-05-23 05:01:28 +00:00
Merge pull request #28 from Tillerino/windowsNames
Pretty network drive names on Windows
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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("汉语"));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user