From dbf86907531497e7ae27e032141b224cd5943b85 Mon Sep 17 00:00:00 2001 From: chengchongzhen <15939054361@163.com> Date: Mon, 30 Dec 2024 13:39:24 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=AE=9E=E7=8E=B0=E8=AE=B8=E5=8F=AF?= =?UTF-8?q?=E8=AF=81=E6=BF=80=E6=B4=BB=E5=92=8C=E9=AA=8C=E8=AF=81=E5=8A=9F?= =?UTF-8?q?=E8=83=BD=EF=BC=8C=E5=A2=9E=E5=8A=A0=E8=AE=B8=E5=8F=AF=E8=AF=81?= =?UTF-8?q?=E7=AE=A1=E7=90=86=E6=9C=8D=E5=8A=A1=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cursor_pro_keep_alive.py | 17 +++-- license_manager.py | 156 ++++++++++++++++++++++++++++++++------- server/.env | 3 + server/models/License.js | 28 +++++++ server/package.json | 21 ++++++ server/server.js | 144 ++++++++++++++++++++++++++++++++++++ 6 files changed, 336 insertions(+), 33 deletions(-) create mode 100644 server/.env create mode 100644 server/models/License.js create mode 100644 server/package.json create mode 100644 server/server.js diff --git a/cursor_pro_keep_alive.py b/cursor_pro_keep_alive.py index 9631de2..1da79fa 100644 --- a/cursor_pro_keep_alive.py +++ b/cursor_pro_keep_alive.py @@ -348,13 +348,20 @@ def cleanup_temp_files(): if __name__ == "__main__": browser_manager = None - license_manager = None try: - # 检查许可证 license_manager = LicenseManager() - if not license_manager.check_license(): - print("免费使用次数已用完") - sys.exit(1) + + # 验证许可证 + is_valid, message = license_manager.verify_license() + if not is_valid: + print(f"许可证验证失败: {message}") + # 提示用户激活 + license_key = input("请输入激活码: ") + success, activate_message = license_manager.activate_license(license_key) + if not success: + print(f"激活失败: {activate_message}") + sys.exit(1) + print("激活成功!") # 加载配置 config = load_config() diff --git a/license_manager.py b/license_manager.py index 02a5e5d..9a79f2f 100644 --- a/license_manager.py +++ b/license_manager.py @@ -1,5 +1,12 @@ +import requests import json import os +import platform +import uuid +import hashlib +from datetime import datetime +from cryptography.fernet import Fernet +import base64 class LicenseManager: @@ -7,39 +14,132 @@ class LicenseManager: self.license_file = os.path.join( os.getenv("APPDATA"), "CursorPro", "license.json" ) - self.max_uses = 10 # 最大使用次数 + self.activation_url = ( + "https://your-activation-server.com/activate" # 替换为您的激活服务器地址 + ) + self.verify_url = ( + "https://your-activation-server.com/verify" # 替换为您的验证服务器地址 + ) + self.key = b"Kj8nP9x2Qs5mY7vR4wL1hC3fA6tD0iB8" + self.fernet = Fernet(base64.b64encode(self.key)) - def check_license(self): + def get_hardware_info(self): + """获取硬件信息作为机器码""" + system_info = { + "platform": platform.platform(), + "machine": platform.machine(), + "processor": platform.processor(), + "hostname": platform.node(), + } + + # 获取MAC地址 + mac = ":".join( + [ + "{:02x}".format((uuid.getnode() >> elements) & 0xFF) + for elements in range(0, 2 * 6, 2) + ][::-1] + ) + system_info["mac"] = mac + + # 生成机器码 + machine_code = hashlib.md5(json.dumps(system_info).encode()).hexdigest() + return machine_code + + def activate_license(self, license_key): + """在线激活许可证""" try: - # 确保目录存在 - os.makedirs(os.path.dirname(self.license_file), exist_ok=True) + machine_code = self.get_hardware_info() - if not os.path.exists(self.license_file): - # 首次运行,创建许可文件 - license_data = {"use_count": 0, "is_activated": False} - with open(self.license_file, "w") as f: - json.dump(license_data, f) - return True + # 准备激活数据 + activation_data = { + "license_key": license_key, + "machine_code": machine_code, + "activation_date": datetime.now().strftime("%Y-%m-%d %H:%M:%S"), + } - # 读取许可信息 - with open(self.license_file, "r") as f: - license_data = json.load(f) + # 发送激活请求 + response = requests.post( + self.activation_url, json=activation_data, timeout=10 + ) - if license_data.get("is_activated"): - return True + if response.status_code == 200: + result = response.json() + if result.get("success"): + # 保存许可证信息 + license_data = { + "license_key": license_key, + "machine_code": machine_code, + "activation_date": activation_data["activation_date"], + "expiry_date": result.get("expiry_date"), + "is_activated": True, + } - # 检查使用次数 - use_count = license_data.get("use_count", 0) - if use_count >= self.max_uses: - return False - - # 增加使用次数并保存 - license_data["use_count"] = use_count + 1 - with open(self.license_file, "w") as f: - json.dump(license_data, f) - - return True + self._save_license(license_data) + return True, "激活成功!" + else: + return False, result.get("message", "激活失败") + else: + return False, "服务器连接失败" except Exception as e: - print(f"License check error: {e}") - return False + return False, f"激活过程出错: {str(e)}" + + def verify_license(self): + """验证许可证""" + try: + if not os.path.exists(self.license_file): + return False, "未找到许可证文件" + + license_data = self._load_license() + if not license_data: + return False, "许可证文件无效" + + # 验证机器码 + current_machine = self.get_hardware_info() + if current_machine != license_data.get("machine_code"): + return False, "硬件信息不匹配" + + # 在线验证 + verify_data = { + "license_key": license_data.get("license_key"), + "machine_code": current_machine, + } + + response = requests.post(self.verify_url, json=verify_data, timeout=10) + + if response.status_code == 200: + result = response.json() + if result.get("success"): + return True, "许可证有效" + return False, result.get("message", "许可证无效") + + # 如果在线验证失败,使用本地数据 + expiry_date = datetime.strptime(license_data["expiry_date"], "%Y-%m-%d") + if datetime.now() > expiry_date: + return False, "许可证已过期" + + return True, "许可证有效" + + except Exception as e: + return False, f"验证过程出错: {str(e)}" + + def _save_license(self, license_data): + """加密保存许可证数据""" + try: + os.makedirs(os.path.dirname(self.license_file), exist_ok=True) + encrypted_data = self.fernet.encrypt(json.dumps(license_data).encode()) + with open(self.license_file, "wb") as f: + f.write(encrypted_data) + except Exception as e: + print(f"保存许可证出错: {e}") + + def _load_license(self): + """加密读取许可证数据""" + try: + with open(self.license_file, "rb") as f: + encrypted_data = f.read() + decrypted_data = self.fernet.decrypt(encrypted_data) + return json.loads(decrypted_data) + except Exception as e: + print(f"读取许可证出错: {e}") + return None diff --git a/server/.env b/server/.env new file mode 100644 index 0000000..e48f571 --- /dev/null +++ b/server/.env @@ -0,0 +1,3 @@ +MONGODB_URI=mongodb://49.234.181.38:27017/license-manager +PORT=3000 +ENCRYPTION_KEY=Kj8nP9x2Qs5mY7vR4wL1hC3fA6tD0iB8 \ No newline at end of file diff --git a/server/models/License.js b/server/models/License.js new file mode 100644 index 0000000..0cf823e --- /dev/null +++ b/server/models/License.js @@ -0,0 +1,28 @@ +const mongoose = require('mongoose'); + +const licenseSchema = new mongoose.Schema({ + licenseKey: { + type: String, + required: true, + unique: true + }, + machineCode: { + type: String, + required: true + }, + activationDate: { + type: Date, + required: true, + default: Date.now + }, + expiryDate: { + type: Date, + required: true + }, + isActive: { + type: Boolean, + default: true + } +}); + +module.exports = mongoose.model('License', licenseSchema); \ No newline at end of file diff --git a/server/package.json b/server/package.json new file mode 100644 index 0000000..c5a98c8 --- /dev/null +++ b/server/package.json @@ -0,0 +1,21 @@ +{ + "name": "license-server", + "version": "1.0.0", + "description": "License activation server for Cursor Pro", + "main": "server.js", + "scripts": { + "start": "node server.js", + "dev": "nodemon server.js" + }, + "dependencies": { + "express": "^4.18.2", + "mongoose": "^8.0.3", + "dotenv": "^16.3.1", + "cors": "^2.8.5", + "crypto": "^1.0.1", + "moment": "^2.29.4" + }, + "devDependencies": { + "nodemon": "^3.0.2" + } +} \ No newline at end of file diff --git a/server/server.js b/server/server.js new file mode 100644 index 0000000..db9bd8b --- /dev/null +++ b/server/server.js @@ -0,0 +1,144 @@ +require('dotenv').config(); +const express = require('express'); +const mongoose = require('mongoose'); +const cors = require('cors'); +const crypto = require('crypto'); +const moment = require('moment'); +const License = require('./models/License'); + +const app = express(); + +// Middleware +app.use(cors()); +app.use(express.json()); + +// Connect to MongoDB +mongoose.connect(process.env.MONGODB_URI) + .then(() => console.log('Connected to MongoDB')) + .catch(err => console.error('MongoDB connection error:', err)); + +// Activation endpoint +app.post('/activate', async (req, res) => { + try { + const { license_key, machine_code, activation_date } = req.body; + + // Validate input + if (!license_key || !machine_code) { + return res.status(400).json({ + success: false, + message: '许可证密钥和机器码是必需的' + }); + } + + // Check if license already exists + const existingLicense = await License.findOne({ licenseKey: license_key }); + if (existingLicense) { + if (existingLicense.machineCode !== machine_code) { + return res.status(400).json({ + success: false, + message: '许可证已在其他设备上激活' + }); + } + if (!existingLicense.isActive) { + return res.status(400).json({ + success: false, + message: '许可证已被禁用' + }); + } + } + + // Create new license or update existing one + const expiryDate = moment().add(1, 'year').toDate(); // 设置一年有效期 + const licenseData = { + licenseKey: license_key, + machineCode: machine_code, + activationDate: activation_date || new Date(), + expiryDate: expiryDate, + isActive: true + }; + + if (existingLicense) { + await License.updateOne({ licenseKey: license_key }, licenseData); + } else { + await License.create(licenseData); + } + + return res.json({ + success: true, + message: '激活成功', + expiry_date: expiryDate.toISOString().split('T')[0] + }); + } catch (error) { + console.error('激活错误:', error); + return res.status(500).json({ + success: false, + message: '服务器错误' + }); + } +}); + +// Verification endpoint +app.post('/verify', async (req, res) => { + try { + const { license_key, machine_code } = req.body; + + // Validate input + if (!license_key || !machine_code) { + return res.status(400).json({ + success: false, + message: '许可证密钥和机器码是必需的' + }); + } + + // Find license + const license = await License.findOne({ licenseKey: license_key }); + + if (!license) { + return res.status(404).json({ + success: false, + message: '许可证不存在' + }); + } + + // Check machine code + if (license.machineCode !== machine_code) { + return res.status(400).json({ + success: false, + message: '硬件信息不匹配' + }); + } + + // Check if license is active + if (!license.isActive) { + return res.status(400).json({ + success: false, + message: '许可证已被禁用' + }); + } + + // Check expiry + if (moment().isAfter(license.expiryDate)) { + return res.status(400).json({ + success: false, + message: '许可证已过期' + }); + } + + return res.json({ + success: true, + message: '许可证有效', + expiry_date: license.expiryDate.toISOString().split('T')[0] + }); + } catch (error) { + console.error('验证错误:', error); + return res.status(500).json({ + success: false, + message: '服务器错误' + }); + } +}); + +const PORT = process.env.PORT || 3000; +app.listen(PORT, () => { + console.log(`Server is running on port ${PORT}`); +}); \ No newline at end of file