@zorilla/puppeteer-extra-plugin-stealth 1.0.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 (270) hide show
  1. package/.claude/settings.local.json +21 -0
  2. package/LICENSE +21 -0
  3. package/README.md +324 -0
  4. package/dist/evasions/README.md +13 -0
  5. package/dist/evasions/_template/README.md +18 -0
  6. package/dist/evasions/_template/index.d.ts +13 -0
  7. package/dist/evasions/_template/index.d.ts.map +1 -0
  8. package/dist/evasions/_template/index.js +26 -0
  9. package/dist/evasions/_template/index.js.map +1 -0
  10. package/dist/evasions/_template/package.json +5 -0
  11. package/dist/evasions/_utils/README.md +287 -0
  12. package/dist/evasions/_utils/index.d.ts +238 -0
  13. package/dist/evasions/_utils/index.d.ts.map +1 -0
  14. package/dist/evasions/_utils/index.js +588 -0
  15. package/dist/evasions/_utils/index.js.map +1 -0
  16. package/dist/evasions/_utils/withUtils.d.ts +12 -0
  17. package/dist/evasions/_utils/withUtils.d.ts.map +1 -0
  18. package/dist/evasions/_utils/withUtils.js +47 -0
  19. package/dist/evasions/_utils/withUtils.js.map +1 -0
  20. package/dist/evasions/chrome.app/README.md +16 -0
  21. package/dist/evasions/chrome.app/index.d.ts +11 -0
  22. package/dist/evasions/chrome.app/index.d.ts.map +1 -0
  23. package/dist/evasions/chrome.app/index.js +97 -0
  24. package/dist/evasions/chrome.app/index.js.map +1 -0
  25. package/dist/evasions/chrome.app/package.json +5 -0
  26. package/dist/evasions/chrome.csi/README.md +29 -0
  27. package/dist/evasions/chrome.csi/index.d.ts +25 -0
  28. package/dist/evasions/chrome.csi/index.d.ts.map +1 -0
  29. package/dist/evasions/chrome.csi/index.js +69 -0
  30. package/dist/evasions/chrome.csi/index.js.map +1 -0
  31. package/dist/evasions/chrome.csi/package.json +5 -0
  32. package/dist/evasions/chrome.loadTimes/README.md +27 -0
  33. package/dist/evasions/chrome.loadTimes/index.d.ts +23 -0
  34. package/dist/evasions/chrome.loadTimes/index.d.ts.map +1 -0
  35. package/dist/evasions/chrome.loadTimes/index.js +163 -0
  36. package/dist/evasions/chrome.loadTimes/index.js.map +1 -0
  37. package/dist/evasions/chrome.loadTimes/package.json +5 -0
  38. package/dist/evasions/chrome.runtime/README.md +32 -0
  39. package/dist/evasions/chrome.runtime/index.d.ts +14 -0
  40. package/dist/evasions/chrome.runtime/index.d.ts.map +1 -0
  41. package/dist/evasions/chrome.runtime/index.js +252 -0
  42. package/dist/evasions/chrome.runtime/index.js.map +1 -0
  43. package/dist/evasions/chrome.runtime/package.json +5 -0
  44. package/dist/evasions/chrome.runtime/staticData.json +41 -0
  45. package/dist/evasions/defaultArgs/README.md +17 -0
  46. package/dist/evasions/defaultArgs/index.d.ts +2 -0
  47. package/dist/evasions/defaultArgs/index.d.ts.map +1 -0
  48. package/dist/evasions/defaultArgs/index.js +43 -0
  49. package/dist/evasions/defaultArgs/index.js.map +1 -0
  50. package/dist/evasions/defaultArgs/package.json +5 -0
  51. package/dist/evasions/iframe.contentWindow/README.md +19 -0
  52. package/dist/evasions/iframe.contentWindow/index.d.ts +15 -0
  53. package/dist/evasions/iframe.contentWindow/index.d.ts.map +1 -0
  54. package/dist/evasions/iframe.contentWindow/index.js +132 -0
  55. package/dist/evasions/iframe.contentWindow/index.js.map +1 -0
  56. package/dist/evasions/iframe.contentWindow/package.json +5 -0
  57. package/dist/evasions/media.codecs/README.md +38 -0
  58. package/dist/evasions/media.codecs/index.d.ts +12 -0
  59. package/dist/evasions/media.codecs/index.d.ts.map +1 -0
  60. package/dist/evasions/media.codecs/index.js +89 -0
  61. package/dist/evasions/media.codecs/index.js.map +1 -0
  62. package/dist/evasions/media.codecs/package.json +5 -0
  63. package/dist/evasions/navigator.hardwareConcurrency/README.md +19 -0
  64. package/dist/evasions/navigator.hardwareConcurrency/index.d.ts +2 -0
  65. package/dist/evasions/navigator.hardwareConcurrency/index.d.ts.map +1 -0
  66. package/dist/evasions/navigator.hardwareConcurrency/index.js +45 -0
  67. package/dist/evasions/navigator.hardwareConcurrency/index.js.map +1 -0
  68. package/dist/evasions/navigator.hardwareConcurrency/package.json +5 -0
  69. package/dist/evasions/navigator.languages/README.md +17 -0
  70. package/dist/evasions/navigator.languages/index.d.ts +2 -0
  71. package/dist/evasions/navigator.languages/index.d.ts.map +1 -0
  72. package/dist/evasions/navigator.languages/index.js +44 -0
  73. package/dist/evasions/navigator.languages/index.js.map +1 -0
  74. package/dist/evasions/navigator.languages/package.json +5 -0
  75. package/dist/evasions/navigator.permissions/README.md +16 -0
  76. package/dist/evasions/navigator.permissions/index.d.ts +2 -0
  77. package/dist/evasions/navigator.permissions/index.d.ts.map +1 -0
  78. package/dist/evasions/navigator.permissions/index.js +66 -0
  79. package/dist/evasions/navigator.permissions/index.js.map +1 -0
  80. package/dist/evasions/navigator.permissions/package.json +5 -0
  81. package/dist/evasions/navigator.plugins/README.md +24 -0
  82. package/dist/evasions/navigator.plugins/data.json +48 -0
  83. package/dist/evasions/navigator.plugins/functionMocks.d.ts +9 -0
  84. package/dist/evasions/navigator.plugins/functionMocks.d.ts.map +1 -0
  85. package/dist/evasions/navigator.plugins/functionMocks.js +47 -0
  86. package/dist/evasions/navigator.plugins/functionMocks.js.map +1 -0
  87. package/dist/evasions/navigator.plugins/index.d.ts +19 -0
  88. package/dist/evasions/navigator.plugins/index.d.ts.map +1 -0
  89. package/dist/evasions/navigator.plugins/index.js +98 -0
  90. package/dist/evasions/navigator.plugins/index.js.map +1 -0
  91. package/dist/evasions/navigator.plugins/magicArray.d.ts +2 -0
  92. package/dist/evasions/navigator.plugins/magicArray.d.ts.map +1 -0
  93. package/dist/evasions/navigator.plugins/magicArray.js +145 -0
  94. package/dist/evasions/navigator.plugins/magicArray.js.map +1 -0
  95. package/dist/evasions/navigator.plugins/mimeTypes.d.ts +2 -0
  96. package/dist/evasions/navigator.plugins/mimeTypes.d.ts.map +1 -0
  97. package/dist/evasions/navigator.plugins/mimeTypes.js +18 -0
  98. package/dist/evasions/navigator.plugins/mimeTypes.js.map +1 -0
  99. package/dist/evasions/navigator.plugins/package.json +5 -0
  100. package/dist/evasions/navigator.plugins/plugins.d.ts +2 -0
  101. package/dist/evasions/navigator.plugins/plugins.d.ts.map +1 -0
  102. package/dist/evasions/navigator.plugins/plugins.js +18 -0
  103. package/dist/evasions/navigator.plugins/plugins.js.map +1 -0
  104. package/dist/evasions/navigator.vendor/README.md +36 -0
  105. package/dist/evasions/navigator.vendor/index.d.ts +2 -0
  106. package/dist/evasions/navigator.vendor/index.d.ts.map +1 -0
  107. package/dist/evasions/navigator.vendor/index.js +64 -0
  108. package/dist/evasions/navigator.vendor/index.js.map +1 -0
  109. package/dist/evasions/navigator.vendor/package.json +5 -0
  110. package/dist/evasions/navigator.webdriver/README.md +17 -0
  111. package/dist/evasions/navigator.webdriver/index.d.ts +13 -0
  112. package/dist/evasions/navigator.webdriver/index.d.ts.map +1 -0
  113. package/dist/evasions/navigator.webdriver/index.js +48 -0
  114. package/dist/evasions/navigator.webdriver/index.js.map +1 -0
  115. package/dist/evasions/navigator.webdriver/package.json +5 -0
  116. package/dist/evasions/sourceurl/README.md +17 -0
  117. package/dist/evasions/sourceurl/_fixtures/test.html +35 -0
  118. package/dist/evasions/sourceurl/index.d.ts +12 -0
  119. package/dist/evasions/sourceurl/index.d.ts.map +1 -0
  120. package/dist/evasions/sourceurl/index.js +82 -0
  121. package/dist/evasions/sourceurl/index.js.map +1 -0
  122. package/dist/evasions/sourceurl/package.json +5 -0
  123. package/dist/evasions/user-agent-override/README.md +53 -0
  124. package/dist/evasions/user-agent-override/index.d.ts +2 -0
  125. package/dist/evasions/user-agent-override/index.d.ts.map +1 -0
  126. package/dist/evasions/user-agent-override/index.js +206 -0
  127. package/dist/evasions/user-agent-override/index.js.map +1 -0
  128. package/dist/evasions/user-agent-override/package.json +5 -0
  129. package/dist/evasions/webgl.vendor/README.md +20 -0
  130. package/dist/evasions/webgl.vendor/index.d.ts +17 -0
  131. package/dist/evasions/webgl.vendor/index.d.ts.map +1 -0
  132. package/dist/evasions/webgl.vendor/index.js +57 -0
  133. package/dist/evasions/webgl.vendor/index.js.map +1 -0
  134. package/dist/evasions/webgl.vendor/package.json +5 -0
  135. package/dist/evasions/window.outerdimensions/README.md +17 -0
  136. package/dist/evasions/window.outerdimensions/index.d.ts +13 -0
  137. package/dist/evasions/window.outerdimensions/index.d.ts.map +1 -0
  138. package/dist/evasions/window.outerdimensions/index.js +42 -0
  139. package/dist/evasions/window.outerdimensions/index.js.map +1 -0
  140. package/dist/evasions/window.outerdimensions/package.json +5 -0
  141. package/dist/index.d.ts +130 -0
  142. package/dist/index.d.ts.map +1 -0
  143. package/dist/index.js +164 -0
  144. package/dist/index.js.map +1 -0
  145. package/examples/detect-headless.js +95 -0
  146. package/examples/test1.js +20 -0
  147. package/examples/test2.js +25 -0
  148. package/package.json +70 -0
  149. package/src/evasions/README.md +13 -0
  150. package/src/evasions/_template/README.md +18 -0
  151. package/src/evasions/_template/index.js +26 -0
  152. package/src/evasions/_template/package.json +5 -0
  153. package/src/evasions/_utils/README.md +287 -0
  154. package/src/evasions/_utils/index.js +588 -0
  155. package/src/evasions/_utils/withUtils.js +47 -0
  156. package/src/evasions/chrome.app/README.md +16 -0
  157. package/src/evasions/chrome.app/index.js +97 -0
  158. package/src/evasions/chrome.app/package.json +5 -0
  159. package/src/evasions/chrome.csi/README.md +29 -0
  160. package/src/evasions/chrome.csi/index.js +69 -0
  161. package/src/evasions/chrome.csi/package.json +5 -0
  162. package/src/evasions/chrome.loadTimes/README.md +27 -0
  163. package/src/evasions/chrome.loadTimes/index.js +163 -0
  164. package/src/evasions/chrome.loadTimes/package.json +5 -0
  165. package/src/evasions/chrome.runtime/README.md +32 -0
  166. package/src/evasions/chrome.runtime/index.js +252 -0
  167. package/src/evasions/chrome.runtime/package.json +5 -0
  168. package/src/evasions/chrome.runtime/staticData.json +41 -0
  169. package/src/evasions/defaultArgs/README.md +17 -0
  170. package/src/evasions/defaultArgs/index.js +43 -0
  171. package/src/evasions/defaultArgs/package.json +5 -0
  172. package/src/evasions/iframe.contentWindow/README.md +19 -0
  173. package/src/evasions/iframe.contentWindow/index.js +132 -0
  174. package/src/evasions/iframe.contentWindow/package.json +5 -0
  175. package/src/evasions/media.codecs/README.md +38 -0
  176. package/src/evasions/media.codecs/index.js +89 -0
  177. package/src/evasions/media.codecs/package.json +5 -0
  178. package/src/evasions/navigator.hardwareConcurrency/README.md +19 -0
  179. package/src/evasions/navigator.hardwareConcurrency/index.js +45 -0
  180. package/src/evasions/navigator.hardwareConcurrency/package.json +5 -0
  181. package/src/evasions/navigator.languages/README.md +17 -0
  182. package/src/evasions/navigator.languages/index.js +44 -0
  183. package/src/evasions/navigator.languages/package.json +5 -0
  184. package/src/evasions/navigator.permissions/README.md +16 -0
  185. package/src/evasions/navigator.permissions/index.js +66 -0
  186. package/src/evasions/navigator.permissions/package.json +5 -0
  187. package/src/evasions/navigator.plugins/README.md +24 -0
  188. package/src/evasions/navigator.plugins/data.json +48 -0
  189. package/src/evasions/navigator.plugins/functionMocks.js +47 -0
  190. package/src/evasions/navigator.plugins/index.js +98 -0
  191. package/src/evasions/navigator.plugins/magicArray.js +145 -0
  192. package/src/evasions/navigator.plugins/mimeTypes.js +18 -0
  193. package/src/evasions/navigator.plugins/package.json +5 -0
  194. package/src/evasions/navigator.plugins/plugins.js +18 -0
  195. package/src/evasions/navigator.vendor/README.md +36 -0
  196. package/src/evasions/navigator.vendor/index.js +64 -0
  197. package/src/evasions/navigator.vendor/package.json +5 -0
  198. package/src/evasions/navigator.webdriver/README.md +17 -0
  199. package/src/evasions/navigator.webdriver/index.js +48 -0
  200. package/src/evasions/navigator.webdriver/package.json +5 -0
  201. package/src/evasions/sourceurl/README.md +17 -0
  202. package/src/evasions/sourceurl/_fixtures/test.html +35 -0
  203. package/src/evasions/sourceurl/index.js +82 -0
  204. package/src/evasions/sourceurl/package.json +5 -0
  205. package/src/evasions/user-agent-override/README.md +53 -0
  206. package/src/evasions/user-agent-override/index.js +206 -0
  207. package/src/evasions/user-agent-override/package.json +5 -0
  208. package/src/evasions/webgl.vendor/README.md +20 -0
  209. package/src/evasions/webgl.vendor/index.js +57 -0
  210. package/src/evasions/webgl.vendor/package.json +5 -0
  211. package/src/evasions/window.outerdimensions/README.md +17 -0
  212. package/src/evasions/window.outerdimensions/index.js +42 -0
  213. package/src/evasions/window.outerdimensions/package.json +5 -0
  214. package/src/index.d.ts +111 -0
  215. package/src/index.ts +188 -0
  216. package/test/cat-and-mouse.test.ts +170 -0
  217. package/test/evasions/_utils/index.test.ts +710 -0
  218. package/test/evasions/chrome.app/index.test.ts +69 -0
  219. package/test/evasions/chrome.csi/index.test.ts +46 -0
  220. package/test/evasions/chrome.loadTimes/index.test.ts +61 -0
  221. package/test/evasions/chrome.runtime/index.test.ts +282 -0
  222. package/test/evasions/defaultArgs/index.test.ts +36 -0
  223. package/test/evasions/iframe.contentWindow/index.test.js +450 -0
  224. package/test/evasions/media.codecs/index.test.js +103 -0
  225. package/test/evasions/navigator.hardwareConcurrency/index.test.js +58 -0
  226. package/test/evasions/navigator.languages/index.test.js +101 -0
  227. package/test/evasions/navigator.permissions/index.test.js +104 -0
  228. package/test/evasions/navigator.plugins/index.test.js +55 -0
  229. package/test/evasions/navigator.plugins/mimeTypes.test.js +220 -0
  230. package/test/evasions/navigator.plugins/plugins.test.js +181 -0
  231. package/test/evasions/navigator.vendor/index.test.js +68 -0
  232. package/test/evasions/navigator.webdriver/index.test.js +47 -0
  233. package/test/evasions/sourceurl/_fixtures/test.html +35 -0
  234. package/test/evasions/sourceurl/index.test.js +62 -0
  235. package/test/evasions/user-agent-override/index.test.js +338 -0
  236. package/test/evasions/webgl.vendor/index.test.js +220 -0
  237. package/test/fixtures/dummy-with-service-worker.html +22 -0
  238. package/test/fixtures/dummy.html +11 -0
  239. package/test/fixtures/sw.js +1 -0
  240. package/test/fpscanner.test.ts +54 -0
  241. package/test/index.test.ts +51 -0
  242. package/test/service-worker.test.ts +112 -0
  243. package/test/stealth/_results/_thumbs/headful-chrome-stealth.js.png +0 -0
  244. package/test/stealth/_results/_thumbs/headful-chrome-vanilla.js.png +0 -0
  245. package/test/stealth/_results/_thumbs/headful-chromium-stealth.js.png +0 -0
  246. package/test/stealth/_results/_thumbs/headful-chromium-vanilla.js.png +0 -0
  247. package/test/stealth/_results/_thumbs/headless-chrome-stealth.js.png +0 -0
  248. package/test/stealth/_results/_thumbs/headless-chrome-vanilla.js.png +0 -0
  249. package/test/stealth/_results/_thumbs/headless-chromium-stealth.js.png +0 -0
  250. package/test/stealth/_results/_thumbs/headless-chromium-vanilla.js.png +0 -0
  251. package/test/stealth/_results/headful-chrome-stealth.js.png +0 -0
  252. package/test/stealth/_results/headful-chrome-vanilla.js.png +0 -0
  253. package/test/stealth/_results/headful-chromium-stealth.js.png +0 -0
  254. package/test/stealth/_results/headful-chromium-vanilla.js.png +0 -0
  255. package/test/stealth/_results/headless-chrome-stealth.js.png +0 -0
  256. package/test/stealth/_results/headless-chrome-vanilla.js.png +0 -0
  257. package/test/stealth/_results/headless-chromium-stealth.js.png +0 -0
  258. package/test/stealth/_results/headless-chromium-vanilla.js.png +0 -0
  259. package/test/stealth/headful-chrome-stealth.js +25 -0
  260. package/test/stealth/headful-chrome-vanilla.js +23 -0
  261. package/test/stealth/headful-chromium-stealth.js +22 -0
  262. package/test/stealth/headful-chromium-vanilla.js +20 -0
  263. package/test/stealth/headless-chrome-stealth.js +25 -0
  264. package/test/stealth/headless-chrome-vanilla.js +23 -0
  265. package/test/stealth/headless-chromium-stealth.js +22 -0
  266. package/test/stealth/headless-chromium-vanilla.js +20 -0
  267. package/test/util.js +82 -0
  268. package/tsconfig.json +10 -0
  269. package/tsconfig.tsbuildinfo +1 -0
  270. package/vitest.config.ts +28 -0
