From d9a7c46ba9464598320693a3aa2ad4c8784d90df Mon Sep 17 00:00:00 2001 From: Harsh Shandilya Date: Sun, 17 Dec 2023 18:36:34 +0530 Subject: refactor: rework `BiometricAuthenticator` API Align internal representation with the AndroidX documentation --- .../ui/autofill/AutofillDecryptActivity.kt | 5 +- .../app/passwordstore/ui/crypto/DecryptActivity.kt | 5 +- .../app/passwordstore/ui/main/LaunchActivity.kt | 3 +- .../util/auth/BiometricAuthenticator.kt | 66 ++++++++++++++-------- .../util/git/operation/GitOperation.kt | 8 ++- 5 files changed, 57 insertions(+), 30 deletions(-) (limited to 'app') diff --git a/app/src/main/java/app/passwordstore/ui/autofill/AutofillDecryptActivity.kt b/app/src/main/java/app/passwordstore/ui/autofill/AutofillDecryptActivity.kt index 98eadb3f..e6e14fcf 100644 --- a/app/src/main/java/app/passwordstore/ui/autofill/AutofillDecryptActivity.kt +++ b/app/src/main/java/app/passwordstore/ui/autofill/AutofillDecryptActivity.kt @@ -81,7 +81,7 @@ class AutofillDecryptActivity : BasePGPActivity() { decrypt(filePath, clientState, action, authResult) } } 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 is Result.Retry -> {} // 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.HardwareUnavailableOrDisabled -> askPassphrase(filePath, clientState, action) // diff --git a/app/src/main/java/app/passwordstore/ui/crypto/DecryptActivity.kt b/app/src/main/java/app/passwordstore/ui/crypto/DecryptActivity.kt index d9472d5d..9fb20af2 100644 --- a/app/src/main/java/app/passwordstore/ui/crypto/DecryptActivity.kt +++ b/app/src/main/java/app/passwordstore/ui/crypto/DecryptActivity.kt @@ -78,7 +78,7 @@ class DecryptActivity : BasePGPActivity() { requireKeysExist { decrypt(isError = false, authResult) } } } 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 is Result.Retry -> {} // 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.HardwareUnavailableOrDisabled -> askPassphrase(isError, gpgIdentifiers, authResult) diff --git a/app/src/main/java/app/passwordstore/ui/main/LaunchActivity.kt b/app/src/main/java/app/passwordstore/ui/main/LaunchActivity.kt index 1f08f529..91c826ce 100644 --- a/app/src/main/java/app/passwordstore/ui/main/LaunchActivity.kt +++ b/app/src/main/java/app/passwordstore/ui/main/LaunchActivity.kt @@ -36,7 +36,8 @@ class LaunchActivity : AppCompatActivity() { startTargetActivity(false) } is Result.Failure, - Result.Cancelled -> { + Result.CanceledBySystem, + Result.CanceledByUser -> { finish() } is Result.Retry -> {} diff --git a/app/src/main/java/app/passwordstore/util/auth/BiometricAuthenticator.kt b/app/src/main/java/app/passwordstore/util/auth/BiometricAuthenticator.kt index 4e862f2d..c6cd5820 100644 --- a/app/src/main/java/app/passwordstore/util/auth/BiometricAuthenticator.kt +++ b/app/src/main/java/app/passwordstore/util/auth/BiometricAuthenticator.kt @@ -42,8 +42,11 @@ object BiometricAuthenticator { /** The biometric hardware is unavailable or disabled on a software or hardware level. */ data object HardwareUnavailableOrDisabled : Result() - /** The prompt was dismissed. */ - data object Cancelled : Result() + /** The biometric prompt was canceled due to a user-initiated action. */ + data object CanceledByUser : Result() + + /** The biometric prompt was canceled by the system. */ + data object CanceledBySystem : Result() } fun canAuthenticate(activity: FragmentActivity): Boolean { @@ -84,32 +87,51 @@ object BiometricAuthenticator { super.onAuthenticationError(errorCode, errString) logcat(TAG) { "onAuthenticationError(errorCode=$errorCode, msg=$errString)" } when (errorCode) { - BiometricPrompt.ERROR_CANCELED, - BiometricPrompt.ERROR_USER_CANCELED, - BiometricPrompt.ERROR_NEGATIVE_BUTTON -> { - callback(Result.Cancelled) - } - 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 -> { + /** Keep in sync with [androidx.biometric.BiometricPrompt.AuthenticationError] */ + BiometricPrompt.ERROR_HW_UNAVAILABLE -> callback(Result.HardwareUnavailableOrDisabled) + BiometricPrompt.ERROR_UNABLE_TO_PROCESS -> callback(Result.Retry) + BiometricPrompt.ERROR_TIMEOUT -> callback( Result.Failure( errorCode, activity.getString(R.string.biometric_auth_error_reason, errString) ) ) - } - BiometricPrompt.ERROR_UNABLE_TO_PROCESS -> { - callback(Result.Retry) - } + BiometricPrompt.ERROR_NO_SPACE -> + callback( + 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 // at the end of the day so a catch-all else will always be required. else -> { diff --git a/app/src/main/java/app/passwordstore/util/git/operation/GitOperation.kt b/app/src/main/java/app/passwordstore/util/git/operation/GitOperation.kt index 89194b79..5887903d 100644 --- a/app/src/main/java/app/passwordstore/util/git/operation/GitOperation.kt +++ b/app/src/main/java/app/passwordstore/util/git/operation/GitOperation.kt @@ -12,7 +12,8 @@ import app.passwordstore.data.repo.PasswordRepository import app.passwordstore.ui.sshkeygen.SshKeyGenActivity import app.passwordstore.ui.sshkeygen.SshKeyImportActivity 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.Retry import app.passwordstore.util.auth.BiometricAuthenticator.Result.Success @@ -183,10 +184,11 @@ abstract class GitOperation(protected val callingActivity: FragmentActivity) { is Success -> { registerAuthProviders(SshAuthMethod.SshKey(authActivity)) } - is Cancelled -> { + is CanceledByUser -> { return Err(SSHException(DisconnectReason.AUTH_CANCELLED_BY_USER)) } - is Failure -> { + is Failure, + is CanceledBySystem -> { throw IllegalStateException("Biometric authentication failures should be ignored") } else -> { -- cgit v1.2.3