mirror of
https://github.com/cryptomator/cryptomator.git
synced 2026-05-14 08:41:28 +00:00
removed multi user functionality (see #21)
using fixed masterkey filename now
This commit is contained in:
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -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<? 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));
|
||||
}
|
||||
|
||||
// ****************************************
|
||||
// Retype password field
|
||||
// ****************************************
|
||||
|
||||
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);
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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() {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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" />
|
||||
<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 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"/>
|
||||
<!-- Row 3-->
|
||||
<ProgressIndicator progress="-1" fx:id="progressIndicator" GridPane.rowIndex="3" GridPane.columnIndex="0" GridPane.columnSpan="2" GridPane.halignment="CENTER" visible="false"/>
|
||||
|
||||
<!-- Row 4-->
|
||||
<ProgressIndicator progress="-1" fx:id="progressIndicator" GridPane.rowIndex="4" 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>
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user