Skip to content

Commit 2fb7827

Browse files
committed
allow for a function
1 parent 20e1cf4 commit 2fb7827

File tree

3 files changed

+80
-6
lines changed

3 files changed

+80
-6
lines changed

spec/CloudCode.Validator.spec.js

+61
Original file line numberDiff line numberDiff line change
@@ -935,6 +935,67 @@ describe('cloud validator', () => {
935935
done();
936936
});
937937

938+
it('allow requireAnyUserRoles to be a function', async function (done) {
939+
Parse.Cloud.define(
940+
'cloudFunction',
941+
() => {
942+
return true;
943+
},
944+
{
945+
requireUser: true,
946+
requireAnyUserRoles: () => {
947+
return ['Admin Func'];
948+
},
949+
}
950+
);
951+
const user = await Parse.User.signUp('testuser', 'p@ssword');
952+
try {
953+
await Parse.Cloud.run('cloudFunction');
954+
fail('cloud validator should have failed.');
955+
} catch (e) {
956+
expect(e.message).toBe('Validation failed. User does not match the required roles.');
957+
}
958+
const roleACL = new Parse.ACL();
959+
roleACL.setPublicReadAccess(true);
960+
const role = new Parse.Role('Admin Func', roleACL);
961+
role.getUsers().add(user);
962+
await role.save({ useMasterKey: true });
963+
await Parse.Cloud.run('cloudFunction');
964+
done();
965+
});
966+
967+
it('allow requireAllUserRoles to be a function', async function (done) {
968+
Parse.Cloud.define(
969+
'cloudFunction',
970+
() => {
971+
return true;
972+
},
973+
{
974+
requireUser: true,
975+
requireAllUserRoles: () => {
976+
return ['AdminA', 'AdminB'];
977+
},
978+
}
979+
);
980+
const user = await Parse.User.signUp('testuser', 'p@ssword');
981+
try {
982+
await Parse.Cloud.run('cloudFunction');
983+
fail('cloud validator should have failed.');
984+
} catch (e) {
985+
expect(e.message).toBe('Validation failed. User does not match all the required roles.');
986+
}
987+
const roleACL = new Parse.ACL();
988+
roleACL.setPublicReadAccess(true);
989+
const role = new Parse.Role('AdminA', roleACL);
990+
role.getUsers().add(user);
991+
992+
const role2 = new Parse.Role('AdminB', roleACL);
993+
role2.getUsers().add(user);
994+
await Promise.all([role.save({ useMasterKey: true }), role2.save({ useMasterKey: true })]);
995+
await Parse.Cloud.run('cloudFunction');
996+
done();
997+
});
998+
938999
it('basic requireAllUserRoles but no user', async function (done) {
9391000
Parse.Cloud.define(
9401001
'cloudFunction',

src/cloud-code/Parse.Cloud.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -751,8 +751,8 @@ module.exports = ParseCloud;
751751
* @property {Array|function|Any} requireUserKeys.field.options array of options that the field can be, function to validate field, or single value. Throw an error if value is invalid.
752752
* @property {String} requireUserKeys.field.error custom error message if field is invalid.
753753
*
754-
* @property {Array<String>}requireAnyUserRoles If set, request.user has to be part of at least one roles name to make the request.
755-
* @property {Array<String>}requireAllUserRoles If set, request.user has to be part all roles name to make the request.
754+
* @property {Array<String>|function}requireAnyUserRoles If set, request.user has to be part of at least one roles name to make the request. If set to a function, function must return role names.
755+
* @property {Array<String>|function}requireAllUserRoles If set, request.user has to be part all roles name to make the request. If set to a function, function must return role names.
756756
*
757757
* @property {Object|Array<String>} fields if an array of strings, validator will look for keys in request.params, and throw if not provided. If Object, fields to validate. If the trigger is a cloud function, `request.params` will be validated, otherwise `request.object`.
758758
* @property {String} fields.field name of field to validate.

src/triggers.js

+17-4
Original file line numberDiff line numberDiff line change
@@ -735,11 +735,24 @@ async function builtInTriggerValidator(options, request, auth) {
735735
}
736736
}
737737
}
738-
const userRoles = options.requireAnyUserRoles;
739-
const requireAllRoles = options.requireAllUserRoles;
740-
let roles;
738+
let userRoles = options.requireAnyUserRoles;
739+
let requireAllRoles = options.requireAllUserRoles;
740+
const promises = [Promise.resolve(), Promise.resolve(), Promise.resolve()];
741741
if (userRoles || requireAllRoles) {
742-
roles = await auth.getUserRoles();
742+
promises[0] = auth.getUserRoles();
743+
}
744+
if (typeof userRoles === 'function') {
745+
promises[1] = userRoles();
746+
}
747+
if (typeof requireAllRoles === 'function') {
748+
promises[2] = requireAllRoles();
749+
}
750+
const [roles, resolvedUserRoles, resolvedRequireAll] = await Promise.all(promises);
751+
if (resolvedUserRoles && Array.isArray(resolvedUserRoles)) {
752+
userRoles = resolvedUserRoles;
753+
}
754+
if (resolvedRequireAll && Array.isArray(resolvedRequireAll)) {
755+
requireAllRoles = resolvedRequireAll;
743756
}
744757
if (userRoles) {
745758
const hasRole = userRoles.some(requiredRole => roles.includes(`role:${requiredRole}`));

0 commit comments

Comments
 (0)