import express from 'express'; import cookieParser from 'cookie-parser'; import { fileURLToPath } from 'url'; import { dirname, join } from 'path'; import ejsLayouts from 'express-ejs-layouts'; import logger from '../utils/logger.js'; import { requireAuth, handleLogin, handleLogout } from './auth.js'; import { csrfMiddleware, validateCsrf, validateCsrfFromBody } from './csrf.js'; import { asyncHandler, globalErrorHandler } from './errorHandler.js'; import dashboardRouter from './routes/dashboard.js'; import catalogRouter from './routes/catalog.js'; import catalogProductsRouter from './routes/catalogProducts.js'; import usersRouter from './routes/users.js'; import productsRouter from './routes/products.js'; import walletsRouter from './routes/wallets.js'; import purchasesRouter from './routes/purchases.js'; import auditRouter from './routes/audit.js'; import settingsRouter from './routes/settings.js'; import categoriesRouter from './routes/categories.js'; import paymentWalletsRouter from './routes/paymentWallets.js'; import locationsRouter from './routes/locations.js'; import seedRouter from './routes/seed.js'; import localesRouter from './routes/locales.js'; const __dirname = dirname(fileURLToPath(import.meta.url)); const app = express(); // Configure EJS as view engine with layouts app.set('view engine', 'ejs'); app.set('views', join(__dirname, 'views')); app.use(ejsLayouts); app.set('layout', 'layout'); app.use(cookieParser()); app.use(express.urlencoded({ extended: true })); app.use(express.json()); // Serve static assets from public directory app.use(express.static(join(__dirname, 'public'))); app.get('/health', (req, res) => { res.json({ status: 'ok', uptime: process.uptime() }); }); app.get('/login', (req, res) => { res.render('auth-login', { error: null, layout: false, pageTitle: 'Login' }); }); app.post('/login', handleLogin); app.get('/logout', handleLogout); // CSRF token for all authenticated views app.use(csrfMiddleware); app.use(requireAuth); // Apply CSRF validation to all state-changing routes app.use(validateCsrf); // Protect uploads behind auth with MIME hardening app.use('/uploads', express.static(join(__dirname, '..', '..', 'uploads'), { setHeaders: (res, path) => { res.setHeader('X-Content-Type-Options', 'nosniff'); res.setHeader('Content-Disposition', 'attachment'); } })); app.use('/', dashboardRouter); app.use('/catalog', catalogRouter); app.use('/catalog', catalogProductsRouter); app.use('/users', usersRouter); app.use('/products', productsRouter); app.use('/wallets', walletsRouter); app.use('/purchases', purchasesRouter); app.use('/audit', auditRouter); app.use('/settings', settingsRouter); app.use('/categories', categoriesRouter); app.use('/locations', locationsRouter); app.use('/payment-wallets', paymentWalletsRouter); app.use('/seed', seedRouter); app.use('/locales', localesRouter); // Global error handler app.use(globalErrorHandler); export function startAdminPanel() { const port = parseInt(process.env.ADMIN_PORT || '3001', 10); app.listen(port, () => { logger.info({ port }, 'Admin panel started'); }); }