const nocodbService = require('../services/nocodb'); const logger = require('../utils/logger'); const { extractId } = require('../utils/helpers'); class AuthController { async login(req, res) { try { const { email, password } = req.body; // Validate input if (!email || !password) { return res.status(400).json({ success: false, error: 'Email and password are required' }); } // Validate email format const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; if (!emailRegex.test(email)) { return res.status(400).json({ success: false, error: 'Invalid email format' }); } logger.info('Login attempt:', { email, ip: req.ip, cfIp: req.headers['cf-connecting-ip'], userAgent: req.headers['user-agent'] }); // Fetch user from NocoDB const user = await nocodbService.getUserByEmail(email); if (!user) { logger.warn(`No user found with email: ${email}`); return res.status(401).json({ success: false, error: 'Invalid email or password' }); } // Check password if (user.Password !== password && user.password !== password) { logger.warn(`Invalid password for email: ${email}`); return res.status(401).json({ success: false, error: 'Invalid email or password' }); } // Check if temp user has expired const userType = user.UserType || user.userType || 'user'; if (userType === 'temp') { 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 attempted login: ${email}, expired: ${expiration}`); return res.status(401).json({ success: false, error: 'Account has expired. Please contact an administrator.' }); } } } // Update last login time try { const userId = extractId(user); await nocodbService.update( require('../config').nocodb.loginSheetId, userId, { 'Last Login': new Date().toISOString(), last_login: new Date().toISOString() } ); } catch (updateError) { logger.warn('Failed to update last login time:', updateError.message); // Don't fail the login } // Set session req.session.authenticated = true; req.session.userId = user.id || user.Id; req.session.userEmail = user.email || user.Email; // Make sure this is set req.session.userName = user.name || user.Name; req.session.isAdmin = user.admin || user.Admin || false; req.session.userType = user.UserType || user.userType || (req.session.isAdmin ? 'admin' : 'user'); logger.info('User logged in:', { email: req.session.userEmail, admin: req.session.isAdmin }); // Force session save req.session.save((err) => { if (err) { logger.error('Session save error:', err); return res.status(500).json({ success: false, error: 'Session error. Please try again.' }); } logger.info(`User authenticated: ${email}, Admin: ${req.session.isAdmin}`); res.json({ success: true, message: 'Login successful', user: { email: email, name: req.session.userName, isAdmin: req.session.isAdmin, userType: req.session.userType } }); }); } catch (error) { logger.error('Login error:', error.message); res.status(500).json({ success: false, error: 'Authentication service error. Please try again later.' }); } } async logout(req, res) { req.session.destroy((err) => { if (err) { logger.error('Logout error:', err); return res.status(500).json({ success: false, error: 'Logout failed' }); } res.json({ success: true, message: 'Logged out successfully' }); }); } async check(req, res) { // If user is authenticated, check for temp user expiration if (req.session?.authenticated && 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 in check: ${req.session.userEmail}, expired: ${expiration}`); // Destroy the session req.session.destroy((err) => { if (err) { logger.error('Session destroy error:', err); } }); return res.json({ authenticated: false, user: null, expired: true, message: 'Account has expired. Please contact an administrator.' }); } } } } catch (error) { logger.error('Error checking temp user expiration in check:', error.message); // Don't fail the check on database errors, just log it } } res.json({ authenticated: req.session?.authenticated || false, user: req.session?.authenticated ? { email: req.session.userEmail, name: req.session.userName, isAdmin: req.session.isAdmin || false, userType: req.session.userType || 'user' } : null }); } } module.exports = new AuthController();