clearcote 0.1.2 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -48,10 +48,28 @@ const browser = await launch({
48
48
  fingerprint: "user-7423",
49
49
  proxy: { server: "http://host:8080", username: "u", password: "p" }, // standard Playwright option
50
50
  timezone: "America/New_York",
51
- webrtcIp: "203.0.113.10", // make WebRTC report the proxy egress IP
51
+ webrtcIp: "203.0.113.10", // make WebRTC report the proxy egress IP, not your host's
52
52
  });
53
53
  ```
54
54
 
55
+ **WebRTC won't leak your real IP.** The engine *fabricates* the WebRTC server-reflexive (`srflx`) candidate at `webrtcIp` and sends **no real STUN** from your host — so WebRTC reports the proxy IP and your real IP never leaks at the packet level. A plain candidate "relabel" doesn't stop the leak (the real STUN packet still goes out from your host); Clearcote sends none. Raw host candidates are suppressed, and the candidate set stays coherent (not empty/disabled).
56
+
57
+ ### Auto geo-match (`geoip`)
58
+
59
+ Set `geoip: true` and Clearcote resolves the **proxy's exit IP** (looked up *through* the proxy) and auto-fills any unset `timezone`, `acceptLanguage`, `location`, **and `webrtcIp`** so the whole identity — clock, language, geo, and WebRTC IP — matches the proxy's region:
60
+
61
+ ```ts
62
+ const browser = await launch({
63
+ fingerprint: "user-7423",
64
+ proxy: { server: "http://host:8080", username: "u", password: "p" },
65
+ geoip: true, // timezone, languages, location, AND WebRTC IP all auto-set to the proxy's geo
66
+ });
67
+ ```
68
+
69
+ Anything you set explicitly wins over `geoip`. With no proxy it uses your direct connection's IP. The lookup needs an **http(s) proxy** — SOCKS proxies are skipped (set `timezone`/`acceptLanguage` yourself).
70
+
71
+ Geo data comes from the offline [geoip-all-in-one](https://github.com/daijro/geoip-all-in-one) MaxMind database (downloaded + cached on first use; GPL-3.0 data, the same source Camoufox uses) — more accurate than a single online API — with `ip-api.com` as a fallback.
72
+
55
73
  ### Persistent profile
56
74
 
57
75
  ```ts
@@ -80,8 +98,10 @@ All optional. Anything not listed here is passed straight through to Playwright
80
98
  | `hardwareConcurrency` | `--fingerprint-hardware-concurrency` | `navigator.hardwareConcurrency`. |
81
99
  | `location` | `--fingerprint-location` | `"lat,lng"` (only when geo permission is granted). |
82
100
  | `timezone` | `--timezone` | IANA timezone, e.g. `America/New_York`. |
83
- | `webrtcIp` | `--webrtc-ip` | WebRTC egress IP to report (your proxy IP). |
101
+ | `acceptLanguage` | `--accept-lang` | `navigator.languages` + `Accept-Language` header, e.g. `en-US,en`. |
102
+ | `webrtcIp` | `--webrtc-ip` | WebRTC IP to report. The engine **fabricates** the `srflx` candidate at this IP and sends **no real STUN** from the host, so the real IP never leaks (not merely relabeled). |
84
103
  | `disableGpuFingerprint` | `--disable-gpu-fingerprint` | Turn off GPU/WebGL spoofing. |
104
+ | `geoip` | _(directive)_ | `true` → resolve the proxy's exit-IP geo and auto-fill timezone/acceptLanguage/location/**webrtcIp**. |
85
105
 
86
106
  ## API
87
107
 
