File size: 8,629 Bytes
56b6d1b | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 | /**
* API.js β FINAL TOTAL
* Rate limiting + Cloudflare Interstitial + Cache + Task Queue
*/
const express = require('express');
const { connect } = require("puppeteer-real-browser");
const fs = require('fs');
const path = require('path');
const app = express();
const port = process.env.PORT || 7860;
// ================= CONFIG =================
global.browserLimit = 100; // Maksimal browser bersamaan
global.timeOut = 120000; // 2 menit timeout
const CACHE_DIR = path.join(__dirname, "cache");
const CACHE_TTL = 5 * 60 * 1000; // 5 menit
const MAX_CONCURRENT = global.browserLimit;
// ================= QUEUE =================
const taskQueue = [];
let activeTasks = 0;
function processQueue() {
if (activeTasks >= MAX_CONCURRENT || taskQueue.length === 0) return;
const { task, resolve, reject } = taskQueue.shift();
activeTasks++;
task()
.then(result => {
activeTasks--;
resolve(result);
processQueue();
})
.catch(error => {
activeTasks--;
reject(error);
processQueue();
});
}
function addTask(task) {
return new Promise((resolve, reject) => {
taskQueue.push({ task, resolve, reject });
processQueue();
});
}
// ================= CACHE =================
function readCache(type, taskId) {
const file = path.join(CACHE_DIR, type, `${taskId}.json`);
if (!fs.existsSync(file)) return null;
try {
const data = JSON.parse(fs.readFileSync(file, 'utf-8'));
if (Date.now() - data.timestamp < CACHE_TTL) return data;
return null;
} catch { return null; }
}
function writeCache(type, taskId, value) {
const dir = path.join(CACHE_DIR, type);
if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
const file = path.join(dir, `${taskId}.json`);
const data = { timestamp: Date.now(), ...value };
fs.writeFileSync(file, JSON.stringify(data, null, 2), 'utf-8');
console.log(`cache SAVED: ${type}:${taskId}`);
}
// ================= CLEAN CACHE PERIODIC =================
setInterval(() => {
const types = ["recaptcha2", "recaptcha3", "turnstile", "interstitial"];
const now = Date.now();
types.forEach(type => {
const dir = path.join(CACHE_DIR, type);
if (!fs.existsSync(dir)) return;
fs.readdirSync(dir).forEach(file => {
const filePath = path.join(dir, file);
try {
const data = JSON.parse(fs.readFileSync(filePath, 'utf-8'));
if (now - data.timestamp > CACHE_TTL) fs.unlinkSync(filePath);
} catch {}
});
});
}, 600000); // 10 menit
// ================= EXPRESS =================
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
const tasks = {};
// Health endpoint
app.get("/health", (req, res) => {
res.json({
status: "healthy",
activeTasks,
queueLength: taskQueue.length,
maxConcurrent: MAX_CONCURRENT,
memory: process.memoryUsage()
});
});
// Root endpoint
app.get("/", (req, res) => {
res.json({
message: "CAPTCHA Solver API",
version: "8.0.0",
limits: { concurrent: MAX_CONCURRENT, timeout: global.timeOut },
endpoints: ["/solve", "/health", "/stats"]
});
});
// ================= SOLVE ENDPOINT =================
app.post('/solve', async (req, res) => {
const { type, domain, siteKey, taskId, action, proxy, isInvisible } = req.body;
// Polling jika taskId dikirim
if (taskId) {
const task = tasks[taskId];
if (!task) return res.status(404).json({ status: "error", message: "Task not found" });
if (task.status === "pending") return res.json({ status: "processing", position: taskQueue.length });
return res.json({ status: task.status, solution: task.solution });
}
// Buat task baru
const newTaskId = Date.now().toString(36) + Math.random().toString(36).substr(2);
tasks[newTaskId] = { status: "pending" };
console.log(`π New task: ${newTaskId}=${type}:${domain}`);
// Cek cache
const cached = readCache(type, newTaskId);
if (cached) {
tasks[newTaskId] = cached;
return res.json({ taskId: newTaskId, status: "done", cached: true });
}
try {
const result = await addTask(async () => {
console.log(`π Processing: ${newTaskId}`);
const ctx = await init_browser(proxy?.server);
const page = ctx.page;
let solution = {};
switch (type) {
case "recaptcha2":
solution = await recaptchaV2({ domain, siteKey, action, isInvisible, proxy }, page);
break;
case "recaptcha3":
solution = await recaptchaV3({ domain, siteKey, action, proxy }, page);
break;
case "turnstile":
solution = await turnstile({ domain, siteKey, action, proxy }, page);
break;
case "interstitial":
solution = await interstitial({ domain, proxy }, page);
break;
default:
throw new Error("Invalid type");
}
tasks[newTaskId] = { status: "done", solution };
writeCache(type, newTaskId, tasks[newTaskId]);
await ctx.browser.close();
console.log(`β
Completed: ${newTaskId}`);
return solution;
});
res.json({
taskId: newTaskId,
status: "queued",
position: taskQueue.length,
estimatedWait: taskQueue.length * 30000
});
} catch (error) {
tasks[newTaskId] = { status: "error", message: error.message };
console.error(`β Failed: ${newTaskId} - ${error.message}`);
res.status(500).json({ taskId: newTaskId, status: "error", message: error.message });
}
});
// GET /solve?taskId=xxx β polling
app.get('/solve', (req, res) => {
const { taskId } = req.query;
if (!taskId) return res.status(400).json({ error: "Missing taskId" });
const task = tasks[taskId];
if (!task) return res.status(404).json({ error: "Task not found" });
if (task.status === "pending") return res.json({ status: "processing", position: taskQueue.length });
return res.json({ status: task.status, solution: task.solution });
});
// ================= BROWSER INIT =================
async function init_browser(proxyServer = null) {
const connectOptions = {
headless: false,
turnstile: true,
connectOption: {
defaultViewport: null,
args: [
'--no-sandbox',
'--disable-setuid-sandbox',
'--disable-dev-shm-usage',
'--disable-accelerated-2d-canvas',
'--disable-gpu',
'--window-size=1024,768'
]
},
disableXvfb: false,
};
if (proxyServer) connectOptions.connectOption.args.push(`--proxy-server=${proxyServer}`);
const { browser } = await connect(connectOptions);
const [page] = await browser.pages();
// Block resources yang tidak perlu
await page.setRequestInterception(true);
page.on('request', req => {
const type = req.resourceType();
if (["image", "stylesheet", "font", "media"].includes(type)) req.abort();
else req.continue();
});
console.log(`π Browser initialized${proxyServer ? " with proxy" : ""}`);
return { browser, page };
}
// ================= LOAD MODULES =================
const recaptchaV2 = require('./Api/recaptcha2');
const recaptchaV3 = require('./Api/recaptcha3');
const turnstile = require('./Api/turnstile');
const interstitial = require('./interstitial'); // pastikan file ini ada
// ================= STATS =================
app.get('/stats', (req, res) => {
res.json({
activeTasks,
queueLength: taskQueue.length,
maxConcurrent: MAX_CONCURRENT,
memory: process.memoryUsage(),
uptime: process.uptime()
});
});
// 404 handler
app.use((req, res) => res.status(404).json({ message: 'Endpoint not found' }));
// ================= START =================
app.listen(port, () => {
console.log(`
==========================================
π CAPTCHA Solver API v8.0.0
π Port: ${port}
β‘ Concurrent Limit: ${MAX_CONCURRENT}
β±οΈ Timeout: ${global.timeOut}ms
π Started: ${new Date().toISOString()}
==========================================
`);
});
|