const { query } = require('../../utils/db') const PUBLIC_COLS = 'id, username, role, totp_enabled, created_at, last_login_at' async function insertUser({ username, passwordHash, role = 'admin' }) { const res = await query( 'INSERT INTO users (username, password_hash, role) VALUES (?, ?, ?)', [username, passwordHash, role], ) return res.insertId } async function findByUsername(username) { const rows = await query('SELECT * FROM users WHERE username = ? LIMIT 1', [username]) return rows[0] || null } async function findById(id) { const rows = await query('SELECT * FROM users WHERE id = ? LIMIT 1', [id]) return rows[0] || null } async function listUsers() { return query(`SELECT ${PUBLIC_COLS} FROM users ORDER BY id ASC`) } async function updateUser(id, fields) { const cols = [] const params = [] for (const [key, val] of Object.entries(fields)) { cols.push(`${key} = ?`) params.push(val) } if (cols.length === 0) return params.push(id) await query(`UPDATE users SET ${cols.join(', ')} WHERE id = ?`, params) } async function deleteUser(id) { return query('DELETE FROM users WHERE id = ?', [id]) } async function countUsers() { const rows = await query('SELECT COUNT(*) AS c FROM users') return Number(rows[0].c) } async function countAdmins() { const rows = await query("SELECT COUNT(*) AS c FROM users WHERE role = 'admin'") return Number(rows[0].c) } async function touchLastLogin(id) { return query('UPDATE users SET last_login_at = NOW() WHERE id = ?', [id]) } // Move the "tokens valid after" cutoff to now, invalidating every session token // issued before this instant (password change / log out everywhere). requireAuth // compares each session's issued-at against this column. async function bumpTokensValidAfter(id) { return query('UPDATE users SET tokens_valid_after = NOW() WHERE id = ?', [id]) } // Store a (not-yet-enabled) TOTP secret for a user. Enabling is a separate step // so a secret is never trusted until the user has confirmed one code. async function setTotpSecret(id, secret) { return query('UPDATE users SET totp_secret = ?, totp_enabled = 0 WHERE id = ?', [secret, id]) } async function enableTotp(id) { return query('UPDATE users SET totp_enabled = 1 WHERE id = ?', [id]) } async function disableTotp(id) { return query('UPDATE users SET totp_secret = NULL, totp_enabled = 0 WHERE id = ?', [id]) } module.exports = { insertUser, findByUsername, findById, listUsers, updateUser, deleteUser, countUsers, countAdmins, touchLastLogin, bumpTokensValidAfter, setTotpSecret, enableTotp, disableTotp, }