vipsphi commited on
Commit
58461df
·
verified ·
1 Parent(s): b42f308

Upload 11 files

Browse files
Files changed (12) hide show
  1. .gitattributes +1 -0
  2. cert.pem +28 -0
  3. check_proxy_alive.js +73 -0
  4. database.sqlite +3 -0
  5. key.pem +28 -0
  6. logger.js +51 -0
  7. package-lock.json +0 -0
  8. package.json +18 -0
  9. server.js +399 -0
  10. solver.js +197 -0
  11. stress_test_queue.js +35 -0
  12. test_proxy.js +66 -0
.gitattributes CHANGED
@@ -33,3 +33,4 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
+ database.sqlite filter=lfs diff=lfs merge=lfs -text
cert.pem ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ -----BEGIN CERTIFICATE-----
2
+ MIIEsjCCA5qgAwIBAgIUWjp7uG3wH7CzK8BZ2dGz3qMF4l8wDQYJKoZIhvcNAQEL
3
+ BQAwgYsxCzAJBgNVBAYTAlVTMRkwFwYDVQQKExBDbG91ZEZsYXJlLCBJbmMuMTQw
4
+ MgYDVQQLEytDbG91ZEZsYXJlIE9yaWdpbiBTU0wgQ2VydGlmaWNhdGUgQXV0aG9y
5
+ aXR5MRYwFAYDVQQHEw1TYW4gRnJhbmNpc2NvMRMwEQYDVQQIEwpDYWxpZm9ybmlh
6
+ MB4XDTI1MTIyOTA1NTMwMFoXDTQwMTIyNTA1NTMwMFowYjEZMBcGA1UEChMQQ2xv
7
+ dWRGbGFyZSwgSW5jLjEdMBsGA1UECxMUQ2xvdWRGbGFyZSBPcmlnaW4gQ0ExJjAk
8
+ BgNVBAMTHUNsb3VkRmxhcmUgT3JpZ2luIENlcnRpZmljYXRlMIIBIjANBgkqhkiG
9
+ 9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqpUOrPW40xlB4F6MxiQmKgIHeSqJQBAzXkMq
10
+ Ec3Juhb1zT6FP5l2gKSUcX2WWriQBm82MRPca70ni22vEjNKfD76MC8yYun8E5mR
11
+ 2hCOBfhn6ZBv5OCLDljfHg6p1umAhamGty3ACriI/j3WOMw0rhUJwqsIuQ5i3DK4
12
+ dbuqpNnqkBGcxy9Tzd+PYCbtl5z1QAKlVc1fvGJ4MJ/1m8yflyoYEcZ8aVdrBDwx
13
+ KV3Kpl6EpRS+NN0peFrPViOcaWunQPRIiYS/UyjLihoXVFrFFiDJL3DtwxPe7C+t
14
+ FHVW2I5UFNm1qRX4bSNZ6f9KEnNwtXZ+rriYXIkd23ENizpniQIDAQABo4IBNDCC
15
+ ATAwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcD
16
+ ATAMBgNVHRMBAf8EAjAAMB0GA1UdDgQWBBT8P5IcgCbSZeu7AHjm/6ry0kw3KjAf
17
+ BgNVHSMEGDAWgBQk6FNXXXw0QIep65TbuuEWePwppDBABggrBgEFBQcBAQQ0MDIw
18
+ MAYIKwYBBQUHMAGGJGh0dHA6Ly9vY3NwLmNsb3VkZmxhcmUuY29tL29yaWdpbl9j
19
+ YTA1BgNVHREELjAsghUqLmtpbnhzb2Z0d2FyZS5vbmxpbmWCE2tpbnhzb2Z0d2Fy
20
+ ZS5vbmxpbmUwOAYDVR0fBDEwLzAtoCugKYYnaHR0cDovL2NybC5jbG91ZGZsYXJl
21
+ LmNvbS9vcmlnaW5fY2EuY3JsMA0GCSqGSIb3DQEBCwUAA4IBAQBQMhFjPAOP398v
22
+ owmv7zOxYerdHwkZ9wp5TMDUV2dO8DuExmPzzuPmz34bIjVzFUS5B3vwelkzU4z4
23
+ MhpxWqeXB5iQWMYo3DzW8UQgGq8qKtZl/LHIuyAkNCWXdlepdsdo4625ehcddTE9
24
+ lG4qRuxV+9KavzFZhu14kqqZkQ+e7jqELF74dqx2tBGayQgP//0Z0AXgaLihvzAx
25
+ yc4suJp5tN3UCfyiFBhWyoD0cPhNNlyfM2O5g3mgo0nEvPSIyNQFfZF67Pcj/Gag
26
+ VylmV9p3XvAa8Nn+oHrnxck5YUhkdltExoSi9se0k8uP07Nzc6F/n51Mq9LO9HFS
27
+ YzcQo2vT
28
+ -----END CERTIFICATE-----
check_proxy_alive.js ADDED
@@ -0,0 +1,73 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ const http = require('http');
2
+ const https = require('https');
3
+
4
+ async function testProxy(protocol, targetHost, targetPath) {
5
+ const proxy = 'http://zlet9i3y:oZJQ0o4V@157.10.49.215:44128';
6
+ const targetUrl = `${protocol}://${targetHost}${targetPath}`;
7
+
8
+ console.log(`Testing Proxy: ${proxy}`);
9
+ console.log(`Target: ${targetUrl}`);
10
+
11
+ const url = new URL(proxy);
12
+ const auth = 'Basic ' + Buffer.from(url.username + ':' + url.password).toString('base64');
13
+
14
+ if (protocol === 'http') {
15
+ return new Promise((resolve) => {
16
+ const options = {
17
+ host: url.hostname,
18
+ port: url.port,
19
+ path: targetUrl,
20
+ headers: {
21
+ 'Proxy-Authorization': auth,
22
+ 'Host': targetHost
23
+ }
24
+ };
25
+ http.get(options, (res) => {
26
+ let data = '';
27
+ res.on('data', chunk => data += chunk);
28
+ res.on('end', () => {
29
+ console.log(`HTTP Status: ${res.statusCode}`);
30
+ resolve(true);
31
+ });
32
+ }).on('error', e => {
33
+ console.error(`HTTP Proxy Error: ${e.message}`);
34
+ resolve(false);
35
+ });
36
+ });
37
+ } else {
38
+ // HTTPS CONNECT
39
+ return new Promise((resolve) => {
40
+ const req = http.request({
41
+ host: url.hostname,
42
+ port: url.port,
43
+ method: 'CONNECT',
44
+ path: `${targetHost}:443`,
45
+ headers: {
46
+ 'Proxy-Authorization': auth
47
+ }
48
+ });
49
+
50
+ req.on('connect', (res, socket, head) => {
51
+ console.log('HTTPS CONNECT established');
52
+ socket.destroy();
53
+ resolve(true);
54
+ });
55
+
56
+ req.on('error', e => {
57
+ console.error(`HTTPS Proxy Error (CONNECT): ${e.message}`);
58
+ resolve(false);
59
+ });
60
+
61
+ req.end();
62
+ });
63
+ }
64
+ }
65
+
66
+ async function run() {
67
+ console.log('--- Step 1: HTTP Test ---');
68
+ await testProxy('http', 'httpbin.org', '/ip');
69
+ console.log('\n--- Step 2: HTTPS Test ---');
70
+ await testProxy('https', 'labs.google', '/');
71
+ }
72
+
73
+ run();
database.sqlite ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:0b0e4ce04c7967f0e0b3b7e1d0daaefab740e8c7d7af0aa9275d9d66f8465cf5
3
+ size 184320
key.pem ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ -----BEGIN PRIVATE KEY-----
2
+ MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQCqlQ6s9bjTGUHg
3
+ XozGJCYqAgd5KolAEDNeQyoRzcm6FvXNPoU/mXaApJRxfZZauJAGbzYxE9xrvSeL
4
+ ba8SM0p8PvowLzJi6fwTmZHaEI4F+GfpkG/k4IsOWN8eDqnW6YCFqYa3LcAKuIj+
5
+ PdY4zDSuFQnCqwi5DmLcMrh1u6qk2eqQEZzHL1PN349gJu2XnPVAAqVVzV+8Yngw
6
+ n/WbzJ+XKhgRxnxpV2sEPDEpXcqmXoSlFL403Sl4Ws9WI5xpa6dA9EiJhL9TKMuK
7
+ GhdUWsUWIMkvcO3DE97sL60UdVbYjlQU2bWpFfhtI1np/0oSc3C1dn6uuJhciR3b
8
+ cQ2LOmeJAgMBAAECggEAFKR4k+wha2RPUUJH2VN3DdbUhjBkTw0W1kWc8e4cBwmv
9
+ waBa+h0NVthzwT8gIobaoPi0z2AWqLAJeMkzaimsThhF6O5RM+CaWVnYaVHfCfBr
10
+ TLummsUkdr5A88909JWpsKMY8xJVfsahh1i+0308s8NGfNj7M3++7WQy58Znyk6E
11
+ zN+yRa7vSUZIvCoElzfZwGgcmTGZL3GomRCCOFqHP/+/iahm1N+8uLRa680mjnQ2
12
+ 8twYjF2D5agOwmpKG9YOmt2rtUlTq+k0bEt+s1XOu5Lln7DC8z6d5LxMJqH6IYo2
13
+ HDnNo25EFK7Pg5Gi1iLrRJdW+mcePp/5JpJObyYl4QKBgQDm3iBKeYkToFvPTbBV
14
+ YiSc8t/8hnXTLV8HZtflr51nXVTALEUAg7NnWhWOzK60Ust1aCvqco3vgXzNXtEx
15
+ MS9Pp/Nb7l51W9uazocQmOZlUZut3wyMl6152Zk5rtjBmZ8RD1gP8/UVOwMkicDe
16
+ KgiCIse+PfyP990IC2Nu14oeGQKBgQC9JuIOgyl5v9v0F5JGJZ9vsADrT9LopHO3
17
+ Ecb838XnmV9YQS5pyZZwD5IEBsUbOsRchUEZJRcsPXKXse+N5Eu5qC6jOF2HR/rX
18
+ xUj2GQIWLKYvzPIpkWq7YFvZ5PdJp6uXWoA9TN544pvlmewcr3XixDZAGw/TTUls
19
+ HkzGQPLi8QKBgQCdZ7cmb+S43+2Y0sQ2AtspsyJqHxb4a4fOGR18OZcdIXImMEi/
20
+ iAvqnG30VbOLuKOFogfHKmGBeYyozUvduUYjjkQLWuNGKuH4k3VdKJJ1ZAW7r0b0
21
+ GHoriOPCg2a/4MimLgsBnXhtCDYlVFKOZqQ0bhg3qjWnxvwJfxJFQWmnCQKBgQCq
22
+ pI2D8ihUwhW43BsGVaLEq8/oehcX8mTCX7NZJrfv/JnbkNJCda7WYfWk1Ea2Dgpg
23
+ PYdBHAkPzE+5MrmfFLqMP4HzlkIqbXGLf1wXSPBs+NLkhMxjW+EiMggrRzkgpbdT
24
+ 0D2pD9QU0rs6I+ay6kg70C/xHXjlc/AtLhitMqLswQKBgQDhz8aTa2B8jslQ8R/b
25
+ h1YXmrgkVjHimTYTeLXeE45sMna9HplIWDDUAeoD4GipbIbRVixwS7NTNW0lTGzk
26
+ ZeKiRUzz9og3W3KtXm9Sglfjk9IeOPGUH3VEah0D79LgsB0yi8IOzBCNXluFcI8p
27
+ q5kyqlfB1fRhzkZ6yqq43zD6EQ==
28
+ -----END PRIVATE KEY-----
logger.js ADDED
@@ -0,0 +1,51 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+
4
+ const logFile = path.join(__dirname, 'app.log');
5
+ const logStream = fs.createWriteStream(logFile, { flags: 'a' });
6
+
7
+ class Logger {
8
+ constructor() {
9
+ this.queueCount = 0;
10
+ this.activeCount = 0;
11
+ this.lastStatusTime = 0;
12
+ }
13
+
14
+ info(msg) {
15
+ this.writeToFile(`[INFO] ${msg}`);
16
+ console.log(`[${new Date().toLocaleTimeString()}] INFO: ${msg}`);
17
+ }
18
+
19
+ warn(msg) {
20
+ this.writeToFile(`[WARN] ${msg}`);
21
+ console.warn(`[${new Date().toLocaleTimeString()}] WARN: ${msg}`);
22
+ }
23
+
24
+ error(msg) {
25
+ this.writeToFile(`[ERROR] ${msg}`);
26
+ console.error(`[${new Date().toLocaleTimeString()}] ERROR: ${msg}`);
27
+ }
28
+
29
+ debug(msg) {
30
+ this.writeToFile(`[DEBUG] ${msg}`);
31
+ }
32
+
33
+ writeToFile(msg) {
34
+ const timestamp = new Date().toISOString();
35
+ logStream.write(`[${timestamp}] ${msg}\n`);
36
+ }
37
+
38
+ // Specialized throttled stats for the console
39
+ updateStats(active, queue) {
40
+ this.activeCount = active;
41
+ this.queueCount = queue;
42
+
43
+ const now = Date.now();
44
+ if (now - this.lastStatusTime > 3000) { // Update console every 3 seconds
45
+ this.lastStatusTime = now;
46
+ process.stdout.write(`\r[Status] Active: ${active} | Queued: ${queue} | Logs: See app.log `);
47
+ }
48
+ }
49
+ }
50
+
51
+ module.exports = new Logger();
package-lock.json ADDED
The diff for this file is too large to render. See raw diff
 
