nlcurl 0.6.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (151) hide show
  1. package/dist/cache/store.d.ts +89 -0
  2. package/dist/cache/store.d.ts.map +1 -0
  3. package/dist/cache/store.js +402 -0
  4. package/dist/cache/store.js.map +1 -0
  5. package/dist/cache/types.d.ts +101 -0
  6. package/dist/cache/types.d.ts.map +1 -0
  7. package/dist/cache/types.js +2 -0
  8. package/dist/cache/types.js.map +1 -0
  9. package/dist/cookies/jar.d.ts +11 -0
  10. package/dist/cookies/jar.d.ts.map +1 -1
  11. package/dist/cookies/jar.js +50 -4
  12. package/dist/cookies/jar.js.map +1 -1
  13. package/dist/cookies/parser.d.ts +2 -0
  14. package/dist/cookies/parser.d.ts.map +1 -1
  15. package/dist/cookies/parser.js +14 -0
  16. package/dist/cookies/parser.js.map +1 -1
  17. package/dist/cookies/psl-data.d.ts +1 -1
  18. package/dist/cookies/psl-data.js +1 -1
  19. package/dist/core/client.js +3 -0
  20. package/dist/core/client.js.map +1 -1
  21. package/dist/core/request.d.ts +68 -2
  22. package/dist/core/request.d.ts.map +1 -1
  23. package/dist/core/response.d.ts +22 -0
  24. package/dist/core/response.d.ts.map +1 -1
  25. package/dist/core/response.js +32 -0
  26. package/dist/core/response.js.map +1 -1
  27. package/dist/core/session.d.ts +23 -0
  28. package/dist/core/session.d.ts.map +1 -1
  29. package/dist/core/session.js +101 -3
  30. package/dist/core/session.js.map +1 -1
  31. package/dist/core/validation.d.ts +2 -1
  32. package/dist/core/validation.d.ts.map +1 -1
  33. package/dist/core/validation.js +5 -4
  34. package/dist/core/validation.js.map +1 -1
  35. package/dist/dns/codec.d.ts +37 -0
  36. package/dist/dns/codec.d.ts.map +1 -0
  37. package/dist/dns/codec.js +254 -0
  38. package/dist/dns/codec.js.map +1 -0
  39. package/dist/dns/doh-resolver.d.ts +52 -0
  40. package/dist/dns/doh-resolver.d.ts.map +1 -0
  41. package/dist/dns/doh-resolver.js +192 -0
  42. package/dist/dns/doh-resolver.js.map +1 -0
  43. package/dist/dns/https-rr.d.ts +51 -0
  44. package/dist/dns/https-rr.d.ts.map +1 -0
  45. package/dist/dns/https-rr.js +127 -0
  46. package/dist/dns/https-rr.js.map +1 -0
  47. package/dist/dns/types.d.ts +110 -0
  48. package/dist/dns/types.d.ts.map +1 -0
  49. package/dist/dns/types.js +34 -0
  50. package/dist/dns/types.js.map +1 -0
  51. package/dist/hsts/store.d.ts +41 -0
  52. package/dist/hsts/store.d.ts.map +1 -0
  53. package/dist/hsts/store.js +171 -0
  54. package/dist/hsts/store.js.map +1 -0
  55. package/dist/hsts/types.d.ts +28 -0
  56. package/dist/hsts/types.d.ts.map +1 -0
  57. package/dist/hsts/types.js +2 -0
  58. package/dist/hsts/types.js.map +1 -0
  59. package/dist/http/alt-svc.d.ts +85 -0
  60. package/dist/http/alt-svc.d.ts.map +1 -0
  61. package/dist/http/alt-svc.js +220 -0
  62. package/dist/http/alt-svc.js.map +1 -0
  63. package/dist/http/h1/client.d.ts.map +1 -1
  64. package/dist/http/h1/client.js +16 -0
  65. package/dist/http/h1/client.js.map +1 -1
  66. package/dist/http/h3/detection.d.ts +17 -0
  67. package/dist/http/h3/detection.d.ts.map +1 -0
  68. package/dist/http/h3/detection.js +59 -0
  69. package/dist/http/h3/detection.js.map +1 -0
  70. package/dist/http/negotiator.d.ts +24 -1
  71. package/dist/http/negotiator.d.ts.map +1 -1
  72. package/dist/http/negotiator.js +88 -18
  73. package/dist/http/negotiator.js.map +1 -1
  74. package/dist/http/pool.d.ts +2 -2
  75. package/dist/http/pool.d.ts.map +1 -1
  76. package/dist/http/pool.js.map +1 -1
  77. package/dist/index.d.ts +16 -1
  78. package/dist/index.d.ts.map +1 -1
  79. package/dist/index.js +12 -0
  80. package/dist/index.js.map +1 -1
  81. package/dist/middleware/rate-limiter.d.ts.map +1 -1
  82. package/dist/middleware/rate-limiter.js +4 -0
  83. package/dist/middleware/rate-limiter.js.map +1 -1
  84. package/dist/proxy/env-proxy.d.ts +21 -0
  85. package/dist/proxy/env-proxy.d.ts.map +1 -0
  86. package/dist/proxy/env-proxy.js +74 -0
  87. package/dist/proxy/env-proxy.js.map +1 -0
  88. package/dist/proxy/http-proxy.d.ts +2 -0
  89. package/dist/proxy/http-proxy.d.ts.map +1 -1
  90. package/dist/proxy/http-proxy.js +19 -6
  91. package/dist/proxy/http-proxy.js.map +1 -1
  92. package/dist/proxy/socks.js +1 -1
  93. package/dist/proxy/socks.js.map +1 -1
  94. package/dist/sse/parser.d.ts +70 -0
  95. package/dist/sse/parser.d.ts.map +1 -0
  96. package/dist/sse/parser.js +153 -0
  97. package/dist/sse/parser.js.map +1 -0
  98. package/dist/tls/ech.d.ts +147 -0
  99. package/dist/tls/ech.d.ts.map +1 -0
  100. package/dist/tls/ech.js +401 -0
  101. package/dist/tls/ech.js.map +1 -0
  102. package/dist/tls/node-engine.d.ts +9 -1
  103. package/dist/tls/node-engine.d.ts.map +1 -1
  104. package/dist/tls/node-engine.js +39 -1
  105. package/dist/tls/node-engine.js.map +1 -1
  106. package/dist/tls/pin-verification.d.ts +9 -0
  107. package/dist/tls/pin-verification.d.ts.map +1 -0
  108. package/dist/tls/pin-verification.js +34 -0
  109. package/dist/tls/pin-verification.js.map +1 -0
  110. package/dist/tls/session-cache.d.ts +70 -0
  111. package/dist/tls/session-cache.d.ts.map +1 -0
  112. package/dist/tls/session-cache.js +80 -0
  113. package/dist/tls/session-cache.js.map +1 -0
  114. package/dist/tls/stealth/client-hello.d.ts +21 -0
  115. package/dist/tls/stealth/client-hello.d.ts.map +1 -1
  116. package/dist/tls/stealth/client-hello.js +116 -0
  117. package/dist/tls/stealth/client-hello.js.map +1 -1
  118. package/dist/tls/stealth/engine.d.ts.map +1 -1
  119. package/dist/tls/stealth/engine.js +152 -30
  120. package/dist/tls/stealth/engine.js.map +1 -1
  121. package/dist/tls/stealth/handshake.d.ts +2 -1
  122. package/dist/tls/stealth/handshake.d.ts.map +1 -1
  123. package/dist/tls/stealth/handshake.js +118 -5
  124. package/dist/tls/stealth/handshake.js.map +1 -1
  125. package/dist/tls/stealth/tls12-handshake.d.ts +14 -0
  126. package/dist/tls/stealth/tls12-handshake.d.ts.map +1 -0
  127. package/dist/tls/stealth/tls12-handshake.js +462 -0
  128. package/dist/tls/stealth/tls12-handshake.js.map +1 -0
  129. package/dist/tls/types.d.ts +16 -0
  130. package/dist/tls/types.d.ts.map +1 -1
  131. package/dist/utils/encoding.d.ts +8 -6
  132. package/dist/utils/encoding.d.ts.map +1 -1
  133. package/dist/utils/encoding.js +92 -24
  134. package/dist/utils/encoding.js.map +1 -1
  135. package/dist/utils/happy-eyeballs.d.ts +3 -0
  136. package/dist/utils/happy-eyeballs.d.ts.map +1 -1
  137. package/dist/utils/happy-eyeballs.js +42 -2
  138. package/dist/utils/happy-eyeballs.js.map +1 -1
  139. package/dist/ws/client.d.ts +3 -0
  140. package/dist/ws/client.d.ts.map +1 -1
  141. package/dist/ws/client.js +63 -7
  142. package/dist/ws/client.js.map +1 -1
  143. package/dist/ws/frame.d.ts +4 -2
  144. package/dist/ws/frame.d.ts.map +1 -1
  145. package/dist/ws/frame.js +8 -5
  146. package/dist/ws/frame.js.map +1 -1
  147. package/dist/ws/permessage-deflate.d.ts +58 -0
  148. package/dist/ws/permessage-deflate.d.ts.map +1 -0
  149. package/dist/ws/permessage-deflate.js +148 -0
  150. package/dist/ws/permessage-deflate.js.map +1 -0
  151. package/package.json +2 -2
