Skip to content

Commit

Permalink
build 2.2.0
Browse files Browse the repository at this point in the history
  • Loading branch information
onury committed Nov 26, 2017
1 parent d1e8900 commit 4606c8f
Show file tree
Hide file tree
Showing 6 changed files with 93 additions and 80 deletions.
2 changes: 1 addition & 1 deletion lib/AccessControl.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ declare class AccessControl {
/**
* @private
*/
private _locked;
private _isLocked;
/**
* Initializes a new instance of `AccessControl` with the given grants.
* @ignore
Expand Down
25 changes: 20 additions & 5 deletions lib/AccessControl.js
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ var AccessControl = /** @class */ (function () {
/**
* @private
*/
this._locked = false;
this._isLocked = false;
// explicit undefined is not allowed
if (arguments.length === 0)
grants = {};
Expand All @@ -128,7 +128,7 @@ var AccessControl = /** @class */ (function () {
* @type {Boolean}
*/
get: function () {
return this._locked && Object.isFrozen(this._grants);
return this._isLocked && Object.isFrozen(this._grants);
},
enumerable: true,
configurable: true
Expand Down Expand Up @@ -288,8 +288,14 @@ var AccessControl = /** @class */ (function () {
if (this.isLocked)
throw new core_1.AccessControlError(utils_1.ERR_LOCK);
var rolesToRemove = utils_1.utils.toStringArray(roles);
rolesToRemove.forEach(function (role) {
delete _this._grants[role];
if (rolesToRemove.length === 0 || !utils_1.utils.isFilledStringArray(rolesToRemove)) {
throw new core_1.AccessControlError("Invalid role(s): " + JSON.stringify(roles));
}
rolesToRemove.forEach(function (roleName) {
if (!_this._grants[roleName]) {
throw new core_1.AccessControlError("Cannot remove a non-existing role: \"" + roleName + "\"");
}
delete _this._grants[roleName];
});
// also remove these roles from $extend list of each remaining role.
utils_1.utils.eachRole(this._grants, function (roleItem, roleName) {
Expand Down Expand Up @@ -626,8 +632,17 @@ var AccessControl = /** @class */ (function () {
AccessControl.prototype._removePermission = function (resources, roles, actionPossession) {
var _this = this;
resources = utils_1.utils.toStringArray(resources);
if (roles)
// resources is set but returns empty array.
if (resources.length === 0 || !utils_1.utils.isFilledStringArray(resources)) {
throw new core_1.AccessControlError("Invalid resource(s): " + JSON.stringify(resources));
}
if (roles !== undefined) {
roles = utils_1.utils.toStringArray(roles);
// roles is set but returns empty array.
if (roles.length === 0 || !utils_1.utils.isFilledStringArray(roles)) {
throw new core_1.AccessControlError("Invalid role(s): " + JSON.stringify(roles));
}
}
utils_1.utils.eachRoleResource(this._grants, function (role, resource, permissions) {
if (resources.indexOf(resource) >= 0
// roles is optional. so remove if role is not defined.
Expand Down
4 changes: 1 addition & 3 deletions lib/core/Access.js
Original file line number Diff line number Diff line change
Expand Up @@ -448,14 +448,12 @@ var Access = /** @class */ (function () {
this._.possession = possession;
if (resource)
this._.resource = resource;
if (attributes)
this._.attributes = attributes;
if (this._.denied) {
this._.attributes = [];
}
else {
// if omitted and not denied, all attributes are allowed
this._.attributes = this._.attributes ? utils_1.utils.toStringArray(this._.attributes) : ['*'];
this._.attributes = attributes ? utils_1.utils.toStringArray(attributes) : ['*'];
}
utils_1.utils.commitToGrants(this._grants, this._, false);
// important: reset attributes for chained methods
Expand Down
3 changes: 2 additions & 1 deletion lib/core/AccessControlError.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,10 @@ var AccessControlError = /** @class */ (function (_super) {
__extends(AccessControlError, _super);
function AccessControlError(message) {
if (message === void 0) { message = ''; }
var _this = _super.call(this, message) || this;
var _this = _super.call(this, message) /* istanbul ignore next */ || this;
_this.message = message;
_this.name = 'AccessControlError';
// https://github.com/gotwarlost/istanbul/issues/690
// http://stackoverflow.com/a/41429145/112731
Object.setPrototypeOf(_this, AccessControlError.prototype);
return _this;
Expand Down
2 changes: 1 addition & 1 deletion lib/utils.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ declare const utils: {
getRoleHierarchyOf(grants: any, roleName: string, rootRole?: string): string[];
getFlatRoles(grants: any, roles: string | string[]): string[];
getNonExistentRoles(grants: any, roles: string[]): string[];
getCrossInheritedRole(grants: any, roleName: string, extenderRoles: string | string[]): string | boolean;
getCrossExtendingRole(grants: any, roleName: string, extenderRoles: string | string[]): string;
extendRole(grants: any, roles: string | string[], extenderRoles: string | string[]): void;
preCreateRoles(grants: any, roles: string | string[]): void;
commitToGrants(grants: any, access: IAccessInfo, normalizeAll?: boolean): void;
Expand Down
137 changes: 68 additions & 69 deletions lib/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,19 +50,20 @@ var utils = {
return o.hasOwnProperty(propName) && o[propName] !== undefined;
},
/**
* Converts the given (string) value into an array of string.
* Note that this does not throw if the value is not a string or array.
* It will silently return `null`.
* Converts the given (string) value into an array of string. Note that
* this does not throw if the value is not a string or array. It will
* silently return `[]` (empty array). So where ever it's used, the host
* function should consider throwing.
* @param {Any} value
* @returns {Boolean|null}
* @returns {string[]}
*/
toStringArray: function (value) {
if (Array.isArray(value))
return value;
if (typeof value === 'string')
return value.trim().split(/\s*[;,]\s*/);
// throw new Error('Cannot convert value to array!');
return null;
// throw new Error('Expected a string or array of strings, got ' + utils.type(value));
return [];
},
/**
* Checks whether the given array consists of non-empty string items.
Expand Down Expand Up @@ -298,14 +299,11 @@ var utils = {
* is invalid.
*/
validRoleObject: function (grants, roleName) {
console.log('enter!');
var role = grants[roleName];
if (!role || utils.type(role) !== 'object') {
console.log('Invalid role:', roleName);
throw new core_1.AccessControlError("Invalid role definition.");
}
utils.eachKey(role, function (resourceName) {
console.log(resourceName, utils.validName(resourceName, false));
if (!utils.validName(resourceName, false)) {
if (resourceName === '$extend') {
var extRoles = role[resourceName]; // semantics
Expand All @@ -322,8 +320,8 @@ var utils = {
throw new core_1.AccessControlError("Cannot use reserved name \"" + resourceName + "\" for a resource.");
}
}
else if (!utils.validResourceObject(role[resourceName])) {
// throw new AccessControlError(`Invalid resource definition ("${resourceName}") for role "${roleName}".`);
else {
utils.validResourceObject(role[resourceName]); // throws on failure
}
});
return true;
Expand All @@ -347,9 +345,12 @@ var utils = {
if (type === 'object') {
utils.eachKey(o, function (roleName) {
if (utils.validName(roleName)) {
return utils.validRoleObject(o, roleName); // will throw on failure
return utils.validRoleObject(o, roleName); // throws on failure
}
/* istanbul ignore next */
return false;
// above is redundant, previous checks will already throw on
// failure so we'll never need to break early from this.
});
grants = o;
}
Expand Down Expand Up @@ -393,7 +394,8 @@ var utils = {
if (asString === void 0) { asString = false; }
// validate and normalize action
if (typeof info.action !== 'string') {
throw new core_1.AccessControlError("Invalid action: " + info.action);
// throw new AccessControlError(`Invalid action: ${info.action}`);
throw new core_1.AccessControlError("Invalid action: " + JSON.stringify(info));
}
var s = info.action.split(':');
if (enums_1.actions.indexOf(s[0].trim().toLowerCase()) < 0) {
Expand Down Expand Up @@ -466,12 +468,12 @@ var utils = {
access = Object.assign({}, access);
// validate and normalize role(s)
access.role = utils.toStringArray(access.role);
if (!utils.isFilledStringArray(access.role)) {
if (access.role.length === 0 || !utils.isFilledStringArray(access.role)) {
throw new core_1.AccessControlError("Invalid role(s): " + JSON.stringify(access.role));
}
// validate and normalize resource
access.resource = utils.toStringArray(access.resource);
if (!utils.isFilledStringArray(access.resource)) {
if (access.resource.length === 0 || !utils.isFilledStringArray(access.resource)) {
throw new core_1.AccessControlError("Invalid resource(s): " + JSON.stringify(access.resource));
}
// normalize attributes
Expand Down Expand Up @@ -515,7 +517,7 @@ var utils = {
getRoleHierarchyOf: function (grants, roleName, rootRole) {
// `rootRole` is for memory storage. Do NOT set it when using;
// and do NOT document this paramter.
rootRole = rootRole || roleName;
// rootRole = rootRole || roleName;
var role = grants[roleName];
if (!role)
throw new core_1.AccessControlError("Role not found: \"" + roleName + "\"");
Expand All @@ -531,10 +533,10 @@ var utils = {
}
// throw if cross-inheritance and also avoid memory leak with
// maximum call stack error
if (rootRole === exRoleName) {
if (rootRole && (rootRole === exRoleName)) {
throw new core_1.AccessControlError("Cross inheritance is not allowed. Role \"" + exRoleName + "\" already extends \"" + rootRole + "\".");
}
var ext = utils.getRoleHierarchyOf(grants, exRoleName, rootRole);
var ext = utils.getRoleHierarchyOf(grants, exRoleName, rootRole || roleName);
arr = utils.uniqConcat(arr, ext);
});
return arr;
Expand All @@ -543,11 +545,12 @@ var utils = {
* Gets roles and extended roles in a flat array.
*/
getFlatRoles: function (grants, roles) {
roles = utils.toStringArray(roles);
if (!roles)
var arrRoles = utils.toStringArray(roles);
if (arrRoles.length === 0) {
throw new core_1.AccessControlError("Invalid role(s): " + JSON.stringify(roles));
var arr = utils.uniqConcat([], roles); // roles.concat();
roles.forEach(function (roleName) {
}
var arr = utils.uniqConcat([], arrRoles); // roles.concat();
arrRoles.forEach(function (roleName) {
arr = utils.uniqConcat(arr, utils.getRoleHierarchyOf(grants, roleName));
});
// console.log(`flat roles for ${roles}`, arr);
Expand Down Expand Up @@ -581,13 +584,14 @@ var utils = {
*
* @param {Any} grants - Grants model to be checked.
* @param {string} roles - Target role to be checked.
* @param {string|string[]} extenderRoles - Extender role(s) to be
* checked.
* @returns {Boolean}
* @param {string|string[]} extenderRoles - Extender role(s) to be checked.
*
* @returns {string|null} - Returns the first cross extending role. `null`
* if none.
*/
getCrossInheritedRole: function (grants, roleName, extenderRoles) {
var extenders = utils.toStringArray(extenderRoles); // [roleName].concat();
var crossInherited = false;
getCrossExtendingRole: function (grants, roleName, extenderRoles) {
var extenders = utils.toStringArray(extenderRoles);
var crossInherited = null;
utils.each(extenders, function (e) {
if (crossInherited || roleName === e) {
return false; // break out of loop
Expand Down Expand Up @@ -623,43 +627,41 @@ var utils = {
* a cross-inherited role.
*/
extendRole: function (grants, roles, extenderRoles) {
// roles cannot be omitted or an empty array
roles = utils.toStringArray(roles);
if (roles.length === 0) {
throw new core_1.AccessControlError("Invalid role(s): " + JSON.stringify(roles));
}
// extenderRoles cannot be omitted or but can be an empty array
if (utils.isEmptyArray(extenderRoles))
return;
var arrExtRoles = utils.toStringArray(extenderRoles).concat();
if (!arrExtRoles)
if (arrExtRoles.length === 0) {
throw new core_1.AccessControlError("Cannot inherit invalid role(s): " + JSON.stringify(extenderRoles));
}
var nonExistentExtRoles = utils.getNonExistentRoles(grants, arrExtRoles);
if (nonExistentExtRoles.length > 0) {
throw new core_1.AccessControlError("Cannot inherit non-existent role(s): \"" + nonExistentExtRoles.join(', ') + "\"");
}
roles = utils.toStringArray(roles);
if (!roles)
throw new core_1.AccessControlError("Invalid role(s): " + JSON.stringify(roles));
roles.forEach(function (roleName) {
if (!grants[roleName])
throw new core_1.AccessControlError("Role not found: \"" + roleName + "\"");
if (arrExtRoles.indexOf(roleName) >= 0) {
throw new core_1.AccessControlError("Cannot extend role \"" + roleName + "\" by itself.");
}
// getCrossInheritedRole() returns false or the first
// getCrossExtendingRole() returns false or the first
// cross-inherited role, if found.
var crossInherited = utils.getCrossInheritedRole(grants, roleName, arrExtRoles);
var crossInherited = utils.getCrossExtendingRole(grants, roleName, arrExtRoles);
if (crossInherited) {
throw new core_1.AccessControlError("Cross inheritance is not allowed. Role \"" + crossInherited + "\" already extends \"" + roleName + "\".");
}
if (utils.validName(roleName)) {
if (!grants.hasOwnProperty(roleName)) {
grants[roleName] = {
$extend: arrExtRoles
};
}
else {
var r = grants[roleName];
if (Array.isArray(r.$extend)) {
r.$extend = utils.uniqConcat(r.$extend, arrExtRoles);
}
else {
r.$extend = arrExtRoles;
}
}
utils.validName(roleName); // throws if false
var r = grants[roleName];
if (Array.isArray(r.$extend)) {
r.$extend = utils.uniqConcat(r.$extend, arrExtRoles);
}
else {
r.$extend = arrExtRoles;
}
});
},
Expand Down Expand Up @@ -728,31 +730,27 @@ var utils = {
* @returns {string[]} - Array of union'ed attributes.
*/
getUnionAttrsOfRoles: function (grants, query) {
if (!grants) {
throw new core_1.AccessControlError('Grants are not set.');
}
// throws if has any invalid property value
query = utils.normalizeQueryInfo(query);
var grantItem;
var role;
var resource;
var attrsList = [];
// get roles and extended roles in a flat array
var roles = utils.getFlatRoles(grants, query.role);
// iterate through roles and add permission attributes (array) of
// each role to attrsList (array).
roles.forEach(function (role, index) {
grantItem = grants[role];
if (grantItem) {
resource = grantItem[query.resource];
if (resource) {
// e.g. resource['create:own']
// If action has possession "any", it will also return
// `granted=true` for "own", if "own" is not defined.
attrsList.push((resource[query.action + ':' + query.possession]
|| resource[query.action + ':any']
|| []).concat());
// console.log(resource, 'for:', action + '.' + possession);
}
roles.forEach(function (roleName, index) {
role = grants[roleName];
// no need to check role existence #getFlatRoles() does that.
resource = role[query.resource];
if (resource) {
// e.g. resource['create:own']
// If action has possession "any", it will also return
// `granted=true` for "own", if "own" is not defined.
attrsList.push((resource[query.action + ':' + query.possession]
|| resource[query.action + ':any']
|| []).concat());
// console.log(resource, 'for:', action + '.' + possession);
}
});
// union all arrays of (permitted resource) attributes (for each role)
Expand All @@ -776,16 +774,17 @@ var utils = {
*/
lockAC: function (ac) {
var _ac = ac; // ts
if (!_ac._grants) {
throw new core_1.AccessControlError('Cannot lock due to invalid grants model.');
if (!_ac._grants || Object.keys(_ac._grants).length === 0) {
throw new core_1.AccessControlError('Cannot lock empty or invalid grants model.');
}
var locked = ac.isLocked && Object.isFrozen(_ac._grants);
if (!locked)
locked = Boolean(utils.deepFreeze(_ac._grants));
/* istanbul ignore next */
if (!locked) {
throw new core_1.AccessControlError("Could not lock grants: " + typeof _ac._grants);
}
_ac._locked = locked;
_ac._isLocked = locked;
},
// ----------------------
// NOTATION/GLOB UTILS
Expand Down

0 comments on commit 4606c8f

Please sign in to comment.