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:
@@ -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();
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -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 => {
|
it('can add classes without needing an object', done => {
|
||||||
config.database.loadSchema()
|
config.database.loadSchema()
|
||||||
.then(schema => schema.addClassIfNotExists('NewClass', {
|
.then(schema => schema.addClassIfNotExists('NewClass', {
|
||||||
|
|||||||
@@ -744,6 +744,9 @@ DatabaseController.prototype.find = function(className, query, {
|
|||||||
const isMaster = acl === undefined;
|
const isMaster = acl === undefined;
|
||||||
const aclGroup = acl || [];
|
const aclGroup = acl || [];
|
||||||
op = op || (typeof query.objectId == 'string' && Object.keys(query).length === 1 ? 'get' : 'find');
|
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;
|
let classExists = true;
|
||||||
return this.loadSchema()
|
return this.loadSchema()
|
||||||
.then(schemaController => {
|
.then(schemaController => {
|
||||||
|
|||||||
@@ -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) {
|
function validateCLP(perms, fields) {
|
||||||
if (!perms) {
|
if (!perms) {
|
||||||
return;
|
return;
|
||||||
@@ -820,7 +820,7 @@ export default class SchemaController {
|
|||||||
|
|
||||||
// No matching CLP, let's check the Pointer permissions
|
// No matching CLP, let's check the Pointer permissions
|
||||||
// And handle those later
|
// 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
|
// Reject create when write lockdown
|
||||||
if (permissionField == 'writeUserFields' && operation == 'create') {
|
if (permissionField == 'writeUserFields' && operation == 'create') {
|
||||||
|
|||||||
@@ -155,11 +155,12 @@ export function getRequestObject(triggerType, auth, parseObject, originalParseOb
|
|||||||
return request;
|
return request;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getRequestQueryObject(triggerType, auth, query, config) {
|
export function getRequestQueryObject(triggerType, auth, query, count, config) {
|
||||||
var request = {
|
var request = {
|
||||||
triggerName: triggerType,
|
triggerName: triggerType,
|
||||||
query: query,
|
query,
|
||||||
master: false,
|
master: false,
|
||||||
|
count,
|
||||||
log: config.loggerController
|
log: config.loggerController
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -298,6 +299,7 @@ export function maybeRunQueryTrigger(triggerType, className, restWhere, restOpti
|
|||||||
if (restWhere) {
|
if (restWhere) {
|
||||||
parseQuery._where = restWhere;
|
parseQuery._where = restWhere;
|
||||||
}
|
}
|
||||||
|
let count = false;
|
||||||
if (restOptions) {
|
if (restOptions) {
|
||||||
if (restOptions.include && restOptions.include.length > 0) {
|
if (restOptions.include && restOptions.include.length > 0) {
|
||||||
parseQuery._include = restOptions.include.split(',');
|
parseQuery._include = restOptions.include.split(',');
|
||||||
@@ -308,8 +310,9 @@ export function maybeRunQueryTrigger(triggerType, className, restWhere, restOpti
|
|||||||
if (restOptions.limit) {
|
if (restOptions.limit) {
|
||||||
parseQuery._limit = 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 Promise.resolve().then(() => {
|
||||||
return trigger(requestObject);
|
return trigger(requestObject);
|
||||||
}).then((result) => {
|
}).then((result) => {
|
||||||
|
|||||||
Reference in New Issue
Block a user