hpcompaq435/accessaudit-scanner
0
1import { createServer, type IncomingMessage } from "node:http";2import { scanUrl } from "./scanner.js";3import { remediateAll } from "./remediate.js";4import { renderReportPdf, type ReportInput } from "./report.js";5 6const PORT = Number(process.env.PORT ?? 8080);7/** Optional shared secret so only your web app can call this worker. */8const API_KEY = process.env.SCANNER_API_KEY;9 10function readJson(req: IncomingMessage): Promise<Record<string, unknown>> {11 return new Promise((resolve, reject) => {12 let raw = "";13 req.on("data", (c) => {14 raw += c;15 if (raw.length > 1_000_000) reject(new Error("body too large"));16 });17 req.on("end", () => {18 try {19 resolve(raw ? JSON.parse(raw) : {});20 } catch {21 reject(new Error("invalid JSON body"));22 }23 });24 req.on("error", reject);25 });26}27 28const server = createServer(async (req, res) => {29 const json = (code: number, body: unknown) => {30 res.writeHead(code, { "content-type": "application/json" });31 res.end(JSON.stringify(body));32 };33 34 if (req.method === "GET" && req.url === "/health") return json(200, { ok: true });35 36 if (req.method === "POST" && req.url === "/scan") {37 if (API_KEY && req.headers["x-api-key"] !== API_KEY) {38 return json(401, { error: "unauthorized" });39 }40 try {41 const body = await readJson(req);42 const url = typeof body.url === "string" ? body.url : "";43 if (!/^https?:\/\//.test(url)) return json(400, { error: "valid url required" });44 45 const scan = await scanUrl(url);46 const violations = await remediateAll(scan.violations);47 return json(200, { ...scan, violations });48 } catch (e) {49 console.error("scan failed:", e);50 return json(500, { error: e instanceof Error ? e.message : String(e) });51 }52 }53 54 if (req.method === "POST" && req.url === "/report") {55 if (API_KEY && req.headers["x-api-key"] !== API_KEY) {56 return json(401, { error: "unauthorized" });57 }58 try {59 const body = await readJson(req);60 const report = body.report as ReportInput | undefined;61 if (!report || typeof report.url !== "string") {62 return json(400, { error: "report object required" });63 }64 const pdf = await renderReportPdf(report, {65 orgName: typeof body.orgName === "string" ? body.orgName : undefined,66 contactEmail:67 typeof body.contactEmail === "string" ? body.contactEmail : undefined,68 });69 res.writeHead(200, {70 "content-type": "application/pdf",71 "content-disposition": 'attachment; filename="accessaudit-report.pdf"',72 });73 return res.end(pdf);74 } catch (e) {75 console.error("report failed:", e);76 return json(500, { error: e instanceof Error ? e.message : String(e) });77 }78 }79 80 return json(404, { error: "not found" });81});82 83server.listen(PORT, () => console.log(`AccessAudit scanner listening on :${PORT}`));84 