registration.py 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  1. import json
  2. import base64
  3. import hashlib
  4. from datetime import datetime
  5. from Crypto.Cipher import AES
  6. from Crypto.Util.Padding import pad, unpad
  7. import os
  8. import sys
  9. from typing import Tuple, Optional, Dict
  10. class RegistrationValidator:
  11. def __init__(self, secret_key: str):
  12. """
  13. 初始化注册验证器
  14. Args:
  15. secret_key: 密钥(必须与生成时相同)
  16. """
  17. if len(secret_key) not in [16, 24, 32]:
  18. # 自动调整密钥长度
  19. if len(secret_key) < 16:
  20. secret_key = secret_key.ljust(16, "0")
  21. elif len(secret_key) < 24:
  22. secret_key = secret_key.ljust(24, "0")
  23. elif len(secret_key) < 32:
  24. secret_key = secret_key.ljust(32, "0")
  25. else:
  26. secret_key = secret_key[:32]
  27. self.secret_key = secret_key.encode("utf-8")
  28. def _get_cipher(self, iv=None):
  29. """获取AES加密对象"""
  30. if iv is None:
  31. # 使用密钥的前16字节作为固定IV
  32. iv = hashlib.md5(self.secret_key).digest()[:16]
  33. return AES.new(self.secret_key, AES.MODE_CBC, iv)
  34. def decrypt_registration(self, registration_code: str) -> Optional[Dict]:
  35. """
  36. 解密注册码
  37. Returns:
  38. 注册信息字典,解密失败返回None
  39. """
  40. try:
  41. # Base64解码
  42. encrypted = base64.urlsafe_b64decode(registration_code.encode("utf-8"))
  43. # AES解密
  44. cipher = self._get_cipher()
  45. decrypted = unpad(cipher.decrypt(encrypted), AES.block_size)
  46. # JSON解析
  47. reg_data = json.loads(decrypted.decode("utf-8"))
  48. return reg_data
  49. except Exception as e:
  50. print(f"解密注册码失败: {e}")
  51. return None
  52. def validate(self, device_id: str, registration_code: str) -> Tuple[bool, str]:
  53. """
  54. 验证注册码
  55. Args:
  56. device_id: 当前设备特征码
  57. registration_code: 注册码
  58. Returns:
  59. (是否有效, 消息)
  60. """
  61. if not registration_code or registration_code.strip() == "":
  62. return False, "未提供注册码"
  63. # 解密注册码
  64. reg_info = self.decrypt_registration(registration_code)
  65. if not reg_info:
  66. return False, "注册码无效或已损坏"
  67. # 检查设备ID
  68. reg_device_id = reg_info.get("device_id", "")
  69. if reg_device_id != device_id:
  70. return (
  71. False,
  72. f"设备不匹配。注册设备: {reg_device_id},当前设备: {device_id}",
  73. )
  74. # 检查有效期
  75. expire_date_str = reg_info.get("expire_date", "")
  76. if not expire_date_str:
  77. return False, "注册信息不完整(缺少有效期)"
  78. try:
  79. expire_date = datetime.strptime(expire_date_str, "%Y-%m-%d").date()
  80. current_date = datetime.now().date()
  81. if current_date > expire_date:
  82. days_overdue = (current_date - expire_date).days
  83. return (
  84. False,
  85. f"注册已过期 {days_overdue} 天!有效期至: {expire_date_str}",
  86. )
  87. # 计算剩余天数
  88. days_left = (expire_date - current_date).days
  89. if days_left <= 7:
  90. return (
  91. True,
  92. f"注册有效({days_left}天后到期)有效期至: {expire_date_str}",
  93. )
  94. elif days_left <= 30:
  95. return True, f"注册有效(剩余{days_left}天)有效期至: {expire_date_str}"
  96. else:
  97. return True, f"注册有效,有效期至: {expire_date_str}"
  98. except ValueError as e:
  99. return False, f"日期格式错误: {str(e)}"
  100. def check_registration_required() -> bool:
  101. """
  102. 检查是否需要注册验证
  103. 可以通过环境变量控制是否启用注册验证
  104. """
  105. return os.getenv("REGISTRATION_REQUIRED", "true").lower() == "true"
  106. def get_registration_code() -> str:
  107. """
  108. 获取注册码
  109. 优先级:
  110. 1. 环境变量 REGISTRATION_CODE(取消)
  111. 2. 配置文件 .registration
  112. 3. 当前目录的 registration.txt
  113. """
  114. # # 从环境变量获取
  115. # reg_code = os.getenv("REGISTRATION_CODE", "").strip()
  116. # if reg_code:
  117. # return reg_code
  118. current_file_dir = os.path.dirname(os.path.abspath(__file__)) # utils目录
  119. project_root = os.path.dirname(current_file_dir) # 项目根目录
  120. # 配置文件列表
  121. config_files = [
  122. os.path.join(project_root, ".registration"),
  123. os.path.join(project_root, "registration.txt"),
  124. os.path.join(project_root, "config", "registration.txt"),
  125. # 保留当前目录作为备用
  126. ".registration",
  127. "registration.txt",
  128. ]
  129. for config_file in config_files:
  130. if os.path.exists(config_file):
  131. try:
  132. with open(config_file, "r") as f:
  133. for line in f:
  134. if line.startswith("REGISTRATION_CODE="):
  135. return line.strip().split("=", 1)[1]
  136. elif (
  137. not line.startswith("#")
  138. and "=" not in line
  139. and len(line.strip()) > 20
  140. ):
  141. # 可能是单独的注册码
  142. return line.strip()
  143. except:
  144. continue
  145. return ""
  146. def validate_registration(
  147. secret_key: str, device_id_func=None
  148. ) -> Tuple[bool, str, Optional[Dict]]:
  149. """
  150. 验证注册的主函数
  151. Args:
  152. secret_key: 密钥
  153. device_id_func: 获取设备ID的函数,默认为导入device_id模块
  154. Returns:
  155. (是否通过, 消息, 注册信息)
  156. """
  157. # 如果不要求注册验证,直接通过
  158. if not check_registration_required():
  159. return True, "注册验证已禁用", None
  160. # 获取设备ID函数
  161. if device_id_func is None:
  162. try:
  163. from device_id import get_device_id
  164. device_id_func = get_device_id
  165. except ImportError:
  166. # 如果在同一文件中定义了get_device_id
  167. from device_id import get_device_id as device_id_func
  168. # 获取当前设备ID
  169. try:
  170. current_device_id = device_id_func()
  171. except Exception as e:
  172. return False, f"获取设备特征码失败: {e}", None
  173. # 获取注册码
  174. registration_code = get_registration_code()
  175. if not registration_code:
  176. return (
  177. False,
  178. "未找到注册码。本机特征码为: {current_device_id},请申请注册并设置REGISTRATION_CODE环境变量或创建注册文件。",
  179. None,
  180. )
  181. # 创建验证器并验证
  182. validator = RegistrationValidator(secret_key)
  183. # 解密注册信息
  184. reg_info = validator.decrypt_registration(registration_code)
  185. if not reg_info:
  186. return False, "注册码无效或已损坏", None
  187. # 验证
  188. is_valid, message = validator.validate(current_device_id, registration_code)
  189. return is_valid, message, reg_info
  190. # 使用示例
  191. if __name__ == "__main__":
  192. # 测试验证
  193. secret_key = "ialwayslovelongjoe"
  194. from device_id import get_device_id
  195. is_valid, message, reg_info = validate_registration(secret_key, get_device_id)
  196. print(f"验证结果: {is_valid}")
  197. print(f"消息: {message}")
  198. if reg_info:
  199. print(f"注册信息: {reg_info}")