@authup/access 1.0.0-beta.34 → 1.0.0-beta.36

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.mjs CHANGED
@@ -1,1259 +1,1006 @@
1
- import { AuthupError, ErrorCode } from '@authup/errors';
2
- import { DecisionStrategy, isObject, flattenObject, hasOwnProperty } from '@authup/kit';
3
- export { DecisionStrategy } from '@authup/kit';
4
- import { defineIssueItem, defineIssueGroup, Container } from 'validup';
5
- import { createValidator } from '@validup/adapter-zod';
6
- import { z } from 'zod';
7
- import { guard } from '@ucast/mongo2js';
8
-
9
- class PermissionError extends AuthupError {
10
- constructor(options = {}){
11
- super({
12
- ...options,
13
- message: options.message || 'A permission error occurred.',
14
- statusCode: options.statusCode || 403
15
- });
16
- }
17
- addIssue(data) {
18
- this.issues.push(data);
19
- }
20
- addIssues(data) {
21
- this.issues.push(...data);
22
- }
23
- static notFound(name) {
24
- return new PermissionError({
25
- message: `The permission ${name} was not found.`,
26
- code: ErrorCode.PERMISSION_NOT_FOUND
27
- });
28
- }
29
- static denied(name) {
30
- return new PermissionError({
31
- message: `The permission ${name} has not been granted.`,
32
- code: ErrorCode.PERMISSION_DENIED
33
- });
34
- }
35
- static deniedAll(names) {
36
- return new PermissionError({
37
- message: `None of the permissions ${names.join(', ')} has been granted.`,
38
- code: ErrorCode.PERMISSION_DENIED
39
- });
40
- }
41
- static evaluationFailed(name) {
42
- if (Array.isArray(name)) {
43
- return new PermissionError({
44
- message: `The evaluation of permissions ${name.join(', ')} failed`,
45
- code: ErrorCode.PERMISSION_EVALUATION_FAILED
46
- });
47
- }
48
- return new PermissionError({
49
- message: `The evaluation of permission ${name} failed`,
50
- code: ErrorCode.PERMISSION_EVALUATION_FAILED
51
- });
52
- }
53
- }
54
-
55
- /*
56
- * Copyright (c) 2024-2024.
57
- * Author Peter Placzek (tada5hi)
58
- * For the full copyright and license information,
59
- * view the LICENSE file that was distributed with this source code.
60
- */ function isPermissionPolicyBindingEqual(a, b) {
61
- if (a.permission.name !== b.permission.name) {
62
- return false;
63
- }
64
- if ((a.permission.realm_id ?? null) !== (b.permission.realm_id ?? null)) {
65
- return false;
66
- }
67
- if ((a.permission.client_id ?? null) !== (b.permission.client_id ?? null)) {
68
- return false;
69
- }
70
- return true;
71
- }
72
-
73
- /*
74
- * Copyright (c) 2025.
75
- * Author Peter Placzek (tada5hi)
76
- * For the full copyright and license information,
77
- * view the LICENSE file that was distributed with this source code.
78
- */ function formatKeySegment(value) {
79
- return value || '*';
1
+ import { AuthupError, ErrorCode } from "@authup/errors";
2
+ import { DecisionStrategy, DecisionStrategy as DecisionStrategy$1, flattenObject, hasOwnProperty, isObject } from "@authup/kit";
3
+ import { Container, defineIssueGroup, defineIssueItem } from "validup";
4
+ import { createValidator } from "@validup/adapter-zod";
5
+ import { z } from "zod";
6
+ import { guard } from "@ucast/mongo2js";
7
+ //#region src/permission/error/module.ts
8
+ var PermissionError = class PermissionError extends AuthupError {
9
+ constructor(options = {}) {
10
+ super({
11
+ ...options,
12
+ message: options.message || "A permission error occurred.",
13
+ statusCode: options.statusCode || 403
14
+ });
15
+ }
16
+ addIssue(data) {
17
+ this.issues.push(data);
18
+ }
19
+ addIssues(data) {
20
+ this.issues.push(...data);
21
+ }
22
+ static notFound(name) {
23
+ return new PermissionError({
24
+ message: `The permission ${name} was not found.`,
25
+ code: ErrorCode.PERMISSION_NOT_FOUND
26
+ });
27
+ }
28
+ static denied(name) {
29
+ return new PermissionError({
30
+ message: `The permission ${name} has not been granted.`,
31
+ code: ErrorCode.PERMISSION_DENIED
32
+ });
33
+ }
34
+ static deniedAll(names) {
35
+ return new PermissionError({
36
+ message: `None of the permissions ${names.join(", ")} has been granted.`,
37
+ code: ErrorCode.PERMISSION_DENIED
38
+ });
39
+ }
40
+ static evaluationFailed(name) {
41
+ if (Array.isArray(name)) return new PermissionError({
42
+ message: `The evaluation of permissions ${name.join(", ")} failed`,
43
+ code: ErrorCode.PERMISSION_EVALUATION_FAILED
44
+ });
45
+ return new PermissionError({
46
+ message: `The evaluation of permission ${name} failed`,
47
+ code: ErrorCode.PERMISSION_EVALUATION_FAILED
48
+ });
49
+ }
50
+ };
51
+ //#endregion
52
+ //#region src/permission/helpers/equal.ts
53
+ function isPermissionPolicyBindingEqual(a, b) {
54
+ if (a.permission.name !== b.permission.name) return false;
55
+ if ((a.permission.realm_id ?? null) !== (b.permission.realm_id ?? null)) return false;
56
+ if ((a.permission.client_id ?? null) !== (b.permission.client_id ?? null)) return false;
57
+ return true;
58
+ }
59
+ //#endregion
60
+ //#region src/permission/helpers/key.ts
61
+ function formatKeySegment(value) {
62
+ return value || "*";
80
63
  }
81
64
  function buildPermissionKey(input) {
82
- return `${formatKeySegment(input.realm_id)}/${formatKeySegment(input.client_id)}/${input.name}`;
65
+ return `${formatKeySegment(input.realm_id)}/${formatKeySegment(input.client_id)}/${input.name}`;
83
66
  }
84
-
67
+ //#endregion
68
+ //#region src/permission/helpers/merge.ts
85
69
  function mergePermissionPolicyBindings(input) {
86
- const grouped = input.reduce((previous, current)=>{
87
- const key = buildPermissionKey(current.permission);
88
- if (!previous[key]) {
89
- previous[key] = [];
90
- }
91
- previous[key].push(current);
92
- return previous;
93
- }, {});
94
- const output = [];
95
- const keys = Object.keys(grouped);
96
- for (const key of keys){
97
- const group = grouped[key];
98
- const first = group[0];
99
- if (group.length === 1) {
100
- output.push(first);
101
- continue;
102
- }
103
- const children = [];
104
- for (const element of group){
105
- if (!element.policies || element.policies.length === 0) {
106
- continue;
107
- }
108
- const policy = {
109
- type: 'composite',
110
- decision_strategy: element.permission.decision_strategy || DecisionStrategy.UNANIMOUS,
111
- children: element.policies
112
- };
113
- children.push(policy);
114
- }
115
- let mergedPolicies;
116
- if (children.length > 0 && children.length === group.length) {
117
- const policy = {
118
- type: 'composite',
119
- decision_strategy: DecisionStrategy.AFFIRMATIVE,
120
- children
121
- };
122
- mergedPolicies = [
123
- policy
124
- ];
125
- }
126
- output.push({
127
- permission: {
128
- ...first.permission,
129
- decision_strategy: DecisionStrategy.AFFIRMATIVE
130
- },
131
- policies: mergedPolicies
132
- });
133
- }
134
- return output;
135
- }
136
-
137
- class PermissionMemoryProvider {
138
- items = {};
139
- constructor(items = []){
140
- this.setMany(items);
141
- }
142
- async findOne(options) {
143
- const key = buildPermissionKey({
144
- name: options.name,
145
- client_id: options.clientId,
146
- realm_id: options.realmId
147
- });
148
- const entry = this.items[key];
149
- if (entry) {
150
- return entry;
151
- }
152
- return null;
153
- }
154
- setMany(input) {
155
- this.items = mergePermissionPolicyBindings(input).reduce((prev, current)=>{
156
- const key = buildPermissionKey(current.permission);
157
- prev[key] = current;
158
- return prev;
159
- }, {});
160
- }
161
- }
162
-
163
- /*
164
- * Copyright (c) 2024-2024.
165
- * Author Peter Placzek (tada5hi)
166
- * For the full copyright and license information,
167
- * view the LICENSE file that was distributed with this source code.
168
- */ function maybeInvertPolicyOutcome(outcome, invert) {
169
- if (typeof invert === 'undefined') {
170
- return outcome;
171
- }
172
- if (typeof invert === 'function') {
173
- return invert(outcome);
174
- }
175
- if (!invert) {
176
- return outcome;
177
- }
178
- return !outcome;
179
- }
180
-
181
- class PolicyError extends AuthupError {
182
- constructor(message, code){
183
- super({
184
- message,
185
- code
186
- });
187
- }
188
- addIssue(data) {
189
- this.issues.push(data);
190
- }
191
- addIssues(data) {
192
- this.issues.push(...data);
193
- }
194
- static evaluatorNotFound(type) {
195
- return new PolicyError(`No evaluator is registered to handle the policy: ${type}`, ErrorCode.POLICY_EVALUATOR_NOT_FOUND);
196
- }
197
- static evaluatorNotProcessable() {
198
- return new PolicyError('The evaluator can not process the policy.', ErrorCode.POLICY_EVALUATOR_NOT_PROCESSABLE);
199
- }
200
- static evaluatorContextInvalid() {
201
- return new PolicyError('The evaluator context is not valid.', ErrorCode.POLICY_EVALUATOR_CONTEXT_INVALID);
202
- }
203
- }
204
-
70
+ const grouped = input.reduce((previous, current) => {
71
+ const key = buildPermissionKey(current.permission);
72
+ if (!previous[key]) previous[key] = [];
73
+ previous[key].push(current);
74
+ return previous;
75
+ }, {});
76
+ const output = [];
77
+ const keys = Object.keys(grouped);
78
+ for (const key of keys) {
79
+ const group = grouped[key];
80
+ const first = group[0];
81
+ if (group.length === 1) {
82
+ output.push(first);
83
+ continue;
84
+ }
85
+ const children = [];
86
+ for (const element of group) {
87
+ if (!element.policies || element.policies.length === 0) continue;
88
+ const policy = {
89
+ type: "composite",
90
+ decision_strategy: element.permission.decision_strategy || DecisionStrategy$1.UNANIMOUS,
91
+ children: element.policies
92
+ };
93
+ children.push(policy);
94
+ }
95
+ let mergedPolicies;
96
+ if (children.length > 0 && children.length === group.length) mergedPolicies = [{
97
+ type: "composite",
98
+ decision_strategy: DecisionStrategy$1.AFFIRMATIVE,
99
+ children
100
+ }];
101
+ output.push({
102
+ permission: {
103
+ ...first.permission,
104
+ decision_strategy: DecisionStrategy$1.AFFIRMATIVE
105
+ },
106
+ policies: mergedPolicies
107
+ });
108
+ }
109
+ return output;
110
+ }
111
+ //#endregion
112
+ //#region src/permission/provider/memory.ts
113
+ var PermissionMemoryProvider = class {
114
+ items = {};
115
+ constructor(items = []) {
116
+ this.setMany(items);
117
+ }
118
+ async findOne(options) {
119
+ const key = buildPermissionKey({
120
+ name: options.name,
121
+ client_id: options.clientId,
122
+ realm_id: options.realmId
123
+ });
124
+ const entry = this.items[key];
125
+ if (entry) return entry;
126
+ return null;
127
+ }
128
+ setMany(input) {
129
+ this.items = mergePermissionPolicyBindings(input).reduce((prev, current) => {
130
+ const key = buildPermissionKey(current.permission);
131
+ prev[key] = current;
132
+ return prev;
133
+ }, {});
134
+ }
135
+ };
136
+ //#endregion
137
+ //#region src/policy/helpers/invert.ts
138
+ function maybeInvertPolicyOutcome(outcome, invert) {
139
+ if (typeof invert === "undefined") return outcome;
140
+ if (typeof invert === "function") return invert(outcome);
141
+ if (!invert) return outcome;
142
+ return !outcome;
143
+ }
144
+ //#endregion
145
+ //#region src/policy/error/module.ts
146
+ var PolicyError = class PolicyError extends AuthupError {
147
+ constructor(message, code) {
148
+ super({
149
+ message,
150
+ code
151
+ });
152
+ }
153
+ addIssue(data) {
154
+ this.issues.push(data);
155
+ }
156
+ addIssues(data) {
157
+ this.issues.push(...data);
158
+ }
159
+ static evaluatorNotFound(type) {
160
+ return new PolicyError(`No evaluator is registered to handle the policy: ${type}`, ErrorCode.POLICY_EVALUATOR_NOT_FOUND);
161
+ }
162
+ static evaluatorNotProcessable() {
163
+ return new PolicyError("The evaluator can not process the policy.", ErrorCode.POLICY_EVALUATOR_NOT_PROCESSABLE);
164
+ }
165
+ static evaluatorContextInvalid() {
166
+ return new PolicyError("The evaluator context is not valid.", ErrorCode.POLICY_EVALUATOR_CONTEXT_INVALID);
167
+ }
168
+ };
169
+ //#endregion
170
+ //#region src/policy/engine/module.ts
205
171
  /**
206
- * The policy engine is a component that interprets defined policies and makes decisions
207
- * on whether to allow or deny a particular access.
208
- */ class PolicyEngine {
209
- evaluators;
210
- constructor(evaluators = {}){
211
- this.evaluators = evaluators;
212
- }
213
- registerEvaluator(type, evaluator) {
214
- this.evaluators[type] = evaluator;
215
- }
216
- registerEvaluators(evaluators) {
217
- const keys = Object.keys(evaluators);
218
- for (const key of keys){
219
- this.registerEvaluator(key, evaluators[key]);
220
- }
221
- }
222
- /**
223
- * @param policy
224
- * @param ctx
225
- */ async evaluate(policy, ctx) {
226
- if (!policy.type) {
227
- return {
228
- success: maybeInvertPolicyOutcome(false, policy.invert),
229
- issues: [
230
- defineIssueItem({
231
- path: [],
232
- message: 'The policy can not be handled by any evaluator.',
233
- code: ErrorCode.POLICY_EVALUATOR_NOT_FOUND
234
- })
235
- ]
236
- };
237
- }
238
- if (ctx.exclude && ctx.exclude.length > 0 && ctx.exclude.includes(policy.type)) {
239
- return {
240
- success: maybeInvertPolicyOutcome(true, policy.invert)
241
- };
242
- }
243
- if (ctx.include && ctx.include.length > 0 && !ctx.include.includes(policy.type)) {
244
- return {
245
- success: maybeInvertPolicyOutcome(true, policy.invert)
246
- };
247
- }
248
- const issues = [];
249
- const evaluator = this.evaluators[policy.type];
250
- if (!evaluator) {
251
- // todo: add issue here instead + return false ?
252
- issues.push(defineIssueItem({
253
- path: [
254
- policy.type
255
- ],
256
- message: `The policy ${policy.type} can not be handled by any evaluator.`,
257
- code: ErrorCode.POLICY_EVALUATOR_NOT_FOUND
258
- }));
259
- return {
260
- success: maybeInvertPolicyOutcome(false, policy.invert),
261
- issues
262
- };
263
- }
264
- try {
265
- return await evaluator.evaluate(policy, {
266
- ...ctx,
267
- evaluators: {
268
- ...this.evaluators,
269
- ...ctx.evaluators || {}
270
- }
271
- });
272
- } catch {
273
- issues.push(defineIssueItem({
274
- path: [
275
- policy.type
276
- ],
277
- message: `The ${policy.type} evaluator can not process the policy specification.`,
278
- code: ErrorCode.POLICY_EVALUATOR_NOT_PROCESSABLE
279
- }));
280
- return {
281
- success: maybeInvertPolicyOutcome(false, policy.invert),
282
- issues
283
- };
284
- }
285
- }
286
- async evaluateOrFail(policy, ctx) {
287
- const issues = [];
288
- try {
289
- const outcome = await this.evaluate(policy, ctx);
290
- if (outcome.success) {
291
- return;
292
- }
293
- if (outcome.issues) {
294
- issues.push(...outcome.issues);
295
- }
296
- } catch (e) {
297
- if (e instanceof PolicyError) {
298
- throw e;
299
- }
300
- }
301
- const error = new PolicyError(`The policy ${policy.type} evaluation failed.`);
302
- error.addIssues(issues);
303
- throw error;
304
- }
305
- }
306
-
307
- /*
308
- * Copyright (c) 2026.
309
- * Author Peter Placzek (tada5hi)
310
- * For the full copyright and license information,
311
- * view the LICENSE file that was distributed with this source code.
312
- */ class PolicyData {
313
- data;
314
- validated;
315
- constructor(data = {}, validated = new Set()){
316
- this.data = data;
317
- this.validated = validated;
318
- }
319
- set(key, value) {
320
- this.data[key] = value;
321
- this.validated.delete(key);
322
- }
323
- get(key) {
324
- if (key in this.data) {
325
- return this.data[key];
326
- }
327
- throw new Error(`Policy data item ${key} does not exist.`);
328
- }
329
- has(key) {
330
- return key in this.data;
331
- }
332
- setValidated(key) {
333
- this.validated.add(key);
334
- }
335
- isValidated(key) {
336
- return this.validated.has(key);
337
- }
338
- clone() {
339
- return new PolicyData({
340
- ...this.data
341
- }, new Set(this.validated));
342
- }
343
- }
344
-
172
+ * The policy engine is a component that interprets defined policies and makes decisions
173
+ * on whether to allow or deny a particular access.
174
+ */
175
+ var PolicyEngine = class {
176
+ evaluators;
177
+ constructor(evaluators = {}) {
178
+ this.evaluators = evaluators;
179
+ }
180
+ registerEvaluator(type, evaluator) {
181
+ this.evaluators[type] = evaluator;
182
+ }
183
+ registerEvaluators(evaluators) {
184
+ const keys = Object.keys(evaluators);
185
+ for (const key of keys) this.registerEvaluator(key, evaluators[key]);
186
+ }
187
+ /**
188
+ * @param policy
189
+ * @param ctx
190
+ */
191
+ async evaluate(policy, ctx) {
192
+ if (!policy.type) return {
193
+ success: maybeInvertPolicyOutcome(false, policy.invert),
194
+ issues: [defineIssueItem({
195
+ path: [],
196
+ message: "The policy can not be handled by any evaluator.",
197
+ code: ErrorCode.POLICY_EVALUATOR_NOT_FOUND
198
+ })]
199
+ };
200
+ if (ctx.exclude && ctx.exclude.length > 0 && ctx.exclude.includes(policy.type)) return { success: maybeInvertPolicyOutcome(true, policy.invert) };
201
+ if (ctx.include && ctx.include.length > 0 && !ctx.include.includes(policy.type)) return { success: maybeInvertPolicyOutcome(true, policy.invert) };
202
+ const issues = [];
203
+ const evaluator = this.evaluators[policy.type];
204
+ if (!evaluator) {
205
+ issues.push(defineIssueItem({
206
+ path: [policy.type],
207
+ message: `The policy ${policy.type} can not be handled by any evaluator.`,
208
+ code: ErrorCode.POLICY_EVALUATOR_NOT_FOUND
209
+ }));
210
+ return {
211
+ success: maybeInvertPolicyOutcome(false, policy.invert),
212
+ issues
213
+ };
214
+ }
215
+ try {
216
+ return await evaluator.evaluate(policy, {
217
+ ...ctx,
218
+ evaluators: {
219
+ ...this.evaluators,
220
+ ...ctx.evaluators || {}
221
+ }
222
+ });
223
+ } catch {
224
+ issues.push(defineIssueItem({
225
+ path: [policy.type],
226
+ message: `The ${policy.type} evaluator can not process the policy specification.`,
227
+ code: ErrorCode.POLICY_EVALUATOR_NOT_PROCESSABLE
228
+ }));
229
+ return {
230
+ success: maybeInvertPolicyOutcome(false, policy.invert),
231
+ issues
232
+ };
233
+ }
234
+ }
235
+ async evaluateOrFail(policy, ctx) {
236
+ const issues = [];
237
+ try {
238
+ const outcome = await this.evaluate(policy, ctx);
239
+ if (outcome.success) return;
240
+ if (outcome.issues) issues.push(...outcome.issues);
241
+ } catch (e) {
242
+ if (e instanceof PolicyError) throw e;
243
+ }
244
+ const error = new PolicyError(`The policy ${policy.type} evaluation failed.`);
245
+ error.addIssues(issues);
246
+ throw error;
247
+ }
248
+ };
249
+ //#endregion
250
+ //#region src/policy/data.ts
251
+ var PolicyData = class PolicyData {
252
+ data;
253
+ validated;
254
+ constructor(data = {}, validated = /* @__PURE__ */ new Set()) {
255
+ this.data = data;
256
+ this.validated = validated;
257
+ }
258
+ set(key, value) {
259
+ this.data[key] = value;
260
+ this.validated.delete(key);
261
+ }
262
+ get(key) {
263
+ if (key in this.data) return this.data[key];
264
+ throw new Error(`Policy data item ${key} does not exist.`);
265
+ }
266
+ has(key) {
267
+ return key in this.data;
268
+ }
269
+ setValidated(key) {
270
+ this.validated.add(key);
271
+ }
272
+ isValidated(key) {
273
+ return this.validated.has(key);
274
+ }
275
+ clone() {
276
+ return new PolicyData({ ...this.data }, new Set(this.validated));
277
+ }
278
+ };
279
+ //#endregion
280
+ //#region src/policy/evaluation/context/define.ts
345
281
  function definePolicyEvaluationContext(input = {}) {
346
- return {
347
- evaluators: input.evaluators || {},
348
- path: input.path || [],
349
- data: input.data || new PolicyData(),
350
- include: input.include || [],
351
- exclude: input.exclude || []
352
- };
353
- }
354
-
355
- /*
356
- * Copyright (c) 2026-2026.
357
- * Author Peter Placzek (tada5hi)
358
- * For the full copyright and license information,
359
- * view the LICENSE file that was distributed with this source code.
360
- */ var PolicyIssueSeverity = /*#__PURE__*/ function(PolicyIssueSeverity) {
361
- PolicyIssueSeverity["WARNING"] = "warning";
362
- PolicyIssueSeverity["ERROR"] = "error";
363
- return PolicyIssueSeverity;
282
+ return {
283
+ evaluators: input.evaluators || {},
284
+ path: input.path || [],
285
+ data: input.data || new PolicyData(),
286
+ include: input.include || [],
287
+ exclude: input.exclude || []
288
+ };
289
+ }
290
+ //#endregion
291
+ //#region src/policy/issue/constants.ts
292
+ let PolicyIssueSeverity = /* @__PURE__ */ function(PolicyIssueSeverity) {
293
+ PolicyIssueSeverity["WARNING"] = "warning";
294
+ PolicyIssueSeverity["ERROR"] = "error";
295
+ return PolicyIssueSeverity;
364
296
  }({});
