Skip to content

Commit

Permalink
re-build
Browse files Browse the repository at this point in the history
  • Loading branch information
onury committed Nov 26, 2017
1 parent ef4b888 commit 7fee23b
Show file tree
Hide file tree
Showing 6 changed files with 252 additions and 205 deletions.
100 changes: 47 additions & 53 deletions lib/AccessControl.js
Original file line number Diff line number Diff line change
Expand Up @@ -253,11 +253,11 @@ var AccessControl = /** @class */ (function () {
* Extends the given role(s) with privileges of one or more other roles.
* @chainable
*
* @param {String|Array<String>} roles Role(s) to be extended. Single role
* @param {string|Array<String>} roles Role(s) to be extended. Single role
* as a `String` or multiple roles as an `Array`. Note that if a
* role does not exist, it will be automatically created.
*
* @param {String|Array<String>} extenderRoles Role(s) to inherit from.
* @param {string|Array<String>} extenderRoles Role(s) to inherit from.
* Single role as a `String` or multiple roles as an `Array`. Note
* that if a extender role does not exist, it will throw.
*
Expand All @@ -276,7 +276,7 @@ var AccessControl = /** @class */ (function () {
* Removes all the given role(s) and their granted permissions, at once.
* @chainable
*
* @param {String|Array<String>} roles - An array of roles to be removed.
* @param {string|Array<String>} roles - An array of roles to be removed.
* Also accepts a string that can be used to remove a single role.
*
* @returns {AccessControl} - `AccessControl` instance for chaining.
Expand All @@ -292,7 +292,7 @@ var AccessControl = /** @class */ (function () {
delete _this._grants[role];
});
// also remove these roles from $extend list of each remaining role.
this._each(function (role, roleItem) {
utils_1.utils.eachRole(this._grants, function (roleItem, roleName) {
if (Array.isArray(roleItem.$extend)) {
roleItem.$extend = utils_1.utils.subtractArray(roleItem.$extend, rolesToRemove);
}
Expand All @@ -305,9 +305,9 @@ var AccessControl = /** @class */ (function () {
* roles only.
* @chainable
*
* @param {String|Array<String>} resources - A single or array of resources to
* @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
* @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.
*
Expand Down Expand Up @@ -341,12 +341,12 @@ var AccessControl = /** @class */ (function () {
* @alias AccessControl#getExtendedRolesOf
* @function
*
* @param {String} role - Target role name.
* @param {string} role - Target role name.
*
* @returns {Array<String>}
*/
AccessControl.prototype.getInheritedRolesOf = function (role) {
var roles = utils_1.utils.getInheritedRolesOf(this._grants, role);
var roles = utils_1.utils.getRoleHierarchyOf(this._grants, role);
roles.shift();
return roles;
};
Expand All @@ -364,35 +364,38 @@ var AccessControl = /** @class */ (function () {
* @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);
return utils_1.utils.getResources(this._grants);
};
/**
* Checks whether any permissions are granted to the given role.
* Checks whether the grants include the given role or roles.
*
* @param {String} role - Role to be checked.
* @param {string|string[]} role - Role to be checked. You can also pass an
* array of strings to check multiple roles at once.
*
* @returns {Boolean}
*/
AccessControl.prototype.hasRole = function (role) {
var _this = this;
if (Array.isArray(role)) {
return role.every(function (item) { return _this._grants.hasOwnProperty(item); });
}
return this._grants.hasOwnProperty(role);
};
/**
* Checks whether any permissions are granted for the given resource.
* Checks whether grants include the given resource or resources.
*
* @param {String} resource - Resource to be checked.
* @param {string|string[]} resource - Resource to be checked. You can also pass an
* array of strings to check multiple resources at once.
*
* @returns {Boolean}
*/
AccessControl.prototype.hasResource = function (resource) {
if (typeof resource !== 'string' || resource === '') {
return false;
}
var resources = this.getResources();
if (Array.isArray(resource)) {
return resource.every(function (item) { return resources.indexOf(item) >= 0; });
}
if (typeof resource !== 'string' || resource === '')
return false;
return resources.indexOf(resource) >= 0;
};
/**
Expand All @@ -405,7 +408,7 @@ var AccessControl = /** @class */ (function () {
* @function
* @chainable
*
* @param {String|Array|IQueryInfo} role - A single role (as a string), a
* @param {string|Array|IQueryInfo} role - A single role (as a string), a
* list of roles (as an array) or an
* {@link ?api=ac#AccessControl~IQueryInfo|`IQueryInfo` object} that fully
* or partially defines the access to be checked.
Expand All @@ -428,6 +431,11 @@ var AccessControl = /** @class */ (function () {
* // Note: when multiple roles checked, acquired attributes are unioned (merged).
*/
AccessControl.prototype.can = function (role) {
// throw on explicit undefined
if (arguments.length !== 0 && role === undefined) {
throw new core_1.AccessControlError('Invalid role(s): undefined');
}
// other explicit invalid values will be checked in constructor.
return new core_1.Query(this._grants, role);
};
/**
Expand Down Expand Up @@ -474,15 +482,17 @@ var AccessControl = /** @class */ (function () {
* @function
* @chainable
*
* @param {String|Array<String>|IAccessInfo} role A single role (as a
* @param {string|Array<String>|IAccessInfo} [role] A single role (as a
* string), a list of roles (as an array) or an
* {@link ?api=ac#AccessControl~IAccessInfo|`IAccessInfo` object} that
* fully or partially defines the access to be granted.
* fully or partially defines the access to be granted. This can be omitted
* and chained with `.role()` to define the role.
*
* @return {Access} - The returned object provides chainable properties to
* build and define the access to be granted. See the examples for details.
* See {@link ?api=ac#AccessControl~Access|`Access` inner class}.
*
* @throws {AccessControlError} - If `role` is explicitly set to an invalid value.
* @throws {AccessControlError} - If called after `.lock()` is called.
*
* @example
Expand Down Expand Up @@ -524,6 +534,11 @@ var AccessControl = /** @class */ (function () {
AccessControl.prototype.grant = function (role) {
if (this.isLocked)
throw new core_1.AccessControlError(utils_1.ERR_LOCK);
// throw on explicit undefined
if (arguments.length !== 0 && role === undefined) {
throw new core_1.AccessControlError('Invalid role(s): undefined');
}
// other explicit invalid values will be checked in constructor.
return new core_1.Access(this, role, false);
};
/**
Expand All @@ -543,7 +558,7 @@ var AccessControl = /** @class */ (function () {
* @function
* @chainable
*
* @param {String|Array<String>|IAccessInfo} role A single role (as a
* @param {string|Array<String>|IAccessInfo} role A single role (as a
* string), a list of roles (as an array) or an
* {@link ?api=ac#AccessControl~IAccessInfo|`IAccessInfo` object} that
* fully or partially defines the access to be denied.
Expand All @@ -552,6 +567,7 @@ var AccessControl = /** @class */ (function () {
* build and define the access to be granted. See
* {@link ?api=ac#AccessControl~Access|`Access` inner class}.
*
* @throws {AccessControlError} - If `role` is explicitly set to an invalid value.
* @throws {AccessControlError} - If called after `.lock()` is called.
*
* @example
Expand Down Expand Up @@ -587,6 +603,11 @@ var AccessControl = /** @class */ (function () {
AccessControl.prototype.deny = function (role) {
if (this.isLocked)
throw new core_1.AccessControlError(utils_1.ERR_LOCK);
// throw on explicit undefined
if (arguments.length !== 0 && role === undefined) {
throw new core_1.AccessControlError('Invalid role(s): undefined');
}
// other explicit invalid values will be checked in constructor.
return new core_1.Access(this, role, true);
};
/**
Expand All @@ -599,33 +620,6 @@ var AccessControl = /** @class */ (function () {
// -------------------------------
// PRIVATE METHODS
// -------------------------------
/**
* @private
*/
AccessControl.prototype._each = function (callback) {
var _this = this;
utils_1.utils.eachKey(this._grants, function (role) { return callback(role, _this._grants[role]); });
};
/**
* @private
*/
AccessControl.prototype._eachRole = function (callback) {
utils_1.utils.eachKey(this._grants, function (role) { return callback(role); });
};
/**
* @private
*/
AccessControl.prototype._eachRoleResource = function (callback) {
var _this = this;
var resources, resourceDefinition;
this._eachRole(function (role) {
resources = _this._grants[role];
utils_1.utils.eachKey(resources, function (resource) {
resourceDefinition = role[resource];
callback(role, resource, resourceDefinition);
});
});
};
/**
* @private
*/
Expand All @@ -634,7 +628,7 @@ var AccessControl = /** @class */ (function () {
resources = utils_1.utils.toStringArray(resources);
if (roles)
roles = utils_1.utils.toStringArray(roles);
this._eachRoleResource(function (role, resource, permissions) {
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.
// if defined, check if the current role is in the list.
Expand Down
9 changes: 9 additions & 0 deletions lib/core/Access.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var core_1 = require("../core");
var enums_1 = require("../enums");
var utils_1 = require("../utils");
/**
Expand Down Expand Up @@ -43,13 +44,21 @@ var Access = /** @class */ (function () {
this.role(roleOrInfo);
}
else if (utils_1.utils.type(roleOrInfo) === 'object') {
if (Object.keys(roleOrInfo).length === 0) {
throw new core_1.AccessControlError('Invalid IAccessInfo: {}');
}
// if an IAccessInfo instance is passed and it has 'action' defined, we
// should directly commit it to grants.
roleOrInfo.denied = denied;
this._ = utils_1.utils.resetAttributes(roleOrInfo);
if (utils_1.utils.isInfoFulfilled(this._))
utils_1.utils.commitToGrants(this._grants, this._, true);
}
else if (roleOrInfo !== undefined) {
// undefined is allowed (`roleOrInfo` can be omitted) but throw if
// some other type is passed.
throw new core_1.AccessControlError('Invalid role(s), expected a valid string, string[] or IAccessInfo.');
}
}
Object.defineProperty(Access.prototype, "denied", {
// -------------------------------
Expand Down
3 changes: 2 additions & 1 deletion lib/core/Permission.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,10 @@ var Permission = /** @class */ (function () {
* @private
*/
this._ = {};
// set attributes first. this also validates the `query` object.
this._.attributes = utils_1.utils.getUnionAttrsOfRoles(grants, query);
this._.role = query.role;
this._.resource = query.resource;
this._.attributes = utils_1.utils.getUnionAttrsOfRoles(grants, query);
}
Object.defineProperty(Permission.prototype, "roles", {
/**
Expand Down
26 changes: 17 additions & 9 deletions lib/core/Query.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,27 +20,35 @@ var Query = /** @class */ (function () {
* @param {Any} grants
* Underlying grants model against which the permissions will be
* queried and checked.
* @param {string|Array<String>|IQueryInfo} [role]
* @param {string|Array<String>|IQueryInfo} [roleOrInfo]
* Either a single or array of roles or an
* {@link ?api=ac#AccessControl~IQueryInfo|`IQueryInfo` arbitrary object}.
*/
function Query(grants, role) {
function Query(grants, roleOrInfo) {
/**
* Inner `IQueryInfo` object.
* @protected
* @type {IQueryInfo}
*/
this._ = {};
this._grants = grants;
// if this is a (permission) object, we directly build attributes from
// grants.
if (utils_1.utils.type(role) === 'object') {
this._ = role;
}
else {
if (typeof roleOrInfo === 'string' || Array.isArray(roleOrInfo)) {
// if this is just role(s); a string or array; we start building
// the grant object for this.
this._.role = role;
this.role(roleOrInfo);
}
else if (utils_1.utils.type(roleOrInfo) === 'object') {
// if this is a (permission) object, we directly build attributes
// from grants.
if (Object.keys(roleOrInfo).length === 0) {
throw new core_1.AccessControlError('Invalid IQueryInfo: {}');
}
this._ = roleOrInfo;
}
else if (roleOrInfo !== undefined) {
// undefined is allowed (`role` can be omitted) but throw if some
// other type is passed.
throw new core_1.AccessControlError('Invalid role(s), expected a valid string, string[] or IQueryInfo.');
}
}
// -------------------------------
Expand Down
20 changes: 11 additions & 9 deletions lib/utils.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,28 +14,30 @@ declare const utils: {
hasDefined(o: any, propName: string): boolean;
toStringArray(value: any): string[];
isFilledStringArray(arr: any[]): boolean;
isStringOrArray(value: any): boolean;
isEmptyArray(value: any): boolean;
pushUniq(arr: string[], item: string): string[];
uniqConcat(arrA: string[], arrB: string[]): string[];
subtractArray(arrA: string[], arrB: string[]): string[];
deepFreeze(o: any): any;
each(array: any, callback: any, thisArg?: any): void;
eachKey(object: any, callback: any): void;
eachKey(object: any, callback: any, thisArg?: any): void;
eachRole(grants: any, callback: (role: any, roleName: string) => void): void;
eachRoleResource(grants: any, callback: (role: string, resource: string, resourceDefinition: any) => void): void;
isInfoFulfilled(info: IAccessInfo | IQueryInfo): boolean;
validName(name: string, throwOnInvalid?: boolean, msg?: string): boolean;
hasValidNames(list: any, throwOnInvalid?: boolean, msg?: string): boolean;
validResourceObject(o: any, throwOnInvalid?: boolean): boolean;
validRoleObject(o: any, roleName: string, throwOnInvalid?: boolean): boolean;
validName(name: string, throwOnInvalid?: boolean): boolean;
hasValidNames(list: any, throwOnInvalid?: boolean): boolean;
validResourceObject(o: any): boolean;
validRoleObject(grants: any, roleName: string): boolean;
getInspectedGrants(o: any): any;
getResources(grants: any): string[];
normalizeActionPossession(info: IAccessInfo | IQueryInfo, asString?: boolean): string | IAccessInfo | IQueryInfo;
normalizeQueryInfo(query: IQueryInfo, all?: boolean): IQueryInfo;
normalizeQueryInfo(query: IQueryInfo): IQueryInfo;
normalizeAccessInfo(access: IAccessInfo, all?: boolean): IAccessInfo;
resetAttributes(access: IAccessInfo): IAccessInfo;
getInheritedRolesOf(grants: any, roleName: string): string[];
getRoleHierarchyOf(grants: any, roleName: string, rootRole?: string): string[];
getFlatRoles(grants: any, roles: string | string[]): string[];
getNonExistentRoles(grants: any, roles: string[]): string[];
getCrossInheritedRole(grants: any, role: string, extenderRoles: string | string[]): string | boolean;
getCrossInheritedRole(grants: any, roleName: string, extenderRoles: string | string[]): string | boolean;
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
Loading

0 comments on commit 7fee23b

Please sign in to comment.