fix: rewrite token detection — polling + exposeFunction instead of waitForSelector
Browse files- turnstile-solver.js +28 -5
turnstile-solver.js
CHANGED
|
@@ -149,21 +149,44 @@ class TurnstileSolver {
|
|
| 149 |
const fakeHtml = FAKE_PAGE.replace(/<site-key>/g, siteKey);
|
| 150 |
const baseUrl = url.endsWith('/') ? url : url + '/';
|
| 151 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 152 |
await page.setRequestInterception(true);
|
| 153 |
page.on('request', async (req) => {
|
| 154 |
if ([url, baseUrl].includes(req.url()) && req.resourceType() === 'document') {
|
| 155 |
-
await req.respond({ status: 200, contentType: 'text/html', body:
|
| 156 |
} else {
|
| 157 |
await req.continue().catch(() => {});
|
| 158 |
}
|
| 159 |
});
|
| 160 |
|
| 161 |
await page.goto(url, { waitUntil: 'domcontentloaded', timeout: 25000 });
|
| 162 |
-
await page.waitForSelector('[name="cf-response"]', { timeout: this.timeout });
|
| 163 |
|
| 164 |
-
|
| 165 |
-
|
| 166 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 167 |
|
| 168 |
await this._stopRecording(rec);
|
| 169 |
await page.close();
|
|
|
|
| 149 |
const fakeHtml = FAKE_PAGE.replace(/<site-key>/g, siteKey);
|
| 150 |
const baseUrl = url.endsWith('/') ? url : url + '/';
|
| 151 |
|
| 152 |
+
// Tangkap token via exposed function — dipanggil dari callback turnstile
|
| 153 |
+
let capturedToken = null;
|
| 154 |
+
await page.exposeFunction('__onTurnstileToken', (t) => { capturedToken = t; });
|
| 155 |
+
|
| 156 |
+
// Fake HTML pakai callback yang memanggil exposed function
|
| 157 |
+
const injectedHtml = fakeHtml.replace(
|
| 158 |
+
'callback: function (token) {',
|
| 159 |
+
'callback: function (token) { window.__onTurnstileToken(token);'
|
| 160 |
+
);
|
| 161 |
+
|
| 162 |
await page.setRequestInterception(true);
|
| 163 |
page.on('request', async (req) => {
|
| 164 |
if ([url, baseUrl].includes(req.url()) && req.resourceType() === 'document') {
|
| 165 |
+
await req.respond({ status: 200, contentType: 'text/html', body: injectedHtml });
|
| 166 |
} else {
|
| 167 |
await req.continue().catch(() => {});
|
| 168 |
}
|
| 169 |
});
|
| 170 |
|
| 171 |
await page.goto(url, { waitUntil: 'domcontentloaded', timeout: 25000 });
|
|
|
|
| 172 |
|
| 173 |
+
// Poll: cek capturedToken atau window.turnstile.getResponse()
|
| 174 |
+
const deadline = Date.now() + this.timeout;
|
| 175 |
+
let token = null;
|
| 176 |
+
while (Date.now() < deadline) {
|
| 177 |
+
if (capturedToken) { token = capturedToken; break; }
|
| 178 |
+
token = await page.evaluate(() => {
|
| 179 |
+
try { return window.turnstile?.getResponse() || null; } catch { return null; }
|
| 180 |
+
});
|
| 181 |
+
if (token && token.length > 10) break;
|
| 182 |
+
// Cek juga DOM fallback
|
| 183 |
+
token = await page.evaluate(() =>
|
| 184 |
+
document.querySelector('[name="cf-response"]')?.value ?? null
|
| 185 |
+
);
|
| 186 |
+
if (token && token.length > 10) break;
|
| 187 |
+
token = null;
|
| 188 |
+
await new Promise(r => setTimeout(r, 500));
|
| 189 |
+
}
|
| 190 |
|
| 191 |
await this._stopRecording(rec);
|
| 192 |
await page.close();
|