import HttpRouter from "@lib/router.ts"; import { Eta } from "@eta-dev/eta"; import { serveFile } from "jsr:@std/http/file-server"; import rateLimitMiddleware from "@src/middleware/rateLimiter.ts"; import authMiddleware from "@src/middleware/auth.ts"; import loggerMiddleware from "@src/middleware/logger.ts"; import { SchemaValidationError, z } from "@shared/utils/validator.ts"; import { Api } from "@src/lib/apiValidator.ts"; import { loginApi } from "./api.ts"; import { err, getMessageFromError, ok } from "@shared/utils/result.ts"; import admin from "@src/lib/admin.ts"; import { FailedToParseRequestAsJSON, QueryExecutionError, } from "@src/lib/errors.ts"; import { Context } from "@src/lib/context.ts"; const AUTH_COOKIE_NAME = "token"; const router = new HttpRouter(); const views = Deno.cwd() + "/views/"; const eta = new Eta({ views }); router.use(loggerMiddleware); router.use(rateLimitMiddleware); router.use(authMiddleware); const cache: Map = new Map(); router.get("/public/*", async (c) => { const filePath = "." + c.path; //const cached = cache.get(filePath); // //if (cached) { // return cached.clone(); //} const res = await serveFile(c.req, filePath); //cache.set(filePath, res.clone()); return res; }); router .get(["", "/index.html"], (c) => { return c.html(eta.render("./index.html", {})); }) .get(["/login", "/login.html"], (c) => { return c.html(eta.render("./login.html", {})); }); const schema = { req: z.obj({ password: z.string().max(1024), }), res: z.result(z.void(), z.string()), }; router.api(loginApi, async (c) => { const r = await c .parseBody() .andThenAsync( ({ password }) => admin.verifyPassword(password), ); if (r.isErr()) { if (r.error.type === "AdminPasswordNotSetError") { return c.json( err({ type: r.error.type, msg: r.error.message, }), ); } return handleCommonErrors(c, r.error); } return admin.sessions.create() .map(({ value, expires }) => { c.cookies.set({ name: AUTH_COOKIE_NAME, value, expires, }); return ok(); }).match( () => c.json(ok()), (e) => handleCommonErrors(c, e), ); }); function handleCommonErrors( c: Context, error: | QueryExecutionError | FailedToParseRequestAsJSON | SchemaValidationError, ): Response { switch (error.type) { case "QueryExecutionError": return c.json( err(new QueryExecutionError("Server failed to execute query")), { status: 500 }, ); case "FailedToParseRequestAsJSON": case "SchemaValiationError": return c.json( err(error), { status: 400 }, ); } } export default { async fetch(req, connInfo) { return await router.handleRequest(req, connInfo); }, } satisfies Deno.ServeDefaultExport;