// Authentication Routes const express = require('express'); const bcrypt = require('bcryptjs'); const crypto = require('crypto'); function createAuthRouter(db) { const router = express.Router(); // Login router.post('/login', async (req, res) => { const { username, password } = req.body; if (!username || !password) { return res.status(400).json({ error: 'Username and password are required' }); } try { // Find user const user = await new Promise((resolve, reject) => { db.get( 'SELECT * FROM users WHERE username = ?', [username], (err, row) => { if (err) reject(err); else resolve(row); } ); }); if (!user) { return res.status(401).json({ error: 'Invalid username or password' }); } if (!user.is_active) { return res.status(401).json({ error: 'Account is disabled' }); } // Verify password const validPassword = await bcrypt.compare(password, user.password_hash); if (!validPassword) { return res.status(401).json({ error: 'Invalid username or password' }); } // Generate session ID const sessionId = crypto.randomBytes(32).toString('hex'); const expiresAt = new Date(Date.now() + 24 * 60 * 60 * 1000); // 24 hours // Create session await new Promise((resolve, reject) => { db.run( 'INSERT INTO sessions (session_id, user_id, expires_at) VALUES (?, ?, ?)', [sessionId, user.id, expiresAt.toISOString()], (err) => { if (err) reject(err); else resolve(); } ); }); // Update last login await new Promise((resolve, reject) => { db.run( 'UPDATE users SET last_login = CURRENT_TIMESTAMP WHERE id = ?', [user.id], (err) => { if (err) reject(err); else resolve(); } ); }); // Set cookie res.cookie('session_id', sessionId, { httpOnly: true, secure: process.env.NODE_ENV === 'production', sameSite: 'lax', maxAge: 24 * 60 * 60 * 1000 // 24 hours }); res.json({ message: 'Login successful', user: { id: user.id, username: user.username, email: user.email, role: user.role } }); } catch (err) { console.error('Login error:', err); res.status(500).json({ error: 'Login failed' }); } }); // Logout router.post('/logout', async (req, res) => { const sessionId = req.cookies?.session_id; if (sessionId) { // Delete session from database await new Promise((resolve) => { db.run( 'DELETE FROM sessions WHERE session_id = ?', [sessionId], () => resolve() ); }); } // Clear cookie res.clearCookie('session_id'); res.json({ message: 'Logged out successfully' }); }); // Get current user router.get('/me', async (req, res) => { const sessionId = req.cookies?.session_id; if (!sessionId) { return res.status(401).json({ error: 'Not authenticated' }); } try { const session = await new Promise((resolve, reject) => { db.get( `SELECT s.*, u.id as user_id, u.username, u.email, u.role, u.is_active FROM sessions s JOIN users u ON s.user_id = u.id WHERE s.session_id = ? AND s.expires_at > datetime('now')`, [sessionId], (err, row) => { if (err) reject(err); else resolve(row); } ); }); if (!session) { res.clearCookie('session_id'); return res.status(401).json({ error: 'Session expired' }); } if (!session.is_active) { res.clearCookie('session_id'); return res.status(401).json({ error: 'Account is disabled' }); } res.json({ user: { id: session.user_id, username: session.username, email: session.email, role: session.role } }); } catch (err) { console.error('Get user error:', err); res.status(500).json({ error: 'Failed to get user' }); } }); // Clean up expired sessions (can be called periodically) router.post('/cleanup-sessions', async (req, res) => { try { await new Promise((resolve, reject) => { db.run( "DELETE FROM sessions WHERE expires_at < datetime('now')", (err) => { if (err) reject(err); else resolve(); } ); }); res.json({ message: 'Expired sessions cleaned up' }); } catch (err) { console.error('Session cleanup error:', err); res.status(500).json({ error: 'Cleanup failed' }); } }); return router; } module.exports = createAuthRouter;