import { Hono } from "jsr:@hono/hono@4"; import { serveStatic } from "jsr:@hono/hono@4/deno"; import { deleteCookie } from "jsr:@hono/hono@4/cookie"; import { MetadataService } from "jsr:@simplewebauthn/server@13"; import { initDb, sqlWrapper } from "./core/db.ts"; import { pingValkey, valkey } from "./core/valkey.ts"; import { contentNegotiation } from "./core/content_negotiation.ts"; import { payloadCapGuard } from "./core/auth_guards.ts"; import { startConnectRpcServer } from "./core/rpc.ts"; import { extractAllSessionIds, getAuthenticatedUser, getCookieDomain, } from "./core/session.ts"; import { isSafeRedirectUrl } from "./core/forward_auth.ts"; import { auditWrapper } from "./core/audit.ts"; import { authRoutes } from "./features/auth/routes.tsx"; import { adminRoutes } from "./features/admin/routes.tsx"; import { eventsRoutes } from "./features/events/routes.tsx"; import { sessionRoutes } from "./features/sessions/routes.tsx"; import { passRoutes } from "./features/sessions/pass_routes.ts"; import { forwardAuthRoutes } from "./features/forward_auth/routes.ts"; const app: Hono = new Hono(); app.use("*", payloadCapGuard); app.use("*", contentNegotiation()); // Serve static assets (specifically Datastar, WebAuthn scripts, and stylesheets) app.use("/public/*", serveStatic({ root: "./" })); // Root, Navigation & Logout Endpoints app.get("/", (c) => { c.header("Cache-Control", "no-store, no-cache, must-revalidate, max-age=0"); return c.redirect("/login"); }); app.get("/logout", async (c) => { const sessionIds = extractAllSessionIds(c); const rawRedirect = c.req.query("redirect"); let safeRedirect = null; const userIp = c.req.header("x-forwarded-for") || "127.0.0.1"; let userId = null; if (sessionIds.length > 0) { try { const authUser = await getAuthenticatedUser(c); if (authUser) { userId = authUser.userId; } for (const sId of sessionIds) { try { await valkey.del(sId); await sqlWrapper.sql`DELETE FROM sessions WHERE id = ${sId}`; } catch (_e) {} } } catch (_e) {} } if (rawRedirect && isSafeRedirectUrl(rawRedirect)) { safeRedirect = rawRedirect; } auditWrapper.auditLog(userId, "logout_success", "session", null, userIp); const cookieDomain = getCookieDomain(); if (cookieDomain) { deleteCookie(c, "session_id", { domain: cookieDomain, path: "/", httpOnly: true, secure: true, sameSite: "Lax", }); } deleteCookie(c, "session_id", { path: "/", httpOnly: true, secure: true, sameSite: "Lax", }); c.header("Cache-Control", "no-store, no-cache, must-revalidate, max-age=0"); return c.redirect(safeRedirect || "/login"); }); // Wire Sub-routers and Vertical Slices app.route("/pass", passRoutes); app.route("/", forwardAuthRoutes); app.route("/", authRoutes); app.route("/", eventsRoutes); app.route("/", sessionRoutes); app.route("/admin", adminRoutes); app.route("/api/admin", adminRoutes); // Workload Mesh ConnectRPC Daemon startConnectRpcServer(app); // Basic health check app.get("/healthz", (c) => c.text("OK")); if (import.meta.main) { const rpID = Deno.env.get("RP_ID"); const origin = Deno.env.get("ORIGIN"); if (!rpID || !origin) { console.warn( "[Auth-Yes] Warning: RP_ID or ORIGIN not set in environment. Falling back to defaults.", ); } console.log("[Auth-Yes] Initializing FIDO MDS3 Metadata Blob..."); try { await MetadataService.initialize(); console.log("[Auth-Yes] FIDO MDS3 Metadata Blob successfully loaded."); } catch (error) { console.warn( "[Auth-Yes] Failed to initialize FIDO MDS3 Metadata Blob (offline mode):", error, ); } console.log("[Auth-Yes] Initializing database and cache..."); await initDb(); await pingValkey(); const port = parseInt(Deno.env.get("PORT") || "8000", 10); console.log(`[Auth-Yes] Hypermedia Server running on port ${port}`); Deno.serve({ port }, app.fetch); } export default app;