const jwt = require("jsonwebtoken"); const { getPrismaClient } = require("../config/prisma"); const { validate_session, update_session_activity, is_tfa_bypassed, } = require("../utils/session_manager"); const prisma = getPrismaClient(); // Middleware to verify JWT token with session validation const authenticateToken = async (req, res, next) => { try { const authHeader = req.headers.authorization; const token = authHeader?.split(" ")[1]; // Bearer TOKEN if (!token) { return res.status(401).json({ error: "Access token required" }); } // Verify token if (!process.env.JWT_SECRET) { throw new Error("JWT_SECRET environment variable is required"); } const decoded = jwt.verify(token, process.env.JWT_SECRET); // Validate session and check inactivity timeout const validation = await validate_session(decoded.sessionId, token); if (!validation.valid) { const error_messages = { "Session not found": "Session not found", "Session revoked": "Session has been revoked", "Session expired": "Session has expired", "Session inactive": validation.message || "Session timed out due to inactivity", "Token mismatch": "Invalid token", "User inactive": "User account is inactive", }; return res.status(401).json({ error: error_messages[validation.reason] || "Authentication failed", reason: validation.reason, }); } // Update session activity timestamp await update_session_activity(decoded.sessionId); // Check if TFA is bypassed for this session const tfa_bypassed = await is_tfa_bypassed(decoded.sessionId); // Update last login (only on successful authentication) await prisma.users.update({ where: { id: validation.user.id }, data: { last_login: new Date(), updated_at: new Date(), }, }); req.user = validation.user; req.session_id = decoded.sessionId; req.tfa_bypassed = tfa_bypassed; next(); } catch (error) { if (error.name === "JsonWebTokenError") { return res.status(401).json({ error: "Invalid token" }); } if (error.name === "TokenExpiredError") { return res.status(401).json({ error: "Token expired" }); } console.error("Auth middleware error:", error); return res.status(500).json({ error: "Authentication failed" }); } }; // Middleware to check admin role const requireAdmin = (req, res, next) => { if (req.user.role !== "admin") { return res.status(403).json({ error: "Admin access required" }); } next(); }; // Middleware to check if user is authenticated (optional) const optionalAuth = async (req, _res, next) => { try { const authHeader = req.headers.authorization; const token = authHeader?.split(" ")[1]; if (token) { if (!process.env.JWT_SECRET) { throw new Error("JWT_SECRET environment variable is required"); } const decoded = jwt.verify(token, process.env.JWT_SECRET); const user = await prisma.users.findUnique({ where: { id: decoded.userId }, select: { id: true, username: true, email: true, role: true, is_active: true, last_login: true, created_at: true, updated_at: true, }, }); if (user?.is_active) { req.user = user; } } next(); } catch { // Continue without authentication for optional auth next(); } }; // Middleware to check if TFA is required for sensitive operations const requireTfaIfEnabled = async (req, res, next) => { try { // Check if user has TFA enabled const user = await prisma.users.findUnique({ where: { id: req.user.id }, select: { tfa_enabled: true }, }); // If TFA is enabled and not bypassed, require TFA verification if (user?.tfa_enabled && !req.tfa_bypassed) { return res.status(403).json({ error: "Two-factor authentication required for this operation", requires_tfa: true, }); } next(); } catch (error) { console.error("TFA requirement check error:", error); return res.status(500).json({ error: "Authentication check failed" }); } }; module.exports = { authenticateToken, requireAdmin, optionalAuth, requireTfaIfEnabled, };