fix: correctly use biometrics result in passphrase cache flow
This commit is contained in:
parent
dfe4b14b4c
commit
fe7aee24d4
2 changed files with 57 additions and 31 deletions
|
@ -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,
|
||||||
|
|
|
@ -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 -> {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue