// src/captcha.js — Optional CAPTCHA solving (2captcha / CapSolver) const fetch = require("node-fetch"); const CAPTCHA_KEY = process.env.CAPTCHA_API_KEY; const CAPTCHA_SERVICE = process.env.CAPTCHA_SERVICE || "2captcha"; // "2captcha" বা "capsolver" // ── 2captcha ────────────────────────────────────────────────────────────── async function solve2captcha(type, params) { const baseUrl = "https://2captcha.com"; // Submit const submitRes = await fetch(`${baseUrl}/in.php`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ key: CAPTCHA_KEY, method: type, json: 1, ...params }), }); const submitData = await submitRes.json(); if (submitData.status !== 1) throw new Error(`2captcha submit failed: ${submitData.request}`); const taskId = submitData.request; // Poll result for (let i = 0; i < 24; i++) { await new Promise((r) => setTimeout(r, 5000)); const res = await fetch(`${baseUrl}/res.php?key=${CAPTCHA_KEY}&action=get&id=${taskId}&json=1`); const data = await res.json(); if (data.status === 1) return data.request; if (data.request !== "CAPCHA_NOT_READY") throw new Error(`2captcha error: ${data.request}`); } throw new Error("2captcha timeout"); } // ── CapSolver ───────────────────────────────────────────────────────────── async function solveCapsolver(type, params) { const res = await fetch("https://api.capsolver.com/createTask", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ clientKey: CAPTCHA_KEY, task: { type, ...params } }), }); const data = await res.json(); if (data.errorId) throw new Error(`CapSolver error: ${data.errorDescription}`); const taskId = data.taskId; for (let i = 0; i < 24; i++) { await new Promise((r) => setTimeout(r, 5000)); const res2 = await fetch("https://api.capsolver.com/getTaskResult", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ clientKey: CAPTCHA_KEY, taskId }), }); const result = await res2.json(); if (result.status === "ready") return result.solution?.gRecaptchaResponse || result.solution?.token; if (result.errorId) throw new Error(`CapSolver: ${result.errorDescription}`); } throw new Error("CapSolver timeout"); } // ── Main solver ─────────────────────────────────────────────────────────── async function solveCaptcha(type, params) { if (!CAPTCHA_KEY) throw new Error("CAPTCHA_API_KEY নেই"); if (CAPTCHA_SERVICE === "capsolver") return solveCapsolver(type, params); return solve2captcha(type, params); } // ── reCAPTCHA v2 solve + inject ─────────────────────────────────────────── async function solveRecaptchaV2(page) { if (!CAPTCHA_KEY) return false; try { const siteKey = await page.evaluate(() => { const el = document.querySelector(".g-recaptcha,[data-sitekey]"); return el?.dataset?.sitekey || null; }); if (!siteKey) return false; console.log("🤖 reCAPTCHA v2 solve করছি..."); const token = await solveCaptcha("userrecaptcha", { googlekey: siteKey, pageurl: page.url() }); await page.evaluate((t) => { document.getElementById("g-recaptcha-response").innerHTML = t; if (window.___grecaptcha_cfg) { const entries = Object.entries(window.___grecaptcha_cfg.clients || {}); if (entries.length) entries[0][1]?.aa?.l?.click?.(); } }, token); return true; } catch (err) { console.warn("CAPTCHA solve failed:", err.message); return false; } } // ── hCaptcha solve ──────────────────────────────────────────────────────── async function solveHcaptcha(page) { if (!CAPTCHA_KEY) return false; try { const siteKey = await page.evaluate(() => document.querySelector("[data-hcaptcha-widget-id],[data-sitekey]")?.dataset?.sitekey || null ); if (!siteKey) return false; console.log("🤖 hCaptcha solve করছি..."); const token = CAPTCHA_SERVICE === "capsolver" ? await solveCapsolver("HCaptchaTaskProxyLess", { websiteURL: page.url(), websiteKey: siteKey }) : await solve2captcha("hcaptcha", { sitekey: siteKey, pageurl: page.url() }); await page.evaluate((t) => { const ta = document.querySelector("[name=h-captcha-response]"); if (ta) ta.value = t; }, token); return true; } catch (err) { console.warn("hCaptcha solve failed:", err.message); return false; } } function isAvailable() { return !!CAPTCHA_KEY; } module.exports = { solveCaptcha, solveRecaptchaV2, solveHcaptcha, isAvailable };