This repository has no description
0

Configure Feed

Select the types of activity you want to include in your feed.

WIP: fixing CORS issue for unknown origins

+25 -39
+25 -39
src/shared/infrastructure/http/app.ts
··· 1 - import express, { Express, Request, Response, NextFunction } from 'express'; 1 + import express, { Express } from 'express'; 2 2 import cors from 'cors'; 3 3 import cookieParser from 'cookie-parser'; 4 4 import { Router } from 'express'; ··· 53 53 const environment = configService.get().environment; 54 54 const allowedOrigins = getAllowedOrigins(); 55 55 const allowedMethods = ['GET', 'POST', 'PUT', 'DELETE']; 56 - 57 - if (environment === Environment.PROD) { 58 - app.use( 59 - cors({ 60 - origin: allowedOrigins, 61 - methods: allowedMethods, 62 - credentials: true, // Required for cookies to work in cross-origin requests 63 - }), 64 - ); 65 - } else { 66 - // DEV/LOCAL: allow credentialed CORS for known origins, open CORS for everyone else. 67 - // Non-allowed origins get '*' which browsers refuse to use with credentials — 68 - // so cookie-auth endpoints naturally fail for them, while read-only endpoints work. 69 - const allowedOriginsSet = new Set(allowedOrigins); 70 - app.use((req: Request, res: Response, next: NextFunction) => { 71 - const origin = req.headers.origin; 72 - 73 - if (typeof origin === 'string' && allowedOriginsSet.has(origin)) { 74 - res.setHeader('Access-Control-Allow-Origin', origin); 75 - res.setHeader('Access-Control-Allow-Credentials', 'true'); 76 - res.setHeader('Vary', 'Origin'); 77 - } else { 78 - res.setHeader('Access-Control-Allow-Origin', '*'); 79 - } 80 - 81 - res.setHeader('Access-Control-Allow-Methods', allowedMethods.join(',')); 82 - res.setHeader( 83 - 'Access-Control-Allow-Headers', 84 - 'Content-Type,Authorization', 85 - ); 86 - 87 - if (req.method === 'OPTIONS') { 88 - res.status(204).end(); 89 - return; 90 - } 56 + const allowedOriginsSet = new Set(allowedOrigins); 91 57 92 - next(); 93 - }); 94 - } 58 + // PROD: strict allowlist only — no open-CORS fallback. 59 + // DEV/LOCAL: credentialed CORS for known origins, open wildcard for everyone else 60 + // so public read endpoints are callable from any third-party origin. 61 + // We use an origin callback rather than a custom middleware to avoid Fly.io's 62 + // proxy rewriting the Origin header and then stripping the reflected ACAO header. 63 + app.use( 64 + cors({ 65 + origin: (origin, callback) => { 66 + if (!origin || allowedOriginsSet.has(origin)) { 67 + // No origin (server-to-server) or known origin: allow with credentials 68 + callback(null, origin || true); 69 + } else if (environment === Environment.PROD) { 70 + // Prod: reject unknown origins entirely 71 + callback(new Error(`Origin ${origin} not allowed`)); 72 + } else { 73 + // DEV/LOCAL: allow unknown origins without credentials (open read access) 74 + callback(null, '*'); 75 + } 76 + }, 77 + credentials: true, 78 + methods: allowedMethods, 79 + }), 80 + ); 95 81 96 82 // Middleware setup 97 83 app.use(cookieParser()); // Parse cookies from incoming requests