From b7a8d142db9eb71f8bb49c92e1419cfda723a4d2 Mon Sep 17 00:00:00 2001 From: salvacybersec Date: Tue, 11 Nov 2025 05:58:45 +0300 Subject: [PATCH] Fix: Relax Helmet CSP for SPA and improve static file serving --- backend/src/app.js | 45 ++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 42 insertions(+), 3 deletions(-) diff --git a/backend/src/app.js b/backend/src/app.js index 6245a39..1c60495 100644 --- a/backend/src/app.js +++ b/backend/src/app.js @@ -12,8 +12,32 @@ const { apiLimiter } = require('./middlewares/rateLimiter'); const app = express(); const PORT = process.env.PORT || 3000; -// Security middleware -app.use(helmet()); +// Security middleware with relaxed CSP for SPA +app.use( + helmet({ + contentSecurityPolicy: { + directives: { + defaultSrc: ["'self'"], + scriptSrc: [ + "'self'", + "'unsafe-inline'", // Required for Vite HMR and some inline scripts + "'unsafe-eval'", // Required for Vite dev mode + ], + styleSrc: [ + "'self'", + "'unsafe-inline'", // Required for inline styles + ], + imgSrc: ["'self'", "data:", "https:"], + fontSrc: ["'self'", "data:", "https:"], + connectSrc: ["'self'", "https:", "http:", "ws:", "wss:"], // Allow API calls + frameSrc: ["'none'"], + objectSrc: ["'none'"], + upgradeInsecureRequests: [], // Upgrade HTTP to HTTPS if needed + }, + }, + crossOriginEmbedderPolicy: false, // Disable for better compatibility + }) +); // Dynamic CORS configuration // Development: Allow ALL origins (no restrictions) @@ -105,7 +129,22 @@ const path = require('path'); const frontendDistPath = path.join(__dirname, '../../frontend/dist'); const fs = require('fs'); if (fs.existsSync(frontendDistPath)) { - app.use(express.static(frontendDistPath)); + // Serve static files with proper headers for SPA + app.use(express.static(frontendDistPath, { + maxAge: '1y', // Cache static assets + etag: true, + lastModified: true, + setHeaders: (res, path) => { + // Set proper content type for JS/CSS files + if (path.endsWith('.js')) { + res.setHeader('Content-Type', 'application/javascript'); + } else if (path.endsWith('.css')) { + res.setHeader('Content-Type', 'text/css'); + } + // Allow CORS for assets (if needed) + res.setHeader('Access-Control-Allow-Origin', '*'); + }, + })); } // Session middleware