fix(store): use string prefix + URLSearchParams for connection URL parsing

The URL constructor parses non-standard protocols (multica://)
differently across engines — Chromium may return empty hostname
while Node.js returns "connect". Replace new URL() with simple
startsWith check and URLSearchParams to ensure consistent behavior
in both web and Electron environments.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Naiyuan Qing 2026-02-03 20:13:51 +08:00
parent ff80cf0732
commit b6d7626239

View file

@ -22,10 +22,50 @@ function isConnectionInfo(obj: unknown): obj is ConnectionInfo {
)
}
// Parse multica://connect?gateway=...&hub=...&agent=...&token=...&exp=... URL format
// Uses string prefix + URLSearchParams to avoid cross-engine URL hostname differences
function parseConnectionUrl(input: string): ConnectionInfo | null {
const prefix = "multica://connect?"
if (!input.startsWith(prefix)) return null
try {
const params = new URLSearchParams(input.slice(prefix.length))
const gateway = params.get("gateway")
const hubId = params.get("hub")
const agentId = params.get("agent")
const token = params.get("token")
const exp = params.get("exp")
if (!gateway || !hubId || !agentId || !token || !exp) return null
return {
type: "multica-connect",
gateway,
hubId,
agentId,
token,
expires: Number(exp),
}
} catch {
return null
}
}
function isExpired(expires: number): boolean {
// Desktop generates expires as millisecond timestamp (Date.now() + seconds * 1000)
return Date.now() > expires
}
export function parseConnectionCode(input: string): ConnectionInfo {
const trimmed = input.trim()
// Try JSON first
// Try multica:// URL format first (desktop "Copy Link" output)
const fromUrl = parseConnectionUrl(trimmed)
if (fromUrl) {
if (isExpired(fromUrl.expires)) {
throw new Error("Connection code has expired")
}
return fromUrl
}
// Try JSON (QR code scan output)
let parsed: unknown
try {
parsed = JSON.parse(trimmed)
@ -42,7 +82,7 @@ export function parseConnectionCode(input: string): ConnectionInfo {
throw new Error("Invalid connection code format")
}
if (Date.now() > parsed.expires * 1000) {
if (isExpired(parsed.expires)) {
throw new Error("Connection code has expired")
}
@ -60,7 +100,7 @@ export function loadConnection(): ConnectionInfo | null {
try {
const info = JSON.parse(raw)
if (!isConnectionInfo(info)) return null
if (Date.now() > info.expires * 1000) {
if (isExpired(info.expires)) {
localStorage.removeItem(STORAGE_KEY)
return null
}