@@ -0,0 +1,70 @@
1
+ /**
2
+ * TLS session ticket cache for session resumption (RFC 5077 / RFC 8446 §4.6.1).
3
+ * Stores session tickets keyed by origin (`host:port`) and evicts expired
4
+ * entries automatically. Used by both {@link NodeTLSEngine} and
5
+ * {@link StealthTLSEngine} to enable 0-RTT and abbreviated handshakes.
6
+ */
7
+ /**
8
+ * A cached TLS session ticket with its expiration metadata.
9
+ *
10
+ * @typedef {Object} SessionTicketEntry
11
+ * @property {Buffer} ticket - Opaque session ticket bytes.
12
+ * @property {number} expiresAt - Unix timestamp (ms) at which the ticket is no longer valid.
13
+ * @property {string} [alpn] - ALPN protocol negotiated during the original handshake.
14
+ */
15
+ export interface SessionTicketEntry {
16
+ ticket: Buffer;
17
+ expiresAt: number;
18
+ alpn?: string;
19
+ }
20
+ /**
21
+ * Options for constructing a {@link TLSSessionCache}.
22
+ *
23
+ * @typedef {Object} SessionCacheOptions
24
+ * @property {number} [maxEntries=256] - Maximum number of tickets to store.
25
+ * @property {number} [defaultLifetimeMs=7200000] - Default ticket lifetime in ms when server doesn't specify.
26
+ */
27
+ export interface SessionCacheOptions {
28
+ maxEntries?: number;
29
+ defaultLifetimeMs?: number;
30
+ }
31
+ /**
32
+ * In-memory LRU cache for TLS session tickets. Thread-safe for single-threaded
33
+ * Node.js usage. Keys are `host:port` origin strings. Only valid (non-expired)
34
+ * tickets are returned on lookup.
35
+ */
36
+ export declare class TLSSessionCache {
37
+ private readonly maxEntries;
38
+ private readonly defaultLifetimeMs;
39
+ private readonly entries;
40
+ constructor(options?: SessionCacheOptions);
41
+ /**
42
+ * Stores a session ticket for the given origin.
43
+ *
44
+ * @param {string} origin - Origin key in `host:port` form.
45
+ * @param {Buffer} ticket - Opaque session ticket bytes.
46
+ * @param {number} [lifetimeMs] - Ticket lifetime in ms; uses default if omitted.
47
+ * @param {string} [alpn] - ALPN protocol from the original handshake.
48
+ */
49
+ set(origin: string, ticket: Buffer, lifetimeMs?: number, alpn?: string): void;
50
+ /**
51
+ * Retrieves a valid, non-expired session ticket for the given origin.
52
+ * Returns `undefined` if no ticket exists or the ticket has expired.
53
+ *
54
+ * @param {string} origin - Origin key in `host:port` form.
55
+ * @returns {SessionTicketEntry | undefined}
56
+ */
57
+ get(origin: string): SessionTicketEntry | undefined;
58
+ /**
59
+ * Removes a specific ticket from the cache.
60
+ *
61
+ * @param {string} origin - Origin key.
62
+ * @returns {boolean} Whether an entry was removed.
63
+ */
64
+ delete(origin: string): boolean;
65
+ /** Removes all entries from the cache. */
66
+ clear(): void;
67
+ /** Returns the number of entries currently cached. */
68
+ get size(): number;
69
+ }
70
+ //# sourceMappingURL=session-cache.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-cache.d.ts","sourceRoot":"","sources":["../../src/tls/session-cache.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;;;;;;GAOG;AACH,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAKD;;;;;;GAMG;AACH,MAAM,WAAW,mBAAmB;IAClC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED;;;;GAIG;AACH,qBAAa,eAAe;IAC1B,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAS;IAC3C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAyC;gBAErD,OAAO,GAAE,mBAAwB;IAK7C;;;;;;;OAOG;IACH,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI;IAc7E;;;;;;OAMG;IACH,GAAG,CAAC,MAAM,EAAE,MAAM,GAAG,kBAAkB,GAAG,SAAS;IAcnD;;;;;OAKG;IACH,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO;IAI/B,0CAA0C;IAC1C,KAAK,IAAI,IAAI;IAIb,sDAAsD;IACtD,IAAI,IAAI,IAAI,MAAM,CAEjB;CACF"}
@@ -0,0 +1,80 @@
1
+ /**
2
+ * TLS session ticket cache for session resumption (RFC 5077 / RFC 8446 §4.6.1).
3
+ * Stores session tickets keyed by origin (`host:port`) and evicts expired
4
+ * entries automatically. Used by both {@link NodeTLSEngine} and
5
+ * {@link StealthTLSEngine} to enable 0-RTT and abbreviated handshakes.
6
+ */
7
+ const DEFAULT_MAX_ENTRIES = 256;
8
+ const DEFAULT_LIFETIME_MS = 7200_000;
9
+ /**
10
+ * In-memory LRU cache for TLS session tickets. Thread-safe for single-threaded
11
+ * Node.js usage. Keys are `host:port` origin strings. Only valid (non-expired)
12
+ * tickets are returned on lookup.
13
+ */
14
+ export class TLSSessionCache {
15
+ maxEntries;
16
+ defaultLifetimeMs;
17
+ entries = new Map();
18
+ constructor(options = {}) {
19
+ this.maxEntries = options.maxEntries ?? DEFAULT_MAX_ENTRIES;
20
+ this.defaultLifetimeMs = options.defaultLifetimeMs ?? DEFAULT_LIFETIME_MS;
21
+ }
22
+ /**
23
+ * Stores a session ticket for the given origin.
24
+ *
25
+ * @param {string} origin - Origin key in `host:port` form.
26
+ * @param {Buffer} ticket - Opaque session ticket bytes.
27
+ * @param {number} [lifetimeMs] - Ticket lifetime in ms; uses default if omitted.
28
+ * @param {string} [alpn] - ALPN protocol from the original handshake.
29
+ */
30
+ set(origin, ticket, lifetimeMs, alpn) {
31
+ if (this.entries.size >= this.maxEntries) {
32
+ const oldest = this.entries.keys().next().value;
33
+ if (oldest !== undefined)
34
+ this.entries.delete(oldest);
35
+ }
36
+ this.entries.delete(origin);
37
+ this.entries.set(origin, {
38
+ ticket,
39
+ expiresAt: Date.now() + (lifetimeMs ?? this.defaultLifetimeMs),
40
+ alpn,
41
+ });
42
+ }
43
+ /**
44
+ * Retrieves a valid, non-expired session ticket for the given origin.
45
+ * Returns `undefined` if no ticket exists or the ticket has expired.
46
+ *
47
+ * @param {string} origin - Origin key in `host:port` form.
48
+ * @returns {SessionTicketEntry | undefined}
49
+ */
50
+ get(origin) {
51
+ const entry = this.entries.get(origin);
52
+ if (!entry)
53
+ return undefined;
54
+ if (Date.now() >= entry.expiresAt) {
55
+ this.entries.delete(origin);
56
+ return undefined;
57
+ }
58
+ this.entries.delete(origin);
59
+ this.entries.set(origin, entry);
60
+ return entry;
61
+ }
62
+ /**
63
+ * Removes a specific ticket from the cache.
64
+ *
65
+ * @param {string} origin - Origin key.
66
+ * @returns {boolean} Whether an entry was removed.
67
+ */
68
+ delete(origin) {
69
+ return this.entries.delete(origin);
70
+ }
71
+ /** Removes all entries from the cache. */
72
+ clear() {
73
+ this.entries.clear();
74
+ }
75
+ /** Returns the number of entries currently cached. */
76
+ get size() {
77
+ return this.entries.size;
78
+ }
79
+ }
80
+ //# sourceMappingURL=session-cache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-cache.js","sourceRoot":"","sources":["../../src/tls/session-cache.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAgBH,MAAM,mBAAmB,GAAG,GAAG,CAAC;AAChC,MAAM,mBAAmB,GAAG,QAAQ,CAAC;AAcrC;;;;GAIG;AACH,MAAM,OAAO,eAAe;IACT,UAAU,CAAS;IACnB,iBAAiB,CAAS;IAC1B,OAAO,GAAG,IAAI,GAAG,EAA8B,CAAC;IAEjE,YAAY,UAA+B,EAAE;QAC3C,IAAI,CAAC,UAAU,GAAG,OAAO,CAAC,UAAU,IAAI,mBAAmB,CAAC;QAC5D,IAAI,CAAC,iBAAiB,GAAG,OAAO,CAAC,iBAAiB,IAAI,mBAAmB,CAAC;IAC5E,CAAC;IAED;;;;;;;OAOG;IACH,GAAG,CAAC,MAAc,EAAE,MAAc,EAAE,UAAmB,EAAE,IAAa;QACpE,IAAI,IAAI,CAAC,OAAO,CAAC,IAAI,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;YACzC,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC;YAChD,IAAI,MAAM,KAAK,SAAS;gBAAE,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QACxD,CAAC;QAED,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QAC5B,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE;YACvB,MAAM;YACN,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,CAAC,UAAU,IAAI,IAAI,CAAC,iBAAiB,CAAC;YAC9D,IAAI;SACL,CAAC,CAAC;IACL,CAAC;IAED;;;;;;OAMG;IACH,GAAG,CAAC,MAAc;QAChB,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QACvC,IAAI,CAAC,KAAK;YAAE,OAAO,SAAS,CAAC;QAE7B,IAAI,IAAI,CAAC,GAAG,EAAE,IAAI,KAAK,CAAC,SAAS,EAAE,CAAC;YAClC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;YAC5B,OAAO,SAAS,CAAC;QACnB,CAAC;QAED,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QAC5B,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;QAChC,OAAO,KAAK,CAAC;IACf,CAAC;IAED;;;;;OAKG;IACH,MAAM,CAAC,MAAc;QACnB,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IACrC,CAAC;IAED,0CAA0C;IAC1C,KAAK;QACH,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;IACvB,CAAC;IAED,sDAAsD;IACtD,IAAI,IAAI;QACN,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC;IAC3B,CAAC;CACF"}
@@ -1,4 +1,5 @@
1
1
  import type { BrowserProfile } from "../../fingerprints/types.js";
