From 9a1a54a6fcfa6fd6cf142f2af9804375255d14cf Mon Sep 17 00:00:00 2001 From: Harsh Shandilya Date: Wed, 2 Oct 2019 11:00:45 +0530 Subject: Initial biometric authentication support (#541) * [WIP] Initial biometric authentication support * Redirect decryption app shortcut to go through LaunchActivity * UserPreference: Clear existing shortcuts when toggling password auth Clears out any auth-bypassed entries that exist * Fix hilarious copypasta derp Signed-off-by: Harsh Shandilya --- .../pwdstore/utils/auth/AuthenticationResult.kt | 14 +++++ .../com/zeapo/pwdstore/utils/auth/Authenticator.kt | 63 ++++++++++++++++++++++ 2 files changed, 77 insertions(+) create mode 100644 app/src/main/java/com/zeapo/pwdstore/utils/auth/AuthenticationResult.kt create mode 100644 app/src/main/java/com/zeapo/pwdstore/utils/auth/Authenticator.kt (limited to 'app/src/main/java/com/zeapo/pwdstore/utils') diff --git a/app/src/main/java/com/zeapo/pwdstore/utils/auth/AuthenticationResult.kt b/app/src/main/java/com/zeapo/pwdstore/utils/auth/AuthenticationResult.kt new file mode 100644 index 00000000..d8530ba3 --- /dev/null +++ b/app/src/main/java/com/zeapo/pwdstore/utils/auth/AuthenticationResult.kt @@ -0,0 +1,14 @@ +package com.zeapo.pwdstore.utils.auth + +import androidx.biometric.BiometricPrompt + +internal sealed class AuthenticationResult { + internal data class Success(val cryptoObject: BiometricPrompt.CryptoObject?) : + AuthenticationResult() + internal data class RecoverableError(val code: Int, val message: CharSequence) : + AuthenticationResult() + internal data class UnrecoverableError(val code: Int, val message: CharSequence) : + AuthenticationResult() + internal object Failure : AuthenticationResult() + internal object Cancelled : AuthenticationResult() +} diff --git a/app/src/main/java/com/zeapo/pwdstore/utils/auth/Authenticator.kt b/app/src/main/java/com/zeapo/pwdstore/utils/auth/Authenticator.kt new file mode 100644 index 00000000..5139ef01 --- /dev/null +++ b/app/src/main/java/com/zeapo/pwdstore/utils/auth/Authenticator.kt @@ -0,0 +1,63 @@ +package com.zeapo.pwdstore.utils.auth + +import android.os.Handler +import android.util.Log +import androidx.biometric.BiometricManager +import androidx.biometric.BiometricPrompt +import androidx.fragment.app.FragmentActivity +import com.zeapo.pwdstore.R + +internal class Authenticator( + private val fragmentActivity: FragmentActivity, + private val callback: (AuthenticationResult) -> Unit +) { + private val handler = Handler() + private val biometricManager = BiometricManager.from(fragmentActivity) + + private val authCallback = object : BiometricPrompt.AuthenticationCallback() { + + override fun onAuthenticationError(errorCode: Int, errString: CharSequence) { + super.onAuthenticationError(errorCode, errString) + Log.d(TAG,"Error: $errorCode: $errString") + callback(AuthenticationResult.UnrecoverableError(errorCode, errString)) + } + + override fun onAuthenticationFailed() { + super.onAuthenticationFailed() + Log.d(TAG, "Failed") + callback(AuthenticationResult.Failure) + } + + override fun onAuthenticationSucceeded(result: BiometricPrompt.AuthenticationResult) { + super.onAuthenticationSucceeded(result) + Log.d(TAG, "Success") + callback(AuthenticationResult.Success(result.cryptoObject)) + } + } + + private val biometricPrompt = BiometricPrompt( + fragmentActivity, + { runnable -> handler.post(runnable) }, + authCallback + ) + + private val promptInfo = BiometricPrompt.PromptInfo.Builder() + .setTitle(fragmentActivity.getString(R.string.biometric_prompt_title)) + .setNegativeButtonText(fragmentActivity.getString(R.string.biometric_prompt_negative_text)) + .build() + + fun authenticate() { + if (biometricManager.canAuthenticate() != BiometricManager.BIOMETRIC_SUCCESS) { + callback(AuthenticationResult.UnrecoverableError( + 0, + fragmentActivity.getString(R.string.biometric_prompt_no_hardware) + )) + } else { + biometricPrompt.authenticate(promptInfo) + } + } + + companion object { + private const val TAG = "Authenticator" + } +} -- cgit v1.2.3