@blamejs/core 0.14.4 → 0.14.6

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 (43) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/README.md +1 -0
  3. package/lib/a2a-tasks.js +6 -6
  4. package/lib/ai-input.js +1 -1
  5. package/lib/auth/sd-jwt-vc.js +1 -1
  6. package/lib/calendar.js +6 -6
  7. package/lib/content-credentials.js +2 -2
  8. package/lib/cra-report.js +3 -3
  9. package/lib/guard-cidr.js +1 -1
  10. package/lib/http-client-cache.js +1 -1
  11. package/lib/mail-auth.js +1 -1
  12. package/lib/mail-crypto-smime.js +1 -1
  13. package/lib/mail-deploy.js +1 -1
  14. package/lib/mail-dkim.js +1 -1
  15. package/lib/mail-server-jmap.js +2 -2
  16. package/lib/mcp.js +6 -6
  17. package/lib/middleware/age-gate.js +20 -7
  18. package/lib/middleware/bearer-auth.js +36 -35
  19. package/lib/middleware/bot-guard.js +17 -5
  20. package/lib/middleware/compose-pipeline.js +1 -1
  21. package/lib/middleware/cors.js +28 -12
  22. package/lib/middleware/csrf-protect.js +22 -14
  23. package/lib/middleware/daily-byte-quota.js +27 -13
  24. package/lib/middleware/deny-response.js +140 -0
  25. package/lib/middleware/dpop.js +32 -19
  26. package/lib/middleware/fetch-metadata.js +21 -12
  27. package/lib/middleware/host-allowlist.js +19 -8
  28. package/lib/middleware/index.js +3 -0
  29. package/lib/middleware/network-allowlist.js +24 -10
  30. package/lib/middleware/rate-limit.js +22 -5
  31. package/lib/middleware/require-aal.js +25 -10
  32. package/lib/middleware/require-auth.js +32 -16
  33. package/lib/middleware/require-bound-key.js +49 -18
  34. package/lib/middleware/require-content-type.js +19 -8
  35. package/lib/middleware/require-methods.js +17 -7
  36. package/lib/middleware/require-mtls.js +27 -14
  37. package/lib/network.js +4 -4
  38. package/lib/safe-decompress.js +1 -1
  39. package/lib/safe-url.js +1 -1
  40. package/lib/stream-throttle.js +2 -2
  41. package/lib/websocket.js +2 -2
  42. package/package.json +1 -1
  43. package/sbom.cdx.json +6 -6
@@ -16,6 +16,7 @@
16
16
  */
17
17
 
18
18
  var lazyRequire = require("../lazy-require");
19
+ var denyResponse = require("./deny-response").denyResponse;
19
20
  var { defineClass } = require("../framework-error");
20
21
 
21
22
  var RequireMethodsError = defineClass("RequireMethodsError", { alwaysPermanent: true });
