Files
website/src/util/session.ts
2025-10-13 21:04:21 +02:00

78 lines
2.3 KiB
TypeScript

import type { AstroCookies, AstroCookieSetOptions } from 'astro';
import { ActionError } from 'astro:actions';
import crypto from 'node:crypto';
import { Permissions } from './permissions.ts';
import { ADMIN_COOKIE } from 'astro:env/server';
export class Session {
static readonly #cookieOptions: AstroCookieSetOptions = {
httpOnly: true,
path: '/',
sameSite: 'lax'
};
static #sessions: Session[] = [];
readonly sessionId: string;
readonly adminId: number;
readonly permissions: Permissions;
private constructor(sessionId: string, adminId: number, permissions: Permissions) {
this.sessionId = sessionId;
this.adminId = adminId;
this.permissions = permissions;
Session.#sessions.push(this);
}
invalidate(cookies?: AstroCookies) {
for (let i = 0; i < Session.#sessions.length; i++) {
if (Session.#sessions[i] == this) {
Session.#sessions = Session.#sessions.splice(i, 1);
if (cookies) cookies.delete(ADMIN_COOKIE, Session.#cookieOptions);
break;
}
}
}
static newSession(adminId: number, permissions: Permissions, cookies: AstroCookies) {
const session = new Session(crypto.randomBytes(16).toString('hex'), adminId, permissions);
Session.#sessions.push(session);
cookies.set(ADMIN_COOKIE, session.sessionId, Session.#cookieOptions);
return session;
}
static sessionFromCookies(cookies: AstroCookies, neededPermissions?: Permissions) {
const sessionId = cookies.get(ADMIN_COOKIE);
if (!sessionId) return null;
for (const session of Session.#sessions) {
if (session.sessionId == sessionId.value) {
if (neededPermissions && !session.permissions.hasPermissions(neededPermissions)) {
break;
}
return session;
}
}
return null;
}
static actionSessionFromCookies(cookies: AstroCookies, neededPermissions?: Permissions) {
const sessionId = cookies.get(ADMIN_COOKIE);
if (!sessionId) throw new ActionError({ code: 'UNAUTHORIZED' });
for (const session of Session.#sessions) {
if (session.sessionId == sessionId.value) {
if (neededPermissions && !session.permissions.hasPermissions(neededPermissions)) {
throw new ActionError({ code: 'UNAUTHORIZED' });
}
return session;
}
}
throw new ActionError({ code: 'UNAUTHORIZED' });
}
}