// Firefrost Arbiter v2.0.0 // Discord Role Management & OAuth Gateway // Built: March 30, 2026 const VERSION = '2.0.0'; require('dotenv').config(); const express = require('express'); const session = require('express-session'); const SQLiteStore = require('connect-sqlite3')(session); const rateLimit = require('express-rate-limit'); const { client } = require('./discordService'); const db = require('./database'); const app = express(); const PORT = process.env.PORT || 3500; // Trust reverse proxy (Nginx) for secure cookies app.set('trust proxy', 1); // Middleware - Body Parsers app.use(express.json()); app.use(express.urlencoded({ extended: true })); // Middleware - Session Configuration app.use(session({ store: new SQLiteStore({ db: 'sessions.db', dir: './' }), secret: process.env.SESSION_SECRET, resave: false, saveUninitialized: false, cookie: { secure: process.env.NODE_ENV === 'production', // true if HTTPS httpOnly: true, maxAge: 1000 * 60 * 60 * 24 * 7 // 1 week } })); // Middleware - Rate Limiting const apiLimiter = rateLimit({ windowMs: 15 * 60 * 1000, // 15 minutes max: 100, // Limit each IP to 100 requests per window message: 'Too many requests from this IP, please try again after 15 minutes', standardHeaders: true, legacyHeaders: false, }); // Apply rate limiting to specific routes app.use('/auth', apiLimiter); app.use('/webhook', apiLimiter); app.use('/admin/api', apiLimiter); // Routes app.use('/webhook', require('./routes/webhook')); app.use('/auth', require('./routes/oauth')); app.use('/admin', require('./routes/adminAuth')); app.use('/admin', require('./routes/admin')); // Health Check Endpoint app.get('/health', async (req, res) => { let dbStatus = 'down'; try { db.prepare('SELECT 1').get(); dbStatus = 'ok'; } catch (e) { console.error('[Health] Database check failed:', e); } const status = { uptime: process.uptime(), discord: client.isReady() ? 'ok' : 'down', database: dbStatus, timestamp: new Date().toISOString() }; const httpStatus = (status.discord === 'ok' && status.database === 'ok') ? 200 : 503; res.status(httpStatus).json(status); }); // Root endpoint app.get('/', (req, res) => { res.send('Firefrost Arbiter - Discord Role Management System'); }); // Start Server app.listen(PORT, () => { console.log(`[Server] Listening on port ${PORT}`); console.log(`[Server] Environment: ${process.env.NODE_ENV || 'development'}`); console.log(`[Server] Health check: http://localhost:${PORT}/health`); }); // Discord Bot Ready Event client.on('ready', () => { console.log(`[Discord] Bot ready as ${client.user.tag}`); }); // Graceful Shutdown process.on('SIGTERM', () => { console.log('[Server] SIGTERM received, shutting down gracefully...'); client.destroy(); process.exit(0); });