package net.aliasvault.app.credentialprovider

import android.os.Build
import android.util.Base64
import android.util.Log
import androidx.annotation.RequiresApi
import androidx.credentials.provider.CallingAppInfo
import org.json.JSONArray
import java.io.BufferedReader
import java.io.InputStreamReader
import java.net.HttpURLConnection
import java.net.URL
import java.security.MessageDigest

/**
 * Validates caller origin for WebAuthn credential requests.
 *
 * For privileged apps (browsers): Uses CallingAppInfo.getOrigin() with an allowlist.
 * For native apps: Computes facetId from the app's signing certificate SHA-256 hash.
 *
 * Reference: https://developer.android.com/identity/sign-in/credential-provider
 */
class OriginVerifier {

    companion object {
        private const val TAG = "OriginVerifier"

        /**
         * Privileged app allowlist for CallingAppInfo.getOrigin().
         * Includes major browsers trusted to make requests on behalf of web origins.
         * ------
         * 2025-12-30 cached version based on Google's full list: https://www.gstatic.com/gpm-passkeys-privileged-apps/apps.json
         */
        private val PRIVILEGED_ALLOWLIST_JSON = """
        {
            "apps": [
                {
                "type": "android",
                "info": {
                    "package_name": "com.android.chrome",
                    "signatures": [
                    {
                        "build": "release",
                        "cert_fingerprint_sha256": "F0:FD:6C:5B:41:0F:25:CB:25:C3:B5:33:46:C8:97:2F:AE:30:F8:EE:74:11:DF:91:04:80:AD:6B:2D:60:DB:83"
                    },
                    {
                        "build": "userdebug",
                        "cert_fingerprint_sha256": "19:75:B2:F1:71:77:BC:89:A5:DF:F3:1F:9E:64:A6:CA:E2:81:A5:3D:C1:D1:D5:9B:1D:14:7F:E1:C8:2A:FA:00"
                    }
                    ]
                }
                },
                {
                "type": "android",
                "info": {
                    "package_name": "com.chrome.beta",
                    "signatures": [
                    {
                        "build": "release",
                        "cert_fingerprint_sha256": "DA:63:3D:34:B6:9E:63:AE:21:03:B4:9D:53:CE:05:2F:C5:F7:F3:C5:3A:AB:94:FD:C2:A2:08:BD:FD:14:24:9C"
                    },
                    {
                        "build": "release",
                        "cert_fingerprint_sha256": "3D:7A:12:23:01:9A:A3:9D:9E:A0:E3:43:6A:B7:C0:89:6B:FB:4F:B6:79:F4:DE:5F:E7:C2:3F:32:6C:8F:99:4A"
                    }
                    ]
                }
                },
                {
                "type": "android",
                "info": {
                    "package_name": "com.chrome.dev",
                    "signatures": [
                    {
                        "build": "release",
                        "cert_fingerprint_sha256": "90:44:EE:5F:EE:4B:BC:5E:21:DD:44:66:54:31:C4:EB:1F:1F:71:A3:27:16:A0:BC:92:7B:CB:B3:92:33:CA:BF"
                    },
                    {
                        "build": "release",
                        "cert_fingerprint_sha256": "3D:7A:12:23:01:9A:A3:9D:9E:A0:E3:43:6A:B7:C0:89:6B:FB:4F:B6:79:F4:DE:5F:E7:C2:3F:32:6C:8F:99:4A"
                    }
                    ]
                }
                },
                {
                "type": "android",
                "info": {
                    "package_name": "com.chrome.canary",
                    "signatures": [
                    {
                        "build": "release",
                        "cert_fingerprint_sha256": "20:19:DF:A1:FB:23:EF:BF:70:C5:BC:D1:44:3C:5B:EA:B0:4F:3F:2F:F4:36:6E:9A:C1:E3:45:76:39:A2:4C:FC"
                    }
                    ]
                }
                },
                {
                "type": "android",
                "info": {
                    "package_name": "org.chromium.chrome",
                    "signatures": [
                    {
                        "build": "release",
                        "cert_fingerprint_sha256": "C6:AD:B8:B8:3C:6D:4C:17:D2:92:AF:DE:56:FD:48:8A:51:D3:16:FF:8F:2C:11:C5:41:02:23:BF:F8:A7:DB:B3"
                    },
                    {
                        "build": "userdebug",
                        "cert_fingerprint_sha256": "19:75:B2:F1:71:77:BC:89:A5:DF:F3:1F:9E:64:A6:CA:E2:81:A5:3D:C1:D1:D5:9B:1D:14:7F:E1:C8:2A:FA:00"
                    }
                    ]
                }
                },
                {
                "type": "android",
                "info": {
                    "package_name": "com.google.android.apps.chrome",
                    "signatures": [
                    {
                        "build": "userdebug",
                        "cert_fingerprint_sha256": "19:75:B2:F1:71:77:BC:89:A5:DF:F3:1F:9E:64:A6:CA:E2:81:A5:3D:C1:D1:D5:9B:1D:14:7F:E1:C8:2A:FA:00"
                    }
                    ]
                }
                },
                {
                "type": "android",
                "info": {
                    "package_name": "org.mozilla.fennec_webauthndebug",
                    "signatures": [
                    {
                        "build": "userdebug",
                        "cert_fingerprint_sha256": "BD:AE:82:02:80:D2:AF:B7:74:94:EF:22:58:AA:78:A9:AE:A1:36:41:7E:8B:C2:3D:C9:87:75:2E:6F:48:E8:48"
                    }
                    ]
                }
                },
                {
                "type": "android",
                "info": {
                    "package_name": "org.mozilla.firefox",
                    "signatures": [
                    {
                        "build": "release",
                        "cert_fingerprint_sha256": "A7:8B:62:A5:16:5B:44:94:B2:FE:AD:9E:76:A2:80:D2:2D:93:7F:EE:62:51:AE:CE:59:94:46:B2:EA:31:9B:04"
                    }
                    ]
                }
                },
                {
                "type": "android",
                "info": {
                    "package_name": "org.mozilla.firefox_beta",
                    "signatures": [
                    {
                        "build": "release",
                        "cert_fingerprint_sha256": "A7:8B:62:A5:16:5B:44:94:B2:FE:AD:9E:76:A2:80:D2:2D:93:7F:EE:62:51:AE:CE:59:94:46:B2:EA:31:9B:04"
                    }
                    ]
                }
                },
                {
                "type": "android",
                "info": {
                    "package_name": "org.mozilla.focus",
                    "signatures": [
                    {
                        "build": "release",
                        "cert_fingerprint_sha256": "62:03:A4:73:BE:36:D6:4E:E3:7F:87:FA:50:0E:DB:C7:9E:AB:93:06:10:AB:9B:9F:A4:CA:7D:5C:1F:1B:4F:FC"
                    }
                    ]
                }
                },
                {
                "type": "android",
                "info": {
                    "package_name": "org.mozilla.fennec_aurora",
                    "signatures": [
                    {
                        "build": "release",
                        "cert_fingerprint_sha256": "BC:04:88:83:8D:06:F4:CA:6B:F3:23:86:DA:AB:0D:D8:EB:CF:3E:77:30:78:74:59:F6:2F:B3:CD:14:A1:BA:AA"
                    }
                    ]
                }
                },
                {
                "type": "android",
                "info": {
                    "package_name": "org.mozilla.rocket",
                    "signatures": [
                    {
                        "build": "release",
                        "cert_fingerprint_sha256": "86:3A:46:F0:97:39:32:B7:D0:19:9B:54:91:12:74:1C:2D:27:31:AC:72:EA:11:B7:52:3A:A9:0A:11:BF:56:91"
                    }
                    ]
                }
                },
                {
                "type": "android",
                "info": {
                    "package_name": "org.mozilla.fenix",
                    "signatures": [
                    {
                        "build": "release",
                        "cert_fingerprint_sha256": "50:04:77:90:88:E7:F9:88:D5:BC:5C:C5:F8:79:8F:EB:F4:F8:CD:08:4A:1B:2A:46:EF:D4:C8:EE:4A:EA:F2:11"
                    }
                    ]
                }
                },
                {
                "type": "android",
                "info": {
                    "package_name": "org.mozilla.fenix.debug",
                    "signatures": [
                    {
                        "build": "userdebug",
                        "cert_fingerprint_sha256": "BD:AE:82:02:80:D2:AF:B7:74:94:EF:22:58:AA:78:A9:AE:A1:36:41:7E:8B:C2:3D:C9:87:75:2E:6F:48:E8:48"
                    }
                    ]
                }
                },
                {
                "type": "android",
                "info": {
                    "package_name": "org.mozilla.focus.beta",
                    "signatures": [
                    {
                        "build": "release",
                        "cert_fingerprint_sha256": "62:03:A4:73:BE:36:D6:4E:E3:7F:87:FA:50:0E:DB:C7:9E:AB:93:06:10:AB:9B:9F:A4:CA:7D:5C:1F:1B:4F:FC"
                    }
                    ]
                }
                },
                {
                "type": "android",
                "info": {
                    "package_name": "org.mozilla.focus.nightly",
                    "signatures": [
                    {
                        "build": "release",
                        "cert_fingerprint_sha256": "62:03:A4:73:BE:36:D6:4E:E3:7F:87:FA:50:0E:DB:C7:9E:AB:93:06:10:AB:9B:9F:A4:CA:7D:5C:1F:1B:4F:FC"
                    }
                    ]
                }
                },
                {
                "type": "android",
                "info": {
                    "package_name": "org.mozilla.klar",
                    "signatures": [
                    {
                        "build": "release",
                        "cert_fingerprint_sha256": "62:03:A4:73:BE:36:D6:4E:E3:7F:87:FA:50:0E:DB:C7:9E:AB:93:06:10:AB:9B:9F:A4:CA:7D:5C:1F:1B:4F:FC"
                    }
                    ]
                }
                },
                {
                "type": "android",
                "info": {
                    "package_name": "org.mozilla.reference.browser",
                    "signatures": [
                    {
                        "build": "release",
                        "cert_fingerprint_sha256": "B0:09:90:E3:0F:9D:81:5D:2E:BC:7B:9B:B2:21:CE:47:E5:C9:D5:17:AA:C7:0E:7F:D5:95:B1:E5:3E:9A:4B:14"
                    }
                    ]
                }
                },
                {
                "type": "android",
                "info": {
                    "package_name": "com.microsoft.emmx.canary",
                    "signatures": [
                    {
                        "build": "release",
                        "cert_fingerprint_sha256": "01:E1:99:97:10:A8:2C:27:49:B4:D5:0C:44:5D:C8:5D:67:0B:61:36:08:9D:0A:76:6A:73:82:7C:82:A1:EA:C9"
                    }
                    ]
                }
                },
                {
                "type": "android",
                "info": {
                    "package_name": "com.microsoft.emmx.dev",
                    "signatures": [
                    {
                        "build": "release",
                        "cert_fingerprint_sha256": "01:E1:99:97:10:A8:2C:27:49:B4:D5:0C:44:5D:C8:5D:67:0B:61:36:08:9D:0A:76:6A:73:82:7C:82:A1:EA:C9"
                    }
                    ]
                }
                },
                {
                "type": "android",
                "info": {
                    "package_name": "com.microsoft.emmx.beta",
                    "signatures": [
                    {
                        "build": "release",
                        "cert_fingerprint_sha256": "01:E1:99:97:10:A8:2C:27:49:B4:D5:0C:44:5D:C8:5D:67:0B:61:36:08:9D:0A:76:6A:73:82:7C:82:A1:EA:C9"
                    }
                    ]
                }
                },
                {
                "type": "android",
                "info": {
                    "package_name": "com.microsoft.emmx",
                    "signatures": [
                    {
                        "build": "release",
                        "cert_fingerprint_sha256": "01:E1:99:97:10:A8:2C:27:49:B4:D5:0C:44:5D:C8:5D:67:0B:61:36:08:9D:0A:76:6A:73:82:7C:82:A1:EA:C9"
                    }
                    ]
                }
                },
                {
                "type": "android",
                "info": {
                    "package_name": "com.microsoft.emmx.rolling",
                    "signatures": [
                    {
                        "build": "userdebug",
                        "cert_fingerprint_sha256": "32:A2:FC:74:D7:31:10:58:59:E5:A8:5D:F1:6D:95:F1:02:D8:5B:22:09:9B:80:64:C5:D8:91:5C:61:DA:D1:E0"
                    }
                    ]
                }
                },
                {
                "type": "android",
                "info": {
                    "package_name": "com.microsoft.emmx.local",
                    "signatures": [
                    {
                        "build": "userdebug",
                        "cert_fingerprint_sha256": "32:A2:FC:74:D7:31:10:58:59:E5:A8:5D:F1:6D:95:F1:02:D8:5B:22:09:9B:80:64:C5:D8:91:5C:61:DA:D1:E0"
                    }
                    ]
                }
                },
                {
                "type": "android",
                "info": {
                    "package_name": "com.brave.browser",
                    "signatures": [
                    {
                        "build": "release",
                        "cert_fingerprint_sha256": "9C:2D:B7:05:13:51:5F:DB:FB:BC:58:5B:3E:DF:3D:71:23:D4:DC:67:C9:4F:FD:30:63:61:C1:D7:9B:BF:18:AC"
                    }
                    ]
                }
                },
                {
                "type": "android",
                "info": {
                    "package_name": "com.brave.browser_beta",
                    "signatures": [
                    {
                        "build": "release",
                        "cert_fingerprint_sha256": "9C:2D:B7:05:13:51:5F:DB:FB:BC:58:5B:3E:DF:3D:71:23:D4:DC:67:C9:4F:FD:30:63:61:C1:D7:9B:BF:18:AC"
                    }
                    ]
                }
                },
                {
                "type": "android",
                "info": {
                    "package_name": "com.brave.browser_nightly",
                    "signatures": [
                    {
                        "build": "release",
                        "cert_fingerprint_sha256": "9C:2D:B7:05:13:51:5F:DB:FB:BC:58:5B:3E:DF:3D:71:23:D4:DC:67:C9:4F:FD:30:63:61:C1:D7:9B:BF:18:AC"
                    }
                    ]
                }
                },
                {
                "type": "android",
                "info": {
                    "package_name": "app.vanadium.browser",
                    "signatures": [
                    {
                        "build": "release",
                        "cert_fingerprint_sha256": "C6:AD:B8:B8:3C:6D:4C:17:D2:92:AF:DE:56:FD:48:8A:51:D3:16:FF:8F:2C:11:C5:41:02:23:BF:F8:A7:DB:B3"
                    }
                    ]
                }
                },
                {
                "type": "android",
                "info": {
                    "package_name": "com.vivaldi.browser",
                    "signatures": [
                    {
                        "build": "release",
                        "cert_fingerprint_sha256": "E8:A7:85:44:65:5B:A8:C0:98:17:F7:32:76:8F:56:89:B1:66:2E:C4:B2:BC:5A:0B:C0:EC:13:8D:33:CA:3D:1E"
                    }
                    ]
                }
                },
                {
                "type": "android",
                "info": {
                    "package_name": "com.vivaldi.browser.snapshot",
                    "signatures": [
                    {
                        "build": "release",
                        "cert_fingerprint_sha256": "E8:A7:85:44:65:5B:A8:C0:98:17:F7:32:76:8F:56:89:B1:66:2E:C4:B2:BC:5A:0B:C0:EC:13:8D:33:CA:3D:1E"
                    }
                    ]
                }
                },
                {
                "type": "android",
                "info": {
                    "package_name": "com.vivaldi.browser.sopranos",
                    "signatures": [
                    {
                        "build": "release",
                        "cert_fingerprint_sha256": "E8:A7:85:44:65:5B:A8:C0:98:17:F7:32:76:8F:56:89:B1:66:2E:C4:B2:BC:5A:0B:C0:EC:13:8D:33:CA:3D:1E"
                    }
                    ]
                }
                },
                {
                "type": "android",
                "info": {
                    "package_name": "com.citrix.Receiver",
                    "signatures": [
                    {
                        "build": "release",
                        "cert_fingerprint_sha256": "3D:D1:12:67:10:69:AB:36:4E:F9:BE:73:9A:B7:B5:EE:15:E1:CD:E9:D8:75:7B:1B:F0:64:F5:0C:55:68:9A:49"
                    },
                    {
                        "build": "release",
                        "cert_fingerprint_sha256": "CE:B2:23:D7:77:09:F2:B6:BC:0B:3A:78:36:F5:A5:AF:4C:E1:D3:55:F4:A7:28:86:F7:9D:F8:0D:C9:D6:12:2E"
                    },
                    {
                        "build": "release",
                        "cert_fingerprint_sha256": "AA:D0:D4:57:E6:33:C3:78:25:77:30:5B:C1:B2:D9:E3:81:41:C7:21:DF:0D:AA:6E:29:07:2F:C4:1D:34:F0:AB"
                    }
                    ]
                }
                },
                {
                "type": "android",
                "info": {
                    "package_name": "com.android.browser",
                    "signatures": [
                    {
                        "build": "release",
                        "cert_fingerprint_sha256": "C9:00:9D:01:EB:F9:F5:D0:30:2B:C7:1B:2F:E9:AA:9A:47:A4:32:BB:A1:73:08:A3:11:1B:75:D7:B2:14:90:25"
                    }
                    ]
                }
                },
                {
                "type": "android",
                "info": {
                    "package_name": "com.sec.android.app.sbrowser",
                    "signatures": [
                    {
                        "build": "release",
                        "cert_fingerprint_sha256": "C8:A2:E9:BC:CF:59:7C:2F:B6:DC:66:BE:E2:93:FC:13:F2:FC:47:EC:77:BC:6B:2B:0D:52:C1:1F:51:19:2A:B8"
                    },
                    {
                        "build": "release",
                        "cert_fingerprint_sha256": "34:DF:0E:7A:9F:1C:F1:89:2E:45:C0:56:B4:97:3C:D8:1C:CF:14:8A:40:50:D1:1A:EA:4A:C5:A6:5F:90:0A:42"
                    }
                    ]
                }
                },
                {
                "type": "android",
                "info": {
                    "package_name": "com.sec.android.app.sbrowser.beta",
                    "signatures": [
                    {
                        "build": "release",
                        "cert_fingerprint_sha256": "C8:A2:E9:BC:CF:59:7C:2F:B6:DC:66:BE:E2:93:FC:13:F2:FC:47:EC:77:BC:6B:2B:0D:52:C1:1F:51:19:2A:B8"
                    },
                    {
                        "build": "release",
                        "cert_fingerprint_sha256": "34:DF:0E:7A:9F:1C:F1:89:2E:45:C0:56:B4:97:3C:D8:1C:CF:14:8A:40:50:D1:1A:EA:4A:C5:A6:5F:90:0A:42"
                    }
                    ]
                }
                },
                {
                "type": "android",
                "info": {
                    "package_name": "com.google.android.gms",
                    "signatures": [
                    {
                        "build": "release",
                        "cert_fingerprint_sha256": "7C:E8:3C:1B:71:F3:D5:72:FE:D0:4C:8D:40:C5:CB:10:FF:75:E6:D8:7D:9D:F6:FB:D5:3F:04:68:C2:90:50:53"
                    },
                    {
                        "build": "release",
                        "cert_fingerprint_sha256": "D2:2C:C5:00:29:9F:B2:28:73:A0:1A:01:0D:E1:C8:2F:BE:4D:06:11:19:B9:48:14:DD:30:1D:AB:50:CB:76:78"
                    },
                    {
                        "build": "release",
                        "cert_fingerprint_sha256": "F0:FD:6C:5B:41:0F:25:CB:25:C3:B5:33:46:C8:97:2F:AE:30:F8:EE:74:11:DF:91:04:80:AD:6B:2D:60:DB:83"
                    },
                    {
                        "build": "release",
                        "cert_fingerprint_sha256": "19:75:B2:F1:71:77:BC:89:A5:DF:F3:1F:9E:64:A6:CA:E2:81:A5:3D:C1:D1:D5:9B:1D:14:7F:E1:C8:2A:FA:00"
                    }
                    ]
                }
                },
                {
                "type": "android",
                "info": {
                    "package_name": "com.yandex.browser",
                    "signatures": [
                    {
                        "build": "release",
                        "cert_fingerprint_sha256": "AC:A4:05:DE:D8:B2:5C:B2:E8:C6:DA:69:42:5D:2B:43:07:D0:87:C1:27:6F:C0:6A:D5:94:27:31:CC:C5:1D:BA"
                    }
                    ]
                }
                },
                {
                "type": "android",
                "info": {
                    "package_name": "com.yandex.browser.beta",
                    "signatures": [
                    {
                        "build": "release",
                        "cert_fingerprint_sha256": "AC:A4:05:DE:D8:B2:5C:B2:E8:C6:DA:69:42:5D:2B:43:07:D0:87:C1:27:6F:C0:6A:D5:94:27:31:CC:C5:1D:BA"
                    }
                    ]
                }
                },
                {
                "type": "android",
                "info": {
                    "package_name": "com.yandex.browser.alpha",
                    "signatures": [
                    {
                        "build": "release",
                        "cert_fingerprint_sha256": "AC:A4:05:DE:D8:B2:5C:B2:E8:C6:DA:69:42:5D:2B:43:07:D0:87:C1:27:6F:C0:6A:D5:94:27:31:CC:C5:1D:BA"
                    }
                    ]
                }
                },
                {
                "type": "android",
                "info": {
                    "package_name": "com.yandex.browser.corp",
                    "signatures": [
                    {
                        "build": "release",
                        "cert_fingerprint_sha256": "AC:A4:05:DE:D8:B2:5C:B2:E8:C6:DA:69:42:5D:2B:43:07:D0:87:C1:27:6F:C0:6A:D5:94:27:31:CC:C5:1D:BA"
                    }
                    ]
                }
                },
                {
                "type": "android",
                "info": {
                    "package_name": "com.yandex.browser.canary",
                    "signatures": [
                    {
                        "build": "release",
                        "cert_fingerprint_sha256": "1D:A9:CB:AE:2D:CC:C6:A5:8D:6C:94:7B:E9:4C:DB:B7:33:D6:5D:A4:D1:77:0F:A1:4A:53:64:CB:4A:28:EB:49"
                    }
                    ]
                }
                },
                {
                "type": "android",
                "info": {
                    "package_name": "com.yandex.browser.broteam",
                    "signatures": [
                    {
                        "build": "release",
                        "cert_fingerprint_sha256": "1D:A9:CB:AE:2D:CC:C6:A5:8D:6C:94:7B:E9:4C:DB:B7:33:D6:5D:A4:D1:77:0F:A1:4A:53:64:CB:4A:28:EB:49"
                    }
                    ]
                }
                },
                {
                "type": "android",
                "info": {
                    "package_name": "com.talonsec.talon",
                    "signatures": [
                    {
                        "build": "release",
                        "cert_fingerprint_sha256": "A3:66:03:44:A6:F6:AF:CA:81:8C:BF:43:96:A2:3C:CF:D5:ED:7A:78:1B:B4:A3:D1:85:03:01:E2:F4:6D:23:83"
                    },
                    {
                        "build": "release",
                        "cert_fingerprint_sha256": "E2:A5:64:74:EA:23:7B:06:67:B6:F5:2C:DC:E9:04:5E:24:88:3B:AE:D0:82:59:9A:A2:DF:0B:60:3A:CF:6A:3B"
                    }
                    ]
                }
                },
                {
                "type": "android",
                "info": {
                    "package_name": "com.talonsec.talon_beta",
                    "signatures": [
                    {
                        "build": "release",
                        "cert_fingerprint_sha256": "F5:86:62:7A:32:C8:9F:E6:7E:00:6D:B1:8C:34:31:9E:01:7F:B3:B2:BE:D6:9D:01:01:B7:F9:43:E7:7C:48:AE"
                    },
                    {
                        "build": "release",
                        "cert_fingerprint_sha256": "9A:A1:25:D5:E5:5E:3F:B0:DE:96:72:D9:A9:5D:04:65:3F:49:4A:1E:C3:EE:76:1E:94:C4:4E:5D:2F:65:8E:2F"
                    }
                    ]
                }
                },
                {
                "type": "android",
                "info": {
                    "package_name": "com.duckduckgo.mobile.android.debug",
                    "signatures": [
                    {
                        "build": "release",
                        "cert_fingerprint_sha256": "C4:F0:9E:2B:D7:25:AD:F5:AD:92:0B:A2:80:27:66:AC:16:4A:C1:53:B3:EA:9E:08:48:B0:57:98:37:F7:6A:29"
                    }
                    ]
                }
                },
                {
                "type": "android",
                "info": {
                    "package_name": "com.duckduckgo.mobile.android",
                    "signatures": [
                    {
                        "build": "release",
                        "cert_fingerprint_sha256": "BB:7B:B3:1C:57:3C:46:A1:DA:7F:C5:C5:28:A6:AC:F4:32:10:84:56:FE:EC:50:81:0C:7F:33:69:4E:B3:D2:D4"
                    }
                    ]
                }
                },
                {
                "type": "android",
                "info": {
                    "package_name": "com.naver.whale",
                    "signatures": [
                    {
                        "build": "release",
                        "cert_fingerprint_sha256": "0B:8B:85:23:BB:4A:EF:FA:34:6E:4B:DD:4F:BF:7D:19:34:50:56:9A:A1:4A:AA:D4:AD:FD:94:A3:F7:B2:27:BB"
                    }
                    ]
                }
                },
                {
                "type": "android",
                "info": {
                    "package_name": "com.fido.fido2client",
                    "signatures": [
                    {
                        "build": "release",
                        "cert_fingerprint_sha256": "FC:98:DA:E6:3A:D3:96:26:C8:C6:7F:BE:83:F2:F0:6F:74:93:2A:9C:D1:46:B9:2C:EC:FC:6A:04:7A:90:43:86"
                    }
                    ]
                }
                },
                {
                "type": "android",
                "info": {
                    "package_name": "com.heytap.browser",
                    "signatures": [
                    {
                        "build": "release",
                        "cert_fingerprint_sha256": "AF:F8:A7:49:CF:0E:7D:75:44:65:D0:FB:FA:7B:8D:0C:64:5E:22:5C:10:C6:E2:32:AD:A0:D9:74:88:36:B8:E5"
                    },
                    {
                        "build": "release",
                        "cert_fingerprint_sha256": "A8:FE:A4:CA:FB:93:32:DA:26:B8:E6:81:08:17:C1:DA:90:A5:03:0E:35:A6:0A:79:E0:6C:90:97:AA:C6:A4:42"
                    }
                    ]
                }
                },
                {
                "type": "android",
                "info": {
                    "package_name": "io.island.Island",
                    "signatures": [
                    {
                        "build": "release",
                        "cert_fingerprint_sha256": "D9:C3:39:AC:9C:3A:EE:E1:75:1D:85:8C:35:D9:BA:C5:CC:87:B3:CE:76:30:93:F0:F5:10:64:F5:A2:F6:9B:04"
                    },
                    {
                        "build": "userdebug",
                        "cert_fingerprint_sha256": "6C:65:BD:B0:33:F5:CE:B1:74:09:EF:F9:99:48:D5:58:9F:55:63:9A:63:78:D5:A5:00:EB:95:FC:01:BC:6D:44"
                    }
                    ]
                }
                },
                {
                "type": "android",
                "info": {
                    "package_name": "io.island.IslandCanary",
                    "signatures": [
                    {
                        "build": "release",
                        "cert_fingerprint_sha256": "90:17:13:23:45:6E:6F:39:CB:FD:CF:B2:56:BE:1D:CF:F3:BC:1C:59:8A:15:93:30:E4:97:73:D0:4C:B9:C9:05"
                    },
                    {
                        "build": "userdebug",
                        "cert_fingerprint_sha256": "6C:65:BD:B0:33:F5:CE:B1:74:09:EF:F9:99:48:D5:58:9F:55:63:9A:63:78:D5:A5:00:EB:95:FC:01:BC:6D:44"
                    }
                    ]
                }
                },
                {
                "type": "android",
                "info": {
                    "package_name": "io.island.IslandBeta",
                    "signatures": [
                    {
                        "build": "release",
                        "cert_fingerprint_sha256": "35:31:83:1A:9E:2B:21:1D:E6:AA:C3:69:4B:45:83:6E:56:09:B9:D7:D0:04:C3:1B:21:87:40:FB:77:17:38:D1"
                    },
                    {
                        "build": "userdebug",
                        "cert_fingerprint_sha256": "6C:65:BD:B0:33:F5:CE:B1:74:09:EF:F9:99:48:D5:58:9F:55:63:9A:63:78:D5:A5:00:EB:95:FC:01:BC:6D:44"
                    }
                    ]
                }
                },
                {
                "type": "android",
                "info": {
                    "package_name": "io.island.IslandDev",
                    "signatures": [
                    {
                        "build": "userdebug",
                        "cert_fingerprint_sha256": "6C:65:BD:B0:33:F5:CE:B1:74:09:EF:F9:99:48:D5:58:9F:55:63:9A:63:78:D5:A5:00:EB:95:FC:01:BC:6D:44"
                    }
                    ]
                }
                },
                {
                "type": "android",
                "info": {
                    "package_name": "io.island.island.intune",
                    "signatures": [
                    {
                        "build": "release",
                        "cert_fingerprint_sha256": "C2:38:24:15:41:20:A0:8F:C3:95:42:AC:D8:2A:E9:24:94:78:80:1E:47:FD:6C:66:2B:18:1C:28:CA:7E:59:4E"
                    },
                    {
                        "build": "userdebug",
                        "cert_fingerprint_sha256": "6C:65:BD:B0:33:F5:CE:B1:74:09:EF:F9:99:48:D5:58:9F:55:63:9A:63:78:D5:A5:00:EB:95:FC:01:BC:6D:44"
                    }
                    ]
                }
                },
                {
                "type": "android",
                "info": {
                    "package_name": "io.island.island.canary.intune",
                    "signatures": [
                    {
                        "build": "release",
                        "cert_fingerprint_sha256": "1E:16:74:BB:79:EA:09:FB:37:CF:9F:1B:07:1B:1D:51:8D:46:03:0E:D3:EE:F2:C1:4E:AD:93:9E:C6:EE:3A:4C"
                    },
                    {
                        "build": "userdebug",
                        "cert_fingerprint_sha256": "6C:65:BD:B0:33:F5:CE:B1:74:09:EF:F9:99:48:D5:58:9F:55:63:9A:63:78:D5:A5:00:EB:95:FC:01:BC:6D:44"
                    }
                    ]
                }
                },
                {
                "type": "android",
                "info": {
                    "package_name": "io.island.island.beta.intune",
                    "signatures": [
                    {
                        "build": "release",
                        "cert_fingerprint_sha256": "D2:5E:AD:F6:1C:E6:36:6C:A4:23:A4:7F:C4:DB:9B:8C:9C:8A:35:B4:B0:19:E8:D9:82:FB:D0:8A:D9:DB:49:5A"
                    },
                    {
                        "build": "userdebug",
                        "cert_fingerprint_sha256": "6C:65:BD:B0:33:F5:CE:B1:74:09:EF:F9:99:48:D5:58:9F:55:63:9A:63:78:D5:A5:00:EB:95:FC:01:BC:6D:44"
                    }
                    ]
                }
                },
                {
                "type": "android",
                "info": {
                    "package_name": "io.island.island.dev.intune",
                    "signatures": [
                    {
                        "build": "userdebug",
                        "cert_fingerprint_sha256": "6C:65:BD:B0:33:F5:CE:B1:74:09:EF:F9:99:48:D5:58:9F:55:63:9A:63:78:D5:A5:00:EB:95:FC:01:BC:6D:44"
                    }
                    ]
                }
                },
                {
                "type": "android",
                "info": {
                    "package_name": "net.quetta.browser",
                    "signatures": [
                    {
                        "build": "release",
                        "cert_fingerprint_sha256": "BE:FE:E7:31:12:6A:A5:6E:7E:FD:AE:AF:5E:F3:FA:EA:44:1C:19:CC:E0:CA:EC:42:6B:65:BB:F8:2C:59:46:80"
                    },
                    {
                        "build": "userdebug",
                        "cert_fingerprint_sha256": "F1:38:00:4F:38:04:51:D4:8A:05:2B:B3:A3:EF:17:24:23:D4:B0:D0:C8:A3:AA:DD:FB:DB:66:30:31:48:EC:A4"
                    }
                    ]
                }
                },
                {
                "type": "android",
                "info": {
                    "package_name": "cz.seznam.sbrowser",
                    "signatures": [
                    {
                        "build": "release",
                        "cert_fingerprint_sha256": "DB:95:40:66:10:78:83:6E:4E:B1:66:F6:9E:F4:07:30:9E:8D:AE:33:34:68:5E:C8:F6:FA:2F:13:81:B9:AC:F6"
                    }
                    ]
                }
                },
                {
                "type": "android",
                "info": {
                    "package_name": "com.opera.mini.native",
                    "signatures": [
                    {
                        "build": "release",
                        "cert_fingerprint_sha256": "57:AC:BC:52:5F:1B:2E:BD:19:19:6C:D6:F0:14:39:7C:C9:10:FD:18:84:1E:0A:E8:50:FE:BC:3E:1E:59:3F:F2"
                    }
                    ]
                }
                },
                {
                "type": "android",
                "info": {
                    "package_name": "com.opera.mini.native.beta",
                    "signatures": [
                    {
                        "build": "release",
                        "cert_fingerprint_sha256": "57:AC:BC:52:5F:1B:2E:BD:19:19:6C:D6:F0:14:39:7C:C9:10:FD:18:84:1E:0A:E8:50:FE:BC:3E:1E:59:3F:F2"
                    }
                    ]
                }
                }
            ]
        }
        """.trimIndent()
    }

