/**
* 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);
}