Created
February 1, 2026 20:29
-
-
Save guest271314/927807f5f305b6da01eaf77c0c077dac to your computer and use it in GitHub Desktop.
quico bundled
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // https://github.com/colocohen/quico | |
| // node_modules/quico/h3_server.js | |
| import dgram from "node:dgram"; | |
| import { createRequire as createRequire2 } from "node:module"; | |
| // node_modules/@noble/hashes/utils.js | |
| /*! noble-hashes - MIT License (c) 2022 Paul Miller (paulmillr.com) */ | |
| function isBytes(a) { | |
| return a instanceof Uint8Array || ArrayBuffer.isView(a) && a.constructor.name === "Uint8Array"; | |
| } | |
| function anumber(n, title = "") { | |
| if (!Number.isSafeInteger(n) || n < 0) { | |
| const prefix = title && `"${title}" `; | |
| throw new Error(`${prefix}expected integer >= 0, got ${n}`); | |
| } | |
| } | |
| function abytes(value, length, title = "") { | |
| const bytes = isBytes(value); | |
| const len = value?.length; | |
| const needsLen = length !== undefined; | |
| if (!bytes || needsLen && len !== length) { | |
| const prefix = title && `"${title}" `; | |
| const ofLen = needsLen ? ` of length ${length}` : ""; | |
| const got = bytes ? `length=${len}` : `type=${typeof value}`; | |
| throw new Error(prefix + "expected Uint8Array" + ofLen + ", got " + got); | |
| } | |
| return value; | |
| } | |
| function ahash(h) { | |
| if (typeof h !== "function" || typeof h.create !== "function") | |
| throw new Error("Hash must wrapped by utils.createHasher"); | |
| anumber(h.outputLen); | |
| anumber(h.blockLen); | |
| } | |
| function aexists(instance, checkFinished = true) { | |
| if (instance.destroyed) | |
| throw new Error("Hash instance has been destroyed"); | |
| if (checkFinished && instance.finished) | |
| throw new Error("Hash#digest() has already been called"); | |
| } | |
| function aoutput(out, instance) { | |
| abytes(out, undefined, "digestInto() output"); | |
| const min = instance.outputLen; | |
| if (out.length < min) { | |
| throw new Error('"digestInto() output" expected to be of length >=' + min); | |
| } | |
| } | |
| function clean(...arrays) { | |
| for (let i = 0;i < arrays.length; i++) { | |
| arrays[i].fill(0); | |
| } | |
| } | |
| function createView(arr) { | |
| return new DataView(arr.buffer, arr.byteOffset, arr.byteLength); | |
| } | |
| function rotr(word, shift) { | |
| return word << 32 - shift | word >>> shift; | |
| } | |
| var hasHexBuiltin = /* @__PURE__ */ (() => typeof Uint8Array.from([]).toHex === "function" && typeof Uint8Array.fromHex === "function")(); | |
| var hexes = /* @__PURE__ */ Array.from({ length: 256 }, (_, i) => i.toString(16).padStart(2, "0")); | |
| function bytesToHex(bytes) { | |
| abytes(bytes); | |
| if (hasHexBuiltin) | |
| return bytes.toHex(); | |
| let hex = ""; | |
| for (let i = 0;i < bytes.length; i++) { | |
| hex += hexes[bytes[i]]; | |
| } | |
| return hex; | |
| } | |
| var asciis = { _0: 48, _9: 57, A: 65, F: 70, a: 97, f: 102 }; | |
| function asciiToBase16(ch) { | |
| if (ch >= asciis._0 && ch <= asciis._9) | |
| return ch - asciis._0; | |
| if (ch >= asciis.A && ch <= asciis.F) | |
| return ch - (asciis.A - 10); | |
| if (ch >= asciis.a && ch <= asciis.f) | |
| return ch - (asciis.a - 10); | |
| return; | |
| } | |
| function hexToBytes(hex) { | |
| if (typeof hex !== "string") | |
| throw new Error("hex string expected, got " + typeof hex); | |
| if (hasHexBuiltin) | |
| return Uint8Array.fromHex(hex); | |
| const hl = hex.length; | |
| const al = hl / 2; | |
| if (hl % 2) | |
| throw new Error("hex string expected, got unpadded hex of length " + hl); | |
| const array = new Uint8Array(al); | |
| for (let ai = 0, hi = 0;ai < al; ai++, hi += 2) { | |
| const n1 = asciiToBase16(hex.charCodeAt(hi)); | |
| const n2 = asciiToBase16(hex.charCodeAt(hi + 1)); | |
| if (n1 === undefined || n2 === undefined) { | |
| const char = hex[hi] + hex[hi + 1]; | |
| throw new Error('hex string expected, got non-hex character "' + char + '" at index ' + hi); | |
| } | |
| array[ai] = n1 * 16 + n2; | |
| } | |
| return array; | |
| } | |
| function concatBytes(...arrays) { | |
| let sum = 0; | |
| for (let i = 0;i < arrays.length; i++) { | |
| const a = arrays[i]; | |
| abytes(a); | |
| sum += a.length; | |
| } | |
| const res = new Uint8Array(sum); | |
| for (let i = 0, pad = 0;i < arrays.length; i++) { | |
| const a = arrays[i]; | |
| res.set(a, pad); | |
| pad += a.length; | |
| } | |
| return res; | |
| } | |
| function createHasher(hashCons, info = {}) { | |
| const hashC = (msg, opts) => hashCons(opts).update(msg).digest(); | |
| const tmp = hashCons(undefined); | |
| hashC.outputLen = tmp.outputLen; | |
| hashC.blockLen = tmp.blockLen; | |
| hashC.create = (opts) => hashCons(opts); | |
| Object.assign(hashC, info); | |
| return Object.freeze(hashC); | |
| } | |
| function randomBytes(bytesLength = 32) { | |
| const cr = typeof globalThis === "object" ? globalThis.crypto : null; | |
| if (typeof cr?.getRandomValues !== "function") | |
| throw new Error("crypto.getRandomValues must be defined"); | |
| return cr.getRandomValues(new Uint8Array(bytesLength)); | |
| } | |
| var oidNist = (suffix) => ({ | |
| oid: Uint8Array.from([6, 9, 96, 134, 72, 1, 101, 3, 4, 2, suffix]) | |
| }); | |
| // node_modules/@noble/hashes/hmac.js | |
| class _HMAC { | |
| oHash; | |
| iHash; | |
| blockLen; | |
| outputLen; | |
| finished = false; | |
| destroyed = false; | |
| constructor(hash, key) { | |
| ahash(hash); | |
| abytes(key, undefined, "key"); | |
| this.iHash = hash.create(); | |
| if (typeof this.iHash.update !== "function") | |
| throw new Error("Expected instance of class which extends utils.Hash"); | |
| this.blockLen = this.iHash.blockLen; | |
| this.outputLen = this.iHash.outputLen; | |
| const blockLen = this.blockLen; | |
| const pad = new Uint8Array(blockLen); | |
| pad.set(key.length > blockLen ? hash.create().update(key).digest() : key); | |
| for (let i = 0;i < pad.length; i++) | |
| pad[i] ^= 54; | |
| this.iHash.update(pad); | |
| this.oHash = hash.create(); | |
| for (let i = 0;i < pad.length; i++) | |
| pad[i] ^= 54 ^ 92; | |
| this.oHash.update(pad); | |
| clean(pad); | |
| } | |
| update(buf) { | |
| aexists(this); | |
| this.iHash.update(buf); | |
| return this; | |
| } | |
| digestInto(out) { | |
| aexists(this); | |
| abytes(out, this.outputLen, "output"); | |
| this.finished = true; | |
| this.iHash.digestInto(out); | |
| this.oHash.update(out); | |
| this.oHash.digestInto(out); | |
| this.destroy(); | |
| } | |
| digest() { | |
| const out = new Uint8Array(this.oHash.outputLen); | |
| this.digestInto(out); | |
| return out; | |
| } | |
| _cloneInto(to) { | |
| to ||= Object.create(Object.getPrototypeOf(this), {}); | |
| const { oHash, iHash, finished, destroyed, blockLen, outputLen } = this; | |
| to = to; | |
| to.finished = finished; | |
| to.destroyed = destroyed; | |
| to.blockLen = blockLen; | |
| to.outputLen = outputLen; | |
| to.oHash = oHash._cloneInto(to.oHash); | |
| to.iHash = iHash._cloneInto(to.iHash); | |
| return to; | |
| } | |
| clone() { | |
| return this._cloneInto(); | |
| } | |
| destroy() { | |
| this.destroyed = true; | |
| this.oHash.destroy(); | |
| this.iHash.destroy(); | |
| } | |
| } | |
| var hmac = (hash, key, message) => new _HMAC(hash, key).update(message).digest(); | |
| hmac.create = (hash, key) => new _HMAC(hash, key); | |
| // node_modules/@noble/hashes/hkdf.js | |
| function extract(hash, ikm, salt) { | |
| ahash(hash); | |
| if (salt === undefined) | |
| salt = new Uint8Array(hash.outputLen); | |
| return hmac(hash, salt, ikm); | |
| } | |
| var HKDF_COUNTER = /* @__PURE__ */ Uint8Array.of(0); | |
| var EMPTY_BUFFER = /* @__PURE__ */ Uint8Array.of(); | |
| function expand(hash, prk, info, length = 32) { | |
| ahash(hash); | |
| anumber(length, "length"); | |
| const olen = hash.outputLen; | |
| if (length > 255 * olen) | |
| throw new Error("Length must be <= 255*HashLen"); | |
| const blocks = Math.ceil(length / olen); | |
| if (info === undefined) | |
| info = EMPTY_BUFFER; | |
| else | |
| abytes(info, undefined, "info"); | |
| const okm = new Uint8Array(blocks * olen); | |
| const HMAC = hmac.create(hash, prk); | |
| const HMACTmp = HMAC._cloneInto(); | |
| const T = new Uint8Array(HMAC.outputLen); | |
| for (let counter = 0;counter < blocks; counter++) { | |
| HKDF_COUNTER[0] = counter + 1; | |
| HMACTmp.update(counter === 0 ? EMPTY_BUFFER : T).update(info).update(HKDF_COUNTER).digestInto(T); | |
| okm.set(T, olen * counter); | |
| HMAC._cloneInto(HMACTmp); | |
| } | |
| HMAC.destroy(); | |
| HMACTmp.destroy(); | |
| clean(T, HKDF_COUNTER); | |
| return okm.slice(0, length); | |
| } | |
| var hkdf = (hash, ikm, salt, info, length) => expand(hash, extract(hash, ikm, salt), info, length); | |
| // node_modules/@noble/hashes/_md.js | |
| function Chi(a, b, c) { | |
| return a & b ^ ~a & c; | |
| } | |
| function Maj(a, b, c) { | |
| return a & b ^ a & c ^ b & c; | |
| } | |
| class HashMD { | |
| blockLen; | |
| outputLen; | |
| padOffset; | |
| isLE; | |
| buffer; | |
| view; | |
| finished = false; | |
| length = 0; | |
| pos = 0; | |
| destroyed = false; | |
| constructor(blockLen, outputLen, padOffset, isLE) { | |
| this.blockLen = blockLen; | |
| this.outputLen = outputLen; | |
| this.padOffset = padOffset; | |
| this.isLE = isLE; | |
| this.buffer = new Uint8Array(blockLen); | |
| this.view = createView(this.buffer); | |
| } | |
| update(data) { | |
| aexists(this); | |
| abytes(data); | |
| const { view, buffer, blockLen } = this; | |
| const len = data.length; | |
| for (let pos = 0;pos < len; ) { | |
| const take = Math.min(blockLen - this.pos, len - pos); | |
| if (take === blockLen) { | |
| const dataView = createView(data); | |
| for (;blockLen <= len - pos; pos += blockLen) | |
| this.process(dataView, pos); | |
| continue; | |
| } | |
| buffer.set(data.subarray(pos, pos + take), this.pos); | |
| this.pos += take; | |
| pos += take; | |
| if (this.pos === blockLen) { | |
| this.process(view, 0); | |
| this.pos = 0; | |
| } | |
| } | |
| this.length += data.length; | |
| this.roundClean(); | |
| return this; | |
| } | |
| digestInto(out) { | |
| aexists(this); | |
| aoutput(out, this); | |
| this.finished = true; | |
| const { buffer, view, blockLen, isLE } = this; | |
| let { pos } = this; | |
| buffer[pos++] = 128; | |
| clean(this.buffer.subarray(pos)); | |
| if (this.padOffset > blockLen - pos) { | |
| this.process(view, 0); | |
| pos = 0; | |
| } | |
| for (let i = pos;i < blockLen; i++) | |
| buffer[i] = 0; | |
| view.setBigUint64(blockLen - 8, BigInt(this.length * 8), isLE); | |
| this.process(view, 0); | |
| const oview = createView(out); | |
| const len = this.outputLen; | |
| if (len % 4) | |
| throw new Error("_sha2: outputLen must be aligned to 32bit"); | |
| const outLen = len / 4; | |
| const state = this.get(); | |
| if (outLen > state.length) | |
| throw new Error("_sha2: outputLen bigger than state"); | |
| for (let i = 0;i < outLen; i++) | |
| oview.setUint32(4 * i, state[i], isLE); | |
| } | |
| digest() { | |
| const { buffer, outputLen } = this; | |
| this.digestInto(buffer); | |
| const res = buffer.slice(0, outputLen); | |
| this.destroy(); | |
| return res; | |
| } | |
| _cloneInto(to) { | |
| to ||= new this.constructor; | |
| to.set(...this.get()); | |
| const { blockLen, buffer, length, finished, destroyed, pos } = this; | |
| to.destroyed = destroyed; | |
| to.finished = finished; | |
| to.length = length; | |
| to.pos = pos; | |
| if (length % blockLen) | |
| to.buffer.set(buffer); | |
| return to; | |
| } | |
| clone() { | |
| return this._cloneInto(); | |
| } | |
| } | |
| var SHA256_IV = /* @__PURE__ */ Uint32Array.from([ | |
| 1779033703, | |
| 3144134277, | |
| 1013904242, | |
| 2773480762, | |
| 1359893119, | |
| 2600822924, | |
| 528734635, | |
| 1541459225 | |
| ]); | |
| var SHA224_IV = /* @__PURE__ */ Uint32Array.from([ | |
| 3238371032, | |
| 914150663, | |
| 812702999, | |
| 4144912697, | |
| 4290775857, | |
| 1750603025, | |
| 1694076839, | |
| 3204075428 | |
| ]); | |
| var SHA384_IV = /* @__PURE__ */ Uint32Array.from([ | |
| 3418070365, | |
| 3238371032, | |
| 1654270250, | |
| 914150663, | |
| 2438529370, | |
| 812702999, | |
| 355462360, | |
| 4144912697, | |
| 1731405415, | |
| 4290775857, | |
| 2394180231, | |
| 1750603025, | |
| 3675008525, | |
| 1694076839, | |
| 1203062813, | |
| 3204075428 | |
| ]); | |
| var SHA512_IV = /* @__PURE__ */ Uint32Array.from([ | |
| 1779033703, | |
| 4089235720, | |
| 3144134277, | |
| 2227873595, | |
| 1013904242, | |
| 4271175723, | |
| 2773480762, | |
| 1595750129, | |
| 1359893119, | |
| 2917565137, | |
| 2600822924, | |
| 725511199, | |
| 528734635, | |
| 4215389547, | |
| 1541459225, | |
| 327033209 | |
| ]); | |
| // node_modules/@noble/hashes/_u64.js | |
| var U32_MASK64 = /* @__PURE__ */ BigInt(2 ** 32 - 1); | |
| var _32n = /* @__PURE__ */ BigInt(32); | |
| function fromBig(n, le = false) { | |
| if (le) | |
| return { h: Number(n & U32_MASK64), l: Number(n >> _32n & U32_MASK64) }; | |
| return { h: Number(n >> _32n & U32_MASK64) | 0, l: Number(n & U32_MASK64) | 0 }; | |
| } | |
| function split(lst, le = false) { | |
| const len = lst.length; | |
| let Ah = new Uint32Array(len); | |
| let Al = new Uint32Array(len); | |
| for (let i = 0;i < len; i++) { | |
| const { h, l } = fromBig(lst[i], le); | |
| [Ah[i], Al[i]] = [h, l]; | |
| } | |
| return [Ah, Al]; | |
| } | |
| var shrSH = (h, _l, s) => h >>> s; | |
| var shrSL = (h, l, s) => h << 32 - s | l >>> s; | |
| var rotrSH = (h, l, s) => h >>> s | l << 32 - s; | |
| var rotrSL = (h, l, s) => h << 32 - s | l >>> s; | |
| var rotrBH = (h, l, s) => h << 64 - s | l >>> s - 32; | |
| var rotrBL = (h, l, s) => h >>> s - 32 | l << 64 - s; | |
| function add(Ah, Al, Bh, Bl) { | |
| const l = (Al >>> 0) + (Bl >>> 0); | |
| return { h: Ah + Bh + (l / 2 ** 32 | 0) | 0, l: l | 0 }; | |
| } | |
| var add3L = (Al, Bl, Cl) => (Al >>> 0) + (Bl >>> 0) + (Cl >>> 0); | |
| var add3H = (low, Ah, Bh, Ch) => Ah + Bh + Ch + (low / 2 ** 32 | 0) | 0; | |
| var add4L = (Al, Bl, Cl, Dl) => (Al >>> 0) + (Bl >>> 0) + (Cl >>> 0) + (Dl >>> 0); | |
| var add4H = (low, Ah, Bh, Ch, Dh) => Ah + Bh + Ch + Dh + (low / 2 ** 32 | 0) | 0; | |
| var add5L = (Al, Bl, Cl, Dl, El) => (Al >>> 0) + (Bl >>> 0) + (Cl >>> 0) + (Dl >>> 0) + (El >>> 0); | |
| var add5H = (low, Ah, Bh, Ch, Dh, Eh) => Ah + Bh + Ch + Dh + Eh + (low / 2 ** 32 | 0) | 0; | |
| // node_modules/@noble/hashes/sha2.js | |
| var SHA256_K = /* @__PURE__ */ Uint32Array.from([ | |
| 1116352408, | |
| 1899447441, | |
| 3049323471, | |
| 3921009573, | |
| 961987163, | |
| 1508970993, | |
| 2453635748, | |
| 2870763221, | |
| 3624381080, | |
| 310598401, | |
| 607225278, | |
| 1426881987, | |
| 1925078388, | |
| 2162078206, | |
| 2614888103, | |
| 3248222580, | |
| 3835390401, | |
| 4022224774, | |
| 264347078, | |
| 604807628, | |
| 770255983, | |
| 1249150122, | |
| 1555081692, | |
| 1996064986, | |
| 2554220882, | |
| 2821834349, | |
| 2952996808, | |
| 3210313671, | |
| 3336571891, | |
| 3584528711, | |
| 113926993, | |
| 338241895, | |
| 666307205, | |
| 773529912, | |
| 1294757372, | |
| 1396182291, | |
| 1695183700, | |
| 1986661051, | |
| 2177026350, | |
| 2456956037, | |
| 2730485921, | |
| 2820302411, | |
| 3259730800, | |
| 3345764771, | |
| 3516065817, | |
| 3600352804, | |
| 4094571909, | |
| 275423344, | |
| 430227734, | |
| 506948616, | |
| 659060556, | |
| 883997877, | |
| 958139571, | |
| 1322822218, | |
| 1537002063, | |
| 1747873779, | |
| 1955562222, | |
| 2024104815, | |
| 2227730452, | |
| 2361852424, | |
| 2428436474, | |
| 2756734187, | |
| 3204031479, | |
| 3329325298 | |
| ]); | |
| var SHA256_W = /* @__PURE__ */ new Uint32Array(64); | |
| class SHA2_32B extends HashMD { | |
| constructor(outputLen) { | |
| super(64, outputLen, 8, false); | |
| } | |
| get() { | |
| const { A, B, C, D, E, F, G, H } = this; | |
| return [A, B, C, D, E, F, G, H]; | |
| } | |
| set(A, B, C, D, E, F, G, H) { | |
| this.A = A | 0; | |
| this.B = B | 0; | |
| this.C = C | 0; | |
| this.D = D | 0; | |
| this.E = E | 0; | |
| this.F = F | 0; | |
| this.G = G | 0; | |
| this.H = H | 0; | |
| } | |
| process(view, offset) { | |
| for (let i = 0;i < 16; i++, offset += 4) | |
| SHA256_W[i] = view.getUint32(offset, false); | |
| for (let i = 16;i < 64; i++) { | |
| const W15 = SHA256_W[i - 15]; | |
| const W2 = SHA256_W[i - 2]; | |
| const s0 = rotr(W15, 7) ^ rotr(W15, 18) ^ W15 >>> 3; | |
| const s1 = rotr(W2, 17) ^ rotr(W2, 19) ^ W2 >>> 10; | |
| SHA256_W[i] = s1 + SHA256_W[i - 7] + s0 + SHA256_W[i - 16] | 0; | |
| } | |
| let { A, B, C, D, E, F, G, H } = this; | |
| for (let i = 0;i < 64; i++) { | |
| const sigma1 = rotr(E, 6) ^ rotr(E, 11) ^ rotr(E, 25); | |
| const T1 = H + sigma1 + Chi(E, F, G) + SHA256_K[i] + SHA256_W[i] | 0; | |
| const sigma0 = rotr(A, 2) ^ rotr(A, 13) ^ rotr(A, 22); | |
| const T2 = sigma0 + Maj(A, B, C) | 0; | |
| H = G; | |
| G = F; | |
| F = E; | |
| E = D + T1 | 0; | |
| D = C; | |
| C = B; | |
| B = A; | |
| A = T1 + T2 | 0; | |
| } | |
| A = A + this.A | 0; | |
| B = B + this.B | 0; | |
| C = C + this.C | 0; | |
| D = D + this.D | 0; | |
| E = E + this.E | 0; | |
| F = F + this.F | 0; | |
| G = G + this.G | 0; | |
| H = H + this.H | 0; | |
| this.set(A, B, C, D, E, F, G, H); | |
| } | |
| roundClean() { | |
| clean(SHA256_W); | |
| } | |
| destroy() { | |
| this.set(0, 0, 0, 0, 0, 0, 0, 0); | |
| clean(this.buffer); | |
| } | |
| } | |
| class _SHA256 extends SHA2_32B { | |
| A = SHA256_IV[0] | 0; | |
| B = SHA256_IV[1] | 0; | |
| C = SHA256_IV[2] | 0; | |
| D = SHA256_IV[3] | 0; | |
| E = SHA256_IV[4] | 0; | |
| F = SHA256_IV[5] | 0; | |
| G = SHA256_IV[6] | 0; | |
| H = SHA256_IV[7] | 0; | |
| constructor() { | |
| super(32); | |
| } | |
| } | |
| class _SHA224 extends SHA2_32B { | |
| A = SHA224_IV[0] | 0; | |
| B = SHA224_IV[1] | 0; | |
| C = SHA224_IV[2] | 0; | |
| D = SHA224_IV[3] | 0; | |
| E = SHA224_IV[4] | 0; | |
| F = SHA224_IV[5] | 0; | |
| G = SHA224_IV[6] | 0; | |
| H = SHA224_IV[7] | 0; | |
| constructor() { | |
| super(28); | |
| } | |
| } | |
| var K512 = /* @__PURE__ */ (() => split([ | |
| "0x428a2f98d728ae22", | |
| "0x7137449123ef65cd", | |
| "0xb5c0fbcfec4d3b2f", | |
| "0xe9b5dba58189dbbc", | |
| "0x3956c25bf348b538", | |
| "0x59f111f1b605d019", | |
| "0x923f82a4af194f9b", | |
| "0xab1c5ed5da6d8118", | |
| "0xd807aa98a3030242", | |
| "0x12835b0145706fbe", | |
| "0x243185be4ee4b28c", | |
| "0x550c7dc3d5ffb4e2", | |
| "0x72be5d74f27b896f", | |
| "0x80deb1fe3b1696b1", | |
| "0x9bdc06a725c71235", | |
| "0xc19bf174cf692694", | |
| "0xe49b69c19ef14ad2", | |
| "0xefbe4786384f25e3", | |
| "0x0fc19dc68b8cd5b5", | |
| "0x240ca1cc77ac9c65", | |
| "0x2de92c6f592b0275", | |
| "0x4a7484aa6ea6e483", | |
| "0x5cb0a9dcbd41fbd4", | |
| "0x76f988da831153b5", | |
| "0x983e5152ee66dfab", | |
| "0xa831c66d2db43210", | |
| "0xb00327c898fb213f", | |
| "0xbf597fc7beef0ee4", | |
| "0xc6e00bf33da88fc2", | |
| "0xd5a79147930aa725", | |
| "0x06ca6351e003826f", | |
| "0x142929670a0e6e70", | |
| "0x27b70a8546d22ffc", | |
| "0x2e1b21385c26c926", | |
| "0x4d2c6dfc5ac42aed", | |
| "0x53380d139d95b3df", | |
| "0x650a73548baf63de", | |
| "0x766a0abb3c77b2a8", | |
| "0x81c2c92e47edaee6", | |
| "0x92722c851482353b", | |
| "0xa2bfe8a14cf10364", | |
| "0xa81a664bbc423001", | |
| "0xc24b8b70d0f89791", | |
| "0xc76c51a30654be30", | |
| "0xd192e819d6ef5218", | |
| "0xd69906245565a910", | |
| "0xf40e35855771202a", | |
| "0x106aa07032bbd1b8", | |
| "0x19a4c116b8d2d0c8", | |
| "0x1e376c085141ab53", | |
| "0x2748774cdf8eeb99", | |
| "0x34b0bcb5e19b48a8", | |
| "0x391c0cb3c5c95a63", | |
| "0x4ed8aa4ae3418acb", | |
| "0x5b9cca4f7763e373", | |
| "0x682e6ff3d6b2b8a3", | |
| "0x748f82ee5defb2fc", | |
| "0x78a5636f43172f60", | |
| "0x84c87814a1f0ab72", | |
| "0x8cc702081a6439ec", | |
| "0x90befffa23631e28", | |
| "0xa4506cebde82bde9", | |
| "0xbef9a3f7b2c67915", | |
| "0xc67178f2e372532b", | |
| "0xca273eceea26619c", | |
| "0xd186b8c721c0c207", | |
| "0xeada7dd6cde0eb1e", | |
| "0xf57d4f7fee6ed178", | |
| "0x06f067aa72176fba", | |
| "0x0a637dc5a2c898a6", | |
| "0x113f9804bef90dae", | |
| "0x1b710b35131c471b", | |
| "0x28db77f523047d84", | |
| "0x32caab7b40c72493", | |
| "0x3c9ebe0a15c9bebc", | |
| "0x431d67c49c100d4c", | |
| "0x4cc5d4becb3e42b6", | |
| "0x597f299cfc657e2a", | |
| "0x5fcb6fab3ad6faec", | |
| "0x6c44198c4a475817" | |
| ].map((n) => BigInt(n))))(); | |
| var SHA512_Kh = /* @__PURE__ */ (() => K512[0])(); | |
| var SHA512_Kl = /* @__PURE__ */ (() => K512[1])(); | |
| var SHA512_W_H = /* @__PURE__ */ new Uint32Array(80); | |
| var SHA512_W_L = /* @__PURE__ */ new Uint32Array(80); | |
| class SHA2_64B extends HashMD { | |
| constructor(outputLen) { | |
| super(128, outputLen, 16, false); | |
| } | |
| get() { | |
| const { Ah, Al, Bh, Bl, Ch, Cl, Dh, Dl, Eh, El, Fh, Fl, Gh, Gl, Hh, Hl } = this; | |
| return [Ah, Al, Bh, Bl, Ch, Cl, Dh, Dl, Eh, El, Fh, Fl, Gh, Gl, Hh, Hl]; | |
| } | |
| set(Ah, Al, Bh, Bl, Ch, Cl, Dh, Dl, Eh, El, Fh, Fl, Gh, Gl, Hh, Hl) { | |
| this.Ah = Ah | 0; | |
| this.Al = Al | 0; | |
| this.Bh = Bh | 0; | |
| this.Bl = Bl | 0; | |
| this.Ch = Ch | 0; | |
| this.Cl = Cl | 0; | |
| this.Dh = Dh | 0; | |
| this.Dl = Dl | 0; | |
| this.Eh = Eh | 0; | |
| this.El = El | 0; | |
| this.Fh = Fh | 0; | |
| this.Fl = Fl | 0; | |
| this.Gh = Gh | 0; | |
| this.Gl = Gl | 0; | |
| this.Hh = Hh | 0; | |
| this.Hl = Hl | 0; | |
| } | |
| process(view, offset) { | |
| for (let i = 0;i < 16; i++, offset += 4) { | |
| SHA512_W_H[i] = view.getUint32(offset); | |
| SHA512_W_L[i] = view.getUint32(offset += 4); | |
| } | |
| for (let i = 16;i < 80; i++) { | |
| const W15h = SHA512_W_H[i - 15] | 0; | |
| const W15l = SHA512_W_L[i - 15] | 0; | |
| const s0h = rotrSH(W15h, W15l, 1) ^ rotrSH(W15h, W15l, 8) ^ shrSH(W15h, W15l, 7); | |
| const s0l = rotrSL(W15h, W15l, 1) ^ rotrSL(W15h, W15l, 8) ^ shrSL(W15h, W15l, 7); | |
| const W2h = SHA512_W_H[i - 2] | 0; | |
| const W2l = SHA512_W_L[i - 2] | 0; | |
| const s1h = rotrSH(W2h, W2l, 19) ^ rotrBH(W2h, W2l, 61) ^ shrSH(W2h, W2l, 6); | |
| const s1l = rotrSL(W2h, W2l, 19) ^ rotrBL(W2h, W2l, 61) ^ shrSL(W2h, W2l, 6); | |
| const SUMl = add4L(s0l, s1l, SHA512_W_L[i - 7], SHA512_W_L[i - 16]); | |
| const SUMh = add4H(SUMl, s0h, s1h, SHA512_W_H[i - 7], SHA512_W_H[i - 16]); | |
| SHA512_W_H[i] = SUMh | 0; | |
| SHA512_W_L[i] = SUMl | 0; | |
| } | |
| let { Ah, Al, Bh, Bl, Ch, Cl, Dh, Dl, Eh, El, Fh, Fl, Gh, Gl, Hh, Hl } = this; | |
| for (let i = 0;i < 80; i++) { | |
| const sigma1h = rotrSH(Eh, El, 14) ^ rotrSH(Eh, El, 18) ^ rotrBH(Eh, El, 41); | |
| const sigma1l = rotrSL(Eh, El, 14) ^ rotrSL(Eh, El, 18) ^ rotrBL(Eh, El, 41); | |
| const CHIh = Eh & Fh ^ ~Eh & Gh; | |
| const CHIl = El & Fl ^ ~El & Gl; | |
| const T1ll = add5L(Hl, sigma1l, CHIl, SHA512_Kl[i], SHA512_W_L[i]); | |
| const T1h = add5H(T1ll, Hh, sigma1h, CHIh, SHA512_Kh[i], SHA512_W_H[i]); | |
| const T1l = T1ll | 0; | |
| const sigma0h = rotrSH(Ah, Al, 28) ^ rotrBH(Ah, Al, 34) ^ rotrBH(Ah, Al, 39); | |
| const sigma0l = rotrSL(Ah, Al, 28) ^ rotrBL(Ah, Al, 34) ^ rotrBL(Ah, Al, 39); | |
| const MAJh = Ah & Bh ^ Ah & Ch ^ Bh & Ch; | |
| const MAJl = Al & Bl ^ Al & Cl ^ Bl & Cl; | |
| Hh = Gh | 0; | |
| Hl = Gl | 0; | |
| Gh = Fh | 0; | |
| Gl = Fl | 0; | |
| Fh = Eh | 0; | |
| Fl = El | 0; | |
| ({ h: Eh, l: El } = add(Dh | 0, Dl | 0, T1h | 0, T1l | 0)); | |
| Dh = Ch | 0; | |
| Dl = Cl | 0; | |
| Ch = Bh | 0; | |
| Cl = Bl | 0; | |
| Bh = Ah | 0; | |
| Bl = Al | 0; | |
| const All = add3L(T1l, sigma0l, MAJl); | |
| Ah = add3H(All, T1h, sigma0h, MAJh); | |
| Al = All | 0; | |
| } | |
| ({ h: Ah, l: Al } = add(this.Ah | 0, this.Al | 0, Ah | 0, Al | 0)); | |
| ({ h: Bh, l: Bl } = add(this.Bh | 0, this.Bl | 0, Bh | 0, Bl | 0)); | |
| ({ h: Ch, l: Cl } = add(this.Ch | 0, this.Cl | 0, Ch | 0, Cl | 0)); | |
| ({ h: Dh, l: Dl } = add(this.Dh | 0, this.Dl | 0, Dh | 0, Dl | 0)); | |
| ({ h: Eh, l: El } = add(this.Eh | 0, this.El | 0, Eh | 0, El | 0)); | |
| ({ h: Fh, l: Fl } = add(this.Fh | 0, this.Fl | 0, Fh | 0, Fl | 0)); | |
| ({ h: Gh, l: Gl } = add(this.Gh | 0, this.Gl | 0, Gh | 0, Gl | 0)); | |
| ({ h: Hh, l: Hl } = add(this.Hh | 0, this.Hl | 0, Hh | 0, Hl | 0)); | |
| this.set(Ah, Al, Bh, Bl, Ch, Cl, Dh, Dl, Eh, El, Fh, Fl, Gh, Gl, Hh, Hl); | |
| } | |
| roundClean() { | |
| clean(SHA512_W_H, SHA512_W_L); | |
| } | |
| destroy() { | |
| clean(this.buffer); | |
| this.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); | |
| } | |
| } | |
| class _SHA512 extends SHA2_64B { | |
| Ah = SHA512_IV[0] | 0; | |
| Al = SHA512_IV[1] | 0; | |
| Bh = SHA512_IV[2] | 0; | |
| Bl = SHA512_IV[3] | 0; | |
| Ch = SHA512_IV[4] | 0; | |
| Cl = SHA512_IV[5] | 0; | |
| Dh = SHA512_IV[6] | 0; | |
| Dl = SHA512_IV[7] | 0; | |
| Eh = SHA512_IV[8] | 0; | |
| El = SHA512_IV[9] | 0; | |
| Fh = SHA512_IV[10] | 0; | |
| Fl = SHA512_IV[11] | 0; | |
| Gh = SHA512_IV[12] | 0; | |
| Gl = SHA512_IV[13] | 0; | |
| Hh = SHA512_IV[14] | 0; | |
| Hl = SHA512_IV[15] | 0; | |
| constructor() { | |
| super(64); | |
| } | |
| } | |
| class _SHA384 extends SHA2_64B { | |
| Ah = SHA384_IV[0] | 0; | |
| Al = SHA384_IV[1] | 0; | |
| Bh = SHA384_IV[2] | 0; | |
| Bl = SHA384_IV[3] | 0; | |
| Ch = SHA384_IV[4] | 0; | |
| Cl = SHA384_IV[5] | 0; | |
| Dh = SHA384_IV[6] | 0; | |
| Dl = SHA384_IV[7] | 0; | |
| Eh = SHA384_IV[8] | 0; | |
| El = SHA384_IV[9] | 0; | |
| Fh = SHA384_IV[10] | 0; | |
| Fl = SHA384_IV[11] | 0; | |
| Gh = SHA384_IV[12] | 0; | |
| Gl = SHA384_IV[13] | 0; | |
| Hh = SHA384_IV[14] | 0; | |
| Hl = SHA384_IV[15] | 0; | |
| constructor() { | |
| super(48); | |
| } | |
| } | |
| var T224_IV = /* @__PURE__ */ Uint32Array.from([ | |
| 2352822216, | |
| 424955298, | |
| 1944164710, | |
| 2312950998, | |
| 502970286, | |
| 855612546, | |
| 1738396948, | |
| 1479516111, | |
| 258812777, | |
| 2077511080, | |
| 2011393907, | |
| 79989058, | |
| 1067287976, | |
| 1780299464, | |
| 286451373, | |
| 2446758561 | |
| ]); | |
| var T256_IV = /* @__PURE__ */ Uint32Array.from([ | |
| 573645204, | |
| 4230739756, | |
| 2673172387, | |
| 3360449730, | |
| 596883563, | |
| 1867755857, | |
| 2520282905, | |
| 1497426621, | |
| 2519219938, | |
| 2827943907, | |
| 3193839141, | |
| 1401305490, | |
| 721525244, | |
| 746961066, | |
| 246885852, | |
| 2177182882 | |
| ]); | |
| class _SHA512_224 extends SHA2_64B { | |
| Ah = T224_IV[0] | 0; | |
| Al = T224_IV[1] | 0; | |
| Bh = T224_IV[2] | 0; | |
| Bl = T224_IV[3] | 0; | |
| Ch = T224_IV[4] | 0; | |
| Cl = T224_IV[5] | 0; | |
| Dh = T224_IV[6] | 0; | |
| Dl = T224_IV[7] | 0; | |
| Eh = T224_IV[8] | 0; | |
| El = T224_IV[9] | 0; | |
| Fh = T224_IV[10] | 0; | |
| Fl = T224_IV[11] | 0; | |
| Gh = T224_IV[12] | 0; | |
| Gl = T224_IV[13] | 0; | |
| Hh = T224_IV[14] | 0; | |
| Hl = T224_IV[15] | 0; | |
| constructor() { | |
| super(28); | |
| } | |
| } | |
| class _SHA512_256 extends SHA2_64B { | |
| Ah = T256_IV[0] | 0; | |
| Al = T256_IV[1] | 0; | |
| Bh = T256_IV[2] | 0; | |
| Bl = T256_IV[3] | 0; | |
| Ch = T256_IV[4] | 0; | |
| Cl = T256_IV[5] | 0; | |
| Dh = T256_IV[6] | 0; | |
| Dl = T256_IV[7] | 0; | |
| Eh = T256_IV[8] | 0; | |
| El = T256_IV[9] | 0; | |
| Fh = T256_IV[10] | 0; | |
| Fl = T256_IV[11] | 0; | |
| Gh = T256_IV[12] | 0; | |
| Gl = T256_IV[13] | 0; | |
| Hh = T256_IV[14] | 0; | |
| Hl = T256_IV[15] | 0; | |
| constructor() { | |
| super(32); | |
| } | |
| } | |
| var sha256 = /* @__PURE__ */ createHasher(() => new _SHA256, /* @__PURE__ */ oidNist(1)); | |
| var sha384 = /* @__PURE__ */ createHasher(() => new _SHA384, /* @__PURE__ */ oidNist(2)); | |
| // node_modules/@noble/curves/utils.js | |
| /*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */ | |
| var _0n = /* @__PURE__ */ BigInt(0); | |
| var _1n = /* @__PURE__ */ BigInt(1); | |
| function abool(value, title = "") { | |
| if (typeof value !== "boolean") { | |
| const prefix = title && `"${title}" `; | |
| throw new Error(prefix + "expected boolean, got type=" + typeof value); | |
| } | |
| return value; | |
| } | |
| function abignumber(n) { | |
| if (typeof n === "bigint") { | |
| if (!isPosBig(n)) | |
| throw new Error("positive bigint expected, got " + n); | |
| } else | |
| anumber(n); | |
| return n; | |
| } | |
| function numberToHexUnpadded(num) { | |
| const hex = abignumber(num).toString(16); | |
| return hex.length & 1 ? "0" + hex : hex; | |
| } | |
| function hexToNumber(hex) { | |
| if (typeof hex !== "string") | |
| throw new Error("hex string expected, got " + typeof hex); | |
| return hex === "" ? _0n : BigInt("0x" + hex); | |
| } | |
| function bytesToNumberBE(bytes) { | |
| return hexToNumber(bytesToHex(bytes)); | |
| } | |
| function bytesToNumberLE(bytes) { | |
| return hexToNumber(bytesToHex(copyBytes(abytes(bytes)).reverse())); | |
| } | |
| function numberToBytesBE(n, len) { | |
| anumber(len); | |
| n = abignumber(n); | |
| const res = hexToBytes(n.toString(16).padStart(len * 2, "0")); | |
| if (res.length !== len) | |
| throw new Error("number too large"); | |
| return res; | |
| } | |
| function numberToBytesLE(n, len) { | |
| return numberToBytesBE(n, len).reverse(); | |
| } | |
| function copyBytes(bytes) { | |
| return Uint8Array.from(bytes); | |
| } | |
| var isPosBig = (n) => typeof n === "bigint" && _0n <= n; | |
| function inRange(n, min, max) { | |
| return isPosBig(n) && isPosBig(min) && isPosBig(max) && min <= n && n < max; | |
| } | |
| function aInRange(title, n, min, max) { | |
| if (!inRange(n, min, max)) | |
| throw new Error("expected valid " + title + ": " + min + " <= n < " + max + ", got " + n); | |
| } | |
| function bitLen(n) { | |
| let len; | |
| for (len = 0;n > _0n; n >>= _1n, len += 1) | |
| ; | |
| return len; | |
| } | |
| var bitMask = (n) => (_1n << BigInt(n)) - _1n; | |
| function createHmacDrbg(hashLen, qByteLen, hmacFn) { | |
| anumber(hashLen, "hashLen"); | |
| anumber(qByteLen, "qByteLen"); | |
| if (typeof hmacFn !== "function") | |
| throw new Error("hmacFn must be a function"); | |
| const u8n = (len) => new Uint8Array(len); | |
| const NULL = Uint8Array.of(); | |
| const byte0 = Uint8Array.of(0); | |
| const byte1 = Uint8Array.of(1); | |
| const _maxDrbgIters = 1000; | |
| let v = u8n(hashLen); | |
| let k = u8n(hashLen); | |
| let i = 0; | |
| const reset = () => { | |
| v.fill(1); | |
| k.fill(0); | |
| i = 0; | |
| }; | |
| const h = (...msgs) => hmacFn(k, concatBytes(v, ...msgs)); | |
| const reseed = (seed = NULL) => { | |
| k = h(byte0, seed); | |
| v = h(); | |
| if (seed.length === 0) | |
| return; | |
| k = h(byte1, seed); | |
| v = h(); | |
| }; | |
| const gen = () => { | |
| if (i++ >= _maxDrbgIters) | |
| throw new Error("drbg: tried max amount of iterations"); | |
| let len = 0; | |
| const out = []; | |
| while (len < qByteLen) { | |
| v = h(); | |
| const sl = v.slice(); | |
| out.push(sl); | |
| len += v.length; | |
| } | |
| return concatBytes(...out); | |
| }; | |
| const genUntil = (seed, pred) => { | |
| reset(); | |
| reseed(seed); | |
| let res = undefined; | |
| while (!(res = pred(gen()))) | |
| reseed(); | |
| reset(); | |
| return res; | |
| }; | |
| return genUntil; | |
| } | |
| function validateObject(object, fields = {}, optFields = {}) { | |
| if (!object || typeof object !== "object") | |
| throw new Error("expected valid options object"); | |
| function checkField(fieldName, expectedType, isOpt) { | |
| const val = object[fieldName]; | |
| if (isOpt && val === undefined) | |
| return; | |
| const current = typeof val; | |
| if (current !== expectedType || val === null) | |
| throw new Error(`param "${fieldName}" is invalid: expected ${expectedType}, got ${current}`); | |
| } | |
| const iter = (f, isOpt) => Object.entries(f).forEach(([k, v]) => checkField(k, v, isOpt)); | |
| iter(fields, false); | |
| iter(optFields, true); | |
| } | |
| function memoized(fn) { | |
| const map = new WeakMap; | |
| return (arg, ...args) => { | |
| const val = map.get(arg); | |
| if (val !== undefined) | |
| return val; | |
| const computed = fn(arg, ...args); | |
| map.set(arg, computed); | |
| return computed; | |
| }; | |
| } | |
| // node_modules/@noble/curves/abstract/modular.js | |
| /*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */ | |
| var _0n2 = /* @__PURE__ */ BigInt(0); | |
| var _1n2 = /* @__PURE__ */ BigInt(1); | |
| var _2n = /* @__PURE__ */ BigInt(2); | |
| var _3n = /* @__PURE__ */ BigInt(3); | |
| var _4n = /* @__PURE__ */ BigInt(4); | |
| var _5n = /* @__PURE__ */ BigInt(5); | |
| var _7n = /* @__PURE__ */ BigInt(7); | |
| var _8n = /* @__PURE__ */ BigInt(8); | |
| var _9n = /* @__PURE__ */ BigInt(9); | |
| var _16n = /* @__PURE__ */ BigInt(16); | |
| function mod(a, b) { | |
| const result = a % b; | |
| return result >= _0n2 ? result : b + result; | |
| } | |
| function pow2(x, power, modulo) { | |
| let res = x; | |
| while (power-- > _0n2) { | |
| res *= res; | |
| res %= modulo; | |
| } | |
| return res; | |
| } | |
| function invert(number, modulo) { | |
| if (number === _0n2) | |
| throw new Error("invert: expected non-zero number"); | |
| if (modulo <= _0n2) | |
| throw new Error("invert: expected positive modulus, got " + modulo); | |
| let a = mod(number, modulo); | |
| let b = modulo; | |
| let x = _0n2, y = _1n2, u = _1n2, v = _0n2; | |
| while (a !== _0n2) { | |
| const q = b / a; | |
| const r = b % a; | |
| const m = x - u * q; | |
| const n = y - v * q; | |
| b = a, a = r, x = u, y = v, u = m, v = n; | |
| } | |
| const gcd = b; | |
| if (gcd !== _1n2) | |
| throw new Error("invert: does not exist"); | |
| return mod(x, modulo); | |
| } | |
| function assertIsSquare(Fp, root, n) { | |
| if (!Fp.eql(Fp.sqr(root), n)) | |
| throw new Error("Cannot find square root"); | |
| } | |
| function sqrt3mod4(Fp, n) { | |
| const p1div4 = (Fp.ORDER + _1n2) / _4n; | |
| const root = Fp.pow(n, p1div4); | |
| assertIsSquare(Fp, root, n); | |
| return root; | |
| } | |
| function sqrt5mod8(Fp, n) { | |
| const p5div8 = (Fp.ORDER - _5n) / _8n; | |
| const n2 = Fp.mul(n, _2n); | |
| const v = Fp.pow(n2, p5div8); | |
| const nv = Fp.mul(n, v); | |
| const i = Fp.mul(Fp.mul(nv, _2n), v); | |
| const root = Fp.mul(nv, Fp.sub(i, Fp.ONE)); | |
| assertIsSquare(Fp, root, n); | |
| return root; | |
| } | |
| function sqrt9mod16(P) { | |
| const Fp_ = Field(P); | |
| const tn = tonelliShanks(P); | |
| const c1 = tn(Fp_, Fp_.neg(Fp_.ONE)); | |
| const c2 = tn(Fp_, c1); | |
| const c3 = tn(Fp_, Fp_.neg(c1)); | |
| const c4 = (P + _7n) / _16n; | |
| return (Fp, n) => { | |
| let tv1 = Fp.pow(n, c4); | |
| let tv2 = Fp.mul(tv1, c1); | |
| const tv3 = Fp.mul(tv1, c2); | |
| const tv4 = Fp.mul(tv1, c3); | |
| const e1 = Fp.eql(Fp.sqr(tv2), n); | |
| const e2 = Fp.eql(Fp.sqr(tv3), n); | |
| tv1 = Fp.cmov(tv1, tv2, e1); | |
| tv2 = Fp.cmov(tv4, tv3, e2); | |
| const e3 = Fp.eql(Fp.sqr(tv2), n); | |
| const root = Fp.cmov(tv1, tv2, e3); | |
| assertIsSquare(Fp, root, n); | |
| return root; | |
| }; | |
| } | |
| function tonelliShanks(P) { | |
| if (P < _3n) | |
| throw new Error("sqrt is not defined for small field"); | |
| let Q = P - _1n2; | |
| let S = 0; | |
| while (Q % _2n === _0n2) { | |
| Q /= _2n; | |
| S++; | |
| } | |
| let Z = _2n; | |
| const _Fp = Field(P); | |
| while (FpLegendre(_Fp, Z) === 1) { | |
| if (Z++ > 1000) | |
| throw new Error("Cannot find square root: probably non-prime P"); | |
| } | |
| if (S === 1) | |
| return sqrt3mod4; | |
| let cc = _Fp.pow(Z, Q); | |
| const Q1div2 = (Q + _1n2) / _2n; | |
| return function tonelliSlow(Fp, n) { | |
| if (Fp.is0(n)) | |
| return n; | |
| if (FpLegendre(Fp, n) !== 1) | |
| throw new Error("Cannot find square root"); | |
| let M = S; | |
| let c = Fp.mul(Fp.ONE, cc); | |
| let t = Fp.pow(n, Q); | |
| let R = Fp.pow(n, Q1div2); | |
| while (!Fp.eql(t, Fp.ONE)) { | |
| if (Fp.is0(t)) | |
| return Fp.ZERO; | |
| let i = 1; | |
| let t_tmp = Fp.sqr(t); | |
| while (!Fp.eql(t_tmp, Fp.ONE)) { | |
| i++; | |
| t_tmp = Fp.sqr(t_tmp); | |
| if (i === M) | |
| throw new Error("Cannot find square root"); | |
| } | |
| const exponent = _1n2 << BigInt(M - i - 1); | |
| const b = Fp.pow(c, exponent); | |
| M = i; | |
| c = Fp.sqr(b); | |
| t = Fp.mul(t, c); | |
| R = Fp.mul(R, b); | |
| } | |
| return R; | |
| }; | |
| } | |
| function FpSqrt(P) { | |
| if (P % _4n === _3n) | |
| return sqrt3mod4; | |
| if (P % _8n === _5n) | |
| return sqrt5mod8; | |
| if (P % _16n === _9n) | |
| return sqrt9mod16(P); | |
| return tonelliShanks(P); | |
| } | |
| var FIELD_FIELDS = [ | |
| "create", | |
| "isValid", | |
| "is0", | |
| "neg", | |
| "inv", | |
| "sqrt", | |
| "sqr", | |
| "eql", | |
| "add", | |
| "sub", | |
| "mul", | |
| "pow", | |
| "div", | |
| "addN", | |
| "subN", | |
| "mulN", | |
| "sqrN" | |
| ]; | |
| function validateField(field) { | |
| const initial = { | |
| ORDER: "bigint", | |
| BYTES: "number", | |
| BITS: "number" | |
| }; | |
| const opts = FIELD_FIELDS.reduce((map, val) => { | |
| map[val] = "function"; | |
| return map; | |
| }, initial); | |
| validateObject(field, opts); | |
| return field; | |
| } | |
| function FpPow(Fp, num, power) { | |
| if (power < _0n2) | |
| throw new Error("invalid exponent, negatives unsupported"); | |
| if (power === _0n2) | |
| return Fp.ONE; | |
| if (power === _1n2) | |
| return num; | |
| let p = Fp.ONE; | |
| let d = num; | |
| while (power > _0n2) { | |
| if (power & _1n2) | |
| p = Fp.mul(p, d); | |
| d = Fp.sqr(d); | |
| power >>= _1n2; | |
| } | |
| return p; | |
| } | |
| function FpInvertBatch(Fp, nums, passZero = false) { | |
| const inverted = new Array(nums.length).fill(passZero ? Fp.ZERO : undefined); | |
| const multipliedAcc = nums.reduce((acc, num, i) => { | |
| if (Fp.is0(num)) | |
| return acc; | |
| inverted[i] = acc; | |
| return Fp.mul(acc, num); | |
| }, Fp.ONE); | |
| const invertedAcc = Fp.inv(multipliedAcc); | |
| nums.reduceRight((acc, num, i) => { | |
| if (Fp.is0(num)) | |
| return acc; | |
| inverted[i] = Fp.mul(acc, inverted[i]); | |
| return Fp.mul(acc, num); | |
| }, invertedAcc); | |
| return inverted; | |
| } | |
| function FpLegendre(Fp, n) { | |
| const p1mod2 = (Fp.ORDER - _1n2) / _2n; | |
| const powered = Fp.pow(n, p1mod2); | |
| const yes = Fp.eql(powered, Fp.ONE); | |
| const zero = Fp.eql(powered, Fp.ZERO); | |
| const no = Fp.eql(powered, Fp.neg(Fp.ONE)); | |
| if (!yes && !zero && !no) | |
| throw new Error("invalid Legendre symbol result"); | |
| return yes ? 1 : zero ? 0 : -1; | |
| } | |
| function nLength(n, nBitLength) { | |
| if (nBitLength !== undefined) | |
| anumber(nBitLength); | |
| const _nBitLength = nBitLength !== undefined ? nBitLength : n.toString(2).length; | |
| const nByteLength = Math.ceil(_nBitLength / 8); | |
| return { nBitLength: _nBitLength, nByteLength }; | |
| } | |
| class _Field { | |
| ORDER; | |
| BITS; | |
| BYTES; | |
| isLE; | |
| ZERO = _0n2; | |
| ONE = _1n2; | |
| _lengths; | |
| _sqrt; | |
| _mod; | |
| constructor(ORDER, opts = {}) { | |
| if (ORDER <= _0n2) | |
| throw new Error("invalid field: expected ORDER > 0, got " + ORDER); | |
| let _nbitLength = undefined; | |
| this.isLE = false; | |
| if (opts != null && typeof opts === "object") { | |
| if (typeof opts.BITS === "number") | |
| _nbitLength = opts.BITS; | |
| if (typeof opts.sqrt === "function") | |
| this.sqrt = opts.sqrt; | |
| if (typeof opts.isLE === "boolean") | |
| this.isLE = opts.isLE; | |
| if (opts.allowedLengths) | |
| this._lengths = opts.allowedLengths?.slice(); | |
| if (typeof opts.modFromBytes === "boolean") | |
| this._mod = opts.modFromBytes; | |
| } | |
| const { nBitLength, nByteLength } = nLength(ORDER, _nbitLength); | |
| if (nByteLength > 2048) | |
| throw new Error("invalid field: expected ORDER of <= 2048 bytes"); | |
| this.ORDER = ORDER; | |
| this.BITS = nBitLength; | |
| this.BYTES = nByteLength; | |
| this._sqrt = undefined; | |
| Object.preventExtensions(this); | |
| } | |
| create(num) { | |
| return mod(num, this.ORDER); | |
| } | |
| isValid(num) { | |
| if (typeof num !== "bigint") | |
| throw new Error("invalid field element: expected bigint, got " + typeof num); | |
| return _0n2 <= num && num < this.ORDER; | |
| } | |
| is0(num) { | |
| return num === _0n2; | |
| } | |
| isValidNot0(num) { | |
| return !this.is0(num) && this.isValid(num); | |
| } | |
| isOdd(num) { | |
| return (num & _1n2) === _1n2; | |
| } | |
| neg(num) { | |
| return mod(-num, this.ORDER); | |
| } | |
| eql(lhs, rhs) { | |
| return lhs === rhs; | |
| } | |
| sqr(num) { | |
| return mod(num * num, this.ORDER); | |
| } | |
| add(lhs, rhs) { | |
| return mod(lhs + rhs, this.ORDER); | |
| } | |
| sub(lhs, rhs) { | |
| return mod(lhs - rhs, this.ORDER); | |
| } | |
| mul(lhs, rhs) { | |
| return mod(lhs * rhs, this.ORDER); | |
| } | |
| pow(num, power) { | |
| return FpPow(this, num, power); | |
| } | |
| div(lhs, rhs) { | |
| return mod(lhs * invert(rhs, this.ORDER), this.ORDER); | |
| } | |
| sqrN(num) { | |
| return num * num; | |
| } | |
| addN(lhs, rhs) { | |
| return lhs + rhs; | |
| } | |
| subN(lhs, rhs) { | |
| return lhs - rhs; | |
| } | |
| mulN(lhs, rhs) { | |
| return lhs * rhs; | |
| } | |
| inv(num) { | |
| return invert(num, this.ORDER); | |
| } | |
| sqrt(num) { | |
| if (!this._sqrt) | |
| this._sqrt = FpSqrt(this.ORDER); | |
| return this._sqrt(this, num); | |
| } | |
| toBytes(num) { | |
| return this.isLE ? numberToBytesLE(num, this.BYTES) : numberToBytesBE(num, this.BYTES); | |
| } | |
| fromBytes(bytes, skipValidation = false) { | |
| abytes(bytes); | |
| const { _lengths: allowedLengths, BYTES, isLE, ORDER, _mod: modFromBytes } = this; | |
| if (allowedLengths) { | |
| if (!allowedLengths.includes(bytes.length) || bytes.length > BYTES) { | |
| throw new Error("Field.fromBytes: expected " + allowedLengths + " bytes, got " + bytes.length); | |
| } | |
| const padded = new Uint8Array(BYTES); | |
| padded.set(bytes, isLE ? 0 : padded.length - bytes.length); | |
| bytes = padded; | |
| } | |
| if (bytes.length !== BYTES) | |
| throw new Error("Field.fromBytes: expected " + BYTES + " bytes, got " + bytes.length); | |
| let scalar = isLE ? bytesToNumberLE(bytes) : bytesToNumberBE(bytes); | |
| if (modFromBytes) | |
| scalar = mod(scalar, ORDER); | |
| if (!skipValidation) { | |
| if (!this.isValid(scalar)) | |
| throw new Error("invalid field element: outside of range 0..ORDER"); | |
| } | |
| return scalar; | |
| } | |
| invertBatch(lst) { | |
| return FpInvertBatch(this, lst); | |
| } | |
| cmov(a, b, condition) { | |
| return condition ? b : a; | |
| } | |
| } | |
| function Field(ORDER, opts = {}) { | |
| return new _Field(ORDER, opts); | |
| } | |
| function getFieldBytesLength(fieldOrder) { | |
| if (typeof fieldOrder !== "bigint") | |
| throw new Error("field order must be bigint"); | |
| const bitLength = fieldOrder.toString(2).length; | |
| return Math.ceil(bitLength / 8); | |
| } | |
| function getMinHashLength(fieldOrder) { | |
| const length = getFieldBytesLength(fieldOrder); | |
| return length + Math.ceil(length / 2); | |
| } | |
| function mapHashToField(key, fieldOrder, isLE = false) { | |
| abytes(key); | |
| const len = key.length; | |
| const fieldLen = getFieldBytesLength(fieldOrder); | |
| const minLen = getMinHashLength(fieldOrder); | |
| if (len < 16 || len < minLen || len > 1024) | |
| throw new Error("expected " + minLen + "-1024 bytes of input, got " + len); | |
| const num = isLE ? bytesToNumberLE(key) : bytesToNumberBE(key); | |
| const reduced = mod(num, fieldOrder - _1n2) + _1n2; | |
| return isLE ? numberToBytesLE(reduced, fieldLen) : numberToBytesBE(reduced, fieldLen); | |
| } | |
| // node_modules/@noble/curves/abstract/curve.js | |
| /*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */ | |
| var _0n3 = /* @__PURE__ */ BigInt(0); | |
| var _1n3 = /* @__PURE__ */ BigInt(1); | |
| function negateCt(condition, item) { | |
| const neg = item.negate(); | |
| return condition ? neg : item; | |
| } | |
| function normalizeZ(c, points) { | |
| const invertedZs = FpInvertBatch(c.Fp, points.map((p) => p.Z)); | |
| return points.map((p, i) => c.fromAffine(p.toAffine(invertedZs[i]))); | |
| } | |
| function validateW(W, bits) { | |
| if (!Number.isSafeInteger(W) || W <= 0 || W > bits) | |
| throw new Error("invalid window size, expected [1.." + bits + "], got W=" + W); | |
| } | |
| function calcWOpts(W, scalarBits) { | |
| validateW(W, scalarBits); | |
| const windows = Math.ceil(scalarBits / W) + 1; | |
| const windowSize = 2 ** (W - 1); | |
| const maxNumber = 2 ** W; | |
| const mask = bitMask(W); | |
| const shiftBy = BigInt(W); | |
| return { windows, windowSize, mask, maxNumber, shiftBy }; | |
| } | |
| function calcOffsets(n, window, wOpts) { | |
| const { windowSize, mask, maxNumber, shiftBy } = wOpts; | |
| let wbits = Number(n & mask); | |
| let nextN = n >> shiftBy; | |
| if (wbits > windowSize) { | |
| wbits -= maxNumber; | |
| nextN += _1n3; | |
| } | |
| const offsetStart = window * windowSize; | |
| const offset = offsetStart + Math.abs(wbits) - 1; | |
| const isZero = wbits === 0; | |
| const isNeg = wbits < 0; | |
| const isNegF = window % 2 !== 0; | |
| const offsetF = offsetStart; | |
| return { nextN, offset, isZero, isNeg, isNegF, offsetF }; | |
| } | |
| var pointPrecomputes = new WeakMap; | |
| var pointWindowSizes = new WeakMap; | |
| function getW(P) { | |
| return pointWindowSizes.get(P) || 1; | |
| } | |
| function assert0(n) { | |
| if (n !== _0n3) | |
| throw new Error("invalid wNAF"); | |
| } | |
| class wNAF { | |
| BASE; | |
| ZERO; | |
| Fn; | |
| bits; | |
| constructor(Point, bits) { | |
| this.BASE = Point.BASE; | |
| this.ZERO = Point.ZERO; | |
| this.Fn = Point.Fn; | |
| this.bits = bits; | |
| } | |
| _unsafeLadder(elm, n, p = this.ZERO) { | |
| let d = elm; | |
| while (n > _0n3) { | |
| if (n & _1n3) | |
| p = p.add(d); | |
| d = d.double(); | |
| n >>= _1n3; | |
| } | |
| return p; | |
| } | |
| precomputeWindow(point, W) { | |
| const { windows, windowSize } = calcWOpts(W, this.bits); | |
| const points = []; | |
| let p = point; | |
| let base = p; | |
| for (let window = 0;window < windows; window++) { | |
| base = p; | |
| points.push(base); | |
| for (let i = 1;i < windowSize; i++) { | |
| base = base.add(p); | |
| points.push(base); | |
| } | |
| p = base.double(); | |
| } | |
| return points; | |
| } | |
| wNAF(W, precomputes, n) { | |
| if (!this.Fn.isValid(n)) | |
| throw new Error("invalid scalar"); | |
| let p = this.ZERO; | |
| let f = this.BASE; | |
| const wo = calcWOpts(W, this.bits); | |
| for (let window = 0;window < wo.windows; window++) { | |
| const { nextN, offset, isZero, isNeg, isNegF, offsetF } = calcOffsets(n, window, wo); | |
| n = nextN; | |
| if (isZero) { | |
| f = f.add(negateCt(isNegF, precomputes[offsetF])); | |
| } else { | |
| p = p.add(negateCt(isNeg, precomputes[offset])); | |
| } | |
| } | |
| assert0(n); | |
| return { p, f }; | |
| } | |
| wNAFUnsafe(W, precomputes, n, acc = this.ZERO) { | |
| const wo = calcWOpts(W, this.bits); | |
| for (let window = 0;window < wo.windows; window++) { | |
| if (n === _0n3) | |
| break; | |
| const { nextN, offset, isZero, isNeg } = calcOffsets(n, window, wo); | |
| n = nextN; | |
| if (isZero) { | |
| continue; | |
| } else { | |
| const item = precomputes[offset]; | |
| acc = acc.add(isNeg ? item.negate() : item); | |
| } | |
| } | |
| assert0(n); | |
| return acc; | |
| } | |
| getPrecomputes(W, point, transform) { | |
| let comp = pointPrecomputes.get(point); | |
| if (!comp) { | |
| comp = this.precomputeWindow(point, W); | |
| if (W !== 1) { | |
| if (typeof transform === "function") | |
| comp = transform(comp); | |
| pointPrecomputes.set(point, comp); | |
| } | |
| } | |
| return comp; | |
| } | |
| cached(point, scalar, transform) { | |
| const W = getW(point); | |
| return this.wNAF(W, this.getPrecomputes(W, point, transform), scalar); | |
| } | |
| unsafe(point, scalar, transform, prev) { | |
| const W = getW(point); | |
| if (W === 1) | |
| return this._unsafeLadder(point, scalar, prev); | |
| return this.wNAFUnsafe(W, this.getPrecomputes(W, point, transform), scalar, prev); | |
| } | |
| createCache(P, W) { | |
| validateW(W, this.bits); | |
| pointWindowSizes.set(P, W); | |
| pointPrecomputes.delete(P); | |
| } | |
| hasCache(elm) { | |
| return getW(elm) !== 1; | |
| } | |
| } | |
| function mulEndoUnsafe(Point, point, k1, k2) { | |
| let acc = point; | |
| let p1 = Point.ZERO; | |
| let p2 = Point.ZERO; | |
| while (k1 > _0n3 || k2 > _0n3) { | |
| if (k1 & _1n3) | |
| p1 = p1.add(acc); | |
| if (k2 & _1n3) | |
| p2 = p2.add(acc); | |
| acc = acc.double(); | |
| k1 >>= _1n3; | |
| k2 >>= _1n3; | |
| } | |
| return { p1, p2 }; | |
| } | |
| function createField(order, field, isLE) { | |
| if (field) { | |
| if (field.ORDER !== order) | |
| throw new Error("Field.ORDER must match order: Fp == p, Fn == n"); | |
| validateField(field); | |
| return field; | |
| } else { | |
| return Field(order, { isLE }); | |
| } | |
| } | |
| function createCurveFields(type, CURVE, curveOpts = {}, FpFnLE) { | |
| if (FpFnLE === undefined) | |
| FpFnLE = type === "edwards"; | |
| if (!CURVE || typeof CURVE !== "object") | |
| throw new Error(`expected valid ${type} CURVE object`); | |
| for (const p of ["p", "n", "h"]) { | |
| const val = CURVE[p]; | |
| if (!(typeof val === "bigint" && val > _0n3)) | |
| throw new Error(`CURVE.${p} must be positive bigint`); | |
| } | |
| const Fp = createField(CURVE.p, curveOpts.Fp, FpFnLE); | |
| const Fn = createField(CURVE.n, curveOpts.Fn, FpFnLE); | |
| const _b = type === "weierstrass" ? "b" : "d"; | |
| const params = ["Gx", "Gy", "a", _b]; | |
| for (const p of params) { | |
| if (!Fp.isValid(CURVE[p])) | |
| throw new Error(`CURVE.${p} must be valid field element of CURVE.Fp`); | |
| } | |
| CURVE = Object.freeze(Object.assign({}, CURVE)); | |
| return { CURVE, Fp, Fn }; | |
| } | |
| function createKeygen(randomSecretKey, getPublicKey) { | |
| return function keygen(seed) { | |
| const secretKey = randomSecretKey(seed); | |
| return { secretKey, publicKey: getPublicKey(secretKey) }; | |
| }; | |
| } | |
| // node_modules/@noble/curves/abstract/weierstrass.js | |
| /*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */ | |
| var divNearest = (num, den) => (num + (num >= 0 ? den : -den) / _2n2) / den; | |
| function _splitEndoScalar(k, basis, n) { | |
| const [[a1, b1], [a2, b2]] = basis; | |
| const c1 = divNearest(b2 * k, n); | |
| const c2 = divNearest(-b1 * k, n); | |
| let k1 = k - c1 * a1 - c2 * a2; | |
| let k2 = -c1 * b1 - c2 * b2; | |
| const k1neg = k1 < _0n4; | |
| const k2neg = k2 < _0n4; | |
| if (k1neg) | |
| k1 = -k1; | |
| if (k2neg) | |
| k2 = -k2; | |
| const MAX_NUM = bitMask(Math.ceil(bitLen(n) / 2)) + _1n4; | |
| if (k1 < _0n4 || k1 >= MAX_NUM || k2 < _0n4 || k2 >= MAX_NUM) { | |
| throw new Error("splitScalar (endomorphism): failed, k=" + k); | |
| } | |
| return { k1neg, k1, k2neg, k2 }; | |
| } | |
| function validateSigFormat(format) { | |
| if (!["compact", "recovered", "der"].includes(format)) | |
| throw new Error('Signature format must be "compact", "recovered", or "der"'); | |
| return format; | |
| } | |
| function validateSigOpts(opts, def) { | |
| const optsn = {}; | |
| for (let optName of Object.keys(def)) { | |
| optsn[optName] = opts[optName] === undefined ? def[optName] : opts[optName]; | |
| } | |
| abool(optsn.lowS, "lowS"); | |
| abool(optsn.prehash, "prehash"); | |
| if (optsn.format !== undefined) | |
| validateSigFormat(optsn.format); | |
| return optsn; | |
| } | |
| class DERErr extends Error { | |
| constructor(m = "") { | |
| super(m); | |
| } | |
| } | |
| var DER = { | |
| Err: DERErr, | |
| _tlv: { | |
| encode: (tag, data) => { | |
| const { Err: E } = DER; | |
| if (tag < 0 || tag > 256) | |
| throw new E("tlv.encode: wrong tag"); | |
| if (data.length & 1) | |
| throw new E("tlv.encode: unpadded data"); | |
| const dataLen = data.length / 2; | |
| const len = numberToHexUnpadded(dataLen); | |
| if (len.length / 2 & 128) | |
| throw new E("tlv.encode: long form length too big"); | |
| const lenLen = dataLen > 127 ? numberToHexUnpadded(len.length / 2 | 128) : ""; | |
| const t = numberToHexUnpadded(tag); | |
| return t + lenLen + len + data; | |
| }, | |
| decode(tag, data) { | |
| const { Err: E } = DER; | |
| let pos = 0; | |
| if (tag < 0 || tag > 256) | |
| throw new E("tlv.encode: wrong tag"); | |
| if (data.length < 2 || data[pos++] !== tag) | |
| throw new E("tlv.decode: wrong tlv"); | |
| const first = data[pos++]; | |
| const isLong = !!(first & 128); | |
| let length = 0; | |
| if (!isLong) | |
| length = first; | |
| else { | |
| const lenLen = first & 127; | |
| if (!lenLen) | |
| throw new E("tlv.decode(long): indefinite length not supported"); | |
| if (lenLen > 4) | |
| throw new E("tlv.decode(long): byte length is too big"); | |
| const lengthBytes = data.subarray(pos, pos + lenLen); | |
| if (lengthBytes.length !== lenLen) | |
| throw new E("tlv.decode: length bytes not complete"); | |
| if (lengthBytes[0] === 0) | |
| throw new E("tlv.decode(long): zero leftmost byte"); | |
| for (const b of lengthBytes) | |
| length = length << 8 | b; | |
| pos += lenLen; | |
| if (length < 128) | |
| throw new E("tlv.decode(long): not minimal encoding"); | |
| } | |
| const v = data.subarray(pos, pos + length); | |
| if (v.length !== length) | |
| throw new E("tlv.decode: wrong value length"); | |
| return { v, l: data.subarray(pos + length) }; | |
| } | |
| }, | |
| _int: { | |
| encode(num) { | |
| const { Err: E } = DER; | |
| if (num < _0n4) | |
| throw new E("integer: negative integers are not allowed"); | |
| let hex = numberToHexUnpadded(num); | |
| if (Number.parseInt(hex[0], 16) & 8) | |
| hex = "00" + hex; | |
| if (hex.length & 1) | |
| throw new E("unexpected DER parsing assertion: unpadded hex"); | |
| return hex; | |
| }, | |
| decode(data) { | |
| const { Err: E } = DER; | |
| if (data[0] & 128) | |
| throw new E("invalid signature integer: negative"); | |
| if (data[0] === 0 && !(data[1] & 128)) | |
| throw new E("invalid signature integer: unnecessary leading zero"); | |
| return bytesToNumberBE(data); | |
| } | |
| }, | |
| toSig(bytes) { | |
| const { Err: E, _int: int, _tlv: tlv } = DER; | |
| const data = abytes(bytes, undefined, "signature"); | |
| const { v: seqBytes, l: seqLeftBytes } = tlv.decode(48, data); | |
| if (seqLeftBytes.length) | |
| throw new E("invalid signature: left bytes after parsing"); | |
| const { v: rBytes, l: rLeftBytes } = tlv.decode(2, seqBytes); | |
| const { v: sBytes, l: sLeftBytes } = tlv.decode(2, rLeftBytes); | |
| if (sLeftBytes.length) | |
| throw new E("invalid signature: left bytes after parsing"); | |
| return { r: int.decode(rBytes), s: int.decode(sBytes) }; | |
| }, | |
| hexFromSig(sig) { | |
| const { _tlv: tlv, _int: int } = DER; | |
| const rs = tlv.encode(2, int.encode(sig.r)); | |
| const ss = tlv.encode(2, int.encode(sig.s)); | |
| const seq = rs + ss; | |
| return tlv.encode(48, seq); | |
| } | |
| }; | |
| var _0n4 = BigInt(0); | |
| var _1n4 = BigInt(1); | |
| var _2n2 = BigInt(2); | |
| var _3n2 = BigInt(3); | |
| var _4n2 = BigInt(4); | |
| function weierstrass(params, extraOpts = {}) { | |
| const validated = createCurveFields("weierstrass", params, extraOpts); | |
| const { Fp, Fn } = validated; | |
| let CURVE = validated.CURVE; | |
| const { h: cofactor, n: CURVE_ORDER } = CURVE; | |
| validateObject(extraOpts, {}, { | |
| allowInfinityPoint: "boolean", | |
| clearCofactor: "function", | |
| isTorsionFree: "function", | |
| fromBytes: "function", | |
| toBytes: "function", | |
| endo: "object" | |
| }); | |
| const { endo } = extraOpts; | |
| if (endo) { | |
| if (!Fp.is0(CURVE.a) || typeof endo.beta !== "bigint" || !Array.isArray(endo.basises)) { | |
| throw new Error('invalid endo: expected "beta": bigint and "basises": array'); | |
| } | |
| } | |
| const lengths = getWLengths(Fp, Fn); | |
| function assertCompressionIsSupported() { | |
| if (!Fp.isOdd) | |
| throw new Error("compression is not supported: Field does not have .isOdd()"); | |
| } | |
| function pointToBytes(_c, point, isCompressed) { | |
| const { x, y } = point.toAffine(); | |
| const bx = Fp.toBytes(x); | |
| abool(isCompressed, "isCompressed"); | |
| if (isCompressed) { | |
| assertCompressionIsSupported(); | |
| const hasEvenY = !Fp.isOdd(y); | |
| return concatBytes(pprefix(hasEvenY), bx); | |
| } else { | |
| return concatBytes(Uint8Array.of(4), bx, Fp.toBytes(y)); | |
| } | |
| } | |
| function pointFromBytes(bytes) { | |
| abytes(bytes, undefined, "Point"); | |
| const { publicKey: comp, publicKeyUncompressed: uncomp } = lengths; | |
| const length = bytes.length; | |
| const head = bytes[0]; | |
| const tail = bytes.subarray(1); | |
| if (length === comp && (head === 2 || head === 3)) { | |
| const x = Fp.fromBytes(tail); | |
| if (!Fp.isValid(x)) | |
| throw new Error("bad point: is not on curve, wrong x"); | |
| const y2 = weierstrassEquation(x); | |
| let y; | |
| try { | |
| y = Fp.sqrt(y2); | |
| } catch (sqrtError) { | |
| const err = sqrtError instanceof Error ? ": " + sqrtError.message : ""; | |
| throw new Error("bad point: is not on curve, sqrt error" + err); | |
| } | |
| assertCompressionIsSupported(); | |
| const evenY = Fp.isOdd(y); | |
| const evenH = (head & 1) === 1; | |
| if (evenH !== evenY) | |
| y = Fp.neg(y); | |
| return { x, y }; | |
| } else if (length === uncomp && head === 4) { | |
| const L = Fp.BYTES; | |
| const x = Fp.fromBytes(tail.subarray(0, L)); | |
| const y = Fp.fromBytes(tail.subarray(L, L * 2)); | |
| if (!isValidXY(x, y)) | |
| throw new Error("bad point: is not on curve"); | |
| return { x, y }; | |
| } else { | |
| throw new Error(`bad point: got length ${length}, expected compressed=${comp} or uncompressed=${uncomp}`); | |
| } | |
| } | |
| const encodePoint = extraOpts.toBytes || pointToBytes; | |
| const decodePoint = extraOpts.fromBytes || pointFromBytes; | |
| function weierstrassEquation(x) { | |
| const x2 = Fp.sqr(x); | |
| const x3 = Fp.mul(x2, x); | |
| return Fp.add(Fp.add(x3, Fp.mul(x, CURVE.a)), CURVE.b); | |
| } | |
| function isValidXY(x, y) { | |
| const left = Fp.sqr(y); | |
| const right = weierstrassEquation(x); | |
| return Fp.eql(left, right); | |
| } | |
| if (!isValidXY(CURVE.Gx, CURVE.Gy)) | |
| throw new Error("bad curve params: generator point"); | |
| const _4a3 = Fp.mul(Fp.pow(CURVE.a, _3n2), _4n2); | |
| const _27b2 = Fp.mul(Fp.sqr(CURVE.b), BigInt(27)); | |
| if (Fp.is0(Fp.add(_4a3, _27b2))) | |
| throw new Error("bad curve params: a or b"); | |
| function acoord(title, n, banZero = false) { | |
| if (!Fp.isValid(n) || banZero && Fp.is0(n)) | |
| throw new Error(`bad point coordinate ${title}`); | |
| return n; | |
| } | |
| function aprjpoint(other) { | |
| if (!(other instanceof Point)) | |
| throw new Error("Weierstrass Point expected"); | |
| } | |
| function splitEndoScalarN(k) { | |
| if (!endo || !endo.basises) | |
| throw new Error("no endo"); | |
| return _splitEndoScalar(k, endo.basises, Fn.ORDER); | |
| } | |
| const toAffineMemo = memoized((p, iz) => { | |
| const { X, Y, Z } = p; | |
| if (Fp.eql(Z, Fp.ONE)) | |
| return { x: X, y: Y }; | |
| const is0 = p.is0(); | |
| if (iz == null) | |
| iz = is0 ? Fp.ONE : Fp.inv(Z); | |
| const x = Fp.mul(X, iz); | |
| const y = Fp.mul(Y, iz); | |
| const zz = Fp.mul(Z, iz); | |
| if (is0) | |
| return { x: Fp.ZERO, y: Fp.ZERO }; | |
| if (!Fp.eql(zz, Fp.ONE)) | |
| throw new Error("invZ was invalid"); | |
| return { x, y }; | |
| }); | |
| const assertValidMemo = memoized((p) => { | |
| if (p.is0()) { | |
| if (extraOpts.allowInfinityPoint && !Fp.is0(p.Y)) | |
| return; | |
| throw new Error("bad point: ZERO"); | |
| } | |
| const { x, y } = p.toAffine(); | |
| if (!Fp.isValid(x) || !Fp.isValid(y)) | |
| throw new Error("bad point: x or y not field elements"); | |
| if (!isValidXY(x, y)) | |
| throw new Error("bad point: equation left != right"); | |
| if (!p.isTorsionFree()) | |
| throw new Error("bad point: not in prime-order subgroup"); | |
| return true; | |
| }); | |
| function finishEndo(endoBeta, k1p, k2p, k1neg, k2neg) { | |
| k2p = new Point(Fp.mul(k2p.X, endoBeta), k2p.Y, k2p.Z); | |
| k1p = negateCt(k1neg, k1p); | |
| k2p = negateCt(k2neg, k2p); | |
| return k1p.add(k2p); | |
| } | |
| class Point { | |
| static BASE = new Point(CURVE.Gx, CURVE.Gy, Fp.ONE); | |
| static ZERO = new Point(Fp.ZERO, Fp.ONE, Fp.ZERO); | |
| static Fp = Fp; | |
| static Fn = Fn; | |
| X; | |
| Y; | |
| Z; | |
| constructor(X, Y, Z) { | |
| this.X = acoord("x", X); | |
| this.Y = acoord("y", Y, true); | |
| this.Z = acoord("z", Z); | |
| Object.freeze(this); | |
| } | |
| static CURVE() { | |
| return CURVE; | |
| } | |
| static fromAffine(p) { | |
| const { x, y } = p || {}; | |
| if (!p || !Fp.isValid(x) || !Fp.isValid(y)) | |
| throw new Error("invalid affine point"); | |
| if (p instanceof Point) | |
| throw new Error("projective point not allowed"); | |
| if (Fp.is0(x) && Fp.is0(y)) | |
| return Point.ZERO; | |
| return new Point(x, y, Fp.ONE); | |
| } | |
| static fromBytes(bytes) { | |
| const P = Point.fromAffine(decodePoint(abytes(bytes, undefined, "point"))); | |
| P.assertValidity(); | |
| return P; | |
| } | |
| static fromHex(hex) { | |
| return Point.fromBytes(hexToBytes(hex)); | |
| } | |
| get x() { | |
| return this.toAffine().x; | |
| } | |
| get y() { | |
| return this.toAffine().y; | |
| } | |
| precompute(windowSize = 8, isLazy = true) { | |
| wnaf.createCache(this, windowSize); | |
| if (!isLazy) | |
| this.multiply(_3n2); | |
| return this; | |
| } | |
| assertValidity() { | |
| assertValidMemo(this); | |
| } | |
| hasEvenY() { | |
| const { y } = this.toAffine(); | |
| if (!Fp.isOdd) | |
| throw new Error("Field doesn't support isOdd"); | |
| return !Fp.isOdd(y); | |
| } | |
| equals(other) { | |
| aprjpoint(other); | |
| const { X: X1, Y: Y1, Z: Z1 } = this; | |
| const { X: X2, Y: Y2, Z: Z2 } = other; | |
| const U1 = Fp.eql(Fp.mul(X1, Z2), Fp.mul(X2, Z1)); | |
| const U2 = Fp.eql(Fp.mul(Y1, Z2), Fp.mul(Y2, Z1)); | |
| return U1 && U2; | |
| } | |
| negate() { | |
| return new Point(this.X, Fp.neg(this.Y), this.Z); | |
| } | |
| double() { | |
| const { a, b } = CURVE; | |
| const b3 = Fp.mul(b, _3n2); | |
| const { X: X1, Y: Y1, Z: Z1 } = this; | |
| let { ZERO: X3, ZERO: Y3, ZERO: Z3 } = Fp; | |
| let t0 = Fp.mul(X1, X1); | |
| let t1 = Fp.mul(Y1, Y1); | |
| let t2 = Fp.mul(Z1, Z1); | |
| let t3 = Fp.mul(X1, Y1); | |
| t3 = Fp.add(t3, t3); | |
| Z3 = Fp.mul(X1, Z1); | |
| Z3 = Fp.add(Z3, Z3); | |
| X3 = Fp.mul(a, Z3); | |
| Y3 = Fp.mul(b3, t2); | |
| Y3 = Fp.add(X3, Y3); | |
| X3 = Fp.sub(t1, Y3); | |
| Y3 = Fp.add(t1, Y3); | |
| Y3 = Fp.mul(X3, Y3); | |
| X3 = Fp.mul(t3, X3); | |
| Z3 = Fp.mul(b3, Z3); | |
| t2 = Fp.mul(a, t2); | |
| t3 = Fp.sub(t0, t2); | |
| t3 = Fp.mul(a, t3); | |
| t3 = Fp.add(t3, Z3); | |
| Z3 = Fp.add(t0, t0); | |
| t0 = Fp.add(Z3, t0); | |
| t0 = Fp.add(t0, t2); | |
| t0 = Fp.mul(t0, t3); | |
| Y3 = Fp.add(Y3, t0); | |
| t2 = Fp.mul(Y1, Z1); | |
| t2 = Fp.add(t2, t2); | |
| t0 = Fp.mul(t2, t3); | |
| X3 = Fp.sub(X3, t0); | |
| Z3 = Fp.mul(t2, t1); | |
| Z3 = Fp.add(Z3, Z3); | |
| Z3 = Fp.add(Z3, Z3); | |
| return new Point(X3, Y3, Z3); | |
| } | |
| add(other) { | |
| aprjpoint(other); | |
| const { X: X1, Y: Y1, Z: Z1 } = this; | |
| const { X: X2, Y: Y2, Z: Z2 } = other; | |
| let { ZERO: X3, ZERO: Y3, ZERO: Z3 } = Fp; | |
| const a = CURVE.a; | |
| const b3 = Fp.mul(CURVE.b, _3n2); | |
| let t0 = Fp.mul(X1, X2); | |
| let t1 = Fp.mul(Y1, Y2); | |
| let t2 = Fp.mul(Z1, Z2); | |
| let t3 = Fp.add(X1, Y1); | |
| let t4 = Fp.add(X2, Y2); | |
| t3 = Fp.mul(t3, t4); | |
| t4 = Fp.add(t0, t1); | |
| t3 = Fp.sub(t3, t4); | |
| t4 = Fp.add(X1, Z1); | |
| let t5 = Fp.add(X2, Z2); | |
| t4 = Fp.mul(t4, t5); | |
| t5 = Fp.add(t0, t2); | |
| t4 = Fp.sub(t4, t5); | |
| t5 = Fp.add(Y1, Z1); | |
| X3 = Fp.add(Y2, Z2); | |
| t5 = Fp.mul(t5, X3); | |
| X3 = Fp.add(t1, t2); | |
| t5 = Fp.sub(t5, X3); | |
| Z3 = Fp.mul(a, t4); | |
| X3 = Fp.mul(b3, t2); | |
| Z3 = Fp.add(X3, Z3); | |
| X3 = Fp.sub(t1, Z3); | |
| Z3 = Fp.add(t1, Z3); | |
| Y3 = Fp.mul(X3, Z3); | |
| t1 = Fp.add(t0, t0); | |
| t1 = Fp.add(t1, t0); | |
| t2 = Fp.mul(a, t2); | |
| t4 = Fp.mul(b3, t4); | |
| t1 = Fp.add(t1, t2); | |
| t2 = Fp.sub(t0, t2); | |
| t2 = Fp.mul(a, t2); | |
| t4 = Fp.add(t4, t2); | |
| t0 = Fp.mul(t1, t4); | |
| Y3 = Fp.add(Y3, t0); | |
| t0 = Fp.mul(t5, t4); | |
| X3 = Fp.mul(t3, X3); | |
| X3 = Fp.sub(X3, t0); | |
| t0 = Fp.mul(t3, t1); | |
| Z3 = Fp.mul(t5, Z3); | |
| Z3 = Fp.add(Z3, t0); | |
| return new Point(X3, Y3, Z3); | |
| } | |
| subtract(other) { | |
| return this.add(other.negate()); | |
| } | |
| is0() { | |
| return this.equals(Point.ZERO); | |
| } | |
| multiply(scalar) { | |
| const { endo: endo2 } = extraOpts; | |
| if (!Fn.isValidNot0(scalar)) | |
| throw new Error("invalid scalar: out of range"); | |
| let point, fake; | |
| const mul = (n) => wnaf.cached(this, n, (p) => normalizeZ(Point, p)); | |
| if (endo2) { | |
| const { k1neg, k1, k2neg, k2 } = splitEndoScalarN(scalar); | |
| const { p: k1p, f: k1f } = mul(k1); | |
| const { p: k2p, f: k2f } = mul(k2); | |
| fake = k1f.add(k2f); | |
| point = finishEndo(endo2.beta, k1p, k2p, k1neg, k2neg); | |
| } else { | |
| const { p, f } = mul(scalar); | |
| point = p; | |
| fake = f; | |
| } | |
| return normalizeZ(Point, [point, fake])[0]; | |
| } | |
| multiplyUnsafe(sc) { | |
| const { endo: endo2 } = extraOpts; | |
| const p = this; | |
| if (!Fn.isValid(sc)) | |
| throw new Error("invalid scalar: out of range"); | |
| if (sc === _0n4 || p.is0()) | |
| return Point.ZERO; | |
| if (sc === _1n4) | |
| return p; | |
| if (wnaf.hasCache(this)) | |
| return this.multiply(sc); | |
| if (endo2) { | |
| const { k1neg, k1, k2neg, k2 } = splitEndoScalarN(sc); | |
| const { p1, p2 } = mulEndoUnsafe(Point, p, k1, k2); | |
| return finishEndo(endo2.beta, p1, p2, k1neg, k2neg); | |
| } else { | |
| return wnaf.unsafe(p, sc); | |
| } | |
| } | |
| toAffine(invertedZ) { | |
| return toAffineMemo(this, invertedZ); | |
| } | |
| isTorsionFree() { | |
| const { isTorsionFree } = extraOpts; | |
| if (cofactor === _1n4) | |
| return true; | |
| if (isTorsionFree) | |
| return isTorsionFree(Point, this); | |
| return wnaf.unsafe(this, CURVE_ORDER).is0(); | |
| } | |
| clearCofactor() { | |
| const { clearCofactor } = extraOpts; | |
| if (cofactor === _1n4) | |
| return this; | |
| if (clearCofactor) | |
| return clearCofactor(Point, this); | |
| return this.multiplyUnsafe(cofactor); | |
| } | |
| isSmallOrder() { | |
| return this.multiplyUnsafe(cofactor).is0(); | |
| } | |
| toBytes(isCompressed = true) { | |
| abool(isCompressed, "isCompressed"); | |
| this.assertValidity(); | |
| return encodePoint(Point, this, isCompressed); | |
| } | |
| toHex(isCompressed = true) { | |
| return bytesToHex(this.toBytes(isCompressed)); | |
| } | |
| toString() { | |
| return `<Point ${this.is0() ? "ZERO" : this.toHex()}>`; | |
| } | |
| } | |
| const bits = Fn.BITS; | |
| const wnaf = new wNAF(Point, extraOpts.endo ? Math.ceil(bits / 2) : bits); | |
| Point.BASE.precompute(8); | |
| return Point; | |
| } | |
| function pprefix(hasEvenY) { | |
| return Uint8Array.of(hasEvenY ? 2 : 3); | |
| } | |
| function getWLengths(Fp, Fn) { | |
| return { | |
| secretKey: Fn.BYTES, | |
| publicKey: 1 + Fp.BYTES, | |
| publicKeyUncompressed: 1 + 2 * Fp.BYTES, | |
| publicKeyHasPrefix: true, | |
| signature: 2 * Fn.BYTES | |
| }; | |
| } | |
| function ecdh(Point, ecdhOpts = {}) { | |
| const { Fn } = Point; | |
| const randomBytes_ = ecdhOpts.randomBytes || randomBytes; | |
| const lengths = Object.assign(getWLengths(Point.Fp, Fn), { seed: getMinHashLength(Fn.ORDER) }); | |
| function isValidSecretKey(secretKey) { | |
| try { | |
| const num = Fn.fromBytes(secretKey); | |
| return Fn.isValidNot0(num); | |
| } catch (error) { | |
| return false; | |
| } | |
| } | |
| function isValidPublicKey(publicKey, isCompressed) { | |
| const { publicKey: comp, publicKeyUncompressed } = lengths; | |
| try { | |
| const l = publicKey.length; | |
| if (isCompressed === true && l !== comp) | |
| return false; | |
| if (isCompressed === false && l !== publicKeyUncompressed) | |
| return false; | |
| return !!Point.fromBytes(publicKey); | |
| } catch (error) { | |
| return false; | |
| } | |
| } | |
| function randomSecretKey(seed = randomBytes_(lengths.seed)) { | |
| return mapHashToField(abytes(seed, lengths.seed, "seed"), Fn.ORDER); | |
| } | |
| function getPublicKey(secretKey, isCompressed = true) { | |
| return Point.BASE.multiply(Fn.fromBytes(secretKey)).toBytes(isCompressed); | |
| } | |
| function isProbPub(item) { | |
| const { secretKey, publicKey, publicKeyUncompressed } = lengths; | |
| if (!isBytes(item)) | |
| return; | |
| if ("_lengths" in Fn && Fn._lengths || secretKey === publicKey) | |
| return; | |
| const l = abytes(item, undefined, "key").length; | |
| return l === publicKey || l === publicKeyUncompressed; | |
| } | |
| function getSharedSecret(secretKeyA, publicKeyB, isCompressed = true) { | |
| if (isProbPub(secretKeyA) === true) | |
| throw new Error("first arg must be private key"); | |
| if (isProbPub(publicKeyB) === false) | |
| throw new Error("second arg must be public key"); | |
| const s = Fn.fromBytes(secretKeyA); | |
| const b = Point.fromBytes(publicKeyB); | |
| return b.multiply(s).toBytes(isCompressed); | |
| } | |
| const utils = { | |
| isValidSecretKey, | |
| isValidPublicKey, | |
| randomSecretKey | |
| }; | |
| const keygen = createKeygen(randomSecretKey, getPublicKey); | |
| return Object.freeze({ getPublicKey, getSharedSecret, keygen, Point, utils, lengths }); | |
| } | |
| function ecdsa(Point, hash, ecdsaOpts = {}) { | |
| ahash(hash); | |
| validateObject(ecdsaOpts, {}, { | |
| hmac: "function", | |
| lowS: "boolean", | |
| randomBytes: "function", | |
| bits2int: "function", | |
| bits2int_modN: "function" | |
| }); | |
| ecdsaOpts = Object.assign({}, ecdsaOpts); | |
| const randomBytes2 = ecdsaOpts.randomBytes || randomBytes; | |
| const hmac2 = ecdsaOpts.hmac || ((key, msg) => hmac(hash, key, msg)); | |
| const { Fp, Fn } = Point; | |
| const { ORDER: CURVE_ORDER, BITS: fnBits } = Fn; | |
| const { keygen, getPublicKey, getSharedSecret, utils, lengths } = ecdh(Point, ecdsaOpts); | |
| const defaultSigOpts = { | |
| prehash: true, | |
| lowS: typeof ecdsaOpts.lowS === "boolean" ? ecdsaOpts.lowS : true, | |
| format: "compact", | |
| extraEntropy: false | |
| }; | |
| const hasLargeCofactor = CURVE_ORDER * _2n2 < Fp.ORDER; | |
| function isBiggerThanHalfOrder(number) { | |
| const HALF = CURVE_ORDER >> _1n4; | |
| return number > HALF; | |
| } | |
| function validateRS(title, num) { | |
| if (!Fn.isValidNot0(num)) | |
| throw new Error(`invalid signature ${title}: out of range 1..Point.Fn.ORDER`); | |
| return num; | |
| } | |
| function assertSmallCofactor() { | |
| if (hasLargeCofactor) | |
| throw new Error('"recovered" sig type is not supported for cofactor >2 curves'); | |
| } | |
| function validateSigLength(bytes, format) { | |
| validateSigFormat(format); | |
| const size = lengths.signature; | |
| const sizer = format === "compact" ? size : format === "recovered" ? size + 1 : undefined; | |
| return abytes(bytes, sizer); | |
| } | |
| class Signature { | |
| r; | |
| s; | |
| recovery; | |
| constructor(r, s, recovery) { | |
| this.r = validateRS("r", r); | |
| this.s = validateRS("s", s); | |
| if (recovery != null) { | |
| assertSmallCofactor(); | |
| if (![0, 1, 2, 3].includes(recovery)) | |
| throw new Error("invalid recovery id"); | |
| this.recovery = recovery; | |
| } | |
| Object.freeze(this); | |
| } | |
| static fromBytes(bytes, format = defaultSigOpts.format) { | |
| validateSigLength(bytes, format); | |
| let recid; | |
| if (format === "der") { | |
| const { r: r2, s: s2 } = DER.toSig(abytes(bytes)); | |
| return new Signature(r2, s2); | |
| } | |
| if (format === "recovered") { | |
| recid = bytes[0]; | |
| format = "compact"; | |
| bytes = bytes.subarray(1); | |
| } | |
| const L = lengths.signature / 2; | |
| const r = bytes.subarray(0, L); | |
| const s = bytes.subarray(L, L * 2); | |
| return new Signature(Fn.fromBytes(r), Fn.fromBytes(s), recid); | |
| } | |
| static fromHex(hex, format) { | |
| return this.fromBytes(hexToBytes(hex), format); | |
| } | |
| assertRecovery() { | |
| const { recovery } = this; | |
| if (recovery == null) | |
| throw new Error("invalid recovery id: must be present"); | |
| return recovery; | |
| } | |
| addRecoveryBit(recovery) { | |
| return new Signature(this.r, this.s, recovery); | |
| } | |
| recoverPublicKey(messageHash) { | |
| const { r, s } = this; | |
| const recovery = this.assertRecovery(); | |
| const radj = recovery === 2 || recovery === 3 ? r + CURVE_ORDER : r; | |
| if (!Fp.isValid(radj)) | |
| throw new Error("invalid recovery id: sig.r+curve.n != R.x"); | |
| const x = Fp.toBytes(radj); | |
| const R = Point.fromBytes(concatBytes(pprefix((recovery & 1) === 0), x)); | |
| const ir = Fn.inv(radj); | |
| const h = bits2int_modN(abytes(messageHash, undefined, "msgHash")); | |
| const u1 = Fn.create(-h * ir); | |
| const u2 = Fn.create(s * ir); | |
| const Q = Point.BASE.multiplyUnsafe(u1).add(R.multiplyUnsafe(u2)); | |
| if (Q.is0()) | |
| throw new Error("invalid recovery: point at infinify"); | |
| Q.assertValidity(); | |
| return Q; | |
| } | |
| hasHighS() { | |
| return isBiggerThanHalfOrder(this.s); | |
| } | |
| toBytes(format = defaultSigOpts.format) { | |
| validateSigFormat(format); | |
| if (format === "der") | |
| return hexToBytes(DER.hexFromSig(this)); | |
| const { r, s } = this; | |
| const rb = Fn.toBytes(r); | |
| const sb = Fn.toBytes(s); | |
| if (format === "recovered") { | |
| assertSmallCofactor(); | |
| return concatBytes(Uint8Array.of(this.assertRecovery()), rb, sb); | |
| } | |
| return concatBytes(rb, sb); | |
| } | |
| toHex(format) { | |
| return bytesToHex(this.toBytes(format)); | |
| } | |
| } | |
| const bits2int = ecdsaOpts.bits2int || function bits2int_def(bytes) { | |
| if (bytes.length > 8192) | |
| throw new Error("input is too large"); | |
| const num = bytesToNumberBE(bytes); | |
| const delta = bytes.length * 8 - fnBits; | |
| return delta > 0 ? num >> BigInt(delta) : num; | |
| }; | |
| const bits2int_modN = ecdsaOpts.bits2int_modN || function bits2int_modN_def(bytes) { | |
| return Fn.create(bits2int(bytes)); | |
| }; | |
| const ORDER_MASK = bitMask(fnBits); | |
| function int2octets(num) { | |
| aInRange("num < 2^" + fnBits, num, _0n4, ORDER_MASK); | |
| return Fn.toBytes(num); | |
| } | |
| function validateMsgAndHash(message, prehash) { | |
| abytes(message, undefined, "message"); | |
| return prehash ? abytes(hash(message), undefined, "prehashed message") : message; | |
| } | |
| function prepSig(message, secretKey, opts) { | |
| const { lowS, prehash, extraEntropy } = validateSigOpts(opts, defaultSigOpts); | |
| message = validateMsgAndHash(message, prehash); | |
| const h1int = bits2int_modN(message); | |
| const d = Fn.fromBytes(secretKey); | |
| if (!Fn.isValidNot0(d)) | |
| throw new Error("invalid private key"); | |
| const seedArgs = [int2octets(d), int2octets(h1int)]; | |
| if (extraEntropy != null && extraEntropy !== false) { | |
| const e = extraEntropy === true ? randomBytes2(lengths.secretKey) : extraEntropy; | |
| seedArgs.push(abytes(e, undefined, "extraEntropy")); | |
| } | |
| const seed = concatBytes(...seedArgs); | |
| const m = h1int; | |
| function k2sig(kBytes) { | |
| const k = bits2int(kBytes); | |
| if (!Fn.isValidNot0(k)) | |
| return; | |
| const ik = Fn.inv(k); | |
| const q = Point.BASE.multiply(k).toAffine(); | |
| const r = Fn.create(q.x); | |
| if (r === _0n4) | |
| return; | |
| const s = Fn.create(ik * Fn.create(m + r * d)); | |
| if (s === _0n4) | |
| return; | |
| let recovery = (q.x === r ? 0 : 2) | Number(q.y & _1n4); | |
| let normS = s; | |
| if (lowS && isBiggerThanHalfOrder(s)) { | |
| normS = Fn.neg(s); | |
| recovery ^= 1; | |
| } | |
| return new Signature(r, normS, hasLargeCofactor ? undefined : recovery); | |
| } | |
| return { seed, k2sig }; | |
| } | |
| function sign(message, secretKey, opts = {}) { | |
| const { seed, k2sig } = prepSig(message, secretKey, opts); | |
| const drbg = createHmacDrbg(hash.outputLen, Fn.BYTES, hmac2); | |
| const sig = drbg(seed, k2sig); | |
| return sig.toBytes(opts.format); | |
| } | |
| function verify(signature, message, publicKey, opts = {}) { | |
| const { lowS, prehash, format } = validateSigOpts(opts, defaultSigOpts); | |
| publicKey = abytes(publicKey, undefined, "publicKey"); | |
| message = validateMsgAndHash(message, prehash); | |
| if (!isBytes(signature)) { | |
| const end = signature instanceof Signature ? ", use sig.toBytes()" : ""; | |
| throw new Error("verify expects Uint8Array signature" + end); | |
| } | |
| validateSigLength(signature, format); | |
| try { | |
| const sig = Signature.fromBytes(signature, format); | |
| const P = Point.fromBytes(publicKey); | |
| if (lowS && sig.hasHighS()) | |
| return false; | |
| const { r, s } = sig; | |
| const h = bits2int_modN(message); | |
| const is = Fn.inv(s); | |
| const u1 = Fn.create(h * is); | |
| const u2 = Fn.create(r * is); | |
| const R = Point.BASE.multiplyUnsafe(u1).add(P.multiplyUnsafe(u2)); | |
| if (R.is0()) | |
| return false; | |
| const v = Fn.create(R.x); | |
| return v === r; | |
| } catch (e) { | |
| return false; | |
| } | |
| } | |
| function recoverPublicKey(signature, message, opts = {}) { | |
| const { prehash } = validateSigOpts(opts, defaultSigOpts); | |
| message = validateMsgAndHash(message, prehash); | |
| return Signature.fromBytes(signature, "recovered").recoverPublicKey(message).toBytes(); | |
| } | |
| return Object.freeze({ | |
| keygen, | |
| getPublicKey, | |
| getSharedSecret, | |
| utils, | |
| lengths, | |
| Point, | |
| sign, | |
| verify, | |
| recoverPublicKey, | |
| Signature, | |
| hash | |
| }); | |
| } | |
| // node_modules/@noble/curves/nist.js | |
| /*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */ | |
| var p256_CURVE = /* @__PURE__ */ (() => ({ | |
| p: BigInt("0xffffffff00000001000000000000000000000000ffffffffffffffffffffffff"), | |
| n: BigInt("0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551"), | |
| h: BigInt(1), | |
| a: BigInt("0xffffffff00000001000000000000000000000000fffffffffffffffffffffffc"), | |
| b: BigInt("0x5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b"), | |
| Gx: BigInt("0x6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296"), | |
| Gy: BigInt("0x4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5") | |
| }))(); | |
| var p256_Point = /* @__PURE__ */ weierstrass(p256_CURVE); | |
| var p256 = /* @__PURE__ */ ecdsa(p256_Point, sha256); | |
| // node_modules/@noble/curves/abstract/montgomery.js | |
| /*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */ | |
| var _0n5 = BigInt(0); | |
| var _1n5 = BigInt(1); | |
| var _2n3 = BigInt(2); | |
| function validateOpts(curve) { | |
| validateObject(curve, { | |
| adjustScalarBytes: "function", | |
| powPminus2: "function" | |
| }); | |
| return Object.freeze({ ...curve }); | |
| } | |
| function montgomery(curveDef) { | |
| const CURVE = validateOpts(curveDef); | |
| const { P, type, adjustScalarBytes, powPminus2, randomBytes: rand } = CURVE; | |
| const is25519 = type === "x25519"; | |
| if (!is25519 && type !== "x448") | |
| throw new Error("invalid type"); | |
| const randomBytes_ = rand || randomBytes; | |
| const montgomeryBits = is25519 ? 255 : 448; | |
| const fieldLen = is25519 ? 32 : 56; | |
| const Gu = is25519 ? BigInt(9) : BigInt(5); | |
| const a24 = is25519 ? BigInt(121665) : BigInt(39081); | |
| const minScalar = is25519 ? _2n3 ** BigInt(254) : _2n3 ** BigInt(447); | |
| const maxAdded = is25519 ? BigInt(8) * _2n3 ** BigInt(251) - _1n5 : BigInt(4) * _2n3 ** BigInt(445) - _1n5; | |
| const maxScalar = minScalar + maxAdded + _1n5; | |
| const modP = (n) => mod(n, P); | |
| const GuBytes = encodeU(Gu); | |
| function encodeU(u) { | |
| return numberToBytesLE(modP(u), fieldLen); | |
| } | |
| function decodeU(u) { | |
| const _u = copyBytes(abytes(u, fieldLen, "uCoordinate")); | |
| if (is25519) | |
| _u[31] &= 127; | |
| return modP(bytesToNumberLE(_u)); | |
| } | |
| function decodeScalar(scalar) { | |
| return bytesToNumberLE(adjustScalarBytes(copyBytes(abytes(scalar, fieldLen, "scalar")))); | |
| } | |
| function scalarMult(scalar, u) { | |
| const pu = montgomeryLadder(decodeU(u), decodeScalar(scalar)); | |
| if (pu === _0n5) | |
| throw new Error("invalid private or public key received"); | |
| return encodeU(pu); | |
| } | |
| function scalarMultBase(scalar) { | |
| return scalarMult(scalar, GuBytes); | |
| } | |
| const getPublicKey = scalarMultBase; | |
| const getSharedSecret = scalarMult; | |
| function cswap(swap, x_2, x_3) { | |
| const dummy = modP(swap * (x_2 - x_3)); | |
| x_2 = modP(x_2 - dummy); | |
| x_3 = modP(x_3 + dummy); | |
| return { x_2, x_3 }; | |
| } | |
| function montgomeryLadder(u, scalar) { | |
| aInRange("u", u, _0n5, P); | |
| aInRange("scalar", scalar, minScalar, maxScalar); | |
| const k = scalar; | |
| const x_1 = u; | |
| let x_2 = _1n5; | |
| let z_2 = _0n5; | |
| let x_3 = u; | |
| let z_3 = _1n5; | |
| let swap = _0n5; | |
| for (let t = BigInt(montgomeryBits - 1);t >= _0n5; t--) { | |
| const k_t = k >> t & _1n5; | |
| swap ^= k_t; | |
| ({ x_2, x_3 } = cswap(swap, x_2, x_3)); | |
| ({ x_2: z_2, x_3: z_3 } = cswap(swap, z_2, z_3)); | |
| swap = k_t; | |
| const A = x_2 + z_2; | |
| const AA = modP(A * A); | |
| const B = x_2 - z_2; | |
| const BB = modP(B * B); | |
| const E = AA - BB; | |
| const C = x_3 + z_3; | |
| const D = x_3 - z_3; | |
| const DA = modP(D * A); | |
| const CB = modP(C * B); | |
| const dacb = DA + CB; | |
| const da_cb = DA - CB; | |
| x_3 = modP(dacb * dacb); | |
| z_3 = modP(x_1 * modP(da_cb * da_cb)); | |
| x_2 = modP(AA * BB); | |
| z_2 = modP(E * (AA + modP(a24 * E))); | |
| } | |
| ({ x_2, x_3 } = cswap(swap, x_2, x_3)); | |
| ({ x_2: z_2, x_3: z_3 } = cswap(swap, z_2, z_3)); | |
| const z2 = powPminus2(z_2); | |
| return modP(x_2 * z2); | |
| } | |
| const lengths = { | |
| secretKey: fieldLen, | |
| publicKey: fieldLen, | |
| seed: fieldLen | |
| }; | |
| const randomSecretKey = (seed = randomBytes_(fieldLen)) => { | |
| abytes(seed, lengths.seed, "seed"); | |
| return seed; | |
| }; | |
| const utils = { randomSecretKey }; | |
| return Object.freeze({ | |
| keygen: createKeygen(randomSecretKey, getPublicKey), | |
| getSharedSecret, | |
| getPublicKey, | |
| scalarMult, | |
| scalarMultBase, | |
| utils, | |
| GuBytes: GuBytes.slice(), | |
| lengths | |
| }); | |
| } | |
| // node_modules/@noble/curves/ed25519.js | |
| /*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */ | |
| var _1n6 = BigInt(1); | |
| var _2n4 = BigInt(2); | |
| var _3n3 = /* @__PURE__ */ BigInt(3); | |
| var _5n2 = BigInt(5); | |
| var _8n2 = BigInt(8); | |
| var ed25519_CURVE_p = BigInt("0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffed"); | |
| function ed25519_pow_2_252_3(x) { | |
| const _10n = BigInt(10), _20n = BigInt(20), _40n = BigInt(40), _80n = BigInt(80); | |
| const P = ed25519_CURVE_p; | |
| const x2 = x * x % P; | |
| const b2 = x2 * x % P; | |
| const b4 = pow2(b2, _2n4, P) * b2 % P; | |
| const b5 = pow2(b4, _1n6, P) * x % P; | |
| const b10 = pow2(b5, _5n2, P) * b5 % P; | |
| const b20 = pow2(b10, _10n, P) * b10 % P; | |
| const b40 = pow2(b20, _20n, P) * b20 % P; | |
| const b80 = pow2(b40, _40n, P) * b40 % P; | |
| const b160 = pow2(b80, _80n, P) * b80 % P; | |
| const b240 = pow2(b160, _80n, P) * b80 % P; | |
| const b250 = pow2(b240, _10n, P) * b10 % P; | |
| const pow_p_5_8 = pow2(b250, _2n4, P) * x % P; | |
| return { pow_p_5_8, b2 }; | |
| } | |
| function adjustScalarBytes(bytes) { | |
| bytes[0] &= 248; | |
| bytes[31] &= 127; | |
| bytes[31] |= 64; | |
| return bytes; | |
| } | |
| var x25519 = /* @__PURE__ */ (() => { | |
| const P = ed25519_CURVE_p; | |
| return montgomery({ | |
| P, | |
| type: "x25519", | |
| powPminus2: (x) => { | |
| const { pow_p_5_8, b2 } = ed25519_pow_2_252_3(x); | |
| return mod(pow2(pow_p_5_8, _3n3, P) * b2, P); | |
| }, | |
| adjustScalarBytes | |
| }); | |
| })(); | |
| // node_modules/quico/libs/crypto.js | |
| import * as crypto from "crypto"; | |
| // node_modules/quico/libs/utils.js | |
| function writeVarInt(value) { | |
| if (value < 64) { | |
| return new Uint8Array([value]); | |
| } | |
| if (value < 16384) { | |
| return new Uint8Array([ | |
| 64 | value >> 8, | |
| value & 255 | |
| ]); | |
| } | |
| if (value < 1073741824) { | |
| return new Uint8Array([ | |
| 128 | value >> 24, | |
| value >> 16 & 255, | |
| value >> 8 & 255, | |
| value & 255 | |
| ]); | |
| } | |
| if (value <= Number.MAX_SAFE_INTEGER) { | |
| var hi = Math.floor(value / 2 ** 32); | |
| var lo = value >>> 0; | |
| return new Uint8Array([ | |
| 192 | hi >> 24, | |
| hi >> 16 & 255, | |
| hi >> 8 & 255, | |
| hi & 255, | |
| lo >> 24 & 255, | |
| lo >> 16 & 255, | |
| lo >> 8 & 255, | |
| lo & 255 | |
| ]); | |
| } | |
| throw new Error("Value too large for QUIC VarInt"); | |
| } | |
| function readVarInt(array, offset) { | |
| if (offset >= array.length) | |
| return null; | |
| var first = array[offset]; | |
| var prefix = first >> 6; | |
| if (prefix === 0) { | |
| return { | |
| value: first & 63, | |
| byteLength: 1 | |
| }; | |
| } | |
| if (prefix === 1) { | |
| if (offset + 1 >= array.length) | |
| return null; | |
| var value = (first & 63) << 8 | array[offset + 1]; | |
| return { | |
| value, | |
| byteLength: 2 | |
| }; | |
| } | |
| if (prefix === 2) { | |
| if (offset + 3 >= array.length) | |
| return null; | |
| var value = ((first & 63) << 24 | array[offset + 1] << 16 | array[offset + 2] << 8 | array[offset + 3]) >>> 0; | |
| return { | |
| value, | |
| byteLength: 4 | |
| }; | |
| } | |
| if (prefix === 3) { | |
| if (offset + 7 >= array.length) | |
| return null; | |
| var hi = ((first & 63) << 24 | array[offset + 1] << 16 | array[offset + 2] << 8 | array[offset + 3]) >>> 0; | |
| var lo = (array[offset + 4] << 24 | array[offset + 5] << 16 | array[offset + 6] << 8 | array[offset + 7]) >>> 0; | |
| var full = BigInt(hi) * 4294967296n + BigInt(lo); | |
| if (full <= BigInt(Number.MAX_SAFE_INTEGER)) { | |
| return { | |
| value: Number(full), | |
| byteLength: 8 | |
| }; | |
| } else { | |
| return { | |
| value: full, | |
| byteLength: 8 | |
| }; | |
| } | |
| } | |
| return null; | |
| } | |
| function concatUint8Arrays(arrays) { | |
| var totalLength = 0; | |
| for (var i = 0;i < arrays.length; i++) { | |
| totalLength += arrays[i].length; | |
| } | |
| var result = new Uint8Array(totalLength); | |
| var offset = 0; | |
| for (var i = 0;i < arrays.length; i++) { | |
| result.set(arrays[i], offset); | |
| offset += arrays[i].length; | |
| } | |
| return result; | |
| } | |
| function arraybufferEqual(buf1, buf2) { | |
| if (buf1.byteLength !== buf2.byteLength) { | |
| return false; | |
| } | |
| var view1 = new DataView(buf1); | |
| var view2 = new DataView(buf2); | |
| for (var i = 0;i < buf1.byteLength; i++) { | |
| if (view1.getUint8(i) !== view2.getUint8(i)) { | |
| return false; | |
| } | |
| } | |
| return true; | |
| } | |
| function build_ack_info_from_ranges(flatRanges, ecnStats, ackDelay) { | |
| if (!flatRanges || flatRanges.length === 0) | |
| return null; | |
| if (flatRanges.length % 2 !== 0) | |
| throw new Error("flatRanges must be in [from, to, ...] pairs"); | |
| var ranges = []; | |
| for (var i = 0;i < flatRanges.length; i += 2) { | |
| var from = flatRanges[i]; | |
| var to = flatRanges[i + 1]; | |
| if (to < from) | |
| throw new Error("Range end must be >= start"); | |
| ranges.push({ start: from, end: to }); | |
| } | |
| ranges.sort((a, b) => b.end - a.end); | |
| var merged = [ranges[0]]; | |
| for (var i = 1;i < ranges.length; i++) { | |
| var last = merged[merged.length - 1]; | |
| var curr = ranges[i]; | |
| if (curr.end >= last.start - 1) { | |
| last.start = Math.min(last.start, curr.start); | |
| } else { | |
| merged.push(curr); | |
| } | |
| } | |
| var largest = merged[0].end; | |
| var firstRange = largest - merged[0].start; | |
| var ackRanges = []; | |
| for (var i = 1;i < merged.length; i++) { | |
| var gap = merged[i - 1].start - merged[i].end - 1; | |
| var length = merged[i].end - merged[i].start; | |
| ackRanges.push({ gap, length }); | |
| } | |
| return { | |
| type: "ack", | |
| largest, | |
| delay: ackDelay || 0, | |
| firstRange, | |
| ranges: ackRanges, | |
| ecn: ecnStats ? { | |
| ect0: ecnStats.ect0 || 0, | |
| ect1: ecnStats.ect1 || 0, | |
| ce: ecnStats.ce || 0 | |
| } : null | |
| }; | |
| } | |
| function quic_acked_info_to_ranges(ackFrame) { | |
| var flatRanges = []; | |
| if (!ackFrame || ackFrame.type !== "ack") | |
| return flatRanges; | |
| var largest = ackFrame.largest; | |
| var firstRange = ackFrame.firstRange; | |
| var rangeEnd = largest; | |
| var rangeStart = rangeEnd - firstRange; | |
| flatRanges.push(rangeStart, rangeEnd); | |
| var ranges = ackFrame.ranges || []; | |
| for (var i = 0;i < ranges.length; i++) { | |
| var { gap, length } = ranges[i]; | |
| rangeEnd = rangeStart - 1 - gap; | |
| rangeStart = rangeEnd - length; | |
| flatRanges.push(rangeStart, rangeEnd); | |
| } | |
| return flatRanges; | |
| } | |
| // node_modules/quico/libs/crypto.js | |
| var nobleHashes = { hmac, hkdf, hkdf_extract: extract, hkdf_expand: expand, sha256 }; | |
| function getHashFn(hashName) { | |
| if (hashName === "sha256") | |
| return sha256; | |
| if (hashName === "sha384") | |
| return sha384; | |
| throw new Error("Unsupported hash: " + hashName); | |
| } | |
| function build_quic_ext(params) { | |
| var out = []; | |
| function addParam(id, value) { | |
| var id_bytes = writeVarInt(id); | |
| var length_bytes, value_bytes; | |
| if (typeof value === "number") { | |
| value_bytes = writeVarInt(value); | |
| } else if (value instanceof Uint8Array) { | |
| value_bytes = Array.from(value); | |
| } else if (value === true) { | |
| value_bytes = []; | |
| } else { | |
| throw new Error("Unsupported value type for parameter " + id); | |
| } | |
| length_bytes = writeVarInt(value_bytes.length); | |
| out.push(...id_bytes, ...length_bytes, ...value_bytes); | |
| } | |
| if (params.original_destination_connection_id) | |
| addParam(0, params.original_destination_connection_id); | |
| if (params.max_idle_timeout) | |
| addParam(1, params.max_idle_timeout); | |
| if (params.stateless_reset_token) | |
| addParam(2, params.stateless_reset_token); | |
| if (params.max_udp_payload_size) | |
| addParam(3, params.max_udp_payload_size); | |
| if (params.initial_max_data) | |
| addParam(4, params.initial_max_data); | |
| if (params.initial_max_stream_data_bidi_local) | |
| addParam(5, params.initial_max_stream_data_bidi_local); | |
| if (params.initial_max_stream_data_bidi_remote) | |
| addParam(6, params.initial_max_stream_data_bidi_remote); | |
| if (params.initial_max_stream_data_uni) | |
| addParam(7, params.initial_max_stream_data_uni); | |
| if (params.initial_max_streams_bidi) | |
| addParam(8, params.initial_max_streams_bidi); | |
| if (params.initial_max_streams_uni) | |
| addParam(9, params.initial_max_streams_uni); | |
| if (params.ack_delay_exponent !== undefined) | |
| addParam(10, params.ack_delay_exponent); | |
| if (params.max_ack_delay !== undefined) | |
| addParam(11, params.max_ack_delay); | |
| if (params.disable_active_migration) | |
| addParam(12, true); | |
| if (params.active_connection_id_limit) | |
| addParam(14, params.active_connection_id_limit); | |
| if (params.initial_source_connection_id) | |
| addParam(15, params.initial_source_connection_id); | |
| if (params.retry_source_connection_id) | |
| addParam(16, params.retry_source_connection_id); | |
| if (params.max_datagram_frame_size) | |
| addParam(32, params.max_datagram_frame_size); | |
| if (params.web_accepted_origins) { | |
| for (var i = 0;i < params.web_accepted_origins.length; i++) { | |
| var origin = params.web_accepted_origins[i]; | |
| var origin_bytes = new TextEncoder().encode(origin); | |
| addParam(727725890, origin_bytes); | |
| } | |
| } | |
| return new Uint8Array(out); | |
| } | |
| function hkdf_extract2(salt, ikm, hash_func) { | |
| return nobleHashes.hkdf_extract(hash_func, ikm, salt); | |
| } | |
| function hkdf_expand2(prk, info, length, hash_func) { | |
| return nobleHashes.hkdf_expand(hash_func, prk, info, length); | |
| } | |
| function build_hkdf_label(label, context, length) { | |
| var prefix = "tls13 "; | |
| var full = new TextEncoder().encode(prefix + label); | |
| var info = new Uint8Array(2 + 1 + full.length + 1 + context.length); | |
| info[0] = length >> 8 & 255; | |
| info[1] = length & 255; | |
| info[2] = full.length; | |
| info.set(full, 3); | |
| var ctxOfs = 3 + full.length; | |
| info[ctxOfs] = context.length; | |
| info.set(context, ctxOfs + 1); | |
| return info; | |
| } | |
| function hkdf_expand_label(secret, label, context, length, hash_func) { | |
| var info = build_hkdf_label(label, context, length); | |
| return hkdf_expand2(secret, info, length, hash_func); | |
| } | |
| function aes_gcm_decrypt(ciphertext, tag, key, nonce, aad) { | |
| try { | |
| var algo = key.length === 32 ? "aes-256-gcm" : key.length === 16 ? "aes-128-gcm" : (() => { | |
| throw new Error("Unsupported key length: " + key.length); | |
| })(); | |
| var decipher = crypto.createDecipheriv(algo, Buffer.from(key), Buffer.from(nonce)); | |
| decipher.setAuthTag(Buffer.from(tag)); | |
| decipher.setAAD(Buffer.from(aad)); | |
| var decrypted = Buffer.concat([ | |
| decipher.update(Buffer.from(ciphertext)), | |
| decipher.final() | |
| ]); | |
| return new Uint8Array(decrypted); | |
| } catch (e) { | |
| return null; | |
| } | |
| } | |
| var INITIAL_SALTS = { | |
| 1: new Uint8Array([ | |
| 56, | |
| 118, | |
| 44, | |
| 247, | |
| 245, | |
| 89, | |
| 52, | |
| 179, | |
| 77, | |
| 23, | |
| 154, | |
| 230, | |
| 164, | |
| 200, | |
| 12, | |
| 173, | |
| 204, | |
| 187, | |
| 127, | |
| 10 | |
| ]), | |
| 4278190109: new Uint8Array([ | |
| 175, | |
| 191, | |
| 236, | |
| 40, | |
| 153, | |
| 147, | |
| 210, | |
| 76, | |
| 158, | |
| 151, | |
| 134, | |
| 241, | |
| 156, | |
| 97, | |
| 17, | |
| 224, | |
| 67, | |
| 144, | |
| 168, | |
| 153 | |
| ]), | |
| 4278190112: new Uint8Array([ | |
| 127, | |
| 188, | |
| 219, | |
| 14, | |
| 124, | |
| 102, | |
| 187, | |
| 119, | |
| 123, | |
| 227, | |
| 14, | |
| 189, | |
| 95, | |
| 165, | |
| 21, | |
| 135, | |
| 61, | |
| 141, | |
| 110, | |
| 103 | |
| ]), | |
| 1362113840: new Uint8Array([ | |
| 105, | |
| 69, | |
| 111, | |
| 190, | |
| 241, | |
| 110, | |
| 215, | |
| 220, | |
| 72, | |
| 21, | |
| 157, | |
| 152, | |
| 208, | |
| 127, | |
| 92, | |
| 60, | |
| 61, | |
| 90, | |
| 167, | |
| 10 | |
| ]) | |
| }; | |
| function quic_derive_init_secrets(client_dcid, version, direction) { | |
| var hash_func = sha256; | |
| var salt = INITIAL_SALTS[version] || null; | |
| if (!salt) | |
| throw new Error("Unsupported QUIC version: 0x" + version.toString(16)); | |
| var label = direction === "read" ? "client in" : "server in"; | |
| var initial_secret = hkdf_extract2(salt, client_dcid, hash_func); | |
| var initial_secret2 = hkdf_expand_label(initial_secret, label, new Uint8Array(0), 32, hash_func); | |
| var key = hkdf_expand_label(initial_secret2, "quic key", new Uint8Array(0), 16, hash_func); | |
| var iv = hkdf_expand_label(initial_secret2, "quic iv", new Uint8Array(0), 12, hash_func); | |
| var hp = hkdf_expand_label(initial_secret2, "quic hp", new Uint8Array(0), 16, hash_func); | |
| return { key, iv, hp }; | |
| } | |
| function quic_derive_from_tls_secrets(traffic_secret, hash_name) { | |
| var hash_func = getHashFn(hash_name); | |
| if (traffic_secret) { | |
| var key = hkdf_expand_label(traffic_secret, "quic key", new Uint8Array(0), 16, hash_func); | |
| var iv = hkdf_expand_label(traffic_secret, "quic iv", new Uint8Array(0), 12, hash_func); | |
| var hp = hkdf_expand_label(traffic_secret, "quic hp", new Uint8Array(0), 16, hash_func); | |
| return { key, iv, hp }; | |
| } | |
| } | |
| function compute_nonce(iv, packetNumber) { | |
| var nonce = new Uint8Array(iv); | |
| var pnBuffer = new Uint8Array(12); | |
| var n = packetNumber; | |
| for (var i = 11;n > 0 && i >= 0; i--) { | |
| pnBuffer[i] = n & 255; | |
| n >>= 8; | |
| } | |
| for (var i = 0;i < 12; i++) { | |
| nonce[i] ^= pnBuffer[i]; | |
| } | |
| return nonce; | |
| } | |
| function aes_ecb_encrypt(keyBytes, plaintext) { | |
| if (keyBytes.length !== 16 && keyBytes.length !== 24 && keyBytes.length !== 32) { | |
| throw new Error("Invalid AES key size"); | |
| } | |
| if (plaintext.length % 16 !== 0) { | |
| throw new Error("Plaintext must be a multiple of 16 bytes"); | |
| } | |
| var cipher = crypto.createCipheriv("aes-" + keyBytes.length * 8 + "-ecb", keyBytes, null); | |
| cipher.setAutoPadding(false); | |
| var encrypted = Buffer.concat([cipher.update(plaintext), cipher.final()]); | |
| return new Uint8Array(encrypted); | |
| } | |
| function aead_encrypt(key, iv, packetNumber, plaintext, aad) { | |
| try { | |
| var algo = key.length === 32 ? "aes-256-gcm" : key.length === 16 ? "aes-128-gcm" : (() => { | |
| throw new Error("Unsupported key length: " + key.length); | |
| })(); | |
| var nonce = compute_nonce(iv, packetNumber); | |
| var cipher = crypto.createCipheriv(algo, Buffer.from(key), Buffer.from(nonce)); | |
| cipher.setAAD(Buffer.from(aad)); | |
| var encrypted = Buffer.concat([ | |
| cipher.update(Buffer.from(plaintext)), | |
| cipher.final() | |
| ]); | |
| var tag = cipher.getAuthTag(); | |
| var result = new Uint8Array(encrypted.length + tag.length); | |
| result.set(encrypted, 0); | |
| result.set(tag, encrypted.length); | |
| return result; | |
| } catch (e) { | |
| return null; | |
| } | |
| } | |
| function apply_header_protection(packet, pnOffset, hpKey, pnLength) { | |
| var sample = packet.slice(pnOffset + 4, pnOffset + 4 + 16); | |
| if (sample.length < 16) | |
| throw new Error("Not enough bytes for header protection sample"); | |
| var maskFull = aes_ecb_encrypt(hpKey, sample); | |
| var mask = maskFull.slice(0, 5); | |
| var firstByte = packet[0]; | |
| var isLongHeader = (firstByte & 128) !== 0; | |
| if (isLongHeader) { | |
| packet[0] ^= mask[0] & 15; | |
| } else { | |
| packet[0] ^= mask[0] & 31; | |
| } | |
| for (var i = 0;i < pnLength; i++) { | |
| packet[pnOffset + i] ^= mask[1 + i]; | |
| } | |
| return packet; | |
| } | |
| function aes128ecb(sample, hpKey) { | |
| var cipher = crypto.createCipheriv("aes-128-ecb", Buffer.from(hpKey), null); | |
| cipher.setAutoPadding(false); | |
| var input = Buffer.from(sample); | |
| return new Uint8Array(Buffer.concat([cipher.update(input), cipher.final()])); | |
| } | |
| function expandPacketNumber(truncated, pnLen, largestReceived) { | |
| var pnWin = 1 << pnLen * 8; | |
| var pnHalf = pnWin >>> 1; | |
| var expected = largestReceived + 1; | |
| return truncated + pnWin * Math.floor((expected - truncated + pnHalf) / pnWin); | |
| } | |
| function decode_packet_number(array, offset, pnLength) { | |
| var value = 0; | |
| for (var i = 0;i < pnLength; i++) { | |
| value = value << 8 | array[offset + i]; | |
| } | |
| return value; | |
| } | |
| function decode_and_expand_packet_number(array, offset, pnLength, largestReceived) { | |
| var truncated = decode_packet_number(array, offset, pnLength); | |
| return expandPacketNumber(truncated, pnLength, largestReceived); | |
| } | |
| function remove_header_protection(array, pnOffset, hpKey, isShort) { | |
| var sampleOffset = pnOffset + 4; | |
| var sample = array.slice(sampleOffset, sampleOffset + 16); | |
| var mask = aes128ecb(sample, hpKey).slice(0, 5); | |
| var firstByte = array[0]; | |
| if (isShort) { | |
| array[0] ^= mask[0] & 31; | |
| } else { | |
| array[0] ^= mask[0] & 15; | |
| } | |
| var pnLength = (array[0] & 3) + 1; | |
| for (var i = 0;i < pnLength; i++) { | |
| array[pnOffset + i] ^= mask[1 + i]; | |
| } | |
| return pnLength; | |
| } | |
| function decrypt_quic_packet(array, read_key, read_iv, read_hp, dcid, largest_pn) { | |
| if (!(array instanceof Uint8Array)) | |
| throw new Error("Invalid input"); | |
| var firstByte = array[0]; | |
| var isShort = (firstByte & 128) === 0; | |
| var isLong = !isShort; | |
| var keyPhase = false; | |
| var pnOffset = 0; | |
| var pnLength = 0; | |
| var aad = null; | |
| var ciphertext = null; | |
| var tag = null; | |
| var packetNumber = null; | |
| var nonce = null; | |
| if (isLong) { | |
| var view = new DataView(array.buffer, array.byteOffset, array.byteLength); | |
| var version = view.getUint32(1); | |
| var dcidLen = array[5]; | |
| var offset = 6; | |
| var parsed_dcid = array.slice(offset, offset + dcidLen); | |
| offset += dcidLen; | |
| var scidLen = array[offset++]; | |
| var scid = array.slice(offset, offset + scidLen); | |
| offset += scidLen; | |
| var typeBits = (firstByte & 48) >> 4; | |
| var typeMap = ["initial", "0rtt", "handshake", "retry"]; | |
| var packetType = typeMap[typeBits]; | |
| if (packetType === "initial") { | |
| var tokenLen = readVarInt(array, offset); | |
| offset += tokenLen.byteLength + tokenLen.value; | |
| } | |
| var len = readVarInt(array, offset); | |
| offset += len.byteLength; | |
| pnOffset = offset; | |
| pnLength = remove_header_protection(array, pnOffset, read_hp, false); | |
| if (pnLength !== null) { | |
| packetNumber = decode_and_expand_packet_number(array, pnOffset, pnLength, largest_pn); | |
| nonce = compute_nonce(read_iv, packetNumber); | |
| var payloadStart = pnOffset + pnLength; | |
| var payloadLength = len.value - pnLength; | |
| var payloadEnd = payloadStart + payloadLength; | |
| if (payloadEnd > array.length) | |
| throw new Error("Truncated long header packet"); | |
| var payload = array.slice(payloadStart, payloadEnd); | |
| if (payload.length < 16) | |
| throw new Error("Encrypted payload too short"); | |
| ciphertext = payload.slice(0, payload.length - 16); | |
| tag = payload.slice(payload.length - 16); | |
| aad = array.slice(0, pnOffset + pnLength); | |
| } else { | |
| return null; | |
| } | |
| } else { | |
| var dcidLen = dcid.length; | |
| pnOffset = 1 + dcidLen; | |
| pnLength = remove_header_protection(array, pnOffset, read_hp, true); | |
| if (pnLength !== null) { | |
| keyPhase = Boolean((array[0] & 4) >>> 2); | |
| packetNumber = decode_and_expand_packet_number(array, pnOffset, pnLength, largest_pn); | |
| nonce = compute_nonce(read_iv, packetNumber); | |
| var payloadStart = pnOffset + pnLength; | |
| var payload = array.slice(payloadStart); | |
| if (payload.length < 16) | |
| throw new Error("Encrypted payload too short"); | |
| ciphertext = payload.slice(0, payload.length - 16); | |
| tag = payload.slice(payload.length - 16); | |
| aad = array.slice(0, pnOffset + pnLength); | |
| } else { | |
| return null; | |
| } | |
| } | |
| var plaintext = aes_gcm_decrypt(ciphertext, tag, read_key, nonce, aad); | |
| return { | |
| packet_number: packetNumber, | |
| key_phase: keyPhase, | |
| plaintext | |
| }; | |
| } | |
| function extract_tls_messages_from_chunks(chunks, from_offset) { | |
| var offset = from_offset; | |
| var buffers = []; | |
| while (chunks[offset]) { | |
| buffers.push(chunks[offset]); | |
| offset += chunks[offset].length; | |
| } | |
| if (buffers.length === 0) | |
| return false; | |
| var combined = concatUint8Arrays(buffers); | |
| var tls_messages = []; | |
| var i = 0; | |
| while (i + 4 <= combined.length) { | |
| var msgType = combined[i]; | |
| var length = combined[i + 1] << 16 | combined[i + 2] << 8 | combined[i + 3]; | |
| if (i + 4 + length > combined.length) | |
| break; | |
| var msg = combined.slice(i, i + 4 + length); | |
| tls_messages.push(msg); | |
| i += 4 + length; | |
| } | |
| if (i > 0) { | |
| var cleanupOffset = from_offset; | |
| while (cleanupOffset < from_offset + i) { | |
| var chunk = chunks[cleanupOffset]; | |
| delete chunks[cleanupOffset]; | |
| cleanupOffset += chunk.length; | |
| } | |
| if (i < combined.length) { | |
| var leftover = combined.slice(i); | |
| chunks[cleanupOffset] = leftover; | |
| } | |
| from_offset += i; | |
| } | |
| return { tls_messages, new_from_offset: from_offset }; | |
| } | |
| function encode_version(version) { | |
| return new Uint8Array([ | |
| version >>> 24 & 255, | |
| version >>> 16 & 255, | |
| version >>> 8 & 255, | |
| version & 255 | |
| ]); | |
| } | |
| function build_quic_header(packetType, dcid, scid, token, lengthField, pnLen) { | |
| var hdr = []; | |
| var firstByte; | |
| if (packetType === "initial") { | |
| firstByte = 192 | pnLen - 1 & 3; | |
| } else if (packetType === "handshake") { | |
| firstByte = 224 | pnLen - 1 & 3; | |
| } else if (packetType === "0rtt") { | |
| firstByte = 208 | pnLen - 1 & 3; | |
| } else if (packetType === "1rtt") { | |
| firstByte = 64 | pnLen - 1 & 3; | |
| hdr.push(Uint8Array.of(firstByte)); | |
| hdr.push(dcid); | |
| return { | |
| header: concatUint8Arrays(hdr), | |
| packetNumberOffset: hdr.reduce((sum, u82) => sum + u82.length, 0) | |
| }; | |
| } else { | |
| throw new Error("Unsupported packet type: " + packetType); | |
| } | |
| hdr.push(Uint8Array.of(firstByte)); | |
| hdr.push(encode_version(1)); | |
| hdr.push(writeVarInt(dcid.length), dcid); | |
| hdr.push(writeVarInt(scid.length), scid); | |
| if (packetType === "initial") { | |
| if (!token) | |
| token = new Uint8Array(0); | |
| hdr.push(writeVarInt(token.length), token); | |
| } | |
| hdr.push(lengthField); | |
| var header = concatUint8Arrays(hdr); | |
| return { | |
| header, | |
| packetNumberOffset: header.length | |
| }; | |
| } | |
| function encrypt_quic_packet(packetType, encodedFrames, writeKey, writeIv, writeHp, packetNumber, dcid, scid, token) { | |
| var pnLength; | |
| if (packetNumber <= 255) | |
| pnLength = 1; | |
| else if (packetNumber <= 65535) | |
| pnLength = 2; | |
| else if (packetNumber <= 16777215) | |
| pnLength = 3; | |
| else | |
| pnLength = 4; | |
| var pnFull = new Uint8Array(4); | |
| pnFull[0] = packetNumber >>> 24 & 255; | |
| pnFull[1] = packetNumber >>> 16 & 255; | |
| pnFull[2] = packetNumber >>> 8 & 255; | |
| pnFull[3] = packetNumber & 255; | |
| var packetNumberField = pnFull.slice(4 - pnLength); | |
| var unprotectedPayloadLength = encodedFrames.length + pnLength + 16; | |
| var lengthField = writeVarInt(unprotectedPayloadLength); | |
| var headerInfo = build_quic_header(packetType, dcid, scid, token, lengthField, pnLength); | |
| var header = headerInfo.header; | |
| var packetNumberOffset = headerInfo.packetNumberOffset; | |
| var fullHeader = concatUint8Arrays([header, packetNumberField]); | |
| var minSampleLength = 32; | |
| var minTotalLength = packetNumberOffset + pnLength + minSampleLength; | |
| var fullLength = header.length + pnLength + encodedFrames.length + 16; | |
| if (fullLength < minTotalLength) { | |
| var extraPadding = minTotalLength - (header.length + pnLength + encodedFrames.length); | |
| var padded = new Uint8Array(encodedFrames.length + extraPadding); | |
| padded.set(encodedFrames, 0); | |
| encodedFrames = padded; | |
| unprotectedPayloadLength = encodedFrames.length + pnLength + 16; | |
| lengthField = writeVarInt(unprotectedPayloadLength); | |
| headerInfo = build_quic_header(packetType, dcid, scid, token, lengthField, pnLength); | |
| header = headerInfo.header; | |
| packetNumberOffset = headerInfo.packetNumberOffset; | |
| fullHeader = concatUint8Arrays([header, packetNumberField]); | |
| } | |
| var ciphertext = aead_encrypt(writeKey, writeIv, packetNumber, encodedFrames, fullHeader); | |
| if (ciphertext == null) | |
| return null; | |
| var fullPacket = concatUint8Arrays([ | |
| header, | |
| packetNumberField, | |
| ciphertext | |
| ]); | |
| return apply_header_protection(fullPacket, packetNumberOffset, writeHp, pnLength); | |
| } | |
| function encode_quic_frames(frames) { | |
| var parts = []; | |
| var i; | |
| for (i = 0;i < frames.length; i++) { | |
| var frame = frames[i]; | |
| if (frame.type === "padding") { | |
| var pad = new Uint8Array(frame.length); | |
| for (var j = 0;j < pad.length; j++) | |
| pad[j] = 0; | |
| parts.push(pad); | |
| } else if (frame.type === "ping") { | |
| parts.push(new Uint8Array([1])); | |
| } else if (frame.type === "ack") { | |
| var hasECN = frame.ecn !== null && frame.ecn !== undefined; | |
| var typeByte = hasECN ? 3 : 2; | |
| var b1 = writeVarInt(frame.largest); | |
| var b2 = writeVarInt(frame.delay); | |
| var b3 = writeVarInt(frame.ranges.length); | |
| var b4 = writeVarInt(frame.firstRange != null ? frame.firstRange : 0); | |
| var temp = [new Uint8Array([typeByte]), b1, b2, b3, b4]; | |
| for (j = 0;j < frame.ranges.length; j++) { | |
| var gap = writeVarInt(frame.ranges[j].gap); | |
| var len = writeVarInt(frame.ranges[j].length); | |
| temp.push(gap, len); | |
| } | |
| if (hasECN) { | |
| temp.push(writeVarInt(frame.ecn.ect0), writeVarInt(frame.ecn.ect1), writeVarInt(frame.ecn.ce)); | |
| } | |
| parts.push(concatUint8Arrays(temp)); | |
| } else if (frame.type === "reset_stream") { | |
| var id = writeVarInt(frame.id); | |
| var err = new Uint8Array([frame.error >> 8, frame.error & 255]); | |
| var size = writeVarInt(frame.finalSize); | |
| parts.push(concatUint8Arrays([ | |
| new Uint8Array([4]), | |
| id, | |
| err, | |
| size | |
| ])); | |
| } else if (frame.type === "stop_sending") { | |
| var id = writeVarInt(frame.id); | |
| var err = new Uint8Array([frame.error >> 8, frame.error & 255]); | |
| parts.push(concatUint8Arrays([ | |
| new Uint8Array([5]), | |
| id, | |
| err | |
| ])); | |
| } else if (frame.type === "crypto") { | |
| var off = writeVarInt(frame.offset); | |
| var len = writeVarInt(frame.data.length); | |
| parts.push(concatUint8Arrays([ | |
| new Uint8Array([6]), | |
| off, | |
| len, | |
| frame.data | |
| ])); | |
| } else if (frame.type === "new_token") { | |
| var len = writeVarInt(frame.token.length); | |
| parts.push(concatUint8Arrays([ | |
| new Uint8Array([7]), | |
| len, | |
| frame.token | |
| ])); | |
| } else if (frame.type === "stream") { | |
| var typeByte = 8; | |
| var hasOffset = frame.offset != null; | |
| var hasLen = frame.data && frame.data.length > 0; | |
| var hasFin = !!frame.fin; | |
| if (hasOffset) | |
| typeByte |= 4; | |
| if (hasLen) | |
| typeByte |= 2; | |
| if (hasFin) | |
| typeByte |= 1; | |
| var id = writeVarInt(frame.id); | |
| var off = hasOffset ? writeVarInt(frame.offset) : new Uint8Array(0); | |
| var len = hasLen ? writeVarInt(frame.data.length) : new Uint8Array(0); | |
| parts.push(concatUint8Arrays([ | |
| new Uint8Array([typeByte]), | |
| id, | |
| off, | |
| len, | |
| frame.data | |
| ])); | |
| } else if (frame.type === "max_data") { | |
| parts.push(concatUint8Arrays([ | |
| new Uint8Array([9]), | |
| writeVarInt(frame.max) | |
| ])); | |
| } else if (frame.type === "max_stream_data") { | |
| parts.push(concatUint8Arrays([ | |
| new Uint8Array([10]), | |
| writeVarInt(frame.id), | |
| writeVarInt(frame.max) | |
| ])); | |
| } else if (frame.type === "max_streams_bidi" || frame.type === "max_streams_uni") { | |
| var code = frame.type === "max_streams_bidi" ? 11 : 12; | |
| parts.push(concatUint8Arrays([ | |
| new Uint8Array([code]), | |
| writeVarInt(frame.max) | |
| ])); | |
| } else if (frame.type === "data_blocked") { | |
| parts.push(concatUint8Arrays([ | |
| new Uint8Array([13]), | |
| writeVarInt(frame.limit) | |
| ])); | |
| } else if (frame.type === "stream_data_blocked") { | |
| parts.push(concatUint8Arrays([ | |
| new Uint8Array([14]), | |
| writeVarInt(frame.id), | |
| writeVarInt(frame.limit) | |
| ])); | |
| } else if (frame.type === "streams_blocked_bidi") { | |
| parts.push(concatUint8Arrays([ | |
| new Uint8Array([15]), | |
| writeVarInt(frame.limit) | |
| ])); | |
| } else if (frame.type === "streams_blocked_uni") { | |
| parts.push(concatUint8Arrays([ | |
| new Uint8Array([16]), | |
| writeVarInt(frame.limit) | |
| ])); | |
| } else if (frame.type === "new_connection_id") { | |
| parts.push(concatUint8Arrays([ | |
| new Uint8Array([17]), | |
| writeVarInt(frame.seq), | |
| writeVarInt(frame.retire), | |
| new Uint8Array([frame.connId.length]), | |
| frame.connId, | |
| frame.token | |
| ])); | |
| } else if (frame.type === "retire_connection_id") { | |
| parts.push(concatUint8Arrays([ | |
| new Uint8Array([18]), | |
| writeVarInt(frame.seq) | |
| ])); | |
| } else if (frame.type === "path_challenge" || frame.type === "path_response") { | |
| var code = frame.type === "path_challenge" ? 19 : 20; | |
| parts.push(concatUint8Arrays([ | |
| new Uint8Array([code]), | |
| frame.data | |
| ])); | |
| } else if (frame.type === "connection_close") { | |
| var code = frame.application ? 29 : 28; | |
| var err = new Uint8Array([frame.error >> 8, frame.error & 255]); | |
| var ft = frame.application ? new Uint8Array(0) : writeVarInt(frame.frameType); | |
| var reason = new TextEncoder().encode(frame.reason || ""); | |
| var reasonLen = writeVarInt(reason.length); | |
| parts.push(concatUint8Arrays([ | |
| new Uint8Array([code]), | |
| err, | |
| ft, | |
| reasonLen, | |
| reason | |
| ])); | |
| } else if (frame.type === "handshake_done") { | |
| parts.push(new Uint8Array([30])); | |
| } else if (frame.type === "datagram") { | |
| var firstByte; | |
| var prefixBytes; | |
| var payload = frame.data; | |
| if (frame.contextId != null) { | |
| firstByte = 49; | |
| var contextBytes = writeVarInt(frame.contextId); | |
| prefixBytes = concatUint8Arrays([ | |
| new Uint8Array([firstByte]), | |
| contextBytes | |
| ]); | |
| } else { | |
| firstByte = 48; | |
| prefixBytes = new Uint8Array([firstByte]); | |
| } | |
| parts.push(concatUint8Arrays([ | |
| prefixBytes, | |
| payload | |
| ])); | |
| } else {} | |
| } | |
| if (parts.length == 1) { | |
| return parts[0]; | |
| } else { | |
| return concatUint8Arrays(parts); | |
| } | |
| } | |
| function parse_quic_frames(buf) { | |
| var offset = 0; | |
| var frames = []; | |
| var textDecoder = new TextDecoder; | |
| function safeReadVarInt() { | |
| if (offset >= buf.length) | |
| return null; | |
| var res = readVarInt(buf, offset); | |
| if (!res || typeof res.byteLength !== "number") | |
| return null; | |
| offset += res.byteLength; | |
| return res; | |
| } | |
| while (offset < buf.length) { | |
| var start = offset; | |
| var type = buf[offset++]; | |
| if (type >= 128) { | |
| offset--; | |
| var t = safeReadVarInt(); | |
| if (!t) | |
| break; | |
| type = t.value; | |
| } | |
| if (type === 0) {} else if (type === 1) { | |
| frames.push({ type: "ping" }); | |
| } else if ((type & 254) === 2) { | |
| var hasECN = (type & 1) === 1; | |
| var largest = safeReadVarInt(); | |
| if (!largest) | |
| break; | |
| var delay = safeReadVarInt(); | |
| if (!delay) | |
| break; | |
| var rangeCount = safeReadVarInt(); | |
| if (!rangeCount) | |
| break; | |
| var firstRange = safeReadVarInt(); | |
| if (!firstRange) | |
| break; | |
| var ranges = []; | |
| for (var i = 0;i < rangeCount.value; i++) { | |
| var gap = safeReadVarInt(); | |
| if (!gap) | |
| break; | |
| var len = safeReadVarInt(); | |
| if (!len) | |
| break; | |
| ranges.push({ gap: gap.value, length: len.value }); | |
| } | |
| var ecn = null; | |
| if (hasECN) { | |
| var ect0 = safeReadVarInt(); | |
| if (!ect0) | |
| break; | |
| var ect1 = safeReadVarInt(); | |
| if (!ect1) | |
| break; | |
| var ce = safeReadVarInt(); | |
| if (!ce) | |
| break; | |
| ecn = { ect0: ect0.value, ect1: ect1.value, ce: ce.value }; | |
| } | |
| frames.push({ type: "ack", largest: largest.value, delay: delay.value, firstRange: firstRange.value, ranges, ecn }); | |
| } else if (type === 4) { | |
| var id = safeReadVarInt(); | |
| if (!id) | |
| break; | |
| if (offset + 2 > buf.length) | |
| break; | |
| var error = buf[offset++] << 8 | buf[offset++]; | |
| var finalSize = safeReadVarInt(); | |
| if (!finalSize) | |
| break; | |
| frames.push({ type: "reset_stream", id: id.value, error, finalSize: finalSize.value }); | |
| } else if (type === 5) { | |
| var id = safeReadVarInt(); | |
| if (!id) | |
| break; | |
| if (offset + 2 > buf.length) | |
| break; | |
| var error = buf[offset++] << 8 | buf[offset++]; | |
| frames.push({ type: "stop_sending", id: id.value, error }); | |
| } else if (type === 6) { | |
| var off = safeReadVarInt(); | |
| if (!off) | |
| break; | |
| var len = safeReadVarInt(); | |
| if (!len) | |
| break; | |
| if (offset + len.value > buf.length) | |
| break; | |
| var data = buf.slice(offset, offset + len.value); | |
| offset += len.value; | |
| frames.push({ type: "crypto", offset: off.value, data }); | |
| } else if (type === 7) { | |
| var len = safeReadVarInt(); | |
| if (!len) | |
| break; | |
| if (offset + len.value > buf.length) | |
| break; | |
| var token = buf.slice(offset, offset + len.value); | |
| offset += len.value; | |
| frames.push({ type: "new_token", token }); | |
| } else if ((type & 224) === 0) { | |
| var fin = !!(type & 1); | |
| var lenb = !!(type & 2); | |
| var offb = !!(type & 4); | |
| var stream_id = safeReadVarInt(); | |
| if (!stream_id) | |
| break; | |
| var offset_val = offb ? safeReadVarInt() : { value: 0 }; | |
| if (!offset_val) | |
| break; | |
| var length_val = lenb ? safeReadVarInt() : { value: buf.length - offset }; | |
| if (!length_val) | |
| break; | |
| if (offset + length_val.value > buf.length) | |
| break; | |
| var data = buf.slice(offset, offset + length_val.value); | |
| offset += length_val.value; | |
| frames.push({ | |
| type: "stream", | |
| id: stream_id.value, | |
| offset: offset_val.value, | |
| fin, | |
| data | |
| }); | |
| } else if (type === 9) { | |
| var max = safeReadVarInt(); | |
| if (!max) | |
| break; | |
| frames.push({ type: "max_data", max: max.value }); | |
| } else if (type === 10) { | |
| var id = safeReadVarInt(); | |
| if (!id) | |
| break; | |
| var max = safeReadVarInt(); | |
| if (!max) | |
| break; | |
| frames.push({ type: "max_stream_data", id: id.value, max: max.value }); | |
| } else if (type === 18 || type === 19) { | |
| var max = safeReadVarInt(); | |
| if (!max) | |
| break; | |
| frames.push({ type: type === 18 ? "max_streams_bidi" : "max_streams_uni", max: max.value }); | |
| } else if (type === 20) { | |
| var max = safeReadVarInt(); | |
| if (!max) | |
| break; | |
| frames.push({ type: "data_blocked", max: max.value }); | |
| } else if (type === 21) { | |
| var id = safeReadVarInt(); | |
| if (!id) | |
| break; | |
| frames.push({ type: "stream_data_blocked", id: id.value }); | |
| } else if (type === 22 || type === 23) { | |
| var max = safeReadVarInt(); | |
| if (!max) | |
| break; | |
| frames.push({ type: type === 22 ? "streams_blocked_bidi" : "streams_blocked_uni", max: max.value }); | |
| } else if (type === 24) { | |
| var seq = safeReadVarInt(); | |
| if (!seq) | |
| break; | |
| var retire = safeReadVarInt(); | |
| if (!retire) | |
| break; | |
| if (offset >= buf.length) | |
| break; | |
| var len = buf[offset++]; | |
| if (offset + len + 16 > buf.length) | |
| break; | |
| var connId = buf.slice(offset, offset + len); | |
| offset += len; | |
| var token = buf.slice(offset, offset + 16); | |
| offset += 16; | |
| frames.push({ type: "new_connection_id", seq: seq.value, retire: retire.value, connId, token }); | |
| } else if (type === 25) { | |
| var seq = safeReadVarInt(); | |
| if (!seq) | |
| break; | |
| frames.push({ type: "retire_connection_id", seq: seq.value }); | |
| } else if (type === 26 || type === 27) { | |
| if (offset + 8 > buf.length) | |
| break; | |
| var data = buf.slice(offset, offset + 8); | |
| offset += 8; | |
| frames.push({ type: type === 26 ? "path_challenge" : "path_response", data }); | |
| } else if (type === 28 || type === 29) { | |
| if (offset + 2 > buf.length) | |
| break; | |
| var error = buf[offset++] << 8 | buf[offset++]; | |
| var frameType = null; | |
| if (type === 28) { | |
| var ft = safeReadVarInt(); | |
| if (!ft) | |
| break; | |
| frameType = ft.value; | |
| } | |
| var reasonLen = safeReadVarInt(); | |
| if (!reasonLen) | |
| break; | |
| if (offset + reasonLen.value > buf.length) | |
| break; | |
| var reason = textDecoder.decode(buf.slice(offset, offset + reasonLen.value)); | |
| offset += reasonLen.value; | |
| frames.push({ type: "connection_close", application: type === 29, error, frameType, reason }); | |
| } else if (type === 30) { | |
| frames.push({ type: "handshake_done" }); | |
| } else if (type === 31) { | |
| frames.push({ type: "immediate_ack" }); | |
| } else if (type === 48 || type === 49) { | |
| var contextId = null; | |
| var len = null; | |
| if (type === 49) { | |
| var cid = safeReadVarInt(buf, offset); | |
| if (!cid) | |
| break; | |
| contextId = cid.value; | |
| offset = cid.nextOffset; | |
| } | |
| len = { value: buf.length - offset }; | |
| if (offset + len.value > buf.length) | |
| break; | |
| var data = buf.slice(offset, offset + len.value); | |
| offset += len.value; | |
| frames.push({ | |
| type: "datagram", | |
| contextId, | |
| data | |
| }); | |
| } else if (type === 175) { | |
| var seq = safeReadVarInt(); | |
| if (!seq) | |
| break; | |
| var packetTolerance = safeReadVarInt(); | |
| if (!packetTolerance) | |
| break; | |
| if (offset >= buf.length) | |
| break; | |
| var ackDelayExponent = buf[offset++]; | |
| var maxAckDelay = safeReadVarInt(); | |
| if (!maxAckDelay) | |
| break; | |
| frames.push({ | |
| type: "ack_frequency", | |
| seq: seq.value, | |
| packetTolerance: packetTolerance.value, | |
| ackDelayExponent, | |
| maxAckDelay: maxAckDelay.value | |
| }); | |
| } else if (type >= 354585600 && type <= 354585855) { | |
| frames.push({ type: "multipath_extension", frameType: type }); | |
| } else { | |
| frames.push({ type: "unknown", frameType: type, offset: start }); | |
| break; | |
| } | |
| } | |
| return frames; | |
| } | |
| function parse_quic_packet(array, offset0 = 0) { | |
| if (!(array instanceof Uint8Array)) | |
| return null; | |
| if (offset0 >= array.length) | |
| return null; | |
| var firstByte = array[offset0]; | |
| var isLongHeader = (firstByte & 128) !== 0; | |
| if (isLongHeader) { | |
| if (offset0 + 6 > array.length) | |
| return null; | |
| var version = (array[offset0 + 1] << 24 | array[offset0 + 2] << 16 | array[offset0 + 3] << 8 | array[offset0 + 4]) >>> 0; | |
| var dcidLen = array[offset0 + 5]; | |
| var offset = offset0 + 6; | |
| if (offset + dcidLen + 1 > array.length) | |
| return null; | |
| var dcid = array.slice(offset, offset + dcidLen); | |
| offset += dcidLen; | |
| var scidLen = array[offset++]; | |
| if (offset + scidLen > array.length) | |
| return null; | |
| var scid = array.slice(offset, offset + scidLen); | |
| offset += scidLen; | |
| if (version === 0) { | |
| var supportedVersions = []; | |
| while (offset + 4 <= array.length) { | |
| var v = array[offset] << 24 | array[offset + 1] << 16 | array[offset + 2] << 8 | array[offset + 3]; | |
| supportedVersions.push(v); | |
| offset += 4; | |
| } | |
| return { | |
| form: "long", | |
| type: "version_negotiation", | |
| version, | |
| dcid, | |
| scid, | |
| supportedVersions, | |
| totalLength: offset - offset0 | |
| }; | |
| } | |
| var packetTypeBits = (firstByte & 48) >> 4; | |
| var typeMap = ["initial", "0rtt", "handshake", "retry"]; | |
| var packetType = typeMap[packetTypeBits] || "unknown"; | |
| if (packetType === "retry") { | |
| var odcid = array.slice(offset); | |
| return { | |
| form: "long", | |
| type: "retry", | |
| version, | |
| dcid, | |
| scid, | |
| originalDestinationConnectionId: odcid, | |
| totalLength: array.length - offset0 | |
| }; | |
| } | |
| var token = null; | |
| if (packetType === "initial") { | |
| try { | |
| var tokenLen = readVarInt(array, offset); | |
| offset += tokenLen.byteLength; | |
| if (offset + tokenLen.value > array.length) | |
| return null; | |
| token = array.slice(offset, offset + tokenLen.value); | |
| offset += tokenLen.value; | |
| } catch (e) { | |
| return null; | |
| } | |
| } | |
| try { | |
| var lengthInfo = readVarInt(array, offset); | |
| offset += lengthInfo.byteLength; | |
| var payloadLength = lengthInfo.value; | |
| var totalLength = offset - offset0 + payloadLength; | |
| if (offset0 + totalLength > array.length) | |
| return null; | |
| return { | |
| form: "long", | |
| type: packetType, | |
| version, | |
| dcid, | |
| scid, | |
| token, | |
| totalLength | |
| }; | |
| } catch (e) { | |
| return null; | |
| } | |
| } else { | |
| var totalLength = array.length - offset0; | |
| return { | |
| form: "short", | |
| type: "1rtt", | |
| totalLength | |
| }; | |
| } | |
| } | |
| function parse_quic_datagram(array) { | |
| var packets = []; | |
| var offset = 0; | |
| while (offset < array.length) { | |
| var pkt = parse_quic_packet(array, offset); | |
| if (!pkt || !pkt.totalLength) | |
| break; | |
| var start = offset; | |
| var end = offset + pkt.totalLength; | |
| pkt.raw = start === 0 && end === array.length ? array : array.slice(start, end); | |
| packets.push(pkt); | |
| offset = end; | |
| } | |
| return packets; | |
| } | |
| // node_modules/quico/quic_socket.js | |
| import { createRequire } from "node:module"; | |
| // node_modules/lemon-tls/tls_session.js | |
| import * as crypto2 from "crypto"; | |
| // node_modules/lemon-tls/utils.js | |
| function concatUint8Arrays2(arrays) { | |
| var totalLength = 0; | |
| for (var i = 0;i < arrays.length; i++) { | |
| totalLength += arrays[i].length; | |
| } | |
| var result = new Uint8Array(totalLength); | |
| var offset = 0; | |
| for (var i = 0;i < arrays.length; i++) { | |
| result.set(arrays[i], offset); | |
| offset += arrays[i].length; | |
| } | |
| return result; | |
| } | |
| function arraybufferEqual2(buf1, buf2) { | |
| if (buf1.byteLength !== buf2.byteLength) { | |
| return false; | |
| } | |
| var view1 = new DataView(buf1); | |
| var view2 = new DataView(buf2); | |
| for (let i = 0;i < buf1.byteLength; i++) { | |
| if (view1.getUint8(i) !== view2.getUint8(i)) { | |
| return false; | |
| } | |
| } | |
| return true; | |
| } | |
| function arraysEqual(a, b) { | |
| if (a == null || b == null) | |
| return false; | |
| if (a.length !== b.length) | |
| return false; | |
| for (var i = 0;i < a.length; ++i) { | |
| if (typeof a[i] !== "undefined" && typeof b[i] !== "undefined" && a[i] !== null && b[i] !== null && typeof a[i].byteLength == "number" && typeof b[i].byteLength == "number") { | |
| if (arraybufferEqual2(a[i], b[i]) == false) { | |
| return false; | |
| } | |
| } else { | |
| if (typeof a[i] == "string" && typeof b[i] == "string") { | |
| if (a[i] !== b[i]) { | |
| return false; | |
| } | |
| } else if (a[i].constructor == RegExp && typeof b[i] == "string") { | |
| if (a[i].test(b[i]) == false) { | |
| return false; | |
| } | |
| } else if (typeof a[i] == "string" && b[i].constructor == RegExp) { | |
| if (b[i].test(a[i]) == false) { | |
| return false; | |
| } | |
| } else { | |
| if (a[i] !== b[i]) { | |
| return false; | |
| } | |
| } | |
| } | |
| } | |
| return true; | |
| } | |
| // node_modules/lemon-tls/crypto.js | |
| var TLS_CIPHER_SUITES = { | |
| 4865: { | |
| tls: 13, | |
| kex: "TLS13", | |
| sig: "TLS13", | |
| cipher: "AES_128_GCM", | |
| aead: true, | |
| keylen: 16, | |
| ivlen: 12, | |
| hash: "sha256" | |
| }, | |
| 4866: { | |
| tls: 13, | |
| kex: "TLS13", | |
| sig: "TLS13", | |
| cipher: "AES_256_GCM", | |
| aead: true, | |
| keylen: 32, | |
| ivlen: 12, | |
| hash: "sha384" | |
| }, | |
| 4867: { | |
| tls: 13, | |
| kex: "TLS13", | |
| sig: "TLS13", | |
| cipher: "CHACHA20_POLY1305", | |
| aead: true, | |
| keylen: 32, | |
| ivlen: 12, | |
| hash: "sha256" | |
| }, | |
| 49199: { | |
| tls: 12, | |
| kex: "ECDHE_RSA", | |
| sig: "RSA", | |
| cipher: "AES_128_GCM", | |
| aead: true, | |
| keylen: 16, | |
| fixed_ivlen: 4, | |
| record_ivlen: 8, | |
| ivlen: 12, | |
| hash: "sha256" | |
| }, | |
| 49200: { | |
| tls: 12, | |
| kex: "ECDHE_RSA", | |
| sig: "RSA", | |
| cipher: "AES_256_GCM", | |
| aead: true, | |
| keylen: 32, | |
| fixed_ivlen: 4, | |
| record_ivlen: 8, | |
| ivlen: 12, | |
| hash: "sha384" | |
| }, | |
| 49195: { | |
| tls: 12, | |
| kex: "ECDHE_ECDSA", | |
| sig: "ECDSA", | |
| cipher: "AES_128_GCM", | |
| aead: true, | |
| keylen: 16, | |
| fixed_ivlen: 4, | |
| record_ivlen: 8, | |
| ivlen: 12, | |
| hash: "sha256" | |
| }, | |
| 49196: { | |
| tls: 12, | |
| kex: "ECDHE_ECDSA", | |
| sig: "ECDSA", | |
| cipher: "AES_256_GCM", | |
| aead: true, | |
| keylen: 32, | |
| fixed_ivlen: 4, | |
| record_ivlen: 8, | |
| ivlen: 12, | |
| hash: "sha384" | |
| }, | |
| 52392: { | |
| tls: 12, | |
| kex: "ECDHE_RSA", | |
| sig: "RSA", | |
| cipher: "CHACHA20_POLY1305", | |
| aead: true, | |
| keylen: 32, | |
| fixed_ivlen: 4, | |
| record_ivlen: 8, | |
| ivlen: 12, | |
| hash: "sha256" | |
| }, | |
| 52393: { | |
| tls: 12, | |
| kex: "ECDHE_ECDSA", | |
| sig: "ECDSA", | |
| cipher: "CHACHA20_POLY1305", | |
| aead: true, | |
| keylen: 32, | |
| fixed_ivlen: 4, | |
| record_ivlen: 8, | |
| ivlen: 12, | |
| hash: "sha256" | |
| }, | |
| 52394: { | |
| tls: 12, | |
| kex: "DHE_RSA", | |
| sig: "RSA", | |
| cipher: "CHACHA20_POLY1305", | |
| aead: true, | |
| keylen: 32, | |
| fixed_ivlen: 4, | |
| record_ivlen: 8, | |
| ivlen: 12, | |
| hash: "sha256" | |
| }, | |
| 156: { | |
| tls: 12, | |
| kex: "RSA", | |
| sig: "RSA", | |
| cipher: "AES_128_GCM", | |
| aead: true, | |
| keylen: 16, | |
| fixed_ivlen: 4, | |
| record_ivlen: 8, | |
| ivlen: 12, | |
| hash: "sha256" | |
| }, | |
| 157: { | |
| tls: 12, | |
| kex: "RSA", | |
| sig: "RSA", | |
| cipher: "AES_256_GCM", | |
| aead: true, | |
| keylen: 32, | |
| fixed_ivlen: 4, | |
| record_ivlen: 8, | |
| ivlen: 12, | |
| hash: "sha384" | |
| }, | |
| 49171: { | |
| tls: 12, | |
| kex: "ECDHE_RSA", | |
| sig: "RSA", | |
| cipher: "AES_128_CBC", | |
| aead: false, | |
| keylen: 16, | |
| ivlen: 16, | |
| mac: "sha1", | |
| maclen: 20, | |
| hash: "sha256" | |
| }, | |
| 49172: { | |
| tls: 12, | |
| kex: "ECDHE_RSA", | |
| sig: "RSA", | |
| cipher: "AES_256_CBC", | |
| aead: false, | |
| keylen: 32, | |
| ivlen: 16, | |
| mac: "sha1", | |
| maclen: 20, | |
| hash: "sha256" | |
| }, | |
| 60: { | |
| tls: 12, | |
| kex: "RSA", | |
| sig: "RSA", | |
| cipher: "AES_128_CBC", | |
| aead: false, | |
| keylen: 16, | |
| ivlen: 16, | |
| mac: "sha256", | |
| maclen: 32, | |
| hash: "sha256" | |
| }, | |
| 61: { | |
| tls: 12, | |
| kex: "RSA", | |
| sig: "RSA", | |
| cipher: "AES_256_CBC", | |
| aead: false, | |
| keylen: 32, | |
| ivlen: 16, | |
| mac: "sha256", | |
| maclen: 32, | |
| hash: "sha256" | |
| } | |
| }; | |
| function getHashFn2(hashName) { | |
| if (hashName === "sha256") | |
| return sha256; | |
| if (hashName === "sha384") | |
| return sha384; | |
| throw new Error("Unsupported hash: " + hashName); | |
| } | |
| function hmac2(hashName, keyU8, dataU8) { | |
| var hashFn = getHashFn2(hashName); | |
| return hmac(hashFn, keyU8, dataU8); | |
| } | |
| function hkdf_extract(hashName, saltU8, ikmU8) { | |
| var hashFn = getHashFn2(hashName); | |
| return extract(hashFn, ikmU8, saltU8); | |
| } | |
| function hkdf_expand(hashName, prkU8, infoU8, length) { | |
| var hashFn = getHashFn2(hashName); | |
| return expand(hashFn, prkU8, infoU8, length | 0); | |
| } | |
| function build_hkdf_label2(label, context, length) { | |
| var prefix = "tls13 "; | |
| var enc = new TextEncoder; | |
| var full = enc.encode(prefix + label); | |
| var info = new Uint8Array(2 + 1 + full.length + 1 + context.length); | |
| info[0] = length >>> 8 & 255; | |
| info[1] = length & 255; | |
| info[2] = full.length; | |
| info.set(full, 3); | |
| var ofs = 3 + full.length; | |
| info[ofs] = context.length; | |
| info.set(context, ofs + 1); | |
| return info; | |
| } | |
| function hkdf_expand_label2(hashName, secret, label, context, length) { | |
| var info = build_hkdf_label2(label, context, length | 0); | |
| return hkdf_expand(hashName, secret, info, length | 0); | |
| } | |
| function derive_handshake_traffic_secrets(hashName, shared_secret, transcript) { | |
| var hashFn = getHashFn2(hashName); | |
| var hashLen = hashFn.outputLen | 0; | |
| var empty = new Uint8Array(0); | |
| var zeros = new Uint8Array(hashLen); | |
| var early_secret = hkdf_extract(hashName, empty, zeros); | |
| var h_empty = hashFn(empty); | |
| var derived_secret = hkdf_expand_label2(hashName, early_secret, "derived", h_empty, hashLen); | |
| var handshake_secret = hkdf_extract(hashName, derived_secret, shared_secret); | |
| var transcript_hash = hashFn(transcript); | |
| var client_handshake_traffic_secret = hkdf_expand_label2(hashName, handshake_secret, "c hs traffic", transcript_hash, hashLen); | |
| var server_handshake_traffic_secret = hkdf_expand_label2(hashName, handshake_secret, "s hs traffic", transcript_hash, hashLen); | |
| return { | |
| handshake_secret, | |
| client_handshake_traffic_secret, | |
| server_handshake_traffic_secret | |
| }; | |
| } | |
| function derive_app_traffic_secrets(hashName, handshake_secret, transcript) { | |
| var hashFn = getHashFn2(hashName); | |
| var hashLen = hashFn.outputLen | 0; | |
| var empty = new Uint8Array(0); | |
| var zeros = new Uint8Array(hashLen); | |
| var h_empty = hashFn(empty); | |
| var derived_secret = hkdf_expand_label2(hashName, handshake_secret, "derived", h_empty, hashLen); | |
| var master_secret = hkdf_extract(hashName, derived_secret, zeros); | |
| var transcript_hash = hashFn(transcript); | |
| var client_app_traffic_secret = hkdf_expand_label2(hashName, master_secret, "c ap traffic", transcript_hash, hashLen); | |
| var server_app_traffic_secret = hkdf_expand_label2(hashName, master_secret, "s ap traffic", transcript_hash, hashLen); | |
| return { | |
| client_app_traffic_secret, | |
| server_app_traffic_secret, | |
| master_secret | |
| }; | |
| } | |
| function build_cert_verify_tbs(hashName, isServer, transcript) { | |
| if (isServer) { | |
| var label = new TextEncoder().encode("TLS 1.3, server CertificateVerify"); | |
| } else { | |
| var label = new TextEncoder().encode("TLS 1.3, client CertificateVerify"); | |
| } | |
| var separator = new Uint8Array([0]); | |
| var padding = new Uint8Array(64).fill(32); | |
| var hashFn = getHashFn2(hashName); | |
| var transcript_hash = hashFn(transcript); | |
| return concatUint8Arrays2([padding, label, separator, transcript_hash]); | |
| } | |
| function get_handshake_finished(hashName, traffic_secret, transcript) { | |
| var hashFn = getHashFn2(hashName); | |
| var hashLen = hashFn.outputLen | 0; | |
| var empty = new Uint8Array(0); | |
| var finished_key = hkdf_expand_label2(hashName, traffic_secret, "finished", empty, hashLen); | |
| var transcript_hash = hashFn(transcript); | |
| var verify_data = hmac2(hashName, finished_key, transcript_hash); | |
| return verify_data; | |
| } | |
| // node_modules/lemon-tls/wire.js | |
| var TLS_VERSION = { | |
| TLS1_0: 769, | |
| TLS1_1: 770, | |
| TLS1_2: 771, | |
| TLS1_3: 772 | |
| }; | |
| var TLS_MESSAGE_TYPE = { | |
| CLIENT_HELLO: 1, | |
| SERVER_HELLO: 2, | |
| NEW_SESSION_TICKET: 4, | |
| END_OF_EARLY_DATA: 5, | |
| ENCRYPTED_EXTENSIONS: 8, | |
| CERTIFICATE: 11, | |
| SERVER_KEY_EXCHANGE: 12, | |
| CERTIFICATE_REQUEST: 13, | |
| SERVER_HELLO_DONE: 14, | |
| CERTIFICATE_VERIFY: 15, | |
| CLIENT_KEY_EXCHANGE: 16, | |
| FINISHED: 20, | |
| KEY_UPDATE: 24, | |
| MESSAGE_HASH: 254 | |
| }; | |
| var TLS_EXT = { | |
| SERVER_NAME: 0, | |
| MAX_FRAGMENT_LENGTH: 1, | |
| STATUS_REQUEST: 5, | |
| SUPPORTED_GROUPS: 10, | |
| SIGNATURE_ALGORITHMS: 13, | |
| USE_SRTP: 14, | |
| HEARTBEAT: 15, | |
| ALPN: 16, | |
| SCT: 18, | |
| CLIENT_CERT_TYPE: 19, | |
| SERVER_CERT_TYPE: 20, | |
| PADDING: 21, | |
| PRE_SHARED_KEY: 41, | |
| EARLY_DATA: 42, | |
| SUPPORTED_VERSIONS: 43, | |
| COOKIE: 44, | |
| PSK_KEY_EXCHANGE_MODES: 45, | |
| CERTIFICATE_AUTHORITIES: 47, | |
| OID_FILTERS: 48, | |
| POST_HANDSHAKE_AUTH: 49, | |
| SIGNATURE_ALGORITHMS_CERT: 50, | |
| KEY_SHARE: 51, | |
| RENEGOTIATION_INFO: 65281 | |
| }; | |
| function toU8(x) { | |
| if (x == null) | |
| return new Uint8Array(0); | |
| if (x instanceof Uint8Array) | |
| return x; | |
| if (typeof x === "string") | |
| return new TextEncoder().encode(x); | |
| return new Uint8Array(0); | |
| } | |
| function w_u8(buf, off, v) { | |
| buf[off++] = v & 255; | |
| return off; | |
| } | |
| function w_u16(buf, off, v) { | |
| buf[off++] = v >>> 8 & 255; | |
| buf[off++] = v & 255; | |
| return off; | |
| } | |
| function w_u24(buf, off, v) { | |
| buf[off++] = v >>> 16 & 255; | |
| buf[off++] = v >>> 8 & 255; | |
| buf[off++] = v & 255; | |
| return off; | |
| } | |
| function w_bytes(buf, off, b) { | |
| buf.set(b, off); | |
| return off + b.length; | |
| } | |
| function r_u8(buf, off) { | |
| return [buf[off++] >>> 0, off]; | |
| } | |
| function r_u16(buf, off) { | |
| var v = (buf[off] << 8 | buf[off + 1]) >>> 0; | |
| return [v, off + 2]; | |
| } | |
| function r_u24(buf, off) { | |
| var v = (buf[off] << 16 | buf[off + 1] << 8 | buf[off + 2]) >>> 0; | |
| return [v, off + 3]; | |
| } | |
| function r_bytes(buf, off, n) { | |
| var slice; | |
| if (buf instanceof Uint8Array) { | |
| slice = buf.slice(off, off + n); | |
| } else if (typeof Buffer !== "undefined" && Buffer.isBuffer && Buffer.isBuffer(buf)) { | |
| var tmp = buf.slice(off, off + n); | |
| slice = new Uint8Array(tmp); | |
| } else if (Array.isArray(buf)) { | |
| var tmp = buf.slice(off, off + n); | |
| slice = new Uint8Array(tmp); | |
| } else { | |
| throw new Error("r_bytes: unsupported buffer type " + typeof buf); | |
| } | |
| return [slice, off + n]; | |
| } | |
| function veclen(lenBytes, inner) { | |
| var out, off = 0; | |
| if (lenBytes === 1) { | |
| out = new Uint8Array(1 + inner.length); | |
| off = w_u8(out, off, inner.length); | |
| off = w_bytes(out, off, inner); | |
| return out; | |
| } | |
| if (lenBytes === 2) { | |
| out = new Uint8Array(2 + inner.length); | |
| off = w_u16(out, off, inner.length); | |
| off = w_bytes(out, off, inner); | |
| return out; | |
| } | |
| if (lenBytes === 3) { | |
| out = new Uint8Array(3 + inner.length); | |
| off = w_u24(out, off, inner.length); | |
| off = w_bytes(out, off, inner); | |
| return out; | |
| } | |
| throw new Error("veclen only supports 1/2/3"); | |
| } | |
| function readVec(buf, off, lenBytes) { | |
| var n, off2 = off; | |
| if (lenBytes === 1) { | |
| [n, off2] = r_u8(buf, off2); | |
| } else if (lenBytes === 2) { | |
| [n, off2] = r_u16(buf, off2); | |
| } else { | |
| [n, off2] = r_u24(buf, off2); | |
| } | |
| var b; | |
| [b, off2] = r_bytes(buf, off2, n); | |
| return [b, off2]; | |
| } | |
| var exts = {}; | |
| exts.SERVER_NAME = { encode: null, decode: null }; | |
| exts.SUPPORTED_VERSIONS = { encode: null, decode: null }; | |
| exts.SUPPORTED_GROUPS = { encode: null, decode: null }; | |
| exts.SIGNATURE_ALGORITHMS = { encode: null, decode: null }; | |
| exts.PSK_KEY_EXCHANGE_MODES = { encode: null, decode: null }; | |
| exts.KEY_SHARE = { encode: null, decode: null }; | |
| exts.ALPN = { encode: null, decode: null }; | |
| exts.RENEGOTIATION_INFO = { encode: null, decode: null }; | |
| exts.SERVER_NAME.encode = function(value) { | |
| var host = toU8(value || ""); | |
| var inner = new Uint8Array(1 + 2 + host.length); | |
| var off = 0; | |
| off = w_u8(inner, off, 0); | |
| off = w_u16(inner, off, host.length); | |
| off = w_bytes(inner, off, host); | |
| return veclen(2, inner); | |
| }; | |
| exts.SERVER_NAME.decode = function(data) { | |
| var off = 0; | |
| var list; | |
| [list, off] = readVec(data, off, 2); | |
| var off2 = 0; | |
| var host = ""; | |
| while (off2 < list.length) { | |
| var typ; | |
| [typ, off2] = r_u8(list, off2); | |
| var l; | |
| [l, off2] = r_u16(list, off2); | |
| var v; | |
| [v, off2] = r_bytes(list, off2, l); | |
| if (typ === 0) { | |
| host = new TextDecoder().decode(v); | |
| } | |
| } | |
| return host; | |
| }; | |
| exts.SUPPORTED_VERSIONS.encode = function(value) { | |
| if (typeof value === "number") { | |
| var out = new Uint8Array(2); | |
| var off = 0; | |
| off = w_u16(out, off, value); | |
| return out; | |
| } | |
| var arr = Array.isArray(value) ? value : [TLS_VERSION.TLS1_3, TLS_VERSION.TLS1_2]; | |
| var body = new Uint8Array(1 + arr.length * 2); | |
| var off2 = 0; | |
| off2 = w_u8(body, off2, arr.length * 2); | |
| for (var i = 0;i < arr.length; i++) { | |
| off2 = w_u16(body, off2, arr[i]); | |
| } | |
| return body; | |
| }; | |
| exts.SUPPORTED_VERSIONS.decode = function(data) { | |
| if (data.length === 2) { | |
| var v, off = 0; | |
| [v, off] = r_u16(data, off); | |
| return v; | |
| } | |
| var off2 = 0; | |
| var n; | |
| [n, off2] = r_u8(data, off2); | |
| var out = []; | |
| for (var i = 0;i < n; i += 2) { | |
| var vv; | |
| [vv, off2] = r_u16(data, off2); | |
| out.push(vv); | |
| } | |
| return out; | |
| }; | |
| exts.SUPPORTED_GROUPS.encode = function(value) { | |
| var groups = Array.isArray(value) ? value : [23, 29]; | |
| var body = new Uint8Array(2 + groups.length * 2); | |
| var off = 0; | |
| off = w_u16(body, off, groups.length * 2); | |
| for (var i = 0;i < groups.length; i++) { | |
| off = w_u16(body, off, groups[i]); | |
| } | |
| return body; | |
| }; | |
| exts.SUPPORTED_GROUPS.decode = function(data) { | |
| var off = 0; | |
| var n; | |
| [n, off] = r_u16(data, off); | |
| var out = []; | |
| for (var i = 0;i < n; i += 2) { | |
| var g; | |
| [g, off] = r_u16(data, off); | |
| out.push(g); | |
| } | |
| return out; | |
| }; | |
| exts.SIGNATURE_ALGORITHMS.encode = function(value) { | |
| var algs = Array.isArray(value) ? value : [1027, 2052, 1025]; | |
| var body = new Uint8Array(2 + algs.length * 2); | |
| var off = 0; | |
| off = w_u16(body, off, algs.length * 2); | |
| for (var i = 0;i < algs.length; i++) { | |
| off = w_u16(body, off, algs[i]); | |
| } | |
| return body; | |
| }; | |
| exts.SIGNATURE_ALGORITHMS.decode = function(data) { | |
| var off = 0; | |
| var n; | |
| [n, off] = r_u16(data, off); | |
| var out = []; | |
| for (var i = 0;i < n; i += 2) { | |
| var a; | |
| [a, off] = r_u16(data, off); | |
| out.push(a); | |
| } | |
| return out; | |
| }; | |
| exts.PSK_KEY_EXCHANGE_MODES.encode = function(value) { | |
| var modes = Array.isArray(value) ? value : [1]; | |
| var body = new Uint8Array(1 + modes.length); | |
| var off = 0; | |
| off = w_u8(body, off, modes.length); | |
| for (var i = 0;i < modes.length; i++) { | |
| off = w_u8(body, off, modes[i]); | |
| } | |
| return body; | |
| }; | |
| exts.PSK_KEY_EXCHANGE_MODES.decode = function(data) { | |
| var off = 0; | |
| var n; | |
| [n, off] = r_u8(data, off); | |
| var out = []; | |
| for (var i = 0;i < n; i++) { | |
| var m; | |
| [m, off] = r_u8(data, off); | |
| out.push(m); | |
| } | |
| return out; | |
| }; | |
| exts.KEY_SHARE.encode = function(value) { | |
| if (value && typeof value.group === "number" && value.key_exchange) { | |
| var ke = toU8(value.key_exchange); | |
| var out = new Uint8Array(2 + 2 + ke.length); | |
| var off = 0; | |
| off = w_u16(out, off, value.group); | |
| off = w_u16(out, off, ke.length); | |
| off = w_bytes(out, off, ke); | |
| return out; | |
| } | |
| var list = Array.isArray(value) ? value : []; | |
| var parts = []; | |
| for (var i = 0;i < list.length; i++) { | |
| var e = list[i]; | |
| var ke2 = toU8(e.key_exchange || new Uint8Array(0)); | |
| var ent = new Uint8Array(2 + 2 + ke2.length); | |
| var o2 = 0; | |
| o2 = w_u16(ent, o2, e.group >>> 0); | |
| o2 = w_u16(ent, o2, ke2.length); | |
| o2 = w_bytes(ent, o2, ke2); | |
| parts.push(ent); | |
| } | |
| return veclen(2, concatUint8Arrays2(parts)); | |
| }; | |
| exts.KEY_SHARE.decode = function(data) { | |
| if (data.length >= 4) { | |
| var g, off = 0; | |
| [g, off] = r_u16(data, off); | |
| var l; | |
| [l, off] = r_u16(data, off); | |
| if (4 + l === data.length) { | |
| var ke; | |
| [ke, off] = r_bytes(data, off, l); | |
| return { group: g, key_exchange: ke }; | |
| } | |
| } | |
| var off2 = 0; | |
| var listBytes; | |
| [listBytes, off2] = r_u16(data, off2); | |
| var end = off2 + listBytes; | |
| var out = []; | |
| while (off2 < end) { | |
| var g2; | |
| [g2, off2] = r_u16(data, off2); | |
| var l2; | |
| [l2, off2] = r_u16(data, off2); | |
| var ke2; | |
| [ke2, off2] = r_bytes(data, off2, l2); | |
| out.push({ group: g2, key_exchange: ke2 }); | |
| } | |
| return out; | |
| }; | |
| exts.ALPN.encode = function(value) { | |
| var list = Array.isArray(value) ? value : []; | |
| var total = 2; | |
| var items = []; | |
| for (var i = 0;i < list.length; i++) { | |
| var p = toU8(list[i]); | |
| items.push(p); | |
| total += 1 + p.length; | |
| } | |
| var out = new Uint8Array(total); | |
| var off = 0; | |
| off = w_u16(out, off, total - 2); | |
| for (var j = 0;j < items.length; j++) { | |
| off = w_u8(out, off, items[j].length); | |
| off = w_bytes(out, off, items[j]); | |
| } | |
| return out; | |
| }; | |
| exts.ALPN.decode = function(data) { | |
| var off = 0; | |
| var n; | |
| [n, off] = r_u16(data, off); | |
| var end = off + n; | |
| var out = []; | |
| while (off < end) { | |
| var l; | |
| [l, off] = r_u8(data, off); | |
| var v; | |
| [v, off] = r_bytes(data, off, l); | |
| out.push(new TextDecoder().decode(v)); | |
| } | |
| return out; | |
| }; | |
| exts.RENEGOTIATION_INFO.encode = function(value) { | |
| var rb = toU8(value || new Uint8Array(0)); | |
| return veclen(1, rb); | |
| }; | |
| exts.RENEGOTIATION_INFO.decode = function(data) { | |
| var off = 0; | |
| var v; | |
| [v, off] = readVec(data, off, 1); | |
| return v; | |
| }; | |
| function ext_name_by_code(code) { | |
| for (var k in TLS_EXT) { | |
| if (TLS_EXT[k] >>> 0 === code >>> 0) | |
| return k; | |
| } | |
| return "EXT_" + code; | |
| } | |
| function build_extensions(list) { | |
| if (!list || !list.length) { | |
| var e = new Uint8Array(2); | |
| w_u16(e, 0, 0); | |
| return e; | |
| } | |
| var parts = []; | |
| var total = 2; | |
| for (var i = 0;i < list.length; i++) { | |
| var t = list[i].type; | |
| if (typeof t === "string") { | |
| t = TLS_EXT[t]; | |
| } | |
| var payload; | |
| if (list[i].data) { | |
| payload = list[i].data; | |
| } else { | |
| var regKey = ext_name_by_code(t); | |
| var enc = exts[regKey] && exts[regKey].encode; | |
| payload = enc ? enc(list[i].value) : new Uint8Array(0); | |
| } | |
| var rec = new Uint8Array(4 + payload.length); | |
| var off = 0; | |
| off = w_u16(rec, off, t >>> 0); | |
| off = w_u16(rec, off, payload.length); | |
| off = w_bytes(rec, off, payload); | |
| parts.push(rec); | |
| total += rec.length; | |
| } | |
| var out = new Uint8Array(total); | |
| var off2 = 0; | |
| off2 = w_u16(out, off2, total - 2); | |
| for (var j = 0;j < parts.length; j++) { | |
| off2 = w_bytes(out, off2, parts[j]); | |
| } | |
| return out; | |
| } | |
| function parse_extensions(buf) { | |
| var off = 0; | |
| var n; | |
| [n, off] = r_u16(buf, off); | |
| var end = off + n; | |
| var out = []; | |
| while (off < end) { | |
| var t; | |
| [t, off] = r_u16(buf, off); | |
| var l; | |
| [l, off] = r_u16(buf, off); | |
| var d; | |
| [d, off] = r_bytes(buf, off, l); | |
| var name = ext_name_by_code(t); | |
| var dec = exts[name] && exts[name].decode; | |
| var val = dec ? dec(d) : null; | |
| out.push({ type: t, name, data: d, value: val }); | |
| } | |
| return out; | |
| } | |
| function build_hello(kind, params) { | |
| params = params || {}; | |
| var legacy_version = TLS_VERSION.TLS1_2; | |
| var sid = toU8(params.session_id || ""); | |
| if (sid.length > 32) | |
| sid = sid.subarray(0, 32); | |
| var extsBuf = build_extensions(params.extensions || []); | |
| if (kind === "client") { | |
| var cs = params.cipher_suites || [4865, 4866, 4867, 49199, 49195]; | |
| var csBlock = new Uint8Array(2 + cs.length * 2); | |
| var o = 0; | |
| o = w_u16(csBlock, o, cs.length * 2); | |
| for (var i = 0;i < cs.length; i++) { | |
| o = w_u16(csBlock, o, cs[i]); | |
| } | |
| var comp = params.legacy_compression || [0]; | |
| var compBlock = new Uint8Array(1 + comp.length); | |
| var oc = 0; | |
| oc = w_u8(compBlock, oc, comp.length); | |
| for (var j = 0;j < comp.length; j++) { | |
| oc = w_u8(compBlock, oc, comp[j]); | |
| } | |
| var out = new Uint8Array(2 + 32 + 1 + sid.length + csBlock.length + compBlock.length + extsBuf.length); | |
| var off = 0; | |
| off = w_u16(out, off, legacy_version); | |
| off = w_bytes(out, off, params.random); | |
| off = w_u8(out, off, sid.length); | |
| off = w_bytes(out, off, sid); | |
| off = w_bytes(out, off, csBlock); | |
| off = w_bytes(out, off, compBlock); | |
| off = w_bytes(out, off, extsBuf); | |
| return out; | |
| } | |
| if (kind === "server") { | |
| var cipher_suite = typeof params.cipher_suite === "number" ? params.cipher_suite : 4865; | |
| var out2 = new Uint8Array(2 + 32 + 1 + sid.length + 2 + 1 + extsBuf.length); | |
| var off2 = 0; | |
| off2 = w_u16(out2, off2, legacy_version); | |
| off2 = w_bytes(out2, off2, params.random); | |
| off2 = w_u8(out2, off2, sid.length); | |
| off2 = w_bytes(out2, off2, sid); | |
| off2 = w_u16(out2, off2, cipher_suite); | |
| off2 = w_u8(out2, off2, 0); | |
| off2 = w_bytes(out2, off2, extsBuf); | |
| return out2; | |
| } | |
| throw new Error('build_hello: kind must be "client" or "server"'); | |
| } | |
| function parse_hello(hsType, body) { | |
| var isClient = hsType === TLS_MESSAGE_TYPE.CLIENT_HELLO || hsType === "client_hello"; | |
| var off = 0; | |
| var legacy_version; | |
| [legacy_version, off] = r_u16(body, off); | |
| var random; | |
| [random, off] = r_bytes(body, off, 32); | |
| var sidLen; | |
| [sidLen, off] = r_u8(body, off); | |
| var session_id; | |
| [session_id, off] = r_bytes(body, off, sidLen); | |
| if (isClient) { | |
| var csLen; | |
| [csLen, off] = r_u16(body, off); | |
| var csEnd = off + csLen; | |
| var cipher_suites = []; | |
| while (off < csEnd) { | |
| var cs; | |
| [cs, off] = r_u16(body, off); | |
| cipher_suites.push(cs); | |
| } | |
| var compLen; | |
| [compLen, off] = r_u8(body, off); | |
| var legacy_compression = []; | |
| for (var i = 0;i < compLen; i++) { | |
| var c; | |
| [c, off] = r_u8(body, off); | |
| legacy_compression.push(c); | |
| } | |
| var extRaw = body.length > off ? body.subarray(off) : new Uint8Array(0); | |
| var extensions = extRaw.length ? parse_extensions(extRaw) : []; | |
| var ver = legacy_version; | |
| for (var k = 0;k < extensions.length; k++) { | |
| var e = extensions[k]; | |
| if (e.type === TLS_EXT.SUPPORTED_VERSIONS && Array.isArray(e.value)) { | |
| for (var t = 0;t < e.value.length; t++) { | |
| if (e.value[t] === TLS_VERSION.TLS1_3) { | |
| ver = TLS_VERSION.TLS1_3; | |
| break; | |
| } | |
| } | |
| } | |
| } | |
| return { | |
| message: "client_hello", | |
| legacy_version, | |
| version_hint: ver, | |
| random, | |
| session_id, | |
| cipher_suites, | |
| legacy_compression, | |
| extensions | |
| }; | |
| } | |
| var cipher_suite; | |
| [cipher_suite, off] = r_u16(body, off); | |
| var comp; | |
| [comp, off] = r_u8(body, off); | |
| var extRaw2 = body.length > off ? body.subarray(off) : new Uint8Array(0); | |
| var extensions2 = extRaw2.length ? parse_extensions(extRaw2) : []; | |
| var ver2 = legacy_version; | |
| for (var z = 0;z < extensions2.length; z++) { | |
| var ex = extensions2[z]; | |
| if (ex.type === TLS_EXT.SUPPORTED_VERSIONS && typeof ex.value === "number") { | |
| ver2 = ex.value; | |
| } | |
| } | |
| return { | |
| message: "server_hello", | |
| legacy_version, | |
| version: ver2, | |
| random, | |
| session_id, | |
| cipher_suite, | |
| legacy_compression: comp, | |
| extensions: extensions2 | |
| }; | |
| } | |
| function isVec2(u82) { | |
| if (!(u82 instanceof Uint8Array) || u82.length < 2) | |
| return false; | |
| var len = u82[0] << 8 | u82[1]; | |
| return u82.length === 2 + len; | |
| } | |
| function build_certificate(params) { | |
| var v = params.version || TLS_VERSION.TLS1_2; | |
| var entries = Array.isArray(params.entries) ? params.entries.slice() : null; | |
| if (!entries && Array.isArray(params.certs)) { | |
| entries = params.certs.map(function(c2) { | |
| return { cert: c2 }; | |
| }); | |
| } | |
| if (!entries) | |
| entries = []; | |
| if (v === TLS_VERSION.TLS1_3) { | |
| var ctx = toU8(params.request_context || new Uint8Array(0)); | |
| var entryParts = []; | |
| for (var i = 0;i < entries.length; i++) { | |
| var certBytes = toU8(entries[i].cert || new Uint8Array(0)); | |
| var certVec = veclen(3, certBytes); | |
| var extRaw = entries[i].extensions; | |
| if (Array.isArray(extRaw)) { | |
| extRaw = build_extensions(extRaw); | |
| } else if (extRaw instanceof Uint8Array) { | |
| extRaw = isVec2 && isVec2(extRaw) ? extRaw : veclen(2, extRaw); | |
| } else { | |
| extRaw = veclen(2, new Uint8Array(0)); | |
| } | |
| entryParts.push(certVec, extRaw); | |
| } | |
| var ctxVec = veclen(1, ctx); | |
| var listVec = veclen(3, concatUint8Arrays2(entryParts)); | |
| return concatUint8Arrays2([ctxVec, listVec]); | |
| } else { | |
| var certListParts = []; | |
| for (var j = 0;j < entries.length; j++) { | |
| var c = toU8(entries[j].cert || new Uint8Array(0)); | |
| certListParts.push(veclen(3, c)); | |
| } | |
| return veclen(3, concatUint8Arrays2(certListParts)); | |
| } | |
| } | |
| function build_certificate_verify(scheme, signature) { | |
| var sig = toU8(signature || new Uint8Array(0)); | |
| var alg = scheme >>> 0; | |
| var out = new Uint8Array(2 + 2 + sig.length); | |
| var off = 0; | |
| off = w_u16(out, off, alg); | |
| off = w_u16(out, off, sig.length); | |
| off = w_bytes(out, off, sig); | |
| return out; | |
| } | |
| function build_message(params) { | |
| var type = 0; | |
| var body = null; | |
| if (params.type == "server_hello") { | |
| type = TLS_MESSAGE_TYPE.SERVER_HELLO; | |
| body = build_hello("server", params); | |
| } else if (params.type == "client_hello") { | |
| type = TLS_MESSAGE_TYPE.SERVER_HELLO; | |
| body = build_hello("client", params); | |
| } else if (params.type == "encrypted_extensions") { | |
| type = TLS_MESSAGE_TYPE.ENCRYPTED_EXTENSIONS; | |
| body = build_extensions(params.extensions); | |
| } else if (params.type == "certificate") { | |
| type = TLS_MESSAGE_TYPE.CERTIFICATE; | |
| body = build_certificate(params); | |
| } else if (params.type == "certificate_verify") { | |
| type = TLS_MESSAGE_TYPE.CERTIFICATE_VERIFY; | |
| body = build_certificate_verify(params.scheme, params.signature); | |
| } else if (params.type == "finished") { | |
| type = TLS_MESSAGE_TYPE.FINISHED; | |
| body = params.data; | |
| } | |
| var out = new Uint8Array(4 + body.length); | |
| var off = 0; | |
| off = w_u8(out, off, type); | |
| off = w_u24(out, off, body.length); | |
| off = w_bytes(out, off, body); | |
| return out; | |
| } | |
| function parse_message(buf) { | |
| var off = 0; | |
| var t; | |
| [t, off] = r_u8(buf, off); | |
| var l; | |
| [l, off] = r_u24(buf, off); | |
| var b; | |
| [b, off] = r_bytes(buf, off, l); | |
| return { type: t, body: b }; | |
| } | |
| // node_modules/lemon-tls/tls_session.js | |
| function Emitter() { | |
| var listeners = {}; | |
| return { | |
| on: function(name, fn) { | |
| (listeners[name] = listeners[name] || []).push(fn); | |
| }, | |
| emit: function(name) { | |
| var args = Array.prototype.slice.call(arguments, 1); | |
| var arr = listeners[name] || []; | |
| for (var i = 0;i < arr.length; i++) { | |
| try { | |
| arr[i].apply(null, args); | |
| } catch (e) {} | |
| } | |
| } | |
| }; | |
| } | |
| function normalizeHello(hello) { | |
| var out = { | |
| message: hello.message, | |
| legacy_version: hello.legacy_version, | |
| version: hello.version || hello.version_hint || null, | |
| random: hello.random || null, | |
| session_id: hello.session_id || null, | |
| cipher_suites: hello.cipher_suites || null, | |
| cipher_suite: hello.cipher_suite || null, | |
| legacy_compression: hello.legacy_compression || null, | |
| sni: null, | |
| alpn: null, | |
| key_shares: null, | |
| supported_versions: null, | |
| signature_algorithms: null, | |
| supported_groups: null, | |
| renegotiation_info: null, | |
| status_request: null, | |
| max_fragment_length: null, | |
| signature_algorithms_cert: null, | |
| certificate_authorities: null, | |
| sct: null, | |
| heartbeat: null, | |
| use_srtp: null, | |
| cookie: null, | |
| early_data: null, | |
| psk_key_exchange_modes: null, | |
| extensions: hello.extensions || [], | |
| unknown: [] | |
| }; | |
| if (!hello.extensions) { | |
| return out; | |
| } | |
| for (var i = 0;i < hello.extensions.length; i++) { | |
| var e = hello.extensions[i]; | |
| var val = e.value !== undefined && e.value !== null ? e.value : null; | |
| switch (e.name) { | |
| case "SERVER_NAME": | |
| out.sni = val; | |
| break; | |
| case "ALPN": | |
| out.alpn = val; | |
| break; | |
| case "KEY_SHARE": | |
| out.key_shares = val; | |
| break; | |
| case "SUPPORTED_VERSIONS": | |
| out.supported_versions = val; | |
| break; | |
| case "SIGNATURE_ALGORITHMS": | |
| out.signature_algorithms = val; | |
| break; | |
| case "SUPPORTED_GROUPS": | |
| out.supported_groups = val; | |
| break; | |
| case "RENEGOTIATION_INFO": | |
| out.renegotiation_info = val; | |
| break; | |
| case "STATUS_REQUEST": | |
| out.status_request = val; | |
| break; | |
| case "MAX_FRAGMENT_LENGTH": | |
| out.max_fragment_length = val; | |
| break; | |
| case "SIGNATURE_ALGORITHMS_CERT": | |
| out.signature_algorithms_cert = val; | |
| break; | |
| case "CERTIFICATE_AUTHORITIES": | |
| out.certificate_authorities = val; | |
| break; | |
| case "SCT": | |
| out.sct = val; | |
| break; | |
| case "HEARTBEAT": | |
| out.heartbeat = val; | |
| break; | |
| case "USE_SRTP": | |
| out.use_srtp = val; | |
| break; | |
| case "COOKIE": | |
| out.cookie = val; | |
| break; | |
| case "EARLY_DATA": | |
| out.early_data = val === null ? true : val; | |
| break; | |
| case "PSK_KEY_EXCHANGE_MODES": | |
| out.psk_key_exchange_modes = val; | |
| break; | |
| default: | |
| out.unknown.push(e); | |
| } | |
| } | |
| if (out.supported_versions == null) { | |
| if (out.message === "client_hello" && typeof out.legacy_version === "number") { | |
| out.supported_versions = [out.legacy_version | 0]; | |
| } else if (out.message === "server_hello" && typeof out.legacy_version === "number") { | |
| if (out.version == null) | |
| out.version = out.legacy_version | 0; | |
| out.supported_versions = out.version; | |
| } | |
| } | |
| if (out.key_shares == null && out.message === "client_hello") { | |
| out.key_shares = []; | |
| } | |
| return out; | |
| } | |
| function TLSSession(options) { | |
| if (!(this instanceof TLSSession)) | |
| return new TLSSession(options); | |
| options = options || {}; | |
| var ev = Emitter(); | |
| var context = { | |
| state: "new", | |
| isServer: !!options.isServer, | |
| SNICallback: options.SNICallback || null, | |
| local_versions: [], | |
| local_cipher_suites: [], | |
| local_alpns: [], | |
| local_groups: [], | |
| local_signature_algorithms: [], | |
| local_extensions: [], | |
| local_key_share_public: null, | |
| local_key_share_private: null, | |
| remote_versions: [], | |
| remote_cipher_suites: [], | |
| remote_alpns: [], | |
| remote_groups: [], | |
| remote_signature_algorithms: [], | |
| remote_extensions: [], | |
| remote_key_shares: [], | |
| remote_sni: null, | |
| remote_session_id: null, | |
| remote_random: null, | |
| selected_version: null, | |
| selected_cipher_suite: null, | |
| selected_alpn: null, | |
| selected_group: null, | |
| selected_signature_algorithm: null, | |
| selected_extensions: [], | |
| selected_sni: null, | |
| selected_session_id: null, | |
| transcript: [], | |
| local_random: null, | |
| hello_sent: false, | |
| encrypted_exts_sent: false, | |
| cert_sent: false, | |
| cert_verify_sent: false, | |
| finished_sent: false, | |
| message_sent_seq: 0, | |
| remote_finished: null, | |
| expected_remote_finished: null, | |
| remote_finished_ok: false, | |
| local_key_share_private: null, | |
| local_key_share_public: null, | |
| ecdhe_shared_secret: null, | |
| handshake_secret: null, | |
| client_handshake_traffic_secret: null, | |
| server_handshake_traffic_secret: null, | |
| client_app_traffic_secret: null, | |
| server_app_traffic_secret: null, | |
| local_cert_chain: null, | |
| remote_cert_chain: null, | |
| selected_cert: null, | |
| cert_private_key: null | |
| }; | |
| function process_income_message(data) { | |
| var message = parse_message(data); | |
| if (message.type == TLS_MESSAGE_TYPE.CLIENT_HELLO || message.type == TLS_MESSAGE_TYPE.SERVER_HELLO) { | |
| var hello = parse_hello(message.type, message.body); | |
| var info = normalizeHello(hello); | |
| context.transcript.push(data); | |
| set_context({ | |
| remote_random: info.random || null, | |
| remote_sni: info.sni || null, | |
| remote_session_id: info.session_id || null, | |
| remote_cipher_suites: info.cipher_suites || [], | |
| remote_alpns: info.alpn || [], | |
| remote_key_shares: info.key_shares || [], | |
| remote_versions: info.supported_versions || [], | |
| remote_signature_algorithms: info.signature_algorithms || [], | |
| remote_groups: info.supported_groups || [], | |
| remote_extensions: info.extensions || [] | |
| }); | |
| ev.emit("hello"); | |
| if (typeof context.SNICallback == "function") { | |
| context.SNICallback(context.remote_sni, function(err, creds) { | |
| if (!err && creds) { | |
| set_context({ | |
| local_cert_chain: creds.certificateChain, | |
| cert_private_key: creds.privateKey | |
| }); | |
| } else {} | |
| }); | |
| } | |
| } else if (message.type == TLS_MESSAGE_TYPE.FINISHED) { | |
| set_context({ | |
| remote_finished: message.body | |
| }); | |
| } | |
| } | |
| function set_context(options2) { | |
| var has_changed = false; | |
| var fields = [ | |
| "local_versions", | |
| "local_cipher_suites", | |
| "local_alpns", | |
| "local_groups", | |
| "local_signature_algorithms", | |
| "local_extensions", | |
| "remote_versions", | |
| "remote_cipher_suites", | |
| "remote_alpns", | |
| "remote_groups", | |
| "remote_signature_algorithms", | |
| "remote_extensions", | |
| "remote_key_shares", | |
| "remote_sni", | |
| "remote_session_id", | |
| "remote_random", | |
| "selected_version", | |
| "selected_cipher_suite", | |
| "selected_alpn", | |
| "selected_group", | |
| "selected_signature_algorithm", | |
| "selected_extensions", | |
| "selected_sni", | |
| "selected_session_id", | |
| "local_key_share_public", | |
| "local_key_share_private", | |
| "ecdhe_shared_secret", | |
| "server_handshake_traffic_secret", | |
| "client_handshake_traffic_secret", | |
| "server_app_traffic_secret", | |
| "client_app_traffic_secret", | |
| "local_cert_chain", | |
| "remote_cert_chain", | |
| "cert_private_key", | |
| "remote_finished_ok", | |
| "remote_finished", | |
| "expected_remote_finished" | |
| ]; | |
| var prev = {}; | |
| if (options2 && typeof options2 === "object") { | |
| if ("local_versions" in options2) { | |
| if (arraysEqual(options2.local_versions, context.local_versions) == false) { | |
| prev["local_versions"] = context["local_versions"]; | |
| context.local_versions = options2.local_versions; | |
| has_changed = true; | |
| } | |
| } | |
| if ("local_cipher_suites" in options2) { | |
| if (arraysEqual(options2.local_cipher_suites, context.local_cipher_suites) == false) { | |
| prev["local_cipher_suites"] = context["local_cipher_suites"]; | |
| context.local_cipher_suites = options2.local_cipher_suites; | |
| has_changed = true; | |
| } | |
| } | |
| if ("local_alpns" in options2) { | |
| if (arraysEqual(options2.local_alpns, context.local_alpns) == false) { | |
| prev["local_alpns"] = context["local_alpns"]; | |
| context.local_alpns = options2.local_alpns; | |
| has_changed = true; | |
| } | |
| } | |
| if ("local_groups" in options2) { | |
| if (arraysEqual(options2.local_groups, context.local_groups) == false) { | |
| prev["local_groups"] = context["local_groups"]; | |
| context.local_groups = options2.local_groups; | |
| has_changed = true; | |
| } | |
| } | |
| if ("local_signature_algorithms" in options2) { | |
| if (arraysEqual(options2.local_signature_algorithms, context.local_signature_algorithms) == false) { | |
| prev["local_signature_algorithms"] = context["local_signature_algorithms"]; | |
| context.local_signature_algorithms = options2.local_signature_algorithms; | |
| has_changed = true; | |
| } | |
| } | |
| if ("local_extensions" in options2) { | |
| if (arraysEqual(options2.local_extensions, context.local_extensions) == false) { | |
| prev["local_extensions"] = context["local_extensions"]; | |
| context.local_extensions = options2.local_extensions; | |
| has_changed = true; | |
| } | |
| } | |
| if ("local_key_share_public" in options2) { | |
| if (context.local_key_share_public == null && options2.local_key_share_public !== null || !arraybufferEqual2(options2.local_key_share_public.buffer, context.local_key_share_public.buffer)) { | |
| prev["local_key_share_public"] = context["local_key_share_public"]; | |
| context.local_key_share_public = options2.local_key_share_public; | |
| has_changed = true; | |
| } | |
| } | |
| if ("local_key_share_private" in options2) { | |
| if (context.local_key_share_private == null && options2.local_key_share_private !== null || !arraybufferEqual2(options2.local_key_share_private.buffer, context.local_key_share_private.buffer)) { | |
| prev["local_key_share_private"] = context["local_key_share_private"]; | |
| context.local_key_share_private = options2.local_key_share_private; | |
| has_changed = true; | |
| } | |
| } | |
| if ("remote_versions" in options2) { | |
| if (arraysEqual(options2.remote_versions, context.remote_versions) == false) { | |
| prev["remote_versions"] = context["remote_versions"]; | |
| context.remote_versions = options2.remote_versions; | |
| has_changed = true; | |
| } | |
| } | |
| if ("remote_cipher_suites" in options2) { | |
| if (arraysEqual(options2.remote_cipher_suites, context.remote_cipher_suites) == false) { | |
| prev["remote_cipher_suites"] = context["remote_cipher_suites"]; | |
| context.remote_cipher_suites = options2.remote_cipher_suites; | |
| has_changed = true; | |
| } | |
| } | |
| if ("remote_alpns" in options2) { | |
| if (arraysEqual(options2.remote_alpns, context.remote_alpns) == false) { | |
| prev["remote_alpns"] = context["remote_alpns"]; | |
| context.remote_alpns = options2.remote_alpns; | |
| has_changed = true; | |
| } | |
| } | |
| if ("remote_groups" in options2) { | |
| if (arraysEqual(options2.remote_groups, context.remote_groups) == false) { | |
| prev["remote_groups"] = context["remote_groups"]; | |
| context.remote_groups = options2.remote_groups; | |
| has_changed = true; | |
| } | |
| } | |
| if ("remote_signature_algorithms" in options2) { | |
| if (arraysEqual(options2.remote_signature_algorithms, context.remote_signature_algorithms) == false) { | |
| prev["remote_signature_algorithms"] = context["remote_signature_algorithms"]; | |
| context.remote_signature_algorithms = options2.remote_signature_algorithms; | |
| has_changed = true; | |
| } | |
| } | |
| if ("remote_extensions" in options2) { | |
| if (arraysEqual(options2.remote_extensions, context.remote_extensions) == false) { | |
| prev["remote_extensions"] = context["remote_extensions"]; | |
| context.remote_extensions = options2.remote_extensions; | |
| has_changed = true; | |
| } | |
| } | |
| if ("remote_key_shares" in options2) { | |
| if (arraysEqual(options2.remote_key_shares, context.remote_key_shares) == false) { | |
| prev["remote_key_shares"] = context["remote_key_shares"]; | |
| context.remote_key_shares = options2.remote_key_shares; | |
| has_changed = true; | |
| } | |
| } | |
| if ("remote_sni" in options2) { | |
| if (options2.remote_sni !== context.remote_sni) { | |
| prev["remote_sni"] = context["remote_sni"]; | |
| context.remote_sni = options2.remote_sni; | |
| has_changed = true; | |
| } | |
| } | |
| if ("remote_session_id" in options2) { | |
| if (context.remote_session_id == null && options2.remote_session_id !== null || !arraybufferEqual2(options2.remote_session_id.buffer, context.remote_session_id.buffer)) { | |
| prev["remote_session_id"] = context["remote_session_id"]; | |
| context.remote_session_id = options2.remote_session_id; | |
| has_changed = true; | |
| } | |
| } | |
| if ("remote_random" in options2) { | |
| if (context.remote_random == null && options2.remote_random !== null || !arraybufferEqual2(options2.remote_random.buffer, context.remote_random.buffer)) { | |
| prev["remote_random"] = context["remote_random"]; | |
| context.remote_random = options2.remote_random; | |
| has_changed = true; | |
| } | |
| } | |
| if ("selected_version" in options2) { | |
| if (options2.selected_version !== context.selected_version) { | |
| prev["selected_version"] = context["selected_version"]; | |
| context.selected_version = options2.selected_version; | |
| has_changed = true; | |
| } | |
| } | |
| if ("selected_cipher_suite" in options2) { | |
| if (options2.selected_cipher_suite !== context.selected_cipher_suite) { | |
| prev["selected_cipher_suite"] = context["selected_cipher_suite"]; | |
| context.selected_cipher_suite = options2.selected_cipher_suite; | |
| has_changed = true; | |
| } | |
| } | |
| if ("selected_alpn" in options2) { | |
| if (options2.selected_alpn !== context.selected_alpn) { | |
| prev["selected_alpn"] = context["selected_alpn"]; | |
| context.selected_alpn = options2.selected_alpn; | |
| has_changed = true; | |
| } | |
| } | |
| if ("selected_group" in options2) { | |
| if (options2.selected_group !== context.selected_group) { | |
| prev["selected_group"] = context["selected_group"]; | |
| context.selected_group = options2.selected_group; | |
| has_changed = true; | |
| } | |
| } | |
| if ("selected_signature_algorithm" in options2) { | |
| if (options2.selected_signature_algorithm !== context.selected_signature_algorithm) { | |
| prev["selected_signature_algorithm"] = context["selected_signature_algorithm"]; | |
| context.selected_signature_algorithm = options2.selected_signature_algorithm; | |
| has_changed = true; | |
| } | |
| } | |
| if ("selected_extensions" in options2) { | |
| if (arraysEqual(options2.selected_extensions, context.selected_extensions) == false) { | |
| prev["selected_extensions"] = context["selected_extensions"]; | |
| context.selected_extensions = options2.selected_extensions; | |
| has_changed = true; | |
| } | |
| } | |
| if ("selected_sni" in options2) { | |
| if (options2.selected_sni !== context.selected_sni) { | |
| prev["selected_sni"] = context["selected_sni"]; | |
| context.selected_sni = options2.selected_sni; | |
| has_changed = true; | |
| } | |
| } | |
| if ("selected_session_id" in options2) { | |
| if (context.selected_session_id == null && options2.selected_session_id !== null || !arraybufferEqual2(options2.selected_session_id.buffer, context.selected_session_id.buffer)) { | |
| prev["selected_session_id"] = context["selected_session_id"]; | |
| context.selected_session_id = options2.selected_session_id; | |
| has_changed = true; | |
| } | |
| } | |
| if ("ecdhe_shared_secret" in options2) { | |
| if (context.ecdhe_shared_secret == null && options2.ecdhe_shared_secret !== null) { | |
| prev["ecdhe_shared_secret"] = context["ecdhe_shared_secret"]; | |
| context.ecdhe_shared_secret = options2.ecdhe_shared_secret; | |
| has_changed = true; | |
| } | |
| } | |
| if ("handshake_secret" in options2) { | |
| if (context.handshake_secret == null && options2.handshake_secret !== null) { | |
| prev["handshake_secret"] = context["handshake_secret"]; | |
| context.handshake_secret = options2.handshake_secret; | |
| has_changed = true; | |
| } | |
| } | |
| if ("client_handshake_traffic_secret" in options2) { | |
| if (context.client_handshake_traffic_secret == null && options2.client_handshake_traffic_secret !== null) { | |
| prev["client_handshake_traffic_secret"] = context["client_handshake_traffic_secret"]; | |
| context.client_handshake_traffic_secret = options2.client_handshake_traffic_secret; | |
| has_changed = true; | |
| } | |
| } | |
| if ("server_handshake_traffic_secret" in options2) { | |
| if (context.server_handshake_traffic_secret == null && options2.server_handshake_traffic_secret !== null) { | |
| prev["server_handshake_traffic_secret"] = context["server_handshake_traffic_secret"]; | |
| context.server_handshake_traffic_secret = options2.server_handshake_traffic_secret; | |
| has_changed = true; | |
| } | |
| } | |
| if ("client_app_traffic_secret" in options2) { | |
| if (context.client_app_traffic_secret == null && options2.client_app_traffic_secret !== null) { | |
| prev["client_app_traffic_secret"] = context["client_app_traffic_secret"]; | |
| context.client_app_traffic_secret = options2.client_app_traffic_secret; | |
| has_changed = true; | |
| } | |
| } | |
| if ("server_app_traffic_secret" in options2) { | |
| if (context.server_app_traffic_secret == null && options2.server_app_traffic_secret !== null) { | |
| prev["server_app_traffic_secret"] = context["server_app_traffic_secret"]; | |
| context.server_app_traffic_secret = options2.server_app_traffic_secret; | |
| has_changed = true; | |
| } | |
| } | |
| if ("local_cert_chain" in options2) { | |
| if (context.local_cert_chain == null && options2.local_cert_chain !== null) { | |
| prev["local_cert_chain"] = context["local_cert_chain"]; | |
| context.local_cert_chain = options2.local_cert_chain; | |
| has_changed = true; | |
| } | |
| } | |
| if ("cert_private_key" in options2) { | |
| if (context.cert_private_key == null && options2.cert_private_key !== null) { | |
| prev["cert_private_key"] = context["cert_private_key"]; | |
| context.cert_private_key = options2.cert_private_key; | |
| has_changed = true; | |
| } | |
| } | |
| if ("expected_remote_finished" in options2) { | |
| if (context.expected_remote_finished == null && options2.expected_remote_finished !== null) { | |
| prev["expected_remote_finished"] = context["expected_remote_finished"]; | |
| context.expected_remote_finished = options2.expected_remote_finished; | |
| has_changed = true; | |
| } | |
| } | |
| if ("remote_finished" in options2) { | |
| if (context.remote_finished == null && options2.remote_finished !== null) { | |
| prev["remote_finished"] = context["remote_finished"]; | |
| context.remote_finished = options2.remote_finished; | |
| has_changed = true; | |
| } | |
| } | |
| if ("remote_finished_ok" in options2) { | |
| if (context.remote_finished_ok !== options2.remote_finished_ok) { | |
| prev["remote_finished_ok"] = context["remote_finished_ok"]; | |
| context.remote_finished_ok = options2.remote_finished_ok; | |
| has_changed = true; | |
| } | |
| } | |
| } | |
| if (has_changed == true) { | |
| var params_to_set = {}; | |
| if (!arraysEqual(context.local_versions, prev.local_versions) || !arraysEqual(context.remote_versions, prev.remote_versions) || !arraysEqual(context.local_cipher_suites, prev.local_cipher_suites) || !arraysEqual(context.remote_cipher_suites, prev.remote_cipher_suites) || !arraysEqual(context.local_alpns, prev.local_alpns) || !arraysEqual(context.remote_alpns, prev.remote_alpns) || !arraysEqual(context.local_groups, prev.local_groups) || !arraysEqual(context.remote_groups, prev.remote_groups) || !arraysEqual(context.local_signature_algorithms, prev.local_signature_algorithms) || !arraysEqual(context.remote_signature_algorithms, prev.remote_signature_algorithms) || !arraysEqual(context.local_extensions, prev.local_extensions) || !arraysEqual(context.remote_key_shares, prev.remote_key_shares) || !arraybufferEqual2(context.remote_session_id.buffer, prev.remote_session_id.buffer) || context.remote_sni !== prev.remote_sni || true) { | |
| //!arraysEqual(context.local_ee_extensions, prev.local_ee_extensions) || // TLS 1.3 EE | |
| //!arraysEqual(context.remote_extensions_all, prev.remote_extensions_all) || | |
| //!arraysEqual(context.remote_extensions_unknown, prev.remote_extensions_unknown) || | |
| if (context.selected_version == null && context.local_versions.length > 0 && context.remote_versions.length > 0) { | |
| for (var i = 0;i < context.local_versions.length; i++) { | |
| var v = context.local_versions[i] | 0; | |
| for (var j = 0;j < context.remote_versions.length; j++) { | |
| if ((context.remote_versions[j] | 0) == v) { | |
| params_to_set["selected_version"] = v; | |
| break; | |
| } | |
| } | |
| if ("selected_version" in params_to_set == true && params_to_set.selected_version !== null) | |
| break; | |
| } | |
| if ("selected_version" in params_to_set == false || params_to_set.selected_version == null) {} | |
| } | |
| if (context.selected_cipher_suite == null && context.local_cipher_suites.length > 0 && context.remote_cipher_suites.length > 0) { | |
| for (var i2 = 0;i2 < context.local_cipher_suites.length; i2++) { | |
| var cs = context.local_cipher_suites[i2] | 0; | |
| for (var j2 = 0;j2 < context.remote_cipher_suites.length; j2++) { | |
| if ((context.remote_cipher_suites[j2] | 0) == cs) { | |
| params_to_set["selected_cipher_suite"] = cs; | |
| break; | |
| } | |
| } | |
| if ("selected_cipher_suite" in params_to_set == true && params_to_set.selected_cipher_suite !== null) | |
| break; | |
| } | |
| if ("selected_cipher_suite" in params_to_set == false || params_to_set.selected_cipher_suite == null) {} | |
| } | |
| if (context.selected_alpn == null && context.local_alpns && context.remote_alpns) { | |
| for (var a = 0;a < context.local_alpns.length; a++) { | |
| var cand = context.local_alpns[a]; | |
| for (var b = 0;b < context.remote_alpns.length; b++) { | |
| if (context.remote_alpns[b] === cand) { | |
| params_to_set["selected_alpn"] = cand; | |
| break; | |
| } | |
| } | |
| if ("selected_alpn" in params_to_set == true && params_to_set.selected_alpn !== null) | |
| break; | |
| } | |
| } | |
| if (context.selected_group == null) { | |
| if (context.selected_version == TLS_VERSION.TLS1_3) { | |
| if (context.local_groups.length > 0 && context.remote_key_shares.length > 0) { | |
| for (var g = 0;g < context.local_groups.length; g++) { | |
| var grp = context.local_groups[g] | 0; | |
| for (var k2 = 0;k2 < context.remote_key_shares.length; k2++) { | |
| var ent = context.remote_key_shares[k2]; | |
| if ((ent.group | 0) === grp) { | |
| params_to_set["selected_group"] = grp; | |
| params_to_set["remote_key_share_selected_public"] = ent.pubkey || ent.key_exchange || null; | |
| break; | |
| } | |
| } | |
| if ("selected_group" in params_to_set == true && params_to_set.selected_group !== null) | |
| break; | |
| } | |
| if (!params_to_set.selected_group && context.selected_version === TLS_VERSION.TLS1_3) { | |
| params_to_set["need_hrr"] = true; | |
| } | |
| if ("selected_group" in params_to_set == false || params_to_set.selected_group == null) {} | |
| } | |
| } else if (context.selected_version == TLS_VERSION.TLS1_2) { | |
| if (context.local_groups.length > 0 && context.remote_groups.length > 0) { | |
| for (let grp2 of context.local_groups) { | |
| if (context.remote_groups.some((g2) => (g2 | 0) === (grp2 | 0))) { | |
| params_to_set.selected_group = grp2 | 0; | |
| break; | |
| } | |
| } | |
| if ("selected_group" in params_to_set == false || params_to_set.selected_group == null) {} | |
| } | |
| } | |
| } | |
| if (context.selected_signature_algorithm == null && context.local_signature_algorithms.length > 0 && context.remote_signature_algorithms.length > 0) { | |
| for (var s = 0;s < context.local_signature_algorithms.length; s++) { | |
| var sa = context.local_signature_algorithms[s] | 0; | |
| for (var t = 0;t < context.remote_signature_algorithms.length; t++) { | |
| if ((context.remote_signature_algorithms[t] | 0) === sa) { | |
| params_to_set["selected_signature_algorithm"] = sa; | |
| break; | |
| } | |
| } | |
| if ("selected_signature_algorithm" in params_to_set == true && params_to_set.selected_signature_algorithm != null) | |
| break; | |
| } | |
| if ("selected_signature_algorithm" in params_to_set == false || params_to_set.selected_signature_algorithm == null) {} | |
| } | |
| if (context.selected_sni == null) { | |
| params_to_set["selected_sni"] = context.remote_sni || null; | |
| } | |
| if (context.selected_session_id == null) { | |
| params_to_set["selected_session_id"] = context.remote_session_id || new Uint8Array(0); | |
| } | |
| if (context.selected_extensions == null && false) { | |
| var sel; | |
| var allowed; | |
| if (context.local_extensions) { | |
| for (var lx;lx < context.local_extensions.length; lx++) { | |
| var lt; | |
| } | |
| } | |
| if (context.local_ee_extensions) { | |
| for (var ex;ex < context.local_ee_extensions.length; ex++) { | |
| var et; | |
| } | |
| } | |
| if (context.remote_extensions_all) { | |
| for (var rx;rx < context.remote_extensions_all.length; rx++) { | |
| var rt; | |
| } | |
| } | |
| } | |
| } | |
| if (context.selected_group !== null && context.local_key_share_private === null && context.local_key_share_public === null) { | |
| if (context.selected_version === TLS_VERSION.TLS1_3) { | |
| var client_public_key = null; | |
| for (var i = 0;i < context.remote_key_shares.length; i++) { | |
| if ((context.remote_key_shares[i].group | 0) === (context.selected_group | 0)) { | |
| client_public_key = context.remote_key_shares[i].pubkey || context.remote_key_shares[i].key_exchange || null; | |
| break; | |
| } | |
| } | |
| if (client_public_key !== null) { | |
| if (context.selected_group === 29) { | |
| var local_key_share_private = new Uint8Array(crypto2.randomBytes(32)); | |
| var local_key_share_public = x25519.getPublicKey(local_key_share_private); | |
| var ecdhe_shared_secret = x25519.getSharedSecret(local_key_share_private, client_public_key); | |
| params_to_set["local_key_share_private"] = local_key_share_private; | |
| params_to_set["local_key_share_public"] = local_key_share_public; | |
| params_to_set["ecdhe_shared_secret"] = ecdhe_shared_secret; | |
| } else if (context.selected_group === 23) { | |
| var local_key_share_private = p256.utils.randomPrivateKey(); | |
| var local_key_share_public = p256.getPublicKey(priv, false); | |
| var clientPoint = p256.ProjectivePoint.fromHex(client_public_key); | |
| var sharedPoint = clientPoint.multiply(BigInt("0x" + Buffer.from(priv).toString("hex"))); | |
| var affine = sharedPoint.toAffine(); | |
| var xHex = affine.x.toString(16).padStart(64, "0"); | |
| var ecdhe_shared_secret = Uint8Array.from(Buffer.from(xHex, "hex")); | |
| params_to_set["local_key_share_private"] = local_key_share_private; | |
| params_to_set["local_key_share_public"] = local_key_share_public; | |
| params_to_set["ecdhe_shared_secret"] = ecdhe_shared_secret; | |
| } | |
| } | |
| } else if (context.selected_version === TLS_VERSION.TLS1_2) { | |
| if (context.selected_group === 29) { | |
| const priv2 = new Uint8Array(crypto2.randomBytes(32)); | |
| const pub = x25519.getPublicKey(priv2); | |
| params_to_set.local_key_share_private = priv2; | |
| params_to_set.local_key_share_public = pub; | |
| } else if (context.selected_group === 23) { | |
| const priv2 = p256.utils.randomPrivateKey(); | |
| const pub = p256.getPublicKey(priv2, false); | |
| params_to_set.local_key_share_private = priv2; | |
| params_to_set.local_key_share_public = pub; | |
| } | |
| } | |
| } | |
| if (context.selected_version !== prev.selected_version || context.selected_cipher_suite !== prev.selected_cipher_suite || context.selected_session_id !== prev.selected_session_id || context.selected_group !== prev.selected_group || context.local_key_share_public !== prev.local_key_share_public) { | |
| var can_send_hello = false; | |
| if (context.hello_sent == false) { | |
| if (context.selected_version !== null && context.selected_cipher_suite !== null && context.selected_session_id !== null) { | |
| if (context.selected_version === TLS_VERSION.TLS1_3) { | |
| if (context.local_key_share_public !== null && context.selected_group !== null) { | |
| can_send_hello = true; | |
| } | |
| } else if (context.selected_version === TLS_VERSION.TLS1_2) { | |
| can_send_hello = true; | |
| } | |
| } | |
| } | |
| if (can_send_hello == true) { | |
| if (context.local_random == null) { | |
| context.local_random = new Uint8Array(crypto2.randomBytes(32)); | |
| } | |
| var build_message_params = null; | |
| if (context.selected_version == TLS_VERSION.TLS1_3) { | |
| build_message_params = { | |
| type: "server_hello", | |
| version: context.selected_version, | |
| random: context.local_random, | |
| session_id: context.remote_session_id, | |
| cipher_suite: context.selected_cipher_suite, | |
| extensions: [ | |
| { | |
| type: "SUPPORTED_VERSIONS", | |
| value: TLS_VERSION.TLS1_3 | |
| }, | |
| { | |
| type: "KEY_SHARE", | |
| value: { | |
| group: context.selected_group, | |
| key_exchange: context.local_key_share_public | |
| } | |
| } | |
| ] | |
| }; | |
| } else if (context.selected_version == TLS_VERSION.TLS1_2) { | |
| var ext_list = [ | |
| { type: "RENEGOTIATION_INFO", value: new Uint8Array(0) }, | |
| { type: 23, data: new Uint8Array(0) } | |
| ]; | |
| if (context.alpn_selected) { | |
| ext_list.push({ type: "ALPN", value: [String(context.alpn_selected)] }); | |
| } | |
| build_message_params = { | |
| type: "server_hello", | |
| version: context.selected_version, | |
| random: context.local_random, | |
| session_id: context.remote_session_id || new Uint8Array(0), | |
| cipher_suite: context.selected_cipher_suite, | |
| extensions: ext_list | |
| }; | |
| } | |
| if (build_message_params !== null) { | |
| var message_data = build_message(build_message_params); | |
| context.transcript.push(message_data); | |
| context.hello_sent = true; | |
| ev.emit("message", 0, context.message_sent_seq, "hello", message_data); | |
| context.message_sent_seq++; | |
| } | |
| } | |
| } | |
| if (context.selected_version === TLS_VERSION.TLS1_3) { | |
| if (context.selected_cipher_suite !== null && context.ecdhe_shared_secret !== null) { | |
| var d = derive_handshake_traffic_secrets(TLS_CIPHER_SUITES[context.selected_cipher_suite].hash, context.ecdhe_shared_secret, concatUint8Arrays2(context.transcript)); | |
| params_to_set["handshake_secret"] = d.handshake_secret; | |
| params_to_set["client_handshake_traffic_secret"] = d.client_handshake_traffic_secret; | |
| params_to_set["server_handshake_traffic_secret"] = d.server_handshake_traffic_secret; | |
| } | |
| } | |
| if (context.selected_version === TLS_VERSION.TLS1_3) { | |
| if (context.encrypted_exts_sent == false && context.hello_sent == true && context.server_handshake_traffic_secret !== null) { | |
| var extensions = []; | |
| if (context.selected_alpn !== null) { | |
| extensions.push({ type: "ALPN", value: [context.selected_alpn] }); | |
| } | |
| for (var i in context.local_extensions) { | |
| extensions.push(context.local_extensions[i]); | |
| } | |
| var message_data = build_message({ | |
| type: "encrypted_extensions", | |
| extensions | |
| }); | |
| context.transcript.push(message_data); | |
| context.encrypted_exts_sent = true; | |
| ev.emit("message", 1, context.message_sent_seq, "encrypted_extensions", message_data); | |
| context.message_sent_seq++; | |
| } | |
| } | |
| if (context.cert_sent == false && context.local_cert_chain !== null) { | |
| if (context.selected_version === TLS_VERSION.TLS1_3 && context.encrypted_exts_sent == true && context.server_handshake_traffic_secret !== null || context.selected_version === TLS_VERSION.TLS1_2 && context.hello_sent == true) { | |
| var message_data = build_message({ | |
| type: "certificate", | |
| version: context.selected_version, | |
| entries: context.local_cert_chain | |
| }); | |
| context.transcript.push(message_data); | |
| context.cert_sent = true; | |
| if (context.selected_version === TLS_VERSION.TLS1_3) { | |
| ev.emit("message", 1, context.message_sent_seq, "certificate", message_data); | |
| } else { | |
| ev.emit("message", 0, context.message_sent_seq, "certificate", message_data); | |
| } | |
| context.message_sent_seq++; | |
| } | |
| } | |
| if (context.selected_version === TLS_VERSION.TLS1_3) { | |
| if (context.cert_sent == true && context.cert_verify_sent == false && context.local_cert_chain !== null && context.server_handshake_traffic_secret !== null) { | |
| var tbs_data = build_cert_verify_tbs(TLS_CIPHER_SUITES[context.selected_cipher_suite].hash, true, concatUint8Arrays2(context.transcript)); | |
| var cert_private_key_obj = crypto2.createPrivateKey({ | |
| key: Buffer.from(context.cert_private_key), | |
| format: "der", | |
| type: "pkcs8" | |
| }); | |
| var SIG = { | |
| ECDSA_P256_SHA256: 1027, | |
| ECDSA_P384_SHA384: 1283, | |
| ECDSA_P521_SHA512: 1539, | |
| RSA_PSS_SHA256: 2052, | |
| RSA_PSS_SHA384: 2053, | |
| RSA_PSS_SHA512: 2054, | |
| ED25519: 2055, | |
| ED448: 2056 | |
| }; | |
| var candidates = []; | |
| if (cert_private_key_obj.asymmetricKeyType === "ed25519") | |
| candidates.push(SIG.ED25519); | |
| if (cert_private_key_obj.asymmetricKeyType === "ed448") | |
| candidates.push(SIG.ED448); | |
| if (cert_private_key_obj.asymmetricKeyType === "rsa") | |
| candidates.push(SIG.RSA_PSS_SHA256, SIG.RSA_PSS_SHA384, SIG.RSA_PSS_SHA512); | |
| if (cert_private_key_obj.asymmetricKeyType === "ec") { | |
| var c = cert_private_key_obj.asymmetricKeyDetails && cert_private_key_obj.asymmetricKeyDetails && cert_private_key_obj.asymmetricKeyDetails.namedCurve || ""; | |
| if (c === "prime256v1") | |
| candidates.push(SIG.ECDSA_P256_SHA256); | |
| if (c === "secp384r1") | |
| candidates.push(SIG.ECDSA_P384_SHA384); | |
| if (c === "secp521r1") | |
| candidates.push(SIG.ECDSA_P521_SHA512); | |
| } | |
| var preference_order = [ | |
| SIG.ED25519, | |
| SIG.ED448, | |
| SIG.ECDSA_P256_SHA256, | |
| SIG.ECDSA_P384_SHA384, | |
| SIG.ECDSA_P521_SHA512, | |
| SIG.RSA_PSS_SHA256, | |
| SIG.RSA_PSS_SHA384, | |
| SIG.RSA_PSS_SHA512 | |
| ]; | |
| var selected_scheme = null; | |
| for (var s of preference_order) { | |
| if (context.remote_signature_algorithms.includes(s) == true && candidates.includes(s) == true) { | |
| selected_scheme = s; | |
| break; | |
| } | |
| } | |
| var sig_data = null; | |
| switch (selected_scheme) { | |
| case SIG.ED25519: | |
| sig_data = new Uint8Array(crypto2.sign(null, tbs_data, cert_private_key_obj)); | |
| break; | |
| case SIG.ECDSA_P256_SHA256: | |
| sig_data = new Uint8Array(crypto2.sign("sha256", tbs_data, cert_private_key_obj)); | |
| break; | |
| case SIG.ECDSA_P384_SHA384: | |
| sig_data = new Uint8Array(crypto2.sign("sha384", tbs_data, cert_private_key_obj)); | |
| break; | |
| case SIG.ECDSA_P521_SHA512: | |
| sig_data = new Uint8Array(crypto2.sign("sha512", tbs_data, cert_private_key_obj)); | |
| break; | |
| case SIG.RSA_PSS_SHA256: | |
| sig_data = new Uint8Array(crypto2.sign("sha256", tbs_data, { | |
| key: cert_private_key_obj, | |
| padding: crypto2.constants.RSA_PKCS1_PSS_PADDING, | |
| saltLength: 32 | |
| })); | |
| break; | |
| case SIG.RSA_PSS_SHA384: | |
| sig_data = new Uint8Array(crypto2.sign("sha384", tbs_data, { | |
| key: cert_private_key_obj, | |
| padding: crypto2.constants.RSA_PKCS1_PSS_PADDING, | |
| saltLength: 48 | |
| })); | |
| break; | |
| case SIG.RSA_PSS_SHA512: | |
| sig_data = new Uint8Array(crypto2.sign("sha512", tbs_data, { | |
| key: cert_private_key_obj, | |
| padding: crypto2.constants.RSA_PKCS1_PSS_PADDING, | |
| saltLength: 64 | |
| })); | |
| break; | |
| } | |
| if (sig_data) { | |
| var message_data = build_message({ | |
| type: "certificate_verify", | |
| scheme: selected_scheme, | |
| signature: sig_data | |
| }); | |
| context.transcript.push(message_data); | |
| context.cert_verify_sent = true; | |
| ev.emit("message", 1, context.message_sent_seq, "certificate_verify", message_data); | |
| context.message_sent_seq++; | |
| } else {} | |
| } | |
| } | |
| if (context.selected_version === TLS_VERSION.TLS1_3) { | |
| if (context.cert_verify_sent == true && context.finished_sent == false && context.local_cert_chain !== null && context.server_handshake_traffic_secret !== null) { | |
| var finished_data = get_handshake_finished(TLS_CIPHER_SUITES[context.selected_cipher_suite].hash, context.server_handshake_traffic_secret, concatUint8Arrays2(context.transcript)); | |
| var message_data = build_message({ | |
| type: "finished", | |
| data: finished_data | |
| }); | |
| context.transcript.push(message_data); | |
| context.finished_sent = true; | |
| ev.emit("message", 1, context.message_sent_seq, "finished", message_data); | |
| context.message_sent_seq++; | |
| } | |
| } | |
| if (context.selected_version === TLS_VERSION.TLS1_3) { | |
| if (context.finished_sent == true && context.handshake_secret !== null && context.server_app_traffic_secret == null) { | |
| var d2 = derive_app_traffic_secrets(TLS_CIPHER_SUITES[context.selected_cipher_suite].hash, context.handshake_secret, concatUint8Arrays2(context.transcript)); | |
| params_to_set["handshake_secret"] = null; | |
| params_to_set["client_app_traffic_secret"] = d2.client_app_traffic_secret; | |
| params_to_set["server_app_traffic_secret"] = d2.server_app_traffic_secret; | |
| } | |
| } | |
| if (context.selected_version === TLS_VERSION.TLS1_3) { | |
| if (context.finished_sent == true && context.expected_remote_finished == null && context.client_handshake_traffic_secret !== null) { | |
| params_to_set["expected_remote_finished"] = get_handshake_finished(TLS_CIPHER_SUITES[context.selected_cipher_suite].hash, context.client_handshake_traffic_secret, concatUint8Arrays2(context.transcript)); | |
| } | |
| } | |
| if (context.selected_version === TLS_VERSION.TLS1_3) { | |
| if (context.remote_finished_ok == false && context.remote_finished !== null && context.expected_remote_finished !== null) { | |
| if (arraybufferEqual2(context.remote_finished.buffer, context.expected_remote_finished.buffer) == true) { | |
| context.transcript.push(context.remote_finished); | |
| context.remote_finished_ok = true; | |
| context.remote_finished = null; | |
| context.expected_remote_finished = null; | |
| } else { | |
| context.remote_finished = null; | |
| } | |
| } | |
| } | |
| if (context.selected_version === TLS_VERSION.TLS1_3) { | |
| if (context.remote_finished_ok == true && context.server_app_traffic_secret !== null) { | |
| ev.emit("secureConnect"); | |
| } | |
| } | |
| set_context(params_to_set); | |
| } | |
| } | |
| function close() {} | |
| var api = { | |
| context, | |
| on: function(name, fn) { | |
| ev.on(name, fn); | |
| }, | |
| message: process_income_message, | |
| set_context, | |
| close, | |
| getCipher: function() { | |
| return null; | |
| }, | |
| getPeerCertificate: function(detailed) { | |
| return context.peerCert; | |
| }, | |
| exportKeyingMaterial: function(length, label, context2) { | |
| return new Uint8Array(0); | |
| } | |
| }; | |
| for (var k in api) | |
| if (Object.prototype.hasOwnProperty.call(api, k)) | |
| this[k] = api[k]; | |
| return this; | |
| } | |
| var tls_session_default = TLSSession; | |
| // node_modules/@stablelib/wipe/lib/wipe.js | |
| function wipe(array) { | |
| for (let i = 0;i < array.length; i++) { | |
| array[i] = 0; | |
| } | |
| return array; | |
| } | |
| // node_modules/@stablelib/int/lib/int.js | |
| var MAX_SAFE_INTEGER = Number.MAX_SAFE_INTEGER; | |
| // node_modules/@stablelib/binary/lib/binary.js | |
| function readUint32BE(array, offset = 0) { | |
| return (array[offset] << 24 | array[offset + 1] << 16 | array[offset + 2] << 8 | array[offset + 3]) >>> 0; | |
| } | |
| function writeUint32BE(value, out = new Uint8Array(4), offset = 0) { | |
| out[offset + 0] = value >>> 24; | |
| out[offset + 1] = value >>> 16; | |
| out[offset + 2] = value >>> 8; | |
| out[offset + 3] = value >>> 0; | |
| return out; | |
| } | |
| // node_modules/@stablelib/aes/lib/aes.js | |
| var POWX = new Uint8Array([ | |
| 1, | |
| 2, | |
| 4, | |
| 8, | |
| 16, | |
| 32, | |
| 64, | |
| 128, | |
| 27, | |
| 54, | |
| 108, | |
| 216, | |
| 171, | |
| 77, | |
| 154, | |
| 47 | |
| ]); | |
| var SBOX0 = new Uint8Array([ | |
| 99, | |
| 124, | |
| 119, | |
| 123, | |
| 242, | |
| 107, | |
| 111, | |
| 197, | |
| 48, | |
| 1, | |
| 103, | |
| 43, | |
| 254, | |
| 215, | |
| 171, | |
| 118, | |
| 202, | |
| 130, | |
| 201, | |
| 125, | |
| 250, | |
| 89, | |
| 71, | |
| 240, | |
| 173, | |
| 212, | |
| 162, | |
| 175, | |
| 156, | |
| 164, | |
| 114, | |
| 192, | |
| 183, | |
| 253, | |
| 147, | |
| 38, | |
| 54, | |
| 63, | |
| 247, | |
| 204, | |
| 52, | |
| 165, | |
| 229, | |
| 241, | |
| 113, | |
| 216, | |
| 49, | |
| 21, | |
| 4, | |
| 199, | |
| 35, | |
| 195, | |
| 24, | |
| 150, | |
| 5, | |
| 154, | |
| 7, | |
| 18, | |
| 128, | |
| 226, | |
| 235, | |
| 39, | |
| 178, | |
| 117, | |
| 9, | |
| 131, | |
| 44, | |
| 26, | |
| 27, | |
| 110, | |
| 90, | |
| 160, | |
| 82, | |
| 59, | |
| 214, | |
| 179, | |
| 41, | |
| 227, | |
| 47, | |
| 132, | |
| 83, | |
| 209, | |
| 0, | |
| 237, | |
| 32, | |
| 252, | |
| 177, | |
| 91, | |
| 106, | |
| 203, | |
| 190, | |
| 57, | |
| 74, | |
| 76, | |
| 88, | |
| 207, | |
| 208, | |
| 239, | |
| 170, | |
| 251, | |
| 67, | |
| 77, | |
| 51, | |
| 133, | |
| 69, | |
| 249, | |
| 2, | |
| 127, | |
| 80, | |
| 60, | |
| 159, | |
| 168, | |
| 81, | |
| 163, | |
| 64, | |
| 143, | |
| 146, | |
| 157, | |
| 56, | |
| 245, | |
| 188, | |
| 182, | |
| 218, | |
| 33, | |
| 16, | |
| 255, | |
| 243, | |
| 210, | |
| 205, | |
| 12, | |
| 19, | |
| 236, | |
| 95, | |
| 151, | |
| 68, | |
| 23, | |
| 196, | |
| 167, | |
| 126, | |
| 61, | |
| 100, | |
| 93, | |
| 25, | |
| 115, | |
| 96, | |
| 129, | |
| 79, | |
| 220, | |
| 34, | |
| 42, | |
| 144, | |
| 136, | |
| 70, | |
| 238, | |
| 184, | |
| 20, | |
| 222, | |
| 94, | |
| 11, | |
| 219, | |
| 224, | |
| 50, | |
| 58, | |
| 10, | |
| 73, | |
| 6, | |
| 36, | |
| 92, | |
| 194, | |
| 211, | |
| 172, | |
| 98, | |
| 145, | |
| 149, | |
| 228, | |
| 121, | |
| 231, | |
| 200, | |
| 55, | |
| 109, | |
| 141, | |
| 213, | |
| 78, | |
| 169, | |
| 108, | |
| 86, | |
| 244, | |
| 234, | |
| 101, | |
| 122, | |
| 174, | |
| 8, | |
| 186, | |
| 120, | |
| 37, | |
| 46, | |
| 28, | |
| 166, | |
| 180, | |
| 198, | |
| 232, | |
| 221, | |
| 116, | |
| 31, | |
| 75, | |
| 189, | |
| 139, | |
| 138, | |
| 112, | |
| 62, | |
| 181, | |
| 102, | |
| 72, | |
| 3, | |
| 246, | |
| 14, | |
| 97, | |
| 53, | |
| 87, | |
| 185, | |
| 134, | |
| 193, | |
| 29, | |
| 158, | |
| 225, | |
| 248, | |
| 152, | |
| 17, | |
| 105, | |
| 217, | |
| 142, | |
| 148, | |
| 155, | |
| 30, | |
| 135, | |
| 233, | |
| 206, | |
| 85, | |
| 40, | |
| 223, | |
| 140, | |
| 161, | |
| 137, | |
| 13, | |
| 191, | |
| 230, | |
| 66, | |
| 104, | |
| 65, | |
| 153, | |
| 45, | |
| 15, | |
| 176, | |
| 84, | |
| 187, | |
| 22 | |
| ]); | |
| var SBOX1 = new Uint8Array([ | |
| 82, | |
| 9, | |
| 106, | |
| 213, | |
| 48, | |
| 54, | |
| 165, | |
| 56, | |
| 191, | |
| 64, | |
| 163, | |
| 158, | |
| 129, | |
| 243, | |
| 215, | |
| 251, | |
| 124, | |
| 227, | |
| 57, | |
| 130, | |
| 155, | |
| 47, | |
| 255, | |
| 135, | |
| 52, | |
| 142, | |
| 67, | |
| 68, | |
| 196, | |
| 222, | |
| 233, | |
| 203, | |
| 84, | |
| 123, | |
| 148, | |
| 50, | |
| 166, | |
| 194, | |
| 35, | |
| 61, | |
| 238, | |
| 76, | |
| 149, | |
| 11, | |
| 66, | |
| 250, | |
| 195, | |
| 78, | |
| 8, | |
| 46, | |
| 161, | |
| 102, | |
| 40, | |
| 217, | |
| 36, | |
| 178, | |
| 118, | |
| 91, | |
| 162, | |
| 73, | |
| 109, | |
| 139, | |
| 209, | |
| 37, | |
| 114, | |
| 248, | |
| 246, | |
| 100, | |
| 134, | |
| 104, | |
| 152, | |
| 22, | |
| 212, | |
| 164, | |
| 92, | |
| 204, | |
| 93, | |
| 101, | |
| 182, | |
| 146, | |
| 108, | |
| 112, | |
| 72, | |
| 80, | |
| 253, | |
| 237, | |
| 185, | |
| 218, | |
| 94, | |
| 21, | |
| 70, | |
| 87, | |
| 167, | |
| 141, | |
| 157, | |
| 132, | |
| 144, | |
| 216, | |
| 171, | |
| 0, | |
| 140, | |
| 188, | |
| 211, | |
| 10, | |
| 247, | |
| 228, | |
| 88, | |
| 5, | |
| 184, | |
| 179, | |
| 69, | |
| 6, | |
| 208, | |
| 44, | |
| 30, | |
| 143, | |
| 202, | |
| 63, | |
| 15, | |
| 2, | |
| 193, | |
| 175, | |
| 189, | |
| 3, | |
| 1, | |
| 19, | |
| 138, | |
| 107, | |
| 58, | |
| 145, | |
| 17, | |
| 65, | |
| 79, | |
| 103, | |
| 220, | |
| 234, | |
| 151, | |
| 242, | |
| 207, | |
| 206, | |
| 240, | |
| 180, | |
| 230, | |
| 115, | |
| 150, | |
| 172, | |
| 116, | |
| 34, | |
| 231, | |
| 173, | |
| 53, | |
| 133, | |
| 226, | |
| 249, | |
| 55, | |
| 232, | |
| 28, | |
| 117, | |
| 223, | |
| 110, | |
| 71, | |
| 241, | |
| 26, | |
| 113, | |
| 29, | |
| 41, | |
| 197, | |
| 137, | |
| 111, | |
| 183, | |
| 98, | |
| 14, | |
| 170, | |
| 24, | |
| 190, | |
| 27, | |
| 252, | |
| 86, | |
| 62, | |
| 75, | |
| 198, | |
| 210, | |
| 121, | |
| 32, | |
| 154, | |
| 219, | |
| 192, | |
| 254, | |
| 120, | |
| 205, | |
| 90, | |
| 244, | |
| 31, | |
| 221, | |
| 168, | |
| 51, | |
| 136, | |
| 7, | |
| 199, | |
| 49, | |
| 177, | |
| 18, | |
| 16, | |
| 89, | |
| 39, | |
| 128, | |
| 236, | |
| 95, | |
| 96, | |
| 81, | |
| 127, | |
| 169, | |
| 25, | |
| 181, | |
| 74, | |
| 13, | |
| 45, | |
| 229, | |
| 122, | |
| 159, | |
| 147, | |
| 201, | |
| 156, | |
| 239, | |
| 160, | |
| 224, | |
| 59, | |
| 77, | |
| 174, | |
| 42, | |
| 245, | |
| 176, | |
| 200, | |
| 235, | |
| 187, | |
| 60, | |
| 131, | |
| 83, | |
| 153, | |
| 97, | |
| 23, | |
| 43, | |
| 4, | |
| 126, | |
| 186, | |
| 119, | |
| 214, | |
| 38, | |
| 225, | |
| 105, | |
| 20, | |
| 99, | |
| 85, | |
| 33, | |
| 12, | |
| 125 | |
| ]); | |
| var isInitialized = false; | |
| var Te0; | |
| var Te1; | |
| var Te2; | |
| var Te3; | |
| var Td0; | |
| var Td1; | |
| var Td2; | |
| var Td3; | |
| function initialize() { | |
| const poly = 1 << 8 | 1 << 4 | 1 << 3 | 1 << 1 | 1 << 0; | |
| function mul(b, c) { | |
| let i = b; | |
| let j = c; | |
| let s = 0; | |
| for (let k = 1;k < 256 && j !== 0; k <<= 1) { | |
| if ((j & k) !== 0) { | |
| s ^= i; | |
| j ^= k; | |
| } | |
| i <<= 1; | |
| if ((i & 256) !== 0) { | |
| i ^= poly; | |
| } | |
| } | |
| return s; | |
| } | |
| const rot = (x) => x << 24 | x >>> 8; | |
| Te0 = new Uint32Array(256); | |
| Te1 = new Uint32Array(256); | |
| Te2 = new Uint32Array(256); | |
| Te3 = new Uint32Array(256); | |
| for (let i = 0;i < 256; i++) { | |
| const s = SBOX0[i]; | |
| let w = mul(s, 2) << 24 | s << 16 | s << 8 | mul(s, 3); | |
| Te0[i] = w; | |
| w = rot(w); | |
| Te1[i] = w; | |
| w = rot(w); | |
| Te2[i] = w; | |
| w = rot(w); | |
| Te3[i] = w; | |
| w = rot(w); | |
| } | |
| Td0 = new Uint32Array(256); | |
| Td1 = new Uint32Array(256); | |
| Td2 = new Uint32Array(256); | |
| Td3 = new Uint32Array(256); | |
| for (let i = 0;i < 256; i++) { | |
| const s = SBOX1[i]; | |
| let w = mul(s, 14) << 24 | mul(s, 9) << 16 | mul(s, 13) << 8 | mul(s, 11); | |
| Td0[i] = w; | |
| w = rot(w); | |
| Td1[i] = w; | |
| w = rot(w); | |
| Td2[i] = w; | |
| w = rot(w); | |
| Td3[i] = w; | |
| w = rot(w); | |
| } | |
| isInitialized = true; | |
| } | |
| class AES { | |
| blockSize = 16; | |
| _keyLen; | |
| _encKey; | |
| _decKey; | |
| constructor(key, noDecryption = false) { | |
| if (!isInitialized) { | |
| initialize(); | |
| } | |
| this._keyLen = key.length; | |
| this.setKey(key, noDecryption); | |
| } | |
| setKey(key, noDecryption = false) { | |
| if (key.length !== 16 && key.length !== 24 && key.length !== 32) { | |
| throw new Error("AES: wrong key size (must be 16, 24 or 32)"); | |
| } | |
| if (this._keyLen !== key.length) { | |
| throw new Error("AES: initialized with different key size"); | |
| } | |
| if (!this._encKey) { | |
| this._encKey = new Uint32Array(key.length + 28); | |
| } | |
| if (noDecryption) { | |
| if (this._decKey) { | |
| wipe(this._decKey); | |
| } | |
| } else { | |
| if (!this._decKey) { | |
| this._decKey = new Uint32Array(key.length + 28); | |
| } | |
| } | |
| expandKey(key, this._encKey, this._decKey); | |
| return this; | |
| } | |
| clean() { | |
| if (this._encKey) { | |
| wipe(this._encKey); | |
| } | |
| if (this._decKey) { | |
| wipe(this._decKey); | |
| } | |
| return this; | |
| } | |
| encryptBlock(src, dst) { | |
| if (src.length < this.blockSize) { | |
| throw new Error("AES: source block too small"); | |
| } | |
| if (dst.length < this.blockSize) { | |
| throw new Error("AES: destination block too small"); | |
| } | |
| encryptBlock(this._encKey, src, dst); | |
| return this; | |
| } | |
| decryptBlock(src, dst) { | |
| if (src.length < this.blockSize) { | |
| throw new Error("AES: source block too small"); | |
| } | |
| if (dst.length < this.blockSize) { | |
| throw new Error("AES: destination block too small"); | |
| } | |
| if (!this._decKey) { | |
| throw new Error("AES: decrypting with instance created with noDecryption option"); | |
| } else { | |
| decryptBlock(this._decKey, src, dst); | |
| } | |
| return this; | |
| } | |
| } | |
| function subw(w) { | |
| return SBOX0[w >>> 24 & 255] << 24 | SBOX0[w >>> 16 & 255] << 16 | SBOX0[w >>> 8 & 255] << 8 | SBOX0[w & 255]; | |
| } | |
| function rotw(w) { | |
| return w << 8 | w >>> 24; | |
| } | |
| function expandKey(key, encKey, decKey) { | |
| const nk = key.length / 4 | 0; | |
| const n = encKey.length; | |
| for (let i = 0;i < nk; i++) { | |
| encKey[i] = readUint32BE(key, i * 4); | |
| } | |
| for (let i = nk;i < n; i++) { | |
| let t = encKey[i - 1]; | |
| if (i % nk === 0) { | |
| t = subw(rotw(t)) ^ POWX[i / nk - 1] << 24; | |
| } else if (nk > 6 && i % nk === 4) { | |
| t = subw(t); | |
| } | |
| encKey[i] = encKey[i - nk] ^ t; | |
| } | |
| if (decKey) { | |
| for (let i = 0;i < n; i += 4) { | |
| const ei = n - i - 4; | |
| for (let j = 0;j < 4; j++) { | |
| let x = encKey[ei + j]; | |
| if (i > 0 && i + 4 < n) { | |
| x = Td0[SBOX0[x >>> 24 & 255]] ^ Td1[SBOX0[x >>> 16 & 255]] ^ Td2[SBOX0[x >>> 8 & 255]] ^ Td3[SBOX0[x & 255]]; | |
| } | |
| decKey[i + j] = x; | |
| } | |
| } | |
| } | |
| } | |
| function encryptBlock(xk, src, dst) { | |
| let s0 = readUint32BE(src, 0); | |
| let s1 = readUint32BE(src, 4); | |
| let s2 = readUint32BE(src, 8); | |
| let s3 = readUint32BE(src, 12); | |
| s0 ^= xk[0]; | |
| s1 ^= xk[1]; | |
| s2 ^= xk[2]; | |
| s3 ^= xk[3]; | |
| let t0 = 0, t1 = 0, t2 = 0, t3 = 0; | |
| const nr = xk.length / 4 - 2; | |
| let k = 4; | |
| for (let r = 0;r < nr; r++) { | |
| t0 = xk[k + 0] ^ Te0[s0 >>> 24 & 255] ^ Te1[s1 >>> 16 & 255] ^ Te2[s2 >>> 8 & 255] ^ Te3[s3 & 255]; | |
| t1 = xk[k + 1] ^ Te0[s1 >>> 24 & 255] ^ Te1[s2 >>> 16 & 255] ^ Te2[s3 >>> 8 & 255] ^ Te3[s0 & 255]; | |
| t2 = xk[k + 2] ^ Te0[s2 >>> 24 & 255] ^ Te1[s3 >>> 16 & 255] ^ Te2[s0 >>> 8 & 255] ^ Te3[s1 & 255]; | |
| t3 = xk[k + 3] ^ Te0[s3 >>> 24 & 255] ^ Te1[s0 >>> 16 & 255] ^ Te2[s1 >>> 8 & 255] ^ Te3[s2 & 255]; | |
| k += 4; | |
| s0 = t0; | |
| s1 = t1; | |
| s2 = t2; | |
| s3 = t3; | |
| } | |
| s0 = SBOX0[t0 >>> 24] << 24 | SBOX0[t1 >>> 16 & 255] << 16 | SBOX0[t2 >>> 8 & 255] << 8 | SBOX0[t3 & 255]; | |
| s1 = SBOX0[t1 >>> 24] << 24 | SBOX0[t2 >>> 16 & 255] << 16 | SBOX0[t3 >>> 8 & 255] << 8 | SBOX0[t0 & 255]; | |
| s2 = SBOX0[t2 >>> 24] << 24 | SBOX0[t3 >>> 16 & 255] << 16 | SBOX0[t0 >>> 8 & 255] << 8 | SBOX0[t1 & 255]; | |
| s3 = SBOX0[t3 >>> 24] << 24 | SBOX0[t0 >>> 16 & 255] << 16 | SBOX0[t1 >>> 8 & 255] << 8 | SBOX0[t2 & 255]; | |
| s0 ^= xk[k + 0]; | |
| s1 ^= xk[k + 1]; | |
| s2 ^= xk[k + 2]; | |
| s3 ^= xk[k + 3]; | |
| writeUint32BE(s0, dst, 0); | |
| writeUint32BE(s1, dst, 4); | |
| writeUint32BE(s2, dst, 8); | |
| writeUint32BE(s3, dst, 12); | |
| } | |
| function decryptBlock(xk, src, dst) { | |
| let s0 = readUint32BE(src, 0); | |
| let s1 = readUint32BE(src, 4); | |
| let s2 = readUint32BE(src, 8); | |
| let s3 = readUint32BE(src, 12); | |
| s0 ^= xk[0]; | |
| s1 ^= xk[1]; | |
| s2 ^= xk[2]; | |
| s3 ^= xk[3]; | |
| let t0 = 0, t1 = 0, t2 = 0, t3 = 0; | |
| const nr = xk.length / 4 - 2; | |
| let k = 4; | |
| for (let r = 0;r < nr; r++) { | |
| t0 = xk[k + 0] ^ Td0[s0 >>> 24 & 255] ^ Td1[s3 >>> 16 & 255] ^ Td2[s2 >>> 8 & 255] ^ Td3[s1 & 255]; | |
| t1 = xk[k + 1] ^ Td0[s1 >>> 24 & 255] ^ Td1[s0 >>> 16 & 255] ^ Td2[s3 >>> 8 & 255] ^ Td3[s2 & 255]; | |
| t2 = xk[k + 2] ^ Td0[s2 >>> 24 & 255] ^ Td1[s1 >>> 16 & 255] ^ Td2[s0 >>> 8 & 255] ^ Td3[s3 & 255]; | |
| t3 = xk[k + 3] ^ Td0[s3 >>> 24 & 255] ^ Td1[s2 >>> 16 & 255] ^ Td2[s1 >>> 8 & 255] ^ Td3[s0 & 255]; | |
| k += 4; | |
| s0 = t0; | |
| s1 = t1; | |
| s2 = t2; | |
| s3 = t3; | |
| } | |
| s0 = SBOX1[t0 >>> 24] << 24 | SBOX1[t3 >>> 16 & 255] << 16 | SBOX1[t2 >>> 8 & 255] << 8 | SBOX1[t1 & 255]; | |
| s1 = SBOX1[t1 >>> 24] << 24 | SBOX1[t0 >>> 16 & 255] << 16 | SBOX1[t3 >>> 8 & 255] << 8 | SBOX1[t2 & 255]; | |
| s2 = SBOX1[t2 >>> 24] << 24 | SBOX1[t1 >>> 16 & 255] << 16 | SBOX1[t0 >>> 8 & 255] << 8 | SBOX1[t3 & 255]; | |
| s3 = SBOX1[t3 >>> 24] << 24 | SBOX1[t2 >>> 16 & 255] << 16 | SBOX1[t1 >>> 8 & 255] << 8 | SBOX1[t0 & 255]; | |
| s0 ^= xk[k + 0]; | |
| s1 ^= xk[k + 1]; | |
| s2 ^= xk[k + 2]; | |
| s3 ^= xk[k + 3]; | |
| writeUint32BE(s0, dst, 0); | |
| writeUint32BE(s1, dst, 4); | |
| writeUint32BE(s2, dst, 8); | |
| writeUint32BE(s3, dst, 12); | |
| } | |
| // node_modules/@stablelib/ctr/lib/ctr.js | |
| class CTR { | |
| _counter; | |
| _buffer; | |
| _bufpos = 0; | |
| _cipher; | |
| constructor(cipher, iv) { | |
| this._counter = new Uint8Array(cipher.blockSize); | |
| this._buffer = new Uint8Array(cipher.blockSize); | |
| this.setCipher(cipher, iv); | |
| } | |
| setCipher(cipher, iv) { | |
| this._cipher = undefined; | |
| if (iv.length !== this._counter.length) { | |
| throw new Error("CTR: iv length must be equal to cipher block size"); | |
| } | |
| this._cipher = cipher; | |
| this._counter.set(iv); | |
| this._bufpos = this._buffer.length; | |
| return this; | |
| } | |
| clean() { | |
| wipe(this._buffer); | |
| wipe(this._counter); | |
| this._bufpos = this._buffer.length; | |
| this._cipher = undefined; | |
| return this; | |
| } | |
| fillBuffer() { | |
| this._cipher.encryptBlock(this._counter, this._buffer); | |
| this._bufpos = 0; | |
| incrementCounter(this._counter); | |
| } | |
| streamXOR(src, dst) { | |
| for (let i = 0;i < src.length; i++) { | |
| if (this._bufpos === this._buffer.length) { | |
| this.fillBuffer(); | |
| } | |
| dst[i] = src[i] ^ this._buffer[this._bufpos++]; | |
| } | |
| } | |
| stream(dst) { | |
| for (let i = 0;i < dst.length; i++) { | |
| if (this._bufpos === this._buffer.length) { | |
| this.fillBuffer(); | |
| } | |
| dst[i] = this._buffer[this._bufpos++]; | |
| } | |
| } | |
| } | |
| function incrementCounter(counter) { | |
| let carry = 1; | |
| for (let i = counter.length - 1;i >= 0; i--) { | |
| carry = carry + (counter[i] & 255) | 0; | |
| counter[i] = carry & 255; | |
| carry >>>= 8; | |
| } | |
| if (carry > 0) { | |
| throw new Error("CTR: counter overflow"); | |
| } | |
| } | |
| // node_modules/@stablelib/constant-time/lib/constant-time.js | |
| function compare(a, b) { | |
| if (a.length !== b.length) { | |
| return 0; | |
| } | |
| let result = 0; | |
| for (let i = 0;i < a.length; i++) { | |
| result |= a[i] ^ b[i]; | |
| } | |
| return 1 & result - 1 >>> 8; | |
| } | |
| function equal(a, b) { | |
| if (a.length === 0 || b.length === 0) { | |
| return false; | |
| } | |
| return compare(a, b) !== 0; | |
| } | |
| // node_modules/@stablelib/gcm/lib/gcm.js | |
| var NONCE_LENGTH = 12; | |
| var TAG_LENGTH = 16; | |
| class GCM { | |
| nonceLength = NONCE_LENGTH; | |
| tagLength = TAG_LENGTH; | |
| _subkey; | |
| _cipher; | |
| constructor(cipher) { | |
| if (cipher.blockSize !== 16) { | |
| throw new Error("GCM supports only 16-byte block cipher"); | |
| } | |
| this._cipher = cipher; | |
| this._subkey = new Uint8Array(this._cipher.blockSize); | |
| this._cipher.encryptBlock(new Uint8Array(this._cipher.blockSize), this._subkey); | |
| } | |
| seal(nonce, plaintext, associatedData, dst) { | |
| if (nonce.length !== this.nonceLength) { | |
| throw new Error("GCM: incorrect nonce length"); | |
| } | |
| const blockSize = this._cipher.blockSize; | |
| const resultLength = plaintext.length + this.tagLength; | |
| let result; | |
| if (dst) { | |
| if (dst.length !== resultLength) { | |
| throw new Error("GCM: incorrect destination length"); | |
| } | |
| result = dst; | |
| } else { | |
| result = new Uint8Array(resultLength); | |
| } | |
| const counter = new Uint8Array(blockSize); | |
| counter.set(nonce); | |
| counter[counter.length - 1] = 1; | |
| const tagMask = new Uint8Array(blockSize); | |
| this._cipher.encryptBlock(counter, tagMask); | |
| counter[counter.length - 1] = 2; | |
| const ctr = new CTR(this._cipher, counter); | |
| ctr.streamXOR(plaintext, result); | |
| ctr.clean(); | |
| this._authenticate(result.subarray(result.length - this.tagLength, result.length), tagMask, result.subarray(0, result.length - this.tagLength), associatedData); | |
| wipe(counter); | |
| wipe(tagMask); | |
| return result; | |
| } | |
| open(nonce, sealed, associatedData, dst) { | |
| if (nonce.length !== this.nonceLength) { | |
| throw new Error("GCM: incorrect nonce length"); | |
| } | |
| if (sealed.length < this.tagLength) { | |
| return null; | |
| } | |
| const blockSize = this._cipher.blockSize; | |
| const counter = new Uint8Array(blockSize); | |
| counter.set(nonce); | |
| counter[counter.length - 1] = 1; | |
| const tagMask = new Uint8Array(blockSize); | |
| this._cipher.encryptBlock(counter, tagMask); | |
| counter[counter.length - 1] = 2; | |
| const calculatedTag = new Uint8Array(this.tagLength); | |
| this._authenticate(calculatedTag, tagMask, sealed.subarray(0, sealed.length - this.tagLength), associatedData); | |
| if (!equal(calculatedTag, sealed.subarray(sealed.length - this.tagLength, sealed.length))) { | |
| return null; | |
| } | |
| const resultLength = sealed.length - this.tagLength; | |
| let result; | |
| if (dst) { | |
| if (dst.length !== resultLength) { | |
| throw new Error("GCM: incorrect destination length"); | |
| } | |
| result = dst; | |
| } else { | |
| result = new Uint8Array(resultLength); | |
| } | |
| const ctr = new CTR(this._cipher, counter); | |
| ctr.streamXOR(sealed.subarray(0, sealed.length - this.tagLength), result); | |
| ctr.clean(); | |
| wipe(counter); | |
| wipe(tagMask); | |
| return result; | |
| } | |
| clean() { | |
| wipe(this._subkey); | |
| return this; | |
| } | |
| _authenticate(tagOut, tagMask, ciphertext, associatedData) { | |
| const blockSize = this._cipher.blockSize; | |
| if (associatedData) { | |
| for (let i = 0;i < associatedData.length; i += blockSize) { | |
| const slice = associatedData.subarray(i, Math.min(i + blockSize, associatedData.length)); | |
| addmul(tagOut, slice, this._subkey); | |
| } | |
| } | |
| for (let i = 0;i < ciphertext.length; i += blockSize) { | |
| const slice = ciphertext.subarray(i, Math.min(i + blockSize, ciphertext.length)); | |
| addmul(tagOut, slice, this._subkey); | |
| } | |
| const lengthsBlock = new Uint8Array(blockSize); | |
| if (associatedData) { | |
| writeBitLength(associatedData.length, lengthsBlock, 0); | |
| } | |
| writeBitLength(ciphertext.length, lengthsBlock, 8); | |
| addmul(tagOut, lengthsBlock, this._subkey); | |
| for (let i = 0;i < tagMask.length; i++) { | |
| tagOut[i] ^= tagMask[i]; | |
| } | |
| wipe(lengthsBlock); | |
| } | |
| } | |
| function writeBitLength(byteLength, dst, offset = 0) { | |
| const hi = byteLength / 536870912 | 0; | |
| const lo = byteLength << 3; | |
| writeUint32BE(hi, dst, offset + 0); | |
| writeUint32BE(lo, dst, offset + 4); | |
| } | |
| function addmul(a, x, y) { | |
| for (let i = 0;i < x.length; i++) { | |
| a[i] ^= x[i]; | |
| } | |
| let v0 = y[3] | y[2] << 8 | y[1] << 16 | y[0] << 24; | |
| let v1 = y[7] | y[6] << 8 | y[5] << 16 | y[4] << 24; | |
| let v2 = y[11] | y[10] << 8 | y[9] << 16 | y[8] << 24; | |
| let v3 = y[15] | y[14] << 8 | y[13] << 16 | y[12] << 24; | |
| let z0 = 0, z1 = 0, z2 = 0, z3 = 0; | |
| for (let i = 0;i < 128; i++) { | |
| let mask = ~((-(a[i >> 3] & 1 << (~i & 7)) >>> 31 & 1) - 1); | |
| z0 ^= v0 & mask; | |
| z1 ^= v1 & mask; | |
| z2 ^= v2 & mask; | |
| z3 ^= v3 & mask; | |
| mask = ~((v3 & 1) - 1); | |
| v3 = v2 << 31 | v3 >>> 1; | |
| v2 = v1 << 31 | v2 >>> 1; | |
| v1 = v0 << 31 | v1 >>> 1; | |
| v0 = v0 >>> 1 ^ 3774873600 & mask; | |
| } | |
| writeUint32BE(z0, a, 0); | |
| writeUint32BE(z1, a, 4); | |
| writeUint32BE(z2, a, 8); | |
| writeUint32BE(z3, a, 12); | |
| } | |
| // node_modules/lemon-tls/tls_socket.js | |
| function Emitter2() { | |
| var listeners = {}; | |
| return { | |
| on: function(name, fn) { | |
| (listeners[name] = listeners[name] || []).push(fn); | |
| }, | |
| emit: function(name) { | |
| var args = Array.prototype.slice.call(arguments, 1); | |
| var arr = listeners[name] || []; | |
| for (var i = 0;i < arr.length; i++) { | |
| try { | |
| arr[i].apply(null, args); | |
| } catch (e) {} | |
| } | |
| } | |
| }; | |
| } | |
| var CT = { CHANGE_CIPHER_SPEC: 20, ALERT: 21, HANDSHAKE: 22, APPLICATION_DATA: 23 }; | |
| function toBuf(u82) { | |
| return Buffer.isBuffer(u82) ? u82 : Buffer.from(u82 || []); | |
| } | |
| function tls_derive_from_tls_secrets(traffic_secret, cipher_suite) { | |
| var empty = new Uint8Array(0); | |
| var key = hkdf_expand_label2(TLS_CIPHER_SUITES[cipher_suite].hash, traffic_secret, "key", empty, TLS_CIPHER_SUITES[cipher_suite].keylen); | |
| var iv = hkdf_expand_label2(TLS_CIPHER_SUITES[cipher_suite].hash, traffic_secret, "iv", empty, 12); | |
| return { | |
| key, | |
| iv | |
| }; | |
| } | |
| function get_nonce(iv, seq) { | |
| var seq_buf = new Uint8Array(12); | |
| var view = new DataView(seq_buf.buffer); | |
| view.setBigUint64(4, BigInt(seq)); | |
| var nonce = new Uint8Array(12); | |
| for (var i = 0;i < 12; i++) { | |
| nonce[i] = iv[i] ^ seq_buf[i]; | |
| } | |
| return nonce; | |
| } | |
| function encrypt_tls_record(innerType, plaintext, key, nonce) { | |
| const aes = new AES(key); | |
| const gcm = new GCM(aes); | |
| const full_plaintext = new Uint8Array(plaintext.length + 1); | |
| full_plaintext.set(plaintext); | |
| full_plaintext[plaintext.length] = innerType; | |
| const aad = new Uint8Array(5); | |
| aad[0] = 23; | |
| aad[1] = 3; | |
| aad[2] = 3; | |
| const recLen = full_plaintext.length + 16; | |
| aad[3] = recLen >>> 8 & 255; | |
| aad[4] = recLen & 255; | |
| const ciphertext = gcm.seal(nonce, full_plaintext, aad); | |
| return ciphertext; | |
| } | |
| function decrypt_tls_record(ciphertext, key, nonce) { | |
| var aes = new AES(key); | |
| var gcm = new GCM(aes); | |
| var aad = new Uint8Array(5); | |
| aad[0] = 23; | |
| aad[1] = 3; | |
| aad[2] = 3; | |
| var len = ciphertext.length; | |
| aad[3] = len >> 8 & 255; | |
| aad[4] = len & 255; | |
| var full_plaintext = gcm.open(nonce, ciphertext, aad); | |
| if (!full_plaintext) { | |
| throw new Error("GCM authentication failed (bad tag)"); | |
| } | |
| return full_plaintext; | |
| } | |
| function parse_tls_inner_plaintext(full_plaintext) { | |
| var j = full_plaintext.length - 1; | |
| while (j >= 0 && full_plaintext[j] === 0) { | |
| j--; | |
| } | |
| if (j < 0) | |
| throw new Error("Malformed TLSInnerPlaintext (no content type)"); | |
| var content_type = full_plaintext[j]; | |
| var content = full_plaintext.slice(0, j); | |
| return { content_type, content }; | |
| } | |
| function TLSSocket(duplex, options) { | |
| if (!(this instanceof TLSSocket)) | |
| return new TLSSocket(duplex, options); | |
| options = options || {}; | |
| var ev = Emitter2(); | |
| var context = { | |
| options, | |
| transport: duplex && typeof duplex.write === "function" ? duplex : null, | |
| session: new tls_session_default({ | |
| isServer: !!options.isServer, | |
| servername: options.servername, | |
| ALPNProtocols: options.ALPNProtocols || null, | |
| SNICallback: options.SNICallback || null | |
| }), | |
| handshake_write_key: null, | |
| handshake_write_iv: null, | |
| handshake_write_seq: 0, | |
| handshake_write_aead: null, | |
| handshake_read_key: null, | |
| handshake_read_iv: null, | |
| handshake_read_seq: 0, | |
| handshake_read_aead: null, | |
| app_write_key: null, | |
| app_write_iv: null, | |
| app_write_seq: 0, | |
| app_write_aead: null, | |
| app_read_key: null, | |
| app_read_iv: null, | |
| app_read_seq: 0, | |
| app_read_aead: null, | |
| using_app_keys: false, | |
| readBuffer: Buffer.alloc(0), | |
| appWriteQueue: [], | |
| destroyed: false, | |
| secureEstablished: false, | |
| rec_version: 771 | |
| }; | |
| function writeRecord(type, payload) { | |
| if (!context.transport) | |
| throw new Error("No transport attached to TLSSocket"); | |
| var rec = Buffer.allocUnsafe(5 + payload.length); | |
| rec.writeUInt8(type, 0); | |
| rec.writeUInt16BE(context.rec_version, 1); | |
| rec.writeUInt16BE(payload.length, 3); | |
| payload.copy(rec, 5); | |
| try { | |
| context.transport.write(rec); | |
| } catch (e) { | |
| ev.emit("error", e); | |
| } | |
| } | |
| function writeAppData(plain) { | |
| if (context.session.context.server_app_traffic_secret !== null) { | |
| if (context.app_write_key == null || context.app_write_iv == null) { | |
| var d = tls_derive_from_tls_secrets(context.session.context.server_app_traffic_secret, context.session.context.selected_cipher_suite); | |
| context.app_write_key = d.key; | |
| context.app_write_iv = d.iv; | |
| } | |
| } else {} | |
| var enc1 = encrypt_tls_record(CT.APPLICATION_DATA, plain, context.app_write_key, get_nonce(context.app_write_iv, context.app_write_seq)); | |
| context.app_write_seq++; | |
| try { | |
| writeRecord(CT.APPLICATION_DATA, Buffer.from(enc1)); | |
| } catch (e) { | |
| ev.emit("error", e); | |
| } | |
| } | |
| function processCiphertext(body) { | |
| var out = null; | |
| if (context.using_app_keys == true) { | |
| if (context.session.context.client_app_traffic_secret !== null) { | |
| if (context.app_read_key == null || context.app_read_iv == null) { | |
| var d = tls_derive_from_tls_secrets(context.session.context.client_app_traffic_secret, context.session.context.selected_cipher_suite); | |
| context.app_read_key = d.key; | |
| context.app_read_iv = d.iv; | |
| } | |
| out = decrypt_tls_record(body, context.app_read_key, get_nonce(context.app_read_iv, context.app_read_seq)); | |
| context.app_read_seq++; | |
| } else {} | |
| } else { | |
| if (context.session.context.client_handshake_traffic_secret !== null) { | |
| if (context.handshake_read_key == null || context.handshake_read_iv == null) { | |
| var d = tls_derive_from_tls_secrets(context.session.context.client_handshake_traffic_secret, context.session.context.selected_cipher_suite); | |
| context.handshake_read_key = d.key; | |
| context.handshake_read_iv = d.iv; | |
| } | |
| out = decrypt_tls_record(body, context.handshake_read_key, get_nonce(context.handshake_read_iv, context.handshake_read_seq)); | |
| context.handshake_read_seq++; | |
| } else {} | |
| } | |
| if (out !== null) { | |
| var { content_type, content } = parse_tls_inner_plaintext(out); | |
| if (content_type === CT.HANDSHAKE || content_type === CT.ALERT) { | |
| try { | |
| context.session.message(new Uint8Array(content)); | |
| } catch (e) { | |
| ev.emit("error", e); | |
| } | |
| return; | |
| } | |
| if (content_type === CT.APPLICATION_DATA) { | |
| ev.emit("data", content); | |
| return; | |
| } | |
| if (content_type === CT.CHANGE_CIPHER_SPEC) { | |
| return; | |
| } | |
| } | |
| } | |
| function parseRecordsAndDispatch() { | |
| while (context.readBuffer.length >= 5) { | |
| var type = context.readBuffer.readUInt8(0); | |
| var ver = context.readBuffer.readUInt16BE(1); | |
| var len = context.readBuffer.readUInt16BE(3); | |
| if (context.readBuffer.length < 5 + len) | |
| break; | |
| var body = context.readBuffer.slice(5, 5 + len); | |
| context.readBuffer = context.readBuffer.slice(5 + len); | |
| if (type === CT.APPLICATION_DATA) { | |
| try { | |
| processCiphertext(body); | |
| } catch (e) { | |
| ev.emit("error", e); | |
| } | |
| continue; | |
| } | |
| if (type === CT.HANDSHAKE || type === CT.ALERT || type === CT.CHANGE_CIPHER_SPEC) { | |
| try { | |
| context.session.message(new Uint8Array(body)); | |
| } catch (e) { | |
| ev.emit("error", e); | |
| } | |
| continue; | |
| } | |
| } | |
| } | |
| function bindTransport() { | |
| if (!context.transport) | |
| return; | |
| context.transport.on("data", function(chunk) { | |
| context.readBuffer = Buffer.concat([context.readBuffer, chunk]); | |
| parseRecordsAndDispatch(); | |
| }); | |
| context.transport.on("error", function(err) { | |
| ev.emit("error", err); | |
| }); | |
| context.transport.on("close", function() { | |
| ev.emit("close"); | |
| }); | |
| } | |
| context.session.on("message", function(epoch, seq, type, data) { | |
| var buf = toBuf(data || []); | |
| if (epoch === 0) { | |
| writeRecord(CT.HANDSHAKE, buf); | |
| return; | |
| } | |
| if (epoch === 1) { | |
| if (context.session.context.server_handshake_traffic_secret !== null) { | |
| if (context.handshake_write_key == null || context.handshake_write_iv == null) { | |
| var d = tls_derive_from_tls_secrets(context.session.context.server_handshake_traffic_secret, context.session.context.selected_cipher_suite); | |
| context.handshake_write_key = d.key; | |
| context.handshake_write_iv = d.iv; | |
| } | |
| var enc1 = encrypt_tls_record(CT.HANDSHAKE, buf, context.handshake_write_key, get_nonce(context.handshake_write_iv, context.handshake_write_seq)); | |
| context.handshake_write_seq++; | |
| try { | |
| writeRecord(CT.APPLICATION_DATA, Buffer.from(enc1)); | |
| } catch (e) { | |
| ev.emit("error", e); | |
| } | |
| } else { | |
| ev.emit("error", new Error("Missing handshake write keys")); | |
| } | |
| } | |
| if (epoch === 2) { | |
| if (!context.application_write) { | |
| ev.emit("error", new Error("Missing application write keys")); | |
| return; | |
| } | |
| try { | |
| var enc2 = aeadEncrypt(context.application_write, CT.HANDSHAKE, buf); | |
| writeRecord(CT.APPLICATION_DATA, enc2); | |
| } catch (e) { | |
| ev.emit("error", e); | |
| } | |
| return; | |
| } | |
| }); | |
| context.session.on("hello", function(info) { | |
| context.rec_version = 771; | |
| context.session.set_context({ | |
| local_versions: [772], | |
| local_alpns: ["http/1.1"], | |
| local_groups: [29, 23, 24], | |
| local_cipher_suites: [ | |
| 4865, | |
| 4866, | |
| 49199, | |
| 49200, | |
| 52392 | |
| ], | |
| local_signature_algorithms: [1025, 1281, 1537], | |
| local_signature_algorithms_cert: [1025, 1281, 1537] | |
| }); | |
| }); | |
| context.session.on("secureConnect", function() { | |
| context.using_app_keys = true; | |
| ev.emit("secureConnect"); | |
| }); | |
| if (context.transport) { | |
| bindTransport(); | |
| } | |
| var api = { | |
| on: function(name, fn) { | |
| ev.on(name, fn); | |
| }, | |
| setSocket: function(duplex2) { | |
| if (!duplex2 || typeof duplex2.write !== "function") | |
| throw new Error("setSocket expects a Duplex-like stream"); | |
| context.transport = duplex2; | |
| bindTransport(); | |
| }, | |
| write: function(data) { | |
| if (context.destroyed) | |
| return false; | |
| var buf = toBuf(data); | |
| if (!context.using_app_keys) { | |
| context.appWriteQueue.push(buf); | |
| return true; | |
| } | |
| return writeAppData(buf); | |
| }, | |
| end: function(data) { | |
| if (context.destroyed) | |
| return; | |
| if (typeof data !== "undefined" && data !== null) | |
| api.write(data); | |
| try { | |
| context.transport && context.transport.end && context.transport.end(); | |
| } catch (e) {} | |
| }, | |
| destroy: function() { | |
| if (context.destroyed) | |
| return; | |
| context.destroyed = true; | |
| try { | |
| context.transport && context.transport.destroy && context.transport.destroy(); | |
| } catch (e) {} | |
| }, | |
| getCipher: function() { | |
| var cs = context.session && context.session.context && context.session.context.selected_cipher_suite; | |
| return { name: cs || "TLS_AES_128_GCM_SHA256", version: "TLSv1.3" }; | |
| }, | |
| getPeerCertificate: function() { | |
| return null; | |
| }, | |
| authorized: function() { | |
| return true; | |
| } | |
| }; | |
| for (var k in api) | |
| if (Object.prototype.hasOwnProperty.call(api, k)) | |
| this[k] = api[k]; | |
| return this; | |
| } | |
| var tls_socket_default = TLSSocket; | |
| // node_modules/lemon-tls/secure_context.js | |
| import fs from "node:fs"; | |
| import path from "node:path"; | |
| import crypto3 from "node:crypto"; | |
| function looksLikePath(x) { | |
| return typeof x === "string" && x.indexOf(` | |
| `) === -1 && x.length < 4096 && x.indexOf("-----BEGIN") === -1; | |
| } | |
| function readMaybeFile(x) { | |
| if (x == null) | |
| return null; | |
| if (looksLikePath(x)) | |
| return fs.readFileSync(path.resolve(String(x))); | |
| if (Buffer.isBuffer(x)) | |
| return x; | |
| if (x instanceof Uint8Array) | |
| return Buffer.from(x); | |
| if (typeof x === "string") | |
| return Buffer.from(x, "utf8"); | |
| throw new Error("Unsupported input type (expected path/string/Buffer/Uint8Array)."); | |
| } | |
| function isPEM(buf) { | |
| if (!buf) | |
| return false; | |
| var s = buf.toString("utf8"); | |
| return s.indexOf("-----BEGIN ") !== -1 && s.indexOf("-----END ") !== -1; | |
| } | |
| function splitPEMBlocks(pemText) { | |
| var out = []; | |
| var re = /-----BEGIN ([A-Z0-9 \-]+)-----([\s\S]*?)-----END \1-----/g; | |
| var m; | |
| while ((m = re.exec(pemText)) !== null) { | |
| var typ = m[1].trim(); | |
| var b64 = m[2].replace(/[\r\n\s]/g, ""); | |
| var derBuf = Buffer.from(b64, "base64"); | |
| out.push({ type: typ, der: new Uint8Array(derBuf) }); | |
| } | |
| return out; | |
| } | |
| function ensureArray(x) { | |
| return x == null ? [] : Array.isArray(x) ? x : [x]; | |
| } | |
| function normalizeCA(caOption) { | |
| var arr = ensureArray(caOption); | |
| var ders = []; | |
| for (var i = 0;i < arr.length; i++) { | |
| var raw = readMaybeFile(arr[i]); | |
| if (!raw) | |
| continue; | |
| if (isPEM(raw)) { | |
| var blocks = splitPEMBlocks(raw.toString("utf8")); | |
| for (var j = 0;j < blocks.length; j++) { | |
| if (blocks[j].type.indexOf("CERTIFICATE") !== -1) | |
| ders.push(blocks[j].der); | |
| } | |
| } else { | |
| ders.push(new Uint8Array(raw)); | |
| } | |
| } | |
| return ders; | |
| } | |
| function makeX509FromDerOrPem(buf) { | |
| return new crypto3.X509Certificate(Buffer.from(buf)); | |
| } | |
| function makePrivateKeyFromDerOrPem(buf, passphrase) { | |
| if (isPEM(buf)) { | |
| return crypto3.createPrivateKey({ key: buf, format: "pem", passphrase }); | |
| } else { | |
| var der = Buffer.from(buf), keyObj = null; | |
| try { | |
| keyObj = crypto3.createPrivateKey({ key: der, format: "der", type: "pkcs8", passphrase }); | |
| } catch (e1) { | |
| try { | |
| keyObj = crypto3.createPrivateKey({ key: der, format: "der", type: "pkcs1", passphrase }); | |
| } catch (e2) { | |
| keyObj = crypto3.createPrivateKey({ key: der, format: "der", type: "sec1", passphrase }); | |
| } | |
| } | |
| return keyObj; | |
| } | |
| } | |
| function exportKeyPkcs8Der(keyObj) { | |
| return new Uint8Array(keyObj.export({ format: "der", type: "pkcs8" })); | |
| } | |
| function u8eq(a, b) { | |
| if (a.length !== b.length) | |
| return false; | |
| for (var i = 0;i < a.length; i++) | |
| if (a[i] !== b[i]) | |
| return false; | |
| return true; | |
| } | |
| function dedupeDerArray(arr) { | |
| var out = []; | |
| for (var i = 0;i < arr.length; i++) { | |
| var keep = true; | |
| for (var j = 0;j < out.length; j++) { | |
| if (u8eq(arr[i], out[j])) { | |
| keep = false; | |
| break; | |
| } | |
| } | |
| if (keep) | |
| out.push(arr[i]); | |
| } | |
| return out; | |
| } | |
| function createSecureContext(options) { | |
| if (!options) | |
| options = {}; | |
| var certBlocksDer = []; | |
| var certObjs = []; | |
| if (options.cert != null) { | |
| var cRaw = readMaybeFile(options.cert); | |
| if (isPEM(cRaw)) { | |
| var blocks = splitPEMBlocks(cRaw.toString("utf8")); | |
| for (var i = 0;i < blocks.length; i++) { | |
| if (blocks[i].type.indexOf("CERTIFICATE") !== -1) { | |
| certBlocksDer.push(blocks[i].der); | |
| certObjs.push(makeX509FromDerOrPem(blocks[i].der)); | |
| } | |
| } | |
| } else { | |
| var der = new Uint8Array(cRaw); | |
| certBlocksDer.push(der); | |
| certObjs.push(makeX509FromDerOrPem(der)); | |
| } | |
| } | |
| var keyObj = null; | |
| var privateKey = null; | |
| if (options.key != null) { | |
| var kRaw = readMaybeFile(options.key); | |
| keyObj = makePrivateKeyFromDerOrPem(kRaw, options.passphrase); | |
| privateKey = exportKeyPkcs8Der(keyObj); | |
| } | |
| if (!options.pfx) { | |
| if (certBlocksDer.length === 0) | |
| throw new Error("createSecureContext: missing cert."); | |
| if (!privateKey) | |
| throw new Error("createSecureContext: missing private key."); | |
| } | |
| var ca = normalizeCA(options.ca); | |
| var ocsp = null; | |
| if (options.ocsp != null) | |
| ocsp = new Uint8Array(readMaybeFile(options.ocsp)); | |
| var ticketKeys = null; | |
| if (options.ticketKeys != null) | |
| ticketKeys = new Uint8Array(readMaybeFile(options.ticketKeys)); | |
| var chainDer = dedupeDerArray(certBlocksDer); | |
| var certificateChain = []; | |
| for (var c = 0;c < chainDer.length; c++) { | |
| certificateChain.push({ cert: chainDer[c] }); | |
| } | |
| var leafPublicKeyType = null; | |
| if (certObjs.length > 0 && certObjs[0].publicKey) { | |
| try { | |
| leafPublicKeyType = certObjs[0].publicKey.asymmetricKeyType || null; | |
| } catch (e) { | |
| leafPublicKeyType = null; | |
| } | |
| } | |
| return { | |
| certificateChain, | |
| privateKey, | |
| ca, | |
| ocsp, | |
| ticketKeys, | |
| certObjs, | |
| keyObj, | |
| leafPublicKeyType, | |
| minVersion: String(options.minVersion || "TLSv1.2"), | |
| maxVersion: String(options.maxVersion || "TLSv1.3"), | |
| ciphers: options.ciphers || null, | |
| sigalgs: options.sigalgs || null, | |
| ecdhCurve: options.ecdhCurve || null, | |
| honorCipherOrder: !!options.honorCipherOrder, | |
| pfx: options.pfx ? new Uint8Array(readMaybeFile(options.pfx)) : null, | |
| passphrase: options.passphrase ? String(options.passphrase) : null | |
| }; | |
| } | |
| var secure_context_default = createSecureContext; | |
| // node_modules/lemon-tls/index.js | |
| var lemon_tls_default = { | |
| TLSSocket: tls_socket_default, | |
| TLSSession: tls_session_default, | |
| createSecureContext: secure_context_default | |
| }; | |
| // node_modules/quico/quic_socket.js | |
| var require2 = createRequire(import.meta.url); | |
| var flat_ranges = require2("flat-ranges"); | |
| function Emitter3() { | |
| var listeners = {}; | |
| return { | |
| on: function(name, fn) { | |
| (listeners[name] = listeners[name] || []).push(fn); | |
| }, | |
| emit: function(name) { | |
| var args = Array.prototype.slice.call(arguments, 1); | |
| var arr = listeners[name] || []; | |
| for (var i = 0;i < arr.length; i++) { | |
| try { | |
| arr[i].apply(null, args); | |
| } catch (e) {} | |
| } | |
| } | |
| }; | |
| } | |
| var TLS_CIPHER_SUITES2 = { | |
| 4865: { | |
| tls: 13, | |
| kex: "TLS13", | |
| sig: "TLS13", | |
| cipher: "AES_128_GCM", | |
| aead: true, | |
| keylen: 16, | |
| ivlen: 12, | |
| hash: "sha256" | |
| }, | |
| 4866: { | |
| tls: 13, | |
| kex: "TLS13", | |
| sig: "TLS13", | |
| cipher: "AES_256_GCM", | |
| aead: true, | |
| keylen: 32, | |
| ivlen: 12, | |
| hash: "sha384" | |
| }, | |
| 4867: { | |
| tls: 13, | |
| kex: "TLS13", | |
| sig: "TLS13", | |
| cipher: "CHACHA20_POLY1305", | |
| aead: true, | |
| keylen: 32, | |
| ivlen: 12, | |
| hash: "sha256" | |
| } | |
| }; | |
| function QUICSocket(options) { | |
| if (!(this instanceof QUICSocket)) | |
| return new QUICSocket(options); | |
| options = options || {}; | |
| var ev = Emitter3(); | |
| var context = { | |
| connection_status: 4, | |
| version: 1, | |
| my_cids: [], | |
| their_cids: [], | |
| original_dcid: null, | |
| tls_session: null, | |
| SNICallback: options.SNICallback || null, | |
| init_read_key: null, | |
| init_read_iv: null, | |
| init_read_hp: null, | |
| init_write_key: null, | |
| init_write_iv: null, | |
| init_write_hp: null, | |
| handshake_read_key: null, | |
| handshake_read_iv: null, | |
| handshake_read_hp: null, | |
| handshake_write_key: null, | |
| handshake_write_iv: null, | |
| handshake_write_hp: null, | |
| app_prev_read_key: null, | |
| app_prev_read_iv: null, | |
| app_prev_read_hp: null, | |
| app_read_key: null, | |
| app_read_iv: null, | |
| app_read_hp: null, | |
| read_key_phase: false, | |
| app_write_key: null, | |
| app_write_iv: null, | |
| app_write_hp: null, | |
| handshake_done: false, | |
| handshake_done_sent: false, | |
| sending_init_pn_next: 1, | |
| sending_init_chunks: [], | |
| sending_init_offset_next: 0, | |
| sending_init_pn_acked_ranges: [], | |
| sending_handshake_pn_next: 1, | |
| sending_handshake_chunks: [], | |
| sending_handshake_offset_next: 0, | |
| sending_handshake_pn_acked_ranges: [], | |
| sending_streams: {}, | |
| sending_stream_id_next: 0, | |
| max_sending_packets_per_sec: 1000, | |
| max_sending_total_bytes_per_sec: 150000, | |
| max_sending_packet_size: 1200, | |
| min_sending_packet_size: 35, | |
| max_sending_packets_in_flight: 20, | |
| max_sending_bytes_in_flight: 150000, | |
| sending_app_pn_base: 1, | |
| sending_app_pn_history: [], | |
| rtt_history: [], | |
| sending_app_pn_in_flight: new Set, | |
| next_send_quic_packet_timer: null, | |
| sending_quic_packet_now: false, | |
| receiving_init_pn_largest: -1, | |
| receiving_init_pn_ranges: [], | |
| receiving_init_chunks: {}, | |
| receiving_init_from_offset: 0, | |
| receiving_init_ranges: [], | |
| receiving_handshake_pn_largest: -1, | |
| receiving_handshake_pn_ranges: [], | |
| receiving_handshake_chunks: {}, | |
| receiving_handshake_from_offset: 0, | |
| receiving_handshake_ranges: [], | |
| receiving_app_pn_largest: -1, | |
| receiving_app_pn_ranges: [], | |
| receiving_app_pn_history: [], | |
| receiving_app_pn_pending_ack: [], | |
| receiving_streams: {}, | |
| receiving_streams_next_check_timer: null, | |
| remote_ack_delay_exponent: 3, | |
| remote_max_udp_payload_size: 1000 | |
| }; | |
| function set_context(options2) { | |
| var has_changed = false; | |
| var fields = [ | |
| "connection_status" | |
| ]; | |
| var prev = {}; | |
| if (options2 && typeof options2 === "object") { | |
| if ("connection_status" in options2) { | |
| if (context.connection_status !== options2.connection_status) { | |
| prev["connection_status"] = context["connection_status"]; | |
| context.connection_status = options2.connection_status; | |
| has_changed = true; | |
| } | |
| } | |
| } | |
| if (has_changed == true) { | |
| if (context.connection_status == 1 && context.connection_status !== prev.connection_status) { | |
| ev.emit("connect"); | |
| } | |
| } | |
| } | |
| function get_quic_stream_chunks_to_send(stream_id, allowed_bytes) { | |
| var stream = context.sending_streams[stream_id]; | |
| if (!stream || !stream.pending_data) { | |
| return { | |
| chunks: [], | |
| send_offset_next: stream ? stream.send_offset_next : 0 | |
| }; | |
| } | |
| var total_bytes = stream.total_size; | |
| if (typeof total_bytes !== "number" || total_bytes <= 0) { | |
| total_bytes = stream.write_offset_next; | |
| } | |
| var base_offset = stream.pending_offset_start; | |
| var send_offset_next = stream.send_offset_next; | |
| var relative_missing = flat_ranges.invert(stream.acked_ranges, 0, total_bytes); | |
| for (var i = 0;i < relative_missing.length; i++) { | |
| relative_missing[i] += base_offset; | |
| } | |
| var chunks = []; | |
| var total_bytes_used = 0; | |
| var first_chunk_offset = null; | |
| for (var i = 0;i < relative_missing.length; i += 2) { | |
| var f = relative_missing[i]; | |
| var t = relative_missing[i + 1]; | |
| if (f <= send_offset_next && send_offset_next < t) { | |
| var offset = send_offset_next; | |
| while (offset < t && total_bytes_used < allowed_bytes) { | |
| var space_left = allowed_bytes - total_bytes_used; | |
| var len = Math.min(space_left, t - offset); | |
| if (len <= 0) | |
| break; | |
| if (first_chunk_offset === null) | |
| first_chunk_offset = offset; | |
| var rel_start = offset - base_offset; | |
| var rel_end = rel_start + len; | |
| var chunk_data = stream.pending_data.slice(rel_start, rel_end); | |
| chunks.push({ | |
| offset, | |
| data: chunk_data | |
| }); | |
| total_bytes_used += len; | |
| offset += len; | |
| } | |
| break; | |
| } | |
| } | |
| if (total_bytes_used < allowed_bytes && first_chunk_offset !== null) { | |
| for (var i = 0;i < relative_missing.length; i += 2) { | |
| var f = relative_missing[i]; | |
| var t = relative_missing[i + 1]; | |
| var offset = f; | |
| while (offset < t && offset < first_chunk_offset && total_bytes_used < allowed_bytes) { | |
| var space_left = allowed_bytes - total_bytes_used; | |
| var len = Math.min(space_left, t - offset, first_chunk_offset - offset); | |
| if (len <= 0) | |
| break; | |
| var rel_start = offset - base_offset; | |
| var rel_end = rel_start + len; | |
| var chunk_data = stream.pending_data.slice(rel_start, rel_end); | |
| chunks.push({ | |
| offset, | |
| data: chunk_data | |
| }); | |
| total_bytes_used += len; | |
| offset += len; | |
| } | |
| } | |
| } | |
| var new_send_offset = send_offset_next; | |
| for (var i = 0;i < chunks.length; i++) { | |
| var chunk = chunks[i]; | |
| if (chunk.offset === new_send_offset) { | |
| new_send_offset = chunk.offset + chunk.data.length; | |
| } else { | |
| break; | |
| } | |
| } | |
| return { | |
| chunks, | |
| send_offset_next: new_send_offset | |
| }; | |
| } | |
| function prepare_and_send_quic_packet() { | |
| if (context.sending_quic_packet_now == false) { | |
| context.sending_quic_packet_now = true; | |
| if (context.next_send_quic_packet_timer !== null) { | |
| clearTimeout(context.next_send_quic_packet_timer); | |
| context.next_send_quic_packet_timer = null; | |
| } | |
| var now = Math.floor(performance.timeOrigin + performance.now()); | |
| var total_bytes_last_1s = 0; | |
| var packet_count_last_1s = 0; | |
| var oldest_packet_time_bytes = null; | |
| var oldest_packet_time_packets = null; | |
| for (var i in context.sending_app_pn_history) { | |
| var [ts, size] = context.sending_app_pn_history[i]; | |
| if (ts > now - 1000) { | |
| total_bytes_last_1s += size; | |
| packet_count_last_1s++; | |
| } else { | |
| if (oldest_packet_time_bytes === null || ts < oldest_packet_time_bytes) { | |
| oldest_packet_time_bytes = ts; | |
| } | |
| if (oldest_packet_time_packets === null || ts < oldest_packet_time_packets) { | |
| oldest_packet_time_packets = ts; | |
| } | |
| } | |
| } | |
| var bytes_left = context.max_sending_total_bytes_per_sec - total_bytes_last_1s; | |
| var packets_left = context.max_sending_packets_per_sec - packet_count_last_1s; | |
| var in_flight_packet_count = context.sending_app_pn_in_flight.size; | |
| var in_flight_total_bytes = 0; | |
| for (var pn of context.sending_app_pn_in_flight) { | |
| var pn_index = Number(pn) - (context.sending_app_pn_base - context.sending_app_pn_history.length); | |
| if (pn_index >= 0 && pn_index < context.sending_app_pn_history.length) { | |
| var info = context.sending_app_pn_history[pn_index]; | |
| if (info) { | |
| in_flight_total_bytes = in_flight_total_bytes + info[1]; | |
| } | |
| } | |
| } | |
| var in_flight_room = context.max_sending_bytes_in_flight - in_flight_total_bytes; | |
| var allowed_packet_size = Math.min(bytes_left, context.max_sending_packet_size, in_flight_room); | |
| if (packets_left > 0 && allowed_packet_size >= context.min_sending_packet_size && in_flight_packet_count < context.max_sending_packets_in_flight && in_flight_total_bytes + allowed_packet_size <= context.max_sending_bytes_in_flight) { | |
| var encoded_frames = []; | |
| var update_streams = {}; | |
| var remove_pending_ack = []; | |
| if (context.receiving_app_pn_pending_ack.length > 0 && true) { | |
| var ack_delay_ms = 0; | |
| var largest_pn = context.receiving_app_pn_pending_ack[context.receiving_app_pn_pending_ack.length - 1]; | |
| for (var i2 = 0;i2 < context.receiving_app_pn_history.length; i2++) { | |
| var [pn_recv, ts_recv, size_recv] = context.receiving_app_pn_history[i2]; | |
| if (pn_recv == largest_pn) { | |
| ack_delay_ms = now - ts_recv; | |
| break; | |
| } | |
| } | |
| var delay_ns = ack_delay_ms * 1e6; | |
| var ack_delay_raw = Math.floor(delay_ns / (1 << context.remote_ack_delay_exponent)); | |
| var ack_frame = build_ack_info_from_ranges(context.receiving_app_pn_pending_ack, null, ack_delay_raw); | |
| encoded_frames.push(encode_quic_frames([ack_frame])); | |
| remove_pending_ack = context.receiving_app_pn_pending_ack.slice(); | |
| } | |
| var active_stream_count = 0; | |
| for (var stream_id in context.sending_streams) { | |
| active_stream_count++; | |
| } | |
| var per_stream_bytes = Math.floor(allowed_packet_size / active_stream_count); | |
| for (var stream_id in context.sending_streams) { | |
| var chunks_ranges = []; | |
| var { chunks, send_offset_next } = get_quic_stream_chunks_to_send(Number(stream_id), per_stream_bytes); | |
| if (chunks.length > 0) { | |
| for (var i in chunks) { | |
| var is_fin = false; | |
| if (typeof context.sending_streams[stream_id].total_size == "number" && context.sending_streams[stream_id].total_size > 0 && chunks[i].offset + chunks[i].data.byteLength >= context.sending_streams[stream_id].total_size) { | |
| is_fin = true; | |
| } | |
| var stream_frame = { | |
| type: "stream", | |
| id: Number(stream_id), | |
| offset: chunks[i].offset, | |
| fin: is_fin, | |
| data: chunks[i].data | |
| }; | |
| encoded_frames.push(encode_quic_frames([stream_frame])); | |
| chunks_ranges.push(chunks[i].offset, chunks[i].offset + chunks[i].data.length); | |
| } | |
| chunks_ranges.sort(function(a, b) { | |
| return a - b; | |
| }); | |
| update_streams[stream_id] = { | |
| chunks_ranges, | |
| send_offset_next | |
| }; | |
| } | |
| } | |
| if (encoded_frames.length > 0) { | |
| if (encoded_frames.length == 1) { | |
| var all_encoded_frames = encoded_frames[0]; | |
| } else if (encoded_frames.length > 1) { | |
| var all_encoded_frames = concatUint8Arrays(encoded_frames); | |
| } | |
| send_quic_packet_frames("1rtt", all_encoded_frames); | |
| if (true) { | |
| now = Math.floor(performance.timeOrigin + performance.now()); | |
| var packet_number = context.sending_app_pn_base; | |
| context.sending_app_pn_history.push([now, all_encoded_frames.length]); | |
| context.sending_app_pn_in_flight.add(packet_number); | |
| for (var stream_id in update_streams) { | |
| context.sending_streams[stream_id].in_flight_ranges[packet_number] = update_streams[stream_id].chunks_ranges; | |
| context.sending_streams[stream_id].send_offset_next = update_streams[stream_id].send_offset_next; | |
| } | |
| if (remove_pending_ack.length > 0) { | |
| flat_ranges.remove(context.receiving_app_pn_pending_ack, remove_pending_ack); | |
| } | |
| context.sending_app_pn_base++; | |
| } | |
| context.next_send_quic_packet_timer = setTimeout(function() { | |
| context.sending_quic_packet_now = false; | |
| context.next_send_quic_packet_timer = null; | |
| prepare_and_send_quic_packet(); | |
| }, 0); | |
| } else { | |
| context.next_send_quic_packet_timer = null; | |
| context.sending_quic_packet_now = false; | |
| } | |
| } else { | |
| var wait_options = []; | |
| if (packets_left <= 0 && oldest_packet_time_packets !== null) { | |
| var wait_packets = Math.max(0, oldest_packet_time_packets + 1000 - now); | |
| wait_options.push(wait_packets); | |
| } | |
| if (bytes_left < context.min_sending_packet_size && oldest_packet_time_bytes !== null) { | |
| var wait_bytes = Math.max(0, oldest_packet_time_bytes + 1000 - now); | |
| wait_options.push(wait_bytes); | |
| } | |
| if (wait_options.length > 0) { | |
| context.next_send_quic_packet_timer = setTimeout(function() { | |
| context.next_send_quic_packet_timer = null; | |
| context.sending_quic_packet_now = false; | |
| prepare_and_send_quic_packet(); | |
| }, Math.max(...wait_options)); | |
| } else { | |
| context.sending_quic_packet_now = false; | |
| } | |
| } | |
| } | |
| } | |
| function stream_write(stream_id, data, fin) { | |
| console.log("stream_write1", data, fin); | |
| if (stream_id in context.sending_streams == false) { | |
| context.sending_streams[stream_id] = { | |
| pending_data: null, | |
| write_offset_next: 0, | |
| pending_offset_start: 0, | |
| send_offset_next: 0, | |
| total_size: 0, | |
| in_flight_ranges: {}, | |
| acked_ranges: [] | |
| }; | |
| } | |
| var stream = context.sending_streams[stream_id]; | |
| if (data == null) { | |
| if (stream.total_size == 0) { | |
| stream.total_size = stream.write_offset_next; | |
| } | |
| } else { | |
| var start_offset = stream.write_offset_next; | |
| var end_offset = start_offset + data.byteLength; | |
| stream.write_offset_next = end_offset; | |
| var pending_offset_start = 0; | |
| if (stream.acked_ranges.length > 0 && stream.acked_ranges[0] === 0) { | |
| pending_offset_start = stream.acked_ranges[1]; | |
| } | |
| var skip = Math.max(pending_offset_start - start_offset, 0); | |
| if (skip >= data.byteLength) | |
| return; | |
| var trimmed_data = data.slice(skip); | |
| if (stream.pending_data === null) { | |
| stream.pending_data = trimmed_data; | |
| stream.pending_offset_start = start_offset + skip; | |
| } else { | |
| var old = stream.pending_data; | |
| var old_offset = stream.pending_offset_start; | |
| var new_offset = start_offset + skip; | |
| var new_start = Math.min(old_offset, new_offset); | |
| var new_end = Math.max(old_offset + old.length, new_offset + trimmed_data.length); | |
| var total_len = new_end - new_start; | |
| var merged = new Uint8Array(total_len); | |
| merged.set(old, old_offset - new_start); | |
| merged.set(trimmed_data, new_offset - new_start); | |
| stream.pending_data = merged; | |
| stream.pending_offset_start = new_start; | |
| } | |
| } | |
| if (typeof fin == "boolean" && fin == true || data == null) { | |
| if (stream.total_size == 0) { | |
| stream.total_size = stream.write_offset_next; | |
| } | |
| } | |
| prepare_and_send_quic_packet(); | |
| } | |
| function send_quic_packet_frames(packet_type, encoded_frames) { | |
| var write_key = null; | |
| var write_iv = null; | |
| var write_hp = null; | |
| var packet_number = 1; | |
| if (packet_type == "initial") { | |
| if (context.init_write_key !== null && context.init_write_iv !== null && context.init_write_hp !== null) { | |
| write_key = context.init_write_key; | |
| write_iv = context.init_write_iv; | |
| write_hp = context.init_write_hp; | |
| } else { | |
| var d = quic_derive_init_secrets(context.original_dcid, context.version, "write"); | |
| write_key = d.key; | |
| write_iv = d.iv; | |
| write_hp = d.hp; | |
| context.init_write_key = d.key; | |
| context.init_write_iv = d.iv; | |
| context.init_write_hp = d.hp; | |
| } | |
| packet_number = Number(context.sending_init_pn_next) + 0; | |
| } else if (packet_type == "handshake") { | |
| if (context.handshake_write_key !== null && context.handshake_write_iv !== null && context.handshake_write_hp !== null) { | |
| write_key = context.handshake_write_key; | |
| write_iv = context.handshake_write_iv; | |
| write_hp = context.handshake_write_hp; | |
| } else if (context.tls_session.context.server_handshake_traffic_secret !== null) { | |
| var d = quic_derive_from_tls_secrets(context.tls_session.context.server_handshake_traffic_secret, TLS_CIPHER_SUITES2[context.tls_session.context.selected_cipher_suite].hash); | |
| write_key = d.key; | |
| write_iv = d.iv; | |
| write_hp = d.hp; | |
| context.handshake_write_key = d.key; | |
| context.handshake_write_iv = d.iv; | |
| context.handshake_write_hp = d.hp; | |
| } | |
| packet_number = Number(context.sending_handshake_pn_next) + 0; | |
| } else if (packet_type == "1rtt") { | |
| if (context.app_write_key !== null && context.app_write_iv !== null && context.app_write_hp !== null) { | |
| write_key = context.app_write_key; | |
| write_iv = context.app_write_iv; | |
| write_hp = context.app_write_hp; | |
| } else if (context.tls_session.context.server_app_traffic_secret !== null) { | |
| var d = quic_derive_from_tls_secrets(context.tls_session.context.server_app_traffic_secret, TLS_CIPHER_SUITES2[context.tls_session.context.selected_cipher_suite].hash); | |
| write_key = d.key; | |
| write_iv = d.iv; | |
| write_hp = d.hp; | |
| context.app_write_key = d.key; | |
| context.app_write_iv = d.iv; | |
| context.app_write_hp = d.hp; | |
| } | |
| packet_number = Number(context.sending_app_pn_base) + 0; | |
| } | |
| var dcid = new Uint8Array(0); | |
| if (context.their_cids.length > 0) { | |
| dcid = context.their_cids[0]; | |
| } | |
| var encrypted_quic_packet = encrypt_quic_packet(packet_type, encoded_frames, write_key, write_iv, write_hp, packet_number, dcid, context.original_dcid, new Uint8Array(0)); | |
| if (packet_type == "initial") { | |
| context.sending_init_pn_next++; | |
| } else if (packet_type == "handshake") { | |
| context.sending_handshake_pn_next++; | |
| } else if (packet_type == "1rtt") { | |
| var now = Math.floor(performance.timeOrigin + performance.now()); | |
| context.sending_app_pn_history.push([now, encoded_frames.length]); | |
| context.sending_app_pn_base++; | |
| } | |
| ev.emit("packet", encrypted_quic_packet); | |
| } | |
| function process_reset_stream_frame(packet_type, stream_id, final_size, reset_error_code) { | |
| if (stream_id in context.receiving_streams == false) { | |
| context.receiving_streams[stream_id] = { | |
| data_chunks: {}, | |
| total_size: 0, | |
| receiving_ranges: [], | |
| next_flush_offset: 0, | |
| next_flush_timer: null, | |
| reset_error_code: 0, | |
| delete_timer: null | |
| }; | |
| } | |
| context.receiving_streams[stream_id].total_size = final_size | 0; | |
| context.receiving_streams[stream_id].reset_error_code = reset_error_code | 0; | |
| } | |
| function process_stream_frame(packet_type, stream_id, offset, data, fin) { | |
| console.log("process_stream_frame", new TextDecoder().decode(data)); | |
| var is_new_chunk = false; | |
| if (stream_id in context.receiving_streams == false) { | |
| context.receiving_streams[stream_id] = { | |
| data_chunks: {}, | |
| total_size: 0, | |
| receiving_ranges: [], | |
| next_flush_offset: 0, | |
| next_flush_timer: null, | |
| reset_error_code: 0, | |
| delete_timer: null | |
| }; | |
| } | |
| if (flat_ranges.add(context.receiving_streams[stream_id].receiving_ranges, [offset, offset + data.length]) == true) { | |
| if (offset in context.receiving_streams[stream_id].data_chunks == false || context.receiving_streams[stream_id].data_chunks[offset].byteLength < data.byteLength) { | |
| context.receiving_streams[stream_id].data_chunks[offset] = data; | |
| } | |
| if (typeof fin == "boolean" && fin == true) { | |
| context.receiving_streams[stream_id].total_size = offset + data.byteLength; | |
| } | |
| is_new_chunk = true; | |
| } | |
| if (is_new_chunk == true) { | |
| if (context.receiving_streams[stream_id].receiving_ranges.length == 2 && typeof context.receiving_streams[stream_id].total_size == "number" && context.receiving_streams[stream_id].total_size > 0 && context.receiving_streams[stream_id].receiving_ranges[0] == 0 && context.receiving_streams[stream_id].receiving_ranges[1] == context.receiving_streams[stream_id].total_size) { | |
| flush_stream_chunk(stream_id); | |
| } else if (context.receiving_streams[stream_id].next_flush_timer == null) { | |
| context.receiving_streams[stream_id].next_flush_timer = setTimeout(function() { | |
| context.receiving_streams[stream_id].next_flush_timer = null; | |
| flush_stream_chunk(stream_id); | |
| }, 3); | |
| } | |
| } | |
| } | |
| function flush_stream_chunk(stream_id) { | |
| if (stream_id in context.receiving_streams == true) { | |
| if (context.receiving_streams[stream_id].next_flush_timer !== null) { | |
| clearTimeout(context.receiving_streams[stream_id].next_flush_timer); | |
| context.receiving_streams[stream_id].next_flush_timer = null; | |
| } | |
| var to_concat = []; | |
| var next_flush_offset = context.receiving_streams[stream_id].next_flush_offset; | |
| while (next_flush_offset in context.receiving_streams[stream_id].data_chunks) { | |
| var part = context.receiving_streams[stream_id].data_chunks[next_flush_offset]; | |
| delete context.receiving_streams[stream_id].data_chunks[next_flush_offset]; | |
| to_concat.push(part); | |
| next_flush_offset += part.byteLength; | |
| } | |
| if (to_concat.length > 0) { | |
| context.receiving_streams[stream_id].next_flush_offset = next_flush_offset; | |
| if (to_concat.length > 2) { | |
| var out = concatUint8Arrays(to_concat); | |
| } else { | |
| var out = to_concat[0]; | |
| } | |
| if (context.receiving_streams[stream_id].total_size > 0 && context.receiving_streams[stream_id].total_size <= context.receiving_streams[stream_id].next_flush_offset) { | |
| var fin = true; | |
| } else { | |
| var fin = false; | |
| } | |
| ev.emit("stream", Number(stream_id), out, fin); | |
| } | |
| } | |
| } | |
| function crypto_write(packet_type, data) { | |
| if (packet_type == "initial") { | |
| var encoded_frames = encode_quic_frames([{ | |
| type: "crypto", | |
| offset: context.sending_init_offset_next, | |
| data | |
| }]); | |
| context.sending_init_offset_next = context.sending_init_offset_next + data.byteLength; | |
| } else if (packet_type == "handshake") { | |
| var encoded_frames = encode_quic_frames([{ | |
| type: "crypto", | |
| offset: context.sending_handshake_offset_next, | |
| data | |
| }]); | |
| context.sending_handshake_offset_next = context.sending_handshake_offset_next + data.byteLength; | |
| } | |
| send_quic_packet_frames(packet_type, encoded_frames); | |
| } | |
| function process_crypto_frame(packet_type, offset, data) { | |
| var is_new_chunk = false; | |
| if (packet_type == "initial") { | |
| if (flat_ranges.add(context.receiving_init_ranges, [offset, offset + data.length]) == true) { | |
| if (offset in context.receiving_init_chunks == false || context.receiving_init_chunks[offset].byteLength < data.byteLength) { | |
| context.receiving_init_chunks[offset] = data; | |
| } | |
| is_new_chunk = true; | |
| } | |
| } else if (packet_type == "handshake") { | |
| if (flat_ranges.add(context.receiving_handshake_ranges, [offset, offset + data.length]) == true) { | |
| if (offset in context.receiving_handshake_chunks == false || context.receiving_handshake_chunks[offset].byteLength < data.byteLength) { | |
| context.receiving_handshake_chunks[offset] = data; | |
| } | |
| is_new_chunk = true; | |
| } | |
| } | |
| if (is_new_chunk == true) { | |
| var tls_messages = []; | |
| if (packet_type == "initial") { | |
| var ext = extract_tls_messages_from_chunks(context.receiving_init_chunks, context.receiving_init_from_offset); | |
| if (ext) { | |
| tls_messages = ext.tls_messages; | |
| context.receiving_init_from_offset = ext.new_from_offset; | |
| } | |
| } else if (packet_type == "handshake") { | |
| var ext = extract_tls_messages_from_chunks(context.receiving_handshake_chunks, context.receiving_handshake_from_offset); | |
| if (ext) { | |
| tls_messages = ext.tls_messages; | |
| context.receiving_handshake_from_offset = ext.new_from_offset; | |
| } | |
| } | |
| if (tls_messages && tls_messages.length > 0) { | |
| if (context.tls_session == null) { | |
| context.tls_session = new tls_session_default({ | |
| isServer: true, | |
| SNICallback: context.SNICallback | |
| }); | |
| context.tls_session.on("message", function(epoch, seq, type, data2) { | |
| if (epoch == 0) { | |
| crypto_write("initial", data2); | |
| } else if (epoch == 1) { | |
| crypto_write("handshake", data2); | |
| } else if (epoch == 3) { | |
| crypto_write("app", data2); | |
| } | |
| }); | |
| context.tls_session.on("hello", function(info) { | |
| var quic_ext_data = build_quic_ext({ | |
| original_destination_connection_id: context.original_dcid, | |
| initial_source_connection_id: context.original_dcid, | |
| max_udp_payload_size: 65527, | |
| max_idle_timeout: 30000, | |
| stateless_reset_token: new Uint8Array(16).fill(171), | |
| initial_max_data: 1048576, | |
| initial_max_stream_data_bidi_local: 262144, | |
| initial_max_stream_data_bidi_remote: 262144, | |
| initial_max_stream_data_uni: 131072, | |
| initial_max_streams_bidi: 100, | |
| initial_max_streams_uni: 3, | |
| ack_delay_exponent: 3, | |
| max_ack_delay: 25, | |
| disable_active_migration: true, | |
| active_connection_id_limit: 4, | |
| max_datagram_frame_size: 65527, | |
| web_accepted_origins: [ | |
| "*" | |
| ] | |
| }); | |
| context.tls_session.set_context({ | |
| local_versions: [772], | |
| local_alpns: ["h3"], | |
| local_groups: [29, 23, 24], | |
| local_cipher_suites: [ | |
| 4865, | |
| 4866, | |
| 49199, | |
| 49200, | |
| 52392 | |
| ], | |
| local_extensions: [ | |
| { type: 57, data: quic_ext_data } | |
| ], | |
| local_signature_algorithms: [1025, 1281, 1537], | |
| local_signature_algorithms_cert: [1025, 1281, 1537] | |
| }); | |
| }); | |
| context.tls_session.on("secureConnect", function() { | |
| set_context({ | |
| connection_status: 1, | |
| handshake_done: true | |
| }); | |
| }); | |
| } | |
| for (var i in tls_messages) { | |
| context.tls_session.message(tls_messages[i]); | |
| } | |
| } | |
| } | |
| } | |
| function process_ack_frame(packet_type, frame) { | |
| var acked_ranges = quic_acked_info_to_ranges(frame); | |
| if (packet_type == "initial") { | |
| if (flat_ranges.add(context.sending_init_pn_acked_ranges, acked_ranges) == true) {} | |
| } else if (packet_type == "handshake") { | |
| if (flat_ranges.add(context.sending_handshake_pn_acked_ranges, acked_ranges) == true) {} | |
| } else if (packet_type == "1rtt") { | |
| if ("largest" in frame && "delay" in frame) { | |
| var largest_pn = frame.largest; | |
| if (context.sending_app_pn_in_flight.has(largest_pn) == true) { | |
| var now = Math.floor(performance.timeOrigin + performance.now()); | |
| var ack_delay_raw = frame.delay; | |
| var ack_delay_ms = Math.round(ack_delay_raw * Math.pow(2, 3) / 1000); | |
| var pn_index = largest_pn - (context.sending_app_pn_base - context.sending_app_pn_history.length); | |
| if (pn_index >= 0 && pn_index < context.sending_app_pn_history.length) { | |
| var start_time = context.sending_app_pn_history[pn_index][0]; | |
| var received_time_estimate = now - ack_delay_ms; | |
| var measured_rtt = now - start_time - ack_delay_ms; | |
| var sent_bytes_during = 0; | |
| var sent_packets_during = 0; | |
| for (var i2 = pn_index;i2 < context.sending_app_pn_history.length; i2++) { | |
| var [ts, size] = context.sending_app_pn_history[i2]; | |
| if (received_time_estimate >= ts) { | |
| sent_bytes_during += size; | |
| sent_packets_during++; | |
| } | |
| } | |
| var received_bytes_during = 0; | |
| var received_packets_during = 0; | |
| for (var i2 = 0;i2 < context.receiving_app_pn_history.length; i2++) { | |
| var [pn_recv, ts_recv, size_recv] = context.receiving_app_pn_history[i2]; | |
| if (ts_recv > received_time_estimate) { | |
| break; | |
| } else if (ts_recv >= start_time) { | |
| received_bytes_during += size_recv; | |
| received_packets_during++; | |
| } | |
| } | |
| var last_rtt_record = null; | |
| if (context.rtt_history.length > 0) { | |
| last_rtt_record = context.rtt_history[context.rtt_history.length - 1]; | |
| } | |
| if (last_rtt_record == null || last_rtt_record[0] !== start_time && last_rtt_record[1] !== received_time_estimate) { | |
| context.rtt_history.push([ | |
| start_time, | |
| received_time_estimate, | |
| sent_bytes_during, | |
| sent_packets_during, | |
| received_bytes_during, | |
| received_packets_during, | |
| measured_rtt | |
| ]); | |
| } | |
| } | |
| } | |
| } | |
| for (var pn of context.sending_app_pn_in_flight) { | |
| var is_ack_in_ranges = false; | |
| for (var i2 = 0;i2 < acked_ranges.length; i2 += 2) { | |
| var from = acked_ranges[i2]; | |
| var to = acked_ranges[i2 + 1]; | |
| if (pn >= from && pn <= to) { | |
| is_ack_in_ranges = true; | |
| break; | |
| } | |
| } | |
| if (is_ack_in_ranges == true) { | |
| context.sending_app_pn_in_flight.delete(pn); | |
| for (var stream_id in context.sending_streams) { | |
| if ("in_flight_ranges" in context.sending_streams[stream_id] && pn in context.sending_streams[stream_id].in_flight_ranges == true) { | |
| if (flat_ranges.add(context.sending_streams[stream_id].acked_ranges, context.sending_streams[stream_id].in_flight_ranges[pn]) == true) {} | |
| delete context.sending_streams[stream_id].in_flight_ranges[pn]; | |
| if (context.sending_streams[stream_id].acked_ranges.length == 2 && typeof context.sending_streams[stream_id].total_size == "number" && context.sending_streams[stream_id].total_size > 0 && context.sending_streams[stream_id].acked_ranges[0] == 0 && context.sending_streams[stream_id].acked_ranges[1] == context.sending_streams[stream_id].total_size) { | |
| delete context.sending_streams[stream_id]; | |
| } | |
| } | |
| } | |
| } | |
| } | |
| } | |
| } | |
| function process_decrypted_quic_packet(packet_type, packet_number, data) { | |
| var ack_eliciting = false; | |
| var frames = parse_quic_frames(data); | |
| for (var i in frames) { | |
| if (ack_eliciting == false && (frames[i].type == "stream" || frames[i].type == "crypto" || frames[i].type == "new_connection_id" || frames[i].type == "handshake_done" || frames[i].type == "path_challenge" || frames[i].type == "path_response" || frames[i].type == "ping")) { | |
| ack_eliciting = true; | |
| } | |
| if (frames[i].type == "crypto") { | |
| process_crypto_frame(packet_type, frames[i].offset, frames[i].data); | |
| } else if (frames[i].type == "stream") { | |
| process_stream_frame(packet_type, frames[i].id, frames[i].offset, frames[i].data, frames[i].fin); | |
| } else if (frames[i].type == "reset_stream") {} else if (frames[i].type == "stop_sending") {} else if (frames[i].type == "datagram") { | |
| ev.emit("datagram", frames[i].contextId, frames[i].data); | |
| } else if (frames[i].type == "ack") { | |
| process_ack_frame(packet_type, frames[i]); | |
| } else {} | |
| } | |
| if (ack_eliciting == true) { | |
| var ack_frame_to_send = []; | |
| if (packet_type == "initial") { | |
| ack_frame_to_send.push(build_ack_info_from_ranges(context.receiving_init_pn_ranges, null, 0)); | |
| } else if (packet_type == "handshake") { | |
| ack_frame_to_send.push(build_ack_info_from_ranges(context.receiving_handshake_pn_ranges, null, 0)); | |
| } else if (packet_type == "1rtt") { | |
| flat_ranges.add(context.receiving_app_pn_pending_ack, [packet_number, packet_number]); | |
| prepare_and_send_quic_packet(); | |
| } | |
| if (ack_frame_to_send.length > 0) { | |
| var encoded_frames = encode_quic_frames(ack_frame_to_send); | |
| send_quic_packet_frames(packet_type, encoded_frames); | |
| } | |
| } | |
| } | |
| function process_quic_packet(data) { | |
| if ("version" in data) { | |
| if (context.version !== data.version) { | |
| context.version = data.version; | |
| } | |
| } | |
| if ("dcid" in data && data.dcid && data.dcid.byteLength > 0) { | |
| if (context.original_dcid == null || context.original_dcid.byteLength <= 0 || arraybufferEqual(data.dcid.buffer, context.original_dcid.buffer) == false) { | |
| context.original_dcid = data.dcid; | |
| } | |
| } | |
| if ("scid" in data && data.scid && data.scid.byteLength > 0) { | |
| var is_scid_exist = false; | |
| for (var i in context.their_cids) { | |
| if (arraybufferEqual(data.scid.buffer, context.their_cids[i].buffer) == true) { | |
| is_scid_exist = true; | |
| break; | |
| } | |
| } | |
| if (is_scid_exist == false) { | |
| context.their_cids.push(data.scid); | |
| } | |
| } | |
| var read_key = null; | |
| var read_iv = null; | |
| var read_hp = null; | |
| var largest_pn = -1; | |
| if (data["type"] == "initial") { | |
| if (context.init_read_key !== null && context.init_read_iv !== null && context.init_read_hp !== null) { | |
| read_key = context.init_read_key; | |
| read_iv = context.init_read_iv; | |
| read_hp = context.init_read_hp; | |
| } else { | |
| var d = quic_derive_init_secrets(context.original_dcid, context.version, "read"); | |
| read_key = d.key; | |
| read_iv = d.iv; | |
| read_hp = d.hp; | |
| context.init_read_key = d.key; | |
| context.init_read_iv = d.iv; | |
| context.init_read_hp = d.hp; | |
| } | |
| largest_pn = Number(context.receiving_init_pn_largest) + 0; | |
| } else if (data["type"] == "handshake") { | |
| if (context.tls_session !== null) { | |
| if (context.handshake_read_key !== null && context.handshake_read_iv !== null && context.handshake_read_hp !== null) { | |
| read_key = context.handshake_read_key; | |
| read_iv = context.handshake_read_iv; | |
| read_hp = context.handshake_read_hp; | |
| } else if (context.tls_session.context.client_handshake_traffic_secret !== null) { | |
| var d = quic_derive_from_tls_secrets(context.tls_session.context.client_handshake_traffic_secret, TLS_CIPHER_SUITES2[context.tls_session.context.selected_cipher_suite].hash); | |
| read_key = d.key; | |
| read_iv = d.iv; | |
| read_hp = d.hp; | |
| context.handshake_read_key = d.key; | |
| context.handshake_read_iv = d.iv; | |
| context.handshake_read_hp = d.hp; | |
| } | |
| largest_pn = Number(context.receiving_handshake_pn_largest) + 0; | |
| } else {} | |
| } else if (data["type"] == "1rtt") { | |
| if (context.tls_session !== null) { | |
| if (context.app_read_key !== null && context.app_read_iv !== null && context.app_read_hp !== null) { | |
| read_key = context.app_read_key; | |
| read_iv = context.app_read_iv; | |
| read_hp = context.app_read_hp; | |
| } else if (context.tls_session.context.client_app_traffic_secret !== null) { | |
| var d = quic_derive_from_tls_secrets(context.tls_session.context.client_app_traffic_secret, TLS_CIPHER_SUITES2[context.tls_session.context.selected_cipher_suite].hash); | |
| read_key = d.key; | |
| read_iv = d.iv; | |
| read_hp = d.hp; | |
| context.app_read_key = d.key; | |
| context.app_read_iv = d.iv; | |
| context.app_read_hp = d.hp; | |
| } | |
| largest_pn = Number(context.receiving_app_pn_largest) + 0; | |
| } else {} | |
| } | |
| if (read_key !== null && read_iv !== null) { | |
| var decrypted_packet = decrypt_quic_packet(data["raw"], read_key, read_iv, read_hp, context.original_dcid, largest_pn); | |
| if (decrypted_packet && decrypted_packet.plaintext !== null && decrypted_packet.plaintext.byteLength > 0) { | |
| var is_new_packet = false; | |
| if (data["type"] == "initial") { | |
| is_new_packet = flat_ranges.add(context.receiving_init_pn_ranges, [decrypted_packet.packet_number, decrypted_packet.packet_number]); | |
| if (is_new_packet && context.receiving_init_pn_largest < decrypted_packet.packet_number) { | |
| context.receiving_init_pn_largest = decrypted_packet.packet_number; | |
| } | |
| } else if (data["type"] == "handshake") { | |
| is_new_packet = flat_ranges.add(context.receiving_handshake_pn_ranges, [decrypted_packet.packet_number, decrypted_packet.packet_number]); | |
| if (is_new_packet && context.receiving_handshake_pn_largest < decrypted_packet.packet_number) { | |
| context.receiving_handshake_pn_largest = decrypted_packet.packet_number; | |
| } | |
| } else if (data["type"] == "1rtt") { | |
| is_new_packet = flat_ranges.add(context.receiving_app_pn_ranges, [decrypted_packet.packet_number, decrypted_packet.packet_number]); | |
| if (is_new_packet && context.receiving_app_pn_largest < decrypted_packet.packet_number) { | |
| context.receiving_app_pn_largest = decrypted_packet.packet_number; | |
| } | |
| if (context.handshake_done_sent == false) { | |
| context.handshake_done_sent = true; | |
| send_quic_packet_frames(data["type"], encode_quic_frames([{ | |
| type: "handshake_done" | |
| }])); | |
| } | |
| } | |
| if (is_new_packet == true) { | |
| process_decrypted_quic_packet(data["type"], decrypted_packet.packet_number, decrypted_packet.plaintext); | |
| } | |
| } else {} | |
| } else {} | |
| } | |
| var api = { | |
| on: function(name, fn) { | |
| ev.on(name, fn); | |
| }, | |
| packet: process_quic_packet, | |
| stream: stream_write, | |
| end: function(data) { | |
| if (context.destroyed) | |
| return; | |
| if (typeof data !== "undefined" && data !== null) | |
| api.write(data); | |
| try { | |
| context.transport && context.transport.end && context.transport.end(); | |
| } catch (e) {} | |
| }, | |
| destroy: function() { | |
| if (context.destroyed) | |
| return; | |
| context.destroyed = true; | |
| try { | |
| context.transport && context.transport.destroy && context.transport.destroy(); | |
| } catch (e) {} | |
| } | |
| }; | |
| for (var k in api) | |
| if (Object.prototype.hasOwnProperty.call(api, k)) | |
| this[k] = api[k]; | |
| return this; | |
| } | |
| var quic_socket_default = QUICSocket; | |
| // node_modules/quico/libs/h3.js | |
| var huffman_codes = new Uint32Array([ | |
| 8184, | |
| 8388568, | |
| 268435426, | |
| 268435427, | |
| 268435428, | |
| 268435429, | |
| 268435430, | |
| 268435431, | |
| 268435432, | |
| 16777194, | |
| 1073741820, | |
| 268435433, | |
| 268435434, | |
| 1073741821, | |
| 268435435, | |
| 268435436, | |
| 268435437, | |
| 268435438, | |
| 268435439, | |
| 268435440, | |
| 268435441, | |
| 268435442, | |
| 1073741822, | |
| 268435443, | |
| 268435444, | |
| 268435445, | |
| 268435446, | |
| 268435447, | |
| 268435448, | |
| 268435449, | |
| 268435450, | |
| 268435451, | |
| 20, | |
| 1016, | |
| 1017, | |
| 4090, | |
| 8185, | |
| 21, | |
| 248, | |
| 2042, | |
| 1018, | |
| 1019, | |
| 249, | |
| 2043, | |
| 250, | |
| 22, | |
| 23, | |
| 24, | |
| 0, | |
| 1, | |
| 2, | |
| 25, | |
| 26, | |
| 27, | |
| 28, | |
| 29, | |
| 30, | |
| 31, | |
| 92, | |
| 251, | |
| 32764, | |
| 32, | |
| 4091, | |
| 1020, | |
| 8186, | |
| 33, | |
| 93, | |
| 94, | |
| 95, | |
| 96, | |
| 97, | |
| 98, | |
| 99, | |
| 100, | |
| 101, | |
| 102, | |
| 103, | |
| 104, | |
| 105, | |
| 106, | |
| 107, | |
| 108, | |
| 109, | |
| 110, | |
| 111, | |
| 112, | |
| 113, | |
| 114, | |
| 252, | |
| 115, | |
| 253, | |
| 8187, | |
| 524272, | |
| 8188, | |
| 16380, | |
| 34, | |
| 32765, | |
| 3, | |
| 35, | |
| 4, | |
| 36, | |
| 5, | |
| 37, | |
| 38, | |
| 39, | |
| 6, | |
| 116, | |
| 117, | |
| 40, | |
| 41, | |
| 42, | |
| 7, | |
| 43, | |
| 118, | |
| 44, | |
| 8, | |
| 9, | |
| 45, | |
| 119, | |
| 120, | |
| 121, | |
| 122, | |
| 123, | |
| 32766, | |
| 2044, | |
| 16381, | |
| 8189, | |
| 268435452, | |
| 1048550, | |
| 4194258, | |
| 1048551, | |
| 1048552, | |
| 4194259, | |
| 4194260, | |
| 4194261, | |
| 8388569, | |
| 4194262, | |
| 8388570, | |
| 8388571, | |
| 8388572, | |
| 8388573, | |
| 8388574, | |
| 16777195, | |
| 8388575, | |
| 16777196, | |
| 16777197, | |
| 4194263, | |
| 8388576, | |
| 16777198, | |
| 8388577, | |
| 8388578, | |
| 8388579, | |
| 8388580, | |
| 2097116, | |
| 4194264, | |
| 8388581, | |
| 4194265, | |
| 8388582, | |
| 8388583, | |
| 16777199, | |
| 4194266, | |
| 2097117, | |
| 1048553, | |
| 4194267, | |
| 4194268, | |
| 8388584, | |
| 8388585, | |
| 2097118, | |
| 8388586, | |
| 4194269, | |
| 4194270, | |
| 16777200, | |
| 2097119, | |
| 4194271, | |
| 8388587, | |
| 8388588, | |
| 2097120, | |
| 2097121, | |
| 4194272, | |
| 2097122, | |
| 8388589, | |
| 4194273, | |
| 8388590, | |
| 8388591, | |
| 1048554, | |
| 4194274, | |
| 4194275, | |
| 4194276, | |
| 8388592, | |
| 4194277, | |
| 4194278, | |
| 8388593, | |
| 67108832, | |
| 67108833, | |
| 1048555, | |
| 524273, | |
| 4194279, | |
| 8388594, | |
| 4194280, | |
| 33554412, | |
| 67108834, | |
| 67108835, | |
| 67108836, | |
| 134217694, | |
| 134217695, | |
| 67108837, | |
| 16777201, | |
| 33554413, | |
| 524274, | |
| 2097123, | |
| 67108838, | |
| 134217696, | |
| 134217697, | |
| 67108839, | |
| 134217698, | |
| 16777202, | |
| 2097124, | |
| 2097125, | |
| 67108840, | |
| 67108841, | |
| 268435453, | |
| 134217699, | |
| 134217700, | |
| 134217701, | |
| 1048556, | |
| 16777203, | |
| 1048557, | |
| 2097126, | |
| 4194281, | |
| 2097127, | |
| 2097128, | |
| 8388595, | |
| 4194282, | |
| 4194283, | |
| 33554414, | |
| 33554415, | |
| 16777204, | |
| 16777205, | |
| 67108842, | |
| 8388596, | |
| 67108843, | |
| 134217702, | |
| 67108844, | |
| 67108845, | |
| 134217703, | |
| 134217704, | |
| 134217705, | |
| 134217706, | |
| 134217707, | |
| 268435454, | |
| 134217708, | |
| 134217709, | |
| 134217710, | |
| 134217711, | |
| 134217712, | |
| 67108846, | |
| 1073741823 | |
| ]); | |
| var huffman_bits = new Uint8Array([13, 23, 28, 28, 28, 28, 28, 28, 28, 24, 30, 28, 28, 30, 28, 28, 28, 28, 28, 28, 28, 28, 30, 28, 28, 28, 28, 28, 28, 28, 28, 28, 6, 10, 10, 12, 13, 6, 8, 11, 10, 10, 8, 11, 8, 6, 6, 6, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 7, 8, 15, 6, 12, 10, 13, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 7, 8, 13, 19, 13, 14, 6, 15, 5, 6, 5, 6, 5, 6, 6, 6, 5, 7, 7, 6, 6, 6, 5, 6, 7, 6, 5, 5, 6, 7, 7, 7, 7, 7, 15, 11, 14, 13, 28, 20, 22, 20, 20, 22, 22, 22, 23, 22, 23, 23, 23, 23, 23, 24, 23, 24, 24, 22, 23, 24, 23, 23, 23, 23, 21, 22, 23, 22, 23, 23, 24, 22, 21, 20, 22, 22, 23, 23, 21, 23, 22, 22, 24, 21, 22, 23, 23, 21, 21, 22, 21, 23, 22, 23, 23, 20, 22, 22, 22, 23, 22, 22, 23, 26, 26, 20, 19, 22, 23, 22, 25, 26, 26, 26, 27, 27, 26, 24, 25, 19, 21, 26, 27, 27, 26, 27, 24, 21, 21, 26, 26, 28, 27, 27, 27, 20, 24, 20, 21, 22, 21, 21, 23, 22, 22, 25, 25, 24, 24, 26, 23, 26, 27, 26, 26, 27, 27, 27, 27, 27, 28, 27, 27, 27, 27, 27, 26, 30]); | |
| function buildHuffmanDecodeTrie() { | |
| var root = {}; | |
| for (var i = 0;i < huffman_codes.length; i++) { | |
| var code = huffman_codes[i]; | |
| var length = huffman_bits[i]; | |
| var node = root; | |
| for (var j = length - 1;j >= 0; j--) { | |
| var bit = code >> j & 1; | |
| if (!node[bit]) | |
| node[bit] = {}; | |
| node = node[bit]; | |
| } | |
| node.symbol = i; | |
| } | |
| return root; | |
| } | |
| var huffman_flat_decode_tables = buildHuffmanDecodeTrie(); | |
| var qpack_static_table_entries = [ | |
| [":authority", ""], | |
| [":path", "/"], | |
| ["age", "0"], | |
| ["content-disposition", ""], | |
| ["content-length", "0"], | |
| ["cookie", ""], | |
| ["date", ""], | |
| ["etag", ""], | |
| ["if-modified-since", ""], | |
| ["if-none-match", ""], | |
| ["last-modified", ""], | |
| ["link", ""], | |
| ["location", ""], | |
| ["referer", ""], | |
| ["set-cookie", ""], | |
| [":method", "CONNECT"], | |
| [":method", "DELETE"], | |
| [":method", "GET"], | |
| [":method", "HEAD"], | |
| [":method", "OPTIONS"], | |
| [":method", "POST"], | |
| [":method", "PUT"], | |
| [":scheme", "http"], | |
| [":scheme", "https"], | |
| [":status", "103"], | |
| [":status", "200"], | |
| [":status", "304"], | |
| [":status", "404"], | |
| [":status", "503"], | |
| ["accept", "*/*"], | |
| ["accept", "application/dns-message"], | |
| ["accept-encoding", "gzip, deflate, br"], | |
| ["accept-ranges", "bytes"], | |
| ["access-control-allow-headers", "cache-control"], | |
| ["access-control-allow-headers", "content-type"], | |
| ["access-control-allow-origin", "*"], | |
| ["cache-control", "max-age=0"], | |
| ["cache-control", "max-age=2592000"], | |
| ["cache-control", "max-age=604800"], | |
| ["cache-control", "no-cache"], | |
| ["cache-control", "no-store"], | |
| ["cache-control", "public, max-age=31536000"], | |
| ["content-encoding", "br"], | |
| ["content-encoding", "gzip"], | |
| ["content-type", "application/dns-message"], | |
| ["content-type", "application/javascript"], | |
| ["content-type", "application/json"], | |
| ["content-type", "application/x-www-form-urlencoded"], | |
| ["content-type", "image/gif"], | |
| ["content-type", "image/jpeg"], | |
| ["content-type", "image/png"], | |
| ["content-type", "text/css"], | |
| ["content-type", "text/html; charset=utf-8"], | |
| ["content-type", "text/plain"], | |
| ["content-type", "text/plain;charset=utf-8"], | |
| ["range", "bytes=0-"], | |
| ["strict-transport-security", "max-age=31536000"], | |
| ["strict-transport-security", "max-age=31536000; includesubdomains"], | |
| ["strict-transport-security", "max-age=31536000; includesubdomains; preload"], | |
| ["vary", "accept-encoding"], | |
| ["vary", "origin"], | |
| ["x-content-type-options", "nosniff"], | |
| ["x-xss-protection", "1; mode=block"], | |
| [":status", "100"], | |
| [":status", "204"], | |
| [":status", "206"], | |
| [":status", "302"], | |
| [":status", "400"], | |
| [":status", "403"], | |
| [":status", "421"], | |
| [":status", "425"], | |
| [":status", "500"], | |
| ["accept-language", ""], | |
| ["access-control-allow-credentials", "FALSE"], | |
| ["access-control-allow-credentials", "TRUE"], | |
| ["access-control-allow-headers", "*"], | |
| ["access-control-allow-methods", "get"], | |
| ["access-control-allow-methods", "get, post, options"], | |
| ["access-control-allow-methods", "options"], | |
| ["access-control-expose-headers", "content-length"], | |
| ["access-control-request-headers", "content-type"], | |
| ["access-control-request-method", "get"], | |
| ["access-control-request-method", "post"], | |
| ["alt-svc", "clear"], | |
| ["authorization", ""], | |
| ["content-security-policy", "script-src 'none'; object-src 'none'; base-uri 'none'"], | |
| ["early-data", "1"], | |
| ["expect-ct", ""], | |
| ["forwarded", ""], | |
| ["if-range", ""], | |
| ["origin", ""], | |
| ["purpose", "prefetch"], | |
| ["server", ""], | |
| ["timing-allow-origin", "*"], | |
| ["upgrade-insecure-requests", "1"], | |
| ["user-agent", ""], | |
| ["x-forwarded-for", ""], | |
| ["x-frame-options", "deny"], | |
| ["x-frame-options", "sameorigin"] | |
| ]; | |
| function decodeVarInt(buf, prefixBits, pos) { | |
| var maxPrefix = (1 << prefixBits) - 1; | |
| var byte = buf[pos]; | |
| var value = byte & maxPrefix; | |
| pos++; | |
| if (value < maxPrefix) | |
| return { value, next: pos }; | |
| var m = 0; | |
| while (true) { | |
| byte = buf[pos++]; | |
| value += (byte & 127) << m; | |
| if ((byte & 128) === 0) | |
| break; | |
| m += 7; | |
| } | |
| return { value, next: pos }; | |
| } | |
| function decodeHuffman(buf) { | |
| var output = []; | |
| var node = huffman_flat_decode_tables; | |
| var current = 0; | |
| var nbits = 0; | |
| for (var i = 0;i < buf.length; i++) { | |
| current = current << 8 | buf[i]; | |
| nbits += 8; | |
| while (nbits > 0) { | |
| var bit = current >> nbits - 1 & 1; | |
| node = node[bit]; | |
| if (!node) | |
| throw new Error("Invalid Huffman encoding"); | |
| nbits--; | |
| if (node.symbol !== undefined) { | |
| output.push(node.symbol); | |
| node = huffman_flat_decode_tables; | |
| } | |
| } | |
| } | |
| var padding = (1 << nbits) - 1; | |
| if ((current & padding) !== padding) { | |
| throw new Error("Invalid Huffman padding"); | |
| } | |
| return new TextDecoder().decode(Uint8Array.from(output)); | |
| } | |
| function parse_qpack_header_block(buf) { | |
| var pos = 0; | |
| var headers = []; | |
| var ric = decodeVarInt(buf, 8, pos); | |
| pos = ric.next; | |
| var firstDbByte = buf[pos]; | |
| var postBase = (firstDbByte & 128) !== 0; | |
| var db = decodeVarInt(buf, 7, pos); | |
| pos = db.next; | |
| var baseIndex = postBase ? ric.value + db.value : ric.value - db.value; | |
| while (pos < buf.length) { | |
| var byte = buf[pos]; | |
| if ((byte & 128) === 128) { | |
| var fromStatic = (byte & 64) !== 0; | |
| var idx = decodeVarInt(buf, 6, pos); | |
| pos = idx.next; | |
| headers.push({ | |
| type: "indexed", | |
| from_static_table: fromStatic, | |
| index: idx.value | |
| }); | |
| continue; | |
| } | |
| if ((byte & 192) === 64) { | |
| var neverIndexed = (byte & 32) !== 0; | |
| var fromStatic = (byte & 16) !== 0; | |
| var nameIdx = decodeVarInt(buf, 4, pos); | |
| pos = nameIdx.next; | |
| var valH = (buf[pos] & 128) !== 0; | |
| var valLen = decodeVarInt(buf, 7, pos); | |
| pos = valLen.next; | |
| var valBytes = buf.slice(pos, pos + valLen.value); | |
| pos += valLen.value; | |
| var value = valH ? decodeHuffman(valBytes) : new TextDecoder().decode(valBytes); | |
| headers.push({ | |
| type: "literal_with_name_ref", | |
| never_indexed: neverIndexed, | |
| from_static_table: fromStatic, | |
| name_index: nameIdx.value, | |
| value | |
| }); | |
| continue; | |
| } | |
| if ((byte & 224) === 32) { | |
| var neverIndexed = (byte & 16) !== 0; | |
| var nameH = (byte & 8) !== 0; | |
| var nameLen = decodeVarInt(buf, 3, pos); | |
| pos = nameLen.next; | |
| var nameBytes = buf.slice(pos, pos + nameLen.value); | |
| pos += nameLen.value; | |
| var name = nameH ? decodeHuffman(nameBytes) : new TextDecoder().decode(nameBytes); | |
| var valH = (buf[pos] & 128) !== 0; | |
| var valLen = decodeVarInt(buf, 7, pos); | |
| pos = valLen.next; | |
| var valBytes = buf.slice(pos, pos + valLen.value); | |
| pos += valLen.value; | |
| var value = valH ? decodeHuffman(valBytes) : new TextDecoder().decode(valBytes); | |
| headers.push({ | |
| type: "literal_with_literal_name", | |
| never_indexed: neverIndexed, | |
| name, | |
| value | |
| }); | |
| continue; | |
| } | |
| throw new Error(`Unknown header-block instruction at byte ${pos} (0x${byte.toString(16)})`); | |
| } | |
| return { | |
| insert_count: ric.value, | |
| delta_base: db.value, | |
| post_base: postBase, | |
| base_index: baseIndex, | |
| headers | |
| }; | |
| } | |
| function extract_h3_frames_from_chunks(chunks, from_offset) { | |
| if (!chunks || chunks.length === 0) { | |
| return { frames: [], new_from_offset: from_offset }; | |
| } | |
| var buffers = []; | |
| var acc = 0; | |
| for (var i = 0;i < chunks.length; i++) { | |
| var c = chunks[i]; | |
| var nextAcc = acc + c.length; | |
| if (from_offset < nextAcc) { | |
| var start = from_offset - acc; | |
| buffers.push(c.slice(start)); | |
| for (var j = i + 1;j < chunks.length; j++) { | |
| buffers.push(chunks[j]); | |
| } | |
| break; | |
| } | |
| acc = nextAcc; | |
| } | |
| if (buffers.length === 0) { | |
| return { frames: [], new_from_offset: from_offset }; | |
| } | |
| var combined = concatUint8Arrays(buffers); | |
| var offset = 0; | |
| var frames = []; | |
| function safeReadVarInt() { | |
| if (offset >= combined.length) | |
| return null; | |
| var firstByte = combined[offset]; | |
| var lengthBits = firstByte >> 6; | |
| var neededLength = 1 << lengthBits; | |
| if (offset + neededLength > combined.length) | |
| return null; | |
| var res = readVarInt(combined, offset); | |
| if (!res || typeof res.byteLength !== "number") | |
| return null; | |
| offset += res.byteLength; | |
| return res; | |
| } | |
| while (offset < combined.length) { | |
| var startOffset = offset; | |
| var frameType = safeReadVarInt(); | |
| if (!frameType) | |
| break; | |
| var lengthInfo = safeReadVarInt(); | |
| if (!lengthInfo) { | |
| offset = startOffset; | |
| break; | |
| } | |
| var payloadLength = lengthInfo.value >>> 0; | |
| if (offset + payloadLength > combined.length) { | |
| offset = startOffset; | |
| break; | |
| } | |
| var payload = combined.slice(offset, offset + payloadLength); | |
| frames.push({ frame_type: frameType.value, payload }); | |
| offset += payloadLength; | |
| } | |
| return { frames, new_from_offset: from_offset + offset }; | |
| } | |
| function build_h3_frames(frames) { | |
| var parts = []; | |
| for (var i = 0;i < frames.length; i++) { | |
| var frame = frames[i]; | |
| var typeBytes = writeVarInt(frame.frame_type); | |
| var lenBytes = writeVarInt(frame.payload.length); | |
| var payload = frame.payload; | |
| parts.push(typeBytes, lenBytes, payload); | |
| } | |
| return concatUint8Arrays(parts); | |
| } | |
| function computeVarIntLen(buf, pos, prefixBits) { | |
| if (pos >= buf.length) | |
| return null; | |
| var first = buf[pos]; | |
| var prefixMask = (1 << prefixBits) - 1; | |
| var prefixVal = first & prefixMask; | |
| if (prefixVal < prefixMask) | |
| return 1; | |
| var len = 1; | |
| var idx = pos + 1; | |
| while (idx < buf.length) { | |
| len++; | |
| if ((buf[idx] & 128) === 0) | |
| return len; | |
| idx++; | |
| } | |
| return null; | |
| } | |
| function safeDecodeVarInt(buf, posRef, prefixBits) { | |
| var len = computeVarIntLen(buf, posRef.pos, prefixBits); | |
| if (len === null) | |
| return null; | |
| var res = decodeVarInt(buf, prefixBits, posRef.pos); | |
| posRef.pos = res.next; | |
| return res.value; | |
| } | |
| function extract_qpack_encoder_instructions_from_chunks(chunks, from_offset) { | |
| if (!chunks || chunks.length === 0) { | |
| return { instructions: [], new_from_offset: from_offset }; | |
| } | |
| var buffers = []; | |
| var acc = 0; | |
| for (var i = 0;i < chunks.length; i++) { | |
| var c = chunks[i]; | |
| var nextAcc = acc + c.length; | |
| if (from_offset < nextAcc) { | |
| var start = from_offset - acc; | |
| buffers.push(c.slice(start)); | |
| for (var j = i + 1;j < chunks.length; j++) { | |
| buffers.push(chunks[j]); | |
| } | |
| break; | |
| } | |
| acc = nextAcc; | |
| } | |
| if (buffers.length === 0) { | |
| return { instructions: [], new_from_offset: from_offset }; | |
| } | |
| var combined = concatUint8Arrays(buffers); | |
| var posRef = { pos: 0 }; | |
| var instructions = []; | |
| while (posRef.pos < combined.length) { | |
| var startPos = posRef.pos; | |
| if (posRef.pos >= combined.length) | |
| break; | |
| var byte = combined[posRef.pos]; | |
| if ((byte & 128) === 128) { | |
| var fromStatic = (byte & 64) !== 0; | |
| var nameIdx = safeDecodeVarInt(combined, posRef, 6); | |
| if (nameIdx === null) | |
| break; | |
| if (posRef.pos >= combined.length) { | |
| posRef.pos = startPos; | |
| break; | |
| } | |
| var valHuffman = (combined[posRef.pos] & 128) !== 0; | |
| var valLen = safeDecodeVarInt(combined, posRef, 7); | |
| if (valLen === null || posRef.pos + valLen > combined.length) { | |
| posRef.pos = startPos; | |
| break; | |
| } | |
| var valBytes = combined.slice(posRef.pos, posRef.pos + valLen); | |
| posRef.pos += valLen; | |
| var value = valHuffman ? decodeHuffman(valBytes) : new TextDecoder().decode(valBytes); | |
| instructions.push({ | |
| type: "insert_with_name_ref", | |
| from_static_table: fromStatic, | |
| name_index: nameIdx, | |
| value | |
| }); | |
| continue; | |
| } | |
| if ((byte & 192) === 64) { | |
| var nameH = (byte & 32) !== 0; | |
| var nameLen = safeDecodeVarInt(combined, posRef, 5); | |
| if (nameLen === null || posRef.pos + nameLen > combined.length) { | |
| posRef.pos = startPos; | |
| break; | |
| } | |
| var nameBytes = combined.slice(posRef.pos, posRef.pos + nameLen); | |
| posRef.pos += nameLen; | |
| if (posRef.pos >= combined.length) { | |
| posRef.pos = startPos; | |
| break; | |
| } | |
| var valH = (combined[posRef.pos] & 128) !== 0; | |
| var valLen2 = safeDecodeVarInt(combined, posRef, 7); | |
| if (valLen2 === null || posRef.pos + valLen2 > combined.length) { | |
| posRef.pos = startPos; | |
| break; | |
| } | |
| var valBytes2 = combined.slice(posRef.pos, posRef.pos + valLen2); | |
| posRef.pos += valLen2; | |
| var nameStr = nameH ? decodeHuffman(nameBytes) : new TextDecoder().decode(nameBytes); | |
| var valueStr = valH ? decodeHuffman(valBytes2) : new TextDecoder().decode(valBytes2); | |
| instructions.push({ | |
| type: "insert_without_name_ref", | |
| name: nameStr, | |
| value: valueStr | |
| }); | |
| continue; | |
| } | |
| if ((byte & 224) === 32) { | |
| var capacity = safeDecodeVarInt(combined, posRef, 5); | |
| if (capacity === null) { | |
| posRef.pos = startPos; | |
| break; | |
| } | |
| instructions.push({ | |
| type: "set_dynamic_table_capacity", | |
| capacity | |
| }); | |
| continue; | |
| } | |
| if ((byte & 240) === 0) { | |
| var dupIndex = safeDecodeVarInt(combined, posRef, 4); | |
| if (dupIndex === null) { | |
| posRef.pos = startPos; | |
| break; | |
| } | |
| instructions.push({ | |
| type: "duplicate", | |
| index: dupIndex | |
| }); | |
| continue; | |
| } | |
| break; | |
| } | |
| var consumed = posRef.pos | 0; | |
| return { instructions, new_from_offset: from_offset + consumed }; | |
| } | |
| var h3_settings_frame_params = [ | |
| [1, "SETTINGS_QPACK_MAX_TABLE_CAPACITY"], | |
| [6, "SETTINGS_MAX_FIELD_SECTION_SIZE"], | |
| [7, "SETTINGS_QPACK_BLOCKED_STREAMS"], | |
| [8, "SETTINGS_ENABLE_CONNECT_PROTOCOL"], | |
| [51, "SETTINGS_H3_DATAGRAM"], | |
| [727725890, "SETTINGS_ENABLE_WEBTRANSPORT"], | |
| [13, "SETTINGS_NO_RFC9114_LEGACY_CODEPOINT"], | |
| [350866729, "SETTINGS_WT_MAX_SESSIONS"], | |
| [19780, "SETTINGS_ENABLE_METADATA"] | |
| ]; | |
| var h3_name_to_id = {}; | |
| var h3_id_to_name = {}; | |
| for (i = 0;i < h3_settings_frame_params.length; i++) { | |
| [id, name] = h3_settings_frame_params[i]; | |
| h3_name_to_id[name] = id; | |
| h3_id_to_name[id] = name; | |
| } | |
| var id; | |
| var name; | |
| var i; | |
| function parse_h3_settings_frame(buf) { | |
| var settings = {}; | |
| var offset = 0; | |
| while (offset < buf.length) { | |
| var idRes = readVarInt(buf, offset); | |
| if (!idRes) | |
| break; | |
| offset += idRes.byteLength; | |
| var valRes = readVarInt(buf, offset); | |
| if (!valRes) | |
| break; | |
| offset += valRes.byteLength; | |
| var id2 = idRes.value; | |
| var value = valRes.value; | |
| var name2 = h3_id_to_name[id2] || `UNKNOWN_0x${id2.toString(16)}`; | |
| settings[name2] = value; | |
| } | |
| return settings; | |
| } | |
| function build_settings_frame(settings_named) { | |
| var frame_payload = []; | |
| for (var name2 in settings_named) { | |
| var id2 = h3_name_to_id[name2]; | |
| if (id2 === undefined) { | |
| throw new Error("Unknown setting name: " + name2); | |
| } | |
| var value = settings_named[name2]; | |
| frame_payload.push(...writeVarInt(id2)); | |
| frame_payload.push(...writeVarInt(value)); | |
| } | |
| return new Uint8Array(frame_payload); | |
| } | |
| function encodeInt(value, prefixBits) { | |
| var max = (1 << prefixBits) - 1; | |
| if (value < max) | |
| return [value]; | |
| var bytes = [max]; | |
| value -= max; | |
| while (value >= 128) { | |
| bytes.push(value & 127 | 128); | |
| value >>= 7; | |
| } | |
| bytes.push(value); | |
| return bytes; | |
| } | |
| function encodeStringLiteral(bytes, hFlag) { | |
| var lenBytes = encodeInt(bytes.length, 7); | |
| lenBytes[0] |= hFlag << 7; | |
| return lenBytes.concat(Array.from(bytes)); | |
| } | |
| function build_http3_literal_headers_frame(headers) { | |
| var out = []; | |
| out.push(0, 0); | |
| for (var header_name in headers) { | |
| var nameBytes = new TextEncoder().encode(header_name.toLowerCase()); | |
| var valueBytes = new TextEncoder().encode(String(headers[header_name])); | |
| var nameLenEnc = encodeInt(nameBytes.length, 3); | |
| var firstByte = 32 | nameLenEnc[0]; | |
| out.push(firstByte, ...nameLenEnc.slice(1), ...nameBytes); | |
| out.push(...encodeStringLiteral(valueBytes, 0)); | |
| } | |
| return new Uint8Array(out); | |
| } | |
| // node_modules/quico/h3_socket.js | |
| function Emitter4() { | |
| var listeners = {}; | |
| return { | |
| on: function(name2, fn) { | |
| (listeners[name2] = listeners[name2] || []).push(fn); | |
| }, | |
| emit: function(name2) { | |
| var args = Array.prototype.slice.call(arguments, 1); | |
| var arr = listeners[name2] || []; | |
| for (var i2 = 0;i2 < arr.length; i2++) { | |
| try { | |
| arr[i2].apply(null, args); | |
| } catch (e) {} | |
| } | |
| } | |
| }; | |
| } | |
| function H3Socket(options) { | |
| if (!(this instanceof H3Socket)) | |
| return new H3Socket(options); | |
| options = options || {}; | |
| var ev = Emitter4(); | |
| var context = { | |
| isServer: true, | |
| local_max_header_size: 65536, | |
| local_qpack_max_table_capacity: 65536, | |
| local_datagram_support: true, | |
| remote_max_header_size: 0, | |
| remote_qpack_max_table_capacity: 0, | |
| remote_datagram_support: null, | |
| remote_qpack_table_base_index: 0, | |
| remote_qpack_table_capacity: 0, | |
| remote_qpack_dynamic_table: [], | |
| receiving_streams: {} | |
| }; | |
| function process_qpack_instructions(instructions) { | |
| var arr_inserts = []; | |
| for (var i2 in instructions) { | |
| if (instructions[i2].type == "set_dynamic_table_capacity") { | |
| context.remote_qpack_table_capacity = instructions[i2].capacity; | |
| } else if (instructions[i2].type == "insert_with_name_ref" || instructions[i2].type == "insert_without_name_ref") { | |
| var name2 = null; | |
| var value = instructions[i2].value; | |
| if (instructions[i2].type == "insert_with_name_ref") { | |
| if (instructions[i2].from_static_table == true) { | |
| if (instructions[i2].name_index < qpack_static_table_entries.length) { | |
| name2 = qpack_static_table_entries[instructions[i2].name_index][0]; | |
| } else {} | |
| } else { | |
| var base_index = context.remote_qpack_table_base_index; | |
| var name_index = instructions[i2].name_index; | |
| var dynamic_index = base_index - 1 - name_index; | |
| var dynamic_table = context.remote_qpack_dynamic_table; | |
| if (dynamic_index >= 0 && dynamic_index < dynamic_table.length) { | |
| name2 = dynamic_table[dynamic_index][0]; | |
| } else {} | |
| } | |
| } else { | |
| name2 = instructions[i2].name; | |
| } | |
| if (name2 !== null) { | |
| arr_inserts.push([name2, value]); | |
| } | |
| } | |
| } | |
| if (arr_inserts.length > 0) { | |
| for (var i2 in arr_inserts) { | |
| insert_into_qpack_remote_encoder_dynamic_table(arr_inserts[i2][0], arr_inserts[i2][1]); | |
| } | |
| } | |
| } | |
| function http_header_write(stream_id, headers) { | |
| var headers_payload = build_http3_literal_headers_frame(headers); | |
| var http3_response = build_h3_frames([ | |
| { frame_type: 1, payload: headers_payload } | |
| ]); | |
| ev.emit("stream", stream_id, http3_response); | |
| } | |
| function http_body_write(stream_id, payload, fin) { | |
| if (payload == null) { | |
| ev.emit("stream", stream_id, null, true); | |
| } else { | |
| var http3_response = build_h3_frames([ | |
| { frame_type: 0, payload } | |
| ]); | |
| ev.emit("stream", stream_id, http3_response, fin); | |
| } | |
| } | |
| function process_http_frame(stream_id, frame_type, payload) { | |
| if (frame_type == 1) { | |
| var headers = {}; | |
| var dynamic_table = context.remote_qpack_dynamic_table; | |
| var header_block = parse_qpack_header_block(payload); | |
| if (header_block.insert_count <= dynamic_table.length) { | |
| var used_dynamic_ref = false; | |
| for (var i2 in header_block.headers) { | |
| if (header_block.headers[i2].type == "indexed") { | |
| if (header_block.headers[i2].from_static_table == true) { | |
| if (header_block.headers[i2].index < qpack_static_table_entries.length) { | |
| headers[qpack_static_table_entries[header_block.headers[i2].index][0]] = qpack_static_table_entries[header_block.headers[i2].index][1]; | |
| } else {} | |
| } else { | |
| used_dynamic_ref = true; | |
| var dynamic_index = header_block.base_index - 1 - header_block.headers[i2].index; | |
| if (dynamic_index >= 0 && dynamic_index < dynamic_table.length) { | |
| var [name2, value] = dynamic_table[dynamic_index]; | |
| headers[name2] = value; | |
| } | |
| } | |
| } else if (header_block.headers[i2].type == "literal_with_name_ref") { | |
| if (header_block.headers[i2].from_static_table == true) { | |
| if (header_block.headers[i2].name_index < qpack_static_table_entries.length) { | |
| headers[qpack_static_table_entries[header_block.headers[i2].name_index][0]] = header_block.headers[i2].value; | |
| } | |
| } else { | |
| used_dynamic_ref = true; | |
| var dynamic_index = header_block.base_index - 1 - header_block.headers[i2].name_index; | |
| if (dynamic_index >= 0 && dynamic_index < dynamic_table.length) { | |
| var [name2] = dynamic_table[dynamic_index]; | |
| headers[name2] = header_block.headers[i2].value; | |
| } | |
| } | |
| } else if (header_block.headers[i2].type == "literal_with_literal_name") { | |
| headers[header_block.headers[i2].name] = header_block.headers[i2].value; | |
| } | |
| } | |
| if (used_dynamic_ref == true) {} | |
| } | |
| ev.emit("http_headers", Number(stream_id), headers); | |
| } else if (frame_type == 0) { | |
| ev.emit("http_body", Number(stream_id), payload); | |
| } | |
| } | |
| function evict_qpack_remote_dynamic_table_if_needed() { | |
| var entries = context.remote_qpack_dynamic_table; | |
| var capacity = context.remote_qpack_table_capacity; | |
| var totalSize = 0; | |
| for (var i2 = 0;i2 < entries.length; i2++) { | |
| var name2 = entries[i2][0]; | |
| var value = entries[i2][1]; | |
| totalSize += name2.length + value.length + 32; | |
| } | |
| while (totalSize > capacity && entries.length > 0) { | |
| var removed = entries.pop(); | |
| var removedSize = removed[0].length + removed[1].length + 32; | |
| totalSize -= removedSize; | |
| } | |
| } | |
| function insert_into_qpack_remote_encoder_dynamic_table(name2, value) { | |
| var entry_size = name2.length + value.length + 32; | |
| if (entry_size > context.remote_qpack_table_capacity) | |
| return false; | |
| context.remote_qpack_dynamic_table.unshift([name2, value]); | |
| context.remote_qpack_table_base_index++; | |
| evict_qpack_remote_dynamic_table_if_needed(); | |
| return true; | |
| } | |
| function process_settings_frame(payload) { | |
| var control_settings = parse_h3_settings_frame(payload); | |
| if ("SETTINGS_QPACK_MAX_TABLE_CAPACITY" in control_settings && control_settings["SETTINGS_QPACK_MAX_TABLE_CAPACITY"] > 0) { | |
| context.remote_qpack_max_table_capacity = control_settings["SETTINGS_QPACK_MAX_TABLE_CAPACITY"]; | |
| evict_qpack_remote_dynamic_table_if_needed(); | |
| } | |
| if ("SETTINGS_MAX_FIELD_SECTION_SIZE" in control_settings && control_settings["SETTINGS_MAX_FIELD_SECTION_SIZE"] > 0) { | |
| context.remote_max_header_size = control_settings["SETTINGS_MAX_FIELD_SECTION_SIZE"]; | |
| } | |
| if ("SETTINGS_H3_DATAGRAM" in control_settings && control_settings["SETTINGS_H3_DATAGRAM"] > 0) { | |
| context.remote_datagram_support = Boolean(control_settings["SETTINGS_H3_DATAGRAM"]); | |
| } | |
| } | |
| function stream_write(stream_id, data, fin) { | |
| console.log("stream_write2", new TextDecoder().decode(data), fin); | |
| if (stream_id in context.receiving_streams == false) { | |
| context.receiving_streams[stream_id] = { | |
| data_chunks: [], | |
| next_offset: 0, | |
| total_size: 0, | |
| from_offset: 0, | |
| type: null | |
| }; | |
| } | |
| context.receiving_streams[stream_id].data_chunks.push(data); | |
| context.receiving_streams[stream_id].next_offset = context.receiving_streams[stream_id].next_offset + data.byteLength; | |
| if (context.receiving_streams[stream_id].total_size == 0) { | |
| if (typeof fin == "boolean" && fin == true) { | |
| context.receiving_streams[stream_id].total_size = context.receiving_streams[stream_id].next_offset; | |
| } | |
| } | |
| if (context.receiving_streams[stream_id].type == null) { | |
| var is_unidirectional = (Number(stream_id) & 2) !== 0; | |
| if (is_unidirectional) { | |
| if (context.receiving_streams[stream_id].data_chunks.length > 0 && context.receiving_streams[stream_id].data_chunks[0].byteLength > 0) { | |
| var first_byte = context.receiving_streams[stream_id].data_chunks[0][0]; | |
| if (first_byte == 0) { | |
| context.receiving_streams[stream_id].type = 0; | |
| context.receiving_streams[stream_id].from_offset = 1; | |
| } else if (first_byte == 1) {} else if (first_byte == 2) { | |
| context.receiving_streams[stream_id].type = 2; | |
| context.receiving_streams[stream_id].from_offset = 1; | |
| } else if (first_byte == 3) { | |
| context.receiving_streams[stream_id].type = 3; | |
| context.receiving_streams[stream_id].from_offset = 1; | |
| } else {} | |
| } | |
| } else { | |
| context.receiving_streams[stream_id].type = 4; | |
| context.receiving_streams[stream_id].from_offset = 0; | |
| } | |
| } | |
| var ext = null; | |
| if (context.receiving_streams[stream_id].type == 2 || context.receiving_streams[stream_id].type == 3) { | |
| ext = extract_qpack_encoder_instructions_from_chunks(context.receiving_streams[stream_id].data_chunks, context.receiving_streams[stream_id].from_offset); | |
| } else { | |
| ext = extract_h3_frames_from_chunks(context.receiving_streams[stream_id].data_chunks, context.receiving_streams[stream_id].from_offset); | |
| } | |
| if (ext && context.receiving_streams[stream_id].from_offset !== ext.new_from_offset) { | |
| context.receiving_streams[stream_id].from_offset = ext.new_from_offset; | |
| if (context.receiving_streams[stream_id].type == 0) { | |
| for (var i2 in ext.frames) { | |
| if (ext.frames[i2].frame_type == 4) { | |
| process_settings_frame(ext.frames[i2].payload); | |
| } else if (ext.frames[i2].frame_type == 7) {} | |
| } | |
| } else if (context.receiving_streams[stream_id].type == 2) { | |
| process_qpack_instructions(ext.instructions); | |
| } else if (context.receiving_streams[stream_id].type == 3) {} else if (context.receiving_streams[stream_id].type == 4) { | |
| for (var i2 in ext.frames) { | |
| process_http_frame(Number(stream_id), ext.frames[i2].frame_type, ext.frames[i2].payload); | |
| } | |
| } | |
| } | |
| } | |
| function connect() { | |
| if (context.local_max_header_size > 0) {} | |
| var settings_frame = build_settings_frame({ | |
| SETTINGS_QPACK_MAX_TABLE_CAPACITY: context.local_qpack_max_table_capacity, | |
| SETTINGS_MAX_FIELD_SECTION_SIZE: context.local_max_header_size, | |
| SETTINGS_ENABLE_WEBTRANSPORT: context.local_datagram_support, | |
| SETTINGS_H3_DATAGRAM: context.local_datagram_support, | |
| SETTINGS_ENABLE_CONNECT_PROTOCOL: context.local_datagram_support, | |
| SETTINGS_WT_MAX_SESSIONS: 1 | |
| }); | |
| var control_stream_frames = build_h3_frames([ | |
| { frame_type: 4, payload: settings_frame } | |
| ]); | |
| ev.emit("stream", 3, new Uint8Array([0])); | |
| ev.emit("stream", 3, control_stream_frames); | |
| ev.emit("stream", 7, new Uint8Array([2])); | |
| ev.emit("stream", 11, new Uint8Array([3])); | |
| } | |
| setTimeout(connect, 0); | |
| var api = { | |
| on: function(name2, fn) { | |
| ev.on(name2, fn); | |
| }, | |
| stream: stream_write, | |
| http_header: http_header_write, | |
| http_body: http_body_write, | |
| end: function(data) { | |
| if (context.destroyed) | |
| return; | |
| if (typeof data !== "undefined" && data !== null) | |
| api.write(data); | |
| try { | |
| context.transport && context.transport.end && context.transport.end(); | |
| } catch (e) {} | |
| }, | |
| destroy: function() { | |
| if (context.destroyed) | |
| return; | |
| context.destroyed = true; | |
| try { | |
| context.transport && context.transport.destroy && context.transport.destroy(); | |
| } catch (e) {} | |
| } | |
| }; | |
| for (var k in api) | |
| if (Object.prototype.hasOwnProperty.call(api, k)) | |
| this[k] = api[k]; | |
| return this; | |
| } | |
| var h3_socket_default = H3Socket; | |
| // node_modules/quico/h3_server.js | |
| var require3 = createRequire2(import.meta.url); | |
| var flat_ranges2 = require3("flat-ranges"); | |
| function Emitter5() { | |
| var listeners = {}; | |
| return { | |
| on: function(name2, fn) { | |
| (listeners[name2] = listeners[name2] || []).push(fn); | |
| }, | |
| emit: function(name2) { | |
| var args = Array.prototype.slice.call(arguments, 1); | |
| var arr = listeners[name2] || []; | |
| for (var i2 = 0;i2 < arr.length; i2++) { | |
| try { | |
| arr[i2].apply(null, args); | |
| } catch (e) {} | |
| } | |
| } | |
| }; | |
| } | |
| function createServer(options, handler) { | |
| options = options || {}; | |
| var ev = Emitter5(); | |
| var context = { | |
| udp4: null, | |
| udp6: null, | |
| port: null, | |
| _handler: handler || null, | |
| SNICallback: options.SNICallback || null, | |
| connections: {}, | |
| address_binds: {}, | |
| timeout: null | |
| }; | |
| function set_http_stream(quic_connection_id, stream_id, params) { | |
| var is_new = false; | |
| if (stream_id in context.connections[quic_connection_id].http_streams == false) { | |
| var req = { | |
| method: null, | |
| path: null, | |
| headers: {}, | |
| stream_id: Number(stream_id) | |
| }; | |
| var res = { | |
| statusCode: null, | |
| headers: {}, | |
| headersSent: false, | |
| writeHead: function(statusCode, headers) { | |
| if (res.headersSent == false) { | |
| res.statusCode = statusCode; | |
| res.headers[":status"] = String(statusCode); | |
| if (typeof headers == "object") { | |
| for (var field_name2 in headers) { | |
| res.headers[field_name2] = headers[field_name2]; | |
| } | |
| } | |
| } | |
| context.connections[quic_connection_id].h3_socket.http_header(stream_id, res.headers); | |
| }, | |
| writeEarlyHints: function(hints) {}, | |
| write: function(chunk) { | |
| if (typeof chunk == "string") { | |
| var data = new TextEncoder().encode(chunk); | |
| context.connections[quic_connection_id].h3_socket.http_body(Number(stream_id), data); | |
| } else { | |
| context.connections[quic_connection_id].h3_socket.http_body(Number(stream_id), chunk); | |
| } | |
| }, | |
| end: function(chunk) { | |
| if (typeof chunk !== "undefined") { | |
| if (typeof chunk == "string") { | |
| var data = new TextEncoder().encode(chunk); | |
| context.connections[quic_connection_id].h3_socket.http_body(Number(stream_id), data, true); | |
| } else { | |
| context.connections[quic_connection_id].h3_socket.http_body(Number(stream_id), chunk, true); | |
| } | |
| } else { | |
| context.connections[quic_connection_id].h3_socket.http_body(Number(stream_id), null); | |
| } | |
| } | |
| }; | |
| context.connections[quic_connection_id].http_streams[stream_id] = { | |
| req, | |
| res | |
| }; | |
| is_new = true; | |
| } | |
| if (typeof params == "object") { | |
| if ("request_headers" in params) { | |
| for (var field_name in params["request_headers"]) { | |
| context.connections[quic_connection_id].http_streams[stream_id].req.headers[field_name] = params["request_headers"][field_name]; | |
| } | |
| } | |
| if (context.connections[quic_connection_id].http_streams[stream_id].req.method == null && ":method" in context.connections[quic_connection_id].http_streams[stream_id].req.headers == true) { | |
| context.connections[quic_connection_id].http_streams[stream_id].req.method = context.connections[quic_connection_id].http_streams[stream_id].req.headers[":method"]; | |
| } | |
| if (context.connections[quic_connection_id].http_streams[stream_id].req.path == null && ":path" in context.connections[quic_connection_id].http_streams[stream_id].req.headers == true) { | |
| context.connections[quic_connection_id].http_streams[stream_id].req.path = context.connections[quic_connection_id].http_streams[stream_id].req.headers[":path"]; | |
| } | |
| } | |
| if (is_new == true) { | |
| context._handler(context.connections[quic_connection_id].http_streams[stream_id].req, context.connections[quic_connection_id].http_streams[stream_id].res); | |
| } | |
| } | |
| function receiving_quic_packet(from_ip, from_port, data) { | |
| var quic_connection_id = null; | |
| var address_str = from_ip + ":" + from_port; | |
| var dcid_str = null; | |
| if ("dcid" in data && data.dcid && data.dcid.byteLength > 0) { | |
| dcid_str = Array.from(data.dcid).join(""); | |
| } | |
| if (dcid_str !== null) { | |
| if (dcid_str in context.connections == true) { | |
| quic_connection_id = dcid_str; | |
| } | |
| } else { | |
| if (address_str in context.address_binds == true) { | |
| if (context.address_binds[address_str] in context.connections == true) { | |
| quic_connection_id = context.address_binds[address_str]; | |
| } | |
| } | |
| } | |
| if (quic_connection_id == null) { | |
| if (dcid_str !== null) { | |
| quic_connection_id = dcid_str; | |
| } else { | |
| quic_connection_id = Math.floor(Math.random() * 9007199254740991); | |
| } | |
| } | |
| if (address_str in context.address_binds == false || context.address_binds[address_str] !== quic_connection_id) { | |
| context.address_binds[address_str] = quic_connection_id; | |
| } | |
| if (quic_connection_id in context.connections == false) { | |
| context.connections[quic_connection_id] = { | |
| quic_socket: null, | |
| h3_socket: null, | |
| http_streams: {} | |
| }; | |
| } | |
| if (context.connections[quic_connection_id].quic_socket == null) { | |
| var quic_socket = new quic_socket_default({ | |
| isServer: true, | |
| SNICallback: context.SNICallback | |
| }); | |
| context.connections[quic_connection_id].quic_socket = quic_socket; | |
| quic_socket.on("packet", function(data_to_send) { | |
| send_udp_packet(from_ip, from_port, data_to_send); | |
| }); | |
| quic_socket.on("connect", function() { | |
| var h3_socket = new h3_socket_default({ | |
| isServer: true | |
| }); | |
| context.connections[quic_connection_id].h3_socket = h3_socket; | |
| quic_socket.on("stream", function(stream_id, data2, fin) { | |
| h3_socket.stream(stream_id, data2, fin); | |
| }); | |
| h3_socket.on("stream", function(stream_id, data2, fin) { | |
| quic_socket.stream(stream_id, data2, fin); | |
| }); | |
| h3_socket.on("http_headers", function(stream_id, headers) { | |
| set_http_stream(quic_connection_id, stream_id, { | |
| request_headers: headers | |
| }); | |
| }); | |
| h3_socket.on("http_body", function(stream_id, payload) { | |
| set_http_stream(quic_connection_id, stream_id, { | |
| add_request_body_chunk: payload | |
| }); | |
| }); | |
| }); | |
| } | |
| context.connections[quic_connection_id].quic_socket.packet(data); | |
| } | |
| function receiving_udp_packet(from_ip, from_port, data) { | |
| var quic_packets = parse_quic_datagram(data); | |
| //console.log("quic_packets", quic_packets); | |
| if (quic_packets.length > 0) { | |
| for (var i2 in quic_packets) { | |
| if (quic_packets[i2] !== null) { | |
| receiving_quic_packet(from_ip, from_port, quic_packets[i2]); | |
| } | |
| } | |
| } | |
| } | |
| function send_udp_packet(to_ip, to_port, data, callback) { | |
| if (to_ip.indexOf(":") >= 0) { | |
| context.udp6.send(data, to_port, to_ip, function(error) { | |
| if (error) { | |
| if (typeof callback == "function") { | |
| callback(false); | |
| } | |
| } else { | |
| if (typeof callback == "function") { | |
| callback(true); | |
| } | |
| } | |
| }); | |
| } else { | |
| context.udp4.send(data, to_port, to_ip, function(error) { | |
| if (error) { | |
| if (typeof callback == "function") { | |
| callback(false); | |
| } | |
| } else { | |
| if (typeof callback == "function") { | |
| callback(true); | |
| } | |
| } | |
| }); | |
| } | |
| } | |
| function listen(port, host, callback) { | |
| if (typeof host === "function") { | |
| callback = host; | |
| host = null; | |
| } | |
| context.port = port || 443; | |
| host = host || "::"; | |
| context.udp4 = dgram.createSocket("udp4"); | |
| context.udp4.on("message", function(message, rinfo) { | |
| receiving_udp_packet(rinfo.address, rinfo.port, new Uint8Array(message)); | |
| }); | |
| context.udp4.on("error", function(error) {}); | |
| if (host === "::" || host.indexOf(".") !== -1) { | |
| var host4 = host.indexOf(".") !== -1 ? host : "0.0.0.0"; | |
| context.udp4.bind(context.port, host4); | |
| } | |
| context.udp6 = dgram.createSocket({ type: "udp6", ipv6Only: true }); | |
| context.udp6.on("message", function(message, rinfo) { | |
| receiving_udp_packet(rinfo.address, rinfo.port, new Uint8Array(message)); | |
| }); | |
| context.udp6.on("error", function(error) {}); | |
| var host6 = host.indexOf(":") !== -1 ? host : "::"; | |
| context.udp6.bind(context.port, host6, function() { | |
| if (typeof callback === "function") { | |
| callback(); | |
| } | |
| }); | |
| } | |
| function close() {} | |
| var api = { | |
| context, | |
| on: function(name2, fn) { | |
| ev.on(name2, fn); | |
| }, | |
| listen, | |
| close, | |
| setTimeout: function() {} | |
| }; | |
| for (var k in api) | |
| if (Object.prototype.hasOwnProperty.call(api, k)) | |
| this[k] = api[k]; | |
| return this; | |
| } | |
| // node_modules/quico/index.js | |
| var quico_default = { createServer }; | |
| export { | |
| lemon_tls_default as tls, | |
| quico_default as quico | |
| }; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment