90 lines
2.7 KiB
JavaScript
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;
|