31 lines
1.4 KiB
TypeScript
31 lines
1.4 KiB
TypeScript
import { eq } from 'drizzle-orm';
|
||
import { db } from '../db';
|
||
import { userSessions } from '@shared/schema';
|
||
|
||
/**
|
||
* Проверка отзыва сессии (user_sessions.is_revoked) для access-токенов с claim sid.
|
||
* In-memory кэш ~30 сек: неизменный ответ не дёргает БД на каждый запрос,
|
||
* отозванная сессия умирает в течение ~30 секунд на всех инстансах приложения.
|
||
*/
|
||
const CACHE_TTL_MS = 30_000;
|
||
const cache = new Map<number, { revoked: boolean; ts: number }>();
|
||
|
||
export async function isSessionRevoked(sid: number): Promise<boolean> {
|
||
const hit = cache.get(sid);
|
||
if (hit && Date.now() - hit.ts < CACHE_TTL_MS) return hit.revoked;
|
||
const [row] = await db
|
||
.select({ isRevoked: userSessions.isRevoked })
|
||
.from(userSessions)
|
||
.where(eq(userSessions.id, sid));
|
||
// Неизвестная/удалённая сессия считается отозванной
|
||
const revoked = row ? row.isRevoked : true;
|
||
cache.set(sid, { revoked, ts: Date.now() });
|
||
return revoked;
|
||
}
|
||
|
||
/** Сброс кэша после явного отзыва (logout, отзыв устройства, смена пароля) */
|
||
export function invalidateSessionRevocationCache(sid?: number): void {
|
||
if (sid === undefined) cache.clear();
|
||
else cache.delete(sid);
|
||
}
|