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; // Damit Nginx + HTTPS korrekt funktioniert app.set('trust proxy', 1); // ── Security headers ────────────────────────────────── // CSP deaktiviert — inline scripts und onclick werden sonst vom Browser geblockt // Sicher weil self-hosted und kein user-generated HTML gerendert wird app.use(helmet({ contentSecurityPolicy: false, })); // ── 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: false, // Nginx macht HTTPS, Node sieht nur HTTP intern 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 */ } } });