this repo has no description
1import { Hono } from "hono";
2import { serveStatic } from "hono/bun";
3import { getCookie, setCookie, deleteCookie } from "hono/cookie";
4import { authRoutes } from "./routes/auth";
5import { publicationRoutes } from "./routes/publication";
6import { documentRoutes } from "./routes/documents";
7import { layout } from "./views/layouts/main";
8import { homePage } from "./views/home";
9import { getSession } from "./lib/session";
10import { getClientMetadata, getJwks } from "./lib/oauth";
11import { csrfProtection, getCSRFToken } from "./lib/csrf";
12import type { AppVariables } from "./types";
13
14export const app = new Hono<{ Variables: AppVariables }>();
15
16// Static files
17app.use("/public/*", serveStatic({ root: "./" }));
18
19// OAuth metadata endpoints at root level
20// These MUST be publicly accessible (no authentication)
21app.get("/client-metadata.json", async (c) => {
22 try {
23 const metadata = await getClientMetadata();
24 // Set appropriate cache headers
25 c.header("Cache-Control", "public, max-age=600"); // Cache for 10 minutes
26 c.header("Access-Control-Allow-Origin", "*");
27 return c.json(metadata);
28 } catch (error) {
29 console.error("Error getting client metadata:", error);
30 return c.json({ error: "Failed to get client metadata" }, 500);
31 }
32});
33
34app.get("/jwks.json", async (c) => {
35 try {
36 const jwks = await getJwks();
37 // Set appropriate cache headers
38 c.header("Cache-Control", "public, max-age=600"); // Cache for 10 minutes
39 c.header("Access-Control-Allow-Origin", "*");
40 return c.json(jwks);
41 } catch (error) {
42 console.error("Error getting JWKS:", error);
43 return c.json({ error: "Failed to get JWKS" }, 500);
44 }
45});
46
47// Session middleware - adds session and CSRF token to context
48app.use("*", async (c, next) => {
49 const session = await getSession(c);
50 c.set("session", session);
51 // Generate CSRF token for all requests (sets cookie if not present)
52 const csrfToken = getCSRFToken(c);
53 c.set("csrfToken", csrfToken);
54 await next();
55});
56
57// CSRF protection for state-changing requests
58// Applied after session middleware but before routes
59app.use("/auth/*", csrfProtection);
60app.use("/publication/*", csrfProtection);
61app.use("/documents/*", csrfProtection);
62
63// Home page
64app.get("/", async (c) => {
65 const session = c.get("session");
66 return c.html(layout(homePage(session), { session }));
67});
68
69// Mount routes
70app.route("/auth", authRoutes);
71app.route("/publication", publicationRoutes);
72app.route("/documents", documentRoutes);
73
74const port = parseInt(process.env.PORT || "8000");
75console.log(`Starting server on http://localhost:${port}`);
76console.log(
77 `Public URL: ${process.env.PUBLIC_URL || "http://localhost:" + port}`,
78);
79
80export default {
81 port,
82 fetch: app.fetch,
83};