fix: correctly use biometrics result in passphrase cache flow

This commit is contained in:
Harsh Shandilya 2023-07-09 17:22:06 +05:30
parent dfe4b14b4c
commit fe7aee24d4
No known key found for this signature in database
2 changed files with 57 additions and 31 deletions

View file

@ -18,6 +18,7 @@ import app.passwordstore.data.passfile.PasswordEntry
import app.passwordstore.ui.crypto.BasePGPActivity import app.passwordstore.ui.crypto.BasePGPActivity
import app.passwordstore.ui.crypto.PasswordDialog import app.passwordstore.ui.crypto.PasswordDialog
import app.passwordstore.util.auth.BiometricAuthenticator import app.passwordstore.util.auth.BiometricAuthenticator
import app.passwordstore.util.auth.BiometricAuthenticator.Result
import app.passwordstore.util.autofill.AutofillPreferences import app.passwordstore.util.autofill.AutofillPreferences
import app.passwordstore.util.autofill.AutofillResponseBuilder import app.passwordstore.util.autofill.AutofillResponseBuilder
import app.passwordstore.util.autofill.DirectoryStructure import app.passwordstore.util.autofill.DirectoryStructure
@ -70,7 +71,6 @@ class AutofillDecryptActivity : BasePGPActivity() {
directoryStructure = AutofillPreferences.directoryStructure(this) directoryStructure = AutofillPreferences.directoryStructure(this)
logcat { action.toString() } logcat { action.toString() }
requireKeysExist { requireKeysExist {
val gpgIdentifiers = getPGPIdentifiers("") ?: return@requireKeysExist
if ( if (
features.isEnabled(EnablePGPPassphraseCache) && BiometricAuthenticator.canAuthenticate(this) features.isEnabled(EnablePGPPassphraseCache) && BiometricAuthenticator.canAuthenticate(this)
) { ) {
@ -78,25 +78,42 @@ class AutofillDecryptActivity : BasePGPActivity() {
this, this,
R.string.biometric_prompt_title_gpg_passphrase_cache, R.string.biometric_prompt_title_gpg_passphrase_cache,
) { authResult -> ) { authResult ->
if (authResult is BiometricAuthenticator.Result.Success) { decrypt(filePath, clientState, action, authResult)
lifecycleScope.launch { }
} else {
decrypt(filePath, clientState, action, Result.Cancelled)
}
}
}
private fun decrypt(
filePath: String,
clientState: Bundle,
action: AutofillAction,
authResult: Result,
) {
val gpgIdentifiers = getPGPIdentifiers("") ?: return
lifecycleScope.launch(dispatcherProvider.main()) {
when (authResult) {
// Internally handled by the prompt dialog
is Result.Retry -> {}
// If the dialog is dismissed for any reason, prompt for passphrase
is Result.Cancelled,
is Result.Failure,
is Result.HardwareUnavailableOrDisabled -> askPassphrase(filePath, clientState, action)
//
is Result.Success -> {
val cachedPassphrase = val cachedPassphrase =
passphraseCache.retrieveCachedPassphrase( passphraseCache.retrieveCachedPassphrase(
this@AutofillDecryptActivity, this@AutofillDecryptActivity,
gpgIdentifiers.first() gpgIdentifiers.first()
) )
if (cachedPassphrase != null) { if (cachedPassphrase != null) {
decrypt(File(filePath), clientState, action, cachedPassphrase) decryptWithPassphrase(File(filePath), clientState, action, cachedPassphrase)
} else { } else {
askPassphrase(filePath, clientState, action) askPassphrase(filePath, clientState, action)
} }
} }
} else {
askPassphrase(filePath, clientState, action)
}
}
} else {
askPassphrase(filePath, clientState, action)
} }
} }
} }
@ -107,7 +124,7 @@ class AutofillDecryptActivity : BasePGPActivity() {
withContext(dispatcherProvider.main()) { withContext(dispatcherProvider.main()) {
dialog.password.collectLatest { value -> dialog.password.collectLatest { value ->
if (value != null) { if (value != null) {
decrypt(File(filePath), clientState, action, value) decryptWithPassphrase(File(filePath), clientState, action, value)
} }
} }
} }
@ -115,7 +132,7 @@ class AutofillDecryptActivity : BasePGPActivity() {
dialog.show(supportFragmentManager, "PASSWORD_DIALOG") dialog.show(supportFragmentManager, "PASSWORD_DIALOG")
} }
private suspend fun decrypt( private suspend fun decryptWithPassphrase(
filePath: File, filePath: File,
clientState: Bundle, clientState: Bundle,
action: AutofillAction, action: AutofillAction,

View file

@ -18,6 +18,7 @@ import app.passwordstore.data.password.FieldItem
import app.passwordstore.databinding.DecryptLayoutBinding import app.passwordstore.databinding.DecryptLayoutBinding
import app.passwordstore.ui.adapters.FieldItemAdapter import app.passwordstore.ui.adapters.FieldItemAdapter
import app.passwordstore.util.auth.BiometricAuthenticator import app.passwordstore.util.auth.BiometricAuthenticator
import app.passwordstore.util.auth.BiometricAuthenticator.Result
import app.passwordstore.util.extensions.getString import app.passwordstore.util.extensions.getString
import app.passwordstore.util.extensions.unsafeLazy import app.passwordstore.util.extensions.unsafeLazy
import app.passwordstore.util.extensions.viewBinding import app.passwordstore.util.extensions.viewBinding
@ -77,7 +78,7 @@ class DecryptActivity : BasePGPActivity() {
requireKeysExist { decrypt(isError = false, authResult) } requireKeysExist { decrypt(isError = false, authResult) }
} }
} else { } else {
requireKeysExist { decrypt(isError = false, BiometricAuthenticator.Result.Cancelled) } requireKeysExist { decrypt(isError = false, Result.Cancelled) }
} }
} }
@ -149,10 +150,19 @@ class DecryptActivity : BasePGPActivity() {
) )
} }
private fun decrypt(isError: Boolean, authResult: BiometricAuthenticator.Result) { private fun decrypt(isError: Boolean, authResult: Result) {
val gpgIdentifiers = getPGPIdentifiers("") ?: return val gpgIdentifiers = getPGPIdentifiers("") ?: return
lifecycleScope.launch(dispatcherProvider.main()) { lifecycleScope.launch(dispatcherProvider.main()) {
if (authResult is BiometricAuthenticator.Result.Success) { when (authResult) {
// Internally handled by the prompt dialog
is Result.Retry -> {}
// If the dialog is dismissed for any reason, prompt for passphrase
is Result.Cancelled,
is Result.Failure,
is Result.HardwareUnavailableOrDisabled ->
askPassphrase(isError, gpgIdentifiers, authResult)
//
is Result.Success -> {
val cachedPassphrase = val cachedPassphrase =
passphraseCache.retrieveCachedPassphrase(this@DecryptActivity, gpgIdentifiers.first()) passphraseCache.retrieveCachedPassphrase(this@DecryptActivity, gpgIdentifiers.first())
if (cachedPassphrase != null) { if (cachedPassphrase != null) {
@ -160,8 +170,7 @@ class DecryptActivity : BasePGPActivity() {
} else { } else {
askPassphrase(isError, gpgIdentifiers, authResult) askPassphrase(isError, gpgIdentifiers, authResult)
} }
} else { }
askPassphrase(isError, gpgIdentifiers, authResult)
} }
} }
} }
@ -169,7 +178,7 @@ class DecryptActivity : BasePGPActivity() {
private fun askPassphrase( private fun askPassphrase(
isError: Boolean, isError: Boolean,
gpgIdentifiers: List<PGPIdentifier>, gpgIdentifiers: List<PGPIdentifier>,
authResult: BiometricAuthenticator.Result, authResult: Result,
) { ) {
if (retries < MAX_RETRIES) { if (retries < MAX_RETRIES) {
retries += 1 retries += 1
@ -189,7 +198,7 @@ class DecryptActivity : BasePGPActivity() {
passwordEntry = entry passwordEntry = entry
createPasswordUI(entry) createPasswordUI(entry)
startAutoDismissTimer() startAutoDismissTimer()
if (authResult is BiometricAuthenticator.Result.Success) { if (authResult is Result.Success) {
passphraseCache.cachePassphrase(this@DecryptActivity, gpgIdentifiers.first(), value) passphraseCache.cachePassphrase(this@DecryptActivity, gpgIdentifiers.first(), value)
} }
} }
@ -207,7 +216,7 @@ class DecryptActivity : BasePGPActivity() {
private suspend fun decryptWithCachedPassphrase( private suspend fun decryptWithCachedPassphrase(
passphrase: String, passphrase: String,
identifiers: List<PGPIdentifier>, identifiers: List<PGPIdentifier>,
authResult: BiometricAuthenticator.Result, authResult: Result,
) { ) {
when (val result = decryptWithPassphrase(passphrase, identifiers)) { when (val result = decryptWithPassphrase(passphrase, identifiers)) {
is Ok -> { is Ok -> {