Files
loot-hunt/src/routes/auth.js
Mike Johnston 83e552bd07
All checks were successful
Build Images and Deploy / Update-PROD-Stack (push) Successful in 29s
add organizer role and features
2026-02-28 01:50:20 -05:00

121 lines
4.2 KiB
JavaScript

const express = require('express');
const router = express.Router();
const { Users } = require('../models');
router.get('/login', (req, res) => {
res.render('auth/login', { title: 'Login', error: null });
});
router.post('/login', (req, res) => {
const { username, password } = req.body;
if (!username || !password) {
return res.render('auth/login', { title: 'Login', error: 'Username and password are required.' });
}
const user = Users.findByUsername(username);
if (!user || !Users.verifyPassword(user, password)) {
return res.render('auth/login', { title: 'Login', error: 'Invalid username or password.' });
}
req.session.userId = user.id;
req.session.username = user.username;
req.session.isAdmin = !!user.is_admin;
req.session.isOrganizer = !!user.is_organizer;
const returnTo = req.session.returnTo || '/';
delete req.session.returnTo;
res.redirect(returnTo);
});
router.get('/register', (req, res) => {
res.render('auth/register', { title: 'Register', error: null });
});
router.post('/register', (req, res) => {
const { username, password, password_confirm } = req.body;
if (!username || !password) {
return res.render('auth/register', { title: 'Register', error: 'Username and password are required.' });
}
if (username.length < 3 || username.length > 24) {
return res.render('auth/register', { title: 'Register', error: 'Username must be 3-24 characters.' });
}
if (!/^[a-zA-Z0-9_-]+$/.test(username)) {
return res.render('auth/register', { title: 'Register', error: 'Username can only contain letters, numbers, hyphens and underscores.' });
}
if (password.length < 6) {
return res.render('auth/register', { title: 'Register', error: 'Password must be at least 6 characters.' });
}
if (password !== password_confirm) {
return res.render('auth/register', { title: 'Register', error: 'Passwords do not match.' });
}
if (Users.findByUsername(username)) {
return res.render('auth/register', { title: 'Register', error: 'Username is already taken.' });
}
try {
const userId = Users.create(username, password);
req.session.userId = userId;
req.session.username = username;
req.session.isAdmin = false;
req.session.isOrganizer = false;
req.session.flash = { type: 'success', message: 'Account created! Welcome to Loot Hunt.' };
const returnTo = req.session.returnTo || '/';
delete req.session.returnTo;
res.redirect(returnTo);
} catch (err) {
console.error('Registration error:', err);
res.render('auth/register', { title: 'Register', error: 'Registration failed. Try a different username.' });
}
});
router.get('/logout', (req, res) => {
req.session.destroy(() => {
res.redirect('/');
});
});
// ─── Password reset (via admin-generated URL) ────────────
router.get('/reset/:token', (req, res) => {
const tokenRecord = Users.findByResetToken(req.params.token);
if (!tokenRecord) {
return res.render('error', { title: 'Invalid Link', message: 'This password reset link is invalid or has expired.' });
}
res.render('auth/reset', { title: 'Reset Password', token: req.params.token, username: tokenRecord.username, error: null });
});
router.post('/reset/:token', (req, res) => {
const tokenRecord = Users.findByResetToken(req.params.token);
if (!tokenRecord) {
return res.render('error', { title: 'Invalid Link', message: 'This password reset link is invalid or has expired.' });
}
const { password, password_confirm } = req.body;
if (!password || password.length < 6) {
return res.render('auth/reset', { title: 'Reset Password', token: req.params.token, username: tokenRecord.username, error: 'Password must be at least 6 characters.' });
}
if (password !== password_confirm) {
return res.render('auth/reset', { title: 'Reset Password', token: req.params.token, username: tokenRecord.username, error: 'Passwords do not match.' });
}
Users.setPassword(tokenRecord.user_id, password);
Users.consumeResetToken(req.params.token);
// Log the user in
req.session.userId = tokenRecord.user_id;
req.session.username = tokenRecord.username;
req.session.isAdmin = false; // they can re-check on next load
res.redirect('/');
});
module.exports = router;