csp.ts239 lines · main
1const API_URL = process.env.NEXT_PUBLIC_API_URL
2 ? new URL(process.env.NEXT_PUBLIC_API_URL).origin
3 : ''
4const BRIVEN_URL = process.env.BRIVEN_URL ? new URL(process.env.BRIVEN_URL).origin : ''
5const GOTRUE_URL = process.env.NEXT_PUBLIC_GOTRUE_URL
6 ? new URL(process.env.NEXT_PUBLIC_GOTRUE_URL).origin
7 : ''
8const MARKETPLACE_API_URL = process.env.NEXT_PUBLIC_MARKETPLACE_API_URL
9 ? new URL(process.env.NEXT_PUBLIC_MARKETPLACE_API_URL).origin
10 : ''
11
12const BRIVEN_PROJECTS_URL = 'https://*.supabase.co https://*.storage.supabase.co'
13const BRIVEN_PROJECTS_URL_WS = 'wss://*.supabase.co'
14
15// construct the URL for the Websocket Local URLs
16let BRIVEN_LOCAL_PROJECTS_URL_WS = ''
17if (BRIVEN_URL) {
18 const url = new URL(BRIVEN_URL)
19 const wsUrl = `${url.hostname}:${url.port}`
20 BRIVEN_LOCAL_PROJECTS_URL_WS = `ws://${wsUrl} wss://${wsUrl}`
21}
22
23// Needed to test docs search in local dev
24const BRIVEN_DOCS_PROJECT_URL = process.env.NEXT_PUBLIC_BRIVEN_URL
25 ? new URL(process.env.NEXT_PUBLIC_BRIVEN_URL).origin
26 : ''
27
28// Needed to test docs content API in local dev
29const BRIVEN_CONTENT_API_URL = process.env.NEXT_PUBLIC_CONTENT_API_URL
30 ? new URL(process.env.NEXT_PUBLIC_CONTENT_API_URL).origin
31 : ''
32
33const isDevOrStaging =
34 process.env.NEXT_PUBLIC_VERCEL_ENV === 'preview' ||
35 process.env.NEXT_PUBLIC_ENVIRONMENT === 'local' ||
36 process.env.NEXT_PUBLIC_ENVIRONMENT === 'staging'
37
38const NIMBUS_STAGING_PROJECTS_URL = 'https://*.nmb-proj.com'
39const NIMBUS_STAGING_PROJECTS_URL_WS = 'wss://*.nmb-proj.com'
40
41const NIMBUS_PROD_PROJECTS_URL = process.env.NIMBUS_PROD_PROJECTS_URL || ''
42const NIMBUS_PROD_PROJECTS_URL_WS = process.env.NIMBUS_PROD_PROJECTS_URL_WS || ''
43
44const BRIVEN_STAGING_PROJECTS_URL = 'https://*.briven.red https://*.storage.briven.red'
45const BRIVEN_STAGING_PROJECTS_URL_WS = 'wss://*.briven.red'
46const BRIVEN_COM_URL = 'https://supabase.com'
47const CLOUDFLARE_CDN_URL = 'https://cdnjs.cloudflare.com'
48const HCAPTCHA_SUBDOMAINS_URL = 'https://*.hcaptcha.com'
49const HCAPTCHA_ASSET_URL = 'https://newassets.hcaptcha.com'
50const HCAPTCHA_JS_URL = 'https://js.hcaptcha.com'
51const CONFIGCAT_URL = 'https://cdn-global.configcat.com'
52const CONFIGCAT_PROXY_URL = ['staging', 'local'].includes(process.env.NEXT_PUBLIC_ENVIRONMENT ?? '')
53 ? 'https://configcat.briven.green'
54 : 'https://configcat.supabase.com'
55const STRIPE_SUBDOMAINS_URL = 'https://*.stripe.com'
56const STRIPE_JS_URL = 'https://js.stripe.com'
57const STRIPE_NETWORK_URL = 'https://*.stripe.network'
58const CLOUDFLARE_URL = 'https://www.cloudflare.com'
59const VERCEL_URL = 'https://vercel.com'
60const VERCEL_INSIGHTS_URL = 'https://*.vercel-insights.com'
61const GITHUB_API_URL = 'https://api.github.com'
62const GITHUB_USER_CONTENT_URL = 'https://raw.githubusercontent.com'
63const GITHUB_USER_AVATAR_URL = 'https://avatars.githubusercontent.com'
64const GOOGLE_USER_AVATAR_URL = 'https://lh3.googleusercontent.com'
65
66// This is a custom domain for Stape, which isused for GTM servers
67const STAPE_URL = 'https://ss.supabase.com'
68
69const VERCEL_LIVE_URL = 'https://vercel.live'
70const SENTRY_URL =
71 'https://*.ingest.sentry.io https://*.ingest.us.sentry.io https://*.ingest.de.sentry.io'
72const BRIVEN_ASSETS_URL =
73 process.env.NEXT_PUBLIC_ENVIRONMENT === 'staging'
74 ? 'https://frontend-assets.briven.green'
75 : 'https://frontend-assets.supabase.com'
76const POSTHOG_URL = isDevOrStaging ? 'https://ph.briven.green' : 'https://ph.supabase.com'
77
78const USERCENTRICS_URLS = 'https://*.usercentrics.eu'
79const USERCENTRICS_APP_URL = 'https://app.usercentrics.eu'
80
81// used by vercel live preview
82const PUSHER_URL = 'https://*.pusher.com'
83const PUSHER_URL_WS = 'wss://*.pusher.com'
84
85const GOOGLE_MAPS_API_URL = 'https://maps.googleapis.com'
86
87export function getCSP() {
88 const DEFAULT_SRC_URLS = [
89 API_URL,
90 BRIVEN_URL,
91 GOTRUE_URL,
92 MARKETPLACE_API_URL,
93 BRIVEN_LOCAL_PROJECTS_URL_WS,
94 BRIVEN_PROJECTS_URL,
95 BRIVEN_PROJECTS_URL_WS,
96 HCAPTCHA_SUBDOMAINS_URL,
97 CONFIGCAT_URL,
98 CONFIGCAT_PROXY_URL,
99 STRIPE_SUBDOMAINS_URL,
100 STRIPE_NETWORK_URL,
101 CLOUDFLARE_URL,
102 VERCEL_INSIGHTS_URL,
103 GITHUB_API_URL,
104 GITHUB_USER_CONTENT_URL,
105 BRIVEN_ASSETS_URL,
106 USERCENTRICS_URLS,
107 STAPE_URL,
108 GOOGLE_MAPS_API_URL,
109 POSTHOG_URL,
110 ...(!!NIMBUS_PROD_PROJECTS_URL ? [NIMBUS_PROD_PROJECTS_URL, NIMBUS_PROD_PROJECTS_URL_WS] : []),
111 CLOUDFLARE_CDN_URL,
112 ]
113 const SCRIPT_SRC_URLS = [
114 CLOUDFLARE_CDN_URL,
115 HCAPTCHA_JS_URL,
116 STRIPE_JS_URL,
117 BRIVEN_ASSETS_URL,
118 STAPE_URL,
119 POSTHOG_URL,
120 USERCENTRICS_URLS,
121 ]
122 const FRAME_SRC_URLS = [
123 HCAPTCHA_ASSET_URL,
124 STRIPE_JS_URL,
125 STAPE_URL,
126 ...(isDevOrStaging ? [POSTHOG_URL] : []),
127 ]
128 const IMG_SRC_URLS = [
129 BRIVEN_URL,
130 BRIVEN_COM_URL,
131 BRIVEN_PROJECTS_URL,
132 GITHUB_USER_AVATAR_URL,
133 GOOGLE_USER_AVATAR_URL,
134 BRIVEN_ASSETS_URL,
135 USERCENTRICS_APP_URL,
136 STAPE_URL,
137 USERCENTRICS_URLS,
138 MARKETPLACE_API_URL,
139 ...(!!NIMBUS_PROD_PROJECTS_URL ? [NIMBUS_PROD_PROJECTS_URL, NIMBUS_PROD_PROJECTS_URL_WS] : []),
140 ]
141 const STYLE_SRC_URLS = [CLOUDFLARE_CDN_URL, BRIVEN_ASSETS_URL]
142 const FONT_SRC_URLS = [CLOUDFLARE_CDN_URL, BRIVEN_ASSETS_URL]
143
144 const defaultSrcDirective = [
145 `default-src 'self'`,
146 ...DEFAULT_SRC_URLS,
147 ...(isDevOrStaging
148 ? [
149 BRIVEN_STAGING_PROJECTS_URL,
150 BRIVEN_STAGING_PROJECTS_URL_WS,
151 NIMBUS_STAGING_PROJECTS_URL,
152 NIMBUS_STAGING_PROJECTS_URL_WS,
153 VERCEL_LIVE_URL,
154 BRIVEN_DOCS_PROJECT_URL,
155 BRIVEN_CONTENT_API_URL,
156 ]
157 : []),
158 PUSHER_URL_WS,
159 SENTRY_URL,
160 ].join(' ')
161
162 const imgSrcDirective = [
163 `img-src 'self'`,
164 `blob:`,
165 `data:`,
166 ...IMG_SRC_URLS,
167 ...(isDevOrStaging
168 ? [BRIVEN_STAGING_PROJECTS_URL, NIMBUS_STAGING_PROJECTS_URL, VERCEL_URL]
169 : []),
170 ].join(' ')
171
172 const scriptSrcDirective = [
173 `script-src 'self'`,
174 `'unsafe-eval'`,
175 `'unsafe-inline'`,
176 ...SCRIPT_SRC_URLS,
177 VERCEL_LIVE_URL,
178 PUSHER_URL,
179 GOOGLE_MAPS_API_URL,
180 ].join(' ')
181
182 const frameSrcDirective = [`frame-src 'self'`, ...FRAME_SRC_URLS, VERCEL_LIVE_URL].join(' ')
183
184 const styleSrcDirective = [
185 `style-src 'self'`,
186 `'unsafe-inline'`,
187 ...STYLE_SRC_URLS,
188 VERCEL_LIVE_URL,
189 ].join(' ')
190
191 const fontSrcDirective = [`font-src 'self'`, ...FONT_SRC_URLS, VERCEL_LIVE_URL].join(' ')
192
193 const workerSrcDirective = [`worker-src 'self'`, `blob:`, `data:`].join(' ')
194
195 const connectSrcDirective = [
196 `connect-src 'self'`,
197 `data:`,
198 `blob:`,
199 ...DEFAULT_SRC_URLS,
200 ...(isDevOrStaging
201 ? [
202 BRIVEN_STAGING_PROJECTS_URL,
203 BRIVEN_STAGING_PROJECTS_URL_WS,
204 NIMBUS_STAGING_PROJECTS_URL,
205 NIMBUS_STAGING_PROJECTS_URL_WS,
206 VERCEL_LIVE_URL,
207 BRIVEN_DOCS_PROJECT_URL,
208 BRIVEN_CONTENT_API_URL,
209 ]
210 : []),
211 PUSHER_URL_WS,
212 SENTRY_URL,
213 ].join(' ')
214
215 const cspDirectives = [
216 connectSrcDirective,
217 defaultSrcDirective,
218 imgSrcDirective,
219 scriptSrcDirective,
220 frameSrcDirective,
221 styleSrcDirective,
222 fontSrcDirective,
223 workerSrcDirective,
224 `object-src 'none'`,
225 `base-uri 'self'`,
226 `form-action 'self'`,
227 `frame-ancestors 'none'`,
228 `block-all-mixed-content`,
229 ...(process.env.NEXT_PUBLIC_IS_PLATFORM === 'true' &&
230 process.env.NEXT_PUBLIC_ENVIRONMENT === 'prod'
231 ? [`upgrade-insecure-requests`]
232 : []),
233 ]
234
235 const csp = cspDirectives.join('; ') + ';'
236
237 // Replace newline characters and spaces
238 return csp.replace(/\s{2,}/g, ' ').trim()
239}