@@ -241,70 +241,22 @@ export async function handleParseHeaders(req, res, next) {
241241 req . config . ip = clientIp ;
242242 req . info = info ;
243243
244- const isMaintenance =
245- req . config . maintenanceKey && info . maintenanceKey === req . config . maintenanceKey ;
246- if ( isMaintenance ) {
247- if ( checkIp ( clientIp , req . config . maintenanceKeyIps || [ ] , req . config . maintenanceKeyIpsStore ) ) {
248- req . auth = new auth . Auth ( {
249- config : req . config ,
250- installationId : info . installationId ,
251- isMaintenance : true ,
252- } ) ;
253- next ( ) ;
254- return ;
255- }
256- const log = req . config ?. loggerController || defaultLogger ;
257- log . error (
258- `Request using maintenance key rejected as the request IP address '${ clientIp } ' is not set in Parse Server option 'maintenanceKeyIps'.`
259- ) ;
260- }
261-
262- const masterKey = await req . config . loadMasterKey ( ) ;
263- let isMaster = info . masterKey === masterKey ;
264-
265- if ( isMaster && ! checkIp ( clientIp , req . config . masterKeyIps || [ ] , req . config . masterKeyIpsStore ) ) {
266- const log = req . config ?. loggerController || defaultLogger ;
267- log . error (
268- `Request using master key rejected as the request IP address '${ clientIp } ' is not set in Parse Server option 'masterKeyIps'.`
269- ) ;
270- isMaster = false ;
271- const error = new Error ( ) ;
272- error . status = 403 ;
273- error . message = `unauthorized` ;
274- throw error ;
275- }
276-
277- if ( isMaster ) {
278- req . auth = new auth . Auth ( {
244+ // Skip key detection if already resolved by handleParseAuth (header-based).
245+ // Only resolve here for body-based _MasterKey (info.masterKey may come from body).
246+ if ( ! req . auth || ( ! req . auth . isMaster && ! req . auth . isMaintenance ) ) {
247+ const resolved = await resolveKeyAuth ( {
279248 config : req . config ,
249+ keyValue : info . masterKey ,
250+ maintenanceKeyValue : info . maintenanceKey ,
280251 installationId : info . installationId ,
281- isMaster : true ,
252+ clientIp ,
282253 } ) ;
283- return handleRateLimit ( req , res , next ) ;
254+ if ( resolved ) {
255+ req . auth = resolved ;
256+ }
284257 }
285258
286- var isReadOnlyMaster = info . masterKey === req . config . readOnlyMasterKey ;
287- if (
288- typeof req . config . readOnlyMasterKey != 'undefined' &&
289- req . config . readOnlyMasterKey &&
290- isReadOnlyMaster
291- ) {
292- if ( ! checkIp ( clientIp , req . config . readOnlyMasterKeyIps || [ ] , req . config . readOnlyMasterKeyIpsStore ) ) {
293- const log = req . config ?. loggerController || defaultLogger ;
294- log . error (
295- `Request using read-only master key rejected as the request IP address '${ clientIp } ' is not set in Parse Server option 'readOnlyMasterKeyIps'.`
296- ) ;
297- const error = new Error ( ) ;
298- error . status = 403 ;
299- error . message = 'unauthorized' ;
300- throw error ;
301- }
302- req . auth = new auth . Auth ( {
303- config : req . config ,
304- installationId : info . installationId ,
305- isMaster : true ,
306- isReadOnly : true ,
307- } ) ;
259+ if ( req . auth && ( req . auth . isMaster || req . auth . isMaintenance ) ) {
308260 return handleRateLimit ( req , res , next ) ;
309261 }
310262
@@ -491,6 +443,88 @@ export function allowMethodOverride(req, res, next) {
491443 next ( ) ;
492444}
493445
446+ async function resolveKeyAuth ( { config, keyValue, maintenanceKeyValue, installationId, clientIp } ) {
447+ if ( maintenanceKeyValue && maintenanceKeyValue === config . maintenanceKey ) {
448+ if ( checkIp ( clientIp , config . maintenanceKeyIps || [ ] , config . maintenanceKeyIpsStore ) ) {
449+ return new auth . Auth ( { config, installationId, isMaintenance : true } ) ;
450+ }
451+ const log = config . loggerController || defaultLogger ;
452+ log . error (
453+ `Request using maintenance key rejected as the request IP address '${ clientIp } ' is not set in Parse Server option 'maintenanceKeyIps'.`
454+ ) ;
455+ }
456+ const masterKey = await config . loadMasterKey ( ) ;
457+ if ( keyValue === masterKey ) {
458+ if ( checkIp ( clientIp , config . masterKeyIps || [ ] , config . masterKeyIpsStore ) ) {
459+ return new auth . Auth ( { config, installationId, isMaster : true } ) ;
460+ }
461+ const log = config . loggerController || defaultLogger ;
462+ log . error (
463+ `Request using master key rejected as the request IP address '${ clientIp } ' is not set in Parse Server option 'masterKeyIps'.`
464+ ) ;
465+ const error = new Error ( ) ;
466+ error . status = 403 ;
467+ error . message = 'unauthorized' ;
468+ throw error ;
469+ }
470+ if (
471+ keyValue &&
472+ typeof config . readOnlyMasterKey !== 'undefined' &&
473+ config . readOnlyMasterKey &&
474+ keyValue === config . readOnlyMasterKey
475+ ) {
476+ if ( checkIp ( clientIp , config . readOnlyMasterKeyIps || [ ] , config . readOnlyMasterKeyIpsStore ) ) {
477+ return new auth . Auth ( { config, installationId, isMaster : true , isReadOnly : true } ) ;
478+ }
479+ const log = config . loggerController || defaultLogger ;
480+ log . error (
481+ `Request using read-only master key rejected as the request IP address '${ clientIp } ' is not set in Parse Server option 'readOnlyMasterKeyIps'.`
482+ ) ;
483+ const error = new Error ( ) ;
484+ error . status = 403 ;
485+ error . message = 'unauthorized' ;
486+ throw error ;
487+ }
488+ return null ;
489+ }
490+
491+ export function handleParseAuth ( appId ) {
492+ return async ( req , res , next ) => {
493+ const mount = getMountForRequest ( req ) ;
494+ const config = Config . get ( appId , mount ) ;
495+ if ( ! config ) {
496+ return next ( ) ;
497+ }
498+ req . config = config ;
499+ const clientIp = getClientIp ( req ) ;
500+ req . config . ip = clientIp ;
501+ await config . loadKeys ( ) ;
502+ const resolved = await resolveKeyAuth ( {
503+ config,
504+ keyValue : req . get ( 'X-Parse-Master-Key' ) || null ,
505+ maintenanceKeyValue : req . get ( 'X-Parse-Maintenance-Key' ) || null ,
506+ installationId : req . get ( 'X-Parse-Installation-Id' ) || 'cloud' ,
507+ clientIp,
508+ } ) ;
509+ if ( resolved ) {
510+ req . auth = resolved ;
511+ }
512+ return next ( ) ;
513+ } ;
514+ }
515+
516+ export function handleParseHealth ( options ) {
517+ return ( req , res ) => {
518+ res . status ( options . state === 'ok' ? 200 : 503 ) ;
519+ if ( options . state === 'starting' ) {
520+ res . set ( 'Retry-After' , 1 ) ;
521+ }
522+ res . json ( {
523+ status : options . state ,
524+ } ) ;
525+ } ;
526+ }
527+
494528export function enforceRouteAllowList ( req , res , next ) {
495529 const config = req . config ;
496530 if ( ! config || config . routeAllowList === undefined || config . routeAllowList === null ) {
0 commit comments