ad458e292ac6

fix: Preserve Autofill picker origin type (v2.3.40)

- Carry web-vs-native origin type into the Autofill picker intent - Match web origins by registrable domain and native app origins by exact package - Add picker matching tests for web, native, and package lookalike cases - Verified with focused AutofillMatchTest and full testDebugUnitTest/assembleDebug/lintDebug gate

time
2026-06-26 13:29 UTC · 4 months ago
machine
koh2
parent
d651e3c935cd
4 files app/build.gradle+2 −2app/src/main/java/com/peachpasswords/autofill/AutofillEntryPickerActivity.kt+15 −2app/src/main/java/com/peachpasswords/autofill/AutofillIntents.kt+2 −0app/src/test/java/com/peachpasswords/autofill/AutofillMatchTest.kt+19 −0
app/build.gradle+2 −2
@@ -16,8 +16,8 @@1616         applicationId "com.peachpasswords"1717         minSdk 261818         targetSdk 3519-        versionCode 23390020-        versionName "2.3.39"19+        versionCode 23400020+        versionName "2.3.40"2121 2222         testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"2323         vectorDrawables {

view file

app/src/main/java/com/peachpasswords/autofill/AutofillEntryPickerActivity.kt+15 −2
@@ -61,15 +61,18 @@6161     override fun onCreate(savedInstanceState: Bundle?) {6262         super.onCreate(savedInstanceState)6363 64+        val origin = intent.getStringExtra(AutofillIntents.EXTRA_ORIGIN)65+        val isWebOrigin = intent.getBooleanExtra(AutofillIntents.EXTRA_IS_WEB_ORIGIN, false)6466         val parsed = ParsedStructure(6567             usernameId = intentAutofillId(AutofillIntents.EXTRA_IDENTITY_ID),6668             passwordId = intentAutofillId(AutofillIntents.EXTRA_PASSWORD_ID),6769             otpId = intentAutofillId(AutofillIntents.EXTRA_OTP_ID),68-            webDomain = intent.getStringExtra(AutofillIntents.EXTRA_ORIGIN),70+            webDomain = origin.takeIf { isWebOrigin },71+            packageName = origin.takeUnless { isWebOrigin },6972         )7073         val unlocked = vault.isUnlocked.value7174         val entries = if (unlocked) {72-            AutofillResponseBuilder.matchEntries(vault.getEntries(), parsed.origin).all.take(MAX_ROWS)75+            autofillPickerEntries(vault.getEntries(), parsed, MAX_ROWS)7376         } else {7477             emptyList()7578         }@@ -125,6 +128,16 @@125128     private companion object {126129         const val MAX_ROWS = 12127130     }131+}132+133+internal fun autofillPickerEntries(134+    entries: List<VaultEntry>,135+    parsed: ParsedStructure,136+    limit: Int,137+): List<VaultEntry> = when {138+    parsed.webDomain != null -> AutofillResponseBuilder.matchEntries(entries, parsed.webDomain).all.take(limit)139+    parsed.packageName != null -> entries.filter { it.url == parsed.packageName }.take(limit)140+    else -> AutofillResponseBuilder.matchEntries(entries, null).all.take(limit)128141 }129142 130143 @Composable

view file

app/src/main/java/com/peachpasswords/autofill/AutofillIntents.kt+2 −0
@@ -16,6 +16,7 @@1616     const val EXTRA_PASSWORD_ID = "peach.autofill.passwordId"1717     const val EXTRA_OTP_ID = "peach.autofill.otpId"1818     const val EXTRA_ORIGIN = "peach.autofill.origin"19+    const val EXTRA_IS_WEB_ORIGIN = "peach.autofill.isWebOrigin"1920 2021     private const val REQ_CHIP = 0xC0DE2122     private const val REQ_PICKER = 0xBEEF@@ -33,6 +34,7 @@3334             putExtra(EXTRA_PASSWORD_ID, parsed.passwordId)3435             putExtra(EXTRA_OTP_ID, parsed.otpId)3536             putExtra(EXTRA_ORIGIN, parsed.origin)37+            putExtra(EXTRA_IS_WEB_ORIGIN, parsed.webDomain != null)3638         }3739         return PendingIntent.getActivity(context, REQ_PICKER, intent, mutableFlags()).intentSender3840     }

view file

app/src/test/java/com/peachpasswords/autofill/AutofillMatchTest.kt+19 −0
@@ -46,6 +46,25 @@4646         assertTrue(result.rest.isEmpty())4747     }4848 49+    @Test fun picker_web_origin_uses_domain_matching() {50+        val peach = entry("Peach", "https://peachpasswords.com")51+        val parsed = ParsedStructure(webDomain = "app.peachpasswords.com")52+        assertEquals(listOf(peach), autofillPickerEntries(listOf(peach), parsed, limit = 12))53+    }54+55+    @Test fun picker_native_origin_requires_exact_package_match() {56+        val app = entry("Native", "com.example.app")57+        val other = entry("Other", "com.example.other")58+        val parsed = ParsedStructure(packageName = "com.example.app")59+        assertEquals(listOf(app), autofillPickerEntries(listOf(app, other), parsed, limit = 12))60+    }61+62+    @Test fun picker_native_origin_rejects_package_substrings() {63+        val app = entry("Native", "com.example.app")64+        val parsed = ParsedStructure(packageName = "evil.com.example.app")65+        assertTrue(autofillPickerEntries(listOf(app), parsed, limit = 12).isEmpty())66+    }67+4968     @Test fun null_origin_yields_no_hits_only_fallback() {5069         val a = entry("A", "https://a.com")5170         val b = entry("B", "https://b.com")

view file