    /** Result of origin verification. */
    sealed class OriginResult {
        /**
         * Origin was successfully verified.
         * @property origin The verified origin string.
         * @property isPrivileged True if the caller is a privileged app (browser).
         */
        data class Success(val origin: String, val isPrivileged: Boolean) : OriginResult()

        /**
         * Origin verification failed.
         * @property reason Human-readable reason for failure.
         */
        data class Failure(val reason: String) : OriginResult()
    }

    /** Result of asset links verification. */
    private sealed class AssetLinksResult {
        data object Success : AssetLinksResult()
        data class Failure(val reason: String) : AssetLinksResult()
    }

    /**
     * Verify and compute the origin for a credential request.
     */
    @RequiresApi(Build.VERSION_CODES.P)
    fun verifyOrigin(
        callingAppInfo: CallingAppInfo?,
        requestedRpId: String,
    ): OriginResult {
        if (callingAppInfo == null) {
            Log.e(TAG, "CallingAppInfo is null - cannot verify origin")
            return OriginResult.Failure("Cannot identify calling application")
        }

        val packageName = callingAppInfo.packageName
        Log.d(TAG, "Verifying origin for package: $packageName, rpId: $requestedRpId")

        // Try to get origin from privileged app (browser)
        val privilegedOrigin = try {
            callingAppInfo.getOrigin(PRIVILEGED_ALLOWLIST_JSON)
        } catch (e: Exception) {
            Log.d(TAG, "Not a privileged caller or getOrigin failed: ${e.message}")
            null
        }

        if (privilegedOrigin != null) {
            Log.d(TAG, "Privileged caller detected, origin: $privilegedOrigin")

            if (!isOriginValidForRpId(privilegedOrigin, requestedRpId)) {
                Log.w(TAG, "Privileged origin $privilegedOrigin does not match rpId $requestedRpId")
                return OriginResult.Failure("Origin does not match RP ID")
            }

            return OriginResult.Success(privilegedOrigin, isPrivileged = true)
        }

        // Not a privileged caller - compute facetId from signing certificate
        val facetId = computeFacetId(callingAppInfo)
        if (facetId == null) {
            Log.e(TAG, "Failed to compute facetId for $packageName")
            return OriginResult.Failure("Cannot verify calling application signature")
        }

        Log.d(TAG, "Native app detected, facetId: $facetId")

        // Verify the native app is authorized via Asset Links
        val certFingerprint = getCertificateFingerprint(callingAppInfo)
        if (certFingerprint == null) {
            Log.e(TAG, "Failed to get certificate fingerprint for $packageName")
            return OriginResult.Failure("Cannot verify calling application signature")
        }

        val assetLinksResult = verifyAssetLinks(requestedRpId, packageName, certFingerprint)
        if (assetLinksResult is AssetLinksResult.Failure) {
            Log.e(TAG, "Asset links verification failed for $packageName on $requestedRpId: ${assetLinksResult.reason}")
            return OriginResult.Failure(assetLinksResult.reason)
        }

        Log.d(TAG, "Asset links verification passed for $packageName on $requestedRpId")
        return OriginResult.Success(facetId, isPrivileged = false)
    }

