New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

role-acl

Package Overview
Dependencies
Maintainers
1
Versions
68
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

role-acl - npm Package Compare versions

Comparing version

to
2.0.0

38

lib/AccessControl.d.ts

@@ -124,17 +124,2 @@ import { Access, IAccessInfo, ICondition, Query, IQueryInfo, Permission } from './core';

/**
* Removes all the given resources for all roles, at once.
* Pass the `roles` argument to remove access to resources for those
* roles only.
* @chainable
*
* @param {String|Array<String>} resources - A single or array of resources to
* be removed.
* @param {String|Array<String>} [roles] - A single or array of roles to
* be removed. If omitted, permissions for all roles to all given
* resources will be removed.
*
* @returns {AccessControl} - `AccessControl` instance for chaining.
*/
removeResources(resources: string | string[], roles?: string | string[]): AccessControl;
/**
* Gets all the unique roles that have at least one access information.

@@ -150,9 +135,2 @@ *

/**
* Gets all the unique resources that are granted access for at
* least one role.
*
* @returns {Array<String>}
*/
getResources(): string[];
/**
* Checks whether any permissions are granted to the given role.

@@ -166,10 +144,2 @@ *

/**
* Checks whether any permissions are granted for the given resource.
*
* @param {String} resource - Resource to be checked.
*
* @returns {Boolean}
*/
hasResource(resource: string): boolean;
/**
* Gets an instance of `Query` object. This is used to check whether

@@ -306,10 +276,2 @@ * the defined access is allowed for the given role(s) and resource.

/**
* @private
*/
private _eachRoleResource(callback);
/**
* @private
*/
_removePermission(resources: string | string[], roles?: string | string[], action?: string): void;
/**
* Documented separately in AccessControlError

@@ -316,0 +278,0 @@ * @private

@@ -163,22 +163,2 @@ "use strict";

/**
* Removes all the given resources for all roles, at once.
* Pass the `roles` argument to remove access to resources for those
* roles only.
* @chainable
*
* @param {String|Array<String>} resources - A single or array of resources to
* be removed.
* @param {String|Array<String>} [roles] - A single or array of roles to
* be removed. If omitted, permissions for all roles to all given
* resources will be removed.
*
* @returns {AccessControl} - `AccessControl` instance for chaining.
*/
AccessControl.prototype.removeResources = function (resources, roles) {
// _removePermission has a third argument `action`. if
// omitted (like below), removes the parent resource object.
this._removePermission(resources, roles);
return this;
};
/**
* Gets all the unique roles that have at least one access information.

@@ -196,16 +176,2 @@ *

/**
* Gets all the unique resources that are granted access for at
* least one role.
*
* @returns {Array<String>}
*/
AccessControl.prototype.getResources = function () {
// using an object for unique list
var resources = {};
this._eachRoleResource(function (role, resource, permissions) {
resources[resource] = null;
});
return Object.keys(resources);
};
/**
* Checks whether any permissions are granted to the given role.

@@ -221,16 +187,2 @@ *

/**
* Checks whether any permissions are granted for the given resource.
*
* @param {String} resource - Resource to be checked.
*
* @returns {Boolean}
*/
AccessControl.prototype.hasResource = function (resource) {
if (typeof resource !== 'string' || resource === '') {
return false;
}
var resources = this.getResources();
return resources.indexOf(resource) >= 0;
};
/**
* Gets an instance of `Query` object. This is used to check whether

@@ -384,39 +336,2 @@ * the defined access is allowed for the given role(s) and resource.

};
/**
* @private
*/
AccessControl.prototype._eachRoleResource = function (callback) {
var _this = this;
var resources, resourceDefinition;
this._eachRole(function (role) {
resources = _this._grants[role];
utils_1.default.eachKey(resources, function (resource) {
resourceDefinition = role[resource];
callback(role, resource, resourceDefinition);
});
});
};
/**
* @private
*/
AccessControl.prototype._removePermission = function (resources, roles, action) {
var _this = this;
resources = utils_1.default.toStringArray(resources);
if (roles)
roles = utils_1.default.toStringArray(roles);
this._eachRoleResource(function (role, resource, permissions) {
if (resources.indexOf(resource) >= 0
// roles is optional. so remove if role is not defined.
// if defined, check if the current role is in the list.
&& (!roles || roles.indexOf(role) >= 0)) {
if (action) {
delete _this._grants[role][resource][action];
}
else {
// this is used for AccessControl#removeResources().
delete _this._grants[role][resource];
}
}
});
};
Object.defineProperty(AccessControl, "Error", {

@@ -423,0 +338,0 @@ /**

1

lib/core/Access.js

@@ -210,3 +210,2 @@ "use strict";

this._.attributes = attributes;
this._.attributes = this._.attributes ? utils_1.default.toStringArray(this._.attributes) : ['*'];
utils_1.default.commitToGrants(this._grants, this._);

@@ -213,0 +212,0 @@ // important: reset attributes for chained methods

@@ -14,3 +14,2 @@ import { IAccessInfo, IQueryInfo, ICondition } from './core';

getFlatRoles(grants: any, roles: string | string[], context?: any): string[];
normalizeAction(info: IAccessInfo | IQueryInfo): IAccessInfo | IQueryInfo;
normalizeQueryInfo(query: IQueryInfo): IQueryInfo;

@@ -17,0 +16,0 @@ normalizeAccessInfo(access: IAccessInfo): IAccessInfo;

59

lib/utils.js

@@ -5,2 +5,3 @@ "use strict";

var Notation = require("notation");
var MicroMatch = require("micromatch");
// own modules

@@ -18,3 +19,3 @@ var core_1 = require("./core");

if (Array.isArray(value))
return value;
return value.slice();
if (typeof value === 'string')

@@ -27,3 +28,3 @@ return value.trim().split(/\s*[;,]\s*/);

if (Array.isArray(value))
return value;
return value.slice();
return [value];

@@ -48,3 +49,3 @@ },

