const { getSessionUser, COOKIE_NAME, publicUser } = require('../services/authService'); const { getDb, getSetting } = require('../db/database'); const { standardizeError } = require('./errorFormatter'); function getSingleModeUser() { if (getSetting('auth_mode') !== 'single') return null; const userId = getSetting('default_user_id'); if (!userId) return null; // Security FIX (2026-05-08): In single-user mode, we must validate the user // against the sessions table to ensure session expiry and active flag are checked. // This prevents replay attacks with expired sessions. const row = getDb().prepare(` SELECT u.id, u.username, u.display_name, u.role, u.must_change_password, u.first_login, u.active, u.is_default_admin FROM users u LEFT JOIN sessions s ON s.user_id = u.id WHERE u.id = ? AND u.role = 'user' AND u.active = 1 AND (s.expires_at > datetime('now') OR s.id IS NULL) `).get(userId); return row ? publicUser(row) : null; } function requireAuth(req, res, next) { // Single-user mode: bypass session entirely, auto-attach the default user const singleUser = getSingleModeUser(); if (singleUser) { req.user = singleUser; req.singleUserMode = true; return next(); } const user = getSessionUser(req.cookies?.[COOKIE_NAME]); if (!user) return res.status(401).json(standardizeError('Not authenticated', 'AUTH_ERROR')); req.user = user; next(); } function requireUser(req, res, next) { if (req.user?.is_default_admin) { return res.status(403).json(standardizeError('Default admin account does not have tracker access', 'FORBIDDEN')); } if (!['user', 'admin'].includes(req.user?.role)) { return res.status(403).json(standardizeError('Access denied: user account required', 'FORBIDDEN')); } next(); } function requireAdmin(req, res, next) { // In single-user mode the auto-attached user is never admin, // so admin routes naturally stay protected by session. if (req.user?.role !== 'admin') { return res.status(403).json(standardizeError('Access denied: admin account required', 'FORBIDDEN')); } next(); } module.exports = { requireAuth, requireUser, requireAdmin };