154 lines
3.6 KiB
TypeScript
154 lines
3.6 KiB
TypeScript
/**
|
|
* Sistema de sessão usando Redis
|
|
* Armazena informações de sessão do usuário
|
|
*/
|
|
|
|
import { getRedisClient } from "./index";
|
|
|
|
const SESSION_PREFIX = "session:";
|
|
const USER_SESSION_PREFIX = "user_session:";
|
|
const SESSION_TTL = 60 * 60 * 24 * 7; // 7 dias (mesmo que refresh token)
|
|
|
|
export interface SessionTierInfo {
|
|
subscriptionTierId: number | null;
|
|
subscriptionTierSlug: string | null;
|
|
subscriptionTierName: string | null;
|
|
subscriptionTierLevel: number | null;
|
|
}
|
|
|
|
export interface SessionData {
|
|
userId: number;
|
|
username: string;
|
|
email: string;
|
|
accessToken: string;
|
|
createdAt: number;
|
|
subscriptionTierId: number | null;
|
|
subscriptionTierSlug: string | null;
|
|
subscriptionTierName: string | null;
|
|
subscriptionTierLevel: number | null;
|
|
}
|
|
|
|
/**
|
|
* Cria ou atualiza uma sessão
|
|
*/
|
|
export async function setSession(
|
|
sessionId: string,
|
|
data: SessionData,
|
|
): Promise<void> {
|
|
try {
|
|
const client = getRedisClient();
|
|
if (!client.isOpen) {
|
|
await client.connect();
|
|
}
|
|
|
|
const key = `${SESSION_PREFIX}${sessionId}`;
|
|
await client.setEx(key, SESSION_TTL, JSON.stringify(data));
|
|
|
|
// Também armazenar referência por userId para invalidar todas as sessões
|
|
const userKey = `${USER_SESSION_PREFIX}${data.userId}`;
|
|
await client.sAdd(userKey, sessionId);
|
|
await client.expire(userKey, SESSION_TTL);
|
|
} catch (error) {
|
|
console.error("❌ Erro ao criar sessão:", error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Obtém dados de uma sessão
|
|
*/
|
|
export async function getSession(
|
|
sessionId: string,
|
|
): Promise<SessionData | null> {
|
|
try {
|
|
const client = getRedisClient();
|
|
if (!client.isOpen) {
|
|
await client.connect();
|
|
}
|
|
|
|
const key = `${SESSION_PREFIX}${sessionId}`;
|
|
const data = await client.get(key);
|
|
|
|
if (!data) {
|
|
return null;
|
|
}
|
|
|
|
return JSON.parse(data) as SessionData;
|
|
} catch (error) {
|
|
console.error("❌ Erro ao obter sessão:", error);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Remove uma sessão
|
|
*/
|
|
export async function deleteSession(sessionId: string): Promise<void> {
|
|
try {
|
|
const client = getRedisClient();
|
|
if (!client.isOpen) {
|
|
await client.connect();
|
|
}
|
|
|
|
const key = `${SESSION_PREFIX}${sessionId}`;
|
|
const data = await client.get(key);
|
|
|
|
if (data) {
|
|
const sessionData = JSON.parse(data) as SessionData;
|
|
const userKey = `${USER_SESSION_PREFIX}${sessionData.userId}`;
|
|
await client.sRem(userKey, sessionId);
|
|
}
|
|
|
|
await client.del(key);
|
|
} catch (error) {
|
|
console.error("❌ Erro ao remover sessão:", error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Remove todas as sessões de um usuário
|
|
*/
|
|
export async function deleteAllUserSessions(userId: number): Promise<void> {
|
|
try {
|
|
const client = getRedisClient();
|
|
if (!client.isOpen) {
|
|
await client.connect();
|
|
}
|
|
|
|
const userKey = `${USER_SESSION_PREFIX}${userId}`;
|
|
const sessionIds = await client.sMembers(userKey);
|
|
|
|
if (sessionIds.length > 0) {
|
|
const keys = sessionIds.map((id) => `${SESSION_PREFIX}${id}`);
|
|
await client.del(keys);
|
|
await client.del(userKey);
|
|
}
|
|
} catch (error) {
|
|
console.error("❌ Erro ao remover todas as sessões do usuário:", error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Atualiza TTL de uma sessão
|
|
*/
|
|
export async function refreshSession(sessionId: string): Promise<void> {
|
|
try {
|
|
const client = getRedisClient();
|
|
if (!client.isOpen) {
|
|
await client.connect();
|
|
}
|
|
|
|
const key = `${SESSION_PREFIX}${sessionId}`;
|
|
const exists = await client.exists(key);
|
|
|
|
if (exists) {
|
|
await client.expire(key, SESSION_TTL);
|
|
}
|
|
} catch (error) {
|
|
console.error("❌ Erro ao atualizar TTL da sessão:", error);
|
|
throw error;
|
|
}
|
|
}
|