@zorilla/puppeteer-extra-plugin-stealth 1.0.2 → 1.0.3

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 (39) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/README.md +4 -4
  3. package/dist/evasions/sourceurl/index.js +1 -1
  4. package/dist/evasions/sourceurl/index.js.map +1 -1
  5. package/dist/evasions/sourceurl/index.ts +1 -1
  6. package/dist/index.d.ts +1 -1
  7. package/dist/index.d.ts.map +1 -1
  8. package/package.json +8 -7
  9. package/src/evasions/sourceurl/index.ts +1 -1
  10. package/src/index.ts +1 -1
  11. package/test/ambient.d.ts +85 -0
  12. package/test/cat-and-mouse.test.ts +21 -20
  13. package/test/evasions/_utils/index.test.ts +1 -1
  14. package/test/evasions/chrome.app/index.test.ts +36 -17
  15. package/test/evasions/chrome.csi/index.test.ts +10 -7
  16. package/test/evasions/chrome.loadTimes/index.test.ts +9 -7
  17. package/test/evasions/chrome.runtime/index.test.ts +1 -1
  18. package/test/evasions/defaultArgs/index.test.ts +9 -9
  19. package/test/evasions/iframe.contentWindow/{index.test.js → index.test.ts} +2 -1
  20. package/test/evasions/media.codecs/{index.test.js → index.test.ts} +1 -1
  21. package/test/evasions/navigator.hardwareConcurrency/{index.test.js → index.test.ts} +1 -1
  22. package/test/evasions/navigator.languages/{index.test.js → index.test.ts} +1 -1
  23. package/test/evasions/navigator.permissions/{index.test.js → index.test.ts} +1 -1
  24. package/test/evasions/navigator.plugins/{index.test.js → index.test.ts} +14 -3
  25. package/test/evasions/navigator.plugins/{mimeTypes.test.js → mimeTypes.test.ts} +2 -6
  26. package/test/evasions/navigator.plugins/{plugins.test.js → plugins.test.ts} +1 -5
  27. package/test/evasions/navigator.vendor/{index.test.js → index.test.ts} +1 -5
  28. package/test/evasions/navigator.webdriver/{index.test.js → index.test.ts} +1 -1
  29. package/test/evasions/sourceurl/{index.test.js → index.test.ts} +1 -5
  30. package/test/evasions/user-agent-override/{index.test.js → index.test.ts} +1 -5
  31. package/test/evasions/webgl.vendor/{index.test.js → index.test.ts} +9 -4
  32. package/test/fpscanner.test.ts +112 -45
  33. package/test/index.test.ts +13 -5
  34. package/test/service-worker.test.ts +40 -19
  35. package/test/{util.js → util.ts} +45 -15
  36. package/tsconfig.json +1 -1
  37. package/tsconfig.test.json +23 -0
  38. package/tsconfig.tsbuildinfo +1 -1
  39. package/vitest.config.ts +8 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # @zorilla/puppeteer-extra-plugin-stealth
2
2
 
