diff --git a/scripts/reset-admin.js b/scripts/reset-admin.js index e0f267d..6343ba3 100644 --- a/scripts/reset-admin.js +++ b/scripts/reset-admin.js @@ -13,7 +13,7 @@ const crypto = require('crypto'); const nonce = crypto.randomBytes(8).toString('hex'); const token = jwt.sign( - { id: 'recovery-' + nonce, email: 'admin@localhost', role: 'admin' }, + { id: 'recovery-' + nonce, email: 'admin@localhost', role: 'admin', recovery: true }, config.jwtSecret, { expiresIn: '1h' } ); diff --git a/server/middleware/auth.js b/server/middleware/auth.js index afae556..a5404c2 100644 --- a/server/middleware/auth.js +++ b/server/middleware/auth.js @@ -14,6 +14,20 @@ function verifyToken(token) { return jwt.verify(token, config.jwtSecret, { algorithms: ['HS256'] }); } +// Synthetic user record for recovery tokens (scripts/reset-admin.js). Not +// persisted; only exists for the lifetime of the request. +function recoveryUser(decoded) { + return { + id: decoded.id, + email: decoded.email || 'admin@localhost', + name: 'Recovery Admin', + role: decoded.role || 'admin', + auth_provider: 'recovery', + avatar_url: null, + plan_id: 'enterprise' + }; +} + // Express middleware - requires valid JWT function requireAuth(req, res, next) { const authHeader = req.headers.authorization; @@ -24,6 +38,10 @@ function requireAuth(req, res, next) { try { const token = authHeader.split(' ')[1]; const decoded = verifyToken(token); + if (decoded.recovery) { + req.user = recoveryUser(decoded); + return next(); + } const user = db.prepare('SELECT id, email, name, role, auth_provider, avatar_url, plan_id FROM users WHERE id = ?').get(decoded.id); if (!user) return res.status(401).json({ error: 'User not found' }); req.user = user; @@ -40,7 +58,9 @@ function optionalAuth(req, res, next) { try { const token = authHeader.split(' ')[1]; const decoded = verifyToken(token); - req.user = db.prepare('SELECT id, email, name, role, auth_provider, avatar_url, plan_id FROM users WHERE id = ?').get(decoded.id); + req.user = decoded.recovery + ? recoveryUser(decoded) + : db.prepare('SELECT id, email, name, role, auth_provider, avatar_url, plan_id FROM users WHERE id = ?').get(decoded.id); } catch (err) { // Token invalid, continue without user }