@@ -23,6 +23,7 @@ import type { AddressInfo } from 'net';
2323import { randomUUID } from 'crypto' ;
2424import { listify } from '../modules/utils.js' ;
2525import { afLogger } from '../modules/logger.js' ;
26+ import { ADMINFORTH_CLIENT_ID_HEADER , runWithRequestContext } from '../modules/requestContext.js' ;
2627import * as z from 'zod' ;
2728import multer from 'multer' ;
2829
@@ -52,6 +53,11 @@ function parseCookiesString(cookiesString: string): Array<{
5253 return result ;
5354}
5455
56+ function getHeaderString ( headers : Record < string , any > , name : string ) : string | undefined {
57+ const value = headers [ name ] ;
58+ return typeof value === 'string' ? value : undefined ;
59+ }
60+
5561async function parseExpressCookie ( req ) : Promise <
5662 Array < {
5763 key : string ,
@@ -271,6 +277,7 @@ class ExpressServer implements IExpressHttpServer {
271277 this . adminforth . websocket . registerWsClient (
272278 new WebSocketClient ( {
273279 id : randomUUID ( ) ,
280+ clientId : typeof req . url === 'string' ? new URL ( req . url , 'http://localhost' ) . searchParams . get ( 'clientId' ) || undefined : undefined ,
274281 adminUser,
275282 send : ( data ) => ws . send ( data ) ,
276283 close : ( ) => ws . close ( ) ,
@@ -287,6 +294,11 @@ class ExpressServer implements IExpressHttpServer {
287294
288295 serve ( app ) {
289296 this . expressApp = app ;
297+ this . expressApp . use ( ( req , res , next ) => {
298+ runWithRequestContext ( {
299+ websocketClientId : getHeaderString ( req . headers , ADMINFORTH_CLIENT_ID_HEADER ) ,
300+ } , next ) ;
301+ } ) ;
290302 this . patchSchemaAwareRouteRegistration ( ) ;
291303 this . flushPendingEndpointRegistrations ( ) ;
292304 const stack = ( this . expressApp as any ) ?. _router ?. stack ;
@@ -337,55 +349,63 @@ class ExpressServer implements IExpressHttpServer {
337349 }
338350 }
339351 }
352+
353+ runInRequestContext ( req , callback ) {
354+ return runWithRequestContext ( {
355+ websocketClientId : getHeaderString ( req . headers , ADMINFORTH_CLIENT_ID_HEADER ) ,
356+ } , callback ) ;
357+ }
340358
341359
342360 authorize ( handler ) {
343361 return async ( req , res , next ) => {
344- const cookies = await parseExpressCookie ( req ) ;
345- const brandSlug = this . adminforth . config . customization . brandNameSlug ;
346- // check if multiple adminforth_jwt providerd and show warning
347- const jwts = cookies . filter ( ( { key} ) => key === `adminforth_${ brandSlug } _jwt` ) ;
348- if ( jwts . length > 1 ) {
349- afLogger . error ( 'Multiple adminforth_jwt cookies provided' ) ;
350- }
362+ return this . runInRequestContext ( req , async ( ) => {
363+ const cookies = await parseExpressCookie ( req ) ;
364+ const brandSlug = this . adminforth . config . customization . brandNameSlug ;
365+ // check if multiple adminforth_jwt providerd and show warning
366+ const jwts = cookies . filter ( ( { key} ) => key === `adminforth_${ brandSlug } _jwt` ) ;
367+ if ( jwts . length > 1 ) {
368+ afLogger . error ( 'Multiple adminforth_jwt cookies provided' ) ;
369+ }
351370
352- const jwt = jwts [ 0 ] ?. value ;
371+ const jwt = jwts [ 0 ] ?. value ;
353372
354- if ( ! jwt ) {
355- res . status ( 401 ) . send ( 'Unauthorized by AdminForth' ) ;
356- return
357- }
358- let adminforthUser ;
359- try {
360- adminforthUser = await this . adminforth . auth . verify ( jwt , 'auth' ) ;
361- } catch ( e ) {
362- // this might happen if e.g. database intialization in progress.
363- // so we can't answer with 401 (would logout user)
364- // reproduced during usage of listRowsAutoRefreshSeconds
365- afLogger . error ( e . stack ) ;
366- res . status ( 500 ) . send ( 'Failed to verify JWT token - something went wrong' ) ;
367- return ;
368- }
369- if ( ! adminforthUser ) {
370- res . status ( 401 ) . send ( 'Unauthorized by AdminForth' ) ;
371- } else {
372- req . adminUser = adminforthUser ;
373- const toReturn : { error ?: string , allowed : boolean } = { allowed : true } ;
374- await this . processAuthorizeCallbacks ( adminforthUser , toReturn , res , {
375- body : req . body ,
376- query : req . query ,
377- headers : req . headers ,
378- cookies : cookies as any ,
379- requestUrl : req . url ,
380- meta : { } ,
381- response : res
382- } ) ;
383- if ( ! toReturn . allowed ) {
373+ if ( ! jwt ) {
374+ res . status ( 401 ) . send ( 'Unauthorized by AdminForth' ) ;
375+ return
376+ }
377+ let adminforthUser ;
378+ try {
379+ adminforthUser = await this . adminforth . auth . verify ( jwt , 'auth' ) ;
380+ } catch ( e ) {
381+ // this might happen if e.g. database intialization in progress.
382+ // so we can't answer with 401 (would logout user)
383+ // reproduced during usage of listRowsAutoRefreshSeconds
384+ afLogger . error ( e . stack ) ;
385+ res . status ( 500 ) . send ( 'Failed to verify JWT token - something went wrong' ) ;
386+ return ;
387+ }
388+ if ( ! adminforthUser ) {
384389 res . status ( 401 ) . send ( 'Unauthorized by AdminForth' ) ;
385390 } else {
386- handler ( req , res , next ) ;
391+ req . adminUser = adminforthUser ;
392+ const toReturn : { error ?: string , allowed : boolean } = { allowed : true } ;
393+ await this . processAuthorizeCallbacks ( adminforthUser , toReturn , res , {
394+ body : req . body ,
395+ query : req . query ,
396+ headers : req . headers ,
397+ cookies : cookies as any ,
398+ requestUrl : req . url ,
399+ meta : { } ,
400+ response : res
401+ } ) ;
402+ if ( ! toReturn . allowed ) {
403+ res . status ( 401 ) . send ( 'Unauthorized by AdminForth' ) ;
404+ } else {
405+ handler ( req , res , next ) ;
406+ }
387407 }
388- }
408+ } ) ;
389409 } ;
390410 }
391411
@@ -590,7 +610,7 @@ class ExpressServer implements IExpressHttpServer {
590610 } )
591611 : null ;
592612
593- const expressHandler = async ( req , res ) => {
613+ const expressHandler = async ( req , res ) => this . runInRequestContext ( req , async ( ) => {
594614 const abortController = new AbortController ( ) ;
595615 res . on ( 'close' , ( ) => {
596616 if ( req . destroyed ) {
@@ -718,7 +738,7 @@ class ExpressServer implements IExpressHttpServer {
718738 }
719739
720740 res . json ( output ) ;
721- }
741+ } ) ;
722742
723743 const registerEndpoint = ( ) => {
724744 afLogger . trace ( `👂 Adding endpoint ${ method } ${ fullPath } ` ) ;
0 commit comments