require('dotenv').config(); const express = require('express'); const session = require('express-session'); const passport = require('passport'); const helmet = require('helmet'); const path = require('path'); const db = require('./db'); const authRoutes = require('./routes/auth'); const apiRoutes = require('./routes/api'); const adminRoutes = require('./routes/admin'); const app = express(); const PORT = process.env.PORT || 3000; // ── Security headers ────────────────────────────────── app.use(helmet({ contentSecurityPolicy: { directives: { defaultSrc: ["'self'"], scriptSrc: ["'self'", "'unsafe-inline'", "fonts.googleapis.com"], styleSrc: ["'self'", "'unsafe-inline'", "fonts.googleapis.com", "fonts.gstatic.com"], fontSrc: ["'self'", "fonts.gstatic.com", "fonts.googleapis.com"], imgSrc: ["'self'", "data:", "cdn.discordapp.com"], connectSrc: ["'self'", "discord.com"], }, }, })); // ── Body parsers ────────────────────────────────────── app.use(express.json()); app.use(express.urlencoded({ extended: true })); // ── Session with MySQL store ────────────────────────── const MySQLStore = require('express-mysql-session')(session); app.use(session({ secret: process.env.SESSION_SECRET, resave: false, saveUninitialized: false, store: new MySQLStore({ host: process.env.DB_HOST, port: parseInt(process.env.DB_PORT) || 3306, database: process.env.DB_NAME, user: process.env.DB_USER, password: process.env.DB_PASS, createDatabaseTable: true, }), cookie: { maxAge: 7 * 24 * 60 * 60 * 1000, // 7 Tage secure: process.env.NODE_ENV === 'production', httpOnly: true, sameSite: 'lax', }, })); // ── Passport ────────────────────────────────────────── require('./middleware/passport')(passport); app.use(passport.initialize()); app.use(passport.session()); // ── Static files ────────────────────────────────────── app.use(express.static(path.join(__dirname, 'public'))); // ── Routes ──────────────────────────────────────────── app.use('/auth', authRoutes); app.use('/api', apiRoutes); app.use('/admin', adminRoutes); // ── SPA fallback ────────────────────────────────────── app.get('*', (req, res) => { res.sendFile(path.join(__dirname, 'public', 'index.html')); }); // ── Start ───────────────────────────────────────────── app.listen(PORT, async () => { console.log(`\n🎃 Blair Dashboard läuft auf http://localhost:${PORT}`); console.log(` Modus: ${process.env.NODE_ENV || 'development'}\n`); // Owner automatisch als Admin eintragen (falls noch nicht vorhanden) if (process.env.OWNER_DISCORD_ID) { try { await db.query( 'INSERT IGNORE INTO admin_whitelist (discord_id, discord_username, added_by) VALUES (?, ?, ?)', [process.env.OWNER_DISCORD_ID, process.env.OWNER_DISCORD_NAME || 'Owner', 'system'] ); } catch (e) { /* ignore */ } } });