Compare commits

...

17 Commits

Author SHA1 Message Date
yeongpin
4122701468 test2 2025-02-08 23:07:23 +08:00
yeongpin
1ee9813155 test1 2025-02-08 23:05:50 +08:00
yeongpin
a9e4b3a5c6 test 2025-02-08 23:02:22 +08:00
yeongpin
a83851d441 update new build.yml 2025-02-08 22:54:02 +08:00
yeongpin
1e290d0417 build.yml update 2025-02-08 22:50:05 +08:00
yeongpin
53ab15604e update build 2025-02-08 22:45:32 +08:00
yeongpin
638916e5ef update github 2025-02-08 22:38:11 +08:00
yeongpin
9500ce1249 update new build 2025-02-08 22:22:19 +08:00
yeongpin
721c13cb2f update build 2025-02-08 22:16:02 +08:00
yeongpin
a04eed2c6b update build.yml 2025-02-08 22:12:17 +08:00
yeongpin
8107bede63 update remake 2025-02-08 22:10:00 +08:00
yeongpin
4166bc5135 update reissue 2025-02-08 22:04:14 +08:00
yeongpin
69994d2486 update v4 2025-02-08 22:02:01 +08:00
yeongpin
ffcb8ec140 update 2025-02-08 22:00:19 +08:00
yeongpin
b61b61c607 add workflow 2025-02-08 21:57:44 +08:00
yeongpin
7326d0eeb0 newest reset machine 2025-02-08 21:52:16 +08:00
yeongpin
371f00645d update readme 2025-02-05 19:33:42 +08:00
10 changed files with 579 additions and 70 deletions

4
.env
View File

@@ -1,2 +1,2 @@
version=1.0.8 version=1.0.9
VERSION=1.0.8 VERSION=1.0.9

201
.github/workflows/build.yml vendored Normal file
View File

