mirror of
https://github.com/Kunzisoft/KeePassDX.git
synced 2025-12-04 15:49:33 +01:00
Add editable chars fields #539
This commit is contained in:
@@ -2,6 +2,7 @@ KeePassDX(3.4.0)
|
||||
* Show visual password strength indicator with entropy #631 #869
|
||||
* Dynamically save password generator configuration #618
|
||||
* Add advanced password filters #1052
|
||||
* Add editable chars fields #539
|
||||
|
||||
KeePassDX(3.3.3)
|
||||
* Fix shared otpauth link if database not open #1274
|
||||
|
||||
@@ -57,6 +57,8 @@ class GeneratePasswordDialogFragment : DatabaseDialogFragment() {
|
||||
private var specialsCompound: CompoundButton? = null
|
||||
private var bracketsCompound: CompoundButton? = null
|
||||
private var extendedCompound: CompoundButton? = null
|
||||
private var considerCharsEditText: EditText? = null
|
||||
private var ignoreCharsEditText: EditText? = null
|
||||
private var atLeastOneCompound: CompoundButton? = null
|
||||
private var excludeAmbiguousCompound: CompoundButton? = null
|
||||
|
||||
@@ -104,6 +106,8 @@ class GeneratePasswordDialogFragment : DatabaseDialogFragment() {
|
||||
specialsCompound = root?.findViewById(R.id.special_filter)
|
||||
bracketsCompound = root?.findViewById(R.id.brackets_filter)
|
||||
extendedCompound = root?.findViewById(R.id.extendedASCII_filter)
|
||||
considerCharsEditText = root?.findViewById(R.id.consider_chars_filter)
|
||||
ignoreCharsEditText = root?.findViewById(R.id.ignore_chars_filter)
|
||||
atLeastOneCompound = root?.findViewById(R.id.atLeastOne_filter)
|
||||
excludeAmbiguousCompound = root?.findViewById(R.id.excludeAmbiguous_filter)
|
||||
|
||||
@@ -138,6 +142,12 @@ class GeneratePasswordDialogFragment : DatabaseDialogFragment() {
|
||||
extendedCompound?.setOnCheckedChangeListener { _, _ ->
|
||||
fillPassword()
|
||||
}
|
||||
considerCharsEditText?.doOnTextChanged { _, _, _, _ ->
|
||||
fillPassword()
|
||||
}
|
||||
ignoreCharsEditText?.doOnTextChanged { _, _, _, _ ->
|
||||
fillPassword()
|
||||
}
|
||||
atLeastOneCompound?.setOnCheckedChangeListener { _, _ ->
|
||||
fillPassword()
|
||||
}
|
||||
@@ -325,6 +335,8 @@ class GeneratePasswordDialogFragment : DatabaseDialogFragment() {
|
||||
specialsCompound?.isChecked == true,
|
||||
bracketsCompound?.isChecked == true,
|
||||
extendedCompound?.isChecked == true,
|
||||
considerCharsEditText?.text?.toString() ?: "",
|
||||
ignoreCharsEditText?.text?.toString() ?: "",
|
||||
atLeastOneCompound?.isChecked == true,
|
||||
excludeAmbiguousCompound?.isChecked == true)
|
||||
} catch (e: Exception) {
|
||||
|
||||
@@ -37,6 +37,8 @@ class PasswordGenerator(private val resources: Resources) {
|
||||
specials: Boolean,
|
||||
brackets: Boolean,
|
||||
extended: Boolean,
|
||||
considerChars: String,
|
||||
ignoreChars: String,
|
||||
atLeastOneFromEach: Boolean,
|
||||
excludeAmbiguousChar: Boolean): String {
|
||||
// Desired password length is 0 or less
|
||||
@@ -53,83 +55,75 @@ class PasswordGenerator(private val resources: Resources) {
|
||||
&& !space
|
||||
&& !specials
|
||||
&& !brackets
|
||||
&& !extended) {
|
||||
&& !extended
|
||||
&& considerChars.isEmpty()) {
|
||||
throw IllegalArgumentException(resources.getString(R.string.error_pass_gen_type))
|
||||
}
|
||||
|
||||
// Filter builder
|
||||
val passwordFilters = PasswordFilters().apply {
|
||||
this.length = length
|
||||
this.ignoreChars = ignoreChars
|
||||
if (excludeAmbiguousChar)
|
||||
this.ignoreChars += AMBIGUOUS_CHARS
|
||||
if (upperCase) {
|
||||
addFilter(
|
||||
Filter(
|
||||
if (excludeAmbiguousChar) UPPERCASE_NON_AMBIGUOUS_CHARS else UPPERCASE_CHARS,
|
||||
UPPERCASE_CHARS,
|
||||
if (atLeastOneFromEach) 1 else 0
|
||||
)
|
||||
)
|
||||
}
|
||||
if (lowerCase) {
|
||||
addFilter(
|
||||
Filter(
|
||||
if (excludeAmbiguousChar) LOWERCASE_NON_AMBIGUOUS_CHARS else LOWERCASE_CHARS,
|
||||
LOWERCASE_CHARS,
|
||||
if (atLeastOneFromEach) 1 else 0
|
||||
)
|
||||
)
|
||||
}
|
||||
if (digits) {
|
||||
addFilter(
|
||||
Filter(
|
||||
if (excludeAmbiguousChar) DIGIT_NON_AMBIGUOUS_CHARS else DIGIT_CHARS,
|
||||
DIGIT_CHARS,
|
||||
if (atLeastOneFromEach) 1 else 0
|
||||
)
|
||||
)
|
||||
}
|
||||
if (minus) {
|
||||
addFilter(
|
||||
Filter(
|
||||
MINUS_CHAR,
|
||||
if (atLeastOneFromEach) 1 else 0
|
||||
)
|
||||
)
|
||||
}
|
||||
if (underline) {
|
||||
addFilter(
|
||||
Filter(
|
||||
UNDERLINE_CHAR,
|
||||
if (atLeastOneFromEach) 1 else 0
|
||||
)
|
||||
)
|
||||
}
|
||||
if (space) {
|
||||
addFilter(
|
||||
Filter(
|
||||
SPACE_CHAR,
|
||||
if (atLeastOneFromEach) 1 else 0
|
||||
)
|
||||
)
|
||||
}
|
||||
if (specials) {
|
||||
addFilter(
|
||||
Filter(
|
||||
SPECIAL_CHARS,
|
||||
if (atLeastOneFromEach) 1 else 0
|
||||
)
|
||||
)
|
||||
}
|
||||
if (brackets) {
|
||||
addFilter(
|
||||
Filter(
|
||||
BRACKET_CHARS,
|
||||
if (atLeastOneFromEach) 1 else 0
|
||||
)
|
||||
)
|
||||
}
|
||||
if (extended) {
|
||||
addFilter(
|
||||
Filter(
|
||||
extendedChars(),
|
||||
if (atLeastOneFromEach) 1 else 0
|
||||
)
|
||||
}
|
||||
if (considerChars.isNotEmpty()) {
|
||||
addFilter(
|
||||
considerChars,
|
||||
if (atLeastOneFromEach) 1 else 0
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -145,21 +139,24 @@ class PasswordGenerator(private val resources: Resources) {
|
||||
|
||||
// Build the password.
|
||||
for (i in 0 until passwordFilters.length) {
|
||||
val selectableChars: String = if (requiredCharactersLeft < passwordFilters.length - i) {
|
||||
var selectableChars: String = if (requiredCharactersLeft < passwordFilters.length - i) {
|
||||
// choose from any group at random
|
||||
passwordFilters.getSelectableChars()
|
||||
} else {
|
||||
// choose only from a group that we need to satisfy a minimum for.
|
||||
passwordFilters.getSelectableCharsForNeed()
|
||||
}
|
||||
passwordFilters.ignoreChars.forEach {
|
||||
selectableChars = selectableChars.replace(it.toString(), "")
|
||||
}
|
||||
|
||||
// Now that the string is built, get the next random character.
|
||||
val selectableCharsMaxIndex = selectableChars.length - 1
|
||||
val selectableCharsMaxIndex = selectableChars.length
|
||||
val randomSelectableCharsIndex = if (selectableCharsMaxIndex > 0) random.nextInt(selectableCharsMaxIndex) else 0
|
||||
val nextChar = selectableChars[randomSelectableCharsIndex]
|
||||
|
||||
// Put at random position
|
||||
val randomStringMaxIndex = randomString.length - 1
|
||||
val randomStringMaxIndex = randomString.length
|
||||
val randomStringIndex = if (randomStringMaxIndex > 0) random.nextInt(randomStringMaxIndex) else 0
|
||||
randomString.insert(randomStringIndex, nextChar)
|
||||
|
||||
@@ -179,10 +176,11 @@ class PasswordGenerator(private val resources: Resources) {
|
||||
|
||||
private class PasswordFilters {
|
||||
var length: Int = 0
|
||||
var ignoreChars = ""
|
||||
val filters = mutableListOf<Filter>()
|
||||
|
||||
fun addFilter(filter: Filter) {
|
||||
filters.add(filter)
|
||||
fun addFilter(chars: String, minCharsNeeded: Int) {
|
||||
filters.add(Filter(chars, minCharsNeeded))
|
||||
}
|
||||
|
||||
fun getRequiredCharactersLeft(): Int {
|
||||
@@ -241,15 +239,13 @@ class PasswordGenerator(private val resources: Resources) {
|
||||
|
||||
companion object {
|
||||
private const val UPPERCASE_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
private const val UPPERCASE_NON_AMBIGUOUS_CHARS = "ABCDEFGHJKMNPQRSTUVWXYZ"
|
||||
private const val LOWERCASE_CHARS = "abcdefghijklmnopqrstuvwxyz"
|
||||
private const val LOWERCASE_NON_AMBIGUOUS_CHARS = "abcdefghjkmnpqrstuvwxyz"
|
||||
private const val DIGIT_CHARS = "0123456789"
|
||||
private const val DIGIT_NON_AMBIGUOUS_CHARS = "23456789"
|
||||
private const val MINUS_CHAR = "-"
|
||||
private const val UNDERLINE_CHAR = "_"
|
||||
private const val SPACE_CHAR = " "
|
||||
private const val SPECIAL_CHARS = "!\"#$%&'*+,./:;=?@\\^`"
|
||||
private const val BRACKET_CHARS = "[]{}()<>"
|
||||
private const val AMBIGUOUS_CHARS = "iI|lLoO01"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -196,6 +196,35 @@
|
||||
|
||||
</com.google.android.material.chip.ChipGroup>
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:id="@+id/consider_chars_filter_layout"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@+id/ignore_chars_filter_layout"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content">
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/consider_chars_filter"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="@string/consider_chars_filter"/>
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:id="@+id/ignore_chars_filter_layout"
|
||||
app:layout_constraintStart_toEndOf="@+id/consider_chars_filter_layout"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content">
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/ignore_chars_filter"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="@string/ignore_chars_filter"/>
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
<com.google.android.material.chip.ChipGroup
|
||||
android:id="@+id/password_advanced"
|
||||
android:layout_width="match_parent"
|
||||
|
||||
@@ -608,6 +608,8 @@
|
||||
<string name="entropy_calculate">Entropy: Calculate…</string>
|
||||
<string name="at_least_one_char">At least one character from each</string>
|
||||
<string name="exclude_ambiguous_chars">Exclude ambiguous characters</string>
|
||||
<string name="consider_chars_filter">Consider characters</string>
|
||||
<string name="ignore_chars_filter">Ignore characters</string>
|
||||
<string-array name="timeout_options">
|
||||
<item>5 seconds</item>
|
||||
<item>10 seconds</item>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
* Show visual password strength indicator with entropy #631 #869
|
||||
* Dynamically save password generator configuration #618
|
||||
* Add advanced password filters #1052
|
||||
* Add editable chars fields #539
|
||||
@@ -1,3 +1,4 @@
|
||||
* Affichage d'un indicateur visuel de la force du mot de passe avec entropie #631 #869
|
||||
* Sauvegarde dynamique de la configuration du générateur de mots de passe #618
|
||||
* Ajout des filtres de mots de passe avancés #1052
|
||||
* Ajout de champs éditable de génération #539
|
||||
Reference in New Issue
Block a user