chore: reformat with trailing commas changes

This commit is contained in:
Harsh Shandilya 2024-05-28 15:11:50 +05:30
parent de6cdfee0e
commit c980c898de
100 changed files with 309 additions and 563 deletions

View file

@ -77,11 +77,6 @@ constructor(
.withAsciiArmor(settings.getBoolean(PreferenceKeys.ASCII_ARMOR, false)) .withAsciiArmor(settings.getBoolean(PreferenceKeys.ASCII_ARMOR, false))
.build() .build()
val keys = identities.map { id -> pgpKeyManager.getKeyById(id) }.filterValues() val keys = identities.map { id -> pgpKeyManager.getKeyById(id) }.filterValues()
return pgpCryptoHandler.encrypt( return pgpCryptoHandler.encrypt(keys, content, out, encryptionOptions)
keys,
content,
out,
encryptionOptions,
)
} }
} }

View file

@ -11,35 +11,21 @@ import javax.inject.Inject
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
/** Implements a rudimentary [EncryptedSharedPreferences]-backed cache for GPG passphrases. */ /** Implements a rudimentary [EncryptedSharedPreferences]-backed cache for GPG passphrases. */
class PGPPassphraseCache class PGPPassphraseCache @Inject constructor(private val dispatcherProvider: DispatcherProvider) {
@Inject
constructor(
private val dispatcherProvider: DispatcherProvider,
) {
suspend fun cachePassphrase( suspend fun cachePassphrase(context: Context, identifier: PGPIdentifier, passphrase: String) {
context: Context,
identifier: PGPIdentifier,
passphrase: String,
) {
withContext(dispatcherProvider.io()) { withContext(dispatcherProvider.io()) {
getPreferences(context).edit { putString(identifier.toString(), passphrase) } getPreferences(context).edit { putString(identifier.toString(), passphrase) }
} }
} }
suspend fun retrieveCachedPassphrase( suspend fun retrieveCachedPassphrase(context: Context, identifier: PGPIdentifier): String? {
context: Context,
identifier: PGPIdentifier,
): String? {
return withContext(dispatcherProvider.io()) { return withContext(dispatcherProvider.io()) {
getPreferences(context).getString(identifier.toString()) getPreferences(context).getString(identifier.toString())
} }
} }
suspend fun clearCachedPassphrase( suspend fun clearCachedPassphrase(context: Context, identifier: PGPIdentifier) {
context: Context,
identifier: PGPIdentifier,
) {
withContext(dispatcherProvider.io()) { withContext(dispatcherProvider.io()) {
getPreferences(context).edit { remove(identifier.toString()) } getPreferences(context).edit { remove(identifier.toString()) }
} }

View file

@ -10,7 +10,7 @@ import app.passwordstore.data.passfile.Totp
class FieldItem(val key: String, val value: String, val action: ActionType) { class FieldItem(val key: String, val value: String, val action: ActionType) {
enum class ActionType { enum class ActionType {
COPY, COPY,
HIDE HIDE,
} }
enum class ItemType(val type: String, val label: String) { enum class ItemType(val type: String, val label: String) {

View file

@ -16,7 +16,7 @@ data class PasswordItem(
val parent: PasswordItem? = null, val parent: PasswordItem? = null,
val type: Char, val type: Char,
val file: File, val file: File,
val rootDir: File val rootDir: File,
) : Comparable<PasswordItem> { ) : Comparable<PasswordItem> {
val fullPathToParent = file.absolutePath.replace(rootDir.absolutePath, "").replace(file.name, "") val fullPathToParent = file.absolutePath.replace(rootDir.absolutePath, "").replace(file.name, "")

View file

@ -167,7 +167,7 @@ object PasswordRepository {
fun getPasswords( fun getPasswords(
path: File, path: File,
rootDir: File, rootDir: File,
sortOrder: PasswordSortOrder sortOrder: PasswordSortOrder,
): ArrayList<PasswordItem> { ): ArrayList<PasswordItem> {
// We need to recover the passwords then parse the files // We need to recover the passwords then parse the files
val passList = getFilesList(path).also { it.sortBy { f -> f.name } } val passList = getFilesList(path).also { it.sortBy { f -> f.name } }

View file

@ -23,10 +23,7 @@ object KeyManagerModule {
@PGPKeyDir keyDir: String, @PGPKeyDir keyDir: String,
dispatcherProvider: DispatcherProvider, dispatcherProvider: DispatcherProvider,
): PGPKeyManager { ): PGPKeyManager {
return PGPKeyManager( return PGPKeyManager(keyDir, dispatcherProvider.io())
keyDir,
dispatcherProvider.io(),
)
} }
@Provides @Provides

View file

@ -25,7 +25,7 @@ class PreferenceModule {
fileName, fileName,
masterKeyAlias, masterKeyAlias,
EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV, EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM,
) )
} }

View file

@ -32,9 +32,7 @@ object DicewareModule {
} }
@Provides @Provides
fun provideDie( fun provideDie(intGenerator: RandomIntGenerator): Die {
intGenerator: RandomIntGenerator,
): Die {
return Die(6, intGenerator) return Die(6, intGenerator)
} }

View file

@ -113,7 +113,7 @@ class AutofillDecryptActivity : BasePGPActivity() {
val cachedPassphrase = val cachedPassphrase =
passphraseCache.retrieveCachedPassphrase( passphraseCache.retrieveCachedPassphrase(
this@AutofillDecryptActivity, this@AutofillDecryptActivity,
gpgIdentifiers.first() gpgIdentifiers.first(),
) )
if (cachedPassphrase != null) { if (cachedPassphrase != null) {
decryptWithPassphrase( decryptWithPassphrase(
@ -121,7 +121,7 @@ class AutofillDecryptActivity : BasePGPActivity() {
gpgIdentifiers, gpgIdentifiers,
clientState, clientState,
action, action,
cachedPassphrase cachedPassphrase,
) )
} else { } else {
askPassphrase(filePath, gpgIdentifiers, clientState, action) askPassphrase(filePath, gpgIdentifiers, clientState, action)
@ -169,12 +169,12 @@ class AutofillDecryptActivity : BasePGPActivity() {
this@AutofillDecryptActivity, this@AutofillDecryptActivity,
credentials, credentials,
clientState, clientState,
action action,
) )
withContext(dispatcherProvider.main()) { withContext(dispatcherProvider.main()) {
setResult( setResult(
RESULT_OK, 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 { runCatching {
withContext(dispatcherProvider.io()) { withContext(dispatcherProvider.io()) {
val outputStream = ByteArrayOutputStream() val outputStream = ByteArrayOutputStream()
repository.decrypt( repository.decrypt(password, identifiers, encryptedInput, outputStream)
password,
identifiers,
encryptedInput,
outputStream,
)
outputStream outputStream
} }
} }

View file

@ -61,7 +61,7 @@ class AutofillFilterView : AppCompatActivity() {
fun makeMatchAndDecryptFileIntentSender( fun makeMatchAndDecryptFileIntentSender(
context: Context, context: Context,
formOrigin: FormOrigin formOrigin: FormOrigin,
): IntentSender { ): IntentSender {
val intent = val intent =
Intent(context, AutofillFilterView::class.java).apply { Intent(context, AutofillFilterView::class.java).apply {
@ -193,7 +193,7 @@ class AutofillFilterView : AppCompatActivity() {
shouldMatch.text = shouldMatch.text =
getString( getString(
R.string.oreo_autofill_match_with, R.string.oreo_autofill_match_with,
formOrigin.getPrettyIdentifier(applicationContext) formOrigin.getPrettyIdentifier(applicationContext),
) )
lifecycleScope.launch { handleSearchResults() } lifecycleScope.launch { handleSearchResults() }
} }
@ -222,7 +222,7 @@ class AutofillFilterView : AppCompatActivity() {
filterMode = filterMode =
if (binding.strictDomainSearch.isChecked) FilterMode.StrictDomain else FilterMode.Fuzzy, if (binding.strictDomainSearch.isChecked) FilterMode.StrictDomain else FilterMode.Fuzzy,
searchMode = SearchMode.RecursivelyInSubdirectories, searchMode = SearchMode.RecursivelyInSubdirectories,
listMode = ListMode.FilesOnly listMode = ListMode.FilesOnly,
) )
} }

View file

@ -92,17 +92,17 @@ class AutofillPublisherChangedActivity : AppCompatActivity() {
resetButton.setOnClickListener { resetButton.setOnClickListener {
AutofillMatcher.clearMatchesFor( AutofillMatcher.clearMatchesFor(
this@AutofillPublisherChangedActivity, this@AutofillPublisherChangedActivity,
FormOrigin.App(appPackage) FormOrigin.App(appPackage),
) )
val fillResponse = val fillResponse =
IntentCompat.getParcelableExtra( IntentCompat.getParcelableExtra(
intent, intent,
EXTRA_FILL_RESPONSE_AFTER_RESET, EXTRA_FILL_RESPONSE_AFTER_RESET,
FillResponse::class.java FillResponse::class.java,
) )
setResult( setResult(
RESULT_OK, RESULT_OK,
Intent().apply { putExtra(AutofillManager.EXTRA_AUTHENTICATION_RESULT, fillResponse) } Intent().apply { putExtra(AutofillManager.EXTRA_AUTHENTICATION_RESULT, fillResponse) },
) )
finish() finish()
} }
@ -122,7 +122,7 @@ class AutofillPublisherChangedActivity : AppCompatActivity() {
warningAppName.text = warningAppName.text =
getString( getString(
R.string.oreo_autofill_warning_publisher_app_name, R.string.oreo_autofill_warning_publisher_app_name,
packageManager.getApplicationLabel(appInfo) packageManager.getApplicationLabel(appInfo),
) )
val currentHash = val currentHash =
@ -131,7 +131,7 @@ class AutofillPublisherChangedActivity : AppCompatActivity() {
getString( getString(
R.string.oreo_autofill_warning_publisher_advanced_info_template, R.string.oreo_autofill_warning_publisher_advanced_info_template,
appPackage, appPackage,
currentHash currentHash,
) )
} }
} }

View file

@ -47,7 +47,7 @@ class AutofillSaveActivity : AppCompatActivity() {
fun makeSaveIntentSender( fun makeSaveIntentSender(
context: Context, context: Context,
credentials: Credentials?, credentials: Credentials?,
formOrigin: FormOrigin formOrigin: FormOrigin,
): IntentSender { ): IntentSender {
val identifier = formOrigin.getPrettyIdentifier(context, untrusted = false) val identifier = formOrigin.getPrettyIdentifier(context, untrusted = false)
// Prevent directory traversals // Prevent directory traversals
@ -58,12 +58,12 @@ class AutofillSaveActivity : AppCompatActivity() {
val folderName = val folderName =
directoryStructure.getSaveFolderName( directoryStructure.getSaveFolderName(
sanitizedIdentifier = sanitizedIdentifier, sanitizedIdentifier = sanitizedIdentifier,
username = credentials?.username username = credentials?.username,
) )
val fileName = val fileName =
directoryStructure.getSaveFileName( directoryStructure.getSaveFileName(
username = credentials?.username, username = credentials?.username,
identifier = identifier identifier = identifier,
) )
val intent = val intent =
Intent(context, AutofillSaveActivity::class.java).apply { Intent(context, AutofillSaveActivity::class.java).apply {
@ -76,7 +76,7 @@ class AutofillSaveActivity : AppCompatActivity() {
formOrigin.identifier.takeIf { formOrigin is FormOrigin.App }, formOrigin.identifier.takeIf { formOrigin is FormOrigin.App },
EXTRA_SHOULD_MATCH_WEB to EXTRA_SHOULD_MATCH_WEB to
formOrigin.identifier.takeIf { formOrigin is FormOrigin.Web }, 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, context,
saveRequestCode++, saveRequestCode++,
intent, intent,
PendingIntent.FLAG_CANCEL_CURRENT or PendingIntent.FLAG_IMMUTABLE PendingIntent.FLAG_CANCEL_CURRENT or PendingIntent.FLAG_IMMUTABLE,
) )
.intentSender .intentSender
} }
@ -114,7 +114,7 @@ class AutofillSaveActivity : AppCompatActivity() {
PasswordCreationActivity.EXTRA_FILE_NAME to intent.getStringExtra(EXTRA_NAME), PasswordCreationActivity.EXTRA_FILE_NAME to intent.getStringExtra(EXTRA_NAME),
PasswordCreationActivity.EXTRA_PASSWORD to intent.getStringExtra(EXTRA_PASSWORD), PasswordCreationActivity.EXTRA_PASSWORD to intent.getStringExtra(EXTRA_PASSWORD),
PasswordCreationActivity.EXTRA_GENERATE_PASSWORD to 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, this,
credentials, credentials,
clientState, clientState,
AutofillAction.Generate AutofillAction.Generate,
) )
Intent().apply { Intent().apply {
putExtra(AutofillManager.EXTRA_AUTHENTICATION_RESULT, fillInDataset) putExtra(AutofillManager.EXTRA_AUTHENTICATION_RESULT, fillInDataset)

View file

@ -90,7 +90,7 @@ open class BasePGPActivity : AppCompatActivity() {
fun copyTextToClipboard( fun copyTextToClipboard(
text: String?, text: String?,
showSnackbar: Boolean = true, showSnackbar: Boolean = true,
@StringRes snackbarTextRes: Int = R.string.clipboard_copied_text @StringRes snackbarTextRes: Int = R.string.clipboard_copied_text,
) { ) {
val clipboard = clipboard ?: return val clipboard = clipboard ?: return
val clip = ClipData.newPlainText("pgp_handler_result_pm", text) val clip = ClipData.newPlainText("pgp_handler_result_pm", text)

View file

@ -40,7 +40,7 @@ fun EditPasswordScreen(
onNavigationIconClick = onNavigateUp, onNavigationIconClick = onNavigateUp,
backgroundColor = MaterialTheme.colorScheme.surface, backgroundColor = MaterialTheme.colorScheme.surface,
) )
}, }
) { paddingValues -> ) { paddingValues ->
Box(modifier = modifier.padding(paddingValues)) { Box(modifier = modifier.padding(paddingValues)) {
Column(modifier = Modifier.padding(vertical = 8.dp, horizontal = 16.dp).fillMaxSize()) { Column(modifier = Modifier.padding(vertical = 8.dp, horizontal = 16.dp).fillMaxSize()) {
@ -59,10 +59,7 @@ fun EditPasswordScreen(
} }
@Composable @Composable
private fun ExtraContent( private fun ExtraContent(entry: PasswordEntry, modifier: Modifier = Modifier) {
entry: PasswordEntry,
modifier: Modifier = Modifier,
) {
TextField( TextField(
value = entry.extraContentString, value = entry.extraContentString,
onValueChange = {}, onValueChange = {},
@ -95,5 +92,5 @@ private fun createTestEntry() =
|URL: example.com |URL: example.com
""" """
.trimMargin() .trimMargin()
.encodeToByteArray() .encodeToByteArray(),
) )

View file

@ -147,7 +147,7 @@ class PasswordCreationActivity : BasePGPActivity() {
otpImportButton.setOnClickListener { otpImportButton.setOnClickListener {
supportFragmentManager.setFragmentResultListener( supportFragmentManager.setFragmentResultListener(
OTP_RESULT_REQUEST_KEY, OTP_RESULT_REQUEST_KEY,
this@PasswordCreationActivity this@PasswordCreationActivity,
) { requestKey, bundle -> ) { requestKey, bundle ->
if (requestKey == OTP_RESULT_REQUEST_KEY) { if (requestKey == OTP_RESULT_REQUEST_KEY) {
val contents = bundle.getString(RESULT) val contents = bundle.getString(RESULT)

View file

@ -46,7 +46,7 @@ fun ViewPasswordScreen(
onNavigationIconClick = onNavigateUp, onNavigationIconClick = onNavigateUp,
backgroundColor = MaterialTheme.colorScheme.surface, backgroundColor = MaterialTheme.colorScheme.surface,
) )
}, }
) { paddingValues -> ) { paddingValues ->
Box(modifier = modifier.padding(paddingValues)) { Box(modifier = modifier.padding(paddingValues)) {
Column(modifier = Modifier.padding(vertical = 8.dp, horizontal = 16.dp).fillMaxSize()) { Column(modifier = Modifier.padding(vertical = 8.dp, horizontal = 16.dp).fillMaxSize()) {
@ -87,10 +87,7 @@ fun ViewPasswordScreen(
} }
@Composable @Composable
private fun ExtraContent( private fun ExtraContent(entry: PasswordEntry, modifier: Modifier = Modifier) {
entry: PasswordEntry,
modifier: Modifier = Modifier,
) {
entry.extraContent.forEach { (label, value) -> entry.extraContent.forEach { (label, value) ->
TextField( TextField(
value = value, value = value,
@ -107,11 +104,7 @@ private fun ExtraContent(
@Composable @Composable
private fun ViewPasswordScreenPreview() { private fun ViewPasswordScreenPreview() {
APSTheme { APSTheme {
ViewPasswordScreen( ViewPasswordScreen(entryName = "Test Entry", entry = createTestEntry(), onNavigateUp = {})
entryName = "Test Entry",
entry = createTestEntry(),
onNavigateUp = {},
)
} }
} }
@ -126,5 +119,5 @@ private fun createTestEntry() =
|URL: example.com |URL: example.com
""" """
.trimMargin() .trimMargin()
.encodeToByteArray() .encodeToByteArray(),
) )

View file

@ -54,7 +54,7 @@ private constructor(
override fun onCreateView( override fun onCreateView(
inflater: LayoutInflater, inflater: LayoutInflater,
container: ViewGroup?, container: ViewGroup?,
savedInstanceState: Bundle? savedInstanceState: Bundle?,
): View? { ): View? {
if (savedInstanceState != null) dismiss() if (savedInstanceState != null) dismiss()
return layoutInflater.inflate(R.layout.basic_bottom_sheet, container, false) return layoutInflater.inflate(R.layout.basic_bottom_sheet, container, false)
@ -157,9 +157,7 @@ private constructor(
return this return this
} }
fun setOnDismissListener( fun setOnDismissListener(onDismissListener: OnDismissListener): Builder {
onDismissListener: OnDismissListener,
): Builder {
this.onDismissListener = onDismissListener this.onDismissListener = onDismissListener
return this return this
} }

View file

@ -59,7 +59,7 @@ class DicewarePasswordGeneratorDialogFragment : DialogFragment() {
setPositiveButton(R.string.dialog_ok) { _, _ -> setPositiveButton(R.string.dialog_ok) { _, _ ->
setFragmentResult( setFragmentResult(
PasswordCreationActivity.PASSWORD_RESULT_REQUEST_KEY, PasswordCreationActivity.PASSWORD_RESULT_REQUEST_KEY,
bundleOf(PasswordCreationActivity.RESULT to "${binding.passwordText.text}") bundleOf(PasswordCreationActivity.RESULT to "${binding.passwordText.text}"),
) )
} }
setNeutralButton(R.string.dialog_cancel) { _, _ -> } setNeutralButton(R.string.dialog_cancel) { _, _ -> }

View file

@ -38,7 +38,7 @@ class ItemCreationBottomSheet : BottomSheetDialogFragment() {
override fun onCreateView( override fun onCreateView(
inflater: LayoutInflater, inflater: LayoutInflater,
container: ViewGroup?, container: ViewGroup?,
savedInstanceState: Bundle? savedInstanceState: Bundle?,
): View? { ): View? {
if (savedInstanceState != null) dismiss() if (savedInstanceState != null) dismiss()
return inflater.inflate(R.layout.item_create_sheet, container, false) return inflater.inflate(R.layout.item_create_sheet, container, false)

View file

@ -25,7 +25,7 @@ class OtpImportDialogFragment : DialogFragment() {
builder.setPositiveButton(android.R.string.ok) { _, _ -> builder.setPositiveButton(android.R.string.ok) { _, _ ->
setFragmentResult( setFragmentResult(
PasswordCreationActivity.OTP_RESULT_REQUEST_KEY, PasswordCreationActivity.OTP_RESULT_REQUEST_KEY,
bundleOf(PasswordCreationActivity.RESULT to getTOTPUri(binding)) bundleOf(PasswordCreationActivity.RESULT to getTOTPUri(binding)),
) )
} }
val dialog = builder.create() val dialog = builder.create()

View file

@ -73,7 +73,7 @@ class PasswordGeneratorDialogFragment : DialogFragment() {
setPositiveButton(R.string.dialog_ok) { _, _ -> setPositiveButton(R.string.dialog_ok) { _, _ ->
setFragmentResult( setFragmentResult(
PasswordCreationActivity.PASSWORD_RESULT_REQUEST_KEY, PasswordCreationActivity.PASSWORD_RESULT_REQUEST_KEY,
bundleOf(PasswordCreationActivity.RESULT to "${binding.passwordText.text}") bundleOf(PasswordCreationActivity.RESULT to "${binding.passwordText.text}"),
) )
} }
setNeutralButton(R.string.dialog_cancel) { _, _ -> } setNeutralButton(R.string.dialog_cancel) { _, _ -> }
@ -123,7 +123,7 @@ class PasswordGeneratorDialogFragment : DialogFragment() {
PasswordOption.NoUppercaseLetters.takeIf { !isChecked(R.id.uppercase) }, PasswordOption.NoUppercaseLetters.takeIf { !isChecked(R.id.uppercase) },
PasswordOption.NoAmbiguousCharacters.takeIf { !isChecked(R.id.ambiguous) }, PasswordOption.NoAmbiguousCharacters.takeIf { !isChecked(R.id.ambiguous) },
PasswordOption.FullyRandom.takeIf { !isChecked(R.id.pronounceable) }, PasswordOption.FullyRandom.takeIf { !isChecked(R.id.pronounceable) },
PasswordOption.NoLowercaseLetters.takeIf { !isChecked(R.id.lowercase) } PasswordOption.NoLowercaseLetters.takeIf { !isChecked(R.id.lowercase) },
) )
} }

View file

@ -28,7 +28,7 @@ class SelectFolderActivity : AppCompatActivity(R.layout.select_folder_layout) {
val args = Bundle() val args = Bundle()
args.putString( args.putString(
PasswordStore.REQUEST_ARG_PATH, PasswordStore.REQUEST_ARG_PATH,
PasswordRepository.getRepositoryDirectory().absolutePath PasswordRepository.getRepositoryDirectory().absolutePath,
) )
passwordList.arguments = args passwordList.arguments = args

View file

@ -131,7 +131,7 @@ abstract class BaseGitActivity : AppCompatActivity() {
gitSettings.useMultiplexing = false gitSettings.useMultiplexing = false
SSHException( SSHException(
DisconnectReason.TOO_MANY_CONNECTIONS, 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 -> { 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 -> { err.disconnectReason == DisconnectReason.HOST_KEY_NOT_VERIFIABLE -> {
SSHException( SSHException(
DisconnectReason.HOST_KEY_NOT_VERIFIABLE, 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 -> { else -> {

View file

@ -61,7 +61,7 @@ class GitConfigActivity : BaseGitActivity() {
Snackbar.make( Snackbar.make(
binding.root, binding.root,
getString(R.string.git_server_config_save_success), getString(R.string.git_server_config_save_success),
Snackbar.LENGTH_SHORT Snackbar.LENGTH_SHORT,
) )
.show() .show()
Handler(Looper.getMainLooper()).postDelayed(500) { finish() } Handler(Looper.getMainLooper()).postDelayed(500) { finish() }

View file

@ -94,7 +94,7 @@ class GitServerConfigActivity : BaseGitActivity() {
Snackbar.make( Snackbar.make(
binding.root, binding.root,
getString(R.string.clear_saved_host_key_success), getString(R.string.clear_saved_host_key_success),
Snackbar.LENGTH_LONG Snackbar.LENGTH_LONG,
) )
.show() .show()
it.isVisible = false it.isVisible = false
@ -140,14 +140,14 @@ class GitServerConfigActivity : BaseGitActivity() {
val updateResult = val updateResult =
gitSettings.updateConnectionSettingsIfValid( gitSettings.updateConnectionSettingsIfValid(
newAuthMode = newAuthMode, newAuthMode = newAuthMode,
newUrl = binding.serverUrl.text.toString().trim() newUrl = binding.serverUrl.text.toString().trim(),
) )
) { ) {
GitSettings.UpdateConnectionSettingsResult.FailedToParseUrl -> { GitSettings.UpdateConnectionSettingsResult.FailedToParseUrl -> {
Snackbar.make( Snackbar.make(
binding.root, binding.root,
getString(R.string.git_server_config_save_error), getString(R.string.git_server_config_save_error),
Snackbar.LENGTH_LONG Snackbar.LENGTH_LONG,
) )
.show() .show()
} }
@ -175,7 +175,7 @@ class GitServerConfigActivity : BaseGitActivity() {
Snackbar.make( Snackbar.make(
binding.root, binding.root,
getString(R.string.git_server_config_save_success), getString(R.string.git_server_config_save_success),
Snackbar.LENGTH_SHORT Snackbar.LENGTH_SHORT,
) )
.show() .show()
Handler(Looper.getMainLooper()).postDelayed(500) { finish() } Handler(Looper.getMainLooper()).postDelayed(500) { finish() }
@ -242,7 +242,7 @@ class GitServerConfigActivity : BaseGitActivity() {
val snackbar = val snackbar =
snackbar( snackbar(
message = getString(R.string.delete_directory_progress_text), message = getString(R.string.delete_directory_progress_text),
length = Snackbar.LENGTH_INDEFINITE length = Snackbar.LENGTH_INDEFINITE,
) )
withContext(dispatcherProvider.io()) { withContext(dispatcherProvider.io()) {
localDir.deleteRecursively() localDir.deleteRecursively()
@ -255,7 +255,7 @@ class GitServerConfigActivity : BaseGitActivity() {
setResult(RESULT_OK) setResult(RESULT_OK)
finish() finish()
}, },
failure = { err -> promptOnErrorHandler(err) { finish() } } failure = { err -> promptOnErrorHandler(err) { finish() } },
) )
} }
} }

View file

@ -58,11 +58,11 @@ class LaunchActivity : AppCompatActivity() {
getDecryptIntent().apply { getDecryptIntent().apply {
putExtra( putExtra(
BasePGPActivity.EXTRA_FILE_PATH, BasePGPActivity.EXTRA_FILE_PATH,
intent.getStringExtra(BasePGPActivity.EXTRA_FILE_PATH) intent.getStringExtra(BasePGPActivity.EXTRA_FILE_PATH),
) )
putExtra( putExtra(
BasePGPActivity.EXTRA_REPO_PATH, 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) else Intent(this, PasswordStore::class.java).setAction(Intent.ACTION_VIEW)

View file

@ -156,7 +156,7 @@ class PasswordFragment : Fragment(R.layout.password_recycler_view) {
resources.getQuantityString( resources.getQuantityString(
R.plurals.delete_title, R.plurals.delete_title,
selection.size(), selection.size(),
selection.size() selection.size(),
) )
actionMode!!.invalidate() actionMode!!.invalidate()
} else { } else {
@ -256,7 +256,7 @@ class PasswordFragment : Fragment(R.layout.password_recycler_view) {
val passwordItem = recyclerAdapter.getSelectedItems()[0] val passwordItem = recyclerAdapter.getSelectedItems()[0]
shortcutHandler.addPinnedShortcut( shortcutHandler.addPinnedShortcut(
passwordItem, passwordItem,
passwordItem.createAuthEnabledIntent(requireContext()) passwordItem.createAuthEnabledIntent(requireContext()),
) )
false false
} }
@ -372,7 +372,7 @@ class PasswordFragment : Fragment(R.layout.password_recycler_view) {
requireStore().clearSearch() requireStore().clearSearch()
model.navigateTo( model.navigateTo(
file, file,
recyclerViewState = binding.passRecycler.layoutManager!!.onSaveInstanceState() recyclerViewState = binding.passRecycler.layoutManager!!.onSaveInstanceState(),
) )
requireStore().supportActionBar?.setDisplayHomeAsUpEnabled(true) requireStore().supportActionBar?.setDisplayHomeAsUpEnabled(true)
} }

View file

@ -115,7 +115,7 @@ class PasswordStore : BaseGitActivity() {
getLongName( getLongName(
requireNotNull(source.parent) { "$file has no parent" }, requireNotNull(source.parent) { "$file has no parent" },
repositoryPath, repositoryPath,
basename basename,
) )
val destinationLongName = getLongName(target.absolutePath, repositoryPath, basename) val destinationLongName = getLongName(target.absolutePath, repositoryPath, basename)
if (destinationFile.exists()) { if (destinationFile.exists()) {
@ -127,7 +127,7 @@ class PasswordStore : BaseGitActivity() {
resources.getString( resources.getString(
R.string.password_exists_message, R.string.password_exists_message,
destinationLongName, destinationLongName,
sourceLongName sourceLongName,
) )
) )
.setPositiveButton(R.string.dialog_ok) { _, _ -> .setPositiveButton(R.string.dialog_ok) { _, _ ->
@ -148,7 +148,7 @@ class PasswordStore : BaseGitActivity() {
getLongName( getLongName(
requireNotNull(source.parent) { "$basename has no parent" }, requireNotNull(source.parent) { "$basename has no parent" },
repositoryPath, repositoryPath,
basename basename,
) )
val destinationLongName = getLongName(target.absolutePath, repositoryPath, basename) val destinationLongName = getLongName(target.absolutePath, repositoryPath, basename)
withContext(dispatcherProvider.main()) { withContext(dispatcherProvider.main()) {
@ -156,8 +156,8 @@ class PasswordStore : BaseGitActivity() {
resources.getString( resources.getString(
R.string.git_commit_move_text, R.string.git_commit_move_text,
sourceLongName, sourceLongName,
destinationLongName destinationLongName,
), )
) )
} }
} }
@ -166,7 +166,7 @@ class PasswordStore : BaseGitActivity() {
val relativePath = getRelativePath("${target.absolutePath}/", repoDir) val relativePath = getRelativePath("${target.absolutePath}/", repoDir)
withContext(dispatcherProvider.main()) { withContext(dispatcherProvider.main()) {
commitChange( 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) = private fun runGitOperation(operation: GitOp) =
lifecycleScope.launch { lifecycleScope.launch {
launchGitOperation(operation) launchGitOperation(operation)
.fold( .fold(success = { refreshPasswordList() }, failure = { promptOnErrorHandler(it) })
success = { refreshPasswordList() },
failure = { promptOnErrorHandler(it) },
)
} }
private fun checkLocalRepository() { private fun checkLocalRepository() {
@ -414,7 +411,7 @@ class PasswordStore : BaseGitActivity() {
intent.putExtra(BasePGPActivity.EXTRA_FILE_PATH, currentDir.absolutePath) intent.putExtra(BasePGPActivity.EXTRA_FILE_PATH, currentDir.absolutePath)
intent.putExtra( intent.putExtra(
BasePGPActivity.EXTRA_REPO_PATH, BasePGPActivity.EXTRA_REPO_PATH,
PasswordRepository.getRepositoryDirectory().absolutePath PasswordRepository.getRepositoryDirectory().absolutePath,
) )
listRefreshAction.launch(intent) listRefreshAction.launch(intent)
} }
@ -450,9 +447,7 @@ class PasswordStore : BaseGitActivity() {
item.file.toRelativeString(PasswordRepository.getRepositoryDirectory()) item.file.toRelativeString(PasswordRepository.getRepositoryDirectory())
} }
lifecycleScope.launch { lifecycleScope.launch {
commitChange( commitChange(resources.getString(R.string.git_commit_remove_text, fmt))
resources.getString(R.string.git_commit_remove_text, fmt),
)
} }
} }
.setNegativeButton(resources.getString(R.string.dialog_no), null) .setNegativeButton(resources.getString(R.string.dialog_no), null)
@ -487,7 +482,7 @@ class PasswordStore : BaseGitActivity() {
*/ */
private fun renameCategory( private fun renameCategory(
oldCategory: PasswordItem, oldCategory: PasswordItem,
error: CategoryRenameError = CategoryRenameError.None error: CategoryRenameError = CategoryRenameError.None,
) { ) {
val view = layoutInflater.inflate(R.layout.folder_dialog_fragment, null) val view = layoutInflater.inflate(R.layout.folder_dialog_fragment, null)
val newCategoryEditText = view.findViewById<TextInputEditText>(R.id.folder_name_text) val newCategoryEditText = view.findViewById<TextInputEditText>(R.id.folder_name_text)
@ -530,8 +525,8 @@ class PasswordStore : BaseGitActivity() {
resources.getString( resources.getString(
R.string.git_commit_move_text, R.string.git_commit_move_text,
oldCategory.name, oldCategory.name,
newCategory.name newCategory.name,
), )
) )
} }
} }

View file

@ -54,7 +54,7 @@ fun KeyList(
) { ) {
Image( Image(
painter = painterResource(id = R.drawable.ic_launcher_foreground), 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)) Text(stringResource(R.string.pgp_key_manager_no_keys_guidance))
} }
@ -81,7 +81,7 @@ private fun KeyItem(
onConfirm = { onConfirm = {
onItemClick(identifier) onItemClick(identifier)
isDeleting = false isDeleting = false
} },
) )
val label = val label =
when (identifier) { when (identifier) {
@ -106,7 +106,7 @@ private fun KeyItem(
IconButton(onClick = { isDeleting = true }, modifier = Modifier.requiredSize(24.dp)) { IconButton(onClick = { isDeleting = true }, modifier = Modifier.requiredSize(24.dp)) {
Icon( Icon(
painter = painterResource(R.drawable.ic_delete_24dp), 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"), PGPIdentifier.fromString("0xB950AE2813841585"),
) )
.toPersistentList(), .toPersistentList(),
onItemClick = {} onItemClick = {},
) )
} }
} }

View file

@ -52,10 +52,10 @@ class PGPKeyListActivity : ComponentActivity() {
) { ) {
Icon( Icon(
painter = painterResource(R.drawable.ic_add_48dp), painter = painterResource(R.drawable.ic_add_48dp),
stringResource(R.string.pref_import_pgp_key_title) stringResource(R.string.pref_import_pgp_key_title),
) )
} }
} },
) { paddingValues -> ) { paddingValues ->
KeyList( KeyList(
identifiers = viewModel.keys, identifiers = viewModel.keys,

View file

@ -22,10 +22,7 @@ class PasswordSettings(private val activity: FragmentActivity) : SettingsProvide
val values = activity.resources.getStringArray(R.array.pwgen_provider_values) val values = activity.resources.getStringArray(R.array.pwgen_provider_values)
val labels = activity.resources.getStringArray(R.array.pwgen_provider_labels) val labels = activity.resources.getStringArray(R.array.pwgen_provider_labels)
val items = values.zip(labels).map { SelectionItem(it.first, it.second, null) } val items = values.zip(labels).map { SelectionItem(it.first, it.second, null) }
singleChoice( singleChoice(PreferenceKeys.PREF_KEY_PWGEN_TYPE, items) {
PreferenceKeys.PREF_KEY_PWGEN_TYPE,
items,
) {
initialSelection = "diceware" initialSelection = "diceware"
titleRes = R.string.pref_password_generator_type_title titleRes = R.string.pref_password_generator_type_title
} }

View file

@ -103,7 +103,7 @@ class SettingsActivity : AppCompatActivity() {
BundleCompat.getParcelable( BundleCompat.getParcelable(
savedInstanceState, savedInstanceState,
"adapter", "adapter",
PreferencesAdapter.SavedState::class.java PreferencesAdapter.SavedState::class.java,
) )
?.let(adapter::loadSavedState) ?.let(adapter::loadSavedState)
} }

View file

@ -126,7 +126,7 @@ class SshKeyGenActivity : AppCompatActivity() {
suspendCoroutine { cont -> suspendCoroutine { cont ->
BiometricAuthenticator.authenticate( BiometricAuthenticator.authenticate(
this@SshKeyGenActivity, this@SshKeyGenActivity,
R.string.biometric_prompt_title_ssh_keygen R.string.biometric_prompt_title_ssh_keygen,
) { result -> ) { result ->
// Do not cancel on failed attempts as these are handled by the // Do not cancel on failed attempts as these are handled by the
// authenticator UI. // authenticator UI.

View file

@ -29,7 +29,7 @@ class SshKeyImportActivity : AppCompatActivity() {
Toast.makeText( Toast.makeText(
this, this,
resources.getString(R.string.ssh_key_success_dialog_title), resources.getString(R.string.ssh_key_success_dialog_title),
Toast.LENGTH_LONG Toast.LENGTH_LONG,
) )
.show() .show()
setResult(RESULT_OK) setResult(RESULT_OK)

View file

@ -23,7 +23,7 @@ class OnOffItemAnimator : DefaultItemAnimator() {
override fun animateAppearance( override fun animateAppearance(
viewHolder: RecyclerView.ViewHolder, viewHolder: RecyclerView.ViewHolder,
preLayoutInfo: ItemHolderInfo?, preLayoutInfo: ItemHolderInfo?,
postLayoutInfo: ItemHolderInfo postLayoutInfo: ItemHolderInfo,
): Boolean { ): Boolean {
return if (isEnabled) { return if (isEnabled) {
super.animateAppearance(viewHolder, preLayoutInfo, postLayoutInfo) super.animateAppearance(viewHolder, preLayoutInfo, postLayoutInfo)
@ -36,7 +36,7 @@ class OnOffItemAnimator : DefaultItemAnimator() {
oldHolder: RecyclerView.ViewHolder, oldHolder: RecyclerView.ViewHolder,
newHolder: RecyclerView.ViewHolder, newHolder: RecyclerView.ViewHolder,
preInfo: ItemHolderInfo, preInfo: ItemHolderInfo,
postInfo: ItemHolderInfo postInfo: ItemHolderInfo,
): Boolean { ): Boolean {
return if (isEnabled) { return if (isEnabled) {
super.animateChange(oldHolder, newHolder, preInfo, postInfo) super.animateChange(oldHolder, newHolder, preInfo, postInfo)
@ -48,7 +48,7 @@ class OnOffItemAnimator : DefaultItemAnimator() {
override fun animateDisappearance( override fun animateDisappearance(
viewHolder: RecyclerView.ViewHolder, viewHolder: RecyclerView.ViewHolder,
preLayoutInfo: ItemHolderInfo, preLayoutInfo: ItemHolderInfo,
postLayoutInfo: ItemHolderInfo? postLayoutInfo: ItemHolderInfo?,
): Boolean { ): Boolean {
return if (isEnabled) { return if (isEnabled) {
super.animateDisappearance(viewHolder, preLayoutInfo, postLayoutInfo) super.animateDisappearance(viewHolder, preLayoutInfo, postLayoutInfo)
@ -60,7 +60,7 @@ class OnOffItemAnimator : DefaultItemAnimator() {
override fun animatePersistence( override fun animatePersistence(
viewHolder: RecyclerView.ViewHolder, viewHolder: RecyclerView.ViewHolder,
preInfo: ItemHolderInfo, preInfo: ItemHolderInfo,
postInfo: ItemHolderInfo postInfo: ItemHolderInfo,
): Boolean { ): Boolean {
return if (isEnabled) { return if (isEnabled) {
super.animatePersistence(viewHolder, preInfo, postInfo) super.animatePersistence(viewHolder, preInfo, postInfo)

View file

@ -57,7 +57,7 @@ object BiometricAuthenticator {
fun authenticate( fun authenticate(
activity: FragmentActivity, activity: FragmentActivity,
@StringRes dialogTitleRes: Int = R.string.biometric_prompt_title, @StringRes dialogTitleRes: Int = R.string.biometric_prompt_title,
callback: (Result) -> Unit callback: (Result) -> Unit,
) { ) {
val authCallback = createPromptAuthenticationCallback(activity, callback) val authCallback = createPromptAuthenticationCallback(activity, callback)
val deviceHasKeyguard = activity.getSystemService<KeyguardManager>()?.isDeviceSecure == true val deviceHasKeyguard = activity.getSystemService<KeyguardManager>()?.isDeviceSecure == true
@ -94,14 +94,14 @@ object BiometricAuthenticator {
callback( callback(
Result.Failure( Result.Failure(
errorCode, errorCode,
activity.getString(R.string.biometric_auth_error_reason, errString) activity.getString(R.string.biometric_auth_error_reason, errString),
) )
) )
BiometricPrompt.ERROR_NO_SPACE -> BiometricPrompt.ERROR_NO_SPACE ->
callback( callback(
Result.Failure( Result.Failure(
errorCode, 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) BiometricPrompt.ERROR_CANCELED -> callback(Result.CanceledBySystem)
@ -109,21 +109,21 @@ object BiometricAuthenticator {
callback( callback(
Result.Failure( Result.Failure(
errorCode, errorCode,
activity.getString(R.string.biometric_auth_error_reason, errString) activity.getString(R.string.biometric_auth_error_reason, errString),
) )
) )
BiometricPrompt.ERROR_VENDOR -> BiometricPrompt.ERROR_VENDOR ->
callback( callback(
Result.Failure( Result.Failure(
errorCode, errorCode,
activity.getString(R.string.biometric_auth_error_reason, errString) activity.getString(R.string.biometric_auth_error_reason, errString),
) )
) )
BiometricPrompt.ERROR_LOCKOUT_PERMANENT -> BiometricPrompt.ERROR_LOCKOUT_PERMANENT ->
callback( callback(
Result.Failure( Result.Failure(
errorCode, 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) BiometricPrompt.ERROR_USER_CANCELED -> callback(Result.CanceledByUser)
@ -138,7 +138,7 @@ object BiometricAuthenticator {
callback( callback(
Result.Failure( Result.Failure(
errorCode, errorCode,
activity.getString(R.string.biometric_auth_error_reason, errString) activity.getString(R.string.biometric_auth_error_reason, errString),
) )
) )
} }

View file

@ -26,15 +26,12 @@ import logcat.LogPriority.ERROR
import logcat.asLog import logcat.asLog
import logcat.logcat import logcat.logcat
class Api26AutofillResponseBuilder class Api26AutofillResponseBuilder private constructor(form: FillableForm) :
private constructor( AutofillResponseBuilder {
form: FillableForm,
) : AutofillResponseBuilder {
object Factory : AutofillResponseBuilder.Factory { object Factory : AutofillResponseBuilder.Factory {
override fun create( override fun create(form: FillableForm): AutofillResponseBuilder =
form: FillableForm, Api26AutofillResponseBuilder(form)
): AutofillResponseBuilder = Api26AutofillResponseBuilder(form)
} }
private val formOrigin = form.formOrigin private val formOrigin = form.formOrigin
@ -104,14 +101,14 @@ private constructor(
AutofillPublisherChangedActivity.makePublisherChangedIntentSender( AutofillPublisherChangedActivity.makePublisherChangedIntentSender(
context, context,
publisherChangedException, publisherChangedException,
fillResponseAfterReset fillResponseAfterReset,
) )
return makeIntentDataset(context, AutofillAction.Match, intentSender, metadata) return makeIntentDataset(context, AutofillAction.Match, intentSender, metadata)
} }
private fun makePublisherChangedResponse( private fun makePublisherChangedResponse(
context: Context, context: Context,
publisherChangedException: AutofillPublisherChangedException publisherChangedException: AutofillPublisherChangedException,
): FillResponse { ): FillResponse {
return FillResponse.Builder().run { return FillResponse.Builder().run {
addDataset(makePublisherChangedDataset(context, publisherChangedException)) addDataset(makePublisherChangedDataset(context, publisherChangedException))
@ -164,7 +161,7 @@ private constructor(
setHeader( setHeader(
makeRemoteView( makeRemoteView(
context, context,
makeHeaderMetadata(formOrigin.getPrettyIdentifier(context, untrusted = true)) makeHeaderMetadata(formOrigin.getPrettyIdentifier(context, untrusted = true)),
) )
) )
} }
@ -183,7 +180,7 @@ private constructor(
failure = { e -> failure = { e ->
logcat(ERROR) { e.asLog() } logcat(ERROR) { e.asLog() }
callback.onSuccess(makePublisherChangedResponse(context, e)) callback.onSuccess(makePublisherChangedResponse(context, e))
} },
) )
} }
} }

View file

@ -33,15 +33,12 @@ import logcat.logcat
/** Implements [AutofillResponseBuilder]'s methods for API 30 and above */ /** Implements [AutofillResponseBuilder]'s methods for API 30 and above */
@RequiresApi(Build.VERSION_CODES.R) @RequiresApi(Build.VERSION_CODES.R)
class Api30AutofillResponseBuilder class Api30AutofillResponseBuilder private constructor(form: FillableForm) :
private constructor( AutofillResponseBuilder {
form: FillableForm,
) : AutofillResponseBuilder {
object Factory : AutofillResponseBuilder.Factory { object Factory : AutofillResponseBuilder.Factory {
override fun create( override fun create(form: FillableForm): AutofillResponseBuilder =
form: FillableForm, Api30AutofillResponseBuilder(form)
): AutofillResponseBuilder = Api30AutofillResponseBuilder(form)
} }
private val formOrigin = form.formOrigin private val formOrigin = form.formOrigin
@ -127,7 +124,7 @@ private constructor(
private fun makeMatchDataset( private fun makeMatchDataset(
context: Context, context: Context,
file: File, file: File,
imeSpec: InlinePresentationSpec? imeSpec: InlinePresentationSpec?,
): Dataset? { ): Dataset? {
if (!scenario.hasFieldsToFillOn(AutofillAction.Match)) return null if (!scenario.hasFieldsToFillOn(AutofillAction.Match)) return null
val metadata = makeFillMatchMetadata(context, file) val metadata = makeFillMatchMetadata(context, file)
@ -151,7 +148,7 @@ private constructor(
private fun makeFillOtpFromSmsDataset( private fun makeFillOtpFromSmsDataset(
context: Context, context: Context,
imeSpec: InlinePresentationSpec? imeSpec: InlinePresentationSpec?,
): Dataset? { ): Dataset? {
if (!scenario.hasFieldsToFillOn(AutofillAction.FillOtpFromSms)) return null if (!scenario.hasFieldsToFillOn(AutofillAction.FillOtpFromSms)) return null
if (!AutofillSmsActivity.shouldOfferFillFromSms(context)) return null if (!AutofillSmsActivity.shouldOfferFillFromSms(context)) return null
@ -162,14 +159,14 @@ private constructor(
AutofillAction.FillOtpFromSms, AutofillAction.FillOtpFromSms,
intentSender, intentSender,
metadata, metadata,
imeSpec imeSpec,
) )
} }
private fun makePublisherChangedDataset( private fun makePublisherChangedDataset(
context: Context, context: Context,
publisherChangedException: AutofillPublisherChangedException, publisherChangedException: AutofillPublisherChangedException,
imeSpec: InlinePresentationSpec? imeSpec: InlinePresentationSpec?,
): Dataset { ): Dataset {
val metadata = makeWarningMetadata(context) val metadata = makeWarningMetadata(context)
// If the user decides to trust the new publisher, they can choose reset the list of // If the user decides to trust the new publisher, they can choose reset the list of
@ -181,7 +178,7 @@ private constructor(
AutofillPublisherChangedActivity.makePublisherChangedIntentSender( AutofillPublisherChangedActivity.makePublisherChangedIntentSender(
context, context,
publisherChangedException, publisherChangedException,
fillResponseAfterReset fillResponseAfterReset,
) )
return makeIntentDataset(context, AutofillAction.Match, intentSender, metadata, imeSpec) return makeIntentDataset(context, AutofillAction.Match, intentSender, metadata, imeSpec)
} }
@ -189,7 +186,7 @@ private constructor(
private fun makePublisherChangedResponse( private fun makePublisherChangedResponse(
context: Context, context: Context,
inlineSuggestionsRequest: InlineSuggestionsRequest?, inlineSuggestionsRequest: InlineSuggestionsRequest?,
publisherChangedException: AutofillPublisherChangedException publisherChangedException: AutofillPublisherChangedException,
): FillResponse { ): FillResponse {
val imeSpec = inlineSuggestionsRequest?.inlinePresentationSpecs?.firstOrNull() val imeSpec = inlineSuggestionsRequest?.inlinePresentationSpecs?.firstOrNull()
return FillResponse.Builder().run { return FillResponse.Builder().run {
@ -202,7 +199,7 @@ private constructor(
private fun makeFillResponse( private fun makeFillResponse(
context: Context, context: Context,
inlineSuggestionsRequest: InlineSuggestionsRequest?, inlineSuggestionsRequest: InlineSuggestionsRequest?,
matchedFiles: List<File> matchedFiles: List<File>,
): FillResponse? { ): FillResponse? {
var datasetCount = 0 var datasetCount = 0
val imeSpecs = inlineSuggestionsRequest?.inlinePresentationSpecs ?: emptyList() val imeSpecs = inlineSuggestionsRequest?.inlinePresentationSpecs ?: emptyList()
@ -229,7 +226,7 @@ private constructor(
setHeader( setHeader(
makeRemoteView( makeRemoteView(
context, context,
makeHeaderMetadata(formOrigin.getPrettyIdentifier(context, untrusted = true)) makeHeaderMetadata(formOrigin.getPrettyIdentifier(context, untrusted = true)),
) )
) )
makeSaveInfo()?.let { setSaveInfo(it) } makeSaveInfo()?.let { setSaveInfo(it) }
@ -271,7 +268,7 @@ private constructor(
callback.onSuccess( callback.onSuccess(
makePublisherChangedResponse(context, fillRequest.inlineSuggestionsRequest, e) makePublisherChangedResponse(context, fillRequest.inlineSuggestionsRequest, e)
) )
} },
) )
} }
} }

View file

@ -102,7 +102,7 @@ class AutofillMatcher {
*/ */
fun getMatchesFor( fun getMatchesFor(
context: Context, context: Context,
formOrigin: FormOrigin formOrigin: FormOrigin,
): Result<List<File>, AutofillPublisherChangedException> { ): Result<List<File>, AutofillPublisherChangedException> {
if (hasFormOriginHashChanged(context, formOrigin)) { if (hasFormOriginHashChanged(context, formOrigin)) {
return Err(AutofillPublisherChangedException(formOrigin)) return Err(AutofillPublisherChangedException(formOrigin))
@ -151,7 +151,7 @@ class AutofillMatcher {
Toast.makeText( Toast.makeText(
context, context,
context.getString(R.string.oreo_autofill_max_matches_reached, MAX_NUM_MATCHES), context.getString(R.string.oreo_autofill_max_matches_reached, MAX_NUM_MATCHES),
Toast.LENGTH_LONG Toast.LENGTH_LONG,
) )
.show() .show()
return return
@ -170,7 +170,7 @@ class AutofillMatcher {
fun updateMatches( fun updateMatches(
context: Context, context: Context,
moveFromTo: Map<File, File> = emptyMap(), moveFromTo: Map<File, File> = emptyMap(),
delete: Collection<File> = emptyList() delete: Collection<File> = emptyList(),
) { ) {
val deletePathList = delete.map { it.absolutePath } val deletePathList = delete.map { it.absolutePath }
val oldNewPathMap = val oldNewPathMap =

View file

@ -134,7 +134,7 @@ object AutofillPreferences {
context: Context, context: Context,
file: File, file: File,
entry: PasswordEntry, entry: PasswordEntry,
directoryStructure: DirectoryStructure directoryStructure: DirectoryStructure,
): Credentials { ): Credentials {
// Always give priority to a username stored in the encrypted extras // Always give priority to a username stored in the encrypted extras
val username = val username =

View file

@ -26,7 +26,7 @@ interface AutofillResponseBuilder {
context: Context, context: Context,
credentials: Credentials, credentials: Credentials,
clientState: Bundle, clientState: Bundle,
action: AutofillAction action: AutofillAction,
): Dataset { ): Dataset {
val scenario = AutofillScenario.fromClientState(clientState) val scenario = AutofillScenario.fromClientState(clientState)
// Before Android P, Datasets used for fill-in had to come with a RemoteViews, even // Before Android P, Datasets used for fill-in had to come with a RemoteViews, even

View file

@ -45,7 +45,7 @@ fun makeRemoteView(context: Context, metadata: DatasetMetadata): RemoteViews {
fun makeInlinePresentation( fun makeInlinePresentation(
context: Context, context: Context,
imeSpec: InlinePresentationSpec, imeSpec: InlinePresentationSpec,
metadata: DatasetMetadata metadata: DatasetMetadata,
): InlinePresentation? { ): InlinePresentation? {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) return null if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) return null
@ -91,21 +91,21 @@ fun makeSearchAndFillMetadata(context: Context) =
DatasetMetadata( DatasetMetadata(
context.getString(R.string.oreo_autofill_search_in_store), context.getString(R.string.oreo_autofill_search_in_store),
null, null,
R.drawable.ic_search_black_24dp R.drawable.ic_search_black_24dp,
) )
fun makeGenerateAndFillMetadata(context: Context) = fun makeGenerateAndFillMetadata(context: Context) =
DatasetMetadata( DatasetMetadata(
context.getString(R.string.oreo_autofill_generate_password), context.getString(R.string.oreo_autofill_generate_password),
null, null,
R.drawable.ic_autofill_new_password R.drawable.ic_autofill_new_password,
) )
fun makeFillOtpFromSmsMetadata(context: Context) = fun makeFillOtpFromSmsMetadata(context: Context) =
DatasetMetadata( DatasetMetadata(
context.getString(R.string.oreo_autofill_fill_otp_from_sms), context.getString(R.string.oreo_autofill_fill_otp_from_sms),
null, null,
R.drawable.ic_autofill_sms R.drawable.ic_autofill_sms,
) )
fun makeEmptyMetadata() = DatasetMetadata("PLACEHOLDER", "PLACEHOLDER", R.mipmap.ic_launcher) fun makeEmptyMetadata() = DatasetMetadata("PLACEHOLDER", "PLACEHOLDER", R.mipmap.ic_launcher)
@ -114,7 +114,7 @@ fun makeWarningMetadata(context: Context) =
DatasetMetadata( DatasetMetadata(
context.getString(R.string.oreo_autofill_warning_publisher_dataset_title), context.getString(R.string.oreo_autofill_warning_publisher_dataset_title),
context.getString(R.string.oreo_autofill_warning_publisher_dataset_summary), 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) fun makeHeaderMetadata(title: String) = DatasetMetadata(title, null, 0)

View file

@ -56,7 +56,7 @@ private fun Context.getEncryptedPrefs(fileName: String): SharedPreferences {
fileName, fileName,
masterKeyAlias, masterKeyAlias,
EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV, 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 * Commit changes to the store from a [FragmentActivity] using a custom implementation of
* [GitOperation] * [GitOperation]
*/ */
suspend fun FragmentActivity.commitChange( suspend fun FragmentActivity.commitChange(message: String): Result<Unit, Throwable> {
message: String,
): Result<Unit, Throwable> {
if (!PasswordRepository.isInitialized) { if (!PasswordRepository.isInitialized) {
return Ok(Unit) return Ok(Unit)
} }

View file

@ -25,7 +25,7 @@ fun Fragment.finish() = requireActivity().finish()
*/ */
fun FragmentManager.performTransactionWithBackStack( fun FragmentManager.performTransactionWithBackStack(
destinationFragment: Fragment, destinationFragment: Fragment,
@IdRes containerViewId: Int = android.R.id.content @IdRes containerViewId: Int = android.R.id.content,
) { ) {
commit { commit {
addToBackStack(destinationFragment.tag) addToBackStack(destinationFragment.tag)
@ -33,7 +33,7 @@ fun FragmentManager.performTransactionWithBackStack(
R.animator.slide_in_left, R.animator.slide_in_left,
R.animator.slide_out_left, R.animator.slide_out_left,
R.animator.slide_in_right, R.animator.slide_in_right,
R.animator.slide_out_right R.animator.slide_out_right,
) )
replace(containerViewId, destinationFragment) replace(containerViewId, destinationFragment)
} }

View file

@ -22,7 +22,7 @@ import kotlin.reflect.KProperty
*/ */
class FragmentViewBindingDelegate<T : ViewBinding>( class FragmentViewBindingDelegate<T : ViewBinding>(
val fragment: Fragment, val fragment: Fragment,
val viewBindingFactory: (View) -> T val viewBindingFactory: (View) -> T,
) : ReadOnlyProperty<Fragment, T> { ) : ReadOnlyProperty<Fragment, T> {
private var binding: T? = null private var binding: T? = null

View file

@ -14,5 +14,5 @@ enum class Feature(
) { ) {
/** Opt into a cache layer for PGP passphrases. */ /** Opt into a cache layer for PGP passphrases. */
EnablePGPPassphraseCache(false, "enable_gpg_passphrase_cache"), EnablePGPPassphraseCache(false, "enable_gpg_passphrase_cache")
} }

View file

@ -11,9 +11,7 @@ import javax.inject.Inject
class Features class Features
@Inject @Inject
constructor( constructor(@SettingsPreferences private val preferences: SharedPreferences) {
@SettingsPreferences private val preferences: SharedPreferences,
) {
fun isEnabled(feature: Feature): Boolean { fun isEnabled(feature: Feature): Boolean {
return preferences.getBoolean(feature.configKey, feature.defaultValue) return preferences.getBoolean(feature.configKey, feature.defaultValue)

View file

@ -38,7 +38,7 @@ class GitCommandExecutor(
private val hiltEntryPoint by unsafeLazy { private val hiltEntryPoint by unsafeLazy {
EntryPointAccessors.fromApplication( EntryPointAccessors.fromApplication(
activity.applicationContext, activity.applicationContext,
GitCommandExecutorEntryPoint::class.java GitCommandExecutorEntryPoint::class.java,
) )
} }
@ -93,7 +93,7 @@ class GitCommandExecutor(
RemoteRefUpdate.Status.REJECTED_NODELETE, RemoteRefUpdate.Status.REJECTED_NODELETE,
RemoteRefUpdate.Status.REJECTED_REMOTE_CHANGED, RemoteRefUpdate.Status.REJECTED_REMOTE_CHANGED,
RemoteRefUpdate.Status.NON_EXISTING, RemoteRefUpdate.Status.NON_EXISTING,
RemoteRefUpdate.Status.NOT_ATTEMPTED, -> RemoteRefUpdate.Status.NOT_ATTEMPTED ->
throw PushException.Generic(rru.status.name) throw PushException.Generic(rru.status.name)
RemoteRefUpdate.Status.REJECTED_OTHER_REASON -> { RemoteRefUpdate.Status.REJECTED_OTHER_REASON -> {
throw if ("non-fast-forward" == rru.message) { throw if ("non-fast-forward" == rru.message) {
@ -107,7 +107,7 @@ class GitCommandExecutor(
Toast.makeText( Toast.makeText(
activity, activity,
activity.applicationContext.getString(R.string.git_push_up_to_date), activity.applicationContext.getString(R.string.git_push_up_to_date),
Toast.LENGTH_SHORT Toast.LENGTH_SHORT,
) )
.show() .show()
} }

View file

@ -19,5 +19,5 @@ data class GitCommit(
val hash: String, val hash: String,
val shortMessage: String, val shortMessage: String,
val authorName: String, val authorName: String,
val time: Instant val time: Instant,
) )

View file

@ -18,7 +18,5 @@ class CloneOperation(callingActivity: AppCompatActivity, uri: String) :
GitOperation(callingActivity) { GitOperation(callingActivity) {
override val commands: Array<GitCommand<out Any>> = override val commands: Array<GitCommand<out Any>> =
arrayOf( arrayOf(Git.cloneRepository().setDirectory(repository.workTree).setURI(uri))
Git.cloneRepository().setDirectory(repository.workTree).setURI(uri),
)
} }

View file

@ -12,9 +12,7 @@ import org.eclipse.jgit.api.GitCommand
* Run an aggressive garbage collection job on the repository, expiring every loose object to * Run an aggressive garbage collection job on the repository, expiring every loose object to
* achieve the best compression. * achieve the best compression.
*/ */
class GcOperation( class GcOperation(callingActivity: AppCompatActivity) : GitOperation(callingActivity) {
callingActivity: AppCompatActivity,
) : GitOperation(callingActivity) {
override val requiresAuth: Boolean = false override val requiresAuth: Boolean = false
override val commands: Array<GitCommand<out Any>> = override val commands: Array<GitCommand<out Any>> =

View file

@ -116,7 +116,7 @@ abstract class GitOperation(protected val callingActivity: FragmentActivity) {
private fun registerAuthProviders( private fun registerAuthProviders(
authMethod: SshAuthMethod, authMethod: SshAuthMethod,
credentialsProvider: CredentialsProvider? = null credentialsProvider: CredentialsProvider? = null,
) { ) {
sshSessionFactory = sshSessionFactory =
SshjSessionFactory(authMethod, hostKeyFile, hiltEntryPoint.dispatcherProvider()) SshjSessionFactory(authMethod, hostKeyFile, hiltEntryPoint.dispatcherProvider())
@ -134,12 +134,7 @@ abstract class GitOperation(protected val callingActivity: FragmentActivity) {
if (!preExecute()) { if (!preExecute()) {
return Ok(Unit) return Ok(Unit)
} }
val operationResult = val operationResult = GitCommandExecutor(callingActivity, this).execute()
GitCommandExecutor(
callingActivity,
this,
)
.execute()
postExecute() postExecute()
return operationResult return operationResult
} }
@ -174,7 +169,7 @@ abstract class GitOperation(protected val callingActivity: FragmentActivity) {
suspendCoroutine { cont -> suspendCoroutine { cont ->
BiometricAuthenticator.authenticate( BiometricAuthenticator.authenticate(
callingActivity, callingActivity,
R.string.biometric_prompt_title_ssh_auth R.string.biometric_prompt_title_ssh_auth,
) { result -> ) { result ->
if (result !is Failure && result !is Retry) cont.resume(result) if (result !is Failure && result !is Retry) cont.resume(result)
} }
@ -199,7 +194,7 @@ abstract class GitOperation(protected val callingActivity: FragmentActivity) {
Toast.makeText( Toast.makeText(
callingActivity, callingActivity,
R.string.biometric_auth_generic_failure, R.string.biometric_auth_generic_failure,
Toast.LENGTH_LONG Toast.LENGTH_LONG,
) )
.show() .show()
callingActivity.finish() callingActivity.finish()
@ -220,7 +215,7 @@ abstract class GitOperation(protected val callingActivity: FragmentActivity) {
CredentialFinder( CredentialFinder(
callingActivity, callingActivity,
AuthMode.Password, AuthMode.Password,
hiltEntryPoint.dispatcherProvider() hiltEntryPoint.dispatcherProvider(),
) )
) )
registerAuthProviders(SshAuthMethod.Password(authActivity), httpsCredentialProvider) registerAuthProviders(SshAuthMethod.Password(authActivity), httpsCredentialProvider)

View file

@ -7,10 +7,8 @@ package app.passwordstore.util.git.operation
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import org.eclipse.jgit.api.GitCommand import org.eclipse.jgit.api.GitCommand
class PullOperation( class PullOperation(callingActivity: AppCompatActivity, rebase: Boolean) :
callingActivity: AppCompatActivity, GitOperation(callingActivity) {
rebase: Boolean,
) : GitOperation(callingActivity) {
/** /**
* The story of why the pull operation is committing files goes like this: Once upon a time when * The story of why the pull operation is committing files goes like this: Once upon a time when

View file

@ -10,7 +10,5 @@ import org.eclipse.jgit.api.GitCommand
class PushOperation(callingActivity: AppCompatActivity) : GitOperation(callingActivity) { class PushOperation(callingActivity: AppCompatActivity) : GitOperation(callingActivity) {
override val commands: Array<GitCommand<out Any>> = override val commands: Array<GitCommand<out Any>> =
arrayOf( arrayOf(git.push().setPushAll().setRemote("origin"))
git.push().setPushAll().setRemote("origin"),
)
} }

View file

@ -7,10 +7,8 @@ package app.passwordstore.util.git.operation
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import org.eclipse.jgit.api.GitCommand import org.eclipse.jgit.api.GitCommand
class SyncOperation( class SyncOperation(callingActivity: AppCompatActivity, rebase: Boolean) :
callingActivity: AppCompatActivity, GitOperation(callingActivity) {
rebase: Boolean,
) : GitOperation(callingActivity) {
override val commands: Array<GitCommand<out Any>> = override val commands: Array<GitCommand<out Any>> =
arrayOf( arrayOf(

View file

@ -135,8 +135,7 @@ object SshKey {
KeystoreWrappedEd25519("keystore_wrapped_ed25519"), KeystoreWrappedEd25519("keystore_wrapped_ed25519"),
// Behaves like `Imported`, but allows to view the public key. // Behaves like `Imported`, but allows to view the public key.
LegacyGenerated("legacy_generated"), LegacyGenerated("legacy_generated");
;
companion object { companion object {
@ -146,7 +145,7 @@ object SshKey {
enum class Algorithm( enum class Algorithm(
val algorithm: String, val algorithm: String,
val applyToSpec: KeyGenParameterSpec.Builder.() -> Unit val applyToSpec: KeyGenParameterSpec.Builder.() -> Unit,
) { ) {
Rsa( Rsa(
KeyProperties.KEY_ALGORITHM_RSA, KeyProperties.KEY_ALGORITHM_RSA,
@ -156,9 +155,9 @@ object SshKey {
setDigests( setDigests(
KeyProperties.DIGEST_SHA1, KeyProperties.DIGEST_SHA1,
KeyProperties.DIGEST_SHA256, KeyProperties.DIGEST_SHA256,
KeyProperties.DIGEST_SHA512 KeyProperties.DIGEST_SHA512,
) )
} },
), ),
Ecdsa( Ecdsa(
KeyProperties.KEY_ALGORITHM_EC, KeyProperties.KEY_ALGORITHM_EC,
@ -169,7 +168,7 @@ object SshKey {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
setIsStrongBoxBacked(isStrongBoxSupported) setIsStrongBoxBacked(isStrongBoxSupported)
} }
} },
), ),
} }
@ -250,7 +249,7 @@ object SshKey {
context, context,
privateKeyFile, privateKeyFile,
getOrCreateWrappingMasterKey(requireAuthentication), getOrCreateWrappingMasterKey(requireAuthentication),
EncryptedFile.FileEncryptionScheme.AES256_GCM_HKDF_4KB EncryptedFile.FileEncryptionScheme.AES256_GCM_HKDF_4KB,
) )
.setKeysetPrefName(ANDROIDX_SECURITY_KEYSET_PREF_NAME) .setKeysetPrefName(ANDROIDX_SECURITY_KEYSET_PREF_NAME)
.build() .build()
@ -319,7 +318,7 @@ object SshKey {
logcat { error.asLog() } logcat { error.asLog() }
throw IOException( throw IOException(
"Failed to get public key '$KEYSTORE_ALIAS' from Android Keystore", "Failed to get public key '$KEYSTORE_ALIAS' from Android Keystore",
error error,
) )
} }
@ -329,7 +328,7 @@ object SshKey {
logcat { error.asLog() } logcat { error.asLog() }
throw IOException( throw IOException(
"Failed to access private key '$KEYSTORE_ALIAS' from Android Keystore", "Failed to access private key '$KEYSTORE_ALIAS' from Android Keystore",
error error,
) )
} }

View file

@ -140,18 +140,10 @@ class SshjConfig : ConfigImpl() {
private fun initMACFactories() { private fun initMACFactories() {
macFactories = macFactories =
listOf( listOf(Macs.HMACSHA2512Etm(), Macs.HMACSHA2256Etm(), Macs.HMACSHA2512(), Macs.HMACSHA2256())
Macs.HMACSHA2512Etm(),
Macs.HMACSHA2256Etm(),
Macs.HMACSHA2512(),
Macs.HMACSHA2256(),
)
} }
private fun initCompressionFactories() { private fun initCompressionFactories() {
compressionFactories = compressionFactories = listOf(NoneCompression.Factory())
listOf(
NoneCompression.Factory(),
)
} }
} }

View file

@ -79,7 +79,7 @@ class SshjSessionFactory(
uri: URIish, uri: URIish,
credentialsProvider: CredentialsProvider?, credentialsProvider: CredentialsProvider?,
fs: FS?, fs: FS?,
tms: Int tms: Int,
): RemoteSession { ): RemoteSession {
return currentSession return currentSession
?: SshjSession(uri, uri.user, authMethod, hostKeyFile, dispatcherProvider).connect().also { ?: SshjSession(uri, uri.user, authMethod, hostKeyFile, dispatcherProvider).connect().also {
@ -164,7 +164,7 @@ private class SshjSession(
AuthPublickey( AuthPublickey(
SshKey.provide( SshKey.provide(
ssh, ssh,
CredentialFinder(authMethod.activity, AuthMode.SshKey, dispatcherProvider) CredentialFinder(authMethod.activity, AuthMode.SshKey, dispatcherProvider),
) )
) )
ssh.auth(username, pubkeyAuth, passwordAuth) ssh.auth(username, pubkeyAuth, passwordAuth)

View file

@ -125,7 +125,7 @@ class ClipboardService : Service() {
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_MUTABLE PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_MUTABLE
} else { } else {
PendingIntent.FLAG_UPDATE_CURRENT PendingIntent.FLAG_UPDATE_CURRENT
} },
) )
val notification = createNotification(pendingIntent, clearTimeMs) val notification = createNotification(pendingIntent, clearTimeMs)
@ -152,7 +152,7 @@ class ClipboardService : Service() {
NotificationChannel( NotificationChannel(
CHANNEL_ID, CHANNEL_ID,
getString(R.string.app_name), getString(R.string.app_name),
NotificationManager.IMPORTANCE_LOW NotificationManager.IMPORTANCE_LOW,
) )
val manager = getSystemService<NotificationManager>() val manager = getSystemService<NotificationManager>()
if (manager != null) { if (manager != null) {

View file

@ -65,7 +65,7 @@ class OreoAutofillService : AutofillService() {
override fun onFillRequest( override fun onFillRequest(
request: FillRequest, request: FillRequest,
cancellationSignal: CancellationSignal, cancellationSignal: CancellationSignal,
callback: FillCallback callback: FillCallback,
) { ) {
val structure = val structure =
request.fillContexts.lastOrNull()?.structure request.fillContexts.lastOrNull()?.structure
@ -144,7 +144,7 @@ class OreoAutofillService : AutofillService() {
AutofillSaveActivity.makeSaveIntentSender( AutofillSaveActivity.makeSaveIntentSender(
this, this,
credentials = Credentials(username, password, null), credentials = Credentials(username, password, null),
formOrigin = formOrigin formOrigin = formOrigin,
) )
) )
} }

View file

@ -134,7 +134,7 @@ class PasswordExportService : Service() {
NotificationChannel( NotificationChannel(
CHANNEL_ID, CHANNEL_ID,
getString(R.string.app_name), getString(R.string.app_name),
NotificationManager.IMPORTANCE_LOW NotificationManager.IMPORTANCE_LOW,
) )
val manager = getSystemService<NotificationManager>() val manager = getSystemService<NotificationManager>()
if (manager != null) { if (manager != null) {

View file

@ -21,8 +21,7 @@ import org.eclipse.jgit.transport.URIish
enum class Protocol(val pref: String) { enum class Protocol(val pref: String) {
Ssh("ssh://"), Ssh("ssh://"),
Https("https://"), Https("https://");
;
companion object { companion object {
@ -36,8 +35,7 @@ enum class Protocol(val pref: String) {
enum class AuthMode(val pref: String) { enum class AuthMode(val pref: String) {
SshKey("ssh-key"), SshKey("ssh-key"),
Password("username/password"), Password("username/password"),
None("None"), None("None");
;
companion object { companion object {
@ -140,7 +138,7 @@ constructor(
fun updateConnectionSettingsIfValid( fun updateConnectionSettingsIfValid(
newAuthMode: AuthMode, newAuthMode: AuthMode,
newUrl: String newUrl: String,
): UpdateConnectionSettingsResult { ): UpdateConnectionSettingsResult {
val parsedUrl = val parsedUrl =
runCatching { URIish(newUrl) } runCatching { URIish(newUrl) }

View file

@ -91,7 +91,7 @@ private fun migrateToGitUrlBasedConfig(sharedPrefs: SharedPreferences, gitSettin
url == null || url == null ||
gitSettings.updateConnectionSettingsIfValid( gitSettings.updateConnectionSettingsIfValid(
newAuthMode = gitSettings.authMode, newAuthMode = gitSettings.authMode,
newUrl = url newUrl = url,
) != GitSettings.UpdateConnectionSettingsResult.Valid ) != GitSettings.UpdateConnectionSettingsResult.Valid
) { ) {
logcat(TAG, ERROR) { "Failed to migrate to URL-based Git config, generated URL is invalid" } 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 { sharedPrefs.edit {
putBoolean( putBoolean(
PreferenceKeys.CLEAR_CLIPBOARD_HISTORY, PreferenceKeys.CLEAR_CLIPBOARD_HISTORY,
sharedPrefs.getBoolean(PreferenceKeys.CLEAR_CLIPBOARD_20X, false) sharedPrefs.getBoolean(PreferenceKeys.CLEAR_CLIPBOARD_20X, false),
) )
remove(PreferenceKeys.CLEAR_CLIPBOARD_20X) remove(PreferenceKeys.CLEAR_CLIPBOARD_20X)
} }

View file

@ -64,7 +64,7 @@ object PreferenceKeys {
@Deprecated( @Deprecated(
message = "Use SHOW_HIDDEN_CONTENTS instead", 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_FOLDERS = "show_hidden_folders"
const val SHOW_HIDDEN_CONTENTS = "show_hidden_contents" const val SHOW_HIDDEN_CONTENTS = "show_hidden_contents"

View file

@ -19,11 +19,7 @@ import javax.inject.Inject
import logcat.logcat import logcat.logcat
@Reusable @Reusable
class ShortcutHandler class ShortcutHandler @Inject constructor(@ApplicationContext val context: Context) {
@Inject
constructor(
@ApplicationContext val context: Context,
) {
private companion object { private companion object {

View file

@ -67,7 +67,7 @@ private val CaseInsensitiveComparator = Collator.getInstance().apply { strength
private fun PasswordItem.Companion.makeComparator( private fun PasswordItem.Companion.makeComparator(
typeSortOrder: PasswordSortOrder, typeSortOrder: PasswordSortOrder,
directoryStructure: DirectoryStructure directoryStructure: DirectoryStructure,
): Comparator<PasswordItem> { ): Comparator<PasswordItem> {
return when (typeSortOrder) { return when (typeSortOrder) {
PasswordSortOrder.FOLDER_FIRST -> compareBy { it.type } PasswordSortOrder.FOLDER_FIRST -> compareBy { it.type }
@ -158,7 +158,7 @@ constructor(
val listMode: ListMode, val listMode: ListMode,
// This counter can be increased to force a reexecution of the search action even if all // This counter can be increased to force a reexecution of the search action even if all
// other arguments are left unchanged. // other arguments are left unchanged.
val updateCounter: Int val updateCounter: Int,
) )
private fun makeSearchAction( private fun makeSearchAction(
@ -166,7 +166,7 @@ constructor(
filter: String, filter: String,
filterMode: FilterMode, filterMode: FilterMode,
searchMode: SearchMode, searchMode: SearchMode,
listMode: ListMode listMode: ListMode,
): SearchAction { ): SearchAction {
return SearchAction( return SearchAction(
baseDirectory = baseDirectory, baseDirectory = baseDirectory,
@ -174,7 +174,7 @@ constructor(
filterMode = filterMode, filterMode = filterMode,
searchMode = searchMode, searchMode = searchMode,
listMode = listMode, listMode = listMode,
updateCounter = updateCounter updateCounter = updateCounter,
) )
} }
@ -187,7 +187,7 @@ constructor(
filter = "", filter = "",
filterMode = FilterMode.NoFilter, filterMode = FilterMode.NoFilter,
searchMode = SearchMode.InCurrentDirectoryOnly, searchMode = SearchMode.InCurrentDirectoryOnly,
listMode = ListMode.AllEntries listMode = ListMode.AllEntries,
) )
) )
@ -310,7 +310,7 @@ constructor(
newDirectory: File = root, newDirectory: File = root,
listMode: ListMode = ListMode.AllEntries, listMode: ListMode = ListMode.AllEntries,
recyclerViewState: Parcelable? = null, recyclerViewState: Parcelable? = null,
pushPreviousLocation: Boolean = true pushPreviousLocation: Boolean = true,
) { ) {
if (!newDirectory.exists()) return if (!newDirectory.exists()) return
require(newDirectory.isDirectory) { "Can only navigate to a directory" } require(newDirectory.isDirectory) { "Can only navigate to a directory" }
@ -323,7 +323,7 @@ constructor(
baseDirectory = newDirectory, baseDirectory = newDirectory,
filterMode = FilterMode.NoFilter, filterMode = FilterMode.NoFilter,
searchMode = SearchMode.InCurrentDirectoryOnly, searchMode = SearchMode.InCurrentDirectoryOnly,
listMode = listMode listMode = listMode,
) )
} }
_currentDir.update { newDirectory } _currentDir.update { newDirectory }
@ -356,7 +356,7 @@ constructor(
baseDirectory: File? = null, baseDirectory: File? = null,
filterMode: FilterMode = FilterMode.Fuzzy, filterMode: FilterMode = FilterMode.Fuzzy,
searchMode: SearchMode? = null, searchMode: SearchMode? = null,
listMode: ListMode = ListMode.AllEntries listMode: ListMode = ListMode.AllEntries,
) { ) {
require(baseDirectory?.isDirectory != false) { "Can only search in a directory" } require(baseDirectory?.isDirectory != false) { "Can only search in a directory" }
searchActionFlow.update { searchActionFlow.update {
@ -365,7 +365,7 @@ constructor(
baseDirectory = baseDirectory ?: _currentDir.value, baseDirectory = baseDirectory ?: _currentDir.value,
filterMode = filterMode, filterMode = filterMode,
searchMode = searchMode ?: defaultSearchMode, searchMode = searchMode ?: defaultSearchMode,
listMode = listMode listMode = listMode,
) )
} }
} }
@ -417,7 +417,7 @@ open class SearchableRepositoryAdapter<T : RecyclerView.ViewHolder>(
fun <T : ItemDetailsLookup<String>> makeSelectable( fun <T : ItemDetailsLookup<String>> makeSelectable(
recyclerView: RecyclerView, recyclerView: RecyclerView,
itemDetailsLookupCreator: (recyclerView: RecyclerView) -> T itemDetailsLookupCreator: (recyclerView: RecyclerView) -> T,
) { ) {
selectionTracker = selectionTracker =
SelectionTracker.Builder( SelectionTracker.Builder(
@ -425,7 +425,7 @@ open class SearchableRepositoryAdapter<T : RecyclerView.ViewHolder>(
recyclerView, recyclerView,
itemKeyProvider, itemKeyProvider,
itemDetailsLookupCreator(recyclerView), itemDetailsLookupCreator(recyclerView),
StorageStrategy.createStringStorage() StorageStrategy.createStringStorage(),
) )
.withSelectionPredicate(SelectionPredicates.createSelectAnything()) .withSelectionPredicate(SelectionPredicates.createSelectAnything())
.build() .build()

View file

@ -87,7 +87,7 @@ class AutofillSmsActivity : AppCompatActivity() {
context, context,
fillOtpFromSmsRequestCode++, fillOtpFromSmsRequestCode++,
intent, intent,
PendingIntent.FLAG_CANCEL_CURRENT or PendingIntent.FLAG_IMMUTABLE PendingIntent.FLAG_CANCEL_CURRENT or PendingIntent.FLAG_IMMUTABLE,
) )
.intentSender .intentSender
} }
@ -159,11 +159,11 @@ class AutofillSmsActivity : AppCompatActivity() {
this@AutofillSmsActivity, this@AutofillSmsActivity,
Credentials(null, null, smsCode), Credentials(null, null, smsCode),
clientState, clientState,
AutofillAction.FillOtpFromSms AutofillAction.FillOtpFromSms,
) )
setResult( setResult(
RESULT_OK, RESULT_OK,
Intent().apply { putExtra(AutofillManager.EXTRA_AUTHENTICATION_RESULT, fillInDataset) } Intent().apply { putExtra(AutofillManager.EXTRA_AUTHENTICATION_RESULT, fillInDataset) },
) )
finish() finish()
} }

View file

@ -61,12 +61,12 @@ class MigrationsTest {
runMigrations( runMigrations(
filesDir, filesDir,
sharedPrefs, sharedPrefs,
GitSettings(sharedPrefs, encryptedSharedPreferences, proxySharedPreferences, filesDir) GitSettings(sharedPrefs, encryptedSharedPreferences, proxySharedPreferences, filesDir),
) )
checkOldKeysAreRemoved() checkOldKeysAreRemoved()
assertEquals( assertEquals(
sharedPrefs.getString(PreferenceKeys.GIT_REMOTE_URL), 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( runMigrations(
filesDir, filesDir,
sharedPrefs, sharedPrefs,
GitSettings(sharedPrefs, encryptedSharedPreferences, proxySharedPreferences, filesDir) GitSettings(sharedPrefs, encryptedSharedPreferences, proxySharedPreferences, filesDir),
) )
checkOldKeysAreRemoved() checkOldKeysAreRemoved()
assertEquals( assertEquals(
sharedPrefs.getString(PreferenceKeys.GIT_REMOTE_URL), 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( runMigrations(
filesDir, filesDir,
sharedPrefs, sharedPrefs,
GitSettings(sharedPrefs, encryptedSharedPreferences, proxySharedPreferences, filesDir) GitSettings(sharedPrefs, encryptedSharedPreferences, proxySharedPreferences, filesDir),
) )
checkOldKeysAreRemoved() checkOldKeysAreRemoved()
assertEquals( assertEquals(
sharedPrefs.getString(PreferenceKeys.GIT_REMOTE_URL), 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( runMigrations(
filesDir, filesDir,
sharedPrefs, sharedPrefs,
GitSettings(sharedPrefs, encryptedSharedPreferences, proxySharedPreferences, filesDir) GitSettings(sharedPrefs, encryptedSharedPreferences, proxySharedPreferences, filesDir),
) )
assertEquals(true, sharedPrefs.getBoolean(PreferenceKeys.SHOW_HIDDEN_FOLDERS, true)) assertEquals(true, sharedPrefs.getBoolean(PreferenceKeys.SHOW_HIDDEN_FOLDERS, true))
assertEquals(false, sharedPrefs.getBoolean(PreferenceKeys.SHOW_HIDDEN_CONTENTS, false)) assertEquals(false, sharedPrefs.getBoolean(PreferenceKeys.SHOW_HIDDEN_CONTENTS, false))
@ -129,7 +129,7 @@ class MigrationsTest {
runMigrations( runMigrations(
filesDir, filesDir,
sharedPrefs, sharedPrefs,
GitSettings(sharedPrefs, encryptedSharedPreferences, proxySharedPreferences, filesDir) GitSettings(sharedPrefs, encryptedSharedPreferences, proxySharedPreferences, filesDir),
) )
assertEquals(false, sharedPrefs.getBoolean(PreferenceKeys.SHOW_HIDDEN_FOLDERS, false)) assertEquals(false, sharedPrefs.getBoolean(PreferenceKeys.SHOW_HIDDEN_FOLDERS, false))
assertEquals(true, sharedPrefs.getBoolean(PreferenceKeys.SHOW_HIDDEN_CONTENTS, false)) assertEquals(true, sharedPrefs.getBoolean(PreferenceKeys.SHOW_HIDDEN_CONTENTS, false))
@ -141,7 +141,7 @@ class MigrationsTest {
runMigrations( runMigrations(
filesDir, filesDir,
sharedPrefs, sharedPrefs,
GitSettings(sharedPrefs, encryptedSharedPreferences, proxySharedPreferences, filesDir) GitSettings(sharedPrefs, encryptedSharedPreferences, proxySharedPreferences, filesDir),
) )
assertEquals(true, sharedPrefs.getBoolean(PreferenceKeys.CLEAR_CLIPBOARD_HISTORY, false)) assertEquals(true, sharedPrefs.getBoolean(PreferenceKeys.CLEAR_CLIPBOARD_HISTORY, false))
assertFalse(sharedPrefs.contains(PreferenceKeys.CLEAR_CLIPBOARD_20X)) assertFalse(sharedPrefs.contains(PreferenceKeys.CLEAR_CLIPBOARD_20X))

View file

@ -47,7 +47,7 @@ public sealed class FormOrigin(public open val identifier: String) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
context.packageManager.getApplicationInfo( context.packageManager.getApplicationInfo(
identifier, identifier,
ApplicationInfoFlags.of(PackageManager.GET_META_DATA.toLong()) ApplicationInfoFlags.of(PackageManager.GET_META_DATA.toLong()),
) )
} else { } else {
context.packageManager.getApplicationInfo(identifier, PackageManager.GET_META_DATA) context.packageManager.getApplicationInfo(identifier, PackageManager.GET_META_DATA)
@ -74,7 +74,7 @@ private class AutofillFormParser(
context: Context, context: Context,
structure: AssistStructure, structure: AssistStructure,
isManualRequest: Boolean, isManualRequest: Boolean,
private val customSuffixes: Sequence<String> private val customSuffixes: Sequence<String>,
) { ) {
companion object { companion object {
@ -136,7 +136,7 @@ private class AutofillFormParser(
autofillStrategy.match( autofillStrategy.match(
relevantFields, relevantFields,
singleOriginMode = trustedBrowserInfo?.multiOriginMethod == BrowserMultiOriginMethod.None, singleOriginMode = trustedBrowserInfo?.multiOriginMethod == BrowserMultiOriginMethod.None,
isManualRequest = isManualRequest isManualRequest = isManualRequest,
) )
private fun trackOrigin(node: AssistStructure.ViewNode) { private fun trackOrigin(node: AssistStructure.ViewNode) {
@ -187,7 +187,7 @@ private class AutofillFormParser(
// situation is uncertain and Autofill should not be offered. // situation is uncertain and Autofill should not be offered.
webOriginToFormOrigin( webOriginToFormOrigin(
context, 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 formOrigin: FormOrigin,
public val scenario: AutofillScenario<AutofillId>, public val scenario: AutofillScenario<AutofillId>,
public val ignoredIds: List<AutofillId>, public val ignoredIds: List<AutofillId>,
public val saveFlags: Int? public val saveFlags: Int?,
) { ) {
public companion object { public companion object {
/** Returns a [FillableForm] if a login form could be detected in [structure]. */ /** Returns a [FillableForm] if a login form could be detected in [structure]. */
@ -222,7 +222,7 @@ private constructor(
form.formOrigin, form.formOrigin,
form.scenario.map { it.autofillId }, form.scenario.map { it.autofillId },
form.ignoredIds, form.ignoredIds,
form.saveFlags form.saveFlags,
) )
} }
} }

View file

@ -57,7 +57,7 @@ public fun computeCertificatesHash(context: Context, appPackage: String): String
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
context.packageManager.getPackageInfo( context.packageManager.getPackageInfo(
appPackage, appPackage,
PackageManager.PackageInfoFlags.of(PackageManager.GET_SIGNING_CERTIFICATES.toLong()) PackageManager.PackageInfoFlags.of(PackageManager.GET_SIGNING_CERTIFICATES.toLong()),
) )
} else { } else {
context.packageManager.getPackageInfo(appPackage, PackageManager.GET_SIGNING_CERTIFICATES) context.packageManager.getPackageInfo(appPackage, PackageManager.GET_SIGNING_CERTIFICATES)
@ -121,7 +121,7 @@ private fun visitViewNodes(structure: AssistStructure, block: (AssistStructure.V
private fun visitViewNode( private fun visitViewNode(
node: AssistStructure.ViewNode, node: AssistStructure.ViewNode,
block: (AssistStructure.ViewNode) -> Unit block: (AssistStructure.ViewNode) -> Unit,
) { ) {
block(node) block(node)
for (i in 0 until node.childCount) { for (i in 0 until node.childCount) {

View file

@ -21,7 +21,7 @@ public enum class AutofillAction {
Match, Match,
Search, Search,
Generate, Generate,
FillOtpFromSms FillOtpFromSms,
} }
/** /**
@ -46,8 +46,8 @@ public sealed class AutofillScenario<out T : Any> {
"Use `fromClientState` instead.", "Use `fromClientState` instead.",
ReplaceWith( ReplaceWith(
"fromClientState(clientState)", "fromClientState(clientState)",
"com.github.androidpasswordstore.autofillparser.AutofillScenario.Companion.fromClientState" "com.github.androidpasswordstore.autofillparser.AutofillScenario.Companion.fromClientState",
) ),
) )
public fun fromBundle(clientState: Bundle): AutofillScenario<AutofillId>? { public fun fromBundle(clientState: Bundle): AutofillScenario<AutofillId>? {
return fromClientState(clientState) return fromClientState(clientState)
@ -61,7 +61,7 @@ public sealed class AutofillScenario<out T : Any> {
BundleCompat.getParcelable( BundleCompat.getParcelable(
clientState, clientState,
BUNDLE_KEY_USERNAME_ID, BUNDLE_KEY_USERNAME_ID,
AutofillId::class.java AutofillId::class.java,
) )
fillUsername = clientState.getBoolean(BUNDLE_KEY_FILL_USERNAME) fillUsername = clientState.getBoolean(BUNDLE_KEY_FILL_USERNAME)
otp = BundleCompat.getParcelable(clientState, BUNDLE_KEY_OTP_ID, AutofillId::class.java) otp = BundleCompat.getParcelable(clientState, BUNDLE_KEY_OTP_ID, AutofillId::class.java)
@ -69,21 +69,21 @@ public sealed class AutofillScenario<out T : Any> {
BundleCompat.getParcelableArrayList( BundleCompat.getParcelableArrayList(
clientState, clientState,
BUNDLE_KEY_CURRENT_PASSWORD_IDS, BUNDLE_KEY_CURRENT_PASSWORD_IDS,
AutofillId::class.java AutofillId::class.java,
) ?: emptyList() ) ?: emptyList()
) )
newPassword.addAll( newPassword.addAll(
BundleCompat.getParcelableArrayList( BundleCompat.getParcelableArrayList(
clientState, clientState,
BUNDLE_KEY_NEW_PASSWORD_IDS, BUNDLE_KEY_NEW_PASSWORD_IDS,
AutofillId::class.java AutofillId::class.java,
) ?: emptyList() ) ?: emptyList()
) )
genericPassword.addAll( genericPassword.addAll(
BundleCompat.getParcelableArrayList( BundleCompat.getParcelableArrayList(
clientState, clientState,
BUNDLE_KEY_GENERIC_PASSWORD_IDS, BUNDLE_KEY_GENERIC_PASSWORD_IDS,
AutofillId::class.java AutofillId::class.java,
) ?: emptyList() ) ?: emptyList()
) )
} }
@ -114,14 +114,14 @@ public sealed class AutofillScenario<out T : Any> {
fillUsername = fillUsername, fillUsername = fillUsername,
otp = otp, otp = otp,
currentPassword = currentPassword, currentPassword = currentPassword,
newPassword = newPassword newPassword = newPassword,
) )
} else { } else {
GenericAutofillScenario( GenericAutofillScenario(
username = username, username = username,
fillUsername = fillUsername, fillUsername = fillUsername,
otp = otp, otp = otp,
genericPassword = genericPassword genericPassword = genericPassword,
) )
} }
} }
@ -193,7 +193,7 @@ internal data class ClassifiedAutofillScenario<T : Any>(
override val fillUsername: Boolean, override val fillUsername: Boolean,
override val otp: T?, override val otp: T?,
val currentPassword: List<T>, val currentPassword: List<T>,
val newPassword: List<T> val newPassword: List<T>,
) : AutofillScenario<T>() { ) : AutofillScenario<T>() {
override val allPasswordFields override val allPasswordFields
@ -217,7 +217,7 @@ internal data class GenericAutofillScenario<T : Any>(
override val username: T?, override val username: T?,
override val fillUsername: Boolean, override val fillUsername: Boolean,
override val otp: T?, override val otp: T?,
val genericPassword: List<T> val genericPassword: List<T>,
) : AutofillScenario<T>() { ) : AutofillScenario<T>() {
override val allPasswordFields override val allPasswordFields
@ -254,7 +254,7 @@ internal fun AutofillScenario<FormField>.passesOriginCheck(singleOriginMode: Boo
public fun Dataset.Builder.fillWith( public fun Dataset.Builder.fillWith(
scenario: AutofillScenario<AutofillId>, scenario: AutofillScenario<AutofillId>,
action: AutofillAction, action: AutofillAction,
credentials: Credentials? credentials: Credentials?,
) { ) {
val credentialsToFill = credentials ?: Credentials("USERNAME", "PASSWORD", "OTP") val credentialsToFill = credentials ?: Credentials("USERNAME", "PASSWORD", "OTP")
for (field in scenario.fieldsToFillOn(action)) { for (field in scenario.fieldsToFillOn(action)) {
@ -303,7 +303,7 @@ internal fun AutofillScenario<AutofillId>.toBundle(): Bundle =
putParcelable(AutofillScenario.BUNDLE_KEY_OTP_ID, otp) putParcelable(AutofillScenario.BUNDLE_KEY_OTP_ID, otp)
putParcelableArrayList( putParcelableArrayList(
AutofillScenario.BUNDLE_KEY_CURRENT_PASSWORD_IDS, AutofillScenario.BUNDLE_KEY_CURRENT_PASSWORD_IDS,
ArrayList(currentPassword) ArrayList(currentPassword),
) )
putParcelableArrayList(AutofillScenario.BUNDLE_KEY_NEW_PASSWORD_IDS, ArrayList(newPassword)) 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) putParcelable(AutofillScenario.BUNDLE_KEY_OTP_ID, otp)
putParcelableArrayList( putParcelableArrayList(
AutofillScenario.BUNDLE_KEY_GENERIC_PASSWORD_IDS, AutofillScenario.BUNDLE_KEY_GENERIC_PASSWORD_IDS,
ArrayList(genericPassword) ArrayList(genericPassword),
) )
} }
} }

View file

@ -75,7 +75,7 @@ internal interface FieldMatcher {
@RequiresApi(Build.VERSION_CODES.O) @RequiresApi(Build.VERSION_CODES.O)
internal class SingleFieldMatcher( internal class SingleFieldMatcher(
private val take: (FormField, List<FormField>) -> Boolean, private val take: (FormField, List<FormField>) -> Boolean,
private val tieBreakers: List<(FormField, List<FormField>) -> Boolean> private val tieBreakers: List<(FormField, List<FormField>) -> Boolean>,
) : FieldMatcher { ) : FieldMatcher {
@AutofillDsl @AutofillDsl
@ -100,7 +100,7 @@ internal class SingleFieldMatcher(
fun build() = fun build() =
SingleFieldMatcher( SingleFieldMatcher(
takeSingle ?: throw IllegalArgumentException("Every block needs a take{Single,Pair} block"), 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) @RequiresApi(Build.VERSION_CODES.O)
private class PairOfFieldsMatcher( private class PairOfFieldsMatcher(
private val take: (Pair<FormField, FormField>, List<FormField>) -> Boolean, 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 { ) : FieldMatcher {
override fun match(fields: List<FormField>, alreadyMatched: List<FormField>): List<FormField>? { override fun match(fields: List<FormField>, alreadyMatched: List<FormField>): List<FormField>? {
@ -180,14 +180,14 @@ private constructor(
private val matchers: List<AutofillRuleMatcher>, private val matchers: List<AutofillRuleMatcher>,
private val applyInSingleOriginMode: Boolean, private val applyInSingleOriginMode: Boolean,
private val applyOnManualRequestOnly: Boolean, private val applyOnManualRequestOnly: Boolean,
private val name: String private val name: String,
) { ) {
data class AutofillRuleMatcher( data class AutofillRuleMatcher(
val type: FillableFieldType, val type: FillableFieldType,
val matcher: FieldMatcher, val matcher: FieldMatcher,
val optional: Boolean, val optional: Boolean,
val matchHidden: Boolean val matchHidden: Boolean,
) )
enum class FillableFieldType { enum class FillableFieldType {
@ -201,7 +201,7 @@ private constructor(
@AutofillDsl @AutofillDsl
class Builder( class Builder(
private val applyInSingleOriginMode: Boolean, private val applyInSingleOriginMode: Boolean,
private val applyOnManualRequestOnly: Boolean private val applyOnManualRequestOnly: Boolean,
) { ) {
companion object { companion object {
@ -215,7 +215,7 @@ private constructor(
fun username( fun username(
optional: Boolean = false, optional: Boolean = false,
matchHidden: Boolean = false, matchHidden: Boolean = false,
block: SingleFieldMatcher.Builder.() -> Unit block: SingleFieldMatcher.Builder.() -> Unit,
) { ) {
require(matchers.none { it.type == FillableFieldType.Username }) { require(matchers.none { it.type == FillableFieldType.Username }) {
"Every rule block can only have at most one username block" "Every rule block can only have at most one username block"
@ -225,7 +225,7 @@ private constructor(
type = FillableFieldType.Username, type = FillableFieldType.Username,
matcher = SingleFieldMatcher.Builder().apply(block).build(), matcher = SingleFieldMatcher.Builder().apply(block).build(),
optional = optional, optional = optional,
matchHidden = matchHidden matchHidden = matchHidden,
) )
) )
} }
@ -239,7 +239,7 @@ private constructor(
type = FillableFieldType.Otp, type = FillableFieldType.Otp,
matcher = SingleFieldMatcher.Builder().apply(block).build(), matcher = SingleFieldMatcher.Builder().apply(block).build(),
optional = optional, optional = optional,
matchHidden = false matchHidden = false,
) )
) )
} }
@ -247,7 +247,7 @@ private constructor(
fun currentPassword( fun currentPassword(
optional: Boolean = false, optional: Boolean = false,
matchHidden: Boolean = false, matchHidden: Boolean = false,
block: FieldMatcher.Builder.() -> Unit block: FieldMatcher.Builder.() -> Unit,
) { ) {
require(matchers.none { it.type == FillableFieldType.GenericPassword }) { require(matchers.none { it.type == FillableFieldType.GenericPassword }) {
"Every rule block can only have either genericPassword or {current,new}Password blocks" "Every rule block can only have either genericPassword or {current,new}Password blocks"
@ -257,7 +257,7 @@ private constructor(
type = FillableFieldType.CurrentPassword, type = FillableFieldType.CurrentPassword,
matcher = FieldMatcher.Builder().apply(block).build(), matcher = FieldMatcher.Builder().apply(block).build(),
optional = optional, optional = optional,
matchHidden = matchHidden matchHidden = matchHidden,
) )
) )
} }
@ -271,7 +271,7 @@ private constructor(
type = FillableFieldType.NewPassword, type = FillableFieldType.NewPassword,
matcher = FieldMatcher.Builder().apply(block).build(), matcher = FieldMatcher.Builder().apply(block).build(),
optional = optional, optional = optional,
matchHidden = false matchHidden = false,
) )
) )
} }
@ -279,11 +279,7 @@ private constructor(
fun genericPassword(optional: Boolean = false, block: FieldMatcher.Builder.() -> Unit) { fun genericPassword(optional: Boolean = false, block: FieldMatcher.Builder.() -> Unit) {
require( require(
matchers.none { matchers.none {
it.type in it.type in listOf(FillableFieldType.CurrentPassword, FillableFieldType.NewPassword)
listOf(
FillableFieldType.CurrentPassword,
FillableFieldType.NewPassword,
)
} }
) { ) {
"Every rule block can only have either genericPassword or {current,new}Password blocks" "Every rule block can only have either genericPassword or {current,new}Password blocks"
@ -293,7 +289,7 @@ private constructor(
type = FillableFieldType.GenericPassword, type = FillableFieldType.GenericPassword,
matcher = FieldMatcher.Builder().apply(block).build(), matcher = FieldMatcher.Builder().apply(block).build(),
optional = optional, optional = optional,
matchHidden = false matchHidden = false,
) )
) )
} }
@ -314,7 +310,7 @@ private constructor(
matchers, matchers,
applyInSingleOriginMode, applyInSingleOriginMode,
applyOnManualRequestOnly, applyOnManualRequestOnly,
name ?: "Rule #$ruleId" name ?: "Rule #$ruleId",
) )
.also { ruleId++ } .also { ruleId++ }
} }
@ -325,7 +321,7 @@ private constructor(
allUsername: List<FormField>, allUsername: List<FormField>,
allOtp: List<FormField>, allOtp: List<FormField>,
singleOriginMode: Boolean, singleOriginMode: Boolean,
isManualRequest: Boolean isManualRequest: Boolean,
): AutofillScenario<FormField>? { ): AutofillScenario<FormField>? {
if (singleOriginMode && !applyInSingleOriginMode) { if (singleOriginMode && !applyInSingleOriginMode) {
logcat { "$name: Skipped in single origin mode" } logcat { "$name: Skipped in single origin mode" }
@ -399,12 +395,12 @@ internal class AutofillStrategy private constructor(private val rules: List<Auto
fun rule( fun rule(
applyInSingleOriginMode: Boolean = false, applyInSingleOriginMode: Boolean = false,
applyOnManualRequestOnly: Boolean = false, applyOnManualRequestOnly: Boolean = false,
block: AutofillRule.Builder.() -> Unit block: AutofillRule.Builder.() -> Unit,
) { ) {
rules.add( rules.add(
AutofillRule.Builder( AutofillRule.Builder(
applyInSingleOriginMode = applyInSingleOriginMode, applyInSingleOriginMode = applyInSingleOriginMode,
applyOnManualRequestOnly = applyOnManualRequestOnly applyOnManualRequestOnly = applyOnManualRequestOnly,
) )
.apply(block) .apply(block)
.build() .build()
@ -417,7 +413,7 @@ internal class AutofillStrategy private constructor(private val rules: List<Auto
fun match( fun match(
fields: List<FormField>, fields: List<FormField>,
singleOriginMode: Boolean, singleOriginMode: Boolean,
isManualRequest: Boolean isManualRequest: Boolean,
): AutofillScenario<FormField>? { ): AutofillScenario<FormField>? {
val possiblePasswordFields = fields.filter { it.passwordCertainty >= CertaintyLevel.Possible } val possiblePasswordFields = fields.filter { it.passwordCertainty >= CertaintyLevel.Possible }
logcat { "Possible password fields: ${possiblePasswordFields.size}" } logcat { "Possible password fields: ${possiblePasswordFields.size}" }
@ -433,7 +429,7 @@ internal class AutofillStrategy private constructor(private val rules: List<Auto
possibleUsernameFields, possibleUsernameFields,
possibleOtpFields, possibleOtpFields,
singleOriginMode = singleOriginMode, singleOriginMode = singleOriginMode,
isManualRequest = isManualRequest isManualRequest = isManualRequest,
) ?: continue ) ?: continue
} }
return null return null

View file

@ -59,7 +59,7 @@ private val TRUSTED_BROWSER_CERTIFICATE_HASH =
"com.duckduckgo.mobile.android" to "com.duckduckgo.mobile.android" to
arrayOf( arrayOf(
"u3uzHFc8RqHaf8XFKKas9DIQhFb+7FCBDH8zaU6z0tQ=", "u3uzHFc8RqHaf8XFKKas9DIQhFb+7FCBDH8zaU6z0tQ=",
"8HB9AhwL8+b43MEbo/VwBCXVl9yjAaMeIQVWk067Gwo=" "8HB9AhwL8+b43MEbo/VwBCXVl9yjAaMeIQVWk067Gwo=",
), ),
"com.jamal2367.styx" to arrayOf("Lph3oaG1C8WLhLiK5PVxOp5+6wTU9ipJSBYlD2bA3VI="), "com.jamal2367.styx" to arrayOf("Lph3oaG1C8WLhLiK5PVxOp5+6wTU9ipJSBYlD2bA3VI="),
"com.microsoft.emmx" to arrayOf("AeGZlxCoLCdJtNUMRF3IXWcLYTYInQp2anOCfIKh6sk="), "com.microsoft.emmx" to arrayOf("AeGZlxCoLCdJtNUMRF3IXWcLYTYInQp2anOCfIKh6sk="),
@ -85,7 +85,7 @@ private val TRUSTED_BROWSER_CERTIFICATE_HASH =
"us.spotco.fennec_dos" to "us.spotco.fennec_dos" to
arrayOf( arrayOf(
"Jg4KSWeMeLcMAtZTet07bcChcXG73oznX9QCaoo+GNI=", "Jg4KSWeMeLcMAtZTet07bcChcXG73oznX9QCaoo+GNI=",
"/4H1vlY5ZZTu5w/vKDIlbhUhQSLiupzt0mAF/9S8qqg=" "/4H1vlY5ZZTu5w/vKDIlbhUhQSLiupzt0mAF/9S8qqg=",
), ),
"com.vivaldi.browser" to arrayOf("6KeFRGVbqMCYF/cydo9WibFmLsSyvFoLwOwTjTPKPR4="), "com.vivaldi.browser" to arrayOf("6KeFRGVbqMCYF/cydo9WibFmLsSyvFoLwOwTjTPKPR4="),
"app.vanadium.browser" to arrayOf("xq24uDxtTBfSkq/eVv1IilHTFv+PLBHFQQIjv/in27M="), "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 { internal enum class BrowserMultiOriginMethod {
None, None,
WebView, WebView,
Field Field,
} }
/** /**
@ -173,7 +173,7 @@ private fun isNoAccessibilityServiceEnabled(context: Context): Boolean {
// See https://chromium.googlesource.com/chromium/src/+/447a31e977a65e2eb78804e4a09633699b4ede33 // See https://chromium.googlesource.com/chromium/src/+/447a31e977a65e2eb78804e4a09633699b4ede33
return Settings.Secure.getString( return Settings.Secure.getString(
context.contentResolver, context.contentResolver,
Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
) )
.isNullOrEmpty() .isNullOrEmpty()
} }
@ -187,25 +187,22 @@ private fun getBrowserSaveFlag(context: Context, appPackage: String): Int? =
internal data class BrowserAutofillSupportInfo( internal data class BrowserAutofillSupportInfo(
val multiOriginMethod: BrowserMultiOriginMethod, val multiOriginMethod: BrowserMultiOriginMethod,
val saveFlags: Int? val saveFlags: Int?,
) )
@RequiresApi(Build.VERSION_CODES.O) @RequiresApi(Build.VERSION_CODES.O)
internal fun getBrowserAutofillSupportInfoIfTrusted( internal fun getBrowserAutofillSupportInfoIfTrusted(
context: Context, context: Context,
appPackage: String appPackage: String,
): BrowserAutofillSupportInfo? { ): BrowserAutofillSupportInfo? {
if (!isTrustedBrowser(context, appPackage)) return null if (!isTrustedBrowser(context, appPackage)) return null
return BrowserAutofillSupportInfo( return BrowserAutofillSupportInfo(
multiOriginMethod = getBrowserMultiOriginMethod(appPackage), multiOriginMethod = getBrowserMultiOriginMethod(appPackage),
saveFlags = getBrowserSaveFlag(context, appPackage) saveFlags = getBrowserSaveFlag(context, appPackage),
) )
} }
private val FLAKY_BROWSERS = private val FLAKY_BROWSERS = listOf("com.kiwibrowser.browser")
listOf(
"com.kiwibrowser.browser",
)
public enum class BrowserAutofillSupportLevel { public enum class BrowserAutofillSupportLevel {
None, None,
@ -219,7 +216,7 @@ public enum class BrowserAutofillSupportLevel {
@RequiresApi(Build.VERSION_CODES.O) @RequiresApi(Build.VERSION_CODES.O)
private fun getBrowserAutofillSupportLevel( private fun getBrowserAutofillSupportLevel(
context: Context, context: Context,
appPackage: String appPackage: String,
): BrowserAutofillSupportLevel { ): BrowserAutofillSupportLevel {
val browserInfo = getBrowserAutofillSupportInfoIfTrusted(context, appPackage) val browserInfo = getBrowserAutofillSupportInfoIfTrusted(context, appPackage)
return when { return when {
@ -252,7 +249,7 @@ public fun getInstalledBrowsersWithAutofillSupportLevel(
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
context.packageManager.queryIntentActivities( context.packageManager.queryIntentActivities(
testWebIntent, testWebIntent,
ResolveInfoFlags.of(PackageManager.MATCH_ALL.toLong()) ResolveInfoFlags.of(PackageManager.MATCH_ALL.toLong()),
) )
} else { } else {
context.packageManager.queryIntentActivities(testWebIntent, PackageManager.MATCH_ALL) context.packageManager.queryIntentActivities(testWebIntent, PackageManager.MATCH_ALL)

View file

@ -17,7 +17,7 @@ internal enum class CertaintyLevel {
Impossible, Impossible,
Possible, Possible,
Likely, Likely,
Certain Certain,
} }
/** /**
@ -29,31 +29,19 @@ internal class FormField(
node: AssistStructure.ViewNode, node: AssistStructure.ViewNode,
private val index: Int, private val index: Int,
passDownWebViewOrigins: Boolean, passDownWebViewOrigins: Boolean,
passedDownWebOrigin: String? = null passedDownWebOrigin: String? = null,
) { ) {
companion object { companion object {
private val HINTS_USERNAME = private val HINTS_USERNAME =
listOf( listOf(HintConstants.AUTOFILL_HINT_USERNAME, HintConstants.AUTOFILL_HINT_NEW_USERNAME)
HintConstants.AUTOFILL_HINT_USERNAME, private val HINTS_NEW_PASSWORD = listOf(HintConstants.AUTOFILL_HINT_NEW_PASSWORD)
HintConstants.AUTOFILL_HINT_NEW_USERNAME,
)
private val HINTS_NEW_PASSWORD =
listOf(
HintConstants.AUTOFILL_HINT_NEW_PASSWORD,
)
private val HINTS_PASSWORD = private val HINTS_PASSWORD =
HINTS_NEW_PASSWORD + HINTS_NEW_PASSWORD +
listOf( listOf(HintConstants.AUTOFILL_HINT_PASSWORD, HintConstants.AUTOFILL_HINT_WIFI_PASSWORD)
HintConstants.AUTOFILL_HINT_PASSWORD,
HintConstants.AUTOFILL_HINT_WIFI_PASSWORD,
)
private val HINTS_OTP = private val HINTS_OTP =
listOf( listOf(HintConstants.AUTOFILL_HINT_SMS_OTP, HintConstants.AUTOFILL_HINT_2FA_APP_OTP)
HintConstants.AUTOFILL_HINT_SMS_OTP,
HintConstants.AUTOFILL_HINT_2FA_APP_OTP,
)
@Suppress("DEPRECATION") @Suppress("DEPRECATION")
private val HINTS_FILLABLE = private val HINTS_FILLABLE =
@ -93,21 +81,9 @@ internal class FormField(
} }
} }
private val HTML_INPUT_FIELD_TYPES_USERNAME = private val HTML_INPUT_FIELD_TYPES_USERNAME = listOf("email", "tel", "text")
listOf( private val HTML_INPUT_FIELD_TYPES_PASSWORD = listOf("password")
"email", private val HTML_INPUT_FIELD_TYPES_OTP = listOf("tel", "text")
"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 = private val HTML_INPUT_FIELD_TYPES_FILLABLE =
(HTML_INPUT_FIELD_TYPES_USERNAME + (HTML_INPUT_FIELD_TYPES_USERNAME +
HTML_INPUT_FIELD_TYPES_PASSWORD + HTML_INPUT_FIELD_TYPES_PASSWORD +
@ -128,33 +104,11 @@ internal class FormField(
"captcha", "captcha",
"postal", // Prevent postal code fields from being mistaken for OTP fields "postal", // Prevent postal code fields from being mistaken for OTP fields
) )
private val PASSWORD_HEURISTIC_TERMS = private val PASSWORD_HEURISTIC_TERMS = listOf("pass", "pswd", "pwd")
listOf(
"pass",
"pswd",
"pwd",
)
private val USERNAME_HEURISTIC_TERMS = private val USERNAME_HEURISTIC_TERMS =
listOf( listOf("alias", "benutzername", "e-mail", "email", "mail", "login", "user")
"alias", private val OTP_HEURISTIC_TERMS = listOf("einmal", "otp", "challenge", "verification")
"benutzername", private val OTP_WEAK_HEURISTIC_TERMS = listOf("code")
"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 private val List<String>.anyMatchesFieldInfo

View file

@ -39,7 +39,7 @@ public fun cachePublicSuffixList(context: Context) {
internal fun getPublicSuffixPlusOne( internal fun getPublicSuffixPlusOne(
context: Context, context: Context,
domain: String, domain: String,
customSuffixes: Sequence<String> customSuffixes: Sequence<String>,
) = runBlocking { ) = runBlocking {
// We only feed valid domain names which are not IP addresses into getPublicSuffixPlusOne. // 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 // 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( private suspend fun getCanonicalSuffix(
context: Context, context: Context,
domain: String, domain: String,
customSuffixes: Sequence<String> customSuffixes: Sequence<String>,
): String { ): String {
val publicSuffixList = PublicSuffixListCache.getOrCachePublicSuffixList(context) val publicSuffixList = PublicSuffixListCache.getOrCachePublicSuffixList(context)
val publicSuffixPlusOne = val publicSuffixPlusOne =

View file

@ -29,7 +29,7 @@ import kotlinx.coroutines.async
internal class PublicSuffixList( internal class PublicSuffixList(
context: Context, context: Context,
dispatcher: CoroutineDispatcher = Dispatchers.IO, dispatcher: CoroutineDispatcher = Dispatchers.IO,
private val scope: CoroutineScope = CoroutineScope(dispatcher) private val scope: CoroutineScope = CoroutineScope(dispatcher),
) { ) {
private val data: PublicSuffixListData by private val data: PublicSuffixListData by

View file

@ -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. */ /** Class wrapping the public suffix list data and offering methods for accessing rules in it. */
internal class PublicSuffixListData( internal class PublicSuffixListData(
private val rules: ByteArray, private val rules: ByteArray,
private val exceptions: ByteArray private val exceptions: ByteArray,
) { ) {
private fun binarySearchRules(labels: List<ByteArray>, labelIndex: Int): String? { private fun binarySearchRules(labels: List<ByteArray>, labelIndex: Int): String? {

View file

@ -41,10 +41,7 @@ class KotlinCommonPlugin : Plugin<Project> {
companion object { companion object {
private val ADDITIONAL_COMPILER_ARGS = private val ADDITIONAL_COMPILER_ARGS =
listOf( listOf("-opt-in=kotlin.RequiresOptIn", "-Xsuppress-version-warnings")
"-opt-in=kotlin.RequiresOptIn",
"-Xsuppress-version-warnings",
)
val JVM_TOOLCHAIN_ACTION = val JVM_TOOLCHAIN_ACTION =
Action<JavaToolchainSpec> { languageVersion.set(JavaLanguageVersion.of(17)) } Action<JavaToolchainSpec> { languageVersion.set(JavaLanguageVersion.of(17)) }

View file

@ -62,10 +62,7 @@ class CrowdinDownloadPlugin : Plugin<Project> {
if (extension.skipCleanup.getOrElse(false)) { if (extension.skipCleanup.getOrElse(false)) {
emptySet() emptySet()
} else { } else {
setOf( setOf(extractStrings.map { it.source }, downloadCrowdin.map { it.outputFiles })
extractStrings.map { it.source },
downloadCrowdin.map { it.outputFiles },
)
} }
} }
} }

View file

@ -57,7 +57,7 @@ abstract class KtfmtCheckTask : SourceTask() {
maxWidth = 100, maxWidth = 100,
continuationIndent = 2, continuationIndent = 2,
), ),
originCode originCode,
) )
val pathNormalizer = { file: File -> file.toRelativeString(projectDirectory.asFile.get()) } val pathNormalizer = { file: File -> file.toRelativeString(projectDirectory.asFile.get()) }
return (originCode != formattedCode) to return (originCode != formattedCode) to

View file

@ -10,7 +10,7 @@ object KtfmtDiffer {
fun computeDiff( fun computeDiff(
inputFile: File, inputFile: File,
formattedCode: String, formattedCode: String,
pathNormalizer: (File) -> String pathNormalizer: (File) -> String,
): List<KtfmtDiffEntry> { ): List<KtfmtDiffEntry> {
val originCode = inputFile.readText() val originCode = inputFile.readText()
return DiffUtils.diff(originCode, formattedCode, null).deltas.map { return DiffUtils.diff(originCode, formattedCode, null).deltas.map {

View file

@ -11,10 +11,8 @@ import org.jetbrains.kotlin.utils.addToStdlib.ifNotEmpty
abstract class KtfmtFormatTask abstract class KtfmtFormatTask
@Inject @Inject
constructor( constructor(private val workerExecutor: WorkerExecutor, private val projectLayout: ProjectLayout) :
private val workerExecutor: WorkerExecutor, SourceTask() {
private val projectLayout: ProjectLayout,
) : SourceTask() {
@TaskAction @TaskAction
fun execute() { fun execute() {

View file

@ -104,7 +104,7 @@ abstract class PSLUpdateTask : DefaultTask() {
var totalRuleBytes: Int = 0, var totalRuleBytes: Int = 0,
var totalExceptionRuleBytes: Int = 0, var totalExceptionRuleBytes: Int = 0,
val sortedRules: TreeSet<ByteString> = TreeSet(), val sortedRules: TreeSet<ByteString> = TreeSet(),
val sortedExceptionRules: TreeSet<ByteString> = TreeSet() val sortedExceptionRules: TreeSet<ByteString> = TreeSet(),
) )
private companion object { private companion object {

View file

@ -48,7 +48,7 @@ abstract class GitHooks : DefaultTask() {
GROUP_EXECUTE, GROUP_EXECUTE,
OTHERS_READ, OTHERS_READ,
OTHERS_EXECUTE, OTHERS_EXECUTE,
) ),
) )
} }
} }

View file

@ -1,10 +1,8 @@
package app.passwordstore.crypto package app.passwordstore.crypto
/** [CryptoOptions] implementation for PGPainless decrypt operations. */ /** [CryptoOptions] implementation for PGPainless decrypt operations. */
public class PGPDecryptOptions public class PGPDecryptOptions private constructor(private val values: Map<String, Boolean>) :
private constructor( CryptoOptions {
private val values: Map<String, Boolean>,
) : CryptoOptions {
override fun isOptionEnabled(option: String): Boolean { override fun isOptionEnabled(option: String): Boolean {
return values.getOrDefault(option, false) return values.getOrDefault(option, false)

View file

@ -1,10 +1,8 @@
package app.passwordstore.crypto package app.passwordstore.crypto
/** [CryptoOptions] implementation for PGPainless encrypt operations. */ /** [CryptoOptions] implementation for PGPainless encrypt operations. */
public class PGPEncryptOptions public class PGPEncryptOptions private constructor(private val values: Map<String, Boolean>) :
private constructor( CryptoOptions {
private val values: Map<String, Boolean>,
) : CryptoOptions {
internal companion object { internal companion object {
const val ASCII_ARMOR = "ASCII_ARMOR" const val ASCII_ARMOR = "ASCII_ARMOR"

View file

@ -31,10 +31,8 @@ import org.pgpainless.util.selection.userid.SelectUserId
public class PGPKeyManager public class PGPKeyManager
@Inject @Inject
constructor( constructor(filesDir: String, private val dispatcher: CoroutineDispatcher) :
filesDir: String, KeyManager<PGPKey, PGPIdentifier> {
private val dispatcher: CoroutineDispatcher,
) : KeyManager<PGPKey, PGPIdentifier> {
private val keyDir = File(filesDir, KEY_DIR_NAME) private val keyDir = File(filesDir, KEY_DIR_NAME)

View file

@ -217,10 +217,7 @@ class PGPKeyManagerTest {
KeyId(-961222705095032109), // Bobby KeyId(-961222705095032109), // Bobby
) )
val userIds = val userIds =
arrayOf( arrayOf(UserId("Alice <owner@example.com>"), UserId("Bobby <owner@example.com>"))
UserId("Alice <owner@example.com>"),
UserId("Bobby <owner@example.com>"),
)
for (idCollection in arrayOf(longKeyIds, userIds)) { for (idCollection in arrayOf(longKeyIds, userIds)) {
val alice1 = keyManager.getKeyById(idCollection[0]) val alice1 = keyManager.getKeyById(idCollection[0])

View file

@ -205,7 +205,7 @@ constructor(
millis / (THOUSAND_MILLIS * totpPeriod), millis / (THOUSAND_MILLIS * totpPeriod),
totpAlgorithm, totpAlgorithm,
digits, digits,
issuer issuer,
) )
.mapBoth({ code -> Ok(Totp(code, remainingTime)) }, ::Err) .mapBoth({ code -> Ok(Totp(code, remainingTime)) }, ::Err)
} }
@ -233,12 +233,7 @@ constructor(
"identity:", "identity:",
) )
@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
public val PASSWORD_FIELDS: Array<String> = public val PASSWORD_FIELDS: Array<String> = arrayOf("password:", "secret:", "pass:")
arrayOf(
"password:",
"secret:",
"pass:",
)
private const val THOUSAND_MILLIS = 1000L private const val THOUSAND_MILLIS = 1000L
} }
} }

View file

@ -26,11 +26,7 @@ class PasswordEntryTest {
private val totpFinder = UriTotpFinder() private val totpFinder = UriTotpFinder()
private fun makeEntry(content: String, clock: UserClock = fakeClock) = private fun makeEntry(content: String, clock: UserClock = fakeClock) =
PasswordEntry( PasswordEntry(clock, totpFinder, content.encodeToByteArray())
clock,
totpFinder,
content.encodeToByteArray(),
)
@Test @Test
fun getPassword() { fun getPassword() {
@ -62,7 +58,7 @@ class PasswordEntryTest {
assertEquals("blubb", makeEntry("password: foo\nblubb").extraContentString) assertEquals("blubb", makeEntry("password: foo\nblubb").extraContentString)
assertEquals( assertEquals(
"blubb\nusername: bar", "blubb\nusername: bar",
makeEntry("blubb\npassword: foo\nusername: bar").extraContentString makeEntry("blubb\npassword: foo\nusername: bar").extraContentString,
) )
assertEquals("", makeEntry("\n").extraContentString) assertEquals("", makeEntry("\n").extraContentString)
assertEquals("", makeEntry("").extraContentString) assertEquals("", makeEntry("").extraContentString)
@ -107,7 +103,7 @@ class PasswordEntryTest {
assertEquals("username", makeEntry("\n$field username").username) assertEquals("username", makeEntry("\n$field username").username)
assertEquals( assertEquals(
"username", "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) assertEquals("username", makeEntry("secret\nextra\nlogin: username\ncontent\n").username)

View file

@ -25,103 +25,36 @@ class OtpTest {
@Test @Test
fun otpGeneration6Digits() { fun otpGeneration6Digits() {
assertEquals( assertEquals("953550", generateOtp(counter = 1593333298159 / (1000 * 30)))
"953550", assertEquals("275379", generateOtp(counter = 1593333571918 / (1000 * 30)))
generateOtp( assertEquals("867507", generateOtp(counter = 1593333600517 / (1000 * 57)))
counter = 1593333298159 / (1000 * 30),
)
)
assertEquals(
"275379",
generateOtp(
counter = 1593333571918 / (1000 * 30),
)
)
assertEquals(
"867507",
generateOtp(
counter = 1593333600517 / (1000 * 57),
)
)
} }
@Test @Test
fun otpGeneration10Digits() { fun otpGeneration10Digits() {
assertEquals( assertEquals("0740900914", generateOtp(counter = 1593333655044 / (1000 * 30), digits = "10"))
"0740900914", assertEquals("0070632029", generateOtp(counter = 1593333691405 / (1000 * 30), digits = "10"))
generateOtp( assertEquals("1017265882", generateOtp(counter = 1593333728893 / (1000 * 83), digits = "10"))
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 @Test
fun otpGenerationIllegalInput() { fun otpGenerationIllegalInput() {
assertNull( assertNull(generateOtp(counter = 10000, algorithm = "SHA0", digits = "10"))
generateOtp( assertNull(generateOtp(counter = 10000, digits = "a"))
counter = 10000, assertNull(generateOtp(counter = 10000, algorithm = "SHA1", digits = "5"))
algorithm = "SHA0", assertNull(generateOtp(counter = 10000, digits = "11"))
digits = "10", assertNull(generateOtp(counter = 10000, secret = "JBSWY3DPEHPK3PXPAAAAB", digits = "6"))
)
)
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 @Test
fun otpGenerationUnusualSecrets() { fun otpGenerationUnusualSecrets() {
assertEquals( assertEquals(
"127764", "127764",
generateOtp( generateOtp(counter = 1593367111963 / (1000 * 30), secret = "JBSWY3DPEHPK3PXPAAAAAAAA"),
counter = 1593367111963 / (1000 * 30),
secret = "JBSWY3DPEHPK3PXPAAAAAAAA",
)
) )
assertEquals( assertEquals(
"047515", "047515",
generateOtp( generateOtp(counter = 1593367171420 / (1000 * 30), secret = "JBSWY3DPEHPK3PXPAAAAA"),
counter = 1593367171420 / (1000 * 30),
secret = "JBSWY3DPEHPK3PXPAAAAA",
)
) )
} }

View file

@ -17,7 +17,7 @@ class UriTotpFinderTest {
assertEquals("HXDMVJECJJWSRB3HWIZR4IFUGFTMXBOZ", totpFinder.findSecret(TOTP_URI)) assertEquals("HXDMVJECJJWSRB3HWIZR4IFUGFTMXBOZ", totpFinder.findSecret(TOTP_URI))
assertEquals( assertEquals(
"HXDMVJECJJWSRB3HWIZR4IFUGFTMXBOZ", "HXDMVJECJJWSRB3HWIZR4IFUGFTMXBOZ",
totpFinder.findSecret("name\npassword\ntotp: HXDMVJECJJWSRB3HWIZR4IFUGFTMXBOZ") totpFinder.findSecret("name\npassword\ntotp: HXDMVJECJJWSRB3HWIZR4IFUGFTMXBOZ"),
) )
assertEquals("HXDMVJECJJWSRB3HWIZR4IFUGFTMXBOZ", totpFinder.findSecret(PASS_FILE_CONTENT)) assertEquals("HXDMVJECJJWSRB3HWIZR4IFUGFTMXBOZ", totpFinder.findSecret(PASS_FILE_CONTENT))
} }

View file

@ -14,10 +14,7 @@ import javax.inject.Inject
*/ */
public class DicewarePassphraseGenerator public class DicewarePassphraseGenerator
@Inject @Inject
constructor( constructor(private val die: Die, wordList: InputStream) {
private val die: Die,
wordList: InputStream,
) {
private val wordMap = WordListParser.parse(wordList) private val wordMap = WordListParser.parse(wordList)

View file

@ -10,10 +10,7 @@ import javax.inject.Inject
/** Basic implementation of a die with configurable number of sides. */ /** Basic implementation of a die with configurable number of sides. */
public class Die public class Die
@Inject @Inject
constructor( constructor(private val sides: Int, private val random: RandomIntGenerator) {
private val sides: Int,
private val random: RandomIntGenerator,
) {
/** Roll the die to return a single number. */ /** Roll the die to return a single number. */
public fun roll(): Int { public fun roll(): Int {

View file

@ -19,11 +19,7 @@ class DicewarePassphraseGeneratorTest {
fun generatePassphrase() { fun generatePassphrase() {
val die = Die(6, intGenerator) val die = Die(6, intGenerator)
val generator = val generator = DicewarePassphraseGenerator(die, WordListParserTest.getDefaultWordList())
DicewarePassphraseGenerator(
die,
WordListParserTest.getDefaultWordList(),
)
assertEquals("salvation_cozily_croon_trustee_fidgety", generator.generatePassphrase(5, '_')) assertEquals("salvation_cozily_croon_trustee_fidgety", generator.generatePassphrase(5, '_'))
} }

View file

@ -6,5 +6,5 @@ public enum class PasswordOption(public val key: String) {
NoAmbiguousCharacters("B"), NoAmbiguousCharacters("B"),
FullyRandom("s"), FullyRandom("s"),
AtLeastOneSymbol("y"), AtLeastOneSymbol("y"),
NoLowercaseLetters("L") NoLowercaseLetters("L"),
} }

View file

@ -55,7 +55,7 @@ internal object RandomPhonemesGenerator {
Element("w", CONSONANT), Element("w", CONSONANT),
Element("x", CONSONANT), Element("x", CONSONANT),
Element("y", CONSONANT), Element("y", CONSONANT),
Element("z", CONSONANT) Element("z", CONSONANT),
) )
private class Element(str: String, val flags: Int) { private class Element(str: String, val flags: Int) {

View file

@ -39,10 +39,7 @@ public fun APSAppBar(
navigationIcon = { navigationIcon = {
if (navigationIcon != null) { if (navigationIcon != null) {
IconButton(onClick = { onNavigationIconClick.invoke() }) { IconButton(onClick = { onNavigationIconClick.invoke() }) {
Icon( Icon(painter = navigationIcon, contentDescription = null)
painter = navigationIcon,
contentDescription = null,
)
} }
} }
}, },
@ -68,7 +65,7 @@ private fun APSAppBarPreview() {
contentDescription = "Search items", contentDescription = "Search items",
) )
} }
} },
) )
} }
} }

View file

@ -56,10 +56,7 @@ private fun ToggleButton(
val icon = val icon =
if (visible) painterResource(id = R.drawable.baseline_visibility_off_24) if (visible) painterResource(id = R.drawable.baseline_visibility_off_24)
else painterResource(id = R.drawable.baseline_visibility_24) else painterResource(id = R.drawable.baseline_visibility_24)
Icon( Icon(painter = icon, contentDescription = contentDescription)
painter = icon,
contentDescription = contentDescription,
)
} }
} }
@ -70,10 +67,7 @@ public fun CopyButton(
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
) { ) {
val clipboard = LocalClipboardManager.current val clipboard = LocalClipboardManager.current
IconButton( IconButton(onClick = { clipboard.setText(AnnotatedString(textToCopy)) }, modifier = modifier) {
onClick = { clipboard.setText(AnnotatedString(textToCopy)) },
modifier = modifier,
) {
Icon( Icon(
painter = painterResource(R.drawable.ic_content_copy), painter = painterResource(R.drawable.ic_content_copy),
contentDescription = stringResource(buttonLabelRes), contentDescription = stringResource(buttonLabelRes),

View file

@ -34,7 +34,7 @@ public fun PasswordItem(
label: String, label: String,
type: ItemType, type: ItemType,
onClick: () -> Unit, onClick: () -> Unit,
modifier: Modifier = Modifier modifier: Modifier = Modifier,
) { ) {
Row( Row(
modifier = modifier =