@@ -23,6 +23,12 @@ export interface FingerprintOptions {
23
23
  location?: string;
24
24
  /** IANA timezone, e.g. "America/New_York". */
25
25
  timezone?: string;
26
+ /**
27
+ * Accept-Language / navigator.languages, e.g. "en-US,en". Sets BOTH the server-side
28
+ * Accept-Language header and navigator.language(s) coherently (Chromium `--accept-lang`).
29
+ * Set this to match the timezone/proxy region — or let `geoip` fill it automatically.
30
+ */
31
+ acceptLanguage?: string;
26
32
  /** WebRTC egress IP to report (typically your proxy's public IP). */
27
33
  webrtcIp?: string;
28
34
  /** Turn OFF GPU/WebGL fingerprint spoofing (advertise the real backend). */
@@ -33,6 +39,10 @@ export declare function splitFingerprintOptions<T extends FingerprintOptions>(op
33
39
  fingerprint: FingerprintOptions;
34
40
  rest: Omit<T, keyof FingerprintOptions>;
35
41
  };
42
+ /** Normalize an Accept-Language value for Chromium's `--accept-lang`: a plain comma-separated
43
+ * tag list with NO `;q=` weights or spaces (Chromium adds the q-weights to the header itself; a
44
+ * `;` in the switch value trips a DCHECK and crashes the renderer). */
45
+ export declare function cleanAcceptLanguage(v: string): string;
36
46
  /** Build the Chromium switches for a set of fingerprint options. */
37
47
  export declare function fingerprintArgs(o: FingerprintOptions): string[];
38
48
  //# sourceMappingURL=fingerprint.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"fingerprint.d.ts","sourceRoot":"","sources":["../src/fingerprint.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,kBAAkB;IACjC;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC9B,6DAA6D;IAC7D,QAAQ,CAAC,EAAE,SAAS,GAAG,OAAO,GAAG,OAAO,CAAC;IACzC,qDAAqD;IACrD,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,oCAAoC;IACpC,KAAK,CAAC,EAAE,QAAQ,GAAG,MAAM,GAAG,OAAO,GAAG,SAAS,GAAG,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC;IAChE,qBAAqB;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,oCAAoC;IACpC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,sCAAsC;IACtC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,qCAAqC;IACrC,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,oFAAoF;IACpF,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,8CAA8C;IAC9C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,qEAAqE;IACrE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,4EAA4E;IAC5E,qBAAqB,CAAC,EAAE,OAAO,CAAC;CACjC;AAiBD,6FAA6F;AAC7F,wBAAgB,uBAAuB,CAAC,CAAC,SAAS,kBAAkB,EAClE,OAAO,EAAE,CAAC,GACT;IAAE,WAAW,EAAE,kBAAkB,CAAC;IAAC,IAAI,EAAE,IAAI,CAAC,CAAC,EAAE,MAAM,kBAAkB,CAAC,CAAA;CAAE,CAW9E;AAED,oEAAoE;AACpE,wBAAgB,eAAe,CAAC,CAAC,EAAE,kBAAkB,GAAG,MAAM,EAAE,CAoB/D"}
1
+ {"version":3,"file":"fingerprint.d.ts","sourceRoot":"","sources":["../src/fingerprint.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,kBAAkB;IACjC;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC9B,6DAA6D;IAC7D,QAAQ,CAAC,EAAE,SAAS,GAAG,OAAO,GAAG,OAAO,CAAC;IACzC,qDAAqD;IACrD,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,oCAAoC;IACpC,KAAK,CAAC,EAAE,QAAQ,GAAG,MAAM,GAAG,OAAO,GAAG,SAAS,GAAG,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC;IAChE,qBAAqB;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,oCAAoC;IACpC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,sCAAsC;IACtC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,qCAAqC;IACrC,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,oFAAoF;IACpF,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,8CAA8C;IAC9C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;;OAIG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,qEAAqE;IACrE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,4EAA4E;IAC5E,qBAAqB,CAAC,EAAE,OAAO,CAAC;CACjC;AAkBD,6FAA6F;AAC7F,wBAAgB,uBAAuB,CAAC,CAAC,SAAS,kBAAkB,EAClE,OAAO,EAAE,CAAC,GACT;IAAE,WAAW,EAAE,kBAAkB,CAAC;IAAC,IAAI,EAAE,IAAI,CAAC,CAAC,EAAE,MAAM,kBAAkB,CAAC,CAAA;CAAE,CAW9E;AAED;;uEAEuE;AACvE,wBAAgB,mBAAmB,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAMrD;AAED,oEAAoE;AACpE,wBAAgB,eAAe,CAAC,CAAC,EAAE,kBAAkB,GAAG,MAAM,EAAE,CAqB/D"}
@@ -11,6 +11,7 @@ const FINGERPRINT_KEYS = [
11
11
  "hardwareConcurrency",
12
12
  "location",
13
13
  "timezone",
14
+ "acceptLanguage",
14
15
  "webrtcIp",
15
16
  "disableGpuFingerprint",
16
17
  ];
@@ -28,6 +29,16 @@ export function splitFingerprintOptions(options) {
28
29
  }
29
30
  return { fingerprint, rest: rest };
30
31
  }
32
+ /** Normalize an Accept-Language value for Chromium's `--accept-lang`: a plain comma-separated
33
+ * tag list with NO `;q=` weights or spaces (Chromium adds the q-weights to the header itself; a
34
+ * `;` in the switch value trips a DCHECK and crashes the renderer). */
35
+ export function cleanAcceptLanguage(v) {
36
+ return String(v)
37
+ .split(",")
38
+ .map((t) => t.split(";")[0].trim())
39
+ .filter(Boolean)
40
+ .join(",");
41
+ }
31
42
  /** Build the Chromium switches for a set of fingerprint options. */
32
43
  export function fingerprintArgs(o) {
33
44
  const args = [];
@@ -46,6 +57,8 @@ export function fingerprintArgs(o) {
46
57
  set("fingerprint-hardware-concurrency", o.hardwareConcurrency);
47
58
  set("fingerprint-location", o.location);
48
59
  set("timezone", o.timezone);
60
+ if (o.acceptLanguage)
61
+ args.push(`--accept-lang=${cleanAcceptLanguage(String(o.acceptLanguage))}`);
49
62
  set("webrtc-ip", o.webrtcIp);
50
63
  if (o.disableGpuFingerprint)
51
64
  args.push("--disable-gpu-fingerprint");
@@ -1 +1 @@
1
- {"version":3,"file":"fingerprint.js","sourceRoot":"","sources":["../src/fingerprint.ts"],"names":[],"mappings":"AAAA,sFAAsF;AACtF,+GAA+G;AAiC/G,MAAM,gBAAgB,GAAiC;IACrD,aAAa;IACb,UAAU;IACV,iBAAiB;IACjB,OAAO;IACP,cAAc;IACd,WAAW;IACX,aAAa;IACb,qBAAqB;IACrB,UAAU;IACV,UAAU;IACV,UAAU;IACV,uBAAuB;CACxB,CAAC;AAEF,6FAA6F;AAC7F,MAAM,UAAU,uBAAuB,CACrC,OAAU;IAEV,MAAM,WAAW,GAAuB,EAAE,CAAC;IAC3C,MAAM,IAAI,GAA4B,EAAE,CAAC;IACzC,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;QAC7C,IAAK,gBAA6B,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC;YAC9C,WAAuC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;QAClD,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;QACd,CAAC;IACH,CAAC;IACD,OAAO,EAAE,WAAW,EAAE,IAAI,EAAE,IAAyC,EAAE,CAAC;AAC1E,CAAC;AAED,oEAAoE;AACpE,MAAM,UAAU,eAAe,CAAC,CAAqB;IACnD,MAAM,IAAI,GAAa,EAAE,CAAC;IAC1B,MAAM,GAAG,GAAG,CAAC,IAAY,EAAE,KAAc,EAAE,EAAE;QAC3C,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,EAAE,EAAE,CAAC;YAC1D,IAAI,CAAC,IAAI,CAAC,KAAK,IAAI,IAAI,KAAK,EAAE,CAAC,CAAC;QAClC,CAAC;IACH,CAAC,CAAC;IACF,GAAG,CAAC,aAAa,EAAE,CAAC,CAAC,WAAW,CAAC,CAAC;IAClC,GAAG,CAAC,sBAAsB,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC;IACxC,GAAG,CAAC,8BAA8B,EAAE,CAAC,CAAC,eAAe,CAAC,CAAC;IACvD,GAAG,CAAC,mBAAmB,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC;IAClC,GAAG,CAAC,2BAA2B,EAAE,CAAC,CAAC,YAAY,CAAC,CAAC;IACjD,GAAG,CAAC,wBAAwB,EAAE,CAAC,CAAC,SAAS,CAAC,CAAC;IAC3C,GAAG,CAAC,0BAA0B,EAAE,CAAC,CAAC,WAAW,CAAC,CAAC;IAC/C,GAAG,CAAC,kCAAkC,EAAE,CAAC,CAAC,mBAAmB,CAAC,CAAC;IAC/D,GAAG,CAAC,sBAAsB,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC;IACxC,GAAG,CAAC,UAAU,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC;IAC5B,GAAG,CAAC,WAAW,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC;IAC7B,IAAI,CAAC,CAAC,qBAAqB;QAAE,IAAI,CAAC,IAAI,CAAC,2BAA2B,CAAC,CAAC;IACpE,OAAO,IAAI,CAAC;AACd,CAAC"}
1
+ {"version":3,"file":"fingerprint.js","sourceRoot":"","sources":["../src/fingerprint.ts"],"names":[],"mappings":"AAAA,sFAAsF;AACtF,+GAA+G;AAuC/G,MAAM,gBAAgB,GAAiC;IACrD,aAAa;IACb,UAAU;IACV,iBAAiB;IACjB,OAAO;IACP,cAAc;IACd,WAAW;IACX,aAAa;IACb,qBAAqB;IACrB,UAAU;IACV,UAAU;IACV,gBAAgB;IAChB,UAAU;IACV,uBAAuB;CACxB,CAAC;AAEF,6FAA6F;AAC7F,MAAM,UAAU,uBAAuB,CACrC,OAAU;IAEV,MAAM,WAAW,GAAuB,EAAE,CAAC;IAC3C,MAAM,IAAI,GAA4B,EAAE,CAAC;IACzC,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;QAC7C,IAAK,gBAA6B,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC;YAC9C,WAAuC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;QAClD,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;QACd,CAAC;IACH,CAAC;IACD,OAAO,EAAE,WAAW,EAAE,IAAI,EAAE,IAAyC,EAAE,CAAC;AAC1E,CAAC;AAED;;uEAEuE;AACvE,MAAM,UAAU,mBAAmB,CAAC,CAAS;IAC3C,OAAO,MAAM,CAAC,CAAC,CAAC;SACb,KAAK,CAAC,GAAG,CAAC;SACV,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;SAClC,MAAM,CAAC,OAAO,CAAC;SACf,IAAI,CAAC,GAAG,CAAC,CAAC;AACf,CAAC;AAED,oEAAoE;AACpE,MAAM,UAAU,eAAe,CAAC,CAAqB;IACnD,MAAM,IAAI,GAAa,EAAE,CAAC;IAC1B,MAAM,GAAG,GAAG,CAAC,IAAY,EAAE,KAAc,EAAE,EAAE;QAC3C,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,EAAE,EAAE,CAAC;YAC1D,IAAI,CAAC,IAAI,CAAC,KAAK,IAAI,IAAI,KAAK,EAAE,CAAC,CAAC;QAClC,CAAC;IACH,CAAC,CAAC;IACF,GAAG,CAAC,aAAa,EAAE,CAAC,CAAC,WAAW,CAAC,CAAC;IAClC,GAAG,CAAC,sBAAsB,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC;IACxC,GAAG,CAAC,8BAA8B,EAAE,CAAC,CAAC,eAAe,CAAC,CAAC;IACvD,GAAG,CAAC,mBAAmB,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC;IAClC,GAAG,CAAC,2BAA2B,EAAE,CAAC,CAAC,YAAY,CAAC,CAAC;IACjD,GAAG,CAAC,wBAAwB,EAAE,CAAC,CAAC,SAAS,CAAC,CAAC;IAC3C,GAAG,CAAC,0BAA0B,EAAE,CAAC,CAAC,WAAW,CAAC,CAAC;IAC/C,GAAG,CAAC,kCAAkC,EAAE,CAAC,CAAC,mBAAmB,CAAC,CAAC;IAC/D,GAAG,CAAC,sBAAsB,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC;IACxC,GAAG,CAAC,UAAU,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC;IAC5B,IAAI,CAAC,CAAC,cAAc;QAAE,IAAI,CAAC,IAAI,CAAC,iBAAiB,mBAAmB,CAAC,MAAM,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,EAAE,CAAC,CAAC;IAClG,GAAG,CAAC,WAAW,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC;IAC7B,IAAI,CAAC,CAAC,qBAAqB;QAAE,IAAI,CAAC,IAAI,CAAC,2BAA2B,CAAC,CAAC;IACpE,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -0,0 +1,20 @@
1
+ export interface Geo {
2
+ ip?: string;
3
+ country?: string;
4
+ timezone?: string;
5
+ acceptLanguage?: string;
6
+ location?: string;
7
+ }
8
+ /**
9
+ * Resolve geo for the egress (through `proxy` if given, else direct). Never throws — returns null
10
+ * on failure. Uses the geoip-all-in-one offline DB first, ip-api.com as a fallback.
11
+ */
12
+ export declare function resolveGeo(proxy?: {
13
+ server?: string;
14
+ username?: string;
15
+ password?: string;
16
+ }, opts?: {
17
+ quiet?: boolean;
18
+ }): Promise<Geo | null>;
19
+ export declare function acceptLanguageForCountry(cc?: string): string;
20
+ //# sourceMappingURL=geoip.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"geoip.d.ts","sourceRoot":"","sources":["../src/geoip.ts"],"names":[],"mappings":"AAyBA,MAAM,WAAW,GAAG;IAClB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAiLD;;;GAGG;AACH,wBAAsB,UAAU,CAC9B,KAAK,CAAC,EAAE;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,EACjE,IAAI,GAAE;IAAE,KAAK,CAAC,EAAE,OAAO,CAAA;CAAO,GAC7B,OAAO,CAAC,GAAG,GAAG,IAAI,CAAC,CAWrB;AAqBD,wBAAgB,wBAAwB,CAAC,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAG5D"}
package/dist/geoip.js ADDED
@@ -0,0 +1,252 @@
1
+ // geoip: resolve the egress IP's geo (timezone + lat/lon + language) so the browser matches the
2
+ // proxy actually in use — the way Camoufox does it. Primary source is daijro's offline
3
+ // "geoip-all-in-one" MaxMind DB (more accurate than a single online API; merges IP2Location +
4
+ // GeoLite2 + DB-IP, timezone computed from coordinates). Flow: discover the exit IP via a small
5
+ // IP-echo *through the proxy*, then look that IP up in the cached .mmdb. Falls back to ip-api.com
6
+ // (direct geo through the proxy) if the DB can't be fetched/opened.
7
+ //
8
+ // The .mmdb (GPL-3.0 data) is downloaded + cached on first use (≈52 MB zip → ≈120 MB), NOT bundled.
9
+ // http(s) proxies only for the lookup; SOCKS is skipped (we never fall back to the local IP under a
10
+ // proxy, which would give the wrong region).
11
+ import http from "node:http";
12
+ import { createWriteStream, existsSync, mkdirSync, readdirSync, rmSync, statSync } from "node:fs";
13
+ import os from "node:os";
14
+ import path from "node:path";
15
+ import { Readable } from "node:stream";
16
+ import { pipeline } from "node:stream/promises";
17
+ import extract from "extract-zip";
18
+ import maxmind from "maxmind";
19
+ const MMDB_URL = "https://github.com/daijro/geoip-all-in-one/releases/latest/download/geoip-aio-all.mmdb.zip";
20
+ const MMDB_MAX_AGE_DAYS = 30;
21
+ const IPECHO_URLS = ["http://api.ipify.org", "http://ip-api.com/line/?fields=query"];
22
+ const IPAPI_URL = "http://ip-api.com/json/?fields=status,message,countryCode,timezone,lat,lon,query";
23
+ function log(quiet, m) {
24
+ if (!quiet)
25
+ process.stderr.write(`[clearcote] ${m}\n`);
26
+ }
27
+ function geoCacheRoot() {
28
+ if (process.env.CLEARCOTE_CACHE)
29
+ return path.join(process.env.CLEARCOTE_CACHE, "geoip");
30
+ if (process.platform === "win32")
31
+ return path.join(process.env.LOCALAPPDATA || path.join(os.homedir(), "AppData", "Local"), "clearcote", "geoip");
32
+ if (process.platform === "darwin")
33
+ return path.join(os.homedir(), "Library", "Caches", "clearcote", "geoip");
34
+ return path.join(process.env.XDG_CACHE_HOME || path.join(os.homedir(), ".cache"), "clearcote", "geoip");
35
+ }
36
+ function proxyUrl(proxy) {
37
+ if (!proxy?.server)
38
+ return null;
39
+ let server = proxy.server;
40
+ if (!/:\/\//.test(server))
41
+ server = "http://" + server;
42
+ if (proxy.username) {
43
+ const u = new URL(server);
44
+ u.username = encodeURIComponent(proxy.username);
45
+ if (proxy.password)
46
+ u.password = encodeURIComponent(proxy.password);
47
+ return u.toString();
48
+ }
49
+ return server;
50
+ }
51
+ function isSocks(proxy) {
52
+ return !!proxy?.server && /^socks/i.test(proxy.server);
53
+ }
54
+ // GET an http:// URL, optionally through an http proxy (absolute-form request target). Text body.
55
+ function httpGetText(targetUrl, proxy, timeoutMs) {
56
+ return new Promise((resolve, reject) => {
57
+ const t = new URL(targetUrl);
58
+ let opts;
59
+ if (proxy) {
60
+ const p = new URL(proxy);
61
+ opts = { host: p.hostname, port: p.port || 80, path: targetUrl, timeout: timeoutMs,
62
+ headers: { Host: t.host, "User-Agent": "clearcote-sdk", Accept: "*/*" } };
63
+ if (p.username) {
64
+ const cred = Buffer.from(`${decodeURIComponent(p.username)}:${decodeURIComponent(p.password)}`).toString("base64");
65
+ opts.headers["Proxy-Authorization"] = `Basic ${cred}`;
66
+ }
67
+ }
68
+ else {
69
+ opts = { host: t.hostname, port: t.port || 80, path: t.pathname + t.search, timeout: timeoutMs,
70
+ headers: { Host: t.host, "User-Agent": "clearcote-sdk", Accept: "*/*" } };
71
+ }
72
+ const req = http.request(opts, (res) => {
73
+ let data = "";
74
+ res.setEncoding("utf8");
75
+ res.on("data", (c) => (data += c));
76
+ res.on("end", () => resolve(data.trim()));
77
+ });
78
+ req.on("error", reject);
79
+ req.on("timeout", () => req.destroy(new Error("timed out")));
80
+ req.end();
81
+ });
82
+ }
83
+ const IPV4 = /^(?:\d{1,3}\.){3}\d{1,3}$/;
84
+ const IPV6 = /^[0-9a-f:]+$/i;
85
+ function looksLikeIp(s) {
86
+ return IPV4.test(s) || (s.includes(":") && IPV6.test(s));
87
+ }
88
+ /** Discover the egress IP via an IP-echo through the proxy (or direct). */
89
+ async function exitIp(proxy, quiet) {
90
+ for (const url of IPECHO_URLS) {
91
+ try {
92
+ const ip = (await httpGetText(url, proxy, 8000)).split(/\s+/)[0];
93
+ if (looksLikeIp(ip))
94
+ return ip;
95
+ }
96
+ catch {
97
+ /* try next */
98
+ }
99
+ }
100
+ log(quiet, "geoip: could not determine the exit IP");
101
+ return null;
102
+ }
103
+ let _mmdbInflight = null;
104
+ async function ensureMmdb(quiet) {
105
+ const dir = geoCacheRoot();
106
+ const file = path.join(dir, "geoip-aio-all.mmdb");
107
+ if (existsSync(file)) {
108
+ const ageDays = (Date.now() - statSync(file).mtimeMs) / 86_400_000;
109
+ if (ageDays < MMDB_MAX_AGE_DAYS)
110
+ return file;
111
+ }
112
+ if (_mmdbInflight)
113
+ return _mmdbInflight;
114
+ _mmdbInflight = (async () => {
115
+ try {
116
+ mkdirSync(dir, { recursive: true });
117
+ const zip = path.join(dir, "geoip-aio-all.mmdb.zip");
118
+ log(quiet, "geoip: downloading the geoip-all-in-one database (~52 MB, first run only)");
119
+ const res = await fetch(MMDB_URL, { redirect: "follow" });
120
+ if (!res.ok || !res.body)
121
+ throw new Error(`HTTP ${res.status}`);
122
+ await pipeline(Readable.fromWeb(res.body), createWriteStream(zip));
123
+ const tmp = path.join(dir, ".extract");
124
+ rmSync(tmp, { recursive: true, force: true });
125
+ await extract(zip, { dir: tmp });
126
+ const found = findMmdb(tmp);
127
+ if (!found)
128
+ throw new Error("no .mmdb in archive");
129
+ rmSync(file, { force: true });
130
+ // move (rename across same dir)
131
+ const fs = await import("node:fs");
132
+ fs.renameSync(found, file);
133
+ rmSync(zip, { force: true });
134
+ rmSync(tmp, { recursive: true, force: true });
135
+ log(quiet, "geoip: database ready");
136
+ return file;
137
+ }
138
+ catch (e) {
139
+ log(quiet, `geoip: database fetch failed (${e.message}) — falling back to ip-api`);
140
+ return null;
141
+ }
142
+ finally {
143
+ _mmdbInflight = null;
144
+ }
145
+ })();
146
+ return _mmdbInflight;
147
+ }
148
+ function findMmdb(dir) {
149
+ const stack = [dir];
150
+ while (stack.length) {
151
+ const cur = stack.pop();
152
+ for (const e of readdirSync(cur, { withFileTypes: true })) {
153
+ const full = path.join(cur, e.name);
154
+ if (e.isDirectory())
155
+ stack.push(full);
156
+ else if (e.name.toLowerCase().endsWith(".mmdb"))
157
+ return full;
158
+ }
159
+ }
160
+ return null;
161
+ }
162
+ let _reader = null;
163
+ async function mmdbLookup(ip, quiet) {
164
+ const file = await ensureMmdb(quiet);
165
+ if (!file)
166
+ return null;
167
+ try {
168
+ if (!_reader)
169
+ _reader = await maxmind.open(file);
170
+ const rec = _reader.get(ip);
171
+ if (!rec)
172
+ return null;
173
+ const country = rec?.country?.iso_code;
174
+ const lat = rec?.location?.latitude;
175
+ const lon = rec?.location?.longitude;
176
+ const tz = rec?.location?.time_zone;
177
+ if (!tz && lat == null)
178
+ return null;
179
+ return {
180
+ ip,
181
+ country,
182
+ timezone: tz,
183
+ acceptLanguage: acceptLanguageForCountry(country),
184
+ location: lat != null && lon != null ? `${lat},${lon}` : undefined,
185
+ };
186
+ }
187
+ catch (e) {
188
+ log(quiet, `geoip: mmdb read failed (${e.message})`);
189
+ return null;
190
+ }
191
+ }
192
+ // Fallback: ip-api.com returns geo directly (through the proxy), no DB needed.
193
+ async function ipApiFallback(proxy, quiet) {
194
+ try {
195
+ const txt = await httpGetText(IPAPI_URL, proxy, 8000);
196
+ const j = JSON.parse(txt);
197
+ if (j?.status !== "success")
198
+ return null;
199
+ return {
200
+ ip: j.query,
201
+ country: j.countryCode,
202
+ timezone: j.timezone,
203
+ acceptLanguage: acceptLanguageForCountry(j.countryCode),
204
+ location: j.lat != null && j.lon != null ? `${j.lat},${j.lon}` : undefined,
205
+ };
206
+ }
207
+ catch {
208
+ return null;
209
+ }
210
+ }
211
+ /**
212
+ * Resolve geo for the egress (through `proxy` if given, else direct). Never throws — returns null
213
+ * on failure. Uses the geoip-all-in-one offline DB first, ip-api.com as a fallback.
214
+ */
215
+ export async function resolveGeo(proxy, opts = {}) {
216
+ if (isSocks(proxy)) {
217
+ log(opts.quiet, "geoip: SOCKS proxy can't be used for the geo lookup — set timezone/acceptLanguage explicitly. Skipping.");
218
+ return null;
219
+ }
220
+ const purl = proxyUrl(proxy);
221
+ const ip = await exitIp(purl, opts.quiet);
222
+ let geo = ip ? await mmdbLookup(ip, opts.quiet) : null;
223
+ if (!geo)
224
+ geo = await ipApiFallback(purl, opts.quiet);
225
+ if (geo)
226
+ log(opts.quiet, `geoip: ${geo.ip} -> ${geo.country} tz=${geo.timezone} lang=${geo.acceptLanguage}`);
227
+ return geo;
228
+ }
229
+ // country (ISO-3166 alpha-2) -> Accept-Language. Plain comma list (NO ;q= weights — Chromium's
230
+ // --accept-lang adds those). The geoip DB has no language data, so this maps the resolved country.
231
+ const COUNTRY_LANG = {
232
+ US: "en-US,en", GB: "en-GB,en", CA: "en-CA,en,fr-CA", AU: "en-AU,en", NZ: "en-NZ,en",
233
+ IE: "en-IE,en", IN: "en-IN,en,hi", ZA: "en-ZA,en", SG: "en-SG,en",
234
+ DE: "de-DE,de,en", AT: "de-AT,de,en", CH: "de-CH,de,fr,en",
235
+ FR: "fr-FR,fr,en", BE: "nl-BE,nl,fr,en", NL: "nl-NL,nl,en",
236
+ ES: "es-ES,es,en", MX: "es-MX,es,en", AR: "es-AR,es,en", CL: "es-CL,es,en",
237
+ CO: "es-CO,es,en", PT: "pt-PT,pt,en", BR: "pt-BR,pt,en",
238
+ IT: "it-IT,it,en", PL: "pl-PL,pl,en", RU: "ru-RU,ru,en", UA: "uk-UA,uk,ru,en",
239
+ SE: "sv-SE,sv,en", NO: "nb-NO,no,en", DK: "da-DK,da,en", FI: "fi-FI,fi,en",
240
+ CZ: "cs-CZ,cs,en", RO: "ro-RO,ro,en", HU: "hu-HU,hu,en", GR: "el-GR,el,en",
241
+ TR: "tr-TR,tr,en", IL: "he-IL,he,en", SA: "ar-SA,ar,en", AE: "ar-AE,ar,en",
242
+ EG: "ar-EG,ar,en", JP: "ja-JP,ja,en", KR: "ko-KR,ko,en",
243
+ CN: "zh-CN,zh,en", HK: "zh-HK,zh,en", TW: "zh-TW,zh,en",
244
+ TH: "th-TH,th,en", VN: "vi-VN,vi,en", ID: "id-ID,id,en",
245
+ MY: "ms-MY,ms,en", PH: "en-PH,en,fil",
246
+ };
247
+ export function acceptLanguageForCountry(cc) {
248
+ if (!cc)
249
+ return "en-US,en";
250
+ return COUNTRY_LANG[cc.toUpperCase()] || "en-US,en";
251
+ }
252
+ //# sourceMappingURL=geoip.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"geoip.js","sourceRoot":"","sources":["../src/geoip.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ import type { Browser, BrowserContext, Page } from "playwright-core";
2
+ export interface HumanizeOptions {
3
+ /** Route clicks/moves/scroll through the engine's humanized (bezier, trusted) input. */
4
+ humanize?: boolean;
5
+ /** Show a red cursor dot that tracks the motion (visualization). */
6
+ showCursor?: boolean;
7
+ }
8
+ /** Overlay: a red dot that follows real mousemove events. Idempotent IIFE so it works both as
9
+ * an addInitScript source string AND when passed to page.evaluate (Node treats a bare arrow
10
+ * string as an uncalled expression — an IIFE actually runs). */
11
+ export declare const CURSOR_OVERLAY = "(() => {\n if (window.__clearcoteCursor) return; window.__clearcoteCursor = 1;\n const make = () => {\n if (document.getElementById('__clearcote_cursor')) return;\n const d = document.createElement('div'); d.id = '__clearcote_cursor';\n d.style.cssText = 'position:fixed;left:0;top:0;width:20px;height:20px;margin:-10px 0 0 -10px;' +\n 'border-radius:50%;border:2px solid #ff3b3b;background:rgba(255,59,59,.22);' +\n 'box-shadow:0 0 10px rgba(255,59,59,.6);pointer-events:none;z-index:2147483647';\n (document.body || document.documentElement).appendChild(d);\n };\n if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', make); else make();\n document.addEventListener('mousemove', (e) => {\n const d = document.getElementById('__clearcote_cursor');\n if (d) { d.style.left = e.clientX + 'px'; d.style.top = e.clientY + 'px'; }\n }, true);\n})();";
12
+ /** Wrap a single page's input methods + (optionally) inject the cursor overlay. */
13
+ export declare function attachHumanize(browser: Browser, page: Page, opts: HumanizeOptions): Promise<void>;
14
+ /** Install humanize/showCursor on a browser: wraps newPage/newContext so every page is covered. */
15
+ export declare function installHumanize(browser: Browser, opts: HumanizeOptions): void;
16
+ /** Install humanize/showCursor on a single context (used for launchPersistentContext). */
17
+ export declare function installHumanizeOnContext(context: BrowserContext, opts: HumanizeOptions, browser?: Browser | null): void;
18
+ //# sourceMappingURL=humanize.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"humanize.d.ts","sourceRoot":"","sources":["../src/humanize.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,OAAO,EAAE,cAAc,EAAc,IAAI,EAAE,MAAM,iBAAiB,CAAC;AAEjF,MAAM,WAAW,eAAe;IAC9B,wFAAwF;IACxF,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,oEAAoE;IACpE,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED;;gEAEgE;AAChE,eAAO,MAAM,cAAc,o5BAerB,CAAC;AAUP,mFAAmF;AACnF,wBAAsB,cAAc,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CA0EvG;AAED,mGAAmG;AACnG,wBAAgB,eAAe,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,eAAe,GAAG,IAAI,CAc7E;AAED,0FAA0F;AAC1F,wBAAgB,wBAAwB,CACtC,OAAO,EAAE,cAAc,EAAE,IAAI,EAAE,eAAe,EAAE,OAAO,CAAC,EAAE,OAAO,GAAG,IAAI,GACvE,IAAI,CAQN"}
@@ -0,0 +1,150 @@
1
+ // Humanized input + cursor visualization.
2
+ //
3
+ // `humanize: true` — routes page.click/hover/mouse.move/mouse.click through the engine's
4
+ // `Browser.humanizedClick` CDP command (real trusted WebMouseEvent along a cubic-bezier path,
5
+ // isTrusted===true, navigator.webdriver stays false), and eases mouse.wheel SDK-side.
6
+ // `showCursor: true` — injects a red cursor dot that follows the real mousemove events the engine
7
+ // fires, so you can watch the motion (cross-platform; no native overlay needed).
8
+ //
9
+ // Requires a Clearcote binary that exposes Browser.humanizedClick (the humanized-input engine
10
+ // build). On an older binary the command is absent; humanize falls back to native Playwright input.
11
+ /** Overlay: a red dot that follows real mousemove events. Idempotent IIFE so it works both as
12
+ * an addInitScript source string AND when passed to page.evaluate (Node treats a bare arrow
13
+ * string as an uncalled expression — an IIFE actually runs). */
14
+ export const CURSOR_OVERLAY = `(() => {
15
+ if (window.__clearcoteCursor) return; window.__clearcoteCursor = 1;
16
+ const make = () => {
17
+ if (document.getElementById('__clearcote_cursor')) return;
18
+ const d = document.createElement('div'); d.id = '__clearcote_cursor';
19
+ d.style.cssText = 'position:fixed;left:0;top:0;width:20px;height:20px;margin:-10px 0 0 -10px;' +
20
+ 'border-radius:50%;border:2px solid #ff3b3b;background:rgba(255,59,59,.22);' +
21
+ 'box-shadow:0 0 10px rgba(255,59,59,.6);pointer-events:none;z-index:2147483647';
22
+ (document.body || document.documentElement).appendChild(d);
23
+ };
24
+ if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', make); else make();
25
+ document.addEventListener('mousemove', (e) => {
26
+ const d = document.getElementById('__clearcote_cursor');
27
+ if (d) { d.style.left = e.clientX + 'px'; d.style.top = e.clientY + 'px'; }
28
+ }, true);
29
+ })();`;
30
+ const rand = (a, b) => a + Math.random() * (b - a);
31
+ async function pageTargetId(page) {
32
+ const s = await page.context().newCDPSession(page);
33
+ const info = await s.send("Target.getTargetInfo");
34
+ return info.targetInfo.targetId;
35
+ }
36
+ /** Wrap a single page's input methods + (optionally) inject the cursor overlay. */
37
+ export async function attachHumanize(browser, page, opts) {
38
+ if (opts.showCursor) {
39
+ const inject = () => page.evaluate(CURSOR_OVERLAY).catch(() => { });
40
+ inject();
41
+ page.on("load", () => { inject(); });
42
+ page.on("framenavigated", (f) => { if (f === page.mainFrame())
43
+ inject(); });
44
+ }
45
+ if (!opts.humanize)
46
+ return;
47
+ let bsession = null;
48
+ let tid = null;
49
+ let supported = true;
50
+ const humanizedMove = async (x, y, noClick, duration) => {
51
+ if (!supported)
52
+ return false;
53
+ try {
54
+ bsession ??= await browser.newBrowserCDPSession();
55
+ tid ??= await pageTargetId(page);
56
+ await bsession.send("Browser.humanizedClick", {
57
+ targetId: tid, x: Math.round(x), y: Math.round(y),
58
+ duration: duration ?? rand(0.45, 0.95), noClick,
59
+ });
60
+ return true;
61
+ }
62
+ catch (e) {
63
+ // older binary without the command -> stop trying, fall back to native input
64
+ supported = false;
65
+ return false;
66
+ }
67
+ };
68
+ const mouse = page.mouse;
69
+ const nativeMove = mouse.move.bind(mouse);
70
+ const nativeClick = mouse.click.bind(mouse);
71
+ const nativeWheel = mouse.wheel.bind(mouse);
72
+ mouse.move = async (x, y, options) => {
73
+ if (!(await humanizedMove(x, y, true)))
74
+ return nativeMove(x, y, options);
75
+ };
76
+ mouse.click = async (x, y, options) => {
77
+ if (!(await humanizedMove(x, y, false)))
78
+ return nativeClick(x, y, options);
79
+ };
80
+ // scroll easing (engine humanizedClick doesn't cover wheel): break into eased chunks
81
+ mouse.wheel = async (dx, dy) => {
82
+ const steps = Math.max(5, Math.min(20, Math.round((Math.abs(dx) + Math.abs(dy)) / 80)));
83
+ const ease = (u) => u * u * (3 - 2 * u);
84
+ let px = 0, py = 0;
85
+ for (let i = 1; i <= steps; i++) {
86
+ const f = ease(i / steps);
87
+ const nx = Math.round(dx * f), ny = Math.round(dy * f);
88
+ await nativeWheel(nx - px, ny - py);
89
+ px = nx;
90
+ py = ny;
91
+ await page.waitForTimeout(rand(12, 45));
92
+ }
93
+ if (px !== dx || py !== dy)
94
+ await nativeWheel(dx - px, dy - py);
95
+ };
96
+ const wrapTargeted = (name, noClick) => {
97
+ const orig = page[name].bind(page);
98
+ page[name] = async (selector, options = {}) => {
99
+ try {
100
+ const loc = page.locator(selector).first();
101
+ await loc.scrollIntoViewIfNeeded({ timeout: options.timeout ?? 30000 });
102
+ const box = await loc.boundingBox();
103
+ if (!box)
104
+ return orig(selector, options);
105
+ const x = box.x + box.width * rand(0.3, 0.7);
106
+ const y = box.y + box.height * rand(0.3, 0.7);
107
+ if (await humanizedMove(x, y, noClick))
108
+ return;
109
+ return orig(selector, options);
110
+ }
111
+ catch {
112
+ return orig(selector, options);
113
+ }
114
+ };
115
+ };
116
+ wrapTargeted("click", false);
117
+ wrapTargeted("hover", true);
118
+ }
119
+ /** Install humanize/showCursor on a browser: wraps newPage/newContext so every page is covered. */
120
+ export function installHumanize(browser, opts) {
121
+ if (!opts.humanize && !opts.showCursor)
122
+ return;
123
+ const origNewPage = browser.newPage.bind(browser);
124
+ browser.newPage = async (options) => {
125
+ const page = await origNewPage(options);
126
+ await attachHumanize(browser, page, opts);
127
+ return page;
128
+ };
129
+ const origNewContext = browser.newContext.bind(browser);
130
+ browser.newContext = async (options) => {
131
+ const ctx = await origNewContext(options);
132
+ installHumanizeOnContext(ctx, opts, browser);
133
+ return ctx;
134
+ };
135
+ }
136
+ /** Install humanize/showCursor on a single context (used for launchPersistentContext). */
137
+ export function installHumanizeOnContext(context, opts, browser) {
138
+ if (!opts.humanize && !opts.showCursor)
139
+ return;
140
+ const b = browser ?? context.browser();
141
+ if (opts.showCursor) {
142
+ context.addInitScript(CURSOR_OVERLAY).catch(() => { });
143
+ }
144
+ if (b) {
145
+ context.on("page", (p) => { attachHumanize(b, p, opts).catch(() => { }); });
146
+ for (const p of context.pages())
147
+ attachHumanize(b, p, opts).catch(() => { });
148
+ }
149
+ }
150
+ //# sourceMappingURL=humanize.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"humanize.js","sourceRoot":"","sources":["../src/humanize.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -1,14 +1,22 @@
1
1
  import type { Browser, BrowserContext, BrowserContextOptions, LaunchOptions as PlaywrightLaunchOptions } from "playwright-core";
2
2
  import { type DownloadOptions } from "./download.js";
3
3
  import { type FingerprintOptions } from "./fingerprint.js";
4
+ import { type HumanizeOptions } from "./humanize.js";
4
5
  export type { FingerprintOptions } from "./fingerprint.js";
5
6
  export type { DownloadOptions } from "./download.js";
7
+ export { resolveGeo, type Geo } from "./geoip.js";
8
+ export type { HumanizeOptions } from "./humanize.js";
6
9
  export { RELEASE } from "./release.js";
10
+ /** When true (and a proxy is set), resolve the proxy's exit-IP geo and auto-fill any unset
11
+ * `timezone` + `acceptLanguage` (+ `location`) so they match the proxy region. */
12
+ interface GeoipOption {
13
+ geoip?: boolean;
14
+ }
7
15
  /** Options for {@link launch}: Playwright launch options + Clearcote fingerprint options. */
8
- export interface LaunchOptions extends PlaywrightLaunchOptions, FingerprintOptions {
16
+ export interface LaunchOptions extends PlaywrightLaunchOptions, FingerprintOptions, GeoipOption, HumanizeOptions {
9
17
  }
10
18
  /** Options for {@link launchPersistentContext}. */
11
- export interface PersistentContextOptions extends PlaywrightLaunchOptions, BrowserContextOptions, FingerprintOptions {
19
+ export interface PersistentContextOptions extends PlaywrightLaunchOptions, BrowserContextOptions, FingerprintOptions, GeoipOption, HumanizeOptions {
12
20
  }
13
21
  /**
14
22
  * Resolve the Clearcote chrome.exe path, downloading + verifying it if needed.
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EACV,OAAO,EACP,cAAc,EACd,qBAAqB,EACrB,aAAa,IAAI,uBAAuB,EACzC,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAgB,KAAK,eAAe,EAAE,MAAM,eAAe,CAAC;AACnE,OAAO,EAA4C,KAAK,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAGrG,YAAY,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAC3D,YAAY,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AACrD,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAEvC,6FAA6F;AAC7F,MAAM,WAAW,aAAc,SAAQ,uBAAuB,EAAE,kBAAkB;CAAG;AAErF,mDAAmD;AACnD,MAAM,WAAW,wBACf,SAAQ,uBAAuB,EAC7B,qBAAqB,EACrB,kBAAkB;CAAG;AAYzB;;;GAGG;AACH,wBAAsB,cAAc,CAClC,OAAO,GAAE;IAAE,cAAc,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,eAAoB,GAC1D,OAAO,CAAC,MAAM,CAAC,CAIjB;AAED,iGAAiG;AACjG,wBAAsB,QAAQ,CAAC,OAAO,GAAE,eAAoB,GAAG,OAAO,CAAC,MAAM,CAAC,CAE7E;AAED,yEAAyE;AACzE,wBAAsB,MAAM,CAAC,OAAO,GAAE,aAAkB,GAAG,OAAO,CAAC,OAAO,CAAC,CAU1E;AAED;;;GAGG;AACH,wBAAsB,uBAAuB,CAC3C,WAAW,EAAE,MAAM,EACnB,OAAO,GAAE,wBAA6B,GACrC,OAAO,CAAC,cAAc,CAAC,CAUzB;;;;;;;;AAED,wBAAsF"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EACV,OAAO,EACP,cAAc,EACd,qBAAqB,EACrB,aAAa,IAAI,uBAAuB,EACzC,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAgB,KAAK,eAAe,EAAE,MAAM,eAAe,CAAC;AACnE,OAAO,EAA4C,KAAK,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAErG,OAAO,EAA6C,KAAK,eAAe,EAAE,MAAM,eAAe,CAAC;AAGhG,YAAY,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAC3D,YAAY,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AACrD,OAAO,EAAE,UAAU,EAAE,KAAK,GAAG,EAAE,MAAM,YAAY,CAAC;AAClD,YAAY,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AACrD,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAEvC;kFACkF;AAClF,UAAU,WAAW;IACnB,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED,6FAA6F;AAC7F,MAAM,WAAW,aAAc,SAAQ,uBAAuB,EAAE,kBAAkB,EAAE,WAAW,EAAE,eAAe;CAAG;AAEnH,mDAAmD;AACnD,MAAM,WAAW,wBACf,SAAQ,uBAAuB,EAC7B,qBAAqB,EACrB,kBAAkB,EAClB,WAAW,EACX,eAAe;CAAG;AAwBtB;;;GAGG;AACH,wBAAsB,cAAc,CAClC,OAAO,GAAE;IAAE,cAAc,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,eAAoB,GAC1D,OAAO,CAAC,MAAM,CAAC,CAIjB;AAED,iGAAiG;AACjG,wBAAsB,QAAQ,CAAC,OAAO,GAAE,eAAoB,GAAG,OAAO,CAAC,MAAM,CAAC,CAE7E;AAED,yEAAyE;AACzE,wBAAsB,MAAM,CAAC,OAAO,GAAE,aAAkB,GAAG,OAAO,CAAC,OAAO,CAAC,CAa1E;AAED;;;GAGG;AACH,wBAAsB,uBAAuB,CAC3C,WAAW,EAAE,MAAM,EACnB,OAAO,GAAE,wBAA6B,GACrC,OAAO,CAAC,cAAc,CAAC,CAazB;;;;;;;;AAED,wBAAsF"}
package/dist/index.js CHANGED
@@ -12,8 +12,27 @@
12
12
  import { chromium } from "playwright-core";
13
13
  import { ensureBinary } from "./download.js";
14
14
  import { fingerprintArgs, splitFingerprintOptions } from "./fingerprint.js";
15
+ import { resolveGeo } from "./geoip.js";
16
+ import { installHumanize, installHumanizeOnContext } from "./humanize.js";
15
17
  import { RELEASE } from "./release.js";
18
+ export { resolveGeo } from "./geoip.js";
16
19
  export { RELEASE } from "./release.js";
20
+ /** Fill unset timezone/acceptLanguage/location/webrtcIp on `fp` from the proxy's exit-IP geo. */
21
+ async function applyGeoip(fp, proxy) {
22
+ const geo = await resolveGeo(proxy);
23
+ if (!geo)
24
+ return;
25
+ if (geo.timezone && fp.timezone == null)
26
+ fp.timezone = geo.timezone;
27
+ if (geo.acceptLanguage && fp.acceptLanguage == null)
28
+ fp.acceptLanguage = geo.acceptLanguage;
29
+ if (geo.location && fp.location == null)
30
+ fp.location = geo.location;
31
+ // make WebRTC report the proxy egress IP too, coherent with HTTP egress (engine fabricates
32
+ // the srflx candidate at this IP; no real STUN leaves the host).
33
+ if (geo.ip && fp.webrtcIp == null)
34
+ fp.webrtcIp = geo.ip;
35
+ }
17
36
  function ensureRunnableHere(exe) {
18
37
  if (process.platform !== "win32") {
19
38
  throw new Error(`Clearcote ${RELEASE.version} ships a Windows x64 binary only — it cannot launch on '${process.platform}'.\n` +
@@ -38,30 +57,38 @@ export async function download(options = {}) {
38
57
  }
39
58
  /** Launch Clearcote and return a standard Playwright {@link Browser}. */
40
59
  export async function launch(options = {}) {
41
- const { executablePath: exeOption, args, ...rest } = options;
60
+ const { executablePath: exeOption, args, geoip, humanize, showCursor, ...rest } = options;
42
61
  const { fingerprint, rest: pwOptions } = splitFingerprintOptions(rest);
62
+ if (geoip)
63
+ await applyGeoip(fingerprint, pwOptions.proxy);
43
64
  const exe = await executablePath({ executablePath: exeOption });
44
65
  ensureRunnableHere(exe);
45
- return chromium.launch({
66
+ const browser = await chromium.launch({
46
67
  ...pwOptions,
47
68
  executablePath: exe,
48
69
  args: [...fingerprintArgs(fingerprint), ...(args ?? [])],
49
70
  });
71
+ installHumanize(browser, { humanize, showCursor });
72
+ return browser;
50
73
  }
51
74
  /**
52
75
  * Launch Clearcote with a persistent profile directory and return a Playwright
53
76
  * {@link BrowserContext} (cookies, storage, etc. persist in `userDataDir`).
54
77
  */
55
78
  export async function launchPersistentContext(userDataDir, options = {}) {
56
- const { executablePath: exeOption, args, ...rest } = options;
79
+ const { executablePath: exeOption, args, geoip, humanize, showCursor, ...rest } = options;
57
80
  const { fingerprint, rest: pwOptions } = splitFingerprintOptions(rest);
81
+ if (geoip)
82
+ await applyGeoip(fingerprint, pwOptions.proxy);
58
83
  const exe = await executablePath({ executablePath: exeOption });
59
84
  ensureRunnableHere(exe);
60
- return chromium.launchPersistentContext(userDataDir, {
85
+ const context = await chromium.launchPersistentContext(userDataDir, {
61
86
  ...pwOptions,
62
87
  executablePath: exe,
63
88
  args: [...fingerprintArgs(fingerprint), ...(args ?? [])],
64
89
  });
90
+ installHumanizeOnContext(context, { humanize, showCursor });
91
+ return context;
65
92
  }
66
93
  export default { launch, launchPersistentContext, executablePath, download, RELEASE };
67
94
  //# 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,kCAAkC;AAClC,EAAE;AACF,wCAAwC;AACxC,oFAAoF;AACpF,0CAA0C;AAC1C,iEAAiE;AACjE,EAAE;AACF,4FAA4F;AAC5F,gGAAgG;AAChG,gGAAgG;AAChG,sBAAsB;AAEtB,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAO3C,OAAO,EAAE,YAAY,EAAwB,MAAM,eAAe,CAAC;AACnE,OAAO,EAAE,eAAe,EAAE,uBAAuB,EAA2B,MAAM,kBAAkB,CAAC;AACrG,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAIvC,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAWvC,SAAS,kBAAkB,CAAC,GAAW;IACrC,IAAI,OAAO,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;QACjC,MAAM,IAAI,KAAK,CACb,aAAa,OAAO,CAAC,OAAO,2DAA2D,OAAO,CAAC,QAAQ,MAAM;YAC3G,kEAAkE;YAClE,8DAA8D,GAAG,GAAG,CACvE,CAAC;IACJ,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,UAAyD,EAAE;IAE3D,IAAI,OAAO,CAAC,cAAc;QAAE,OAAO,OAAO,CAAC,cAAc,CAAC;IAC1D,IAAI,OAAO,CAAC,GAAG,CAAC,gBAAgB;QAAE,OAAO,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC;IACtE,OAAO,YAAY,CAAC,EAAE,QAAQ,EAAE,OAAO,CAAC,QAAQ,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC;AAC5E,CAAC;AAED,iGAAiG;AACjG,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,UAA2B,EAAE;IAC1D,OAAO,YAAY,CAAC,OAAO,CAAC,CAAC;AAC/B,CAAC;AAED,yEAAyE;AACzE,MAAM,CAAC,KAAK,UAAU,MAAM,CAAC,UAAyB,EAAE;IACtD,MAAM,EAAE,cAAc,EAAE,SAAS,EAAE,IAAI,EAAE,GAAG,IAAI,EAAE,GAAG,OAAO,CAAC;IAC7D,MAAM,EAAE,WAAW,EAAE,IAAI,EAAE,SAAS,EAAE,GAAG,uBAAuB,CAAC,IAAI,CAAC,CAAC;IACvE,MAAM,GAAG,GAAG,MAAM,cAAc,CAAC,EAAE,cAAc,EAAE,SAAS,EAAE,CAAC,CAAC;IAChE,kBAAkB,CAAC,GAAG,CAAC,CAAC;IACxB,OAAO,QAAQ,CAAC,MAAM,CAAC;QACrB,GAAI,SAAqC;QACzC,cAAc,EAAE,GAAG;QACnB,IAAI,EAAE,CAAC,GAAG,eAAe,CAAC,WAAW,CAAC,EAAE,GAAG,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC;KACzD,CAAC,CAAC;AACL,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAC3C,WAAmB,EACnB,UAAoC,EAAE;IAEtC,MAAM,EAAE,cAAc,EAAE,SAAS,EAAE,IAAI,EAAE,GAAG,IAAI,EAAE,GAAG,OAAO,CAAC;IAC7D,MAAM,EAAE,WAAW,EAAE,IAAI,EAAE,SAAS,EAAE,GAAG,uBAAuB,CAAC,IAAI,CAAC,CAAC;IACvE,MAAM,GAAG,GAAG,MAAM,cAAc,CAAC,EAAE,cAAc,EAAE,SAAS,EAAE,CAAC,CAAC;IAChE,kBAAkB,CAAC,GAAG,CAAC,CAAC;IACxB,OAAO,QAAQ,CAAC,uBAAuB,CAAC,WAAW,EAAE;QACnD,GAAI,SAA6D;QACjE,cAAc,EAAE,GAAG;QACnB,IAAI,EAAE,CAAC,GAAG,eAAe,CAAC,WAAW,CAAC,EAAE,GAAG,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC;KACzD,CAAC,CAAC;AACL,CAAC;AAED,eAAe,EAAE,MAAM,EAAE,uBAAuB,EAAE,cAAc,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,kCAAkC;AAClC,EAAE;AACF,wCAAwC;AACxC,oFAAoF;AACpF,0CAA0C;AAC1C,iEAAiE;AACjE,EAAE;AACF,4FAA4F;AAC5F,gGAAgG;AAChG,gGAAgG;AAChG,sBAAsB;AAEtB,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAO3C,OAAO,EAAE,YAAY,EAAwB,MAAM,eAAe,CAAC;AACnE,OAAO,EAAE,eAAe,EAAE,uBAAuB,EAA2B,MAAM,kBAAkB,CAAC;AACrG,OAAO,EAAE,UAAU,EAAY,MAAM,YAAY,CAAC;AAClD,OAAO,EAAE,eAAe,EAAE,wBAAwB,EAAwB,MAAM,eAAe,CAAC;AAChG,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAIvC,OAAO,EAAE,UAAU,EAAY,MAAM,YAAY,CAAC;AAElD,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAmBvC,iGAAiG;AACjG,KAAK,UAAU,UAAU,CAAC,EAAsB,EAAE,KAAc;IAC9D,MAAM,GAAG,GAAe,MAAM,UAAU,CAAC,KAA8E,CAAC,CAAC;IACzH,IAAI,CAAC,GAAG;QAAE,OAAO;IACjB,IAAI,GAAG,CAAC,QAAQ,IAAI,EAAE,CAAC,QAAQ,IAAI,IAAI;QAAE,EAAE,CAAC,QAAQ,GAAG,GAAG,CAAC,QAAQ,CAAC;IACpE,IAAI,GAAG,CAAC,cAAc,IAAI,EAAE,CAAC,cAAc,IAAI,IAAI;QAAE,EAAE,CAAC,cAAc,GAAG,GAAG,CAAC,cAAc,CAAC;IAC5F,IAAI,GAAG,CAAC,QAAQ,IAAI,EAAE,CAAC,QAAQ,IAAI,IAAI;QAAE,EAAE,CAAC,QAAQ,GAAG,GAAG,CAAC,QAAQ,CAAC;IACpE,2FAA2F;IAC3F,iEAAiE;IACjE,IAAI,GAAG,CAAC,EAAE,IAAI,EAAE,CAAC,QAAQ,IAAI,IAAI;QAAE,EAAE,CAAC,QAAQ,GAAG,GAAG,CAAC,EAAE,CAAC;AAC1D,CAAC;AAED,SAAS,kBAAkB,CAAC,GAAW;IACrC,IAAI,OAAO,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;QACjC,MAAM,IAAI,KAAK,CACb,aAAa,OAAO,CAAC,OAAO,2DAA2D,OAAO,CAAC,QAAQ,MAAM;YAC3G,kEAAkE;YAClE,8DAA8D,GAAG,GAAG,CACvE,CAAC;IACJ,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,UAAyD,EAAE;IAE3D,IAAI,OAAO,CAAC,cAAc;QAAE,OAAO,OAAO,CAAC,cAAc,CAAC;IAC1D,IAAI,OAAO,CAAC,GAAG,CAAC,gBAAgB;QAAE,OAAO,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC;IACtE,OAAO,YAAY,CAAC,EAAE,QAAQ,EAAE,OAAO,CAAC,QAAQ,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC;AAC5E,CAAC;AAED,iGAAiG;AACjG,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,UAA2B,EAAE;IAC1D,OAAO,YAAY,CAAC,OAAO,CAAC,CAAC;AAC/B,CAAC;AAED,yEAAyE;AACzE,MAAM,CAAC,KAAK,UAAU,MAAM,CAAC,UAAyB,EAAE;IACtD,MAAM,EAAE,cAAc,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,UAAU,EAAE,GAAG,IAAI,EAAE,GAAG,OAAO,CAAC;IAC1F,MAAM,EAAE,WAAW,EAAE,IAAI,EAAE,SAAS,EAAE,GAAG,uBAAuB,CAAC,IAAI,CAAC,CAAC;IACvE,IAAI,KAAK;QAAE,MAAM,UAAU,CAAC,WAAW,EAAG,SAAqC,CAAC,KAAK,CAAC,CAAC;IACvF,MAAM,GAAG,GAAG,MAAM,cAAc,CAAC,EAAE,cAAc,EAAE,SAAS,EAAE,CAAC,CAAC;IAChE,kBAAkB,CAAC,GAAG,CAAC,CAAC;IACxB,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,MAAM,CAAC;QACpC,GAAI,SAAqC;QACzC,cAAc,EAAE,GAAG;QACnB,IAAI,EAAE,CAAC,GAAG,eAAe,CAAC,WAAW,CAAC,EAAE,GAAG,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC;KACzD,CAAC,CAAC;IACH,eAAe,CAAC,OAAO,EAAE,EAAE,QAAQ,EAAE,UAAU,EAAE,CAAC,CAAC;IACnD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAC3C,WAAmB,EACnB,UAAoC,EAAE;IAEtC,MAAM,EAAE,cAAc,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,UAAU,EAAE,GAAG,IAAI,EAAE,GAAG,OAAO,CAAC;IAC1F,MAAM,EAAE,WAAW,EAAE,IAAI,EAAE,SAAS,EAAE,GAAG,uBAAuB,CAAC,IAAI,CAAC,CAAC;IACvE,IAAI,KAAK;QAAE,MAAM,UAAU,CAAC,WAAW,EAAG,SAAqC,CAAC,KAAK,CAAC,CAAC;IACvF,MAAM,GAAG,GAAG,MAAM,cAAc,CAAC,EAAE,cAAc,EAAE,SAAS,EAAE,CAAC,CAAC;IAChE,kBAAkB,CAAC,GAAG,CAAC,CAAC;IACxB,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,uBAAuB,CAAC,WAAW,EAAE;QAClE,GAAI,SAA6D;QACjE,cAAc,EAAE,GAAG;QACnB,IAAI,EAAE,CAAC,GAAG,eAAe,CAAC,WAAW,CAAC,EAAE,GAAG,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC;KACzD,CAAC,CAAC;IACH,wBAAwB,CAAC,OAAO,EAAE,EAAE,QAAQ,EAAE,UAAU,EAAE,CAAC,CAAC;IAC5D,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,eAAe,EAAE,MAAM,EAAE,uBAAuB,EAAE,cAAc,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC"}
package/dist/release.js CHANGED
@@ -4,13 +4,13 @@
4
4
  // this package, the hash check guarantees you run exactly the published, signed binary.
5
5
  // Published checksums + GPG signatures live on the release page.
6
6
  export const RELEASE = {
7
- tag: "v0.1.0-pre.4",
7
+ tag: "v0.1.0-pre.5",
8
8
  version: "149.0.7827.114",
9
9
  asset: "clearcote-149.0.7827.114-windows-x64.zip",
10
- url: "https://github.com/clearcotelabs/clearcote-browser/releases/download/v0.1.0-pre.4/clearcote-149.0.7827.114-windows-x64.zip",
11
- sha256: "40972168909e887434a3db4188d336bb7389d319a5c75967fb66ca6114c22e4c",
10
+ url: "https://github.com/clearcotelabs/clearcote-browser/releases/download/v0.1.0-pre.5/clearcote-149.0.7827.114-windows-x64.zip",
11
+ sha256: "21b6c520f2866ead759c19aa02ac30570aee3ebb41f5196518c27604a693c7e6",
12
12
  exeSha256: "5743595256c89c6874804bf3315acce592fc7f1883760c8d380c010151a73b23",
13
- size: 253019015,
13
+ size: 242548712,
14
14
  os: "win32",
15
15
  };
16
16
  //# sourceMappingURL=release.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "clearcote",
3
- "version": "0.1.2",
3
+ "version": "0.3.0",
4
4
  "description": "Playwright drop-in for the Clearcote anti-fingerprint Chromium build. launch() returns a standard Playwright Browser backed by the verified Clearcote binary, which is auto-downloaded and SHA-256 checked.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -25,6 +25,7 @@
25
25
  },
26
26
  "dependencies": {
27
27
  "extract-zip": "^2.0.1",
28
+ "maxmind": "^4.3.0",
28
29
  "playwright-core": "^1.49.0"
29
30
  },
30
31
  "devDependencies": {