Compare commits

...

34 Commits

Author SHA1 Message Date
yeongpin
654157b371 fix update readme 2025-02-12 14:36:54 +08:00
yeongpin
f4314cc6da Big Update - Fixed Human Verify Problem 2025-02-12 14:31:11 +08:00
yeongpin
1f29b2dbbe update readme 2025-02-11 16:58:20 +08:00
yeongpin
9c2b3f2fc8 update 2025-02-11 16:53:18 +08:00
yeongpin
8e20a0ed3d update env 2025-02-11 16:50:52 +08:00
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
yeongpin
a873291481 update env 2025-02-05 19:22:01 +08:00
yeongpin
7710ea4bb3 Update support 0.45 2025-02-05 19:21:34 +08:00
yeongpin
13483eed77 update auth message & reset message 2025-01-17 10:12:18 +08:00
yeongpin
eb69f933af Update & Fix reset machine problem 2025-01-15 17:14:05 +08:00
yeongpin
54cd8cf323 Update 107 2025-01-15 13:54:38 +08:00
yeongpin
4e0289c86c Update New107 images 2025-01-15 13:46:54 +08:00
yeongpin
af4a1c4065 Update Readme 2025-01-15 13:44:22 +08:00
yeongpin
e5a4134a41 Update Readme 2025-01-15 13:40:41 +08:00
yeongpin
731db36121 new locale language file 2025-01-15 13:35:09 +08:00
yeongpin
f139fa189d Update Readme 2025-01-15 11:17:34 +08:00
yeongpin
a7e927a557 test update ps1 2025-01-15 11:16:02 +08:00
yeongpin
ffd7b839e7 update stage 2025-01-15 11:07:20 +08:00
31 changed files with 1947 additions and 12383 deletions

4
.env
View File

@@ -1,2 +1,2 @@
version=1.0.6
VERSION=1.0.6
version=1.1.01
VERSION=1.1.01

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

@@ -0,0 +1,206 @@
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: Prepare release files
run: |
cd artifacts
# 重命名文件为最终的可执行文件名
mv CursorFreeVIP_${{ env.VERSION }}_windows.exe/CursorFreeVIP.exe CursorFreeVIP_${{ env.VERSION }}_windows.exe
mv CursorFreeVIP_${{ env.VERSION }}_mac_arm64/CursorFreeVIP CursorFreeVIP_${{ env.VERSION }}_mac_arm64
mv CursorFreeVIP_${{ env.VERSION }}_linux/CursorFreeVIP CursorFreeVIP_${{ env.VERSION }}_linux
mv CursorFreeVIP_${{ env.VERSION }}_mac_intel/CursorFreeVIP CursorFreeVIP_${{ env.VERSION }}_mac_intel
# 删除空目录
rm -rf */
ls -la
- name: Create Release
uses: softprops/action-gh-release@v1
with:
tag_name: v${{ env.VERSION }}
files: |
artifacts/CursorFreeVIP_${{ env.VERSION }}_windows.exe
artifacts/CursorFreeVIP_${{ env.VERSION }}_mac_arm64
artifacts/CursorFreeVIP_${{ env.VERSION }}_linux
artifacts/CursorFreeVIP_${{ env.VERSION }}_mac_intel
draft: false
prerelease: false
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View File

