@tmlmobilidade/go-types-permissions 20260828.1636.54
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/allow-all.d.ts +4 -0
- package/dist/allow-all.js +5 -0
- package/dist/catalog.d.ts +199 -0
- package/dist/catalog.js +349 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +5 -0
- package/dist/permissions.d.ts +397 -0
- package/dist/permissions.js +47 -0
- package/dist/registry.d.ts +192 -0
- package/dist/registry.js +47 -0
- package/dist/resources-registy.d.ts +16 -0
- package/dist/resources-registy.js +32 -0
- package/dist/scopes/agencies/actions.d.ts +3 -0
- package/dist/scopes/agencies/actions.js +11 -0
- package/dist/scopes/agencies/permission.d.ts +12 -0
- package/dist/scopes/agencies/permission.js +9 -0
- package/dist/scopes/agencies/registry.d.ts +12 -0
- package/dist/scopes/agencies/registry.js +9 -0
- package/dist/scopes/agencies/scope.d.ts +3 -0
- package/dist/scopes/agencies/scope.js +4 -0
- package/dist/scopes/alerts/actions.d.ts +3 -0
- package/dist/scopes/alerts/actions.js +14 -0
- package/dist/scopes/alerts/permission.d.ts +30 -0
- package/dist/scopes/alerts/permission.js +11 -0
- package/dist/scopes/alerts/registry.d.ts +12 -0
- package/dist/scopes/alerts/registry.js +9 -0
- package/dist/scopes/alerts/resources.d.ts +12 -0
- package/dist/scopes/alerts/resources.js +7 -0
- package/dist/scopes/alerts/scope.d.ts +3 -0
- package/dist/scopes/alerts/scope.js +4 -0
- package/dist/scopes/annotations/actions.d.ts +3 -0
- package/dist/scopes/annotations/actions.js +11 -0
- package/dist/scopes/annotations/permission.d.ts +25 -0
- package/dist/scopes/annotations/permission.js +11 -0
- package/dist/scopes/annotations/registry.d.ts +12 -0
- package/dist/scopes/annotations/registry.js +9 -0
- package/dist/scopes/annotations/resources.d.ts +9 -0
- package/dist/scopes/annotations/resources.js +6 -0
- package/dist/scopes/annotations/scope.d.ts +3 -0
- package/dist/scopes/annotations/scope.js +4 -0
- package/dist/scopes/events/actions.d.ts +3 -0
- package/dist/scopes/events/actions.js +11 -0
- package/dist/scopes/events/permission.d.ts +25 -0
- package/dist/scopes/events/permission.js +11 -0
- package/dist/scopes/events/registry.d.ts +12 -0
- package/dist/scopes/events/registry.js +9 -0
- package/dist/scopes/events/resources.d.ts +9 -0
- package/dist/scopes/events/resources.js +6 -0
- package/dist/scopes/events/scope.d.ts +3 -0
- package/dist/scopes/events/scope.js +4 -0
- package/dist/scopes/fares/actions.d.ts +3 -0
- package/dist/scopes/fares/actions.js +11 -0
- package/dist/scopes/fares/permission.d.ts +25 -0
- package/dist/scopes/fares/permission.js +11 -0
- package/dist/scopes/fares/registry.d.ts +12 -0
- package/dist/scopes/fares/registry.js +9 -0
- package/dist/scopes/fares/resources.d.ts +9 -0
- package/dist/scopes/fares/resources.js +6 -0
- package/dist/scopes/fares/scope.d.ts +3 -0
- package/dist/scopes/fares/scope.js +4 -0
- package/dist/scopes/gtfs-validations/actions.d.ts +3 -0
- package/dist/scopes/gtfs-validations/actions.js +11 -0
- package/dist/scopes/gtfs-validations/permission.d.ts +25 -0
- package/dist/scopes/gtfs-validations/permission.js +11 -0
- package/dist/scopes/gtfs-validations/registry.d.ts +12 -0
- package/dist/scopes/gtfs-validations/registry.js +9 -0
- package/dist/scopes/gtfs-validations/resources.d.ts +9 -0
- package/dist/scopes/gtfs-validations/resources.js +6 -0
- package/dist/scopes/gtfs-validations/scope.d.ts +3 -0
- package/dist/scopes/gtfs-validations/scope.js +4 -0
- package/dist/scopes/holidays/actions.d.ts +3 -0
- package/dist/scopes/holidays/actions.js +11 -0
- package/dist/scopes/holidays/permission.d.ts +25 -0
- package/dist/scopes/holidays/permission.js +11 -0
- package/dist/scopes/holidays/registry.d.ts +12 -0
- package/dist/scopes/holidays/registry.js +9 -0
- package/dist/scopes/holidays/resources.d.ts +9 -0
- package/dist/scopes/holidays/resources.js +6 -0
- package/dist/scopes/holidays/scope.d.ts +3 -0
- package/dist/scopes/holidays/scope.js +4 -0
- package/dist/scopes/home/actions.d.ts +3 -0
- package/dist/scopes/home/actions.js +8 -0
- package/dist/scopes/home/permission.d.ts +12 -0
- package/dist/scopes/home/permission.js +9 -0
- package/dist/scopes/home/registry.d.ts +12 -0
- package/dist/scopes/home/registry.js +9 -0
- package/dist/scopes/home/scope.d.ts +3 -0
- package/dist/scopes/home/scope.js +4 -0
- package/dist/scopes/lines/actions.d.ts +3 -0
- package/dist/scopes/lines/actions.js +11 -0
- package/dist/scopes/lines/permission.d.ts +25 -0
- package/dist/scopes/lines/permission.js +11 -0
- package/dist/scopes/lines/registry.d.ts +12 -0
- package/dist/scopes/lines/registry.js +9 -0
- package/dist/scopes/lines/resources.d.ts +9 -0
- package/dist/scopes/lines/resources.js +6 -0
- package/dist/scopes/lines/scope.d.ts +3 -0
- package/dist/scopes/lines/scope.js +4 -0
- package/dist/scopes/organizations/actions.d.ts +3 -0
- package/dist/scopes/organizations/actions.js +11 -0
- package/dist/scopes/organizations/permission.d.ts +12 -0
- package/dist/scopes/organizations/permission.js +9 -0
- package/dist/scopes/organizations/registry.d.ts +12 -0
- package/dist/scopes/organizations/registry.js +9 -0
- package/dist/scopes/organizations/scope.d.ts +3 -0
- package/dist/scopes/organizations/scope.js +4 -0
- package/dist/scopes/performance/actions.d.ts +3 -0
- package/dist/scopes/performance/actions.js +7 -0
- package/dist/scopes/performance/permission.d.ts +12 -0
- package/dist/scopes/performance/permission.js +9 -0
- package/dist/scopes/performance/registry.d.ts +12 -0
- package/dist/scopes/performance/registry.js +9 -0
- package/dist/scopes/performance/scope.d.ts +3 -0
- package/dist/scopes/performance/scope.js +4 -0
- package/dist/scopes/plans/actions.d.ts +3 -0
- package/dist/scopes/plans/actions.js +22 -0
- package/dist/scopes/plans/permission.d.ts +25 -0
- package/dist/scopes/plans/permission.js +11 -0
- package/dist/scopes/plans/registry.d.ts +12 -0
- package/dist/scopes/plans/registry.js +9 -0
- package/dist/scopes/plans/resources.d.ts +9 -0
- package/dist/scopes/plans/resources.js +6 -0
- package/dist/scopes/plans/scope.d.ts +3 -0
- package/dist/scopes/plans/scope.js +4 -0
- package/dist/scopes/rides/actions.d.ts +3 -0
- package/dist/scopes/rides/actions.js +19 -0
- package/dist/scopes/rides/permission.d.ts +25 -0
- package/dist/scopes/rides/permission.js +11 -0
- package/dist/scopes/rides/registry.d.ts +12 -0
- package/dist/scopes/rides/registry.js +9 -0
- package/dist/scopes/rides/resources.d.ts +9 -0
- package/dist/scopes/rides/resources.js +6 -0
- package/dist/scopes/rides/scope.d.ts +3 -0
- package/dist/scopes/rides/scope.js +4 -0
- package/dist/scopes/roles/actions.d.ts +3 -0
- package/dist/scopes/roles/actions.js +11 -0
- package/dist/scopes/roles/permission.d.ts +12 -0
- package/dist/scopes/roles/permission.js +9 -0
- package/dist/scopes/roles/registry.d.ts +12 -0
- package/dist/scopes/roles/registry.js +9 -0
- package/dist/scopes/roles/scope.d.ts +3 -0
- package/dist/scopes/roles/scope.js +4 -0
- package/dist/scopes/sams/actions.d.ts +3 -0
- package/dist/scopes/sams/actions.js +8 -0
- package/dist/scopes/sams/permission.d.ts +25 -0
- package/dist/scopes/sams/permission.js +11 -0
- package/dist/scopes/sams/registry.d.ts +12 -0
- package/dist/scopes/sams/registry.js +9 -0
- package/dist/scopes/sams/resources.d.ts +9 -0
- package/dist/scopes/sams/resources.js +6 -0
- package/dist/scopes/sams/scope.d.ts +3 -0
- package/dist/scopes/sams/scope.js +4 -0
- package/dist/scopes/stops/actions.d.ts +3 -0
- package/dist/scopes/stops/actions.js +14 -0
- package/dist/scopes/stops/permission.d.ts +30 -0
- package/dist/scopes/stops/permission.js +11 -0
- package/dist/scopes/stops/registry.d.ts +12 -0
- package/dist/scopes/stops/registry.js +9 -0
- package/dist/scopes/stops/resources.d.ts +12 -0
- package/dist/scopes/stops/resources.js +7 -0
- package/dist/scopes/stops/scope.d.ts +3 -0
- package/dist/scopes/stops/scope.js +4 -0
- package/dist/scopes/typologies/actions.d.ts +3 -0
- package/dist/scopes/typologies/actions.js +11 -0
- package/dist/scopes/typologies/permission.d.ts +25 -0
- package/dist/scopes/typologies/permission.js +11 -0
- package/dist/scopes/typologies/registry.d.ts +12 -0
- package/dist/scopes/typologies/registry.js +9 -0
- package/dist/scopes/typologies/resources.d.ts +9 -0
- package/dist/scopes/typologies/resources.js +6 -0
- package/dist/scopes/typologies/scope.d.ts +3 -0
- package/dist/scopes/typologies/scope.js +4 -0
- package/dist/scopes/users/actions.d.ts +3 -0
- package/dist/scopes/users/actions.js +11 -0
- package/dist/scopes/users/permission.d.ts +12 -0
- package/dist/scopes/users/permission.js +9 -0
- package/dist/scopes/users/registry.d.ts +12 -0
- package/dist/scopes/users/registry.js +9 -0
- package/dist/scopes/users/scope.d.ts +3 -0
- package/dist/scopes/users/scope.js +4 -0
- package/dist/scopes/vehicles/actions.d.ts +3 -0
- package/dist/scopes/vehicles/actions.js +11 -0
- package/dist/scopes/vehicles/permission.d.ts +25 -0
- package/dist/scopes/vehicles/permission.js +11 -0
- package/dist/scopes/vehicles/registry.d.ts +12 -0
- package/dist/scopes/vehicles/registry.js +9 -0
- package/dist/scopes/vehicles/resources.d.ts +9 -0
- package/dist/scopes/vehicles/resources.js +6 -0
- package/dist/scopes/vehicles/scope.d.ts +3 -0
- package/dist/scopes/vehicles/scope.js +4 -0
- package/dist/scopes/year-periods/actions.d.ts +3 -0
- package/dist/scopes/year-periods/actions.js +11 -0
- package/dist/scopes/year-periods/permission.d.ts +25 -0
- package/dist/scopes/year-periods/permission.js +11 -0
- package/dist/scopes/year-periods/registry.d.ts +12 -0
- package/dist/scopes/year-periods/registry.js +9 -0
- package/dist/scopes/year-periods/resources.d.ts +9 -0
- package/dist/scopes/year-periods/resources.js +6 -0
- package/dist/scopes/year-periods/scope.d.ts +3 -0
- package/dist/scopes/year-periods/scope.js +4 -0
- package/dist/scopes/zones/actions.d.ts +3 -0
- package/dist/scopes/zones/actions.js +11 -0
- package/dist/scopes/zones/permission.d.ts +25 -0
- package/dist/scopes/zones/permission.js +11 -0
- package/dist/scopes/zones/registry.d.ts +12 -0
- package/dist/scopes/zones/registry.js +9 -0
- package/dist/scopes/zones/resources.d.ts +9 -0
- package/dist/scopes/zones/resources.js +6 -0
- package/dist/scopes/zones/scope.d.ts +3 -0
- package/dist/scopes/zones/scope.js +4 -0
- package/dist/utils/has-permission-resource.d.ts +29 -0
- package/dist/utils/has-permission-resource.js +41 -0
- package/dist/utils/has-permission.d.ts +8 -0
- package/dist/utils/has-permission.js +20 -0
- package/dist/utils/index.d.ts +2 -0
- package/dist/utils/index.js +2 -0
- package/package.json +48 -0
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
import { Permission } from './permissions.js';
|
|
2
|
+
export type ActionsOf<S extends Permission['scope']> = Extract<Permission, {
|
|
3
|
+
scope: S;
|
|
4
|
+
}>['action'];
|
|
5
|
+
export type PermissionCatalogType = {
|
|
6
|
+
[S in Permission['scope']]: {
|
|
7
|
+
actions: {
|
|
8
|
+
[A in ActionsOf<S>]: A;
|
|
9
|
+
};
|
|
10
|
+
scope: S;
|
|
11
|
+
};
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* Arguments for hasPermissionResource function.
|
|
15
|
+
* @param T The type of the resource.
|
|
16
|
+
*/
|
|
17
|
+
export interface HasPermissionResourceArgs {
|
|
18
|
+
action: string;
|
|
19
|
+
permissions: Permission[];
|
|
20
|
+
resource_key: string;
|
|
21
|
+
scope: string;
|
|
22
|
+
value: unknown;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Arguments for filterPermissionResourceValues function.
|
|
26
|
+
* @param T The type of the resource.
|
|
27
|
+
*/
|
|
28
|
+
export interface FilterPermissionResourceValuesArgs<TValue = string> {
|
|
29
|
+
action: ActionsOf<Permission['scope']>;
|
|
30
|
+
permissions: Permission[];
|
|
31
|
+
resourceKey: string;
|
|
32
|
+
scope: Permission['scope'];
|
|
33
|
+
values: TValue[] | undefined;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* A scope/action pair used to collect resource access from one or more permissions.
|
|
37
|
+
*/
|
|
38
|
+
export interface PermissionResourceCheck<S extends Permission['scope'] = Permission['scope']> {
|
|
39
|
+
action: ActionsOf<S>;
|
|
40
|
+
scope: S;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Arguments for getPermissionResourceAccess function.
|
|
44
|
+
*/
|
|
45
|
+
export interface GetPermissionResourceAccessArgs {
|
|
46
|
+
checks: PermissionResourceCheck[];
|
|
47
|
+
permissions: Permission[];
|
|
48
|
+
resource_key: string;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Aggregated access to a permission resource key.
|
|
52
|
+
* When allowAll is true, callers should ignore values and treat the user
|
|
53
|
+
* as having access to every value for that resource key.
|
|
54
|
+
*/
|
|
55
|
+
export interface PermissionResourceAccess<TValue = string> {
|
|
56
|
+
allowAll: boolean;
|
|
57
|
+
values: TValue[];
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Arguments for getScopePermissions function.
|
|
61
|
+
*/
|
|
62
|
+
export interface GetScopePermissionsArgs<S extends Permission['scope']> {
|
|
63
|
+
actions: PermissionCatalogType[S]['actions'];
|
|
64
|
+
permissions: Permission[];
|
|
65
|
+
resource?: {
|
|
66
|
+
key: string;
|
|
67
|
+
requireAll?: boolean;
|
|
68
|
+
value: unknown;
|
|
69
|
+
};
|
|
70
|
+
scope: S;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Result object containing permission checks for a scope.
|
|
74
|
+
* Maps each action of the scope to a boolean indicating if the user has that permission.
|
|
75
|
+
*/
|
|
76
|
+
export type ScopePermissions<S extends Permission['scope']> = Record<ActionsOf<S>, boolean>;
|
|
77
|
+
/**
|
|
78
|
+
* PermissionCatalog provides a structured catalog of all available permissions
|
|
79
|
+
* in the system, categorized by scope and their respective actions.
|
|
80
|
+
* Use it to reference required permissions in components and services.
|
|
81
|
+
*/
|
|
82
|
+
export declare class PermissionCatalog {
|
|
83
|
+
static readonly ALLOW_ALL_FLAG = "allow_all";
|
|
84
|
+
/**
|
|
85
|
+
* Generates the complete permission catalog by extracting
|
|
86
|
+
* scopes and actions from the defined PermissionSchema.
|
|
87
|
+
* @return A catalog object mapping scopes to their actions.
|
|
88
|
+
*/
|
|
89
|
+
static get all(): PermissionCatalogType;
|
|
90
|
+
/**
|
|
91
|
+
* Get a specific permission from a full list by scope and action.
|
|
92
|
+
* @param permissionEntries The full list of permissions of the user.
|
|
93
|
+
* @param scope The resource scope of the permission to filter by.
|
|
94
|
+
* @param action The action of the permission to filter by.
|
|
95
|
+
* @returns The filtered Permission object or undefined if not found.
|
|
96
|
+
*/
|
|
97
|
+
static get<S extends Permission['scope']>(permissionEntries: Permission[], scope: S, action: ActionsOf<S>): Extract<Permission, {
|
|
98
|
+
action: ActionsOf<S>;
|
|
99
|
+
scope: S;
|
|
100
|
+
}> | undefined;
|
|
101
|
+
/**
|
|
102
|
+
* Get all permissions for a given scope and set of actions in one call.
|
|
103
|
+
* More efficient than calling hasPermission or hasPermissionResource multiple times.
|
|
104
|
+
* @param args Arguments object containing permissions, scope, actions, and optional resource.
|
|
105
|
+
* @param args.resource.requireAll If true, uses hasPermissionResourceAll (user must have permission for ALL values in array). If false/undefined, uses hasPermissionResource (user needs permission for ANY value).
|
|
106
|
+
* @returns Object with boolean values for each action in the scope.
|
|
107
|
+
*/
|
|
108
|
+
static getScopePermissions<S extends Permission['scope']>({ actions, permissions, resource, scope }: GetScopePermissionsArgs<S>): ScopePermissions<S>;
|
|
109
|
+
/**
|
|
110
|
+
* Check if a list of permission entries has the requested scope/action pair.
|
|
111
|
+
* @param permissionEntries The list of permission entries to check against.
|
|
112
|
+
* @param scope The required scope to check.
|
|
113
|
+
* @param action The required action to check.
|
|
114
|
+
* @returns The permission object or undefined if not found.
|
|
115
|
+
*/
|
|
116
|
+
static hasPermission<S extends Permission['scope']>(permissionEntries: Permission[], scope: S, action: ActionsOf<S>): boolean;
|
|
117
|
+
/**
|
|
118
|
+
* Collect allowed values for a resource key across multiple scope/action checks.
|
|
119
|
+
*
|
|
120
|
+
* Use this when a caller needs to build a database filter before loading
|
|
121
|
+
* documents. For example, a list endpoint can combine `lines.read`,
|
|
122
|
+
* `lines.update`, and `zones.nav` permissions into a single set of
|
|
123
|
+
* allowed `agency_ids`, then query MongoDB with `{ agency_ids: { $in: values } }`.
|
|
124
|
+
*
|
|
125
|
+
* This complements `hasPermissionResource`: that method answers whether
|
|
126
|
+
* a user can access a known resource value, while this method answers which
|
|
127
|
+
* resource values the user can access for a set of allowed permissions.
|
|
128
|
+
*
|
|
129
|
+
* If any matching permission contains PermissionCatalog.ALLOW_ALL_FLAG for
|
|
130
|
+
* the resource key, this returns `{ allowAll: true, values: [] }`.
|
|
131
|
+
*
|
|
132
|
+
* @param permissions The list of permissions from a user or request.
|
|
133
|
+
* @param checks The scope/action pairs whose resource values should be merged.
|
|
134
|
+
* @param resource_key The permission resource key to collect, e.g. `agency_ids`.
|
|
135
|
+
* @returns The aggregated resource access for the requested checks.
|
|
136
|
+
*/
|
|
137
|
+
static getPermissionResourceAccess<TValue = string>(args: GetPermissionResourceAccessArgs): PermissionResourceAccess<TValue>;
|
|
138
|
+
/**
|
|
139
|
+
* Check if a permission exists in a list of permissions, with additional check for a given resource value.
|
|
140
|
+
* If a `value` exists in a `resource` of a User `permissions` object that
|
|
141
|
+
* matches the given `action` and `scope`. For example, if you want to check if
|
|
142
|
+
* a user has access to a specific `agency_id`, you set `value=43` and `resource_key='agency_ids'`.
|
|
143
|
+
* If the provided `permissions` object contains the value `43` inside the `scope='plans'`,
|
|
144
|
+
* `action='create'` and `resource_key='agency_ids'` the function will return true.
|
|
145
|
+
* @param permissions The list of permissions (from a user or request).
|
|
146
|
+
* @param value The permission value to check against.
|
|
147
|
+
* @param resource_key The key of the resource.
|
|
148
|
+
* @param scope The scope of the permission.
|
|
149
|
+
* @param action The action of the permission.
|
|
150
|
+
* @returns The permission.
|
|
151
|
+
*/
|
|
152
|
+
static hasPermissionResource({ action, permissions, resource_key, scope, value }: HasPermissionResourceArgs): boolean;
|
|
153
|
+
/**
|
|
154
|
+
* Checks whether the user has permission to perform a specific action
|
|
155
|
+
* within a specific scope for ALL values in an array.
|
|
156
|
+
* This is stricter than `hasPermissionResource` which only requires permission for ANY value.
|
|
157
|
+
* Use this for operations like update/delete where the user must have permission for all agencies involved.
|
|
158
|
+
* @param permissions The list of permissions (from a user or request).
|
|
159
|
+
* @param value The permission value(s) to check against - if array, ALL values must be permitted.
|
|
160
|
+
* @param resource_key The key of the resource.
|
|
161
|
+
* @param scope The scope of the permission.
|
|
162
|
+
* @param action The action of the permission.
|
|
163
|
+
* @returns True if user has permission for ALL values, false otherwise.
|
|
164
|
+
*/
|
|
165
|
+
static hasPermissionResourceAll({ action, permissions, resource_key, scope, value }: HasPermissionResourceArgs): boolean;
|
|
166
|
+
/**
|
|
167
|
+
* Sanitizes a list of permissions by removing any entries
|
|
168
|
+
* that do not correspond to valid scopes and actions
|
|
169
|
+
* defined in the PermissionCatalog.
|
|
170
|
+
* @param existingEntries Array of Permission objects to sanitize.
|
|
171
|
+
* @return A cleaned array containing only valid permissions.
|
|
172
|
+
*/
|
|
173
|
+
static sanitize(existingEntries: Permission[]): Permission[];
|
|
174
|
+
/**
|
|
175
|
+
* Sanitizes a list of permissions by removing any entries
|
|
176
|
+
* that do not correspond to valid scopes and actions
|
|
177
|
+
* defined in the PermissionCatalog.
|
|
178
|
+
* @param existingEntries Array of Permission objects to sanitize.
|
|
179
|
+
* @return A cleaned array containing only valid permissions.
|
|
180
|
+
*/
|
|
181
|
+
static updatePermissionResource<S extends Permission['scope']>(permissionEntries: Permission[], scope: S, action: ActionsOf<S>, resources: Record<string, unknown>): Permission[];
|
|
182
|
+
/**
|
|
183
|
+
* Filters requested resource values to only those the user is permitted to access.
|
|
184
|
+
*
|
|
185
|
+
* Unlike `hasPermissionResource`, which answers whether access should be granted,
|
|
186
|
+
* this method returns the subset of requested values that are actually permitted.
|
|
187
|
+
*
|
|
188
|
+
* An empty `values` array means no resource filter was requested, so all values
|
|
189
|
+
* are returned unchanged.
|
|
190
|
+
*
|
|
191
|
+
* @param permissions The list of permissions from a user or request.
|
|
192
|
+
* @param scope The scope of the permission.
|
|
193
|
+
* @param action The action of the permission.
|
|
194
|
+
* @param resource_key The resource key containing the allowed values.
|
|
195
|
+
* @param values The resource values requested by the caller.
|
|
196
|
+
* @returns Only the requested values that the user is permitted to access.
|
|
197
|
+
*/
|
|
198
|
+
static filterPermissionResourceValues<TValue = string>({ action, permissions, resourceKey, scope, values }: FilterPermissionResourceValuesArgs<TValue>): TValue[];
|
|
199
|
+
}
|
package/dist/catalog.js
ADDED
|
@@ -0,0 +1,349 @@
|
|
|
1
|
+
/* * */
|
|
2
|
+
import { PermissionSchema } from './permissions.js';
|
|
3
|
+
/**
|
|
4
|
+
* PermissionCatalog provides a structured catalog of all available permissions
|
|
5
|
+
* in the system, categorized by scope and their respective actions.
|
|
6
|
+
* Use it to reference required permissions in components and services.
|
|
7
|
+
*/
|
|
8
|
+
export class PermissionCatalog {
|
|
9
|
+
//
|
|
10
|
+
static ALLOW_ALL_FLAG = 'allow_all';
|
|
11
|
+
/**
|
|
12
|
+
* Generates the complete permission catalog by extracting
|
|
13
|
+
* scopes and actions from the defined PermissionSchema.
|
|
14
|
+
* @return A catalog object mapping scopes to their actions.
|
|
15
|
+
*/
|
|
16
|
+
static get all() {
|
|
17
|
+
// Initialize catalog object
|
|
18
|
+
const catalog = {};
|
|
19
|
+
// Iterate over each schema option
|
|
20
|
+
for (const schemaOption of PermissionSchema.options) {
|
|
21
|
+
// Extract scope name and actions
|
|
22
|
+
const scopeName = schemaOption.shape.scope.value;
|
|
23
|
+
const actions = schemaOption.shape.action.options;
|
|
24
|
+
// Build catalog entry
|
|
25
|
+
catalog[scopeName] = {
|
|
26
|
+
actions: Object.fromEntries(actions.map((a) => [a, a])),
|
|
27
|
+
scope: scopeName,
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
// Return the completed catalog
|
|
31
|
+
return catalog;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Get a specific permission from a full list by scope and action.
|
|
35
|
+
* @param permissionEntries The full list of permissions of the user.
|
|
36
|
+
* @param scope The resource scope of the permission to filter by.
|
|
37
|
+
* @param action The action of the permission to filter by.
|
|
38
|
+
* @returns The filtered Permission object or undefined if not found.
|
|
39
|
+
*/
|
|
40
|
+
static get(permissionEntries, scope, action) {
|
|
41
|
+
return permissionEntries.find((p) => p.scope === scope && p.action === action);
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Get all permissions for a given scope and set of actions in one call.
|
|
45
|
+
* More efficient than calling hasPermission or hasPermissionResource multiple times.
|
|
46
|
+
* @param args Arguments object containing permissions, scope, actions, and optional resource.
|
|
47
|
+
* @param args.resource.requireAll If true, uses hasPermissionResourceAll (user must have permission for ALL values in array). If false/undefined, uses hasPermissionResource (user needs permission for ANY value).
|
|
48
|
+
* @returns Object with boolean values for each action in the scope.
|
|
49
|
+
*/
|
|
50
|
+
static getScopePermissions({ actions, permissions, resource, scope }) {
|
|
51
|
+
if (!permissions) {
|
|
52
|
+
return Object.keys(actions).reduce((acc, key) => ({ ...acc, [key]: false }), {});
|
|
53
|
+
}
|
|
54
|
+
const result = {};
|
|
55
|
+
for (const [key, action] of Object.entries(actions)) {
|
|
56
|
+
if (!action || typeof action !== 'string') {
|
|
57
|
+
result[key] = false;
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
if (resource) {
|
|
61
|
+
// Use hasPermissionResourceAll if requireAll is true, otherwise use hasPermissionResource
|
|
62
|
+
if (resource.requireAll) {
|
|
63
|
+
result[key] = this.hasPermissionResourceAll({
|
|
64
|
+
action,
|
|
65
|
+
permissions,
|
|
66
|
+
resource_key: resource.key,
|
|
67
|
+
scope,
|
|
68
|
+
value: resource.value,
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
result[key] = this.hasPermissionResource({
|
|
73
|
+
action,
|
|
74
|
+
permissions,
|
|
75
|
+
resource_key: resource.key,
|
|
76
|
+
scope,
|
|
77
|
+
value: resource.value,
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
result[key] = this.hasPermission(permissions, scope, action);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return result;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Check if a list of permission entries has the requested scope/action pair.
|
|
89
|
+
* @param permissionEntries The list of permission entries to check against.
|
|
90
|
+
* @param scope The required scope to check.
|
|
91
|
+
* @param action The required action to check.
|
|
92
|
+
* @returns The permission object or undefined if not found.
|
|
93
|
+
*/
|
|
94
|
+
static hasPermission(permissionEntries, scope, action) {
|
|
95
|
+
return permissionEntries.find(p => p.scope === scope && p.action === action) !== undefined;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Collect allowed values for a resource key across multiple scope/action checks.
|
|
99
|
+
*
|
|
100
|
+
* Use this when a caller needs to build a database filter before loading
|
|
101
|
+
* documents. For example, a list endpoint can combine `lines.read`,
|
|
102
|
+
* `lines.update`, and `zones.nav` permissions into a single set of
|
|
103
|
+
* allowed `agency_ids`, then query MongoDB with `{ agency_ids: { $in: values } }`.
|
|
104
|
+
*
|
|
105
|
+
* This complements `hasPermissionResource`: that method answers whether
|
|
106
|
+
* a user can access a known resource value, while this method answers which
|
|
107
|
+
* resource values the user can access for a set of allowed permissions.
|
|
108
|
+
*
|
|
109
|
+
* If any matching permission contains PermissionCatalog.ALLOW_ALL_FLAG for
|
|
110
|
+
* the resource key, this returns `{ allowAll: true, values: [] }`.
|
|
111
|
+
*
|
|
112
|
+
* @param permissions The list of permissions from a user or request.
|
|
113
|
+
* @param checks The scope/action pairs whose resource values should be merged.
|
|
114
|
+
* @param resource_key The permission resource key to collect, e.g. `agency_ids`.
|
|
115
|
+
* @returns The aggregated resource access for the requested checks.
|
|
116
|
+
*/
|
|
117
|
+
static getPermissionResourceAccess(args) {
|
|
118
|
+
//
|
|
119
|
+
if (!args.permissions?.length || !args.checks.length) {
|
|
120
|
+
return { allowAll: false, values: [] };
|
|
121
|
+
}
|
|
122
|
+
const values = new Set();
|
|
123
|
+
for (const check of args.checks) {
|
|
124
|
+
const matchingPermissions = args.permissions.filter(permission => permission.scope === check.scope && permission.action === check.action);
|
|
125
|
+
for (const permission of matchingPermissions) {
|
|
126
|
+
const resourceValues = permission['resources']?.[args.resource_key];
|
|
127
|
+
if (!resourceValues)
|
|
128
|
+
continue;
|
|
129
|
+
if (Array.isArray(resourceValues)) {
|
|
130
|
+
if (resourceValues.includes(this.ALLOW_ALL_FLAG)) {
|
|
131
|
+
return { allowAll: true, values: [] };
|
|
132
|
+
}
|
|
133
|
+
for (const resourceValue of resourceValues) {
|
|
134
|
+
values.add(resourceValue);
|
|
135
|
+
}
|
|
136
|
+
continue;
|
|
137
|
+
}
|
|
138
|
+
if (resourceValues === this.ALLOW_ALL_FLAG) {
|
|
139
|
+
return { allowAll: true, values: [] };
|
|
140
|
+
}
|
|
141
|
+
values.add(resourceValues);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
return {
|
|
145
|
+
allowAll: false,
|
|
146
|
+
values: [...values],
|
|
147
|
+
};
|
|
148
|
+
//
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Check if a permission exists in a list of permissions, with additional check for a given resource value.
|
|
152
|
+
* If a `value` exists in a `resource` of a User `permissions` object that
|
|
153
|
+
* matches the given `action` and `scope`. For example, if you want to check if
|
|
154
|
+
* a user has access to a specific `agency_id`, you set `value=43` and `resource_key='agency_ids'`.
|
|
155
|
+
* If the provided `permissions` object contains the value `43` inside the `scope='plans'`,
|
|
156
|
+
* `action='create'` and `resource_key='agency_ids'` the function will return true.
|
|
157
|
+
* @param permissions The list of permissions (from a user or request).
|
|
158
|
+
* @param value The permission value to check against.
|
|
159
|
+
* @param resource_key The key of the resource.
|
|
160
|
+
* @param scope The scope of the permission.
|
|
161
|
+
* @param action The action of the permission.
|
|
162
|
+
* @returns The permission.
|
|
163
|
+
*/
|
|
164
|
+
static hasPermissionResource({ action, permissions, resource_key, scope, value }) {
|
|
165
|
+
//
|
|
166
|
+
//
|
|
167
|
+
// Return false if no permissions
|
|
168
|
+
if (!permissions)
|
|
169
|
+
return false;
|
|
170
|
+
//
|
|
171
|
+
// Find the permission with the given action and scope
|
|
172
|
+
const foundPermission = permissions.find(p => p.action === action && p.scope === scope);
|
|
173
|
+
if (!foundPermission)
|
|
174
|
+
return false;
|
|
175
|
+
//
|
|
176
|
+
// Check if value exists in the permission.resources[resource_key]
|
|
177
|
+
const resourceValues = foundPermission['resources']?.[resource_key];
|
|
178
|
+
if (!resourceValues)
|
|
179
|
+
return false;
|
|
180
|
+
//
|
|
181
|
+
// If resourceValues is an Array, check if value is in the array
|
|
182
|
+
// or if it contains the ALLOW_ALL_FLAG.
|
|
183
|
+
if (Array.isArray(resourceValues) && resourceValues.includes(this.ALLOW_ALL_FLAG))
|
|
184
|
+
return true;
|
|
185
|
+
//
|
|
186
|
+
// If value is an array, check if there's any overlap between value and resourceValues
|
|
187
|
+
if (Array.isArray(value)) {
|
|
188
|
+
if (Array.isArray(resourceValues)) {
|
|
189
|
+
return value.some(v => resourceValues.includes(v));
|
|
190
|
+
}
|
|
191
|
+
return value.includes(resourceValues);
|
|
192
|
+
}
|
|
193
|
+
//
|
|
194
|
+
// If value is not an array, check if it's in resourceValues
|
|
195
|
+
if (Array.isArray(resourceValues) && resourceValues.includes(value))
|
|
196
|
+
return true;
|
|
197
|
+
//
|
|
198
|
+
// If resourceValues is not an Array, check if it is equal to the requested value
|
|
199
|
+
if (resourceValues === value)
|
|
200
|
+
return true;
|
|
201
|
+
//
|
|
202
|
+
// Otherwise, return false
|
|
203
|
+
return false;
|
|
204
|
+
//
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* Checks whether the user has permission to perform a specific action
|
|
208
|
+
* within a specific scope for ALL values in an array.
|
|
209
|
+
* This is stricter than `hasPermissionResource` which only requires permission for ANY value.
|
|
210
|
+
* Use this for operations like update/delete where the user must have permission for all agencies involved.
|
|
211
|
+
* @param permissions The list of permissions (from a user or request).
|
|
212
|
+
* @param value The permission value(s) to check against - if array, ALL values must be permitted.
|
|
213
|
+
* @param resource_key The key of the resource.
|
|
214
|
+
* @param scope The scope of the permission.
|
|
215
|
+
* @param action The action of the permission.
|
|
216
|
+
* @returns True if user has permission for ALL values, false otherwise.
|
|
217
|
+
*/
|
|
218
|
+
static hasPermissionResourceAll({ action, permissions, resource_key, scope, value }) {
|
|
219
|
+
//
|
|
220
|
+
//
|
|
221
|
+
// Return false if no permissions
|
|
222
|
+
if (!permissions)
|
|
223
|
+
return false;
|
|
224
|
+
//
|
|
225
|
+
// Find the permission with the given action and scope
|
|
226
|
+
const foundPermission = permissions.find(p => p.action === action && p.scope === scope);
|
|
227
|
+
if (!foundPermission)
|
|
228
|
+
return false;
|
|
229
|
+
//
|
|
230
|
+
// Check if value exists in the permission.resources[resource_key]
|
|
231
|
+
const resourceValues = foundPermission['resources']?.[resource_key];
|
|
232
|
+
if (!resourceValues)
|
|
233
|
+
return false;
|
|
234
|
+
//
|
|
235
|
+
// If resourceValues contains the ALLOW_ALL_FLAG, user has permission for everything
|
|
236
|
+
if (Array.isArray(resourceValues) && resourceValues.includes(this.ALLOW_ALL_FLAG))
|
|
237
|
+
return true;
|
|
238
|
+
//
|
|
239
|
+
// If value is an array, check if ALL elements are in resourceValues
|
|
240
|
+
if (Array.isArray(value)) {
|
|
241
|
+
if (Array.isArray(resourceValues)) {
|
|
242
|
+
return value.every(v => resourceValues.includes(v));
|
|
243
|
+
}
|
|
244
|
+
return value.every(v => v === resourceValues);
|
|
245
|
+
}
|
|
246
|
+
//
|
|
247
|
+
// If value is not an array, check if it's in resourceValues
|
|
248
|
+
if (Array.isArray(resourceValues) && resourceValues.includes(value))
|
|
249
|
+
return true;
|
|
250
|
+
//
|
|
251
|
+
// If resourceValues is not an Array, check if it is equal to the requested value
|
|
252
|
+
if (resourceValues === value)
|
|
253
|
+
return true;
|
|
254
|
+
//
|
|
255
|
+
// Otherwise, return false
|
|
256
|
+
return false;
|
|
257
|
+
//
|
|
258
|
+
}
|
|
259
|
+
/**
|
|
260
|
+
* Sanitizes a list of permissions by removing any entries
|
|
261
|
+
* that do not correspond to valid scopes and actions
|
|
262
|
+
* defined in the PermissionCatalog.
|
|
263
|
+
* @param existingEntries Array of Permission objects to sanitize.
|
|
264
|
+
* @return A cleaned array containing only valid permissions.
|
|
265
|
+
*/
|
|
266
|
+
static sanitize(existingEntries) {
|
|
267
|
+
// Create a new array to hold valid permissions
|
|
268
|
+
const cleanedPermissions = {};
|
|
269
|
+
// Iterate through each permission entry of the user
|
|
270
|
+
for (const permissionEntry of existingEntries) {
|
|
271
|
+
// Validate the permission entry
|
|
272
|
+
const validationResult = PermissionSchema.safeParse(permissionEntry);
|
|
273
|
+
if (!validationResult.success)
|
|
274
|
+
continue;
|
|
275
|
+
// Permission is valid; keep it
|
|
276
|
+
cleanedPermissions[`${permissionEntry.scope}:${permissionEntry.action}`] = permissionEntry;
|
|
277
|
+
}
|
|
278
|
+
// Return the cleaned permissions array
|
|
279
|
+
return Object.values(cleanedPermissions);
|
|
280
|
+
}
|
|
281
|
+
/**
|
|
282
|
+
* Sanitizes a list of permissions by removing any entries
|
|
283
|
+
* that do not correspond to valid scopes and actions
|
|
284
|
+
* defined in the PermissionCatalog.
|
|
285
|
+
* @param existingEntries Array of Permission objects to sanitize.
|
|
286
|
+
* @return A cleaned array containing only valid permissions.
|
|
287
|
+
*/
|
|
288
|
+
static updatePermissionResource(permissionEntries, scope, action, resources) {
|
|
289
|
+
// Create a copy of the existing permissions
|
|
290
|
+
const updatedPermissions = JSON.parse(JSON.stringify(permissionEntries));
|
|
291
|
+
// Find the index of the permission to update
|
|
292
|
+
const permissionIndex = updatedPermissions.findIndex(p => p.scope === scope && p.action === action);
|
|
293
|
+
if (permissionIndex === -1)
|
|
294
|
+
return updatedPermissions;
|
|
295
|
+
// Update the permission at the found index
|
|
296
|
+
updatedPermissions[permissionIndex]['resources'] = { ...updatedPermissions[permissionIndex]['resources'], ...resources };
|
|
297
|
+
// Return the updated permissions array
|
|
298
|
+
return updatedPermissions;
|
|
299
|
+
}
|
|
300
|
+
//
|
|
301
|
+
/**
|
|
302
|
+
* Filters requested resource values to only those the user is permitted to access.
|
|
303
|
+
*
|
|
304
|
+
* Unlike `hasPermissionResource`, which answers whether access should be granted,
|
|
305
|
+
* this method returns the subset of requested values that are actually permitted.
|
|
306
|
+
*
|
|
307
|
+
* An empty `values` array means no resource filter was requested, so all values
|
|
308
|
+
* are returned unchanged.
|
|
309
|
+
*
|
|
310
|
+
* @param permissions The list of permissions from a user or request.
|
|
311
|
+
* @param scope The scope of the permission.
|
|
312
|
+
* @param action The action of the permission.
|
|
313
|
+
* @param resource_key The resource key containing the allowed values.
|
|
314
|
+
* @param values The resource values requested by the caller.
|
|
315
|
+
* @returns Only the requested values that the user is permitted to access.
|
|
316
|
+
*/
|
|
317
|
+
static filterPermissionResourceValues({ action, permissions, resourceKey, scope, values }) {
|
|
318
|
+
// No filter was requested, so preserve the original values.
|
|
319
|
+
if (!values || values.length === 0)
|
|
320
|
+
return values ?? [];
|
|
321
|
+
if (!permissions?.length)
|
|
322
|
+
return [];
|
|
323
|
+
const allowedValues = new Set();
|
|
324
|
+
// Collect resource values from every matching permission.
|
|
325
|
+
for (const permission of permissions) {
|
|
326
|
+
if (permission.scope !== scope || permission.action !== action) {
|
|
327
|
+
continue;
|
|
328
|
+
}
|
|
329
|
+
const resourceValues = permission['resources']?.[resourceKey];
|
|
330
|
+
if (!resourceValues)
|
|
331
|
+
continue;
|
|
332
|
+
// The allow-all flag grants access to every requested value.
|
|
333
|
+
if (Array.isArray(resourceValues) &&
|
|
334
|
+
resourceValues.includes(this.ALLOW_ALL_FLAG)) {
|
|
335
|
+
return values;
|
|
336
|
+
}
|
|
337
|
+
if (Array.isArray(resourceValues)) {
|
|
338
|
+
for (const resourceValue of resourceValues) {
|
|
339
|
+
allowedValues.add(resourceValue);
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
else {
|
|
343
|
+
allowedValues.add(resourceValues);
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
// Return only requested values that exist in the user's allowed resources.
|
|
347
|
+
return values.filter(value => allowedValues.has(value));
|
|
348
|
+
}
|
|
349
|
+
}
|
package/dist/index.d.ts
ADDED