@@ -38,7 +39,9 @@ var observability = lazyRequire(function () { return require("../observability")
38
39
  *
39
40
  * @opts
40
41
  * {
41
- * audit: boolean, // default true
42
+ * audit: boolean, // default true
43
+ * onDeny: function(req, res, info): void, // own the 405; info = { status, reason, method, allowed }
44
+ * problemDetails: boolean, // default false — emit RFC 9457 application/problem+json instead of text/plain
42
45
  * }
43
46
  *
44
47
  * @example
@@ -69,18 +72,25 @@ function create(allowed, opts) {
69
72
  var allowHeader = normalized.join(", ");
70
73
  opts = opts || {};
71
74
  var auditOn = opts.audit !== false;
75
+ var onDeny = typeof opts.onDeny === "function" ? opts.onDeny : null;
76
+ var problemMode = opts.problemDetails === true;
72
77
 
73
78
  return function requireMethodsMiddleware(req, res, next) {
74
79
  var m = (req.method || "").toUpperCase();
75
80
  if (normalized.indexOf(m) !== -1) return next();
76
81
  if (!res.headersSent) {
77
- var body = "Method Not Allowed";
78
- res.writeHead(405, { // HTTP 405 status
79
- "Allow": allowHeader,
80
- "Content-Type": "text/plain; charset=utf-8",
81
- "Content-Length": Buffer.byteLength(body),
82
+ denyResponse(req, res, {
83
+ onDeny: onDeny,
84
+ problem: problemMode,
85
+ status: 405,
86
+ info: { status: 405, reason: "method-not-allowed", method: m, allowed: normalized },
87
+ problemCode: "method-not-allowed",
88
+ problemTitle: "Method Not Allowed",
89
+ problemDetail: "The " + m + " method is not allowed on this resource.",
90
+ headers: { "Allow": allowHeader },
91
+ contentType: "text/plain; charset=utf-8",
92
+ body: "Method Not Allowed",
82
93
  });
83
- res.end(body);
84
94
  }
85
95
  if (auditOn) {
86
96
  try {
@@ -48,6 +48,7 @@
48
48
  var defineClass = require("../framework-error").defineClass;
49
49
  var lazyRequire = require("../lazy-require");
50
50
  var validateOpts = require("../validate-opts");
51
+ var denyResponse = require("./deny-response").denyResponse;
51
52
 
52
53
  var bCrypto = lazyRequire(function () { return require("../crypto"); });
53
54
  var audit = lazyRequire(function () { return require("../audit"); });
@@ -84,6 +85,8 @@ function _normalizeFingerprintEntry(entry) {
84
85
  * fingerprintAllowList: string[],
85
86
  * denyList: string[],
86
87
  * onAuthenticated: function(req, res, next): void,
88
+ * onDeny: function(req, res, info): void, // own the refusal (mirrors onAuthenticated); info = { status, reason, ...metadata }
89
+ * problemDetails: boolean, // default false — emit RFC 9457 application/problem+json instead of the default JSON envelope
87
90
  * auditAction: string,
88
91
  * errorMessage: string,
89
92
  * audit: object,
@@ -100,7 +103,7 @@ function create(opts) {
100
103
  opts = opts || {};
101
104
  validateOpts(opts, [
102
105
  "fingerprintAllowList", "denyList",
103
- "onAuthenticated", "audit",
106
+ "onAuthenticated", "onDeny", "problemDetails", "audit",
104
107
  "auditAction", "errorMessage",
105
108
  ], "middleware.requireMtls");
106
109
 
@@ -109,6 +112,8 @@ function create(opts) {
109
112
  var denyList = Array.isArray(opts.denyList)
110
113
  ? opts.denyList.map(_normalizeFingerprintEntry) : [];
111
114
  var onAuthenticated = typeof opts.onAuthenticated === "function" ? opts.onAuthenticated : null;
115
+ var onDeny = typeof opts.onDeny === "function" ? opts.onDeny : null;
116
+ var problemMode = opts.problemDetails === true;
112
117
  var auditOn = opts.audit !== false;
113
118
  var actionBase = typeof opts.auditAction === "string" && opts.auditAction.length > 0
114
119
  ? opts.auditAction : "mtls.required";
@@ -126,16 +131,24 @@ function create(opts) {
126
131
  } catch (_e) { /* drop-silent — audit is best-effort, never blocks the request */ }
127
132
  }
128
133
 
129
- function _refuse(res, reason, metadata) {
134
+ function _refuse(req, res, reason, metadata) {
130
135
  _emit("denied", Object.assign({ reason: reason }, metadata || {}));
131
- if (typeof res.writeHead === "function") {
132
- res.writeHead(401, {
133
- "Content-Type": "application/json; charset=utf-8",
136
+ denyResponse(req, res, {
137
+ onDeny: onDeny,
138
+ problem: problemMode,
139
+ status: 401,
140
+ info: Object.assign({ status: 401, reason: reason }, metadata || {}),
141
+ problemCode: "client-certificate-required",
142
+ problemTitle: "Unauthorized",
143
+ problemDetail: errorMessage,
144
+ problemExt: { reason: reason },
145
+ headers: {
134
146
  "WWW-Authenticate": "Mutual",
135
147
  "Cache-Control": "no-store",
136
- });
137
- res.end(JSON.stringify({ error: errorMessage, reason: reason }));
138
- }
148
+ },
149
+ contentType: "application/json; charset=utf-8",
150
+ body: JSON.stringify({ error: errorMessage, reason: reason }),
151
+ });
139
152
  }
140
153
 
141
154
  return function requireMtlsMiddleware(req, res, next) {
@@ -158,10 +171,10 @@ function create(opts) {
158
171
 
159
172
  if (!authorized) {
160
173
  var authzError = (sock && sock.authorizationError) || "no-peer-cert";
161
- return _refuse(res, "tls-unauthorized", { authorizationError: String(authzError) });
174
+ return _refuse(req, res, "tls-unauthorized", { authorizationError: String(authzError) });
162
175
  }
163
176
  if (!peerCert || !peerCert.raw) {
164
- return _refuse(res, "no-peer-cert", {});
177
+ return _refuse(req, res, "no-peer-cert", {});
165
178
  }
166
179
 
167
180
  // Compute fingerprint via the framework's SHA3-512 helper. Buffer
@@ -171,17 +184,17 @@ function create(opts) {
171
184
  try {
172
185
  fp = bCrypto().hashCertFingerprint(peerCert.raw);
173
186
  } catch (e) {
174
- return _refuse(res, "fingerprint-failed", { error: (e && e.message) || String(e) });
187
+ return _refuse(req, res, "fingerprint-failed", { error: (e && e.message) || String(e) });
175
188
  }
176
189
 
177
190
  if (denyList.length > 0 && bCrypto().isCertRevoked(peerCert.raw, denyList)) {
178
- return _refuse(res, "fingerprint-on-deny-list", {
191
+ return _refuse(req, res, "fingerprint-on-deny-list", {
179
192
  fingerprint: fp.colon,
180
193
  subject: (peerCert.subject && peerCert.subject.CN) || null,
181
194
  });
182
195
  }
183
196
  if (allowList && allowList.length > 0 && !bCrypto().isCertRevoked(peerCert.raw, allowList)) {
184
- return _refuse(res, "fingerprint-not-allowed", {
197
+ return _refuse(req, res, "fingerprint-not-allowed", {
185
198
  fingerprint: fp.colon,
186
199
  subject: (peerCert.subject && peerCert.subject.CN) || null,
187
200
  });
@@ -199,7 +212,7 @@ function create(opts) {
199
212
  if (onAuthenticated) {
200
213
  try { return onAuthenticated(req, res, next); }
201
214
  catch (e) {
202
- return _refuse(res, "on-authenticated-threw", { error: (e && e.message) || String(e) });
215
+ return _refuse(req, res, "on-authenticated-threw", { error: (e && e.message) || String(e) });
203
216
  }
204
217
  }
205
218
  return next();
package/lib/network.js CHANGED
@@ -108,8 +108,8 @@ function _socketDefaults() {
108
108
  }
109
109
 
110
110
  /**
111
- * @primitive b.network.applyToSocket
112
- * @signature b.network.applyToSocket(socket)
111
+ * @primitive b.network.socket.applyToSocket
112
+ * @signature b.network.socket.applyToSocket(socket)
113
113
  * @since 0.7.68
114
114
  * @related b.network.bootFromEnv, b.network.snapshot
115
115
  *
@@ -124,7 +124,7 @@ function _socketDefaults() {
124
124
  * @example
125
125
  * var net = require("net");
126
126
  * var s = new net.Socket();
127
- * var ret = b.network.applyToSocket(s);
127
+ * var ret = b.network.socket.applyToSocket(s);
128
128
  * ret === s;
129
129
  * // → true
130
130
  * s.destroy();
@@ -164,7 +164,7 @@ var ntpFacade = {
164
164
  * @primitive b.network.bootFromEnv
165
165
  * @signature b.network.bootFromEnv(opts)
166
166
  * @since 0.7.68
167
- * @related b.network.snapshot, b.network.applyToSocket
167
+ * @related b.network.snapshot, b.network.socket.applyToSocket
168
168
  *
169
169
  * Read `BLAMEJS_*` environment variables once and apply the union to
170
170
  * the live network facade. Recognised keys cover NTP servers /
@@ -105,7 +105,7 @@ var _algorithms = {
105
105
  // classic bomb shapes (1000:1) while leaving headroom for legitimate
106
106
  // text / JSON / XML payloads (which compress 20-50:1 commonly). Per
107
107
  // RFC 8460 §5.2 community guidance for TLS-RPT report decompression.
108
- var DEFAULT_MAX_RATIO = 50; // allow:raw-byte-literal — RFC 8460 §5.2 community guidance / allow:raw-time-literal — RFC number not seconds
108
+ var DEFAULT_MAX_RATIO = 50; // allow:raw-time-literal — RFC number not seconds
109
109
 
110
110
  // Default input cap when operator omits opts.maxCompressedBytes —
111
111
  // 4 MiB matches the TLS-RPT receive surface and is a reasonable
package/lib/safe-url.js CHANGED
@@ -407,7 +407,7 @@ function format(url) {
407
407
  }
408
408
  // Constructing URL() is the path that surfaces the IDN-crash on
409
409
  // older Node — wrap so the listener never crashes.
410
- var u = new URL(url); // allow:raw-new-url — safeUrl.format wraps URL ctor for CVE-2026-21712; this IS the safe wrapper. // allow:raw-byte-literal — no byte literal; suppresses cross-detector false-positive from neighboring text
410
+ var u = new URL(url); // allow:raw-new-url — safeUrl.format wraps URL ctor for CVE-2026-21712; this IS the safe wrapper.
411
411
  return u.href;
412
412
  } catch (e) {
413
413
  if (e && e.isSafeUrlError) throw e;
@@ -71,9 +71,9 @@ var StreamThrottleError = defineClass("StreamThrottleError", { alwaysPermanent:
71
71
  // (bytes/sec ↔ wait-ms). This is a unit-conversion constant, not a
72
72
  // memory cap or protocol-byte literal; the framework's C.TIME / C.BYTES
73
73
  // helpers don't apply.
74
- var MS_PER_SECOND = 1000; // allow:raw-byte-literal — ms/sec unit conversion // allow:raw-time-literal — ms/sec unit conversion
74
+ var MS_PER_SECOND = 1000; // allow:raw-time-literal — ms/sec unit conversion
75
75
  var NS_PER_MS = 1e6; // ns/ms unit conversion
76
- var MS_PER_SECOND_HRTIME = 1000; // allow:raw-byte-literal — hrtime seconds→ms // allow:raw-time-literal — hrtime seconds→ms
76
+ var MS_PER_SECOND_HRTIME = 1000; // allow:raw-time-literal — hrtime seconds→ms
77
77
 
78
78
  /**
79
79
  * @primitive b.streamThrottle.create
package/lib/websocket.js CHANGED
@@ -190,8 +190,8 @@ var CLOSE_GRACE_MS = C.TIME.seconds(2);
190
190
  // invalid.
191
191
  function _isValidCloseCode(code) {
192
192
  if (code === 1004 || code === 1005 || code === 1006 || code === 1015) return false; // RFC 6455 §7.4.2 reserved codes
193
- if (code >= 1000 && code <= 1011) return true; // allow:raw-byte-literal — RFC 6455 §7.4.2 spec range / allow:raw-time-literal — code is a numeric, not seconds
194
- if (code >= 3000 && code <= 4999) return true; // allow:raw-byte-literal — RFC 6455 §7.4.2 IANA / private range / allow:raw-time-literal — code is a numeric, not seconds
193
+ if (code >= 1000 && code <= 1011) return true; // allow:raw-time-literal — code is a numeric, not seconds
194
+ if (code >= 3000 && code <= 4999) return true; // allow:raw-time-literal — code is a numeric, not seconds
195
195
  return false;
196
196
  }
197
197
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blamejs/core",
3
- "version": "0.14.4",
3
+ "version": "0.14.6",
4
4
  "description": "The Node framework that owns its stack.",
5
5
  "license": "Apache-2.0",
6
6
  "author": "blamejs contributors",
package/sbom.cdx.json CHANGED
@@ -2,10 +2,10 @@
2
2
  "$schema": "http://cyclonedx.org/schema/bom-1.5.schema.json",
3
3
  "bomFormat": "CycloneDX",
4
4
  "specVersion": "1.5",
5
- "serialNumber": "urn:uuid:3b6688f8-8f17-4d81-9bad-f0e6166a53c7",
5
+ "serialNumber": "urn:uuid:ba3e9bdd-f642-4d42-a03c-794d89554a0a",
6
6
  "version": 1,
7
7
  "metadata": {
8
- "timestamp": "2026-05-30T08:50:20.572Z",
8
+ "timestamp": "2026-05-30T16:30:23.236Z",
9
9
  "lifecycles": [
10
10
  {
11
11
  "phase": "build"
@@ -19,14 +19,14 @@
19
19
  }
20
20
  ],
21
21
  "component": {
22
- "bom-ref": "@blamejs/core@0.14.4",
22
+ "bom-ref": "@blamejs/core@0.14.6",
23
23
  "type": "application",
24
24
  "name": "blamejs",
25
- "version": "0.14.4",
25
+ "version": "0.14.6",
26
26
  "scope": "required",
27
27
  "author": "blamejs contributors",
28
28
  "description": "The Node framework that owns its stack.",
29
- "purl": "pkg:npm/%40blamejs/core@0.14.4",
29
+ "purl": "pkg:npm/%40blamejs/core@0.14.6",
30
30
  "properties": [],
31
31
  "externalReferences": [
32
32
  {
@@ -54,7 +54,7 @@
54
54
  "components": [],
55
55
  "dependencies": [
56
56
  {
57
- "ref": "@blamejs/core@0.14.4",
57
+ "ref": "@blamejs/core@0.14.6",
58
58
  "dependsOn": []
59
59
  }
60
60
  ]