import { randomBytes } from "node:crypto" import { softwareReviewHTML } from "./software-review-ui" import { softwareDashboardHTML } from "./software-dashboard-ui" import { requestJSON, type Connection } from "./agentpaas" // Credentials never enter the page. This explicit operator UI is bound to one // review, with Host/Origin/CSRF checks and no general-purpose forwarding route. export function startSoftwareReviewPanel(config: Connection, reviewID: string, port = 0, mode: "review" | "dashboard" = "review") { if (!/^[a-f0-9]{32}$/.test(reviewID)) throw new Error("无效审阅编号") const token = randomBytes(32).toString("hex") const server = Bun.serve({ hostname: "127.0.0.1", port, async fetch(req, server) { const origin = `http://127.0.0.1:${server.port}` const route = new URL(req.url).pathname const headers = { "Cache-Control": "no-store", "X-Content-Type-Options": "nosniff", "Referrer-Policy": "no-referrer" } if (req.headers.get("host") !== `127.0.0.1:${server.port}`) return new Response("Forbidden", { status: 403 }) if (req.method === "GET" && route === "/") return new Response(mode === "dashboard" ? softwareDashboardHTML(token) : softwareReviewHTML(token), { headers: { ...headers, "Content-Type": "text/html; charset=utf-8", "Content-Security-Policy": "default-src 'none'; script-src 'unsafe-inline'; style-src 'unsafe-inline'; connect-src 'self'; frame-ancestors 'none'; base-uri 'none'" } }) if (req.headers.get("X-Review-Token") !== token || (req.method !== "GET" && req.headers.get("origin") !== origin)) return Response.json({ error: "Forbidden" }, { status: 403 }) if (mode === "dashboard" && req.method !== "GET") return new Response("Read only", { status: 405, headers }) const suffix = route === "/api/review" && req.method === "GET" ? "" : route === "/api/evidence" && req.method === "GET" ? "/evidence" : route === "/api/evidence-text" && req.method === "GET" ? "/evidence-text" + new URL(req.url).search : route === "/api/selection" && req.method === "POST" ? "/selection" : route === "/api/execute" && req.method === "POST" ? "/execute" : route === "/api/reopen" && req.method === "POST" ? "/reopen" : undefined if (suffix === undefined) return new Response("Not found", { status: 404 }) try { const body = req.method === "POST" ? await req.text() : undefined if (body && body.length > 64000) return new Response("Too large", { status: 413 }) return Response.json(await requestJSON(config, `/software-reviews/${reviewID}${suffix}`, new AbortController().signal, { method: req.method, headers: { "Content-Type": "application/json" }, body }), { headers }) } catch (error) { return Response.json({ error: error instanceof Error ? error.message : "读取失败" }, { status: 502, headers }) } }, }) return { url: `http://127.0.0.1:${server.port}/`, server } }