    /**
     * Compute the facetId (origin) for a native Android app.
     * Format: android:apk-key-hash:<base64url-encoded-sha256>
     */
    @RequiresApi(Build.VERSION_CODES.P)
    private fun computeFacetId(callingAppInfo: CallingAppInfo): String? {
        return try {
            val signingInfo = callingAppInfo.signingInfo
            val signers = signingInfo.apkContentsSigners
            if (signers.isEmpty()) {
                Log.e(TAG, "No signing certificates found for ${callingAppInfo.packageName}")
                return null
            }

            val cert = signers[0].toByteArray()
            val md = MessageDigest.getInstance("SHA-256")
            val certHash = md.digest(cert)

            // Encode as base64url (no padding, URL-safe characters)
            val base64Hash = Base64.encodeToString(
                certHash,
                Base64.URL_SAFE or Base64.NO_WRAP or Base64.NO_PADDING,
            )

            "android:apk-key-hash:$base64Hash"
        } catch (e: Exception) {
            Log.e(TAG, "Error computing facetId", e)
            null
        }
    }

    /**
     * Verify that an origin is valid for the given RP ID.
     * The origin must be https:// and the host must equal or be a subdomain of the RP ID.
     */
    private fun isOriginValidForRpId(origin: String, rpId: String): Boolean {
        val originHost = try {
            val url = URL(origin)
            if (url.protocol != "https") {
                Log.w(TAG, "Origin is not HTTPS: $origin")
                return false
            }
            url.host.lowercase()
        } catch (e: Exception) {
            Log.w(TAG, "Invalid origin URL: $origin", e)
            return false
        }

        val rpIdLower = rpId.lowercase()
        return originHost == rpIdLower || originHost.endsWith(".$rpIdLower")
    }

