XBotz commited on
Commit
2e625ce
Β·
unverified Β·
0 Parent(s):

Create turnstile-solver.js

Browse files
Files changed (1) hide show
  1. turnstile-solver.js +228 -0
turnstile-solver.js ADDED
@@ -0,0 +1,228 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+
4
+ const puppeteer = require('puppeteer-extra');
5
+ puppeteer.use(require('puppeteer-extra-plugin-stealth')());
6
+ const fs = require('fs');
7
+ const path = require('path');
8
+
9
+ const FALLBACK_UA = [
10
+ "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 Chrome/120.0 Safari/537.36",
11
+ "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 Chrome/120.0 Safari/537.36",
12
+ "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:120.0) Gecko/20100101 Firefox/120.0",
13
+ ];
14
+
15
+ const HTML_TEMPLATE = `<!DOCTYPE html>
16
+ <html lang="en">
17
+ <head>
18
+ <meta charset="UTF-8">
19
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
20
+ <title>Turnstile Solver</title>
21
+ <script src="https://challenges.cloudflare.com/turnstile/v0/api.js" async></script>
22
+ <style>
23
+ body{display:flex;justify-content:center;align-items:center;height:100vh;margin:0;background:#f0f0f0;font-family:Arial}
24
+ .container{background:white;padding:30px;border-radius:10px;box-shadow:0 4px 20px rgba(0,0,0,.1);text-align:center}
25
+ .turnstile-container{margin-top:20px}
26
+ #status{margin-top:20px;background:#f8f8f8;padding:10px;border-radius:6px}
27
+ </style>
28
+ <script>
29
+ function updateStatus(t){document.getElementById("status").innerText=t}
30
+ function checkToken(){const el=document.querySelector("[name='cf-turnstile-response']");if(el&&el.value)updateStatus("Token received ("+el.value.length+" chars)")}
31
+ window.onload=function(){setInterval(checkToken,500);updateStatus("Turnstile loading...")}
32
+ </script>
33
+ </head>
34
+ <body>
35
+ <div class="container">
36
+ <h2>Cloudflare Turnstile Test</h2>
37
+ <div class="turnstile-container"><!-- TURNSTILE_WIDGET --></div>
38
+ <div id="status">Initializing...</div>
39
+ </div>
40
+ </body>
41
+ </html>`;
42
+
43
+ const sleep = (ms) => new Promise(r => setTimeout(r, ms));
44
+ const rand = (arr) => arr[Math.floor(Math.random() * arr.length)];
45
+
46
+ function getRandomUA() {
47
+ try {
48
+ const p = path.join("data", "useragents.txt");
49
+ if (fs.existsSync(p)) {
50
+ const uas = fs.readFileSync(p, "utf8").split("\n").map(l => l.trim()).filter(Boolean);
51
+ if (uas.length) return rand(uas);
52
+ }
53
+ } catch {}
54
+ return rand(FALLBACK_UA);
55
+ }
56
+
57
+ function getRandomProxy() {
58
+ try {
59
+ const p = path.join("data", "proxies.txt");
60
+ if (fs.existsSync(p)) {
61
+ const proxies = fs.readFileSync(p, "utf8").split("\n").map(l => l.trim()).filter(Boolean);
62
+ if (proxies.length) return rand(proxies);
63
+ }
64
+ } catch {}
65
+ return null;
66
+ }
67
+
68
+ class TurnstileSolver {
69
+ constructor({ headless = true, threads = 1, useProxy = false, useragent = null } = {}) {
70
+ this.headless = headless;
71
+ this.threads = threads;
72
+ this.useProxy = useProxy;
73
+ this.useragent = useragent || getRandomUA();
74
+ this.pool = []; // array of browser instances
75
+ }
76
+
77
+ async initialize() {
78
+ for (let i = 0; i < this.threads; i++) {
79
+ this.pool.push(await this._createBrowser());
80
+ }
81
+ }
82
+
83
+ async _createBrowser() {
84
+ const args = [
85
+ "--no-sandbox",
86
+ "--disable-dev-shm-usage",
87
+ "--disable-blink-features=AutomationControlled",
88
+ "--disable-web-security",
89
+ `--user-agent=${this.useragent}`,
90
+ ];
91
+ return puppeteer.launch({ headless: this.headless, args });
92
+ }
93
+
94
+ async _acquireBrowser() {
95
+ // Simple pool: wait until one is available
96
+ while (this.pool.length === 0) await sleep(100);
97
+ return this.pool.pop();
98
+ }
99
+
100
+ _releaseBrowser(browser) {
101
+ this.pool.push(browser);
102
+ }
103
+
104
+ async solve(url, sitekey, action = null) {
105
+ const t0 = Date.now();
106
+ const browser = await this._acquireBrowser();
107
+ try {
108
+ const result = await this._solvePage(browser, url, sitekey, action, t0);
109
+ this._releaseBrowser(browser);
110
+ return result;
111
+ } catch (err) {
112
+ this._releaseBrowser(browser);
113
+ return { success: false, error: err.message, time: ((Date.now() - t0) / 1000).toFixed(3) };
114
+ }
115
+ }
116
+
117
+ async _solvePage(browser, url, sitekey, action, t0) {
118
+ const contextOpts = {};
119
+ if (this.useProxy) {
120
+ const proxy = getRandomProxy();
121
+ if (proxy) contextOpts.proxyServer = proxy;
122
+ }
123
+
124
+ const ctx = await browser.createBrowserContext();
125
+ const page = await ctx.newPage();
126
+
127
+ // Build widget HTML
128
+ let widget = `<div class="cf-turnstile" data-sitekey="${sitekey}"`;
129
+ if (action) widget += ` data-action="${action}"`;
130
+ widget += "></div>";
131
+ const html = HTML_TEMPLATE.replace("<!-- TURNSTILE_WIDGET -->", widget);
132
+
133
+ const urlFixed = url.endsWith("/") ? url : url + "/";
134
+
135
+ // Intercept the target URL and serve our HTML
136
+ await page.setRequestInterception(true);
137
+ page.on('request', (req) => {
138
+ if (req.url() === urlFixed && req.resourceType() === 'document') {
139
+ req.respond({ status: 200, contentType: 'text/html', body: html });
140
+ } else {
141
+ req.continue();
142
+ }
143
+ });
144
+
145
+ await page.goto(urlFixed, { waitUntil: 'domcontentloaded' });
146
+ await page.waitForSelector('.cf-turnstile', { timeout: 10000 });
147
+ await sleep(2000);
148
+
149
+ // Try clicking the widget/iframe
150
+ try {
151
+ const iframe = await page.$('iframe[title*="cloudflare"]');
152
+ if (iframe) await iframe.click();
153
+ else await page.click('.cf-turnstile');
154
+ } catch {
155
+ await page.evaluate(() => document.querySelector('.cf-turnstile')?.click());
156
+ }
157
+
158
+ // Poll for token up to 30s
159
+ for (let i = 0; i < 30; i++) {
160
+ const token = await page.evaluate(() => {
161
+ const el = document.querySelector("[name='cf-turnstile-response']");
162
+ return el?.value || null;
163
+ });
164
+ if (token) {
165
+ await ctx.close();
166
+ return { success: true, creator: "XAi Community", token, time: +((Date.now() - t0) / 1000).toFixed(3) }; // Jangan hapus creator! | Don't remove creator!
167
+ }
168
+ await sleep(1000);
169
+ }
170
+
171
+ await ctx.close();
172
+ throw new Error("Token not received");
173
+ }
174
+
175
+ async cleanup() {
176
+ for (const browser of this.pool) {
177
+ try { await browser.close(); } catch {}
178
+ }
179
+ this.pool = [];
180
+ }
181
+ }
182
+
183
+ // ─── CLI ──────────────────────────────────────────────────────────────────────
184
+
185
+ function parseArgs() {
186
+ const args = process.argv.slice(2);
187
+ const get = (flag, def = null) => {
188
+ const i = args.indexOf(flag);
189
+ return i !== -1 ? args[i + 1] ?? def : def;
190
+ };
191
+ const has = (flag) => args.includes(flag);
192
+ return {
193
+ url: get("--url"),
194
+ sitekey: get("--sitekey"),
195
+ action: get("--action"),
196
+ threads: parseInt(get("--threads", "1"), 10),
197
+ headless: has("--headless"),
198
+ proxy: has("--proxy"),
199
+ };
200
+ }
201
+
202
+ async function main() {
203
+ const args = parseArgs();
204
+ if (!args.url || !args.sitekey) {
205
+ console.error("Usage: node turnstile-solver.js --url <url> --sitekey <key> [--action <a>] [--threads N] [--headless] [--proxy]");
206
+ process.exit(1);
207
+ }
208
+
209
+ const solver = new TurnstileSolver({
210
+ headless: args.headless,
211
+ threads: args.threads,
212
+ useProxy: args.proxy,
213
+ });
214
+
215
+ await solver.initialize();
216
+ try {
217
+ const result = await solver.solve(args.url, args.sitekey, args.action);
218
+ console.log(JSON.stringify(result));
219
+ } finally {
220
+ await solver.cleanup();
221
+ }
222
+ }
223
+
224
+ main().catch(err => { console.error(err.message); process.exit(1); });
225
+
226
+ /** Install:
227
+ * npm install puppeteer-extra puppeteer-extra-plugin-stealth
228
+ */