Public Access
47 lines
1.3 KiB
TypeScript
47 lines
1.3 KiB
TypeScript
/**
|
|
* In-memory token blacklist with SQLite persistence.
|
|
* Tokens are blacklisted on logout and expire automatically based on JWT expiry.
|
|
*/
|
|
|
|
import { getDb } from '../db/database.js'
|
|
|
|
const memoryCache = new Set<string>()
|
|
let initialized = false
|
|
|
|
function initCache(): void {
|
|
if (initialized) return
|
|
const db = getDb()
|
|
db.exec(`
|
|
CREATE TABLE IF NOT EXISTS token_blacklist (
|
|
token_hash TEXT PRIMARY KEY,
|
|
expires_at INTEGER NOT NULL
|
|
);
|
|
CREATE INDEX IF NOT EXISTS idx_token_blacklist_expires ON token_blacklist(expires_at);
|
|
`)
|
|
// Load recent blacklisted tokens into memory
|
|
const rows = db.prepare('SELECT token_hash FROM token_blacklist WHERE expires_at > ?')
|
|
.all(Date.now()) as { token_hash: string }[]
|
|
for (const row of rows) {
|
|
memoryCache.add(row.token_hash)
|
|
}
|
|
initialized = true
|
|
}
|
|
|
|
export function isTokenBlacklisted(tokenHash: string): boolean {
|
|
initCache()
|
|
return memoryCache.has(tokenHash)
|
|
}
|
|
|
|
export function blacklistToken(tokenHash: string, expiresAt: number): void {
|
|
initCache()
|
|
memoryCache.add(tokenHash)
|
|
const db = getDb()
|
|
db.prepare('INSERT OR IGNORE INTO token_blacklist (token_hash, expires_at) VALUES (?, ?)')
|
|
.run(tokenHash, expiresAt)
|
|
}
|
|
|
|
export function cleanupExpiredTokens(): void {
|
|
const db = getDb()
|
|
db.prepare('DELETE FROM token_blacklist WHERE expires_at <= ?').run(Date.now())
|
|
}
|