import express from 'express'; import session from 'express-session'; import FileStore from 'session-file-store'; import bodyParser from 'body-parser'; import cors from 'cors'; import fs from 'fs'; import path from 'path'; import config from './config.js'; import { initDatabase } from './db.js'; import { initOIDC, isOIDCEnabled } from './middleware/oidcMiddleware.js'; import { requestLogger, securityHeaders, errorHandler, } from './middleware/security.js'; import authRoutes from './routes/authRoutes.js'; import { authCallback } from './controllers/authController.js'; import adminRoutes from './routes/adminRoutes.js'; import dashboardRoutes from './routes/dashboardRoutes.js'; import reverseProxyMiddleware from './middleware/proxyMiddleware.js'; const app = express(); const FileStoreSession = FileStore(session); // Create sessions directory FIRST (before any middleware) try { const sessionsDir = path.join(process.cwd(), 'sessions'); fs.mkdirSync(sessionsDir, { recursive: true }); } catch (error) { console.error('✗ Failed to create sessions directory:', error); process.exit(1); } // Initialize async function initialize() { console.log('🚀 Initializing Secure Proxy...'); // Database initialization try { await initDatabase(config.db.path); console.log('✓ Database initialized'); } catch (error) { console.error('✗ Database initialization failed:', error); process.exit(1); } // OIDC initialization try { await initOIDC(); } catch (error) { console.error('✗ OIDC initialization failed:', error); console.log('⚠️ Running in OIDC-disabled mode for development'); } } // Middleware app.set('trust proxy', 1); app.use(requestLogger); app.use(securityHeaders); app.use(bodyParser.json({ limit: '10mb' })); app.use(bodyParser.urlencoded({ limit: '10mb', extended: true })); app.use(cors({ origin: config.proxyUrl, credentials: true, })); // Session configuration app.use( session({ store: new FileStoreSession({ path: './sessions' }), secret: config.sessionSecret, resave: false, saveUninitialized: false, cookie: { secure: config.nodeEnv === 'production', httpOnly: true, sameSite: 'strict', maxAge: 24 * 60 * 60 * 1000, // 24 hours }, }) ); // Static files app.use(express.static('public')); // Development mode: auto-create session for /admin and /api access app.use((req, res, next) => { // In dev mode without OIDC, create a session automatically if (req.path.startsWith('/admin') || req.path.startsWith('/api') || req.path.startsWith('/dashboard')) { if (!isOIDCEnabled() && !req.session.user) { req.session.user = { sub: 'dev-user-' + Date.now(), name: 'Dev User', email: 'dev@localhost', isAdmin: true, }; } } next(); }); // Routes app.use('/auth', authRoutes); app.use('/api', adminRoutes); app.use('/dashboard', dashboardRoutes); // OAuth callback redirect (Keycloak sends to /callback, not /auth/callback) app.post('/callback', authCallback); // Home page app.get('/', (req, res) => { if (req.session?.user) { res.send(`