@blamejs/core 0.9.12 → 0.9.15
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 +3 -0
- package/lib/a2a.js +11 -11
- package/lib/acme.js +5 -5
- package/lib/ai-input.js +2 -2
- package/lib/api-key.js +4 -4
- package/lib/api-snapshot.js +10 -7
- package/lib/app-shutdown.js +2 -2
- package/lib/app.js +5 -5
- package/lib/archive.js +8 -8
- package/lib/argon2-builtin.js +2 -2
- package/lib/atomic-file.js +53 -53
- package/lib/audit-sign.js +8 -8
- package/lib/audit-tools.js +22 -22
- package/lib/audit.js +29 -17
- package/lib/auth/dpop.js +3 -3
- package/lib/auth/sd-jwt-vc.js +2 -2
- package/lib/backup/bundle.js +17 -17
- package/lib/backup/index.js +36 -36
- package/lib/budr.js +3 -3
- package/lib/bundler.js +20 -20
- package/lib/circuit-breaker.js +24 -9
- package/lib/cli.js +25 -26
- package/lib/cluster.js +2 -2
- package/lib/compliance-sanctions.js +2 -2
- package/lib/config-drift.js +15 -15
- package/lib/content-credentials.js +4 -4
- package/lib/credential-hash.js +3 -3
- package/lib/crypto.js +145 -0
- package/lib/daemon.js +19 -19
- package/lib/db-file-lifecycle.js +24 -24
- package/lib/db-schema.js +2 -2
- package/lib/db.js +35 -35
- package/lib/dev.js +10 -10
- package/lib/dr-runbook.js +5 -5
- package/lib/dsr.js +22 -15
- package/lib/dual-control.js +2 -2
- package/lib/external-db-migrate.js +2 -2
- package/lib/external-db.js +2 -2
- package/lib/fdx.js +2 -2
- package/lib/file-upload.js +30 -30
- package/lib/flag-providers.js +4 -4
- package/lib/gate-contract.js +5 -5
- package/lib/graphql-federation.js +4 -7
- package/lib/honeytoken.js +6 -6
- package/lib/http-client-cookie-jar.js +6 -6
- package/lib/http-client.js +18 -18
- package/lib/i18n.js +5 -5
- package/lib/inbox.js +21 -15
- package/lib/keychain.js +9 -9
- package/lib/legal-hold.js +2 -2
- package/lib/local-db-thin.js +9 -9
- package/lib/log-stream-local.js +17 -17
- package/lib/log-stream-syslog.js +2 -2
- package/lib/log-stream.js +3 -3
- package/lib/mail-bounce.js +2 -2
- package/lib/mail-mdn.js +2 -2
- package/lib/mail-srs.js +2 -2
- package/lib/mail.js +4 -4
- package/lib/mcp.js +2 -2
- package/lib/metrics.js +249 -2
- package/lib/middleware/api-encrypt.js +16 -16
- package/lib/middleware/body-parser.js +16 -16
- package/lib/middleware/compression.js +3 -3
- package/lib/middleware/csp-nonce.js +4 -4
- package/lib/middleware/health.js +7 -7
- package/lib/middleware/idempotency-key.js +250 -0
- package/lib/migrations.js +3 -3
- package/lib/mtls-ca.js +26 -26
- package/lib/mtls-engine-default.js +5 -5
- package/lib/network-dns.js +2 -2
- package/lib/network-nts.js +2 -2
- package/lib/network-proxy.js +3 -3
- package/lib/network-smtp-policy.js +2 -2
- package/lib/network-tls.js +17 -17
- package/lib/network.js +13 -13
- package/lib/notify.js +3 -3
- package/lib/object-store/gcs-bucket-ops.js +2 -2
- package/lib/object-store/gcs.js +5 -5
- package/lib/object-store/index.js +6 -6
- package/lib/object-store/local.js +19 -19
- package/lib/object-store/sigv4.js +3 -3
- package/lib/observability-tracer.js +4 -4
- package/lib/otel-export.js +3 -3
- package/lib/pagination.js +5 -5
- package/lib/parsers/safe-xml.js +3 -3
- package/lib/pqc-agent.js +116 -26
- package/lib/pqc-gate.js +5 -5
- package/lib/pubsub-redis.js +2 -2
- package/lib/queue-local.js +3 -3
- package/lib/queue.js +2 -2
- package/lib/redis-client.js +4 -4
- package/lib/restore-bundle.js +18 -18
- package/lib/restore-rollback.js +34 -34
- package/lib/restore.js +16 -16
- package/lib/retry.js +50 -0
- package/lib/router.js +13 -13
- package/lib/sandbox.js +8 -8
- package/lib/sec-cyber.js +3 -3
- package/lib/security-assert.js +2 -2
- package/lib/seeders.js +4 -4
- package/lib/self-update-standalone-verifier.js +280 -0
- package/lib/self-update.js +32 -26
- package/lib/session-device-binding.js +2 -2
- package/lib/static.js +22 -22
- package/lib/template.js +19 -19
- package/lib/testing.js +7 -7
- package/lib/tls-exporter.js +5 -5
- package/lib/tracing.js +3 -3
- package/lib/vault/index.js +11 -11
- package/lib/vault/passphrase-ops.js +37 -37
- package/lib/vault/passphrase-source.js +2 -2
- package/lib/vault/rotate.js +70 -66
- package/lib/vault/seal-pem-file.js +26 -26
- package/lib/watcher.js +23 -23
- package/lib/webhook.js +10 -10
- package/lib/worker-pool.js +6 -6
- package/lib/ws-client.js +4 -4
- package/package.json +1 -1
- package/sbom.cdx.json +6 -6
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
* source: "/etc/letsencrypt/live/example.com/privkey.pem",
|
|
20
20
|
* destination: "/var/lib/blamejs/server.key.sealed",
|
|
21
21
|
* audit: true, // default
|
|
22
|
-
* pollInterval: b.constants.TIME.seconds(2), //
|
|
22
|
+
* pollInterval: b.constants.TIME.seconds(2), // nodeFs.watchFile cadence
|
|
23
23
|
* onResealed: function (info) { ... }, // { srcPath, destPath, bytes,
|
|
24
24
|
* resealedAt, generation }
|
|
25
25
|
* onError: function (err) { ... }, // sealing failed
|
|
@@ -42,10 +42,10 @@
|
|
|
42
42
|
* (rename did not happen). The recovery routine re-runs the seal from
|
|
43
43
|
* source — idempotent because the source PEM is the source of truth.
|
|
44
44
|
*
|
|
45
|
-
*
|
|
45
|
+
* nodeFs.watchFile semantics:
|
|
46
46
|
*
|
|
47
|
-
* Node's
|
|
48
|
-
* pollInterval. It fires on mtime / size change.
|
|
47
|
+
* Node's nodeFs.watchFile is a polling stat() loop with the configured
|
|
48
|
+
* pollInterval. It fires on mtime / size change. nodeFs.watch (the
|
|
49
49
|
* inotify / kqueue backend) is more efficient but inconsistent across
|
|
50
50
|
* platforms — single rename events surface as multiple change events
|
|
51
51
|
* on Linux (events fire on the directory entry, the file, and the
|
|
@@ -54,8 +54,8 @@
|
|
|
54
54
|
* pollInterval) is acceptable for renewal cadences measured in days.
|
|
55
55
|
*/
|
|
56
56
|
|
|
57
|
-
var
|
|
58
|
-
var
|
|
57
|
+
var nodeFs = require("fs");
|
|
58
|
+
var nodePath = require("path");
|
|
59
59
|
var atomicFile = require("../atomic-file");
|
|
60
60
|
var C = require("../constants");
|
|
61
61
|
var lazyRequire = require("../lazy-require");
|
|
@@ -76,7 +76,7 @@ var SealPemFileError = defineClass("SealPemFileError", { alwaysPermanent: true }
|
|
|
76
76
|
// 2-second worst-case re-seal latency — negligible against the
|
|
77
77
|
// renewal cadence. Operators with sub-second-sensitive use cases
|
|
78
78
|
// override via opts.pollInterval.
|
|
79
|
-
// H6 #6 —
|
|
79
|
+
// H6 #6 — nodeFs.watchFile default cadence reduced from 2s to 500ms so a
|
|
80
80
|
// fast renewal-then-revert (mtime bump then second bump within ~2s)
|
|
81
81
|
// doesn't sneak past the watcher. Operators with extremely-quiet
|
|
82
82
|
// renewal cycles can override via opts.pollInterval; the cost of
|
|
@@ -126,7 +126,7 @@ var DEFAULT_MAX_SOURCE_BYTES = C.BYTES.mib(1);
|
|
|
126
126
|
* source: string, // plaintext PEM path (required)
|
|
127
127
|
* destination: string, // sealed-output path (required, must differ from source)
|
|
128
128
|
* audit: boolean, // emit b.audit events on every reseal (default true)
|
|
129
|
-
* pollInterval: number, //
|
|
129
|
+
* pollInterval: number, // nodeFs.watchFile cadence in ms (default 500)
|
|
130
130
|
* onResealed: function, // (info) => void — { srcPath, destPath, bytes, resealedAt, generation }
|
|
131
131
|
* onError: function, // (err) => void — sealing failed
|
|
132
132
|
* maxSourceBytes: number, // refuse source larger than this (default 1 MiB)
|
|
@@ -219,7 +219,7 @@ function sealPemFile(opts) {
|
|
|
219
219
|
// marker create and marker remove, the marker remains on disk
|
|
220
220
|
// and _recoverIfNeeded() detects it on the next start().
|
|
221
221
|
var markerPath = destination + ".rewriting";
|
|
222
|
-
var destDir =
|
|
222
|
+
var destDir = nodePath.dirname(destination);
|
|
223
223
|
atomicFile.ensureDir(destDir);
|
|
224
224
|
// H6 #4 — assert parent-dir mode. If the directory is world-
|
|
225
225
|
// writable, an attacker can swap the destination file or the
|
|
@@ -229,7 +229,7 @@ function sealPemFile(opts) {
|
|
|
229
229
|
// skip the check there.
|
|
230
230
|
if (process.platform !== "win32") {
|
|
231
231
|
try {
|
|
232
|
-
var dirStat =
|
|
232
|
+
var dirStat = nodeFs.statSync(destDir);
|
|
233
233
|
if ((dirStat.mode & 0o022) !== 0) { // allow:raw-byte-literal — POSIX mode mask
|
|
234
234
|
throw new SealPemFileError("seal-pem-file/parent-dir-writable",
|
|
235
235
|
"destination parent dir '" + destDir + "' is group/other-writable " +
|
|
@@ -242,23 +242,23 @@ function sealPemFile(opts) {
|
|
|
242
242
|
}
|
|
243
243
|
}
|
|
244
244
|
var sealed = vault().seal(plaintextBytes);
|
|
245
|
-
|
|
245
|
+
nodeFs.writeFileSync(markerPath, String(Date.now()), { mode: 0o600 }); // allow:raw-byte-literal — POSIX file mode
|
|
246
246
|
try {
|
|
247
247
|
atomicFile.writeSync(destination, sealed, { fileMode: 0o600 }); // allow:raw-byte-literal — POSIX file mode
|
|
248
248
|
} catch (e) {
|
|
249
|
-
try {
|
|
249
|
+
try { nodeFs.unlinkSync(markerPath); } catch (_e) { /* best-effort */ }
|
|
250
250
|
throw e;
|
|
251
251
|
}
|
|
252
|
-
try {
|
|
252
|
+
try { nodeFs.unlinkSync(markerPath); } catch (_e) { /* marker cleanup best-effort */ }
|
|
253
253
|
// H6 #5 — fsync the destination directory so the rename + marker
|
|
254
254
|
// unlink survive a power loss. Crash + backup-snapshot edge case:
|
|
255
255
|
// without dir-fsync, a journaled fs may have the new file inode
|
|
256
256
|
// but not the directory entry update by the time the snapshot
|
|
257
257
|
// reads.
|
|
258
258
|
try {
|
|
259
|
-
var dirFd =
|
|
260
|
-
try {
|
|
261
|
-
finally {
|
|
259
|
+
var dirFd = nodeFs.openSync(destDir, "r");
|
|
260
|
+
try { nodeFs.fsyncSync(dirFd); }
|
|
261
|
+
finally { nodeFs.closeSync(dirFd); }
|
|
262
262
|
} catch (_e) { /* dir fsync best-effort — Windows / non-POSIX may refuse */ }
|
|
263
263
|
}
|
|
264
264
|
|
|
@@ -267,14 +267,14 @@ function sealPemFile(opts) {
|
|
|
267
267
|
resealing = true;
|
|
268
268
|
var plaintext = null;
|
|
269
269
|
try {
|
|
270
|
-
// H6 #1 — bounded read.
|
|
270
|
+
// H6 #1 — bounded read. nodeFs.readFileSync without a size cap on a
|
|
271
271
|
// file the operator's renewal process writes is an OOM vector.
|
|
272
|
-
// H6 #3 — symlink TOCTOU defense. Open the file via
|
|
272
|
+
// H6 #3 — symlink TOCTOU defense. Open the file via nodeFs.openSync
|
|
273
273
|
// with O_NOFOLLOW where possible; lstat first to verify the
|
|
274
274
|
// source isn't a symlink we don't expect, then read via fd so
|
|
275
275
|
// a swap-after-stat doesn't change which bytes we read.
|
|
276
276
|
try {
|
|
277
|
-
var lstat =
|
|
277
|
+
var lstat = nodeFs.lstatSync(source);
|
|
278
278
|
if (lstat.isSymbolicLink()) {
|
|
279
279
|
throw new SealPemFileError("seal-pem-file/symlink-refused",
|
|
280
280
|
"source is a symlink (refused; follow + re-stat opens TOCTOU)");
|
|
@@ -283,9 +283,9 @@ function sealPemFile(opts) {
|
|
|
283
283
|
throw new SealPemFileError("seal-pem-file/source-too-large",
|
|
284
284
|
"source size " + lstat.size + " exceeds maxSourceBytes " + maxSourceBytes);
|
|
285
285
|
}
|
|
286
|
-
var fd =
|
|
286
|
+
var fd = nodeFs.openSync(source, "r");
|
|
287
287
|
try {
|
|
288
|
-
var fstat =
|
|
288
|
+
var fstat = nodeFs.fstatSync(fd);
|
|
289
289
|
// H6 #3 — confirm the fd points at the same inode lstat saw.
|
|
290
290
|
if (fstat.ino !== lstat.ino || fstat.size > maxSourceBytes) {
|
|
291
291
|
throw new SealPemFileError("seal-pem-file/toctou-detected",
|
|
@@ -294,7 +294,7 @@ function sealPemFile(opts) {
|
|
|
294
294
|
plaintext = Buffer.alloc(fstat.size);
|
|
295
295
|
var read = 0;
|
|
296
296
|
while (read < fstat.size) {
|
|
297
|
-
var n =
|
|
297
|
+
var n = nodeFs.readSync(fd, plaintext, read, fstat.size - read, null);
|
|
298
298
|
if (n === 0) break;
|
|
299
299
|
read += n;
|
|
300
300
|
}
|
|
@@ -303,7 +303,7 @@ function sealPemFile(opts) {
|
|
|
303
303
|
"short read: " + read + " of " + fstat.size + " bytes");
|
|
304
304
|
}
|
|
305
305
|
} finally {
|
|
306
|
-
try {
|
|
306
|
+
try { nodeFs.closeSync(fd); } catch (_e) { /* close best-effort */ }
|
|
307
307
|
}
|
|
308
308
|
}
|
|
309
309
|
catch (e) {
|
|
@@ -390,7 +390,7 @@ function sealPemFile(opts) {
|
|
|
390
390
|
// reseal was interrupted. Re-seal from source idempotently.
|
|
391
391
|
function _recoverIfNeeded() {
|
|
392
392
|
var markerPath = destination + ".rewriting";
|
|
393
|
-
if (
|
|
393
|
+
if (nodeFs.existsSync(markerPath)) {
|
|
394
394
|
log.info("vault.sealPemFile: recovery — marker '" + markerPath +
|
|
395
395
|
"' present from prior crashed reseal; re-sealing from source");
|
|
396
396
|
_emitAudit("recovery_started", "success", {
|
|
@@ -414,7 +414,7 @@ function sealPemFile(opts) {
|
|
|
414
414
|
_resealNow();
|
|
415
415
|
}
|
|
416
416
|
};
|
|
417
|
-
|
|
417
|
+
nodeFs.watchFile(source, { persistent: false, interval: pollInterval }, listener);
|
|
418
418
|
watching = true;
|
|
419
419
|
_emitAudit("watch_started", "success", {
|
|
420
420
|
source: source,
|
|
@@ -425,7 +425,7 @@ function sealPemFile(opts) {
|
|
|
425
425
|
|
|
426
426
|
function stop() {
|
|
427
427
|
if (!watching) return;
|
|
428
|
-
|
|
428
|
+
nodeFs.unwatchFile(source, listener);
|
|
429
429
|
listener = null;
|
|
430
430
|
watching = false;
|
|
431
431
|
_emitAudit("watch_stopped", "success", {
|
package/lib/watcher.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* b.watcher — recursive filesystem-watch primitive with cross-platform
|
|
4
4
|
* event normalization.
|
|
5
5
|
*
|
|
6
|
-
* Wraps `
|
|
6
|
+
* Wraps `nodeFs.watch(root, { recursive: true })` and turns the per-platform
|
|
7
7
|
* event soup (Linux inotify "rename" + "change", macOS FSEvents
|
|
8
8
|
* coalesced "rename", Windows ReadDirectoryChangesW pure "rename" /
|
|
9
9
|
* "change") into a single shape:
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
* `type` is one of "file" or "dir". The watcher is build-tool-shaped:
|
|
16
16
|
* use it to drive incremental rebuilds, hot-reload-on-change,
|
|
17
17
|
* config-file watching, or content-store cache busts. It is NOT a
|
|
18
|
-
* security primitive —
|
|
18
|
+
* security primitive — nodeFs.watch is best-effort across kernels and the
|
|
19
19
|
* caller must not rely on it for audit-grade change detection.
|
|
20
20
|
*
|
|
21
21
|
* Cross-platform notes baked in:
|
|
@@ -45,8 +45,8 @@
|
|
|
45
45
|
* watcher.WatcherError
|
|
46
46
|
*/
|
|
47
47
|
|
|
48
|
-
var
|
|
49
|
-
var
|
|
48
|
+
var nodeFs = require("fs");
|
|
49
|
+
var nodePath = require("path");
|
|
50
50
|
var lazyRequire = require("./lazy-require");
|
|
51
51
|
var validateOpts = require("./validate-opts");
|
|
52
52
|
var { WatcherError } = require("./framework-error");
|
|
@@ -56,7 +56,7 @@ var observability = lazyRequire(function () { return require("./observability");
|
|
|
56
56
|
|
|
57
57
|
var DEFAULT_DEBOUNCE_MS = 100;
|
|
58
58
|
// Polling-mode defaults. The polling backend exists for environments
|
|
59
|
-
// where
|
|
59
|
+
// where nodeFs.watch's native events don't reach userspace — most commonly
|
|
60
60
|
// Docker Desktop bind-mounts on Windows / macOS hosts (where the
|
|
61
61
|
// inotify events from the Linux container's mount don't propagate
|
|
62
62
|
// through the gRPC-FUSE / VirtioFS bridge to the host fs), or NFS /
|
|
@@ -166,8 +166,8 @@ function _compileIgnore(patterns) {
|
|
|
166
166
|
}
|
|
167
167
|
}
|
|
168
168
|
return function (relPath) {
|
|
169
|
-
var base =
|
|
170
|
-
var normalized = relPath.split(
|
|
169
|
+
var base = nodePath.basename(relPath);
|
|
170
|
+
var normalized = relPath.split(nodePath.sep).join("/");
|
|
171
171
|
for (var j = 0; j < compiled.length; j += 1) {
|
|
172
172
|
var c = compiled[j];
|
|
173
173
|
if (c.kind === "exact" && (c.value === relPath || c.value === normalized)) return true;
|
|
@@ -212,7 +212,7 @@ function _validateOpts(opts) {
|
|
|
212
212
|
function create(opts) {
|
|
213
213
|
_validateOpts(opts);
|
|
214
214
|
|
|
215
|
-
var root =
|
|
215
|
+
var root = nodePath.resolve(opts.root);
|
|
216
216
|
var debounceMs = (opts.debounceMs !== undefined) ? opts.debounceMs : DEFAULT_DEBOUNCE_MS;
|
|
217
217
|
var maxPending = (opts.maxPending !== undefined) ? opts.maxPending : DEFAULT_MAX_PENDING;
|
|
218
218
|
var mode = opts.mode || "fs";
|
|
@@ -226,7 +226,7 @@ function create(opts) {
|
|
|
226
226
|
|
|
227
227
|
// Pre-flight: root must exist and be a directory.
|
|
228
228
|
var rootStat;
|
|
229
|
-
try { rootStat =
|
|
229
|
+
try { rootStat = nodeFs.statSync(root); }
|
|
230
230
|
catch (e) {
|
|
231
231
|
throw new WatcherError("watcher/root-missing",
|
|
232
232
|
"watcher.create: root '" + root + "' is not accessible: " + ((e && e.message) || String(e)));
|
|
@@ -260,10 +260,10 @@ function create(opts) {
|
|
|
260
260
|
function _normalizeAndDispatch(relPath) {
|
|
261
261
|
if (stopped) return;
|
|
262
262
|
if (isIgnored(relPath)) return;
|
|
263
|
-
var fullPath =
|
|
263
|
+
var fullPath = nodePath.join(root, relPath);
|
|
264
264
|
// lstat (NOT stat) — refuses to follow symlinks out of root.
|
|
265
265
|
var lst;
|
|
266
|
-
try { lst =
|
|
266
|
+
try { lst = nodeFs.lstatSync(fullPath); }
|
|
267
267
|
catch (e) {
|
|
268
268
|
if (e && e.code === "ENOENT") {
|
|
269
269
|
// Path is gone — delete event. Type unknown by the time we
|
|
@@ -335,9 +335,9 @@ function create(opts) {
|
|
|
335
335
|
var stack = [""];
|
|
336
336
|
while (stack.length > 0) {
|
|
337
337
|
var relDir = stack.pop();
|
|
338
|
-
var absDir = relDir === "" ? root :
|
|
338
|
+
var absDir = relDir === "" ? root : nodePath.join(root, relDir);
|
|
339
339
|
var entries;
|
|
340
|
-
try { entries =
|
|
340
|
+
try { entries = nodeFs.readdirSync(absDir, { withFileTypes: true }); }
|
|
341
341
|
catch (_e) {
|
|
342
342
|
// Root vanished mid-walk OR an inner dir got deleted between
|
|
343
343
|
// the parent listing and the descent. Skip — the next tick's
|
|
@@ -348,8 +348,8 @@ function create(opts) {
|
|
|
348
348
|
var entry = entries[i];
|
|
349
349
|
var relPath = relDir === "" ? entry.name : (relDir + "/" + entry.name);
|
|
350
350
|
// Normalize to forward-slash so glob ignore-matching is
|
|
351
|
-
// consistent with the
|
|
352
|
-
relPath = relPath.split(
|
|
351
|
+
// consistent with the nodeFs.watch path the operator's hooks see.
|
|
352
|
+
relPath = relPath.split(nodePath.sep).join("/");
|
|
353
353
|
if (isIgnored(relPath)) continue;
|
|
354
354
|
if (entry.isSymbolicLink()) continue; // never follow symlinks
|
|
355
355
|
fileCount += 1;
|
|
@@ -358,9 +358,9 @@ function create(opts) {
|
|
|
358
358
|
"watcher.poll: tree exceeds pollMaxFiles=" + pollMaxFiles +
|
|
359
359
|
" — narrow `ignore` patterns OR raise pollMaxFiles, OR switch to mode: \"fs\"");
|
|
360
360
|
}
|
|
361
|
-
var absPath =
|
|
361
|
+
var absPath = nodePath.join(absDir, entry.name);
|
|
362
362
|
var st;
|
|
363
|
-
try { st =
|
|
363
|
+
try { st = nodeFs.statSync(absPath); }
|
|
364
364
|
catch (_e) { continue; } // race — entry vanished
|
|
365
365
|
if (entry.isDirectory()) {
|
|
366
366
|
snapshot.set(relPath, { type: "dir", size: 0, mtimeMs: st.mtimeMs });
|
|
@@ -382,13 +382,13 @@ function create(opts) {
|
|
|
382
382
|
if (pollSnapshot === null) {
|
|
383
383
|
// First tick — establish the baseline without firing events.
|
|
384
384
|
// Operators get add events on file CREATION after start, not on
|
|
385
|
-
// pre-existing files (matches
|
|
385
|
+
// pre-existing files (matches nodeFs.watch semantics).
|
|
386
386
|
pollSnapshot = next;
|
|
387
387
|
return;
|
|
388
388
|
}
|
|
389
389
|
// Diff: anything in `next` not in `pollSnapshot`, OR with size /
|
|
390
390
|
// mtimeMs different, fires onChange via the same _enqueue path the
|
|
391
|
-
//
|
|
391
|
+
// nodeFs.watch backend uses (so debounce + ignore + lstat dispatch
|
|
392
392
|
// stay uniform). Anything in `pollSnapshot` missing from `next`
|
|
393
393
|
// fires onDelete (via _normalizeAndDispatch's ENOENT branch).
|
|
394
394
|
next.forEach(function (info, relPath) {
|
|
@@ -416,12 +416,12 @@ function create(opts) {
|
|
|
416
416
|
if (typeof pollTimer.unref === "function") pollTimer.unref();
|
|
417
417
|
} else {
|
|
418
418
|
try {
|
|
419
|
-
watcherHandle =
|
|
419
|
+
watcherHandle = nodeFs.watch(root, { recursive: true, persistent: true }, function (eventType, filename) {
|
|
420
420
|
if (stopped) return;
|
|
421
421
|
if (!filename) return;
|
|
422
422
|
var rel = filename;
|
|
423
|
-
if (
|
|
424
|
-
rel =
|
|
423
|
+
if (nodePath.isAbsolute(rel) && rel.indexOf(root) === 0) {
|
|
424
|
+
rel = nodePath.relative(root, rel);
|
|
425
425
|
}
|
|
426
426
|
if (rel === "" || rel === ".") return;
|
|
427
427
|
_enqueue(rel);
|
|
@@ -434,7 +434,7 @@ function create(opts) {
|
|
|
434
434
|
((e && e.message) || String(e)) + " — pass mode: \"poll\" to fall back to interval polling");
|
|
435
435
|
}
|
|
436
436
|
throw new WatcherError("watcher/start-failed",
|
|
437
|
-
"watcher.create:
|
|
437
|
+
"watcher.create: nodeFs.watch failed: " + ((e && e.message) || String(e)));
|
|
438
438
|
}
|
|
439
439
|
}
|
|
440
440
|
|
package/lib/webhook.js
CHANGED
|
@@ -48,11 +48,11 @@
|
|
|
48
48
|
*/
|
|
49
49
|
|
|
50
50
|
var nodeCrypto = require("crypto");
|
|
51
|
-
var
|
|
51
|
+
var bCrypto = require("./crypto");
|
|
52
52
|
var httpClient = require("./http-client");
|
|
53
53
|
var safeBuffer = require("./safe-buffer");
|
|
54
54
|
var safeUrl = require("./safe-url");
|
|
55
|
-
var
|
|
55
|
+
var retryHelper = require("./retry");
|
|
56
56
|
var C = require("./constants");
|
|
57
57
|
var lazyRequire = require("./lazy-require");
|
|
58
58
|
var numericChecks = require("./numeric-checks");
|
|
@@ -220,13 +220,13 @@ function _composeSignedString(algo, kid, timestamp, id, body) {
|
|
|
220
220
|
// ---- Sign / verify primitives ----
|
|
221
221
|
|
|
222
222
|
function _hmacSign(key, data) {
|
|
223
|
-
return
|
|
223
|
+
return bCrypto.hmacSha3(key, data); // hex string
|
|
224
224
|
}
|
|
225
225
|
|
|
226
226
|
function _hmacVerify(key, data, expectedHex) {
|
|
227
227
|
if (!safeBuffer.isHex(expectedHex)) return false;
|
|
228
|
-
var actualHex =
|
|
229
|
-
return
|
|
228
|
+
var actualHex = bCrypto.hmacSha3(key, data);
|
|
229
|
+
return bCrypto.timingSafeEqual(actualHex, expectedHex);
|
|
230
230
|
}
|
|
231
231
|
|
|
232
232
|
// PQC signatures encode as base64url. SLH-DSA-SHAKE-256f signatures
|
|
@@ -242,7 +242,7 @@ function _hmacVerify(key, data, expectedHex) {
|
|
|
242
242
|
// shaped value is decoded as hex. New signatures are emitted as
|
|
243
243
|
// base64url; old hex-encoded signatures still verify.
|
|
244
244
|
function _pqcSign(privateKeyPem, data) {
|
|
245
|
-
return
|
|
245
|
+
return bCrypto.sign(data, privateKeyPem).toString("base64url");
|
|
246
246
|
}
|
|
247
247
|
|
|
248
248
|
var _BASE64URL_RE = safeBuffer.BASE64URL_RE;
|
|
@@ -260,7 +260,7 @@ function _pqcVerify(publicKeyPem, data, expectedSig) {
|
|
|
260
260
|
return false;
|
|
261
261
|
}
|
|
262
262
|
} catch (_e) { return false; }
|
|
263
|
-
try { return
|
|
263
|
+
try { return bCrypto.verify(data, sigBuf, publicKeyPem); }
|
|
264
264
|
catch (_e) { return false; }
|
|
265
265
|
}
|
|
266
266
|
|
|
@@ -364,9 +364,9 @@ function signer(opts) {
|
|
|
364
364
|
var kids = _objectKeys(keys);
|
|
365
365
|
var defaultKid = opts.defaultKid || kids[0];
|
|
366
366
|
var sigHeader = cfg.signatureHeader;
|
|
367
|
-
var idGen = opts.idGenerator || function () { return
|
|
367
|
+
var idGen = opts.idGenerator || function () { return bCrypto.generateToken(C.BYTES.bytes(16)); };
|
|
368
368
|
var nowFn = opts.now || function () { return Date.now(); };
|
|
369
|
-
var retryOpts = opts.retry ||
|
|
369
|
+
var retryOpts = opts.retry || retryHelper.DEFAULT_RETRY;
|
|
370
370
|
var httpOpts = opts.http || {};
|
|
371
371
|
var audit = opts.audit || null;
|
|
372
372
|
var auditFailures = cfg.auditFailures;
|
|
@@ -452,7 +452,7 @@ function signer(opts) {
|
|
|
452
452
|
}).host;
|
|
453
453
|
} catch (_e) { hostLabel = ""; }
|
|
454
454
|
try {
|
|
455
|
-
var res = await
|
|
455
|
+
var res = await retryHelper.withRetry(function () {
|
|
456
456
|
return httpClient.request(requestOpts);
|
|
457
457
|
}, retryOpts);
|
|
458
458
|
var statusCode = (res && (res.statusCode || res.status)) || 0;
|
package/lib/worker-pool.js
CHANGED
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
* var pool = b.workerPool.create("/abs/path/to/worker.js", {
|
|
25
25
|
* size: 4,
|
|
26
26
|
* maxQueueDepth: C.BYTES.kib(1), // 1024 max queued tasks
|
|
27
|
-
* taskTimeoutMs: b.
|
|
27
|
+
* taskTimeoutMs: b.C.TIME.minutes(2),
|
|
28
28
|
* onExit: function (code, workerId) { ... },
|
|
29
29
|
* });
|
|
30
30
|
* var result = await pool.run({ kind: "hash", payload: buf },
|
|
@@ -67,11 +67,11 @@
|
|
|
67
67
|
*/
|
|
68
68
|
|
|
69
69
|
var os = require("node:os");
|
|
70
|
-
var
|
|
70
|
+
var nodePath = require("node:path");
|
|
71
71
|
var lazyRequire = require("./lazy-require");
|
|
72
72
|
var validateOpts = require("./validate-opts");
|
|
73
73
|
var numericBounds = require("./numeric-bounds");
|
|
74
|
-
var
|
|
74
|
+
var C = require("./constants");
|
|
75
75
|
var { WorkerPoolError } = require("./framework-error");
|
|
76
76
|
|
|
77
77
|
var audit = lazyRequire(function () { return require("./audit"); });
|
|
@@ -80,8 +80,8 @@ var MIN_SIZE = 1;
|
|
|
80
80
|
var MAX_SIZE = 256; // allow:raw-byte-literal — sanity ceiling on worker count, not bytes
|
|
81
81
|
var DEFAULT_MAX_QUEUE_DEPTH = 1024; // allow:raw-byte-literal — task-queue depth, not bytes
|
|
82
82
|
var MAX_QUEUE_DEPTH_CAP = 1048576; // allow:raw-byte-literal — task-queue depth ceiling, not bytes
|
|
83
|
-
var DEFAULT_TASK_TIMEOUT_MS =
|
|
84
|
-
var MAX_TASK_TIMEOUT_MS =
|
|
83
|
+
var DEFAULT_TASK_TIMEOUT_MS = C.TIME.minutes(5);
|
|
84
|
+
var MAX_TASK_TIMEOUT_MS = C.TIME.hours(1);
|
|
85
85
|
|
|
86
86
|
// Refuse operator-supplied `eval`-style script paths. Worker_threads
|
|
87
87
|
// supports `{ eval: true }` to spawn from a string; this primitive
|
|
@@ -90,7 +90,7 @@ var MAX_TASK_TIMEOUT_MS = constants.TIME.hours(1);
|
|
|
90
90
|
function _validateScriptPath(scriptPath) {
|
|
91
91
|
validateOpts.requireNonEmptyString(scriptPath,
|
|
92
92
|
"workerPool.create: scriptPath", WorkerPoolError, "workerpool/bad-script-path");
|
|
93
|
-
if (!
|
|
93
|
+
if (!nodePath.isAbsolute(scriptPath)) {
|
|
94
94
|
throw new WorkerPoolError("workerpool/bad-script-path",
|
|
95
95
|
"workerPool.create: scriptPath must be an absolute path; got " +
|
|
96
96
|
JSON.stringify(scriptPath));
|
package/lib/ws-client.js
CHANGED
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
*/
|
|
47
47
|
|
|
48
48
|
var net = require("net");
|
|
49
|
-
var
|
|
49
|
+
var nodeUrl = require("url");
|
|
50
50
|
var nodeCrypto = require("crypto");
|
|
51
51
|
var EventEmitter = require("events");
|
|
52
52
|
|
|
@@ -146,7 +146,7 @@ function _expectedAccept(secKey, handshakeGuid) {
|
|
|
146
146
|
|
|
147
147
|
function _parseUrl(target) {
|
|
148
148
|
var parsed;
|
|
149
|
-
try { parsed = new
|
|
149
|
+
try { parsed = new nodeUrl.URL(target); }
|
|
150
150
|
catch (e) {
|
|
151
151
|
throw new WsClientError("ws-client/bad-url",
|
|
152
152
|
"wsClient.connect: url is malformed - " + e.message);
|
|
@@ -252,7 +252,7 @@ function connect(target, opts) {
|
|
|
252
252
|
// rebinding TOCTOU window). Cloud-metadata IPs are unconditional
|
|
253
253
|
// hard-deny — `allowInternal: true` does not bypass them.
|
|
254
254
|
var hostnameForUrl = parsed.protocol === "wss:" ? "https:" : "http:";
|
|
255
|
-
var probeUrl = new
|
|
255
|
+
var probeUrl = new nodeUrl.URL(hostnameForUrl + "//" + parsed.host + parsed.pathname + parsed.search);
|
|
256
256
|
ssrfGuard.checkUrl(probeUrl, {
|
|
257
257
|
allowInternal: opts.allowInternal,
|
|
258
258
|
errorClass: WsClientError,
|
|
@@ -334,7 +334,7 @@ class WsClient extends EventEmitter {
|
|
|
334
334
|
dialParsed = _parseUrl(nextTarget);
|
|
335
335
|
dialTarget = nextTarget;
|
|
336
336
|
var probeProto = dialParsed.protocol === "wss:" ? "https:" : "http:";
|
|
337
|
-
var probeUrl = new
|
|
337
|
+
var probeUrl = new nodeUrl.URL(probeProto + "//" + dialParsed.host + dialParsed.pathname + dialParsed.search);
|
|
338
338
|
var probe = ssrfGuard.checkUrl(probeUrl, {
|
|
339
339
|
allowInternal: opts.allowInternal,
|
|
340
340
|
errorClass: WsClientError,
|
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.6",
|
|
5
|
-
"serialNumber": "urn:uuid:
|
|
5
|
+
"serialNumber": "urn:uuid:40df0b28-c547-4f48-9bbf-f005b59cbd1b",
|
|
6
6
|
"version": 1,
|
|
7
7
|
"metadata": {
|
|
8
|
-
"timestamp": "2026-05-
|
|
8
|
+
"timestamp": "2026-05-14T00:04:25.956Z",
|
|
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.9.
|
|
22
|
+
"bom-ref": "@blamejs/core@0.9.15",
|
|
23
23
|
"type": "library",
|
|
24
24
|
"name": "blamejs",
|
|
25
|
-
"version": "0.9.
|
|
25
|
+
"version": "0.9.15",
|
|
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.9.
|
|
29
|
+
"purl": "pkg:npm/%40blamejs/core@0.9.15",
|
|
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.9.
|
|
57
|
+
"ref": "@blamejs/core@0.9.15",
|
|
58
58
|
"dependsOn": []
|
|
59
59
|
}
|
|
60
60
|
]
|