fix: static files before routes, fix CSP for assets and Cloudflare, SPA fallback safety
Build Institutional Trader / build-and-deploy (push) Successful in 1m57s
Details
Build Institutional Trader / build-and-deploy (push) Successful in 1m57s
Details
This commit is contained in:
parent
78b408057c
commit
7344d5a2b1
|
|
@ -9,10 +9,15 @@ export const setupSecurity = (app) => {
|
||||||
directives: {
|
directives: {
|
||||||
defaultSrc: ["'self'"],
|
defaultSrc: ["'self'"],
|
||||||
styleSrc: ["'self'", "'unsafe-inline'"],
|
styleSrc: ["'self'", "'unsafe-inline'"],
|
||||||
scriptSrc: ["'self'"],
|
scriptSrc: ["'self'", "'unsafe-inline'", 'https://static.cloudflareinsights.com'],
|
||||||
|
scriptSrcElem: ["'self'", "'unsafe-inline'", 'https://static.cloudflareinsights.com'],
|
||||||
imgSrc: ["'self'", 'data:', 'https:'],
|
imgSrc: ["'self'", 'data:', 'https:'],
|
||||||
|
connectSrc: ["'self'", 'https:', 'wss:'],
|
||||||
|
workerSrc: ["'self'", 'blob:'],
|
||||||
|
fontSrc: ["'self'", 'https:', 'data:'],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
crossOriginEmbedderPolicy: false,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
// CORS
|
// CORS
|
||||||
|
|
|
||||||
|
|
@ -46,6 +46,17 @@ setupSecurity(app);
|
||||||
// Body parsing
|
// Body parsing
|
||||||
app.use(express.json());
|
app.use(express.json());
|
||||||
|
|
||||||
|
// Serve static frontend files in production
|
||||||
|
const __filename = fileURLToPath(import.meta.url);
|
||||||
|
const __dirname = path.dirname(__filename);
|
||||||
|
const frontendPath = path.join(__dirname, '../../public');
|
||||||
|
|
||||||
|
// Static files MUST come before the wildcard catch-all
|
||||||
|
app.use(express.static(frontendPath, {
|
||||||
|
maxAge: '1d',
|
||||||
|
etag: true,
|
||||||
|
}));
|
||||||
|
|
||||||
// Routes
|
// Routes
|
||||||
app.use('/api/options', optionsFlowRouter);
|
app.use('/api/options', optionsFlowRouter);
|
||||||
app.use('/api/analysis', dailyAnalysisRouter);
|
app.use('/api/analysis', dailyAnalysisRouter);
|
||||||
|
|
@ -61,19 +72,15 @@ app.use('/api/market', marketAnalysisRouter);
|
||||||
app.use('/api/backtest', backtestRouter);
|
app.use('/api/backtest', backtestRouter);
|
||||||
app.use('/health', healthRouter);
|
app.use('/health', healthRouter);
|
||||||
|
|
||||||
// Serve static frontend files in production
|
// SPA fallback — only for non-API, non-asset routes
|
||||||
const __filename = fileURLToPath(import.meta.url);
|
|
||||||
const __dirname = path.dirname(__filename);
|
|
||||||
const frontendPath = path.join(__dirname, '../../public');
|
|
||||||
|
|
||||||
app.use(express.static(frontendPath));
|
|
||||||
|
|
||||||
// Fallback all other routes to React's index.html
|
|
||||||
app.get('*', (req, res, next) => {
|
app.get('*', (req, res, next) => {
|
||||||
if (req.path.startsWith('/api/') || req.path.startsWith('/health')) {
|
if (req.path.startsWith('/api/') || req.path.startsWith('/health') || req.path.startsWith('/assets/')) {
|
||||||
return next();
|
return next();
|
||||||
}
|
}
|
||||||
res.sendFile(path.join(frontendPath, 'index.html'));
|
const indexPath = path.join(frontendPath, 'index.html');
|
||||||
|
res.sendFile(indexPath, (err) => {
|
||||||
|
if (err) next(err);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// Error handler (must be last)
|
// Error handler (must be last)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue