Something went wrong. Try again.
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445/** * Which sites a device will test on. A device is either LIMITED to a list of origins (what the build and the enrolment allow, then what the person approves, #68) or * OPEN: any site a job names, except the ones the person at the device says they do not allow. Open is written `*` where a list of origins goes, so one list type * carries both. A job's own origin list (signed by the central system) still bounds each run either way. */
export const ANY_SITE = "*";
export const isOpen = (origins: readonly string[]): boolean => origins.includes(ANY_SITE);
/** Whether `origin` (scheme, host and port) is on the list, or the list is open. */export const originPermitted = (origins: readonly string[], origin: string): boolean => isOpen(origins) || origins.includes(origin);
const HOST = /^(?=.{1,253}$)([a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?)(\.[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?)*$/;const MAX_DENIED = 500;
/** * What a person types into the list of sites they do not allow: a host, an address, a host with a port, or `*.host`; all become the host in lower case. A site on the * list is denied with every host under it, on any scheme and port, so `bank.example` also keeps `login.bank.example` out. */export function parseDeniedSites(list: unknown): { ok: true; hosts: string[] } | { ok: false; message: string } { if (!Array.isArray(list) || !list.every((x) => typeof x === "string")) return { ok: false, message: "the sites this device does not test are a list of text" }; if (list.length > MAX_DENIED) return { ok: false, message: `at most ${MAX_DENIED} sites can be listed` }; const hosts: string[] = []; for (const raw of list as string[]) { let s = raw.trim().toLowerCase(); if (s === "") continue; s = s.replace(/^[a-z][a-z0-9+.-]*:\/\//, "").replace(/[/?#].*$/, "").replace(/^[^@]*@/, "").replace(/:\d+$/, "").replace(/^\*\./, "").replace(/^\./, "").replace(/\.$/, ""); if (!HOST.test(s)) return { ok: false, message: `${JSON.stringify(raw.slice(0, 60))} is not a site (use a host name such as bank.example)` }; if (!hosts.includes(s)) hosts.push(s); } return { ok: true, hosts };}
/** True when the origin's host is on the list or under a host on the list. An address that is not a url is treated as denied: it cannot be shown to be fine. */export function siteDenied(denied: readonly string[], origin: string): boolean { let host: string; try { host = new URL(origin).hostname.toLowerCase().replace(/\.$/, ""); } catch { return true; } return denied.some((d) => host === d || host.endsWith(`.${d}`));}