mirror of
https://github.com/beemdevelopment/Aegis.git
synced 2025-04-23 23:39:14 +00:00
Merge pull request #1336 from alexbakker/limit-strength-analysis
Stop analyzing password strength if it becomes longer than 64 chars
This commit is contained in:
commit
3c124deae1
4 changed files with 65 additions and 43 deletions
|
@ -1,14 +1,60 @@
|
||||||
package com.beemdevelopment.aegis.helpers;
|
package com.beemdevelopment.aegis.helpers;
|
||||||
|
|
||||||
import android.content.Context;
|
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.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 {
|
public class PasswordStrengthHelper {
|
||||||
// Material design color palette
|
// Limit the password length to prevent zxcvbn4j from exploding
|
||||||
private static String[] COLORS = {"#FF5252", "#FF5252", "#FFC107", "#8BC34A", "#4CAF50"};
|
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) {
|
if (score < 0 || score > 4) {
|
||||||
throw new IllegalArgumentException("Not a valid zxcvbn score");
|
throw new IllegalArgumentException("Not a valid zxcvbn score");
|
||||||
}
|
}
|
||||||
|
@ -17,7 +63,7 @@ public class PasswordStrengthHelper {
|
||||||
return strings[score];
|
return strings[score];
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String getColor(int score) {
|
private static String getColor(int score) {
|
||||||
if (score < 0 || score > 4) {
|
if (score < 0 || score > 4) {
|
||||||
throw new IllegalArgumentException("Not a valid zxcvbn score");
|
throw new IllegalArgumentException("Not a valid zxcvbn score");
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,8 +5,6 @@ import android.content.ClipData;
|
||||||
import android.content.ClipboardManager;
|
import android.content.ClipboardManager;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.DialogInterface;
|
import android.content.DialogInterface;
|
||||||
import android.content.res.ColorStateList;
|
|
||||||
import android.graphics.Color;
|
|
||||||
import android.text.InputType;
|
import android.text.InputType;
|
||||||
import android.text.SpannableStringBuilder;
|
import android.text.SpannableStringBuilder;
|
||||||
import android.text.TextWatcher;
|
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.dialog.MaterialAlertDialogBuilder;
|
||||||
import com.google.android.material.textfield.TextInputEditText;
|
import com.google.android.material.textfield.TextInputEditText;
|
||||||
import com.google.android.material.textfield.TextInputLayout;
|
import com.google.android.material.textfield.TextInputLayout;
|
||||||
import com.nulabinc.zxcvbn.Strength;
|
|
||||||
import com.nulabinc.zxcvbn.Zxcvbn;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -120,7 +116,6 @@ public class Dialogs {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void showSetPasswordDialog(ComponentActivity activity, PasswordSlotListener listener) {
|
public static void showSetPasswordDialog(ComponentActivity activity, PasswordSlotListener listener) {
|
||||||
Zxcvbn zxcvbn = new Zxcvbn();
|
|
||||||
View view = activity.getLayoutInflater().inflate(R.layout.dialog_password, null);
|
View view = activity.getLayoutInflater().inflate(R.layout.dialog_password, null);
|
||||||
EditText textPassword = view.findViewById(R.id.text_password);
|
EditText textPassword = view.findViewById(R.id.text_password);
|
||||||
EditText textPasswordConfirm = view.findViewById(R.id.text_password_confirm);
|
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);
|
TextView textPasswordStrength = view.findViewById(R.id.text_password_strength);
|
||||||
TextInputLayout textPasswordWrapper = view.findViewById(R.id.text_password_wrapper);
|
TextInputLayout textPasswordWrapper = view.findViewById(R.id.text_password_wrapper);
|
||||||
CheckBox switchToggleVisibility = view.findViewById(R.id.check_toggle_visibility);
|
CheckBox switchToggleVisibility = view.findViewById(R.id.check_toggle_visibility);
|
||||||
|
PasswordStrengthHelper passStrength = new PasswordStrengthHelper(
|
||||||
|
textPassword, barPasswordStrength, textPasswordStrength, textPasswordWrapper);
|
||||||
|
|
||||||
switchToggleVisibility.setOnCheckedChangeListener((buttonView, isChecked) -> {
|
switchToggleVisibility.setOnCheckedChangeListener((buttonView, isChecked) -> {
|
||||||
if (isChecked) {
|
if (isChecked) {
|
||||||
|
@ -183,13 +180,7 @@ public class Dialogs {
|
||||||
TextWatcher watcher = new SimpleTextWatcher(text -> {
|
TextWatcher watcher = new SimpleTextWatcher(text -> {
|
||||||
boolean equal = EditTextHelper.areEditTextsEqual(textPassword, textPasswordConfirm);
|
boolean equal = EditTextHelper.areEditTextsEqual(textPassword, textPasswordConfirm);
|
||||||
buttonOK.get().setEnabled(equal);
|
buttonOK.get().setEnabled(equal);
|
||||||
|
passStrength.measure(activity);
|
||||||
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();
|
|
||||||
});
|
});
|
||||||
textPassword.addTextChangedListener(watcher);
|
textPassword.addTextChangedListener(watcher);
|
||||||
textPasswordConfirm.addTextChangedListener(watcher);
|
textPasswordConfirm.addTextChangedListener(watcher);
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
package com.beemdevelopment.aegis.ui.slides;
|
package com.beemdevelopment.aegis.ui.slides;
|
||||||
|
|
||||||
import android.content.res.ColorStateList;
|
import static com.beemdevelopment.aegis.ui.slides.SecurityPickerSlide.CRYPT_TYPE_BIOMETRIC;
|
||||||
import android.graphics.Color;
|
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.os.Bundle;
|
||||||
import android.text.Editable;
|
import android.text.Editable;
|
||||||
import android.text.TextWatcher;
|
|
||||||
import android.text.method.PasswordTransformationMethod;
|
import android.text.method.PasswordTransformationMethod;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
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.BiometricsHelper;
|
||||||
import com.beemdevelopment.aegis.helpers.EditTextHelper;
|
import com.beemdevelopment.aegis.helpers.EditTextHelper;
|
||||||
import com.beemdevelopment.aegis.helpers.PasswordStrengthHelper;
|
import com.beemdevelopment.aegis.helpers.PasswordStrengthHelper;
|
||||||
|
import com.beemdevelopment.aegis.helpers.SimpleTextWatcher;
|
||||||
import com.beemdevelopment.aegis.ui.dialogs.Dialogs;
|
import com.beemdevelopment.aegis.ui.dialogs.Dialogs;
|
||||||
import com.beemdevelopment.aegis.ui.intro.SlideFragment;
|
import com.beemdevelopment.aegis.ui.intro.SlideFragment;
|
||||||
import com.beemdevelopment.aegis.ui.tasks.KeyDerivationTask;
|
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.Slot;
|
||||||
import com.beemdevelopment.aegis.vault.slots.SlotException;
|
import com.beemdevelopment.aegis.vault.slots.SlotException;
|
||||||
import com.google.android.material.textfield.TextInputLayout;
|
import com.google.android.material.textfield.TextInputLayout;
|
||||||
import com.nulabinc.zxcvbn.Strength;
|
|
||||||
import com.nulabinc.zxcvbn.Zxcvbn;
|
|
||||||
|
|
||||||
import javax.crypto.Cipher;
|
import javax.crypto.Cipher;
|
||||||
import javax.crypto.SecretKey;
|
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 {
|
public class SecuritySetupSlide extends SlideFragment {
|
||||||
private EditText _textPassword;
|
private EditText _textPassword;
|
||||||
private EditText _textPasswordConfirm;
|
private EditText _textPasswordConfirm;
|
||||||
|
@ -76,27 +72,15 @@ public class SecuritySetupSlide extends SlideFragment {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
_textPassword.addTextChangedListener(new TextWatcher() {
|
_textPassword.addTextChangedListener(new SimpleTextWatcher(new SimpleTextWatcher.Listener() {
|
||||||
private Zxcvbn _zxcvbn = new Zxcvbn();
|
private final PasswordStrengthHelper passStrength = new PasswordStrengthHelper(
|
||||||
|
_textPassword, _barPasswordStrength, _textPasswordStrength, _textPasswordWrapper);
|
||||||
@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) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void afterTextChanged(Editable s) {
|
public void afterTextChanged(Editable s) {
|
||||||
|
passStrength.measure(requireContext());
|
||||||
}
|
}
|
||||||
});
|
}));
|
||||||
|
|
||||||
return view;
|
return view;
|
||||||
}
|
}
|
||||||
|
|
|
@ -447,6 +447,7 @@
|
||||||
<string name="password_strength_fair">Fair</string>
|
<string name="password_strength_fair">Fair</string>
|
||||||
<string name="password_strength_good">Good</string>
|
<string name="password_strength_good">Good</string>
|
||||||
<string name="password_strength_strong">Strong</string>
|
<string name="password_strength_strong">Strong</string>
|
||||||
|
<string name="password_strength_unknown">Password too long for strength analysis</string>
|
||||||
<string name="pref_pin_keyboard_title">Use PIN keyboard on lockscreen</string>
|
<string name="pref_pin_keyboard_title">Use PIN keyboard on lockscreen</string>
|
||||||
<string name="pref_pin_keyboard_summary">Enable this if you want to enable the PIN keyboard on the lockscreen. This only works for numeric passwords</string>
|
<string name="pref_pin_keyboard_summary">Enable this if you want to enable the PIN keyboard on the lockscreen. This only works for numeric passwords</string>
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue