diff --git a/app/src/main/java/com/beemdevelopment/aegis/helpers/PasswordStrengthHelper.java b/app/src/main/java/com/beemdevelopment/aegis/helpers/PasswordStrengthHelper.java
index 518ebcc1..373ef114 100644
--- a/app/src/main/java/com/beemdevelopment/aegis/helpers/PasswordStrengthHelper.java
+++ b/app/src/main/java/com/beemdevelopment/aegis/helpers/PasswordStrengthHelper.java
@@ -1,14 +1,60 @@
package com.beemdevelopment.aegis.helpers;
import android.content.Context;
+import android.content.res.ColorStateList;
+import android.graphics.Color;
+import android.widget.EditText;
+import android.widget.ProgressBar;
+import android.widget.TextView;
import com.beemdevelopment.aegis.R;
+import com.google.android.material.textfield.TextInputLayout;
+import com.google.common.base.Strings;
+import com.nulabinc.zxcvbn.Strength;
+import com.nulabinc.zxcvbn.Zxcvbn;
public class PasswordStrengthHelper {
- // Material design color palette
- private static String[] COLORS = {"#FF5252", "#FF5252", "#FFC107", "#8BC34A", "#4CAF50"};
+ // Limit the password length to prevent zxcvbn4j from exploding
+ private static final int MAX_PASSWORD_LENGTH = 64;
- public static String getString(int score, Context context) {
+ // Material design color palette
+ private final static String[] COLORS = {"#FF5252", "#FF5252", "#FFC107", "#8BC34A", "#4CAF50"};
+
+ private final Zxcvbn _zxcvbn = new Zxcvbn();
+ private final EditText _textPassword;
+ private final ProgressBar _barPasswordStrength;
+ private final TextView _textPasswordStrength;
+ private final TextInputLayout _textPasswordWrapper;
+
+ public PasswordStrengthHelper(
+ EditText textPassword,
+ ProgressBar barPasswordStrength,
+ TextView textPasswordStrength,
+ TextInputLayout textPasswordWrapper
+ ) {
+ _textPassword = textPassword;
+ _barPasswordStrength = barPasswordStrength;
+ _textPasswordStrength = textPasswordStrength;
+ _textPasswordWrapper = textPasswordWrapper;
+ }
+
+ public void measure(Context context) {
+ if (_textPassword.getText().length() > MAX_PASSWORD_LENGTH) {
+ _barPasswordStrength.setProgress(0);
+ _textPasswordStrength.setText(R.string.password_strength_unknown);
+ } else {
+ Strength strength = _zxcvbn.measure(_textPassword.getText());
+ _barPasswordStrength.setProgress(strength.getScore());
+ _barPasswordStrength.setProgressTintList(ColorStateList.valueOf(Color.parseColor(getColor(strength.getScore()))));
+ _textPasswordStrength.setText((_textPassword.getText().length() != 0) ? getString(strength.getScore(), context) : "");
+ String warning = strength.getFeedback().getWarning();
+ _textPasswordWrapper.setError(warning);
+ _textPasswordWrapper.setErrorEnabled(!Strings.isNullOrEmpty(warning));
+ strength.wipe();
+ }
+ }
+
+ private static String getString(int score, Context context) {
if (score < 0 || score > 4) {
throw new IllegalArgumentException("Not a valid zxcvbn score");
}
@@ -17,7 +63,7 @@ public class PasswordStrengthHelper {
return strings[score];
}
- public static String getColor(int score) {
+ private static String getColor(int score) {
if (score < 0 || score > 4) {
throw new IllegalArgumentException("Not a valid zxcvbn score");
}
diff --git a/app/src/main/java/com/beemdevelopment/aegis/ui/dialogs/Dialogs.java b/app/src/main/java/com/beemdevelopment/aegis/ui/dialogs/Dialogs.java
index b1156ee8..7bede047 100644
--- a/app/src/main/java/com/beemdevelopment/aegis/ui/dialogs/Dialogs.java
+++ b/app/src/main/java/com/beemdevelopment/aegis/ui/dialogs/Dialogs.java
@@ -5,8 +5,6 @@ import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context;
import android.content.DialogInterface;
-import android.content.res.ColorStateList;
-import android.graphics.Color;
import android.text.InputType;
import android.text.SpannableStringBuilder;
import android.text.TextWatcher;
@@ -43,8 +41,6 @@ import com.beemdevelopment.aegis.vault.slots.SlotException;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import com.google.android.material.textfield.TextInputEditText;
import com.google.android.material.textfield.TextInputLayout;
-import com.nulabinc.zxcvbn.Strength;
-import com.nulabinc.zxcvbn.Zxcvbn;
import java.util.ArrayList;
import java.util.List;
@@ -120,7 +116,6 @@ public class Dialogs {
}
public static void showSetPasswordDialog(ComponentActivity activity, PasswordSlotListener listener) {
- Zxcvbn zxcvbn = new Zxcvbn();
View view = activity.getLayoutInflater().inflate(R.layout.dialog_password, null);
EditText textPassword = view.findViewById(R.id.text_password);
EditText textPasswordConfirm = view.findViewById(R.id.text_password_confirm);
@@ -128,6 +123,8 @@ public class Dialogs {
TextView textPasswordStrength = view.findViewById(R.id.text_password_strength);
TextInputLayout textPasswordWrapper = view.findViewById(R.id.text_password_wrapper);
CheckBox switchToggleVisibility = view.findViewById(R.id.check_toggle_visibility);
+ PasswordStrengthHelper passStrength = new PasswordStrengthHelper(
+ textPassword, barPasswordStrength, textPasswordStrength, textPasswordWrapper);
switchToggleVisibility.setOnCheckedChangeListener((buttonView, isChecked) -> {
if (isChecked) {
@@ -183,13 +180,7 @@ public class Dialogs {
TextWatcher watcher = new SimpleTextWatcher(text -> {
boolean equal = EditTextHelper.areEditTextsEqual(textPassword, textPasswordConfirm);
buttonOK.get().setEnabled(equal);
-
- Strength strength = zxcvbn.measure(textPassword.getText());
- barPasswordStrength.setProgress(strength.getScore());
- barPasswordStrength.setProgressTintList(ColorStateList.valueOf(Color.parseColor(PasswordStrengthHelper.getColor(strength.getScore()))));
- textPasswordStrength.setText((textPassword.getText().length() != 0) ? PasswordStrengthHelper.getString(strength.getScore(), activity) : "");
- textPasswordWrapper.setError(strength.getFeedback().getWarning());
- strength.wipe();
+ passStrength.measure(activity);
});
textPassword.addTextChangedListener(watcher);
textPasswordConfirm.addTextChangedListener(watcher);
diff --git a/app/src/main/java/com/beemdevelopment/aegis/ui/slides/SecuritySetupSlide.java b/app/src/main/java/com/beemdevelopment/aegis/ui/slides/SecuritySetupSlide.java
index 8611299c..23082fa4 100644
--- a/app/src/main/java/com/beemdevelopment/aegis/ui/slides/SecuritySetupSlide.java
+++ b/app/src/main/java/com/beemdevelopment/aegis/ui/slides/SecuritySetupSlide.java
@@ -1,10 +1,12 @@
package com.beemdevelopment.aegis.ui.slides;
-import android.content.res.ColorStateList;
-import android.graphics.Color;
+import static com.beemdevelopment.aegis.ui.slides.SecurityPickerSlide.CRYPT_TYPE_BIOMETRIC;
+import static com.beemdevelopment.aegis.ui.slides.SecurityPickerSlide.CRYPT_TYPE_INVALID;
+import static com.beemdevelopment.aegis.ui.slides.SecurityPickerSlide.CRYPT_TYPE_NONE;
+import static com.beemdevelopment.aegis.ui.slides.SecurityPickerSlide.CRYPT_TYPE_PASS;
+
import android.os.Bundle;
import android.text.Editable;
-import android.text.TextWatcher;
import android.text.method.PasswordTransformationMethod;
import android.view.LayoutInflater;
import android.view.View;
@@ -23,6 +25,7 @@ import com.beemdevelopment.aegis.helpers.BiometricSlotInitializer;
import com.beemdevelopment.aegis.helpers.BiometricsHelper;
import com.beemdevelopment.aegis.helpers.EditTextHelper;
import com.beemdevelopment.aegis.helpers.PasswordStrengthHelper;
+import com.beemdevelopment.aegis.helpers.SimpleTextWatcher;
import com.beemdevelopment.aegis.ui.dialogs.Dialogs;
import com.beemdevelopment.aegis.ui.intro.SlideFragment;
import com.beemdevelopment.aegis.ui.tasks.KeyDerivationTask;
@@ -32,17 +35,10 @@ import com.beemdevelopment.aegis.vault.slots.PasswordSlot;
import com.beemdevelopment.aegis.vault.slots.Slot;
import com.beemdevelopment.aegis.vault.slots.SlotException;
import com.google.android.material.textfield.TextInputLayout;
-import com.nulabinc.zxcvbn.Strength;
-import com.nulabinc.zxcvbn.Zxcvbn;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
-import static com.beemdevelopment.aegis.ui.slides.SecurityPickerSlide.CRYPT_TYPE_BIOMETRIC;
-import static com.beemdevelopment.aegis.ui.slides.SecurityPickerSlide.CRYPT_TYPE_INVALID;
-import static com.beemdevelopment.aegis.ui.slides.SecurityPickerSlide.CRYPT_TYPE_NONE;
-import static com.beemdevelopment.aegis.ui.slides.SecurityPickerSlide.CRYPT_TYPE_PASS;
-
public class SecuritySetupSlide extends SlideFragment {
private EditText _textPassword;
private EditText _textPasswordConfirm;
@@ -76,27 +72,15 @@ public class SecuritySetupSlide extends SlideFragment {
}
});
- _textPassword.addTextChangedListener(new TextWatcher() {
- private Zxcvbn _zxcvbn = new Zxcvbn();
-
- @Override
- public void onTextChanged(CharSequence s, int start, int before, int count) {
- Strength strength = _zxcvbn.measure(_textPassword.getText());
- _barPasswordStrength.setProgress(strength.getScore());
- _barPasswordStrength.setProgressTintList(ColorStateList.valueOf(Color.parseColor(PasswordStrengthHelper.getColor(strength.getScore()))));
- _textPasswordStrength.setText((_textPassword.getText().length() != 0) ? PasswordStrengthHelper.getString(strength.getScore(), requireContext()) : "");
- _textPasswordWrapper.setError(strength.getFeedback().getWarning());
- strength.wipe();
- }
-
- @Override
- public void beforeTextChanged(CharSequence s, int start, int count, int after) {
- }
+ _textPassword.addTextChangedListener(new SimpleTextWatcher(new SimpleTextWatcher.Listener() {
+ private final PasswordStrengthHelper passStrength = new PasswordStrengthHelper(
+ _textPassword, _barPasswordStrength, _textPasswordStrength, _textPasswordWrapper);
@Override
public void afterTextChanged(Editable s) {
+ passStrength.measure(requireContext());
}
- });
+ }));
return view;
}
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 02cfc4bc..846b15b4 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -447,6 +447,7 @@
Fair
Good
Strong
+ Password too long for strength analysis
Use PIN keyboard on lockscreen
Enable this if you want to enable the PIN keyboard on the lockscreen. This only works for numeric passwords