@rester159/blacktip 0.2.0 → 0.5.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 (53) hide show
  1. package/CHANGELOG.md +222 -0
  2. package/README.md +25 -0
  3. package/dist/akamai-sensor.d.ts +128 -0
  4. package/dist/akamai-sensor.d.ts.map +1 -0
  5. package/dist/akamai-sensor.js +190 -0
  6. package/dist/akamai-sensor.js.map +1 -0
  7. package/dist/behavioral/parsers.d.ts +89 -0
  8. package/dist/behavioral/parsers.d.ts.map +1 -0
  9. package/dist/behavioral/parsers.js +223 -0
  10. package/dist/behavioral/parsers.js.map +1 -0
  11. package/dist/blacktip.d.ts +68 -1
  12. package/dist/blacktip.d.ts.map +1 -1
  13. package/dist/blacktip.js +140 -1
  14. package/dist/blacktip.js.map +1 -1
  15. package/dist/browser-core.d.ts +10 -0
  16. package/dist/browser-core.d.ts.map +1 -1
  17. package/dist/browser-core.js +49 -0
  18. package/dist/browser-core.js.map +1 -1
  19. package/dist/diagnostics.d.ts +31 -0
  20. package/dist/diagnostics.d.ts.map +1 -1
  21. package/dist/diagnostics.js +146 -0
  22. package/dist/diagnostics.js.map +1 -1
  23. package/dist/identity-pool.d.ts +160 -0
  24. package/dist/identity-pool.d.ts.map +1 -0
  25. package/dist/identity-pool.js +288 -0
  26. package/dist/identity-pool.js.map +1 -0
  27. package/dist/index.d.ts +11 -2
  28. package/dist/index.d.ts.map +1 -1
  29. package/dist/index.js +11 -1
  30. package/dist/index.js.map +1 -1
  31. package/dist/tls-rewriter.d.ts +74 -0
  32. package/dist/tls-rewriter.d.ts.map +1 -0
  33. package/dist/tls-rewriter.js +203 -0
  34. package/dist/tls-rewriter.js.map +1 -0
  35. package/dist/tls-side-channel.d.ts +91 -0
  36. package/dist/tls-side-channel.d.ts.map +1 -0
  37. package/dist/tls-side-channel.js +248 -0
  38. package/dist/tls-side-channel.js.map +1 -0
  39. package/dist/types.d.ts +46 -0
  40. package/dist/types.d.ts.map +1 -1
  41. package/dist/types.js.map +1 -1
  42. package/docs/akamai-bypass.md +257 -0
  43. package/docs/akamai-sensor.md +183 -0
  44. package/docs/anti-bot-validation.md +84 -0
  45. package/docs/calibration-validation.md +93 -0
  46. package/docs/identity-pool.md +176 -0
  47. package/docs/tls-rewriting.md +121 -0
  48. package/docs/tls-side-channel.md +83 -0
  49. package/native/tls-client/go.mod +21 -0
  50. package/native/tls-client/go.sum +36 -0
  51. package/native/tls-client/main.go +216 -0
  52. package/package.json +8 -2
  53. package/scripts/fit-cmu-keystroke.mjs +186 -0
package/dist/index.d.ts CHANGED
@@ -8,14 +8,23 @@ export { Logger } from './logging.js';
8
8
  export { BrowserCore } from './browser-core.js';
9
9
  export { fitDistribution, fitFittsLaw, fitMouseDynamics, fitTypingDynamics, fitFromSamples, deriveProfileConfig, } from './behavioral/calibration.js';
10
10
  export type { MouseSample, MouseMovement, KeystrokeSample, TypingSession, DistributionFit, MouseFit, TypingFit, CalibratedProfile, } from './behavioral/calibration.js';
11
+ export { parseCmuKeystrokeCsv, parseBalabitMouseCsv, parseGenericTelemetryJson, CMU_PHRASE, } from './behavioral/parsers.js';
12
+ export { TlsSideChannel } from './tls-side-channel.js';
13
+ export type { TlsRequest, TlsResponse, ParsedCookie } from './tls-side-channel.js';
14
+ export { installTlsRewriter } from './tls-rewriter.js';
15
+ export type { TlsRewriterOptions, TlsRewriterStats } from './tls-rewriter.js';
16
+ export { solveAkamaiChallenge, parseAbckState } from './akamai-sensor.js';
17
+ export type { AkamaiChallengeResult } from './akamai-sensor.js';
18
+ export { IdentityPool } from './identity-pool.js';
19
+ export type { Identity, IdentityPoolOptions, RotationPolicy, DeviceProfileName, } from './identity-pool.js';
11
20
  export { ProxyPool, ProxyProviders, proxyToUrl } from './proxy-pool.js';
