diff --git a/account_switcher.py b/account_switcher.py index 64c496c..ed2784e 100644 --- a/account_switcher.py +++ b/account_switcher.py @@ -105,8 +105,9 @@ class AccountSwitcher: Tuple[bool, str, Optional[Dict]]: (是否成功, 提示消息, 账号信息) """ try: - # 获取当前状态 + # 获取当前状态和历史记录 member_info = self.config.load_member_info() + activation_history = member_info.get("activation_records", []) if member_info else [] # 分割多个激活码 codes = [c.strip() for c in code.split(',')] @@ -182,16 +183,27 @@ class AccountSwitcher: # 使用最后一次激活的结果作为最终状态 final_result = activation_results[-1] - # 保存会员信息 + # 合并历史记录 + new_activation_records = final_result.get("activation_records", []) + if activation_history: + # 保留旧的激活记录,避免重复 + existing_codes = {record.get("code") for record in activation_history} + for record in new_activation_records: + if record.get("code") not in existing_codes: + activation_history.append(record) + else: + activation_history = new_activation_records + + # 保存会员信息,包含完整的历史记录 member_info = { "hardware_id": final_result.get("machine_id", self.hardware_id), "expire_time": final_result.get("expire_time", ""), - "days_left": final_result.get("days_left", 0), # 使用days_left - "total_days": final_result.get("total_days", 0), # 使用total_days + "days_left": final_result.get("days_left", 0), + "total_days": final_result.get("total_days", 0), "status": final_result.get("status", "inactive"), "device_info": final_result.get("device_info", device_info), "activation_time": final_result.get("activation_time", ""), - "activation_records": final_result.get("activation_records", []) # 保存激活记录 + "activation_records": activation_history # 使用合并后的历史记录 } self.config.save_member_info(member_info) @@ -201,8 +213,7 @@ class AccountSwitcher: # 显示每个成功激活码的信息 for i, result in enumerate(activation_results, 1): message += f"\n第{i}个激活码:\n" - message += f"- 新增天数: {result.get('added_days', 0)}天\n" # 使用added_days显示本次新增天数 - # 格式化时间显示 + message += f"- 新增天数: {result.get('added_days', 0)}天\n" activation_time = result.get('activation_time', '') if activation_time: try: @@ -214,8 +225,8 @@ class AccountSwitcher: message += f"- 激活时间: {activation_time}\n" message += f"\n最终状态:" - message += f"\n- 总天数: {final_result.get('total_days', 0)}天" # 累计总天数 - message += f"\n- 剩余天数: {final_result.get('days_left', 0)}天" # 剩余天数 + message += f"\n- 总天数: {final_result.get('total_days', 0)}天" + message += f"\n- 剩余天数: {final_result.get('days_left', 0)}天" # 格式化到期时间显示 expire_time = final_result.get('expire_time', '') @@ -227,9 +238,9 @@ class AccountSwitcher: pass message += f"\n- 到期时间: {expire_time}" - # 显示激活记录历史 + # 显示完整的激活记录历史 message += "\n\n历史激活记录:" - for record in final_result.get('activation_records', []): + for record in activation_history: activation_time = record.get('activation_time', '') if activation_time: try: @@ -248,11 +259,11 @@ class AccountSwitcher: except Exception as e: logging.error(f"处理激活结果时出错: {str(e)}") - return False, f"处理激活结果失败: {str(e)}", None + return False, f"处理激活结果时出错: {str(e)}", None except Exception as e: - logging.error(f"激活码验证过程出错: {str(e)}") - return False, f"激活失败: {str(e)}", None + logging.error(f"验证激活码时出错: {str(e)}") + return False, f"验证激活码时出错: {str(e)}", None def reset_machine_id(self) -> bool: """重置机器码""" @@ -262,7 +273,15 @@ class AccountSwitcher: os.system("taskkill /f /im Cursor.exe >nul 2>&1") time.sleep(2) - # 2. 删除 package.json 中的 machineId + # 2. 清理注册表(包括更新系统 MachineGuid) + if not self.registry.clean_registry(): + logging.warning("注册表清理失败") + + # 3. 清理文件(包括备份 storage.json) + if not self.registry.clean_cursor_files(): + logging.warning("文件清理失败") + + # 4. 修改 package.json 中的 machineId if self.package_json.exists(): with open(self.package_json, "r", encoding="utf-8") as f: data = json.load(f) @@ -273,67 +292,20 @@ class AccountSwitcher: with open(self.package_json, "w", encoding="utf-8") as f: json.dump(data, f, indent=2) - # 3. 清理特定的配置文件和缓存 - local_app_data = Path(os.getenv('LOCALAPPDATA')) - cursor_path = local_app_data / "Cursor" - - # 需要清理的目录 - cache_dirs = [ - cursor_path / "Cache", - cursor_path / "Code Cache", - cursor_path / "GPUCache", - cursor_path / "Local Storage" / "leveldb" - ] - - # 需要删除的配置文件 - config_files = [ - cursor_path / "User" / "globalStorage" / "storage.json", - cursor_path / "User" / "globalStorage" / "state.json", - self.app_path / "config.json", - self.app_path / "state.json", - self.app_path / "settings.json" - ] - - # 清理缓存目录 - for dir_path in cache_dirs: - if dir_path.exists(): - try: - import shutil - shutil.rmtree(str(dir_path)) - logging.info(f"清理目录成功: {dir_path}") - except Exception as e: - logging.warning(f"清理目录失败: {dir_path}, 错误: {str(e)}") - - # 删除配置文件 - for file_path in config_files: - if file_path.exists(): - try: - os.remove(file_path) - logging.info(f"删除配置文件成功: {file_path}") - except Exception as e: - logging.warning(f"删除配置文件失败: {file_path}, 错误: {str(e)}") - - # 4. 刷新注册表 - if not self.registry.refresh_registry(): - logging.warning("注册表刷新失败") - - # 5. 删除卸载注册表项 - try: - import winreg - with winreg.OpenKey(winreg.HKEY_CURRENT_USER, r"Software\Microsoft\Windows\CurrentVersion\Uninstall", 0, winreg.KEY_ALL_ACCESS) as key: - # 遍历所有子键,找到Cursor相关的 - i = 0 - while True: - try: - subkey_name = winreg.EnumKey(key, i) - if "Cursor" in subkey_name: - winreg.DeleteKey(key, subkey_name) - logging.info(f"删除注册表项成功: {subkey_name}") - i += 1 - except WindowsError: - break - except Exception as e: - logging.warning(f"删除注册表项失败: {str(e)}") + # 5. 修改 storage.json 中的遥测 ID + storage_path = Path(os.getenv('APPDATA')) / "Cursor" / "User" / "globalStorage" / "storage.json" + if storage_path.exists(): + with open(storage_path, "r", encoding="utf-8") as f: + storage_data = json.load(f) + + # 只修改 machineId,保持其他遥测 ID 不变 + if "telemetry.machineId" in storage_data: + # 生成新的 machineId(使用与 GitHub 脚本类似的格式) + new_machine_id = hashlib.sha256(str(uuid.uuid4()).encode()).hexdigest() + storage_data["telemetry.machineId"] = new_machine_id + + with open(storage_path, "w", encoding="utf-8") as f: + json.dump(storage_data, f, indent=2) # 6. 重启Cursor cursor_exe = self.cursor_path / "Cursor.exe" @@ -523,7 +495,12 @@ class AccountSwitcher: Tuple[bool, str]: (是否成功, 提示消息) """ try: - # 获取未使用的账号 + # 1. 先关闭所有Cursor进程 + if sys.platform == "win32": + os.system("taskkill /f /im Cursor.exe >nul 2>&1") + time.sleep(2) + + # 2. 获取未使用的账号 endpoint = "https://cursorapi.nosqli.com/admin/api.account/getUnused" data = { "machine_id": self.hardware_id @@ -559,26 +536,14 @@ class AccountSwitcher: if not all([email, access_token, refresh_token]): return False, "获取账号信息不完整" - # 更新Cursor认证信息 + # 3. 更新Cursor认证信息 if not self.auth_manager.update_auth(email, access_token, refresh_token): return False, "更新Cursor认证信息失败" - # 重置机器码 + # 4. 重置机器码(包含了清理注册表、文件和重启操作) if not self.reset_machine_id(): return False, "重置机器码失败" - # 刷新注册表 - if not self.registry.refresh_registry(): - logging.warning("注册表刷新失败,但不影响主要功能") - - # 重启Cursor - if not self.auth_manager.restart_cursor(): - return False, "重启Cursor失败" - # 重启Cursor - # if not self.restart_cursor(): - # logging.warning("Cursor重启失败,请手动重启") - # return True, f"授权刷新成功,请手动重启Cursor编辑器\n邮箱: {email}\n到期时间: {expire_time}\n剩余天数: {days_left}天" - return True, f"授权刷新成功,Cursor编辑器已重启\n邮箱: {email}\n" elif response_data.get("code") == 404: diff --git a/after_github_reset.json b/after_github_reset.json new file mode 100644 index 0000000..2f08546 --- /dev/null +++ b/after_github_reset.json @@ -0,0 +1,202 @@ +{ + "package_json": { + "C:\\Users\\huangzhen\\AppData\\Local\\Programs\\Cursor\\resources\\app\\package.json": { + "homepage": "https://cursor.so", + "author": { + "name": "Cursor AI, Inc.", + "email": "hiring@cursor.so" + }, + "productName": "Cursor", + "description": "Cursor is an AI-first coding environment.", + "main": "./out/main.js", + "dependencies": { + "@todesktop/runtime": "=1.6.1", + "@electron/asar": "^3.2.3", + "@anysphere/file-service": "0.0.0-73d604b6", + "@microsoft/1ds-core-js": "^3.2.13", + "@microsoft/1ds-post-js": "^3.2.13", + "@parcel/watcher": "2.5.0", + "@sentry/electron": "5.7.0", + "@sentry/node": "8.35.0", + "@types/semver": "^7.5.8", + "@vscode/deviceid": "^0.1.1", + "@vscode/iconv-lite-umd": "0.7.0", + "@vscode/policy-watcher": "^1.1.8", + "@vscode/proxy-agent": "^0.27.0", + "@vscode/ripgrep": "^1.15.10", + "@vscode/spdlog": "^0.15.0", + "@vscode/sqlite3": "5.1.8-vscode", + "@vscode/sudo-prompt": "9.3.1", + "@vscode/tree-sitter-wasm": "^0.0.4", + "@vscode/vscode-languagedetection": "1.0.21", + "@vscode/windows-mutex": "^0.5.0", + "@vscode/windows-process-tree": "^0.6.0", + "@vscode/windows-registry": "^1.1.0", + "@xterm/addon-clipboard": "^0.2.0-beta.53", + "@xterm/addon-image": "^0.9.0-beta.70", + "@xterm/addon-ligatures": "^0.10.0-beta.70", + "@xterm/addon-search": "^0.16.0-beta.70", + "@xterm/addon-serialize": "^0.14.0-beta.70", + "@xterm/addon-unicode11": "^0.9.0-beta.70", + "@xterm/addon-webgl": "^0.19.0-beta.70", + "@xterm/headless": "^5.6.0-beta.70", + "@xterm/xterm": "^5.6.0-beta.70", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.2", + "jschardet": "3.1.4", + "kerberos": "2.1.1", + "minimist": "^1.2.6", + "multiformats": "^13.3.1", + "native-is-elevated": "0.7.0", + "native-keymap": "^3.3.5", + "native-watchdog": "^1.4.1", + "node-fetch": "2.7.0", + "node-pty": "1.1.0-beta22", + "open": "^8.4.2", + "tas-client-umd": "0.2.0", + "v8-inspect-profiler": "^0.1.1", + "vscode-oniguruma": "1.7.0", + "vscode-regexpp": "^3.1.0", + "vscode-textmate": "9.1.0", + "yauzl": "^3.0.0", + "yazl": "^2.4.3" + }, + "name": "cursor", + "version": "0.45.11", + "type": "module", + "desktopName": "cursor-url-handler.desktop", + "overrides": {}, + "tdBuildId": "250207y6nbaw5qc", + "email": "jrxqnsoz250264@nosqli.com", + "accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJhdXRoMHx1c2VyXzAxSktTUEJLQlIxOTNKMjY3RENSVDRTR1YyIiwidGltZSI6IjE3MzkyNTAzNDgiLCJyYW5kb21uZXNzIjoiYWIyNWVhYTYtNDQzZC00Y2Q0IiwiZXhwIjo0MzMxMjUwMzQ4LCJpc3MiOiJodHRwczovL2F1dGhlbnRpY2F0aW9uLmN1cnNvci5zaCIsInNjb3BlIjoib3BlbmlkIHByb2ZpbGUgZW1haWwgb2ZmbGluZV9hY2Nlc3MiLCJhdWQiOiJodHRwczovL2N1cnNvci5jb20ifQ.f3VIttCJLWqhkEZpPmWJlYw32FuV_gLWl9E0N-O9oIc", + "refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJhdXRoMHx1c2VyXzAxSktTUEJLQlIxOTNKMjY3RENSVDRTR1YyIiwidGltZSI6IjE3MzkyNTAzNDgiLCJyYW5kb21uZXNzIjoiYWIyNWVhYTYtNDQzZC00Y2Q0IiwiZXhwIjo0MzMxMjUwMzQ4LCJpc3MiOiJodHRwczovL2F1dGhlbnRpY2F0aW9uLmN1cnNvci5zaCIsInNjb3BlIjoib3BlbmlkIHByb2ZpbGUgZW1haWwgb2ZmbGluZV9hY2Nlc3MiLCJhdWQiOiJodHRwczovL2N1cnNvci5jb20ifQ.f3VIttCJLWqhkEZpPmWJlYw32FuV_gLWl9E0N-O9oIc" + } + }, + "storage_json": { + "telemetry.machineId": "758a7f7f7f79078f9f2c690514878ea3e8f064c0a49e837dd396db89df58429c", + "telemetry.macMachineId": "ff2a4a580f6e9e484c830204bb502866e9a333d3e0299ef81c34e01940da953e", + "telemetry.sqmId": "{D73E6881-666C-4182-8CB2-E2A3EED5AEFF}", + "telemetry.devDeviceId": "1ae7f91c-3ab8-448c-bbd3-ef34345a5b05", + "backupWorkspaces": { + "workspaces": [], + "folders": [ + { + "folderUri": "file:///d%3A/W/python/001cursro.app/interactive" + } + ], + "emptyWindows": [ + { + "backupFolder": "1739332115293" + } + ] + }, + "windowControlHeight": 35, + "profileAssociations": { + "workspaces": { + "file:///d%3A/W/python/001cursro.app/interactive": "__default__profile__" + }, + "emptyWindows": { + "1739332115293": "__default__profile__" + } + }, + "theme": "vs-dark", + "themeBackground": "#1f1f1f", + "windowSplash": { + "zoomLevel": 0, + "baseTheme": "vs-dark", + "colorInfo": { + "foreground": "#cccccc", + "background": "#1f1f1f", + "editorBackground": "#1f1f1f", + "titleBarBackground": "#181818", + "titleBarBorder": "#2b2b2b", + "activityBarBackground": "#181818", + "activityBarBorder": "#2b2b2b", + "sideBarBackground": "#181818", + "sideBarBorder": "#2b2b2b", + "statusBarBackground": "#181818", + "statusBarBorder": "#2b2b2b", + "statusBarNoFolderBackground": "#1f1f1f" + }, + "layoutInfo": { + "sideBarSide": "left", + "editorPartMinWidth": 220, + "titleBarHeight": 35, + "activityBarWidth": 0, + "sideBarWidth": 170, + "statusBarHeight": 22, + "windowBorder": false + } + } + }, + "registry": { + "HKLM_MachineGuid": { + "exists": true, + "value": "776c6b6c-195f-42dc-94d6-72b70c3aca74" + }, + "HKCU_cursor_shell": { + "exists": false, + "values": {} + }, + "HKCU_cursor_command": { + "exists": false, + "values": {} + }, + "HKCU_cursor_auth": { + "exists": false, + "values": {} + }, + "HKCU_cursor_updates": { + "exists": false, + "values": {} + }, + "HKCU_cursor_main": { + "exists": false, + "values": {} + } + }, + "files": { + "storage": { + "exists": true, + "is_dir": false, + "size": 1891, + "modified_time": "2025-02-12T11:48:42.627574" + }, + "storage_backup": { + "exists": true, + "is_dir": true, + "size": null, + "modified_time": "2025-02-12T11:48:26.403770" + }, + "user_data": { + "exists": false, + "is_dir": null, + "size": null, + "modified_time": null + }, + "global_storage": { + "exists": true, + "is_dir": true, + "size": null, + "modified_time": "2025-02-12T11:48:47.490659" + }, + "cache": { + "exists": false, + "is_dir": null, + "size": null, + "modified_time": null + }, + "updater": { + "exists": true, + "is_dir": false, + "size": 0, + "modified_time": "2025-02-10T17:19:39.071580" + } + }, + "telemetry": { + "machineId": "758a7f7f7f79078f9f2c690514878ea3e8f064c0a49e837dd396db89df58429c", + "macMachineId": "ff2a4a580f6e9e484c830204bb502866e9a333d3e0299ef81c34e01940da953e", + "devDeviceId": "1ae7f91c-3ab8-448c-bbd3-ef34345a5b05", + "sqmId": "{D73E6881-666C-4182-8CB2-E2A3EED5AEFF}" + } +} \ No newline at end of file diff --git a/after_our_reset.json b/after_our_reset.json new file mode 100644 index 0000000..cdf12a2 --- /dev/null +++ b/after_our_reset.json @@ -0,0 +1,216 @@ +{ + "package_json": { + "C:\\Users\\huangzhen\\AppData\\Local\\Programs\\Cursor\\resources\\app\\package.json": { + "homepage": "https://cursor.so", + "author": { + "name": "Cursor AI, Inc.", + "email": "hiring@cursor.so" + }, + "productName": "Cursor", + "description": "Cursor is an AI-first coding environment.", + "main": "./out/main.js", + "dependencies": { + "@todesktop/runtime": "=1.6.1", + "@electron/asar": "^3.2.3", + "@anysphere/file-service": "0.0.0-73d604b6", + "@microsoft/1ds-core-js": "^3.2.13", + "@microsoft/1ds-post-js": "^3.2.13", + "@parcel/watcher": "2.5.0", + "@sentry/electron": "5.7.0", + "@sentry/node": "8.35.0", + "@types/semver": "^7.5.8", + "@vscode/deviceid": "^0.1.1", + "@vscode/iconv-lite-umd": "0.7.0", + "@vscode/policy-watcher": "^1.1.8", + "@vscode/proxy-agent": "^0.27.0", + "@vscode/ripgrep": "^1.15.10", + "@vscode/spdlog": "^0.15.0", + "@vscode/sqlite3": "5.1.8-vscode", + "@vscode/sudo-prompt": "9.3.1", + "@vscode/tree-sitter-wasm": "^0.0.4", + "@vscode/vscode-languagedetection": "1.0.21", + "@vscode/windows-mutex": "^0.5.0", + "@vscode/windows-process-tree": "^0.6.0", + "@vscode/windows-registry": "^1.1.0", + "@xterm/addon-clipboard": "^0.2.0-beta.53", + "@xterm/addon-image": "^0.9.0-beta.70", + "@xterm/addon-ligatures": "^0.10.0-beta.70", + "@xterm/addon-search": "^0.16.0-beta.70", + "@xterm/addon-serialize": "^0.14.0-beta.70", + "@xterm/addon-unicode11": "^0.9.0-beta.70", + "@xterm/addon-webgl": "^0.19.0-beta.70", + "@xterm/headless": "^5.6.0-beta.70", + "@xterm/xterm": "^5.6.0-beta.70", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.2", + "jschardet": "3.1.4", + "kerberos": "2.1.1", + "minimist": "^1.2.6", + "multiformats": "^13.3.1", + "native-is-elevated": "0.7.0", + "native-keymap": "^3.3.5", + "native-watchdog": "^1.4.1", + "node-fetch": "2.7.0", + "node-pty": "1.1.0-beta22", + "open": "^8.4.2", + "tas-client-umd": "0.2.0", + "v8-inspect-profiler": "^0.1.1", + "vscode-oniguruma": "1.7.0", + "vscode-regexpp": "^3.1.0", + "vscode-textmate": "9.1.0", + "yauzl": "^3.0.0", + "yazl": "^2.4.3" + }, + "name": "cursor", + "version": "0.45.11", + "type": "module", + "desktopName": "cursor-url-handler.desktop", + "overrides": {}, + "tdBuildId": "250207y6nbaw5qc", + "email": "jrxqnsoz250264@nosqli.com", + "accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJhdXRoMHx1c2VyXzAxSktTUEJLQlIxOTNKMjY3RENSVDRTR1YyIiwidGltZSI6IjE3MzkyNTAzNDgiLCJyYW5kb21uZXNzIjoiYWIyNWVhYTYtNDQzZC00Y2Q0IiwiZXhwIjo0MzMxMjUwMzQ4LCJpc3MiOiJodHRwczovL2F1dGhlbnRpY2F0aW9uLmN1cnNvci5zaCIsInNjb3BlIjoib3BlbmlkIHByb2ZpbGUgZW1haWwgb2ZmbGluZV9hY2Nlc3MiLCJhdWQiOiJodHRwczovL2N1cnNvci5jb20ifQ.f3VIttCJLWqhkEZpPmWJlYw32FuV_gLWl9E0N-O9oIc", + "refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJhdXRoMHx1c2VyXzAxSktTUEJLQlIxOTNKMjY3RENSVDRTR1YyIiwidGltZSI6IjE3MzkyNTAzNDgiLCJyYW5kb21uZXNzIjoiYWIyNWVhYTYtNDQzZC00Y2Q0IiwiZXhwIjo0MzMxMjUwMzQ4LCJpc3MiOiJodHRwczovL2F1dGhlbnRpY2F0aW9uLmN1cnNvci5zaCIsInNjb3BlIjoib3BlbmlkIHByb2ZpbGUgZW1haWwgb2ZmbGluZV9hY2Nlc3MiLCJhdWQiOiJodHRwczovL2N1cnNvci5jb20ifQ.f3VIttCJLWqhkEZpPmWJlYw32FuV_gLWl9E0N-O9oIc", + "updateUrl": "", + "disableUpdate": true, + "enableNodeApiUncaughtExceptionPolicy": true, + "nodeOptions": [ + "--force-node-api-uncaught-exceptions-policy=true" + ] + } + }, + "storage_json": { + "telemetry.machineId": "b0cbb2d13ca4c983be40d31e010819f16adb3d6083598f1457094837bdaa3def", + "telemetry.macMachineId": "ff2a4a580f6e9e484c830204bb502866e9a333d3e0299ef81c34e01940da953e", + "telemetry.sqmId": "{D73E6881-666C-4182-8CB2-E2A3EED5AEFF}", + "telemetry.devDeviceId": "1ae7f91c-3ab8-448c-bbd3-ef34345a5b05", + "backupWorkspaces": { + "workspaces": [], + "folders": [ + { + "folderUri": "file:///d%3A/W/python/001cursro.app/interactive" + } + ], + "emptyWindows": [] + }, + "windowControlHeight": 35, + "profileAssociations": { + "workspaces": { + "file:///d%3A/W/python/001cursro.app/interactive": "__default__profile__" + }, + "emptyWindows": {} + }, + "theme": "vs-dark", + "themeBackground": "#1f1f1f", + "windowSplash": { + "zoomLevel": 0, + "baseTheme": "vs-dark", + "colorInfo": { + "foreground": "#cccccc", + "background": "#1f1f1f", + "editorBackground": "#1f1f1f", + "titleBarBackground": "#181818", + "titleBarBorder": "#2b2b2b", + "activityBarBackground": "#181818", + "activityBarBorder": "#2b2b2b", + "sideBarBackground": "#181818", + "sideBarBorder": "#2b2b2b", + "statusBarBackground": "#181818", + "statusBarBorder": "#2b2b2b", + "statusBarNoFolderBackground": "#1f1f1f" + }, + "layoutInfo": { + "sideBarSide": "left", + "editorPartMinWidth": 220, + "titleBarHeight": 35, + "activityBarWidth": 0, + "sideBarWidth": 300, + "statusBarHeight": 22, + "windowBorder": false + } + }, + "windowsState": { + "lastActiveWindow": { + "folder": "file:///d%3A/W/python/001cursro.app/interactive", + "backupPath": "C:\\Users\\huangzhen\\AppData\\Roaming\\Cursor\\Backups\\385f155a4a13070be99ee4e76a057235", + "uiState": { + "mode": 0, + "x": 512, + "y": 192, + "width": 1024, + "height": 768 + } + }, + "openedWindows": [] + } + }, + "registry": { + "HKLM_MachineGuid": { + "exists": true, + "value": "1deb25e7-cdd4-4367-a347-fba8b33b9b03" + }, + "HKCU_cursor_shell": { + "exists": false, + "values": {} + }, + "HKCU_cursor_command": { + "exists": false, + "values": {} + }, + "HKCU_cursor_auth": { + "exists": false, + "values": {} + }, + "HKCU_cursor_updates": { + "exists": false, + "values": {} + }, + "HKCU_cursor_main": { + "exists": false, + "values": {} + } + }, + "files": { + "storage": { + "exists": true, + "is_dir": false, + "size": 1980, + "modified_time": "2025-02-12T12:37:17.428609" + }, + "storage_backup": { + "exists": true, + "is_dir": true, + "size": null, + "modified_time": "2025-02-12T12:37:17.371311" + }, + "user_data": { + "exists": false, + "is_dir": null, + "size": null, + "modified_time": null + }, + "global_storage": { + "exists": true, + "is_dir": true, + "size": null, + "modified_time": "2025-02-12T12:37:14.253083" + }, + "cache": { + "exists": false, + "is_dir": null, + "size": null, + "modified_time": null + }, + "updater": { + "exists": true, + "is_dir": false, + "size": 0, + "modified_time": "2025-02-10T17:19:39.071580" + } + }, + "telemetry": { + "machineId": "b0cbb2d13ca4c983be40d31e010819f16adb3d6083598f1457094837bdaa3def", + "macMachineId": "ff2a4a580f6e9e484c830204bb502866e9a333d3e0299ef81c34e01940da953e", + "devDeviceId": "1ae7f91c-3ab8-448c-bbd3-ef34345a5b05", + "sqmId": "{D73E6881-666C-4182-8CB2-E2A3EED5AEFF}" + } +} \ No newline at end of file diff --git a/before_github_reset.json b/before_github_reset.json new file mode 100644 index 0000000..6097539 --- /dev/null +++ b/before_github_reset.json @@ -0,0 +1,244 @@ +{ + "package_json": { + "C:\\Users\\huangzhen\\AppData\\Local\\Programs\\Cursor\\resources\\app\\package.json": { + "homepage": "https://cursor.so", + "author": { + "name": "Cursor AI, Inc.", + "email": "hiring@cursor.so" + }, + "productName": "Cursor", + "description": "Cursor is an AI-first coding environment.", + "main": "./out/main.js", + "dependencies": { + "@todesktop/runtime": "=1.6.1", + "@electron/asar": "^3.2.3", + "@anysphere/file-service": "0.0.0-73d604b6", + "@microsoft/1ds-core-js": "^3.2.13", + "@microsoft/1ds-post-js": "^3.2.13", + "@parcel/watcher": "2.5.0", + "@sentry/electron": "5.7.0", + "@sentry/node": "8.35.0", + "@types/semver": "^7.5.8", + "@vscode/deviceid": "^0.1.1", + "@vscode/iconv-lite-umd": "0.7.0", + "@vscode/policy-watcher": "^1.1.8", + "@vscode/proxy-agent": "^0.27.0", + "@vscode/ripgrep": "^1.15.10", + "@vscode/spdlog": "^0.15.0", + "@vscode/sqlite3": "5.1.8-vscode", + "@vscode/sudo-prompt": "9.3.1", + "@vscode/tree-sitter-wasm": "^0.0.4", + "@vscode/vscode-languagedetection": "1.0.21", + "@vscode/windows-mutex": "^0.5.0", + "@vscode/windows-process-tree": "^0.6.0", + "@vscode/windows-registry": "^1.1.0", + "@xterm/addon-clipboard": "^0.2.0-beta.53", + "@xterm/addon-image": "^0.9.0-beta.70", + "@xterm/addon-ligatures": "^0.10.0-beta.70", + "@xterm/addon-search": "^0.16.0-beta.70", + "@xterm/addon-serialize": "^0.14.0-beta.70", + "@xterm/addon-unicode11": "^0.9.0-beta.70", + "@xterm/addon-webgl": "^0.19.0-beta.70", + "@xterm/headless": "^5.6.0-beta.70", + "@xterm/xterm": "^5.6.0-beta.70", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.2", + "jschardet": "3.1.4", + "kerberos": "2.1.1", + "minimist": "^1.2.6", + "multiformats": "^13.3.1", + "native-is-elevated": "0.7.0", + "native-keymap": "^3.3.5", + "native-watchdog": "^1.4.1", + "node-fetch": "2.7.0", + "node-pty": "1.1.0-beta22", + "open": "^8.4.2", + "tas-client-umd": "0.2.0", + "v8-inspect-profiler": "^0.1.1", + "vscode-oniguruma": "1.7.0", + "vscode-regexpp": "^3.1.0", + "vscode-textmate": "9.1.0", + "yauzl": "^3.0.0", + "yazl": "^2.4.3" + }, + "name": "cursor", + "version": "0.45.11", + "type": "module", + "desktopName": "cursor-url-handler.desktop", + "overrides": {}, + "tdBuildId": "250207y6nbaw5qc", + "email": "jrxqnsoz250264@nosqli.com", + "accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJhdXRoMHx1c2VyXzAxSktTUEJLQlIxOTNKMjY3RENSVDRTR1YyIiwidGltZSI6IjE3MzkyNTAzNDgiLCJyYW5kb21uZXNzIjoiYWIyNWVhYTYtNDQzZC00Y2Q0IiwiZXhwIjo0MzMxMjUwMzQ4LCJpc3MiOiJodHRwczovL2F1dGhlbnRpY2F0aW9uLmN1cnNvci5zaCIsInNjb3BlIjoib3BlbmlkIHByb2ZpbGUgZW1haWwgb2ZmbGluZV9hY2Nlc3MiLCJhdWQiOiJodHRwczovL2N1cnNvci5jb20ifQ.f3VIttCJLWqhkEZpPmWJlYw32FuV_gLWl9E0N-O9oIc", + "refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJhdXRoMHx1c2VyXzAxSktTUEJLQlIxOTNKMjY3RENSVDRTR1YyIiwidGltZSI6IjE3MzkyNTAzNDgiLCJyYW5kb21uZXNzIjoiYWIyNWVhYTYtNDQzZC00Y2Q0IiwiZXhwIjo0MzMxMjUwMzQ4LCJpc3MiOiJodHRwczovL2F1dGhlbnRpY2F0aW9uLmN1cnNvci5zaCIsInNjb3BlIjoib3BlbmlkIHByb2ZpbGUgZW1haWwgb2ZmbGluZV9hY2Nlc3MiLCJhdWQiOiJodHRwczovL2N1cnNvci5jb20ifQ.f3VIttCJLWqhkEZpPmWJlYw32FuV_gLWl9E0N-O9oIc" + } + }, + "storage_json": { + "telemetry.machineId": "31b3701f1790cdb754bd8a02bad4913a9f8a3f04c9e19c519996be8c7b8cb561", + "telemetry.macMachineId": "ff2a4a580f6e9e484c830204bb502866e9a333d3e0299ef81c34e01940da953e", + "telemetry.sqmId": "{D73E6881-666C-4182-8CB2-E2A3EED5AEFF}", + "telemetry.devDeviceId": "1ae7f91c-3ab8-448c-bbd3-ef34345a5b05", + "backupWorkspaces": { + "workspaces": [], + "folders": [ + { + "folderUri": "file:///d%3A/W/python/001cursro.app/interactive" + }, + { + "folderUri": "file:///d%3A/W/python/003cursorapiadmin" + } + ], + "emptyWindows": [ + { + "backupFolder": "1739329218500" + }, + { + "backupFolder": "1739329245089" + } + ] + }, + "windowControlHeight": 35, + "profileAssociations": { + "workspaces": { + "file:///d%3A/W/python/001cursro.app/interactive": "__default__profile__", + "file:///d%3A/W/python/003cursorapiadmin": "__default__profile__" + }, + "emptyWindows": {} + }, + "theme": "vs-dark", + "themeBackground": "#1f1f1f", + "windowSplash": { + "zoomLevel": 0, + "baseTheme": "vs-dark", + "colorInfo": { + "foreground": "#cccccc", + "background": "#1f1f1f", + "editorBackground": "#1f1f1f", + "titleBarBackground": "#181818", + "titleBarBorder": "#2b2b2b", + "activityBarBackground": "#181818", + "activityBarBorder": "#2b2b2b", + "sideBarBackground": "#181818", + "sideBarBorder": "#2b2b2b", + "statusBarBackground": "#181818", + "statusBarBorder": "#2b2b2b", + "statusBarNoFolderBackground": "#1f1f1f" + }, + "layoutInfo": { + "sideBarSide": "left", + "editorPartMinWidth": 220, + "titleBarHeight": 35, + "activityBarWidth": 0, + "sideBarWidth": 170, + "statusBarHeight": 22, + "windowBorder": false + } + }, + "windowsState": { + "lastActiveWindow": { + "folder": "file:///d%3A/W/python/001cursro.app/interactive", + "backupPath": "C:\\Users\\huangzhen\\AppData\\Roaming\\Cursor\\Backups\\385f155a4a13070be99ee4e76a057235", + "uiState": { + "mode": 0, + "x": 512, + "y": 192, + "width": 1024, + "height": 768 + } + }, + "openedWindows": [ + { + "folder": "file:///d%3A/W/python/001cursro.app/interactive", + "backupPath": "C:\\Users\\huangzhen\\AppData\\Roaming\\Cursor\\Backups\\385f155a4a13070be99ee4e76a057235", + "uiState": { + "mode": 0, + "x": 512, + "y": 192, + "width": 1024, + "height": 768 + } + }, + { + "folder": "file:///d%3A/W/python/003cursorapiadmin", + "backupPath": "C:\\Users\\huangzhen\\AppData\\Roaming\\Cursor\\Backups\\b6b8cfb24ed2ddb05d90d45cce5443e7", + "uiState": { + "mode": 0, + "x": 512, + "y": 192, + "width": 1024, + "height": 768 + } + } + ] + } + }, + "registry": { + "HKLM_MachineGuid": { + "exists": true, + "value": "d890ab3d-43cd-40c8-a9ef-f5683b5a64e3" + }, + "HKCU_cursor_shell": { + "exists": false, + "values": {} + }, + "HKCU_cursor_command": { + "exists": false, + "values": {} + }, + "HKCU_cursor_auth": { + "exists": false, + "values": {} + }, + "HKCU_cursor_updates": { + "exists": false, + "values": {} + }, + "HKCU_cursor_main": { + "exists": false, + "values": {} + } + }, + "files": { + "storage": { + "exists": true, + "is_dir": false, + "size": 3427, + "modified_time": "2025-02-12T11:40:57.046415" + }, + "storage_backup": { + "exists": true, + "is_dir": true, + "size": null, + "modified_time": "2025-02-12T11:00:01.555876" + }, + "user_data": { + "exists": false, + "is_dir": null, + "size": null, + "modified_time": null + }, + "global_storage": { + "exists": true, + "is_dir": true, + "size": null, + "modified_time": "2025-02-12T11:47:27.627883" + }, + "cache": { + "exists": false, + "is_dir": null, + "size": null, + "modified_time": null + }, + "updater": { + "exists": true, + "is_dir": false, + "size": 0, + "modified_time": "2025-02-10T17:19:39.071580" + } + }, + "telemetry": { + "machineId": "31b3701f1790cdb754bd8a02bad4913a9f8a3f04c9e19c519996be8c7b8cb561", + "macMachineId": "ff2a4a580f6e9e484c830204bb502866e9a333d3e0299ef81c34e01940da953e", + "devDeviceId": "1ae7f91c-3ab8-448c-bbd3-ef34345a5b05", + "sqmId": "{D73E6881-666C-4182-8CB2-E2A3EED5AEFF}" + } +} \ No newline at end of file diff --git a/before_our_reset.json b/before_our_reset.json new file mode 100644 index 0000000..c646f07 --- /dev/null +++ b/before_our_reset.json @@ -0,0 +1,216 @@ +{ + "package_json": { + "C:\\Users\\huangzhen\\AppData\\Local\\Programs\\Cursor\\resources\\app\\package.json": { + "homepage": "https://cursor.so", + "author": { + "name": "Cursor AI, Inc.", + "email": "hiring@cursor.so" + }, + "productName": "Cursor", + "description": "Cursor is an AI-first coding environment.", + "main": "./out/main.js", + "dependencies": { + "@todesktop/runtime": "=1.6.1", + "@electron/asar": "^3.2.3", + "@anysphere/file-service": "0.0.0-73d604b6", + "@microsoft/1ds-core-js": "^3.2.13", + "@microsoft/1ds-post-js": "^3.2.13", + "@parcel/watcher": "2.5.0", + "@sentry/electron": "5.7.0", + "@sentry/node": "8.35.0", + "@types/semver": "^7.5.8", + "@vscode/deviceid": "^0.1.1", + "@vscode/iconv-lite-umd": "0.7.0", + "@vscode/policy-watcher": "^1.1.8", + "@vscode/proxy-agent": "^0.27.0", + "@vscode/ripgrep": "^1.15.10", + "@vscode/spdlog": "^0.15.0", + "@vscode/sqlite3": "5.1.8-vscode", + "@vscode/sudo-prompt": "9.3.1", + "@vscode/tree-sitter-wasm": "^0.0.4", + "@vscode/vscode-languagedetection": "1.0.21", + "@vscode/windows-mutex": "^0.5.0", + "@vscode/windows-process-tree": "^0.6.0", + "@vscode/windows-registry": "^1.1.0", + "@xterm/addon-clipboard": "^0.2.0-beta.53", + "@xterm/addon-image": "^0.9.0-beta.70", + "@xterm/addon-ligatures": "^0.10.0-beta.70", + "@xterm/addon-search": "^0.16.0-beta.70", + "@xterm/addon-serialize": "^0.14.0-beta.70", + "@xterm/addon-unicode11": "^0.9.0-beta.70", + "@xterm/addon-webgl": "^0.19.0-beta.70", + "@xterm/headless": "^5.6.0-beta.70", + "@xterm/xterm": "^5.6.0-beta.70", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.2", + "jschardet": "3.1.4", + "kerberos": "2.1.1", + "minimist": "^1.2.6", + "multiformats": "^13.3.1", + "native-is-elevated": "0.7.0", + "native-keymap": "^3.3.5", + "native-watchdog": "^1.4.1", + "node-fetch": "2.7.0", + "node-pty": "1.1.0-beta22", + "open": "^8.4.2", + "tas-client-umd": "0.2.0", + "v8-inspect-profiler": "^0.1.1", + "vscode-oniguruma": "1.7.0", + "vscode-regexpp": "^3.1.0", + "vscode-textmate": "9.1.0", + "yauzl": "^3.0.0", + "yazl": "^2.4.3" + }, + "name": "cursor", + "version": "0.45.11", + "type": "module", + "desktopName": "cursor-url-handler.desktop", + "overrides": {}, + "tdBuildId": "250207y6nbaw5qc", + "email": "jrxqnsoz250264@nosqli.com", + "accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJhdXRoMHx1c2VyXzAxSktTUEJLQlIxOTNKMjY3RENSVDRTR1YyIiwidGltZSI6IjE3MzkyNTAzNDgiLCJyYW5kb21uZXNzIjoiYWIyNWVhYTYtNDQzZC00Y2Q0IiwiZXhwIjo0MzMxMjUwMzQ4LCJpc3MiOiJodHRwczovL2F1dGhlbnRpY2F0aW9uLmN1cnNvci5zaCIsInNjb3BlIjoib3BlbmlkIHByb2ZpbGUgZW1haWwgb2ZmbGluZV9hY2Nlc3MiLCJhdWQiOiJodHRwczovL2N1cnNvci5jb20ifQ.f3VIttCJLWqhkEZpPmWJlYw32FuV_gLWl9E0N-O9oIc", + "refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJhdXRoMHx1c2VyXzAxSktTUEJLQlIxOTNKMjY3RENSVDRTR1YyIiwidGltZSI6IjE3MzkyNTAzNDgiLCJyYW5kb21uZXNzIjoiYWIyNWVhYTYtNDQzZC00Y2Q0IiwiZXhwIjo0MzMxMjUwMzQ4LCJpc3MiOiJodHRwczovL2F1dGhlbnRpY2F0aW9uLmN1cnNvci5zaCIsInNjb3BlIjoib3BlbmlkIHByb2ZpbGUgZW1haWwgb2ZmbGluZV9hY2Nlc3MiLCJhdWQiOiJodHRwczovL2N1cnNvci5jb20ifQ.f3VIttCJLWqhkEZpPmWJlYw32FuV_gLWl9E0N-O9oIc", + "updateUrl": "", + "disableUpdate": true, + "enableNodeApiUncaughtExceptionPolicy": true, + "nodeOptions": [ + "--force-node-api-uncaught-exceptions-policy=true" + ] + } + }, + "storage_json": { + "telemetry.machineId": "9eb67b11924f32572a67e6480ce4f1cabf3f61503aa4918af506b259527a4745", + "telemetry.macMachineId": "ff2a4a580f6e9e484c830204bb502866e9a333d3e0299ef81c34e01940da953e", + "telemetry.sqmId": "{D73E6881-666C-4182-8CB2-E2A3EED5AEFF}", + "telemetry.devDeviceId": "1ae7f91c-3ab8-448c-bbd3-ef34345a5b05", + "backupWorkspaces": { + "workspaces": [], + "folders": [ + { + "folderUri": "file:///d%3A/W/python/001cursro.app/interactive" + } + ], + "emptyWindows": [] + }, + "windowControlHeight": 35, + "profileAssociations": { + "workspaces": { + "file:///d%3A/W/python/001cursro.app/interactive": "__default__profile__" + }, + "emptyWindows": {} + }, + "theme": "vs-dark", + "themeBackground": "#1f1f1f", + "windowSplash": { + "zoomLevel": 0, + "baseTheme": "vs-dark", + "colorInfo": { + "foreground": "#cccccc", + "background": "#1f1f1f", + "editorBackground": "#1f1f1f", + "titleBarBackground": "#181818", + "titleBarBorder": "#2b2b2b", + "activityBarBackground": "#181818", + "activityBarBorder": "#2b2b2b", + "sideBarBackground": "#181818", + "sideBarBorder": "#2b2b2b", + "statusBarBackground": "#181818", + "statusBarBorder": "#2b2b2b", + "statusBarNoFolderBackground": "#1f1f1f" + }, + "layoutInfo": { + "sideBarSide": "left", + "editorPartMinWidth": 220, + "titleBarHeight": 35, + "activityBarWidth": 0, + "sideBarWidth": 300, + "statusBarHeight": 22, + "windowBorder": false + } + }, + "windowsState": { + "lastActiveWindow": { + "folder": "file:///d%3A/W/python/001cursro.app/interactive", + "backupPath": "C:\\Users\\huangzhen\\AppData\\Roaming\\Cursor\\Backups\\385f155a4a13070be99ee4e76a057235", + "uiState": { + "mode": 0, + "x": 512, + "y": 192, + "width": 1024, + "height": 768 + } + }, + "openedWindows": [] + } + }, + "registry": { + "HKLM_MachineGuid": { + "exists": true, + "value": "948b93c1-ee34-4a48-95d0-a2fce9af92b1" + }, + "HKCU_cursor_shell": { + "exists": false, + "values": {} + }, + "HKCU_cursor_command": { + "exists": false, + "values": {} + }, + "HKCU_cursor_auth": { + "exists": false, + "values": {} + }, + "HKCU_cursor_updates": { + "exists": false, + "values": {} + }, + "HKCU_cursor_main": { + "exists": false, + "values": {} + } + }, + "files": { + "storage": { + "exists": true, + "is_dir": false, + "size": 2214, + "modified_time": "2025-02-12T12:36:27.187387" + }, + "storage_backup": { + "exists": true, + "is_dir": true, + "size": null, + "modified_time": "2025-02-12T12:33:10.408749" + }, + "user_data": { + "exists": false, + "is_dir": null, + "size": null, + "modified_time": null + }, + "global_storage": { + "exists": true, + "is_dir": true, + "size": null, + "modified_time": "2025-02-12T12:37:14.253083" + }, + "cache": { + "exists": false, + "is_dir": null, + "size": null, + "modified_time": null + }, + "updater": { + "exists": true, + "is_dir": false, + "size": 0, + "modified_time": "2025-02-10T17:19:39.071580" + } + }, + "telemetry": { + "machineId": "9eb67b11924f32572a67e6480ce4f1cabf3f61503aa4918af506b259527a4745", + "macMachineId": "ff2a4a580f6e9e484c830204bb502866e9a333d3e0299ef81c34e01940da953e", + "devDeviceId": "1ae7f91c-3ab8-448c-bbd3-ef34345a5b05", + "sqmId": "{D73E6881-666C-4182-8CB2-E2A3EED5AEFF}" + } +} \ No newline at end of file diff --git a/build_nezha.spec b/build_nezha.spec index 9d8c045..de0c009 100644 --- a/build_nezha.spec +++ b/build_nezha.spec @@ -13,7 +13,12 @@ a = Analysis( pathex=[], binaries=[], datas=[('icon', 'icon'), ('version.txt', '.')], - hiddenimports=[], + hiddenimports=[ + 'win32gui', 'win32con', 'win32process', 'psutil', # Windows API 相关 + 'tkinter', 'tkinter.ttk', # GUI 相关 + 'requests', 'urllib3', 'certifi', # 网络请求相关 + 'json', 'uuid', 'hashlib', 'logging' # 基础功能相关 + ], hookspath=[], hooksconfig={}, runtime_hooks=[], diff --git a/cursor_win_id_modifier.ps1 b/cursor_win_id_modifier.ps1 new file mode 100644 index 0000000..4f94558 --- /dev/null +++ b/cursor_win_id_modifier.ps1 @@ -0,0 +1,504 @@ +# 设置输出编码为 UTF-8 +$OutputEncoding = [System.Text.Encoding]::UTF8 +[Console]::OutputEncoding = [System.Text.Encoding]::UTF8 + +# 颜色定义 +$RED = "`e[31m" +$GREEN = "`e[32m" +$YELLOW = "`e[33m" +$BLUE = "`e[34m" +$NC = "`e[0m" + +# 配置文件路径 +$STORAGE_FILE = "$env:APPDATA\Cursor\User\globalStorage\storage.json" +$BACKUP_DIR = "$env:APPDATA\Cursor\User\globalStorage\backups" + +# 检查管理员权限 +function Test-Administrator { + $user = [Security.Principal.WindowsIdentity]::GetCurrent() + $principal = New-Object Security.Principal.WindowsPrincipal($user) + return $principal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator) +} + +if (-not (Test-Administrator)) { + Write-Host "$RED[错误]$NC 请以管理员身份运行此脚本" + Write-Host "请右键点击脚本,选择'以管理员身份运行'" + Read-Host "按回车键退出" + exit 1 +} + +# 显示 Logo +Clear-Host +Write-Host @" + + ██████╗██╗ ██╗██████╗ ███████╗ ██████╗ ██████╗ + ██╔════╝██║ ██║██╔══██╗██╔════╝██╔═══██╗██╔══██╗ + ██║ ██║ ██║██████╔╝███████╗██║ ██║██████╔╝ + ██║ ██║ ██║██╔══██╗╚════██║██║ ██║██╔══██╗ + ╚██████╗╚██████╔╝██║ ██║███████║╚██████╔╝██║ ██║ + ╚═════╝ ╚═════╝ ╚═╝ ╚═╝╚══════╝ ╚═════╝ ╚═╝ ╚═╝ + +"@ +Write-Host "$BLUE================================$NC" +Write-Host "$GREEN Cursor 设备ID 修改工具 $NC" +Write-Host "$YELLOW 关注公众号【煎饼果子卷AI】 $NC" +Write-Host "$YELLOW 一起交流更多Cursor技巧和AI知识(脚本免费、关注公众号加群有更多技巧和大佬) $NC" +Write-Host "$YELLOW [重要提示] 本工具免费,如果对您有帮助,请关注公众号【煎饼果子卷AI】 $NC" +Write-Host "$BLUE================================$NC" +Write-Host "" + +# 获取并显示 Cursor 版本 +function Get-CursorVersion { + try { + # 主要检测路径 + $packagePath = "$env:LOCALAPPDATA\Programs\cursor\resources\app\package.json" + + if (Test-Path $packagePath) { + $packageJson = Get-Content $packagePath -Raw | ConvertFrom-Json + if ($packageJson.version) { + Write-Host "$GREEN[信息]$NC 当前安装的 Cursor 版本: v$($packageJson.version)" + return $packageJson.version + } + } + + # 备用路径检测 + $altPath = "$env:LOCALAPPDATA\cursor\resources\app\package.json" + if (Test-Path $altPath) { + $packageJson = Get-Content $altPath -Raw | ConvertFrom-Json + if ($packageJson.version) { + Write-Host "$GREEN[信息]$NC 当前安装的 Cursor 版本: v$($packageJson.version)" + return $packageJson.version + } + } + + Write-Host "$YELLOW[警告]$NC 无法检测到 Cursor 版本" + Write-Host "$YELLOW[提示]$NC 请确保 Cursor 已正确安装" + return $null + } + catch { + Write-Host "$RED[错误]$NC 获取 Cursor 版本失败: $_" + return $null + } +} + +# 获取并显示版本信息 +$cursorVersion = Get-CursorVersion +Write-Host "" + +Write-Host "$YELLOW[重要提示]$NC 最新的 0.45.x (以支持)" +Write-Host "" + +# 检查并关闭 Cursor 进程 +Write-Host "$GREEN[信息]$NC 检查 Cursor 进程..." + +function Get-ProcessDetails { + param($processName) + Write-Host "$BLUE[调试]$NC 正在获取 $processName 进程详细信息:" + Get-WmiObject Win32_Process -Filter "name='$processName'" | + Select-Object ProcessId, ExecutablePath, CommandLine | + Format-List +} + +# 定义最大重试次数和等待时间 +$MAX_RETRIES = 5 +$WAIT_TIME = 1 + +# 处理进程关闭 +function Close-CursorProcess { + param($processName) + + $process = Get-Process -Name $processName -ErrorAction SilentlyContinue + if ($process) { + Write-Host "$YELLOW[警告]$NC 发现 $processName 正在运行" + Get-ProcessDetails $processName + + Write-Host "$YELLOW[警告]$NC 尝试关闭 $processName..." + Stop-Process -Name $processName -Force + + $retryCount = 0 + while ($retryCount -lt $MAX_RETRIES) { + $process = Get-Process -Name $processName -ErrorAction SilentlyContinue + if (-not $process) { break } + + $retryCount++ + if ($retryCount -ge $MAX_RETRIES) { + Write-Host "$RED[错误]$NC 在 $MAX_RETRIES 次尝试后仍无法关闭 $processName" + Get-ProcessDetails $processName + Write-Host "$RED[错误]$NC 请手动关闭进程后重试" + Read-Host "按回车键退出" + exit 1 + } + Write-Host "$YELLOW[警告]$NC 等待进程关闭,尝试 $retryCount/$MAX_RETRIES..." + Start-Sleep -Seconds $WAIT_TIME + } + Write-Host "$GREEN[信息]$NC $processName 已成功关闭" + } +} + +# 关闭所有 Cursor 进程 +Close-CursorProcess "Cursor" +Close-CursorProcess "cursor" + +# 创建备份目录 +if (-not (Test-Path $BACKUP_DIR)) { + New-Item -ItemType Directory -Path $BACKUP_DIR | Out-Null +} + +# 备份现有配置 +if (Test-Path $STORAGE_FILE) { + Write-Host "$GREEN[信息]$NC 正在备份配置文件..." + $backupName = "storage.json.backup_$(Get-Date -Format 'yyyyMMdd_HHmmss')" + Copy-Item $STORAGE_FILE "$BACKUP_DIR\$backupName" +} + +# 生成新的 ID +Write-Host "$GREEN[信息]$NC 正在生成新的 ID..." + +# 在颜色定义后添加此函数 +function Get-RandomHex { + param ( + [int]$length + ) + + $bytes = New-Object byte[] ($length) + $rng = [System.Security.Cryptography.RNGCryptoServiceProvider]::new() + $rng.GetBytes($bytes) + $hexString = [System.BitConverter]::ToString($bytes) -replace '-','' + $rng.Dispose() + return $hexString +} + +# 改进 ID 生成函数 +function New-StandardMachineId { + $template = "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx" + $result = $template -replace '[xy]', { + param($match) + $r = [Random]::new().Next(16) + $v = if ($match.Value -eq "x") { $r } else { ($r -band 0x3) -bor 0x8 } + return $v.ToString("x") + } + return $result +} + +# 在生成 ID 时使用新函数 +$MAC_MACHINE_ID = New-StandardMachineId +$UUID = [System.Guid]::NewGuid().ToString() +# 将 auth0|user_ 转换为字节数组的十六进制 +$prefixBytes = [System.Text.Encoding]::UTF8.GetBytes("auth0|user_") +$prefixHex = -join ($prefixBytes | ForEach-Object { '{0:x2}' -f $_ }) +# 生成32字节(64个十六进制字符)的随机数作为 machineId 的随机部分 +$randomPart = Get-RandomHex -length 32 +$MACHINE_ID = "$prefixHex$randomPart" +$SQM_ID = "{$([System.Guid]::NewGuid().ToString().ToUpper())}" + +# 在生成新ID后直接执行注册表操作,移除询问 +function Update-MachineGuid { + try { + $newMachineGuid = [System.Guid]::NewGuid().ToString() + $registryPath = "HKLM:\SOFTWARE\Microsoft\Cryptography" + + # 备份原始值 + $originalGuid = (Get-ItemProperty -Path $registryPath -Name "MachineGuid").MachineGuid + $backupFile = "$BACKUP_DIR\MachineGuid.backup_$(Get-Date -Format 'yyyyMMdd_HHmmss')" + $originalGuid | Out-File $backupFile -Encoding UTF8 + + # 更新注册表 + Set-ItemProperty -Path $registryPath -Name "MachineGuid" -Value $newMachineGuid + Write-Host "$GREEN[信息]$NC 已更新系统 MachineGuid: $newMachineGuid" + Write-Host "$GREEN[信息]$NC 原始值已备份至: $backupFile" + Write-Host "$GREEN[信息]$NC 注册表路径: 计算机\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography" + Write-Host "$GREEN[信息]$NC 注册表项名: MachineGuid" + } + catch { + Write-Host "$RED[错误]$NC 更新系统 MachineGuid 失败: $_" + } +} + +# 创建或更新配置文件 +Write-Host "$GREEN[信息]$NC 正在更新配置..." + +try { + # 检查配置文件是否存在 + if (-not (Test-Path $STORAGE_FILE)) { + Write-Host "$RED[错误]$NC 未找到配置文件: $STORAGE_FILE" + Write-Host "$YELLOW[提示]$NC 请先安装并运行一次 Cursor 后再使用此脚本" + Read-Host "按回车键退出" + exit 1 + } + + # 读取现有配置文件 + try { + $originalContent = Get-Content $STORAGE_FILE -Raw -Encoding UTF8 + + # 将 JSON 字符串转换为 PowerShell 对象 + $config = $originalContent | ConvertFrom-Json + + # 备份当前值 + $oldValues = @{ + 'machineId' = $config.'telemetry.machineId' + 'macMachineId' = $config.'telemetry.macMachineId' + 'devDeviceId' = $config.'telemetry.devDeviceId' + 'sqmId' = $config.'telemetry.sqmId' + } + + # 更新特定的值 + $config.'telemetry.machineId' = $MACHINE_ID + $config.'telemetry.macMachineId' = $MAC_MACHINE_ID + $config.'telemetry.devDeviceId' = $UUID + $config.'telemetry.sqmId' = $SQM_ID + + # 将更新后的对象转换回 JSON 并保存 + $updatedJson = $config | ConvertTo-Json -Depth 10 + [System.IO.File]::WriteAllText( + [System.IO.Path]::GetFullPath($STORAGE_FILE), + $updatedJson, + [System.Text.Encoding]::UTF8 + ) + Write-Host "$GREEN[信息]$NC 成功更新配置文件" + } catch { + # 如果出错,尝试恢复原始内容 + if ($originalContent) { + [System.IO.File]::WriteAllText( + [System.IO.Path]::GetFullPath($STORAGE_FILE), + $originalContent, + [System.Text.Encoding]::UTF8 + ) + } + throw "处理 JSON 失败: $_" + } + # 直接执行更新 MachineGuid,不再询问 + Update-MachineGuid + # 显示结果 + Write-Host "" + Write-Host "$GREEN[信息]$NC 已更新配置:" + Write-Host "$BLUE[调试]$NC machineId: $MACHINE_ID" + Write-Host "$BLUE[调试]$NC macMachineId: $MAC_MACHINE_ID" + Write-Host "$BLUE[调试]$NC devDeviceId: $UUID" + Write-Host "$BLUE[调试]$NC sqmId: $SQM_ID" + + # 显示文件树结构 + Write-Host "" + Write-Host "$GREEN[信息]$NC 文件结构:" + Write-Host "$BLUE$env:APPDATA\Cursor\User$NC" + Write-Host "├── globalStorage" + Write-Host "│ ├── storage.json (已修改)" + Write-Host "│ └── backups" + + # 列出备份文件 + $backupFiles = Get-ChildItem "$BACKUP_DIR\*" -ErrorAction SilentlyContinue + if ($backupFiles) { + foreach ($file in $backupFiles) { + Write-Host "│ └── $($file.Name)" + } + } else { + Write-Host "│ └── (空)" + } + + # 显示公众号信息 + Write-Host "" + Write-Host "$GREEN================================$NC" + Write-Host "$YELLOW 关注公众号【煎饼果子卷AI】一起交流更多Cursor技巧和AI知识(脚本免费、关注公众号加群有更多技巧和大佬) $NC" + Write-Host "$GREEN================================$NC" + Write-Host "" + Write-Host "$GREEN[信息]$NC 请重启 Cursor 以应用新的配置" + Write-Host "" + + # 询问是否要禁用自动更新 + Write-Host "" + Write-Host "$YELLOW[询问]$NC 是否要禁用 Cursor 自动更新功能?" + Write-Host "0) 否 - 保持默认设置 (按回车键)" + Write-Host "1) 是 - 禁用自动更新" + $choice = Read-Host "请输入选项 (0)" + + if ($choice -eq "1") { + Write-Host "" + Write-Host "$GREEN[信息]$NC 正在处理自动更新..." + $updaterPath = "$env:LOCALAPPDATA\cursor-updater" + + # 定义手动设置教程 + function Show-ManualGuide { + Write-Host "" + Write-Host "$YELLOW[警告]$NC 自动设置失败,请尝试手动操作:" + Write-Host "$YELLOW手动禁用更新步骤:$NC" + Write-Host "1. 以管理员身份打开 PowerShell" + Write-Host "2. 复制粘贴以下命令:" + Write-Host "$BLUE命令1 - 删除现有目录(如果存在):$NC" + Write-Host "Remove-Item -Path `"$updaterPath`" -Force -Recurse -ErrorAction SilentlyContinue" + Write-Host "" + Write-Host "$BLUE命令2 - 创建阻止文件:$NC" + Write-Host "New-Item -Path `"$updaterPath`" -ItemType File -Force | Out-Null" + Write-Host "" + Write-Host "$BLUE命令3 - 设置只读属性:$NC" + Write-Host "Set-ItemProperty -Path `"$updaterPath`" -Name IsReadOnly -Value `$true" + Write-Host "" + Write-Host "$BLUE命令4 - 设置权限(可选):$NC" + Write-Host "icacls `"$updaterPath`" /inheritance:r /grant:r `"`$($env:USERNAME):(R)`"" + Write-Host "" + Write-Host "$YELLOW验证方法:$NC" + Write-Host "1. 运行命令:Get-ItemProperty `"$updaterPath`"" + Write-Host "2. 确认 IsReadOnly 属性为 True" + Write-Host "3. 运行命令:icacls `"$updaterPath`"" + Write-Host "4. 确认只有读取权限" + Write-Host "" + Write-Host "$YELLOW[提示]$NC 完成后请重启 Cursor" + } + + try { + # 删除现有目录 + if (Test-Path $updaterPath) { + try { + Remove-Item -Path $updaterPath -Force -Recurse -ErrorAction Stop + Write-Host "$GREEN[信息]$NC 成功删除 cursor-updater 目录" + } + catch { + Write-Host "$RED[错误]$NC 删除 cursor-updater 目录失败" + Show-ManualGuide + return + } + } + + # 创建阻止文件 + try { + New-Item -Path $updaterPath -ItemType File -Force -ErrorAction Stop | Out-Null + Write-Host "$GREEN[信息]$NC 成功创建阻止文件" + } + catch { + Write-Host "$RED[错误]$NC 创建阻止文件失败" + Show-ManualGuide + return + } + + # 设置文件权限 + try { + # 设置只读属性 + Set-ItemProperty -Path $updaterPath -Name IsReadOnly -Value $true -ErrorAction Stop + + # 使用 icacls 设置权限 + $result = Start-Process "icacls.exe" -ArgumentList "`"$updaterPath`" /inheritance:r /grant:r `"$($env:USERNAME):(R)`"" -Wait -NoNewWindow -PassThru + if ($result.ExitCode -ne 0) { + throw "icacls 命令失败" + } + + Write-Host "$GREEN[信息]$NC 成功设置文件权限" + } + catch { + Write-Host "$RED[错误]$NC 设置文件权限失败" + Show-ManualGuide + return + } + + # 验证设置 + try { + $fileInfo = Get-ItemProperty $updaterPath + if (-not $fileInfo.IsReadOnly) { + Write-Host "$RED[错误]$NC 验证失败:文件权限设置可能未生效" + Show-ManualGuide + return + } + } + catch { + Write-Host "$RED[错误]$NC 验证设置失败" + Show-ManualGuide + return + } + + Write-Host "$GREEN[信息]$NC 成功禁用自动更新" + } + catch { + Write-Host "$RED[错误]$NC 发生未知错误: $_" + Show-ManualGuide + } + } + else { + Write-Host "$GREEN[信息]$NC 保持默认设置,不进行更改" + } + +} catch { + Write-Host "$RED[错误]$NC 主要操作失败: $_" + Write-Host "$YELLOW[尝试]$NC 使用备选方法..." + + try { + # 备选方法:使用 Add-Content + $tempFile = [System.IO.Path]::GetTempFileName() + $config | ConvertTo-Json | Set-Content -Path $tempFile -Encoding UTF8 + Copy-Item -Path $tempFile -Destination $STORAGE_FILE -Force + Remove-Item -Path $tempFile + Write-Host "$GREEN[信息]$NC 使用备选方法成功写入配置" + } catch { + Write-Host "$RED[错误]$NC 所有尝试都失败了" + Write-Host "错误详情: $_" + Write-Host "目标文件: $STORAGE_FILE" + Write-Host "请确保您有足够的权限访问该文件" + Read-Host "按回车键退出" + exit 1 + } +} + +Write-Host "" +Read-Host "按回车键退出" +exit 0 + +# 在文件写入部分修改 +function Write-ConfigFile { + param($config, $filePath) + + try { + # 使用 UTF8 无 BOM 编码 + $utf8NoBom = New-Object System.Text.UTF8Encoding $false + $jsonContent = $config | ConvertTo-Json -Depth 10 + + # 统一使用 LF 换行符 + $jsonContent = $jsonContent.Replace("`r`n", "`n") + + [System.IO.File]::WriteAllText( + [System.IO.Path]::GetFullPath($filePath), + $jsonContent, + $utf8NoBom + ) + + Write-Host "$GREEN[信息]$NC 成功写入配置文件(UTF8 无 BOM)" + } + catch { + throw "写入配置文件失败: $_" + } +} + +function Compare-Version { + param ( + [string]$version1, + [string]$version2 + ) + + try { + $v1 = [version]($version1 -replace '[^\d\.].*$') + $v2 = [version]($version2 -replace '[^\d\.].*$') + return $v1.CompareTo($v2) + } + catch { + Write-Host "$RED[错误]$NC 版本比较失败: $_" + return 0 + } +} + +# 在主流程开始时添加版本检查 +Write-Host "$GREEN[信息]$NC 正在检查 Cursor 版本..." +$cursorVersion = Get-CursorVersion + +if ($cursorVersion) { + $compareResult = Compare-Version $cursorVersion "0.45.0" + if ($compareResult -ge 0) { + Write-Host "$RED[错误]$NC 当前版本 ($cursorVersion) 暂不支持" + Write-Host "$YELLOW[建议]$NC 请使用 v0.44.11 及以下版本" + Write-Host "$YELLOW[建议]$NC 可以从以下地址下载支持的版本:" + Write-Host "Windows: https://download.todesktop.com/230313mzl4w4u92/Cursor%20Setup%200.44.11%20-%20Build%20250103fqxdt5u9z-x64.exe" + Write-Host "Mac ARM64: https://dl.todesktop.com/230313mzl4w4u92/versions/0.44.11/mac/zip/arm64" + Read-Host "按回车键退出" + exit 1 + } + else { + Write-Host "$GREEN[信息]$NC 当前版本 ($cursorVersion) 支持重置功能" + } +} +else { + Write-Host "$YELLOW[警告]$NC 无法检测版本,将继续执行..." +} \ No newline at end of file diff --git a/github_script_changes.json b/github_script_changes.json new file mode 100644 index 0000000..cd12746 --- /dev/null +++ b/github_script_changes.json @@ -0,0 +1,59 @@ +{ + "package_json_changes": {}, + "registry_changes": { + "HKLM_MachineGuid": { + "before": { + "exists": true, + "value": "d890ab3d-43cd-40c8-a9ef-f5683b5a64e3" + }, + "after": { + "exists": true, + "value": "776c6b6c-195f-42dc-94d6-72b70c3aca74" + } + } + }, + "file_changes": { + "storage": { + "before": { + "exists": true, + "is_dir": false, + "size": 3427, + "modified_time": "2025-02-12T11:40:57.046415" + }, + "after": { + "exists": true, + "is_dir": false, + "size": 1891, + "modified_time": "2025-02-12T11:48:42.627574" + } + }, + "storage_backup": { + "before": { + "exists": true, + "is_dir": true, + "size": null, + "modified_time": "2025-02-12T11:00:01.555876" + }, + "after": { + "exists": true, + "is_dir": true, + "size": null, + "modified_time": "2025-02-12T11:48:26.403770" + } + }, + "global_storage": { + "before": { + "exists": true, + "is_dir": true, + "size": null, + "modified_time": "2025-02-12T11:47:27.627883" + }, + "after": { + "exists": true, + "is_dir": true, + "size": null, + "modified_time": "2025-02-12T11:48:47.490659" + } + } + } +} \ No newline at end of file diff --git a/gui/main_window.py b/gui/main_window.py index 968fb75..1c5ef03 100644 --- a/gui/main_window.py +++ b/gui/main_window.py @@ -122,7 +122,7 @@ class MainWindow: btn_frame.pack(fill="x", pady=5) self.style.configure("Action.TButton", padding=8) - ttk.Button(btn_frame, text="刷新Cursor编辑器授权", command=self.reset_machine_id, style="Action.TButton").pack(fill="x", pady=2) + ttk.Button(btn_frame, text="刷新Cursor编辑器授权", command=self.refresh_cursor_auth, style="Action.TButton").pack(fill="x", pady=2) ttk.Button(btn_frame, text="突破Cursor0.45.x限制", command=self.dummy_function, style="Action.TButton").pack(fill="x", pady=2) ttk.Button(btn_frame, text="禁用Cursor版本更新", command=self.disable_cursor_update, style="Action.TButton").pack(fill="x", pady=2) @@ -348,7 +348,7 @@ class MainWindow: """运行程序""" self.root.mainloop() - def reset_machine_id(self): + def refresh_cursor_auth(self): """刷新Cursor编辑器授权""" if not self.check_status(): self.show_purchase_info() diff --git a/reset_methods_comparison.json b/reset_methods_comparison.json new file mode 100644 index 0000000..bd96b2f --- /dev/null +++ b/reset_methods_comparison.json @@ -0,0 +1,106 @@ +{ + "github_changes": { + "package_json_changes": {}, + "registry_changes": { + "HKLM_MachineGuid": { + "before": { + "exists": true, + "value": "d890ab3d-43cd-40c8-a9ef-f5683b5a64e3" + }, + "after": { + "exists": true, + "value": "776c6b6c-195f-42dc-94d6-72b70c3aca74" + } + } + }, + "file_changes": { + "storage": { + "before": { + "exists": true, + "is_dir": false, + "size": 3427, + "modified_time": "2025-02-12T11:40:57.046415" + }, + "after": { + "exists": true, + "is_dir": false, + "size": 1891, + "modified_time": "2025-02-12T11:48:42.627574" + } + }, + "storage_backup": { + "before": { + "exists": true, + "is_dir": true, + "size": null, + "modified_time": "2025-02-12T11:00:01.555876" + }, + "after": { + "exists": true, + "is_dir": true, + "size": null, + "modified_time": "2025-02-12T11:48:26.403770" + } + }, + "global_storage": { + "before": { + "exists": true, + "is_dir": true, + "size": null, + "modified_time": "2025-02-12T11:47:27.627883" + }, + "after": { + "exists": true, + "is_dir": true, + "size": null, + "modified_time": "2025-02-12T11:48:47.490659" + } + } + } + }, + "our_changes": { + "package_json_changes": {}, + "registry_changes": { + "HKLM_MachineGuid": { + "before": { + "exists": true, + "value": "948b93c1-ee34-4a48-95d0-a2fce9af92b1" + }, + "after": { + "exists": true, + "value": "1deb25e7-cdd4-4367-a347-fba8b33b9b03" + } + } + }, + "file_changes": { + "storage_backup": { + "before": { + "exists": true, + "is_dir": true, + "size": null, + "modified_time": "2025-02-12T12:33:10.408749" + }, + "after": { + "exists": true, + "is_dir": true, + "size": null, + "modified_time": "2025-02-12T12:37:17.371311" + } + }, + "storage": { + "before": { + "exists": true, + "is_dir": false, + "size": 2214, + "modified_time": "2025-02-12T12:36:27.187387" + }, + "after": { + "exists": true, + "is_dir": false, + "size": 1980, + "modified_time": "2025-02-12T12:37:17.428609" + } + } + } + } +} \ No newline at end of file diff --git a/test_compare_reset.py b/test_compare_reset.py new file mode 100644 index 0000000..10eddbb --- /dev/null +++ b/test_compare_reset.py @@ -0,0 +1,295 @@ +import json +import logging +import os +import time +import subprocess +from pathlib import Path +from datetime import datetime +from account_switcher import AccountSwitcher + +def get_full_machine_info(): + """获取更完整的机器码相关信息""" + info = {} + + # 1. 获取 package.json 中的所有信息(检查两个可能的路径) + cursor_paths = [ + Path(os.path.expanduser("~")) / "AppData" / "Local" / "Programs" / "Cursor", + Path(os.path.expanduser("~")) / "AppData" / "Local" / "cursor" + ] + + info["package_json"] = {} + for cursor_path in cursor_paths: + package_json = cursor_path / "resources" / "app" / "package.json" + if package_json.exists(): + with open(package_json, "r", encoding="utf-8") as f: + info["package_json"][str(package_json)] = json.load(f) + + # 2. 获取 storage.json 的内容 + storage_path = Path(os.getenv('APPDATA')) / "Cursor" / "User" / "globalStorage" / "storage.json" + info["storage_json"] = None + if storage_path.exists(): + try: + with open(storage_path, "r", encoding="utf-8") as f: + info["storage_json"] = json.load(f) + except: + pass + + # 3. 检查注册表项和其值 + import winreg + registry_paths = { + "cryptography": r"SOFTWARE\Microsoft\Cryptography", # 系统 MachineGuid + "cursor_shell": r"Software\Classes\Directory\Background\shell\Cursor", + "cursor_command": r"Software\Classes\Directory\Background\shell\Cursor\command", + "cursor_auth": r"Software\Cursor\Auth", + "cursor_updates": r"Software\Cursor\Updates", + "cursor_main": r"Software\Cursor" + } + + info["registry"] = {} + + # HKEY_LOCAL_MACHINE 项 + try: + key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, registry_paths["cryptography"], 0, winreg.KEY_READ | winreg.KEY_WOW64_64KEY) + info["registry"]["HKLM_MachineGuid"] = { + "exists": True, + "value": winreg.QueryValueEx(key, "MachineGuid")[0] + } + except WindowsError: + info["registry"]["HKLM_MachineGuid"] = { + "exists": False, + "value": None + } + + # HKEY_CURRENT_USER 项 + for name, path in registry_paths.items(): + if name == "cryptography": + continue + try: + key = winreg.OpenKey(winreg.HKEY_CURRENT_USER, path, 0, winreg.KEY_READ) + info["registry"][f"HKCU_{name}"] = {"exists": True, "values": {}} + try: + i = 0 + while True: + name, value, type = winreg.EnumValue(key, i) + info["registry"][f"HKCU_{name}"]["values"][name] = value + i += 1 + except WindowsError: + pass + except WindowsError: + info["registry"][f"HKCU_{name}"] = {"exists": False, "values": {}} + + # 4. 检查关键文件的存在状态 + paths_to_check = { + "storage": storage_path, + "storage_backup": Path(os.getenv('APPDATA')) / "Cursor" / "User" / "globalStorage" / "backups", + "user_data": Path(os.getenv('LOCALAPPDATA')) / "Cursor" / "User", + "global_storage": Path(os.getenv('APPDATA')) / "Cursor" / "User" / "globalStorage", + "cache": Path(os.getenv('LOCALAPPDATA')) / "Cursor" / "Cache", + "updater": Path(os.getenv('LOCALAPPDATA')) / "cursor-updater" + } + + info["files"] = {} + for name, path in paths_to_check.items(): + if path.exists(): + info["files"][name] = { + "exists": True, + "is_dir": path.is_dir(), + "size": os.path.getsize(path) if path.is_file() else None, + "modified_time": datetime.fromtimestamp(os.path.getmtime(path)).isoformat() + } + else: + info["files"][name] = { + "exists": False, + "is_dir": None, + "size": None, + "modified_time": None + } + + # 5. 获取遥测相关的配置值 + info["telemetry"] = { + "machineId": info["storage_json"].get("telemetry.machineId") if info["storage_json"] else None, + "macMachineId": info["storage_json"].get("telemetry.macMachineId") if info["storage_json"] else None, + "devDeviceId": info["storage_json"].get("telemetry.devDeviceId") if info["storage_json"] else None, + "sqmId": info["storage_json"].get("telemetry.sqmId") if info["storage_json"] else None + } + + return info + +def save_info(info, filename): + """保存信息到文件""" + with open(filename, "w", encoding="utf-8") as f: + json.dump(info, f, indent=2, ensure_ascii=False) + +def compare_info(before_file, after_file): + """比较两个信息文件的差异""" + with open(before_file, "r", encoding="utf-8") as f: + before = json.load(f) + with open(after_file, "r", encoding="utf-8") as f: + after = json.load(f) + + differences = { + "package_json_changes": {}, + "registry_changes": {}, + "file_changes": {} + } + + # 比较 package.json 变化 + if "package_json" in before and "package_json" in after: + for key in set(before["package_json"].keys()) | set(after["package_json"].keys()): + before_val = before["package_json"].get(key) + after_val = after["package_json"].get(key) + if before_val != after_val: + differences["package_json_changes"][key] = { + "before": before_val, + "after": after_val + } + + # 比较注册表变化 + for path in set(before["registry"].keys()) | set(after["registry"].keys()): + before_reg = before["registry"].get(path, {}) + after_reg = after["registry"].get(path, {}) + if before_reg != after_reg: + differences["registry_changes"][path] = { + "before": before_reg, + "after": after_reg + } + + # 比较文件变化 + for name in set(before["files"].keys()) | set(after["files"].keys()): + before_file = before["files"].get(name, {}) + after_file = after["files"].get(name, {}) + if before_file != after_file: + differences["file_changes"][name] = { + "before": before_file, + "after": after_file + } + + return differences + +def main(): + """主测试流程""" + # 设置日志 + logging.basicConfig(level=logging.INFO) + + print("选择操作:") + print("1. 记录当前状态(在运行 GitHub 脚本前执行)") + print("2. 记录重置后状态并对比(在运行 GitHub 脚本后执行)") + print("3. 运行我们的重置方法并记录对比") + + choice = input("\n请选择操作 (1/2/3): ").strip() + + if choice == "1": + # 记录初始状态 + print("\n记录初始状态...") + initial_info = get_full_machine_info() + save_info(initial_info, "before_github_reset.json") + print("初始状态已保存到 before_github_reset.json") + + elif choice == "2": + # 检查是否存在初始状态文件 + if not os.path.exists("before_github_reset.json"): + print("错误:找不到初始状态文件 before_github_reset.json") + print("请先执行选项 1 记录初始状态") + return + + # 记录 GitHub 脚本执行后的状态 + print("\n记录 GitHub 脚本执行后的状态...") + after_info = get_full_machine_info() + save_info(after_info, "after_github_reset.json") + + # 对比变化 + print("\n=== GitHub 脚本执行前后的变化 ===") + differences = compare_info("before_github_reset.json", "after_github_reset.json") + + # 显示 package.json 的变化 + if differences["package_json_changes"]: + print("\npackage.json 变化:") + for key, change in differences["package_json_changes"].items(): + print(f"- {key}:") + print(f" 之前: {change['before']}") + print(f" 之后: {change['after']}") + + # 显示注册表的变化 + if differences["registry_changes"]: + print("\n注册表变化:") + for path, change in differences["registry_changes"].items(): + print(f"\n- {path}:") + print(f" 之前: {change['before']}") + print(f" 之后: {change['after']}") + + # 显示文件的变化 + if differences["file_changes"]: + print("\n文件变化:") + for name, change in differences["file_changes"].items(): + print(f"\n- {name}:") + before_status = "存在" if change["before"].get("exists") else "不存在" + after_status = "存在" if change["after"].get("exists") else "不存在" + print(f" 状态: {before_status} -> {after_status}") + if change["before"].get("exists") and change["after"].get("exists"): + if change["before"].get("size") != change["after"].get("size"): + print(f" 大小: {change['before'].get('size')} -> {change['after'].get('size')}") + if change["before"].get("modified_time") != change["after"].get("modified_time"): + print(f" 修改时间: {change['before'].get('modified_time')} -> {change['after'].get('modified_time')}") + + # 保存差异到文件 + save_info(differences, "github_script_changes.json") + print("\n详细的变化信息已保存到 github_script_changes.json") + + elif choice == "3": + if not os.path.exists("github_script_changes.json"): + print("错误:找不到 GitHub 脚本的变化记录文件 github_script_changes.json") + print("请先执行选项 1 和 2 来记录 GitHub 脚本的变化") + return + + # 记录运行我们的重置方法前的状态 + print("\n记录当前状态...") + before_our_reset = get_full_machine_info() + save_info(before_our_reset, "before_our_reset.json") + + # 运行我们的重置方法 + print("\n运行我们的重置方法...") + switcher = AccountSwitcher() + original_restart = switcher.restart_cursor + try: + switcher.restart_cursor = lambda: True + switcher.reset_machine_id() + finally: + switcher.restart_cursor = original_restart + + # 记录重置后的状态 + print("\n记录重置后的状态...") + after_our_reset = get_full_machine_info() + save_info(after_our_reset, "after_our_reset.json") + + # 对比我们的方法与 GitHub 脚本的差异 + print("\n=== 对比我们的重置方法与 GitHub 脚本的差异 ===") + with open("github_script_changes.json", "r", encoding="utf-8") as f: + github_changes = json.load(f) + our_changes = compare_info("before_our_reset.json", "after_our_reset.json") + + # 分析差异 + print("\n=== 差异分析 ===") + print("1. GitHub 脚本改变但我们没有改变的项:") + for category in ["package_json_changes", "registry_changes", "file_changes"]: + for key in github_changes[category]: + if key not in our_changes[category]: + print(f"- {category}: {key}") + + print("\n2. 我们改变但 GitHub 脚本没有改变的项:") + for category in ["package_json_changes", "registry_changes", "file_changes"]: + for key in our_changes[category]: + if key not in github_changes[category]: + print(f"- {category}: {key}") + + # 保存分析结果 + save_info({ + "github_changes": github_changes, + "our_changes": our_changes + }, "reset_methods_comparison.json") + print("\n详细的对比结果已保存到 reset_methods_comparison.json") + + else: + print("无效的选择") + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/test_reset.py b/test_reset.py new file mode 100644 index 0000000..97887bc --- /dev/null +++ b/test_reset.py @@ -0,0 +1,104 @@ +import json +import logging +from pathlib import Path +from account_switcher import AccountSwitcher +import os + +def get_machine_info(): + """获取当前机器码相关信息""" + info = {} + + # 1. 获取 package.json 中的 machineId + cursor_path = Path(os.path.expanduser("~")) / "AppData" / "Local" / "Programs" / "Cursor" + package_json = cursor_path / "resources" / "app" / "package.json" + if package_json.exists(): + with open(package_json, "r", encoding="utf-8") as f: + data = json.load(f) + info["machine_id"] = data.get("machineId", "未找到") + + # 2. 检查注册表项是否存在 + import winreg + 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" + ] + + info["registry"] = {} + for path in registry_paths: + try: + winreg.OpenKey(winreg.HKEY_CURRENT_USER, path, 0, winreg.KEY_READ) + info["registry"][path] = "存在" + except WindowsError: + info["registry"][path] = "不存在" + + # 3. 检查文件是否存在 + local_app_data = Path(os.getenv('LOCALAPPDATA')) + files_to_check = [ + local_app_data / "Cursor" / "User" / "globalStorage", + local_app_data / "Cursor" / "Cache", + local_app_data / "cursor-updater", + cursor_path / "resources" / "app" / "config.json", + cursor_path / "resources" / "app" / "state.json", + cursor_path / "resources" / "app" / "settings.json" + ] + + info["files"] = {} + for path in files_to_check: + info["files"][str(path)] = "存在" if path.exists() else "不存在" + + return info + +def test_reset_machine_id(): + """测试重置机器码功能""" + # 设置日志 + logging.basicConfig(level=logging.INFO) + + print("=== 重置前的状态 ===") + before_info = get_machine_info() + print(json.dumps(before_info, indent=2, ensure_ascii=False)) + + # 创建 AccountSwitcher 实例并修改 reset_machine_id 方法以跳过重启 + switcher = AccountSwitcher() + + # 保存原始的 restart_cursor 方法 + original_restart = switcher.restart_cursor + + try: + # 替换 restart_cursor 方法为空函数 + switcher.restart_cursor = lambda: True + + # 执行重置 + print("\n=== 执行重置 ===") + result = switcher.reset_machine_id() + print(f"重置结果: {result}") + + print("\n=== 重置后的状态 ===") + after_info = get_machine_info() + print(json.dumps(after_info, indent=2, ensure_ascii=False)) + + # 比较差异 + print("\n=== 变化分析 ===") + + # 检查 machineId + if before_info.get("machine_id") != after_info.get("machine_id"): + print(f"machineId 变化: {before_info.get('machine_id')} -> {after_info.get('machine_id')}") + + # 检查注册表变化 + for path in before_info["registry"]: + if before_info["registry"][path] != after_info["registry"][path]: + print(f"注册表 {path}: {before_info['registry'][path]} -> {after_info['registry'][path]}") + + # 检查文件变化 + for path in before_info["files"]: + if before_info["files"][path] != after_info["files"][path]: + print(f"文件 {path}: {before_info['files'][path]} -> {after_info['files'][path]}") + + finally: + # 恢复原始的 restart_cursor 方法 + switcher.restart_cursor = original_restart + +if __name__ == "__main__": + test_reset_machine_id() \ No newline at end of file diff --git a/utils/cursor_registry.py b/utils/cursor_registry.py index ad652f5..6071c6a 100644 --- a/utils/cursor_registry.py +++ b/utils/cursor_registry.py @@ -1,8 +1,12 @@ 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注册表操作工具类""" @@ -10,53 +14,61 @@ class CursorRegistry: def __init__(self): self.cursor_path = Path(os.path.expanduser("~")) / "AppData" / "Local" / "Programs" / "Cursor" self.app_path = self.cursor_path / "resources" / "app" - self.machine_guid_path = r"SOFTWARE\Microsoft\Cryptography" - self.machine_guid_name = "MachineGuid" - def refresh_registry(self) -> bool: - """刷新注册表 + def update_machine_guid(self) -> bool: + """更新系统的 MachineGuid + Returns: bool: 是否成功 """ try: - # 生成新的GUID + # 生成新的 GUID new_guid = str(uuid.uuid4()) + registry_path = r"SOFTWARE\Microsoft\Cryptography" - # 修改 MachineGuid try: - with winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, self.machine_guid_path, 0, winreg.KEY_ALL_ACCESS) as key: - winreg.SetValueEx(key, self.machine_guid_name, 0, winreg.REG_SZ, new_guid) - logging.info(f"更新 MachineGuid 成功: {new_guid}") - except Exception as e: - logging.error(f"更新 MachineGuid 失败: {str(e)}") - return False - - # 获取Cursor安装路径 - cursor_exe = self.cursor_path / "Cursor.exe" - if not cursor_exe.exists(): - logging.error("未找到Cursor.exe") - return False + # 使用管理员权限打开注册表项 + 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) - # 刷新注册表项 - try: - # 打开HKEY_CURRENT_USER\Software\Classes\Directory\Background\shell\Cursor - key_path = r"Software\Classes\Directory\Background\shell\Cursor" - with winreg.OpenKey(winreg.HKEY_CURRENT_USER, key_path, 0, winreg.KEY_WRITE) as key: - winreg.SetValueEx(key, "Icon", 0, winreg.REG_SZ, str(cursor_exe)) - - # 打开command子键 - with winreg.OpenKey(winreg.HKEY_CURRENT_USER, key_path + r"\command", 0, winreg.KEY_WRITE) as key: - winreg.SetValueEx(key, "", 0, winreg.REG_SZ, f'"{str(cursor_exe)}" "%V"') - - logging.info("注册表刷新成功") + # 设置新的 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"刷新注册表失败: {str(e)}") + logging.error(f"更新系统 MachineGuid 失败: {str(e)}") return False except Exception as e: - logging.error(f"刷新注册表失败: {str(e)}") + logging.error(f"更新 MachineGuid 过程出错: {str(e)}") return False def clean_registry(self) -> bool: @@ -66,21 +78,149 @@ class CursorRegistry: bool: 是否成功 """ try: - # 删除注册表项 - try: - key_path = r"Software\Classes\Directory\Background\shell\Cursor" - winreg.DeleteKey(winreg.HKEY_CURRENT_USER, key_path + r"\command") - winreg.DeleteKey(winreg.HKEY_CURRENT_USER, key_path) - logging.info("注册表清理成功") - return True - - except WindowsError as e: - if e.winerror == 2: # 找不到注册表项 - logging.info("注册表项不存在,无需清理") - return True - logging.error(f"清理注册表失败: {str(e)}") - return False + # 需要清理的注册表路径列表 + 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 \ No newline at end of file diff --git a/version.txt b/version.txt index 489200c..c4a602d 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -3.0.9 \ No newline at end of file +3.2.6 \ No newline at end of file