365
- var PolicyIssueCode = /*#__PURE__*/ function(PolicyIssueCode) {
366
- // Data/Input
367
- PolicyIssueCode["DATA_MISSING"] = "DATA_MISSING";
368
- PolicyIssueCode["DATA_INVALID"] = "DATA_INVALID";
369
- // Policy Spec / Config
370
- PolicyIssueCode["INVALID"] = "INVALID";
371
- PolicyIssueCode["TYPE_UNKNOWN"] = "TYPE_UNKNOWN";
372
- PolicyIssueCode["FIELD_MISSING"] = "FIELD_MISSING";
373
- PolicyIssueCode["FIELD_INVALID"] = "FIELD_INVALID";
374
- // Composite / Tree evaluation
375
- PolicyIssueCode["CHILD_INVALID"] = "CHILD_INVALID";
376
- PolicyIssueCode["CHILD_EVALUATION_FAILED"] = "CHILD_EVALUATION_FAILED";
377
- // Engine / Evaluator registry
378
- PolicyIssueCode["EVALUATION_DENIED"] = "EVALUATION_DENIED";
379
- PolicyIssueCode["EVALUATOR_NOT_FOUND"] = "EVALUATOR_NOT_FOUND";
380
- PolicyIssueCode["EVALUATOR_ERROR"] = "EVALUATOR_ERROR";
381
- // Execution control
382
- PolicyIssueCode["SKIPPED_EXCLUDED"] = "SKIPPED_EXCLUDED";
383
- PolicyIssueCode["SKIPPED_NOT_INCLUDED"] = "SKIPPED_NOT_INCLUDED";
384
- // Internal / unexpected
385
- PolicyIssueCode["INTERNAL_ERROR"] = "INTERNAL_ERROR";
386
- return PolicyIssueCode;
297
+ let PolicyIssueCode = /* @__PURE__ */ function(PolicyIssueCode) {
298
+ PolicyIssueCode["DATA_MISSING"] = "DATA_MISSING";
299
+ PolicyIssueCode["DATA_INVALID"] = "DATA_INVALID";
300
+ PolicyIssueCode["INVALID"] = "INVALID";
301
+ PolicyIssueCode["TYPE_UNKNOWN"] = "TYPE_UNKNOWN";
302
+ PolicyIssueCode["FIELD_MISSING"] = "FIELD_MISSING";
303
+ PolicyIssueCode["FIELD_INVALID"] = "FIELD_INVALID";
304
+ PolicyIssueCode["CHILD_INVALID"] = "CHILD_INVALID";
305
+ PolicyIssueCode["CHILD_EVALUATION_FAILED"] = "CHILD_EVALUATION_FAILED";
306
+ PolicyIssueCode["EVALUATION_DENIED"] = "EVALUATION_DENIED";
307
+ PolicyIssueCode["EVALUATOR_NOT_FOUND"] = "EVALUATOR_NOT_FOUND";
308
+ PolicyIssueCode["EVALUATOR_ERROR"] = "EVALUATOR_ERROR";
309
+ PolicyIssueCode["SKIPPED_EXCLUDED"] = "SKIPPED_EXCLUDED";
310
+ PolicyIssueCode["SKIPPED_NOT_INCLUDED"] = "SKIPPED_NOT_INCLUDED";
311
+ PolicyIssueCode["INTERNAL_ERROR"] = "INTERNAL_ERROR";
312
+ return PolicyIssueCode;
387
313
  }({});
388
-
314
+ //#endregion
315
+ //#region src/policy/issue/define.ts
389
316
  function definePolicyIssueItem(input) {
390
- return defineIssueItem(input);
317
+ return defineIssueItem(input);
391
318
  }
392
319
  function definePolicyIssueGroup(input) {
393
- return defineIssueGroup(input);
394
- }
395
-
396
- class AttributeNamesPolicyValidator extends Container {
397
- initialize() {
398
- super.initialize();
399
- this.mount('names', createValidator(z.array(z.string().min(3).max(128))));
400
- this.mount('invert', createValidator(z.boolean().or(z.null()).or(z.undefined()).optional()));
401
- }
402
- }
403
-
404
- /*
405
- * Copyright (c) 2025.
406
- * Author Peter Placzek (tada5hi)
407
- * For the full copyright and license information,
408
- * view the LICENSE file that was distributed with this source code.
409
- */ function defineAttributesPolicy(data) {
410
- return data;
411
- }
412
-
413
- /*
414
- * Copyright (c) 2024-2024.
415
- * Author Peter Placzek (tada5hi)
416
- * For the full copyright and license information,
417
- * view the LICENSE file that was distributed with this source code.
418
- */ var BuiltInPolicyType = /*#__PURE__*/ function(BuiltInPolicyType) {
419
- /**
420
- * Bundles different policies.
421
- */ BuiltInPolicyType["COMPOSITE"] = "composite";
422
- /**
423
- * Date Based Access Control (DBAC)
424
- */ BuiltInPolicyType["DATE"] = "date";
425
- /**
426
- * Time Based Access Control (TBAC)
427
- */ BuiltInPolicyType["TIME"] = "time";
428
- /**
429
- * Attribute Name Based Access Control (ANBAC)
430
- */ BuiltInPolicyType["ATTRIBUTE_NAMES"] = "attributeNames";
431
- /**
432
- * Attribute Based Access Control (ABAC)
433
- */ BuiltInPolicyType["ATTRIBUTES"] = "attributes";
434
- /**
435
- * Realm of Identity is for attribute realm.
436
- */ BuiltInPolicyType["REALM_MATCH"] = "realmMatch";
437
- /**
438
- * Restriction based on identity (type, id, ...)
439
- */ BuiltInPolicyType["IDENTITY"] = "identity";
440
- /**
441
- * Restriction based on a binding between identity <-> permission
442
- */ BuiltInPolicyType["PERMISSION_BINDING"] = "permissionBinding";
443
- return BuiltInPolicyType;
320
+ return defineIssueGroup(input);
321
+ }
322
+ //#endregion
323
+ //#region src/policy/built-in/attribute-names/validator.ts
324
+ var AttributeNamesPolicyValidator = class extends Container {
325
+ initialize() {
326
+ super.initialize();
327
+ this.mount("names", createValidator(z.array(z.string().min(3).max(128))));
328
+ this.mount("invert", createValidator(z.boolean().or(z.null()).or(z.undefined()).optional()));
329
+ }
330
+ };
331
+ //#endregion
332
+ //#region src/policy/built-in/attributes/define.ts
333
+ function defineAttributesPolicy(data) {
334
+ return data;
335
+ }
336
+ //#endregion
337
+ //#region src/policy/built-in/constants.ts
338
+ let BuiltInPolicyType = /* @__PURE__ */ function(BuiltInPolicyType) {
339
+ /**
340
+ * Bundles different policies.
341
+ */
342
+ BuiltInPolicyType["COMPOSITE"] = "composite";
343
+ /**
344
+ * Date Based Access Control (DBAC)
345
+ */
346
+ BuiltInPolicyType["DATE"] = "date";
347
+ /**
348
+ * Time Based Access Control (TBAC)
349
+ */
350
+ BuiltInPolicyType["TIME"] = "time";
351
+ /**
352
+ * Attribute Name Based Access Control (ANBAC)
353
+ */
354
+ BuiltInPolicyType["ATTRIBUTE_NAMES"] = "attributeNames";
355
+ /**
356
+ * Attribute Based Access Control (ABAC)
357
+ */
358
+ BuiltInPolicyType["ATTRIBUTES"] = "attributes";
359
+ /**
360
+ * Realm of Identity is for attribute realm.
361
+ */
362
+ BuiltInPolicyType["REALM_MATCH"] = "realmMatch";
363
+ /**
364
+ * Restriction based on identity (type, id, ...)
365
+ */
366
+ BuiltInPolicyType["IDENTITY"] = "identity";
367
+ /**
368
+ * Restriction based on a binding between identity <-> permission
369
+ */
370
+ BuiltInPolicyType["PERMISSION_BINDING"] = "permissionBinding";
371
+ return BuiltInPolicyType;
444
372
  }({});
445
373
  const SystemPolicyName = {
446
- DEFAULT: 'system.default',
447
- IDENTITY: 'system.identity',
448
- PERMISSION_BINDING: 'system.permission-binding',
449
- REALM_MATCH: 'system.realm-match',
450
- REALM_BOUND: 'system.realm-bound',
451
- REALM_OR_GLOBAL: 'system.realm-or-global'
374
+ DEFAULT: "system.default",
375
+ IDENTITY: "system.identity",
376
+ PERMISSION_BINDING: "system.permission-binding",
377
+ REALM_MATCH: "system.realm-match",
378
+ REALM_BOUND: "system.realm-bound",
379
+ REALM_OR_GLOBAL: "system.realm-or-global"
452
380
  };
453
-
454
- class AttributesPolicyValidator extends Container {
455
- initialize() {
456
- super.initialize();
457
- this.mount('query', createValidator(z.looseObject({})));
458
- this.mount('invert', createValidator(z.boolean().or(z.null()).or(z.undefined()).optional()));
459
- }
460
- }
461
-
462
- class AttributesPolicyEvaluator {
463
- validator;
464
- constructor(){
465
- this.validator = new AttributesPolicyValidator();
466
- }
467
- async accessData(ctx) {
468
- if (!ctx.data.has(BuiltInPolicyType.ATTRIBUTES)) {
469
- return null;
470
- }
471
- if (ctx.data.isValidated(BuiltInPolicyType.ATTRIBUTES)) {
472
- return ctx.data.get(BuiltInPolicyType.ATTRIBUTES);
473
- }
474
- // todo: run validator on attributes (isObject ...)
475
- const data = ctx.data.get(BuiltInPolicyType.ATTRIBUTES);
476
- ctx.data.set(BuiltInPolicyType.ATTRIBUTES, data);
477
- ctx.data.setValidated(BuiltInPolicyType.ATTRIBUTES);
478
- return data;
479
- }
480
- async evaluate(value, ctx) {
481
- // todo: catch errors + transform to issue(s)
482
- const policy = await this.validator.run(value);
483
- const data = await this.accessData(ctx);
484
- if (!data) {
485
- return {
486
- success: false,
487
- issues: [
488
- definePolicyIssueItem({
489
- code: PolicyIssueCode.DATA_MISSING,
490
- message: 'The data property attributes is missing',
491
- path: ctx.path
492
- })
493
- ]
494
- };
495
- }
496
- this.fixQuery(policy.query);
497
- const testIt = guard(policy.query);
498
- return {
499
- success: maybeInvertPolicyOutcome(testIt(data), policy.invert)
500
- };
501
- }
502
- fixQuery(query) {
503
- if (Array.isArray(query)) {
504
- for (const element of query){
505
- this.fixQuery(element);
506
- }
507
- return;
508
- }
509
- if (isObject(query)) {
510
- const keys = Object.keys(query);
511
- for (const key of keys){
512
- const value = query[key];
513
- if (isObject(value) || Array.isArray(value)) {
514
- this.fixQuery(value);
515
- continue;
516
- }
517
- if (key === '$regex' && typeof value === 'string') {
518
- const fragments = value.match(/\/(.*?)\/([a-z]*)?$/i);
519
- if (fragments && fragments[1] !== undefined) {
520
- query[key] = new RegExp(fragments[1], fragments[2] || '');
521
- }
522
- }
523
- }
524
- }
525
- }
526
- }
527
-
528
- class AttributeNamesPolicyEvaluator {
529
- validator;
530
- attributesEvaluator;
531
- constructor(){
532
- this.validator = new AttributeNamesPolicyValidator();
533
- this.attributesEvaluator = new AttributesPolicyEvaluator();
534
- }
535
- async evaluate(value, ctx) {
536
- // todo: catch errors + transform to issue(s)
537
- const policy = await this.validator.run(value);
538
- const data = await this.attributesEvaluator.accessData(ctx);
539
- if (!data) {
540
- return {
541
- success: false,
542
- issues: [
543
- definePolicyIssueItem({
544
- code: PolicyIssueCode.DATA_MISSING,
545
- message: 'The data property attributes is missing',
546
- path: ctx.path
547
- })
548
- ]
549
- };
550
- }
551
- const attributes = flattenObject(data);
552
- const keys = Object.keys(attributes);
553
- const issues = [];
554
- for (const key of keys){
555
- const index = policy.names.indexOf(key);
556
- if (index === -1) {
557
- issues.push(definePolicyIssueItem({
558
- code: PolicyIssueCode.EVALUATION_DENIED,
559
- message: `The attribute ${key} is not included`,
560
- path: [
561
- ...ctx.path,
562
- key
563
- ]
564
- }));
565
- }
566
- }
567
- return {
568
- success: maybeInvertPolicyOutcome(issues.length === 0, policy.invert),
569
- issues
570
- };
571
- }
572
- }
573
-
574
- class CompositePolicyValidator extends Container {
575
- initialize() {
576
- super.initialize();
577
- this.mount('decision_strategy', createValidator(z.enum(DecisionStrategy).or(z.null()).or(z.undefined()).optional()));
578
- this.mount('children', createValidator(z.array(z.looseObject({
579
- type: z.string().min(3)
580
- }))));
581
- this.mount('invert', createValidator(z.boolean().or(z.null()).or(z.undefined()).optional()));
582
- }
583
- }
584
-
585
- class CompositePolicyEvaluator {
586
- validator;
587
- constructor(){
588
- this.validator = new CompositePolicyValidator();
589
- }
590
- async evaluate(value, ctx) {
591
- // todo: catch errors + transform to issue(s)
592
- const policy = await this.validator.run(value);
593
- let count = 0;
594
- const decision_strategy = policy.decision_strategy ?? DecisionStrategy.UNANIMOUS;
595
- const engine = new PolicyEngine(ctx.evaluators);
596
- const issues = [];
597
- for (const childPolicy of policy.children){
598
- const path = [
599
- ...ctx.path || [],
600
- ...childPolicy.type ? [
601
- childPolicy.type
602
- ] : []
603
- ];
604
- const outcome = await engine.evaluate(childPolicy, {
605
- ...ctx,
606
- path
607
- });
608
- if (outcome.success) {
609
- if (decision_strategy === DecisionStrategy.AFFIRMATIVE) {
610
- return {
611
- success: maybeInvertPolicyOutcome(true, policy.invert),
612
- issues: []
613
- };
614
- }
615
- count++;
616
- } else {
617
- if (outcome.issues) {
618
- issues.push(defineIssueGroup({
619
- message: `The evaluation of child policy ${childPolicy.type} failed`,
620
- issues: outcome.issues || [],
621
- path
622
- }));
623
- }
624
- if (decision_strategy === DecisionStrategy.UNANIMOUS) {
625
- return {
626
- success: maybeInvertPolicyOutcome(false, policy.invert),
627
- issues: [
628
- defineIssueGroup({
629
- message: `The evaluation of composite policy failed (${DecisionStrategy.UNANIMOUS})`,
630
- issues,
631
- path: ctx.path
632
- })
633
- ]
634
- };
635
- }
636
- count--;
637
- }
638
- }
639
- if (count > 0) {
640
- return {
641
- success: maybeInvertPolicyOutcome(true, policy.invert)
642
- };
643
- }
644
- return {
645
- success: maybeInvertPolicyOutcome(false, policy.invert),
646
- issues: [
647
- defineIssueGroup({
648
- message: `The evaluation of composite policy failed (${DecisionStrategy.CONSENSUS})`,
649
- issues: issues || [],
650
- path: ctx.path
651
- })
652
- ]
653
- };
654
- }
655
- }
656
-
381
+ //#endregion
382
+ //#region src/policy/built-in/attributes/validator.ts
383
+ var AttributesPolicyValidator = class extends Container {
384
+ initialize() {
385
+ super.initialize();
386
+ this.mount("query", createValidator(z.looseObject({})));
387
+ this.mount("invert", createValidator(z.boolean().or(z.null()).or(z.undefined()).optional()));
388
+ }
389
+ };
390
+ //#endregion
391
+ //#region src/policy/built-in/attributes/evaluator.ts
392
+ var AttributesPolicyEvaluator = class {
393
+ validator;
394
+ constructor() {
395
+ this.validator = new AttributesPolicyValidator();
396
+ }
397
+ async accessData(ctx) {
398
+ if (!ctx.data.has("attributes")) return null;
399
+ if (ctx.data.isValidated("attributes")) return ctx.data.get("attributes");
400
+ const data = ctx.data.get("attributes");
401
+ ctx.data.set("attributes", data);
402
+ ctx.data.setValidated("attributes");
403
+ return data;
404
+ }
405
+ async evaluate(value, ctx) {
406
+ const policy = await this.validator.run(value);
407
+ const data = await this.accessData(ctx);
408
+ if (!data) return {
409
+ success: false,
410
+ issues: [definePolicyIssueItem({
411
+ code: "DATA_MISSING",
412
+ message: "The data property attributes is missing",
413
+ path: ctx.path
414
+ })]
415
+ };
416
+ this.fixQuery(policy.query);
417
+ return { success: maybeInvertPolicyOutcome(guard(policy.query)(data), policy.invert) };
418
+ }
419
+ fixQuery(query) {
420
+ if (Array.isArray(query)) {
421
+ for (const element of query) this.fixQuery(element);
422
+ return;
423
+ }
424
+ if (isObject(query)) {
425
+ const keys = Object.keys(query);
426
+ for (const key of keys) {
427
+ const value = query[key];
428
+ if (isObject(value) || Array.isArray(value)) {
429
+ this.fixQuery(value);
430
+ continue;
431
+ }
432
+ if (key === "$regex" && typeof value === "string") {
433
+ const fragments = value.match(/\/(.*?)\/([a-z]*)?$/i);
434
+ if (fragments && fragments[1] !== void 0) query[key] = new RegExp(fragments[1], fragments[2] || "");
435
+ }
436
+ }
437
+ }
438
+ }
439
+ };
440
+ //#endregion
441
+ //#region src/policy/built-in/attribute-names/evaluator.ts
442
+ var AttributeNamesPolicyEvaluator = class {
443
+ validator;
444
+ attributesEvaluator;
445
+ constructor() {
446
+ this.validator = new AttributeNamesPolicyValidator();
447
+ this.attributesEvaluator = new AttributesPolicyEvaluator();
448
+ }
449
+ async evaluate(value, ctx) {
450
+ const policy = await this.validator.run(value);
451
+ const data = await this.attributesEvaluator.accessData(ctx);
452
+ if (!data) return {
453
+ success: false,
454
+ issues: [definePolicyIssueItem({
455
+ code: "DATA_MISSING",
456
+ message: "The data property attributes is missing",
457
+ path: ctx.path
458
+ })]
459
+ };
460
+ const attributes = flattenObject(data);
461
+ const keys = Object.keys(attributes);
462
+ const issues = [];
463
+ for (const key of keys) if (policy.names.indexOf(key) === -1) issues.push(definePolicyIssueItem({
464
+ code: "EVALUATION_DENIED",
465
+ message: `The attribute ${key} is not included`,
466
+ path: [...ctx.path, key]
467
+ }));
468
+ return {
469
+ success: maybeInvertPolicyOutcome(issues.length === 0, policy.invert),
470
+ issues
471
+ };
472
+ }
473
+ };
474
+ //#endregion
475
+ //#region src/policy/built-in/composite/validator.ts
476
+ var CompositePolicyValidator = class extends Container {
477
+ initialize() {
478
+ super.initialize();
479
+ this.mount("decision_strategy", createValidator(z.enum(DecisionStrategy).or(z.null()).or(z.undefined()).optional()));
480
+ this.mount("children", createValidator(z.array(z.looseObject({ type: z.string().min(3) }))));
481
+ this.mount("invert", createValidator(z.boolean().or(z.null()).or(z.undefined()).optional()));
482
+ }
483
+ };
484
+ //#endregion
485
+ //#region src/policy/built-in/composite/evaluator.ts
486
+ var CompositePolicyEvaluator = class {
487
+ validator;
488
+ constructor() {
489
+ this.validator = new CompositePolicyValidator();
490
+ }
491
+ async evaluate(value, ctx) {
492
+ const policy = await this.validator.run(value);
493
+ let count = 0;
494
+ const decision_strategy = policy.decision_strategy ?? DecisionStrategy.UNANIMOUS;
495
+ const engine = new PolicyEngine(ctx.evaluators);
496
+ const issues = [];
497
+ for (const childPolicy of policy.children) {
498
+ const path = [...ctx.path || [], ...childPolicy.type ? [childPolicy.type] : []];
499
+ const outcome = await engine.evaluate(childPolicy, {
500
+ ...ctx,
501
+ path
502
+ });
503
+ if (outcome.success) {
504
+ if (decision_strategy === DecisionStrategy.AFFIRMATIVE) return {
505
+ success: maybeInvertPolicyOutcome(true, policy.invert),
506
+ issues: []
507
+ };
508
+ count++;
509
+ } else {
510
+ if (outcome.issues) issues.push(defineIssueGroup({
511
+ message: `The evaluation of child policy ${childPolicy.type} failed`,
512
+ issues: outcome.issues || [],
513
+ path
514
+ }));
515
+ if (decision_strategy === DecisionStrategy.UNANIMOUS) return {
516
+ success: maybeInvertPolicyOutcome(false, policy.invert),
517
+ issues: [defineIssueGroup({
518
+ message: `The evaluation of composite policy failed (${DecisionStrategy.UNANIMOUS})`,
519
+ issues,
520
+ path: ctx.path
521
+ })]
522
+ };
523
+ count--;
524
+ }
525
+ }
526
+ if (count > 0) return { success: maybeInvertPolicyOutcome(true, policy.invert) };
527
+ return {
528
+ success: maybeInvertPolicyOutcome(false, policy.invert),
529
+ issues: [defineIssueGroup({
530
+ message: `The evaluation of composite policy failed (${DecisionStrategy.CONSENSUS})`,
531
+ issues: issues || [],
532
+ path: ctx.path
533
+ })]
534
+ };
535
+ }
536
+ };
537
+ //#endregion
538
+ //#region src/policy/built-in/composite/helper.ts
657
539
  function isCompositePolicy(input) {
658
- return input.type === BuiltInPolicyType.COMPOSITE;
659
- }
660
-
661
- class DatePolicyValidator extends Container {
662
- initialize() {
663
- super.initialize();
664
- this.mount('start', createValidator(z.date().or(z.iso.date()).or(z.number()).or(z.null()).or(z.undefined()).optional()));
665
- this.mount('end', createValidator(z.date().or(z.iso.date()).or(z.number()).or(z.null()).or(z.undefined()).optional()));
666
- this.mount('invert', createValidator(z.boolean().or(z.undefined()).or(z.null()).optional()));
667
- }
668
- }
669
-
540
+ return input.type === "composite";
541
+ }
542
+ //#endregion
543
+ //#region src/policy/built-in/date/validator.ts
544
+ var DatePolicyValidator = class extends Container {
545
+ initialize() {
546
+ super.initialize();
547
+ this.mount("start", createValidator(z.date().or(z.iso.date()).or(z.number()).or(z.null()).or(z.undefined()).optional()));
548
+ this.mount("end", createValidator(z.date().or(z.iso.date()).or(z.number()).or(z.null()).or(z.undefined()).optional()));
549
+ this.mount("invert", createValidator(z.boolean().or(z.undefined()).or(z.null()).optional()));
550
+ }
551
+ };
552
+ //#endregion
553
+ //#region src/policy/built-in/date/evaluator.ts
670
554
  function normalizeDate$1(input) {
671
- return new Date(input.getFullYear(), input.getMonth(), input.getDate());
555
+ return new Date(input.getFullYear(), input.getMonth(), input.getDate());
672
556
  }
