import { Request, Response, NextFunction } from 'express'; import { getUserById } from './userStore.js'; // ============================================================ // Auth Middleware — Session-based avec vérification passwordChangedAt // ============================================================ /** * Middleware d'authentification. * Vérifie que l'utilisateur est connecté ET que sa session n'a pas été * invalidée par un changement de mot de passe. */ const authMiddleware = (req: Request, res: Response, next: NextFunction) => { const session = req.session as any; if (!session.user || !session.user.id) { return res.status(401).json({ error: "Non autorisé. Veuillez vous connecter." }); } // Bloquer les APIs si changement de mot de passe requis if (session.user.mustChangePassword && req.path !== '/api/change-password' && req.path !== '/api/logout') { return res.status(403).json({ error: "Changement de mot de passe obligatoire.", mustChangePassword: true }); } // Vérifier que le user existe encore et que le password n'a pas changé depuis le login const user = getUserById(session.user.id); if (!user) { // User supprimé depuis le login → détruire la session session.destroy(() => {}); return res.status(401).json({ error: "Session invalide. Veuillez vous reconnecter." }); } // Comparer loginAt avec passwordChangedAt — si le password a changé après le login, invalider if (session.user.loginAt && user.passwordChangedAt) { const loginTime = new Date(session.user.loginAt).getTime(); const passwordChangeTime = new Date(user.passwordChangedAt).getTime(); if (passwordChangeTime > loginTime) { session.destroy(() => {}); return res.status(401).json({ error: "Votre mot de passe a été modifié. Veuillez vous reconnecter." }); } } next(); }; /** * Middleware admin. * Doit être utilisé APRÈS authMiddleware (session.user déjà vérifié). * Vérifie que l'utilisateur a le rôle admin. */ export const requireAdmin = (req: Request, res: Response, next: NextFunction) => { const session = req.session as any; if (!session.user || session.user.role !== 'admin') { return res.status(403).json({ error: "Accès refusé. Droits administrateur requis." }); } next(); }; /** * Middleware de vue d'authentification. * Identique à authMiddleware mais redirige vers /login au lieu de retourner du JSON. */ export const viewAuthMiddleware = (req: Request, res: Response, next: NextFunction) => { const session = req.session as any; if (!session.user || !session.user.id) { return res.redirect('/login'); } // Même vérification passwordChangedAt const user = getUserById(session.user.id); if (!user) { session.destroy(() => {}); return res.redirect('/login'); } if (session.user.loginAt && user.passwordChangedAt) { const loginTime = new Date(session.user.loginAt).getTime(); const passwordChangeTime = new Date(user.passwordChangedAt).getTime(); if (passwordChangeTime > loginTime) { session.destroy(() => {}); return res.redirect('/login'); } } next(); }; /** * Middleware de vue exigeant le rôle admin. * Redirige les non-admins vers /trending en déposant un cookie d'erreur. */ export const viewRequireAdmin = (req: Request, res: Response, next: NextFunction) => { const session = req.session as any; if (!session.user || session.user.role !== 'admin') { res.cookie('authError', "Accès refusé. Droits administrateur requis.", { maxAge: 10000 }); return res.redirect('/trending'); } next(); }; export default authMiddleware;