nexus / scripts /browser-guard.mjs
betterwithage's picture
deploy(hf): sync szl-holdings/nexus@00edebc993282efd5b43b0144b3d3d27ab43e264 derived COPY set
31b3c47 verified
Raw History Blame Contribute Delete
1.72 kB
/**
* Target checks shared by the Playwright capture scripts.
*
* Both run Chromium with `--no-sandbox` as root and take their URL and output
* path from argv, so unchecked they will render `file:///root/.grok/auth.json`
* into a PNG the agent can read, and write it anywhere.
*/
import { resolve, sep } from "node:path";
const LOOPBACK_HOSTNAMES = new Set(["127.0.0.1", "localhost", "::1", "[::1]"]);
/** http/https loopback only, else exit 1. `BROWSER_ALLOW_EXTERNAL_HOST=1` opts out. */
export function checkedUrl(url) {
let parsed;
try {
parsed = new URL(url);
} catch {
fail(`not a valid URL: ${url}`);
}
// Rules out file:, data:, chrome:, view-source:.
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
fail(`only http/https URLs are allowed, got ${parsed.protocol} in ${url}`);
}
if (!LOOPBACK_HOSTNAMES.has(parsed.hostname) && process.env.BROWSER_ALLOW_EXTERNAL_HOST !== "1") {
fail(
`${parsed.hostname} is not a loopback host; these scripts screenshot the ` +
`local dev server. Set BROWSER_ALLOW_EXTERNAL_HOST=1 to override.`,
);
}
return url;
}
/** Absolute `target` if it is strictly inside `allowedDirs`, else exit 1. */
export function checkedOutputPath(target, allowedDirs, label = "screenshot") {
// Resolve first so `..` cannot slip past the prefix check.
const abs = resolve(target);
const allowed = allowedDirs.some((dir) => abs.startsWith(dir.endsWith(sep) ? dir : dir + sep));
if (!allowed) {
fail(`${label} path must be under ${allowedDirs.join(" or ")}, got ${abs}`);
}
return abs;
}
function fail(message) {
console.error(JSON.stringify({ ok: false, error: message }, null, 2));
process.exit(1);
}