Skip to content
This repository was archived by the owner on Oct 15, 2024. It is now read-only.

Commit fe7aee2

Browse files
committed
fix: correctly use biometrics result in passphrase cache flow
1 parent dfe4b14 commit fe7aee2

File tree

2 files changed

+57
-31
lines changed

2 files changed

+57
-31
lines changed

app/src/main/java/app/passwordstore/ui/autofill/AutofillDecryptActivity.kt

Lines changed: 35 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import app.passwordstore.data.passfile.PasswordEntry
1818
import app.passwordstore.ui.crypto.BasePGPActivity
1919
import app.passwordstore.ui.crypto.PasswordDialog
2020
import app.passwordstore.util.auth.BiometricAuthenticator
21+
import app.passwordstore.util.auth.BiometricAuthenticator.Result
2122
import app.passwordstore.util.autofill.AutofillPreferences
2223
import app.passwordstore.util.autofill.AutofillResponseBuilder
2324
import app.passwordstore.util.autofill.DirectoryStructure
@@ -70,33 +71,49 @@ class AutofillDecryptActivity : BasePGPActivity() {
7071
directoryStructure = AutofillPreferences.directoryStructure(this)
7172
logcat { action.toString() }
7273
requireKeysExist {
73-
val gpgIdentifiers = getPGPIdentifiers("") ?: return@requireKeysExist
7474
if (
7575
features.isEnabled(EnablePGPPassphraseCache) && BiometricAuthenticator.canAuthenticate(this)
7676
) {
7777
BiometricAuthenticator.authenticate(
7878
this,
7979
R.string.biometric_prompt_title_gpg_passphrase_cache,
8080
) { authResult ->
81-
if (authResult is BiometricAuthenticator.Result.Success) {
82-
lifecycleScope.launch {
83-
val cachedPassphrase =
84-
passphraseCache.retrieveCachedPassphrase(
85-
this@AutofillDecryptActivity,
86-
gpgIdentifiers.first()
87-
)
88-
if (cachedPassphrase != null) {
89-
decrypt(File(filePath), clientState, action, cachedPassphrase)
90-
} else {
91-
askPassphrase(filePath, clientState, action)
92-
}
93-
}
81+
decrypt(filePath, clientState, action, authResult)
82+
}
83+
} else {
84+
decrypt(filePath, clientState, action, Result.Cancelled)
85+
}
86+
}
87+
}
88+
89+
private fun decrypt(
90+
filePath: String,
91+
clientState: Bundle,
92+
action: AutofillAction,
93+
authResult: Result,
94+
) {
95+
val gpgIdentifiers = getPGPIdentifiers("") ?: return
96+
lifecycleScope.launch(dispatcherProvider.main()) {
97+
when (authResult) {
98+
// Internally handled by the prompt dialog
99+
is Result.Retry -> {}
100+
// If the dialog is dismissed for any reason, prompt for passphrase
101+
is Result.Cancelled,
102+
is Result.Failure,
103+
is Result.HardwareUnavailableOrDisabled -> askPassphrase(filePath, clientState, action)
104+
//
105+
is Result.Success -> {
106+
val cachedPassphrase =
107+
passphraseCache.retrieveCachedPassphrase(
108+
this@AutofillDecryptActivity,
109+
gpgIdentifiers.first()
110+
)
111+
if (cachedPassphrase != null) {
112+
decryptWithPassphrase(File(filePath), clientState, action, cachedPassphrase)
94113
} else {
95114
askPassphrase(filePath, clientState, action)
96115
}
97116
}
98-
} else {
99-
askPassphrase(filePath, clientState, action)
100117
}
101118
}
102119
}
@@ -107,15 +124,15 @@ class AutofillDecryptActivity : BasePGPActivity() {
107124
withContext(dispatcherProvider.main()) {
108125
dialog.password.collectLatest { value ->
109126
if (value != null) {
110-
decrypt(File(filePath), clientState, action, value)
127+
decryptWithPassphrase(File(filePath), clientState, action, value)
111128
}
112129
}
113130
}
114131
}
115132
dialog.show(supportFragmentManager, "PASSWORD_DIALOG")
116133
}
117134

