mirror of
https://github.com/beemdevelopment/Aegis.git
synced 2025-04-26 00:36:11 +00:00
Merge pull request #442 from orangenbaumblatt/feature/password-strength
Add password strength meter
This commit is contained in:
commit
bf9173301c
8 changed files with 182 additions and 42 deletions
|
@ -122,6 +122,7 @@ dependencies {
|
|||
implementation 'com.google.protobuf:protobuf-javalite:3.12.1'
|
||||
implementation "com.mikepenz:iconics-core:3.2.5"
|
||||
implementation 'com.mikepenz:material-design-iconic-typeface:2.2.0.5@aar'
|
||||
implementation 'com.nulab-inc:zxcvbn:1.3.0'
|
||||
implementation 'de.hdodenhof:circleimageview:3.1.0'
|
||||
implementation 'de.psdev.licensesdialog:licensesdialog:2.1.0'
|
||||
implementation 'me.dm7.barcodescanner:zxing:1.9.8'
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
package com.beemdevelopment.aegis.helpers;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import com.beemdevelopment.aegis.R;
|
||||
|
||||
public class PasswordStrengthHelper {
|
||||
// Material design color palette
|
||||
private static String[] COLORS = {"#FF5252", "#FF5252", "#FFC107", "#8BC34A", "#4CAF50"};
|
||||
|
||||
public static String getString(int score, Context context) {
|
||||
if (score < 0 || score > 4) {
|
||||
throw new IllegalArgumentException("Not a valid zxcvbn score");
|
||||
}
|
||||
|
||||
String[] strings = context.getResources().getStringArray(R.array.password_strength);
|
||||
return strings[score];
|
||||
}
|
||||
|
||||
public static String getColor(int score) {
|
||||
if (score < 0 || score > 4) {
|
||||
throw new IllegalArgumentException("Not a valid zxcvbn score");
|
||||
}
|
||||
|
||||
return COLORS[score];
|
||||
}
|
||||
}
|
|
@ -7,6 +7,8 @@ import android.content.ClipboardManager;
|
|||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.content.res.ColorStateList;
|
||||
import android.graphics.Color;
|
||||
import android.provider.Settings;
|
||||
import android.text.Editable;
|
||||
import android.text.InputType;
|
||||
|
@ -20,6 +22,7 @@ import android.widget.CheckBox;
|
|||
import android.widget.CompoundButton;
|
||||
import android.widget.EditText;
|
||||
import android.widget.NumberPicker;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.StringRes;
|
||||
|
@ -28,10 +31,14 @@ import androidx.appcompat.app.AlertDialog;
|
|||
import com.beemdevelopment.aegis.Preferences;
|
||||
import com.beemdevelopment.aegis.R;
|
||||
import com.beemdevelopment.aegis.helpers.EditTextHelper;
|
||||
import com.beemdevelopment.aegis.helpers.PasswordStrengthHelper;
|
||||
import com.beemdevelopment.aegis.ui.tasks.KeyDerivationTask;
|
||||
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 java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
|
@ -90,9 +97,13 @@ public class Dialogs {
|
|||
}
|
||||
|
||||
public static void showSetPasswordDialog(Activity activity, Dialogs.SlotListener 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);
|
||||
ProgressBar barPasswordStrength = view.findViewById(R.id.progressBar);
|
||||
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);
|
||||
|
||||
switchToggleVisibility.setOnCheckedChangeListener((CompoundButton.OnCheckedChangeListener) (buttonView, isChecked) -> {
|
||||
|
@ -145,14 +156,24 @@ public class Dialogs {
|
|||
});
|
||||
|
||||
TextWatcher watcher = new TextWatcher() {
|
||||
@Override
|
||||
public void onTextChanged(CharSequence c, int start, int before, int count) {
|
||||
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();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beforeTextChanged(CharSequence c, int start, int count, int after) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterTextChanged(Editable c) {
|
||||
}
|
||||
};
|
||||
|
|
|
@ -1,13 +1,19 @@
|
|||
package com.beemdevelopment.aegis.ui.slides;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.content.res.ColorStateList;
|
||||
import android.graphics.Color;
|
||||
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;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.EditText;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.biometric.BiometricPrompt;
|
||||
|
@ -17,6 +23,7 @@ import com.beemdevelopment.aegis.R;
|
|||
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.ui.Dialogs;
|
||||
import com.beemdevelopment.aegis.ui.IntroActivity;
|
||||
import com.beemdevelopment.aegis.ui.tasks.KeyDerivationTask;
|
||||
|
@ -28,6 +35,9 @@ import com.beemdevelopment.aegis.vault.slots.SlotException;
|
|||
import com.github.appintro.SlidePolicy;
|
||||
import com.github.appintro.SlideSelectionListener;
|
||||
import com.google.android.material.snackbar.Snackbar;
|
||||
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;
|
||||
|
@ -37,16 +47,23 @@ public class SecuritySetupSlide extends Fragment implements SlidePolicy, SlideSe
|
|||
private EditText _textPassword;
|
||||
private EditText _textPasswordConfirm;
|
||||
private CheckBox _checkPasswordVisibility;
|
||||
private ProgressBar _barPasswordStrength;
|
||||
private TextView _textPasswordStrength;
|
||||
private TextInputLayout _textPasswordWrapper;
|
||||
|
||||
private int _cryptType;
|
||||
private VaultFileCredentials _creds;
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
Zxcvbn zxcvbn = new Zxcvbn();
|
||||
final View view = inflater.inflate(R.layout.fragment_security_setup_slide, container, false);
|
||||
_textPassword = view.findViewById(R.id.text_password);
|
||||
_textPasswordConfirm = view.findViewById(R.id.text_password_confirm);
|
||||
_checkPasswordVisibility = view.findViewById(R.id.check_toggle_visibility);
|
||||
_barPasswordStrength = view.findViewById(R.id.progressBar);
|
||||
_textPasswordStrength = view.findViewById(R.id.text_password_strength);
|
||||
_textPasswordWrapper = view.findViewById(R.id.text_password_wrapper);
|
||||
|
||||
_checkPasswordVisibility.setOnCheckedChangeListener((buttonView, isChecked) -> {
|
||||
if (isChecked) {
|
||||
|
@ -60,6 +77,26 @@ public class SecuritySetupSlide extends Fragment implements SlidePolicy, SlideSe
|
|||
}
|
||||
});
|
||||
|
||||
_textPassword.addTextChangedListener(new TextWatcher() {
|
||||
@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(), getContext()) : "");
|
||||
_textPasswordWrapper.setError(strength.getFeedback().getWarning());
|
||||
strength.wipe();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterTextChanged(Editable s) {
|
||||
}
|
||||
});
|
||||
|
||||
view.findViewById(R.id.main).setBackgroundColor(_bgColor);
|
||||
return view;
|
||||
}
|
||||
|
|
|
@ -14,19 +14,50 @@
|
|||
android:textColor="#FF0000"
|
||||
android:textStyle="bold"
|
||||
android:layout_marginStart="5dp"
|
||||
android:layout_marginEnd="5dp"/>
|
||||
<EditText
|
||||
android:id="@+id/text_password"
|
||||
android:hint="@string/password"
|
||||
android:inputType="textPassword"
|
||||
android:layout_marginEnd="5dp"
|
||||
android:layout_marginBottom="10dp" />
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:id="@+id/text_password_wrapper"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"/>
|
||||
<EditText
|
||||
android:hint="@string/confirm_password"
|
||||
android:id="@+id/text_password_confirm"
|
||||
android:inputType="textPassword"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<EditText
|
||||
android:id="@+id/text_password"
|
||||
android:hint="@string/password"
|
||||
android:inputType="textPassword"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"/>
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:id="@+id/text_password_confirm_wrapper"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"/>
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="10dp">
|
||||
|
||||
<EditText
|
||||
android:hint="@string/confirm_password"
|
||||
android:id="@+id/text_password_confirm"
|
||||
android:inputType="textPassword"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/progressBar"
|
||||
style="?android:attr/progressBarStyleHorizontal"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="10dp"
|
||||
android:max="4"
|
||||
android:paddingStart="4dp"
|
||||
android:paddingEnd="3.5dp" />
|
||||
<TextView
|
||||
android:id="@+id/text_password_strength"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="end" />
|
||||
|
||||
<CheckBox
|
||||
android:id="@+id/check_toggle_visibility"
|
||||
|
@ -34,4 +65,10 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="5dp"
|
||||
android:text="@string/show_password" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/text_password_hint"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="end" />
|
||||
</LinearLayout>
|
||||
|
|
|
@ -28,44 +28,47 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="24dp">
|
||||
|
||||
<TextView
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:id="@+id/text_password_wrapper"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentTop="true"
|
||||
android:layout_alignParentStart="true"
|
||||
android:id="@+id/textView4"
|
||||
android:text="@string/set_password"/>
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<EditText
|
||||
<EditText
|
||||
android:id="@+id/text_password"
|
||||
android:hint="@string/set_password"
|
||||
android:inputType="textPassword"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"/>
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:id="@+id/text_password_confirm_wrapper"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="10dp">
|
||||
|
||||
<EditText
|
||||
android:hint="@string/set_password_confirm"
|
||||
android:id="@+id/text_password_confirm"
|
||||
android:inputType="textPassword"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/progressBar"
|
||||
style="?android:attr/progressBarStyleHorizontal"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:inputType="textPassword"
|
||||
android:ems="10"
|
||||
android:id="@+id/text_password"
|
||||
android:layout_below="@+id/textView3"
|
||||
android:layout_alignParentStart="true"
|
||||
android:layout_marginTop="10dp"
|
||||
android:layout_alignParentEnd="true"/>
|
||||
|
||||
android:max="4"
|
||||
android:paddingStart="4dp"
|
||||
android:paddingEnd="3.5dp" />
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:id="@+id/text_password_strength"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/textView3"
|
||||
android:text="@string/set_password_confirm"
|
||||
android:layout_marginTop="20dp"
|
||||
android:layout_below="@+id/textView4"
|
||||
/>
|
||||
|
||||
<EditText
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:inputType="textPassword"
|
||||
android:ems="10"
|
||||
android:id="@+id/text_password_confirm"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_below="@+id/textView4"
|
||||
android:layout_alignParentStart="true"
|
||||
android:layout_alignParentEnd="true"/>
|
||||
android:layout_gravity="end" />
|
||||
|
||||
<CheckBox
|
||||
android:id="@+id/check_toggle_visibility"
|
||||
|
|
|
@ -64,5 +64,13 @@
|
|||
<item>tr</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="password_strength">
|
||||
<item>@string/password_strength_very_weak</item>
|
||||
<item>@string/password_strength_weak</item>
|
||||
<item>@string/password_strength_fair</item>
|
||||
<item>@string/password_strength_good</item>
|
||||
<item>@string/password_strength_strong</item>
|
||||
</string-array>
|
||||
|
||||
</resources>
|
||||
|
||||
|
|
|
@ -276,4 +276,10 @@
|
|||
<string name="previous">Previous</string>
|
||||
<string name="transfer_entry">Transfer entry</string>
|
||||
<string name="transfer_entry_description">Scan this QR code with the authenticator app you would like to transfer this entry to</string>
|
||||
|
||||
<string name="password_strength_very_weak">Very weak</string>
|
||||
<string name="password_strength_weak">Weak</string>
|
||||
<string name="password_strength_fair">Fair</string>
|
||||
<string name="password_strength_good">Good</string>
|
||||
<string name="password_strength_strong">Strong</string>
|
||||
</resources>
|
||||
|
|
Loading…
Add table
Reference in a new issue