|
|
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 = 3; |
|
|
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', |
|
|
], |
|
|
|
|
|
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, cData = null, action = null) { |
|
|
return new Promise(async (resolve, reject) => { |
|
|
|
|
|
const timeout = setTimeout(() => reject(new Error("Timeout waiting for Turnstile token")), 60000); |
|
|
|
|
|
try { |
|
|
console.log(`[Turnstile] Navigating to Real URL: ${url}`); |
|
|
|
|
|
|
|
|
await page.goto(url, { waitUntil: "domcontentloaded", timeout: 30000 }); |
|
|
|
|
|
|
|
|
|
|
|
await page.evaluate((key, data, act) => { |
|
|
|
|
|
document.querySelectorAll('.cf-turnstile').forEach(e => e.remove()); |
|
|
document.querySelectorAll('iframe[src*="challenges.cloudflare.com"]').forEach(e => e.remove()); |
|
|
|
|
|
|
|
|
const div = document.createElement('div'); |
|
|
div.id = 'custom-turnstile-container'; |
|
|
div.style.position = 'fixed'; |
|
|
div.style.top = '10px'; |
|
|
div.style.left = '10px'; |
|
|
div.style.zIndex = '99999'; |
|
|
document.body.appendChild(div); |
|
|
|
|
|
|
|
|
if (typeof window.turnstile === 'undefined') { |
|
|
const script = document.createElement('script'); |
|
|
script.src = "https://challenges.cloudflare.com/turnstile/v0/api.js"; |
|
|
document.body.appendChild(script); |
|
|
} |
|
|
|
|
|
|
|
|
window.cf_solved_token = null; |
|
|
|
|
|
|
|
|
setTimeout(() => { |
|
|
if (window.turnstile) { |
|
|
window.turnstile.render('#custom-turnstile-container', { |
|
|
sitekey: key, |
|
|
cData: data, |
|
|
action: act, |
|
|
callback: function(token) { |
|
|
window.cf_solved_token = token; |
|
|
} |
|
|
}); |
|
|
} |
|
|
}, 1000); |
|
|
}, siteKey, cData, action); |
|
|
|
|
|
|
|
|
const checkToken = setInterval(async () => { |
|
|
try { |
|
|
const token = await page.evaluate(() => window.cf_solved_token); |
|
|
if (token) { |
|
|
clearInterval(checkToken); |
|
|
clearTimeout(timeout); |
|
|
resolve({ token: token }); |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
} catch (e) {} |
|
|
}, 1000); |
|
|
|
|
|
} catch (e) { |
|
|
clearTimeout(timeout); |
|
|
reject(e); |
|
|
} |
|
|
}); |
|
|
} |
|
|
|
|
|
|
|
|
app.post('/bypass', async (req, res) => { |
|
|
|
|
|
const { url, mode, siteKey, cdata, action, proxy } = req.body; |
|
|
|
|
|
if (!url || !mode) return res.status(400).json({ status: "error", message: "Missing url or mode" }); |
|
|
if (mode === 'turnstile' && !siteKey) return res.status(400).json({ status: "error", message: "siteKey required for turnstile" }); |
|
|
|
|
|
|
|
|
if (activeBrowsers >= MAX_CONCURRENT_BROWSERS) { |
|
|
return res.status(429).json({ status: "busy", message: "Server busy, try again later" }); |
|
|
} |
|
|
|
|
|
activeBrowsers++; |
|
|
let browserInstance = null; |
|
|
|
|
|
try { |
|
|
console.log(`[REQ] Processing: ${url} | Mode: ${mode} | cData: ${cdata ? "YES" : "NO"}`); |
|
|
|
|
|
const { browser, page } = await createBrowser(proxy); |
|
|
browserInstance = browser; |
|
|
|
|
|
let result; |
|
|
if (mode === 'turnstile') { |
|
|
|
|
|
result = await handleTurnstile(page, url, siteKey, cdata, action); |
|
|
} else { |
|
|
throw new Error("Invalid mode. Only 'turnstile' supported in this fix."); |
|
|
} |
|
|
|
|
|
console.log(`[SUCCESS] Token: ${result.token.substring(0, 15)}...`); |
|
|
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 cData Solver Ready")); |
|
|
app.listen(PORT, () => console.log(`Server listening on port ${PORT}`)); |
|
|
|