File size: 4,193 Bytes
4f05ffd
 
 
 
 
 
 
 
7358211
4f05ffd
7358211
83fd9d8
161f857
4f05ffd
7358211
4f05ffd
 
 
 
 
 
7358211
4f05ffd
 
 
7358211
4f05ffd
 
 
7358211
4f05ffd
 
 
7358211
 
 
 
 
 
 
4f05ffd
 
 
 
 
 
 
 
 
 
 
 
 
 
7358211
4f05ffd
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7358211
4f05ffd
 
 
 
 
 
7358211
 
4f05ffd
 
7358211
 
 
 
4f05ffd
7358211
 
 
 
 
 
 
 
 
 
4f05ffd
7358211
 
 
 
 
 
 
 
4f05ffd
 
 
 
 
 
 
 
 
 
 
 
7358211
 
4f05ffd
 
7358211
4f05ffd
 
 
 
 
 
 
7358211
4f05ffd
 
 
 
 
 
7358211
 
 
4f05ffd
7358211
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
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;
const authToken = process.env.authToken || null;
const domain = process.env.DOMAIN || `Limit2`;

// Konfigurasi Global
global.browserLimit = Number(process.env.browserLimit) || 30;
global.timeOut = Number(process.env.timeOut) || 120000;

// Cache System (Pikeun Cloudflare/Turnstile)
const CACHE_DIR = path.join(__dirname, "cache");
const CACHE_FILE = path.join(CACHE_DIR, "cache.json");
const CACHE_TTL = 5 * 60 * 1000;

function loadCache() {
  if (!fs.existsSync(CACHE_FILE)) return {};
  try { return JSON.parse(fs.readFileSync(CACHE_FILE, 'utf-8')); } catch { return {}; }
}

function saveCache(cache) {
  if (!fs.existsSync(CACHE_DIR)) fs.mkdirSync(CACHE_DIR, { recursive: true });
  fs.writeFileSync(CACHE_FILE, JSON.stringify(cache, null, 2), 'utf-8');
}

// Middleware
app.use(express.json({ limit: "50mb" }));
app.use(express.urlencoded({ extended: true, limit: "50mb" }));

// --- IMPORT ENDPOINTS ---
// Ngaran variabel dijieun béda (solveAntibot) meh teu bentrok jeung route /antibot
const solveTurnstile = require('./endpoints/turnstile');
const solveCloudflare = require('./endpoints/cloudflare');
const solveAntibot = require('./endpoints/antibot');

// Dashboard Status
app.get("/", (req, res) => {
  res.json({
    message: "Server is running!",
    endpoints: {
      cloudflare: `${domain}/cloudflare`,
      antibot: `${domain}/antibot`
    },
    status: {
      browserLimit: global.browserLimit,
      authRequired: authToken !== null
    }
  });
});

// Browser Creator Utility
async function createBrowser(proxyServer = null) {
  const connectOptions = {
    headless: false,
    turnstile: true,
    connectOption: { defaultViewport: null },
    disableXvfb: false,
  };
  if (proxyServer) connectOptions.args = [`--proxy-server=${proxyServer}`];

  const { browser } = await connect(connectOptions);
  const [page] = await browser.pages();

  await page.goto('about:blank');
  await page.setRequestInterception(true);
  page.on('request', (req) => {
    if (["image", "stylesheet", "font", "media"].includes(req.resourceType())) req.abort();
    else req.continue();
  });

  return { browser, page };
}

// --- ROUTE: ANTIBOT (KHUSUS PHP BOT) ---
app.post("/antibot", async (req, res) => {
  const data = req.body;

  // Validasi data ti PHP
  if (!data || !data.main || !Array.isArray(data.bots)) {
    return res.status(400).json({ message: "Body format salah (kudu aya main & bots array)" });
  }

  try {
    console.log("Menerima tantangan Antibot...");
    // Manggil fungsi solveAntibot tina folder endpoints/
    const result = await solveAntibot(data);
    
    // Kirim hasilna balik ka PHP
    res.json(result);
  } catch (err) {
    console.error("Error Antibot:", err.message);
    res.status(500).json({ message: err.message });
  }
});

// --- ROUTE: CLOUDFLARE/TURNSTILE ---
app.post('/cloudflare', async (req, res) => {
  const data = req.body;
  if (!data || !data.mode) return res.status(400).json({ message: 'Missing mode' });

  if (global.browserLimit <= 0) return res.status(429).json({ message: 'Server Busy' });

  global.browserLimit--;
  let result, browser;

  try {
    const proxyServer = data.proxy ? `${data.proxy.hostname}:${data.proxy.port}` : null;
    const ctx = await createBrowser(proxyServer);
    browser = ctx.browser;
    const page = ctx.page;

    switch (data.mode) {
      case "turnstile":
        const token = await solveTurnstile(data, page);
        result = { token };
        break;
      case "iuam":
        result = await solveCloudflare(data, page);
        break;
      default:
        result = { code: 400, message: 'Invalid mode' };
    }
  } catch (err) {
    result = { code: 500, message: err.message };
  } finally {
    if (browser) await browser.close();
    global.browserLimit++;
  }

  res.status(result.code ?? 200).json(result);
});

// Start Server
const server = app.listen(port, () => {
  console.log(`API Server jalan dina port ${port}`);
});
server.timeout = global.timeOut;