瀏覽代碼

removed multi user functionality (see #21)
using fixed masterkey filename now

Sebastian Stenzel 10 年之前
父節點
當前提交
ea3384d189

+ 0 - 10
main/crypto-aes/src/main/java/org/cryptomator/crypto/aes256/FileNamingConventions.java

@@ -16,16 +16,6 @@ import org.apache.commons.codec.binary.BaseNCodec;
 
 interface FileNamingConventions {
 
-	/**
-	 * Extension of masterkey files inside the root directory of the encrypted storage.
-	 */
-	String MASTERKEY_FILE_EXT = ".masterkey.json";
-
-	/**
-	 * Additional extension for masterkey backup files.
-	 */
-	String MASTERKEY_BACKUP_FILE_EXT = ".bkup";
-
 	/**
 	 * How to encode the encrypted file names safely. Base32 uses only alphanumeric characters and is case-insensitive.
 	 */

+ 7 - 52
main/ui/src/main/java/org/cryptomator/ui/InitializeController.java

@@ -24,13 +24,7 @@ import javafx.fxml.FXML;
 import javafx.fxml.Initializable;
 import javafx.scene.control.Button;
 import javafx.scene.control.Label;
-import javafx.scene.control.TextField;
-import javafx.scene.input.KeyEvent;
 
-import org.apache.commons.lang3.CharUtils;
-import org.apache.commons.lang3.StringUtils;
-import org.cryptomator.crypto.aes256.Aes256Cryptor;
-import org.cryptomator.ui.controls.ClearOnDisableListener;
 import org.cryptomator.ui.controls.SecPasswordField;
 import org.cryptomator.ui.model.Vault;
 import org.slf4j.Logger;
@@ -39,15 +33,11 @@ import org.slf4j.LoggerFactory;
 public class InitializeController implements Initializable {
 
 	private static final Logger LOG = LoggerFactory.getLogger(InitializeController.class);
-	private static final int MAX_USERNAME_LENGTH = 250;
 
 	private ResourceBundle localization;
 	private Vault directory;
 	private InitializationListener listener;
 
-	@FXML
-	private TextField usernameField;
-
 	@FXML
 	private SecPasswordField passwordField;
 
@@ -63,50 +53,18 @@ public class InitializeController implements Initializable {
 	@Override
 	public void initialize(URL url, ResourceBundle rb) {
 		this.localization = rb;
-		usernameField.addEventFilter(KeyEvent.KEY_TYPED, this::filterAlphanumericKeyEvents);
-		usernameField.textProperty().addListener(this::usernameFieldDidChange);
-		passwordField.textProperty().addListener(this::passwordFieldDidChange);
-		retypePasswordField.textProperty().addListener(this::retypePasswordFieldDidChange);
-		retypePasswordField.disableProperty().addListener(new ClearOnDisableListener(retypePasswordField));
-
-	}
-
-	// ****************************************
-	// Username field
-	// ****************************************
-
-	public void filterAlphanumericKeyEvents(KeyEvent t) {
-		if (t.getCharacter() == null || t.getCharacter().length() == 0) {
-			return;
-		}
-		char c = t.getCharacter().charAt(0);
-		if (!CharUtils.isAsciiAlphanumeric(c)) {
-			t.consume();
-		}
-	}
-
-	public void usernameFieldDidChange(ObservableValue<? extends String> property, String oldValue, String newValue) {
-		if (StringUtils.length(newValue) > MAX_USERNAME_LENGTH) {
-			usernameField.setText(newValue.substring(0, MAX_USERNAME_LENGTH));
-		}
-		passwordField.setDisable(StringUtils.isEmpty(newValue));
-	}
-
-	// ****************************************
-	// Password field
-	// ****************************************
-
-	private void passwordFieldDidChange(ObservableValue<? extends String> property, String oldValue, String newValue) {
-		retypePasswordField.setDisable(StringUtils.isEmpty(newValue));
+		passwordField.textProperty().addListener(this::passwordFieldsDidChange);
+		retypePasswordField.textProperty().addListener(this::passwordFieldsDidChange);
 	}
 
 	// ****************************************
-	// Retype password field
+	// Password fields
 	// ****************************************
 
-	private void retypePasswordFieldDidChange(ObservableValue<? extends String> property, String oldValue, String newValue) {
+	private void passwordFieldsDidChange(ObservableValue<? extends String> property, String oldValue, String newValue) {
+		boolean passwordIsEmpty = passwordField.getText().isEmpty();
 		boolean passwordsAreEqual = passwordField.getText().equals(retypePasswordField.getText());
-		okButton.setDisable(!passwordsAreEqual);
+		okButton.setDisable(passwordIsEmpty || !passwordsAreEqual);
 	}
 
 	// ****************************************
@@ -116,8 +74,7 @@ public class InitializeController implements Initializable {
 	@FXML
 	protected void initializeVault(ActionEvent event) {
 		setControlsDisabled(true);
-		final String masterKeyFileName = usernameField.getText() + Aes256Cryptor.MASTERKEY_FILE_EXT;
-		final Path masterKeyPath = directory.getPath().resolve(masterKeyFileName);
+		final Path masterKeyPath = directory.getPath().resolve(Vault.VAULT_MASTERKEY_FILE);
 		final CharSequence password = passwordField.getCharacters();
 		try (OutputStream masterKeyOutputStream = Files.newOutputStream(masterKeyPath, StandardOpenOption.WRITE, StandardOpenOption.CREATE_NEW)) {
 			directory.getCryptor().encryptMasterKey(masterKeyOutputStream, password);
@@ -132,14 +89,12 @@ public class InitializeController implements Initializable {
 			LOG.error("I/O Exception", ex);
 		} finally {
 			setControlsDisabled(false);
-			usernameField.setText(null);
 			passwordField.swipe();
 			retypePasswordField.swipe();
 		}
 	}
 
 	private void setControlsDisabled(boolean disable) {
-		usernameField.setDisable(disable);
 		passwordField.setDisable(disable);
 		retypePasswordField.setDisable(disable);
 		okButton.setDisable(disable);

+ 19 - 53
main/ui/src/main/java/org/cryptomator/ui/UnlockController.java

@@ -11,7 +11,6 @@ package org.cryptomator.ui;
 import java.io.IOException;
 import java.io.InputStream;
 import java.net.URL;
-import java.nio.file.DirectoryStream;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.StandardCopyOption;
@@ -26,21 +25,19 @@ import javafx.event.ActionEvent;
 import javafx.fxml.FXML;
 import javafx.fxml.Initializable;
 import javafx.scene.control.Button;
-import javafx.scene.control.ComboBox;
 import javafx.scene.control.Label;
 import javafx.scene.control.ProgressIndicator;
 import javafx.scene.control.TextField;
+import javafx.scene.input.KeyEvent;
 
 import org.apache.commons.io.IOUtils;
-import org.apache.commons.lang3.StringUtils;
-import org.cryptomator.crypto.aes256.Aes256Cryptor;
+import org.apache.commons.lang3.CharUtils;
 import org.cryptomator.crypto.exceptions.DecryptFailedException;
 import org.cryptomator.crypto.exceptions.UnsupportedKeyLengthException;
 import org.cryptomator.crypto.exceptions.WrongPasswordException;
 import org.cryptomator.ui.controls.SecPasswordField;
 import org.cryptomator.ui.model.Vault;
 import org.cryptomator.ui.util.FXThreads;
-import org.cryptomator.ui.util.MasterKeyFilter;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -54,9 +51,6 @@ public class UnlockController implements Initializable {
 	private UnlockListener listener;
 	private Vault vault;
 
-	@FXML
-	private ComboBox<String> usernameBox;
-
 	@FXML
 	private SecPasswordField passwordField;
 
@@ -84,19 +78,8 @@ public class UnlockController implements Initializable {
 	public void initialize(URL url, ResourceBundle rb) {
 		this.rb = rb;
 
-		usernameBox.valueProperty().addListener(this::didChooseUsername);
-		mountName.textProperty().addListener(this::didTypeMountName);
-	}
-
-	// ****************************************
-	// Username box
-	// ****************************************
-
-	public void didChooseUsername(ObservableValue<? extends String> property, String oldValue, String newValue) {
-		if (newValue != null) {
-			Platform.runLater(passwordField::requestFocus);
-		}
-		passwordField.setDisable(StringUtils.isEmpty(newValue));
+		mountName.addEventFilter(KeyEvent.KEY_TYPED, this::filterAlphanumericKeyEvents);
+		mountName.textProperty().addListener(this::mountNameDidChange);
 	}
 
 	// ****************************************
@@ -106,10 +89,8 @@ public class UnlockController implements Initializable {
 	@FXML
 	private void didClickUnlockButton(ActionEvent event) {
 		setControlsDisabled(true);
-		final String masterKeyFileName = usernameBox.getValue() + Aes256Cryptor.MASTERKEY_FILE_EXT;
-		final String masterKeyBackupFileName = masterKeyFileName + Aes256Cryptor.MASTERKEY_BACKUP_FILE_EXT;
-		final Path masterKeyPath = vault.getPath().resolve(masterKeyFileName);
-		final Path masterKeyBackupPath = vault.getPath().resolve(masterKeyBackupFileName);
+		final Path masterKeyPath = vault.getPath().resolve(Vault.VAULT_MASTERKEY_FILE);
+		final Path masterKeyBackupPath = vault.getPath().resolve(Vault.VAULT_MASTERKEY_BACKUP_FILE);
 		final CharSequence password = passwordField.getCharacters();
 		InputStream masterKeyInputStream = null;
 		try {
@@ -151,30 +132,10 @@ public class UnlockController implements Initializable {
 	}
 
 	private void setControlsDisabled(boolean disable) {
-		usernameBox.setDisable(disable);
 		passwordField.setDisable(disable);
 		unlockButton.setDisable(disable);
 	}
 
-	private void findExistingUsernames() {
-		try {
-			DirectoryStream<Path> ds = MasterKeyFilter.filteredDirectory(vault.getPath());
-			final String masterKeyExt = Aes256Cryptor.MASTERKEY_FILE_EXT.toLowerCase();
-			usernameBox.getItems().clear();
-			for (final Path path : ds) {
-				final String fileName = path.getFileName().toString();
-				final int beginOfExt = fileName.toLowerCase().lastIndexOf(masterKeyExt);
-				final String baseName = fileName.substring(0, beginOfExt);
-				usernameBox.getItems().add(baseName);
-			}
-			if (usernameBox.getItems().size() == 1) {
-				usernameBox.getSelectionModel().selectFirst();
-			}
-		} catch (IOException e) {
-			LOG.trace("Invalid path: " + vault.getPath(), e);
-		}
-	}
-
 	private void didUnlockAndMount(boolean mountSuccess) {
 		progressIndicator.setVisible(false);
 		if (listener != null) {
@@ -182,13 +143,19 @@ public class UnlockController implements Initializable {
 		}
 	}
 
-	private void didTypeMountName(ObservableValue<? extends String> property, String oldValue, String newValue) {
-		try {
-			vault.setMountName(newValue);
-			if (!newValue.equals(vault.getMountName())) {
-				mountName.setText(vault.getMountName());
-			}
-		} catch (IllegalArgumentException e) {
+	public void filterAlphanumericKeyEvents(KeyEvent t) {
+		if (t.getCharacter() == null || t.getCharacter().length() == 0) {
+			return;
+		}
+		char c = t.getCharacter().charAt(0);
+		if (!CharUtils.isAsciiAlphanumeric(c)) {
+			t.consume();
+		}
+	}
+
+	private void mountNameDidChange(ObservableValue<? extends String> property, String oldValue, String newValue) {
+		// newValue is guaranteed to be a-z0-9, see #filterAlphanumericKeyEvents
+		if (newValue.isEmpty()) {
 			mountName.setText(vault.getMountName());
 		}
 	}
@@ -201,7 +168,6 @@ public class UnlockController implements Initializable {
 
 	public void setVault(Vault vault) {
 		this.vault = vault;
-		this.findExistingUsernames();
 		this.mountName.setText(vault.getMountName());
 	}
 

+ 0 - 30
main/ui/src/main/java/org/cryptomator/ui/controls/ClearOnDisableListener.java

@@ -1,30 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2014 Sebastian Stenzel
- * This file is licensed under the terms of the MIT license.
- * See the LICENSE.txt file for more info.
- * 
- * Contributors:
- *     Sebastian Stenzel - initial API and implementation
- ******************************************************************************/
-package org.cryptomator.ui.controls;
-
-import javafx.beans.value.ChangeListener;
-import javafx.beans.value.ObservableValue;
-import javafx.scene.control.TextInputControl;
-
-public class ClearOnDisableListener implements ChangeListener<Boolean> {
-
-	final TextInputControl control;
-
-	public ClearOnDisableListener(TextInputControl control) {
-		this.control = control;
-	}
-
-	@Override
-	public void changed(ObservableValue<? extends Boolean> property, Boolean wasDisabled, Boolean isDisabled) {
-		if (isDisabled) {
-			control.clear();
-		}
-	}
-
-}

+ 4 - 2
main/ui/src/main/java/org/cryptomator/ui/model/Vault.java

@@ -15,7 +15,6 @@ import org.apache.commons.lang3.StringUtils;
 import org.cryptomator.crypto.Cryptor;
 import org.cryptomator.ui.util.DeferredClosable;
 import org.cryptomator.ui.util.DeferredCloser;
-import org.cryptomator.ui.util.MasterKeyFilter;
 import org.cryptomator.ui.util.mount.CommandFailedException;
 import org.cryptomator.ui.util.mount.WebDavMount;
 import org.cryptomator.ui.util.mount.WebDavMounter;
@@ -30,6 +29,8 @@ public class Vault implements Serializable {
 	private static final Logger LOG = LoggerFactory.getLogger(Vault.class);
 
 	public static final String VAULT_FILE_EXTENSION = ".cryptomator";
+	public static final String VAULT_MASTERKEY_FILE = "masterkey.cryptomator";
+	public static final String VAULT_MASTERKEY_BACKUP_FILE = "masterkey.cryptomator.bkup";
 
 	private final Path path;
 	private final WebDavServer server;
@@ -63,7 +64,8 @@ public class Vault implements Serializable {
 	}
 
 	public boolean containsMasterKey() throws IOException {
-		return MasterKeyFilter.filteredDirectory(path).iterator().hasNext();
+		final Path masterKeyPath = path.resolve(VAULT_MASTERKEY_FILE);
+		return Files.isRegularFile(masterKeyPath);
 	}
 
 	public synchronized boolean startServer() {

+ 0 - 34
main/ui/src/main/java/org/cryptomator/ui/util/MasterKeyFilter.java

@@ -1,34 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2014 Sebastian Stenzel
- * This file is licensed under the terms of the MIT license.
- * See the LICENSE.txt file for more info.
- * 
- * Contributors:
- *     Sebastian Stenzel - initial API and implementation
- ******************************************************************************/
-package org.cryptomator.ui.util;
-
-import java.io.IOException;
-import java.nio.file.DirectoryStream;
-import java.nio.file.DirectoryStream.Filter;
-import java.nio.file.Files;
-import java.nio.file.Path;
-
-import org.cryptomator.crypto.aes256.Aes256Cryptor;
-
-public class MasterKeyFilter implements Filter<Path> {
-
-	public static MasterKeyFilter FILTER = new MasterKeyFilter();
-
-	private final String masterKeyExt = Aes256Cryptor.MASTERKEY_FILE_EXT.toLowerCase();
-
-	@Override
-	public boolean accept(Path child) throws IOException {
-		return child.getFileName().toString().toLowerCase().endsWith(masterKeyExt);
-	}
-
-	public static final DirectoryStream<Path> filteredDirectory(Path dir) throws IOException {
-		return Files.newDirectoryStream(dir, FILTER);
-	}
-
-}

+ 7 - 11
main/ui/src/main/resources/fxml/initialize.fxml

@@ -30,22 +30,18 @@
 
 	<children>
 		<!-- Row 0 -->
-		<Label GridPane.rowIndex="0" GridPane.columnIndex="0" text="%initialize.label.username" />
-		<TextField fx:id="usernameField" GridPane.rowIndex="0" GridPane.columnIndex="1" />
+		<Label GridPane.rowIndex="0" GridPane.columnIndex="0" text="%initialize.label.password" />
+		<SecPasswordField fx:id="passwordField" GridPane.rowIndex="0" GridPane.columnIndex="1" />
 		
 		<!-- Row 1 -->
-		<Label GridPane.rowIndex="1" GridPane.columnIndex="0" text="%initialize.label.password" />
-		<SecPasswordField fx:id="passwordField" GridPane.rowIndex="1" GridPane.columnIndex="1" disable="true" />
+		<Label GridPane.rowIndex="1" GridPane.columnIndex="0" text="%initialize.label.retypePassword" />
+		<SecPasswordField fx:id="retypePasswordField" GridPane.rowIndex="1" GridPane.columnIndex="1" />
 		
 		<!-- Row 2 -->
-		<Label GridPane.rowIndex="2" GridPane.columnIndex="0" text="%initialize.label.retypePassword" />
-		<SecPasswordField fx:id="retypePasswordField" GridPane.rowIndex="2" GridPane.columnIndex="1" disable="true" />
-		
-		<!-- Row 3 -->
-		<Button fx:id="okButton" defaultButton="true" GridPane.rowIndex="3" GridPane.columnIndex="0" GridPane.columnSpan="2" GridPane.halignment="RIGHT" text="%initialize.button.ok" prefWidth="150.0" onAction="#initializeVault" focusTraversable="false" disable="true" />
+		<Button fx:id="okButton" defaultButton="true" GridPane.rowIndex="2" GridPane.columnIndex="0" GridPane.columnSpan="2" GridPane.halignment="RIGHT" text="%initialize.button.ok" prefWidth="150.0" onAction="#initializeVault" focusTraversable="false" disable="true" />
 				
-		<!-- Row 5 -->
-		<Label fx:id="messageLabel" GridPane.rowIndex="5" GridPane.columnIndex="0" GridPane.columnSpan="2" />
+		<!-- Row 3 -->
+		<Label fx:id="messageLabel" GridPane.rowIndex="3" GridPane.columnIndex="0" GridPane.columnSpan="2" />
 	</children>
 </GridPane>
 

+ 0 - 1
main/ui/src/main/resources/fxml/main.fxml

@@ -29,7 +29,6 @@
 			<items>
 				<MenuItem text="%main.directoryList.contextMenu.remove" onAction="#didClickRemoveSelectedEntry" />
 				<!-- TODO: -->
-				<MenuItem text="%main.directoryList.contextMenu.addUser" disable="true" />
 				<MenuItem text="%main.directoryList.contextMenu.changePassword" disable="true" />
 			</items>
 		</ContextMenu>

+ 10 - 14
main/ui/src/main/resources/fxml/unlock.fxml

@@ -31,25 +31,21 @@
 
 	<children>
 		<!-- Row 0 -->
-		<Label text="%unlock.label.username" GridPane.rowIndex="0" GridPane.columnIndex="0" />
-		<ComboBox fx:id="usernameBox" GridPane.rowIndex="0" GridPane.columnIndex="1" GridPane.hgrow="ALWAYS" maxWidth="Infinity" promptText="$access.label.username" />
-
+		<Label text="%unlock.label.password" GridPane.rowIndex="0" GridPane.columnIndex="0" />
+		<SecPasswordField fx:id="passwordField" GridPane.rowIndex="0" GridPane.columnIndex="1" GridPane.hgrow="ALWAYS" maxWidth="Infinity" />
+		
 		<!-- Row 1 -->
-		<Label text="%unlock.label.password" GridPane.rowIndex="1" GridPane.columnIndex="0" />
-		<SecPasswordField fx:id="passwordField" GridPane.rowIndex="1" GridPane.columnIndex="1" GridPane.hgrow="ALWAYS" maxWidth="Infinity" />
+		<Label text="%unlock.label.mountName" GridPane.rowIndex="1" GridPane.columnIndex="0" />
+		<TextField fx:id="mountName" GridPane.rowIndex="1" GridPane.columnIndex="1" GridPane.hgrow="ALWAYS" maxWidth="Infinity" />
 		
 		<!-- Row 2 -->
-		<Label text="%unlock.label.mountName" GridPane.rowIndex="2" GridPane.columnIndex="0" />
-		<TextField fx:id="mountName" 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"/>
+		<Button fx:id="unlockButton" text="%unlock.button.unlock" defaultButton="true" GridPane.rowIndex="2" GridPane.columnIndex="0" GridPane.columnSpan="2" GridPane.halignment="RIGHT" prefWidth="150.0" onAction="#didClickUnlockButton"/>
 		
-		<!-- Row 4-->
-		<ProgressIndicator progress="-1" fx:id="progressIndicator" GridPane.rowIndex="4" GridPane.columnIndex="0" GridPane.columnSpan="2" GridPane.halignment="CENTER" visible="false"/>
+		<!-- Row 3-->
+		<ProgressIndicator progress="-1" fx:id="progressIndicator" GridPane.rowIndex="3" GridPane.columnIndex="0" GridPane.columnSpan="2" GridPane.halignment="CENTER" visible="false"/>
 		
-		<!-- Row 5 -->
-		<Label fx:id="messageLabel" GridPane.rowIndex="5" GridPane.columnIndex="0" GridPane.columnSpan="2" />
+		<!-- Row 4 -->
+		<Label fx:id="messageLabel" GridPane.rowIndex="4" GridPane.columnIndex="0" GridPane.columnSpan="2" />
 	</children>
 </GridPane>
 

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

@@ -11,7 +11,6 @@ app.name=Cryptomator
 
 # main.fxml
 main.directoryList.contextMenu.remove=Remove from list
-main.directoryList.contextMenu.addUser=Add user
 main.directoryList.contextMenu.changePassword=Change password
 main.addDirectory.contextMenu.new=Create new vault
 main.addDirectory.contextMenu.open=Add existing vault
@@ -23,7 +22,6 @@ welcome.addButtonInstructionLabel=Start by adding a new vault :-)
 
 
 # initialize.fxml
-initialize.label.username=Username
 initialize.label.password=Password
 initialize.label.retypePassword=Retype password
 initialize.button.ok=Create vault
@@ -32,11 +30,8 @@ initialize.alert.directoryIsNotEmpty.content=All existing files inside this dire
 
 
 # unlock.fxml
-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.
 unlock.errorMessage.decryptionFailed=Decryption failed.