testapi / Api.js
gadisk820's picture
Upload 22 files
56b6d1b verified
/**
* 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()}
==========================================
`);
});