@@ -0,0 +1,201 @@
name: Build Executables
on:
workflow_dispatch:
inputs:
version:
description: 'Version number (e.g. 1.0.9)'
required: true
default: '1.0.9-dev'
permissions:
contents: write
actions: write
packages: write
jobs:
create-tag:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
with:
fetch-depth: 0 # 获取所有标签
- name: Delete existing tag if exists
run: |
if git ls-remote --tags origin | grep -q "refs/tags/v${{ github.event.inputs.version }}"; then
git push origin --delete "v${{ github.event.inputs.version }}" || true
git tag -d "v${{ github.event.inputs.version }}" || true
fi
- name: Create Tag
run: |
git tag "v${{ github.event.inputs.version }}"
git push origin "v${{ github.event.inputs.version }}"
build-windows:
needs: create-tag
runs-on: windows-latest
steps:
- uses: actions/checkout@v2
- name: Set up Python
uses: actions/setup-python@v2
with:
python-version: '3.x'
- name: Set version
shell: bash
run: echo "VERSION=${{ github.event.inputs.version }}" >> $GITHUB_ENV
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install pyinstaller
pip install -r requirements.txt
- name: Build EXE
run: |
pyinstaller build.spec
- name: Upload Windows artifact
uses: actions/upload-artifact@v4
with:
name: CursorFreeVIP_${{ env.VERSION }}_windows.exe
path: dist/*
build-macos-arm64:
needs: create-tag
runs-on: macos-latest
steps:
- uses: actions/checkout@v2
- name: Set up Python
uses: actions/setup-python@v2
with:
python-version: '3.x'
- name: Set version
shell: bash
run: echo "VERSION=${{ github.event.inputs.version }}" >> $GITHUB_ENV
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install pyinstaller
pip install -r requirements.txt
- name: Build MacOS ARM executable
run: |
pyinstaller build.spec
- name: Upload MacOS ARM artifact
uses: actions/upload-artifact@v4
with:
name: CursorFreeVIP_${{ env.VERSION }}_mac_arm64
path: dist/*
build-linux:
needs: create-tag
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v2
- name: Set up Python
uses: actions/setup-python@v2
with:
python-version: '3.x'
- name: Set version
shell: bash
run: echo "VERSION=${{ github.event.inputs.version }}" >> $GITHUB_ENV
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install pyinstaller
pip install -r requirements.txt
- name: Build Linux executable
run: |
pyinstaller build.spec
- name: Upload Linux artifact
uses: actions/upload-artifact@v4
with:
name: CursorFreeVIP_${{ env.VERSION }}_linux
path: dist/*
build-macos-intel:
needs: create-tag
runs-on: macos-latest
steps:
- uses: actions/checkout@v2
- name: Set up Python
uses: actions/setup-python@v2
with:
python-version: '3.x'
- name: Set version
shell: bash
run: echo "VERSION=${{ github.event.inputs.version }}" >> $GITHUB_ENV
- name: Install dependencies
run: |
arch -x86_64 pip3 install --upgrade pip
arch -x86_64 pip3 install pyinstaller
arch -x86_64 pip3 install -r requirements.txt
- name: Build MacOS Intel executable
env:
TARGET_ARCH: 'x86_64'
run: |
arch -x86_64 python3 -m PyInstaller build.spec
- name: Upload MacOS Intel artifact
uses: actions/upload-artifact@v4
with:
name: CursorFreeVIP_${{ env.VERSION }}_mac_intel
path: dist/*
create-release:
needs: [build-windows, build-macos-arm64, build-linux, build-macos-intel]
runs-on: ubuntu-22.04
steps:
- name: Get version
shell: bash
run: echo "VERSION=${{ github.event.inputs.version }}" >> $GITHUB_ENV
- name: Download all artifacts
uses: actions/download-artifact@v4
with:
path: artifacts
- name: List and prepare files
run: |
cd artifacts
ls -la
echo "Current files in artifacts:"
find . -type f
- name: Create Release
uses: softprops/action-gh-release@v1
with:
tag_name: v${{ env.VERSION }}
files: |
artifacts/CursorFreeVIP_${{ env.VERSION }}_windows.exe/CursorFreeVIP.exe
artifacts/CursorFreeVIP_${{ env.VERSION }}_mac_arm64/CursorFreeVIP
artifacts/CursorFreeVIP_${{ env.VERSION }}_linux/CursorFreeVIP
artifacts/CursorFreeVIP_${{ env.VERSION }}_mac_intel/CursorFreeVIP
draft: false
prerelease: false
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View File

@@ -11,6 +11,7 @@
[![Stars](https://img.shields.io/github/stars/yeongpin/cursor-free-vip?style=flat-square&logo=github)](https://github.com/yeongpin/cursor-free-vip/stargazers) [![Stars](https://img.shields.io/github/stars/yeongpin/cursor-free-vip?style=flat-square&logo=github)](https://github.com/yeongpin/cursor-free-vip/stargazers)
</p> </p>
<h4>Support Latest 0.45.11 Version | 支持最新0.45.11版本</h4>
This is a tool to automatically register (except for Google verification code), support Windows and macOS systems, complete Auth verification, and reset Cursor's configuration. This is a tool to automatically register (except for Google verification code), support Windows and macOS systems, complete Auth verification, and reset Cursor's configuration.
@@ -37,14 +38,34 @@ This is a tool to automatically register (except for Google verification code),
## 🔄 更新日志 ## 🔄 更新日志
<details open> <details open>
<summary>v1.0.9</summary>
<p align="center">
<img src="./images/pass_2025-02-08_21-48-36.png" alt="free" width="400"/><br>
</p>
1. Fixed New 0.45.x Version Reset Machine | 修復新0.45版本重置機器
2. Fix Locale Language | 修復多語言
3. Add Support Crypto Machine Regedit | 增加支持加密機器註冊
4. Add Remake main.js | 重做main.js
</details>
<details>
<summary>Other Version Change Log</summary>
<details>
<summary>v1.0.8</summary>
1. Fix New 0.45 Version Reset Machine | 修復新0.45版本重置機器
2. Fix Locale Language | 修復多語言
3. Add Support Crypto Machine Regedit | 增加支持加密機器註冊
</details>
<details>
<summary>v1.0.7 - HotFix</summary> <summary>v1.0.7 - HotFix</summary>
1. Fix Reset Machine | 修復重置機器 1. Fix Reset Machine | 修復重置機器
2. Fix Locale Language | 修復多語言 2. Fix Locale Language | 修復多語言
</details> </details>
<details> <details>
<summary>Other Version Change Log</summary>
<details>
<summary>v1.0.7</summary> <summary>v1.0.7</summary>
1. Add Locale Language Support | 增加多語言支持 1. Add Locale Language Support | 增加多語言支持

View File

@@ -2,6 +2,7 @@ from DrissionPage import ChromiumOptions, ChromiumPage
import sys import sys
import os import os
import logging import logging
import random
class BrowserManager: class BrowserManager:
@@ -36,17 +37,58 @@ class BrowserManager:
except FileNotFoundError as e: except FileNotFoundError as e:
logging.warning(f"警告: {e}") logging.warning(f"警告: {e}")
# 设置更真实的用户代理
co.set_user_agent( co.set_user_agent(
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.6723.92 Safari/537.36" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"
) )
# 基本设置
co.set_pref("credentials_enable_service", False) co.set_pref("credentials_enable_service", False)
co.set_pref("profile.password_manager_enabled", False)
# 禁用自动化标志
co.set_pref("useAutomationExtension", False)
co.set_pref("excludeSwitches", ["enable-automation"])
# WebGL 和 GPU 设置
co.set_pref("webgl.disabled", False)
co.set_pref("webgl.enable_webgl2", True)
# 设置语言和地区
co.set_pref("intl.accept_languages", "en-US,en")
# 基本命令行参数
co.set_argument("--disable-blink-features=AutomationControlled")
co.set_argument("--hide-crash-restore-bubble") co.set_argument("--hide-crash-restore-bubble")
co.set_argument("--no-first-run")
co.set_argument("--no-default-browser-check")
co.set_argument("--disable-popup-blocking")
# 性能和稳定性参数
co.set_argument("--disable-dev-shm-usage")
co.set_argument("--disable-gpu")
co.set_argument("--no-sandbox")
co.set_argument("--ignore-certificate-errors")
# WebGL 相关参数
co.set_argument("--use-gl=swiftshader")
co.set_argument("--enable-webgl")
# 随机端口
co.auto_port() co.auto_port()
# Mac 系统特殊处理 # 系统特定设置
if sys.platform == "darwin": if sys.platform == "darwin": # macOS
co.set_argument("--no-sandbox")
co.set_argument("--disable-gpu") co.set_argument("--disable-gpu")
co.set_argument("--no-sandbox")
elif sys.platform == "win32": # Windows
co.set_argument("--disable-software-rasterizer")
# 设置窗口大小
window_width = random.randint(1024, 1920)
window_height = random.randint(768, 1080)
co.set_argument(f"--window-size={window_width},{window_height}")
return co return co

View File

@@ -246,56 +246,87 @@ class CursorRegistration:
def _handle_turnstile(self): def _handle_turnstile(self):
"""处理 Turnstile 验证""" """处理 Turnstile 验证"""
print(f"{Fore.YELLOW}{EMOJI['VERIFY']} {self.translator.get('register.handle_turnstile')}...{Style.RESET_ALL}") try:
print(f"{Fore.YELLOW}{EMOJI['VERIFY']} {self.translator.get('register.handle_turnstile')}...{Style.RESET_ALL}")
# 设置最大等待时间(秒)
max_wait_time = 10 # 增加等待时间 max_retries = 2
start_time = time.time() retry_interval = (1, 2)
retry_count = 0
while True:
try: while retry_count < max_retries:
# 检查是否超时 retry_count += 1
if time.time() - start_time > max_wait_time: print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('register.turnstile_attempt', attempt=retry_count)}...{Style.RESET_ALL}")
print(f"{Fore.YELLOW}{EMOJI['WAIT']} {self.translator.get('register.no_turnstile')}...{Style.RESET_ALL}")
time.sleep(2)
break
try: try:
challengeCheck = ( # 尝试重置 turnstile
self.signup_tab.ele("@id=cf-turnstile", timeout=1) self.signup_tab.run_js("try { turnstile.reset() } catch(e) { }")
time.sleep(2)
# 定位验证框元素
challenge_check = (
self.signup_tab.ele("@id=cf-turnstile", timeout=2)
.child() .child()
.shadow_root.ele("tag:iframe") .shadow_root.ele("tag:iframe")
.ele("tag:body") .ele("tag:body")
.sr("tag:input") .sr("tag:input")
) )
if challengeCheck: if challenge_check:
challengeCheck.click() print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('register.turnstile_detected')}...{Style.RESET_ALL}")
time.sleep(3)
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('register.turnstile_passed')}{Style.RESET_ALL}") # 随机延时后点击验证
time.sleep(random.uniform(1, 3))
challenge_check.click()
time.sleep(2) time.sleep(2)
break
except:
pass
try:
if (self.signup_tab.ele("@name=password", timeout=0.5) or
self.signup_tab.ele("@name=email", timeout=0.5) or
self.signup_tab.ele("@data-index=0", timeout=0.5)):
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('register.turnstile_passed')}{Style.RESET_ALL}")
time.sleep(2)
break
except:
pass
time.sleep(1)
except Exception as e:
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('register.error', error=str(e))}{Style.RESET_ALL}")
time.sleep(2)
break
time.sleep(2) # 检查验证结果
if self._check_verification_success():
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('register.turnstile_passed')}{Style.RESET_ALL}")
return True
except Exception as e:
print(f"{Fore.YELLOW}{EMOJI['INFO']} {self.translator.get('register.turnstile_attempt_failed', error=str(e))}{Style.RESET_ALL}")
# 检查是否已经验证成功
if self._check_verification_success():
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('register.turnstile_passed')}{Style.RESET_ALL}")
return True
# 随机延时后继续下一次尝试
time.sleep(random.uniform(*retry_interval))
# 超出最大重试次数
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('register.turnstile_max_retries', max=max_retries)}{Style.RESET_ALL}")
return False
except Exception as e:
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('register.turnstile_error', error=str(e))}{Style.RESET_ALL}")
return False
def _check_verification_success(self):
"""检查验证是否成功"""
try:
# 检查是否存在后续表单元素,这表示验证已通过
if (self.signup_tab.ele("@name=password", timeout=0.5) or
self.signup_tab.ele("@name=email", timeout=0.5) or
self.signup_tab.ele("@data-index=0", timeout=0.5) or
self.signup_tab.ele("Account Settings", timeout=0.5)):
return True
# 检查是否出现错误消息
error_messages = [
'xpath://div[contains(text(), "Can\'t verify the user is human")]',
'xpath://div[contains(text(), "Error: 600010")]',
'xpath://div[contains(text(), "Please try again")]'
]
for error_xpath in error_messages:
if self.signup_tab.ele(error_xpath):
return False
return False
except:
return False
def _get_account_info(self): def _get_account_info(self):
"""获取账户信息和 Token""" """获取账户信息和 Token"""

Binary file not shown.

After

Width:  |  Height:  |  Size: 137 KiB

View File

@@ -46,12 +46,28 @@
"sqlite_success": "SQLite Database Updated Successfully", "sqlite_success": "SQLite Database Updated Successfully",
"sqlite_error": "SQLite Database Update Failed: {error}", "sqlite_error": "SQLite Database Update Failed: {error}",
"press_enter": "Press Enter to Exit", "press_enter": "Press Enter to Exit",
"unsupported_os": "Unsupported OS: {os}",
"linux_path_not_found": "Linux Path Not Found",
"updating_system_ids": "Updating System IDs", "updating_system_ids": "Updating System IDs",
"system_ids_updated": "System IDs Updated Successfully", "system_ids_updated": "System IDs Updated Successfully",
"system_ids_update_failed": "System IDs Update Failed: {error}" "system_ids_update_failed": "System IDs Update Failed: {error}",
"windows_guid_updated": "Windows GUID Updated Successfully",
"windows_permission_denied": "Windows Permission Denied",
"windows_guid_update_failed": "Windows GUID Update Failed",
"macos_uuid_updated": "macOS UUID Updated Successfully",
"plutil_command_failed": "plutil Command Failed",
"start_patching": "Starting Patching getMachineId",
"macos_uuid_update_failed": "macOS UUID Update Failed",
"current_version": "Current Cursor Version: {version}",
"patch_completed": "Patching getMachineId Completed",
"patch_failed": "Patching getMachineId Failed: {error}",
"version_check_passed": "Cursor Version Check Passed",
"file_modified": "File Modified"
}, },
"register": { "register": {
"title": "Cursor Registration Tool", "title": "Cursor Registration Tool",
"start": "Starting Registration Process", "start": "Starting Registration Process",
"mailbox": "Successfully Entered Mailbox", "mailbox": "Successfully Entered Mailbox",
"register_start": "Start Register", "register_start": "Start Register",

View File

@@ -48,7 +48,21 @@
"press_enter": "按回车键退出", "press_enter": "按回车键退出",
"updating_system_ids": "更新系统ID", "updating_system_ids": "更新系统ID",
"system_ids_updated": "系统ID更新成功", "system_ids_updated": "系统ID更新成功",
"system_ids_update_failed": "系统ID更新失败: {error}" "system_ids_update_failed": "系统ID更新失败: {error}",
"unsupported_os": "不支持的操作系统: {os}",
"linux_path_not_found": "Linux路径未找到",
"windows_guid_updated": "Windows GUID更新成功",
"windows_permission_denied": "Windows权限拒绝",
"windows_guid_update_failed": "Windows GUID更新失败",
"macos_uuid_updated": "macOS UUID更新成功",
"plutil_command_failed": "plutil命令失败",
"macos_uuid_update_failed": "macOS UUID更新失败",
"start_patching": "开始修补getMachineId",
"current_version": "当前Cursor版本: {version}",
"patch_completed": "getMachineId修补完成",
"patch_failed": "getMachineId修补失败: {error}",
"version_check_passed": "Cursor版本检查通过",
"file_modified": "文件已修改"
}, },
"register": { "register": {
"title": "Cursor 注册工具", "title": "Cursor 注册工具",

View File

@@ -48,8 +48,26 @@
"press_enter": "按回車鍵退出", "press_enter": "按回車鍵退出",
"updating_system_ids": "更新系統ID", "updating_system_ids": "更新系統ID",
"system_ids_updated": "系統ID更新成功", "system_ids_updated": "系統ID更新成功",
"system_ids_update_failed": "系統ID更新失敗: {error}" "system_ids_update_failed": "系統ID更新失敗: {error}",
"unsupported_os": "不支持的操作系統: {os}",
"linux_path_not_found": "Linux路徑未找到",
"windows_guid_updated": "Windows GUID更新成功",
"windows_permission_denied": "Windows權限拒絕",
"windows_guid_update_failed": "Windows GUID更新失敗",
"macos_uuid_updated": "macOS UUID更新成功",
"plutil_command_failed": "plutil命令失敗",
"macos_uuid_update_failed": "macOS UUID更新失敗",
"start_patching": "開始修補getMachineId",
"current_version": "當前Cursor版本: {version}",
"patch_completed": "getMachineId修補完成",
"patch_failed": "getMachineId修補失敗: {error}",
"version_check_passed": "Cursor版本檢查通過",
"file_modified": "文件已修改"
}, },
"register": { "register": {
"title": "Cursor 註冊工具", "title": "Cursor 註冊工具",
"start": "開始註冊流程", "start": "開始註冊流程",

View File

@@ -5,19 +5,11 @@ import uuid
import hashlib import hashlib
import shutil import shutil
import sqlite3 import sqlite3
import logging import platform
import re
import tempfile
from colorama import Fore, Style, init from colorama import Fore, Style, init
from typing import Tuple
# 设置日志记录
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s',
handlers=[
logging.StreamHandler(),
logging.FileHandler('reset_machine.log', encoding='utf-8')
]
)
logger = logging.getLogger(__name__)
# 初始化colorama # 初始化colorama
init() init()
@@ -32,6 +24,173 @@ EMOJI = {
"RESET": "🔄", "RESET": "🔄",
} }
def get_cursor_paths(translator=None) -> Tuple[str, str]:
"""根据不同操作系统获取 Cursor 相关路径"""
system = platform.system()
paths_map = {
"Darwin": {
"base": "/Applications/Cursor.app/Contents/Resources/app",
"package": "package.json",
"main": "out/main.js",
},
"Windows": {
"base": os.path.join(
os.getenv("LOCALAPPDATA", ""), "Programs", "Cursor", "resources", "app"
),
"package": "package.json",
"main": "out/main.js",
},
"Linux": {
"bases": ["/opt/Cursor/resources/app", "/usr/share/cursor/resources/app"],
"package": "package.json",
"main": "out/main.js",
},
}
if system not in paths_map:
raise OSError(translator.get('reset.unsupported_os', system=system) if translator else f"不支持的操作系统: {system}")
if system == "Linux":
for base in paths_map["Linux"]["bases"]:
pkg_path = os.path.join(base, paths_map["Linux"]["package"])
if os.path.exists(pkg_path):
return (pkg_path, os.path.join(base, paths_map["Linux"]["main"]))
raise OSError(translator.get('reset.linux_path_not_found') if translator else "在 Linux 系统上未找到 Cursor 安装路径")
base_path = paths_map[system]["base"]
return (
os.path.join(base_path, paths_map[system]["package"]),
os.path.join(base_path, paths_map[system]["main"]),
)
def version_check(version: str, min_version: str = "", max_version: str = "", translator=None) -> bool:
"""版本号检查"""
version_pattern = r"^\d+\.\d+\.\d+$"
try:
if not re.match(version_pattern, version):
print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('reset.invalid_version_format', version=version)}{Style.RESET_ALL}")
return False
def parse_version(ver: str) -> Tuple[int, ...]:
return tuple(map(int, ver.split(".")))
current = parse_version(version)
if min_version and current < parse_version(min_version):
print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('reset.version_too_low', version=version, min_version=min_version)}{Style.RESET_ALL}")
return False
if max_version and current > parse_version(max_version):
print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('reset.version_too_high', version=version, max_version=max_version)}{Style.RESET_ALL}")
return False
return True
except Exception as e:
print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('reset.version_check_error', error=str(e))}{Style.RESET_ALL}")
return False
def check_cursor_version(translator) -> bool:
"""检查 Cursor 版本"""
try:
pkg_path, _ = get_cursor_paths(translator)
with open(pkg_path, "r", encoding="utf-8") as f:
version = json.load(f)["version"]
return version_check(version, min_version="0.45.0", translator=translator)
except Exception as e:
print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('reset.check_version_failed', error=str(e))}{Style.RESET_ALL}")
return False
def modify_main_js(main_path: str, translator) -> bool:
"""修改 main.js 文件"""
try:
original_stat = os.stat(main_path)
original_mode = original_stat.st_mode
original_uid = original_stat.st_uid
original_gid = original_stat.st_gid
with tempfile.NamedTemporaryFile(mode="w", delete=False) as tmp_file:
with open(main_path, "r", encoding="utf-8") as main_file:
content = main_file.read()
patterns = {
r"async getMachineId\(\)\{return [^??]+\?\?([^}]+)\}": r"async getMachineId(){return \1}",
r"async getMacMachineId\(\)\{return [^??]+\?\?([^}]+)\}": r"async getMacMachineId(){return \1}",
}
for pattern, replacement in patterns.items():
content = re.sub(pattern, replacement, content)
tmp_file.write(content)
tmp_path = tmp_file.name
shutil.copy2(main_path, main_path + ".old")
shutil.move(tmp_path, main_path)
os.chmod(main_path, original_mode)
if os.name != "nt":
os.chown(main_path, original_uid, original_gid)
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {translator.get('reset.file_modified')}{Style.RESET_ALL}")
return True
except Exception as e:
print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('reset.modify_file_failed', error=str(e))}{Style.RESET_ALL}")
if "tmp_path" in locals():
os.unlink(tmp_path)
return False
def patch_cursor_get_machine_id(translator) -> bool:
"""修补 Cursor getMachineId 函数"""
try:
print(f"{Fore.CYAN}{EMOJI['INFO']} {translator.get('reset.start_patching')}...{Style.RESET_ALL}")
# 获取路径
pkg_path, main_path = get_cursor_paths(translator)
# 检查文件权限
for file_path in [pkg_path, main_path]:
if not os.path.isfile(file_path):
print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('reset.file_not_found', path=file_path)}{Style.RESET_ALL}")
return False
if not os.access(file_path, os.W_OK):
print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('reset.no_write_permission', path=file_path)}{Style.RESET_ALL}")
return False
# 获取版本号
try:
with open(pkg_path, "r", encoding="utf-8") as f:
version = json.load(f)["version"]
print(f"{Fore.CYAN}{EMOJI['INFO']} {translator.get('reset.current_version', version=version)}{Style.RESET_ALL}")
except Exception as e:
print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('reset.read_version_failed', error=str(e))}{Style.RESET_ALL}")
return False
# 检查版本
if not version_check(version, min_version="0.45.0", translator=translator):
print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('reset.version_not_supported')}{Style.RESET_ALL}")
return False
print(f"{Fore.CYAN}{EMOJI['INFO']} {translator.get('reset.version_check_passed')}{Style.RESET_ALL}")
# 备份文件
backup_path = main_path + ".bak"
if not os.path.exists(backup_path):
shutil.copy2(main_path, backup_path)
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {translator.get('reset.backup_created', path=backup_path)}{Style.RESET_ALL}")
# 修改文件
if not modify_main_js(main_path, translator):
return False
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {translator.get('reset.patch_completed')}{Style.RESET_ALL}")
return True
except Exception as e:
print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('reset.patch_failed', error=str(e))}{Style.RESET_ALL}")
return False
class MachineIDResetter: class MachineIDResetter:
def __init__(self, translator=None): def __init__(self, translator=None):
self.translator = translator self.translator = translator
@@ -135,7 +294,6 @@ class MachineIDResetter:
return True return True
except Exception as e: except Exception as e:
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('reset.system_ids_update_failed', error=str(e))}{Style.RESET_ALL}") print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('reset.system_ids_update_failed', error=str(e))}{Style.RESET_ALL}")
logger.error(f"System IDs update failed: {e}")
return False return False
def _update_windows_machine_guid(self): def _update_windows_machine_guid(self):
@@ -151,12 +309,12 @@ class MachineIDResetter:
new_guid = str(uuid.uuid4()) new_guid = str(uuid.uuid4())
winreg.SetValueEx(key, "MachineGuid", 0, winreg.REG_SZ, new_guid) winreg.SetValueEx(key, "MachineGuid", 0, winreg.REG_SZ, new_guid)
winreg.CloseKey(key) winreg.CloseKey(key)
logger.info("Windows MachineGuid updated successfully") print("Windows MachineGuid updated successfully")
except PermissionError: except PermissionError:
logger.error("Permission denied: Run as administrator to update Windows MachineGuid") print("Permission denied: Run as administrator to update Windows MachineGuid")
raise raise
except Exception as e: except Exception as e:
logger.error(f"Failed to update Windows MachineGuid: {e}") print(f"Failed to update Windows MachineGuid: {e}")
raise raise
def _update_macos_platform_uuid(self, new_ids): def _update_macos_platform_uuid(self, new_ids):
@@ -168,11 +326,11 @@ class MachineIDResetter:
cmd = f'sudo plutil -replace "UUID" -string "{new_ids["telemetry.macMachineId"]}" "{uuid_file}"' cmd = f'sudo plutil -replace "UUID" -string "{new_ids["telemetry.macMachineId"]}" "{uuid_file}"'
result = os.system(cmd) result = os.system(cmd)
if result == 0: if result == 0:
logger.info("macOS Platform UUID updated successfully") print("macOS Platform UUID updated successfully")
else: else:
raise Exception("Failed to execute plutil command") raise Exception("Failed to execute plutil command")
except Exception as e: except Exception as e:
logger.error(f"Failed to update macOS Platform UUID: {e}") print(f"Failed to update macOS Platform UUID: {e}")
raise raise
def reset_machine_ids(self): def reset_machine_ids(self):
@@ -215,6 +373,14 @@ class MachineIDResetter:
# 更新系统ID # 更新系统ID
self.update_system_ids(new_ids) self.update_system_ids(new_ids)
# 检查 Cursor 版本并执行相应的操作
greater_than_0_45 = check_cursor_version(self.translator)
if greater_than_0_45:
print(f"{Fore.CYAN}{EMOJI['INFO']} 检测到 Cursor 版本 >= 0.45.0,正在修补 getMachineId...{Style.RESET_ALL}")
patch_cursor_get_machine_id(self.translator)
else:
print(f"{Fore.YELLOW}{EMOJI['INFO']} Cursor 版本 < 0.45.0,跳过 getMachineId 修补{Style.RESET_ALL}")
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('reset.success')}{Style.RESET_ALL}") print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('reset.success')}{Style.RESET_ALL}")
print(f"\n{Fore.CYAN}{self.translator.get('reset.new_id')}:{Style.RESET_ALL}") print(f"\n{Fore.CYAN}{self.translator.get('reset.new_id')}:{Style.RESET_ALL}")
for key, value in new_ids.items(): for key, value in new_ids.items():