chore: reformat with trailing commas changes
This commit is contained in:
parent
de6cdfee0e
commit
c980c898de
100 changed files with 309 additions and 563 deletions
|
@ -77,11 +77,6 @@ constructor(
|
|||
.withAsciiArmor(settings.getBoolean(PreferenceKeys.ASCII_ARMOR, false))
|
||||
.build()
|
||||
val keys = identities.map { id -> pgpKeyManager.getKeyById(id) }.filterValues()
|
||||
return pgpCryptoHandler.encrypt(
|
||||
keys,
|
||||
content,
|
||||
out,
|
||||
encryptionOptions,
|
||||
)
|
||||
return pgpCryptoHandler.encrypt(keys, content, out, encryptionOptions)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,35 +11,21 @@ import javax.inject.Inject
|
|||
import kotlinx.coroutines.withContext
|
||||
|
||||
/** Implements a rudimentary [EncryptedSharedPreferences]-backed cache for GPG passphrases. */
|
||||
class PGPPassphraseCache
|
||||
@Inject
|
||||
constructor(
|
||||
private val dispatcherProvider: DispatcherProvider,
|
||||
) {
|
||||
class PGPPassphraseCache @Inject constructor(private val dispatcherProvider: DispatcherProvider) {
|
||||
|
||||
suspend fun cachePassphrase(
|
||||
context: Context,
|
||||
identifier: PGPIdentifier,
|
||||
passphrase: String,
|
||||
) {
|
||||
suspend fun cachePassphrase(context: Context, identifier: PGPIdentifier, passphrase: String) {
|
||||
withContext(dispatcherProvider.io()) {
|
||||
getPreferences(context).edit { putString(identifier.toString(), passphrase) }
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun retrieveCachedPassphrase(
|
||||
context: Context,
|
||||
identifier: PGPIdentifier,
|
||||
): String? {
|
||||
suspend fun retrieveCachedPassphrase(context: Context, identifier: PGPIdentifier): String? {
|
||||
return withContext(dispatcherProvider.io()) {
|
||||
getPreferences(context).getString(identifier.toString())
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun clearCachedPassphrase(
|
||||
context: Context,
|
||||
identifier: PGPIdentifier,
|
||||
) {
|
||||
suspend fun clearCachedPassphrase(context: Context, identifier: PGPIdentifier) {
|
||||
withContext(dispatcherProvider.io()) {
|
||||
getPreferences(context).edit { remove(identifier.toString()) }
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ import app.passwordstore.data.passfile.Totp
|
|||
class FieldItem(val key: String, val value: String, val action: ActionType) {
|
||||
enum class ActionType {
|
||||
COPY,
|
||||
HIDE
|
||||
HIDE,
|
||||
}
|
||||
|
||||
enum class ItemType(val type: String, val label: String) {
|
||||
|
|
|
@ -16,7 +16,7 @@ data class PasswordItem(
|
|||
val parent: PasswordItem? = null,
|
||||
val type: Char,
|
||||
val file: File,
|
||||
val rootDir: File
|
||||
val rootDir: File,
|
||||
) : Comparable<PasswordItem> {
|
||||
|
||||
val fullPathToParent = file.absolutePath.replace(rootDir.absolutePath, "").replace(file.name, "")
|
||||
|
|
|
@ -167,7 +167,7 @@ object PasswordRepository {
|
|||
fun getPasswords(
|
||||
path: File,
|
||||
rootDir: File,
|
||||
sortOrder: PasswordSortOrder
|
||||
sortOrder: PasswordSortOrder,
|
||||
): ArrayList<PasswordItem> {
|
||||
// We need to recover the passwords then parse the files
|
||||
val passList = getFilesList(path).also { it.sortBy { f -> f.name } }
|
||||
|
|
|
@ -23,10 +23,7 @@ object KeyManagerModule {
|
|||
@PGPKeyDir keyDir: String,
|
||||
dispatcherProvider: DispatcherProvider,
|
||||
): PGPKeyManager {
|
||||
return PGPKeyManager(
|
||||
keyDir,
|
||||
dispatcherProvider.io(),
|
||||
)
|
||||
return PGPKeyManager(keyDir, dispatcherProvider.io())
|
||||
}
|
||||
|
||||
@Provides
|
||||
|
|
|
@ -25,7 +25,7 @@ class PreferenceModule {
|
|||
fileName,
|
||||
masterKeyAlias,
|
||||
EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
|
||||
EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
|
||||
EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -32,9 +32,7 @@ object DicewareModule {
|
|||
}
|
||||
|
||||
@Provides
|
||||
fun provideDie(
|
||||
intGenerator: RandomIntGenerator,
|
||||
): Die {
|
||||
fun provideDie(intGenerator: RandomIntGenerator): Die {
|
||||
return Die(6, intGenerator)
|
||||
}
|
||||
|
||||
|
|
|
@ -113,7 +113,7 @@ class AutofillDecryptActivity : BasePGPActivity() {
|
|||
val cachedPassphrase =
|
||||
passphraseCache.retrieveCachedPassphrase(
|
||||
this@AutofillDecryptActivity,
|
||||
gpgIdentifiers.first()
|
||||
gpgIdentifiers.first(),
|
||||
)
|
||||
if (cachedPassphrase != null) {
|
||||
decryptWithPassphrase(
|
||||
|
@ -121,7 +121,7 @@ class AutofillDecryptActivity : BasePGPActivity() {
|
|||
gpgIdentifiers,
|
||||
clientState,
|
||||
action,
|
||||
cachedPassphrase
|
||||
cachedPassphrase,
|
||||
)
|
||||
} else {
|
||||
askPassphrase(filePath, gpgIdentifiers, clientState, action)
|
||||
|
@ -169,12 +169,12 @@ class AutofillDecryptActivity : BasePGPActivity() {
|
|||
this@AutofillDecryptActivity,
|
||||
credentials,
|
||||
clientState,
|
||||
action
|
||||
action,
|
||||
)
|
||||
withContext(dispatcherProvider.main()) {
|
||||
setResult(
|
||||
RESULT_OK,
|
||||
Intent().apply { putExtra(AutofillManager.EXTRA_AUTHENTICATION_RESULT, fillInDataset) }
|
||||
Intent().apply { putExtra(AutofillManager.EXTRA_AUTHENTICATION_RESULT, fillInDataset) },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -195,12 +195,7 @@ class AutofillDecryptActivity : BasePGPActivity() {
|
|||
runCatching {
|
||||
withContext(dispatcherProvider.io()) {
|
||||
val outputStream = ByteArrayOutputStream()
|
||||
repository.decrypt(
|
||||
password,
|
||||
identifiers,
|
||||
encryptedInput,
|
||||
outputStream,
|
||||
)
|
||||
repository.decrypt(password, identifiers, encryptedInput, outputStream)
|
||||
outputStream
|
||||
}
|
||||
}
|
||||
|
|
|
@ -61,7 +61,7 @@ class AutofillFilterView : AppCompatActivity() {
|
|||
|
||||
fun makeMatchAndDecryptFileIntentSender(
|
||||
context: Context,
|
||||
formOrigin: FormOrigin
|
||||
formOrigin: FormOrigin,
|
||||
): IntentSender {
|
||||
val intent =
|
||||
Intent(context, AutofillFilterView::class.java).apply {
|
||||
|
@ -193,7 +193,7 @@ class AutofillFilterView : AppCompatActivity() {
|
|||
shouldMatch.text =
|
||||
getString(
|
||||
R.string.oreo_autofill_match_with,
|
||||
formOrigin.getPrettyIdentifier(applicationContext)
|
||||
formOrigin.getPrettyIdentifier(applicationContext),
|
||||
)
|
||||
lifecycleScope.launch { handleSearchResults() }
|
||||
}
|
||||
|
@ -222,7 +222,7 @@ class AutofillFilterView : AppCompatActivity() {
|
|||
filterMode =
|
||||
if (binding.strictDomainSearch.isChecked) FilterMode.StrictDomain else FilterMode.Fuzzy,
|
||||
searchMode = SearchMode.RecursivelyInSubdirectories,
|
||||
listMode = ListMode.FilesOnly
|
||||
listMode = ListMode.FilesOnly,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -92,17 +92,17 @@ class AutofillPublisherChangedActivity : AppCompatActivity() {
|
|||
resetButton.setOnClickListener {
|
||||
AutofillMatcher.clearMatchesFor(
|
||||
this@AutofillPublisherChangedActivity,
|
||||
FormOrigin.App(appPackage)
|
||||
FormOrigin.App(appPackage),
|
||||
)
|
||||
val fillResponse =
|
||||
IntentCompat.getParcelableExtra(
|
||||
intent,
|
||||
EXTRA_FILL_RESPONSE_AFTER_RESET,
|
||||
FillResponse::class.java
|
||||
FillResponse::class.java,
|
||||
)
|
||||
setResult(
|
||||
RESULT_OK,
|
||||
Intent().apply { putExtra(AutofillManager.EXTRA_AUTHENTICATION_RESULT, fillResponse) }
|
||||
Intent().apply { putExtra(AutofillManager.EXTRA_AUTHENTICATION_RESULT, fillResponse) },
|
||||
)
|
||||
finish()
|
||||
}
|
||||
|
@ -122,7 +122,7 @@ class AutofillPublisherChangedActivity : AppCompatActivity() {
|
|||
warningAppName.text =
|
||||
getString(
|
||||
R.string.oreo_autofill_warning_publisher_app_name,
|
||||
packageManager.getApplicationLabel(appInfo)
|
||||
packageManager.getApplicationLabel(appInfo),
|
||||
)
|
||||
|
||||
val currentHash =
|
||||
|
@ -131,7 +131,7 @@ class AutofillPublisherChangedActivity : AppCompatActivity() {
|
|||
getString(
|
||||
R.string.oreo_autofill_warning_publisher_advanced_info_template,
|
||||
appPackage,
|
||||
currentHash
|
||||
currentHash,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -47,7 +47,7 @@ class AutofillSaveActivity : AppCompatActivity() {
|
|||
fun makeSaveIntentSender(
|
||||
context: Context,
|
||||
credentials: Credentials?,
|
||||
formOrigin: FormOrigin
|
||||
formOrigin: FormOrigin,
|
||||
): IntentSender {
|
||||
val identifier = formOrigin.getPrettyIdentifier(context, untrusted = false)
|
||||
// Prevent directory traversals
|
||||
|
@ -58,12 +58,12 @@ class AutofillSaveActivity : AppCompatActivity() {
|
|||
val folderName =
|
||||
directoryStructure.getSaveFolderName(
|
||||
sanitizedIdentifier = sanitizedIdentifier,
|
||||
username = credentials?.username
|
||||
username = credentials?.username,
|
||||
)
|
||||
val fileName =
|
||||
directoryStructure.getSaveFileName(
|
||||
username = credentials?.username,
|
||||
identifier = identifier
|
||||
identifier = identifier,
|
||||
)
|
||||
val intent =
|
||||
Intent(context, AutofillSaveActivity::class.java).apply {
|
||||
|
@ -76,7 +76,7 @@ class AutofillSaveActivity : AppCompatActivity() {
|
|||
formOrigin.identifier.takeIf { formOrigin is FormOrigin.App },
|
||||
EXTRA_SHOULD_MATCH_WEB to
|
||||
formOrigin.identifier.takeIf { formOrigin is FormOrigin.Web },
|
||||
EXTRA_GENERATE_PASSWORD to (credentials == null)
|
||||
EXTRA_GENERATE_PASSWORD to (credentials == null),
|
||||
)
|
||||
)
|
||||
}
|
||||
|
@ -84,7 +84,7 @@ class AutofillSaveActivity : AppCompatActivity() {
|
|||
context,
|
||||
saveRequestCode++,
|
||||
intent,
|
||||
PendingIntent.FLAG_CANCEL_CURRENT or PendingIntent.FLAG_IMMUTABLE
|
||||
PendingIntent.FLAG_CANCEL_CURRENT or PendingIntent.FLAG_IMMUTABLE,
|
||||
)
|
||||
.intentSender
|
||||
}
|
||||
|
@ -114,7 +114,7 @@ class AutofillSaveActivity : AppCompatActivity() {
|
|||
PasswordCreationActivity.EXTRA_FILE_NAME to intent.getStringExtra(EXTRA_NAME),
|
||||
PasswordCreationActivity.EXTRA_PASSWORD to intent.getStringExtra(EXTRA_PASSWORD),
|
||||
PasswordCreationActivity.EXTRA_GENERATE_PASSWORD to
|
||||
intent.getBooleanExtra(EXTRA_GENERATE_PASSWORD, false)
|
||||
intent.getBooleanExtra(EXTRA_GENERATE_PASSWORD, false),
|
||||
)
|
||||
)
|
||||
}
|
||||
|
@ -141,7 +141,7 @@ class AutofillSaveActivity : AppCompatActivity() {
|
|||
this,
|
||||
credentials,
|
||||
clientState,
|
||||
AutofillAction.Generate
|
||||
AutofillAction.Generate,
|
||||
)
|
||||
Intent().apply {
|
||||
putExtra(AutofillManager.EXTRA_AUTHENTICATION_RESULT, fillInDataset)
|
||||
|
|
|
@ -90,7 +90,7 @@ open class BasePGPActivity : AppCompatActivity() {
|
|||
fun copyTextToClipboard(
|
||||
text: String?,
|
||||
showSnackbar: Boolean = true,
|
||||
@StringRes snackbarTextRes: Int = R.string.clipboard_copied_text
|
||||
@StringRes snackbarTextRes: Int = R.string.clipboard_copied_text,
|
||||
) {
|
||||
val clipboard = clipboard ?: return
|
||||
val clip = ClipData.newPlainText("pgp_handler_result_pm", text)
|
||||
|
|
|
@ -40,7 +40,7 @@ fun EditPasswordScreen(
|
|||
onNavigationIconClick = onNavigateUp,
|
||||
backgroundColor = MaterialTheme.colorScheme.surface,
|
||||
)
|
||||
},
|
||||
}
|
||||
) { paddingValues ->
|
||||
Box(modifier = modifier.padding(paddingValues)) {
|
||||
Column(modifier = Modifier.padding(vertical = 8.dp, horizontal = 16.dp).fillMaxSize()) {
|
||||
|
@ -59,10 +59,7 @@ fun EditPasswordScreen(
|
|||
}
|
||||
|
||||
@Composable
|
||||
private fun ExtraContent(
|
||||
entry: PasswordEntry,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
private fun ExtraContent(entry: PasswordEntry, modifier: Modifier = Modifier) {
|
||||
TextField(
|
||||
value = entry.extraContentString,
|
||||
onValueChange = {},
|
||||
|
@ -95,5 +92,5 @@ private fun createTestEntry() =
|
|||
|URL: example.com
|
||||
"""
|
||||
.trimMargin()
|
||||
.encodeToByteArray()
|
||||
.encodeToByteArray(),
|
||||
)
|
||||
|
|
|
@ -147,7 +147,7 @@ class PasswordCreationActivity : BasePGPActivity() {
|
|||
otpImportButton.setOnClickListener {
|
||||
supportFragmentManager.setFragmentResultListener(
|
||||
OTP_RESULT_REQUEST_KEY,
|
||||
this@PasswordCreationActivity
|
||||
this@PasswordCreationActivity,
|
||||
) { requestKey, bundle ->
|
||||
if (requestKey == OTP_RESULT_REQUEST_KEY) {
|
||||
val contents = bundle.getString(RESULT)
|
||||
|
|
|
@ -46,7 +46,7 @@ fun ViewPasswordScreen(
|
|||
onNavigationIconClick = onNavigateUp,
|
||||
backgroundColor = MaterialTheme.colorScheme.surface,
|
||||
)
|
||||
},
|
||||
}
|
||||
) { paddingValues ->
|
||||
Box(modifier = modifier.padding(paddingValues)) {
|
||||
Column(modifier = Modifier.padding(vertical = 8.dp, horizontal = 16.dp).fillMaxSize()) {
|
||||
|
@ -87,10 +87,7 @@ fun ViewPasswordScreen(
|
|||
}
|
||||
|
||||
@Composable
|
||||
private fun ExtraContent(
|
||||
entry: PasswordEntry,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
private fun ExtraContent(entry: PasswordEntry, modifier: Modifier = Modifier) {
|
||||
entry.extraContent.forEach { (label, value) ->
|
||||
TextField(
|
||||
value = value,
|
||||
|
@ -107,11 +104,7 @@ private fun ExtraContent(
|
|||
@Composable
|
||||
private fun ViewPasswordScreenPreview() {
|
||||
APSTheme {
|
||||
ViewPasswordScreen(
|
||||
entryName = "Test Entry",
|
||||
entry = createTestEntry(),
|
||||
onNavigateUp = {},
|
||||
)
|
||||
ViewPasswordScreen(entryName = "Test Entry", entry = createTestEntry(), onNavigateUp = {})
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -126,5 +119,5 @@ private fun createTestEntry() =
|
|||
|URL: example.com
|
||||
"""
|
||||
.trimMargin()
|
||||
.encodeToByteArray()
|
||||
.encodeToByteArray(),
|
||||
)
|
||||
|
|
|
@ -54,7 +54,7 @@ private constructor(
|
|||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
savedInstanceState: Bundle?,
|
||||
): View? {
|
||||
if (savedInstanceState != null) dismiss()
|
||||
return layoutInflater.inflate(R.layout.basic_bottom_sheet, container, false)
|
||||
|
@ -157,9 +157,7 @@ private constructor(
|
|||
return this
|
||||
}
|
||||
|
||||
fun setOnDismissListener(
|
||||
onDismissListener: OnDismissListener,
|
||||
): Builder {
|
||||
fun setOnDismissListener(onDismissListener: OnDismissListener): Builder {
|
||||
this.onDismissListener = onDismissListener
|
||||
return this
|
||||
}
|
||||
|
|
|
@ -59,7 +59,7 @@ class DicewarePasswordGeneratorDialogFragment : DialogFragment() {
|
|||
setPositiveButton(R.string.dialog_ok) { _, _ ->
|
||||
setFragmentResult(
|
||||
PasswordCreationActivity.PASSWORD_RESULT_REQUEST_KEY,
|
||||
bundleOf(PasswordCreationActivity.RESULT to "${binding.passwordText.text}")
|
||||
bundleOf(PasswordCreationActivity.RESULT to "${binding.passwordText.text}"),
|
||||
)
|
||||
}
|
||||
setNeutralButton(R.string.dialog_cancel) { _, _ -> }
|
||||
|
|
|
@ -38,7 +38,7 @@ class ItemCreationBottomSheet : BottomSheetDialogFragment() {
|
|||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
savedInstanceState: Bundle?,
|
||||
): View? {
|
||||
if (savedInstanceState != null) dismiss()
|
||||
return inflater.inflate(R.layout.item_create_sheet, container, false)
|
||||
|
|
|
@ -25,7 +25,7 @@ class OtpImportDialogFragment : DialogFragment() {
|
|||
builder.setPositiveButton(android.R.string.ok) { _, _ ->
|
||||
setFragmentResult(
|
||||
PasswordCreationActivity.OTP_RESULT_REQUEST_KEY,
|
||||
bundleOf(PasswordCreationActivity.RESULT to getTOTPUri(binding))
|
||||
bundleOf(PasswordCreationActivity.RESULT to getTOTPUri(binding)),
|
||||
)
|
||||
}
|
||||
val dialog = builder.create()
|
||||
|
|
|
@ -73,7 +73,7 @@ class PasswordGeneratorDialogFragment : DialogFragment() {
|
|||
setPositiveButton(R.string.dialog_ok) { _, _ ->
|
||||
setFragmentResult(
|
||||
PasswordCreationActivity.PASSWORD_RESULT_REQUEST_KEY,
|
||||
bundleOf(PasswordCreationActivity.RESULT to "${binding.passwordText.text}")
|
||||
bundleOf(PasswordCreationActivity.RESULT to "${binding.passwordText.text}"),
|
||||
)
|
||||
}
|
||||
setNeutralButton(R.string.dialog_cancel) { _, _ -> }
|
||||
|
@ -123,7 +123,7 @@ class PasswordGeneratorDialogFragment : DialogFragment() {
|
|||
PasswordOption.NoUppercaseLetters.takeIf { !isChecked(R.id.uppercase) },
|
||||
PasswordOption.NoAmbiguousCharacters.takeIf { !isChecked(R.id.ambiguous) },
|
||||
PasswordOption.FullyRandom.takeIf { !isChecked(R.id.pronounceable) },
|
||||
PasswordOption.NoLowercaseLetters.takeIf { !isChecked(R.id.lowercase) }
|
||||
PasswordOption.NoLowercaseLetters.takeIf { !isChecked(R.id.lowercase) },
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -28,7 +28,7 @@ class SelectFolderActivity : AppCompatActivity(R.layout.select_folder_layout) {
|
|||
val args = Bundle()
|
||||
args.putString(
|
||||
PasswordStore.REQUEST_ARG_PATH,
|
||||
PasswordRepository.getRepositoryDirectory().absolutePath
|
||||
PasswordRepository.getRepositoryDirectory().absolutePath,
|
||||
)
|
||||
|
||||
passwordList.arguments = args
|
||||
|
|
|
@ -131,7 +131,7 @@ abstract class BaseGitActivity : AppCompatActivity() {
|
|||
gitSettings.useMultiplexing = false
|
||||
SSHException(
|
||||
DisconnectReason.TOO_MANY_CONNECTIONS,
|
||||
"The server does not support multiple Git operations per SSH session. Please try again, a slower fallback mode will be used."
|
||||
"The server does not support multiple Git operations per SSH session. Please try again, a slower fallback mode will be used.",
|
||||
)
|
||||
}
|
||||
err.message?.contains("int org.eclipse.jgit.lib.AnyObjectId.w1") == true -> {
|
||||
|
@ -143,7 +143,7 @@ abstract class BaseGitActivity : AppCompatActivity() {
|
|||
err.disconnectReason == DisconnectReason.HOST_KEY_NOT_VERIFIABLE -> {
|
||||
SSHException(
|
||||
DisconnectReason.HOST_KEY_NOT_VERIFIABLE,
|
||||
"WARNING: The remote host key has changed. If this is expected, please go to Git server settings and clear the saved host key."
|
||||
"WARNING: The remote host key has changed. If this is expected, please go to Git server settings and clear the saved host key.",
|
||||
)
|
||||
}
|
||||
else -> {
|
||||
|
|
|
@ -61,7 +61,7 @@ class GitConfigActivity : BaseGitActivity() {
|
|||
Snackbar.make(
|
||||
binding.root,
|
||||
getString(R.string.git_server_config_save_success),
|
||||
Snackbar.LENGTH_SHORT
|
||||
Snackbar.LENGTH_SHORT,
|
||||
)
|
||||
.show()
|
||||
Handler(Looper.getMainLooper()).postDelayed(500) { finish() }
|
||||
|
|
|
@ -94,7 +94,7 @@ class GitServerConfigActivity : BaseGitActivity() {
|
|||
Snackbar.make(
|
||||
binding.root,
|
||||
getString(R.string.clear_saved_host_key_success),
|
||||
Snackbar.LENGTH_LONG
|
||||
Snackbar.LENGTH_LONG,
|
||||
)
|
||||
.show()
|
||||
it.isVisible = false
|
||||
|
@ -140,14 +140,14 @@ class GitServerConfigActivity : BaseGitActivity() {
|
|||
val updateResult =
|
||||
gitSettings.updateConnectionSettingsIfValid(
|
||||
newAuthMode = newAuthMode,
|
||||
newUrl = binding.serverUrl.text.toString().trim()
|
||||
newUrl = binding.serverUrl.text.toString().trim(),
|
||||
)
|
||||
) {
|
||||
GitSettings.UpdateConnectionSettingsResult.FailedToParseUrl -> {
|
||||
Snackbar.make(
|
||||
binding.root,
|
||||
getString(R.string.git_server_config_save_error),
|
||||
Snackbar.LENGTH_LONG
|
||||
Snackbar.LENGTH_LONG,
|
||||
)
|
||||
.show()
|
||||
}
|
||||
|
@ -175,7 +175,7 @@ class GitServerConfigActivity : BaseGitActivity() {
|
|||
Snackbar.make(
|
||||
binding.root,
|
||||
getString(R.string.git_server_config_save_success),
|
||||
Snackbar.LENGTH_SHORT
|
||||
Snackbar.LENGTH_SHORT,
|
||||
)
|
||||
.show()
|
||||
Handler(Looper.getMainLooper()).postDelayed(500) { finish() }
|
||||
|
@ -242,7 +242,7 @@ class GitServerConfigActivity : BaseGitActivity() {
|
|||
val snackbar =
|
||||
snackbar(
|
||||
message = getString(R.string.delete_directory_progress_text),
|
||||
length = Snackbar.LENGTH_INDEFINITE
|
||||
length = Snackbar.LENGTH_INDEFINITE,
|
||||
)
|
||||
withContext(dispatcherProvider.io()) {
|
||||
localDir.deleteRecursively()
|
||||
|
@ -255,7 +255,7 @@ class GitServerConfigActivity : BaseGitActivity() {
|
|||
setResult(RESULT_OK)
|
||||
finish()
|
||||
},
|
||||
failure = { err -> promptOnErrorHandler(err) { finish() } }
|
||||
failure = { err -> promptOnErrorHandler(err) { finish() } },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -58,11 +58,11 @@ class LaunchActivity : AppCompatActivity() {
|
|||
getDecryptIntent().apply {
|
||||
putExtra(
|
||||
BasePGPActivity.EXTRA_FILE_PATH,
|
||||
intent.getStringExtra(BasePGPActivity.EXTRA_FILE_PATH)
|
||||
intent.getStringExtra(BasePGPActivity.EXTRA_FILE_PATH),
|
||||
)
|
||||
putExtra(
|
||||
BasePGPActivity.EXTRA_REPO_PATH,
|
||||
intent.getStringExtra(BasePGPActivity.EXTRA_REPO_PATH)
|
||||
intent.getStringExtra(BasePGPActivity.EXTRA_REPO_PATH),
|
||||
)
|
||||
}
|
||||
else Intent(this, PasswordStore::class.java).setAction(Intent.ACTION_VIEW)
|
||||
|
|
|
@ -156,7 +156,7 @@ class PasswordFragment : Fragment(R.layout.password_recycler_view) {
|
|||
resources.getQuantityString(
|
||||
R.plurals.delete_title,
|
||||
selection.size(),
|
||||
selection.size()
|
||||
selection.size(),
|
||||
)
|
||||
actionMode!!.invalidate()
|
||||
} else {
|
||||
|
@ -256,7 +256,7 @@ class PasswordFragment : Fragment(R.layout.password_recycler_view) {
|
|||
val passwordItem = recyclerAdapter.getSelectedItems()[0]
|
||||
shortcutHandler.addPinnedShortcut(
|
||||
passwordItem,
|
||||
passwordItem.createAuthEnabledIntent(requireContext())
|
||||
passwordItem.createAuthEnabledIntent(requireContext()),
|
||||
)
|
||||
false
|
||||
}
|
||||
|
@ -372,7 +372,7 @@ class PasswordFragment : Fragment(R.layout.password_recycler_view) {
|
|||
requireStore().clearSearch()
|
||||
model.navigateTo(
|
||||
file,
|
||||
recyclerViewState = binding.passRecycler.layoutManager!!.onSaveInstanceState()
|
||||
recyclerViewState = binding.passRecycler.layoutManager!!.onSaveInstanceState(),
|
||||
)
|
||||
requireStore().supportActionBar?.setDisplayHomeAsUpEnabled(true)
|
||||
}
|
||||
|
|
|
@ -115,7 +115,7 @@ class PasswordStore : BaseGitActivity() {
|
|||
getLongName(
|
||||
requireNotNull(source.parent) { "$file has no parent" },
|
||||
repositoryPath,
|
||||
basename
|
||||
basename,
|
||||
)
|
||||
val destinationLongName = getLongName(target.absolutePath, repositoryPath, basename)
|
||||
if (destinationFile.exists()) {
|
||||
|
@ -127,7 +127,7 @@ class PasswordStore : BaseGitActivity() {
|
|||
resources.getString(
|
||||
R.string.password_exists_message,
|
||||
destinationLongName,
|
||||
sourceLongName
|
||||
sourceLongName,
|
||||
)
|
||||
)
|
||||
.setPositiveButton(R.string.dialog_ok) { _, _ ->
|
||||
|
@ -148,7 +148,7 @@ class PasswordStore : BaseGitActivity() {
|
|||
getLongName(
|
||||
requireNotNull(source.parent) { "$basename has no parent" },
|
||||
repositoryPath,
|
||||
basename
|
||||
basename,
|
||||
)
|
||||
val destinationLongName = getLongName(target.absolutePath, repositoryPath, basename)
|
||||
withContext(dispatcherProvider.main()) {
|
||||
|
@ -156,8 +156,8 @@ class PasswordStore : BaseGitActivity() {
|
|||
resources.getString(
|
||||
R.string.git_commit_move_text,
|
||||
sourceLongName,
|
||||
destinationLongName
|
||||
),
|
||||
destinationLongName,
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -166,7 +166,7 @@ class PasswordStore : BaseGitActivity() {
|
|||
val relativePath = getRelativePath("${target.absolutePath}/", repoDir)
|
||||
withContext(dispatcherProvider.main()) {
|
||||
commitChange(
|
||||
resources.getString(R.string.git_commit_move_multiple_text, relativePath),
|
||||
resources.getString(R.string.git_commit_move_multiple_text, relativePath)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -340,10 +340,7 @@ class PasswordStore : BaseGitActivity() {
|
|||
private fun runGitOperation(operation: GitOp) =
|
||||
lifecycleScope.launch {
|
||||
launchGitOperation(operation)
|
||||
.fold(
|
||||
success = { refreshPasswordList() },
|
||||
failure = { promptOnErrorHandler(it) },
|
||||
)
|
||||
.fold(success = { refreshPasswordList() }, failure = { promptOnErrorHandler(it) })
|
||||
}
|
||||
|
||||
private fun checkLocalRepository() {
|
||||
|
@ -414,7 +411,7 @@ class PasswordStore : BaseGitActivity() {
|
|||
intent.putExtra(BasePGPActivity.EXTRA_FILE_PATH, currentDir.absolutePath)
|
||||
intent.putExtra(
|
||||
BasePGPActivity.EXTRA_REPO_PATH,
|
||||
PasswordRepository.getRepositoryDirectory().absolutePath
|
||||
PasswordRepository.getRepositoryDirectory().absolutePath,
|
||||
)
|
||||
listRefreshAction.launch(intent)
|
||||
}
|
||||
|
@ -450,9 +447,7 @@ class PasswordStore : BaseGitActivity() {
|
|||
item.file.toRelativeString(PasswordRepository.getRepositoryDirectory())
|
||||
}
|
||||
lifecycleScope.launch {
|
||||
commitChange(
|
||||
resources.getString(R.string.git_commit_remove_text, fmt),
|
||||
)
|
||||
commitChange(resources.getString(R.string.git_commit_remove_text, fmt))
|
||||
}
|
||||
}
|
||||
.setNegativeButton(resources.getString(R.string.dialog_no), null)
|
||||
|
@ -487,7 +482,7 @@ class PasswordStore : BaseGitActivity() {
|
|||
*/
|
||||
private fun renameCategory(
|
||||
oldCategory: PasswordItem,
|
||||
error: CategoryRenameError = CategoryRenameError.None
|
||||
error: CategoryRenameError = CategoryRenameError.None,
|
||||
) {
|
||||
val view = layoutInflater.inflate(R.layout.folder_dialog_fragment, null)
|
||||
val newCategoryEditText = view.findViewById<TextInputEditText>(R.id.folder_name_text)
|
||||
|
@ -530,8 +525,8 @@ class PasswordStore : BaseGitActivity() {
|
|||
resources.getString(
|
||||
R.string.git_commit_move_text,
|
||||
oldCategory.name,
|
||||
newCategory.name
|
||||
),
|
||||
newCategory.name,
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -54,7 +54,7 @@ fun KeyList(
|
|||
) {
|
||||
Image(
|
||||
painter = painterResource(id = R.drawable.ic_launcher_foreground),
|
||||
contentDescription = "Password Store logo"
|
||||
contentDescription = "Password Store logo",
|
||||
)
|
||||
Text(stringResource(R.string.pgp_key_manager_no_keys_guidance))
|
||||
}
|
||||
|
@ -81,7 +81,7 @@ private fun KeyItem(
|
|||
onConfirm = {
|
||||
onItemClick(identifier)
|
||||
isDeleting = false
|
||||
}
|
||||
},
|
||||
)
|
||||
val label =
|
||||
when (identifier) {
|
||||
|
@ -106,7 +106,7 @@ private fun KeyItem(
|
|||
IconButton(onClick = { isDeleting = true }, modifier = Modifier.requiredSize(24.dp)) {
|
||||
Icon(
|
||||
painter = painterResource(R.drawable.ic_delete_24dp),
|
||||
stringResource(id = R.string.delete)
|
||||
stringResource(id = R.string.delete),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -148,7 +148,7 @@ private fun KeyListPreview() {
|
|||
PGPIdentifier.fromString("0xB950AE2813841585"),
|
||||
)
|
||||
.toPersistentList(),
|
||||
onItemClick = {}
|
||||
onItemClick = {},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -52,10 +52,10 @@ class PGPKeyListActivity : ComponentActivity() {
|
|||
) {
|
||||
Icon(
|
||||
painter = painterResource(R.drawable.ic_add_48dp),
|
||||
stringResource(R.string.pref_import_pgp_key_title)
|
||||
stringResource(R.string.pref_import_pgp_key_title),
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
) { paddingValues ->
|
||||
KeyList(
|
||||
identifiers = viewModel.keys,
|
||||
|
|
|
@ -22,10 +22,7 @@ class PasswordSettings(private val activity: FragmentActivity) : SettingsProvide
|
|||
val values = activity.resources.getStringArray(R.array.pwgen_provider_values)
|
||||
val labels = activity.resources.getStringArray(R.array.pwgen_provider_labels)
|
||||
val items = values.zip(labels).map { SelectionItem(it.first, it.second, null) }
|
||||
singleChoice(
|
||||
PreferenceKeys.PREF_KEY_PWGEN_TYPE,
|
||||
items,
|
||||
) {
|
||||
singleChoice(PreferenceKeys.PREF_KEY_PWGEN_TYPE, items) {
|
||||
initialSelection = "diceware"
|
||||
titleRes = R.string.pref_password_generator_type_title
|
||||
}
|
||||
|
|
|
@ -103,7 +103,7 @@ class SettingsActivity : AppCompatActivity() {
|
|||
BundleCompat.getParcelable(
|
||||
savedInstanceState,
|
||||
"adapter",
|
||||
PreferencesAdapter.SavedState::class.java
|
||||
PreferencesAdapter.SavedState::class.java,
|
||||
)
|
||||
?.let(adapter::loadSavedState)
|
||||
}
|
||||
|
|
|
@ -126,7 +126,7 @@ class SshKeyGenActivity : AppCompatActivity() {
|
|||
suspendCoroutine { cont ->
|
||||
BiometricAuthenticator.authenticate(
|
||||
this@SshKeyGenActivity,
|
||||
R.string.biometric_prompt_title_ssh_keygen
|
||||
R.string.biometric_prompt_title_ssh_keygen,
|
||||
) { result ->
|
||||
// Do not cancel on failed attempts as these are handled by the
|
||||
// authenticator UI.
|
||||
|
|
|
@ -29,7 +29,7 @@ class SshKeyImportActivity : AppCompatActivity() {
|
|||
Toast.makeText(
|
||||
this,
|
||||
resources.getString(R.string.ssh_key_success_dialog_title),
|
||||
Toast.LENGTH_LONG
|
||||
Toast.LENGTH_LONG,
|
||||
)
|
||||
.show()
|
||||
setResult(RESULT_OK)
|
||||
|
|
|
@ -23,7 +23,7 @@ class OnOffItemAnimator : DefaultItemAnimator() {
|
|||
override fun animateAppearance(
|
||||
viewHolder: RecyclerView.ViewHolder,
|
||||
preLayoutInfo: ItemHolderInfo?,
|
||||
postLayoutInfo: ItemHolderInfo
|
||||
postLayoutInfo: ItemHolderInfo,
|
||||
): Boolean {
|
||||
return if (isEnabled) {
|
||||
super.animateAppearance(viewHolder, preLayoutInfo, postLayoutInfo)
|
||||
|
@ -36,7 +36,7 @@ class OnOffItemAnimator : DefaultItemAnimator() {
|
|||
oldHolder: RecyclerView.ViewHolder,
|
||||
newHolder: RecyclerView.ViewHolder,
|
||||
preInfo: ItemHolderInfo,
|
||||
postInfo: ItemHolderInfo
|
||||
postInfo: ItemHolderInfo,
|
||||
): Boolean {
|
||||
return if (isEnabled) {
|
||||
super.animateChange(oldHolder, newHolder, preInfo, postInfo)
|
||||
|
@ -48,7 +48,7 @@ class OnOffItemAnimator : DefaultItemAnimator() {
|
|||
override fun animateDisappearance(
|
||||
viewHolder: RecyclerView.ViewHolder,
|
||||
preLayoutInfo: ItemHolderInfo,
|
||||
postLayoutInfo: ItemHolderInfo?
|
||||
postLayoutInfo: ItemHolderInfo?,
|
||||
): Boolean {
|
||||
return if (isEnabled) {
|
||||
super.animateDisappearance(viewHolder, preLayoutInfo, postLayoutInfo)
|
||||
|
@ -60,7 +60,7 @@ class OnOffItemAnimator : DefaultItemAnimator() {
|
|||
override fun animatePersistence(
|
||||
viewHolder: RecyclerView.ViewHolder,
|
||||
preInfo: ItemHolderInfo,
|
||||
postInfo: ItemHolderInfo
|
||||
postInfo: ItemHolderInfo,
|
||||
): Boolean {
|
||||
return if (isEnabled) {
|
||||
super.animatePersistence(viewHolder, preInfo, postInfo)
|
||||
|
|
|
@ -57,7 +57,7 @@ object BiometricAuthenticator {
|
|||
fun authenticate(
|
||||
activity: FragmentActivity,
|
||||
@StringRes dialogTitleRes: Int = R.string.biometric_prompt_title,
|
||||
callback: (Result) -> Unit
|
||||
callback: (Result) -> Unit,
|
||||
) {
|
||||
val authCallback = createPromptAuthenticationCallback(activity, callback)
|
||||
val deviceHasKeyguard = activity.getSystemService<KeyguardManager>()?.isDeviceSecure == true
|
||||
|
@ -94,14 +94,14 @@ object BiometricAuthenticator {
|
|||
callback(
|
||||
Result.Failure(
|
||||
errorCode,
|
||||
activity.getString(R.string.biometric_auth_error_reason, errString)
|
||||
activity.getString(R.string.biometric_auth_error_reason, errString),
|
||||
)
|
||||
)
|
||||
BiometricPrompt.ERROR_NO_SPACE ->
|
||||
callback(
|
||||
Result.Failure(
|
||||
errorCode,
|
||||
activity.getString(R.string.biometric_auth_error_reason, errString)
|
||||
activity.getString(R.string.biometric_auth_error_reason, errString),
|
||||
)
|
||||
)
|
||||
BiometricPrompt.ERROR_CANCELED -> callback(Result.CanceledBySystem)
|
||||
|
@ -109,21 +109,21 @@ object BiometricAuthenticator {
|
|||
callback(
|
||||
Result.Failure(
|
||||
errorCode,
|
||||
activity.getString(R.string.biometric_auth_error_reason, errString)
|
||||
activity.getString(R.string.biometric_auth_error_reason, errString),
|
||||
)
|
||||
)
|
||||
BiometricPrompt.ERROR_VENDOR ->
|
||||
callback(
|
||||
Result.Failure(
|
||||
errorCode,
|
||||
activity.getString(R.string.biometric_auth_error_reason, errString)
|
||||
activity.getString(R.string.biometric_auth_error_reason, errString),
|
||||
)
|
||||
)
|
||||
BiometricPrompt.ERROR_LOCKOUT_PERMANENT ->
|
||||
callback(
|
||||
Result.Failure(
|
||||
errorCode,
|
||||
activity.getString(R.string.biometric_auth_error_reason, errString)
|
||||
activity.getString(R.string.biometric_auth_error_reason, errString),
|
||||
)
|
||||
)
|
||||
BiometricPrompt.ERROR_USER_CANCELED -> callback(Result.CanceledByUser)
|
||||
|
@ -138,7 +138,7 @@ object BiometricAuthenticator {
|
|||
callback(
|
||||
Result.Failure(
|
||||
errorCode,
|
||||
activity.getString(R.string.biometric_auth_error_reason, errString)
|
||||
activity.getString(R.string.biometric_auth_error_reason, errString),
|
||||
)
|
||||
)
|
||||
}
|
||||
|
|
|
@ -26,15 +26,12 @@ import logcat.LogPriority.ERROR
|
|||
import logcat.asLog
|
||||
import logcat.logcat
|
||||
|
||||
class Api26AutofillResponseBuilder
|
||||
private constructor(
|
||||
form: FillableForm,
|
||||
) : AutofillResponseBuilder {
|
||||
class Api26AutofillResponseBuilder private constructor(form: FillableForm) :
|
||||
AutofillResponseBuilder {
|
||||
|
||||
object Factory : AutofillResponseBuilder.Factory {
|
||||
override fun create(
|
||||
form: FillableForm,
|
||||
): AutofillResponseBuilder = Api26AutofillResponseBuilder(form)
|
||||
override fun create(form: FillableForm): AutofillResponseBuilder =
|
||||
Api26AutofillResponseBuilder(form)
|
||||
}
|
||||
|
||||
private val formOrigin = form.formOrigin
|
||||
|
@ -104,14 +101,14 @@ private constructor(
|
|||
AutofillPublisherChangedActivity.makePublisherChangedIntentSender(
|
||||
context,
|
||||
publisherChangedException,
|
||||
fillResponseAfterReset
|
||||
fillResponseAfterReset,
|
||||
)
|
||||
return makeIntentDataset(context, AutofillAction.Match, intentSender, metadata)
|
||||
}
|
||||
|
||||
private fun makePublisherChangedResponse(
|
||||
context: Context,
|
||||
publisherChangedException: AutofillPublisherChangedException
|
||||
publisherChangedException: AutofillPublisherChangedException,
|
||||
): FillResponse {
|
||||
return FillResponse.Builder().run {
|
||||
addDataset(makePublisherChangedDataset(context, publisherChangedException))
|
||||
|
@ -164,7 +161,7 @@ private constructor(
|
|||
setHeader(
|
||||
makeRemoteView(
|
||||
context,
|
||||
makeHeaderMetadata(formOrigin.getPrettyIdentifier(context, untrusted = true))
|
||||
makeHeaderMetadata(formOrigin.getPrettyIdentifier(context, untrusted = true)),
|
||||
)
|
||||
)
|
||||
}
|
||||
|
@ -183,7 +180,7 @@ private constructor(
|
|||
failure = { e ->
|
||||
logcat(ERROR) { e.asLog() }
|
||||
callback.onSuccess(makePublisherChangedResponse(context, e))
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,15 +33,12 @@ import logcat.logcat
|
|||
|
||||
/** Implements [AutofillResponseBuilder]'s methods for API 30 and above */
|
||||
@RequiresApi(Build.VERSION_CODES.R)
|
||||
class Api30AutofillResponseBuilder
|
||||
private constructor(
|
||||
form: FillableForm,
|
||||
) : AutofillResponseBuilder {
|
||||
class Api30AutofillResponseBuilder private constructor(form: FillableForm) :
|
||||
AutofillResponseBuilder {
|
||||
|
||||
object Factory : AutofillResponseBuilder.Factory {
|
||||
override fun create(
|
||||
form: FillableForm,
|
||||
): AutofillResponseBuilder = Api30AutofillResponseBuilder(form)
|
||||
override fun create(form: FillableForm): AutofillResponseBuilder =
|
||||
Api30AutofillResponseBuilder(form)
|
||||
}
|
||||
|
||||
private val formOrigin = form.formOrigin
|
||||
|
@ -127,7 +124,7 @@ private constructor(
|
|||
private fun makeMatchDataset(
|
||||
context: Context,
|
||||
file: File,
|
||||
imeSpec: InlinePresentationSpec?
|
||||
imeSpec: InlinePresentationSpec?,
|
||||
): Dataset? {
|
||||
if (!scenario.hasFieldsToFillOn(AutofillAction.Match)) return null
|
||||
val metadata = makeFillMatchMetadata(context, file)
|
||||
|
@ -151,7 +148,7 @@ private constructor(
|
|||
|
||||
private fun makeFillOtpFromSmsDataset(
|
||||
context: Context,
|
||||
imeSpec: InlinePresentationSpec?
|
||||
imeSpec: InlinePresentationSpec?,
|
||||
): Dataset? {
|
||||
if (!scenario.hasFieldsToFillOn(AutofillAction.FillOtpFromSms)) return null
|
||||
if (!AutofillSmsActivity.shouldOfferFillFromSms(context)) return null
|
||||
|
@ -162,14 +159,14 @@ private constructor(
|
|||
AutofillAction.FillOtpFromSms,
|
||||
intentSender,
|
||||
metadata,
|
||||
imeSpec
|
||||
imeSpec,
|
||||
)
|
||||
}
|
||||
|
||||
private fun makePublisherChangedDataset(
|
||||
context: Context,
|
||||
publisherChangedException: AutofillPublisherChangedException,
|
||||
imeSpec: InlinePresentationSpec?
|
||||
imeSpec: InlinePresentationSpec?,
|
||||
): Dataset {
|
||||
val metadata = makeWarningMetadata(context)
|
||||
// If the user decides to trust the new publisher, they can choose reset the list of
|
||||
|
@ -181,7 +178,7 @@ private constructor(
|
|||
AutofillPublisherChangedActivity.makePublisherChangedIntentSender(
|
||||
context,
|
||||
publisherChangedException,
|
||||
fillResponseAfterReset
|
||||
fillResponseAfterReset,
|
||||
)
|
||||
return makeIntentDataset(context, AutofillAction.Match, intentSender, metadata, imeSpec)
|
||||
}
|
||||
|
@ -189,7 +186,7 @@ private constructor(
|
|||
private fun makePublisherChangedResponse(
|
||||
context: Context,
|
||||
inlineSuggestionsRequest: InlineSuggestionsRequest?,
|
||||
publisherChangedException: AutofillPublisherChangedException
|
||||
publisherChangedException: AutofillPublisherChangedException,
|
||||
): FillResponse {
|
||||
val imeSpec = inlineSuggestionsRequest?.inlinePresentationSpecs?.firstOrNull()
|
||||
return FillResponse.Builder().run {
|
||||
|
@ -202,7 +199,7 @@ private constructor(
|
|||
private fun makeFillResponse(
|
||||
context: Context,
|
||||
inlineSuggestionsRequest: InlineSuggestionsRequest?,
|
||||
matchedFiles: List<File>
|
||||
matchedFiles: List<File>,
|
||||
): FillResponse? {
|
||||
var datasetCount = 0
|
||||
val imeSpecs = inlineSuggestionsRequest?.inlinePresentationSpecs ?: emptyList()
|
||||
|
@ -229,7 +226,7 @@ private constructor(
|
|||
setHeader(
|
||||
makeRemoteView(
|
||||
context,
|
||||
makeHeaderMetadata(formOrigin.getPrettyIdentifier(context, untrusted = true))
|
||||
makeHeaderMetadata(formOrigin.getPrettyIdentifier(context, untrusted = true)),
|
||||
)
|
||||
)
|
||||
makeSaveInfo()?.let { setSaveInfo(it) }
|
||||
|
@ -271,7 +268,7 @@ private constructor(
|
|||
callback.onSuccess(
|
||||
makePublisherChangedResponse(context, fillRequest.inlineSuggestionsRequest, e)
|
||||
)
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -102,7 +102,7 @@ class AutofillMatcher {
|
|||
*/
|
||||
fun getMatchesFor(
|
||||
context: Context,
|
||||
formOrigin: FormOrigin
|
||||
formOrigin: FormOrigin,
|
||||
): Result<List<File>, AutofillPublisherChangedException> {
|
||||
if (hasFormOriginHashChanged(context, formOrigin)) {
|
||||
return Err(AutofillPublisherChangedException(formOrigin))
|
||||
|
@ -151,7 +151,7 @@ class AutofillMatcher {
|
|||
Toast.makeText(
|
||||
context,
|
||||
context.getString(R.string.oreo_autofill_max_matches_reached, MAX_NUM_MATCHES),
|
||||
Toast.LENGTH_LONG
|
||||
Toast.LENGTH_LONG,
|
||||
)
|
||||
.show()
|
||||
return
|
||||
|
@ -170,7 +170,7 @@ class AutofillMatcher {
|
|||
fun updateMatches(
|
||||
context: Context,
|
||||
moveFromTo: Map<File, File> = emptyMap(),
|
||||
delete: Collection<File> = emptyList()
|
||||
delete: Collection<File> = emptyList(),
|
||||
) {
|
||||
val deletePathList = delete.map { it.absolutePath }
|
||||
val oldNewPathMap =
|
||||
|
|
|
@ -134,7 +134,7 @@ object AutofillPreferences {
|
|||
context: Context,
|
||||
file: File,
|
||||
entry: PasswordEntry,
|
||||
directoryStructure: DirectoryStructure
|
||||
directoryStructure: DirectoryStructure,
|
||||
): Credentials {
|
||||
// Always give priority to a username stored in the encrypted extras
|
||||
val username =
|
||||
|
|
|
@ -26,7 +26,7 @@ interface AutofillResponseBuilder {
|
|||
context: Context,
|
||||
credentials: Credentials,
|
||||
clientState: Bundle,
|
||||
action: AutofillAction
|
||||
action: AutofillAction,
|
||||
): Dataset {
|
||||
val scenario = AutofillScenario.fromClientState(clientState)
|
||||
// Before Android P, Datasets used for fill-in had to come with a RemoteViews, even
|
||||
|
|
|
@ -45,7 +45,7 @@ fun makeRemoteView(context: Context, metadata: DatasetMetadata): RemoteViews {
|
|||
fun makeInlinePresentation(
|
||||
context: Context,
|
||||
imeSpec: InlinePresentationSpec,
|
||||
metadata: DatasetMetadata
|
||||
metadata: DatasetMetadata,
|
||||
): InlinePresentation? {
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) return null
|
||||
|
||||
|
@ -91,21 +91,21 @@ fun makeSearchAndFillMetadata(context: Context) =
|
|||
DatasetMetadata(
|
||||
context.getString(R.string.oreo_autofill_search_in_store),
|
||||
null,
|
||||
R.drawable.ic_search_black_24dp
|
||||
R.drawable.ic_search_black_24dp,
|
||||
)
|
||||
|
||||
fun makeGenerateAndFillMetadata(context: Context) =
|
||||
DatasetMetadata(
|
||||
context.getString(R.string.oreo_autofill_generate_password),
|
||||
null,
|
||||
R.drawable.ic_autofill_new_password
|
||||
R.drawable.ic_autofill_new_password,
|
||||
)
|
||||
|
||||
fun makeFillOtpFromSmsMetadata(context: Context) =
|
||||
DatasetMetadata(
|
||||
context.getString(R.string.oreo_autofill_fill_otp_from_sms),
|
||||
null,
|
||||
R.drawable.ic_autofill_sms
|
||||
R.drawable.ic_autofill_sms,
|
||||
)
|
||||
|
||||
fun makeEmptyMetadata() = DatasetMetadata("PLACEHOLDER", "PLACEHOLDER", R.mipmap.ic_launcher)
|
||||
|
@ -114,7 +114,7 @@ fun makeWarningMetadata(context: Context) =
|
|||
DatasetMetadata(
|
||||
context.getString(R.string.oreo_autofill_warning_publisher_dataset_title),
|
||||
context.getString(R.string.oreo_autofill_warning_publisher_dataset_summary),
|
||||
R.drawable.ic_warning_red_24dp
|
||||
R.drawable.ic_warning_red_24dp,
|
||||
)
|
||||
|
||||
fun makeHeaderMetadata(title: String) = DatasetMetadata(title, null, 0)
|
||||
|
|
|
@ -56,7 +56,7 @@ private fun Context.getEncryptedPrefs(fileName: String): SharedPreferences {
|
|||
fileName,
|
||||
masterKeyAlias,
|
||||
EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
|
||||
EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
|
||||
EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM,
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -79,9 +79,7 @@ fun Context.resolveAttribute(attr: Int): Int {
|
|||
* Commit changes to the store from a [FragmentActivity] using a custom implementation of
|
||||
* [GitOperation]
|
||||
*/
|
||||
suspend fun FragmentActivity.commitChange(
|
||||
message: String,
|
||||
): Result<Unit, Throwable> {
|
||||
suspend fun FragmentActivity.commitChange(message: String): Result<Unit, Throwable> {
|
||||
if (!PasswordRepository.isInitialized) {
|
||||
return Ok(Unit)
|
||||
}
|
||||
|
|
|
@ -25,7 +25,7 @@ fun Fragment.finish() = requireActivity().finish()
|
|||
*/
|
||||
fun FragmentManager.performTransactionWithBackStack(
|
||||
destinationFragment: Fragment,
|
||||
@IdRes containerViewId: Int = android.R.id.content
|
||||
@IdRes containerViewId: Int = android.R.id.content,
|
||||
) {
|
||||
commit {
|
||||
addToBackStack(destinationFragment.tag)
|
||||
|
@ -33,7 +33,7 @@ fun FragmentManager.performTransactionWithBackStack(
|
|||
R.animator.slide_in_left,
|
||||
R.animator.slide_out_left,
|
||||
R.animator.slide_in_right,
|
||||
R.animator.slide_out_right
|
||||
R.animator.slide_out_right,
|
||||
)
|
||||
replace(containerViewId, destinationFragment)
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ import kotlin.reflect.KProperty
|
|||
*/
|
||||
class FragmentViewBindingDelegate<T : ViewBinding>(
|
||||
val fragment: Fragment,
|
||||
val viewBindingFactory: (View) -> T
|
||||
val viewBindingFactory: (View) -> T,
|
||||
) : ReadOnlyProperty<Fragment, T> {
|
||||
|
||||
private var binding: T? = null
|
||||
|
|
|
@ -14,5 +14,5 @@ enum class Feature(
|
|||
) {
|
||||
|
||||
/** Opt into a cache layer for PGP passphrases. */
|
||||
EnablePGPPassphraseCache(false, "enable_gpg_passphrase_cache"),
|
||||
EnablePGPPassphraseCache(false, "enable_gpg_passphrase_cache")
|
||||
}
|
||||
|
|
|
@ -11,9 +11,7 @@ import javax.inject.Inject
|
|||
|
||||
class Features
|
||||
@Inject
|
||||
constructor(
|
||||
@SettingsPreferences private val preferences: SharedPreferences,
|
||||
) {
|
||||
constructor(@SettingsPreferences private val preferences: SharedPreferences) {
|
||||
|
||||
fun isEnabled(feature: Feature): Boolean {
|
||||
return preferences.getBoolean(feature.configKey, feature.defaultValue)
|
||||
|
|
|
@ -38,7 +38,7 @@ class GitCommandExecutor(
|
|||
private val hiltEntryPoint by unsafeLazy {
|
||||
EntryPointAccessors.fromApplication(
|
||||
activity.applicationContext,
|
||||
GitCommandExecutorEntryPoint::class.java
|
||||
GitCommandExecutorEntryPoint::class.java,
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -93,7 +93,7 @@ class GitCommandExecutor(
|
|||
RemoteRefUpdate.Status.REJECTED_NODELETE,
|
||||
RemoteRefUpdate.Status.REJECTED_REMOTE_CHANGED,
|
||||
RemoteRefUpdate.Status.NON_EXISTING,
|
||||
RemoteRefUpdate.Status.NOT_ATTEMPTED, ->
|
||||
RemoteRefUpdate.Status.NOT_ATTEMPTED ->
|
||||
throw PushException.Generic(rru.status.name)
|
||||
RemoteRefUpdate.Status.REJECTED_OTHER_REASON -> {
|
||||
throw if ("non-fast-forward" == rru.message) {
|
||||
|
@ -107,7 +107,7 @@ class GitCommandExecutor(
|
|||
Toast.makeText(
|
||||
activity,
|
||||
activity.applicationContext.getString(R.string.git_push_up_to_date),
|
||||
Toast.LENGTH_SHORT
|
||||
Toast.LENGTH_SHORT,
|
||||
)
|
||||
.show()
|
||||
}
|
||||
|
|
|
@ -19,5 +19,5 @@ data class GitCommit(
|
|||
val hash: String,
|
||||
val shortMessage: String,
|
||||
val authorName: String,
|
||||
val time: Instant
|
||||
val time: Instant,
|
||||
)
|
||||
|
|
|
@ -18,7 +18,5 @@ class CloneOperation(callingActivity: AppCompatActivity, uri: String) :
|
|||
GitOperation(callingActivity) {
|
||||
|
||||
override val commands: Array<GitCommand<out Any>> =
|
||||
arrayOf(
|
||||
Git.cloneRepository().setDirectory(repository.workTree).setURI(uri),
|
||||
)
|
||||
arrayOf(Git.cloneRepository().setDirectory(repository.workTree).setURI(uri))
|
||||
}
|
||||
|
|
|
@ -12,9 +12,7 @@ import org.eclipse.jgit.api.GitCommand
|
|||
* Run an aggressive garbage collection job on the repository, expiring every loose object to
|
||||
* achieve the best compression.
|
||||
*/
|
||||
class GcOperation(
|
||||
callingActivity: AppCompatActivity,
|
||||
) : GitOperation(callingActivity) {
|
||||
class GcOperation(callingActivity: AppCompatActivity) : GitOperation(callingActivity) {
|
||||
|
||||
override val requiresAuth: Boolean = false
|
||||
override val commands: Array<GitCommand<out Any>> =
|
||||
|
|
|
@ -116,7 +116,7 @@ abstract class GitOperation(protected val callingActivity: FragmentActivity) {
|
|||
|
||||
private fun registerAuthProviders(
|
||||
authMethod: SshAuthMethod,
|
||||
credentialsProvider: CredentialsProvider? = null
|
||||
credentialsProvider: CredentialsProvider? = null,
|
||||
) {
|
||||
sshSessionFactory =
|
||||
SshjSessionFactory(authMethod, hostKeyFile, hiltEntryPoint.dispatcherProvider())
|
||||
|
@ -134,12 +134,7 @@ abstract class GitOperation(protected val callingActivity: FragmentActivity) {
|
|||
if (!preExecute()) {
|
||||
return Ok(Unit)
|
||||
}
|
||||
val operationResult =
|
||||
GitCommandExecutor(
|
||||
callingActivity,
|
||||
this,
|
||||
)
|
||||
.execute()
|
||||
val operationResult = GitCommandExecutor(callingActivity, this).execute()
|
||||
postExecute()
|
||||
return operationResult
|
||||
}
|
||||
|
@ -174,7 +169,7 @@ abstract class GitOperation(protected val callingActivity: FragmentActivity) {
|
|||
suspendCoroutine { cont ->
|
||||
BiometricAuthenticator.authenticate(
|
||||
callingActivity,
|
||||
R.string.biometric_prompt_title_ssh_auth
|
||||
R.string.biometric_prompt_title_ssh_auth,
|
||||
) { result ->
|
||||
if (result !is Failure && result !is Retry) cont.resume(result)
|
||||
}
|
||||
|
@ -199,7 +194,7 @@ abstract class GitOperation(protected val callingActivity: FragmentActivity) {
|
|||
Toast.makeText(
|
||||
callingActivity,
|
||||
R.string.biometric_auth_generic_failure,
|
||||
Toast.LENGTH_LONG
|
||||
Toast.LENGTH_LONG,
|
||||
)
|
||||
.show()
|
||||
callingActivity.finish()
|
||||
|
@ -220,7 +215,7 @@ abstract class GitOperation(protected val callingActivity: FragmentActivity) {
|
|||
CredentialFinder(
|
||||
callingActivity,
|
||||
AuthMode.Password,
|
||||
hiltEntryPoint.dispatcherProvider()
|
||||
hiltEntryPoint.dispatcherProvider(),
|
||||
)
|
||||
)
|
||||
registerAuthProviders(SshAuthMethod.Password(authActivity), httpsCredentialProvider)
|
||||
|
|
|
@ -7,10 +7,8 @@ package app.passwordstore.util.git.operation
|
|||
import androidx.appcompat.app.AppCompatActivity
|
||||
import org.eclipse.jgit.api.GitCommand
|
||||
|
||||
class PullOperation(
|
||||
callingActivity: AppCompatActivity,
|
||||
rebase: Boolean,
|
||||
) : GitOperation(callingActivity) {
|
||||
class PullOperation(callingActivity: AppCompatActivity, rebase: Boolean) :
|
||||
GitOperation(callingActivity) {
|
||||
|
||||
/**
|
||||
* The story of why the pull operation is committing files goes like this: Once upon a time when
|
||||
|
|
|
@ -10,7 +10,5 @@ import org.eclipse.jgit.api.GitCommand
|
|||
class PushOperation(callingActivity: AppCompatActivity) : GitOperation(callingActivity) {
|
||||
|
||||
override val commands: Array<GitCommand<out Any>> =
|
||||
arrayOf(
|
||||
git.push().setPushAll().setRemote("origin"),
|
||||
)
|
||||
arrayOf(git.push().setPushAll().setRemote("origin"))
|
||||
}
|
||||
|
|
|
@ -7,10 +7,8 @@ package app.passwordstore.util.git.operation
|
|||
import androidx.appcompat.app.AppCompatActivity
|
||||
import org.eclipse.jgit.api.GitCommand
|
||||
|
||||
class SyncOperation(
|
||||
callingActivity: AppCompatActivity,
|
||||
rebase: Boolean,
|
||||
) : GitOperation(callingActivity) {
|
||||
class SyncOperation(callingActivity: AppCompatActivity, rebase: Boolean) :
|
||||
GitOperation(callingActivity) {
|
||||
|
||||
override val commands: Array<GitCommand<out Any>> =
|
||||
arrayOf(
|
||||
|
|
|
@ -135,8 +135,7 @@ object SshKey {
|
|||
KeystoreWrappedEd25519("keystore_wrapped_ed25519"),
|
||||
|
||||
// Behaves like `Imported`, but allows to view the public key.
|
||||
LegacyGenerated("legacy_generated"),
|
||||
;
|
||||
LegacyGenerated("legacy_generated");
|
||||
|
||||
companion object {
|
||||
|
||||
|
@ -146,7 +145,7 @@ object SshKey {
|
|||
|
||||
enum class Algorithm(
|
||||
val algorithm: String,
|
||||
val applyToSpec: KeyGenParameterSpec.Builder.() -> Unit
|
||||
val applyToSpec: KeyGenParameterSpec.Builder.() -> Unit,
|
||||
) {
|
||||
Rsa(
|
||||
KeyProperties.KEY_ALGORITHM_RSA,
|
||||
|
@ -156,9 +155,9 @@ object SshKey {
|
|||
setDigests(
|
||||
KeyProperties.DIGEST_SHA1,
|
||||
KeyProperties.DIGEST_SHA256,
|
||||
KeyProperties.DIGEST_SHA512
|
||||
KeyProperties.DIGEST_SHA512,
|
||||
)
|
||||
}
|
||||
},
|
||||
),
|
||||
Ecdsa(
|
||||
KeyProperties.KEY_ALGORITHM_EC,
|
||||
|
@ -169,7 +168,7 @@ object SshKey {
|
|||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
||||
setIsStrongBoxBacked(isStrongBoxSupported)
|
||||
}
|
||||
}
|
||||
},
|
||||
),
|
||||
}
|
||||
|
||||
|
@ -250,7 +249,7 @@ object SshKey {
|
|||
context,
|
||||
privateKeyFile,
|
||||
getOrCreateWrappingMasterKey(requireAuthentication),
|
||||
EncryptedFile.FileEncryptionScheme.AES256_GCM_HKDF_4KB
|
||||
EncryptedFile.FileEncryptionScheme.AES256_GCM_HKDF_4KB,
|
||||
)
|
||||
.setKeysetPrefName(ANDROIDX_SECURITY_KEYSET_PREF_NAME)
|
||||
.build()
|
||||
|
@ -319,7 +318,7 @@ object SshKey {
|
|||
logcat { error.asLog() }
|
||||
throw IOException(
|
||||
"Failed to get public key '$KEYSTORE_ALIAS' from Android Keystore",
|
||||
error
|
||||
error,
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -329,7 +328,7 @@ object SshKey {
|
|||
logcat { error.asLog() }
|
||||
throw IOException(
|
||||
"Failed to access private key '$KEYSTORE_ALIAS' from Android Keystore",
|
||||
error
|
||||
error,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -140,18 +140,10 @@ class SshjConfig : ConfigImpl() {
|
|||
|
||||
private fun initMACFactories() {
|
||||
macFactories =
|
||||
listOf(
|
||||
Macs.HMACSHA2512Etm(),
|
||||
Macs.HMACSHA2256Etm(),
|
||||
Macs.HMACSHA2512(),
|
||||
Macs.HMACSHA2256(),
|
||||
)
|
||||
listOf(Macs.HMACSHA2512Etm(), Macs.HMACSHA2256Etm(), Macs.HMACSHA2512(), Macs.HMACSHA2256())
|
||||
}
|
||||
|
||||
private fun initCompressionFactories() {
|
||||
compressionFactories =
|
||||
listOf(
|
||||
NoneCompression.Factory(),
|
||||
)
|
||||
compressionFactories = listOf(NoneCompression.Factory())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -79,7 +79,7 @@ class SshjSessionFactory(
|
|||
uri: URIish,
|
||||
credentialsProvider: CredentialsProvider?,
|
||||
fs: FS?,
|
||||
tms: Int
|
||||
tms: Int,
|
||||
): RemoteSession {
|
||||
return currentSession
|
||||
?: SshjSession(uri, uri.user, authMethod, hostKeyFile, dispatcherProvider).connect().also {
|
||||
|
@ -164,7 +164,7 @@ private class SshjSession(
|
|||
AuthPublickey(
|
||||
SshKey.provide(
|
||||
ssh,
|
||||
CredentialFinder(authMethod.activity, AuthMode.SshKey, dispatcherProvider)
|
||||
CredentialFinder(authMethod.activity, AuthMode.SshKey, dispatcherProvider),
|
||||
)
|
||||
)
|
||||
ssh.auth(username, pubkeyAuth, passwordAuth)
|
||||
|
|
|
@ -125,7 +125,7 @@ class ClipboardService : Service() {
|
|||
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_MUTABLE
|
||||
} else {
|
||||
PendingIntent.FLAG_UPDATE_CURRENT
|
||||
}
|
||||
},
|
||||
)
|
||||
val notification = createNotification(pendingIntent, clearTimeMs)
|
||||
|
||||
|
@ -152,7 +152,7 @@ class ClipboardService : Service() {
|
|||
NotificationChannel(
|
||||
CHANNEL_ID,
|
||||
getString(R.string.app_name),
|
||||
NotificationManager.IMPORTANCE_LOW
|
||||
NotificationManager.IMPORTANCE_LOW,
|
||||
)
|
||||
val manager = getSystemService<NotificationManager>()
|
||||
if (manager != null) {
|
||||
|
|
|
@ -65,7 +65,7 @@ class OreoAutofillService : AutofillService() {
|
|||
override fun onFillRequest(
|
||||
request: FillRequest,
|
||||
cancellationSignal: CancellationSignal,
|
||||
callback: FillCallback
|
||||
callback: FillCallback,
|
||||
) {
|
||||
val structure =
|
||||
request.fillContexts.lastOrNull()?.structure
|
||||
|
@ -144,7 +144,7 @@ class OreoAutofillService : AutofillService() {
|
|||
AutofillSaveActivity.makeSaveIntentSender(
|
||||
this,
|
||||
credentials = Credentials(username, password, null),
|
||||
formOrigin = formOrigin
|
||||
formOrigin = formOrigin,
|
||||
)
|
||||
)
|
||||
}
|
||||
|
|
|
@ -134,7 +134,7 @@ class PasswordExportService : Service() {
|
|||
NotificationChannel(
|
||||
CHANNEL_ID,
|
||||
getString(R.string.app_name),
|
||||
NotificationManager.IMPORTANCE_LOW
|
||||
NotificationManager.IMPORTANCE_LOW,
|
||||
)
|
||||
val manager = getSystemService<NotificationManager>()
|
||||
if (manager != null) {
|
||||
|
|
|
@ -21,8 +21,7 @@ import org.eclipse.jgit.transport.URIish
|
|||
|
||||
enum class Protocol(val pref: String) {
|
||||
Ssh("ssh://"),
|
||||
Https("https://"),
|
||||
;
|
||||
Https("https://");
|
||||
|
||||
companion object {
|
||||
|
||||
|
@ -36,8 +35,7 @@ enum class Protocol(val pref: String) {
|
|||
enum class AuthMode(val pref: String) {
|
||||
SshKey("ssh-key"),
|
||||
Password("username/password"),
|
||||
None("None"),
|
||||
;
|
||||
None("None");
|
||||
|
||||
companion object {
|
||||
|
||||
|
@ -140,7 +138,7 @@ constructor(
|
|||
|
||||
fun updateConnectionSettingsIfValid(
|
||||
newAuthMode: AuthMode,
|
||||
newUrl: String
|
||||
newUrl: String,
|
||||
): UpdateConnectionSettingsResult {
|
||||
val parsedUrl =
|
||||
runCatching { URIish(newUrl) }
|
||||
|
|
|
@ -91,7 +91,7 @@ private fun migrateToGitUrlBasedConfig(sharedPrefs: SharedPreferences, gitSettin
|
|||
url == null ||
|
||||
gitSettings.updateConnectionSettingsIfValid(
|
||||
newAuthMode = gitSettings.authMode,
|
||||
newUrl = url
|
||||
newUrl = url,
|
||||
) != GitSettings.UpdateConnectionSettingsResult.Valid
|
||||
) {
|
||||
logcat(TAG, ERROR) { "Failed to migrate to URL-based Git config, generated URL is invalid" }
|
||||
|
@ -128,7 +128,7 @@ private fun migrateToClipboardHistory(sharedPrefs: SharedPreferences) {
|
|||
sharedPrefs.edit {
|
||||
putBoolean(
|
||||
PreferenceKeys.CLEAR_CLIPBOARD_HISTORY,
|
||||
sharedPrefs.getBoolean(PreferenceKeys.CLEAR_CLIPBOARD_20X, false)
|
||||
sharedPrefs.getBoolean(PreferenceKeys.CLEAR_CLIPBOARD_20X, false),
|
||||
)
|
||||
remove(PreferenceKeys.CLEAR_CLIPBOARD_20X)
|
||||
}
|
||||
|
|
|
@ -64,7 +64,7 @@ object PreferenceKeys {
|
|||
|
||||
@Deprecated(
|
||||
message = "Use SHOW_HIDDEN_CONTENTS instead",
|
||||
replaceWith = ReplaceWith("PreferenceKeys.SHOW_HIDDEN_CONTENTS")
|
||||
replaceWith = ReplaceWith("PreferenceKeys.SHOW_HIDDEN_CONTENTS"),
|
||||
)
|
||||
const val SHOW_HIDDEN_FOLDERS = "show_hidden_folders"
|
||||
const val SHOW_HIDDEN_CONTENTS = "show_hidden_contents"
|
||||
|
|
|
@ -19,11 +19,7 @@ import javax.inject.Inject
|
|||
import logcat.logcat
|
||||
|
||||
@Reusable
|
||||
class ShortcutHandler
|
||||
@Inject
|
||||
constructor(
|
||||
@ApplicationContext val context: Context,
|
||||
) {
|
||||
class ShortcutHandler @Inject constructor(@ApplicationContext val context: Context) {
|
||||
|
||||
private companion object {
|
||||
|
||||
|
|
|
@ -67,7 +67,7 @@ private val CaseInsensitiveComparator = Collator.getInstance().apply { strength
|
|||
|
||||
private fun PasswordItem.Companion.makeComparator(
|
||||
typeSortOrder: PasswordSortOrder,
|
||||
directoryStructure: DirectoryStructure
|
||||
directoryStructure: DirectoryStructure,
|
||||
): Comparator<PasswordItem> {
|
||||
return when (typeSortOrder) {
|
||||
PasswordSortOrder.FOLDER_FIRST -> compareBy { it.type }
|
||||
|
@ -158,7 +158,7 @@ constructor(
|
|||
val listMode: ListMode,
|
||||
// This counter can be increased to force a reexecution of the search action even if all
|
||||
// other arguments are left unchanged.
|
||||
val updateCounter: Int
|
||||
val updateCounter: Int,
|
||||
)
|
||||
|
||||
private fun makeSearchAction(
|
||||
|
@ -166,7 +166,7 @@ constructor(
|
|||
filter: String,
|
||||
filterMode: FilterMode,
|
||||
searchMode: SearchMode,
|
||||
listMode: ListMode
|
||||
listMode: ListMode,
|
||||
): SearchAction {
|
||||
return SearchAction(
|
||||
baseDirectory = baseDirectory,
|
||||
|
@ -174,7 +174,7 @@ constructor(
|
|||
filterMode = filterMode,
|
||||
searchMode = searchMode,
|
||||
listMode = listMode,
|
||||
updateCounter = updateCounter
|
||||
updateCounter = updateCounter,
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -187,7 +187,7 @@ constructor(
|
|||
filter = "",
|
||||
filterMode = FilterMode.NoFilter,
|
||||
searchMode = SearchMode.InCurrentDirectoryOnly,
|
||||
listMode = ListMode.AllEntries
|
||||
listMode = ListMode.AllEntries,
|
||||
)
|
||||
)
|
||||
|
||||
|
@ -310,7 +310,7 @@ constructor(
|
|||
newDirectory: File = root,
|
||||
listMode: ListMode = ListMode.AllEntries,
|
||||
recyclerViewState: Parcelable? = null,
|
||||
pushPreviousLocation: Boolean = true
|
||||
pushPreviousLocation: Boolean = true,
|
||||
) {
|
||||
if (!newDirectory.exists()) return
|
||||
require(newDirectory.isDirectory) { "Can only navigate to a directory" }
|
||||
|
@ -323,7 +323,7 @@ constructor(
|
|||
baseDirectory = newDirectory,
|
||||
filterMode = FilterMode.NoFilter,
|
||||
searchMode = SearchMode.InCurrentDirectoryOnly,
|
||||
listMode = listMode
|
||||
listMode = listMode,
|
||||
)
|
||||
}
|
||||
_currentDir.update { newDirectory }
|
||||
|
@ -356,7 +356,7 @@ constructor(
|
|||
baseDirectory: File? = null,
|
||||
filterMode: FilterMode = FilterMode.Fuzzy,
|
||||
searchMode: SearchMode? = null,
|
||||
listMode: ListMode = ListMode.AllEntries
|
||||
listMode: ListMode = ListMode.AllEntries,
|
||||
) {
|
||||
require(baseDirectory?.isDirectory != false) { "Can only search in a directory" }
|
||||
searchActionFlow.update {
|
||||
|
@ -365,7 +365,7 @@ constructor(
|
|||
baseDirectory = baseDirectory ?: _currentDir.value,
|
||||
filterMode = filterMode,
|
||||
searchMode = searchMode ?: defaultSearchMode,
|
||||
listMode = listMode
|
||||
listMode = listMode,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -417,7 +417,7 @@ open class SearchableRepositoryAdapter<T : RecyclerView.ViewHolder>(
|
|||
|
||||
fun <T : ItemDetailsLookup<String>> makeSelectable(
|
||||
recyclerView: RecyclerView,
|
||||
itemDetailsLookupCreator: (recyclerView: RecyclerView) -> T
|
||||
itemDetailsLookupCreator: (recyclerView: RecyclerView) -> T,
|
||||
) {
|
||||
selectionTracker =
|
||||
SelectionTracker.Builder(
|
||||
|
@ -425,7 +425,7 @@ open class SearchableRepositoryAdapter<T : RecyclerView.ViewHolder>(
|
|||
recyclerView,
|
||||
itemKeyProvider,
|
||||
itemDetailsLookupCreator(recyclerView),
|
||||
StorageStrategy.createStringStorage()
|
||||
StorageStrategy.createStringStorage(),
|
||||
)
|
||||
.withSelectionPredicate(SelectionPredicates.createSelectAnything())
|
||||
.build()
|
||||
|
|
|
@ -87,7 +87,7 @@ class AutofillSmsActivity : AppCompatActivity() {
|
|||
context,
|
||||
fillOtpFromSmsRequestCode++,
|
||||
intent,
|
||||
PendingIntent.FLAG_CANCEL_CURRENT or PendingIntent.FLAG_IMMUTABLE
|
||||
PendingIntent.FLAG_CANCEL_CURRENT or PendingIntent.FLAG_IMMUTABLE,
|
||||
)
|
||||
.intentSender
|
||||
}
|
||||
|
@ -159,11 +159,11 @@ class AutofillSmsActivity : AppCompatActivity() {
|
|||
this@AutofillSmsActivity,
|
||||
Credentials(null, null, smsCode),
|
||||
clientState,
|
||||
AutofillAction.FillOtpFromSms
|
||||
AutofillAction.FillOtpFromSms,
|
||||
)
|
||||
setResult(
|
||||
RESULT_OK,
|
||||
Intent().apply { putExtra(AutofillManager.EXTRA_AUTHENTICATION_RESULT, fillInDataset) }
|
||||
Intent().apply { putExtra(AutofillManager.EXTRA_AUTHENTICATION_RESULT, fillInDataset) },
|
||||
)
|
||||
finish()
|
||||
}
|
||||
|
|
|
@ -61,12 +61,12 @@ class MigrationsTest {
|
|||
runMigrations(
|
||||
filesDir,
|
||||
sharedPrefs,
|
||||
GitSettings(sharedPrefs, encryptedSharedPreferences, proxySharedPreferences, filesDir)
|
||||
GitSettings(sharedPrefs, encryptedSharedPreferences, proxySharedPreferences, filesDir),
|
||||
)
|
||||
checkOldKeysAreRemoved()
|
||||
assertEquals(
|
||||
sharedPrefs.getString(PreferenceKeys.GIT_REMOTE_URL),
|
||||
"ssh://msfjarvis@192.168.0.102:2200/mnt/disk3/pass-repo"
|
||||
"ssh://msfjarvis@192.168.0.102:2200/mnt/disk3/pass-repo",
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -82,12 +82,12 @@ class MigrationsTest {
|
|||
runMigrations(
|
||||
filesDir,
|
||||
sharedPrefs,
|
||||
GitSettings(sharedPrefs, encryptedSharedPreferences, proxySharedPreferences, filesDir)
|
||||
GitSettings(sharedPrefs, encryptedSharedPreferences, proxySharedPreferences, filesDir),
|
||||
)
|
||||
checkOldKeysAreRemoved()
|
||||
assertEquals(
|
||||
sharedPrefs.getString(PreferenceKeys.GIT_REMOTE_URL),
|
||||
"msfjarvis@192.168.0.102:/mnt/disk3/pass-repo"
|
||||
"msfjarvis@192.168.0.102:/mnt/disk3/pass-repo",
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -103,12 +103,12 @@ class MigrationsTest {
|
|||
runMigrations(
|
||||
filesDir,
|
||||
sharedPrefs,
|
||||
GitSettings(sharedPrefs, encryptedSharedPreferences, proxySharedPreferences, filesDir)
|
||||
GitSettings(sharedPrefs, encryptedSharedPreferences, proxySharedPreferences, filesDir),
|
||||
)
|
||||
checkOldKeysAreRemoved()
|
||||
assertEquals(
|
||||
sharedPrefs.getString(PreferenceKeys.GIT_REMOTE_URL),
|
||||
"https://github.com/Android-Password-Store/pass-test"
|
||||
"https://github.com/Android-Password-Store/pass-test",
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -117,7 +117,7 @@ class MigrationsTest {
|
|||
runMigrations(
|
||||
filesDir,
|
||||
sharedPrefs,
|
||||
GitSettings(sharedPrefs, encryptedSharedPreferences, proxySharedPreferences, filesDir)
|
||||
GitSettings(sharedPrefs, encryptedSharedPreferences, proxySharedPreferences, filesDir),
|
||||
)
|
||||
assertEquals(true, sharedPrefs.getBoolean(PreferenceKeys.SHOW_HIDDEN_FOLDERS, true))
|
||||
assertEquals(false, sharedPrefs.getBoolean(PreferenceKeys.SHOW_HIDDEN_CONTENTS, false))
|
||||
|
@ -129,7 +129,7 @@ class MigrationsTest {
|
|||
runMigrations(
|
||||
filesDir,
|
||||
sharedPrefs,
|
||||
GitSettings(sharedPrefs, encryptedSharedPreferences, proxySharedPreferences, filesDir)
|
||||
GitSettings(sharedPrefs, encryptedSharedPreferences, proxySharedPreferences, filesDir),
|
||||
)
|
||||
assertEquals(false, sharedPrefs.getBoolean(PreferenceKeys.SHOW_HIDDEN_FOLDERS, false))
|
||||
assertEquals(true, sharedPrefs.getBoolean(PreferenceKeys.SHOW_HIDDEN_CONTENTS, false))
|
||||
|
@ -141,7 +141,7 @@ class MigrationsTest {
|
|||
runMigrations(
|
||||
filesDir,
|
||||
sharedPrefs,
|
||||
GitSettings(sharedPrefs, encryptedSharedPreferences, proxySharedPreferences, filesDir)
|
||||
GitSettings(sharedPrefs, encryptedSharedPreferences, proxySharedPreferences, filesDir),
|
||||
)
|
||||
assertEquals(true, sharedPrefs.getBoolean(PreferenceKeys.CLEAR_CLIPBOARD_HISTORY, false))
|
||||
assertFalse(sharedPrefs.contains(PreferenceKeys.CLEAR_CLIPBOARD_20X))
|
||||
|
|
|
@ -47,7 +47,7 @@ public sealed class FormOrigin(public open val identifier: String) {
|
|||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
context.packageManager.getApplicationInfo(
|
||||
identifier,
|
||||
ApplicationInfoFlags.of(PackageManager.GET_META_DATA.toLong())
|
||||
ApplicationInfoFlags.of(PackageManager.GET_META_DATA.toLong()),
|
||||
)
|
||||
} else {
|
||||
context.packageManager.getApplicationInfo(identifier, PackageManager.GET_META_DATA)
|
||||
|
@ -74,7 +74,7 @@ private class AutofillFormParser(
|
|||
context: Context,
|
||||
structure: AssistStructure,
|
||||
isManualRequest: Boolean,
|
||||
private val customSuffixes: Sequence<String>
|
||||
private val customSuffixes: Sequence<String>,
|
||||
) {
|
||||
|
||||
companion object {
|
||||
|
@ -136,7 +136,7 @@ private class AutofillFormParser(
|
|||
autofillStrategy.match(
|
||||
relevantFields,
|
||||
singleOriginMode = trustedBrowserInfo?.multiOriginMethod == BrowserMultiOriginMethod.None,
|
||||
isManualRequest = isManualRequest
|
||||
isManualRequest = isManualRequest,
|
||||
)
|
||||
|
||||
private fun trackOrigin(node: AssistStructure.ViewNode) {
|
||||
|
@ -187,7 +187,7 @@ private class AutofillFormParser(
|
|||
// situation is uncertain and Autofill should not be offered.
|
||||
webOriginToFormOrigin(
|
||||
context,
|
||||
scenario.allFields.map { it.webOrigin }.toSet().singleOrNull() ?: return null
|
||||
scenario.allFields.map { it.webOrigin }.toSet().singleOrNull() ?: return null,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -206,7 +206,7 @@ private constructor(
|
|||
public val formOrigin: FormOrigin,
|
||||
public val scenario: AutofillScenario<AutofillId>,
|
||||
public val ignoredIds: List<AutofillId>,
|
||||
public val saveFlags: Int?
|
||||
public val saveFlags: Int?,
|
||||
) {
|
||||
public companion object {
|
||||
/** Returns a [FillableForm] if a login form could be detected in [structure]. */
|
||||
|
@ -222,7 +222,7 @@ private constructor(
|
|||
form.formOrigin,
|
||||
form.scenario.map { it.autofillId },
|
||||
form.ignoredIds,
|
||||
form.saveFlags
|
||||
form.saveFlags,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -57,7 +57,7 @@ public fun computeCertificatesHash(context: Context, appPackage: String): String
|
|||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
context.packageManager.getPackageInfo(
|
||||
appPackage,
|
||||
PackageManager.PackageInfoFlags.of(PackageManager.GET_SIGNING_CERTIFICATES.toLong())
|
||||
PackageManager.PackageInfoFlags.of(PackageManager.GET_SIGNING_CERTIFICATES.toLong()),
|
||||
)
|
||||
} else {
|
||||
context.packageManager.getPackageInfo(appPackage, PackageManager.GET_SIGNING_CERTIFICATES)
|
||||
|
@ -121,7 +121,7 @@ private fun visitViewNodes(structure: AssistStructure, block: (AssistStructure.V
|
|||
|
||||
private fun visitViewNode(
|
||||
node: AssistStructure.ViewNode,
|
||||
block: (AssistStructure.ViewNode) -> Unit
|
||||
block: (AssistStructure.ViewNode) -> Unit,
|
||||
) {
|
||||
block(node)
|
||||
for (i in 0 until node.childCount) {
|
||||
|
|
|
@ -21,7 +21,7 @@ public enum class AutofillAction {
|
|||
Match,
|
||||
Search,
|
||||
Generate,
|
||||
FillOtpFromSms
|
||||
FillOtpFromSms,
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -46,8 +46,8 @@ public sealed class AutofillScenario<out T : Any> {
|
|||
"Use `fromClientState` instead.",
|
||||
ReplaceWith(
|
||||
"fromClientState(clientState)",
|
||||
"com.github.androidpasswordstore.autofillparser.AutofillScenario.Companion.fromClientState"
|
||||
)
|
||||
"com.github.androidpasswordstore.autofillparser.AutofillScenario.Companion.fromClientState",
|
||||
),
|
||||
)
|
||||
public fun fromBundle(clientState: Bundle): AutofillScenario<AutofillId>? {
|
||||
return fromClientState(clientState)
|
||||
|
@ -61,7 +61,7 @@ public sealed class AutofillScenario<out T : Any> {
|
|||
BundleCompat.getParcelable(
|
||||
clientState,
|
||||
BUNDLE_KEY_USERNAME_ID,
|
||||
AutofillId::class.java
|
||||
AutofillId::class.java,
|
||||
)
|
||||
fillUsername = clientState.getBoolean(BUNDLE_KEY_FILL_USERNAME)
|
||||
otp = BundleCompat.getParcelable(clientState, BUNDLE_KEY_OTP_ID, AutofillId::class.java)
|
||||
|
@ -69,21 +69,21 @@ public sealed class AutofillScenario<out T : Any> {
|
|||
BundleCompat.getParcelableArrayList(
|
||||
clientState,
|
||||
BUNDLE_KEY_CURRENT_PASSWORD_IDS,
|
||||
AutofillId::class.java
|
||||
AutofillId::class.java,
|
||||
) ?: emptyList()
|
||||
)
|
||||
newPassword.addAll(
|
||||
BundleCompat.getParcelableArrayList(
|
||||
clientState,
|
||||
BUNDLE_KEY_NEW_PASSWORD_IDS,
|
||||
AutofillId::class.java
|
||||
AutofillId::class.java,
|
||||
) ?: emptyList()
|
||||
)
|
||||
genericPassword.addAll(
|
||||
BundleCompat.getParcelableArrayList(
|
||||
clientState,
|
||||
BUNDLE_KEY_GENERIC_PASSWORD_IDS,
|
||||
AutofillId::class.java
|
||||
AutofillId::class.java,
|
||||
) ?: emptyList()
|
||||
)
|
||||
}
|
||||
|
@ -114,14 +114,14 @@ public sealed class AutofillScenario<out T : Any> {
|
|||
fillUsername = fillUsername,
|
||||
otp = otp,
|
||||
currentPassword = currentPassword,
|
||||
newPassword = newPassword
|
||||
newPassword = newPassword,
|
||||
)
|
||||
} else {
|
||||
GenericAutofillScenario(
|
||||
username = username,
|
||||
fillUsername = fillUsername,
|
||||
otp = otp,
|
||||
genericPassword = genericPassword
|
||||
genericPassword = genericPassword,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -193,7 +193,7 @@ internal data class ClassifiedAutofillScenario<T : Any>(
|
|||
override val fillUsername: Boolean,
|
||||
override val otp: T?,
|
||||
val currentPassword: List<T>,
|
||||
val newPassword: List<T>
|
||||
val newPassword: List<T>,
|
||||
) : AutofillScenario<T>() {
|
||||
|
||||
override val allPasswordFields
|
||||
|
@ -217,7 +217,7 @@ internal data class GenericAutofillScenario<T : Any>(
|
|||
override val username: T?,
|
||||
override val fillUsername: Boolean,
|
||||
override val otp: T?,
|
||||
val genericPassword: List<T>
|
||||
val genericPassword: List<T>,
|
||||
) : AutofillScenario<T>() {
|
||||
|
||||
override val allPasswordFields
|
||||
|
@ -254,7 +254,7 @@ internal fun AutofillScenario<FormField>.passesOriginCheck(singleOriginMode: Boo
|
|||
public fun Dataset.Builder.fillWith(
|
||||
scenario: AutofillScenario<AutofillId>,
|
||||
action: AutofillAction,
|
||||
credentials: Credentials?
|
||||
credentials: Credentials?,
|
||||
) {
|
||||
val credentialsToFill = credentials ?: Credentials("USERNAME", "PASSWORD", "OTP")
|
||||
for (field in scenario.fieldsToFillOn(action)) {
|
||||
|
@ -303,7 +303,7 @@ internal fun AutofillScenario<AutofillId>.toBundle(): Bundle =
|
|||
putParcelable(AutofillScenario.BUNDLE_KEY_OTP_ID, otp)
|
||||
putParcelableArrayList(
|
||||
AutofillScenario.BUNDLE_KEY_CURRENT_PASSWORD_IDS,
|
||||
ArrayList(currentPassword)
|
||||
ArrayList(currentPassword),
|
||||
)
|
||||
putParcelableArrayList(AutofillScenario.BUNDLE_KEY_NEW_PASSWORD_IDS, ArrayList(newPassword))
|
||||
}
|
||||
|
@ -315,7 +315,7 @@ internal fun AutofillScenario<AutofillId>.toBundle(): Bundle =
|
|||
putParcelable(AutofillScenario.BUNDLE_KEY_OTP_ID, otp)
|
||||
putParcelableArrayList(
|
||||
AutofillScenario.BUNDLE_KEY_GENERIC_PASSWORD_IDS,
|
||||
ArrayList(genericPassword)
|
||||
ArrayList(genericPassword),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -75,7 +75,7 @@ internal interface FieldMatcher {
|
|||
@RequiresApi(Build.VERSION_CODES.O)
|
||||
internal class SingleFieldMatcher(
|
||||
private val take: (FormField, List<FormField>) -> Boolean,
|
||||
private val tieBreakers: List<(FormField, List<FormField>) -> Boolean>
|
||||
private val tieBreakers: List<(FormField, List<FormField>) -> Boolean>,
|
||||
) : FieldMatcher {
|
||||
|
||||
@AutofillDsl
|
||||
|
@ -100,7 +100,7 @@ internal class SingleFieldMatcher(
|
|||
fun build() =
|
||||
SingleFieldMatcher(
|
||||
takeSingle ?: throw IllegalArgumentException("Every block needs a take{Single,Pair} block"),
|
||||
tieBreakersSingle
|
||||
tieBreakersSingle,
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -139,7 +139,7 @@ internal class SingleFieldMatcher(
|
|||
@RequiresApi(Build.VERSION_CODES.O)
|
||||
private class PairOfFieldsMatcher(
|
||||
private val take: (Pair<FormField, FormField>, List<FormField>) -> Boolean,
|
||||
private val tieBreakers: List<(Pair<FormField, FormField>, List<FormField>) -> Boolean>
|
||||
private val tieBreakers: List<(Pair<FormField, FormField>, List<FormField>) -> Boolean>,
|
||||
) : FieldMatcher {
|
||||
|
||||
override fun match(fields: List<FormField>, alreadyMatched: List<FormField>): List<FormField>? {
|
||||
|
@ -180,14 +180,14 @@ private constructor(
|
|||
private val matchers: List<AutofillRuleMatcher>,
|
||||
private val applyInSingleOriginMode: Boolean,
|
||||
private val applyOnManualRequestOnly: Boolean,
|
||||
private val name: String
|
||||
private val name: String,
|
||||
) {
|
||||
|
||||
data class AutofillRuleMatcher(
|
||||
val type: FillableFieldType,
|
||||
val matcher: FieldMatcher,
|
||||
val optional: Boolean,
|
||||
val matchHidden: Boolean
|
||||
val matchHidden: Boolean,
|
||||
)
|
||||
|
||||
enum class FillableFieldType {
|
||||
|
@ -201,7 +201,7 @@ private constructor(
|
|||
@AutofillDsl
|
||||
class Builder(
|
||||
private val applyInSingleOriginMode: Boolean,
|
||||
private val applyOnManualRequestOnly: Boolean
|
||||
private val applyOnManualRequestOnly: Boolean,
|
||||
) {
|
||||
|
||||
companion object {
|
||||
|
@ -215,7 +215,7 @@ private constructor(
|
|||
fun username(
|
||||
optional: Boolean = false,
|
||||
matchHidden: Boolean = false,
|
||||
block: SingleFieldMatcher.Builder.() -> Unit
|
||||
block: SingleFieldMatcher.Builder.() -> Unit,
|
||||
) {
|
||||
require(matchers.none { it.type == FillableFieldType.Username }) {
|
||||
"Every rule block can only have at most one username block"
|
||||
|
@ -225,7 +225,7 @@ private constructor(
|
|||
type = FillableFieldType.Username,
|
||||
matcher = SingleFieldMatcher.Builder().apply(block).build(),
|
||||
optional = optional,
|
||||
matchHidden = matchHidden
|
||||
matchHidden = matchHidden,
|
||||
)
|
||||
)
|
||||
}
|
||||
|
@ -239,7 +239,7 @@ private constructor(
|
|||
type = FillableFieldType.Otp,
|
||||
matcher = SingleFieldMatcher.Builder().apply(block).build(),
|
||||
optional = optional,
|
||||
matchHidden = false
|
||||
matchHidden = false,
|
||||
)
|
||||
)
|
||||
}
|
||||
|
@ -247,7 +247,7 @@ private constructor(
|
|||
fun currentPassword(
|
||||
optional: Boolean = false,
|
||||
matchHidden: Boolean = false,
|
||||
block: FieldMatcher.Builder.() -> Unit
|
||||
block: FieldMatcher.Builder.() -> Unit,
|
||||
) {
|
||||
require(matchers.none { it.type == FillableFieldType.GenericPassword }) {
|
||||
"Every rule block can only have either genericPassword or {current,new}Password blocks"
|
||||
|
@ -257,7 +257,7 @@ private constructor(
|
|||
type = FillableFieldType.CurrentPassword,
|
||||
matcher = FieldMatcher.Builder().apply(block).build(),
|
||||
optional = optional,
|
||||
matchHidden = matchHidden
|
||||
matchHidden = matchHidden,
|
||||
)
|
||||
)
|
||||
}
|
||||
|
@ -271,7 +271,7 @@ private constructor(
|
|||
type = FillableFieldType.NewPassword,
|
||||
matcher = FieldMatcher.Builder().apply(block).build(),
|
||||
optional = optional,
|
||||
matchHidden = false
|
||||
matchHidden = false,
|
||||
)
|
||||
)
|
||||
}
|
||||
|
@ -279,11 +279,7 @@ private constructor(
|
|||
fun genericPassword(optional: Boolean = false, block: FieldMatcher.Builder.() -> Unit) {
|
||||
require(
|
||||
matchers.none {
|
||||
it.type in
|
||||
listOf(
|
||||
FillableFieldType.CurrentPassword,
|
||||
FillableFieldType.NewPassword,
|
||||
)
|
||||
it.type in listOf(FillableFieldType.CurrentPassword, FillableFieldType.NewPassword)
|
||||
}
|
||||
) {
|
||||
"Every rule block can only have either genericPassword or {current,new}Password blocks"
|
||||
|
@ -293,7 +289,7 @@ private constructor(
|
|||
type = FillableFieldType.GenericPassword,
|
||||
matcher = FieldMatcher.Builder().apply(block).build(),
|
||||
optional = optional,
|
||||
matchHidden = false
|
||||
matchHidden = false,
|
||||
)
|
||||
)
|
||||
}
|
||||
|
@ -314,7 +310,7 @@ private constructor(
|
|||
matchers,
|
||||
applyInSingleOriginMode,
|
||||
applyOnManualRequestOnly,
|
||||
name ?: "Rule #$ruleId"
|
||||
name ?: "Rule #$ruleId",
|
||||
)
|
||||
.also { ruleId++ }
|
||||
}
|
||||
|
@ -325,7 +321,7 @@ private constructor(
|
|||
allUsername: List<FormField>,
|
||||
allOtp: List<FormField>,
|
||||
singleOriginMode: Boolean,
|
||||
isManualRequest: Boolean
|
||||
isManualRequest: Boolean,
|
||||
): AutofillScenario<FormField>? {
|
||||
if (singleOriginMode && !applyInSingleOriginMode) {
|
||||
logcat { "$name: Skipped in single origin mode" }
|
||||
|
@ -399,12 +395,12 @@ internal class AutofillStrategy private constructor(private val rules: List<Auto
|
|||
fun rule(
|
||||
applyInSingleOriginMode: Boolean = false,
|
||||
applyOnManualRequestOnly: Boolean = false,
|
||||
block: AutofillRule.Builder.() -> Unit
|
||||
block: AutofillRule.Builder.() -> Unit,
|
||||
) {
|
||||
rules.add(
|
||||
AutofillRule.Builder(
|
||||
applyInSingleOriginMode = applyInSingleOriginMode,
|
||||
applyOnManualRequestOnly = applyOnManualRequestOnly
|
||||
applyOnManualRequestOnly = applyOnManualRequestOnly,
|
||||
)
|
||||
.apply(block)
|
||||
.build()
|
||||
|
@ -417,7 +413,7 @@ internal class AutofillStrategy private constructor(private val rules: List<Auto
|
|||
fun match(
|
||||
fields: List<FormField>,
|
||||
singleOriginMode: Boolean,
|
||||
isManualRequest: Boolean
|
||||
isManualRequest: Boolean,
|
||||
): AutofillScenario<FormField>? {
|
||||
val possiblePasswordFields = fields.filter { it.passwordCertainty >= CertaintyLevel.Possible }
|
||||
logcat { "Possible password fields: ${possiblePasswordFields.size}" }
|
||||
|
@ -433,7 +429,7 @@ internal class AutofillStrategy private constructor(private val rules: List<Auto
|
|||
possibleUsernameFields,
|
||||
possibleOtpFields,
|
||||
singleOriginMode = singleOriginMode,
|
||||
isManualRequest = isManualRequest
|
||||
isManualRequest = isManualRequest,
|
||||
) ?: continue
|
||||
}
|
||||
return null
|
||||
|
|
|
@ -59,7 +59,7 @@ private val TRUSTED_BROWSER_CERTIFICATE_HASH =
|
|||
"com.duckduckgo.mobile.android" to
|
||||
arrayOf(
|
||||
"u3uzHFc8RqHaf8XFKKas9DIQhFb+7FCBDH8zaU6z0tQ=",
|
||||
"8HB9AhwL8+b43MEbo/VwBCXVl9yjAaMeIQVWk067Gwo="
|
||||
"8HB9AhwL8+b43MEbo/VwBCXVl9yjAaMeIQVWk067Gwo=",
|
||||
),
|
||||
"com.jamal2367.styx" to arrayOf("Lph3oaG1C8WLhLiK5PVxOp5+6wTU9ipJSBYlD2bA3VI="),
|
||||
"com.microsoft.emmx" to arrayOf("AeGZlxCoLCdJtNUMRF3IXWcLYTYInQp2anOCfIKh6sk="),
|
||||
|
@ -85,7 +85,7 @@ private val TRUSTED_BROWSER_CERTIFICATE_HASH =
|
|||
"us.spotco.fennec_dos" to
|
||||
arrayOf(
|
||||
"Jg4KSWeMeLcMAtZTet07bcChcXG73oznX9QCaoo+GNI=",
|
||||
"/4H1vlY5ZZTu5w/vKDIlbhUhQSLiupzt0mAF/9S8qqg="
|
||||
"/4H1vlY5ZZTu5w/vKDIlbhUhQSLiupzt0mAF/9S8qqg=",
|
||||
),
|
||||
"com.vivaldi.browser" to arrayOf("6KeFRGVbqMCYF/cydo9WibFmLsSyvFoLwOwTjTPKPR4="),
|
||||
"app.vanadium.browser" to arrayOf("xq24uDxtTBfSkq/eVv1IilHTFv+PLBHFQQIjv/in27M="),
|
||||
|
@ -100,7 +100,7 @@ private fun isTrustedBrowser(context: Context, appPackage: String): Boolean {
|
|||
internal enum class BrowserMultiOriginMethod {
|
||||
None,
|
||||
WebView,
|
||||
Field
|
||||
Field,
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -173,7 +173,7 @@ private fun isNoAccessibilityServiceEnabled(context: Context): Boolean {
|
|||
// See https://chromium.googlesource.com/chromium/src/+/447a31e977a65e2eb78804e4a09633699b4ede33
|
||||
return Settings.Secure.getString(
|
||||
context.contentResolver,
|
||||
Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES
|
||||
Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
|
||||
)
|
||||
.isNullOrEmpty()
|
||||
}
|
||||
|
@ -187,25 +187,22 @@ private fun getBrowserSaveFlag(context: Context, appPackage: String): Int? =
|
|||
|
||||
internal data class BrowserAutofillSupportInfo(
|
||||
val multiOriginMethod: BrowserMultiOriginMethod,
|
||||
val saveFlags: Int?
|
||||
val saveFlags: Int?,
|
||||
)
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.O)
|
||||
internal fun getBrowserAutofillSupportInfoIfTrusted(
|
||||
context: Context,
|
||||
appPackage: String
|
||||
appPackage: String,
|
||||
): BrowserAutofillSupportInfo? {
|
||||
if (!isTrustedBrowser(context, appPackage)) return null
|
||||
return BrowserAutofillSupportInfo(
|
||||
multiOriginMethod = getBrowserMultiOriginMethod(appPackage),
|
||||
saveFlags = getBrowserSaveFlag(context, appPackage)
|
||||
saveFlags = getBrowserSaveFlag(context, appPackage),
|
||||
)
|
||||
}
|
||||
|
||||
private val FLAKY_BROWSERS =
|
||||
listOf(
|
||||
"com.kiwibrowser.browser",
|
||||
)
|
||||
private val FLAKY_BROWSERS = listOf("com.kiwibrowser.browser")
|
||||
|
||||
public enum class BrowserAutofillSupportLevel {
|
||||
None,
|
||||
|
@ -219,7 +216,7 @@ public enum class BrowserAutofillSupportLevel {
|
|||
@RequiresApi(Build.VERSION_CODES.O)
|
||||
private fun getBrowserAutofillSupportLevel(
|
||||
context: Context,
|
||||
appPackage: String
|
||||
appPackage: String,
|
||||
): BrowserAutofillSupportLevel {
|
||||
val browserInfo = getBrowserAutofillSupportInfoIfTrusted(context, appPackage)
|
||||
return when {
|
||||
|
@ -252,7 +249,7 @@ public fun getInstalledBrowsersWithAutofillSupportLevel(
|
|||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
context.packageManager.queryIntentActivities(
|
||||
testWebIntent,
|
||||
ResolveInfoFlags.of(PackageManager.MATCH_ALL.toLong())
|
||||
ResolveInfoFlags.of(PackageManager.MATCH_ALL.toLong()),
|
||||
)
|
||||
} else {
|
||||
context.packageManager.queryIntentActivities(testWebIntent, PackageManager.MATCH_ALL)
|
||||
|
|
|
@ -17,7 +17,7 @@ internal enum class CertaintyLevel {
|
|||
Impossible,
|
||||
Possible,
|
||||
Likely,
|
||||
Certain
|
||||
Certain,
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -29,31 +29,19 @@ internal class FormField(
|
|||
node: AssistStructure.ViewNode,
|
||||
private val index: Int,
|
||||
passDownWebViewOrigins: Boolean,
|
||||
passedDownWebOrigin: String? = null
|
||||
passedDownWebOrigin: String? = null,
|
||||
) {
|
||||
|
||||
companion object {
|
||||
|
||||
private val HINTS_USERNAME =
|
||||
listOf(
|
||||
HintConstants.AUTOFILL_HINT_USERNAME,
|
||||
HintConstants.AUTOFILL_HINT_NEW_USERNAME,
|
||||
)
|
||||
private val HINTS_NEW_PASSWORD =
|
||||
listOf(
|
||||
HintConstants.AUTOFILL_HINT_NEW_PASSWORD,
|
||||
)
|
||||
listOf(HintConstants.AUTOFILL_HINT_USERNAME, HintConstants.AUTOFILL_HINT_NEW_USERNAME)
|
||||
private val HINTS_NEW_PASSWORD = listOf(HintConstants.AUTOFILL_HINT_NEW_PASSWORD)
|
||||
private val HINTS_PASSWORD =
|
||||
HINTS_NEW_PASSWORD +
|
||||
listOf(
|
||||
HintConstants.AUTOFILL_HINT_PASSWORD,
|
||||
HintConstants.AUTOFILL_HINT_WIFI_PASSWORD,
|
||||
)
|
||||
listOf(HintConstants.AUTOFILL_HINT_PASSWORD, HintConstants.AUTOFILL_HINT_WIFI_PASSWORD)
|
||||
private val HINTS_OTP =
|
||||
listOf(
|
||||
HintConstants.AUTOFILL_HINT_SMS_OTP,
|
||||
HintConstants.AUTOFILL_HINT_2FA_APP_OTP,
|
||||
)
|
||||
listOf(HintConstants.AUTOFILL_HINT_SMS_OTP, HintConstants.AUTOFILL_HINT_2FA_APP_OTP)
|
||||
|
||||
@Suppress("DEPRECATION")
|
||||
private val HINTS_FILLABLE =
|
||||
|
@ -93,21 +81,9 @@ internal class FormField(
|
|||
}
|
||||
}
|
||||
|
||||
private val HTML_INPUT_FIELD_TYPES_USERNAME =
|
||||
listOf(
|
||||
"email",
|
||||
"tel",
|
||||
"text",
|
||||
)
|
||||
private val HTML_INPUT_FIELD_TYPES_PASSWORD =
|
||||
listOf(
|
||||
"password",
|
||||
)
|
||||
private val HTML_INPUT_FIELD_TYPES_OTP =
|
||||
listOf(
|
||||
"tel",
|
||||
"text",
|
||||
)
|
||||
private val HTML_INPUT_FIELD_TYPES_USERNAME = listOf("email", "tel", "text")
|
||||
private val HTML_INPUT_FIELD_TYPES_PASSWORD = listOf("password")
|
||||
private val HTML_INPUT_FIELD_TYPES_OTP = listOf("tel", "text")
|
||||
private val HTML_INPUT_FIELD_TYPES_FILLABLE =
|
||||
(HTML_INPUT_FIELD_TYPES_USERNAME +
|
||||
HTML_INPUT_FIELD_TYPES_PASSWORD +
|
||||
|
@ -128,33 +104,11 @@ internal class FormField(
|
|||
"captcha",
|
||||
"postal", // Prevent postal code fields from being mistaken for OTP fields
|
||||
)
|
||||
private val PASSWORD_HEURISTIC_TERMS =
|
||||
listOf(
|
||||
"pass",
|
||||
"pswd",
|
||||
"pwd",
|
||||
)
|
||||
private val PASSWORD_HEURISTIC_TERMS = listOf("pass", "pswd", "pwd")
|
||||
private val USERNAME_HEURISTIC_TERMS =
|
||||
listOf(
|
||||
"alias",
|
||||
"benutzername",
|
||||
"e-mail",
|
||||
"email",
|
||||
"mail",
|
||||
"login",
|
||||
"user",
|
||||
)
|
||||
private val OTP_HEURISTIC_TERMS =
|
||||
listOf(
|
||||
"einmal",
|
||||
"otp",
|
||||
"challenge",
|
||||
"verification",
|
||||
)
|
||||
private val OTP_WEAK_HEURISTIC_TERMS =
|
||||
listOf(
|
||||
"code",
|
||||
)
|
||||
listOf("alias", "benutzername", "e-mail", "email", "mail", "login", "user")
|
||||
private val OTP_HEURISTIC_TERMS = listOf("einmal", "otp", "challenge", "verification")
|
||||
private val OTP_WEAK_HEURISTIC_TERMS = listOf("code")
|
||||
}
|
||||
|
||||
private val List<String>.anyMatchesFieldInfo
|
||||
|
|
|
@ -39,7 +39,7 @@ public fun cachePublicSuffixList(context: Context) {
|
|||
internal fun getPublicSuffixPlusOne(
|
||||
context: Context,
|
||||
domain: String,
|
||||
customSuffixes: Sequence<String>
|
||||
customSuffixes: Sequence<String>,
|
||||
) = runBlocking {
|
||||
// We only feed valid domain names which are not IP addresses into getPublicSuffixPlusOne.
|
||||
// We do not check whether the domain actually exists (actually, not even whether its TLD
|
||||
|
@ -77,7 +77,7 @@ private fun getSuffixPlusUpToOne(domain: String, suffix: String): String? {
|
|||
private suspend fun getCanonicalSuffix(
|
||||
context: Context,
|
||||
domain: String,
|
||||
customSuffixes: Sequence<String>
|
||||
customSuffixes: Sequence<String>,
|
||||
): String {
|
||||
val publicSuffixList = PublicSuffixListCache.getOrCachePublicSuffixList(context)
|
||||
val publicSuffixPlusOne =
|
||||
|
|
|
@ -29,7 +29,7 @@ import kotlinx.coroutines.async
|
|||
internal class PublicSuffixList(
|
||||
context: Context,
|
||||
dispatcher: CoroutineDispatcher = Dispatchers.IO,
|
||||
private val scope: CoroutineScope = CoroutineScope(dispatcher)
|
||||
private val scope: CoroutineScope = CoroutineScope(dispatcher),
|
||||
) {
|
||||
|
||||
private val data: PublicSuffixListData by
|
||||
|
|
|
@ -14,7 +14,7 @@ import mozilla.components.lib.publicsuffixlist.ext.binarySearch
|
|||
/** Class wrapping the public suffix list data and offering methods for accessing rules in it. */
|
||||
internal class PublicSuffixListData(
|
||||
private val rules: ByteArray,
|
||||
private val exceptions: ByteArray
|
||||
private val exceptions: ByteArray,
|
||||
) {
|
||||
|
||||
private fun binarySearchRules(labels: List<ByteArray>, labelIndex: Int): String? {
|
||||
|
|
|
@ -41,10 +41,7 @@ class KotlinCommonPlugin : Plugin<Project> {
|
|||
|
||||
companion object {
|
||||
private val ADDITIONAL_COMPILER_ARGS =
|
||||
listOf(
|
||||
"-opt-in=kotlin.RequiresOptIn",
|
||||
"-Xsuppress-version-warnings",
|
||||
)
|
||||
listOf("-opt-in=kotlin.RequiresOptIn", "-Xsuppress-version-warnings")
|
||||
|
||||
val JVM_TOOLCHAIN_ACTION =
|
||||
Action<JavaToolchainSpec> { languageVersion.set(JavaLanguageVersion.of(17)) }
|
||||
|
|
|
@ -62,10 +62,7 @@ class CrowdinDownloadPlugin : Plugin<Project> {
|
|||
if (extension.skipCleanup.getOrElse(false)) {
|
||||
emptySet()
|
||||
} else {
|
||||
setOf(
|
||||
extractStrings.map { it.source },
|
||||
downloadCrowdin.map { it.outputFiles },
|
||||
)
|
||||
setOf(extractStrings.map { it.source }, downloadCrowdin.map { it.outputFiles })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -57,7 +57,7 @@ abstract class KtfmtCheckTask : SourceTask() {
|
|||
maxWidth = 100,
|
||||
continuationIndent = 2,
|
||||
),
|
||||
originCode
|
||||
originCode,
|
||||
)
|
||||
val pathNormalizer = { file: File -> file.toRelativeString(projectDirectory.asFile.get()) }
|
||||
return (originCode != formattedCode) to
|
||||
|
|
|
@ -10,7 +10,7 @@ object KtfmtDiffer {
|
|||
fun computeDiff(
|
||||
inputFile: File,
|
||||
formattedCode: String,
|
||||
pathNormalizer: (File) -> String
|
||||
pathNormalizer: (File) -> String,
|
||||
): List<KtfmtDiffEntry> {
|
||||
val originCode = inputFile.readText()
|
||||
return DiffUtils.diff(originCode, formattedCode, null).deltas.map {
|
||||
|
|
|
@ -11,10 +11,8 @@ import org.jetbrains.kotlin.utils.addToStdlib.ifNotEmpty
|
|||
|
||||
abstract class KtfmtFormatTask
|
||||
@Inject
|
||||
constructor(
|
||||
private val workerExecutor: WorkerExecutor,
|
||||
private val projectLayout: ProjectLayout,
|
||||
) : SourceTask() {
|
||||
constructor(private val workerExecutor: WorkerExecutor, private val projectLayout: ProjectLayout) :
|
||||
SourceTask() {
|
||||
|
||||
@TaskAction
|
||||
fun execute() {
|
||||
|
|
|
@ -104,7 +104,7 @@ abstract class PSLUpdateTask : DefaultTask() {
|
|||
var totalRuleBytes: Int = 0,
|
||||
var totalExceptionRuleBytes: Int = 0,
|
||||
val sortedRules: TreeSet<ByteString> = TreeSet(),
|
||||
val sortedExceptionRules: TreeSet<ByteString> = TreeSet()
|
||||
val sortedExceptionRules: TreeSet<ByteString> = TreeSet(),
|
||||
)
|
||||
|
||||
private companion object {
|
||||
|
|
|
@ -48,7 +48,7 @@ abstract class GitHooks : DefaultTask() {
|
|||
GROUP_EXECUTE,
|
||||
OTHERS_READ,
|
||||
OTHERS_EXECUTE,
|
||||
)
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,8 @@
|
|||
package app.passwordstore.crypto
|
||||
|
||||
/** [CryptoOptions] implementation for PGPainless decrypt operations. */
|
||||
public class PGPDecryptOptions
|
||||
private constructor(
|
||||
private val values: Map<String, Boolean>,
|
||||
) : CryptoOptions {
|
||||
public class PGPDecryptOptions private constructor(private val values: Map<String, Boolean>) :
|
||||
CryptoOptions {
|
||||
|
||||
override fun isOptionEnabled(option: String): Boolean {
|
||||
return values.getOrDefault(option, false)
|
||||
|
|
|
@ -1,10 +1,8 @@
|
|||
package app.passwordstore.crypto
|
||||
|
||||
/** [CryptoOptions] implementation for PGPainless encrypt operations. */
|
||||
public class PGPEncryptOptions
|
||||
private constructor(
|
||||
private val values: Map<String, Boolean>,
|
||||
) : CryptoOptions {
|
||||
public class PGPEncryptOptions private constructor(private val values: Map<String, Boolean>) :
|
||||
CryptoOptions {
|
||||
|
||||
internal companion object {
|
||||
const val ASCII_ARMOR = "ASCII_ARMOR"
|
||||
|
|
|
@ -31,10 +31,8 @@ import org.pgpainless.util.selection.userid.SelectUserId
|
|||
|
||||
public class PGPKeyManager
|
||||
@Inject
|
||||
constructor(
|
||||
filesDir: String,
|
||||
private val dispatcher: CoroutineDispatcher,
|
||||
) : KeyManager<PGPKey, PGPIdentifier> {
|
||||
constructor(filesDir: String, private val dispatcher: CoroutineDispatcher) :
|
||||
KeyManager<PGPKey, PGPIdentifier> {
|
||||
|
||||
private val keyDir = File(filesDir, KEY_DIR_NAME)
|
||||
|
||||
|
|
|
@ -217,10 +217,7 @@ class PGPKeyManagerTest {
|
|||
KeyId(-961222705095032109), // Bobby
|
||||
)
|
||||
val userIds =
|
||||
arrayOf(
|
||||
UserId("Alice <owner@example.com>"),
|
||||
UserId("Bobby <owner@example.com>"),
|
||||
)
|
||||
arrayOf(UserId("Alice <owner@example.com>"), UserId("Bobby <owner@example.com>"))
|
||||
|
||||
for (idCollection in arrayOf(longKeyIds, userIds)) {
|
||||
val alice1 = keyManager.getKeyById(idCollection[0])
|
||||
|
|
|
@ -205,7 +205,7 @@ constructor(
|
|||
millis / (THOUSAND_MILLIS * totpPeriod),
|
||||
totpAlgorithm,
|
||||
digits,
|
||||
issuer
|
||||
issuer,
|
||||
)
|
||||
.mapBoth({ code -> Ok(Totp(code, remainingTime)) }, ::Err)
|
||||
}
|
||||
|
@ -233,12 +233,7 @@ constructor(
|
|||
"identity:",
|
||||
)
|
||||
@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
|
||||
public val PASSWORD_FIELDS: Array<String> =
|
||||
arrayOf(
|
||||
"password:",
|
||||
"secret:",
|
||||
"pass:",
|
||||
)
|
||||
public val PASSWORD_FIELDS: Array<String> = arrayOf("password:", "secret:", "pass:")
|
||||
private const val THOUSAND_MILLIS = 1000L
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,11 +26,7 @@ class PasswordEntryTest {
|
|||
private val totpFinder = UriTotpFinder()
|
||||
|
||||
private fun makeEntry(content: String, clock: UserClock = fakeClock) =
|
||||
PasswordEntry(
|
||||
clock,
|
||||
totpFinder,
|
||||
content.encodeToByteArray(),
|
||||
)
|
||||
PasswordEntry(clock, totpFinder, content.encodeToByteArray())
|
||||
|
||||
@Test
|
||||
fun getPassword() {
|
||||
|
@ -62,7 +58,7 @@ class PasswordEntryTest {
|
|||
assertEquals("blubb", makeEntry("password: foo\nblubb").extraContentString)
|
||||
assertEquals(
|
||||
"blubb\nusername: bar",
|
||||
makeEntry("blubb\npassword: foo\nusername: bar").extraContentString
|
||||
makeEntry("blubb\npassword: foo\nusername: bar").extraContentString,
|
||||
)
|
||||
assertEquals("", makeEntry("\n").extraContentString)
|
||||
assertEquals("", makeEntry("").extraContentString)
|
||||
|
@ -107,7 +103,7 @@ class PasswordEntryTest {
|
|||
assertEquals("username", makeEntry("\n$field username").username)
|
||||
assertEquals(
|
||||
"username",
|
||||
makeEntry("\n${field.uppercase(Locale.getDefault())} username").username
|
||||
makeEntry("\n${field.uppercase(Locale.getDefault())} username").username,
|
||||
)
|
||||
}
|
||||
assertEquals("username", makeEntry("secret\nextra\nlogin: username\ncontent\n").username)
|
||||
|
|
|
@ -25,103 +25,36 @@ class OtpTest {
|
|||
|
||||
@Test
|
||||
fun otpGeneration6Digits() {
|
||||
assertEquals(
|
||||
"953550",
|
||||
generateOtp(
|
||||
counter = 1593333298159 / (1000 * 30),
|
||||
)
|
||||
)
|
||||
assertEquals(
|
||||
"275379",
|
||||
generateOtp(
|
||||
counter = 1593333571918 / (1000 * 30),
|
||||
)
|
||||
)
|
||||
assertEquals(
|
||||
"867507",
|
||||
generateOtp(
|
||||
counter = 1593333600517 / (1000 * 57),
|
||||
)
|
||||
)
|
||||
assertEquals("953550", generateOtp(counter = 1593333298159 / (1000 * 30)))
|
||||
assertEquals("275379", generateOtp(counter = 1593333571918 / (1000 * 30)))
|
||||
assertEquals("867507", generateOtp(counter = 1593333600517 / (1000 * 57)))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun otpGeneration10Digits() {
|
||||
assertEquals(
|
||||
"0740900914",
|
||||
generateOtp(
|
||||
counter = 1593333655044 / (1000 * 30),
|
||||
digits = "10",
|
||||
)
|
||||
)
|
||||
assertEquals(
|
||||
"0070632029",
|
||||
generateOtp(
|
||||
counter = 1593333691405 / (1000 * 30),
|
||||
digits = "10",
|
||||
)
|
||||
)
|
||||
assertEquals(
|
||||
"1017265882",
|
||||
generateOtp(
|
||||
counter = 1593333728893 / (1000 * 83),
|
||||
digits = "10",
|
||||
)
|
||||
)
|
||||
assertEquals("0740900914", generateOtp(counter = 1593333655044 / (1000 * 30), digits = "10"))
|
||||
assertEquals("0070632029", generateOtp(counter = 1593333691405 / (1000 * 30), digits = "10"))
|
||||
assertEquals("1017265882", generateOtp(counter = 1593333728893 / (1000 * 83), digits = "10"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun otpGenerationIllegalInput() {
|
||||
assertNull(
|
||||
generateOtp(
|
||||
counter = 10000,
|
||||
algorithm = "SHA0",
|
||||
digits = "10",
|
||||
)
|
||||
)
|
||||
assertNull(
|
||||
generateOtp(
|
||||
counter = 10000,
|
||||
digits = "a",
|
||||
)
|
||||
)
|
||||
assertNull(
|
||||
generateOtp(
|
||||
counter = 10000,
|
||||
algorithm = "SHA1",
|
||||
digits = "5",
|
||||
)
|
||||
)
|
||||
assertNull(
|
||||
generateOtp(
|
||||
counter = 10000,
|
||||
digits = "11",
|
||||
)
|
||||
)
|
||||
assertNull(
|
||||
generateOtp(
|
||||
counter = 10000,
|
||||
secret = "JBSWY3DPEHPK3PXPAAAAB",
|
||||
digits = "6",
|
||||
)
|
||||
)
|
||||
assertNull(generateOtp(counter = 10000, algorithm = "SHA0", digits = "10"))
|
||||
assertNull(generateOtp(counter = 10000, digits = "a"))
|
||||
assertNull(generateOtp(counter = 10000, algorithm = "SHA1", digits = "5"))
|
||||
assertNull(generateOtp(counter = 10000, digits = "11"))
|
||||
assertNull(generateOtp(counter = 10000, secret = "JBSWY3DPEHPK3PXPAAAAB", digits = "6"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun otpGenerationUnusualSecrets() {
|
||||
assertEquals(
|
||||
"127764",
|
||||
generateOtp(
|
||||
counter = 1593367111963 / (1000 * 30),
|
||||
secret = "JBSWY3DPEHPK3PXPAAAAAAAA",
|
||||
)
|
||||
generateOtp(counter = 1593367111963 / (1000 * 30), secret = "JBSWY3DPEHPK3PXPAAAAAAAA"),
|
||||
)
|
||||
assertEquals(
|
||||
"047515",
|
||||
generateOtp(
|
||||
counter = 1593367171420 / (1000 * 30),
|
||||
secret = "JBSWY3DPEHPK3PXPAAAAA",
|
||||
)
|
||||
generateOtp(counter = 1593367171420 / (1000 * 30), secret = "JBSWY3DPEHPK3PXPAAAAA"),
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@ class UriTotpFinderTest {
|
|||
assertEquals("HXDMVJECJJWSRB3HWIZR4IFUGFTMXBOZ", totpFinder.findSecret(TOTP_URI))
|
||||
assertEquals(
|
||||
"HXDMVJECJJWSRB3HWIZR4IFUGFTMXBOZ",
|
||||
totpFinder.findSecret("name\npassword\ntotp: HXDMVJECJJWSRB3HWIZR4IFUGFTMXBOZ")
|
||||
totpFinder.findSecret("name\npassword\ntotp: HXDMVJECJJWSRB3HWIZR4IFUGFTMXBOZ"),
|
||||
)
|
||||
assertEquals("HXDMVJECJJWSRB3HWIZR4IFUGFTMXBOZ", totpFinder.findSecret(PASS_FILE_CONTENT))
|
||||
}
|
||||
|
|
|
@ -14,10 +14,7 @@ import javax.inject.Inject
|
|||
*/
|
||||
public class DicewarePassphraseGenerator
|
||||
@Inject
|
||||
constructor(
|
||||
private val die: Die,
|
||||
wordList: InputStream,
|
||||
) {
|
||||
constructor(private val die: Die, wordList: InputStream) {
|
||||
|
||||
private val wordMap = WordListParser.parse(wordList)
|
||||
|
||||
|
|
|
@ -10,10 +10,7 @@ import javax.inject.Inject
|
|||
/** Basic implementation of a die with configurable number of sides. */
|
||||
public class Die
|
||||
@Inject
|
||||
constructor(
|
||||
private val sides: Int,
|
||||
private val random: RandomIntGenerator,
|
||||
) {
|
||||
constructor(private val sides: Int, private val random: RandomIntGenerator) {
|
||||
|
||||
/** Roll the die to return a single number. */
|
||||
public fun roll(): Int {
|
||||
|
|
|
@ -19,11 +19,7 @@ class DicewarePassphraseGeneratorTest {
|
|||
fun generatePassphrase() {
|
||||
val die = Die(6, intGenerator)
|
||||
|
||||
val generator =
|
||||
DicewarePassphraseGenerator(
|
||||
die,
|
||||
WordListParserTest.getDefaultWordList(),
|
||||
)
|
||||
val generator = DicewarePassphraseGenerator(die, WordListParserTest.getDefaultWordList())
|
||||
|
||||
assertEquals("salvation_cozily_croon_trustee_fidgety", generator.generatePassphrase(5, '_'))
|
||||
}
|
||||
|
|
|
@ -6,5 +6,5 @@ public enum class PasswordOption(public val key: String) {
|
|||
NoAmbiguousCharacters("B"),
|
||||
FullyRandom("s"),
|
||||
AtLeastOneSymbol("y"),
|
||||
NoLowercaseLetters("L")
|
||||
NoLowercaseLetters("L"),
|
||||
}
|
||||
|
|
|
@ -55,7 +55,7 @@ internal object RandomPhonemesGenerator {
|
|||
Element("w", CONSONANT),
|
||||
Element("x", CONSONANT),
|
||||
Element("y", CONSONANT),
|
||||
Element("z", CONSONANT)
|
||||
Element("z", CONSONANT),
|
||||
)
|
||||
|
||||
private class Element(str: String, val flags: Int) {
|
||||
|
|
|
@ -39,10 +39,7 @@ public fun APSAppBar(
|
|||
navigationIcon = {
|
||||
if (navigationIcon != null) {
|
||||
IconButton(onClick = { onNavigationIconClick.invoke() }) {
|
||||
Icon(
|
||||
painter = navigationIcon,
|
||||
contentDescription = null,
|
||||
)
|
||||
Icon(painter = navigationIcon, contentDescription = null)
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -68,7 +65,7 @@ private fun APSAppBarPreview() {
|
|||
contentDescription = "Search items",
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -56,10 +56,7 @@ private fun ToggleButton(
|
|||
val icon =
|
||||
if (visible) painterResource(id = R.drawable.baseline_visibility_off_24)
|
||||
else painterResource(id = R.drawable.baseline_visibility_24)
|
||||
Icon(
|
||||
painter = icon,
|
||||
contentDescription = contentDescription,
|
||||
)
|
||||
Icon(painter = icon, contentDescription = contentDescription)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -70,10 +67,7 @@ public fun CopyButton(
|
|||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
val clipboard = LocalClipboardManager.current
|
||||
IconButton(
|
||||
onClick = { clipboard.setText(AnnotatedString(textToCopy)) },
|
||||
modifier = modifier,
|
||||
) {
|
||||
IconButton(onClick = { clipboard.setText(AnnotatedString(textToCopy)) }, modifier = modifier) {
|
||||
Icon(
|
||||
painter = painterResource(R.drawable.ic_content_copy),
|
||||
contentDescription = stringResource(buttonLabelRes),
|
||||
|
|
|
@ -34,7 +34,7 @@ public fun PasswordItem(
|
|||
label: String,
|
||||
type: ItemType,
|
||||
onClick: () -> Unit,
|
||||
modifier: Modifier = Modifier
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
Row(
|
||||
modifier =
|
||||
|
|
Loading…
Reference in a new issue