diff --git a/lib/check_permissions.js b/lib/check_permissions.js index 39fc1fa..19bdcc1 100644 --- a/lib/check_permissions.js +++ b/lib/check_permissions.js @@ -7,8 +7,8 @@ var _ = require('lodash'); * role: 'basic-user' * userType: 'parent-guardian' * customValidator: [{ - * role: 'cd-x', - * cmd: 'fn' + * role: 'cd-x', + * cmd: 'fn' * }] *} * @@ -22,7 +22,8 @@ function checkPermissions (args, cb) { var permissions = require('../config/permissions.js')(); var user = {}; var cmd = args.act; - seneca.log.debug('tested:', args.role, cmd ); + var ctrl = args.params.ctrl; + seneca.log.debug('tested:', args.role, cmd); var origin = args.role; var rules = seneca.export('cd-permissions/config')[origin]; var httpErr = {}; @@ -32,7 +33,10 @@ function checkPermissions (args, cb) { function getProfilesByActName (waterfallCb) { var profiles = {}; + // TODO : refactor to avoid having to add subpatterns conditionnally + // https://github.com/CoderDojo/cp-permissions-plugin/issues/8 if (rules[cmd]) profiles = rules[cmd]; + if (rules[ctrl] && rules[ctrl][cmd]) profiles = rules[ctrl][cmd]; waterfallCb(null, profiles); } @@ -43,11 +47,10 @@ function checkPermissions (args, cb) { seneca.log.debug('No rule defined for this call'); cb(null, {'allowed': true}); } else { - async.someSeries(profiles, checkValidity, function(err, valid){ + async.someSeries(profiles, checkValidity, function (err, valid) { seneca.log.debug('validity', valid === true || httpErr, httpErr); cb(null, {'allowed': valid === true || httpErr}); }); - } } @@ -65,7 +68,7 @@ function checkPermissions (args, cb) { if (profile.userType) actions.push(isUserTypeAllowed); if (profile.customValidator) actions.push(applyCustomValidator); - user = args.user ? args.user : {roles: ['none']} ; + user = args.user ? args.user : {roles: ['none']}; async.waterfall(actions, function (err, validities) { // We can't return err as httpErr because if one of the profiles fails, it stops the other possible profiles tests return validityCb(null, allowed); @@ -85,12 +88,12 @@ function checkPermissions (args, cb) { if (profileDepth >= userRoleDepth.value && userRoleDepth.value < maxUserRoleDepth) { allowed = allowed && true; httpErr = null; - }else { + } else { allowed = false; } // Out of jail scenario for highest role // We bypass further check to avoid over defining scenarios - if( userRoleDepth.value === 0 ){ + if (userRoleDepth.value === 0) { return validityCb(null, true); } return done(httpErr); @@ -106,12 +109,12 @@ function checkPermissions (args, cb) { if (!_.isEmpty(userTypes)) { if (!_.isError(_.attempt(JSON.parse, userTypes))) { // var initType = JSON.parse(userTypes); - if (initType.name){ + if (initType.name) { userTypes = [initType.name]; } } else if (_.isObject(userTypes) && !_.isArray(userTypes)) { userTypes = _.keys(userTypes); - } else if (_.isString(userTypes)){ + } else if (_.isString(userTypes)) { userTypes = [userTypes]; } var userTypeDepth = getHighestTreeMatch(permissions.userTypeHierarchy, _.toArray(userTypes), maxUserTypeDepth); @@ -129,17 +132,17 @@ function checkPermissions (args, cb) { function getAssociatedUserTypes (done) { seneca.act({role: 'cd-dojos', cmd: 'load_usersdojos', query: { userId: user.id }}, - function(err, associations){ + function (err, associations) { var userTypes = []; userTypes.push(JSON.parse(user.initUserType).name); - _.map(associations, function(association) { - _.map(association.userTypes, function(userType) { + _.map(associations, function (association) { + _.map(association.userTypes, function (userType) { userTypes.push(userType); }); }); extendedUserTypes = _.uniq(userTypes); return done(err); - }); + }); } /** @@ -153,24 +156,22 @@ function checkPermissions (args, cb) { status: 401 }; var omittedFields = [ 'cmd', 'role', 'ungate$', 'transport$', 'tx$', 'default$', 'meta$', 'plugin$', 'fatal$' ]; - //We omit perm on purpose - async.every(customValidator, function(validatorAct, validatorCb) { + // We omit perm on purpose + async.every(customValidator, function (validatorAct, validatorCb) { var msg = _.assign(_.omit(_.clone(args), omittedFields), validatorAct); - seneca.act(msg, function(err, response){ + seneca.act(msg, function (err, response) { return validatorCb(null, response.allowed); }); - }, function(err, valid){ + }, function (err, valid) { if (valid) { allowed = valid && true; httpErr = null; - }else { + } else { allowed = false; } return done(httpErr); }); - } - } /** @@ -180,28 +181,26 @@ function checkPermissions (args, cb) { * @param {String} value one of those tree values * @return {Integer} the depth */ - function getTreeDepth(tree, value, maxDepth){ + function getTreeDepth (tree, value, maxDepth) { var found = false; var depth = -1; var localTree = _.clone(tree); - while (!found && depth < maxDepth){ + while (!found && depth < maxDepth) { var picked = localTree[value]; depth += 1; - if(!_.isUndefined(picked)){ + if (!_.isUndefined(picked)) { found = true; } // Flatten our object (lodash doesn't support flattening of object, only arrays) var tempTree = {}; _.each(_.keys(localTree), function (key) { - _.merge(tempTree, localTree[key]); + _.merge(tempTree, localTree[key]); }); - localTree = tempTree ; - + localTree = tempTree; } return depth; } - /** * Search for the highest possible value in a tree when multiple options are possible * (ex multiple userTypes) @@ -209,22 +208,21 @@ function checkPermissions (args, cb) { * @param {Array} values haystack for the highest one * @return {String} one of the userType/Role without the actual index */ - function getHighestTreeMatch(tree, values, maxDepth){ + function getHighestTreeMatch (tree, values, maxDepth) { var lowerDepth = values[0]; var indexes = {}; - lowerDepth = _.minBy(values, function(value){ + lowerDepth = _.minBy(values, function (value) { indexes[value] = getTreeDepth(tree, value, maxDepth); return indexes[value]; }); return {name: lowerDepth, - value: indexes[lowerDepth]}; + value: indexes[lowerDepth]}; } async.waterfall([ getProfilesByActName, checkProfiles ]); - } module.exports = checkPermissions;