Adds count class level permission (#3814)

* Adds count class level permission

* fixup! Adds count class level permission

* Adds missing count property on beforeFind request object

* nits
This commit is contained in:
Florent Vilmart
2017-05-14 21:47:30 -04:00
committed by GitHub
parent d71683a7e2
commit 691cf5988a
5 changed files with 75 additions and 5 deletions

View File

@@ -1470,4 +1470,36 @@ describe('afterFind hooks', () => {
});
});
});
it('should set count to true on beforeFind hooks if query is count', (done) => {
const hook = {
method: function(req) {
expect(req.count).toBe(true);
return Promise.resolve();
}
};
spyOn(hook, 'method').and.callThrough();
Parse.Cloud.beforeFind('Stuff', hook.method);
new Parse.Query('Stuff').count().then((count) => {
expect(count).toBe(0);
expect(hook.method).toHaveBeenCalled();
done();
});
});
it('should set count to false on beforeFind hooks if query is not count', (done) => {
const hook = {
method: function(req) {
expect(req.count).toBe(false);
return Promise.resolve();
}
};
spyOn(hook, 'method').and.callThrough();
Parse.Cloud.beforeFind('Stuff', hook.method);
new Parse.Query('Stuff').find().then((res) => {
expect(res.length).toBe(0);
expect(hook.method).toHaveBeenCalled();
done();
});
});
});

View File

@@ -178,6 +178,38 @@ describe('SchemaController', () => {
});
});
it('class-level permissions test count', (done) => {
var obj;
return config.database.loadSchema()
// Create a valid class
.then(schema => schema.validateObject('Stuff', {foo: 'bar'}))
.then(schema => {
var count = {};
return schema.setPermissions('Stuff', {
'create': {'*': true},
'find': {'*': true},
'count': count
})
}).then(() => {
obj = new Parse.Object('Stuff');
obj.set('foo', 'bar');
return obj.save();
}).then((o) => {
obj = o;
var query = new Parse.Query('Stuff');
return query.find();
}).then((results) => {
expect(results.length).toBe(1);
var query = new Parse.Query('Stuff');
return query.count();
}).then(() => {
fail('Class permissions should have rejected this query.');
}, (err) => {
expect(err.message).toEqual('Permission denied for action count on class Stuff.');
done();
});
});
it('can add classes without needing an object', done => {
config.database.loadSchema()
.then(schema => schema.addClassIfNotExists('NewClass', {

View File

@@ -744,6 +744,9 @@ DatabaseController.prototype.find = function(className, query, {
const isMaster = acl === undefined;
const aclGroup = acl || [];
op = op || (typeof query.objectId == 'string' && Object.keys(query).length === 1 ? 'get' : 'find');
// Count operation if counting
op = (count === true ? 'count' : op);
let classExists = true;
return this.loadSchema()
.then(schemaController => {

View File

@@ -137,7 +137,7 @@ function verifyPermissionKey(key) {
}
}
const CLPValidKeys = Object.freeze(['find', 'get', 'create', 'update', 'delete', 'addField', 'readUserFields', 'writeUserFields']);
const CLPValidKeys = Object.freeze(['find', 'count', 'get', 'create', 'update', 'delete', 'addField', 'readUserFields', 'writeUserFields']);
function validateCLP(perms, fields) {
if (!perms) {
return;
@@ -820,7 +820,7 @@ export default class SchemaController {
// No matching CLP, let's check the Pointer permissions
// And handle those later
const permissionField = ['get', 'find'].indexOf(operation) > -1 ? 'readUserFields' : 'writeUserFields';
const permissionField = ['get', 'find', 'count'].indexOf(operation) > -1 ? 'readUserFields' : 'writeUserFields';
// Reject create when write lockdown
if (permissionField == 'writeUserFields' && operation == 'create') {

View File

@@ -155,11 +155,12 @@ export function getRequestObject(triggerType, auth, parseObject, originalParseOb
return request;
}
export function getRequestQueryObject(triggerType, auth, query, config) {
export function getRequestQueryObject(triggerType, auth, query, count, config) {
var request = {
triggerName: triggerType,
query: query,
query,
master: false,
count,
log: config.loggerController
};
@@ -298,6 +299,7 @@ export function maybeRunQueryTrigger(triggerType, className, restWhere, restOpti
if (restWhere) {
parseQuery._where = restWhere;
}
let count = false;
if (restOptions) {
if (restOptions.include && restOptions.include.length > 0) {
parseQuery._include = restOptions.include.split(',');
@@ -308,8 +310,9 @@ export function maybeRunQueryTrigger(triggerType, className, restWhere, restOpti
if (restOptions.limit) {
parseQuery._limit = restOptions.limit;
}
count = !!restOptions.count;
}
const requestObject = getRequestQueryObject(triggerType, auth, parseQuery, config);
const requestObject = getRequestQueryObject(triggerType, auth, parseQuery, count, config);
return Promise.resolve().then(() => {
return trigger(requestObject);
}).then((result) => {