@ahmed109/gatekeeper-core 0.2.0 → 0.3.0
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/dist/index.cjs +47 -8
- package/dist/index.d.cts +18 -1
- package/dist/index.d.ts +18 -1
- package/dist/index.js +42 -7
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -25,15 +25,19 @@ __export(index_exports, {
|
|
|
25
25
|
canAll: () => canAll,
|
|
26
26
|
canAny: () => canAny,
|
|
27
27
|
createSubject: () => createSubject,
|
|
28
|
+
defineRoleHierarchy: () => defineRoleHierarchy,
|
|
28
29
|
defineRolePermissions: () => defineRolePermissions,
|
|
29
30
|
evaluatePermission: () => evaluatePermission,
|
|
31
|
+
explain: () => explain,
|
|
30
32
|
fromJwtClaims: () => fromJwtClaims,
|
|
31
33
|
fromPermissions: () => fromPermissions,
|
|
32
34
|
fromRoles: () => fromRoles,
|
|
33
35
|
getUserEffectivePermissions: () => getUserEffectivePermissions,
|
|
34
36
|
isFeatureEnabled: () => isFeatureEnabled,
|
|
35
37
|
normalizeFeatureFlags: () => normalizeFeatureFlags,
|
|
36
|
-
parseEvaluateOptions: () => parseEvaluateOptions
|
|
38
|
+
parseEvaluateOptions: () => parseEvaluateOptions,
|
|
39
|
+
permissionMatches: () => permissionMatches,
|
|
40
|
+
resolveInheritedRoles: () => resolveInheritedRoles
|
|
37
41
|
});
|
|
38
42
|
module.exports = __toCommonJS(index_exports);
|
|
39
43
|
|
|
@@ -55,13 +59,28 @@ function defineRolePermissions(customMap, baseMap = DEFAULT_ROLE_PERMISSIONS) {
|
|
|
55
59
|
}
|
|
56
60
|
return merged;
|
|
57
61
|
}
|
|
62
|
+
function defineRoleHierarchy(hierarchy) {
|
|
63
|
+
return Object.fromEntries(
|
|
64
|
+
Object.entries(hierarchy).map(([role, parents]) => [role, [...parents]])
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
function resolveInheritedRoles(roles, hierarchy) {
|
|
68
|
+
const resolved = /* @__PURE__ */ new Set();
|
|
69
|
+
const visit = (role) => {
|
|
70
|
+
if (resolved.has(role)) return;
|
|
71
|
+
resolved.add(role);
|
|
72
|
+
for (const parent of hierarchy?.[role] ?? []) visit(parent);
|
|
73
|
+
};
|
|
74
|
+
for (const role of roles) visit(role);
|
|
75
|
+
return [...resolved];
|
|
76
|
+
}
|
|
58
77
|
|
|
59
78
|
// src/evaluator.ts
|
|
60
79
|
function parseEvaluateOptions(options) {
|
|
61
80
|
if (!options || typeof options !== "object") {
|
|
62
81
|
return {};
|
|
63
82
|
}
|
|
64
|
-
if ("roleMap" in options || "context" in options || "policy" in options) {
|
|
83
|
+
if ("roleMap" in options || "roleHierarchy" in options || "context" in options || "policy" in options) {
|
|
65
84
|
return options;
|
|
66
85
|
}
|
|
67
86
|
const values = Object.values(options);
|
|
@@ -86,7 +105,7 @@ function getUserEffectivePermissions(subject, roleMapOrOptions) {
|
|
|
86
105
|
if (subject.role) {
|
|
87
106
|
rolesToEvaluate.add(subject.role);
|
|
88
107
|
}
|
|
89
|
-
for (const role of rolesToEvaluate) {
|
|
108
|
+
for (const role of resolveInheritedRoles(rolesToEvaluate, opts.roleHierarchy)) {
|
|
90
109
|
const rolePerms = roleMap[role];
|
|
91
110
|
if (rolePerms && Array.isArray(rolePerms)) {
|
|
92
111
|
for (const perm of rolePerms) {
|
|
@@ -101,6 +120,9 @@ function getUserEffectivePermissions(subject, roleMapOrOptions) {
|
|
|
101
120
|
}
|
|
102
121
|
return permissions;
|
|
103
122
|
}
|
|
123
|
+
function permissionMatches(granted, requested) {
|
|
124
|
+
return granted === requested || granted.endsWith(".*") && requested.startsWith(granted.slice(0, -1));
|
|
125
|
+
}
|
|
104
126
|
function can(subject, permission, options) {
|
|
105
127
|
if (!subject || !permission) {
|
|
106
128
|
return false;
|
|
@@ -113,7 +135,7 @@ function can(subject, permission, options) {
|
|
|
113
135
|
}
|
|
114
136
|
}
|
|
115
137
|
const effective = getUserEffectivePermissions(subject, options !== void 0 ? opts : void 0);
|
|
116
|
-
return effective.
|
|
138
|
+
return [...effective].some((granted) => permissionMatches(granted, permission));
|
|
117
139
|
}
|
|
118
140
|
function canAll(subject, permissions, options) {
|
|
119
141
|
if (!subject || !permissions.length) {
|
|
@@ -147,20 +169,33 @@ function evaluatePermission(subject, permission, options) {
|
|
|
147
169
|
}
|
|
148
170
|
}
|
|
149
171
|
const effective = getUserEffectivePermissions(subject, options !== void 0 ? opts : void 0);
|
|
150
|
-
const
|
|
172
|
+
const matchedPermission = [...effective].find((granted) => permissionMatches(granted, permission));
|
|
173
|
+
const allowed = matchedPermission !== void 0;
|
|
151
174
|
if (allowed) {
|
|
152
175
|
return {
|
|
153
176
|
allowed: true,
|
|
154
|
-
reason: "Permission granted."
|
|
177
|
+
reason: "Permission granted.",
|
|
178
|
+
matchedPermission,
|
|
179
|
+
source: subject.permissions?.includes(matchedPermission) ? "direct-permission" : "role-permission",
|
|
180
|
+
evaluatedRoles: resolveInheritedRoles(
|
|
181
|
+
[...subject.roles ?? [], ...subject.role ? [subject.role] : []],
|
|
182
|
+
opts.roleHierarchy
|
|
183
|
+
)
|
|
155
184
|
};
|
|
156
185
|
}
|
|
157
186
|
const roleDesc = subject.role ?? (subject.roles?.length ? subject.roles.join(", ") : "none");
|
|
158
187
|
return {
|
|
159
188
|
allowed: false,
|
|
160
189
|
reason: `User with role '${roleDesc}' lacks required permission '${permission}'.`,
|
|
161
|
-
missingPermissions: [permission]
|
|
190
|
+
missingPermissions: [permission],
|
|
191
|
+
source: "none",
|
|
192
|
+
evaluatedRoles: resolveInheritedRoles(
|
|
193
|
+
[...subject.roles ?? [], ...subject.role ? [subject.role] : []],
|
|
194
|
+
opts.roleHierarchy
|
|
195
|
+
)
|
|
162
196
|
};
|
|
163
197
|
}
|
|
198
|
+
var explain = evaluatePermission;
|
|
164
199
|
function normalizeFeatureFlags(flags) {
|
|
165
200
|
if (!flags) {
|
|
166
201
|
return {};
|
|
@@ -366,13 +401,17 @@ function createSubject(source, mapping) {
|
|
|
366
401
|
canAll,
|
|
367
402
|
canAny,
|
|
368
403
|
createSubject,
|
|
404
|
+
defineRoleHierarchy,
|
|
369
405
|
defineRolePermissions,
|
|
370
406
|
evaluatePermission,
|
|
407
|
+
explain,
|
|
371
408
|
fromJwtClaims,
|
|
372
409
|
fromPermissions,
|
|
373
410
|
fromRoles,
|
|
374
411
|
getUserEffectivePermissions,
|
|
375
412
|
isFeatureEnabled,
|
|
376
413
|
normalizeFeatureFlags,
|
|
377
|
-
parseEvaluateOptions
|
|
414
|
+
parseEvaluateOptions,
|
|
415
|
+
permissionMatches,
|
|
416
|
+
resolveInheritedRoles
|
|
378
417
|
});
|
package/dist/index.d.cts
CHANGED
|
@@ -45,6 +45,8 @@ type AuthorizationPolicy = (subject: AuthorizationSubject, permission: Permissio
|
|
|
45
45
|
*/
|
|
46
46
|
interface EvaluateOptions {
|
|
47
47
|
roleMap?: RolePermissionsMap;
|
|
48
|
+
/** A role can inherit permissions from one or more parent roles. */
|
|
49
|
+
roleHierarchy?: RoleHierarchy;
|
|
48
50
|
context?: Record<string, unknown>;
|
|
49
51
|
policy?: AuthorizationPolicy;
|
|
50
52
|
}
|
|
@@ -65,11 +67,18 @@ interface AuthorizationResult {
|
|
|
65
67
|
allowed: boolean;
|
|
66
68
|
reason?: string;
|
|
67
69
|
missingPermissions?: Permission[];
|
|
70
|
+
/** Roles considered after resolving inheritance. */
|
|
71
|
+
evaluatedRoles?: Role[];
|
|
72
|
+
/** How the decision was reached. */
|
|
73
|
+
source?: 'policy' | 'direct-permission' | 'role-permission' | 'none';
|
|
74
|
+
matchedPermission?: Permission;
|
|
68
75
|
}
|
|
69
76
|
/**
|
|
70
77
|
* Mapping from roles to their granted permissions.
|
|
71
78
|
*/
|
|
72
79
|
type RolePermissionsMap = Record<Role, readonly Permission[] | Permission[]>;
|
|
80
|
+
/** Maps a role to the roles whose permissions it inherits. */
|
|
81
|
+
type RoleHierarchy = Record<Role, readonly Role[] | Role[]>;
|
|
73
82
|
|
|
74
83
|
/**
|
|
75
84
|
* Default role-to-permissions map for Gatekeeper.
|
|
@@ -83,6 +92,10 @@ declare const DEFAULT_ROLE_PERMISSIONS: RolePermissionsMap;
|
|
|
83
92
|
* Creates a merged role-to-permissions map by extending or overriding the defaults.
|
|
84
93
|
*/
|
|
85
94
|
declare function defineRolePermissions(customMap?: Partial<RolePermissionsMap>, baseMap?: RolePermissionsMap): RolePermissionsMap;
|
|
95
|
+
/** Creates a defensive copy of role inheritance declarations. */
|
|
96
|
+
declare function defineRoleHierarchy(hierarchy: RoleHierarchy): RoleHierarchy;
|
|
97
|
+
/** Resolves all inherited roles safely, including cyclic declarations. */
|
|
98
|
+
declare function resolveInheritedRoles(roles: Iterable<Role>, hierarchy?: RoleHierarchy): Role[];
|
|
86
99
|
|
|
87
100
|
/**
|
|
88
101
|
* Normalizes either a legacy RolePermissionsMap or a modern EvaluateOptions object.
|
|
@@ -97,6 +110,8 @@ declare function parseEvaluateOptions(options?: RoleMapOrOptions): EvaluateOptio
|
|
|
97
110
|
* Deduplicates permissions and denies safely if no roles or permissions exist.
|
|
98
111
|
*/
|
|
99
112
|
declare function getUserEffectivePermissions(subject: AuthorizationSubject | null | undefined, roleMapOrOptions?: RoleMapOrOptions): Set<Permission>;
|
|
113
|
+
/** Supports exact permissions and namespace wildcards such as `billing.*`. */
|
|
114
|
+
declare function permissionMatches(granted: Permission, requested: Permission): boolean;
|
|
100
115
|
/**
|
|
101
116
|
* Evaluates whether a subject has a specific permission.
|
|
102
117
|
* Supports scoped policy checks and legacy roleMap options.
|
|
@@ -119,6 +134,8 @@ declare function canAny(subject: AuthorizationSubject | null | undefined, permis
|
|
|
119
134
|
* Evaluates access with detailed diagnostic reasons.
|
|
120
135
|
*/
|
|
121
136
|
declare function evaluatePermission(subject: AuthorizationSubject | null | undefined, permission: Permission, options?: RoleMapOrOptions): AuthorizationResult;
|
|
137
|
+
/** Alias for evaluatePermission, optimized for audit/debug UI naming. */
|
|
138
|
+
declare const explain: typeof evaluatePermission;
|
|
122
139
|
/**
|
|
123
140
|
* Normalizes feature flag inputs (either an array of FeatureFlag or a record of boolean flags)
|
|
124
141
|
* into a standard Record<string, boolean>.
|
|
@@ -239,4 +256,4 @@ interface SubjectMappingConfig<TSource> {
|
|
|
239
256
|
*/
|
|
240
257
|
declare function createSubject<TSource>(source: TSource, mapping: SubjectMappingConfig<TSource> | ((source: TSource) => AuthorizationSubject)): AuthorizationSubject;
|
|
241
258
|
|
|
242
|
-
export { type AuthorizationPolicy, type AuthorizationResult, type AuthorizationSubject, DEFAULT_ROLE_PERMISSIONS, type EvaluateOptions, type FeatureFlag, type FromPermissionsInput, type FromRolesInput, type GatekeeperUser, type JwtClaimsOptions, type Permission, type Role, type RoleMapOrOptions, type RolePermissionsMap, type StandardPermission, type StandardRole, type SubjectMappingConfig, can, canAll, canAny, createSubject, defineRolePermissions, evaluatePermission, fromJwtClaims, fromPermissions, fromRoles, getUserEffectivePermissions, isFeatureEnabled, normalizeFeatureFlags, parseEvaluateOptions };
|
|
259
|
+
export { type AuthorizationPolicy, type AuthorizationResult, type AuthorizationSubject, DEFAULT_ROLE_PERMISSIONS, type EvaluateOptions, type FeatureFlag, type FromPermissionsInput, type FromRolesInput, type GatekeeperUser, type JwtClaimsOptions, type Permission, type Role, type RoleHierarchy, type RoleMapOrOptions, type RolePermissionsMap, type StandardPermission, type StandardRole, type SubjectMappingConfig, can, canAll, canAny, createSubject, defineRoleHierarchy, defineRolePermissions, evaluatePermission, explain, fromJwtClaims, fromPermissions, fromRoles, getUserEffectivePermissions, isFeatureEnabled, normalizeFeatureFlags, parseEvaluateOptions, permissionMatches, resolveInheritedRoles };
|
package/dist/index.d.ts
CHANGED
|
@@ -45,6 +45,8 @@ type AuthorizationPolicy = (subject: AuthorizationSubject, permission: Permissio
|
|
|
45
45
|
*/
|
|
46
46
|
interface EvaluateOptions {
|
|
47
47
|
roleMap?: RolePermissionsMap;
|
|
48
|
+
/** A role can inherit permissions from one or more parent roles. */
|
|
49
|
+
roleHierarchy?: RoleHierarchy;
|
|
48
50
|
context?: Record<string, unknown>;
|
|
49
51
|
policy?: AuthorizationPolicy;
|
|
50
52
|
}
|
|
@@ -65,11 +67,18 @@ interface AuthorizationResult {
|
|
|
65
67
|
allowed: boolean;
|
|
66
68
|
reason?: string;
|
|
67
69
|
missingPermissions?: Permission[];
|
|
70
|
+
/** Roles considered after resolving inheritance. */
|
|
71
|
+
evaluatedRoles?: Role[];
|
|
72
|
+
/** How the decision was reached. */
|
|
73
|
+
source?: 'policy' | 'direct-permission' | 'role-permission' | 'none';
|
|
74
|
+
matchedPermission?: Permission;
|
|
68
75
|
}
|
|
69
76
|
/**
|
|
70
77
|
* Mapping from roles to their granted permissions.
|
|
71
78
|
*/
|
|
72
79
|
type RolePermissionsMap = Record<Role, readonly Permission[] | Permission[]>;
|
|
80
|
+
/** Maps a role to the roles whose permissions it inherits. */
|
|
81
|
+
type RoleHierarchy = Record<Role, readonly Role[] | Role[]>;
|
|
73
82
|
|
|
74
83
|
/**
|
|
75
84
|
* Default role-to-permissions map for Gatekeeper.
|
|
@@ -83,6 +92,10 @@ declare const DEFAULT_ROLE_PERMISSIONS: RolePermissionsMap;
|
|
|
83
92
|
* Creates a merged role-to-permissions map by extending or overriding the defaults.
|
|
84
93
|
*/
|
|
85
94
|
declare function defineRolePermissions(customMap?: Partial<RolePermissionsMap>, baseMap?: RolePermissionsMap): RolePermissionsMap;
|
|
95
|
+
/** Creates a defensive copy of role inheritance declarations. */
|
|
96
|
+
declare function defineRoleHierarchy(hierarchy: RoleHierarchy): RoleHierarchy;
|
|
97
|
+
/** Resolves all inherited roles safely, including cyclic declarations. */
|
|
98
|
+
declare function resolveInheritedRoles(roles: Iterable<Role>, hierarchy?: RoleHierarchy): Role[];
|
|
86
99
|
|
|
87
100
|
/**
|
|
88
101
|
* Normalizes either a legacy RolePermissionsMap or a modern EvaluateOptions object.
|
|
@@ -97,6 +110,8 @@ declare function parseEvaluateOptions(options?: RoleMapOrOptions): EvaluateOptio
|
|
|
97
110
|
* Deduplicates permissions and denies safely if no roles or permissions exist.
|
|
98
111
|
*/
|
|
99
112
|
declare function getUserEffectivePermissions(subject: AuthorizationSubject | null | undefined, roleMapOrOptions?: RoleMapOrOptions): Set<Permission>;
|
|
113
|
+
/** Supports exact permissions and namespace wildcards such as `billing.*`. */
|
|
114
|
+
declare function permissionMatches(granted: Permission, requested: Permission): boolean;
|
|
100
115
|
/**
|
|
101
116
|
* Evaluates whether a subject has a specific permission.
|
|
102
117
|
* Supports scoped policy checks and legacy roleMap options.
|
|
@@ -119,6 +134,8 @@ declare function canAny(subject: AuthorizationSubject | null | undefined, permis
|
|
|
119
134
|
* Evaluates access with detailed diagnostic reasons.
|
|
120
135
|
*/
|
|
121
136
|
declare function evaluatePermission(subject: AuthorizationSubject | null | undefined, permission: Permission, options?: RoleMapOrOptions): AuthorizationResult;
|
|
137
|
+
/** Alias for evaluatePermission, optimized for audit/debug UI naming. */
|
|
138
|
+
declare const explain: typeof evaluatePermission;
|
|
122
139
|
/**
|
|
123
140
|
* Normalizes feature flag inputs (either an array of FeatureFlag or a record of boolean flags)
|
|
124
141
|
* into a standard Record<string, boolean>.
|
|
@@ -239,4 +256,4 @@ interface SubjectMappingConfig<TSource> {
|
|
|
239
256
|
*/
|
|
240
257
|
declare function createSubject<TSource>(source: TSource, mapping: SubjectMappingConfig<TSource> | ((source: TSource) => AuthorizationSubject)): AuthorizationSubject;
|
|
241
258
|
|
|
242
|
-
export { type AuthorizationPolicy, type AuthorizationResult, type AuthorizationSubject, DEFAULT_ROLE_PERMISSIONS, type EvaluateOptions, type FeatureFlag, type FromPermissionsInput, type FromRolesInput, type GatekeeperUser, type JwtClaimsOptions, type Permission, type Role, type RoleMapOrOptions, type RolePermissionsMap, type StandardPermission, type StandardRole, type SubjectMappingConfig, can, canAll, canAny, createSubject, defineRolePermissions, evaluatePermission, fromJwtClaims, fromPermissions, fromRoles, getUserEffectivePermissions, isFeatureEnabled, normalizeFeatureFlags, parseEvaluateOptions };
|
|
259
|
+
export { type AuthorizationPolicy, type AuthorizationResult, type AuthorizationSubject, DEFAULT_ROLE_PERMISSIONS, type EvaluateOptions, type FeatureFlag, type FromPermissionsInput, type FromRolesInput, type GatekeeperUser, type JwtClaimsOptions, type Permission, type Role, type RoleHierarchy, type RoleMapOrOptions, type RolePermissionsMap, type StandardPermission, type StandardRole, type SubjectMappingConfig, can, canAll, canAny, createSubject, defineRoleHierarchy, defineRolePermissions, evaluatePermission, explain, fromJwtClaims, fromPermissions, fromRoles, getUserEffectivePermissions, isFeatureEnabled, normalizeFeatureFlags, parseEvaluateOptions, permissionMatches, resolveInheritedRoles };
|
package/dist/index.js
CHANGED
|
@@ -16,13 +16,28 @@ function defineRolePermissions(customMap, baseMap = DEFAULT_ROLE_PERMISSIONS) {
|
|
|
16
16
|
}
|
|
17
17
|
return merged;
|
|
18
18
|
}
|
|
19
|
+
function defineRoleHierarchy(hierarchy) {
|
|
20
|
+
return Object.fromEntries(
|
|
21
|
+
Object.entries(hierarchy).map(([role, parents]) => [role, [...parents]])
|
|
22
|
+
);
|
|
23
|
+
}
|
|
24
|
+
function resolveInheritedRoles(roles, hierarchy) {
|
|
25
|
+
const resolved = /* @__PURE__ */ new Set();
|
|
26
|
+
const visit = (role) => {
|
|
27
|
+
if (resolved.has(role)) return;
|
|
28
|
+
resolved.add(role);
|
|
29
|
+
for (const parent of hierarchy?.[role] ?? []) visit(parent);
|
|
30
|
+
};
|
|
31
|
+
for (const role of roles) visit(role);
|
|
32
|
+
return [...resolved];
|
|
33
|
+
}
|
|
19
34
|
|
|
20
35
|
// src/evaluator.ts
|
|
21
36
|
function parseEvaluateOptions(options) {
|
|
22
37
|
if (!options || typeof options !== "object") {
|
|
23
38
|
return {};
|
|
24
39
|
}
|
|
25
|
-
if ("roleMap" in options || "context" in options || "policy" in options) {
|
|
40
|
+
if ("roleMap" in options || "roleHierarchy" in options || "context" in options || "policy" in options) {
|
|
26
41
|
return options;
|
|
27
42
|
}
|
|
28
43
|
const values = Object.values(options);
|
|
@@ -47,7 +62,7 @@ function getUserEffectivePermissions(subject, roleMapOrOptions) {
|
|
|
47
62
|
if (subject.role) {
|
|
48
63
|
rolesToEvaluate.add(subject.role);
|
|
49
64
|
}
|
|
50
|
-
for (const role of rolesToEvaluate) {
|
|
65
|
+
for (const role of resolveInheritedRoles(rolesToEvaluate, opts.roleHierarchy)) {
|
|
51
66
|
const rolePerms = roleMap[role];
|
|
52
67
|
if (rolePerms && Array.isArray(rolePerms)) {
|
|
53
68
|
for (const perm of rolePerms) {
|
|
@@ -62,6 +77,9 @@ function getUserEffectivePermissions(subject, roleMapOrOptions) {
|
|
|
62
77
|
}
|
|
63
78
|
return permissions;
|
|
64
79
|
}
|
|
80
|
+
function permissionMatches(granted, requested) {
|
|
81
|
+
return granted === requested || granted.endsWith(".*") && requested.startsWith(granted.slice(0, -1));
|
|
82
|
+
}
|
|
65
83
|
function can(subject, permission, options) {
|
|
66
84
|
if (!subject || !permission) {
|
|
67
85
|
return false;
|
|
@@ -74,7 +92,7 @@ function can(subject, permission, options) {
|
|
|
74
92
|
}
|
|
75
93
|
}
|
|
76
94
|
const effective = getUserEffectivePermissions(subject, options !== void 0 ? opts : void 0);
|
|
77
|
-
return effective.
|
|
95
|
+
return [...effective].some((granted) => permissionMatches(granted, permission));
|
|
78
96
|
}
|
|
79
97
|
function canAll(subject, permissions, options) {
|
|
80
98
|
if (!subject || !permissions.length) {
|
|
@@ -108,20 +126,33 @@ function evaluatePermission(subject, permission, options) {
|
|
|
108
126
|
}
|
|
109
127
|
}
|
|
110
128
|
const effective = getUserEffectivePermissions(subject, options !== void 0 ? opts : void 0);
|
|
111
|
-
const
|
|
129
|
+
const matchedPermission = [...effective].find((granted) => permissionMatches(granted, permission));
|
|
130
|
+
const allowed = matchedPermission !== void 0;
|
|
112
131
|
if (allowed) {
|
|
113
132
|
return {
|
|
114
133
|
allowed: true,
|
|
115
|
-
reason: "Permission granted."
|
|
134
|
+
reason: "Permission granted.",
|
|
135
|
+
matchedPermission,
|
|
136
|
+
source: subject.permissions?.includes(matchedPermission) ? "direct-permission" : "role-permission",
|
|
137
|
+
evaluatedRoles: resolveInheritedRoles(
|
|
138
|
+
[...subject.roles ?? [], ...subject.role ? [subject.role] : []],
|
|
139
|
+
opts.roleHierarchy
|
|
140
|
+
)
|
|
116
141
|
};
|
|
117
142
|
}
|
|
118
143
|
const roleDesc = subject.role ?? (subject.roles?.length ? subject.roles.join(", ") : "none");
|
|
119
144
|
return {
|
|
120
145
|
allowed: false,
|
|
121
146
|
reason: `User with role '${roleDesc}' lacks required permission '${permission}'.`,
|
|
122
|
-
missingPermissions: [permission]
|
|
147
|
+
missingPermissions: [permission],
|
|
148
|
+
source: "none",
|
|
149
|
+
evaluatedRoles: resolveInheritedRoles(
|
|
150
|
+
[...subject.roles ?? [], ...subject.role ? [subject.role] : []],
|
|
151
|
+
opts.roleHierarchy
|
|
152
|
+
)
|
|
123
153
|
};
|
|
124
154
|
}
|
|
155
|
+
var explain = evaluatePermission;
|
|
125
156
|
function normalizeFeatureFlags(flags) {
|
|
126
157
|
if (!flags) {
|
|
127
158
|
return {};
|
|
@@ -326,13 +357,17 @@ export {
|
|
|
326
357
|
canAll,
|
|
327
358
|
canAny,
|
|
328
359
|
createSubject,
|
|
360
|
+
defineRoleHierarchy,
|
|
329
361
|
defineRolePermissions,
|
|
330
362
|
evaluatePermission,
|
|
363
|
+
explain,
|
|
331
364
|
fromJwtClaims,
|
|
332
365
|
fromPermissions,
|
|
333
366
|
fromRoles,
|
|
334
367
|
getUserEffectivePermissions,
|
|
335
368
|
isFeatureEnabled,
|
|
336
369
|
normalizeFeatureFlags,
|
|
337
|
-
parseEvaluateOptions
|
|
370
|
+
parseEvaluateOptions,
|
|
371
|
+
permissionMatches,
|
|
372
|
+
resolveInheritedRoles
|
|
338
373
|
};
|