673
557
  function toDate$1(input) {
674
- if (typeof input === 'string') {
675
- return new Date(input);
676
- }
677
- if (typeof input === 'number') {
678
- return new Date(input);
679
- }
680
- return input;
681
- }
682
- class DatePolicyEvaluator {
683
- validator;
684
- constructor(){
685
- this.validator = new DatePolicyValidator();
686
- }
687
- async evaluate(value, ctx) {
688
- // todo: catch errors + transform to issue(s)
689
- const policy = await this.validator.run(value);
690
- let now;
691
- if (ctx.data.has(BuiltInPolicyType.DATE)) {
692
- if (ctx.data.isValidated(BuiltInPolicyType.DATE)) {
693
- now = ctx.data.get(BuiltInPolicyType.DATE);
694
- } else {
695
- // todo: run validator on attributes (isObject ...)
696
- now = normalizeDate$1(toDate$1(ctx.data.get(BuiltInPolicyType.DATE)));
697
- ctx.data.set(BuiltInPolicyType.DATE, now);
698
- ctx.data.setValidated(BuiltInPolicyType.DATE);
699
- }
700
- } else {
701
- now = normalizeDate$1(new Date());
702
- }
703
- if (policy.start) {
704
- const start = normalizeDate$1(toDate$1(policy.start));
705
- if (now < start) {
706
- return {
707
- success: maybeInvertPolicyOutcome(false, policy.invert)
708
- };
709
- }
710
- }
711
- if (policy.end) {
712
- const end = normalizeDate$1(toDate$1(policy.end));
713
- if (now > end) {
714
- return {
715
- success: maybeInvertPolicyOutcome(false, policy.invert)
716
- };
717
- }
718
- }
719
- return {
720
- success: maybeInvertPolicyOutcome(true, policy.invert)
721
- };
722
- }
723
- }
724
-
725
- class PolicyIdentityDataValidator extends Container {
726
- initialize() {
727
- super.initialize();
728
- this.mount('type', createValidator(z.string().min(3).max(128)));
729
- this.mount('id', createValidator(z.uuid()));
730
- this.mount('clientId', createValidator(z.uuid().or(z.null()).or(z.undefined()).optional()));
731
- this.mount('realmId', createValidator(z.uuid().or(z.null()).or(z.undefined()).optional()));
732
- this.mount('realmName', createValidator(z.string().min(3).max(128).or(z.null()).or(z.undefined()).optional()));
733
- }
734
- }
735
-
736
- class IdentityPolicyValidator extends Container {
737
- initialize() {
738
- this.mount('types', createValidator(z.array(z.string()).or(z.null()).or(z.undefined()).optional()));
739
- this.mount('invert', createValidator(z.boolean().or(z.null()).or(z.undefined()).optional()));
740
- }
741
- }
742
-
743
- class IdentityPolicyEvaluator {
744
- validator;
745
- dataValidator;
746
- constructor(){
747
- this.validator = new IdentityPolicyValidator();
748
- this.dataValidator = new PolicyIdentityDataValidator();
749
- }
750
- async accessData(ctx) {
751
- if (!ctx.data.has('identity')) {
752
- return null;
753
- }
754
- if (ctx.data.isValidated('identity')) {
755
- return ctx.data.get('identity');
756
- }
757
- const data = await this.dataValidator.run(ctx.data.get('identity'));
758
- ctx.data.set('identity', data);
759
- ctx.data.setValidated('identity');
760
- return data;
761
- }
762
- async evaluate(value, ctx) {
763
- // todo: catch errors + transform to issue(s)
764
- const policy = await this.validator.run(value);
765
- const data = await this.accessData(ctx);
766
- if (!data) {
767
- return {
768
- success: false,
769
- issues: [
770
- definePolicyIssueItem({
771
- code: PolicyIssueCode.DATA_MISSING,
772
- message: 'The data property identity is missing',
773
- path: ctx.path
774
- })
775
- ]
776
- };
777
- }
778
- if (!policy.types || policy.types.length === 0) {
779
- return {
780
- success: maybeInvertPolicyOutcome(true, policy.invert)
781
- };
782
- }
783
- const typeAllowed = policy.types.includes(data.type);
784
- if (typeAllowed) {
785
- return {
786
- success: maybeInvertPolicyOutcome(typeAllowed, policy.invert)
787
- };
788
- }
789
- return {
790
- success: maybeInvertPolicyOutcome(typeAllowed, policy.invert),
791
- issues: [
792
- definePolicyIssueItem({
793
- code: PolicyIssueCode.EVALUATION_DENIED,
794
- message: `The type ${data.type} is not covered by the policy configuration`,
795
- path: ctx.path
796
- })
797
- ]
798
- };
799
- }
800
- }
801
-
802
- class PermissionBindingPolicyValidator extends Container {
803
- initialize() {}
804
- }
805
-
806
- class PermissionBindingPolicyEvaluator {
807
- validator;
808
- constructor(){
809
- this.validator = new PermissionBindingPolicyValidator();
810
- }
811
- async evaluate(value) {
812
- const policy = await this.validator.run(value);
813
- // todo: this must be changed when the permission-checker not only checks owned permissions.
814
- return {
815
- success: maybeInvertPolicyOutcome(true, policy.invert)
816
- };
817
- }
818
- }
819
-
820
- class RealmMatchPolicyValidator extends Container {
821
- initialize() {
822
- super.initialize();
823
- this.mount('decision_strategy', createValidator(z.enum(DecisionStrategy).or(z.null()).or(z.undefined()).optional()));
824
- this.mount('attribute_name', createValidator(z.string().min(3).or(z.array(z.string().min(3))).or(z.null()).or(z.undefined()).optional()));
825
- this.mount('attribute_name_strict', createValidator(z.boolean().or(z.null()).or(z.undefined()).optional()));
826
- this.mount('attribute_null_match_all', createValidator(z.boolean().or(z.null()).or(z.undefined()).optional()));
827
- this.mount('identity_master_match_all', createValidator(z.boolean().or(z.null()).or(z.undefined()).optional()));
828
- this.mount('invert', createValidator(z.boolean().or(z.null()).or(z.undefined()).optional()));
829
- }
830
- }
831
-
832
- class RealmMatchPolicyEvaluator {
833
- validator;
834
- identityEvaluator;
835
- attributesEvaluator;
836
- constructor(){
837
- this.validator = new RealmMatchPolicyValidator();
838
- this.identityEvaluator = new IdentityPolicyEvaluator();
839
- this.attributesEvaluator = new AttributesPolicyEvaluator();
840
- }
841
- async evaluate(value, ctx) {
842
- // todo: catch errors + transform to issue(s)
843
- const policy = await this.validator.run(value);
844
- const identity = await this.identityEvaluator.accessData(ctx);
845
- if (!identity) {
846
- return {
847
- success: false,
848
- issues: [
849
- definePolicyIssueItem({
850
- code: PolicyIssueCode.DATA_MISSING,
851
- message: 'The data property identity is missing',
852
- path: ctx.path
853
- })
854
- ]
855
- };
856
- }
857
- const attributes = await this.attributesEvaluator.accessData(ctx);
858
- if (!attributes) {
859
- return {
860
- success: false,
861
- issues: [
862
- definePolicyIssueItem({
863
- code: PolicyIssueCode.DATA_MISSING,
864
- message: 'The data property attributes is missing',
865
- path: ctx.path
866
- })
867
- ]
868
- };
869
- }
870
- const identityMasterMatchAll = policy.identity_master_match_all ?? true;
871
- if (identityMasterMatchAll && identity.realmName && identity.realmName === 'master') {
872
- return {
873
- success: maybeInvertPolicyOutcome(true, policy.invert)
874
- };
875
- }
876
- let keys;
877
- if (policy.attribute_name) {
878
- if (Array.isArray(policy.attribute_name)) {
879
- keys = policy.attribute_name;
880
- } else {
881
- keys = [
882
- policy.attribute_name
883
- ];
884
- }
885
- } else {
886
- keys = [
887
- 'realm_id',
888
- 'realm_name',
889
- 'realmId',
890
- 'realmName'
891
- ];
892
- policy.decision_strategy = DecisionStrategy.CONSENSUS;
893
- }
894
- const attribute_name_strict = policy.attribute_name_strict ?? true;
895
- if (!attribute_name_strict) {
896
- const resourceKeys = Object.keys(attributes);
897
- const keysToAdd = [];
898
- for (const resourceKey of resourceKeys){
899
- let contains = false;
900
- for (const key of keys){
901
- if (resourceKey !== key && resourceKey.includes(key)) {
902
- contains = true;
903
- break;
904
- }
905
- }
906
- if (contains) {
907
- keysToAdd.push(resourceKey);
908
- }
909
- }
910
- if (keysToAdd.length > 0) {
911
- keys.push(...keysToAdd);
912
- }
913
- }
914
- let count = 0;
915
- let evaluated = false;
916
- for (const key of keys){
917
- if (!hasOwnProperty(attributes, key)) {
918
- continue;
919
- }
920
- evaluated = true;
921
- let outcome = false;
922
- const attributeValue = attributes[key];
923
- if (attributeValue === null && policy.attribute_null_match_all) {
924
- outcome = true;
925
- } else if (attributeValue === identity.realmId || attributeValue === identity.realmName) {
926
- outcome = true;
927
- }
928
- if (outcome) {
929
- if (policy.decision_strategy === DecisionStrategy.AFFIRMATIVE) {
930
- return {
931
- success: maybeInvertPolicyOutcome(true, policy.invert)
932
- };
933
- }
934
- count++;
935
- } else {
936
- if (policy.decision_strategy === DecisionStrategy.UNANIMOUS) {
937
- return {
938
- success: maybeInvertPolicyOutcome(false, policy.invert)
939
- };
940
- }
941
- count--;
942
- }
943
- }
944
- if (!evaluated) {
945
- return {
946
- success: maybeInvertPolicyOutcome(true, policy.invert)
947
- };
948
- }
949
- return {
950
- success: maybeInvertPolicyOutcome(count > 0, policy.invert)
951
- };
952
- }
953
- }
954
-
955
- /*
956
- * Copyright (c) 2024-2024.
957
- * Author Peter Placzek (tada5hi)
958
- * For the full copyright and license information,
959
- * view the LICENSE file that was distributed with this source code.
960
- */ var TimePolicyInterval = /*#__PURE__*/ function(TimePolicyInterval) {
961
- TimePolicyInterval["DAILY"] = "daily";
962
- TimePolicyInterval["WEEKLY"] = "weekly";
963
- TimePolicyInterval["MONTHLY"] = "monthly";
964
- TimePolicyInterval["YEARLY"] = "yearly";
965
- return TimePolicyInterval;
558
+ if (typeof input === "string") return new Date(input);
559
+ if (typeof input === "number") return new Date(input);
560
+ return input;
561
+ }
562
+ var DatePolicyEvaluator = class {
563
+ validator;
564
+ constructor() {
565
+ this.validator = new DatePolicyValidator();
566
+ }
567
+ async evaluate(value, ctx) {
568
+ const policy = await this.validator.run(value);
569
+ let now;
570
+ if (ctx.data.has("date")) if (ctx.data.isValidated("date")) now = ctx.data.get("date");
571
+ else {
572
+ now = normalizeDate$1(toDate$1(ctx.data.get("date")));
573
+ ctx.data.set("date", now);
574
+ ctx.data.setValidated("date");
575
+ }
576
+ else now = normalizeDate$1(/* @__PURE__ */ new Date());
577
+ if (policy.start) {
578
+ const start = normalizeDate$1(toDate$1(policy.start));
579
+ if (now < start) return { success: maybeInvertPolicyOutcome(false, policy.invert) };
580
+ }
581
+ if (policy.end) {
582
+ const end = normalizeDate$1(toDate$1(policy.end));
583
+ if (now > end) return { success: maybeInvertPolicyOutcome(false, policy.invert) };
584
+ }
585
+ return { success: maybeInvertPolicyOutcome(true, policy.invert) };
586
+ }
587
+ };
588
+ //#endregion
589
+ //#region src/policy/built-in/identity/data/validator.ts
590
+ var PolicyIdentityDataValidator = class extends Container {
591
+ initialize() {
592
+ super.initialize();
593
+ this.mount("type", createValidator(z.string().min(3).max(128)));
594
+ this.mount("id", createValidator(z.uuid()));
595
+ this.mount("clientId", createValidator(z.uuid().or(z.null()).or(z.undefined()).optional()));
596
+ this.mount("realmId", createValidator(z.uuid().or(z.null()).or(z.undefined()).optional()));
597
+ this.mount("realmName", createValidator(z.string().min(3).max(128).or(z.null()).or(z.undefined()).optional()));
598
+ }
599
+ };
600
+ //#endregion
601
+ //#region src/policy/built-in/identity/validator.ts
602
+ var IdentityPolicyValidator = class extends Container {
603
+ initialize() {
604
+ this.mount("types", createValidator(z.array(z.string()).or(z.null()).or(z.undefined()).optional()));
605
+ this.mount("invert", createValidator(z.boolean().or(z.null()).or(z.undefined()).optional()));
606
+ }
607
+ };
608
+ //#endregion
609
+ //#region src/policy/built-in/identity/evaluator.ts
610
+ var IdentityPolicyEvaluator = class {
611
+ validator;
612
+ dataValidator;
613
+ constructor() {
614
+ this.validator = new IdentityPolicyValidator();
615
+ this.dataValidator = new PolicyIdentityDataValidator();
616
+ }
617
+ async accessData(ctx) {
618
+ if (!ctx.data.has("identity")) return null;
619
+ if (ctx.data.isValidated("identity")) return ctx.data.get("identity");
620
+ const data = await this.dataValidator.run(ctx.data.get("identity"));
621
+ ctx.data.set("identity", data);
622
+ ctx.data.setValidated("identity");
623
+ return data;
624
+ }
625
+ async evaluate(value, ctx) {
626
+ const policy = await this.validator.run(value);
627
+ const data = await this.accessData(ctx);
628
+ if (!data) return {
629
+ success: false,
630
+ issues: [definePolicyIssueItem({
631
+ code: "DATA_MISSING",
632
+ message: "The data property identity is missing",
633
+ path: ctx.path
634
+ })]
635
+ };
636
+ if (!policy.types || policy.types.length === 0) return { success: maybeInvertPolicyOutcome(true, policy.invert) };
637
+ const typeAllowed = policy.types.includes(data.type);
638
+ if (typeAllowed) return { success: maybeInvertPolicyOutcome(typeAllowed, policy.invert) };
639
+ return {
640
+ success: maybeInvertPolicyOutcome(typeAllowed, policy.invert),
641
+ issues: [definePolicyIssueItem({
642
+ code: "EVALUATION_DENIED",
643
+ message: `The type ${data.type} is not covered by the policy configuration`,
644
+ path: ctx.path
645
+ })]
646
+ };
647
+ }
648
+ };
649
+ //#endregion
650
+ //#region src/policy/built-in/permission-binding/validator.ts
651
+ var PermissionBindingPolicyValidator = class extends Container {
652
+ initialize() {}
653
+ };
654
+ //#endregion
655
+ //#region src/policy/built-in/permission-binding/module.ts
656
+ var PermissionBindingPolicyEvaluator = class {
657
+ validator;
658
+ constructor() {
659
+ this.validator = new PermissionBindingPolicyValidator();
660
+ }
661
+ async evaluate(value) {
662
+ return { success: maybeInvertPolicyOutcome(true, (await this.validator.run(value)).invert) };
663
+ }
664
+ };
665
+ //#endregion
666
+ //#region src/policy/built-in/realm-match/validator.ts
667
+ var RealmMatchPolicyValidator = class extends Container {
668
+ initialize() {
669
+ super.initialize();
670
+ this.mount("decision_strategy", createValidator(z.enum(DecisionStrategy).or(z.null()).or(z.undefined()).optional()));
671
+ this.mount("attribute_name", createValidator(z.string().min(3).or(z.array(z.string().min(3))).or(z.null()).or(z.undefined()).optional()));
672
+ this.mount("attribute_name_strict", createValidator(z.boolean().or(z.null()).or(z.undefined()).optional()));
673
+ this.mount("attribute_null_match_all", createValidator(z.boolean().or(z.null()).or(z.undefined()).optional()));
674
+ this.mount("identity_master_match_all", createValidator(z.boolean().or(z.null()).or(z.undefined()).optional()));
675
+ this.mount("invert", createValidator(z.boolean().or(z.null()).or(z.undefined()).optional()));
676
+ }
677
+ };
678
+ //#endregion
679
+ //#region src/policy/built-in/realm-match/evaluator.ts
680
+ var RealmMatchPolicyEvaluator = class {
681
+ validator;
682
+ identityEvaluator;
683
+ attributesEvaluator;
684
+ constructor() {
685
+ this.validator = new RealmMatchPolicyValidator();
686
+ this.identityEvaluator = new IdentityPolicyEvaluator();
687
+ this.attributesEvaluator = new AttributesPolicyEvaluator();
688
+ }
689
+ async evaluate(value, ctx) {
690
+ const policy = await this.validator.run(value);
691
+ const identity = await this.identityEvaluator.accessData(ctx);
692
+ if (!identity) return {
693
+ success: false,
694
+ issues: [definePolicyIssueItem({
695
+ code: "DATA_MISSING",
696
+ message: "The data property identity is missing",
697
+ path: ctx.path
698
+ })]
699
+ };
700
+ const attributes = await this.attributesEvaluator.accessData(ctx);
701
+ if (!attributes) return {
702
+ success: false,
703
+ issues: [definePolicyIssueItem({
704
+ code: "DATA_MISSING",
705
+ message: "The data property attributes is missing",
706
+ path: ctx.path
707
+ })]
708
+ };
709
+ if ((policy.identity_master_match_all ?? true) && identity.realmName && identity.realmName === "master") return { success: maybeInvertPolicyOutcome(true, policy.invert) };
710
+ let keys;
711
+ if (policy.attribute_name) if (Array.isArray(policy.attribute_name)) keys = policy.attribute_name;
712
+ else keys = [policy.attribute_name];
713
+ else {
714
+ keys = [
715
+ "realm_id",
716
+ "realm_name",
717
+ "realmId",
718
+ "realmName"
719
+ ];
720
+ policy.decision_strategy = DecisionStrategy.CONSENSUS;
721
+ }
722
+ if (!(policy.attribute_name_strict ?? true)) {
723
+ const resourceKeys = Object.keys(attributes);
724
+ const keysToAdd = [];
725
+ for (const resourceKey of resourceKeys) {
726
+ let contains = false;
727
+ for (const key of keys) if (resourceKey !== key && resourceKey.includes(key)) {
728
+ contains = true;
729
+ break;
730
+ }
731
+ if (contains) keysToAdd.push(resourceKey);
732
+ }
733
+ if (keysToAdd.length > 0) keys.push(...keysToAdd);
734
+ }
735
+ let count = 0;
736
+ let evaluated = false;
737
+ for (const key of keys) {
738
+ if (!hasOwnProperty(attributes, key)) continue;
739
+ evaluated = true;
740
+ let outcome = false;
741
+ const attributeValue = attributes[key];
742
+ if (attributeValue === null && policy.attribute_null_match_all) outcome = true;
743
+ else if (attributeValue === identity.realmId || attributeValue === identity.realmName) outcome = true;
744
+ if (outcome) {
745
+ if (policy.decision_strategy === DecisionStrategy.AFFIRMATIVE) return { success: maybeInvertPolicyOutcome(true, policy.invert) };
746
+ count++;
747
+ } else {
748
+ if (policy.decision_strategy === DecisionStrategy.UNANIMOUS) return { success: maybeInvertPolicyOutcome(false, policy.invert) };
749
+ count--;
750
+ }
751
+ }
752
+ if (!evaluated) return { success: maybeInvertPolicyOutcome(true, policy.invert) };
753
+ return { success: maybeInvertPolicyOutcome(count > 0, policy.invert) };
754
+ }
755
+ };
756
+ //#endregion
757
+ //#region src/policy/built-in/time/constants.ts
758
+ let TimePolicyInterval = /* @__PURE__ */ function(TimePolicyInterval) {
759
+ TimePolicyInterval["DAILY"] = "daily";
760
+ TimePolicyInterval["WEEKLY"] = "weekly";
761
+ TimePolicyInterval["MONTHLY"] = "monthly";
762
+ TimePolicyInterval["YEARLY"] = "yearly";
763
+ return TimePolicyInterval;
966
764
  }({});
967
-
765
+ //#endregion
766
+ //#region src/policy/built-in/time/helpers.ts
968
767
  function isIntervalForDayOfWeek(interval) {
969
- return interval === TimePolicyInterval.WEEKLY || interval === TimePolicyInterval.MONTHLY || interval === TimePolicyInterval.YEARLY;
768
+ return interval === "weekly" || interval === "monthly" || interval === "yearly";
970
769
  }
971
770
  function isIntervalForDayOfMonth(interval) {
972
- return interval === TimePolicyInterval.MONTHLY || interval === TimePolicyInterval.YEARLY;
771
+ return interval === "monthly" || interval === "yearly";
973
772
  }
974
773
  function isIntervalForDayOfYear(interval) {
975
- return interval === TimePolicyInterval.YEARLY;
976
- }
977
-
978
- class TimePolicyValidator extends Container {
979
- initialize() {
980
- super.initialize();
981
- this.mount('day_of_week', createValidator(z.number().min(0).max(6).or(z.null()).or(z.undefined()).optional()));
982
- this.mount('day_of_month', createValidator(z.number().min(1).max(31).or(z.null()).or(z.undefined()).optional()));
983
- this.mount('day_of_year', createValidator(z.number().min(1).max(365).or(z.null()).or(z.undefined()).optional()));
984
- this.mount('start', createValidator(z.date().or(z.iso.datetime()).or(z.iso.time()).or(z.number()).or(z.null()).or(z.undefined()).optional()));
985
- this.mount('end', createValidator(z.date().or(z.iso.datetime()).or(z.iso.time()).or(z.number()).or(z.null()).or(z.undefined()).optional()));
986
- this.mount('interval', createValidator(z.enum(TimePolicyInterval).or(z.null()).or(z.undefined()).optional()));
987
- this.mount('invert', createValidator(z.boolean().or(z.undefined()).or(z.null()).optional()));
988
- }
989
- }
990
-
774
+ return interval === "yearly";
775
+ }
776
+ //#endregion
777
+ //#region src/policy/built-in/time/validator.ts
778
+ var TimePolicyValidator = class extends Container {
779
+ initialize() {
780
+ super.initialize();
781
+ this.mount("day_of_week", createValidator(z.number().min(0).max(6).or(z.null()).or(z.undefined()).optional()));
782
+ this.mount("day_of_month", createValidator(z.number().min(1).max(31).or(z.null()).or(z.undefined()).optional()));
783
+ this.mount("day_of_year", createValidator(z.number().min(1).max(365).or(z.null()).or(z.undefined()).optional()));
784
+ this.mount("start", createValidator(z.date().or(z.iso.datetime()).or(z.iso.time()).or(z.number()).or(z.null()).or(z.undefined()).optional()));
785
+ this.mount("end", createValidator(z.date().or(z.iso.datetime()).or(z.iso.time()).or(z.number()).or(z.null()).or(z.undefined()).optional()));
786
+ this.mount("interval", createValidator(z.enum(TimePolicyInterval).or(z.null()).or(z.undefined()).optional()));
787
+ this.mount("invert", createValidator(z.boolean().or(z.undefined()).or(z.null()).optional()));
788
+ }
789
+ };
790
+ //#endregion
791
+ //#region src/policy/built-in/time/evaluator.ts
991
792
  const timeRegex = /^(?:[01]\d|2[0-3]):[0-5]\d(?::[0-5]\d)?$/;
992
793
  function normalizeDate(input, dateRef) {
993
- const date = dateRef ? new Date(dateRef) : new Date();
994
- date.setHours(input.getHours(), input.getMinutes());
995
- return date;
794
+ const date = dateRef ? new Date(dateRef) : /* @__PURE__ */ new Date();
795
+ date.setHours(input.getHours(), input.getMinutes());
796
+ return date;
996
797
  }
997
798
  function toDate(input, dateRef) {
998
- if (typeof input === 'string') {
999
- if (timeRegex.test(input)) {
1000
- const parts = input.split(':');
1001
- const startHours = Number(parts[0]);
1002
- const startMinutes = Number(parts[1]);
1003
- const startSeconds = parts[2] !== undefined ? Number(parts[2]) : 0;
1004
- if (Number.isFinite(startHours) && Number.isFinite(startMinutes) && Number.isFinite(startSeconds)) {
1005
- const date = dateRef ? new Date(dateRef) : new Date();
1006
- date.setHours(startHours, startMinutes, startSeconds, 0);
1007
- return date;
1008
- }
1009
- }
1010
- return new Date(input);
1011
- }
1012
- if (typeof input === 'number') {
1013
- return new Date(input);
1014
- }
1015
- return input;
1016
- }
1017
- class TimePolicyEvaluator {
1018
- validator;
1019
- constructor(){
1020
- this.validator = new TimePolicyValidator();
1021
- }
1022
- async evaluate(value, ctx) {
1023
- // todo: catch errors + transform to issue(s)
1024
- const policy = await this.validator.run(value);
1025
- let now;
1026
- if (ctx.data.has(BuiltInPolicyType.TIME)) {
1027
- if (ctx.data.isValidated(BuiltInPolicyType.TIME)) {
1028
- now = ctx.data.get(BuiltInPolicyType.TIME);
1029
- } else {
1030
- // todo: run validator on attributes (isObject ...)
1031
- now = toDate(ctx.data.get(BuiltInPolicyType.TIME));
1032
- ctx.data.set(BuiltInPolicyType.TIME, now);
1033
- ctx.data.setValidated(BuiltInPolicyType.TIME);
1034
- }
1035
- } else {
1036
- now = new Date();
1037
- }
1038
- if (policy.start) {
1039
- const start = normalizeDate(toDate(policy.start, now), now);
1040
- if (now < start) {
1041
- return {
1042
- success: maybeInvertPolicyOutcome(false, policy.invert)
1043
- };
1044
- }
1045
- }
1046
- if (policy.end) {
1047
- const end = normalizeDate(toDate(policy.end, now), now);
1048
- if (now > end) {
1049
- return {
1050
- success: maybeInvertPolicyOutcome(false, policy.invert)
1051
- };
1052
- }
1053
- }
1054
- if (policy.interval) {
1055
- if (isIntervalForDayOfWeek(policy.interval) && policy.day_of_week) {
1056
- if (now.getDay() !== policy.day_of_week) {
1057
- return {
1058
- success: maybeInvertPolicyOutcome(false, policy.invert)
1059
- };
1060
- }
1061
- }
1062
- if (isIntervalForDayOfMonth(policy.interval) && policy.day_of_month) {
1063
- if (now.getDate() !== policy.day_of_month) {
1064
- return {
1065
- success: maybeInvertPolicyOutcome(false, policy.invert)
1066
- };
1067
- }
1068
- }
1069
- if (isIntervalForDayOfYear(policy.interval) && policy.day_of_year) {
1070
- const start = new Date(now.getFullYear(), 0, 0);
1071
- const diff = now.getTime() - start.getTime() + (start.getTimezoneOffset() - now.getTimezoneOffset()) * 60 * 1000;
1072
- const oneDay = 1000 * 60 * 60 * 24;
1073
- const dayOfYear = Math.floor(diff / oneDay);
1074
- if (dayOfYear !== policy.day_of_year) {
1075
- return {
1076
- success: maybeInvertPolicyOutcome(false, policy.invert)
1077
- };
1078
- }
1079
- }
1080
- }
1081
- return {
1082
- success: maybeInvertPolicyOutcome(true, policy.invert)
1083
- };
1084
- }
1085
- }
1086
-
1087
- /*
1088
- * Copyright (c) 2025.
1089
- * Author Peter Placzek (tada5hi)
1090
- * For the full copyright and license information,
1091
- * view the LICENSE file that was distributed with this source code.
1092
- */ function definePolicyWithType(type, data) {
1093
- return {
1094
- ...data,
1095
- type
1096
- };
1097
- }
1098
-
799
+ if (typeof input === "string") {
800
+ if (timeRegex.test(input)) {
801
+ const parts = input.split(":");
802
+ const startHours = Number(parts[0]);
803
+ const startMinutes = Number(parts[1]);
804
+ const startSeconds = parts[2] !== void 0 ? Number(parts[2]) : 0;
805
+ if (Number.isFinite(startHours) && Number.isFinite(startMinutes) && Number.isFinite(startSeconds)) {
806
+ const date = dateRef ? new Date(dateRef) : /* @__PURE__ */ new Date();
807
+ date.setHours(startHours, startMinutes, startSeconds, 0);
808
+ return date;
809
+ }
810
+ }
811
+ return new Date(input);
812
+ }
813
+ if (typeof input === "number") return new Date(input);
814
+ return input;
815
+ }
816
+ var TimePolicyEvaluator = class {
817
+ validator;
818
+ constructor() {
819
+ this.validator = new TimePolicyValidator();
820
+ }
821
+ async evaluate(value, ctx) {
822
+ const policy = await this.validator.run(value);
823
+ let now;
824
+ if (ctx.data.has("time")) if (ctx.data.isValidated("time")) now = ctx.data.get("time");
825
+ else {
826
+ now = toDate(ctx.data.get("time"));
827
+ ctx.data.set("time", now);
828
+ ctx.data.setValidated("time");
829
+ }
830
+ else now = /* @__PURE__ */ new Date();
831
+ if (policy.start) {
832
+ const start = normalizeDate(toDate(policy.start, now), now);
833
+ if (now < start) return { success: maybeInvertPolicyOutcome(false, policy.invert) };
834
+ }
835
+ if (policy.end) {
836
+ const end = normalizeDate(toDate(policy.end, now), now);
837
+ if (now > end) return { success: maybeInvertPolicyOutcome(false, policy.invert) };
838
+ }
839
+ if (policy.interval) {
840
+ if (isIntervalForDayOfWeek(policy.interval) && policy.day_of_week) {
841
+ if (now.getDay() !== policy.day_of_week) return { success: maybeInvertPolicyOutcome(false, policy.invert) };
842
+ }
843
+ if (isIntervalForDayOfMonth(policy.interval) && policy.day_of_month) {
844
+ if (now.getDate() !== policy.day_of_month) return { success: maybeInvertPolicyOutcome(false, policy.invert) };
845
+ }
846
+ if (isIntervalForDayOfYear(policy.interval) && policy.day_of_year) {
847
+ const start = new Date(now.getFullYear(), 0, 0);
848
+ const diff = now.getTime() - start.getTime() + (start.getTimezoneOffset() - now.getTimezoneOffset()) * 60 * 1e3;
849
+ if (Math.floor(diff / (1e3 * 60 * 60 * 24)) !== policy.day_of_year) return { success: maybeInvertPolicyOutcome(false, policy.invert) };
850
+ }
851
+ }
852
+ return { success: maybeInvertPolicyOutcome(true, policy.invert) };
853
+ }
854
+ };
855
+ //#endregion
856
+ //#region src/policy/built-in/define.ts
857
+ function definePolicyWithType(type, data) {
858
+ return {
859
+ ...data,
860
+ type
861
+ };
862
+ }
863
+ //#endregion
864
+ //#region src/policy/constants.ts
1099
865
  const PolicyDefaultEvaluators = {
1100
- [BuiltInPolicyType.COMPOSITE]: new CompositePolicyEvaluator(),
1101
- [BuiltInPolicyType.ATTRIBUTES]: new AttributesPolicyEvaluator(),
1102
- [BuiltInPolicyType.ATTRIBUTE_NAMES]: new AttributeNamesPolicyEvaluator(),
1103
- [BuiltInPolicyType.DATE]: new DatePolicyEvaluator(),
1104
- [BuiltInPolicyType.IDENTITY]: new IdentityPolicyEvaluator(),
1105
- [BuiltInPolicyType.PERMISSION_BINDING]: new PermissionBindingPolicyEvaluator(),
1106
- [BuiltInPolicyType.REALM_MATCH]: new RealmMatchPolicyEvaluator(),
1107
- [BuiltInPolicyType.TIME]: new TimePolicyEvaluator()
866
+ ["composite"]: new CompositePolicyEvaluator(),
867
+ ["attributes"]: new AttributesPolicyEvaluator(),
868
+ ["attributeNames"]: new AttributeNamesPolicyEvaluator(),
869
+ ["date"]: new DatePolicyEvaluator(),
870
+ ["identity"]: new IdentityPolicyEvaluator(),
871
+ ["permissionBinding"]: new PermissionBindingPolicyEvaluator(),
872
+ ["realmMatch"]: new RealmMatchPolicyEvaluator(),
873
+ ["time"]: new TimePolicyEvaluator()
1108
874
  };