12
21
  export type { ProxyDescriptor, ProxyProtocol, PoolOptions } from './proxy-pool.js';
13
22
  export { SnapshotManager } from './snapshot.js';
14
23
  export type { SessionSnapshot } from './snapshot.js';
15
24
  export { attachObservability, JsonlFileExporter, ConsoleExporter, newTraceId, } from './observability.js';
16
25
  export type { StructuredEvent, EventExporter } from './observability.js';
17
- export { captureFingerprint, checkIpReputation, testAgainstAkamai, } from './diagnostics.js';
18
- export type { FingerprintSnapshot, IpReputationResult, AkamaiTestResult, } from './diagnostics.js';
26
+ export { captureFingerprint, checkIpReputation, testAgainstAkamai, testAgainstAntiBot, } from './diagnostics.js';
27
+ export type { FingerprintSnapshot, IpReputationResult, AkamaiTestResult, AntiBotTestResult, AntiBotVendor, } from './diagnostics.js';
19
28
  export type { BlackTipConfig, ProfileConfig, DeviceProfile, PluginData, ActionResult, NavigateResult, ScreenshotResult, WaitResult, ActionEvent, BehavioralMetadata, ErrorEvent, RetryEvent, TabChangeEvent, LogEntry, TabInfo, FrameInfo, LogLevel, ClickOptions, TypeOptions, ScrollOptions, HoverOptions, SelectOptions, PressKeyOptions, UploadFileOptions, NavigateOptions, ScreenshotOptions, WaitForOptions, WaitForNavigationOptions, ExtractTextOptions, PageContentOptions, ErrorCode, RetryStrategy, Point, BoundingBox, } from './types.js';
20
29
  export { ErrorCodes } from './types.js';
21
30
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AACxD,OAAO,EAAE,gBAAgB,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAC1F,YAAY,EAAE,SAAS,EAAE,aAAa,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AACrG,OAAO,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AACxD,OAAO,EAAE,sBAAsB,EAAE,MAAM,cAAc,CAAC;AACtD,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AACtC,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAGhD,OAAO,EACL,eAAe,EACf,WAAW,EACX,gBAAgB,EAChB,iBAAiB,EACjB,cAAc,EACd,mBAAmB,GACpB,MAAM,6BAA6B,CAAC;AACrC,YAAY,EACV,WAAW,EACX,aAAa,EACb,eAAe,EACf,aAAa,EACb,eAAe,EACf,QAAQ,EACR,SAAS,EACT,iBAAiB,GAClB,MAAM,6BAA6B,CAAC;AAErC,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AACxE,YAAY,EAAE,eAAe,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAEnF,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAChD,YAAY,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAErD,OAAO,EACL,mBAAmB,EACnB,iBAAiB,EACjB,eAAe,EACf,UAAU,GACX,MAAM,oBAAoB,CAAC;AAC5B,YAAY,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAGzE,OAAO,EACL,kBAAkB,EAClB,iBAAiB,EACjB,iBAAiB,GAClB,MAAM,kBAAkB,CAAC;AAC1B,YAAY,EACV,mBAAmB,EACnB,kBAAkB,EAClB,gBAAgB,GACjB,MAAM,kBAAkB,CAAC;AAE1B,YAAY,EACV,cAAc,EACd,aAAa,EACb,aAAa,EACb,UAAU,EACV,YAAY,EACZ,cAAc,EACd,gBAAgB,EAChB,UAAU,EACV,WAAW,EACX,kBAAkB,EAClB,UAAU,EACV,UAAU,EACV,cAAc,EACd,QAAQ,EACR,OAAO,EACP,SAAS,EACT,QAAQ,EACR,YAAY,EACZ,WAAW,EACX,aAAa,EACb,YAAY,EACZ,aAAa,EACb,eAAe,EACf,iBAAiB,EACjB,eAAe,EACf,iBAAiB,EACjB,cAAc,EACd,wBAAwB,EACxB,kBAAkB,EAClB,kBAAkB,EAClB,SAAS,EACT,aAAa,EACb,KAAK,EACL,WAAW,GACZ,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -7,10 +7,20 @@ export { Logger } from './logging.js';
7
7
  export { BrowserCore } from './browser-core.js';
