import express, { type Router, type Request, type Response } from 'express' import jwt from 'jsonwebtoken' import { UserModel } from '../../../models/user.model.ts' import ldapAuth from './ldap.ts' const router = express.Router() const ACCESS_TOKEN_SECRET = process.env.ACCESS_TOKEN_SECRET! const REFRESH_TOKEN_SECRET = process.env.REFRESH_TOKEN_SECRET! function createAccessToken(user: any) { return jwt.sign( { sub: user._id, role: user.role }, ACCESS_TOKEN_SECRET, { expiresIn: '15m' }, ) } function createRefreshToken(user: any) { return jwt.sign( { sub: user._id }, REFRESH_TOKEN_SECRET, { expiresIn: '7d' }, ) } router.post('/login', async (req: Request, res: Response) => { const { username, password, remember } = req.body if (!username || !password) return res.status(400).json({ error: 'Missing credentials' }) try { const ldapUser = await ldapAuth({ username, password }) if (!ldapUser.auth) return res.status(401).json({ error: 'Invalid credentials' }) let user = await UserModel.findOne({ username: ldapUser.user.cn }) if (!user) { user = await UserModel.create({ username: ldapUser.user.cn, email: ldapUser.user.dn, refreshToken: '', }) } const accessToken = createAccessToken(user) const refreshToken = createRefreshToken(user) user.refreshToken = refreshToken await user.save() res.cookie('access_token', accessToken, { httpOnly: true, sameSite: 'lax', secure: process.env.NODE_ENV !== 'dev', maxAge: 7 * 24 * 60 * 60 * 1000, }) const refreshMaxAge = remember > 7 ? 365 * 24 * 60 * 60 * 1000 : 7 * 24 * 60 * 60 * 1000 res.cookie('refreshToken', refreshToken, { httpOnly: true, sameSite: 'lax', secure: process.env.NODE_ENV !== 'dev', maxAge: refreshMaxAge, }) res.json({ ok: true, user: { username: ldapUser.user.cn, email: ldapUser.user.dn }, }) } catch (err) { console.error(err) res.status(401).json({ error: 'Invalid credentials' }) } }) router.post('/refresh', async (req: Request, res: Response) => { const token = req.cookies.refreshToken if (!token) return res.status(401).json({ error: 'No refresh token' }) try { const payload = jwt.verify(token, REFRESH_TOKEN_SECRET) as any const user = await UserModel.findById(payload.sub) if (!user || user.refreshToken !== token) return res.status(403).json({ error: 'Invalid refresh token' }) const newAccessToken = createAccessToken(user) const newRefreshToken = createRefreshToken(user) user.refreshToken = newRefreshToken await user.save() const existingRefreshCookie = req.cookies.refreshToken const decodedOld = jwt.decode(existingRefreshCookie) as any const remainingDays = (decodedOld.exp * 1000 - Date.now()) / (1000 * 60 * 60 * 24) const refreshMaxAge = remainingDays > 7 ? 365 * 24 * 60 * 60 * 1000 : 7 * 24 * 60 * 60 * 1000 res.cookie('access_token', newAccessToken, { httpOnly: true, sameSite: 'lax', secure: process.env.NODE_ENV !== 'dev', maxAge: 15 * 60 * 1000, }) res.cookie('refreshToken', newRefreshToken, { httpOnly: true, sameSite: 'lax', secure: process.env.NODE_ENV !== 'dev', maxAge: refreshMaxAge, }) return res.json({ ok: true }) } catch (error) { return res.status(401).json({ error: 'Invalid refresh token' }) } }) router.post('/logout', async (req: Request, res: Response) => { const token = req.cookies.refreshToken if (token) { try { const payload = jwt.verify(token, REFRESH_TOKEN_SECRET) const user = await UserModel.findById(payload.sub) if (user) { user.refreshToken = '' await user.save() } } catch { } } res.clearCookie('access_token') res.clearCookie('refreshToken') res.json({ loggedOut: true }) }) export default router as Router