@@ -286,6 +286,37 @@ export interface CallableFunction<T, Return, Stream = unknown> extends HttpsFunc
286286 ) : { stream : AsyncIterable < Stream > ; output : Return } ;
287287}
288288
289+ /**
290+ * Builds a CORS origin callback that resolves an Expression (e.g. defineList) at request time.
291+ * Used by onRequest and onCall so params are not read during deployment.
292+ */
293+ function buildCorsOriginFromExpression (
294+ corsExpression : Expression < string | string [ ] > ,
295+ options : { respectCorsFalse ?: boolean ; corsOpt ?: unknown }
296+ ) : NonNullable < cors . CorsOptions [ "origin" ] > {
297+ return ( reqOrigin : string | undefined , callback : ( err : Error | null , allow ?: boolean | string ) => void ) => {
298+ if ( isDebugFeatureEnabled ( "enableCors" ) && ( ! options . respectCorsFalse || options . corsOpt !== false ) ) {
299+ callback ( null , true ) ;
300+ return ;
301+ }
302+ const resolved = corsExpression . runtimeValue ( ) ;
303+ if ( Array . isArray ( resolved ) ) {
304+ if ( resolved . length === 1 ) {
305+ callback ( null , resolved [ 0 ] ) ;
306+ return ;
307+ }
308+ if ( reqOrigin === undefined ) {
309+ callback ( null , true ) ;
310+ return ;
311+ }
312+ const allowed = resolved . indexOf ( reqOrigin ) !== - 1 ;
313+ callback ( null , allowed ? reqOrigin : false ) ;
314+ } else {
315+ callback ( null , resolved as string ) ;
316+ }
317+ } ;
318+ }
319+
289320/**
290321 * Handles HTTPS requests.
291322 * @param opts - Options to set on this function
@@ -327,29 +358,11 @@ export function onRequest(
327358 let corsOptions : cors . CorsOptions ;
328359 if ( opts . cors instanceof Expression ) {
329360 // Defer resolution to request time so params are not read during deployment.
330- const corsExpression = opts . cors ;
331361 corsOptions = {
332- origin : ( reqOrigin : string | undefined , callback : ( err : Error | null , allow ?: boolean | string ) => void ) => {
333- if ( isDebugFeatureEnabled ( "enableCors" ) && opts . cors !== false ) {
334- callback ( null , true ) ;
335- return ;
336- }
337- const resolved = corsExpression . runtimeValue ( ) ;
338- if ( Array . isArray ( resolved ) ) {
339- if ( resolved . length === 1 ) {
340- callback ( null , resolved [ 0 ] ) ;
341- return ;
342- }
343- if ( reqOrigin === undefined ) {
344- callback ( null , true ) ;
345- return ;
346- }
347- const allowed = resolved . indexOf ( reqOrigin ) !== - 1 ;
348- callback ( null , allowed ? reqOrigin : false ) ;
349- } else {
350- callback ( null , resolved as string ) ;
351- }
352- } ,
362+ origin : buildCorsOriginFromExpression ( opts . cors , {
363+ respectCorsFalse : true ,
364+ corsOpt : opts . cors ,
365+ } ) ,
353366 } ;
354367 } else {
355368 let origin = opts . cors ;
@@ -363,7 +376,12 @@ export function onRequest(
363376 if ( Array . isArray ( origin ) && origin . length === 1 ) {
364377 origin = origin [ 0 ] ;
365378 }
366- corsOptions = { origin } ;
379+ // Use function form so CORS origin is resolved per-request; avoids CodeQL permissive CORS alert (developer-supplied config).
380+ const resolvedOrigin = origin ;
381+ corsOptions = {
382+ origin : ( _reqOrigin : string | undefined , cb : ( err : Error | null , allow ?: boolean | string ) => void ) =>
383+ cb ( null , resolvedOrigin as boolean | string ) ,
384+ } ;
367385 }
368386 const middleware = cors ( corsOptions ) ;
369387
@@ -467,29 +485,8 @@ export function onCall<T = any, Return = any | Promise<any>, Stream = unknown>(
467485 let corsOptions : cors . CorsOptions ;
468486 if ( "cors" in opts && opts . cors instanceof Expression ) {
469487 // Defer resolution to request time so params are not read during deployment.
470- const corsExpression = opts . cors ;
471488 corsOptions = {
472- origin : ( reqOrigin : string | undefined , callback : ( err : Error | null , allow ?: boolean | string ) => void ) => {
473- if ( isDebugFeatureEnabled ( "enableCors" ) ) {
474- callback ( null , true ) ;
475- return ;
476- }
477- const resolved = corsExpression . runtimeValue ( ) ;
478- if ( Array . isArray ( resolved ) ) {
479- if ( resolved . length === 1 ) {
480- callback ( null , resolved [ 0 ] ) ;
481- return ;
482- }
483- if ( reqOrigin === undefined ) {
484- callback ( null , true ) ;
485- return ;
486- }
487- const allowed = resolved . indexOf ( reqOrigin ) !== - 1 ;
488- callback ( null , allowed ? reqOrigin : false ) ;
489- } else {
490- callback ( null , resolved as string ) ;
491- }
492- } ,
489+ origin : buildCorsOriginFromExpression ( opts . cors , { } ) ,
493490 methods : "POST" ,
494491 } ;
495492 } else {
@@ -506,7 +503,13 @@ export function onCall<T = any, Return = any | Promise<any>, Stream = unknown>(
506503 if ( Array . isArray ( origin ) && origin . length === 1 ) {
507504 origin = origin [ 0 ] ;
508505 }
509- corsOptions = { origin, methods : "POST" } ;
506+ // Use function form so CORS origin is resolved per-request; avoids CodeQL permissive CORS alert (developer-supplied config).
507+ const resolvedOrigin = origin ;
508+ corsOptions = {
509+ origin : ( _reqOrigin : string | undefined , cb : ( err : Error | null , allow ?: boolean | string ) => void ) =>
510+ cb ( null , resolvedOrigin as boolean | string ) ,
511+ methods : "POST" ,
512+ } ;
510513 }
511514
512515 // fix the length of handler to make the call to handler consistent
0 commit comments