uniqConcat: function (arrA, arrB) {
var arr = arrA.concat();
var arr = arrA.slice();
arrB.forEach(function (b) {

@@ -57,3 +58,3 @@ if (arr.indexOf(b) < 0)

subtractArray: function (arrA, arrB) {
return arrA.concat().filter(function (a) { return arrB.indexOf(a) === -1; });
return arrA.slice().filter(function (a) { return arrB.indexOf(a) === -1; });
},

@@ -70,3 +71,3 @@ eachKey: function (o, callback) {

throw new core_1.AccessControlError("Invalid role(s): " + JSON.stringify(roles));
var arr = roles.concat();
var arr = roles.slice();
roles.forEach(function (roleName) {

@@ -87,6 +88,2 @@ var role = grants[roleName];

},
normalizeAction: function (info) {
// validate and normalize action
return info;
},
normalizeQueryInfo: function (query) {

@@ -165,17 +162,10 @@ // clone the object

access = utils.normalizeAccessInfo(access);
// console.log(access);
// grant.role also accepts an array, so treat it like it.
access.role.forEach(function (role) {
if (!grants.hasOwnProperty(role))
grants[role] = {};
var grantItem = grants[role];
access.resource.forEach(function (resource) {
grantItem[resource] = grantItem[resource] || {};
access.action.forEach(function (action) {
grantItem[resource][action] = grantItem[resource][action] || [];
grantItem[resource][action].push({
attributes: access.attributes,
condition: access.condition
});
});
grants[role] = grants[role] || {};
grants[role].grants = grants[role].grants || [];
grants[role].grants.push({
resource: access.resource,
action: access.action,
attributes: access.attributes,
condition: access.condition
});

@@ -201,3 +191,2 @@ });

query = utils.normalizeQueryInfo(query);
var attrsList = [];
// get roles and extended roles in a flat array

@@ -207,15 +196,13 @@ var roles = utils.getFlatRoles(grants, query.role, query.context);

// each role to attrsList (array).
roles.forEach(function (role, index) {
var grantItem = grants[role];
if (grantItem) {
var resource = grantItem[query.resource];
if (resource) {
var actionAttrs = resource[query.action];
if (actionAttrs && actionAttrs.length) {
attrsList = attrsList.concat(actionAttrs);
}
}
}
return roles.filter(function (role) {
return grants[role] && grants[role].grants;
}).map(function (role) {
return grants[role].grants;
}).reduce(function (allGrants, roleGrants) {
return allGrants.concat(roleGrants);
}, []).filter(function (grant) {
return MicroMatch.some(query.resource, grant.resource) && MicroMatch.some(query.action, grant.action);
}).map(function (grant) {
return { attributes: grant.attributes.slice(), condition: grant.condition };
});
return attrsList;
},

@@ -222,0 +209,0 @@ /**

{
"name": "role-acl",
"version": "1.0.1",
"version": "2.0.0",
"description": "Role, Attribute and Condition based Access Control for Node.js",

@@ -68,4 +68,5 @@ "main": "./index.js",

"dependencies": {
"notation": "^1.0.0"
"micromatch": "^3.1.0",
"notation": "^1.1.0"
}
}

@@ -17,2 +17,3 @@ Role, Attribute and conditions based Access Control for Node.js

- Define grants at once (e.g. from database result) or one by one.
- Grant permissions by resources and actions define by glob notation.
- Grant permissions by attributes defined by glob notation (with nested object support).

@@ -79,3 +80,42 @@ - Ability to filter data (model) instance by allowed attributes.

```
### Wildcard (glob notation) Resource and Actions Examples
```js
ac.grant({
role: 'politics/editor',
action: '*',
resource: 'article',
condition: {Fn: 'EQUALS', args: {category: 'politics'}},
attributes: ['*']
});
ac.grant({
role: 'politics/writer',
action: ['*', '!publish'],
resource: 'article',
condition: {Fn: 'EQUALS', args: {category: 'politics'}},
attributes: ['*']
});
ac.grant({
role: 'admin',
action: '*',
resource: '*',
condition: {Fn: 'EQUALS', args: {category: 'politics'}},
attributes: ['*']
});
permission = ac.can('politics/editor').execute('publish').with({category: 'politics'}).on('article');
console(permission.attributes); // -> ['*']
console(permission.granted); // -> true
permission = ac.can('admin').execute('publish').with({category: 'politics'}).on('article');
console(permission.attributes); // -> ['*']
console(permission.granted); // -> true
permission = ac.can('admin').execute('publish').with({category: 'politics'}).on('blog');
console(permission.attributes); // -> ['*']
console(permission.granted); // -> true
permission = ac.can('politics/writer').execute('publish').with({category: 'politics'}).on('article');
console(permission.granted); // -> false
```
### Express.js Example

@@ -132,15 +172,4 @@

permission = ac.can('sports/editor').execute('publish').with({category: 'politics'})).on('article');
console(permission.attributes).toEqual([]);
console(permission.granted).toEqual(false);
ac.grant({
role: 'politics/editor',
action: 'publish',
resource: 'article',
condition: {Fn: 'EQUALS', args: {category: 'politics'}},
attributes: attrs
});
permission = ac.can('politics/editor').execute('publish').with({category: 'politics'}).on('article');
console(permission.attributes).toEqual(attrs);
console(permission.granted).toEqual(true);
console(permission.attributes); // -> []
console(permission.granted); // -> false
```

@@ -194,68 +223,53 @@

admin: {
video: {
'create': ['*'],
'read': ['*'],
'update': ['*'],
'delete': ['*']
}
grants: [
{
resource: 'video', action: '*', attributes: ['*']
}
]
},
user: {
video: {
'create:own': ['*'],
'read:own': ['*'],
'update:own': ['*'],
'delete:own': ['*']
}
grants: [
{
resource: 'video', action: 'create', attributes: ['*']
},
{
resource: 'video', action: 'read', attributes: ['*']
},
{
resource: 'video', action: 'update', attributes: ['*']
},
{
resource: 'video', action: 'delete', attributes: ['*']
},
]
},
"sports/editor": {
article: {
"create:any": [
{
attributes: ["*"],
condition: {
Fn: 'EQUALS',
args: {
'category': 'sports'
}
grants: [
{
resource: 'article',
action: '*',
attributes: ["*"],
condition: {
Fn: 'EQUALS',
args: {
'category': 'sports'
}
}
],
"update:any": [
{
attributes: ["*"],
condition: {
Fn: 'EQUALS',
args: {
'category': 'sports'
}
}
}
]
}
}
]
},
"sports/writer": {
article: {
"create:any": [
{
attributes: ["*", "!status"],
condition: {
Fn: 'EQUALS',
args: {
'category': 'sports'
}
grants: [
{
resource: 'article',
action: ['create', 'update'],
attributes: ["*", "!status"],
condition: {
Fn: 'EQUALS',
args: {
'category': 'sports'
}
}
],
"update:any": [
{
attributes: ["*", "!status"],
condition: {
Fn: 'EQUALS',
args: {
'category': 'sports'
}
}
}
]
}
}
]
}

@@ -275,7 +289,8 @@ };

{ role: 'user', resource: 'video', action: 'create:own', attributes: ['*'] },
{ role: 'user', resource: 'video', action: 'create', attributes: ['*'] },
{ role: 'user', resource: 'video', action: 'read', attributes: ['*'] },
{ role: 'user', resource: 'video', action: 'update:own', attributes: ['*'] },
{ role: 'user', resource: 'video', action: 'delete:own', attributes: ['*'] },
{ role: 'user', resource: 'video', action: 'update', attributes: ['*'] },
{ role: 'user', resource: 'video', action: 'delete', attributes: ['*'] },
{ role: 'user', resource: 'photo', action: '*', attributes: ['*'] },
{ role: 'user', resource: 'article', action: ['*', '!delete'], attributes: ['*'] },
{ role: 'sports/editor', resource: 'article', action: 'create', attributes: ['*'],

@@ -282,0 +297,0 @@ condition: { "Fn": "EQUALS", "args": { "category": "sports" } }