/** * Where the extension may send its tokens. A device's access and refresh tokens and its enrolment code are bearer secrets, so they only travel over https (or * wss), except to this machine itself, where a person testing locally has no certificate to use. */ export function isLoopbackHost(hostname: string): boolean { const h = hostname.toLowerCase().replace(/^\[|\]$/g, ""); return h === "localhost" || h === "::1" || /^127(\.\d{1,3}){3}$/.test(h); } /** The address without a trailing slash if it is https, or http to this machine; otherwise nothing. */ export function secureHttpBase(address: string): string | undefined { if (!URL.canParse(address)) return undefined; const u = new URL(address); if (u.protocol === "https:" || (u.protocol === "http:" && isLoopbackHost(u.hostname))) return address.replace(/\/+$/, ""); return undefined; } /** True when `url` is a wss address (or ws to this machine) on the same host as the central address: the access token is sent there, so the server cannot send it elsewhere. */ export function secureSocketFor(url: string, central: string): boolean { if (!URL.canParse(url) || !URL.canParse(central)) return false; const u = new URL(url); const c = new URL(central); if (u.hostname.toLowerCase() !== c.hostname.toLowerCase()) return false; return u.protocol === "wss:" || (u.protocol === "ws:" && isLoopbackHost(u.hostname)); }