DomainUtils.kt
1package com.peachpasswords.shared23import okhttp3.HttpUrl.Companion.toHttpUrlOrNull45/**6 * eTLD+1 ("bank.co.uk", not "co.uk"), the key everything from autofill matching to7 * vault health compares on.8 *9 * [okhttp3.HttpUrl.topPrivateDomain] is OkHttp's *public* API over the same public10 * suffix list its internal `PublicSuffixDatabase` exposes, so this keeps real PSL11 * accuracy without depending on an `okhttp3.internal` class. Accuracy is not12 * optional here: a "last two labels" heuristic would collapse `evil.co.uk` and13 * `bank.co.uk` to the same key and hand credentials to the wrong site.14 * Returns null for IP literals and bare public suffixes, as before.15 */16fun extractDomain(url: String): String? {17 return try {18 val normalized = if (url.startsWith("http")) url else "https://$url"19 normalized.toHttpUrlOrNull()?.topPrivateDomain()20 } catch (_: Exception) {21 null22 }23}2425fun getDisplayDomain(url: String): String {26 return try {27 val normalized = if (url.startsWith("http")) url else "https://$url"28 java.net.URL(normalized).host29 } catch (_: Exception) {30 url31 }32}3334/**35 * Browser parity with `shared/domain.ts::detectHomograph`: true when the host36 * contains non-ASCII characters or a punycode `xn--` label. This is warning-only;37 * matching/keying remains handled by [extractDomain].38 */39fun detectHomograph(url: String): Boolean {40 return try {41 val normalized = if (url.contains("://")) url else "https://$url"42 val host = java.net.URL(normalized).host43 host.any { it.code > 0x7F } || host.split('.').any { it.startsWith("xn--", ignoreCase = true) }44 } catch (_: Exception) {45 false46 }47}