2
+ import type { ECHEncryptionParams } from "../ech.js";
2
3
  /**
3
4
  * An ephemeral key share generated for a specific named group, used during
4
5
  * TLS 1.3 key exchange. Contains both the public key to advertise in the
@@ -51,4 +52,24 @@ export interface ClientHelloResult {
51
52
  * @returns {ClientHelloResult} The encoded record alongside key material needed for the handshake.
52
53
  */
53
54
  export declare function buildClientHello(profile: BrowserProfile, hostname: string): ClientHelloResult;
55
+ /**
56
+ * Result of building an ECH-encrypted ClientHello pair.
57
+ */
58
+ export interface ClientHelloECHResult extends ClientHelloResult {
59
+ /** Inner ClientHello handshake message (used for transcript if ECH is accepted). */
60
+ innerHandshakeMessage: Buffer;
61
+ /** Inner client random (used for ECH accept confirmation check). */
62
+ innerRandom: Buffer;
63
+ }
64
+ /**
65
+ * Builds a ClientHello pair with ECH encryption: an outer ClientHello
66
+ * (with the encrypted inner ClientHello in the ECH extension) and the
67
+ * inner ClientHello needed for transcript computation upon acceptance.
68
+ *
69
+ * @param profile Browser profile whose fingerprint to replicate.
70
+ * @param hostname Real server hostname (used in the inner ClientHello SNI).
71
+ * @param echParams ECH config and raw bytes for HPKE encryption.
72
+ * @returns The outer record to send plus the inner message for the transcript.
73
+ */
74
+ export declare function buildClientHelloWithECH(profile: BrowserProfile, hostname: string, echParams: ECHEncryptionParams): ClientHelloECHResult;
54
75
  //# sourceMappingURL=client-hello.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"client-hello.d.ts","sourceRoot":"","sources":["../../../src/tls/stealth/client-hello.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAmB,MAAM,6BAA6B,CAAC;AAMnF;;;;;;;;;GASG;AACH,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,aAAa,CAyB7D;AAiBD;;;;;;;;;;GAUG;AACH,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,aAAa,EAAE,CAAC;IAC3B,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,gBAAgB,EAAE,MAAM,CAAC;CAC1B;AAED;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,GAAG,iBAAiB,CA2E7F"}
