@@ -32,14 +32,18 @@ app.use(requestIdMiddleware);
3232app . disable ( 'x-powered-by' ) ;
3333
3434// Helmet-equivalent core headers without external dependency.
35+ // Strict CSP applied globally; the /api-docs route overrides it below for Swagger UI.
3536app . use ( ( req : Request , res : Response , next : NextFunction ) => {
3637 res . setHeader ( 'X-Content-Type-Options' , 'nosniff' ) ;
3738 res . setHeader ( 'X-Frame-Options' , 'DENY' ) ;
3839 res . setHeader ( 'Referrer-Policy' , 'no-referrer' ) ;
3940 res . setHeader ( 'X-DNS-Prefetch-Control' , 'off' ) ;
4041 res . setHeader ( 'X-Download-Options' , 'noopen' ) ;
4142 res . setHeader ( 'X-Permitted-Cross-Domain-Policies' , 'none' ) ;
42- if ( isProduction ) {
43+ res . setHeader ( 'Content-Security-Policy' , "default-src 'self'; script-src 'self'; style-src 'self'; img-src 'self' data:; frame-ancestors 'none'; object-src 'none'" ) ;
44+ res . setHeader ( 'Cross-Origin-Opener-Policy' , 'same-origin' ) ;
45+ res . setHeader ( 'Cross-Origin-Resource-Policy' , 'same-origin' ) ;
46+ if ( process . env . NODE_ENV === 'production' ) {
4347 res . setHeader ( 'Strict-Transport-Security' , 'max-age=31536000; includeSubDomains' ) ;
4448 }
4549 next ( ) ;
@@ -78,7 +82,11 @@ app.use(express.json({ limit: '1mb' }));
7882app . use ( sandboxMiddleware ) ;
7983
8084// Swagger UI setup
81- app . use ( '/api-docs' , swaggerUi . serve , swaggerUi . setup ( swaggerSpec , {
85+ // Override CSP for /api-docs only: Swagger UI requires inline scripts/styles.
86+ app . use ( '/api-docs' , ( req : Request , res : Response , next : NextFunction ) => {
87+ res . setHeader ( 'Content-Security-Policy' , "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; frame-ancestors 'none'; object-src 'none'" ) ;
88+ next ( ) ;
89+ } , swaggerUi . serve , swaggerUi . setup ( swaggerSpec , {
8290 customCss : '.swagger-ui .topbar { display: none }' ,
8391 customSiteTitle : 'FlowFi API Documentation' ,
8492} ) ) ;
@@ -105,35 +113,6 @@ app.use((req: Request, res: Response, next: NextFunction) => {
105113 return next ( ) ; // Not versioned, continue to deprecated handlers
106114} ) ;
107115
108- // Legacy routes (deprecated - redirect to v1)
109- // These will be removed in a future version
110- // Only match unversioned requests
111- app . use ( '/streams' , ( req : Request , res : Response , next ) => {
112- res . status ( 410 ) . json ( {
113- error : 'Deprecated endpoint' ,
114- message : 'This endpoint has been deprecated. Please use /v1/streams instead.' ,
115- deprecated : true ,
116- migration : {
117- old : '/streams' ,
118- new : '/v1/streams' ,
119- } ,
120- sunsetDate : '2024-12-31' ,
121- } ) ;
122- } ) ;
123-
124- app . use ( '/events' , ( req : Request , res : Response , next ) => {
125- res . status ( 410 ) . json ( {
126- error : 'Deprecated endpoint' ,
127- message : 'This endpoint has been deprecated. Please use /v1/events instead.' ,
128- deprecated : true ,
129- migration : {
130- old : '/events' ,
131- new : '/v1/events' ,
132- } ,
133- sunsetDate : '2024-12-31' ,
134- } ) ;
135- } ) ;
136-
137116// Health check routes
138117app . use ( '/health' , healthRoutes ) ;
139118
0 commit comments