@@ -11,13 +11,14 @@
[![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>
<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.
這是一個自動化工具自動註冊除了Google驗證碼),支持 Windows 和 macOS 系統完成Auth驗證重置Cursor的配置。
<p align="center">
<img src="./images/pro_2025-01-14_14-40-37.png" alt="new" width="400"/><br>
<img src="./images/new107_2025-01-15_13-53-56.png" alt="new" width="400"/><br>
</p>
<br>
@@ -37,6 +38,67 @@ This is a tool to automatically register (except for Google verification code),
## 🔄 更新日志
<details open>
<summary>v1.1.01</summary>
<p align="center">
<img src="./images/cloudflare_2025-02-12_13-43-21.png" alt="free" width="400"/><br>
</p>
1. Hot Fix Cursor Cloudflare Problem | 修復Cursor Cloudflare問題
2. Fix Cursor Cloudflare Human Verification Problem | 修復Cursor Cloudflare人機驗證問題
3. Remake signup logic | 重做註冊邏輯
</details>
<details>
<summary>Other Version Change Log</summary>
<details>
<summary>v1.0.10</summary>
1. Hot Fix Mac Chrome Problem | 修復Mac Chrome問題
2. Fix Linux Start Donet Problem | 修復Linux啟動開發者問題
</details>
<details>
<summary>v1.0.9</summary>
<p align="center">
<img src="./images/cloudflare_2025-02-12_13-43-21.png.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>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>
1. Fix Reset Machine | 修復重置機器
2. Fix Locale Language | 修復多語言
</details>
<details>
<summary>v1.0.7</summary>
1. Add Locale Language Support | 增加多語言支持
<p align="center">
<img src="./images/locale_2025-01-15_13-40-08.png" alt="locale" width="400"/><br>
</p>
</details>
<details>
<summary>v1.0.6</summary>
1. Add Quit Cursor Option | 增加退出Cursor選項
2. Add Recaptcha Path Patch | 增加Recaptcha路徑修復
3. Fix Admin Permission | 修復管理員權限問題
4. Remove all need admin permission | 移除所有需要管理員權限
</details>
<details>
<summary>v1.0.5 - HotFix</summary>
1. Fix: Mac Browser Control | 修復Mac瀏覽器控制問題
@@ -114,6 +176,7 @@ This is a tool to automatically register (except for Google verification code),
<img src="./images/pro_2025-01-11_16-24-03.png" alt="Cursor Pro Logo" width="400"/><br>
</p>
</details>
</details>
## ✨ Features | 功能特點

5
blacklist.txt Normal file
View File

@@ -0,0 +1,5 @@
fr.nf
yopmail.com
1s.fr
xl.cx
fr.cr

View File

@@ -2,6 +2,7 @@ from DrissionPage import ChromiumOptions, ChromiumPage
import sys
import os
import logging
import random
class BrowserManager:
@@ -26,27 +27,71 @@ class BrowserManager:
try:
extension_path = self._get_extension_path()
co.add_extension(extension_path)
co.set_argument("--allow-extensions-in-incognito")
extension_block_path = self.get_extension_block()
co.add_extension(extension_block_path)
co.set_argument("--allow-extensions-in-incognito")
extension_recaptcha_path = self.get_extension_recaptcha()
co.add_extension(extension_recaptcha_path)
co.set_argument("--allow-extensions-in-incognito")
except FileNotFoundError as e:
logging.warning(f"警告: {e}")
# 设置更真实的用户代理
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("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("--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()
# Mac 系统特殊处理
if sys.platform == "darwin":
co.set_argument("--no-sandbox")
# 系统特定设置
if sys.platform == "darwin": # macOS
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

View File

@@ -26,11 +26,14 @@ a = Analysis(
('turnstilePatch', 'turnstilePatch'),
('recaptchaPatch', 'recaptchaPatch'),
('uBlock0.chromium', 'uBlock0.chromium'),
('locales', 'locales'),
('cursor_auth.py', '.'),
('reset_machine_manual.py', '.'),
('cursor_register.py', '.'),
('browser.py', '.'),
('control.py', '.')
('control.py', '.'),
('.env', '.'),
('blacklist.txt', '.')
],
hiddenimports=[
'cursor_auth',

View File

@@ -1,11 +1,25 @@
import time
from colorama import Fore, Style
import random
import os
from colorama import Fore, Style, init
# 初始化colorama
init()
# 定义emoji常量
EMOJI = {
'MAIL': '📧',
'REFRESH': '🔄',
'SUCCESS': '',
'ERROR': '',
'INFO': '',
'CODE': '📱'
}
class BrowserControl:
def __init__(self, browser):
def __init__(self, browser, translator=None):
self.browser = browser
self.translator = translator # 保存translator
self.sign_up_url = "https://authenticator.cursor.sh/sign-up"
self.current_tab = None # 当前标签页
self.signup_tab = None # 注册标签页
@@ -25,20 +39,20 @@ class BrowserControl:
# 保存新标签页
self.signup_tab = new_browser
print(f"{Fore.GREEN}Create New Tab Success | 成功创建新窗口{Style.RESET_ALL}")
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('control.create_new_tab_success')}{Style.RESET_ALL}")
return new_browser
except Exception as e:
print(f"{Fore.RED}Create New Tab Failed | 创建新窗口时发生错误: {str(e)}{Style.RESET_ALL}")
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('control.create_new_tab_failed', error=str(e))}{Style.RESET_ALL}")
return None
def switch_to_tab(self, browser):
"""切换到指定浏览器窗口"""
try:
self.browser = browser
print(f"{Fore.GREEN}Switch Tab Success | 成功切换窗口{Style.RESET_ALL}")
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('control.switch_tab_success')}{Style.RESET_ALL}")
return True
except Exception as e:
print(f"{Fore.RED}Switch Tab Failed | 切换窗口时发生错误: {str(e)}{Style.RESET_ALL}")
except Exception as e:
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('control.switch_tab_failed', error=str(e))}{Style.RESET_ALL}")
return False
def get_current_tab(self):
@@ -48,61 +62,91 @@ class BrowserControl:
def generate_new_email(self):
"""点击新的按钮生成新邮箱"""
try:
print(f"{Fore.CYAN}Click Generate New Email | 点击生成新邮箱...{Style.RESET_ALL}")
print(f"{Fore.CYAN}{EMOJI['MAIL']} {self.translator.get('control.generate_email')}...{Style.RESET_ALL}")
new_button = self.browser.ele('xpath://button[contains(@class, "egenbut")]')
if new_button:
new_button.click()
time.sleep(1) # 等待生成
print(f"{Fore.GREEN}Generate New Email | 成功生成新邮箱{Style.RESET_ALL}")
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('control.generate_email_success')}{Style.RESET_ALL}")
return True
else:
print(f"{Fore.RED}No Generate Button Found | 未找到生成按钮{Style.RESET_ALL}")
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('control.generate_email_failed')}{Style.RESET_ALL}")
return False
except Exception as e:
print(f"{Fore.RED}Generate New Email Failed | 生成新邮箱时发生错误: {str(e)}{Style.RESET_ALL}")
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('control.browser_error', error=str(e))}{Style.RESET_ALL}")
return False
def select_email_domain(self, domain_index=None):
"""选择邮箱域名如果不指定index则随机选择"""
try:
print(f"{Fore.CYAN}Select Email Domain | 选择邮箱域名...{Style.RESET_ALL}")
print(f"{Fore.CYAN}{EMOJI['MAIL']} {self.translator.get('control.select_email_domain')}...{Style.RESET_ALL}")
# 读取黑名单域名
blacklist = []
try:
with open('blacklist.txt', 'r', encoding='utf-8') as f:
blacklist = [line.strip().lower() for line in f if line.strip()]
except FileNotFoundError:
# 如果文件不存在,创建一个包含已知黑名单域名的文件
with open('blacklist.txt', 'w', encoding='utf-8') as f:
f.write("fr.nf\nyopmail.com\n1s.fr\nfr.cr")
blacklist = ["fr.nf", "yopmail.com", "1s.fr", "fr.cr"]
# 找到下拉框
select_element = self.browser.ele('xpath://select[@id="seldom"]')
if select_element:
# 获取所有选项,包括两个 optgroup 下的所有 option
# 获取所有选项
all_options = []
# 获取 "新的" 组下的选项
new_options = self.browser.eles('xpath://select[@id="seldom"]/optgroup[@label="-- 新的 --"]/option')
all_options.extend(new_options)
# 获取 "其他" 组下的选项
other_options = self.browser.eles('xpath://select[@id="seldom"]/optgroup[@label="-- 其他 --"]/option')
all_options.extend(new_options)
all_options.extend(other_options)
if all_options:
# 如果没有指定索引,随机选择一个
if domain_index is None:
domain_index = random.randint(0, len(all_options) - 1)
max_attempts = 5
attempt = 0
if domain_index < len(all_options):
# 获取选中选项的文本
selected_domain = all_options[domain_index].text
print(f"{Fore.CYAN}Select Email Domain | 选择域名: {selected_domain}{Style.RESET_ALL}")
while attempt < max_attempts:
if domain_index is None:
domain_index = random.randint(0, len(all_options) - 1)
# 点击选择
all_options[domain_index].click()
time.sleep(1)
print(f"{Fore.GREEN}Select Email Domain | 成功选择邮箱域名{Style.RESET_ALL}")
return True
if domain_index < len(all_options):
selected_domain = all_options[domain_index].text.lower()
# 检查域名是否在黑名单中
is_blacklisted = False
for blocked_domain in blacklist:
if blocked_domain in selected_domain:
print(f"{Fore.YELLOW}{EMOJI['INFO']} {self.translator.get('control.blocked_domain', domain=blocked_domain)}{Style.RESET_ALL}")
domain_index = None
attempt += 1
is_blacklisted = True
break
if is_blacklisted:
continue
print(f"{Fore.CYAN}{EMOJI['MAIL']} {self.translator.get('control.select_email_domain')}: {selected_domain}{Style.RESET_ALL}")
# 点击选择
all_options[domain_index].click()
time.sleep(1)
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('control.select_email_domain_success')}{Style.RESET_ALL}")
return True
attempt += 1
print(f"{Fore.RED}No Available Domain Options | 未找到可用的域名选项,总共有 {len(all_options)} 个选项{Style.RESET_ALL}")
print(f"{Fore.RED}{EMOJI['ERROR']} 无法找到可用的域名{Style.RESET_ALL}")
return False
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('control.no_available_domain_options', count=len(all_options))}{Style.RESET_ALL}")
return False
else:
print(f"{Fore.RED}No Domain Select Box Found | 未找到域名选择框{Style.RESET_ALL}")
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('control.no_domain_select_box')}{Style.RESET_ALL}")
return False
except Exception as e:
print(f"{Fore.RED}Select Email Domain Failed | 选择邮箱域名时发生错误: {str(e)}{Style.RESET_ALL}")
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('control.select_email_domain_failed', error=str(e))}{Style.RESET_ALL}")
return False
def wait_for_page_load(self, seconds=2):
@@ -112,18 +156,18 @@ class BrowserControl:
def navigate_to(self, url):
"""导航到指定URL"""
try:
print(f"{Fore.CYAN}Navigate to {url} | 正在访问 {url}...{Style.RESET_ALL}")
print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('control.navigate_to', url=url)}...{Style.RESET_ALL}")
self.browser.get(url)
self.wait_for_page_load()
return True
except Exception as e:
print(f"{Fore.RED}Visit {url} Failed | 访问 {url} 时发生错误: {str(e)}{Style.RESET_ALL}")
return False
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('control.browser_error', error=str(e))}{Style.RESET_ALL}")
return False
def copy_and_get_email(self):
"""获取邮箱地址"""
try:
print(f"{Fore.CYAN}Get Email Info | 获取邮箱信息...{Style.RESET_ALL}")
print(f"{Fore.CYAN}{EMOJI['MAIL']} {self.translator.get('control.generate_email')}...{Style.RESET_ALL}")
# 等待元素加载
time.sleep(1)
@@ -133,12 +177,12 @@ class BrowserControl:
email_div = self.browser.ele('xpath://div[@class="segen"]//div[contains(@style, "color: #e5e5e5")]')
if email_div:
email_name = email_div.text.split()[0]
print(f"{Fore.CYAN}Get Email Name | 找到邮箱名称: {email_name}{Style.RESET_ALL}")
print(f"{Fore.CYAN}{EMOJI['MAIL']} {self.translator.get('control.get_email_name')}: {email_name}{Style.RESET_ALL}")
else:
print(f"{Fore.RED}Get Email Name Failed | 无法找到邮箱名称元素{Style.RESET_ALL}")
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('control.get_email_name_failed')}{Style.RESET_ALL}")
return None
except Exception as e:
print(f"{Fore.RED}Get Email Name Failed | 获取邮箱名称时出错: {str(e)}{Style.RESET_ALL}")
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('control.get_email_name_failed', error=str(e))}{Style.RESET_ALL}")
return None
# 直接使用上一步选择的域名
@@ -152,65 +196,47 @@ class BrowserControl:
# 组合完整邮箱地址
full_email = f"{email_name}{domain}"
print(f"{Fore.GREEN}Get Email Address | 完整邮箱地址: {full_email}{Style.RESET_ALL}")
print(f"{Fore.GREEN}{EMOJI['MAIL']} {self.translator.get('control.get_email_address')}: {full_email}{Style.RESET_ALL}")
return full_email
except Exception as e:
print(f"{Fore.RED}Get Email Address Failed | 获取邮箱地址时发生错误: {str(e)}{Style.RESET_ALL}")
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('control.get_email_address_failed', error=str(e))}{Style.RESET_ALL}")
return None
def view_mailbox(self):
"""点击查看邮箱按钮"""
try:
print(f"{Fore.CYAN}Enter Mailbox | 正在进入邮箱...{Style.RESET_ALL}")
print(f"{Fore.CYAN}{EMOJI['MAIL']} {self.translator.get('control.enter_mailbox')}...{Style.RESET_ALL}")
view_button = self.browser.ele('xpath://button[contains(@class, "egenbut") and contains(.//span, "查看邮箱")]')
if view_button:
view_button.click()
time.sleep(2) # 等待页面加载
print(f"{Fore.GREEN}Successfully Entered Mailbox | 成功进入邮箱{Style.RESET_ALL}")
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('control.enter_mailbox_success')}{Style.RESET_ALL}")
return True
else:
print(f"{Fore.RED}No View Mailbox Button Found | 未找到查看邮箱按钮{Style.RESET_ALL}")
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('control.no_view_mailbox_button')}{Style.RESET_ALL}")
return False
except Exception as e:
print(f"{Fore.RED}Enter Mailbox Failed | 进入邮箱时发生错误: {str(e)}{Style.RESET_ALL}")
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('control.enter_mailbox_failed', error=str(e))}{Style.RESET_ALL}")
return False
def refresh_mailbox(self):
"""刷新邮箱获取最新信息"""
try:
print(f"{Fore.CYAN}Refresh Mailbox | 正在刷新邮箱...{Style.RESET_ALL}")
print(f"{Fore.CYAN}{EMOJI['MAIL']} {self.translator.get('control.refresh_mailbox')}...{Style.RESET_ALL}")
refresh_button = self.browser.ele('xpath://button[@id="refresh"]')
if refresh_button:
refresh_button.click()
time.sleep(2) # 等待刷新完成
print(f"{Fore.GREEN}Mailbox Refreshed Successfully | 邮箱刷新成功{Style.RESET_ALL}")
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('control.refresh_mailbox_success')}{Style.RESET_ALL}")
return True
else:
print(f"{Fore.RED}No Refresh Button Found | 未找到刷新按钮{Style.RESET_ALL}")
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('control.no_refresh_button')}{Style.RESET_ALL}")
return False
except Exception as e:
print(f"{Fore.RED}Refresh Mailbox Failed | 刷新邮箱时发生错误: {str(e)}{Style.RESET_ALL}")
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('control.refresh_mailbox_failed', error=str(e))}{Style.RESET_ALL}")
return False
def check_and_click_recaptcha(self):
"""检查并点击验证码复选框"""
try:
# 使用环境变量或配置文件中预设的坐标
click_x = int(os.getenv('RECAPTCHA_X', '100')) # 默认值100
click_y = int(os.getenv('RECAPTCHA_Y', '100')) # 默认值100
print(f"{Fore.CYAN}使用预设坐标点击: x={click_x}, y={click_y}{Style.RESET_ALL}")
# 直接点击预设坐标
self.browser.page.mouse.click(click_x, click_y)
print(f"{Fore.GREEN}Clicked reCAPTCHA Position | 已点击 reCAPTCHA 位置{Style.RESET_ALL}")
time.sleep(1)
return True
except Exception as e:
print(f"{Fore.YELLOW}Click reCAPTCHA Failed | 点击 reCAPTCHA 失败: {str(e)}{Style.RESET_ALL}")
return False
def get_verification_code(self):
"""从邮件中获取验证码"""
@@ -233,24 +259,24 @@ class BrowserControl:
if code_div:
verification_code = code_div.text.strip()
if verification_code.isdigit() and len(verification_code) == 6:
print(f"{Fore.GREEN}Found Verification Code | 找到验证码: {verification_code}{Style.RESET_ALL}")
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('control.found_verification_code')}: {verification_code}{Style.RESET_ALL}")
return verification_code
print(f"{Fore.YELLOW}No Valid Verification Code Found | 未找到有效验证码{Style.RESET_ALL}")
print(f"{Fore.YELLOW}{EMOJI['ERROR']} {self.translator.get('control.no_valid_verification_code')}{Style.RESET_ALL}")
return None
except Exception as e:
print(f"{Fore.RED}Get Verification Code Error | 获取验证码时发生错误: {str(e)}{Style.RESET_ALL}")
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('control.get_verification_code_error', error=str(e))}{Style.RESET_ALL}")
return None
def fill_verification_code(self, code):
"""填写验证码"""
try:
if not code or len(code) != 6:
print(f"{Fore.RED}Verification Code Format Error | 验证码格式不正确{Style.RESET_ALL}")
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('control.verification_code_format_error')}{Style.RESET_ALL}")
return False
print(f"{Fore.CYAN}Fill Verification Code | 正在填写验证码...{Style.RESET_ALL}")
print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('control.fill_verification_code')}...{Style.RESET_ALL}")
# 记住当前标签页(邮箱页面)
email_tab = self.browser
@@ -264,10 +290,10 @@ class BrowserControl:
self.browser.actions.input(digit)
time.sleep(random.uniform(0.1, 0.3))
print(f"{Fore.GREEN}Verification Code Filled | 验证码填写完成{Style.RESET_ALL}")
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('control.verification_code_filled')}{Style.RESET_ALL}")
# 等待页面加载和登录完成
print(f"{Fore.CYAN}Wait for Login | 等待登录完成...{Style.RESET_ALL}")
print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('control.wait_for_login')}...{Style.RESET_ALL}")
time.sleep(5)
# 先访问登录页面确保登录状态
@@ -278,7 +304,7 @@ class BrowserControl:
# 获取cookies第一次尝试
token = self.get_cursor_session_token()
if not token:
print(f"{Fore.YELLOW}Get Token Failed | 首次获取token失败等待后重试...{Style.RESET_ALL}")
print(f"{Fore.YELLOW}{EMOJI['ERROR']} {self.translator.get('control.get_token_failed')}...{Style.RESET_ALL}")
time.sleep(3)
token = self.get_cursor_session_token()
@@ -287,7 +313,7 @@ class BrowserControl:
# 获取到token后再访问设置页面
settings_url = "https://www.cursor.com/settings"
print(f"{Fore.CYAN}Get Account Info | 正在访问设置页面获取账户信息...{Style.RESET_ALL}")
print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('control.get_account_info')}...{Style.RESET_ALL}")
self.browser.get(settings_url)
time.sleep(2)
@@ -302,9 +328,9 @@ class BrowserControl:
if usage_ele:
usage_info = usage_ele.text
total_usage = usage_info.split("/")[-1].strip()
print(f"{Fore.GREEN}Account Usage Limit | 账户可用额度上限: {total_usage}{Style.RESET_ALL}")
print(f"{Fore.GREEN}{EMOJI['INFO']} {self.translator.get('control.account_usage_limit')}: {total_usage}{Style.RESET_ALL}")
except Exception as e:
print(f"{Fore.RED}Get Account Usage Failed | 获取账户额度信息失败: {str(e)}{Style.RESET_ALL}")
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('control.get_account_usage_failed', error=str(e))}{Style.RESET_ALL}")
# 切换回邮箱页面
self.switch_to_tab(email_tab)
@@ -312,7 +338,7 @@ class BrowserControl:
return True
except Exception as e:
print(f"{Fore.RED}Fill Verification Code Failed | 填写验证码时发生错误: {str(e)}{Style.RESET_ALL}")
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('control.fill_verification_code_failed', error=str(e))}{Style.RESET_ALL}")
return False
def check_and_click_turnstile(self):
@@ -324,19 +350,19 @@ class BrowserControl:
# 查找验证框
verify_checkbox = self.browser.ele('xpath://label[contains(@class, "cb-lb")]//input[@type="checkbox"]')
if verify_checkbox:
print(f"{Fore.CYAN}Find Turnstile Verification Box | 找到 Turnstile 验证框,尝试点击...{Style.RESET_ALL}")
print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('control.find_turnstile_verification_box')}...{Style.RESET_ALL}")
verify_checkbox.click()
time.sleep(2) # 等待验证完成
print(f"{Fore.GREEN}Clicked Turnstile Verification Box | 已点击 Turnstile 验证框{Style.RESET_ALL}")
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('control.clicked_turnstile_verification_box')}{Style.RESET_ALL}")
return True
return False
except Exception as e:
print(f"{Fore.YELLOW}Check and Click Turnstile Failed | 未找到 Turnstile 验证框或点击失败: {str(e)}{Style.RESET_ALL}")
print(f"{Fore.YELLOW}{EMOJI['ERROR']} {self.translator.get('control.check_and_click_turnstile_failed', error=str(e))}{Style.RESET_ALL}")
return False
def get_cursor_session_token(self, max_attempts=3, retry_interval=2):
"""获取Cursor会话token"""
print(f"{Fore.CYAN}Get Cursor Session Token | 开始获取cookie...{Style.RESET_ALL}")
print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('control.get_cursor_session_token')}...{Style.RESET_ALL}")
attempts = 0
while attempts < max_attempts:
@@ -348,21 +374,21 @@ class BrowserControl:
for cookie in all_cookies:
if cookie.get("name") == "WorkosCursorSessionToken":
token = cookie["value"].split("%3A%3A")[1]
print(f"{Fore.GREEN}成功获取CursorSessionToken: {token}{Style.RESET_ALL}")
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('control.get_cursor_session_token_success')}: {token}{Style.RESET_ALL}")
return token
attempts += 1
if attempts < max_attempts:
print(f"{Fore.YELLOW} Try | 第 {attempts} 次尝试未获取到CursorSessionToken{retry_interval}秒后重试...{Style.RESET_ALL}")
print(f"{Fore.YELLOW}{EMOJI['ERROR']} {self.translator.get('control.get_cursor_session_token_failed', attempts=attempts, retry_interval=retry_interval)}...{Style.RESET_ALL}")
time.sleep(retry_interval)
else:
print(f"{Fore.RED}Reach Max Attempts ({max_attempts}) | 已达到最大尝试次数({max_attempts})获取CursorSessionToken失败{Style.RESET_ALL}")
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('control.reach_max_attempts', max_attempts=max_attempts)}{Style.RESET_ALL}")
except Exception as e:
print(f"{Fore.RED}获取cookie失败: {str(e)}{Style.RESET_ALL}")
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('control.get_cookie_failed', error=str(e))}{Style.RESET_ALL}")
attempts += 1
if attempts < max_attempts:
print(f"{Fore.YELLOW}Will Retry in {retry_interval} seconds | 将在 {retry_interval} 秒后重试...{Style.RESET_ALL}")
print(f"{Fore.YELLOW}{EMOJI['ERROR']} {self.translator.get('control.will_retry_in', retry_interval=retry_interval)}...{Style.RESET_ALL}")
time.sleep(retry_interval)
return None
@@ -373,6 +399,6 @@ class BrowserControl:
with open('cursor_tokens.txt', 'a', encoding='utf-8') as f:
f.write(f"Token: {token}\n")
f.write("-" * 50 + "\n")
print(f"{Fore.GREEN}Token Saved to cursor_tokens.txt | Token已保存到 cursor_tokens.txt{Style.RESET_ALL}")
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('control.token_saved_to_file')}{Style.RESET_ALL}")
except Exception as e:
print(f"{Fore.RED}Save Token Failed | 保存Token时发生错误: {str(e)}{Style.RESET_ALL}")
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('control.save_token_failed', error=str(e))}{Style.RESET_ALL}")

View File

