// Which endpoints the room page takes from outside its own code: a relay, a room service, a // fixture or an issuer directory its query string names, and the URI a relay's GOAWAY moves // the session to. A page that took any of them as given could be pointed, by a link, at // another origin, and a visitor who joined from it would send their camera and microphone // there. So an endpoint is taken only when it is the page's own origin: `https://`, or `wss://` for a relay. A page served from the loopback interface // (a fixture page, or the end-to-end harness, whose relays and services listen on other // loopback ports) takes a loopback endpoint, and nothing else. /** The host names of the loopback interface, as `URL.hostname` writes them. */ export const LOOPBACK_HOSTS = ["localhost", "127.0.0.1", "[::1]"]; export function isLoopback(hostname) { return LOOPBACK_HOSTS.includes(hostname); } /** * Whether the page at `page` (a URL, or `location`) takes `value` as an endpoint of `kind`: * "http" for a fetch or a WebTransport session, "ws" for a WebSocket relay. A relative value * is resolved against the page. Returns `{ ok: true, url }` with the endpoint in full, or * `{ ok: false, reason }`. */ export function checkEndpoint(value, kind, page) { const p = new URL(String(page)); let u; try { u = new URL(String(value), p.href); } catch { return { ok: false, reason: "not a URL" }; } const schemes = kind === "ws" ? ["wss:", "ws:"] : ["https:", "http:"]; if (!schemes.includes(u.protocol)) return { ok: false, reason: `the scheme ${u.protocol} is not a ${kind === "ws" ? "WebSocket" : "web"} endpoint's` }; // User information before a host reads as a host to a person and names none: never taken. if (u.username || u.password) return { ok: false, reason: "it carries user information" }; if (isLoopback(p.hostname)) { return isLoopback(u.hostname) ? { ok: true, url: u.href } : { ok: false, reason: `a loopback page takes only loopback endpoints, not ${u.host}` }; } const secure = kind === "ws" ? "wss:" : "https:"; if (p.protocol !== "https:" || u.protocol !== secure || u.host !== p.host) return { ok: false, reason: `${u.protocol}//${u.host} is not this page's origin` }; return { ok: true, url: u.href }; } /** The kind of endpoint a URI is by its scheme: "ws" for ws: and wss:, else "http". */ export function kindOf(value) { return /^wss?:/i.test(String(value)) ? "ws" : "http"; }