Download cloudflare-solver.js from kavion/cf: direct link, hf CLI and curl.
- Browser
- Download file 7.5 kB
-
https://huggingface.co/spaces/kavion/cf/resolve/main/cloudflare-solver.js
- Command line
-
hf download hf://spaces/kavion/cf/cloudflare-solver.js
-
curl -L -o cloudflare-solver.js https://huggingface.co/spaces/kavion/cf/resolve/main/cloudflare-solver.js
7.5 kB
| ; | |
| const { | |
| connect | |
| } = require('puppeteer-real-browser'); | |
| const fs = require('fs'); | |
| const WIDTH = 1280; | |
| const HEIGHT = 800; | |
| const ChallengePlatform = { | |
| JAVASCRIPT: 'non-interactive', | |
| MANAGED: 'managed', | |
| INTERACTIVE: 'interactive', | |
| }; | |
| const FALLBACK_UA = | |
| 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 ' + | |
| '(KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36'; | |
| const sleep = (ms) => new Promise((r) => setTimeout(r, ms)); | |
| function loadLines(fp) { | |
| try { | |
| return fs.readFileSync(fp, 'utf8').split('\n').map(l => l.trim()).filter(Boolean); | |
| } catch { | |
| return []; | |
| } | |
| } | |
| function randomChoice(arr) { | |
| return arr[Math.floor(Math.random() * arr.length)]; | |
| } | |
| function getChromeUA() { | |
| const agents = loadLines('data/useragents.txt'); | |
| return agents.length ? randomChoice(agents) : FALLBACK_UA; | |
| } | |
| function parseProxy(url) { | |
| const u = new URL(url); | |
| return { | |
| serverUrl: `${u.protocol}//${u.hostname}${u.port ? ':' + u.port : ''}`, | |
| username: u.username || null, | |
| password: u.password || null, | |
| }; | |
| } | |
| function extractClearance(cookies) { | |
| return cookies.find(c => c.name === 'cf_clearance') || null; | |
| } | |
| function buildCookieString(cookies) { | |
| return cookies.map(c => `${c.name}=${c.value}`).join('; '); | |
| } | |
| async function detectChallenge(page) { | |
| try { | |
| const html = await page.content(); | |
| for (const val of Object.values(ChallengePlatform)) { | |
| if (html.includes(`cType: '${val}'`)) return val; | |
| } | |
| return null; | |
| } catch { | |
| return null; | |
| } | |
| } | |
| async function findCFFrame(page) { | |
| try { | |
| const frame = page.frames().find(f => { | |
| try { | |
| return f.url().includes('challenges.cloudflare.com'); | |
| } catch { | |
| return false; | |
| } | |
| }); | |
| if (frame) return frame; | |
| } catch { | |
| /* ignore */ } | |
| try { | |
| const el = await page.$('iframe[src*="challenges.cloudflare.com"]'); | |
| if (el) return await el.contentFrame(); | |
| } catch { | |
| /* ignore */ } | |
| return null; | |
| } | |
| async function clickCFFrame(page, frame) { | |
| await sleep(1500); | |
| try { | |
| const cb = await frame.$('input[type="checkbox"]').catch(() => null); | |
| if (cb) { | |
| const box = await cb.boundingBox().catch(() => null); | |
| if (box) { | |
| await cb.click(); | |
| return 'checkbox'; | |
| } | |
| } | |
| const label = await frame.$('label').catch(() => null); | |
| if (label) { | |
| const box = await label.boundingBox().catch(() => null); | |
| if (box) { | |
| await label.click(); | |
| return 'label'; | |
| } | |
| } | |
| const widget = await frame.$('.cf-turnstile-content, #cf-stage, .ctp-checkbox-label').catch(() => null); | |
| if (widget) { | |
| const box = await widget.boundingBox().catch(() => null); | |
| if (box) { | |
| await widget.click(); | |
| return 'widget'; | |
| } | |
| } | |
| const body = await frame.$('body').catch(() => null); | |
| if (body) { | |
| const box = await body.boundingBox().catch(() => null); | |
| if (box && box.width > 0) { | |
| await body.click(); | |
| return 'body'; | |
| } | |
| } | |
| } catch (e) {} | |
| return null; | |
| } | |
| async function solveChallenge(page, timeoutSecs = 30) { | |
| const deadline = Date.now() + timeoutSecs * 1000; | |
| let attempt = 0; | |
| let lastClicked = 0; | |
| while (Date.now() < deadline) { | |
| attempt++; | |
| const cookies = await page.cookies().catch(() => []); | |
| if (extractClearance(cookies)) { | |
| return; | |
| } | |
| const platform = await detectChallenge(page); | |
| if (!platform) { | |
| return; | |
| } | |
| const frame = await findCFFrame(page); | |
| if (!frame) { | |
| await sleep(500); | |
| continue; | |
| } | |
| if (Date.now() - lastClicked < 5000) { | |
| await sleep(500); | |
| continue; | |
| } | |
| const result = await clickCFFrame(page, frame); | |
| if (result) { | |
| lastClicked = Date.now(); | |
| await sleep(2500); | |
| } else { | |
| await sleep(500); | |
| } | |
| } | |
| } | |
| async function solveCloudflare({ | |
| url, | |
| headless = true, | |
| proxy = null, | |
| proxyFile = null, | |
| timeout = 30, | |
| } = {}) { | |
| const proxies = proxyFile ? loadLines(proxyFile) : []; | |
| const chosenProxy = proxy || (proxies.length ? randomChoice(proxies) : null); | |
| const userAgent = getChromeUA(); | |
| const parsed = chosenProxy ? parseProxy(chosenProxy) : null; | |
| const args = [ | |
| '--no-sandbox', | |
| '--disable-setuid-sandbox', | |
| '--disable-quic', | |
| `--window-size=${WIDTH},${HEIGHT}`, | |
| ]; | |
| if (parsed) args.push(`--proxy-server=${parsed.serverUrl}`); | |
| const { | |
| browser, | |
| page | |
| } = await connect({ | |
| headless, | |
| args, | |
| turnstile: false, | |
| connectOption: {}, | |
| disableXvfb: false, | |
| ignoreAllFlags: false, | |
| }); | |
| try { | |
| await page.setViewport({ | |
| width: WIDTH, | |
| height: HEIGHT | |
| }); | |
| await page.setUserAgent(userAgent); | |
| if (parsed?.username) { | |
| await page.authenticate({ | |
| username: parsed.username, | |
| password: parsed.password | |
| }); | |
| } | |
| try { | |
| await page.goto(url, { | |
| waitUntil: 'domcontentloaded', | |
| timeout: timeout * 1000 | |
| }); | |
| } catch (e) { | |
| await browser.close(); | |
| return { | |
| url, | |
| success: false, | |
| error: `Navigation error: ${e.message}` | |
| }; | |
| } | |
| await sleep(2000); | |
| let cookies = await page.cookies().catch(() => []); | |
| let clearance = extractClearance(cookies); | |
| if (!clearance) { | |
| const platform = await detectChallenge(page); | |
| if (!platform) { | |
| await browser.close(); | |
| return { | |
| url, | |
| success: false, | |
| error: 'No Cloudflare challenge detected' | |
| }; | |
| } | |
| await solveChallenge(page, timeout); | |
| cookies = await page.cookies().catch(() => []); | |
| clearance = extractClearance(cookies); | |
| } | |
| const finalUA = await page.evaluate(() => navigator.userAgent).catch(() => userAgent); | |
| await browser.close(); | |
| if (!clearance) { | |
| return { | |
| url, | |
| success: false, | |
| error: 'Failed to obtain cf_clearance cookie' | |
| }; | |
| } | |
| const cookieString = buildCookieString(cookies); | |
| const unixTimestamp = Math.floor(clearance.expires - 365 * 24 * 3600); | |
| const timestamp = new Date(unixTimestamp * 1000).toISOString(); | |
| return { | |
| success: true, | |
| url, | |
| proxy: chosenProxy, | |
| user_agent: finalUA, | |
| cf_clearance: clearance.value, | |
| all_cookies: cookies, | |
| cookie_string: cookieString, | |
| unix_timestamp: unixTimestamp, | |
| timestamp, | |
| domain: clearance.domain, | |
| }; | |
| } catch (err) { | |
| await browser.close().catch(() => {}); | |
| throw err; | |
| } | |
| } | |
| module.exports = { | |
| solveCloudflare | |
| }; | |