refactor: rework BiometricAuthenticator API

Align internal representation with the AndroidX documentation
This commit is contained in:
Harsh Shandilya 2023-12-17 18:36:34 +05:30
parent 38f63c6304
commit d9a7c46ba9
No known key found for this signature in database
5 changed files with 57 additions and 30 deletions

View File

@ -81,7 +81,7 @@ class AutofillDecryptActivity : BasePGPActivity() {
decrypt(filePath, clientState, action, authResult) decrypt(filePath, clientState, action, authResult)
} }
} else { } else {
decrypt(filePath, clientState, action, Result.Cancelled) decrypt(filePath, clientState, action, Result.CanceledByUser)
} }
} }
} }
@ -98,7 +98,8 @@ class AutofillDecryptActivity : BasePGPActivity() {
// Internally handled by the prompt dialog // Internally handled by the prompt dialog
is Result.Retry -> {} is Result.Retry -> {}
// If the dialog is dismissed for any reason, prompt for passphrase // If the dialog is dismissed for any reason, prompt for passphrase
is Result.Cancelled, is Result.CanceledBySystem,
is Result.CanceledByUser,
is Result.Failure, is Result.Failure,
is Result.HardwareUnavailableOrDisabled -> askPassphrase(filePath, clientState, action) is Result.HardwareUnavailableOrDisabled -> askPassphrase(filePath, clientState, action)
// //

View File

@ -78,7 +78,7 @@ class DecryptActivity : BasePGPActivity() {
requireKeysExist { decrypt(isError = false, authResult) } requireKeysExist { decrypt(isError = false, authResult) }
} }
} else { } else {
requireKeysExist { decrypt(isError = false, Result.Cancelled) } requireKeysExist { decrypt(isError = false, Result.CanceledByUser) }
} }
} }
@ -158,7 +158,8 @@ class DecryptActivity : BasePGPActivity() {
// Internally handled by the prompt dialog // Internally handled by the prompt dialog
is Result.Retry -> {} is Result.Retry -> {}
// If the dialog is dismissed for any reason, prompt for passphrase // If the dialog is dismissed for any reason, prompt for passphrase
is Result.Cancelled, is Result.CanceledByUser,
is Result.CanceledBySystem,
is Result.Failure, is Result.Failure,
is Result.HardwareUnavailableOrDisabled -> is Result.HardwareUnavailableOrDisabled ->
askPassphrase(isError, gpgIdentifiers, authResult) askPassphrase(isError, gpgIdentifiers, authResult)

View File

@ -36,7 +36,8 @@ class LaunchActivity : AppCompatActivity() {
startTargetActivity(false) startTargetActivity(false)
} }
is Result.Failure, is Result.Failure,
Result.Cancelled -> { Result.CanceledBySystem,
Result.CanceledByUser -> {
finish() finish()
} }
is Result.Retry -> {} is Result.Retry -> {}

View File

