@blamejs/core 0.10.11 → 0.10.13
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/README.md +2 -0
- package/index.js +4 -0
- package/lib/cms-codec.js +685 -0
- package/lib/daemon.js +29 -4
- package/lib/mail-crypto-pgp.js +10 -9
- package/lib/mail-crypto-smime.js +15 -31
- package/lib/mail-server-imap.js +8 -0
- package/lib/mail-server-jmap.js +9 -3
- package/lib/mail-server-managesieve.js +4 -0
- package/lib/mail-server-pop3.js +35 -0
- package/lib/mail-server-registry.js +45 -0
- package/lib/mail-server-submission.js +33 -0
- package/lib/metrics.js +68 -8
- package/lib/stream-throttle.js +235 -0
- package/package.json +1 -1
- package/sbom.cdx.json +6 -6
package/CHANGELOG.md
CHANGED
|
@@ -8,6 +8,8 @@ upgrading across more than a few patches at a time.
|
|
|
8
8
|
|
|
9
9
|
## v0.10.x
|
|
10
10
|
|
|
11
|
+
- v0.10.13 (2026-05-18) — **`b.cms` CMS codec + `b.streamThrottle` bandwidth limiter + histogram-aware snapshot writer + Windows-safe daemonize.** **`b.cms` — RFC 5652 Cryptographic Message Syntax codec.** New crypto primitive: in-tree CMS encoder + decoder built on the existing `b.asn1Der` walker and the vendored noble-post-quantum primitives. **(a) `b.cms.encodeSignedData({ encapContent, digestAlg, signers })`** — emits a DER-encoded `ContentInfo` carrying `SignedData` per RFC 5652 §5 with PQC signers: ML-DSA-65 + ML-DSA-87 ([RFC 9909](https://www.rfc-editor.org/rfc/rfc9909.html)) and SLH-DSA-SHAKE-256f ([RFC 9881](https://www.rfc-editor.org/rfc/rfc9881.html)). Digest algorithms are SHA3-256 or SHA3-512 (PQC-first; SHA-2 family refused with `cms/bad-digest`). Signed-attributes carry `contentType` + `messageDigest` + `signingTime` in DER-canonical SET-OF ordering; the signature input re-tags the IMPLICIT `[0]` to the universal SET (`0x31`) per §5.4 paragraph 3 so signatures round-trip with any conforming verifier. Signer identifiers carry the full `issuerAndSerialNumber` extracted from the operator-supplied cert DER ([RFC 5652 §10.2.4](https://www.rfc-editor.org/rfc/rfc5652#section-10.2.4)). **(b) `b.cms.encodeEnvelopedData({ plaintext, recipients })`** — emits a DER-encoded `ContentInfo` carrying `EnvelopedData` with `KEMRecipientInfo` recipients per [RFC 9629](https://www.rfc-editor.org/rfc/rfc9629.html) and ML-KEM-1024 per [RFC 9936](https://www.rfc-editor.org/rfc/rfc9936.html). Each recipient encapsulates against the operator-supplied ML-KEM-1024 public key; the framework's SHAKE256 KDF derives a 32-byte content-encryption KEK from the KEM shared-secret bound to the literal label `cms/kemri/chacha20-poly1305` (so a key derived for this composition cannot be confused with one derived for any other framework path). Content encryption is ChaCha20-Poly1305 ([RFC 8103](https://www.rfc-editor.org/rfc/rfc8103.html) OID); the AEAD tag makes Efail-class CBC-malleability impossible by construction ([CVE-2017-17688](https://nvd.nist.gov/vuln/detail/CVE-2017-17688) / [CVE-2017-17689](https://nvd.nist.gov/vuln/detail/CVE-2017-17689)). **(c) `b.cms.decode(buf, { maxBytes? })`** — returns `{ contentType, content }` where `contentType` is the dotted-OID string and `content` is the inner `asn1-der` node. Refuses input past `maxBytes` (default 64 MiB), non-SEQUENCE top-level, missing `[0] EXPLICIT` content, and malformed OID encodings (closes the [CVE-2022-47629](https://nvd.nist.gov/vuln/detail/CVE-2022-47629) libksba class via the existing `b.asn1Der` strict-decode posture). **(d) Refusal posture documented in `lib/cms-codec.js` @intro**: only PQC signature algorithms (`cms/bad-sig-alg`), only ML-KEM-1024 recipients (`cms/bad-recipient-type`), non-empty signers / recipients required at encode (`cms/no-signers` / `cms/no-recipients`). **Operator impact:** no breaking changes; new primitive at `b.cms`. **Deferred to v0.10.14:** the on-the-wire S/MIME 4.0 layer ([RFC 8551](https://www.rfc-editor.org/rfc/rfc8551.html) `multipart/signed` framing, base64 DER body, `micalg` mapping) and OpenPGP encrypt + decrypt + WKD discovery ([RFC 9580](https://www.rfc-editor.org/rfc/rfc9580.html) §5.1 / §5.13 packets plus [draft-koch-openpgp-webkey-service](https://datatracker.ietf.org/doc/draft-koch-openpgp-webkey-service/)) land together so the mail-crypto surface lights up coherently rather than half-on-each-side across two patches. AuthEnvelopedData ([RFC 5083](https://www.rfc-editor.org/rfc/rfc5083.html)) as a distinct `ContentInfo` shape is deferred — EnvelopedData with ChaCha20-Poly1305 is already AEAD by construction; the §5083 OID rewrap lights up alongside S/MIME for peers that refuse the EnvelopedData form. References: [RFC 5652 CMS](https://www.rfc-editor.org/rfc/rfc5652.html) · [RFC 9629 KEMRecipientInfo](https://www.rfc-editor.org/rfc/rfc9629.html) · [RFC 9909 ML-DSA in X.509+CMS](https://www.rfc-editor.org/rfc/rfc9909.html) · [RFC 9881 SLH-DSA in X.509+CMS](https://www.rfc-editor.org/rfc/rfc9881.html) · [RFC 9936 ML-KEM in CMS](https://www.rfc-editor.org/rfc/rfc9936.html) · [RFC 8103 ChaCha20-Poly1305 in CMS](https://www.rfc-editor.org/rfc/rfc8103.html). **(e) `b.streamThrottle` — token-bucket bandwidth limiter.** New primitive: `b.streamThrottle.create({ bytesPerSec, burstBytes? })` returns a shared token bucket whose `.transform()` instances each consume from the same budget. The missing primitive between per-request rate-limit and per-process worker pools: N parallel transfers share the operator-configured byte budget rather than each getting their own. Composes with `node:stream.pipeline` as a regular `stream.Transform`; chunks larger than `burstBytes` refuse with `stream-throttle/oversize-chunk` unless `transform({ allowOversize: true })`. Algorithm is the [RFC 2697 srTCM](https://www.rfc-editor.org/rfc/rfc2697.html) single-rate token-bucket shape, with lazy refill so there is no per-throttle background timer. **(f) Histogram-aware metrics snapshot writer.** `b.metrics.snapshot.startWriter` gains an opt-in `registry` field. When supplied, the JSON snapshot grows a `metrics` field carrying every registered counter / gauge / histogram in structured form — histograms include `buckets` + `observations: [{ labels, counts, sum, count }]`, so sidecar readers compose `histogram_quantile()` against the snapshot file without running a separate `/metrics` HTTP endpoint. `fileMode` default unchanged (0o640). **(g) Windows-safe daemonize.** `b.daemon.start` detached-fork mode now branches by platform. POSIX continues inheriting the parent-opened log FD via `stdio: ["ignore", logFd, logFd]` (unchanged). Windows now uses `stdio: "ignore"` + `windowsHide: true` so the child has no inherited handles that the OS invalidates on parent exit — the previously-broken Windows daemonize path now produces a survivable detached process. The child is responsible for opening its own log file (operators pass `--log` in `opts.args`). `daemon.started` audit gains `stdioMode` so operators can grep for the chosen strategy. **Closes: [#94](https://github.com/blamejs/blamejs/issues/94), [#100](https://github.com/blamejs/blamejs/issues/100), [#101](https://github.com/blamejs/blamejs/issues/101); also closes [#92](https://github.com/blamejs/blamejs/issues/92) and [#93](https://github.com/blamejs/blamejs/issues/93) (already shipped in v0.10.9 as `b.promisePool` / `b.sdNotify` — left open until now).**
|
|
12
|
+
- v0.10.12 (2026-05-18) — **`b.agent.tenant` adoption across the mail-server listeners.** The v0.10.11 shared `b.mail.serverRegistry` primitive gains optional `opts.tenantScope` (a `b.agent.tenant.create()` instance) + `opts.agentTenantId` (the tenant this listener serves). When supplied, every method dispatch first gates on `tenantScope.check(state.actor, agentTenantId)` BEFORE guard validation or audit emission; cross-tenant access surfaces as the v0.9.25-typed `agent-tenant/cross-tenant-access-refused` which the listener's catch-path converts to the protocol's `BAD` / `NO` refusal reply. **(a) `b.mail.server.imap.create({ tenantScope, agentTenantId })`** — IMAP dispatch is gated for every command after AUTH. **(b) `b.mail.server.jmap.create({ tenantScope, agentTenantId })`** — JMAP per-method dispatch routes through the tenant scope alongside its existing per-`accountId` isolation. **(c) `b.mail.server.managesieve.create({ tenantScope, agentTenantId })`** — ManageSieve same pattern. **(d) `b.mail.server.submission.create({ tenantScope, agentTenantId })`** — submission listener gates at the AUTH-success boundary (before `state.actor` is committed) so cross-tenant authentication surfaces as `535 5.7.0 Authentication rejected (cross-tenant)` and the SMTP envelope never begins under the wrong tenant. **(e) `b.mail.server.pop3.create({ tenantScope, agentTenantId })`** — same AUTH-success gate; cross-tenant refusal returns `-ERR Authentication rejected (cross-tenant)`. New audit events: `mail.server.submission.cross_tenant_refused` and `mail.server.pop3.cross_tenant_refused`. **Operator impact:** no breaking changes — `tenantScope` / `agentTenantId` are optional; operators not running multi-tenant see identical behavior. Operators with multi-tenant deployments wire `b.agent.tenant.create({...})` once and pass the same scope to every per-tenant listener instance — cross-tenant isolation becomes structural rather than per-handler opt-in. **Deferred to v0.10.12.1:** per-tenant `b.mailStore` seal-key derivation via `tenantScope.derivedKey(tenantId, "seal")` and per-tenant audit namespaces via `tenantScope.auditFor(tenantId)`. Today every mail listener seals through the framework primary vault key — adequate for single-tenant and multi-tenant-trusted deployments; the v0.10.12.1 follow-up adds per-tenant key separation for compromise-isolation use cases. References: [RFC 9051 IMAP4rev2 §3 state machine](https://www.rfc-editor.org/rfc/rfc9051#section-3) · [RFC 8620 JMAP Core §1.6.2 accountId](https://www.rfc-editor.org/rfc/rfc8620#section-1.6.2) · [RFC 6409 Submission §6.1 actor-to-MAIL-FROM identity binding](https://www.rfc-editor.org/rfc/rfc6409#section-6.1) · [RFC 1939 POP3 §6 transaction state](https://www.rfc-editor.org/rfc/rfc1939#section-6) · v0.9.25 `b.agent.tenant` contract.
|
|
11
13
|
- v0.10.11 (2026-05-18) — **Mail-server per-method registration sweep.** New shared primitive `b.mail.serverRegistry` (`lib/mail-server-registry.js`) replaces the hand-rolled `switch (verb)` dispatchers in the IMAP, JMAP, and ManageSieve listener factories. Operators can now override individual command / method handlers (e.g. IMAP `FETCH`, JMAP `Email/query`, ManageSieve `PUTSCRIPT`) via `opts.overrides: { NAME: { fn, maxHandlerBytes, maxHandlerMs } }` without re-implementing wire-protocol state machines or bypassing the guard substrate. **(a) Per-handler resource budgets — required at registration.** Operators MUST supply `maxHandlerBytes` (≤ 256 MiB) and `maxHandlerMs` (≤ 5 min) on every override; the registration throws `mail-server-registry/bad-max-handler-bytes` / `bad-max-handler-ms` on missing or out-of-range budgets. Defends [CVE-2024-34055](https://nvd.nist.gov/vuln/detail/CVE-2024-34055) (Cyrus authenticated OOM) and [CVE-2026-26312](https://nvd.nist.gov/vuln/detail/CVE-2026-26312) (Stalwart malformed nested `message/rfc822` cyclical OOM) by forcing operators to declare the resource ceiling explicitly. **(b) Catalogue gate.** Per-protocol method names outside the IANA / RFC catalogue refuse registration unless `allowExperimental: true` is supplied — opting in audits the registration so operators can grep for off-spec handlers. **(c) Guard chain preserved.** The listener factories run `b.guardImapCommand` / `b.guardJmap` / `b.guardManagesieveCommand` BEFORE the registry lookup; operator overrides cannot bypass the wire-protocol validation, smuggling defenses, or rate-limit budgets. **(d) Handler timeout.** Promise-returning handlers wrap through `b.safeAsync.withTimeout(maxHandlerMs)`; a runaway override raises `mail-server-registry/handler-timeout` rather than pinning the connection. **(e) Defaults seeded.** IMAP picks up 30 verbs (CAPABILITY, NOOP, LOGOUT, ID, STARTTLS, AUTHENTICATE, LOGIN, ENABLE, SELECT, EXAMINE, LIST, STATUS, NAMESPACE, APPEND, CHECK, CLOSE, UNSELECT, EXPUNGE, FETCH, STORE, UID, IDLE, DONE — plus the previously-undispatched SEARCH / CREATE / DELETE / RENAME / SUBSCRIBE / UNSUBSCRIBE / COPY / MOVE which default to `NO not-configured` until operator overrides); ManageSieve picks up 12 verbs (CAPABILITY, NOOP, STARTTLS, LOGOUT, AUTHENTICATE, HAVESPACE, PUTSCRIPT, LISTSCRIPTS, SETACTIVE, GETSCRIPT, DELETESCRIPT, RENAMESCRIPT); JMAP wraps the existing `opts.methods` map with a one-time deprecation audit (`mail.server.jmap.methods_opt_deprecated`) and routes through the same registry — operators migrate to `opts.overrides` with explicit budgets. **(f) New audit event:** `mail.serverRegistry.method_dispatch` carries `{ protocol, name, source: "builtin" | "operator-override" }` on every dispatch; `mail.serverRegistry.experimental_registration` audits opt-in off-catalogue registrations. **Operator impact:** existing JMAP `opts.methods` callers see the deprecation audit but continue to function (legacy auto-budget = 10 MiB / 30 s); existing IMAP / ManageSieve operators have no migration burden — the listener factories continue to accept the same opts shape. Operators wiring NEW overrides MUST supply explicit budgets. References: [RFC 9051 IMAP4rev2](https://www.rfc-editor.org/rfc/rfc9051) · [RFC 8620 JMAP Core](https://www.rfc-editor.org/rfc/rfc8620) · [RFC 8621 JMAP for Mail](https://www.rfc-editor.org/rfc/rfc8621) · [RFC 5804 ManageSieve](https://www.rfc-editor.org/rfc/rfc5804) · [RFC 2971 IMAP4 ID](https://www.rfc-editor.org/rfc/rfc2971) · [RFC 2177 IMAP IDLE](https://www.rfc-editor.org/rfc/rfc2177) · [CVE-2024-34055](https://nvd.nist.gov/vuln/detail/CVE-2024-34055) · [CVE-2026-26312](https://nvd.nist.gov/vuln/detail/CVE-2026-26312).
|
|
12
14
|
- v0.10.10 (2026-05-17) — **PQC envelope completion (experimental).** Two new opt-in PQC-protocol primitives behind explicit experimental namespaces. **(a) `b.jose.jwe.experimental.encrypt` / `.decrypt`** — RFC 7516 compact-serialization JWE with ML-KEM-1024 key encapsulation and XChaCha20-Poly1305 AEAD content encryption. Lives under `b.jose.jwe.experimental` because the JOSE PQC IANA codepoint registration ([draft-ietf-jose-pqc-kem-05](https://datatracker.ietf.org/doc/draft-ietf-jose-pqc-kem/)) hasn't finalized — the namespace name is the contract: codepoints may change between minors without affecting the framework's stable surface. Header carries `{ alg: "ML-KEM-1024", enc: "XC20P", "x-blamejs-experimental": true }`; decrypt refuses any envelope missing the experimental marker (defends a stable-system consumer that accidentally ingests an experimental envelope and treats it as IANA-compliant). Header bytes route through `b.safeJson.parse` for proto-pollution / depth / size defenses; header is byte-capped at 4 KiB. **(b) `b.crypto.hpke.pq.connolly.seal` / `.open` + `b.crypto.hpke.pq.wg.seal` / `.open`** — both active PQ-HPKE drafts behind explicit opt-in: [draft-connolly-cfrg-hpke-mlkem-04](https://datatracker.ietf.org/doc/draft-connolly-cfrg-hpke-mlkem/) (individual; codepoints today) and [draft-ietf-hpke-pq-03](https://datatracker.ietf.org/doc/draft-ietf-hpke-pq/) (WG-adopted). Each wrapper binds a draft-distinguishing label into the RFC 9180 §5.1 `info` parameter so cross-draft substitution (sealing under connolly and opening as wg, or vice versa) refuses by construction — the derived AEAD key diverges and Poly1305 verify fails. Both compose the existing `b.crypto.hpke.seal` / `.open` core (ML-KEM-1024 KEM + HKDF-SHA3-512 + ChaCha20-Poly1305 per project PQC-first policy); the wrappers add the draft-isolation label without touching the wire-format primitives. **New audit namespace:** `jose` (`jose.jwe.experimental.encrypt` / `.decrypt`). **Operator impact:** no breaking changes. The stable `b.crypto.hpke.seal` and the existing `b.crypto.encrypt` envelope shape are unaffected. Operators integrating against systems speaking one of the active PQ-HPKE drafts use the explicit `.pq.connolly` / `.pq.wg` paths; operators wanting IANA-final codepoints wait for graduation to the stable surface (one-minor deprecation window will ship when IANA registration lands). The framework refuses to silently pick a winner between the two drafts. **Deferred to follow-up:** COSE-PQ signatures (draft-ietf-cose-pqc-* — pending IANA codepoint registration), JWE JSON serialization variant (compact-only at this experimental tier), FIPS 203 KAT test vectors against the vendored bundle (test-corpus addition; functional parity is established by the existing v0.8.41 hybrid-KEM verify path). References: [draft-ietf-jose-pqc-kem-05](https://datatracker.ietf.org/doc/draft-ietf-jose-pqc-kem/) · [draft-connolly-cfrg-hpke-mlkem-04](https://datatracker.ietf.org/doc/draft-connolly-cfrg-hpke-mlkem/) · [draft-ietf-hpke-pq-03](https://datatracker.ietf.org/doc/draft-ietf-hpke-pq/) · [RFC 9180 HPKE](https://www.rfc-editor.org/rfc/rfc9180.html) · [RFC 7516 JWE](https://www.rfc-editor.org/rfc/rfc7516.html) · [FIPS 203 ML-KEM](https://csrc.nist.gov/pubs/fips/203/final) · [draft-irtf-cfrg-xchacha XChaCha20-Poly1305](https://datatracker.ietf.org/doc/draft-irtf-cfrg-xchacha/).
|
|
13
15
|
- v0.10.9 (2026-05-17) — **Ergonomic helpers bundle (A / B / C / D / E / H).** Six small DX primitives bundled into one release. **(a) `b.safePath.resolve` / `.resolveOrNull` / `.validate`** — path-traversal-safe multi-segment resolve. Refuses absolute / UNC / drive-letter `rel`, NUL bytes, C0 control chars, bidi-override codepoints (CVE-2021-42574 Trojan Source class), URL-encoded + fullwidth + division-slash path separators, Windows reserved device names CON / PRN / AUX / NUL / COM[0-9] / LPT[0-9] on EVERY platform (closes [CVE-2025-27210](https://nvd.nist.gov/vuln/detail/CVE-2025-27210) cross-mount class), trailing-`.`/trailing-space segments under windows-mode, NTFS Alternate Data Stream markers ([CVE-2024-12217](https://nvd.nist.gov/vuln/detail/CVE-2024-12217) class), and `..` segments that escape `base` after lexical resolve. Optional `opts.realpath: true` adds symlink-escape detection via `fs.realpathSync.native`. Every documented failure mode → coded refusal (`safe-path/absolute-rel` / `null-byte` / `bidi` / `win-reserved` / `escapes-base` / etc.); no best-effort path. **(b) `b.bootGates.run([{ name, fn, timeoutMs?, exitCode?, onFail? }], opts?)`** — sequential boot-invariant runner. Each gate runs in order; on first failure: emits `bootgates.failed` audit, runs the gate's `onFail` callback (swallows + audits onFail throws), writes a single-line failure summary via `opts.log`, and calls the operator-supplied `opts.exit(code)`. The default `exit` throws `BootGatesError("bootgates/no-exit-wired")` rather than calling `process.exit` directly (lib/ never terminates the process — the CLI surface owns that wiring). Each gate runs under a 60s default `timeoutMs` budget configurable per-gate; overall budget via `opts.overallTimeoutMs`. **(c) `b.metrics.snapshot.shadowRegistry({ namespace, counters, gauges, info, cardinalityCap?, onCardinalityExceeded? })`** — namespaced shadow registry that mirrors a subset of a primary registry's metrics for export to systems needing isolated views (sidecar / per-tenant scrape endpoint / compliance-tagged subset). Cardinality cap (default 10000 per metric name) closes the [client_golang CVE-2022-21698](https://nvd.nist.gov/vuln/detail/CVE-2022-21698) unbounded-cardinality DoS class; policy is `drop` (default), `audit-only`, or `refuse`. Emits `metrics.shadow.cardinality_dropped` audit (rate-limited to 1/sec per shadow registry). **(d) Per-instance `agent.reloadCerts({ cert, key, ca })` on `b.pqcAgent.create()` returns** — long-running daemons that rotate TLS material via explicit `b.pqcAgent.create()` agents previously needed a process restart; the new instance method tests the new material via `tls.createSecureContext`, swaps `agent.options` atomically, closes idle keep-alive sockets via `agent.destroy()` (in-flight sockets complete naturally), and emits `pqcagent.reloadCerts` audit. Cert/key mismatch surfaces as `pqcagent/reload-mismatch` with the OpenSSL chain; CA bundle parse failures surface as `pqcagent/reload-bad-ca`. **(e) `b.metrics.snapshot.render(snap, { format: "text", groups })`** — operator-readable text format gains an `opts.groups` map that sections the output (`== HTTP ==` / `== Queue ==` / `== TLS ==`); fields not named in any group fall to `== Other ==`. Group ordering preserved per insertion order. Prometheus / OpenMetrics formats unchanged. **(h) ISO-8601 date strings render-eligible in the text format** — timestamps shaped as `2026-05-17T20:00:00.000Z` (length-bounded at 64 chars) now render verbatim in the text format instead of degrading to `[skipped: non-numeric]`; the Prometheus format gets a parallel `<name>_epoch_ms` gauge so downstream alerting can compute durations per OpenMetrics 1.0 §3.4 (Timestamps MUST be float64 Unix-epoch). Non-ISO strings continue to skip in Prometheus (label-value injection defense). **New compliance scaffold:** new namespace `b.bootGates`. New audit namespaces: `bootgates`, `metrics`. **Operator impact:** no breaking changes. `b.bootGates.run` callers MUST supply `opts.exit: process.exit.bind(process)` from their daemon main() if they want the failure path to terminate the process — the default-throw shape exists so lib/-internal callers can't accidentally `process.exit` from inside a primitive. `b.safePath.resolve` is a brand-new primitive; existing code is unaffected. References: [Node.js path.resolve docs](https://nodejs.org/api/path.html#pathresolvepaths) · [CVE-2025-27210 Windows device-name bypass](https://nvd.nist.gov/vuln/detail/CVE-2025-27210) · [CVE-2024-12217 NTFS ADS](https://nvd.nist.gov/vuln/detail/CVE-2024-12217) · [CVE-2021-42574 Trojan Source](https://nvd.nist.gov/vuln/detail/CVE-2021-42574) · [CVE-2022-21698 Prometheus cardinality DoS](https://nvd.nist.gov/vuln/detail/CVE-2022-21698) · [OpenMetrics 1.0 spec](https://github.com/prometheus/OpenMetrics/blob/v1.0.0/specification/OpenMetrics.md) · [CVE-2026-21637 SNI sync-throw](https://nvd.nist.gov/vuln/detail/CVE-2026-21637).
|
package/README.md
CHANGED
|
@@ -95,6 +95,8 @@ The framework bundles the surface a typical Node app reaches for. Every primitiv
|
|
|
95
95
|
- **AAD-bound sealed columns** — AEAD tag tied to `(table, rowId, column, schemaVersion)`; copy-paste between rows or schema-version replay surfaces as refused decrypt (`b.vault.aad`)
|
|
96
96
|
- **Signed webhooks + API encryption** — SLH-DSA-SHAKE-256f default; ML-DSA-65 opt-in; ECIES API encryption (`b.webhook`, `b.crypto`)
|
|
97
97
|
- **HPKE / HTTP signatures** — RFC 9180 HPKE with ML-KEM-1024 + HKDF-SHA3-512 + ChaCha20-Poly1305 (`b.crypto.hpke`); RFC 9421 HTTP Message Signatures with derived components and ed25519 / ML-DSA-65 (`b.crypto.httpSig`)
|
|
98
|
+
- **CMS codec** — RFC 5652 Cryptographic Message Syntax encoder + decoder with PQC signers (ML-DSA-65 / ML-DSA-87 / SLH-DSA-SHAKE-256f; RFC 9909 + 9881) and KEMRecipientInfo recipients (ML-KEM-1024; RFC 9629 + 9936); ChaCha20-Poly1305 content encryption (RFC 8103) so Efail-class malleability cannot apply (`b.cms`)
|
|
99
|
+
- **Stream throttle** — shared token-bucket bandwidth limiter (RFC 2697 srTCM shape); N concurrent `node:stream` pipelines draw from one operator-configured `bytesPerSec` budget (`b.streamThrottle`)
|
|
98
100
|
- **TLS / channel binding** — RFC 9266 TLS-Exporter token-to-session pinning (`b.tlsExporter`); RFC 9162 CT v2 inclusion-proof verification (`b.network.tls.ct.verifyInclusion`); RFC 8555 ACME + RFC 9773 ARI for 47-day certs with `{ jitter: true }` fleet-scheduling (`b.acme.renewIfDue`); draft-aaron-acme-profiles (`acme.listProfiles()` + `newOrder({ profile })`); draft-ietf-acme-dns-account-label (`acme.dnsAccount01ChallengeRecord(token, { identifier })`); RFC 8470 0-RTT inbound posture refuse / replay-cache (`b.router.create({tls0Rtt})`); RFC 9794 SecP256r1MLKEM768 in preferred-group order (`b.network.tls.preferredGroups`)
|
|
99
101
|
- **mTLS CA** — pure-JS, issues clientAuth / serverAuth / dual-EKU certs with SAN; auto-detects highest-PQC signature alg (today ECDSA-P384-SHA384; self-upgrades to SLH-DSA / ML-DSA when X.509 ecosystem catches up); PQC TLS gates inbound + outbound (`b.mtlsCa`, `b.pqcGate`, `b.pqcAgent`)
|
|
100
102
|
### HTTP
|
package/index.js
CHANGED
|
@@ -375,9 +375,13 @@ var watcher = require("./lib/watcher");
|
|
|
375
375
|
var localDbThin = require("./lib/local-db-thin");
|
|
376
376
|
var daemon = require("./lib/daemon");
|
|
377
377
|
var selfUpdate = require("./lib/self-update");
|
|
378
|
+
var cmsCodec = require("./lib/cms-codec");
|
|
379
|
+
var streamThrottle = require("./lib/stream-throttle");
|
|
378
380
|
|
|
379
381
|
module.exports = {
|
|
380
382
|
crypto: crypto,
|
|
383
|
+
cms: cmsCodec,
|
|
384
|
+
streamThrottle: streamThrottle,
|
|
381
385
|
router: router,
|
|
382
386
|
constants: constants,
|
|
383
387
|
vault: vault,
|