feat(selfhost): start full updates from administration
This commit is contained in:
38
backend/src/routes/selfhostUpdates.ts
Normal file
38
backend/src/routes/selfhostUpdates.ts
Normal file
@@ -0,0 +1,38 @@
|
||||
import type { FastifyInstance } from "fastify";
|
||||
import { applyBody, checkBody, createUpdaterClient, requestId, UpdaterError } from "../modules/selfhost-updater";
|
||||
import { requireSystemAdmin } from "../utils/requireSystemAdmin";
|
||||
import { getBuildInfo } from "../utils/buildInfo";
|
||||
|
||||
export default async function selfhostUpdateRoutes(server: FastifyInstance, options: { client?: ReturnType<typeof createUpdaterClient> }) {
|
||||
const client = options.client || createUpdaterClient();
|
||||
server.addHook("preHandler", async (req, reply) => {
|
||||
reply.header("Cache-Control", "no-store");
|
||||
await requireSystemAdmin(server, req, reply);
|
||||
});
|
||||
const forward = async (reply: any, method: "GET" | "POST", path: string, body?: unknown) => {
|
||||
try {
|
||||
const result = await client(method, path, body);
|
||||
return reply.code(result.status).send(path === "/v1/status"
|
||||
? { ...result.body as object, backend: getBuildInfo() } : result.body);
|
||||
} catch (error) {
|
||||
const safe = error instanceof UpdaterError ? error : new UpdaterError("UPDATER_UNAVAILABLE");
|
||||
return reply.code(safe.status).send({ error: { code: safe.code, message: safe.message } });
|
||||
}
|
||||
};
|
||||
server.get("/admin/updates/status", async (_req, reply) => forward(reply, "GET", "/v1/status"));
|
||||
server.get<{ Params: { id: string } }>("/admin/updates/requests/:id", async (req, reply) => {
|
||||
if (!requestId.safeParse(req.params.id).success) return reply.code(400).send({ error: { code: "INVALID_REQUEST" } });
|
||||
return forward(reply, "GET", `/v1/requests/${req.params.id}`);
|
||||
});
|
||||
for (const command of ["check", "apply"] as const) {
|
||||
server.post(`/admin/updates/${command}`, { bodyLimit: 4096 }, async (req, reply) => {
|
||||
// The auth plugin verifies this JWT. Cookies alone cannot trigger host operations (CSRF).
|
||||
if (!/^Bearer \S{11,}$/.test(req.headers.authorization || "")) {
|
||||
return reply.code(403).send({ error: { code: "BEARER_REQUIRED", message: "Bitte erneut anmelden." } });
|
||||
}
|
||||
const parsed = (command === "apply" ? applyBody : checkBody).safeParse(req.body);
|
||||
if (!parsed.success) return reply.code(400).send({ error: { code: "INVALID_REQUEST" } });
|
||||
return forward(reply, "POST", `/v1/${command}`, parsed.data);
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user