118-
private suspend fun decrypt(
135+
private suspend fun decryptWithPassphrase(
119136
filePath: File,
120137
clientState: Bundle,
121138
action: AutofillAction,

app/src/main/java/app/passwordstore/ui/crypto/DecryptActivity.kt

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import app.passwordstore.data.password.FieldItem
1818
import app.passwordstore.databinding.DecryptLayoutBinding
1919
import app.passwordstore.ui.adapters.FieldItemAdapter
2020
import app.passwordstore.util.auth.BiometricAuthenticator
21+
import app.passwordstore.util.auth.BiometricAuthenticator.Result
2122
import app.passwordstore.util.extensions.getString
2223
import app.passwordstore.util.extensions.unsafeLazy
2324
import app.passwordstore.util.extensions.viewBinding
@@ -77,7 +78,7 @@ class DecryptActivity : BasePGPActivity() {
7778
requireKeysExist { decrypt(isError = false, authResult) }
7879
}
7980
} else {
80-
requireKeysExist { decrypt(isError = false, BiometricAuthenticator.Result.Cancelled) }
81+
requireKeysExist { decrypt(isError = false, Result.Cancelled) }
8182
}
8283
}
8384

@@ -149,27 +150,35 @@ class DecryptActivity : BasePGPActivity() {
149150
)
150151
}
151152

152-
private fun decrypt(isError: Boolean, authResult: BiometricAuthenticator.Result) {
153+
private fun decrypt(isError: Boolean, authResult: Result) {
153154
val gpgIdentifiers = getPGPIdentifiers("") ?: return
154155
lifecycleScope.launch(dispatcherProvider.main()) {
155-
if (authResult is BiometricAuthenticator.Result.Success) {
156-
val cachedPassphrase =
157-
passphraseCache.retrieveCachedPassphrase(this@DecryptActivity, gpgIdentifiers.first())
158-
if (cachedPassphrase != null) {
159-
decryptWithCachedPassphrase(cachedPassphrase, gpgIdentifiers, authResult)
160-
} else {
156+
when (authResult) {
157+
// Internally handled by the prompt dialog
158+
is Result.Retry -> {}
159+
// If the dialog is dismissed for any reason, prompt for passphrase
160+
is Result.Cancelled,
161+
is Result.Failure,
162+
is Result.HardwareUnavailableOrDisabled ->
161163
askPassphrase(isError, gpgIdentifiers, authResult)
164+
//
165+
is Result.Success -> {
166+
val cachedPassphrase =
167+
passphraseCache.retrieveCachedPassphrase(this@DecryptActivity, gpgIdentifiers.first())
168+
if (cachedPassphrase != null) {
169+
decryptWithCachedPassphrase(cachedPassphrase, gpgIdentifiers, authResult)
170+
} else {
171+
askPassphrase(isError, gpgIdentifiers, authResult)
172+
}
162173
}
163-
} else {
164-
askPassphrase(isError, gpgIdentifiers, authResult)
165174
}
166175
}
167176
}
168177

169178
private fun askPassphrase(
170179
isError: Boolean,
171180
gpgIdentifiers: List<PGPIdentifier>,
172-
authResult: BiometricAuthenticator.Result,
181+
authResult: Result,
173182
) {
174183
if (retries < MAX_RETRIES) {
175184
retries += 1
@@ -189,7 +198,7 @@ class DecryptActivity : BasePGPActivity() {
189198
passwordEntry = entry
190199
createPasswordUI(entry)
191200
startAutoDismissTimer()
192-
if (authResult is BiometricAuthenticator.Result.Success) {
201+
if (authResult is Result.Success) {
193202
passphraseCache.cachePassphrase(this@DecryptActivity, gpgIdentifiers.first(), value)
194203
}
195204
}
@@ -207,7 +216,7 @@ class DecryptActivity : BasePGPActivity() {
207216
private suspend fun decryptWithCachedPassphrase(
208217
passphrase: String,
209218
identifiers: List<PGPIdentifier>,
210-
authResult: BiometricAuthenticator.Result,
219+
authResult: Result,
211220
) {
212221
when (val result = decryptWithPassphrase(passphrase, identifiers)) {
213222
is Ok -> {

0 commit comments

Comments
 (0)