78 lines
2.3 KiB
TypeScript
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' });
|
|
}
|
|
}
|