Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Socket
Sign inDemoInstall

@lifeomic/abac

Package Overview
Dependencies
Maintainers
2
Versions
42
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@lifeomic/abac - npm Package Compare versions

Comparing version 4.7.0 to 4.8.0

146

dist/index.js

@@ -6,3 +6,3 @@ 'use strict';

});
exports.policyRequiresAttribute = exports.privilegesSync = exports.privilegesLenient = exports.privileges = exports.extract = exports.enforceAny = exports.enforceSync = exports.enforceLenient = exports.enforce = exports.reduceSync = exports.reduce = exports.merge = exports.validate = undefined;
exports.policyRequiresAttribute = exports.privilegesSync = exports.privilegesLenient = exports.privileges = exports.extract = exports.enforceAny = exports.enforceSync = exports.enforceLenient = exports.enforce = exports.reduceSync = exports.reduce = exports.merge = exports.validate = exports.COMPARISON_REVERSION_MAP = undefined;

@@ -37,2 +37,6 @@ var _values = require('babel-runtime/core-js/object/values');

var _lodash = require('lodash.clonedeep');
var _lodash2 = _interopRequireDefault(_lodash);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

@@ -44,4 +48,47 @@

const COMPARISON_REVERSION_MAP = exports.COMPARISON_REVERSION_MAP = {
endsWith: 'suffixOf',
equals: 'equals',
in: 'includes',
includes: 'in',
notEquals: 'notEquals',
notIn: 'notIncludes',
notIncludes: 'notIn',
prefixOf: 'startsWith',
startsWith: 'prefixOf',
subset: 'superset',
suffixOf: 'endsWith',
superset: 'subset'
};
const isString = value => typeof value === 'string' || value instanceof String;
// We reverse conditions when we have a known "key" value and an unknown
// "target" value.
const maybeReverseCondition = (pathToCheck, condition, attributes) => {
const noOp = {
pathToCheck,
condition
};
if (!condition.target || condition.comparison === 'exists') {
return noOp;
}
const originalPathToCheckValue = getAttribute(attributes, pathToCheck);
const originalTargetValue = getAttribute(attributes, condition.target);
if (originalPathToCheckValue && !originalTargetValue) {
return {
pathToCheck: condition.target,
condition: {
comparison: COMPARISON_REVERSION_MAP[condition.comparison],
target: pathToCheck
}
};
}
return noOp;
};
/**

@@ -157,27 +204,25 @@ * Validate a policy.

const getCompareValue = (condition, attributes) => {
if ('target' in condition) {
return getAttribute(attributes, condition.target);
}
return condition.value;
};
/**
* @returns `true` if the comparision matches, `false` if there is a mismatch,
* and `undefined` if the target value is not known to compute the
* result
* @param condition a condition to evaluate against the given
* value.
* @param condition.comparison a comparison operation string from the available
* list of comparison operations.
* @param condition.value the value to be compared against the function's
* "value" argument using the condition's operation.
* @param value the value to be compared against the condition's value
* using the condition's comparison operator.
*
* @returns `true` if the comparision matches, `false` if there is a mismatch.
*/
const compare = (condition, value, attributes) => {
const compareValue = getCompareValue(condition, attributes);
const compare = (condition, value) => {
const compareValue = condition.value;
switch (condition.comparison) {
case 'includes':
if (compareValue === undefined) return undefined;
return Array.isArray(value) && value.includes(compareValue);
case 'in':
if (compareValue === undefined) return undefined;
return Array.isArray(compareValue) && compareValue.includes(value);
case 'equals':
if (compareValue === undefined) return undefined;
return (0, _fastDeepEqual2.default)(value, compareValue);

@@ -189,36 +234,26 @@

case 'notEquals':
if (compareValue === undefined) return undefined;
return !(0, _fastDeepEqual2.default)(value, compareValue);
case 'notIn':
if (compareValue === undefined) return undefined;
return Array.isArray(compareValue) && !compareValue.includes(value);
case 'notIncludes':
// No undefined check for compareValue here since AJV catches that
// and throws error.
return Array.isArray(value) && !value.includes(compareValue);
case 'superset':
if (compareValue === undefined) return undefined;
return Array.isArray(value) && Array.isArray(compareValue) && compareValue.every(x => value.includes(x));
case 'subset':
if (compareValue === undefined) return undefined;
return Array.isArray(value) && Array.isArray(compareValue) && value.every(x => compareValue.includes(x));
case 'startsWith':
if (compareValue === undefined) return undefined;
return isString(value) && value.startsWith(compareValue);
case 'prefixOf':
if (compareValue === undefined) return undefined;
return isString(value) && isString(compareValue) && compareValue.startsWith(value);
case 'endsWith':
if (compareValue === undefined) return undefined;
return isString(value) && value.endsWith(compareValue);
case 'suffixOf':
if (compareValue === undefined) return undefined;
return isString(value) && isString(compareValue) && compareValue.endsWith(value);

@@ -235,17 +270,31 @@

for (const [name, condition] of (0, _entries2.default)(rule)) {
const values = getAttributeValues(attributes, name.split('.'));
for (let [pathToCheck, condition] of (0, _entries2.default)((0, _lodash2.default)(rule))) {
const { pathToCheck: newPathToCheck, condition: newCondition } = maybeReverseCondition(pathToCheck, condition, attributes);
pathToCheck = newPathToCheck;
condition = newCondition;
// When we already know the value of the target, we replace it with an
// in-line value.
if (condition.target) {
const inLineTargetValue = getAttribute(attributes, condition.target);
if (inLineTargetValue) {
condition.value = inLineTargetValue;
delete condition.target;
}
}
const values = getAttributeValues(attributes, pathToCheck.split('.'));
if (values.length === 0) {
result[name] = condition;
result[pathToCheck] = condition;
} else {
for (const value of values) {
const compareResult = compare(condition, value, attributes);
if (compareResult === undefined) {
result[name] = condition;
break;
} else {
if (compareResult === false) {
return false;
}
// At this point, all target props in the condition should have been
// replaced by the actual value. "condition.value" and the resulting
// "compareResult" should never be undefined at this point.
const compareResult = compare(condition, value);
if (compareResult === false) {
return false;
}

@@ -259,2 +308,3 @@ }

}
return result;

@@ -264,2 +314,4 @@ };

const reduceRules = (rules, attributes) => {
const attributesClone = (0, _lodash2.default)(attributes);
const result = [];

@@ -271,4 +323,5 @@

for (const rule of rules) {
const reducedRule = reduceRule(rule, attributes);
for (const rule of (0, _lodash2.default)(rules)) {
const reducedRule = reduceRule(rule, attributesClone);
if (reducedRule === true) {

@@ -286,9 +339,14 @@ return true;

* Performs a synchronous reduction for whether the given policy might
* allow the operations. This function's intended use is for
* client applications that need a simple check to disable
* or annotate UI elements.
* allow the operations. This function's intended use is for client applications
* that need a simple check to disable or annotate UI elements.
*
* When a rule where the "key" is known and the "target" is unknown, a
* reversion and in-line replacement will occur so the policy can be
* evaluated immediately without consumers needing to be aware of the
* target attributes.
*
* @param {object} policy the policy to evaluate
* @param {object} attributes the attributes to use for the evaluation
* @returns {object} the policy reduced to conditions involving attributes not not given
* @returns {object} the policy reduced to conditions involving attributes not
* not given
* @throws {Error} if the policy is invalid

@@ -300,4 +358,6 @@ */

validate(policy);
(0, _entries2.default)(policy.rules).forEach(([operation, rules]) => {
rules = reduceRules(rules, attributes);
if (rules === true || Array.isArray(rules) && rules.length > 0) {

@@ -304,0 +364,0 @@ result[operation] = rules;

@@ -13,2 +13,3 @@ 'use strict';

import equals from 'fast-deep-equal';
import cloneDeep from 'lodash.clonedeep';

@@ -25,2 +26,17 @@ var ajv = new Ajv();

export var COMPARISON_REVERSION_MAP = {
endsWith: 'suffixOf',
equals: 'equals',
in: 'includes',
includes: 'in',
notEquals: 'notEquals',
notIn: 'notIncludes',
notIncludes: 'notIn',
prefixOf: 'startsWith',
startsWith: 'prefixOf',
subset: 'superset',
suffixOf: 'endsWith',
superset: 'subset'
};
var isString = function isString(value) {

@@ -30,2 +46,30 @@ return typeof value === 'string' || value instanceof String;

// We reverse conditions when we have a known "key" value and an unknown
// "target" value.
var maybeReverseCondition = function maybeReverseCondition(pathToCheck, condition, attributes) {
var noOp = {
pathToCheck: pathToCheck,
condition: condition
};
if (!condition.target || condition.comparison === 'exists') {
return noOp;
}
var originalPathToCheckValue = getAttribute(attributes, pathToCheck);
var originalTargetValue = getAttribute(attributes, condition.target);
if (originalPathToCheckValue && !originalTargetValue) {
return {
pathToCheck: condition.target,
condition: {
comparison: COMPARISON_REVERSION_MAP[condition.comparison],
target: pathToCheck
}
};
}
return noOp;
};
/**

@@ -195,27 +239,25 @@ * Validate a policy.

var getCompareValue = function getCompareValue(condition, attributes) {
if ('target' in condition) {
return getAttribute(attributes, condition.target);
}
return condition.value;
};
/**
* @returns `true` if the comparision matches, `false` if there is a mismatch,
* and `undefined` if the target value is not known to compute the
* result
* @param condition a condition to evaluate against the given
* value.
* @param condition.comparison a comparison operation string from the available
* list of comparison operations.
* @param condition.value the value to be compared against the function's
* "value" argument using the condition's operation.
* @param value the value to be compared against the condition's value
* using the condition's comparison operator.
*
* @returns `true` if the comparision matches, `false` if there is a mismatch.
*/
var compare = function compare(condition, value, attributes) {
var compareValue = getCompareValue(condition, attributes);
var compare = function compare(condition, value) {
var compareValue = condition.value;
switch (condition.comparison) {
case 'includes':
if (compareValue === undefined) return undefined;
return Array.isArray(value) && value.includes(compareValue);
case 'in':
if (compareValue === undefined) return undefined;
return Array.isArray(compareValue) && compareValue.includes(value);
case 'equals':
if (compareValue === undefined) return undefined;
return equals(value, compareValue);

@@ -227,16 +269,11 @@

case 'notEquals':
if (compareValue === undefined) return undefined;
return !equals(value, compareValue);
case 'notIn':
if (compareValue === undefined) return undefined;
return Array.isArray(compareValue) && !compareValue.includes(value);
case 'notIncludes':
// No undefined check for compareValue here since AJV catches that
// and throws error.
return Array.isArray(value) && !value.includes(compareValue);
case 'superset':
if (compareValue === undefined) return undefined;
return Array.isArray(value) && Array.isArray(compareValue) && compareValue.every(function (x) {

@@ -247,3 +284,2 @@ return value.includes(x);

case 'subset':
if (compareValue === undefined) return undefined;
return Array.isArray(value) && Array.isArray(compareValue) && value.every(function (x) {

@@ -254,15 +290,11 @@ return compareValue.includes(x);

case 'startsWith':
if (compareValue === undefined) return undefined;
return isString(value) && value.startsWith(compareValue);
case 'prefixOf':
if (compareValue === undefined) return undefined;
return isString(value) && isString(compareValue) && compareValue.startsWith(value);
case 'endsWith':
if (compareValue === undefined) return undefined;
return isString(value) && value.endsWith(compareValue);
case 'suffixOf':
if (compareValue === undefined) return undefined;
return isString(value) && isString(compareValue) && compareValue.endsWith(value);

@@ -284,3 +316,3 @@

try {
for (var _iterator3 = _getIterator(_Object$entries(rule)), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) {
for (var _iterator3 = _getIterator(_Object$entries(cloneDeep(rule))), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) {
var _ref7 = _step3.value;

@@ -290,9 +322,27 @@

var name = _ref8[0];
var pathToCheck = _ref8[0];
var condition = _ref8[1];
var values = getAttributeValues(attributes, name.split('.'));
var _maybeReverseConditio = maybeReverseCondition(pathToCheck, condition, attributes),
newPathToCheck = _maybeReverseConditio.pathToCheck,
newCondition = _maybeReverseConditio.condition;
pathToCheck = newPathToCheck;
condition = newCondition;
// When we already know the value of the target, we replace it with an
// in-line value.
if (condition.target) {
var inLineTargetValue = getAttribute(attributes, condition.target);
if (inLineTargetValue) {
condition.value = inLineTargetValue;
delete condition.target;
}
}
var values = getAttributeValues(attributes, pathToCheck.split('.'));
if (values.length === 0) {
result[name] = condition;
result[pathToCheck] = condition;
} else {

@@ -307,10 +357,9 @@ var _iteratorNormalCompletion4 = true;

var compareResult = compare(condition, value, attributes);
if (compareResult === undefined) {
result[name] = condition;
break;
} else {
if (compareResult === false) {
return false;
}
// At this point, all target props in the condition should have been
// replaced by the actual value. "condition.value" and the resulting
// "compareResult" should never be undefined at this point.
var compareResult = compare(condition, value);
if (compareResult === false) {
return false;
}

@@ -352,2 +401,3 @@ }

}
return result;

@@ -357,2 +407,4 @@ };

var reduceRules = function reduceRules(rules, attributes) {
var attributesClone = cloneDeep(attributes);
var result = [];

@@ -369,6 +421,7 @@

try {
for (var _iterator5 = _getIterator(rules), _step5; !(_iteratorNormalCompletion5 = (_step5 = _iterator5.next()).done); _iteratorNormalCompletion5 = true) {
for (var _iterator5 = _getIterator(cloneDeep(rules)), _step5; !(_iteratorNormalCompletion5 = (_step5 = _iterator5.next()).done); _iteratorNormalCompletion5 = true) {
var rule = _step5.value;
var reducedRule = reduceRule(rule, attributes);
var reducedRule = reduceRule(rule, attributesClone);
if (reducedRule === true) {

@@ -400,9 +453,14 @@ return true;

* Performs a synchronous reduction for whether the given policy might
* allow the operations. This function's intended use is for
* client applications that need a simple check to disable
* or annotate UI elements.
* allow the operations. This function's intended use is for client applications
* that need a simple check to disable or annotate UI elements.
*
* When a rule where the "key" is known and the "target" is unknown, a
* reversion and in-line replacement will occur so the policy can be
* evaluated immediately without consumers needing to be aware of the
* target attributes.
*
* @param {object} policy the policy to evaluate
* @param {object} attributes the attributes to use for the evaluation
* @returns {object} the policy reduced to conditions involving attributes not not given
* @returns {object} the policy reduced to conditions involving attributes not
* not given
* @throws {Error} if the policy is invalid

@@ -414,2 +472,3 @@ */

validate(policy);
_Object$entries(policy.rules).forEach(function (_ref9) {

@@ -421,2 +480,3 @@ var _ref10 = _slicedToArray(_ref9, 2),

rules = reduceRules(rules, attributes);
if (rules === true || Array.isArray(rules) && rules.length > 0) {

@@ -423,0 +483,0 @@ result[operation] = rules;

@@ -10,2 +10,3 @@ 'use strict';

import equals from 'fast-deep-equal';
import cloneDeep from 'lodash.clonedeep';

@@ -16,4 +17,47 @@ const ajv = new Ajv();

export const COMPARISON_REVERSION_MAP = {
endsWith: 'suffixOf',
equals: 'equals',
in: 'includes',
includes: 'in',
notEquals: 'notEquals',
notIn: 'notIncludes',
notIncludes: 'notIn',
prefixOf: 'startsWith',
startsWith: 'prefixOf',
subset: 'superset',
suffixOf: 'endsWith',
superset: 'subset'
};
const isString = value => typeof value === 'string' || value instanceof String;
// We reverse conditions when we have a known "key" value and an unknown
// "target" value.
const maybeReverseCondition = (pathToCheck, condition, attributes) => {
const noOp = {
pathToCheck,
condition
};
if (!condition.target || condition.comparison === 'exists') {
return noOp;
}
const originalPathToCheckValue = getAttribute(attributes, pathToCheck);
const originalTargetValue = getAttribute(attributes, condition.target);
if (originalPathToCheckValue && !originalTargetValue) {
return {
pathToCheck: condition.target,
condition: {
comparison: COMPARISON_REVERSION_MAP[condition.comparison],
target: pathToCheck
}
};
}
return noOp;
};
/**

@@ -129,27 +173,25 @@ * Validate a policy.

const getCompareValue = (condition, attributes) => {
if ('target' in condition) {
return getAttribute(attributes, condition.target);
}
return condition.value;
};
/**
* @returns `true` if the comparision matches, `false` if there is a mismatch,
* and `undefined` if the target value is not known to compute the
* result
* @param condition a condition to evaluate against the given
* value.
* @param condition.comparison a comparison operation string from the available
* list of comparison operations.
* @param condition.value the value to be compared against the function's
* "value" argument using the condition's operation.
* @param value the value to be compared against the condition's value
* using the condition's comparison operator.
*
* @returns `true` if the comparision matches, `false` if there is a mismatch.
*/
const compare = (condition, value, attributes) => {
const compareValue = getCompareValue(condition, attributes);
const compare = (condition, value) => {
const compareValue = condition.value;
switch (condition.comparison) {
case 'includes':
if (compareValue === undefined) return undefined;
return Array.isArray(value) && value.includes(compareValue);
case 'in':
if (compareValue === undefined) return undefined;
return Array.isArray(compareValue) && compareValue.includes(value);
case 'equals':
if (compareValue === undefined) return undefined;
return equals(value, compareValue);

@@ -161,36 +203,26 @@

case 'notEquals':
if (compareValue === undefined) return undefined;
return !equals(value, compareValue);
case 'notIn':
if (compareValue === undefined) return undefined;
return Array.isArray(compareValue) && !compareValue.includes(value);
case 'notIncludes':
// No undefined check for compareValue here since AJV catches that
// and throws error.
return Array.isArray(value) && !value.includes(compareValue);
case 'superset':
if (compareValue === undefined) return undefined;
return Array.isArray(value) && Array.isArray(compareValue) && compareValue.every(x => value.includes(x));
case 'subset':
if (compareValue === undefined) return undefined;
return Array.isArray(value) && Array.isArray(compareValue) && value.every(x => compareValue.includes(x));
case 'startsWith':
if (compareValue === undefined) return undefined;
return isString(value) && value.startsWith(compareValue);
case 'prefixOf':
if (compareValue === undefined) return undefined;
return isString(value) && isString(compareValue) && compareValue.startsWith(value);
case 'endsWith':
if (compareValue === undefined) return undefined;
return isString(value) && value.endsWith(compareValue);
case 'suffixOf':
if (compareValue === undefined) return undefined;
return isString(value) && isString(compareValue) && compareValue.endsWith(value);

@@ -207,17 +239,31 @@

for (const [name, condition] of _Object$entries(rule)) {
const values = getAttributeValues(attributes, name.split('.'));
for (let [pathToCheck, condition] of _Object$entries(cloneDeep(rule))) {
const { pathToCheck: newPathToCheck, condition: newCondition } = maybeReverseCondition(pathToCheck, condition, attributes);
pathToCheck = newPathToCheck;
condition = newCondition;
// When we already know the value of the target, we replace it with an
// in-line value.
if (condition.target) {
const inLineTargetValue = getAttribute(attributes, condition.target);
if (inLineTargetValue) {
condition.value = inLineTargetValue;
delete condition.target;
}
}
const values = getAttributeValues(attributes, pathToCheck.split('.'));
if (values.length === 0) {
result[name] = condition;
result[pathToCheck] = condition;
} else {
for (const value of values) {
const compareResult = compare(condition, value, attributes);
if (compareResult === undefined) {
result[name] = condition;
break;
} else {
if (compareResult === false) {
return false;
}
// At this point, all target props in the condition should have been
// replaced by the actual value. "condition.value" and the resulting
// "compareResult" should never be undefined at this point.
const compareResult = compare(condition, value);
if (compareResult === false) {
return false;
}

@@ -231,2 +277,3 @@ }

}
return result;

@@ -236,2 +283,4 @@ };

const reduceRules = (rules, attributes) => {
const attributesClone = cloneDeep(attributes);
const result = [];

@@ -243,4 +292,5 @@

for (const rule of rules) {
const reducedRule = reduceRule(rule, attributes);
for (const rule of cloneDeep(rules)) {
const reducedRule = reduceRule(rule, attributesClone);
if (reducedRule === true) {

@@ -258,9 +308,14 @@ return true;

* Performs a synchronous reduction for whether the given policy might
* allow the operations. This function's intended use is for
* client applications that need a simple check to disable
* or annotate UI elements.
* allow the operations. This function's intended use is for client applications
* that need a simple check to disable or annotate UI elements.
*
* When a rule where the "key" is known and the "target" is unknown, a
* reversion and in-line replacement will occur so the policy can be
* evaluated immediately without consumers needing to be aware of the
* target attributes.
*
* @param {object} policy the policy to evaluate
* @param {object} attributes the attributes to use for the evaluation
* @returns {object} the policy reduced to conditions involving attributes not not given
* @returns {object} the policy reduced to conditions involving attributes not
* not given
* @throws {Error} if the policy is invalid

@@ -272,4 +327,6 @@ */

validate(policy);
_Object$entries(policy.rules).forEach(([operation, rules]) => {
rules = reduceRules(rules, attributes);
if (rules === true || Array.isArray(rules) && rules.length > 0) {

@@ -276,0 +333,0 @@ result[operation] = rules;

{
"name": "@lifeomic/abac",
"version": "4.7.0",
"version": "4.8.0",
"description": "Lifeomic Attribute Based Access Control Support Module",

@@ -30,2 +30,3 @@ "main": "./dist/index.js",

"fast-deep-equal": "^3.1.3",
"lodash.clonedeep": "^4.5.0",
"util-deprecate": "^1.0.2"

@@ -32,0 +33,0 @@ },

@@ -18,11 +18,14 @@ # abac

- Comparison
- equals: Value being checked is exactly equal to the value defined in the ABAC policy
- notEquals: Value being checked does not equal the value defined in the ABAC policy
- in: value being checked is contained within the array in ABAC policy
- notIn: value not in ABAC array
- includes: array of values includes the value in the ABAC policy
- superset: array of values is a superset of the array in the ABAC policy
- subset: array of values is a subset of the array in the ABAC policy
- startsWith: Value being checked that starts with an exact string value
- endsWith: Value being checked that ends with an exact string value
- `endsWith`: value being checked that ends with an exact string value
- `equals`: value being checked is exactly equal to the value defined in the ABAC policy
- `in`: value being checked is contained within the array in ABAC policy
- `includes`: array of values includes the value in the ABAC policy
- `notEquals`: value being checked does not equal the value defined in the ABAC policy
- `notIn`: value not in ABAC array
- `notIncludes`: array of values does not include the value in the ABAC policy
- `prefixOf`: value being checked is a prefix of the value defined in the ABAC policy
- `startsWith`: value being checked starts with an exact string value
- `subset`: array of values is a subset of the array in the ABAC policy
- `suffixOf`: value being checked is a suffix of the value defined in the ABAC policy
- `superset`: array of values is a superset of the array in the ABAC policy
- Target

@@ -29,0 +32,0 @@ - Value of another attribute

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc