fourmovie commited on
Commit
83eeab2
·
1 Parent(s): 02f17f2
Files changed (1) hide show
  1. index.js +111 -218
index.js CHANGED
@@ -1,272 +1,165 @@
1
- const express = require('express')
2
- const { connect } = require("puppeteer-real-browser")
3
- const fs = require("fs")
4
- const path = require("path")
5
 
6
- const app = express()
7
- const port = process.env.PORT || 7860
8
- const authToken = process.env.authToken || null
9
- const DOMAIN = 'https://rezaharis-cf.hf.space' // DOMAINNYA DI SINI
10
 
11
- global.browserLimit = Number(process.env.browserLimit) || 20
12
- global.timeOut = Number(process.env.timeOut) || 60000
13
 
14
- const CACHE_DIR = path.join(__dirname, "cache")
15
- const CACHE_FILE = path.join(CACHE_DIR, "cache.json")
16
- const CACHE_TTL = 5 * 60 * 1000
17
 
18
  function loadCache() {
19
- if (!fs.existsSync(CACHE_FILE)) return {}
20
  try {
21
- return JSON.parse(fs.readFileSync(CACHE_FILE, "utf-8"))
22
  } catch {
23
- return {}
24
  }
25
  }
26
 
27
  function saveCache(cache) {
28
  if (!fs.existsSync(CACHE_DIR)) {
29
- fs.mkdirSync(CACHE_DIR, { recursive: true })
30
  }
31
- fs.writeFileSync(CACHE_FILE, JSON.stringify(cache, null, 2), "utf-8")
32
  }
33
 
34
  function readCache(key) {
35
- const cache = loadCache()
36
- const entry = cache[key]
37
  if (entry && Date.now() - entry.timestamp < CACHE_TTL) {
38
- return entry.value
39
  }
40
- return null
41
  }
42
 
43
  function writeCache(key, value) {
44
- const cache = loadCache()
45
- cache[key] = { timestamp: Date.now(), value }
46
- saveCache(cache)
47
  }
48
 
49
- app.use(express.json())
50
- app.use(express.urlencoded({ extended: true }))
51
-
52
- // Middleware untuk auth token
53
- app.use((req, res, next) => {
54
- if (authToken && req.path !== '/health' && req.path !== '/') {
55
- const token = req.body.authToken || req.query.authToken
56
- if (token !== authToken) {
57
- return res.status(401).json({ message: 'Unauthorized' })
 
 
 
 
 
 
58
  }
59
- }
60
- next()
61
- })
62
-
63
- // Root endpoint
64
- app.get('/', (req, res) => {
65
- res.status(200).json({
66
- message: 'Cloudflare Solver API',
67
- status: 'active',
68
- domain: DOMAIN, // TAMPILKAN DOMAIN DI RESPONSE
69
- endpoints: ['/cloudflare', '/turnstile', '/health', '/info']
70
- })
71
- })
72
-
73
- // Health check endpoint
74
- app.get('/health', (req, res) => {
75
- res.status(200).json({
76
- status: 'OK',
77
- browserLimit: global.browserLimit,
78
- domain: DOMAIN,
79
- timestamp: new Date().toISOString()
80
- })
81
- })
82
-
83
- // Info endpoint
84
- app.get('/info', (req, res) => {
85
- res.status(200).json({
86
- browserLimit: global.browserLimit,
87
- timeOut: global.timeOut,
88
- domain: DOMAIN,
89
- cacheEnabled: true,
90
- cacheTTL: CACHE_TTL
91
- })
92
- })
93
 
94
  if (process.env.NODE_ENV !== 'development') {
95
- let server = app.listen(port, '0.0.0.0', () => {
96
- console.log(`Server running on port ${port}`)
97
- console.log(`Domain: ${DOMAIN}`)
98
- })
99
  try {
100
- server.timeout = global.timeOut
101
- server.keepAliveTimeout = 60000
102
  } catch {}
103
  }
