import { Router } from 'express'; import config from '../config.js'; import { sendVerificationEmail } from '../email/mailer.js'; import { consumeVerificationToken, createSession, createUser, destroySession, validateRegistration, verifyPassword, } from './service.js'; const router = Router(); function setSessionCookie(res, session) { res.cookie(config.auth.cookieName, session.id, { httpOnly: true, sameSite: 'lax', secure: config.env === 'production', expires: new Date(session.expiresAt), }); } router.post('/register', async (req, res) => { const { email, username, password } = req.body ?? {}; const errors = validateRegistration({ email, username, password }); if (Object.keys(errors).length) return res.status(400).json({ errors }); let user; try { user = await createUser({ email, username, password }); } catch (err) { if (err.code === 'EMAIL_TAKEN') return res.status(409).json({ errors: { email: err.message } }); if (err.code === 'USERNAME_TAKEN') return res.status(409).json({ errors: { username: err.message } }); throw err; } const link = `${config.baseUrl}/api/auth/verify?token=${user.verificationToken}`; const mailResult = await sendVerificationEmail(user.email, link); const session = createSession(user.id); setSessionCookie(res, session); res.status(201).json({ user: { id: user.id, email: user.email, username: user.username, emailVerified: false }, verification: { sent: mailResult.delivered, devLink: mailResult.devLogged ? link : null }, }); }); router.post('/login', async (req, res) => { const { identifier, password } = req.body ?? {}; if (!identifier || !password) return res.status(400).json({ error: 'Missing credentials.' }); const user = await verifyPassword(identifier, password); if (!user) return res.status(401).json({ error: 'Invalid credentials.' }); const session = createSession(user.id); setSessionCookie(res, session); res.json({ user: { id: user.id, email: user.email, username: user.username, emailVerified: !!user.email_verified, }, }); }); router.post('/logout', (req, res) => { destroySession(req.sessionId); res.clearCookie(config.auth.cookieName); res.json({ ok: true }); }); router.get('/me', (req, res) => { if (!req.user) return res.json({ user: null }); res.json({ user: req.user }); }); router.get('/verify', (req, res) => { const token = String(req.query.token ?? ''); const userId = consumeVerificationToken(token); if (!userId) { return res.status(400).send('
Link invalid or expired.
'); } res.send('You can close this tab and return to the game.
'); }); export default router;