1
+ {"version":3,"file":"client-hello.d.ts","sourceRoot":"","sources":["../../../src/tls/stealth/client-hello.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAmB,MAAM,6BAA6B,CAAC;AACnF,OAAO,KAAK,EAAa,mBAAmB,EAAE,MAAM,WAAW,CAAC;AAOhE;;;;;;;;;GASG;AACH,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,aAAa,CAyB7D;AAiBD;;;;;;;;;;GAUG;AACH,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,aAAa,EAAE,CAAC;IAC3B,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,gBAAgB,EAAE,MAAM,CAAC;CAC1B;AAED;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,GAAG,iBAAiB,CA2E7F;AA6CD;;GAEG;AACH,MAAM,WAAW,oBAAqB,SAAQ,iBAAiB;IAC7D,oFAAoF;IACpF,qBAAqB,EAAE,MAAM,CAAC;IAC9B,oEAAoE;IACpE,WAAW,EAAE,MAAM,CAAC;CACrB;AAED;;;;;;;;;GASG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,mBAAmB,GAAG,oBAAoB,CA8DvI"}
@@ -1,6 +1,7 @@
1
1
  import { randomBytes, createECDH, generateKeyPairSync } from "node:crypto";
2
2
  import { BufferWriter } from "../../utils/buffer-writer.js";
3
3
  import { RecordType, HandshakeType, ExtensionType, GREASE_VALUES, NamedGroup } from "../constants.js";
4
+ import { echEncryptInner, buildECHOuterExtData, parseHpkeKeyConfig, getMaxNameLength } from "../ech.js";
4
5
  function randomGrease() {
5
6
  return GREASE_VALUES[Math.floor(Math.random() * GREASE_VALUES.length)];
6
7
  }
@@ -164,4 +165,119 @@ function writeExtension(w, extDef, hostname, keyShares, tlsProfile, grease) {
164
165
  w.writeUInt16(0);
165
166
  }
166
167
  }
