notXCS/routes/auth.js

143 lines
4.7 KiB
JavaScript

const express = require('express');
const bcrypt = require('bcryptjs');
const router = express.Router();
const { ROLES } = require('../lib/auth');
const { createDefaultOrg } = require('../lib/orgs');
let db;
module.exports = (dbInit) => {
db = dbInit;
return router;
};
router.post('/register', (req, res) => {
const { username, password } = req.body || {};
if (!username || !password) {
return res.status(400).json({ success: false, message: "Username and password are required" });
}
if (typeof username !== 'string' || typeof password !== 'string' || username.trim().length < 3 || password.length < 6) {
return res.status(400).json({ success: false, message: "Username must be at least 3 characters and password at least 6 characters" });
}
db.get(`SELECT id FROM users WHERE username = ?`, [username], (err, existing) => {
if (err) {
console.error('Failed to check for existing user:', err.message);
return res.status(500).json({ success: false, message: "Internal server error" });
}
if (existing) {
return res.status(409).json({ success: false, message: "Username is already taken" });
}
// The very first registered user becomes a superadmin; every user after that is a normal user.
// This is the only way to obtain a superadmin account short of editing the database directly.
db.get(`SELECT COUNT(*) as count FROM users`, [], (err, row) => {
if (err) {
console.error('Failed to count users:', err.message);
return res.status(500).json({ success: false, message: "Internal server error" });
}
const role = row.count === 0 ? ROLES.SUPERADMIN : ROLES.USER;
bcrypt.hash(password, 10, (err, hash) => {
if (err) {
console.error('Failed to hash password:', err.message);
return res.status(500).json({ success: false, message: "Internal server error" });
}
db.run(`INSERT INTO users (username, password, role) VALUES (?, ?, ?)`, [username, hash, role], function (err) {
if (err) {
console.error('Failed to create user:', err.message);
return res.status(500).json({ success: false, message: "Internal server error" });
}
const userId = this.lastID;
// Every new user gets a default personal organization (replacing the old per-place
// sharing model), and is made an Admin member of it so they can invite others later.
createDefaultOrg(db, userId, username, (err) => {
if (err) {
console.error('Failed to create default organization:', err.message);
return res.status(500).json({ success: false, message: "Internal server error" });
}
req.session.userId = userId;
req.session.username = username;
res.json({ success: true, user: { id: userId, username, role } });
});
});
});
});
});
});
router.post('/login', (req, res) => {
const { username, password } = req.body || {};
if (!username || !password) {
return res.status(400).json({ success: false, message: "Username and password are required" });
}
db.get(`SELECT * FROM users WHERE username = ?`, [username], (err, user) => {
if (err) {
console.error('Failed to retrieve user:', err.message);
return res.status(500).json({ success: false, message: "Internal server error" });
}
if (!user) {
return res.status(401).json({ success: false, message: "Invalid username or password" });
}
bcrypt.compare(password, user.password, (err, matches) => {
if (err) {
console.error('Failed to verify password:', err.message);
return res.status(500).json({ success: false, message: "Internal server error" });
}
if (!matches) {
return res.status(401).json({ success: false, message: "Invalid username or password" });
}
req.session.userId = user.id;
req.session.username = user.username;
res.json({ success: true, user: { id: user.id, username: user.username, role: user.role } });
});
});
});
router.post('/logout', (req, res) => {
req.session.destroy((err) => {
if (err) {
console.error('Failed to destroy session:', err.message);
return res.status(500).json({ success: false, message: "Internal server error" });
}
res.clearCookie('connect.sid');
res.json({ success: true });
});
});
router.get('/me', (req, res) => {
if (!req.session.userId) {
return res.status(401).json({ success: false, message: "Not authenticated" });
}
db.get(`SELECT id, username, role FROM users WHERE id = ?`, [req.session.userId], (err, user) => {
if (err) {
console.error('Failed to retrieve user:', err.message);
return res.status(500).json({ success: false, message: "Internal server error" });
}
if (!user) {
return req.session.destroy(() => {
res.status(401).json({ success: false, message: "Not authenticated" });
});
}
res.json({ success: true, user });
});
});