875
+ //#endregion
876
+ //#region src/permission/evaluator/module.ts
877
+ var PermissionEvaluator = class {
878
+ provider;
879
+ policyEngine;
880
+ clientId;
881
+ realmId;
882
+ constructor(options) {
883
+ this.provider = options.provider;
884
+ this.clientId = options.clientId || null;
885
+ this.realmId = options.realmId || null;
886
+ if (options.policyEngine) this.policyEngine = options.policyEngine;
887
+ else this.policyEngine = new PolicyEngine(PolicyDefaultEvaluators);
888
+ }
889
+ async findOne(input, overrides = {}) {
890
+ return this.provider.findOne({
891
+ name: input,
892
+ clientId: overrides.clientId ?? this.clientId,
893
+ realmId: overrides.realmId ?? this.realmId
894
+ });
895
+ }
896
+ async evaluate(ctx) {
897
+ if (!Array.isArray(ctx.name)) {
898
+ await this.evaluate({
899
+ ...ctx,
900
+ name: [ctx.name]
901
+ });
902
+ return;
903
+ }
904
+ const { options = {} } = ctx;
905
+ const decisionStrategy = options.decisionStrategy ?? DecisionStrategy.UNANIMOUS;
906
+ const issues = [];
907
+ let count = 0;
908
+ const dataBase = ctx.input || new PolicyData();
909
+ for (const name of ctx.name) {
910
+ const binding = await this.findOne(name, {
911
+ realmId: ctx.realmId,
912
+ clientId: ctx.clientId
913
+ });
914
+ if (!binding) {
915
+ issues.push(defineIssueItem({
916
+ code: ErrorCode.PERMISSION_NOT_FOUND,
917
+ message: `The ${name} permission could not be resolved`,
918
+ path: [name]
919
+ }));
920
+ if (decisionStrategy === DecisionStrategy.UNANIMOUS) {
921
+ const error = PermissionError.evaluationFailed(ctx.name);
922
+ error.addIssues(issues);
923
+ throw error;
924
+ }
925
+ continue;
926
+ }
927
+ const policies = binding.policies ?? [];
928
+ if (policies.length === 0) {
929
+ if (decisionStrategy === DecisionStrategy.AFFIRMATIVE) return;
930
+ count++;
931
+ continue;
932
+ }
933
+ const data = dataBase.clone();
934
+ data.set("permissionBinding", binding);
935
+ const compositePolicy = {
936
+ type: "composite",
937
+ decision_strategy: binding.permission.decision_strategy ?? DecisionStrategy.UNANIMOUS,
938
+ children: policies
939
+ };
940
+ const evaluationResult = await this.policyEngine.evaluate(compositePolicy, definePolicyEvaluationContext({
941
+ include: options.policiesIncluded,
942
+ exclude: options.policiesExcluded,
943
+ data
944
+ }));
945
+ if (evaluationResult.success) {
946
+ if (decisionStrategy === DecisionStrategy.AFFIRMATIVE) return;
947
+ count++;
948
+ } else {
949
+ issues.push(definePolicyIssueGroup({
950
+ code: ErrorCode.PERMISSION_EVALUATION_FAILED,
951
+ issues: evaluationResult.issues || [],
952
+ message: `The ${binding.permission.name} permissions policy evaluation failed`,
953
+ path: [binding.permission.name]
954
+ }));
955
+ if (decisionStrategy === DecisionStrategy.UNANIMOUS) {
956
+ const error = PermissionError.evaluationFailed(binding.permission.name);
957
+ error.addIssues(issues);
958
+ throw error;
959
+ }
960
+ count--;
961
+ }
962
+ }
963
+ if (count > 0) return;
964
+ if (issues.length === 0) throw PermissionError.deniedAll(ctx.name);
965
+ else {
966
+ const error = PermissionError.evaluationFailed(ctx.name);
967
+ error.addIssues(issues);
968
+ throw error;
969
+ }
970
+ }
971
+ async evaluateOneOf(ctx) {
972
+ return this.evaluate({
973
+ ...ctx,
974
+ options: {
975
+ ...ctx.options || {},
976
+ decisionStrategy: DecisionStrategy.AFFIRMATIVE
977
+ }
978
+ });
979
+ }
980
+ async preEvaluate(ctx) {
981
+ return this.evaluate({
982
+ ...ctx,
983
+ options: {
984
+ ...ctx.options || {},
985
+ policiesExcluded: [
986
+ "attributes",
987
+ "attributeNames",
988
+ "realmMatch"
989
+ ]
990
+ }
991
+ });
992
+ }
993
+ async preEvaluateOneOf(ctx) {
994
+ return this.preEvaluate({
995
+ ...ctx,
996
+ options: {
997
+ ...ctx.options || {},
998
+ decisionStrategy: DecisionStrategy.AFFIRMATIVE
999
+ }
1000
+ });
1001
+ }
1002
+ };
1003
+ //#endregion
1004
+ export { AttributeNamesPolicyEvaluator, AttributeNamesPolicyValidator, AttributesPolicyEvaluator, AttributesPolicyValidator, BuiltInPolicyType, CompositePolicyEvaluator, CompositePolicyValidator, DatePolicyEvaluator, DatePolicyValidator, DecisionStrategy, IdentityPolicyEvaluator, IdentityPolicyValidator, PermissionBindingPolicyEvaluator, PermissionBindingPolicyValidator, PermissionError, PermissionEvaluator, PermissionMemoryProvider, PolicyData, PolicyDefaultEvaluators, PolicyEngine, PolicyError, PolicyIssueCode, PolicyIssueSeverity, RealmMatchPolicyEvaluator, RealmMatchPolicyValidator, SystemPolicyName, TimePolicyEvaluator, TimePolicyInterval, TimePolicyValidator, buildPermissionKey, defineAttributesPolicy, definePolicyEvaluationContext, definePolicyIssueGroup, definePolicyIssueItem, definePolicyWithType, isCompositePolicy, isIntervalForDayOfMonth, isIntervalForDayOfWeek, isIntervalForDayOfYear, isPermissionPolicyBindingEqual, maybeInvertPolicyOutcome, mergePermissionPolicyBindings };
1109
1005
 
