Files
ThothII/backend/src/routes/pi-management.ts
T

43 lines
1.6 KiB
TypeScript

import type { FastifyInstance, FastifyReply, FastifyRequest } from "fastify";
import {
isPrincipalContext,
requirePermission,
requireSameOriginOrNonBrowser,
} from "../auth/authorization.js";
import { PiManagementError, type PiManagementService } from "../pi/management.js";
export function piManagementRoutes(
app: FastifyInstance,
deps: { service: PiManagementService },
): void {
app.get("/pi-management/status", async (request, reply) => run(request, reply, deps, () => deps.service.status()));
app.post("/pi-management/test", async (request, reply) => run(request, reply, deps, () => deps.service.test()));
app.get("/pi-management/logs", async (request, reply) => run(request, reply, deps, () => deps.service.logs()));
}
async function run<T>(
request: FastifyRequest,
reply: FastifyReply,
deps: { service: PiManagementService },
action: () => Promise<T>,
): Promise<T | FastifyReply> {
const principal = requirePermission(request, reply, "pi.manage");
if (!isPrincipalContext(principal)) return principal;
if (principal.issuer === "local" && isWrite(request.method)) {
const csrfDenied = requireSameOriginOrNonBrowser(request, reply);
if (csrfDenied) return csrfDenied;
}
try {
return await action();
} catch (error) {
if (error instanceof PiManagementError) {
return reply.code(503).send({ code: error.code, error: error.message });
}
return reply.code(503).send({ code: "pi_management_unavailable", error: "Pi management is unavailable" });
}
}
function isWrite(method: string): boolean {
return method === "POST" || method === "PUT" || method === "PATCH" || method === "DELETE";
}