mirror of
https://github.com/Kunzisoft/KeePassDX.git
synced 2025-12-04 15:49:33 +01:00
Refactoring classes
This commit is contained in:
@@ -51,7 +51,7 @@ import com.kunzisoft.keepass.activities.selection.SpecialModeActivity
|
|||||||
import com.kunzisoft.keepass.app.database.CipherDatabaseEntity
|
import com.kunzisoft.keepass.app.database.CipherDatabaseEntity
|
||||||
import com.kunzisoft.keepass.autofill.AutofillHelper
|
import com.kunzisoft.keepass.autofill.AutofillHelper
|
||||||
import com.kunzisoft.keepass.biometric.AdvancedUnlockManager
|
import com.kunzisoft.keepass.biometric.AdvancedUnlockManager
|
||||||
import com.kunzisoft.keepass.biometric.BiometricUnlockDatabaseHelper
|
import com.kunzisoft.keepass.biometric.AdvancedUnlockHelper
|
||||||
import com.kunzisoft.keepass.database.action.ProgressDatabaseTaskProvider
|
import com.kunzisoft.keepass.database.action.ProgressDatabaseTaskProvider
|
||||||
import com.kunzisoft.keepass.database.element.Database
|
import com.kunzisoft.keepass.database.element.Database
|
||||||
import com.kunzisoft.keepass.database.exception.DuplicateUuidDatabaseException
|
import com.kunzisoft.keepass.database.exception.DuplicateUuidDatabaseException
|
||||||
@@ -674,7 +674,7 @@ open class PasswordActivity : SpecialModeActivity() {
|
|||||||
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
|
||||||
&& !readOnlyEducationPerformed) {
|
&& !readOnlyEducationPerformed) {
|
||||||
val biometricCanAuthenticate = BiometricUnlockDatabaseHelper.canAuthenticate(this)
|
val biometricCanAuthenticate = AdvancedUnlockHelper.canAuthenticate(this)
|
||||||
PreferencesUtil.isAdvancedUnlockEnable(applicationContext)
|
PreferencesUtil.isAdvancedUnlockEnable(applicationContext)
|
||||||
&& (biometricCanAuthenticate == BiometricManager.BIOMETRIC_ERROR_NONE_ENROLLED || biometricCanAuthenticate == BiometricManager.BIOMETRIC_SUCCESS)
|
&& (biometricCanAuthenticate == BiometricManager.BIOMETRIC_ERROR_NONE_ENROLLED || biometricCanAuthenticate == BiometricManager.BIOMETRIC_SUCCESS)
|
||||||
&& advancedUnlockInfoView != null && advancedUnlockInfoView?.visibility == View.VISIBLE
|
&& advancedUnlockInfoView != null && advancedUnlockInfoView?.visibility == View.VISIBLE
|
||||||
@@ -727,7 +727,7 @@ open class PasswordActivity : SpecialModeActivity() {
|
|||||||
|
|
||||||
// To get device credential unlock result
|
// To get device credential unlock result
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||||
// TODO Advanced unlock response
|
advancedUnlockManager?.onActivityResult(requestCode, resultCode, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
// To get entry in result
|
// To get entry in result
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2019 Jeremy Jamet / Kunzisoft.
|
* Copyright 2020 Jeremy Jamet / Kunzisoft.
|
||||||
*
|
*
|
||||||
* This file is part of KeePassDX.
|
* This file is part of KeePassDX.
|
||||||
*
|
*
|
||||||
@@ -19,8 +19,10 @@
|
|||||||
*/
|
*/
|
||||||
package com.kunzisoft.keepass.biometric
|
package com.kunzisoft.keepass.biometric
|
||||||
|
|
||||||
|
import android.app.Activity
|
||||||
import android.app.KeyguardManager
|
import android.app.KeyguardManager
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.security.keystore.KeyGenParameterSpec
|
import android.security.keystore.KeyGenParameterSpec
|
||||||
import android.security.keystore.KeyPermanentlyInvalidatedException
|
import android.security.keystore.KeyPermanentlyInvalidatedException
|
||||||
@@ -45,15 +47,28 @@ import javax.crypto.SecretKey
|
|||||||
import javax.crypto.spec.IvParameterSpec
|
import javax.crypto.spec.IvParameterSpec
|
||||||
|
|
||||||
@RequiresApi(api = Build.VERSION_CODES.M)
|
@RequiresApi(api = Build.VERSION_CODES.M)
|
||||||
class BiometricUnlockDatabaseHelper(private val context: FragmentActivity) {
|
class AdvancedUnlockHelper(private val context: FragmentActivity) {
|
||||||
|
|
||||||
private var keyStore: KeyStore? = null
|
private var keyStore: KeyStore? = null
|
||||||
private var keyGenerator: KeyGenerator? = null
|
private var keyGenerator: KeyGenerator? = null
|
||||||
private var cipher: Cipher? = null
|
private var cipher: Cipher? = null
|
||||||
|
|
||||||
private var biometricPrompt: BiometricPrompt? = null
|
private var biometricPrompt: BiometricPrompt? = null
|
||||||
var authenticationCallback: BiometricPrompt.AuthenticationCallback? = null
|
private var authenticationCallback = object: BiometricPrompt.AuthenticationCallback() {
|
||||||
var biometricUnlockCallback: BiometricUnlockCallback? = null
|
override fun onAuthenticationSucceeded(result: BiometricPrompt.AuthenticationResult) {
|
||||||
|
advancedUnlockCallback?.onAuthenticationSucceeded()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onAuthenticationFailed() {
|
||||||
|
advancedUnlockCallback?.onAuthenticationFailed()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onAuthenticationError(errorCode: Int, errString: CharSequence) {
|
||||||
|
advancedUnlockCallback?.onAuthenticationError(errorCode, errString)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var advancedUnlockCallback: AdvancedUnlockCallback? = null
|
||||||
|
|
||||||
private var isKeyManagerInit = false
|
private var isKeyManagerInit = false
|
||||||
|
|
||||||
@@ -63,7 +78,7 @@ class BiometricUnlockDatabaseHelper(private val context: FragmentActivity) {
|
|||||||
val isKeyManagerInitialized: Boolean
|
val isKeyManagerInitialized: Boolean
|
||||||
get() {
|
get() {
|
||||||
if (!isKeyManagerInit) {
|
if (!isKeyManagerInit) {
|
||||||
biometricUnlockCallback?.onBiometricException(Exception("Biometric not initialized"))
|
advancedUnlockCallback?.onGenericException(Exception("Biometric not initialized"))
|
||||||
}
|
}
|
||||||
return isKeyManagerInit
|
return isKeyManagerInit
|
||||||
}
|
}
|
||||||
@@ -99,7 +114,7 @@ class BiometricUnlockDatabaseHelper(private val context: FragmentActivity) {
|
|||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Log.e(TAG, "Unable to initialize the keystore", e)
|
Log.e(TAG, "Unable to initialize the keystore", e)
|
||||||
isKeyManagerInit = false
|
isKeyManagerInit = false
|
||||||
biometricUnlockCallback?.onBiometricException(e)
|
advancedUnlockCallback?.onGenericException(e)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// really not much to do when no fingerprint support found
|
// really not much to do when no fingerprint support found
|
||||||
@@ -139,14 +154,14 @@ class BiometricUnlockDatabaseHelper(private val context: FragmentActivity) {
|
|||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Log.e(TAG, "Unable to create a key in keystore", e)
|
Log.e(TAG, "Unable to create a key in keystore", e)
|
||||||
biometricUnlockCallback?.onBiometricException(e)
|
advancedUnlockCallback?.onGenericException(e)
|
||||||
}
|
}
|
||||||
|
|
||||||
return keyStore.getKey(ADVANCED_UNLOCK_KEYSTORE_KEY, null) as SecretKey?
|
return keyStore.getKey(ADVANCED_UNLOCK_KEYSTORE_KEY, null) as SecretKey?
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Log.e(TAG, "Unable to retrieve the key in keystore", e)
|
Log.e(TAG, "Unable to retrieve the key in keystore", e)
|
||||||
biometricUnlockCallback?.onBiometricException(e)
|
advancedUnlockCallback?.onGenericException(e)
|
||||||
}
|
}
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
@@ -173,13 +188,13 @@ class BiometricUnlockDatabaseHelper(private val context: FragmentActivity) {
|
|||||||
}
|
}
|
||||||
} catch (unrecoverableKeyException: UnrecoverableKeyException) {
|
} catch (unrecoverableKeyException: UnrecoverableKeyException) {
|
||||||
Log.e(TAG, "Unable to initialize encrypt data", unrecoverableKeyException)
|
Log.e(TAG, "Unable to initialize encrypt data", unrecoverableKeyException)
|
||||||
biometricUnlockCallback?.onInvalidKeyException(unrecoverableKeyException)
|
advancedUnlockCallback?.onInvalidKeyException(unrecoverableKeyException)
|
||||||
} catch (invalidKeyException: KeyPermanentlyInvalidatedException) {
|
} catch (invalidKeyException: KeyPermanentlyInvalidatedException) {
|
||||||
Log.e(TAG, "Unable to initialize encrypt data", invalidKeyException)
|
Log.e(TAG, "Unable to initialize encrypt data", invalidKeyException)
|
||||||
biometricUnlockCallback?.onInvalidKeyException(invalidKeyException)
|
advancedUnlockCallback?.onInvalidKeyException(invalidKeyException)
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Log.e(TAG, "Unable to initialize encrypt data", e)
|
Log.e(TAG, "Unable to initialize encrypt data", e)
|
||||||
biometricUnlockCallback?.onBiometricException(e)
|
advancedUnlockCallback?.onGenericException(e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -194,12 +209,12 @@ class BiometricUnlockDatabaseHelper(private val context: FragmentActivity) {
|
|||||||
// passes updated iv spec on to callback so this can be stored for decryption
|
// passes updated iv spec on to callback so this can be stored for decryption
|
||||||
cipher?.parameters?.getParameterSpec(IvParameterSpec::class.java)?.let{ spec ->
|
cipher?.parameters?.getParameterSpec(IvParameterSpec::class.java)?.let{ spec ->
|
||||||
val ivSpecValue = Base64.encodeToString(spec.iv, Base64.NO_WRAP)
|
val ivSpecValue = Base64.encodeToString(spec.iv, Base64.NO_WRAP)
|
||||||
biometricUnlockCallback?.handleEncryptedResult(encryptedBase64, ivSpecValue)
|
advancedUnlockCallback?.handleEncryptedResult(encryptedBase64, ivSpecValue)
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
val exception = Exception(context.getString(R.string.keystore_not_accessible), e)
|
val exception = Exception(context.getString(R.string.keystore_not_accessible), e)
|
||||||
Log.e(TAG, "Unable to encrypt data", e)
|
Log.e(TAG, "Unable to encrypt data", e)
|
||||||
biometricUnlockCallback?.onBiometricException(exception)
|
advancedUnlockCallback?.onGenericException(exception)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -232,10 +247,10 @@ class BiometricUnlockDatabaseHelper(private val context: FragmentActivity) {
|
|||||||
deleteKeystoreKey()
|
deleteKeystoreKey()
|
||||||
} catch (invalidKeyException: KeyPermanentlyInvalidatedException) {
|
} catch (invalidKeyException: KeyPermanentlyInvalidatedException) {
|
||||||
Log.e(TAG, "Unable to initialize decrypt data", invalidKeyException)
|
Log.e(TAG, "Unable to initialize decrypt data", invalidKeyException)
|
||||||
biometricUnlockCallback?.onInvalidKeyException(invalidKeyException)
|
advancedUnlockCallback?.onInvalidKeyException(invalidKeyException)
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Log.e(TAG, "Unable to initialize decrypt data", e)
|
Log.e(TAG, "Unable to initialize decrypt data", e)
|
||||||
biometricUnlockCallback?.onBiometricException(e)
|
advancedUnlockCallback?.onGenericException(e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -247,15 +262,15 @@ class BiometricUnlockDatabaseHelper(private val context: FragmentActivity) {
|
|||||||
// actual decryption here
|
// actual decryption here
|
||||||
val encrypted = Base64.decode(encryptedValue, Base64.NO_WRAP)
|
val encrypted = Base64.decode(encryptedValue, Base64.NO_WRAP)
|
||||||
cipher?.doFinal(encrypted)?.let { decrypted ->
|
cipher?.doFinal(encrypted)?.let { decrypted ->
|
||||||
biometricUnlockCallback?.handleDecryptedResult(String(decrypted))
|
advancedUnlockCallback?.handleDecryptedResult(String(decrypted))
|
||||||
}
|
}
|
||||||
} catch (badPaddingException: BadPaddingException) {
|
} catch (badPaddingException: BadPaddingException) {
|
||||||
Log.e(TAG, "Unable to decrypt data", badPaddingException)
|
Log.e(TAG, "Unable to decrypt data", badPaddingException)
|
||||||
biometricUnlockCallback?.onInvalidKeyException(badPaddingException)
|
advancedUnlockCallback?.onInvalidKeyException(badPaddingException)
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
val exception = Exception(context.getString(R.string.keystore_not_accessible), e)
|
val exception = Exception(context.getString(R.string.keystore_not_accessible), e)
|
||||||
Log.e(TAG, "Unable to decrypt data", exception)
|
Log.e(TAG, "Unable to decrypt data", exception)
|
||||||
biometricUnlockCallback?.onBiometricException(exception)
|
advancedUnlockCallback?.onGenericException(exception)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -265,7 +280,7 @@ class BiometricUnlockDatabaseHelper(private val context: FragmentActivity) {
|
|||||||
keyStore?.deleteEntry(ADVANCED_UNLOCK_KEYSTORE_KEY)
|
keyStore?.deleteEntry(ADVANCED_UNLOCK_KEYSTORE_KEY)
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Log.e(TAG, "Unable to delete entry key in keystore", e)
|
Log.e(TAG, "Unable to delete entry key in keystore", e)
|
||||||
biometricUnlockCallback?.onBiometricException(e)
|
advancedUnlockCallback?.onGenericException(e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -274,9 +289,9 @@ class BiometricUnlockDatabaseHelper(private val context: FragmentActivity) {
|
|||||||
fun openAdvancedUnlockPrompt(cryptoPrompt: AdvancedUnlockCryptoPrompt) {
|
fun openAdvancedUnlockPrompt(cryptoPrompt: AdvancedUnlockCryptoPrompt) {
|
||||||
// Init advanced unlock prompt
|
// Init advanced unlock prompt
|
||||||
if (biometricPrompt == null) {
|
if (biometricPrompt == null) {
|
||||||
authenticationCallback?.let { callback ->
|
biometricPrompt = BiometricPrompt(context,
|
||||||
biometricPrompt = BiometricPrompt(context, Executors.newSingleThreadExecutor(), callback)
|
Executors.newSingleThreadExecutor(),
|
||||||
}
|
authenticationCallback)
|
||||||
}
|
}
|
||||||
|
|
||||||
val promptTitle = context.getString(cryptoPrompt.promptTitleId)
|
val promptTitle = context.getString(cryptoPrompt.promptTitleId)
|
||||||
@@ -310,23 +325,37 @@ class BiometricUnlockDatabaseHelper(private val context: FragmentActivity) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Synchronized
|
||||||
|
fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||||
|
if (requestCode == REQUEST_DEVICE_CREDENTIAL) {
|
||||||
|
if (resultCode == Activity.RESULT_OK) {
|
||||||
|
advancedUnlockCallback?.onAuthenticationSucceeded()
|
||||||
|
} else {
|
||||||
|
advancedUnlockCallback?.onAuthenticationFailed()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun closeBiometricPrompt() {
|
fun closeBiometricPrompt() {
|
||||||
biometricPrompt?.cancelAuthentication()
|
biometricPrompt?.cancelAuthentication()
|
||||||
}
|
}
|
||||||
|
|
||||||
interface BiometricUnlockErrorCallback {
|
interface AdvancedUnlockErrorCallback {
|
||||||
fun onInvalidKeyException(e: Exception)
|
fun onInvalidKeyException(e: Exception)
|
||||||
fun onBiometricException(e: Exception)
|
fun onGenericException(e: Exception)
|
||||||
}
|
}
|
||||||
|
|
||||||
interface BiometricUnlockCallback : BiometricUnlockErrorCallback {
|
interface AdvancedUnlockCallback : AdvancedUnlockErrorCallback {
|
||||||
|
fun onAuthenticationSucceeded()
|
||||||
|
fun onAuthenticationFailed()
|
||||||
|
fun onAuthenticationError(errorCode: Int, errString: CharSequence)
|
||||||
fun handleEncryptedResult(encryptedValue: String, ivSpec: String)
|
fun handleEncryptedResult(encryptedValue: String, ivSpec: String)
|
||||||
fun handleDecryptedResult(decryptedValue: String)
|
fun handleDecryptedResult(decryptedValue: String)
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
private val TAG = BiometricUnlockDatabaseHelper::class.java.name
|
private val TAG = AdvancedUnlockHelper::class.java.name
|
||||||
|
|
||||||
private const val ADVANCED_UNLOCK_KEYSTORE = "AndroidKeyStore"
|
private const val ADVANCED_UNLOCK_KEYSTORE = "AndroidKeyStore"
|
||||||
private const val ADVANCED_UNLOCK_KEYSTORE_KEY = "com.kunzisoft.keepass.biometric.key"
|
private const val ADVANCED_UNLOCK_KEYSTORE_KEY = "com.kunzisoft.keepass.biometric.key"
|
||||||
@@ -423,20 +452,25 @@ class BiometricUnlockDatabaseHelper(private val context: FragmentActivity) {
|
|||||||
*/
|
*/
|
||||||
@RequiresApi(api = Build.VERSION_CODES.M)
|
@RequiresApi(api = Build.VERSION_CODES.M)
|
||||||
fun deleteEntryKeyInKeystoreForBiometric(context: FragmentActivity,
|
fun deleteEntryKeyInKeystoreForBiometric(context: FragmentActivity,
|
||||||
biometricCallback: BiometricUnlockErrorCallback) {
|
advancedCallback: AdvancedUnlockErrorCallback) {
|
||||||
BiometricUnlockDatabaseHelper(context).apply {
|
AdvancedUnlockHelper(context).apply {
|
||||||
biometricUnlockCallback = object : BiometricUnlockCallback {
|
advancedUnlockCallback = object : AdvancedUnlockCallback {
|
||||||
|
override fun onAuthenticationSucceeded() {}
|
||||||
|
|
||||||
|
override fun onAuthenticationFailed() {}
|
||||||
|
|
||||||
|
override fun onAuthenticationError(errorCode: Int, errString: CharSequence) {}
|
||||||
|
|
||||||
override fun handleEncryptedResult(encryptedValue: String, ivSpec: String) {}
|
override fun handleEncryptedResult(encryptedValue: String, ivSpec: String) {}
|
||||||
|
|
||||||
override fun handleDecryptedResult(decryptedValue: String) {}
|
override fun handleDecryptedResult(decryptedValue: String) {}
|
||||||
|
|
||||||
override fun onInvalidKeyException(e: Exception) {
|
override fun onInvalidKeyException(e: Exception) {
|
||||||
biometricCallback.onInvalidKeyException(e)
|
advancedCallback.onInvalidKeyException(e)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onBiometricException(e: Exception) {
|
override fun onGenericException(e: Exception) {
|
||||||
biometricCallback.onBiometricException(e)
|
advancedCallback.onGenericException(e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
deleteKeystoreKey()
|
deleteKeystoreKey()
|
||||||
@@ -48,9 +48,9 @@ class AdvancedUnlockManager(var context: FragmentActivity,
|
|||||||
var passwordView: TextView?,
|
var passwordView: TextView?,
|
||||||
private var loadDatabaseAfterRegisterCredentials: (encryptedPassword: String?, ivSpec: String?) -> Unit,
|
private var loadDatabaseAfterRegisterCredentials: (encryptedPassword: String?, ivSpec: String?) -> Unit,
|
||||||
private var loadDatabaseAfterRetrieveCredentials: (decryptedPassword: String?) -> Unit)
|
private var loadDatabaseAfterRetrieveCredentials: (decryptedPassword: String?) -> Unit)
|
||||||
: BiometricUnlockDatabaseHelper.BiometricUnlockCallback {
|
: AdvancedUnlockHelper.AdvancedUnlockCallback {
|
||||||
|
|
||||||
private var biometricUnlockDatabaseHelper: BiometricUnlockDatabaseHelper? = null
|
private var advancedUnlockHelper: AdvancedUnlockHelper? = null
|
||||||
private var biometricMode: Mode = Mode.BIOMETRIC_UNAVAILABLE
|
private var biometricMode: Mode = Mode.BIOMETRIC_UNAVAILABLE
|
||||||
|
|
||||||
// Only to fix multiple fingerprint menu #332
|
// Only to fix multiple fingerprint menu #332
|
||||||
@@ -104,7 +104,7 @@ class AdvancedUnlockManager(var context: FragmentActivity,
|
|||||||
|
|
||||||
// biometric not supported (by API level or hardware) so keep option hidden
|
// biometric not supported (by API level or hardware) so keep option hidden
|
||||||
// or manually disable
|
// or manually disable
|
||||||
val biometricCanAuthenticate = BiometricUnlockDatabaseHelper.canAuthenticate(context)
|
val biometricCanAuthenticate = AdvancedUnlockHelper.canAuthenticate(context)
|
||||||
allowOpenBiometricPrompt = true
|
allowOpenBiometricPrompt = true
|
||||||
|
|
||||||
if (!PreferencesUtil.isAdvancedUnlockEnable(context)
|
if (!PreferencesUtil.isAdvancedUnlockEnable(context)
|
||||||
@@ -120,14 +120,13 @@ class AdvancedUnlockManager(var context: FragmentActivity,
|
|||||||
} else {
|
} else {
|
||||||
// Check if fingerprint well init (be called the first time the fingerprint is configured
|
// Check if fingerprint well init (be called the first time the fingerprint is configured
|
||||||
// and the activity still active)
|
// and the activity still active)
|
||||||
if (biometricUnlockDatabaseHelper?.isKeyManagerInitialized != true) {
|
if (advancedUnlockHelper?.isKeyManagerInitialized != true) {
|
||||||
biometricUnlockDatabaseHelper = BiometricUnlockDatabaseHelper(context)
|
advancedUnlockHelper = AdvancedUnlockHelper(context)
|
||||||
// callback for fingerprint findings
|
// callback for fingerprint findings
|
||||||
biometricUnlockDatabaseHelper?.biometricUnlockCallback = this
|
advancedUnlockHelper?.advancedUnlockCallback = this
|
||||||
biometricUnlockDatabaseHelper?.authenticationCallback = biometricAuthenticationCallback
|
|
||||||
}
|
}
|
||||||
// Recheck to change the mode
|
// Recheck to change the mode
|
||||||
if (biometricUnlockDatabaseHelper?.isKeyManagerInitialized != true) {
|
if (advancedUnlockHelper?.isKeyManagerInitialized != true) {
|
||||||
toggleMode(Mode.KEY_MANAGER_UNAVAILABLE)
|
toggleMode(Mode.KEY_MANAGER_UNAVAILABLE)
|
||||||
} else {
|
} else {
|
||||||
if (checkboxPasswordView?.isChecked == true) {
|
if (checkboxPasswordView?.isChecked == true) {
|
||||||
@@ -157,55 +156,6 @@ class AdvancedUnlockManager(var context: FragmentActivity,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private val biometricAuthenticationCallback = object : BiometricPrompt.AuthenticationCallback () {
|
|
||||||
|
|
||||||
override fun onAuthenticationError(
|
|
||||||
errorCode: Int,
|
|
||||||
errString: CharSequence) {
|
|
||||||
context.runOnUiThread {
|
|
||||||
Log.e(TAG, "Biometric authentication error. Code : $errorCode Error : $errString")
|
|
||||||
setAdvancedUnlockedMessageView(errString.toString())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onAuthenticationFailed() {
|
|
||||||
context.runOnUiThread {
|
|
||||||
Log.e(TAG, "Biometric authentication failed, biometric not recognized")
|
|
||||||
setAdvancedUnlockedMessageView(R.string.advanced_unlock_not_recognized)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onAuthenticationSucceeded(result: BiometricPrompt.AuthenticationResult) {
|
|
||||||
context.runOnUiThread {
|
|
||||||
when (biometricMode) {
|
|
||||||
Mode.BIOMETRIC_UNAVAILABLE -> {
|
|
||||||
}
|
|
||||||
Mode.BIOMETRIC_SECURITY_UPDATE_REQUIRED -> {
|
|
||||||
}
|
|
||||||
Mode.BIOMETRIC_NOT_CONFIGURED -> {
|
|
||||||
}
|
|
||||||
Mode.KEY_MANAGER_UNAVAILABLE -> {
|
|
||||||
}
|
|
||||||
Mode.WAIT_CREDENTIAL -> {
|
|
||||||
}
|
|
||||||
Mode.STORE_CREDENTIAL -> {
|
|
||||||
// newly store the entered password in encrypted way
|
|
||||||
biometricUnlockDatabaseHelper?.encryptData(passwordView?.text.toString())
|
|
||||||
AdvancedUnlockNotificationService.startServiceForTimeout(context)
|
|
||||||
}
|
|
||||||
Mode.EXTRACT_CREDENTIAL -> {
|
|
||||||
// retrieve the encrypted value from preferences
|
|
||||||
cipherDatabaseAction.getCipherDatabase(databaseFileUri) { cipherDatabase ->
|
|
||||||
cipherDatabase?.encryptedValue?.let { value ->
|
|
||||||
biometricUnlockDatabaseHelper?.decryptData(value)
|
|
||||||
} ?: deleteEncryptedDatabaseKey()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun initNotAvailable() {
|
private fun initNotAvailable() {
|
||||||
showFingerPrintViews(false)
|
showFingerPrintViews(false)
|
||||||
|
|
||||||
@@ -248,7 +198,7 @@ class AdvancedUnlockManager(var context: FragmentActivity,
|
|||||||
setAdvancedUnlockedMessageView("")
|
setAdvancedUnlockedMessageView("")
|
||||||
|
|
||||||
advancedUnlockInfoView?.setIconViewClickListener(false) {
|
advancedUnlockInfoView?.setIconViewClickListener(false) {
|
||||||
biometricAuthenticationCallback.onAuthenticationError(BiometricPrompt.ERROR_UNABLE_TO_PROCESS,
|
onAuthenticationError(BiometricPrompt.ERROR_UNABLE_TO_PROCESS,
|
||||||
context.getString(R.string.credential_before_click_advanced_unlock_button))
|
context.getString(R.string.credential_before_click_advanced_unlock_button))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -257,7 +207,8 @@ class AdvancedUnlockManager(var context: FragmentActivity,
|
|||||||
context.runOnUiThread {
|
context.runOnUiThread {
|
||||||
if (allowOpenBiometricPrompt) {
|
if (allowOpenBiometricPrompt) {
|
||||||
try {
|
try {
|
||||||
biometricUnlockDatabaseHelper?.openAdvancedUnlockPrompt(cryptoPrompt)
|
advancedUnlockHelper
|
||||||
|
?.openAdvancedUnlockPrompt(cryptoPrompt)
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Log.e(TAG, "Unable to open advanced unlock prompt", e)
|
Log.e(TAG, "Unable to open advanced unlock prompt", e)
|
||||||
setAdvancedUnlockedTitleView(R.string.advanced_unlock_prompt_not_initialized)
|
setAdvancedUnlockedTitleView(R.string.advanced_unlock_prompt_not_initialized)
|
||||||
@@ -271,7 +222,7 @@ class AdvancedUnlockManager(var context: FragmentActivity,
|
|||||||
setAdvancedUnlockedTitleView(R.string.open_advanced_unlock_prompt_store_credential)
|
setAdvancedUnlockedTitleView(R.string.open_advanced_unlock_prompt_store_credential)
|
||||||
setAdvancedUnlockedMessageView("")
|
setAdvancedUnlockedMessageView("")
|
||||||
|
|
||||||
biometricUnlockDatabaseHelper?.initEncryptData { cryptoPrompt ->
|
advancedUnlockHelper?.initEncryptData { cryptoPrompt ->
|
||||||
// Set listener to open the biometric dialog and save credential
|
// Set listener to open the biometric dialog and save credential
|
||||||
advancedUnlockInfoView?.setIconViewClickListener { _ ->
|
advancedUnlockInfoView?.setIconViewClickListener { _ ->
|
||||||
openAdvancedUnlockPrompt(cryptoPrompt)
|
openAdvancedUnlockPrompt(cryptoPrompt)
|
||||||
@@ -284,10 +235,10 @@ class AdvancedUnlockManager(var context: FragmentActivity,
|
|||||||
setAdvancedUnlockedTitleView(R.string.open_advanced_unlock_prompt_unlock_database)
|
setAdvancedUnlockedTitleView(R.string.open_advanced_unlock_prompt_unlock_database)
|
||||||
setAdvancedUnlockedMessageView("")
|
setAdvancedUnlockedMessageView("")
|
||||||
|
|
||||||
if (biometricUnlockDatabaseHelper != null) {
|
if (advancedUnlockHelper != null) {
|
||||||
cipherDatabaseAction.getCipherDatabase(databaseFileUri) { cipherDatabase ->
|
cipherDatabaseAction.getCipherDatabase(databaseFileUri) { cipherDatabase ->
|
||||||
cipherDatabase?.let {
|
cipherDatabase?.let {
|
||||||
biometricUnlockDatabaseHelper?.initDecryptData(it.specParameters) { cryptoPrompt ->
|
advancedUnlockHelper?.initDecryptData(it.specParameters) { cryptoPrompt ->
|
||||||
|
|
||||||
// Set listener to open the biometric dialog and check credential
|
// Set listener to open the biometric dialog and check credential
|
||||||
advancedUnlockInfoView?.setIconViewClickListener { _ ->
|
advancedUnlockInfoView?.setIconViewClickListener { _ ->
|
||||||
@@ -338,7 +289,7 @@ class AdvancedUnlockManager(var context: FragmentActivity,
|
|||||||
fun destroy() {
|
fun destroy() {
|
||||||
// Close the biometric prompt
|
// Close the biometric prompt
|
||||||
allowOpenBiometricPrompt = false
|
allowOpenBiometricPrompt = false
|
||||||
biometricUnlockDatabaseHelper?.closeBiometricPrompt()
|
advancedUnlockHelper?.closeBiometricPrompt()
|
||||||
// Restore the checked listener
|
// Restore the checked listener
|
||||||
checkboxPasswordView?.setOnCheckedChangeListener(onCheckedPasswordChangeListener)
|
checkboxPasswordView?.setOnCheckedChangeListener(onCheckedPasswordChangeListener)
|
||||||
cipherDatabaseAction.unregisterDatabaseListener(cipherDatabaseListener)
|
cipherDatabaseAction.unregisterDatabaseListener(cipherDatabaseListener)
|
||||||
@@ -352,12 +303,60 @@ class AdvancedUnlockManager(var context: FragmentActivity,
|
|||||||
fun deleteEncryptedDatabaseKey() {
|
fun deleteEncryptedDatabaseKey() {
|
||||||
allowOpenBiometricPrompt = false
|
allowOpenBiometricPrompt = false
|
||||||
advancedUnlockInfoView?.setIconViewClickListener(false, null)
|
advancedUnlockInfoView?.setIconViewClickListener(false, null)
|
||||||
biometricUnlockDatabaseHelper?.closeBiometricPrompt()
|
advancedUnlockHelper?.closeBiometricPrompt()
|
||||||
cipherDatabaseAction.deleteByDatabaseUri(databaseFileUri) {
|
cipherDatabaseAction.deleteByDatabaseUri(databaseFileUri) {
|
||||||
checkBiometricAvailability()
|
checkBiometricAvailability()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||||
|
advancedUnlockHelper?.onActivityResult(requestCode, resultCode, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onAuthenticationError(errorCode: Int, errString: CharSequence) {
|
||||||
|
context.runOnUiThread {
|
||||||
|
Log.e(TAG, "Biometric authentication error. Code : $errorCode Error : $errString")
|
||||||
|
setAdvancedUnlockedMessageView(errString.toString())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onAuthenticationFailed() {
|
||||||
|
context.runOnUiThread {
|
||||||
|
Log.e(TAG, "Biometric authentication failed, biometric not recognized")
|
||||||
|
setAdvancedUnlockedMessageView(R.string.advanced_unlock_not_recognized)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onAuthenticationSucceeded() {
|
||||||
|
context.runOnUiThread {
|
||||||
|
when (biometricMode) {
|
||||||
|
Mode.BIOMETRIC_UNAVAILABLE -> {
|
||||||
|
}
|
||||||
|
Mode.BIOMETRIC_SECURITY_UPDATE_REQUIRED -> {
|
||||||
|
}
|
||||||
|
Mode.BIOMETRIC_NOT_CONFIGURED -> {
|
||||||
|
}
|
||||||
|
Mode.KEY_MANAGER_UNAVAILABLE -> {
|
||||||
|
}
|
||||||
|
Mode.WAIT_CREDENTIAL -> {
|
||||||
|
}
|
||||||
|
Mode.STORE_CREDENTIAL -> {
|
||||||
|
// newly store the entered password in encrypted way
|
||||||
|
advancedUnlockHelper?.encryptData(passwordView?.text.toString())
|
||||||
|
AdvancedUnlockNotificationService.startServiceForTimeout(context)
|
||||||
|
}
|
||||||
|
Mode.EXTRACT_CREDENTIAL -> {
|
||||||
|
// retrieve the encrypted value from preferences
|
||||||
|
cipherDatabaseAction.getCipherDatabase(databaseFileUri) { cipherDatabase ->
|
||||||
|
cipherDatabase?.encryptedValue?.let { value ->
|
||||||
|
advancedUnlockHelper?.decryptData(value)
|
||||||
|
} ?: deleteEncryptedDatabaseKey()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun handleEncryptedResult(encryptedValue: String, ivSpec: String) {
|
override fun handleEncryptedResult(encryptedValue: String, ivSpec: String) {
|
||||||
loadDatabaseAfterRegisterCredentials.invoke(encryptedValue, ivSpec)
|
loadDatabaseAfterRegisterCredentials.invoke(encryptedValue, ivSpec)
|
||||||
}
|
}
|
||||||
@@ -371,7 +370,7 @@ class AdvancedUnlockManager(var context: FragmentActivity,
|
|||||||
setAdvancedUnlockedMessageView(R.string.advanced_unlock_invalid_key)
|
setAdvancedUnlockedMessageView(R.string.advanced_unlock_invalid_key)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onBiometricException(e: Exception) {
|
override fun onGenericException(e: Exception) {
|
||||||
val errorMessage = e.cause?.localizedMessage ?: e.localizedMessage ?: ""
|
val errorMessage = e.cause?.localizedMessage ?: e.localizedMessage ?: ""
|
||||||
setAdvancedUnlockedMessageView(errorMessage)
|
setAdvancedUnlockedMessageView(errorMessage)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ import com.kunzisoft.keepass.activities.dialogs.UnavailableFeatureDialogFragment
|
|||||||
import com.kunzisoft.keepass.activities.stylish.Stylish
|
import com.kunzisoft.keepass.activities.stylish.Stylish
|
||||||
import com.kunzisoft.keepass.app.database.CipherDatabaseAction
|
import com.kunzisoft.keepass.app.database.CipherDatabaseAction
|
||||||
import com.kunzisoft.keepass.app.database.FileDatabaseHistoryAction
|
import com.kunzisoft.keepass.app.database.FileDatabaseHistoryAction
|
||||||
import com.kunzisoft.keepass.biometric.BiometricUnlockDatabaseHelper
|
import com.kunzisoft.keepass.biometric.AdvancedUnlockHelper
|
||||||
import com.kunzisoft.keepass.education.Education
|
import com.kunzisoft.keepass.education.Education
|
||||||
import com.kunzisoft.keepass.icons.IconPackChooser
|
import com.kunzisoft.keepass.icons.IconPackChooser
|
||||||
import com.kunzisoft.keepass.notifications.AdvancedUnlockNotificationService
|
import com.kunzisoft.keepass.notifications.AdvancedUnlockNotificationService
|
||||||
@@ -218,7 +218,7 @@ class NestedAppSettingsFragment : NestedSettingsFragment() {
|
|||||||
val tempAdvancedUnlockPreference: SwitchPreference? = findPreference(getString(R.string.temp_advanced_unlock_enable_key))
|
val tempAdvancedUnlockPreference: SwitchPreference? = findPreference(getString(R.string.temp_advanced_unlock_enable_key))
|
||||||
|
|
||||||
val biometricUnlockSupported = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
val biometricUnlockSupported = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||||
BiometricUnlockDatabaseHelper.biometricUnlockSupported(activity)
|
AdvancedUnlockHelper.biometricUnlockSupported(activity)
|
||||||
} else false
|
} else false
|
||||||
biometricUnlockEnablePreference?.apply {
|
biometricUnlockEnablePreference?.apply {
|
||||||
// False if under Marshmallow
|
// False if under Marshmallow
|
||||||
@@ -259,7 +259,7 @@ class NestedAppSettingsFragment : NestedSettingsFragment() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
val deviceCredentialUnlockSupported = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
val deviceCredentialUnlockSupported = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||||
BiometricUnlockDatabaseHelper.deviceCredentialUnlockSupported(activity)
|
AdvancedUnlockHelper.deviceCredentialUnlockSupported(activity)
|
||||||
} else false
|
} else false
|
||||||
deviceCredentialUnlockEnablePreference?.apply {
|
deviceCredentialUnlockEnablePreference?.apply {
|
||||||
if (!deviceCredentialUnlockSupported) {
|
if (!deviceCredentialUnlockSupported) {
|
||||||
@@ -337,9 +337,9 @@ class NestedAppSettingsFragment : NestedSettingsFragment() {
|
|||||||
validate?.invoke()
|
validate?.invoke()
|
||||||
deleteKeysAlertDialog?.setOnDismissListener(null)
|
deleteKeysAlertDialog?.setOnDismissListener(null)
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||||
BiometricUnlockDatabaseHelper.deleteEntryKeyInKeystoreForBiometric(
|
AdvancedUnlockHelper.deleteEntryKeyInKeystoreForBiometric(
|
||||||
activity,
|
activity,
|
||||||
object : BiometricUnlockDatabaseHelper.BiometricUnlockErrorCallback {
|
object : AdvancedUnlockHelper.AdvancedUnlockErrorCallback {
|
||||||
fun showException(e: Exception) {
|
fun showException(e: Exception) {
|
||||||
Toast.makeText(context,
|
Toast.makeText(context,
|
||||||
getString(R.string.advanced_unlock_scanning_error, e.localizedMessage),
|
getString(R.string.advanced_unlock_scanning_error, e.localizedMessage),
|
||||||
@@ -350,7 +350,7 @@ class NestedAppSettingsFragment : NestedSettingsFragment() {
|
|||||||
showException(e)
|
showException(e)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onBiometricException(e: Exception) {
|
override fun onGenericException(e: Exception) {
|
||||||
showException(e)
|
showException(e)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user