@blamejs/core 0.14.7 → 0.14.9
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 +4 -0
- package/lib/a2a-tasks.js +6 -6
- package/lib/ai-input.js +1 -1
- package/lib/auth/acr-vocabulary.js +1 -1
- package/lib/auth/ciba.js +3 -3
- package/lib/auth/oauth.js +1 -1
- package/lib/auth/oid4vci.js +1 -1
- package/lib/auth/openid-federation.js +1 -1
- package/lib/auth/saml.js +5 -5
- package/lib/backup/index.js +3 -3
- package/lib/breach-deadline.js +3 -3
- package/lib/calendar.js +2 -2
- package/lib/compliance-ai-act.js +7 -7
- package/lib/compliance.js +21 -21
- package/lib/content-credentials.js +3 -3
- package/lib/ddl-change-control.js +2 -2
- package/lib/did.js +2 -2
- package/lib/dsr.js +5 -5
- package/lib/external-db.js +1 -1
- package/lib/guard-archive.js +1 -1
- package/lib/guard-cidr.js +1 -1
- package/lib/guard-image.js +1 -1
- package/lib/guard-list-unsubscribe.js +1 -1
- package/lib/guard-time.js +1 -1
- package/lib/guard-xml.js +1 -1
- package/lib/http-client-cache.js +1 -1
- package/lib/iab-tcf.js +4 -4
- package/lib/json-schema.js +1 -1
- package/lib/jtd.js +1 -1
- package/lib/mail-auth.js +1 -1
- package/lib/mail-bimi.js +1 -1
- package/lib/mail-crypto-pgp.js +1 -1
- package/lib/mail-crypto-smime.js +1 -1
- package/lib/mail-server-mx.js +1 -1
- package/lib/mail-server-rate-limit.js +1 -1
- package/lib/mail-server-submission.js +1 -1
- package/lib/mcp.js +7 -7
- package/lib/mdoc.js +1 -1
- package/lib/metrics.js +2 -2
- package/lib/middleware/compose-pipeline.js +1 -1
- package/lib/network-dnssec.js +2 -2
- package/lib/network-smtp-policy.js +1 -1
- package/lib/network-tls.js +1 -1
- package/lib/network-tsig.js +3 -3
- package/lib/parsers/index.js +0 -6
- package/lib/rfc3339.js +2 -2
- package/lib/safe-decompress.js +1 -1
- package/lib/standard-webhooks.js +3 -3
- package/lib/stream-throttle.js +2 -2
- package/lib/structured-fields.js +1 -1
- package/lib/vault/seal-pem-file.js +1 -1
- package/lib/web-push-vapid.js +1 -1
- package/lib/webhook.js +1 -1
- package/lib/websocket.js +1 -1
- package/package.json +1 -1
- package/sbom.cdx.json +6 -6
package/CHANGELOG.md
CHANGED
|
@@ -8,6 +8,10 @@ upgrading across more than a few patches at a time.
|
|
|
8
8
|
|
|
9
9
|
## v0.14.x
|
|
10
10
|
|
|
11
|
+
- v0.14.9 (2026-05-30) — **Corrects EU AI Act doc paths that named an uncallable namespace, plus source-comment hygiene and two new codebase checks.** A documentation fix and internal hygiene. The `@primitive` / `@signature` / `@example` blocks for the EU AI Act fundamental-rights-impact-assessment and GPAI training-data-summary helpers advertised `b.complianceAiAct.*`, which is undefined — the callable path is `b.compliance.aiAct.*` — so an operator copying the documented call got `undefined is not a function`. The documented paths now match the real surface. Alongside that: a duplicate parser entry in a doc block is removed, version stamps embedded in section-divider comments are stripped, and two codebase checks are added — one that fails the build when a `@primitive` block documents a wholly-unresolvable namespace (the gap that hid the AI Act paths), and one that flags a version stamp left inside a section divider. No exported API, error code, wire format, or runtime behaviour changes. **Changed:** *Source-comment hygiene* — Removed a duplicate `env` entry from the parsers `@module` doc block, and stripped internal version stamps (`vX.Y.Z`) from `// ---- ... ----` section-divider comments across several files, keeping the descriptive label. Comment-only; no behaviour change. **Fixed:** *EU AI Act helper documentation named an uncallable path* — `b.compliance.aiAct.fundamentalRightsImpactAssessment` and `b.compliance.aiAct.gpai.trainingDataSummary` were documented as `b.complianceAiAct.*` in their `@primitive` / `@signature` / `@example` blocks (and one returned reference string). `b.complianceAiAct` is undefined, so the documented call failed; the documented paths now match the callable surface. **Detectors:** *`@primitive` reachability covers wrong-namespace paths* — The reachability check previously only flagged a missing leaf on a resolved namespace; a `@primitive` whose entire dotted prefix is unresolvable (the shape that hid the AI Act doc paths) was silently skipped. It now walks each prefix segment and fails the build on any unresolvable one, while preserving the factory-instance-shorthand exemption. · *Version-stamp-in-divider check* — A new check flags a version stamp (`vX.Y.Z`) left immediately after a section divider's dashes (`// ---- vX.Y.Z ...`) — internal release vocabulary that does not belong in shipped source comments — without matching legitimate `@since` tags or prose version references.
|
|
12
|
+
|
|
13
|
+
- v0.14.8 (2026-05-30) — **Source-comment and codebase-check hygiene, plus a new require-block alignment check; no API or behaviour changes.** Internal lint and comment cleanup with no operator-facing surface change. Several codebase-check comments and one stub helper name that described behaviour the check no longer has are corrected; an unused lint-suppression class and a set of stale duplicate-cluster qualifiers (functions that were since renamed or extracted) are pruned or re-pointed. Fifty-nine `// allow:` markers that named the byte-size or time-literal check on values those checks no longer flag are removed, and twenty self-negating rationales on markers the time check genuinely fires on are rewritten to say why the value coincidentally matches. A new codebase check holds top-of-file require blocks to consistent `=` column alignment, with the files that currently carry drift listed as a migration allowlist. No exported API, error code, wire format, or runtime behaviour changes. **Changed:** *Lint-suppression and codebase-check comment cleanup* — Corrected codebase-check comments that overstated their check's scope (a duplicate-code threshold described as three files when the advisory threshold is two, a narrowed byte-literal check carrying its pre-narrowing description, and a deferred-scan helper named as though it enforced a guarantee it does not yet provide). Removed an unused lint-suppression class and its one dead in-code marker, and pruned or re-pointed stale duplicate-cluster qualifiers that named functions since renamed or extracted into shared helpers. Removed fifty-nine `// allow:` markers that suppressed nothing, and rewrote twenty self-negating marker rationales (which read "not seconds" while sitting on a value the time check fires on) to explain the coincidental match. Source-comment and test hygiene only. **Detectors:** *Require-block `=` alignment check* — A new codebase check flags a top-of-file require block that mixes its `=` column alignment — a fittable line whose `=` drifts off the column the rest of the block shares. Compact single-space blocks are exempt (only blocks that declare alignment intent are checked), as are destructures and long names physically too wide to reach the column, and blank- or comment-separated tiers align independently. The files that currently carry such drift are an explicit migration allowlist, reflowed over time; new code is held to the rule.
|
|
14
|
+
|
|
11
15
|
- v0.14.7 (2026-05-30) — **Storage and audit-trail hardening: queries are gated to declared columns, raw SQL refuses embedded literals, the database key is bound to its location, sealed-column lookup hashes gain a keyed mode, audit-chain purges can require dual control, and breach deadlines ship a running clock.** This release tightens the data and audit layers against a set of failure modes that were previously reachable. Database queries are now checked against the columns a table declared in its schema: a reference to an undeclared column fails closed by default instead of silently matching nothing, and the `whereRaw` escape hatch refuses an embedded string literal so values bind through placeholders. The database encryption key is sealed with its purpose, data directory, and key path as additional authenticated data, so a key file cannot be relocated to another deployment and unsealed there; an older key without that binding upgrades itself on first load. Sealed-column equality-lookup hashes can now be computed as a keyed MAC (HMAC-SHAKE256) off a per-deployment key, making the lookup hash unforgeable without that key, while the salted-SHA3 default is unchanged. Purging the tamper-evident audit chain can be placed under a two-authorizer dual-control grant so one operator cannot erase it alone, and database credential-rejection audits now record which relation the rejected credential tried to reach. Finally, breach-notification deadlines get a running clock that raises approaching and passed alerts as each regime's window elapses. One behavior change to note: the column gate defaults to reject — if a service issues queries against columns it did not declare in its schema, set `db.init({ columnGate: "warn" })` (audited, allowed) or `"off"` while the schema is reconciled. **Added:** *Column-membership gate on every query* — `b.db.from(table)` now checks each referenced column against the table's declared schema. The mode is set with `db.init({ columnGate: "reject" | "warn" | "off" })` (default `reject`), and `query.allowedColumns([...])` narrows a single query to an explicit allowlist that is always enforced. `b.db.getDeclaredColumns(table)` returns a table's declared column names (or `null` for an unknown table). This is defense in depth against typo'd or caller-influenced column names reaching the SQL layer (CWE-89). · *Keyed mode for sealed-column lookup hashes* — Equality-lookup ("derived") hashes for sealed columns can be computed as `hmac-shake256` — a keyed MAC over a per-deployment key — instead of the default `salted-sha3`. Set it per table with `cryptoField.registerTable(name, { derivedHashMode: "hmac-shake256" })` or per column with `{ from, mode: "hmac-shake256" }`. The keyed hash is unforgeable and un-correlatable without the deployment's MAC key, which raises the bar against offline lookup-table attacks on low-entropy sealed values (CWE-916). `b.vault.getDerivedHashMacKey()` exposes the 32-byte per-deployment key; it is created on first use and re-sealed across key rotation automatically. · *Dual-control gate on audit-chain purge* — `b.auditTools.purge` accepts `dualControlGrant`. When `audit_log` is placed under dual control, a verified archive and `confirm: true` are no longer sufficient: the purge additionally requires a consumed m-of-n grant whose action is bound to the purge, so a grant minted for another operation cannot be replayed and one operator cannot erase the tamper-evident chain alone (NIST SP 800-53 AU-9, separation of duties). · *Running clock for breach-notification deadlines* — `b.incident.report.createDeadlineClock({ notify, approachThresholds })` tracks open incidents and raises `deadline_approaching` and `deadline_passed` alerts as each regime's window elapses (GDPR 72h, DORA, NIS2, and the rest of the registry). Alerts are deduplicated per incident and stage, suppressed once a submission stage is acknowledged, and the clock can run on an interval or be ticked manually. **Changed:** *Queries against undeclared columns now fail closed by default* — The column gate defaults to `reject`: a query that references a column the table did not declare throws rather than silently matching nothing. A service that intentionally queries undeclared columns can set `db.init({ columnGate: "warn" })` to audit and allow, or `"off"` to disable the gate, while its schema is reconciled. Framework-declared columns (including `_id` and derived-hash columns) are always members. **Security:** *Database encryption key bound to its location* — `db.key.enc` is sealed with additional authenticated data over its purpose, resolved data directory, and resolved key path. A sealed key copied to a different deployment or path no longer unseals there — the AEAD authentication fails — which prevents silent key relocation. A legacy key sealed without this binding is detected and re-sealed in the bound format on first load, with no operator action required. · *`whereRaw` refuses embedded string literals* — `whereRaw(sql, params)` and `WhereBuilder.raw(sql, params)` reject a raw fragment containing a string literal (`'...'`); values must bind through the `params` array. A static, operator-controlled literal can opt in with `{ allowLiterals: true }`. This closes a path where a value concatenated into a raw fragment would reintroduce SQL injection (CWE-89). · *Credential-rejection audits record the attempted relation* — A `db.auth.failed` audit row (SQLSTATE 28000 / 28P01 / 42501) now carries `attemptedTable`, the relation the rejected credential tried to reach, extracted defensively from the statement. Triage can scope the blast radius of a credential-abuse event without correlating back to the raw SQL log (CWE-778). **Detectors:** *Audit-purge dual-control gate* — A new check fails the build if a call to `purgeAuditChain` appears in a file that does not also route through the dual-control gate, so a future caller cannot physically delete chain rows without two-authorizer enforcement. · *Raw-SQL literal/interpolation guard* — A new check fails the build on a `whereRaw` / `.raw` call whose SQL argument is built by template interpolation or string concatenation, keeping the bound-params discipline enforceable in framework code. · *Hand-rolled lookup-hash guard* — A new check fails the build if a sealed-column lookup hash is derived from the per-deployment salt outside the canonical helper, so call sites cannot bypass the keyed-mode and per-column mode policy. · *Auth-audit attempted-relation guard* — A new check fails the build if a `db.auth.failed` audit is emitted in a file that does not name `attemptedTable`, so the forensic field cannot be dropped from a future emitter.
|
|
12
16
|
|
|
13
17
|
- v0.14.6 (2026-05-30) — **Access-refusal middleware can return RFC 9457 problem+json or a custom response, and several documented-but-uncallable APIs are now reachable.** Every access-refusal middleware — the auth gates (bearer, DPoP, mTLS, AAL, bound-key), CSRF, CORS, rate-limit, bot-guard, age-gate, the host and network allowlists, and the method and content-type gates — now accepts two uniform options: `problemDetails: true` returns an RFC 9457 `application/problem+json` body, and `onDeny(req, res, info)` hands the response to the caller. With neither set the refusal is byte-for-byte what it was, so this is a drop-in change that lets a service standardize one error envelope across its API instead of working around each middleware's hardcoded body. Alongside that: `b.middleware.requireBoundKey` is now exported (it was documented and tested but never wired into the middleware surface), `b.middleware.bearerAuth` accepts `requiredScopes` (previously rejected at construction, which made its scope-enforcement path unreachable), API-key refusals send the RFC 6750 challenge code that matches the failure, two documented call paths that named a missing namespace segment are corrected, and the release flow now flags stale GitHub Actions and vendored bundles — with a ready-to-paste pin — before a dependency PR is needed. **Added:** *Uniform `onDeny` and `problemDetails` options on every access-refusal middleware* — Each request-lifecycle middleware that refuses a request now takes `problemDetails: true` to emit an RFC 9457 `application/problem+json` body (composing `b.problemDetails`) and `onDeny(req, res, info)` to take over the response entirely; `info` carries the status, a machine reason, and the middleware-specific fields. The deny-path response headers (`Allow`, `WWW-Authenticate`, `Retry-After`, `Accept`) survive every mode. When neither option is set the response is unchanged. Covers `requireAuth`, `requireAal`, `requireMethods`, `requireContentType`, `requireMtls`, `requireBoundKey`, `bearerAuth`, `dpop`, `csrfProtect`, `fetchMetadata`, `botGuard`, `ageGate`, `hostAllowlist`, `networkAllowlist`, `cors`, `rateLimit`, and `dailyByteQuota` (whose existing `onExceeded` keeps working as an alias of `onDeny`). **Fixed:** *`b.middleware.requireBoundKey` is now callable* — The Bearer-API-key middleware was documented (with examples and tests) but never exported on `b.middleware`, so `b.middleware.requireBoundKey(...)` threw `undefined is not a function`. It is now wired into the middleware surface. · *`b.middleware.bearerAuth` accepts `requiredScopes`* — The RFC 6750 scope-enforcement path read `opts.requiredScopes`, but the option was rejected at construction with `unknown option`, making the 403 `insufficient_scope` behavior unreachable. `requiredScopes` is now an accepted option. · *RFC 6750 challenge codes on API-key refusals* — `b.middleware.requireBoundKey` now sends the `WWW-Authenticate` error code that matches the failure: `insufficient_scope` on a 403 missing-scope, `invalid_token` on an unknown or revoked token, and no error code on a 401 that presented no credentials (RFC 6750 §3). It previously sent `invalid_request` for every refusal. · *Corrected two documented call paths* — The compliance and network references named a path that dropped a namespace segment: the conformity-assessment scaffold is at `b.cra.report.conformityAssessment` (not `b.cra.conformityAssessment`), and the per-socket tuning helper is at `b.network.socket.applyToSocket` (not `b.network.applyToSocket`). The documented signatures now match the callable paths. · *GitHub Actions pins refreshed* — `github/codeql-action` 4.35.5 to 4.36.0, and `docker/login-action`, `docker/setup-buildx-action`, and `docker/setup-qemu-action` to their latest releases. **Detectors:** *`@primitive` reachability gate* — A new check resolves every documented `b.X.Y` primitive against the actual public surface and fails the build when a documented path is not callable (factory-instance shorthands excluded). This is the gate that would have caught the `requireBoundKey` and call-path issues above. · *Deny-path composition gate* — A new check requires every access-refusal middleware to route its refusal through the shared deny-response writer, so a future middleware cannot reintroduce a hardcoded body that locks callers out of `onDeny` / `problemDetails`. · *Actions and vendor currency in the release flow* — The release flow now fails the cut when a SHA-pinned GitHub Action or a vendored bundle is behind its latest upstream release. The actions report prints a ready-to-paste `owner/repo@<sha> # vX.Y.Z` pin and every file and line that uses it, so the bump is copy-paste rather than an after-the-fact dependency PR. Transient registry or API errors stay advisory so a flaky network response does not block an unrelated release.
|
package/lib/a2a-tasks.js
CHANGED
|
@@ -62,17 +62,17 @@ var A2aTasksError = defineClass("A2aTasksError", { alwaysPermanent: true });
|
|
|
62
62
|
var JSONRPC_VERSION = "2.0";
|
|
63
63
|
|
|
64
64
|
// JSON-RPC 2.0 fixed error codes — A2A inherits these.
|
|
65
|
-
var JSONRPC_PARSE_ERROR = -32700; // allow:raw-time-literal — not
|
|
66
|
-
var JSONRPC_INVALID_REQUEST = -32600;
|
|
67
|
-
var JSONRPC_METHOD_NOT_FOUND = -32601;
|
|
68
|
-
var JSONRPC_INVALID_PARAMS = -32602;
|
|
69
|
-
var JSONRPC_INTERNAL_ERROR = -32603;
|
|
65
|
+
var JSONRPC_PARSE_ERROR = -32700; // allow:raw-time-literal — JSON-RPC error code -32700; coincidental multiple-of-60, not a time value, C.TIME N/A
|
|
66
|
+
var JSONRPC_INVALID_REQUEST = -32600;
|
|
67
|
+
var JSONRPC_METHOD_NOT_FOUND = -32601;
|
|
68
|
+
var JSONRPC_INVALID_PARAMS = -32602;
|
|
69
|
+
var JSONRPC_INTERNAL_ERROR = -32603;
|
|
70
70
|
|
|
71
71
|
// A2A-specific error codes per the spec's task-error vocabulary.
|
|
72
72
|
// A2A_TASK_NOT_FOUND (-32002) + A2A_TASK_NOT_CANCELABLE (-32003) are
|
|
73
73
|
// raised by operator handlers — they're reserved here for documentation
|
|
74
74
|
// purposes only.
|
|
75
|
-
var A2A_SCOPE_DENIED = -32001;
|
|
75
|
+
var A2A_SCOPE_DENIED = -32001;
|
|
76
76
|
|
|
77
77
|
var ALLOWED_METHODS = Object.freeze(["tasks/send", "tasks/get", "tasks/cancel"]);
|
|
78
78
|
|
package/lib/ai-input.js
CHANGED
|
@@ -26,7 +26,7 @@ var audit = require("./audit");
|
|
|
26
26
|
var { AiInputError } = require("./framework-error");
|
|
27
27
|
|
|
28
28
|
var SAMPLE_TRUNC = 80; // sample truncation length, not bytes
|
|
29
|
-
var CONFIDENCE_BASE = 60; // allow:raw-time-literal — not
|
|
29
|
+
var CONFIDENCE_BASE = 60; // allow:raw-time-literal — confidence-score base 60; coincidental multiple-of-60, not a duration, C.TIME N/A
|
|
30
30
|
|
|
31
31
|
var PATTERNS = [
|
|
32
32
|
{ id: "ignore-prior-instructions", severity: 3, re:
|
|
@@ -90,7 +90,7 @@ var BUILTIN_RANKS = {
|
|
|
90
90
|
"urn:mace:incommon:iap:silver": 32, // ACR rank, not bytes
|
|
91
91
|
|
|
92
92
|
// Phishing-resistant multi-factor (passkey UV)
|
|
93
|
-
"phrh": 60, // allow:raw-time-literal — ACR rank, not
|
|
93
|
+
"phrh": 60, // allow:raw-time-literal — ACR rank value 60; coincidental multiple-of-60, not a duration, C.TIME N/A
|
|
94
94
|
|
|
95
95
|
// Hardware-bound + phishing-resistant + multi-factor
|
|
96
96
|
"loa3": 70,
|
package/lib/auth/ciba.js
CHANGED
|
@@ -68,9 +68,9 @@ var emit = validateOpts.makeNamespacedEmitters("auth.ciba", { audit: audit, obse
|
|
|
68
68
|
var DEFAULT_INTERVAL_SEC = 5;
|
|
69
69
|
var DEFAULT_EXPIRES_SEC = 600;
|
|
70
70
|
var MAX_BINDING_MSG_LEN = 200;
|
|
71
|
-
var MAX_RESPONSE_BYTES = 64 * 1024;
|
|
71
|
+
var MAX_RESPONSE_BYTES = 64 * 1024;
|
|
72
72
|
var MIN_INTERVAL_SEC = 1;
|
|
73
|
-
var MAX_INTERVAL_SEC = 300; // allow:raw-time-literal — interval ceiling
|
|
73
|
+
var MAX_INTERVAL_SEC = 300; // allow:raw-time-literal — 300s polling-interval ceiling; time-derived literal, C.TIME.seconds(300) applies, retained pending migration
|
|
74
74
|
|
|
75
75
|
// _emitAudit emits under the "auth.ciba.<action>" namespace; _emitMetric
|
|
76
76
|
// fires the matching observability counter. Implementations live in
|
|
@@ -490,7 +490,7 @@ function create(opts) {
|
|
|
490
490
|
var current = entry ? entry.interval : DEFAULT_INTERVAL_SEC;
|
|
491
491
|
var idpSuggested = err.cibaError && typeof err.cibaError.interval === "number"
|
|
492
492
|
? err.cibaError.interval : null;
|
|
493
|
-
var next = current + 5;
|
|
493
|
+
var next = current + 5;
|
|
494
494
|
if (idpSuggested !== null && idpSuggested > next && idpSuggested <= MAX_INTERVAL_SEC) {
|
|
495
495
|
next = idpSuggested;
|
|
496
496
|
}
|
package/lib/auth/oauth.js
CHANGED
|
@@ -220,7 +220,7 @@ var PSS_SALT_BYTES_SHA512 = C.BYTES.bytes(64);
|
|
|
220
220
|
// CSPRNG output and refuses pathological payloads.
|
|
221
221
|
var MAX_DEVICE_CODE_BYTES = C.BYTES.kib(8);
|
|
222
222
|
// RFC 8628 §3.4 — 5s is the spec-documented MINIMUM polling interval.
|
|
223
|
-
var MIN_DEVICE_POLL_INTERVAL_SEC = 5;
|
|
223
|
+
var MIN_DEVICE_POLL_INTERVAL_SEC = 5;
|
|
224
224
|
// OIDC Back-Channel Logout §2.6 — replay defense via jti store catches
|
|
225
225
|
// duplicate-jti reuse, but pre-v0.9.x an old captured logout-token
|
|
226
226
|
// with a fresh jti could still pass. Enforce iat freshness against
|
package/lib/auth/oid4vci.js
CHANGED
|
@@ -69,7 +69,7 @@ var emit = validateOpts.makeNamespacedEmitters("auth.oid4vci", { audit: audit, o
|
|
|
69
69
|
var DEFAULT_PRE_AUTH_TTL_MS = C.TIME.minutes(5);
|
|
70
70
|
var DEFAULT_ACCESS_TOKEN_TTL = C.TIME.minutes(15);
|
|
71
71
|
var DEFAULT_C_NONCE_TTL_MS = C.TIME.minutes(5);
|
|
72
|
-
var MAX_PROOF_BYTES = 32 * 1024;
|
|
72
|
+
var MAX_PROOF_BYTES = 32 * 1024;
|
|
73
73
|
var SUPPORTED_CREDENTIAL_FORMATS = ["vc+sd-jwt", "dc+sd-jwt"];
|
|
74
74
|
|
|
75
75
|
var _emitAudit = emit.audit;
|
|
@@ -81,7 +81,7 @@ var _emitAudit = emit.audit;
|
|
|
81
81
|
var _emitMetric = emit.metric;
|
|
82
82
|
|
|
83
83
|
var SUPPORTED_ALGS = ["ES256", "ES384", "ES512", "PS256", "PS384", "PS512", "RS256", "EdDSA"];
|
|
84
|
-
var MAX_STATEMENT_BYTES = 64 * 1024;
|
|
84
|
+
var MAX_STATEMENT_BYTES = 64 * 1024;
|
|
85
85
|
var MAX_CHAIN_DEPTH = 10; // federation chain depth ceiling
|
|
86
86
|
|
|
87
87
|
function _b64uDecodeStr(s) { return Buffer.from(s, "base64url").toString("utf8"); }
|
package/lib/auth/saml.js
CHANGED
|
@@ -842,7 +842,7 @@ function create(opts) {
|
|
|
842
842
|
"</md:EntityDescriptor>";
|
|
843
843
|
}
|
|
844
844
|
|
|
845
|
-
// ----
|
|
845
|
+
// ---- Single Logout (RFC SAML Bindings §3.4 HTTP-Redirect) ----
|
|
846
846
|
|
|
847
847
|
/**
|
|
848
848
|
* @primitive b.auth.saml.sp.buildLogoutRequest
|
|
@@ -1250,7 +1250,7 @@ function create(opts) {
|
|
|
1250
1250
|
};
|
|
1251
1251
|
}
|
|
1252
1252
|
|
|
1253
|
-
// ----
|
|
1253
|
+
// ---- SLO HTTP-POST binding (SAML Bindings §3.5) ----
|
|
1254
1254
|
|
|
1255
1255
|
/**
|
|
1256
1256
|
* @primitive b.auth.saml.sp.buildLogoutRequestPost
|
|
@@ -1524,7 +1524,7 @@ function create(opts) {
|
|
|
1524
1524
|
};
|
|
1525
1525
|
}
|
|
1526
1526
|
|
|
1527
|
-
// ----
|
|
1527
|
+
// ---- SAML EncryptedAssertion decrypt (XMLEnc) ----
|
|
1528
1528
|
|
|
1529
1529
|
// XMLEnc Algorithm URIs we support.
|
|
1530
1530
|
//
|
|
@@ -1722,7 +1722,7 @@ function _decryptEncryptedAssertion(encAssertion, spPrivateKeyPem) {
|
|
|
1722
1722
|
return clearBytes.toString("utf8");
|
|
1723
1723
|
}
|
|
1724
1724
|
|
|
1725
|
-
// ----
|
|
1725
|
+
// ---- SAML SLO XMLDSig-Enveloped (HTTP-POST/SOAP) ----
|
|
1726
1726
|
|
|
1727
1727
|
// PQC SignatureMethod URIs used by the embedded XMLDSig signatures.
|
|
1728
1728
|
// Standard XMLDSig vocabulary classical signing URIs (W3C XMLDSig
|
|
@@ -1936,7 +1936,7 @@ function _verifyEmbeddedXmlDsig(xml, idpVerifyKey, idpVerifyAlg, expectedRootLoc
|
|
|
1936
1936
|
}
|
|
1937
1937
|
}
|
|
1938
1938
|
|
|
1939
|
-
// ----
|
|
1939
|
+
// ---- SAML SLO signature-alg dispatch ----
|
|
1940
1940
|
|
|
1941
1941
|
function _sigAlgUrn(alg) {
|
|
1942
1942
|
// PQC signers — framework-private experimental URIs. The `urn:`
|
package/lib/backup/index.js
CHANGED
|
@@ -1015,7 +1015,7 @@ module.exports = {
|
|
|
1015
1015
|
BUNDLE_ID_RE: BUNDLE_ID_RE,
|
|
1016
1016
|
};
|
|
1017
1017
|
|
|
1018
|
-
// ----
|
|
1018
|
+
// ---- bundleAdapterStorage ---------------------------------------
|
|
1019
1019
|
|
|
1020
1020
|
/**
|
|
1021
1021
|
* @primitive b.backup.bundleAdapterStorage
|
|
@@ -2257,7 +2257,7 @@ bundleAdapterStorage.fsAdapter = function (fsOpts) {
|
|
|
2257
2257
|
};
|
|
2258
2258
|
};
|
|
2259
2259
|
|
|
2260
|
-
// ----
|
|
2260
|
+
// ---- objectStoreAdapter ----------------------------------------
|
|
2261
2261
|
|
|
2262
2262
|
/**
|
|
2263
2263
|
* @primitive b.backup.bundleAdapterStorage.objectStoreAdapter
|
|
@@ -2475,7 +2475,7 @@ bundleAdapterStorage.objectStoreAdapter = function (client, osOpts) {
|
|
|
2475
2475
|
};
|
|
2476
2476
|
};
|
|
2477
2477
|
|
|
2478
|
-
// ----
|
|
2478
|
+
// ---- migrate ----------------------------------------------------
|
|
2479
2479
|
|
|
2480
2480
|
/**
|
|
2481
2481
|
* @primitive b.backup.migrate
|
package/lib/breach-deadline.js
CHANGED
|
@@ -48,8 +48,8 @@ var STATE_DEADLINES = Object.freeze({
|
|
|
48
48
|
// Each entry: { days, statute, asapCeilingDays }
|
|
49
49
|
// Days = statutory hard deadline in days. asapCeilingDays = the
|
|
50
50
|
// operator-defensible ceiling for "without unreasonable delay" states.
|
|
51
|
-
AL: { days: 45, statute: "Ala. Code §8-38-5" },
|
|
52
|
-
AK: { days: 45, statute: "Alaska Stat. §45.48.010" },
|
|
51
|
+
AL: { days: 45, statute: "Ala. Code §8-38-5" },
|
|
52
|
+
AK: { days: 45, statute: "Alaska Stat. §45.48.010" },
|
|
53
53
|
AZ: { days: 45, statute: "Ariz. Rev. Stat. §18-552" }, /* allow:raw-time-literal — statutory deadline days */
|
|
54
54
|
AR: { days: 45, statute: "Ark. Code §4-110-105" }, /* allow:raw-time-literal — statutory deadline days */
|
|
55
55
|
CA: { days: WITHOUT_UNREASONABLE_DELAY, statute: "Cal. Civ. Code §1798.82", asapCeilingDays: 60 }, /* allow:raw-time-literal — statutory ASAP ceiling days */
|
|
@@ -67,7 +67,7 @@ var STATE_DEADLINES = Object.freeze({
|
|
|
67
67
|
KS: { days: WITHOUT_UNREASONABLE_DELAY, statute: "Kan. Stat. §50-7a02", asapCeilingDays: 60 }, /* allow:raw-time-literal — statutory ASAP ceiling days */
|
|
68
68
|
KY: { days: WITHOUT_UNREASONABLE_DELAY, statute: "Ky. Rev. Stat. §365.732", asapCeilingDays: 60 }, /* allow:raw-time-literal — statutory ASAP ceiling days */
|
|
69
69
|
LA: { days: 60, statute: "La. Rev. Stat. §51:3074" }, /* allow:raw-time-literal — statutory deadline days */
|
|
70
|
-
ME: { days: 30, statute: "Me. Rev. Stat. tit. 10 §1348" },
|
|
70
|
+
ME: { days: 30, statute: "Me. Rev. Stat. tit. 10 §1348" },
|
|
71
71
|
MD: { days: 45, statute: "Md. Code Com. Law §14-3504" }, /* allow:raw-time-literal — statutory deadline days */
|
|
72
72
|
MA: { days: WITHOUT_UNREASONABLE_DELAY, statute: "Mass. Gen. Laws ch. 93H §3", asapCeilingDays: 30 }, /* allow:raw-time-literal — statutory ASAP ceiling days */
|
|
73
73
|
MI: { days: WITHOUT_UNREASONABLE_DELAY, statute: "Mich. Comp. Laws §445.72", asapCeilingDays: 60 }, /* allow:raw-time-literal — statutory ASAP ceiling days */
|
package/lib/calendar.js
CHANGED
|
@@ -697,7 +697,7 @@ function _expandSingleRule(rule, startMs, ctx) {
|
|
|
697
697
|
}
|
|
698
698
|
var byHourSet = _bySet(rule.byHour, 0, 23); // RFC 5545 hour range
|
|
699
699
|
var byMinuteSet = _bySet(rule.byMinute, 0, 59); // RFC 5545 minute range
|
|
700
|
-
var bySecondSet = _bySet(rule.bySecond, 0, 60); // allow:raw-time-literal — second-of-minute bound, not a duration
|
|
700
|
+
var bySecondSet = _bySet(rule.bySecond, 0, 60); // allow:raw-time-literal — second-of-minute upper bound (0..60); coincidental multiple-of-60, not a duration, C.TIME N/A
|
|
701
701
|
|
|
702
702
|
function _isoWeekParts(d) {
|
|
703
703
|
// ISO 8601 week-of-year + week-year. The week-YEAR can differ
|
|
@@ -709,7 +709,7 @@ function _expandSingleRule(rule, startMs, ctx) {
|
|
|
709
709
|
tmp.setUTCDate(tmp.getUTCDate() + 4 - dayOfWeek); // ISO week-year anchor (Thursday)
|
|
710
710
|
var weekYear = tmp.getUTCFullYear();
|
|
711
711
|
var yearStart = new Date(Date.UTC(weekYear, 0, 1));
|
|
712
|
-
var week = Math.ceil((((tmp - yearStart) / 86400000) + 1) / 7);
|
|
712
|
+
var week = Math.ceil((((tmp - yearStart) / 86400000) + 1) / 7);
|
|
713
713
|
return { week: week, year: weekYear };
|
|
714
714
|
}
|
|
715
715
|
function _isoWeekOf(d) {
|
package/lib/compliance-ai-act.js
CHANGED
|
@@ -538,8 +538,8 @@ function deployerChecklist(assessment) {
|
|
|
538
538
|
}
|
|
539
539
|
|
|
540
540
|
/**
|
|
541
|
-
* @primitive b.
|
|
542
|
-
* @signature b.
|
|
541
|
+
* @primitive b.compliance.aiAct.fundamentalRightsImpactAssessment
|
|
542
|
+
* @signature b.compliance.aiAct.fundamentalRightsImpactAssessment(opts)
|
|
543
543
|
* @since 0.8.77
|
|
544
544
|
*
|
|
545
545
|
* EU AI Act Article 27 — Fundamental Rights Impact Assessment (FRIA).
|
|
@@ -569,7 +569,7 @@ function deployerChecklist(assessment) {
|
|
|
569
569
|
* }
|
|
570
570
|
*
|
|
571
571
|
* @example
|
|
572
|
-
* var fria = b.
|
|
572
|
+
* var fria = b.compliance.aiAct.fundamentalRightsImpactAssessment({
|
|
573
573
|
* systemId: "credit-scoring-v3",
|
|
574
574
|
* deploymentContext: { purpose: "loan approval", sector: "financial",
|
|
575
575
|
* geography: "EU", scale: "1M decisions/year" },
|
|
@@ -603,13 +603,13 @@ function fundamentalRightsImpactAssessment(opts) {
|
|
|
603
603
|
notificationStatus: "operator-must-notify",
|
|
604
604
|
note: "Notify national market-surveillance authority before first use (Art 27(3))",
|
|
605
605
|
auditHook: "b.audit emission action='aiact.fria.completed' recommended",
|
|
606
|
-
annexIVReference: "see b.
|
|
606
|
+
annexIVReference: "see b.compliance.aiAct.annexIVScaffold for technical documentation",
|
|
607
607
|
};
|
|
608
608
|
}
|
|
609
609
|
|
|
610
610
|
/**
|
|
611
|
-
* @primitive b.
|
|
612
|
-
* @signature b.
|
|
611
|
+
* @primitive b.compliance.aiAct.gpai.trainingDataSummary
|
|
612
|
+
* @signature b.compliance.aiAct.gpai.trainingDataSummary(opts)
|
|
613
613
|
* @since 0.8.77
|
|
614
614
|
*
|
|
615
615
|
* EU AI Act Article 53(1)(d) — GPAI training-data summary template
|
|
@@ -634,7 +634,7 @@ function fundamentalRightsImpactAssessment(opts) {
|
|
|
634
634
|
* contentProvenance: object, // { synthIdEmbed, c2paManifestEmbed, watermarkProvider }
|
|
635
635
|
*
|
|
636
636
|
* @example
|
|
637
|
-
* var summary = b.
|
|
637
|
+
* var summary = b.compliance.aiAct.gpai.trainingDataSummary({
|
|
638
638
|
* modelId: "acme-llm-7b",
|
|
639
639
|
* modelVersion: "1.0",
|
|
640
640
|
* provider: { name: "Acme AI", address: "1 St", contact: "ai@acme.example" },
|
package/lib/compliance.js
CHANGED
|
@@ -107,12 +107,12 @@ var KNOWN_POSTURES = Object.freeze([
|
|
|
107
107
|
"bsi-c5", // Germany BSI C5
|
|
108
108
|
"ens-es", // Spain Esquema Nacional de Seguridad
|
|
109
109
|
"uk-g-cloud", // UK G-Cloud
|
|
110
|
-
// ----
|
|
110
|
+
// ---- 2026 effective deadlines ----
|
|
111
111
|
"modpa", // Maryland Online Data Privacy Act (effective 2025-10-01) — strict data-min
|
|
112
112
|
"nydfs-500", // NYDFS 23 NYCRR 500 Amendment 2 — financial cybersecurity (multi-factor + asset inventory + governance)
|
|
113
113
|
"hipaa-2026", // HHS HIPAA Security Rule 2026-Q4 final — extends hipaa with mandatory MFA + asset inventory + 72h restoration testing
|
|
114
114
|
"quebec-25", // Quebec Law 25 final phase (effective 2026-09-22) — DPIA + automated-decision opt-out
|
|
115
|
-
// ----
|
|
115
|
+
// ---- US state consumer-privacy postures ----
|
|
116
116
|
// Each posture carries per-state cure-period, profiling opt-out
|
|
117
117
|
// and minor-consent metadata via b.dsr.stateRules(state). The
|
|
118
118
|
// generic DSR primitive (b.dsr.submit) covers ~80% of the surface;
|
|
@@ -139,7 +139,7 @@ var KNOWN_POSTURES = Object.freeze([
|
|
|
139
139
|
"ct-sb3", // Connecticut SB 3 Consumer Health Data
|
|
140
140
|
"tx-cubi", // Texas Capture or Use of Biometric Identifier
|
|
141
141
|
"fl-fdbr", // Florida Digital Bill of Rights (SB 262, effective 2024-07-01) — narrow scope ($1B+ revenue threshold)
|
|
142
|
-
// ----
|
|
142
|
+
// ---- AI-governance postures ----
|
|
143
143
|
// State + sectoral AI regulations crystallizing through 2026. Each
|
|
144
144
|
// posture is a flag that operators pin alongside their base
|
|
145
145
|
// privacy/sectoral posture; the floors enforce audit-chain signing
|
|
@@ -153,20 +153,20 @@ var KNOWN_POSTURES = Object.freeze([
|
|
|
153
153
|
"ca-tfaia", // California SB 53 — Transparency in Frontier AI Act (effective 2026-01-01)
|
|
154
154
|
"kr-ai-basic", // South Korea AI Basic Act (effective 2026-01-22)
|
|
155
155
|
"cn-ai-label", // China Measures for Labelling of AI-Generated Content (effective 2025-09-01)
|
|
156
|
-
// ----
|
|
156
|
+
// ---- AI management cross-walks ----
|
|
157
157
|
"iso-42001", // ISO/IEC 42001:2023 — AI Management System
|
|
158
158
|
"iso-23894", // ISO/IEC 23894:2023 — AI Risk Management Guidance
|
|
159
|
-
// ----
|
|
159
|
+
// ---- content-credentials posture flags ----
|
|
160
160
|
"ca-sb942", // California SB-942 (Cal. Bus. & Prof. Code §22757) gen-AI disclosure (effective 2026-08-02) // regulatory identifier + date, not bytes
|
|
161
161
|
"ca-ab853", // California AB-853 platform-side gen-AI detection (effective 2026-08-02) // regulatory identifier + date, not bytes
|
|
162
|
-
// ----
|
|
162
|
+
// ---- substrate-to-posture cleanup ----
|
|
163
163
|
"eaa", // EU Accessibility Act / Directive (EU) 2019/882 (effective 2025-06-28)
|
|
164
164
|
"wcag-2-2", // W3C Web Content Accessibility Guidelines 2.2 (Oct 2023 Recommendation)
|
|
165
165
|
"eu-data-act", // EU Data Act / Regulation (EU) 2023/2854 (effective 2025-09-12)
|
|
166
166
|
"hitech", // Health Information Technology for Economic and Clinical Health Act (2009)
|
|
167
167
|
"ferpa", // Family Educational Rights and Privacy Act (20 U.S.C. §1232g)
|
|
168
168
|
"dpdp", // India Digital Personal Data Protection Act 2023 (rules-pending; cascade tier exists)
|
|
169
|
-
// ----
|
|
169
|
+
// ---- privacy 2026 sweep ----
|
|
170
170
|
// US federal child / financial privacy
|
|
171
171
|
"coppa", // Children's Online Privacy Protection Act (15 U.S.C. §6501)
|
|
172
172
|
"coppa-2025", // COPPA 2025 Amendment (FTC final 2025-04-22; effective 2026-06-23 — biometric expansion + knowing-collection disclosure)
|
|
@@ -203,7 +203,7 @@ var KNOWN_POSTURES = Object.freeze([
|
|
|
203
203
|
"eu-cer", // EU Critical Entities Resilience Directive (2022/2557; transposition 2024-10-17)
|
|
204
204
|
"eu-cyber-sol", // EU Cyber Solidarity Act (Regulation 2025/38; effective 2025-02-04)
|
|
205
205
|
"eidas-2", // eIDAS 2 / EUDI Wallet (Regulation 2024/1183; rollout 2026-2027)
|
|
206
|
-
// ----
|
|
206
|
+
// ---- sectoral + cybersecurity directives ----
|
|
207
207
|
"cmmc-2.0", // US DoD Cybersecurity Maturity Model Certification 2.0 (effective 2025-Q1)
|
|
208
208
|
"cjis-v6", // FBI Criminal Justice Information Services Security Policy v6.0 (Dec 2024)
|
|
209
209
|
"iso-27001-2022", // ISO/IEC 27001:2022 — Information Security Management System
|
|
@@ -214,7 +214,7 @@ var KNOWN_POSTURES = Object.freeze([
|
|
|
214
214
|
"nist-800-66-r2", // NIST SP 800-66 Rev 2 — HIPAA Security Rule implementation guidance // NIST publication number, not bytes
|
|
215
215
|
"ehds", // EU European Health Data Space (Regulation 2025/327; phased 2027-2029)
|
|
216
216
|
"circia", // US Cyber Incident Reporting for Critical Infrastructure Act (final rule pending)
|
|
217
|
-
// ----
|
|
217
|
+
// ---- exceptd framework-control-gap closure ----
|
|
218
218
|
// Postures added to recognise every framework cited in the
|
|
219
219
|
// exceptd 2026-05-11 framework-control-gaps catalog. Each posture
|
|
220
220
|
// either (a) maps to a framework the operator must audit against,
|
|
@@ -248,7 +248,7 @@ var KNOWN_POSTURES = Object.freeze([
|
|
|
248
248
|
"cwe-top-25-2024", // CWE Top 25 Most Dangerous Software Weaknesses (2024)
|
|
249
249
|
"cis-controls-v8", // CIS Controls v8
|
|
250
250
|
"cmmc-2.0-level-2", // CMMC 2.0 Level 2 (Advanced) — 110 NIST 800-171 Rev 2 controls // NIST pub number / level, not bytes
|
|
251
|
-
// ----
|
|
251
|
+
// ---- granular CMMC level distinction ----
|
|
252
252
|
// CMMC 2.0 maturity levels carry distinct control-mapping
|
|
253
253
|
// expectations: Level 1 = 15 controls (FAR 52.204-21), Level 2 =
|
|
254
254
|
// 110 controls (NIST 800-171 Rev 2), Level 3 = additional NIST
|
|
@@ -257,7 +257,7 @@ var KNOWN_POSTURES = Object.freeze([
|
|
|
257
257
|
// L1/L2/L3 postures are the recommended pin for new deployments.
|
|
258
258
|
"cmmc-2.0-level-1", // CMMC 2.0 Level 1 (Foundational) — 15 FAR controls; FCI-only data // regulatory identifier, not bytes
|
|
259
259
|
"cmmc-2.0-level-3", // CMMC 2.0 Level 3 (Expert) — NIST 800-172 enhanced controls atop L2 // regulatory identifier, not bytes
|
|
260
|
-
// ----
|
|
260
|
+
// ---- promote POSTURE_DEFAULTS-only entries into the
|
|
261
261
|
// canonical KNOWN_POSTURES surface so operators can actually
|
|
262
262
|
// `b.compliance.set(...)` them. Each entry had cascade
|
|
263
263
|
// configuration wired but couldn't be pinned because set()'s
|
|
@@ -757,7 +757,7 @@ var REGIME_MAP = Object.freeze({
|
|
|
757
757
|
"ct-sb3": { name: "Connecticut SB 3 Consumer Health Data", citation: "Conn. P.A. 23-56 (effective 2023-07-01)", jurisdiction: "US-CT", domain: "health" },
|
|
758
758
|
"tx-cubi": { name: "Texas Capture or Use of Biometric Identifier", citation: "Tex. Bus. & Com. Code §503.001 (effective 2009-09-01)", jurisdiction: "US-TX", domain: "biometric" },
|
|
759
759
|
"fl-fdbr": { name: "Florida Digital Bill of Rights", citation: "Fla. Stat. §501.701 et seq. SB 262 (effective 2024-07-01)", jurisdiction: "US-FL", domain: "privacy" },
|
|
760
|
-
// ----
|
|
760
|
+
// ---- AI governance ----
|
|
761
761
|
"co-ai": { name: "Colorado AI Act", citation: "C.R.S. §6-1-1701 et seq. SB24-205 (postponed to 2026-06-30; enforcement stayed)", jurisdiction: "US-CO", domain: "ai-governance" },
|
|
762
762
|
"il-hb3773": { name: "Illinois HB 3773 — AI in Employment", citation: "775 ILCS 5 IHRA AI amendment (effective 2026-01-01)", jurisdiction: "US-IL", domain: "ai-governance" },
|
|
763
763
|
"tx-traiga": { name: "Texas Responsible AI Governance Act", citation: "Tex. Bus. & Com. Code Ch. 552 HB 149 (effective 2026-01-01)", jurisdiction: "US-TX", domain: "ai-governance" },
|
|
@@ -766,20 +766,20 @@ var REGIME_MAP = Object.freeze({
|
|
|
766
766
|
"ca-tfaia": { name: "California Transparency in Frontier AI Act", citation: "Cal. Bus. & Prof. Code §22757.10 et seq. SB 53 (effective 2026-01-01)", jurisdiction: "US-CA", domain: "ai-governance" },
|
|
767
767
|
"kr-ai-basic": { name: "South Korea AI Basic Act", citation: "Framework Act on Development of AI (effective 2026-01-22)", jurisdiction: "KR", domain: "ai-governance" },
|
|
768
768
|
"cn-ai-label": { name: "China — Measures for Labelling AI-Generated Content", citation: "CAC + MIIT + Ministry of Public Security + NRTA Order (effective 2025-09-01)", jurisdiction: "CN", domain: "ai-governance" },
|
|
769
|
-
// ----
|
|
769
|
+
// ---- AI management cross-walks ----
|
|
770
770
|
"iso-42001": { name: "ISO/IEC 42001 — AI Management System", citation: "ISO/IEC 42001:2023", jurisdiction: "international", domain: "ai-governance" },
|
|
771
771
|
"iso-23894": { name: "ISO/IEC 23894 — AI Risk Management", citation: "ISO/IEC 23894:2023", jurisdiction: "international", domain: "ai-governance" },
|
|
772
|
-
// ----
|
|
772
|
+
// ---- content-credentials posture flags ----
|
|
773
773
|
"ca-sb942": { name: "California Gen-AI Provenance Disclosure", citation: "Cal. Bus. & Prof. Code §22757 SB-942 (effective 2026-08-02)", jurisdiction: "US-CA", domain: "content-credentials" },
|
|
774
774
|
"ca-ab853": { name: "California Platform Gen-AI Detection", citation: "Cal. Bus. & Prof. Code §22757 AB-853 (effective 2026-08-02)", jurisdiction: "US-CA", domain: "content-credentials" },
|
|
775
|
-
// ----
|
|
775
|
+
// ---- substrate-to-posture cleanup ----
|
|
776
776
|
"eaa": { name: "EU Accessibility Act", citation: "Directive (EU) 2019/882 (effective 2025-06-28)", jurisdiction: "EU", domain: "accessibility" },
|
|
777
777
|
"wcag-2-2": { name: "W3C Web Content Accessibility Guidelines 2.2", citation: "W3C Recommendation (Oct 2023)", jurisdiction: "international", domain: "accessibility" },
|
|
778
778
|
"eu-data-act": { name: "EU Data Act", citation: "Regulation (EU) 2023/2854 (effective 2025-09-12)", jurisdiction: "EU", domain: "data-sharing" },
|
|
779
779
|
"hitech": { name: "Health Information Technology for Economic and Clinical Health Act", citation: "Pub. L. 111-5, Title XIII, Subtitle D (2009)", jurisdiction: "US", domain: "health" },
|
|
780
780
|
"ferpa": { name: "Family Educational Rights and Privacy Act", citation: "20 U.S.C. §1232g; 34 CFR Part 99", jurisdiction: "US", domain: "student-records" },
|
|
781
781
|
"dpdp": { name: "Digital Personal Data Protection Act 2023", citation: "Act 22 of 2023 (India; rules pending)", jurisdiction: "IN", domain: "privacy" },
|
|
782
|
-
// ----
|
|
782
|
+
// ---- privacy 2026 sweep ----
|
|
783
783
|
// US federal
|
|
784
784
|
"coppa": { name: "Children's Online Privacy Protection Act", citation: "15 U.S.C. §§6501-6506; 16 CFR Part 312 (effective 2000-04-21)", jurisdiction: "US", domain: "child-privacy" },
|
|
785
785
|
"coppa-2025": { name: "COPPA 2025 Amendment", citation: "FTC final rule (2025-04-22; effective 2026-06-23) — biometric expansion + knowing-collection-13-and-under disclosure", jurisdiction: "US", domain: "child-privacy" },
|
|
@@ -815,7 +815,7 @@ var REGIME_MAP = Object.freeze({
|
|
|
815
815
|
"eu-cer": { name: "EU Critical Entities Resilience Directive", citation: "Directive (EU) 2022/2557 (transposition 2024-10-17)", jurisdiction: "EU", domain: "cybersecurity" },
|
|
816
816
|
"eu-cyber-sol": { name: "EU Cyber Solidarity Act", citation: "Regulation (EU) 2025/38 (effective 2025-02-04)", jurisdiction: "EU", domain: "cybersecurity" },
|
|
817
817
|
"eidas-2": { name: "eIDAS 2 / EUDI Wallet", citation: "Regulation (EU) 2024/1183 (rollout 2026-2027)", jurisdiction: "EU", domain: "identity" },
|
|
818
|
-
// ----
|
|
818
|
+
// ---- sectoral + cybersecurity directives ----
|
|
819
819
|
"cmmc-2.0": { name: "Cybersecurity Maturity Model Certification 2.0", citation: "32 CFR Part 170 (DFARS rule effective 2025-Q1)", jurisdiction: "US", domain: "cybersecurity" },
|
|
820
820
|
"cjis-v6": { name: "FBI CJIS Security Policy v6.0", citation: "CJIS Security Policy v6.0 (effective 2024-12)", jurisdiction: "US", domain: "law-enforcement" },
|
|
821
821
|
"iso-27001-2022": { name: "ISO/IEC 27001:2022 Information Security Management System", citation: "ISO/IEC 27001:2022", jurisdiction: "international", domain: "cybersecurity" },
|
|
@@ -826,7 +826,7 @@ var REGIME_MAP = Object.freeze({
|
|
|
826
826
|
"nist-800-66-r2": { name: "NIST SP 800-66 Rev 2 — HIPAA Security Rule Guidance", citation: "NIST SP 800-66 Rev 2 (Feb 2024)", jurisdiction: "US", domain: "health" },
|
|
827
827
|
"ehds": { name: "European Health Data Space", citation: "Regulation (EU) 2025/327 (phased 2027-2029)", jurisdiction: "EU", domain: "health" },
|
|
828
828
|
"circia": { name: "Cyber Incident Reporting for Critical Infrastructure Act", citation: "6 U.S.C. §681 et seq. (final rule pending)", jurisdiction: "US", domain: "cybersecurity" },
|
|
829
|
-
// ----
|
|
829
|
+
// ---- REGIME_MAP backfill for KNOWN_POSTURES without
|
|
830
830
|
// describe() coverage. Each entry resolves `b.compliance.describe
|
|
831
831
|
// (posture)` → { name, citation, jurisdiction, domain } so admin
|
|
832
832
|
// UI / generated audit reports rendering "running under <name>
|
|
@@ -870,7 +870,7 @@ var REGIME_MAP = Object.freeze({
|
|
|
870
870
|
"bsi-c5": { name: "Germany BSI C5 — Cloud Computing Compliance Catalogue", citation: "BSI Cloud Computing Compliance Criteria Catalogue (C5:2020)", jurisdiction: "DE", domain: "cybersecurity" },
|
|
871
871
|
"ens-es": { name: "Spain Esquema Nacional de Seguridad", citation: "Real Decreto 311/2022", jurisdiction: "ES", domain: "cybersecurity" },
|
|
872
872
|
"uk-g-cloud": { name: "UK G-Cloud Framework", citation: "UK Crown Commercial Service G-Cloud 14", jurisdiction: "UK", domain: "cybersecurity" },
|
|
873
|
-
// ----
|
|
873
|
+
// ---- REGIME_MAP backfill (cybersecurity / AI / supply-chain frameworks) ----
|
|
874
874
|
"nist-800-53": { name: "NIST SP 800-53 Rev 5 — Security & Privacy Controls", citation: "NIST SP 800-53 Rev 5", jurisdiction: "US", domain: "cybersecurity" },
|
|
875
875
|
"nist-ai-rmf-1.0": { name: "NIST AI Risk Management Framework 1.0", citation: "NIST AI 100-1 (Jan 2023)", jurisdiction: "US", domain: "ai" },
|
|
876
876
|
"iso-42001-2023": { name: "ISO/IEC 42001:2023 — AI Management System", citation: "ISO/IEC 42001:2023", jurisdiction: "international", domain: "ai" },
|
|
@@ -1176,7 +1176,7 @@ var POSTURE_DEFAULTS = Object.freeze({
|
|
|
1176
1176
|
"nist-800-66-r2": Object.freeze({ backupEncryptionRequired: true, auditChainSignedRequired: true, tlsMinVersion: "TLSv1.3", requireVacuumAfterErase: true }),
|
|
1177
1177
|
"ehds": Object.freeze({ backupEncryptionRequired: true, auditChainSignedRequired: true, tlsMinVersion: "TLSv1.3", requireVacuumAfterErase: true }),
|
|
1178
1178
|
"circia": Object.freeze({ backupEncryptionRequired: false, auditChainSignedRequired: true, tlsMinVersion: "TLSv1.3", requireVacuumAfterErase: false }),
|
|
1179
|
-
// ----
|
|
1179
|
+
// ---- exceptd framework-control-gap closure cascade ----
|
|
1180
1180
|
"nist-800-53": Object.freeze({ backupEncryptionRequired: true, auditChainSignedRequired: true, tlsMinVersion: "TLSv1.3", requireVacuumAfterErase: true }),
|
|
1181
1181
|
// NIST AI-RMF MANAGE.4.3 / ISO 23894 §6.5 / ISO 42001
|
|
1182
1182
|
// §A.6 require encrypted backups for AI system state (model
|
|
@@ -1242,7 +1242,7 @@ var POSTURE_DEFAULTS = Object.freeze({
|
|
|
1242
1242
|
"cmmc-2.0-level-1": Object.freeze({ backupEncryptionRequired: false, auditChainSignedRequired: true, tlsMinVersion: "TLSv1.3", requireVacuumAfterErase: false }),
|
|
1243
1243
|
"cmmc-2.0-level-2": Object.freeze({ backupEncryptionRequired: true, auditChainSignedRequired: true, tlsMinVersion: "TLSv1.3", requireVacuumAfterErase: true }),
|
|
1244
1244
|
"cmmc-2.0-level-3": Object.freeze({ backupEncryptionRequired: true, auditChainSignedRequired: true, tlsMinVersion: "TLSv1.3", requireVacuumAfterErase: true, fipsMode: false }),
|
|
1245
|
-
// ----
|
|
1245
|
+
// ---- sectoral catch-up ----
|
|
1246
1246
|
// 42 CFR Part 2 — Substance Use Disorder records confidentiality
|
|
1247
1247
|
// (HHS final rule 2024-04-16 aligns Part 2 with HIPAA but retains
|
|
1248
1248
|
// a stricter consent floor; encrypted backups + signed audit chain
|
|
@@ -492,7 +492,7 @@ function signCose(manifest, opts) {
|
|
|
492
492
|
}
|
|
493
493
|
unprotectedHdr = Buffer.concat([
|
|
494
494
|
_cborMapHeader(1),
|
|
495
|
-
_cborInt(33), // allow:raw-time-literal — RFC 9360 x5chain header label, not a duration
|
|
495
|
+
_cborInt(33), // allow:raw-time-literal — RFC 9360 x5chain COSE header label; coincidental multiple-of-60, not a duration, C.TIME N/A
|
|
496
496
|
chainArray,
|
|
497
497
|
]);
|
|
498
498
|
} else {
|
|
@@ -590,7 +590,7 @@ var CAC_KIND_ENUM = Object.freeze({
|
|
|
590
590
|
text: true, image: true, audio: true, video: true,
|
|
591
591
|
"virtual-scene": true, other: true,
|
|
592
592
|
});
|
|
593
|
-
var CAC_USCC_RE = /^[0-9A-HJ-NPQRTUWXY]{18}$/;
|
|
593
|
+
var CAC_USCC_RE = /^[0-9A-HJ-NPQRTUWXY]{18}$/;
|
|
594
594
|
var ISO8601_RE = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?Z$/;
|
|
595
595
|
|
|
596
596
|
function cacImplicitLabel(opts) {
|
|
@@ -605,7 +605,7 @@ function cacImplicitLabel(opts) {
|
|
|
605
605
|
throw new ContentCredentialsError("cac-implicit-label/oversize-provider-name",
|
|
606
606
|
"cacImplicitLabel: providerName exceeds " + STR_LEN_MAX + " bytes (UTF-8)");
|
|
607
607
|
}
|
|
608
|
-
if (typeof opts.providerCode !== "string" || opts.providerCode.length !== 18 ||
|
|
608
|
+
if (typeof opts.providerCode !== "string" || opts.providerCode.length !== 18 ||
|
|
609
609
|
!CAC_USCC_RE.test(opts.providerCode)) { // allow:regex-no-length-cap — length-bounded immediately above
|
|
610
610
|
throw new ContentCredentialsError("cac-implicit-label/bad-provider-code",
|
|
611
611
|
"cacImplicitLabel: providerCode must be an 18-char unified social credit code " +
|
|
@@ -132,7 +132,7 @@ function _parseHHMM(s) {
|
|
|
132
132
|
throw new DdlChangeControlError("ddl-change-control/bad-window",
|
|
133
133
|
"windowSpec time out of range - got " + s);
|
|
134
134
|
}
|
|
135
|
-
return hh * 60 + mm; // allow:raw-time-literal —
|
|
135
|
+
return hh * 60 + mm; // allow:raw-time-literal — HH*60+MM minute-of-day conversion; coincidental multiple-of-60 factor, not a duration, C.TIME N/A
|
|
136
136
|
}
|
|
137
137
|
|
|
138
138
|
function _isInWindow(window, nowMs) {
|
|
@@ -141,7 +141,7 @@ function _isInWindow(window, nowMs) {
|
|
|
141
141
|
var d = new Date(nowMs);
|
|
142
142
|
var dayIdx = d.getUTCDay();
|
|
143
143
|
if (!window.days.has(dayIdx)) return false;
|
|
144
|
-
var min = d.getUTCHours() * 60 + d.getUTCMinutes(); // allow:raw-time-literal —
|
|
144
|
+
var min = d.getUTCHours() * 60 + d.getUTCMinutes(); // allow:raw-time-literal — HH*60+MM minute-of-day conversion; coincidental multiple-of-60 factor, not a duration, C.TIME N/A
|
|
145
145
|
return min >= window.startMin && min < window.endMin;
|
|
146
146
|
}
|
|
147
147
|
|
package/lib/did.js
CHANGED
|
@@ -65,7 +65,7 @@ var MAX_JWK_B64_CHARS = 8192; // bounded did:jwk encode
|
|
|
65
65
|
// keyLen is the multicodec payload: Ed25519 raw 32; EC compressed point.
|
|
66
66
|
var MULTICODEC = {
|
|
67
67
|
0xed: { name: "Ed25519", kind: "okp" }, // ed25519-pub
|
|
68
|
-
0x1200: { name: "P-256", kind: "ec", curveOid: "1.2.840.10045.3.1.7" },
|
|
68
|
+
0x1200: { name: "P-256", kind: "ec", curveOid: "1.2.840.10045.3.1.7" },
|
|
69
69
|
0x1201: { name: "P-384", kind: "ec", curveOid: "1.3.132.0.34" }, // p384-pub multicodec code
|
|
70
70
|
0xe7: { name: "secp256k1", kind: "ec", curveOid: "1.3.132.0.10" }, // secp256k1-pub
|
|
71
71
|
};
|
|
@@ -159,7 +159,7 @@ function _keyObjectFromMulticodec(code, keyBytes) {
|
|
|
159
159
|
|
|
160
160
|
// AlgorithmIdentifier SEQUENCE { id-ecPublicKey, namedCurve OID }.
|
|
161
161
|
function _ecAlgId(curveOid) {
|
|
162
|
-
var idEcPublicKey = Buffer.from("06072a8648ce3d0201", "hex");
|
|
162
|
+
var idEcPublicKey = Buffer.from("06072a8648ce3d0201", "hex");
|
|
163
163
|
var curve = _oidDer(curveOid);
|
|
164
164
|
var inner = Buffer.concat([idEcPublicKey, curve]);
|
|
165
165
|
return Buffer.concat([Buffer.from([0x30, inner.length]), inner]);
|
package/lib/dsr.js
CHANGED
|
@@ -1078,7 +1078,7 @@ function dbTicketStore(opts) {
|
|
|
1078
1078
|
};
|
|
1079
1079
|
}
|
|
1080
1080
|
|
|
1081
|
-
// ----
|
|
1081
|
+
// ---- US state-law DSR drift registry -------------------
|
|
1082
1082
|
//
|
|
1083
1083
|
// Each US state consumer-privacy law expresses the same DSR core
|
|
1084
1084
|
// (access / deletion / correction / portability) but with per-state
|
|
@@ -1094,7 +1094,7 @@ function dbTicketStore(opts) {
|
|
|
1094
1094
|
|
|
1095
1095
|
// State DSR rule table — `responseDays` / `extensionDays` / `cureDays`
|
|
1096
1096
|
// are integer day-counts from per-state statutes (not durations in
|
|
1097
|
-
// seconds/ms).
|
|
1097
|
+
// seconds/ms).
|
|
1098
1098
|
var STATE_RULES = Object.freeze({
|
|
1099
1099
|
"vcdpa": { posture: "vcdpa", state: "VA", responseDays: 45, extensionDays: 45, cureDays: 30, profilingOptOut: true, minorOptIn: 13, notes: "Cure right sunset 2025-01-01" }, // allow:raw-time-literal
|
|
1100
1100
|
"co-cpa": { posture: "co-cpa", state: "CO", responseDays: 45, extensionDays: 45, cureDays: 60, profilingOptOut: true, minorOptIn: 13, notes: "Cure right sunset 2025-01-01; UOOM (GPC) mandatory" }, // allow:raw-time-literal
|
|
@@ -1110,7 +1110,7 @@ var STATE_RULES = Object.freeze({
|
|
|
1110
1110
|
"nj-njdpa": { posture: "nj-njdpa", state: "NJ", responseDays: 45, extensionDays: 45, cureDays: 30, profilingOptOut: true, minorOptIn: 17, notes: "Under-17 opt-in default" }, // allow:raw-time-literal
|
|
1111
1111
|
"ky-kcdpa": { posture: "ky-kcdpa", state: "KY", responseDays: 45, extensionDays: 45, cureDays: 30, profilingOptOut: true, minorOptIn: 13, notes: "Effective 2026-01-01" }, // allow:raw-time-literal
|
|
1112
1112
|
"tn-tipa": { posture: "tn-tipa", state: "TN", responseDays: 45, extensionDays: 45, cureDays: 60, profilingOptOut: true, minorOptIn: 13, notes: "NIST CSF safe-harbor available" }, // allow:raw-time-literal
|
|
1113
|
-
"mn-mncdpa": { posture: "mn-mncdpa", state: "MN", responseDays: 45, extensionDays: 45, cureDays: 30, profilingOptOut: true, minorOptIn: 13, notes: "Effective 2026-07-31; profiling opt-out for consequential decisions" },
|
|
1113
|
+
"mn-mncdpa": { posture: "mn-mncdpa", state: "MN", responseDays: 45, extensionDays: 45, cureDays: 30, profilingOptOut: true, minorOptIn: 13, notes: "Effective 2026-07-31; profiling opt-out for consequential decisions" },
|
|
1114
1114
|
"ri-ricpa": { posture: "ri-ricpa", state: "RI", responseDays: 45, extensionDays: 45, cureDays: 0, profilingOptOut: true, minorOptIn: 13, notes: "Effective 2026-01-01; no cure period" }, // allow:raw-time-literal
|
|
1115
1115
|
"ne-dpa": { posture: "ne-dpa", state: "NE", responseDays: 45, extensionDays: 45, cureDays: 30, profilingOptOut: true, minorOptIn: 13, notes: "Effective 2025-01-01" }, // allow:raw-time-literal
|
|
1116
1116
|
"nv-sb370": { posture: "nv-sb370", state: "NV", responseDays: 60, extensionDays: 30, cureDays: 0, profilingOptOut: false, minorOptIn: null, notes: "Consumer-health data only" }, // allow:raw-time-literal
|
|
@@ -1118,8 +1118,8 @@ var STATE_RULES = Object.freeze({
|
|
|
1118
1118
|
"ct-sb3": { posture: "ct-sb3", state: "CT", responseDays: 45, extensionDays: 45, cureDays: 60, profilingOptOut: false, minorOptIn: null, notes: "Consumer-health data only" }, // allow:raw-time-literal
|
|
1119
1119
|
"tx-cubi": { posture: "tx-cubi", state: "TX", responseDays: 0, extensionDays: 0, cureDays: 0, profilingOptOut: false, minorOptIn: null, notes: "Biometric-only; private-right-of-action absent" }, // allow:raw-time-literal
|
|
1120
1120
|
"modpa": { posture: "modpa", state: "MD", responseDays: 45, extensionDays: 45, cureDays: 60, profilingOptOut: true, minorOptIn: 13, notes: "Strict data-minimization; effective 2026-10-01" }, // allow:raw-time-literal
|
|
1121
|
-
"quebec-25": { posture: "quebec-25", state: "QC", responseDays: 30, extensionDays: 30, cureDays: 0, profilingOptOut: true, minorOptIn: 14, notes: "DPIA + automated-decision opt-out; FR-language obligations" },
|
|
1122
|
-
"fl-fdbr": { posture: "fl-fdbr", state: "FL", responseDays: 45, extensionDays: 15, cureDays: 30, profilingOptOut: true, minorOptIn: 13, notes: "Narrow scope ($1B+ revenue threshold); effective 2024-07-01; AG-only enforcement" },
|
|
1121
|
+
"quebec-25": { posture: "quebec-25", state: "QC", responseDays: 30, extensionDays: 30, cureDays: 0, profilingOptOut: true, minorOptIn: 14, notes: "DPIA + automated-decision opt-out; FR-language obligations" },
|
|
1122
|
+
"fl-fdbr": { posture: "fl-fdbr", state: "FL", responseDays: 45, extensionDays: 15, cureDays: 30, profilingOptOut: true, minorOptIn: 13, notes: "Narrow scope ($1B+ revenue threshold); effective 2024-07-01; AG-only enforcement" },
|
|
1123
1123
|
});
|
|
1124
1124
|
|
|
1125
1125
|
/**
|
package/lib/external-db.js
CHANGED
|
@@ -803,7 +803,7 @@ async function transaction(fn, opts) {
|
|
|
803
803
|
_emitMetric("externaldb.transaction.retry", 1,
|
|
804
804
|
{ backend: b.name, code: txErr.code, attempt: String(attempt) });
|
|
805
805
|
var jitter = bCrypto.randomInt(0, 6); // 0-5ms jitter
|
|
806
|
-
await safeAsync.sleep(attempt * 5 + jitter);
|
|
806
|
+
await safeAsync.sleep(attempt * 5 + jitter);
|
|
807
807
|
continue;
|
|
808
808
|
}
|
|
809
809
|
var failureMs = Date.now() - t0;
|
package/lib/guard-archive.js
CHANGED
|
@@ -905,7 +905,7 @@ module.exports = {
|
|
|
905
905
|
tarEntryPolicy: tarEntryPolicy,
|
|
906
906
|
};
|
|
907
907
|
|
|
908
|
-
// ----
|
|
908
|
+
// ---- extensions ---------------------------------------------------
|
|
909
909
|
|
|
910
910
|
/**
|
|
911
911
|
* @primitive b.guardArchive.inspect
|
package/lib/guard-cidr.js
CHANGED
|
@@ -73,7 +73,7 @@ var IPV4_RESERVED = Object.freeze([
|
|
|
73
73
|
{ net: _ipv4ToUint32([127, 0, 0, 0]), prefix: 8, label: "loopback" }, // IPv4 octets
|
|
74
74
|
{ net: _ipv4ToUint32([169, 254, 0, 0]), prefix: 16, label: "link-local" }, // IPv4 octets
|
|
75
75
|
{ net: _ipv4ToUint32([224, 0, 0, 0]), prefix: 4, label: "multicast" }, // IPv4 octets
|
|
76
|
-
{ net: _ipv4ToUint32([240, 0, 0, 0]), prefix: 4, label: "reserved-class-e" }, // allow:raw-time-literal —
|
|
76
|
+
{ net: _ipv4ToUint32([240, 0, 0, 0]), prefix: 4, label: "reserved-class-e" }, // allow:raw-time-literal — IPv4 octet 240; coincidental multiple-of-60, not a duration, C.TIME N/A
|
|
77
77
|
{ net: _ipv4ToUint32([192, 0, 2, 0]), prefix: 24, label: "documentation-test-net-1" }, // IPv4 octets
|
|
78
78
|
{ net: _ipv4ToUint32([198, 51, 100, 0]), prefix: 24, label: "documentation-test-net-2" }, // IPv4 octets
|
|
79
79
|
{ net: _ipv4ToUint32([203, 0, 113, 0]), prefix: 24, label: "documentation-test-net-3" }, // IPv4 octets
|
package/lib/guard-image.js
CHANGED
|
@@ -111,7 +111,7 @@ var PROFILES = Object.freeze({
|
|
|
111
111
|
framesPolicy: "reject",
|
|
112
112
|
maxWidth: C.BYTES.bytes(8192), // pixel cap, repurposing bytes() for clarity
|
|
113
113
|
maxHeight: C.BYTES.bytes(8192),
|
|
114
|
-
maxFrames: 60, // allow:raw-time-literal —
|
|
114
|
+
maxFrames: 60, // allow:raw-time-literal — max-frame count 60; coincidental multiple-of-60, not a duration, C.TIME N/A
|
|
115
115
|
maxBytes: C.BYTES.mib(32),
|
|
116
116
|
maxRuntimeMs: C.TIME.seconds(5),
|
|
117
117
|
},
|
|
@@ -371,7 +371,7 @@ function _hasControlChar(s) {
|
|
|
371
371
|
|
|
372
372
|
function _trunc(s) {
|
|
373
373
|
if (s.length <= 64) return s; // error-message truncation
|
|
374
|
-
return s.slice(0, 60) + "…"; // allow:raw-time-literal — char
|
|
374
|
+
return s.slice(0, 60) + "…"; // allow:raw-time-literal — truncation char-count 60; coincidental multiple-of-60, not a duration, C.TIME N/A
|
|
375
375
|
}
|
|
376
376
|
|
|
377
377
|
function _verdict(action, reason, extra) {
|
package/lib/guard-time.js
CHANGED
|
@@ -254,7 +254,7 @@ function _detectIssues(input, opts) {
|
|
|
254
254
|
snippet: "minute " + minute + " > 59",
|
|
255
255
|
});
|
|
256
256
|
}
|
|
257
|
-
if (second > 60) { // allow:raw-time-literal — leap-second ceiling
|
|
257
|
+
if (second > 60) { // allow:raw-time-literal — leap-second ceiling literal 60 (RFC 3339 5.6); coincidental multiple-of-60, not a duration, C.TIME N/A
|
|
258
258
|
issues.push({
|
|
259
259
|
kind: "second-range", severity: "high",
|
|
260
260
|
ruleId: "time.second-range",
|
package/lib/guard-xml.js
CHANGED
|
@@ -303,7 +303,7 @@ function _detectIssues(input, opts) {
|
|
|
303
303
|
// get the NCR cap disabled with them. The `maxNumericCharRefs` opt
|
|
304
304
|
// is validated by `numericBounds.requireAllPositiveFiniteIntIfPresent`
|
|
305
305
|
// at the public-surface boundary above.
|
|
306
|
-
var ncrCap = opts.maxNumericCharRefs;
|
|
306
|
+
var ncrCap = opts.maxNumericCharRefs;
|
|
307
307
|
if (ncrCap !== undefined && ncrCap !== null) {
|
|
308
308
|
var ncrMatches = input.match(NUMERIC_CHAR_REF_RE); // allow:regex-no-length-cap — input bounded by maxBytes above
|
|
309
309
|
var ncrCount = ncrMatches === null ? 0 : ncrMatches.length;
|
package/lib/http-client-cache.js
CHANGED
|
@@ -66,7 +66,7 @@ var HEURISTIC_MAX_AGE_MS = C.TIME.hours(24);
|
|
|
66
66
|
// Statuses RFC 9110 designates as heuristically cacheable. (Plus 200/206
|
|
67
67
|
// which are universally cacheable when a freshness lifetime is given.)
|
|
68
68
|
var CACHEABLE_STATUSES = new Set([
|
|
69
|
-
200, 203, 204, 206, 300, 301, 308, 404, 405, 410, 414, 501, // allow:raw-time-literal —
|
|
69
|
+
200, 203, 204, 206, 300, 301, 308, 404, 405, 410, 414, 501, // allow:raw-time-literal — RFC 9111 cacheable status-code set; coincidental multiple-of-60 entries, not durations, C.TIME N/A
|
|
70
70
|
]);
|
|
71
71
|
|
|
72
72
|
// Headers that MUST not be forwarded when serving a 304-updated entry.
|
package/lib/iab-tcf.js
CHANGED
|
@@ -108,7 +108,7 @@ var TCF_V23_POLICY_VERSION = 4;
|
|
|
108
108
|
var SEGMENT_TYPE_DISCLOSED_VENDORS = 1; // TCF segment-type marker, not bytes
|
|
109
109
|
var SEGMENT_TYPE_ALLOWED_VENDORS = 2; // TCF segment-type marker, not bytes
|
|
110
110
|
var SEGMENT_TYPE_PUBLISHER_TC = 3; // TCF segment-type marker, not bytes
|
|
111
|
-
var MAX_TC_STRING_BYTES = 64 * 1024;
|
|
111
|
+
var MAX_TC_STRING_BYTES = 64 * 1024;
|
|
112
112
|
|
|
113
113
|
// base64url decode (no padding) → Buffer.
|
|
114
114
|
function _b64urlDecode(s) {
|
|
@@ -186,8 +186,8 @@ function _parseCore(buf) {
|
|
|
186
186
|
var publisherRestrictions = _parsePublisherRestrictions(r);
|
|
187
187
|
return {
|
|
188
188
|
version: version,
|
|
189
|
-
createdAt: createdRaw * 100,
|
|
190
|
-
lastUpdatedAt: lastUpdatedRaw * 100,
|
|
189
|
+
createdAt: createdRaw * 100,
|
|
190
|
+
lastUpdatedAt: lastUpdatedRaw * 100,
|
|
191
191
|
cmpId: cmpId,
|
|
192
192
|
cmpVersion: cmpVersion,
|
|
193
193
|
consentScreen: consentScreen,
|
|
@@ -545,7 +545,7 @@ function _idRuns(ids) {
|
|
|
545
545
|
function _decisec(t) {
|
|
546
546
|
var ms = t instanceof Date ? t.getTime() : (t == null ? Date.now() : Number(t));
|
|
547
547
|
if (!isFinite(ms) || ms < 0) throw IabTcfError.factory("iab-tcf/bad-value", "iabTcf.encode: timestamp must be a Date or non-negative epoch-ms");
|
|
548
|
-
return Math.round(ms / 100);
|
|
548
|
+
return Math.round(ms / 100);
|
|
549
549
|
}
|
|
550
550
|
|
|
551
551
|
// Bit writer mirroring _bitReader: bits are packed high-bit-first, then the
|
package/lib/json-schema.js
CHANGED
|
@@ -487,7 +487,7 @@ function _typeMatches(typeKw, instance, actual) {
|
|
|
487
487
|
function _checkNumber(schema, n, emit) {
|
|
488
488
|
if (typeof schema.multipleOf === "number") {
|
|
489
489
|
var q = n / schema.multipleOf;
|
|
490
|
-
if (!isFinite(q) || Math.abs(q - Math.round(q)) > 1e-9 * Math.max(1, Math.abs(q))) {
|
|
490
|
+
if (!isFinite(q) || Math.abs(q - Math.round(q)) > 1e-9 * Math.max(1, Math.abs(q))) {
|
|
491
491
|
// Exact check for integers; tolerance only bridges float error.
|
|
492
492
|
if (n % schema.multipleOf !== 0) emit("multipleOf", "value is not a multiple of " + schema.multipleOf);
|
|
493
493
|
}
|
package/lib/jtd.js
CHANGED
|
@@ -33,7 +33,7 @@ var rfc3339 = require("./rfc3339");
|
|
|
33
33
|
|
|
34
34
|
var JtdError = defineClass("JtdError", { alwaysPermanent: true });
|
|
35
35
|
|
|
36
|
-
var MAX_DEPTH = 10000;
|
|
36
|
+
var MAX_DEPTH = 10000;
|
|
37
37
|
|
|
38
38
|
var TYPES = {
|
|
39
39
|
boolean: 1, string: 1, timestamp: 1, float32: 1, float64: 1,
|
package/lib/mail-auth.js
CHANGED
|
@@ -1819,7 +1819,7 @@ function authResultsEmit(opts) {
|
|
|
1819
1819
|
// // }
|
|
1820
1820
|
|
|
1821
1821
|
var DMARC_RUA_MAX_REPORT_BYTES = C.BYTES.mib(8);
|
|
1822
|
-
var DMARC_RUA_MAX_RECORDS_PER_REPORT = 10000;
|
|
1822
|
+
var DMARC_RUA_MAX_RECORDS_PER_REPORT = 10000;
|
|
1823
1823
|
|
|
1824
1824
|
function _arrayOf(value) {
|
|
1825
1825
|
if (value === undefined || value === null) return [];
|
package/lib/mail-bimi.js
CHANGED
|
@@ -444,7 +444,7 @@ function validateTinyPsSvg(svgBytes) {
|
|
|
444
444
|
if (lname === "href" || lname === "xlink:href") {
|
|
445
445
|
if (aval.length > 0 && aval.charAt(0) !== "#") {
|
|
446
446
|
_vio("external-ref-forbidden",
|
|
447
|
-
"external reference in `" + aname + "='" + aval.slice(0, 60) /* allow:raw-time-literal — display truncation
|
|
447
|
+
"external reference in `" + aname + "='" + aval.slice(0, 60) /* allow:raw-time-literal — display truncation char-count 60; coincidental multiple-of-60, not a duration, C.TIME N/A */ + "...'` " +
|
|
448
448
|
"is forbidden in Tiny-PS (only `#fragment` permitted)");
|
|
449
449
|
}
|
|
450
450
|
}
|
package/lib/mail-crypto-pgp.js
CHANGED
|
@@ -928,7 +928,7 @@ function _audit(auditHandle, action, outcome, metadata) {
|
|
|
928
928
|
} catch (_e) { /* drop-silent — audit failures must not crash callers */ }
|
|
929
929
|
}
|
|
930
930
|
|
|
931
|
-
// ----
|
|
931
|
+
// ---- experimental encrypt/decrypt + WKD ----
|
|
932
932
|
//
|
|
933
933
|
// PQC PGP encrypt/decrypt for ML-KEM-1024 recipients shipped under
|
|
934
934
|
// `experimental` namespace (RFC 9580bis PKESK ML-KEM codepoints
|
package/lib/mail-crypto-smime.js
CHANGED
|
@@ -754,7 +754,7 @@ function checkCert(opts) {
|
|
|
754
754
|
if (pub && pub.asymmetricKeyType === "rsa") {
|
|
755
755
|
var jwk = pub.export({ format: "jwk" });
|
|
756
756
|
var nBytes = Buffer.from(jwk.n, "base64url");
|
|
757
|
-
var bits = nBytes.length * 8; // allow:raw-time-literal —
|
|
757
|
+
var bits = nBytes.length * 8; // allow:raw-time-literal — byte-length*8 bit count; coincidental multiple-of-60 product, not a duration, C.TIME N/A
|
|
758
758
|
if (bits < RSA_MIN_BITS) {
|
|
759
759
|
throw new MailCryptoError("mail-crypto/smime/rsa-too-small",
|
|
760
760
|
"cert public key is " + bits + " RSA bits; minimum is " + RSA_MIN_BITS +
|
package/lib/mail-server-mx.js
CHANGED
|
@@ -998,7 +998,7 @@ function create(opts) {
|
|
|
998
998
|
});
|
|
999
999
|
var deadline = Date.now() + timeoutMs;
|
|
1000
1000
|
while (connections.size > 0 && Date.now() < deadline) {
|
|
1001
|
-
await safeAsync.sleep(100);
|
|
1001
|
+
await safeAsync.sleep(100);
|
|
1002
1002
|
}
|
|
1003
1003
|
connections.forEach(function (sock) {
|
|
1004
1004
|
try { sock.destroy(); } catch (_e) { /* best-effort */ }
|
|
@@ -96,7 +96,7 @@ var MailServerRateLimitError = defineClass("MailServerRateLimitError", { alwaysP
|
|
|
96
96
|
|
|
97
97
|
var DEFAULTS = Object.freeze({
|
|
98
98
|
maxConcurrentConnectionsPerIp: 10,
|
|
99
|
-
connectionsPerIpPerMinute: 60, // allow:raw-time-literal — connection
|
|
99
|
+
connectionsPerIpPerMinute: 60, // allow:raw-time-literal — per-minute connection rate 60; time-derived (per-minute) single source of truth, C.TIME N/A as a count
|
|
100
100
|
authFailuresPerIpPer15Min: 10,
|
|
101
101
|
minBytesPerSecond: 100, // slow-loris byte-rate floor
|
|
102
102
|
// RCPT-TO recipient-failure cap defends against the 550-vs-250
|
|
@@ -1347,7 +1347,7 @@ function create(opts) {
|
|
|
1347
1347
|
});
|
|
1348
1348
|
var deadline = Date.now() + timeoutMs;
|
|
1349
1349
|
while (connections.size > 0 && Date.now() < deadline) {
|
|
1350
|
-
await safeAsync.sleep(100);
|
|
1350
|
+
await safeAsync.sleep(100);
|
|
1351
1351
|
}
|
|
1352
1352
|
connections.forEach(function (sock) {
|
|
1353
1353
|
try { sock.destroy(); } catch (_e) { /* best-effort */ }
|
package/lib/mcp.js
CHANGED
|
@@ -45,12 +45,12 @@ var METHOD_NAME_MAX = 256;
|
|
|
45
45
|
// JSON-RPC 2.0 error codes (https://www.jsonrpc.org/specification#error_object).
|
|
46
46
|
// Negative numerics by spec; mapped to HTTP status for the framework's
|
|
47
47
|
// HTTP-shaped reply envelope.
|
|
48
|
-
var JSONRPC_PARSE_ERROR = -32700; // allow:raw-time-literal — not
|
|
49
|
-
var JSONRPC_INVALID_REQUEST = -32600;
|
|
50
|
-
var JSONRPC_METHOD_NOT_FOUND= -32601;
|
|
51
|
-
var JSONRPC_INVALID_PARAMS = -32602;
|
|
52
|
-
var JSONRPC_INTERNAL_ERROR = -32603;
|
|
53
|
-
var JSONRPC_AUTH_REQUIRED = -32001;
|
|
48
|
+
var JSONRPC_PARSE_ERROR = -32700; // allow:raw-time-literal — JSON-RPC error code -32700; coincidental multiple-of-60, not a time value, C.TIME N/A
|
|
49
|
+
var JSONRPC_INVALID_REQUEST = -32600;
|
|
50
|
+
var JSONRPC_METHOD_NOT_FOUND= -32601;
|
|
51
|
+
var JSONRPC_INVALID_PARAMS = -32602;
|
|
52
|
+
var JSONRPC_INTERNAL_ERROR = -32603;
|
|
53
|
+
var JSONRPC_AUTH_REQUIRED = -32001;
|
|
54
54
|
var TOOL_NAME_RE = /^[a-zA-Z][a-zA-Z0-9._-]{0,63}$/;
|
|
55
55
|
var RESOURCE_NAME_RE = /^[a-zA-Z][a-zA-Z0-9._/-]{0,255}$/;
|
|
56
56
|
|
|
@@ -424,7 +424,7 @@ function serverGuard(opts) {
|
|
|
424
424
|
* var safe = b.mcp.toolResult.sanitize(toolResp, { posture: "sanitize" });
|
|
425
425
|
* // → { content: [{ type: "text", text: "<cleaned>" }] }
|
|
426
426
|
*/
|
|
427
|
-
var DEFAULT_TOOL_OUTPUT_MAX_BYTES = 64 * 1024;
|
|
427
|
+
var DEFAULT_TOOL_OUTPUT_MAX_BYTES = 64 * 1024;
|
|
428
428
|
var PROMPT_INJECTION_MARKERS = [
|
|
429
429
|
"ignore (previous|prior|all) instructions",
|
|
430
430
|
"system:\\s*you are",
|
package/lib/mdoc.js
CHANGED
|
@@ -58,7 +58,7 @@ var { defineClass } = require("./framework-error");
|
|
|
58
58
|
|
|
59
59
|
var MdocError = defineClass("MdocError", { alwaysPermanent: true });
|
|
60
60
|
|
|
61
|
-
var HDR_X5CHAIN = 33;
|
|
61
|
+
var HDR_X5CHAIN = 33;
|
|
62
62
|
var TAG_ENCODED_CBOR = 24; // RFC 8949 §3.4.5.1 embedded-CBOR tag
|
|
63
63
|
// Tags ISO 18013-5 uses in issuer data: tdate(0), epoch(1), embedded
|
|
64
64
|
// CBOR(24), full-date(1004, RFC 8943). Bounded — others are refused.
|
package/lib/metrics.js
CHANGED
|
@@ -729,7 +729,7 @@ function create(opts) {
|
|
|
729
729
|
exemplar = {
|
|
730
730
|
labels: { trace_id: req.span.traceId, span_id: req.span.spanId },
|
|
731
731
|
value: elapsedSec,
|
|
732
|
-
timestamp: Date.now() / 1000,
|
|
732
|
+
timestamp: Date.now() / 1000,
|
|
733
733
|
};
|
|
734
734
|
} else if (req.trace && req.trace.sampled && req.trace.traceId && req.trace.spanId) {
|
|
735
735
|
// Operators wiring traceparent directly without
|
|
@@ -740,7 +740,7 @@ function create(opts) {
|
|
|
740
740
|
exemplar = {
|
|
741
741
|
labels: { trace_id: req.trace.traceId, span_id: req.trace.spanId },
|
|
742
742
|
value: elapsedSec,
|
|
743
|
-
timestamp: Date.now() / 1000,
|
|
743
|
+
timestamp: Date.now() / 1000,
|
|
744
744
|
};
|
|
745
745
|
}
|
|
746
746
|
try { requestDuration.observe(durLabels, elapsedSec, exemplar); }
|
|
@@ -97,7 +97,7 @@ var CANONICAL_POSITIONS = Object.freeze({
|
|
|
97
97
|
botGuard: 42, // canonical position bucket
|
|
98
98
|
requireAuth: 50, // canonical position bucket
|
|
99
99
|
attachUser: 52, // canonical position bucket
|
|
100
|
-
handler: 60, // allow:raw-time-literal — pipeline position
|
|
100
|
+
handler: 60, // allow:raw-time-literal — pipeline position bucket; coincidental multiple-of-60, C.TIME N/A
|
|
101
101
|
errorHandler: 90, // canonical position bucket
|
|
102
102
|
});
|
|
103
103
|
|
package/lib/network-dnssec.js
CHANGED
|
@@ -293,7 +293,7 @@ function verifyRrset(opts) {
|
|
|
293
293
|
} else {
|
|
294
294
|
atMs = Date.now();
|
|
295
295
|
}
|
|
296
|
-
var nowSec = Math.floor(atMs / 1000);
|
|
296
|
+
var nowSec = Math.floor(atMs / 1000);
|
|
297
297
|
if (nowSec < (rrsig.inception >>> 0)) throw new DnssecError("dnssec/not-yet-valid", "dnssec.verifyRrset: RRSIG inception is in the future");
|
|
298
298
|
if (nowSec > (rrsig.expiration >>> 0)) throw new DnssecError("dnssec/expired", "dnssec.verifyRrset: RRSIG has expired");
|
|
299
299
|
|
|
@@ -349,7 +349,7 @@ var BASE32HEX = "0123456789ABCDEFGHIJKLMNOPQRSTUV"; // RFC 4648 §7 ext
|
|
|
349
349
|
var TYPE_DS = 43; // IANA RR type DS
|
|
350
350
|
var TYPE_CNAME = 5;
|
|
351
351
|
var NSEC3_HASH_SHA1 = 1; // RFC 5155 §5 — the only registered NSEC3 hash
|
|
352
|
-
var DEFAULT_MAX_NSEC3_ITERATIONS = 150;
|
|
352
|
+
var DEFAULT_MAX_NSEC3_ITERATIONS = 150;
|
|
353
353
|
|
|
354
354
|
// KeyTrap (CVE-2023-50387) amplification caps. A hostile zone can publish
|
|
355
355
|
// many DNSKEYs sharing one 16-bit key tag and many RRSIGs, forcing a
|
|
@@ -716,7 +716,7 @@ async function tlsRptSubmit(report, opts) {
|
|
|
716
716
|
// tlsRpt.recordShape / tlsRpt.submit on the send side.
|
|
717
717
|
|
|
718
718
|
var TLS_RPT_MAX_REPORT_BYTES = C.BYTES.mib(8);
|
|
719
|
-
var TLS_RPT_MAX_POLICIES_PER_REPORT = 1024;
|
|
719
|
+
var TLS_RPT_MAX_POLICIES_PER_REPORT = 1024;
|
|
720
720
|
|
|
721
721
|
function tlsRptParseReport(body, opts) {
|
|
722
722
|
opts = opts || {};
|
package/lib/network-tls.js
CHANGED
|
@@ -837,7 +837,7 @@ function _parseTime(node) {
|
|
|
837
837
|
if (s.length === 13 && s.charAt(12) === "Z") { // UTCTime length per X.690
|
|
838
838
|
// UTCTime YYMMDDhhmmssZ — 50+ → 19xx, else 20xx (RFC 5280 §4.1.2.5).
|
|
839
839
|
year = parseInt(s.slice(0, 2), 10);
|
|
840
|
-
year += year >= 50 ? 1900 : 2000;
|
|
840
|
+
year += year >= 50 ? 1900 : 2000;
|
|
841
841
|
month = parseInt(s.slice(2, 4), 10);
|
|
842
842
|
day = parseInt(s.slice(4, 6), 10);
|
|
843
843
|
hour = parseInt(s.slice(6, 8), 10); // UTCTime hour-byte offsets
|
package/lib/network-tsig.js
CHANGED
|
@@ -41,7 +41,7 @@ var TsigError = defineClass("TsigError", { alwaysPermanent: true });
|
|
|
41
41
|
|
|
42
42
|
var TYPE_TSIG = 250; // IANA RR type TSIG
|
|
43
43
|
var CLASS_ANY = 255; // TSIG RRs use CLASS ANY
|
|
44
|
-
var DEFAULT_FUDGE = 300;
|
|
44
|
+
var DEFAULT_FUDGE = 300;
|
|
45
45
|
|
|
46
46
|
// Algorithm name → Node hash. The strong HMAC-SHA-2 family is the safe set;
|
|
47
47
|
// HMAC-MD5 and HMAC-SHA-1 are refused unless allowLegacy (kept only for
|
|
@@ -225,7 +225,7 @@ function sign(message, opts) {
|
|
|
225
225
|
var secret = _secretBuf(opts.secret);
|
|
226
226
|
var fudge = opts.fudge == null ? DEFAULT_FUDGE : opts.fudge;
|
|
227
227
|
if (typeof fudge !== "number" || !isFinite(fudge) || fudge < 0 || fudge > 0xffff) throw new TsigError("tsig/bad-opt", "tsig.sign: fudge must be 0..65535 seconds"); // 16-bit fudge field
|
|
228
|
-
var time = opts.time == null ? Math.floor(Date.now() / 1000) : opts.time;
|
|
228
|
+
var time = opts.time == null ? Math.floor(Date.now() / 1000) : opts.time;
|
|
229
229
|
if (typeof time !== "number" || !isFinite(time) || time < 0) throw new TsigError("tsig/bad-opt", "tsig.sign: time must be a non-negative Unix-seconds number");
|
|
230
230
|
var error = opts.error == null ? 0 : opts.error;
|
|
231
231
|
var otherData = Buffer.isBuffer(opts.otherData) ? opts.otherData : Buffer.alloc(0);
|
|
@@ -379,7 +379,7 @@ function verify(message, opts) {
|
|
|
379
379
|
macValid = timingSafeEqual(rr.mac, expected.slice(0, rr.mac.length));
|
|
380
380
|
}
|
|
381
381
|
|
|
382
|
-
var now = opts.now == null ? Math.floor(Date.now() / 1000) : opts.now;
|
|
382
|
+
var now = opts.now == null ? Math.floor(Date.now() / 1000) : opts.now;
|
|
383
383
|
var timeValid = Math.abs(now - rr.timeSigned) <= rr.fudge;
|
|
384
384
|
|
|
385
385
|
var reason = null;
|
package/lib/parsers/index.js
CHANGED
|
@@ -36,12 +36,6 @@
|
|
|
36
36
|
* parsed as `country: false`). Block + flow style;
|
|
37
37
|
* literal `|` and folded `>` block scalars with chomp
|
|
38
38
|
* indicators.
|
|
39
|
-
* env — .env file loader with size cap + schema validation;
|
|
40
|
-
* refuses to expand $VAR references; refuses to silently
|
|
41
|
-
* overwrite existing process.env values unless explicitly
|
|
42
|
-
* opted in. Dev-tooling — production secrets should still
|
|
43
|
-
* come through the operator's secrets-management; this is
|
|
44
|
-
* the local-development convenience.
|
|
45
39
|
* ini — INI / .gitconfig / systemd-unit / php.ini / tox.ini parser.
|
|
46
40
|
* Sections (incl. [parent.child] / [parent "child"] nesting),
|
|
47
41
|
* ; or # comments (inline + leading), single + double quoting
|
package/lib/rfc3339.js
CHANGED
|
@@ -25,11 +25,11 @@ function isValidDateTime(s) {
|
|
|
25
25
|
if (!m) return false;
|
|
26
26
|
var mo = +m[2], d = +m[3], h = +m[4], mi = +m[5], se = +m[6];
|
|
27
27
|
if (mo < 1 || mo > 12 || d < 1 || d > 31 || h > 23 || mi > 59 || se > 60) return false; // allow:raw-time-literal — RFC 3339 field ranges (60 = leap second)
|
|
28
|
-
var days = [31, ((+m[1] % 4 === 0 && +m[1] % 100 !== 0) || +m[1] % 400 === 0) ? 29 : 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
|
|
28
|
+
var days = [31, ((+m[1] % 4 === 0 && +m[1] % 100 !== 0) || +m[1] % 400 === 0) ? 29 : 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
|
|
29
29
|
if (d > days[mo - 1]) return false;
|
|
30
30
|
var tz = m[8];
|
|
31
31
|
if (tz !== "Z" && tz !== "z") {
|
|
32
|
-
if (+tz.slice(1, 3) > 23 || +tz.slice(4, 6) > 59) return false;
|
|
32
|
+
if (+tz.slice(1, 3) > 23 || +tz.slice(4, 6) > 59) return false;
|
|
33
33
|
}
|
|
34
34
|
return true;
|
|
35
35
|
}
|
package/lib/safe-decompress.js
CHANGED
|
@@ -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;
|
|
108
|
+
var DEFAULT_MAX_RATIO = 50;
|
|
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/standard-webhooks.js
CHANGED
|
@@ -32,7 +32,7 @@ var { defineClass } = require("./framework-error");
|
|
|
32
32
|
|
|
33
33
|
var StandardWebhooksError = defineClass("StandardWebhooksError", { alwaysPermanent: true });
|
|
34
34
|
|
|
35
|
-
var DEFAULT_TOLERANCE_SEC = 300;
|
|
35
|
+
var DEFAULT_TOLERANCE_SEC = 300;
|
|
36
36
|
|
|
37
37
|
/**
|
|
38
38
|
* @primitive b.standardWebhooks.sign
|
|
@@ -70,7 +70,7 @@ function sign(opts) {
|
|
|
70
70
|
var id = opts.id || ("msg_" + bCrypto.generateToken(32)); // 32-char id token
|
|
71
71
|
var timestamp = typeof opts.timestamp === "number"
|
|
72
72
|
? opts.timestamp
|
|
73
|
-
: Math.floor(Date.now() / 1000);
|
|
73
|
+
: Math.floor(Date.now() / 1000);
|
|
74
74
|
if (timestamp <= 0 || !isFinite(timestamp)) {
|
|
75
75
|
throw new StandardWebhooksError("standard-webhooks/bad-timestamp",
|
|
76
76
|
"sign: timestamp must be a positive finite integer");
|
|
@@ -148,7 +148,7 @@ function verify(opts) {
|
|
|
148
148
|
numericBounds.requirePositiveFiniteIntIfPresent(opts.toleranceSec, "toleranceSec",
|
|
149
149
|
StandardWebhooksError, "standard-webhooks/bad-tolerance");
|
|
150
150
|
var tolerance = typeof opts.toleranceSec === "number" ? opts.toleranceSec : DEFAULT_TOLERANCE_SEC;
|
|
151
|
-
var nowSec = Math.floor(Date.now() / 1000);
|
|
151
|
+
var nowSec = Math.floor(Date.now() / 1000);
|
|
152
152
|
if (Math.abs(nowSec - ts) > tolerance) {
|
|
153
153
|
throw new StandardWebhooksError("standard-webhooks/timestamp-skew",
|
|
154
154
|
"verify: timestamp skew " + Math.abs(nowSec - ts) + "s exceeds tolerance " + tolerance + "s");
|
package/lib/stream-throttle.js
CHANGED
|
@@ -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;
|
|
74
|
+
var MS_PER_SECOND = 1000;
|
|
75
75
|
var NS_PER_MS = 1e6; // ns/ms unit conversion
|
|
76
|
-
var MS_PER_SECOND_HRTIME = 1000;
|
|
76
|
+
var MS_PER_SECOND_HRTIME = 1000;
|
|
77
77
|
|
|
78
78
|
/**
|
|
79
79
|
* @primitive b.streamThrottle.create
|
package/lib/structured-fields.js
CHANGED
|
@@ -542,7 +542,7 @@ function parse(input, type, opts) {
|
|
|
542
542
|
|
|
543
543
|
function _serDecimal(v, E) {
|
|
544
544
|
if (!isFinite(v)) throw E("structured-fields/serialize", "cannot serialize a non-finite decimal");
|
|
545
|
-
var n = Math.round(v * 1000) / 1000; // allow:raw-time-literal — RFC 8941
|
|
545
|
+
var n = Math.round(v * 1000) / 1000; // allow:raw-time-literal — RFC 8941 4.1.5 decimal-scale 10^3 rounding; coincidental * 1000, not a duration, C.TIME N/A
|
|
546
546
|
if (Math.abs(Math.trunc(n)).toString().length > 12) throw E("structured-fields/serialize", "decimal integer part exceeds 12 digits"); // §4.1.5 cap
|
|
547
547
|
var s = n.toString();
|
|
548
548
|
if (s.indexOf(".") === -1) s += ".0"; // a Decimal must carry a fractional part
|
|
@@ -81,7 +81,7 @@ var SealPemFileError = defineClass("SealPemFileError", { alwaysPermanent: true }
|
|
|
81
81
|
// doesn't sneak past the watcher. Operators with extremely-quiet
|
|
82
82
|
// renewal cycles can override via opts.pollInterval; the cost of
|
|
83
83
|
// 500ms polling on an idle PEM file is ~2 stat() syscalls/sec.
|
|
84
|
-
var DEFAULT_POLL_MS = 500;
|
|
84
|
+
var DEFAULT_POLL_MS = 500;
|
|
85
85
|
|
|
86
86
|
// PEM files are tiny — 4 KiB for an ECDSA key, ~8 KiB for a 4096-bit
|
|
87
87
|
// RSA key, ~64 KiB for a long cert chain. Cap at 1 MiB so an operator
|
package/lib/web-push-vapid.js
CHANGED
|
@@ -134,7 +134,7 @@ function buildVapidAuthHeader(opts) {
|
|
|
134
134
|
"buildVapidAuthHeader: subscription.endpoint is not a parseable URL");
|
|
135
135
|
}
|
|
136
136
|
var aud = endpointUrl.origin;
|
|
137
|
-
var now = Math.floor(Date.now() / 1000);
|
|
137
|
+
var now = Math.floor(Date.now() / 1000);
|
|
138
138
|
// Inline JWT sign with ES256 — VAPID strictly mandates ECDSA-P256
|
|
139
139
|
// (RFC 8292 §3.1). The framework jwt.sign is PQC-first and refuses
|
|
140
140
|
// ES256 by design; VAPID is a wire-protocol constraint outside
|
package/lib/webhook.js
CHANGED
|
@@ -955,7 +955,7 @@ function sign(input) {
|
|
|
955
955
|
}
|
|
956
956
|
ts = Math.floor(input.timestamp);
|
|
957
957
|
} else {
|
|
958
|
-
ts = Math.floor(Date.now() / 1000);
|
|
958
|
+
ts = Math.floor(Date.now() / 1000);
|
|
959
959
|
}
|
|
960
960
|
var hex = _hmacSha256Hex(secretBytes, ts + "." + bodyStr);
|
|
961
961
|
return "t=" + ts + ",v1=" + hex;
|
package/lib/websocket.js
CHANGED
|
@@ -191,7 +191,7 @@ var CLOSE_GRACE_MS = C.TIME.seconds(2);
|
|
|
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
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
|
|
194
|
+
if (code >= 3000 && code <= 4999) return true; // allow:raw-time-literal — WebSocket close-code range bound (RFC 6455 7.4.2); coincidental multiple-of-60, C.TIME N/A
|
|
195
195
|
return false;
|
|
196
196
|
}
|
|
197
197
|
|
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:1e3ccafc-71e3-4207-a3d7-5672ad58b137",
|
|
6
6
|
"version": 1,
|
|
7
7
|
"metadata": {
|
|
8
|
-
"timestamp": "2026-05-
|
|
8
|
+
"timestamp": "2026-05-31T04:50:32.275Z",
|
|
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.
|
|
22
|
+
"bom-ref": "@blamejs/core@0.14.9",
|
|
23
23
|
"type": "application",
|
|
24
24
|
"name": "blamejs",
|
|
25
|
-
"version": "0.14.
|
|
25
|
+
"version": "0.14.9",
|
|
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.
|
|
29
|
+
"purl": "pkg:npm/%40blamejs/core@0.14.9",
|
|
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.
|
|
57
|
+
"ref": "@blamejs/core@0.14.9",
|
|
58
58
|
"dependsOn": []
|
|
59
59
|
}
|
|
60
60
|
]
|