pi-mono/apps/p2/plugins/artifacts/server.ts
Mario Zechner 05dc8d239d feat: add apps/p2 (imported from pi-private at 7dadff697)
p2 (Pi Mobile on Chord v2) moves from pi-private into pi as one commit. Root scripts that loop all workspaces
use --if-present; npm test, ./test.sh and the release script cover packages/* only (p2: cd apps/p2 && npm test);
sync-versions also updates apps' workspace pins.
2026-11-03 13:39:06 +00:00

60 lines
2.9 KiB
TypeScript

import { canView, contribute, defineFacet } from "@p2/app/v1";
import { type RouteHandler, Routes, Server } from "@p2/app/v1/server";
import { Catalog } from "../sessions/contract.ts";
import { ArtifactError, Artifacts, instrumentArtifact } from "./store.ts";
const EXECUTABLE_CSP =
"default-src 'none'; script-src 'unsafe-inline' 'wasm-unsafe-eval' https:; style-src 'unsafe-inline' https:; img-src data: blob: https:; font-src data: https:; media-src data: blob: https:; connect-src https:; worker-src blob:; frame-src 'none'; object-src 'none'; base-uri 'none'; form-action 'none'; frame-ancestors 'self'; sandbox allow-scripts allow-modals allow-pointer-lock";
const DOCUMENT_CSP = "default-src 'none'; base-uri 'none'; form-action 'none'; frame-ancestors 'self'; sandbox";
export default defineFacet((host) => {
contribute(host, "p2.artifact-routes", (self) => {
const server = self.get(Server, {});
const catalog = self.get(Catalog, {});
const artifacts = self.open(
async () => new Artifacts(server.info.value.dataDir),
() => {},
);
const serve: RouteHandler = async (request, response, { principal }, ctx) => {
const query = new URL(request.url ?? "/", "http://localhost").searchParams;
const session = query.get("session") ?? "";
if (!canView(principal, session) || request.headers["sec-fetch-site"] === "cross-site") {
response.writeHead(403);
response.end("Forbidden");
return;
}
try {
await catalog.get({ id: session }, ctx);
const artifact = await artifacts.value.read(session, query.get("name") ?? "", Number(query.get("version")));
const download = query.get("download") === "1";
const executable = artifact.info.type === "html" || artifact.info.type === "svg";
const body = Buffer.from(
executable && !download ? instrumentArtifact(artifact.info, artifact.content) : artifact.content,
"utf8",
);
const extension =
artifact.info.type === "markdown" ? "md" : artifact.info.type === "text" ? "txt" : artifact.info.type;
response.writeHead(200, {
"Content-Security-Policy": executable ? EXECUTABLE_CSP : DOCUMENT_CSP,
"Content-Type":
artifact.info.type === "html"
? "text/html; charset=utf-8"
: artifact.info.type === "svg"
? "image/svg+xml; charset=utf-8"
: "text/plain; charset=utf-8",
"Content-Length": body.byteLength,
"Content-Disposition": download ? `attachment; filename="${artifact.info.name}.${extension}"` : "inline",
"Cross-Origin-Resource-Policy": "same-origin",
});
response.end(request.method === "HEAD" ? undefined : body);
} catch (error) {
if (response.headersSent) response.destroy();
else {
response.writeHead(error instanceof ArtifactError ? error.status : 404);
response.end("Artifact not found");
}
}
};
self.contribute(Routes, { "GET /artifact": serve, "HEAD /artifact": serve });
});
});