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.PasswordDialog
import app.passwordstore.util.auth.BiometricAuthenticator
import app.passwordstore.util.auth.BiometricAuthenticator.Result
import app.passwordstore.util.autofill.AutofillPreferences
import app.passwordstore.util.autofill.AutofillResponseBuilder
import app.passwordstore.util.autofill.DirectoryStructure
@ -70,7 +71,6 @@ class AutofillDecryptActivity : BasePGPActivity() {
directoryStructure = AutofillPreferences.directoryStructure(this)
logcat { action.toString() }
requireKeysExist {
val gpgIdentifiers = getPGPIdentifiers("") ?: return@requireKeysExist
if (
features.isEnabled(EnablePGPPassphraseCache) && BiometricAuthenticator.canAuthenticate(this)
) {
@ -78,25 +78,42 @@ class AutofillDecryptActivity : BasePGPActivity() {
this,
R.string.biometric_prompt_title_gpg_passphrase_cache,
) { authResult ->
if (authResult is BiometricAuthenticator.Result.Success) {
lifecycleScope.launch {
val cachedPassphrase =
passphraseCache.retrieveCachedPassphrase(
this@AutofillDecryptActivity,
gpgIdentifiers.first()
)
if (cachedPassphrase != null) {
decrypt(File(filePath), clientState, action, cachedPassphrase)
} else {
askPassphrase(filePath, clientState, action)
}
}
decrypt(filePath, clientState, action, authResult)
}
} 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 =
passphraseCache.retrieveCachedPassphrase(
this@AutofillDecryptActivity,
gpgIdentifiers.first()
)
if (cachedPassphrase != null) {
decryptWithPassphrase(File(filePath), clientState, action, cachedPassphrase)
} else {
askPassphrase(filePath, clientState, action)
}
}
} else {
askPassphrase(filePath, clientState, action)
}
}
}
@ -107,7 +124,7 @@ class AutofillDecryptActivity : BasePGPActivity() {
withContext(dispatcherProvider.main()) {
dialog.password.collectLatest { value ->
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")
}
private suspend fun decrypt(
private suspend fun decryptWithPassphrase(
filePath: File,
clientState: Bundle,
action: AutofillAction,

View file

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