@@ -14,11 +14,13 @@ EMOJI = {
'ERROR': '',
'WARN': '⚠️',
'INFO': '',
'KEY': '🔑'
'FILE': '📄',
'KEY': '🔐'
}
class CursorAuth:
def __init__(self):
def __init__(self, translator=None):
self.translator = translator
# 判断操作系统
if os.name == "nt": # Windows
self.db_path = os.path.join(
@@ -54,7 +56,7 @@ class CursorAuth:
# 重新连接数据库
conn = sqlite3.connect(self.db_path)
print(f"{EMOJI['INFO']} {Fore.GREEN}Successfully connected to database | 成功连接到数据库{Style.RESET_ALL}")
print(f"{EMOJI['INFO']} {Fore.GREEN} {self.translator.get('auth.connected_to_database')}{Style.RESET_ALL}")
cursor = conn.cursor()
# 增加超时和其他优化设置
@@ -88,10 +90,10 @@ class CursorAuth:
UPDATE ItemTable SET value = ?
WHERE key = ?
""", (value, key))
print(f"{EMOJI['INFO']} {Fore.CYAN}Updating {key.split('/')[-1]}...{Style.RESET_ALL}")
print(f"{EMOJI['INFO']} {Fore.CYAN} {self.translator.get('auth.updating_pair')} {key.split('/')[-1]}...{Style.RESET_ALL}")
cursor.execute("COMMIT")
print(f"{EMOJI['SUCCESS']} {Fore.GREEN}Database updated successfully | 数据库更新成功{Style.RESET_ALL}")
print(f"{EMOJI['SUCCESS']} {Fore.GREEN}{self.translator.get('auth.database_updated_successfully')}{Style.RESET_ALL}")
return True
except Exception as e:
@@ -99,14 +101,14 @@ class CursorAuth:
raise e
except sqlite3.Error as e:
print(f"\n{EMOJI['ERROR']} {Fore.RED}Database error | 数据库错误: {str(e)}{Style.RESET_ALL}")
print(f"\n{EMOJI['ERROR']} {Fore.RED} {self.translator.get('auth.database_error', error=str(e))}{Style.RESET_ALL}")
return False
except Exception as e:
print(f"\n{EMOJI['ERROR']} {Fore.RED}An error occurred | 发生错误: {str(e)}{Style.RESET_ALL}")
print(f"\n{EMOJI['ERROR']} {Fore.RED} {self.translator.get('auth.an_error_occurred', error=str(e))}{Style.RESET_ALL}")
return False
finally:
if conn:
conn.close()
print(f"{EMOJI['DB']} {Fore.CYAN}Database connection closed | 数据库连接已关闭{Style.RESET_ALL}")
print(f"{EMOJI['DB']} {Fore.CYAN} {self.translator.get('auth.database_connection_closed')}{Style.RESET_ALL}")

View File

@@ -13,7 +13,7 @@ os.environ["PYINSTALLER_VERBOSE"] = "0"
# 初始化colorama
init()
# 定义emoji和颜色常量
# 定义emoji常量
EMOJI = {
'START': '🚀',
'FORM': '📝',
@@ -24,13 +24,15 @@ EMOJI = {
'ERROR': '',
'WAIT': '',
'SUCCESS': '',
'MAIL': '<EFBFBD><EFBFBD>',
'MAIL': '📧',
'KEY': '🔐',
'UPDATE': '🔄'
'UPDATE': '🔄',
'INFO': ''
}
class CursorRegistration:
def __init__(self):
def __init__(self, translator=None):
self.translator = translator
# 设置为显示模式
os.environ['BROWSER_HEADLESS'] = 'False'
self.browser_manager = BrowserManager()
@@ -60,11 +62,11 @@ class CursorRegistration:
return first_letter + rest_letters
def setup_email(self):
"""Setup Temporary Email"""
"""设置邮箱"""
try:
print(f"{Fore.CYAN}Staring Browser | 正在启动浏览器...{Style.RESET_ALL}")
print(f"{Fore.CYAN}{EMOJI['START']} {self.translator.get('register.browser_start')}...{Style.RESET_ALL}")
self.browser = self.browser_manager.init_browser()
self.controller = BrowserControl(self.browser)
self.controller = BrowserControl(self.browser, self.translator)
# 打开邮箱生成器页面(第一个标签页)
self.controller.navigate_to(self.mail_url)
@@ -80,7 +82,7 @@ class CursorRegistration:
# 获取邮箱地址
self.email_address = self.controller.copy_and_get_email()
if self.email_address:
print(f"{Fore.CYAN}Get Email Address | 获取到的邮箱地址: {self.email_address}{Style.RESET_ALL}")
print(f"{EMOJI['MAIL']}{Fore.CYAN} {self.translator.get('register.get_email_address')}: {self.email_address}{Style.RESET_ALL}")
# 进入邮箱
if self.controller.view_mailbox():
@@ -89,224 +91,62 @@ class CursorRegistration:
return False
except Exception as e:
print(f"{Fore.RED}Error Occured | 发生错误: {str(e)}{Style.RESET_ALL}")
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('register.setup_error', error=str(e))}{Style.RESET_ALL}")
return False
def register_cursor(self):
"""注册 Cursor 账号"""
signup_browser_manager = None
"""注册 Cursor"""
browser_tab = None
try:
print(f"\n{Fore.CYAN}{EMOJI['START']}Start Register | 开始 Cursor 注册流程{Style.RESET_ALL}")
print(f"{Fore.CYAN}{EMOJI['START']} {self.translator.get('register.register_start')}...{Style.RESET_ALL}")
# 创建新的浏览器实例用于注册
from browser import BrowserManager
signup_browser_manager = BrowserManager(noheader=True)
self.signup_tab = signup_browser_manager.init_browser()
# 直接使用 new_signup.py 进行注册
from new_signup import main as new_signup_main
# 访问注册页面
self.signup_tab.get(self.sign_up_url)
time.sleep(2)
# 填写注册表单
if self.signup_tab.ele("@name=first_name"):
print(f"{Fore.YELLOW}{EMOJI['FORM']}Fill Form | 填写注册信息...{Style.RESET_ALL}")
self.signup_tab.ele("@name=first_name").input(self.first_name)
time.sleep(random.uniform(1, 2))
self.signup_tab.ele("@name=last_name").input(self.last_name)
time.sleep(random.uniform(1, 2))
self.signup_tab.ele("@name=email").input(self.email_address)
time.sleep(random.uniform(1, 2))
self.signup_tab.ele("@type=submit").click()
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} Basic Info Submitted | 基本信息提交完成{Style.RESET_ALL}")
# 处理 Turnstile 验证
self._handle_turnstile()
# 设置密码
if self.signup_tab.ele("@name=password"):
print(f"{Fore.YELLOW}{EMOJI['PASSWORD']} Set Password | 设置密码...{Style.RESET_ALL}")
self.signup_tab.ele("@name=password").input(self.password)
time.sleep(random.uniform(1, 2))
self.signup_tab.ele("@type=submit").click()
# 执行新的注册流程,传入 translator
result, browser_tab = new_signup_main(
email=self.email_address,
password=self.password,
first_name=self.first_name,
last_name=self.last_name,
email_tab=self.email_tab,
controller=self.controller,
translator=self.translator
)
self._handle_turnstile()
# 等待并获取验证码
time.sleep(5) # 等待验证码邮件
self.browser.refresh()
if result:
# 使用返回的浏览器实例获取账户信息
self.signup_tab = browser_tab # 保存浏览器实例
success = self._get_account_info()
# 获取信息后关闭浏览器
if browser_tab:
try:
browser_tab.quit()
except:
pass
return success
# 获取验证码设置60秒超时
verification_code = None
max_attempts = 10 # 增加到10次尝试
retry_interval = 5 # 每5秒重试一次
start_time = time.time()
timeout = 60 # 60秒超时
print(f"{Fore.CYAN}{EMOJI['WAIT']} Start Getting Verification Code | 开始获取验证码将在60秒内尝试...{Style.RESET_ALL}")
return False
for attempt in range(max_attempts):
# 检查是否超时
if time.time() - start_time > timeout:
print(f"{Fore.RED}{EMOJI['ERROR']} Get Verification Code Timeout | 获取验证码超时{Style.RESET_ALL}")
break
verification_code = self.controller.get_verification_code()
if verification_code:
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} Get Verification Code Success | 成功获取验证码: {verification_code}{Style.RESET_ALL}")
break
remaining_time = int(timeout - (time.time() - start_time))
print(f"{Fore.YELLOW}{EMOJI['WAIT']} Try | 第 {attempt + 1} Get Verification Code | 次尝试未获取到验证码Time Remaining | 剩余时间: {remaining_time}{Style.RESET_ALL}")
# 刷新邮箱
self.browser.refresh()
time.sleep(retry_interval)
if verification_code:
# 在注册页面填写验证码
for i, digit in enumerate(verification_code):
self.signup_tab.ele(f"@data-index={i}").input(digit)
time.sleep(random.uniform(0.1, 0.3))
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} Verification Code Filled | 验证码填写完成{Style.RESET_ALL}")
time.sleep(3)
self._handle_turnstile()
# 检查当前URL
current_url = self.signup_tab.url
if "authenticator.cursor.sh" in current_url:
print(f"{Fore.CYAN}{EMOJI['VERIFY']} Detect Login Page | 检测到登录页面,开始登录...{Style.RESET_ALL}")
# 填写邮箱
email_input = self.signup_tab.ele('@name=email')
if email_input:
email_input.input(self.email_address)
time.sleep(random.uniform(1, 2))
# 点击提交
submit_button = self.signup_tab.ele('@type=submit')
if submit_button:
submit_button.click()
time.sleep(2)
# 处理 Turnstile 验证
self._handle_turnstile()
# 填写密码
password_input = self.signup_tab.ele('@name=password')
if password_input:
password_input.input(self.password)
time.sleep(random.uniform(1, 2))
# 点击提交
submit_button = self.signup_tab.ele('@type=submit')
if submit_button:
submit_button.click()
time.sleep(2)
# 处理 Turnstile 验证
self._handle_turnstile()
# 等待跳转到设置页面
max_wait = 30
start_time = time.time()
while time.time() - start_time < max_wait:
if "cursor.com/settings" in self.signup_tab.url:
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} Login Success and Jump to Settings Page | 成功登录并跳转到设置页面{Style.RESET_ALL}")
break
time.sleep(1)
# 获取账户信息
result = self._get_account_info()
# 关闭注册窗口
if signup_browser_manager:
signup_browser_manager.quit()
return result
else:
print(f"{Fore.RED}{EMOJI['ERROR']} Get Verification Code Timeout | 未能在60秒内获取到验证码{Style.RESET_ALL}")
return False
except Exception as e:
print(f"{Fore.RED}{EMOJI['ERROR']} Register Process Error | 注册过程出错: {str(e)}{Style.RESET_ALL}")
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('register.register_process_error', error=str(e))}{Style.RESET_ALL}")
return False
finally:
# 确保在任何情况下都关闭注册窗口
if signup_browser_manager:
signup_browser_manager.quit()
def _handle_turnstile(self):
"""处理 Turnstile 验证"""
print(f"{Fore.YELLOW}{EMOJI['VERIFY']} Handle Turnstile | 处理 Turnstile 验证...{Style.RESET_ALL}")
# 设置最大等待时间(秒)
max_wait_time = 10 # 增加等待时间
start_time = time.time()
while True:
try:
# 检查是否超时
if time.time() - start_time > max_wait_time:
print(f"{Fore.YELLOW}{EMOJI['WAIT']} Not Detect Turnstile | 未检测到 Turnstile 验证,继续下一步...{Style.RESET_ALL}")
time.sleep(2) # 添加短暂延迟
break
# 检查是否存在验证框
# 确保在任何情况下都关闭浏览器
if browser_tab:
try:
challengeCheck = (
self.signup_tab.ele("@id=cf-turnstile", timeout=1)
.child()
.shadow_root.ele("tag:iframe")
.ele("tag:body")
.sr("tag:input")
)
if challengeCheck:
challengeCheck.click()
time.sleep(3) # 增加点击后的等待时间
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} Turnstile Passed | 验证通过{Style.RESET_ALL}")
time.sleep(2) # 确保验证完全完成
break
browser_tab.quit()
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']} Verification Passed | 验证已通过{Style.RESET_ALL}")
time.sleep(2) # 添加短暂延迟
break
except:
pass
# 等待短暂时间后继续检查
time.sleep(1)
except Exception as e:
print(f"{Fore.RED}{EMOJI['ERROR']} Turnstile Error | Turnstile 处理出错: {str(e)}{Style.RESET_ALL}")
time.sleep(2) # 出错时等待更长时间
break
# 最后再等待一下,确保页面加载完成
time.sleep(2)
def _get_account_info(self):
"""获取账户信息和 Token"""
try:
# 访问设置页面
self.signup_tab.get(self.settings_url)
time.sleep(2)
# 获取账户额度信息
usage_selector = (
"css:div.col-span-2 > div > div > div > div > "
"div:nth-child(1) > div.flex.items-center.justify-between.gap-2 > "
@@ -317,8 +157,7 @@ class CursorRegistration:
if usage_ele:
total_usage = usage_ele.text.split("/")[-1].strip()
# 获取 Token
print(f"{Fore.CYAN}{EMOJI['WAIT']} Get Cursor Session Token | 开始获取 Cursor Session Token...{Style.RESET_ALL}")
print(f"{Fore.CYAN}{EMOJI['WAIT']} {self.translator.get('register.get_token')}...{Style.RESET_ALL}")
max_attempts = 30
retry_interval = 2
attempts = 0
@@ -329,46 +168,45 @@ class CursorRegistration:
for cookie in cookies:
if cookie.get("name") == "WorkosCursorSessionToken":
token = cookie["value"].split("%3A%3A")[1]
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} Get Token Success | Token 获取成功{Style.RESET_ALL}")
# 保存账户信息
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('register.token_success')}{Style.RESET_ALL}")
self._save_account_info(token, total_usage)
return True
attempts += 1
if attempts < max_attempts:
print(
f"{Fore.YELLOW}{EMOJI['WAIT']} Try | 第 {attempts} times to get Token | 次尝试未获取到 Token{retry_interval}秒后重试...{Style.RESET_ALL}"
)
print(f"{Fore.YELLOW}{EMOJI['WAIT']} {self.translator.get('register.token_attempt', attempt=attempts, time=retry_interval)}{Style.RESET_ALL}")
time.sleep(retry_interval)
else:
print(f"{Fore.RED}{EMOJI['ERROR']} Reach Max Attempts ({max_attempts}) | 已达到最大尝试次数({max_attempts}),获取 Token 失败{Style.RESET_ALL}")
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('register.token_max_attempts', max=max_attempts)}{Style.RESET_ALL}")
except Exception as e:
print(f"{Fore.RED}{EMOJI['ERROR']} Get Token Failed | 获取 Token 失败: {str(e)}{Style.RESET_ALL}")
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('register.token_failed', error=str(e))}{Style.RESET_ALL}")
attempts += 1
if attempts < max_attempts:
print(f"{Fore.YELLOW}{EMOJI['WAIT']} Will Retry in {retry_interval} seconds | 将在 {retry_interval} 秒后重试...{Style.RESET_ALL}")
print(f"{Fore.YELLOW}{EMOJI['WAIT']} {self.translator.get('register.token_attempt', attempt=attempts, time=retry_interval)}{Style.RESET_ALL}")
time.sleep(retry_interval)
return False
except Exception as e:
print(f"{Fore.RED}{EMOJI['ERROR']} Get Account Info Failed | 获取账户信息失败: {str(e)}{Style.RESET_ALL}")
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('register.account_error', error=str(e))}{Style.RESET_ALL}")
return False
def _save_account_info(self, token, total_usage):
"""保存账户信息到文件"""
try:
# 先更新认证信息
print(f"{Fore.CYAN}{EMOJI['KEY']} 正在更新 Cursor 认证信息...{Style.RESET_ALL}")
if update_cursor_auth(email=self.email_address, access_token=token, refresh_token=token):
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} Cursor Auth Info Updated | 认证信息更新成功{Style.RESET_ALL}")
print(f"{Fore.CYAN}{EMOJI['KEY']} {self.translator.get('register.update_cursor_auth_info')}...{Style.RESET_ALL}")
if self.update_cursor_auth(email=self.email_address, access_token=token, refresh_token=token):
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('register.cursor_auth_info_updated')}...{Style.RESET_ALL}")
else:
print(f"{Fore.RED}{EMOJI['ERROR']} Cursor Auth Info Update Failed | 认证信息更新失败{Style.RESET_ALL}")
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('register.cursor_auth_info_update_failed')}...{Style.RESET_ALL}")
# 重置机器ID
print(f"{Fore.CYAN}{EMOJI['UPDATE']} Reset Machine ID | 正在重置机器ID...{Style.RESET_ALL}")
MachineIDResetter().reset_machine_ids()
print(f"{Fore.CYAN}{EMOJI['UPDATE']} {self.translator.get('register.reset_machine_id')}...{Style.RESET_ALL}")
resetter = MachineIDResetter(self.translator) # 创建实例时传入translator
if not resetter.reset_machine_ids(): # 直接调用reset_machine_ids方法
raise Exception("Failed to reset machine ID")
# 保存账户信息到文件
with open('cursor_accounts.txt', 'a', encoding='utf-8') as f:
@@ -379,11 +217,11 @@ class CursorRegistration:
f.write(f"Usage Limit: {total_usage}\n")
f.write(f"{'='*50}\n")
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} Account Info Saved to cursor_accounts.txt | 账户信息已保存到 cursor_accounts.txt{Style.RESET_ALL}")
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('register.account_info_saved')}...{Style.RESET_ALL}")
return True
except Exception as e:
print(f"{Fore.RED}{EMOJI['ERROR']} Save Account Info Failed | 保存账户信息失败: {str(e)}{Style.RESET_ALL}")
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('register.save_account_info_failed', error=str(e))}{Style.RESET_ALL}")
return False
def start(self):
@@ -391,25 +229,30 @@ class CursorRegistration:
try:
if self.setup_email():
if self.register_cursor():
print(f"\n{Fore.GREEN}{EMOJI['DONE']} Cursor Registration Completed | 注册完成!{Style.RESET_ALL}")
print(f"\n{Fore.GREEN}{EMOJI['DONE']} {self.translator.get('register.cursor_registration_completed')}...{Style.RESET_ALL}")
return True
return False
finally:
if self.browser_manager:
self.browser_manager.quit()
def update_cursor_auth(self, email=None, access_token=None, refresh_token=None):
"""更新Cursor的认证信息的便捷函数"""
auth_manager = CursorAuth(translator=self.translator)
return auth_manager.update_auth(email, access_token, refresh_token)
def main(translator=None):
"""Main function to be called from main.py"""
print(f"\n{Fore.CYAN}{'='*50}{Style.RESET_ALL}")
print(f"{Fore.CYAN}{EMOJI['START']} {translator.get('register.title')}{Style.RESET_ALL}")
print(f"{Fore.CYAN}{'='*50}{Style.RESET_ALL}")
def update_cursor_auth(email=None, access_token=None, refresh_token=None):
"""
更新Cursor的认证信息的便捷函数
"""
auth_manager = CursorAuth()
return auth_manager.update_auth(email, access_token, refresh_token)
def main():
registration = CursorRegistration()
registration = CursorRegistration(translator)
registration.start()
print(f"\n{Fore.CYAN}{'='*50}{Style.RESET_ALL}")
input(f"{EMOJI['INFO']} {translator.get('register.press_enter')}...")
if __name__ == "__main__":
main()
from main import translator as main_translator
main(main_translator)

Binary file not shown.

After

Width:  |  Height:  |  Size: 288 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 137 KiB

178
locales/en.json Normal file
View File

@@ -0,0 +1,178 @@
{
"menu": {
"title": "Available Options",
"exit": "Exit Program",
"reset": "Reset Machine Manual",
"register": "Register Cursor",
"quit": "Quit Cursor",
"select_language": "Select Language",
"input_choice": "Enter your choice ({choices})",
"invalid_choice": "Invalid choice. Please try again",
"program_terminated": "Program terminated by user",
"error_occurred": "An error occurred: {error}",
"press_enter": "Press Enter to Exit"
},
"languages": {
"en": "English",
"zh_cn": "简体中文",
"zh_tw": "繁體中文"
},
"quit_cursor": {
"start": "Start Quitting Cursor",
"no_process": "No Running Cursor Process",
"terminating": "Terminating Process {pid}",
"waiting": "Waiting for Process to Exit",
"success": "All Cursor Processes Closed",
"timeout": "Process Timeout: {pids}",
"error": "Error Occurred: {error}"
},
"reset": {
"title": "Cursor Machine ID Reset Tool",
"checking": "Checking Config File",
"not_found": "Config File Not Found",
"no_permission": "Cannot Read or Write Config File, Please Check File Permissions",
"reading": "Reading Current Config",
"creating_backup": "Creating Config Backup",
"backup_exists": "Backup File Already Exists, Skipping Backup Step",
"generating": "Generating New Machine ID",
"saving_json": "Saving New Config to JSON",
"success": "Machine ID Reset Successfully",
"new_id": "New Machine ID",
"permission_error": "Permission Error: {error}",
"run_as_admin": "Please Try Running This Program as Administrator",
"process_error": "Reset Process Error: {error}",
"updating_sqlite": "Updating SQLite Database",
"updating_pair": "Updating Key-Value Pair",
"sqlite_success": "SQLite Database Updated Successfully",
"sqlite_error": "SQLite Database Update Failed: {error}",
"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",
"system_ids_updated": "System IDs Updated Successfully",
"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": {
"title": "Cursor Registration Tool",
"start": "Starting Registration Process",
"handling_turnstile": "Handling Turnstile",
"retry_verification": "Retry Verification",
"detect_turnstile": "Detect Turnstile",
"verification_success": "Verification Success",
"starting_browser": "Starting Browser",
"form_success": "Form Success",
"browser_started": "Browser Started",
"waiting_for_second_verification": "Waiting for Second Verification",
"waiting_for_verification_code": "Waiting for Verification Code",
"password_success": "Password Set Successfully",
"password_error": "Password Set Failed: {error}",
"waiting_for_page_load": "Waiting for Page Load",
"first_verification_passed": "First Verification Passed",
"mailbox": "Successfully Entered Mailbox",
"register_start": "Start Register",
"form_submitted": "Form Submitted, Start Verification...",
"filling_form": "Fill Form",
"visiting_url": "Visiting URL",
"basic_info": "Basic Info Submitted",
"handle_turnstile": "Handle Turnstile",
"no_turnstile": "Not Detect Turnstile",
"turnstile_passed": "Turnstile Passed",
"verification_start": "Start Getting Verification Code",
"verification_timeout": "Get Verification Code Timeout",
"verification_not_found": "No Verification Code Found",
"try_get_code": "Try | {attempt} Get Verification Code | Time Remaining: {time}s",
"get_account": "Getting Account Info",
"get_token": "Get Cursor Session Token",
"token_success": "Get Token Success",
"token_attempt": "Try | {attempt} times to get Token | Will retry in {time}s",
"token_max_attempts": "Reach Max Attempts ({max}) | Failed to get Token",
"token_failed": "Get Token Failed: {error}",
"account_error": "Get Account Info Failed: {error}",
"press_enter": "Press Enter to Exit",
"browser_start": "Starting Browser",
"open_mailbox": "Opening Mailbox Page",
"email_error": "Failed to Get Email Address",
"setup_error": "Email Setup Error: {error}",
"start_getting_verification_code": "Start Getting Verification Code, Will Try in 60s",
"get_verification_code_timeout": "Get Verification Code Timeout",
"get_verification_code_success": "Get Verification Code Success",
"try_get_verification_code": "Try | {attempt} Get Verification Code | Time Remaining: {remaining_time}s",
"verification_code_filled": "Verification Code Filled",
"login_success_and_jump_to_settings_page": "Login Success and Jump to Settings Page",
"detect_login_page": "Detect Login Page, Start Login...",
"cursor_registration_completed": "Cursor Registration Completed!",
"set_password": "Set Password",
"basic_info_submitted": "Basic Info Submitted",
"cursor_auth_info_updated": "Cursor Auth Info Updated",
"cursor_auth_info_update_failed": "Cursor Auth Info Update Failed",
"reset_machine_id": "Reset Machine ID",
"account_info_saved": "Account Info Saved",
"save_account_info_failed": "Save Account Info Failed",
"get_email_address": "Get Email Address",
"update_cursor_auth_info": "Update Cursor Auth Info",
"register_process_error": "Register Process Error: {error}"
},
"auth": {
"title": "Cursor Auth Manager",
"checking_auth": "Checking Auth File",
"auth_not_found": "Auth File Not Found",
"auth_file_error": "Auth File Error: {error}",
"reading_auth": "Reading Auth File",
"updating_auth": "Updating Auth Info",
"auth_updated": "Auth Info Updated Successfully",
"auth_update_failed": "Auth Info Update Failed: {error}",
"auth_file_created": "Auth File Created",
"auth_file_create_failed": "Auth File Create Failed: {error}",
"press_enter": "Press Enter to Exit",
"reset_machine_id": "Reset Machine ID",
"database_connection_closed": "Database Connection Closed",
"database_updated_successfully": "Database Updated Successfully",
"connected_to_database": "Connected to Database",
"updating_pair": "Updating Key-Value Pair"
},
"control": {
"generate_email": "Generating New Email",
"blocked_domain": "Blocked Domain",
"select_domain": "Selecting Random Domain",
"copy_email": "Copying Email Address",
"enter_mailbox": "Entering Mailbox",
"refresh_mailbox": "Refreshing Mailbox",
"check_verification": "Checking Verification Code",
"verification_found": "Verification Code Found",
"verification_not_found": "No Verification Code Found",
"browser_error": "Browser Control Error: {error}",
"navigation_error": "Navigation Error: {error}",
"email_copy_error": "Email Copy Error: {error}",
"mailbox_error": "Mailbox Error: {error}",
"token_saved_to_file": "Token Saved to cursor_tokens.txt",
"navigate_to": "Navigating to {url}",
"generate_email_success": "Generate Email Success",
"select_email_domain": "Select Email Domain",
"select_email_domain_success": "Select Email Domain Success",
"get_email_name": "Get Email Name",
"get_email_name_success": "Get Email Name Success",
"get_email_address": "Get Email Address",
"get_email_address_success": "Get Email Address Success",
"enter_mailbox_success": "Enter Mailbox Success",
"found_verification_code": "Found Verification Code",
"get_cursor_session_token": "Get Cursor Session Token",
"get_cursor_session_token_success": "Get Cursor Session Token Success",
"get_cursor_session_token_failed": "Get Cursor Session Token Failed",
"save_token_failed": "Save Token Failed",
"database_updated_successfully": "Database Updated Successfully",
"database_connection_closed": "Database Connection Closed",
"no_valid_verification_code": "No Valid Verification Code"
}
}

175
locales/zh_cn.json Normal file
View File

@@ -0,0 +1,175 @@
{
"menu": {
"title": "可用选项",
"exit": "退出程序",
"reset": "重置机器标识",
"register": "注册 Cursor",
"quit": "退出 Cursor",
"select_language": "选择语言",
"input_choice": "输入选择 ({choices})",
"invalid_choice": "无效选择,请重试",
"program_terminated": "程序被用户终止",
"error_occurred": "发生错误: {error}",
"press_enter": "按回车键退出"
},
"languages": {
"en": "English",
"zh_cn": "简体中文",
"zh_tw": "繁體中文"
},
"quit_cursor": {
"start": "开始退出 Cursor",
"no_process": "未发现运行中的 Cursor 进程",
"terminating": "正在终止进程 {pid}",
"waiting": "等待进程退出",
"success": "所有 Cursor 进程已正常关闭",
"timeout": "以下进程未能在规定时间内关闭: {pids}",
"error": "关闭 Cursor 进程时发生错误: {error}"
},
"reset": {
"title": "Cursor 机器标识重置工具",
"checking": "检查配置文件",
"not_found": "配置文件未找到",
"no_permission": "无法读取或写入配置文件,请检查文件权限",
"reading": "读取当前配置",
"creating_backup": "创建配置备份",
"backup_exists": "备份文件已存在,跳过备份步骤",
"generating": "生成新机器标识",
"saving_json": "保存新配置到JSON",
"success": "机器标识重置成功",
"new_id": "新机器标识",
"permission_error": "权限错误: {error}",
"run_as_admin": "请尝试以管理员身份运行此程序",
"process_error": "重置进程错误: {error}",
"updating_sqlite": "更新SQLite数据库",
"updating_pair": "更新键值对",
"sqlite_success": "SQLite数据库更新成功",
"sqlite_error": "SQLite数据库更新失败: {error}",
"press_enter": "按回车键退出",
"updating_system_ids": "更新系统ID",
"system_ids_updated": "系统ID更新成功",
"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": {
"title": "Cursor 注册工具",
"start": "开始注册流程",
"browser_started": "浏览器已启动",
"password_success": "密码设置完成",
"password_error": "密码设置失败: {error}",
"waiting_for_page_load": "等待页面加载",
"mailbox": "成功进入邮箱",
"waiting_for_second_verification": "等待第二阶段验证",
"waiting_for_verification_code": "等待验证码",
"first_verification_passed": "第一阶段验证通过",
"register_start": "开始注册流程",
"form_submitted": "表单已提交,开始验证...",
"filling_form": "填写注册信息",
"visiting_url": "访问URL",
"basic_info": "基本信息提交完成",
"handling_turnstile": "处理 Turnstile 验证",
"retry_verification": "重试验证",
"detect_turnstile": "检测 Turnstile 验证",
"verification_success": "验证成功",
"starting_browser": "启动浏览器",
"form_success": "表单提交成功",
"handle_turnstile": "处理 Turnstile 验证",
"no_turnstile": "未检测到 Turnstile 验证",
"turnstile_passed": "验证通过",
"verification_start": "开始获取验证码",
"verification_timeout": "获取验证码超时",
"verification_not_found": "未找到验证码",
"try_get_code": "第 {attempt} 次尝试获取验证码 | 剩余时间: {time}秒",
"get_account": "获取账户信息",
"get_token": "获取 Cursor Session Token",
"token_success": "Token 获取成功",
"token_attempt": "第 {attempt} 次尝试未获取到 Token{time}秒后重试",
"token_max_attempts": "已达到最大尝试次数({max}),获取 Token 失败",
"token_failed": "获取 Token 失败: {error}",
"account_error": "获取账户信息失败: {error}",
"press_enter": "按回车键退出",
"browser_start": "正在启动浏览器",
"open_mailbox": "正在打开邮箱页面",
"email_error": "获取邮箱地址失败",
"setup_error": "邮箱设置出错: {error}",
"start_getting_verification_code": "开始获取验证码将在60秒内尝试...",
"get_verification_code_timeout": "获取验证码超时",
"get_verification_code_success": "成功获取验证码",
"try_get_verification_code": "第 {attempt} 次尝试未获取到验证码,剩余时间: {remaining_time}秒",
"verification_code_filled": "验证码填写完成",
"login_success_and_jump_to_settings_page": "成功登录并跳转到设置页面",
"detect_login_page": "检测到登录页面,开始登录...",
"cursor_registration_completed": "注册完成!",
"set_password": "设置密码",
"basic_info_submitted": "基本信息提交完成",
"cursor_auth_info_updated": "Cursor 认证信息更新成功",
"cursor_auth_info_update_failed": "Cursor 认证信息更新失败",
"reset_machine_id": "重置机器ID",
"account_info_saved": "账户信息已保存",
"save_account_info_failed": "保存账户信息失败",
"get_email_address": "获取邮箱地址",
"register_process_error": "注册流程错误: {error}",
"update_cursor_auth_info": "更新Cursor认证信息"
},
"auth": {
"title": "Cursor 认证管理器",
"checking_auth": "检查认证文件",
"auth_not_found": "未找到认证文件",
"auth_file_error": "认证文件错误: {error}",
"reading_auth": "读取认证文件",
"updating_auth": "更新认证信息",
"auth_updated": "认证信息更新成功",
"auth_update_failed": "认证信息更新失败: {error}",
"auth_file_created": "认证文件已创建",
"auth_file_create_failed": "认证文件创建失败: {error}",
"press_enter": "按回车键退出",
"connected_to_database": "已连接到数据库",
"database_updated_successfully": "数据库更新成功",
"database_connection_closed": "数据库连接已关闭",
"updating_pair": "更新键值对"
},
"control": {
"generate_email": "生成新邮箱",
"select_domain": "选择随机域名",
"copy_email": "复制邮箱地址",
"enter_mailbox": "进入邮箱",
"blocked_domain": "被屏蔽的域名",
"refresh_mailbox": "刷新邮箱",
"check_verification": "检查验证码",
"verification_found": "找到验证码",
"verification_not_found": "未找到验证码",
"browser_error": "浏览器控制错误: {error}",
"navigation_error": "导航错误: {error}",
"email_copy_error": "邮箱复制错误: {error}",
"mailbox_error": "邮箱错误: {error}",
"token_saved_to_file": "Token已保存到 cursor_tokens.txt",
"navigate_to": "导航到 {url}",
"generate_email_success": "生成邮箱成功",
"select_email_domain": "选择邮箱域名",
"select_email_domain_success": "选择邮箱域名成功",
"get_email_name": "获取邮箱名称",
"get_email_name_success": "获取邮箱名称成功",
"get_email_address": "获取邮箱地址",
"get_email_address_success": "获取邮箱地址成功",
"enter_mailbox_success": "进入邮箱成功",
"found_verification_code": "找到验证码",
"get_cursor_session_token": "获取Cursor Session Token",
"get_cursor_session_token_success": "获取Cursor Session Token成功",
"get_cursor_session_token_failed": "获取Cursor Session Token失败",
"save_token_failed": "保存Token失败",
"no_valid_verification_code": "没有有效的验证码"
}
}

175
locales/zh_tw.json Normal file
View File

@@ -0,0 +1,175 @@
{
"menu": {
"title": "可用選項",
"exit": "退出程序",
"reset": "重置機器標識",
"register": "註冊 Cursor",
"quit": "退出 Cursor",
"select_language": "選擇語言",
"input_choice": "輸入選擇 ({choices})",
"invalid_choice": "無效選擇,請重試",
"program_terminated": "程序被用戶終止",
"error_occurred": "發生錯誤: {error}",
"press_enter": "按回車鍵退出"
},
"languages": {
"en": "English",
"zh_cn": "简体中文",
"zh_tw": "繁體中文"
},
"quit_cursor": {
"start": "開始退出 Cursor",
"no_process": "未發現運行中的 Cursor 進程",
"terminating": "正在終止進程 {pid}",
"waiting": "等待進程退出",
"success": "所有 Cursor 進程已正常關閉",
"timeout": "以下進程未能在規定時間內關閉: {pids}",
"error": "關閉 Cursor 進程時發生錯誤: {error}"
},
"reset": {
"title": "Cursor 機器標識重置工具",
"checking": "檢查配置文件",
"not_found": "配置文件未找到",
"no_permission": "無法讀取或寫入配置文件,請檢查文件權限",
"reading": "讀取當前配置",
"creating_backup": "創建配置備份",
"backup_exists": "備份文件已存在,跳過備份步驟",
"generating": "生成新機器標識",
"saving_json": "保存新配置到JSON",
"success": "機器標識重置成功",
"new_id": "新機器標識",
"permission_error": "權限錯誤: {error}",
"run_as_admin": "請嘗試以管理員身份運行此程序",
"process_error": "重置進程錯誤: {error}",
"updating_sqlite": "更新SQLite數據庫",
"updating_pair": "更新鍵值對",
"sqlite_success": "SQLite數據庫更新成功",
"sqlite_error": "SQLite數據庫更新失敗: {error}",
"press_enter": "按回車鍵退出",
"updating_system_ids": "更新系統ID",
"system_ids_updated": "系統ID更新成功",
"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": {
"title": "Cursor 註冊工具",
"start": "開始註冊流程",
"mailbox": "成功進入郵箱",
"browser_started": "瀏覽器已啟動",
"waiting_for_page_load": "等待頁面加載",
"password_success": "密碼設置完成",
"password_error": "密碼設置失敗: {error}",
"visiting_url": "訪問URL",
"first_verification_passed": "第一階段驗證通過",
"register_start": "開始註冊流程",
"form_submitted": "表單已提交,開始驗證...",
"waiting_for_second_verification": "等待第二階段驗證",
"filling_form": "填寫註冊信息",
"basic_info": "基本信息提交完成",
"handle_turnstile": "處理 Turnstile 驗證",
"no_turnstile": "未檢測到 Turnstile 驗證",
"turnstile_passed": "驗證通過",
"verification_start": "開始獲取驗證碼",
"waiting_for_verification_code": "等待驗證碼",
"handling_turnstile": "處理 Turnstile 驗證",
"retry_verification": "重試驗證",
"detect_turnstile": "檢測 Turnstile 驗證",
"verification_success": "驗證成功",
"starting_browser": "啟動瀏覽器",
"form_success": "表單提交成功",
"verification_timeout": "獲取驗證碼超時",
"verification_not_found": "未找到驗證碼",
"try_get_code": "第 {attempt} 次嘗試獲取驗證碼 | 剩餘時間: {time}秒",
"get_account": "獲取賬戶信息",
"get_token": "獲取 Cursor Session Token",
"token_success": "Token 獲取成功",
"token_attempt": "第 {attempt} 次嘗試未獲取到 Token{time}秒後重試",
"token_max_attempts": "已達到最大嘗試次數({max}),獲取 Token 失敗",
"token_failed": "獲取 Token 失敗: {error}",
"account_error": "獲取賬戶信息失敗: {error}",
"press_enter": "按回車鍵退出",
"browser_start": "正在啟動瀏覽器",
"open_mailbox": "正在打開郵箱頁面",
"email_error": "獲取郵箱地址失敗",
"setup_error": "郵箱設置出錯: {error}",
"start_getting_verification_code": "開始獲取驗證碼將在60秒內嘗試...",
"get_verification_code_timeout": "獲取驗證碼超時",
"get_verification_code_success": "成功獲取驗證碼",
"try_get_verification_code": "第 {attempt} 次嘗試未獲取到驗證碼,剩餘時間: {remaining_time}秒",
"verification_code_filled": "驗證碼填寫完成",
"login_success_and_jump_to_settings_page": "成功登錄並跳轉到設置頁面",
"detect_login_page": "檢測到登錄頁面,開始登錄...",
"cursor_registration_completed": "註冊完成!",
"set_password": "設置密碼",
"basic_info_submitted": "基本信息提交完成",
"cursor_auth_info_updated": "Cursor 認證信息更新成功",
"cursor_auth_info_update_failed": "Cursor 認證信息更新失敗",
"reset_machine_id": "重置機器ID",
"account_info_saved": "賬戶信息已保存",
"save_account_info_failed": "保存賬戶信息失敗",
"get_email_address": "獲取郵箱地址",
"register_process_error": "註冊流程錯誤: {error}",
"update_cursor_auth_info": "更新Cursor認證信息"
},
"auth": {
"title": "Cursor 認證管理器",
"checking_auth": "檢查認證文件",
"auth_not_found": "未找到認證文件",
"auth_file_error": "認證文件錯誤: {error}",
"reading_auth": "讀取認證文件",
"updating_auth": "更新認證信息",
"auth_updated": "認證信息更新成功",
"auth_update_failed": "認證信息更新失敗: {error}",
"auth_file_created": "認證文件已創建",
"auth_file_create_failed": "認證文件創建失敗: {error}",
"press_enter": "按回車鍵退出",
"connected_to_database": "已連接到數據庫",
"database_updated_successfully": "數據庫更新成功",
"database_connection_closed": "數據庫連接已關閉",
"updating_pair": "更新鍵值對"
},
"control": {
"generate_email": "生成新郵箱",
"select_domain": "選擇隨機域名",
"copy_email": "複製郵箱地址",
"enter_mailbox": "進入郵箱",
"refresh_mailbox": "刷新郵箱",
"check_verification": "檢查驗證碼",
"verification_found": "找到驗證碼",
"verification_not_found": "未找到驗證碼",
"browser_error": "瀏覽器控制錯誤: {error}",
"navigation_error": "導航錯誤: {error}",
"email_copy_error": "郵箱複製錯誤: {error}",
"mailbox_error": "郵箱錯誤: {error}",
"token_saved_to_file": "Token已保存到 cursor_tokens.txt",
"navigate_to": "導航到 {url}",
"generate_email_success": "生成郵箱成功",
"select_email_domain": "選擇郵箱域名",
"select_email_domain_success": "選擇郵箱域名成功",
"get_email_name": "獲取郵箱名稱",
"get_email_name_success": "獲取郵箱名稱成功",
"get_email_address": "獲取郵箱地址",
"get_email_address_success": "獲取郵箱地址成功",
"enter_mailbox_success": "進入郵箱成功",
"found_verification_code": "找到驗證碼",
"get_cursor_session_token": "獲取Cursor Session Token",
"get_cursor_session_token_success": "獲取Cursor Session Token成功",
"get_cursor_session_token_failed": "獲取Cursor Session Token失敗",
"save_token_failed": "保存Token失敗",
"blocked_domain": "被屏蔽的域名",
"no_valid_verification_code": "沒有有效的驗證碼"
}
}

20
logo.py
View File

@@ -1,4 +1,17 @@
from colorama import Fore, Style, init
from dotenv import load_dotenv
import os
# 獲取當前腳本所在目錄
current_dir = os.path.dirname(os.path.abspath(__file__))
# 構建.env文件的完整路徑
env_path = os.path.join(current_dir, '.env')
# 加載環境變量,指定.env文件路徑
load_dotenv(env_path)
# 獲取版本號,如果未找到則使用默認值
version = os.getenv('VERSION', '1.0.0')
# 初始化 colorama
init()
@@ -11,15 +24,16 @@ CURSOR_LOGO = f"""
╚██████╗╚██████╔╝██║ ██║███████║╚██████╔╝██║ ██║ ██║ ██║ ██║╚██████╔╝
╚═════╝ ╚═════╝ ╚═╝ ╚═╝╚══════╝ ╚═════╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═════╝
{Fore.YELLOW}
Pro Version Activator
Pro Version Activator v{version}
{Fore.GREEN}
Author: Pin Studios | yeongpin
Author: Pin Studios | yeongpin
{Fore.RED}
Press 4 to change language | 按下 4 键切换语言
{Style.RESET_ALL}
"""
def print_logo():
print(CURSOR_LOGO)
if __name__ == "__main__":
print_logo()

106
main.py
View File

@@ -1,5 +1,8 @@
# main.py
# This script allows the user to choose which script to run.
import os
import sys
import json
from logo import print_logo
from colorama import Fore, Style, init
@@ -16,58 +19,125 @@ EMOJI = {
"RESET": "🔄",
"MENU": "📋",
"ARROW": "",
"LANG": "🌐"
}
class Translator:
def __init__(self):
self.current_language = 'zh_tw' # 默认语言
self.translations = {}
self.load_translations()
def load_translations(self):
"""加载所有可用的翻译"""
locales_dir = os.path.join(os.path.dirname(__file__), 'locales')
if hasattr(sys, '_MEIPASS'):
locales_dir = os.path.join(sys._MEIPASS, 'locales')
for file in os.listdir(locales_dir):
if file.endswith('.json'):
lang_code = file[:-5] # 移除 .json
with open(os.path.join(locales_dir, file), 'r', encoding='utf-8') as f:
self.translations[lang_code] = json.load(f)
def get(self, key, **kwargs):
"""获取翻译文本"""
try:
keys = key.split('.')
value = self.translations.get(self.current_language, {})
for k in keys:
if isinstance(value, dict):
value = value.get(k, key)
else:
return key # 如果中間值不是字典返回原始key
return value.format(**kwargs) if kwargs else value
except Exception:
return key # 出現任何錯誤時返回原始key
def set_language(self, lang_code):
"""设置当前语言"""
if lang_code in self.translations:
self.current_language = lang_code
return True
return False
# 创建翻译器实例
translator = Translator()
def print_menu():
"""打印菜单选项"""
print(f"\n{Fore.CYAN}{EMOJI['MENU']} Available Options | 可用选项:{Style.RESET_ALL}")
print(f"\n{Fore.CYAN}{EMOJI['MENU']} {translator.get('menu.title')}:{Style.RESET_ALL}")
print(f"{Fore.YELLOW}{'' * 40}{Style.RESET_ALL}")
print(f"{Fore.GREEN}0{Style.RESET_ALL}. {EMOJI['ERROR']} Exit Program | 退出程序")
print(f"{Fore.GREEN}1{Style.RESET_ALL}. {EMOJI['RESET']} Reset Machine Manual | 重置机器标识")
print(f"{Fore.GREEN}2{Style.RESET_ALL}. {EMOJI['SUCCESS']} Register Cursor | 注册 Cursor")
print(f"{Fore.GREEN}3{Style.RESET_ALL}. {EMOJI['ERROR']} Quit Cursor | 退出 Cursor")
# 在这里添加更多选项
print(f"{Fore.GREEN}0{Style.RESET_ALL}. {EMOJI['ERROR']} {translator.get('menu.exit')}")
print(f"{Fore.GREEN}1{Style.RESET_ALL}. {EMOJI['RESET']} {translator.get('menu.reset')}")
print(f"{Fore.GREEN}2{Style.RESET_ALL}. {EMOJI['SUCCESS']} {translator.get('menu.register')}")
print(f"{Fore.GREEN}3{Style.RESET_ALL}. {EMOJI['ERROR']} {translator.get('menu.quit')}")
print(f"{Fore.GREEN}4{Style.RESET_ALL}. {EMOJI['LANG']} {translator.get('menu.select_language')}")
print(f"{Fore.YELLOW}{'' * 40}{Style.RESET_ALL}")
def select_language():
"""语言选择菜单"""
print(f"\n{Fore.CYAN}{EMOJI['LANG']} {translator.get('menu.select_language')}:{Style.RESET_ALL}")
print(f"{Fore.YELLOW}{'' * 40}{Style.RESET_ALL}")
languages = translator.get('languages')
for i, (code, name) in enumerate(languages.items()):
print(f"{Fore.GREEN}{i}{Style.RESET_ALL}. {name}")
try:
choice = input(f"\n{EMOJI['ARROW']} {Fore.CYAN}{translator.get('menu.input_choice', choices='0-' + str(len(languages)-1))}: {Style.RESET_ALL}")
if choice.isdigit() and 0 <= int(choice) < len(languages):
lang_code = list(languages.keys())[int(choice)]
translator.set_language(lang_code)
return True
except (ValueError, IndexError):
pass
print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('menu.invalid_choice')}{Style.RESET_ALL}")
return False
def main():
print_logo()
print_menu()
while True:
try:
choice = input(f"\n{EMOJI['ARROW']} {Fore.CYAN}Enter your choice (0-3) | 输入选择 (0-3): {Style.RESET_ALL}")
choice = input(f"\n{EMOJI['ARROW']} {Fore.CYAN}{translator.get('menu.input_choice', choices='0-4')}: {Style.RESET_ALL}")
if choice == "0":
print(f"\n{Fore.YELLOW}{EMOJI['INFO']} Exiting program... | 正在退出程序...{Style.RESET_ALL}")
print(f"\n{Fore.YELLOW}{EMOJI['INFO']} {translator.get('menu.exit')}...{Style.RESET_ALL}")
print(f"{Fore.CYAN}{'' * 50}{Style.RESET_ALL}")
return # 直接返回,不等待按键
return
elif choice == "1":
import reset_machine_manual
reset_machine_manual.run()
reset_machine_manual.run(translator)
break
elif choice == "2":
import cursor_register
cursor_register.main()
cursor_register.main(translator)
break
elif choice == "3":
import quit_cursor
quit_cursor.quit_cursor()
quit_cursor.quit_cursor(translator)
break
elif choice == "4":
if select_language():
print_menu()
continue
else:
print(f"{Fore.RED}{EMOJI['ERROR']} Invalid choice. Please try again | 无效选择,请重试{Style.RESET_ALL}")
print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('menu.invalid_choice')}{Style.RESET_ALL}")
print_menu()
except KeyboardInterrupt:
print(f"\n{Fore.YELLOW}{EMOJI['INFO']} Program terminated by user | 程序被用户终止{Style.RESET_ALL}")
print(f"\n{Fore.YELLOW}{EMOJI['INFO']} {translator.get('menu.program_terminated')}{Style.RESET_ALL}")
print(f"{Fore.CYAN}{'' * 50}{Style.RESET_ALL}")
return # 直接返回,不等待按键
return
except Exception as e:
print(f"{Fore.RED}{EMOJI['ERROR']} An error occurred | 发生错误: {str(e)}{Style.RESET_ALL}")
print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('menu.error_occurred', error=str(e))}{Style.RESET_ALL}")
break
# 只有在执行完其他选项后才显示按键退出提示
print(f"\n{Fore.CYAN}{'' * 50}{Style.RESET_ALL}")
input(f"{EMOJI['INFO']} Press Enter to Exit | 按回车键退出...{Style.RESET_ALL}")
input(f"{EMOJI['INFO']} {translator.get('menu.press_enter')}...{Style.RESET_ALL}")
if __name__ == "__main__":
main()

468
new_signup.py Normal file
View File

@@ -0,0 +1,468 @@
from DrissionPage import ChromiumOptions, ChromiumPage
import time
import os
import signal
import random
# 在文件开头添加全局变量
_translator = None
def cleanup_chrome_processes(translator=None):
"""清理所有Chrome相关进程"""
print("\n正在清理Chrome进程...")
try:
if os.name == 'nt':
os.system('taskkill /F /IM chrome.exe /T 2>nul')
os.system('taskkill /F /IM chromedriver.exe /T 2>nul')
else:
os.system('pkill -f chrome')
os.system('pkill -f chromedriver')
except Exception as e:
if translator:
print(f"{translator.get('register.cleanup_error', error=str(e))}")
else:
print(f"清理进程时出错: {e}")
def signal_handler(signum, frame):
"""处理Ctrl+C信号"""
global _translator
if _translator:
print(f"{_translator.get('register.exit_signal')}")
else:
print("\n接收到退出信号,正在关闭...")
cleanup_chrome_processes(_translator)
os._exit(0)
def simulate_human_input(page, url, translator=None):
"""访问网址"""
if translator:
print(f"{translator.get('register.visiting_url')}: {url}")
else:
print("正在访问网址...")
# 先访问空白页面
page.get('about:blank')
time.sleep(random.uniform(1.0, 2.0))
# 访问目标页面
page.get(url)
time.sleep(random.uniform(2.0, 3.0)) # 等待页面加载
def fill_signup_form(page, first_name, last_name, email, translator=None):
"""填写注册表单"""
try:
if translator:
print(f"{translator.get('register.filling_form')}")
else:
print("\n正在填写注册表单...")
# 填写名字
first_name_input = page.ele("@name=first_name")
if first_name_input:
first_name_input.input(first_name)
time.sleep(random.uniform(0.5, 1.0))
# 填写姓氏
last_name_input = page.ele("@name=last_name")
if last_name_input:
last_name_input.input(last_name)
time.sleep(random.uniform(0.5, 1.0))
# 填写邮箱
email_input = page.ele("@name=email")
if email_input:
email_input.input(email)
time.sleep(random.uniform(0.5, 1.0))
# 点击提交按钮
submit_button = page.ele("@type=submit")
if submit_button:
submit_button.click()
time.sleep(random.uniform(2.0, 3.0))
if translator:
print(f"{translator.get('register.form_success')}")
else:
print("表单填写完成")
return True
except Exception as e:
if translator:
print(f"{translator.get('register.form_error', error=str(e))}")
else:
print(f"填写表单时出错: {e}")
return False
def setup_driver(translator=None):
"""设置浏览器驱动"""
co = ChromiumOptions()
# 使用无痕模式
co.set_argument("--incognito")
# 设置随机端口
co.auto_port()
# 使用有头模式
co.headless(False)
try:
# 加载插件
extension_path = os.path.join(os.getcwd(), "turnstilePatch")
if os.path.exists(extension_path):
co.set_argument("--allow-extensions-in-incognito")
co.add_extension(extension_path)
except Exception as e:
if translator:
print(f"{translator.get('register.extension_load_error', error=str(e))}")
else:
print(f"加载插件失败: {e}")
if translator:
print(f"{translator.get('register.starting_browser')}")
else:
print("正在启动浏览器...")
page = ChromiumPage(co)
return page
def handle_turnstile(page, translator=None):
"""处理 Turnstile 验证"""
try:
if translator:
print(f"{translator.get('register.handling_turnstile')}")
else:
print("\n正在处理 Turnstile 验证...")
max_retries = 2
retry_count = 0
while retry_count < max_retries:
retry_count += 1
if translator:
print(f"{translator.get('register.retry_verification', attempt=retry_count)}")
else:
print(f"{retry_count} 次尝试验证...")
try:
# 尝试重置 turnstile
page.run_js("try { turnstile.reset() } catch(e) { }")
time.sleep(2)
# 定位验证框元素
challenge_check = (
page.ele("@id=cf-turnstile", timeout=2)
.child()
.shadow_root.ele("tag:iframe")
.ele("tag:body")
.sr("tag:input")
)
if challenge_check:
if translator:
print(f"{translator.get('register.detect_turnstile')}")
else:
print("检测到验证框...")
# 随机延时后点击验证
time.sleep(random.uniform(1, 3))
challenge_check.click()
time.sleep(2)
# 检查验证结果
if check_verification_success(page, translator):
if translator:
print(f"{translator.get('register.verification_success')}")
else:
print("验证通过!")
return True
except Exception as e:
if translator:
print(f"{translator.get('register.verification_failed')}")
else:
print(f"验证尝试失败: {e}")
# 检查是否已经验证成功
if check_verification_success(page, translator):
if translator:
print(f"{translator.get('register.verification_success')}")
else:
print("验证通过!")
return True
time.sleep(random.uniform(1, 2))
if translator:
print(f"{translator.get('register.verification_failed')}")
else:
print("超出最大重试次数")
return False
except Exception as e:
if translator:
print(f"{translator.get('register.verification_error', error=str(e))}")
else:
print(f"验证过程出错: {e}")
return False
def check_verification_success(page, translator=None):
"""检查验证是否成功"""
try:
# 检查是否存在后续表单元素,这表示验证已通过
if (page.ele("@name=password", timeout=0.5) or
page.ele("@name=email", timeout=0.5) or
page.ele("@data-index=0", timeout=0.5) or
page.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 page.ele(error_xpath):
return False
return False
except:
return False
def generate_password(length=12):
"""生成随机密码"""
chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*"
return ''.join(random.choices(chars, k=length))
def fill_password(page, password, translator=None):
"""填写密码"""
try:
print("\n正在设置密码...")
password_input = page.ele("@name=password")
if password_input:
password_input.input(password)
time.sleep(random.uniform(0.5, 1.0))
submit_button = page.ele("@type=submit")
if submit_button:
submit_button.click()
time.sleep(random.uniform(2.0, 3.0))
if translator:
print(f"{translator.get('register.password_success')}")
else:
print(f"密码设置完成: {password}")
return True
except Exception as e:
if translator:
print(f"{translator.get('register.password_error', error=str(e))}")
else:
print(f"设置密码时出错: {e}")
return False
def handle_verification_code(browser_tab, email_tab, controller, email, password, translator=None):
"""处理验证码"""
try:
if translator:
print(f"\n{translator.get('register.waiting_for_verification_code')}")
else:
print("\n等待并获取验证码...")
time.sleep(5) # 等待验证码邮件
# 刷新邮箱页面
email_tab.refresh()
# 获取验证码,设置超时
verification_code = None
max_attempts = 20
retry_interval = 10
start_time = time.time()
timeout = 160
if translator:
print(f"\n{translator.get('register.start_getting_verification_code')}")
else:
print("开始获取验证码...")
for attempt in range(max_attempts):
# 检查是否超时
if time.time() - start_time > timeout:
if translator:
print(f"{translator.get('register.verification_timeout')}")
else:
print("获取验证码超时...")
break
verification_code = controller.get_verification_code()
if verification_code:
if translator:
print(f"{translator.get('register.verification_success')}")
else:
print(f"成功获取验证码: {verification_code}")
break
remaining_time = int(timeout - (time.time() - start_time))
if translator:
print(f"{translator.get('register.try_get_code', attempt=attempt + 1, time=remaining_time)}")
else:
print(f"{attempt + 1} 次尝试获取验证码,剩余时间: {remaining_time}秒...")
# 刷新邮箱
email_tab.refresh()
time.sleep(retry_interval)
if verification_code:
# 在注册页面填写验证码
for i, digit in enumerate(verification_code):
browser_tab.ele(f"@data-index={i}").input(digit)
time.sleep(random.uniform(0.1, 0.3))
if translator:
print(f"{translator.get('register.verification_success')}")
else:
print("验证码填写完成")
time.sleep(3)
# 处理最后一次 Turnstile 验证
if handle_turnstile(browser_tab, translator):
if translator:
print(f"{translator.get('register.verification_success')}")
else:
print("最后一次验证通过!")
time.sleep(2)
# 直接访问设置页面
if translator:
print(f"{translator.get('register.visiting_url')}: https://www.cursor.com/settings")
else:
print("访问设置页面...")
browser_tab.get("https://www.cursor.com/settings")
time.sleep(3) # 等待页面加载
# 直接返回成功,让 cursor_register.py 处理账户信息获取
return True
else:
if translator:
print(f"{translator.get('register.verification_failed')}")
else:
print("最后一次验证失败")
return False
return False
except Exception as e:
if translator:
print(f"{translator.get('register.verification_error', error=str(e))}")
else:
print(f"处理验证码时出错: {e}")
return False
def main(email=None, password=None, first_name=None, last_name=None, email_tab=None, controller=None, translator=None):
"""主函数,可以接收账号信息、邮箱标签页和翻译器"""
global _translator
_translator = translator # 保存到全局变量
signal.signal(signal.SIGINT, signal_handler)
signal.signal(signal.SIGTERM, signal_handler)
page = None
success = False
try:
page = setup_driver(translator)
if translator:
print(f"{translator.get('register.browser_started')}")
else:
print("浏览器已启动")
# 访问注册页面
url = "https://authenticator.cursor.sh/sign-up"
if translator:
print(f"\n{translator.get('register.visiting_url')}: {url}")
else:
print(f"\n正在访问: {url}")
# 访问页面
simulate_human_input(page, url, translator)
if translator:
print(f"{translator.get('register.waiting_for_page_load')}")
else:
print("等待页面加载...")
time.sleep(5)
# 如果没有提供账号信息,则生成随机信息
if not all([email, password, first_name, last_name]):
first_name = ''.join(random.choices('abcdefghijklmnopqrstuvwxyz', k=6)).capitalize()
last_name = ''.join(random.choices('abcdefghijklmnopqrstuvwxyz', k=6)).capitalize()
email = f"{first_name.lower()}{random.randint(100,999)}@example.com"
password = generate_password()
# 保存账号信息
with open('test_accounts.txt', 'a', encoding='utf-8') as f:
f.write(f"\n{'='*50}\n")
f.write(f"Email: {email}\n")
f.write(f"Password: {password}\n")
f.write(f"{'='*50}\n")
# 填写表单
if fill_signup_form(page, first_name, last_name, email, translator):
if translator:
print(f"\n{translator.get('register.form_submitted')}")
else:
print("\n表单已提交,开始验证...")
# 处理第一次 Turnstile 验证
if handle_turnstile(page, translator):
if translator:
print(f"\n{translator.get('register.first_verification_passed')}")
else:
print("\n第一阶段验证通过!")
# 填写密码
if fill_password(page, password, translator):
if translator:
print(f"\n{translator.get('register.waiting_for_second_verification')}")
else:
print("\n等待第二次验证...")
time.sleep(2)
# 处理第二次 Turnstile 验证
if handle_turnstile(page, translator):
if translator:
print(f"\n{translator.get('register.waiting_for_verification_code')}")
else:
print("\n开始处理验证码...")
if handle_verification_code(page, email_tab, controller, email, password, translator):
if translator:
print(f"\n{translator.get('register.verification_success')}")
else:
print("\n注册流程完成!")
success = True
return True, page # 返回成功状态和浏览器实例
else:
print("\n验证码处理失败")
else:
print("\n第二次验证失败")
else:
print("\n密码设置失败")
else:
print("\n第一次验证失败")
return False, None
except Exception as e:
print(f"发生错误: {e}")
return False, None
finally:
if page and not success: # 只在失败时清理
try:
page.quit()
except:
pass
cleanup_chrome_processes(translator)
if __name__ == "__main__":
main() # 直接运行时不传参数,使用随机生成的信息

View File

@@ -1,30 +1,30 @@
import psutil
import time
from colorama import Fore, Style, init
import sys
import os
# 初始化colorama
init()
# 定义emoji和颜色常量
# 定义emoji常量
EMOJI = {
"FILE": "📄",
"BACKUP": "💾",
"PROCESS": "⚙️",
"SUCCESS": "",
"ERROR": "",
"INFO": "",
"RESET": "🔄",
"PROCESS": "⚙️",
"WAIT": ""
}
class CursorQuitter:
def __init__(self, timeout=5):
def __init__(self, timeout=5, translator=None):
self.timeout = timeout
self.translator = translator # 使用传入的翻译器
def quit_cursor(self):
"""温和地关闭 Cursor 进程"""
try:
print(f"{Fore.CYAN}{EMOJI['PROCESS']} Start Quitting Cursor | 开始退出 Cursor...{Style.RESET_ALL}")
print(f"{Fore.CYAN}{EMOJI['PROCESS']} {self.translator.get('quit_cursor.start')}...{Style.RESET_ALL}")
cursor_processes = []
# 收集所有 Cursor 进程
@@ -36,20 +36,20 @@ class CursorQuitter:
continue
if not cursor_processes:
print(f"{Fore.GREEN}{EMOJI['INFO']} No Running Cursor Process | 未发现运行中的 Cursor 进程{Style.RESET_ALL}")
print(f"{Fore.GREEN}{EMOJI['INFO']} {self.translator.get('quit_cursor.no_process')}{Style.RESET_ALL}")
return True
# 温和地请求进程终止
for proc in cursor_processes:
try:
if proc.is_running():
print(f"{Fore.YELLOW}{EMOJI['PROCESS']} Terminating Process | 正在终止进程 {proc.pid}...{Style.RESET_ALL}")
proc.terminate() # 发送终止信号
print(f"{Fore.YELLOW}{EMOJI['PROCESS']} {self.translator.get('quit_cursor.terminating', pid=proc.pid)}...{Style.RESET_ALL}")
proc.terminate()
except (psutil.NoSuchProcess, psutil.AccessDenied):
continue
# 等待进程自然终止
print(f"{Fore.CYAN}{EMOJI['WAIT']} Waiting for Process to Exit | 等待进程退出...{Style.RESET_ALL}")
print(f"{Fore.CYAN}{EMOJI['WAIT']} {self.translator.get('quit_cursor.waiting')}...{Style.RESET_ALL}")
start_time = time.time()
while time.time() - start_time < self.timeout:
still_running = []
@@ -61,28 +61,29 @@ class CursorQuitter:
continue
if not still_running:
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} All Cursor Processes Closed | 所有 Cursor 进程已正常关闭{Style.RESET_ALL}")
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('quit_cursor.success')}{Style.RESET_ALL}")
return True
# 等待一小段时间再检查
time.sleep(0.5)
# 如果超时后仍有进程在运行
if still_running:
process_list = ", ".join([str(p.pid) for p in still_running])
print(f"{Fore.RED}{EMOJI['ERROR']} Process Timeout | 以下进程未能在规定时间内关闭: {process_list}{Style.RESET_ALL}")
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('quit_cursor.timeout', pids=process_list)}{Style.RESET_ALL}")
return False
return True
except Exception as e:
print(f"{Fore.RED}{EMOJI['ERROR']} Error Occurred | 关闭 Cursor 进程时发生错误: {str(e)}{Style.RESET_ALL}")
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('quit_cursor.error', error=str(e))}{Style.RESET_ALL}")
return False
def quit_cursor(timeout=5):
def quit_cursor(translator=None, timeout=5):
"""便捷函数,用于直接调用退出功能"""
quitter = CursorQuitter(timeout)
quitter = CursorQuitter(timeout, translator)
return quitter.quit_cursor()
if __name__ == "__main__":
quit_cursor()
# 如果直接运行,使用默认翻译器
from main import translator as main_translator
quit_cursor(main_translator)

View File

@@ -5,13 +5,16 @@ import uuid
import hashlib
import shutil
import sqlite3
from logo import print_logo
import platform
import re
import tempfile
from colorama import Fore, Style, init
from typing import Tuple
# 初始化colorama
init()
# 定义emoji和颜色常量
# 定义emoji常量
EMOJI = {
"FILE": "📄",
"BACKUP": "💾",
@@ -21,14 +24,182 @@ EMOJI = {
"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:
def __init__(self):
def __init__(self, translator=None):
self.translator = translator
# 判断操作系统
if sys.platform == "win32": # Windows
appdata = os.getenv("APPDATA")
if appdata is None:
raise EnvironmentError("APPDATA Environment Variable Not Set | APPDATA 环境变量未设置")
raise EnvironmentError("APPDATA Environment Variable Not Set")
self.db_path = os.path.join(
appdata, "Cursor", "User", "globalStorage", "storage.json"
)
@@ -42,7 +213,7 @@ class MachineIDResetter:
self.sqlite_path = os.path.abspath(os.path.expanduser(
"~/Library/Application Support/Cursor/User/globalStorage/state.vscdb"
))
elif sys.platform == "linux": # Linux 和其他类Unix系统
elif sys.platform == "linux": # Linux
self.db_path = os.path.abspath(os.path.expanduser(
"~/.config/Cursor/User/globalStorage/storage.json"
))
@@ -50,7 +221,7 @@ class MachineIDResetter:
"~/.config/Cursor/User/globalStorage/state.vscdb"
))
else:
raise NotImplementedError(f"Not Supported Os| 不支持的操作系统: {sys.platform}")
raise NotImplementedError(f"Not Supported OS: {sys.platform}")
def generate_new_ids(self):
"""生成新的机器ID"""
@@ -77,13 +248,11 @@ class MachineIDResetter:
def update_sqlite_db(self, new_ids):
"""更新 SQLite 数据库中的机器ID"""
try:
print(f"{Fore.CYAN}{EMOJI['INFO']} Updating SQLite Database | 正在更新 SQLite 数据库...{Style.RESET_ALL}")
print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('reset.updating_sqlite')}...{Style.RESET_ALL}")
# 创建数据库连接
conn = sqlite3.connect(self.sqlite_path)
cursor = conn.cursor()
# 确保表存在
cursor.execute("""
CREATE TABLE IF NOT EXISTS ItemTable (
key TEXT PRIMARY KEY,
@@ -91,108 +260,154 @@ class MachineIDResetter:
)
""")
# 准备更新数据
updates = [
(key, value) for key, value in new_ids.items()
]
# 使用参数化查询来避免 SQL 注入和处理长文本
for key, value in updates:
cursor.execute("""
INSERT OR REPLACE INTO ItemTable (key, value)
VALUES (?, ?)
""", (key, value))
print(f"{EMOJI['INFO']} {Fore.CYAN}Updating Key-Value Pair | 更新键值对: {key}{Style.RESET_ALL}")
print(f"{EMOJI['INFO']} {Fore.CYAN} {self.translator.get('reset.updating_pair')}: {key}{Style.RESET_ALL}")
# 提交更改并关闭连接
conn.commit()
conn.close()
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} SQLite Database Updated Successfully | 数据库更新成功!{Style.RESET_ALL}")
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('reset.sqlite_success')}{Style.RESET_ALL}")
return True
except Exception as e:
print(f"{Fore.RED}{EMOJI['ERROR']} SQLite Database Update Failed | 数据库更新失败: {str(e)}{Style.RESET_ALL}")
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('reset.sqlite_error', error=str(e))}{Style.RESET_ALL}")
return False
def update_system_ids(self, new_ids):
"""更新系统级别的ID"""
try:
print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('reset.updating_system_ids')}...{Style.RESET_ALL}")
if sys.platform.startswith("win"):
self._update_windows_machine_guid()
elif sys.platform == "darwin":
self._update_macos_platform_uuid(new_ids)
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('reset.system_ids_updated')}{Style.RESET_ALL}")
return True
except Exception as e:
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('reset.system_ids_update_failed', error=str(e))}{Style.RESET_ALL}")
return False
def _update_windows_machine_guid(self):
"""更新Windows MachineGuid"""
try:
import winreg
key = winreg.OpenKey(
winreg.HKEY_LOCAL_MACHINE,
"SOFTWARE\\Microsoft\\Cryptography",
0,
winreg.KEY_WRITE | winreg.KEY_WOW64_64KEY
)
new_guid = str(uuid.uuid4())
winreg.SetValueEx(key, "MachineGuid", 0, winreg.REG_SZ, new_guid)
winreg.CloseKey(key)
print("Windows MachineGuid updated successfully")
except PermissionError:
print("Permission denied: Run as administrator to update Windows MachineGuid")
raise
except Exception as e:
print(f"Failed to update Windows MachineGuid: {e}")
raise
def _update_macos_platform_uuid(self, new_ids):
"""更新macOS Platform UUID"""
try:
uuid_file = "/var/root/Library/Preferences/SystemConfiguration/com.apple.platform.uuid.plist"
if os.path.exists(uuid_file):
# 使用sudo来执行plutil命令
cmd = f'sudo plutil -replace "UUID" -string "{new_ids["telemetry.macMachineId"]}" "{uuid_file}"'
result = os.system(cmd)
if result == 0:
print("macOS Platform UUID updated successfully")
else:
raise Exception("Failed to execute plutil command")
except Exception as e:
print(f"Failed to update macOS Platform UUID: {e}")
raise
def reset_machine_ids(self):
"""重置机器ID并备份原文件"""
try:
print(f"{Fore.CYAN}{EMOJI['INFO']} Checking Config File | 正在检查配置文件...{Style.RESET_ALL}")
print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('reset.checking')}...{Style.RESET_ALL}")
# 检查JSON文件是否存在
if not os.path.exists(self.db_path):
print(
f"{Fore.RED}{EMOJI['ERROR']} Config File Not Found | 配置文件不存在: {self.db_path}{Style.RESET_ALL}"
)
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('reset.not_found')}: {self.db_path}{Style.RESET_ALL}")
return False
# 检查文件权限
if not os.access(self.db_path, os.R_OK | os.W_OK):
print(
f"{Fore.RED}{EMOJI['ERROR']} Cannot Read or Write Config File, Please Check File Permissions | 无法读写配置文件,请检查文件权限!{Style.RESET_ALL}"
)
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('reset.no_permission')}{Style.RESET_ALL}")
return False
# 读取现有配置
print(f"{Fore.CYAN}{EMOJI['FILE']} Reading Current Config | 读取当前配置...{Style.RESET_ALL}")
print(f"{Fore.CYAN}{EMOJI['FILE']} {self.translator.get('reset.reading')}...{Style.RESET_ALL}")
with open(self.db_path, "r", encoding="utf-8") as f:
config = json.load(f)
# 只在没有备份文件时创建备份
backup_path = self.db_path + ".bak"
if not os.path.exists(backup_path):
print(
f"{Fore.YELLOW}{EMOJI['BACKUP']} Creating Config Backup | 创建配置备份: {backup_path}{Style.RESET_ALL}"
)
print(f"{Fore.YELLOW}{EMOJI['BACKUP']} {self.translator.get('reset.creating_backup')}: {backup_path}{Style.RESET_ALL}")
shutil.copy2(self.db_path, backup_path)
else:
print(
f"{Fore.YELLOW}{EMOJI['INFO']} Backup File Already Exists, Skipping Backup Step | 已存在备份文件,跳过备份步骤{Style.RESET_ALL}"
)
print(f"{Fore.YELLOW}{EMOJI['INFO']} {self.translator.get('reset.backup_exists')}{Style.RESET_ALL}")
# 生成新的ID
print(f"{Fore.CYAN}{EMOJI['RESET']} Generating New Machine ID | 生成新的机器标识...{Style.RESET_ALL}")
print(f"{Fore.CYAN}{EMOJI['RESET']} {self.translator.get('reset.generating')}...{Style.RESET_ALL}")
new_ids = self.generate_new_ids()
# 更新配置
# 更新配置文件
config.update(new_ids)
# 保存新配置到 JSON
print(f"{Fore.CYAN}{EMOJI['FILE']} Saving New Config to JSON | 保存新配置到 JSON...{Style.RESET_ALL}")
print(f"{Fore.CYAN}{EMOJI['FILE']} {self.translator.get('reset.saving_json')}...{Style.RESET_ALL}")
with open(self.db_path, "w", encoding="utf-8") as f:
json.dump(config, f, indent=4)
# 更新 SQLite 数据库
# 更新SQLite数据库
self.update_sqlite_db(new_ids)
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} Machine ID Reset Successfully | 机器标识重置成功!{Style.RESET_ALL}")
print(f"\n{Fore.CYAN}New Machine ID | 新的机器标识:{Style.RESET_ALL}")
# 更新系统ID
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"\n{Fore.CYAN}{self.translator.get('reset.new_id')}:{Style.RESET_ALL}")
for key, value in new_ids.items():
print(f"{EMOJI['INFO']} {key}: {Fore.GREEN}{value}{Style.RESET_ALL}")
return True
except PermissionError as e:
print(f"{Fore.RED}{EMOJI['ERROR']} Permission Error | 权限错误: {str(e)}{Style.RESET_ALL}")
print(
f"{Fore.YELLOW}{EMOJI['INFO']} Please Try Running This Program as Administrator | 请尝试以管理员身份运行此程序{Style.RESET_ALL}"
)
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('reset.permission_error', error=str(e))}{Style.RESET_ALL}")
print(f"{Fore.YELLOW}{EMOJI['INFO']} {self.translator.get('reset.run_as_admin')}{Style.RESET_ALL}")
return False
except Exception as e:
print(f"{Fore.RED}{EMOJI['ERROR']} Reset Process Error | 重置过程出错: {str(e)}{Style.RESET_ALL}")
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('reset.process_error', error=str(e))}{Style.RESET_ALL}")
return False
def run():
"""Main function to be called from main.py"""
def run(translator=None):
"""便捷函数,用于直接调用重置功能"""
print(f"\n{Fore.CYAN}{'='*50}{Style.RESET_ALL}")
print(f"{Fore.CYAN}{EMOJI['RESET']} Cursor Machine ID Reset Tool | Cursor 机器标识重置工具{Style.RESET_ALL}")
print(f"{Fore.CYAN}{EMOJI['RESET']} {translator.get('reset.title')}{Style.RESET_ALL}")
print(f"{Fore.CYAN}{'='*50}{Style.RESET_ALL}")
resetter = MachineIDResetter()
resetter = MachineIDResetter(translator) # 正確傳遞 translator
resetter.reset_machine_ids()
print(f"\n{Fore.CYAN}{'='*50}{Style.RESET_ALL}")
input(f"{EMOJI['INFO']} Press Enter to Exit | 按回车键退出...")
input(f"{EMOJI['INFO']} {translator.get('reset.press_enter')}...")
if __name__ == "__main__":
run()
from main import translator as main_translator
run(main_translator)

View File

@@ -1,8 +1,3 @@
# 檢查是否是通過權限提升啟動的
param(
[switch]$Elevated
)
# 設置顏色主題
$Theme = @{
Primary = 'Cyan'
@@ -22,19 +17,6 @@ $Logo = @"
"@
# 進度條函數
function Write-ProgressBar {
param (
[int]$Percent,
[string]$Activity
)
$width = $Host.UI.RawUI.WindowSize.Width - 20
$completed = [math]::Floor($width * ($Percent / 100))
$remaining = $width - $completed
$progressBar = "[" + ("" * $completed) + ("-" * $remaining) + "]"
Write-Host "`r$Activity $progressBar $Percent%" -NoNewline
}
# 美化輸出函數
function Write-Styled {
param (
@@ -43,14 +25,14 @@ function Write-Styled {
[string]$Prefix = "",
[switch]$NoNewline
)
$emoji = switch ($Color) {
$Theme.Success { "" }
$Theme.Error { "" }
$Theme.Warning { "⚠️" }
default { "" }
$symbol = switch ($Color) {
$Theme.Success { "[OK]" }
$Theme.Error { "[X]" }
$Theme.Warning { "[!]" }
default { "[*]" }
}
$output = if ($Prefix) { "$emoji $Prefix :: $Message" } else { "$emoji $Message" }
$output = if ($Prefix) { "$symbol $Prefix :: $Message" } else { "$symbol $Message" }
if ($NoNewline) {
Write-Host $output -ForegroundColor $Color -NoNewline
} else {
@@ -58,61 +40,6 @@ function Write-Styled {
}
}
# 檢查管理員權限
$isAdmin = ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator")
if (-NOT $isAdmin) {
Write-Styled "需要管理員權限來安裝" -Color $Theme.Warning -Prefix "權限"
Write-Styled "正在請求管理員權限..." -Color $Theme.Primary -Prefix "提升"
# 顯示操作選項
Write-Host "`n選擇操作:" -ForegroundColor $Theme.Primary
Write-Host "1. 請求管理員權限" -ForegroundColor $Theme.Info
Write-Host "2. 退出程序" -ForegroundColor $Theme.Info
$choice = Read-Host "`n請輸入選項 (1-2)"
if ($choice -ne "1") {
Write-Styled "安裝已取消" -Color $Theme.Warning -Prefix "取消"
Write-Host "`n按任意鍵退出..." -ForegroundColor $Theme.Info
$null = $Host.UI.RawUI.ReadKey('NoEcho,IncludeKeyDown')
exit
}
$pwshPath = if (Get-Command "pwsh" -ErrorAction SilentlyContinue) {
(Get-Command "pwsh").Source
} elseif (Test-Path "$env:ProgramFiles\PowerShell\7\pwsh.exe") {
"$env:ProgramFiles\PowerShell\7\pwsh.exe"
} else {
"powershell.exe"
}
try {
$arguments = "-NoProfile -ExecutionPolicy Bypass -File `"$($MyInvocation.MyCommand.Path)`" -Elevated -WindowStyle Normal"
Start-Process -FilePath $pwshPath -Verb RunAs -ArgumentList $arguments
Write-Host "`n請在新開啟的管理員權限視窗中繼續操作..." -ForegroundColor $Theme.Primary
# 等待用戶確認
Write-Host "`n按任意鍵退出此窗口..." -ForegroundColor $Theme.Info
$null = $Host.UI.RawUI.ReadKey('NoEcho,IncludeKeyDown')
exit
}
catch {
Write-Styled "無法獲取管理員權限" -Color $Theme.Error -Prefix "錯誤"
Write-Styled "請以管理員身份運行 PowerShell 後重試" -Color $Theme.Warning -Prefix "提示"
Write-Styled "您可以:" -Color $Theme.Info
Write-Host "1. 右鍵點擊 PowerShell選擇「以系統管理員身分執行」" -ForegroundColor $Theme.Info
Write-Host "2. 然後重新運行此安裝程序" -ForegroundColor $Theme.Info
Write-Host "`n按任意鍵退出..." -ForegroundColor $Theme.Info
$null = $Host.UI.RawUI.ReadKey('NoEcho,IncludeKeyDown')
exit 1
}
}
# 如果是提升權限後的窗口,等待一下確保窗口可見
if ($Elevated) {
Start-Sleep -Seconds 1
}
# 獲取版本號函數
function Get-LatestVersion {
try {
@@ -122,8 +49,8 @@ function Get-LatestVersion {
Assets = $latestRelease.assets
}
} catch {
Write-Styled $_.Exception.Message -Color $Theme.Error -Prefix "錯誤"
throw "無法獲取最新版本信息"
Write-Styled $_.Exception.Message -Color $Theme.Error -Prefix "Error"
throw "Cannot get latest version"
}
}
@@ -137,72 +64,47 @@ Write-Host "Created by YeongPin`n" -ForegroundColor $Theme.Info
# 設置 TLS 1.2
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
# 創建臨時目錄
$TmpDir = Join-Path $env:TEMP ([System.Guid]::NewGuid().ToString())
New-Item -ItemType Directory -Path $TmpDir -Force | Out-Null
# 清理函數
function Cleanup {
if (Test-Path $TmpDir) {
Remove-Item -Recurse -Force $TmpDir -ErrorAction SilentlyContinue
}
}
# 主安裝函數
function Install-CursorFreeVIP {
Write-Styled "開始安裝 Cursor Free VIP" -Color $Theme.Primary -Prefix "安裝"
# 設置安裝目錄
$InstallDir = "$env:ProgramFiles\CursorFreeVIP"
if (!(Test-Path $InstallDir)) {
New-Item -ItemType Directory -Path $InstallDir -Force | Out-Null
}
Write-Styled "Start downloading Cursor Free VIP" -Color $Theme.Primary -Prefix "Download"
try {
# 獲取最新版本
Write-Styled "正在檢查最新版本..." -Color $Theme.Primary -Prefix "更新"
Write-Styled "Checking latest version..." -Color $Theme.Primary -Prefix "Update"
$releaseInfo = Get-LatestVersion
$version = $releaseInfo.Version
Write-Styled "找到最新版本: $version" -Color $Theme.Success -Prefix "版本"
Write-Styled "Found latest version: $version" -Color $Theme.Success -Prefix "Version"
# 查找對應的資源
$asset = $releaseInfo.Assets | Where-Object { $_.name -eq "CursorFreeVIP_${version}_windows.exe" }
if (!$asset) {
Write-Styled "找不到檔案: CursorFreeVIP_${version}_windows.exe" -Color $Theme.Error -Prefix "錯誤"
Write-Styled "可用的檔案:" -Color $Theme.Warning -Prefix "資訊"
Write-Styled "File not found: CursorFreeVIP_${version}_windows.exe" -Color $Theme.Error -Prefix "Error"
Write-Styled "Available files:" -Color $Theme.Warning -Prefix "Info"
$releaseInfo.Assets | ForEach-Object {
Write-Styled "- $($_.name)" -Color $Theme.Info
}
throw "找不到對應的安裝檔案"
throw "Cannot find target file"
}
# 下載
Write-Styled "正在下載..." -Color $Theme.Primary -Prefix "下載"
# 下載到Downloads文件夾
$DownloadsPath = [Environment]::GetFolderPath("UserProfile") + "\Downloads"
$downloadPath = Join-Path $DownloadsPath "CursorFreeVIP.exe"
Write-Styled "Downloading to Downloads folder..." -Color $Theme.Primary -Prefix "Download"
$webClient = New-Object System.Net.WebClient
$webClient.Headers.Add("User-Agent", "PowerShell Script")
$downloadPath = Join-Path $TmpDir "CursorFreeVIP.exe"
$webClient.DownloadFile($asset.browser_download_url, $downloadPath)
# 安裝
Write-Styled "正在安裝到系統..." -Color $Theme.Primary -Prefix "安裝"
Copy-Item -Path $downloadPath -Destination "$InstallDir\CursorFreeVIP.exe" -Force
# 添加到 PATH
$currentPath = [Environment]::GetEnvironmentVariable("Path", "Machine")
if ($currentPath -notlike "*$InstallDir*") {
[Environment]::SetEnvironmentVariable("Path", "$currentPath;$InstallDir", "Machine")
}
Write-Styled "安裝完成!" -Color $Theme.Success -Prefix "完成"
Write-Styled "正在啟動程序..." -Color $Theme.Primary -Prefix "啟動"
Write-Styled "Download completed!" -Color $Theme.Success -Prefix "Complete"
Write-Styled "File location: $downloadPath" -Color $Theme.Info -Prefix "Location"
Write-Styled "Starting program..." -Color $Theme.Primary -Prefix "Launch"
# 運行程序
Start-Process "$InstallDir\CursorFreeVIP.exe"
Start-Process $downloadPath
}
catch {
Write-Styled $_.Exception.Message -Color $Theme.Error -Prefix "錯誤"
Write-Styled $_.Exception.Message -Color $Theme.Error -Prefix "Error"
throw
}
}
@@ -212,11 +114,10 @@ try {
Install-CursorFreeVIP
}
catch {
Write-Styled "安裝失敗" -Color $Theme.Error -Prefix "錯誤"
Write-Styled "Download failed" -Color $Theme.Error -Prefix "Error"
Write-Styled $_.Exception.Message -Color $Theme.Error
}
finally {
Cleanup
Write-Host "`n按任意鍵退出..." -ForegroundColor $Theme.Info
Write-Host "`nPress any key to exit..." -ForegroundColor $Theme.Info
$null = $Host.UI.RawUI.ReadKey('NoEcho,IncludeKeyDown')
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff