@blamejs/blamejs-shop 0.1.31 → 0.1.33

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.
Files changed (98) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/README.md +4 -0
  3. package/lib/admin.js +18 -10
  4. package/lib/asset-manifest.json +17 -5
  5. package/lib/bundles.js +28 -0
  6. package/lib/checkout.js +48 -2
  7. package/lib/storefront.js +792 -45
  8. package/lib/vendor/MANIFEST.json +2 -2
  9. package/lib/vendor/blamejs/CHANGELOG.md +8 -0
  10. package/lib/vendor/blamejs/README.md +3 -1
  11. package/lib/vendor/blamejs/api-snapshot.json +99 -2
  12. package/lib/vendor/blamejs/index.js +3 -0
  13. package/lib/vendor/blamejs/lib/crypto-oprf.js +110 -0
  14. package/lib/vendor/blamejs/lib/network-tsig.js +404 -0
  15. package/lib/vendor/blamejs/lib/network.js +1 -0
  16. package/lib/vendor/blamejs/lib/vendor/MANIFEST.json +44 -9
  17. package/lib/vendor/blamejs/lib/vendor/noble-curves.cjs +19 -0
  18. package/lib/vendor/blamejs/lib/worm.js +246 -0
  19. package/lib/vendor/blamejs/package.json +1 -1
  20. package/lib/vendor/blamejs/release-notes/v0.12.x.json +1844 -0
  21. package/lib/vendor/blamejs/release-notes/v0.13.0.json +22 -0
  22. package/lib/vendor/blamejs/release-notes/v0.13.1.json +18 -0
  23. package/lib/vendor/blamejs/scripts/vendor-update.sh +11 -1
  24. package/lib/vendor/blamejs/test/layer-0-primitives/codebase-patterns.test.js +3 -1
  25. package/lib/vendor/blamejs/test/layer-0-primitives/crypto-oprf.test.js +101 -0
  26. package/lib/vendor/blamejs/test/layer-0-primitives/network-tsig.test.js +149 -0
  27. package/lib/vendor/blamejs/test/layer-0-primitives/sandbox.test.js +2 -2
  28. package/lib/vendor/blamejs/test/layer-0-primitives/testing.test.js +3 -3
  29. package/lib/vendor/blamejs/test/layer-0-primitives/worm.test.js +126 -0
  30. package/package.json +2 -2
  31. package/lib/vendor/blamejs/release-notes/v0.12.0.json +0 -64
  32. package/lib/vendor/blamejs/release-notes/v0.12.1.json +0 -32
  33. package/lib/vendor/blamejs/release-notes/v0.12.10.json +0 -65
  34. package/lib/vendor/blamejs/release-notes/v0.12.11.json +0 -39
  35. package/lib/vendor/blamejs/release-notes/v0.12.12.json +0 -48
  36. package/lib/vendor/blamejs/release-notes/v0.12.13.json +0 -31
  37. package/lib/vendor/blamejs/release-notes/v0.12.14.json +0 -18
  38. package/lib/vendor/blamejs/release-notes/v0.12.15.json +0 -27
  39. package/lib/vendor/blamejs/release-notes/v0.12.16.json +0 -18
  40. package/lib/vendor/blamejs/release-notes/v0.12.17.json +0 -22
  41. package/lib/vendor/blamejs/release-notes/v0.12.18.json +0 -22
  42. package/lib/vendor/blamejs/release-notes/v0.12.19.json +0 -22
  43. package/lib/vendor/blamejs/release-notes/v0.12.2.json +0 -45
  44. package/lib/vendor/blamejs/release-notes/v0.12.20.json +0 -18
  45. package/lib/vendor/blamejs/release-notes/v0.12.21.json +0 -27
  46. package/lib/vendor/blamejs/release-notes/v0.12.22.json +0 -18
  47. package/lib/vendor/blamejs/release-notes/v0.12.23.json +0 -18
  48. package/lib/vendor/blamejs/release-notes/v0.12.24.json +0 -18
  49. package/lib/vendor/blamejs/release-notes/v0.12.25.json +0 -18
  50. package/lib/vendor/blamejs/release-notes/v0.12.26.json +0 -30
  51. package/lib/vendor/blamejs/release-notes/v0.12.27.json +0 -26
  52. package/lib/vendor/blamejs/release-notes/v0.12.28.json +0 -26
  53. package/lib/vendor/blamejs/release-notes/v0.12.29.json +0 -31
  54. package/lib/vendor/blamejs/release-notes/v0.12.3.json +0 -23
  55. package/lib/vendor/blamejs/release-notes/v0.12.30.json +0 -18
  56. package/lib/vendor/blamejs/release-notes/v0.12.31.json +0 -18
  57. package/lib/vendor/blamejs/release-notes/v0.12.32.json +0 -27
  58. package/lib/vendor/blamejs/release-notes/v0.12.33.json +0 -31
  59. package/lib/vendor/blamejs/release-notes/v0.12.34.json +0 -18
  60. package/lib/vendor/blamejs/release-notes/v0.12.35.json +0 -22
  61. package/lib/vendor/blamejs/release-notes/v0.12.36.json +0 -18
  62. package/lib/vendor/blamejs/release-notes/v0.12.37.json +0 -27
  63. package/lib/vendor/blamejs/release-notes/v0.12.38.json +0 -18
  64. package/lib/vendor/blamejs/release-notes/v0.12.39.json +0 -18
  65. package/lib/vendor/blamejs/release-notes/v0.12.4.json +0 -19
  66. package/lib/vendor/blamejs/release-notes/v0.12.40.json +0 -18
  67. package/lib/vendor/blamejs/release-notes/v0.12.41.json +0 -18
  68. package/lib/vendor/blamejs/release-notes/v0.12.42.json +0 -18
  69. package/lib/vendor/blamejs/release-notes/v0.12.43.json +0 -18
  70. package/lib/vendor/blamejs/release-notes/v0.12.44.json +0 -18
  71. package/lib/vendor/blamejs/release-notes/v0.12.45.json +0 -18
  72. package/lib/vendor/blamejs/release-notes/v0.12.46.json +0 -18
  73. package/lib/vendor/blamejs/release-notes/v0.12.47.json +0 -18
  74. package/lib/vendor/blamejs/release-notes/v0.12.48.json +0 -22
  75. package/lib/vendor/blamejs/release-notes/v0.12.49.json +0 -31
  76. package/lib/vendor/blamejs/release-notes/v0.12.5.json +0 -40
  77. package/lib/vendor/blamejs/release-notes/v0.12.50.json +0 -18
  78. package/lib/vendor/blamejs/release-notes/v0.12.51.json +0 -18
  79. package/lib/vendor/blamejs/release-notes/v0.12.52.json +0 -18
  80. package/lib/vendor/blamejs/release-notes/v0.12.53.json +0 -18
  81. package/lib/vendor/blamejs/release-notes/v0.12.54.json +0 -18
  82. package/lib/vendor/blamejs/release-notes/v0.12.55.json +0 -18
  83. package/lib/vendor/blamejs/release-notes/v0.12.56.json +0 -27
  84. package/lib/vendor/blamejs/release-notes/v0.12.57.json +0 -18
  85. package/lib/vendor/blamejs/release-notes/v0.12.58.json +0 -22
  86. package/lib/vendor/blamejs/release-notes/v0.12.6.json +0 -45
  87. package/lib/vendor/blamejs/release-notes/v0.12.60.json +0 -18
  88. package/lib/vendor/blamejs/release-notes/v0.12.61.json +0 -18
  89. package/lib/vendor/blamejs/release-notes/v0.12.62.json +0 -18
  90. package/lib/vendor/blamejs/release-notes/v0.12.63.json +0 -27
  91. package/lib/vendor/blamejs/release-notes/v0.12.64.json +0 -18
  92. package/lib/vendor/blamejs/release-notes/v0.12.65.json +0 -27
  93. package/lib/vendor/blamejs/release-notes/v0.12.66.json +0 -18
  94. package/lib/vendor/blamejs/release-notes/v0.12.68.json +0 -27
  95. package/lib/vendor/blamejs/release-notes/v0.12.69.json +0 -27
  96. package/lib/vendor/blamejs/release-notes/v0.12.7.json +0 -86
  97. package/lib/vendor/blamejs/release-notes/v0.12.8.json +0 -81
  98. package/lib/vendor/blamejs/release-notes/v0.12.9.json +0 -61
