feat: Custom settings and privileged

This commit is contained in:
J-Jamet
2025-09-02 19:57:02 +02:00
parent 2bedbf8a6c
commit 8924254c25
71 changed files with 647 additions and 350 deletions

View File

@@ -159,20 +159,22 @@
android:label="@string/about" />
<activity
android:name="com.kunzisoft.keepass.settings.SettingsActivity" />
<activity
android:name="com.kunzisoft.keepass.credentialprovider.activity.AutofillLauncherActivity"
android:theme="@style/Theme.Transparent"
android:configChanges="keyboardHidden"
android:excludeFromRecents="true"/>
<activity
android:name="com.kunzisoft.keepass.settings.DeviceUnlockSettingsActivity" />
<activity
android:name="com.kunzisoft.keepass.settings.AutofillSettingsActivity" />
<activity
android:name="com.kunzisoft.keepass.settings.PasskeysSettingsActivity" />
<activity
android:name="com.kunzisoft.keepass.settings.AppearanceSettingsActivity" />
<activity
android:name="com.kunzisoft.keepass.hardware.HardwareKeyActivity"
android:theme="@style/Theme.Transparent" />
<activity
android:name="com.kunzisoft.keepass.credentialprovider.activity.AutofillLauncherActivity"
android:theme="@style/Theme.Transparent"
android:configChanges="keyboardHidden"
android:excludeFromRecents="true"/>
<activity
android:name="com.kunzisoft.keepass.credentialprovider.activity.EntrySelectionLauncherActivity"
android:theme="@style/Theme.Transparent"

View File

@@ -20,7 +20,6 @@
package com.kunzisoft.keepass.activities
import android.content.pm.PackageManager.NameNotFoundException
import android.os.Build
import android.os.Bundle
import android.text.method.LinkMovementMethod
import android.util.Log
@@ -32,7 +31,7 @@ import androidx.core.text.HtmlCompat
import com.kunzisoft.keepass.BuildConfig
import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.activities.stylish.StylishActivity
import com.kunzisoft.keepass.utils.UriUtil.isContributingUser
import com.kunzisoft.keepass.utils.AppUtil.isContributingUser
import com.kunzisoft.keepass.utils.getPackageInfoCompat
import org.joda.time.DateTime

View File

@@ -44,14 +44,14 @@ import androidx.recyclerview.widget.SimpleItemAnimator
import com.google.android.material.snackbar.Snackbar
import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.activities.dialogs.SetMainCredentialDialogFragment
import com.kunzisoft.keepass.credentialprovider.EntrySelectionHelper
import com.kunzisoft.keepass.activities.helpers.ExternalFileHelper
import com.kunzisoft.keepass.credentialprovider.SpecialMode
import com.kunzisoft.keepass.activities.helpers.setOpenDocumentClickListener
import com.kunzisoft.keepass.activities.legacy.DatabaseModeActivity
import com.kunzisoft.keepass.adapters.FileDatabaseHistoryAdapter
import com.kunzisoft.keepass.app.database.FileDatabaseHistoryAction
import com.kunzisoft.keepass.credentialprovider.EntrySelectionHelper
import com.kunzisoft.keepass.credentialprovider.EntrySelectionHelper.buildActivityResultLauncher
import com.kunzisoft.keepass.credentialprovider.SpecialMode
import com.kunzisoft.keepass.credentialprovider.TypeMode
import com.kunzisoft.keepass.credentialprovider.autofill.AutofillComponent
import com.kunzisoft.keepass.database.ContextualDatabase
@@ -66,10 +66,10 @@ import com.kunzisoft.keepass.services.DatabaseTaskNotificationService.Companion.
import com.kunzisoft.keepass.services.DatabaseTaskNotificationService.Companion.DATABASE_URI_KEY
import com.kunzisoft.keepass.settings.PreferencesUtil
import com.kunzisoft.keepass.tasks.ActionRunnable
import com.kunzisoft.keepass.utils.AppUtil.isContributingUser
import com.kunzisoft.keepass.utils.DexUtil
import com.kunzisoft.keepass.utils.MagikeyboardUtil
import com.kunzisoft.keepass.utils.MenuUtil
import com.kunzisoft.keepass.utils.UriUtil.isContributingUser
import com.kunzisoft.keepass.utils.UriUtil.openUrl
import com.kunzisoft.keepass.utils.getParcelableCompat
import com.kunzisoft.keepass.view.asError

View File

