| 123456789101112131415161718192021222324252627282930313233 |
- 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 }
- }
|