Skip to content

Commit 15fc186

Browse files
committed
Extract query validation logic
1 parent ea09213 commit 15fc186

File tree

4 files changed

+38
-43
lines changed

4 files changed

+38
-43
lines changed

src/Adapters/Storage/Mongo/MongoStorageAdapter.js

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -185,12 +185,7 @@ export class MongoStorageAdapter {
185185
deleteObjectsByQuery(className, query, validate, schema) {
186186
return this.adaptiveCollection(className)
187187
.then(collection => {
188-
if (query.ACL) {
189-
throw new Parse.Error(Parse.Error.INVALID_QUERY, 'Cannot query on ACL.');
190-
}
191-
if (validate && Object.keys(query).some(restKey => !specialQuerykeys.includes(restKey) && !restKey.match(/^[a-zA-Z][a-zA-Z0-9_\.]*$/))) {
192-
throw new Parse.Error(Parse.Error.INVALID_KEY_NAME, `Invalid key name: ${restKey}`);
193-
}
188+
transform.validateQuery(query);
194189
let mongoWhere = transform.transformWhere(className, query, schema);
195190
return collection.deleteMany(mongoWhere)
196191
})

src/Adapters/Storage/Mongo/MongoTransform.js

Lines changed: 32 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -167,31 +167,9 @@ function transformQueryKeyValue(className, key, value, schema) {
167167
case '_perishable_token':
168168
case '_email_verify_token': return {key, value}
169169
case '$or':
170-
if (!(value instanceof Array)) {
171-
throw new Parse.Error(Parse.Error.INVALID_QUERY, 'bad $or format - use an array value');
172-
}
173-
if (value.some(subQuery => subQuery.ACL)) {
174-
throw new Parse.Error(Parse.Error.INVALID_QUERY, 'Cannot query on ACL.');
175-
Object.keys(subQuery).forEach(restKey => {
176-
if (!specialQuerykeys.includes(restKey) && !restKey.match(/^[a-zA-Z][a-zA-Z0-9_\.]*$/)) {
177-
throw new Parse.Error(Parse.Error.INVALID_KEY_NAME, `Invalid key name: ${restKey}`);
178-
}
179-
});
180-
}
181-
return {key: '$or', value: value.map(subQuery => transformWhere(className, subQuery, {}, schema))};
170+
return {key: '$or', value: value.map(subQuery => transformWhere(className, subQuery, schema))};
182171
case '$and':
183-
if (!(value instanceof Array)) {
184-
throw new Parse.Error(Parse.Error.INVALID_QUERY, 'bad $and format - use an array value');
185-
}
186-
if (value.some(subQuery => subQuery.ACL)) {
187-
throw new Parse.Error(Parse.Error.INVALID_QUERY, 'Cannot query on ACL.');
188-
Object.keys(subQuery).forEach(restKey => {
189-
if (!specialQuerykeys.includes(restKey) && !restKey.match(/^[a-zA-Z][a-zA-Z0-9_\.]*$/)) {
190-
throw new Parse.Error(Parse.Error.INVALID_KEY_NAME, `Invalid key name: ${restKey}`);
191-
}
192-
});
193-
}
194-
return {key: '$and', value: value.map(subQuery => transformWhere(className, subQuery, {}, schema))};
172+
return {key: '$and', value: value.map(subQuery => transformWhere(className, subQuery, schema))};
195173
default:
196174
// Other auth data
197175
const authDataMatch = key.match(/^authData\.([a-zA-Z0-9_]+)\.id$/);
@@ -233,17 +211,42 @@ function transformQueryKeyValue(className, key, value, schema) {
233211
}
234212
}
235213

214+
const validateQuery = query => {
215+
if (query.ACL) {
216+
throw new Parse.Error(Parse.Error.INVALID_QUERY, 'Cannot query on ACL.');
217+
}
218+
219+
if (query.$or) {
220+
if (query.$or instanceof Array) {
221+
query.$or.forEach(validateQuery);
222+
} else {
223+
throw new Parse.Error(Parse.Error.INVALID_QUERY, 'Bad $or format - use an array value.');
224+
}
225+
}
226+
227+
if (query.$and) {
228+
if (query.$and instanceof Array) {
229+
query.$and.forEach(validateQuery);
230+
} else {
231+
throw new Parse.Error(Parse.Error.INVALID_QUERY, 'Bad $and format - use an array value.');
232+
}
233+
}
234+
235+
Object.keys(query).forEach(key => {
236+
if (!specialQuerykeys.includes(key) && !key.match(/^[a-zA-Z][a-zA-Z0-9_\.]*$/)) {
237+
throw new Parse.Error(Parse.Error.INVALID_KEY_NAME, `Invalid key name: ${key}`);
238+
}
239+
});
240+
}
241+
236242
// Main exposed method to help run queries.
237243
// restWhere is the "where" clause in REST API form.
238244
// Returns the mongo form of the query.
239245
// Throws a Parse.Error if the input query is invalid.
240246
const specialQuerykeys = ['$and', '$or', '_rperm', '_wperm', '_perishable_token', '_email_verify_token'];
241-
function transformWhere(className, restWhere, { validate = true } = {}, schema) {
247+
function transformWhere(className, restWhere, schema) {
242248
let mongoWhere = {};
243249
for (let restKey in restWhere) {
244-
if (validate && !specialQuerykeys.includes(restKey) && !restKey.match(/^[a-zA-Z][a-zA-Z0-9_\.]*$/)) {
245-
throw new Parse.Error(Parse.Error.INVALID_KEY_NAME, `Invalid key name: ${restKey}`);
246-
}
247250
let out = transformQueryKeyValue(className, restKey, restWhere[restKey], schema);
248251
mongoWhere[out.key] = out.value;
249252
}
@@ -1045,6 +1048,7 @@ var FileCoder = {
10451048

10461049
module.exports = {
10471050
transformKey,
1051+
validateQuery,
10481052
parseObjectToMongoObjectForCreate,
10491053
transformUpdate,
10501054
transformWhere,

src/Controllers/DatabaseController.js

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -184,10 +184,8 @@ DatabaseController.prototype.update = function(className, query, update, {
184184
throw error;
185185
})
186186
.then(parseFormatSchema => {
187-
if (query.ACL) {
188-
throw new Parse.Error(Parse.Error.INVALID_QUERY, 'Cannot query on ACL.');
189-
}
190-
var mongoWhere = this.transform.transformWhere(className, query, {validate: !this.skipValidation}, parseFormatSchema);
187+
this.transform.validateQuery(query);
188+
var mongoWhere = this.transform.transformWhere(className, query, parseFormatSchema);
191189
mongoUpdate = this.transform.transformUpdate(
192190
schemaController,
193191
className,
@@ -671,10 +669,8 @@ DatabaseController.prototype.find = function(className, query, {
671669
if (!isMaster) {
672670
query = addReadACL(query, aclGroup);
673671
}
674-
if (query.ACL) {
675-
throw new Parse.Error(Parse.Error.INVALID_QUERY, 'Cannot query on ACL.');
676-
}
677-
let mongoWhere = this.transform.transformWhere(className, query, {}, schema);
672+
this.transform.validateQuery(query);
673+
let mongoWhere = this.transform.transformWhere(className, query, schema);
678674
if (count) {
679675
delete mongoOptions.limit;
680676
return collection.count(mongoWhere, mongoOptions);

src/Routers/GlobalConfigRouter.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ export class GlobalConfigRouter extends PromiseRouter {
2424
return acc;
2525
}, {});
2626
let database = req.config.database.WithoutValidation();
27-
return database.update('_GlobalConfig', {_id: 1}, update, {upsert: true}).then(() => {
27+
return database.update('_GlobalConfig', {objectId: 1}, update, {upsert: true}).then(() => {
2828
return Promise.resolve({ response: { result: true } });
2929
});
3030
}

0 commit comments

Comments
 (0)