aboutsummaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
authorHarsh Shandilya <me@msfjarvis.dev>2021-12-29 16:05:19 +0530
committerGitHub <noreply@github.com>2021-12-29 10:35:19 +0000
commit4c9413709d58594a6d2c1e2bdbf854ec4a7fc291 (patch)
tree927c818c22f0094974a4e0499f335da0260de076 /app
parent8b5be3f7857605dd0c152610fbf2fb750f717b67 (diff)
Refactor BiometricAuthenticator and add proper support for retries (#1627)
Diffstat (limited to 'app')
-rw-r--r--app/src/main/java/dev/msfjarvis/aps/ui/main/LaunchActivity.kt12
-rw-r--r--app/src/main/java/dev/msfjarvis/aps/ui/settings/GeneralSettings.kt4
-rw-r--r--app/src/main/java/dev/msfjarvis/aps/ui/sshkeygen/SshKeyGenActivity.kt9
-rw-r--r--app/src/main/java/dev/msfjarvis/aps/util/auth/BiometricAuthenticator.kt39
-rw-r--r--app/src/main/java/dev/msfjarvis/aps/util/git/operation/GitOperation.kt9
5 files changed, 57 insertions, 16 deletions
diff --git a/app/src/main/java/dev/msfjarvis/aps/ui/main/LaunchActivity.kt b/app/src/main/java/dev/msfjarvis/aps/ui/main/LaunchActivity.kt
index 629ddb9c..b5f7a593 100644
--- a/app/src/main/java/dev/msfjarvis/aps/ui/main/LaunchActivity.kt
+++ b/app/src/main/java/dev/msfjarvis/aps/ui/main/LaunchActivity.kt
@@ -14,6 +14,7 @@ import dev.msfjarvis.aps.ui.crypto.BasePgpActivity
import dev.msfjarvis.aps.ui.crypto.DecryptActivity
import dev.msfjarvis.aps.ui.passwords.PasswordStore
import dev.msfjarvis.aps.util.auth.BiometricAuthenticator
+import dev.msfjarvis.aps.util.auth.BiometricAuthenticator.Result
import dev.msfjarvis.aps.util.extensions.sharedPrefs
import dev.msfjarvis.aps.util.settings.PreferenceKeys
@@ -23,18 +24,19 @@ class LaunchActivity : AppCompatActivity() {
super.onCreate(savedInstanceState)
val prefs = sharedPrefs
if (prefs.getBoolean(PreferenceKeys.BIOMETRIC_AUTH, false)) {
- BiometricAuthenticator.authenticate(this) {
- when (it) {
- is BiometricAuthenticator.Result.Success -> {
+ BiometricAuthenticator.authenticate(this) { result ->
+ when (result) {
+ is Result.Success -> {
startTargetActivity(false)
}
- is BiometricAuthenticator.Result.HardwareUnavailableOrDisabled -> {
+ is Result.HardwareUnavailableOrDisabled -> {
prefs.edit { remove(PreferenceKeys.BIOMETRIC_AUTH) }
startTargetActivity(false)
}
- is BiometricAuthenticator.Result.Failure, BiometricAuthenticator.Result.Cancelled -> {
+ is Result.Failure, Result.Cancelled -> {
finish()
}
+ is Result.Retry -> {}
}
}
} else {
diff --git a/app/src/main/java/dev/msfjarvis/aps/ui/settings/GeneralSettings.kt b/app/src/main/java/dev/msfjarvis/aps/ui/settings/GeneralSettings.kt
index 1e67a2b5..f78f2cb2 100644
--- a/app/src/main/java/dev/msfjarvis/aps/ui/settings/GeneralSettings.kt
+++ b/app/src/main/java/dev/msfjarvis/aps/ui/settings/GeneralSettings.kt
@@ -17,6 +17,7 @@ import de.Maxr1998.modernpreferences.helpers.singleChoice
import de.Maxr1998.modernpreferences.preferences.choice.SelectionItem
import dev.msfjarvis.aps.R
import dev.msfjarvis.aps.util.auth.BiometricAuthenticator
+import dev.msfjarvis.aps.util.auth.BiometricAuthenticator.Result
import dev.msfjarvis.aps.util.extensions.sharedPrefs
import dev.msfjarvis.aps.util.settings.PreferenceKeys
@@ -73,11 +74,12 @@ class GeneralSettings(private val activity: FragmentActivity) : SettingsProvider
activity.sharedPrefs.edit {
BiometricAuthenticator.authenticate(activity) { result ->
when (result) {
- is BiometricAuthenticator.Result.Success -> {
+ is Result.Success -> {
// Apply the changes
putBoolean(PreferenceKeys.BIOMETRIC_AUTH, checked)
enabled = true
}
+ is Result.Retry -> {}
else -> {
// If any error occurs, revert back to the previous
// state. This
diff --git a/app/src/main/java/dev/msfjarvis/aps/ui/sshkeygen/SshKeyGenActivity.kt b/app/src/main/java/dev/msfjarvis/aps/ui/sshkeygen/SshKeyGenActivity.kt
index 0d8ffcbc..63abdf7c 100644
--- a/app/src/main/java/dev/msfjarvis/aps/ui/sshkeygen/SshKeyGenActivity.kt
+++ b/app/src/main/java/dev/msfjarvis/aps/ui/sshkeygen/SshKeyGenActivity.kt
@@ -22,6 +22,7 @@ import dev.msfjarvis.aps.R
import dev.msfjarvis.aps.databinding.ActivitySshKeygenBinding
import dev.msfjarvis.aps.injection.prefs.GitPreferences
import dev.msfjarvis.aps.util.auth.BiometricAuthenticator
+import dev.msfjarvis.aps.util.auth.BiometricAuthenticator.Result
import dev.msfjarvis.aps.util.extensions.keyguardManager
import dev.msfjarvis.aps.util.extensions.viewBinding
import dev.msfjarvis.aps.util.git.sshj.SshKey
@@ -121,17 +122,17 @@ class SshKeyGenActivity : AppCompatActivity() {
if (requireAuthentication) {
val result =
withContext(Dispatchers.Main) {
- suspendCoroutine<BiometricAuthenticator.Result> { cont ->
+ suspendCoroutine<Result> { cont ->
BiometricAuthenticator.authenticate(
this@SshKeyGenActivity,
R.string.biometric_prompt_title_ssh_keygen
- ) {
+ ) { result ->
// Do not cancel on failed attempts as these are handled by the authenticator UI.
- if (it !is BiometricAuthenticator.Result.Failure) cont.resume(it)
+ if (result !is Result.Retry) cont.resume(result)
}
}
}
- if (result !is BiometricAuthenticator.Result.Success)
+ if (result !is Result.Success)
throw UserNotAuthenticatedException(getString(R.string.biometric_auth_generic_failure))
}
keyGenType.generateKey(requireAuthentication)
diff --git a/app/src/main/java/dev/msfjarvis/aps/util/auth/BiometricAuthenticator.kt b/app/src/main/java/dev/msfjarvis/aps/util/auth/BiometricAuthenticator.kt
index a582337b..50f11b5b 100644
--- a/app/src/main/java/dev/msfjarvis/aps/util/auth/BiometricAuthenticator.kt
+++ b/app/src/main/java/dev/msfjarvis/aps/util/auth/BiometricAuthenticator.kt
@@ -21,10 +21,28 @@ object BiometricAuthenticator {
private const val validAuthenticators =
Authenticators.DEVICE_CREDENTIAL or Authenticators.BIOMETRIC_WEAK
+ /**
+ * Sealed class to wrap [BiometricPrompt]'s [Int]-based return codes into more easily-interpreted
+ * types.
+ */
sealed class Result {
+
+ /** Biometric authentication was a success. */
data class Success(val cryptoObject: BiometricPrompt.CryptoObject?) : Result()
+
+ /** Biometric authentication has irreversibly failed. */
data class Failure(val code: Int?, val message: CharSequence) : Result()
+
+ /**
+ * An incorrect biometric was entered, but the prompt UI is offering the option to retry the
+ * operation.
+ */
+ object Retry : Result()
+
+ /** The biometric hardware is unavailable or disabled on a software or hardware level. */
object HardwareUnavailableOrDisabled : Result()
+
+ /** The prompt was dismissed. */
object Cancelled : Result()
}
@@ -56,18 +74,35 @@ object BiometricAuthenticator {
BiometricPrompt.ERROR_NO_DEVICE_CREDENTIAL -> {
Result.HardwareUnavailableOrDisabled
}
- else ->
+ BiometricPrompt.ERROR_LOCKOUT,
+ BiometricPrompt.ERROR_LOCKOUT_PERMANENT,
+ BiometricPrompt.ERROR_NO_SPACE,
+ BiometricPrompt.ERROR_TIMEOUT,
+ BiometricPrompt.ERROR_VENDOR -> {
+ Result.Failure(
+ errorCode,
+ activity.getString(R.string.biometric_auth_error_reason, errString)
+ )
+ }
+ BiometricPrompt.ERROR_UNABLE_TO_PROCESS -> {
+ Result.Retry
+ }
+ // 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 -> {
Result.Failure(
errorCode,
activity.getString(R.string.biometric_auth_error_reason, errString)
)
+ }
}
)
}
override fun onAuthenticationFailed() {
super.onAuthenticationFailed()
- callback(Result.Failure(null, activity.getString(R.string.biometric_auth_error)))
+ callback(Result.Retry)
}
override fun onAuthenticationSucceeded(result: BiometricPrompt.AuthenticationResult) {
diff --git a/app/src/main/java/dev/msfjarvis/aps/util/git/operation/GitOperation.kt b/app/src/main/java/dev/msfjarvis/aps/util/git/operation/GitOperation.kt
index 736b69c2..141de348 100644
--- a/app/src/main/java/dev/msfjarvis/aps/util/git/operation/GitOperation.kt
+++ b/app/src/main/java/dev/msfjarvis/aps/util/git/operation/GitOperation.kt
@@ -22,6 +22,7 @@ import dev.msfjarvis.aps.data.repo.PasswordRepository
import dev.msfjarvis.aps.ui.sshkeygen.SshKeyGenActivity
import dev.msfjarvis.aps.ui.sshkeygen.SshKeyImportActivity
import dev.msfjarvis.aps.util.auth.BiometricAuthenticator
+import dev.msfjarvis.aps.util.auth.BiometricAuthenticator.Result.*
import dev.msfjarvis.aps.util.git.GitCommandExecutor
import dev.msfjarvis.aps.util.git.sshj.ContinuationContainerActivity
import dev.msfjarvis.aps.util.git.sshj.SshAuthMethod
@@ -172,17 +173,17 @@ abstract class GitOperation(protected val callingActivity: FragmentActivity) {
BiometricAuthenticator.authenticate(
callingActivity,
R.string.biometric_prompt_title_ssh_auth
- ) { if (it !is BiometricAuthenticator.Result.Failure) cont.resume(it) }
+ ) { result -> if (result !is Failure) cont.resume(result) }
}
}
when (result) {
- is BiometricAuthenticator.Result.Success -> {
+ is Success -> {
registerAuthProviders(SshAuthMethod.SshKey(authActivity))
}
- is BiometricAuthenticator.Result.Cancelled -> {
+ is Cancelled -> {
return Err(SSHException(DisconnectReason.AUTH_CANCELLED_BY_USER))
}
- is BiometricAuthenticator.Result.Failure -> {
+ is Failure -> {
throw IllegalStateException("Biometric authentication failures should be ignored")
}
else -> {