const logger = require('../utils/logger'); const nocodbService = require('../services/nocodb'); // Helper function to check if a temp user has expired const checkTempUserExpiration = async (req, res) => { if (req.session?.userType === 'temp' && req.session?.userEmail) { try { const user = await nocodbService.getUserByEmail(req.session.userEmail); if (user) { const expiration = user.ExpiresAt || user.expiresAt || user.Expiration || user.expiration; if (expiration) { const expirationDate = new Date(expiration); const now = new Date(); if (now > expirationDate) { logger.warn(`Expired temp user session detected: ${req.session.userEmail}, expired: ${expiration}`); // Destroy the session req.session.destroy((err) => { if (err) { logger.error('Session destroy error:', err); } }); if (req.xhr || req.headers.accept?.indexOf('json') > -1) { return res.status(401).json({ success: false, error: 'Account has expired. Please contact an administrator.', expired: true }); } else { return res.redirect('/login.html?expired=true'); } } } } } catch (error) { logger.error('Error checking temp user expiration:', error.message); // Don't fail the request on database errors, just log it } } return null; // No expiration issue }; const requireAuth = async (req, res, next) => { const isAuthenticated = (req.session && req.session.authenticated) || (req.session && req.session.userId && req.session.userEmail); if (isAuthenticated) { // Check if temp user has expired const expirationResponse = await checkTempUserExpiration(req, res); if (expirationResponse) { return; // Response already sent by checkTempUserExpiration } // Set up req.user object for controllers that expect it req.user = { id: req.session.userId, email: req.session.userEmail, isAdmin: req.session.isAdmin || false, userType: req.session.userType }; next(); } else { logger.warn('Unauthorized access attempt', { ip: req.ip, path: req.path, userAgent: req.get('User-Agent'), referer: req.get('Referer'), // Add referer to see where requests come from method: req.method, timestamp: new Date().toISOString() }); // Check if this is an auto-refresh request if (req.headers['x-requested-with'] === 'XMLHttpRequest' || req.path.includes('/api/locations')) { return res.status(401).json({ authenticated: false, error: 'Session expired', isAutoRefresh: true }); } if (req.xhr || req.headers.accept?.indexOf('json') > -1) { res.status(401).json({ success: false, error: 'Authentication required' }); } else { res.redirect('/login.html'); } } }; const requireAdmin = async (req, res, next) => { // Check for both authentication patterns used in your app const isAuthenticated = (req.session && req.session.authenticated) || (req.session && req.session.userId && req.session.userEmail); if (isAuthenticated && req.session.isAdmin) { // Check if temp user has expired const expirationResponse = await checkTempUserExpiration(req, res); if (expirationResponse) { return; // Response already sent by checkTempUserExpiration } // Set up req.user object for controllers that expect it req.user = { id: req.session.userId, email: req.session.userEmail, isAdmin: req.session.isAdmin || false, userType: req.session.userType }; next(); } else { logger.warn('Unauthorized admin access attempt', { ip: req.ip, path: req.path, user: req.session?.userEmail || 'anonymous', userAgent: req.get('User-Agent') }); if (req.xhr || req.headers.accept?.indexOf('json') > -1) { res.status(403).json({ success: false, error: 'Admin access required' }); } else { res.redirect('/login.html'); } } }; const requireNonTemp = async (req, res, next) => { const isAuthenticated = (req.session && req.session.authenticated) || (req.session && req.session.userId && req.session.userEmail); if (isAuthenticated && req.session.userType !== 'temp') { // Check if temp user has expired (shouldn't happen here, but for safety) const expirationResponse = await checkTempUserExpiration(req, res); if (expirationResponse) { return; // Response already sent by checkTempUserExpiration } // Set up req.user object for controllers that expect it req.user = { id: req.session.userId, email: req.session.userEmail, isAdmin: req.session.isAdmin || false, userType: req.session.userType }; next(); } else { logger.warn('Temp user access denied', { ip: req.ip, path: req.path, user: req.session?.userEmail || 'anonymous', userType: req.session?.userType || 'unknown' }); if (req.xhr || req.headers.accept?.indexOf('json') > -1) { res.status(403).json({ success: false, error: 'Access denied for temporary users' }); } else { res.redirect('/'); } } }; const requireDeletePermission = async (req, res, next) => { const isAuthenticated = (req.session && req.session.authenticated) || (req.session && req.session.userId && req.session.userEmail); // Only admins and regular users can delete, not temps if (isAuthenticated && req.session.userType !== 'temp') { // Check if temp user has expired (shouldn't happen here, but for safety) const expirationResponse = await checkTempUserExpiration(req, res); if (expirationResponse) { return; // Response already sent by checkTempUserExpiration } next(); } else { logger.warn('Delete permission denied', { ip: req.ip, path: req.path, user: req.session?.userEmail || 'anonymous', userType: req.session?.userType || 'unknown' }); res.status(403).json({ success: false, error: 'Delete permission denied' }); } }; module.exports = { requireAuth, requireAdmin, requireNonTemp, requireDeletePermission };