165 lines
4.2 KiB
JavaScript
165 lines
4.2 KiB
JavaScript
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}`);
|
|
});
|