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 if (parsed.webDomain != null) {27 return applyWebOriginVerification(28 parsed,29 PasskeyCallerOrigin.isVerifiedBrowser(context, parsed.packageName),30 )31 }32 return parsed.copy(33 originDomains = appLinkDomains(context, parsed.packageName),34 appTitle = appLabel(context, parsed.packageName),35 )36}373839internal fun applyWebOriginVerification(40 parsed: ParsedStructure,41 verifiedBrowser: Boolean,42): ParsedStructure {43 val webDomain = parsed.webDomain ?: return parsed44 return if (verifiedBrowser) {45 parsed.copy(46 originDomains = listOfNotNull(extractDomain(webDomain)),47 appTitle = null,48 credentialReleaseAllowed = true,49 )50 } else {51 parsed.copy(52 webDomain = null,53 originDomains = emptyList(),54 appTitle = null,55 credentialReleaseAllowed = false,56 )57 }58}596061internal fun appLabel(context: Context, packageName: String?): String? {62 if (packageName.isNullOrBlank()) return null63 return runCatching {64 context.packageManager.getApplicationLabel(65 context.packageManager.getApplicationInfo(packageName, 0),66 ).toString().takeIf { it.isNotBlank() }67 }.getOrNull()68}697071internal fun appLinkDomains(context: Context, packageName: String?): List<String> {72 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S || packageName.isNullOrBlank()) {73 return emptyList()74 }75 return runCatching {76 val state = context.getSystemService(DomainVerificationManager::class.java)77 ?.getDomainVerificationUserState(packageName)78 state?.hostToStateMap.orEmpty()79 .filterValues { it == DomainVerificationUserState.DOMAIN_STATE_VERIFIED }80 .keys81 .mapNotNull { extractDomain(it.removePrefix("*.")) }82 .distinct()83 .sorted()84 }.getOrDefault(emptyList())85}8687888990919293internal fun rememberOfferDomains(entry: VaultEntry, parsed: ParsedStructure): List<String> {94 val existing = sequenceOf(entry.url)95 .plus(entry.additionalUrls.orEmpty().asSequence())96 .filterNotNull()97 .mapNotNull(::extractDomain)98 .toSet()99 if (existing.isEmpty() || parsed.originDomains.isEmpty()) return emptyList()100 return parsed.originDomains.filter { it !in existing }101}