From ccd5da0962ff10f9ab813af8af49a8ed45052d62 Mon Sep 17 00:00:00 2001 From: J-Jamet Date: Thu, 11 Sep 2025 00:00:22 +0200 Subject: [PATCH] feat: Add backup as setting #2135 --- .../activity/PasskeyLauncherActivity.kt | 16 +++++++++++++--- .../passkey/util/PasskeyHelper.kt | 18 ++++++++++-------- .../keepass/settings/PreferencesUtil.kt | 12 ++++++++++++ app/src/main/res/values/donottranslate.xml | 4 ++++ app/src/main/res/values/strings.xml | 4 ++++ app/src/main/res/xml/preferences_passkeys.xml | 9 ++++++--- 6 files changed, 49 insertions(+), 14 deletions(-) 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 a0158b38c..8e4f1b9a9 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 @@ -68,6 +68,7 @@ import com.kunzisoft.keepass.model.AppOrigin import com.kunzisoft.keepass.model.Passkey import com.kunzisoft.keepass.model.RegisterInfo import com.kunzisoft.keepass.model.SearchInfo +import com.kunzisoft.keepass.settings.PreferencesUtil import kotlinx.coroutines.CoroutineExceptionHandler import kotlinx.coroutines.launch import java.io.IOException @@ -81,6 +82,9 @@ class PasskeyLauncherActivity : DatabaseModeActivity() { private var mCreationParameters: PublicKeyCredentialCreationParameters? = null private var mPasskey: Passkey? = null + private val mBackupEligibility = PreferencesUtil.isPasskeyBackupEligibilityEnable(this) + private val mBackupState = PreferencesUtil.isPasskeyBackupStateEnable(this) + private var mPasskeySelectionActivityResultLauncher: ActivityResultLauncher? = this.buildActivityResultLauncher( lockDatabase = true, @@ -108,7 +112,9 @@ class PasskeyLauncherActivity : DatabaseModeActivity() { usageParameters = usageParameters, appOrigin = appOrigin ), - passkey = passkey + passkey = passkey, + backupEligibility = mBackupEligibility, + backupState = mBackupState ) ) ) @@ -141,7 +147,9 @@ class PasskeyLauncherActivity : DatabaseModeActivity() { PendingIntentHandler.setCreateCredentialResponse( intent = responseIntent, response = buildCreatePublicKeyCredentialResponse( - publicKeyCredentialCreationParameters = it + publicKeyCredentialCreationParameters = it, + backupEligibility = mBackupEligibility, + backupState = mBackupState ) ) } @@ -272,7 +280,9 @@ class PasskeyLauncherActivity : DatabaseModeActivity() { usageParameters = usageParameters, appOrigin = appOrigin ), - passkey = passkey + passkey = passkey, + backupEligibility = mBackupEligibility, + backupState = mBackupState ) ) ) diff --git a/app/src/main/java/com/kunzisoft/keepass/credentialprovider/passkey/util/PasskeyHelper.kt b/app/src/main/java/com/kunzisoft/keepass/credentialprovider/passkey/util/PasskeyHelper.kt index 850f189a8..b97b48031 100644 --- a/app/src/main/java/com/kunzisoft/keepass/credentialprovider/passkey/util/PasskeyHelper.kt +++ b/app/src/main/java/com/kunzisoft/keepass/credentialprovider/passkey/util/PasskeyHelper.kt @@ -472,7 +472,9 @@ object PasskeyHelper { * by calling this method the user is always recognized as present and verified */ fun buildCreatePublicKeyCredentialResponse( - publicKeyCredentialCreationParameters: PublicKeyCredentialCreationParameters + publicKeyCredentialCreationParameters: PublicKeyCredentialCreationParameters, + backupEligibility: Boolean, + backupState: Boolean ): CreatePublicKeyCredentialResponse { val keyPair = publicKeyCredentialCreationParameters.signatureKey.first @@ -489,8 +491,8 @@ object PasskeyHelper { ) ?: mapOf()), userPresent = true, userVerified = true, - backupEligibility = BACKUP_ELIGIBILITY, - backupState = false, // TODO Setting to add a backup manually #2135 + backupEligibility = backupEligibility, + backupState = backupState, publicKeyTypeId = keyTypeId, publicKeyCbor = Signature.convertPublicKey(keyPair.public, keyTypeId)!!, clientDataResponse = publicKeyCredentialCreationParameters.clientDataResponse @@ -559,7 +561,9 @@ object PasskeyHelper { fun buildPasskeyPublicKeyCredential( requestOptions: PublicKeyCredentialRequestOptions, clientDataResponse: ClientDataResponse, - passkey: Passkey + passkey: Passkey, + backupEligibility: Boolean, + backupState: Boolean ): PublicKeyCredential { val getCredentialResponse = FidoPublicKeyCredential( id = passkey.credentialId, @@ -567,8 +571,8 @@ object PasskeyHelper { requestOptions = requestOptions, userPresent = true, userVerified = true, - backupEligibility = BACKUP_ELIGIBILITY, - backupState = false, // TODO Setting to add a backup manually #2135 + backupEligibility = backupEligibility, + backupState = backupState, userHandle = passkey.userHandle, privateKey = passkey.privateKeyPem, clientDataResponse = clientDataResponse @@ -599,6 +603,4 @@ object PasskeyHelper { ) } } - - private const val BACKUP_ELIGIBILITY = true } \ No newline at end of file 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 e88e7e069..3a2c05e6f 100644 --- a/app/src/main/java/com/kunzisoft/keepass/settings/PreferencesUtil.kt +++ b/app/src/main/java/com/kunzisoft/keepass/settings/PreferencesUtil.kt @@ -686,6 +686,18 @@ object PreferencesUtil { context.resources.getBoolean(R.bool.keyboard_previous_lock_default)) } + fun isPasskeyBackupEligibilityEnable(context: Context): Boolean { + val prefs = PreferenceManager.getDefaultSharedPreferences(context) + return prefs.getBoolean(context.getString(R.string.passkeys_backup_eligibility_key), + context.resources.getBoolean(R.bool.passkeys_backup_eligibility_default)) + } + + fun isPasskeyBackupStateEnable(context: Context): Boolean { + val prefs = PreferenceManager.getDefaultSharedPreferences(context) + return prefs.getBoolean(context.getString(R.string.passkeys_backup_state_key), + context.resources.getBoolean(R.bool.passkeys_backup_state_default)) + } + fun isAutofillCloseDatabaseEnable(context: Context): Boolean { val prefs = PreferenceManager.getDefaultSharedPreferences(context) return prefs.getBoolean(context.getString(R.string.autofill_close_database_key), diff --git a/app/src/main/res/values/donottranslate.xml b/app/src/main/res/values/donottranslate.xml index bdd31f4aa..ac6a15604 100644 --- a/app/src/main/res/values/donottranslate.xml +++ b/app/src/main/res/values/donottranslate.xml @@ -135,6 +135,10 @@ passkeys_explanation_key settings_passkeys_key passkeys_privileged_apps_key + passkeys_backup_eligibility_key + true + passkeys_backup_state_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 4e3f289da..bf7249f93 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -427,6 +427,10 @@ WARNING : A privileged app acts as a gateway to retrieve the origin of an authentication. Ensure its legitimacy to avoid security issues. App not recognized %1$s attempts to perform a Passkey action.\n\nWould you like to add it to the list of privileged apps? + Backup Eligibility + Determine at creation time whether the public key credential source is allowed to be backed up + Backup State + Indicate that credentials are backed up and protected against the loss of a single device Autofill Passkeys, Autofill credential provider Sign in with KeePassDX diff --git a/app/src/main/res/xml/preferences_passkeys.xml b/app/src/main/res/xml/preferences_passkeys.xml index 397a4afb2..502403320 100644 --- a/app/src/main/res/xml/preferences_passkeys.xml +++ b/app/src/main/res/xml/preferences_passkeys.xml @@ -24,14 +24,17 @@ android:key="@string/passkeys_privileged_apps_key" android:title="@string/passkeys_privileged_apps_title" android:summary="@string/passkeys_privileged_apps_summary"/> -