2025-08-09通过授权码的方式给exe程序充值

2025-08-09通过授权码的方式给exe程序充值

主要点:

一次性授权机制: 新增 .used_licenses 文件记录所有已使用的授权码 每次激活前检查授权码是否在已使用列表中 激活成功后立即将授权码标记为已使用 时效性验证: 授权码包含过期时间戳(默认 24 小时有效) 超过有效期的授权码无法使用 防止用户长期保存授权码多次使用 授权码格式升级: 新格式:次数|过期时间戳|哈希值(例如:50|1620000000|xxxxxxxxxxx) 时间戳精确到分钟,确保唯一性

使用流程:

开发者生成授权码: 运行 license_generator.py 输入次数(如 50)和有效期(如 24 小时) 生成授权码并发送给用户 用户使用授权码: 在程序中输入授权码并激活 系统验证通过后增加次数并记录此授权码 再次使用同一授权码会提示 "已被使用"

首先创建一个授权码生成工具(开发者使用):

python 复制代码
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 random
​
DEVELOPER_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:
                        pass
                
                test_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:
                continue
        
        return None
​
    def _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_part
            return None
        except:
            return None
​
    def 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:
                        pass
        except:
            pass
​
    def read_use_count(self):
        if not os.path.exists(self.license_file):
            return 0
            
        try:
            with open(self.license_file, 'r') as f:
                content = f.read().strip()
            
            data = self._decrypt_data(content)
            if data is None:
                return 0
                
            return int(data) if data.isdigit() else 0
        except:
            return 0
​
    def write_use_count(self, count):
        try:
            with open(self.license_file, 'w') as f:
                f.write(self._encrypt_data(str(count)))
            return True
        except:
            return False
​
    def 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_codes
            return False
        except:
            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 True
        except:
            return False
    
    def 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_uses
            if 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, "提示", "请输入授权码")
            return
            
        success, 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)
            return
        else:
            self.status_label.setText(msg)
​
        url_text = self.url_entry.toPlainText().strip()
        if not url_text:
            QMessageBox.critical(self, "错误", "请输入有效的URL")
            return
​
        urls = []
        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")
            return
​
        self.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. 然后在主程序中添加授权码输入功能(用户使用)

python 复制代码
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)}")
​
相关推荐
深度红薯8 分钟前
SAM3:开放式分割,太强了(后面有SAM3权重下载方式)(单图测试、视频测试、实时跟踪)
图像处理·人工智能·python·深度学习·毕业设计·毕设·sam3
weixin_4249993612 分钟前
html如何修改备注
jvm·数据库·python
214396517 分钟前
HTML怎么创建时间轴布局_HTML结构化时间线写法【方法】
jvm·数据库·python
小草cys17 分钟前
树莓派4b + USRP B210 搭建反无人机(反无)系统( HTML + CDN )
开发语言·python·机器学习
gmaajt17 分钟前
HTML函数开发需要SSD吗_SSD对HTML函数开发效率影响【详解】
jvm·数据库·python
LiAo_1996_Y18 分钟前
p标签能嵌套div吗_HTML块级元素嵌套规则【解答】
jvm·数据库·python
2301_8166602120 分钟前
c++怎么将纯C的FILE-升级为C++的fstream_流缓冲绑定技巧【详解】
jvm·数据库·python
码界筑梦坊21 分钟前
89-基于Django的加利福尼亚州各县死亡概况分析系统
数据库·python·信息可视化·数据分析·django·毕业设计
m0_5145205722 分钟前
CSS如何实现输入框提示文字的浮动动画_利用transform translateY上移
jvm·数据库·python
yejqvow1224 分钟前
php怎么调用字节跳动AI商品推荐_php如何基于用户行为生成千人千面
jvm·数据库·python