168
+ /**
169
+ * Builds a ClientHello pair with ECH encryption: an outer ClientHello
170
+ * (with the encrypted inner ClientHello in the ECH extension) and the
171
+ * inner ClientHello needed for transcript computation upon acceptance.
172
+ *
173
+ * @param profile Browser profile whose fingerprint to replicate.
174
+ * @param hostname Real server hostname (used in the inner ClientHello SNI).
175
+ * @param echParams ECH config and raw bytes for HPKE encryption.
176
+ * @returns The outer record to send plus the inner message for the transcript.
177
+ */
178
+ export function buildClientHelloWithECH(profile, hostname, echParams) {
179
+ const tlsProfile = profile.tls;
180
+ const innerRandom = randomBytes(32);
181
+ const outerRandom = randomBytes(32);
182
+ const outerSessionId = tlsProfile.randomSessionId ? randomBytes(32) : Buffer.alloc(0);
183
+ const keyShares = tlsProfile.keyShareGroups.map(generateKeyShare);
184
+ const greaseCipher = tlsProfile.grease ? randomGrease() : 0;
185
+ const greaseExt = tlsProfile.grease ? randomGrease() : 0;
186
+ const greaseGroup = tlsProfile.grease ? randomGrease() : 0;
187
+ const greaseVersion = tlsProfile.grease ? randomGrease() : 0;
188
+ const lastGreaseInner = tlsProfile.grease ? randomGrease() : 0;
189
+ const lastGreaseOuter = tlsProfile.grease ? randomGrease() : 0;
190
+ const greaseVals = { greaseGroup, greaseVersion };
191
+ const hpkeConfig = parseHpkeKeyConfig(echParams.config.contents);
192
+ if (!hpkeConfig || hpkeConfig.kemId !== 0x0020) {
193
+ throw new Error("Unsupported ECH config: requires DHKEM(X25519, HKDF-SHA256)");
194
+ }
195
+ const suite = hpkeConfig.cipherSuites.find((cs) => cs.kdfId === 0x0001 && (cs.aeadId === 0x0001 || cs.aeadId === 0x0003));
196
+ if (!suite)
197
+ throw new Error("No supported HPKE cipher suite in ECH config");
198
+ const innerCHBody = buildCHBodyCore(tlsProfile, hostname, innerRandom, Buffer.alloc(0), keyShares, greaseCipher, greaseExt, lastGreaseInner, greaseVals, Buffer.from([0x01]));
199
+ const innerHSMsg = wrapHandshakeMessage(innerCHBody);
200
+ const maxNameLen = getMaxNameLength(echParams.config.contents);
201
+ const hostLen = Buffer.byteLength(hostname, "ascii");
202
+ const paddingLen = Math.max(0, maxNameLen - hostLen);
203
+ const paddedInner = paddingLen > 0 ? Buffer.concat([innerCHBody, Buffer.alloc(paddingLen)]) : innerCHBody;
204
+ const expectedPayloadLen = paddedInner.length + 16;
205
+ const zeroEchExt = buildECHOuterExtData(suite.kdfId, suite.aeadId, hpkeConfig.configId, Buffer.alloc(32), Buffer.alloc(expectedPayloadLen));
206
+ const buildOuter = (echExtData) => buildCHBodyCore(tlsProfile, echParams.config.publicName, outerRandom, outerSessionId, keyShares, greaseCipher, greaseExt, lastGreaseOuter, greaseVals, echExtData);
207
+ const outerBodyZero = buildOuter(zeroEchExt);
208
+ const outerAAD = wrapHandshakeMessage(outerBodyZero);
209
+ const echResult = echEncryptInner(paddedInner, outerAAD, echParams.config, echParams.configRaw);
210
+ const finalOuterBody = buildOuter(echResult.extensionData);
211
+ const finalHandshakeMessage = wrapHandshakeMessage(finalOuterBody);
212
+ const record = new BufferWriter(5 + finalHandshakeMessage.length);
213
+ record.writeUInt8(RecordType.HANDSHAKE);
214
+ record.writeUInt16(tlsProfile.recordVersion);
215
+ record.writeUInt16(finalHandshakeMessage.length);
216
+ record.writeBytes(finalHandshakeMessage);
217
+ return {
218
+ record: record.toBuffer(),
219
+ keyShares,
220
+ clientRandom: outerRandom,
221
+ sessionId: outerSessionId,
222
+ handshakeMessage: finalHandshakeMessage,
223
+ innerHandshakeMessage: innerHSMsg,
224
+ innerRandom,
225
+ };
226
+ }
227
+ /**
228
+ * Core ClientHello body builder shared by both `buildClientHello` and
229
+ * `buildClientHelloWithECH`. Builds the ClientHello payload (after the
230
+ * handshake header) with deterministic GREASE values.
231
+ *
232
+ * @param echExtData When provided, replaces the profile's ECH extension
233
+ * with this data. For inner CH: `Buffer.from([0x01])`.
234
+ * For outer CH: the full outer ECH extension payload.
235
+ */
236
+ function buildCHBodyCore(tlsProfile, hostname, clientRandom, sessionId, keyShares, greaseCipher, greaseExt, lastGrease, grease, echExtData) {
237
+ const body = new BufferWriter(4096);
238
+ body.writeUInt16(tlsProfile.clientVersion);
239
+ body.writeBytes(clientRandom);
240
+ body.writeUInt8(sessionId.length);
241
+ if (sessionId.length > 0)
242
+ body.writeBytes(sessionId);
243
+ const ciphers = tlsProfile.grease ? [greaseCipher, ...tlsProfile.cipherSuites] : [...tlsProfile.cipherSuites];
244
+ body.writeUInt16(ciphers.length * 2);
245
+ for (const c of ciphers)
246
+ body.writeUInt16(c);
247
+ body.writeUInt8(tlsProfile.compressionMethods.length);
248
+ for (const m of tlsProfile.compressionMethods)
249
+ body.writeUInt8(m);
250
+ const extWriter = new BufferWriter(4096);
251
+ if (tlsProfile.grease) {
252
+ extWriter.writeUInt16(greaseExt);
253
+ extWriter.writeUInt16(1);
254
+ extWriter.writeUInt8(0);
255
+ }
256
+ for (const extDef of tlsProfile.extensions) {
257
+ if (extDef.type === ExtensionType.ENCRYPTED_CLIENT_HELLO && echExtData) {
258
+ extWriter.writeUInt16(ExtensionType.ENCRYPTED_CLIENT_HELLO);
259
+ extWriter.writeUInt16(echExtData.length);
260
+ extWriter.writeBytes(echExtData);
261
+ continue;
262
+ }
263
+ writeExtension(extWriter, extDef, hostname, keyShares, tlsProfile, grease);
264
+ }
265
+ if (tlsProfile.grease) {
266
+ extWriter.writeUInt16(lastGrease);
267
+ extWriter.writeUInt16(1);
268
+ extWriter.writeUInt8(0);
269
+ }
270
+ const extBytes = extWriter.toBuffer();
271
+ body.writeUInt16(extBytes.length);
272
+ body.writeBytes(extBytes);
273
+ return body.toBuffer();
274
+ }
275
+ /** Wraps a ClientHello body in a handshake message (type + length + body). */
276
+ function wrapHandshakeMessage(chBody) {
277
+ const w = new BufferWriter(4 + chBody.length);
278
+ w.writeUInt8(HandshakeType.CLIENT_HELLO);
279
+ w.writeUInt24(chBody.length);
280
+ w.writeBytes(chBody);
281
+ return w.toBuffer();
282
+ }
167
283
  //# sourceMappingURL=client-hello.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"client-hello.js","sourceRoot":"","sources":["../../../src/tls/stealth/client-hello.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"client-hello.js","sourceRoot":"","sources":["../../../src/tls/stealth/client-hello.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../../../src/tls/stealth/engine.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,iBAAiB,EAAqB,SAAS,EAAE,MAAM,aAAa,CAAC;AAC/F,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AA4GlE;;;;;;GAMG;AACH,qBAAa,gBAAiB,YAAW,UAAU;IACjD;;;;;;;;;;OAUG;IACG,OAAO,CAAC,OAAO,EAAE,iBAAiB,EAAE,OAAO,CAAC,EAAE,cAAc,GAAG,OAAO,CAAC,SAAS,CAAC;CAiBxF"}