    /**
     * Verify that a native app is authorized for the given RP ID via Asset Links.
     * Fetches /.well-known/assetlinks.json and checks for get_login_creds permission.
     */
    private fun verifyAssetLinks(rpId: String, packageName: String, certHash: String): AssetLinksResult {
        return try {
            val assetLinksUrl = URL("https://$rpId/.well-known/assetlinks.json")
            val connection = assetLinksUrl.openConnection() as HttpURLConnection
            connection.connectTimeout = 5000
            connection.readTimeout = 5000
            connection.requestMethod = "GET"

            if (connection.responseCode != HttpURLConnection.HTTP_OK) {
                Log.w(TAG, "Asset links not found for $rpId: ${connection.responseCode}")
                return AssetLinksResult.Failure(
                    "App is not authorized to access passkeys for $rpId",
                )
            }

            val reader = BufferedReader(InputStreamReader(connection.inputStream))
            val response = reader.readText()
            reader.close()

            val assetLinks = JSONArray(response)
            val normalizedCertHash = certHash.replace(":", "").lowercase()

            val found = (0 until assetLinks.length()).any { i ->
                val link = assetLinks.getJSONObject(i)
                isMatchingAssetLink(link, packageName, normalizedCertHash)
            }

            if (found) {
                Log.d(TAG, "Asset links verification passed for $packageName on $rpId")
                AssetLinksResult.Success
            } else {
                Log.w(TAG, "App $packageName not found in asset links for $rpId")
                AssetLinksResult.Failure(
                    "App is not authorized to access passkeys for $rpId",
                )
            }
        } catch (e: Exception) {
            Log.w(TAG, "Asset links verification failed for $rpId", e)
            AssetLinksResult.Failure(
                "App is not authorized to access passkeys for $rpId",
            )
        }
    }

