diff --git a/main/pom.xml b/main/pom.xml
index abcdf6abc..aebabe97b 100644
--- a/main/pom.xml
+++ b/main/pom.xml
@@ -238,6 +238,7 @@
hamcrest-all
${hamcrest.version}
+
diff --git a/main/ui/pom.xml b/main/ui/pom.xml
index c1dc24234..6808f3887 100644
--- a/main/ui/pom.xml
+++ b/main/ui/pom.xml
@@ -99,5 +99,12 @@
org.cryptomator
commons-test
+
+
+
+ com.nulab-inc
+ zxcvbn
+ 1.1.1
+
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 19a1187df..02b1255df 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
@@ -2,27 +2,12 @@
* Copyright (c) 2014, 2016 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.controllers;
-import java.io.IOException;
-import java.io.UncheckedIOException;
-import java.net.URL;
-import java.nio.file.FileAlreadyExistsException;
-import java.util.Optional;
-
-import javax.inject.Inject;
-import javax.inject.Singleton;
-
-import org.cryptomator.ui.controls.SecPasswordField;
-import org.cryptomator.ui.model.Vault;
-import org.cryptomator.ui.settings.Localization;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
import javafx.application.Platform;
import javafx.beans.binding.BooleanBinding;
import javafx.beans.property.ObjectProperty;
@@ -31,6 +16,26 @@ import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
+import javafx.scene.paint.Color;
+import javafx.scene.shape.Rectangle;
+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.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+import java.io.IOException;
+import java.io.UncheckedIOException;
+import java.net.URL;
+import java.nio.file.FileAlreadyExistsException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+
+import com.nulabinc.zxcvbn.*;
@Singleton
public class InitializeController extends LocalizedFXMLViewController {
@@ -39,6 +44,8 @@ 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();
@Inject
public InitializeController(Localization localization) {
@@ -57,11 +64,31 @@ public class InitializeController extends LocalizedFXMLViewController {
@FXML
private Label messageLabel;
+ @FXML
+ private Label passwordStrengthLabel;
+
+ @FXML
+ private Rectangle passwordStrengthShape;
+
@Override
public void initialize() {
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);
+ });
+
+ // progressbar graphic properties
+ passwordStrengthShape.setFill(Color.web("#ff1a1a"));
+ passwordStrengthShape.setStroke(Color.GRAY);
+
+ // default password strength bar visual properties
+ changeProgressBarAspect(0f, 0f, Color.web("#ff1a1a"));
+ passwordStrengthLabel.setText(localization.getString("initialize.messageLabel.passwordStrength") + " : 0%");
+
+ // preparing inputs for the password strength checker
+ sanitizedInputs.add("cryptomator");
}
@Override
@@ -100,6 +127,49 @@ public class InitializeController extends LocalizedFXMLViewController {
this.listener = Optional.ofNullable(listener);
}
+ /* 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);
+ }
+
/* callback */
private void invokeListenerLater(InitializationListener listener) {
diff --git a/main/ui/src/main/resources/fxml/initialize.fxml b/main/ui/src/main/resources/fxml/initialize.fxml
index 65ca244c6..4ddee6948 100644
--- a/main/ui/src/main/resources/fxml/initialize.fxml
+++ b/main/ui/src/main/resources/fxml/initialize.fxml
@@ -1,4 +1,5 @@
+
+
+
-
+
+
+
+
@@ -30,17 +36,22 @@
-
+
-
+
-
-
+
+
+
+
+
-
+
+
+
+
+
-
-
diff --git a/main/ui/src/main/resources/localization.properties b/main/ui/src/main/resources/localization.properties
index 1220e3388..1542fa747 100644
--- a/main/ui/src/main/resources/localization.properties
+++ b/main/ui/src/main/resources/localization.properties
@@ -26,6 +26,7 @@ initialize.label.retypePassword=Retype password
initialize.button.ok=Create vault
initialize.messageLabel.alreadyInitialized=Vault already initialized
initialize.messageLabel.initializationFailed=Could not initialize vault. See logfile for details.
+initialize.messageLabel.passwordStrength=Password Strength
# notfound.fxml
notfound.label=Vault couldn't be found. Has it been moved?