├── README.md └── reset_machine_id.py /README.md: -------------------------------------------------------------------------------- 1 | # Cursor 机器ID重置工具 2 | 3 | 一个简单易用的工具,帮助您重置 Cursor IDE 的机器ID,支持 Windows、macOS 和 Linux。 4 | 5 | ## 🚀 快速开始 6 | 7 | 1. 确保已安装 Python 3.6+ 8 | 2. 下载 Cursor IDE: 9 | 10 | **建议使用v1.0.0版本,最新版的机器码逻辑有更新,暂未兼容**(如需要使用新版功能,需要用1.0.0版本覆盖安装后,重置机器码,然后再用最新版覆盖安装) 11 | 12 | - [Linux (.deb)](https://github.com/adysec/cursor/releases/latest) - 支持 Ubuntu 24.04 AMD64 13 | - [Windows](https://cursor.com) 14 | - [macOS](https://cursor.com) 15 | 4. 运行重置工具: 16 | ```bash 17 | python reset_machine_id.py 18 | ``` 19 | 5. 按照提示完成操作 20 | 21 | ## ✨ 特性 22 | 23 | - ✅ 全平台支持(Windows/macOS/Linux) 24 | - 🔒 自动备份原始配置 25 | - 🛡️ 安全的数据处理 26 | - 📦 零依赖,开箱即用 27 | - 📝 详细的操作指引 28 | 29 | ## 📋 使用步骤 30 | 31 | 1. **注销账号** 32 | - 打开 Cursor 33 | - 点击左下角账号图标 34 | - 选择"Sign Out"或"登出" 35 | 36 | 2. **退出程序** 37 | - 确保 Cursor 完全退出 38 | - 程序会自动检查并关闭进程 39 | 40 | 3. **重置ID** 41 | - 程序自动生成新ID 42 | - 备份原始配置 43 | - 更新必要文件 44 | 45 | 4. **重新登录** 46 | - 访问 [Cursor官网](https://cursor.com) 47 | - 注销原账号 48 | - 注册新账号(可使用原账号) 49 | - 使用新账号登录 50 | 51 | ## BTW 52 | 53 | 无限邮箱 54 | 55 | Cloudflare => 托管域名yourdomain.com => 电子邮件 => 电子邮件路由 => 路由规则 => Catch-All 发送到电子邮件 username@gmail.com 56 | 57 | 58 | 59 | 60 | ## 🤝 贡献 61 | 62 | 欢迎提交 Issue 和 Pull Request 来改进这个工具。 63 | -------------------------------------------------------------------------------- /reset_machine_id.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | import json 4 | import uuid 5 | import hashlib 6 | import sqlite3 7 | import shutil 8 | import tempfile 9 | import configparser 10 | import subprocess 11 | import time 12 | from datetime import datetime 13 | from pathlib import Path 14 | from typing import Dict, Optional, Tuple, Union, NoReturn 15 | from dataclasses import dataclass 16 | 17 | # 内置配置 18 | DEFAULT_CONFIG = """ 19 | [WindowsPaths] 20 | storage_path = %APPDATA%\\Cursor\\User\\globalStorage\\storage.json 21 | sqlite_path = %APPDATA%\\Cursor\\User\\globalStorage\\state.vscdb 22 | cursor_path = %LOCALAPPDATA%\\Programs\\Cursor\\resources\\app 23 | 24 | [MacPaths] 25 | storage_path = ~/Library/Application Support/Cursor/User/globalStorage/storage.json 26 | sqlite_path = ~/Library/Application Support/Cursor/User/globalStorage/state.vscdb 27 | cursor_path = /Applications/Cursor.app/Contents/Resources/app 28 | 29 | [LinuxPaths] 30 | storage_path = ~/.config/cursor/User/globalStorage/storage.json 31 | sqlite_path = ~/.config/cursor/User/globalStorage/state.vscdb 32 | cursor_path = /usr/share/cursor/resources/app 33 | """ 34 | 35 | @dataclass 36 | class SystemPaths: 37 | """系统路径配置类""" 38 | storage_path: str 39 | sqlite_path: str 40 | cursor_path: str 41 | 42 | class ConfigManager: 43 | """配置管理类""" 44 | def __init__(self): 45 | self.config = configparser.ConfigParser() 46 | self._load_default_config() 47 | 48 | def _load_default_config(self) -> None: 49 | """加载默认配置""" 50 | self.config.read_string(DEFAULT_CONFIG) 51 | 52 | def get_system_paths(self) -> SystemPaths: 53 | """获取系统路径配置""" 54 | if sys.platform == "win32": 55 | section = 'WindowsPaths' 56 | elif sys.platform == "darwin": 57 | section = 'MacPaths' 58 | elif sys.platform == "linux": 59 | section = 'LinuxPaths' 60 | else: 61 | raise NotImplementedError(f"不支持的操作系统: {sys.platform}") 62 | 63 | return SystemPaths( 64 | storage_path=os.path.expandvars(os.path.expanduser(self.config.get(section, 'storage_path'))), 65 | sqlite_path=os.path.expandvars(os.path.expanduser(self.config.get(section, 'sqlite_path'))), 66 | cursor_path=os.path.expandvars(os.path.expanduser(self.config.get(section, 'cursor_path'))) 67 | ) 68 | 69 | class ProcessManager: 70 | """进程管理类""" 71 | @staticmethod 72 | def is_cursor_running() -> bool: 73 | """检查Cursor是否正在运行""" 74 | try: 75 | if sys.platform == "win32": 76 | result = subprocess.run(["tasklist", "/FI", "IMAGENAME eq cursor.exe"], 77 | capture_output=True, text=True) 78 | return "cursor.exe" in result.stdout 79 | else: 80 | cmd = "pgrep -f cursor" if sys.platform == "linux" else "pgrep -f Cursor" 81 | result = subprocess.run(cmd.split(), capture_output=True, text=True) 82 | return bool(result.stdout.strip()) 83 | except Exception: 84 | return False 85 | 86 | @staticmethod 87 | def terminate_cursor() -> None: 88 | """终止Cursor进程""" 89 | try: 90 | if sys.platform == "win32": 91 | subprocess.run(["taskkill", "/IM", "cursor.exe"], check=False) 92 | else: 93 | cmd = "pkill -f cursor" if sys.platform == "linux" else "pkill -f Cursor" 94 | subprocess.run(cmd.split(), check=False) 95 | except Exception as e: 96 | print(f"终止进程时出错: {str(e)}") 97 | 98 | class IDGenerator: 99 | """ID生成器类""" 100 | @staticmethod 101 | def generate_new_ids() -> Dict[str, str]: 102 | """生成新的机器ID""" 103 | dev_device_id = str(uuid.uuid4()) 104 | machine_id = hashlib.sha256(os.urandom(32)).hexdigest() 105 | mac_machine_id = hashlib.sha512(os.urandom(64)).hexdigest() 106 | sqm_id = "{" + str(uuid.uuid4()).upper() + "}" 107 | 108 | return { 109 | "telemetry.devDeviceId": dev_device_id, 110 | "telemetry.macMachineId": mac_machine_id, 111 | "telemetry.machineId": machine_id, 112 | "telemetry.sqmId": sqm_id, 113 | "storage.serviceMachineId": dev_device_id, 114 | } 115 | 116 | class DatabaseManager: 117 | """数据库管理类""" 118 | def __init__(self, sqlite_path: str): 119 | self.sqlite_path = sqlite_path 120 | 121 | def update_ids(self, new_ids: Dict[str, str]) -> bool: 122 | """更新SQLite数据库中的机器ID""" 123 | try: 124 | conn = sqlite3.connect(self.sqlite_path) 125 | cursor = conn.cursor() 126 | 127 | cursor.execute(""" 128 | CREATE TABLE IF NOT EXISTS ItemTable ( 129 | key TEXT PRIMARY KEY, 130 | value TEXT 131 | ) 132 | """) 133 | 134 | for key, value in new_ids.items(): 135 | cursor.execute(""" 136 | INSERT OR REPLACE INTO ItemTable (key, value) 137 | VALUES (?, ?) 138 | """, (key, value)) 139 | 140 | conn.commit() 141 | return True 142 | except Exception as e: 143 | print(f"SQLite数据库更新失败: {str(e)}") 144 | return False 145 | finally: 146 | if 'conn' in locals(): 147 | conn.close() 148 | 149 | class StorageManager: 150 | """存储管理类""" 151 | def __init__(self, storage_path: str): 152 | self.storage_path = Path(storage_path) 153 | self._ensure_storage_exists() 154 | 155 | def _ensure_storage_exists(self) -> None: 156 | """确保存储文件存在""" 157 | self.storage_path.parent.mkdir(parents=True, exist_ok=True) 158 | if not self.storage_path.exists(): 159 | with open(self.storage_path, 'w', encoding='utf-8') as f: 160 | json.dump({}, f) 161 | 162 | def backup_and_update(self, new_ids: Dict[str, str]) -> bool: 163 | """备份并更新存储文件""" 164 | try: 165 | # 创建备份 166 | timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") 167 | backup_path = f"{self.storage_path}.bak.{timestamp}" 168 | shutil.copy2(self.storage_path, backup_path) 169 | 170 | # 读取并更新配置 171 | with open(self.storage_path, "r", encoding="utf-8") as f: 172 | config = json.load(f) 173 | config.update(new_ids) 174 | 175 | # 保存新配置 176 | with open(self.storage_path, "w", encoding="utf-8") as f: 177 | json.dump(config, f, indent=4) 178 | return True 179 | except Exception as e: 180 | print(f"存储文件更新失败: {str(e)}") 181 | return False 182 | 183 | class MachineIDResetter: 184 | """机器ID重置主类""" 185 | def __init__(self): 186 | self.config_manager = ConfigManager() 187 | self.paths = self.config_manager.get_system_paths() 188 | self.process_manager = ProcessManager() 189 | self.id_generator = IDGenerator() 190 | self.db_manager = DatabaseManager(self.paths.sqlite_path) 191 | self.storage_manager = StorageManager(self.paths.storage_path) 192 | 193 | def logout_cursor(self) -> None: 194 | """注销Cursor账号""" 195 | print("\n第一步:注销Cursor账号") 196 | print("1. 打开Cursor") 197 | print("2. 点击左下角的账号图标") 198 | print("3. 选择'Sign Out'或'登出'") 199 | print("4. 确认登出") 200 | print("\n注意:") 201 | print("- 请确保完全登出账号,不要只是关闭窗口") 202 | print("- 登出后,您的账号将被注销") 203 | print("- 所有本地设置将被保留") 204 | input("\n完成上述步骤后,按回车键继续...") 205 | 206 | def exit_cursor(self) -> None: 207 | """优雅地退出Cursor程序""" 208 | print("\n第二步:退出Cursor程序") 209 | print("正在检查Cursor进程...") 210 | 211 | if self.process_manager.is_cursor_running(): 212 | print("发现正在运行的Cursor进程,正在尝试优雅关闭...") 213 | print("请在10秒内保存您的工作...") 214 | time.sleep(10) 215 | 216 | self.process_manager.terminate_cursor() 217 | time.sleep(2) 218 | 219 | if self.process_manager.is_cursor_running(): 220 | print("Cursor进程仍在运行,请手动关闭") 221 | 222 | input("\n确保Cursor已完全关闭后,按回车键继续...") 223 | 224 | def reset_machine_ids(self) -> bool: 225 | """重置机器ID""" 226 | print("\n第三步:重置机器ID") 227 | print("正在检查配置...") 228 | 229 | if not self.storage_manager.storage_path.exists(): 230 | print(f"找不到配置文件: {self.storage_manager.storage_path}") 231 | return False 232 | 233 | if not os.access(self.storage_manager.storage_path, os.R_OK | os.W_OK): 234 | print("没有读写配置文件的权限") 235 | return False 236 | 237 | print("正在生成新的机器ID...") 238 | new_ids = self.id_generator.generate_new_ids() 239 | 240 | # 更新存储文件 241 | if not self.storage_manager.backup_and_update(new_ids): 242 | return False 243 | 244 | # 更新数据库 245 | if not self.db_manager.update_ids(new_ids): 246 | return False 247 | 248 | print("机器ID重置成功!") 249 | print("\n新的机器ID:") 250 | for key, value in new_ids.items(): 251 | print(f"{key}: {value}") 252 | return True 253 | 254 | def show_login_instructions(self) -> None: 255 | """显示重新注册和登录的说明""" 256 | print("\n第四步:重新注册和登录Cursor") 257 | print("1. 访问Cursor官网 (https://cursor.sh)") 258 | print("2. 点击右上角头像,在'Account选项卡',找到'Advanced',选择'Delete Account'注销账号") 259 | print("3. 点击'Sign Up'注册新账号") 260 | print("4. 选择注册方式:") 261 | print(" - Google账号(推荐)") 262 | print(" - GitHub账号") 263 | print("5. 完成注册后,打开Cursor客户端") 264 | print("6. 点击左下角的账号图标") 265 | print("7. 选择'Sign In'或'登录'") 266 | print("8. 使用新注册的账号登录") 267 | input("\n完成上述步骤后,按回车键退出程序...") 268 | 269 | def main() -> None: 270 | try: 271 | print("\n" + "="*50) 272 | print("Cursor 机器ID重置工具") 273 | print("="*50) 274 | print("本工具将帮助您重置Cursor的机器ID") 275 | print("请按照以下步骤操作:") 276 | 277 | resetter = MachineIDResetter() 278 | resetter.logout_cursor() 279 | resetter.exit_cursor() 280 | 281 | if resetter.reset_machine_ids(): 282 | resetter.show_login_instructions() 283 | else: 284 | print("\n重置过程失败,请检查错误信息并重试。") 285 | 286 | except Exception as e: 287 | print(f"\n程序执行出错: {str(e)}") 288 | sys.exit(1) 289 | 290 | if __name__ == "__main__": 291 | main() 292 | --------------------------------------------------------------------------------