feat: 优化硬件ID生成方案,增加计算机名作为备选方案,确保ID生成的稳定性 v3.5.2
This commit is contained in:
@@ -13,7 +13,12 @@ from pathlib import Path
|
||||
from utils.config import Config
|
||||
from utils.cursor_registry import CursorRegistry
|
||||
from cursor_auth_manager import CursorAuthManager
|
||||
from utils.cursor_resetter import CursorResetter # 添加导入
|
||||
from utils.cursor_resetter import CursorResetter
|
||||
from datetime import datetime
|
||||
|
||||
# 添加缓存文件路径常量
|
||||
CACHE_DIR = Path(os.path.expanduser("~")) / ".cursor_cache"
|
||||
HARDWARE_ID_CACHE = CACHE_DIR / "hardware_id.json"
|
||||
|
||||
def is_admin() -> bool:
|
||||
"""检查是否具有管理员权限
|
||||
@@ -56,7 +61,11 @@ def run_as_admin():
|
||||
return False
|
||||
|
||||
def get_hardware_id() -> str:
|
||||
"""获取硬件唯一标识"""
|
||||
"""获取硬件唯一标识
|
||||
方案1: CPU ID + 主板序列号 + BIOS序列号
|
||||
方案2: 系统盘序列号 + Windows安装时间
|
||||
方案3: 计算机名(最后的备选方案)
|
||||
"""
|
||||
try:
|
||||
# 创建startupinfo对象来隐藏命令行窗口
|
||||
startupinfo = None
|
||||
@@ -64,26 +73,70 @@ def get_hardware_id() -> str:
|
||||
startupinfo = subprocess.STARTUPINFO()
|
||||
startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
|
||||
startupinfo.wShowWindow = subprocess.SW_HIDE
|
||||
|
||||
# 获取CPU信息
|
||||
cpu_info = subprocess.check_output('wmic cpu get ProcessorId', startupinfo=startupinfo).decode()
|
||||
cpu_id = cpu_info.split('\n')[1].strip()
|
||||
|
||||
# 获取主板序列号
|
||||
board_info = subprocess.check_output('wmic baseboard get SerialNumber', startupinfo=startupinfo).decode()
|
||||
board_id = board_info.split('\n')[1].strip()
|
||||
|
||||
# 获取BIOS序列号
|
||||
bios_info = subprocess.check_output('wmic bios get SerialNumber', startupinfo=startupinfo).decode()
|
||||
bios_id = bios_info.split('\n')[1].strip()
|
||||
|
||||
# 组合信息并生成哈希
|
||||
combined = f"{cpu_id}:{board_id}:{bios_id}"
|
||||
return hashlib.md5(combined.encode()).hexdigest()
|
||||
|
||||
# 方案1: 尝试获取硬件信息
|
||||
try:
|
||||
# 获取CPU ID
|
||||
cpu_info = subprocess.check_output('wmic cpu get ProcessorId', startupinfo=startupinfo).decode()
|
||||
cpu_id = cpu_info.split('\n')[1].strip()
|
||||
|
||||
# 获取主板序列号
|
||||
board_info = subprocess.check_output('wmic baseboard get SerialNumber', startupinfo=startupinfo).decode()
|
||||
board_id = board_info.split('\n')[1].strip()
|
||||
|
||||
# 获取BIOS序列号
|
||||
bios_info = subprocess.check_output('wmic bios get SerialNumber', startupinfo=startupinfo).decode()
|
||||
bios_id = bios_info.split('\n')[1].strip()
|
||||
|
||||
# 如果所有信息都获取成功且有效
|
||||
if all([cpu_id, board_id, bios_id]) and not all(x in ['', '0', 'None', 'To be filled by O.E.M.'] for x in [cpu_id, board_id, bios_id]):
|
||||
combined = f"{cpu_id}:{board_id}:{bios_id}"
|
||||
hardware_id = hashlib.md5(combined.encode()).hexdigest()
|
||||
logging.info("使用硬件信息生成ID成功")
|
||||
return hardware_id
|
||||
|
||||
except Exception as e:
|
||||
logging.warning(f"方案1失败: {str(e)}")
|
||||
|
||||
# 方案2: 系统盘序列号 + Windows安装时间
|
||||
try:
|
||||
backup_info = []
|
||||
|
||||
# 获取系统盘序列号
|
||||
volume_info = subprocess.check_output('wmic logicaldisk where "DeviceID=\'C:\'" get VolumeSerialNumber', startupinfo=startupinfo).decode()
|
||||
volume_serial = volume_info.split('\n')[1].strip()
|
||||
if volume_serial and volume_serial not in ['', '0']:
|
||||
backup_info.append(("volume", volume_serial))
|
||||
|
||||
# 获取Windows安装时间
|
||||
os_info = subprocess.check_output('wmic os get InstallDate', startupinfo=startupinfo).decode()
|
||||
install_date = os_info.split('\n')[1].strip()
|
||||
if install_date:
|
||||
backup_info.append(("install", install_date))
|
||||
|
||||
if backup_info:
|
||||
combined = "|".join(f"{k}:{v}" for k, v in sorted(backup_info))
|
||||
hardware_id = hashlib.md5(combined.encode()).hexdigest()
|
||||
logging.info("使用系统信息生成ID成功")
|
||||
return hardware_id
|
||||
|
||||
except Exception as e:
|
||||
logging.warning(f"方案2失败: {str(e)}")
|
||||
|
||||
# 方案3: 使用计算机名(最后的备选方案)
|
||||
import platform
|
||||
computer_name = platform.node()
|
||||
if computer_name:
|
||||
hardware_id = hashlib.md5(computer_name.encode()).hexdigest()
|
||||
logging.info("使用计算机名生成ID成功")
|
||||
return hardware_id
|
||||
|
||||
raise ValueError("无法获取任何可用信息来生成硬件ID")
|
||||
|
||||
except Exception as e:
|
||||
logging.error(f"获取硬件ID失败: {str(e)}")
|
||||
# 如果获取失败,使用UUID作为备选方案
|
||||
return str(uuid.uuid4())
|
||||
error_msg = f"生成硬件ID失败: {str(e)}"
|
||||
logging.error(error_msg)
|
||||
raise RuntimeError(error_msg)
|
||||
|
||||
class AccountSwitcher:
|
||||
def __init__(self):
|
||||
@@ -101,9 +154,9 @@ class AccountSwitcher:
|
||||
self.package_json = self.app_path / "package.json"
|
||||
self.auth_manager = CursorAuthManager()
|
||||
self.config = Config()
|
||||
self.hardware_id = self.get_hardware_id() # 先获取硬件ID
|
||||
self.registry = CursorRegistry() # 添加注册表操作工具类
|
||||
self.resetter = CursorResetter() # 添加重置工具类
|
||||
self.hardware_id = get_hardware_id() # 使用新的硬件ID获取函数
|
||||
self.registry = CursorRegistry()
|
||||
self.resetter = CursorResetter()
|
||||
self.max_retries = 5
|
||||
self.wait_time = 1
|
||||
|
||||
@@ -111,33 +164,7 @@ class AccountSwitcher:
|
||||
|
||||
def get_hardware_id(self) -> str:
|
||||
"""获取硬件唯一标识"""
|
||||
try:
|
||||
# 创建startupinfo对象来隐藏命令行窗口
|
||||
startupinfo = None
|
||||
if sys.platform == "win32":
|
||||
startupinfo = subprocess.STARTUPINFO()
|
||||
startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
|
||||
startupinfo.wShowWindow = subprocess.SW_HIDE
|
||||
|
||||
# 获取CPU信息
|
||||
cpu_info = subprocess.check_output('wmic cpu get ProcessorId', startupinfo=startupinfo).decode()
|
||||
cpu_id = cpu_info.split('\n')[1].strip()
|
||||
|
||||
# 获取主板序列号
|
||||
board_info = subprocess.check_output('wmic baseboard get SerialNumber', startupinfo=startupinfo).decode()
|
||||
board_id = board_info.split('\n')[1].strip()
|
||||
|
||||
# 获取BIOS序列号
|
||||
bios_info = subprocess.check_output('wmic bios get SerialNumber', startupinfo=startupinfo).decode()
|
||||
bios_id = bios_info.split('\n')[1].strip()
|
||||
|
||||
# 组合信息并生成哈希
|
||||
combined = f"{cpu_id}:{board_id}:{bios_id}"
|
||||
return hashlib.md5(combined.encode()).hexdigest()
|
||||
except Exception as e:
|
||||
logging.error(f"获取硬件ID失败: {str(e)}")
|
||||
# 如果获取失败,使用UUID作为备选方案
|
||||
return str(uuid.uuid4())
|
||||
return get_hardware_id() # 使用全局函数
|
||||
|
||||
def get_cursor_version(self) -> str:
|
||||
"""获取Cursor版本号"""
|
||||
@@ -387,24 +414,40 @@ class AccountSwitcher:
|
||||
shell=True
|
||||
)
|
||||
|
||||
# 等待进程关闭
|
||||
# 等待进程关闭,增加重试次数和等待时间
|
||||
retry_count = 0
|
||||
while retry_count < self.max_retries:
|
||||
if not self.get_process_details("Cursor.exe"):
|
||||
max_retries = 10 # 增加最大重试次数
|
||||
wait_time = 2 # 增加每次等待时间
|
||||
|
||||
while retry_count < max_retries:
|
||||
remaining_processes = self.get_process_details("Cursor.exe")
|
||||
if not remaining_processes:
|
||||
logging.info("所有Cursor进程已关闭")
|
||||
# 额外等待一段时间确保系统资源完全释放
|
||||
time.sleep(2)
|
||||
return True
|
||||
|
||||
retry_count += 1
|
||||
if retry_count >= self.max_retries:
|
||||
if retry_count >= max_retries:
|
||||
processes = self.get_process_details("Cursor.exe")
|
||||
if processes:
|
||||
logging.error(f"无法关闭以下进程:")
|
||||
for p in processes:
|
||||
logging.error(f"PID={p['pid']}, 路径={p['name']}")
|
||||
# 最后一次尝试强制结束
|
||||
try:
|
||||
subprocess.run(
|
||||
"taskkill /f /im Cursor.exe /t >nul 2>&1",
|
||||
startupinfo=startupinfo,
|
||||
shell=True
|
||||
)
|
||||
time.sleep(2)
|
||||
except:
|
||||
pass
|
||||
return False
|
||||
|
||||
logging.warning(f"等待进程关闭, 尝试 {retry_count}/{self.max_retries}...")
|
||||
time.sleep(self.wait_time)
|
||||
logging.warning(f"等待进程关闭, 尝试 {retry_count}/{max_retries}...")
|
||||
time.sleep(wait_time)
|
||||
|
||||
return True
|
||||
else:
|
||||
@@ -456,61 +499,74 @@ class AccountSwitcher:
|
||||
logging.error("无法关闭Cursor进程")
|
||||
return False
|
||||
|
||||
# 等待进程完全关闭
|
||||
time.sleep(2)
|
||||
# 等待系统资源释放
|
||||
time.sleep(3)
|
||||
|
||||
# 启动Cursor
|
||||
if sys.platform == "win32":
|
||||
cursor_exe = self.cursor_path / "Cursor.exe"
|
||||
if cursor_exe.exists():
|
||||
try:
|
||||
# 使用subprocess启动
|
||||
startupinfo = subprocess.STARTUPINFO()
|
||||
startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
|
||||
|
||||
subprocess.Popen(
|
||||
str(cursor_exe),
|
||||
startupinfo=startupinfo,
|
||||
creationflags=subprocess.CREATE_NEW_CONSOLE
|
||||
)
|
||||
|
||||
# 等待进程启动
|
||||
time.sleep(3)
|
||||
|
||||
# 验证进程是否启动
|
||||
processes = self.get_process_details("Cursor.exe")
|
||||
if processes:
|
||||
logging.info("Cursor启动成功")
|
||||
return True
|
||||
else:
|
||||
logging.error("Cursor进程未找到")
|
||||
# 尝试使用 os.startfile 作为备选方案
|
||||
max_retries = 3
|
||||
for attempt in range(max_retries):
|
||||
try:
|
||||
# 使用subprocess启动
|
||||
startupinfo = subprocess.STARTUPINFO()
|
||||
startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
|
||||
|
||||
subprocess.Popen(
|
||||
str(cursor_exe),
|
||||
startupinfo=startupinfo,
|
||||
creationflags=subprocess.CREATE_NEW_CONSOLE
|
||||
)
|
||||
|
||||
# 等待进程启动
|
||||
time.sleep(5) # 增加等待时间
|
||||
|
||||
# 验证进程是否启动
|
||||
processes = self.get_process_details("Cursor.exe")
|
||||
if processes:
|
||||
logging.info("Cursor启动成功")
|
||||
return True
|
||||
else:
|
||||
if attempt < max_retries - 1:
|
||||
logging.warning(f"启动尝试 {attempt + 1} 失败,准备重试...")
|
||||
time.sleep(3)
|
||||
continue
|
||||
|
||||
logging.error("Cursor进程未找到")
|
||||
# 尝试使用 os.startfile 作为备选方案
|
||||
try:
|
||||
os.startfile(str(cursor_exe))
|
||||
time.sleep(5)
|
||||
logging.info("使用备选方案启动Cursor")
|
||||
return True
|
||||
except Exception as e:
|
||||
logging.error(f"备选启动方案失败: {str(e)}")
|
||||
return False
|
||||
|
||||
except Exception as e:
|
||||
if attempt < max_retries - 1:
|
||||
logging.warning(f"启动尝试 {attempt + 1} 失败: {str(e)},准备重试...")
|
||||
time.sleep(3)
|
||||
continue
|
||||
|
||||
logging.error(f"启动Cursor失败: {str(e)}")
|
||||
# 尝试使用 os.startfile 作为最后的备选方案
|
||||
try:
|
||||
os.startfile(str(cursor_exe))
|
||||
time.sleep(3)
|
||||
time.sleep(5)
|
||||
logging.info("使用备选方案启动Cursor")
|
||||
return True
|
||||
except Exception as e:
|
||||
logging.error(f"备选启动方案失败: {str(e)}")
|
||||
return False
|
||||
|
||||
except Exception as e:
|
||||
logging.error(f"启动Cursor失败: {str(e)}")
|
||||
# 尝试使用 os.startfile 作为备选方案
|
||||
try:
|
||||
os.startfile(str(cursor_exe))
|
||||
time.sleep(3)
|
||||
logging.info("使用备选方案启动Cursor")
|
||||
return True
|
||||
except Exception as e:
|
||||
logging.error(f"备选启动方案失败: {str(e)}")
|
||||
return False
|
||||
else:
|
||||
logging.error(f"未找到Cursor程序: {cursor_exe}")
|
||||
return False
|
||||
elif sys.platform == "darwin":
|
||||
try:
|
||||
subprocess.run("open -a Cursor", shell=True, check=True)
|
||||
time.sleep(5)
|
||||
logging.info("Cursor启动成功")
|
||||
return True
|
||||
except subprocess.CalledProcessError as e:
|
||||
@@ -519,6 +575,7 @@ class AccountSwitcher:
|
||||
elif sys.platform == "linux":
|
||||
try:
|
||||
subprocess.run("cursor &", shell=True, check=True)
|
||||
time.sleep(5)
|
||||
logging.info("Cursor启动成功")
|
||||
return True
|
||||
except subprocess.CalledProcessError as e:
|
||||
@@ -529,16 +586,6 @@ class AccountSwitcher:
|
||||
|
||||
except Exception as e:
|
||||
logging.error(f"重启Cursor失败: {str(e)}")
|
||||
# 尝试使用 os.startfile 作为最后的备选方案
|
||||
try:
|
||||
cursor_exe = self.cursor_path / "Cursor.exe"
|
||||
if cursor_exe.exists():
|
||||
os.startfile(str(cursor_exe))
|
||||
time.sleep(3)
|
||||
logging.info("使用最终备选方案启动Cursor")
|
||||
return True
|
||||
except:
|
||||
pass
|
||||
return False
|
||||
|
||||
def activate_and_switch(self, activation_code: str) -> Tuple[bool, str]:
|
||||
|
||||
@@ -1,145 +0,0 @@
|
||||
import sys
|
||||
from pathlib import Path
|
||||
import logging
|
||||
import os
|
||||
from PIL import Image
|
||||
from PyQt5.QtWidgets import (QMainWindow, QWidget, QVBoxLayout, QHBoxLayout,
|
||||
QLabel, QLineEdit, QPushButton, QFrame, QTextEdit,
|
||||
QMessageBox, QApplication, QSystemTrayIcon, QMenu,
|
||||
QDialog, QProgressBar, QStyle)
|
||||
from PyQt5.QtCore import Qt, QTimer, QThread, pyqtSignal
|
||||
from PyQt5.QtGui import QIcon, QPixmap
|
||||
import time
|
||||
import requests
|
||||
from urllib.parse import quote
|
||||
import subprocess
|
||||
|
||||
sys.path.append(str(Path(__file__).parent.parent))
|
||||
|
||||
from utils.config import Config
|
||||
from utils.version_manager import VersionManager
|
||||
from account_switcher import AccountSwitcher
|
||||
|
||||
class MainWindow(QMainWindow):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.config = Config()
|
||||
self.switcher = AccountSwitcher()
|
||||
self.version_manager = VersionManager()
|
||||
|
||||
# 添加激活状态缓存
|
||||
self._activation_status = None # 缓存的激活状态
|
||||
self._status_timer = None # 状态更新定时器
|
||||
|
||||
# 添加心跳定时器
|
||||
self._heartbeat_timer = QTimer()
|
||||
self._heartbeat_timer.timeout.connect(self.send_heartbeat)
|
||||
self._heartbeat_timer.start(5 * 60 * 1000) # 每5分钟发送一次心跳
|
||||
|
||||
# 添加请求锁,防止重复提交
|
||||
self._is_requesting = False
|
||||
self._last_request_time = 0
|
||||
self._request_cooldown = 2 # 请求冷却时间(秒)
|
||||
|
||||
version = get_version()
|
||||
cursor_version = self.switcher.get_cursor_version()
|
||||
self.setWindowTitle(f"听泉Cursor助手 v{version} (本机Cursor版本: {cursor_version})")
|
||||
self.setMinimumSize(600, 680) # 增加最小宽度到600
|
||||
|
||||
# 设置窗口图标
|
||||
icon_path = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "icon", "two.ico")
|
||||
if os.path.exists(icon_path):
|
||||
self.window_icon = QIcon(icon_path)
|
||||
if not self.window_icon.isNull():
|
||||
self.setWindowIcon(self.window_icon)
|
||||
logging.info(f"成功设置窗口图标: {icon_path}")
|
||||
else:
|
||||
logging.warning("图标文件加载失败")
|
||||
|
||||
# 创建系统托盘图标
|
||||
self.create_tray_icon()
|
||||
|
||||
# 创建主窗口部件
|
||||
central_widget = QWidget()
|
||||
self.setCentralWidget(central_widget)
|
||||
|
||||
# 设置主窗口样式
|
||||
central_widget.setStyleSheet("""
|
||||
QWidget {
|
||||
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
|
||||
stop:0 #f8f9fa,
|
||||
stop:0.5 #ffffff,
|
||||
stop:1 #f8f9fa);
|
||||
}
|
||||
QFrame {
|
||||
border: none;
|
||||
background: transparent;
|
||||
}
|
||||
""")
|
||||
|
||||
# 创建主布局
|
||||
main_layout = QVBoxLayout(central_widget)
|
||||
main_layout.setSpacing(12) # 减小区域间距
|
||||
main_layout.setContentsMargins(20, 15, 20, 15) # 调整外边距
|
||||
|
||||
# 启动时检查一次状态
|
||||
QTimer.singleShot(0, self.check_status)
|
||||
|
||||
# 启动时自动检查更新
|
||||
QTimer.singleShot(1000, self.check_for_updates)
|
||||
|
||||
def send_heartbeat(self):
|
||||
"""发送心跳请求"""
|
||||
if not self._check_request_throttle():
|
||||
return
|
||||
|
||||
def heartbeat_func():
|
||||
return self.switcher.send_heartbeat()
|
||||
|
||||
# 创建工作线程
|
||||
self.heartbeat_worker = ApiWorker(heartbeat_func)
|
||||
self.heartbeat_worker.finished.connect(self.on_heartbeat_complete)
|
||||
self.heartbeat_worker.start()
|
||||
|
||||
def on_heartbeat_complete(self, result):
|
||||
"""心跳完成回调"""
|
||||
success, message = result
|
||||
self._request_complete()
|
||||
|
||||
if success:
|
||||
logging.info(f"心跳发送成功: {message}")
|
||||
# 更新状态显示
|
||||
self.check_status()
|
||||
else:
|
||||
logging.error(f"心跳发送失败: {message}")
|
||||
|
||||
def closeEvent(self, event):
|
||||
"""窗口关闭事件"""
|
||||
try:
|
||||
if hasattr(self, 'tray_icon') and self.tray_icon.isVisible():
|
||||
event.ignore()
|
||||
self.hide()
|
||||
# 确保托盘图标显示
|
||||
self.tray_icon.show()
|
||||
self.tray_icon.showMessage(
|
||||
"听泉Cursor助手",
|
||||
"程序已最小化到系统托盘",
|
||||
QSystemTrayIcon.Information,
|
||||
2000
|
||||
)
|
||||
else:
|
||||
# 如果托盘图标不可用,则正常退出
|
||||
if self._status_timer:
|
||||
self._status_timer.stop()
|
||||
if hasattr(self, '_heartbeat_timer'):
|
||||
self._heartbeat_timer.stop()
|
||||
event.accept()
|
||||
|
||||
except Exception as e:
|
||||
logging.error(f"处理关闭事件时发生错误: {str(e)}")
|
||||
# 发生错误时,接受关闭事件
|
||||
if self._status_timer:
|
||||
self._status_timer.stop()
|
||||
if hasattr(self, '_heartbeat_timer'):
|
||||
self._heartbeat_timer.stop()
|
||||
event.accept()
|
||||
54
test_computer_name.py
Normal file
54
test_computer_name.py
Normal file
@@ -0,0 +1,54 @@
|
||||
import platform
|
||||
import hashlib
|
||||
import time
|
||||
|
||||
def get_computer_name_id():
|
||||
"""使用计算机名生成ID(方案三)"""
|
||||
try:
|
||||
computer_name = platform.node()
|
||||
if computer_name:
|
||||
print(f"\n计算机名: {computer_name}")
|
||||
hardware_id = hashlib.md5(computer_name.encode()).hexdigest()
|
||||
return hardware_id
|
||||
return None
|
||||
except Exception as e:
|
||||
print(f"获取计算机名失败: {str(e)}")
|
||||
return None
|
||||
|
||||
def test_stability():
|
||||
"""测试ID的稳定性"""
|
||||
print("开始测试计算机名生成ID的稳定性...")
|
||||
print("将进行10次测试,每次间隔1秒")
|
||||
|
||||
# 存储每次生成的ID
|
||||
computer_ids = []
|
||||
|
||||
for i in range(10):
|
||||
print(f"\n第 {i+1} 次测试:")
|
||||
|
||||
# 测试计算机名方案
|
||||
comp_id = get_computer_name_id()
|
||||
if comp_id:
|
||||
print(f"使用计算机名生成的ID: {comp_id}")
|
||||
computer_ids.append(comp_id)
|
||||
|
||||
time.sleep(1)
|
||||
|
||||
# 分析结果
|
||||
print("\n测试结果分析:")
|
||||
|
||||
if computer_ids:
|
||||
unique_ids = set(computer_ids)
|
||||
print(f"\n计算机名方案:")
|
||||
print(f"生成次数: {len(computer_ids)}")
|
||||
print(f"唯一ID数: {len(unique_ids)}")
|
||||
print("是否稳定: " + ("是" if len(unique_ids) == 1 else "否"))
|
||||
if len(unique_ids) > 1:
|
||||
print("出现的不同ID:")
|
||||
for idx, id in enumerate(unique_ids):
|
||||
print(f"{idx+1}. {id}")
|
||||
else:
|
||||
print("\n计算机名方案: 获取失败")
|
||||
|
||||
if __name__ == "__main__":
|
||||
test_stability()
|
||||
131
test_hardware_id.py
Normal file
131
test_hardware_id.py
Normal file
@@ -0,0 +1,131 @@
|
||||
import subprocess
|
||||
import hashlib
|
||||
import logging
|
||||
import sys
|
||||
import time
|
||||
|
||||
def get_hardware_info():
|
||||
"""获取硬件信息(方案一)"""
|
||||
startupinfo = None
|
||||
if sys.platform == "win32":
|
||||
startupinfo = subprocess.STARTUPINFO()
|
||||
startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
|
||||
startupinfo.wShowWindow = subprocess.SW_HIDE
|
||||
|
||||
try:
|
||||
# 获取CPU ID
|
||||
cpu_info = subprocess.check_output('wmic cpu get ProcessorId', startupinfo=startupinfo).decode()
|
||||
cpu_id = cpu_info.split('\n')[1].strip()
|
||||
|
||||
# 获取主板序列号
|
||||
board_info = subprocess.check_output('wmic baseboard get SerialNumber', startupinfo=startupinfo).decode()
|
||||
board_id = board_info.split('\n')[1].strip()
|
||||
|
||||
# 获取BIOS序列号
|
||||
bios_info = subprocess.check_output('wmic bios get SerialNumber', startupinfo=startupinfo).decode()
|
||||
bios_id = bios_info.split('\n')[1].strip()
|
||||
|
||||
if all([cpu_id, board_id, bios_id]):
|
||||
print(f"\n方案一硬件信息:")
|
||||
print(f"CPU ID: {cpu_id}")
|
||||
print(f"主板序列号: {board_id}")
|
||||
print(f"BIOS序列号: {bios_id}")
|
||||
|
||||
combined = f"{cpu_id}:{board_id}:{bios_id}"
|
||||
return hashlib.md5(combined.encode()).hexdigest()
|
||||
except Exception as e:
|
||||
print(f"方案一获取失败: {str(e)}")
|
||||
return None
|
||||
|
||||
def get_system_info():
|
||||
"""获取系统信息(方案二)"""
|
||||
startupinfo = None
|
||||
if sys.platform == "win32":
|
||||
startupinfo = subprocess.STARTUPINFO()
|
||||
startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
|
||||
startupinfo.wShowWindow = subprocess.SW_HIDE
|
||||
|
||||
backup_info = []
|
||||
|
||||
try:
|
||||
# 获取系统盘序列号
|
||||
volume_info = subprocess.check_output('wmic logicaldisk where "DeviceID=\'C:\'" get VolumeSerialNumber', startupinfo=startupinfo).decode()
|
||||
volume_serial = volume_info.split('\n')[1].strip()
|
||||
if volume_serial:
|
||||
backup_info.append(("volume", volume_serial))
|
||||
print(f"\n系统盘序列号: {volume_serial}")
|
||||
except Exception as e:
|
||||
print(f"获取系统盘序列号失败: {str(e)}")
|
||||
|
||||
try:
|
||||
# 获取Windows安装时间
|
||||
os_info = subprocess.check_output('wmic os get InstallDate', startupinfo=startupinfo).decode()
|
||||
install_date = os_info.split('\n')[1].strip()
|
||||
if install_date:
|
||||
backup_info.append(("install", install_date))
|
||||
print(f"Windows安装时间: {install_date}")
|
||||
except Exception as e:
|
||||
print(f"获取系统安装时间失败: {str(e)}")
|
||||
|
||||
if backup_info:
|
||||
combined = "|".join(f"{k}:{v}" for k, v in sorted(backup_info))
|
||||
return hashlib.md5(combined.encode()).hexdigest()
|
||||
return None
|
||||
|
||||
def test_stability():
|
||||
"""测试ID的稳定性"""
|
||||
print("开始测试硬件ID稳定性...")
|
||||
print("将进行10次测试,每次间隔1秒")
|
||||
|
||||
# 存储每次生成的ID
|
||||
hardware_ids = []
|
||||
system_ids = []
|
||||
|
||||
for i in range(10):
|
||||
print(f"\n第 {i+1} 次测试:")
|
||||
|
||||
# 测试方案一
|
||||
hw_id = get_hardware_info()
|
||||
if hw_id:
|
||||
print(f"方案一(硬件信息)生成的ID: {hw_id}")
|
||||
hardware_ids.append(hw_id)
|
||||
|
||||
# 测试方案二
|
||||
sys_id = get_system_info()
|
||||
if sys_id:
|
||||
print(f"方案二(系统信息)生成的ID: {sys_id}")
|
||||
system_ids.append(sys_id)
|
||||
|
||||
time.sleep(1)
|
||||
|
||||
# 分析结果
|
||||
print("\n测试结果分析:")
|
||||
|
||||
if hardware_ids:
|
||||
unique_hw_ids = set(hardware_ids)
|
||||
print(f"\n方案一(硬件信息):")
|
||||
print(f"生成次数: {len(hardware_ids)}")
|
||||
print(f"唯一ID数: {len(unique_hw_ids)}")
|
||||
print("是否稳定: " + ("是" if len(unique_hw_ids) == 1 else "否"))
|
||||
if len(unique_hw_ids) > 1:
|
||||
print("出现的不同ID:")
|
||||
for idx, id in enumerate(unique_hw_ids):
|
||||
print(f"{idx+1}. {id}")
|
||||
else:
|
||||
print("\n方案一(硬件信息): 获取失败")
|
||||
|
||||
if system_ids:
|
||||
unique_sys_ids = set(system_ids)
|
||||
print(f"\n方案二(系统信息):")
|
||||
print(f"生成次数: {len(system_ids)}")
|
||||
print(f"唯一ID数: {len(unique_sys_ids)}")
|
||||
print("是否稳定: " + ("是" if len(unique_sys_ids) == 1 else "否"))
|
||||
if len(unique_sys_ids) > 1:
|
||||
print("出现的不同ID:")
|
||||
for idx, id in enumerate(unique_sys_ids):
|
||||
print(f"{idx+1}. {id}")
|
||||
else:
|
||||
print("\n方案二(系统信息): 获取失败")
|
||||
|
||||
if __name__ == "__main__":
|
||||
test_stability()
|
||||
@@ -1 +1 @@
|
||||
3.5.0
|
||||
3.5.2
|
||||
Reference in New Issue
Block a user