22 * Shared utilities for Connect demo API routes
33 */
44
5- // Allowed origins for CORS security
6- export const ALLOWED_ORIGINS = [
7- "https://pipedream.com" ,
8- "https://www.pipedream.com" ,
9- "http://localhost:3000" , // For local development
10- ] ;
5+ /**
6+ * Get allowed origins from environment variables or use defaults
7+ * This supports Vercel preview deployments with their dynamic URLs
8+ */
9+ export function getAllowedOrigins ( ) {
10+ // Get from environment if defined
11+ const originsFromEnv = process . env . ALLOWED_ORIGINS
12+ ? process . env . ALLOWED_ORIGINS . split ( "," ) . map ( ( origin ) => origin . trim ( ) )
13+ : [ ] ;
14+
15+ // Default allowed origins
16+ const defaultOrigins = [
17+ "https://pipedream.com" ,
18+ "https://www.pipedream.com" ,
19+ "http://localhost:3000" , // For local development
20+ ] ;
21+
22+ // Vercel preview deployment support - match any Vercel preview URL
23+ const vercelPreviewRegexes = [
24+ / ^ h t t p s : \/ \/ [ a - z A - Z 0 - 9 - ] + - [ a - z A - Z 0 - 9 - ] + - [ a - z A - Z 0 - 9 - ] + \. v e r c e l \. a p p $ / ,
25+ ] ;
26+
27+ return {
28+ originsList : [
29+ ...defaultOrigins ,
30+ ...originsFromEnv ,
31+ ] ,
32+ regexPatterns : vercelPreviewRegexes ,
33+
34+ // Helper method to check if an origin is allowed
35+ isAllowed ( origin ) {
36+ if ( ! origin ) return false ;
37+
38+ // Check exact matches
39+ if ( this . originsList . includes ( origin ) ) return true ;
40+
41+ // Check regex patterns
42+ return this . regexPatterns . some ( ( pattern ) => pattern . test ( origin ) ) ;
43+ } ,
44+ } ;
45+ }
46+
47+ // Export the helper for consistent use
48+ export const ALLOWED_ORIGINS = getAllowedOrigins ( ) ;
1149
1250/**
1351 * Generate a browser-specific token based on request properties
@@ -22,9 +60,10 @@ export function generateRequestToken(req) {
2260 * Sets CORS headers for API responses
2361 */
2462export function setCorsHeaders ( req , res , methods = "GET, POST, OPTIONS" ) {
63+ // Use the new isAllowed method to check if the origin is allowed
2564 res . setHeader (
2665 "Access-Control-Allow-Origin" ,
27- ALLOWED_ORIGINS . includes ( req . headers . origin )
66+ ALLOWED_ORIGINS . isAllowed ( req . headers . origin )
2867 ? req . headers . origin
2968 : "" ,
3069 ) ;
@@ -42,16 +81,21 @@ export function validateRequest(req, res, allowedMethod) {
4281 const requestToken = req . headers [ "x-request-token" ] ;
4382
4483 // Origin validation
45- if ( origin && ! ALLOWED_ORIGINS . includes ( origin ) ) {
84+ if ( origin && ! ALLOWED_ORIGINS . isAllowed ( origin ) ) {
4685 return res . status ( 403 ) . json ( {
4786 error : "Access denied" ,
4887 } ) ;
4988 }
5089
51- // Referer validation
90+ // Referer validation for docs context
5291 if (
5392 referer &&
54- ! ALLOWED_ORIGINS . some ( ( allowed ) => referer . startsWith ( allowed ) ) &&
93+ // Check if referer starts with any allowed origin
94+ ! ALLOWED_ORIGINS . originsList . some ( ( allowed ) => referer . startsWith ( allowed ) ) &&
95+ // Check if referer matches any regex pattern
96+ ! ALLOWED_ORIGINS . regexPatterns . some ( ( pattern ) =>
97+ pattern . test ( referer . split ( "/" ) [ 0 ] + "//" + referer . split ( "/" ) [ 2 ] ) ) &&
98+ // Allow if it contains the docs path
5599 ! referer . includes ( "/docs/connect/" )
56100 ) {
57101 return res . status ( 403 ) . json ( {
0 commit comments