| 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}`)); |
|
|