/** * Copyright (C) 2026 SofĂ­a Aritz and contributors * * This file is part of Everest. * * Everest is free software: you can redistribute it and/or modify it under the * terms of the GNU General Public License as published by the Free Software * Foundation, either version 3 of the License, or (at your option) any later * version. * * Everest is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A * PARTICULAR PURPOSE. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along with * Everest. If not, see . */ import { jwtVerify, SignJWT } from "jose"; import { type SerializeOptions } from "cookie"; const sessionSecret = process.env.SESSION_SECRET; if (!sessionSecret) throw new Error("Environment variable SESSION_SECRET is required"); const encodedSecret = new TextEncoder().encode(sessionSecret); const ALGORITHM = "HS256"; const COOKIE_NAME = "session"; interface CookieListItem extends Pick< SerializeOptions, "domain" | "path" | "sameSite" | "secure" > { name: string; value: string; expires?: SerializeOptions["expires"] | number; } type ResponseCookie = CookieListItem & Pick; interface CookieStore { get: (name: string) => { name: string; value: string } | undefined; set: { (name: string, value: string, cookie?: Partial): void; (options: ResponseCookie): void; }; delete: (name: string) => void; } export type SessionPayload = { did: string; }; export async function setStoredSession(payload: SessionPayload, cookies: CookieStore) { const jwt = await new SignJWT({ ...payload }) .setProtectedHeader({ alg: ALGORITHM }) .setIssuedAt() .setExpirationTime("7d") .sign(encodedSecret); cookies.set(COOKIE_NAME, jwt, { httpOnly: true, secure: process.env.NODE_ENV === "production", sameSite: "lax", maxAge: 60 * 60 * 24 * 7, // 1 week path: "/", }); } export async function getStoredSession(cookies: CookieStore) { try { const session = cookies.get(COOKIE_NAME)?.value; if (!session) return null; const { payload } = await jwtVerify(session, encodedSecret, { algorithms: [ALGORITHM], }); return payload as unknown as SessionPayload; } catch (error) { console.error("Failed to verify session", error); return null; } } export function deleteSession(cookies: CookieStore) { cookies.delete(COOKIE_NAME); }