2025-08-09通过授权码的方式给exe程序充值
2025-08-09通过授权码的方式给exe程序充值
主要点:
一次性授权机制:
新增 .used_licenses 文件记录所有已使用的授权码
每次激活前检查授权码是否在已使用列表中
激活成功后立即将授权码标记为已使用
时效性验证:
授权码包含过期时间戳(默认 24 小时有效)
超过有效期的授权码无法使用
防止用户长期保存授权码多次使用
授权码格式升级:
新格式:次数|过期时间戳|哈希值(例如:50|1620000000|xxxxxxxxxxx)
时间戳精确到分钟,确保唯一性
使用流程:
开发者生成授权码:
运行 license_generator.py
输入次数(如 50)和有效期(如 24 小时)
生成授权码并发送给用户
用户使用授权码:
在程序中输入授权码并激活
系统验证通过后增加次数并记录此授权码
再次使用同一授权码会提示 “已被使用”
首先创建一个授权码生成工具(开发者使用):
import os
import time
import threading
import hashlib
import ctypes
from datetime import datetime
from PyQt5.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout,QHBoxLayout, QLabel, QTextEdit, QPushButton, QProgressBar, QMessageBox, QLineEdit, QDialog)
from PyQt5.QtCore import Qt, pyqtSignal, QObject
from PyQt5.QtGui import QTextOption, QFont
from DrissionPage import ChromiumPage
from lxml import etree
import requests
from concurrent.futures import ThreadPoolExecutor, as_completed
import randomDEVELOPER_INFO = """
已超过试用次数,请联系开发者。
邮箱: xurennie@qq.com
微信:X331752133
需备注添加微信来意,谢谢!
"""PRICING_INFO = """
价格说明:
- 0.05元/URL(每个项目链接)
- 最低充值金额:5元(可下载约100个项目)
- 批量购买可享受优惠,详情请咨询开发者使用说明:
1. 在输入框中填写Behance项目URL,多个URL用逗号分隔
2. 点击"开始下载"按钮进行下载
3. 每次下载会消耗1次使用次数
4. 次数用尽后,请联系开发者充值
5. 充值后将获得授权码,输入授权码即可继续使用联系方式:
邮箱: xurennie@qq.com
微信:X331752133
(添加微信时请备注:Behance下载器充值)
"""LICENSE_KEY = b"behance_downloader_license_key_2024"class LicenseManager:def __init__(self):self.license_file = self.get_secure_license_path()self.used_codes_file = os.path.join(os.path.dirname(self.license_file), ".used_licenses")if not self.license_file:QMessageBox.critical(None, "错误", "无法找到合适的位置存储授权文件\n程序将退出")os._exit(1)self.ensure_license_file()self.ensure_used_codes_file()def get_secure_license_path(self):candidate_paths = []try:if os.name == 'nt':appdata = os.environ.get('APPDATA')if appdata:path1 = os.path.join(appdata, ".BehanceData", "config")candidate_paths.append(path1)localappdata = os.environ.get('LOCALAPPDATA')if localappdata:path2 = os.path.join(localappdata, ".BehanceData", "config")candidate_paths.append(path2)doc_path = os.path.join(os.path.expanduser("~"), "Documents", ".BehanceData")candidate_paths.append(doc_path)exe_dir = os.path.dirname(os.path.abspath(__file__))path4 = os.path.join(exe_dir, ".BehanceData")candidate_paths.append(path4)temp_path = os.environ.get('TEMP', os.path.join(os.path.expanduser("~"), "Temp"))path5 = os.path.join(temp_path, ".BehanceData")candidate_paths.append(path5)else:candidate_paths.append(os.path.join(os.path.expanduser("~"), ".behance_data", "config"))candidate_paths.append(os.path.join(os.path.expanduser("~"), ".config", "behance_data"))candidate_paths.append(os.path.join(os.path.dirname(os.path.abspath(__file__)), ".behance_data"))except Exception as e:print(f"路径生成错误: {e}")for path in candidate_paths:try:os.makedirs(path, exist_ok=True)if os.name == 'nt':try:ctypes.windll.kernel32.SetFileAttributesW(path, 0x02)except:passtest_file = os.path.join(path, ".license_test")with open(test_file, 'w') as f:f.write("test")os.remove(test_file)return os.path.join(path, ".license")except:continuereturn Nonedef _encrypt_data(self, data):hash_obj = hashlib.sha256(LICENSE_KEY)hash_obj.update(str(data).encode())return f"{data}|{hash_obj.hexdigest()}"def _decrypt_data(self, encrypted_data):try:data_part, hash_part = encrypted_data.split('|', 1)hash_obj = hashlib.sha256(LICENSE_KEY)hash_obj.update(data_part.encode())if hash_obj.hexdigest() == hash_part:return data_partreturn Noneexcept:return Nonedef ensure_license_file(self):try:if not os.path.exists(self.license_file):with open(self.license_file, 'w') as f:f.write(self._encrypt_data("30"))except Exception as e:QMessageBox.critical(None, "错误", f"无法创建授权文件: {str(e)}\n程序将退出")os._exit(1)def ensure_used_codes_file(self):"""确保已使用授权码记录文件存在"""try:if not os.path.exists(self.used_codes_file):with open(self.used_codes_file, 'w') as f:f.write("") # 创建空文件# 设置为隐藏文件if os.name == 'nt':try:ctypes.windll.kernel32.SetFileAttributesW(self.used_codes_file, 0x02)except:passexcept:passdef read_use_count(self):if not os.path.exists(self.license_file):return 0try:with open(self.license_file, 'r') as f:content = f.read().strip()data = self._decrypt_data(content)if data is None:return 0return int(data) if data.isdigit() else 0except:return 0def write_use_count(self, count):try:with open(self.license_file, 'w') as f:f.write(self._encrypt_data(str(count)))return Trueexcept:return Falsedef check_license(self):remaining = self.read_use_count()if remaining <= 0:return False, "试用次数已用完"return True, f"剩余试用次数: {remaining}"def update_license(self):remaining = self.read_use_count()if remaining > 0:self.write_use_count(remaining - 1)def is_code_used(self, license_code):"""检查授权码是否已被使用"""try:if os.path.exists(self.used_codes_file):with open(self.used_codes_file, 'r') as f:used_codes = f.read().splitlines()return license_code in used_codesreturn Falseexcept:return False # 读取失败时默认视为已使用,提高安全性def mark_code_as_used(self, license_code):"""标记授权码为已使用"""try:with open(self.used_codes_file, 'a') as f:f.write(f"{license_code}\n")return Trueexcept:return Falsedef add_uses(self, license_code):"""添加使用次数(通过一次性授权码)"""try:# 检查授权码是否已使用if self.is_code_used(license_code):return False, "此授权码已被使用,请联系开发者获取新的授权码"# 解析授权码parts = license_code.split('|')if len(parts) != 3:return False, "授权码格式错误"additional_uses_str, expire_timestamp_str, hash_part = parts# 验证授权码data = f"{additional_uses_str}|{expire_timestamp_str}"hash_obj = hashlib.sha256(LICENSE_KEY)hash_obj.update(data.encode())if hash_obj.hexdigest() != hash_part:return False, "授权码无效"# 验证时间有效性current_timestamp = int(time.time() // 60)expire_timestamp = int(expire_timestamp_str)if current_timestamp > expire_timestamp:return False, "授权码已过期,请联系开发者获取新的授权码"# 验证次数是否为正整数additional_uses = int(additional_uses_str)if additional_uses <= 0:return False, "授权码无效"# 增加次数current_uses = self.read_use_count()new_uses = current_uses + additional_usesif not self.write_use_count(new_uses):return False, "更新次数失败"# 标记为已使用self.mark_code_as_used(license_code)return True, f"成功增加 {additional_uses} 次使用次数,当前剩余: {new_uses} 次"except ValueError:return False, "授权码包含无效数字"except Exception as e:return False, f"处理失败: {str(e)}"class HelpDialog(QDialog):"""帮助对话框,显示价格信息和使用说明"""def __init__(self, parent=None):super().__init__(parent)self.setWindowTitle("使用帮助")self.setGeometry(200, 200, 500, 400)self.init_ui()def init_ui(self):layout = QVBoxLayout()# 创建文本编辑框显示帮助信息help_text = QTextEdit()help_text.setReadOnly(True)help_text.setPlainText(PRICING_INFO)# 设置字体,使内容更易读font = QFont()font.setPointSize(10)help_text.setFont(font)# 添加关闭按钮close_btn = QPushButton("关闭")close_btn.clicked.connect(self.close)# 添加到布局layout.addWidget(help_text)layout.addWidget(close_btn)self.setLayout(layout)class Communicate(QObject):update_signal = pyqtSignal(str)progress_signal = pyqtSignal(int)status_signal = pyqtSignal(str)license_check_signal = pyqtSignal(bool, str)class BehanceDownloaderGUI(QMainWindow):def __init__(self):super().__init__()self.setWindowTitle("Behance图片下载器(可根据个人需求定制)")self.setGeometry(100, 100, 800, 600)self.license = LicenseManager()self.comm = Communicate()self.init_ui()self.check_license_on_start()self.comm.update_signal.connect(self.log)self.comm.progress_signal.connect(self.update_progress)self.comm.status_signal.connect(self.update_status)self.comm.license_check_signal.connect(self.handle_license_check)def init_ui(self):central_widget = QWidget()self.setCentralWidget(central_widget)layout = QVBoxLayout()# 顶部按钮区域:授权码输入和帮助按钮top_layout = QVBoxLayout()# 授权码输入区域license_layout = QHBoxLayout()self.license_input = QLineEdit()self.license_input.setPlaceholderText("输入授权码以增加使用次数(每次需新授权码)")self.activate_btn = QPushButton("激活授权码")self.activate_btn.clicked.connect(self.activate_license)license_layout.addWidget(self.license_input)license_layout.addWidget(self.activate_btn)# 帮助按钮行help_layout = QHBoxLayout()help_layout.setAlignment(Qt.AlignRight) # 右对齐self.help_btn = QPushButton("使用帮助")self.help_btn.clicked.connect(self.show_help)help_layout.addWidget(self.help_btn)# 将授权码布局和帮助按钮布局添加到顶部布局top_layout.addLayout(license_layout)top_layout.addLayout(help_layout)layout.addLayout(top_layout)# URL输入标签self.url_label = QLabel("Behance作品URL:")self.url_label.setWordWrap(True)# URL输入self.url_entry = QTextEdit()self.url_entry.setMaximumHeight(80)self.url_entry.setWordWrapMode(QTextOption.WrapAnywhere)self.url_entry.setPlaceholderText("支持多个url项目下载,每个url用英文输入状态下的,号隔开,示例:https://www.behance.net/url-1,https://www.behance.net/url-2")# 下载按钮self.download_btn = QPushButton("开始下载")self.download_btn.clicked.connect(self.start_download)# 进度条self.progress = QProgressBar()self.progress.setAlignment(Qt.AlignCenter)# 状态标签self.status_label = QLabel("")self.status_label.setAlignment(Qt.AlignCenter)# 日志区域self.log_text = QTextEdit()self.log_text.setReadOnly(True)# 添加到布局layout.addWidget(self.url_label)layout.addWidget(self.url_entry)layout.addWidget(self.download_btn)layout.addWidget(self.progress)layout.addWidget(self.status_label)layout.addWidget(self.log_text)central_widget.setLayout(layout)def show_help(self):"""显示帮助对话框"""help_dialog = HelpDialog(self)help_dialog.exec_()def activate_license(self):"""处理授权码激活"""code = self.license_input.text().strip()if not code:QMessageBox.warning(self, "提示", "请输入授权码")returnsuccess, msg = self.license.add_uses(code)if success:QMessageBox.information(self, "成功", msg)self.license_input.clear()# 更新状态显示valid, status_msg = self.license.check_license()self.status_label.setText(status_msg)else:QMessageBox.critical(self, "失败", msg)def check_license_on_start(self):valid, msg = self.license.check_license()self.comm.license_check_signal.emit(valid, msg)def handle_license_check(self, valid, msg):if not valid:QMessageBox.critical(self, "授权限制", DEVELOPER_INFO + "\n" + msg)self.status_label.setText(msg)else:self.status_label.setText(msg)def log(self, message):self.log_text.append(message)def update_progress(self, value):self.progress.setValue(value)def update_status(self, text):self.status_label.setText(text)def sanitize_filename(self, filename):invalid_chars = '<>:"/\\|?*'for char in invalid_chars:filename = filename.replace(char, '')filename = filename.strip()if len(filename) > 100:filename = filename[:100]return filename if filename else "untitled"def start_download(self):valid, msg = self.license.check_license()if not valid:QMessageBox.critical(self, "授权限制", DEVELOPER_INFO + "\n" + msg)returnelse:self.status_label.setText(msg)url_text = self.url_entry.toPlainText().strip()if not url_text:QMessageBox.critical(self, "错误", "请输入有效的URL")returnurls = []lines = url_text.split('\n')for line in lines:line = line.strip()if line:line_urls = line.split(',')for url in line_urls:url = url.strip()if url and (url.startswith('http://') or url.startswith('https://')):urls.append(url)if not urls:QMessageBox.critical(self, "错误", "请输入有效的URL")returnself.download_btn.setEnabled(False)self.comm.update_signal.emit(f"开始下载任务,共 {len(urls)} 个项目...")download_thread = threading.Thread(target=self.download_projects,args=(urls,),daemon=True)download_thread.start()if __name__ == "__main__":app = QApplication([])window = BehanceDownloaderGUI()window.show()app.exec_()
2. 然后在主程序中添加授权码输入功能(用户使用)
import hashlib
import time# 必须与主程序中的密钥保持一致
LICENSE_KEY = b"behance_downloader_license_key_2024"def generate_license_code(additional_uses, valid_hours=24):"""生成一次性授权码additional_uses: 增加的次数valid_hours: 授权码有效期(小时),默认24小时"""if not isinstance(additional_uses, int) or additional_uses <= 0:raise ValueError("增加的次数必须是正整数")# 添加时间戳(精确到分钟),确保授权码时效性timestamp = int(time.time() // 60) # 每分钟更新一次时间戳# 计算过期时间戳expire_timestamp = timestamp + (valid_hours * 60)# 数据格式: 次数|过期时间戳data = f"{additional_uses}|{expire_timestamp}"# 计算哈希值hash_obj = hashlib.sha256(LICENSE_KEY)hash_obj.update(data.encode())hash_value = hash_obj.hexdigest()# 生成授权码(格式:数据|哈希值)return f"{data}|{hash_value}"if __name__ == "__main__":try:uses = int(input("请输入要增加的次数: "))hours = int(input("请输入授权码有效期(小时,默认24): ") or "24")code = generate_license_code(uses, hours)print(f"\n生成的授权码:{code}")print(f"此授权码有效期为{hours}小时")time.sleep(60)except ValueError as e:print(f"错误: {e}")except Exception as e:print(f"发生错误: {str(e)}")