import { createHash, pbkdf2Sync, randomBytes } from "node:crypto"; let db; let users; export function initAuth(app, db) { users = db.collection('users'); app.post('/auth/login', loginUser); } async function loginUser(req, res) { const username = req.body.username; const password = req.body.password; let userCount = await users.estimatedDocumentCount(); let sessiontoken = null; if (userCount <= 0) { // create first user sessiontoken = await createUser(username, password, 'admin'); } else { // authenticate user sessiontoken = await authenticateUser(username, password); } if (sessiontoken !== null) { const expires = new Date(); expires.setDate(expires.getDate() + 1); res.cookie('jeopardytoken', sessiontoken, { maxAge: 1e3 * 60 * 60 * 24 }) res.sendStatus(200); } else { res.sendStatus(403); } } async function createUser(username, password, role) { const salt = randomBytes(128).toString('base64'); const iterations = Math.floor(Math.random() * 5000) + 5000; const hash = generateHash(password, salt, iterations); const sessiontoken = generateSessionToken(); await users.insertOne({ username, role, salt, iterations, hash, sessiontoken }); return sessiontoken; } async function authenticateUser(username, password) { let foundUser = await users.findOne({username}); if (foundUser === null) return null; const hash = generateHash(password, foundUser.salt, foundUser.iterations); if (hash === foundUser.hash) { const sessiontoken = generateSessionToken(); await users.updateOne({_id: foundUser._id}, {$set: { sessiontoken }}); return sessiontoken; } return null; } function generateSessionToken() { return randomBytes(128).toString('base64'); } function generateHash(password, salt, iterations) { return pbkdf2Sync(password, salt, iterations, 128, 'sha512').toString('hex'); }