mirror of
https://github.com/Kunzisoft/KeePassDX.git
synced 2025-12-04 15:49:33 +01:00
Better unlock settings
This commit is contained in:
@@ -90,12 +90,12 @@ class UnavailableFeatureDialogFragment : DialogFragment() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (apiName.isEmpty()) {
|
if (apiName.isEmpty()) {
|
||||||
val mapper = arrayOf("ANDROID BASE", "ANDROID BASE 1.1", "CUPCAKE", "DONUT", "ECLAIR", "ECLAIR_0_1", "ECLAIR_MR1", "FROYO", "GINGERBREAD", "GINGERBREAD_MR1", "HONEYCOMB", "HONEYCOMB_MR1", "HONEYCOMB_MR2", "ICE_CREAM_SANDWICH", "ICE_CREAM_SANDWICH_MR1", "JELLY_BEAN", "JELLY_BEAN", "JELLY_BEAN", "KITKAT", "KITKAT", "LOLLIPOOP", "LOLLIPOOP_MR1", "MARSHMALLOW", "NOUGAT", "NOUGAT", "OREO", "OREO")
|
val mapper = arrayOf("ANDROID BASE", "ANDROID BASE 1.1", "CUPCAKE", "DONUT", "ECLAIR", "ECLAIR_0_1", "ECLAIR_MR1", "FROYO", "GINGERBREAD", "GINGERBREAD_MR1", "HONEYCOMB", "HONEYCOMB_MR1", "HONEYCOMB_MR2", "ICE_CREAM_SANDWICH", "ICE_CREAM_SANDWICH_MR1", "JELLY_BEAN", "JELLY_BEAN", "JELLY_BEAN", "KITKAT", "KITKAT", "LOLLIPOOP", "LOLLIPOOP_MR1", "MARSHMALLOW", "NOUGAT", "NOUGAT", "OREO", "OREO", "PIE", "", "")
|
||||||
val index = apiNumber - 1
|
val index = apiNumber - 1
|
||||||
apiName = if (index < mapper.size) mapper[index] else "UNKNOWN_VERSION"
|
apiName = if (index < mapper.size) mapper[index] else "UNKNOWN_VERSION"
|
||||||
}
|
}
|
||||||
if (version.isEmpty()) {
|
if (version.isEmpty()) {
|
||||||
val versions = arrayOf("1.0", "1.1", "1.5", "1.6", "2.0", "2.0.1", "2.1", "2.2.X", "2.3", "2.3.3", "3.0", "3.1", "3.2.0", "4.0.1", "4.0.3", "4.1.0", "4.2.0", "4.3.0", "4.4", "4.4", "5.0", "5.1", "6.0", "7.0", "7.1", "8.0.0", "8.1.0")
|
val versions = arrayOf("1.0", "1.1", "1.5", "1.6", "2.0", "2.0.1", "2.1", "2.2.X", "2.3", "2.3.3", "3.0", "3.1", "3.2.0", "4.0.1", "4.0.3", "4.1.0", "4.2.0", "4.3.0", "4.4", "4.4", "5.0", "5.1", "6.0", "7.0", "7.1", "8.0.0", "8.1.0", "9", "10", "11")
|
||||||
val index = apiNumber - 1
|
val index = apiNumber - 1
|
||||||
version = if (index < versions.size) versions[index] else "UNKNOWN_VERSION"
|
version = if (index < versions.size) versions[index] else "UNKNOWN_VERSION"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -307,21 +307,26 @@ class BiometricUnlockDatabaseHelper(private val context: FragmentActivity) {
|
|||||||
private const val BIOMETRIC_BLOCKS_MODES = KeyProperties.BLOCK_MODE_CBC
|
private const val BIOMETRIC_BLOCKS_MODES = KeyProperties.BLOCK_MODE_CBC
|
||||||
private const val BIOMETRIC_ENCRYPTION_PADDING = KeyProperties.ENCRYPTION_PADDING_PKCS7
|
private const val BIOMETRIC_ENCRYPTION_PADDING = KeyProperties.ENCRYPTION_PADDING_PKCS7
|
||||||
|
|
||||||
|
@RequiresApi(api = Build.VERSION_CODES.M)
|
||||||
fun canAuthenticate(context: Context): Int {
|
fun canAuthenticate(context: Context): Int {
|
||||||
return try {
|
return try {
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
BiometricManager.from(context).canAuthenticate(
|
||||||
BiometricManager.from(context).canAuthenticate(BIOMETRIC_STRONG or DEVICE_CREDENTIAL)
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||||
} else {
|
BIOMETRIC_STRONG or DEVICE_CREDENTIAL
|
||||||
BiometricManager.from(context).canAuthenticate(BIOMETRIC_STRONG)
|
} else {
|
||||||
}
|
BIOMETRIC_STRONG
|
||||||
|
}
|
||||||
|
)
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Log.e(TAG, "Unable to authenticate with strong biometric.", e)
|
Log.e(TAG, "Unable to authenticate with strong biometric.", e)
|
||||||
try {
|
try {
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
BiometricManager.from(context).canAuthenticate(
|
||||||
BiometricManager.from(context).canAuthenticate(BIOMETRIC_WEAK or DEVICE_CREDENTIAL)
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||||
} else {
|
BIOMETRIC_WEAK or DEVICE_CREDENTIAL
|
||||||
BiometricManager.from(context).canAuthenticate(BIOMETRIC_WEAK)
|
} else {
|
||||||
}
|
BIOMETRIC_WEAK
|
||||||
|
}
|
||||||
|
)
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Log.e(TAG, "Unable to authenticate with weak biometric.", e)
|
Log.e(TAG, "Unable to authenticate with weak biometric.", e)
|
||||||
BiometricManager.BIOMETRIC_ERROR_NO_HARDWARE
|
BiometricManager.BIOMETRIC_ERROR_NO_HARDWARE
|
||||||
@@ -329,6 +334,7 @@ class BiometricUnlockDatabaseHelper(private val context: FragmentActivity) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@RequiresApi(api = Build.VERSION_CODES.M)
|
||||||
fun allowInitKeyStore(context: Context): Boolean {
|
fun allowInitKeyStore(context: Context): Boolean {
|
||||||
val biometricCanAuthenticate = canAuthenticate(context)
|
val biometricCanAuthenticate = canAuthenticate(context)
|
||||||
return ( biometricCanAuthenticate == BiometricManager.BIOMETRIC_SUCCESS
|
return ( biometricCanAuthenticate == BiometricManager.BIOMETRIC_SUCCESS
|
||||||
@@ -336,19 +342,42 @@ class BiometricUnlockDatabaseHelper(private val context: FragmentActivity) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun unlockSupported(context: Context): Boolean {
|
@RequiresApi(api = Build.VERSION_CODES.M)
|
||||||
val biometricCanAuthenticate = canAuthenticate(context)
|
fun biometricUnlockSupported(context: Context): Boolean {
|
||||||
return ( biometricCanAuthenticate == BiometricManager.BIOMETRIC_SUCCESS
|
val biometricCanAuthenticate = try {
|
||||||
|
BiometricManager.from(context).canAuthenticate(BIOMETRIC_STRONG)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Log.e(TAG, "Unable to authenticate with strong biometric.", e)
|
||||||
|
try {
|
||||||
|
BiometricManager.from(context).canAuthenticate(BIOMETRIC_WEAK)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Log.e(TAG, "Unable to authenticate with weak biometric.", e)
|
||||||
|
BiometricManager.BIOMETRIC_ERROR_NO_HARDWARE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (biometricCanAuthenticate == BiometricManager.BIOMETRIC_SUCCESS
|
||||||
|| biometricCanAuthenticate == BiometricManager.BIOMETRIC_STATUS_UNKNOWN
|
|| biometricCanAuthenticate == BiometricManager.BIOMETRIC_STATUS_UNKNOWN
|
||||||
|| biometricCanAuthenticate == BiometricManager.BIOMETRIC_ERROR_HW_UNAVAILABLE
|
|| biometricCanAuthenticate == BiometricManager.BIOMETRIC_ERROR_HW_UNAVAILABLE
|
||||||
|| biometricCanAuthenticate == BiometricManager.BIOMETRIC_ERROR_NONE_ENROLLED
|
|| biometricCanAuthenticate == BiometricManager.BIOMETRIC_ERROR_NONE_ENROLLED
|
||||||
|| biometricCanAuthenticate == BiometricManager.BIOMETRIC_ERROR_SECURITY_UPDATE_REQUIRED
|
|| biometricCanAuthenticate == BiometricManager.BIOMETRIC_ERROR_SECURITY_UPDATE_REQUIRED
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@RequiresApi(api = Build.VERSION_CODES.R)
|
||||||
|
fun deviceCredentialUnlockSupported(context: Context): Boolean {
|
||||||
|
val biometricCanAuthenticate = BiometricManager.from(context).canAuthenticate(DEVICE_CREDENTIAL)
|
||||||
|
return (biometricCanAuthenticate == BiometricManager.BIOMETRIC_SUCCESS
|
||||||
|
|| biometricCanAuthenticate == BiometricManager.BIOMETRIC_STATUS_UNKNOWN
|
||||||
|
|| biometricCanAuthenticate == BiometricManager.BIOMETRIC_ERROR_HW_UNAVAILABLE
|
||||||
|
|| biometricCanAuthenticate == BiometricManager.BIOMETRIC_ERROR_NONE_ENROLLED
|
||||||
|
|| biometricCanAuthenticate == BiometricManager.BIOMETRIC_ERROR_SECURITY_UPDATE_REQUIRED
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove entry key in keystore
|
* Remove entry key in keystore
|
||||||
*/
|
*/
|
||||||
|
@RequiresApi(api = Build.VERSION_CODES.M)
|
||||||
fun deleteEntryKeyInKeystoreForBiometric(context: FragmentActivity,
|
fun deleteEntryKeyInKeystoreForBiometric(context: FragmentActivity,
|
||||||
biometricCallback: BiometricUnlockErrorCallback) {
|
biometricCallback: BiometricUnlockErrorCallback) {
|
||||||
BiometricUnlockDatabaseHelper(context).apply {
|
BiometricUnlockDatabaseHelper(context).apply {
|
||||||
|
|||||||
@@ -30,7 +30,6 @@ import android.view.autofill.AutofillManager
|
|||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.annotation.RequiresApi
|
import androidx.annotation.RequiresApi
|
||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
import androidx.biometric.BiometricManager
|
|
||||||
import androidx.preference.ListPreference
|
import androidx.preference.ListPreference
|
||||||
import androidx.preference.Preference
|
import androidx.preference.Preference
|
||||||
import androidx.preference.SwitchPreference
|
import androidx.preference.SwitchPreference
|
||||||
@@ -209,14 +208,15 @@ class NestedAppSettingsFragment : NestedSettingsFragment() {
|
|||||||
|
|
||||||
activity?.let { activity ->
|
activity?.let { activity ->
|
||||||
val biometricUnlockEnablePreference: SwitchPreference? = findPreference(getString(R.string.biometric_unlock_enable_key))
|
val biometricUnlockEnablePreference: SwitchPreference? = findPreference(getString(R.string.biometric_unlock_enable_key))
|
||||||
val deleteKeysFingerprints: Preference? = findPreference(getString(R.string.biometric_delete_all_key_key))
|
val deviceCredentialUnlockEnablePreference: SwitchPreference? = findPreference(getString(R.string.device_credential_unlock_enable_key))
|
||||||
// < M solve verifyError exception
|
val autoOpenPromptPreference: SwitchPreference? = findPreference(getString(R.string.biometric_auto_open_prompt_key))
|
||||||
|
|
||||||
val biometricUnlockSupported = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
val biometricUnlockSupported = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||||
BiometricUnlockDatabaseHelper.unlockSupported(activity)
|
BiometricUnlockDatabaseHelper.biometricUnlockSupported(activity)
|
||||||
} else false
|
} else false
|
||||||
if (!biometricUnlockSupported) {
|
biometricUnlockEnablePreference?.apply {
|
||||||
// False if under Marshmallow
|
// False if under Marshmallow
|
||||||
biometricUnlockEnablePreference?.apply {
|
if (!biometricUnlockSupported) {
|
||||||
isChecked = false
|
isChecked = false
|
||||||
setOnPreferenceClickListener { preference ->
|
setOnPreferenceClickListener { preference ->
|
||||||
(preference as SwitchPreference).isChecked = false
|
(preference as SwitchPreference).isChecked = false
|
||||||
@@ -224,9 +224,48 @@ class NestedAppSettingsFragment : NestedSettingsFragment() {
|
|||||||
.show(parentFragmentManager, "unavailableFeatureDialog")
|
.show(parentFragmentManager, "unavailableFeatureDialog")
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
setOnPreferenceChangeListener { _, newValue ->
|
||||||
|
val checked = (newValue as Boolean)
|
||||||
|
autoOpenPromptPreference?.isEnabled = checked
|
||||||
|
|| deviceCredentialUnlockEnablePreference?.isChecked == true
|
||||||
|
if (checked)
|
||||||
|
deviceCredentialUnlockEnablePreference?.isChecked = false
|
||||||
|
true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
deleteKeysFingerprints?.isEnabled = false
|
}
|
||||||
} else {
|
|
||||||
|
|
||||||
|
val deviceCredentialUnlockSupported = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||||
|
BiometricUnlockDatabaseHelper.deviceCredentialUnlockSupported(activity)
|
||||||
|
} else false
|
||||||
|
deviceCredentialUnlockEnablePreference?.apply {
|
||||||
|
if (!deviceCredentialUnlockSupported) {
|
||||||
|
isChecked = false
|
||||||
|
setOnPreferenceClickListener { preference ->
|
||||||
|
(preference as SwitchPreference).isChecked = false
|
||||||
|
UnavailableFeatureDialogFragment.getInstance(Build.VERSION_CODES.R)
|
||||||
|
.show(parentFragmentManager, "unavailableFeatureDialog")
|
||||||
|
false
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
setOnPreferenceChangeListener { _, newValue ->
|
||||||
|
val checked = (newValue as Boolean)
|
||||||
|
autoOpenPromptPreference?.isEnabled = checked ||
|
||||||
|
biometricUnlockEnablePreference?.isChecked == true
|
||||||
|
if (checked)
|
||||||
|
biometricUnlockEnablePreference?.isChecked = false
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
autoOpenPromptPreference?.isEnabled = biometricUnlockEnablePreference?.isChecked == true
|
||||||
|
|| deviceCredentialUnlockEnablePreference?.isChecked == true
|
||||||
|
|
||||||
|
val deleteKeysFingerprints: Preference? = findPreference(getString(R.string.biometric_delete_all_key_key))
|
||||||
|
if (biometricUnlockSupported || deviceCredentialUnlockSupported) {
|
||||||
deleteKeysFingerprints?.setOnPreferenceClickListener {
|
deleteKeysFingerprints?.setOnPreferenceClickListener {
|
||||||
context?.let { context ->
|
context?.let { context ->
|
||||||
AlertDialog.Builder(context)
|
AlertDialog.Builder(context)
|
||||||
@@ -260,6 +299,8 @@ class NestedAppSettingsFragment : NestedSettingsFragment() {
|
|||||||
}
|
}
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
deleteKeysFingerprints?.isEnabled = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -324,8 +324,8 @@
|
|||||||
<string name="biometric_unlock_enable_summary">Lets you scan your biometric to open the database</string>
|
<string name="biometric_unlock_enable_summary">Lets you scan your biometric to open the database</string>
|
||||||
<string name="device_credential_unlock_enable_title">Device credential unlocking</string>
|
<string name="device_credential_unlock_enable_title">Device credential unlocking</string>
|
||||||
<string name="device_credential_unlock_enable_summary">Lets you use your device credential to open the database</string>
|
<string name="device_credential_unlock_enable_summary">Lets you use your device credential to open the database</string>
|
||||||
<string name="biometric_auto_open_prompt_title">Auto-open biometric prompt</string>
|
<string name="biometric_auto_open_prompt_title">Auto-open prompt</string>
|
||||||
<string name="biometric_auto_open_prompt_summary">Automatically ask for biometric if the database is set up to use it</string>
|
<string name="biometric_auto_open_prompt_summary">Automatically request advanced unlock if the database is set up to use it</string>
|
||||||
<string name="biometric_delete_all_key_title">Delete encryption keys</string>
|
<string name="biometric_delete_all_key_title">Delete encryption keys</string>
|
||||||
<string name="biometric_delete_all_key_summary">Delete all encryption keys related to advanced unlock recognition</string>
|
<string name="biometric_delete_all_key_summary">Delete all encryption keys related to advanced unlock recognition</string>
|
||||||
<string name="biometric_delete_all_key_warning">Delete all encryption keys related to advanced unlock recognition?</string>
|
<string name="biometric_delete_all_key_warning">Delete all encryption keys related to advanced unlock recognition?</string>
|
||||||
|
|||||||
@@ -18,34 +18,27 @@
|
|||||||
along with KeePassDX. If not, see <http://www.gnu.org/licenses/>.
|
along with KeePassDX. If not, see <http://www.gnu.org/licenses/>.
|
||||||
-->
|
-->
|
||||||
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
|
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
<Preference
|
|
||||||
android:key="@string/advanced_unlock_explanation_key"
|
|
||||||
android:icon="@drawable/prefs_info_24dp"
|
|
||||||
android:summary="@string/advanced_unlock_explanation_summary"/>
|
|
||||||
<PreferenceCategory
|
<PreferenceCategory
|
||||||
android:title="@string/biometric">
|
android:title="@string/general">
|
||||||
|
<Preference
|
||||||
|
android:key="@string/advanced_unlock_explanation_key"
|
||||||
|
android:icon="@drawable/prefs_info_24dp"
|
||||||
|
android:summary="@string/advanced_unlock_explanation_summary"/>
|
||||||
<SwitchPreference
|
<SwitchPreference
|
||||||
android:key="@string/biometric_unlock_enable_key"
|
android:key="@string/biometric_unlock_enable_key"
|
||||||
android:title="@string/biometric_unlock_enable_title"
|
android:title="@string/biometric_unlock_enable_title"
|
||||||
android:summary="@string/biometric_unlock_enable_summary"
|
android:summary="@string/biometric_unlock_enable_summary"
|
||||||
android:defaultValue="@bool/biometric_unlock_enable_default"/>
|
android:defaultValue="@bool/biometric_unlock_enable_default"/>
|
||||||
<SwitchPreference
|
|
||||||
android:key="@string/biometric_auto_open_prompt_key"
|
|
||||||
android:title="@string/biometric_auto_open_prompt_title"
|
|
||||||
android:summary="@string/biometric_auto_open_prompt_summary"
|
|
||||||
android:dependency="@string/biometric_unlock_enable_key"
|
|
||||||
android:defaultValue="@bool/biometric_auto_open_prompt_default"/>
|
|
||||||
</PreferenceCategory>
|
|
||||||
<PreferenceCategory
|
|
||||||
android:title="@string/device_credential">
|
|
||||||
<SwitchPreference
|
<SwitchPreference
|
||||||
android:key="@string/device_credential_unlock_enable_key"
|
android:key="@string/device_credential_unlock_enable_key"
|
||||||
android:title="@string/device_credential_unlock_enable_title"
|
android:title="@string/device_credential_unlock_enable_title"
|
||||||
android:summary="@string/device_credential_unlock_enable_summary"
|
android:summary="@string/device_credential_unlock_enable_summary"
|
||||||
android:defaultValue="@bool/device_credential_unlock_enable_default"/>
|
android:defaultValue="@bool/device_credential_unlock_enable_default"/>
|
||||||
</PreferenceCategory>
|
<SwitchPreference
|
||||||
<PreferenceCategory
|
android:key="@string/biometric_auto_open_prompt_key"
|
||||||
android:title="@string/general">
|
android:title="@string/biometric_auto_open_prompt_title"
|
||||||
|
android:summary="@string/biometric_auto_open_prompt_summary"
|
||||||
|
android:defaultValue="@bool/biometric_auto_open_prompt_default"/>
|
||||||
<Preference
|
<Preference
|
||||||
android:key="@string/biometric_delete_all_key_key"
|
android:key="@string/biometric_delete_all_key_key"
|
||||||
android:title="@string/biometric_delete_all_key_title"
|
android:title="@string/biometric_delete_all_key_title"
|
||||||
|
|||||||
Reference in New Issue
Block a user