require('dotenv').config({ path: '../.env' }); const express = require('express'); const cors = require('cors'); const bcrypt = require('bcrypt'); const jwt = require('jsonwebtoken'); const { Pool } = require('pg'); const morgan = require('morgan'); const authRoutes = require('./routes'); // Log startup configuration console.log('Starting auth server with config:', { host: process.env.DB_HOST, user: process.env.DB_USER, database: process.env.DB_NAME, port: process.env.DB_PORT, auth_port: process.env.AUTH_PORT }); const app = express(); const port = process.env.AUTH_PORT || 3011; // Database configuration const pool = new Pool({ host: process.env.DB_HOST, user: process.env.DB_USER, password: process.env.DB_PASSWORD, database: process.env.DB_NAME, port: process.env.DB_PORT, }); // Make pool available globally global.pool = pool; // Middleware app.use(express.json()); app.use(morgan('combined')); app.use(cors({ origin: ['http://localhost:5173', 'http://localhost:5174', 'https://inventory.kent.pw'], credentials: true })); // Login endpoint app.post('/login', async (req, res) => { const { username, password } = req.body; try { // Get user from database const result = await pool.query( 'SELECT id, username, password, is_admin, is_active FROM users WHERE username = $1', [username] ); const user = result.rows[0]; // Check if user exists and password is correct if (!user || !(await bcrypt.compare(password, user.password))) { return res.status(401).json({ error: 'Invalid username or password' }); } // Check if user is active if (!user.is_active) { return res.status(403).json({ error: 'Account is inactive' }); } // Generate JWT token const token = jwt.sign( { userId: user.id, username: user.username }, process.env.JWT_SECRET, { expiresIn: '24h' } ); // Get user permissions for the response const permissionsResult = await pool.query(` SELECT code FROM permissions p JOIN user_permissions up ON p.id = up.permission_id WHERE up.user_id = $1 `, [user.id]); const permissions = permissionsResult.rows.map(row => row.code); res.json({ token, user: { id: user.id, username: user.username, is_admin: user.is_admin, permissions: user.is_admin ? [] : permissions } }); } catch (error) { console.error('Login error:', error); res.status(500).json({ error: 'Internal server error' }); } }); // User info endpoint app.get('/me', async (req, res) => { const authHeader = req.headers.authorization; if (!authHeader || !authHeader.startsWith('Bearer ')) { return res.status(401).json({ error: 'No token provided' }); } try { const token = authHeader.split(' ')[1]; const decoded = jwt.verify(token, process.env.JWT_SECRET); // Get user details from database const userResult = await pool.query( 'SELECT id, username, email, is_admin, is_active FROM users WHERE id = $1', [decoded.userId] ); if (userResult.rows.length === 0) { return res.status(404).json({ error: 'User not found' }); } const user = userResult.rows[0]; // Get user permissions let permissions = []; if (!user.is_admin) { const permissionsResult = await pool.query(` SELECT code FROM permissions p JOIN user_permissions up ON p.id = up.permission_id WHERE up.user_id = $1 `, [user.id]); permissions = permissionsResult.rows.map(row => row.code); } res.json({ id: user.id, username: user.username, email: user.email, is_admin: user.is_admin, permissions: permissions }); } catch (error) { console.error('Token verification error:', error); res.status(401).json({ error: 'Invalid token' }); } }); // Mount all routes from routes.js app.use('/', authRoutes); // Health check endpoint app.get('/health', (req, res) => { res.json({ status: 'healthy' }); }); // Error handling middleware app.use((err, req, res, next) => { console.error(err.stack); res.status(500).json({ error: 'Something broke!' }); }); // Start server app.listen(port, () => { console.log(`Auth server running on port ${port}`); });