import { randomBytes } from 'crypto' import { RedisGenericManager } from './redisGenericManager' class RedisSessions extends RedisGenericManager { /** * Generates a random session ID */ private generateSessionId(): string { return randomBytes(32).toString('hex') } /** * Creates a new session for a user * @param userSecretTokenHash The ID of the user * @returns The generated session ID */ async createSession(userSecretTokenHash: string): Promise { const sessionId = this.generateSessionId() // Store the session with user ID await this.redisClient.set(`session:${sessionId}`, userSecretTokenHash, { EX: this.expirationTime, }) // Store session ID in user's sessions set await this.redisClient.sAdd(`user:${userSecretTokenHash}:sessions`, sessionId) return sessionId } /** * Gets the user ID associated with a session * @param sessionId The session ID to look up * @returns The user ID or null if session not found */ async getUserBySessionId(sessionId: string): Promise { const userSecretTokenHash = await this.redisClient.get(`session:${sessionId}`) return userSecretTokenHash } /** * Deletes all sessions for a user * @param userSecretTokenHash The ID of the user whose sessions should be deleted */ async deleteUserSessions(userSecretTokenHash: string): Promise { // Get all session IDs for the user const sessionIds = await this.redisClient.sMembers(`user:${userSecretTokenHash}:sessions`) if (sessionIds.length > 0) { // Delete each session // Delete sessions one by one to avoid type issues with spread operator for (const sessionId of sessionIds) { await this.redisClient.del(`session:${sessionId}`) } // Delete the set of user's sessions await this.redisClient.del(`user:${userSecretTokenHash}:sessions`) } } /** * Deletes a specific session * @param sessionId The session ID to delete */ async deleteSession(sessionId: string): Promise { const userSecretTokenHash = await this.getUserBySessionId(sessionId) if (userSecretTokenHash) { await this.redisClient.del(`session:${sessionId}`) await this.redisClient.sRem(`user:${userSecretTokenHash}:sessions`, sessionId) } } } export const redisSessions = await RedisSessions.createAndConnect({ expirationTime: 60 * 60 * 24, // 24 hours in seconds })