104
 
105
- async function createBrowser(proxyServer = null, proxyAuth = null) {
106
  const connectOptions = {
107
- headless: true,
108
  turnstile: true,
109
- connectOption: {
110
- defaultViewport: null,
111
- args: [
112
- '--no-sandbox',
113
- '--disable-setuid-sandbox',
114
- '--disable-dev-shm-usage',
115
- '--disable-accelerated-2d-canvas',
116
- '--no-first-run',
117
- '--no-zygote',
118
- '--disable-gpu',
119
- '--disable-web-security',
120
- '--disable-features=site-per-process',
121
- '--disable-blink-features=AutomationControlled'
122
- ]
123
- },
124
- disableXvfb: true,
125
- }
126
-
127
- if (proxyServer) {
128
- connectOptions.connectOption.args.push(`--proxy-server=${proxyServer}`)
129
- }
130
-
131
- const { browser } = await connect(connectOptions)
132
 
133
- // Set stealth
134
- const pages = await browser.pages()
135
- const page = pages[0]
136
 
137
- // Remove webdriver property
138
- await page.evaluateOnNewDocument(() => {
139
- Object.defineProperty(navigator, 'webdriver', {
140
- get: () => undefined,
141
- })
142
- })
143
-
144
- await page.setRequestInterception(true)
145
  page.on('request', (req) => {
146
- const type = req.resourceType()
147
- if (["image", "stylesheet", "font", "media"].includes(type)) {
148
- req.abort()
149
- } else {
150
- req.continue()
151
- }
152
- })
153
 
154
- return { browser, page }
155
  }
156
 
157
- // Import endpoints
158
- const turnstile = require('./endpoints/turnstile')
159
- const cloudflare = require('./endpoints/cloudflare')
160
 
161
- // ENDPOINT CLOUDFLARE - GUNAKAN DOMAIN YANG SUDAH DIATUR
162
  app.post('/cloudflare', async (req, res) => {
163
- const data = req.body
164
- if (!data) {
165
- return res.status(400).json({ message: 'Bad Request: missing data' })
 
 
 
 
 
 
 
 
 
 
 
166
  }
167
 
168
- // Gunakan domain dari request atau domain default
169
- const domain = data.domain || DOMAIN
170
-
171
- if (global.browserLimit <= 0) {
172
- return res.status(429).json({ message: 'Too Many Requests: browser limit reached' })
173
- }
174
-
175
- // Check cache
176
- const cacheKey = JSON.stringify({...data, domain})
177
- const cached = readCache(cacheKey)
178
- if (cached) {
179
- return res.status(200).json({ ...cached, cached: true })
180
- }
181
-
182
- global.browserLimit--
183
- let result
184
- let browser, page
185
 
186
  try {
187
- const proxyServer = data.proxy ? `${data.proxy.hostname}:${data.proxy.port}` : null
188
- const ctx = await createBrowser(proxyServer, data.proxy)
189
- browser = ctx.browser
190
- page = ctx.page
191
-
192
- // Pass domain ke fungsi cloudflare
193
- result = await cloudflare({...data, domain}, page)
194
-
195
- if (result.cf_clearance) {
196
- writeCache(cacheKey, result)
 
 
 
 
 
 
 
 
 
 
 
 
 
197
  }
198
-
199
- } catch (err) {
200
- result = {
201
- cf_clearance: null,
202
- user_agent: null,
203
- elapsed_time: 0,
204
- error: err.message
205
- }
206
- } finally {
207
- if (browser) {
208
- try {
209
- await browser.close()
210
- } catch (err) {
211
- console.error('Error closing browser:', err.message)
212
- }
213
- }
214
- global.browserLimit++
215
- }
216
-
217
- res.status(200).json(result)
218
- })
219
-
220
- // Endpoint khusus untuk Turnstile
221
- app.post('/turnstile', async (req, res) => {
222
- const data = req.body
223
- if (!data || !data.sitekey || !data.url) {
224
- return res.status(400).json({ message: 'Bad Request: missing sitekey or url' })
225
- }
226
-
227
- if (global.browserLimit <= 0) {
228
- return res.status(429).json({ message: 'Too Many Requests: browser limit reached' })
229
- }
230
-
231
- global.browserLimit--
232
- let result
233
- let browser, page
234
-
235
- try {
236
- const proxyServer = data.proxy ? `${data.proxy.hostname}:${data.proxy.port}` : null
237
- const ctx = await createBrowser(proxyServer, data.proxy)
238
- browser = ctx.browser
239
- page = ctx.page
240
-
241
- const token = await turnstile(data, page)
242
- result = { token }
243
-
244
  } catch (err) {
245
- result = { error: err.message }
246
  } finally {
247
- if (browser) {
248
- try {
249
- await browser.close()
250
- } catch (err) {
251
- console.error('Error closing browser:', err.message)
252
- }
253
- }
254
- global.browserLimit++
255
  }
256
 
257
- res.status(200).json(result)
258
- })
259
 
