package com.peachpasswords.autofill import android.content.Context import android.content.pm.verify.domain.DomainVerificationManager import android.content.pm.verify.domain.DomainVerificationUserState import android.os.Build import com.peachpasswords.shared.extractDomain /** * Origin resolution for autofill matching. * * Origin *verification* (browser certificate pinning + caller-trust gating) was * removed (queue #3, June 2026-08-02) — it flagged nearly every request as * "unverified" and withheld matches, adding friction without value. Matches are * now ranked purely by content: the page domain for web origins, and a native * app's app-link domains + display label for app origins. The caller package is * still the framework-authenticated identity (never a caller-supplied extra). */ /** * Populate [ParsedStructure.originDomains] and [ParsedStructure.appTitle] from * the authenticated origin. Web origins match on the page domain; native apps * match on their app-link domains and their display label. No trust * classification — every origin is eligible to see its matching entries. */ internal fun resolveAutofillOrigin(context: Context, parsed: ParsedStructure): ParsedStructure { val webDomain = parsed.webDomain if (webDomain != null) { return parsed.copy(originDomains = listOfNotNull(extractDomain(webDomain)), appTitle = null) } return parsed.copy( originDomains = appLinkDomains(context, parsed.packageName), appTitle = appLabel(context, parsed.packageName), ) } /** The display label of the calling app, for matching entries by app title. */ internal fun appLabel(context: Context, packageName: String?): String? { if (packageName.isNullOrBlank()) return null return runCatching { context.packageManager.getApplicationLabel( context.packageManager.getApplicationInfo(packageName, 0), ).toString().takeIf { it.isNotBlank() } }.getOrNull() } /** A native app's verified app-link domains (Android's cached Digital Asset Links verdict). */ internal fun appLinkDomains(context: Context, packageName: String?): List { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S || packageName.isNullOrBlank()) { return emptyList() } return runCatching { val state = context.getSystemService(DomainVerificationManager::class.java) ?.getDomainVerificationUserState(packageName) state?.hostToStateMap.orEmpty() .filterValues { it == DomainVerificationUserState.DOMAIN_STATE_VERIFIED } .keys .mapNotNull { extractDomain(it.removePrefix("*.")) } .distinct() .sorted() }.getOrDefault(emptyList()) }