bots / index.html
rectangleworm's picture
Update index.html
6a47cd2 verified
Raw History Blame Contribute Delete
6.28 kB
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>stealth-probe</title>
<style>
body { font-family: "Fira Mono", Menlo, monospace; background:#0d1117; color:#c9d1d9; padding:24px; }
h1 { font-size: 1.1rem; color:#58a6ff; }
code#jsonResult { white-space: pre; display:block; background:#161b22; padding:16px; border-radius:8px; }
.badge { display:inline-block; padding:2px 8px; border-radius:4px; font-weight:bold; }
.badge.bot { background:#f85149; color:#fff; }
.badge.clean { background:#3fb950; color:#fff; }
</style>
</head>
<body>
<h1>stealth-probe — client-side automation fingerprint check</h1>
<div id="badge"></div>
<code class="language-json" id="jsonResult">{}</code>
<script>
(function () {
"use strict";
function safe(fn, fallback) {
try { return fn(); } catch (e) { return fallback; }
}
// --- 1. Automation object leaks (Selenium / old CDP shims) ---------------
function detectCdpLeakKeys() {
let suspects = [
"__webdriver_evaluate", "__selenium_evaluate", "__webdriver_script_function",
"__webdriver_script_func", "__webdriver_script_fn", "__fxdriver_evaluate",
"__driver_unwrapped", "__webdriver_unwrapped", "__selenium_unwrapped",
"__fxdriver_unwrapped", "__driver_evaluate", "$cdc_asdjflasutopfhvcZLmcfl_",
"$chrome_asyncScriptInfo", "domAutomation", "domAutomationController"
];
let found = [];
try {
for (let i = 0; i < suspects.length; i++) {
if (suspects[i] in window) found.push(suspects[i]);
}
} catch (e) {}
try {
let winKeys = Object.getOwnPropertyNames(window);
for (let j = 0; j < winKeys.length; j++) {
if (winKeys[j].indexOf("cdc_") === 0 || winKeys[j].indexOf("__webdriver") === 0) {
found.push(winKeys[j]);
}
}
} catch (e) {}
return found;
}
// --- 2. Function.toString native-code spoofing ---------------------------
function functionsLookNative() {
let fns = [window.alert, Function.prototype.bind, navigator.permissions ? navigator.permissions.query : null];
return fns.every(function (f) {
if (!f) return true;
return safe(function () { return f.toString().indexOf("[native code]") !== -1; }, false);
});
}
// --- 3. Canvas fingerprint sanity (blank / blocked canvas = automation tell) ---
function canvasWorks() {
return safe(function () {
let c = document.createElement("canvas");
c.width = 220; c.height = 30;
let ctx = c.getContext("2d");
ctx.textBaseline = "top";
ctx.font = "14px Arial";
ctx.fillStyle = "#f60";
ctx.fillRect(0, 0, 220, 30);
ctx.fillStyle = "#069";
ctx.fillText("stealth-probe 🦊 canvas", 2, 2);
let data = c.toDataURL();
return data.length > 100 && data !== "data:,";
}, false);
}
// --- 4. WebGL vendor/renderer consistency ---------------------------------
function webglInfo() {
return safe(function () {
let c = document.createElement("canvas");
let gl = c.getContext("webgl") || c.getContext("experimental-webgl");
if (!gl) return { supported: false };
let dbg = gl.getExtension("WEBGL_debug_renderer_info");
return {
supported: true,
vendor: gl.getParameter(gl.VENDOR),
renderer: gl.getParameter(gl.RENDERER),
unmaskedVendor: dbg ? gl.getParameter(dbg.UNMASKED_VENDOR_WEBGL) : null,
unmaskedRenderer: dbg ? gl.getParameter(dbg.UNMASKED_RENDERER_WEBGL) : null
};
}, { supported: false });
}
// --- 5. Headless-default screen resolution tell ---------------------------
function hasHeadlessDefaultResolution() {
// classic old-headless Chrome default viewport
return (window.outerWidth === 0 || window.outerHeight === 0) ||
(screen.width === 800 && screen.height === 600);
}
// --- 6. Permissions API mismatch (a known Chrome headless tell) -----------
function permissionsInconsistent() {
// Notification.permission === 'denied' while permissions.query resolves to 'prompt'
// is asynchronous; we just record raw values here, evaluated further downstream if needed.
return safe(function () {
return typeof Notification === "undefined" ? null : Notification.permission;
}, null);
}
// --- 7. Timing resolution jitter (automation frameworks sometimes clamp) --
function timingHasJitter() {
let samples = [];
for (let i = 0; i < 20; i++) samples.push(performance.now());
let allRounded = samples.every(function (v) { return v === Math.floor(v); });
return !allRounded;
}
let ua = navigator.userAgent || "";
let details = {
hasWebdriverTrue: navigator.webdriver === true,
hasBotUserAgent: /HeadlessChrome|bot|crawl|spider|slimerjs|phantomjs/i.test(ua),
hasInconsistentChromeObject: /Chrome/.test(ua) && typeof window.chrome !== "object",
hasNoPlugins: (navigator.plugins ? navigator.plugins.length : 0) === 0,
hasNoLanguages: !(navigator.languages && navigator.languages.length),
cdpLeakKeys: detectCdpLeakKeys(),
functionsSpoofed: !functionsLookNative(),
canvasBlocked: !canvasWorks(),
webgl: webglInfo(),
hasHeadlessDefaultScreenResolution: hasHeadlessDefaultResolution(),
hardwareConcurrency: navigator.hardwareConcurrency || 0,
hasHighHardwareConcurrency: (navigator.hardwareConcurrency || 0) > 32,
notificationPermission: permissionsInconsistent(),
hasSuspiciousTimingResolution: !timingHasJitter(),
userAgent: ua
};
let isBot = details.hasWebdriverTrue ||
details.hasBotUserAgent ||
details.hasInconsistentChromeObject ||
details.cdpLeakKeys.length > 0 ||
details.functionsSpoofed ||
details.canvasBlocked ||
details.hasHeadlessDefaultScreenResolution;
let result = { isBot: isBot, details: details };
document.getElementById("jsonResult").textContent = JSON.stringify(result, null, 2);
let badge = document.getElementById("badge");
badge.innerHTML = '<span class="badge ' + (isBot ? "bot" : "clean") + '">' +
(isBot ? "DETECTED AS BOT" : "CLEAN") + "</span>";
// Expose for Playwright evaluate() convenience without re-parsing text.
window.__stealthProbeResult = result;
})();
</script>
</body>
</html>