const crypto = require('crypto'); const bcrypt = require('bcryptjs'); const jwt = require('jsonwebtoken'); const store = require('./store'); const COOKIE = 'ph_session'; const TOKEN_TTL = '30d'; // JWT signing secret — generated once and persisted in settings. let cachedSecret = null; async function getSecret() { if (cachedSecret) return cachedSecret; let secret = await store.getSetting('auth_secret'); if (!secret) { secret = crypto.randomBytes(48).toString('hex'); await store.setSetting('auth_secret', secret); } cachedSecret = secret; return secret; } function hashPassword(password) { return bcrypt.hash(password, 12); } function verifyPassword(password, hash) { return bcrypt.compare(password, hash); } async function issueToken(user) { return jwt.sign({ sub: user.id, email: user.email }, await getSecret(), { expiresIn: TOKEN_TTL }); } function setAuthCookie(res, token) { res.cookie(COOKIE, token, { httpOnly: true, sameSite: 'lax', secure: process.env.COOKIE_SECURE === 'true', maxAge: 30 * 24 * 60 * 60 * 1000, }); } function clearAuthCookie(res) { res.clearCookie(COOKIE); } // Resolve the current user from the session cookie, or null. async function currentUser(req) { const token = req.cookies && req.cookies[COOKIE]; if (!token) return null; try { const payload = jwt.verify(token, await getSecret()); return store.getUserById(payload.sub); } catch { return null; } } // Express middleware: 401 unless authenticated. async function requireAuth(req, res, next) { const user = await currentUser(req); if (!user) return res.status(401).json({ error: 'Authentication required' }); req.user = user; next(); } // Password-reset tokens: return { token, hash } — store the hash, email the token. function makeResetToken() { const token = crypto.randomBytes(32).toString('hex'); const hash = crypto.createHash('sha256').update(token).digest('hex'); return { token, hash }; } function hashResetToken(token) { return crypto.createHash('sha256').update(token).digest('hex'); } module.exports = { COOKIE, hashPassword, verifyPassword, issueToken, setAuthCookie, clearAuthCookie, currentUser, requireAuth, makeResetToken, hashResetToken, };