1
+ {"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../../../src/tls/stealth/engine.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAE,iBAAiB,EAAqB,SAAS,EAAE,MAAM,aAAa,CAAC;AAC/F,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AA4NlE;;;;;;GAMG;AACH,qBAAa,gBAAiB,YAAW,UAAU;IACjD;;;;;;;;;;OAUG;IACG,OAAO,CAAC,OAAO,EAAE,iBAAiB,EAAE,OAAO,CAAC,EAAE,cAAc,GAAG,OAAO,CAAC,SAAS,CAAC;CA4BxF"}
@@ -1,10 +1,13 @@
1
1
  import * as net from "node:net";
2
+ import { createCipheriv, createDecipheriv } from "node:crypto";
2
3
  import { Duplex } from "node:stream";
3
4
  import { TLSError } from "../../core/errors.js";
4
5
  import { performHandshake } from "./handshake.js";
5
- import { wrapEncryptedRecord, unwrapEncryptedRecord, readRecord } from "./record-layer.js";
6
- import { RecordType } from "../constants.js";
6
+ import { wrapEncryptedRecord, unwrapEncryptedRecord, readRecord, writeRecord } from "./record-layer.js";
7
+ import { RecordType, ProtocolVersion } from "../constants.js";
7
8
  import { DEFAULT_PROFILE } from "../../fingerprints/database.js";
