currently only doing analysis when using phantomjs
Created
June 4, 2022 02:39
-
-
Save binsarjr/e62540e7dd4d35a83281bda0de427d49 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const headlessDetected = () => { | |
alert("Automation detected") | |
} | |
// Test for user agent | |
function testUserAgent() { | |
const userAgent = ['phantomjs', 'Headless'] | |
let agent = navigator.userAgent; | |
return new RegExp(userAgent.join('|'), 'ig').test(agent); | |
} | |
// Test for app version (almost equal to user agent) | |
function testAppVersion() { | |
let appVersion = navigator.appVersion; | |
return /headless/i.test(appVersion); | |
} | |
// Test for webdriver (headless browser has this flag true) | |
function testWebdriver() { | |
let webdriver = navigator.webdriver; | |
return Boolean(webdriver); | |
} | |
// Test for stack trace | |
function testStackTrace(headless = 'headless') { | |
let err | |
try { | |
null[0]() | |
} catch (e) { | |
err = e | |
} finally { | |
return err.stack.indexOf(headless) > -1 | |
} | |
} | |
// Test for permission | |
async function testPermission() { | |
let permissionStatus, notificationPermission; | |
if (!navigator.permissions) { | |
return false; | |
} | |
permissionStatus = await navigator.permissions.query({ name: "notifications" }); | |
notificationPermission = Notification.permission; | |
return notificationPermission === "denied" && permissionStatus.state === "prompt" | |
} | |
// Test for connection-rtt | |
function testConnectionRtt() { | |
let connection = navigator.connection; | |
let connectionRtt = connection ? connection.rtt : undefined; | |
if (connectionRtt === undefined) { | |
return false; | |
} else { | |
return connectionRtt === 0; | |
} | |
} | |
// Test for devtools protocol | |
function testDevtool() { | |
const any = /./; | |
let count = 0; | |
let oldToString = any.toString; | |
any.toString = function () { | |
count++; | |
return "any"; | |
} | |
let usingDevTools = count > 1; | |
any.toString = oldToString; | |
return usingDevTools | |
} | |
// Test for languages | |
function testLanguages() { | |
let language = navigator.language; | |
let languagesLength = navigator.languages.length; | |
return !language || languagesLength === 0 | |
} | |
// Tests for mime types prototype | |
function testMimePrototype() { | |
let correctPrototypes = MimeTypeArray.prototype === navigator.mimeTypes.__proto__; | |
if (navigator.mimeTypes.length > 0) | |
correctPrototypes &= MimeType.prototype === navigator.mimeTypes[0].__proto__; | |
return !correctPrototypes; | |
} | |
// Test for plugins | |
function testPlugins() { | |
return !navigator.plugins instanceof PluginArray || navigator.plugins.length == 0 | |
} | |
// Tests for plugins prototype | |
function testPluginsPrototype() { | |
let correctPrototypes = PluginArray.prototype === navigator.plugins.__proto__; | |
if (navigator.plugins.length > 0) | |
correctPrototypes &= Plugin.prototype === navigator.plugins[0].__proto__; | |
return !correctPrototypes; | |
} | |
function testPhantomJS() { | |
const callPhantom = () => Boolean(window.callPhantom || window._phantom) | |
return testStackTrace('phantomjs') || callPhantom() | |
} | |
// Test for time elapsed after alert(). If it's closed too fast (< 30ms), it means | |
// the browser is headless | |
function testTimeElapse() { | |
let start = Date.now(); | |
alert("Tekan OK"); | |
let elapse = Date.now() - start; | |
return elapse < 30; | |
} | |
async function test() { | |
if (testUserAgent()) return headlessDetected() | |
if (testAppVersion()) return headlessDetected() | |
if (testWebdriver()) return headlessDetected() | |
if (testStackTrace()) return headlessDetected() | |
if (await testPermission()) return headlessDetected() | |
if (testConnectionRtt()) return headlessDetected() | |
if (testDevtool()) return headlessDetected() | |
if (testLanguages()) return headlessDetected() | |
if (testMimePrototype()) return headlessDetected() | |
if (testPlugins()) return headlessDetected() | |
if (testPluginsPrototype()) return headlessDetected() | |
if (testPhantomJS()) return headlessDetected() | |
if (testTimeElapse()) return headlessDetected() | |
} | |
; (async function () { | |
await test() | |
if (!Function.prototype.bind) { | |
detected() | |
} | |
if (Function.prototype.bind.toString().replace(/bind/g, 'Error') != Error.toString()) { | |
detected() | |
} | |
if (Function.prototype.toString.toString().replace(/toString/g, 'Error') != Error.toString()) { | |
detected() | |
} | |
})() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment