File size: 2,989 Bytes
46fb463
 
 
 
 
 
 
 
 
 
 
 
60cf846
46fb463
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1445d9d
46fb463
 
 
 
1445d9d
 
 
 
 
 
 
 
46fb463
 
 
 
 
 
 
 
 
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
'use strict';

const express = require('express');
const TurnstileSolver = require('./turnstile-solver');

const app = express();
const PORT = process.env.PORT || 7860;

app.use(express.json());

// Singleton solver — browser tetap hidup selama server berjalan
const solver = new TurnstileSolver({
    timeout: 25000,
    record: false,
    width: 1280,
    height: 720,
});

// Inisialisasi browser saat startup
let ready = false;
(async () => {
    try {
        await solver.initialize();
        ready = true;
        console.log('[API] Solver ready.');
    } catch (e) {
        console.error('[API] Solver init failed:', e.message);
    }
})();

/**
 * GET /bypass/turnstile-min
 * Query params:
 *   - url      : URL target (wajib)
 *   - siteKey  : Sitekey Turnstile (opsional, kalau tidak ada pakai mode page)
 *   - apikey   : API key sederhana untuk proteksi (opsional, cek env API_KEY)
 *
 * Response (sukses):
 *   { status: true, token: "...", time: 3.2 }
 *
 * Response (gagal):
 *   { status: false, message: "..." }
 */
app.get('/bypass/turnstile-min', async (req, res) => {
    // Cek API key kalau dikonfigurasi
    const apiKey = process.env.API_KEY;
    if (apiKey && req.query.apikey !== apiKey) {
        return res.status(401).json({ status: false, message: 'Invalid API key.' });
    }

    const { url, siteKey } = req.query;

    if (!url) {
        return res.status(400).json({ status: false, message: 'Parameter "url" wajib diisi.' });
    }

    if (!ready) {
        return res.status(503).json({ status: false, message: 'Solver belum siap, coba lagi sebentar.' });
    }

    try {
        const result = await solver.solve(url, siteKey || null);

        if (!result.success) {
            return res.status(500).json({
                status: false,
                message: result.error || 'Gagal mendapatkan token Turnstile.',
                time: result.time,
            });
        }

        return res.json({
            status: true,
            creator: 'XAi Community',
            token: result.token,
            time: result.time,
        });
    } catch (e) {
        return res.status(500).json({ status: false, message: e.message });
    }
});

// Health check
app.get('/', (req, res) => {
    res.json({
        status: 'ok',
        ready,
        endpoints: [
            'GET /bypass/turnstile-min?url=<URL>&siteKey=<SITEKEY>&apikey=<KEY>',
            'GET /debug/screenshot — lihat screenshot terakhir saat solving gagal',
        ],
    });
});

// Debug: lihat screenshot terakhir
const fs = require('fs');
app.get('/debug/screenshot', (req, res) => {
    const p = '/tmp/debug_turnstile.png';
    if (!fs.existsSync(p)) return res.status(404).json({ error: 'Belum ada screenshot.' });
    res.sendFile(p);
});

app.listen(PORT, '0.0.0.0', () => {
    console.log(`[API] Server jalan di port ${PORT}`);
});

// Cleanup saat proses mati
process.on('SIGTERM', async () => {
    await solver.cleanup();
    process.exit(0);
});