@authup/access 1.0.0-beta.24 → 1.0.0-beta.26

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.
Files changed (58) hide show
  1. package/LICENSE +1 -1
  2. package/dist/index.cjs +208 -160
  3. package/dist/index.cjs.map +1 -1
  4. package/dist/index.mjs +204 -162
  5. package/dist/index.mjs.map +1 -1
  6. package/dist/permission/error/module.d.ts +5 -4
  7. package/dist/permission/error/module.d.ts.map +1 -1
  8. package/dist/permission/helpers/equal.d.ts.map +1 -1
  9. package/dist/permission/helpers/index.d.ts +1 -0
  10. package/dist/permission/helpers/index.d.ts.map +1 -1
  11. package/dist/permission/helpers/key.d.ts +3 -0
  12. package/dist/permission/helpers/key.d.ts.map +1 -0
  13. package/dist/permission/helpers/merge.d.ts.map +1 -1
  14. package/dist/permission/module.d.ts +2 -1
  15. package/dist/permission/module.d.ts.map +1 -1
  16. package/dist/permission/provider/types.d.ts +2 -1
  17. package/dist/permission/provider/types.d.ts.map +1 -1
  18. package/dist/permission/types.d.ts +4 -2
  19. package/dist/permission/types.d.ts.map +1 -1
  20. package/dist/policy/built-in/attribute-names/validator.d.ts +1 -1
  21. package/dist/policy/built-in/attribute-names/validator.d.ts.map +1 -1
  22. package/dist/policy/built-in/attributes/define.d.ts +3 -0
  23. package/dist/policy/built-in/attributes/define.d.ts.map +1 -0
  24. package/dist/policy/built-in/attributes/index.d.ts +1 -0
  25. package/dist/policy/built-in/attributes/index.d.ts.map +1 -1
  26. package/dist/policy/built-in/attributes/validator.d.ts +2 -3
  27. package/dist/policy/built-in/attributes/validator.d.ts.map +1 -1
  28. package/dist/policy/built-in/composite/validator.d.ts +2 -3
  29. package/dist/policy/built-in/composite/validator.d.ts.map +1 -1
  30. package/dist/policy/built-in/date/validator.d.ts +2 -3
  31. package/dist/policy/built-in/date/validator.d.ts.map +1 -1
  32. package/dist/policy/built-in/define.d.ts +4 -0
  33. package/dist/policy/built-in/define.d.ts.map +1 -0
  34. package/dist/policy/built-in/identity/validator.d.ts.map +1 -1
  35. package/dist/policy/built-in/index.d.ts +1 -0
  36. package/dist/policy/built-in/index.d.ts.map +1 -1
  37. package/dist/policy/built-in/realm-match/validator.d.ts +2 -3
  38. package/dist/policy/built-in/realm-match/validator.d.ts.map +1 -1
  39. package/dist/policy/built-in/time/evaluator.d.ts.map +1 -1
  40. package/dist/policy/built-in/time/helpers.d.ts +5 -0
  41. package/dist/policy/built-in/time/helpers.d.ts.map +1 -0
  42. package/dist/policy/built-in/time/index.d.ts +1 -0
  43. package/dist/policy/built-in/time/index.d.ts.map +1 -1
  44. package/dist/policy/built-in/time/validator.d.ts +2 -3
  45. package/dist/policy/built-in/time/validator.d.ts.map +1 -1
  46. package/dist/policy/built-in/types.d.ts +21 -1
  47. package/dist/policy/built-in/types.d.ts.map +1 -1
  48. package/dist/policy/error/module.d.ts +2 -2
  49. package/dist/policy/error/module.d.ts.map +1 -1
  50. package/dist/policy/evaluator/data/identity/validator.d.ts +1 -3
  51. package/dist/policy/evaluator/data/identity/validator.d.ts.map +1 -1
  52. package/dist/policy/evaluator/data/permission/validator.d.ts +1 -3
  53. package/dist/policy/evaluator/data/permission/validator.d.ts.map +1 -1
  54. package/dist/policy/evaluator/data/validator.d.ts +1 -3
  55. package/dist/policy/evaluator/data/validator.d.ts.map +1 -1
  56. package/dist/policy/types.d.ts +20 -4
  57. package/dist/policy/types.d.ts.map +1 -1
  58. package/package.json +8 -6
