fertig-classic-games/server/auth/routes.js

90 lines
2.7 KiB
JavaScript

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('<h1>Verification failed</h1><p>Link invalid or expired.</p>');
}
res.send('<h1>Email verified</h1><p>You can close this tab and return to the game.</p>');
});
export default router;