UNPKG

3.09 kBJavaScriptView Raw
1// initial evasions from @sangaline
2// https://intoli.com/blog/not-possible-to-block-chrome-headless/
3// https://intoli.com/blog/not-possible-to-block-chrome-headless/test-headless-final.js
4
5module.exports = async function(page) {
6 // Pass the User-Agent Test.
7 const userAgent =
8 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36';
9 await page.setUserAgent(userAgent);
10
11 // Pass the Webdriver Test.
12 await page.evaluateOnNewDocument(() => {
13 Object.defineProperty(navigator, 'webdriver', {
14 get: () => false,
15 });
16 });
17
18 // Pass the Chrome Test.
19 await page.evaluateOnNewDocument(() => {
20 // We can mock this in as much depth as we need for the test.
21 window.chrome = {
22 runtime: {},
23 };
24 });
25
26 // Pass the Permissions Test.
27 await page.evaluateOnNewDocument(() => {
28 const originalQuery = window.navigator.permissions.query;
29 window.navigator.permissions.__proto__.query = parameters =>
30 parameters.name === 'notifications'
31 ? Promise.resolve({ state: Notification.permission })
32 : originalQuery(parameters);
33
34 // Inspired by: https://github.com/ikarienator/phantomjs_hide_and_seek/blob/master/5.spoofFunctionBind.js
35 const oldCall = Function.prototype.call;
36
37 function call() {
38 return oldCall.apply(this, arguments);
39 }
40
41 Function.prototype.call = call;
42
43 const nativeToStringFunctionString = Error.toString().replace(/Error/g, 'toString');
44 const oldToString = Function.prototype.toString;
45
46 function functionToString() {
47 if (this === window.navigator.permissions.query) {
48 return 'function query() { [native code] }';
49 }
50 if (this === functionToString) {
51 return nativeToStringFunctionString;
52 }
53 return oldCall.call(oldToString, this);
54 }
55
56 Function.prototype.toString = functionToString;
57 });
58
59 // Pass the Plugins Length Test.
60 await page.evaluateOnNewDocument(() => {
61 // Overwrite the `plugins` property to use a custom getter.
62 Object.defineProperty(navigator, 'plugins', {
63 // This just needs to have `length > 0` for the current test,
64 // but we could mock the plugins too if necessary.
65 get: () => [1, 2, 3, 4, 5],
66 });
67 });
68
69 // Pass the Languages Test.
70 await page.evaluateOnNewDocument(() => {
71 // Overwrite the `plugins` property to use a custom getter.
72 Object.defineProperty(navigator, 'languages', {
73 get: () => ['pt-BR', 'pt', 'en-US', 'en', 'es'],
74 });
75 });
76
77 // Pass the iframe Test
78 await page.evaluateOnNewDocument(() => {
79 Object.defineProperty(HTMLIFrameElement.prototype, 'contentWindow', {
80 get: function() {
81 return window;
82 },
83 });
84 });
85
86 // Pass toString test, though it breaks console.debug() from working
87 await page.evaluateOnNewDocument(() => {
88 window.console.debug = () => {
89 return null;
90 };
91 });
92
93 await page.setExtraHTTPHeaders({
94 'accept-encoding': 'gzip, deflate, br',
95 'accept-language': 'pt-BR,pt;q=0.9,en-US;q=0.8,en;q=0.7,es;q=0.6',
96 });
97};