8
8
  // v2 additions — Tier 2 calibration, Tier 3 infrastructure, observability.
9
9
  export { fitDistribution, fitFittsLaw, fitMouseDynamics, fitTypingDynamics, fitFromSamples, deriveProfileConfig, } from './behavioral/calibration.js';
10
+ // v0.3.0 — dataset parsers for end-to-end calibration
11
+ export { parseCmuKeystrokeCsv, parseBalabitMouseCsv, parseGenericTelemetryJson, CMU_PHRASE, } from './behavioral/parsers.js';
12
+ // v0.3.0 — TLS side-channel via bogdanfinn/tls-client
13
+ export { TlsSideChannel } from './tls-side-channel.js';
14
+ // v0.5.0 — full TLS rewriting via CDP Fetch interception + Go daemon
15
+ export { installTlsRewriter } from './tls-rewriter.js';
16
+ // v0.5.0 — Akamai sensor challenge solver
17
+ export { solveAkamaiChallenge, parseAbckState } from './akamai-sensor.js';
18
+ // v0.4.0 — IdentityPool: long-running session and identity rotation
19
+ export { IdentityPool } from './identity-pool.js';
10
20
  export { ProxyPool, ProxyProviders, proxyToUrl } from './proxy-pool.js';
11
21
  export { SnapshotManager } from './snapshot.js';
12
22
  export { attachObservability, JsonlFileExporter, ConsoleExporter, newTraceId, } from './observability.js';
13
23
  // v0.2.0 — stealth diagnostics
14
- export { captureFingerprint, checkIpReputation, testAgainstAkamai, } from './diagnostics.js';
24
+ export { captureFingerprint, checkIpReputation, testAgainstAkamai, testAgainstAntiBot, } from './diagnostics.js';
15
25
  export { ErrorCodes } from './types.js';
