@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,97 @@
|
|
|
1
|
+
import { PuppeteerExtraPlugin } from '@zorilla/puppeteer-extra-plugin';
|
|
2
|
+
import withUtils from '../_utils/withUtils.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Mock the `chrome.app` object if not available (e.g. when running headless).
|
|
6
|
+
*/
|
|
7
|
+
class Plugin extends PuppeteerExtraPlugin {
|
|
8
|
+
constructor(opts = {}) {
|
|
9
|
+
super(opts);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
get name() {
|
|
13
|
+
return 'stealth/evasions/chrome.app';
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
async onPageCreated(page) {
|
|
17
|
+
await withUtils(page).evaluateOnNewDocument(utils => {
|
|
18
|
+
if (!window.chrome) {
|
|
19
|
+
// Use the exact property descriptor found in headful Chrome
|
|
20
|
+
// fetch it via `Object.getOwnPropertyDescriptor(window, 'chrome')`
|
|
21
|
+
Object.defineProperty(window, 'chrome', {
|
|
22
|
+
writable: true,
|
|
23
|
+
enumerable: true,
|
|
24
|
+
configurable: false, // note!
|
|
25
|
+
value: {}, // We'll extend that later
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// That means we're running headful and don't need to mock anything
|
|
30
|
+
if ('app' in window.chrome) {
|
|
31
|
+
return; // Nothing to do here
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const makeError = {
|
|
35
|
+
ErrorInInvocation: fn => {
|
|
36
|
+
const err = new TypeError(`Error in invocation of app.${fn}()`);
|
|
37
|
+
return utils.stripErrorWithAnchor(
|
|
38
|
+
err,
|
|
39
|
+
`at ${fn} (eval at <anonymous>`
|
|
40
|
+
);
|
|
41
|
+
},
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
// There's a some static data in that property which doesn't seem to change,
|
|
45
|
+
// we should periodically check for updates: `JSON.stringify(window.app, null, 2)`
|
|
46
|
+
const STATIC_DATA = JSON.parse(
|
|
47
|
+
`
|
|
48
|
+
{
|
|
49
|
+
"isInstalled": false,
|
|
50
|
+
"InstallState": {
|
|
51
|
+
"DISABLED": "disabled",
|
|
52
|
+
"INSTALLED": "installed",
|
|
53
|
+
"NOT_INSTALLED": "not_installed"
|
|
54
|
+
},
|
|
55
|
+
"RunningState": {
|
|
56
|
+
"CANNOT_RUN": "cannot_run",
|
|
57
|
+
"READY_TO_RUN": "ready_to_run",
|
|
58
|
+
"RUNNING": "running"
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
`.trim()
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
window.chrome.app = {
|
|
65
|
+
...STATIC_DATA,
|
|
66
|
+
|
|
67
|
+
get isInstalled() {
|
|
68
|
+
return false;
|
|
69
|
+
},
|
|
70
|
+
|
|
71
|
+
getDetails: function getDetails() {
|
|
72
|
+
if (arguments.length) {
|
|
73
|
+
throw makeError.ErrorInInvocation(`getDetails`);
|
|
74
|
+
}
|
|
75
|
+
return null;
|
|
76
|
+
},
|
|
77
|
+
getIsInstalled: function getIsInstalled() {
|
|
78
|
+
if (arguments.length) {
|
|
79
|
+
throw makeError.ErrorInInvocation(`getIsInstalled`);
|
|
80
|
+
}
|
|
81
|
+
return false;
|
|
82
|
+
},
|
|
83
|
+
runningState: function runningState() {
|
|
84
|
+
if (arguments.length) {
|
|
85
|
+
throw makeError.ErrorInInvocation(`runningState`);
|
|
86
|
+
}
|
|
87
|
+
return 'cannot_run';
|
|
88
|
+
},
|
|
89
|
+
};
|
|
90
|
+
utils.patchToStringNested(window.chrome.app);
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export default function (pluginConfig) {
|
|
96
|
+
return new Plugin(pluginConfig);
|
|
97
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
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/chrome.csi/index.js#L25-L70)
|
|
9
|
+
|
|
10
|
+
- `opts` (optional, default `{}`)
|
|
11
|
+
|
|
12
|
+
**Extends: PuppeteerExtraPlugin**
|
|
13
|
+
|
|
14
|
+
Mock the `chrome.csi` function if not available (e.g. when running headless).
|
|
15
|
+
It's a deprecated (but unfortunately still existing) chrome specific API to fetch browser timings.
|
|
16
|
+
|
|
17
|
+
Internally chromium switched the implementation to use the WebPerformance API,
|
|
18
|
+
so we can do the same to create a fully functional mock. :-)
|
|
19
|
+
|
|
20
|
+
Note: We're using the deprecated PerformanceTiming API instead of the new Navigation Timing Level 2 API on purpopse.
|
|
21
|
+
|
|
22
|
+
- **See: <https://bugs.chromium.org/p/chromium/issues/detail?id=113048>**
|
|
23
|
+
- **See: <https://codereview.chromium.org/2456293003/>**
|
|
24
|
+
- **See: <https://developers.google.com/web/updates/2017/12/chrome-loadtimes-deprecated>**
|
|
25
|
+
- **See: <https://developer.mozilla.org/en-US/docs/Web/API/PerformanceTiming>**
|
|
26
|
+
- **See: <https://source.chromium.org/chromium/chromium/src/+/master:chrome/renderer/loadtimes_extension_bindings.cc;l=124?q=loadtimes&ss=chromium>**
|
|
27
|
+
- **See: `chrome.loadTimes` evasion**
|
|
28
|
+
|
|
29
|
+
---
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { PuppeteerExtraPlugin } from '@zorilla/puppeteer-extra-plugin';
|
|
2
|
+
|
|
3
|
+
import withUtils from '../_utils/withUtils.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Mock the `chrome.csi` function if not available (e.g. when running headless).
|
|
7
|
+
* It's a deprecated (but unfortunately still existing) chrome specific API to fetch browser timings.
|
|
8
|
+
*
|
|
9
|
+
* Internally chromium switched the implementation to use the WebPerformance API,
|
|
10
|
+
* so we can do the same to create a fully functional mock. :-)
|
|
11
|
+
*
|
|
12
|
+
* Note: We're using the deprecated PerformanceTiming API instead of the new Navigation Timing Level 2 API on purpopse.
|
|
13
|
+
*
|
|
14
|
+
* @see https://bugs.chromium.org/p/chromium/issues/detail?id=113048
|
|
15
|
+
* @see https://codereview.chromium.org/2456293003/
|
|
16
|
+
* @see https://developers.google.com/web/updates/2017/12/chrome-loadtimes-deprecated
|
|
17
|
+
* @see https://developer.mozilla.org/en-US/docs/Web/API/PerformanceTiming
|
|
18
|
+
* @see https://source.chromium.org/chromium/chromium/src/+/master:chrome/renderer/loadtimes_extension_bindings.cc;l=124?q=loadtimes&ss=chromium
|
|
19
|
+
* @see `chrome.loadTimes` evasion
|
|
20
|
+
*
|
|
21
|
+
*/
|
|
22
|
+
class Plugin extends PuppeteerExtraPlugin {
|
|
23
|
+
constructor(opts = {}) {
|
|
24
|
+
super(opts);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
get name() {
|
|
28
|
+
return 'stealth/evasions/chrome.csi';
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
async onPageCreated(page) {
|
|
32
|
+
await withUtils(page).evaluateOnNewDocument(utils => {
|
|
33
|
+
if (!window.chrome) {
|
|
34
|
+
// Use the exact property descriptor found in headful Chrome
|
|
35
|
+
// fetch it via `Object.getOwnPropertyDescriptor(window, 'chrome')`
|
|
36
|
+
Object.defineProperty(window, 'chrome', {
|
|
37
|
+
writable: true,
|
|
38
|
+
enumerable: true,
|
|
39
|
+
configurable: false, // note!
|
|
40
|
+
value: {}, // We'll extend that later
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// That means we're running headful and don't need to mock anything
|
|
45
|
+
if ('csi' in window.chrome) {
|
|
46
|
+
return; // Nothing to do here
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Check that the Navigation Timing API v1 is available, we need that
|
|
50
|
+
if (!window.performance || !window.performance.timing) {
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const { timing } = window.performance;
|
|
55
|
+
|
|
56
|
+
window.chrome.csi = () => ({
|
|
57
|
+
onloadT: timing.domContentLoadedEventEnd,
|
|
58
|
+
startE: timing.navigationStart,
|
|
59
|
+
pageT: Date.now() - timing.navigationStart,
|
|
60
|
+
tran: 15, // Transition type or something
|
|
61
|
+
});
|
|
62
|
+
utils.patchToString(window.chrome.csi);
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export default function (pluginConfig) {
|
|
68
|
+
return new Plugin(pluginConfig);
|
|
69
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
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/chrome.loadTimes/index.js#L23-L164)
|
|
9
|
+
|
|
10
|
+
- `opts` (optional, default `{}`)
|
|
11
|
+
|
|
12
|
+
**Extends: PuppeteerExtraPlugin**
|
|
13
|
+
|
|
14
|
+
Mock the `chrome.loadTimes` function if not available (e.g. when running headless).
|
|
15
|
+
It's a deprecated (but unfortunately still existing) chrome specific API to fetch browser timings and connection info.
|
|
16
|
+
|
|
17
|
+
Internally chromium switched the implementation to use the WebPerformance API,
|
|
18
|
+
so we can do the same to create a fully functional mock. :-)
|
|
19
|
+
|
|
20
|
+
Note: We're using the deprecated PerformanceTiming API instead of the new Navigation Timing Level 2 API on purpopse.
|
|
21
|
+
|
|
22
|
+
- **See: <https://developers.google.com/web/updates/2017/12/chrome-loadtimes-deprecated>**
|
|
23
|
+
- **See: <https://developer.mozilla.org/en-US/docs/Web/API/PerformanceTiming>**
|
|
24
|
+
- **See: <https://source.chromium.org/chromium/chromium/src/+/master:chrome/renderer/loadtimes_extension_bindings.cc;l=124?q=loadtimes&ss=chromium>**
|
|
25
|
+
- **See: `chrome.csi` evasion**
|
|
26
|
+
|
|
27
|
+
---
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import { PuppeteerExtraPlugin } from '@zorilla/puppeteer-extra-plugin';
|
|
2
|
+
|
|
3
|
+
import withUtils from '../_utils/withUtils.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Mock the `chrome.loadTimes` function if not available (e.g. when running headless).
|
|
7
|
+
* It's a deprecated (but unfortunately still existing) chrome specific API to fetch browser timings and connection info.
|
|
8
|
+
*
|
|
9
|
+
* Internally chromium switched the implementation to use the WebPerformance API,
|
|
10
|
+
* so we can do the same to create a fully functional mock. :-)
|
|
11
|
+
*
|
|
12
|
+
* Note: We're using the deprecated PerformanceTiming API instead of the new Navigation Timing Level 2 API on purpopse.
|
|
13
|
+
*
|
|
14
|
+
* @see https://developers.google.com/web/updates/2017/12/chrome-loadtimes-deprecated
|
|
15
|
+
* @see https://developer.mozilla.org/en-US/docs/Web/API/PerformanceTiming
|
|
16
|
+
* @see https://source.chromium.org/chromium/chromium/src/+/master:chrome/renderer/loadtimes_extension_bindings.cc;l=124?q=loadtimes&ss=chromium
|
|
17
|
+
* @see `chrome.csi` evasion
|
|
18
|
+
*
|
|
19
|
+
*/
|
|
20
|
+
class Plugin extends PuppeteerExtraPlugin {
|
|
21
|
+
constructor(opts = {}) {
|
|
22
|
+
super(opts);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
get name() {
|
|
26
|
+
return 'stealth/evasions/chrome.loadTimes';
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
async onPageCreated(page) {
|
|
30
|
+
await withUtils(page).evaluateOnNewDocument(
|
|
31
|
+
(utils, { opts }) => {
|
|
32
|
+
if (!window.chrome) {
|
|
33
|
+
// Use the exact property descriptor found in headful Chrome
|
|
34
|
+
// fetch it via `Object.getOwnPropertyDescriptor(window, 'chrome')`
|
|
35
|
+
Object.defineProperty(window, 'chrome', {
|
|
36
|
+
writable: true,
|
|
37
|
+
enumerable: true,
|
|
38
|
+
configurable: false, // note!
|
|
39
|
+
value: {}, // We'll extend that later
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// That means we're running headful and don't need to mock anything
|
|
44
|
+
if ('loadTimes' in window.chrome) {
|
|
45
|
+
return; // Nothing to do here
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Check that the Navigation Timing API v1 + v2 is available, we need that
|
|
49
|
+
if (
|
|
50
|
+
!window.performance ||
|
|
51
|
+
!window.performance.timing ||
|
|
52
|
+
!window.PerformancePaintTiming
|
|
53
|
+
) {
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const { performance } = window;
|
|
58
|
+
|
|
59
|
+
// Some stuff is not available on about:blank as it requires a navigation to occur,
|
|
60
|
+
// let's harden the code to not fail then:
|
|
61
|
+
const ntEntryFallback = {
|
|
62
|
+
nextHopProtocol: 'h2',
|
|
63
|
+
type: 'other',
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
// The API exposes some funky info regarding the connection
|
|
67
|
+
const protocolInfo = {
|
|
68
|
+
get connectionInfo() {
|
|
69
|
+
const ntEntry =
|
|
70
|
+
performance.getEntriesByType('navigation')[0] || ntEntryFallback;
|
|
71
|
+
return ntEntry.nextHopProtocol;
|
|
72
|
+
},
|
|
73
|
+
get npnNegotiatedProtocol() {
|
|
74
|
+
// NPN is deprecated in favor of ALPN, but this implementation returns the
|
|
75
|
+
// HTTP/2 or HTTP2+QUIC/39 requests negotiated via ALPN.
|
|
76
|
+
const ntEntry =
|
|
77
|
+
performance.getEntriesByType('navigation')[0] || ntEntryFallback;
|
|
78
|
+
return ['h2', 'hq'].includes(ntEntry.nextHopProtocol)
|
|
79
|
+
? ntEntry.nextHopProtocol
|
|
80
|
+
: 'unknown';
|
|
81
|
+
},
|
|
82
|
+
get navigationType() {
|
|
83
|
+
const ntEntry =
|
|
84
|
+
performance.getEntriesByType('navigation')[0] || ntEntryFallback;
|
|
85
|
+
return ntEntry.type;
|
|
86
|
+
},
|
|
87
|
+
get wasAlternateProtocolAvailable() {
|
|
88
|
+
// The Alternate-Protocol header is deprecated in favor of Alt-Svc
|
|
89
|
+
// (https://www.mnot.net/blog/2016/03/09/alt-svc), so technically this
|
|
90
|
+
// should always return false.
|
|
91
|
+
return false;
|
|
92
|
+
},
|
|
93
|
+
get wasFetchedViaSpdy() {
|
|
94
|
+
// SPDY is deprecated in favor of HTTP/2, but this implementation returns
|
|
95
|
+
// true for HTTP/2 or HTTP2+QUIC/39 as well.
|
|
96
|
+
const ntEntry =
|
|
97
|
+
performance.getEntriesByType('navigation')[0] || ntEntryFallback;
|
|
98
|
+
return ['h2', 'hq'].includes(ntEntry.nextHopProtocol);
|
|
99
|
+
},
|
|
100
|
+
get wasNpnNegotiated() {
|
|
101
|
+
// NPN is deprecated in favor of ALPN, but this implementation returns true
|
|
102
|
+
// for HTTP/2 or HTTP2+QUIC/39 requests negotiated via ALPN.
|
|
103
|
+
const ntEntry =
|
|
104
|
+
performance.getEntriesByType('navigation')[0] || ntEntryFallback;
|
|
105
|
+
return ['h2', 'hq'].includes(ntEntry.nextHopProtocol);
|
|
106
|
+
},
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
const { timing } = window.performance;
|
|
110
|
+
|
|
111
|
+
// Truncate number to specific number of decimals, most of the `loadTimes` stuff has 3
|
|
112
|
+
function toFixed(num, fixed) {
|
|
113
|
+
var re = new RegExp('^-?\\d+(?:.\\d{0,' + (fixed || -1) + '})?');
|
|
114
|
+
return num.toString().match(re)[0];
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const timingInfo = {
|
|
118
|
+
get firstPaintAfterLoadTime() {
|
|
119
|
+
// This was never actually implemented and always returns 0.
|
|
120
|
+
return 0;
|
|
121
|
+
},
|
|
122
|
+
get requestTime() {
|
|
123
|
+
return timing.navigationStart / 1000;
|
|
124
|
+
},
|
|
125
|
+
get startLoadTime() {
|
|
126
|
+
return timing.navigationStart / 1000;
|
|
127
|
+
},
|
|
128
|
+
get commitLoadTime() {
|
|
129
|
+
return timing.responseStart / 1000;
|
|
130
|
+
},
|
|
131
|
+
get finishDocumentLoadTime() {
|
|
132
|
+
return timing.domContentLoadedEventEnd / 1000;
|
|
133
|
+
},
|
|
134
|
+
get finishLoadTime() {
|
|
135
|
+
return timing.loadEventEnd / 1000;
|
|
136
|
+
},
|
|
137
|
+
get firstPaintTime() {
|
|
138
|
+
const fpEntry = performance.getEntriesByType('paint')[0] || {
|
|
139
|
+
startTime: timing.loadEventEnd / 1000, // Fallback if no navigation occured (`about:blank`)
|
|
140
|
+
};
|
|
141
|
+
return toFixed(
|
|
142
|
+
(fpEntry.startTime + performance.timeOrigin) / 1000,
|
|
143
|
+
3
|
|
144
|
+
);
|
|
145
|
+
},
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
window.chrome.loadTimes = () => ({
|
|
149
|
+
...protocolInfo,
|
|
150
|
+
...timingInfo,
|
|
151
|
+
});
|
|
152
|
+
utils.patchToString(window.chrome.loadTimes);
|
|
153
|
+
},
|
|
154
|
+
{
|
|
155
|
+
opts: this.opts,
|
|
156
|
+
}
|
|
157
|
+
);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
export default function (pluginConfig) {
|
|
162
|
+
return new Plugin(pluginConfig);
|
|
163
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
## API
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
#### Table of Contents
|
|
5
|
+
|
|
6
|
+
- [class: Plugin](#class-plugin)
|
|
7
|
+
- [sendMessageHandler()](#sendmessagehandler)
|
|
8
|
+
- [connectHandler()](#connecthandler)
|
|
9
|
+
|
|
10
|
+
### class: [Plugin](https://github.com/zorillajs/zorilla/blob/e6133619b051febed630ada35241664eba59b9fa/packages/puppeteer-extra-plugin-stealth/evasions/chrome.runtime/index.js#L13-L251)
|
|
11
|
+
|
|
12
|
+
- `opts` (optional, default `{}`)
|
|
13
|
+
|
|
14
|
+
**Extends: PuppeteerExtraPlugin**
|
|
15
|
+
|
|
16
|
+
Mock the `chrome.runtime` object if not available (e.g. when running headless) and on a secure site.
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
### [sendMessageHandler()](https://github.com/zorillajs/zorilla/blob/e6133619b051febed630ada35241664eba59b9fa/packages/puppeteer-extra-plugin-stealth/evasions/chrome.runtime/index.js#L80-L123)
|
|
21
|
+
|
|
22
|
+
Mock `chrome.runtime.sendMessage`
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
### [connectHandler()](https://github.com/zorillajs/zorilla/blob/e6133619b051febed630ada35241664eba59b9fa/packages/puppeteer-extra-plugin-stealth/evasions/chrome.runtime/index.js#L136-L210)
|
|
27
|
+
|
|
28
|
+
Mock `chrome.runtime.connect`
|
|
29
|
+
|
|
30
|
+
- **See: <https://developer.chrome.com/apps/runtime#method-connect>**
|
|
31
|
+
|
|
32
|
+
---
|