@cobuildlab/rbac
Advanced tools
Comparing version 0.1.0 to 0.2.0
import { ValidatorFunctionType } from './types'; | ||
export declare class RBAC<R extends Record<string, string>, P extends Record<string, string>, D extends Partial<Record<keyof P, unknown>> = {}> { | ||
export declare class RBAC<R extends string, P extends string, D extends Partial<Record<P, unknown>> = {}> { | ||
private rules; | ||
private currentRole; | ||
constructor(roles?: R, permissions?: P); | ||
constructor(defualtRole: R); | ||
/** | ||
@@ -13,3 +13,3 @@ * @description - Generate a role and assign a permission. | ||
*/ | ||
createRule(roleName: keyof R, permissionName: keyof P, test: boolean | ValidatorFunctionType<D[keyof P]>, message?: string): void; | ||
createRule(roleName: R, permissionName: P, test: boolean | ValidatorFunctionType<D[P]>, message?: string): void; | ||
/** | ||
@@ -32,3 +32,3 @@ * @description - Check if a role is withing the rules. | ||
*/ | ||
setDefaultRole(name: keyof R): void; | ||
setDefaultRole(name: R): void; | ||
/** | ||
@@ -41,3 +41,3 @@ * @description - Function check used for validation. | ||
*/ | ||
check(role: keyof R | null, permission: keyof P, data?: D[keyof P]): [boolean, string?]; | ||
check(role: R | null, permission: P, data?: D[P]): [boolean, string?]; | ||
} |
@@ -5,5 +5,5 @@ "use strict"; | ||
var RBAC = /** @class */ (function () { | ||
function RBAC(roles, permissions) { | ||
function RBAC(defualtRole) { | ||
this.rules = {}; | ||
this.currentRole = ''; | ||
this.currentRole = defualtRole; | ||
} | ||
@@ -67,7 +67,5 @@ /** | ||
RBAC.prototype.check = function (role, permission, data) { | ||
var _a, _b, _c, _d; | ||
var currentRole = ((_b = (_a = this.currentRole) === null || _a === void 0 ? void 0 : _a.toString()) === null || _b === void 0 ? void 0 : _b.length) && !role | ||
? this.currentRole | ||
: role !== null && role !== void 0 ? role : ''; | ||
if (!((_d = (_c = this.currentRole) === null || _c === void 0 ? void 0 : _c.toString()) === null || _d === void 0 ? void 0 : _d.length) && !role) { | ||
var _a, _b; | ||
var currentRole = role !== null && role !== void 0 ? role : this.currentRole; | ||
if (!((_b = (_a = this.currentRole) === null || _a === void 0 ? void 0 : _a.toString()) === null || _b === void 0 ? void 0 : _b.length) && !role) { | ||
console.error('Not default role or default-role found'); | ||
@@ -74,0 +72,0 @@ return [false, 'Not default role or default-role found']; |
@@ -1,10 +0,6 @@ | ||
export declare type RulesType<R, P> = { | ||
[role in keyof R]: { | ||
[permission in keyof P]: { | ||
can?: boolean; | ||
dynamic?: ValidatorFunctionType; | ||
message?: string; | ||
}; | ||
}; | ||
}; | ||
export declare type RulesType<R extends string, P extends string> = Record<R, Record<P, { | ||
can?: boolean; | ||
dynamic?: ValidatorFunctionType; | ||
message?: string; | ||
}>>; | ||
export declare type ValidatorFunctionType<T = unknown> = (data: T) => [boolean, string?]; |
"use strict"; | ||
// export type RulesType<R,P> = { | ||
// [role in keyof R]: { | ||
// [permission in keyof P]: { | ||
// can?: boolean; | ||
// dynamic?: ValidatorFunctionType; | ||
// message?: string; | ||
// }; | ||
// }; | ||
// }; | ||
Object.defineProperty(exports, "__esModule", { value: true }); |
{ | ||
"name": "@cobuildlab/rbac", | ||
"version": "0.1.0", | ||
"version": "0.2.0", | ||
"description": "", | ||
@@ -5,0 +5,0 @@ "main": "lib/index.js", |
168
README.md
# Role-Based Access Control | ||
Role-based access control (RBAC) refers to the idea of assigning permissions to users based on their role within an organization. It offers a simple, manageable approach to access management that is less prone to error than assigning permissions to users individually. | ||
Role-based access control (RBAC) refers to the idea of assigning permissions to users based on their role within an organization. It offers a simple, manageable approach to access management that is less prone to error than assigning permissions to users individually. | ||
### RBAC architecture conventions discussion | ||
https://github.com/cobuildlab/conventions/issues/24 | ||
https://github.com/cobuildlab/conventions/issues/24 | ||
<br/> | ||
@@ -26,3 +27,2 @@ | ||
## Installation | ||
@@ -37,13 +37,34 @@ | ||
[`Example`](#Examples) | ||
### Basic use | ||
### Basic use (Strictly types by defualt) | ||
```typescript | ||
const RBACproject = new RBAC(); | ||
// It is strictly typed so it need enums declared before initialization | ||
enum Roles { | ||
ADMIN = 'ADMIN', | ||
MANAGER = 'MANAGER', | ||
} | ||
// defined the rules | ||
RBACproject.createRule('admin', 'dashboard', true, 'Access granted'); | ||
RBACproject.createRule('manager', 'dashboard', false, 'Access denied'); | ||
enum Permissions { | ||
DASHBOARD = 'DASHBOARD', | ||
} | ||
RBACproject.check('admin', 'dashboard') // [true, 'Access granted'] | ||
// It needs the Roles and Permissions passed as generics, and a default role. | ||
const RBACproject = new RBAC<Roles, Permissions>(Roles.ADMIN); | ||
// defined the rules | ||
RBACproject.createRule( | ||
Roles.ADMIN, | ||
Permissions.DASHBOARD, | ||
true, | ||
'Access granted', | ||
); | ||
RBACproject.createRule( | ||
Roles.MANAGER, | ||
Permissions.DASHBOARD, | ||
false, | ||
'Access denied', | ||
); | ||
RBACproject.check(Roles.ADMIN, Permissions.DASHBOARD); // [true, 'Access granted'] | ||
``` | ||
@@ -54,43 +75,56 @@ | ||
```typescript | ||
const RBACdynamic = new RBAC(); | ||
// It is strictly typed so it need enums declared before initialization | ||
enum Roles { | ||
ADMIN = 'ADMIN', | ||
MANAGER = 'MANAGER', | ||
} | ||
// defined dynamic rules | ||
RBACdynamic.createRule('admin', 'dashboard', (data: any) => { | ||
const result = data.id === testData.id; | ||
const message = result ? 'Access granted' : 'Access denied'; | ||
return [result, message]; | ||
}); | ||
enum Permissions { | ||
DASHBOARD = 'DASHBOARD', | ||
} | ||
const testData = { id: 'test' }; // fake data | ||
RBACdynamic.check('admin', 'dashboard', testData) | ||
// It accept a type for the dinamic data of the permission | ||
const RBACdynamic = new RBAC< | ||
Roles, | ||
Permissions, | ||
{ DASHBOARD: { shouldEdit: boolean } } | ||
>(Roles.ADMIN); | ||
// Here data will be types as `{ shouldEdit: boolean }` | ||
RBACdynamic.createRule(Roles.ADMIN, Permissions.DASHBOARD, (data) => { | ||
const result = data.shouldEdit; | ||
const message = result ? 'Access granted' : 'Access denied'; | ||
return [result, message]; | ||
}); | ||
const testData = { shouldEdit: true }; // fake data | ||
RBACdynamic.check(Roles.ADMIN, Permissions.DASHBOARD, testData); | ||
``` | ||
### Set default role | ||
```typescript | ||
const defaultRole = new RBAC(); | ||
enum Roles { | ||
ADMIN = 'ADMIN', | ||
MANAGER = 'MANAGER', | ||
} | ||
defaultRole.createRule('admin', 'dashboard', false, 'Access granted'); | ||
defaultRole.setDefaultRole('admin'); | ||
enum Permissions { | ||
DASHBOARD = 'DASHBOARD', | ||
} | ||
rule.check(null, 'dashboard') // [false, 'Access granted'] | ||
``` | ||
const defaultRole = new RBAC<Roles, Permissions>(Roles.MANGER); | ||
### Strict Type | ||
defaultRole.createRule( | ||
Roles.ADMIN, | ||
Permissions.DASHBOARD, | ||
false, | ||
'Access granted', | ||
); | ||
```typescript | ||
enum Roles { | ||
ADMIN = 'ADMIN', | ||
MANAGER = 'MANAGER', | ||
} | ||
// This method allows to set a defualt role, after initialization | ||
defaultRole.setDefaultRole(Roles.ADMIN); | ||
enum Permissions { | ||
DASHBOARD = 'DASHBOARD', | ||
} | ||
const defaultRole = new RBAC(Roles, Permissions); | ||
defaultRole.createRule(Roles.ADMIN, Permissions.DASHBOARD, false, 'Access granted'); | ||
rule.check(Roles.ADMIN, 'dashboard') // [false, 'Access granted'] | ||
defaultRole.check(null, Permissions.DASHBOARD); // [false, 'Access granted'] | ||
``` | ||
@@ -100,11 +134,22 @@ | ||
```js | ||
const RBAC = new RBAC(); | ||
RBAC.createRule('admin', 'AGENT_ADMIN_USER_DETAILS', false, 'Access granted'); | ||
```tsx | ||
enum Roles { | ||
ADMIN = 'ADMIN', | ||
MANAGER = 'MANAGER', | ||
} | ||
const RoleAuthorization = ({ | ||
render, | ||
error, | ||
permission, | ||
}) => { | ||
enum Permissions { | ||
AGENT_ADMIN_USER_DETAILS = 'AGENT_ADMIN_USER_DETAILS', | ||
} | ||
const RBAC = new RBAC<Roles, Permissions>(Roles.MANGER); | ||
RBAC.createRule( | ||
Roles.ADMIN, | ||
Permissions.AGENT_ADMIN_USER_DETAILS, | ||
false, | ||
'Access granted', | ||
); | ||
const RoleAuthorization = ({ render, error, permission }) => { | ||
const [canRender, message] = RBAC.check('admin', permission, data); | ||
@@ -124,3 +169,32 @@ if (canRender) { | ||
); | ||
``` | ||
### Integration with Node.js | ||
```ts | ||
const api = require('api-request'); | ||
enum Roles { | ||
ADMIN = 'ADMIN', | ||
MANAGER = 'MANAGER', | ||
} | ||
enum Permissions { | ||
CAN_READ_USERS = 'CAN_READ_USERS', | ||
} | ||
const RBAC = new RBAC<Roles, Permissions>(Roles.MANGER); | ||
RBAC.createRule( | ||
Roles.ADMIN, | ||
Permissions.CAN_READ_USERS, | ||
true, | ||
'Access granted', | ||
); | ||
if (RBAC.check(Roles.ADMIN, Permissions.CAN_READ_USERS)) { | ||
api.getUser().then((users) => { | ||
//Do some stuff with uses. | ||
}); | ||
} | ||
``` |
@@ -13,3 +13,4 @@ import { test, expect } from '@jest/globals'; | ||
const staticRules = new RBAC(Roles, Permissions); | ||
const staticRules = new RBAC<Roles, Permissions>(Roles.ADMIN); | ||
staticRules.createRule( | ||
@@ -44,7 +45,5 @@ Roles.ADMIN, | ||
const dynamic = new RBAC< | ||
typeof Roles, | ||
typeof Permissions, | ||
{ DASHBOARD: { id: string } } | ||
>(); | ||
const dynamic = new RBAC<Roles, Permissions, { DASHBOARD: { id: string } }>( | ||
Roles.ADMIN, | ||
); | ||
const testData = { id: 'test' }; | ||
@@ -76,3 +75,3 @@ dynamic.createRule( | ||
} | ||
const rule = new RBAC<typeof Roles, typeof Permissions>(); | ||
const rule = new RBAC<Roles, Permissions>(Roles.ADMIN); | ||
rule.createRule(Roles.ADMIN, Permissions.DASHBOARD, false, 'Access granted'); | ||
@@ -88,14 +87,1 @@ rule.setDefaultRole(Roles.ADMIN); | ||
}); | ||
test('Unexpected use of check', () => { | ||
const rule = new RBAC(); | ||
rule.createRule('admin', 'dashboard', false, 'Access granted'); | ||
expect(rule.check(null, 'dashboard')).toStrictEqual([ | ||
false, | ||
'Not default role or default-role found', | ||
]); | ||
expect(rule.check('error-role', 'dashboard')).toStrictEqual([ | ||
false, | ||
'Not permission error-role found in rules', | ||
]); | ||
}); |
@@ -7,11 +7,11 @@ /* eslint-disable @typescript-eslint/ban-types */ | ||
export class RBAC< | ||
R extends Record<string, string>, | ||
P extends Record<string, string>, | ||
D extends Partial<Record<keyof P, unknown>> = {} | ||
R extends string, | ||
P extends string, | ||
D extends Partial<Record<P, unknown>> = {} | ||
> { | ||
private rules: Partial<RulesType<R, P>> = {}; | ||
private currentRole: keyof R; | ||
private currentRole: R; | ||
constructor(roles?: R, permissions?: P) { | ||
this.currentRole = ''; | ||
constructor(defualtRole: R) { | ||
this.currentRole = defualtRole; | ||
} | ||
@@ -27,5 +27,5 @@ | ||
createRule( | ||
roleName: keyof R, | ||
permissionName: keyof P, | ||
test: boolean | ValidatorFunctionType<D[keyof P]>, | ||
roleName: R, | ||
permissionName: P, | ||
test: boolean | ValidatorFunctionType<D[P]>, | ||
message?: string, | ||
@@ -49,3 +49,3 @@ ): void { | ||
*/ | ||
private isRoleInRules(role: keyof R): boolean { | ||
private isRoleInRules(role: R): boolean { | ||
return Boolean(this.rules[role]); | ||
@@ -60,3 +60,3 @@ } | ||
*/ | ||
private isPermissionInRole(role: keyof R, permission: keyof P): boolean { | ||
private isPermissionInRole(role: R, permission: P): boolean { | ||
return Boolean(this.rules[role]?.[permission]); | ||
@@ -69,3 +69,3 @@ } | ||
*/ | ||
setDefaultRole(name: keyof R): void { | ||
setDefaultRole(name: R): void { | ||
if (this.isRoleInRules(name)) { | ||
@@ -85,11 +85,4 @@ this.currentRole = name; | ||
*/ | ||
check( | ||
role: keyof R | null, | ||
permission: keyof P, | ||
data?: D[keyof P], | ||
): [boolean, string?] { | ||
const currentRole: keyof R = | ||
this.currentRole?.toString()?.length && !role | ||
? this.currentRole | ||
: role ?? ''; | ||
check(role: R | null, permission: P, data?: D[P]): [boolean, string?] { | ||
const currentRole: R = role ?? this.currentRole; | ||
@@ -96,0 +89,0 @@ if (!this.currentRole?.toString()?.length && !role) { |
@@ -1,11 +0,22 @@ | ||
export type RulesType<R,P> = { | ||
[role in keyof R]: { | ||
[permission in keyof P]: { | ||
// export type RulesType<R,P> = { | ||
// [role in keyof R]: { | ||
// [permission in keyof P]: { | ||
// can?: boolean; | ||
// dynamic?: ValidatorFunctionType; | ||
// message?: string; | ||
// }; | ||
// }; | ||
// }; | ||
export type RulesType<R extends string, P extends string> = Record< | ||
R, | ||
Record< | ||
P, | ||
{ | ||
can?: boolean; | ||
dynamic?: ValidatorFunctionType; | ||
message?: string; | ||
}; | ||
}; | ||
}; | ||
} | ||
> | ||
>; | ||
export type ValidatorFunctionType<T = unknown> = ( | ||
@@ -12,0 +23,0 @@ // eslint-disable-next-line @typescript-eslint/no-explicit-any |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
26247
196
444