fix(redirects): move redirects for terms/privacy to client-side redirects (#1418)

This commit is contained in:
Waleed
2025-09-22 15:10:29 -07:00
committed by GitHub
parent 8eaa83fe21
commit 7cb303e713
5 changed files with 56 additions and 33 deletions
+8
View File
@@ -1,9 +1,17 @@
'use client'
import { useEffect } from 'react'
import Link from 'next/link'
import { getEnv } from '@/lib/env'
import { LegalLayout } from '@/app/(landing)/components'
export default function PrivacyPolicy() {
useEffect(() => {
const privacyUrl = getEnv('NEXT_PUBLIC_PRIVACY_URL')
if (privacyUrl?.startsWith('http')) {
window.location.href = privacyUrl
}
}, [])
return (
<LegalLayout title='Privacy Policy'>
<section>
+8
View File
@@ -1,9 +1,17 @@
'use client'
import { useEffect } from 'react'
import Link from 'next/link'
import { getEnv } from '@/lib/env'
import { LegalLayout } from '@/app/(landing)/components'
export default function TermsOfService() {
useEffect(() => {
const termsUrl = getEnv('NEXT_PUBLIC_TERMS_URL')
if (termsUrl?.startsWith('http')) {
window.location.href = termsUrl
}
}, [])
return (
<LegalLayout title='Terms of Service'>
<section>
+10 -2
View File
@@ -74,6 +74,7 @@ export const buildTimeCSPDirectives: CSPDirectives = {
'https://*.amazonaws.com',
'https://*.blob.core.windows.net',
...getHostnameFromUrl(env.NEXT_PUBLIC_BRAND_LOGO_URL),
...getHostnameFromUrl(env.NEXT_PUBLIC_BRAND_FAVICON_URL),
],
'media-src': ["'self'", 'blob:'],
@@ -146,19 +147,26 @@ export function generateRuntimeCSP(): string {
const ollamaUrl = getEnv('OLLAMA_URL') || 'http://localhost:11434'
const brandLogoDomains = getHostnameFromUrl(getEnv('NEXT_PUBLIC_BRAND_LOGO_URL'))
const brandFaviconDomains = getHostnameFromUrl(getEnv('NEXT_PUBLIC_BRAND_FAVICON_URL'))
const privacyDomains = getHostnameFromUrl(getEnv('NEXT_PUBLIC_PRIVACY_URL'))
const termsDomains = getHostnameFromUrl(getEnv('NEXT_PUBLIC_TERMS_URL'))
const allDynamicDomains = [...brandLogoDomains, ...privacyDomains, ...termsDomains]
const allDynamicDomains = [
...brandLogoDomains,
...brandFaviconDomains,
...privacyDomains,
...termsDomains,
]
const uniqueDynamicDomains = Array.from(new Set(allDynamicDomains))
const dynamicDomainsStr = uniqueDynamicDomains.join(' ')
const brandLogoDomain = brandLogoDomains[0] || ''
const brandFaviconDomain = brandFaviconDomains[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 ${brandLogoDomain};
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} ${brandFaviconDomain};
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 ${dynamicDomainsStr};
-31
View File
@@ -93,37 +93,6 @@ export async function middleware(request: NextRequest) {
}
}
// Handle whitelabel redirects for terms and privacy pages
if (url.pathname === '/terms') {
const termsUrl = process.env.NEXT_PUBLIC_TERMS_URL
if (termsUrl?.startsWith('http')) {
return NextResponse.redirect(termsUrl)
}
}
if (url.pathname === '/privacy') {
const privacyUrl = process.env.NEXT_PUBLIC_PRIVACY_URL
if (privacyUrl?.startsWith('http')) {
return NextResponse.redirect(privacyUrl)
}
}
// Legacy redirect: /w -> /workspace (will be handled by workspace layout)
if (url.pathname === '/w' || url.pathname.startsWith('/w/')) {
// Extract workflow ID if present
const pathParts = url.pathname.split('/')
if (pathParts.length >= 3 && pathParts[1] === 'w') {
const workflowId = pathParts[2]
// Redirect old workflow URLs to new format
// We'll need to resolve the workspace ID for this workflow
return NextResponse.redirect(
new URL(`/workspace?redirect_workflow=${workflowId}`, request.url)
)
}
// Simple /w redirect to workspace root
return NextResponse.redirect(new URL('/workspace', request.url))
}
// Handle login page - redirect authenticated users to workspace
if (url.pathname === '/login' || url.pathname === '/signup') {
if (hasActiveSession) {
+30
View File
@@ -43,6 +43,36 @@ const nextConfig: NextConfig = {
},
]
: []),
// Brand logo domain if configured
...(env.NEXT_PUBLIC_BRAND_LOGO_URL
? (() => {
try {
return [
{
protocol: 'https' as const,
hostname: new URL(env.NEXT_PUBLIC_BRAND_LOGO_URL).hostname,
},
]
} catch {
return []
}
})()
: []),
// Brand favicon domain if configured
...(env.NEXT_PUBLIC_BRAND_FAVICON_URL
? (() => {
try {
return [
{
protocol: 'https' as const,
hostname: new URL(env.NEXT_PUBLIC_BRAND_FAVICON_URL).hostname,
},
]
} catch {
return []
}
})()
: []),
],
},
typescript: {