@blamejs/core 0.7.1 → 0.7.18
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 +423 -389
- package/README.md +150 -149
- package/bin/blamejs.js +0 -0
- package/index.js +308 -282
- package/lib/api-key.js +660 -672
- package/lib/api-snapshot.js +338 -338
- package/lib/app-shutdown.js +385 -385
- package/lib/app.js +365 -365
- package/lib/archive.js +250 -250
- package/lib/atomic-file.js +544 -544
- package/lib/audit-chain.js +177 -177
- package/lib/audit-sign.js +344 -344
- package/lib/audit-tools.js +677 -677
- package/lib/audit.js +766 -766
- package/lib/auth/jwt.js +311 -311
- package/lib/auth/lockout.js +436 -436
- package/lib/auth/oauth.js +721 -721
- package/lib/auth/passkey.js +181 -181
- package/lib/auth/password.js +594 -594
- package/lib/backup/bundle.js +217 -217
- package/lib/backup/crypto.js +176 -176
- package/lib/backup/index.js +515 -515
- package/lib/backup/manifest.js +282 -282
- package/lib/break-glass.js +1338 -1338
- package/lib/bundler.js +441 -441
- package/lib/cache-redis.js +256 -266
- package/lib/cache.js +1206 -1211
- package/lib/canonical-json.js +115 -115
- package/lib/chain-writer.js +234 -234
- package/lib/cli-helpers.js +206 -206
- package/lib/cli.js +2334 -2334
- package/lib/cluster-provider-db.js +317 -317
- package/lib/cluster-storage.js +226 -226
- package/lib/cluster.js +703 -703
- package/lib/codepoint-class.js +196 -0
- package/lib/config-drift.js +301 -301
- package/lib/consent.js +222 -222
- package/lib/constants.js +191 -191
- package/lib/cookies.js +315 -315
- package/lib/credential-hash.js +322 -322
- package/lib/crypto.js +266 -266
- package/lib/csv.js +275 -286
- package/lib/db-declare-row-policy.js +267 -267
- package/lib/db-declare-view.js +420 -421
- package/lib/db-query.js +406 -406
- package/lib/db-schema.js +319 -319
- package/lib/db.js +1288 -1288
- package/lib/deprecate.js +222 -222
- package/lib/dev.js +335 -335
- package/lib/dual-control.js +473 -473
- package/lib/error-page.js +420 -420
- package/lib/external-db-migrate.js +441 -441
- package/lib/external-db.js +1061 -1061
- package/lib/file-type.js +273 -273
- package/lib/file-upload.js +1136 -0
- package/lib/forms.js +422 -422
- package/lib/framework-error.js +293 -202
- package/lib/framework-schema.js +717 -717
- package/lib/gate-contract.js +971 -0
- package/lib/guard-all.js +405 -0
- package/lib/guard-archive.js +739 -0
- package/lib/guard-csv.js +816 -0
- package/lib/guard-email.js +744 -0
- package/lib/guard-filename.js +724 -0
- package/lib/guard-html.js +976 -0
- package/lib/guard-json.js +729 -0
- package/lib/guard-markdown.js +586 -0
- package/lib/guard-svg.js +976 -0
- package/lib/guard-xml.js +405 -0
- package/lib/guard-yaml.js +529 -0
- package/lib/handlers.js +350 -350
- package/lib/http-client-cookie-jar.js +508 -508
- package/lib/http-client.js +1195 -1195
- package/lib/i18n.js +878 -878
- package/lib/jobs.js +185 -185
- package/lib/log-stream-cloudwatch.js +369 -369
- package/lib/log-stream-local.js +146 -146
- package/lib/log-stream-otlp-grpc.js +410 -410
- package/lib/log-stream-otlp.js +286 -286
- package/lib/log-stream-syslog.js +302 -302
- package/lib/log-stream-webhook.js +199 -199
- package/lib/log-stream.js +330 -330
- package/lib/log.js +500 -500
- package/lib/mail-bounce.js +528 -528
- package/lib/mail-dkim.js +369 -362
- package/lib/mail.js +981 -962
- package/lib/metrics.js +683 -683
- package/lib/middleware/api-encrypt.js +936 -573
- package/lib/middleware/attach-user.js +157 -157
- package/lib/middleware/body-parser.js +1170 -1091
- package/lib/middleware/bot-guard.js +178 -178
- package/lib/middleware/compression.js +452 -452
- package/lib/middleware/cors.js +314 -314
- package/lib/middleware/csp-nonce.js +348 -348
- package/lib/middleware/csrf-protect.js +316 -316
- package/lib/middleware/db-role-for.js +264 -269
- package/lib/middleware/health.js +392 -392
- package/lib/middleware/index.js +79 -79
- package/lib/middleware/rate-limit.js +358 -358
- package/lib/middleware/request-id.js +61 -61
- package/lib/middleware/request-log.js +168 -168
- package/lib/middleware/require-auth.js +104 -104
- package/lib/middleware/security-headers.js +116 -116
- package/lib/middleware/sse.js +166 -166
- package/lib/migrations.js +383 -383
- package/lib/mtls-ca.js +518 -518
- package/lib/mtls-engine-default.js +481 -481
- package/lib/network-dns.js +632 -632
- package/lib/network-heartbeat.js +290 -290
- package/lib/network-nts.js +574 -574
- package/lib/network-proxy.js +265 -265
- package/lib/network-tls.js +328 -328
- package/lib/network.js +233 -233
- package/lib/notify.js +612 -614
- package/lib/ntp-check.js +229 -229
- package/lib/numeric-bounds.js +111 -91
- package/lib/object-store/azure-blob-bucket-ops.js +349 -349
- package/lib/object-store/azure-blob.js +488 -451
- package/lib/object-store/gcs-bucket-ops.js +351 -351
- package/lib/object-store/gcs.js +519 -479
- package/lib/object-store/http-put.js +153 -153
- package/lib/object-store/index.js +197 -197
- package/lib/object-store/sigv4-bucket-ops.js +1092 -1092
- package/lib/object-store/sigv4.js +903 -855
- package/lib/observability.js +151 -151
- package/lib/otel-export.js +269 -269
- package/lib/pagination.js +464 -464
- package/lib/parsers/index.js +80 -80
- package/lib/parsers/safe-env.js +642 -642
- package/lib/parsers/safe-ini.js +292 -292
- package/lib/parsers/safe-toml.js +784 -784
- package/lib/parsers/safe-xml.js +390 -390
- package/lib/parsers/safe-yaml.js +1015 -1015
- package/lib/permissions.js +708 -708
- package/lib/pqc-agent.js +87 -87
- package/lib/pqc-gate.js +279 -279
- package/lib/protobuf-encoder.js +190 -190
- package/lib/protocol-dispatcher.js +161 -161
- package/lib/pubsub-redis.js +167 -177
- package/lib/pubsub.js +429 -429
- package/lib/queue-local.js +476 -476
- package/lib/queue-redis.js +745 -752
- package/lib/queue-sqs.js +319 -319
- package/lib/queue.js +695 -695
- package/lib/redis-client.js +519 -489
- package/lib/request-helpers.js +340 -336
- package/lib/restore-bundle.js +237 -237
- package/lib/restore-rollback.js +259 -259
- package/lib/restore.js +409 -409
- package/lib/retry.js +376 -376
- package/lib/router.js +748 -748
- package/lib/safe-async.js +735 -735
- package/lib/safe-buffer.js +237 -237
- package/lib/safe-json.js +541 -541
- package/lib/safe-schema.js +1266 -1266
- package/lib/safe-url.js +159 -159
- package/lib/scheduler.js +706 -706
- package/lib/security-assert.js +373 -373
- package/lib/seeders.js +618 -630
- package/lib/session.js +478 -478
- package/lib/slug.js +269 -269
- package/lib/ssrf-guard.js +401 -401
- package/lib/static.js +879 -114
- package/lib/storage.js +471 -471
- package/lib/subject.js +281 -281
- package/lib/template.js +791 -791
- package/lib/testing.js +798 -798
- package/lib/time.js +310 -310
- package/lib/totp.js +302 -302
- package/lib/tracing.js +494 -494
- package/lib/uuid.js +132 -132
- package/lib/validate-opts.js +340 -270
- package/lib/vault/index.js +308 -308
- package/lib/vault/rotate.js +784 -784
- package/lib/vault/wrap.js +296 -296
- package/lib/vendor/noble-ciphers.cjs +9 -9
- package/lib/webhook.js +595 -598
- package/lib/websocket.js +1048 -1048
- package/package.json +77 -77
- package/sbom.cyclonedx.json +7 -7
package/lib/network.js
CHANGED
|
@@ -1,233 +1,233 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
var ntpCheck = require("./ntp-check");
|
|
4
|
-
var nts = require("./network-nts");
|
|
5
|
-
var dns = require("./network-dns");
|
|
6
|
-
var proxy = require("./network-proxy");
|
|
7
|
-
var trust = require("./network-tls");
|
|
8
|
-
var heartbeat = require("./network-heartbeat");
|
|
9
|
-
|
|
10
|
-
var validateOpts = require("./validate-opts");
|
|
11
|
-
var lazyRequire = require("./lazy-require");
|
|
12
|
-
var { defineClass } = require("./framework-error");
|
|
13
|
-
|
|
14
|
-
var NetworkError = defineClass("NetworkError", { alwaysPermanent: true });
|
|
15
|
-
|
|
16
|
-
var observability = lazyRequire(function () { return require("./observability"); });
|
|
17
|
-
var audit = lazyRequire(function () { return require("./audit"); });
|
|
18
|
-
|
|
19
|
-
var SOCKET_DEFAULTS = {
|
|
20
|
-
noDelay: true,
|
|
21
|
-
keepAlive: true,
|
|
22
|
-
keepAliveInitialDelayMs: 0,
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
function _setSocketNoDelay(value) {
|
|
26
|
-
if (typeof value !== "boolean") {
|
|
27
|
-
throw new NetworkError("socket/bad-no-delay", "socket.setDefaultNoDelay: expected boolean, got " + typeof value);
|
|
28
|
-
}
|
|
29
|
-
SOCKET_DEFAULTS.noDelay = value;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
function _setSocketKeepAlive(opts) {
|
|
33
|
-
opts = opts || {};
|
|
34
|
-
validateOpts(opts, ["enable", "initialDelayMs"], "socket.setDefaultKeepAlive");
|
|
35
|
-
if (opts.enable !== undefined) {
|
|
36
|
-
if (typeof opts.enable !== "boolean") {
|
|
37
|
-
throw new NetworkError("socket/bad-keepalive", "socket.setDefaultKeepAlive: enable must be boolean");
|
|
38
|
-
}
|
|
39
|
-
SOCKET_DEFAULTS.keepAlive = opts.enable;
|
|
40
|
-
}
|
|
41
|
-
if (opts.initialDelayMs !== undefined) {
|
|
42
|
-
if (typeof opts.initialDelayMs !== "number" || !isFinite(opts.initialDelayMs) || opts.initialDelayMs < 0) {
|
|
43
|
-
throw new NetworkError("socket/bad-keepalive-delay", "socket.setDefaultKeepAlive: initialDelayMs must be non-negative finite number");
|
|
44
|
-
}
|
|
45
|
-
SOCKET_DEFAULTS.keepAliveInitialDelayMs = opts.initialDelayMs;
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
// SO_LINGER is intentionally NOT exposed: Node's net.Socket has no
|
|
50
|
-
// public setLinger() method (the option is tracked at
|
|
51
|
-
// nodejs/node#27293 / rejected for the public surface). Reaching into
|
|
52
|
-
// socket._handle to call setLinger is an unstable internal API. The
|
|
53
|
-
// closest operator-exposed semantic is socket.destroy() (RST = "abort
|
|
54
|
-
// on close") vs socket.end() (graceful FIN). Operators needing true
|
|
55
|
-
// SO_LINGER should use a native binding outside the framework. This
|
|
56
|
-
// stub stays in the export with throw-on-call so a future Node release
|
|
57
|
-
// that exposes setLinger can be wired without an API addition.
|
|
58
|
-
function _setSocketLinger(_opts) {
|
|
59
|
-
throw new NetworkError("socket/linger-not-supported",
|
|
60
|
-
"socket.setDefaultLinger: SO_LINGER is not exposed by Node's public net.Socket API " +
|
|
61
|
-
"(see nodejs/node#27293). Use socket.destroy() (abort) vs socket.end() (graceful) " +
|
|
62
|
-
"to control close semantics, or a native binding if true SO_LINGER is required.");
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
function _socketDefaults() {
|
|
66
|
-
return {
|
|
67
|
-
noDelay: SOCKET_DEFAULTS.noDelay,
|
|
68
|
-
keepAlive: SOCKET_DEFAULTS.keepAlive,
|
|
69
|
-
keepAliveInitialDelayMs: SOCKET_DEFAULTS.keepAliveInitialDelayMs,
|
|
70
|
-
};
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
function applyToSocket(socket) {
|
|
74
|
-
if (!socket) return socket;
|
|
75
|
-
try {
|
|
76
|
-
if (typeof socket.setNoDelay === "function") socket.setNoDelay(SOCKET_DEFAULTS.noDelay);
|
|
77
|
-
if (typeof socket.setKeepAlive === "function") {
|
|
78
|
-
socket.setKeepAlive(SOCKET_DEFAULTS.keepAlive, SOCKET_DEFAULTS.keepAliveInitialDelayMs || 0);
|
|
79
|
-
}
|
|
80
|
-
} catch (_e) { /* best-effort socket-tuning — apply or skip */ }
|
|
81
|
-
return socket;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
var ntpFacade = {
|
|
85
|
-
querySingle: ntpCheck.querySingle,
|
|
86
|
-
checkDrift: ntpCheck.checkDrift,
|
|
87
|
-
bootCheck: ntpCheck.bootCheck,
|
|
88
|
-
setThresholds: ntpCheck.setThresholds,
|
|
89
|
-
getThresholds: ntpCheck.getThresholds,
|
|
90
|
-
setServers: function (list) {
|
|
91
|
-
if (!Array.isArray(list) || list.length === 0) {
|
|
92
|
-
throw new NetworkError("ntp/bad-servers", "ntp.setServers: expected non-empty array");
|
|
93
|
-
}
|
|
94
|
-
ntpFacade._defaultServers = list.slice();
|
|
95
|
-
_emitObs("network.ntp.servers.set", { count: list.length });
|
|
96
|
-
},
|
|
97
|
-
getServers: function () {
|
|
98
|
-
return (ntpFacade._defaultServers || ntpCheck.DEFAULT_SERVERS).slice();
|
|
99
|
-
},
|
|
100
|
-
_defaultServers: null,
|
|
101
|
-
nts: nts,
|
|
102
|
-
};
|
|
103
|
-
|
|
104
|
-
function bootFromEnv(opts) {
|
|
105
|
-
opts = opts || {};
|
|
106
|
-
validateOpts(opts, ["env", "audit"], "network.bootFromEnv");
|
|
107
|
-
var env = opts.env || process.env;
|
|
108
|
-
var applied = { ntp: {}, dns: {}, proxy: false, tls: {}, heartbeat: 0, socket: {} };
|
|
109
|
-
|
|
110
|
-
if (env.BLAMEJS_NTP_SERVERS) {
|
|
111
|
-
var list = String(env.BLAMEJS_NTP_SERVERS).split(",").map(function (s) { return s.trim(); }).filter(Boolean);
|
|
112
|
-
if (list.length > 0) { ntpFacade.setServers(list); applied.ntp.servers = list.length; }
|
|
113
|
-
}
|
|
114
|
-
var ntpTimeout = env.BLAMEJS_NTP_TIMEOUT_MS;
|
|
115
|
-
if (ntpTimeout) {
|
|
116
|
-
var t = parseInt(ntpTimeout, 10);
|
|
117
|
-
if (isFinite(t) && t > 0) { ntpFacade._defaultTimeoutMs = t; applied.ntp.timeoutMs = t; }
|
|
118
|
-
}
|
|
119
|
-
var ntpWarn = env.BLAMEJS_NTP_DRIFT_WARN_MS;
|
|
120
|
-
var ntpFatal = env.BLAMEJS_NTP_DRIFT_FATAL_MS;
|
|
121
|
-
if (ntpWarn || ntpFatal) {
|
|
122
|
-
var thr = {};
|
|
123
|
-
if (ntpWarn) { thr.warnMs = parseInt(ntpWarn, 10); applied.ntp.warnMs = thr.warnMs; }
|
|
124
|
-
if (ntpFatal) { thr.fatalMs = parseInt(ntpFatal, 10); applied.ntp.fatalMs = thr.fatalMs; }
|
|
125
|
-
ntpCheck.setThresholds(thr);
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
var dnsServers = env.BLAMEJS_DNS_SERVERS;
|
|
129
|
-
if (dnsServers) {
|
|
130
|
-
var dl = String(dnsServers).split(",").map(function (s) { return s.trim(); }).filter(Boolean);
|
|
131
|
-
if (dl.length > 0) { dns.setServers(dl); applied.dns.servers = dl.length; }
|
|
132
|
-
}
|
|
133
|
-
if (env.BLAMEJS_DNS_RESULT_ORDER) { dns.setResultOrder(env.BLAMEJS_DNS_RESULT_ORDER); applied.dns.resultOrder = env.BLAMEJS_DNS_RESULT_ORDER; }
|
|
134
|
-
if (env.BLAMEJS_DNS_FAMILY) { dns.setFamily(parseInt(env.BLAMEJS_DNS_FAMILY, 10)); applied.dns.family = parseInt(env.BLAMEJS_DNS_FAMILY, 10); }
|
|
135
|
-
if (env.BLAMEJS_DNS_LOOKUP_TIMEOUT_MS) { dns.setLookupTimeoutMs(parseInt(env.BLAMEJS_DNS_LOOKUP_TIMEOUT_MS, 10)); applied.dns.lookupTimeoutMs = parseInt(env.BLAMEJS_DNS_LOOKUP_TIMEOUT_MS, 10); }
|
|
136
|
-
if (env.BLAMEJS_DNS_CACHE_TTL_MS) { dns.setCacheTtlMs(parseInt(env.BLAMEJS_DNS_CACHE_TTL_MS, 10)); applied.dns.cacheTtlMs = parseInt(env.BLAMEJS_DNS_CACHE_TTL_MS, 10); }
|
|
137
|
-
if (env.BLAMEJS_DOH_URL) { dns.useDnsOverHttps({ url: env.BLAMEJS_DOH_URL }); applied.dns.doh = env.BLAMEJS_DOH_URL; }
|
|
138
|
-
else if (env.BLAMEJS_DOH_PROVIDER) { dns.useDnsOverHttps({ provider: env.BLAMEJS_DOH_PROVIDER }); applied.dns.dohProvider = env.BLAMEJS_DOH_PROVIDER; }
|
|
139
|
-
if (env.BLAMEJS_DOT_HOST) { dns.useDnsOverTls({ host: env.BLAMEJS_DOT_HOST, port: env.BLAMEJS_DOT_PORT ? parseInt(env.BLAMEJS_DOT_PORT, 10) : 853 }); applied.dns.dot = env.BLAMEJS_DOT_HOST; }
|
|
140
|
-
|
|
141
|
-
if (env.HTTP_PROXY || env.http_proxy || env.HTTPS_PROXY || env.https_proxy ||
|
|
142
|
-
env.NO_PROXY || env.no_proxy || env.ALL_PROXY || env.all_proxy) {
|
|
143
|
-
applied.proxy = proxy.fromEnv(env);
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
if (env.BLAMEJS_EXTRA_CA_CERTS) {
|
|
147
|
-
trust.addCa(env.BLAMEJS_EXTRA_CA_CERTS, { label: "BLAMEJS_EXTRA_CA_CERTS" });
|
|
148
|
-
applied.tls.fileLoaded = env.BLAMEJS_EXTRA_CA_CERTS;
|
|
149
|
-
}
|
|
150
|
-
if (env.BLAMEJS_EXTRA_CA_CERTS_DIR) {
|
|
151
|
-
trust.addCaBundle(env.BLAMEJS_EXTRA_CA_CERTS_DIR, { label: "BLAMEJS_EXTRA_CA_CERTS_DIR" });
|
|
152
|
-
applied.tls.dirLoaded = env.BLAMEJS_EXTRA_CA_CERTS_DIR;
|
|
153
|
-
}
|
|
154
|
-
if (env.BLAMEJS_USE_SYSTEM_TRUST === "1" || env.BLAMEJS_USE_SYSTEM_TRUST === "true") {
|
|
155
|
-
trust.useSystemTrust(true);
|
|
156
|
-
applied.tls.systemTrust = true;
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
if (env.BLAMEJS_SOCKET_NO_DELAY) _setSocketNoDelay(env.BLAMEJS_SOCKET_NO_DELAY === "1" || env.BLAMEJS_SOCKET_NO_DELAY === "true");
|
|
160
|
-
if (env.BLAMEJS_SOCKET_KEEPALIVE) _setSocketKeepAlive({ enable: env.BLAMEJS_SOCKET_KEEPALIVE === "1" || env.BLAMEJS_SOCKET_KEEPALIVE === "true" });
|
|
161
|
-
if (env.BLAMEJS_SOCKET_KEEPALIVE_DELAY_MS) _setSocketKeepAlive({ initialDelayMs: parseInt(env.BLAMEJS_SOCKET_KEEPALIVE_DELAY_MS, 10) });
|
|
162
|
-
applied.socket = _socketDefaults();
|
|
163
|
-
|
|
164
|
-
var auditOn = opts.audit !== false;
|
|
165
|
-
if (auditOn) {
|
|
166
|
-
var sink;
|
|
167
|
-
try { sink = audit(); } catch (_e) { sink = null; }
|
|
168
|
-
if (sink && typeof sink.safeEmit === "function") {
|
|
169
|
-
try {
|
|
170
|
-
sink.safeEmit({
|
|
171
|
-
action: "network.boot.from_env",
|
|
172
|
-
outcome: "success",
|
|
173
|
-
metadata: applied,
|
|
174
|
-
});
|
|
175
|
-
} catch (_e) { /* audit best-effort — never break boot */ }
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
_emitObs("network.boot.from_env", { source: "env" });
|
|
179
|
-
return applied;
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
function snapshot() {
|
|
183
|
-
return {
|
|
184
|
-
ntp: {
|
|
185
|
-
servers: ntpFacade.getServers(),
|
|
186
|
-
thresholds: ntpCheck.getThresholds(),
|
|
187
|
-
},
|
|
188
|
-
dns: dns._stateForTest(),
|
|
189
|
-
proxy: proxy.snapshot(),
|
|
190
|
-
tls: {
|
|
191
|
-
systemTrust: trust.isSystemTrustEnabled(),
|
|
192
|
-
caCount: trust.getTrustStore().length,
|
|
193
|
-
},
|
|
194
|
-
heartbeat: heartbeat.statuses(),
|
|
195
|
-
socket: _socketDefaults(),
|
|
196
|
-
};
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
function _emitObs(name, fields) {
|
|
200
|
-
try { observability().emit(name, fields || {}); } catch (_e) { /* obs best-effort */ }
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
function _resetForTest() {
|
|
204
|
-
ntpFacade._defaultServers = null;
|
|
205
|
-
ntpFacade._defaultTimeoutMs = null;
|
|
206
|
-
if (typeof ntpCheck._resetThresholdsForTest === "function") ntpCheck._resetThresholdsForTest();
|
|
207
|
-
dns._resetForTest();
|
|
208
|
-
proxy._resetForTest();
|
|
209
|
-
trust._resetForTest();
|
|
210
|
-
heartbeat._resetForTest();
|
|
211
|
-
SOCKET_DEFAULTS.noDelay = true;
|
|
212
|
-
SOCKET_DEFAULTS.keepAlive = true;
|
|
213
|
-
SOCKET_DEFAULTS.keepAliveInitialDelayMs = 0;
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
module.exports = {
|
|
217
|
-
ntp: ntpFacade,
|
|
218
|
-
dns: dns,
|
|
219
|
-
proxy: proxy,
|
|
220
|
-
tls: trust,
|
|
221
|
-
heartbeat: heartbeat,
|
|
222
|
-
socket: {
|
|
223
|
-
setDefaultNoDelay: _setSocketNoDelay,
|
|
224
|
-
setDefaultKeepAlive: _setSocketKeepAlive,
|
|
225
|
-
setDefaultLinger: _setSocketLinger,
|
|
226
|
-
defaults: _socketDefaults,
|
|
227
|
-
applyToSocket: applyToSocket,
|
|
228
|
-
},
|
|
229
|
-
bootFromEnv: bootFromEnv,
|
|
230
|
-
snapshot: snapshot,
|
|
231
|
-
NetworkError: NetworkError,
|
|
232
|
-
_resetForTest: _resetForTest,
|
|
233
|
-
};
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var ntpCheck = require("./ntp-check");
|
|
4
|
+
var nts = require("./network-nts");
|
|
5
|
+
var dns = require("./network-dns");
|
|
6
|
+
var proxy = require("./network-proxy");
|
|
7
|
+
var trust = require("./network-tls");
|
|
8
|
+
var heartbeat = require("./network-heartbeat");
|
|
9
|
+
|
|
10
|
+
var validateOpts = require("./validate-opts");
|
|
11
|
+
var lazyRequire = require("./lazy-require");
|
|
12
|
+
var { defineClass } = require("./framework-error");
|
|
13
|
+
|
|
14
|
+
var NetworkError = defineClass("NetworkError", { alwaysPermanent: true });
|
|
15
|
+
|
|
16
|
+
var observability = lazyRequire(function () { return require("./observability"); });
|
|
17
|
+
var audit = lazyRequire(function () { return require("./audit"); });
|
|
18
|
+
|
|
19
|
+
var SOCKET_DEFAULTS = {
|
|
20
|
+
noDelay: true,
|
|
21
|
+
keepAlive: true,
|
|
22
|
+
keepAliveInitialDelayMs: 0,
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
function _setSocketNoDelay(value) {
|
|
26
|
+
if (typeof value !== "boolean") {
|
|
27
|
+
throw new NetworkError("socket/bad-no-delay", "socket.setDefaultNoDelay: expected boolean, got " + typeof value);
|
|
28
|
+
}
|
|
29
|
+
SOCKET_DEFAULTS.noDelay = value;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function _setSocketKeepAlive(opts) {
|
|
33
|
+
opts = opts || {};
|
|
34
|
+
validateOpts(opts, ["enable", "initialDelayMs"], "socket.setDefaultKeepAlive");
|
|
35
|
+
if (opts.enable !== undefined) {
|
|
36
|
+
if (typeof opts.enable !== "boolean") {
|
|
37
|
+
throw new NetworkError("socket/bad-keepalive", "socket.setDefaultKeepAlive: enable must be boolean");
|
|
38
|
+
}
|
|
39
|
+
SOCKET_DEFAULTS.keepAlive = opts.enable;
|
|
40
|
+
}
|
|
41
|
+
if (opts.initialDelayMs !== undefined) {
|
|
42
|
+
if (typeof opts.initialDelayMs !== "number" || !isFinite(opts.initialDelayMs) || opts.initialDelayMs < 0) {
|
|
43
|
+
throw new NetworkError("socket/bad-keepalive-delay", "socket.setDefaultKeepAlive: initialDelayMs must be non-negative finite number");
|
|
44
|
+
}
|
|
45
|
+
SOCKET_DEFAULTS.keepAliveInitialDelayMs = opts.initialDelayMs;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// SO_LINGER is intentionally NOT exposed: Node's net.Socket has no
|
|
50
|
+
// public setLinger() method (the option is tracked at
|
|
51
|
+
// nodejs/node#27293 / rejected for the public surface). Reaching into
|
|
52
|
+
// socket._handle to call setLinger is an unstable internal API. The
|
|
53
|
+
// closest operator-exposed semantic is socket.destroy() (RST = "abort
|
|
54
|
+
// on close") vs socket.end() (graceful FIN). Operators needing true
|
|
55
|
+
// SO_LINGER should use a native binding outside the framework. This
|
|
56
|
+
// stub stays in the export with throw-on-call so a future Node release
|
|
57
|
+
// that exposes setLinger can be wired without an API addition.
|
|
58
|
+
function _setSocketLinger(_opts) {
|
|
59
|
+
throw new NetworkError("socket/linger-not-supported",
|
|
60
|
+
"socket.setDefaultLinger: SO_LINGER is not exposed by Node's public net.Socket API " +
|
|
61
|
+
"(see nodejs/node#27293). Use socket.destroy() (abort) vs socket.end() (graceful) " +
|
|
62
|
+
"to control close semantics, or a native binding if true SO_LINGER is required.");
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function _socketDefaults() {
|
|
66
|
+
return {
|
|
67
|
+
noDelay: SOCKET_DEFAULTS.noDelay,
|
|
68
|
+
keepAlive: SOCKET_DEFAULTS.keepAlive,
|
|
69
|
+
keepAliveInitialDelayMs: SOCKET_DEFAULTS.keepAliveInitialDelayMs,
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function applyToSocket(socket) {
|
|
74
|
+
if (!socket) return socket;
|
|
75
|
+
try {
|
|
76
|
+
if (typeof socket.setNoDelay === "function") socket.setNoDelay(SOCKET_DEFAULTS.noDelay);
|
|
77
|
+
if (typeof socket.setKeepAlive === "function") {
|
|
78
|
+
socket.setKeepAlive(SOCKET_DEFAULTS.keepAlive, SOCKET_DEFAULTS.keepAliveInitialDelayMs || 0);
|
|
79
|
+
}
|
|
80
|
+
} catch (_e) { /* best-effort socket-tuning — apply or skip */ }
|
|
81
|
+
return socket;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
var ntpFacade = {
|
|
85
|
+
querySingle: ntpCheck.querySingle,
|
|
86
|
+
checkDrift: ntpCheck.checkDrift,
|
|
87
|
+
bootCheck: ntpCheck.bootCheck,
|
|
88
|
+
setThresholds: ntpCheck.setThresholds,
|
|
89
|
+
getThresholds: ntpCheck.getThresholds,
|
|
90
|
+
setServers: function (list) {
|
|
91
|
+
if (!Array.isArray(list) || list.length === 0) {
|
|
92
|
+
throw new NetworkError("ntp/bad-servers", "ntp.setServers: expected non-empty array");
|
|
93
|
+
}
|
|
94
|
+
ntpFacade._defaultServers = list.slice();
|
|
95
|
+
_emitObs("network.ntp.servers.set", { count: list.length });
|
|
96
|
+
},
|
|
97
|
+
getServers: function () {
|
|
98
|
+
return (ntpFacade._defaultServers || ntpCheck.DEFAULT_SERVERS).slice();
|
|
99
|
+
},
|
|
100
|
+
_defaultServers: null,
|
|
101
|
+
nts: nts,
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
function bootFromEnv(opts) {
|
|
105
|
+
opts = opts || {};
|
|
106
|
+
validateOpts(opts, ["env", "audit"], "network.bootFromEnv");
|
|
107
|
+
var env = opts.env || process.env;
|
|
108
|
+
var applied = { ntp: {}, dns: {}, proxy: false, tls: {}, heartbeat: 0, socket: {} };
|
|
109
|
+
|
|
110
|
+
if (env.BLAMEJS_NTP_SERVERS) {
|
|
111
|
+
var list = String(env.BLAMEJS_NTP_SERVERS).split(",").map(function (s) { return s.trim(); }).filter(Boolean);
|
|
112
|
+
if (list.length > 0) { ntpFacade.setServers(list); applied.ntp.servers = list.length; }
|
|
113
|
+
}
|
|
114
|
+
var ntpTimeout = env.BLAMEJS_NTP_TIMEOUT_MS;
|
|
115
|
+
if (ntpTimeout) {
|
|
116
|
+
var t = parseInt(ntpTimeout, 10);
|
|
117
|
+
if (isFinite(t) && t > 0) { ntpFacade._defaultTimeoutMs = t; applied.ntp.timeoutMs = t; }
|
|
118
|
+
}
|
|
119
|
+
var ntpWarn = env.BLAMEJS_NTP_DRIFT_WARN_MS;
|
|
120
|
+
var ntpFatal = env.BLAMEJS_NTP_DRIFT_FATAL_MS;
|
|
121
|
+
if (ntpWarn || ntpFatal) {
|
|
122
|
+
var thr = {};
|
|
123
|
+
if (ntpWarn) { thr.warnMs = parseInt(ntpWarn, 10); applied.ntp.warnMs = thr.warnMs; }
|
|
124
|
+
if (ntpFatal) { thr.fatalMs = parseInt(ntpFatal, 10); applied.ntp.fatalMs = thr.fatalMs; }
|
|
125
|
+
ntpCheck.setThresholds(thr);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
var dnsServers = env.BLAMEJS_DNS_SERVERS;
|
|
129
|
+
if (dnsServers) {
|
|
130
|
+
var dl = String(dnsServers).split(",").map(function (s) { return s.trim(); }).filter(Boolean);
|
|
131
|
+
if (dl.length > 0) { dns.setServers(dl); applied.dns.servers = dl.length; }
|
|
132
|
+
}
|
|
133
|
+
if (env.BLAMEJS_DNS_RESULT_ORDER) { dns.setResultOrder(env.BLAMEJS_DNS_RESULT_ORDER); applied.dns.resultOrder = env.BLAMEJS_DNS_RESULT_ORDER; }
|
|
134
|
+
if (env.BLAMEJS_DNS_FAMILY) { dns.setFamily(parseInt(env.BLAMEJS_DNS_FAMILY, 10)); applied.dns.family = parseInt(env.BLAMEJS_DNS_FAMILY, 10); }
|
|
135
|
+
if (env.BLAMEJS_DNS_LOOKUP_TIMEOUT_MS) { dns.setLookupTimeoutMs(parseInt(env.BLAMEJS_DNS_LOOKUP_TIMEOUT_MS, 10)); applied.dns.lookupTimeoutMs = parseInt(env.BLAMEJS_DNS_LOOKUP_TIMEOUT_MS, 10); }
|
|
136
|
+
if (env.BLAMEJS_DNS_CACHE_TTL_MS) { dns.setCacheTtlMs(parseInt(env.BLAMEJS_DNS_CACHE_TTL_MS, 10)); applied.dns.cacheTtlMs = parseInt(env.BLAMEJS_DNS_CACHE_TTL_MS, 10); }
|
|
137
|
+
if (env.BLAMEJS_DOH_URL) { dns.useDnsOverHttps({ url: env.BLAMEJS_DOH_URL }); applied.dns.doh = env.BLAMEJS_DOH_URL; }
|
|
138
|
+
else if (env.BLAMEJS_DOH_PROVIDER) { dns.useDnsOverHttps({ provider: env.BLAMEJS_DOH_PROVIDER }); applied.dns.dohProvider = env.BLAMEJS_DOH_PROVIDER; }
|
|
139
|
+
if (env.BLAMEJS_DOT_HOST) { dns.useDnsOverTls({ host: env.BLAMEJS_DOT_HOST, port: env.BLAMEJS_DOT_PORT ? parseInt(env.BLAMEJS_DOT_PORT, 10) : 853 }); applied.dns.dot = env.BLAMEJS_DOT_HOST; }
|
|
140
|
+
|
|
141
|
+
if (env.HTTP_PROXY || env.http_proxy || env.HTTPS_PROXY || env.https_proxy ||
|
|
142
|
+
env.NO_PROXY || env.no_proxy || env.ALL_PROXY || env.all_proxy) {
|
|
143
|
+
applied.proxy = proxy.fromEnv(env);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
if (env.BLAMEJS_EXTRA_CA_CERTS) {
|
|
147
|
+
trust.addCa(env.BLAMEJS_EXTRA_CA_CERTS, { label: "BLAMEJS_EXTRA_CA_CERTS" });
|
|
148
|
+
applied.tls.fileLoaded = env.BLAMEJS_EXTRA_CA_CERTS;
|
|
149
|
+
}
|
|
150
|
+
if (env.BLAMEJS_EXTRA_CA_CERTS_DIR) {
|
|
151
|
+
trust.addCaBundle(env.BLAMEJS_EXTRA_CA_CERTS_DIR, { label: "BLAMEJS_EXTRA_CA_CERTS_DIR" });
|
|
152
|
+
applied.tls.dirLoaded = env.BLAMEJS_EXTRA_CA_CERTS_DIR;
|
|
153
|
+
}
|
|
154
|
+
if (env.BLAMEJS_USE_SYSTEM_TRUST === "1" || env.BLAMEJS_USE_SYSTEM_TRUST === "true") {
|
|
155
|
+
trust.useSystemTrust(true);
|
|
156
|
+
applied.tls.systemTrust = true;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
if (env.BLAMEJS_SOCKET_NO_DELAY) _setSocketNoDelay(env.BLAMEJS_SOCKET_NO_DELAY === "1" || env.BLAMEJS_SOCKET_NO_DELAY === "true");
|
|
160
|
+
if (env.BLAMEJS_SOCKET_KEEPALIVE) _setSocketKeepAlive({ enable: env.BLAMEJS_SOCKET_KEEPALIVE === "1" || env.BLAMEJS_SOCKET_KEEPALIVE === "true" });
|
|
161
|
+
if (env.BLAMEJS_SOCKET_KEEPALIVE_DELAY_MS) _setSocketKeepAlive({ initialDelayMs: parseInt(env.BLAMEJS_SOCKET_KEEPALIVE_DELAY_MS, 10) });
|
|
162
|
+
applied.socket = _socketDefaults();
|
|
163
|
+
|
|
164
|
+
var auditOn = opts.audit !== false;
|
|
165
|
+
if (auditOn) {
|
|
166
|
+
var sink;
|
|
167
|
+
try { sink = audit(); } catch (_e) { sink = null; }
|
|
168
|
+
if (sink && typeof sink.safeEmit === "function") {
|
|
169
|
+
try {
|
|
170
|
+
sink.safeEmit({
|
|
171
|
+
action: "network.boot.from_env",
|
|
172
|
+
outcome: "success",
|
|
173
|
+
metadata: applied,
|
|
174
|
+
});
|
|
175
|
+
} catch (_e) { /* audit best-effort — never break boot */ }
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
_emitObs("network.boot.from_env", { source: "env" });
|
|
179
|
+
return applied;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
function snapshot() {
|
|
183
|
+
return {
|
|
184
|
+
ntp: {
|
|
185
|
+
servers: ntpFacade.getServers(),
|
|
186
|
+
thresholds: ntpCheck.getThresholds(),
|
|
187
|
+
},
|
|
188
|
+
dns: dns._stateForTest(),
|
|
189
|
+
proxy: proxy.snapshot(),
|
|
190
|
+
tls: {
|
|
191
|
+
systemTrust: trust.isSystemTrustEnabled(),
|
|
192
|
+
caCount: trust.getTrustStore().length,
|
|
193
|
+
},
|
|
194
|
+
heartbeat: heartbeat.statuses(),
|
|
195
|
+
socket: _socketDefaults(),
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
function _emitObs(name, fields) {
|
|
200
|
+
try { observability().emit(name, fields || {}); } catch (_e) { /* obs best-effort */ }
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
function _resetForTest() {
|
|
204
|
+
ntpFacade._defaultServers = null;
|
|
205
|
+
ntpFacade._defaultTimeoutMs = null;
|
|
206
|
+
if (typeof ntpCheck._resetThresholdsForTest === "function") ntpCheck._resetThresholdsForTest();
|
|
207
|
+
dns._resetForTest();
|
|
208
|
+
proxy._resetForTest();
|
|
209
|
+
trust._resetForTest();
|
|
210
|
+
heartbeat._resetForTest();
|
|
211
|
+
SOCKET_DEFAULTS.noDelay = true;
|
|
212
|
+
SOCKET_DEFAULTS.keepAlive = true;
|
|
213
|
+
SOCKET_DEFAULTS.keepAliveInitialDelayMs = 0;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
module.exports = {
|
|
217
|
+
ntp: ntpFacade,
|
|
218
|
+
dns: dns,
|
|
219
|
+
proxy: proxy,
|
|
220
|
+
tls: trust,
|
|
221
|
+
heartbeat: heartbeat,
|
|
222
|
+
socket: {
|
|
223
|
+
setDefaultNoDelay: _setSocketNoDelay,
|
|
224
|
+
setDefaultKeepAlive: _setSocketKeepAlive,
|
|
225
|
+
setDefaultLinger: _setSocketLinger,
|
|
226
|
+
defaults: _socketDefaults,
|
|
227
|
+
applyToSocket: applyToSocket,
|
|
228
|
+
},
|
|
229
|
+
bootFromEnv: bootFromEnv,
|
|
230
|
+
snapshot: snapshot,
|
|
231
|
+
NetworkError: NetworkError,
|
|
232
|
+
_resetForTest: _resetForTest,
|
|
233
|
+
};
|