Pimped Password Field

Added reveal icon as well, capslock warnings as well a warning for unprintable chars (fixes #458)
This commit is contained in:
Sebastian Stenzel
2019-09-04 17:16:24 +02:00
parent 9c104beeba
commit efaf5a1553
20 changed files with 242 additions and 108 deletions

View File

@@ -28,6 +28,7 @@ public class Environment {
@Inject
public Environment() {
LOG.debug("java.library.path: {}", System.getProperty("java.library.path"));
LOG.debug("user.language: {}", System.getProperty("user.language"));
LOG.debug("user.region: {}", System.getProperty("user.region"));
LOG.debug("logback.configurationFile: {}", System.getProperty("logback.configurationFile"));

View File

@@ -28,7 +28,7 @@ import org.cryptomator.ui.common.FxmlFile;
import org.cryptomator.ui.common.FxmlScene;
import org.cryptomator.ui.common.Tasks;
import org.cryptomator.ui.controls.FontAwesome5IconView;
import org.cryptomator.ui.controls.SecPasswordField;
import org.cryptomator.ui.controls.NiceSecurePasswordField;
import org.cryptomator.ui.util.PasswordStrengthUtil;
import org.fxmisc.easybind.EasyBind;
import org.slf4j.Logger;
@@ -71,8 +71,8 @@ public class CreateNewVaultPasswordController implements FxController {
private final BooleanProperty readyToCreateVault;
private final ObjectBinding<ContentDisplay> createVaultButtonState;
public SecPasswordField passwordField;
public SecPasswordField reenterField;
public NiceSecurePasswordField passwordField;
public NiceSecurePasswordField reenterField;
public Label passwordStrengthLabel;
public HBox passwordMatchBox;
public FontAwesome5IconView checkmark;

View File

@@ -14,7 +14,7 @@ import org.cryptomator.common.vaults.Vault;
import org.cryptomator.cryptolib.api.InvalidPassphraseException;
import org.cryptomator.ui.common.FxController;
import org.cryptomator.ui.controls.FontAwesome5IconView;
import org.cryptomator.ui.controls.SecPasswordField;
import org.cryptomator.ui.controls.NiceSecurePasswordField;
import org.cryptomator.ui.util.PasswordStrengthUtil;
import org.fxmisc.easybind.EasyBind;
import org.slf4j.Logger;
@@ -35,9 +35,9 @@ public class ChangePasswordController implements FxController {
private final PasswordStrengthUtil strengthRater;
private final IntegerProperty passwordStrength;
public SecPasswordField oldPasswordField;
public SecPasswordField newPasswordField;
public SecPasswordField reenterPasswordField;
public NiceSecurePasswordField oldPasswordField;
public NiceSecurePasswordField newPasswordField;
public NiceSecurePasswordField reenterPasswordField;
public Label passwordStrengthLabel;
public HBox passwordMatchBox;
public FontAwesome5IconView checkmark;
@@ -71,7 +71,6 @@ public class ChangePasswordController implements FxController {
cross.visibleProperty().bind(passwordsMatch.not().and(reenterFieldNotEmpty));
cross.managedProperty().bind(cross.visibleProperty());
passwordMatchLabel.textProperty().bind(Bindings.when(passwordsMatch.and(reenterFieldNotEmpty)).then(resourceBundle.getString("changepassword.passwordsMatch")).otherwise(resourceBundle.getString("changepassword.passwordsDoNotMatch")));
passwordStrengthLabel.textProperty().bind(EasyBind.map(passwordStrength, strengthRater::getStrengthDescription));
}

View File

@@ -25,7 +25,7 @@ import javafx.scene.layout.Region;
import javafx.scene.text.Text;
import org.cryptomator.cryptolib.api.InvalidPassphraseException;
import org.cryptomator.cryptolib.api.UnsupportedVaultFormatException;
import org.cryptomator.ui.controls.SecPasswordField;
import org.cryptomator.ui.controls.SecurePasswordField;
import org.cryptomator.ui.l10n.Localization;
import org.cryptomator.common.vaults.Vault;
import org.cryptomator.ui.util.PasswordStrengthUtil;
@@ -58,13 +58,13 @@ public class ChangePasswordController implements ViewController {
}
@FXML
private SecPasswordField oldPasswordField;
private SecurePasswordField oldPasswordField;
@FXML
private SecPasswordField newPasswordField;
private SecurePasswordField newPasswordField;
@FXML
private SecPasswordField retypePasswordField;
private SecurePasswordField retypePasswordField;
@FXML
private Button changePasswordButton;

View File

@@ -20,7 +20,7 @@ import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.Region;
import org.cryptomator.ui.controls.SecPasswordField;
import org.cryptomator.ui.controls.SecurePasswordField;
import org.cryptomator.ui.l10n.Localization;
import org.cryptomator.common.vaults.Vault;
import org.cryptomator.ui.util.PasswordStrengthUtil;
@@ -51,10 +51,10 @@ public class InitializeController implements ViewController {
}
@FXML
private SecPasswordField passwordField;
private SecurePasswordField passwordField;
@FXML
private SecPasswordField retypePasswordField;
private SecurePasswordField retypePasswordField;
@FXML
private Button okButton;

View File

@@ -41,7 +41,7 @@ import org.cryptomator.cryptolib.api.InvalidPassphraseException;
import org.cryptomator.cryptolib.api.UnsupportedVaultFormatException;
import org.cryptomator.keychain.KeychainAccess;
import org.cryptomator.keychain.KeychainAccessException;
import org.cryptomator.ui.controls.SecPasswordField;
import org.cryptomator.ui.controls.SecurePasswordField;
import org.cryptomator.ui.l10n.Localization;
import org.cryptomator.common.vaults.Vault;
import org.cryptomator.common.vaults.WindowsDriveLetters;
@@ -99,7 +99,7 @@ public class UnlockController implements ViewController {
}
@FXML
private SecPasswordField passwordField;
private SecurePasswordField passwordField;
@FXML
private Button advancedOptionsButton;

View File

@@ -21,7 +21,7 @@ import javafx.scene.control.CheckBox;
import javafx.scene.control.Label;
import javafx.scene.control.ProgressIndicator;
import javafx.scene.layout.GridPane;
import org.cryptomator.ui.controls.SecPasswordField;
import org.cryptomator.ui.controls.SecurePasswordField;
import org.cryptomator.ui.model.upgrade.UpgradeStrategies;
import org.cryptomator.ui.model.upgrade.UpgradeStrategy;
import org.cryptomator.ui.model.upgrade.UpgradeStrategy.UpgradeFailedException;
@@ -50,7 +50,7 @@ public class UpgradeController implements ViewController {
private Label upgradeMsgLabel;
@FXML
private SecPasswordField passwordField;
private SecurePasswordField passwordField;
@FXML
private CheckBox confirmationCheckbox;

View File

@@ -5,11 +5,13 @@ package org.cryptomator.ui.controls;
*/
public enum FontAwesome5Icon {
ANCHOR("\uF13D"), //
ARROW_ALT_UP("\uF357"), //
CHECK("\uF00C"), //
COG("\uF013"), //
COGS("\uF085"), //
EXCLAMATION_TRIANGLE("\uF071"), //
EYE("\uF06E"), //
EYE_SLASH("\uF070"), //
FOLDER_OPEN("\uF07C"), //
HDD("\uF0A0"), //
KEY("\uF084"), //

View File

@@ -0,0 +1,89 @@
package org.cryptomator.ui.controls;
import javafx.beans.binding.Bindings;
import javafx.beans.property.StringProperty;
import javafx.geometry.Pos;
import javafx.scene.control.ContentDisplay;
import javafx.scene.control.ToggleButton;
import javafx.scene.layout.HBox;
import javafx.scene.layout.StackPane;
public class NiceSecurePasswordField extends StackPane {
private static final String STYLE_CLASS = "nice-secure-password-field";
private static final String ICONS_STLYE_CLASS = "icons";
private static final String REVEAL_BUTTON_STLYE_CLASS = "reveal-button";
private static final int ICON_SPACING = 6;
private static final double ICON_SIZE = 14.0;
private final SecurePasswordField passwordField = new SecurePasswordField();
private final FontAwesome5IconView capsLockedIcon = new FontAwesome5IconView();
private final FontAwesome5IconView nonPrintableCharsIcon = new FontAwesome5IconView();
private final FontAwesome5IconView revealPasswordIcon = new FontAwesome5IconView();
private final ToggleButton revealPasswordButton = new ToggleButton(null, revealPasswordIcon);
private final HBox iconContainer = new HBox(ICON_SPACING, nonPrintableCharsIcon, capsLockedIcon, revealPasswordButton);
public NiceSecurePasswordField() {
getStyleClass().add(STYLE_CLASS);
iconContainer.setAlignment(Pos.CENTER_RIGHT);
iconContainer.setMaxWidth(Double.NEGATIVE_INFINITY);
iconContainer.setPrefWidth(42); // TODO
iconContainer.getStyleClass().add(ICONS_STLYE_CLASS);
StackPane.setAlignment(iconContainer, Pos.CENTER_RIGHT);
capsLockedIcon.setGlyph(FontAwesome5Icon.ARROW_ALT_UP);
capsLockedIcon.setGlyphSize(ICON_SIZE);
capsLockedIcon.visibleProperty().bind(passwordField.capsLockedProperty());
capsLockedIcon.managedProperty().bind(passwordField.capsLockedProperty());
nonPrintableCharsIcon.setGlyph(FontAwesome5Icon.EXCLAMATION_TRIANGLE);
nonPrintableCharsIcon.setGlyphSize(ICON_SIZE);
nonPrintableCharsIcon.visibleProperty().bind(passwordField.containingNonPrintableCharsProperty());
nonPrintableCharsIcon.managedProperty().bind(passwordField.containingNonPrintableCharsProperty());
revealPasswordIcon.setGlyph(FontAwesome5Icon.EYE);
revealPasswordIcon.glyphProperty().bind(Bindings.createObjectBinding(this::getRevealPasswordGlyph, revealPasswordButton.selectedProperty()));
revealPasswordIcon.setGlyphSize(ICON_SIZE);
revealPasswordButton.setContentDisplay(ContentDisplay.LEFT);
revealPasswordButton.setFocusTraversable(false);
revealPasswordButton.visibleProperty().bind(passwordField.focusedProperty());
revealPasswordButton.managedProperty().bind(passwordField.focusedProperty());
revealPasswordButton.getStyleClass().add(REVEAL_BUTTON_STLYE_CLASS);
passwordField.revealPasswordProperty().bind(revealPasswordButton.selectedProperty());
getChildren().addAll(passwordField, iconContainer);
}
private FontAwesome5Icon getRevealPasswordGlyph() {
return revealPasswordButton.isSelected() ? FontAwesome5Icon.EYE_SLASH : FontAwesome5Icon.EYE;
}
/* Passthrough */
public StringProperty textProperty() {
return passwordField.textProperty();
}
public CharSequence getCharacters() {
return passwordField.getCharacters();
}
public void setPassword(char[] password) {
passwordField.setPassword(password);
}
public void swipe() {
passwordField.swipe();;
}
public void selectAll() {
passwordField.selectAll();
}
public void selectRange(int anchor, int caretPosition) {
passwordField.selectRange(anchor, caretPosition);
}
}

View File

@@ -11,20 +11,19 @@ package org.cryptomator.ui.controls;
import com.google.common.base.Strings;
import javafx.beans.NamedArg;
import javafx.beans.Observable;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.control.Label;
import javafx.scene.control.OverrunStyle;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.ReadOnlyBooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.scene.AccessibleAttribute;
import javafx.scene.AccessibleRole;
import javafx.scene.control.IndexRange;
import javafx.scene.control.PasswordField;
import javafx.scene.control.Tooltip;
import javafx.scene.control.TextField;
import javafx.scene.input.DragEvent;
import javafx.scene.input.Dragboard;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.input.TransferMode;
import javafx.scene.paint.Color;
import javafx.scene.text.Font;
import javafx.scene.text.Text;
import java.awt.Toolkit;
import java.nio.CharBuffer;
@@ -33,53 +32,54 @@ import java.text.Normalizer.Form;
import java.util.Arrays;
/**
* Patched PasswordField that doesn't create String copies of the password in memory. Instead the password is stored in a char[] that can be swiped.
* Patched PasswordField that doesn't create String copies of the password in memory (unless explicitly revealed). Instead the password is stored in a char[] that can be swiped.
*
* @implNote Since {@link #setText(String)} is final, we can not override its behaviour. For that reason you should not use the {@link #textProperty()} for anything else than display purposes.
*/
public class SecPasswordField extends PasswordField {
public class SecurePasswordField extends TextField {
private static final char SWIPE_CHAR = ' ';
private static final int INITIAL_BUFFER_SIZE = 50;
private static final int GROW_BUFFER_SIZE = 50;
private static final String PLACEHOLDER = "*";
private static final double PADDING = 2.0;
private static final double INDICATOR_PADDING = 4.0;
private static final Color INDICATOR_COLOR = new Color(0.901, 0.494, 0.133, 1.0);
private static final String DEFAULT_PLACEHOLDER = "";
private static final String STYLE_CLASS = "secure-password-field";
private final Tooltip tooltip = new Tooltip();
private final Label indicator = new Label();
private final String nonPrintableCharsWarning;
private final String capslockWarning;
private final String placeholderChar;
private final BooleanProperty capsLocked = new SimpleBooleanProperty();
private final BooleanProperty containingNonPrintableChars = new SimpleBooleanProperty();
private final BooleanProperty revealPassword = new SimpleBooleanProperty();
private char[] content = new char[INITIAL_BUFFER_SIZE];
private int length = 0;
public SecPasswordField() {
this("", "");
public SecurePasswordField() {
this(DEFAULT_PLACEHOLDER);
}
public SecPasswordField(@NamedArg("nonPrintableCharsWarning") String nonPrintableCharsWarning, @NamedArg("capslockWarning") String capslockWarning) {
this.nonPrintableCharsWarning = nonPrintableCharsWarning;
this.capslockWarning = capslockWarning;
indicator.setPadding(new Insets(PADDING, INDICATOR_PADDING, PADDING, INDICATOR_PADDING));
indicator.setAlignment(Pos.CENTER_RIGHT);
indicator.setMouseTransparent(true);
indicator.setTextOverrun(OverrunStyle.CLIP);
indicator.setTextFill(INDICATOR_COLOR);
indicator.setFont(Font.font(indicator.getFont().getFamily(), 15.0));
this.getChildren().add(indicator);
public SecurePasswordField(@NamedArg("placeholderChar") String placeholderChar) {
this.getStyleClass().add(STYLE_CLASS);
this.placeholderChar = placeholderChar;
this.setAccessibleRole(AccessibleRole.PASSWORD_FIELD);
this.addEventHandler(DragEvent.DRAG_OVER, this::handleDragOver);
this.addEventHandler(DragEvent.DRAG_DROPPED, this::handleDragDropped);
this.addEventHandler(KeyEvent.ANY, this::handleKeyEvent);
this.revealPasswordProperty().addListener(this::revealPasswordChanged);
this.focusedProperty().addListener(this::focusedChanged);
}
@Override
protected void layoutChildren() {
super.layoutChildren();
indicator.relocate(0.0, 0.0);
indicator.resize(getWidth(), getHeight());
public void cut() {
}
public void copy() {
}
public Object queryAccessibleAttribute(AccessibleAttribute attribute, Object... parameters) {
switch(attribute) {
case TEXT:
return null;
default:
return super.queryAccessibleAttribute(attribute, parameters);
}
}
private void handleDragOver(DragEvent event) {
@@ -100,42 +100,32 @@ public class SecPasswordField extends PasswordField {
private void handleKeyEvent(KeyEvent e) {
if (e.getCode() == KeyCode.CAPS) {
updateVisualHints(true);
updateCapsLocked();
}
}
private void revealPasswordChanged(@SuppressWarnings("unused") Observable observable) {
IndexRange selection = getSelection();
if (isRevealPassword()) {
super.setText(this.getCharacters().toString());
} else {
String placeholderText = Strings.repeat(placeholderChar, length);
super.setText(placeholderText);
}
selectRange(selection.getStart(), selection.getEnd());
}
private void focusedChanged(@SuppressWarnings("unused") Observable observable) {
updateVisualHints(isFocused());
updateCapsLocked();
}
private void updateVisualHints(boolean focused) {
StringBuilder tooltipSb = new StringBuilder();
StringBuilder indicatorSb = new StringBuilder();
if (containsNonPrintableCharacters()) {
indicatorSb.append('⚠');
tooltipSb.append("- ").append(nonPrintableCharsWarning).append('\n');
}
private void updateCapsLocked() {
// AWT code needed until https://bugs.openjdk.java.net/browse/JDK-8090882 is closed:
if (focused && Toolkit.getDefaultToolkit().getLockingKeyState(java.awt.event.KeyEvent.VK_CAPS_LOCK)) {
indicatorSb.append('⇪');
tooltipSb.append("- ").append(capslockWarning).append('\n');
}
indicator.setText(indicatorSb.toString());
if (!indicator.getText().isEmpty()) {
setPadding(new Insets(PADDING, getIndicatorWidth(), PADDING, PADDING));
} else {
setPadding(new Insets(PADDING));
}
tooltip.setText(tooltipSb.toString());
if (tooltip.getText().isEmpty()) {
setTooltip(null);
} else {
setTooltip(tooltip);
}
capsLocked.set(isFocused() && Toolkit.getDefaultToolkit().getLockingKeyState(java.awt.event.KeyEvent.VK_CAPS_LOCK));
}
private double getIndicatorWidth() {
return new Text(indicator.getText()).getLayoutBounds().getWidth() + INDICATOR_PADDING * 2.0;
private void updateContainingNonPrintableChars() {
containingNonPrintableChars.set(containsNonPrintableCharacters());
}
/**
@@ -144,7 +134,7 @@ public class SecPasswordField extends PasswordField {
*/
boolean containsNonPrintableCharacters() {
for (int i = 0; i < length; i++) {
if (Character.isISOControl(content[i])) {
if (Character.isDigit(content[i])) {
return true;
}
}
@@ -183,9 +173,13 @@ public class SecPasswordField extends PasswordField {
normalizedText.getChars(0, normalizedText.length(), content, start);
// trigger visual hints
updateVisualHints(true);
String placeholderString = Strings.repeat(PLACEHOLDER, normalizedText.length());
super.replaceText(start, end, placeholderString);
updateContainingNonPrintableChars();
if (isRevealPassword()) {
super.replaceText(start, end, text);
} else {
String placeholderString = Strings.repeat(placeholderChar, normalizedText.length());
super.replaceText(start, end, placeholderString);
}
}
private void growContentIfNeeded() {
@@ -200,9 +194,9 @@ public class SecPasswordField extends PasswordField {
/**
* Creates a CharSequence by wrapping the password characters.
*
* @return A character sequence backed by the SecPasswordField's buffer (not a copy).
* @return A character sequence backed by the SecurePasswordField's buffer (not a copy).
* @implNote The CharSequence will not copy the backing char[].
* Therefore any mutation to the SecPasswordField's content will mutate or eventually swipe the returned CharSequence.
* Therefore any mutation to the SecurePasswordField's content will mutate or eventually swipe the returned CharSequence.
* @implSpec The CharSequence is usually in <a href="https://www.unicode.org/glossary/#normalization_form_c">NFC</a> representation (unless NFD-encoded char[] is set via {@link #setPassword(char[])}).
* @see #swipe()
*/
@@ -238,7 +232,7 @@ public class SecPasswordField extends PasswordField {
content = Arrays.copyOf(password, password.length);
length = password.length;
String placeholderString = Strings.repeat(PLACEHOLDER, password.length);
String placeholderString = Strings.repeat(placeholderChar, password.length);
setText(placeholderString);
}
@@ -255,4 +249,33 @@ public class SecPasswordField extends PasswordField {
Arrays.fill(buffer, SWIPE_CHAR);
}
/* Observable Properties */
public ReadOnlyBooleanProperty capsLockedProperty() {
return capsLocked;
}
public boolean isCapsLocked() {
return capsLocked.get();
}
public ReadOnlyBooleanProperty containingNonPrintableCharsProperty() {
return containingNonPrintableChars;
}
public boolean isContainingNonPrintableChars() {
return containingNonPrintableChars.get();
}
public BooleanProperty revealPasswordProperty() {
return revealPassword;
}
public boolean isRevealPassword() {
return revealPassword.get();
}
public void setRevealPassword(boolean revealPassword) {
this.revealPassword.set(revealPassword);
}
}

View File

@@ -29,7 +29,8 @@ import org.cryptomator.ui.common.FxController;
import org.cryptomator.ui.common.FxmlFile;
import org.cryptomator.ui.common.FxmlScene;
import org.cryptomator.ui.common.Tasks;
import org.cryptomator.ui.controls.SecPasswordField;
import org.cryptomator.ui.controls.NiceSecurePasswordField;
import org.cryptomator.ui.controls.SecurePasswordField;
import org.cryptomator.ui.util.DialogBuilderUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -55,7 +56,7 @@ public class UnlockController implements FxController {
private final ResourceBundle resourceBundle;
private final Lazy<Scene> successScene;
private final BooleanProperty unlockButtonDisabled;
public SecPasswordField passwordField;
public NiceSecurePasswordField passwordField;
public CheckBox savePassword;
@Inject

View File

@@ -455,6 +455,15 @@
-fx-background-color: CONTROL_BORDER_DISABLED, CONTROL_BG_DISABLED;
}
.nice-secure-password-field .secure-password-field {
-fx-padding: 0.3em 48px 0.3em 0.5em;
}
.nice-secure-password-field .icons {
-fx-width: 42px;
-fx-padding: 4px 6px 4px 0;
}
/*******************************************************************************
* *
* Buttons *

View File

@@ -455,6 +455,15 @@
-fx-background-color: CONTROL_BORDER_DISABLED, CONTROL_BG_DISABLED;
}
.nice-secure-password-field .secure-password-field {
-fx-padding: 0.3em 48px 0.3em 0.5em;
}
.nice-secure-password-field .icons {
-fx-width: 42px;
-fx-padding: 4px 6px 4px 0;
}
/*******************************************************************************
* *
* Buttons *

View File

@@ -11,7 +11,8 @@
<?import javafx.scene.layout.VBox?>
<?import org.cryptomator.ui.controls.FontAwesome5IconView?>
<?import org.cryptomator.ui.controls.PasswordStrengthIndicator?>
<?import org.cryptomator.ui.controls.SecPasswordField?>
<?import org.cryptomator.ui.controls.SecurePasswordField?>
<?import org.cryptomator.ui.controls.NiceSecurePasswordField?>
<VBox xmlns="http://javafx.com/javafx"
xmlns:fx="http://javafx.com/fxml"
fx:controller="org.cryptomator.ui.addvaultwizard.CreateNewVaultPasswordController"
@@ -27,13 +28,13 @@
<VBox spacing="6">
<Label text="%addvaultwizard.new.enterPassword" labelFor="$passwordField"/>
<SecPasswordField fx:id="passwordField"/>
<NiceSecurePasswordField fx:id="passwordField"/>
<PasswordStrengthIndicator spacing="6" prefHeight="6" strength="${controller.passwordStrength}"/>
<Label fx:id="passwordStrengthLabel" styleClass="label-secondary" labelFor="$passwordField" alignment="CENTER_RIGHT" maxWidth="Infinity"/>
</VBox>
<VBox spacing="6">
<Label text="%addvaultwizard.new.reenterPassword" labelFor="$reenterField"/>
<SecPasswordField fx:id="reenterField"/>
<NiceSecurePasswordField fx:id="reenterField"/>
<HBox fx:id="passwordMatchBox" spacing="6" alignment="CENTER_RIGHT">
<FontAwesome5IconView fx:id="checkmark" styleClass="glyph-icon-primary" glyph="CHECK"/>
<FontAwesome5IconView fx:id="cross" styleClass="glyph-icon-red" glyph="TIMES"/>

View File

@@ -10,8 +10,8 @@
<?import javafx.scene.layout.VBox?>
<?import org.cryptomator.ui.controls.FontAwesome5IconView?>
<?import org.cryptomator.ui.controls.FormattedLabel?>
<?import org.cryptomator.ui.controls.NiceSecurePasswordField?>
<?import org.cryptomator.ui.controls.PasswordStrengthIndicator?>
<?import org.cryptomator.ui.controls.SecPasswordField?>
<VBox xmlns="http://javafx.com/javafx"
xmlns:fx="http://javafx.com/fxml"
fx:controller="org.cryptomator.ui.changepassword.ChangePasswordController"
@@ -24,20 +24,20 @@
<children>
<VBox spacing="6">
<FormattedLabel format="%changepassword.enterOldPassword" arg1="${controller.vault.displayableName}" wrapText="true"/>
<SecPasswordField fx:id="oldPasswordField"/>
<NiceSecurePasswordField fx:id="oldPasswordField"/>
</VBox>
<Region prefHeight="12" VBox.vgrow="NEVER"/>
<VBox spacing="6">
<Label labelFor="$newPasswordField" text="%changepassword.enterNewPassword"/>
<SecPasswordField fx:id="newPasswordField"/>
<NiceSecurePasswordField fx:id="newPasswordField"/>
<PasswordStrengthIndicator prefHeight="6" spacing="6" strength="${controller.passwordStrength}"/>
<Label fx:id="passwordStrengthLabel" styleClass="label-secondary" alignment="CENTER_RIGHT" maxWidth="Infinity"/>
</VBox>
<VBox spacing="6">
<Label labelFor="$reenterPasswordField" text="%changepassword.reenterNewPassword"/>
<SecPasswordField fx:id="reenterPasswordField"/>
<NiceSecurePasswordField fx:id="reenterPasswordField"/>
<HBox fx:id="passwordMatchBox" spacing="6" alignment="CENTER_RIGHT">
<FontAwesome5IconView fx:id="checkmark" styleClass="glyph-icon-primary" glyph="CHECK"/>
<FontAwesome5IconView fx:id="cross" styleClass="glyph-icon-red" glyph="TIMES"/>

View File

@@ -19,7 +19,7 @@
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.ProgressBar?>
<?import javafx.scene.control.ProgressIndicator?>
<?import org.cryptomator.ui.controls.SecPasswordField?>
<?import org.cryptomator.ui.controls.SecurePasswordField?>
<?import javafx.scene.layout.Region?>
<?import javafx.scene.layout.VBox?>
@@ -36,11 +36,11 @@
<children>
<!-- Row 0 -->
<Label GridPane.rowIndex="0" GridPane.columnIndex="0" text="%initialize.label.password" cacheShape="true" cache="true" />
<SecPasswordField fx:id="passwordField" capslockWarning="%ctrl.secPasswordField.capsLocked" nonPrintableCharsWarning="%ctrl.secPasswordField.nonPrintableChars" GridPane.rowIndex="0" GridPane.columnIndex="1" cacheShape="true" cache="true" />
<SecurePasswordField fx:id="passwordField" capslockWarning="%ctrl.secPasswordField.capsLocked" nonPrintableCharsWarning="%ctrl.secPasswordField.nonPrintableChars" GridPane.rowIndex="0" GridPane.columnIndex="1" cacheShape="true" cache="true" />
<!-- Row 1 -->
<Label GridPane.rowIndex="1" GridPane.columnIndex="0" text="%initialize.label.retypePassword" cacheShape="true" cache="true" />
<SecPasswordField fx:id="retypePasswordField" capslockWarning="%ctrl.secPasswordField.capsLocked" nonPrintableCharsWarning="%ctrl.secPasswordField.nonPrintableChars" GridPane.rowIndex="1" GridPane.columnIndex="1" cacheShape="true" cache="true" />
<SecurePasswordField fx:id="retypePasswordField" capslockWarning="%ctrl.secPasswordField.capsLocked" nonPrintableCharsWarning="%ctrl.secPasswordField.nonPrintableChars" GridPane.rowIndex="1" GridPane.columnIndex="1" cacheShape="true" cache="true" />
<!-- Row 2 -->
<VBox GridPane.columnIndex="1" GridPane.rowIndex="2" spacing="6.0">

View File

@@ -21,7 +21,7 @@
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.text.Text?>
<?import javafx.scene.text.TextFlow?>
<?import org.cryptomator.ui.controls.SecPasswordField?>
<?import org.cryptomator.ui.controls.SecurePasswordField?>
<VBox fx:controller="org.cryptomator.ui.controllers.UnlockController" fx:id="root" spacing="12" alignment="BOTTOM_CENTER" xmlns:fx="http://javafx.com/fxml" prefWidth="400">
<padding>
@@ -31,7 +31,7 @@
<!-- Password Field -->
<HBox spacing="12" alignment="BASELINE_LEFT">
<Label text="%unlock.label.password" HBox.hgrow="NEVER"/>
<SecPasswordField fx:id="passwordField" capslockWarning="%ctrl.secPasswordField.capsLocked" nonPrintableCharsWarning="%ctrl.secPasswordField.nonPrintableChars" maxWidth="Infinity" HBox.hgrow="ALWAYS"/>
<SecurePasswordField fx:id="passwordField" capslockWarning="%ctrl.secPasswordField.capsLocked" nonPrintableCharsWarning="%ctrl.secPasswordField.nonPrintableChars" maxWidth="Infinity" HBox.hgrow="ALWAYS"/>
</HBox>
<!-- Unlock Button / Advanced Options Button -->

View File

@@ -7,7 +7,7 @@
<?import javafx.scene.control.ProgressIndicator?>
<?import javafx.scene.layout.VBox?>
<?import org.cryptomator.ui.controls.FormattedLabel?>
<?import org.cryptomator.ui.controls.SecPasswordField?>
<?import org.cryptomator.ui.controls.NiceSecurePasswordField?>
<VBox xmlns="http://javafx.com/javafx"
xmlns:fx="http://javafx.com/fxml"
fx:controller="org.cryptomator.ui.unlock.UnlockController"
@@ -21,7 +21,7 @@
<children>
<VBox spacing="6">
<FormattedLabel format="%unlock.passwordPrompt" arg1="${controller.vault.displayableName}" wrapText="true"/>
<SecPasswordField fx:id="passwordField"/>
<NiceSecurePasswordField fx:id="passwordField"/>
<CheckBox fx:id="savePassword" text="%unlock.savePassword" onAction="#didClickSavePasswordCheckbox"/>
</VBox>

View File

@@ -11,7 +11,7 @@
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.ProgressIndicator?>
<?import javafx.scene.control.Button?>
<?import org.cryptomator.ui.controls.SecPasswordField?>
<?import org.cryptomator.ui.controls.SecurePasswordField?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.ColumnConstraints?>
@@ -39,7 +39,7 @@
</Pane>
<Label text="%unlock.label.password" GridPane.rowIndex="3" GridPane.columnIndex="0" cacheShape="true" cache="true" />
<SecPasswordField fx:id="passwordField" GridPane.rowIndex="3" GridPane.columnIndex="1" cacheShape="true" cache="true" />
<SecurePasswordField fx:id="passwordField" GridPane.rowIndex="3" GridPane.columnIndex="1" cacheShape="true" cache="true" />
<CheckBox fx:id="confirmationCheckbox" text="%upgrade.confirmation.label" wrapText="true" GridPane.rowIndex="4" GridPane.columnIndex="0" GridPane.columnSpan="2" cacheShape="true" cache="true" />

View File

@@ -12,9 +12,9 @@ import java.awt.GraphicsEnvironment;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
class SecPasswordFieldTest {
class SecurePasswordFieldTest {
private SecPasswordField pwField = new SecPasswordField();
private SecurePasswordField pwField = new SecurePasswordField();
@BeforeAll
static void initJavaFx() throws InterruptedException {