@@ -29,7 +29,11 @@ import android.view.MotionEvent
import android.view.View
import android.view.ViewGroup
import android.view.inputmethod.EditorInfo
import android.widget.*
import android.widget.AdapterView
import android.widget.ArrayAdapter
import android.widget.EditText
import android.widget.Spinner
import android.widget.TextView
import androidx.appcompat.app.AlertDialog
import com.google.android.material.textfield.TextInputLayout
import com.kunzisoft.keepass.R
@@ -40,15 +44,15 @@ import com.kunzisoft.keepass.otp.OtpElement.Companion.MAX_OTP_DIGITS
import com.kunzisoft.keepass.otp.OtpElement.Companion.MAX_TOTP_PERIOD
import com.kunzisoft.keepass.otp.OtpElement.Companion.MIN_HOTP_COUNTER
import com.kunzisoft.keepass.otp.OtpElement.Companion.MIN_OTP_DIGITS
import com.kunzisoft.keepass.otp.OtpElement.Companion.MIN_TOTP_PERIOD
import com.kunzisoft.keepass.otp.OtpElement.Companion.MIN_OTP_SECRET
import com.kunzisoft.keepass.otp.OtpElement.Companion.MIN_TOTP_PERIOD
import com.kunzisoft.keepass.otp.OtpTokenType
import com.kunzisoft.keepass.otp.OtpType
import com.kunzisoft.keepass.otp.TokenCalculator
import com.kunzisoft.keepass.utils.UriUtil.isContributingUser
import com.kunzisoft.keepass.utils.AppUtil.isContributingUser
import com.kunzisoft.keepass.utils.UriUtil.openUrl
import com.kunzisoft.keepass.utils.getParcelableCompat
import java.util.*
import java.util.Locale
class SetOTPDialogFragment : DatabaseDialogFragment() {

View File

@@ -44,7 +44,7 @@ import com.kunzisoft.keepass.database.ContextualDatabase
import com.kunzisoft.keepass.database.helper.SearchHelper
import com.kunzisoft.keepass.model.RegisterInfo
import com.kunzisoft.keepass.model.SearchInfo
import com.kunzisoft.keepass.utils.WebDomain
import com.kunzisoft.keepass.utils.AppUtil
import com.kunzisoft.keepass.utils.getParcelableCompat
import com.kunzisoft.keepass.utils.getParcelableExtraCompat
@@ -79,7 +79,7 @@ class AutofillLauncherActivity : DatabaseModeActivity() {
}
// Build search param
bundle.getParcelableCompat<SearchInfo>(KEY_SEARCH_INFO)?.let { searchInfo ->
WebDomain.getConcreteWebDomain(
AppUtil.getConcreteWebDomain(
this,
searchInfo.webDomain
) { concreteWebDomain ->
@@ -109,7 +109,7 @@ class AutofillLauncherActivity : DatabaseModeActivity() {
KEY_REGISTER_INFO
)
val searchInfo = SearchInfo(registerInfo?.searchInfo)
WebDomain.getConcreteWebDomain(this, searchInfo.webDomain) { concreteWebDomain ->
AppUtil.getConcreteWebDomain(this, searchInfo.webDomain) { concreteWebDomain ->
searchInfo.webDomain = concreteWebDomain
launchRegistration(database, searchInfo, registerInfo)
}

View File

@@ -33,8 +33,8 @@ import com.kunzisoft.keepass.database.ContextualDatabase
import com.kunzisoft.keepass.database.helper.SearchHelper
import com.kunzisoft.keepass.model.SearchInfo
import com.kunzisoft.keepass.otp.OtpEntryFields
import com.kunzisoft.keepass.utils.AppUtil
import com.kunzisoft.keepass.utils.KeyboardUtil.isKeyboardActivatedInSettings
import com.kunzisoft.keepass.utils.WebDomain
import com.kunzisoft.keepass.utils.getParcelableCompat
/**
@@ -109,7 +109,7 @@ class EntrySelectionLauncherActivity : DatabaseModeActivity() {
this.otpString = otpString
}
WebDomain.getConcreteWebDomain(this, searchInfo.webDomain) { concreteWebDomain ->
AppUtil.getConcreteWebDomain(this, searchInfo.webDomain) { concreteWebDomain ->
searchInfo.webDomain = concreteWebDomain
launch(database, searchInfo)
}

View File

@@ -53,7 +53,7 @@ import com.kunzisoft.keepass.model.RegisterInfo
import com.kunzisoft.keepass.model.SearchInfo
import com.kunzisoft.keepass.settings.AutofillSettingsActivity
import com.kunzisoft.keepass.settings.PreferencesUtil
import com.kunzisoft.keepass.utils.WebDomain
import com.kunzisoft.keepass.utils.AppUtil
import org.joda.time.DateTime
@@ -120,7 +120,7 @@ class KeeAutofillService : AutofillService() {
webDomain = parseResult.webDomain
webScheme = parseResult.webScheme
}
WebDomain.getConcreteWebDomain(this, searchInfo.webDomain) { webDomainWithoutSubDomain ->
AppUtil.getConcreteWebDomain(this, searchInfo.webDomain) { webDomainWithoutSubDomain ->
searchInfo.webDomain = webDomainWithoutSubDomain
val inlineSuggestionsRequest = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R
&& autofillInlineSuggestionsEnabled) {

View File

@@ -328,19 +328,54 @@ object PasskeyHelper {
return request.credentialOptions[0] as GetPublicKeyCredentialOption
}
private fun getOriginFromPrivilegedAllowList(
/**
* Get the origin from a privileged allow list,
* [fileName] is the name of the file in assets containing the origin list as JSON
*/
private fun getOriginFromPrivilegedAllowListFile(
callingAppInfo: CallingAppInfo,
assets: AssetManager,
fileName: String): String? {
fileName: String
): String? {
val privilegedAllowList = assets.open(fileName).bufferedReader().use {
it.readText()
}
return callingAppInfo.getOrigin(privilegedAllowList)?.removeSuffix("/")
}
/**
* Get the origin from the predefined privileged allow lists
*/
private fun getOriginFromPrivilegedAllowLists(
callingAppInfo: CallingAppInfo,
assets: AssetManager
): String? {
return try {
// TODO add the manual privileged apps
// Check the community apps first
getOriginFromPrivilegedAllowListFile(
callingAppInfo = callingAppInfo,
assets = assets,
fileName = FILE_NAME_PRIVILEGED_APPS_COMMUNITY
)
} catch (e: Exception) {
// Then the Google list if allowed
if (BuildConfig.CLOSED_STORE) {
// http://www.gstatic.com/gpm-passkeys-privileged-apps/apps.json
getOriginFromPrivilegedAllowListFile(
callingAppInfo = callingAppInfo,
assets = assets,
fileName = FILE_NAME_PRIVILEGED_APPS_GOOGLE
)
} else {
throw e
}
}
}
/**
* Utility method to retrieve the origin asynchronously,
* checks for the presence of the application in the privilege list of the fido2_privileged_google.json file,
* checks for the presence of the application in the privilege list of the passkeys_privileged_apps_google.json file,
* call [onOriginRetrieved] if the origin is already calculated by the system and in the privileged list, return the clientDataHash
* call [onOriginNotRetrieved] if the origin is not retrieved from the system, return a new Android Origin
*/
@@ -357,32 +392,15 @@ object PasskeyHelper {
withContext(Dispatchers.IO) {
// For trusted browsers like Chrome and Firefox
// Check the community apps first
val callOrigin = try {
getOriginFromPrivilegedAllowList(
callingAppInfo,
assets,
"fido2_privileged_community.json"
)
} catch (e: Exception) {
// Then the Google list if allowed
if (BuildConfig.CLOSED_STORE) {
getOriginFromPrivilegedAllowList(
callingAppInfo,
assets,
"fido2_privileged_google.json"
)
} else {
throw e
}
}
val callOrigin = getOriginFromPrivilegedAllowLists(callingAppInfo, assets)
// Build the default Android origin
val androidOrigin = AndroidOrigin(
packageName = callingAppInfo.packageName,
fingerprint = callingAppInfo.signingInfo.getApplicationFingerprints()
)
// Check if the webDomain is validated for the
// Check if the webDomain is validated by the system
withContext(Dispatchers.Main) {
if (callOrigin != null && providedClientDataHash != null) {
// Origin already defined by the system
@@ -624,4 +642,7 @@ object PasskeyHelper {
}
private const val BACKUP_ELIGIBILITY = true
private const val FILE_NAME_PRIVILEGED_APPS_COMMUNITY = "passkeys_privileged_apps_community.json"
private const val FILE_NAME_PRIVILEGED_APPS_GOOGLE = "passkeys_privileged_apps_google.json"
}

View File

@@ -14,7 +14,7 @@ import androidx.appcompat.app.AlertDialog
import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.activities.legacy.DatabaseModeActivity
import com.kunzisoft.keepass.database.ContextualDatabase
import com.kunzisoft.keepass.utils.UriUtil.openExternalApp
import com.kunzisoft.keepass.utils.AppUtil.openExternalApp
/**
* Special activity to deal with hardware key drivers,

View File

@@ -1,144 +0,0 @@
package com.kunzisoft.keepass.hardware
import android.app.Activity
import android.content.Intent
import android.os.Bundle
import android.util.Log
import androidx.activity.result.ActivityResult
import androidx.activity.result.ActivityResultCallback
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AlertDialog
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
import androidx.lifecycle.lifecycleScope
import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.utils.UriUtil.openExternalApp
import kotlinx.coroutines.launch
class HardwareKeyResponseHelper {
private var activity: FragmentActivity? = null
private var fragment: Fragment? = null
private var getChallengeResponseResultLauncher: ActivityResultLauncher<Intent>? = null
constructor(context: FragmentActivity) {
this.activity = context
this.fragment = null
}
constructor(context: Fragment) {
this.activity = context.activity
this.fragment = context
}
fun buildHardwareKeyResponse(onChallengeResponded: (challengeResponse: ByteArray?,
extra: Bundle?) -> Unit) {
val resultCallback = ActivityResultCallback<ActivityResult> { result ->
if (result.resultCode == Activity.RESULT_OK) {
val challengeResponse: ByteArray? = result.data?.getByteArrayExtra(HARDWARE_KEY_RESPONSE_KEY)
Log.d(TAG, "Response form challenge")
onChallengeResponded.invoke(challengeResponse,
result.data?.getBundleExtra(EXTRA_BUNDLE_KEY))
} else {
Log.e(TAG, "Response from challenge error")
onChallengeResponded.invoke(null,
result.data?.getBundleExtra(EXTRA_BUNDLE_KEY))
}
}
getChallengeResponseResultLauncher = if (fragment != null) {
fragment?.registerForActivityResult(
ActivityResultContracts.StartActivityForResult(),
resultCallback
)
} else {
activity?.registerForActivityResult(
ActivityResultContracts.StartActivityForResult(),
resultCallback
)
}
}
fun launchChallengeForResponse(hardwareKey: HardwareKey, seed: ByteArray?) {
when (hardwareKey) {
/*
HardwareKey.FIDO2_SECRET -> {
// TODO FIDO2 under development
throw Exception("FIDO2 not implemented")
}
*/
HardwareKey.CHALLENGE_RESPONSE_YUBIKEY -> {
// Transform the seed before sending
var challenge: ByteArray? = null
if (seed != null) {
challenge = ByteArray(64)
seed.copyInto(challenge, 0, 0, 32)
challenge.fill(32, 32, 64)
}
// Send to the driver
getChallengeResponseResultLauncher!!.launch(
Intent(YUBIKEY_CHALLENGE_RESPONSE_INTENT).apply {
putExtra(HARDWARE_KEY_CHALLENGE_KEY, challenge)
}
)
Log.d(TAG, "Challenge sent")
}
}
}
companion object {
private val TAG = HardwareKeyResponseHelper::class.java.simpleName
private const val YUBIKEY_CHALLENGE_RESPONSE_INTENT = "android.yubikey.intent.action.CHALLENGE_RESPONSE"
private const val HARDWARE_KEY_CHALLENGE_KEY = "challenge"
private const val HARDWARE_KEY_RESPONSE_KEY = "response"
private const val EXTRA_BUNDLE_KEY = "EXTRA_BUNDLE_KEY"
fun isHardwareKeyAvailable(
activity: FragmentActivity,
hardwareKey: HardwareKey,
showDialog: Boolean = true
): Boolean {
return when (hardwareKey) {
/*
HardwareKey.FIDO2_SECRET -> {
// TODO FIDO2 under development
if (showDialog)
UnderDevelopmentFeatureDialogFragment()
.show(activity.supportFragmentManager, "underDevFeatureDialog")
false
}
*/
HardwareKey.CHALLENGE_RESPONSE_YUBIKEY -> {
// Check available intent
val yubikeyDriverAvailable =
Intent(YUBIKEY_CHALLENGE_RESPONSE_INTENT)
.resolveActivity(activity.packageManager) != null
if (showDialog && !yubikeyDriverAvailable)
showHardwareKeyDriverNeeded(activity, hardwareKey)
yubikeyDriverAvailable
}
}
}
private fun showHardwareKeyDriverNeeded(
activity: FragmentActivity,
hardwareKey: HardwareKey
) {
activity.lifecycleScope.launch {
val builder = AlertDialog.Builder(activity)
builder
.setMessage(
activity.getString(R.string.error_driver_required, hardwareKey.toString())
)
.setPositiveButton(R.string.download) { _, _ ->
activity.openExternalApp(activity.getString(R.string.key_driver_app_id))
}
.setNegativeButton(android.R.string.cancel) { _, _ -> }
builder.create().show()
}
}
}
}

View File

@@ -21,7 +21,6 @@ package com.kunzisoft.keepass.settings
import android.content.ActivityNotFoundException
import android.content.Intent
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.provider.Settings
@@ -30,6 +29,7 @@ import android.view.autofill.AutofillManager
import android.widget.Toast
import androidx.annotation.RequiresApi
import androidx.appcompat.app.AlertDialog
import androidx.core.net.toUri
import androidx.fragment.app.DialogFragment
import androidx.fragment.app.FragmentActivity
import androidx.preference.ListPreference
@@ -47,7 +47,7 @@ import com.kunzisoft.keepass.icons.IconPackChooser
import com.kunzisoft.keepass.services.ClipboardEntryNotificationService
import com.kunzisoft.keepass.settings.preference.IconPackListPreference
import com.kunzisoft.keepass.settings.preferencedialogfragment.DurationDialogFragmentCompat
import com.kunzisoft.keepass.utils.UriUtil.isContributingUser
import com.kunzisoft.keepass.utils.AppUtil.isContributingUser
import com.kunzisoft.keepass.utils.UriUtil.openUrl
import com.kunzisoft.keepass.utils.UriUtil.releaseAllUnnecessaryPermissionUris
@@ -119,7 +119,7 @@ class NestedAppSettingsFragment : NestedSettingsFragment() {
activity?.let { activity ->
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val autoFillEnablePreference: TwoStatePreference? = findPreference(getString(R.string.settings_autofill_enable_key))
val autoFillEnablePreference: TwoStatePreference? = findPreference(getString(R.string.settings_credential_provider_enable_key))
activity.getSystemService(AutofillManager::class.java)?.let { autofillManager ->
if (autofillManager.hasEnabledAutofillServices())
autoFillEnablePreference?.isChecked = autofillManager.hasEnabledAutofillServices()
@@ -161,7 +161,7 @@ class NestedAppSettingsFragment : NestedSettingsFragment() {
val intent =
Intent(Settings.ACTION_REQUEST_SET_AUTOFILL_SERVICE)
intent.data =
Uri.parse("package:com.kunzisoft.keepass.autofill.KeeAutofillService")
"package:com.kunzisoft.keepass.autofill.KeeAutofillService".toUri()
Log.d(javaClass.name, "Autofill enable service: intent=$intent")
startActivity(intent)
} else {
@@ -171,7 +171,7 @@ class NestedAppSettingsFragment : NestedSettingsFragment() {
}
}
} else {
findPreference<Preference>(getString(R.string.autofill_key))?.isVisible = false
findPreference<Preference>(getString(R.string.credential_provider_key))?.isVisible = false
}
}
@@ -202,6 +202,11 @@ class NestedAppSettingsFragment : NestedSettingsFragment() {
false
}
findPreference<Preference>(getString(R.string.settings_passkeys_key))?.setOnPreferenceClickListener {
startActivity(Intent(context, PasskeysSettingsActivity::class.java))
false
}
findPreference<Preference>(getString(R.string.clipboard_notifications_key))?.setOnPreferenceChangeListener { _, newValue ->
if (!(newValue as Boolean)) {
ClipboardEntryNotificationService.removeNotification(context)
@@ -530,7 +535,7 @@ class NestedAppSettingsFragment : NestedSettingsFragment() {
super.onResume()
activity?.let { activity ->
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
findPreference<TwoStatePreference?>(getString(R.string.settings_autofill_enable_key))?.let { autoFillEnablePreference ->
findPreference<TwoStatePreference?>(getString(R.string.settings_credential_provider_enable_key))?.let { autoFillEnablePreference ->
val autofillManager = activity.getSystemService(AutofillManager::class.java)
autoFillEnablePreference.isChecked = autofillManager != null
&& autofillManager.hasEnabledAutofillServices()

View File

@@ -0,0 +1,34 @@
/*
* Copyright 2025 Jeremy Jamet / Kunzisoft.
*
* This file is part of KeePassDX.
*
* KeePassDX is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* KeePassDX is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with KeePassDX. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.kunzisoft.keepass.settings
import androidx.preference.PreferenceFragmentCompat
import com.kunzisoft.keepass.R
class PasskeysSettingsActivity : ExternalSettingsActivity() {
override fun retrieveTitle(): Int {
return R.string.passkeys_preference_title
}
override fun retrievePreferenceFragment(): PreferenceFragmentCompat {
return PasskeysSettingsFragment()
}
}

View File

@@ -0,0 +1,63 @@
/*
* Copyright 2025 Jeremy Jamet / Kunzisoft.
*
* This file is part of KeePassDX.
*
* KeePassDX is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* KeePassDX is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with KeePassDX. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.kunzisoft.keepass.settings
import android.os.Build
import android.os.Bundle
import androidx.fragment.app.DialogFragment
import androidx.preference.Preference
import androidx.preference.PreferenceFragmentCompat
import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.settings.preferencedialogfragment.PasskeysPrivilegedAppsPreferenceDialogFragmentCompat
class PasskeysSettingsFragment : PreferenceFragmentCompat() {
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
// Load the preferences from an XML resource
setPreferencesFromResource(R.xml.preferences_passkeys, rootKey)
}
override fun onDisplayPreferenceDialog(preference: Preference) {
var otherDialogFragment = false
var dialogFragment: DialogFragment? = null
when (preference.key) {
getString(R.string.passkeys_privileged_apps_key) -> {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
dialogFragment = PasskeysPrivilegedAppsPreferenceDialogFragmentCompat.newInstance(preference.key)
}
}
else -> otherDialogFragment = true
}
if (dialogFragment != null) {
dialogFragment.setTargetFragment(this, 0)
dialogFragment.show(parentFragmentManager, TAG_PASSKEYS_PREF_FRAGMENT)
} else if (otherDialogFragment) {
super.onDisplayPreferenceDialog(preference)
}
}
companion object {
private const val TAG_PASSKEYS_PREF_FRAGMENT = "TAG_PASSKEYS_PREF_FRAGMENT"
}
}

View File

@@ -35,8 +35,8 @@ import com.kunzisoft.keepass.database.search.SearchParameters
import com.kunzisoft.keepass.education.Education
import com.kunzisoft.keepass.password.PassphraseGenerator
import com.kunzisoft.keepass.timeout.TimeoutHelper
import com.kunzisoft.keepass.utils.AppUtil.isContributingUser
import com.kunzisoft.keepass.utils.KeyboardUtil.isKeyboardActivatedInSettings
import com.kunzisoft.keepass.utils.UriUtil.isContributingUser
import java.util.Properties
object PreferencesUtil {
@@ -821,7 +821,7 @@ object PreferencesUtil {
context.getString(R.string.clipboard_notifications_key) -> editor.putBoolean(name, value.toBoolean())
context.getString(R.string.clear_clipboard_notification_key) -> editor.putBoolean(name, value.toBoolean())
context.getString(R.string.clipboard_timeout_key) -> editor.putString(name, value.toLong().toString())
context.getString(R.string.settings_autofill_enable_key) -> editor.putBoolean(name, value.toBoolean())
context.getString(R.string.settings_credential_provider_enable_key) -> editor.putBoolean(name, value.toBoolean())
context.getString(R.string.keyboard_notification_entry_key) -> editor.putBoolean(name, value.toBoolean())
context.getString(R.string.keyboard_notification_entry_clear_close_key) -> editor.putBoolean(name, value.toBoolean())
context.getString(R.string.keyboard_entry_timeout_key) -> editor.putString(name, value.toLong().toString())

View File

@@ -0,0 +1,73 @@
/*
* Copyright 2025 Jeremy Jamet / Kunzisoft.
*
* This file is part of KeePassDX.
*
* KeePassDX is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* KeePassDX is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with KeePassDX. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.kunzisoft.keepass.settings.preferencedialogfragment
import android.os.Build
import android.os.Bundle
import android.view.View
import androidx.annotation.RequiresApi
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.model.AndroidOrigin
import com.kunzisoft.keepass.settings.preferencedialogfragment.adapter.ListSelectionItemAdapter
import com.kunzisoft.keepass.utils.AppUtil.getInstalledBrowsersWithSignatures
@RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
class PasskeysPrivilegedAppsPreferenceDialogFragmentCompat
: InputPreferenceDialogFragmentCompat() {
private var mAdapter = ListSelectionItemAdapter<AndroidOrigin>()
private var mListBrowsers: List<AndroidOrigin> = mutableListOf()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
mListBrowsers = getInstalledBrowsersWithSignatures(requireContext())
// TODO filter with current privileged apps
}
override fun onBindDialogView(view: View) {
super.onBindDialogView(view)
view.findViewById<RecyclerView>(R.id.pref_dialog_list).apply {
layoutManager = LinearLayoutManager(context)
adapter = mAdapter.apply {
setItems(mListBrowsers)
}
}
}
override fun onDialogClosed(positiveResult: Boolean) {
if (positiveResult) {
// TODO Save selected item in JSON
mAdapter.selectedItem
}
}
companion object {
fun newInstance(key: String): PasskeysPrivilegedAppsPreferenceDialogFragmentCompat {
val fragment = PasskeysPrivilegedAppsPreferenceDialogFragmentCompat()
val bundle = Bundle(1)
bundle.putString(ARG_KEY, key)
fragment.arguments = bundle
return fragment
}
}
}

View File

@@ -0,0 +1,78 @@
/*
* Copyright 2025 Jeremy Jamet / Kunzisoft.
*
* This file is part of KeePassDX.
*
* KeePassDX is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* KeePassDX is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with KeePassDX. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.kunzisoft.keepass.settings.preferencedialogfragment.adapter
import android.annotation.SuppressLint
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import com.kunzisoft.keepass.R
class ListSelectionItemAdapter<T>()
: RecyclerView.Adapter<ListSelectionItemAdapter.SelectionViewHolder>() {
private val itemList: MutableList<T> = ArrayList()
var selectedItem: T? = null
private set
var itemSelectedCallback: ItemSelectedCallback<T>? = null
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SelectionViewHolder {
return SelectionViewHolder(LayoutInflater.from(parent.context)
.inflate(R.layout.pref_dialog_list_item, parent, false))
}
@SuppressLint("SetTextI18n", "NotifyDataSetChanged")
override fun onBindViewHolder(holder: SelectionViewHolder, position: Int) {
val item = itemList[position]
holder.container.apply {
isSelected = item == selectedItem
}
holder.textView.apply {
text = item.toString()
setOnClickListener {
selectedItem = if (item == selectedItem) null else item
itemSelectedCallback?.onItemSelected(item)
notifyDataSetChanged()
}
}
}
override fun getItemCount(): Int {
return itemList.size
}
fun setItems(items: List<T>) {
this.itemList.clear()
this.itemList.addAll(items)
}
interface ItemSelectedCallback<T> {
fun onItemSelected(item: T)
}
class SelectionViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
var textView: TextView = itemView.findViewById(R.id.pref_dialog_list_text)
var container: ViewGroup = itemView.findViewById(R.id.pref_dialog_list_container)
}
}

View File

@@ -0,0 +1,147 @@
package com.kunzisoft.keepass.utils
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.content.pm.ResolveInfo
import android.os.Build
import android.util.Log
import androidx.annotation.RequiresApi
import androidx.core.net.toUri
import com.kunzisoft.encrypt.Signature.getApplicationFingerprints
import com.kunzisoft.keepass.BuildConfig
import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.education.Education
import com.kunzisoft.keepass.model.AndroidOrigin
import com.kunzisoft.keepass.model.SearchInfo
import com.kunzisoft.keepass.settings.PreferencesUtil
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import mozilla.components.lib.publicsuffixlist.PublicSuffixList
object AppUtil {
fun Context.isExternalAppInstalled(packageName: String, showError: Boolean = true): Boolean {
try {
this.applicationContext.packageManager.getPackageInfoCompat(
packageName,
PackageManager.GET_ACTIVITIES
)
Education.setEducationScreenReclickedPerformed(this)
return true
} catch (e: Exception) {
if (showError)
Log.e(AppUtil::class.simpleName, "App not accessible", e)
}
return false
}
fun Context.openExternalApp(packageName: String, sourcesURL: String? = null) {
var launchIntent: Intent? = null
try {
launchIntent = this.packageManager.getLaunchIntentForPackage(packageName)?.apply {
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
}
} catch (ignored: Exception) { }
try {
if (launchIntent == null) {
this.startActivity(
Intent(Intent.ACTION_VIEW)
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
.setData(
if (sourcesURL != null
&& !BuildConfig.CLOSED_STORE
) {
sourcesURL
} else {
this.getString(
if (BuildConfig.CLOSED_STORE)
R.string.play_store_url
else
R.string.f_droid_url,
packageName
)
}.toUri()
)
)
} else {
this.startActivity(launchIntent)
}
} catch (e: Exception) {
Log.e(AppUtil::class.simpleName, "App cannot be open", e)
}
}
fun Context.isContributingUser(): Boolean {
return (Education.isEducationScreenReclickedPerformed(this)
|| isExternalAppInstalled(this.getString(R.string.keepro_app_id), false)
)
}
/**
* Get the concrete web domain AKA without sub domain if needed
*/
fun getConcreteWebDomain(context: Context,
webDomain: String?,
concreteWebDomain: (String?) -> Unit) {
CoroutineScope(Dispatchers.Main).launch {
if (webDomain != null) {
// Warning, web domain can contains IP, don't crop in this case
if (PreferencesUtil.searchSubdomains(context)
|| Regex(SearchInfo.WEB_IP_REGEX).matches(webDomain)) {
concreteWebDomain.invoke(webDomain)
} else {
val publicSuffixList = PublicSuffixList(context)
concreteWebDomain.invoke(publicSuffixList
.getPublicSuffixPlusOne(webDomain).await())
}
} else {
concreteWebDomain.invoke(null)
}
}
}
@RequiresApi(Build.VERSION_CODES.P)
fun getInstalledBrowsersWithSignatures(context: Context): List<AndroidOrigin> {
val packageManager = context.packageManager
val browserList = mutableListOf<AndroidOrigin>()
// Create a generic web intent
val intent = Intent(Intent.ACTION_VIEW)
intent.data = "http://www.example.com".toUri() // Dummy URL
// Query for apps that can handle this intent
val resolveInfoList: List<ResolveInfo> = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
packageManager.queryIntentActivities(
intent,
PackageManager.ResolveInfoFlags.of(PackageManager.MATCH_ALL.toLong())
)
} else {
@Suppress("DEPRECATION")
packageManager.queryIntentActivities(intent, PackageManager.MATCH_ALL)
}
val processedPackageNames = mutableSetOf<String>()
for (resolveInfo in resolveInfoList) {
val packageName = resolveInfo.activityInfo.packageName
if (packageName != null && !processedPackageNames.contains(packageName)) {
try {
val packageInfo = packageManager.getPackageInfo(
packageName,
PackageManager.GET_SIGNING_CERTIFICATES
)
val signatureFingerprints = packageInfo.signingInfo.getApplicationFingerprints()
signatureFingerprints?.let {
browserList.add(AndroidOrigin(packageName, signatureFingerprints))
processedPackageNames.add(packageName)
}
} catch (e: Exception) {
Log.e(AppUtil::class.simpleName, "Error processing package: $packageName", e)
}
}
}
return browserList.distinctBy { it.packageName } // Ensure uniqueness just in case
}
}

View File

@@ -28,7 +28,7 @@ import android.view.MenuItem
import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.activities.AboutActivity
import com.kunzisoft.keepass.settings.SettingsActivity
import com.kunzisoft.keepass.utils.UriUtil.isContributingUser
import com.kunzisoft.keepass.utils.AppUtil.isContributingUser
import com.kunzisoft.keepass.utils.UriUtil.openUrl
object MenuUtil {
@@ -40,9 +40,6 @@ object MenuUtil {
menu.findItem(R.id.menu_contribute)?.isVisible = false
}
/*
* @param checkLock Check the time lock before launch settings in LockingActivity
*/
fun onDefaultMenuOptionsItemSelected(activity: Activity,
item: MenuItem,
timeoutEnable: Boolean = false) {

View File

@@ -200,64 +200,5 @@ object UriUtil {
this.openUrl(this.getString(resId))
}
fun Context.isContributingUser(): Boolean {
return (Education.isEducationScreenReclickedPerformed(this)
|| isExternalAppInstalled(this.getString(R.string.keepro_app_id), false)
)
}
fun Context.isExternalAppInstalled(packageName: String, showError: Boolean = true): Boolean {
try {
this.applicationContext.packageManager.getPackageInfoCompat(
packageName,
PackageManager.GET_ACTIVITIES
)
Education.setEducationScreenReclickedPerformed(this)
return true
} catch (e: Exception) {
if (showError)
Log.e(TAG, "App not accessible", e)
}
return false
}
fun Context.openExternalApp(packageName: String, sourcesURL: String? = null) {
var launchIntent: Intent? = null
try {
launchIntent = this.packageManager.getLaunchIntentForPackage(packageName)?.apply {
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
}
} catch (ignored: Exception) { }
try {
if (launchIntent == null) {
this.startActivity(
Intent(Intent.ACTION_VIEW)
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
.setData(
Uri.parse(
if (sourcesURL != null
&& !BuildConfig.CLOSED_STORE
) {
sourcesURL
} else {
this.getString(
if (BuildConfig.CLOSED_STORE)
R.string.play_store_url
else
R.string.f_droid_url,
packageName
)
}
)
)
)
} else {
this.startActivity(launchIntent)
}
} catch (e: Exception) {
Log.e(TAG, "App cannot be open", e)
}
}
private const val TAG = "UriUtil"
}

View File

@@ -1,35 +0,0 @@
package com.kunzisoft.keepass.utils
import android.content.Context
import com.kunzisoft.keepass.model.SearchInfo
import com.kunzisoft.keepass.settings.PreferencesUtil
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import mozilla.components.lib.publicsuffixlist.PublicSuffixList
object WebDomain {
/**
* Get the concrete web domain AKA without sub domain if needed
*/
fun getConcreteWebDomain(context: Context,
webDomain: String?,
concreteWebDomain: (String?) -> Unit) {
CoroutineScope(Dispatchers.Main).launch {
if (webDomain != null) {
// Warning, web domain can contains IP, don't crop in this case
if (PreferencesUtil.searchSubdomains(context)
|| Regex(SearchInfo.WEB_IP_REGEX).matches(webDomain)) {
concreteWebDomain.invoke(webDomain)
} else {
val publicSuffixList = PublicSuffixList(context)
concreteWebDomain.invoke(publicSuffixList
.getPublicSuffixPlusOne(webDomain).await())
}
} else {
concreteWebDomain.invoke(null)
}
}
}
}

View File

@@ -20,7 +20,6 @@
package com.kunzisoft.keepass.view
import android.content.Context
import android.os.Build
import android.text.InputFilter
import android.text.util.Linkify
import android.util.AttributeSet
@@ -37,7 +36,7 @@ import androidx.core.view.ViewCompat
import androidx.core.view.isVisible
import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.model.AppOriginEntryField.APPLICATION_ID_FIELD_NAME
import com.kunzisoft.keepass.utils.UriUtil.openExternalApp
import com.kunzisoft.keepass.utils.AppUtil.openExternalApp
open class TextFieldView @JvmOverloads constructor(context: Context,

View File

@@ -0,0 +1,35 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2019 Jeremy Jamet / Kunzisoft.
This file is part of KeePassDX.
KeePassDX is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
KeePassDX is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with KeePassDX. If not, see <http://www.gnu.org/licenses/>.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/pref_dialog_list_container"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:minHeight="@dimen/selectable_min_height"
style="@style/KeepassDXStyle.Selectable.Item"
android:layout_margin="8dp">
<TextView
android:id="@+id/pref_dialog_list_text"
android:layout_margin="8dp"
style="@style/KeepassDXStyle.Title.Entry"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>

View File

@@ -167,7 +167,7 @@
<string name="general">عام</string>
<string name="autofill">الملء التلقائي</string>
<string name="autofill_sign_in_prompt">سجل باستخدام KeePassDX</string>
<string name="set_autofill_service_title">تعيين خدمة الملأ التلقائي الافتراضية</string>
<string name="set_credential_provider_service_title">تعيين خدمة الملأ التلقائي الافتراضية</string>
<string name="password_size_title">حجم كلمة السر المولدة</string>
<string name="password_size_summary">تعيين الحجم الافتراضي لكلمات السر المولدة</string>
<string name="list_password_generator_options_title">محارف كلمة السر</string>

View File

@@ -518,7 +518,7 @@
<string name="device_unlock_prompt_not_initialized">Cihaz kilid açma istəyini başlatmaq mümkün deyil.</string>
<string name="autofill_explanation_summary">Digər tətbiqlərdə formları (anket) daha sürətli doldurmaq üçün avtomatik doldurma funksiyasını aktiv edin</string>
<string name="autofill_select_entry">Şifrə seç .…</string>
<string name="set_autofill_service_title">Standart avtomatik doldurma xidmətini təyin edin</string>
<string name="set_credential_provider_service_title">Standart avtomatik doldurma xidmətini təyin edin</string>
<string name="autofill_preference_title">Avtomatik doldurmanın parametrləri</string>
<string name="password_size_title">Yaradılan şifrə həcmi</string>
<string name="password_size_summary">Yaradılan şifrələrin standart həcmini təyin edər</string>

View File

@@ -288,7 +288,7 @@
<string name="read_only">Само за четене</string>
<string name="contains_duplicate_uuid">Хранилището съдържа повтарящ се идентификатор.</string>
<string name="biometric">Биометричен ключ</string>
<string name="set_autofill_service_title">Задаване на подразбирана услуга за автоматично попълване</string>
<string name="set_credential_provider_service_title">Задаване на подразбирана услуга за автоматично попълване</string>
<string name="password_size_title">Дължина на създаваните пароли</string>
<string name="lock_database_back_root_title">Заключване при „Назад“</string>
<string name="content">Съдържание</string>

View File

@@ -410,7 +410,7 @@
<string name="waiting_challenge_response">Esperant la resposta de desafiament…</string>
<string name="bank_name">Nom del banc</string>
<string name="wireless">Wi-Fi</string>
<string name="set_autofill_service_title">Estableix el servei d\'emplenament automàtic predeterminat</string>
<string name="set_credential_provider_service_title">Estableix el servei d\'emplenament automàtic predeterminat</string>
<string name="compression">Compressió</string>
<string name="id_card">Targeta d\'identificació</string>
<string name="error_hardware_key_unsupported">Clau física no suportada.</string>

View File

@@ -181,7 +181,7 @@
<string name="autofill">Samovyplnění</string>
<string name="autofill_service_name">KeePassDX samovyplnění formulářů</string>
<string name="autofill_sign_in_prompt">Přihlásit se s KeePassDX</string>
<string name="set_autofill_service_title">Nastavit výchozí službu samovyplnění</string>
<string name="set_credential_provider_service_title">Nastavit výchozí službu samovyplnění</string>
<string name="autofill_explanation_summary">Zapnout samovyplnění formulářů za účelem rychlého vyplnění v ostatních aplikacích</string>
<string name="password_size_title">Délka generovaného hesla</string>
<string name="password_size_summary">Nastavení výchozí délky generovaných hesel</string>

View File

@@ -180,7 +180,7 @@
<string name="autofill">Autoudfyld</string>
<string name="autofill_service_name">KeePassDX formularudfyldning</string>
<string name="autofill_sign_in_prompt">Log ind med KeePassDX</string>
<string name="set_autofill_service_title">Indstil standard autoudfyldningstjeneste</string>
<string name="set_credential_provider_service_title">Indstil standard autoudfyldningstjeneste</string>
<string name="autofill_explanation_summary">Aktiver autofyldning for hurtigt at udfylde formularer i andre apps</string>
<string name="password_size_title">Genereret adgangskodelængde</string>
<string name="password_size_summary">Angiver standardlængden for genererede adgangskoder</string>

View File

@@ -197,7 +197,7 @@
<string name="autofill">Automatisches Ausfüllen</string>
<string name="autofill_service_name">KeePassDX Auto-Formularausfüllung</string>
<string name="autofill_sign_in_prompt">Mit KeePassDX anmelden</string>
<string name="set_autofill_service_title">Standard-Autofill-Service festlegen</string>
<string name="set_credential_provider_service_title">Standard-Autofill-Service festlegen</string>
<string name="autofill_explanation_summary">Automatisches Ausfüllen aktivieren, um Formulare in anderen Apps schnell auszufüllen</string>
<string name="autofill_select_entry">Eintrag auswählen </string>
<string name="clipboard">Zwischenablage</string>

View File

@@ -169,7 +169,7 @@
<string name="autofill">Αυτόματη συμπλήρωση</string>
<string name="autofill_service_name">Μορφή KeePassDX αυτόματης συμπλήρωσης</string>
<string name="autofill_sign_in_prompt">Συνδεθείτε με το KeePassDX</string>
<string name="set_autofill_service_title">Ορίστε την προεπιλεγμένη υπηρεσία αυτόματης συμπλήρωσης</string>
<string name="set_credential_provider_service_title">Ορίστε την προεπιλεγμένη υπηρεσία αυτόματης συμπλήρωσης</string>
<string name="password_size_title">Παραγόμενο μέγεθος κωδικού πρόσβασης</string>
<string name="password_size_summary">Ορίστε το προεπιλεγμένο μέγεθος των παραγόμενων κωδικών πρόσβασης</string>
<string name="list_password_generator_options_title">Χαρακτήρες Κωδικού Πρόσβασης</string>

View File

@@ -172,7 +172,7 @@
<string name="autofill">Autocompletado</string>
<string name="autofill_service_name">Autocompletado de formularios de KeePassDX</string>
<string name="autofill_sign_in_prompt">Iniciar sesión con KeePassDX</string>
<string name="set_autofill_service_title">Establecer servicio de autocompletado por defecto</string>
<string name="set_credential_provider_service_title">Establecer servicio de autocompletado por defecto</string>
<string name="password_size_title">Tamaño de la contraseña generada</string>
<string name="password_size_summary">Establece el tamaño predeterminado de las contraseñas generadas</string>
<string name="list_password_generator_options_title">Caracteres de contraseña</string>

View File

@@ -474,7 +474,7 @@
<string name="autofill_service_name">KeePassDXi automaattäite teenus</string>
<string name="autofill_explanation_summary">Täitmaks andmevorme teistes rakenduses, luba automaattäite teenus</string>
<string name="autofill_select_entry">Vali kirje…</string>
<string name="set_autofill_service_title">Vali vaikimisi kasutatav automaattäite teenus</string>
<string name="set_credential_provider_service_title">Vali vaikimisi kasutatav automaattäite teenus</string>
<string name="autofill_preference_title">Automaattäite teenuse seadistused</string>
<string name="database_opened">Andmebaas on avatud</string>
<string name="clipboard">Lõikelaud</string>

View File

@@ -575,7 +575,7 @@
<string name="warning_database_revoked">Fitxategirako atzipena baliogabetu du fitxategi kudeatzaileak, itxi datu-basea eta berriro ireki ezazu bere lokalizaziotik.</string>
<string name="device_unlock_prompt_store_credential_title">Gailuaren desblokeorako esteka</string>
<string name="device_unlock_prompt_not_initialized">Ezin izan da hasieratu gailuaren desblokeatze menua.</string>
<string name="set_autofill_service_title">Lehenetsi betetze automatiko zerbitzua</string>
<string name="set_credential_provider_service_title">Lehenetsi betetze automatiko zerbitzua</string>
<string name="content">Edukia</string>
<string name="education_device_unlock_title">Datu-basearen desblokeatze automatikoa</string>
<string name="screenshot_mode_banner_text">Pantaila-argazki modua</string>

View File

@@ -237,7 +237,7 @@
<string name="kdf_explanation">Pääavain muunnetaan käyttäen satunnaista suolattua avaimen johtamisfunktiota, jotta salausalgoritmin avain voidaan generoida.</string>
<string name="encryption_explanation">Salasanatietokannan salausalgoritmi, jota käytetään kaikelle datalle.</string>
<string name="password_size_title">Generoidun salasanan pituus</string>
<string name="set_autofill_service_title">Aseta oletus automaattiselle täytölle</string>
<string name="set_credential_provider_service_title">Aseta oletus automaattiselle täytölle</string>
<string name="autofill_sign_in_prompt">Kirjaudu sisään KeePassDX:llä</string>
<string name="autofill_service_name">KeePassDX:n automaattinen täyttö</string>
<string name="autofill">Automaattinen täyttö</string>

View File

@@ -165,7 +165,7 @@
<string name="autofill">Remplissage automatique</string>
<string name="autofill_service_name">Remplissage automatique des formulaires KeePassDX</string>
<string name="autofill_sign_in_prompt">Se connecter avec KeePassDX</string>
<string name="set_autofill_service_title">Définir le service de remplissage automatique par défaut</string>
<string name="set_credential_provider_service_title">Définir le service de remplissage automatique par défaut</string>
<string name="autofill_explanation_summary">Activer le remplissage automatique pour remplir rapidement des formulaires dans dautres applications</string>
<string name="autofill_select_entry">Sélectionner une entrée…</string>
<string name="password_size_title">Taille du mot de passe généré</string>

View File

@@ -373,7 +373,7 @@
<string name="biometric">Biométrico</string>
<string name="autofill_explanation_summary">Habilite o servizo para autocompletar rapidamente os formularios de outras aplicacións</string>
<string name="clipboard_notifications_title">Notificacións do portapapeis</string>
<string name="set_autofill_service_title">Estabelecer o servizo de autocompletado predefinido</string>
<string name="set_credential_provider_service_title">Estabelecer o servizo de autocompletado predefinido</string>
<string name="lock_database_back_root_summary">Bloquear a base de datos cando o usuario faga click no botón de volver á pantalla principal</string>
<string name="lock_database_show_button_title">Mostrar botón de bloqueo</string>
<string name="clipboard_notifications_summary">Mostrar notificacións do portapapeis ao visualizar unha entrada</string>

View File

@@ -178,7 +178,7 @@
<string name="general">Opće</string>
<string name="autofill">Automatsko ispunjavanje</string>
<string name="autofill_service_name">Automatsko ispunjavanje KeePassDX obrasca</string>
<string name="set_autofill_service_title">Postavi standardnu uslugu automatskog ispunjavanja</string>
<string name="set_credential_provider_service_title">Postavi standardnu uslugu automatskog ispunjavanja</string>
<string name="list_password_generator_options_title">Znakovi lozinke</string>
<string name="list_password_generator_options_summary">Postavi dozvoljene znakove za generiranje lozinke</string>
<string name="database_opened">Baza podataka otvorena</string>

View File

@@ -185,7 +185,7 @@
<string name="autofill">Automatikus kitöltés</string>
<string name="autofill_service_name">KeePassDX űrlapkitöltés</string>
<string name="autofill_sign_in_prompt">Bejelentkezés a KeePassDX-szel</string>
<string name="set_autofill_service_title">Alapértelmezett automatikus kitöltési szolgáltatás beállítása</string>
<string name="set_credential_provider_service_title">Alapértelmezett automatikus kitöltési szolgáltatás beállítása</string>
<string name="autofill_explanation_summary">Automatikus kitöltés engedélyezése az űrlapok gyors kitöltéséhez más alkalmazásokban</string>
<string name="password_size_title">Előállított jelszó mérete</string>
<string name="password_size_summary">Beállítja az előállított jelszavak alapértelmezett méretét</string>

View File

@@ -423,7 +423,7 @@
<string name="credential_before_click_device_unlock_button">Ketik kata sandi, lalu klik tombol ini.</string>
<string name="autofill_service_name">Isi formulir KeePassDX otomatis</string>
<string name="autofill_preference_title">Pengaturan isi otomatis</string>
<string name="set_autofill_service_title">Setel layanan isi otomatis secara default</string>
<string name="set_credential_provider_service_title">Setel layanan isi otomatis secara default</string>
<string name="autofill_explanation_summary">Aktifkan pengisian otomatis untuk mengisi formulir dengan cepat di aplikasi lain</string>
<string name="autofill_sign_in_prompt">Masuk dengan KeePassDX</string>
<string name="autofill">Isi otomatis</string>

View File

@@ -180,7 +180,7 @@
<string name="autofill">Autocompletamento</string>
<string name="autofill_service_name">Autocompletamento di KeePassDX</string>
<string name="autofill_sign_in_prompt">Accedi con KeePassDX</string>
<string name="set_autofill_service_title">Servizio predefinito di autocompletamento</string>
<string name="set_credential_provider_service_title">Servizio predefinito di autocompletamento</string>
<string name="autofill_explanation_summary">Attiva l\'autocompletamento per riempire velocemente i campi in altre app</string>
<string name="password_size_title">Dimensione password generata</string>
<string name="password_size_summary">Imposta la dimensione predefinita delle password generate</string>

View File

@@ -414,7 +414,7 @@
<string name="autofill_sign_in_prompt">התחבר עם KeePassDX</string>
<string name="general">כללי</string>
<string name="autofill_explanation_summary">הפעל מילוי אוטומטי כדי למלא במהירות טפסים ביישומים אחרים</string>
<string name="set_autofill_service_title">הגדר שירות מילוי אוטומטי ברירת מחדל</string>
<string name="set_credential_provider_service_title">הגדר שירות מילוי אוטומטי ברירת מחדל</string>
<string name="password_size_title">גודל סיסמה שנוצרה</string>
<string name="password_size_summary">מגדיר גודל ברירת המחדל של הסיסמאות שנוצרו</string>
<string name="list_password_generator_options_title">תווי סיסמה</string>

View File

@@ -276,7 +276,7 @@
<string name="autofill_service_name">KeePassDX フォーム自動入力</string>
<string name="autofill_sign_in_prompt">KeePassDX でログイン</string>
<string name="autofill_explanation_summary">自動入力を有効にして、他のアプリ内のフォームにすばやく入力します</string>
<string name="set_autofill_service_title">デフォルトの自動入力サービスに設定</string>
<string name="set_credential_provider_service_title">デフォルトの自動入力サービスに設定</string>
<string name="autofill_preference_title">自動入力の設定</string>
<string name="password_size_title">生成されるパスワードの長さ</string>
<string name="password_size_summary">生成されるパスワードの長さのデフォルト値を設定します</string>

View File

@@ -385,7 +385,7 @@
<string name="autofill_sign_in_prompt">KeePassDX로 로그인</string>
<string name="password_size_title">생성된 비밀번호 크기</string>
<string name="autofill_preference_title">자동 완성 설정</string>
<string name="set_autofill_service_title">기본 자동완성 서비스 설정</string>
<string name="set_credential_provider_service_title">기본 자동완성 서비스 설정</string>
<string name="lock_database_screen_off_title">화면 꺼짐 시 잠금</string>
<string name="device_unlock_explanation_summary">기기 잠금 방식을 사용하여 데이터베이스를 더 쉽게 여세요</string>
<string name="biometric_unlock_enable_title">생체 인식 잠금 해제</string>

View File

@@ -361,7 +361,7 @@
<string name="warning_keyfile_integrity">Failo \"hash\" reikšmė nėra garantuota, nes \"Android\" gali keisti jo duomenis. Norėdami užtikrinti teisingą vientisumą, pakeiskite failo plėtinį į .bin.</string>
<string name="configure_biometric">Biometriniai duomenys ar prietaiso įgaliojimai neįrašomi.</string>
<string name="autofill_preference_title">Automatinio pildymo nustatymai</string>
<string name="set_autofill_service_title">Nustatyti numatytąją automatinio pildymo paslaugą</string>
<string name="set_credential_provider_service_title">Nustatyti numatytąją automatinio pildymo paslaugą</string>
<string name="lock_database_screen_off_title">Ekrano užraktas</string>
<string name="biometric_unlock_enable_title">Biometrinis atrakinimas</string>
<string name="show_uuid_title">Rodyti UUID</string>

View File

@@ -339,7 +339,7 @@
<string name="clipboard_explanation_summary">നിങ്ങളുടെ ഉപകരണത്തിന്റെ ക്ലിപ്പ്ബോർഡ് ഉപയോഗിച്ച് എൻട്രി ഫീൽഡുകൾ പകർത്തുക</string>
<string name="list_password_generator_options_title">പാസ്‌വേഡ് പ്രതീകങ്ങൾ</string>
<string name="password_size_summary">സൃഷ്ടിച്ച പാസ്‌വേഡുകളുടെ സ്ഥിരസ്ഥിതി വലുപ്പം സജ്ജമാക്കുക</string>
<string name="set_autofill_service_title">സ്ഥിരസ്ഥിതി ഓട്ടോഫിൽ സേവനം സജ്ജമാക്കുക</string>
<string name="set_credential_provider_service_title">സ്ഥിരസ്ഥിതി ഓട്ടോഫിൽ സേവനം സജ്ജമാക്കുക</string>
<string name="autofill_explanation_summary">മറ്റ് അപ്ലിക്കേഷനുകളിൽ ഫോമുകൾ വേഗത്തിൽ പൂരിപ്പിക്കുന്നതിന് ഓട്ടോഫില്ലിംഗ് പ്രവർത്തനക്ഷമമാക്കുക</string>
<string name="keystore_not_accessible">കീസ്റ്റോർ ശരിയായി സമാരംഭിച്ചിട്ടില്ല.</string>
<string name="sort_recycle_bin_bottom">റീസൈക്കിൾ ബിൻ ചുവടെയുണ്ട്</string>

View File

@@ -175,7 +175,7 @@
<string name="autofill">Autofyll</string>
<string name="autofill_service_name">KeePassDX autofyll-tjeneste</string>
<string name="autofill_sign_in_prompt">Logg inn med KeePassDX</string>
<string name="set_autofill_service_title">Sett forvalgt autofyll-tjeneste</string>
<string name="set_credential_provider_service_title">Sett forvalgt autofyll-tjeneste</string>
<string name="autofill_explanation_summary">Skru på tjenesten for å fylle ut skjema fra andre programmer</string>
<string name="password_size_title">Passordsstørrelse</string>
<string name="password_size_summary">Sett forvalgt størrelse for generert passord</string>

View File

@@ -187,7 +187,7 @@
<string name="autofill">Automatisch aanvullen</string>
<string name="autofill_service_name">KeePassDX dienst automatisch aanvullen</string>
<string name="autofill_sign_in_prompt">Inloggen met KeePassDX</string>
<string name="set_autofill_service_title">Dienst automatisch aanvullen</string>
<string name="set_credential_provider_service_title">Dienst automatisch aanvullen</string>
<string name="autofill_explanation_summary">Schakel de dienst in om formulieren in andere apps in te vullen</string>
<string name="password_size_title">Gegenereerde wachtwoordlengte</string>
<string name="password_size_summary">Stel de standaardlengte van gegenereerde wachtwoorden in</string>

View File

@@ -266,7 +266,7 @@
<string name="lock_database_back_root_title">ਲਾਕ ਕਰਨ ਲਈ \'ਪਿੱਛੇ\' ਨੂੰ ਦਬਾਓ</string>
<string name="lock_database_screen_off_summary">ਜਦੋਂ ਸਕਰੀਨ ਬੰਦ ਹੋ ਜਾਵੇ ਤਾਂ ਡਾਟਾਬੇਸ ਨੂੰ ਲਾਕ ਕਰੋ</string>
<string name="clipboard_notifications_title">ਕਲਿੱਪਬੋਰਡ ਨੋਟੀਫਿਕੇਸ਼ਨ</string>
<string name="set_autofill_service_title">ਮੂਲ ਆਪੇ-ਭਰਨ ਸੇਵਾ ਵਜੋਂ ਸੈੱਟ ਕਰੋ</string>
<string name="set_credential_provider_service_title">ਮੂਲ ਆਪੇ-ਭਰਨ ਸੇਵਾ ਵਜੋਂ ਸੈੱਟ ਕਰੋ</string>
<string name="configure_biometric">ਕੋਈ ਬਾਇਓਮੈਟਰਿਕ ਜਾਂ ਡਿਵਾਈਸ ਸਨਦ ਦਾਖਲ ਨਹੀਂ ਕੀਤੀ ਹੈ।</string>
<string name="warning_sure_remove_data">ਇਹ ਡਾਟਾ ਕਿਵੇਂ ਵੀ ਹਟਾਉਣਾ ਹੈ\?</string>
<string name="warning_sure_add_file">ਕਿਵੇਂ ਵੀ ਫ਼ਾਇਲ ਜੋੜਨੀ ਹੈ\?</string>

View File

@@ -182,7 +182,7 @@
<string name="autofill">Wypełnij automatycznie</string>
<string name="autofill_service_name">Autouzupełnianie formularzy KeePassDX</string>
<string name="autofill_sign_in_prompt">Zaloguj się za pomocą KeePassDX</string>
<string name="set_autofill_service_title">Ustaw domyślną usługę autouzupełniania</string>
<string name="set_credential_provider_service_title">Ustaw domyślną usługę autouzupełniania</string>
<string name="autofill_explanation_summary">Włącz autouzupełnianie, aby móc szybko wypełniać formularze w innych aplikacjach</string>
<string name="password_size_title">Wygenerowany rozmiar hasła</string>
<string name="password_size_summary">Ustawia domyślny rozmiar wygenerowanych haseł</string>

View File

@@ -180,7 +180,7 @@
<string name="autofill">Preenchimento automático</string>
<string name="autofill_service_name">Preenchimento automático do KeePassDX</string>
<string name="autofill_sign_in_prompt">Entre com o KeePassDX</string>
<string name="set_autofill_service_title">Definir serviço padrão de preenchimento automático</string>
<string name="set_credential_provider_service_title">Definir serviço padrão de preenchimento automático</string>
<string name="autofill_explanation_summary">Habilite o serviço para rapidamente preencher formulários em outros aplicativos</string>
<string name="password_size_title">Comprimento da senha gerada</string>
<string name="password_size_summary">Define o tamanho padrão para senhas geradas</string>

View File

@@ -179,7 +179,7 @@
<string name="autofill">Preenchimento automático</string>
<string name="autofill_service_name">Serviço de preenchimento automático do KeePassDX</string>
<string name="autofill_sign_in_prompt">Iniciar sessão com KeePassDX</string>
<string name="set_autofill_service_title">Definir como serviço de preenchimento automático predefinido</string>
<string name="set_credential_provider_service_title">Definir como serviço de preenchimento automático predefinido</string>
<string name="autofill_explanation_summary">Ative o serviço de preencher automático para preencher formulários noutras aplicações</string>
<string name="password_size_title">Tamanho da palavra-passe gerada</string>
<string name="edit_entry">Editar entrada</string>

View File

@@ -91,7 +91,7 @@
<string name="list_password_generator_options_title">Caracteres das palavras-passe</string>
<string name="password_size_summary">Define o tamanho predefinido para as palavras-passe geradas</string>
<string name="password_size_title">Tamanho da palavra-passe gerada</string>
<string name="set_autofill_service_title">Definir como serviço de preenchimento automático predefinido</string>
<string name="set_credential_provider_service_title">Definir como serviço de preenchimento automático predefinido</string>
<string name="autofill_sign_in_prompt">Iniciar sessão com KeePassDX</string>
<string name="autofill_service_name">Serviço de preenchimento automático do KeePassDX</string>
<string name="autofill">Preenchimento automático</string>

View File

@@ -240,7 +240,7 @@
<string name="autofill_service_name">Completarea automată cu KeePassDX</string>
<string name="autofill_sign_in_prompt">Conectați-vă cu KeePassDX</string>
<string name="autofill_explanation_summary">Activați completarea automată pentru a completa rapid formulare în alte aplicații</string>
<string name="set_autofill_service_title">Setați serviciul implicit de autocompletare</string>
<string name="set_credential_provider_service_title">Setați serviciul implicit de autocompletare</string>
<string name="password_size_title">Dimensiunea parolei generate</string>
<string name="password_size_summary">Setează dimensiunea implicită a parolelor generate</string>
<string name="list_password_generator_options_title">Caractere parolă</string>

View File

@@ -184,7 +184,7 @@
<string name="autofill_service_name">Служба автозаполнения KeePassDX</string>
<string name="autofill_sign_in_prompt">Войти с помощью KeePassDX</string>
<string name="autofill_explanation_summary">Включите службу для быстрого заполнения форм в других приложениях</string>
<string name="set_autofill_service_title">Использовать службу автозаполнения</string>
<string name="set_credential_provider_service_title">Использовать службу автозаполнения</string>
<string name="password_size_title">Длина создаваемого пароля</string>
<string name="password_size_summary">Настройка длины создаваемых паролей по умолчанию</string>
<string name="list_password_generator_options_title">Символы пароля</string>

View File

@@ -595,7 +595,7 @@
<string name="properties">Vlastnosti</string>
<string name="menu_appearance_settings">Vzhľad</string>
<string name="autofill_explanation_summary">Povoľte automatické dopĺňanie na rýchle vyplnenie formulárov v iných aplikáciách</string>
<string name="set_autofill_service_title">Nastavte predvolenú službu automatického dopĺňania</string>
<string name="set_credential_provider_service_title">Nastavte predvolenú službu automatického dopĺňania</string>
<string name="list_password_generator_options_summary">Nastavte povolené znaky generátora hesiel</string>
<string name="biometric_unlock_enable_summary">Umožňuje vám skenovať biometrické údaje a otvoriť databázu</string>
<string name="max_history_items_title">Maximálny počet</string>

View File

@@ -570,7 +570,7 @@
<string name="style_brightness_summary">Përzgjidhni tema të çelëta ose të errëta</string>
<string name="icon_pack_choose_summary">Paketë ikonash të përdorura te aplikacioni</string>
<string name="hide_expired_entries_summary">Zërat e skaduar nuk shfaqen</string>
<string name="set_autofill_service_title">Caktoni shërbim parazgjedhje vetëplotësimesh</string>
<string name="set_credential_provider_service_title">Caktoni shërbim parazgjedhje vetëplotësimesh</string>
<string name="autofill_explanation_summary">Aktivizoni vetëplotësimet, për të plotësuar shpejt formularë në aplikacione të tjerë</string>
<string name="autofill_preference_title">Rregullime vetëplotësimi</string>
<string name="password_size_summary">Cakton madhësinë parazgjedhje për fjalëkalimet e prodhuar</string>

View File

@@ -189,7 +189,7 @@
<string name="autofill">Autofyll</string>
<string name="autofill_service_name">KeePassDX autofyll formulär</string>
<string name="autofill_sign_in_prompt">Logga in med KeePassDX</string>
<string name="set_autofill_service_title">Välj standardtjänst för autofyll</string>
<string name="set_credential_provider_service_title">Välj standardtjänst för autofyll</string>
<string name="password_size_title">Längd på genererat lösenord</string>
<string name="password_size_summary">Anger standardlängden för de genererade lösenorden</string>
<string name="list_password_generator_options_title">Lösenordstecken</string>

View File

@@ -73,7 +73,7 @@
<string name="biometric_security_update_required">பயோமெட்ரிக் பாதுகாப்பு புதுப்பிப்பு தேவை.</string>
<string name="keystore_not_accessible">கீச்டோர் சரியாக துவக்கப்படவில்லை.</string>
<string name="menu_appearance_settings">தோற்றம்</string>
<string name="set_autofill_service_title">இயல்புநிலை ஆட்டோஃபில் சேவையை அமைக்கவும்</string>
<string name="set_credential_provider_service_title">இயல்புநிலை ஆட்டோஃபில் சேவையை அமைக்கவும்</string>
<string name="autofill_preference_title">ஆட்டோஃபில் அமைப்புகள்</string>
<string name="lock_database_screen_off_title">திரை பூட்டு</string>
<string name="content">உள்ளடக்கம்</string>

View File

@@ -529,7 +529,7 @@
<string name="database_history">ประวัติ</string>
<string name="import_app_properties_summary">เลือกไฟล์ที่จะนําเข้าการตั้งค่าของแอป</string>
<string name="success_import_app_properties">นำเข้าการตั้งค่าแอปแล้ว</string>
<string name="set_autofill_service_title">ตั่งค่าเป็นบริการกรอกข้อมูลอัตโนมัติเรื่มต้น</string>
<string name="set_credential_provider_service_title">ตั่งค่าเป็นบริการกรอกข้อมูลอัตโนมัติเรื่มต้น</string>
<string name="error_export_app_properties">เกิดข้อผิดพลาดระหว่างการส่งออกการตั้งค่าของแอป</string>
<string name="menu_appearance_settings">ลักษณะ</string>
<string name="biometric">ไบโอเมตริก</string>

View File

@@ -176,7 +176,7 @@
<string name="autofill">Otomatik Doldurma</string>
<string name="autofill_service_name">KeePassDX formu otomatik doldurma</string>
<string name="autofill_sign_in_prompt">KeePassDX ile giriş yap</string>
<string name="set_autofill_service_title">Öntanımlı otomatik doldurma hizmetini ayarla</string>
<string name="set_credential_provider_service_title">Öntanımlı otomatik doldurma hizmetini ayarla</string>
<string name="autofill_explanation_summary">Diğer uygulamalardaki formları hızlı doldurmak için otomatik doldurmayı etkinleştirin</string>
<string name="password_size_title">Oluşturulan parola boyutu</string>
<string name="password_size_summary">Oluşturulan parolaların öntanımlı boyutunu ayarlar</string>

View File

@@ -394,7 +394,7 @@
<string name="password_size_summary">Встановити типову довжину створюваних паролів</string>
<string name="password_size_title">Довжина створюваного пароля</string>
<string name="autofill_preference_title">Налаштування автозаповнення</string>
<string name="set_autofill_service_title">Встановити типовою службою автозаповнення</string>
<string name="set_credential_provider_service_title">Встановити типовою службою автозаповнення</string>
<string name="autofill_explanation_summary">Увімкнути автозаповнення для швидкого заповнення форм в інших застосунках</string>
<string name="autofill_sign_in_prompt">Увійти за допомогою KeePassDX</string>
<string name="autofill_service_name">Автозаповнення форм KeePassDX</string>

View File

@@ -415,7 +415,7 @@
<string name="autofill_sign_in_prompt">Đăng nhập bằng KeePassDX</string>
<string name="autofill_explanation_summary">Bật tính năng tự động điền để nhanh chóng điền vào biểu mẫu trong các ứng dụng khác</string>
<string name="autofill_select_entry">Chọn mục…</string>
<string name="set_autofill_service_title">Đặt dịch vụ tự động điền mặc định</string>
<string name="set_credential_provider_service_title">Đặt dịch vụ tự động điền mặc định</string>
<string name="autofill_preference_title">Thiết đặt tự động điền</string>
<string name="password_size_title">Kích thước mật khẩu đã tạo</string>
<string name="password_size_summary">Đặt kích thước mặc định của mật khẩu được tạo</string>

View File

@@ -206,7 +206,7 @@
<string name="build_label">构建 %1$s</string>
<string name="encrypted_value_stored">加密密码已保存</string>
<string name="unavailable">不可用</string>
<string name="set_autofill_service_title">设为默认自动填充服务</string>
<string name="set_credential_provider_service_title">设为默认自动填充服务</string>
<string name="autofill_explanation_summary">启用自动填充功能,以快速填写其他应用中的表单</string>
<string name="password_size_title">密码生成长度</string>
<string name="password_size_summary">设置生成密码的默认长度</string>

View File

@@ -501,7 +501,7 @@
<string name="select_entry">選擇條目</string>
<string name="select_to_copy">複製%1$s到剪貼簿</string>
<string name="selection_mode">選擇模式</string>
<string name="set_autofill_service_title">設置為預設的填充服務</string>
<string name="set_credential_provider_service_title">設置為預設的填充服務</string>
<string name="settings">設定</string>
<string name="settings_database_force_changing_master_key_next_time_summary">下次強制更改主密鑰(一次)</string>
<string name="settings_database_force_changing_master_key_next_time_title">下次強制更換</string>

View File

@@ -126,11 +126,14 @@
<bool name="clear_clipboard_notification_default" translatable="false">false</bool>
<string name="clipboard_timeout_key" translatable="false">clip_timeout_key</string>
<string name="clipboard_timeout_default" translatable="false">20000</string>
<string name="autofill_key" translatable="false">autofill_key</string>
<string name="credential_provider_key" translatable="false">credential_provider_key</string>
<string name="settings_credential_provider_enable_key" translatable="false">settings_credential_provider_enable_key</string>
<bool name="settings_credential_provider_enable_default" translatable="false">false</bool>
<string name="autofill_explanation_key" translatable="false">autofill_explanation_key</string>
<string name="settings_autofill_enable_key" translatable="false">settings_autofill_enable_key</string>
<bool name="settings_autofill_enable_default" translatable="false">false</bool>
<string name="settings_autofill_key" translatable="false">settings_autofill_key</string>
<string name="passkeys_explanation_key" translatable="false">passkeys_explanation_key</string>
<string name="settings_passkeys_key" translatable="false">settings_passkeys_key</string>
<string name="passkeys_privileged_apps_key" translatable="false">passkeys_privileged_apps_key</string>
<string name="keyboard_notification_entry_key" translatable="false">keyboard_notification_entry_key</string>
<bool name="keyboard_notification_entry_default" translatable="false">true</bool>
<string name="keyboard_notification_entry_clear_close_key" translatable="false">keyboard_notification_entry_clear_close_key</string>

View File

@@ -417,12 +417,19 @@
<string name="biometric">Biometric</string>
<string name="device_credential">Device credential</string>
<string name="general">General</string>
<string name="credential_provider">Credential provider</string>
<string name="set_credential_provider_service_title">Credential provider service</string>
<string name="passkeys">Passkeys</string>
<string name="passkeys_explanation_summary">Configure Passkeys for fast and secure passwordless login</string>
<string name="passkeys_preference_title">Passkeys settings</string>
<string name="passkeys_privileged_apps_title">Privileged apps</string>
<string name="passkeys_privileged_apps_summary">Add a browser to the list of privileged apps</string>
<string name="passkeys_privileged_apps_explanation">Select an app to add to the list of privileged apps</string>
<string name="autofill">Autofill</string>
<string name="autofill_service_name">KeePassDX form autofilling</string>
<string name="autofill_sign_in_prompt">Sign in with KeePassDX</string>
<string name="autofill_explanation_summary">Enable autofilling to quickly fill out forms in other apps</string>
<string name="autofill_explanation_summary">Configure autofilling to quickly fill out forms in other apps</string>
<string name="autofill_select_entry">Select entry…</string>
<string name="set_autofill_service_title">Set default autofill service</string>
<string name="autofill_preference_title">Autofill settings</string>
<string name="password_size_title">Generated password size</string>
<string name="password_size_summary">Sets default size of the generated passwords</string>

View File

@@ -34,16 +34,23 @@
</PreferenceCategory>
<PreferenceCategory
android:key="@string/autofill_key"
android:title="@string/autofill">
android:key="@string/credential_provider_key"
android:title="@string/credential_provider">
<SwitchPreferenceCompat
android:key="@string/settings_credential_provider_enable_key"
android:title="@string/set_credential_provider_service_title"
android:defaultValue="@bool/settings_credential_provider_enable_default"/>
<Preference
android:key="@string/passkeys_explanation_key"
android:icon="@drawable/prefs_info_24dp"
android:summary="@string/passkeys_explanation_summary"/>
<Preference
android:key="@string/settings_passkeys_key"
android:title="@string/passkeys_preference_title" />
<Preference
android:key="@string/autofill_explanation_key"
android:icon="@drawable/prefs_info_24dp"
android:summary="@string/autofill_explanation_summary"/>
<SwitchPreferenceCompat
android:key="@string/settings_autofill_enable_key"
android:title="@string/set_autofill_service_title"
android:defaultValue="@bool/settings_autofill_enable_default"/>
<Preference
android:key="@string/settings_autofill_key"
android:title="@string/autofill_preference_title" />

View File

@@ -0,0 +1,53 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2020 Jeremy Jamet / Kunzisoft.
This file is part of KeePassDX.
KeePassDX is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
KeePassDX is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with KeePassDX. If not, see <http://www.gnu.org/licenses/>.
-->
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<PreferenceCategory
android:title="@string/general">
<com.kunzisoft.keepass.settings.preference.DialogListExplanationPreference
android:key="@string/passkeys_privileged_apps_key"
android:title="@string/passkeys_privileged_apps_title"
android:summary="@string/passkeys_privileged_apps_summary"/>
<!--
// TODO Backup state #2135
<SwitchPreferenceCompat
android:key="@string/passkeys_backup_state_key"
android:title="@string/passkeys_backup_state_title"
android:summary="@string/passkeys_backup_state_summary"
android:defaultValue="@bool/passkeys_backup_state_default"/>
-->
</PreferenceCategory>
<!--
// TODO Passkeys default group #2123
<PreferenceCategory
android:title="@string/save">
<SwitchPreferenceCompat
android:key="@string/passkeys_default_group_creation_key"
android:persistent="false"
android:title="@string/passkeys_default_group_creation_title"
android:summary="@string/passkeys_default_group_creation_summary"
android:enabled="false"/>
<com.kunzisoft.keepass.settings.preference.DialogListExplanationPreference
android:key="@string/passkeys_group_creation_key"
android:persistent="false"
android:title="@string/passkeys_default_group_creation_title"
android:enabled="false"/>
</PreferenceCategory>
-->
</PreferenceScreen>

View File

@@ -119,6 +119,10 @@ data class AndroidOrigin(
}
return "android:apk-key-hash:${fingerprintToUrlSafeBase64(fingerprint)}"
}
override fun toString(): String {
return "$packageName (${fingerprint})"
}
}
@Parcelize
@@ -134,6 +138,10 @@ data class WebOrigin(
return "${origin}/.well-known/assetlinks.json"
}
override fun toString(): String {
return origin
}
companion object {
const val RELYING_PARTY_DEFAULT_PROTOCOL = "https"
fun fromRelyingParty(relyingParty: String): WebOrigin = WebOrigin(