import type { IncomingHttpHeaders } from "node:http"; const SENSITIVE_RESPONSE_HEADERS = new Set(["clear-site-data", "set-cookie", "set-cookie2"]); const SCREEN_SANDBOX = "sandbox allow-scripts allow-pointer-lock"; /** Screen listeners are untrusted even when their capability URL is opened outside an iframe. */ export function safeScreenProxyResponseHeaders(headers: IncomingHttpHeaders) { const safe: IncomingHttpHeaders = {}; const policies: string[] = []; for (const [key, value] of Object.entries(headers)) { const name = key.toLowerCase(); if (value == null || name.startsWith(":") || SENSITIVE_RESPONSE_HEADERS.has(name)) continue; if (name === "content-security-policy") { policies.push(...(Array.isArray(value) ? value : [value])); } else { safe[name] = value; } } // Separate CSP policies intersect. An upstream allow-same-origin cannot relax this sandbox, // and existing provider restrictions (including frame-ancestors) remain in force. safe["content-security-policy"] = [...policies, SCREEN_SANDBOX]; // Module imports from the opaque sandbox origin still need access to noVNC assets. safe["access-control-allow-origin"] = "*"; return safe; } export function stripSensitiveHandshakeHeaders(response: Buffer) { const end = response.indexOf("\r\n\r\n"); if (end < 0) return null; const lines = response.subarray(0, end).toString("latin1").split("\r\n"); const safeLines = lines.filter((line, index) => { if (index === 0) return true; const separator = line.indexOf(":"); const name = separator < 0 ? line : line.slice(0, separator); return !SENSITIVE_RESPONSE_HEADERS.has(name.trim().toLowerCase()); }); return Buffer.concat([ Buffer.from(`${safeLines.join("\r\n")}\r\n\r\n`, "latin1"), response.subarray(end + 4), ]); }