import express from 'express'; import helmet from 'helmet'; import morgan from 'morgan'; import dotenv from 'dotenv'; import cookieParser from 'cookie-parser'; import { UserService } from './services/user.service'; import { SSOUserData } from './types/auth.types'; import { sequelize } from './config/database'; import { corsMiddleware } from './middlewares/cors.middleware'; import { metricsMiddleware, createMetricsRouter } from './middlewares/metrics.middleware'; import routes from './routes/index'; import { ensureUploadDir, UPLOAD_DIR } from './config/storage'; import { initializeGoogleSecretManager } from './services/googleSecretManager.service'; import path from 'path'; // Load environment variables from .env file first dotenv.config(); // Secrets are now initialized in server.ts before app is imported const app: express.Application = express(); // 1. Security middleware - Manual "Gold Standard" CSP to ensure it survives 301/404/etc. // This handles a specific Express/Helmet edge case where redirects lose headers. app.use((req: express.Request, res: express.Response, next: express.NextFunction) => { const isDev = process.env.NODE_ENV !== 'production'; const frontendUrl = process.env.FRONTEND_URL || 'http://localhost:3000'; // Build connect-src dynamically const connectSrc = ["'self'", "blob:", "data:"]; if (isDev) { connectSrc.push("http://localhost:3000", "http://localhost:5000", "ws://localhost:3000", "ws://localhost:5000"); if (frontendUrl.includes('localhost')) connectSrc.push(frontendUrl); } else if (frontendUrl && frontendUrl !== '*') { const origins = frontendUrl.split(',').map(url => url.trim()).filter(Boolean); connectSrc.push(...origins); } // Define strict CSP directives const directives = [ "default-src 'none'", // sha256-47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU= is for empty