Download server.js from vipsphi/luadao: direct link, hf CLI and curl.
- Browser
- Download file 12.2 kB
-
https://huggingface.co/spaces/vipsphi/luadao/resolve/main/server.js
- Command line
-
hf download hf://spaces/vipsphi/luadao/server.js
-
curl -L -o server.js https://huggingface.co/spaces/vipsphi/luadao/resolve/main/server.js
12.2 kB
| const { app: electronApp } = require("electron"); | |
| const express = require("express"); | |
| const bodyParser = require("body-parser"); | |
| const cors = require("cors"); | |
| const sqlite3 = require("sqlite3").verbose(); | |
| const { v4: uuidv4 } = require("uuid"); | |
| const path = require("path"); | |
| const RecaptchaSolver = require("./solver"); | |
| const http = require("http"); | |
| const { Server } = require("socket.io"); | |
| const PORT = 7860; | |
| const app = express(); | |
| const server = http.createServer(app); | |
| const io = new Server(server, { | |
| cors: { origin: "*" }, | |
| }); | |
| const db = new sqlite3.Database("./database.sqlite"); | |
| // --- INIT DB --- | |
| db.serialize(() => { | |
| // Thêm cột role để phân quyền (admin/user) | |
| db.run(`CREATE TABLE IF NOT EXISTS users ( | |
| id INTEGER PRIMARY KEY AUTOINCREMENT, | |
| username TEXT UNIQUE, | |
| password TEXT, | |
| api_key TEXT, | |
| credits INTEGER DEFAULT 0, | |
| role TEXT DEFAULT 'user', | |
| hwid TEXT | |
| )`); | |
| db.run("ALTER TABLE users ADD COLUMN hwid TEXT", (err) => { | |
| if (err) { | |
| if (!err.message.includes("duplicate column name")) { | |
| console.error("Migration error (hwid):", err.message); | |
| } | |
| } | |
| }); | |
| db.run("UPDATE users SET role = 'admin' WHERE username = 'admin'"); | |
| // Bảng lưu lịch sử nạp tiền chờ duyệt | |
| db.run(`CREATE TABLE IF NOT EXISTS transactions ( | |
| id INTEGER PRIMARY KEY AUTOINCREMENT, | |
| user_id INTEGER, | |
| username TEXT, | |
| amount INTEGER, | |
| method TEXT, | |
| status TEXT DEFAULT 'pending', -- pending, approved, rejected | |
| created_at DATETIME DEFAULT CURRENT_TIMESTAMP | |
| )`); | |
| // Bảng log lịch sử sử dụng | |
| db.run(`CREATE TABLE IF NOT EXISTS usage_logs ( | |
| id INTEGER PRIMARY KEY AUTOINCREMENT, | |
| user_id INTEGER, | |
| action TEXT, | |
| details TEXT, | |
| timestamp DATETIME DEFAULT CURRENT_TIMESTAMP | |
| )`); | |
| }); | |
| app.use(cors()); | |
| app.use(bodyParser.json()); | |
| app.use(express.static(path.join(__dirname, "public"))); | |
| // --- HEALTH CHECK --- | |
| app.get("/ping", (req, res) => { | |
| res.status(200).send("pong"); | |
| }); | |
| // --- MIDDLEWARE CHECK ADMIN --- | |
| const requireAdmin = (req, res, next) => { | |
| const apiKey = req.headers["x-api-key"]; | |
| db.get("SELECT role FROM users WHERE api_key = ?", [apiKey], (err, row) => { | |
| if (row && row.role === "admin") next(); | |
| else res.status(403).json({ error: "Bạn không phải Admin!" }); | |
| }); | |
| }; | |
| // --- AUTH --- | |
| app.post("/api/register", (req, res) => { | |
| const { username, password, hwid } = req.body; | |
| const apiKey = uuidv4(); | |
| // Kiểm tra xem HWID này đã được cộng tiền lần nào chưa | |
| db.get("SELECT id FROM users WHERE hwid = ?", [hwid], (err, row) => { | |
| const initialCredits = row ? 0 : 100; // Nếu đã tồn tại HWID thì 0, mới thì 100 | |
| const message = row | |
| ? "Đăng ký thành công! (Máy này đã nhận bonus trước đó nên không được cộng thêm)" | |
| : "Đăng ký thành công! Bạn nhận được +100 Credits bonus."; | |
| const stmt = db.prepare( | |
| "INSERT INTO users (username, password, api_key, credits, role, hwid) VALUES (?, ?, ?, ?, 'user', ?)" | |
| ); | |
| stmt.run(username, password, apiKey, initialCredits, hwid, function (err) { | |
| if (err) return res.status(400).json({ error: "User đã tồn tại" }); | |
| res.json({ success: true, message: message }); | |
| io.emit("admin:new-user"); | |
| }); | |
| stmt.finalize(); | |
| }); | |
| }); | |
| app.post("/api/login", (req, res) => { | |
| const { username, password } = req.body; | |
| db.get( | |
| "SELECT * FROM users WHERE username = ? AND password = ?", | |
| [username, password], | |
| (err, row) => { | |
| if (!row) return res.status(401).json({ error: "Sai thông tin" }); | |
| res.json({ success: true, user: row }); | |
| } | |
| ); | |
| }); | |
| app.get("/api/me", (req, res) => { | |
| const apiKey = req.headers["x-api-key"]; | |
| db.get( | |
| "SELECT username, credits, api_key, role FROM users WHERE api_key = ?", | |
| [apiKey], | |
| (err, row) => { | |
| if (row) res.json(row); | |
| else res.status(401).json({ error: "Key lỗi" }); | |
| } | |
| ); | |
| }); | |
| // --- HISTORY API --- | |
| app.get("/api/history/usage", (req, res) => { | |
| const apiKey = req.headers["x-api-key"]; | |
| db.get("SELECT id FROM users WHERE api_key = ?", [apiKey], (err, user) => { | |
| if (!user) return res.status(401).json({ error: "Auth failed" }); | |
| db.all( | |
| "SELECT * FROM usage_logs WHERE user_id = ? ORDER BY id DESC LIMIT 50", | |
| [user.id], | |
| (err, rows) => { | |
| res.json(rows); | |
| } | |
| ); | |
| }); | |
| }); | |
| app.get("/api/history/transactions", (req, res) => { | |
| const apiKey = req.headers["x-api-key"]; | |
| db.get("SELECT id FROM users WHERE api_key = ?", [apiKey], (err, user) => { | |
| if (!user) return res.status(401).json({ error: "Auth failed" }); | |
| db.all( | |
| "SELECT * FROM transactions WHERE user_id = ? ORDER BY id DESC", | |
| [user.id], | |
| (err, rows) => { | |
| res.json(rows); | |
| } | |
| ); | |
| }); | |
| }); | |
| // --- USER: TẠO YÊU CẦU NẠP TIỀN --- | |
| app.post("/api/deposit", (req, res) => { | |
| const apiKey = req.headers["x-api-key"]; | |
| const { amount, method } = req.body; // amount tính bằng USD (1, 5, 10) | |
| db.get( | |
| "SELECT id, username FROM users WHERE api_key = ?", | |
| [apiKey], | |
| (err, user) => { | |
| if (!user) return res.status(401).json({ error: "User không tồn tại" }); | |
| const stmt = db.prepare( | |
| "INSERT INTO transactions (user_id, username, amount, method) VALUES (?, ?, ?, ?)" | |
| ); | |
| stmt.run(user.id, user.username, amount, method, function (err) { | |
| if (err) return res.status(500).json({ error: "Lỗi tạo giao dịch" }); | |
| res.json({ | |
| success: true, | |
| message: "Đã gửi yêu cầu! Vui lòng đợi Admin duyệt.", | |
| }); | |
| io.emit("admin:new-transaction"); // Notify admin | |
| }); | |
| stmt.finalize(); | |
| } | |
| ); | |
| }); | |
| // --- ADMIN API --- | |
| // 1. Lấy danh sách user | |
| app.get("/api/admin/users", requireAdmin, (req, res) => { | |
| db.all( | |
| "SELECT id, username, credits, role, api_key FROM users", | |
| [], | |
| (err, rows) => { | |
| res.json(rows); | |
| } | |
| ); | |
| }); | |
| // 2. Lấy danh sách giao dịch nạp tiền | |
| app.get("/api/admin/transactions", requireAdmin, (req, res) => { | |
| db.all("SELECT * FROM transactions ORDER BY id DESC", [], (err, rows) => { | |
| res.json(rows); | |
| }); | |
| }); | |
| // 3. Duyệt hoặc Từ chối nạp tiền | |
| app.post("/api/admin/approve", requireAdmin, (req, res) => { | |
| const { transId, action } = req.body; // action: 'approve' | 'reject' | |
| db.get("SELECT * FROM transactions WHERE id = ?", [transId], (err, trans) => { | |
| if (!trans || trans.status !== "pending") | |
| return res.status(400).json({ error: "Giao dịch không hợp lệ" }); | |
| if (action === "reject") { | |
| db.run("UPDATE transactions SET status = 'rejected' WHERE id = ?", [ | |
| transId, | |
| ]); | |
| db.run("UPDATE transactions SET status = 'rejected' WHERE id = ?", [ | |
| transId, | |
| ]); | |
| io.emit("transaction-updated"); | |
| return res.json({ success: true, message: "Đã từ chối giao dịch" }); | |
| } | |
| if (action === "approve") { | |
| const creditsToAdd = trans.amount * 1000; // $1 = 1000 credits | |
| db.serialize(() => { | |
| db.run("UPDATE transactions SET status = 'approved' WHERE id = ?", [ | |
| transId, | |
| ]); | |
| db.run("UPDATE users SET credits = credits + ? WHERE id = ?", [ | |
| creditsToAdd, | |
| trans.user_id, | |
| ]); | |
| }); | |
| return res.json({ | |
| success: true, | |
| message: `Đã duyệt! Cộng ${creditsToAdd} credits cho ${trans.username}`, | |
| }); | |
| io.emit("transaction-updated"); | |
| // Notify specific user to update credits (client filters by checking if it's their update) | |
| io.emit("user:credit-update"); | |
| } | |
| }); | |
| }); | |
| // 5. Xóa user | |
| app.post("/api/admin/delete-user", requireAdmin, (req, res) => { | |
| const { userId } = req.body; | |
| db.run("DELETE FROM users WHERE id = ?", [userId], function (err) { | |
| if (err) return res.status(500).json({ error: "Lỗi xóa user" }); | |
| res.json({ success: true, message: "Đã xóa người dùng thành công." }); | |
| io.emit("admin:user-deleted"); // Notify admin to refresh list | |
| }); | |
| }); | |
| // 4. Cộng/Trừ tiền thủ công cho user | |
| app.post("/api/admin/update-credits", requireAdmin, (req, res) => { | |
| const { userId, amount } = req.body; // amount có thể là số âm để trừ | |
| db.run( | |
| "UPDATE users SET credits = credits + ? WHERE id = ?", | |
| [amount, userId], | |
| function (err) { | |
| if (err) return res.status(500).json({ error: "Lỗi database" }); | |
| res.json({ success: true, message: "Đã cập nhật số dư user." }); | |
| io.emit("user:credit-update"); | |
| } | |
| ); | |
| }); | |
| // --- API GIẢI CAPTCHA (GIỮ NGUYÊN) --- | |
| app.post("/api/solve", async (req, res) => { | |
| // const { url, siteKey, action } = req.body; | |
| const { action } = req.body; | |
| const targetUrl = "https://labs.google"; | |
| const targetKey = "6LdsFiUsAAAAAIjVDZcuLhaHiDn5nnHVXVRQGeMV"; | |
| const apiKey = req.headers["x-api-key"]; | |
| if (!apiKey) return res.status(401).json({ error: "Thiếu API Key" }); | |
| db.get( | |
| "SELECT * FROM users WHERE api_key = ?", | |
| [apiKey], | |
| async (err, user) => { | |
| if (!user) | |
| return res.status(403).json({ error: "API Key không tồn tại" }); | |
| if (user.credits <= 0) | |
| return res.status(402).json({ error: "Hết tiền rồi!" }); | |
| const solver = new RecaptchaSolver(); | |
| try { | |
| const token = await solver.getRecaptchaToken( | |
| targetUrl, | |
| targetKey, | |
| action || undefined | |
| ); | |
| if (token && !token.startsWith("ERROR")) { | |
| db.run("UPDATE users SET credits = credits - 1 WHERE id = ?", [ | |
| user.id, | |
| ]); | |
| const logDetails = JSON.stringify({ | |
| url: targetUrl, | |
| status: "Success", | |
| length: token.length, | |
| }); | |
| db.run( | |
| "INSERT INTO usage_logs (user_id, action, details) VALUES (?, ?, ?)", | |
| [user.id, "SOLVE_CAPTCHA", logDetails] | |
| ); | |
| res.json({ success: true, token: token }); | |
| io.emit("user:credit-update"); | |
| } else { | |
| // Log Failure | |
| const logDetails = JSON.stringify({ | |
| url: targetUrl, | |
| status: "Failed", | |
| error: token || "Unknown Error", | |
| length: 0, | |
| }); | |
| db.run( | |
| "INSERT INTO usage_logs (user_id, action, details) VALUES (?, ?, ?)", | |
| [user.id, "SOLVE_CAPTCHA", logDetails] | |
| ); | |
| res.status(500).json({ success: false, error: token }); | |
| } | |
| } catch (e) { | |
| res.status(500).json({ success: false, error: e.message }); | |
| } | |
| } | |
| ); | |
| }); | |
| const https = require("https"); | |
| const fs = require("fs"); | |
| electronApp.on("window-all-closed", (e) => e.preventDefault()); | |
| electronApp.whenReady().then(() => { | |
| // 1. Start Default Port 3000 | |
| server.listen(PORT, () => | |
| console.log(`Server running at: http://localhost:${PORT}`) | |
| ); | |
| // 2. Start HTTP Port 80 | |
| try { | |
| const httpServer = http.createServer(app); | |
| io.attach(httpServer); | |
| httpServer.listen(80, () => console.log("HTTP Server running on port 80")); | |
| httpServer.on("error", (e) => | |
| console.error("Error on Port 80:", e.message) | |
| ); | |
| } catch (e) { | |
| console.error("Could not start HTTP server on port 80"); | |
| } | |
| // 3. Start HTTPS Port 443 | |
| const certPath = path.join(__dirname, "cert.pem"); | |
| const keyPath = path.join(__dirname, "key.pem"); | |
| if (fs.existsSync(certPath) && fs.existsSync(keyPath)) { | |
| try { | |
| const httpsServer = https.createServer( | |
| { | |
| key: fs.readFileSync(keyPath), | |
| cert: fs.readFileSync(certPath), | |
| }, | |
| app | |
| ); | |
| io.attach(httpsServer); | |
| httpsServer.listen(443, () => | |
| console.log("HTTPS Server running on port 443") | |
| ); | |
| httpsServer.on("error", (e) => | |
| console.error("Error on Port 443:", e.message) | |
| ); | |
| } catch (e) { | |
| console.error("Could not start HTTPS server on port 443"); | |
| } | |
| } else { | |
| console.log( | |
| "No SSL certificates found (cert.pem, key.pem). Skipping HTTPS (443)." | |
| ); | |
| } | |
| }); | |