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.VaultEntry101112131415161718192021222324252627282930internal fun resolveAutofillOrigin(context: Context, parsed: ParsedStructure): ParsedStructure {31 if (parsed.webDomain != null) {32 return applyWebOriginVerification(33 parsed,34 PasskeyCallerOrigin.isVerifiedBrowser(context, parsed.packageName),35 )36 }37 return parsed.copy(originDomains = appLinkDomains(context, parsed.packageName))38}394041internal fun applyWebOriginVerification(42 parsed: ParsedStructure,43 verifiedBrowser: Boolean,44): ParsedStructure {45 val webDomain = parsed.webDomain ?: return parsed46 return if (verifiedBrowser) {47 parsed.copy(48 originDomains = listOfNotNull(extractDomain(webDomain)),49 credentialReleaseAllowed = true,50 )51 } else {52 parsed.copy(53 webDomain = null,54 originDomains = emptyList(),55 credentialReleaseAllowed = false,56 )57 }58}596061internal fun appLinkDomains(context: Context, packageName: String?): List<String> {62 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S || packageName.isNullOrBlank()) {63 return emptyList()64 }65 return runCatching {66 val state = context.getSystemService(DomainVerificationManager::class.java)67 ?.getDomainVerificationUserState(packageName)68 state?.hostToStateMap.orEmpty()69 .filterValues { it == DomainVerificationUserState.DOMAIN_STATE_VERIFIED }70 .keys71 .mapNotNull { extractDomain(it.removePrefix("*.")) }72 .distinct()73 .sorted()74 }.getOrDefault(emptyList())75}7677787980818283internal fun rememberOfferDomains(entry: VaultEntry, parsed: ParsedStructure): List<String> {84 val existing = sequenceOf(entry.url)85 .plus(entry.additionalUrls.orEmpty().asSequence())86 .filterNotNull()87 .mapNotNull(::extractDomain)88 .toSet()89 if (existing.isEmpty() || parsed.originDomains.isEmpty()) return emptyList()90 return parsed.originDomains.filter { it !in existing }91}