diff --git a/app/src/main/java/com/kunzisoft/keepass/credentialprovider/UserVerificationHelper.kt b/app/src/main/java/com/kunzisoft/keepass/credentialprovider/UserVerificationHelper.kt index 8ee640a7e..06593ce15 100644 --- a/app/src/main/java/com/kunzisoft/keepass/credentialprovider/UserVerificationHelper.kt +++ b/app/src/main/java/com/kunzisoft/keepass/credentialprovider/UserVerificationHelper.kt @@ -15,6 +15,7 @@ import com.kunzisoft.keepass.R import com.kunzisoft.keepass.activities.dialogs.CheckDatabaseCredentialDialogFragment import com.kunzisoft.keepass.credentialprovider.passkey.data.UserVerificationRequirement import com.kunzisoft.keepass.model.EntryInfo +import com.kunzisoft.keepass.settings.PreferencesUtil.isUserVerificationDeviceCredential import com.kunzisoft.keepass.utils.getEnumExtra import com.kunzisoft.keepass.utils.putEnumExtra import com.kunzisoft.keepass.view.toastError @@ -96,11 +97,7 @@ class UserVerificationHelper { userVerificationViewModel: UserVerificationViewModel, dataToVerify: UserVerificationData ) { - if (context?.isAuthenticatorsAllowed() == true) { - activity?.showUserVerificationDeviceCredential(userVerificationViewModel, dataToVerify) - } else { - activity?.showUserVerificationDatabaseCredential(userVerificationViewModel, dataToVerify) - } + activity?.checkUserVerification(userVerificationViewModel, dataToVerify) } /** @@ -110,7 +107,7 @@ class UserVerificationHelper { userVerificationViewModel: UserVerificationViewModel, dataToVerify: UserVerificationData ) { - if (isAuthenticatorsAllowed()) { + if (isAuthenticatorsAllowed() && isUserVerificationDeviceCredential(this)) { showUserVerificationDeviceCredential(userVerificationViewModel, dataToVerify) } else { showUserVerificationDatabaseCredential(userVerificationViewModel, dataToVerify) diff --git a/app/src/main/java/com/kunzisoft/keepass/credentialprovider/activity/PasskeyLauncherActivity.kt b/app/src/main/java/com/kunzisoft/keepass/credentialprovider/activity/PasskeyLauncherActivity.kt index 61ed1e82e..f27e86091 100644 --- a/app/src/main/java/com/kunzisoft/keepass/credentialprovider/activity/PasskeyLauncherActivity.kt +++ b/app/src/main/java/com/kunzisoft/keepass/credentialprovider/activity/PasskeyLauncherActivity.kt @@ -60,7 +60,7 @@ import com.kunzisoft.keepass.database.ContextualDatabase import com.kunzisoft.keepass.model.AppOrigin import com.kunzisoft.keepass.model.SearchInfo import com.kunzisoft.keepass.services.DatabaseTaskNotificationService.Companion.ACTION_DATABASE_UPDATE_ENTRY_TASK -import com.kunzisoft.keepass.settings.PreferencesUtil.isPasskeyUserVerificationPreferred +import com.kunzisoft.keepass.settings.PreferencesUtil.isUserVerificationPreferred import com.kunzisoft.keepass.tasks.ActionRunnable import com.kunzisoft.keepass.utils.AppUtil.randomRequestCode import com.kunzisoft.keepass.view.toastError @@ -202,7 +202,7 @@ class PasskeyLauncherActivity : DatabaseLockActivity() { super.onUnknownDatabaseRetrieved(database) // To manage https://github.com/Kunzisoft/KeePassDX/issues/2283 val userVerificationNeeded = intent.isUserVerificationNeeded( - userVerificationPreferred = isPasskeyUserVerificationPreferred(this) + userVerificationPreferred = isUserVerificationPreferred(this) ) && intent.getUserVerifiedWithAuth().not() if (userVerificationNeeded) { checkUserVerification( diff --git a/app/src/main/java/com/kunzisoft/keepass/settings/NestedAppSettingsFragment.kt b/app/src/main/java/com/kunzisoft/keepass/settings/NestedAppSettingsFragment.kt index fca226a01..7e0df5669 100644 --- a/app/src/main/java/com/kunzisoft/keepass/settings/NestedAppSettingsFragment.kt +++ b/app/src/main/java/com/kunzisoft/keepass/settings/NestedAppSettingsFragment.kt @@ -302,7 +302,7 @@ class NestedAppSettingsFragment : NestedSettingsFragment() { biometricUnlockEnablePreference.isChecked = false warningMessage(activity, keystoreWarning = true, deleteKeys = true) { biometricUnlockEnablePreference.isChecked = true - deviceCredentialUnlockEnablePreference?.isChecked = false + deviceCredentialUnlockEnablePreference.isChecked = false } } else { biometricUnlockEnablePreference.isChecked = false @@ -349,7 +349,7 @@ class NestedAppSettingsFragment : NestedSettingsFragment() { deviceCredentialUnlockEnablePreference.isChecked = false warningMessage(activity, keystoreWarning = true, deleteKeys = true) { deviceCredentialUnlockEnablePreference.isChecked = true - biometricUnlockEnablePreference?.isChecked = false + biometricUnlockEnablePreference.isChecked = false } } else { deviceCredentialUnlockEnablePreference.isChecked = false @@ -523,27 +523,23 @@ class NestedAppSettingsFragment : NestedSettingsFragment() { } override fun onDisplayPreferenceDialog(preference: Preference) { - - var otherDialogFragment = false - var dialogFragment: DialogFragment? = null - // Main Preferences + when (preference.key) { getString(R.string.app_timeout_key), getString(R.string.clipboard_timeout_key), getString(R.string.temp_device_unlock_timeout_key) -> { dialogFragment = DurationDialogFragmentCompat.newInstance(preference.key) } - else -> otherDialogFragment = true + else -> {} } if (dialogFragment != null) { @Suppress("DEPRECATION") dialogFragment.setTargetFragment(this, 0) dialogFragment.show(parentFragmentManager, TAG_PREF_FRAGMENT) - } - // Could not be handled here. Try with the super method. - else if (otherDialogFragment) { + } else { + // Could not be handled here. Try with the super method. super.onDisplayPreferenceDialog(preference) } } diff --git a/app/src/main/java/com/kunzisoft/keepass/settings/NestedSettingsFragment.kt b/app/src/main/java/com/kunzisoft/keepass/settings/NestedSettingsFragment.kt index 0e6d020e0..a1dc7d82b 100644 --- a/app/src/main/java/com/kunzisoft/keepass/settings/NestedSettingsFragment.kt +++ b/app/src/main/java/com/kunzisoft/keepass/settings/NestedSettingsFragment.kt @@ -30,11 +30,17 @@ import com.kunzisoft.keepass.activities.dialogs.UnderDevelopmentFeatureDialogFra abstract class NestedSettingsFragment : PreferenceFragmentCompat() { enum class Screen { - APPLICATION, FORM_FILLING, DEVICE_UNLOCK, APPEARANCE, DATABASE, DATABASE_SECURITY, DATABASE_MASTER_KEY + APPLICATION, + FORM_FILLING, + DEVICE_UNLOCK, + APPEARANCE, + DATABASE, + DATABASE_SECURITY, + DATABASE_MASTER_KEY } fun getScreen(): Screen { - return Screen.values()[requireArguments().getInt(TAG_KEY)] + return Screen.entries[requireArguments().getInt(TAG_KEY)] } override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { @@ -50,8 +56,7 @@ abstract class NestedSettingsFragment : PreferenceFragmentCompat() { preferenceInDev.setOnPreferenceClickListener { preference -> try { // don't check if we can (preference as TwoStatePreference).isChecked = false - } catch (ignored: Exception) { - } + } catch (_: Exception) {} UnderDevelopmentFeatureDialogFragment().show(parentFragmentManager, "underDevFeatureDialog") false } diff --git a/app/src/main/java/com/kunzisoft/keepass/settings/PreferencesUtil.kt b/app/src/main/java/com/kunzisoft/keepass/settings/PreferencesUtil.kt index ea19872ea..99df926b2 100644 --- a/app/src/main/java/com/kunzisoft/keepass/settings/PreferencesUtil.kt +++ b/app/src/main/java/com/kunzisoft/keepass/settings/PreferencesUtil.kt @@ -690,10 +690,16 @@ object PreferencesUtil { context.resources.getBoolean(R.bool.passkeys_close_database_default)) } - fun isPasskeyUserVerificationPreferred(context: Context): Boolean { + fun isUserVerificationDeviceCredential(context: Context): Boolean { val prefs = PreferenceManager.getDefaultSharedPreferences(context) - return prefs.getBoolean(context.getString(R.string.passkeys_user_verification_preferred_key), - context.resources.getBoolean(R.bool.passkeys_user_verification_preferred_default)) + return prefs.getBoolean(context.getString(R.string.user_verification_device_credential_key), + context.resources.getBoolean(R.bool.user_verification_device_credential_default)) + } + + fun isUserVerificationPreferred(context: Context): Boolean { + val prefs = PreferenceManager.getDefaultSharedPreferences(context) + return prefs.getBoolean(context.getString(R.string.user_verification_preferred_key), + context.resources.getBoolean(R.bool.user_verification_preferred_default)) } fun isPasskeyBackupEligibilityEnable(context: Context): Boolean { diff --git a/app/src/main/res/drawable/prefs_user_verification_24dp.xml b/app/src/main/res/drawable/prefs_user_verification_24dp.xml new file mode 100644 index 000000000..f51cf2607 --- /dev/null +++ b/app/src/main/res/drawable/prefs_user_verification_24dp.xml @@ -0,0 +1,9 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/values/donottranslate.xml b/app/src/main/res/values/donottranslate.xml index 00da027fd..7d95a353b 100644 --- a/app/src/main/res/values/donottranslate.xml +++ b/app/src/main/res/values/donottranslate.xml @@ -69,6 +69,8 @@ false delete_entered_password_key true + user_verification_device_credential_key + true enable_auto_save_database_key true enable_keep_screen_on_key @@ -77,8 +79,6 @@ false auto_focus_search_key false - subdomain_search_key - false app_timeout_key lock_database_screen_off_key true @@ -140,12 +140,14 @@ passkeys_privileged_apps_key passkeys_auto_select_key true - passkeys_user_verification_preferred_key - false passkeys_backup_eligibility_key true passkeys_backup_state_key true + user_verification_preferred_key + false + subdomain_search_key + false keyboard_notification_entry_key true keyboard_notification_entry_clear_close_key diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 0e5a60584..f97b6fae0 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -434,8 +434,6 @@ Add app signature to passkey entry? Auto select Auto select if only one entry and the database is open, only if the requesting app is compatible - Preferred User Verification - Perform a user verification to access sensitive data when the relying party requests \"preferred\". Backup Eligibility Determine at creation time whether the public key credential source is allowed to be backed up Backup State @@ -446,6 +444,10 @@ Configure autofilling to quickly fill out forms in other apps Select entry… Autofill settings + Device credential + Use the device credential as user verification if available + Preferred User Verification + Perform a user verification when the relying party requests \"preferred\" Generated password size Sets default size of the generated passwords Password characters diff --git a/app/src/main/res/xml/preferences_application.xml b/app/src/main/res/xml/preferences_application.xml index 47338bff7..251a4d00e 100644 --- a/app/src/main/res/xml/preferences_application.xml +++ b/app/src/main/res/xml/preferences_application.xml @@ -32,6 +32,11 @@ android:title="@string/delete_entered_password_title" android:summary="@string/delete_entered_password_summary" android:defaultValue="@bool/delete_entered_password_default"/> + + android:key="@string/credential_provider_key" + android:title="@string/credential_provider"> + android:key="@string/settings_credential_provider_enable_key" + android:title="@string/set_credential_provider_service_title" + android:defaultValue="@bool/settings_credential_provider_enable_default"/> + + + + + + android:title="@string/general"> - - - - + android:key="@string/subdomain_search_key" + android:title="@string/subdomain_search_title" + android:summary="@string/subdomain_search_summary" + android:defaultValue="@bool/subdomain_search_default"/> - + + + + + Passkey Streamline Icon: https://streamlinehq.com + + + diff --git a/art/ic_user_verification.svg b/art/ic_user_verification.svg new file mode 100644 index 000000000..752cca889 --- /dev/null +++ b/art/ic_user_verification.svg @@ -0,0 +1,45 @@ + + + + + + + +