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)}")
​
相关推荐
BK贝壳4 小时前
亿级用户签到位图选型复盘:用 bool-hybrid-array 扛冷启动打卡,也把它和 Roaring/Redis 的边界测清楚了
数据结构·python·性能优化·numpy
2601_966949655 小时前
如何根据研究的起止时间截取分钟级行情?Python 实战与 QuantDash 数据处理指南
开发语言·python·pandas·量化交易·1024程序员节·股票数据·quantdash
在世修行9 小时前
智学文枢:页面切换与跨页数据预填
python·桌面应用·signal·1024程序员节·pyside·跨页跳转·状态预填
2601_9628857210 小时前
如何用 Python 把 K 线重采样成任意周期?
开发语言·python
打工仔折腾 AI10 小时前
在 Ubuntu ARM64 部署 Q1 V3.0 MuJoCo 模型:加载、单步推理与执行器响应解析
linux·运维·人工智能·python·深度学习·ubuntu·性能优化
信誓旦旦的程序猿11 小时前
【Python量化实战宝典 #21】北向资金跟随手册:聪明钱择时信号(Python 可跑)
python·1024程序员节·股票数据api·股票数据api接口·股票api数据接口·股票量化数据api·股票量化数据接口
严谨的麻辣烫11 小时前
静态 ISP 代理请求超时怎么排查?Python 与 curl 实战
python·http·requests·1024程序员节·网络排障
KeepRobots13 小时前
11-01 温哥华不回拨:用 60 行 Python 查你的工单系统会不会差一小时(KeepRobots 工程笔记)
python
xiao77mwq13 小时前
你以为 OCR 慢?实测 81.3 s 里全是故障代价:如何把「定格态」消掉,让耗时从 6.5 s 到 13 倍差距显出原形
python
深圳市益普科技有限公司13 小时前
半导体良率管理YMS:良率与设备参数的相关性,先拉哪几组数据
人工智能·python·算法