fix(csp): added terms, privacy, & logo URLs to CSP (#1413)

This commit is contained in:
Waleed
2025-09-22 12:04:48 -07:00
committed by GitHub
parent 25781279e2
commit 73d779ad79

View File

@@ -2,9 +2,17 @@ import { env, getEnv } from '../env'
/**
* Content Security Policy (CSP) configuration builder
* This creates a more maintainable and readable CSP configuration
*/
function getHostnameFromUrl(url: string | undefined): string[] {
if (!url) return []
try {
return [`https://${new URL(url).hostname}`]
} catch {
return []
}
}
export interface CSPDirectives {
'default-src'?: string[]
'script-src'?: string[]
@@ -43,7 +51,6 @@ export const buildTimeCSPDirectives: CSPDirectives = {
'style-src': ["'self'", "'unsafe-inline'", 'https://fonts.googleapis.com'],
'img-src': [
'https://agentics.epiqglobal.com',
"'self'",
'data:',
'blob:',
@@ -66,6 +73,7 @@ export const buildTimeCSPDirectives: CSPDirectives = {
: []),
'https://*.amazonaws.com',
'https://*.blob.core.windows.net',
...getHostnameFromUrl(env.NEXT_PUBLIC_BRAND_LOGO_URL),
],
'media-src': ["'self'", 'blob:'],
@@ -98,14 +106,12 @@ export const buildTimeCSPDirectives: CSPDirectives = {
'https://*.vercel.app',
'wss://*.vercel.app',
'https://pro.ip-api.com',
...getHostnameFromUrl(env.NEXT_PUBLIC_BRAND_LOGO_URL),
...getHostnameFromUrl(env.NEXT_PUBLIC_PRIVACY_URL),
...getHostnameFromUrl(env.NEXT_PUBLIC_TERMS_URL),
],
// Google Picker and Drive integration
'frame-src': [
'https://drive.google.com',
'https://docs.google.com', // Required for Google Picker
'https://*.google.com',
],
'frame-src': ['https://drive.google.com', 'https://docs.google.com', 'https://*.google.com'],
'frame-ancestors': ["'self'"],
'form-action': ["'self'"],
@@ -120,7 +126,6 @@ export function buildCSPString(directives: CSPDirectives): string {
return Object.entries(directives)
.map(([directive, sources]) => {
if (!sources || sources.length === 0) return ''
// Filter out empty strings
const validSources = sources.filter((source: string) => source && source.trim() !== '')
if (validSources.length === 0) return ''
return `${directive} ${validSources.join(' ')}`
@@ -140,14 +145,23 @@ export function generateRuntimeCSP(): string {
const appUrl = getEnv('NEXT_PUBLIC_APP_URL') || ''
const ollamaUrl = getEnv('OLLAMA_URL') || 'http://localhost:11434'
const brandLogoDomains = getHostnameFromUrl(getEnv('NEXT_PUBLIC_BRAND_LOGO_URL'))
const privacyDomains = getHostnameFromUrl(getEnv('NEXT_PUBLIC_PRIVACY_URL'))
const termsDomains = getHostnameFromUrl(getEnv('NEXT_PUBLIC_TERMS_URL'))
const allDynamicDomains = [...brandLogoDomains, ...privacyDomains, ...termsDomains]
const uniqueDynamicDomains = Array.from(new Set(allDynamicDomains))
const dynamicDomainsStr = uniqueDynamicDomains.join(' ')
const brandLogoDomain = brandLogoDomains[0] || ''
return `
default-src 'self';
script-src 'self' 'unsafe-inline' 'unsafe-eval' https://*.google.com https://apis.google.com https://*.vercel-scripts.com https://*.vercel-insights.com https://vercel.live https://*.vercel.live https://vercel.com https://*.vercel.app https://vitals.vercel-insights.com https://b2bjsstore.s3.us-west-2.amazonaws.com;
style-src 'self' 'unsafe-inline' https://fonts.googleapis.com;
img-src 'self' data: blob: https://*.googleusercontent.com https://*.google.com https://*.atlassian.com https://cdn.discordapp.com https://*.githubusercontent.com https://*.public.blob.vercel-storage.com;
img-src 'self' data: blob: https://*.googleusercontent.com https://*.google.com https://*.atlassian.com https://cdn.discordapp.com https://*.githubusercontent.com https://*.public.blob.vercel-storage.com ${brandLogoDomain};
media-src 'self' blob:;
font-src 'self' https://fonts.gstatic.com;
connect-src 'self' ${appUrl} ${ollamaUrl} ${socketUrl} ${socketWsUrl} https://*.up.railway.app wss://*.up.railway.app https://api.browser-use.com https://api.exa.ai https://api.firecrawl.dev https://*.googleapis.com https://*.amazonaws.com https://*.s3.amazonaws.com https://*.blob.core.windows.net https://*.vercel-insights.com https://vitals.vercel-insights.com https://*.atlassian.com https://*.supabase.co https://vercel.live https://*.vercel.live https://vercel.com https://*.vercel.app wss://*.vercel.app https://pro.ip-api.com;
connect-src 'self' ${appUrl} ${ollamaUrl} ${socketUrl} ${socketWsUrl} https://*.up.railway.app wss://*.up.railway.app https://api.browser-use.com https://api.exa.ai https://api.firecrawl.dev https://*.googleapis.com https://*.amazonaws.com https://*.s3.amazonaws.com https://*.blob.core.windows.net https://*.vercel-insights.com https://vitals.vercel-insights.com https://*.atlassian.com https://*.supabase.co https://vercel.live https://*.vercel.live https://vercel.com https://*.vercel.app wss://*.vercel.app https://pro.ip-api.com ${dynamicDomainsStr};
frame-src https://drive.google.com https://docs.google.com https://*.google.com;
frame-ancestors 'self';
form-action 'self';