| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142 |
- #!/usr/bin/env python3
- # -*- coding: utf-8 -*-
- """
- License 验证模块
- """
- import sys
- import json
- import base64
- import os
- from datetime import datetime
- from pathlib import Path
- try:
- from cryptography.hazmat.primitives import hashes, serialization
- from cryptography.hazmat.primitives.asymmetric import padding
- from cryptography.hazmat.backends import default_backend
- from cryptography.exceptions import InvalidSignature
- except ImportError:
- print("错误: 缺少 cryptography 库")
- sys.exit(1)
- PRODUCT_NAME = "laser_cal"
- def _get_base_dir():
- """获取程序基础目录"""
- if getattr(sys, 'frozen', False) or '__compiled__' in dir():
- # 如果是被打包的程序,寻找当前执行路径的目录
- return Path(sys.executable).parent
- # 开发环境下,如果是从共享库加载,__file__ 指向当前文件
- return Path(__file__).parent
- def _find_file(filename):
- """在可能的位置查找文件"""
- # 1. 尝试当前执行文件目录
- base = _get_base_dir()
- if (base / filename).exists():
- return base / filename
-
- # 2. 尝试当前工作目录
- cwd = Path.cwd()
- if (cwd / filename).exists():
- return cwd / filename
-
- # 3. 尝试开发环境下的 dist/license 目录
- dev_path = Path(__file__).parent / "dist" / "license" / filename
- if dev_path.exists():
- return dev_path
-
- return None
- def verify_license(verbose=False):
- """验证 License 文件"""
- license_path = _find_file("license.lic")
- pubkey_path = _find_file("public_key.pem")
- if not license_path:
- if verbose:
- print(f"[授权错误] License 文件 (license.lic) 不存在")
- return False
- if not pubkey_path:
- if verbose:
- print(f"[授权错误] 公钥文件 (public_key.pem) 不存在")
- return False
- try:
- license_content = json.loads(license_path.read_text(encoding="utf-8"))
- license_data = license_content["license_data"]
- signature_b64 = license_content["signature"]
- except (json.JSONDecodeError, KeyError):
- if verbose:
- print("[授权错误] License 文件格式无效")
- return False
- try:
- public_key = serialization.load_pem_public_key(
- pubkey_path.read_bytes(), backend=default_backend()
- )
- except Exception:
- if verbose:
- print("[授权错误] 公钥加载失败")
- return False
- # 验证 RSA 签名
- try:
- license_json = json.dumps(license_data, sort_keys=True, ensure_ascii=False)
- signature = base64.b64decode(signature_b64)
- public_key.verify(
- signature, license_json.encode("utf-8"), padding.PKCS1v15(), hashes.SHA256()
- )
- except InvalidSignature:
- if verbose:
- print("[授权错误] License 签名验证失败,文件可能被篡改")
- return False
- except Exception:
- if verbose:
- print("[授权错误] 签名验证过程出错")
- return False
- # 检查过期日期
- expire_str = license_data.get("expire_date", "")
- if expire_str.lower() != "never":
- try:
- expire_date = datetime.strptime(expire_str, "%Y-%m-%d")
- if datetime.now() > expire_date:
- if verbose:
- print(f"[授权错误] License 已过期: {expire_str}")
- return False
- except ValueError:
- if verbose:
- print("[授权错误] 过期日期格式无效")
- return False
- # 检查产品名
- if license_data.get("product", "") != PRODUCT_NAME:
- if verbose:
- print("[授权错误] License 产品不匹配")
- return False
- if verbose:
- print(f"[授权验证] 通过 | {license_data.get('licensee')} | 过期: {expire_str}")
- return True
- def get_license_info():
- """获取 License 信息"""
- license_path = _find_file("license.lic")
- if not license_path:
- return {}
- try:
- content = json.loads(license_path.read_text(encoding="utf-8"))
- return content.get("license_data", {})
- except Exception:
- return {}
- if __name__ == "__main__":
- verify_license(verbose=True)
|