@blamejs/core 0.9.14 → 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 +1 -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 +6 -6
- 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/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 +4 -4
- 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/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/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/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 +2 -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 +163 -63
- 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-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/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.js +18 -18
- 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 +64 -64
- 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
package/lib/http-client.js
CHANGED
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
* Outbound HTTP client with SSRF gate, retry, circuit breaker, wall-clock + idle timeouts, AbortSignal propagation, connection pooling, streaming, and ALPN-negotiated HTTP/2.
|
|
36
36
|
*/
|
|
37
37
|
|
|
38
|
-
var
|
|
38
|
+
var nodeFs = require("fs");
|
|
39
39
|
var http = require("http");
|
|
40
40
|
var https = require("https");
|
|
41
41
|
var http2 = require("http2");
|
|
@@ -46,7 +46,7 @@ var streamPromises = require("node:stream/promises");
|
|
|
46
46
|
var { URL } = require("url");
|
|
47
47
|
var atomicFile = require("./atomic-file");
|
|
48
48
|
var C = require("./constants");
|
|
49
|
-
var
|
|
49
|
+
var bCrypto = require("./crypto");
|
|
50
50
|
var pqcAgent = require("./pqc-agent");
|
|
51
51
|
var safeAsync = require("./safe-async");
|
|
52
52
|
var safeBuffer = require("./safe-buffer");
|
|
@@ -461,7 +461,7 @@ function _attachJarCookie(headers, jar, url) {
|
|
|
461
461
|
// emits boundary headers + content + CRLF in order. Avoids the
|
|
462
462
|
// Buffer.concat() OOM class on large uploads. contentLength is
|
|
463
463
|
// a finite number when every source's size is statically
|
|
464
|
-
// resolvable (Buffer length,
|
|
464
|
+
// resolvable (Buffer length, nodeFs.statSync().size, opts.size on
|
|
465
465
|
// a stream entry); null otherwise — caller falls back to
|
|
466
466
|
// chunked transfer.
|
|
467
467
|
//
|
|
@@ -474,9 +474,9 @@ function _attachJarCookie(headers, jar, url) {
|
|
|
474
474
|
// `filename` and `contentType` apply to all three shapes; for
|
|
475
475
|
// `filePath` entries, `filename` defaults to path.basename(filePath).
|
|
476
476
|
function _buildMultipartBody(spec) {
|
|
477
|
-
var boundary = "----blamejs-mp-" +
|
|
477
|
+
var boundary = "----blamejs-mp-" + bCrypto.generateToken(C.BYTES.bytes(16));
|
|
478
478
|
var CRLF = "\r\n";
|
|
479
|
-
var
|
|
479
|
+
var nodeFs = require("fs"); // allow:inline-require — only on multipart paths that touch the filesystem
|
|
480
480
|
var path = require("path"); // allow:inline-require — same
|
|
481
481
|
var nodeStream = require("stream"); // allow:inline-require — Readable subclass only when streaming
|
|
482
482
|
|
|
@@ -558,7 +558,7 @@ function _buildMultipartBody(spec) {
|
|
|
558
558
|
} else if (hasFilePath) {
|
|
559
559
|
anyStreaming = true;
|
|
560
560
|
var st;
|
|
561
|
-
try { st =
|
|
561
|
+
try { st = nodeFs.statSync(file.filePath); }
|
|
562
562
|
catch (e) { throw new Error("multipart: file.filePath not readable: " + e.message); }
|
|
563
563
|
if (!st.isFile()) throw new Error("multipart: file.filePath is not a regular file");
|
|
564
564
|
_addEntry(head, { kind: "filePath", filePath: file.filePath, size: st.size });
|
|
@@ -613,7 +613,7 @@ function _buildMultipartBody(spec) {
|
|
|
613
613
|
if (entry.source.kind === "buffer") {
|
|
614
614
|
yield entry.source.buf;
|
|
615
615
|
} else if (entry.source.kind === "filePath") {
|
|
616
|
-
var rs =
|
|
616
|
+
var rs = nodeFs.createReadStream(entry.source.filePath);
|
|
617
617
|
try {
|
|
618
618
|
for await (var chunk of rs) yield chunk;
|
|
619
619
|
} finally {
|
|
@@ -1699,7 +1699,7 @@ function _requestH2(transport, u, opts) {
|
|
|
1699
1699
|
//
|
|
1700
1700
|
// uploadMultipartStream — POST a file body via multipart/form-data
|
|
1701
1701
|
// without buffering. Streams from disk through the request body using
|
|
1702
|
-
// `
|
|
1702
|
+
// `nodeFs.createReadStream` + `node:stream/promises` pipeline.
|
|
1703
1703
|
//
|
|
1704
1704
|
// Both compose through `request()` (responseMode: "stream") so safeUrl,
|
|
1705
1705
|
// ssrfGuard, allowedHosts, network-proxy, audit-on-host-deny, and the
|
|
@@ -1799,7 +1799,7 @@ async function downloadStream(opts) {
|
|
|
1799
1799
|
_validateDownloadOpts(opts);
|
|
1800
1800
|
var alg = opts.hash || DEFAULT_DOWNLOAD_HASH_ALG;
|
|
1801
1801
|
var dest = opts.dest;
|
|
1802
|
-
var tmpPath = dest + ".tmp-" +
|
|
1802
|
+
var tmpPath = dest + ".tmp-" + bCrypto.generateToken(C.BYTES.bytes(8));
|
|
1803
1803
|
var dir = nodePath.dirname(dest);
|
|
1804
1804
|
|
|
1805
1805
|
atomicFile.ensureDir(dir);
|
|
@@ -1857,13 +1857,13 @@ async function downloadStream(opts) {
|
|
|
1857
1857
|
});
|
|
1858
1858
|
counter.bytesWritten = 0;
|
|
1859
1859
|
|
|
1860
|
-
var fileStream =
|
|
1860
|
+
var fileStream = nodeFs.createWriteStream(tmpPath, { mode: DEFAULT_DOWNLOAD_FILE_MODE, flags: "w" });
|
|
1861
1861
|
|
|
1862
1862
|
try {
|
|
1863
1863
|
await streamPromises.pipeline(res.body, counter, fileStream);
|
|
1864
1864
|
} catch (e) {
|
|
1865
1865
|
// Pipeline failure → tmp may be partially written. Remove + audit.
|
|
1866
|
-
try {
|
|
1866
|
+
try { nodeFs.unlinkSync(tmpPath); } catch (_u) { /* best-effort cleanup */ }
|
|
1867
1867
|
_emitAudit(opts, "system.httpclient.download_stream.refused", "denied", {
|
|
1868
1868
|
reason: "pipeline-failed", message: e.message, code: e.code,
|
|
1869
1869
|
});
|
|
@@ -1876,15 +1876,15 @@ async function downloadStream(opts) {
|
|
|
1876
1876
|
// across platforms but matches the discipline of the rest of the
|
|
1877
1877
|
// framework's atomic-write paths.
|
|
1878
1878
|
try {
|
|
1879
|
-
var fd =
|
|
1880
|
-
try { atomicFile.fsync(fd); } finally { try {
|
|
1879
|
+
var fd = nodeFs.openSync(tmpPath, "r+");
|
|
1880
|
+
try { atomicFile.fsync(fd); } finally { try { nodeFs.closeSync(fd); } catch (_c) { /* best-effort fd close */ } }
|
|
1881
1881
|
} catch (_fe) { /* fsync best-effort */ }
|
|
1882
1882
|
|
|
1883
1883
|
var actualHex = hasher.digest("hex");
|
|
1884
1884
|
if (typeof opts.expected === "string" && opts.expected.length > 0) {
|
|
1885
1885
|
var expected = opts.expected.toLowerCase();
|
|
1886
1886
|
if (actualHex.toLowerCase() !== expected) {
|
|
1887
|
-
try {
|
|
1887
|
+
try { nodeFs.unlinkSync(tmpPath); } catch (_u) { /* best-effort cleanup */ }
|
|
1888
1888
|
_emitAudit(opts, "system.httpclient.download_stream.refused", "denied", {
|
|
1889
1889
|
reason: "hash-mismatch", alg: alg, expected: expected, actual: actualHex,
|
|
1890
1890
|
statusCode: res.statusCode, bytesWritten: counter.bytesWritten,
|
|
@@ -1897,10 +1897,10 @@ async function downloadStream(opts) {
|
|
|
1897
1897
|
|
|
1898
1898
|
// Atomic rename + dir fsync.
|
|
1899
1899
|
try {
|
|
1900
|
-
|
|
1900
|
+
nodeFs.renameSync(tmpPath, dest);
|
|
1901
1901
|
atomicFile.fsyncDir(dir);
|
|
1902
1902
|
} catch (e) {
|
|
1903
|
-
try {
|
|
1903
|
+
try { nodeFs.unlinkSync(tmpPath); } catch (_u) { /* best-effort cleanup */ }
|
|
1904
1904
|
_emitAudit(opts, "system.httpclient.download_stream.refused", "denied", {
|
|
1905
1905
|
reason: "rename-failed", message: e.message,
|
|
1906
1906
|
});
|
|
@@ -1959,7 +1959,7 @@ function _validateUploadOpts(opts) {
|
|
|
1959
1959
|
*
|
|
1960
1960
|
* POSTs a file body via `multipart/form-data` without buffering the
|
|
1961
1961
|
* file in memory. Streams from disk through the request body using
|
|
1962
|
-
* `
|
|
1962
|
+
* `nodeFs.createReadStream` + `node:stream/promises` pipeline. Throws
|
|
1963
1963
|
* `httpclient/missing-file` when `opts.file.path` doesn't exist or
|
|
1964
1964
|
* isn't a regular file. Composes through `request()` so SSRF gating,
|
|
1965
1965
|
* proxy routing, and the per-origin transport cache apply unchanged.
|
|
@@ -1989,7 +1989,7 @@ async function uploadMultipartStream(opts) {
|
|
|
1989
1989
|
|
|
1990
1990
|
var filePath = opts.file.path;
|
|
1991
1991
|
var st;
|
|
1992
|
-
try { st =
|
|
1992
|
+
try { st = nodeFs.statSync(filePath); }
|
|
1993
1993
|
catch (e) {
|
|
1994
1994
|
_emitAudit(opts, "system.httpclient.upload_stream.refused", "denied", {
|
|
1995
1995
|
reason: "missing-file", path: filePath, message: e.message,
|
package/lib/i18n.js
CHANGED
|
@@ -57,8 +57,8 @@
|
|
|
57
57
|
* ICU MessageFormat + CLDR Plural Rules + locale-aware Intl formatters with translation lookup.
|
|
58
58
|
*/
|
|
59
59
|
|
|
60
|
-
var
|
|
61
|
-
var
|
|
60
|
+
var nodeFs = require("node:fs");
|
|
61
|
+
var nodePath = require("node:path");
|
|
62
62
|
var lazyRequire = require("./lazy-require");
|
|
63
63
|
var requestHelpers = require("./request-helpers");
|
|
64
64
|
var safeJson = require("./safe-json");
|
|
@@ -227,13 +227,13 @@ function _loadFromDir(dir, locales) {
|
|
|
227
227
|
var out = {};
|
|
228
228
|
for (var i = 0; i < locales.length; i++) {
|
|
229
229
|
var locale = locales[i];
|
|
230
|
-
var filePath =
|
|
231
|
-
if (!
|
|
230
|
+
var filePath = nodePath.join(dir, locale + ".json");
|
|
231
|
+
if (!nodeFs.existsSync(filePath)) {
|
|
232
232
|
throw _err("LOAD_FAILED",
|
|
233
233
|
"i18n: translations file not found for locale '" + locale + "': " + filePath);
|
|
234
234
|
}
|
|
235
235
|
var raw;
|
|
236
|
-
try { raw =
|
|
236
|
+
try { raw = nodeFs.readFileSync(filePath, "utf8"); }
|
|
237
237
|
catch (e) {
|
|
238
238
|
throw _err("LOAD_FAILED",
|
|
239
239
|
"i18n: failed to read '" + filePath + "': " + ((e && e.message) || String(e)));
|
package/lib/keychain.js
CHANGED
|
@@ -43,8 +43,8 @@
|
|
|
43
43
|
* OS keychain abstraction with encrypted-file fallback — stores / retrieves / removes a `(service, account) -> password` binding via the host operating system's native credential store.
|
|
44
44
|
*/
|
|
45
45
|
|
|
46
|
-
var
|
|
47
|
-
var
|
|
46
|
+
var nodeFs = require("fs");
|
|
47
|
+
var nodePath = require("path");
|
|
48
48
|
|
|
49
49
|
var atomicFile = require("./atomic-file");
|
|
50
50
|
var C = require("./constants");
|
|
@@ -91,7 +91,7 @@ function _detectBackend() {
|
|
|
91
91
|
|
|
92
92
|
function _existsExecutable(filepath) {
|
|
93
93
|
try {
|
|
94
|
-
var st =
|
|
94
|
+
var st = nodeFs.statSync(filepath);
|
|
95
95
|
return st.isFile();
|
|
96
96
|
} catch (_e) { return false; }
|
|
97
97
|
}
|
|
@@ -124,7 +124,7 @@ function _resolveOnPath(binName) {
|
|
|
124
124
|
for (var i = 0; i < parts.length; i += 1) {
|
|
125
125
|
var dir = parts[i];
|
|
126
126
|
if (typeof dir !== "string" || dir.length === 0) continue;
|
|
127
|
-
var candidate =
|
|
127
|
+
var candidate = nodePath.join(dir, binName);
|
|
128
128
|
if (_existsExecutable(candidate)) return candidate;
|
|
129
129
|
}
|
|
130
130
|
return null;
|
|
@@ -159,9 +159,9 @@ function _validateCommonOpts(opts, primitive) {
|
|
|
159
159
|
function _validateFallbackFile(filepath, primitive) {
|
|
160
160
|
validateOpts.requireNonEmptyString(filepath, "fallbackFile",
|
|
161
161
|
KeychainError, "keychain/bad-fallback-file");
|
|
162
|
-
if (!
|
|
162
|
+
if (!nodePath.isAbsolute(filepath)) {
|
|
163
163
|
throw new KeychainError("keychain/relative-fallback-file",
|
|
164
|
-
primitive + ": fallbackFile must be an absolute
|
|
164
|
+
primitive + ": fallbackFile must be an absolute nodePath; got " + filepath);
|
|
165
165
|
}
|
|
166
166
|
}
|
|
167
167
|
|
|
@@ -613,7 +613,7 @@ function _isFallbackError(e) {
|
|
|
613
613
|
* service: string, // required, no NUL/CR/LF bytes
|
|
614
614
|
* account: string, // required, no NUL/CR/LF bytes
|
|
615
615
|
* password: string, // required, non-empty
|
|
616
|
-
* fallbackFile?: string, // absolute
|
|
616
|
+
* fallbackFile?: string, // absolute nodePath; required if file fallback may engage
|
|
617
617
|
* passphrase?: string, // required when fallbackFile engages (Argon2id-derived KEK)
|
|
618
618
|
* preferFile?: boolean, // default: false
|
|
619
619
|
* audit?: boolean, // default: true (emits keychain.stored)
|
|
@@ -685,7 +685,7 @@ async function store(opts) {
|
|
|
685
685
|
* {
|
|
686
686
|
* service: string, // required
|
|
687
687
|
* account: string, // required
|
|
688
|
-
* fallbackFile?: string, // absolute
|
|
688
|
+
* fallbackFile?: string, // absolute nodePath; required for file-backend lookup
|
|
689
689
|
* passphrase?: string, // required when fallbackFile engages
|
|
690
690
|
* preferFile?: boolean, // default: false
|
|
691
691
|
* audit?: boolean, // default: true (emits keychain.retrieved)
|
|
@@ -781,7 +781,7 @@ async function retrieve(opts) {
|
|
|
781
781
|
* {
|
|
782
782
|
* service: string, // required
|
|
783
783
|
* account: string, // required
|
|
784
|
-
* fallbackFile?: string, // absolute
|
|
784
|
+
* fallbackFile?: string, // absolute nodePath; required for file-backend cleanup
|
|
785
785
|
* passphrase?: string, // required when fallbackFile engages
|
|
786
786
|
* preferFile?: boolean, // default: false
|
|
787
787
|
* audit?: boolean, // default: true (emits keychain.removed)
|
package/lib/legal-hold.js
CHANGED
|
@@ -59,7 +59,7 @@
|
|
|
59
59
|
* missing/garbage subjectId at the API; emit + return shaped error
|
|
60
60
|
* on policy denials (already-held / not-held / invalid-citation).
|
|
61
61
|
*/
|
|
62
|
-
var
|
|
62
|
+
var bCrypto = require("./crypto");
|
|
63
63
|
var lazyRequire = require("./lazy-require");
|
|
64
64
|
var safeJson = require("./safe-json");
|
|
65
65
|
var validateOpts = require("./validate-opts");
|
|
@@ -96,7 +96,7 @@ function _subjectIdString(subjectId) {
|
|
|
96
96
|
}
|
|
97
97
|
|
|
98
98
|
function _hashSubject(subjectId) {
|
|
99
|
-
return
|
|
99
|
+
return bCrypto.sha3Hash("bj-legal-hold:" + subjectId);
|
|
100
100
|
}
|
|
101
101
|
|
|
102
102
|
function create(opts) {
|
package/lib/local-db-thin.js
CHANGED
|
@@ -53,8 +53,8 @@
|
|
|
53
53
|
* localdb.thin.closed { file }
|
|
54
54
|
*/
|
|
55
55
|
|
|
56
|
-
var
|
|
57
|
-
var
|
|
56
|
+
var nodeFs = require("fs");
|
|
57
|
+
var nodePath = require("path");
|
|
58
58
|
var lazyRequire = require("./lazy-require");
|
|
59
59
|
var validateOpts = require("./validate-opts");
|
|
60
60
|
var safeSql = require("./safe-sql");
|
|
@@ -77,7 +77,7 @@ var NUL_BYTE = String.fromCharCode(0);
|
|
|
77
77
|
function _validateOpts(opts) {
|
|
78
78
|
validateOpts.requireObject(opts, "localDb.thin", LocalDbThinError, "localdb-thin/bad-opts");
|
|
79
79
|
validateOpts.requireNonEmptyString(opts.file, "file", LocalDbThinError, "localdb-thin/bad-file");
|
|
80
|
-
// `file` is operator-supplied (daemon's chosen storage
|
|
80
|
+
// `file` is operator-supplied (daemon's chosen storage nodePath), not
|
|
81
81
|
// request-driven input. Reject NUL bytes defensively — Node's path
|
|
82
82
|
// routines silently truncate at the first NUL, which would let a
|
|
83
83
|
// typo open a different file than the operator intended.
|
|
@@ -144,7 +144,7 @@ function thin(opts) {
|
|
|
144
144
|
_validateOpts(opts);
|
|
145
145
|
|
|
146
146
|
var auditOn = opts.audit !== false;
|
|
147
|
-
// opts.file is operator-config (daemon-author chosen storage
|
|
147
|
+
// opts.file is operator-config (daemon-author chosen storage nodePath),
|
|
148
148
|
// not request-driven input. Validation above already rejected non-
|
|
149
149
|
// strings and NUL bytes. The operator picks the file location; the
|
|
150
150
|
// wrapper opens it as-is.
|
|
@@ -168,7 +168,7 @@ function thin(opts) {
|
|
|
168
168
|
|
|
169
169
|
// Ensure parent directory exists — operators commonly point this at
|
|
170
170
|
// an OS app-data path that may not exist on first daemon launch.
|
|
171
|
-
try {
|
|
171
|
+
try { nodeFs.mkdirSync(nodePath.dirname(file), { recursive: true }); } catch (_e) { /* best-effort */ }
|
|
172
172
|
|
|
173
173
|
var database = null;
|
|
174
174
|
var renamedTo = null;
|
|
@@ -203,13 +203,13 @@ function thin(opts) {
|
|
|
203
203
|
var lastRenameErr = null;
|
|
204
204
|
for (var attempt = 0; attempt < 20 && !renamed; attempt += 1) {
|
|
205
205
|
try {
|
|
206
|
-
if (
|
|
206
|
+
if (nodeFs.existsSync(file)) nodeFs.renameSync(file, renamedTo);
|
|
207
207
|
renamed = true;
|
|
208
208
|
} catch (re) {
|
|
209
209
|
lastRenameErr = re;
|
|
210
210
|
if (re && (re.code === "EBUSY" || re.code === "EPERM")) {
|
|
211
211
|
// Synchronous spin — don't reach for setTimeout in a
|
|
212
|
-
// boot-time
|
|
212
|
+
// boot-time nodePath. 100ms × 20 = 2s upper bound.
|
|
213
213
|
var until = Date.now() + 100;
|
|
214
214
|
while (Date.now() < until) { /* spin */ }
|
|
215
215
|
continue;
|
|
@@ -227,8 +227,8 @@ function thin(opts) {
|
|
|
227
227
|
// re-attach a half-open journal.
|
|
228
228
|
["-wal", "-shm"].forEach(function (suffix) {
|
|
229
229
|
var sibling = file + suffix;
|
|
230
|
-
if (
|
|
231
|
-
try {
|
|
230
|
+
if (nodeFs.existsSync(sibling)) {
|
|
231
|
+
try { nodeFs.renameSync(sibling, sibling + ".corrupt-" + stamp); }
|
|
232
232
|
catch (_se) { /* best-effort */ }
|
|
233
233
|
}
|
|
234
234
|
});
|
package/lib/log-stream-local.js
CHANGED
|
@@ -23,8 +23,8 @@
|
|
|
23
23
|
* fileNamePrefix: 'blamejs'
|
|
24
24
|
* }
|
|
25
25
|
*/
|
|
26
|
-
var
|
|
27
|
-
var
|
|
26
|
+
var nodeFs = require("fs");
|
|
27
|
+
var nodePath = require("path");
|
|
28
28
|
var zlib = require("zlib");
|
|
29
29
|
var atomicFile = require("./atomic-file");
|
|
30
30
|
var C = require("./constants");
|
|
@@ -48,19 +48,19 @@ var _err = LogStreamError.factory;
|
|
|
48
48
|
function create(config) {
|
|
49
49
|
if (!config || !config.dir) throw new Error("log-stream local requires { dir }");
|
|
50
50
|
var cfg = Object.assign({}, DEFAULTS, config);
|
|
51
|
-
var dir =
|
|
52
|
-
if (!
|
|
51
|
+
var dir = nodePath.resolve(cfg.dir);
|
|
52
|
+
if (!nodeFs.existsSync(dir)) nodeFs.mkdirSync(dir, { recursive: true, mode: 0o700 });
|
|
53
53
|
|
|
54
|
-
var activePath =
|
|
54
|
+
var activePath = nodePath.join(dir, cfg.fileNamePrefix + ".log");
|
|
55
55
|
var fd = null;
|
|
56
56
|
var openedAt = 0;
|
|
57
57
|
var bytesWritten = 0;
|
|
58
58
|
|
|
59
59
|
function _open() {
|
|
60
|
-
fd =
|
|
60
|
+
fd = nodeFs.openSync(activePath, "a", cfg.fileMode);
|
|
61
61
|
openedAt = Date.now();
|
|
62
62
|
try {
|
|
63
|
-
var stat =
|
|
63
|
+
var stat = nodeFs.fstatSync(fd);
|
|
64
64
|
bytesWritten = stat.size;
|
|
65
65
|
} catch (_e) {
|
|
66
66
|
bytesWritten = 0;
|
|
@@ -77,20 +77,20 @@ function create(config) {
|
|
|
77
77
|
function _rotate() {
|
|
78
78
|
try {
|
|
79
79
|
if (fd != null) {
|
|
80
|
-
try {
|
|
80
|
+
try { nodeFs.closeSync(fd); }
|
|
81
81
|
catch (e) { log.warn("rotate-close-failed: " + e.message); }
|
|
82
82
|
fd = null;
|
|
83
83
|
}
|
|
84
84
|
// Build rotated filename: blamejs-YYYYMMDDTHHMMSSZ.log
|
|
85
85
|
var stamp = time.toIso8601NoMs(new Date()).replace(/[-:]/g, "");
|
|
86
|
-
var rotated =
|
|
87
|
-
if (
|
|
88
|
-
|
|
86
|
+
var rotated = nodePath.join(dir, cfg.fileNamePrefix + "-" + stamp + ".log");
|
|
87
|
+
if (nodeFs.existsSync(activePath)) {
|
|
88
|
+
nodeFs.renameSync(activePath, rotated);
|
|
89
89
|
if (cfg.compressRotations) {
|
|
90
|
-
var data =
|
|
90
|
+
var data = nodeFs.readFileSync(rotated);
|
|
91
91
|
var gz = zlib.gzipSync(data);
|
|
92
92
|
atomicFile.writeSync(rotated + ".gz", gz, { fileMode: cfg.fileMode });
|
|
93
|
-
|
|
93
|
+
nodeFs.unlinkSync(rotated);
|
|
94
94
|
}
|
|
95
95
|
}
|
|
96
96
|
_pruneOld();
|
|
@@ -109,7 +109,7 @@ function create(config) {
|
|
|
109
109
|
includeStat: true,
|
|
110
110
|
}).sort(function (a, b) { return b.mtimeMs - a.mtimeMs; }); // newest first
|
|
111
111
|
for (var i = cfg.keepRotations; i < entries.length; i++) {
|
|
112
|
-
try {
|
|
112
|
+
try { nodeFs.unlinkSync(entries[i].fullPath); } catch (_e) { /* best effort */ }
|
|
113
113
|
}
|
|
114
114
|
}
|
|
115
115
|
|
|
@@ -117,15 +117,15 @@ function create(config) {
|
|
|
117
117
|
if (_shouldRotate()) _rotate();
|
|
118
118
|
var line = JSON.stringify(record) + "\n";
|
|
119
119
|
var buf = Buffer.from(line, "utf8");
|
|
120
|
-
|
|
120
|
+
nodeFs.writeSync(fd, buf, 0, buf.length, null);
|
|
121
121
|
bytesWritten += buf.length;
|
|
122
122
|
return Promise.resolve({ bytes: buf.length });
|
|
123
123
|
}
|
|
124
124
|
|
|
125
125
|
function close() {
|
|
126
126
|
if (fd != null) {
|
|
127
|
-
try {
|
|
128
|
-
try {
|
|
127
|
+
try { nodeFs.fsyncSync(fd); } catch (_e) { /* best effort */ }
|
|
128
|
+
try { nodeFs.closeSync(fd); }
|
|
129
129
|
catch (e) { log.warn("close-failed: " + e.message); }
|
|
130
130
|
fd = null;
|
|
131
131
|
}
|
package/lib/log-stream-syslog.js
CHANGED
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
var dgram = require("dgram");
|
|
31
31
|
var net = require("net");
|
|
32
32
|
var os = require("os");
|
|
33
|
-
var
|
|
33
|
+
var nodeTls = require("tls");
|
|
34
34
|
var C = require("./constants");
|
|
35
35
|
var { boot } = require("./log");
|
|
36
36
|
var safeAsync = require("./safe-async");
|
|
@@ -223,7 +223,7 @@ function create(config) {
|
|
|
223
223
|
});
|
|
224
224
|
if (cfg.ca) tlsOpts.ca = cfg.ca;
|
|
225
225
|
if (cfg.servername) tlsOpts.servername = cfg.servername;
|
|
226
|
-
sock =
|
|
226
|
+
sock = nodeTls.connect(tlsOpts, onConnect);
|
|
227
227
|
} else {
|
|
228
228
|
sock = net.connect(connectOpts, onConnect);
|
|
229
229
|
}
|
package/lib/log-stream.js
CHANGED
|
@@ -55,7 +55,7 @@ var otlpGrpcProto = require("./log-stream-otlp-grpc");
|
|
|
55
55
|
var cloudwatchProto = require("./log-stream-cloudwatch");
|
|
56
56
|
var syslogProto = require("./log-stream-syslog");
|
|
57
57
|
var { boot } = require("./log");
|
|
58
|
-
var
|
|
58
|
+
var redact = require("./redact");
|
|
59
59
|
var lazyRequire = require("./lazy-require");
|
|
60
60
|
var protocolDispatcher = require("./protocol-dispatcher");
|
|
61
61
|
var { LogStreamError } = require("./framework-error");
|
|
@@ -215,7 +215,7 @@ function emit(level, message, meta) {
|
|
|
215
215
|
message: message == null ? null : String(message),
|
|
216
216
|
};
|
|
217
217
|
if (meta) {
|
|
218
|
-
record.meta =
|
|
218
|
+
record.meta = redact.redact(meta);
|
|
219
219
|
}
|
|
220
220
|
|
|
221
221
|
// Fire-and-forget to all sinks. Sink errors don't bubble — they're
|
|
@@ -367,7 +367,7 @@ function onIncoming(handler) {
|
|
|
367
367
|
*/
|
|
368
368
|
async function deliverIncoming(payload, opts) {
|
|
369
369
|
opts = opts || {};
|
|
370
|
-
var redacted =
|
|
370
|
+
var redacted = redact.redact(payload);
|
|
371
371
|
// Audit-log the inbound command BEFORE invoking handlers — even handler
|
|
372
372
|
// exceptions don't lose the receipt.
|
|
373
373
|
audit().safeEmit({
|
package/lib/mail-bounce.js
CHANGED
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
* Inbound mail bounce-handler — parse the vendor's webhook DSN / complaint / delivery payload, normalize it into one event shape, classify hard vs soft bounces, and feed an operator-supplied suppression-list hook.
|
|
40
40
|
*/
|
|
41
41
|
|
|
42
|
-
var
|
|
42
|
+
var bCrypto = require("./crypto");
|
|
43
43
|
var lazyRequire = require("./lazy-require");
|
|
44
44
|
var mimeParse = require("./mime-parse");
|
|
45
45
|
var numericBounds = require("./numeric-bounds");
|
|
@@ -817,7 +817,7 @@ function _foldFieldValue(name, value) {
|
|
|
817
817
|
}
|
|
818
818
|
|
|
819
819
|
function _generateBoundary() {
|
|
820
|
-
return "blamejs-dsn-" +
|
|
820
|
+
return "blamejs-dsn-" + bCrypto.generateToken(C.BYTES.bytes(12));
|
|
821
821
|
}
|
|
822
822
|
|
|
823
823
|
function _buildDsn(opts) {
|
package/lib/mail-mdn.js
CHANGED
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
* RFC 3798 / RFC 8098 Message Disposition Notification builder + parser — generate "message read" return-receipts and parse inbound MDNs into a normalized event shape. Auto-generation refuses without explicit operator opt-in to prevent accidental privacy leaks.
|
|
29
29
|
*/
|
|
30
30
|
|
|
31
|
-
var
|
|
31
|
+
var bCrypto = require("./crypto");
|
|
32
32
|
var lazyRequire = require("./lazy-require");
|
|
33
33
|
var mimeParse = require("./mime-parse");
|
|
34
34
|
var audit = lazyRequire(function () { return require("./audit"); });
|
|
@@ -99,7 +99,7 @@ function _parseDisposition(value) {
|
|
|
99
99
|
}
|
|
100
100
|
|
|
101
101
|
function _generateBoundary() {
|
|
102
|
-
return "blamejs-mdn-" +
|
|
102
|
+
return "blamejs-mdn-" + bCrypto.generateToken(C.BYTES.bytes(12));
|
|
103
103
|
}
|
|
104
104
|
|
|
105
105
|
/**
|
package/lib/mail-srs.js
CHANGED
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
*/
|
|
44
44
|
|
|
45
45
|
var nodeCrypto = require("node:crypto");
|
|
46
|
-
var
|
|
46
|
+
var bCrypto = require("./crypto");
|
|
47
47
|
var validateOpts = require("./validate-opts");
|
|
48
48
|
var { defineClass } = require("./framework-error");
|
|
49
49
|
|
|
@@ -239,7 +239,7 @@ function create(opts) {
|
|
|
239
239
|
|
|
240
240
|
function _timingSafeStringEqual(a, b) {
|
|
241
241
|
if (typeof a !== "string" || typeof b !== "string") return false;
|
|
242
|
-
return
|
|
242
|
+
return bCrypto.timingSafeEqual(Buffer.from(a, "utf8"), Buffer.from(b, "utf8"));
|
|
243
243
|
}
|
|
244
244
|
|
|
245
245
|
module.exports = {
|
package/lib/mail.js
CHANGED
|
@@ -56,7 +56,7 @@
|
|
|
56
56
|
* SMTP / HTTP-API email send with multipart RFC 5322 message composition, DKIM signing on the way out, and full inbound mail- authentication parsing on the way in.
|
|
57
57
|
*/
|
|
58
58
|
var C = require("./constants");
|
|
59
|
-
var
|
|
59
|
+
var bCrypto = require("./crypto");
|
|
60
60
|
var lazyRequire = require("./lazy-require");
|
|
61
61
|
var safeBuffer = require("./safe-buffer");
|
|
62
62
|
var audit = lazyRequire(function () { return require("./audit"); });
|
|
@@ -64,7 +64,7 @@ var httpClient = lazyRequire(function () { return require("./http-client"); });
|
|
|
64
64
|
var guardEmail = lazyRequire(function () { return require("./guard-email"); });
|
|
65
65
|
var guardFilename = lazyRequire(function () { return require("./guard-filename"); });
|
|
66
66
|
var fileType = lazyRequire(function () { return require("./file-type"); });
|
|
67
|
-
var
|
|
67
|
+
var dkim = require("./mail-dkim");
|
|
68
68
|
var mailAuth = require("./mail-auth");
|
|
69
69
|
var mailBimi = require("./mail-bimi");
|
|
70
70
|
var mailUnsubscribe = require("./mail-unsubscribe");
|
|
@@ -634,7 +634,7 @@ function _newBoundary(label) {
|
|
|
634
634
|
// convention. RFC 5322 only requires uniqueness within a message,
|
|
635
635
|
// but consistency with how every other identifier in lib/ is built
|
|
636
636
|
// wins over premature differentiation.
|
|
637
|
-
return "blamejs-" + label + "-" + Date.now() + "-" +
|
|
637
|
+
return "blamejs-" + label + "-" + Date.now() + "-" + bCrypto.generateToken(C.BYTES.bytes(8));
|
|
638
638
|
}
|
|
639
639
|
|
|
640
640
|
// base64-encode the buffer with line wrapping at 76 chars (RFC 2045
|
|
@@ -1841,7 +1841,7 @@ module.exports = {
|
|
|
1841
1841
|
// DKIM-Signature header generation for outbound mail (rsa-sha256
|
|
1842
1842
|
// default, ed25519-sha256 opt-in). Wire it into the smtp transport
|
|
1843
1843
|
// via opts.dkimSigner. See lib/mail-dkim.js for the full surface.
|
|
1844
|
-
dkim:
|
|
1844
|
+
dkim: dkim,
|
|
1845
1845
|
// Inbound mail authentication-results verification: SPF (RFC 7208),
|
|
1846
1846
|
// DMARC (RFC 7489), ARC (RFC 8617). Outbound DKIM signing lives in
|
|
1847
1847
|
// .dkim above; per-hop DKIM verification is deferred (composes with
|
package/lib/mcp.js
CHANGED
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
*/
|
|
32
32
|
|
|
33
33
|
var C = require("./constants");
|
|
34
|
-
var
|
|
34
|
+
var numericBounds = require("./numeric-bounds");
|
|
35
35
|
var safeUrl = require("./safe-url");
|
|
36
36
|
var safeJson = require("./safe-json");
|
|
37
37
|
var safeBuffer = require("./safe-buffer");
|
|
@@ -261,7 +261,7 @@ function serverGuard(opts) {
|
|
|
261
261
|
}
|
|
262
262
|
var toolAllowlist = Array.isArray(opts.toolAllowlist) ? opts.toolAllowlist : null;
|
|
263
263
|
var resourceAllowlist = Array.isArray(opts.resourceAllowlist) ? opts.resourceAllowlist : null;
|
|
264
|
-
|
|
264
|
+
numericBounds.requirePositiveFiniteIntIfPresent(opts.maxBodyBytes, "mcp.serverGuard: opts.maxBodyBytes", errorClass, "BAD_MAX_BYTES");
|
|
265
265
|
var maxBodyBytes = opts.maxBodyBytes || C.BYTES.mib(1);
|
|
266
266
|
var auditOn = opts.audit !== false;
|
|
267
267
|
|
package/lib/metrics.js
CHANGED
|
@@ -44,7 +44,7 @@ var atomicFile = require("./atomic-file");
|
|
|
44
44
|
var safeJson = require("./safe-json");
|
|
45
45
|
var { defineClass } = require("./framework-error");
|
|
46
46
|
var { boot } = require("./log");
|
|
47
|
-
var
|
|
47
|
+
var numericBounds = require("./numeric-bounds");
|
|
48
48
|
var { resolveRoute, captureResponseStatus, HTTP_STATUS } = require("./request-helpers");
|
|
49
49
|
var validateOpts = require("./validate-opts");
|
|
50
50
|
|
|
@@ -279,7 +279,7 @@ function create(opts) {
|
|
|
279
279
|
], "b.metrics");
|
|
280
280
|
var namespace = opts.namespace || "";
|
|
281
281
|
var defaultLabels = opts.defaultLabels || {};
|
|
282
|
-
|
|
282
|
+
numericBounds.requirePositiveFiniteIntIfPresent(opts.labelCardinalityCap,
|
|
283
283
|
"labelCardinalityCap", MetricsError, "metrics/bad-opt");
|
|
284
284
|
var cardinalityCap = opts.labelCardinalityCap || DEFAULT_CARDINALITY_CAP;
|
|
285
285
|
|