import crypto from 'node:crypto'; import type { NextFunction, Request, Response } from 'express'; import { createSession, createUser, deleteSession, findUserBySessionToken, findUserByUsername } from './db.ts'; import type { AuthenticatedUser } from './types.ts'; declare global { namespace Express { interface Request { authUser?: AuthenticatedUser; authToken?: string; } } } export function hashPassword(password: string, salt = crypto.randomBytes(16).toString('hex')) { const hash = crypto.scryptSync(password, salt, 64).toString('hex'); return { hash, salt }; } export function verifyPassword(password: string, passwordHash: string, passwordSalt: string) { const { hash } = hashPassword(password, passwordSalt); return crypto.timingSafeEqual(Buffer.from(hash, 'hex'), Buffer.from(passwordHash, 'hex')); } export function issueSession(userId: number) { const token = crypto.randomBytes(32).toString('hex'); createSession(token, userId); return token; } export function registerUser(username: string, password: string) { if (findUserByUsername(username)) { throw new Error('Õ˺ÅÒÑ´æÔÚ'); } const { hash, salt } = hashPassword(password); const user = createUser(username, hash, salt); if (!user) { throw new Error('Õ˺Ŵ´½¨Ê§°Ü'); } const token = issueSession(user.id); return { token, user: { id: user.id, username: user.username }, }; } export function loginUser(username: string, password: string) { const user = findUserByUsername(username); if (!user || !verifyPassword(password, user.password_hash, user.password_salt)) { throw new Error('Õ˺ŻòÃÜÂë´íÎó'); } const token = issueSession(user.id); return { token, user: { id: user.id, username: user.username }, }; } export function requireAuth(req: Request, res: Response, next: NextFunction) { const header = req.headers.authorization || ''; const token = header.startsWith('Bearer ') ? header.slice(7) : ''; if (!token) { res.status(401).json({ error: 'δµÇ¼' }); return; } const user = findUserBySessionToken(token); if (!user) { res.status(401).json({ error: 'µÇ¼ÒÑʧЧ' }); return; } req.authToken = token; req.authUser = { id: user.id, username: user.username }; next(); } export function resolveSession(token: string) { const user = findUserBySessionToken(token); return user ? { id: user.id, username: user.username } : null; } export function logoutSession(token: string) { deleteSession(token); }