mirror of
https://github.com/cryptomator/cryptomator.git
synced 2026-04-21 01:56:55 -04:00
- Fixed "return" key in unlock view
- Fixed password field focus - Don't show unlock error messages from one vault, when switching to another vault - Hide advanced mount options by default (preparation for things like #74)
This commit is contained in:
@@ -129,12 +129,12 @@
|
||||
<dependency>
|
||||
<groupId>com.google.dagger</groupId>
|
||||
<artifactId>dagger</artifactId>
|
||||
<version>2.0</version>
|
||||
<version>2.0.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.dagger</groupId>
|
||||
<artifactId>dagger-compiler</artifactId>
|
||||
<version>2.0</version>
|
||||
<version>2.0.1</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
|
||||
@@ -42,6 +42,7 @@ import javafx.scene.control.Hyperlink;
|
||||
import javafx.scene.control.ProgressIndicator;
|
||||
import javafx.scene.control.TextField;
|
||||
import javafx.scene.input.KeyEvent;
|
||||
import javafx.scene.layout.GridPane;
|
||||
import javafx.scene.text.Text;
|
||||
|
||||
public class UnlockController extends AbstractFXMLViewController {
|
||||
@@ -57,6 +58,9 @@ public class UnlockController extends AbstractFXMLViewController {
|
||||
@FXML
|
||||
private TextField mountName;
|
||||
|
||||
@FXML
|
||||
private Button advancedOptionsButton;
|
||||
|
||||
@FXML
|
||||
private Button unlockButton;
|
||||
|
||||
@@ -69,6 +73,9 @@ public class UnlockController extends AbstractFXMLViewController {
|
||||
@FXML
|
||||
private Hyperlink downloadsPageLink;
|
||||
|
||||
@FXML
|
||||
private GridPane advancedOptions;
|
||||
|
||||
private final ExecutorService exec;
|
||||
private final Application app;
|
||||
|
||||
@@ -93,6 +100,17 @@ public class UnlockController extends AbstractFXMLViewController {
|
||||
passwordField.textProperty().addListener(this::passwordFieldsDidChange);
|
||||
mountName.addEventFilter(KeyEvent.KEY_TYPED, this::filterAlphanumericKeyEvents);
|
||||
mountName.textProperty().addListener(this::mountNameDidChange);
|
||||
advancedOptions.managedProperty().bind(advancedOptions.visibleProperty());
|
||||
}
|
||||
|
||||
private void resetView() {
|
||||
unlockButton.setDisable(true);
|
||||
advancedOptions.setVisible(false);
|
||||
advancedOptionsButton.setText(resourceBundle.getString("unlock.button.advancedOptions.show"));
|
||||
progressIndicator.setVisible(false);
|
||||
passwordField.clear();
|
||||
downloadsPageLink.setVisible(false);
|
||||
messageText.setText(null);
|
||||
}
|
||||
|
||||
// ****************************************
|
||||
@@ -113,6 +131,20 @@ public class UnlockController extends AbstractFXMLViewController {
|
||||
app.getHostServices().showDocument("https://cryptomator.org/downloads/");
|
||||
}
|
||||
|
||||
// ****************************************
|
||||
// Advanced options button
|
||||
// ****************************************
|
||||
|
||||
@FXML
|
||||
private void didClickAdvancedOptionsButton(ActionEvent event) {
|
||||
advancedOptions.setVisible(!advancedOptions.isVisible());
|
||||
if (advancedOptions.isVisible()) {
|
||||
advancedOptionsButton.setText(resourceBundle.getString("unlock.button.advancedOptions.hide"));
|
||||
} else {
|
||||
advancedOptionsButton.setText(resourceBundle.getString("unlock.button.advancedOptions.show"));
|
||||
}
|
||||
}
|
||||
|
||||
// ****************************************
|
||||
// Unlock button
|
||||
// ****************************************
|
||||
@@ -138,23 +170,14 @@ public class UnlockController extends AbstractFXMLViewController {
|
||||
final Future<Boolean> futureMount = exec.submit(() -> (boolean) vault.mount());
|
||||
FXThreads.runOnMainThreadWhenFinished(exec, futureMount, this::unlockAndMountFinished);
|
||||
} catch (IOException ex) {
|
||||
setControlsDisabled(false);
|
||||
progressIndicator.setVisible(false);
|
||||
messageText.setText(resourceBundle.getString("unlock.errorMessage.decryptionFailed"));
|
||||
LOG.error("Decryption failed for technical reasons.", ex);
|
||||
} catch (WrongPasswordException e) {
|
||||
setControlsDisabled(false);
|
||||
progressIndicator.setVisible(false);
|
||||
messageText.setText(resourceBundle.getString("unlock.errorMessage.wrongPassword"));
|
||||
Platform.runLater(passwordField::requestFocus);
|
||||
} catch (UnsupportedKeyLengthException ex) {
|
||||
setControlsDisabled(false);
|
||||
progressIndicator.setVisible(false);
|
||||
messageText.setText(resourceBundle.getString("unlock.errorMessage.unsupportedKeyLengthInstallJCE"));
|
||||
LOG.warn("Unsupported Key-Length. Please install Oracle Java Cryptography Extension (JCE).", ex);
|
||||
} catch (UnsupportedVaultException e) {
|
||||
setControlsDisabled(false);
|
||||
progressIndicator.setVisible(false);
|
||||
downloadsPageLink.setVisible(true);
|
||||
if (e.isVaultOlderThanSoftware()) {
|
||||
messageText.setText(resourceBundle.getString("unlock.errorMessage.unsupportedVersion.vaultOlderThanSoftware") + " ");
|
||||
@@ -162,11 +185,12 @@ public class UnlockController extends AbstractFXMLViewController {
|
||||
messageText.setText(resourceBundle.getString("unlock.errorMessage.unsupportedVersion.softwareOlderThanVault") + " ");
|
||||
}
|
||||
} catch (DestroyFailedException e) {
|
||||
setControlsDisabled(false);
|
||||
progressIndicator.setVisible(false);
|
||||
LOG.error("Destruction of cryptor threw an exception.", e);
|
||||
} finally {
|
||||
setControlsDisabled(false);
|
||||
progressIndicator.setVisible(false);
|
||||
passwordField.swipe();
|
||||
Platform.runLater(passwordField::requestFocus);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -174,6 +198,7 @@ public class UnlockController extends AbstractFXMLViewController {
|
||||
passwordField.setDisable(disable);
|
||||
mountName.setDisable(disable);
|
||||
unlockButton.setDisable(disable);
|
||||
advancedOptionsButton.setDisable(disable);
|
||||
}
|
||||
|
||||
private void unlockAndMountFinished(boolean mountSuccess) {
|
||||
@@ -214,9 +239,9 @@ public class UnlockController extends AbstractFXMLViewController {
|
||||
}
|
||||
|
||||
public void setVault(Vault vault) {
|
||||
this.resetView();
|
||||
this.vault = vault;
|
||||
this.mountName.setText(vault.getMountName());
|
||||
this.passwordField.clear();
|
||||
}
|
||||
|
||||
public UnlockListener getListener() {
|
||||
|
||||
@@ -16,18 +16,18 @@ import javafx.scene.control.PasswordField;
|
||||
* Compromise in security. While the text can be swiped, any access to the {@link #getText()} method will create a copy of the String in the heap.
|
||||
*/
|
||||
public class SecPasswordField extends PasswordField {
|
||||
|
||||
|
||||
private static final char SWIPE_CHAR = ' ';
|
||||
|
||||
|
||||
/**
|
||||
* {@link #getContent()} uses a StringBuilder, which in turn is backed by a char[].
|
||||
* The delete operation of AbstractStringBuilder closes the gap, that forms by deleting chars, by moving up the following chars.
|
||||
* <br/>
|
||||
* Imagine the following example with <code>pass</code> being the password, <code>x</code> being the swipe char and <code>'</code> being the offset of the char array:
|
||||
* <ol>
|
||||
* <li>Append filling chars to the end of the password: <code>passxxxx'</code></li>
|
||||
* <li>Delete first 4 chars. Internal implementation will then copy the following chars to the position, where the deletion occured: <code>xxxx'xxxx</code></li>
|
||||
* <li>Delete first 4 chars again, as we appended 4 chars in step 1: <code>'xxxxxx</code></li>
|
||||
* <li>Append filling chars to the end of the password: <code>passxxxx'</code></li>
|
||||
* <li>Delete first 4 chars. Internal implementation will then copy the following chars to the position, where the deletion occured: <code>xxxx'xxxx</code></li>
|
||||
* <li>Delete first 4 chars again, as we appended 4 chars in step 1: <code>'xxxxxx</code></li>
|
||||
* </ol>
|
||||
*/
|
||||
public void swipe() {
|
||||
@@ -37,8 +37,8 @@ public class SecPasswordField extends PasswordField {
|
||||
this.getContent().insert(pwLength, new String(fillingChars), false);
|
||||
this.getContent().delete(0, pwLength, true);
|
||||
this.getContent().delete(0, pwLength, true);
|
||||
// previous text has now been overwritten. still we need to update the text to trigger some property bindings:
|
||||
this.setText("");
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -225,6 +225,22 @@
|
||||
-fx-font-size: 0.8em;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* *
|
||||
* Separator *
|
||||
* *
|
||||
****************************************************************************/
|
||||
|
||||
.separator .line {
|
||||
-fx-border-style: solid;
|
||||
-fx-border-width: 1px;
|
||||
-fx-background-color: null;
|
||||
}
|
||||
|
||||
.separator:horizontal .line {
|
||||
-fx-border-color: COLOR_BORDER transparent transparent transparent;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* *
|
||||
* CheckBox *
|
||||
|
||||
@@ -291,6 +291,22 @@
|
||||
-fx-font-size: 0.8em;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* *
|
||||
* Separator *
|
||||
* *
|
||||
****************************************************************************/
|
||||
|
||||
.separator .line {
|
||||
-fx-border-style: solid;
|
||||
-fx-border-width: 1px;
|
||||
-fx-background-color: null;
|
||||
}
|
||||
|
||||
.separator:horizontal .line {
|
||||
-fx-border-color: COLOR_BORDER transparent transparent transparent;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* *
|
||||
* CheckBox *
|
||||
|
||||
@@ -281,6 +281,22 @@
|
||||
-fx-font-size: 0.9em;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* *
|
||||
* Separator *
|
||||
* *
|
||||
****************************************************************************/
|
||||
|
||||
.separator .line {
|
||||
-fx-border-style: solid;
|
||||
-fx-border-width: 1px;
|
||||
-fx-background-color: null;
|
||||
}
|
||||
|
||||
.separator:horizontal .line {
|
||||
-fx-border-color: COLOR_BORDER transparent transparent transparent;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* *
|
||||
* CheckBox *
|
||||
|
||||
@@ -21,6 +21,8 @@
|
||||
<?import javafx.scene.text.TextFlow?>
|
||||
<?import javafx.scene.control.Hyperlink?>
|
||||
<?import javafx.scene.text.Text?>
|
||||
<?import javafx.scene.layout.HBox?>
|
||||
<?import javafx.scene.control.Separator?>
|
||||
|
||||
<GridPane vgap="12.0" hgap="12.0" prefWidth="400.0" xmlns:fx="http://javafx.com/fxml">
|
||||
<padding>
|
||||
@@ -36,24 +38,52 @@
|
||||
<!-- Row 0 -->
|
||||
<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.mountName" GridPane.rowIndex="1" GridPane.columnIndex="0" />
|
||||
<TextField fx:id="mountName" GridPane.rowIndex="1" GridPane.columnIndex="1" GridPane.hgrow="ALWAYS" maxWidth="Infinity" />
|
||||
<HBox GridPane.rowIndex="2" GridPane.columnIndex="0" GridPane.columnSpan="2" spacing="12.0" alignment="CENTER_RIGHT">
|
||||
<Button fx:id="advancedOptionsButton" text="%unlock.button.advancedOptions.show" prefWidth="150.0" onAction="#didClickAdvancedOptionsButton"/>
|
||||
<Button fx:id="unlockButton" text="%unlock.button.unlock" defaultButton="true" prefWidth="150.0" onAction="#didClickUnlockButton" disable="true"/>
|
||||
</HBox>
|
||||
|
||||
<!-- Row 2 -->
|
||||
<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" disable="true"/>
|
||||
|
||||
<!-- Row 3-->
|
||||
<ProgressIndicator progress="-1" fx:id="progressIndicator" GridPane.rowIndex="3" GridPane.columnIndex="0" GridPane.columnSpan="2" GridPane.halignment="CENTER" visible="false"/>
|
||||
<!-- Row 3 -->
|
||||
<GridPane fx:id="advancedOptions" vgap="12.0" hgap="12.0" prefWidth="400.0" GridPane.rowIndex="3" GridPane.columnIndex="0" GridPane.columnSpan="2" visible="false">
|
||||
<padding>
|
||||
<Insets top="24.0" />
|
||||
</padding>
|
||||
|
||||
<columnConstraints>
|
||||
<ColumnConstraints percentWidth="38.2"/>
|
||||
<ColumnConstraints percentWidth="61.8"/>
|
||||
</columnConstraints>
|
||||
|
||||
<!-- Row 3.0 -->
|
||||
<Separator GridPane.rowIndex="0" GridPane.columnIndex="0" GridPane.columnSpan="2" />
|
||||
<HBox alignment="CENTER" prefWidth="400.0" GridPane.rowIndex="0" GridPane.columnIndex="0" GridPane.columnSpan="2">
|
||||
<Label text="%unlock.label.advancedHeading" style="-fx-background-color: COLOR_BACKGROUND;">
|
||||
<padding>
|
||||
<Insets left="6.0" right="6.0"/>
|
||||
</padding>
|
||||
</Label>
|
||||
</HBox>
|
||||
|
||||
<!-- Row 3.1 -->
|
||||
<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" />
|
||||
</GridPane>
|
||||
|
||||
<!-- Row 4 -->
|
||||
<TextFlow GridPane.rowIndex="4" GridPane.columnIndex="0" GridPane.columnSpan="2" >
|
||||
<TextFlow GridPane.rowIndex="4" GridPane.columnIndex="0" GridPane.columnSpan="2">
|
||||
<GridPane.margin>
|
||||
<Insets top="24.0"/>
|
||||
</GridPane.margin>
|
||||
<children>
|
||||
<Text fx:id="messageText" />
|
||||
<Text fx:id="messageText" text="asd"/>
|
||||
<Hyperlink fx:id="downloadsPageLink" text="%unlock.label.downloadsPageLink" visible="false" onAction="#didClickDownloadsLink" />
|
||||
</children>
|
||||
</TextFlow>
|
||||
|
||||
<!-- Row 5-->
|
||||
<ProgressIndicator progress="-1" fx:id="progressIndicator" GridPane.rowIndex="5" GridPane.columnIndex="0" GridPane.columnSpan="2" GridPane.halignment="CENTER" />
|
||||
</children>
|
||||
</GridPane>
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
|
||||
<!-- Row 1 -->
|
||||
<Label fx:id="messageLabel" GridPane.rowIndex="1" GridPane.columnIndex="0" />
|
||||
<Button text="%unlocked.button.lock" defaultButton="true" GridPane.rowIndex="1" GridPane.columnIndex="1" GridPane.halignment="RIGHT" prefWidth="150.0" onAction="#didClickCloseVault" focusTraversable="false"/>
|
||||
<Button text="%unlocked.button.lock" GridPane.rowIndex="1" GridPane.columnIndex="1" GridPane.halignment="RIGHT" prefWidth="150.0" onAction="#didClickCloseVault" focusTraversable="false"/>
|
||||
</children>
|
||||
</GridPane>
|
||||
|
||||
|
||||
@@ -31,7 +31,10 @@ initialize.button.ok=Create vault
|
||||
unlock.label.password=Password
|
||||
unlock.label.mountName=Drive name
|
||||
unlock.label.downloadsPageLink=All Cryptomator versions
|
||||
unlock.label.advancedHeading=Advanced options
|
||||
unlock.button.unlock=Unlock vault
|
||||
unlock.button.advancedOptions.show=More options
|
||||
unlock.button.advancedOptions.hide=Less options
|
||||
unlock.errorMessage.wrongPassword=Wrong password.
|
||||
unlock.errorMessage.decryptionFailed=Decryption failed.
|
||||
unlock.errorMessage.unsupportedKeyLengthInstallJCE=Decryption failed. Please install Oracle JCE Unlimited Strength Policy.
|
||||
|
||||
Reference in New Issue
Block a user