@@ -112,6 +112,16 @@ describe('request complexity', () => {
112112 ) ;
113113 } ) ;
114114
115+ it ( 'should reject non-boolean value for allowRegex' , async ( ) => {
116+ await expectAsync (
117+ reconfigureServer ( {
118+ requestComplexity : { allowRegex : 'yes' } ,
119+ } )
120+ ) . toBeRejectedWith (
121+ new Error ( 'requestComplexity.allowRegex must be a boolean.' )
122+ ) ;
123+ } ) ;
124+
115125 it ( 'should reject unknown properties' , async ( ) => {
116126 await expectAsync (
117127 reconfigureServer ( {
@@ -147,6 +157,7 @@ describe('request complexity', () => {
147157 await reconfigureServer ( { } ) ;
148158 const config = Config . get ( 'test' ) ;
149159 expect ( config . requestComplexity ) . toEqual ( {
160+ allowRegex : true ,
150161 batchRequestLimit : - 1 ,
151162 includeDepth : - 1 ,
152163 includeCount : - 1 ,
@@ -540,4 +551,185 @@ describe('request complexity', () => {
540551 ) . toBeResolved ( ) ;
541552 } ) ;
542553 } ) ;
554+
555+ describe ( 'allowRegex' , ( ) => {
556+ let config ;
557+
558+ beforeEach ( async ( ) => {
559+ await reconfigureServer ( {
560+ requestComplexity : { allowRegex : false } ,
561+ } ) ;
562+ config = Config . get ( 'test' ) ;
563+ } ) ;
564+
565+ it ( 'should reject $regex query when allowRegex is false (unauthenticated)' , async ( ) => {
566+ const where = { username : { $regex : 'test' } } ;
567+ await expectAsync (
568+ rest . find ( config , auth . nobody ( config ) , '_User' , where )
569+ ) . toBeRejectedWith (
570+ jasmine . objectContaining ( {
571+ message : '$regex operator is not allowed' ,
572+ } )
573+ ) ;
574+ } ) ;
575+
576+ it ( 'should reject $regex query when allowRegex is false (authenticated user)' , async ( ) => {
577+ const user = new Parse . User ( ) ;
578+ user . setUsername ( 'testuser' ) ;
579+ user . setPassword ( 'testpass' ) ;
580+ await user . signUp ( ) ;
581+ const userAuth = new auth . Auth ( {
582+ config,
583+ isMaster : false ,
584+ user,
585+ } ) ;
586+ const where = { username : { $regex : 'test' } } ;
587+ await expectAsync (
588+ rest . find ( config , userAuth , '_User' , where )
589+ ) . toBeRejectedWith (
590+ jasmine . objectContaining ( {
591+ message : '$regex operator is not allowed' ,
592+ } )
593+ ) ;
594+ } ) ;
595+
596+ it ( 'should allow $regex query when allowRegex is false with master key' , async ( ) => {
597+ const where = { username : { $regex : 'test' } } ;
598+ await expectAsync (
599+ rest . find ( config , auth . master ( config ) , '_User' , where )
600+ ) . toBeResolved ( ) ;
601+ } ) ;
602+
603+ it ( 'should allow $regex query when allowRegex is true (default)' , async ( ) => {
604+ await reconfigureServer ( {
605+ requestComplexity : { allowRegex : true } ,
606+ } ) ;
607+ config = Config . get ( 'test' ) ;
608+ const where = { username : { $regex : 'test' } } ;
609+ await expectAsync (
610+ rest . find ( config , auth . nobody ( config ) , '_User' , where )
611+ ) . toBeResolved ( ) ;
612+ } ) ;
613+
614+ it ( 'should reject $regex inside $or when allowRegex is false' , async ( ) => {
615+ const where = {
616+ $or : [
617+ { username : { $regex : 'test' } } ,
618+ { username : 'exact' } ,
619+ ] ,
620+ } ;
621+ await expectAsync (
622+ rest . find ( config , auth . nobody ( config ) , '_User' , where )
623+ ) . toBeRejectedWith (
624+ jasmine . objectContaining ( {
625+ message : '$regex operator is not allowed' ,
626+ } )
627+ ) ;
628+ } ) ;
629+
630+ it ( 'should reject $regex inside $and when allowRegex is false' , async ( ) => {
631+ const where = {
632+ $and : [
633+ { username : { $regex : 'test' } } ,
634+ { username : 'exact' } ,
635+ ] ,
636+ } ;
637+ await expectAsync (
638+ rest . find ( config , auth . nobody ( config ) , '_User' , where )
639+ ) . toBeRejectedWith (
640+ jasmine . objectContaining ( {
641+ message : '$regex operator is not allowed' ,
642+ } )
643+ ) ;
644+ } ) ;
645+
646+ it ( 'should reject $regex inside $nor when allowRegex is false' , async ( ) => {
647+ const where = {
648+ $nor : [
649+ { username : { $regex : 'test' } } ,
650+ ] ,
651+ } ;
652+ await expectAsync (
653+ rest . find ( config , auth . nobody ( config ) , '_User' , where )
654+ ) . toBeRejectedWith (
655+ jasmine . objectContaining ( {
656+ message : '$regex operator is not allowed' ,
657+ } )
658+ ) ;
659+ } ) ;
660+
661+ it ( 'should allow $regex by default when allowRegex is not configured' , async ( ) => {
662+ await reconfigureServer ( { } ) ;
663+ config = Config . get ( 'test' ) ;
664+ const where = { username : { $regex : 'test' } } ;
665+ await expectAsync (
666+ rest . find ( config , auth . nobody ( config ) , '_User' , where )
667+ ) . toBeResolved ( ) ;
668+ } ) ;
669+
670+ it ( 'should reject empty-string $regex when allowRegex is false' , async ( ) => {
671+ const where = { username : { $regex : '' } } ;
672+ await expectAsync (
673+ rest . find ( config , auth . nobody ( config ) , '_User' , where )
674+ ) . toBeRejectedWith (
675+ jasmine . objectContaining ( {
676+ message : '$regex operator is not allowed' ,
677+ } )
678+ ) ;
679+ } ) ;
680+
681+ it ( 'should allow $regex with maintenance key when allowRegex is false' , async ( ) => {
682+ const where = { username : { $regex : 'test' } } ;
683+ await expectAsync (
684+ rest . find ( config , auth . maintenance ( config ) , '_User' , where )
685+ ) . toBeResolved ( ) ;
686+ } ) ;
687+
688+ describe ( 'LiveQuery' , ( ) => {
689+ beforeEach ( async ( ) => {
690+ await reconfigureServer ( {
691+ requestComplexity : { allowRegex : false } ,
692+ liveQuery : { classNames : [ 'TestObject' ] } ,
693+ startLiveQueryServer : true ,
694+ } ) ;
695+ config = Config . get ( 'test' ) ;
696+ } ) ;
697+
698+ afterEach ( async ( ) => {
699+ const client = await Parse . CoreManager . getLiveQueryController ( ) . getDefaultLiveQueryClient ( ) ;
700+ if ( client ) {
701+ await client . close ( ) ;
702+ }
703+ } ) ;
704+
705+ it ( 'should reject LiveQuery subscription with $regex when allowRegex is false' , async ( ) => {
706+ const query = new Parse . Query ( 'TestObject' ) ;
707+ query . matches ( 'field' , / t e s t / ) ;
708+ await expectAsync ( query . subscribe ( ) ) . toBeRejectedWith (
709+ jasmine . objectContaining ( { code : Parse . Error . INVALID_QUERY } )
710+ ) ;
711+ } ) ;
712+
713+ it ( 'should reject LiveQuery subscription with $regex inside $or when allowRegex is false' , async ( ) => {
714+ const query = new Parse . Query ( 'TestObject' ) ;
715+ query . _where = {
716+ $or : [
717+ { field : { $regex : 'test' } } ,
718+ { field : 'exact' } ,
719+ ] ,
720+ } ;
721+ await expectAsync ( query . subscribe ( ) ) . toBeRejectedWith (
722+ jasmine . objectContaining ( { code : Parse . Error . INVALID_QUERY } )
723+ ) ;
724+ } ) ;
725+
726+ it ( 'should allow LiveQuery subscription without $regex when allowRegex is false' , async ( ) => {
727+ const query = new Parse . Query ( 'TestObject' ) ;
728+ query . equalTo ( 'field' , 'test' ) ;
729+ const subscription = await query . subscribe ( ) ;
730+ expect ( subscription ) . toBeDefined ( ) ;
731+ subscription . unsubscribe ( ) ;
732+ } ) ;
733+ } ) ;
734+ } ) ;
543735} ) ;
0 commit comments