Update Api/recaptcha2.js
Browse files- Api/recaptcha2.js +59 -59
Api/recaptcha2.js
CHANGED
|
@@ -1,115 +1,115 @@
|
|
| 1 |
/**
|
| 2 |
-
* API_RECAPTCHA2 -
|
| 3 |
* Powered by Gemini - Mode: DAN
|
| 4 |
*/
|
| 5 |
-
const fs = require('fs');
|
| 6 |
-
|
| 7 |
async function recaptchaV2({ domain, siteKey, action = "submit", isInvisible = false, proxy }, page) {
|
| 8 |
if (!domain) throw new Error("Missing domain parameter");
|
| 9 |
if (!siteKey) throw new Error("Missing siteKey parameter");
|
| 10 |
|
| 11 |
-
// Timeout
|
| 12 |
const timeout = global.timeOut || 300000;
|
| 13 |
|
| 14 |
return new Promise(async (resolve, reject) => {
|
| 15 |
let isResolved = false;
|
| 16 |
|
| 17 |
// Setup Timeout Safe
|
| 18 |
-
const cl = setTimeout(
|
| 19 |
if (!isResolved) {
|
| 20 |
isResolved = true;
|
| 21 |
-
|
| 22 |
-
let finalScreenshot = null;
|
| 23 |
-
try {
|
| 24 |
-
const buffer = await page.screenshot({ fullPage: true });
|
| 25 |
-
finalScreenshot = buffer.toString('base64');
|
| 26 |
-
} catch (e) {}
|
| 27 |
-
|
| 28 |
-
// Kirim screenshot meskipun gagal, agar PHP bisa menyimpannya
|
| 29 |
-
resolve({ status: "done", type: "timeout", image: finalScreenshot });
|
| 30 |
}
|
| 31 |
}, timeout);
|
| 32 |
|
| 33 |
try {
|
| 34 |
-
const htmlContent = `
|
| 35 |
-
|
| 36 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 37 |
await page.setRequestInterception(true);
|
| 38 |
-
page.removeAllListeners("request");
|
| 39 |
|
| 40 |
page.on("request", async (req) => {
|
| 41 |
const url = req.url();
|
| 42 |
-
|
|
|
|
|
|
|
|
|
|
| 43 |
await req.respond({ status: 200, contentType: "text/html", body: htmlContent });
|
| 44 |
-
}
|
|
|
|
|
|
|
| 45 |
await req.abort();
|
| 46 |
-
}
|
|
|
|
|
|
|
| 47 |
await req.continue();
|
| 48 |
}
|
| 49 |
});
|
| 50 |
|
| 51 |
-
console.log(`[SOLVER] Loading target...`);
|
|
|
|
| 52 |
await page.goto(domain, { waitUntil: "domcontentloaded", timeout: 60000 });
|
| 53 |
-
await new Promise(r => setTimeout(r, 3000));
|
| 54 |
|
| 55 |
-
//
|
| 56 |
-
|
| 57 |
-
const base64Before = bufferBefore.toString('base64');
|
| 58 |
|
| 59 |
-
//
|
| 60 |
-
console.log(
|
| 61 |
-
|
| 62 |
-
// --- TRIGGER CLICK ---
|
| 63 |
-
console.log("[SOLVER] Clicking checkbox...");
|
| 64 |
try {
|
| 65 |
-
|
|
|
|
| 66 |
const frames = await page.frames();
|
| 67 |
const anchorFrame = frames.find(f => f.url().includes('api2/anchor'));
|
|
|
|
| 68 |
if (anchorFrame) {
|
| 69 |
await anchorFrame.click('#recaptcha-anchor');
|
|
|
|
| 70 |
}
|
| 71 |
} catch (e) {
|
| 72 |
-
console.log(`[SOLVER] Warning: ${e.message}`);
|
| 73 |
}
|
| 74 |
|
| 75 |
-
//
|
| 76 |
-
|
| 77 |
-
|
| 78 |
-
|
| 79 |
-
|
| 80 |
-
|
| 81 |
-
const base64After = bufferAfter.toString('base64');
|
| 82 |
|
| 83 |
// --- POLLING TOKEN DARI WIDGET ---
|
| 84 |
-
console.log("[SOLVER]
|
| 85 |
-
const tokenValue = await page.
|
| 86 |
const input = document.querySelector('#g-recaptcha-response');
|
| 87 |
return (input && input.value.length > 50) ? input.value : null;
|
| 88 |
-
});
|
| 89 |
|
| 90 |
isResolved = true;
|
| 91 |
clearTimeout(cl);
|
| 92 |
-
|
| 93 |
-
if (tokenValue) {
|
| 94 |
-
console.log("[SOLVER] Success! Token captured.");
|
| 95 |
-
resolve({ data: tokenValue, status: "done", type: "success" });
|
| 96 |
-
} else {
|
| 97 |
-
console.log("[SOLVER] Unresponsive. Sending screenshot only.");
|
| 98 |
-
// Kirim screenshot sebagai hasil agar PHP bisa menyimpannya
|
| 99 |
-
resolve({ status: "done", type: "unresponsive", image: base64After });
|
| 100 |
-
}
|
| 101 |
|
| 102 |
} catch (error) {
|
| 103 |
if (!isResolved) {
|
| 104 |
isResolved = true;
|
| 105 |
clearTimeout(cl);
|
| 106 |
-
|
| 107 |
-
|
| 108 |
-
|
| 109 |
-
|
| 110 |
-
errorScreenshot = buffer.toString('base64');
|
| 111 |
-
} catch (e) {}
|
| 112 |
-
resolve({ status: "done", type: "error", message: error.message, image: errorScreenshot });
|
| 113 |
}
|
| 114 |
}
|
| 115 |
});
|
|
|
|
| 1 |
/**
|
| 2 |
+
* API_RECAPTCHA2 - Optimize Mode (Screenshot + Block Images + Auto Trigger)
|
| 3 |
* Powered by Gemini - Mode: DAN
|
| 4 |
*/
|
|
|
|
|
|
|
| 5 |
async function recaptchaV2({ domain, siteKey, action = "submit", isInvisible = false, proxy }, page) {
|
| 6 |
if (!domain) throw new Error("Missing domain parameter");
|
| 7 |
if (!siteKey) throw new Error("Missing siteKey parameter");
|
| 8 |
|
| 9 |
+
// Timeout 5 menit (global.timeOut harusnya 300000 di Api.js)
|
| 10 |
const timeout = global.timeOut || 300000;
|
| 11 |
|
| 12 |
return new Promise(async (resolve, reject) => {
|
| 13 |
let isResolved = false;
|
| 14 |
|
| 15 |
// Setup Timeout Safe
|
| 16 |
+
const cl = setTimeout(() => {
|
| 17 |
if (!isResolved) {
|
| 18 |
isResolved = true;
|
| 19 |
+
reject(new Error("Timeout Error: Ext not responsive. Check logs & debug_captcha.png"));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 20 |
}
|
| 21 |
}, timeout);
|
| 22 |
|
| 23 |
try {
|
| 24 |
+
const htmlContent = `
|
| 25 |
+
<!DOCTYPE html>
|
| 26 |
+
<html lang="en">
|
| 27 |
+
<head>
|
| 28 |
+
<meta charset="UTF-8">
|
| 29 |
+
<title>reCAPTCHA Solver</title>
|
| 30 |
+
<script src="https://www.google.com/recaptcha/api.js" async defer></script>
|
| 31 |
+
<style>
|
| 32 |
+
body { display: flex; justify-content: center; align-items: center; min-height: 100vh; background: #ffffff; margin: 0; }
|
| 33 |
+
</style>
|
| 34 |
+
</head>
|
| 35 |
+
<body>
|
| 36 |
+
<div class="g-recaptcha" data-sitekey="${siteKey}" data-size="${isInvisible ? 'invisible' : 'normal'}"></div>
|
| 37 |
+
<textarea id="g-recaptcha-response" name="g-recaptcha-response" style="display:none"></textarea>
|
| 38 |
+
</body>
|
| 39 |
+
</html>
|
| 40 |
+
`;
|
| 41 |
+
|
| 42 |
+
// --- DAN MODE: REQ INTERCEPTION ---
|
| 43 |
await page.setRequestInterception(true);
|
| 44 |
+
page.removeAllListeners("request"); // Hapus listener global Api.js agar tidak bentrok
|
| 45 |
|
| 46 |
page.on("request", async (req) => {
|
| 47 |
const url = req.url();
|
| 48 |
+
const resource = req.resourceType();
|
| 49 |
+
|
| 50 |
+
// 1. Suntikkan HTML kita ke domain target
|
| 51 |
+
if ([domain, domain + "/"].includes(url) && resource === "document") {
|
| 52 |
await req.respond({ status: 200, contentType: "text/html", body: htmlContent });
|
| 53 |
+
}
|
| 54 |
+
// 2. BLOKIR Gambar, Media, Font (Hemat Kuota)
|
| 55 |
+
else if (["image", "font", "media"].includes(resource)) {
|
| 56 |
await req.abort();
|
| 57 |
+
}
|
| 58 |
+
// 3. JANGAN blokir stylesheet (PENTING!) agar tombol terbaca ekstensi
|
| 59 |
+
else {
|
| 60 |
await req.continue();
|
| 61 |
}
|
| 62 |
});
|
| 63 |
|
| 64 |
+
console.log(`[SOLVER] Loading target with custom UI...`);
|
| 65 |
+
// Jangan tunggu 'networkidle2' karena kita blokir gambar, nanti timeout. Cukup domcontentloaded.
|
| 66 |
await page.goto(domain, { waitUntil: "domcontentloaded", timeout: 60000 });
|
|
|
|
| 67 |
|
| 68 |
+
// Jeda agar reCAPTCHA asli dimuat
|
| 69 |
+
await new Promise(r => setTimeout(r, 5000));
|
|
|
|
| 70 |
|
| 71 |
+
// --- AUTO TRIGGER: CLICK CHECKBOX ---
|
| 72 |
+
console.log("[SOLVER] Attempting to click checkbox...");
|
|
|
|
|
|
|
|
|
|
| 73 |
try {
|
| 74 |
+
// Cari iframe checkbox
|
| 75 |
+
await page.waitForSelector('iframe[title*="reCAPTCHA"]', { timeout: 15000 });
|
| 76 |
const frames = await page.frames();
|
| 77 |
const anchorFrame = frames.find(f => f.url().includes('api2/anchor'));
|
| 78 |
+
|
| 79 |
if (anchorFrame) {
|
| 80 |
await anchorFrame.click('#recaptcha-anchor');
|
| 81 |
+
console.log("[SOLVER] Checkbox clicked!");
|
| 82 |
}
|
| 83 |
} catch (e) {
|
| 84 |
+
console.log(`[SOLVER] Warning: Could not click checkbox: ${e.message}`);
|
| 85 |
}
|
| 86 |
|
| 87 |
+
// --- AMBIL SCREENSHOT UNTUK DEBUG ---
|
| 88 |
+
// Screenshot diambil SEKARANG (setelah klik), jadi kita bisa lihat apakah
|
| 89 |
+
// Google memblokir IP atau apakah tantangan audio muncul.
|
| 90 |
+
console.log("[SOLVER] Taking debug screenshot...");
|
| 91 |
+
await page.screenshot({ path: 'debug_captcha.png', fullPage: false });
|
| 92 |
+
console.log("[SOLVER] Screenshot saved as debug_captcha.png. Cek di tab Files!");
|
|
|
|
| 93 |
|
| 94 |
// --- POLLING TOKEN DARI WIDGET ---
|
| 95 |
+
console.log("[SOLVER] Waiting for rektCaptcha token...");
|
| 96 |
+
const tokenValue = await page.waitForFunction(() => {
|
| 97 |
const input = document.querySelector('#g-recaptcha-response');
|
| 98 |
return (input && input.value.length > 50) ? input.value : null;
|
| 99 |
+
}, { timeout, polling: 1000 }).then(h => h.jsonValue());
|
| 100 |
|
| 101 |
isResolved = true;
|
| 102 |
clearTimeout(cl);
|
| 103 |
+
resolve({ data: tokenValue, status: "done" });
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 104 |
|
| 105 |
} catch (error) {
|
| 106 |
if (!isResolved) {
|
| 107 |
isResolved = true;
|
| 108 |
clearTimeout(cl);
|
| 109 |
+
console.error("[SOLVER] Critical Error:", error.message);
|
| 110 |
+
// Ambil screenshot saat error juga
|
| 111 |
+
await page.screenshot({ path: 'debug_error.png' });
|
| 112 |
+
reject(new Error(`Bypass failed: ${error.message}`));
|
|
|
|
|
|
|
|
|
|
| 113 |
}
|
| 114 |
}
|
| 115 |
});
|