@blamejs/core 0.15.13 → 0.15.14
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/CHANGELOG.md +2 -0
- package/lib/a2a-tasks.js +38 -6
- package/lib/agent-event-bus.js +13 -0
- package/lib/agent-idempotency.js +5 -1
- package/lib/agent-snapshot.js +32 -2
- package/lib/ai-aedt-bias-audit.js +2 -1
- package/lib/ai-content-detect.js +1 -3
- package/lib/ai-frontier-protocol.js +1 -1
- package/lib/ai-model-manifest.js +1 -1
- package/lib/ai-output.js +16 -7
- package/lib/api-snapshot.js +4 -1
- package/lib/app-shutdown.js +7 -1
- package/lib/archive-gz.js +9 -0
- package/lib/archive-read.js +9 -7
- package/lib/archive-tar-read.js +51 -8
- package/lib/archive.js +4 -2
- package/lib/asn1-der.js +70 -22
- package/lib/atomic-file.js +204 -2
- package/lib/audit-chain.js +54 -5
- package/lib/audit-daily-review.js +12 -2
- package/lib/audit-sign.js +2 -1
- package/lib/audit-tools.js +108 -23
- package/lib/audit.js +7 -2
- package/lib/auth/access-lock.js +2 -2
- package/lib/auth/bot-challenge.js +1 -1
- package/lib/auth/ciba.js +43 -4
- package/lib/auth/dpop.js +6 -1
- package/lib/auth/fido-mds3.js +5 -1
- package/lib/auth/jwt.js +2 -2
- package/lib/auth/lockout.js +18 -2
- package/lib/auth/passkey.js +1 -1
- package/lib/auth/password.js +1 -1
- package/lib/auth/saml.js +33 -13
- package/lib/auth/sd-jwt-vc.js +24 -4
- package/lib/auth/status-list.js +14 -2
- package/lib/auth/step-up.js +9 -1
- package/lib/auth-bot-challenge.js +21 -2
- package/lib/backup/bundle.js +7 -2
- package/lib/backup/crypto.js +23 -8
- package/lib/backup/index.js +41 -20
- package/lib/backup/manifest.js +7 -1
- package/lib/break-glass.js +41 -22
- package/lib/cbor.js +34 -11
- package/lib/cdn-cache-control.js +7 -3
- package/lib/cert.js +5 -3
- package/lib/cli.js +5 -1
- package/lib/cloud-events.js +3 -2
- package/lib/cluster-storage.js +7 -3
- package/lib/codepoint-class.js +17 -0
- package/lib/compliance-eaa.js +1 -1
- package/lib/compliance-sanctions.js +9 -7
- package/lib/compliance.js +1 -1
- package/lib/config-drift.js +22 -8
- package/lib/content-credentials.js +11 -8
- package/lib/content-digest.js +11 -4
- package/lib/cookies.js +10 -2
- package/lib/cose.js +20 -0
- package/lib/crdt.js +2 -1
- package/lib/crypto-field.js +29 -23
- package/lib/crypto.js +18 -4
- package/lib/csp.js +4 -0
- package/lib/daemon.js +4 -1
- package/lib/data-act.js +27 -4
- package/lib/db-file-lifecycle.js +14 -6
- package/lib/db-query.js +69 -9
- package/lib/db.js +32 -15
- package/lib/dora.js +43 -13
- package/lib/dr-runbook.js +1 -1
- package/lib/dsa.js +2 -1
- package/lib/dsr.js +22 -8
- package/lib/early-hints.js +19 -0
- package/lib/eat.js +5 -1
- package/lib/external-db.js +60 -4
- package/lib/fda-21cfr11.js +30 -5
- package/lib/flag-providers.js +6 -2
- package/lib/forms.js +1 -1
- package/lib/gate-contract.js +46 -5
- package/lib/gdpr-ropa.js +18 -9
- package/lib/graphql-federation.js +17 -4
- package/lib/guard-all.js +2 -2
- package/lib/guard-dsn.js +1 -1
- package/lib/guard-envelope.js +1 -1
- package/lib/guard-html.js +9 -11
- package/lib/guard-imap-command.js +1 -1
- package/lib/guard-jmap.js +1 -1
- package/lib/guard-json.js +14 -6
- package/lib/guard-mail-move.js +1 -1
- package/lib/guard-managesieve-command.js +1 -1
- package/lib/guard-pop3-command.js +1 -1
- package/lib/guard-smtp-command.js +1 -1
- package/lib/guard-svg.js +8 -9
- package/lib/html-balance.js +7 -3
- package/lib/http-client-cookie-jar.js +33 -12
- package/lib/http-client.js +225 -53
- package/lib/iab-tcf.js +3 -2
- package/lib/importmap-integrity.js +41 -1
- package/lib/incident-report.js +9 -6
- package/lib/json-patch.js +1 -1
- package/lib/json-path.js +24 -3
- package/lib/jtd.js +2 -2
- package/lib/legal-hold.js +24 -8
- package/lib/log.js +2 -2
- package/lib/mail-agent.js +2 -2
- package/lib/mail-arf.js +1 -1
- package/lib/mail-auth.js +3 -3
- package/lib/mail-bimi.js +16 -16
- package/lib/mail-bounce.js +3 -3
- package/lib/mail-crypto-smime.js +71 -6
- package/lib/mail-deploy.js +9 -5
- package/lib/mail-greylist.js +2 -4
- package/lib/mail-helo.js +2 -4
- package/lib/mail-journal.js +11 -8
- package/lib/mail-mdn.js +8 -4
- package/lib/mail-rbl.js +2 -4
- package/lib/mail-scan.js +3 -5
- package/lib/mail-server-jmap.js +4 -1
- package/lib/mail-server-registry.js +1 -1
- package/lib/mail-server-tls.js +9 -2
- package/lib/mail-spam-score.js +2 -4
- package/lib/mail-store-fts.js +1 -1
- package/lib/mail.js +22 -2
- package/lib/markup-tokenizer.js +24 -0
- package/lib/mcp.js +6 -4
- package/lib/mdoc.js +26 -3
- package/lib/metrics.js +14 -3
- package/lib/middleware/api-encrypt.js +2 -2
- package/lib/middleware/body-parser.js +10 -4
- package/lib/middleware/bot-guard.js +26 -18
- package/lib/middleware/clear-site-data.js +5 -1
- package/lib/middleware/compression.js +9 -0
- package/lib/middleware/cors.js +32 -23
- package/lib/middleware/csrf-protect.js +60 -21
- package/lib/middleware/daily-byte-quota.js +6 -4
- package/lib/middleware/fetch-metadata.js +28 -4
- package/lib/middleware/network-allowlist.js +61 -30
- package/lib/middleware/rate-limit.js +25 -16
- package/lib/middleware/scim-server.js +2 -1
- package/lib/middleware/security-headers.js +24 -6
- package/lib/middleware/speculation-rules.js +6 -3
- package/lib/middleware/tus-upload.js +2 -2
- package/lib/money.js +1 -1
- package/lib/mtls-ca.js +10 -6
- package/lib/network-dns-resolver.js +1 -1
- package/lib/network-dns.js +9 -2
- package/lib/network-dnssec.js +2 -1
- package/lib/network-smtp-policy.js +23 -5
- package/lib/network-tls.js +27 -5
- package/lib/network-tsig.js +2 -2
- package/lib/nis2-report.js +1 -1
- package/lib/nist-crosswalk.js +1 -1
- package/lib/ntp-check.js +28 -0
- package/lib/numeric-bounds.js +9 -0
- package/lib/object-store/azure-blob.js +1 -2
- package/lib/object-store/gcs-bucket-ops.js +4 -2
- package/lib/object-store/gcs.js +6 -4
- package/lib/object-store/http-put.js +1 -2
- package/lib/object-store/http-request.js +30 -1
- package/lib/object-store/local.js +37 -17
- package/lib/object-store/sigv4.js +1 -2
- package/lib/observability-otlp-exporter.js +20 -4
- package/lib/outbox.js +11 -4
- package/lib/parsers/safe-xml.js +1 -1
- package/lib/parsers/safe-yaml.js +21 -3
- package/lib/queue-local.js +10 -3
- package/lib/redact.js +7 -3
- package/lib/request-helpers.js +201 -23
- package/lib/resource-access-lock.js +3 -3
- package/lib/restore-bundle.js +46 -18
- package/lib/restore-rollback.js +10 -4
- package/lib/restore.js +19 -0
- package/lib/retention.js +20 -4
- package/lib/router.js +17 -4
- package/lib/safe-ical.js +2 -2
- package/lib/safe-icap.js +1 -1
- package/lib/safe-json.js +44 -0
- package/lib/safe-sieve.js +1 -1
- package/lib/safe-vcard.js +1 -1
- package/lib/sandbox-worker.js +6 -0
- package/lib/sandbox.js +1 -1
- package/lib/scheduler.js +17 -1
- package/lib/self-update-standalone-verifier.js +16 -0
- package/lib/session.js +27 -3
- package/lib/sql.js +3 -3
- package/lib/static.js +65 -13
- package/lib/template.js +7 -5
- package/lib/tenant-quota.js +52 -19
- package/lib/tsa.js +5 -2
- package/lib/vault/index.js +5 -0
- package/lib/vault/passphrase-ops.js +22 -26
- package/lib/vault/passphrase-source.js +8 -3
- package/lib/vault/rotate.js +13 -18
- package/lib/vault/seal-pem-file.js +4 -1
- package/lib/vc.js +1 -1
- package/lib/vendor/MANIFEST.json +10 -10
- package/lib/vendor/public-suffix-list.dat +23 -10
- package/lib/vendor/public-suffix-list.data.js +5498 -5494
- package/lib/webhook.js +16 -1
- package/lib/websocket.js +1 -1
- package/lib/worm.js +1 -1
- package/lib/ws-client.js +57 -46
- package/lib/x509-chain.js +44 -0
- package/package.json +1 -1
- package/sbom.cdx.json +6 -6
package/lib/webhook.js
CHANGED
|
@@ -48,6 +48,7 @@
|
|
|
48
48
|
*/
|
|
49
49
|
|
|
50
50
|
var nodeCrypto = require("node:crypto");
|
|
51
|
+
var numericBounds = require("./numeric-bounds");
|
|
51
52
|
var bCrypto = require("./crypto");
|
|
52
53
|
var httpClient = require("./http-client");
|
|
53
54
|
var safeBuffer = require("./safe-buffer");
|
|
@@ -57,6 +58,8 @@ var C = require("./constants");
|
|
|
57
58
|
var lazyRequire = require("./lazy-require");
|
|
58
59
|
var numericChecks = require("./numeric-checks");
|
|
59
60
|
var requestHelpers = require("./request-helpers");
|
|
61
|
+
// Lazy — ssrf-guard pulls in the DNS/network stack; only touched on send().
|
|
62
|
+
var ssrfGuard = lazyRequire(function () { return require("./ssrf-guard"); });
|
|
60
63
|
var validateOpts = require("./validate-opts");
|
|
61
64
|
var { WebhookError } = require("./framework-error");
|
|
62
65
|
// b.webhook.dispatcher — durable signed-webhook delivery store. Lives in its
|
|
@@ -428,6 +431,18 @@ function signer(opts) {
|
|
|
428
431
|
allowedProtocols: httpOpts.allowedProtocols || safeUrl.ALLOW_HTTP_TLS,
|
|
429
432
|
errorClass: WebhookError,
|
|
430
433
|
});
|
|
434
|
+
// SSRF gate at the webhook layer: refuse private / loopback / link-local /
|
|
435
|
+
// cloud-metadata destinations up front, before the retry loop. httpClient
|
|
436
|
+
// also enforces this on every request, but checking here fails fast (no
|
|
437
|
+
// wasted retries) and keeps the SSRF boundary explicit at the send() API
|
|
438
|
+
// rather than relying on the transport's internal gate. allowInternal
|
|
439
|
+
// mirrors the operator's http opts (its affirmative waiver).
|
|
440
|
+
try {
|
|
441
|
+
await ssrfGuard().checkUrl(url, { allowInternal: httpOpts.allowInternal === true });
|
|
442
|
+
} catch (e) {
|
|
443
|
+
if (e && e.isSsrfError) throw _err("SSRF_REFUSED", "webhook.signer.send: " + e.message);
|
|
444
|
+
throw e;
|
|
445
|
+
}
|
|
431
446
|
_validateBody(body);
|
|
432
447
|
var signed = sign(body, { kid: input.kid });
|
|
433
448
|
var mergedHeaders = Object.assign({}, input.headers || {}, signed.headers);
|
|
@@ -645,7 +660,7 @@ function verifier(opts) {
|
|
|
645
660
|
throw _failure("MISSING_TIMESTAMP", "webhook: t= field missing from signature header", "missing-timestamp", ctxReq);
|
|
646
661
|
}
|
|
647
662
|
var ts = Number(parsed.t);
|
|
648
|
-
if (!
|
|
663
|
+
if (!numericBounds.isNonNegativeFiniteInt(ts)) {
|
|
649
664
|
throw _failure("BAD_TIMESTAMP", "webhook: t= field is not a non-negative integer, got " + JSON.stringify(parsed.t), "bad-timestamp", ctxReq);
|
|
650
665
|
}
|
|
651
666
|
if (parsed.id === null || parsed.id.length === 0) {
|
package/lib/websocket.js
CHANGED
|
@@ -573,7 +573,7 @@ function _negotiatePermessageDeflate(reqHeader) {
|
|
|
573
573
|
"server_max_window_bits": true, "client_max_window_bits": true,
|
|
574
574
|
};
|
|
575
575
|
var ok = true;
|
|
576
|
-
for (var k in p) { if (Object.prototype.hasOwnProperty.call(p, k) && !KNOWN
|
|
576
|
+
for (var k in p) { if (Object.prototype.hasOwnProperty.call(p, k) && !Object.prototype.hasOwnProperty.call(KNOWN, k)) { ok = false; break; } }
|
|
577
577
|
if (!ok) continue;
|
|
578
578
|
// Always negotiate WITH no_context_takeover in BOTH directions, so
|
|
579
579
|
// every message uses a fresh zlib state. Echo any client window-
|
package/lib/worm.js
CHANGED
|
@@ -102,7 +102,7 @@ function create(opts) {
|
|
|
102
102
|
opts = opts || {};
|
|
103
103
|
validateOpts(opts, ["store", "mode", "defaultRetentionMs", "clock"], "worm.create");
|
|
104
104
|
var mode = opts.mode || "compliance";
|
|
105
|
-
if (!MODES
|
|
105
|
+
if (!Object.prototype.hasOwnProperty.call(MODES, mode)) throw new WormError("worm/bad-mode", "worm.create: mode must be 'compliance' or 'governance'");
|
|
106
106
|
var store = opts.store || _memStore();
|
|
107
107
|
["get", "set", "delete", "has", "keys"].forEach(function (m) {
|
|
108
108
|
if (typeof store[m] !== "function") throw new WormError("worm/bad-store", "worm.create: store adapter must implement " + m + "()");
|
package/lib/ws-client.js
CHANGED
|
@@ -248,17 +248,13 @@ function connect(target, opts) {
|
|
|
248
248
|
});
|
|
249
249
|
// SSRF gate — refuse private / loopback / link-local / cloud-metadata /
|
|
250
250
|
// reserved IP destinations by default. Symmetric to b.httpClient. The
|
|
251
|
-
//
|
|
251
|
+
// validated `ips` are pinned through tls.connect / net.connect so the
|
|
252
252
|
// actual TCP connect targets the validated address (closes the DNS-
|
|
253
253
|
// rebinding TOCTOU window). Cloud-metadata IPs are unconditional
|
|
254
|
-
// hard-deny — `allowInternal: true` does not bypass them.
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
allowInternal: opts.allowInternal,
|
|
259
|
-
errorClass: WsClientError,
|
|
260
|
-
}).then(function (result) {
|
|
261
|
-
client._ssrfPinnedIps = result && result.ips;
|
|
254
|
+
// hard-deny — `allowInternal: true` does not bypass them. _prepareDial
|
|
255
|
+
// performs the (async) check + pinning before the dial and reruns it on
|
|
256
|
+
// every reconnect, so a urlFor-swapped target is validated too.
|
|
257
|
+
client._prepareDial().then(function () {
|
|
262
258
|
client._dial();
|
|
263
259
|
}).catch(function (e) {
|
|
264
260
|
setImmediate(function () { client._handleSocketError(e); });
|
|
@@ -315,51 +311,50 @@ class WsClient extends EventEmitter {
|
|
|
315
311
|
get subprotocol() { return this._negotiatedSubprotocol; }
|
|
316
312
|
get url() { return this._opts.target; }
|
|
317
313
|
|
|
318
|
-
|
|
319
|
-
|
|
314
|
+
// Resolve the dial target and re-validate it BEFORE any socket opens.
|
|
315
|
+
// urlFor may swap the URL and tlsOptsFor may rotate TLS material every
|
|
316
|
+
// dial (including reconnects). The resolved target is re-checked through
|
|
317
|
+
// ssrfGuard — AWAITED, because checkUrl is async: the prior code called it
|
|
318
|
+
// synchronously inside _dial and discarded the Promise, so a urlFor that
|
|
319
|
+
// pointed at a private / cloud-metadata address mid-reconnect was connected
|
|
320
|
+
// anyway (the SSRF rejection surfaced only as an unhandled rejection) and
|
|
321
|
+
// the connect was never pinned. Returns a Promise; sync throws from
|
|
322
|
+
// urlFor / tlsOptsFor become rejections (async fn) handled by the caller.
|
|
323
|
+
async _prepareDial() {
|
|
320
324
|
var opts = this._opts;
|
|
321
|
-
this._readyState = "connecting";
|
|
322
|
-
|
|
323
|
-
// Per-dial overrides — urlFor swaps the target URL, tlsOptsFor
|
|
324
|
-
// overrides TLS material. Both fire every dial including reconnects
|
|
325
|
-
// so callers can rotate state. urlFor's result is re-validated
|
|
326
|
-
// through ssrfGuard so a hostile upstream can't direct the client
|
|
327
|
-
// at a private address mid-reconnect.
|
|
328
325
|
var attempt = this._reconnectAttempt || 0;
|
|
329
|
-
var dialTarget = opts.target;
|
|
330
326
|
var dialParsed = opts.parsedUrl;
|
|
331
327
|
if (typeof opts.urlFor === "function") {
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
dialParsed = _parseUrl(nextTarget);
|
|
336
|
-
dialTarget = nextTarget;
|
|
337
|
-
var probeProto = dialParsed.protocol === "wss:" ? "https:" : "http:";
|
|
338
|
-
var probeUrl = new nodeUrl.URL(probeProto + "//" + dialParsed.host + dialParsed.pathname + dialParsed.search);
|
|
339
|
-
var probe = ssrfGuard.checkUrl(probeUrl, {
|
|
340
|
-
allowInternal: opts.allowInternal,
|
|
341
|
-
errorClass: WsClientError,
|
|
342
|
-
});
|
|
343
|
-
this._ssrfPinnedIps = probe && probe.ips ? probe.ips : null;
|
|
344
|
-
}
|
|
345
|
-
} catch (e) {
|
|
346
|
-
return self._handleSocketError(e);
|
|
328
|
+
var nextTarget = opts.urlFor(attempt);
|
|
329
|
+
if (typeof nextTarget === "string" && nextTarget.length > 0 && nextTarget !== opts.target) {
|
|
330
|
+
dialParsed = _parseUrl(nextTarget);
|
|
347
331
|
}
|
|
348
332
|
}
|
|
349
|
-
|
|
350
333
|
var dialTlsOpts = opts.tlsOpts;
|
|
351
334
|
if (typeof opts.tlsOptsFor === "function") {
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
dialTlsOpts = Object.assign({}, opts.tlsOpts || {}, override);
|
|
356
|
-
}
|
|
357
|
-
} catch (e) {
|
|
358
|
-
return self._handleSocketError(e);
|
|
335
|
+
var override = opts.tlsOptsFor(attempt);
|
|
336
|
+
if (override && typeof override === "object") {
|
|
337
|
+
dialTlsOpts = Object.assign({}, opts.tlsOpts || {}, override);
|
|
359
338
|
}
|
|
360
339
|
}
|
|
340
|
+
var probeProto = dialParsed.protocol === "wss:" ? "https:" : "http:";
|
|
341
|
+
var probeUrl = new nodeUrl.URL(probeProto + "//" + dialParsed.host + dialParsed.pathname + dialParsed.search);
|
|
342
|
+
var probe = await ssrfGuard.checkUrl(probeUrl, {
|
|
343
|
+
allowInternal: opts.allowInternal,
|
|
344
|
+
errorClass: WsClientError,
|
|
345
|
+
});
|
|
346
|
+
this._ssrfPinnedIps = probe && probe.ips ? probe.ips : null;
|
|
347
|
+
this._dialParsed = dialParsed;
|
|
348
|
+
this._dialTlsOpts = dialTlsOpts;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
_dial() {
|
|
352
|
+
var self = this;
|
|
353
|
+
this._readyState = "connecting";
|
|
361
354
|
|
|
362
|
-
|
|
355
|
+
// Target + TLS material were resolved and SSRF-validated by _prepareDial.
|
|
356
|
+
var parsed = this._dialParsed || this._opts.parsedUrl;
|
|
357
|
+
var dialTlsOpts = this._dialTlsOpts || this._opts.tlsOpts;
|
|
363
358
|
var port = parsed.port ? parseInt(parsed.port, 10) :
|
|
364
359
|
(parsed.protocol === "wss:" ? 443 : 80); // TLS / HTTP default port
|
|
365
360
|
var host = parsed.hostname;
|
|
@@ -422,8 +417,8 @@ class WsClient extends EventEmitter {
|
|
|
422
417
|
|
|
423
418
|
this._handshakeTimer = setTimeout(function () {
|
|
424
419
|
self._handleSocketError(new WsClientError("ws-client/handshake-timeout",
|
|
425
|
-
"Handshake exceeded " +
|
|
426
|
-
},
|
|
420
|
+
"Handshake exceeded " + self._opts.handshakeTimeoutMs + "ms"));
|
|
421
|
+
}, self._opts.handshakeTimeoutMs);
|
|
427
422
|
if (typeof this._handshakeTimer.unref === "function") this._handshakeTimer.unref();
|
|
428
423
|
}
|
|
429
424
|
|
|
@@ -644,6 +639,17 @@ class WsClient extends EventEmitter {
|
|
|
644
639
|
return;
|
|
645
640
|
}
|
|
646
641
|
}
|
|
642
|
+
// Fail the connection on any opcode outside the six RFC 6455 §5.2-defined
|
|
643
|
+
// values (CONT/TEXT/BINARY/CLOSE/PING/PONG). Without this, a reserved
|
|
644
|
+
// opcode (0x3-0x7, 0xB-0xF) from a malicious server fell through every
|
|
645
|
+
// branch to the FIN block and emitted a (stale/empty) message — a
|
|
646
|
+
// fragmented-message desync / frame-injection lever.
|
|
647
|
+
if (frame.opcode !== OPCODE_CONT && frame.opcode !== OPCODE_TEXT &&
|
|
648
|
+
frame.opcode !== OPCODE_BINARY && !isControl) {
|
|
649
|
+
this._handleSocketError(new WsClientError("ws-client/reserved-opcode",
|
|
650
|
+
"reserved/unknown WebSocket opcode 0x" + frame.opcode.toString(16) + " (RFC 6455 §5.2)"));
|
|
651
|
+
return;
|
|
652
|
+
}
|
|
647
653
|
// Continuation frames MUST NOT carry rsv1 (RFC 7692 §6.1) — only
|
|
648
654
|
// the first frame of a compressed message sets rsv1.
|
|
649
655
|
if (frame.opcode === OPCODE_CONT && frame.rsv1) {
|
|
@@ -926,7 +932,12 @@ class WsClient extends EventEmitter {
|
|
|
926
932
|
this._reconnectTimer = setTimeout(function () {
|
|
927
933
|
self._reconnectTimer = null;
|
|
928
934
|
if (self._closed) return; // operator-cancelled in flight
|
|
929
|
-
|
|
935
|
+
// Re-resolve + re-validate the target (urlFor swap, DNS rebind) before
|
|
936
|
+
// reconnecting — awaited, so a now-private/metadata address is refused.
|
|
937
|
+
self._prepareDial().then(function () {
|
|
938
|
+
if (self._closed) return;
|
|
939
|
+
self._dial();
|
|
940
|
+
}).catch(function (e) { self._handleSocketError(e); });
|
|
930
941
|
}, delay);
|
|
931
942
|
if (typeof this._reconnectTimer.unref === "function") this._reconnectTimer.unref();
|
|
932
943
|
this.emit("reconnecting", { attempt: this._reconnectAttempt, delayMs: delay });
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
// Internal X.509 path-validation helpers shared by the framework's
|
|
4
|
+
// certificate-chain walkers (b.tsa.verifyToken, b.mail.bimi VMC/CMC,
|
|
5
|
+
// b.mail.crypto.smime.verify). They exist because node:crypto's
|
|
6
|
+
// X509Certificate.checkIssued() validates the issuer/subject DN match,
|
|
7
|
+
// the AKI/SKI linkage, and — when a keyUsage extension is present —
|
|
8
|
+
// keyCertSign, but it does NOT enforce basicConstraints cA:TRUE. A
|
|
9
|
+
// leaf / end-entity certificate (cA:FALSE) that omits keyUsage is
|
|
10
|
+
// therefore wrongly accepted as a signing CA for the next cert in the
|
|
11
|
+
// chain — the classic basicConstraints bypass (CVE-2002-0862 class).
|
|
12
|
+
// Every chain walker routes its issuer test through these helpers so the
|
|
13
|
+
// cA enforcement can never be forgotten in one walker but present in
|
|
14
|
+
// another.
|
|
15
|
+
|
|
16
|
+
// True only when `cert` asserts basicConstraints cA:TRUE. node's
|
|
17
|
+
// X509Certificate exposes `.ca` (a boolean); a cert with no
|
|
18
|
+
// basicConstraints extension or with cA:FALSE returns false. A missing
|
|
19
|
+
// cert or a non-boolean `.ca` (parse failure / unsupported runtime)
|
|
20
|
+
// fails closed.
|
|
21
|
+
function isCaCert(cert) {
|
|
22
|
+
return !!cert && cert.ca === true;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// True when `issuer` validly issued `subject` AND is itself a CA: the
|
|
26
|
+
// DN / AKI-SKI / keyUsage linkage (checkIssued), the cryptographic
|
|
27
|
+
// signature (verify), and basicConstraints cA:TRUE (isCaCert). The cA
|
|
28
|
+
// check runs first so a non-CA cert is rejected before the expensive
|
|
29
|
+
// signature verification. Any exception (malformed cert, unsupported
|
|
30
|
+
// key type) fails closed to false.
|
|
31
|
+
function issuerValidlyIssued(issuer, subject) {
|
|
32
|
+
try {
|
|
33
|
+
return isCaCert(issuer) &&
|
|
34
|
+
subject.checkIssued(issuer) &&
|
|
35
|
+
subject.verify(issuer.publicKey);
|
|
36
|
+
} catch (_e) {
|
|
37
|
+
return false;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
module.exports = {
|
|
42
|
+
isCaCert: isCaCert,
|
|
43
|
+
issuerValidlyIssued: issuerValidlyIssued,
|
|
44
|
+
};
|
package/package.json
CHANGED
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:
|
|
5
|
+
"serialNumber": "urn:uuid:81a205f2-938f-47e5-9426-3245e2ac5859",
|
|
6
6
|
"version": 1,
|
|
7
7
|
"metadata": {
|
|
8
|
-
"timestamp": "2026-06-
|
|
8
|
+
"timestamp": "2026-06-21T13:24:58.132Z",
|
|
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.15.
|
|
22
|
+
"bom-ref": "@blamejs/core@0.15.14",
|
|
23
23
|
"type": "application",
|
|
24
24
|
"name": "blamejs",
|
|
25
|
-
"version": "0.15.
|
|
25
|
+
"version": "0.15.14",
|
|
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.15.
|
|
29
|
+
"purl": "pkg:npm/%40blamejs/core@0.15.14",
|
|
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.15.
|
|
57
|
+
"ref": "@blamejs/core@0.15.14",
|
|
58
58
|
"dependsOn": []
|
|
59
59
|
}
|
|
60
60
|
]
|