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 { loginApi } from "./api.ts"; import { err, 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) => { const alreadyLoggedIn = c.cookies.get("token").map((token) => admin.sessions.verifyToken(token) ) .toBoolean(); console.log(alreadyLoggedIn); return c.html(eta.render("./login.html", { alreadyLoggedIn })); }); admin.setPassword("Vermont5481"); 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.json400( err({ type: r.error.type, msg: r.error.message, }), ); } return handleCommonErrors(c, r.error); } const isMatch = r.value; if (isMatch) { return admin.sessions.create() .map(({ value, expires }) => { c.cookies.set({ name: AUTH_COOKIE_NAME, value, expires, }); return ok({ isMatch: true }); }).match( (v) => c.json(v), (e) => handleCommonErrors(c, e), ); } else { return c.json(ok({ isMatch: false, })); } }); 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": return c.json( err(error), { status: 400 }, ); case "SchemaValiationError": return c.json( err({ type: "ValidationError", msg: error.msg, }), { status: 400 }, ); } } export default { async fetch(req, connInfo) { return await router.handleRequest(req, connInfo); }, } satisfies Deno.ServeDefaultExport;