@superawesome/permissions
Version:
Fine grained permissions / access control with ownerships & attribute picking, done right.
94 lines • 4.9 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.consolidatePermissionDefinitions = exports.mergeCompatibleGrants = exports.deleteDefinedGrants = exports.consolidatePermissions = exports.areCompatibleOwnHooks = exports.mergeTwoPermissions = void 0;
// 3rd
const _ = require("lodash");
const _f = require("lodash/fp");
const accesscontrol_1 = require("accesscontrol");
// own
const utils_1 = require("./utils");
const logger_1 = require("./logger");
exports.mergeTwoPermissions = (receivingPD, pd) => {
// @todo: throw if !canPermissionsBeMerged
const result = Object.assign(Object.assign(Object.assign({}, receivingPD), pd), { grant: Object.assign(Object.assign({}, receivingPD.grant), pd.grant) });
return result;
};
exports.areCompatibleOwnHooks = (pd1, pd2) => (pd1.isOwner === pd2.isOwner || !pd1.isOwner || !pd2.isOwner) &&
(pd1.listOwned === pd2.listOwned || !pd1.listOwned || !pd2.listOwned);
exports.consolidatePermissions = _f.reduce((consolidatedCPDs, cpd) => {
const matchingPds = _.filter(consolidatedCPDs, (consolidatedCpd) => utils_1.isArraySetEqual(consolidatedCpd.roles, cpd.roles, _.isEqual) &&
consolidatedCpd.resource === cpd.resource &&
exports.areCompatibleOwnHooks(consolidatedCpd, cpd));
if (_.isEmpty(matchingPds)) {
consolidatedCPDs.push(cpd);
}
else if (matchingPds.length === 1) {
// consolidate the two
const idx = _.indexOf(consolidatedCPDs, matchingPds[0]);
consolidatedCPDs[idx] = exports.mergeTwoPermissions(consolidatedCPDs[idx], cpd);
}
else
throw new Error('Something is wrong with _internalPermissionDefinitions - we have duplicated consolidated PDs');
return consolidatedCPDs;
});
exports.deleteDefinedGrants = _f.reduce(
// refactor, not needs to be reducer, just a visitor to delete grant props
(consolidatedCPDs, cpd) => {
const [accessControl] = _.isEmpty(consolidatedCPDs)
? [new accesscontrol_1.AccessControl()] // dummy
: utils_1.buildAccessControl(consolidatedCPDs);
// check if grant for all roles is already defined and delete it!
_.each(cpd.grant, (attributes, action) => {
const grantExists = _.every(cpd.roles, (role) => {
try {
const perm = accessControl.permission({
action,
resource: cpd.resource,
role,
});
return perm.granted && _.isEqual(perm.attributes, attributes);
}
catch (error) {
return false; // ignore errors of roles missing etc, simply means its not defined
}
});
if (grantExists)
delete cpd.grant[action];
});
// add anyway, it will be eliminated if it ends up empty
consolidatedCPDs.push(cpd);
return consolidatedCPDs;
});
exports.mergeCompatibleGrants = (pds) => {
// for every parent PD, find ones below it that have the a super set with the same exact grants
for (let parentIdx = 0; parentIdx < pds.length; parentIdx++) {
const parentPd = pds[parentIdx];
for (let childIdx = parentIdx + 1; childIdx < pds.length; childIdx++) {
const childPd = pds[childIdx];
if (parentPd.resource === childPd.resource && utils_1.isLike(parentPd.grant, childPd.grant)) {
// delete ALL child grants that exist in parent (and are seen as moved there)
// add all roles of child to parent
parentPd.roles = _.uniq([...parentPd.roles, ...childPd.roles]);
_.each(_.keys(parentPd.grant), (actionKey) => delete childPd.grant[actionKey]);
}
}
}
return pds;
};
exports.consolidatePermissionDefinitions = (filter, consolidateFlag) => _f.flow(_f.filter(filter), _f.tap((ipds) => {
if (_.some(ipds, utils_1.hasSomeOwnGrant)) {
const msg = `getDefinitions() with consolidate = true PermissionDefinitions is **experimental** and NOT compatible when Possession.own is used ('force' is needed)!
Use "getDefinitions()" with consolidate = false to avoid consolidations.`;
if (consolidateFlag === true)
throw new Error(`SA-Permissions: ${msg} Use "getDefinitions()" with consolidate = 'force' to proceed with consolidations of own, at your own risk.`);
if (consolidateFlag === 'force')
logger_1.getLogger().warn(msg);
}
}), exports.consolidatePermissions([]), exports.deleteDefinedGrants([]), exports.mergeCompatibleGrants, _f.map(_f.omitBy(
// omit keys of filter & empty ones
(val, key) => (_.isEmpty(val) && !_.isFunction(val)) ||
(_.isObjectLike(filter) &&
(_.isEqual(filter[key], val) || utils_1.isArraySetEqual(filter[key], val))))),
// eliminate PDs with empty grants
_f.reject((pd) => _.isEmpty(pd.grant)));
//# sourceMappingURL=consolidations.js.map