/** * Admin Auth Controller - Independent Admin Authentication */ const bcrypt = require('bcryptjs'); const jwt = require('jsonwebtoken'); const { getPool } = require('../db'); const ADMIN_JWT_SECRET = process.env.ADMIN_JWT_SECRET; const JWT_EXPIRES_IN = '8h'; // Longer session for admins const JWT_REFRESH_EXPIRES_IN = '30d'; // Security check: Ensure ADMIN_JWT_SECRET is configured if (!ADMIN_JWT_SECRET) { console.error('⚠️ SECURITY WARNING: ADMIN_JWT_SECRET environment variable is not set!'); if (process.env.NODE_ENV === 'production') { console.error('❌ FATAL: Cannot run in production without ADMIN_JWT_SECRET'); process.exit(1); } } /** * Generate JWT tokens for Admin (matching UserService shape) */ function generateTokens(admin) { const accessToken = jwt.sign( { id: admin.id, username: admin.username, email: admin.email, role: 'admin', permissions: admin.permissions }, ADMIN_JWT_SECRET, { expiresIn: JWT_EXPIRES_IN } ); const refreshToken = jwt.sign( { id: admin.id, type: 'refresh' }, ADMIN_JWT_SECRET, { expiresIn: JWT_REFRESH_EXPIRES_IN } ); return { accessToken, refreshToken }; } /** * Register Admin */ async function register(req, res) { const { username, email, password, name } = req.body; const pool = getPool(); if (!pool) return res.status(500).json({ error: 'Database not connected' }); try { const existing = await pool.query('SELECT id FROM admins WHERE email = $1 OR username = $2', [email, username]); if (existing.rows.length > 0) { return res.status(400).json({ error: 'Admin already exists' }); } const hashedPassword = await bcrypt.hash(password, 12); const result = await pool.query( 'INSERT INTO admins (username, email, password_hash, name, permissions) VALUES ($1, $2, $3, $4, $5) RETURNING id, username, email, name, permissions', [username, email, hashedPassword, name, JSON.stringify(['all'])] ); const admin = result.rows[0]; const tokens = generateTokens(admin); res.status(201).json({ admin, tokens }); } catch (error) { console.error('[Admin Register Error]', error.message); res.status(500).json({ error: 'Failed to register admin' }); } } /** * Login Admin */ async function login(req, res) { const { email, password } = req.body; const pool = getPool(); if (!pool) return res.status(500).json({ error: 'Database not connected' }); try { const result = await pool.query('SELECT * FROM admins WHERE email = $1', [email]); if (result.rows.length === 0) { return res.status(401).json({ error: 'Invalid credentials' }); } const admin = result.rows[0]; const valid = await bcrypt.compare(password, admin.password_hash); if (!valid) { return res.status(401).json({ error: 'Invalid credentials' }); } const tokens = generateTokens(admin); delete admin.password_hash; res.json({ admin, tokens }); } catch (error) { console.error('[Admin Login Error]', error.message); res.status(500).json({ error: 'Login failed' }); } } /** * Get current admin profile */ async function getMe(req, res) { const pool = getPool(); try { const result = await pool.query('SELECT id, username, email, name, permissions FROM admins WHERE id = $1', [req.user.id]); if (result.rows.length === 0) return res.status(404).json({ error: 'Admin not found' }); res.json({ admin: result.rows[0] }); } catch (error) { res.status(500).json({ error: 'Failed to fetch profile' }); } } module.exports = { register, login, getMe };