@blamejs/core 0.7.106 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/CHANGELOG.md +19 -1
  2. package/NOTICE +17 -1
  3. package/README.md +4 -3
  4. package/index.js +16 -0
  5. package/lib/asyncapi-bindings.js +160 -0
  6. package/lib/asyncapi-traits.js +143 -0
  7. package/lib/asyncapi.js +531 -0
  8. package/lib/audit.js +6 -0
  9. package/lib/auth/acr-vocabulary.js +265 -0
  10. package/lib/auth/auth-time-tracker.js +111 -0
  11. package/lib/auth/elevation-grant.js +306 -0
  12. package/lib/auth/sd-jwt-vc-disclosure.js +95 -0
  13. package/lib/auth/sd-jwt-vc-holder.js +203 -0
  14. package/lib/auth/sd-jwt-vc-issuer.js +197 -0
  15. package/lib/auth/sd-jwt-vc.js +526 -0
  16. package/lib/auth/step-up-policy.js +335 -0
  17. package/lib/auth/step-up.js +445 -0
  18. package/lib/compliance-ai-act-logging.js +186 -0
  19. package/lib/compliance-ai-act-prohibited.js +205 -0
  20. package/lib/compliance-ai-act-risk.js +189 -0
  21. package/lib/compliance-ai-act-transparency.js +200 -0
  22. package/lib/compliance-ai-act.js +558 -0
  23. package/lib/compliance.js +2 -0
  24. package/lib/crypto.js +32 -0
  25. package/lib/flag-cache.js +136 -0
  26. package/lib/flag-evaluation-context.js +135 -0
  27. package/lib/flag-providers.js +279 -0
  28. package/lib/flag-targeting.js +210 -0
  29. package/lib/flag.js +284 -0
  30. package/lib/inbox.js +367 -0
  31. package/lib/mail-arc-sign.js +372 -0
  32. package/lib/mail-auth.js +2 -0
  33. package/lib/middleware/ai-act-disclosure.js +166 -0
  34. package/lib/middleware/asyncapi-serve.js +136 -0
  35. package/lib/middleware/flag-context.js +76 -0
  36. package/lib/middleware/index.js +15 -0
  37. package/lib/middleware/openapi-serve.js +143 -0
  38. package/lib/middleware/require-step-up.js +186 -0
  39. package/lib/openapi-paths-builder.js +248 -0
  40. package/lib/openapi-schema-walk.js +192 -0
  41. package/lib/openapi-security.js +169 -0
  42. package/lib/openapi-yaml.js +154 -0
  43. package/lib/openapi.js +443 -0
  44. package/lib/pqc-software.js +195 -0
  45. package/lib/vault/index.js +3 -0
  46. package/lib/vault-aad.js +259 -0
  47. package/lib/vendor/MANIFEST.json +29 -0
  48. package/lib/vendor/noble-post-quantum.cjs +18 -0
  49. package/lib/ws-client.js +829 -0
  50. package/package.json +1 -1
  51. package/sbom.cyclonedx.json +6 -6
