fix: Autofill pending intent bypass #2238

This commit is contained in:
J-Jamet
2025-10-24 14:43:42 +02:00
parent d6dc75961b
commit d2549d61d6
4 changed files with 115 additions and 17 deletions

View File

@@ -39,9 +39,12 @@ import com.kunzisoft.keepass.model.EntryInfo
import com.kunzisoft.keepass.model.RegisterInfo
import com.kunzisoft.keepass.model.SearchInfo
import com.kunzisoft.keepass.utils.LOCK_ACTION
import com.kunzisoft.keepass.utils.getEnum
import com.kunzisoft.keepass.utils.getEnumExtra
import com.kunzisoft.keepass.utils.getParcelableCompat
import com.kunzisoft.keepass.utils.getParcelableExtraCompat
import com.kunzisoft.keepass.utils.getParcelableList
import com.kunzisoft.keepass.utils.putEnum
import com.kunzisoft.keepass.utils.putEnumExtra
import com.kunzisoft.keepass.utils.putParcelableList
import java.io.IOException
@@ -159,10 +162,21 @@ object EntrySelectionHelper {
return this
}
fun Bundle.addSearchInfo(searchInfo: SearchInfo?): Bundle {
searchInfo?.let {
putParcelable(KEY_SEARCH_INFO, it)
}
return this
}
fun Intent.retrieveSearchInfo(): SearchInfo? {
return getParcelableExtraCompat(KEY_SEARCH_INFO)
}
fun Bundle.getSearchInfo(): SearchInfo? {
return getParcelableCompat(KEY_SEARCH_INFO)
}
fun Intent.addRegisterInfo(registerInfo: RegisterInfo?): Intent {
registerInfo?.let {
putExtra(KEY_REGISTER_INFO, it)
@@ -170,10 +184,21 @@ object EntrySelectionHelper {
return this
}
fun Bundle.addRegisterInfo(registerInfo: RegisterInfo?): Bundle {
registerInfo?.let {
putParcelable(KEY_REGISTER_INFO, it)
}
return this
}
fun Intent.retrieveRegisterInfo(): RegisterInfo? {
return getParcelableExtraCompat(KEY_REGISTER_INFO)
}
fun Bundle.getRegisterInfo(): RegisterInfo? {
return getParcelableCompat(KEY_REGISTER_INFO)
}
fun Intent.removeInfo() {
removeExtra(KEY_SEARCH_INFO)
removeExtra(KEY_REGISTER_INFO)
@@ -184,8 +209,17 @@ object EntrySelectionHelper {
return this
}
fun Bundle.addSpecialMode(specialMode: SpecialMode): Bundle {
this.putEnum(KEY_SPECIAL_MODE, specialMode)
return this
}
fun Intent.retrieveSpecialMode(): SpecialMode {
return getEnumExtra<SpecialMode>(KEY_SPECIAL_MODE) ?: SpecialMode.DEFAULT
return this.getEnumExtra<SpecialMode>(KEY_SPECIAL_MODE) ?: SpecialMode.DEFAULT
}
fun Bundle.getSpecialMode(): SpecialMode {
return this.getEnum<SpecialMode>(KEY_SPECIAL_MODE) ?: SpecialMode.DEFAULT
}
fun Intent.addTypeMode(typeMode: TypeMode): Intent {
@@ -236,7 +270,7 @@ object EntrySelectionHelper {
}
/**
* Retrieve nodes ids from [intent] and get the corresponding entry info list in [database]
* Retrieve nodes ids from intent and get the corresponding entry info list in [database]
*/
fun Intent.retrieveAndRemoveEntries(database: ContextualDatabase): List<EntryInfo> {
val nodesIds = retrieveNodesIds()

View File

@@ -38,10 +38,14 @@ import com.kunzisoft.keepass.activities.legacy.DatabaseModeActivity
import com.kunzisoft.keepass.credentialprovider.EntrySelectionHelper.addRegisterInfo
import com.kunzisoft.keepass.credentialprovider.EntrySelectionHelper.addSearchInfo
import com.kunzisoft.keepass.credentialprovider.EntrySelectionHelper.addSpecialMode
import com.kunzisoft.keepass.credentialprovider.EntrySelectionHelper.getRegisterInfo
import com.kunzisoft.keepass.credentialprovider.EntrySelectionHelper.getSearchInfo
import com.kunzisoft.keepass.credentialprovider.EntrySelectionHelper.getSpecialMode
import com.kunzisoft.keepass.credentialprovider.EntrySelectionHelper.setActivityResult
import com.kunzisoft.keepass.credentialprovider.SpecialMode
import com.kunzisoft.keepass.credentialprovider.autofill.AutofillComponent
import com.kunzisoft.keepass.credentialprovider.autofill.AutofillHelper.addAutofillComponent
import com.kunzisoft.keepass.credentialprovider.autofill.AutofillHelper.retrieveAutofillComponent
import com.kunzisoft.keepass.credentialprovider.viewmodel.AutofillLauncherViewModel
import com.kunzisoft.keepass.credentialprovider.viewmodel.CredentialLauncherViewModel
import com.kunzisoft.keepass.database.ContextualDatabase
@@ -75,6 +79,14 @@ class AutofillLauncherActivity : DatabaseModeActivity() {
}
override fun onCreate(savedInstanceState: Bundle?) {
// To apply the bypass https://github.com/Kunzisoft/KeePassDX/issues/2238
// before managing intent in super class
intent.retrieveSelectionBundle()?.apply {
intent.addSpecialMode(getSpecialMode())
intent.addSearchInfo(getSearchInfo())
intent.addRegisterInfo(getRegisterInfo())
intent.addAutofillComponent(retrieveAutofillComponent())
}
super.onCreate(savedInstanceState)
autofillLauncherViewModel.initialize()
lifecycleScope.launch {
@@ -171,23 +183,32 @@ class AutofillLauncherActivity : DatabaseModeActivity() {
companion object {
private const val KEY_PENDING_INTENT_BUNDLE = "com.kunzisoft.keepass.extra.BUNDLE"
private val TAG = AutofillLauncherActivity::class.java.name
fun Intent.retrieveSelectionBundle(): Bundle? {
return this.getBundleExtra(KEY_PENDING_INTENT_BUNDLE)
}
fun getPendingIntentForSelection(
context: Context,
searchInfo: SearchInfo? = null,
autofillComponent: AutofillComponent
): PendingIntent? {
try {
// Doesn't work with direct extra Parcelable in Android 11 (don't know why?)
// https://github.com/Kunzisoft/KeePassDX/issues/2238
// Wrap into a bundle to bypass the problem
val tempBundle = Bundle().apply {
addSpecialMode(SpecialMode.SELECTION)
addSearchInfo(searchInfo)
addAutofillComponent(autofillComponent)
}
return PendingIntent.getActivity(
context,
randomRequestCode(),
// Doesn't work with direct extra Parcelable (don't know why?)
// Wrap into a bundle to bypass the problem
Intent(context, AutofillLauncherActivity::class.java).apply {
addSpecialMode(SpecialMode.SELECTION)
addSearchInfo(searchInfo)
addAutofillComponent(autofillComponent)
putExtra(KEY_PENDING_INTENT_BUNDLE, tempBundle)
},
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
PendingIntent.FLAG_MUTABLE or PendingIntent.FLAG_CANCEL_CURRENT
@@ -206,12 +227,16 @@ class AutofillLauncherActivity : DatabaseModeActivity() {
registerInfo: RegisterInfo
): PendingIntent? {
try {
// Bypass intent issue
val tempBundle = Bundle().apply {
addSpecialMode(SpecialMode.REGISTRATION)
addRegisterInfo(registerInfo)
}
return PendingIntent.getActivity(
context,
randomRequestCode(),
Intent(context, AutofillLauncherActivity::class.java).apply {
addSpecialMode(SpecialMode.REGISTRATION)
addRegisterInfo(registerInfo)
putExtra(KEY_PENDING_INTENT_BUNDLE, tempBundle)
},
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
PendingIntent.FLAG_MUTABLE or PendingIntent.FLAG_CANCEL_CURRENT

View File

@@ -27,6 +27,7 @@ import android.content.Intent
import android.graphics.BlendMode
import android.graphics.drawable.Icon
import android.os.Build
import android.os.Bundle
import android.service.autofill.Dataset
import android.service.autofill.Field
import android.service.autofill.FillResponse
@@ -53,6 +54,7 @@ import com.kunzisoft.keepass.model.SearchInfo
import com.kunzisoft.keepass.settings.AutofillSettingsActivity
import com.kunzisoft.keepass.settings.PreferencesUtil
import com.kunzisoft.keepass.utils.AppUtil.randomRequestCode
import com.kunzisoft.keepass.utils.getParcelableCompat
import com.kunzisoft.keepass.utils.getParcelableExtraCompat
import java.io.IOException
import kotlin.math.min
@@ -64,20 +66,50 @@ object AutofillHelper {
private const val EXTRA_BASE_STRUCTURE = "com.kunzisoft.keepass.autofill.BASE_STRUCTURE"
private const val EXTRA_INLINE_SUGGESTIONS_REQUEST = "com.kunzisoft.keepass.autofill.INLINE_SUGGESTIONS_REQUEST"
fun Intent.addAutofillComponent(autofillComponent: AutofillComponent) {
this.putExtra(EXTRA_BASE_STRUCTURE, autofillComponent.assistStructure)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
autofillComponent.compatInlineSuggestionsRequest?.let {
this.putExtra(EXTRA_INLINE_SUGGESTIONS_REQUEST, it)
fun Intent.addAutofillComponent(autofillComponent: AutofillComponent?): Intent {
autofillComponent?.let {
this.putExtra(EXTRA_BASE_STRUCTURE, autofillComponent.assistStructure)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
autofillComponent.compatInlineSuggestionsRequest?.let {
this.putExtra(EXTRA_INLINE_SUGGESTIONS_REQUEST, it)
}
}
}
return this
}
fun Intent.retrieveAutofillComponent(): AutofillComponent? {
getParcelableExtraCompat<AssistStructure>(EXTRA_BASE_STRUCTURE)?.let { assistStructure ->
this.getParcelableExtraCompat<AssistStructure>(EXTRA_BASE_STRUCTURE)?.let { assistStructure ->
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
AutofillComponent(assistStructure,
getParcelableExtraCompat(EXTRA_INLINE_SUGGESTIONS_REQUEST))
AutofillComponent(
assistStructure,
this.getParcelableExtraCompat(EXTRA_INLINE_SUGGESTIONS_REQUEST))
} else {
AutofillComponent(assistStructure, null)
}
}
return null
}
fun Bundle.addAutofillComponent(autofillComponent: AutofillComponent?): Bundle {
autofillComponent?.let {
this.putParcelable(EXTRA_BASE_STRUCTURE, autofillComponent.assistStructure)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
autofillComponent.compatInlineSuggestionsRequest?.let {
this.putParcelable(EXTRA_INLINE_SUGGESTIONS_REQUEST, it)
}
}
}
return this
}
fun Bundle.retrieveAutofillComponent(): AutofillComponent? {
this.getParcelableCompat<AssistStructure>(EXTRA_BASE_STRUCTURE)?.let { assistStructure ->
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
AutofillComponent(
assistStructure,
this.getParcelableCompat(EXTRA_INLINE_SUGGESTIONS_REQUEST)
)
} else {
AutofillComponent(assistStructure, null)
}