@blamejs/core 0.13.22 → 0.13.23
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/archive-wrap.js +1 -1
- package/lib/auth/jwt.js +7 -4
- package/lib/auth/saml.js +2 -2
- package/lib/cose.js +1 -1
- package/lib/did.js +1 -1
- package/lib/link-header.js +3 -2
- package/lib/mail-agent.js +4 -2
- package/lib/middleware/rate-limit.js +2 -2
- package/lib/tsa.js +2 -1
- 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.13.x
|
|
10
10
|
|
|
11
|
+
- v0.13.23 (2026-05-28) — **Documentation corrected to match actual behavior across several primitives.** A set of JSDoc / doc-comment corrections where the documented contract had drifted from what the code does. No behavior changes — the implementations already behaved as now documented; only the docs were wrong. The most operator-relevant is the JWT signer doc: an expiring token signed without an explicit jti receives an auto-minted 128-bit jti (so the replay-defense path has the jti it needs), which the sign-opts doc previously denied. Also corrected: did.resolve's unsupported-method error now names did:jwk (always supported); b.cose.verify is marked stable to match its stable sign sibling and the CWT / EAT / SCITT / mdoc verifiers built on it; b.linkHeader.serialize's doc now states every parameter value is double-quoted; b.auth.saml verifyResponse's documented return shape now lists inResponseTo and issuer (both always returned); and the rate-limit custom-backend contract drops a gc member the middleware never invoked. **Fixed:** *JWT signer doc now describes the auto-minted jti on expiring tokens* — `b.auth.jwt.sign`'s opts doc claimed that omitting `jti` adds no jti. In fact, when a token carries an `exp` and no operator-supplied `jti`, the signer auto-mints a random 128-bit `jti` so a replay-protected token always carries the identifier `verify`'s replay store requires. The doc now describes this; pass an explicit `jti` for a deterministic value. Behavior is unchanged. · *`b.did.resolve` unsupported-method error now names did:jwk* — The thrown error for an unsupported DID method listed only `did:key` and `did:web`, omitting `did:jwk`, which `resolve` fully supports. The message now reads `(did:key, did:jwk, and did:web only)`. · *`b.cose.verify` marked stable* — `b.cose.verify` carried `@status experimental` while its `b.cose.sign` sibling is stable and the CWT / EAT / SCITT / mdoc verifiers that depend on it are stable and shipped. The verifier is the same maturity as the rest of the COSE_Sign1 round-trip; its status now reflects that. · *`b.linkHeader.serialize` doc matches its quoting behavior* — The doc said parameters are token-encoded when they fit RFC 7230 token grammar and double-quoted otherwise. The serializer always double-quotes every value (valid under RFC 8288, and required for space-separated multi-rel and media-type values). The doc now states that. · *`b.auth.saml` verifyResponse documented return shape lists all fields* — The prose and the example each omitted a different field that `verifyResponse` always returns. The documented shape now lists all of `nameId`, `nameIdFormat`, `sessionIndex`, `attributes`, `audience`, `inResponseTo`, and `issuer`. · *rate-limit custom-backend contract is `{ take, reset }`* — The custom-backend opts doc listed a `gc` member that the middleware never reads or invokes (the runtime contract is `take` / `reset` / `close`, and the error message already said `{ take, reset }`). The documented shape now matches; an operator-supplied `gc` was always silently ignored. · *`b.mail.agent.create` doc no longer lists consumer as a method* — The created agent's method list named `consumer`, which is not a method on the returned object — the queue consumer is the sibling export `b.mail.agent.consumer`. The doc now says so.
|
|
12
|
+
|
|
11
13
|
- v0.13.22 (2026-05-27) — **`b.archive.read.zip.fromTrustedStream` reads a ZIP from a Readable — no longer an experimental stub.** fromTrustedStream was an experimental stub whose inspect / entries / extract methods threw, forcing callers to buffer the stream themselves and use the random-access reader. It now works, with the same shape as the tar trusted-stream reader: pass b.archive.adapters.trustedStream(readable) and the bytes are collected into a size-capped buffer (1 GiB hard ceiling) and read through the same bomb-cap, path-traversal, and entry-type decode as the random-access reader — so bombPolicy, guardProfile, entryTypePolicy, and audit all apply, and inspect / entries / extract / extractEntries all return data. This is a bounded-memory reader (the archive is held in memory under the ceiling), not zero-buffer streaming; a future forward-inflate walker shared with the tar reader would lift the ceiling. **Added:** *`b.archive.read.zip.fromTrustedStream` now reads — `inspect` / `entries` / `extract` / `extractEntries`* — The ZIP trusted-stream reader is implemented (was an experimental stub that threw). Pass `b.archive.adapters.trustedStream(readable)` to read a ZIP straight from a Node Readable without buffering it yourself. The stream is collected into a size-capped buffer (1 GiB ceiling, matching `b.archive.read.tar`'s trusted-stream reader) and decoded through the same adversarial-safe path as the random-access reader, so `bombPolicy` / `guardProfile` / `entryTypePolicy` / `audit` are honored on decode. Adversarial archives remain fully bomb-capped; "trusted" refers only to the source-size bound. A non-trusted-stream adapter is refused with `archive-read/bad-adapter`.
|
|
12
14
|
|
|
13
15
|
- v0.13.21 (2026-05-27) — **`b.cose.exportKey` — serialize a public key as a COSE_Key, the inverse of `b.cose.importKey`.** b.cose could import a COSE_Key (RFC 9052 §7) into a node:crypto key for verification, but had no way to produce one — so a key used with b.cose.sign could not be shipped to a verifier in COSE form without hand-building the CBOR map. b.cose.exportKey(keyObject, opts?) closes the round-trip: it serializes an EC2 (P-256 / P-384 / P-521) or OKP (Ed25519) public key as the CBOR-encoded COSE_Key map, with optional alg and kid common parameters. A private key has its public half exported; unsupported curves / key types are refused rather than emitting a COSE_Key no verifier here would accept. The bytes round-trip through b.cose.importKey, and feed the mdoc MSO / COSE_Key header / SCITT / C2PA verification-key paths. **Added:** *`b.cose.exportKey(keyObject, { alg?, kid? })` — KeyObject → COSE_Key (RFC 9052 §7)* — Serialize a `node:crypto` public key as the CBOR-encoded COSE_Key map — the inverse of `b.cose.importKey`. Supports EC2 (P-256 / P-384 / P-521) and OKP (Ed25519), the same key types `b.cose.verify` accepts; `opts.alg` (e.g. `"ES256"`) and `opts.kid` populate the COSE_Key alg (label 3) and kid (label 2) common parameters. A private key exports its public half; unsupported curves / key types throw rather than producing a COSE_Key no verifier would accept. `b.cose.importKey(b.cbor.decode(exportKey(k)))` round-trips, so a key signed with `b.cose.sign` can be shipped to a verifier as bytes — the mdoc MSO / COSE_Key header / SCITT / C2PA verification-key paths.
|
package/lib/archive-wrap.js
CHANGED
|
@@ -370,7 +370,7 @@ function sniffEnvelope(bytes) {
|
|
|
370
370
|
* @signature b.archive.wrapWithPassphrase(bytes, opts)
|
|
371
371
|
* @since 0.12.11
|
|
372
372
|
* @status stable
|
|
373
|
-
* @related b.archive.unwrapWithPassphrase, b.archive.wrap
|
|
373
|
+
* @related b.archive.unwrapWithPassphrase, b.archive.wrap
|
|
374
374
|
*
|
|
375
375
|
* Wrap archive bytes in a passphrase-derived envelope. The envelope
|
|
376
376
|
* wire format is the framework's standard Argon2id (RFC 9106) +
|
package/lib/auth/jwt.js
CHANGED
|
@@ -48,10 +48,13 @@
|
|
|
48
48
|
* subject: claims.sub override
|
|
49
49
|
* expiresInSec: relative exp (claims.exp = now + expiresInSec)
|
|
50
50
|
* notBeforeSec: relative nbf (claims.nbf = now + notBeforeSec)
|
|
51
|
-
* jti: claims.jti override (string
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
*
|
|
51
|
+
* jti: claims.jti override (string). When omitted, a random
|
|
52
|
+
* 128-bit jti is auto-minted if (and only if) the token
|
|
53
|
+
* carries an exp — so a replay-protected token always
|
|
54
|
+
* has the jti the verifier's replay store requires,
|
|
55
|
+
* closing the silent hole where a sign without jti would
|
|
56
|
+
* never replay-protect. Pass an explicit jti for a
|
|
57
|
+
* deterministic value.
|
|
55
58
|
* now: test-time clock injection (epoch milliseconds)
|
|
56
59
|
*
|
|
57
60
|
* Verify opts:
|
package/lib/auth/saml.js
CHANGED
|
@@ -415,7 +415,7 @@ function create(opts) {
|
|
|
415
415
|
* (Response-level OR Assertion-level signature), the assertion's
|
|
416
416
|
* SubjectConfirmation Bearer constraints, and Conditions audience
|
|
417
417
|
* + time bounds. Returns `{ nameId, nameIdFormat, sessionIndex,
|
|
418
|
-
* attributes, audience, inResponseTo }`.
|
|
418
|
+
* attributes, audience, inResponseTo, issuer }`.
|
|
419
419
|
*
|
|
420
420
|
* @opts
|
|
421
421
|
* {
|
|
@@ -428,7 +428,7 @@ function create(opts) {
|
|
|
428
428
|
* var info = sp.verifyResponse(req.body.SAMLResponse, {
|
|
429
429
|
* expectedInResponseTo: req.session.samlRequestId,
|
|
430
430
|
* });
|
|
431
|
-
* // → { nameId, nameIdFormat, sessionIndex, attributes, audience, issuer }
|
|
431
|
+
* // → { nameId, nameIdFormat, sessionIndex, attributes, audience, inResponseTo, issuer }
|
|
432
432
|
* });
|
|
433
433
|
*/
|
|
434
434
|
function verifyResponse(samlResponseB64, vopts) {
|
package/lib/cose.js
CHANGED
|
@@ -227,7 +227,7 @@ async function sign(payload, opts) {
|
|
|
227
227
|
* @primitive b.cose.verify
|
|
228
228
|
* @signature b.cose.verify(coseSign1, opts)
|
|
229
229
|
* @since 0.12.33
|
|
230
|
-
* @status
|
|
230
|
+
* @status stable
|
|
231
231
|
* @related b.cose.sign, b.cbor.decode
|
|
232
232
|
*
|
|
233
233
|
* Verify a COSE_Sign1 (RFC 9052) and return its payload + headers.
|
package/lib/did.js
CHANGED
|
@@ -365,7 +365,7 @@ function resolve(did, opts) {
|
|
|
365
365
|
return { didDocument: docW, verificationMethods: _extractVerificationMethods(docW) };
|
|
366
366
|
}
|
|
367
367
|
|
|
368
|
-
throw new DidError("did/unsupported-method", "did.resolve: unsupported DID method '" + parsed.method + "' (did:key and did:web only)");
|
|
368
|
+
throw new DidError("did/unsupported-method", "did.resolve: unsupported DID method '" + parsed.method + "' (did:key, did:jwk, and did:web only)");
|
|
369
369
|
}
|
|
370
370
|
|
|
371
371
|
// Import a publicKeyJwk after allowlisting its kty/crv — a DID document
|
package/lib/link-header.js
CHANGED
|
@@ -125,8 +125,9 @@ function _serParam(name, value) {
|
|
|
125
125
|
* Build an HTTP <code>Link</code> header value from an array of
|
|
126
126
|
* <code>{ uri, rel, params? }</code> (or a single such object). The URI
|
|
127
127
|
* is angle-bracketed, <code>rel</code> (string or array) is emitted
|
|
128
|
-
* first, and
|
|
129
|
-
*
|
|
128
|
+
* first, and every parameter value is double-quoted (always valid under
|
|
129
|
+
* RFC 8288, and required for space-separated multi-rel and media-type
|
|
130
|
+
* values like <code>text/html</code>). Useful for emitting standard REST
|
|
130
131
|
* pagination links.
|
|
131
132
|
*
|
|
132
133
|
* @example
|
package/lib/mail-agent.js
CHANGED
|
@@ -156,8 +156,10 @@ var COMPOSE_HINT = Object.freeze({
|
|
|
156
156
|
* @related b.mailStore, b.mail.agent.consumer
|
|
157
157
|
*
|
|
158
158
|
* Create the agent facade. Returns an object with read / write / sieve
|
|
159
|
-
* / identity / mdn / export / import
|
|
160
|
-
* synchronous-shaped via promises; writes audit on completion.
|
|
159
|
+
* / identity / mdn / export / import methods. Reads stay
|
|
160
|
+
* synchronous-shaped via promises; writes audit on completion. (The
|
|
161
|
+
* queue consumer is the sibling export <code>b.mail.agent.consumer</code>,
|
|
162
|
+
* not a method on this object.)
|
|
161
163
|
*
|
|
162
164
|
* @opts
|
|
163
165
|
* store: b.mailStore instance, // required
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
* header: true // set X-RateLimit-* response headers
|
|
37
37
|
* skipPaths: [] // string-prefix or regex matchers
|
|
38
38
|
* scope: 'global' | 'per-route' (default 'global')
|
|
39
|
-
* backend: 'memory' (default) | 'cluster' | { take, reset
|
|
39
|
+
* backend: 'memory' (default) | 'cluster' | { take, reset }
|
|
40
40
|
* algorithm: 'token-bucket' (default) | 'fixed-window'
|
|
41
41
|
* // memory backend only; ignored
|
|
42
42
|
* // for cluster backend (which is
|
|
@@ -366,7 +366,7 @@ function _resolveBackend(opts) {
|
|
|
366
366
|
* header: boolean, // default true
|
|
367
367
|
* skipPaths: Array<string|RegExp>,
|
|
368
368
|
* scope: "global"|"per-route",
|
|
369
|
-
* backend: "memory"|"cluster"|{ take, reset
|
|
369
|
+
* backend: "memory"|"cluster"|{ take, reset },
|
|
370
370
|
* algorithm: "token-bucket"|"fixed-window",
|
|
371
371
|
* burst: number,
|
|
372
372
|
* refillPerSecond: number,
|
package/lib/tsa.js
CHANGED
|
@@ -183,7 +183,8 @@ function buildRequest(data, opts) {
|
|
|
183
183
|
nonce = Buffer.isBuffer(opts.nonce) ? opts.nonce : nodeCrypto.randomBytes(8); // allow:raw-byte-literal — RFC 3161 nonce: 64-bit random
|
|
184
184
|
children.push(asn1.writeInteger(nonce));
|
|
185
185
|
}
|
|
186
|
-
// certReq
|
|
186
|
+
// certReq DEFAULTS TRUE (RFC 3161 §2.4.1) — encode the boolean unless
|
|
187
|
+
// the caller explicitly opts out with certReq:false.
|
|
187
188
|
var certReq = opts.certReq !== false;
|
|
188
189
|
if (certReq) children.push(asn1.writeBoolean(true));
|
|
189
190
|
|
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:a0f54545-2664-4289-8bd2-f3db973d437a",
|
|
6
6
|
"version": 1,
|
|
7
7
|
"metadata": {
|
|
8
|
-
"timestamp": "2026-05-
|
|
8
|
+
"timestamp": "2026-05-28T08:15:53.205Z",
|
|
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.13.
|
|
22
|
+
"bom-ref": "@blamejs/core@0.13.23",
|
|
23
23
|
"type": "application",
|
|
24
24
|
"name": "blamejs",
|
|
25
|
-
"version": "0.13.
|
|
25
|
+
"version": "0.13.23",
|
|
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.13.
|
|
29
|
+
"purl": "pkg:npm/%40blamejs/core@0.13.23",
|
|
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.13.
|
|
57
|
+
"ref": "@blamejs/core@0.13.23",
|
|
58
58
|
"dependsOn": []
|
|
59
59
|
}
|
|
60
60
|
]
|