@ -42,8 +42,11 @@ object BiometricAuthenticator {
/** The biometric hardware is unavailable or disabled on a software or hardware level. */ /** The biometric hardware is unavailable or disabled on a software or hardware level. */
data object HardwareUnavailableOrDisabled : Result() data object HardwareUnavailableOrDisabled : Result()
/** The prompt was dismissed. */ /** The biometric prompt was canceled due to a user-initiated action. */
data object Cancelled : Result() data object CanceledByUser : Result()
/** The biometric prompt was canceled by the system. */
data object CanceledBySystem : Result()
} }
fun canAuthenticate(activity: FragmentActivity): Boolean { fun canAuthenticate(activity: FragmentActivity): Boolean {
@ -84,32 +87,51 @@ object BiometricAuthenticator {
super.onAuthenticationError(errorCode, errString) super.onAuthenticationError(errorCode, errString)
logcat(TAG) { "onAuthenticationError(errorCode=$errorCode, msg=$errString)" } logcat(TAG) { "onAuthenticationError(errorCode=$errorCode, msg=$errString)" }
when (errorCode) { when (errorCode) {
BiometricPrompt.ERROR_CANCELED, /** Keep in sync with [androidx.biometric.BiometricPrompt.AuthenticationError] */
BiometricPrompt.ERROR_USER_CANCELED, BiometricPrompt.ERROR_HW_UNAVAILABLE -> callback(Result.HardwareUnavailableOrDisabled)
BiometricPrompt.ERROR_NEGATIVE_BUTTON -> { BiometricPrompt.ERROR_UNABLE_TO_PROCESS -> callback(Result.Retry)
callback(Result.Cancelled) BiometricPrompt.ERROR_TIMEOUT ->
}
BiometricPrompt.ERROR_HW_NOT_PRESENT,
BiometricPrompt.ERROR_HW_UNAVAILABLE,
BiometricPrompt.ERROR_NO_BIOMETRICS,
BiometricPrompt.ERROR_NO_DEVICE_CREDENTIAL -> {
callback(Result.HardwareUnavailableOrDisabled)
}
BiometricPrompt.ERROR_LOCKOUT,
BiometricPrompt.ERROR_LOCKOUT_PERMANENT,
BiometricPrompt.ERROR_NO_SPACE,
BiometricPrompt.ERROR_TIMEOUT,
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_NO_SPACE ->
BiometricPrompt.ERROR_UNABLE_TO_PROCESS -> { callback(
callback(Result.Retry) Result.Failure(
} errorCode,
activity.getString(R.string.biometric_auth_error_reason, errString)
)
)
BiometricPrompt.ERROR_CANCELED -> callback(Result.CanceledBySystem)
BiometricPrompt.ERROR_LOCKOUT ->
callback(
Result.Failure(
errorCode,
activity.getString(R.string.biometric_auth_error_reason, errString)
)
)
BiometricPrompt.ERROR_VENDOR ->
callback(
Result.Failure(
errorCode,
activity.getString(R.string.biometric_auth_error_reason, errString)
)
)
BiometricPrompt.ERROR_LOCKOUT_PERMANENT ->
callback(
Result.Failure(
errorCode,
activity.getString(R.string.biometric_auth_error_reason, errString)
)
)
BiometricPrompt.ERROR_USER_CANCELED -> callback(Result.CanceledByUser)
BiometricPrompt.ERROR_NO_BIOMETRICS -> callback(Result.HardwareUnavailableOrDisabled)
BiometricPrompt.ERROR_HW_NOT_PRESENT -> callback(Result.HardwareUnavailableOrDisabled)
BiometricPrompt.ERROR_NEGATIVE_BUTTON -> callback(Result.CanceledByUser)
BiometricPrompt.ERROR_NO_DEVICE_CREDENTIAL ->
callback(Result.HardwareUnavailableOrDisabled)
// We cover all guaranteed values above, but [errorCode] is still an Int // We cover all guaranteed values above, but [errorCode] is still an Int
// at the end of the day so a catch-all else will always be required. // at the end of the day so a catch-all else will always be required.
else -> { else -> {

View File

@ -12,7 +12,8 @@ import app.passwordstore.data.repo.PasswordRepository
import app.passwordstore.ui.sshkeygen.SshKeyGenActivity import app.passwordstore.ui.sshkeygen.SshKeyGenActivity
import app.passwordstore.ui.sshkeygen.SshKeyImportActivity import app.passwordstore.ui.sshkeygen.SshKeyImportActivity
import app.passwordstore.util.auth.BiometricAuthenticator import app.passwordstore.util.auth.BiometricAuthenticator
import app.passwordstore.util.auth.BiometricAuthenticator.Result.Cancelled import app.passwordstore.util.auth.BiometricAuthenticator.Result.CanceledBySystem
import app.passwordstore.util.auth.BiometricAuthenticator.Result.CanceledByUser
import app.passwordstore.util.auth.BiometricAuthenticator.Result.Failure import app.passwordstore.util.auth.BiometricAuthenticator.Result.Failure
import app.passwordstore.util.auth.BiometricAuthenticator.Result.Retry import app.passwordstore.util.auth.BiometricAuthenticator.Result.Retry
import app.passwordstore.util.auth.BiometricAuthenticator.Result.Success import app.passwordstore.util.auth.BiometricAuthenticator.Result.Success
@ -183,10 +184,11 @@ abstract class GitOperation(protected val callingActivity: FragmentActivity) {
is Success -> { is Success -> {
registerAuthProviders(SshAuthMethod.SshKey(authActivity)) registerAuthProviders(SshAuthMethod.SshKey(authActivity))
} }
is Cancelled -> { is CanceledByUser -> {
return Err(SSHException(DisconnectReason.AUTH_CANCELLED_BY_USER)) return Err(SSHException(DisconnectReason.AUTH_CANCELLED_BY_USER))
} }
is Failure -> { is Failure,
is CanceledBySystem -> {
throw IllegalStateException("Biometric authentication failures should be ignored") throw IllegalStateException("Biometric authentication failures should be ignored")
} }
else -> { else -> {