9
+ import { parseECHConfigList, extractFirstECHConfigRaw } from "../ech.js";
10
+ const AEAD_TAG_SIZE = 16;
8
11
  class StealthTLSStream extends Duplex {
9
12
  rawSocket;
10
13
  aead;
@@ -12,6 +15,7 @@ class StealthTLSStream extends Duplex {
12
15
  clientIV;
13
16
  serverKey;
14
17
  serverIV;
18
+ isTLS12;
15
19
  clientSeq = 0n;
16
20
  serverSeq = 0n;
17
21
  readBuffer = Buffer.alloc(0);
@@ -25,6 +29,7 @@ class StealthTLSStream extends Duplex {
25
29
  this.clientIV = handshake.clientIV;
26
30
  this.serverKey = handshake.serverKey;
27
31
  this.serverIV = handshake.serverIV;
32
+ this.isTLS12 = handshake.version === "TLSv1.2";
28
33
  this.connectionInfo = {
29
34
  version: handshake.version,
30
35
  alpnProtocol: handshake.alpnProtocol,
@@ -40,7 +45,13 @@ class StealthTLSStream extends Duplex {
40
45
  _read() { }
41
46
  _write(chunk, _encoding, callback) {
42
47
  try {
43
- const encrypted = wrapEncryptedRecord(this.aead, this.clientKey, this.clientIV, this.clientSeq++, RecordType.APPLICATION_DATA, chunk);
48
+ let encrypted;
49
+ if (this.isTLS12) {
50
+ encrypted = this.tls12EncryptRecord(RecordType.APPLICATION_DATA, chunk);
51
+ }
52
+ else {
53
+ encrypted = wrapEncryptedRecord(this.aead, this.clientKey, this.clientIV, this.clientSeq++, RecordType.APPLICATION_DATA, chunk);
54
+ }
44
55
  this.rawSocket.write(encrypted, callback);
45
56
  }
46
57
  catch (err) {
@@ -55,6 +66,79 @@ class StealthTLSStream extends Duplex {
55
66
  destroyTLS() {
56
67
  this.destroy();
57
68
  }
69
+ tls12EncryptRecord(contentType, plaintext) {
70
+ const isChaCha = this.aead === "chacha20-poly1305";
71
+ let nonce;
72
+ let prefix;
73
+ if (isChaCha) {
74
+ nonce = Buffer.from(this.clientIV);
75
+ const seqBuf = Buffer.alloc(8);
76
+ seqBuf.writeBigUInt64BE(this.clientSeq);
77
+ for (let i = 0; i < 8; i++)
78
+ nonce[nonce.length - 8 + i] ^= seqBuf[i];
79
+ prefix = Buffer.alloc(0);
80
+ }
81
+ else {
82
+ const explicitNonce = Buffer.alloc(8);
83
+ explicitNonce.writeBigUInt64BE(this.clientSeq);
84
+ nonce = Buffer.concat([this.clientIV, explicitNonce]);
85
+ prefix = explicitNonce;
86
+ }
87
+ const aad = Buffer.alloc(13);
88
+ aad.writeBigUInt64BE(this.clientSeq, 0);
89
+ aad[8] = contentType;
90
+ aad.writeUInt16BE(ProtocolVersion.TLS_1_2, 9);
91
+ aad.writeUInt16BE(plaintext.length, 11);
92
+ const cipher = createCipheriv(this.aead, this.clientKey, nonce, { authTagLength: AEAD_TAG_SIZE });
93
+ cipher.setAAD(aad);
94
+ const enc = cipher.update(plaintext);
95
+ const final = cipher.final();
96
+ const tag = cipher.getAuthTag();
97
+ const payload = Buffer.concat([prefix, enc, final, tag]);
98
+ this.clientSeq++;
99
+ return writeRecord(contentType, ProtocolVersion.TLS_1_2, payload);
100
+ }
101
+ tls12DecryptRecord(record) {
102
+ const isChaCha = this.aead === "chacha20-poly1305";
103
+ let nonce;
104
+ let encData;
105
+ if (isChaCha) {
106
+ nonce = Buffer.from(this.serverIV);
107
+ const seqBuf = Buffer.alloc(8);
108
+ seqBuf.writeBigUInt64BE(this.serverSeq);
109
+ for (let i = 0; i < 8; i++)
110
+ nonce[nonce.length - 8 + i] ^= seqBuf[i];
111
+ encData = record.fragment;
112
+ }
113
+ else {
114
+ if (record.fragment.length < 8 + AEAD_TAG_SIZE)
115
+ throw new TLSError("TLS 1.2 record too short");
116
+ const explicitNonce = record.fragment.subarray(0, 8);
117
+ nonce = Buffer.concat([this.serverIV, explicitNonce]);
118
+ encData = record.fragment.subarray(8);
119
+ }
120
+ if (encData.length < AEAD_TAG_SIZE)
121
+ throw new TLSError("TLS 1.2 record too short for tag");
122
+ const encryptedData = encData.subarray(0, encData.length - AEAD_TAG_SIZE);
123
+ const tag = encData.subarray(encData.length - AEAD_TAG_SIZE);
124
+ const aad = Buffer.alloc(13);
125
+ aad.writeBigUInt64BE(this.serverSeq, 0);
126
+ aad[8] = record.type;
127
+ aad.writeUInt16BE(ProtocolVersion.TLS_1_2, 9);
128
+ aad.writeUInt16BE(encryptedData.length, 11);
129
+ const decipher = createDecipheriv(this.aead, this.serverKey, nonce, { authTagLength: AEAD_TAG_SIZE });
130
+ decipher.setAAD(aad);
131
+ decipher.setAuthTag(tag);
132
+ try {
133
+ const decrypted = decipher.update(encryptedData);
134
+ const final = decipher.final();
135
+ this.serverSeq++;
136
+ return Buffer.concat([decrypted, final]);
137
+ }
138
+ catch {
139
+ throw new TLSError("TLS 1.2 AEAD decryption failed");
140
+ }
141
+ }
58
142
  handleRawData(chunk) {
59
143
  this.readBuffer = Buffer.concat([this.readBuffer, chunk]);
60
144
  this.processReadBuffer();
@@ -66,36 +150,64 @@ class StealthTLSStream extends Duplex {
66
150
  break;
67
151
  this.readBuffer = this.readBuffer.subarray(result.bytesRead);
68
152
  const { record } = result;
69
- if (record.type === RecordType.APPLICATION_DATA) {
70
- try {
71
- const decrypted = unwrapEncryptedRecord(this.aead, this.serverKey, this.serverIV, this.serverSeq++, record);
72
- if (decrypted.contentType === RecordType.APPLICATION_DATA) {
73
- this.push(decrypted.plaintext);
153
+ if (this.isTLS12) {
154
+ this.processRecordTLS12(record);
155
+ }
156
+ else {
157
+ this.processRecordTLS13(record);
158
+ }
159
+ }
160
+ }
161
+ processRecordTLS12(record) {
162
+ if (record.type === RecordType.APPLICATION_DATA) {
163
+ try {
164
+ const plaintext = this.tls12DecryptRecord(record);
165
+ this.push(plaintext);
166
+ }
167
+ catch (err) {
168
+ this.destroy(err instanceof Error ? err : new Error(String(err)));
169
+ }
170
+ }
171
+ else if (record.type === RecordType.ALERT) {
172
+ const desc = record.fragment.length >= 2 ? record.fragment[1] : 0;
173
+ if (desc === 0) {
174
+ this.push(null);
175
+ }
176
+ else {
177
+ this.destroy(new TLSError(`TLS alert: desc=${desc}`, desc));
178
+ }
179
+ }
180
+ }
181
+ processRecordTLS13(record) {
182
+ if (record.type === RecordType.APPLICATION_DATA) {
183
+ try {
184
+ const decrypted = unwrapEncryptedRecord(this.aead, this.serverKey, this.serverIV, this.serverSeq++, record);
185
+ if (decrypted.contentType === RecordType.APPLICATION_DATA) {
186
+ this.push(decrypted.plaintext);
187
+ }
188
+ else if (decrypted.contentType === RecordType.ALERT) {
189
+ const level = decrypted.plaintext[0];
190
+ const desc = decrypted.plaintext[1];
191
+ if (desc === 0) {
192
+ this.push(null);
74
193
  }
75
- else if (decrypted.contentType === RecordType.ALERT) {
76
- const level = decrypted.plaintext[0];
77
- const desc = decrypted.plaintext[1];
78
- if (desc === 0) {
79
- this.push(null);
80
- }
81
- else {
82
- this.destroy(new TLSError(`TLS alert: level=${level} desc=${desc}`, desc));
83
- }
194
+ else {
195
+ this.destroy(new TLSError(`TLS alert: level=${level} desc=${desc}`, desc));
84
196
  }
85
197
  }
86
- catch (err) {
87
- this.destroy(err instanceof Error ? err : new Error(String(err)));
88
- return;
89
- }
90
198
  }
91
- else if (record.type === RecordType.ALERT) {
92
- const desc = record.fragment.length >= 2 ? record.fragment[1] : 0;
93
- if (desc === 0) {
94
- this.push(null);
95
- }
96
- else {
97
- this.destroy(new TLSError(`Unencrypted alert: desc=${desc}`, desc));
98
- }
199
+ catch (err) {
200
+ this.destroy(err instanceof Error ? err : new Error(String(err)));
201
+ return;
202
+ }
203
+ }
204
+ else if (record.type === RecordType.ALERT) {
205
+ const desc = record.fragment.length >= 2 ? record.fragment[1] : 0;
206
+ if (desc === 0) {
207
+ this.push(null);
208
+ }
209
+ else {
210
+ this.destroy(new TLSError(`Unencrypted alert: desc=${desc}`, desc));
99
211
  }
100
212
  }
101
213
  }
@@ -124,7 +236,17 @@ export class StealthTLSEngine {
124
236
  const hostname = options.servername ?? options.host;
125
237
  const rawSocket = options.socket ? options.socket : await tcpConnect(options.host, options.port, options.timeout, options.signal);
126
238
  try {
127
- const handshake = await performHandshake(rawSocket, effectiveProfile, hostname, options.insecure ?? false);
239
+ let echParams;
240
+ if (options.echConfigList) {
241
+ const parsed = parseECHConfigList(options.echConfigList);
242
+ if (parsed && parsed.configs.length > 0) {
243
+ const configRaw = extractFirstECHConfigRaw(options.echConfigList);
244
+ if (configRaw) {
245
+ echParams = { config: parsed.configs[0], configRaw };
246
+ }
247
+ }
248
+ }
249
+ const handshake = await performHandshake(rawSocket, effectiveProfile, hostname, options.insecure ?? false, options.pinnedPublicKey, echParams);
128
250
  const stream = new StealthTLSStream(rawSocket, handshake);
129
251
  return stream;
130
252
  }