const jwt = require('jsonwebtoken'); const bcrypt = require('bcryptjs'); class AuthenticationManager { constructor(model, secretKey) { this.Authentication = model; this.SECRET_KEY = secretKey; } // ========================================================= // USER // ========================================================= async findUser(sAMAccountName) { return this.Authentication.findOne({ where: { sAMAccountName } }); } // ========================================================= // PASSWORD // ========================================================= async setPassword(sAMAccountName, password) { const user = await this.findUser(sAMAccountName); if (!user) { return { token: null, levelId: 2, message: 'Unbekannter User' }; } user.password = await bcrypt.hash(password, 10); await user.save(); return { token: null, levelId: 0, message: 'Passwort gesetzt' }; } // ========================================================= // LOGIN // ========================================================= async login(sAMAccountName, password) { const user = await this.findUser(sAMAccountName); if (!user) { return { token: null, levelId: 2, message: 'Unbekannter Benutzer' }; } if (!user.password) { await this.setPassword(sAMAccountName, password); return { token: null, levelId: 1, message: 'Benutzer nicht registriert' }; } const ok = await bcrypt.compare(password, user.password); if (!ok) { return { token: null, levelId: 2, message: 'Falsches Passwort' }; } const token = jwt.sign( { ObjectGUID: user.ObjectGUID, sAMAccountName: user.sAMAccountName }, this.SECRET_KEY, { expiresIn: '1y' } ); user.refreshtoken = token; user.online = true; await user.save(); return { token, levelId: 0, message: 'Erfolgreich angemeldet' }; } // ========================================================= // LOGOUT // ========================================================= async logout(sAMAccountName) { const user = await this.findUser(sAMAccountName); if (!user) { return { token: null, levelId: 2, message: 'User nicht gefunden' }; } user.refreshtoken = null; user.online = false; await user.save(); return { token: null, levelId: 0, message: 'Erfolgreich abgemeldet' }; } // ========================================================= // VERIFY TOKEN // ========================================================= async verifyUserToken(sAMAccountName) { const user = await this.findUser(sAMAccountName); if (!user || !user.refreshtoken) { return { valid: false, levelId: 1 }; } try { const payload = jwt.verify(user.refreshtoken, this.SECRET_KEY); return { valid: true, user, payload }; } catch { return { valid: false, levelId: 4 }; } } // ========================================================= // 🔥 MIDDLEWARE BLEIBT HIER // ========================================================= authenticate() { return async (req, res, next) => { try { // ===================================================== // 🔥 GLOBAL PUBLIC ROUTE BYPASS (ROBUST) // ===================================================== const url = req.originalUrl.split('?')[0]; const publicRoutes = [ '/login', '/public' ]; const isPublicRoute = publicRoutes.some(route => url === route || url.startsWith(route + '/') ); if (isPublicRoute) { return next(); } // ===================================================== // 🔐 AUTH FLOW // ===================================================== const sAMAccountName = req.cookies?.sAMAccountName; if (!sAMAccountName) { return res.redirect('/login'); } const user = await this.findUser(sAMAccountName); if (!user || !user.active) { return res.redirect('/login'); } let payload; try { payload = jwt.verify(user.refreshtoken, this.SECRET_KEY); } catch { return res.redirect('/login'); } const rbac = await this.rbac.resolvePermissions(user.ObjectGUID); const normalized = this.rbac.normalize(rbac.permissions); const isSuperAdmin = this.rbac.isSuperAdmin(normalized); req.user = { ...user.toJSON(), jwt: payload, groups: rbac.groups, roles: rbac.roles, permissions: normalized, isSuperAdmin }; next(); } catch (err) { console.error(err); return res.redirect('/login'); } }; } } module.exports = AuthenticationManager;