1package com.peachpasswords.autofill23import android.content.Context4import android.content.pm.verify.domain.DomainVerificationManager5import android.content.pm.verify.domain.DomainVerificationUserState6import android.os.Build7import com.peachpasswords.shared.extractDomain8import com.peachpasswords.passkeys.PasskeyCallerOrigin9import com.peachpasswords.vault.VaultEntry10111213141516171819202122232425internal fun resolveAutofillOrigin(context: Context, parsed: ParsedStructure): ParsedStructure {26 val webDomain = parsed.webDomain27 if (webDomain != null) {28 if (!PasskeyCallerOrigin.isVerifiedBrowser(context, parsed.packageName)) {29 return parsed.copy(webDomain = null, originDomains = emptyList(), appTitle = null)30 }31 return parsed.copy(originDomains = listOfNotNull(extractDomain(webDomain)), appTitle = null)32 }33 return parsed.copy(34 originDomains = appLinkDomains(context, parsed.packageName),35 appTitle = appLabel(context, parsed.packageName),36 )37}383940internal fun appLabel(context: Context, packageName: String?): String? {41 if (packageName.isNullOrBlank()) return null42 return runCatching {43 context.packageManager.getApplicationLabel(44 context.packageManager.getApplicationInfo(packageName, 0),45 ).toString().takeIf { it.isNotBlank() }46 }.getOrNull()47}484950internal fun appLinkDomains(context: Context, packageName: String?): List<String> {51 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S || packageName.isNullOrBlank()) {52 return emptyList()53 }54 return runCatching {55 val state = context.getSystemService(DomainVerificationManager::class.java)56 ?.getDomainVerificationUserState(packageName)57 state?.hostToStateMap.orEmpty()58 .filterValues { it == DomainVerificationUserState.DOMAIN_STATE_VERIFIED }59 .keys60 .mapNotNull { extractDomain(it.removePrefix("*.")) }61 .distinct()62 .sorted()63 }.getOrDefault(emptyList())64}6566676869707172internal fun rememberOfferDomains(entry: VaultEntry, parsed: ParsedStructure): List<String> {73 val existing = sequenceOf(entry.url)74 .plus(entry.additionalUrls.orEmpty().asSequence())75 .filterNotNull()76 .mapNotNull(::extractDomain)77 .toSet()78 if (existing.isEmpty() || parsed.originDomains.isEmpty()) return emptyList()79 return parsed.originDomains.filter { it !in existing }80}