@@ -5565,4 +5565,188 @@ describe('Parse.Query testing', () => {
55655565 }
55665566 ) ;
55675567 } ) ;
5568+
5569+ describe ( 'query input type validation' , ( ) => {
5570+ const restHeaders = {
5571+ 'Content-Type' : 'application/json' ,
5572+ 'X-Parse-Application-Id' : 'test' ,
5573+ 'X-Parse-REST-API-Key' : 'rest' ,
5574+ } ;
5575+
5576+ describe ( 'malformed where parameter' , ( ) => {
5577+ it ( 'rejects invalid JSON in where parameter with proper error instead of 500' , async ( ) => {
5578+ await expectAsync (
5579+ request ( {
5580+ method : 'GET' ,
5581+ url : 'http://localhost:8378/1/classes/TestClass?where=%7Bbad-json' ,
5582+ headers : restHeaders ,
5583+ } )
5584+ ) . toBeRejectedWith ( jasmine . objectContaining ( { status : 400 } ) ) ;
5585+ } ) ;
5586+
5587+ it ( 'rejects invalid JSON in where parameter for roles endpoint' , async ( ) => {
5588+ await expectAsync (
5589+ request ( {
5590+ method : 'GET' ,
5591+ url : 'http://localhost:8378/1/roles?where=%7Bbad-json' ,
5592+ headers : restHeaders ,
5593+ } )
5594+ ) . toBeRejectedWith ( jasmine . objectContaining ( { status : 400 } ) ) ;
5595+ } ) ;
5596+
5597+ it ( 'rejects invalid JSON in where parameter for users endpoint' , async ( ) => {
5598+ await expectAsync (
5599+ request ( {
5600+ method : 'GET' ,
5601+ url : 'http://localhost:8378/1/users?where=%7Bbad-json' ,
5602+ headers : restHeaders ,
5603+ } )
5604+ ) . toBeRejectedWith ( jasmine . objectContaining ( { status : 400 } ) ) ;
5605+ } ) ;
5606+
5607+ it ( 'rejects invalid JSON in where parameter for sessions endpoint' , async ( ) => {
5608+ await expectAsync (
5609+ request ( {
5610+ method : 'GET' ,
5611+ url : 'http://localhost:8378/1/sessions?where=%7Bbad-json' ,
5612+ headers : restHeaders ,
5613+ } )
5614+ ) . toBeRejectedWith ( jasmine . objectContaining ( { status : 400 } ) ) ;
5615+ } ) ;
5616+
5617+ it ( 'still accepts valid JSON in where parameter' , async ( ) => {
5618+ const result = await request ( {
5619+ method : 'GET' ,
5620+ url : `http://localhost:8378/1/classes/TestClass?where=${ encodeURIComponent ( JSON . stringify ( { } ) ) } ` ,
5621+ headers : restHeaders ,
5622+ } ) ;
5623+ expect ( result . data . results ) . toEqual ( [ ] ) ;
5624+ } ) ;
5625+ } ) ;
5626+
5627+ describe ( '$regex type validation' , ( ) => {
5628+ it ( 'rejects object $regex in query' , async ( ) => {
5629+ const where = JSON . stringify ( { field : { $regex : { a : 1 } } } ) ;
5630+ await expectAsync (
5631+ request ( {
5632+ method : 'GET' ,
5633+ url : `http://localhost:8378/1/classes/TestClass?where=${ encodeURIComponent ( where ) } ` ,
5634+ headers : restHeaders ,
5635+ } )
5636+ ) . toBeRejectedWith ( jasmine . objectContaining ( { status : 400 } ) ) ;
5637+ } ) ;
5638+
5639+ it ( 'rejects numeric $regex in query' , async ( ) => {
5640+ const where = JSON . stringify ( { field : { $regex : 123 } } ) ;
5641+ await expectAsync (
5642+ request ( {
5643+ method : 'GET' ,
5644+ url : `http://localhost:8378/1/classes/TestClass?where=${ encodeURIComponent ( where ) } ` ,
5645+ headers : restHeaders ,
5646+ } )
5647+ ) . toBeRejectedWith ( jasmine . objectContaining ( { status : 400 } ) ) ;
5648+ } ) ;
5649+
5650+ it ( 'rejects array $regex in query' , async ( ) => {
5651+ const where = JSON . stringify ( { field : { $regex : [ 'test' ] } } ) ;
5652+ await expectAsync (
5653+ request ( {
5654+ method : 'GET' ,
5655+ url : `http://localhost:8378/1/classes/TestClass?where=${ encodeURIComponent ( where ) } ` ,
5656+ headers : restHeaders ,
5657+ } )
5658+ ) . toBeRejectedWith ( jasmine . objectContaining ( { status : 400 } ) ) ;
5659+ } ) ;
5660+
5661+ it ( 'still accepts valid string $regex in query' , async ( ) => {
5662+ const obj = new Parse . Object ( 'TestClass' ) ;
5663+ obj . set ( 'field' , 'hello' ) ;
5664+ await obj . save ( ) ;
5665+ const where = JSON . stringify ( { field : { $regex : '^hello$' } } ) ;
5666+ const result = await request ( {
5667+ method : 'GET' ,
5668+ url : `http://localhost:8378/1/classes/TestClass?where=${ encodeURIComponent ( where ) } ` ,
5669+ headers : restHeaders ,
5670+ } ) ;
5671+ expect ( result . data . results . length ) . toBe ( 1 ) ;
5672+ } ) ;
5673+ } ) ;
5674+
5675+ describe ( '$options type validation' , ( ) => {
5676+ it ( 'rejects numeric $options in query' , async ( ) => {
5677+ const where = JSON . stringify ( { field : { $regex : 'test' , $options : 123 } } ) ;
5678+ await expectAsync (
5679+ request ( {
5680+ method : 'GET' ,
5681+ url : `http://localhost:8378/1/classes/TestClass?where=${ encodeURIComponent ( where ) } ` ,
5682+ headers : restHeaders ,
5683+ } )
5684+ ) . toBeRejectedWith ( jasmine . objectContaining ( { status : 400 } ) ) ;
5685+ } ) ;
5686+
5687+ it ( 'rejects object $options in query' , async ( ) => {
5688+ const where = JSON . stringify ( { field : { $regex : 'test' , $options : { a : 1 } } } ) ;
5689+ await expectAsync (
5690+ request ( {
5691+ method : 'GET' ,
5692+ url : `http://localhost:8378/1/classes/TestClass?where=${ encodeURIComponent ( where ) } ` ,
5693+ headers : restHeaders ,
5694+ } )
5695+ ) . toBeRejectedWith ( jasmine . objectContaining ( { status : 400 } ) ) ;
5696+ } ) ;
5697+
5698+ it ( 'rejects boolean $options in query' , async ( ) => {
5699+ const where = JSON . stringify ( { field : { $regex : 'test' , $options : true } } ) ;
5700+ await expectAsync (
5701+ request ( {
5702+ method : 'GET' ,
5703+ url : `http://localhost:8378/1/classes/TestClass?where=${ encodeURIComponent ( where ) } ` ,
5704+ headers : restHeaders ,
5705+ } )
5706+ ) . toBeRejectedWith ( jasmine . objectContaining ( { status : 400 } ) ) ;
5707+ } ) ;
5708+
5709+ it ( 'still accepts valid string $options in query' , async ( ) => {
5710+ const obj = new Parse . Object ( 'TestClass' ) ;
5711+ obj . set ( 'field' , 'hello' ) ;
5712+ await obj . save ( ) ;
5713+ const where = JSON . stringify ( { field : { $regex : 'hello' , $options : 'i' } } ) ;
5714+ const result = await request ( {
5715+ method : 'GET' ,
5716+ url : `http://localhost:8378/1/classes/TestClass?where=${ encodeURIComponent ( where ) } ` ,
5717+ headers : restHeaders ,
5718+ } ) ;
5719+ expect ( result . data . results . length ) . toBe ( 1 ) ;
5720+ } ) ;
5721+ } ) ;
5722+
5723+ describe ( '$in type validation on text fields' , ( ) => {
5724+ it_only_db ( 'postgres' ) ( 'rejects non-matching type in $in for text field with proper error instead of 500' , async ( ) => {
5725+ const obj = new Parse . Object ( 'TestClass' ) ;
5726+ obj . set ( 'textField' , 'hello' ) ;
5727+ await obj . save ( ) ;
5728+ const where = JSON . stringify ( { textField : { $in : [ 1 , 2 , 3 ] } } ) ;
5729+ await expectAsync (
5730+ request ( {
5731+ method : 'GET' ,
5732+ url : `http://localhost:8378/1/classes/TestClass?where=${ encodeURIComponent ( where ) } ` ,
5733+ headers : restHeaders ,
5734+ } )
5735+ ) . toBeRejectedWith ( jasmine . objectContaining ( { status : 400 } ) ) ;
5736+ } ) ;
5737+
5738+ it ( 'still accepts matching type in $in for text field' , async ( ) => {
5739+ const obj = new Parse . Object ( 'TestClass' ) ;
5740+ obj . set ( 'textField' , 'hello' ) ;
5741+ await obj . save ( ) ;
5742+ const where = JSON . stringify ( { textField : { $in : [ 'hello' , 'world' ] } } ) ;
5743+ const result = await request ( {
5744+ method : 'GET' ,
5745+ url : `http://localhost:8378/1/classes/TestClass?where=${ encodeURIComponent ( where ) } ` ,
5746+ headers : restHeaders ,
5747+ } ) ;
5748+ expect ( result . data . results . length ) . toBe ( 1 ) ;
5749+ } ) ;
5750+ } ) ;
5751+ } ) ;
55685752} ) ;
0 commit comments