| | const express = require('express'); |
| | const cors = require('cors'); |
| | const { connect } = require("puppeteer-real-browser"); |
| |
|
| | const app = express(); |
| | app.use(cors()); |
| | app.use(express.json()); |
| |
|
| | const PORT = process.env.PORT || 7860; |
| | const MAX_CONCURRENT_BROWSERS = 2; |
| | let activeBrowsers = 0; |
| |
|
| | async function createBrowser(proxy = null) { |
| | const options = { |
| | headless: false, |
| | turnstile: true, |
| | args: [ |
| | '--no-sandbox', |
| | '--disable-setuid-sandbox', |
| | '--disable-dev-shm-usage', |
| | '--disable-accelerated-2d-canvas', |
| | '--no-first-run', |
| | '--no-zygote', |
| | '--disable-gpu', |
| | '--window-size=1920,1080', |
| | '--disable-blink-features=AutomationControlled' |
| | ], |
| | executablePath: process.env.CHROME_PATH || "/usr/bin/google-chrome-stable", |
| | customConfig: {}, |
| | connectOption: { defaultViewport: null } |
| | }; |
| |
|
| | if (proxy) { |
| | options.args.push(`--proxy-server=${proxy.hostname}:${proxy.port}`); |
| | } |
| |
|
| | const { browser, page } = await connect(options); |
| | |
| | if (proxy && proxy.username && proxy.password) { |
| | await page.authenticate({ username: proxy.username, password: proxy.password }); |
| | } |
| |
|
| | return { browser, page }; |
| | } |
| |
|
| | async function handleTurnstile(page, url, siteKey) { |
| | return new Promise(async (resolve, reject) => { |
| | |
| | const timeout = setTimeout(() => { |
| | reject(new Error("Timeout Turnstile (120s limit reached)")); |
| | }, 120000); |
| |
|
| | try { |
| | console.log(`[Turnstile] Preparing Injection for ${url}`); |
| |
|
| | |
| | const htmlContent = ` |
| | <!DOCTYPE html> |
| | <html lang="en"> |
| | <head> |
| | <meta charset="UTF-8"> |
| | <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
| | <title>Turnstile Solver</title> |
| | </head> |
| | <body> |
| | <div class="cf-turnstile" data-sitekey="${siteKey}" data-callback="turnstileCallback"></div> |
| | |
| | <script src="https://challenges.cloudflare.com/turnstile/v0/api.js" async defer></script> |
| | |
| | <script> |
| | console.log("Widget rendered..."); |
| | function turnstileCallback(token) { |
| | console.log("Token received in browser!"); |
| | window.cf_token = token; |
| | } |
| | </script> |
| | </body> |
| | </html>`; |
| |
|
| | |
| | await page.setRequestInterception(true); |
| | page.once('request', request => { |
| | request.respond({ |
| | status: 200, |
| | contentType: 'text/html', |
| | body: htmlContent |
| | }); |
| | }); |
| | |
| | |
| | page.on('request', req => { |
| | if (req.isInterceptResolutionHandled()) return; |
| | req.continue(); |
| | }); |
| |
|
| | |
| | console.log(`[Turnstile] Navigating...`); |
| | await page.goto(url, { waitUntil: "domcontentloaded", timeout: 60000 }); |
| |
|
| | |
| | const checkToken = setInterval(async () => { |
| | try { |
| | const token = await page.evaluate(() => window.cf_token); |
| | if (token) { |
| | clearInterval(checkToken); |
| | clearTimeout(timeout); |
| | console.log(`[Turnstile] Token found: ${token.substring(0, 15)}...`); |
| | resolve({ token: token }); |
| | } |
| | } catch (e) {} |
| | }, 1000); |
| |
|
| | } catch (e) { |
| | clearTimeout(timeout); |
| | reject(e); |
| | } |
| | }); |
| | } |
| |
|
| | app.post('/bypass', async (req, res) => { |
| | const { url, mode, siteKey, proxy } = req.body; |
| | |
| | if (!url || !mode) return res.status(400).json({ status: "error", message: "Missing url or mode" }); |
| | |
| | if (activeBrowsers >= MAX_CONCURRENT_BROWSERS) { |
| | return res.status(429).json({ status: "busy", message: "Server busy, try again in a few seconds" }); |
| | } |
| |
|
| | activeBrowsers++; |
| | let browserInstance = null; |
| |
|
| | try { |
| | console.log(`[REQ] Processing: ${url} | Mode: ${mode}`); |
| | const { browser, page } = await createBrowser(proxy); |
| | browserInstance = browser; |
| |
|
| | let result; |
| | if (mode === 'turnstile') { |
| | result = await handleTurnstile(page, url, siteKey); |
| | } else { |
| | throw new Error("Invalid mode (only turnstile supported in this version)"); |
| | } |
| | |
| | console.log(`[SUCCESS] Operation completed.`); |
| | res.json({ status: "success", ...result }); |
| |
|
| | } catch (error) { |
| | console.error(`[ERROR] ${error.message}`); |
| | res.status(500).json({ status: "error", message: error.message }); |
| | } finally { |
| | if (browserInstance) { |
| | try { await browserInstance.close(); } catch {} |
| | } |
| | activeBrowsers--; |
| | } |
| | }); |
| |
|
| | app.get('/', (req, res) => res.send("Turnstile Solver Ready (v3 - 120s Timeout)")); |
| | app.listen(PORT, () => console.log(`Server listening on port ${PORT}`)); |
| |
|