Biometric unlock in priority and device unlock when biometric not available

This commit is contained in:
J-Jamet
2020-12-14 17:51:18 +01:00
parent dc02a8d78c
commit e633c7a861
5 changed files with 38 additions and 27 deletions

View File

@@ -151,7 +151,8 @@ class AdvancedUnlockFragment: StylishFragment(), AdvancedUnlockManager.AdvancedU
fun loadDatabase(databaseUri: Uri?, autoOpenPrompt: Boolean) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
// To get device credential unlock result, only if same database uri
if (databaseUri != null && mAdvancedUnlockEnabled) {
if (databaseUri != null
&& mAdvancedUnlockEnabled) {
activityResult?.let {
if (databaseUri == databaseFileUri) {
advancedUnlockManager?.onActivityResult(it.requestCode, it.resultCode)
@@ -175,14 +176,7 @@ class AdvancedUnlockFragment: StylishFragment(), AdvancedUnlockManager.AdvancedU
fun checkUnlockAvailability() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
allowOpenBiometricPrompt = true
if (PreferencesUtil.isDeviceCredentialUnlockEnable(requireContext())) {
mAdvancedUnlockInfoView?.setIconResource(R.drawable.bolt)
if (AdvancedUnlockManager.isDeviceSecure(requireContext())) {
selectMode()
} else {
toggleMode(Mode.DEVICE_CREDENTIAL_OR_BIOMETRIC_NOT_CONFIGURED)
}
} else if (PreferencesUtil.isBiometricUnlockEnable(requireContext())) {
if (PreferencesUtil.isBiometricUnlockEnable(requireContext())) {
mAdvancedUnlockInfoView?.setIconResource(R.drawable.fingerprint)
// biometric not supported (by API level or hardware) so keep option hidden
@@ -202,6 +196,13 @@ class AdvancedUnlockFragment: StylishFragment(), AdvancedUnlockManager.AdvancedU
selectMode()
}
}
} else if (PreferencesUtil.isDeviceCredentialUnlockEnable(requireContext())) {
mAdvancedUnlockInfoView?.setIconResource(R.drawable.bolt)
if (AdvancedUnlockManager.isDeviceSecure(requireContext())) {
selectMode()
} else {
toggleMode(Mode.DEVICE_CREDENTIAL_OR_BIOMETRIC_NOT_CONFIGURED)
}
}
}
}

View File

@@ -71,8 +71,8 @@ class AdvancedUnlockManager(private var retrieveContext: () -> FragmentActivity)
private var isKeyManagerInit = false
private val deviceCredentialUnlockEnable = PreferencesUtil.isDeviceCredentialUnlockEnable(retrieveContext())
private val biometricUnlockEnable = PreferencesUtil.isBiometricUnlockEnable(retrieveContext())
private val deviceCredentialUnlockEnable = PreferencesUtil.isDeviceCredentialUnlockEnable(retrieveContext())
val isKeyManagerInitialized: Boolean
get() {
@@ -82,6 +82,10 @@ class AdvancedUnlockManager(private var retrieveContext: () -> FragmentActivity)
return isKeyManagerInit
}
private fun isBiometricOperation(): Boolean {
return biometricUnlockEnable || isDeviceCredentialBiometricOperation()
}
// Since Android 30, device credential is also a biometric operation
private fun isDeviceCredentialOperation(): Boolean {
return Build.VERSION.SDK_INT < Build.VERSION_CODES.R
@@ -93,13 +97,9 @@ class AdvancedUnlockManager(private var retrieveContext: () -> FragmentActivity)
&& deviceCredentialUnlockEnable
}
private fun isBiometricOperation(): Boolean {
return biometricUnlockEnable || isDeviceCredentialBiometricOperation()
}
init {
if (isDeviceSecure(retrieveContext())
&& (deviceCredentialUnlockEnable || biometricUnlockEnable)) {
&& (biometricUnlockEnable || deviceCredentialUnlockEnable)) {
try {
this.keyStore = KeyStore.getInstance(ADVANCED_UNLOCK_KEYSTORE)
this.keyGenerator = KeyGenerator.getInstance(ADVANCED_UNLOCK_KEY_ALGORITHM, ADVANCED_UNLOCK_KEYSTORE)
@@ -293,13 +293,7 @@ class AdvancedUnlockManager(private var retrieveContext: () -> FragmentActivity)
retrieveContext().getString(descriptionId)
} ?: ""
if (cryptoPrompt.isDeviceCredentialOperation) {
val keyGuardManager = ContextCompat.getSystemService(retrieveContext(), KeyguardManager::class.java)
retrieveContext().startActivityForResult(
keyGuardManager?.createConfirmDeviceCredentialIntent(promptTitle, promptDescription),
REQUEST_DEVICE_CREDENTIAL)
}
else if (cryptoPrompt.isBiometricOperation) {
if (cryptoPrompt.isBiometricOperation) {
val promptInfoExtractCredential = BiometricPrompt.PromptInfo.Builder().apply {
setTitle(promptTitle)
if (promptDescription.isNotEmpty())
@@ -311,11 +305,16 @@ class AdvancedUnlockManager(private var retrieveContext: () -> FragmentActivity)
setNegativeButtonText(retrieveContext().getString(android.R.string.cancel))
}
}.build()
biometricPrompt?.authenticate(
promptInfoExtractCredential,
BiometricPrompt.CryptoObject(cryptoPrompt.cipher))
}
else if (cryptoPrompt.isDeviceCredentialOperation) {
val keyGuardManager = ContextCompat.getSystemService(retrieveContext(), KeyguardManager::class.java)
retrieveContext().startActivityForResult(
keyGuardManager?.createConfirmDeviceCredentialIntent(promptTitle, promptDescription),
REQUEST_DEVICE_CREDENTIAL)
}
}
@Synchronized

View File

@@ -62,12 +62,12 @@ class AdvancedUnlockNotificationService : NotificationService() {
action = ACTION_REMOVE_KEYS
}
val pendingDeleteIntent = PendingIntent.getService(this, 0, deleteIntent, PendingIntent.FLAG_UPDATE_CURRENT)
val deviceCredential = PreferencesUtil.isDeviceCredentialUnlockEnable(this)
val biometricUnlockEnabled = PreferencesUtil.isBiometricUnlockEnable(this)
val notificationBuilder = buildNewNotification().apply {
setSmallIcon(if (deviceCredential) {
R.drawable.notification_ic_device_unlock_24dp
} else {
setSmallIcon(if (biometricUnlockEnabled) {
R.drawable.notification_ic_fingerprint_unlock_24dp
} else {
R.drawable.notification_ic_device_unlock_24dp
})
intent?.let {
setContentTitle(getString(R.string.advanced_unlock))

View File

@@ -26,6 +26,7 @@ import android.net.Uri
import androidx.preference.PreferenceManager
import com.kunzisoft.keepass.BuildConfig
import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.biometric.AdvancedUnlockManager
import com.kunzisoft.keepass.database.element.SortNodeEnum
import com.kunzisoft.keepass.timeout.TimeoutHelper
import java.util.*
@@ -240,14 +241,23 @@ object PreferencesUtil {
fun isBiometricUnlockEnable(context: Context): Boolean {
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
val biometricSupported = if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
AdvancedUnlockManager.biometricUnlockSupported(context)
} else {
false
}
return prefs.getBoolean(context.getString(R.string.biometric_unlock_enable_key),
context.resources.getBoolean(R.bool.biometric_unlock_enable_default))
&& biometricSupported
}
fun isDeviceCredentialUnlockEnable(context: Context): Boolean {
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
// Priority to biometric unlock
val biometricAlreadySupported = isBiometricUnlockEnable(context)
return prefs.getBoolean(context.getString(R.string.device_credential_unlock_enable_key),
context.resources.getBoolean(R.bool.device_credential_unlock_enable_default))
&& !biometricAlreadySupported
}
fun isTempAdvancedUnlockEnable(context: Context): Boolean {

View File

@@ -19,4 +19,5 @@
-->
<resources>
<bool name="biometric_unlock_enable_default" translatable="true">true</bool>
<bool name="device_credential_unlock_enable_default" translatable="true">true</bool>
</resources>