260
  app.use((req, res) => {
261
- res.status(404).json({ message: 'Not Found' })
262
- })
263
-
264
- // Error handling middleware
265
- app.use((err, req, res, next) => {
266
- console.error('Server Error:', err)
267
- res.status(500).json({ message: 'Internal Server Error' })
268
- })
269
 
270
  if (process.env.NODE_ENV === 'development') {
271
- module.exports = app
272
  }
 
1
+ const express = require('express');
2
+ const { connect } = require("puppeteer-real-browser");
3
+ const fs = require('fs');
4
+ const path = require('path');
5
 
6
+ const app = express();
7
+ const port = process.env.PORT || 7860;
8
+ const authToken = process.env.authToken || null;
9
+ const domain = process.env.DOMAIN || `https://rezaharis-cf.hf.space`; // VARIABEL DOMAIN DI SINI
10
 
11
+ global.browserLimit = Number(process.env.browserLimit) || 20;
12
+ global.timeOut = Number(process.env.timeOut) || 60000;
13
 
14
+ const CACHE_DIR = path.join(__dirname, "cache");
15
+ const CACHE_FILE = path.join(CACHE_DIR, "cache.json");
16
+ const CACHE_TTL = 5 * 60 * 1000;
17
 
18
  function loadCache() {
19
+ if (!fs.existsSync(CACHE_FILE)) return {};
20
  try {
21
+ return JSON.parse(fs.readFileSync(CACHE_FILE, 'utf-8'));
22
  } catch {
23
+ return {};
24
  }
25
  }
26
 
27
  function saveCache(cache) {
28
  if (!fs.existsSync(CACHE_DIR)) {
29
+ fs.mkdirSync(CACHE_DIR, { recursive: true });
30
  }
31
+ fs.writeFileSync(CACHE_FILE, JSON.stringify(cache, null, 2), 'utf-8');
32
  }
33
 
34
  function readCache(key) {
35
+ const cache = loadCache();
36
+ const entry = cache[key];
37
  if (entry && Date.now() - entry.timestamp < CACHE_TTL) {
38
+ return entry.value;
39
  }
40
+ return null;
41
  }
42
 
43
  function writeCache(key, value) {
44
+ const cache = loadCache();
45
+ cache[key] = { timestamp: Date.now(), value };
46
+ saveCache(cache);
47
  }
48
 
49
+ app.use(express.json());
50
+ app.use(express.urlencoded({ extended: true }));
51
+
52
+ // ROUTE UTAMA APP.GET("/")
53
+ app.get("/", (req, res) => {
54
+ res.json({
55
+ message: "Server is running!",
56
+ domain: domain,
57
+ endpoints: {
58
+ cloudflare: `${domain}/cloudflare`,
59
+ turnstile: `${domain}/cloudflare` // via POST ke /cloudflare dengan mode turnstile
60
+ },
61
+ status: {
62
+ browserLimit: global.browserLimit,
63
+ timeOut: global.timeOut
64
  }
65
+ });
66
+ });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
67
 
