255 lines
9.5 KiB
Python
255 lines
9.5 KiB
Python
|
|
import mysql.connector
|
|||
|
|
from mysql.connector import Error
|
|||
|
|
import uuid
|
|||
|
|
from datetime import datetime, timedelta
|
|||
|
|
import hashlib
|
|||
|
|
import os
|
|||
|
|
|
|||
|
|
|
|||
|
|
class LicenseDatabase:
|
|||
|
|
def __init__(self, host=None, database=None, user=None, password=None):
|
|||
|
|
self.host = host or os.environ.get('DB_HOST', 'taiyiagi.xyz')
|
|||
|
|
self.database = database or os.environ.get('DB_NAME', 'filesend')
|
|||
|
|
self.user = user or os.environ.get('DB_USER', 'taiyi')
|
|||
|
|
self.password = password or os.environ.get('DB_PASSWORD', 'taiyi1224')
|
|||
|
|
self.connection = None
|
|||
|
|
|
|||
|
|
def connect(self):
|
|||
|
|
"""连接到数据库"""
|
|||
|
|
try:
|
|||
|
|
self.connection = mysql.connector.connect(
|
|||
|
|
host=self.host,
|
|||
|
|
database=self.database,
|
|||
|
|
user=self.user,
|
|||
|
|
password=self.password
|
|||
|
|
)
|
|||
|
|
if self.connection.is_connected():
|
|||
|
|
return True
|
|||
|
|
return False
|
|||
|
|
except Error as e:
|
|||
|
|
print(f"数据库连接错误: {e}")
|
|||
|
|
return False
|
|||
|
|
|
|||
|
|
def create_tables(self):
|
|||
|
|
"""创建必要的数据库表"""
|
|||
|
|
if not self.connection or not self.connection.is_connected():
|
|||
|
|
if not self.connect():
|
|||
|
|
return False
|
|||
|
|
|
|||
|
|
try:
|
|||
|
|
cursor = self.connection.cursor()
|
|||
|
|
|
|||
|
|
# 创建卡密表
|
|||
|
|
cursor.execute('''
|
|||
|
|
CREATE TABLE IF NOT EXISTS license_keys (
|
|||
|
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
|||
|
|
key_code VARCHAR(50) NOT NULL UNIQUE,
|
|||
|
|
machine_code VARCHAR(100) DEFAULT NULL,
|
|||
|
|
start_time DATETIME DEFAULT NULL,
|
|||
|
|
end_time DATETIME NOT NULL,
|
|||
|
|
status ENUM('unused', 'active', 'expired', 'banned') DEFAULT 'unused',
|
|||
|
|
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
|||
|
|
)
|
|||
|
|
''')
|
|||
|
|
|
|||
|
|
self.connection.commit()
|
|||
|
|
cursor.close()
|
|||
|
|
return True
|
|||
|
|
except Error as e:
|
|||
|
|
print(f"创建表错误: {e}")
|
|||
|
|
return False
|
|||
|
|
|
|||
|
|
def generate_key(self, days_valid):
|
|||
|
|
"""生成一个新的卡密并保存到数据库"""
|
|||
|
|
if not self.connection or not self.connection.is_connected():
|
|||
|
|
if not self.connect():
|
|||
|
|
return None
|
|||
|
|
|
|||
|
|
try:
|
|||
|
|
# 生成UUID作为基础,然后进行哈希处理
|
|||
|
|
key_uuid = uuid.uuid4().hex
|
|||
|
|
hash_obj = hashlib.sha256(key_uuid.encode())
|
|||
|
|
# 取前20个字符作为卡密
|
|||
|
|
key_code = hash_obj.hexdigest()[:20].upper()
|
|||
|
|
|
|||
|
|
# 格式化卡密,每5个字符一组
|
|||
|
|
formatted_key = '-'.join([key_code[i:i + 5] for i in range(0, len(key_code), 5)])
|
|||
|
|
|
|||
|
|
# 计算过期时间
|
|||
|
|
end_time = datetime.now() + timedelta(days=days_valid)
|
|||
|
|
|
|||
|
|
cursor = self.connection.cursor()
|
|||
|
|
query = """
|
|||
|
|
INSERT INTO license_keys (key_code, end_time)
|
|||
|
|
VALUES (%s, %s)
|
|||
|
|
"""
|
|||
|
|
cursor.execute(query, (formatted_key, end_time))
|
|||
|
|
self.connection.commit()
|
|||
|
|
cursor.close()
|
|||
|
|
|
|||
|
|
return formatted_key
|
|||
|
|
except Error as e:
|
|||
|
|
print(f"生成卡密错误: {e}")
|
|||
|
|
return None
|
|||
|
|
|
|||
|
|
def validate_key(self, key_code, machine_code):
|
|||
|
|
"""验证卡密是否有效,并绑定机器码 - 严格一机一码"""
|
|||
|
|
if not self.connection or not self.connection.is_connected():
|
|||
|
|
if not self.connect():
|
|||
|
|
return False, "数据库连接失败"
|
|||
|
|
|
|||
|
|
try:
|
|||
|
|
cursor = self.connection.cursor(dictionary=True)
|
|||
|
|
|
|||
|
|
# 查询卡密信息
|
|||
|
|
query = "SELECT * FROM license_keys WHERE key_code = %s"
|
|||
|
|
cursor.execute(query, (key_code,))
|
|||
|
|
key_info = cursor.fetchone()
|
|||
|
|
|
|||
|
|
if not key_info:
|
|||
|
|
cursor.close()
|
|||
|
|
return False, "无效的激活码"
|
|||
|
|
|
|||
|
|
# 检查卡密状态
|
|||
|
|
if key_info['status'] == 'banned':
|
|||
|
|
cursor.close()
|
|||
|
|
return False, "激活码已被封禁"
|
|||
|
|
|
|||
|
|
if key_info['status'] == 'expired':
|
|||
|
|
cursor.close()
|
|||
|
|
return False, "激活码已过期"
|
|||
|
|
|
|||
|
|
# 一机一码严格检查:每个激活码只能在一台机器上使用
|
|||
|
|
if key_info['status'] == 'active':
|
|||
|
|
if key_info['machine_code'] != machine_code:
|
|||
|
|
# 这个码已经用过了,不能再次使用
|
|||
|
|
cursor.close()
|
|||
|
|
return False, f"此激活码已在设备{key_info['machine_code'][:8]}...上使用,一个激活码只能在一台设备上使用一次"
|
|||
|
|
else:
|
|||
|
|
# 已经激活过这台机器,验证是否过期
|
|||
|
|
if datetime.now() > key_info['end_time']:
|
|||
|
|
update_query = "UPDATE license_keys SET status = 'expired' WHERE key_code = %s"
|
|||
|
|
cursor.execute(update_query, (key_code,))
|
|||
|
|
self.connection.commit()
|
|||
|
|
cursor.close()
|
|||
|
|
return False, "激活码已过期"
|
|||
|
|
else:
|
|||
|
|
cursor.close()
|
|||
|
|
return True, "此设备已激活,继续使用"
|
|||
|
|
|
|||
|
|
# 首次激活:验证通过后绑定到机器
|
|||
|
|
if key_info['status'] == 'unused':
|
|||
|
|
update_query = """
|
|||
|
|
UPDATE license_keys
|
|||
|
|
SET status = 'active', machine_code = %s, start_time = %s
|
|||
|
|
WHERE key_code = %s AND status = 'unused'
|
|||
|
|
"""
|
|||
|
|
cursor.execute(update_query, (machine_code, datetime.now(), key_code))
|
|||
|
|
rows_affected = cursor.rowcount
|
|||
|
|
self.connection.commit()
|
|||
|
|
|
|||
|
|
if rows_affected == 0:
|
|||
|
|
# 可能已经被其他并发操作激活
|
|||
|
|
cursor.close()
|
|||
|
|
return False, "激活码已被使用,请使用新的激活码"
|
|||
|
|
|
|||
|
|
# 再次检查是否过期(防止并发问题)
|
|||
|
|
final_check_query = "SELECT * FROM license_keys WHERE key_code = %s"
|
|||
|
|
cursor.execute(final_check_query, (key_code,))
|
|||
|
|
final_info = cursor.fetchone()
|
|||
|
|
|
|||
|
|
if final_info and datetime.now() > final_info['end_time']:
|
|||
|
|
update_query = "UPDATE license_keys SET status = 'expired' WHERE key_code = %s"
|
|||
|
|
cursor.execute(update_query, (key_code,))
|
|||
|
|
self.connection.commit()
|
|||
|
|
cursor.close()
|
|||
|
|
return False, "激活码已过期"
|
|||
|
|
|
|||
|
|
cursor.close()
|
|||
|
|
return True, "激活成功"
|
|||
|
|
|
|||
|
|
except Error as e:
|
|||
|
|
print(f"验证激活码错误: {e}")
|
|||
|
|
return False, f"验证过程出错: {str(e)}"
|
|||
|
|
|
|||
|
|
def get_all_keys(self):
|
|||
|
|
"""获取所有卡密信息"""
|
|||
|
|
if not self.connection or not self.connection.is_connected():
|
|||
|
|
if not self.connect():
|
|||
|
|
return []
|
|||
|
|
|
|||
|
|
try:
|
|||
|
|
cursor = self.connection.cursor(dictionary=True)
|
|||
|
|
query = "SELECT * FROM license_keys ORDER BY created_at DESC"
|
|||
|
|
cursor.execute(query)
|
|||
|
|
keys = cursor.fetchall()
|
|||
|
|
cursor.close()
|
|||
|
|
return keys
|
|||
|
|
except Error as e:
|
|||
|
|
print(f"获取卡密列表错误: {e}")
|
|||
|
|
return []
|
|||
|
|
|
|||
|
|
def update_key_status(self, key_code, status):
|
|||
|
|
"""更新卡密状态"""
|
|||
|
|
if not self.connection or not self.connection.is_connected():
|
|||
|
|
if not self.connect():
|
|||
|
|
return False
|
|||
|
|
|
|||
|
|
try:
|
|||
|
|
cursor = self.connection.cursor()
|
|||
|
|
query = "UPDATE license_keys SET status = %s WHERE key_code = %s"
|
|||
|
|
cursor.execute(query, (status, key_code))
|
|||
|
|
self.connection.commit()
|
|||
|
|
cursor.close()
|
|||
|
|
return True
|
|||
|
|
except Error as e:
|
|||
|
|
print(f"更新卡密状态错误: {e}")
|
|||
|
|
return False
|
|||
|
|
|
|||
|
|
def release_key(self, key_code):
|
|||
|
|
"""释放已使用的激活码 - 将其重置为未使用状态,清空机器码"""
|
|||
|
|
if not self.connection or not self.connection.is_connected():
|
|||
|
|
if not self.connect():
|
|||
|
|
return False, "数据库连接失败"
|
|||
|
|
|
|||
|
|
try:
|
|||
|
|
cursor = self.connection.cursor(dictionary=True)
|
|||
|
|
|
|||
|
|
# 检查卡密是否存在且处于已激活状态
|
|||
|
|
check_query = "SELECT * FROM license_keys WHERE key_code = %s"
|
|||
|
|
cursor.execute(check_query, (key_code,))
|
|||
|
|
key_info = cursor.fetchone()
|
|||
|
|
|
|||
|
|
if not key_info:
|
|||
|
|
cursor.close()
|
|||
|
|
return False, "激活码不存在"
|
|||
|
|
|
|||
|
|
if key_info['status'] != 'active':
|
|||
|
|
cursor.close()
|
|||
|
|
return False, f"激活码处于 {key_info['status']} 状态,只能释放已使用的激活码"
|
|||
|
|
|
|||
|
|
# 释放激活码:重置为未使用状态,清空机器码和开始时间
|
|||
|
|
release_query = """
|
|||
|
|
UPDATE license_keys
|
|||
|
|
SET status = 'unused', machine_code = NULL, start_time = NULL
|
|||
|
|
WHERE key_code = %s
|
|||
|
|
"""
|
|||
|
|
cursor.execute(release_query, (key_code,))
|
|||
|
|
rows_affected = cursor.rowcount
|
|||
|
|
self.connection.commit()
|
|||
|
|
cursor.close()
|
|||
|
|
|
|||
|
|
if rows_affected > 0:
|
|||
|
|
return True, "激活码已释放,可以重新使用"
|
|||
|
|
else:
|
|||
|
|
return False, "释放激活码失败"
|
|||
|
|
|
|||
|
|
except Error as e:
|
|||
|
|
print(f"释放激活码错误: {e}")
|
|||
|
|
return False, f"释放过程出错: {str(e)}"
|
|||
|
|
|
|||
|
|
def close(self):
|
|||
|
|
"""关闭数据库连接"""
|
|||
|
|
if self.connection and self.connection.is_connected():
|
|||
|
|
self.connection.close()
|