Exeprotector/main.py

751 lines
30 KiB
Python
Raw Normal View History

2025-09-05 11:52:53 +08:00
"""
作者太一
微信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()