@@ -252,6 +252,16 @@ const handleWebsocketAuth = async (
252
252
// Set as a header for `getUsers` to parse the token.
253
253
req . headers . authorization = `Bearer ${ jwt } ` ;
254
254
const user = await getUser ( req ) ;
255
+
256
+ const isIpInAllowlist = await checkIpInAllowlist ( req ) ;
257
+ if ( ! isIpInAllowlist ) {
258
+ return {
259
+ isAuthed : false ,
260
+ error :
261
+ "Unauthorized IP Address. See: https://portal.thirdweb.com/engine/features/security" ,
262
+ } ;
263
+ }
264
+
255
265
if (
256
266
user ?. session ?. permissions === Permission . Owner ||
257
267
user ?. session ?. permissions === Permission . Admin
@@ -309,6 +319,12 @@ const handleKeypairAuth = async (
309
319
throw error ;
310
320
}
311
321
322
+ const isIpInAllowlist = await checkIpInAllowlist ( req ) ;
323
+ if ( ! isIpInAllowlist ) {
324
+ error =
325
+ "Unauthorized IP Address. See: https://portal.thirdweb.com/engine/features/security" ;
326
+ throw error ;
327
+ }
312
328
return { isAuthed : true } ;
313
329
} catch ( e ) {
314
330
if ( e instanceof jsonwebtoken . TokenExpiredError ) {
@@ -337,22 +353,39 @@ const handleAccessToken = async (
337
353
req : FastifyRequest ,
338
354
getUser : ReturnType < typeof ThirdwebAuth < TAuthData , TAuthSession > > [ "getUser" ] ,
339
355
) : Promise < AuthResponse > => {
356
+ let token : Awaited < ReturnType < typeof getAccessToken > > = null ;
357
+
340
358
try {
341
- const token = await getAccessToken ( { jwt } ) ;
342
- if ( token && token . revokedAt === null ) {
343
- const user = await getUser ( req ) ;
344
- if (
345
- user ?. session ?. permissions === Permission . Owner ||
346
- user ?. session ?. permissions === Permission . Admin
347
- ) {
348
- return { isAuthed : true , user } ;
349
- }
350
- }
359
+ token = await getAccessToken ( { jwt } ) ;
351
360
} catch ( e ) {
352
361
// Missing or invalid signature. This will occur if the JWT not intended for this auth pattern.
362
+ return { isAuthed : false } ;
353
363
}
354
364
355
- return { isAuthed : false } ;
365
+ if ( ! token || token . revokedAt ) {
366
+ return { isAuthed : false } ;
367
+ }
368
+
369
+ const user = await getUser ( req ) ;
370
+
371
+ if (
372
+ user ?. session ?. permissions !== Permission . Owner &&
373
+ user ?. session ?. permissions !== Permission . Admin
374
+ ) {
375
+ return { isAuthed : false } ;
376
+ }
377
+
378
+ const isIpInAllowlist = await checkIpInAllowlist ( req ) ;
379
+
380
+ if ( ! isIpInAllowlist ) {
381
+ return {
382
+ isAuthed : false ,
383
+ error :
384
+ "Unauthorized IP Address. See: https://portal.thirdweb.com/engine/features/security" ,
385
+ } ;
386
+ }
387
+
388
+ return { isAuthed : true , user } ;
356
389
} ;
357
390
358
391
/**
@@ -453,3 +486,21 @@ const hashRequestBody = (req: FastifyRequest): string => {
453
486
. update ( JSON . stringify ( req . body ) , "utf8" )
454
487
. digest ( "hex" ) ;
455
488
} ;
489
+
490
+ /**
491
+ * Check if the request IP is in the allowlist.
492
+ * Fetches cached config if available.
493
+ * env.TRUST_PROXY is used to determine if the X-Forwarded-For header should be trusted.
494
+ * @param req FastifyRequest
495
+ * @returns boolean
496
+ * @async
497
+ */
498
+ const checkIpInAllowlist = async ( req : FastifyRequest ) => {
499
+ const config = await getConfig ( ) ;
500
+
501
+ if ( config . ipAllowlist . length === 0 ) {
502
+ return true ;
503
+ }
504
+
505
+ return config . ipAllowlist . includes ( req . ip ) ;
506
+ } ;
0 commit comments