UNPKG

@superawesome/permissions

Version:

Fine grained permissions / access control with ownerships & attribute picking, done right.

112 lines 5.08 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.deleteEmptyArrayKeys = exports.isLike = exports.isHash = exports.isArraySetEqual = exports.buildAccessControl = exports.projectPDWithDefaultsToInternal = exports.hasSomeOwnGrant = exports.stringify = void 0; const _ = require("lodash"); const accesscontrol_re_1 = require("accesscontrol-re"); const types_1 = require("./types"); const logger_1 = require("./logger"); exports.stringify = (obj) => JSON.stringify(obj, null, 2); exports.hasSomeOwnGrant = (ipd) => _.some(ipd.grant, (attrs, action) => _.endsWith(action, `:${types_1.EPossession.own}`)); exports.projectPDWithDefaultsToInternal = _.curry((defaults, pd) => { const { isOwner, listOwned, limitOwned, descr } = pd; const roles = pd.roles || defaults.roles; const resource = pd.resource || defaults.resource; // prettier-ignore if (!roles) throw new Error(`SA-Permissions: InvalidPermissionDefinitionError: missing "roles" in ${exports.stringify(pd)}.`); // prettier-ignore if (!resource) throw new Error(`SA-Permissions: InvalidPermissionDefinitionError: missing "resource" in ${exports.stringify(pd)}.`); // prettier-ignore if (_.isEmpty(pd.grant)) throw new Error(`SA-Permissions: InvalidPermissionDefinitionError: missing or empty "grant" in ${exports.stringify(pd)}`); // convert ['list', 'ofActions'] to {list: null, ofActions: null} const grantTempObj = !_.isArray(pd.grant) ? pd.grant : _.reduce(pd.grant, (acc, cur) => { acc[cur] = null; return acc; }, {}); // apply defaults const grant = _.reduce(grantTempObj, (acc, possibleAttributes, actionPerhapsWithPossession) => { const [action, possiblePossession] = actionPerhapsWithPossession.split(':'); const possession = possiblePossession || pd.possession || defaults.possession || types_1.EPossession.any; const actionWithPossession = `${action}:${possession}`; acc[actionWithPossession] = possibleAttributes || pd.attributes || defaults.attributes || ['*']; return acc; }, {}); const ipd = { roles: _.isArray(roles) ? roles : [roles], resource, descr, isOwner, listOwned, limitOwned, grant, }; return ipd; }); exports.buildAccessControl = (permissionDefinitions) => { if (_.isEmpty(permissionDefinitions)) throw new Error('SA-Permissions: cant build with empty permissionDefinitions!'); const acre = new accesscontrol_re_1.AccessControlRe(); // first pass: execute only the grant's // so all roles are defined _.each(permissionDefinitions, (pd // {grant, resource, roles} ) => _.each(pd.grant, (attributes, actionPossession) => { const [action, possession] = actionPossession.split(':'); const accessInfo = { action, possession, attributes, role: pd.roles, resource: pd.resource, }; // @todo: check it's a valid IAccessInfo - use class-validator // - has at least one Role, one Resource // - has possession, added either as the default or the grant it self logger_1.getLogger().debug(`addAccessInfo(${exports.stringify(accessInfo)})`); acre.addAccessInfo(accessInfo); })); // @todo: second pass: extend roles (already defined on 1st pass) _.each(permissionDefinitions, (pd) => { if (pd.extend) { throw new Error('extend is not supported yet, and will not until this is fixed https://github.com/onury/accesscontrol/issues/34#issuecomment-466387586 and the whole extend idea redesigned and tested properly.'); // this._accessControl.grant(pd.role).extend(pd.extend); } }); acre.build(); return [acre.accessControl, acre]; }; exports.isArraySetEqual = (ar1, ar2, comparator1, comparator2) => { if (!comparator1) comparator1 = (a, b) => a === b; if (!comparator2) comparator2 = _.flip(comparator1); return (_.isArray(ar1) && _.isArray(ar2) && ar1.length === ar2.length && _.isEmpty(_.differenceWith(ar1, ar2, comparator1)) && _.isEmpty(_.differenceWith(ar2, ar1, comparator2))); }; exports.isHash = (o) => _.isObjectLike(o) && !_.isArray(o) && !_.isFunction(o); // Returns true if the keys+values of `o1` are all _.isEqual to `o2`'s corresponding ones exports.isLike = (o1 = {}, o2 = {}) => _.isEqual(o1, o2) || (exports.isHash(o1) && exports.isHash(o2) && _.every(_.keys(o1), (o1Key) => exports.isLike(o1[o1Key], o2[o1Key]))); // Deletes all object keys with a value of `[]` (empty array) // note: mutates the object exports.deleteEmptyArrayKeys = (o) => { if (exports.isHash(o)) { _.each(o, (val, key) => { if (_.isEqual(val, [])) { delete o[key]; } else exports.deleteEmptyArrayKeys(val); }); } return o; }; //# sourceMappingURL=utils.js.map