Files
nezhacursor/utils/cursor_registry.py
2025-02-12 13:20:06 +08:00

226 lines
9.9 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import os
import winreg
import logging
import shutil
from pathlib import Path
import uuid
from datetime import datetime
import json
import hashlib
class CursorRegistry:
"""Cursor注册表操作工具类"""
def __init__(self):
self.cursor_path = Path(os.path.expanduser("~")) / "AppData" / "Local" / "Programs" / "Cursor"
self.app_path = self.cursor_path / "resources" / "app"
def update_machine_guid(self) -> bool:
"""更新系统的 MachineGuid
Returns:
bool: 是否成功
"""
try:
# 生成新的 GUID
new_guid = str(uuid.uuid4())
registry_path = r"SOFTWARE\Microsoft\Cryptography"
try:
# 使用管理员权限打开注册表项
key = None
try:
# 先尝试直接打开读取权限
key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, registry_path, 0,
winreg.KEY_READ | winreg.KEY_WOW64_64KEY)
# 读取原始值并备份
original_guid = winreg.QueryValueEx(key, "MachineGuid")[0]
winreg.CloseKey(key)
# 备份原始 MachineGuid
backup_dir = Path(os.getenv('APPDATA')) / "Cursor" / "User" / "globalStorage" / "backups"
backup_dir.mkdir(parents=True, exist_ok=True)
backup_name = f"MachineGuid.backup_{datetime.now().strftime('%Y%m%d_%H%M%S')}"
with open(backup_dir / backup_name, 'w', encoding='utf-8') as f:
f.write(original_guid)
logging.info(f"备份 MachineGuid 到: {backup_name}")
# 重新打开写入权限
key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, registry_path, 0,
winreg.KEY_WRITE | winreg.KEY_WOW64_64KEY)
except WindowsError:
# 如果失败,尝试以管理员权限运行
import ctypes
if ctypes.windll.shell32.IsUserAnAdmin() == 0:
logging.warning("需要管理员权限来修改 MachineGuid")
return False
key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, registry_path, 0,
winreg.KEY_ALL_ACCESS | winreg.KEY_WOW64_64KEY)
# 设置新的 GUID
winreg.SetValueEx(key, "MachineGuid", 0, winreg.REG_SZ, new_guid)
winreg.CloseKey(key)
logging.info(f"更新系统 MachineGuid 成功: {new_guid}")
return True
except WindowsError as e:
logging.error(f"更新系统 MachineGuid 失败: {str(e)}")
return False
except Exception as e:
logging.error(f"更新 MachineGuid 过程出错: {str(e)}")
return False
def clean_registry(self) -> bool:
"""清理Cursor相关的注册表项
Returns:
bool: 是否成功
"""
try:
# 需要清理的注册表路径列表
registry_paths = [
r"Software\Classes\Directory\Background\shell\Cursor\command",
r"Software\Classes\Directory\Background\shell\Cursor",
r"Software\Cursor\Auth",
r"Software\Cursor\Updates",
r"Software\Cursor"
]
for path in registry_paths:
try:
winreg.DeleteKey(winreg.HKEY_CURRENT_USER, path)
logging.info(f"删除注册表项成功: {path}")
except WindowsError as e:
if e.winerror == 2: # 找不到注册表项
logging.info(f"注册表项不存在,无需清理: {path}")
else:
logging.error(f"清理注册表失败: {path}, 错误: {str(e)}")
# 更新系统 MachineGuid
self.update_machine_guid()
return True
except Exception as e:
logging.error(f"清理注册表过程出错: {str(e)}")
return False
def clean_cursor_files(self) -> bool:
"""清理Cursor相关的文件和目录但保留重要的配置和历史记录"""
try:
local_app_data = Path(os.getenv('LOCALAPPDATA'))
app_data = Path(os.getenv('APPDATA'))
# 需要备份的文件
storage_path = app_data / "Cursor" / "User" / "globalStorage" / "storage.json"
backup_dir = app_data / "Cursor" / "User" / "globalStorage" / "backups"
global_storage_dir = app_data / "Cursor" / "User" / "globalStorage"
# 如果存在 storage.json先备份
if storage_path.exists():
# 确保备份目录存在
backup_dir.mkdir(parents=True, exist_ok=True)
# 备份 storage.json
backup_name = f"storage.json.backup_{datetime.now().strftime('%Y%m%d_%H%M%S')}"
shutil.copy2(storage_path, backup_dir / backup_name)
logging.info(f"备份 storage.json 到: {backup_name}")
# 备份 global_storage 目录中的其他重要文件
if global_storage_dir.exists():
for item in global_storage_dir.iterdir():
if item.name != "storage.json" and item.name != "backups":
try:
backup_item_dir = backup_dir / f"other_files_{datetime.now().strftime('%Y%m%d_%H%M%S')}"
backup_item_dir.mkdir(exist_ok=True)
if item.is_file():
shutil.copy2(item, backup_item_dir / item.name)
logging.info(f"备份文件: {item.name}")
elif item.is_dir():
shutil.copytree(item, backup_item_dir / item.name)
logging.info(f"备份目录: {item.name}")
except Exception as e:
logging.error(f"备份 {item} 失败: {str(e)}")
# 读取当前内容
with open(storage_path, "r", encoding="utf-8") as f:
storage_data = json.load(f)
# 只修改 machineId保持其他配置不变
if "telemetry.machineId" in storage_data:
# 生成新的 machineId
new_machine_id = hashlib.sha256(str(uuid.uuid4()).encode()).hexdigest()
storage_data["telemetry.machineId"] = new_machine_id
logging.info(f"更新 machineId: {new_machine_id}")
# 保存修改后的内容
with open(storage_path, "w", encoding="utf-8") as f:
json.dump(storage_data, f, indent=2)
# 处理 updater 目录
updater_path = local_app_data / "cursor-updater"
try:
# 如果是目录,则删除
if updater_path.is_dir():
shutil.rmtree(str(updater_path))
logging.info("删除 updater 目录成功")
# 如果是文件,则删除
if updater_path.is_file():
updater_path.unlink()
logging.info("删除 updater 文件成功")
# 创建同名空文件来阻止更新
updater_path.touch()
logging.info("创建 updater 空文件成功")
except Exception as e:
logging.error(f"处理 updater 文件失败: {str(e)}")
# 只清理缓存相关的路径
paths_to_clean = [
local_app_data / "Cursor" / "Cache"
]
for path in paths_to_clean:
try:
if path.is_dir():
shutil.rmtree(str(path), ignore_errors=True)
logging.info(f"删除目录成功: {path}")
elif path.exists():
path.unlink()
logging.info(f"删除文件成功: {path}")
except Exception as e:
logging.error(f"清理文件/目录失败: {path}, 错误: {str(e)}")
# 修复 Cursor 启动配置
self.fix_cursor_startup()
return True
except Exception as e:
logging.error(f"清理文件过程出错: {str(e)}")
return False
def fix_cursor_startup(self) -> bool:
"""修复 Cursor 启动警告"""
try:
# 1. 修改 package.json 中的更新相关配置
if self.app_path.exists():
package_json = self.app_path / "package.json"
if package_json.exists():
with open(package_json, "r", encoding="utf-8") as f:
data = json.load(f)
# 只修改更新相关配置,与 GitHub 脚本保持一致
data["updateUrl"] = "" # 清空更新 URL
data["disableUpdate"] = True # 禁用更新
with open(package_json, "w", encoding="utf-8") as f:
json.dump(data, f, indent=2)
logging.info("已修复 Cursor 启动配置")
return True
except Exception as e:
logging.error(f"修复 Cursor 启动配置失败: {str(e)}")
return False