/** * Session model for Stack.Gallery Registry */ import * as plugins from '../plugins.ts'; import type { ISession } from '../interfaces/auth.interfaces.ts'; import { db } from './db.ts'; @plugins.smartdata.Collection(() => db) export class Session extends plugins.smartdata.SmartDataDbDoc implements ISession { @plugins.smartdata.unI() public id: string = ''; @plugins.smartdata.svDb() @plugins.smartdata.index() public userId: string = ''; @plugins.smartdata.svDb() public userAgent: string = ''; @plugins.smartdata.svDb() public ipAddress: string = ''; @plugins.smartdata.svDb() @plugins.smartdata.index() public isValid: boolean = true; @plugins.smartdata.svDb() public invalidatedAt?: Date; @plugins.smartdata.svDb() public invalidatedReason?: string; @plugins.smartdata.svDb() public lastActivityAt: Date = new Date(); @plugins.smartdata.svDb() @plugins.smartdata.index() public createdAt: Date = new Date(); /** * Create a new session */ public static async createSession(data: { userId: string; userAgent: string; ipAddress: string; }): Promise { const session = new Session(); session.id = await Session.getNewId(); session.userId = data.userId; session.userAgent = data.userAgent; session.ipAddress = data.ipAddress; session.isValid = true; session.lastActivityAt = new Date(); session.createdAt = new Date(); await session.save(); return session; } /** * Find valid session by ID */ public static async findValidSession(sessionId: string): Promise { const session = await Session.getInstance({ id: sessionId, isValid: true, }); if (!session) return null; // Check if session is expired (7 days) const maxAge = 7 * 24 * 60 * 60 * 1000; if (Date.now() - session.createdAt.getTime() > maxAge) { await session.invalidate('expired'); return null; } return session; } /** * Get all valid sessions for a user */ public static async getUserSessions(userId: string): Promise { return await Session.getInstances({ userId, isValid: true, }); } /** * Invalidate all sessions for a user */ public static async invalidateAllUserSessions( userId: string, reason: string = 'logout_all' ): Promise { const sessions = await Session.getUserSessions(userId); for (const session of sessions) { await session.invalidate(reason); } return sessions.length; } /** * Invalidate this session */ public async invalidate(reason: string): Promise { this.isValid = false; this.invalidatedAt = new Date(); this.invalidatedReason = reason; await this.save(); } /** * Update last activity */ public async touchActivity(): Promise { this.lastActivityAt = new Date(); await this.save(); } /** * Lifecycle hook */ public async beforeSave(): Promise { if (!this.id) { this.id = await Session.getNewId(); } } }