fix cors production
Build & Push / Pipeline Tests (push) Successful in 1m58s
Test / Type Check (all packages) (push) Successful in 59s
Build & Push / Build & Push Docker Image (push) Successful in 4m9s
Test / API Unit Tests (push) Successful in 1m13s
Test / Homepage Unit Tests (push) Successful in 50s
Test / Carplace Unit Tests (push) Successful in 43s
Test / Admin Unit Tests (push) Successful in 44s
Test / Dashboard Unit Tests (push) Successful in 46s
Test / API Integration Tests (push) Successful in 1m7s

This commit is contained in:
root
2026-07-29 00:24:48 -04:00
parent 1b3c476dd4
commit a665c942d2
3 changed files with 61 additions and 4 deletions
+41 -3
View File
@@ -55,9 +55,47 @@ const defaultCorsOrigins = [
'http://127.0.0.1:4000',
]
export const corsOrigins = process.env.CORS_ORIGINS
? process.env.CORS_ORIGINS.split(',').map((o) => o.trim()).filter(Boolean)
: defaultCorsOrigins
const frontendOriginEnvKeys = [
'SITE_ORIGIN',
'WEBSITE_URL',
'HOMEPAGE_URL',
'DASHBOARD_URL',
'ADMIN_URL',
'CARPLACE_URL',
'NEXT_PUBLIC_HOMEPAGE_URL',
'NEXT_PUBLIC_WEBSITE_URL',
'NEXT_PUBLIC_DASHBOARD_URL',
'NEXT_PUBLIC_ADMIN_URL',
'NEXT_PUBLIC_CARPLACE_URL',
] as const
function normalizeConfiguredOrigin(value: string): string | null {
try {
return new URL(value).origin
} catch {
return null
}
}
export function getConfiguredCorsOrigins(env: NodeJS.ProcessEnv = process.env) {
const configuredOrigins = (env.CORS_ORIGINS ?? '')
.split(',')
.map((origin) => origin.trim())
.filter(Boolean)
const frontendOrigins = frontendOriginEnvKeys
.flatMap((key) => (env[key] ?? '').split(','))
.map((origin) => origin.trim())
.filter(Boolean)
const rawOrigins = configuredOrigins.length > 0 || frontendOrigins.length > 0
? [...configuredOrigins, ...frontendOrigins]
: defaultCorsOrigins
return Array.from(new Set(rawOrigins.map(normalizeConfiguredOrigin).filter((origin): origin is string => Boolean(origin))))
}
export const corsOrigins = getConfiguredCorsOrigins()
function isAllowedLocalDevOrigin(origin: string) {
if (process.env.NODE_ENV === 'production') return false
+3
View File
@@ -5,10 +5,13 @@ const SESSION_COOKIE_PATTERN = /(?:^|;\s*)(?:admin_session|employee_session|rent
function configuredOrigins() {
return [
process.env.SITE_ORIGIN,
process.env.DASHBOARD_URL,
process.env.ADMIN_URL,
process.env.CARPLACE_URL,
process.env.HOMEPAGE_URL,
process.env.WEBSITE_URL,
process.env.NEXT_PUBLIC_HOMEPAGE_URL,
process.env.NEXT_PUBLIC_DASHBOARD_URL,
process.env.NEXT_PUBLIC_ADMIN_URL,
process.env.NEXT_PUBLIC_CARPLACE_URL,
@@ -16,7 +16,7 @@ vi.mock('../../lib/redis', () => ({
import request from 'supertest'
import { describe, expect, it } from 'vitest'
import { createApp, isCorsOriginAllowed } from '../../app'
import { createApp, getConfiguredCorsOrigins, isCorsOriginAllowed } from '../../app'
import { isTrustedBrowserOrigin } from '../../middleware/csrf'
const app = createApp()
@@ -88,6 +88,22 @@ describe('API foundation integration', () => {
expect(res.headers['access-control-allow-credentials']).toBe('true')
})
it('derives production CORS origins from configured frontend URLs when CORS_ORIGINS is absent', () => {
expect(getConfiguredCorsOrigins({
NODE_ENV: 'production',
SITE_ORIGIN: 'https://rentaldrivego.ma',
NEXT_PUBLIC_DASHBOARD_URL: 'https://rentaldrivego.ma/dashboard',
NEXT_PUBLIC_ADMIN_URL: 'https://rentaldrivego.ma/admin',
})).toEqual(['https://rentaldrivego.ma'])
})
it('normalizes explicit CORS origins and frontend URL origins without duplicates', () => {
expect(getConfiguredCorsOrigins({
CORS_ORIGINS: 'https://rentaldrivego.ma, https://www.rentaldrivego.ma',
NEXT_PUBLIC_DASHBOARD_URL: 'https://rentaldrivego.ma/dashboard',
})).toEqual(['https://rentaldrivego.ma', 'https://www.rentaldrivego.ma'])
})
it('trusts private LAN app origins during local development only on known app ports', () => {
expect(isCorsOriginAllowed('http://192.168.3.3:3000')).toBe(true)
expect(isTrustedBrowserOrigin('http://192.168.3.3:3000')).toBe(true)