NAME commited on
Commit
6403d77
·
1 Parent(s): 5f2330c

Deploy to HF Space

Browse files
Files changed (9) hide show
  1. Api.js +205 -0
  2. Api/Api.md +1 -0
  3. Api/interstitial.js +82 -0
  4. Api/recaptcha2.js +228 -0
  5. Api/recaptcha3.js +54 -0
  6. Api/turnstile.js +92 -0
  7. Dockerfile +25 -0
  8. README.md +6 -5
  9. package.json +17 -0
Api.js ADDED
@@ -0,0 +1,205 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * API.js
3
+ */
4
+ const express = require('express');
5
+ const { connect } = require("puppeteer-real-browser");
6
+ const fs = require('fs');
7
+ const path = require('path');
8
+
9
+ const app = express();
10
+ const port = process.env.PORT || 7860;
11
+ const authToken = process.env.authToken || null;
12
+
13
+ global.browserLimit = 100;
14
+ global.timeOut = 300000;
15
+
16
+ // cache
17
+ const CACHE_DIR = path.join(__dirname, "cache");
18
+ const CACHE_FILE = path.join(CACHE_DIR, "cache.json");
19
+ const CACHE_TTL = 5 * 60 * 1000;
20
+ const CACHE_AUTOSAVE = process.env.CACHE_AUTOSAVE === "true";
21
+
22
+ function readCache(type, taskId) {
23
+ const file = path.join(CACHE_DIR, type, `${taskId}.json`);
24
+ if (!fs.existsSync(file)) return null;
25
+
26
+ try {
27
+ const data = JSON.parse(fs.readFileSync(file, 'utf-8'));
28
+ console.log(`cache check: ${type}:${taskId} => ${data ? "HIT" : "MISS"}`);
29
+ if (Date.now() - data.timestamp < CACHE_TTL) {
30
+ return data;
31
+ }
32
+ return null;
33
+ } catch {
34
+ return null;
35
+ }
36
+ }
37
+
38
+ function writeCache(type, taskId, value) {
39
+ const dir = path.join(CACHE_DIR, type);
40
+ if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
41
+
42
+ const file = path.join(dir, `${taskId}.json`);
43
+ const data = { timestamp: Date.now(), ...value };
44
+
45
+ fs.writeFileSync(file, JSON.stringify(data, null, 2), 'utf-8');
46
+ console.log(`cache saved: ${type}:${taskId}`);
47
+ }
48
+
49
+ function cleanCache() {
50
+ const types = ["turnstile", "recaptcha3", "recaptcha2", "interstitial", "error"];
51
+ const now = Date.now();
52
+ const TTL = 60 * 60 * 1000;
53
+
54
+ types.forEach(type => {
55
+ const dir = path.join(CACHE_DIR, type);
56
+ if (!fs.existsSync(dir)) return;
57
+
58
+ fs.readdirSync(dir).forEach(file => {
59
+ const filePath = path.join(dir, file);
60
+ try {
61
+ const data = JSON.parse(fs.readFileSync(filePath, 'utf-8'));
62
+ if (now - data.timestamp > TTL) {
63
+ fs.unlinkSync(filePath);
64
+ console.log(`cache expired: ${filePath}`);
65
+ }
66
+ } catch {
67
+ fs.unlinkSync(filePath);
68
+ }
69
+ });
70
+ });
71
+ }
72
+
73
+ setInterval(cleanCache, 600 * 1000);
74
+
75
+ app.use(express.json());
76
+ app.use(express.urlencoded({ extended: true }));
77
+ const tasks = {};
78
+
79
+ // Api_route
80
+ app.get("/", (req, res) => {
81
+ const baseUrl = `${req.protocol}://${req.get('host')}`;
82
+ const uptime = process.uptime();
83
+ res.json({
84
+ message: "Welcome",
85
+ server: {
86
+ domain: baseUrl,
87
+ version: "7.3.0",
88
+ uptime: `${Math.floor(uptime)} seconds`,
89
+ limit: global.browserLimit,
90
+ timeout: global.timeOut,
91
+ status: "recently running"
92
+ },
93
+ solvers: ["turnstile", "recaptcha2", "recaptcha3", "interstitial"]
94
+ });
95
+ });
96
+
97
+
98
+ app.post('/solve', async (req, res) => {
99
+ const { type, domain, siteKey, taskId, action, proxy, isInvisible } = req.body;
100
+
101
+ if (taskId) {
102
+ const task = tasks[taskId];
103
+ if (!task) return res.status(404).json({ status: "error", message: "Task not found" });
104
+
105
+ if (task.status === "pending") {
106
+ return res.json({ status: "processing" });
107
+ }
108
+
109
+ return res.json(task);
110
+ }
111
+
112
+ const newTaskId = Date.now().toString(36);
113
+ tasks[newTaskId] = { status: "pending" };
114
+ console.log(`New : ${newTaskId}=${type}:${domain}`);
115
+
116
+ (async () => {
117
+ try {
118
+ const ctx = await init_browser(proxy?.server);
119
+ const page = ctx.page;
120
+ let result;
121
+
122
+ switch (type) {
123
+ case "turnstile":
124
+ result = await turnstile({ domain, siteKey, action, proxy }, page);
125
+ tasks[newTaskId] = { status: "done", ...result };
126
+ console.log(`done: ${newTaskId}=${type}:${domain}`);
127
+ if (CACHE_AUTOSAVE) writeCache("turnstile", newTaskId, tasks[newTaskId]);
128
+ break;
129
+
130
+ case "interstitial":
131
+ result = await interstitial({ domain, proxy }, page);
132
+ tasks[newTaskId] = { status: "done", ...result };
133
+ console.log(`done: ${newTaskId}=${type}:${domain}`);
134
+ if (CACHE_AUTOSAVE) writeCache("interstitial", newTaskId, tasks[newTaskId]);
135
+ break;
136
+
137
+ case "recaptcha2":
138
+ result = await recaptchaV2({ domain, siteKey, action, isInvisible, proxy }, page);
139
+ tasks[newTaskId] = { status: "done", ...result };
140
+ console.log(`done: ${newTaskId}=${type}:${domain}`);
141
+ if (CACHE_AUTOSAVE) writeCache("recaptcha2", newTaskId, tasks[newTaskId]);
142
+ break;
143
+
144
+ case "recaptcha3":
145
+ result = await recaptchaV3({ domain, siteKey, action, proxy }, page);
146
+ tasks[newTaskId] = { status: "done", ...result };
147
+ console.log(`done: ${newTaskId}=${type}:${domain}`);
148
+ if (CACHE_AUTOSAVE) writeCache("recaptcha3", newTaskId, tasks[newTaskId]);
149
+ break;
150
+
151
+ default:
152
+ tasks[newTaskId] = { status: "error", message: "Invalid type" };
153
+ }
154
+
155
+ await ctx.browser.close();
156
+ console.log(`Browser closed ${newTaskId}`);
157
+ } catch (err) {
158
+ tasks[newTaskId] = { status: "error", message: "totally failed" };
159
+ console.error(`failed: ${newTaskId}=${type}:${domain}`);
160
+ console.error("Detailed error:", err);
161
+ }
162
+ })();
163
+
164
+ res.json({ taskId: newTaskId, status: "pending" });
165
+ });
166
+
167
+ // init_browser
168
+ async function init_browser(proxyServer = null) {
169
+ const connectOptions = {
170
+ headless: false,
171
+ turnstile: true,
172
+ connectOption: { defaultViewport: null },
173
+ disableXvfb: false,
174
+ };
175
+ if (proxyServer) connectOptions.args = [`--proxy-server=${proxyServer}`];
176
+
177
+ const { browser } = await connect(connectOptions);
178
+ const [page] = await browser.pages();
179
+
180
+ await page.goto('about:blank');
181
+ await page.setRequestInterception(true);
182
+ page.on('request', (req) => {
183
+ const type = req.resourceType();
184
+ if (["image", "stylesheet", "font", "media"].includes(type)) req.abort();
185
+ else req.continue();
186
+ });
187
+ console.log(`initialized${proxyServer ? "proxy= " + proxyServer : ""}`);
188
+
189
+ return { browser, page };
190
+ }
191
+
192
+
193
+ const turnstile = require('./Api/turnstile');
194
+ const interstitial = require('./Api/interstitial');
195
+ const recaptchaV2 = require('./Api/recaptcha2');
196
+ const recaptchaV3 = require('./Api/recaptcha3');
197
+
198
+ app.use((req, res) => {
199
+ res.status(404).json({ message: 'Not Found' });
200
+ console.warn(`error: ${req.method} ${req.originalUrl}`);
201
+ });
202
+
203
+ app.listen(port, () => {
204
+ console.log(`Server running: http://localhost:${port}`);
205
+ });
Api/Api.md ADDED
@@ -0,0 +1 @@
 
 
1
+ Api
Api/interstitial.js ADDED
@@ -0,0 +1,82 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * INTERSTITIAL
3
+ */
4
+ async function interstitial({ domain, proxy }, page) {
5
+ return new Promise(async (resolve, reject) => {
6
+ if (!domain) return reject(new Error("Missing domain parameter"));
7
+
8
+ const startTime = Date.now();
9
+ let isResolved = false;
10
+ let userAgent = null;
11
+
12
+ const cl = setTimeout(() => {
13
+ if (!isResolved) {
14
+ isResolved = true;
15
+ resolve({
16
+ cf_clearance: null,
17
+ cookies: null,
18
+ user_agent: userAgent,
19
+ type: 'interstitial'
20
+ });
21
+ }
22
+ }, 20000);
23
+
24
+ try {
25
+ if (proxy?.username && proxy?.password) {
26
+ await page.authenticate({
27
+ username: proxy.username,
28
+ password: proxy.password,
29
+ });
30
+ }
31
+
32
+ page.removeAllListeners("request");
33
+ page.removeAllListeners("response");
34
+ await page.setRequestInterception(true);
35
+
36
+ page.on("request", async (req) => {
37
+ try {
38
+ await req.continue();
39
+ } catch (_) {}
40
+ });
41
+
42
+ page.on("response", async (res) => {
43
+ try {
44
+ const url = res.url();
45
+ if (url.includes("/cdn-cgi/challenge-platform/")) {
46
+ const headers = res.headers();
47
+ if (headers["set-cookie"]) {
48
+ const cookies = headers["set-cookie"];
49
+ const match = cookies.match(/cf_clearance=([^;]+)/);
50
+ if (match) {
51
+ const cf_clearance = match[1];
52
+ const userAgent = (await res.request().headers())["user-agent"];
53
+
54
+ if (!isResolved) {
55
+ isResolved = true;
56
+ clearTimeout(cl);
57
+ resolve({
58
+ cf_clearance,
59
+ cookies, // seluruh cookie string
60
+ user_agent: userAgent,
61
+ type: 'interstitial'
62
+ });
63
+ }
64
+ }
65
+ }
66
+ }
67
+ } catch (_) {}
68
+ });
69
+
70
+ await page.goto(domain, { waitUntil: "domcontentloaded" });
71
+ userAgent = await page.evaluate(() => navigator.userAgent);
72
+ } catch (err) {
73
+ if (!isResolved) {
74
+ isResolved = true;
75
+ clearTimeout(cl);
76
+ reject(err);
77
+ }
78
+ }
79
+ });
80
+ }
81
+
82
+ module.exports = interstitial;
Api/recaptcha2.js ADDED
@@ -0,0 +1,228 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * API_RECAPTCHA2
3
+ */
4
+ async function recaptchaV2({ domain, siteKey, action = "submit", isInvisible = false, proxy }, page) {
5
+ if (!domain) throw new Error("Missing domain parameter");
6
+ if (!siteKey) throw new Error("Missing siteKey parameter");
7
+
8
+ const timeout = global.timeOut;
9
+
10
+ return new Promise(async (resolve, reject) => {
11
+ let isResolved = false;
12
+
13
+ const cl = setTimeout(() => {
14
+ if (!isResolved) {
15
+ isResolved = true;
16
+ reject(new Error("Timeout Error"));
17
+ }
18
+ }, timeout);
19
+
20
+ try {
21
+ if (proxy?.username && proxy?.password) {
22
+ await page.authenticate({
23
+ username: proxy.username,
24
+ password: proxy.password,
25
+ });
26
+ }
27
+
28
+ const htmlContent = `
29
+ <!DOCTYPE html>
30
+ <html lang="en">
31
+ <head>
32
+ <meta charset="UTF-8">
33
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
34
+ <title>reCAPTCHA v2 Solver</title>
35
+ <style>
36
+ body {
37
+ font-family: Arial, sans-serif;
38
+ margin: 0;
39
+ padding: 20px;
40
+ background: #f5f5f5;
41
+ display: flex;
42
+ justify-content: center;
43
+ align-items: center;
44
+ min-height: 100vh;
45
+ }
46
+ .container {
47
+ background: white;
48
+ padding: 30px;
49
+ border-radius: 10px;
50
+ box-shadow: 0 2px 10px rgba(0,0,0,0.1);
51
+ text-align: center;
52
+ }
53
+ .status {
54
+ margin-top: 20px;
55
+ padding: 10px;
56
+ border-radius: 5px;
57
+ background: #f8f9fa;
58
+ }
59
+ button {
60
+ background: #007bff;
61
+ color: white;
62
+ border: none;
63
+ padding: 10px 20px;
64
+ border-radius: 5px;
65
+ cursor: pointer;
66
+ margin: 10px;
67
+ }
68
+ button:hover { background: #0056b3; }
69
+ </style>
70
+ </head>
71
+ <body>
72
+ <div class="container">
73
+ <h2>reCAPTCHA v2 Solver</h2>
74
+ <p>SiteKey: ${siteKey}</p>
75
+ <div id="recaptcha-container">
76
+ <div class="g-recaptcha"
77
+ data-sitekey="${siteKey}"
78
+ data-callback="recaptchaCallback"
79
+ data-expired-callback="recaptchaExpired"
80
+ data-error-callback="recaptchaError"
81
+ data-size="${isInvisible ? 'invisible' : 'normal'}"
82
+ data-theme="light"></div>
83
+ </div>
84
+ ${isInvisible ? '<button onclick="executeInvisible()">Execute reCAPTCHA</button>' : ''}
85
+ <button onclick="checkToken()">Check Token</button>
86
+ <div class="status" id="status">Waiting for reCAPTCHA...</div>
87
+ </div>
88
+
89
+ <script>
90
+ window.recaptchaToken = null;
91
+ window.recaptchaSolved = false;
92
+
93
+ window.recaptchaCallback = function(token) {
94
+ console.log('reCAPTCHA token received:', token);
95
+ window.recaptchaToken = token;
96
+ window.recaptchaSolved = true;
97
+
98
+ document.getElementById('status').innerHTML =
99
+ '✅ reCAPTCHA Solved! Token: ' + token.substring(0, 20) + '...';
100
+ document.getElementById('status').style.background = '#d4edda';
101
+ document.getElementById('status').style.color = '#155724';
102
+
103
+ var input = document.createElement('input');
104
+ input.type = 'hidden';
105
+ input.name = 'g-recaptcha-response';
106
+ input.value = token;
107
+ input.id = 'recaptcha-token-input';
108
+ document.body.appendChild(input);
109
+
110
+ localStorage.setItem('recaptcha_token', token);
111
+ };
112
+
113
+ window.recaptchaExpired = function() {
114
+ console.log('reCAPTCHA expired');
115
+ window.recaptchaToken = null;
116
+ window.recaptchaSolved = false;
117
+ document.getElementById('status').innerHTML = '❌ reCAPTCHA Expired - Refreshing...';
118
+ document.getElementById('status').style.background = '#fff3cd';
119
+ document.getElementById('status').style.color = '#856404';
120
+
121
+ var existing = document.getElementById('recaptcha-token-input');
122
+ if (existing) existing.remove();
123
+
124
+ setTimeout(() => { if (window.grecaptcha) grecaptcha.reset(); }, 1000);
125
+ };
126
+
127
+ window.recaptchaError = function() {
128
+ console.log('reCAPTCHA error');
129
+ document.getElementById('status').innerHTML = '❌ reCAPTCHA Error';
130
+ document.getElementById('status').style.background = '#f8d7da';
131
+ document.getElementById('status').style.color = '#721c24';
132
+ };
133
+
134
+ window.executeInvisible = function() {
135
+ if (window.grecaptcha) grecaptcha.execute();
136
+ };
137
+
138
+ window.checkToken = function() {
139
+ const token = window.recaptchaToken ||
140
+ document.getElementById('recaptcha-token-input')?.value;
141
+ document.getElementById('status').innerHTML = token
142
+ ? 'Token: ' + token
143
+ : 'No token yet';
144
+ };
145
+
146
+ window.onload = function() {
147
+ setTimeout(function() {
148
+ if (${isInvisible} && window.grecaptcha) {
149
+ grecaptcha.execute();
150
+ }
151
+ if (!${isInvisible}) {
152
+ var iframe = document.querySelector('iframe[src*="recaptcha"]');
153
+ if (iframe) {
154
+ console.log('Attempting to interact with reCAPTCHA');
155
+ var rect = iframe.getBoundingClientRect();
156
+ var clickEvent = new MouseEvent('click', {
157
+ view: window, bubbles: true, cancelable: true,
158
+ clientX: rect.left + rect.width / 2,
159
+ clientY: rect.top + rect.height / 2
160
+ });
161
+ iframe.dispatchEvent(clickEvent);
162
+ }
163
+ }
164
+ }, 2000);
165
+ };
166
+ </script>
167
+
168
+ <script src="https://www.google.com/recaptcha/api.js" async defer></script>
169
+ </body>
170
+ </html>
171
+ `;
172
+
173
+ await page.setRequestInterception(true);
174
+ page.removeAllListeners("request");
175
+ page.on("request", async (req) => {
176
+ const url = req.url();
177
+ if ([domain, domain + "/"].includes(url) && req.resourceType() === "document") {
178
+ await req.respond({ status: 200, contentType: "text/html", body: htmlContent });
179
+ } else if (["image", "stylesheet", "font"].includes(req.resourceType())) {
180
+ await req.abort();
181
+ } else {
182
+ await req.continue();
183
+ }
184
+ });
185
+
186
+ await page.goto(domain, { waitUntil: "domcontentloaded", timeout });
187
+ await page.waitForSelector('.g-recaptcha', { timeout: 10000 });
188
+
189
+ const tokenHandle = await page.waitForFunction(() => {
190
+ const input = document.querySelector('#recaptcha-token-input');
191
+ if (input?.value?.length > 10) return input.value;
192
+ const stored = localStorage.getItem('recaptcha_token');
193
+ if (stored?.length > 10) return stored;
194
+ if (window.recaptchaToken?.length > 10) return window.recaptchaToken;
195
+ return null;
196
+ }, { timeout, polling: 100 });
197
+
198
+ const tokenValue = await tokenHandle.jsonValue();
199
+
200
+ isResolved = true;
201
+ clearTimeout(cl);
202
+
203
+ if (!tokenValue || tokenValue.length < 10) {
204
+ reject(new Error("Failed to get valid reCAPTCHA token"));
205
+ } else {
206
+ resolve({ token: tokenValue, type: 'recaptcha_v2' });
207
+ }
208
+ } catch (error) {
209
+ if (!isResolved) {
210
+ isResolved = true;
211
+ clearTimeout(cl);
212
+ try {
213
+ const fallbackToken = await page.evaluate(() => {
214
+ const input = document.querySelector('#recaptcha-token-input');
215
+ return input ? input.value : null;
216
+ });
217
+ if (fallbackToken?.length > 10) {
218
+ resolve({ token: fallbackToken, type: 'recaptcha_v2' });
219
+ return;
220
+ }
221
+ } catch {}
222
+ reject(new Error(`reCAPTCHA solving failed: ${error.message}`));
223
+ }
224
+ }
225
+ });
226
+ }
227
+
228
+ module.exports = recaptchaV2;
Api/recaptcha3.js ADDED
@@ -0,0 +1,54 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * recaptcha3.js
3
+ */
4
+ async function recaptchaV3({ domain, siteKey, action, proxy }, page) {
5
+ if (!domain) throw new Error("Missing domain parameter");
6
+ if (!siteKey) throw new Error("Missing siteKey parameter");
7
+
8
+ const timeout = 120000;
9
+
10
+ return new Promise(async (resolve, reject) => {
11
+ let isResolved = false;
12
+
13
+ const cl = setTimeout(() => {
14
+ if (!isResolved) {
15
+ isResolved = true;
16
+ reject(new Error("Timeout Error"));
17
+ }
18
+ }, timeout);
19
+
20
+ try {
21
+ if (proxy?.username && proxy?.password) {
22
+ await page.authenticate({
23
+ username: proxy.username,
24
+ password: proxy.password,
25
+ });
26
+ }
27
+
28
+ await page.goto(domain, { waitUntil: "domcontentloaded" });
29
+
30
+ await page.addScriptTag({ url: "https://www.google.com/recaptcha/api.js?render=" + siteKey });
31
+
32
+ const token = await page.evaluate(async (siteKey, action) => {
33
+ return await grecaptcha.execute(siteKey, { action: action || "login" });
34
+ }, siteKey, action);
35
+
36
+ isResolved = true;
37
+ clearTimeout(cl);
38
+
39
+ if (!token || token.length < 10) {
40
+ reject(new Error("Failed to get token"));
41
+ } else {
42
+ resolve({ token: token, type: "recaptcha3" });
43
+ }
44
+ } catch (e) {
45
+ if (!isResolved) {
46
+ isResolved = true;
47
+ clearTimeout(cl);
48
+ reject(e);
49
+ }
50
+ }
51
+ });
52
+ }
53
+
54
+ module.exports = recaptchaV3;
Api/turnstile.js ADDED
@@ -0,0 +1,92 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * API_TURNSTILE
3
+ */
4
+ async function turnstile({ domain, siteKey, action, proxy }, page) {
5
+ if (!domain) throw new Error("Missing domain parameter");
6
+ if (!siteKey) throw new Error("Missing siteKey parameter");
7
+
8
+ const timeout = global.timeOut;
9
+
10
+ return new Promise(async (resolve, reject) => {
11
+ let isResolved = false;
12
+
13
+ const cl = setTimeout(() => {
14
+ if (!isResolved) {
15
+ isResolved = true;
16
+ reject(new Error("Timeout Error"));
17
+ }
18
+ }, timeout);
19
+
20
+ try {
21
+ if (proxy?.username && proxy?.password) {
22
+ await page.authenticate({
23
+ username: proxy.username,
24
+ password: proxy.password,
25
+ });
26
+ }
27
+
28
+ const htmlContent = `
29
+ <!DOCTYPE html>
30
+ <html lang="en">
31
+ <body>
32
+ <div class="turnstile"></div>
33
+ <script src="https://challenges.cloudflare.com/turnstile/v0/api.js?onload=onloadTurnstileCallback" defer></script>
34
+ <script>
35
+ window.onloadTurnstileCallback = function () {
36
+ turnstile.render('.turnstile', {
37
+ sitekey: '${siteKey}',
38
+ action: '${action || ""}',
39
+ callback: function (token) {
40
+ var c = document.createElement('input');
41
+ c.type = 'hidden';
42
+ c.name = 'cf-response';
43
+ c.value = token;
44
+ document.body.appendChild(c);
45
+ },
46
+ });
47
+ };
48
+ </script>
49
+ </body>
50
+ </html>
51
+ `;
52
+
53
+ await page.setRequestInterception(true);
54
+ page.removeAllListeners("request");
55
+ page.on("request", async (request) => {
56
+ if ([domain, domain + "/"].includes(request.url()) && request.resourceType() === "document") {
57
+ await request.respond({
58
+ status: 200,
59
+ contentType: "text/html",
60
+ body: htmlContent,
61
+ });
62
+ } else {
63
+ await request.continue();
64
+ }
65
+ });
66
+
67
+ await page.goto(domain, { waitUntil: "domcontentloaded" });
68
+ await page.waitForSelector('[name="cf-response"]', { timeout });
69
+
70
+ const token = await page.evaluate(() => {
71
+ return document.querySelector('[name="cf-response"]').value;
72
+ });
73
+
74
+ isResolved = true;
75
+ clearTimeout(cl);
76
+
77
+ if (!token || token.length < 10) {
78
+ reject(new Error("Failed to get token"));
79
+ } else {
80
+ resolve({ token: token, type: 'turnstile' });
81
+ }
82
+ } catch (e) {
83
+ if (!isResolved) {
84
+ isResolved = true;
85
+ clearTimeout(cl);
86
+ reject(e);
87
+ }
88
+ }
89
+ });
90
+ }
91
+
92
+ module.exports = turnstile;
Dockerfile ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM node:20-slim
2
+
3
+ RUN apt update && apt install -y \
4
+ wget gnupg ca-certificates xvfb \
5
+ fonts-liberation libappindicator3-1 libasound2 libatk-bridge2.0-0 \
6
+ libatk1.0-0 libxss1 libnss3 libxcomposite1 libxdamage1 libxrandr2 libgbm1 \
7
+ && wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb \
8
+ && apt install -y ./google-chrome-stable_current_amd64.deb \
9
+ && rm google-chrome-stable_current_amd64.deb
10
+
11
+ WORKDIR /A
12
+
13
+ RUN mkdir -p /A/Api && mkdir -p /A/cache
14
+
15
+ COPY package.json ./
16
+ RUN npm install
17
+
18
+ COPY . .
19
+
20
+ EXPOSE 7860
21
+
22
+ CMD rm -f /tmp/.X99-lock && \
23
+ Xvfb :99 -screen 0 1024x768x24 & \
24
+ export DISPLAY=:99 && \
25
+ npm start
README.md CHANGED
@@ -1,11 +1,12 @@
1
  ---
2
- title: Apalah
3
- emoji: 😻
4
- colorFrom: green
5
- colorTo: indigo
6
  sdk: docker
7
  pinned: false
8
- short_description: Newbie
 
9
  ---
10
 
11
  Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
1
  ---
2
+ title: Api
3
+ emoji: 🦀
4
+ colorFrom: blue
5
+ colorTo: yellow
6
  sdk: docker
7
  pinned: false
8
+ license: mit
9
+ short_description: Api
10
  ---
11
 
12
  Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
package.json ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "api",
3
+ "version": "7.3.0",
4
+ "description": "gmxch_Api",
5
+ "scripts": {
6
+ "start": "node Api.js",
7
+ "dev": "nodemon Api.js"
8
+ },
9
+ "dependencies": {
10
+ "express": "^5.1.0",
11
+ "puppeteer-real-browser": "^1.4.0"
12
+ },
13
+ "devDependencies": {
14
+ "nodemon": "^3.1.10"
15
+ },
16
+ "license": "MIT"
17
+ }