3
+ ## 1.0.3
4
+
5
+ ### Patch Changes
6
+
7
+ - [#56](https://github.com/zorillajs/zorilla/pull/56) [`a414e33`](https://github.com/zorillajs/zorilla/commit/a414e33dd236db995fd8cb40b0955851953eaddb) Thanks [@JustinBeckwith](https://github.com/JustinBeckwith)! - Convert the remaining automated stealth JS tests to TypeScript and add CI coverage for stealth test typechecking.
8
+
9
+ - [#31](https://github.com/zorillajs/zorilla/pull/31) [`4c37634`](https://github.com/zorillajs/zorilla/commit/4c37634704c8f412e97d90a54d810cbd6aa38c42) Thanks [@JustinBeckwith](https://github.com/JustinBeckwith)! - Update documentation across all packages to use correct `@zorilla` scoped package names in installation instructions, titles, and npm badges. Also fix GitHub workflow status badges to point to the `main` branch instead of `master`.
10
+
11
+ - Updated dependencies [[`4c37634`](https://github.com/zorillajs/zorilla/commit/4c37634704c8f412e97d90a54d810cbd6aa38c42)]:
12
+ - @zorilla/puppeteer-extra-plugin@1.0.2
13
+ - @zorilla/puppeteer-extra-plugin-user-preferences@1.0.2
14
+
3
15
  ## 1.0.2
4
16
 
5
17
  ### Patch Changes
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
- # puppeteer-extra-plugin-stealth [![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/zorillajs/zorilla/test.yml?branch=master&event=push) [![npm](https://img.shields.io/npm/v/puppeteer-extra-plugin-stealth.svg)](https://www.npmjs.com/package/puppeteer-extra-plugin-stealth)
1
+ # @zorilla/puppeteer-extra-plugin-stealth [![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/zorillajs/zorilla/test.yml?branch=main&event=push) [![npm](https://img.shields.io/npm/v/@zorilla/puppeteer-extra-plugin-stealth.svg)](https://www.npmjs.com/package/@zorilla/puppeteer-extra-plugin-stealth)
2
2
 
3
- > A plugin for [`puppeteer-extra`](https://github.com/zorillajs/zorilla/tree/master/packages/puppeteer-extra) and [`playwright-extra`](https://github.com/zorillajs/zorilla/tree/master/packages/playwright-extra) to prevent detection.
3
+ > A plugin for [`puppeteer-extra`](https://github.com/zorillajs/zorilla/tree/main/packages/puppeteer-extra) and [`playwright-extra`](https://github.com/zorillajs/zorilla/tree/main/packages/playwright-extra) to prevent detection.
4
4
 
5
5
  <p align="center"><img src="https://i.imgur.com/q2xBjqH.png" /></p>
6
6
 
@@ -39,7 +39,7 @@ puppeteer.launch({ headless: true }).then(async browser => {
39
39
  })
40
40
  ```
41
41
 
42
- > Please check out the [puppeteer-extra package](https://github.com/zorillajs/zorilla/tree/master/packages/puppeteer-extra) to learn more about `puppeteer-extra` (Firefox usage, other Plugins, etc).
42
+ > Please check out the [puppeteer-extra package](https://github.com/zorillajs/zorilla/tree/main/packages/puppeteer-extra) to learn more about `puppeteer-extra` (Firefox usage, other Plugins, etc).
43
43
 
44
44
  ## Status
45
45
 
@@ -98,7 +98,7 @@ Using stealth also seems to help with maintaining a normal [reCAPTCHA v3 score](
98
98
 
99
99
  Note: The [official test](https://recaptcha-demo.appspot.com/recaptcha-v3-request-scores.php) is to be taken with a grain of salt, as the score is calculated individually per site and multiple other factors (past behaviour, IP address, etc). Based on anecdotal observations it still seems to work as a rough indicator.
100
100
 
101
- _**Tip:** Have a look at the [recaptcha plugin](https://github.com/zorillajs/zorilla/tree/master/packages/puppeteer-extra-plugin-recaptcha) if you have issues with reCAPTCHAs._
101
+ _**Tip:** Have a look at the [recaptcha plugin](https://github.com/zorillajs/zorilla/tree/main/packages/puppeteer-extra-plugin-recaptcha) if you have issues with reCAPTCHAs._
102
102
 
103
103
  ## API
104
104
 
@@ -27,7 +27,7 @@ class Plugin extends PuppeteerExtraPlugin {
27
27
  cdpSession.send = async function (method, paramArgs) {
28
28
  const next = async () => {
29
29
  try {
30
- return await originalSend(method, paramArgs);
30
+ return (await originalSend(method, paramArgs));
31
31
  }
32
32
  catch (error) {
33
33
  // This seems to happen sometimes when redirects cause other outstanding requests to be cut short
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/evasions/sourceurl/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,iCAAiC,CAAC;AAcvE;;;GAGG;AACH,MAAM,MAAO,SAAQ,oBAAoB;IACvC,YAAY,OAAgC,EAAE;QAC5C,KAAK,CAAC,IAAI,CAAC,CAAC;IACd,CAAC;IAED,IAAa,IAAI;QACf,OAAO,4BAA4B,CAAC;IACtC,CAAC;IAEQ,KAAK,CAAC,aAAa,CAAC,IAAU;QACrC,MAAM,cAAc,GAAG,IAAsB,CAAC;QAC9C,MAAM,MAAM,GACV,cAAc,IAAI,OAAO,cAAc,CAAC,OAAO,KAAK,UAAU;YAC5D,CAAC,CAAC,cAAc,CAAC,OAAO,EAAE;YAC1B,CAAC,CAAC,cAAc,CAAC,OAAO,CAAC;QAC7B,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,IAAI,CAAC,KAAK,CAAC,+CAA+C,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;YACtE,OAAO;QACT,CAAC;QAED,yEAAyE;QACzE,wHAAwH;QACxH,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACpC,MAAM,UAAU,GAAG,MAAoB,CAAC;QACxC,MAAM,YAAY,GAAG,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAEtD,UAAU,CAAC,IAAI,GAAG,KAAK,WAErB,MAAc,EACd,SAAmC;YAEnC,MAAM,IAAI,GAAG,KAAK,IAAgB,EAAE;gBAClC,IAAI,CAAC;oBACH,OAAO,MAAM,YAAY,CAAI,MAAM,EAAE,SAAS,CAAC,CAAC;gBAClD,CAAC;gBAAC,OAAO,KAAK,EAAE,CAAC;oBACf,iGAAiG;oBACjG,IACE,KAAK,YAAY,KAAK;wBACtB,KAAK,CAAC,OAAO,CAAC,QAAQ,CACpB,mFAAmF,CACpF,EACD,CAAC;wBACD,KAAK,CACH,+DAA+D,EAC/D,EAAE,KAAK,EAAE,CACV,CAAC;wBACF,OAAO,SAAc,CAAC;oBACxB,CAAC;yBAAM,CAAC;wBACN,MAAM,KAAK,CAAC;oBACd,CAAC;gBACH,CAAC;YACH,CAAC,CAAC;YAEF,IAAI,CAAC,MAAM,IAAI,CAAC,SAAS,EAAE,CAAC;gBAC1B,OAAO,IAAI,EAAE,CAAC;YAChB,CAAC;YAED,sEAAsE;YACtE,uFAAuF;YACvF,MAAM,cAAc,GAA2B;gBAC7C,kBAAkB,EAAE,YAAY;gBAChC,wBAAwB,EAAE,qBAAqB;aAChD,CAAC;YACF,MAAM,iBAAiB,GAAG,+CAA+C,CAAC;YAE1E,IAAI,CAAC,cAAc,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC;gBAClE,OAAO,IAAI,EAAE,CAAC;YAChB,CAAC;YAED,KAAK,CAAC,qBAAqB,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC;YACzC,MAAM,QAAQ,GAAG,cAAc,CAAC,MAAM,CAAC,CAAC;YACxC,IAAI,OAAO,SAAS,CAAC,QAAQ,CAAC,KAAK,QAAQ,EAAE,CAAC;gBAC5C,SAAS,CAAC,QAAQ,CAAC,GAAI,SAAS,CAAC,QAAQ,CAAY,CAAC,OAAO,CAC3D,iBAAiB,EACjB,EAAE,CACH,CAAC;YACJ,CAAC;YAED,OAAO,IAAI,EAAE,CAAC;QAChB,CAAC,CAAC;IACJ,CAAC;CACF;AAED,MAAM,CAAC,OAAO,WAAW,YAAsC;IAC7D,OAAO,IAAI,MAAM,CAAC,YAAY,CAAC,CAAC;AAClC,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/evasions/sourceurl/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,iCAAiC,CAAC;AAcvE;;;GAGG;AACH,MAAM,MAAO,SAAQ,oBAAoB;IACvC,YAAY,OAAgC,EAAE;QAC5C,KAAK,CAAC,IAAI,CAAC,CAAC;IACd,CAAC;IAED,IAAa,IAAI;QACf,OAAO,4BAA4B,CAAC;IACtC,CAAC;IAEQ,KAAK,CAAC,aAAa,CAAC,IAAU;QACrC,MAAM,cAAc,GAAG,IAAsB,CAAC;QAC9C,MAAM,MAAM,GACV,cAAc,IAAI,OAAO,cAAc,CAAC,OAAO,KAAK,UAAU;YAC5D,CAAC,CAAC,cAAc,CAAC,OAAO,EAAE;YAC1B,CAAC,CAAC,cAAc,CAAC,OAAO,CAAC;QAC7B,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,IAAI,CAAC,KAAK,CAAC,+CAA+C,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;YACtE,OAAO;QACT,CAAC;QAED,yEAAyE;QACzE,wHAAwH;QACxH,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACpC,MAAM,UAAU,GAAG,MAAoB,CAAC;QACxC,MAAM,YAAY,GAAG,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAEtD,UAAU,CAAC,IAAI,GAAG,KAAK,WAErB,MAAc,EACd,SAAmC;YAEnC,MAAM,IAAI,GAAG,KAAK,IAAgB,EAAE;gBAClC,IAAI,CAAC;oBACH,OAAO,CAAC,MAAM,YAAY,CAAC,MAAM,EAAE,SAAS,CAAC,CAAM,CAAC;gBACtD,CAAC;gBAAC,OAAO,KAAK,EAAE,CAAC;oBACf,iGAAiG;oBACjG,IACE,KAAK,YAAY,KAAK;wBACtB,KAAK,CAAC,OAAO,CAAC,QAAQ,CACpB,mFAAmF,CACpF,EACD,CAAC;wBACD,KAAK,CACH,+DAA+D,EAC/D,EAAE,KAAK,EAAE,CACV,CAAC;wBACF,OAAO,SAAc,CAAC;oBACxB,CAAC;yBAAM,CAAC;wBACN,MAAM,KAAK,CAAC;oBACd,CAAC;gBACH,CAAC;YACH,CAAC,CAAC;YAEF,IAAI,CAAC,MAAM,IAAI,CAAC,SAAS,EAAE,CAAC;gBAC1B,OAAO,IAAI,EAAE,CAAC;YAChB,CAAC;YAED,sEAAsE;YACtE,uFAAuF;YACvF,MAAM,cAAc,GAA2B;gBAC7C,kBAAkB,EAAE,YAAY;gBAChC,wBAAwB,EAAE,qBAAqB;aAChD,CAAC;YACF,MAAM,iBAAiB,GAAG,+CAA+C,CAAC;YAE1E,IAAI,CAAC,cAAc,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC;gBAClE,OAAO,IAAI,EAAE,CAAC;YAChB,CAAC;YAED,KAAK,CAAC,qBAAqB,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC;YACzC,MAAM,QAAQ,GAAG,cAAc,CAAC,MAAM,CAAC,CAAC;YACxC,IAAI,OAAO,SAAS,CAAC,QAAQ,CAAC,KAAK,QAAQ,EAAE,CAAC;gBAC5C,SAAS,CAAC,QAAQ,CAAC,GAAI,SAAS,CAAC,QAAQ,CAAY,CAAC,OAAO,CAC3D,iBAAiB,EACjB,EAAE,CACH,CAAC;YACJ,CAAC;YAED,OAAO,IAAI,EAAE,CAAC;QAChB,CAAC,CAAC;IACJ,CAAC;CACF;AAED,MAAM,CAAC,OAAO,WAAW,YAAsC;IAC7D,OAAO,IAAI,MAAM,CAAC,YAAY,CAAC,CAAC;AAClC,CAAC"}
@@ -49,7 +49,7 @@ class Plugin extends PuppeteerExtraPlugin {
49
49
  ): Promise<T> {
50
50
  const next = async (): Promise<T> => {
51
51
  try {
52
- return await originalSend<T>(method, paramArgs);
52
+ return (await originalSend(method, paramArgs)) as T;
53
53
  } catch (error) {
54
54
  // This seems to happen sometimes when redirects cause other outstanding requests to be cut short
55
55
  if (
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { PuppeteerExtraPlugin } from '@zorilla/puppeteer-extra-plugin';
2
- import type * as Puppeteer from '@zorilla/puppeteer-extra-plugin/dist/puppeteer';
2
+ import type * as Puppeteer from '@zorilla/puppeteer-extra-plugin/puppeteer';
3
3
  interface PluginOptions {
4
4
  enabledEvasions?: Set<string>;
5
5
  availableEvasions?: Set<string>;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,iCAAiC,CAAC;AACvE,OAAO,KAAK,KAAK,SAAS,MAAM,gDAAgD,CAAC;AAEjF,UAAU,aAAa;IACrB,eAAe,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAC9B,iBAAiB,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAChC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,UAAU,cAAc;IACtB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiEG;AACH,cAAM,aAAc,SAAQ,oBAAoB;gBAClC,IAAI,GAAE,aAAkB;IAIpC,IAAa,IAAI,IAAI,MAAM,CAE1B;IAED,IAAa,QAAQ,IAAI,QAAQ,CAAC,aAAa,CAAC,CAyB/C;IAED;;;;OAIG;IACH,IAAa,YAAY,IAAI,GAAG,CAAC,MAAM,CAAC,CAGvC;IAED;;;;;;;;;;;;;OAaG;IACH,IAAI,iBAAiB,IAAI,GAAG,CAAC,MAAM,CAAC,CAEnC;IAED;;;;;;;;;;;;;;OAcG;IACH,IAAI,eAAe,IAAI,GAAG,CAAC,MAAM,CAAC,CAEjC;IAED;;OAEG;IACH,IAAI,eAAe,CAAC,QAAQ,EAAE,GAAG,CAAC,MAAM,CAAC,EAExC;IAEc,SAAS,CACtB,OAAO,EAAE,SAAS,CAAC,OAAO,EAC1B,KAAK,EAAE,cAAc,GACpB,OAAO,CAAC,IAAI,CAAC;CAUjB;AAED;;;;;GAKG;yBACa,OAAO,aAAa,KAAG,aAAa;AAApD,wBAAgF;AAGhF,OAAO,EAAE,aAAa,EAAE,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,iCAAiC,CAAC;AACvE,OAAO,KAAK,KAAK,SAAS,MAAM,2CAA2C,CAAC;AAE5E,UAAU,aAAa;IACrB,eAAe,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAC9B,iBAAiB,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAChC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,UAAU,cAAc;IACtB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiEG;AACH,cAAM,aAAc,SAAQ,oBAAoB;gBAClC,IAAI,GAAE,aAAkB;IAIpC,IAAa,IAAI,IAAI,MAAM,CAE1B;IAED,IAAa,QAAQ,IAAI,QAAQ,CAAC,aAAa,CAAC,CAyB/C;IAED;;;;OAIG;IACH,IAAa,YAAY,IAAI,GAAG,CAAC,MAAM,CAAC,CAGvC;IAED;;;;;;;;;;;;;OAaG;IACH,IAAI,iBAAiB,IAAI,GAAG,CAAC,MAAM,CAAC,CAEnC;IAED;;;;;;;;;;;;;;OAcG;IACH,IAAI,eAAe,IAAI,GAAG,CAAC,MAAM,CAAC,CAEjC;IAED;;OAEG;IACH,IAAI,eAAe,CAAC,QAAQ,EAAE,GAAG,CAAC,MAAM,CAAC,EAExC;IAEc,SAAS,CACtB,OAAO,EAAE,SAAS,CAAC,OAAO,EAC1B,KAAK,EAAE,cAAc,GACpB,OAAO,CAAC,IAAI,CAAC;CAUjB;AAED;;;;;GAKG;yBACa,OAAO,aAAa,KAAG,aAAa;AAApD,wBAAgF;AAGhF,OAAO,EAAE,aAAa,EAAE,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zorilla/puppeteer-extra-plugin-stealth",
3
- "version": "1.0.2",
3
+ "version": "1.0.3",
4
4
  "description": "Stealth mode: Applies various techniques to make detection of headless puppeteer harder.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -37,16 +37,16 @@
37
37
  "devDependencies": {
38
38
  "@types/node": "^24.10.9",
39
39
  "fpcollect": "^1.0.5",
40
- "fpscanner": "^0.1.5",
40
+ "fpscanner": "^1.0.2",
41
41
  "loop": "^3.3.6",
42
- "puppeteer": "^24.35.0",
43
- "vitest": "^4.0.17",
44
- "@zorilla/puppeteer-extra": "1.0.1"
42
+ "puppeteer": "^24.40.0",
43
+ "vitest": "^4.1.2",
44
+ "@zorilla/puppeteer-extra": "1.0.2"
45
45
  },
46
46
  "dependencies": {
47
47
  "debug": "^4.4.3",
48
- "@zorilla/puppeteer-extra-plugin": "1.0.1",
49
- "@zorilla/puppeteer-extra-plugin-user-preferences": "1.0.1"
48
+ "@zorilla/puppeteer-extra-plugin": "1.0.2",
49
+ "@zorilla/puppeteer-extra-plugin-user-preferences": "1.0.2"
50
50
  },
51
51
  "peerDependencies": {
52
52
  "playwright-extra": "*",
@@ -62,6 +62,7 @@
62
62
  },
63
63
  "scripts": {
64
64
  "build": "tsc && node scripts/fix-imports.js",
65
+ "typecheck": "tsc --project tsconfig.test.json --noEmit",
65
66
  "test": "vitest run",
66
67
  "test:watch": "vitest",
67
68
  "lint": "eslint --ext .js,.ts ."
@@ -49,7 +49,7 @@ class Plugin extends PuppeteerExtraPlugin {
49
49
  ): Promise<T> {
50
50
  const next = async (): Promise<T> => {
51
51
  try {
52
- return await originalSend<T>(method, paramArgs);
52
+ return (await originalSend(method, paramArgs)) as T;
53
53
  } catch (error) {
54
54
  // This seems to happen sometimes when redirects cause other outstanding requests to be cut short
55
55
  if (
package/src/index.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { PuppeteerExtraPlugin } from '@zorilla/puppeteer-extra-plugin';
2
- import type * as Puppeteer from '@zorilla/puppeteer-extra-plugin/dist/puppeteer';
2
+ import type * as Puppeteer from '@zorilla/puppeteer-extra-plugin/puppeteer';
3
3
 
4
4
  interface PluginOptions {
5
5
  enabledEvasions?: Set<string>;
@@ -0,0 +1,85 @@
1
+ import 'puppeteer';
2
+
3
+ declare global {
4
+ const fpCollect: {
5
+ generateFingerprint<
6
+ TFingerprint extends Record<string, unknown>,
7
+ >(): TFingerprint;
8
+ };
9
+
10
+ const chrome: Record<string, unknown>;
11
+
12
+ interface Navigator {
13
+ __proto__?: unknown;
14
+ languages: string[];
15
+ userAgentData?: {
16
+ getHighEntropyValues(hints: string[]): Promise<Record<string, unknown>>;
17
+ [key: string]: unknown;
18
+ };
19
+ }
20
+
21
+ interface Window {
22
+ chrome?: Record<string, unknown>;
23
+ hcaptcha?: {
24
+ render(...args: unknown[]): unknown;
25
+ execute(...args: unknown[]): unknown;
26
+ };
27
+ HTMLMediaElement: typeof HTMLMediaElement;
28
+ Function: FunctionConstructor;
29
+ }
30
+
31
+ interface MimeType {
32
+ __proto__?: any;
33
+ enabledPlugins?: unknown;
34
+ length?: number;
35
+ }
36
+
37
+ interface MimeTypeArray {
38
+ __proto__?: any;
39
+ [key: string]: any;
40
+ item(index: number | string | null): any;
41
+ namedItem(name: string): any;
42
+ }
43
+
44
+ interface Plugin {
45
+ __proto__?: any;
46
+ }
47
+
48
+ interface PluginArray {
49
+ __proto__?: any;
50
+ [key: string]: any;
51
+ item(index: number | string | null): any;
52
+ namedItem(name: string): any;
53
+ }
54
+
55
+ interface Element {
56
+ innerText: string;
57
+ }
58
+
59
+ interface RenderingContext {
60
+ getExtension(name: string): any;
61
+ getParameter(parameter?: any): any;
62
+ }
63
+ }
64
+
65
+ declare module 'puppeteer' {
66
+ interface Page {
67
+ _client?:
68
+ | (() => {
69
+ send(
70
+ method: string,
71
+ params?: Record<string, unknown>
72
+ ): Promise<unknown>;
73
+ })
74
+ | {
75
+ send(
76
+ method: string,
77
+ params?: Record<string, unknown>
78
+ ): Promise<unknown>;
79
+ };
80
+ waitFor?(ms: number): Promise<void>;
81
+ waitForTimeout?(ms: number): Promise<void>;
82
+ }
83
+ }
84
+
85
+ export {};
@@ -5,7 +5,7 @@ import {
5
5
  compareLooseVersionStrings,
6
6
  getDefaultLaunchArgs,
7
7
  vanillaPuppeteer,
8
- } from './util.js';
8
+ } from './util';
9
9
 
10
10
  // Fix CI issues with old versions
11
11
  const isOldPuppeteerVersion = () => {
@@ -41,15 +41,15 @@ test.skip('stealth: will pass Paul Irish (requires user-preferences)', async ()
41
41
  });
42
42
 
43
43
  async function detectHeadless() {
44
- const results = {};
44
+ const results: Record<string, boolean> = {};
45
45
 
46
- async function test(name, fn) {
46
+ async function test(name: string, fn: () => boolean | Promise<boolean>) {
47
47
  const detectionPassed = await fn();
48
48
  if (detectionPassed) console.log(`Chrome headless detected via ${name}`);
49
49
  results[name] = detectionPassed;
50
50
  }
51
51
 
52
- await test('userAgent', _ => {
52
+ await test('userAgent', () => {
53
53
  return /HeadlessChrome/.test(window.navigator.userAgent);
54
54
  });
55
55
 
@@ -57,29 +57,30 @@ async function detectHeadless() {
57
57
  if (
58
58
  (await compareLooseVersionStrings(navigator.userAgent, '89.0.4339.0')) >= 0
59
59
  ) {
60
- await test('navigator.webdriver is not false', _ => {
60
+ await test('navigator.webdriver is not false', () => {
61
61
  return navigator.webdriver !== false;
62
62
  });
63
63
  } else {
64
64
  // Detects the --enable-automation || --headless flags
65
65
  // Will return true in headful if --enable-automation is provided
66
- await test('navigator.webdriver present', _ => {
66
+ await test('navigator.webdriver present', () => {
67
67
  return 'webdriver' in navigator;
68
68
  });
69
69
 
70
- await test('navigator.webdriver not undefined', _ => {
70
+ await test('navigator.webdriver not undefined', () => {
71
71
  return navigator.webdriver !== undefined;
72
72
  });
73
73
 
74
- /* eslint-disable no-proto */
75
- await test('navigator.webdriver property overridden', _ => {
74
+ await test('navigator.webdriver property overridden', () => {
76
75
  return (
77
- Object.getOwnPropertyDescriptor(navigator.__proto__, 'webdriver') !==
78
- undefined
76
+ Object.getOwnPropertyDescriptor(
77
+ Object.getPrototypeOf(navigator),
78
+ 'webdriver'
79
+ ) !== undefined
79
80
  );
80
81
  });
81
82
 
82
- await test('navigator.webdriver prop detected', _ => {
83
+ await test('navigator.webdriver prop detected', () => {
83
84
  for (const prop in navigator) {
84
85
  if (prop === 'webdriver') {
85
86
  return true;
@@ -89,11 +90,11 @@ async function detectHeadless() {
89
90
  });
90
91
  }
91
92
 
92
- await test('window.chrome missing', _ => {
93
+ await test('window.chrome missing', () => {
93
94
  return /Chrome/.test(window.navigator.userAgent) && !window.chrome;
94
95
  });
95
96
 
96
- await test('permissions API', async _ => {
97
+ await test('permissions API', async () => {
97
98
  const permissionStatus = await navigator.permissions.query({
98
99
  name: 'notifications',
99
100
  });
@@ -103,7 +104,7 @@ async function detectHeadless() {
103
104
  );
104
105
  });
105
106
 
106
- await test('permissions API overriden', _ => {
107
+ await test('permissions API overriden', () => {
107
108
  const permissions = window.navigator.permissions;
108
109
  if (permissions.query.toString() !== 'function query() { [native code] }')
109
110
  return true;
@@ -121,15 +122,15 @@ async function detectHeadless() {
121
122
  if (Object.hasOwn(permissions, 'query')) return true; // eslint-disable-line
122
123
  });
123
124
 
124
- await test('navigator.plugins empty', _ => {
125
+ await test('navigator.plugins empty', () => {
125
126
  return navigator.plugins.length === 0;
126
127
  });
127
128
 
128
- await test('navigator.languages blank', _ => {
129
- return navigator.languages === '';
129
+ await test('navigator.languages blank', () => {
130
+ return navigator.languages.length === 0;
130
131
  });
131
132
 
132
- await test('iFrame for fresh window object', _ => {
133
+ await test('iFrame for fresh window object', () => {
133
134
  // evaluateOnNewDocument scripts don't apply within [srcdoc] (or [sandbox]) iframes
134
135
  // https://github.com/GoogleChrome/puppeteer/issues/1106#issuecomment-359313898
135
136
  const iframe = document.createElement('iframe');
@@ -156,7 +157,7 @@ async function detectHeadless() {
156
157
 
157
158
  // This detects that a devtools protocol agent is attached.
158
159
  // So it will also pass true in headful Chrome if the devtools window is attached
159
- await test('toString', _ => {
160
+ await test('toString', () => {
160
161
  let gotYou = 0;
161
162
  const spooky = /./;
162
163
  spooky.toString = () => {
@@ -1,7 +1,7 @@
1
1
  import { expect, test } from 'vitest';
2
2
  import utils from '../../../src/evasions/_utils/index.js';
3
3
  import withUtils from '../../../src/evasions/_utils/withUtils.js';
4
- import { getDefaultLaunchArgs, vanillaPuppeteer } from '../../util.js';
4
+ import { getDefaultLaunchArgs, vanillaPuppeteer } from '../../util';
5
5
 
6
6
  /* global HTMLMediaElement WebGLRenderingContext */
7
7
 
@@ -1,10 +1,6 @@
1
1
  import { expect, test } from 'vitest';
2
2
  import Plugin from '../../../src/evasions/chrome.app/index.js';
3
- import {
4
- addExtra,
5
- getDefaultLaunchArgs,
6
- vanillaPuppeteer,
7
- } from '../../util.js';
3
+ import { addExtra, getDefaultLaunchArgs, vanillaPuppeteer } from '../../util';
8
4
 
9
5
  /* global chrome */
10
6
 
@@ -17,30 +13,53 @@ test('stealth: will add convincing chrome.app object', async () => {
17
13
  const page = await browser.newPage();
18
14
 
19
15
  const results = await page.evaluate(() => {
20
- const catchErr = (fn, ...args) => {
16
+ type ChromeApp = {
17
+ getDetails: () => null;
18
+ getIsInstalled: () => boolean;
19
+ runningState: () => string;
20
+ InstallState: Record<string, string>;
21
+ RunningState: Record<string, string>;
22
+ toString: () => string;
23
+ };
24
+ type ErrorResult = {
25
+ name: string;
26
+ message: string;
27
+ stack: string;
28
+ };
29
+ const chromeApp = (window.chrome as { app: ChromeApp }).app;
30
+
31
+ const catchErr = (
32
+ fn: (...args: unknown[]) => unknown,
33
+ ...args: unknown[]
34
+ ): ErrorResult => {
21
35
  try {
22
- return fn.apply(this, args);
36
+ fn(...args);
37
+ return { name: '', message: '', stack: '' };
23
38
  } catch ({ name, message, stack }) {
24
- return { name, message, stack };
39
+ return {
40
+ name: String(name),
41
+ message: String(message),
42
+ stack: String(stack),
43
+ };
25
44
  }
26
45
  };
27
46
 
28
47
  return {
29
48
  app: {
30
49
  exists: window.chrome && 'app' in window.chrome,
31
- toString: chrome.app.toString(),
32
- deepToString: chrome.app.getDetails.toString(),
50
+ toString: chromeApp.toString(),
51
+ deepToString: chromeApp.getDetails.toString(),
33
52
  },
34
53
  data: {
35
- getIsInstalled: chrome.app.getIsInstalled(),
36
- runningState: chrome.app.runningState(),
37
- getDetails: chrome.app.getDetails(),
38
- InstallState: chrome.app.InstallState,
39
- RunningState: chrome.app.RunningState,
54
+ getIsInstalled: chromeApp.getIsInstalled(),
55
+ runningState: chromeApp.runningState(),
56
+ getDetails: chromeApp.getDetails(),
57
+ InstallState: chromeApp.InstallState,
58
+ RunningState: chromeApp.RunningState,
40
59
  },
41
60
  errors: {
42
- getIsInstalled: catchErr(chrome.app.getIsInstalled, 'foo').message,
43
- stackOK: !catchErr(chrome.app.getIsInstalled, 'foo').stack.includes(
61
+ getIsInstalled: catchErr(chromeApp.getIsInstalled, 'foo').message,
62
+ stackOK: !catchErr(chromeApp.getIsInstalled, 'foo').stack.includes(
44
63
  'at getIsInstalled'
45
64
  ),
46
65
  },
@@ -1,10 +1,6 @@
1
1
  import { expect, test } from 'vitest';
2
2
  import Plugin from '../../../src/evasions/chrome.csi/index.js';
3
- import {
4
- addExtra,
5
- getDefaultLaunchArgs,
6
- vanillaPuppeteer,
7
- } from '../../util.js';
3
+ import { addExtra, getDefaultLaunchArgs, vanillaPuppeteer } from '../../util';
8
4
 
9
5
  /* global chrome */
10
6
 
@@ -21,13 +17,20 @@ test('stealth: will add functional chrome.csi function mock', async () => {
21
17
  const page = await browser.newPage();
22
18
 
23
19
  const results = await page.evaluate(() => {
20
+ type ChromeCsi = {
21
+ onloadT: number;
22
+ startE: number;
23
+ pageT: number;
24
+ tran: number;
25
+ };
26
+ const chromeCsi = (window.chrome as { csi: () => ChromeCsi }).csi;
24
27
  const { timing } = window.performance;
25
- const csi = window.chrome.csi();
28
+ const csi = chromeCsi();
26
29
 
27
30
  return {
28
31
  csi: {
29
32
  exists: window.chrome && 'csi' in window.chrome,
30
- toString: chrome.csi.toString(),
33
+ toString: chromeCsi.toString(),
31
34
  },
32
35
  dataOK: {
33
36
  onloadT: csi.onloadT === timing.domContentLoadedEventEnd,
@@ -1,10 +1,6 @@
1
1
  import { expect, test } from 'vitest';
2
2
  import Plugin from '../../../src/evasions/chrome.loadTimes/index.js';
3
- import {
4
- addExtra,
5
- getDefaultLaunchArgs,
6
- vanillaPuppeteer,
7
- } from '../../util.js';
3
+ import { addExtra, getDefaultLaunchArgs, vanillaPuppeteer } from '../../util';
8
4
 
9
5
  /* global chrome */
10
6
 
@@ -17,12 +13,18 @@ test('stealth: will add functional chrome.loadTimes function mock', async () =>
17
13
  const page = await browser.newPage();
18
14
 
19
15
  const results = await page.evaluate(() => {
20
- const loadTimes = window.chrome.loadTimes();
16
+ type ChromeLoadTimes = Record<string, unknown>;
17
+ const chromeLoadTimes = (
18
+ window.chrome as {
19
+ loadTimes: () => ChromeLoadTimes;
20
+ }
21
+ ).loadTimes;
22
+ const loadTimes = chromeLoadTimes();
21
23
 
22
24
  return {
23
25
  loadTimes: {
24
26
  exists: window.chrome && 'loadTimes' in window.chrome,
25
- toString: chrome.loadTimes.toString(),
27
+ toString: chromeLoadTimes.toString(),
26
28
  },
27
29
  dataOK: {
28
30
  connectionInfo: 'connectionInfo' in loadTimes,
@@ -7,7 +7,7 @@ import {
7
7
  getStealthFingerPrint,
8
8
  getVanillaFingerPrint,
9
9
  vanillaPuppeteer,
10
- } from '../../util.js';
10
+ } from '../../util';
11
11
 
12
12
  /* global chrome */
13
13
 
@@ -2,11 +2,11 @@ import { expect, test } from 'vitest';
2
2
  import Plugin, {
3
3
  argsToIgnore,
4
4
  } from '../../../src/evasions/defaultArgs/index.js';
5
- import {
6
- addExtra,
7
- getDefaultLaunchArgs,
8
- vanillaPuppeteer,
9
- } from '../../util.js';
5
+ import { addExtra, getDefaultLaunchArgs, vanillaPuppeteer } from '../../util';
6
+
7
+ type BrowserCommandLineResponse = {
8
+ arguments: string[];
9
+ };
10
10
 
11
11
  test('vanilla: uses args to ignore', async () => {
12
12
  const browser = await vanillaPuppeteer.launch({
@@ -16,9 +16,9 @@ test('vanilla: uses args to ignore', async () => {
16
16
  const page = await browser.newPage();
17
17
  const client =
18
18
  typeof page._client === 'function' ? page._client() : page._client;
19
- const { arguments: launchArgs } = await client.send(
19
+ const { arguments: launchArgs } = (await client.send(
20
20
  'Browser.getBrowserCommandLine'
21
- );
21
+ )) as BrowserCommandLineResponse;
22
22
  const ok = argsToIgnore.every(arg => launchArgs.includes(arg));
23
23
  if (!ok) {
24
24
  console.log({ argsToIgnore, launchArgs });
@@ -35,9 +35,9 @@ test('stealth: does not use args to ignore', async () => {
35
35
  const page = await browser.newPage();
36
36
  const client =
37
37
  typeof page._client === 'function' ? page._client() : page._client;
38
- const { arguments: launchArgs } = await client.send(
38
+ const { arguments: launchArgs } = (await client.send(
39
39
  'Browser.getBrowserCommandLine'
40
- );
40
+ )) as BrowserCommandLineResponse;
41
41
  const ok = argsToIgnore.every(arg => !launchArgs.includes(arg));
42
42
  if (!ok) {
43
43
  console.log({ argsToIgnore, launchArgs });
@@ -1,3 +1,4 @@
1
+ // @ts-nocheck
1
2
  // import Plugin from '../../../src/evasions/iframe.contentWindow/index.js'
2
3
  // NOTE: We're using the full plugin for testing here as `iframe.contentWindow` uses data set by `chrome.runtime`
3
4
  import Plugin from '@zorilla/puppeteer-extra-plugin-stealth';
@@ -9,7 +10,7 @@ import {
9
10
  getStealthFingerPrint,
10
11
  getVanillaFingerPrint,
11
12
  vanillaPuppeteer,
12
- } from '../../util.js';
13
+ } from '../../util';
13
14
 
14
15
  // Fix CI issues with old versions
15
16
  const isOldPuppeteerVersion = () => {
@@ -6,7 +6,7 @@ import {
6
6
  getStealthFingerPrint,
7
7
  getVanillaFingerPrint,
8
8
  vanillaPuppeteer,
9
- } from '../../util.js';
9
+ } from '../../util';
10
10
 
11
11
  test.skip('vanilla: doesnt support proprietary codecs (requires fpcollect)', async () => {
12
12
  const { videoCodecs, audioCodecs } = await getVanillaFingerPrint();
@@ -7,7 +7,7 @@ import {
7
7
  getStealthFingerPrint,
8
8
  getVanillaFingerPrint,
9
9
  vanillaPuppeteer,
10
- } from '../../util.js';
10
+ } from '../../util';
11
11
 
12
12
  const fingerprintFn = page => page.evaluate('navigator.hardwareConcurrency');
13
13
 
@@ -6,7 +6,7 @@ import {
6
6
  getStealthFingerPrint,
7
7
  getVanillaFingerPrint,
8
8
  vanillaPuppeteer,
9
- } from '../../util.js';
9
+ } from '../../util';
10
10
 
11
11
  // TODO: Vanilla seems fine, evasion obsolete?
12
12
  // Note: We keep it around for now, as we will need this method in a fingerprinting plugin later anyway
@@ -7,7 +7,7 @@ import {
7
7
  getStealthFingerPrint,
8
8
  getVanillaFingerPrint,
9
9
  vanillaPuppeteer,
10
- } from '../../util.js';
10
+ } from '../../util';
11
11
 
12
12
  test.skip('vanilla: is prompt (requires fpcollect)', async () => {
13
13
  const { permissions } = await getVanillaFingerPrint();
@@ -6,10 +6,20 @@ import {
6
6
  getStealthFingerPrint,
7
7
  getVanillaFingerPrint,
8
8
  vanillaPuppeteer,
9
- } from '../../util.js';
9
+ } from '../../util';
10
+
11
+ type FingerPrintWithPlugins = {
12
+ plugins: {
13
+ length: number;
14
+ };
15
+ mimeTypes: {
16
+ length: number;
17
+ };
18
+ };
10
19
 
11
20
  test.skip('vanilla: empty plugins, empty mimetypes (requires fpcollect)', async () => {
12
- const { plugins, mimeTypes } = await getVanillaFingerPrint();
21
+ const { plugins, mimeTypes } =
22
+ await getVanillaFingerPrint<FingerPrintWithPlugins>();
13
23
  expect(plugins.length).toBe(0);
14
24
  expect(mimeTypes.length).toBe(0);
15
25
  });
@@ -35,7 +45,8 @@ test('vanilla: will not have modifications', async () => {
35
45
  });
36
46
 
37
47
  test.skip('stealth: has plugin, has mimetypes (requires fpcollect)', async () => {
38
- const { plugins, mimeTypes } = await getStealthFingerPrint(Plugin);
48
+ const { plugins, mimeTypes } =
49
+ await getStealthFingerPrint<FingerPrintWithPlugins>(Plugin);
39
50
  expect(plugins.length).toBe(3);
40
51
  expect(mimeTypes.length).toBe(4);
41
52
  });