@@ -0,0 +1,404 @@
1
+ "use strict";
2
+ /**
3
+ * @module b.network.dns.tsig
4
+ * @nav Network
5
+ * @title DNS TSIG
6
+ *
7
+ * @intro
8
+ * Sign and verify DNS messages with <a
9
+ * href="https://www.rfc-editor.org/rfc/rfc8945">RFC 8945</a> TSIG
10
+ * (Transaction SIGnature) — the shared-key HMAC that authenticates the
11
+ * transaction between a resolver and a server (zone transfers, dynamic
12
+ * updates, and any query/response pair) and proves it was not tampered
13
+ * with in flight. TSIG complements the existing DNSSEC and DANE
14
+ * primitives: DNSSEC authenticates zone <em>data</em> end-to-end, while
15
+ * TSIG authenticates a single hop's <em>transaction</em> with a
16
+ * pre-shared key.
17
+ *
18
+ * <code>sign(message, opts)</code> appends a TSIG resource record to a
19
+ * DNS message and returns the signed wire bytes;
20
+ * <code>verify(message, opts)</code> locates the TSIG record, recomputes
21
+ * the HMAC over the RFC 8945 §4.3.3 digest, compares it in constant time,
22
+ * and checks the time window (the signature is only valid within
23
+ * <code>fudge</code> seconds of <code>timeSigned</code>). The default MAC
24
+ * algorithm is HMAC-SHA-256; SHA-384 / SHA-512 are available, and the
25
+ * broken HMAC-MD5 / HMAC-SHA-1 algorithms are refused unless
26
+ * <code>allowLegacy</code> is set. Signing a response chains the
27
+ * request's MAC into the digest (<code>requestMac</code>) per §5.4.1.
28
+ *
29
+ * @card
30
+ * RFC 8945 DNS TSIG — shared-key HMAC transaction authentication for DNS
31
+ * messages (sign / verify, constant-time MAC compare, time-window check,
32
+ * HMAC-SHA-256 default). The transaction-level companion to DNSSEC + DANE.
33
+ */
34
+
35
+ var nodeCrypto = require("node:crypto");
36
+ var validateOpts = require("./validate-opts");
37
+ var { timingSafeEqual } = require("./crypto");
38
+ var { defineClass } = require("./framework-error");
39
+
40
+ var TsigError = defineClass("TsigError", { alwaysPermanent: true });
41
+
42
+ var TYPE_TSIG = 250; // allow:raw-byte-literal — IANA RR type TSIG
43
+ var CLASS_ANY = 255; // allow:raw-byte-literal — TSIG RRs use CLASS ANY
44
+ var DEFAULT_FUDGE = 300; // allow:raw-time-literal — RFC 8945 recommended fudge window (seconds)
45
+
46
+ // Algorithm name → Node hash. The strong HMAC-SHA-2 family is the safe set;
47
+ // HMAC-MD5 and HMAC-SHA-1 are refused unless allowLegacy (kept only for
48
+ // interop with legacy nameservers).
49
+ var ALGORITHMS = {
50
+ "hmac-sha256": "sha256",
51
+ "hmac-sha384": "sha384",
52
+ "hmac-sha512": "sha512",
53
+ "hmac-sha224": "sha224",
54
+ };
55
+ var LEGACY_ALGORITHMS = {
56
+ "hmac-sha1": "sha1",
57
+ "hmac-md5": "md5",
58
+ };
59
+ // RFC 8945 §5.2.2.1 — TSIG error RCODEs.
60
+ var ERROR = { NOERROR: 0, BADSIG: 16, BADKEY: 17, BADTIME: 18, BADTRUNC: 22 }; // allow:raw-byte-literal — RFC 8945 extended-RCODE values
61
+
62
+ function _normAlg(name, allowLegacy) {
63
+ var key = String(name || "hmac-sha256").toLowerCase().replace(/\.$/, "");
64
+ if (ALGORITHMS[key]) return { name: key, hash: ALGORITHMS[key] };
65
+ if (LEGACY_ALGORITHMS[key]) {
66
+ if (!allowLegacy) throw new TsigError("tsig/legacy-algorithm", "tsig: algorithm '" + key + "' is broken; pass allowLegacy:true to permit it for legacy interop");
67
+ return { name: key, hash: LEGACY_ALGORITHMS[key] };
68
+ }
69
+ throw new TsigError("tsig/bad-algorithm", "tsig: unknown algorithm '" + key + "'");
70
+ }
71
+
72
+ function _secretBuf(secret) {
73
+ if (Buffer.isBuffer(secret)) return secret;
74
+ if (typeof secret === "string") {
75
+ // TSIG keys are conventionally transported as base64.
76
+ var b = Buffer.from(secret, "base64");
77
+ if (b.length === 0 && secret.length > 0) throw new TsigError("tsig/bad-secret", "tsig: secret must be base64 or a Buffer");
78
+ return b;
79
+ }
80
+ throw new TsigError("tsig/bad-secret", "tsig: secret must be a base64 string or Buffer");
81
+ }
82
+
83
+ // Encode a domain name to uncompressed wire form (labels), lower-casing is
84
+ // NOT applied — TSIG uses the names as presented (key names are
85
+ // conventionally lower-case already; algorithm names are canonical).
86
+ function _encodeName(name) {
87
+ var n = String(name).replace(/\.$/, "");
88
+ if (n === "") return Buffer.from([0]);
89
+ var parts = n.split(".");
90
+ var out = [];
91
+ for (var i = 0; i < parts.length; i++) {
92
+ var lab = Buffer.from(parts[i], "ascii");
93
+ if (lab.length === 0 || lab.length > 63) throw new TsigError("tsig/bad-name", "tsig: invalid label in name '" + name + "'"); // allow:raw-byte-literal — RFC 1035 max label length
94
+ out.push(Buffer.from([lab.length]), lab);
95
+ }
96
+ out.push(Buffer.from([0]));
97
+ return Buffer.concat(out);
98
+ }
99
+
100
+ // Read a domain name starting at off, returning { name, end }. Handles a
101
+ // compression pointer as a terminal jump (TSIG only needs the END offset to
102
+ // keep walking; the pointed-at labels are resolved for the name string).
103
+ function _readName(buf, off) {
104
+ var labels = [];
105
+ var i = off;
106
+ var end = -1;
107
+ var jumps = 0;
108
+ for (;;) {
109
+ if (i >= buf.length) throw new TsigError("tsig/truncated", "tsig: truncated name in message");
110
+ var len = buf[i];
111
+ if (len === 0) { if (end === -1) end = i + 1; break; }
112
+ if ((len & 0xc0) === 0xc0) { // allow:raw-byte-literal — RFC 1035 §4.1.4 compression-pointer flag
113
+ if (i + 1 >= buf.length) throw new TsigError("tsig/truncated", "tsig: truncated compression pointer");
114
+ if (end === -1) end = i + 2;
115
+ var ptr = ((len & 0x3f) << 8) | buf[i + 1]; // allow:raw-byte-literal — 14-bit pointer offset
116
+ if (++jumps > 128) throw new TsigError("tsig/bad-name", "tsig: compression-pointer loop"); // allow:raw-byte-literal — pointer-chase cap
117
+ i = ptr;
118
+ continue;
119
+ }
120
+ if ((len & 0xc0) !== 0) throw new TsigError("tsig/bad-name", "tsig: reserved label-length bits set"); // allow:raw-byte-literal — RFC 1035 label top-bits
121
+ i++;
122
+ labels.push(buf.slice(i, i + len).toString("ascii"));
123
+ i += len;
124
+ }
125
+ return { name: labels.length ? labels.join(".") + "." : ".", end: end };
126
+ }
127
+
128
+ // Skip a name, returning the offset after it (compression-pointer aware).
129
+ function _skipName(buf, off) {
130
+ var i = off;
131
+ for (;;) {
132
+ if (i >= buf.length) throw new TsigError("tsig/truncated", "tsig: truncated name");
133
+ var len = buf[i];
134
+ if (len === 0) return i + 1;
135
+ if ((len & 0xc0) === 0xc0) return i + 2; // allow:raw-byte-literal — compression pointer is terminal
136
+ if ((len & 0xc0) !== 0) throw new TsigError("tsig/bad-name", "tsig: reserved label-length bits set"); // allow:raw-byte-literal — RFC 1035 label top-bits
137
+ i += 1 + len;
138
+ }
139
+ }
140
+
141
+ // Walk the message to the start of the LAST resource record, which a
142
+ // TSIG-bearing message requires to be the TSIG RR (RFC 8945 §5.1).
143
+ function _findTsigRr(buf) {
144
+ if (buf.length < 12) throw new TsigError("tsig/truncated", "tsig: message shorter than the 12-byte header"); // allow:raw-byte-literal — DNS header length
145
+ var qd = buf.readUInt16BE(4), an = buf.readUInt16BE(6), ns = buf.readUInt16BE(8), ar = buf.readUInt16BE(10);
146
+ if (ar < 1) throw new TsigError("tsig/no-tsig", "tsig: message has no additional records (no TSIG)");
147
+ var off = 12; // allow:raw-byte-literal — past the DNS header
148
+ var q;
149
+ for (q = 0; q < qd; q++) { off = _skipName(buf, off); off += 4; } // allow:raw-byte-literal — QTYPE + QCLASS
150
+ var total = an + ns + ar;
151
+ var rrStart = -1;
152
+ for (var r = 0; r < total; r++) {
153
+ rrStart = off;
154
+ off = _skipName(buf, off);
155
+ if (off + 10 > buf.length) throw new TsigError("tsig/truncated", "tsig: truncated RR header"); // allow:raw-byte-literal — type+class+ttl+rdlength
156
+ var rdlen = buf.readUInt16BE(off + 8); // allow:raw-byte-literal — rdlength offset within RR header
157
+ off += 10 + rdlen; // allow:raw-byte-literal — RR fixed header before RDATA
158
+ }
159
+ if (off !== buf.length) throw new TsigError("tsig/trailing-bytes", "tsig: trailing bytes after the final record");
160
+ return rrStart;
161
+ }
162
+
163
+ // Build the TSIG-variables byte block (RFC 8945 §4.3.3).
164
+ function _tsigVariables(keyName, algName, timeSigned, fudge, error, otherData) {
165
+ var time = Buffer.alloc(6); // allow:raw-byte-literal — 48-bit time-signed field
166
+ time.writeUIntBE(timeSigned, 0, 6); // allow:raw-byte-literal — 48-bit big-endian
167
+ var head = Buffer.alloc(6); // allow:raw-byte-literal — CLASS(2) + TTL(4)
168
+ head.writeUInt16BE(CLASS_ANY, 0);
169
+ head.writeUInt32BE(0, 2); // TTL is always 0 (4 bytes)
170
+ var tail = Buffer.alloc(6); // allow:raw-byte-literal — fudge(2)+error(2)+otherlen(2)
171
+ tail.writeUInt16BE(fudge, 0);
172
+ tail.writeUInt16BE(error, 2);
173
+ tail.writeUInt16BE(otherData.length, 4);
174
+ // DNS names are case-insensitive and the TSIG digest uses their canonical
175
+ // (lower-cased) form (RFC 8945 §4.3.3 / RFC 4034 §6.2) — the on-the-wire
176
+ // RR may carry any case, but both signer and verifier digest the
177
+ // lower-cased name, so the MAC is stable across case differences.
178
+ return Buffer.concat([_encodeName(String(keyName).toLowerCase()), head, _encodeName(String(algName).toLowerCase()), time, tail, otherData]);
179
+ }
180
+
181
+ function _requestMacPrefix(requestMac) {
182
+ if (!requestMac) return Buffer.alloc(0);
183
+ var len = Buffer.alloc(2);
184
+ len.writeUInt16BE(requestMac.length, 0);
185
+ return Buffer.concat([len, requestMac]);
186
+ }
187
+
188
+ /**
189
+ * @primitive b.network.dns.tsig.sign
190
+ * @signature b.network.dns.tsig.sign(message, opts)
191
+ * @since 0.12.70
192
+ * @status stable
193
+ * @related b.network.dns.tsig.verify
194
+ *
195
+ * Append a TSIG resource record to a DNS message (a Buffer of wire bytes)
196
+ * and return the signed wire Buffer. The MAC is the HMAC over the message
197
+ * plus the RFC 8945 §4.3.3 TSIG variables. Returns
198
+ * <code>{ wire, mac }</code> — <code>wire</code> is the message with the
199
+ * TSIG RR appended and ARCOUNT incremented, and <code>mac</code> is the raw
200
+ * HMAC (keep it to verify the matching response).
201
+ *
202
+ * @opts
203
+ * keyName: string, // REQUIRED — the shared-key name
204
+ * secret: string | Buffer, // REQUIRED — base64 string or raw bytes
205
+ * algorithm: string, // default: "hmac-sha256"
206
+ * fudge: number, // default: 300 (seconds)
207
+ * time: number, // default: now (Unix seconds)
208
+ * originalId: number, // default: the message's own ID
209
+ * requestMac: Buffer, // when signing a response (§5.4.1)
210
+ * error: number, // default: 0 (NOERROR)
211
+ * otherData: Buffer, // default: empty
212
+ * allowLegacy: boolean, // permit HMAC-MD5 / HMAC-SHA-1
213
+ *
214
+ * @example
215
+ * var signed = b.network.dns.tsig.sign(queryWire, {
216
+ * keyName: "update.key.", secret: "<base64-secret>",
217
+ * });
218
+ * socket.send(signed.wire);
219
+ */
220
+ function sign(message, opts) {
221
+ opts = opts || {};
222
+ if (!Buffer.isBuffer(message) || message.length < 12) throw new TsigError("tsig/bad-message", "tsig.sign: message must be a DNS wire Buffer");
223
+ validateOpts.requireNonEmptyString(opts.keyName, "tsig.sign: keyName", TsigError, "tsig/bad-opt");
224
+ var alg = _normAlg(opts.algorithm, opts.allowLegacy === true);
225
+ var secret = _secretBuf(opts.secret);
226
+ var fudge = opts.fudge == null ? DEFAULT_FUDGE : opts.fudge;
227
+ if (typeof fudge !== "number" || !isFinite(fudge) || fudge < 0 || fudge > 0xffff) throw new TsigError("tsig/bad-opt", "tsig.sign: fudge must be 0..65535 seconds"); // allow:raw-byte-literal — 16-bit fudge field
228
+ var time = opts.time == null ? Math.floor(Date.now() / 1000) : opts.time; // allow:raw-time-literal — ms→s
229
+ if (typeof time !== "number" || !isFinite(time) || time < 0) throw new TsigError("tsig/bad-opt", "tsig.sign: time must be a non-negative Unix-seconds number");
230
+ var error = opts.error == null ? 0 : opts.error;
231
+ var otherData = Buffer.isBuffer(opts.otherData) ? opts.otherData : Buffer.alloc(0);
232
+ var originalId = opts.originalId == null ? message.readUInt16BE(0) : opts.originalId;
233
+ var algName = alg.name + ".";
234
+
235
+ var digest = Buffer.concat([
236
+ _requestMacPrefix(opts.requestMac),
237
+ message,
238
+ _tsigVariables(opts.keyName, algName, time, fudge, error, otherData),
239
+ ]);
240
+ var mac = nodeCrypto.createHmac(alg.hash, secret).update(digest).digest();
241
+
242
+ // TSIG RDATA: algorithm name, time signed, fudge, MAC size + MAC,
243
+ // original ID, error, other len + other data.
244
+ var rtime = Buffer.alloc(6); rtime.writeUIntBE(time, 0, 6); // allow:raw-byte-literal — 48-bit time-signed
245
+ var fixed = Buffer.alloc(4); // allow:raw-byte-literal — fudge(2)+macsize(2)
246
+ fixed.writeUInt16BE(fudge, 0);
247
+ fixed.writeUInt16BE(mac.length, 2);
248
+ var trailer = Buffer.alloc(6); // allow:raw-byte-literal — origid(2)+error(2)+otherlen(2)
249
+ trailer.writeUInt16BE(originalId, 0);
250
+ trailer.writeUInt16BE(error, 2);
251
+ trailer.writeUInt16BE(otherData.length, 4);
252
+ var rdata = Buffer.concat([_encodeName(algName), rtime, fixed, mac, trailer, otherData]);
253
+
254
+ var rrHead = Buffer.alloc(10); // allow:raw-byte-literal — type+class+ttl+rdlength
255
+ rrHead.writeUInt16BE(TYPE_TSIG, 0);
256
+ rrHead.writeUInt16BE(CLASS_ANY, 2);
257
+ rrHead.writeUInt32BE(0, 4); // TTL 0
258
+ rrHead.writeUInt16BE(rdata.length, 8); // allow:raw-byte-literal — rdlength offset within the 10-byte RR header
259
+ var tsigRr = Buffer.concat([_encodeName(opts.keyName), rrHead, rdata]);
260
+
261
+ var out = Buffer.from(message); // copy so we can bump ARCOUNT
262
+ out.writeUInt16BE(out.readUInt16BE(10) + 1, 10); // allow:raw-byte-literal — ARCOUNT offset
263
+ return { wire: Buffer.concat([out, tsigRr]), mac: mac };
264
+ }
265
+
266
+ function _parseTsigRr(buf, rrStart) {
267
+ var n = _readName(buf, rrStart);
268
+ var off = n.end;
269
+ var type = buf.readUInt16BE(off);
270
+ if (type !== TYPE_TSIG) throw new TsigError("tsig/not-tsig", "tsig: the final record is not a TSIG RR (type " + type + ")");
271
+ // The MAC digest hard-codes CLASS ANY / TTL 0, so the on-wire CLASS and
272
+ // TTL are outside the signed data — they MUST be validated explicitly or
273
+ // an attacker could flip them in transit and still verify (RFC 8945 §4.2:
274
+ // CLASS = ANY, TTL = 0).
275
+ var rrClass = buf.readUInt16BE(off + 2); // allow:raw-byte-literal — CLASS offset within RR header
276
+ var rrTtl = buf.readUInt32BE(off + 4); // allow:raw-byte-literal — TTL offset within RR header
277
+ if (rrClass !== CLASS_ANY) throw new TsigError("tsig/bad-rr", "tsig: TSIG RR CLASS must be ANY (255), got " + rrClass);
278
+ if (rrTtl !== 0) throw new TsigError("tsig/bad-rr", "tsig: TSIG RR TTL must be 0, got " + rrTtl);
279
+ off += 8; // allow:raw-byte-literal — type(2)+class(2)+ttl(4)
280
+ var rdlen = buf.readUInt16BE(off); off += 2;
281
+ var rdStart = off;
282
+ var alg = _readName(buf, off); off = alg.end;
283
+ var timeSigned = buf.readUIntBE(off, 6); off += 6; // allow:raw-byte-literal — 48-bit time-signed
284
+ var fudge = buf.readUInt16BE(off); off += 2;
285
+ var macSize = buf.readUInt16BE(off); off += 2;
286
+ var mac = buf.slice(off, off + macSize); off += macSize;
287
+ var originalId = buf.readUInt16BE(off); off += 2;
288
+ var error = buf.readUInt16BE(off); off += 2;
289
+ var otherLen = buf.readUInt16BE(off); off += 2;
290
+ var otherData = buf.slice(off, off + otherLen); off += otherLen;
291
+ if (off !== rdStart + rdlen) throw new TsigError("tsig/bad-rdata", "tsig: RDATA length mismatch");
292
+ return {
293
+ keyName: n.name, algName: alg.name.replace(/\.$/, ""), timeSigned: timeSigned, fudge: fudge,
294
+ mac: mac, originalId: originalId, error: error, otherData: otherData, rrStart: rrStart,
295
+ };
296
+ }
297
+
298
+ /**
299
+ * @primitive b.network.dns.tsig.verify
300
+ * @signature b.network.dns.tsig.verify(message, opts)
301
+ * @since 0.12.70
302
+ * @status stable
303
+ * @related b.network.dns.tsig.sign
304
+ *
305
+ * Verify the TSIG record on a DNS message: locate the trailing TSIG RR,
306
+ * recompute the HMAC over the RFC 8945 §4.3.3 digest, compare it in
307
+ * constant time, and check that <code>now</code> is within
308
+ * <code>fudge</code> seconds of <code>timeSigned</code>. Returns
309
+ * <code>{ valid, keyName, algorithm, timeSigned, fudge, error, macValid,
310
+ * timeValid, reason }</code>; <code>valid</code> is true only when the MAC
311
+ * matches, the time window holds, and the embedded error is NOERROR. Never
312
+ * throws for an authentication failure — only for a malformed message or
313
+ * unknown key shape.
314
+ *
315
+ * @opts
316
+ * keys: object, // { "<keyName>": { secret, algorithm } }
317
+ * keyName: string, // single-key form (with secret)
318
+ * secret: string | Buffer, // single-key form
319
+ * algorithm: string, // expected algorithm (single-key form)
320
+ * now: number, // default: now (Unix seconds)
321
+ * requestMac: Buffer, // when verifying a response (§5.4.1)
322
+ * allowLegacy: boolean,
323
+ *
324
+ * @example
325
+ * var r = b.network.dns.tsig.verify(received, {
326
+ * keys: { "update.key.": { secret: "<base64>" } },
327
+ * });
328
+ * if (!r.valid) refuse(r.reason);
329
+ */
330
+ function verify(message, opts) {
331
+ opts = opts || {};
332
+ if (!Buffer.isBuffer(message) || message.length < 12) throw new TsigError("tsig/bad-message", "tsig.verify: message must be a DNS wire Buffer");
333
+ var rrStart = _findTsigRr(message);
334
+ var rr = _parseTsigRr(message, rrStart);
335
+
336
+ // Resolve the key for this RR's owner name. DNS names are
337
+ // case-insensitive, so match the lower-cased, dot-trimmed forms.
338
+ function _normName(s) { return String(s).toLowerCase().replace(/\.$/, ""); }
339
+ var rrKeyNorm = _normName(rr.keyName);
340
+ var keyEntry = null;
341
+ if (opts.keys && typeof opts.keys === "object") {
342
+ var ks = Object.keys(opts.keys);
343
+ for (var ki = 0; ki < ks.length; ki++) {
344
+ if (_normName(ks[ki]) === rrKeyNorm) { keyEntry = opts.keys[ks[ki]]; break; }
345
+ }
346
+ } else if (opts.keyName != null && _normName(opts.keyName) === rrKeyNorm) {
347
+ keyEntry = { secret: opts.secret, algorithm: opts.algorithm };
348
+ }
349
+ if (!keyEntry) {
350
+ return { valid: false, keyName: rr.keyName, algorithm: rr.algName, timeSigned: rr.timeSigned, fudge: rr.fudge, error: ERROR.BADKEY, macValid: false, timeValid: false, reason: "unknown key '" + rr.keyName + "'" };
351
+ }
352
+ var alg = _normAlg(keyEntry.algorithm || rr.algName, opts.allowLegacy === true);
353
+ // The RR's algorithm must match the key's expected algorithm
354
+ // (case-insensitive — _normAlg already lower-cases alg.name).
355
+ if (alg.name !== rr.algName.toLowerCase()) {
356
+ return { valid: false, keyName: rr.keyName, algorithm: rr.algName, timeSigned: rr.timeSigned, fudge: rr.fudge, error: ERROR.BADKEY, macValid: false, timeValid: false, reason: "algorithm mismatch (key expects " + alg.name + ", message used " + rr.algName + ")" };
357
+ }
358
+ var secret = _secretBuf(keyEntry.secret);
359
+
360
+ // Reconstruct the digested message: bytes before the TSIG RR, with
361
+ // ARCOUNT decremented and the ID restored to the original ID.
362
+ var digestMsg = Buffer.from(message.slice(0, rrStart));
363
+ digestMsg.writeUInt16BE(rr.originalId, 0);
364
+ digestMsg.writeUInt16BE(digestMsg.readUInt16BE(10) - 1, 10); // allow:raw-byte-literal — ARCOUNT offset
365
+
366
+ var digest = Buffer.concat([
367
+ _requestMacPrefix(opts.requestMac),
368
+ digestMsg,
369
+ _tsigVariables(rr.keyName, rr.algName + ".", rr.timeSigned, rr.fudge, rr.error, rr.otherData),
370
+ ]);
371
+ var expected = nodeCrypto.createHmac(alg.hash, secret).update(digest).digest();
372
+
373
+ // Constant-time compare. A truncated MAC (macSize < full) is only valid
374
+ // down to the RFC 8945 §5.2.2.1 floor of max(10, fullLen/2) octets.
375
+ var macValid = false;
376
+ if (rr.mac.length === expected.length) {
377
+ macValid = timingSafeEqual(rr.mac, expected);
378
+ } else if (rr.mac.length >= Math.max(10, expected.length / 2) && rr.mac.length < expected.length) { // allow:raw-byte-literal — RFC 8945 §5.2.2.1 minimum truncated-MAC length
379
+ macValid = timingSafeEqual(rr.mac, expected.slice(0, rr.mac.length));
380
+ }
381
+
382
+ var now = opts.now == null ? Math.floor(Date.now() / 1000) : opts.now; // allow:raw-time-literal — ms→s
383
+ var timeValid = Math.abs(now - rr.timeSigned) <= rr.fudge;
384
+
385
+ var reason = null;
386
+ if (!macValid) reason = "MAC mismatch";
387
+ else if (!timeValid) reason = "time outside fudge window";
388
+ else if (rr.error !== ERROR.NOERROR) reason = "TSIG error code " + rr.error;
389
+
390
+ return {
391
+ valid: macValid && timeValid && rr.error === ERROR.NOERROR,
392
+ keyName: rr.keyName, algorithm: rr.algName, timeSigned: rr.timeSigned, fudge: rr.fudge,
393
+ error: macValid ? (timeValid ? rr.error : ERROR.BADTIME) : ERROR.BADSIG,
394
+ macValid: macValid, timeValid: timeValid, reason: reason,
395
+ };
396
+ }
397
+
398
+ module.exports = {
399
+ sign: sign,
400
+ verify: verify,
401
+ ALGORITHMS: ALGORITHMS,
402
+ ERROR: ERROR,
403
+ TsigError: TsigError,
404
+ };
@@ -37,6 +37,7 @@ var networkDns = require("./network-dns");
37
37
  networkDns.resolver = require("./network-dns-resolver");
38
38
  networkDns.dnssec = require("./network-dnssec");
39
39
  networkDns.dane = require("./network-dane");
40
+ networkDns.tsig = require("./network-tsig");
40
41
  var networkProxy = require("./network-proxy");
41
42
  var networkTls = require("./network-tls");
42
43
  var heartbeat = require("./network-heartbeat");
@@ -17,7 +17,30 @@
17
17
  "cpe": "cpe:2.3:a:paulmillr:noble-ciphers:2.2.0:*:*:*:*:node.js:*:*",
18
18
  "hashes": {
19
19
  "server": "sha256:5d539dfc9ef47121d4c09bd7256d76448a1f5ac47ee09ac44c78ff6a062af9ab"
20
- }
20
+ },
21
+ "refreshedAt": "2026-05-26T19:53:53.034Z"
22
+ },
23
+ "@noble/curves": {
24
+ "version": "2.2.0",
25
+ "license": "MIT",
26
+ "author": "Paul Miller",
27
+ "source": "https://github.com/paulmillr/noble-curves",
28
+ "exports": [
29
+ "ristretto255_oprf",
30
+ "p256_oprf",
31
+ "p384_oprf",
32
+ "p521_oprf"
33
+ ],
34
+ "files": {
35
+ "server": "lib/vendor/noble-curves.cjs"
36
+ },
37
+ "bundler": "esbuild --format=cjs --minify --platform=node",
38
+ "bundledAt": "2026-05-26T00:00:00Z",
39
+ "cpe": "cpe:2.3:a:paulmillr:noble-curves:0.0.0:*:*:*:*:node.js:*:*",
40
+ "hashes": {
41
+ "server": "sha256:ebf254d5eb56aef8705a1c4af9603f47987b4870a9bb5e657e06907b701e2731"
42
+ },
43
+ "refreshedAt": "2026-05-26T19:53:53.034Z"
21
44
  },
22
45
  "@noble/post-quantum": {
23
46
  "version": "0.6.1",
@@ -47,7 +70,8 @@
47
70
  "cpe": "cpe:2.3:a:paulmillr:noble-post-quantum:0.6.1:*:*:*:*:node.js:*:*",
48
71
  "hashes": {
49
72
  "server": "sha256:f9190309daadca4c2e2cc2b76beaa6b96e463429cc3c390bd9f0ceaf7b588c68"
50
- }
73
+ },
74
+ "refreshedAt": "2026-05-26T19:53:53.034Z"
51
75
  },
52
76
  "@simplewebauthn/server": {
53
77
  "version": "13.3.0",
@@ -69,7 +93,8 @@
69
93
  "cpe": "cpe:2.3:a:simplewebauthn:server:13.3.0:*:*:*:*:node.js:*:*",
70
94
  "hashes": {
71
95
  "server": "sha256:a9777dca582095d67f17ca24e19a0791de29928555b6b779c2233429175eb3f0"
72
- }
96
+ },
97
+ "refreshedAt": "2026-05-26T19:53:53.034Z"
73
98
  },
74
99
  "SecLists-common-passwords-top-10000": {
75
100
  "version": "10k-most-common (master)",
@@ -88,7 +113,8 @@
88
113
  "data_js": "sha256:87b223beca89f33d2c2c32a2cfda0bc187e58061de40e7127bb5ffc4258c6e2a"
89
114
  },
90
115
  "runtime_artifact": "lib/vendor/common-passwords-top-10000.data.js",
91
- "integrity_layers": "sha256 + sha3-512 + SLH-DSA-SHAKE-256f signature + in-payload canary (where applicable)"
116
+ "integrity_layers": "sha256 + sha3-512 + SLH-DSA-SHAKE-256f signature + in-payload canary (where applicable)",
117
+ "refreshedAt": "2026-05-26T19:53:53.034Z"
92
118
  },
93
119
  "bimi-trust-anchors": {
94
120
  "version": "operator-managed",
@@ -112,7 +138,8 @@
112
138
  "data_js": "sha256:aa7a4d33b65a68422a2a2c1670177689f66fdcaa08bd2514d78798b827bd1608"
113
139
  },
114
140
  "runtime_artifact": "lib/vendor/bimi-trust-anchors.data.js",
115
- "integrity_layers": "sha256 + sha3-512 + SLH-DSA-SHAKE-256f signature + in-payload canary (where applicable)"
141
+ "integrity_layers": "sha256 + sha3-512 + SLH-DSA-SHAKE-256f signature + in-payload canary (where applicable)",
142
+ "refreshedAt": "2026-05-26T19:53:53.034Z"
116
143
  },
117
144
  "publicsuffix-list": {
118
145
  "version": "master",
@@ -131,7 +158,8 @@
131
158
  "data_js": "sha256:b4b6ae76fdacbfe07683c4ea62761326f42894c2ccf4359f253bbcab9826ed04"
132
159
  },
133
160
  "runtime_artifact": "lib/vendor/public-suffix-list.data.js",
134
- "integrity_layers": "sha256 + sha3-512 + SLH-DSA-SHAKE-256f signature + in-payload canary (where applicable)"
161
+ "integrity_layers": "sha256 + sha3-512 + SLH-DSA-SHAKE-256f signature + in-payload canary (where applicable)",
162
+ "refreshedAt": "2026-05-26T19:53:53.034Z"
135
163
  },
136
164
  "peculiar-pki": {
137
165
  "version": "2.0.0+pkijs-3.4.0",
@@ -140,8 +168,14 @@
140
168
  "source": "https://github.com/PeculiarVentures",
141
169
  "_about": "Meta-bundle of @peculiar/x509 + pkijs + reflect-metadata + every transitive ASN.1 schema package. Used by lib/mtls-engine-default.js as the pure-JS CA + PKCS#12 engine wired into b.mtlsCa.",
142
170
  "components": {
143
- "@peculiar/x509": { "url": "https://github.com/PeculiarVentures/x509", "version": "1.13.0" },
144
- "pkijs": { "url": "https://github.com/PeculiarVentures/PKI.js", "version": "3.4.0" }
171
+ "@peculiar/x509": {
172
+ "url": "https://github.com/PeculiarVentures/x509",
173
+ "version": "1.13.0"
174
+ },
175
+ "pkijs": {
176
+ "url": "https://github.com/PeculiarVentures/PKI.js",
177
+ "version": "3.4.0"
178
+ }
145
179
  },
146
180
  "exports": [
147
181
  "x509",
@@ -155,7 +189,8 @@
155
189
  "bundledAt": "2026-04-29T00:00:00Z",
156
190
  "hashes": {
157
191
  "server": "sha256:9bbc191afaaa2b1e5757f00480457c08134cdc2c55d541df18d9155bba9cbf77"
158
- }
192
+ },
193
+ "refreshedAt": "2026-05-26T19:53:53.034Z"
159
194
  }
160
195
  }
161
196
  }