Skip to content

Commit 4606c8f

Browse files
committed
build 2.2.0
1 parent d1e8900 commit 4606c8f

File tree

6 files changed

+93
-80
lines changed

6 files changed

+93
-80
lines changed

lib/AccessControl.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ declare class AccessControl {
103103
/**
104104
* @private
105105
*/
106-
private _locked;
106+
private _isLocked;
107107
/**
108108
* Initializes a new instance of `AccessControl` with the given grants.
109109
* @ignore

lib/AccessControl.js

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ var AccessControl = /** @class */ (function () {
111111
/**
112112
* @private
113113
*/
114-
this._locked = false;
114+
this._isLocked = false;
115115
// explicit undefined is not allowed
116116
if (arguments.length === 0)
117117
grants = {};
@@ -128,7 +128,7 @@ var AccessControl = /** @class */ (function () {
128128
* @type {Boolean}
129129
*/
130130
get: function () {
131-
return this._locked && Object.isFrozen(this._grants);
131+
return this._isLocked && Object.isFrozen(this._grants);
132132
},
133133
enumerable: true,
134134
configurable: true
@@ -288,8 +288,14 @@ var AccessControl = /** @class */ (function () {
288288
if (this.isLocked)
289289
throw new core_1.AccessControlError(utils_1.ERR_LOCK);
290290
var rolesToRemove = utils_1.utils.toStringArray(roles);
291-
rolesToRemove.forEach(function (role) {
292-
delete _this._grants[role];
291+
if (rolesToRemove.length === 0 || !utils_1.utils.isFilledStringArray(rolesToRemove)) {
292+
throw new core_1.AccessControlError("Invalid role(s): " + JSON.stringify(roles));
293+
}
294+
rolesToRemove.forEach(function (roleName) {
295+
if (!_this._grants[roleName]) {
296+
throw new core_1.AccessControlError("Cannot remove a non-existing role: \"" + roleName + "\"");
297+
}
298+
delete _this._grants[roleName];
293299
});
294300
// also remove these roles from $extend list of each remaining role.
295301
utils_1.utils.eachRole(this._grants, function (roleItem, roleName) {
@@ -626,8 +632,17 @@ var AccessControl = /** @class */ (function () {
626632
AccessControl.prototype._removePermission = function (resources, roles, actionPossession) {
627633
var _this = this;
628634
resources = utils_1.utils.toStringArray(resources);
629-
if (roles)
635+
// resources is set but returns empty array.
636+
if (resources.length === 0 || !utils_1.utils.isFilledStringArray(resources)) {
637+
throw new core_1.AccessControlError("Invalid resource(s): " + JSON.stringify(resources));
638+
}
639+
if (roles !== undefined) {
630640
roles = utils_1.utils.toStringArray(roles);
641+
// roles is set but returns empty array.
642+
if (roles.length === 0 || !utils_1.utils.isFilledStringArray(roles)) {
643+
throw new core_1.AccessControlError("Invalid role(s): " + JSON.stringify(roles));
644+
}
645+
}
631646
utils_1.utils.eachRoleResource(this._grants, function (role, resource, permissions) {
632647
if (resources.indexOf(resource) >= 0
633648
// roles is optional. so remove if role is not defined.

lib/core/Access.js

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -448,14 +448,12 @@ var Access = /** @class */ (function () {
448448
this._.possession = possession;
449449
if (resource)
450450
this._.resource = resource;
451-
if (attributes)
452-
this._.attributes = attributes;
453451
if (this._.denied) {
454452
this._.attributes = [];
455453
}
456454
else {
457455
// if omitted and not denied, all attributes are allowed
458-
this._.attributes = this._.attributes ? utils_1.utils.toStringArray(this._.attributes) : ['*'];
456+
this._.attributes = attributes ? utils_1.utils.toStringArray(attributes) : ['*'];
459457
}
460458
utils_1.utils.commitToGrants(this._grants, this._, false);
461459
// important: reset attributes for chained methods

lib/core/AccessControlError.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,10 @@ var AccessControlError = /** @class */ (function (_super) {
2121
__extends(AccessControlError, _super);
2222
function AccessControlError(message) {
2323
if (message === void 0) { message = ''; }
24-
var _this = _super.call(this, message) || this;
24+
var _this = _super.call(this, message) /* istanbul ignore next */ || this;
2525
_this.message = message;
2626
_this.name = 'AccessControlError';
27+
// https://github.com/gotwarlost/istanbul/issues/690
2728
// http://stackoverflow.com/a/41429145/112731
2829
Object.setPrototypeOf(_this, AccessControlError.prototype);
2930
return _this;

lib/utils.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ declare const utils: {
3737
getRoleHierarchyOf(grants: any, roleName: string, rootRole?: string): string[];
3838
getFlatRoles(grants: any, roles: string | string[]): string[];
3939
getNonExistentRoles(grants: any, roles: string[]): string[];
40-
getCrossInheritedRole(grants: any, roleName: string, extenderRoles: string | string[]): string | boolean;
40+
getCrossExtendingRole(grants: any, roleName: string, extenderRoles: string | string[]): string;
4141
extendRole(grants: any, roles: string | string[], extenderRoles: string | string[]): void;
4242
preCreateRoles(grants: any, roles: string | string[]): void;
4343
commitToGrants(grants: any, access: IAccessInfo, normalizeAll?: boolean): void;

lib/utils.js

Lines changed: 68 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -50,19 +50,20 @@ var utils = {
5050
return o.hasOwnProperty(propName) && o[propName] !== undefined;
5151
},
5252
/**
53-
* Converts the given (string) value into an array of string.
54-
* Note that this does not throw if the value is not a string or array.
55-
* It will silently return `null`.
53+
* Converts the given (string) value into an array of string. Note that
54+
* this does not throw if the value is not a string or array. It will
55+
* silently return `[]` (empty array). So where ever it's used, the host
56+
* function should consider throwing.
5657
* @param {Any} value
57-
* @returns {Boolean|null}
58+
* @returns {string[]}
5859
*/
5960
toStringArray: function (value) {
6061
if (Array.isArray(value))
6162
return value;
6263
if (typeof value === 'string')
6364
return value.trim().split(/\s*[;,]\s*/);
64-
// throw new Error('Cannot convert value to array!');
65-
return null;
65+
// throw new Error('Expected a string or array of strings, got ' + utils.type(value));
66+
return [];
6667
},
6768
/**
6869
* Checks whether the given array consists of non-empty string items.
@@ -298,14 +299,11 @@ var utils = {
298299
* is invalid.
299300
*/
300301
validRoleObject: function (grants, roleName) {
301-
console.log('enter!');
302302
var role = grants[roleName];
303303
if (!role || utils.type(role) !== 'object') {
304-
console.log('Invalid role:', roleName);
305304
throw new core_1.AccessControlError("Invalid role definition.");
306305
}
307306
utils.eachKey(role, function (resourceName) {
308-
console.log(resourceName, utils.validName(resourceName, false));
309307
if (!utils.validName(resourceName, false)) {
310308
if (resourceName === '$extend') {
311309
var extRoles = role[resourceName]; // semantics
@@ -322,8 +320,8 @@ var utils = {
322320
throw new core_1.AccessControlError("Cannot use reserved name \"" + resourceName + "\" for a resource.");
323321
}
324322
}
325-
else if (!utils.validResourceObject(role[resourceName])) {
326-
// throw new AccessControlError(`Invalid resource definition ("${resourceName}") for role "${roleName}".`);
323+
else {
324+
utils.validResourceObject(role[resourceName]); // throws on failure
327325
}
328326
});
329327
return true;
@@ -347,9 +345,12 @@ var utils = {
347345
if (type === 'object') {
348346
utils.eachKey(o, function (roleName) {
349347
if (utils.validName(roleName)) {
350-
return utils.validRoleObject(o, roleName); // will throw on failure
348+
return utils.validRoleObject(o, roleName); // throws on failure
351349
}
350+
/* istanbul ignore next */
352351
return false;
352+
// above is redundant, previous checks will already throw on
353+
// failure so we'll never need to break early from this.
353354
});
354355
grants = o;
355356
}
@@ -393,7 +394,8 @@ var utils = {
393394
if (asString === void 0) { asString = false; }
394395
// validate and normalize action
395396
if (typeof info.action !== 'string') {
396-
throw new core_1.AccessControlError("Invalid action: " + info.action);
397+
// throw new AccessControlError(`Invalid action: ${info.action}`);
398+
throw new core_1.AccessControlError("Invalid action: " + JSON.stringify(info));
397399
}
398400
var s = info.action.split(':');
399401
if (enums_1.actions.indexOf(s[0].trim().toLowerCase()) < 0) {
@@ -466,12 +468,12 @@ var utils = {
466468
access = Object.assign({}, access);
467469
// validate and normalize role(s)
468470
access.role = utils.toStringArray(access.role);
469-
if (!utils.isFilledStringArray(access.role)) {
471+
if (access.role.length === 0 || !utils.isFilledStringArray(access.role)) {
470472
throw new core_1.AccessControlError("Invalid role(s): " + JSON.stringify(access.role));
471473
}
472474
// validate and normalize resource
473475
access.resource = utils.toStringArray(access.resource);
474-
if (!utils.isFilledStringArray(access.resource)) {
476+
if (access.resource.length === 0 || !utils.isFilledStringArray(access.resource)) {
475477
throw new core_1.AccessControlError("Invalid resource(s): " + JSON.stringify(access.resource));
476478
}
477479
// normalize attributes
@@ -515,7 +517,7 @@ var utils = {
515517
getRoleHierarchyOf: function (grants, roleName, rootRole) {
516518
// `rootRole` is for memory storage. Do NOT set it when using;
517519
// and do NOT document this paramter.
518-
rootRole = rootRole || roleName;
520+
// rootRole = rootRole || roleName;
519521
var role = grants[roleName];
520522
if (!role)
521523
throw new core_1.AccessControlError("Role not found: \"" + roleName + "\"");
@@ -531,10 +533,10 @@ var utils = {
531533
}
532534
// throw if cross-inheritance and also avoid memory leak with
533535
// maximum call stack error
534-
if (rootRole === exRoleName) {
536+
if (rootRole && (rootRole === exRoleName)) {
535537
throw new core_1.AccessControlError("Cross inheritance is not allowed. Role \"" + exRoleName + "\" already extends \"" + rootRole + "\".");
536538
}
537-
var ext = utils.getRoleHierarchyOf(grants, exRoleName, rootRole);
539+
var ext = utils.getRoleHierarchyOf(grants, exRoleName, rootRole || roleName);
538540
arr = utils.uniqConcat(arr, ext);
539541
});
540542
return arr;
@@ -543,11 +545,12 @@ var utils = {
543545
* Gets roles and extended roles in a flat array.
544546
*/
545547
getFlatRoles: function (grants, roles) {
546-
roles = utils.toStringArray(roles);
547-
if (!roles)
548+
var arrRoles = utils.toStringArray(roles);
549+
if (arrRoles.length === 0) {
548550
throw new core_1.AccessControlError("Invalid role(s): " + JSON.stringify(roles));
549-
var arr = utils.uniqConcat([], roles); // roles.concat();
550-
roles.forEach(function (roleName) {
551+
}
552+
var arr = utils.uniqConcat([], arrRoles); // roles.concat();
553+
arrRoles.forEach(function (roleName) {
551554
arr = utils.uniqConcat(arr, utils.getRoleHierarchyOf(grants, roleName));
552555
});
553556
// console.log(`flat roles for ${roles}`, arr);
@@ -581,13 +584,14 @@ var utils = {
581584
*
582585
* @param {Any} grants - Grants model to be checked.
583586
* @param {string} roles - Target role to be checked.
584-
* @param {string|string[]} extenderRoles - Extender role(s) to be
585-
* checked.
586-
* @returns {Boolean}
587+
* @param {string|string[]} extenderRoles - Extender role(s) to be checked.
588+
*
589+
* @returns {string|null} - Returns the first cross extending role. `null`
590+
* if none.
587591
*/
588-
getCrossInheritedRole: function (grants, roleName, extenderRoles) {
589-
var extenders = utils.toStringArray(extenderRoles); // [roleName].concat();
590-
var crossInherited = false;
592+
getCrossExtendingRole: function (grants, roleName, extenderRoles) {
593+
var extenders = utils.toStringArray(extenderRoles);
594+
var crossInherited = null;
591595
utils.each(extenders, function (e) {
592596
if (crossInherited || roleName === e) {
593597
return false; // break out of loop
@@ -623,43 +627,41 @@ var utils = {
623627
* a cross-inherited role.
624628
*/
625629
extendRole: function (grants, roles, extenderRoles) {
630+
// roles cannot be omitted or an empty array
631+
roles = utils.toStringArray(roles);
632+
if (roles.length === 0) {
633+
throw new core_1.AccessControlError("Invalid role(s): " + JSON.stringify(roles));
634+
}
635+
// extenderRoles cannot be omitted or but can be an empty array
636+
if (utils.isEmptyArray(extenderRoles))
637+
return;
626638
var arrExtRoles = utils.toStringArray(extenderRoles).concat();
627-
if (!arrExtRoles)
639+
if (arrExtRoles.length === 0) {
628640
throw new core_1.AccessControlError("Cannot inherit invalid role(s): " + JSON.stringify(extenderRoles));
641+
}
629642
var nonExistentExtRoles = utils.getNonExistentRoles(grants, arrExtRoles);
630643
if (nonExistentExtRoles.length > 0) {
631644
throw new core_1.AccessControlError("Cannot inherit non-existent role(s): \"" + nonExistentExtRoles.join(', ') + "\"");
632645
}
633-
roles = utils.toStringArray(roles);
634-
if (!roles)
635-
throw new core_1.AccessControlError("Invalid role(s): " + JSON.stringify(roles));
636646
roles.forEach(function (roleName) {
637647
if (!grants[roleName])
638648
throw new core_1.AccessControlError("Role not found: \"" + roleName + "\"");
639649
if (arrExtRoles.indexOf(roleName) >= 0) {
640650
throw new core_1.AccessControlError("Cannot extend role \"" + roleName + "\" by itself.");
641651
}
642-
// getCrossInheritedRole() returns false or the first
652+
// getCrossExtendingRole() returns false or the first
643653
// cross-inherited role, if found.
644-
var crossInherited = utils.getCrossInheritedRole(grants, roleName, arrExtRoles);
654+
var crossInherited = utils.getCrossExtendingRole(grants, roleName, arrExtRoles);
645655
if (crossInherited) {
646656
throw new core_1.AccessControlError("Cross inheritance is not allowed. Role \"" + crossInherited + "\" already extends \"" + roleName + "\".");
647657
}
648-
if (utils.validName(roleName)) {
649-
if (!grants.hasOwnProperty(roleName)) {
650-
grants[roleName] = {
651-
$extend: arrExtRoles
652-
};
653-
}
654-
else {
655-
var r = grants[roleName];
656-
if (Array.isArray(r.$extend)) {
657-
r.$extend = utils.uniqConcat(r.$extend, arrExtRoles);
658-
}
659-
else {
660-
r.$extend = arrExtRoles;
661-
}
662-
}
658+
utils.validName(roleName); // throws if false
659+
var r = grants[roleName];
660+
if (Array.isArray(r.$extend)) {
661+
r.$extend = utils.uniqConcat(r.$extend, arrExtRoles);
662+
}
663+
else {
664+
r.$extend = arrExtRoles;
663665
}
664666
});
665667
},
@@ -728,31 +730,27 @@ var utils = {
728730
* @returns {string[]} - Array of union'ed attributes.
729731
*/
730732
getUnionAttrsOfRoles: function (grants, query) {
731-
if (!grants) {
732-
throw new core_1.AccessControlError('Grants are not set.');
733-
}
734733
// throws if has any invalid property value
735734
query = utils.normalizeQueryInfo(query);
736-
var grantItem;
735+
var role;
737736
var resource;
738737
var attrsList = [];
739738
// get roles and extended roles in a flat array
740739
var roles = utils.getFlatRoles(grants, query.role);
741740
// iterate through roles and add permission attributes (array) of
742741
// each role to attrsList (array).
743-
roles.forEach(function (role, index) {
744-
grantItem = grants[role];
745-
if (grantItem) {
746-
resource = grantItem[query.resource];
747-
if (resource) {
748-
// e.g. resource['create:own']
749-
// If action has possession "any", it will also return
750-
// `granted=true` for "own", if "own" is not defined.
751-
attrsList.push((resource[query.action + ':' + query.possession]
752-
|| resource[query.action + ':any']
753-
|| []).concat());
754-
// console.log(resource, 'for:', action + '.' + possession);
755-
}
742+
roles.forEach(function (roleName, index) {
743+
role = grants[roleName];
744+
// no need to check role existence #getFlatRoles() does that.
745+
resource = role[query.resource];
746+
if (resource) {
747+
// e.g. resource['create:own']
748+
// If action has possession "any", it will also return
749+
// `granted=true` for "own", if "own" is not defined.
750+
attrsList.push((resource[query.action + ':' + query.possession]
751+
|| resource[query.action + ':any']
752+
|| []).concat());
753+
// console.log(resource, 'for:', action + '.' + possession);
756754
}
757755
});
758756
// union all arrays of (permitted resource) attributes (for each role)
@@ -776,16 +774,17 @@ var utils = {
776774
*/
777775
lockAC: function (ac) {
778776
var _ac = ac; // ts
779-
if (!_ac._grants) {
780-
throw new core_1.AccessControlError('Cannot lock due to invalid grants model.');
777+
if (!_ac._grants || Object.keys(_ac._grants).length === 0) {
778+
throw new core_1.AccessControlError('Cannot lock empty or invalid grants model.');
781779
}
782780
var locked = ac.isLocked && Object.isFrozen(_ac._grants);
783781
if (!locked)
784782
locked = Boolean(utils.deepFreeze(_ac._grants));
783+
/* istanbul ignore next */
785784
if (!locked) {
786785
throw new core_1.AccessControlError("Could not lock grants: " + typeof _ac._grants);
787786
}
788-
_ac._locked = locked;
787+
_ac._isLocked = locked;
789788
},
790789
// ----------------------
791790
// NOTATION/GLOB UTILS

0 commit comments

Comments
 (0)