@@ -24,6 +24,35 @@ function addReadACL(query, acl) {
2424 return newQuery ;
2525}
2626
27+ const specialQuerykeys = [ '$and' , '$or' , '_rperm' , '_wperm' , '_perishable_token' , '_email_verify_token' ] ;
28+ const validateQuery = query => {
29+ if ( query . ACL ) {
30+ throw new Parse . Error ( Parse . Error . INVALID_QUERY , 'Cannot query on ACL.' ) ;
31+ }
32+
33+ if ( query . $or ) {
34+ if ( query . $or instanceof Array ) {
35+ query . $or . forEach ( validateQuery ) ;
36+ } else {
37+ throw new Parse . Error ( Parse . Error . INVALID_QUERY , 'Bad $or format - use an array value.' ) ;
38+ }
39+ }
40+
41+ if ( query . $and ) {
42+ if ( query . $and instanceof Array ) {
43+ query . $and . forEach ( validateQuery ) ;
44+ } else {
45+ throw new Parse . Error ( Parse . Error . INVALID_QUERY , 'Bad $and format - use an array value.' ) ;
46+ }
47+ }
48+
49+ Object . keys ( query ) . forEach ( key => {
50+ if ( ! specialQuerykeys . includes ( key ) && ! key . match ( / ^ [ a - z A - Z ] [ a - z A - Z 0 - 9 _ \. ] * $ / ) ) {
51+ throw new Parse . Error ( Parse . Error . INVALID_KEY_NAME , `Invalid key name: ${ key } ` ) ;
52+ }
53+ } ) ;
54+ }
55+
2756function DatabaseController ( adapter , { skipValidation } = { } ) {
2857 this . adapter = adapter ;
2958
@@ -174,6 +203,7 @@ DatabaseController.prototype.update = function(className, query, update, {
174203 if ( acl ) {
175204 query = addWriteACL ( query , acl ) ;
176205 }
206+ validateQuery ( query ) ;
177207 return schemaController . getOneSchema ( className )
178208 . catch ( error => {
179209 // If the schema doesn't exist, pretend it exists with no fields. This behaviour
@@ -184,7 +214,7 @@ DatabaseController.prototype.update = function(className, query, update, {
184214 throw error ;
185215 } )
186216 . then ( parseFormatSchema => {
187- var mongoWhere = this . transform . transformWhere ( className , query , { validate : ! this . skipValidation } , parseFormatSchema ) ;
217+ var mongoWhere = this . transform . transformWhere ( className , query , parseFormatSchema ) ;
188218 mongoUpdate = this . transform . transformUpdate (
189219 schemaController ,
190220 className ,
@@ -328,6 +358,7 @@ DatabaseController.prototype.destroy = function(className, query, { acl } = {})
328358 if ( acl ) {
329359 query = addWriteACL ( query , acl ) ;
330360 }
361+ validateQuery ( query ) ;
331362 return schemaController . getOneSchema ( className )
332363 . catch ( error => {
333364 // If the schema doesn't exist, pretend it exists with no fields. This behaviour
@@ -337,7 +368,7 @@ DatabaseController.prototype.destroy = function(className, query, { acl } = {})
337368 }
338369 throw error ;
339370 } )
340- . then ( parseFormatSchema => this . adapter . deleteObjectsByQuery ( className , query , ! this . skipValidation , parseFormatSchema ) )
371+ . then ( parseFormatSchema => this . adapter . deleteObjectsByQuery ( className , query , parseFormatSchema ) )
341372 . catch ( error => {
342373 // When deleting sessions while changing passwords, don't throw an error if they don't have any sessions.
343374 if ( className === "_Session" && error . code === Parse . Error . OBJECT_NOT_FOUND ) {
@@ -668,7 +699,8 @@ DatabaseController.prototype.find = function(className, query, {
668699 if ( ! isMaster ) {
669700 query = addReadACL ( query , aclGroup ) ;
670701 }
671- let mongoWhere = this . transform . transformWhere ( className , query , { } , schema ) ;
702+ validateQuery ( query ) ;
703+ let mongoWhere = this . transform . transformWhere ( className , query , schema ) ;
672704 if ( count ) {
673705 delete mongoOptions . limit ;
674706 return collection . count ( mongoWhere , mongoOptions ) ;
0 commit comments