拍视频版本
This commit is contained in:
409
tools/cpu_id.py
Normal file
409
tools/cpu_id.py
Normal file
@@ -0,0 +1,409 @@
|
||||
# client.py - RK3588板端激活程序(永久有效)
|
||||
import os
|
||||
import sys
|
||||
import json
|
||||
import hashlib
|
||||
import hmac
|
||||
import requests
|
||||
import subprocess
|
||||
import time
|
||||
import logging
|
||||
import argparse
|
||||
from datetime import datetime
|
||||
|
||||
# 配置日志
|
||||
logging.basicConfig(
|
||||
level=logging.INFO,
|
||||
format='%(asctime)s - %(levelname)s - %(message)s'
|
||||
)
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# 配置
|
||||
CONFIG = {
|
||||
'SERVER_URL': 'http://129.211.170.245:5000/', # 修改为实际服务器地址
|
||||
'KEY_FILE': '/etc/device.key', # 密钥文件存储路径
|
||||
'KEY_BACKUP_FILE': '/etc/device.key.bak', # 密钥备份文件
|
||||
'CHIP_ID_SOURCES': [
|
||||
'/sys/devices/soc0/serial_number',
|
||||
'/sys/devices/platform/ff650000.serial/serial0',
|
||||
'/proc/cpuinfo'
|
||||
],
|
||||
'ACTIVATE_URL': '/activate',
|
||||
'VERIFY_URL': '/verify',
|
||||
'ACTIVATE_RETRY_COUNT': 3,
|
||||
'SECRET_KEY': '69588cc5e1b701942cda09b33de5a95c02471f3aaaf610d80aaf5681f4b166e4' # 必须和服务端一致
|
||||
}
|
||||
|
||||
|
||||
def get_chip_id():
|
||||
"""
|
||||
获取RK3588芯片ID(增强版)
|
||||
"""
|
||||
# 方法1: 从多个系统文件读取
|
||||
for source in CONFIG['CHIP_ID_SOURCES']:
|
||||
try:
|
||||
if os.path.exists(source):
|
||||
with open(source, 'r') as f:
|
||||
content = f.read().strip()
|
||||
|
||||
# 处理cpuinfo的特殊格式
|
||||
if source == '/proc/cpuinfo':
|
||||
for line in content.split('\n'):
|
||||
if 'Serial' in line:
|
||||
chip_id = line.split(':')[1].strip()
|
||||
if chip_id:
|
||||
logger.info(f"从{source}获取芯片ID: {chip_id}")
|
||||
return chip_id
|
||||
else:
|
||||
if content:
|
||||
logger.info(f"从{source}获取芯片ID: {content}")
|
||||
return content
|
||||
except Exception as e:
|
||||
logger.warning(f"读取{source}失败: {e}")
|
||||
|
||||
# 方法2: 使用dmidecode命令
|
||||
try:
|
||||
result = subprocess.run(
|
||||
['dmidecode', '-s', 'system-serial-number'],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
timeout=5
|
||||
)
|
||||
if result.returncode == 0 and result.stdout.strip():
|
||||
chip_id = result.stdout.strip()
|
||||
logger.info(f"从dmidecode获取芯片ID: {chip_id}")
|
||||
return chip_id
|
||||
except Exception as e:
|
||||
logger.warning(f"执行dmidecode失败: {e}")
|
||||
|
||||
# 方法3: 读取MAC地址
|
||||
try:
|
||||
import uuid
|
||||
mac = uuid.UUID(int=uuid.getnode()).hex[-12:]
|
||||
chip_id = f"MAC-{mac}"
|
||||
logger.warning(f"使用MAC地址生成ID: {chip_id}")
|
||||
return chip_id
|
||||
except Exception as e:
|
||||
logger.error(f"无法获取任何标识: {e}")
|
||||
return None
|
||||
|
||||
|
||||
def verify_key_signature(chip_id, key_data):
|
||||
"""
|
||||
验证密钥签名(永久有效)
|
||||
"""
|
||||
try:
|
||||
# 构建待签名数据
|
||||
data_to_sign = f"{chip_id}|{key_data['activation_id']}|{key_data['activate_time']}"
|
||||
|
||||
# 计算期望的签名
|
||||
expected_signature = hmac.new(
|
||||
CONFIG['SECRET_KEY'].encode('utf-8'),
|
||||
data_to_sign.encode('utf-8'),
|
||||
hashlib.sha256
|
||||
).hexdigest()
|
||||
|
||||
# 比对签名
|
||||
if key_data['signature'] != expected_signature:
|
||||
logger.error("密钥签名验证失败")
|
||||
return False, "密钥签名无效"
|
||||
|
||||
logger.info("密钥签名验证通过")
|
||||
return True, "签名验证通过"
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"签名验证异常: {e}")
|
||||
return False, f"验证异常: {str(e)}"
|
||||
|
||||
|
||||
def save_key_file(key_data):
|
||||
"""
|
||||
保存密钥文件到本地(永久有效)
|
||||
"""
|
||||
try:
|
||||
# 确保目录存在
|
||||
key_dir = os.path.dirname(CONFIG['KEY_FILE'])
|
||||
if key_dir and not os.path.exists(key_dir):
|
||||
os.makedirs(key_dir, exist_ok=True)
|
||||
|
||||
# 如果已有密钥文件,先备份
|
||||
if os.path.exists(CONFIG['KEY_FILE']):
|
||||
import shutil
|
||||
shutil.copy2(CONFIG['KEY_FILE'], CONFIG['KEY_BACKUP_FILE'])
|
||||
logger.info(f"已备份旧密钥文件到: {CONFIG['KEY_BACKUP_FILE']}")
|
||||
|
||||
# 保存新密钥文件
|
||||
with open(CONFIG['KEY_FILE'], 'w') as f:
|
||||
json.dump(key_data, f, indent=2)
|
||||
|
||||
# 设置文件权限为只读
|
||||
os.chmod(CONFIG['KEY_FILE'], 0o600)
|
||||
|
||||
logger.info(f"密钥文件已保存: {CONFIG['KEY_FILE']}")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"保存密钥文件失败: {e}")
|
||||
return False
|
||||
|
||||
|
||||
def load_key_file():
|
||||
"""
|
||||
加载本地密钥文件
|
||||
"""
|
||||
try:
|
||||
# 尝试加载主密钥文件
|
||||
if os.path.exists(CONFIG['KEY_FILE']):
|
||||
with open(CONFIG['KEY_FILE'], 'r') as f:
|
||||
key_data = json.load(f)
|
||||
logger.info("密钥文件加载成功")
|
||||
return key_data
|
||||
|
||||
# 尝试加载备份密钥文件
|
||||
if os.path.exists(CONFIG['KEY_BACKUP_FILE']):
|
||||
logger.warning("主密钥文件不存在,尝试加载备份")
|
||||
with open(CONFIG['KEY_BACKUP_FILE'], 'r') as f:
|
||||
key_data = json.load(f)
|
||||
logger.info("备份密钥文件加载成功")
|
||||
return key_data
|
||||
|
||||
logger.warning("密钥文件不存在")
|
||||
return None
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"加载密钥文件失败: {e}")
|
||||
return None
|
||||
|
||||
|
||||
def verify_local_key(chip_id):
|
||||
"""
|
||||
本地验证密钥(永久有效,无过期检查)
|
||||
"""
|
||||
# 加载密钥文件
|
||||
key_data = load_key_file()
|
||||
if not key_data:
|
||||
return False, "密钥文件不存在"
|
||||
|
||||
# 验证芯片ID是否匹配
|
||||
if key_data.get('chip_id') != chip_id:
|
||||
logger.error(f"芯片ID不匹配: 期望 {key_data.get('chip_id')}, 实际 {chip_id}")
|
||||
return False, "芯片ID不匹配"
|
||||
|
||||
# 验证签名
|
||||
valid, message = verify_key_signature(chip_id, key_data)
|
||||
if not valid:
|
||||
return False, message
|
||||
|
||||
# 验证通过
|
||||
logger.info(f"永久激活验证通过!")
|
||||
logger.info(f"激活时间: {key_data['activate_time']}")
|
||||
logger.info(f"激活ID: {key_data['activation_id']}")
|
||||
|
||||
return True, "验证通过(永久有效)"
|
||||
|
||||
|
||||
def activate_device(chip_id):
|
||||
"""
|
||||
联网激活设备(永久激活)
|
||||
"""
|
||||
url = f"{CONFIG['SERVER_URL']}{CONFIG['ACTIVATE_URL']}"
|
||||
payload = {'chip_id': chip_id}
|
||||
|
||||
for attempt in range(CONFIG['ACTIVATE_RETRY_COUNT']):
|
||||
try:
|
||||
logger.info(f"正在激活设备 (尝试 {attempt + 1}/{CONFIG['ACTIVATE_RETRY_COUNT']})...")
|
||||
response = requests.post(
|
||||
url,
|
||||
json=payload,
|
||||
timeout=10,
|
||||
headers={'Content-Type': 'application/json'}
|
||||
)
|
||||
|
||||
if response.status_code == 200:
|
||||
data = response.json()
|
||||
if data.get('code') == 200:
|
||||
# 保存密钥文件
|
||||
key_data = data['data']
|
||||
if save_key_file(key_data):
|
||||
logger.info("设备永久激活成功!")
|
||||
return True
|
||||
else:
|
||||
logger.error("保存密钥文件失败")
|
||||
else:
|
||||
logger.error(f"激活失败: {data.get('message')}")
|
||||
else:
|
||||
logger.error(f"HTTP错误: {response.status_code}")
|
||||
|
||||
except requests.exceptions.RequestException as e:
|
||||
logger.error(f"网络错误: {e}")
|
||||
except Exception as e:
|
||||
logger.error(f"激活过程中发生错误: {e}")
|
||||
|
||||
if attempt < CONFIG['ACTIVATE_RETRY_COUNT'] - 1:
|
||||
wait_time = 2 ** attempt
|
||||
logger.info(f"等待 {wait_time} 秒后重试...")
|
||||
time.sleep(wait_time)
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def create_emergency_key(chip_id):
|
||||
"""
|
||||
创建应急密钥(当无法联网时使用,需人工授权)
|
||||
警告:此功能仅用于紧急情况
|
||||
"""
|
||||
import secrets
|
||||
|
||||
logger.warning("正在创建应急密钥...")
|
||||
|
||||
# 生成应急密钥数据
|
||||
emergency_key = {
|
||||
'chip_id': chip_id,
|
||||
'activation_id': f"EMERGENCY-{secrets.token_hex(8)}",
|
||||
'activate_time': datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
|
||||
'signature': 'EMERGENCY-MODE', # 应急模式签名
|
||||
'permanent': True,
|
||||
'emergency': True,
|
||||
'version': '1.0'
|
||||
}
|
||||
|
||||
# 保存应急密钥
|
||||
if save_key_file(emergency_key):
|
||||
logger.warning("应急密钥已创建!请确保这是授权操作!")
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def main():
|
||||
"""
|
||||
主函数:程序启动验证(永久有效)
|
||||
"""
|
||||
parser = argparse.ArgumentParser(description='设备永久激活和验证程序')
|
||||
parser.add_argument('--force-activate', action='store_true', help='强制重新激活')
|
||||
parser.add_argument('--check-only', action='store_true', help='仅检查验证状态')
|
||||
parser.add_argument('--emergency', action='store_true', help='创建应急密钥(仅限授权使用)')
|
||||
parser.add_argument('--show-info', action='store_true', help='显示激活信息')
|
||||
args = parser.parse_args()
|
||||
|
||||
# 获取芯片ID
|
||||
chip_id = get_chip_id()
|
||||
if not chip_id:
|
||||
logger.error("无法获取芯片ID")
|
||||
sys.exit(1)
|
||||
|
||||
logger.info(f"芯片ID: {chip_id}")
|
||||
|
||||
# 应急模式
|
||||
if args.emergency:
|
||||
if create_emergency_key(chip_id):
|
||||
logger.info("应急密钥创建成功")
|
||||
sys.exit(0)
|
||||
else:
|
||||
logger.error("应急密钥创建失败")
|
||||
sys.exit(1)
|
||||
|
||||
# 显示激活信息
|
||||
if args.show_info:
|
||||
key_data = load_key_file()
|
||||
if key_data:
|
||||
print("\n" + "="*50)
|
||||
print("设备激活信息")
|
||||
print("="*50)
|
||||
print(f"芯片ID: {key_data.get('chip_id')}")
|
||||
print(f"激活时间: {key_data.get('activate_time')}")
|
||||
print(f"激活ID: {key_data.get('activation_id')}")
|
||||
print(f"激活类型: {'永久有效' if key_data.get('permanent') else '临时'}")
|
||||
if key_data.get('emergency'):
|
||||
print("警告: 应急模式激活")
|
||||
print("="*50)
|
||||
else:
|
||||
print("设备未激活")
|
||||
sys.exit(0)
|
||||
|
||||
# 检查是否需要激活
|
||||
need_activate = args.force_activate
|
||||
|
||||
if not need_activate:
|
||||
# 尝试本地验证
|
||||
valid, message = verify_local_key(chip_id)
|
||||
|
||||
if valid:
|
||||
logger.info(f"✅ 验证成功: {message}")
|
||||
if not args.check_only:
|
||||
logger.info("验证通过,启动主程序...")
|
||||
# 在这里调用你的主程序
|
||||
# subprocess.run(['python3', 'your_main_program.py'])
|
||||
sys.exit(0)
|
||||
else:
|
||||
logger.warning(f"❌ 本地验证失败: {message}")
|
||||
need_activate = True
|
||||
|
||||
# 需要联网激活
|
||||
if need_activate:
|
||||
logger.info("开始联网永久激活...")
|
||||
if activate_device(chip_id):
|
||||
# 激活后再次验证
|
||||
valid, message = verify_local_key(chip_id)
|
||||
if valid:
|
||||
logger.info(f"✅ 激活验证成功: {message}")
|
||||
logger.info("设备已永久激活,无需再次联网!")
|
||||
if not args.check_only:
|
||||
logger.info("激活完成,启动主程序...")
|
||||
# subprocess.run(['python3', 'your_main_program.py'])
|
||||
sys.exit(0)
|
||||
else:
|
||||
logger.error(f"❌ 激活后验证失败: {message}")
|
||||
sys.exit(1)
|
||||
else:
|
||||
logger.error("设备激活失败,请检查网络连接")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def install_service():
|
||||
"""
|
||||
安装为系统服务
|
||||
"""
|
||||
service_content = """[Unit]
|
||||
Description=Device Permanent Activation Check Service
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
ExecStart=/usr/bin/python3 /opt/device_activation/client.py --check-only
|
||||
RemainAfterExit=yes
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
"""
|
||||
|
||||
service_file = '/etc/systemd/system/device-activation.service'
|
||||
try:
|
||||
# 复制程序到系统目录
|
||||
script_dir = '/opt/device_activation'
|
||||
os.makedirs(script_dir, exist_ok=True)
|
||||
|
||||
import shutil
|
||||
shutil.copy2(__file__, os.path.join(script_dir, 'client.py'))
|
||||
os.chmod(os.path.join(script_dir, 'client.py'), 0o755)
|
||||
|
||||
# 创建服务文件
|
||||
with open(service_file, 'w') as f:
|
||||
f.write(service_content)
|
||||
os.chmod(service_file, 0o644)
|
||||
|
||||
logger.info(f"服务文件已创建: {service_file}")
|
||||
logger.info("请执行以下命令启用服务:")
|
||||
logger.info("sudo systemctl daemon-reload")
|
||||
logger.info("sudo systemctl enable device-activation.service")
|
||||
logger.info("sudo systemctl start device-activation.service")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"安装服务失败: {e}")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
if len(sys.argv) > 1 and sys.argv[1] == 'install-service':
|
||||
install_service()
|
||||
else:
|
||||
main()
|
||||
Reference in New Issue
Block a user