@@ -0,0 +1,335 @@
1
+ "use strict";
2
+ /**
3
+ * Step-up policy DSL — compose RFC 9470 step-up requirements as a
4
+ * fluent expression rather than a flat object. Useful for routes that
5
+ * need "ACR >= loa3 OR a fresh hardware-key auth within the last 5 min".
6
+ *
7
+ * var policy = b.auth.stepUp.policy
8
+ * .acr("loa3")
9
+ * .and(b.auth.stepUp.policy.maxAge(300))
10
+ * .or(
11
+ * b.auth.stepUp.policy.amr(["hwk", "pop"])
12
+ * .and(b.auth.stepUp.policy.maxAge(120))
13
+ * );
14
+ *
15
+ * var result = policy.evaluate(claims);
16
+ *
17
+ * var middleware = policy.middleware({ realm: "billing-api" });
18
+ *
19
+ * The policy compiles down to RFC 9470 challenges by extracting the
20
+ * outermost-feasible (acr, maxAge, amr, ...) tuple. When an operator's
21
+ * policy is genuinely or-of-and-of-..., the challenge emitted is the
22
+ * UNION of individually-required atoms (so the IdP knows what to ask
23
+ * for) plus an `error_description` hint that there are alternatives.
24
+ *
25
+ * The DSL is pure. All node types are immutable once constructed;
26
+ * chaining returns a new policy object.
27
+ */
28
+
29
+ var lazyRequire = require("../lazy-require");
30
+ var validateOpts = require("../validate-opts");
31
+ var { AuthError } = require("../framework-error");
32
+
33
+ var stepUp = lazyRequire(function () { return require("./step-up"); });
34
+ var requireStepUp = lazyRequire(function () { return require("../middleware/require-step-up"); });
35
+
36
+ function _mkNode(spec) {
37
+ spec.evaluate = function (claims) {
38
+ return spec._run(claims);
39
+ };
40
+ spec.toRequirement = function () {
41
+ return spec._toReq();
42
+ };
43
+ spec.and = function (other) {
44
+ return _and(spec, other);
45
+ };
46
+ spec.or = function (other) {
47
+ return _or(spec, other);
48
+ };
49
+ spec.not = function () {
50
+ return _not(spec);
51
+ };
52
+ spec.middleware = function (opts) {
53
+ opts = opts || {};
54
+ return requireStepUp().create(Object.assign({}, opts, {
55
+ requirement: spec._toReq(),
56
+ }));
57
+ };
58
+ return Object.freeze(spec);
59
+ }
60
+
61
+ function acr(value) {
62
+ validateOpts.requireNonEmptyString(value, "policy.acr: value", AuthError, "auth-stepUp/bad-acr");
63
+ return _mkNode({
64
+ kind: "acr",
65
+ value: value,
66
+ _run: function (claims) {
67
+ var result = stepUp().evaluate({
68
+ claims: claims,
69
+ requirement: { acr: value },
70
+ });
71
+ return { ok: result.ok === true, atom: "acr:" + value, reason: result.reason || null };
72
+ },
73
+ _toReq: function () { return { acr: value }; },
74
+ });
75
+ }
76
+
77
+ function acrAny(values) {
78
+ if (!Array.isArray(values) || values.length === 0) {
79
+ throw new AuthError("auth-stepUp/bad-policy",
80
+ "policy.acrAny: values must be a non-empty array");
81
+ }
82
+ for (var i = 0; i < values.length; i += 1) {
83
+ validateOpts.requireNonEmptyString(values[i],
84
+ "policy.acrAny: values[" + i + "]", AuthError, "auth-stepUp/bad-acr");
85
+ }
86
+ var copy = values.slice();
87
+ return _mkNode({
88
+ kind: "acrAny",
89
+ values: copy,
90
+ _run: function (claims) {
91
+ var result = stepUp().evaluate({
92
+ claims: claims,
93
+ requirement: { acrValues: copy },
94
+ });
95
+ return { ok: result.ok === true, atom: "acrAny:" + copy.join(","), reason: result.reason || null };
96
+ },
97
+ _toReq: function () { return { acrValues: copy }; },
98
+ });
99
+ }
100
+
101
+ function amr(required) {
102
+ if (!Array.isArray(required) || required.length === 0) {
103
+ throw new AuthError("auth-stepUp/bad-policy",
104
+ "policy.amr: required must be a non-empty array");
105
+ }
106
+ for (var i = 0; i < required.length; i += 1) {
107
+ validateOpts.requireNonEmptyString(required[i],
108
+ "policy.amr: required[" + i + "]", AuthError, "auth-stepUp/bad-amr");
109
+ }
110
+ var copy = required.slice();
111
+ return _mkNode({
112
+ kind: "amr",
113
+ required: copy,
114
+ _run: function (claims) {
115
+ var result = stepUp().evaluate({
116
+ claims: claims,
117
+ requirement: { requiredAmr: copy },
118
+ });
119
+ return { ok: result.ok === true, atom: "amr:" + copy.join("+"), reason: result.reason || null };
120
+ },
121
+ _toReq: function () { return { requiredAmr: copy }; },
122
+ });
123
+ }
124
+
125
+ function phishingResistant() {
126
+ return _mkNode({
127
+ kind: "phishingResistant",
128
+ _run: function (claims) {
129
+ var result = stepUp().evaluate({
130
+ claims: claims,
131
+ requirement: { phishingResistant: true },
132
+ });
133
+ return { ok: result.ok === true, atom: "phr", reason: result.reason || null };
134
+ },
135
+ _toReq: function () { return { phishingResistant: true }; },
136
+ });
137
+ }
138
+
139
+ function maxAge(seconds) {
140
+ if (typeof seconds !== "number" || !isFinite(seconds) || seconds < 0) {
141
+ throw new AuthError("auth-stepUp/bad-policy",
142
+ "policy.maxAge: seconds must be a finite number >= 0 — got " +
143
+ JSON.stringify(seconds));
144
+ }
145
+ return _mkNode({
146
+ kind: "maxAge",
147
+ seconds: seconds,
148
+ _run: function (claims) {
149
+ var result = stepUp().evaluate({
150
+ claims: claims,
151
+ requirement: { maxAge: seconds },
152
+ });
153
+ return { ok: result.ok === true, atom: "maxAge:" + seconds, reason: result.reason || null };
154
+ },
155
+ _toReq: function () { return { maxAge: seconds }; },
156
+ });
157
+ }
158
+
159
+ function custom(name, fn) {
160
+ validateOpts.requireNonEmptyString(name, "policy.custom: name", AuthError, "auth-stepUp/bad-policy");
161
+ if (typeof fn !== "function") {
162
+ throw new AuthError("auth-stepUp/bad-policy",
163
+ "policy.custom: fn must be a function — got " + typeof fn);
164
+ }
165
+ return _mkNode({
166
+ kind: "custom",
167
+ name: name,
168
+ _run: function (claims) {
169
+ var ok = false;
170
+ try { ok = fn(claims) === true; } catch (_e) { ok = false; }
171
+ return { ok: ok, atom: "custom:" + name, reason: ok ? null : "custom predicate '" + name + "' returned false" };
172
+ },
173
+ _toReq: function () {
174
+ throw new AuthError("auth-stepUp/policy-no-challenge",
175
+ "policy.custom: cannot translate to RFC 9470 challenge — wrap in .or() with a translatable atom or use .middleware({ requirement: ... })");
176
+ },
177
+ });
178
+ }
179
+
180
+ function _and(left, right) {
181
+ return _mkNode({
182
+ kind: "and",
183
+ left: left,
184
+ right: right,
185
+ _run: function (claims) {
186
+ var l = left._run(claims);
187
+ if (!l.ok) return { ok: false, atom: "and(" + l.atom + ")", reason: l.reason };
188
+ var r = right._run(claims);
189
+ if (!r.ok) return { ok: false, atom: "and(" + l.atom + "," + r.atom + ")", reason: r.reason };
190
+ return { ok: true, atom: "and(" + l.atom + "," + r.atom + ")", reason: null };
191
+ },
192
+ _toReq: function () {
193
+ var lr = left._toReq();
194
+ var rr = right._toReq();
195
+ return _mergeAnd(lr, rr);
196
+ },
197
+ });
198
+ }
199
+
200
+ function _or(left, right) {
201
+ return _mkNode({
202
+ kind: "or",
203
+ left: left,
204
+ right: right,
205
+ _run: function (claims) {
206
+ var l = left._run(claims);
207
+ if (l.ok) return { ok: true, atom: "or(" + l.atom + ")", reason: null };
208
+ var r = right._run(claims);
209
+ if (r.ok) return { ok: true, atom: "or(" + r.atom + ")", reason: null };
210
+ return {
211
+ ok: false,
212
+ atom: "or(" + l.atom + "," + r.atom + ")",
213
+ reason: l.reason + " AND " + r.reason,
214
+ };
215
+ },
216
+ _toReq: function () {
217
+ // RFC 9470 doesn't support OR semantics in WWW-Authenticate. We
218
+ // pick the LEFT branch and emit its challenge — operator can
219
+ // override via .middleware({ requirement }).
220
+ return left._toReq();
221
+ },
222
+ });
223
+ }
224
+
225
+ function _not(inner) {
226
+ return _mkNode({
227
+ kind: "not",
228
+ inner: inner,
229
+ _run: function (claims) {
230
+ var i = inner._run(claims);
231
+ return { ok: !i.ok, atom: "not(" + i.atom + ")", reason: i.ok ? "not(" + i.atom + ") matched" : null };
232
+ },
233
+ _toReq: function () {
234
+ throw new AuthError("auth-stepUp/policy-no-challenge",
235
+ "policy.not: cannot translate to RFC 9470 challenge");
236
+ },
237
+ });
238
+ }
239
+
240
+ function _mergeAnd(a, b) {
241
+ var out = {};
242
+ if (a.acr || b.acr) {
243
+ if (a.acr && b.acr && a.acr !== b.acr) {
244
+ throw new AuthError("auth-stepUp/policy-conflict",
245
+ "policy.and: conflicting acr requirements " +
246
+ JSON.stringify(a.acr) + " and " + JSON.stringify(b.acr));
247
+ }
248
+ out.acr = a.acr || b.acr;
249
+ }
250
+ if (a.acrValues || b.acrValues) {
251
+ out.acrValues = (a.acrValues || []).concat(b.acrValues || []);
252
+ }
253
+ if (a.maxAge != null && b.maxAge != null) {
254
+ out.maxAge = Math.min(a.maxAge, b.maxAge); // tighter wins
255
+ } else if (a.maxAge != null) {
256
+ out.maxAge = a.maxAge;
257
+ } else if (b.maxAge != null) {
258
+ out.maxAge = b.maxAge;
259
+ }
260
+ if (a.requiredAmr || b.requiredAmr) {
261
+ var combined = (a.requiredAmr || []).concat(b.requiredAmr || []);
262
+ var seen = Object.create(null);
263
+ out.requiredAmr = [];
264
+ for (var i = 0; i < combined.length; i += 1) {
265
+ if (!seen[combined[i]]) {
266
+ seen[combined[i]] = true;
267
+ out.requiredAmr.push(combined[i]);
268
+ }
269
+ }
270
+ }
271
+ if (a.phishingResistant === true || b.phishingResistant === true) {
272
+ out.phishingResistant = true;
273
+ }
274
+ return out;
275
+ }
276
+
277
+ // ---- Common preset policies operators reach for ----
278
+
279
+ var C = require("../constants");
280
+ var SEC_5_MIN = C.TIME.minutes(5) / C.TIME.seconds(1);
281
+ var SEC_2_MIN = C.TIME.minutes(2) / C.TIME.seconds(1);
282
+ var SEC_15_MIN = C.TIME.minutes(15) / C.TIME.seconds(1);
283
+ var SEC_1_MIN = C.TIME.minutes(1) / C.TIME.seconds(1);
284
+
285
+ var PRESETS = {
286
+ // Sensitive write: ACR >= loa2 + auth_time within 5 min
287
+ sensitiveWrite: function () {
288
+ return acr("loa2").and(maxAge(SEC_5_MIN));
289
+ },
290
+ // Admin bulk: ACR >= loa3 + max_age 5 min + phishing-resistant
291
+ adminBulk: function () {
292
+ return acr("loa3").and(maxAge(SEC_5_MIN)).and(phishingResistant());
293
+ },
294
+ // Financial: phr-class hardware + max_age 2 min
295
+ financial: function () {
296
+ return acr("loa3").and(amr(["hwk"])).and(maxAge(SEC_2_MIN));
297
+ },
298
+ // PHI read: ACR >= loa2 + max_age 15 min
299
+ phiRead: function () {
300
+ return acr("loa2").and(maxAge(SEC_15_MIN));
301
+ },
302
+ // PHI write: ACR >= loa3 + max_age 5 min + phishing-resistant
303
+ phiWrite: function () {
304
+ return acr("loa3").and(maxAge(SEC_5_MIN)).and(phishingResistant());
305
+ },
306
+ // Account-recovery: phishing-resistant + max_age 1 min
307
+ accountRecovery: function () {
308
+ return phishingResistant().and(maxAge(SEC_1_MIN));
309
+ },
310
+ };
311
+
312
+ function preset(name) {
313
+ if (!Object.prototype.hasOwnProperty.call(PRESETS, name)) {
314
+ throw new AuthError("auth-stepUp/bad-preset",
315
+ "policy.preset: unknown preset " + JSON.stringify(name) +
316
+ " — valid presets: " + Object.keys(PRESETS).join(", "));
317
+ }
318
+ return PRESETS[name]();
319
+ }
320
+
321
+ function listPresets() {
322
+ return Object.keys(PRESETS).slice();
323
+ }
324
+
325
+ module.exports = {
326
+ acr: acr,
327
+ acrAny: acrAny,
328
+ amr: amr,
329
+ phishingResistant: phishingResistant,
330
+ maxAge: maxAge,
331
+ custom: custom,
332
+ preset: preset,
333
+ listPresets: listPresets,
334
+ PRESETS: PRESETS,
335
+ };