aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/ui/src/main/java/com/wireguard/android/util/BiometricAuthenticator.kt
diff options
context:
space:
mode:
Diffstat (limited to 'ui/src/main/java/com/wireguard/android/util/BiometricAuthenticator.kt')
-rw-r--r--ui/src/main/java/com/wireguard/android/util/BiometricAuthenticator.kt69
1 files changed, 29 insertions, 40 deletions
diff --git a/ui/src/main/java/com/wireguard/android/util/BiometricAuthenticator.kt b/ui/src/main/java/com/wireguard/android/util/BiometricAuthenticator.kt
index aed8a4f2..064ea04d 100644
--- a/ui/src/main/java/com/wireguard/android/util/BiometricAuthenticator.kt
+++ b/ui/src/main/java/com/wireguard/android/util/BiometricAuthenticator.kt
@@ -1,28 +1,27 @@
/*
- * Copyright © 2020 WireGuard LLC. All Rights Reserved.
+ * Copyright © 2017-2025 WireGuard LLC. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
package com.wireguard.android.util
-import android.annotation.SuppressLint
-import android.app.KeyguardManager
-import android.content.Context
-import android.os.Build
import android.os.Handler
+import android.os.Looper
import android.util.Log
import androidx.annotation.StringRes
-import androidx.biometric.BiometricConstants
import androidx.biometric.BiometricManager
+import androidx.biometric.BiometricManager.Authenticators
import androidx.biometric.BiometricPrompt
-import androidx.core.content.getSystemService
import androidx.fragment.app.Fragment
import com.wireguard.android.R
object BiometricAuthenticator {
private const val TAG = "WireGuard/BiometricAuthenticator"
- private val handler = Handler()
+
+ // Not all devices support strong biometric auth so we're allowing both device credentials as
+ // well as weak biometrics.
+ private const val allowedAuthenticators = Authenticators.DEVICE_CREDENTIAL or Authenticators.BIOMETRIC_WEAK
sealed class Result {
data class Success(val cryptoObject: BiometricPrompt.CryptoObject?) : Result()
@@ -31,40 +30,30 @@ object BiometricAuthenticator {
object Cancelled : Result()
}
- @SuppressLint("PrivateApi")
- private fun isPinEnabled(context: Context): Boolean {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
- return context.getSystemService<KeyguardManager>()!!.isDeviceSecure
- return try {
- val lockUtilsClass = Class.forName("com.android.internal.widget.LockPatternUtils")
- val lockUtils = lockUtilsClass.getConstructor(Context::class.java).newInstance(context)
- val method = lockUtilsClass.getMethod("isLockScreenDisabled")
- !(method.invoke(lockUtils) as Boolean)
- } catch (e: Exception) {
- false
- }
- }
-
fun authenticate(
- @StringRes dialogTitleRes: Int,
- fragment: Fragment,
- callback: (Result) -> Unit
+ @StringRes dialogTitleRes: Int,
+ fragment: Fragment,
+ callback: (Result) -> Unit
) {
val authCallback = object : BiometricPrompt.AuthenticationCallback() {
override fun onAuthenticationError(errorCode: Int, errString: CharSequence) {
super.onAuthenticationError(errorCode, errString)
Log.d(TAG, "BiometricAuthentication error: errorCode=$errorCode, msg=$errString")
- callback(when (errorCode) {
- BiometricConstants.ERROR_CANCELED, BiometricConstants.ERROR_USER_CANCELED,
- BiometricConstants.ERROR_NEGATIVE_BUTTON -> {
- Result.Cancelled
- }
- BiometricConstants.ERROR_HW_NOT_PRESENT, BiometricConstants.ERROR_HW_UNAVAILABLE,
- BiometricConstants.ERROR_NO_BIOMETRICS, BiometricConstants.ERROR_NO_DEVICE_CREDENTIAL -> {
- Result.HardwareUnavailableOrDisabled
+ callback(
+ when (errorCode) {
+ BiometricPrompt.ERROR_CANCELED, BiometricPrompt.ERROR_USER_CANCELED,
+ BiometricPrompt.ERROR_NEGATIVE_BUTTON -> {
+ Result.Cancelled
+ }
+
+ BiometricPrompt.ERROR_HW_NOT_PRESENT, BiometricPrompt.ERROR_HW_UNAVAILABLE,
+ BiometricPrompt.ERROR_NO_BIOMETRICS, BiometricPrompt.ERROR_NO_DEVICE_CREDENTIAL -> {
+ Result.HardwareUnavailableOrDisabled
+ }
+
+ else -> Result.Failure(errorCode, fragment.getString(R.string.biometric_auth_error_reason, errString))
}
- else -> Result.Failure(errorCode, fragment.getString(R.string.biometric_auth_error_reason, errString))
- })
+ )
}
override fun onAuthenticationFailed() {
@@ -77,12 +66,12 @@ object BiometricAuthenticator {
callback(Result.Success(result.cryptoObject))
}
}
- val biometricPrompt = BiometricPrompt(fragment, { handler.post(it) }, authCallback)
+ val biometricPrompt = BiometricPrompt(fragment, { Handler(Looper.getMainLooper()).post(it) }, authCallback)
val promptInfo = BiometricPrompt.PromptInfo.Builder()
- .setTitle(fragment.getString(dialogTitleRes))
- .setDeviceCredentialAllowed(true)
- .build()
- if (BiometricManager.from(fragment.requireContext()).canAuthenticate() == BiometricManager.BIOMETRIC_SUCCESS || isPinEnabled(fragment.requireContext())) {
+ .setTitle(fragment.getString(dialogTitleRes))
+ .setAllowedAuthenticators(allowedAuthenticators)
+ .build()
+ if (BiometricManager.from(fragment.requireContext()).canAuthenticate(allowedAuthenticators) == BiometricManager.BIOMETRIC_SUCCESS) {
biometricPrompt.authenticate(promptInfo)
} else {
callback(Result.HardwareUnavailableOrDisabled)