-
Notifications
You must be signed in to change notification settings - Fork 72
Open
Description
see this
https://github.com/botswin/BotBrowser/blob/main/examples/bot-script/cloudflare-turnstile.js```
```What Is --bot-script?
--bot-script executes JavaScript in a privileged, non‑extension context where the chrome.debugger API is available. This provides:
No framework dependencies - Pure Chrome DevTools Protocol access
Earlier intervention - Execute before page navigation
Privileged context - Full chrome.debugger API access
Reduced detection surface - No Playwright/Puppeteer artifacts
Usage
./chrome.exe --no-sandbox --bot-profile="/absolute/path/to/profile.enc" --bot-script="your-script.js"
example
import puppeteer from "rebrowser-puppeteer-core";
// import { pageController } from "./module/pageController.mjs";
import { createCursor } from 'ghost-cursor';
// import { checkTurnstile } from './turnstile.mjs';
import kill from 'tree-kill';
export const checkTurnstileOLD = ({ page }) => {
return new Promise(async (resolve, reject) => {
var waitInterval = setTimeout(() => { clearInterval(waitInterval); resolve(false) }, 5000);
try {
const elements = await page.$$('[name="cf-turnstile-response"]');
if (elements.length <= 0) {
const coordinates = await page.evaluate(() => {
let coordinates = [];
document.querySelectorAll('div').forEach(item => {
try {
let itemCoordinates = item.getBoundingClientRect()
let itemCss = window.getComputedStyle(item)
if (itemCss.margin == "0px" && itemCss.padding == "0px" && itemCoordinates.width > 290 && itemCoordinates.width <= 310 && !item.querySelector('*')) {
coordinates.push({ x: itemCoordinates.x, y: item.getBoundingClientRect().y, w: item.getBoundingClientRect().width, h: item.getBoundingClientRect().height })
}
} catch (err) { }
});
if (coordinates.length <= 0) {
document.querySelectorAll('div').forEach(item => {
try {
let itemCoordinates = item.getBoundingClientRect()
if (itemCoordinates.width > 290 && itemCoordinates.width <= 310 && !item.querySelector('*')) {
coordinates.push({ x: itemCoordinates.x, y: item.getBoundingClientRect().y, w: item.getBoundingClientRect().width, h: item.getBoundingClientRect().height })
}
} catch (err) { }
});
}
return coordinates
})
for (const item of coordinates) {
try {
let x = item.x + 30;
let y = item.y + item.h / 2;
await page.mouse.click(x, y);
} catch (err) { }
}
return resolve(true)
}
for (const element of elements) {
try {
const parentElement = await element.evaluateHandle(el => el.parentElement);
const box = await parentElement.boundingBox();
let x = box.x + 30;
let y = box.y + box.height / 2;
await page.mouse.click(x, y);
} catch (err) { }
}
clearInterval(waitInterval)
resolve(true)
} catch (err) {
clearInterval(waitInterval)
resolve(false)
}
})
}
const CLOUDFLARE_CHALLENGE_URL = 'challenges.cloudflare.com/cdn-cgi/challenge-platform';
const MONITORING_INTERVAL = 2000;
const CLICK_X = 30;
const CLICK_Y = 30;
const DEFAULT_TIMEOUT = 30000;
export const checkTurnstile = ({ page, timeout = DEFAULT_TIMEOUT } = {}) => {
return new Promise(async (resolve, reject) => {
if (!page) {
return reject(new Error('Page object is required'));
}
const browser = page.browser();
let monitoringActive = true;
let activeTargets = new Set();
let targetFrameFound = false;
const startTime = Date.now();
console.log("Starting Turnstile automation...");
const sleep = (ms) => new Promise(r => setTimeout(r, ms));
const setupMobileEmulation = async (targetId, cdpSession) => {
try {
const result = await cdpSession.send('Runtime.evaluate', {
expression: `
(() => {
const mobileUserAgent = /Android|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
const hasTouchSupport = ('ontouchstart' in window);
return {
isMobile: mobileUserAgent,
userAgent: navigator.userAgent,
innerWidth: window.innerWidth,
touchSupport: hasTouchSupport,
maxTouchPoints: navigator.maxTouchPoints
};
})()
`,
returnByValue: true
});
if (result?.result?.value) {
const deviceInfo = result.result.value;
console.log("Device detection:", deviceInfo);
if (deviceInfo.isMobile) {
console.log("Mobile device detected, enabling touch events");
await cdpSession.send('Emulation.setEmitTouchEventsForMouse', {
enabled: true,
configuration: 'mobile'
});
console.log("Mobile touch events enabled for target:", targetId);
} else {
console.log("Desktop device detected, using standard mouse events");
}
}
} catch (error) {
console.log("Could not detect device type, defaulting to desktop mode:", error.message);
}
};
const performMouseClick = async (targetId, cdpSession, x, y) => {
console.log("Performing mouse click at coordinates:", x, y);
try {
await cdpSession.send('Input.dispatchMouseEvent', {
type: 'touchStart',///type: "mousePressed", [[Chrome is very forgiving internally. Even if you send a touch-like type to dispatchMouseEvent, it might still trigger a DOM event (pointerdown / pointerup]]
// type: 'mousePressed',///type: "mousePressed", [[Chrome is very forgiving internally. Even if you send a touch-like type to dispatchMouseEvent, it might still trigger a DOM event (pointerdown / pointerup]]
x: x,
y: y,
button: 'left',
clickCount: 1
});
console.log("Mouse pressed at:", x, y);
await sleep(100);///LMAO DOESNT NOT NEED THIS
await cdpSession.send('Input.dispatchMouseEvent', {
type: 'touchEnd',/// type: "mouseReleased",
x: x,
y: y,
button: 'left',
clickCount: 1
});
console.log("Mouse released. Click completed successfully!");
activeTargets.delete(targetId);
targetFrameFound = true;
} catch (error) {
console.error("Mouse event failed:", error.message);
activeTargets.delete(targetId);
throw error;
}
};
const attachToTarget = async (target) => {
const targetId = target._targetId;
const url = target.url();
if (activeTargets.has(targetId)) {
return;
}
const isCloudflareChallenge = url.includes(CLOUDFLARE_CHALLENGE_URL);
if (!isCloudflareChallenge) {
return;
}
console.log("Found Cloudflare challenge frame:", url);
activeTargets.add(targetId);
try {
let cdpSession;
if (target.type() === 'page') {
const targetPage = await target.page();
if (targetPage) {
cdpSession = await targetPage._client();
console.log("Got CDP session from page");
}
} else {
const browserClient = await page._client();
const result = await browserClient.send('Target.attachToTarget', {
targetId: targetId,
flatten: true
});
console.log("Created new CDP session:", result.sessionId);
let connection = browserClient.connection?.() || browserClient.connection || browserClient._connection;
cdpSession = connection?.sessions?.get(result.sessionId) ||
connection?._sessions?.get(result.sessionId) ||
connection?._sessionMap?.get(result.sessionId);
if (!cdpSession) {
console.log("Using fallback session wrapper");
cdpSession = {
_sessionId: result.sessionId,
_browserClient: browserClient,
send: async function (method, params = {}) {
console.log(`Sending command: ${method}`, params);
try {
return await this._browserClient.send(method, params);
} catch (error) {
console.error(`Error sending ${method}:`, error.message);
throw error;
}
}
};
}
}
console.log("Successfully attached to target:", targetId);
await cdpSession.send('Runtime.enable');
console.log("Runtime enabled for target:", targetId);
await setupMobileEmulation(targetId, cdpSession);
await sleep(500);
await performMouseClick(targetId, cdpSession, CLICK_X, CLICK_Y);
} catch (error) {
console.error("Failed to attach to target:", targetId, error.message);
activeTargets.delete(targetId);
}
};
const checkForToken = async () => {
try {
const token = await page.evaluate(() => {
try {
let item = document.querySelector('[name="cf-turnstile-response"]')?.value;
return item && item.length > 20 ? item : null;
} catch (e) {
return null;
}
});
return token;
} catch (e) {
return null;
}
};
const monitor = async () => {
while (monitoringActive) {
if (Date.now() - startTime > timeout) {
monitoringActive = false;
return reject(new Error('Turnstile challenge timeout'));
}
try {
const targets = await browser.targets();
for (const target of targets) {
const type = target.type();
const url = target.url();
if ((type === 'page' || type === 'iframe' || type === 'other') &&
url && url.includes('challenges.cloudflare.com')) {
await attachToTarget(target);
}
}
const token = await checkForToken();
if (token) {
console.log('Cloudflare Turnstile Token obtained:', token);
monitoringActive = false;
return resolve(token);
}
} catch (error) {
console.error("Error during monitoring:", error.message);
}
await sleep(MONITORING_INTERVAL);
}
};
try {
await monitor();
} catch (error) {
reject(error);
}
});
};
function getRandomInt(min, max) {
min = Math.ceil(min);
max = Math.floor(max);
return Math.floor(Math.random() * (max - min + 1)) + min;
}
export async function pageController({ browser, page, proxy, turnstile, xvfbsession, pid, plugins, killProcess = false, chrome }) {
let solveStatus = turnstile
page.on('close', () => {
solveStatus = false
});
browser.on('disconnected', async () => {
solveStatus = false
if (killProcess === true) {
if (xvfbsession) try { xvfbsession.stopSync() } catch (err) { }
if (chrome) try { chrome.kill() } catch (err) { console.log(err); }
if (pid) try { kill(pid, 'SIGKILL', () => { }) } catch (err) { }
}
});
async function turnstileSolver() {
while (solveStatus) {
await checkTurnstile({ page }).catch(() => { });
await new Promise(r => setTimeout(r, 1000));
}
return
}
turnstileSolver()
if (proxy.username && proxy.password) await page.authenticate({ username: proxy.username, password: proxy.password });
if (plugins.length > 0) {
for (const plugin of plugins) {
plugin.onPageCreated(page)
}
}
await page.evaluateOnNewDocument(() => {
Object.defineProperty(MouseEvent.prototype, 'screenX', {
get: function () {
return this.clientX + window.screenX;
}
});
Object.defineProperty(MouseEvent.prototype, 'screenY', {
get: function () {
return this.clientY + window.screenY;
}
});
});
const cursor = createCursor(page);
page.realCursor = cursor
page.realClick = cursor.click
return page
}
// process.env.REBROWSER_PATCHES_DEBUG=1
export async function connect({
args = [],
headless = true,
customConfig = {},
proxy = {},
turnstile = false,
connectOption = {},
disableXvfb = false,
plugins = [],
ignoreAllFlags = false,
} = {}) {
let xvfbsession = null;
if (headless == "auto") headless = false;
if (process.platform === "linux" && disableXvfb === false) {
try {
const { default: Xvfb } = await import("xvfb");
xvfbsession = new Xvfb({
silent: true,
xvfb_args: ["-screen", "0", "1920x1080x24", "-ac"],
});
xvfbsession.startSync();
} catch (err) {
console.log(
"You are running on a Linux platform but do not have xvfb installed. The browser can be captured. Please install it with the following command\n\nsudo apt-get install xvfb\n\n" +
err.message
);
}
}
let chromeFlags;
if (ignoreAllFlags === true) {
chromeFlags = [
...args,
...(headless !== false ? [`--headless=${headless}`] : []),
...(proxy && proxy.host && proxy.port
? [`--proxy-server=${proxy.host}:${proxy.port}`]
: []),
];
} else {
// Default flags: https://github.com/GoogleChrome/chrome-launcher/blob/main/src/flags.ts
const flags = Launcher.defaultFlags();
// Add AutomationControlled to "disable-features" flag
const indexDisableFeatures = flags.findIndex((flag) => flag.startsWith('--disable-features'));
flags[indexDisableFeatures] = `${flags[indexDisableFeatures]},AutomationControlled`;
// Remove "disable-component-update" flag
const indexComponentUpdateFlag = flags.findIndex((flag) => flag.startsWith('--disable-component-update'));
flags.splice(indexComponentUpdateFlag, 1);
chromeFlags = [
...flags,
...args,
...(headless !== false ? [`--headless=${headless}`] : []),
...(proxy && proxy.host && proxy.port
? [`--proxy-server=${proxy.host}:${proxy.port}`]
: []),
"--no-sandbox",
"--disable-dev-shm-usage",
];
}
const chrome = await launch({
executablePath: "C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe",
ignoreDefaultFlags: true,
chromeFlags,
...customConfig,
});
let pextra = null;
if (plugins.length > 0) {
const { addExtra } = await import("puppeteer-extra");
pextra = addExtra(puppeteer);
for (const item of plugins) {
pextra.use(item);
}
}
const browser = await (pextra ? pextra : puppeteer).connect({
browserURL: `http://127.0.0.1:${chrome.port}`,
...connectOption,
});
let [page] = await browser.pages();
let pageControllerConfig = {
browser,
page,
proxy,
turnstile,
xvfbsession,
pid: chrome.pid,
plugins,
};
page = await pageController({
...pageControllerConfig,
chrome,
killProcess: true,
});
browser.on("targetcreated", async (target) => {
if (target.type() === "page") {
let newPage = await target.page();
pageControllerConfig.page = newPage;
newPage = await pageController(pageControllerConfig);
}
});
return {
browser,
page,
};
}
import test from 'node:test';
import assert from 'node:assert';
const realBrowserOption = {
args: [
'--no-sandbox',
'--no-zygote',
"--start-maximized",
'--lang=en-US',
'--disable-dev-shm-usage',
'--disable-client-side-phishing-detection',
'--fingerprint=' + ((Math.random() * 2 ** 32) >>> 0).toString(),
// '--fingerprint=2333',
// '--fingerprint-platform-version=11',
// '--fingerprint-platform-version=141',//this is from ///chrome 139, from https://github.com/adryfish/fingerprint-chromium
// '--fingerprint-brand=Edge',
'--fingerprint-platform=windows'// macos also works , slightly slower, TRY ON DOCKER, important for docker? Unknown I dont use docker
// '--fingerprint-platform=macos'//important for docker? Unknown I dont use docker
],
turnstile: false,
headless: false,
disableXvfb: true,
ignoreAllFlags: false,
// ignoreAllFlags:true,
customConfig: {
chromePath: `C:\\Users\\User\\mlx\\deps\\mimic_140.3\\chrome.exe`, ///chrome 139, from https://github.com/adryfish/fingerprint-chromium
},
connectOption: {
defaultViewport: null
},
plugins: []
}
test('Cloudflare Turnstile', async () => {
const { page, browser } = await connect(realBrowserOption)
//detected with ///chrome 139, from https://github.com/adryfish/fingerprint-chromium
// //IN CHROME WEB CONSOLE : (async () => { if (navigator.userAgentData) { try { const userAgentData = await navigator.userAgentData.getHighEntropyValues([ "architecture", "bitness", "brands", "fullVersionList", "mobile", "model", "platform", "platformVersion" ]); const formattedCode = ` await page.setUserAgent('${navigator.userAgent}',{ "architecture": "${userAgentData.architecture}", "bitness": "${userAgentData.bitness}", "brands": ${JSON.stringify(userAgentData.brands, null, 12)}, "fullVersionList": ${JSON.stringify(userAgentData.fullVersionList, null, 12)}, "mobile": ${userAgentData.mobile}, "model": "${userAgentData.model}", "platform": "${userAgentData.platform}", "platformVersion": "${userAgentData.platformVersion}" }); `; console.log(formattedCode); } catch (error) { console.error("Error retrieving user agent data:", error); console.log("Could not generate the complete code snippet. This might happen if you deny the permission prompt for more detailed information."); } } else { console.log("The navigator.userAgentData API is not available in this browser. The requested detailed format cannot be automatically generated."); console.log("You can use the basic user agent string as follows:"); console.log(`await page.setUserAgent('${navigator.userAgent}');`); } })();
// await page.setUserAgent('Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0', {
// "architecture": "x86", "bitness": "64", "brands": [
// {
// "brand": "Microsoft Edge",
// "version": "141"
// },
// {
// "brand": "Not?A_Brand",
// "version": "8"
// },
// {
// "brand": "Chromium",
// "version": "141"
// }
// ], "fullVersionList": [
// {
// "brand": "Microsoft Edge",
// "version": "141.0.3537.71"
// },
// {
// "brand": "Not?A_Brand",
// "version": "8.0.0.0"
// },
// {
// "brand": "Chromium",
// "version": "141.0.7390.66"
// }
// ], "mobile": false, "model": "", "platform": "Windows", "platformVersion": "10.0.0"
// });
// await page.goto("https://abrahamjuliot.github.io/creepjs/");
// await page.goto("https://bot-detector.rebrowser.net/");
await page.goto("https://turnstile-demo.pages.dev/");
// await page.goto("https://fingerprint.com/products/bot-detection/");
// await page.waitForSelector('#email')
let token = null
let startDate = Date.now()
console.log("Please complete the Turnstile challenge within 30 seconds...")
while (!token && (Date.now() - startDate) < 30000) {
token = await page.evaluate(() => {
try {
let item = document.querySelector('[name="cf-turnstile-response"]').value
return item && item.length > 20 ? item : null
} catch (e) {
return null
}
})
await new Promise(r => setTimeout(r, 1000));
}
await browser.close()
// if (token !== null) console.log('Cloudflare Turnstile Token: ' + token);
assert.strictEqual(token !== null, true, "Cloudflare turnstile test failed!")
})```
Activity
Mahkhmood8 commentedon Oct 18, 2025
https://github.com/botswin/BotBrowser/tree/main/examples/bot-script