Skip to content

Commit 86beaaf

Browse files
committed
Makes sure we run relational updates AFTER validating access to the object
1 parent 6356200 commit 86beaaf

File tree

1 file changed

+44
-20
lines changed

1 file changed

+44
-20
lines changed

src/Controllers/DatabaseController.js

Lines changed: 44 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -235,17 +235,18 @@ DatabaseController.prototype.update = function(className, query, update, {
235235
many,
236236
upsert,
237237
} = {}, skipSanitization = false) {
238+
const originalQuery = query;
238239
const originalUpdate = update;
239240
// Make a copy of the object, so we don't mutate the incoming data.
240241
update = deepcopy(update);
241-
242+
var relationUpdates = [];
242243
var isMaster = acl === undefined;
243244
var aclGroup = acl || [];
244245
return this.loadSchema()
245246
.then(schemaController => {
246247
return (isMaster ? Promise.resolve() : schemaController.validatePermission(className, aclGroup, 'update'))
247-
.then(() => this.handleRelationUpdates(className, query.objectId, update))
248248
.then(() => {
249+
relationUpdates = this.collectRelationUpdates(className, originalQuery.objectId, update);
249250
if (!isMaster) {
250251
query = this.addPointerPermissions(schemaController, className, 'update', query, aclGroup);
251252
}
@@ -295,6 +296,10 @@ DatabaseController.prototype.update = function(className, query, update, {
295296
if (!result) {
296297
return Promise.reject(new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'Object not found.'));
297298
}
299+
return this.handleRelationUpdates(className, originalQuery.objectId, update, relationUpdates).then(() => {
300+
return result;
301+
});
302+
}).then((result) => {
298303
if (skipSanitization) {
299304
return Promise.resolve(result);
300305
}
@@ -320,12 +325,8 @@ function sanitizeDatabaseResult(originalObject, result) {
320325
return Promise.resolve(response);
321326
}
322327

323-
// Processes relation-updating operations from a REST-format update.
324-
// Returns a promise that resolves successfully when these are
325-
// processed.
326-
// This mutates update.
327-
DatabaseController.prototype.handleRelationUpdates = function(className, objectId, update) {
328-
var pending = [];
328+
DatabaseController.prototype.collectRelationUpdates = function(className, objectId, update) {
329+
var ops = [];
329330
var deleteMe = [];
330331
objectId = update.objectId || objectId;
331332

@@ -334,20 +335,12 @@ DatabaseController.prototype.handleRelationUpdates = function(className, objectI
334335
return;
335336
}
336337
if (op.__op == 'AddRelation') {
337-
for (const object of op.objects) {
338-
pending.push(this.addRelation(key, className,
339-
objectId,
340-
object.objectId));
341-
}
338+
ops.push({key, op});
342339
deleteMe.push(key);
343340
}
344341

345342
if (op.__op == 'RemoveRelation') {
346-
for (const object of op.objects) {
347-
pending.push(this.removeRelation(key, className,
348-
objectId,
349-
object.objectId));
350-
}
343+
ops.push({key, op});
351344
deleteMe.push(key);
352345
}
353346

@@ -364,6 +357,37 @@ DatabaseController.prototype.handleRelationUpdates = function(className, objectI
364357
for (const key of deleteMe) {
365358
delete update[key];
366359
}
360+
return ops;
361+
}
362+
363+
// Processes relation-updating operations from a REST-format update.
364+
// Returns a promise that resolves successfully when these are
365+
// processed.
366+
// This mutates update.
367+
DatabaseController.prototype.handleRelationUpdates = function(className, objectId, update, ops) {
368+
var pending = [];
369+
objectId = update.objectId || objectId;
370+
ops.forEach(({key, op}) => {
371+
if (!op) {
372+
return;
373+
}
374+
if (op.__op == 'AddRelation') {
375+
for (const object of op.objects) {
376+
pending.push(this.addRelation(key, className,
377+
objectId,
378+
object.objectId));
379+
}
380+
}
381+
382+
if (op.__op == 'RemoveRelation') {
383+
for (const object of op.objects) {
384+
pending.push(this.removeRelation(key, className,
385+
objectId,
386+
object.objectId));
387+
}
388+
}
389+
});
390+
367391
return Promise.all(pending);
368392
};
369393

@@ -511,12 +535,12 @@ DatabaseController.prototype.create = function(className, object, { acl } = {})
511535

512536
var isMaster = acl === undefined;
513537
var aclGroup = acl || [];
514-
538+
const relationUpdates = this.collectRelationUpdates(className, null, object);
515539
return this.validateClassName(className)
516540
.then(() => this.loadSchema())
517541
.then(schemaController => {
518542
return (isMaster ? Promise.resolve() : schemaController.validatePermission(className, aclGroup, 'create'))
519-
.then(() => this.handleRelationUpdates(className, null, object))
543+
.then(() => this.handleRelationUpdates(className, null, object, relationUpdates))
520544
.then(() => schemaController.enforceClassExists(className))
521545
.then(() => schemaController.reloadData())
522546
.then(() => schemaController.getOneSchema(className, true))

0 commit comments

Comments
 (0)