const jwt = require('jsonwebtoken'); const AdminUser = require('../models/AdminUser'); const { env } = require('../configs/env'); const JWT_SECRET = env.jwtSecret; const readTokenFromRequest = (req) => { const header = req.headers?.authorization || req.headers?.Authorization; if (typeof header === 'string') { const [scheme, value] = header.split(' '); if (scheme && scheme.toLowerCase() === 'bearer' && value) { return value.trim(); } } return req.cookies?.token || ''; }; const protect = async (req, res, next) => { if (!JWT_SECRET) { return res.status(503).json({ message: "Authentication is not configured" }); } const token = readTokenFromRequest(req); if (!token) { return res.status(401).json({ message: "Not authorized, no token" }); } try { const decoded = jwt.verify(token, JWT_SECRET); const adminId = decoded?.id || decoded?.sub; if (!adminId) { return res.status(401).json({ message: "Not authorized, invalid token" }); } const admin = await AdminUser.findById(adminId).select('-passwordHash +sessionToken').lean(); if (!admin) { return res.status(401).json({ message: "User not found" }); } if (admin.isActive === false) { return res.status(403).json({ message: "Account is inactive" }); } if (decoded.st && admin.sessionToken && decoded.st !== admin.sessionToken) { return res.status(401).json({ message: "Session invalidated", code: "SESSION_CONFLICT" }); } req.user = { ...admin, _id: admin._id, id: String(admin._id), role: admin.role || "admin", }; // Belt-and-suspenders: projection already excludes this field; explicit scrub guards against future query changes. delete req.user.passwordHash; return next(); } catch (error) { return res.status(401).json({ message: "Not authorized, invalid token" }); } }; const adminOnly = (req, res, next) => { if (req.user && req.user.role === "admin") { next(); } else { res.status(403).json({ message: "Access denied: Admins only" }); } }; const optionalProtect = async (req, res, next) => { if (!JWT_SECRET) return next(); const token = readTokenFromRequest(req); if (!token) return next(); try { const decoded = jwt.verify(token, JWT_SECRET); const adminId = decoded?.id || decoded?.sub; if (adminId) { const admin = await AdminUser.findById(adminId).select('-passwordHash').lean(); if (admin && admin.isActive !== false) { req.user = { ...admin, _id: admin._id, id: String(admin._id), role: admin.role || 'admin', }; } } } catch { // Invalid token — proceed as unauthenticated } next(); }; module.exports = { protect, adminOnly, optionalProtect };