68
  if (process.env.NODE_ENV !== 'development') {
69
+ let server = app.listen(port, () => {
70
+ console.log(`Server running on port ${port}`);
71
+ console.log(`Domain: ${domain}`);
72
+ });
73
  try {
74
+ server.timeout = global.timeOut;
 
75
  } catch {}
76
  }
77
 
78
+ async function createBrowser(proxyServer = null) {
79
  const connectOptions = {
80
+ headless: false,
81
  turnstile: true,
82
+ connectOption: { defaultViewport: null },
83
+ disableXvfb: false,
84
+ };
85
+ if (proxyServer) connectOptions.args = [`--proxy-server=${proxyServer}`];
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
86
 
87
+ const { browser } = await connect(connectOptions);
88
+ const [page] = await browser.pages();
 
89
 
90
+ await page.goto('about:blank');
91
+ await page.setRequestInterception(true);
 
 
 
 
 
 
92
  page.on('request', (req) => {
93
+ const type = req.resourceType();
94
+ if (["image", "stylesheet", "font", "media"].includes(type)) req.abort();
95
+ else req.continue();
96
+ });
 
 
 
97
 
98
+ return { browser, page };
99
  }
100
 
101
+ const turnstile = require('./endpoints/turnstile');
102
+ const cloudflare = require('./endpoints/cloudflare');
 
103
 
 
104
  app.post('/cloudflare', async (req, res) => {
105
+ const data = req.body;
106
+ if (!data || typeof data.mode !== 'string')
107
+ return res.status(400).json({ message: 'Bad Request: missing or invalid mode' });
108
+ if (authToken && data.authToken !== authToken)
109
+ return res.status(401).json({ message: 'Unauthorized' });
110
+
111
+ if (global.browserLimit <= 0)
112
+ return res.status(429).json({ message: 'Too Many Requests' });
113
+
114
+ let cacheKey, cached;
115
+ if (data.mode === "iuam") {
116
+ cacheKey = JSON.stringify(data);
117
+ cached = readCache(cacheKey);
118
+ if (cached) return res.status(200).json({ ...cached, cached: true });
119
  }
120
 
121
+ global.browserLimit--;
122
+ let result, browser;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
123
 
124
  try {
125
+ const proxyServer = data.proxy ? `${data.proxy.hostname}:${data.proxy.port}` : null;
126
+ const ctx = await createBrowser(proxyServer);
127
+ browser = ctx.browser;
128
+ const page = ctx.page;
129
+
130
+ await page.goto('about:blank');
131
+
132
+ switch (data.mode) {
133
+ case "turnstile":
134
+ result = await turnstile(data, page)
135
+ .then(token => ({ token }))
136
+ .catch(err => ({ code: 500, message: err.message }));
137
+ break;
138
+
139
+ case "iuam":
140
+ result = await cloudflare(data, page)
141
+ .then(r => ({ ...r }))
142
+ .catch(err => ({ code: 500, message: err.message }));
143
+ if (!result.code || result.code === 200) writeCache(cacheKey, result);
144
+ break;
145
+
146
+ default:
147
+ result = { code: 400, message: 'Invalid mode' };
148
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
149
  } catch (err) {
150
+ result = { code: 500, message: err.message };
151
  } finally {
152
+ if (browser) try { await browser.close(); } catch {}
153
+ global.browserLimit++;
 
 
 
 
 
 
154
  }
155
 
156
+ res.status(result.code ?? 200).json(result);
157
+ });
158
 
159
  app.use((req, res) => {
160
+ res.status(404).json({ message: 'Not Found' });
161
+ });
 
 
 
 
 
 
162
 
163
  if (process.env.NODE_ENV === 'development') {
164
+ module.exports = app;
165
  }