@blamejs/core 0.9.15 → 0.9.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +2 -0
- package/lib/a2a-tasks.js +2 -2
- package/lib/acme.js +2 -2
- package/lib/api-snapshot.js +1 -1
- package/lib/app-shutdown.js +2 -2
- package/lib/app.js +2 -2
- package/lib/argon2-builtin.js +1 -1
- package/lib/atomic-file.js +8 -8
- package/lib/audit-sign.js +3 -3
- package/lib/audit-tools.js +2 -2
- package/lib/auth/dpop.js +1 -1
- package/lib/auth/elevation-grant.js +4 -4
- package/lib/auth/fido-mds3.js +6 -6
- package/lib/auth/jwt-external.js +3 -3
- package/lib/auth/jwt.js +1 -1
- package/lib/auth/oauth.js +1 -1
- package/lib/auth/status-list.js +1 -1
- package/lib/backup/bundle.js +2 -2
- package/lib/backup/index.js +7 -7
- package/lib/bundler.js +4 -4
- package/lib/cli.js +1 -1
- package/lib/cloud-events.js +1 -1
- package/lib/compliance-sanctions.js +1 -1
- package/lib/compliance.js +6 -7
- package/lib/config.js +6 -6
- package/lib/credential-hash.js +4 -4
- package/lib/crypto-field.js +9 -9
- package/lib/crypto-hpke.js +1 -1
- package/lib/crypto.js +3 -3
- package/lib/daemon.js +2 -2
- package/lib/db-file-lifecycle.js +5 -5
- package/lib/db-schema.js +1 -1
- package/lib/db.js +3 -3
- package/lib/dev.js +5 -5
- package/lib/dr-runbook.js +2 -2
- package/lib/external-db-migrate.js +16 -16
- package/lib/flag-evaluation-context.js +3 -3
- package/lib/flag-providers.js +1 -1
- package/lib/http-client.js +11 -11
- package/lib/http-message-signature.js +1 -1
- package/lib/keychain.js +6 -6
- package/lib/local-db-thin.js +2 -2
- package/lib/log-stream-local.js +3 -3
- package/lib/log-stream-syslog.js +4 -4
- package/lib/log.js +2 -2
- package/lib/mail-arc-sign.js +1 -1
- package/lib/mail-dkim.js +1 -1
- package/lib/mail.js +7 -7
- package/lib/mcp-tool-registry.js +6 -6
- package/lib/middleware/asyncapi-serve.js +1 -1
- package/lib/middleware/body-parser.js +6 -6
- package/lib/middleware/openapi-serve.js +1 -1
- package/lib/middleware/require-bound-key.js +4 -4
- package/lib/middleware/require-mtls.js +4 -4
- package/lib/middleware/tus-upload.js +1 -1
- package/lib/migrations.js +3 -3
- package/lib/mtls-ca.js +4 -4
- package/lib/network-byte-quota.js +2 -2
- package/lib/network-smtp-policy.js +1 -1
- package/lib/network.js +12 -12
- package/lib/notify.js +8 -8
- package/lib/ntp-check.js +1 -1
- package/lib/object-store/azure-blob.js +3 -3
- package/lib/object-store/gcs.js +3 -3
- package/lib/object-store/http-put.js +1 -1
- package/lib/object-store/local.js +3 -3
- package/lib/object-store/sigv4-bucket-ops.js +1 -1
- package/lib/object-store/sigv4.js +3 -3
- package/lib/observability.js +1 -1
- package/lib/parsers/safe-env.js +3 -3
- package/lib/process-spawn.js +2 -2
- package/lib/restore-bundle.js +3 -3
- package/lib/restore-rollback.js +4 -4
- package/lib/restore.js +3 -3
- package/lib/retry.js +1 -1
- package/lib/router.js +16 -16
- package/lib/safe-url.js +2 -2
- package/lib/sandbox.js +1 -1
- package/lib/security-assert.js +1 -1
- package/lib/seeders.js +4 -4
- package/lib/self-update-standalone-verifier.js +2 -2
- package/lib/self-update.js +5 -5
- package/lib/session-device-binding.js +1 -1
- package/lib/storage.js +1 -1
- package/lib/template.js +2 -2
- package/lib/testing.js +2 -2
- package/lib/totp.js +1 -1
- package/lib/vault/index.js +2 -2
- package/lib/vault/passphrase-ops.js +2 -2
- package/lib/vault/passphrase-source.js +2 -2
- package/lib/vault/rotate.js +7 -7
- package/lib/vault/seal-pem-file.js +8 -8
- package/lib/vault-aad.js +5 -5
- package/lib/vendor-data.js +1 -1
- package/lib/watcher.js +5 -5
- package/lib/webhook.js +1 -1
- package/lib/websocket.js +3 -3
- package/lib/ws-client.js +8 -8
- 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.9.x
|
|
10
10
|
|
|
11
|
+
- v0.9.17 (2026-05-14) — **Two new `codebase-patterns` detectors + 192-site cleanup sweep — `node:` prefix consistency + internal-binding leak prevention.** Post-v0.9.16 audit surfaced two enforceable invariants the existing detectors didn't cover. (1) **`node-builtin-prefix` detector** — every `require("<X>")` of a Node built-in (`fs`, `path`, `crypto`, `stream`, `tls`, `url`, `os`, `net`, `http`, `http2`, `https`, `zlib`, `dgram`, `events`, `child_process`, `readline`, …) must use the modern `require("node:<X>")` form. Three reasons: (a) userland packages on npm CAN be named after built-ins, so without the `node:` prefix a typo or `npm install` accident could shadow the built-in; (b) the prefix is a clearer at-a-glance signal that the dependency is on Node, not on a userland module; (c) bundler / SEA static-trace passes treat `node:` prefix as an unambiguous Node-builtin marker. Sweep: 153 `require()` rewrites across 79 framework files (2 parallel agents). The detector skips JSDoc `@example` block continuation lines (`*`-prefixed), so operator-facing examples that show `var fs = require("fs")` aren't rewritten — operators write their own bindings however they prefer. (2) **`internal-binding-in-prose` detector** — internal binding names (`nodeFs` / `nodePath` / `nodeCrypto` / `nodeStream` / `nodeTls` / `nodeUrl` / `bCrypto` / `retryHelper`) must NOT appear in operator-facing surface: JSDoc/comment continuation lines or string literals (error messages, audit metadata). Operators see the public API name (`path` / `fs` / `crypto` / `retry` / …), never the framework's internal alias. Sweep: 39 prose-leak fixes across 16 files — comments rewritten to use the operator-facing word (`nodePath` → `path`, `nodeFs.watch failed` → `fs.watch failed`, debug-log `"op": "nodeFs.unlinkSync"` → `"op": "fs.unlinkSync"`). (3) **2 follow-on require-binding canonicalizations** surfaced by the node-prefix sweep — `lib/ws-client.js` now destructures `var { EventEmitter } = require("node:events")` (was binding the entire `events` module to a class-shaped name) and `lib/process-spawn.js` renames inline `nodeChild` → `childProcess` (matches the module-level `childProcess` lazyRequire in `lib/dev.js`).
|
|
12
|
+
- v0.9.16 (2026-05-14) — **Operator-facing prose cleanup + `require-binding-name` detector now covers `lazyRequire` wrappers + dbStore seal round-trip test added.** Post-v0.9.15 audit surfaced three classes of follow-up. (1) **Operator-facing prose leaks (7 sites)** — the v0.9.15 mechanical rename pattern `<OLD>.` → `<NEW>.` also caught occurrences inside JSDoc `@opts` comments and error-message string literals, so operators reading `b.keychain.create(opts)` saw `// absolute nodePath; required if file fallback may engage` instead of `// absolute path`. Fixed: `lib/db.js` (stream-limit error), `lib/keychain.js` (fallback-file error + 3 JSDoc lines), `lib/restore-bundle.js` (staging-dir error), `lib/watcher.js` (fs.watch failure error). Operators see plain English; internal binding names stay internal. (2) **`require-binding-name` detector extended to cover `lazyRequire`** — the v0.9.15 detector only matched plain `var X = require("M")` and missed the framework's `var X = lazyRequire(function () { return require("M"); })` pattern (used to break load cycles). 34 additional inconsistencies surfaced (`auditFwk` / `auditMod` / `auditModule` / `lazyAudit` → `audit`, `crypto` / `fwCrypto` → `bCrypto`, `dbMod` / `dbModule` → `db`, etc.) — every minority site renamed per the same canonical-name map. (3) **dbStore seal round-trip test** — the v0.9.15 test suite covered seal-falls-back-when-vault-not-ready and cross-process-sealed-row-preserved, but did NOT exercise the actual default-ON seal/unseal path because the test environment didn't `b.vault.init(...)`. New `testDbStoreSealRoundTripWithVault` bootstraps a plaintext vault, builds a dbStore with `seal: true`, writes a record + reads it back, and asserts (a) `headers` + `body` columns carry the `vault:` envelope on disk, (b) the round-trip restores the original values, and (c) `status_code` stays plaintext so forensic SELECTs still work without unsealing.
|
|
11
13
|
- v0.9.15 (2026-05-13) — **`b.middleware.idempotencyKey.dbStore` hardening + framework-wide `require()` binding-name consistency.** Two operator-surfaced gaps closed: (1) **dbStore now hashes keys + seals body/headers by default.** Operator-supplied idempotency keys sometimes carry PII (order numbers, emails, vendor prefixes); the `k` column previously stored them raw, leaving every DB dump as a PII surface. v0.9.15 sha3-512 namespace-hashes the key via `b.crypto.namespaceHash("idempotency-key", key)` before insert/lookup — round-trips are transparent (operators still pass raw keys), but the DB never sees the original. The schema also splits the previous single-`v` JSON-envelope column into discrete `fingerprint` / `status_code` / `headers` / `body` / `expires_at` columns; `headers` + `body` are sealed via `b.cryptoField.sealRow` (vault-managed AEAD envelope) when vault is initialized, so a DB dump leaks neither cached response bodies nor headers. Non-sealed columns (`status_code`, `fingerprint`, `expires_at`) stay forensic-queryable. Both defaults are operator-opt-out via `opts.hashKeys: false` and `opts.seal: false`; the seal path silently falls back to plaintext + emits an `idempotency.seal_skipped_no_vault` audit warning on first use when vault isn't ready, so test fixtures and boot scripts still work. **Schema migration**: v0.9.15's split columns are incompatible with v0.9.14's single-`v` column — operators with a v0.9.14 idempotency table `DROP TABLE <tableName>;` (or pick a fresh `tableName`) before upgrading. Pre-v1 framework breaks across patch versions for security correctness. (2) **New `require-binding-name` codebase-patterns detector enforces consistent `var X = require("M")` names framework-wide.** Inconsistent names (`fs` vs `nodeFs`, `crypto` vs `nodeCrypto`, `path` vs `nodePath`, `nb` vs `numericBounds`) made `grep` across the lib unreliable and let reviewers miss shadowing bugs (`var crypto = require("crypto")` collides with the framework's own `b.crypto`). The detector carries a `CANONICAL_REQUIRE_BINDINGS` map with safety-first defaults: Node built-ins get a `node<X>` prefix (`nodeFs` / `nodePath` / `nodeCrypto` / `nodeStream` / `nodeTls` / `nodeUrl`) so a local var named `fs` / `path` / `crypto` can never shadow them; the framework's own `lib/crypto.js` binds as `bCrypto` (matches the `b.crypto` public-namespace shape and doesn't shadow node:crypto). Modules without a declared canonical fall back to majority-wins (most-sites name wins, alphabetical tiebreak). Fix is rename, not allowlist — every minority site was updated. **Sweep**: 184 require-binding renames across 108 framework files in this release; primitives + tests unchanged in surface. (3) **`b.graphqlFederation` internal `_timingSafeEqual` now routes through `b.crypto.timingSafeEqual`** (was re-implementing the length-tolerant wrapper inline; the new require-binding-name detector surfaced this; same-patch fix per the audit-existing-code rule).
|
|
12
14
|
- v0.9.14 (2026-05-13) — **Audit-existing-code sweep: `safeSql.quoteIdentifier` adopted across every framework primitive that interpolates SQL identifiers; new `raw-sql-identifier-interpolation` detector seals the bug class.** Codex P1 on PR #44 flagged that `dbStore.get`'s expired-row cleanup was an unconditional `DELETE WHERE k = ?` between SELECT and DELETE — in a multi-process deployment another process could upsert the same key in the race window, and the unconditional delete would erase the fresh row. Fix: scope the delete by the observed `expires_at`. While reviewing, a wider gap surfaced — every `db.prepare("CREATE TABLE " + tableName + ...)` site in the framework had been concatenating identifiers raw, sometimes with inline shape-regex validation that varied per module. The framework already shipped `b.safeSql.quoteIdentifier(name, dialect?)` for exactly this; per the audit-existing-code rule the same patch (a) routes every site through the helper (`lib/audit.js` segregation-of-duties trigger DDL, `lib/dsr.js` ticket store, `lib/inbox.js` message-receive table, `lib/middleware/idempotency-key.js` dbStore, `lib/vault/rotate.js` column-rotation DDL) and (b) adds a `raw-sql-identifier-interpolation` codebase-patterns detector so the bug class can't return. The detector skips variables whose names signal already-quoted identifiers (`q<X>` / `Q_<X>` / `quoted<X>` prefix), so future primitives that use the helper read naturally. **Plus: bounded JSON parse for two file-/DB-backed primitives.** `b.metrics.snapshot.read` and `b.middleware.idempotencyKey.dbStore.get` previously used bare `JSON.parse` with `allow:bare-json-parse` markers; both are read by processes separate from where they were written (CLI/sidecar reads daemon-written snapshot; multi-process fleet shares DB) where a hostile or misbehaving writer could plant a multi-GB value and OOM the reader. Both now route through `b.safeJson.parse(raw, { maxBytes: 4 MiB })`. **Three new primitives — `b.crypto.hashFilesParallel`, `b.pqcAgent.reload`, `b.middleware.idempotencyKey.dbStore` — plus republish of v0.9.13's surface**. v0.9.13's npm-publish workflow failed at the wiki-e2e gate (the Codex P1 fix removed the `opts` parameter from `b.selfUpdate.standaloneVerifier.verify` but the `@signature` JSDoc still declared four arguments — three vs. four arity drift). The v0.9.13 git tag + GH release reached operators but the npm tarball did not; the registry stayed at v0.9.12. v0.9.14 carries v0.9.13's entire shipped surface (circuitBreaker.create({...}) opts-object fix + `b.selfUpdate.standaloneVerifier` + `b.metrics.snapshot` + `b.retry.withBreaker`) plus three additional Tier 2 primitives surfaced by the same downstream consumer that flagged the v0.9.13 batch. (1) **`b.crypto.hashFilesParallel(filePaths, opts?)`** — parallel multi-digest hashing for many files in a single read pass per file. Worker-pool concurrency cap (default `min(8, paths.length)`, 1..256), operator-tunable `algorithms` list (default `["sha256", "sha3-512"]`), optional `onProgress(completed, total)` callback (throws swallowed). Returns rows in the same order as input. The common consumer-side reason to reach for this is SBOM regeneration / vendor-data integrity sweeps / release-asset bundling — situations where N files each need both SHA-256 (legacy compat) and SHA-3-512 (PQC-first) digests and rolling a worker pool by hand has cost a downstream consumer the same two-loop, capture-N-promises, settle-Q boilerplate every release. (2) **`b.pqcAgent.reload()`** — tear down the lazily-built default agent and reset to null so the next `b.pqcAgent.agent` access rebuilds against current TLS posture + `b.network.tls.applyToContext` output. Long-running daemons that rotate the framework's TLS posture (TLS-pinset reload, certificate-pinset refresh, `C.TLS_GROUP_PREFERENCE` update behind a feature flag) need a way to re-source the outbound `https.Agent` without forking a new process. `reload()` calls `.destroy()` on the existing default agent (Node closes idle keep-alive sockets, lets in-flight sockets complete) then nulls the cache. Agents handed out via explicit `b.pqcAgent.create()` are unaffected. Returns `{ destroyed: boolean }`. (3) **`b.middleware.idempotencyKey.dbStore({ db, tableName?, init? })`** — persistent-backed store for the `idempotencyKey` middleware. Same three-method interface as `memoryStore` (`get` / `set` / `delete`) but stores records in any sqlite-shaped database (`{ prepare(sql) → { run, get, all } }`) — the framework's internal `b.db`, an operator-supplied better-sqlite3 instance, or a custom adapter. Use this instead of `memoryStore` when (a) multiple processes share the request-handling fleet so retries can land on a different process than the original, (b) the daemon may restart between the original request and the retry (graceful rolling deploy, OOM kill), or (c) audit / compliance review needs to walk historic idempotency-cache decisions queryable via `SELECT * FROM <tableName>`. TTL is lazily enforced at read time; `set()` upserts on conflict so concurrent retries on different processes don't error. The `tableName` is validated via `b.safeSql.validateIdentifier` (ASCII identifier shape, 63-char cap, no reserved words). (4) **Internal fix**: `b.apiSnapshot.read` now passes `maxBytes: 64 MiB` to `safeJson.parse` — the framework-generated snapshot file outgrew safeJson's 1 MiB default after v0.9.13. Operators consuming `@blamejs/core` via npm jump from v0.9.12 directly to v0.9.14; v0.9.13's content is included.
|
|
13
15
|
- v0.9.13 (2026-05-13) — **Two `b.circuitBreaker.create` / `b.retry` bug fixes plus three new operator-facing primitives: `b.selfUpdate.standaloneVerifier`, `b.metrics.snapshot`, `b.retry.withBreaker`**. (1) `b.circuitBreaker.create({...})` was rejecting the documented opts-object call shape with `name must be a non-empty string, got object` — every consumer following the docstring hit a hard error. The factory now reads `opts.name` (defaulting to empty string) and forwards to the internal `CircuitBreaker(name, opts)` constructor. (2) The breaker's open-circuit error code was documented as `retry/circuit-open` but the runtime threw `CIRCUIT_OPEN`. The docstring is corrected to match the runtime; an alias rename will follow with a deprecation cycle in a future minor. (3) **`b.selfUpdate.standaloneVerifier`** — zero-dep verifier for install-pipeline contexts that run BEFORE the framework is installed (Dockerfile build stages, `install.sh`, `update.sh`, SEA-bundle verification at deploy time). Surface: `verify(assetPath, sigPath, pubkeyPem, opts?)` returns `{ ok, sha3_512, sha256, alg }`. Streams the asset in 64 KiB chunks through SHA-256 + SHA-3-512 + the signature verifier in parallel — multi-GB SEA bundles don't OOM the install runner. Supports ECDSA P-384 (both IEEE-P1363 96-byte and DER encodings), Ed25519, and ML-DSA-87. Detects signature format from length so `verifier.verify(...)` runs exactly once (calling it twice returns stale state and silently passes tampered assets). Module is hermetic: `node:crypto` + `node:fs` only, no framework imports. Operators copy the file via `cp "$(node -p "require('@blamejs/core').selfUpdate.standaloneVerifier.path")" install/standalone-verifier.js` into version control on their side. (4) **`b.metrics.snapshot`** — out-of-process metrics export for long-running daemons. `startWriter({ path, intervalMs, fields })` atomically flushes a JSON snapshot (first flush synchronous so the file exists by return-time; subsequent flushes on the interval with `.unref()`; `stop()` clears + final-flushes). `read(path)` parses with shape validation (writtenAt + fields). `render(snap, { format, prefix })` produces operator-readable text or Prometheus 0.0.4 exposition (gauge metrics, prefixed; only finite numeric scalars with prom-compatible names emit; invalid-name / non-numeric / non-finite fields skipped silently). Lets a CLI process scrape a daemon's live metrics without opening an HTTP port. (5) **`b.retry.withBreaker(fn, { retry, breaker })`** — composition primitive collapsing the two-line wrapper every consumer rolls: `breaker.wrap(() => retry.withRetry(fn, opts.retry))`. One breaker call per retry loop (the retry budget is INSIDE the breaker's accounting, so a single transient burst doesn't open the breaker spuriously). Throws on non-function `fn` or breaker without `.wrap`.
|
package/lib/a2a-tasks.js
CHANGED
|
@@ -92,14 +92,14 @@ function _emitAudit(action, metadata, outcome) {
|
|
|
92
92
|
} catch (_e) { /* best-effort */ }
|
|
93
93
|
}
|
|
94
94
|
|
|
95
|
-
var
|
|
95
|
+
var bCrypto = lazyRequire(function () { return require("./crypto"); });
|
|
96
96
|
|
|
97
97
|
// _newTaskId is reserved for the operator-handler path that mints
|
|
98
98
|
// peer-assigned task IDs server-side. The underscore prefix already
|
|
99
99
|
// satisfies the framework's unused-var policy so the helper stays
|
|
100
100
|
// available without an explicit disable directive.
|
|
101
101
|
function _newTaskId() {
|
|
102
|
-
return
|
|
102
|
+
return bCrypto().generateToken(12); // allow:raw-byte-literal — 96-bit task id, not byte arithmetic on payload
|
|
103
103
|
}
|
|
104
104
|
|
|
105
105
|
function _validateTaskShape(task, where) {
|
package/lib/acme.js
CHANGED
|
@@ -302,8 +302,8 @@ function _findAkiKeyIdentifier(rawDer) {
|
|
|
302
302
|
* maxBytes: number, // default 2 MiB — response body cap
|
|
303
303
|
*
|
|
304
304
|
* @example
|
|
305
|
-
* var
|
|
306
|
-
* var pair =
|
|
305
|
+
* var crypto = require("crypto");
|
|
306
|
+
* var pair = crypto.generateKeyPairSync("ec", { namedCurve: "P-256" });
|
|
307
307
|
* var acme = b.acme.create({
|
|
308
308
|
* directory: "https://acme-staging-v02.api.letsencrypt.org/directory",
|
|
309
309
|
* accountKey: {
|
package/lib/api-snapshot.js
CHANGED
|
@@ -50,7 +50,7 @@
|
|
|
50
50
|
* Public-API surface walker plus breaking-change detector — the framework's LTS-contract enforcement at the type level.
|
|
51
51
|
*/
|
|
52
52
|
|
|
53
|
-
var nodeFs = require("fs");
|
|
53
|
+
var nodeFs = require("node:fs");
|
|
54
54
|
var numericBounds = require("./numeric-bounds");
|
|
55
55
|
var safeJson = require("./safe-json");
|
|
56
56
|
var { FrameworkError } = require("./framework-error");
|
package/lib/app-shutdown.js
CHANGED
|
@@ -449,8 +449,8 @@ function standardPhases(components) {
|
|
|
449
449
|
// fs.openSync) which gives the same single-instance guarantee but
|
|
450
450
|
// without the cross-process advisory lock — the lock file presence
|
|
451
451
|
// IS the lock.
|
|
452
|
-
var nodeFs = require("fs");
|
|
453
|
-
var nodePath = require("path");
|
|
452
|
+
var nodeFs = require("node:fs");
|
|
453
|
+
var nodePath = require("node:path");
|
|
454
454
|
|
|
455
455
|
/**
|
|
456
456
|
* @primitive b.appShutdown.pidLock
|
package/lib/app.js
CHANGED
|
@@ -89,8 +89,8 @@
|
|
|
89
89
|
* level tables still get the framework tables (sessions, queue jobs,
|
|
90
90
|
* audit_log, consent_log).
|
|
91
91
|
*/
|
|
92
|
-
var nodeFs = require("fs");
|
|
93
|
-
var nodePath = require("path");
|
|
92
|
+
var nodeFs = require("node:fs");
|
|
93
|
+
var nodePath = require("node:path");
|
|
94
94
|
var appShutdown = require("./app-shutdown");
|
|
95
95
|
var C = require("./constants");
|
|
96
96
|
var cluster = require("./cluster");
|
package/lib/argon2-builtin.js
CHANGED
package/lib/atomic-file.js
CHANGED
|
@@ -11,8 +11,8 @@
|
|
|
11
11
|
* Every write goes through the same crash-safe sequence:
|
|
12
12
|
* 1. write payload to a sibling temp file (`<filepath>.tmp-<token>`)
|
|
13
13
|
* 2. fsync the file descriptor before close
|
|
14
|
-
* 3.
|
|
15
|
-
* is atomic on the same filesystem; on Windows,
|
|
14
|
+
* 3. fs.rename() the temp file over the destination — POSIX rename
|
|
15
|
+
* is atomic on the same filesystem; on Windows, fs.rename uses
|
|
16
16
|
* MoveFileEx with REPLACE_EXISTING for the same guarantee
|
|
17
17
|
* 4. fsync the parent directory so the rename itself is durable
|
|
18
18
|
*
|
|
@@ -38,8 +38,8 @@
|
|
|
38
38
|
* @card
|
|
39
39
|
* Atomic file I/O with integrity verification, retry on transient errors, and cross-process locking.
|
|
40
40
|
*/
|
|
41
|
-
var nodeFs = require("fs");
|
|
42
|
-
var nodePath = require("path");
|
|
41
|
+
var nodeFs = require("node:fs");
|
|
42
|
+
var nodePath = require("node:path");
|
|
43
43
|
var { generateToken, sha3Hash } = require("./crypto");
|
|
44
44
|
var safeJson = require("./safe-json");
|
|
45
45
|
var C = require("./constants");
|
|
@@ -114,7 +114,7 @@ async function _withRetry(fn, opts) {
|
|
|
114
114
|
* @status stable
|
|
115
115
|
* @related b.atomicFile.fsyncDir, b.atomicFile.write
|
|
116
116
|
*
|
|
117
|
-
* Best-effort
|
|
117
|
+
* Best-effort fs.fsyncSync wrapper. Silently swallows errors because
|
|
118
118
|
* not every platform / fd type supports fsync (some FUSE mounts, some
|
|
119
119
|
* device fds). Use this when you want the durability hint but don't
|
|
120
120
|
* want a non-fsyncable target to crash the caller.
|
|
@@ -124,7 +124,7 @@ async function _withRetry(fn, opts) {
|
|
|
124
124
|
* var fd = fs.openSync("/tmp/note.txt", "w");
|
|
125
125
|
* fs.writeSync(fd, "hello\n");
|
|
126
126
|
* b.atomicFile.fsync(fd);
|
|
127
|
-
*
|
|
127
|
+
* fs.closeSync(fd);
|
|
128
128
|
*/
|
|
129
129
|
function fsync(fd) {
|
|
130
130
|
try { nodeFs.fsyncSync(fd); } catch (_e) { /* not all platforms support fsync on every fd type */ }
|
|
@@ -354,7 +354,7 @@ function writeSync(filepath, data, opts) {
|
|
|
354
354
|
* predict — only glob-by-prefix and prune by age. Operators should
|
|
355
355
|
* call this at boot for every "important" filepath (vault.key.sealed,
|
|
356
356
|
* audit-sign.key.sealed, db.enc, ...) BEFORE the first atomic write
|
|
357
|
-
* to that
|
|
357
|
+
* to that path. Returns the number of orphans removed.
|
|
358
358
|
*
|
|
359
359
|
* @opts
|
|
360
360
|
* olderThanMs: 300000, // only prune temp files older than this many ms (default 5 minutes)
|
|
@@ -706,7 +706,7 @@ async function copy(src, dst, opts) {
|
|
|
706
706
|
* @status stable
|
|
707
707
|
* @related b.atomicFile.read, b.atomicFile.readSync
|
|
708
708
|
*
|
|
709
|
-
* Synchronous existence check. Thin wrapper over `
|
|
709
|
+
* Synchronous existence check. Thin wrapper over `fs.existsSync` that
|
|
710
710
|
* normalises the answer for callers that already require this module
|
|
711
711
|
* — saves an additional `require("fs")` in modules that otherwise
|
|
712
712
|
* only need atomicFile.
|
package/lib/audit-sign.js
CHANGED
|
@@ -58,9 +58,9 @@
|
|
|
58
58
|
* @card
|
|
59
59
|
* SLH-DSA-SHAKE-256f post-quantum signature for audit-chain checkpoints.
|
|
60
60
|
*/
|
|
61
|
-
var nodeFs = require("fs");
|
|
62
|
-
var nodePath = require("path");
|
|
63
|
-
var nodeCrypto = require("crypto");
|
|
61
|
+
var nodeFs = require("node:fs");
|
|
62
|
+
var nodePath = require("node:path");
|
|
63
|
+
var nodeCrypto = require("node:crypto");
|
|
64
64
|
var atomicFile = require("./atomic-file");
|
|
65
65
|
var { sha3Hash } = require("./crypto");
|
|
66
66
|
var { defineClass } = require("./framework-error");
|
package/lib/audit-tools.js
CHANGED
|
@@ -54,8 +54,8 @@
|
|
|
54
54
|
* Operator-side audit-chain inspection / export — verify chain integrity end-to-end, export RFC 8785 canonical-JSON slices, format rows for downstream SIEM (CADF / ISO 19395), and generate tamper-evident compliance-evidence bundles auditors can verify off-line.
|
|
55
55
|
*/
|
|
56
56
|
|
|
57
|
-
var nodeFs = require("fs");
|
|
58
|
-
var nodePath = require("path");
|
|
57
|
+
var nodeFs = require("node:fs");
|
|
58
|
+
var nodePath = require("node:path");
|
|
59
59
|
var pkg = require("../package.json");
|
|
60
60
|
var atomicFile = require("./atomic-file");
|
|
61
61
|
var auditChain = require("./audit-chain");
|
package/lib/auth/dpop.js
CHANGED
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
* Middleware: see `lib/middleware/dpop.js` (`b.middleware.dpop`).
|
|
27
27
|
*/
|
|
28
28
|
|
|
29
|
-
var nodeCrypto = require("crypto");
|
|
29
|
+
var nodeCrypto = require("node:crypto");
|
|
30
30
|
var bCrypto = require("../crypto");
|
|
31
31
|
var safeJson = require("../safe-json");
|
|
32
32
|
var safeUrl = require("../safe-url");
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
* time entry-point); verify() returns structured errors (hot path).
|
|
29
29
|
*/
|
|
30
30
|
|
|
31
|
-
var nodeCrypto = require("crypto");
|
|
31
|
+
var nodeCrypto = require("node:crypto");
|
|
32
32
|
var validateOpts = require("../validate-opts");
|
|
33
33
|
var lazyRequire = require("../lazy-require");
|
|
34
34
|
var safeJson = require("../safe-json");
|
|
@@ -36,7 +36,7 @@ var C = require("../constants");
|
|
|
36
36
|
var { AuthError } = require("../framework-error");
|
|
37
37
|
|
|
38
38
|
var audit = lazyRequire(function () { return require("../audit"); });
|
|
39
|
-
var
|
|
39
|
+
var bCrypto = lazyRequire(function () { return require("../crypto"); });
|
|
40
40
|
|
|
41
41
|
var DEFAULT_TTL_SEC = C.TIME.minutes(15) / C.TIME.seconds(1);
|
|
42
42
|
var MAX_TTL_SEC = C.TIME.hours(1) / C.TIME.seconds(1);
|
|
@@ -82,7 +82,7 @@ function _macFor(payloadB64) {
|
|
|
82
82
|
|
|
83
83
|
function _timingSafeEqualBuf(a, b) {
|
|
84
84
|
if (!Buffer.isBuffer(a) || !Buffer.isBuffer(b)) return false;
|
|
85
|
-
return
|
|
85
|
+
return bCrypto().timingSafeEqual(a, b);
|
|
86
86
|
}
|
|
87
87
|
|
|
88
88
|
function create(opts) {
|
|
@@ -128,7 +128,7 @@ function create(opts) {
|
|
|
128
128
|
}
|
|
129
129
|
var nowSec = (typeof opts.now === "number" && isFinite(opts.now))
|
|
130
130
|
? opts.now : Math.floor(Date.now() / C.TIME.seconds(1));
|
|
131
|
-
var jti =
|
|
131
|
+
var jti = bCrypto().generateBytes(C.BYTES.bytes(16)).toString("base64url");
|
|
132
132
|
var payload = {
|
|
133
133
|
sub: opts.subject,
|
|
134
134
|
scope: opts.scope,
|
package/lib/auth/fido-mds3.js
CHANGED
|
@@ -47,8 +47,8 @@ var _wa = require("../vendor/simplewebauthn-server.cjs");
|
|
|
47
47
|
var { FidoMds3Error } = require("../framework-error");
|
|
48
48
|
|
|
49
49
|
var httpClient = lazyRequire(function () { return require("../http-client"); });
|
|
50
|
-
var
|
|
51
|
-
var
|
|
50
|
+
var cache = lazyRequire(function () { return require("../cache"); });
|
|
51
|
+
var audit = lazyRequire(function () { return require("../audit"); });
|
|
52
52
|
|
|
53
53
|
var DEFAULT_URL = "https://mds3.fidoalliance.org/";
|
|
54
54
|
var DEFAULT_TIMEOUT_MS = C.TIME.seconds(30);
|
|
@@ -289,7 +289,7 @@ function _verifyJws(jws, leafCert) {
|
|
|
289
289
|
var _sharedCache = null;
|
|
290
290
|
function _getCache() {
|
|
291
291
|
if (_sharedCache) return _sharedCache;
|
|
292
|
-
_sharedCache =
|
|
292
|
+
_sharedCache = cache().create({
|
|
293
293
|
namespace: "auth-fido-mds3.blob",
|
|
294
294
|
ttlMs: MAX_CACHE_TTL_MS,
|
|
295
295
|
maxEntries: 8, // allow:raw-byte-literal — operator-pinned URL set
|
|
@@ -440,7 +440,7 @@ async function fetch(opts) { // allow:raw-outbound-http — function name is f
|
|
|
440
440
|
},
|
|
441
441
|
});
|
|
442
442
|
} catch (e) {
|
|
443
|
-
try {
|
|
443
|
+
try { audit().safeEmit({
|
|
444
444
|
action: "auth.fido_mds3.fetch.network",
|
|
445
445
|
outcome: "failure",
|
|
446
446
|
metadata: { url: url, reason: (e && e.message) || String(e) },
|
|
@@ -482,7 +482,7 @@ async function fetch(opts) { // allow:raw-outbound-http — function name is f
|
|
|
482
482
|
// wrap-call's safe-minimum seed).
|
|
483
483
|
try { await c.set(cacheKey, record, _ttlFromNextUpdate(nextUpdate)); }
|
|
484
484
|
catch (_e) { /* cache.set best-effort */ }
|
|
485
|
-
try {
|
|
485
|
+
try { audit().safeEmit({
|
|
486
486
|
action: "auth.fido_mds3.fetch",
|
|
487
487
|
outcome: "success",
|
|
488
488
|
metadata: { url: url, no: payload.no, entries: payload.entries.length,
|
|
@@ -633,7 +633,7 @@ function verifyAuthenticator(blob, registrationInfo, vopts) {
|
|
|
633
633
|
}
|
|
634
634
|
var certifiedLevel = _certifiedLevel(statusReports);
|
|
635
635
|
if (refusedStatus) {
|
|
636
|
-
try {
|
|
636
|
+
try { audit().safeEmit({
|
|
637
637
|
action: "auth.fido_mds3.verify.refused",
|
|
638
638
|
outcome: "denied",
|
|
639
639
|
metadata: { aaguid: registrationInfo.aaguid, status: refusedStatus },
|
package/lib/auth/jwt-external.js
CHANGED
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
* can route alerts on a single class.
|
|
50
50
|
*/
|
|
51
51
|
|
|
52
|
-
var nodeCrypto = require("crypto");
|
|
52
|
+
var nodeCrypto = require("node:crypto");
|
|
53
53
|
var safeJson = require("../safe-json");
|
|
54
54
|
var safeUrl = require("../safe-url");
|
|
55
55
|
var lazyRequire = require("../lazy-require");
|
|
@@ -59,7 +59,7 @@ var { AuthError } = require("../framework-error");
|
|
|
59
59
|
|
|
60
60
|
var httpClient = lazyRequire(function () { return require("../http-client"); });
|
|
61
61
|
var cache = lazyRequire(function () { return require("../cache"); });
|
|
62
|
-
var
|
|
62
|
+
var audit = lazyRequire(function () { return require("../audit"); });
|
|
63
63
|
|
|
64
64
|
// ---- constants ----
|
|
65
65
|
|
|
@@ -271,7 +271,7 @@ async function verifyExternal(token, opts) {
|
|
|
271
271
|
// outright. Operators with JWE need a separate handler wired to
|
|
272
272
|
// their KMS — never a defaulted JWE path on the JWS verifier.
|
|
273
273
|
if (parts.length === 5) {
|
|
274
|
-
try {
|
|
274
|
+
try { audit().safeEmit({
|
|
275
275
|
action: "jwt.jwe.refused",
|
|
276
276
|
outcome: "denied",
|
|
277
277
|
metadata: { reason: "jwe-on-jws-verifier" },
|
package/lib/auth/jwt.js
CHANGED
|
@@ -70,7 +70,7 @@
|
|
|
70
70
|
* codes per failure class so callers can branch (display "expired"
|
|
71
71
|
* vs "not yet valid" UX, audit "bad-signature" attempts separately).
|
|
72
72
|
*/
|
|
73
|
-
var nodeCrypto = require("crypto");
|
|
73
|
+
var nodeCrypto = require("node:crypto");
|
|
74
74
|
var C = require("../constants");
|
|
75
75
|
var safeJson = require("../safe-json");
|
|
76
76
|
var validateOpts = require("../validate-opts");
|
package/lib/auth/oauth.js
CHANGED
|
@@ -112,7 +112,7 @@ var { generateBytes, timingSafeEqual: cryptoTimingSafeEqual } = require("../cryp
|
|
|
112
112
|
var httpClient = require("../http-client");
|
|
113
113
|
var safeJson = require("../safe-json");
|
|
114
114
|
var safeUrl = require("../safe-url");
|
|
115
|
-
var { URL } = require("url");
|
|
115
|
+
var { URL } = require("node:url");
|
|
116
116
|
var { defineClass } = require("../framework-error");
|
|
117
117
|
|
|
118
118
|
// Cap on responses parsed from upstream OAuth providers. Token /
|
package/lib/auth/status-list.js
CHANGED
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
* to a few KB on the wire when most bits are zero.
|
|
45
45
|
*/
|
|
46
46
|
|
|
47
|
-
var nodeCrypto = require("crypto");
|
|
47
|
+
var nodeCrypto = require("node:crypto");
|
|
48
48
|
var zlib = require("node:zlib");
|
|
49
49
|
var safeJson = require("../safe-json");
|
|
50
50
|
var validateOpts = require("../validate-opts");
|
package/lib/backup/bundle.js
CHANGED
|
@@ -46,8 +46,8 @@
|
|
|
46
46
|
* compressor (gzip, zstd) downstream of the framework primitive.
|
|
47
47
|
*/
|
|
48
48
|
|
|
49
|
-
var nodeFs = require("fs");
|
|
50
|
-
var nodePath = require("path");
|
|
49
|
+
var nodeFs = require("node:fs");
|
|
50
|
+
var nodePath = require("node:path");
|
|
51
51
|
var atomicFile = require("../atomic-file");
|
|
52
52
|
var bCrypto = require("./crypto");
|
|
53
53
|
var backupManifest = require("./manifest");
|
package/lib/backup/index.js
CHANGED
|
@@ -48,9 +48,9 @@
|
|
|
48
48
|
* PQC-encrypted backup bundles — sealed columns + audit chain + keyring.
|
|
49
49
|
*/
|
|
50
50
|
|
|
51
|
-
var nodeFs = require("fs");
|
|
52
|
-
var os = require("os");
|
|
53
|
-
var nodePath = require("path");
|
|
51
|
+
var nodeFs = require("node:fs");
|
|
52
|
+
var os = require("node:os");
|
|
53
|
+
var nodePath = require("node:path");
|
|
54
54
|
var bCrypto = require("../crypto");
|
|
55
55
|
var atomicFile = require("../atomic-file");
|
|
56
56
|
var backupBundle = require("./bundle");
|
|
@@ -285,10 +285,10 @@ async function _resolveVaultKeyJson(vaultKeyJsonOpt) {
|
|
|
285
285
|
* var path = require("node:path");
|
|
286
286
|
* var os = require("node:os");
|
|
287
287
|
*
|
|
288
|
-
* var dataDir =
|
|
289
|
-
* var root =
|
|
290
|
-
*
|
|
291
|
-
*
|
|
288
|
+
* var dataDir = fs.mkdtempSync(path.join(os.tmpdir(), "backup-data-"));
|
|
289
|
+
* var root = fs.mkdtempSync(path.join(os.tmpdir(), "backup-root-"));
|
|
290
|
+
* fs.writeFileSync(path.join(dataDir, "db.enc"), Buffer.from([1, 2, 3]));
|
|
291
|
+
* fs.writeFileSync(path.join(dataDir, "db.key.enc"), Buffer.from([4, 5, 6]));
|
|
292
292
|
*
|
|
293
293
|
* var engine = b.backup.create({
|
|
294
294
|
* dataDir: dataDir,
|
package/lib/bundler.js
CHANGED
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
* override via `opts.hashLen` between 4 and 64). Source maps written
|
|
27
27
|
* by an engine land as `<hashed>.<ext>.map` siblings.
|
|
28
28
|
*
|
|
29
|
-
* Watch mode: `bundler.watch(callback)` arms `
|
|
29
|
+
* Watch mode: `bundler.watch(callback)` arms `fs.watch` on each
|
|
30
30
|
* entry's directory, debounces bursts via `opts.graceMs` (default
|
|
31
31
|
* 100 ms), and rebuilds the entire entry set on change.
|
|
32
32
|
*
|
|
@@ -43,8 +43,8 @@
|
|
|
43
43
|
* Client-side asset bundler — produces content-hashed `dist/<name>.<hash>.<ext>` files plus a `manifest.json` mapping logical name to hashed filename.
|
|
44
44
|
*/
|
|
45
45
|
|
|
46
|
-
var nodePath = require("path");
|
|
47
|
-
var nodeFs = require("fs");
|
|
46
|
+
var nodePath = require("node:path");
|
|
47
|
+
var nodeFs = require("node:fs");
|
|
48
48
|
var bCrypto = require("./crypto");
|
|
49
49
|
var atomicFile = require("./atomic-file");
|
|
50
50
|
var logModule = require("./log");
|
|
@@ -200,7 +200,7 @@ function _validateEngine(eng) {
|
|
|
200
200
|
* Build a content-hashed asset pipeline for a fixed set of named
|
|
201
201
|
* entries. The returned object exposes `build()` (one-shot rebuild,
|
|
202
202
|
* resolves to `{ outputs, manifestPath, manifest, durationMs }`),
|
|
203
|
-
* `watch(callback)` (arm `
|
|
203
|
+
* `watch(callback)` (arm `fs.watch` and debounce-rebuild on change),
|
|
204
204
|
* and `close()` (drop watchers and pending timers).
|
|
205
205
|
*
|
|
206
206
|
* Throws `BundlerError` at config time on missing / malformed entries,
|
package/lib/cli.js
CHANGED
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
|
|
37
37
|
var nodeFs = require("node:fs");
|
|
38
38
|
var os = require("node:os");
|
|
39
|
-
var nodePath = require("path");
|
|
39
|
+
var nodePath = require("node:path");
|
|
40
40
|
var apiSnapshot = require("./api-snapshot");
|
|
41
41
|
var argParser = require("./arg-parser");
|
|
42
42
|
var auditChain = require("./audit-chain");
|
package/lib/cloud-events.js
CHANGED
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
* Produce and consume webhook / pubsub / queue payloads in the framework-neutral CNCF CloudEvents v1.0 schema (cloudevents.io/spec/v1.0).
|
|
35
35
|
*/
|
|
36
36
|
|
|
37
|
-
var nodeCrypto = require("crypto");
|
|
37
|
+
var nodeCrypto = require("node:crypto");
|
|
38
38
|
var validateOpts = require("./validate-opts");
|
|
39
39
|
var { defineClass } = require("./framework-error");
|
|
40
40
|
|
|
@@ -483,7 +483,7 @@ function create(opts) {
|
|
|
483
483
|
// ignorable for the audit-trail use case (operators store the
|
|
484
484
|
// ruleVersion + entry count alongside).
|
|
485
485
|
function snapshot() {
|
|
486
|
-
var nodeCrypto = require("crypto");
|
|
486
|
+
var nodeCrypto = require("node:crypto");
|
|
487
487
|
var ids = index.map(function (e) { return e.id; }).sort();
|
|
488
488
|
var hash = nodeCrypto.createHash("sha3-512");
|
|
489
489
|
for (var i = 0; i < ids.length; i++) hash.update(ids[i]);
|
package/lib/compliance.js
CHANGED
|
@@ -46,11 +46,10 @@ var sanctions = require("./compliance-sanctions");
|
|
|
46
46
|
var aiAct = require("./compliance-ai-act");
|
|
47
47
|
var { ComplianceError } = require("./framework-error");
|
|
48
48
|
|
|
49
|
-
var audit
|
|
49
|
+
var audit = lazyRequire(function () { return require("./audit"); });
|
|
50
50
|
var retentionMod = lazyRequire(function () { return require("./retention"); });
|
|
51
|
-
var
|
|
52
|
-
var
|
|
53
|
-
var cryptoFieldMod = lazyRequire(function () { return require("./crypto-field"); });
|
|
51
|
+
var db = lazyRequire(function () { return require("./db"); });
|
|
52
|
+
var cryptoField = lazyRequire(function () { return require("./crypto-field"); });
|
|
54
53
|
|
|
55
54
|
// Recognised posture names. Aligns with the compliance-posture
|
|
56
55
|
// vocabulary every guard / retention floor / etc. accepts. Operators
|
|
@@ -371,9 +370,9 @@ function set(posture) {
|
|
|
371
370
|
function _applyPostureCascade(posture) {
|
|
372
371
|
var steps = [
|
|
373
372
|
{ primitive: "retention", resolver: function () { return retentionMod(); } },
|
|
374
|
-
{ primitive: "audit", resolver: function () { return
|
|
375
|
-
{ primitive: "db", resolver: function () { return
|
|
376
|
-
{ primitive: "cryptoField", resolver: function () { return
|
|
373
|
+
{ primitive: "audit", resolver: function () { return audit(); } },
|
|
374
|
+
{ primitive: "db", resolver: function () { return db(); } },
|
|
375
|
+
{ primitive: "cryptoField", resolver: function () { return cryptoField(); } },
|
|
377
376
|
];
|
|
378
377
|
for (var i = 0; i < steps.length; i += 1) {
|
|
379
378
|
var step = steps[i];
|
package/lib/config.js
CHANGED
|
@@ -29,7 +29,7 @@ var lazyRequire = require("./lazy-require");
|
|
|
29
29
|
var safeAsync = require("./safe-async");
|
|
30
30
|
var { defineClass } = require("./framework-error");
|
|
31
31
|
|
|
32
|
-
var
|
|
32
|
+
var audit = lazyRequire(function () { return require("./audit"); });
|
|
33
33
|
|
|
34
34
|
var REDACT_MASK = "[REDACTED]";
|
|
35
35
|
|
|
@@ -349,7 +349,7 @@ function loadDbBacked(opts) {
|
|
|
349
349
|
try { rows = await opts.fetchRows(); }
|
|
350
350
|
catch (e) {
|
|
351
351
|
try {
|
|
352
|
-
|
|
352
|
+
audit().safeEmit({
|
|
353
353
|
action: "config.reload.failed", outcome: "failure",
|
|
354
354
|
metadata: { phase: "fetch", reason: e && e.message },
|
|
355
355
|
});
|
|
@@ -367,7 +367,7 @@ function loadDbBacked(opts) {
|
|
|
367
367
|
value = await transformValue(row);
|
|
368
368
|
} catch (e) {
|
|
369
369
|
try {
|
|
370
|
-
|
|
370
|
+
audit().safeEmit({
|
|
371
371
|
action: "config.reload.failed", outcome: "failure",
|
|
372
372
|
metadata: { phase: "transform", key: row.key, reason: e && e.message },
|
|
373
373
|
});
|
|
@@ -376,7 +376,7 @@ function loadDbBacked(opts) {
|
|
|
376
376
|
}
|
|
377
377
|
if (typeof value !== "string") {
|
|
378
378
|
try {
|
|
379
|
-
|
|
379
|
+
audit().safeEmit({
|
|
380
380
|
action: "config.reload.failed", outcome: "failure",
|
|
381
381
|
metadata: { phase: "transform", key: row.key, reason: "transformValue did not return a string" },
|
|
382
382
|
});
|
|
@@ -390,7 +390,7 @@ function loadDbBacked(opts) {
|
|
|
390
390
|
// applied its newer fetch — my overlay would clobber fresher data.
|
|
391
391
|
if (mySeq <= ticksAppliedMax) {
|
|
392
392
|
try {
|
|
393
|
-
|
|
393
|
+
audit().safeEmit({
|
|
394
394
|
action: "config.reload.skipped", outcome: "success",
|
|
395
395
|
metadata: { phase: "stale-tick", mySeq: mySeq, appliedMax: ticksAppliedMax },
|
|
396
396
|
});
|
|
@@ -408,7 +408,7 @@ function loadDbBacked(opts) {
|
|
|
408
408
|
}
|
|
409
409
|
catch (e) {
|
|
410
410
|
try {
|
|
411
|
-
|
|
411
|
+
audit().safeEmit({
|
|
412
412
|
action: "config.reload.failed", outcome: "failure",
|
|
413
413
|
metadata: { phase: "validate", reason: e && e.message },
|
|
414
414
|
});
|
package/lib/credential-hash.js
CHANGED
|
@@ -79,7 +79,7 @@ function _shake256(secret, length) {
|
|
|
79
79
|
|
|
80
80
|
// auth/password is required lazily because it imports the (large)
|
|
81
81
|
// argon2 vendor; loading it for SHA3-only callers is wasted work.
|
|
82
|
-
var
|
|
82
|
+
var passwordModule = lazyRequire(function () { return require("./auth/password"); });
|
|
83
83
|
|
|
84
84
|
class CredentialHashError extends FrameworkError {
|
|
85
85
|
constructor(message, code) {
|
|
@@ -219,7 +219,7 @@ async function hash(secret, opts) {
|
|
|
219
219
|
}
|
|
220
220
|
if (algoId === C.CRED_HASH_IDS.ARGON2ID) {
|
|
221
221
|
var plain = Buffer.isBuffer(secret) ? secret.toString("utf8") : secret;
|
|
222
|
-
var phc = await
|
|
222
|
+
var phc = await passwordModule().hash(plain, opts && opts.params);
|
|
223
223
|
var argonEnv = _envelope(algoId, Buffer.from(phc, "utf8"));
|
|
224
224
|
_emitEvent("credentialHash.hash", 1, { algo: algoName });
|
|
225
225
|
return argonEnv;
|
|
@@ -300,7 +300,7 @@ async function verify(secret, envelope) {
|
|
|
300
300
|
var phc = decoded.payload.toString("utf8");
|
|
301
301
|
var plain = Buffer.isBuffer(secret) ? secret.toString("utf8") : secret;
|
|
302
302
|
var argOk = false;
|
|
303
|
-
try { argOk = await
|
|
303
|
+
try { argOk = await passwordModule().verify(phc, plain); }
|
|
304
304
|
catch (_e) { argOk = false; }
|
|
305
305
|
_emitEvent("credentialHash.verify", 1,
|
|
306
306
|
{ outcome: argOk ? "success" : "failure", algo: algoName });
|
|
@@ -377,7 +377,7 @@ function needsRehash(envelope, opts) {
|
|
|
377
377
|
// Defer the parameter-lag check to the password primitive's
|
|
378
378
|
// own needsRehash so the threshold stays in one place.
|
|
379
379
|
var phc = decoded.payload.toString("utf8");
|
|
380
|
-
try { return
|
|
380
|
+
try { return passwordModule().needsRehash(phc, opts && opts.params); }
|
|
381
381
|
catch (_e) { return true; }
|
|
382
382
|
}
|
|
383
383
|
return false;
|
package/lib/crypto-field.js
CHANGED
|
@@ -47,9 +47,9 @@ var vault = require("./vault");
|
|
|
47
47
|
var { sha3Hash, kdf } = require("./crypto");
|
|
48
48
|
var { HASH_PREFIX, VAULT_PREFIX, TIME } = require("./constants");
|
|
49
49
|
|
|
50
|
-
var
|
|
51
|
-
var
|
|
52
|
-
var
|
|
50
|
+
var compliance = lazyRequire(function () { return require("./compliance"); });
|
|
51
|
+
var db = lazyRequire(function () { return require("./db"); });
|
|
52
|
+
var audit = lazyRequire(function () { return require("./audit"); });
|
|
53
53
|
|
|
54
54
|
// F-POSTURE-1 cascade hook + F-RTBF-2 integration. Recording the
|
|
55
55
|
// posture lets eraseRow call b.db.vacuumAfterErase({ mode: "full" })
|
|
@@ -88,7 +88,7 @@ function applyPosture(posture) {
|
|
|
88
88
|
_activePosture = posture;
|
|
89
89
|
var requireVacuum = false;
|
|
90
90
|
try {
|
|
91
|
-
requireVacuum =
|
|
91
|
+
requireVacuum = compliance().postureDefault(posture, "requireVacuumAfterErase") === true;
|
|
92
92
|
} catch (_e) { /* compliance not loaded — record posture only */ }
|
|
93
93
|
return { posture: posture, requireVacuumAfterErase: requireVacuum };
|
|
94
94
|
}
|
|
@@ -495,14 +495,14 @@ function eraseRow(table, row) {
|
|
|
495
495
|
if (_activePosture) {
|
|
496
496
|
var requireVacuum = false;
|
|
497
497
|
try {
|
|
498
|
-
requireVacuum =
|
|
498
|
+
requireVacuum = compliance().postureDefault(
|
|
499
499
|
_activePosture, "requireVacuumAfterErase") === true;
|
|
500
500
|
} catch (_e) { /* compliance lookup best-effort */ }
|
|
501
501
|
if (requireVacuum) {
|
|
502
502
|
try {
|
|
503
|
-
var
|
|
504
|
-
if (
|
|
505
|
-
|
|
503
|
+
var dbInst = db();
|
|
504
|
+
if (dbInst && typeof dbInst.vacuumAfterErase === "function") {
|
|
505
|
+
dbInst.vacuumAfterErase({ mode: "full" });
|
|
506
506
|
}
|
|
507
507
|
} catch (_vacErr) {
|
|
508
508
|
// VACUUM is best-effort at the eraseRow seam — DB might not be
|
|
@@ -510,7 +510,7 @@ function eraseRow(table, row) {
|
|
|
510
510
|
// captures the skip; operators on regulated postures wire the
|
|
511
511
|
// sweep through b.retention which gates erasure on db.init().
|
|
512
512
|
try {
|
|
513
|
-
|
|
513
|
+
audit().safeEmit({
|
|
514
514
|
action: "cryptofield.vacuum.skipped",
|
|
515
515
|
outcome: "failure",
|
|
516
516
|
metadata: {
|
package/lib/crypto-hpke.js
CHANGED
|
@@ -51,7 +51,7 @@
|
|
|
51
51
|
* (recipientPubKey shape, plaintext type, missing private key on open).
|
|
52
52
|
*/
|
|
53
53
|
|
|
54
|
-
var nodeCrypto = require("crypto");
|
|
54
|
+
var nodeCrypto = require("node:crypto");
|
|
55
55
|
var C = require("./constants");
|
|
56
56
|
var lazyRequire = require("./lazy-require");
|
|
57
57
|
var validateOpts = require("./validate-opts");
|