diff --git a/main/ui/src/main/java/org/cryptomator/ui/controllers/ChangePasswordController.java b/main/ui/src/main/java/org/cryptomator/ui/controllers/ChangePasswordController.java index 21dca9911..ad71d2f6c 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/controllers/ChangePasswordController.java +++ b/main/ui/src/main/java/org/cryptomator/ui/controllers/ChangePasswordController.java @@ -5,6 +5,7 @@ * * Contributors: * Sebastian Stenzel - initial API and implementation + * Jean-Noël Charon - password strength meter *******************************************************************************/ package org.cryptomator.ui.controllers; @@ -20,6 +21,8 @@ import javax.inject.Singleton; import com.nulabinc.zxcvbn.Strength; import com.nulabinc.zxcvbn.Zxcvbn; +import javafx.beans.property.IntegerProperty; +import javafx.beans.property.SimpleIntegerProperty; import javafx.scene.control.Label; import javafx.scene.paint.Color; import javafx.scene.shape.Rectangle; @@ -29,6 +32,8 @@ import org.cryptomator.crypto.engine.UnsupportedVaultFormatException; import org.cryptomator.ui.controls.SecPasswordField; import org.cryptomator.ui.model.Vault; import org.cryptomator.ui.settings.Localization; +import org.cryptomator.ui.util.PasswordStrengthUtil; +import org.fxmisc.easybind.EasyBind; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -51,8 +56,7 @@ public class ChangePasswordController extends LocalizedFXMLViewController { private final Application app; final ObjectProperty vault = new SimpleObjectProperty<>(); private Optional listener = Optional.empty(); - private Zxcvbn zxcvbn = new Zxcvbn(); - private List sanitizedInputs = new ArrayList(); + final IntegerProperty passwordStrength = new SimpleIntegerProperty(); // 0-4 @Inject public ChangePasswordController(Application app, Localization localization) { @@ -60,6 +64,9 @@ public class ChangePasswordController extends LocalizedFXMLViewController { this.app = app; } + @Inject + PasswordStrengthUtil strengthRater; + @FXML private SecPasswordField oldPasswordField; @@ -90,17 +97,14 @@ public class ChangePasswordController extends LocalizedFXMLViewController { 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); - }); + EasyBind.subscribe(newPasswordField.textProperty(), this::checkPasswordStrength); - // default password strength bar visual properties - passwordStrengthShape.setStroke(Color.GRAY); - changeProgressBarAspect(0f, 0f, Color.web("#FF0000")); - passwordStrengthLabel.setText(localization.getString("initialize.messageLabel.passwordStrength") + " : 0%"); + strengthRater.setLocalization(localization); - // preparing inputs for the password strength checker - sanitizedInputs.add("cryptomator"); + passwordStrengthShape.widthProperty().bind(EasyBind.map(passwordStrength, strengthRater::getWidth)); + passwordStrengthShape.fillProperty().bind(EasyBind.map(passwordStrength, strengthRater::getStrengthColor)); + passwordStrengthShape.strokeWidthProperty().bind(EasyBind.map(passwordStrength, strengthRater::getStrokeWidth)); + passwordStrengthLabel.textProperty().bind(EasyBind.map(passwordStrength, strengthRater::getStrengthDescription)); } @Override @@ -154,46 +158,8 @@ public class ChangePasswordController extends LocalizedFXMLViewController { // **************************************** 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 - } + passwordStrength.set(strengthRater.computeRate(password)); } - - private void changeProgressBarAspect(float strokeWidth, float length, Color color) { - passwordStrengthShape.setFill(color); - passwordStrengthShape.setStrokeWidth(strokeWidth); - passwordStrengthShape.setWidth(length); - } - /* Getter/Setter */ public ChangePasswordListener getListener() { diff --git a/main/ui/src/main/java/org/cryptomator/ui/controllers/InitializeController.java b/main/ui/src/main/java/org/cryptomator/ui/controllers/InitializeController.java index bab9b948b..a49dac70c 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/controllers/InitializeController.java +++ b/main/ui/src/main/java/org/cryptomator/ui/controllers/InitializeController.java @@ -5,13 +5,13 @@ * * Contributors: * Sebastian Stenzel - initial API and implementation + * Jean-Noël Charon - password strength meter ******************************************************************************/ package org.cryptomator.ui.controllers; import javafx.application.Platform; import javafx.beans.binding.BooleanBinding; -import javafx.beans.property.ObjectProperty; -import javafx.beans.property.SimpleObjectProperty; +import javafx.beans.property.*; import javafx.event.ActionEvent; import javafx.fxml.FXML; import javafx.scene.control.Button; @@ -22,6 +22,8 @@ import org.apache.commons.lang3.StringUtils; import org.cryptomator.ui.controls.SecPasswordField; import org.cryptomator.ui.model.Vault; import org.cryptomator.ui.settings.Localization; +import org.cryptomator.ui.util.PasswordStrengthUtil; +import org.fxmisc.easybind.EasyBind; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -44,14 +46,16 @@ public class InitializeController extends LocalizedFXMLViewController { final ObjectProperty vault = new SimpleObjectProperty<>(); private Optional listener = Optional.empty(); - private Zxcvbn zxcvbn = new Zxcvbn(); - private List sanitizedInputs = new ArrayList(); + final IntegerProperty passwordStrength = new SimpleIntegerProperty(); // 0-4 @Inject public InitializeController(Localization localization) { super(localization); } + @Inject + PasswordStrengthUtil strengthRater; + @FXML private SecPasswordField passwordField; @@ -75,17 +79,14 @@ public class InitializeController extends LocalizedFXMLViewController { BooleanBinding passwordIsEmpty = passwordField.textProperty().isEmpty(); BooleanBinding passwordsDiffer = passwordField.textProperty().isNotEqualTo(retypePasswordField.textProperty()); okButton.disableProperty().bind(passwordIsEmpty.or(passwordsDiffer)); - passwordField.textProperty().addListener((observable, oldValue, newValue) -> { - checkPasswordStrength(newValue); - }); + EasyBind.subscribe(passwordField.textProperty(), this::checkPasswordStrength); - // default password strength bar visual properties - passwordStrengthShape.setStroke(Color.GRAY); - changeProgressBarAspect(0f, 0f, Color.web("#FF0000")); - passwordStrengthLabel.setText(localization.getString("initialize.messageLabel.passwordStrength") + " : 0%"); + strengthRater.setLocalization(localization); - // preparing inputs for the password strength checker - sanitizedInputs.add("cryptomator"); + passwordStrengthShape.widthProperty().bind(EasyBind.map(passwordStrength, strengthRater::getWidth)); + passwordStrengthShape.fillProperty().bind(EasyBind.map(passwordStrength, strengthRater::getStrengthColor)); + passwordStrengthShape.strokeWidthProperty().bind(EasyBind.map(passwordStrength, strengthRater::getStrokeWidth)); + passwordStrengthLabel.textProperty().bind(EasyBind.map(passwordStrength, strengthRater::getStrengthDescription)); } @Override @@ -127,44 +128,7 @@ public class InitializeController extends LocalizedFXMLViewController { /* Methods */ 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); + passwordStrength.set(strengthRater.computeRate(password)); } /* callback */ diff --git a/main/ui/src/main/java/org/cryptomator/ui/controllers/WelcomeController.java b/main/ui/src/main/java/org/cryptomator/ui/controllers/WelcomeController.java index 5c976e317..0ac30e0b2 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/controllers/WelcomeController.java +++ b/main/ui/src/main/java/org/cryptomator/ui/controllers/WelcomeController.java @@ -154,6 +154,7 @@ public class WelcomeController extends LocalizedFXMLViewController { Platform.runLater(() -> { this.updateLink.setText(msg); this.updateLink.setVisible(true); + this.updateLink.setDisable(false); }); } } diff --git a/main/ui/src/main/java/org/cryptomator/ui/util/PasswordStrengthUtil.java b/main/ui/src/main/java/org/cryptomator/ui/util/PasswordStrengthUtil.java new file mode 100644 index 000000000..ea41f446b --- /dev/null +++ b/main/ui/src/main/java/org/cryptomator/ui/util/PasswordStrengthUtil.java @@ -0,0 +1,120 @@ +/******************************************************************************* + * Copyright (c) 2016 Sebastian Stenzel and others. + * This file is licensed under the terms of the MIT license. + * See the LICENSE.txt file for more info. + * + * Contributors: + * Jean-Noël Charon - initial API and implementation + *******************************************************************************/ +package org.cryptomator.ui.util; + +import com.nulabinc.zxcvbn.Zxcvbn; +import javafx.beans.property.IntegerProperty; +import javafx.scene.paint.Color; +import org.apache.commons.lang3.StringUtils; +import org.cryptomator.ui.settings.Localization; + +import javax.inject.Inject; +import javax.inject.Singleton; +import java.util.ArrayList; +import java.util.List; + +@Singleton +public class PasswordStrengthUtil { + + private Zxcvbn zxcvbn = new Zxcvbn(); + private List sanitizedInputs = new ArrayList<>(); + private Localization localization; + + @Inject + public PasswordStrengthUtil(){ + // preparing inputs for the password strength checker + sanitizedInputs.add("cryptomator"); + } + + public int computeRate(String password) { + if (StringUtils.isEmpty(password)) { + return -1; + } else { + return zxcvbn.measure(password, sanitizedInputs).getScore(); + } + } + + public Color getStrengthColor(Number score) { + Color strengthColor = Color.web("#FF0000"); + switch (score.intValue()) { + case 0: + strengthColor = Color.web("#FF0000"); + break; + case 1: + strengthColor = Color.web("#FF8000"); + break; + case 2: + strengthColor = Color.web("#FFBF00"); + break; + case 3: + strengthColor = Color.web("#FFFF00"); + break; + case 4: + strengthColor = Color.web("#BFFF00"); + break; + default: + strengthColor = Color.web("#FF0000"); + break; + } + return strengthColor; + } + + public int getWidth(Number score) { + int width = 0; + switch (score.intValue()) { + case 0: + width += 5; + break; + case 1: + width += 25; + break; + case 2: + width += 50; + break; + case 3: + width += 75; + break; + case 4: + width = 100; + break; + default: + width = 0; + break; + } + return Math.round(width*2.23f); + } + + public float getStrokeWidth(Number score) { + if (score.intValue() >= 0) { + return 0.5f; + } else { + return 0; + } + } + + public String getStrengthDescription(Number score) { + if (score.intValue() >= 0) { + return String.format(localization.getString("initialize.messageLabel.passwordStrength"), + localization.getString("initialize.messageLabel.passwordStrength." + score.intValue())); + } else { + return ""; + } + } + + /* Getter / Setter */ + + public Localization getLocalization() { + return localization; + } + + public void setLocalization(Localization localization) { + this.localization = localization; + } + +} diff --git a/main/ui/src/main/resources/fxml/change_password.fxml b/main/ui/src/main/resources/fxml/change_password.fxml index f415d0dc9..c7f2a617b 100644 --- a/main/ui/src/main/resources/fxml/change_password.fxml +++ b/main/ui/src/main/resources/fxml/change_password.fxml @@ -6,6 +6,7 @@ Contributors: Sebastian Stenzel - initial API and implementation + Jean-Noël Charon - password strength meter --> @@ -50,7 +51,7 @@