package/LICENSE CHANGED
@@ -186,7 +186,7 @@
186
186
  same "printed page" as the copyright notice for easier
187
187
  identification within third-party archives.
188
188
 
189
- Copyright 2021-2024 Peter Placzek
189
+ Copyright 2021-2025 Peter Placzek <peter.placzek1996@gmail.com>
190
190
 
191
191
  Licensed under the Apache License, Version 2.0 (the "License");
192
192
  you may not use this file except in compliance with the License.
package/dist/index.cjs CHANGED
@@ -7,78 +7,7 @@ var validup = require('validup');
7
7
  var zod = require('zod');
8
8
  var mongo2js = require('@ucast/mongo2js');
9
9
 
10
- class PermissionError extends Error {
11
- static notFound(name) {
12
- return new PermissionError({
13
- message: `The permission ${name} was not found.`,
14
- code: errors.ErrorCode.PERMISSION_NOT_FOUND
15
- });
16
- }
17
- static denied(name) {
18
- return new PermissionError({
19
- message: `The permission ${name} has not been granted.`,
20
- code: errors.ErrorCode.PERMISSION_DENIED
21
- });
22
- }
23
- static deniedAll(names) {
24
- return new PermissionError({
25
- message: `None of the permissions ${names.join(', ')} has been granted.`,
26
- code: errors.ErrorCode.PERMISSION_DENIED
27
- });
28
- }
29
- static evaluationFailed(options) {
30
- const error = new PermissionError({
31
- message: `The evaluation of permission ${options.name} failed.`,
32
- code: errors.ErrorCode.PERMISSION_EVALUATION_FAILED
33
- });
34
- if (options.policy) {
35
- error.policy = options.policy;
36
- }
37
- if (options.policyError) {
38
- error.policyError = options.policyError;
39
- }
40
- return error;
41
- }
42
- constructor(options = {}){
43
- super(options.message || 'A permission error occurred.');
44
- this.code = options.code ?? null;
45
- }
46
- }
47
-
48
- /*
49
- * Copyright (c) 2024-2024.
50
- * Author Peter Placzek (tada5hi)
51
- * For the full copyright and license information,
52
- * view the LICENSE file that was distributed with this source code.
53
- */ function isPermissionItemEqual(a, b) {
54
- if (a.name !== b.name) {
55
- return false;
56
- }
57
- if (typeof a.realm_id === 'string' || typeof b.realm_id === 'string') {
58
- return a.realm_id === b.realm_id;
59
- }
60
- return !!a.realm_id === !!b.realm_id;
61
- }
62
-
63
- /*
64
- * Copyright (c) 2024-2024.
65
- * Author Peter Placzek (tada5hi)
66
- * For the full copyright and license information,
67
- * view the LICENSE file that was distributed with this source code.
68
- */ var DecisionStrategy = /*#__PURE__*/ function(DecisionStrategy) {
69
- /**
70
- * One or more positive
71
- */ DecisionStrategy["AFFIRMATIVE"] = "affirmative";
72
- /**
73
- * All positive
74
- */ DecisionStrategy["UNANIMOUS"] = "unanimous";
75
- /**
76
- * More positive than negative
77
- */ DecisionStrategy["CONSENSUS"] = "consensus";
78
- return DecisionStrategy;
79
- }({});
80
-
81
- class PolicyError extends Error {
10
+ class PolicyError extends errors.AuthupError {
82
11
  static evaluatorNotFound(type) {
83
12
  return new PolicyError(`No evaluator is registered to handle the policy: ${type}`, errors.ErrorCode.POLICY_EVALUATOR_NOT_FOUND);
84
13
  }
@@ -89,8 +18,10 @@ class PolicyError extends Error {
89
18
  throw new PolicyError('The evaluator context is not valid.', errors.ErrorCode.POLICY_EVALUATOR_CONTEXT_INVALID);
90
19
  }
91
20
  constructor(message, code){
92
- super(message);
93
- this.code = code ?? null;
21
+ super({
22
+ message,
23
+ code
24
+ });
94
25
  }
95
26
  }
96
27
 
@@ -147,8 +78,9 @@ class PolicyError extends Error {
147
78
 
148
79
  class AttributeNamesPolicyValidator extends validup.Container {
149
80
  initialize() {
81
+ super.initialize();
150
82
  this.mount('names', adapterZod.createValidator(zod.z.array(zod.z.string().min(3).max(128))));
151
- this.mount('invert', adapterZod.createValidator(zod.z.boolean().optional()));
83
+ this.mount('invert', adapterZod.createValidator(zod.z.boolean().or(zod.z.null()).or(zod.z.undefined()).optional()));
152
84
  }
153
85
  }
154
86
 
@@ -184,14 +116,20 @@ class AttributeNamesPolicyEvaluator {
184
116
  }
185
117
  }
186
118
 
119
+ /*
120
+ * Copyright (c) 2025.
121
+ * Author Peter Placzek (tada5hi)
122
+ * For the full copyright and license information,
123
+ * view the LICENSE file that was distributed with this source code.
124
+ */ function defineAttributesPolicy(data) {
125
+ return data;
126
+ }
127
+
187
128
  class AttributesPolicyValidator extends validup.Container {
188
- mountAll() {
129
+ initialize() {
130
+ super.initialize();
189
131
  this.mount('query', adapterZod.createValidator(zod.z.object({}).passthrough()));
190
- this.mount('invert', adapterZod.createValidator(zod.z.boolean().optional()));
191
- }
192
- constructor(options = {}){
193
- super(options);
194
- this.mountAll();
132
+ this.mount('invert', adapterZod.createValidator(zod.z.boolean().or(zod.z.null()).or(zod.z.undefined()).optional()));
195
133
  }
196
134
  }
197
135
 
@@ -238,35 +176,50 @@ class AttributesPolicyEvaluator {
238
176
  }
239
177
  }
240
178
 
179
+ /*
180
+ * Copyright (c) 2024-2024.
181
+ * Author Peter Placzek (tada5hi)
182
+ * For the full copyright and license information,
183
+ * view the LICENSE file that was distributed with this source code.
184
+ */ var DecisionStrategy = /*#__PURE__*/ function(DecisionStrategy) {
185
+ /**
186
+ * One or more positive
187
+ */ DecisionStrategy["AFFIRMATIVE"] = "affirmative";
188
+ /**
189
+ * All positive
190
+ */ DecisionStrategy["UNANIMOUS"] = "unanimous";
191
+ /**
192
+ * More positive than negative
193
+ */ DecisionStrategy["CONSENSUS"] = "consensus";
194
+ return DecisionStrategy;
195
+ }({});
196
+
241
197
  class PolicyDataIdentityValidator extends validup.Container {
242
- mountAll() {
198
+ initialize() {
199
+ super.initialize();
243
200
  this.mount('type', adapterZod.createValidator(zod.z.string().min(3).max(128)));
244
201
  this.mount('id', adapterZod.createValidator(zod.z.string().uuid()));
245
- this.mount('realmId', adapterZod.createValidator(zod.z.string().uuid().optional()));
246
- this.mount('realmName', adapterZod.createValidator(zod.z.string().min(3).max(128).optional()));
247
- }
248
- constructor(options = {}){
249
- super(options);
250
- this.mountAll();
202
+ this.mount('clientId', adapterZod.createValidator(zod.z.string().uuid().or(zod.z.null()).or(zod.z.undefined()).optional()));
203
+ this.mount('realmId', adapterZod.createValidator(zod.z.string().uuid().or(zod.z.null()).or(zod.z.undefined()).optional()));
204
+ this.mount('realmName', adapterZod.createValidator(zod.z.string().min(3).max(128).or(zod.z.null()).or(zod.z.undefined()).optional()));
251
205
  }
252
206
  }
253
207
 
254
208
  class PolicyDataPermissionValidator extends validup.Container {
255
- mountAll() {
209
+ initialize() {
210
+ super.initialize();
256
211
  this.mount('name', adapterZod.createValidator(zod.z.string().min(3).max(256)));
257
- this.mount('realm_id', adapterZod.createValidator(zod.z.string().uuid().optional()));
212
+ this.mount('clientId', adapterZod.createValidator(zod.z.string().uuid().or(zod.z.null()).or(zod.z.undefined()).optional()));
213
+ this.mount('realmId', adapterZod.createValidator(zod.z.string().uuid().or(zod.z.null()).or(zod.z.undefined()).optional()));
258
214
  this.mount('policy', adapterZod.createValidator(zod.z.object({
259
215
  type: zod.z.string()
260
216
  }).optional()));
261
217
  }
262
- constructor(options = {}){
263
- super(options);
264
- this.mountAll();
265
- }
266
218
  }
267
219
 
268
220
  class PolicyDataValidator extends validup.Container {
269
- mountAll() {
221
+ initialize() {
222
+ super.initialize();
270
223
  // todo: optionalValue should be null
271
224
  const identity = new PolicyDataIdentityValidator();
272
225
  this.mount('identity', {
@@ -284,10 +237,6 @@ class PolicyDataValidator extends validup.Container {
284
237
  this.mount('attributes', adapterZod.createValidator(zod.z.object({}).optional()));
285
238
  this.mount('dateTime', adapterZod.createValidator(zod.z.date().or(zod.z.string()).or(zod.z.number()).optional()));
286
239
  }
287
- constructor(options = {}){
288
- super(options);
289
- this.mountAll();
290
- }
291
240
  }
292
241
 
293
242
  async function evaluatePolicy(ctx) {
@@ -337,16 +286,13 @@ function isCompositePolicy(input) {
337
286
  }
338
287
 
339
288
  class CompositePolicyValidator extends validup.Container {
340
- mountAll() {
341
- this.mount('decisionStrategy', adapterZod.createValidator(zod.z.nativeEnum(DecisionStrategy).optional()));
289
+ initialize() {
290
+ super.initialize();
291
+ this.mount('decisionStrategy', adapterZod.createValidator(zod.z.nativeEnum(DecisionStrategy).or(zod.z.null()).or(zod.z.undefined()).optional()));
342
292
  this.mount('children', adapterZod.createValidator(zod.z.array(zod.z.object({
343
293
  type: zod.z.string().min(3)
344
294
  }).passthrough())));
345
- this.mount('invert', adapterZod.createValidator(zod.z.boolean().optional()));
346
- }
347
- constructor(options = {}){
348
- super(options);
349
- this.mountAll();
295
+ this.mount('invert', adapterZod.createValidator(zod.z.boolean().or(zod.z.null()).or(zod.z.undefined()).optional()));
350
296
  }
351
297
  }
352
298
 
@@ -397,14 +343,11 @@ class CompositePolicyEvaluator {
397
343
  }
398
344
 
399
345
  class DatePolicyValidator extends validup.Container {
400
- mountAll() {
401
- this.mount('start', adapterZod.createValidator(zod.z.date().or(zod.z.string()).or(zod.z.number()).optional()));
402
- this.mount('end', adapterZod.createValidator(zod.z.date().or(zod.z.string()).or(zod.z.number()).optional()));
403
- this.mount('invert', adapterZod.createValidator(zod.z.boolean().optional()));
404
- }
405
- constructor(options = {}){
406
- super(options);
407
- this.mountAll();
346
+ initialize() {
347
+ super.initialize();
348
+ this.mount('start', adapterZod.createValidator(zod.z.date().or(zod.z.string().date()).or(zod.z.number()).or(zod.z.null()).or(zod.z.undefined()).optional()));
349
+ this.mount('end', adapterZod.createValidator(zod.z.date().or(zod.z.string().date()).or(zod.z.number()).or(zod.z.null()).or(zod.z.undefined()).optional()));
350
+ this.mount('invert', adapterZod.createValidator(zod.z.boolean().or(zod.z.undefined()).or(zod.z.null()).optional()));
408
351
  }
409
352
  }
410
353
 
@@ -458,8 +401,8 @@ class DatePolicyEvaluator {
458
401
 
459
402
  class IdentityPolicyValidator extends validup.Container {
460
403
  initialize() {
461
- this.mount('types', adapterZod.createValidator(zod.z.array(zod.z.string()).optional()));
462
- this.mount('invert', adapterZod.createValidator(zod.z.boolean().optional()));
404
+ this.mount('types', adapterZod.createValidator(zod.z.array(zod.z.string()).or(zod.z.null()).or(zod.z.undefined()).optional()));
405
+ this.mount('invert', adapterZod.createValidator(zod.z.boolean().or(zod.z.null()).or(zod.z.undefined()).optional()));
463
406
  }
464
407
  }
465
408
 
@@ -516,17 +459,14 @@ class PermissionBindingPolicyEvaluator {
516
459
  }
517
460
 
518
461
  class RealmMatchPolicyValidator extends validup.Container {
519
- mountAll() {
520
- this.mount('decisionStrategy', adapterZod.createValidator(zod.z.nativeEnum(DecisionStrategy).optional()));
521
- this.mount('attributeName', adapterZod.createValidator(zod.z.string().min(3).or(zod.z.array(zod.z.string().min(3))).optional()));
522
- this.mount('attributeNameStrict', adapterZod.createValidator(zod.z.boolean().optional()));
523
- this.mount('attributeNullMatchAll', adapterZod.createValidator(zod.z.boolean().optional()));
524
- this.mount('identityMasterMatchAll', adapterZod.createValidator(zod.z.boolean().optional()));
525
- this.mount('invert', adapterZod.createValidator(zod.z.boolean().optional()));
526
- }
527
- constructor(options = {}){
528
- super(options);
529
- this.mountAll();
462
+ initialize() {
463
+ super.initialize();
464
+ this.mount('decisionStrategy', adapterZod.createValidator(zod.z.nativeEnum(DecisionStrategy).or(zod.z.null()).or(zod.z.undefined()).optional()));
465
+ this.mount('attributeName', adapterZod.createValidator(zod.z.string().min(3).or(zod.z.array(zod.z.string().min(3))).or(zod.z.null()).or(zod.z.undefined()).optional()));
466
+ this.mount('attributeNameStrict', adapterZod.createValidator(zod.z.boolean().or(zod.z.null()).or(zod.z.undefined()).optional()));
467
+ this.mount('attributeNullMatchAll', adapterZod.createValidator(zod.z.boolean().or(zod.z.null()).or(zod.z.undefined()).optional()));
468
+ this.mount('identityMasterMatchAll', adapterZod.createValidator(zod.z.boolean().or(zod.z.null()).or(zod.z.undefined()).optional()));
469
+ this.mount('invert', adapterZod.createValidator(zod.z.boolean().or(zod.z.null()).or(zod.z.undefined()).optional()));
530
470
  }
531
471
  }
532
472
 
@@ -633,23 +573,30 @@ class RealmMatchPolicyEvaluator {
633
573
  return TimePolicyInterval;
634
574
  }({});
635
575
 
576
+ function isIntervalForDayOfWeek(interval) {
577
+ return interval === TimePolicyInterval.WEEKLY || interval === TimePolicyInterval.MONTHLY || interval === TimePolicyInterval.YEARLY;
578
+ }
579
+ function isIntervalForDayOfMonth(interval) {
580
+ return interval === TimePolicyInterval.MONTHLY || interval === TimePolicyInterval.YEARLY;
581
+ }
582
+ function isIntervalForDayOfYear(interval) {
583
+ return interval === TimePolicyInterval.YEARLY;
584
+ }
585
+
636
586
  class TimePolicyValidator extends validup.Container {
637
- mountAll() {
638
- this.mount('dayOfWeek', adapterZod.createValidator(zod.z.number().min(0).max(6).optional()));
639
- this.mount('dayOfMonth', adapterZod.createValidator(zod.z.number().min(1).max(31).optional()));
640
- this.mount('dayOfYear', adapterZod.createValidator(zod.z.number().min(1).max(366).optional()));
641
- this.mount('start', adapterZod.createValidator(zod.z.date().or(zod.z.string()).or(zod.z.number()).optional()));
642
- this.mount('end', adapterZod.createValidator(zod.z.date().or(zod.z.string()).or(zod.z.number()).optional()));
643
- this.mount('interval', adapterZod.createValidator(zod.z.nativeEnum(TimePolicyInterval).optional()));
644
- this.mount('invert', adapterZod.createValidator(zod.z.boolean().optional()));
645
- }
646
- constructor(options = {}){
647
- super(options);
648
- this.mountAll();
587
+ initialize() {
588
+ super.initialize();
589
+ this.mount('dayOfWeek', adapterZod.createValidator(zod.z.number().min(0).max(6).or(zod.z.null()).or(zod.z.undefined()).optional()));
590
+ this.mount('dayOfMonth', adapterZod.createValidator(zod.z.number().min(1).max(31).or(zod.z.null()).or(zod.z.undefined()).optional()));
591
+ this.mount('dayOfYear', adapterZod.createValidator(zod.z.number().min(1).max(366).or(zod.z.null()).or(zod.z.undefined()).optional()));
592
+ this.mount('start', adapterZod.createValidator(zod.z.date().or(zod.z.string().datetime()).or(zod.z.string().time()).or(zod.z.number()).or(zod.z.null()).or(zod.z.undefined()).optional()));
593
+ this.mount('end', adapterZod.createValidator(zod.z.date().or(zod.z.string().datetime()).or(zod.z.string().time()).or(zod.z.number()).or(zod.z.null()).or(zod.z.undefined()).optional()));
594
+ this.mount('interval', adapterZod.createValidator(zod.z.nativeEnum(TimePolicyInterval).or(zod.z.null()).or(zod.z.undefined()).optional()));
595
+ this.mount('invert', adapterZod.createValidator(zod.z.boolean().or(zod.z.undefined()).or(zod.z.null()).optional()));
649
596
  }
650
597
  }
651
598
 
652
- const timeRegex = /^(?:[01]\d|2[0-3]):[0-5]\d$/;
599
+ const timeRegex = /^(?:[01]\d|2[0-3]):[0-5]\d(?::[0-5]\d)?$/;
653
600
  function normalizeDate(input, dateRef) {
654
601
  const date = dateRef ? new Date(dateRef) : new Date();
655
602
  date.setHours(input.getHours(), input.getMinutes());
@@ -699,23 +646,25 @@ class TimePolicyEvaluator {
699
646
  return maybeInvertPolicyOutcome(false, ctx.spec.invert);
700
647
  }
701
648
  }
702
- if (ctx.spec.dayOfWeek) {
703
- if (now.getDay() !== ctx.spec.dayOfWeek) {
704
- return maybeInvertPolicyOutcome(false, ctx.spec.invert);
649
+ if (ctx.spec.interval) {
650
+ if (isIntervalForDayOfWeek(ctx.spec.interval) && ctx.spec.dayOfWeek) {
651
+ if (now.getDay() !== ctx.spec.dayOfWeek) {
652
+ return maybeInvertPolicyOutcome(false, ctx.spec.invert);
653
+ }
705
654
  }
706
- }
707
- if (ctx.spec.dayOfMonth) {
708
- if (now.getDate() !== ctx.spec.dayOfMonth) {
709
- return maybeInvertPolicyOutcome(false, ctx.spec.invert);
655
+ if (isIntervalForDayOfMonth(ctx.spec.interval) && ctx.spec.dayOfMonth) {
656
+ if (now.getDate() !== ctx.spec.dayOfMonth) {
657
+ return maybeInvertPolicyOutcome(false, ctx.spec.invert);
658
+ }
710
659
  }
711
- }
712
- if (ctx.spec.dayOfYear) {
713
- const start = new Date(now.getFullYear(), 0, 0);
714
- const diff = now.getTime() - start.getTime() + (start.getTimezoneOffset() - now.getTimezoneOffset()) * 60 * 1000;
715
- const oneDay = 1000 * 60 * 60 * 24;
716
- const dayOfYear = Math.floor(diff / oneDay);
717
- if (dayOfYear !== ctx.spec.dayOfYear) {
718
- return maybeInvertPolicyOutcome(false, ctx.spec.invert);
660
+ if (isIntervalForDayOfYear(ctx.spec.interval) && ctx.spec.dayOfYear) {
661
+ const start = new Date(now.getFullYear(), 0, 0);
662
+ const diff = now.getTime() - start.getTime() + (start.getTimezoneOffset() - now.getTimezoneOffset()) * 60 * 1000;
663
+ const oneDay = 1000 * 60 * 60 * 24;
664
+ const dayOfYear = Math.floor(diff / oneDay);
665
+ if (dayOfYear !== ctx.spec.dayOfYear) {
666
+ return maybeInvertPolicyOutcome(false, ctx.spec.invert);
667
+ }
719
668
  }
720
669
  }
721
670
  return maybeInvertPolicyOutcome(true, ctx.spec.invert);
@@ -725,6 +674,18 @@ class TimePolicyEvaluator {
725
674
  }
726
675
  }
727
676
 
677
+ /*
678
+ * Copyright (c) 2025.
679
+ * Author Peter Placzek (tada5hi)
680
+ * For the full copyright and license information,
681
+ * view the LICENSE file that was distributed with this source code.
682
+ */ function definePolicyWithType(type, data) {
683
+ return {
684
+ ...data,
685
+ type
686
+ };
687
+ }
688
+
728
689
  /**
729
690
  * The policy engine is a component that interprets defined policies and makes decisions
730
691
  * on whether to allow or deny a particular access.
@@ -766,9 +727,80 @@ class TimePolicyEvaluator {
766
727
  }
767
728
  }
768
729
 
730
+ class PermissionError extends errors.AuthupError {
731
+ static notFound(name) {
732
+ return new PermissionError({
733
+ message: `The permission ${name} was not found.`,
734
+ code: errors.ErrorCode.PERMISSION_NOT_FOUND
735
+ });
736
+ }
737
+ static denied(name) {
738
+ return new PermissionError({
739
+ message: `The permission ${name} has not been granted.`,
740
+ code: errors.ErrorCode.PERMISSION_DENIED
741
+ });
742
+ }
743
+ static deniedAll(names) {
744
+ return new PermissionError({
745
+ message: `None of the permissions ${names.join(', ')} has been granted.`,
746
+ code: errors.ErrorCode.PERMISSION_DENIED
747
+ });
748
+ }
749
+ static evaluationFailed(options) {
750
+ const error = new PermissionError({
751
+ message: `The evaluation of permission ${options.name} failed.`,
752
+ code: errors.ErrorCode.PERMISSION_EVALUATION_FAILED
753
+ });
754
+ if (options.policy) {
755
+ error.policy = options.policy;
756
+ if (options.policy.type === BuiltInPolicyType.IDENTITY) {
757
+ error.statusCode = 401;
758
+ }
759
+ }
760
+ if (options.policyError) {
761
+ error.policyError = options.policyError;
762
+ }
763
+ return error;
764
+ }
765
+ constructor(options = {}){
766
+ super({
767
+ ...options,
768
+ message: options.message || 'A permission error occurred.',
769
+ statusCode: options.statusCode || 403
770
+ });
771
+ }
772
+ }
773
+
774
+ /*
775
+ * Copyright (c) 2025.
776
+ * Author Peter Placzek (tada5hi)
777
+ * For the full copyright and license information,
778
+ * view the LICENSE file that was distributed with this source code.
779
+ */ function buildPermissionItemKey(input) {
780
+ return `${input.realmId || '_'}/${input.clientId || '_'}/${input.name}`;
781
+ }
782
+
783
+ /*
784
+ * Copyright (c) 2024-2024.
785
+ * Author Peter Placzek (tada5hi)
786
+ * For the full copyright and license information,
787
+ * view the LICENSE file that was distributed with this source code.
788
+ */ function isPermissionItemEqual(a, b) {
789
+ if (a.name !== b.name) {
790
+ return false;
791
+ }
792
+ if (typeof a.realmId === 'string' || typeof b.realmId === 'string') {
793
+ return a.realmId === b.realmId;
794
+ }
795
+ if (typeof a.clientId === 'string' || typeof b.clientId === 'string') {
796
+ return a.clientId === b.clientId;
797
+ }
798
+ return !!a.realmId === !!b.realmId && !!a.clientId === !!b.clientId;
799
+ }
800
+
769
801
  function mergePermissionItems(input) {
770
802
  const grouped = input.reduce((previous, current)=>{
771
- const key = current.realm_id || `/${current.name}`;
803
+ const key = buildPermissionItemKey(current);
772
804
  if (!previous[key]) {
773
805
  previous[key] = [];
774
806
  }
@@ -799,11 +831,11 @@ function mergePermissionItems(input) {
799
831
 
800
832
  class PermissionMemoryProvider {
801
833
  async get(options) {
802
- return this.items[`${options.realmId || '/'}:${options.name}`];
834
+ return this.items[buildPermissionItemKey(options)];
803
835
  }
804
836
  setMany(input) {
805
837
  this.items = mergePermissionItems(input).reduce((prev, current)=>{
806
- prev[`${current.realm_id || '/'}:${current.name}`] = current;
838
+ prev[buildPermissionItemKey(current)] = current;
807
839
  return prev;
808
840
  }, {});
809
841
  }
@@ -823,7 +855,10 @@ class PermissionChecker {
823
855
  const options = {
824
856
  name: input
825
857
  };
826
- if (typeof this.realmId !== 'undefined') {
858
+ if (this.clientId) {
859
+ options.clientId = this.clientId;
860
+ }
861
+ if (this.realmId) {
827
862
  options.realmId = this.realmId;
828
863
  }
829
864
  return this.provider.get(options);
@@ -852,7 +887,11 @@ class PermissionChecker {
852
887
  for(let i = 0; i < ctx.name.length; i++){
853
888
  const entity = await this.get(ctx.name[i]);
854
889
  if (!entity) {
855
- throw PermissionError.notFound(ctx.name[i]);
890
+ lastError = PermissionError.notFound(ctx.name[i]);
891
+ if (decisionStrategy === DecisionStrategy.UNANIMOUS) {
892
+ throw lastError;
893
+ }
894
+ continue;
856
895
  }
857
896
  if (!entity.policy) {
858
897
  if (decisionStrategy === DecisionStrategy.AFFIRMATIVE) {
@@ -961,6 +1000,9 @@ class PermissionChecker {
961
1000
  } else {
962
1001
  this.provider = new PermissionMemoryProvider();
963
1002
  }
1003
+ if (options.clientId) {
1004
+ this.clientId = options.clientId;
1005
+ }
964
1006
  if (options.realmId) {
965
1007
  this.realmId = options.realmId;
966
1008
  }
@@ -999,8 +1041,14 @@ exports.RealmMatchPolicyValidator = RealmMatchPolicyValidator;
999
1041
  exports.TimePolicyEvaluator = TimePolicyEvaluator;
1000
1042
  exports.TimePolicyInterval = TimePolicyInterval;
1001
1043
  exports.TimePolicyValidator = TimePolicyValidator;
1044
+ exports.buildPermissionItemKey = buildPermissionItemKey;
1045
+ exports.defineAttributesPolicy = defineAttributesPolicy;
1046
+ exports.definePolicyWithType = definePolicyWithType;
1002
1047
  exports.evaluatePolicy = evaluatePolicy;
1003
1048
  exports.isCompositePolicy = isCompositePolicy;
1049
+ exports.isIntervalForDayOfMonth = isIntervalForDayOfMonth;
1050
+ exports.isIntervalForDayOfWeek = isIntervalForDayOfWeek;
1051
+ exports.isIntervalForDayOfYear = isIntervalForDayOfYear;
1004
1052
  exports.isPermissionItemEqual = isPermissionItemEqual;
1005
1053
  exports.maybeInvertPolicyOutcome = maybeInvertPolicyOutcome;
1006
1054
  exports.mergePermissionItems = mergePermissionItems;