第一次提交
This commit is contained in:
296
app/utils/machine_code.py
Normal file
296
app/utils/machine_code.py
Normal file
@@ -0,0 +1,296 @@
|
||||
import hashlib
|
||||
import platform
|
||||
import subprocess
|
||||
import uuid
|
||||
import os
|
||||
import re
|
||||
from typing import Optional
|
||||
|
||||
class MachineCodeGenerator:
|
||||
"""机器码生成器"""
|
||||
|
||||
def __init__(self):
|
||||
self._machine_code_cache = None
|
||||
|
||||
def generate(self) -> str:
|
||||
"""
|
||||
生成机器码
|
||||
:return: 32位哈希字符串
|
||||
"""
|
||||
if self._machine_code_cache:
|
||||
return self._machine_code_cache
|
||||
|
||||
# 收集硬件信息
|
||||
hw_info = []
|
||||
|
||||
try:
|
||||
# 1. 获取主板序列号
|
||||
board_serial = self._get_board_serial()
|
||||
if board_serial:
|
||||
hw_info.append(board_serial)
|
||||
|
||||
# 2. 获取CPU ID
|
||||
cpu_id = self._get_cpu_id()
|
||||
if cpu_id:
|
||||
hw_info.append(cpu_id)
|
||||
|
||||
# 3. 获取硬盘序列号
|
||||
disk_serial = self._get_disk_serial()
|
||||
if disk_serial:
|
||||
hw_info.append(disk_serial)
|
||||
|
||||
# 4. 获取系统UUID
|
||||
system_uuid = self._get_system_uuid()
|
||||
if system_uuid:
|
||||
hw_info.append(system_uuid)
|
||||
|
||||
# 5. 获取MAC地址
|
||||
mac_address = self._get_mac_address()
|
||||
if mac_address:
|
||||
hw_info.append(mac_address)
|
||||
|
||||
except Exception as e:
|
||||
print(f"获取硬件信息时出错: {e}")
|
||||
|
||||
# 如果没有获取到任何硬件信息,使用备用方案
|
||||
if not hw_info:
|
||||
hw_info = [str(uuid.uuid4()), platform.node()]
|
||||
|
||||
# 组合所有硬件信息并生成哈希
|
||||
combined_info = '|'.join(hw_info)
|
||||
hash_obj = hashlib.sha256(combined_info.encode('utf-8'))
|
||||
machine_code = hash_obj.hexdigest()[:32].upper()
|
||||
|
||||
self._machine_code_cache = machine_code
|
||||
return machine_code
|
||||
|
||||
def _get_board_serial(self) -> Optional[str]:
|
||||
"""获取主板序列号"""
|
||||
try:
|
||||
system = platform.system().lower()
|
||||
|
||||
if system == 'windows':
|
||||
# Windows系统
|
||||
result = subprocess.run(
|
||||
'wmic baseboard get serialnumber',
|
||||
shell=True,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
timeout=10
|
||||
)
|
||||
if result.returncode == 0:
|
||||
lines = result.stdout.strip().split('\n')
|
||||
for line in lines:
|
||||
if line.strip() and 'SerialNumber' not in line:
|
||||
return line.strip()
|
||||
|
||||
elif system == 'linux':
|
||||
# Linux系统
|
||||
for path in ['/sys/class/dmi/id/board_serial', '/sys/class/dmi/id/product_uuid']:
|
||||
if os.path.exists(path):
|
||||
with open(path, 'r') as f:
|
||||
content = f.read().strip()
|
||||
if content:
|
||||
return content
|
||||
|
||||
elif system == 'darwin':
|
||||
# macOS系统
|
||||
result = subprocess.run(
|
||||
'system_profiler SPHardwareDataType | grep "Serial Number"',
|
||||
shell=True,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
timeout=10
|
||||
)
|
||||
if result.returncode == 0:
|
||||
match = re.search(r'Serial Number:\s*(.+)', result.stdout)
|
||||
if match:
|
||||
return match.group(1).strip()
|
||||
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
return None
|
||||
|
||||
def _get_cpu_id(self) -> Optional[str]:
|
||||
"""获取CPU ID"""
|
||||
try:
|
||||
system = platform.system().lower()
|
||||
|
||||
if system == 'windows':
|
||||
# Windows系统
|
||||
result = subprocess.run(
|
||||
'wmic cpu get processorid',
|
||||
shell=True,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
timeout=10
|
||||
)
|
||||
if result.returncode == 0:
|
||||
lines = result.stdout.strip().split('\n')
|
||||
for line in lines:
|
||||
if line.strip() and 'ProcessorId' not in line:
|
||||
return line.strip()
|
||||
|
||||
elif system == 'linux':
|
||||
# Linux系统
|
||||
result = subprocess.run(
|
||||
'cat /proc/cpuinfo | grep -i "processor id" | head -1',
|
||||
shell=True,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
timeout=10
|
||||
)
|
||||
if result.returncode == 0:
|
||||
match = re.search(r':\s*(.+)', result.stdout)
|
||||
if match:
|
||||
return match.group(1).strip()
|
||||
|
||||
elif system == 'darwin':
|
||||
# macOS系统
|
||||
result = subprocess.run(
|
||||
'system_profiler SPHardwareDataType | grep "Processor Name"',
|
||||
shell=True,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
timeout=10
|
||||
)
|
||||
if result.returncode == 0:
|
||||
match = re.search(r'Processor Name:\s*(.+)', result.stdout)
|
||||
if match:
|
||||
return match.group(1).strip()
|
||||
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
return None
|
||||
|
||||
def _get_disk_serial(self) -> Optional[str]:
|
||||
"""获取硬盘序列号"""
|
||||
try:
|
||||
system = platform.system().lower()
|
||||
|
||||
if system == 'windows':
|
||||
# Windows系统
|
||||
result = subprocess.run(
|
||||
'wmic diskdrive get serialnumber',
|
||||
shell=True,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
timeout=10
|
||||
)
|
||||
if result.returncode == 0:
|
||||
lines = result.stdout.strip().split('\n')
|
||||
for line in lines:
|
||||
if line.strip() and 'SerialNumber' not in line:
|
||||
return line.strip()
|
||||
|
||||
elif system == 'linux':
|
||||
# Linux系统
|
||||
result = subprocess.run(
|
||||
'lsblk -d -o serial | head -2 | tail -1',
|
||||
shell=True,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
timeout=10
|
||||
)
|
||||
if result.returncode == 0 and result.stdout.strip():
|
||||
return result.stdout.strip()
|
||||
|
||||
elif system == 'darwin':
|
||||
# macOS系统
|
||||
result = subprocess.run(
|
||||
'diskutil info / | grep "Serial Number"',
|
||||
shell=True,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
timeout=10
|
||||
)
|
||||
if result.returncode == 0:
|
||||
match = re.search(r'Serial Number:\s*(.+)', result.stdout)
|
||||
if match:
|
||||
return match.group(1).strip()
|
||||
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
return None
|
||||
|
||||
def _get_system_uuid(self) -> Optional[str]:
|
||||
"""获取系统UUID"""
|
||||
try:
|
||||
# 尝试使用Python的uuid模块获取
|
||||
system_uuid = str(uuid.getnode())
|
||||
if system_uuid and system_uuid != '0':
|
||||
return system_uuid
|
||||
|
||||
# 备用方案:读取系统UUID文件
|
||||
system = platform.system().lower()
|
||||
|
||||
if system == 'linux':
|
||||
for path in ['/etc/machine-id', '/var/lib/dbus/machine-id']:
|
||||
if os.path.exists(path):
|
||||
with open(path, 'r') as f:
|
||||
content = f.read().strip()
|
||||
if content:
|
||||
return content
|
||||
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
return None
|
||||
|
||||
def _get_mac_address(self) -> Optional[str]:
|
||||
"""获取MAC地址"""
|
||||
try:
|
||||
# 获取第一个非回环网络接口的MAC地址
|
||||
import uuid
|
||||
mac = uuid.getnode()
|
||||
if mac != 0:
|
||||
# 格式化MAC地址
|
||||
mac_str = ':'.join([f'{(mac >> 8*i) & 0xff:02x}' for i in range(6)])
|
||||
return mac_str.upper()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
return None
|
||||
|
||||
def save_to_cache(self, file_path: str = '.machine_code') -> bool:
|
||||
"""
|
||||
保存机器码到缓存文件
|
||||
:param file_path: 缓存文件路径
|
||||
:return: 是否保存成功
|
||||
"""
|
||||
try:
|
||||
machine_code = self.generate()
|
||||
with open(file_path, 'w') as f:
|
||||
f.write(machine_code)
|
||||
return True
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
def load_from_cache(self, file_path: str = '.machine_code') -> Optional[str]:
|
||||
"""
|
||||
从缓存文件加载机器码
|
||||
:param file_path: 缓存文件路径
|
||||
:return: 机器码,如果加载失败返回None
|
||||
"""
|
||||
try:
|
||||
if os.path.exists(file_path):
|
||||
with open(file_path, 'r') as f:
|
||||
machine_code = f.read().strip()
|
||||
if machine_code and len(machine_code) == 32:
|
||||
self._machine_code_cache = machine_code
|
||||
return machine_code
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
return None
|
||||
|
||||
def generate_machine_code() -> str:
|
||||
"""
|
||||
生成机器码的便捷函数
|
||||
:return: 32位机器码字符串
|
||||
"""
|
||||
generator = MachineCodeGenerator()
|
||||
return generator.generate()
|
||||
Reference in New Issue
Block a user