@unchainedshop/roles 4.8.4 → 5.0.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/roles.d.ts +3 -6
- package/lib/roles.js +70 -62
- package/lib/utils/permissions.d.ts +1 -1
- package/lib/utils/permissions.js +17 -18
- package/package.json +1 -1
package/lib/roles.d.ts
CHANGED
|
@@ -14,6 +14,7 @@ export interface RolesInterface {
|
|
|
14
14
|
roles: Record<string, RoleInterface>;
|
|
15
15
|
actions: string[];
|
|
16
16
|
helpers: string[];
|
|
17
|
+
addRole(role: RoleInterface): RoleInterface;
|
|
17
18
|
registerAction(name: string): void;
|
|
18
19
|
registerHelper(name: string): void;
|
|
19
20
|
getUserRoles(userId: string, roles: string[], includeSpecial: boolean): string[];
|
|
@@ -23,16 +24,11 @@ export interface RolesInterface {
|
|
|
23
24
|
loggedInRole?: RoleInterface;
|
|
24
25
|
allRole?: RoleInterface;
|
|
25
26
|
}
|
|
26
|
-
export interface RoleInterface {
|
|
27
|
-
name: string;
|
|
28
|
-
allowRules: Record<string, any>;
|
|
29
|
-
allow(action: string, fn: (root: any, props: any, context: RoleUserContext) => Promise<boolean>): void;
|
|
30
|
-
helpers: Record<string, unknown>;
|
|
31
|
-
}
|
|
32
27
|
export interface IRoleOptionConfig {
|
|
33
28
|
additionalRoles?: Record<string, (role: RolesInterface, actions: Record<string, string>) => void>;
|
|
34
29
|
additionalActions?: string[];
|
|
35
30
|
}
|
|
31
|
+
export declare function createRoles(): RolesInterface;
|
|
36
32
|
export declare const Roles: RolesInterface;
|
|
37
33
|
export declare class Role implements RoleInterface {
|
|
38
34
|
name: string;
|
|
@@ -42,4 +38,5 @@ export declare class Role implements RoleInterface {
|
|
|
42
38
|
helper(helper: string, func: any): void;
|
|
43
39
|
allow(action: any, allow: any): void;
|
|
44
40
|
}
|
|
41
|
+
export declare function initDefaultRoles(roles?: RolesInterface): void;
|
|
45
42
|
export {};
|
package/lib/roles.js
CHANGED
|
@@ -1,74 +1,81 @@
|
|
|
1
1
|
import { has } from "./utils/has.js";
|
|
2
2
|
import { isFunction } from "./utils/isFunction.js";
|
|
3
|
-
export
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
this.
|
|
10
|
-
|
|
11
|
-
},
|
|
12
|
-
registerHelper(name) {
|
|
13
|
-
if (!this.helpers.includes(name)) {
|
|
14
|
-
this.helpers.push(name);
|
|
15
|
-
}
|
|
16
|
-
},
|
|
17
|
-
getUserRoles(userId, roles, includeSpecial) {
|
|
18
|
-
const newRoles = [...(roles || [])];
|
|
19
|
-
if (includeSpecial) {
|
|
20
|
-
newRoles.push('__all__');
|
|
21
|
-
if (!userId) {
|
|
22
|
-
newRoles.push('__notLoggedIn__');
|
|
3
|
+
export function createRoles() {
|
|
4
|
+
const instance = {
|
|
5
|
+
roles: {},
|
|
6
|
+
actions: [],
|
|
7
|
+
helpers: [],
|
|
8
|
+
addRole(role) {
|
|
9
|
+
if (has(this.roles, role.name)) {
|
|
10
|
+
throw new Error(`"${role.name}" role is already defined`);
|
|
23
11
|
}
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
12
|
+
this.roles[role.name] = role;
|
|
13
|
+
return role;
|
|
14
|
+
},
|
|
15
|
+
registerAction(name) {
|
|
16
|
+
if (!this.actions.includes(name)) {
|
|
17
|
+
this.actions.push(name);
|
|
29
18
|
}
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
19
|
+
},
|
|
20
|
+
registerHelper(name) {
|
|
21
|
+
if (!this.helpers.includes(name)) {
|
|
22
|
+
this.helpers.push(name);
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
getUserRoles(userId, roles, includeSpecial) {
|
|
26
|
+
const newRoles = [...(roles || [])];
|
|
27
|
+
if (includeSpecial) {
|
|
28
|
+
newRoles.push('__all__');
|
|
29
|
+
if (!userId) {
|
|
30
|
+
newRoles.push('__notLoggedIn__');
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
newRoles.push('__loggedIn__');
|
|
34
|
+
if (!newRoles.includes('admin')) {
|
|
35
|
+
newRoles.push('__notAdmin__');
|
|
36
|
+
}
|
|
37
|
+
}
|
|
46
38
|
}
|
|
47
|
-
return
|
|
48
|
-
},
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
39
|
+
return newRoles;
|
|
40
|
+
},
|
|
41
|
+
async allow(context, roles, action, [obj, params]) {
|
|
42
|
+
const userRoles = instance.getUserRoles(context.userId, roles, true);
|
|
43
|
+
return userRoles.reduce(async (roleIsAllowedPromise, role) => {
|
|
44
|
+
const roleIsAllowed = await roleIsAllowedPromise;
|
|
45
|
+
if (roleIsAllowed)
|
|
46
|
+
return true;
|
|
47
|
+
if (instance.roles[role] &&
|
|
48
|
+
instance.roles[role].allowRules &&
|
|
49
|
+
instance.roles[role].allowRules[action]) {
|
|
50
|
+
return instance.roles[role].allowRules[action].reduce(async (rulesIsAllowedPromise, allowFn) => {
|
|
51
|
+
const ruleIsAllowed = await rulesIsAllowedPromise;
|
|
52
|
+
if (ruleIsAllowed)
|
|
53
|
+
return true;
|
|
54
|
+
return allowFn(obj, params, context);
|
|
55
|
+
}, Promise.resolve(false));
|
|
56
|
+
}
|
|
57
|
+
return roleIsAllowed;
|
|
58
|
+
}, Promise.resolve(false));
|
|
59
|
+
},
|
|
60
|
+
async userHasPermission(context, action, args) {
|
|
61
|
+
const roles = Array.isArray(context.user?.roles) ? context.user.roles : [];
|
|
62
|
+
const allows = await instance.allow(context, roles, action, args);
|
|
63
|
+
return allows === true;
|
|
64
|
+
},
|
|
65
|
+
};
|
|
66
|
+
return instance;
|
|
67
|
+
}
|
|
68
|
+
export const Roles = createRoles();
|
|
56
69
|
export class Role {
|
|
57
70
|
name;
|
|
58
71
|
allowRules;
|
|
59
72
|
helpers;
|
|
60
73
|
constructor(name) {
|
|
61
|
-
if (has(Roles.roles, name))
|
|
62
|
-
throw new Error(`"${name}" role is already defined`);
|
|
63
74
|
this.name = name;
|
|
64
75
|
this.allowRules = {};
|
|
65
76
|
this.helpers = {};
|
|
66
|
-
Roles.roles[name] = this;
|
|
67
77
|
}
|
|
68
78
|
helper(helper, func) {
|
|
69
|
-
if (!Roles.helpers.includes(helper)) {
|
|
70
|
-
Roles.registerHelper(helper);
|
|
71
|
-
}
|
|
72
79
|
let helperFn = func;
|
|
73
80
|
if (!isFunction(helperFn)) {
|
|
74
81
|
const clonedValue = structuredClone(helperFn);
|
|
@@ -85,9 +92,6 @@ export class Role {
|
|
|
85
92
|
if (!action) {
|
|
86
93
|
throw new Error(`Action doesn't exist`);
|
|
87
94
|
}
|
|
88
|
-
if (!Roles.actions.includes(action)) {
|
|
89
|
-
Roles.registerAction(action);
|
|
90
|
-
}
|
|
91
95
|
let allowFn = allow;
|
|
92
96
|
if (!isFunction(allowFn)) {
|
|
93
97
|
const clonedValue = structuredClone(allowFn);
|
|
@@ -99,6 +103,10 @@ export class Role {
|
|
|
99
103
|
this.allowRules[action].push(allowFn);
|
|
100
104
|
}
|
|
101
105
|
}
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
106
|
+
export function initDefaultRoles(roles = Roles) {
|
|
107
|
+
if (roles.adminRole)
|
|
108
|
+
return;
|
|
109
|
+
roles.adminRole = roles.addRole(new Role('admin'));
|
|
110
|
+
roles.loggedInRole = roles.addRole(new Role('__loggedIn__'));
|
|
111
|
+
roles.allRole = roles.addRole(new Role('__all__'));
|
|
112
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const permissions: (userRoles: any, allRoles: any) => Promise<string[]>;
|
|
1
|
+
export declare const permissions: (userRoles: any, allRoles: any) => Promise<(string | null)[]>;
|
package/lib/utils/permissions.js
CHANGED
|
@@ -1,30 +1,29 @@
|
|
|
1
1
|
export const permissions = async (userRoles, allRoles) => {
|
|
2
|
-
const
|
|
2
|
+
const roleMap = new Map();
|
|
3
3
|
for (const r of Object.values(allRoles)) {
|
|
4
|
-
|
|
5
|
-
rolesByName.set(r.name, r);
|
|
4
|
+
roleMap.set(r.name, r);
|
|
6
5
|
}
|
|
7
|
-
const
|
|
8
|
-
const seen = new Set();
|
|
6
|
+
const actions = [];
|
|
9
7
|
for (const role of userRoles || []) {
|
|
10
|
-
const foundRole =
|
|
8
|
+
const foundRole = roleMap.get(role);
|
|
11
9
|
if (!foundRole)
|
|
12
10
|
continue;
|
|
13
|
-
for (const [
|
|
14
|
-
if (seen.has(actionName))
|
|
15
|
-
continue;
|
|
11
|
+
for (const [roleName, funcs] of Object.entries(foundRole.allowRules || {})) {
|
|
16
12
|
for (const f of funcs) {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
13
|
+
actions.push((async () => {
|
|
14
|
+
try {
|
|
15
|
+
const r = await f(null, null, null);
|
|
16
|
+
if (r)
|
|
17
|
+
return roleName;
|
|
18
|
+
return null;
|
|
22
19
|
}
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
20
|
+
catch {
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
})());
|
|
26
24
|
}
|
|
27
25
|
}
|
|
28
26
|
}
|
|
29
|
-
|
|
27
|
+
const resolvedActions = await Promise.all(actions);
|
|
28
|
+
return [...new Set(resolvedActions)].filter(Boolean).toSorted((a, b) => a.localeCompare(b));
|
|
30
29
|
};
|