11import { createBullBoard } from "@bull-board/api" ;
22import { BullMQAdapter } from "@bull-board/api/bullMQAdapter" ;
33import { FastifyAdapter } from "@bull-board/fastify" ;
4- import fastifyBasicAuth from "@fastify/basic-auth" ;
54import type { Queue } from "bullmq" ;
6- import { timingSafeEqual } from "crypto" ;
75import type { FastifyInstance } from "fastify" ;
86import { StatusCodes } from "http-status-codes" ;
7+ import { timingSafeEqual } from "node:crypto" ;
98import { env } from "../../utils/env" ;
109import { CancelRecycledNoncesQueue } from "../../worker/queues/cancelRecycledNoncesQueue" ;
1110import { MigratePostgresTransactionsQueue } from "../../worker/queues/migratePostgresTransactionsQueue" ;
@@ -19,7 +18,9 @@ import { SendTransactionQueue } from "../../worker/queues/sendTransactionQueue";
1918import { SendWebhookQueue } from "../../worker/queues/sendWebhookQueue" ;
2019
2120export const ADMIN_QUEUES_BASEPATH = "/admin/queues" ;
21+ const ADMIN_ROUTES_USERNAME = "admin" ;
2222const ADMIN_ROUTES_PASSWORD = env . THIRDWEB_API_SECRET_KEY ;
23+
2324// Add queues to monitor here.
2425const QUEUES : Queue [ ] = [
2526 SendWebhookQueue . q ,
@@ -35,57 +36,59 @@ const QUEUES: Queue[] = [
3536] ;
3637
3738export const withAdminRoutes = async ( fastify : FastifyInstance ) => {
38- // Configure basic auth.
39- await fastify . register ( fastifyBasicAuth , {
40- validate : ( username , password , req , reply , done ) => {
41- if ( assertAdminBasicAuth ( username , password ) ) {
42- done ( ) ;
43- return ;
44- }
45- done ( new Error ( "Unauthorized" ) ) ;
46- } ,
47- authenticate : true ,
48- } ) ;
49-
50- // Set up routes after Fastify is set up.
5139 fastify . after ( async ( ) => {
52- // Register bullboard UI .
40+ // Create a new route for Bullboard routes .
5341 const serverAdapter = new FastifyAdapter ( ) ;
5442 serverAdapter . setBasePath ( ADMIN_QUEUES_BASEPATH ) ;
5543
5644 createBullBoard ( {
5745 queues : QUEUES . map ( ( q ) => new BullMQAdapter ( q ) ) ,
5846 serverAdapter,
5947 } ) ;
48+
6049 await fastify . register ( serverAdapter . registerPlugin ( ) , {
6150 basePath : ADMIN_QUEUES_BASEPATH ,
6251 prefix : ADMIN_QUEUES_BASEPATH ,
6352 } ) ;
6453
65- // Apply basic auth only to admin routes.
66- fastify . addHook ( "onRequest" , ( req , reply , done ) => {
54+ fastify . addHook ( "onRequest" , async ( req , reply ) => {
6755 if ( req . url . startsWith ( ADMIN_QUEUES_BASEPATH ) ) {
68- fastify . basicAuth ( req , reply , ( error ) => {
69- if ( error ) {
70- reply
71- . status ( StatusCodes . UNAUTHORIZED )
72- . send ( { error : "Unauthorized" } ) ;
73- return done ( error ) ;
74- }
75- } ) ;
56+ const authHeader = req . headers . authorization ;
57+
58+ if ( ! authHeader || ! authHeader . startsWith ( "Basic " ) ) {
59+ reply
60+ . status ( StatusCodes . UNAUTHORIZED )
61+ . header ( "WWW-Authenticate" , 'Basic realm="Admin Routes"' )
62+ . send ( { error : "Unauthorized" } ) ;
63+ return ;
64+ }
65+
66+ // Parse the basic auth credentials (`Basic <base64 of username:password>`).
67+ const base64Credentials = authHeader . split ( " " ) [ 1 ] ;
68+ const credentials = Buffer . from ( base64Credentials , "base64" ) . toString (
69+ "utf8" ,
70+ ) ;
71+ const [ username , password ] = credentials . split ( ":" ) ;
72+
73+ if ( ! assertAdminBasicAuth ( username , password ) ) {
74+ reply
75+ . status ( StatusCodes . UNAUTHORIZED )
76+ . header ( "WWW-Authenticate" , 'Basic realm="Admin Routes"' )
77+ . send ( { error : "Unauthorized" } ) ;
78+ return ;
79+ }
7680 }
77- done ( ) ;
7881 } ) ;
7982 } ) ;
8083} ;
8184
8285const assertAdminBasicAuth = ( username : string , password : string ) => {
83- if ( username === "admin" ) {
86+ if ( username === ADMIN_ROUTES_USERNAME ) {
8487 try {
8588 const buf1 = Buffer . from ( password . padEnd ( 100 ) ) ;
8689 const buf2 = Buffer . from ( ADMIN_ROUTES_PASSWORD . padEnd ( 100 ) ) ;
8790 return timingSafeEqual ( buf1 , buf2 ) ;
88- } catch ( e ) { }
91+ } catch { }
8992 }
9093 return false ;
9194} ;
0 commit comments