import { Router } from 'express'; import { config, isAllowedUrl } from '../config.js'; import { buildLoginUrl, buildLogoutUrl, handleCallback } from '../oidc.js'; export const authRouter = Router(); /** Rücksprung nur auf das Portal selbst oder erlaubte Tool-Domains. */ function safeReturnTo(raw: unknown): string { if (typeof raw !== 'string' || !raw) return '/'; if (raw.startsWith('/') && !raw.startsWith('//')) return raw; return isAllowedUrl(raw) ? raw : '/'; } authRouter.get('/login', async (req, res, next) => { try { const returnTo = safeReturnTo(req.query.returnTo); if (config.devUser) { req.session.user = { sub: `dev-${config.devUser}`, username: config.devUser, name: config.devUser.charAt(0).toUpperCase() + config.devUser.slice(1), email: `${config.devUser}@example.invalid`, groups: ['HI-Mitarbeiter', 'HI-Admin'], }; return res.redirect(returnTo); } const { url, state, codeVerifier } = await buildLoginUrl(); req.session.login = { state, codeVerifier, returnTo }; req.session.save((err) => (err ? next(err) : res.redirect(url))); } catch (err) { next(err); } }); authRouter.get('/callback', async (req, res) => { const pending = req.session.login; if (!pending) return res.redirect('/auth/login'); try { const query = req.originalUrl.slice(req.originalUrl.indexOf('?')); const { user, idToken } = await handleCallback(query, pending); const returnTo = pending.returnTo; // Neue Session-ID nach dem Login (Schutz vor Session Fixation). req.session.regenerate((err) => { if (err) return res.status(500).send('Anmeldung fehlgeschlagen.'); req.session.user = user; req.session.idToken = idToken; req.session.save(() => res.redirect(returnTo)); }); } catch (err) { console.error('[auth] Callback fehlgeschlagen:', err); delete req.session.login; res.status(401).send('Anmeldung fehlgeschlagen. Erneut versuchen'); } }); authRouter.get('/logout', async (req, res, next) => { try { const url = await buildLogoutUrl(req.session.idToken); req.session.destroy(() => { res.clearCookie('hi.portal.sid'); res.redirect(url); }); } catch (err) { next(err); } });