751 lines
30 KiB
Python
751 lines
30 KiB
Python
"""
|
||
作者:太一
|
||
微信:taiyi1224
|
||
邮箱:shoubo1224@qq.com
|
||
"""
|
||
|
||
import tkinter as tk
|
||
from tkinter import ttk, filedialog, messagebox, scrolledtext
|
||
import os
|
||
import json
|
||
import pyperclip
|
||
from database import LicenseDatabase
|
||
from encryptor import EXEEncryptor
|
||
from machine_code import get_machine_code
|
||
from tkinter import font as tkfont
|
||
|
||
|
||
|
||
def set_dark_theme(root):
|
||
style = ttk.Style(root)
|
||
# 仅 Windows 支持 'vista',其它系统可改为 'clam'
|
||
style.theme_use('clam')
|
||
style.configure('.', background='#2e2e2e', foreground='#ffffff',
|
||
fieldbackground='#3c3f41', selectbackground='#0078d4',
|
||
insertbackground='#ffffff', borderwidth=1,
|
||
focuscolor='none')
|
||
style.map('.', background=[('active', '#0078d4')])
|
||
style.configure('TButton', padding=6, relief='flat',
|
||
background='#0078d4', foreground='#ffffff')
|
||
style.map('TButton', background=[('active', '#106ebe')])
|
||
style.configure('TLabel', background='#2e2e2e', foreground='#ffffff')
|
||
style.configure('TEntry', fieldbackground='#3c3f41', foreground='#ffffff',
|
||
insertbackground='#ffffff', relief='flat', padding=5)
|
||
style.configure('Treeview', background='#252526', foreground='#ffffff',
|
||
fieldbackground='#252526')
|
||
style.configure('Treeview.Heading', background='#3c3f41', foreground='#ffffff')
|
||
|
||
class EXEEncryptionTool(tk.Tk):
|
||
def __init__(self):
|
||
super().__init__()
|
||
self.title("EXE文件加密保护系统")
|
||
self.geometry("800x600")
|
||
self.minsize(800, 600)
|
||
# set_dark_theme(self)
|
||
|
||
# 数据库配置
|
||
self.db_config = {
|
||
'host': '',
|
||
'database': 'license_system',
|
||
'user': '',
|
||
'password': ''
|
||
}
|
||
|
||
# 初始化数据库连接
|
||
self.db = None
|
||
|
||
# 创建界面
|
||
self.create_widgets()
|
||
|
||
# 加载保存的配置
|
||
self.load_config()
|
||
|
||
def create_widgets(self):
|
||
"""创建界面组件"""
|
||
# 创建标签页
|
||
tab_control = ttk.Notebook(self)
|
||
|
||
# 数据库配置标签页
|
||
self.tab_db_config = ttk.Frame(tab_control)
|
||
tab_control.add(self.tab_db_config, text="数据库配置")
|
||
|
||
# 卡密生成标签页
|
||
self.tab_key_gen = ttk.Frame(tab_control)
|
||
tab_control.add(self.tab_key_gen, text="卡密生成")
|
||
|
||
# EXE加密标签页
|
||
self.tab_encrypt = ttk.Frame(tab_control)
|
||
tab_control.add(self.tab_encrypt, text="EXE加密")
|
||
|
||
# 卡密管理标签页
|
||
self.tab_key_manage = ttk.Frame(tab_control)
|
||
tab_control.add(self.tab_key_manage, text="卡密管理")
|
||
|
||
|
||
tab_control.pack(expand=1, fill="both")
|
||
|
||
# 初始化各个标签页
|
||
self.init_db_config_tab()
|
||
self.init_key_gen_tab()
|
||
self.init_encrypt_tab()
|
||
self.init_key_manage_tab()
|
||
|
||
|
||
|
||
# 状态栏
|
||
self.status_var = tk.StringVar(value="就绪")
|
||
status_bar = ttk.Label(self, textvariable=self.status_var, relief=tk.SUNKEN, anchor=tk.W)
|
||
status_bar.pack(side=tk.BOTTOM, fill=tk.X)
|
||
|
||
# def unbind_selected_key(self):
|
||
# key_code = self.get_selected_key_code()
|
||
# if not key_code:
|
||
# return
|
||
# if messagebox.askyesno("确认", f"确定解除卡密 {key_code} 与当前机器的绑定?"):
|
||
# ok, msg = self.db.unbind_key(key_code)
|
||
# messagebox.showinfo("结果", msg)
|
||
# self.load_all_keys()
|
||
|
||
def unbind_selected_key(self):
|
||
"""后台解除卡密与当前机器的绑定"""
|
||
key_code = self.get_selected_key_code()
|
||
if not key_code:
|
||
return
|
||
if not self.db or not self.db.connection.is_connected():
|
||
messagebox.showerror("错误", "请先连接数据库")
|
||
return
|
||
if messagebox.askyesno("确认", f"确定解除卡密 {key_code} 与当前机器的绑定?"):
|
||
ok, msg = self.db.unbind_key(key_code)
|
||
messagebox.showinfo("结果", msg)
|
||
self.load_all_keys() # 刷新列表
|
||
def init_db_config_tab(self):
|
||
"""初始化数据库配置标签页"""
|
||
frame = ttk.LabelFrame(self.tab_db_config, text="数据库连接设置")
|
||
frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
|
||
|
||
# 表单布局
|
||
grid_frame = ttk.Frame(frame)
|
||
grid_frame.pack(padx=10, pady=10, fill=tk.X)
|
||
|
||
# 主机
|
||
ttk.Label(grid_frame, text="主机:").grid(row=0, column=0, padx=5, pady=5, sticky=tk.W)
|
||
self.entry_db_host = ttk.Entry(grid_frame)
|
||
self.entry_db_host.grid(row=0, column=1, padx=5, pady=5, sticky=tk.EW)
|
||
|
||
# 数据库名
|
||
ttk.Label(grid_frame, text="数据库:").grid(row=1, column=0, padx=5, pady=5, sticky=tk.W)
|
||
self.entry_db_name = ttk.Entry(grid_frame)
|
||
self.entry_db_name.grid(row=1, column=1, padx=5, pady=5, sticky=tk.EW)
|
||
self.entry_db_name.insert(0, "")
|
||
|
||
# 用户名
|
||
ttk.Label(grid_frame, text="用户名:").grid(row=2, column=0, padx=5, pady=5, sticky=tk.W)
|
||
self.entry_db_user = ttk.Entry(grid_frame)
|
||
self.entry_db_user.grid(row=2, column=1, padx=5, pady=5, sticky=tk.EW)
|
||
|
||
# 密码
|
||
ttk.Label(grid_frame, text="密码:").grid(row=3, column=0, padx=5, pady=5, sticky=tk.W)
|
||
self.entry_db_password = ttk.Entry(grid_frame, show="*")
|
||
self.entry_db_password.grid(row=3, column=1, padx=5, pady=5, sticky=tk.EW)
|
||
|
||
# 按钮
|
||
button_frame = ttk.Frame(frame)
|
||
button_frame.pack(padx=10, pady=10, fill=tk.X)
|
||
|
||
self.btn_connect_db = ttk.Button(button_frame, text="连接数据库", command=self.connect_db)
|
||
self.btn_connect_db.pack(side=tk.LEFT, padx=5)
|
||
|
||
self.btn_create_tables = ttk.Button(button_frame, text="创建数据库表", command=self.create_db_tables)
|
||
self.btn_create_tables.pack(side=tk.LEFT, padx=5)
|
||
|
||
self.btn_save_db_config = ttk.Button(button_frame, text="保存配置", command=self.save_db_config)
|
||
self.btn_save_db_config.pack(side=tk.RIGHT, padx=5)
|
||
|
||
# 连接状态
|
||
self.label_db_status = ttk.Label(frame, text="未连接数据库", foreground="red")
|
||
self.label_db_status.pack(anchor=tk.W, padx=10, pady=5)
|
||
|
||
# 日志区域
|
||
log_frame = ttk.LabelFrame(frame, text="操作日志")
|
||
log_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
|
||
|
||
self.text_db_log = scrolledtext.ScrolledText(log_frame, height=10)
|
||
self.text_db_log.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
|
||
self.text_db_log.config(state=tk.DISABLED)
|
||
|
||
# 设置网格权重
|
||
grid_frame.columnconfigure(1, weight=1)
|
||
|
||
def init_key_gen_tab(self):
|
||
"""初始化卡密生成标签页"""
|
||
frame = ttk.LabelFrame(self.tab_key_gen, text="卡密生成设置")
|
||
frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
|
||
|
||
# 配置区域
|
||
config_frame = ttk.Frame(frame)
|
||
config_frame.pack(fill=tk.X, padx=10, pady=10)
|
||
|
||
# 有效期
|
||
ttk.Label(config_frame, text="有效期(天):").grid(row=0, column=0, padx=5, pady=5, sticky=tk.W)
|
||
self.entry_valid_days = ttk.Entry(config_frame, width=10)
|
||
self.entry_valid_days.grid(row=0, column=1, padx=5, pady=5)
|
||
self.entry_valid_days.insert(0, "30")
|
||
|
||
# 生成数量
|
||
ttk.Label(config_frame, text="生成数量:").grid(row=0, column=2, padx=5, pady=5, sticky=tk.W)
|
||
self.entry_key_count = ttk.Entry(config_frame, width=10)
|
||
self.entry_key_count.grid(row=0, column=3, padx=5, pady=5)
|
||
self.entry_key_count.insert(0, "1")
|
||
|
||
# 生成按钮
|
||
self.btn_generate_keys = ttk.Button(config_frame, text="生成卡密", command=self.generate_keys)
|
||
self.btn_generate_keys.grid(row=0, column=4, padx=20, pady=5)
|
||
|
||
# 卡密列表
|
||
list_frame = ttk.LabelFrame(frame, text="生成的卡密")
|
||
list_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
|
||
|
||
self.text_keys = scrolledtext.ScrolledText(list_frame)
|
||
self.text_keys.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
|
||
|
||
# 操作按钮
|
||
button_frame = ttk.Frame(frame)
|
||
button_frame.pack(fill=tk.X, padx=10, pady=10)
|
||
|
||
self.btn_copy_keys = ttk.Button(button_frame, text="复制所有卡密", command=self.copy_keys)
|
||
self.btn_copy_keys.pack(side=tk.LEFT, padx=5)
|
||
|
||
self.btn_export_keys = ttk.Button(button_frame, text="导出卡密到文件", command=self.export_keys)
|
||
self.btn_export_keys.pack(side=tk.LEFT, padx=5)
|
||
|
||
# 设置网格权重
|
||
config_frame.columnconfigure(5, weight=1)
|
||
|
||
def init_encrypt_tab(self):
|
||
"""初始化EXE加密标签页"""
|
||
frame = ttk.LabelFrame(self.tab_encrypt, text="EXE文件加密")
|
||
frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
|
||
|
||
# 源文件
|
||
source_frame = ttk.Frame(frame)
|
||
source_frame.pack(fill=tk.X, padx=10, pady=5)
|
||
|
||
ttk.Label(source_frame, text="源EXE文件:").pack(side=tk.LEFT, padx=5)
|
||
self.entry_source_file = ttk.Entry(source_frame)
|
||
self.entry_source_file.pack(side=tk.LEFT, fill=tk.X, expand=True, padx=5)
|
||
self.btn_browse_source = ttk.Button(source_frame, text="浏览...", command=self.browse_source_file)
|
||
self.btn_browse_source.pack(side=tk.LEFT, padx=5)
|
||
|
||
# 目标文件
|
||
dest_frame = ttk.Frame(frame)
|
||
dest_frame.pack(fill=tk.X, padx=10, pady=5)
|
||
|
||
ttk.Label(dest_frame, text="加密后文件:").pack(side=tk.LEFT, padx=5)
|
||
self.entry_dest_file = ttk.Entry(dest_frame)
|
||
self.entry_dest_file.pack(side=tk.LEFT, fill=tk.X, expand=True, padx=5)
|
||
self.btn_browse_dest = ttk.Button(dest_frame, text="浏览...", command=self.browse_dest_file)
|
||
self.btn_browse_dest.pack(side=tk.LEFT, padx=5)
|
||
|
||
# 验证程序
|
||
validator_frame = ttk.Frame(frame)
|
||
validator_frame.pack(fill=tk.X, padx=10, pady=5)
|
||
|
||
ttk.Label(validator_frame, text="验证程序:").pack(side=tk.LEFT, padx=5)
|
||
self.entry_validator = ttk.Entry(validator_frame)
|
||
self.entry_validator.pack(side=tk.LEFT, fill=tk.X, expand=True, padx=5)
|
||
self.btn_browse_validator = ttk.Button(validator_frame, text="浏览...", command=self.browse_validator)
|
||
self.btn_browse_validator.pack(side=tk.LEFT, padx=5)
|
||
|
||
# 加密按钮
|
||
self.btn_encrypt = ttk.Button(frame, text="加密EXE文件", command=self.encrypt_exe)
|
||
self.btn_encrypt.pack(pady=10)
|
||
|
||
# 加密日志
|
||
log_frame = ttk.LabelFrame(frame, text="加密日志")
|
||
log_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
|
||
|
||
self.text_encrypt_log = scrolledtext.ScrolledText(log_frame, height=10)
|
||
self.text_encrypt_log.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
|
||
self.text_encrypt_log.config(state=tk.DISABLED)
|
||
|
||
def init_key_manage_tab(self):
|
||
"""初始化卡密管理标签页"""
|
||
frame = ttk.LabelFrame(self.tab_key_manage, text="卡密管理")
|
||
frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
|
||
|
||
# 搜索区域
|
||
search_frame = ttk.Frame(frame)
|
||
search_frame.pack(fill=tk.X, padx=10, pady=5)
|
||
|
||
ttk.Label(search_frame, text="搜索卡密:").pack(side=tk.LEFT, padx=5)
|
||
self.entry_key_search = ttk.Entry(search_frame)
|
||
self.entry_key_search.pack(side=tk.LEFT, fill=tk.X, expand=True, padx=5)
|
||
self.btn_search_keys = ttk.Button(search_frame, text="搜索", command=self.search_keys)
|
||
self.btn_search_keys.pack(side=tk.LEFT, padx=5)
|
||
self.btn_refresh_keys = ttk.Button(search_frame, text="刷新", command=self.load_all_keys)
|
||
self.btn_refresh_keys.pack(side=tk.LEFT, padx=5)
|
||
|
||
# 卡密列表
|
||
columns = ("id", "key_code", "machine_code", "start_time", "end_time", "status", "created_at")
|
||
self.tree_keys = ttk.Treeview(frame, columns=columns, show="headings")
|
||
|
||
# 设置列标题
|
||
self.tree_keys.heading("id", text="ID")
|
||
self.tree_keys.heading("key_code", text="卡密")
|
||
self.tree_keys.heading("machine_code", text="机器码")
|
||
self.tree_keys.heading("start_time", text="开始时间")
|
||
self.tree_keys.heading("end_time", text="结束时间")
|
||
self.tree_keys.heading("status", text="状态")
|
||
self.tree_keys.heading("created_at", text="创建时间")
|
||
|
||
# 设置列宽
|
||
self.tree_keys.column("id", width=50)
|
||
self.tree_keys.column("key_code", width=150)
|
||
self.tree_keys.column("machine_code", width=120)
|
||
self.tree_keys.column("start_time", width=120)
|
||
self.tree_keys.column("end_time", width=120)
|
||
self.tree_keys.column("status", width=80)
|
||
self.tree_keys.column("created_at", width=120)
|
||
|
||
# 添加滚动条
|
||
scrollbar = ttk.Scrollbar(frame, orient=tk.VERTICAL, command=self.tree_keys.yview)
|
||
self.tree_keys.configure(yscroll=scrollbar.set)
|
||
|
||
self.tree_keys.pack(side=tk.LEFT, fill=tk.BOTH, expand=True, padx=10, pady=5)
|
||
scrollbar.pack(side=tk.RIGHT, fill=tk.Y, pady=5)
|
||
|
||
# 操作按钮
|
||
button_frame = ttk.Frame(frame)
|
||
button_frame.pack(fill=tk.X, padx=10, pady=10)
|
||
|
||
self.btn_ban_key = ttk.Button(button_frame, text="封禁选中卡密", command=self.ban_selected_key)
|
||
self.btn_ban_key.pack(side=tk.LEFT, padx=5)
|
||
|
||
self.btn_unban_key = ttk.Button(button_frame, text="解封选中卡密", command=self.unban_selected_key)
|
||
self.btn_unban_key.pack(side=tk.LEFT, padx=5)
|
||
|
||
self.btn_release_key = ttk.Button(button_frame, text="释放选中卡密", command=self.release_selected_key)
|
||
self.btn_release_key.pack(side=tk.LEFT, padx=5)
|
||
|
||
self.btn_delete_key = ttk.Button(button_frame, text="删除选中卡密", command=self.delete_selected_key)
|
||
self.btn_delete_key.pack(side=tk.LEFT, padx=5)
|
||
# ✅ 新增:解绑卡密按钮
|
||
self.btn_unbind = ttk.Button(button_frame, text="解绑卡密", command=self.unbind_selected_key)
|
||
self.btn_unbind.pack(side=tk.LEFT, padx=5)
|
||
|
||
# 数据库相关方法
|
||
def log(self, text, widget=None):
|
||
"""添加日志信息"""
|
||
if not widget:
|
||
widget = self.text_db_log
|
||
|
||
widget.config(state=tk.NORMAL)
|
||
widget.insert(tk.END, text + "\n")
|
||
widget.see(tk.END)
|
||
widget.config(state=tk.DISABLED)
|
||
self.update_idletasks()
|
||
|
||
def connect_db(self):
|
||
"""连接到数据库"""
|
||
self.db_config['host'] = self.entry_db_host.get()
|
||
self.db_config['database'] = self.entry_db_name.get()
|
||
self.db_config['user'] = self.entry_db_user.get()
|
||
self.db_config['password'] = self.entry_db_password.get()
|
||
|
||
self.log(f"尝试连接到数据库: {self.db_config['host']}/{self.db_config['database']}")
|
||
|
||
self.db = LicenseDatabase(
|
||
self.db_config['host'],
|
||
self.db_config['database'],
|
||
self.db_config['user'],
|
||
self.db_config['password']
|
||
)
|
||
|
||
if self.db.connect():
|
||
self.label_db_status.config(text="已连接到数据库", foreground="green")
|
||
self.log("数据库连接成功")
|
||
messagebox.showinfo("成功", "数据库连接成功")
|
||
# 连接成功后加载卡密列表
|
||
self.load_all_keys()
|
||
else:
|
||
self.label_db_status.config(text="数据库连接失败", foreground="red")
|
||
self.log("数据库连接失败")
|
||
messagebox.showerror("错误", "无法连接到数据库,请检查配置")
|
||
|
||
def create_db_tables(self):
|
||
"""创建数据库表"""
|
||
if not self.db or not self.db.connection.is_connected():
|
||
if not self.connect_db():
|
||
return
|
||
|
||
self.log("尝试创建数据库表...")
|
||
if self.db.create_tables():
|
||
self.log("数据库表创建成功")
|
||
messagebox.showinfo("成功", "数据库表创建成功")
|
||
else:
|
||
self.log("数据库表创建失败")
|
||
messagebox.showerror("错误", "数据库表创建失败")
|
||
|
||
def save_db_config(self):
|
||
"""保存数据库配置"""
|
||
self.db_config['host'] = self.entry_db_host.get()
|
||
self.db_config['database'] = self.entry_db_name.get()
|
||
self.db_config['user'] = self.entry_db_user.get()
|
||
self.db_config['password'] = self.entry_db_password.get()
|
||
|
||
try:
|
||
with open('db_config.json', 'w') as f:
|
||
json.dump(self.db_config, f)
|
||
|
||
self.log("数据库配置保存成功")
|
||
messagebox.showinfo("成功", "数据库配置已保存")
|
||
except Exception as e:
|
||
self.log(f"保存配置失败: {str(e)}")
|
||
messagebox.showerror("错误", f"保存配置失败: {str(e)}")
|
||
|
||
def load_config(self):
|
||
"""加载保存的配置"""
|
||
try:
|
||
if os.path.exists('db_config.json'):
|
||
with open('db_config.json', 'r') as f:
|
||
config = json.load(f)
|
||
|
||
self.entry_db_host.insert(0, config.get('host', ''))
|
||
self.entry_db_name.insert(0, config.get('database', 'license_system'))
|
||
self.entry_db_user.insert(0, config.get('user', ''))
|
||
self.entry_db_password.insert(0, config.get('password', ''))
|
||
except Exception as e:
|
||
print(f"加载配置失败: {e}")
|
||
|
||
# 卡密生成相关方法
|
||
def generate_keys(self):
|
||
"""生成卡密"""
|
||
if not self.db or not self.db.connection.is_connected():
|
||
messagebox.showerror("错误", "请先连接数据库")
|
||
return
|
||
|
||
try:
|
||
days = int(self.entry_valid_days.get())
|
||
count = int(self.entry_key_count.get())
|
||
|
||
if days <= 0 or count <= 0:
|
||
messagebox.showerror("错误", "有效期和数量必须为正数")
|
||
return
|
||
|
||
self.text_keys.delete(1.0, tk.END)
|
||
self.log(f"开始生成 {count} 个有效期为 {days} 天的卡密...", self.text_keys)
|
||
|
||
keys = []
|
||
for i in range(count):
|
||
key = self.db.generate_key(days)
|
||
if key:
|
||
keys.append(key)
|
||
self.text_keys.insert(tk.END, key + "\n")
|
||
self.text_keys.see(tk.END)
|
||
self.update_idletasks()
|
||
|
||
self.log(f"\n成功生成 {len(keys)} 个卡密", self.text_keys)
|
||
messagebox.showinfo("成功", f"成功生成 {len(keys)} 个卡密")
|
||
# 刷新卡密列表
|
||
self.load_all_keys()
|
||
|
||
except ValueError:
|
||
messagebox.showerror("错误", "请输入有效的数字")
|
||
except Exception as e:
|
||
messagebox.showerror("错误", f"生成卡密失败: {str(e)}")
|
||
|
||
def copy_keys(self):
|
||
"""复制卡密到剪贴板"""
|
||
keys = self.text_keys.get(1.0, tk.END).strip()
|
||
if keys:
|
||
pyperclip.copy(keys)
|
||
messagebox.showinfo("成功", "卡密已复制到剪贴板")
|
||
else:
|
||
messagebox.showinfo("提示", "没有可复制的卡密")
|
||
|
||
def export_keys(self):
|
||
"""导出卡密到文件"""
|
||
keys = self.text_keys.get(1.0, tk.END).strip()
|
||
if not keys:
|
||
messagebox.showinfo("提示", "没有可导出的卡密")
|
||
return
|
||
|
||
file_path = filedialog.asksaveasfilename(
|
||
defaultextension=".txt",
|
||
filetypes=[("文本文件", "*.txt"), ("所有文件", "*.*")]
|
||
)
|
||
|
||
if file_path:
|
||
try:
|
||
with open(file_path, 'w') as f:
|
||
f.write(keys)
|
||
messagebox.showinfo("成功", f"卡密已导出到 {file_path}")
|
||
except Exception as e:
|
||
messagebox.showerror("错误", f"导出失败: {str(e)}")
|
||
|
||
# EXE加密相关方法
|
||
def browse_source_file(self):
|
||
"""浏览源文件"""
|
||
file_path = filedialog.askopenfilename(
|
||
filetypes=[("EXE文件", "*.exe"), ("所有文件", "*.*")]
|
||
)
|
||
if file_path:
|
||
self.entry_source_file.delete(0, tk.END)
|
||
self.entry_source_file.insert(0, file_path)
|
||
|
||
# 自动填充目标文件路径
|
||
dir_name, file_name = os.path.split(file_path)
|
||
name, ext = os.path.splitext(file_name)
|
||
dest_file = os.path.join(dir_name, f"{name}_encrypted{ext}")
|
||
self.entry_dest_file.delete(0, tk.END)
|
||
self.entry_dest_file.insert(0, dest_file)
|
||
|
||
# 自动填充验证器路径(使用新的validator_wrapper.py)
|
||
validator_path = os.path.join(os.path.dirname(__file__), "validator_wrapper.py")
|
||
self.entry_validator.delete(0, tk.END)
|
||
self.entry_validator.insert(0, validator_path)
|
||
|
||
def browse_dest_file(self):
|
||
"""浏览目标文件"""
|
||
file_path = filedialog.asksaveasfilename(
|
||
defaultextension=".exe",
|
||
filetypes=[("EXE文件", "*.exe"), ("文本文件", "*.py"), ("所有文件", "*.*")]
|
||
)
|
||
if file_path:
|
||
self.entry_dest_file.delete(0, tk.END)
|
||
self.entry_dest_file.insert(0, file_path)
|
||
|
||
def browse_validator(self):
|
||
"""浏览验证程序"""
|
||
file_path = filedialog.askopenfilename(
|
||
filetypes=[("Python程序", "*.*"), ("EXE文件", "*.exe"), ("所有文件", "*.*")]
|
||
)
|
||
if file_path:
|
||
self.entry_validator.delete(0, tk.END)
|
||
self.entry_validator.insert(0, file_path)
|
||
|
||
def encrypt_exe(self):
|
||
"""加密EXE文件"""
|
||
source_path = self.entry_source_file.get()
|
||
dest_path = self.entry_dest_file.get()
|
||
validator_path = self.entry_validator.get()
|
||
|
||
# 检查文件路径
|
||
if not source_path or not os.path.exists(source_path):
|
||
messagebox.showerror("错误", "请选择有效的源文件")
|
||
return
|
||
|
||
if not dest_path:
|
||
messagebox.showerror("错误", "请选择目标文件路径")
|
||
return
|
||
|
||
if not validator_path or not os.path.exists(validator_path):
|
||
messagebox.showerror("错误", "请选择有效的验证程序")
|
||
return
|
||
|
||
# 检查数据库连接
|
||
if not self.db or not self.db.connection.is_connected():
|
||
if not self.connect_db():
|
||
return
|
||
|
||
# 执行加密
|
||
self.log("开始加密文件...", self.text_encrypt_log)
|
||
self.log(f"源文件: {source_path}", self.text_encrypt_log)
|
||
|
||
try:
|
||
encryptor = EXEEncryptor()
|
||
success, msg = encryptor.encrypt_file(
|
||
source_path,
|
||
dest_path,
|
||
validator_path,
|
||
self.db_config
|
||
)
|
||
|
||
self.log(msg, self.text_encrypt_log)
|
||
|
||
if success:
|
||
self.log(f"加密后的文件已保存到: {dest_path}", self.text_encrypt_log)
|
||
messagebox.showinfo("成功", f"文件加密成功\n保存到: {dest_path}")
|
||
else:
|
||
messagebox.showerror("错误", msg)
|
||
|
||
except Exception as e:
|
||
error_msg = f"加密过程出错: {str(e)}"
|
||
self.log(error_msg, self.text_encrypt_log)
|
||
messagebox.showerror("错误", error_msg)
|
||
|
||
# 卡密管理相关方法
|
||
def load_all_keys(self):
|
||
"""加载所有卡密"""
|
||
if not self.db or not self.db.connection.is_connected():
|
||
return
|
||
|
||
# 清空现有列表
|
||
for item in self.tree_keys.get_children():
|
||
self.tree_keys.delete(item)
|
||
|
||
try:
|
||
keys = self.db.get_all_keys()
|
||
for key in keys:
|
||
# 格式化日期时间
|
||
start_time = key['start_time'].strftime("%Y-%m-%d") if key['start_time'] else ""
|
||
end_time = key['end_time'].strftime("%Y-%m-%d") if key['end_time'] else ""
|
||
created_at = key['created_at'].strftime("%Y-%m-%d") if key['created_at'] else ""
|
||
|
||
self.tree_keys.insert("", tk.END, values=(
|
||
key['id'],
|
||
key['key_code'],
|
||
key['machine_code'] or "",
|
||
start_time,
|
||
end_time,
|
||
key['status'],
|
||
created_at
|
||
))
|
||
|
||
# 根据状态设置行颜色
|
||
item = self.tree_keys.get_children()[-1]
|
||
if key['status'] == 'active':
|
||
self.tree_keys.item(item, tags=('active',))
|
||
elif key['status'] == 'expired':
|
||
self.tree_keys.item(item, tags=('expired',))
|
||
elif key['status'] == 'banned':
|
||
self.tree_keys.item(item, tags=('banned',))
|
||
|
||
# 设置标签样式
|
||
self.tree_keys.tag_configure('active', foreground='green')
|
||
self.tree_keys.tag_configure('expired', foreground='gray')
|
||
self.tree_keys.tag_configure('banned', foreground='red')
|
||
|
||
except Exception as e:
|
||
print(f"加载卡密列表失败: {e}")
|
||
|
||
def search_keys(self):
|
||
"""搜索卡密"""
|
||
if not self.db or not self.db.connection.is_connected():
|
||
return
|
||
|
||
search_text = self.entry_key_search.get().strip().lower()
|
||
if not search_text:
|
||
self.load_all_keys()
|
||
return
|
||
|
||
# 清空现有列表
|
||
for item in self.tree_keys.get_children():
|
||
self.tree_keys.delete(item)
|
||
|
||
try:
|
||
keys = self.db.get_all_keys()
|
||
for key in keys:
|
||
# 检查是否匹配搜索文本
|
||
if (search_text in key['key_code'].lower() or
|
||
search_text in key['status'].lower() or
|
||
(key['machine_code'] and search_text in key['machine_code'].lower())):
|
||
# 格式化日期时间
|
||
start_time = key['start_time'].strftime("%Y-%m-%d") if key['start_time'] else ""
|
||
end_time = key['end_time'].strftime("%Y-%m-%d") if key['end_time'] else ""
|
||
created_at = key['created_at'].strftime("%Y-%m-%d") if key['created_at'] else ""
|
||
|
||
self.tree_keys.insert("", tk.END, values=(
|
||
key['id'],
|
||
key['key_code'],
|
||
key['machine_code'] or "",
|
||
start_time,
|
||
end_time,
|
||
key['status'],
|
||
created_at
|
||
))
|
||
|
||
except Exception as e:
|
||
print(f"搜索卡密失败: {e}")
|
||
|
||
def get_selected_key_code(self):
|
||
"""获取选中的卡密"""
|
||
selected_items = self.tree_keys.selection()
|
||
if not selected_items:
|
||
messagebox.showinfo("提示", "请先选择一个卡密")
|
||
return None
|
||
|
||
item = selected_items[0]
|
||
key_code = self.tree_keys.item(item, "values")[1]
|
||
return key_code
|
||
|
||
def ban_selected_key(self):
|
||
"""封禁选中的卡密"""
|
||
key_code = self.get_selected_key_code()
|
||
if not key_code:
|
||
return
|
||
|
||
if messagebox.askyesno("确认", f"确定要封禁卡密 {key_code} 吗?"):
|
||
if self.db.update_key_status(key_code, 'banned'):
|
||
messagebox.showinfo("成功", "卡密已封禁")
|
||
self.load_all_keys()
|
||
else:
|
||
messagebox.showerror("错误", "封禁卡密失败")
|
||
|
||
def unban_selected_key(self):
|
||
"""解封选中的卡密"""
|
||
key_code = self.get_selected_key_code()
|
||
if not key_code:
|
||
return
|
||
|
||
if messagebox.askyesno("确认", f"确定要解封卡密 {key_code} 吗?"):
|
||
# 检查原状态是未使用还是已激活
|
||
try:
|
||
selected_items = self.tree_keys.selection()
|
||
item = selected_items[0]
|
||
original_status = self.tree_keys.item(item, "values")[5]
|
||
|
||
new_status = 'unused' if original_status == 'banned' and not self.tree_keys.item(item, "values")[
|
||
2] else 'active'
|
||
|
||
if self.db.update_key_status(key_code, new_status):
|
||
messagebox.showinfo("成功", "卡密已解封")
|
||
self.load_all_keys()
|
||
else:
|
||
messagebox.showerror("错误", "解封卡密失败")
|
||
except Exception as e:
|
||
messagebox.showerror("错误", f"操作失败: {str(e)}")
|
||
|
||
def release_selected_key(self):
|
||
"""释放选中的已使用激活码"""
|
||
key_code = self.get_selected_key_code()
|
||
if not key_code:
|
||
return
|
||
|
||
# 获取选择项的状态信息
|
||
selected_items = self.tree_keys.selection()
|
||
if selected_items:
|
||
item = selected_items[0]
|
||
status = self.tree_keys.item(item, "values")[5]
|
||
|
||
if status != 'active':
|
||
messagebox.showwarning("警告", "只能释放处于'激活'状态的激活码")
|
||
return
|
||
|
||
if messagebox.askyesno("确认释放",
|
||
f"确定要释放激活码 '{key_code}' 吗?\n\n释放后:\n1. 该激活码将变为未使用状态\n2. 机器码将被清空\n3. 可以重新在任何机器上使用\n\n此操作不可撤销!"):
|
||
if not self.db or not self.db.connection.is_connected():
|
||
if not self.connect_db():
|
||
return
|
||
|
||
success, msg = self.db.release_key(key_code)
|
||
if success:
|
||
messagebox.showinfo("成功", f"激活码 '{key_code}' 已释放成功\n{msg}")
|
||
self.load_all_keys() # 刷新列表
|
||
else:
|
||
messagebox.showerror("失败", msg)
|
||
|
||
def delete_selected_key(self):
|
||
"""删除选中的卡密"""
|
||
key_code = self.get_selected_key_code()
|
||
if not key_code:
|
||
return
|
||
|
||
if messagebox.askyesno("确认", f"确定要删除卡密 {key_code} 吗?\n此操作不可恢复!"):
|
||
# 实际项目中应该实现delete_key方法
|
||
messagebox.showinfo("提示", "为安全起见,当前版本不允许删除激活码,建议使用封禁或释放功能")
|
||
|
||
|
||
if __name__ == "__main__":
|
||
app = EXEEncryptionTool()
|
||
app.mainloop() |