@@ -0,0 +1,64 @@
1
+ import { PuppeteerExtraPlugin } from '@zorilla/puppeteer-extra-plugin';
2
+
3
+ import withUtils from '../_utils/withUtils.js';
4
+
5
+ /**
6
+ * By default puppeteer will have a fixed `navigator.vendor` property.
7
+ *
8
+ * This plugin makes it possible to change this property.
9
+ *
10
+ * @example
11
+ * const puppeteer = require("puppeteer-extra")
12
+ *
13
+ * const StealthPlugin = require("puppeteer-extra-plugin-stealth")
14
+ * const stealth = StealthPlugin()
15
+ * // Remove this specific stealth plugin from the default set
16
+ * stealth.enabledEvasions.delete("navigator.vendor")
17
+ * puppeteer.use(stealth)
18
+ *
19
+ * // Stealth plugins are just regular `puppeteer-extra` plugins and can be added as such
20
+ * const NavigatorVendorPlugin = require("puppeteer-extra-plugin-stealth/evasions/navigator.vendor")
21
+ * const nvp = NavigatorVendorPlugin({ vendor: 'Apple Computer, Inc.' }) // Custom vendor
22
+ * puppeteer.use(nvp)
23
+ *
24
+ * @param {Object} [opts] - Options
25
+ * @param {string} [opts.vendor] - The vendor to use in `navigator.vendor` (default: `Google Inc.`)
26
+ *
27
+ */
28
+ class Plugin extends PuppeteerExtraPlugin {
29
+ constructor(opts = {}) {
30
+ super(opts);
31
+ }
32
+
33
+ get name() {
34
+ return 'stealth/evasions/navigator.vendor';
35
+ }
36
+
37
+ get defaults() {
38
+ return {
39
+ vendor: 'Google Inc.',
40
+ };
41
+ }
42
+
43
+ async onPageCreated(page) {
44
+ this.debug('onPageCreated', {
45
+ opts: this.opts,
46
+ });
47
+
48
+ await withUtils(page).evaluateOnNewDocument(
49
+ (utils, { opts }) => {
50
+ utils.replaceGetterWithProxy(
51
+ Object.getPrototypeOf(navigator),
52
+ 'vendor',
53
+ utils.makeHandler().getterValue(opts.vendor)
54
+ );
55
+ },
56
+ {
57
+ opts: this.opts,
58
+ }
59
+ );
60
+ } // onPageCreated
61
+ }
62
+
63
+ const defaultExport = opts => new Plugin(opts);
64
+ module.exports = defaultExport;
@@ -0,0 +1,5 @@
1
+ {
2
+ "private": true,
3
+ "type": "module",
4
+ "main": "index.js"
5
+ }
@@ -0,0 +1,17 @@
1
+ ## API
2
+
3
+
4
+ #### Table of Contents
5
+
6
+ - [class: Plugin](#class-plugin)
7
+
8
+ ### class: [Plugin](https://github.com/zorillajs/zorilla/blob/e6133619b051febed630ada35241664eba59b9fa/packages/puppeteer-extra-plugin-stealth/evasions/navigator.webdriver/index.js#L9-L23)
9
+
10
+ - `opts` (optional, default `{}`)
11
+
12
+ **Extends: PuppeteerExtraPlugin**
13
+
14
+ Pass the Webdriver Test.
15
+ Will delete `navigator.webdriver` property.
16
+
17
+ ---
@@ -0,0 +1,48 @@
1
+ import { PuppeteerExtraPlugin } from '@zorilla/puppeteer-extra-plugin';
2
+
3
+ /**
4
+ * Pass the Webdriver Test.
5
+ * Will delete `navigator.webdriver` property.
6
+ */
7
+ class Plugin extends PuppeteerExtraPlugin {
8
+ constructor(opts = {}) {
9
+ super(opts);
10
+ }
11
+
12
+ get name() {
13
+ return 'stealth/evasions/navigator.webdriver';
14
+ }
15
+
16
+ async onPageCreated(page) {
17
+ await page.evaluateOnNewDocument(() => {
18
+ if (navigator.webdriver === false) {
19
+ // Post Chrome 89.0.4339.0 and already good
20
+ } else if (navigator.webdriver === undefined) {
21
+ // Pre Chrome 89.0.4339.0 and already good
22
+ } else {
23
+ // Pre Chrome 88.0.4291.0 and needs patching
24
+ delete Object.getPrototypeOf(navigator).webdriver;
25
+ }
26
+ });
27
+ }
28
+
29
+ // Post Chrome 88.0.4291.0
30
+ // Note: this will add an infobar to Chrome with a warning that an unsupported flag is set
31
+ // To remove this bar on Linux, run: mkdir -p /etc/opt/chrome/policies/managed && echo '{ "CommandLineFlagSecurityWarningsEnabled": false }' > /etc/opt/chrome/policies/managed/managed_policies.json
32
+ async beforeLaunch(options) {
33
+ // If disable-blink-features is already passed, append the AutomationControlled switch
34
+ const idx = options.args.findIndex(arg =>
35
+ arg.startsWith('--disable-blink-features=')
36
+ );
37
+ if (idx !== -1) {
38
+ const arg = options.args[idx];
39
+ options.args[idx] = `${arg},AutomationControlled`;
40
+ } else {
41
+ options.args.push('--disable-blink-features=AutomationControlled');
42
+ }
43
+ }
44
+ }
45
+
46
+ export default function (pluginConfig) {
47
+ return new Plugin(pluginConfig);
48
+ }
@@ -0,0 +1,5 @@
1
+ {
2
+ "private": true,
3
+ "type": "module",
4
+ "main": "index.js"
5
+ }
@@ -0,0 +1,17 @@
1
+ ## API
2
+
3
+
4
+ #### Table of Contents
5
+
6
+ - [class: Plugin](#class-plugin)
7
+
8
+ ### class: [Plugin](https://github.com/zorillajs/zorilla/blob/e6133619b051febed630ada35241664eba59b9fa/packages/puppeteer-extra-plugin-stealth/evasions/sourceurl/index.js#L9-L58)
9
+
10
+ - `opts` (optional, default `{}`)
11
+
12
+ **Extends: PuppeteerExtraPlugin**
13
+
14
+ Strip sourceURL from scripts injected by puppeteer.
15
+ It can be used to identify the presence of pptr via stacktraces.
16
+
17
+ ---
@@ -0,0 +1,35 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <meta charset="utf-8" />
5
+ <title>Page Title</title>
6
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
7
+ </head>
8
+ <body>
9
+ <h1 id="result">Please use `document.querySelector`..</h1>
10
+
11
+ <script>
12
+ function test() {
13
+ const err = new Error('Test Error')
14
+ const isPptr = err.stack
15
+ .toString()
16
+ .includes('__puppeteer_evaluation_script')
17
+
18
+ document.getElementById('result').innerHTML = isPptr ? 'FAIL' : 'PASS'
19
+ console.log({ err, isPptr })
20
+ }
21
+
22
+ function overrideFunction(item) {
23
+ item.obj[item.propName] = ((orig) => function() {
24
+ test()
25
+ return orig.apply(this, arguments)
26
+ })(item.obj[item.propName])
27
+ }
28
+
29
+ overrideFunction({
30
+ propName: 'querySelector',
31
+ obj: document
32
+ })
33
+ </script>
34
+ </body>
35
+ </html>
@@ -0,0 +1,82 @@
1
+ import { PuppeteerExtraPlugin } from '@zorilla/puppeteer-extra-plugin';
2
+
3
+ /**
4
+ * Strip sourceURL from scripts injected by puppeteer.
5
+ * It can be used to identify the presence of pptr via stacktraces.
6
+ */
7
+ class Plugin extends PuppeteerExtraPlugin {
8
+ constructor(opts = {}) {
9
+ super(opts);
10
+ }
11
+
12
+ get name() {
13
+ return 'stealth/evasions/sourceurl';
14
+ }
15
+
16
+ async onPageCreated(page) {
17
+ const client =
18
+ page && typeof page._client === 'function'
19
+ ? page._client()
20
+ : page._client;
21
+ if (!client) {
22
+ this.debug('Warning, missing properties to intercept CDP.', { page });
23
+ return;
24
+ }
25
+
26
+ // Intercept CDP commands and strip identifying and unnecessary sourceURL
27
+ // https://github.com/puppeteer/puppeteer/blob/9b3005c105995cd267fdc7fb95b78aceab82cf0e/new-docs/puppeteer.cdpsession.md
28
+ const debug = this.debug;
29
+ client.send = ((originalMethod, context) =>
30
+ async function () {
31
+ const [method, paramArgs] = arguments || [];
32
+ const next = async () => {
33
+ try {
34
+ return await originalMethod.apply(context, [method, paramArgs]);
35
+ } catch (error) {
36
+ // This seems to happen sometimes when redirects cause other outstanding requests to be cut short
37
+ if (
38
+ error instanceof Error &&
39
+ error.message.includes(
40
+ `Protocol error (Network.getResponseBody): No resource with given identifier found`
41
+ )
42
+ ) {
43
+ debug(
44
+ `Caught and ignored an error about a missing network resource.`,
45
+ { error }
46
+ );
47
+ } else {
48
+ throw error;
49
+ }
50
+ }
51
+ };
52
+
53
+ if (!method || !paramArgs) {
54
+ return next();
55
+ }
56
+
57
+ // To find the methods/props in question check `_evaluateInternal` at:
58
+ // https://github.com/puppeteer/puppeteer/blob/main/src/common/ExecutionContext.ts#L186
59
+ const methodsToPatch = {
60
+ 'Runtime.evaluate': 'expression',
61
+ 'Runtime.callFunctionOn': 'functionDeclaration',
62
+ };
63
+ const SOURCE_URL_SUFFIX =
64
+ '//# sourceURL=__puppeteer_evaluation_script__';
65
+
66
+ if (!methodsToPatch[method] || !paramArgs[methodsToPatch[method]]) {
67
+ return next();
68
+ }
69
+
70
+ debug('Stripping sourceURL', { method });
71
+ paramArgs[methodsToPatch[method]] = paramArgs[
72
+ methodsToPatch[method]
73
+ ].replace(SOURCE_URL_SUFFIX, '');
74
+
75
+ return next();
76
+ })(client.send, client);
77
+ }
78
+ }
79
+
80
+ export default function (pluginConfig) {
81
+ return new Plugin(pluginConfig);
82
+ }
@@ -0,0 +1,5 @@
1
+ {
2
+ "private": true,
3
+ "type": "module",
4
+ "main": "index.js"
5
+ }
@@ -0,0 +1,53 @@
1
+ ## API
2
+
3
+
4
+ #### Table of Contents
5
+
6
+ - [class: Plugin](#class-plugin)
7
+
8
+ ### class: [Plugin](https://github.com/zorillajs/zorilla/blob/ab0047d1af7dc38412744abdb61bcfc35c42dc34/packages/puppeteer-extra-plugin-stealth/evasions/user-agent-override/index.js#L42-L203)
9
+
10
+ - `opts` **[Object](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object)?** Options (optional, default `{}`)
11
+ - `opts.userAgent` **[string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)?** The user agent to use (default: browser.userAgent())
12
+ - `opts.locale` **[string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)?** The locale to use in `Accept-Language` header and in `navigator.languages` (default: `en-US,en`)
13
+ - `opts.maskLinux` **[boolean](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean)?** Wether to hide Linux as platform in the user agent or not - true by default
14
+
15
+ **Extends: PuppeteerExtraPlugin**
16
+
17
+ Fixes the UserAgent info (composed of UA string, Accept-Language, Platform, and UA hints).
18
+
19
+ If you don't provide any values this plugin will default to using the regular UserAgent string (while stripping the headless part).
20
+ Default language is set to "en-US,en", the other settings match the UserAgent string.
21
+ If you are running on Linux, it will mask the settins to look like Windows. This behavior can be disabled with the `maskLinux` option.
22
+
23
+ By default puppeteer will not set a `Accept-Language` header in headless:
24
+ It's (theoretically) possible to fix that using either `page.setExtraHTTPHeaders` or a `--lang` launch arg.
25
+ Unfortunately `page.setExtraHTTPHeaders` will lowercase everything and launch args are not always available. :)
26
+
27
+ In addition, the `navigator.platform` property is always set to the host value, e.g. `Linux` which makes detection very easy.
28
+
29
+ Note: You cannot use the regular `page.setUserAgent()` puppeteer call in your code,
30
+ as it will reset the language and platform values you set with this plugin.
31
+
32
+ Example:
33
+
34
+ ```javascript
35
+ const puppeteer = require('@zorilla/puppeteer-extra')
36
+
37
+ const StealthPlugin = require('@zorilla/puppeteer-extra-plugin-stealth')
38
+ const stealth = StealthPlugin()
39
+ // Remove this specific stealth plugin from the default set
40
+ stealth.enabledEvasions.delete('user-agent-override')
41
+ puppeteer.use(stealth)
42
+
43
+ // Stealth plugins are just regular `puppeteer-extra` plugins and can be added as such
44
+ const UserAgentOverride = require('@zorilla/puppeteer-extra-plugin-stealth/evasions/user-agent-override')
45
+ // Define custom UA and locale
46
+ const ua = UserAgentOverride({
47
+ userAgent: 'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)',
48
+ locale: 'de-DE,de'
49
+ })
50
+ puppeteer.use(ua)
51
+ ```
52
+
53
+ ---
@@ -0,0 +1,206 @@
1
+ import { PuppeteerExtraPlugin } from '@zorilla/puppeteer-extra-plugin';
2
+
3
+ /**
4
+ * Fixes the UserAgent info (composed of UA string, Accept-Language, Platform, and UA hints).
5
+ *
6
+ * If you don't provide any values this plugin will default to using the regular UserAgent string (while stripping the headless part).
7
+ * Default language is set to "en-US,en", the other settings match the UserAgent string.
8
+ * If you are running on Linux, it will mask the settins to look like Windows. This behavior can be disabled with the `maskLinux` option.
9
+ *
10
+ * By default puppeteer will not set a `Accept-Language` header in headless:
11
+ * It's (theoretically) possible to fix that using either `page.setExtraHTTPHeaders` or a `--lang` launch arg.
12
+ * Unfortunately `page.setExtraHTTPHeaders` will lowercase everything and launch args are not always available. :)
13
+ *
14
+ * In addition, the `navigator.platform` property is always set to the host value, e.g. `Linux` which makes detection very easy.
15
+ *
16
+ * Note: You cannot use the regular `page.setUserAgent()` puppeteer call in your code,
17
+ * as it will reset the language and platform values you set with this plugin.
18
+ *
19
+ * @example
20
+ * const puppeteer = require("puppeteer-extra")
21
+ *
22
+ * const StealthPlugin = require("puppeteer-extra-plugin-stealth")
23
+ * const stealth = StealthPlugin()
24
+ * // Remove this specific stealth plugin from the default set
25
+ * stealth.enabledEvasions.delete("user-agent-override")
26
+ * puppeteer.use(stealth)
27
+ *
28
+ * // Stealth plugins are just regular `puppeteer-extra` plugins and can be added as such
29
+ * const UserAgentOverride = require("puppeteer-extra-plugin-stealth/evasions/user-agent-override")
30
+ * // Define custom UA and locale
31
+ * const ua = UserAgentOverride({ userAgent: "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)", locale: "de-DE,de" })
32
+ * puppeteer.use(ua)
33
+ *
34
+ * @param {Object} [opts] - Options
35
+ * @param {string} [opts.userAgent] - The user agent to use (default: browser.userAgent())
36
+ * @param {string} [opts.locale] - The locale to use in `Accept-Language` header and in `navigator.languages` (default: `en-US,en`)
37
+ * @param {boolean} [opts.maskLinux] - Wether to hide Linux as platform in the user agent or not - true by default
38
+ *
39
+ */
40
+ class Plugin extends PuppeteerExtraPlugin {
41
+ constructor(opts = {}) {
42
+ super(opts);
43
+
44
+ this._headless = false;
45
+ }
46
+
47
+ get name() {
48
+ return 'stealth/evasions/user-agent-override';
49
+ }
50
+
51
+ get dependencies() {
52
+ return new Set(['user-preferences']);
53
+ }
54
+
55
+ get defaults() {
56
+ return {
57
+ userAgent: null,
58
+ locale: 'en-US,en',
59
+ maskLinux: true,
60
+ };
61
+ }
62
+
63
+ async onPageCreated(page) {
64
+ // Determine the full user agent string, strip the "Headless" part
65
+ let ua =
66
+ this.opts.userAgent ||
67
+ (await page.browser().userAgent()).replace('HeadlessChrome/', 'Chrome/');
68
+
69
+ if (
70
+ this.opts.maskLinux &&
71
+ ua.includes('Linux') &&
72
+ !ua.includes('Android') // Skip Android user agents since they also contain Linux
73
+ ) {
74
+ ua = ua.replace(/\(([^)]+)\)/, '(Windows NT 10.0; Win64; x64)'); // Replace the first part in parentheses with Windows data
75
+ }
76
+
77
+ // Full version number from Chrome
78
+ const uaVersion = ua.includes('Chrome/')
79
+ ? ua.match(/Chrome\/([\d|.]+)/)[1]
80
+ : (await page.browser().version()).match(/\/([\d|.]+)/)[1];
81
+
82
+ // Get platform identifier (short or long version)
83
+ const _getPlatform = (extended = false) => {
84
+ if (ua.includes('Mac OS X')) {
85
+ return extended ? 'Mac OS X' : 'MacIntel';
86
+ } else if (ua.includes('Android')) {
87
+ return 'Android';
88
+ } else if (ua.includes('Linux')) {
89
+ return 'Linux';
90
+ } else {
91
+ return extended ? 'Windows' : 'Win32';
92
+ }
93
+ };
94
+
95
+ // Source in C++: https://source.chromium.org/chromium/chromium/src/+/master:components/embedder_support/user_agent_utils.cc;l=55-100
96
+ const _getBrands = () => {
97
+ const seed = uaVersion.split('.')[0]; // the major version number of Chrome
98
+
99
+ const order = [
100
+ [0, 1, 2],
101
+ [0, 2, 1],
102
+ [1, 0, 2],
103
+ [1, 2, 0],
104
+ [2, 0, 1],
105
+ [2, 1, 0],
106
+ ][seed % 6];
107
+ const escapedChars = [' ', ' ', ';'];
108
+
109
+ const greaseyBrand = `${escapedChars[order[0]]}Not${
110
+ escapedChars[order[1]]
111
+ }A${escapedChars[order[2]]}Brand`;
112
+
113
+ const greasedBrandVersionList = [];
114
+ greasedBrandVersionList[order[0]] = {
115
+ brand: greaseyBrand,
116
+ version: '99',
117
+ };
118
+ greasedBrandVersionList[order[1]] = {
119
+ brand: 'Chromium',
120
+ version: seed,
121
+ };
122
+ greasedBrandVersionList[order[2]] = {
123
+ brand: 'Google Chrome',
124
+ version: seed,
125
+ };
126
+
127
+ return greasedBrandVersionList;
128
+ };
129
+
130
+ // Return OS version
131
+ const _getPlatformVersion = () => {
132
+ if (ua.includes('Mac OS X ')) {
133
+ return ua.match(/Mac OS X ([^)]+)/)[1];
134
+ } else if (ua.includes('Android ')) {
135
+ return ua.match(/Android ([^;]+)/)[1];
136
+ } else if (ua.includes('Windows ')) {
137
+ return ua.match(/Windows .*?([\d|.]+);?/)[1];
138
+ } else {
139
+ return '';
140
+ }
141
+ };
142
+
143
+ // Get architecture, this seems to be empty on mobile and x86 on desktop
144
+ const _getPlatformArch = () => (_getMobile() ? '' : 'x86');
145
+
146
+ // Return the Android model, empty on desktop
147
+ const _getPlatformModel = () =>
148
+ _getMobile() ? ua.match(/Android.*?;\s([^)]+)/)[1] : '';
149
+
150
+ const _getMobile = () => ua.includes('Android');
151
+
152
+ const override = {
153
+ userAgent: ua,
154
+ platform: _getPlatform(),
155
+ userAgentMetadata: {
156
+ brands: _getBrands(),
157
+ fullVersion: uaVersion,
158
+ platform: _getPlatform(true),
159
+ platformVersion: _getPlatformVersion(),
160
+ architecture: _getPlatformArch(),
161
+ model: _getPlatformModel(),
162
+ mobile: _getMobile(),
163
+ },
164
+ };
165
+
166
+ // In case of headless, override the acceptLanguage in CDP.
167
+ // This is not preferred, as it messed up the header order.
168
+ // On headful, we set the user preference language setting instead.
169
+ if (this._headless) {
170
+ override.acceptLanguage = this.opts.locale || 'en-US,en';
171
+ }
172
+
173
+ this.debug('onPageCreated - Will set these user agent options', {
174
+ override,
175
+ opts: this.opts,
176
+ });
177
+
178
+ const client =
179
+ typeof page._client === 'function' ? page._client() : page._client;
180
+ client.send('Network.setUserAgentOverride', override);
181
+ }
182
+
183
+ async beforeLaunch(options) {
184
+ // Check if launched headless
185
+ this._headless = options.headless;
186
+ }
187
+
188
+ async beforeConnect() {
189
+ // Treat browsers using connect() as headless browsers
190
+ this._headless = true;
191
+ }
192
+
193
+ get data() {
194
+ return [
195
+ {
196
+ name: 'userPreferences',
197
+ value: {
198
+ intl: { accept_languages: this.opts.locale || 'en-US,en' },
199
+ },
200
+ },
201
+ ];
202
+ }
203
+ }
204
+
205
+ const defaultExport = opts => new Plugin(opts);
206
+ module.exports = defaultExport;
@@ -0,0 +1,5 @@
1
+ {
2
+ "private": true,
3
+ "type": "module",
4
+ "main": "index.js"
5
+ }
@@ -0,0 +1,20 @@
1
+ ## API
2
+
3
+
4
+ #### Table of Contents
5
+
6
+ - [class: Plugin](#class-plugin)
7
+
8
+ ### class: [Plugin](https://github.com/zorillajs/zorilla/blob/e6133619b051febed630ada35241664eba59b9fa/packages/puppeteer-extra-plugin-stealth/evasions/webgl.vendor/index.js#L17-L55)
9
+
10
+ - `opts` **[Object](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object)?** Options (optional, default `{}`)
11
+ - `opts.vendor` **[string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)?** The vendor string to use (default: `Intel Inc.`)
12
+ - `opts.renderer` **[string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)?** The renderer string (default: `Intel Iris OpenGL Engine`)
13
+
14
+ **Extends: PuppeteerExtraPlugin**
15
+
16
+ Fix WebGL Vendor/Renderer being set to Google in headless mode
17
+
18
+ Example data (Apple Retina MBP 13): {vendor: "Intel Inc.", renderer: "Intel(R) Iris(TM) Graphics 6100"}
19
+
20
+ ---
@@ -0,0 +1,57 @@
1
+ import { PuppeteerExtraPlugin } from '@zorilla/puppeteer-extra-plugin';
2
+
3
+ import withUtils from '../_utils/withUtils.js';
4
+
5
+ /**
6
+ * Fix WebGL Vendor/Renderer being set to Google in headless mode
7
+ *
8
+ * Example data (Apple Retina MBP 13): {vendor: "Intel Inc.", renderer: "Intel(R) Iris(TM) Graphics 6100"}
9
+ *
10
+ * @param {Object} [opts] - Options
11
+ * @param {string} [opts.vendor] - The vendor string to use (default: `Intel Inc.`)
12
+ * @param {string} [opts.renderer] - The renderer string (default: `Intel Iris OpenGL Engine`)
13
+ */
14
+ class Plugin extends PuppeteerExtraPlugin {
15
+ constructor(opts = {}) {
16
+ super(opts);
17
+ }
18
+
19
+ get name() {
20
+ return 'stealth/evasions/webgl.vendor';
21
+ }
22
+
23
+ /* global WebGLRenderingContext WebGL2RenderingContext */
24
+ async onPageCreated(page) {
25
+ await withUtils(page).evaluateOnNewDocument((utils, opts) => {
26
+ const getParameterProxyHandler = {
27
+ apply: (target, ctx, args) => {
28
+ const param = (args || [])[0];
29
+ const result = utils.cache.Reflect.apply(target, ctx, args);
30
+ // UNMASKED_VENDOR_WEBGL
31
+ if (param === 37445) {
32
+ return opts.vendor || 'Intel Inc.'; // default in headless: Google Inc.
33
+ }
34
+ // UNMASKED_RENDERER_WEBGL
35
+ if (param === 37446) {
36
+ return opts.renderer || 'Intel Iris OpenGL Engine'; // default in headless: Google SwiftShader
37
+ }
38
+ return result;
39
+ },
40
+ };
41
+
42
+ // There's more than one WebGL rendering context
43
+ // https://developer.mozilla.org/en-US/docs/Web/API/WebGL2RenderingContext#Browser_compatibility
44
+ // To find out the original values here: Object.getOwnPropertyDescriptors(WebGLRenderingContext.prototype.getParameter)
45
+ const addProxy = (obj, propName) => {
46
+ utils.replaceWithProxy(obj, propName, getParameterProxyHandler);
47
+ };
48
+ // For whatever weird reason loops don't play nice with Object.defineProperty, here's the next best thing:
49
+ addProxy(WebGLRenderingContext.prototype, 'getParameter');
50
+ addProxy(WebGL2RenderingContext.prototype, 'getParameter');
51
+ }, this.opts);
52
+ }
53
+ }
54
+
55
+ export default function (pluginConfig) {
56
+ return new Plugin(pluginConfig);
57
+ }
@@ -0,0 +1,5 @@
1
+ {
2
+ "private": true,
3
+ "type": "module",
4
+ "main": "index.js"
5
+ }
@@ -0,0 +1,17 @@
1
+ ## API
2
+
3
+
4
+ #### Table of Contents
5
+
6
+ - [class: Plugin](#class-plugin)
7
+
8
+ ### class: [Plugin](https://github.com/zorillajs/zorilla/blob/e6133619b051febed630ada35241664eba59b9fa/packages/puppeteer-extra-plugin-stealth/evasions/window.outerdimensions/index.js#L9-L40)
9
+
10
+ - `opts` (optional, default `{}`)
11
+
12
+ **Extends: PuppeteerExtraPlugin**
13
+
14
+ Fix missing window.outerWidth/window.outerHeight in headless mode
15
+ Will also set the viewport to match window size, unless specified by user
16
+
17
+ ---