import { createRoute, OpenAPIHono, z } from "@hono/zod-openapi"; import axios from "axios"; import { verify } from "hono/jwt"; import jwt from "jsonwebtoken"; import { authMiddleware } from "../middleware/authMiddleware.js"; const session = new OpenAPIHono(); const expiresIn = Number(process.env.JWT_EXPIRES!) || 60; const secret: string = process.env.JWT_SECRET!; const { sign } = jwt; const UserSchema = z.object({ username: z .string() .regex(/^[a-zA-Z0-9_]{3,30}$/) .openapi({ example: "smith034" }), email: z.string().email().openapi({ example: "smith@example.com" }), password: z .string() .min(6, { message: "Passwords must be longer than 3 characters" }) .regex(/[A-Z]/, { message: "Password must contain at least one uppercase letter", }) .regex(/[\W_]/, { message: "Password must contain at least one special character", }) .openapi({ example: "Password1!" }), }); const activeSessions: Record = {}; const SESSION_TIMEOUT_MS = 60 * 60 * 1000; // 1 hour session.openapi( createRoute({ tags: ["Auth"], summary: "Checks a user session based on there token", description: "Can post there via Authentiaction header or cookies", method: "get", path: "/session", middleware: authMiddleware, // request: { // body: { // content: { // "application/json": {schema: UserSchema}, // }, // }, // }, responses: { 200: { content: { "application/json": { schema: z.object({ data: z.object({ token: z.string().openapi({ example: "sdkjhgsldkvhdakl;jvhs;adkjfhvds.kvnsad;ovhads", }), // user: z.object({ // user_id: z.string().openapi({example: "04316c86-f086-4cc6-b3d4-cca164a26f3f"}), // username: z.string().openapi({example: "smith"}), // email: z.string().openapi({example: "smith@example.com"}).optional(), // }), }), }), }, }, description: "Login successful", }, 401: { content: { "application/json": { schema: z.object({ message: z.string().openapi({ example: "Unathenticated" }), }), }, }, description: "Error of why you were not logged in.", }, }, }), async (c: any) => { const cookieHeader = c.req.header("Cookie"); if (!cookieHeader) return c.json({ error: "Unauthorized" }, 401); const res = await axios.get(`${process.env.LST_BASE_URL}/api/user/me`, { headers: { Cookie: cookieHeader }, withCredentials: true, }); if (res.status === 401) return c.json({ error: "Unauthorized" }, 401); const user = res.data.user; // ── record session heartbeat ─────────────────────────────────────────── activeSessions[user.id] = { lastSeen: Date.now(), expiresAt: Date.now() + SESSION_TIMEOUT_MS, }; // clean up stale sessions in the background for (const [key, sess] of Object.entries(activeSessions)) { if (Date.now() > sess.expiresAt) delete activeSessions[key]; } const setCookie = res.headers && ((res.headers["set-cookie"] || res.headers["Set-Cookie"]) as | string[] | undefined); if (setCookie) c.header("Set-Cookie", setCookie); return c.json( { data: { token: res.data.token, user: res.data.user } }, 200, ); // const authHeader = c.req.header("Authorization"); // if (authHeader?.includes("Basic")) { // return c.json( // { message: "You are a Basic user! Please login to get a token" }, // 401 // ); // } // if (!authHeader) { // return c.json({ message: "Unauthorized" }, 401); // } // const token = authHeader?.split("Bearer ")[1] || ""; // try { // const payload = await verify(token, process.env.JWT_SECRET!); // // If it's valid, return a new token // const newToken = sign({ user: payload.user }, secret, { // expiresIn: expiresIn * 60, // }); // return c.json({ data: { token: newToken, user: payload.user } }, 200); // } catch (error) { // return c.json({ message: "Unauthorized" }, 401); // } }, ); // const token = authHeader?.split("Bearer ")[1] || ""; // try { // const payload = await verify(token, process.env.JWT_SECRET!); // //console.log(payload); // //return c.json({data: {token, user: payload.user}}, 200); // return c.json({message: "something"}); // } catch (err) { // return c.json({error: "Invalid or expired token"}, 401); // } // }); export default session;