package.json ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "captcha-service-pro",
3
+ "version": "2.0.0",
4
+ "main": "server.js",
5
+ "scripts": {
6
+ "start": "electron ."
7
+ },
8
+ "dependencies": {
9
+ "body-parser": "^1.20.2",
10
+ "cors": "^2.8.5",
11
+ "electron": "^28.0.0",
12
+ "express": "^4.18.2",
13
+ "puppeteer": "^24.34.0",
14
+ "socket.io": "^4.8.3",
15
+ "sqlite3": "^5.1.7",
16
+ "uuid": "^9.0.1"
17
+ }
18
+ }
server.js ADDED
@@ -0,0 +1,399 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ const { app: electronApp, session } = require("electron");
2
+
3
+ // Global Proxy Auth Handler
4
+ electronApp.on("login", (event, webContents, details, authInfo, callback) => {
5
+ if (authInfo.isProxy) {
6
+ const ses = webContents.session;
7
+ if (ses.proxyCredentials) {
8
+ logger.debug(`[Main] Providing credentials for proxy via app.on('login')`);
9
+ event.preventDefault();
10
+ callback(ses.proxyCredentials.username, ses.proxyCredentials.password);
11
+ }
12
+ }
13
+ });
14
+
15
+ const express = require("express");
16
+ const bodyParser = require("body-parser");
17
+ const cors = require("cors");
18
+ const sqlite3 = require("sqlite3");
19
+ const { v4: uuidv4 } = require("uuid");
20
+ const path = require("path");
21
+ const RecaptchaSolver = require("./solver");
22
+ const http = require("http");
23
+ const { Server } = require("socket.io");
24
+ const logger = require("./logger");
25
+
26
+ const PORT = 3000;
27
+ const app = express();
28
+ const server = http.createServer(app);
29
+ const io = new Server(server, {
30
+ cors: { origin: "*" },
31
+ });
32
+
33
+ const db = new sqlite3.Database("./database.sqlite");
34
+
35
+ // --- INIT DB ---
36
+ db.serialize(() => {
37
+ // Thêm cột role để phân quyền (admin/user)
38
+ db.run(`CREATE TABLE IF NOT EXISTS users (
39
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
40
+ username TEXT UNIQUE,
41
+ password TEXT,
42
+ api_key TEXT,
43
+ credits INTEGER DEFAULT 0,
44
+ role TEXT DEFAULT 'user',
45
+ hwid TEXT
46
+ )`);
47
+ db.run("ALTER TABLE users ADD COLUMN hwid TEXT", (err) => {
48
+ if (err) {
49
+ if (!err.message.includes("duplicate column name")) {
50
+ console.error("Migration error (hwid):", err.message);
51
+ }
52
+ }
53
+ });
54
+ db.run("UPDATE users SET role = 'admin' WHERE username = 'admin'");
55
+
56
+ // Bảng lưu lịch sử nạp tiền chờ duyệt
57
+ db.run(`CREATE TABLE IF NOT EXISTS transactions (
58
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
59
+ user_id INTEGER,
60
+ username TEXT,
61
+ amount INTEGER,
62
+ method TEXT,
63
+ status TEXT DEFAULT 'pending', -- pending, approved, rejected
64
+ created_at DATETIME DEFAULT CURRENT_TIMESTAMP
65
+ )`);
66
+
67
+ // Bảng log lịch sử sử dụng
68
+ db.run(`CREATE TABLE IF NOT EXISTS usage_logs (
69
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
70
+ user_id INTEGER,
71
+ action TEXT,
72
+ details TEXT,
73
+ timestamp DATETIME DEFAULT CURRENT_TIMESTAMP
74
+ )`);
75
+ });
76
+
77
+ app.use(cors());
78
+ app.use(bodyParser.json());
79
+ app.use(express.static(path.join(__dirname, "public")));
80
+
81
+ // --- MIDDLEWARE CHECK ADMIN ---
82
+ const requireAdmin = (req, res, next) => {
83
+ const apiKey = req.headers["x-api-key"];
84
+ db.get("SELECT role FROM users WHERE api_key = ?", [apiKey], (err, row) => {
85
+ if (row && row.role === "admin") next();
86
+ else res.status(403).json({ error: "Bạn không phải Admin!" });
87
+ });
88
+ };
89
+
90
+ // --- AUTH ---
91
+ app.post("/api/register", (req, res) => {
92
+ const { username, password, hwid } = req.body;
93
+ const apiKey = uuidv4();
94
+
95
+ // Kiểm tra xem HWID này đã được cộng tiền lần nào chưa
96
+ db.get("SELECT id FROM users WHERE hwid = ?", [hwid], (err, row) => {
97
+ const initialCredits = row ? 0 : 100; // Nếu đã tồn tại HWID thì 0, mới thì 10
98
+ const message = row
99
+ ? "Đăng ký thành công! (Máy này đã nhận bonus trước đó nên không được cộng thêm)"
100
+ : "Đăng ký thành công! Bạn nhận được +100 Credits bonus.";
101
+
102
+ const stmt = db.prepare(
103
+ "INSERT INTO users (username, password, api_key, credits, role, hwid) VALUES (?, ?, ?, ?, 'user', ?)"
104
+ );
105
+ stmt.run(username, password, apiKey, initialCredits, hwid, function (err) {
106
+ if (err) return res.status(400).json({ error: "User đã tồn tại" });
107
+ res.json({ success: true, message: message });
108
+ io.emit("admin:new-user");
109
+ });
110
+ stmt.finalize();
111
+ });
112
+ });
113
+
114
+ app.post("/api/login", (req, res) => {
115
+ const { username, password } = req.body;
116
+ db.get(
117
+ "SELECT * FROM users WHERE username = ? AND password = ?",
118
+ [username, password],
119
+ (err, row) => {
120
+ if (!row) return res.status(401).json({ error: "Sai thông tin" });
121
+ res.json({ success: true, user: row });
122
+ }
123
+ );
124
+ });
125
+
126
+ app.get("/api/me", (req, res) => {
127
+ const apiKey = req.headers["x-api-key"];
128
+ db.get(
129
+ "SELECT username, credits, api_key, role FROM users WHERE api_key = ?",
130
+ [apiKey],
131
+ (err, row) => {
132
+ if (row) res.json(row);
133
+ else res.status(401).json({ error: "Key lỗi" });
134
+ }
135
+ );
136
+ });
137
+
138
+ // --- HISTORY API ---
139
+ app.get("/api/history/usage", (req, res) => {
140
+ const apiKey = req.headers["x-api-key"];
141
+ db.get("SELECT id FROM users WHERE api_key = ?", [apiKey], (err, user) => {
142
+ if (!user) return res.status(401).json({ error: "Auth failed" });
143
+ db.all(
144
+ "SELECT * FROM usage_logs WHERE user_id = ? ORDER BY id DESC LIMIT 50",
145
+ [user.id],
146
+ (err, rows) => {
147
+ res.json(rows);
148
+ }
149
+ );
150
+ });
151
+ });
152
+
153
+ app.get("/api/history/transactions", (req, res) => {
154
+ const apiKey = req.headers["x-api-key"];
155
+ db.get("SELECT id FROM users WHERE api_key = ?", [apiKey], (err, user) => {
156
+ if (!user) return res.status(401).json({ error: "Auth failed" });
157
+ db.all(
158
+ "SELECT * FROM transactions WHERE user_id = ? ORDER BY id DESC",
159
+ [user.id],
160
+ (err, rows) => {
161
+ res.json(rows);
162
+ }
163
+ );
164
+ });
165
+ });
166
+
167
+ // --- USER: TẠO YÊU CẦU NẠP TIỀN ---
168
+ app.post("/api/deposit", (req, res) => {
169
+ const apiKey = req.headers["x-api-key"];
170
+ const { amount, method } = req.body; // amount tính bằng USD (1, 5, 10)
171
+
172
+ db.get(
173
+ "SELECT id, username FROM users WHERE api_key = ?",
174
+ [apiKey],
175
+ (err, user) => {
176
+ if (!user) return res.status(401).json({ error: "User không tồn tại" });
177
+
178
+ const stmt = db.prepare(
179
+ "INSERT INTO transactions (user_id, username, amount, method) VALUES (?, ?, ?, ?)"
180
+ );
181
+ stmt.run(user.id, user.username, amount, method, function (err) {
182
+ if (err) return res.status(500).json({ error: "Lỗi tạo giao dịch" });
183
+ res.json({
184
+ success: true,
185
+ message: "Đã gửi yêu cầu! Vui lòng đợi Admin duyệt.",
186
+ });
187
+ io.emit("admin:new-transaction"); // Notify admin
188
+ });
189
+ stmt.finalize();
190
+ }
191
+ );
192
+ });
193
+
194
+ // --- ADMIN API ---
195
+
196
+ // 1. Lấy danh sách user
197
+ app.get("/api/admin/users", requireAdmin, (req, res) => {
198
+ db.all(
199
+ "SELECT id, username, credits, role, api_key FROM users",
200
+ [],
201
+ (err, rows) => {
202
+ res.json(rows);
203
+ }
204
+ );
205
+ });
206
+
207
+ // 2. Lấy danh sách giao dịch nạp tiền
208
+ app.get("/api/admin/transactions", requireAdmin, (req, res) => {
209
+ db.all("SELECT * FROM transactions ORDER BY id DESC", [], (err, rows) => {
210
+ res.json(rows);
211
+ });
212
+ });
213
+
214
+ // 3. Duyệt hoặc Từ chối nạp tiền
215
+ app.post("/api/admin/approve", requireAdmin, (req, res) => {
216
+ const { transId, action } = req.body; // action: 'approve' | 'reject'
217
+
218
+ db.get("SELECT * FROM transactions WHERE id = ?", [transId], (err, trans) => {
219
+ if (!trans || trans.status !== "pending")
220
+ return res.status(400).json({ error: "Giao dịch không hợp lệ" });
221
+
222
+ if (action === "reject") {
223
+ db.run("UPDATE transactions SET status = 'rejected' WHERE id = ?", [
224
+ transId,
225
+ ]);
226
+ io.emit("transaction-updated");
227
+ return res.json({ success: true, message: "Đã từ chối giao dịch" });
228
+ }
229
+
230
+ if (action === "approve") {
231
+ const creditsToAdd = trans.amount * 1000; // $1 = 1000 credits
232
+ db.serialize(() => {
233
+ db.run("UPDATE transactions SET status = 'approved' WHERE id = ?", [
234
+ transId,
235
+ ]);
236
+ db.run("UPDATE users SET credits = credits + ? WHERE id = ?", [
237
+ creditsToAdd,
238
+ trans.user_id,
239
+ ]);
240
+ });
241
+ return res.json({
242
+ success: true,
243
+ message: `Đã duyệt! Cộng ${creditsToAdd} credits cho ${trans.username}`,
244
+ });
245
+ io.emit("transaction-updated");
246
+ // Notify specific user to update credits (client filters by checking if it's their update)
247
+ io.emit("user:credit-update");
248
+ }
249
+ });
250
+ });
251
+
252
+ // 5. Xóa user
253
+ app.post("/api/admin/delete-user", requireAdmin, (req, res) => {
254
+ const { userId } = req.body;
255
+ db.run("DELETE FROM users WHERE id = ?", [userId], function (err) {
256
+ if (err) return res.status(500).json({ error: "Lỗi xóa user" });
257
+ res.json({ success: true, message: "Đã xóa người dùng thành công." });
258
+ io.emit("admin:user-deleted"); // Notify admin to refresh list
259
+ });
260
+ });
261
+
262
+ // 4. Cộng/Trừ tiền thủ công cho user
263
+ app.post("/api/admin/update-credits", requireAdmin, (req, res) => {
264
+ const { userId, amount } = req.body; // amount có thể là số âm để trừ
265
+ db.run(
266
+ "UPDATE users SET credits = credits + ? WHERE id = ?",
267
+ [amount, userId],
268
+ function (err) {
269
+ if (err) return res.status(500).json({ error: "Lỗi database" });
270
+ res.json({ success: true, message: "Đã cập nhật số dư user." });
271
+ io.emit("user:credit-update");
272
+ }
273
+ );
274
+ });
275
+
276
+ // --- CAPTCHA SOLVE QUEUE ---
277
+ const solveQueue = [];
278
+ let activeSolves = 0;
279
+ const MAX_CONCURRENT_SOLVES = 3; // Tăng lên 3 vì đã tối ưu logging
280
+
281
+ async function processQueue() {
282
+ if (solveQueue.length === 0 || activeSolves >= MAX_CONCURRENT_SOLVES) {
283
+ logger.updateStats(activeSolves, solveQueue.length);
284
+ return;
285
+ }
286
+
287
+ activeSolves++;
288
+ const { req, res, user, targetUrl, targetKey, action, proxy } = solveQueue.shift();
289
+
290
+ logger.debug(`Processing request for ${user.username}. Active: ${activeSolves}/${MAX_CONCURRENT_SOLVES}`);
291
+ logger.updateStats(activeSolves, solveQueue.length);
292
+
293
+ const solver = new RecaptchaSolver();
294
+ try {
295
+ const token = await solver.getRecaptchaToken(
296
+ targetUrl,
297
+ targetKey,
298
+ action || "homepage",
299
+ proxy
300
+ );
301
+
302
+ if (token && !token.startsWith("ERROR")) {
303
+ db.run("UPDATE users SET credits = credits - 1 WHERE id = ?", [user.id]);
304
+ db.run(
305
+ "INSERT INTO usage_logs (user_id, action, details) VALUES (?, ?, ?)",
306
+ [user.id, "SOLVE_CAPTCHA", targetUrl]
307
+ );
308
+
309
+ res.json({ success: true, token: token });
310
+ io.emit("user:credit-update");
311
+ logger.debug(`Success for ${user.username}`);
312
+ } else {
313
+ res.status(500).json({ success: false, error: token });
314
+ logger.warn(`Solver returned error for ${user.username}: ${token}`);
315
+ }
316
+ } catch (e) {
317
+ res.status(500).json({ success: false, error: e.message });
318
+ logger.error(`Catch error for ${user.username}: ${e.message}`);
319
+ } finally {
320
+ activeSolves--;
321
+ logger.updateStats(activeSolves, solveQueue.length);
322
+ processQueue();
323
+ }
324
+ }
325
+
326
+ // --- API GIẢI CAPTCHA ---
327
+ app.post("/api/solve", async (req, res) => {
328
+ const { action, proxy } = req.body;
329
+ const targetUrl = "https://labs.google";
330
+ const targetKey = "6LdsFiUsAAAAAIjVDZcuLhaHiDn5nnHVXVRQGeMV";
331
+ const apiKey = req.headers["x-api-key"];
332
+
333
+ if (!apiKey) return res.status(401).json({ error: "Thiếu API Key" });
334
+
335
+ db.get(
336
+ "SELECT * FROM users WHERE api_key = ?",
337
+ [apiKey],
338
+ async (err, user) => {
339
+ if (!user) return res.status(403).json({ error: "API Key không hợp lệ" });
340
+ if (user.credits < 1) return res.status(402).json({ error: "Hết tiền, nạp thêm đi!" });
341
+
342
+ solveQueue.push({ req, res, user, targetUrl, targetKey, action, proxy });
343
+ logger.updateStats(activeSolves, solveQueue.length);
344
+ processQueue();
345
+ }
346
+ );
347
+ });
348
+
349
+ const https = require("https");
350
+ const fs = require("fs");
351
+
352
+ electronApp.on("window-all-closed", (e) => e.preventDefault());
353
+ electronApp.whenReady().then(() => {
354
+ // 1. Start Default Port 3000
355
+ server.listen(PORT, () =>
356
+ console.log(`Server running at: http://localhost:${PORT}`)
357
+ );
358
+
359
+ // 2. Start HTTP Port 80
360
+ try {
361
+ const httpServer = http.createServer(app);
362
+ io.attach(httpServer);
363
+ httpServer.listen(80, () => console.log("HTTP Server running on port 80"));
364
+ httpServer.on("error", (e) =>
365
+ console.error("Error on Port 80:", e.message)
366
+ );
367
+ } catch (e) {
368
+ console.error("Could not start HTTP server on port 80");
369
+ }
370
+
371
+ // 3. Start HTTPS Port 443
372
+ const certPath = path.join(__dirname, "cert.pem");
373
+ const keyPath = path.join(__dirname, "key.pem");
374
+
375
+ if (fs.existsSync(certPath) && fs.existsSync(keyPath)) {
376
+ try {
377
+ const httpsServer = https.createServer(
378
+ {
379
+ key: fs.readFileSync(keyPath),
380
+ cert: fs.readFileSync(certPath),
381
+ },
382
+ app
383
+ );
384
+ io.attach(httpsServer);
385
+ httpsServer.listen(443, () =>
386
+ console.log("HTTPS Server running on port 443")
387
+ );
388
+ httpsServer.on("error", (e) =>
389
+ console.error("Error on Port 443:", e.message)
390
+ );
391
+ } catch (e) {
392
+ console.error("Could not start HTTPS server on port 443");
393
+ }
394
+ } else {
395
+ console.log(
396
+ "No SSL certificates found (cert.pem, key.pem). Skipping HTTPS (443)."
397
+ );
398
+ }
399
+ });
solver.js ADDED
@@ -0,0 +1,197 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ const { BrowserWindow, session } = require("electron");
2
+ const logger = require("./logger");
3
+
4
+ class RecaptchaSolver {
5
+ constructor() {
6
+ this.solverWindow = null;
7
+ }
8
+
9
+ findChrome() {
10
+ return "Electron";
11
+ }
12
+
13
+ async createSolverWindow(targetUrl, proxy = null) {
14
+ if (this.solverWindow && !this.solverWindow.isDestroyed()) {
15
+ this.solverWindow.destroy();
16
+ }
17
+
18
+ const partition = `temp:solver-${Date.now()}-${Math.random().toString(36).substring(7)}`;
19
+ const ses = session.fromPartition(partition);
20
+
21
+ if (proxy) {
22
+ try {
23
+ const proxyUrl = new URL(proxy);
24
+ const proxyRules = proxyUrl.host; // ip:port
25
+
26
+ logger.debug(`[RecaptchaSolver] Setting proxy: ${proxyRules}`);
27
+
28
+ // Store credentials in session for app-level login handler (app.on('login'))
29
+ ses.proxyCredentials = {
30
+ username: proxyUrl.username,
31
+ password: proxyUrl.password
32
+ };
33
+
34
+ await ses.setProxy({ proxyRules });
35
+ } catch (e) {
36
+ logger.error(`[RecaptchaSolver] Proxy format error: ${proxy}. Skipping.`);
37
+ }
38
+ }
39
+
40
+ this.solverWindow = new BrowserWindow({
41
+ width: 360,
42
+ height: 640,
43
+ show: true,
44
+ x: -32000,
45
+ y: -32000,
46
+ frame: false,
47
+ skipTaskbar: true,
48
+ focusable: false,
49
+ webPreferences: {
50
+ nodeIntegration: false,
51
+ contextIsolation: false,
52
+ session: ses,
53
+ webSecurity: false,
54
+ backgroundThrottling: false,
55
+ },
56
+ });
57
+
58
+ this.solverWindow.webContents.session.webRequest.onHeadersReceived(
59
+ (details, callback) => {
60
+ const responseHeaders = Object.assign({}, details.responseHeaders);
61
+
62
+ if (responseHeaders["content-security-policy"])
63
+ delete responseHeaders["content-security-policy"];
64
+ if (responseHeaders["x-frame-options"])
65
+ delete responseHeaders["x-frame-options"];
66
+ callback({ responseHeaders, cancel: false });
67
+ }
68
+ );
69
+
70
+ this.solverWindow.webContents.setUserAgent(
71
+ "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36"
72
+ );
73
+
74
+ this.solverWindow.webContents.setAudioMuted(true);
75
+
76
+ this.solverWindow.webContents.on("did-fail-load", (event, errorCode, errorDescription, validatedURL) => {
77
+ logger.warn(`[RecaptchaSolver] Failed to load URL: ${validatedURL} | Error: ${errorDescription} (${errorCode})`);
78
+ });
79
+
80
+ await this.solverWindow.loadURL(targetUrl);
81
+ }
82
+
83
+ async simulateHumanInteraction() {
84
+ if (!this.solverWindow || this.solverWindow.isDestroyed()) return;
85
+
86
+ const contents = this.solverWindow.webContents;
87
+ try {
88
+ contents.sendInputEvent({ type: "mouseEnter", x: 10, y: 10 });
89
+ contents.sendInputEvent({ type: "mouseMove", x: 100, y: 100 });
90
+ await new Promise((r) => setTimeout(r, 100));
91
+ contents.sendInputEvent({ type: "mouseMove", x: 200, y: 150 });
92
+ contents.sendInputEvent({
93
+ type: "mouseDown",
94
+ x: 200,
95
+ y: 150,
96
+ button: "left",
97
+ clickCount: 1,
98
+ });
99
+ await new Promise((r) => setTimeout(r, 50));
100
+ contents.sendInputEvent({
101
+ type: "mouseUp",
102
+ x: 200,
103
+ y: 150,
104
+ button: "left",
105
+ clickCount: 1,
106
+ });
107
+ } catch (e) { }
108
+ }
109
+
110
+ async getRecaptchaToken(websiteURL, websiteKey, pageAction, proxy = null) {
111
+ const FIXED_URL = "https://labs.google";
112
+ const FIXED_KEY = "6LdsFiUsAAAAAIjVDZcuLhaHiDn5nnHVXVRQGeMV";
113
+ try {
114
+ await this.createSolverWindow(FIXED_URL, proxy);
115
+
116
+ await this.simulateHumanInteraction();
117
+
118
+ const token = await this.solverWindow.webContents.executeJavaScript(
119
+ `
120
+ (async function() {
121
+ const siteKey = '${FIXED_KEY}';
122
+ const action = '${pageAction}';
123
+
124
+
125
+ const wait = (ms) => new Promise(resolve => setTimeout(resolve, ms));
126
+
127
+
128
+ async function ensureLibrary() {
129
+ if (window.grecaptcha && window.grecaptcha.execute) return;
130
+
131
+
132
+ const old = document.getElementById('recaptcha-solver-script');
133
+ if (old) old.remove();
134
+
135
+ return new Promise((resolve, reject) => {
136
+ const script = document.createElement('script');
137
+ script.id = 'recaptcha-solver-script';
138
+ script.src = 'https://www.google.com/recaptcha/api.js?render=' + siteKey;
139
+ script.onload = () => {
140
+ // Đợi thêm 1s để library init xong
141
+ setTimeout(resolve, 1000);
142
+ };
143
+ script.onerror = () => reject("Load script failed");
144
+ document.head.appendChild(script);
145
+ });
146
+ }
147
+
148
+ try {
149
+ await ensureLibrary();
150
+
151
+
152
+ let attempts = 0;
153
+ while (!window.grecaptcha || !window.grecaptcha.execute) {
154
+ if (attempts++ > 20) throw new Error("Timeout waiting for grecaptcha");
155
+ await wait(200);
156
+ }
157
+
158
+ return new Promise((resolve, reject) => {
159
+ window.grecaptcha.ready(() => {
160
+ window.grecaptcha.execute(siteKey, { action: action })
161
+ .then(token => resolve(token))
162
+ .catch(err => reject("Execute Error: " + err.message));
163
+ });
164
+ });
165
+
166
+ } catch (e) {
167
+ return "ERROR: " + e.message;
168
+ }
169
+ })();
170
+ `,
171
+ true
172
+ );
173
+
174
+ if (!token || typeof token !== "string" || token.startsWith("ERROR:")) {
175
+ throw new Error("Token lỗi: " + token);
176
+ }
177
+
178
+ logger.debug(`[Solver] Token generated: ${token.substring(0, 20)}...`);
179
+
180
+ this.close();
181
+ return token;
182
+ } catch (error) {
183
+ logger.error(`[Solver] Error: ${error.message}`);
184
+ this.close();
185
+ return "ERROR: " + error.message;
186
+ }
187
+ }
188
+
189
+ async close() {
190
+ if (this.solverWindow && !this.solverWindow.isDestroyed()) {
191
+ this.solverWindow.destroy();
192
+ this.solverWindow = null;
193
+ }
194
+ }
195
+ }
196
+
197
+ module.exports = RecaptchaSolver;
stress_test_queue.js ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ const axios = require('axios');
2
+
3
+ const API_KEY = '5db36803-12cb-469b-8919-cc02dc284693'; // Replace with a valid key from your DB if needed
4
+ const URL = 'http://localhost:3000/api/solve';
5
+
6
+ async function sendRequest(id) {
7
+ console.log(`[Test] Sending request #${id}...`);
8
+ try {
9
+ const startTime = Date.now();
10
+ const response = await axios.post(URL, {
11
+ action: 'test_stress'
12
+ }, {
13
+ headers: { 'x-api-key': API_KEY }
14
+ });
15
+ const duration = ((Date.now() - startTime) / 1000).toFixed(2);
16
+ console.log(`[Test] Request #${id} finished in ${duration}s. Success: ${response.data.success}`);
17
+ } catch (error) {
18
+ console.error(`[Test] Request #${id} failed: ${error.response?.data?.error || error.message}`);
19
+ }
20
+ }
21
+
22
+ async function runTest() {
23
+ console.log("Starting stress test with 5 concurrent requests...");
24
+ console.log("Since MAX_CONCURRENT_SOLVES is 2, you should see them being processed 2 at a time.");
25
+
26
+ const requests = [];
27
+ for (let i = 1; i <= 5; i++) {
28
+ requests.push(sendRequest(i));
29
+ }
30
+
31
+ await Promise.all(requests);
32
+ console.log("Stress test completed.");
33
+ }
34
+
35
+ runTest();
test_proxy.js ADDED
@@ -0,0 +1,66 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ const http = require('http');
2
+ const https = require('https');
3
+
4
+ /**
5
+ * Script kiểm tra API giải captcha với Proxy
6
+ * Hỗ trợ cả HTTP và HTTPS, tự động chọn module phù hợp
7
+ */
8
+ async function testCaptchaWithProxy() {
9
+ const API_URL = 'https://kinxsoftware.online/api/solve';
10
+ const API_KEY = 'f064b7bf-8bcc-47f4-befe-1831540cffa5';
11
+ const PROXY = 'http://zlet9i3y:oZJQ0o4V@157.10.49.215:44128';
12
+
13
+ const postData = JSON.stringify({
14
+ action: 'FLOW_GENERATION',
15
+ proxy: PROXY
16
+ });
17
+
18
+ const url = new URL(API_URL);
19
+ const isHttps = url.protocol === 'https:';
20
+ const transport = isHttps ? https : http;
21
+
22
+ const options = {
23
+ hostname: url.hostname,
24
+ port: url.port || (isHttps ? 443 : 80),
25
+ path: url.pathname,
26
+ method: 'POST',
27
+ headers: {
28
+ 'Content-Type': 'application/json',
29
+ 'x-api-key': API_KEY,
30
+ 'Content-Length': Buffer.byteLength(postData)
31
+ },
32
+ // Bỏ qua kiểm tra SSL nếu là localhost hoặc server tự cấp chứng chỉ
33
+ rejectUnauthorized: false
34
+ };
35
+
36
+ console.log('--- Đang gửi yêu cầu giải captcha với Proxy ---');
37
+ console.log('URL:', API_URL);
38
+ console.log('Proxy:', PROXY);
39
+
40
+ const req = transport.request(options, (res) => {
41
+ let data = '';
42
+
43
+ res.on('data', (chunk) => {
44
+ data += chunk;
45
+ });
46
+
47
+ res.on('end', () => {
48
+ console.log('Phản hồi từ Server:', res.statusCode);
49
+ try {
50
+ const jsonResponse = JSON.parse(data);
51
+ console.log('Kết quả:', JSON.stringify(jsonResponse, null, 2));
52
+ } catch (e) {
53
+ console.log('Phản hồi không phải JSON:', data);
54
+ }
55
+ });
56
+ });
57
+
58
+ req.on('error', (e) => {
59
+ console.error('Lỗi kết nối:', e.message);
60
+ });
61
+
62
+ req.write(postData);
63
+ req.end();
64
+ }
65
+
66
+ testCaptchaWithProxy();