16
26
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AACxD,OAAO,EAAE,gBAAgB,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAE1F,OAAO,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AACxD,OAAO,EAAE,sBAAsB,EAAE,MAAM,cAAc,CAAC;AACtD,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AACtC,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAEhD,2EAA2E;AAC3E,OAAO,EACL,eAAe,EACf,WAAW,EACX,gBAAgB,EAChB,iBAAiB,EACjB,cAAc,EACd,mBAAmB,GACpB,MAAM,6BAA6B,CAAC;AAYrC,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAGxE,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAGhD,OAAO,EACL,mBAAmB,EACnB,iBAAiB,EACjB,eAAe,EACf,UAAU,GACX,MAAM,oBAAoB,CAAC;AAG5B,+BAA+B;AAC/B,OAAO,EACL,kBAAkB,EAClB,iBAAiB,EACjB,iBAAiB,GAClB,MAAM,kBAAkB,CAAC;AA4C1B,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AACxD,OAAO,EAAE,gBAAgB,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAE1F,OAAO,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AACxD,OAAO,EAAE,sBAAsB,EAAE,MAAM,cAAc,CAAC;AACtD,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AACtC,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAEhD,2EAA2E;AAC3E,OAAO,EACL,eAAe,EACf,WAAW,EACX,gBAAgB,EAChB,iBAAiB,EACjB,cAAc,EACd,mBAAmB,GACpB,MAAM,6BAA6B,CAAC;AAYrC,sDAAsD;AACtD,OAAO,EACL,oBAAoB,EACpB,oBAAoB,EACpB,yBAAyB,EACzB,UAAU,GACX,MAAM,yBAAyB,CAAC;AAEjC,sDAAsD;AACtD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAGvD,qEAAqE;AACrE,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAGvD,0CAA0C;AAC1C,OAAO,EAAE,oBAAoB,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAG1E,oEAAoE;AACpE,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAQlD,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAGxE,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAGhD,OAAO,EACL,mBAAmB,EACnB,iBAAiB,EACjB,eAAe,EACf,UAAU,GACX,MAAM,oBAAoB,CAAC;AAG5B,+BAA+B;AAC/B,OAAO,EACL,kBAAkB,EAClB,iBAAiB,EACjB,iBAAiB,EACjB,kBAAkB,GACnB,MAAM,kBAAkB,CAAC;AA8C1B,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC"}
@@ -0,0 +1,74 @@
1
+ /**
2
+ * TLS rewriting via CDP Fetch interception.
3
+ *
4
+ * The v0.5.0 answer to "every wire request should present a real Chrome
5
+ * TLS fingerprint, not just the gating ones." Without a TCP-level MITM
6
+ * proxy (and the OS-specific cert installation hell that entails), we
7
+ * use Chrome DevTools Protocol's `Fetch.enable` to pause every HTTP
8
+ * request the browser issues, hand it to the Go `bogdanfinn/tls-client`
9
+ * daemon for upstream execution, and fulfill the response back through
10
+ * CDP. The browser never opens an upstream TCP connection — all its
11
+ * HTTP is fulfilled by us.
12
+ *
13
+ * Patchright/Playwright expose this as `context.route('**', handler)`,
14
+ * which is the high-level wrapper around CDP Fetch. We use the route
15
+ * handler so we don't need to manage CDP sessions ourselves.
16
+ *
17
+ * What this fixes vs the v0.3.0 side-channel (`bt.fetchWithTls`):
18
+ * - The side-channel only handled gating requests the caller made
19
+ * explicitly. Page subresources, XHR, fetch() from page JS, all
20
+ * went through Chrome's own TLS — meaning the host OS's Chrome
21
+ * fingerprint reached the wire. With this rewriter installed, every
22
+ * subresource also goes through Go.
23
+ * - Cross-platform UA spoofing is restored. The daemon controls every
24
+ * header on the wire; spoof to your heart's content.
25
+ *
26
+ * Known limitations:
27
+ * - WebSocket upgrades can't be intercepted by Fetch.enable. They
28
+ * bypass the rewriter and present Chrome's native TLS. The rewriter
29
+ * logs WS leaks for awareness.
30
+ * - Streaming responses are buffered fully. Bad for video, fine for
31
+ * HTML/JSON/typical web pages.
32
+ * - HTTP/3 (QUIC) requests bypass Fetch.enable entirely because Chrome
33
+ * short-circuits them. We launch with `--disable-quic` so this never
34
+ * fires in practice.
35
+ */
36
+ import type { BrowserContext } from 'patchright';
37
+ import type { TlsSideChannel } from './tls-side-channel.js';
38
+ import type { Logger } from './logging.js';
39
+ export interface TlsRewriterOptions {
40
+ /** TLS daemon spawned by `TlsSideChannel.spawn()`. The rewriter does
41
+ * not own its lifecycle — caller is responsible for `close()`. */
42
+ channel: TlsSideChannel;
43
+ logger: Logger;
44
+ /** Hard timeout per request to the daemon. Default 30s. */
45
+ perRequestTimeoutMs?: number;
46
+ /** Profile name passed to the daemon for every request. Defaults to
47
+ * `chrome_133`. Cross-platform spoofing happens by overriding this
48
+ * per-launch (e.g. `chrome_124`) plus the User-Agent header. */
49
+ profile?: string;
50
+ }
51
+ export interface TlsRewriterStats {
52
+ /** Total requests intercepted. */
53
+ intercepted: number;
54
+ /** Requests fulfilled successfully via the daemon. */
55
+ fulfilled: number;
56
+ /** Requests that fell through to `route.continue()` because of an
57
+ * error in the daemon path (e.g. daemon crashed, upstream timeout). */
58
+ fellThrough: number;
59
+ /** WebSocket upgrade requests we saw but couldn't intercept. */
60
+ webSocketLeaks: number;
61
+ /** Average daemon round-trip in ms. */
62
+ avgDurationMs: number;
63
+ }
64
+ /**
65
+ * Install the TLS rewriter on a Playwright BrowserContext. After this
66
+ * call, every HTTP/HTTPS request the browser issues is intercepted and
67
+ * forwarded through the TLS daemon. Returns a `stats()` accessor and an
68
+ * `uninstall()` callback.
69
+ */
70
+ export declare function installTlsRewriter(context: BrowserContext, options: TlsRewriterOptions): Promise<{
71
+ stats: () => TlsRewriterStats;
72
+ uninstall: () => Promise<void>;
73
+ }>;
74
+ //# sourceMappingURL=tls-rewriter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tls-rewriter.d.ts","sourceRoot":"","sources":["../src/tls-rewriter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAuC,MAAM,YAAY,CAAC;AACtF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAmC3C,MAAM,WAAW,kBAAkB;IACjC;uEACmE;IACnE,OAAO,EAAE,cAAc,CAAC;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,2DAA2D;IAC3D,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B;;qEAEiE;IACjE,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,gBAAgB;IAC/B,kCAAkC;IAClC,WAAW,EAAE,MAAM,CAAC;IACpB,sDAAsD;IACtD,SAAS,EAAE,MAAM,CAAC;IAClB;4EACwE;IACxE,WAAW,EAAE,MAAM,CAAC;IACpB,gEAAgE;IAChE,cAAc,EAAE,MAAM,CAAC;IACvB,uCAAuC;IACvC,aAAa,EAAE,MAAM,CAAC;CACvB;AAED;;;;;GAKG;AACH,wBAAsB,kBAAkB,CACtC,OAAO,EAAE,cAAc,EACvB,OAAO,EAAE,kBAAkB,GAC1B,OAAO,CAAC;IACT,KAAK,EAAE,MAAM,gBAAgB,CAAC;IAC9B,SAAS,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAChC,CAAC,CAqID"}
@@ -0,0 +1,203 @@
1
+ /**
2
+ * TLS rewriting via CDP Fetch interception.
3
+ *
4
+ * The v0.5.0 answer to "every wire request should present a real Chrome
5
+ * TLS fingerprint, not just the gating ones." Without a TCP-level MITM
6
+ * proxy (and the OS-specific cert installation hell that entails), we
7
+ * use Chrome DevTools Protocol's `Fetch.enable` to pause every HTTP
8
+ * request the browser issues, hand it to the Go `bogdanfinn/tls-client`
9
+ * daemon for upstream execution, and fulfill the response back through
10
+ * CDP. The browser never opens an upstream TCP connection — all its
11
+ * HTTP is fulfilled by us.
12
+ *
13
+ * Patchright/Playwright expose this as `context.route('**', handler)`,
14
+ * which is the high-level wrapper around CDP Fetch. We use the route
15
+ * handler so we don't need to manage CDP sessions ourselves.
16
+ *
17
+ * What this fixes vs the v0.3.0 side-channel (`bt.fetchWithTls`):
18
+ * - The side-channel only handled gating requests the caller made
19
+ * explicitly. Page subresources, XHR, fetch() from page JS, all
20
+ * went through Chrome's own TLS — meaning the host OS's Chrome
21
+ * fingerprint reached the wire. With this rewriter installed, every
22
+ * subresource also goes through Go.
23
+ * - Cross-platform UA spoofing is restored. The daemon controls every
24
+ * header on the wire; spoof to your heart's content.
25
+ *
26
+ * Known limitations:
27
+ * - WebSocket upgrades can't be intercepted by Fetch.enable. They
28
+ * bypass the rewriter and present Chrome's native TLS. The rewriter
29
+ * logs WS leaks for awareness.
30
+ * - Streaming responses are buffered fully. Bad for video, fine for
31
+ * HTML/JSON/typical web pages.
32
+ * - HTTP/3 (QUIC) requests bypass Fetch.enable entirely because Chrome
33
+ * short-circuits them. We launch with `--disable-quic` so this never
34
+ * fires in practice.
35
+ */
36
+ /**
37
+ * Headers that Chrome's request lifecycle manages itself and that we
38
+ * MUST NOT pass through verbatim — re-sending them through the daemon
39
+ * either breaks the request (Content-Length) or duplicates state
40
+ * (Cookie, which the daemon will set automatically from the upstream's
41
+ * Set-Cookie response, while the browser's own cookie jar handles the
42
+ * reverse direction). The browser cookie jar IS the source of truth;
43
+ * we forward Cookie verbatim and let Set-Cookie come back via fulfill.
44
+ */
45
+ const STRIP_REQUEST_HEADERS = new Set([
46
+ 'host',
47
+ 'content-length',
48
+ 'connection',
49
+ 'keep-alive',
50
+ 'transfer-encoding',
51
+ 'proxy-authorization',
52
+ 'proxy-connection',
53
+ 'upgrade',
54
+ 'expect',
55
+ ]);
56
+ /**
57
+ * Headers Chrome's response lifecycle re-computes and that we should
58
+ * NOT pass back via fulfill — letting them through breaks framing.
59
+ */
60
+ const STRIP_RESPONSE_HEADERS = new Set([
61
+ 'content-length',
62
+ 'content-encoding', // upstream returns gzip; we hand fulfill the decoded body
63
+ 'transfer-encoding',
64
+ 'connection',
65
+ 'keep-alive',
66
+ ]);
67
+ /**
68
+ * Install the TLS rewriter on a Playwright BrowserContext. After this
69
+ * call, every HTTP/HTTPS request the browser issues is intercepted and
70
+ * forwarded through the TLS daemon. Returns a `stats()` accessor and an
71
+ * `uninstall()` callback.
72
+ */
73
+ export async function installTlsRewriter(context, options) {
74
+ const { channel, logger } = options;
75
+ const profile = options.profile ?? 'chrome_133';
76
+ const perRequestTimeoutMs = options.perRequestTimeoutMs ?? 30_000;
77
+ let intercepted = 0;
78
+ let fulfilled = 0;
79
+ let fellThrough = 0;
80
+ let webSocketLeaks = 0;
81
+ let totalDurationMs = 0;
82
+ const handler = async (route, request) => {
83
+ intercepted++;
84
+ const url = request.url();
85
+ const method = request.method();
86
+ // WebSocket upgrades come through `route` but Fetch can't intercept
87
+ // the upgrade itself — Chrome handles WS frames at a layer we can't
88
+ // see from here. Let them pass through and log a warning.
89
+ if (request.isNavigationRequest() && (url.startsWith('ws://') || url.startsWith('wss://'))) {
90
+ webSocketLeaks++;
91
+ logger.warn('TLS rewriter: WebSocket leak — upgrade bypasses the rewriter', { url });
92
+ await route.continue();
93
+ return;
94
+ }
95
+ const upgradeHeader = request.headers()['upgrade'];
96
+ if (upgradeHeader && upgradeHeader.toLowerCase() === 'websocket') {
97
+ webSocketLeaks++;
98
+ logger.warn('TLS rewriter: WebSocket leak — upgrade bypasses the rewriter', { url });
99
+ await route.continue();
100
+ return;
101
+ }
102
+ // Build the daemon request from the browser-side request.
103
+ const reqHeaders = {};
104
+ for (const [key, value] of Object.entries(request.headers())) {
105
+ if (STRIP_REQUEST_HEADERS.has(key.toLowerCase()))
106
+ continue;
107
+ reqHeaders[key] = value;
108
+ }
109
+ const postBuffer = request.postDataBuffer();
110
+ const body = postBuffer ?? undefined;
111
+ try {
112
+ const resp = await Promise.race([
113
+ channel.fetch({
114
+ url,
115
+ method,
116
+ headers: reqHeaders,
117
+ body,
118
+ profile,
119
+ timeoutMs: perRequestTimeoutMs,
120
+ }),
121
+ new Promise((_resolve, reject) => {
122
+ setTimeout(() => reject(new Error(`TLS rewriter: per-request timeout ${perRequestTimeoutMs}ms`)), perRequestTimeoutMs + 1000).unref();
123
+ }),
124
+ ]);
125
+ totalDurationMs += resp.durationMs;
126
+ // Flatten response headers. Multi-valued headers (e.g. Set-Cookie)
127
+ // need special handling: Playwright's fulfill takes a single string
128
+ // per key, but lets you pass an array via the headers parameter
129
+ // since 1.50 — we use the comma-join fallback for older versions.
130
+ // For Set-Cookie specifically, we use the multi-value extension
131
+ // because cookies must not be merged.
132
+ const respHeaders = {};
133
+ for (const [key, values] of Object.entries(resp.headers)) {
134
+ if (STRIP_RESPONSE_HEADERS.has(key.toLowerCase()))
135
+ continue;
136
+ if (values.length === 1) {
137
+ respHeaders[key] = values[0];
138
+ }
139
+ else {
140
+ // For Set-Cookie, joining with comma is wrong (cookies have
141
+ // their own commas in Expires). Playwright's `fulfill` accepts
142
+ // multiValueHeaders via the headers field as Record<string, string>
143
+ // by joining with `\n` for some headers. Safest fallback: pass
144
+ // each Set-Cookie as a separate header by using the array form
145
+ // if available, otherwise the last cookie wins.
146
+ //
147
+ // Since we can't pass arrays directly to Playwright's fulfill
148
+ // headers, we encode the multi-value as `\n`-separated for
149
+ // Set-Cookie (Chrome accepts this) and comma-join for everything
150
+ // else.
151
+ if (key.toLowerCase() === 'set-cookie') {
152
+ respHeaders[key] = values.join('\n');
153
+ }
154
+ else {
155
+ respHeaders[key] = values.join(', ');
156
+ }
157
+ }
158
+ }
159
+ await route.fulfill({
160
+ status: resp.status,
161
+ headers: respHeaders,
162
+ body: resp.bodyBuffer,
163
+ });
164
+ fulfilled++;
165
+ }
166
+ catch (err) {
167
+ fellThrough++;
168
+ logger.warn('TLS rewriter: daemon path failed, falling through to native fetch', {
169
+ url,
170
+ error: err instanceof Error ? err.message : String(err),
171
+ });
172
+ // Fall through to the browser's native request. Less stealthy but
173
+ // doesn't break the page.
174
+ try {
175
+ await route.continue();
176
+ }
177
+ catch {
178
+ // Route may already be fulfilled/aborted in race conditions; ignore.
179
+ }
180
+ }
181
+ };
182
+ // Install the route handler for all URLs. Patchright/Playwright accept
183
+ // a glob ('**/*') or RegExp; we use the glob for clarity.
184
+ await context.route('**/*', handler);
185
+ return {
186
+ stats: () => ({
187
+ intercepted,
188
+ fulfilled,
189
+ fellThrough,
190
+ webSocketLeaks,
191
+ avgDurationMs: fulfilled > 0 ? Math.round(totalDurationMs / fulfilled) : 0,
192
+ }),
193
+ uninstall: async () => {
194
+ try {
195
+ await context.unroute('**/*', handler);
196
+ }
197
+ catch {
198
+ // Context may be closing; ignore.
199
+ }
200
+ },
201
+ };
202
+ }
203
+ //# sourceMappingURL=tls-rewriter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tls-rewriter.js","sourceRoot":"","sources":["../src/tls-rewriter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,91 @@
1
+ /**
2
+ * TLS side-channel — spawns the Go-based bogdanfinn/tls-client daemon
3
+ * and exposes a `fetchWithTls()` primitive that performs HTTP requests
4
+ * with a real Chrome TLS ClientHello, real H2 frame settings, and real
5
+ * H2 frame order. Used to make gating requests that the browser can't
6
+ * make through itself, then inject the resulting cookies into the
7
+ * BlackTip browser session.
8
+ *
9
+ * This is the v0.3.0 answer to "an edge gates the very first request
10
+ * before BlackTip's browser even has a session." Use it as follows:
11
+ *
12
+ * const channel = await TlsSideChannel.spawn();
13
+ * const resp = await channel.fetch('https://protected.example.com/');
14
+ * await bt.setCookies(resp.cookies.map(c => ({ name: c.name, value: c.value, domain: c.domain, path: c.path })));
15
+ * await bt.navigate('https://protected.example.com/');
16
+ * // ... browser session now has the cookies the gating request earned
17
+ * await channel.close();
18
+ *
19
+ * The daemon binary lives in `native/tls-client/blacktip-tls` (Linux/macOS)
20
+ * or `native/tls-client/blacktip-tls.exe` (Windows). Build it once with
21
+ * `cd native/tls-client && go build -o blacktip-tls .` — Go is the only
22
+ * build dependency, and you can grab it from https://go.dev/dl/.
23
+ *
24
+ * The daemon stays alive across many requests so we don't pay subprocess
25
+ * startup cost per call. It uses a newline-delimited JSON wire protocol
26
+ * with per-request IDs, so multiple `fetch()` calls can be in flight
27
+ * concurrently without interleaving issues.
28
+ */
29
+ export interface TlsRequest {
30
+ url: string;
31
+ method?: string;
32
+ headers?: Record<string, string>;
33
+ /** Request body as a UTF-8 string OR raw Buffer. Buffer is required for
34
+ * binary uploads (multipart, octet-stream); string is fine for form
35
+ * bodies and JSON. Encoded as base64 on the wire. */
36
+ body?: string | Buffer;
37
+ timeoutMs?: number;
38
+ /** Chrome / Firefox / Safari profile name; defaults to chrome_133. */
39
+ profile?: string;
40
+ }
41
+ export interface TlsResponse {
42
+ status: number;
43
+ /** Headers from the upstream response. Multi-valued — Set-Cookie commonly
44
+ * has multiple entries. Header keys preserve the casing the upstream sent. */
45
+ headers: Record<string, string[]>;
46
+ /** Response body as a UTF-8 string. May be garbage for binary content;
47
+ * use `bodyBuffer` for that. Kept as the primary body field for callers
48
+ * that just want JSON / HTML. */
49
+ body: string;
50
+ /** Response body as raw bytes. Use this when the upstream returns binary
51
+ * data (images, fonts, video, anything non-UTF-8). The TLS rewriting
52
+ * route handler always uses this so subresources don't get mangled. */
53
+ bodyBuffer: Buffer;
54
+ finalUrl: string;
55
+ durationMs: number;
56
+ /** Cookies parsed from `Set-Cookie` headers, ready to inject via `bt.setCookies()`. */
57
+ cookies: ParsedCookie[];
58
+ }
59
+ export interface ParsedCookie {
60
+ name: string;
61
+ value: string;
62
+ domain: string;
63
+ path: string;
64
+ httpOnly: boolean;
65
+ secure: boolean;
66
+ sameSite?: 'Strict' | 'Lax' | 'None';
67
+ expires?: number;
68
+ }
69
+ export declare class TlsSideChannel {
70
+ private proc;
71
+ private rl;
72
+ private pending;
73
+ private nextId;
74
+ private closed;
75
+ private constructor();
76
+ /**
77
+ * Spawn the daemon. Throws if the binary isn't built or can't start.
78
+ * The daemon stays alive until you call `close()`.
79
+ */
80
+ static spawn(): Promise<TlsSideChannel>;
81
+ private handleLine;
82
+ /**
83
+ * Perform a single TLS-impersonated request. Multiple `fetch()` calls
84
+ * can be in flight concurrently — the daemon handles each in its own
85
+ * goroutine and matches responses by id.
86
+ */
87
+ fetch(req: TlsRequest): Promise<TlsResponse>;
88
+ /** Shut down the daemon and clean up the subprocess. */
89
+ close(): Promise<void>;
90
+ }
91
+ //# sourceMappingURL=tls-side-channel.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tls-side-channel.d.ts","sourceRoot":"","sources":["../src/tls-side-channel.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAUH,MAAM,WAAW,UAAU;IACzB,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC;;0DAEsD;IACtD,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,sEAAsE;IACtE,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf;mFAC+E;IAC/E,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;IAClC;;sCAEkC;IAClC,IAAI,EAAE,MAAM,CAAC;IACb;;4EAEwE;IACxE,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,uFAAuF;IACvF,OAAO,EAAE,YAAY,EAAE,CAAC;CACzB;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,OAAO,CAAC;IAClB,MAAM,EAAE,OAAO,CAAC;IAChB,QAAQ,CAAC,EAAE,QAAQ,GAAG,KAAK,GAAG,MAAM,CAAC;IACrC,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAoGD,qBAAa,cAAc;IACzB,OAAO,CAAC,IAAI,CAAiC;IAC7C,OAAO,CAAC,EAAE,CAAoB;IAC9B,OAAO,CAAC,OAAO,CAAqC;IACpD,OAAO,CAAC,MAAM,CAAK;IACnB,OAAO,CAAC,MAAM,CAAS;IAEvB,OAAO;IAYP;;;OAGG;WACU,KAAK,IAAI,OAAO,CAAC,cAAc,CAAC;IAU7C,OAAO,CAAC,UAAU;IAgDlB;;;;OAIG;IACG,KAAK,CAAC,GAAG,EAAE,UAAU,GAAG,OAAO,CAAC,WAAW,CAAC;IA4BlD,wDAAwD;IAClD,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAc7B"}