Added the password strength indicator in the change password window

This commit is contained in:
jncharon
2016-04-12 21:27:31 +02:00
parent 588166dce9
commit e66e5b1d96
3 changed files with 85 additions and 9 deletions

View File

@@ -11,11 +11,19 @@ package org.cryptomator.ui.controllers;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import javax.inject.Inject;
import javax.inject.Singleton;
import com.nulabinc.zxcvbn.Strength;
import com.nulabinc.zxcvbn.Zxcvbn;
import javafx.scene.control.Label;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import org.apache.commons.lang3.StringUtils;
import org.cryptomator.crypto.engine.InvalidPassphraseException;
import org.cryptomator.crypto.engine.UnsupportedVaultFormatException;
import org.cryptomator.ui.controls.SecPasswordField;
@@ -43,6 +51,8 @@ public class ChangePasswordController extends LocalizedFXMLViewController {
private final Application app;
final ObjectProperty<Vault> vault = new SimpleObjectProperty<>();
private Optional<ChangePasswordListener> listener = Optional.empty();
private Zxcvbn zxcvbn = new Zxcvbn();
private List<String> sanitizedInputs = new ArrayList();
@Inject
public ChangePasswordController(Application app, Localization localization) {
@@ -68,12 +78,29 @@ public class ChangePasswordController extends LocalizedFXMLViewController {
@FXML
private Hyperlink downloadsPageLink;
@FXML
private Label passwordStrengthLabel;
@FXML
private Rectangle passwordStrengthShape;
@Override
public void initialize() {
BooleanBinding oldPasswordIsEmpty = oldPasswordField.textProperty().isEmpty();
BooleanBinding newPasswordIsEmpty = newPasswordField.textProperty().isEmpty();
BooleanBinding passwordsDiffer = newPasswordField.textProperty().isNotEqualTo(retypePasswordField.textProperty());
changePasswordButton.disableProperty().bind(oldPasswordIsEmpty.or(newPasswordIsEmpty.or(passwordsDiffer)));
newPasswordField.textProperty().addListener((observable, oldValue, newValue) -> {
checkPasswordStrength(newValue);
});
// default password strength bar visual properties
passwordStrengthShape.setStroke(Color.GRAY);
changeProgressBarAspect(0f, 0f, Color.web("#FF0000"));
passwordStrengthLabel.setText(localization.getString("initialize.messageLabel.passwordStrength") + " : 0%");
// preparing inputs for the password strength checker
sanitizedInputs.add("cryptomator");
}
@Override
@@ -122,6 +149,51 @@ public class ChangePasswordController extends LocalizedFXMLViewController {
}
}
// ****************************************
// Password strength management
// ****************************************
private void checkPasswordStrength(String password) {
int strengthPercentage = 0;
if (StringUtils.isEmpty(password)) {
changeProgressBarAspect(0f, 0f, Color.web("#FF0000"));
passwordStrengthLabel.setText(localization.getString("initialize.messageLabel.passwordStrength") + " : " + strengthPercentage + "%");
} else {
Color color = Color.web("#FF0000");
Strength strength = zxcvbn.measure(password, sanitizedInputs);
switch (strength.getScore()) {
case 0:
strengthPercentage = 20;
break;
case 1:
strengthPercentage = 40;
color = Color.web("#FF8000");
break;
case 2:
strengthPercentage = 60;
color = Color.web("#FFBF00");
break;
case 3:
strengthPercentage = 80;
color = Color.web("#FFFF00");
break;
case 4:
strengthPercentage = 100;
color = Color.web("#BFFF00");
break;
}
passwordStrengthLabel.setText(localization.getString("initialize.messageLabel.passwordStrength") + " : " + strengthPercentage + "%");
changeProgressBarAspect(0.5f, strengthPercentage * 2.23f, color); // 2.23f is the factor used to get the width to fit the window
}
}
private void changeProgressBarAspect(float strokeWidth, float length, Color color) {
passwordStrengthShape.setFill(color);
passwordStrengthShape.setStrokeWidth(strokeWidth);
passwordStrengthShape.setWidth(length);
}
/* Getter/Setter */
public ChangePasswordListener getListener() {

View File

@@ -79,12 +79,9 @@ public class InitializeController extends LocalizedFXMLViewController {
checkPasswordStrength(newValue);
});
// progressbar graphic properties
passwordStrengthShape.setFill(Color.web("#ff1a1a"));
passwordStrengthShape.setStroke(Color.GRAY);
// default password strength bar visual properties
changeProgressBarAspect(0f, 0f, Color.web("#ff1a1a"));
passwordStrengthShape.setStroke(Color.GRAY);
changeProgressBarAspect(0f, 0f, Color.web("#FF0000"));
passwordStrengthLabel.setText(localization.getString("initialize.messageLabel.passwordStrength") + " : 0%");
// preparing inputs for the password strength checker

View File

@@ -22,6 +22,7 @@
<?import javafx.scene.text.Text?>
<?import javafx.scene.shape.Rectangle?>
<GridPane vgap="12.0" hgap="12.0" prefWidth="400.0" xmlns:fx="http://javafx.com/fxml" cacheShape="true" cache="true">
<padding>
<Insets top="24.0" right="12.0" bottom="24.0" left="12.0" />
@@ -44,12 +45,18 @@
<!-- Row 2 -->
<Label text="%changePassword.label.retypePassword" GridPane.rowIndex="2" GridPane.columnIndex="0" cacheShape="true" cache="true" />
<SecPasswordField fx:id="retypePasswordField" GridPane.rowIndex="2" GridPane.columnIndex="1" GridPane.hgrow="ALWAYS" maxWidth="Infinity" cacheShape="true" cache="true" />
<!-- Row 3 -->
<Button fx:id="changePasswordButton" text="%changePassword.button.change" defaultButton="true" GridPane.rowIndex="3" GridPane.columnIndex="0" GridPane.columnSpan="2" GridPane.halignment="RIGHT" prefWidth="150.0" onAction="#didClickChangePasswordButton" disable="true" cacheShape="true" cache="true"/>
<Label fx:id="passwordStrengthLabel" cache="true" cacheShape="true" text="" GridPane.columnIndex="1" GridPane.rowIndex="3" />
<!-- Row 4 -->
<TextFlow GridPane.rowIndex="4" GridPane.columnIndex="0" GridPane.columnSpan="2" cacheShape="true" cache="true">
<Rectangle fx:id="passwordStrengthShape" width="0" height="15" GridPane.columnIndex="1" GridPane.rowIndex="4" />
<!-- Row 5 -->
<Button fx:id="changePasswordButton" text="%changePassword.button.change" defaultButton="true" GridPane.rowIndex="5" GridPane.columnIndex="0" GridPane.columnSpan="2" GridPane.halignment="RIGHT" prefWidth="150.0" onAction="#didClickChangePasswordButton" disable="true" cacheShape="true" cache="true"/>
<!-- Row 6 -->
<TextFlow GridPane.rowIndex="6" GridPane.columnIndex="5" GridPane.columnSpan="2" cacheShape="true" cache="true">
<children>
<Text fx:id="messageText" cache="true" />
<Hyperlink fx:id="downloadsPageLink" text="%changePassword.label.downloadsPageLink" visible="false" onAction="#didClickDownloadsLink" cacheShape="true" cache="true" />