    /** Check if an asset link entry matches the given package and certificate. */
    private fun isMatchingAssetLink(
        link: org.json.JSONObject,
        packageName: String,
        normalizedCertHash: String,
    ): Boolean {
        val relation = link.optJSONArray("relation") ?: return false
        val target = link.optJSONObject("target") ?: return false

        if (target.optString("namespace") != "android_app") return false
        if (target.optString("package_name") != packageName) return false

        val hasGetLoginCreds = (0 until relation.length()).any { j ->
            relation.getString(j) == "delegate_permission/common.get_login_creds"
        }
        if (!hasGetLoginCreds) return false

        val fingerprints = target.optJSONArray("sha256_cert_fingerprints") ?: return false
        return (0 until fingerprints.length()).any { j ->
            fingerprints.getString(j).replace(":", "").lowercase() == normalizedCertHash
        }
    }

    /** Get a human-readable certificate fingerprint. */
    @RequiresApi(Build.VERSION_CODES.P)
    fun getCertificateFingerprint(callingAppInfo: CallingAppInfo): String? {
        return try {
            val signers = callingAppInfo.signingInfo.apkContentsSigners
            if (signers.isEmpty()) return null

            val cert = signers[0].toByteArray()
            val md = MessageDigest.getInstance("SHA-256")
            val certHash = md.digest(cert)

            certHash.joinToString(":") { "%02X".format(it) }
        } catch (e: Exception) {
            Log.e(TAG, "Error getting certificate fingerprint", e)
            null
        }
    }
}
