diff --git a/main/crypto-aes/src/main/java/org/cryptomator/crypto/aes256/FileNamingConventions.java b/main/crypto-aes/src/main/java/org/cryptomator/crypto/aes256/FileNamingConventions.java index 111d26653..82e6b6aa7 100644 --- a/main/crypto-aes/src/main/java/org/cryptomator/crypto/aes256/FileNamingConventions.java +++ b/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. */ diff --git a/main/ui/src/main/java/org/cryptomator/ui/InitializeController.java b/main/ui/src/main/java/org/cryptomator/ui/InitializeController.java index f4618e0a5..e15421cfa 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/InitializeController.java +++ b/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)); - + passwordField.textProperty().addListener(this::passwordFieldsDidChange); + retypePasswordField.textProperty().addListener(this::passwordFieldsDidChange); } // **************************************** - // Username field + // Password fields // **************************************** - 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 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 property, String oldValue, String newValue) { - retypePasswordField.setDisable(StringUtils.isEmpty(newValue)); - } - - // **************************************** - // Retype password field - // **************************************** - - private void retypePasswordFieldDidChange(ObservableValue property, String oldValue, String newValue) { + private void passwordFieldsDidChange(ObservableValue 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); diff --git a/main/ui/src/main/java/org/cryptomator/ui/UnlockController.java b/main/ui/src/main/java/org/cryptomator/ui/UnlockController.java index 06ee77651..d3f1dbd01 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/UnlockController.java +++ b/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 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 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 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 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 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()); } diff --git a/main/ui/src/main/java/org/cryptomator/ui/controls/ClearOnDisableListener.java b/main/ui/src/main/java/org/cryptomator/ui/controls/ClearOnDisableListener.java deleted file mode 100644 index b5bf8f68a..000000000 --- a/main/ui/src/main/java/org/cryptomator/ui/controls/ClearOnDisableListener.java +++ /dev/null @@ -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 { - - final TextInputControl control; - - public ClearOnDisableListener(TextInputControl control) { - this.control = control; - } - - @Override - public void changed(ObservableValue property, Boolean wasDisabled, Boolean isDisabled) { - if (isDisabled) { - control.clear(); - } - } - -} \ No newline at end of file diff --git a/main/ui/src/main/java/org/cryptomator/ui/model/Vault.java b/main/ui/src/main/java/org/cryptomator/ui/model/Vault.java index 286376b2f..174473a4c 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/model/Vault.java +++ b/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() { diff --git a/main/ui/src/main/java/org/cryptomator/ui/util/MasterKeyFilter.java b/main/ui/src/main/java/org/cryptomator/ui/util/MasterKeyFilter.java deleted file mode 100644 index 844f42acc..000000000 --- a/main/ui/src/main/java/org/cryptomator/ui/util/MasterKeyFilter.java +++ /dev/null @@ -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 { - - 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 filteredDirectory(Path dir) throws IOException { - return Files.newDirectoryStream(dir, FILTER); - } - -} diff --git a/main/ui/src/main/resources/fxml/initialize.fxml b/main/ui/src/main/resources/fxml/initialize.fxml index fed9f1816..7b4b7791a 100644 --- a/main/ui/src/main/resources/fxml/initialize.fxml +++ b/main/ui/src/main/resources/fxml/initialize.fxml @@ -30,22 +30,18 @@ -