@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.
- package/.claude/settings.local.json +21 -0
- package/LICENSE +21 -0
- package/README.md +324 -0
- package/dist/evasions/README.md +13 -0
- package/dist/evasions/_template/README.md +18 -0
- package/dist/evasions/_template/index.d.ts +13 -0
- package/dist/evasions/_template/index.d.ts.map +1 -0
- package/dist/evasions/_template/index.js +26 -0
- package/dist/evasions/_template/index.js.map +1 -0
- package/dist/evasions/_template/package.json +5 -0
- package/dist/evasions/_utils/README.md +287 -0
- package/dist/evasions/_utils/index.d.ts +238 -0
- package/dist/evasions/_utils/index.d.ts.map +1 -0
- package/dist/evasions/_utils/index.js +588 -0
- package/dist/evasions/_utils/index.js.map +1 -0
- package/dist/evasions/_utils/withUtils.d.ts +12 -0
- package/dist/evasions/_utils/withUtils.d.ts.map +1 -0
- package/dist/evasions/_utils/withUtils.js +47 -0
- package/dist/evasions/_utils/withUtils.js.map +1 -0
- package/dist/evasions/chrome.app/README.md +16 -0
- package/dist/evasions/chrome.app/index.d.ts +11 -0
- package/dist/evasions/chrome.app/index.d.ts.map +1 -0
- package/dist/evasions/chrome.app/index.js +97 -0
- package/dist/evasions/chrome.app/index.js.map +1 -0
- package/dist/evasions/chrome.app/package.json +5 -0
- package/dist/evasions/chrome.csi/README.md +29 -0
- package/dist/evasions/chrome.csi/index.d.ts +25 -0
- package/dist/evasions/chrome.csi/index.d.ts.map +1 -0
- package/dist/evasions/chrome.csi/index.js +69 -0
- package/dist/evasions/chrome.csi/index.js.map +1 -0
- package/dist/evasions/chrome.csi/package.json +5 -0
- package/dist/evasions/chrome.loadTimes/README.md +27 -0
- package/dist/evasions/chrome.loadTimes/index.d.ts +23 -0
- package/dist/evasions/chrome.loadTimes/index.d.ts.map +1 -0
- package/dist/evasions/chrome.loadTimes/index.js +163 -0
- package/dist/evasions/chrome.loadTimes/index.js.map +1 -0
- package/dist/evasions/chrome.loadTimes/package.json +5 -0
- package/dist/evasions/chrome.runtime/README.md +32 -0
- package/dist/evasions/chrome.runtime/index.d.ts +14 -0
- package/dist/evasions/chrome.runtime/index.d.ts.map +1 -0
- package/dist/evasions/chrome.runtime/index.js +252 -0
- package/dist/evasions/chrome.runtime/index.js.map +1 -0
- package/dist/evasions/chrome.runtime/package.json +5 -0
- package/dist/evasions/chrome.runtime/staticData.json +41 -0
- package/dist/evasions/defaultArgs/README.md +17 -0
- package/dist/evasions/defaultArgs/index.d.ts +2 -0
- package/dist/evasions/defaultArgs/index.d.ts.map +1 -0
- package/dist/evasions/defaultArgs/index.js +43 -0
- package/dist/evasions/defaultArgs/index.js.map +1 -0
- package/dist/evasions/defaultArgs/package.json +5 -0
- package/dist/evasions/iframe.contentWindow/README.md +19 -0
- package/dist/evasions/iframe.contentWindow/index.d.ts +15 -0
- package/dist/evasions/iframe.contentWindow/index.d.ts.map +1 -0
- package/dist/evasions/iframe.contentWindow/index.js +132 -0
- package/dist/evasions/iframe.contentWindow/index.js.map +1 -0
- package/dist/evasions/iframe.contentWindow/package.json +5 -0
- package/dist/evasions/media.codecs/README.md +38 -0
- package/dist/evasions/media.codecs/index.d.ts +12 -0
- package/dist/evasions/media.codecs/index.d.ts.map +1 -0
- package/dist/evasions/media.codecs/index.js +89 -0
- package/dist/evasions/media.codecs/index.js.map +1 -0
- package/dist/evasions/media.codecs/package.json +5 -0
- package/dist/evasions/navigator.hardwareConcurrency/README.md +19 -0
- package/dist/evasions/navigator.hardwareConcurrency/index.d.ts +2 -0
- package/dist/evasions/navigator.hardwareConcurrency/index.d.ts.map +1 -0
- package/dist/evasions/navigator.hardwareConcurrency/index.js +45 -0
- package/dist/evasions/navigator.hardwareConcurrency/index.js.map +1 -0
- package/dist/evasions/navigator.hardwareConcurrency/package.json +5 -0
- package/dist/evasions/navigator.languages/README.md +17 -0
- package/dist/evasions/navigator.languages/index.d.ts +2 -0
- package/dist/evasions/navigator.languages/index.d.ts.map +1 -0
- package/dist/evasions/navigator.languages/index.js +44 -0
- package/dist/evasions/navigator.languages/index.js.map +1 -0
- package/dist/evasions/navigator.languages/package.json +5 -0
- package/dist/evasions/navigator.permissions/README.md +16 -0
- package/dist/evasions/navigator.permissions/index.d.ts +2 -0
- package/dist/evasions/navigator.permissions/index.d.ts.map +1 -0
- package/dist/evasions/navigator.permissions/index.js +66 -0
- package/dist/evasions/navigator.permissions/index.js.map +1 -0
- package/dist/evasions/navigator.permissions/package.json +5 -0
- package/dist/evasions/navigator.plugins/README.md +24 -0
- package/dist/evasions/navigator.plugins/data.json +48 -0
- package/dist/evasions/navigator.plugins/functionMocks.d.ts +9 -0
- package/dist/evasions/navigator.plugins/functionMocks.d.ts.map +1 -0
- package/dist/evasions/navigator.plugins/functionMocks.js +47 -0
- package/dist/evasions/navigator.plugins/functionMocks.js.map +1 -0
- package/dist/evasions/navigator.plugins/index.d.ts +19 -0
- package/dist/evasions/navigator.plugins/index.d.ts.map +1 -0
- package/dist/evasions/navigator.plugins/index.js +98 -0
- package/dist/evasions/navigator.plugins/index.js.map +1 -0
- package/dist/evasions/navigator.plugins/magicArray.d.ts +2 -0
- package/dist/evasions/navigator.plugins/magicArray.d.ts.map +1 -0
- package/dist/evasions/navigator.plugins/magicArray.js +145 -0
- package/dist/evasions/navigator.plugins/magicArray.js.map +1 -0
- package/dist/evasions/navigator.plugins/mimeTypes.d.ts +2 -0
- package/dist/evasions/navigator.plugins/mimeTypes.d.ts.map +1 -0
- package/dist/evasions/navigator.plugins/mimeTypes.js +18 -0
- package/dist/evasions/navigator.plugins/mimeTypes.js.map +1 -0
- package/dist/evasions/navigator.plugins/package.json +5 -0
- package/dist/evasions/navigator.plugins/plugins.d.ts +2 -0
- package/dist/evasions/navigator.plugins/plugins.d.ts.map +1 -0
- package/dist/evasions/navigator.plugins/plugins.js +18 -0
- package/dist/evasions/navigator.plugins/plugins.js.map +1 -0
- package/dist/evasions/navigator.vendor/README.md +36 -0
- package/dist/evasions/navigator.vendor/index.d.ts +2 -0
- package/dist/evasions/navigator.vendor/index.d.ts.map +1 -0
- package/dist/evasions/navigator.vendor/index.js +64 -0
- package/dist/evasions/navigator.vendor/index.js.map +1 -0
- package/dist/evasions/navigator.vendor/package.json +5 -0
- package/dist/evasions/navigator.webdriver/README.md +17 -0
- package/dist/evasions/navigator.webdriver/index.d.ts +13 -0
- package/dist/evasions/navigator.webdriver/index.d.ts.map +1 -0
- package/dist/evasions/navigator.webdriver/index.js +48 -0
- package/dist/evasions/navigator.webdriver/index.js.map +1 -0
- package/dist/evasions/navigator.webdriver/package.json +5 -0
- package/dist/evasions/sourceurl/README.md +17 -0
- package/dist/evasions/sourceurl/_fixtures/test.html +35 -0
- package/dist/evasions/sourceurl/index.d.ts +12 -0
- package/dist/evasions/sourceurl/index.d.ts.map +1 -0
- package/dist/evasions/sourceurl/index.js +82 -0
- package/dist/evasions/sourceurl/index.js.map +1 -0
- package/dist/evasions/sourceurl/package.json +5 -0
- package/dist/evasions/user-agent-override/README.md +53 -0
- package/dist/evasions/user-agent-override/index.d.ts +2 -0
- package/dist/evasions/user-agent-override/index.d.ts.map +1 -0
- package/dist/evasions/user-agent-override/index.js +206 -0
- package/dist/evasions/user-agent-override/index.js.map +1 -0
- package/dist/evasions/user-agent-override/package.json +5 -0
- package/dist/evasions/webgl.vendor/README.md +20 -0
- package/dist/evasions/webgl.vendor/index.d.ts +17 -0
- package/dist/evasions/webgl.vendor/index.d.ts.map +1 -0
- package/dist/evasions/webgl.vendor/index.js +57 -0
- package/dist/evasions/webgl.vendor/index.js.map +1 -0
- package/dist/evasions/webgl.vendor/package.json +5 -0
- package/dist/evasions/window.outerdimensions/README.md +17 -0
- package/dist/evasions/window.outerdimensions/index.d.ts +13 -0
- package/dist/evasions/window.outerdimensions/index.d.ts.map +1 -0
- package/dist/evasions/window.outerdimensions/index.js +42 -0
- package/dist/evasions/window.outerdimensions/index.js.map +1 -0
- package/dist/evasions/window.outerdimensions/package.json +5 -0
- package/dist/index.d.ts +130 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +164 -0
- package/dist/index.js.map +1 -0
- package/examples/detect-headless.js +95 -0
- package/examples/test1.js +20 -0
- package/examples/test2.js +25 -0
- package/package.json +70 -0
- package/src/evasions/README.md +13 -0
- package/src/evasions/_template/README.md +18 -0
- package/src/evasions/_template/index.js +26 -0
- package/src/evasions/_template/package.json +5 -0
- package/src/evasions/_utils/README.md +287 -0
- package/src/evasions/_utils/index.js +588 -0
- package/src/evasions/_utils/withUtils.js +47 -0
- package/src/evasions/chrome.app/README.md +16 -0
- package/src/evasions/chrome.app/index.js +97 -0
- package/src/evasions/chrome.app/package.json +5 -0
- package/src/evasions/chrome.csi/README.md +29 -0
- package/src/evasions/chrome.csi/index.js +69 -0
- package/src/evasions/chrome.csi/package.json +5 -0
- package/src/evasions/chrome.loadTimes/README.md +27 -0
- package/src/evasions/chrome.loadTimes/index.js +163 -0
- package/src/evasions/chrome.loadTimes/package.json +5 -0
- package/src/evasions/chrome.runtime/README.md +32 -0
- package/src/evasions/chrome.runtime/index.js +252 -0
- package/src/evasions/chrome.runtime/package.json +5 -0
- package/src/evasions/chrome.runtime/staticData.json +41 -0
- package/src/evasions/defaultArgs/README.md +17 -0
- package/src/evasions/defaultArgs/index.js +43 -0
- package/src/evasions/defaultArgs/package.json +5 -0
- package/src/evasions/iframe.contentWindow/README.md +19 -0
- package/src/evasions/iframe.contentWindow/index.js +132 -0
- package/src/evasions/iframe.contentWindow/package.json +5 -0
- package/src/evasions/media.codecs/README.md +38 -0
- package/src/evasions/media.codecs/index.js +89 -0
- package/src/evasions/media.codecs/package.json +5 -0
- package/src/evasions/navigator.hardwareConcurrency/README.md +19 -0
- package/src/evasions/navigator.hardwareConcurrency/index.js +45 -0
- package/src/evasions/navigator.hardwareConcurrency/package.json +5 -0
- package/src/evasions/navigator.languages/README.md +17 -0
- package/src/evasions/navigator.languages/index.js +44 -0
- package/src/evasions/navigator.languages/package.json +5 -0
- package/src/evasions/navigator.permissions/README.md +16 -0
- package/src/evasions/navigator.permissions/index.js +66 -0
- package/src/evasions/navigator.permissions/package.json +5 -0
- package/src/evasions/navigator.plugins/README.md +24 -0
- package/src/evasions/navigator.plugins/data.json +48 -0
- package/src/evasions/navigator.plugins/functionMocks.js +47 -0
- package/src/evasions/navigator.plugins/index.js +98 -0
- package/src/evasions/navigator.plugins/magicArray.js +145 -0
- package/src/evasions/navigator.plugins/mimeTypes.js +18 -0
- package/src/evasions/navigator.plugins/package.json +5 -0
- package/src/evasions/navigator.plugins/plugins.js +18 -0
- package/src/evasions/navigator.vendor/README.md +36 -0
- package/src/evasions/navigator.vendor/index.js +64 -0
- package/src/evasions/navigator.vendor/package.json +5 -0
- package/src/evasions/navigator.webdriver/README.md +17 -0
- package/src/evasions/navigator.webdriver/index.js +48 -0
- package/src/evasions/navigator.webdriver/package.json +5 -0
- package/src/evasions/sourceurl/README.md +17 -0
- package/src/evasions/sourceurl/_fixtures/test.html +35 -0
- package/src/evasions/sourceurl/index.js +82 -0
- package/src/evasions/sourceurl/package.json +5 -0
- package/src/evasions/user-agent-override/README.md +53 -0
- package/src/evasions/user-agent-override/index.js +206 -0
- package/src/evasions/user-agent-override/package.json +5 -0
- package/src/evasions/webgl.vendor/README.md +20 -0
- package/src/evasions/webgl.vendor/index.js +57 -0
- package/src/evasions/webgl.vendor/package.json +5 -0
- package/src/evasions/window.outerdimensions/README.md +17 -0
- package/src/evasions/window.outerdimensions/index.js +42 -0
- package/src/evasions/window.outerdimensions/package.json +5 -0
- package/src/index.d.ts +111 -0
- package/src/index.ts +188 -0
- package/test/cat-and-mouse.test.ts +170 -0
- package/test/evasions/_utils/index.test.ts +710 -0
- package/test/evasions/chrome.app/index.test.ts +69 -0
- package/test/evasions/chrome.csi/index.test.ts +46 -0
- package/test/evasions/chrome.loadTimes/index.test.ts +61 -0
- package/test/evasions/chrome.runtime/index.test.ts +282 -0
- package/test/evasions/defaultArgs/index.test.ts +36 -0
- package/test/evasions/iframe.contentWindow/index.test.js +450 -0
- package/test/evasions/media.codecs/index.test.js +103 -0
- package/test/evasions/navigator.hardwareConcurrency/index.test.js +58 -0
- package/test/evasions/navigator.languages/index.test.js +101 -0
- package/test/evasions/navigator.permissions/index.test.js +104 -0
- package/test/evasions/navigator.plugins/index.test.js +55 -0
- package/test/evasions/navigator.plugins/mimeTypes.test.js +220 -0
- package/test/evasions/navigator.plugins/plugins.test.js +181 -0
- package/test/evasions/navigator.vendor/index.test.js +68 -0
- package/test/evasions/navigator.webdriver/index.test.js +47 -0
- package/test/evasions/sourceurl/_fixtures/test.html +35 -0
- package/test/evasions/sourceurl/index.test.js +62 -0
- package/test/evasions/user-agent-override/index.test.js +338 -0
- package/test/evasions/webgl.vendor/index.test.js +220 -0
- package/test/fixtures/dummy-with-service-worker.html +22 -0
- package/test/fixtures/dummy.html +11 -0
- package/test/fixtures/sw.js +1 -0
- package/test/fpscanner.test.ts +54 -0
- package/test/index.test.ts +51 -0
- package/test/service-worker.test.ts +112 -0
- package/test/stealth/_results/_thumbs/headful-chrome-stealth.js.png +0 -0
- package/test/stealth/_results/_thumbs/headful-chrome-vanilla.js.png +0 -0
- package/test/stealth/_results/_thumbs/headful-chromium-stealth.js.png +0 -0
- package/test/stealth/_results/_thumbs/headful-chromium-vanilla.js.png +0 -0
- package/test/stealth/_results/_thumbs/headless-chrome-stealth.js.png +0 -0
- package/test/stealth/_results/_thumbs/headless-chrome-vanilla.js.png +0 -0
- package/test/stealth/_results/_thumbs/headless-chromium-stealth.js.png +0 -0
- package/test/stealth/_results/_thumbs/headless-chromium-vanilla.js.png +0 -0
- package/test/stealth/_results/headful-chrome-stealth.js.png +0 -0
- package/test/stealth/_results/headful-chrome-vanilla.js.png +0 -0
- package/test/stealth/_results/headful-chromium-stealth.js.png +0 -0
- package/test/stealth/_results/headful-chromium-vanilla.js.png +0 -0
- package/test/stealth/_results/headless-chrome-stealth.js.png +0 -0
- package/test/stealth/_results/headless-chrome-vanilla.js.png +0 -0
- package/test/stealth/_results/headless-chromium-stealth.js.png +0 -0
- package/test/stealth/_results/headless-chromium-vanilla.js.png +0 -0
- package/test/stealth/headful-chrome-stealth.js +25 -0
- package/test/stealth/headful-chrome-vanilla.js +23 -0
- package/test/stealth/headful-chromium-stealth.js +22 -0
- package/test/stealth/headful-chromium-vanilla.js +20 -0
- package/test/stealth/headless-chrome-stealth.js +25 -0
- package/test/stealth/headless-chrome-vanilla.js +23 -0
- package/test/stealth/headless-chromium-stealth.js +22 -0
- package/test/stealth/headless-chromium-vanilla.js +20 -0
- package/test/util.js +82 -0
- package/tsconfig.json +10 -0
- package/tsconfig.tsbuildinfo +1 -0
- package/vitest.config.ts +28 -0
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { PuppeteerExtraPlugin } from '@zorilla/puppeteer-extra-plugin';
|
|
2
|
+
|
|
3
|
+
import withUtils from '../_utils/withUtils.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Set the hardwareConcurrency to 4 (optionally configurable with `hardwareConcurrency`)
|
|
7
|
+
*
|
|
8
|
+
* @see https://arh.antoinevastel.com/reports/stats/osName_hardwareConcurrency_report.html
|
|
9
|
+
*
|
|
10
|
+
* @param {Object} [opts] - Options
|
|
11
|
+
* @param {number} [opts.hardwareConcurrency] - The value to use in `navigator.hardwareConcurrency` (default: `4`)
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
class Plugin extends PuppeteerExtraPlugin {
|
|
15
|
+
constructor(opts = {}) {
|
|
16
|
+
super(opts);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
get name() {
|
|
20
|
+
return 'stealth/evasions/navigator.hardwareConcurrency';
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
get defaults() {
|
|
24
|
+
return {
|
|
25
|
+
hardwareConcurrency: 4,
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
async onPageCreated(page) {
|
|
30
|
+
await withUtils(page).evaluateOnNewDocument(
|
|
31
|
+
(utils, { opts }) => {
|
|
32
|
+
utils.replaceGetterWithProxy(
|
|
33
|
+
Object.getPrototypeOf(navigator),
|
|
34
|
+
'hardwareConcurrency',
|
|
35
|
+
utils.makeHandler().getterValue(opts.hardwareConcurrency)
|
|
36
|
+
);
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
opts: this.opts,
|
|
40
|
+
}
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
module.exports = pluginConfig => new Plugin(pluginConfig);
|
|
@@ -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.languages/index.js#L11-L28)
|
|
9
|
+
|
|
10
|
+
- `opts` **[Object](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object)?** Options (optional, default `{}`)
|
|
11
|
+
- `opts.languages` **[Array](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array)<[string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)>?** The languages to use (default: `['en-US', 'en']`)
|
|
12
|
+
|
|
13
|
+
**Extends: PuppeteerExtraPlugin**
|
|
14
|
+
|
|
15
|
+
Pass the Languages Test. Allows setting custom languages.
|
|
16
|
+
|
|
17
|
+
---
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { PuppeteerExtraPlugin } from '@zorilla/puppeteer-extra-plugin';
|
|
2
|
+
import withUtils from '../_utils/withUtils.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Pass the Languages Test. Allows setting custom languages.
|
|
6
|
+
*
|
|
7
|
+
* @param {Object} [opts] - Options
|
|
8
|
+
* @param {Array<string>} [opts.languages] - The languages to use (default: `['en-US', 'en']`)
|
|
9
|
+
*/
|
|
10
|
+
class Plugin extends PuppeteerExtraPlugin {
|
|
11
|
+
constructor(opts = {}) {
|
|
12
|
+
super(opts);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
get name() {
|
|
16
|
+
return 'stealth/evasions/navigator.languages';
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
get defaults() {
|
|
20
|
+
return {
|
|
21
|
+
languages: [], // Empty default, otherwise this would be merged with user defined array override
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
async onPageCreated(page) {
|
|
26
|
+
await withUtils(page).evaluateOnNewDocument(
|
|
27
|
+
(utils, { opts }) => {
|
|
28
|
+
const languages = opts.languages.length
|
|
29
|
+
? opts.languages
|
|
30
|
+
: ['en-US', 'en'];
|
|
31
|
+
utils.replaceGetterWithProxy(
|
|
32
|
+
Object.getPrototypeOf(navigator),
|
|
33
|
+
'languages',
|
|
34
|
+
utils.makeHandler().getterValue(Object.freeze([...languages]))
|
|
35
|
+
);
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
opts: this.opts,
|
|
39
|
+
}
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
module.exports = pluginConfig => new Plugin(pluginConfig);
|
|
@@ -0,0 +1,16 @@
|
|
|
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.permissions/index.js#L12-L45)
|
|
9
|
+
|
|
10
|
+
- `opts` (optional, default `{}`)
|
|
11
|
+
|
|
12
|
+
**Extends: PuppeteerExtraPlugin**
|
|
13
|
+
|
|
14
|
+
Pass the Permissions Test.
|
|
15
|
+
|
|
16
|
+
---
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { PuppeteerExtraPlugin } from '@zorilla/puppeteer-extra-plugin';
|
|
2
|
+
|
|
3
|
+
import withUtils from '../_utils/withUtils.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Fix `Notification.permission` behaving weirdly in headless mode
|
|
7
|
+
*
|
|
8
|
+
* @see https://bugs.chromium.org/p/chromium/issues/detail?id=1052332
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
class Plugin extends PuppeteerExtraPlugin {
|
|
12
|
+
constructor(opts = {}) {
|
|
13
|
+
super(opts);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
get name() {
|
|
17
|
+
return 'stealth/evasions/navigator.permissions';
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/* global Notification Permissions PermissionStatus */
|
|
21
|
+
async onPageCreated(page) {
|
|
22
|
+
await withUtils(page).evaluateOnNewDocument((utils, _opts) => {
|
|
23
|
+
const isSecure = document.location.protocol.startsWith('https');
|
|
24
|
+
|
|
25
|
+
// In headful on secure origins the permission should be "default", not "denied"
|
|
26
|
+
if (isSecure) {
|
|
27
|
+
utils.replaceGetterWithProxy(Notification, 'permission', {
|
|
28
|
+
apply() {
|
|
29
|
+
return 'default';
|
|
30
|
+
},
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Another weird behavior:
|
|
35
|
+
// On insecure origins in headful the state is "denied",
|
|
36
|
+
// whereas in headless it's "prompt"
|
|
37
|
+
if (!isSecure) {
|
|
38
|
+
const handler = {
|
|
39
|
+
apply(_target, _ctx, args) {
|
|
40
|
+
const param = (args || [])[0];
|
|
41
|
+
|
|
42
|
+
const isNotifications =
|
|
43
|
+
param?.name && param.name === 'notifications';
|
|
44
|
+
if (!isNotifications) {
|
|
45
|
+
return utils.cache.Reflect.apply(...arguments);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return Promise.resolve(
|
|
49
|
+
Object.setPrototypeOf(
|
|
50
|
+
{
|
|
51
|
+
state: 'denied',
|
|
52
|
+
onchange: null,
|
|
53
|
+
},
|
|
54
|
+
PermissionStatus.prototype
|
|
55
|
+
)
|
|
56
|
+
);
|
|
57
|
+
},
|
|
58
|
+
};
|
|
59
|
+
// Note: Don't use `Object.getPrototypeOf` here
|
|
60
|
+
utils.replaceWithProxy(Permissions.prototype, 'query', handler);
|
|
61
|
+
}
|
|
62
|
+
}, this.opts);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
module.exports = pluginConfig => new Plugin(pluginConfig);
|
|
@@ -0,0 +1,24 @@
|
|
|
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.plugins/index.js#L26-L88)
|
|
9
|
+
|
|
10
|
+
- `opts` (optional, default `{}`)
|
|
11
|
+
|
|
12
|
+
**Extends: PuppeteerExtraPlugin**
|
|
13
|
+
|
|
14
|
+
In headless mode `navigator.mimeTypes` and `navigator.plugins` are empty.
|
|
15
|
+
This plugin emulates both of these with functional mocks to match regular headful Chrome.
|
|
16
|
+
|
|
17
|
+
Note: mimeTypes and plugins cross-reference each other, so it makes sense to do them at the same time.
|
|
18
|
+
|
|
19
|
+
- **See: <https://developer.mozilla.org/en-US/docs/Web/API/NavigatorPlugins/mimeTypes>**
|
|
20
|
+
- **See: <https://developer.mozilla.org/en-US/docs/Web/API/MimeTypeArray>**
|
|
21
|
+
- **See: <https://developer.mozilla.org/en-US/docs/Web/API/NavigatorPlugins/plugins>**
|
|
22
|
+
- **See: <https://developer.mozilla.org/en-US/docs/Web/API/PluginArray>**
|
|
23
|
+
|
|
24
|
+
---
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
{
|
|
2
|
+
"mimeTypes": [
|
|
3
|
+
{
|
|
4
|
+
"type": "application/pdf",
|
|
5
|
+
"suffixes": "pdf",
|
|
6
|
+
"description": "Portable Document Format",
|
|
7
|
+
"__pluginName": "PDF Viewer"
|
|
8
|
+
},
|
|
9
|
+
{
|
|
10
|
+
"type": "text/pdf",
|
|
11
|
+
"suffixes": "pdf",
|
|
12
|
+
"description": "Portable Document Format",
|
|
13
|
+
"__pluginName": "PDF Viewer"
|
|
14
|
+
}
|
|
15
|
+
],
|
|
16
|
+
"plugins": [
|
|
17
|
+
{
|
|
18
|
+
"name": "PDF Viewer",
|
|
19
|
+
"filename": "internal-pdf-viewer",
|
|
20
|
+
"description": "Portable Document Format",
|
|
21
|
+
"__mimeTypes": ["application/pdf", "text/pdf"]
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
"name": "Chrome PDF Viewer",
|
|
25
|
+
"filename": "mhjfbmdgcfjbbpaeojofohoefgiehjai",
|
|
26
|
+
"description": "Portable Document Format",
|
|
27
|
+
"__mimeTypes": ["application/pdf", "text/pdf"]
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
"name": "Chromium PDF Viewer",
|
|
31
|
+
"filename": "chromium-pdf-viewer",
|
|
32
|
+
"description": "Portable Document Format",
|
|
33
|
+
"__mimeTypes": ["application/pdf", "text/pdf"]
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
"name": "Microsoft Edge PDF Viewer",
|
|
37
|
+
"filename": "edge-pdf-viewer",
|
|
38
|
+
"description": "Portable Document Format",
|
|
39
|
+
"__mimeTypes": ["application/pdf", "text/pdf"]
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
"name": "WebKit built-in PDF",
|
|
43
|
+
"filename": "webkit-pdf-plugin",
|
|
44
|
+
"description": "Portable Document Format",
|
|
45
|
+
"__mimeTypes": ["application/pdf", "text/pdf"]
|
|
46
|
+
}
|
|
47
|
+
]
|
|
48
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `navigator.{plugins,mimeTypes}` share similar custom functions to look up properties
|
|
3
|
+
*
|
|
4
|
+
* Note: This is meant to be run in the context of the page.
|
|
5
|
+
*/
|
|
6
|
+
export const generateFunctionMocks =
|
|
7
|
+
utils => (proto, itemMainProp, dataArray) => ({
|
|
8
|
+
/** Returns the MimeType object with the specified index. */
|
|
9
|
+
item: utils.createProxy(proto.item, {
|
|
10
|
+
apply(_target, _ctx, args) {
|
|
11
|
+
if (!args.length) {
|
|
12
|
+
throw new TypeError(
|
|
13
|
+
`Failed to execute 'item' on '${
|
|
14
|
+
proto[Symbol.toStringTag]
|
|
15
|
+
}': 1 argument required, but only 0 present.`
|
|
16
|
+
);
|
|
17
|
+
}
|
|
18
|
+
// Special behavior alert:
|
|
19
|
+
// - Vanilla tries to cast strings to Numbers (only integers!) and use them as property index lookup
|
|
20
|
+
// - If anything else than an integer (including as string) is provided it will return the first entry
|
|
21
|
+
const isInteger = args[0] && Number.isInteger(Number(args[0])); // Cast potential string to number first, then check for integer
|
|
22
|
+
// Note: Vanilla never returns `undefined`
|
|
23
|
+
return (isInteger ? dataArray[Number(args[0])] : dataArray[0]) || null;
|
|
24
|
+
},
|
|
25
|
+
}),
|
|
26
|
+
/** Returns the MimeType object with the specified name. */
|
|
27
|
+
namedItem: utils.createProxy(proto.namedItem, {
|
|
28
|
+
apply(_target, _ctx, args) {
|
|
29
|
+
if (!args.length) {
|
|
30
|
+
throw new TypeError(
|
|
31
|
+
`Failed to execute 'namedItem' on '${
|
|
32
|
+
proto[Symbol.toStringTag]
|
|
33
|
+
}': 1 argument required, but only 0 present.`
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
return dataArray.find(mt => mt[itemMainProp] === args[0]) || null; // Not `undefined`!
|
|
37
|
+
},
|
|
38
|
+
}),
|
|
39
|
+
/** Does nothing and shall return nothing */
|
|
40
|
+
refresh: proto.refresh
|
|
41
|
+
? utils.createProxy(proto.refresh, {
|
|
42
|
+
apply(_target, _ctx, _args) {
|
|
43
|
+
return undefined;
|
|
44
|
+
},
|
|
45
|
+
})
|
|
46
|
+
: undefined,
|
|
47
|
+
});
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { PuppeteerExtraPlugin } from '@zorilla/puppeteer-extra-plugin';
|
|
2
|
+
|
|
3
|
+
import utils from '../_utils/index.js';
|
|
4
|
+
|
|
5
|
+
import withUtils from '../_utils/withUtils.js';
|
|
6
|
+
import data from './data.json' with { type: 'json' };
|
|
7
|
+
import { generateFunctionMocks } from './functionMocks.js';
|
|
8
|
+
import { generateMagicArray } from './magicArray.js';
|
|
9
|
+
import { generateMimeTypeArray } from './mimeTypes.js';
|
|
10
|
+
import { generatePluginArray } from './plugins.js';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* In headless mode `navigator.mimeTypes` and `navigator.plugins` are empty.
|
|
14
|
+
* This plugin emulates both of these with functional mocks to match regular headful Chrome.
|
|
15
|
+
*
|
|
16
|
+
* Note: mimeTypes and plugins cross-reference each other, so it makes sense to do them at the same time.
|
|
17
|
+
*
|
|
18
|
+
* @see https://developer.mozilla.org/en-US/docs/Web/API/NavigatorPlugins/mimeTypes
|
|
19
|
+
* @see https://developer.mozilla.org/en-US/docs/Web/API/MimeTypeArray
|
|
20
|
+
* @see https://developer.mozilla.org/en-US/docs/Web/API/NavigatorPlugins/plugins
|
|
21
|
+
* @see https://developer.mozilla.org/en-US/docs/Web/API/PluginArray
|
|
22
|
+
*/
|
|
23
|
+
class Plugin extends PuppeteerExtraPlugin {
|
|
24
|
+
constructor(opts = {}) {
|
|
25
|
+
super(opts);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
get name() {
|
|
29
|
+
return 'stealth/evasions/navigator.plugins';
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
async onPageCreated(page) {
|
|
33
|
+
await withUtils(page).evaluateOnNewDocument(
|
|
34
|
+
(utils, { fns, data }) => {
|
|
35
|
+
fns = utils.materializeFns(fns);
|
|
36
|
+
|
|
37
|
+
// That means we're running headful
|
|
38
|
+
const hasPlugins = 'plugins' in navigator && navigator.plugins.length;
|
|
39
|
+
if (hasPlugins) {
|
|
40
|
+
return; // nothing to do here
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const mimeTypes = fns.generateMimeTypeArray(utils, fns)(data.mimeTypes);
|
|
44
|
+
const plugins = fns.generatePluginArray(utils, fns)(data.plugins);
|
|
45
|
+
|
|
46
|
+
// Plugin and MimeType cross-reference each other, let's do that now
|
|
47
|
+
// Note: We're looping through `data.plugins` here, not the generated `plugins`
|
|
48
|
+
for (const pluginData of data.plugins) {
|
|
49
|
+
pluginData.__mimeTypes.forEach((type, index) => {
|
|
50
|
+
plugins[pluginData.name][index] = mimeTypes[type];
|
|
51
|
+
|
|
52
|
+
Object.defineProperty(plugins[pluginData.name], type, {
|
|
53
|
+
value: mimeTypes[type],
|
|
54
|
+
writable: false,
|
|
55
|
+
enumerable: false, // Not enumerable
|
|
56
|
+
configurable: true,
|
|
57
|
+
});
|
|
58
|
+
Object.defineProperty(mimeTypes[type], 'enabledPlugin', {
|
|
59
|
+
value:
|
|
60
|
+
type === 'application/x-pnacl'
|
|
61
|
+
? mimeTypes['application/x-nacl'].enabledPlugin // these reference the same plugin, so we need to re-use the Proxy in order to avoid leaks
|
|
62
|
+
: new Proxy(plugins[pluginData.name], {}), // Prevent circular references
|
|
63
|
+
writable: false,
|
|
64
|
+
enumerable: false, // Important: `JSON.stringify(navigator.plugins)`
|
|
65
|
+
configurable: true,
|
|
66
|
+
});
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const patchNavigator = (name, value) =>
|
|
71
|
+
utils.replaceProperty(Object.getPrototypeOf(navigator), name, {
|
|
72
|
+
get() {
|
|
73
|
+
return value;
|
|
74
|
+
},
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
patchNavigator('mimeTypes', mimeTypes);
|
|
78
|
+
patchNavigator('plugins', plugins);
|
|
79
|
+
|
|
80
|
+
// All done
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
// We pass some functions to evaluate to structure the code more nicely
|
|
84
|
+
fns: utils.stringifyFns({
|
|
85
|
+
generateMimeTypeArray,
|
|
86
|
+
generatePluginArray,
|
|
87
|
+
generateMagicArray,
|
|
88
|
+
generateFunctionMocks,
|
|
89
|
+
}),
|
|
90
|
+
data,
|
|
91
|
+
}
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export default function (pluginConfig) {
|
|
97
|
+
return new Plugin(pluginConfig);
|
|
98
|
+
}
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
/* global MimeType MimeTypeArray Plugin PluginArray */
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Generate a convincing and functional MimeType or Plugin array from scratch.
|
|
5
|
+
* They're so similar that it makes sense to use a single generator here.
|
|
6
|
+
*
|
|
7
|
+
* Note: This is meant to be run in the context of the page.
|
|
8
|
+
*/
|
|
9
|
+
export const generateMagicArray =
|
|
10
|
+
(utils, fns) =>
|
|
11
|
+
(
|
|
12
|
+
dataArray = [],
|
|
13
|
+
proto = MimeTypeArray.prototype,
|
|
14
|
+
itemProto = MimeType.prototype,
|
|
15
|
+
itemMainProp = 'type'
|
|
16
|
+
) => {
|
|
17
|
+
// Quick helper to set props with the same descriptors vanilla is using
|
|
18
|
+
const defineProp = (obj, prop, value) =>
|
|
19
|
+
Object.defineProperty(obj, prop, {
|
|
20
|
+
value,
|
|
21
|
+
writable: false,
|
|
22
|
+
enumerable: false, // Important for mimeTypes & plugins: `JSON.stringify(navigator.mimeTypes)`
|
|
23
|
+
configurable: true,
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
// Loop over our fake data and construct items
|
|
27
|
+
const makeItem = data => {
|
|
28
|
+
const item = {};
|
|
29
|
+
for (const prop of Object.keys(data)) {
|
|
30
|
+
if (prop.startsWith('__')) {
|
|
31
|
+
continue;
|
|
32
|
+
}
|
|
33
|
+
defineProp(item, prop, data[prop]);
|
|
34
|
+
}
|
|
35
|
+
return patchItem(item, data);
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
const patchItem = (item, data) => {
|
|
39
|
+
let descriptor = Object.getOwnPropertyDescriptors(item);
|
|
40
|
+
|
|
41
|
+
// Special case: Plugins have a magic length property which is not enumerable
|
|
42
|
+
// e.g. `navigator.plugins[i].length` should always be the length of the assigned mimeTypes
|
|
43
|
+
if (itemProto === Plugin.prototype) {
|
|
44
|
+
descriptor = {
|
|
45
|
+
...descriptor,
|
|
46
|
+
length: {
|
|
47
|
+
value: data.__mimeTypes.length,
|
|
48
|
+
writable: false,
|
|
49
|
+
enumerable: false,
|
|
50
|
+
configurable: true, // Important to be able to use the ownKeys trap in a Proxy to strip `length`
|
|
51
|
+
},
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// We need to spoof a specific `MimeType` or `Plugin` object
|
|
56
|
+
const obj = Object.create(itemProto, descriptor);
|
|
57
|
+
|
|
58
|
+
// Virtually all property keys are not enumerable in vanilla
|
|
59
|
+
const blacklist = [...Object.keys(data), 'length', 'enabledPlugin'];
|
|
60
|
+
return new Proxy(obj, {
|
|
61
|
+
ownKeys(target) {
|
|
62
|
+
return Reflect.ownKeys(target).filter(k => !blacklist.includes(k));
|
|
63
|
+
},
|
|
64
|
+
getOwnPropertyDescriptor(target, prop) {
|
|
65
|
+
if (blacklist.includes(prop)) {
|
|
66
|
+
return undefined;
|
|
67
|
+
}
|
|
68
|
+
return Reflect.getOwnPropertyDescriptor(target, prop);
|
|
69
|
+
},
|
|
70
|
+
});
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
const magicArray = [];
|
|
74
|
+
|
|
75
|
+
// Loop through our fake data and use that to create convincing entities
|
|
76
|
+
dataArray.forEach(data => {
|
|
77
|
+
magicArray.push(makeItem(data));
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
// Add direct property access based on types (e.g. `obj['application/pdf']`) afterwards
|
|
81
|
+
magicArray.forEach(entry => {
|
|
82
|
+
defineProp(magicArray, entry[itemMainProp], entry);
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
// This is the best way to fake the type to make sure this is false: `Array.isArray(navigator.mimeTypes)`
|
|
86
|
+
const magicArrayObj = Object.create(proto, {
|
|
87
|
+
...Object.getOwnPropertyDescriptors(magicArray),
|
|
88
|
+
|
|
89
|
+
// There's one ugly quirk we unfortunately need to take care of:
|
|
90
|
+
// The `MimeTypeArray` prototype has an enumerable `length` property,
|
|
91
|
+
// but headful Chrome will still skip it when running `Object.getOwnPropertyNames(navigator.mimeTypes)`.
|
|
92
|
+
// To strip it we need to make it first `configurable` and can then overlay a Proxy with an `ownKeys` trap.
|
|
93
|
+
length: {
|
|
94
|
+
value: magicArray.length,
|
|
95
|
+
writable: false,
|
|
96
|
+
enumerable: false,
|
|
97
|
+
configurable: true, // Important to be able to use the ownKeys trap in a Proxy to strip `length`
|
|
98
|
+
},
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
// Generate our functional function mocks :-)
|
|
102
|
+
const functionMocks = fns.generateFunctionMocks(utils)(
|
|
103
|
+
proto,
|
|
104
|
+
itemMainProp,
|
|
105
|
+
magicArray
|
|
106
|
+
);
|
|
107
|
+
|
|
108
|
+
// We need to overlay our custom object with a JS Proxy
|
|
109
|
+
const magicArrayObjProxy = new Proxy(magicArrayObj, {
|
|
110
|
+
get(_target, key = '') {
|
|
111
|
+
// Redirect function calls to our custom proxied versions mocking the vanilla behavior
|
|
112
|
+
if (key === 'item') {
|
|
113
|
+
return functionMocks.item;
|
|
114
|
+
}
|
|
115
|
+
if (key === 'namedItem') {
|
|
116
|
+
return functionMocks.namedItem;
|
|
117
|
+
}
|
|
118
|
+
if (proto === PluginArray.prototype && key === 'refresh') {
|
|
119
|
+
return functionMocks.refresh;
|
|
120
|
+
}
|
|
121
|
+
// Everything else can pass through as normal
|
|
122
|
+
return utils.cache.Reflect.get(...arguments);
|
|
123
|
+
},
|
|
124
|
+
ownKeys(_target) {
|
|
125
|
+
// There are a couple of quirks where the original property demonstrates "magical" behavior that makes no sense
|
|
126
|
+
// This can be witnessed when calling `Object.getOwnPropertyNames(navigator.mimeTypes)` and the absense of `length`
|
|
127
|
+
// My guess is that it has to do with the recent change of not allowing data enumeration and this being implemented weirdly
|
|
128
|
+
// For that reason we just completely fake the available property names based on our data to match what regular Chrome is doing
|
|
129
|
+
// Specific issues when not patching this: `length` property is available, direct `types` props (e.g. `obj['application/pdf']`) are missing
|
|
130
|
+
const keys = [];
|
|
131
|
+
const typeProps = magicArray.map(mt => mt[itemMainProp]);
|
|
132
|
+
typeProps.forEach((_, i) => keys.push(`${i}`));
|
|
133
|
+
typeProps.forEach(propName => keys.push(propName));
|
|
134
|
+
return keys;
|
|
135
|
+
},
|
|
136
|
+
getOwnPropertyDescriptor(target, prop) {
|
|
137
|
+
if (prop === 'length') {
|
|
138
|
+
return undefined;
|
|
139
|
+
}
|
|
140
|
+
return Reflect.getOwnPropertyDescriptor(target, prop);
|
|
141
|
+
},
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
return magicArrayObjProxy;
|
|
145
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/* global MimeType MimeTypeArray */
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Generate a convincing and functional MimeTypeArray (with mime types) from scratch.
|
|
5
|
+
*
|
|
6
|
+
* Note: This is meant to be run in the context of the page.
|
|
7
|
+
*
|
|
8
|
+
* @see https://developer.mozilla.org/en-US/docs/Web/API/NavigatorPlugins/mimeTypes
|
|
9
|
+
* @see https://developer.mozilla.org/en-US/docs/Web/API/MimeTypeArray
|
|
10
|
+
*/
|
|
11
|
+
export const generateMimeTypeArray = (utils, fns) => mimeTypesData => {
|
|
12
|
+
return fns.generateMagicArray(utils, fns)(
|
|
13
|
+
mimeTypesData,
|
|
14
|
+
MimeTypeArray.prototype,
|
|
15
|
+
MimeType.prototype,
|
|
16
|
+
'type'
|
|
17
|
+
);
|
|
18
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/* global Plugin PluginArray */
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Generate a convincing and functional PluginArray (with plugins) from scratch.
|
|
5
|
+
*
|
|
6
|
+
* Note: This is meant to be run in the context of the page.
|
|
7
|
+
*
|
|
8
|
+
* @see https://developer.mozilla.org/en-US/docs/Web/API/NavigatorPlugins/plugins
|
|
9
|
+
* @see https://developer.mozilla.org/en-US/docs/Web/API/PluginArray
|
|
10
|
+
*/
|
|
11
|
+
export const generatePluginArray = (utils, fns) => pluginsData => {
|
|
12
|
+
return fns.generateMagicArray(utils, fns)(
|
|
13
|
+
pluginsData,
|
|
14
|
+
PluginArray.prototype,
|
|
15
|
+
Plugin.prototype,
|
|
16
|
+
'name'
|
|
17
|
+
);
|
|
18
|
+
};
|
|
@@ -0,0 +1,36 @@
|
|
|
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.vendor/index.js#L28-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 to use in `navigator.vendor` (default: `Google Inc.`)
|
|
12
|
+
|
|
13
|
+
**Extends: PuppeteerExtraPlugin**
|
|
14
|
+
|
|
15
|
+
By default puppeteer will have a fixed `navigator.vendor` property.
|
|
16
|
+
|
|
17
|
+
This plugin makes it possible to change this property.
|
|
18
|
+
|
|
19
|
+
Example:
|
|
20
|
+
|
|
21
|
+
```javascript
|
|
22
|
+
const puppeteer = require('@zorilla/puppeteer-extra')
|
|
23
|
+
|
|
24
|
+
const StealthPlugin = require('@zorilla/puppeteer-extra-plugin-stealth')
|
|
25
|
+
const stealth = StealthPlugin()
|
|
26
|
+
// Remove this specific stealth plugin from the default set
|
|
27
|
+
stealth.enabledEvasions.delete('navigator.vendor')
|
|
28
|
+
puppeteer.use(stealth)
|
|
29
|
+
|
|
30
|
+
// Stealth plugins are just regular `puppeteer-extra` plugins and can be added as such
|
|
31
|
+
const NavigatorVendorPlugin = require('@zorilla/puppeteer-extra-plugin-stealth/evasions/navigator.vendor')
|
|
32
|
+
const nvp = NavigatorVendorPlugin({ vendor: 'Apple Computer, Inc.' }) // Custom vendor
|
|
33
|
+
puppeteer.use(nvp)
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
---
|