import crypto from 'crypto'; import { db } from '../db/init.js'; // Refresh token lifetime const DISCORD_REFRESH_TTL_DAYS = 90; const GUEST_REFRESH_TTL_DAYS = 7; function hashToken(token) { return crypto.createHash('sha256').update(token).digest('hex'); } function generateToken() { return crypto.randomBytes(48).toString('base64url'); } function ttlDaysFor(userType) { return userType === 'guest' ? GUEST_REFRESH_TTL_DAYS : DISCORD_REFRESH_TTL_DAYS; } export function createRefreshToken({ userType, discordUserId = null, guestId = null, guestUsername = null }) { const token = generateToken(); const tokenHash = hashToken(token); const expiresAt = new Date(Date.now() + ttlDaysFor(userType) * 24 * 60 * 60 * 1000).toISOString(); db.prepare(` INSERT INTO refresh_tokens (token_hash, user_type, discord_user_id, guest_id, guest_username, expires_at) VALUES (?, ?, ?, ?, ?, ?) `).run(tokenHash, userType, discordUserId, guestId, guestUsername, expiresAt); return token; } export function verifyRefreshToken(token) { if (!token) return null; const tokenHash = hashToken(token); const row = db.prepare(` SELECT * FROM refresh_tokens WHERE token_hash = ? AND revoked = 0 AND expires_at > CURRENT_TIMESTAMP `).get(tokenHash); return row || null; } export function revokeRefreshToken(token) { if (!token) return; const tokenHash = hashToken(token); db.prepare('UPDATE refresh_tokens SET revoked = 1 WHERE token_hash = ?').run(tokenHash); } export function revokeRefreshTokenById(id) { db.prepare('UPDATE refresh_tokens SET revoked = 1 WHERE id = ?').run(id); } export function touchRefreshToken(id) { db.prepare('UPDATE refresh_tokens SET last_used_at = CURRENT_TIMESTAMP WHERE id = ?').run(id); } export function revokeAllForDiscordUser(discordUserId) { db.prepare('UPDATE refresh_tokens SET revoked = 1 WHERE discord_user_id = ?').run(discordUserId); }