26 lines
1.9 KiB
JavaScript
26 lines
1.9 KiB
JavaScript
export const SERVER_JOB_NETWORK_POLICY_SCHEMA = 1;
|
|
|
|
function normalizeOrigin(value) {
|
|
if (typeof value !== "string" || value.length > 2048) throw new Error("SERVER_NETWORK_POLICY_INVALID: origin is invalid");
|
|
let url;
|
|
try { url = new URL(value); } catch { throw new Error("SERVER_NETWORK_POLICY_INVALID: origin is invalid"); }
|
|
if (url.username || url.password || url.pathname !== "/" || url.search || url.hash) throw new Error("SERVER_NETWORK_POLICY_INVALID: origin is not canonical");
|
|
if (url.protocol !== "https:" && !(url.protocol === "http:" && ["127.0.0.1", "localhost", "::1"].includes(url.hostname))) throw new Error("SERVER_NETWORK_POLICY_DENIED: origin must be HTTPS or loopback");
|
|
return url.origin;
|
|
}
|
|
|
|
export function parseServerJobNetworkPolicy(value) {
|
|
if (!value || typeof value !== "object" || value.schemaVersion !== SERVER_JOB_NETWORK_POLICY_SCHEMA || !Array.isArray(value.allowedOrigins)) throw new Error("SERVER_NETWORK_POLICY_INVALID: schema is unsupported");
|
|
const origins = [...new Set(value.allowedOrigins.map(normalizeOrigin))].sort();
|
|
if (origins.length > 64) throw new Error("SERVER_NETWORK_POLICY_INVALID: origin count exceeds budget");
|
|
return Object.freeze({ schemaVersion: SERVER_JOB_NETWORK_POLICY_SCHEMA, defaultNetwork: "DENY", allowedOrigins: origins });
|
|
}
|
|
|
|
export function resolveServerJobNetwork(policyValue, requestedOrigin) {
|
|
const policy = parseServerJobNetworkPolicy(policyValue);
|
|
if (requestedOrigin === undefined || requestedOrigin === null) return Object.freeze({ status: "DENIED", code: "SERVER_NETWORK_DENIED", origin: null, network: "DISABLED" });
|
|
const origin = normalizeOrigin(requestedOrigin);
|
|
if (!policy.allowedOrigins.includes(origin)) return Object.freeze({ status: "DENIED", code: "SERVER_NETWORK_DENIED", origin, network: "DISABLED" });
|
|
return Object.freeze({ status: "ALLOWED", code: "SERVER_NETWORK_ALLOWED_ORIGIN", origin, network: "DECLARED_ORIGIN" });
|
|
}
|