1110
- class PermissionEvaluator {
1111
- provider;
1112
- policyEngine;
1113
- clientId;
1114
- realmId;
1115
- // ----------------------------------------------
1116
- constructor(options){
1117
- this.provider = options.provider;
1118
- this.clientId = options.clientId || null;
1119
- this.realmId = options.realmId || null;
1120
- if (options.policyEngine) {
1121
- this.policyEngine = options.policyEngine;
1122
- } else {
1123
- this.policyEngine = new PolicyEngine(PolicyDefaultEvaluators);
1124
- }
1125
- }
1126
- // ----------------------------------------------
1127
- async findOne(input, overrides = {}) {
1128
- return this.provider.findOne({
1129
- name: input,
1130
- clientId: overrides.clientId ?? this.clientId,
1131
- realmId: overrides.realmId ?? this.realmId
1132
- });
1133
- }
1134
- // ----------------------------------------------
1135
- async evaluate(ctx) {
1136
- if (!Array.isArray(ctx.name)) {
1137
- await this.evaluate({
1138
- ...ctx,
1139
- name: [
1140
- ctx.name
1141
- ]
1142
- });
1143
- return;
1144
- }
1145
- const { options = {} } = ctx;
1146
- const decisionStrategy = options.decisionStrategy ?? DecisionStrategy.UNANIMOUS;
1147
- const issues = [];
1148
- let count = 0;
1149
- const dataBase = ctx.input || new PolicyData();
1150
- for (const name of ctx.name){
1151
- const binding = await this.findOne(name, {
1152
- realmId: ctx.realmId,
1153
- clientId: ctx.clientId
1154
- });
1155
- if (!binding) {
1156
- issues.push(defineIssueItem({
1157
- code: ErrorCode.PERMISSION_NOT_FOUND,
1158
- message: `The ${name} permission could not be resolved`,
1159
- path: [
1160
- name
1161
- ]
1162
- }));
1163
- if (decisionStrategy === DecisionStrategy.UNANIMOUS) {
1164
- const error = PermissionError.evaluationFailed(ctx.name);
1165
- error.addIssues(issues);
1166
- throw error;
1167
- }
1168
- continue;
1169
- }
1170
- const policies = binding.policies ?? [];
1171
- if (policies.length === 0) {
1172
- if (decisionStrategy === DecisionStrategy.AFFIRMATIVE) {
1173
- return;
1174
- }
1175
- count++;
1176
- continue;
1177
- }
1178
- const data = dataBase.clone();
1179
- data.set(BuiltInPolicyType.PERMISSION_BINDING, binding);
1180
- const policyDecisionStrategy = binding.permission.decision_strategy ?? DecisionStrategy.UNANIMOUS;
1181
- const compositePolicy = {
1182
- type: BuiltInPolicyType.COMPOSITE,
1183
- decision_strategy: policyDecisionStrategy,
1184
- children: policies
1185
- };
1186
- const evaluationResult = await this.policyEngine.evaluate(compositePolicy, definePolicyEvaluationContext({
1187
- include: options.policiesIncluded,
1188
- exclude: options.policiesExcluded,
1189
- data
1190
- }));
1191
- if (evaluationResult.success) {
1192
- if (decisionStrategy === DecisionStrategy.AFFIRMATIVE) {
1193
- return;
1194
- }
1195
- count++;
1196
- } else {
1197
- issues.push(definePolicyIssueGroup({
1198
- code: ErrorCode.PERMISSION_EVALUATION_FAILED,
1199
- issues: evaluationResult.issues || [],
1200
- message: `The ${binding.permission.name} permissions policy evaluation failed`,
1201
- path: [
1202
- binding.permission.name
1203
- ]
1204
- }));
1205
- if (decisionStrategy === DecisionStrategy.UNANIMOUS) {
1206
- const error = PermissionError.evaluationFailed(binding.permission.name);
1207
- error.addIssues(issues);
1208
- throw error;
1209
- }
1210
- count--;
1211
- }
1212
- }
1213
- if (count > 0) {
1214
- return;
1215
- }
1216
- if (issues.length === 0) {
1217
- throw PermissionError.deniedAll(ctx.name);
1218
- } else {
1219
- const error = PermissionError.evaluationFailed(ctx.name);
1220
- error.addIssues(issues);
1221
- throw error;
1222
- }
1223
- }
1224
- async evaluateOneOf(ctx) {
1225
- return this.evaluate({
1226
- ...ctx,
1227
- options: {
1228
- ...ctx.options || {},
1229
- decisionStrategy: DecisionStrategy.AFFIRMATIVE
1230
- }
1231
- });
1232
- }
1233
- // ----------------------------------------------
1234
- async preEvaluate(ctx) {
1235
- return this.evaluate({
1236
- ...ctx,
1237
- options: {
1238
- ...ctx.options || {},
1239
- policiesExcluded: [
1240
- BuiltInPolicyType.ATTRIBUTES,
1241
- BuiltInPolicyType.ATTRIBUTE_NAMES,
1242
- BuiltInPolicyType.REALM_MATCH
1243
- ]
1244
- }
1245
- });
1246
- }
1247
- async preEvaluateOneOf(ctx) {
1248
- return this.preEvaluate({
1249
- ...ctx,
1250
- options: {
1251
- ...ctx.options || {},
1252
- decisionStrategy: DecisionStrategy.AFFIRMATIVE
1253
- }
1254
- });
1255
- }
1256
- }
1257
-
1258
- export { AttributeNamesPolicyEvaluator, AttributeNamesPolicyValidator, AttributesPolicyEvaluator, AttributesPolicyValidator, BuiltInPolicyType, CompositePolicyEvaluator, CompositePolicyValidator, DatePolicyEvaluator, DatePolicyValidator, IdentityPolicyEvaluator, IdentityPolicyValidator, PermissionBindingPolicyEvaluator, PermissionBindingPolicyValidator, PermissionError, PermissionEvaluator, PermissionMemoryProvider, PolicyData, PolicyDefaultEvaluators, PolicyEngine, PolicyError, PolicyIssueCode, PolicyIssueSeverity, RealmMatchPolicyEvaluator, RealmMatchPolicyValidator, SystemPolicyName, TimePolicyEvaluator, TimePolicyInterval, TimePolicyValidator, buildPermissionKey, defineAttributesPolicy, definePolicyEvaluationContext, definePolicyIssueGroup, definePolicyIssueItem, definePolicyWithType, isCompositePolicy, isIntervalForDayOfMonth, isIntervalForDayOfWeek, isIntervalForDayOfYear, isPermissionPolicyBindingEqual, maybeInvertPolicyOutcome, mergePermissionPolicyBindings };
1259
- //# sourceMappingURL=index.mjs.map
1006
+ //# sourceMappingURL=index.mjs.map