app: remove XkPasswd generator

This commit is contained in:
Harsh Shandilya 2021-12-10 14:51:05 +05:30
parent 0f837b0033
commit a700e2a766
No known key found for this signature in database
GPG key ID: 366D7BBAD1031E80
17 changed files with 15 additions and 9622 deletions

View file

@ -44,7 +44,6 @@ import dev.msfjarvis.aps.data.repo.PasswordRepository
import dev.msfjarvis.aps.databinding.PasswordCreationActivityBinding import dev.msfjarvis.aps.databinding.PasswordCreationActivityBinding
import dev.msfjarvis.aps.ui.dialogs.OtpImportDialogFragment import dev.msfjarvis.aps.ui.dialogs.OtpImportDialogFragment
import dev.msfjarvis.aps.ui.dialogs.PasswordGeneratorDialogFragment import dev.msfjarvis.aps.ui.dialogs.PasswordGeneratorDialogFragment
import dev.msfjarvis.aps.ui.dialogs.XkPasswordGeneratorDialogFragment
import dev.msfjarvis.aps.util.autofill.AutofillPreferences import dev.msfjarvis.aps.util.autofill.AutofillPreferences
import dev.msfjarvis.aps.util.autofill.DirectoryStructure import dev.msfjarvis.aps.util.autofill.DirectoryStructure
import dev.msfjarvis.aps.util.crypto.GpgIdentifier import dev.msfjarvis.aps.util.crypto.GpgIdentifier
@ -361,8 +360,6 @@ class PasswordCreationActivity : BasePgpActivity(), OpenPgpServiceConnection.OnB
when (settings.getString(PreferenceKeys.PREF_KEY_PWGEN_TYPE) ?: KEY_PWGEN_TYPE_CLASSIC) { when (settings.getString(PreferenceKeys.PREF_KEY_PWGEN_TYPE) ?: KEY_PWGEN_TYPE_CLASSIC) {
KEY_PWGEN_TYPE_CLASSIC -> KEY_PWGEN_TYPE_CLASSIC ->
PasswordGeneratorDialogFragment().show(supportFragmentManager, "generator") PasswordGeneratorDialogFragment().show(supportFragmentManager, "generator")
KEY_PWGEN_TYPE_XKPASSWD ->
XkPasswordGeneratorDialogFragment().show(supportFragmentManager, "xkpwgenerator")
} }
} }
@ -594,7 +591,6 @@ class PasswordCreationActivity : BasePgpActivity(), OpenPgpServiceConnection.OnB
companion object { companion object {
private const val KEY_PWGEN_TYPE_CLASSIC = "classic" private const val KEY_PWGEN_TYPE_CLASSIC = "classic"
private const val KEY_PWGEN_TYPE_XKPASSWD = "xkpasswd"
const val PASSWORD_RESULT_REQUEST_KEY = "PASSWORD_GENERATOR" const val PASSWORD_RESULT_REQUEST_KEY = "PASSWORD_GENERATOR"
const val OTP_RESULT_REQUEST_KEY = "OTP_IMPORT" const val OTP_RESULT_REQUEST_KEY = "OTP_IMPORT"
const val RESULT = "RESULT" const val RESULT = "RESULT"

View file

@ -41,7 +41,6 @@ import dev.msfjarvis.aps.databinding.PasswordCreationActivityBinding
import dev.msfjarvis.aps.injection.crypto.CryptoSet import dev.msfjarvis.aps.injection.crypto.CryptoSet
import dev.msfjarvis.aps.ui.dialogs.OtpImportDialogFragment import dev.msfjarvis.aps.ui.dialogs.OtpImportDialogFragment
import dev.msfjarvis.aps.ui.dialogs.PasswordGeneratorDialogFragment import dev.msfjarvis.aps.ui.dialogs.PasswordGeneratorDialogFragment
import dev.msfjarvis.aps.ui.dialogs.XkPasswordGeneratorDialogFragment
import dev.msfjarvis.aps.util.autofill.AutofillPreferences import dev.msfjarvis.aps.util.autofill.AutofillPreferences
import dev.msfjarvis.aps.util.autofill.DirectoryStructure import dev.msfjarvis.aps.util.autofill.DirectoryStructure
import dev.msfjarvis.aps.util.extensions.asLog import dev.msfjarvis.aps.util.extensions.asLog
@ -291,8 +290,6 @@ class PasswordCreationActivityV2 : BasePgpActivity() {
when (settings.getString(PreferenceKeys.PREF_KEY_PWGEN_TYPE) ?: KEY_PWGEN_TYPE_CLASSIC) { when (settings.getString(PreferenceKeys.PREF_KEY_PWGEN_TYPE) ?: KEY_PWGEN_TYPE_CLASSIC) {
KEY_PWGEN_TYPE_CLASSIC -> KEY_PWGEN_TYPE_CLASSIC ->
PasswordGeneratorDialogFragment().show(supportFragmentManager, "generator") PasswordGeneratorDialogFragment().show(supportFragmentManager, "generator")
KEY_PWGEN_TYPE_XKPASSWD ->
XkPasswordGeneratorDialogFragment().show(supportFragmentManager, "xkpwgenerator")
} }
} }
@ -469,7 +466,6 @@ class PasswordCreationActivityV2 : BasePgpActivity() {
companion object { companion object {
private const val KEY_PWGEN_TYPE_CLASSIC = "classic" private const val KEY_PWGEN_TYPE_CLASSIC = "classic"
private const val KEY_PWGEN_TYPE_XKPASSWD = "xkpasswd"
const val PASSWORD_RESULT_REQUEST_KEY = "PASSWORD_GENERATOR" const val PASSWORD_RESULT_REQUEST_KEY = "PASSWORD_GENERATOR"
const val OTP_RESULT_REQUEST_KEY = "OTP_IMPORT" const val OTP_RESULT_REQUEST_KEY = "OTP_IMPORT"
const val RESULT = "RESULT" const val RESULT = "RESULT"

View file

@ -1,156 +0,0 @@
/*
* Copyright © 2014-2021 The Android Password Store Authors. All Rights Reserved.
* SPDX-License-Identifier: GPL-3.0-only
*/
package dev.msfjarvis.aps.ui.dialogs
import android.app.Dialog
import android.content.Context
import android.content.SharedPreferences
import android.graphics.Typeface
import android.os.Bundle
import android.widget.Toast
import androidx.appcompat.app.AlertDialog
import androidx.core.content.edit
import androidx.core.os.bundleOf
import androidx.fragment.app.DialogFragment
import androidx.fragment.app.setFragmentResult
import androidx.lifecycle.lifecycleScope
import com.github.michaelbull.result.fold
import com.github.michaelbull.result.getOr
import com.github.michaelbull.result.runCatching
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import dev.msfjarvis.aps.R
import dev.msfjarvis.aps.databinding.FragmentXkpwgenBinding
import dev.msfjarvis.aps.ui.crypto.PasswordCreationActivity
import dev.msfjarvis.aps.util.extensions.asLog
import dev.msfjarvis.aps.util.extensions.getString
import dev.msfjarvis.aps.util.pwgenxkpwd.CapsType
import dev.msfjarvis.aps.util.pwgenxkpwd.PasswordBuilder
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.merge
import kotlinx.coroutines.flow.onEach
import logcat.LogPriority.ERROR
import logcat.logcat
import reactivecircus.flowbinding.android.widget.afterTextChanges
import reactivecircus.flowbinding.android.widget.selectionEvents
@OptIn(ExperimentalCoroutinesApi::class)
class XkPasswordGeneratorDialogFragment : DialogFragment() {
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val builder = MaterialAlertDialogBuilder(requireContext())
val callingActivity = requireActivity()
val inflater = callingActivity.layoutInflater
val binding = FragmentXkpwgenBinding.inflate(inflater)
val monoTypeface = Typeface.createFromAsset(callingActivity.assets, "fonts/sourcecodepro.ttf")
val prefs = callingActivity.getSharedPreferences("PasswordGenerator", Context.MODE_PRIVATE)
builder.setView(binding.root)
val previousStoredCapStyle: String =
runCatching { prefs.getString(PREF_KEY_CAPITALS_STYLE)!! }.getOr(DEFAULT_CAPS_STYLE)
val lastCapitalsStyleIndex: Int =
runCatching { CapsType.valueOf(previousStoredCapStyle).ordinal }.getOr(DEFAULT_CAPS_INDEX)
binding.xkCapType.setSelection(lastCapitalsStyleIndex)
binding.xkNumWords.setText(prefs.getString(PREF_KEY_NUM_WORDS, DEFAULT_NUMBER_OF_WORDS))
binding.xkSeparator.setText(prefs.getString(PREF_KEY_SEPARATOR, DEFAULT_WORD_SEPARATOR))
binding.xkNumberSymbolMask.setText(
prefs.getString(PREF_KEY_EXTRA_SYMBOLS_MASK, DEFAULT_EXTRA_SYMBOLS_MASK)
)
binding.xkPasswordText.typeface = monoTypeface
builder.setPositiveButton(resources.getString(R.string.dialog_ok)) { _, _ ->
setPreferences(binding, prefs)
setFragmentResult(
PasswordCreationActivity.PASSWORD_RESULT_REQUEST_KEY,
bundleOf(PasswordCreationActivity.RESULT to "${binding.xkPasswordText.text}")
)
}
// flip neutral and negative buttons
builder.setNeutralButton(resources.getString(R.string.dialog_cancel)) { _, _ -> }
builder.setNegativeButton(resources.getString(R.string.pwgen_generate), null)
val dialog = builder.setTitle(this.resources.getString(R.string.xkpwgen_title)).create()
// make parameter changes reactive and automatically update passwords
merge(
binding.xkSeparator.afterTextChanges().skipInitialValue(),
binding.xkCapType.selectionEvents().skipInitialValue(),
binding.xkNumWords.afterTextChanges().skipInitialValue(),
binding.xkNumberSymbolMask.afterTextChanges().skipInitialValue(),
)
.onEach { updatePassword(binding, prefs) }
.launchIn(lifecycleScope)
dialog.setOnShowListener {
updatePassword(binding, prefs)
dialog.getButton(AlertDialog.BUTTON_NEGATIVE).setOnClickListener {
updatePassword(binding, prefs)
}
}
return dialog
}
private fun updatePassword(binding: FragmentXkpwgenBinding, prefs: SharedPreferences) {
setPreferences(binding, prefs)
makeAndSetPassword(binding)
}
private fun makeAndSetPassword(binding: FragmentXkpwgenBinding) {
PasswordBuilder(requireContext())
.setNumberOfWords(binding.xkNumWords.text.toString().ifBlank { "0" }.toInt())
.setMinimumWordLength(DEFAULT_MIN_WORD_LENGTH)
.setMaximumWordLength(DEFAULT_MAX_WORD_LENGTH)
.setSeparator(binding.xkSeparator.text.toString())
.appendNumbers(
binding.xkNumberSymbolMask.text!!.count { c -> c == EXTRA_CHAR_PLACEHOLDER_DIGIT }
)
.appendSymbols(
binding.xkNumberSymbolMask.text!!.count { c -> c == EXTRA_CHAR_PLACEHOLDER_SYMBOL }
)
.setCapitalization(CapsType.valueOf(binding.xkCapType.selectedItem.toString()))
.create()
.fold(
success = { binding.xkPasswordText.text = it },
failure = { e ->
Toast.makeText(requireActivity(), e.message, Toast.LENGTH_SHORT).show()
logcat("xkpw", ERROR) { e.asLog("failure generating xkpasswd") }
binding.xkPasswordText.text = FALLBACK_ERROR_PASS
},
)
}
private fun setPreferences(binding: FragmentXkpwgenBinding, prefs: SharedPreferences) {
prefs.edit {
putString(PREF_KEY_CAPITALS_STYLE, binding.xkCapType.selectedItem.toString())
putString(PREF_KEY_NUM_WORDS, binding.xkNumWords.text.toString())
putString(PREF_KEY_SEPARATOR, binding.xkSeparator.text.toString())
putString(PREF_KEY_EXTRA_SYMBOLS_MASK, binding.xkNumberSymbolMask.text.toString())
}
}
companion object {
const val PREF_KEY_CAPITALS_STYLE = "pref_key_capitals_style"
const val PREF_KEY_NUM_WORDS = "pref_key_num_words"
const val PREF_KEY_SEPARATOR = "pref_key_separator"
const val PREF_KEY_EXTRA_SYMBOLS_MASK = "pref_key_xkpwgen_extra_symbols_mask"
val DEFAULT_CAPS_STYLE = CapsType.Sentence.name
val DEFAULT_CAPS_INDEX = CapsType.Sentence.ordinal
const val DEFAULT_NUMBER_OF_WORDS = "3"
const val DEFAULT_WORD_SEPARATOR = "."
const val DEFAULT_EXTRA_SYMBOLS_MASK = "ds"
const val DEFAULT_MIN_WORD_LENGTH = 3
const val DEFAULT_MAX_WORD_LENGTH = 9
const val FALLBACK_ERROR_PASS = "42"
const val EXTRA_CHAR_PLACEHOLDER_DIGIT = 'd'
const val EXTRA_CHAR_PLACEHOLDER_SYMBOL = 's'
}
}

View file

@ -6,78 +6,20 @@
package dev.msfjarvis.aps.ui.settings package dev.msfjarvis.aps.ui.settings
import android.text.InputType import android.text.InputType
import android.widget.Toast
import androidx.activity.result.contract.ActivityResultContracts
import androidx.core.content.edit
import androidx.fragment.app.FragmentActivity import androidx.fragment.app.FragmentActivity
import de.Maxr1998.modernpreferences.Preference
import de.Maxr1998.modernpreferences.PreferenceScreen import de.Maxr1998.modernpreferences.PreferenceScreen
import de.Maxr1998.modernpreferences.helpers.checkBox import de.Maxr1998.modernpreferences.helpers.checkBox
import de.Maxr1998.modernpreferences.helpers.editText import de.Maxr1998.modernpreferences.helpers.editText
import de.Maxr1998.modernpreferences.helpers.onCheckedChange
import de.Maxr1998.modernpreferences.helpers.onClick
import de.Maxr1998.modernpreferences.helpers.onSelectionChange import de.Maxr1998.modernpreferences.helpers.onSelectionChange
import de.Maxr1998.modernpreferences.helpers.singleChoice import de.Maxr1998.modernpreferences.helpers.singleChoice
import de.Maxr1998.modernpreferences.preferences.CheckBoxPreference
import de.Maxr1998.modernpreferences.preferences.choice.SelectionItem import de.Maxr1998.modernpreferences.preferences.choice.SelectionItem
import dev.msfjarvis.aps.R import dev.msfjarvis.aps.R
import dev.msfjarvis.aps.util.extensions.getString
import dev.msfjarvis.aps.util.extensions.sharedPrefs
import dev.msfjarvis.aps.util.extensions.unsafeLazy
import dev.msfjarvis.aps.util.pwgenxkpwd.XkpwdDictionary
import dev.msfjarvis.aps.util.settings.PreferenceKeys import dev.msfjarvis.aps.util.settings.PreferenceKeys
import java.io.File
class PasswordSettings(private val activity: FragmentActivity) : SettingsProvider { class PasswordSettings(private val activity: FragmentActivity) : SettingsProvider {
private val sharedPrefs by unsafeLazy { activity.sharedPrefs }
private val storeCustomXkpwdDictionaryAction =
activity.registerForActivityResult(ActivityResultContracts.OpenDocument()) { uri ->
if (uri == null) return@registerForActivityResult
Toast.makeText(
activity,
activity.resources.getString(R.string.xkpwgen_custom_dict_imported, uri.path),
Toast.LENGTH_SHORT
)
.show()
sharedPrefs.edit { putString(PreferenceKeys.PREF_KEY_CUSTOM_DICT, uri.toString()) }
val inputStream = activity.contentResolver.openInputStream(uri)
val customDictFile =
File(activity.filesDir.toString(), XkpwdDictionary.XKPWD_CUSTOM_DICT_FILE).outputStream()
inputStream?.copyTo(customDictFile, 1024)
inputStream?.close()
customDictFile.close()
}
override fun provideSettings(builder: PreferenceScreen.Builder) { override fun provideSettings(builder: PreferenceScreen.Builder) {
builder.apply { builder.apply {
val customDictPref =
CheckBoxPreference(PreferenceKeys.PREF_KEY_IS_CUSTOM_DICT).apply {
titleRes = R.string.pref_xkpwgen_custom_wordlist_enabled_title
summaryRes = R.string.pref_xkpwgen_custom_dict_summary_off
summaryOnRes = R.string.pref_xkpwgen_custom_dict_summary_on
visible = sharedPrefs.getString(PreferenceKeys.PREF_KEY_PWGEN_TYPE) == "xkpasswd"
onCheckedChange {
requestRebind()
true
}
}
val customDictPathPref =
Preference(PreferenceKeys.PREF_KEY_CUSTOM_DICT).apply {
dependency = PreferenceKeys.PREF_KEY_IS_CUSTOM_DICT
titleRes = R.string.pref_xkpwgen_custom_dict_picker_title
summary =
sharedPrefs.getString(PreferenceKeys.PREF_KEY_CUSTOM_DICT)
?: activity.resources.getString(R.string.pref_xkpwgen_custom_dict_picker_summary)
visible = sharedPrefs.getString(PreferenceKeys.PREF_KEY_PWGEN_TYPE) == "xkpasswd"
onClick {
storeCustomXkpwdDictionaryAction.launch(arrayOf("*/*"))
true
}
}
val values = activity.resources.getStringArray(R.array.pwgen_provider_values) val values = activity.resources.getStringArray(R.array.pwgen_provider_values)
val labels = activity.resources.getStringArray(R.array.pwgen_provider_labels) val labels = activity.resources.getStringArray(R.array.pwgen_provider_labels)
val items = values.zip(labels).map { SelectionItem(it.first, it.second, null) } val items = values.zip(labels).map { SelectionItem(it.first, it.second, null) }
@ -87,19 +29,8 @@ class PasswordSettings(private val activity: FragmentActivity) : SettingsProvide
) { ) {
initialSelection = "classic" initialSelection = "classic"
titleRes = R.string.pref_password_generator_type_title titleRes = R.string.pref_password_generator_type_title
onSelectionChange { selection -> onSelectionChange { true }
val xkpasswdEnabled = selection == "xkpasswd"
customDictPathPref.visible = xkpasswdEnabled
customDictPref.visible = xkpasswdEnabled
customDictPref.requestRebind()
customDictPathPref.requestRebind()
true
}
} }
// We initialize them early and add them manually to be able to manually force a rebind
// when the password generator type is changed.
addPreferenceItem(customDictPref)
addPreferenceItem(customDictPathPref)
editText(PreferenceKeys.GENERAL_SHOW_TIME) { editText(PreferenceKeys.GENERAL_SHOW_TIME) {
titleRes = R.string.pref_clipboard_timeout_title titleRes = R.string.pref_clipboard_timeout_title
summaryProvider = summaryProvider =

View file

@ -1,13 +0,0 @@
/*
* Copyright © 2014-2021 The Android Password Store Authors. All Rights Reserved.
* SPDX-License-Identifier: GPL-3.0-only
*/
package dev.msfjarvis.aps.util.pwgenxkpwd
enum class CapsType {
lowercase,
UPPERCASE,
TitleCase,
Sentence,
As_iS
}

View file

@ -1,143 +0,0 @@
/*
* Copyright © 2014-2021 The Android Password Store Authors. All Rights Reserved.
* SPDX-License-Identifier: GPL-3.0-only
*/
package dev.msfjarvis.aps.util.pwgenxkpwd
import android.content.Context
import com.github.michaelbull.result.Result
import com.github.michaelbull.result.runCatching
import dev.msfjarvis.aps.R
import dev.msfjarvis.aps.util.pwgen.PasswordGenerator.PasswordGeneratorException
import dev.msfjarvis.aps.util.pwgen.secureRandomCharacter
import dev.msfjarvis.aps.util.pwgen.secureRandomElement
import dev.msfjarvis.aps.util.pwgen.secureRandomNumber
import java.util.Locale
class PasswordBuilder(ctx: Context) {
private var numSymbols = 0
private var isAppendSymbolsSeparator = false
private var context = ctx
private var numWords = 3
private var maxWordLength = 9
private var minWordLength = 5
private var separator = "."
private var capsType = CapsType.Sentence
private var prependDigits = 0
private var numDigits = 0
private var isPrependWithSeparator = false
private var isAppendNumberSeparator = false
fun setNumberOfWords(amount: Int) = apply { numWords = amount }
fun setMinimumWordLength(min: Int) = apply { minWordLength = min }
fun setMaximumWordLength(max: Int) = apply { maxWordLength = max }
fun setSeparator(separator: String) = apply { this.separator = separator }
fun setCapitalization(capitalizationScheme: CapsType) = apply { capsType = capitalizationScheme }
@JvmOverloads
fun prependNumbers(numDigits: Int, addSeparator: Boolean = true) = apply {
prependDigits = numDigits
isPrependWithSeparator = addSeparator
}
@JvmOverloads
fun appendNumbers(numDigits: Int, addSeparator: Boolean = false) = apply {
this.numDigits = numDigits
isAppendNumberSeparator = addSeparator
}
@JvmOverloads
fun appendSymbols(numSymbols: Int, addSeparator: Boolean = false) = apply {
this.numSymbols = numSymbols
isAppendSymbolsSeparator = addSeparator
}
private fun generateRandomNumberSequence(totalNumbers: Int): String {
val numbers = StringBuilder(totalNumbers)
for (i in 0 until totalNumbers) {
numbers.append(secureRandomNumber(10))
}
return numbers.toString()
}
private fun generateRandomSymbolSequence(numSymbols: Int): String {
val numbers = StringBuilder(numSymbols)
for (i in 0 until numSymbols) {
numbers.append(SYMBOLS.secureRandomCharacter())
}
return numbers.toString()
}
@OptIn(ExperimentalStdlibApi::class)
fun create(): Result<String, Throwable> {
val wordBank = mutableListOf<String>()
val password = StringBuilder()
if (prependDigits != 0) {
password.append(generateRandomNumberSequence(prependDigits))
if (isPrependWithSeparator) {
password.append(separator)
}
}
return runCatching {
val dictionary = XkpwdDictionary(context)
val words = dictionary.words
for (wordLength in minWordLength..maxWordLength) {
wordBank.addAll(words[wordLength] ?: emptyList())
}
if (wordBank.size == 0) {
throw PasswordGeneratorException(
context.getString(R.string.xkpwgen_builder_error, minWordLength, maxWordLength)
)
}
for (i in 0 until numWords) {
val candidate = wordBank.secureRandomElement()
val s =
when (capsType) {
CapsType.UPPERCASE -> candidate.uppercase(Locale.getDefault())
CapsType.Sentence ->
if (i == 0)
candidate.replaceFirstChar {
if (it.isLowerCase()) it.titlecase(Locale.getDefault()) else it.toString()
}
else candidate
CapsType.TitleCase ->
candidate.replaceFirstChar {
if (it.isLowerCase()) it.titlecase(Locale.getDefault()) else it.toString()
}
CapsType.lowercase -> candidate.lowercase(Locale.getDefault())
CapsType.As_iS -> candidate
}
password.append(s)
if (i + 1 < numWords) {
password.append(separator)
}
}
if (numDigits != 0) {
if (isAppendNumberSeparator) {
password.append(separator)
}
password.append(generateRandomNumberSequence(numDigits))
}
if (numSymbols != 0) {
if (isAppendSymbolsSeparator) {
password.append(separator)
}
password.append(generateRandomSymbolSequence(numSymbols))
}
password.toString()
}
}
companion object {
private const val SYMBOLS = "!@\$%^&*-_+=:|~?/.;#"
}
}

View file

@ -1,43 +0,0 @@
/*
* Copyright © 2014-2021 The Android Password Store Authors. All Rights Reserved.
* SPDX-License-Identifier: GPL-3.0-only
*/
package dev.msfjarvis.aps.util.pwgenxkpwd
import android.content.Context
import dev.msfjarvis.aps.R
import dev.msfjarvis.aps.util.extensions.getString
import dev.msfjarvis.aps.util.extensions.sharedPrefs
import dev.msfjarvis.aps.util.settings.PreferenceKeys
import java.io.File
class XkpwdDictionary(context: Context) {
val words: Map<Int, List<String>>
init {
val prefs = context.sharedPrefs
val uri = prefs.getString(PreferenceKeys.PREF_KEY_CUSTOM_DICT) ?: ""
val customDictFile = File(context.filesDir, XKPWD_CUSTOM_DICT_FILE)
val lines =
if (prefs.getBoolean(PreferenceKeys.PREF_KEY_IS_CUSTOM_DICT, false) &&
uri.isNotEmpty() &&
customDictFile.canRead()
) {
customDictFile.readLines()
} else {
context.resources.openRawResource(R.raw.xkpwdict).bufferedReader().readLines()
}
words =
lines.asSequence().map { it.trim() }.filter { it.isNotEmpty() && !it.contains(' ') }.groupBy {
it.length
}
}
companion object {
const val XKPWD_CUSTOM_DICT_FILE = "custom_dict.txt"
}
}

View file

@ -1,102 +0,0 @@
<!--
~ Copyright © 2014-2021 The Android Password Store Authors. All Rights Reserved.
~ SPDX-License-Identifier: GPL-3.0-only
-->
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingStart="24dp"
android:paddingTop="20dp"
android:paddingEnd="24dp"
android:paddingBottom="20dp">
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/xkPasswordText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="8dp"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textIsSelectable="true"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="horisticia.tockmendprost" />
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/total_words"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:hint="@string/xkpwgen_length"
android:labelFor="@id/xk_num_words"
app:layout_constraintEnd_toStartOf="@id/separator"
app:layout_constraintHorizontal_weight="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/xkPasswordText">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/xk_num_words"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="number"
android:maxLength="2" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/separator"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:hint="@string/xkpwgen_separator"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_weight="0.5"
app:layout_constraintStart_toEndOf="@id/total_words"
app:layout_constraintTop_toTopOf="@id/total_words">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/xk_separator"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:autofillHints=""
android:inputType="text" />
</com.google.android.material.textfield.TextInputLayout>
<Spinner
android:id="@+id/xkCapType"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:entries="@array/capitalization_type_values"
android:entryValues="@array/capitalization_type_values"
android:spinnerMode="dropdown"
app:layout_constraintEnd_toEndOf="@id/total_words"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/total_words" />
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/xk_numbers_symbols_label"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:hint="@string/xkpwgen_extrachars_label"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="@id/separator"
app:layout_constraintTop_toBottomOf="@id/separator"
app:layout_constraintTop_toTopOf="@id/xkCapType">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/xk_number_symbol_mask"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:autofillHints=""
android:inputType="text"
android:text="@string/xk_numbers_symbols_append_default" />
</com.google.android.material.textfield.TextInputLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
</ScrollView>

File diff suppressed because it is too large Load diff

View file

@ -138,19 +138,9 @@
<string name="pwgen_no_chars_error">Keine Zeichen hinzugefügt</string> <string name="pwgen_no_chars_error">Keine Zeichen hinzugefügt</string>
<string name="pwgen_length_too_short_error">Länge zu kurz für ausgewählte Kriterien</string> <string name="pwgen_length_too_short_error">Länge zu kurz für ausgewählte Kriterien</string>
<string name="pwgen_max_iterations_exceeded">Fehler beim Generieren eines Passworts, das die Einschränkungen erfüllt. Versuchen Sie, die Länge zu erhöhen.</string> <string name="pwgen_max_iterations_exceeded">Fehler beim Generieren eines Passworts, das die Einschränkungen erfüllt. Versuchen Sie, die Länge zu erhöhen.</string>
<!-- XKPWD password generator --> <string name="pwgen_separator">Trennzeichen</string>
<string name="xkpwgen_title">Xkpasswd Generator</string> <!-- Password generator prefs -->
<string name="xkpwgen_length">Wörter insgesamt</string>
<string name="xkpwgen_separator">Trennzeichen</string>
<string name="xkpwgen_custom_dict_imported">Eigene Wortliste: %1$s</string>
<string name="xkpwgen_builder_error">Das ausgewählte Wörterbuch enthält nicht genügend Wörter der angegebenen Länge %1$d..%2$d</string>
<!-- XKPWD prefs -->
<string name="pref_password_generator_type_title">Passwortgenerator</string> <string name="pref_password_generator_type_title">Passwortgenerator</string>
<string name="pref_xkpwgen_custom_wordlist_enabled_title">Eigene Wortliste</string>
<string name="pref_xkpwgen_custom_dict_summary_on">Eigene Wordlist-Datei verwenden</string>
<string name="pref_xkpwgen_custom_dict_summary_off">Integrierte Wortliste verwenden</string>
<string name="pref_xkpwgen_custom_dict_picker_title">Eigene Wortliste</string>
<string name="pref_xkpwgen_custom_dict_picker_summary">Tippen Sie, um eine benutzerdefinierte Wordlist-Datei mit einem Wort pro Zeile auszuwählen</string>
<!-- ssh keygen fragment --> <!-- ssh keygen fragment -->
<string name="ssh_keygen_passphrase">Passwort</string> <string name="ssh_keygen_passphrase">Passwort</string>
<string name="ssh_keygen_generate">Generieren</string> <string name="ssh_keygen_generate">Generieren</string>

View file

@ -142,19 +142,9 @@
<string name="pwgen_no_chars_error">Aucun critère sélectionné</string> <string name="pwgen_no_chars_error">Aucun critère sélectionné</string>
<string name="pwgen_length_too_short_error">Longueur trop faible pour les critères sélectionnés</string> <string name="pwgen_length_too_short_error">Longueur trop faible pour les critères sélectionnés</string>
<string name="pwgen_max_iterations_exceeded">Impossible de générer un mot de passe satisfaisant les critères. Essayez d\'augmenter la longueur.</string> <string name="pwgen_max_iterations_exceeded">Impossible de générer un mot de passe satisfaisant les critères. Essayez d\'augmenter la longueur.</string>
<!-- XKPWD password generator --> <string name="pwgen_separator">Séparateur</string>
<string name="xkpwgen_title">Générateur XKCD</string> <!-- Password generator prefs -->
<string name="xkpwgen_length">Nombre de mots</string>
<string name="xkpwgen_separator">Séparateur</string>
<string name="xkpwgen_custom_dict_imported">Liste de mots personnalisée : %1$s</string>
<string name="xkpwgen_builder_error">Le dictionnaire sélectionné ne contient pas assez de mots de la longueur %1$d..%2$d</string>
<!-- XKPWD prefs -->
<string name="pref_password_generator_type_title">Type de générateur de mot de passe</string> <string name="pref_password_generator_type_title">Type de générateur de mot de passe</string>
<string name="pref_xkpwgen_custom_wordlist_enabled_title">Liste de mots personnalisée</string>
<string name="pref_xkpwgen_custom_dict_summary_on">Utiliser un fichier comme liste de mots personnalisée</string>
<string name="pref_xkpwgen_custom_dict_summary_off">Utilisation de la liste de mots intégrée</string>
<string name="pref_xkpwgen_custom_dict_picker_title">Fichier personnalisé de liste de mots</string>
<string name="pref_xkpwgen_custom_dict_picker_summary">Touchez pour choisir un fichier de liste de mots personnalisés contenant un mot par ligne</string>
<!-- ssh keygen fragment --> <!-- ssh keygen fragment -->
<string name="ssh_keygen_passphrase">Mot de passe</string> <string name="ssh_keygen_passphrase">Mot de passe</string>
<string name="ssh_keygen_generate">Générer</string> <string name="ssh_keygen_generate">Générer</string>

View file

@ -142,19 +142,9 @@
<string name="pwgen_no_chars_error">Sen caracteres incluídos</string> <string name="pwgen_no_chars_error">Sen caracteres incluídos</string>
<string name="pwgen_length_too_short_error">Lonxitude demasiado curta para o criterio</string> <string name="pwgen_length_too_short_error">Lonxitude demasiado curta para o criterio</string>
<string name="pwgen_max_iterations_exceeded">Fallou a creación do contrasinal satisfacendo os requerimentos. Intenta aumentar a lonxitude.</string> <string name="pwgen_max_iterations_exceeded">Fallou a creación do contrasinal satisfacendo os requerimentos. Intenta aumentar a lonxitude.</string>
<!-- XKPWD password generator --> <string name="pwgen_separator">Separador</string>
<string name="xkpwgen_title">Xkpasswd Generator</string> <!-- Password generator prefs -->
<string name="xkpwgen_length">Total de palabras</string>
<string name="xkpwgen_separator">Separador</string>
<string name="xkpwgen_custom_dict_imported">Lista persoal de palabras: %1$s</string>
<string name="xkpwgen_builder_error">O dicionario non contén palabras suficientes da lonxitude dada %1$d .. %2$d</string>
<!-- XKPWD prefs -->
<string name="pref_password_generator_type_title">Tipo de creador de contrasinais</string> <string name="pref_password_generator_type_title">Tipo de creador de contrasinais</string>
<string name="pref_xkpwgen_custom_wordlist_enabled_title">Lista persoal de palabras</string>
<string name="pref_xkpwgen_custom_dict_summary_on">Usar ficheiro con palabras personalizadas</string>
<string name="pref_xkpwgen_custom_dict_summary_off">Usar lista de palabras incluída</string>
<string name="pref_xkpwgen_custom_dict_picker_title">Ficheiro persoal de palabras</string>
<string name="pref_xkpwgen_custom_dict_picker_summary">Toca para escoller un ficheiro persoal con palabras que conteña unha palabra por liña</string>
<!-- ssh keygen fragment --> <!-- ssh keygen fragment -->
<string name="ssh_keygen_passphrase">Frase de paso</string> <string name="ssh_keygen_passphrase">Frase de paso</string>
<string name="ssh_keygen_generate">Crear</string> <string name="ssh_keygen_generate">Crear</string>

View file

@ -136,19 +136,9 @@
<string name="pwgen_no_chars_error">Nessun carattere incluso</string> <string name="pwgen_no_chars_error">Nessun carattere incluso</string>
<string name="pwgen_length_too_short_error">Lunghezza troppo breve per i criteri selezionati</string> <string name="pwgen_length_too_short_error">Lunghezza troppo breve per i criteri selezionati</string>
<string name="pwgen_max_iterations_exceeded">Impossibile generare una password che soddisfi i vincoli. Prova ad aumentare la lunghezza.</string> <string name="pwgen_max_iterations_exceeded">Impossibile generare una password che soddisfi i vincoli. Prova ad aumentare la lunghezza.</string>
<!-- XKPWD password generator --> <string name="pwgen_separator">Separatore</string>
<string name="xkpwgen_title">Generatore di Xkpasswd</string> <!-- Password generator prefs -->
<string name="xkpwgen_length">Parole totali</string>
<string name="xkpwgen_separator">Separatore</string>
<string name="xkpwgen_custom_dict_imported">Lista di parole personalizzata: %1$s</string>
<string name="xkpwgen_builder_error">Il dizionario selezionato non contiene abbastanza parole della data lunghezza %1$d..%2$d</string>
<!-- XKPWD prefs -->
<string name="pref_password_generator_type_title">Tipo di generatore di password</string> <string name="pref_password_generator_type_title">Tipo di generatore di password</string>
<string name="pref_xkpwgen_custom_wordlist_enabled_title">Lista di parole personalizzata</string>
<string name="pref_xkpwgen_custom_dict_summary_on">Usando file di elenco di parole personalizzati</string>
<string name="pref_xkpwgen_custom_dict_summary_off">Usando liste di parole integrate</string>
<string name="pref_xkpwgen_custom_dict_picker_title">File di elenco di parole personalizzato</string>
<string name="pref_xkpwgen_custom_dict_picker_summary">Tocca per selezionare un file di lista di parole personalizzato contenente una parola per riga</string>
<!-- ssh keygen fragment --> <!-- ssh keygen fragment -->
<string name="ssh_keygen_passphrase">Frase Segreta</string> <string name="ssh_keygen_passphrase">Frase Segreta</string>
<string name="ssh_keygen_generate">Genera</string> <string name="ssh_keygen_generate">Genera</string>

View file

@ -142,19 +142,9 @@
<string name="pwgen_no_chars_error">Nenhum caractere incluso</string> <string name="pwgen_no_chars_error">Nenhum caractere incluso</string>
<string name="pwgen_length_too_short_error">Comprimento muito curto para os critérios selecionados</string> <string name="pwgen_length_too_short_error">Comprimento muito curto para os critérios selecionados</string>
<string name="pwgen_max_iterations_exceeded">Falha ao gerar uma senha de acordo com as restrições. Tente aumentar o comprimento.</string> <string name="pwgen_max_iterations_exceeded">Falha ao gerar uma senha de acordo com as restrições. Tente aumentar o comprimento.</string>
<!-- XKPWD password generator --> <string name="pwgen_separator">Separador</string>
<string name="xkpwgen_title">Xkpasswd Generator</string> <!-- Password generator prefs -->
<string name="xkpwgen_length">Total de palavras</string>
<string name="xkpwgen_separator">Separador</string>
<string name="xkpwgen_custom_dict_imported">Lista de palavras personalizada: %1$s</string>
<string name="xkpwgen_builder_error">O dicionário selecionado não contém palavras suficientes de tamanho %1$d..%2$d</string>
<!-- XKPWD prefs -->
<string name="pref_password_generator_type_title">Tipo de gerador de senha</string> <string name="pref_password_generator_type_title">Tipo de gerador de senha</string>
<string name="pref_xkpwgen_custom_wordlist_enabled_title">Lista de palavras personalizadas</string>
<string name="pref_xkpwgen_custom_dict_summary_on">Usando um arquivo de Lista de Palavras</string>
<string name="pref_xkpwgen_custom_dict_summary_off">Usando o arquivo de palavras embutido</string>
<string name="pref_xkpwgen_custom_dict_picker_title">Lista de palavras personalizadas</string>
<string name="pref_xkpwgen_custom_dict_picker_summary">Toque para escolher um arquivo personalizado de lista de palavras contendo uma palavra por linha</string>
<!-- ssh keygen fragment --> <!-- ssh keygen fragment -->
<string name="ssh_keygen_passphrase">Frase Secreta</string> <string name="ssh_keygen_passphrase">Frase Secreta</string>
<string name="ssh_keygen_generate">Gerar</string> <string name="ssh_keygen_generate">Gerar</string>

View file

@ -141,19 +141,9 @@
<string name="pwgen_no_chars_error">Не включать символы</string> <string name="pwgen_no_chars_error">Не включать символы</string>
<string name="pwgen_length_too_short_error">Длина не соответствует выбранным критериям</string> <string name="pwgen_length_too_short_error">Длина не соответствует выбранным критериям</string>
<string name="pwgen_max_iterations_exceeded">Не удалось создать пароль, удовлетворяющий ограничениям. Попробуйте увеличить длину.</string> <string name="pwgen_max_iterations_exceeded">Не удалось создать пароль, удовлетворяющий ограничениям. Попробуйте увеличить длину.</string>
<!-- XKPWD password generator --> <string name="pwgen_separator">Разделитель</string>
<string name="xkpwgen_title">Генератор Xkpasswd</string> <!-- Password generator prefs -->
<string name="xkpwgen_length">Всего слов</string>
<string name="xkpwgen_separator">Разделитель</string>
<string name="xkpwgen_custom_dict_imported">Пользовательский список слов: %1$s</string>
<string name="xkpwgen_builder_error">Выбранный словарь не содержит достаточного количества слова заданной длинны %1$d..%2$d</string>
<!-- XKPWD prefs -->
<string name="pref_password_generator_type_title">Тип генератора паролей</string> <string name="pref_password_generator_type_title">Тип генератора паролей</string>
<string name="pref_xkpwgen_custom_wordlist_enabled_title">Пользовательский список слов</string>
<string name="pref_xkpwgen_custom_dict_summary_on">Использовать файл списка слов созданный пользователем</string>
<string name="pref_xkpwgen_custom_dict_summary_off">Использовать встроенный список слов</string>
<string name="pref_xkpwgen_custom_dict_picker_title">Файл пользовательского списка слов</string>
<string name="pref_xkpwgen_custom_dict_picker_summary">Нажмите чтобы выбрать файл пользовательского списка слов содержащий одно слово на строку</string>
<!-- ssh keygen fragment --> <!-- ssh keygen fragment -->
<string name="ssh_keygen_passphrase">Пароль</string> <string name="ssh_keygen_passphrase">Пароль</string>
<string name="ssh_keygen_generate">Сгенерировать</string> <string name="ssh_keygen_generate">Сгенерировать</string>

View file

@ -24,11 +24,9 @@
</string-array> </string-array>
<string-array name="pwgen_provider_labels"> <string-array name="pwgen_provider_labels">
<item>Classic</item> <item>Classic</item>
<item>XKPasswd</item>
</string-array> </string-array>
<string-array name="pwgen_provider_values"> <string-array name="pwgen_provider_values">
<item>classic</item> <item>classic</item>
<item>xkpasswd</item>
</string-array> </string-array>
<string-array name="oreo_autofill_directory_structure_entries"> <string-array name="oreo_autofill_directory_structure_entries">
<item>work/example.org(.gpg)</item> <item>work/example.org(.gpg)</item>

View file

@ -160,21 +160,10 @@
<string name="pwgen_no_chars_error">No characters included</string> <string name="pwgen_no_chars_error">No characters included</string>
<string name="pwgen_length_too_short_error">Length too short for selected criteria</string> <string name="pwgen_length_too_short_error">Length too short for selected criteria</string>
<string name="pwgen_max_iterations_exceeded">Failed to generate a password satisfying the constraints. Try to increase the length.</string> <string name="pwgen_max_iterations_exceeded">Failed to generate a password satisfying the constraints. Try to increase the length.</string>
<string name="pwgen_separator">Separator</string>
<!-- XKPWD password generator --> <!-- Password generator prefs -->
<string name="xkpwgen_title">Xkpasswd Generator</string>
<string name="xkpwgen_length">Total words</string>
<string name="xkpwgen_separator">Separator</string>
<string name="xkpwgen_custom_dict_imported">Custom wordlist: %1$s</string>
<string name="xkpwgen_builder_error">Selected dictionary does not contain enough words of given length %1$d..%2$d</string>
<!-- XKPWD prefs -->
<string name="pref_password_generator_type_title">Password generator type</string> <string name="pref_password_generator_type_title">Password generator type</string>
<string name="pref_xkpwgen_custom_wordlist_enabled_title">Custom wordlist</string>
<string name="pref_xkpwgen_custom_dict_summary_on">Using custom wordlist file</string>
<string name="pref_xkpwgen_custom_dict_summary_off">Using built-in wordlist</string>
<string name="pref_xkpwgen_custom_dict_picker_title">Custom worldlist file</string>
<string name="pref_xkpwgen_custom_dict_picker_summary">Tap to pick a custom wordlist file containing one word per line</string>
<!-- ssh keygen fragment --> <!-- ssh keygen fragment -->
<string name="ssh_keygen_passphrase">Passphrase</string> <string name="ssh_keygen_passphrase">Passphrase</string>