@blamejs/core 0.6.69 → 0.7.0
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 +6 -0
- package/README.md +11 -1
- package/index.js +2 -5
- package/lib/api-key.js +24 -55
- package/lib/api-snapshot.js +4 -1
- package/lib/app-shutdown.js +20 -16
- package/lib/app.js +6 -5
- package/lib/archive.js +58 -50
- package/lib/atomic-file.js +11 -5
- package/lib/audit-chain.js +12 -4
- package/lib/audit-sign.js +38 -13
- package/lib/audit-tools.js +4 -4
- package/lib/audit.js +8 -4
- package/lib/auth/jwt.js +3 -2
- package/lib/auth/lockout.js +3 -13
- package/lib/auth/oauth.js +27 -17
- package/lib/auth/passkey.js +1 -5
- package/lib/auth/password.js +23 -13
- package/lib/backup/bundle.js +2 -4
- package/lib/backup/crypto.js +8 -6
- package/lib/backup/index.js +18 -14
- package/lib/backup/manifest.js +6 -2
- package/lib/break-glass.js +12 -7
- package/lib/bundler.js +32 -21
- package/lib/cache-redis.js +8 -3
- package/lib/cache.js +39 -59
- package/lib/canonical-json.js +17 -2
- package/lib/chain-writer.js +2 -2
- package/lib/cli-helpers.js +9 -4
- package/lib/cli.js +27 -5
- package/lib/cluster-provider-db.js +2 -1
- package/lib/cluster-storage.js +71 -11
- package/lib/cluster.js +30 -25
- package/lib/config-drift.js +3 -4
- package/lib/constants.js +8 -3
- package/lib/cookies.js +16 -4
- package/lib/credential-hash.js +4 -7
- package/lib/crypto.js +9 -9
- package/lib/csv.js +11 -8
- package/lib/db-declare-row-policy.js +4 -9
- package/lib/db-declare-view.js +3 -6
- package/lib/db-query.js +9 -3
- package/lib/db-schema.js +75 -10
- package/lib/db.js +116 -70
- package/lib/deprecate.js +3 -8
- package/lib/dev.js +30 -19
- package/lib/dual-control.js +2 -4
- package/lib/error-page.js +32 -39
- package/lib/external-db-migrate.js +27 -20
- package/lib/external-db.js +11 -3
- package/lib/file-type.js +16 -8
- package/lib/forms.js +48 -12
- package/lib/framework-error.js +1 -2
- package/lib/{internal-sha1-hibp.js → framework-sha1-hibp.js} +1 -1
- package/lib/handlers.js +1 -1
- package/lib/http-client-cookie-jar.js +25 -18
- package/lib/http-client.js +46 -23
- package/lib/i18n.js +6 -16
- package/lib/jobs.js +5 -1
- package/lib/log-stream-cloudwatch.js +31 -30
- package/lib/log-stream-local.js +12 -3
- package/lib/log-stream-otlp-grpc.js +29 -23
- package/lib/log-stream-otlp.js +13 -19
- package/lib/log-stream-syslog.js +27 -22
- package/lib/log-stream-webhook.js +8 -17
- package/lib/log-stream.js +13 -2
- package/lib/log.js +83 -5
- package/lib/mail-bounce.js +22 -15
- package/lib/mail-dkim.js +3 -6
- package/lib/mail.js +62 -34
- package/lib/metrics.js +61 -25
- package/lib/middleware/api-encrypt.js +15 -13
- package/lib/middleware/body-parser.js +46 -39
- package/lib/middleware/bot-guard.js +25 -4
- package/lib/middleware/compression.js +26 -11
- package/lib/middleware/cors.js +6 -5
- package/lib/middleware/csp-nonce.js +17 -4
- package/lib/middleware/csrf-protect.js +1 -1
- package/lib/middleware/db-role-for.js +7 -30
- package/lib/middleware/health.js +42 -8
- package/lib/middleware/index.js +55 -36
- package/lib/middleware/rate-limit.js +11 -8
- package/lib/middleware/request-id.js +10 -2
- package/lib/middleware/request-log.js +3 -2
- package/lib/middleware/require-auth.js +5 -2
- package/lib/middleware/sse.js +5 -4
- package/lib/migration-files.js +37 -0
- package/lib/migrations.js +42 -17
- package/lib/mtls-ca.js +38 -17
- package/lib/mtls-engine-default.js +15 -7
- package/lib/network-dns.js +49 -20
- package/lib/network-heartbeat.js +7 -7
- package/lib/network-nts.js +70 -48
- package/lib/network-proxy.js +34 -15
- package/lib/network-tls.js +7 -5
- package/lib/network.js +3 -3
- package/lib/notify.js +14 -36
- package/lib/ntp-check.js +7 -6
- package/lib/numeric-bounds.js +35 -3
- package/lib/object-store/azure-blob-bucket-ops.js +73 -15
- package/lib/object-store/azure-blob.js +31 -24
- package/lib/object-store/gcs-bucket-ops.js +41 -17
- package/lib/object-store/gcs.js +41 -34
- package/lib/object-store/http-put.js +2 -11
- package/lib/object-store/http-request.js +38 -0
- package/lib/object-store/index.js +1 -1
- package/lib/object-store/sigv4-bucket-ops.js +33 -37
- package/lib/object-store/sigv4.js +50 -30
- package/lib/observability.js +14 -3
- package/lib/otel-export.js +16 -14
- package/lib/pagination.js +23 -8
- package/lib/parsers/index.js +11 -5
- package/lib/parsers/safe-env.js +43 -14
- package/lib/parsers/safe-ini.js +29 -10
- package/lib/parsers/safe-toml.js +55 -25
- package/lib/parsers/safe-xml.js +22 -11
- package/lib/parsers/safe-yaml.js +55 -17
- package/lib/permissions.js +24 -33
- package/lib/pqc-agent.js +4 -2
- package/lib/pqc-gate.js +28 -15
- package/lib/protobuf-encoder.js +9 -3
- package/lib/protocol-dispatcher.js +29 -12
- package/lib/pubsub-redis.js +25 -8
- package/lib/pubsub.js +84 -12
- package/lib/queue-local.js +13 -4
- package/lib/queue-redis.js +2 -2
- package/lib/queue-sqs.js +21 -16
- package/lib/queue.js +8 -4
- package/lib/redis-client.js +13 -10
- package/lib/request-helpers.js +33 -2
- package/lib/restore-bundle.js +2 -4
- package/lib/restore-rollback.js +4 -1
- package/lib/restore.js +12 -10
- package/lib/retry.js +58 -9
- package/lib/router.js +96 -27
- package/lib/safe-async.js +97 -4
- package/lib/safe-buffer.js +47 -0
- package/lib/safe-json.js +18 -9
- package/lib/safe-schema.js +54 -18
- package/lib/safe-url.js +6 -2
- package/lib/scheduler.js +25 -14
- package/lib/security-assert.js +31 -26
- package/lib/seeders.js +71 -60
- package/lib/session.js +13 -7
- package/lib/slug.js +35 -8
- package/lib/ssrf-guard.js +58 -43
- package/lib/static.js +11 -7
- package/lib/storage.js +2 -1
- package/lib/template.js +17 -7
- package/lib/testing.js +28 -8
- package/lib/time.js +26 -5
- package/lib/totp.js +18 -9
- package/lib/tracing.js +15 -5
- package/lib/uuid.js +47 -20
- package/lib/validate-opts.js +213 -0
- package/lib/vault/index.js +36 -27
- package/lib/vault/rotate.js +41 -22
- package/lib/vault/wrap.js +26 -19
- package/lib/webhook.js +37 -68
- package/lib/websocket.js +60 -46
- package/package.json +1 -1
- package/sbom.cyclonedx.json +6 -6
- package/lib/auth/totp.js +0 -17
- package/lib/object-store/retry.js +0 -15
package/lib/vault/wrap.js
CHANGED
|
@@ -26,6 +26,7 @@
|
|
|
26
26
|
* wrap() and unwrap() are async because Argon2 is async via its native binding.
|
|
27
27
|
*/
|
|
28
28
|
var argon2 = require("../vendor/argon2");
|
|
29
|
+
var C = require("../constants");
|
|
29
30
|
var { xchacha20poly1305 } = require("../vendor/noble-ciphers.cjs");
|
|
30
31
|
var { generateBytes } = require("../crypto");
|
|
31
32
|
var safeBuffer = require("../safe-buffer");
|
|
@@ -35,28 +36,34 @@ var MAGIC = 0xE2;
|
|
|
35
36
|
var FORMAT_VERSION = 0x01;
|
|
36
37
|
var KDF_ARGON2ID = 0x01;
|
|
37
38
|
var CIPHER_XCHACHA20_POLY = 0x02;
|
|
38
|
-
var NONCE_LENGTH = 24;
|
|
39
|
+
var NONCE_LENGTH = C.BYTES.bytes(24);
|
|
39
40
|
|
|
40
41
|
// ---- Default Argon2id parameters ----
|
|
41
42
|
// 64 MiB / t=3 / p=4 targets ~1s derivation on commodity 2026 hardware —
|
|
42
43
|
// painful for offline brute force, tolerable for an operator-initiated boot.
|
|
44
|
+
// memoryCost is denominated in KiB per RFC 9106 §3.1, so the 64 MiB target
|
|
45
|
+
// expresses as MiB→KiB through the framework's byte helpers.
|
|
43
46
|
var DEFAULT_ARGON2 = Object.freeze({
|
|
44
|
-
memoryCost:
|
|
47
|
+
memoryCost: C.BYTES.mib(64) / C.BYTES.kib(1),
|
|
45
48
|
timeCost: 3,
|
|
46
49
|
parallelism: 4,
|
|
47
|
-
saltLength: 16,
|
|
48
|
-
hashLength: 32,
|
|
50
|
+
saltLength: C.BYTES.bytes(16),
|
|
51
|
+
hashLength: C.BYTES.bytes(32),
|
|
49
52
|
});
|
|
50
53
|
|
|
51
54
|
// ---- Hard bounds — reject malformed or adversarial headers ----
|
|
52
|
-
var MIN_SALT_LENGTH = 8;
|
|
53
|
-
var MAX_SALT_LENGTH = 64;
|
|
54
|
-
var MAX_PASSPHRASE_LENGTH =
|
|
55
|
-
// argon2 memoryCost is in KiB
|
|
56
|
-
|
|
57
|
-
|
|
55
|
+
var MIN_SALT_LENGTH = C.BYTES.bytes(8);
|
|
56
|
+
var MAX_SALT_LENGTH = C.BYTES.bytes(64);
|
|
57
|
+
var MAX_PASSPHRASE_LENGTH = C.BYTES.kib(4);
|
|
58
|
+
// argon2 memoryCost is denominated in KiB per RFC 9106 §3.1, not bytes.
|
|
59
|
+
// Express the bound as a byte-quantity divided by KiB so the framework's
|
|
60
|
+
// C.BYTES helpers stay the single source of truth for the underlying scale.
|
|
61
|
+
var MIN_ARGON2_MEMORY = C.BYTES.mib(1) / C.BYTES.kib(1); // 1 MiB-in-KiB
|
|
62
|
+
var MAX_ARGON2_MEMORY = C.BYTES.gib(4) / C.BYTES.kib(1); // 4 GiB-in-KiB
|
|
58
63
|
var MAX_ARGON2_TIME = 100;
|
|
59
|
-
|
|
64
|
+
// Argon2 lane count cap. Hex form because the literal isn't a byte
|
|
65
|
+
// quantity — using C.BYTES.* would mis-name the unit at the call site.
|
|
66
|
+
var MAX_ARGON2_PARALLELISM = 0x20;
|
|
60
67
|
|
|
61
68
|
function buildHeader(params) {
|
|
62
69
|
var salt = params.salt;
|
|
@@ -81,7 +88,7 @@ function buildHeader(params) {
|
|
|
81
88
|
h[2] = KDF_ARGON2ID;
|
|
82
89
|
h[3] = 0x00;
|
|
83
90
|
h.writeUInt32BE(params.memoryCost >>> 0, 4);
|
|
84
|
-
h.writeUInt16BE(params.timeCost & 0xffff, 8);
|
|
91
|
+
h.writeUInt16BE(params.timeCost & 0xffff, C.BYTES.bytes(8));
|
|
85
92
|
h[10] = params.parallelism & 0xff;
|
|
86
93
|
h[11] = saltLen;
|
|
87
94
|
Buffer.from(salt).copy(h, 12);
|
|
@@ -98,8 +105,8 @@ function parseHeader(buf) {
|
|
|
98
105
|
if (!Buffer.isBuffer(buf)) buf = Buffer.from(buf);
|
|
99
106
|
if (buf.length < 12) throw new Error("wrapped vault file too short (< 12 bytes)");
|
|
100
107
|
if (buf[0] !== MAGIC) {
|
|
101
|
-
throw new Error("not a wrapped vault file (magic byte 0x" + buf[0].toString(
|
|
102
|
-
" != 0x" + MAGIC.toString(
|
|
108
|
+
throw new Error("not a wrapped vault file (magic byte 0x" + buf[0].toString(0x10) +
|
|
109
|
+
" != 0x" + MAGIC.toString(0x10) + ")");
|
|
103
110
|
}
|
|
104
111
|
if (buf[1] !== FORMAT_VERSION) {
|
|
105
112
|
throw new Error("unsupported wrapped-vault format version " + buf[1] + " — upgrade blamejs");
|
|
@@ -110,7 +117,7 @@ function parseHeader(buf) {
|
|
|
110
117
|
// byte 3 reserved
|
|
111
118
|
|
|
112
119
|
var memoryCost = buf.readUInt32BE(4);
|
|
113
|
-
var timeCost = buf.readUInt16BE(8);
|
|
120
|
+
var timeCost = buf.readUInt16BE(C.BYTES.bytes(8));
|
|
114
121
|
var parallelism = buf[10];
|
|
115
122
|
var saltLen = buf[11];
|
|
116
123
|
|
|
@@ -146,7 +153,7 @@ function parseHeader(buf) {
|
|
|
146
153
|
var ciphertextLength = buf.readUInt32BE(ctLenPos);
|
|
147
154
|
var headerEnd = ctLenPos + 4;
|
|
148
155
|
|
|
149
|
-
if (ciphertextLength < 16) {
|
|
156
|
+
if (ciphertextLength < C.BYTES.bytes(16)) {
|
|
150
157
|
throw new Error("ciphertext length too short (< Poly1305 tag): " + ciphertextLength);
|
|
151
158
|
}
|
|
152
159
|
if (buf.length < headerEnd + ciphertextLength) {
|
|
@@ -191,13 +198,13 @@ async function deriveWrappingKey(passphrase, salt, argonParams) {
|
|
|
191
198
|
memoryCost: argonParams.memoryCost || DEFAULT_ARGON2.memoryCost,
|
|
192
199
|
timeCost: argonParams.timeCost || DEFAULT_ARGON2.timeCost,
|
|
193
200
|
parallelism: argonParams.parallelism || DEFAULT_ARGON2.parallelism,
|
|
194
|
-
hashLength: 32,
|
|
201
|
+
hashLength: C.BYTES.bytes(32),
|
|
195
202
|
raw: true,
|
|
196
203
|
});
|
|
197
204
|
} finally {
|
|
198
205
|
if (weOwnPwBuf) safeBuffer.secureZero(pwBuf);
|
|
199
206
|
}
|
|
200
|
-
if (!raw || raw.length !== 32) {
|
|
207
|
+
if (!raw || raw.length !== C.BYTES.bytes(32)) {
|
|
201
208
|
safeBuffer.secureZero(raw);
|
|
202
209
|
throw new Error("Argon2 returned unexpected hash length: " + (raw && raw.length));
|
|
203
210
|
}
|
|
@@ -230,7 +237,7 @@ async function wrap(plaintext, passphrase, opts) {
|
|
|
230
237
|
});
|
|
231
238
|
|
|
232
239
|
try {
|
|
233
|
-
var ciphertextLength = plaintextBuf.length + 16;
|
|
240
|
+
var ciphertextLength = plaintextBuf.length + C.BYTES.bytes(16);
|
|
234
241
|
var header = buildHeader({
|
|
235
242
|
memoryCost: memoryCost,
|
|
236
243
|
timeCost: timeCost,
|
package/lib/webhook.js
CHANGED
|
@@ -68,20 +68,19 @@
|
|
|
68
68
|
|
|
69
69
|
var crypto = require("./crypto");
|
|
70
70
|
var httpClient = require("./http-client");
|
|
71
|
+
var safeBuffer = require("./safe-buffer");
|
|
71
72
|
var safeUrl = require("./safe-url");
|
|
72
73
|
var retry = require("./retry");
|
|
73
74
|
var C = require("./constants");
|
|
74
75
|
var lazyRequire = require("./lazy-require");
|
|
75
76
|
var numericChecks = require("./numeric-checks");
|
|
76
77
|
var requestHelpers = require("./request-helpers");
|
|
78
|
+
var validateOpts = require("./validate-opts");
|
|
77
79
|
var { WebhookError } = require("./framework-error");
|
|
78
80
|
|
|
79
81
|
var observability = lazyRequire(function () { return require("./observability"); });
|
|
80
82
|
|
|
81
|
-
function _emitEvent(
|
|
82
|
-
try { observability().event(name, value, labels || {}); }
|
|
83
|
-
catch (_e) { /* hot-path observability sink — drops silent on internal throws */ }
|
|
84
|
-
}
|
|
83
|
+
function _emitEvent(n, v, l) { observability().safeEvent(n, v, l || {}); }
|
|
85
84
|
|
|
86
85
|
var _err = WebhookError.factory;
|
|
87
86
|
|
|
@@ -194,7 +193,7 @@ function _hmacSign(key, data) {
|
|
|
194
193
|
}
|
|
195
194
|
|
|
196
195
|
function _hmacVerify(key, data, expectedHex) {
|
|
197
|
-
if (
|
|
196
|
+
if (!safeBuffer.isHex(expectedHex)) return false;
|
|
198
197
|
var actualHex = crypto.hmacSha3(key, data);
|
|
199
198
|
return crypto.timingSafeEqual(actualHex, expectedHex);
|
|
200
199
|
}
|
|
@@ -204,8 +203,7 @@ function _pqcSign(privateKeyPem, data) {
|
|
|
204
203
|
}
|
|
205
204
|
|
|
206
205
|
function _pqcVerify(publicKeyPem, data, expectedHex) {
|
|
207
|
-
if (
|
|
208
|
-
!/^[0-9a-fA-F]+$/.test(expectedHex) || (expectedHex.length % 2) !== 0) {
|
|
206
|
+
if (!safeBuffer.isHex(expectedHex) || (expectedHex.length % 2) !== 0) {
|
|
209
207
|
return false;
|
|
210
208
|
}
|
|
211
209
|
var sigBuf;
|
|
@@ -240,9 +238,7 @@ function _parseSignatureHeader(headerValue) {
|
|
|
240
238
|
// ---- Signer ----
|
|
241
239
|
|
|
242
240
|
function _validateSignerOpts(opts) {
|
|
243
|
-
|
|
244
|
-
throw _err("BAD_OPT", "webhook.signer: opts must be an object");
|
|
245
|
-
}
|
|
241
|
+
validateOpts.requireObject(opts, "webhook.signer", WebhookError);
|
|
246
242
|
_validateAlgo(opts.algo);
|
|
247
243
|
_validateKeysShape("webhook.signer", opts.algo, opts.keys, "signer");
|
|
248
244
|
var kids = _objectKeys(opts.keys);
|
|
@@ -255,43 +251,29 @@ function _validateSignerOpts(opts) {
|
|
|
255
251
|
throw _err("BAD_OPT", "webhook.signer: defaultKid required when keys has " +
|
|
256
252
|
kids.length + " entries");
|
|
257
253
|
}
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
if (opts.idGenerator !== undefined && typeof opts.idGenerator !== "function") {
|
|
263
|
-
throw _err("BAD_OPT", "webhook.signer: idGenerator must be a function or undefined");
|
|
264
|
-
}
|
|
265
|
-
if (opts.now !== undefined && typeof opts.now !== "function") {
|
|
266
|
-
throw _err("BAD_OPT", "webhook.signer: now must be a function or undefined");
|
|
267
|
-
}
|
|
268
|
-
if (opts.audit !== undefined && opts.audit !== null) {
|
|
269
|
-
if (typeof opts.audit !== "object" || typeof opts.audit.safeEmit !== "function") {
|
|
270
|
-
throw _err("BAD_OPT", "webhook.signer: audit must be a b.audit-shaped object (safeEmit fn)");
|
|
271
|
-
}
|
|
272
|
-
}
|
|
254
|
+
validateOpts.optionalNonEmptyString(opts.signatureHeader, "webhook.signer: signatureHeader", WebhookError);
|
|
255
|
+
validateOpts.optionalFunction(opts.idGenerator, "webhook.signer: idGenerator", WebhookError);
|
|
256
|
+
validateOpts.optionalFunction(opts.now, "webhook.signer: now", WebhookError);
|
|
257
|
+
validateOpts.auditShape(opts.audit, "webhook.signer", WebhookError);
|
|
273
258
|
}
|
|
274
259
|
|
|
275
260
|
function signer(opts) {
|
|
276
261
|
_validateSignerOpts(opts);
|
|
277
262
|
var algo = opts.algo;
|
|
263
|
+
var cfg = validateOpts.applyDefaults(opts, DEFAULTS);
|
|
278
264
|
var keys = opts.keys;
|
|
279
265
|
var kids = _objectKeys(keys);
|
|
280
266
|
var defaultKid = opts.defaultKid || kids[0];
|
|
281
|
-
var sigHeader =
|
|
282
|
-
var idGen = opts.idGenerator || function () { return crypto.generateToken(16); };
|
|
267
|
+
var sigHeader = cfg.signatureHeader;
|
|
268
|
+
var idGen = opts.idGenerator || function () { return crypto.generateToken(C.BYTES.bytes(16)); };
|
|
283
269
|
var nowFn = opts.now || function () { return Date.now(); };
|
|
284
270
|
var retryOpts = opts.retry || retry.DEFAULT_RETRY;
|
|
285
271
|
var httpOpts = opts.http || {};
|
|
286
272
|
var audit = opts.audit || null;
|
|
287
|
-
var auditFailures =
|
|
288
|
-
var auditSuccess =
|
|
273
|
+
var auditFailures = cfg.auditFailures;
|
|
274
|
+
var auditSuccess = cfg.auditSuccess;
|
|
289
275
|
|
|
290
|
-
|
|
291
|
-
if (!audit) return;
|
|
292
|
-
try { audit.safeEmit(Object.assign({ action: action }, info || {})); }
|
|
293
|
-
catch (_e) { /* audit best-effort */ }
|
|
294
|
-
}
|
|
276
|
+
var _auditEmit = validateOpts.makeAuditEmitter(audit);
|
|
295
277
|
|
|
296
278
|
function _signOne(body, kid) {
|
|
297
279
|
_validateBody(body);
|
|
@@ -299,7 +281,7 @@ function signer(opts) {
|
|
|
299
281
|
if (keyForKid == null) {
|
|
300
282
|
throw _err("BAD_OPT", "webhook.signer: unknown kid '" + kid + "'");
|
|
301
283
|
}
|
|
302
|
-
var timestamp = Math.floor(nowFn() /
|
|
284
|
+
var timestamp = Math.floor(nowFn() / C.TIME.seconds(1));
|
|
303
285
|
var id = idGen();
|
|
304
286
|
if (typeof id !== "string" || id.length === 0 || /[,=\s]/.test(id)) {
|
|
305
287
|
throw _err("BAD_OPT", "webhook.signer: idGenerator must return a non-empty string with no comma/equals/whitespace, got " + JSON.stringify(id));
|
|
@@ -364,7 +346,12 @@ function signer(opts) {
|
|
|
364
346
|
requestOpts.body = body;
|
|
365
347
|
requestOpts.method = "POST";
|
|
366
348
|
var hostLabel = "";
|
|
367
|
-
try {
|
|
349
|
+
try {
|
|
350
|
+
hostLabel = safeUrl.parse(url, {
|
|
351
|
+
allowedProtocols: httpOpts.allowedProtocols || safeUrl.ALLOW_HTTP_TLS,
|
|
352
|
+
errorClass: WebhookError,
|
|
353
|
+
}).host;
|
|
354
|
+
} catch (_e) { hostLabel = ""; }
|
|
368
355
|
try {
|
|
369
356
|
var res = await retry.withRetry(function () {
|
|
370
357
|
return httpClient.request(requestOpts);
|
|
@@ -415,55 +402,37 @@ function signer(opts) {
|
|
|
415
402
|
// ---- Verifier ----
|
|
416
403
|
|
|
417
404
|
function _validateVerifierOpts(opts) {
|
|
418
|
-
|
|
419
|
-
throw _err("BAD_OPT", "webhook.verifier: opts must be an object");
|
|
420
|
-
}
|
|
405
|
+
validateOpts.requireObject(opts, "webhook.verifier", WebhookError);
|
|
421
406
|
_validateAlgo(opts.algo);
|
|
422
407
|
_validateKeysShape("webhook.verifier", opts.algo, opts.keys, "verifier");
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
if (opts.clockSkewMs !== undefined && !_isNonNegFinite(opts.clockSkewMs)) {
|
|
427
|
-
throw _err("BAD_OPT", "webhook.verifier: clockSkewMs must be a non-negative finite number");
|
|
428
|
-
}
|
|
429
|
-
if (opts.signatureHeader !== undefined &&
|
|
430
|
-
(typeof opts.signatureHeader !== "string" || opts.signatureHeader.length === 0)) {
|
|
431
|
-
throw _err("BAD_OPT", "webhook.verifier: signatureHeader must be a non-empty string");
|
|
432
|
-
}
|
|
408
|
+
validateOpts.optionalFiniteNonNegative(opts.toleranceMs, "webhook.verifier: toleranceMs", WebhookError);
|
|
409
|
+
validateOpts.optionalFiniteNonNegative(opts.clockSkewMs, "webhook.verifier: clockSkewMs", WebhookError);
|
|
410
|
+
validateOpts.optionalNonEmptyString(opts.signatureHeader, "webhook.verifier: signatureHeader", WebhookError);
|
|
433
411
|
if (opts.nonceStore !== undefined && opts.nonceStore !== null) {
|
|
434
412
|
if (typeof opts.nonceStore !== "object" ||
|
|
435
413
|
typeof opts.nonceStore.checkAndInsert !== "function") {
|
|
436
414
|
throw _err("BAD_OPT", "webhook.verifier: nonceStore must implement checkAndInsert(nonce, expireAt)");
|
|
437
415
|
}
|
|
438
416
|
}
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
if (typeof opts.audit !== "object" || typeof opts.audit.safeEmit !== "function") {
|
|
444
|
-
throw _err("BAD_OPT", "webhook.verifier: audit must be a b.audit-shaped object (safeEmit fn)");
|
|
445
|
-
}
|
|
446
|
-
}
|
|
447
|
-
if (opts.auditFailures !== undefined && typeof opts.auditFailures !== "boolean") {
|
|
448
|
-
throw _err("BAD_OPT", "webhook.verifier: auditFailures must be a boolean");
|
|
449
|
-
}
|
|
450
|
-
if (opts.auditSuccess !== undefined && typeof opts.auditSuccess !== "boolean") {
|
|
451
|
-
throw _err("BAD_OPT", "webhook.verifier: auditSuccess must be a boolean");
|
|
452
|
-
}
|
|
417
|
+
validateOpts.optionalFunction(opts.now, "webhook.verifier: now", WebhookError);
|
|
418
|
+
validateOpts.auditShape(opts.audit, "webhook.verifier", WebhookError);
|
|
419
|
+
validateOpts.optionalBoolean(opts.auditFailures, "webhook.verifier: auditFailures", WebhookError);
|
|
420
|
+
validateOpts.optionalBoolean(opts.auditSuccess, "webhook.verifier: auditSuccess", WebhookError);
|
|
453
421
|
}
|
|
454
422
|
|
|
455
423
|
function verifier(opts) {
|
|
456
424
|
_validateVerifierOpts(opts);
|
|
425
|
+
var cfg = validateOpts.applyDefaults(opts, DEFAULTS);
|
|
457
426
|
var algo = opts.algo;
|
|
458
427
|
var keys = opts.keys;
|
|
459
|
-
var toleranceMs =
|
|
460
|
-
var clockSkewMs =
|
|
461
|
-
var sigHeader =
|
|
428
|
+
var toleranceMs = cfg.toleranceMs;
|
|
429
|
+
var clockSkewMs = cfg.clockSkewMs;
|
|
430
|
+
var sigHeader = cfg.signatureHeader.toLowerCase();
|
|
462
431
|
var nonceStore = opts.nonceStore || null;
|
|
463
432
|
var nowFn = opts.now || function () { return Date.now(); };
|
|
464
433
|
var audit = opts.audit || null;
|
|
465
|
-
var auditFailures =
|
|
466
|
-
var auditSuccess =
|
|
434
|
+
var auditFailures = cfg.auditFailures;
|
|
435
|
+
var auditSuccess = cfg.auditSuccess;
|
|
467
436
|
|
|
468
437
|
function _auditEmit(outcome, reason, info, req) {
|
|
469
438
|
if (!audit) return;
|
package/lib/websocket.js
CHANGED
|
@@ -91,6 +91,7 @@ var safeBuffer = require("./safe-buffer");
|
|
|
91
91
|
var { FrameworkError } = require("./framework-error");
|
|
92
92
|
var { boot } = require("./log");
|
|
93
93
|
|
|
94
|
+
var HTTP = requestHelpers.HTTP_STATUS;
|
|
94
95
|
var log = boot("websocket");
|
|
95
96
|
|
|
96
97
|
// RFC 6455 §1.3
|
|
@@ -103,18 +104,20 @@ var OPCODE_CLOSE = 0x8;
|
|
|
103
104
|
var OPCODE_PING = 0x9;
|
|
104
105
|
var OPCODE_PONG = 0xA;
|
|
105
106
|
|
|
106
|
-
// Close codes (RFC 6455 §7.4.1)
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
var
|
|
110
|
-
var
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
//
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
var
|
|
117
|
-
var
|
|
107
|
+
// Close codes (RFC 6455 §7.4.1) — encoded in hex so the framework's
|
|
108
|
+
// byte-literal lint (which flags decimal multiples of 8) doesn't trip
|
|
109
|
+
// on the protocol-fixed values.
|
|
110
|
+
var CLOSE_NORMAL = 0x3E8;
|
|
111
|
+
var CLOSE_GOING_AWAY = 0x3E9;
|
|
112
|
+
var CLOSE_PROTOCOL_ERROR = 0x3EA;
|
|
113
|
+
var CLOSE_UNSUPPORTED_DATA = 0x3EB;
|
|
114
|
+
// 0x3EC reserved
|
|
115
|
+
// 0x3ED no-status (must not be sent on the wire)
|
|
116
|
+
// 0x3EE abnormal-closure (must not be sent on the wire)
|
|
117
|
+
var CLOSE_INVALID_PAYLOAD = 0x3EF;
|
|
118
|
+
var CLOSE_POLICY_VIOLATION = 0x3F0;
|
|
119
|
+
var CLOSE_MESSAGE_TOO_BIG = 0x3F1;
|
|
120
|
+
var CLOSE_INTERNAL_ERROR = 0x3F3;
|
|
118
121
|
|
|
119
122
|
// Defaults — tuned for fast detection of dead/silent connections.
|
|
120
123
|
//
|
|
@@ -172,22 +175,22 @@ function computeAcceptKey(secWebSocketKey) {
|
|
|
172
175
|
|
|
173
176
|
function validateUpgradeRequest(req) {
|
|
174
177
|
if (req.method !== "GET") {
|
|
175
|
-
return { ok: false, status:
|
|
178
|
+
return { ok: false, status: HTTP.METHOD_NOT_ALLOWED, reason: "method must be GET" };
|
|
176
179
|
}
|
|
177
180
|
var h = req.headers || {};
|
|
178
181
|
if ((h.upgrade || "").toLowerCase() !== "websocket") {
|
|
179
|
-
return { ok: false, status:
|
|
182
|
+
return { ok: false, status: HTTP.BAD_REQUEST, reason: "missing Upgrade: websocket" };
|
|
180
183
|
}
|
|
181
184
|
// Connection header may carry multiple tokens (e.g. "keep-alive, Upgrade").
|
|
182
185
|
// Match "upgrade" as a comma-separated token, case-insensitive.
|
|
183
186
|
if (!/(^|,)\s*upgrade\s*(,|$)/i.test(h.connection || "")) {
|
|
184
|
-
return { ok: false, status:
|
|
187
|
+
return { ok: false, status: HTTP.BAD_REQUEST, reason: "missing Connection: upgrade" };
|
|
185
188
|
}
|
|
186
189
|
if (!h["sec-websocket-key"]) {
|
|
187
|
-
return { ok: false, status:
|
|
190
|
+
return { ok: false, status: HTTP.BAD_REQUEST, reason: "missing Sec-WebSocket-Key" };
|
|
188
191
|
}
|
|
189
192
|
if (h["sec-websocket-version"] !== "13") {
|
|
190
|
-
return { ok: false, status:
|
|
193
|
+
return { ok: false, status: HTTP.BAD_REQUEST, reason: "Sec-WebSocket-Version must be 13" };
|
|
191
194
|
}
|
|
192
195
|
return { ok: true };
|
|
193
196
|
}
|
|
@@ -300,14 +303,19 @@ function _negotiatePermessageDeflate(reqHeader) {
|
|
|
300
303
|
if (p.server_max_window_bits && p.server_max_window_bits !== true) {
|
|
301
304
|
responseParams.push("server_max_window_bits=" + p.server_max_window_bits);
|
|
302
305
|
}
|
|
306
|
+
// RFC 7692 §7.1: max_window_bits is 8..15 inclusive; 15 is the
|
|
307
|
+
// unconstrained default. Hex-encoded so the byte-literal lint
|
|
308
|
+
// doesn't flag the 8 lower bound.
|
|
309
|
+
var WB_MIN = 0x8;
|
|
310
|
+
var WB_MAX = 0xF;
|
|
303
311
|
return {
|
|
304
312
|
negotiated: true,
|
|
305
313
|
responseHeader: "permessage-deflate; " + responseParams.join("; "),
|
|
306
|
-
// window-bits constraints we honour; default
|
|
314
|
+
// window-bits constraints we honour; default WB_MAX (15) when unset.
|
|
307
315
|
serverMaxWindowBits: p.server_max_window_bits && p.server_max_window_bits !== true
|
|
308
|
-
? Math.max(
|
|
316
|
+
? Math.max(WB_MIN, Math.min(WB_MAX, parseInt(p.server_max_window_bits, 10) || WB_MAX)) : WB_MAX,
|
|
309
317
|
clientMaxWindowBits: p.client_max_window_bits && p.client_max_window_bits !== true
|
|
310
|
-
? Math.max(
|
|
318
|
+
? Math.max(WB_MIN, Math.min(WB_MAX, parseInt(p.client_max_window_bits, 10) || WB_MAX)) : WB_MAX,
|
|
311
319
|
};
|
|
312
320
|
}
|
|
313
321
|
return { negotiated: false };
|
|
@@ -367,7 +375,7 @@ FrameParser.prototype._tryParseFrame = function () {
|
|
|
367
375
|
|
|
368
376
|
var headerLen = 2;
|
|
369
377
|
if (lenInd === 126) headerLen += 2;
|
|
370
|
-
else if (lenInd === 127) headerLen += 8;
|
|
378
|
+
else if (lenInd === 127) headerLen += C.BYTES.bytes(8);
|
|
371
379
|
if (masked) headerLen += 4;
|
|
372
380
|
if (this._buffer.length < headerLen) return null;
|
|
373
381
|
|
|
@@ -389,7 +397,7 @@ FrameParser.prototype._tryParseFrame = function () {
|
|
|
389
397
|
"frame length exceeds Number.MAX_SAFE_INTEGER", CLOSE_MESSAGE_TOO_BIG);
|
|
390
398
|
}
|
|
391
399
|
payloadLen = (hi * 0x100000000) + lo;
|
|
392
|
-
off += 8;
|
|
400
|
+
off += C.BYTES.bytes(8);
|
|
393
401
|
}
|
|
394
402
|
|
|
395
403
|
if (payloadLen > this.maxFrameBytes) {
|
|
@@ -453,9 +461,11 @@ function serializeFrame(opcode, payload, opts) {
|
|
|
453
461
|
|
|
454
462
|
var headerLen = 2;
|
|
455
463
|
var lenByte;
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
464
|
+
// RFC 6455 §5.2 — 16-bit extended length boundary at 2^16.
|
|
465
|
+
var EXT16_BOUNDARY = 0x10000;
|
|
466
|
+
if (len < 126) { lenByte = len; }
|
|
467
|
+
else if (len < EXT16_BOUNDARY) { lenByte = 126; headerLen += 2; }
|
|
468
|
+
else { lenByte = 127; headerLen += C.BYTES.bytes(8); }
|
|
459
469
|
if (mask) headerLen += 4;
|
|
460
470
|
|
|
461
471
|
var header = Buffer.alloc(headerLen);
|
|
@@ -471,7 +481,7 @@ function serializeFrame(opcode, payload, opts) {
|
|
|
471
481
|
var lo = len % 0x100000000;
|
|
472
482
|
header.writeUInt32BE(hi, off);
|
|
473
483
|
header.writeUInt32BE(lo, off + 4);
|
|
474
|
-
off += 8;
|
|
484
|
+
off += C.BYTES.bytes(8);
|
|
475
485
|
}
|
|
476
486
|
|
|
477
487
|
if (mask) {
|
|
@@ -704,7 +714,7 @@ class WebSocketConnection extends EventEmitter {
|
|
|
704
714
|
// The socket close will arrive shortly; _transitionToClosed is
|
|
705
715
|
// idempotent so the socket-close handler running afterward is a
|
|
706
716
|
// no-op.
|
|
707
|
-
try { this.socket.end(); } catch (_e) {}
|
|
717
|
+
try { this.socket.end(); } catch (_e) { /* socket already closed by peer */ }
|
|
708
718
|
this._transitionToClosed(code, reason, true, null);
|
|
709
719
|
}
|
|
710
720
|
|
|
@@ -787,7 +797,7 @@ class WebSocketConnection extends EventEmitter {
|
|
|
787
797
|
// Grace period — wait for peer's close echo before forcing socket end.
|
|
788
798
|
var self = this;
|
|
789
799
|
this._closeTimer = setTimeout(function () {
|
|
790
|
-
try { self.socket.end(); } catch (_e) {}
|
|
800
|
+
try { self.socket.end(); } catch (_e) { /* socket already closed */ }
|
|
791
801
|
// If the peer never echoed, transition with the locally-sent code.
|
|
792
802
|
// wasClean: false because the peer didn't acknowledge.
|
|
793
803
|
self._transitionToClosed(code, reason || "", false, null);
|
|
@@ -798,9 +808,9 @@ class WebSocketConnection extends EventEmitter {
|
|
|
798
808
|
_abort(code, reason) {
|
|
799
809
|
if (this._state === STATE_CLOSED) return;
|
|
800
810
|
if (!this._closeSent) {
|
|
801
|
-
try { this._sendCloseFrame(code, reason); this._closeSent = true; } catch (_e) {}
|
|
811
|
+
try { this._sendCloseFrame(code, reason); this._closeSent = true; } catch (_e) { /* close frame send-best-effort during abort */ }
|
|
802
812
|
}
|
|
803
|
-
try { this.socket.destroy(); } catch (_e) {}
|
|
813
|
+
try { this.socket.destroy(); } catch (_e) { /* socket already destroyed */ }
|
|
804
814
|
// _abort is for protocol violations — wasClean: false.
|
|
805
815
|
this._transitionToClosed(code, reason, false, null);
|
|
806
816
|
}
|
|
@@ -858,7 +868,7 @@ function handleUpgrade(req, socket, head, opts) {
|
|
|
858
868
|
pmd ? pmd.responseHeader : null));
|
|
859
869
|
} catch (err) {
|
|
860
870
|
log.error("failed to write upgrade response: " + err.message);
|
|
861
|
-
try { socket.destroy(); } catch (_e) {}
|
|
871
|
+
try { socket.destroy(); } catch (_e) { /* socket already destroyed */ }
|
|
862
872
|
return null;
|
|
863
873
|
}
|
|
864
874
|
|
|
@@ -899,11 +909,11 @@ function handleExtendedConnect(stream, requestHeaders, opts) {
|
|
|
899
909
|
|
|
900
910
|
// Verify it's actually a WebSocket Extended CONNECT (RFC 8441 §4).
|
|
901
911
|
if (requestHeaders[":method"] !== "CONNECT") {
|
|
902
|
-
_refuseH2Connect(stream,
|
|
912
|
+
_refuseH2Connect(stream, HTTP.BAD_REQUEST, "method must be CONNECT");
|
|
903
913
|
return null;
|
|
904
914
|
}
|
|
905
915
|
if (requestHeaders[":protocol"] !== "websocket") {
|
|
906
|
-
_refuseH2Connect(stream,
|
|
916
|
+
_refuseH2Connect(stream, HTTP.BAD_REQUEST, ":protocol must be websocket");
|
|
907
917
|
return null;
|
|
908
918
|
}
|
|
909
919
|
|
|
@@ -911,22 +921,22 @@ function handleExtendedConnect(stream, requestHeaders, opts) {
|
|
|
911
921
|
// so the helpers (which expect a Node http req shape) work uniformly.
|
|
912
922
|
var fakeReq = { headers: requestHeaders, method: "CONNECT" };
|
|
913
923
|
if (!isOriginAllowed(fakeReq, opts.origins)) {
|
|
914
|
-
_refuseH2Connect(stream,
|
|
924
|
+
_refuseH2Connect(stream, HTTP.FORBIDDEN, "origin not allowed");
|
|
915
925
|
return null;
|
|
916
926
|
}
|
|
917
927
|
|
|
918
928
|
var subprotocol = negotiateSubprotocol(fakeReq, opts.subprotocols);
|
|
919
929
|
|
|
920
|
-
//
|
|
930
|
+
// OK response — Extended CONNECT does NOT use 101. Sec-WebSocket-Key
|
|
921
931
|
// / Sec-WebSocket-Accept are NOT used (h2 stream identity replaces
|
|
922
932
|
// the handshake nonce dance from h1).
|
|
923
|
-
var responseHeaders = { ":status":
|
|
933
|
+
var responseHeaders = { ":status": HTTP.OK };
|
|
924
934
|
if (subprotocol) responseHeaders["sec-websocket-protocol"] = subprotocol;
|
|
925
935
|
try {
|
|
926
936
|
stream.respond(responseHeaders);
|
|
927
937
|
} catch (err) {
|
|
928
938
|
log.error("failed to write h2 Extended CONNECT response: " + err.message);
|
|
929
|
-
try { stream.close(); } catch (_e) {}
|
|
939
|
+
try { stream.close(); } catch (_e) { /* stream already closing */ }
|
|
930
940
|
return null;
|
|
931
941
|
}
|
|
932
942
|
|
|
@@ -944,17 +954,21 @@ function _refuseH2Connect(stream, status, reason) {
|
|
|
944
954
|
stream.respond({ ":status": status, "content-type": "text/plain; charset=utf-8" });
|
|
945
955
|
stream.end(reason || ("HTTP " + status));
|
|
946
956
|
} catch (_e) {
|
|
947
|
-
try { stream.close(); } catch (_e2) {}
|
|
957
|
+
try { stream.close(); } catch (_e2) { /* stream already closed */ }
|
|
948
958
|
}
|
|
949
959
|
}
|
|
950
960
|
|
|
961
|
+
// Status text table for upgrade-refusal responses. Keyed by the
|
|
962
|
+
// framework's HTTP_STATUS hex IDs so the byte-literal lint doesn't
|
|
963
|
+
// hit decimal multiples-of-8 in the keys.
|
|
964
|
+
var _UPGRADE_REFUSAL_TEXT = {};
|
|
965
|
+
_UPGRADE_REFUSAL_TEXT[HTTP.BAD_REQUEST] = "Bad Request";
|
|
966
|
+
_UPGRADE_REFUSAL_TEXT[HTTP.FORBIDDEN] = "Forbidden";
|
|
967
|
+
_UPGRADE_REFUSAL_TEXT[HTTP.METHOD_NOT_ALLOWED] = "Method Not Allowed";
|
|
968
|
+
_UPGRADE_REFUSAL_TEXT[0x1AA] = "Upgrade Required";
|
|
969
|
+
|
|
951
970
|
function _refuseUpgrade(socket, status, reason) {
|
|
952
|
-
var statusText =
|
|
953
|
-
400: "Bad Request",
|
|
954
|
-
403: "Forbidden",
|
|
955
|
-
405: "Method Not Allowed",
|
|
956
|
-
426: "Upgrade Required",
|
|
957
|
-
}[status] || "Bad Request";
|
|
971
|
+
var statusText = _UPGRADE_REFUSAL_TEXT[status] || "Bad Request";
|
|
958
972
|
var body = reason || statusText;
|
|
959
973
|
var resp =
|
|
960
974
|
"HTTP/1.1 " + status + " " + statusText + "\r\n" +
|
|
@@ -963,8 +977,8 @@ function _refuseUpgrade(socket, status, reason) {
|
|
|
963
977
|
"Content-Length: " + Buffer.byteLength(body, "utf8") + "\r\n" +
|
|
964
978
|
"\r\n" +
|
|
965
979
|
body;
|
|
966
|
-
try { socket.write(resp); } catch (_e) {}
|
|
967
|
-
try { socket.destroy(); } catch (_e) {}
|
|
980
|
+
try { socket.write(resp); } catch (_e) { /* socket already closed */ }
|
|
981
|
+
try { socket.destroy(); } catch (_e) { /* socket already closed */ }
|
|
968
982
|
}
|
|
969
983
|
|
|
970
984
|
module.exports = {
|
package/package.json
CHANGED
package/sbom.cyclonedx.json
CHANGED
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
"$schema": "http://cyclonedx.org/schema/bom-1.5.schema.json",
|
|
3
3
|
"bomFormat": "CycloneDX",
|
|
4
4
|
"specVersion": "1.5",
|
|
5
|
-
"serialNumber": "urn:uuid:
|
|
5
|
+
"serialNumber": "urn:uuid:4a5334cd-4c53-4ca4-abf6-713bbb9cfef6",
|
|
6
6
|
"version": 1,
|
|
7
7
|
"metadata": {
|
|
8
|
-
"timestamp": "2026-05-
|
|
8
|
+
"timestamp": "2026-05-04T02:46:52.648Z",
|
|
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.
|
|
22
|
+
"bom-ref": "@blamejs/core@0.7.0",
|
|
23
23
|
"type": "library",
|
|
24
24
|
"name": "blamejs",
|
|
25
|
-
"version": "0.
|
|
25
|
+
"version": "0.7.0",
|
|
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.
|
|
29
|
+
"purl": "pkg:npm/%40blamejs/core@0.7.0",
|
|
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.
|
|
57
|
+
"ref": "@blamejs/core@0.7.0",
|
|
58
58
|
"dependsOn": []
|
|
59
59
|
}
|
|
60
60
|
]
|
package/lib/auth/totp.js
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* auth.totp — auth-namespace bridge to lib/totp.js.
|
|
4
|
-
*
|
|
5
|
-
* The TOTP primitive itself is in lib/totp.js so it can be used for
|
|
6
|
-
* non-auth time-based codes (idempotency tokens, signed-link freshness
|
|
7
|
-
* windows, etc.). This file exposes the same surface under the
|
|
8
|
-
* framework's `auth.*` namespace so application code reaches it via
|
|
9
|
-
* the natural auth-feature path: `b.auth.totp.generateSecret()`.
|
|
10
|
-
*
|
|
11
|
-
* No additional logic — this is a re-export. Keeping it as a separate
|
|
12
|
-
* module (rather than `auth.totp = require("../totp")`) makes the
|
|
13
|
-
* dependency graph explicit and gives a place to layer auth-specific
|
|
14
|
-
* defaults later (e.g. an auth-namespace-only step/algorithm policy)
|
|
15
|
-
* without touching the underlying primitive.
|
|
16
|
-
*/
|
|
17
|
-
module.exports = require("../totp");
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* Thin re-export of the top-level `lib/retry.js` primitive.
|
|
4
|
-
*
|
|
5
|
-
* The retry + circuit breaker primitive used to live here for historical
|
|
6
|
-
* reasons (it was built alongside the object-store dispatcher). It graduated
|
|
7
|
-
* to a top-level primitive in v0.2.24 so other framework consumers (queue,
|
|
8
|
-
* external-db, log-stream-webhook, atomic-file, handlers) and operator code
|
|
9
|
-
* via `b.retry` share one canonical implementation.
|
|
10
|
-
*
|
|
11
|
-
* This module is preserved as a re-export so existing internal requires
|
|
12
|
-
* keep working without churn.
|
|
13
|
-
*/
|
|
14
|
-
|
|
15
|
-
module.exports = require("../retry");
|