forked from mirrors/cursor-free-vip
Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ffd48201fd | ||
|
|
cd4f36725c | ||
|
|
dccb524bd7 | ||
|
|
90e9a5b287 | ||
|
|
66a67fce8b | ||
|
|
0981f00b9c | ||
|
|
02851c9a09 |
2
.github/workflows/build.yml
vendored
2
.github/workflows/build.yml
vendored
@@ -6,7 +6,7 @@ on:
|
|||||||
version:
|
version:
|
||||||
description: 'Version number (e.g. 1.0.9)'
|
description: 'Version number (e.g. 1.0.9)'
|
||||||
required: true
|
required: true
|
||||||
default: '1.5.03'
|
default: '1.7.03'
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
contents: write
|
contents: write
|
||||||
|
|||||||
14
CHANGELOG.md
14
CHANGELOG.md
@@ -1,5 +1,19 @@
|
|||||||
# Change Log
|
# Change Log
|
||||||
|
|
||||||
|
## v1.7.03
|
||||||
|
1. Hotfix: Small Problem | 修復一些小問題
|
||||||
|
|
||||||
|
## v1.7.02
|
||||||
|
1. Fix: Cursor Path | 修復Cursor路徑
|
||||||
|
2. Add: Config File | 增加配置文件
|
||||||
|
3. Remove: Workbench Cursor Path | 移除Workbench Cursor路徑
|
||||||
|
4. Remove: Cursor Main JS | 移除Cursor main.js
|
||||||
|
|
||||||
|
## v1.7.01
|
||||||
|
- Refactoring: Extract configuration-related code from the `setup_driver` function to an independent `setup_config` function
|
||||||
|
- Optimization: Improve code maintainability and make configuration management and browser settings more clear
|
||||||
|
- Improvement: The creation and update logic of the configuration file is clearer and more independent
|
||||||
|
|
||||||
## v1.6.03
|
## v1.6.03
|
||||||
1. Hotfix: Small Problem | 修復一些問題
|
1. Hotfix: Small Problem | 修復一些問題
|
||||||
|
|
||||||
|
|||||||
26
README.md
26
README.md
@@ -12,7 +12,7 @@
|
|||||||
[](https://github.com/yeongpin/cursor-free-vip/releases/latest)
|
[](https://github.com/yeongpin/cursor-free-vip/releases/latest)
|
||||||
|
|
||||||
</p>
|
</p>
|
||||||
<h4>Support Latest 0.46.8 Version | 支持最新0.46.8本</h4>
|
<h4>Support Latest 0.46.10 Version | 支持最新0.46.10版本</h4>
|
||||||
|
|
||||||
This is a tool to automatically register , support Windows and macOS systems, complete Auth verification, and reset Cursor's configuration.
|
This is a tool to automatically register , support Windows and macOS systems, complete Auth verification, and reset Cursor's configuration.
|
||||||
|
|
||||||
@@ -86,6 +86,26 @@ irm https://raw.githubusercontent.com/yeongpin/cursor-free-vip/main/scripts/rese
|
|||||||
|
|
||||||
## ❗ Note | 注意事項
|
## ❗ Note | 注意事項
|
||||||
|
|
||||||
|
📝 Config | 文件配置
|
||||||
|
`Win / Macos / Linux Path | 路徑 [Documents/.cursor-free-vip/config.ini]`
|
||||||
|
|
||||||
|
```
|
||||||
|
[Chrome]
|
||||||
|
# Default Google Chrome Path | 默認Google Chrome 遊覽器路徑
|
||||||
|
chromepath = C:\Program Files\Google/Chrome/Application/chrome.exe
|
||||||
|
|
||||||
|
[Turnstile]
|
||||||
|
# Handle Tuenstile Wait Time | 等待人機驗證時間
|
||||||
|
handle_turnstile_time = 2
|
||||||
|
# Handle Tuenstile Wait Random Time (must merge 1-3 or 1,3) | 等待人機驗證隨機時間(必須是 1-3 或者 1,3 這樣的組合)
|
||||||
|
handle_turnstile_random_time = 1-3
|
||||||
|
|
||||||
|
[OSPaths]
|
||||||
|
storage_path = /Users/username/Library/Application Support/Cursor/User/globalStorage/storage.json
|
||||||
|
sqlite_path = /Users/username/Library/Application Support/Cursor/User/globalStorage/state.vscdb
|
||||||
|
machine_id_path = /Users/username/Library/Application Support/Cursor/machineId
|
||||||
|
```
|
||||||
|
|
||||||
* Use administrator to run the script <br>請使用管理員身份運行腳本
|
* Use administrator to run the script <br>請使用管理員身份運行腳本
|
||||||
|
|
||||||
* Confirm that Cursor is closed before running the script <br>請確保在運行腳本前已經關閉 Cursor<br>
|
* Confirm that Cursor is closed before running the script <br>請確保在運行腳本前已經關閉 Cursor<br>
|
||||||
@@ -98,9 +118,9 @@ irm https://raw.githubusercontent.com/yeongpin/cursor-free-vip/main/scripts/rese
|
|||||||
|
|
||||||
## 🚨 Common Issues | 常見問題
|
## 🚨 Common Issues | 常見問題
|
||||||
|
|
||||||
|如果遇到權限問題,請確保:|If you encounter permission issues, please ensure:|
|
|如果遇到權限問題,請確保:| 此腳本以管理員身份運行 |
|
||||||
|:---:|:---:|
|
|:---:|:---:|
|
||||||
| 此腳本以管理員身份運行 | This script is run with administrator privileges |
|
|If you encounter permission issues, please ensure: | This script is run with administrator privileges |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -160,7 +160,7 @@ class CursorRegistration:
|
|||||||
if usage_ele:
|
if usage_ele:
|
||||||
total_usage = usage_ele.text.split("/")[-1].strip()
|
total_usage = usage_ele.text.split("/")[-1].strip()
|
||||||
|
|
||||||
print(f"Total Usage: {total_usage}\n")
|
print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('register.total_usage', usage=total_usage)}{Style.RESET_ALL}")
|
||||||
print(f"{Fore.CYAN}{EMOJI['WAIT']} {self.translator.get('register.get_token')}...{Style.RESET_ALL}")
|
print(f"{Fore.CYAN}{EMOJI['WAIT']} {self.translator.get('register.get_token')}...{Style.RESET_ALL}")
|
||||||
max_attempts = 30
|
max_attempts = 30
|
||||||
retry_interval = 2
|
retry_interval = 2
|
||||||
|
|||||||
@@ -68,7 +68,11 @@
|
|||||||
"version_less_than_0_45": "Cursor Version < 0.45.0, Skip Patching getMachineId",
|
"version_less_than_0_45": "Cursor Version < 0.45.0, Skip Patching getMachineId",
|
||||||
"detecting_version": "Detecting Cursor Version",
|
"detecting_version": "Detecting Cursor Version",
|
||||||
"patching_getmachineid": "Patching getMachineId",
|
"patching_getmachineid": "Patching getMachineId",
|
||||||
"version_greater_than_0_45": "Cursor Version >= 0.45.0, Patching getMachineId"
|
"version_greater_than_0_45": "Cursor Version >= 0.45.0, Patching getMachineId",
|
||||||
|
"permission_denied": "Permission Denied: {error}",
|
||||||
|
"backup_created": "Backup Created",
|
||||||
|
"update_success": "Update Success",
|
||||||
|
"update_failed": "Update Failed: {error}"
|
||||||
},
|
},
|
||||||
"register": {
|
"register": {
|
||||||
"title": "Cursor Registration Tool",
|
"title": "Cursor Registration Tool",
|
||||||
@@ -136,7 +140,14 @@
|
|||||||
"first_name": "First Name",
|
"first_name": "First Name",
|
||||||
"last_name": "Last Name",
|
"last_name": "Last Name",
|
||||||
"exit_signal": "Exit Signal",
|
"exit_signal": "Exit Signal",
|
||||||
"email_address": "Email Address"
|
"email_address": "Email Address",
|
||||||
|
"config_created": "Config Created",
|
||||||
|
"verification_failed": "Verification Failed",
|
||||||
|
"verification_error": "Verification Error: {error}",
|
||||||
|
"config_option_added": "Config Option Added: {option}",
|
||||||
|
"config_updated": "Config Updated",
|
||||||
|
"password_submitted": "Password Submitted",
|
||||||
|
"total_usage": "Total Usage: {usage}"
|
||||||
},
|
},
|
||||||
"auth": {
|
"auth": {
|
||||||
"title": "Cursor Auth Manager",
|
"title": "Cursor Auth Manager",
|
||||||
|
|||||||
@@ -68,7 +68,11 @@
|
|||||||
"version_less_than_0_45": "Cursor版本 < 0.45.0,跳过getMachineId修补",
|
"version_less_than_0_45": "Cursor版本 < 0.45.0,跳过getMachineId修补",
|
||||||
"detecting_version": "检测Cursor版本",
|
"detecting_version": "检测Cursor版本",
|
||||||
"patching_getmachineid": "修补getMachineId",
|
"patching_getmachineid": "修补getMachineId",
|
||||||
"version_greater_than_0_45": "Cursor版本 >= 0.45.0,修补getMachineId"
|
"version_greater_than_0_45": "Cursor版本 >= 0.45.0,修补getMachineId",
|
||||||
|
"permission_denied": "权限拒绝: {error}",
|
||||||
|
"backup_created": "备份已创建",
|
||||||
|
"update_success": "更新成功",
|
||||||
|
"update_failed": "更新失败: {error}"
|
||||||
},
|
},
|
||||||
"register": {
|
"register": {
|
||||||
"title": "Cursor 注册工具",
|
"title": "Cursor 注册工具",
|
||||||
@@ -136,7 +140,14 @@
|
|||||||
"first_name": "名字",
|
"first_name": "名字",
|
||||||
"last_name": "姓氏",
|
"last_name": "姓氏",
|
||||||
"exit_signal": "退出信号",
|
"exit_signal": "退出信号",
|
||||||
"email_address": "邮箱地址"
|
"email_address": "邮箱地址",
|
||||||
|
"config_created": "配置已创建",
|
||||||
|
"verification_failed": "验证失败",
|
||||||
|
"verification_error": "验证错误: {error}",
|
||||||
|
"config_option_added": "配置项已添加: {option}",
|
||||||
|
"config_updated": "配置已更新",
|
||||||
|
"password_submitted": "密码已提交",
|
||||||
|
"total_usage": "总使用量: {usage}"
|
||||||
},
|
},
|
||||||
"auth": {
|
"auth": {
|
||||||
"title": "Cursor 认证管理器",
|
"title": "Cursor 认证管理器",
|
||||||
|
|||||||
@@ -68,7 +68,11 @@
|
|||||||
"version_less_than_0_45": "Cursor版本 < 0.45.0,跳过getMachineId修补",
|
"version_less_than_0_45": "Cursor版本 < 0.45.0,跳过getMachineId修补",
|
||||||
"detecting_version": "檢測Cursor版本",
|
"detecting_version": "檢測Cursor版本",
|
||||||
"patching_getmachineid": "修補getMachineId",
|
"patching_getmachineid": "修補getMachineId",
|
||||||
"version_greater_than_0_45": "Cursor版本 >= 0.45.0,修補getMachineId"
|
"version_greater_than_0_45": "Cursor版本 >= 0.45.0,修補getMachineId",
|
||||||
|
"permission_denied": "權限拒絕: {error}",
|
||||||
|
"backup_created": "備份已創建",
|
||||||
|
"update_success": "更新成功",
|
||||||
|
"update_failed": "更新失敗: {error}"
|
||||||
},
|
},
|
||||||
"register": {
|
"register": {
|
||||||
"title": "Cursor 註冊工具",
|
"title": "Cursor 註冊工具",
|
||||||
@@ -117,7 +121,14 @@
|
|||||||
"first_name": "名字",
|
"first_name": "名字",
|
||||||
"last_name": "姓氏",
|
"last_name": "姓氏",
|
||||||
"exit_signal": "退出信號",
|
"exit_signal": "退出信號",
|
||||||
"email_address": "郵箱地址"
|
"email_address": "郵箱地址",
|
||||||
|
"config_created": "配置已創建",
|
||||||
|
"verification_failed": "驗證失敗",
|
||||||
|
"verification_error": "驗證錯誤: {error}",
|
||||||
|
"config_option_added": "配置項已添加: {option}",
|
||||||
|
"config_updated": "配置已更新",
|
||||||
|
"password_submitted": "密碼已提交",
|
||||||
|
"total_usage": "總使用量: {usage}"
|
||||||
},
|
},
|
||||||
"auth": {
|
"auth": {
|
||||||
"title": "Cursor 認證管理器",
|
"title": "Cursor 認證管理器",
|
||||||
|
|||||||
484
new_signup.py
484
new_signup.py
@@ -4,6 +4,9 @@ import os
|
|||||||
import signal
|
import signal
|
||||||
import random
|
import random
|
||||||
from colorama import Fore, Style
|
from colorama import Fore, Style
|
||||||
|
import configparser
|
||||||
|
from pathlib import Path
|
||||||
|
import sys
|
||||||
|
|
||||||
# 在文件开头添加全局变量
|
# 在文件开头添加全局变量
|
||||||
_translator = None
|
_translator = None
|
||||||
@@ -34,22 +37,20 @@ def signal_handler(signum, frame):
|
|||||||
cleanup_chrome_processes(_translator)
|
cleanup_chrome_processes(_translator)
|
||||||
os._exit(0)
|
os._exit(0)
|
||||||
|
|
||||||
def simulate_human_input(page, url, translator=None):
|
def simulate_human_input(page, url, config, translator=None):
|
||||||
"""访问网址"""
|
"""访问网址"""
|
||||||
if translator:
|
if translator:
|
||||||
print(f"{Fore.CYAN}🚀 {translator.get('register.visiting_url')}: {url}{Style.RESET_ALL}")
|
print(f"{Fore.CYAN}🚀 {translator.get('register.visiting_url')}: {url}{Style.RESET_ALL}")
|
||||||
else:
|
|
||||||
print("正在访问网址...")
|
|
||||||
|
|
||||||
# 先访问空白页面
|
# 先访问空白页面
|
||||||
page.get('about:blank')
|
page.get('about:blank')
|
||||||
time.sleep(random.uniform(1.0, 2.0))
|
time.sleep(get_random_wait_time(config, 'page_load_wait'))
|
||||||
|
|
||||||
# 访问目标页面
|
# 访问目标页面
|
||||||
page.get(url)
|
page.get(url)
|
||||||
time.sleep(random.uniform(2.0, 3.0)) # 等待页面加载
|
time.sleep(get_random_wait_time(config, 'page_load_wait'))
|
||||||
|
|
||||||
def fill_signup_form(page, first_name, last_name, email, translator=None):
|
def fill_signup_form(page, first_name, last_name, email, config, translator=None):
|
||||||
"""填写注册表单"""
|
"""填写注册表单"""
|
||||||
try:
|
try:
|
||||||
if translator:
|
if translator:
|
||||||
@@ -61,25 +62,25 @@ def fill_signup_form(page, first_name, last_name, email, translator=None):
|
|||||||
first_name_input = page.ele("@name=first_name")
|
first_name_input = page.ele("@name=first_name")
|
||||||
if first_name_input:
|
if first_name_input:
|
||||||
first_name_input.input(first_name)
|
first_name_input.input(first_name)
|
||||||
time.sleep(random.uniform(0.5, 1.0))
|
time.sleep(get_random_wait_time(config, 'input_wait'))
|
||||||
|
|
||||||
# 填写姓氏
|
# 填写姓氏
|
||||||
last_name_input = page.ele("@name=last_name")
|
last_name_input = page.ele("@name=last_name")
|
||||||
if last_name_input:
|
if last_name_input:
|
||||||
last_name_input.input(last_name)
|
last_name_input.input(last_name)
|
||||||
time.sleep(random.uniform(0.5, 1.0))
|
time.sleep(get_random_wait_time(config, 'input_wait'))
|
||||||
|
|
||||||
# 填写邮箱
|
# 填写邮箱
|
||||||
email_input = page.ele("@name=email")
|
email_input = page.ele("@name=email")
|
||||||
if email_input:
|
if email_input:
|
||||||
email_input.input(email)
|
email_input.input(email)
|
||||||
time.sleep(random.uniform(0.5, 1.0))
|
time.sleep(get_random_wait_time(config, 'input_wait'))
|
||||||
|
|
||||||
# 点击提交按钮
|
# 点击提交按钮
|
||||||
submit_button = page.ele("@type=submit")
|
submit_button = page.ele("@type=submit")
|
||||||
if submit_button:
|
if submit_button:
|
||||||
submit_button.click()
|
submit_button.click()
|
||||||
time.sleep(random.uniform(2.0, 3.0))
|
time.sleep(get_random_wait_time(config, 'submit_wait'))
|
||||||
|
|
||||||
if translator:
|
if translator:
|
||||||
print(f"{Fore.GREEN}✅ {translator.get('register.form_success')}{Style.RESET_ALL}")
|
print(f"{Fore.GREEN}✅ {translator.get('register.form_success')}{Style.RESET_ALL}")
|
||||||
@@ -94,43 +95,237 @@ def fill_signup_form(page, first_name, last_name, email, translator=None):
|
|||||||
print(f"填写表单时出错: {e}")
|
print(f"填写表单时出错: {e}")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def setup_driver(translator=None):
|
def get_default_chrome_path():
|
||||||
"""设置浏览器驱动"""
|
"""Get default Chrome path"""
|
||||||
co = ChromiumOptions()
|
if sys.platform == "win32":
|
||||||
|
paths = [
|
||||||
# 使用无痕模式
|
os.path.join(os.environ.get('PROGRAMFILES', ''), 'Google/Chrome/Application/chrome.exe'),
|
||||||
co.set_argument("--incognito")
|
os.path.join(os.environ.get('PROGRAMFILES(X86)', ''), 'Google/Chrome/Application/chrome.exe'),
|
||||||
|
os.path.join(os.environ.get('LOCALAPPDATA', ''), 'Google/Chrome/Application/chrome.exe')
|
||||||
|
]
|
||||||
|
elif sys.platform == "darwin":
|
||||||
|
paths = [
|
||||||
|
"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"
|
||||||
|
]
|
||||||
|
else: # Linux
|
||||||
|
paths = [
|
||||||
|
"/usr/bin/google-chrome",
|
||||||
|
"/usr/bin/google-chrome-stable"
|
||||||
|
]
|
||||||
|
|
||||||
# 设置随机端口
|
for path in paths:
|
||||||
co.set_argument("--no-sandbox")
|
if os.path.exists(path):
|
||||||
|
return path
|
||||||
# 设置随机端口
|
return ""
|
||||||
co.auto_port()
|
|
||||||
|
def get_user_documents_path():
|
||||||
# 使用有头模式(一定要设置为False,模擬人類操作)
|
"""Get user Documents folder path"""
|
||||||
co.headless(False)
|
if sys.platform == "win32":
|
||||||
|
return os.path.join(os.path.expanduser("~"), "Documents")
|
||||||
|
elif sys.platform == "darwin":
|
||||||
|
return os.path.join(os.path.expanduser("~"), "Documents")
|
||||||
|
else: # Linux
|
||||||
|
# Get actual user's home directory
|
||||||
|
sudo_user = os.environ.get('SUDO_USER')
|
||||||
|
if sudo_user:
|
||||||
|
return os.path.join("/home", sudo_user, "Documents")
|
||||||
|
return os.path.join(os.path.expanduser("~"), "Documents")
|
||||||
|
|
||||||
|
def get_random_wait_time(config, timing_type='page_load_wait'):
|
||||||
|
"""
|
||||||
|
Get random wait time from config
|
||||||
|
Args:
|
||||||
|
config: ConfigParser object
|
||||||
|
timing_type: Type of timing to get (page_load_wait, input_wait, submit_wait)
|
||||||
|
Returns:
|
||||||
|
float: Random wait time or fixed time
|
||||||
|
"""
|
||||||
try:
|
try:
|
||||||
# 加载插件
|
if not config.has_section('Timing'):
|
||||||
extension_path = os.path.join(os.getcwd(), "turnstilePatch")
|
return random.uniform(0.1, 0.8) # 默认值
|
||||||
if os.path.exists(extension_path):
|
|
||||||
co.set_argument("--allow-extensions-in-incognito")
|
if timing_type == 'random':
|
||||||
co.add_extension(extension_path)
|
min_time = float(config.get('Timing', 'min_random_time', fallback='0.1'))
|
||||||
|
max_time = float(config.get('Timing', 'max_random_time', fallback='0.8'))
|
||||||
|
return random.uniform(min_time, max_time)
|
||||||
|
|
||||||
|
time_value = config.get('Timing', timing_type, fallback='0.1-0.8')
|
||||||
|
|
||||||
|
# 检查是否为固定时间值
|
||||||
|
if '-' not in time_value and ',' not in time_value:
|
||||||
|
return float(time_value) # 返回固定时间
|
||||||
|
|
||||||
|
# 处理范围时间
|
||||||
|
min_time, max_time = map(float, time_value.split('-' if '-' in time_value else ','))
|
||||||
|
return random.uniform(min_time, max_time)
|
||||||
|
except:
|
||||||
|
return random.uniform(0.1, 0.8) # 出错时返回默认值
|
||||||
|
|
||||||
|
def setup_config(translator=None):
|
||||||
|
"""Setup configuration file and return config object"""
|
||||||
|
try:
|
||||||
|
# Set configuration file path
|
||||||
|
config_dir = os.path.join(get_user_documents_path(), ".cursor-free-vip")
|
||||||
|
config_file = os.path.join(config_dir, "config.ini")
|
||||||
|
|
||||||
|
# Create config directory (if it doesn't exist)
|
||||||
|
os.makedirs(config_dir, exist_ok=True)
|
||||||
|
|
||||||
|
# Read or create configuration file
|
||||||
|
config = configparser.ConfigParser()
|
||||||
|
|
||||||
|
# 默认配置
|
||||||
|
default_config = {
|
||||||
|
'Chrome': {
|
||||||
|
'chromepath': get_default_chrome_path()
|
||||||
|
},
|
||||||
|
'Turnstile': {
|
||||||
|
'handle_turnstile_time': '2',
|
||||||
|
'handle_turnstile_random_time': '1-3'
|
||||||
|
},
|
||||||
|
'Timing': {
|
||||||
|
'min_random_time': '0.1',
|
||||||
|
'max_random_time': '0.8',
|
||||||
|
'page_load_wait': '0.1-0.8',
|
||||||
|
'input_wait': '0.3-0.8',
|
||||||
|
'submit_wait': '0.5-1.5',
|
||||||
|
'verification_code_input': '0.1-0.3', # 验证码输入间隔
|
||||||
|
'verification_success_wait': '2-3', # 验证成功后等待
|
||||||
|
'verification_retry_wait': '2-3', # 验证重试等待
|
||||||
|
'email_check_initial_wait': '4-6', # 首次等待邮件时间
|
||||||
|
'email_refresh_wait': '2-4', # 邮箱刷新等待时间
|
||||||
|
'settings_page_load_wait': '1-2', # 设置页面加载等待
|
||||||
|
'failed_retry_time': '0.5-1', # 验证失败重试等待时间
|
||||||
|
'retry_interval': '8-12', # 重试间隔时间
|
||||||
|
'max_timeout': '160' # 最大超时时间
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Add OS-specific path configurations
|
||||||
|
if sys.platform == "win32":
|
||||||
|
appdata = os.getenv("APPDATA")
|
||||||
|
default_config['WindowsPaths'] = {
|
||||||
|
'storage_path': os.path.join(appdata, "Cursor", "User", "globalStorage", "storage.json"),
|
||||||
|
'sqlite_path': os.path.join(appdata, "Cursor", "User", "globalStorage", "state.vscdb"),
|
||||||
|
'machine_id_path': os.path.join(os.getenv("APPDATA"), "Cursor", "machineId")
|
||||||
|
}
|
||||||
|
elif sys.platform == "darwin":
|
||||||
|
default_config['MacPaths'] = {
|
||||||
|
'storage_path': os.path.abspath(os.path.expanduser("~/Library/Application Support/Cursor/User/globalStorage/storage.json")),
|
||||||
|
'sqlite_path': os.path.abspath(os.path.expanduser("~/Library/Application Support/Cursor/User/globalStorage/state.vscdb")),
|
||||||
|
'machine_id_path': os.path.expanduser("~/Library/Application Support/Cursor/machineId")
|
||||||
|
}
|
||||||
|
elif sys.platform == "linux":
|
||||||
|
sudo_user = os.environ.get('SUDO_USER')
|
||||||
|
actual_home = f"/home/{sudo_user}" if sudo_user else os.path.expanduser("~")
|
||||||
|
default_config['LinuxPaths'] = {
|
||||||
|
'storage_path': os.path.abspath(os.path.join(actual_home, ".config/Cursor/User/globalStorage/storage.json")),
|
||||||
|
'sqlite_path': os.path.abspath(os.path.join(actual_home, ".config/Cursor/User/globalStorage/state.vscdb")),
|
||||||
|
'machine_id_path': os.path.expanduser("~/.config/Cursor/machineId")
|
||||||
|
}
|
||||||
|
|
||||||
|
if os.path.exists(config_file):
|
||||||
|
config.read(config_file)
|
||||||
|
config_modified = False
|
||||||
|
|
||||||
|
# 检查并添加缺失的配置项
|
||||||
|
for section, options in default_config.items():
|
||||||
|
if not config.has_section(section):
|
||||||
|
config.add_section(section)
|
||||||
|
config_modified = True
|
||||||
|
for option, value in options.items():
|
||||||
|
if not config.has_option(section, option):
|
||||||
|
config.set(section, option, value)
|
||||||
|
config_modified = True
|
||||||
|
if translator:
|
||||||
|
print(f"{Fore.YELLOW}ℹ️ {translator.get('register.config_option_added', option=f'{section}.{option}') if translator else f'添加配置项: {section}.{option}'}{Style.RESET_ALL}")
|
||||||
|
|
||||||
|
# 如果有新增配置项,保存文件
|
||||||
|
if config_modified:
|
||||||
|
with open(config_file, 'w', encoding='utf-8') as f:
|
||||||
|
config.write(f)
|
||||||
|
if translator:
|
||||||
|
print(f"{Fore.GREEN}✅ {translator.get('register.config_updated') if translator else '配置文件已更新'}{Style.RESET_ALL}")
|
||||||
|
else:
|
||||||
|
# 创建新配置文件
|
||||||
|
config = configparser.ConfigParser()
|
||||||
|
for section, options in default_config.items():
|
||||||
|
config.add_section(section)
|
||||||
|
for option, value in options.items():
|
||||||
|
config.set(section, option, value)
|
||||||
|
|
||||||
|
with open(config_file, 'w', encoding='utf-8') as f:
|
||||||
|
config.write(f)
|
||||||
|
if translator:
|
||||||
|
print(f"{Fore.GREEN}✅ {translator.get('register.config_created') if translator else '已创建配置文件'}: {config_file}{Style.RESET_ALL}")
|
||||||
|
|
||||||
|
return config
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
if translator:
|
if translator:
|
||||||
print(f"{Fore.RED}❌ {translator.get('register.extension_load_error', error=str(e))}{Style.RESET_ALL}")
|
print(f"{Fore.RED}❌ {translator.get('register.config_setup_error', error=str(e)) if translator else f'配置设置出错: {str(e)}'}{Style.RESET_ALL}")
|
||||||
else:
|
raise
|
||||||
print(f"加载插件失败: {e}")
|
|
||||||
|
|
||||||
if translator:
|
|
||||||
print(f"{Fore.CYAN}🚀 {translator.get('register.starting_browser')}{Style.RESET_ALL}")
|
|
||||||
else:
|
|
||||||
print("正在启动浏览器...")
|
|
||||||
page = ChromiumPage(co)
|
|
||||||
|
|
||||||
return page
|
|
||||||
|
|
||||||
def handle_turnstile(page, translator=None):
|
def setup_driver(translator=None):
|
||||||
|
"""Setup browser driver"""
|
||||||
|
try:
|
||||||
|
# 获取配置
|
||||||
|
config = setup_config(translator)
|
||||||
|
|
||||||
|
# Get Chrome path
|
||||||
|
chrome_path = config.get('Chrome', 'chromepath', fallback=get_default_chrome_path())
|
||||||
|
|
||||||
|
if not chrome_path or not os.path.exists(chrome_path):
|
||||||
|
if translator:
|
||||||
|
print(f"{Fore.YELLOW}⚠️ {translator.get('register.chrome_path_invalid') if translator else 'Chrome路径无效,使用默认路径'}{Style.RESET_ALL}")
|
||||||
|
chrome_path = get_default_chrome_path()
|
||||||
|
|
||||||
|
# Set browser options
|
||||||
|
co = ChromiumOptions()
|
||||||
|
|
||||||
|
# Set Chrome path
|
||||||
|
co.set_browser_path(chrome_path)
|
||||||
|
|
||||||
|
# Use incognito mode
|
||||||
|
co.set_argument("--incognito")
|
||||||
|
|
||||||
|
# 设置随机端口
|
||||||
|
co.set_argument("--no-sandbox")
|
||||||
|
|
||||||
|
# 设置随机端口
|
||||||
|
co.auto_port()
|
||||||
|
|
||||||
|
# 使用有头模式(一定要设置为False,模拟人类操作)
|
||||||
|
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"{Fore.RED}❌ {translator.get('register.extension_load_error', error=str(e))}{Style.RESET_ALL}")
|
||||||
|
else:
|
||||||
|
print(f"加载插件失败: {e}")
|
||||||
|
|
||||||
|
if translator:
|
||||||
|
print(f"{Fore.CYAN}🚀 {translator.get('register.starting_browser')}{Style.RESET_ALL}")
|
||||||
|
else:
|
||||||
|
print("正在启动浏览器...")
|
||||||
|
|
||||||
|
page = ChromiumPage(co)
|
||||||
|
return config, page
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
if translator:
|
||||||
|
print(f"{Fore.RED}❌ {translator.get('register.browser_setup_error', error=str(e))}{Style.RESET_ALL}")
|
||||||
|
else:
|
||||||
|
print(f"设置浏览器时出错: {e}")
|
||||||
|
raise
|
||||||
|
|
||||||
|
def handle_turnstile(page, config, translator=None):
|
||||||
"""处理 Turnstile 验证"""
|
"""处理 Turnstile 验证"""
|
||||||
try:
|
try:
|
||||||
if translator:
|
if translator:
|
||||||
@@ -138,6 +333,16 @@ def handle_turnstile(page, translator=None):
|
|||||||
else:
|
else:
|
||||||
print("\n正在处理 Turnstile 验证...")
|
print("\n正在处理 Turnstile 验证...")
|
||||||
|
|
||||||
|
# from config
|
||||||
|
turnstile_time = float(config.get('Turnstile', 'handle_turnstile_time', fallback='2'))
|
||||||
|
random_time_str = config.get('Turnstile', 'handle_turnstile_random_time', fallback='1-3')
|
||||||
|
|
||||||
|
# 解析随机时间范围
|
||||||
|
try:
|
||||||
|
min_time, max_time = map(float, random_time_str.split('-'))
|
||||||
|
except:
|
||||||
|
min_time, max_time = 1, 3 # 默认值
|
||||||
|
|
||||||
max_retries = 2
|
max_retries = 2
|
||||||
retry_count = 0
|
retry_count = 0
|
||||||
|
|
||||||
@@ -151,7 +356,7 @@ def handle_turnstile(page, translator=None):
|
|||||||
try:
|
try:
|
||||||
# 尝试重置 turnstile
|
# 尝试重置 turnstile
|
||||||
page.run_js("try { turnstile.reset() } catch(e) { }")
|
page.run_js("try { turnstile.reset() } catch(e) { }")
|
||||||
time.sleep(2)
|
time.sleep(turnstile_time) # from config
|
||||||
|
|
||||||
# 定位验证框元素
|
# 定位验证框元素
|
||||||
challenge_check = (
|
challenge_check = (
|
||||||
@@ -168,12 +373,12 @@ def handle_turnstile(page, translator=None):
|
|||||||
else:
|
else:
|
||||||
print("检测到验证框...")
|
print("检测到验证框...")
|
||||||
|
|
||||||
# 随机延时后点击验证
|
# from config
|
||||||
time.sleep(random.uniform(1, 3))
|
time.sleep(random.uniform(min_time, max_time))
|
||||||
challenge_check.click()
|
challenge_check.click()
|
||||||
time.sleep(2)
|
time.sleep(turnstile_time) # from config
|
||||||
|
|
||||||
# 检查验证结果
|
# check verification result
|
||||||
if check_verification_success(page, translator):
|
if check_verification_success(page, translator):
|
||||||
if translator:
|
if translator:
|
||||||
print(f"{Fore.GREEN}✅ {translator.get('register.verification_success')}{Style.RESET_ALL}")
|
print(f"{Fore.GREEN}✅ {translator.get('register.verification_success')}{Style.RESET_ALL}")
|
||||||
@@ -195,7 +400,7 @@ def handle_turnstile(page, translator=None):
|
|||||||
print("验证通过!")
|
print("验证通过!")
|
||||||
return True
|
return True
|
||||||
|
|
||||||
time.sleep(random.uniform(1, 2))
|
time.sleep(random.uniform(min_time, max_time))
|
||||||
|
|
||||||
if translator:
|
if translator:
|
||||||
print(f"{Fore.RED}❌ {translator.get('register.verification_failed')}{Style.RESET_ALL}")
|
print(f"{Fore.RED}❌ {translator.get('register.verification_failed')}{Style.RESET_ALL}")
|
||||||
@@ -240,43 +445,57 @@ def generate_password(length=12):
|
|||||||
chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*"
|
chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*"
|
||||||
return ''.join(random.choices(chars, k=length))
|
return ''.join(random.choices(chars, k=length))
|
||||||
|
|
||||||
def fill_password(page, password, translator=None):
|
def fill_password(page, password: str, config, translator=None) -> bool:
|
||||||
"""填写密码"""
|
"""
|
||||||
|
填写密码表单
|
||||||
|
"""
|
||||||
try:
|
try:
|
||||||
if translator:
|
print(f"{Fore.CYAN}🔑 {translator.get('register.setting_password') if translator else '设置密码'}{Style.RESET_ALL}")
|
||||||
print(f"{Fore.CYAN}🔑 {translator.get('register.setting_password')}{Style.RESET_ALL}")
|
|
||||||
else:
|
# 等待密码框出现并尝试多次
|
||||||
print(f"\n{translator.get('register.setting_password')}")
|
max_retries = 5
|
||||||
password_input = page.ele("@name=password")
|
for i in range(max_retries):
|
||||||
if password_input:
|
# 检查是否出现错误信息
|
||||||
password_input.input(password)
|
if page.ele("This email is not available."):
|
||||||
time.sleep(random.uniform(0.5, 1.0))
|
print(f"{Fore.RED}❌ {translator.get('register.email_used') if translator else '注册失败:邮箱已被使用'}{Style.RESET_ALL}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
# 查找密码输入框
|
||||||
|
password_input = page.ele("@name=password")
|
||||||
|
if password_input:
|
||||||
|
# 清除可能存在的旧值并输入新密码
|
||||||
|
password_input.click()
|
||||||
|
time.sleep(get_random_wait_time(config, 'input_wait'))
|
||||||
|
password_input.input(password)
|
||||||
|
time.sleep(get_random_wait_time(config, 'input_wait'))
|
||||||
|
|
||||||
|
# 查找并点击提交按钮
|
||||||
|
submit_button = page.ele("@type=submit")
|
||||||
|
if submit_button:
|
||||||
|
submit_button.click()
|
||||||
|
print(f"{Fore.GREEN}✅ {translator.get('register.password_submitted') if translator else '密码已提交'}{Style.RESET_ALL}")
|
||||||
|
time.sleep(get_random_wait_time(config, 'submit_wait'))
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
print(f"{Fore.YELLOW}⚠️ {translator.get('register.retry_submit') if translator else '未找到提交按钮,重试中...'}{Style.RESET_ALL}")
|
||||||
|
|
||||||
submit_button = page.ele("@type=submit")
|
# 如果没找到密码框,等待后重试
|
||||||
if submit_button:
|
time.sleep(get_random_wait_time(config, 'failed_retry_time'))
|
||||||
submit_button.click()
|
if i < max_retries - 1: # 不是最后一次尝试时才打印
|
||||||
time.sleep(random.uniform(2.0, 3.0))
|
print(f"{Fore.YELLOW}⚠️ {translator.get('register.retry_password', attempt=i+1) if translator else f'第 {i+1} 次尝试设置密码...'}{Style.RESET_ALL}")
|
||||||
|
|
||||||
if translator:
|
print(f"{Fore.RED}❌ {translator.get('register.password_set_failed') if translator else '密码设置失败:超过重试次数'}{Style.RESET_ALL}")
|
||||||
print(f"{Fore.GREEN}✅ {translator.get('register.password_success')}{Style.RESET_ALL}")
|
|
||||||
else:
|
|
||||||
print(f"{translator.get('register.password_success')}: {password}")
|
|
||||||
return True
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
if translator:
|
|
||||||
print(f"{Fore.RED}❌ {translator.get('register.password_error', error=str(e))}{Style.RESET_ALL}")
|
|
||||||
else:
|
|
||||||
print(f"{translator.get('register.password_error')}: {e}")
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def handle_verification_code(browser_tab, email_tab, controller, email, password, translator=None):
|
except Exception as e:
|
||||||
|
print(f"{Fore.RED}❌ {translator.get('register.password_error', error=str(e)) if translator else f'设置密码时出错: {str(e)}'}{Style.RESET_ALL}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
def handle_verification_code(browser_tab, email_tab, controller, email, password, config, translator=None):
|
||||||
"""处理验证码"""
|
"""处理验证码"""
|
||||||
try:
|
try:
|
||||||
if translator:
|
if translator:
|
||||||
print(f"\n{Fore.CYAN}{translator.get('register.waiting_for_verification_code')}{Style.RESET_ALL}")
|
print(f"\n{Fore.CYAN}{translator.get('register.waiting_for_verification_code')}{Style.RESET_ALL}")
|
||||||
else:
|
|
||||||
print(f"\n{translator.get('register.waiting_for_verification_code')}")
|
|
||||||
|
|
||||||
# 检查是否使用手动输入验证码
|
# 检查是否使用手动输入验证码
|
||||||
if hasattr(controller, 'get_verification_code') and email_tab is None: # 手动模式
|
if hasattr(controller, 'get_verification_code') and email_tab is None: # 手动模式
|
||||||
@@ -285,23 +504,21 @@ def handle_verification_code(browser_tab, email_tab, controller, email, password
|
|||||||
# 在注册页面填写验证码
|
# 在注册页面填写验证码
|
||||||
for i, digit in enumerate(verification_code):
|
for i, digit in enumerate(verification_code):
|
||||||
browser_tab.ele(f"@data-index={i}").input(digit)
|
browser_tab.ele(f"@data-index={i}").input(digit)
|
||||||
time.sleep(random.uniform(0.1, 0.3))
|
time.sleep(get_random_wait_time(config, 'verification_code_input'))
|
||||||
|
|
||||||
print(f"{translator.get('register.verification_success')}")
|
print(f"{translator.get('register.verification_success')}")
|
||||||
time.sleep(3)
|
time.sleep(get_random_wait_time(config, 'verification_success_wait'))
|
||||||
|
|
||||||
# 处理最后一次 Turnstile 验证
|
# 处理最后一次 Turnstile 验证
|
||||||
if handle_turnstile(browser_tab, translator):
|
if handle_turnstile(browser_tab, config, translator):
|
||||||
if translator:
|
if translator:
|
||||||
print(f"{translator.get('register.verification_success')}")
|
print(f"{Fore.GREEN}✅ {translator.get('register.verification_success')}{Style.RESET_ALL}")
|
||||||
else:
|
time.sleep(get_random_wait_time(config, 'verification_retry_wait'))
|
||||||
print(f"{translator.get('register.verification_success')}")
|
|
||||||
time.sleep(2)
|
|
||||||
|
|
||||||
# 访问设置页面
|
# 访问设置页面
|
||||||
print(f"{translator.get('register.visiting_url')}: https://www.cursor.com/settings")
|
print(f"{Fore.CYAN} {translator.get('register.visiting_url')}: https://www.cursor.com/settings{Style.RESET_ALL}")
|
||||||
browser_tab.get("https://www.cursor.com/settings")
|
browser_tab.get("https://www.cursor.com/settings")
|
||||||
time.sleep(3) # 等待页面加载
|
time.sleep(get_random_wait_time(config, 'settings_page_load_wait'))
|
||||||
return True, browser_tab
|
return True, browser_tab
|
||||||
|
|
||||||
return False, None
|
return False, None
|
||||||
@@ -309,11 +526,11 @@ def handle_verification_code(browser_tab, email_tab, controller, email, password
|
|||||||
# 自动获取验证码逻辑
|
# 自动获取验证码逻辑
|
||||||
elif email_tab:
|
elif email_tab:
|
||||||
print(f"{translator.get('register.waiting_for_verification_code')}")
|
print(f"{translator.get('register.waiting_for_verification_code')}")
|
||||||
time.sleep(5) # 等待验证码邮件
|
time.sleep(get_random_wait_time(config, 'email_check_initial_wait'))
|
||||||
|
|
||||||
# 使用已有的 email_tab 刷新邮箱
|
# 使用已有的 email_tab 刷新邮箱
|
||||||
email_tab.refresh_inbox()
|
email_tab.refresh_inbox()
|
||||||
time.sleep(3)
|
time.sleep(get_random_wait_time(config, 'email_refresh_wait'))
|
||||||
|
|
||||||
# 检查邮箱是否有验证码邮件
|
# 检查邮箱是否有验证码邮件
|
||||||
if email_tab.check_for_cursor_email():
|
if email_tab.check_for_cursor_email():
|
||||||
@@ -322,28 +539,23 @@ def handle_verification_code(browser_tab, email_tab, controller, email, password
|
|||||||
# 在注册页面填写验证码
|
# 在注册页面填写验证码
|
||||||
for i, digit in enumerate(verification_code):
|
for i, digit in enumerate(verification_code):
|
||||||
browser_tab.ele(f"@data-index={i}").input(digit)
|
browser_tab.ele(f"@data-index={i}").input(digit)
|
||||||
time.sleep(random.uniform(0.1, 0.3))
|
time.sleep(get_random_wait_time(config, 'verification_code_input'))
|
||||||
|
|
||||||
if translator:
|
if translator:
|
||||||
print(f"{Fore.GREEN}✅ {translator.get('register.verification_success')}{Style.RESET_ALL}")
|
print(f"{Fore.GREEN}✅ {translator.get('register.verification_success')}{Style.RESET_ALL}")
|
||||||
else:
|
time.sleep(get_random_wait_time(config, 'verification_success_wait'))
|
||||||
print("验证码填写完成")
|
|
||||||
time.sleep(3)
|
|
||||||
|
|
||||||
# 处理最后一次 Turnstile 验证
|
# 处理最后一次 Turnstile 验证
|
||||||
if handle_turnstile(browser_tab, translator):
|
if handle_turnstile(browser_tab, config, translator):
|
||||||
if translator:
|
if translator:
|
||||||
print(f"{Fore.GREEN}✅ {translator.get('register.verification_success')}{Style.RESET_ALL}")
|
print(f"{Fore.GREEN}✅ {translator.get('register.verification_success')}{Style.RESET_ALL}")
|
||||||
else:
|
time.sleep(get_random_wait_time(config, 'verification_retry_wait'))
|
||||||
print("最后一次验证通过!")
|
|
||||||
time.sleep(2)
|
|
||||||
|
|
||||||
# 访问设置页面
|
# 访问设置页面
|
||||||
if translator:
|
if translator:
|
||||||
print(f"{Fore.CYAN}🔑 {translator.get('register.visiting_url')}: https://www.cursor.com/settings{Style.RESET_ALL}")
|
print(f"{Fore.CYAN}🔑 {translator.get('register.visiting_url')}: https://www.cursor.com/settings{Style.RESET_ALL}")
|
||||||
else:
|
|
||||||
print("访问设置页面...")
|
|
||||||
browser_tab.get("https://www.cursor.com/settings")
|
browser_tab.get("https://www.cursor.com/settings")
|
||||||
time.sleep(3) # 等待页面加载
|
time.sleep(get_random_wait_time(config, 'settings_page_load_wait'))
|
||||||
return True, browser_tab
|
return True, browser_tab
|
||||||
|
|
||||||
else:
|
else:
|
||||||
@@ -356,69 +568,55 @@ def handle_verification_code(browser_tab, email_tab, controller, email, password
|
|||||||
# 获取验证码,设置超时
|
# 获取验证码,设置超时
|
||||||
verification_code = None
|
verification_code = None
|
||||||
max_attempts = 20
|
max_attempts = 20
|
||||||
retry_interval = 10
|
retry_interval = float(config.get('Timing', 'retry_interval', fallback='10')) # 使用配置值
|
||||||
start_time = time.time()
|
start_time = time.time()
|
||||||
timeout = 160
|
timeout = float(config.get('Timing', 'max_timeout', fallback='160')) # 使用配置值
|
||||||
|
|
||||||
if translator:
|
if translator:
|
||||||
print(f"{Fore.CYAN}{translator.get('register.start_getting_verification_code')}{Style.RESET_ALL}")
|
print(f"{Fore.CYAN}{translator.get('register.start_getting_verification_code')}{Style.RESET_ALL}")
|
||||||
else:
|
|
||||||
print("开始获取验证码...")
|
|
||||||
|
|
||||||
for attempt in range(max_attempts):
|
for attempt in range(max_attempts):
|
||||||
# 检查是否超时
|
# 检查是否超时
|
||||||
if time.time() - start_time > timeout:
|
if time.time() - start_time > timeout:
|
||||||
if translator:
|
if translator:
|
||||||
print(f"{Fore.RED}❌ {translator.get('register.verification_timeout')}{Style.RESET_ALL}")
|
print(f"{Fore.RED}❌ {translator.get('register.verification_timeout')}{Style.RESET_ALL}")
|
||||||
else:
|
|
||||||
print("获取验证码超时...")
|
|
||||||
break
|
break
|
||||||
|
|
||||||
verification_code = controller.get_verification_code()
|
verification_code = controller.get_verification_code()
|
||||||
if verification_code:
|
if verification_code:
|
||||||
if translator:
|
if translator:
|
||||||
print(f"{Fore.GREEN}✅ {translator.get('register.verification_success')}{Style.RESET_ALL}")
|
print(f"{Fore.GREEN}✅ {translator.get('register.verification_success')}{Style.RESET_ALL}")
|
||||||
else:
|
|
||||||
print(f"成功获取验证码: {verification_code}")
|
|
||||||
break
|
break
|
||||||
|
|
||||||
remaining_time = int(timeout - (time.time() - start_time))
|
remaining_time = int(timeout - (time.time() - start_time))
|
||||||
if translator:
|
if translator:
|
||||||
print(f"{Fore.CYAN}{translator.get('register.try_get_code', attempt=attempt + 1, time=remaining_time)}{Style.RESET_ALL}")
|
print(f"{Fore.CYAN}{translator.get('register.try_get_code', attempt=attempt + 1, time=remaining_time)}{Style.RESET_ALL}")
|
||||||
else:
|
|
||||||
print(f"第 {attempt + 1} 次尝试获取验证码,剩余时间: {remaining_time}秒...")
|
|
||||||
|
|
||||||
# 刷新邮箱
|
# 刷新邮箱
|
||||||
email_tab.refresh_inbox()
|
email_tab.refresh_inbox()
|
||||||
time.sleep(retry_interval)
|
time.sleep(get_random_wait_time(config, 'retry_interval')) # 使用 get_random_wait_time
|
||||||
|
|
||||||
if verification_code:
|
if verification_code:
|
||||||
# 在注册页面填写验证码
|
# 在注册页面填写验证码
|
||||||
for i, digit in enumerate(verification_code):
|
for i, digit in enumerate(verification_code):
|
||||||
browser_tab.ele(f"@data-index={i}").input(digit)
|
browser_tab.ele(f"@data-index={i}").input(digit)
|
||||||
time.sleep(random.uniform(0.1, 0.3))
|
time.sleep(get_random_wait_time(config, 'verification_code_input'))
|
||||||
|
|
||||||
if translator:
|
if translator:
|
||||||
print(f"{Fore.GREEN}✅ {translator.get('register.verification_success')}{Style.RESET_ALL}")
|
print(f"{Fore.GREEN}✅ {translator.get('register.verification_success')}{Style.RESET_ALL}")
|
||||||
else:
|
time.sleep(get_random_wait_time(config, 'verification_success_wait'))
|
||||||
print("验证码填写完成")
|
|
||||||
time.sleep(3)
|
|
||||||
|
|
||||||
# 处理最后一次 Turnstile 验证
|
# 处理最后一次 Turnstile 验证
|
||||||
if handle_turnstile(browser_tab, translator):
|
if handle_turnstile(browser_tab, config, translator):
|
||||||
if translator:
|
if translator:
|
||||||
print(f"{Fore.GREEN}✅ {translator.get('register.verification_success')}{Style.RESET_ALL}")
|
print(f"{Fore.GREEN}✅ {translator.get('register.verification_success')}{Style.RESET_ALL}")
|
||||||
else:
|
time.sleep(get_random_wait_time(config, 'verification_retry_wait'))
|
||||||
print("最后一次验证通过!")
|
|
||||||
time.sleep(2)
|
|
||||||
|
|
||||||
# 直接访问设置页面
|
# 直接访问设置页面
|
||||||
if translator:
|
if translator:
|
||||||
print(f"{Fore.CYAN}{translator.get('register.visiting_url')}: https://www.cursor.com/settings{Style.RESET_ALL}")
|
print(f"{Fore.CYAN}{translator.get('register.visiting_url')}: https://www.cursor.com/settings{Style.RESET_ALL}")
|
||||||
else:
|
|
||||||
print("访问设置页面...")
|
|
||||||
browser_tab.get("https://www.cursor.com/settings")
|
browser_tab.get("https://www.cursor.com/settings")
|
||||||
time.sleep(3) # 等待页面加载
|
time.sleep(get_random_wait_time(config, 'settings_page_load_wait'))
|
||||||
|
|
||||||
# 直接返回成功,让 cursor_register.py 处理账户信息获取
|
# 直接返回成功,让 cursor_register.py 处理账户信息获取
|
||||||
return True, browser_tab
|
return True, browser_tab
|
||||||
@@ -426,8 +624,6 @@ def handle_verification_code(browser_tab, email_tab, controller, email, password
|
|||||||
else:
|
else:
|
||||||
if translator:
|
if translator:
|
||||||
print(f"{Fore.RED}❌ {translator.get('register.verification_failed')}{Style.RESET_ALL}")
|
print(f"{Fore.RED}❌ {translator.get('register.verification_failed')}{Style.RESET_ALL}")
|
||||||
else:
|
|
||||||
print("最后一次验证失败")
|
|
||||||
return False, None
|
return False, None
|
||||||
|
|
||||||
return False, None
|
return False, None
|
||||||
@@ -435,8 +631,6 @@ def handle_verification_code(browser_tab, email_tab, controller, email, password
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
if translator:
|
if translator:
|
||||||
print(f"{Fore.RED}❌ {translator.get('register.verification_error', error=str(e))}{Style.RESET_ALL}")
|
print(f"{Fore.RED}❌ {translator.get('register.verification_error', error=str(e))}{Style.RESET_ALL}")
|
||||||
else:
|
|
||||||
print(f"处理验证码时出错: {e}")
|
|
||||||
return False, None
|
return False, None
|
||||||
|
|
||||||
def handle_sign_in(browser_tab, email, password, translator=None):
|
def handle_sign_in(browser_tab, email, password, translator=None):
|
||||||
@@ -499,26 +693,20 @@ def main(email=None, password=None, first_name=None, last_name=None, email_tab=N
|
|||||||
page = None
|
page = None
|
||||||
success = False
|
success = False
|
||||||
try:
|
try:
|
||||||
page = setup_driver(translator)
|
config, page = setup_driver(translator)
|
||||||
if translator:
|
if translator:
|
||||||
print(f"{Fore.CYAN}🚀 {translator.get('register.browser_started')}{Style.RESET_ALL}")
|
print(f"{Fore.CYAN}🚀 {translator.get('register.browser_started')}{Style.RESET_ALL}")
|
||||||
else:
|
|
||||||
print("浏览器已启动")
|
|
||||||
|
|
||||||
# 访问注册页面
|
# 访问注册页面
|
||||||
url = "https://authenticator.cursor.sh/sign-up"
|
url = "https://authenticator.cursor.sh/sign-up"
|
||||||
if translator:
|
if translator:
|
||||||
print(f"\n{Fore.CYAN}{translator.get('register.visiting_url')}: {url}{Style.RESET_ALL}")
|
print(f"\n{Fore.CYAN}{translator.get('register.visiting_url')}: {url}{Style.RESET_ALL}")
|
||||||
else:
|
|
||||||
print(f"\n正在访问: {url}")
|
|
||||||
|
|
||||||
# 访问页面
|
# 访问页面
|
||||||
simulate_human_input(page, url, translator)
|
simulate_human_input(page, url, config, translator)
|
||||||
if translator:
|
if translator:
|
||||||
print(f"{Fore.CYAN}{translator.get('register.waiting_for_page_load')}{Style.RESET_ALL}")
|
print(f"{Fore.CYAN}{translator.get('register.waiting_for_page_load')}{Style.RESET_ALL}")
|
||||||
else:
|
time.sleep(get_random_wait_time(config, 'page_load_wait'))
|
||||||
print("等待页面加载...")
|
|
||||||
time.sleep(5)
|
|
||||||
|
|
||||||
# 如果没有提供账号信息,则生成随机信息
|
# 如果没有提供账号信息,则生成随机信息
|
||||||
if not all([email, password, first_name, last_name]):
|
if not all([email, password, first_name, last_name]):
|
||||||
@@ -535,44 +723,36 @@ def main(email=None, password=None, first_name=None, last_name=None, email_tab=N
|
|||||||
f.write(f"{'='*50}\n")
|
f.write(f"{'='*50}\n")
|
||||||
|
|
||||||
# 填写表单
|
# 填写表单
|
||||||
if fill_signup_form(page, first_name, last_name, email, translator):
|
if fill_signup_form(page, first_name, last_name, email, config, translator):
|
||||||
if translator:
|
if translator:
|
||||||
print(f"\n{Fore.GREEN}{translator.get('register.form_submitted')}{Style.RESET_ALL}")
|
print(f"\n{Fore.GREEN}{translator.get('register.form_submitted')}{Style.RESET_ALL}")
|
||||||
else:
|
|
||||||
print("\n表单已提交,开始验证...")
|
|
||||||
|
|
||||||
# 处理第一次 Turnstile 验证
|
# 处理第一次 Turnstile 验证
|
||||||
if handle_turnstile(page, translator):
|
if handle_turnstile(page, config, translator):
|
||||||
if translator:
|
if translator:
|
||||||
print(f"\n{Fore.GREEN}{translator.get('register.first_verification_passed')}{Style.RESET_ALL}")
|
print(f"\n{Fore.GREEN}{translator.get('register.first_verification_passed')}{Style.RESET_ALL}")
|
||||||
else:
|
|
||||||
print("\n第一阶段验证通过!")
|
|
||||||
|
|
||||||
# 填写密码
|
# 填写密码
|
||||||
if fill_password(page, password, translator):
|
if fill_password(page, password, config, translator):
|
||||||
if translator:
|
if translator:
|
||||||
print(f"\n{Fore.CYAN}{translator.get('register.waiting_for_second_verification')}{Style.RESET_ALL}")
|
print(f"\n{Fore.CYAN}{translator.get('register.waiting_for_second_verification')}{Style.RESET_ALL}")
|
||||||
else:
|
|
||||||
print("\n等待第二次验证...")
|
|
||||||
time.sleep(2)
|
time.sleep(2)
|
||||||
|
|
||||||
# 处理第二次 Turnstile 验证
|
# 处理第二次 Turnstile 验证
|
||||||
if handle_turnstile(page, translator):
|
if handle_turnstile(page, config, translator):
|
||||||
if translator:
|
if translator:
|
||||||
print(f"\n{Fore.CYAN}{translator.get('register.waiting_for_verification_code')}{Style.RESET_ALL}")
|
print(f"\n{Fore.CYAN}{translator.get('register.waiting_for_verification_code')}{Style.RESET_ALL}")
|
||||||
else:
|
if handle_verification_code(page, email_tab, controller, email, password, config, translator):
|
||||||
print("\n开始处理验证码...")
|
|
||||||
if handle_verification_code(page, email_tab, controller, email, password, translator):
|
|
||||||
success = True
|
success = True
|
||||||
return True, page # 返回浏览器实例
|
return True, page
|
||||||
else:
|
else:
|
||||||
print("\n验证码处理失败")
|
print(f"\n{Fore.RED} {translator.get('register.verification_code_processing_failed') if translator else '验证码处理失败'}{Style.RESET_ALL}")
|
||||||
else:
|
else:
|
||||||
print("\n第二次验证失败")
|
print(f"\n{Fore.RED} {translator.get('register.second_verification_failed') if translator else '第二次验证失败'}{Style.RESET_ALL}")
|
||||||
else:
|
else:
|
||||||
print("\n密码设置失败")
|
print(f"\n{Fore.RED} {translator.get('register.second_verification_failed') if translator else '第二次验证失败'}{Style.RESET_ALL}")
|
||||||
else:
|
else:
|
||||||
print("\n第一次验证失败")
|
print(f"\n{Fore.RED} {translator.get('register.first_verification_failed') if translator else '第一次验证失败'}{Style.RESET_ALL}")
|
||||||
|
|
||||||
return False, None
|
return False, None
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import requests
|
|||||||
import random
|
import random
|
||||||
import string
|
import string
|
||||||
|
|
||||||
# 初始化 colorama
|
# Initialize colorama
|
||||||
init()
|
init()
|
||||||
|
|
||||||
class NewTempEmail:
|
class NewTempEmail:
|
||||||
@@ -34,7 +34,7 @@ class NewTempEmail:
|
|||||||
# Split text and remove empty lines
|
# Split text and remove empty lines
|
||||||
domains = [line.strip() for line in response.text.split('\n') if line.strip()]
|
domains = [line.strip() for line in response.text.split('\n') if line.strip()]
|
||||||
if self.translator:
|
if self.translator:
|
||||||
print(f"{Fore.CYAN}ℹ️ {self.translator.get('email.blocked_domains_loaded', count=len(domains))}{Style.RESET_ALL}")
|
print(f"{Fore.CYAN}ℹ️ {self.translator.get('email.blocked_domains_loaded', count=len(domains))}{Style.RESET_ALL}")
|
||||||
else:
|
else:
|
||||||
print(f"{Fore.CYAN}ℹ️ 已加载 {len(domains)} 个被屏蔽的域名{Style.RESET_ALL}")
|
print(f"{Fore.CYAN}ℹ️ 已加载 {len(domains)} 个被屏蔽的域名{Style.RESET_ALL}")
|
||||||
return domains
|
return domains
|
||||||
@@ -80,11 +80,11 @@ class NewTempEmail:
|
|||||||
attempt += 1
|
attempt += 1
|
||||||
try:
|
try:
|
||||||
if self.translator:
|
if self.translator:
|
||||||
print(f"{Fore.CYAN}ℹ️ {self.translator.get('email.visiting_site').replace('mail.tm', self.selected_service['name'])}{Style.RESET_ALL}")
|
print(f"{Fore.CYAN}ℹ️ {self.translator.get('email.visiting_site').replace('mail.tm', self.selected_service['name'])}{Style.RESET_ALL}")
|
||||||
else:
|
else:
|
||||||
print(f"{Fore.CYAN}ℹ️ 正在访问 {self.selected_service['name']}...{Style.RESET_ALL}")
|
print(f"{Fore.CYAN}ℹ️ 正在访问 {self.selected_service['name']}...{Style.RESET_ALL}")
|
||||||
|
|
||||||
# 获取可用域名列表
|
# Get available domain list
|
||||||
try:
|
try:
|
||||||
domains_response = requests.get(f"{self.api_url}/domains", timeout=10)
|
domains_response = requests.get(f"{self.api_url}/domains", timeout=10)
|
||||||
if domains_response.status_code != 200:
|
if domains_response.status_code != 200:
|
||||||
@@ -93,7 +93,7 @@ class NewTempEmail:
|
|||||||
raise Exception(f"{self.translator.get('email.failed_to_get_available_domains') if self.translator else 'Failed to get available domains'}")
|
raise Exception(f"{self.translator.get('email.failed_to_get_available_domains') if self.translator else 'Failed to get available domains'}")
|
||||||
|
|
||||||
domains = domains_response.json()["hydra:member"]
|
domains = domains_response.json()["hydra:member"]
|
||||||
print(f"{Fore.CYAN}ℹ️ {self.translator.get('email.available_domains_loaded', count=len(domains))}{Style.RESET_ALL}")
|
print(f"{Fore.CYAN}ℹ️ {self.translator.get('email.available_domains_loaded', count=len(domains))}{Style.RESET_ALL}")
|
||||||
|
|
||||||
if not domains:
|
if not domains:
|
||||||
raise Exception(f"{self.translator.get('email.no_available_domains') if self.translator else '没有可用域名'}")
|
raise Exception(f"{self.translator.get('email.no_available_domains') if self.translator else '没有可用域名'}")
|
||||||
@@ -101,11 +101,11 @@ class NewTempEmail:
|
|||||||
print(f"{Fore.RED}❌ 获取域名列表时出错: {str(e)}{Style.RESET_ALL}")
|
print(f"{Fore.RED}❌ 获取域名列表时出错: {str(e)}{Style.RESET_ALL}")
|
||||||
raise
|
raise
|
||||||
|
|
||||||
# 排除被屏蔽的域名
|
# Exclude blocked domains
|
||||||
try:
|
try:
|
||||||
filtered_domains = self.exclude_blocked_domains(domains)
|
filtered_domains = self.exclude_blocked_domains(domains)
|
||||||
if self.translator:
|
if self.translator:
|
||||||
print(f"{Fore.CYAN}ℹ️ {self.translator.get('email.domains_filtered', count=len(filtered_domains))}{Style.RESET_ALL}")
|
print(f"{Fore.CYAN}ℹ️ {self.translator.get('email.domains_filtered', count=len(filtered_domains))}{Style.RESET_ALL}")
|
||||||
else:
|
else:
|
||||||
print(f"{Fore.CYAN}ℹ️ 过滤后剩余 {len(filtered_domains)} 个可用域名{Style.RESET_ALL}")
|
print(f"{Fore.CYAN}ℹ️ 过滤后剩余 {len(filtered_domains)} 个可用域名{Style.RESET_ALL}")
|
||||||
|
|
||||||
@@ -115,33 +115,33 @@ class NewTempEmail:
|
|||||||
else:
|
else:
|
||||||
print(f"{Fore.RED}❌ 所有域名都被屏蔽了,尝试切换服务{Style.RESET_ALL}")
|
print(f"{Fore.RED}❌ 所有域名都被屏蔽了,尝试切换服务{Style.RESET_ALL}")
|
||||||
|
|
||||||
# 切换到另一个服务
|
# Switch to another service
|
||||||
for service in self.services:
|
for service in self.services:
|
||||||
if service["api_url"] != self.api_url:
|
if service["api_url"] != self.api_url:
|
||||||
self.selected_service = service
|
self.selected_service = service
|
||||||
self.api_url = service["api_url"]
|
self.api_url = service["api_url"]
|
||||||
if self.translator:
|
if self.translator:
|
||||||
print(f"{Fore.CYAN}ℹ️ {self.translator.get('email.switching_service', service=service['name'])}{Style.RESET_ALL}")
|
print(f"{Fore.CYAN}ℹ️ {self.translator.get('email.switching_service', service=service['name'])}{Style.RESET_ALL}")
|
||||||
else:
|
else:
|
||||||
print(f"{Fore.CYAN}ℹ️ 切换到 {service['name']} 服务{Style.RESET_ALL}")
|
print(f"{Fore.CYAN}ℹ️ 切换到 {service['name']} 服务{Style.RESET_ALL}")
|
||||||
return self.create_email() # 递归调用
|
return self.create_email() # Recursively call
|
||||||
|
|
||||||
raise Exception(f"{self.translator.get('email.no_available_domains_after_filtering') if self.translator else '过滤后没有可用域名'}")
|
raise Exception(f"{self.translator.get('email.no_available_domains_after_filtering') if self.translator else '过滤后没有可用域名'}")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"{Fore.RED}❌ 过滤域名时出错: {str(e)}{Style.RESET_ALL}")
|
print(f"{Fore.RED}❌ 过滤域名时出错: {str(e)}{Style.RESET_ALL}")
|
||||||
raise
|
raise
|
||||||
|
|
||||||
# 生成随机用户名和密码
|
# Generate random username and password
|
||||||
try:
|
try:
|
||||||
username, password = self._generate_credentials()
|
username, password = self._generate_credentials()
|
||||||
self.password = password
|
self.password = password
|
||||||
|
|
||||||
# 创建邮箱账户
|
# Create email account
|
||||||
selected_domain = filtered_domains[0]['domain']
|
selected_domain = filtered_domains[0]['domain']
|
||||||
email = f"{username}@{selected_domain}"
|
email = f"{username}@{selected_domain}"
|
||||||
|
|
||||||
if self.translator:
|
if self.translator:
|
||||||
print(f"{Fore.CYAN}ℹ️ {self.translator.get('email.trying_to_create_email', email=email)}{Style.RESET_ALL}")
|
print(f"{Fore.CYAN}ℹ️ {self.translator.get('email.trying_to_create_email', email=email)}{Style.RESET_ALL}")
|
||||||
else:
|
else:
|
||||||
print(f"{Fore.CYAN}ℹ️ 尝试创建邮箱: {email}{Style.RESET_ALL}")
|
print(f"{Fore.CYAN}ℹ️ 尝试创建邮箱: {email}{Style.RESET_ALL}")
|
||||||
|
|
||||||
@@ -153,7 +153,7 @@ class NewTempEmail:
|
|||||||
print(f"{Fore.RED}❌ 生成凭据时出错: {str(e)}{Style.RESET_ALL}")
|
print(f"{Fore.RED}❌ 生成凭据时出错: {str(e)}{Style.RESET_ALL}")
|
||||||
raise
|
raise
|
||||||
|
|
||||||
# 创建账户
|
# Create account
|
||||||
try:
|
try:
|
||||||
create_response = requests.post(f"{self.api_url}/accounts", json=account_data, timeout=15)
|
create_response = requests.post(f"{self.api_url}/accounts", json=account_data, timeout=15)
|
||||||
|
|
||||||
@@ -167,13 +167,13 @@ class NewTempEmail:
|
|||||||
else:
|
else:
|
||||||
print(f"{Fore.RED}❌ 响应内容: {create_response.text}{Style.RESET_ALL}")
|
print(f"{Fore.RED}❌ 响应内容: {create_response.text}{Style.RESET_ALL}")
|
||||||
|
|
||||||
# 如果是域名问题,尝试下一个域名
|
# If it's a domain problem, try the next available domain
|
||||||
if len(filtered_domains) > 1 and ("domain" in create_response.text.lower() or "address" in create_response.text.lower()):
|
if len(filtered_domains) > 1 and ("domain" in create_response.text.lower() or "address" in create_response.text.lower()):
|
||||||
print(f"{Fore.YELLOW}⚠️ 尝试使用下一个可用域名...{Style.RESET_ALL}")
|
print(f"{Fore.YELLOW}⚠️ 尝试使用下一个可用域名...{Style.RESET_ALL}")
|
||||||
# 将当前域名添加到屏蔽列表
|
# Add current domain to blocked list
|
||||||
if selected_domain not in self.blocked_domains:
|
if selected_domain not in self.blocked_domains:
|
||||||
self.blocked_domains.append(selected_domain)
|
self.blocked_domains.append(selected_domain)
|
||||||
# 递归调用自己
|
# Recursively call yourself
|
||||||
return self.create_email()
|
return self.create_email()
|
||||||
|
|
||||||
raise Exception(f"{self.translator.get('email.failed_to_create_account') if self.translator else '创建账户失败'}")
|
raise Exception(f"{self.translator.get('email.failed_to_create_account') if self.translator else '创建账户失败'}")
|
||||||
@@ -184,7 +184,7 @@ class NewTempEmail:
|
|||||||
print(f"{Fore.RED}❌ 创建账户时出错: {str(e)}{Style.RESET_ALL}")
|
print(f"{Fore.RED}❌ 创建账户时出错: {str(e)}{Style.RESET_ALL}")
|
||||||
raise
|
raise
|
||||||
|
|
||||||
# 获取访问令牌
|
# Get access token
|
||||||
try:
|
try:
|
||||||
token_data = {
|
token_data = {
|
||||||
"address": email,
|
"address": email,
|
||||||
@@ -238,7 +238,7 @@ class NewTempEmail:
|
|||||||
else:
|
else:
|
||||||
print(f"{Fore.CYAN}🔄 正在刷新邮箱...{Style.RESET_ALL}")
|
print(f"{Fore.CYAN}🔄 正在刷新邮箱...{Style.RESET_ALL}")
|
||||||
|
|
||||||
# 使用 API 获取最新邮件
|
# Use API to get latest email
|
||||||
headers = {"Authorization": f"Bearer {self.token}"}
|
headers = {"Authorization": f"Bearer {self.token}"}
|
||||||
response = requests.get(f"{self.api_url}/messages", headers=headers)
|
response = requests.get(f"{self.api_url}/messages", headers=headers)
|
||||||
|
|
||||||
@@ -265,7 +265,7 @@ class NewTempEmail:
|
|||||||
def check_for_cursor_email(self):
|
def check_for_cursor_email(self):
|
||||||
"""检查是否有 Cursor 的验证邮件"""
|
"""检查是否有 Cursor 的验证邮件"""
|
||||||
try:
|
try:
|
||||||
# 使用 API 获取邮件列表
|
# Use API to get email list
|
||||||
headers = {"Authorization": f"Bearer {self.token}"}
|
headers = {"Authorization": f"Bearer {self.token}"}
|
||||||
response = requests.get(f"{self.api_url}/messages", headers=headers)
|
response = requests.get(f"{self.api_url}/messages", headers=headers)
|
||||||
|
|
||||||
@@ -273,7 +273,7 @@ class NewTempEmail:
|
|||||||
messages = response.json()["hydra:member"]
|
messages = response.json()["hydra:member"]
|
||||||
for message in messages:
|
for message in messages:
|
||||||
if message["from"]["address"] == "no-reply@cursor.sh" and "Verify your email address" in message["subject"]:
|
if message["from"]["address"] == "no-reply@cursor.sh" and "Verify your email address" in message["subject"]:
|
||||||
# 获取邮件内容
|
# Get email content
|
||||||
message_id = message["id"]
|
message_id = message["id"]
|
||||||
message_response = requests.get(f"{self.api_url}/messages/{message_id}", headers=headers)
|
message_response = requests.get(f"{self.api_url}/messages/{message_id}", headers=headers)
|
||||||
if message_response.status_code == 200:
|
if message_response.status_code == 200:
|
||||||
@@ -299,7 +299,7 @@ class NewTempEmail:
|
|||||||
def get_verification_code(self):
|
def get_verification_code(self):
|
||||||
"""get verification code"""
|
"""get verification code"""
|
||||||
try:
|
try:
|
||||||
# 使用 API 获取邮件列表
|
# Use API to get email list
|
||||||
headers = {"Authorization": f"Bearer {self.token}"}
|
headers = {"Authorization": f"Bearer {self.token}"}
|
||||||
response = requests.get(f"{self.api_url}/messages", headers=headers)
|
response = requests.get(f"{self.api_url}/messages", headers=headers)
|
||||||
|
|
||||||
@@ -307,14 +307,14 @@ class NewTempEmail:
|
|||||||
messages = response.json()["hydra:member"]
|
messages = response.json()["hydra:member"]
|
||||||
for message in messages:
|
for message in messages:
|
||||||
if message["from"]["address"] == "no-reply@cursor.sh" and "Verify your email address" in message["subject"]:
|
if message["from"]["address"] == "no-reply@cursor.sh" and "Verify your email address" in message["subject"]:
|
||||||
# 获取邮件内容
|
# Get email content
|
||||||
message_id = message["id"]
|
message_id = message["id"]
|
||||||
message_response = requests.get(f"{self.api_url}/messages/{message_id}", headers=headers)
|
message_response = requests.get(f"{self.api_url}/messages/{message_id}", headers=headers)
|
||||||
|
|
||||||
if message_response.status_code == 200:
|
if message_response.status_code == 200:
|
||||||
# 从邮件内容中提取验证码
|
# Extract verification code from email content
|
||||||
email_content = message_response.json()["text"]
|
email_content = message_response.json()["text"]
|
||||||
# 查找6位数字验证码
|
# Find 6-digit verification code
|
||||||
import re
|
import re
|
||||||
code_match = re.search(r'\b\d{6}\b', email_content)
|
code_match = re.search(r'\b\d{6}\b', email_content)
|
||||||
|
|
||||||
@@ -350,7 +350,7 @@ def main(translator=None):
|
|||||||
else:
|
else:
|
||||||
print(f"\n{Fore.CYAN}📧 临时邮箱地址: {email}{Style.RESET_ALL}")
|
print(f"\n{Fore.CYAN}📧 临时邮箱地址: {email}{Style.RESET_ALL}")
|
||||||
|
|
||||||
# 测试刷新功能
|
# Test refresh function
|
||||||
while True:
|
while True:
|
||||||
if translator:
|
if translator:
|
||||||
choice = input(f"\n{translator.get('email.refresh_prompt')}: ").lower()
|
choice = input(f"\n{translator.get('email.refresh_prompt')}: ").lower()
|
||||||
|
|||||||
@@ -10,6 +10,8 @@ import re
|
|||||||
import tempfile
|
import tempfile
|
||||||
from colorama import Fore, Style, init
|
from colorama import Fore, Style, init
|
||||||
from typing import Tuple
|
from typing import Tuple
|
||||||
|
import configparser
|
||||||
|
from new_signup import get_user_documents_path
|
||||||
|
|
||||||
# Initialize colorama
|
# Initialize colorama
|
||||||
init()
|
init()
|
||||||
@@ -70,15 +72,42 @@ def get_cursor_machine_id_path(translator=None) -> str:
|
|||||||
Returns:
|
Returns:
|
||||||
str: Path to machineId file
|
str: Path to machineId file
|
||||||
"""
|
"""
|
||||||
|
# Read configuration
|
||||||
|
config_dir = os.path.join(get_user_documents_path(), ".cursor-free-vip")
|
||||||
|
config_file = os.path.join(config_dir, "config.ini")
|
||||||
|
config = configparser.ConfigParser()
|
||||||
|
|
||||||
|
if os.path.exists(config_file):
|
||||||
|
config.read(config_file)
|
||||||
|
|
||||||
if sys.platform == "win32": # Windows
|
if sys.platform == "win32": # Windows
|
||||||
return os.path.join(os.getenv("APPDATA"), "Cursor", "machineId")
|
if not config.has_section('WindowsPaths'):
|
||||||
|
config.add_section('WindowsPaths')
|
||||||
|
config.set('WindowsPaths', 'machine_id_path',
|
||||||
|
os.path.join(os.getenv("APPDATA"), "Cursor", "machineId"))
|
||||||
|
return config.get('WindowsPaths', 'machine_id_path')
|
||||||
|
|
||||||
elif sys.platform == "linux": # Linux
|
elif sys.platform == "linux": # Linux
|
||||||
return os.path.expanduser("~/.config/Cursor/machineId")
|
if not config.has_section('LinuxPaths'):
|
||||||
|
config.add_section('LinuxPaths')
|
||||||
|
config.set('LinuxPaths', 'machine_id_path',
|
||||||
|
os.path.expanduser("~/.config/Cursor/machineId"))
|
||||||
|
return config.get('LinuxPaths', 'machine_id_path')
|
||||||
|
|
||||||
elif sys.platform == "darwin": # macOS
|
elif sys.platform == "darwin": # macOS
|
||||||
return os.path.expanduser("~/Library/Application Support/Cursor/machineId")
|
if not config.has_section('MacPaths'):
|
||||||
|
config.add_section('MacPaths')
|
||||||
|
config.set('MacPaths', 'machine_id_path',
|
||||||
|
os.path.expanduser("~/Library/Application Support/Cursor/machineId"))
|
||||||
|
return config.get('MacPaths', 'machine_id_path')
|
||||||
|
|
||||||
else:
|
else:
|
||||||
raise OSError(f"Unsupported operating system: {sys.platform}")
|
raise OSError(f"Unsupported operating system: {sys.platform}")
|
||||||
|
|
||||||
|
# Save any changes to config file
|
||||||
|
with open(config_file, 'w', encoding='utf-8') as f:
|
||||||
|
config.write(f)
|
||||||
|
|
||||||
def get_workbench_cursor_path(translator=None) -> str:
|
def get_workbench_cursor_path(translator=None) -> str:
|
||||||
"""Get Cursor workbench.desktop.main.js path"""
|
"""Get Cursor workbench.desktop.main.js path"""
|
||||||
system = platform.system()
|
system = platform.system()
|
||||||
@@ -171,9 +200,16 @@ def modify_workbench_js(file_path: str, translator=None) -> bool:
|
|||||||
with open(file_path, "r", encoding="utf-8", errors="ignore") as main_file:
|
with open(file_path, "r", encoding="utf-8", errors="ignore") as main_file:
|
||||||
content = main_file.read()
|
content = main_file.read()
|
||||||
|
|
||||||
# Define replacement patterns
|
if sys.platform == "win32":
|
||||||
CButton_old_pattern = r'$(k,E(Ks,{title:"Upgrade to Pro",size:"small",get codicon(){return F.rocket},get onClick(){return t.pay}}),null)'
|
# Define replacement patterns
|
||||||
CButton_new_pattern = r'$(k,E(Ks,{title:"yeongpin GitHub",size:"small",get codicon(){return F.rocket},get onClick(){return function(){window.open("https://github.com/yeongpin/cursor-free-vip","_blank")}}}),null)'
|
CButton_old_pattern = r'$(k,E(Ks,{title:"Upgrade to Pro",size:"small",get codicon(){return F.rocket},get onClick(){return t.pay}}),null)'
|
||||||
|
CButton_new_pattern = r'$(k,E(Ks,{title:"yeongpin GitHub",size:"small",get codicon(){return F.rocket},get onClick(){return function(){window.open("https://github.com/yeongpin/cursor-free-vip","_blank")}}}),null)'
|
||||||
|
elif sys.platform == "linux":
|
||||||
|
CButton_old_pattern = r'$(k,E(Ks,{title:"Upgrade to Pro",size:"small",get codicon(){return F.rocket},get onClick(){return t.pay}}),null)'
|
||||||
|
CButton_new_pattern = r'$(k,E(Ks,{title:"yeongpin GitHub",size:"small",get codicon(){return F.rocket},get onClick(){return function(){window.open("https://github.com/yeongpin/cursor-free-vip","_blank")}}}),null)'
|
||||||
|
elif sys.platform == "darwin":
|
||||||
|
CButton_old_pattern = r'M(x,I(as,{title:"Upgrade to Pro",size:"small",get codicon(){return $.rocket},get onClick(){return t.pay}}),null)'
|
||||||
|
CButton_new_pattern = r'M(x,I(as,{title:"yeongpin GitHub",size:"small",get codicon(){return $.rocket},get onClick(){return function(){window.open("https://github.com/yeongpin/cursor-free-vip","_blank")}}}),null)'
|
||||||
|
|
||||||
CBadge_old_pattern = r'<div>Pro Trial'
|
CBadge_old_pattern = r'<div>Pro Trial'
|
||||||
CBadge_new_pattern = r'<div>Pro'
|
CBadge_new_pattern = r'<div>Pro'
|
||||||
@@ -311,34 +347,73 @@ class MachineIDResetter:
|
|||||||
def __init__(self, translator=None):
|
def __init__(self, translator=None):
|
||||||
self.translator = translator
|
self.translator = translator
|
||||||
|
|
||||||
|
# Read configuration
|
||||||
|
config_dir = os.path.join(get_user_documents_path(), ".cursor-free-vip")
|
||||||
|
config_file = os.path.join(config_dir, "config.ini")
|
||||||
|
config = configparser.ConfigParser()
|
||||||
|
|
||||||
|
if not os.path.exists(config_file):
|
||||||
|
raise FileNotFoundError(f"Config file not found: {config_file}")
|
||||||
|
|
||||||
|
config.read(config_file)
|
||||||
|
|
||||||
# Check operating system
|
# Check operating system
|
||||||
if sys.platform == "win32": # Windows
|
if sys.platform == "win32": # Windows
|
||||||
appdata = os.getenv("APPDATA")
|
appdata = os.getenv("APPDATA")
|
||||||
if appdata is None:
|
if appdata is None:
|
||||||
raise EnvironmentError("APPDATA Environment Variable Not Set")
|
raise EnvironmentError("APPDATA Environment Variable Not Set")
|
||||||
self.db_path = os.path.join(
|
|
||||||
appdata, "Cursor", "User", "globalStorage", "storage.json"
|
if not config.has_section('WindowsPaths'):
|
||||||
)
|
config.add_section('WindowsPaths')
|
||||||
self.sqlite_path = os.path.join(
|
config.set('WindowsPaths', 'storage_path', os.path.join(
|
||||||
appdata, "Cursor", "User", "globalStorage", "state.vscdb"
|
appdata, "Cursor", "User", "globalStorage", "storage.json"
|
||||||
)
|
))
|
||||||
|
config.set('WindowsPaths', 'sqlite_path', os.path.join(
|
||||||
|
appdata, "Cursor", "User", "globalStorage", "state.vscdb"
|
||||||
|
))
|
||||||
|
|
||||||
|
self.db_path = config.get('WindowsPaths', 'storage_path')
|
||||||
|
self.sqlite_path = config.get('WindowsPaths', 'sqlite_path')
|
||||||
|
|
||||||
elif sys.platform == "darwin": # macOS
|
elif sys.platform == "darwin": # macOS
|
||||||
self.db_path = os.path.abspath(os.path.expanduser(
|
if not config.has_section('MacPaths'):
|
||||||
"~/Library/Application Support/Cursor/User/globalStorage/storage.json"
|
config.add_section('MacPaths')
|
||||||
))
|
config.set('MacPaths', 'storage_path', os.path.abspath(os.path.expanduser(
|
||||||
self.sqlite_path = os.path.abspath(os.path.expanduser(
|
"~/Library/Application Support/Cursor/User/globalStorage/storage.json"
|
||||||
"~/Library/Application Support/Cursor/User/globalStorage/state.vscdb"
|
)))
|
||||||
))
|
config.set('MacPaths', 'sqlite_path', os.path.abspath(os.path.expanduser(
|
||||||
|
"~/Library/Application Support/Cursor/User/globalStorage/state.vscdb"
|
||||||
|
)))
|
||||||
|
|
||||||
|
self.db_path = config.get('MacPaths', 'storage_path')
|
||||||
|
self.sqlite_path = config.get('MacPaths', 'sqlite_path')
|
||||||
|
|
||||||
elif sys.platform == "linux": # Linux
|
elif sys.platform == "linux": # Linux
|
||||||
self.db_path = os.path.abspath(os.path.expanduser(
|
if not config.has_section('LinuxPaths'):
|
||||||
"~/.config/Cursor/User/globalStorage/storage.json"
|
config.add_section('LinuxPaths')
|
||||||
))
|
# 获取实际用户的主目录
|
||||||
self.sqlite_path = os.path.abspath(os.path.expanduser(
|
sudo_user = os.environ.get('SUDO_USER')
|
||||||
"~/.config/Cursor/User/globalStorage/state.vscdb"
|
actual_home = f"/home/{sudo_user}" if sudo_user else os.path.expanduser("~")
|
||||||
))
|
|
||||||
|
config.set('LinuxPaths', 'storage_path', os.path.abspath(os.path.join(
|
||||||
|
actual_home,
|
||||||
|
".config/Cursor/User/globalStorage/storage.json"
|
||||||
|
)))
|
||||||
|
config.set('LinuxPaths', 'sqlite_path', os.path.abspath(os.path.join(
|
||||||
|
actual_home,
|
||||||
|
".config/Cursor/User/globalStorage/state.vscdb"
|
||||||
|
)))
|
||||||
|
|
||||||
|
self.db_path = config.get('LinuxPaths', 'storage_path')
|
||||||
|
self.sqlite_path = config.get('LinuxPaths', 'sqlite_path')
|
||||||
|
|
||||||
else:
|
else:
|
||||||
raise NotImplementedError(f"Not Supported OS: {sys.platform}")
|
raise NotImplementedError(f"Not Supported OS: {sys.platform}")
|
||||||
|
|
||||||
|
# Save any changes to config file
|
||||||
|
with open(config_file, 'w', encoding='utf-8') as f:
|
||||||
|
config.write(f)
|
||||||
|
|
||||||
def generate_new_ids(self):
|
def generate_new_ids(self):
|
||||||
"""Generate new machine ID"""
|
"""Generate new machine ID"""
|
||||||
# Generate new UUID
|
# Generate new UUID
|
||||||
@@ -491,17 +566,22 @@ class MachineIDResetter:
|
|||||||
# Update system IDs
|
# Update system IDs
|
||||||
self.update_system_ids(new_ids)
|
self.update_system_ids(new_ids)
|
||||||
|
|
||||||
# Modify workbench.desktop.main.js
|
|
||||||
workbench_path = get_workbench_cursor_path(self.translator)
|
|
||||||
modify_workbench_js(workbench_path, self.translator)
|
|
||||||
|
|
||||||
|
### Remove In v1.7.02
|
||||||
|
# Modify workbench.desktop.main.js
|
||||||
|
|
||||||
|
# workbench_path = get_workbench_cursor_path(self.translator)
|
||||||
|
# modify_workbench_js(workbench_path, self.translator)
|
||||||
|
|
||||||
|
### Remove In v1.7.02
|
||||||
# Check Cursor version and perform corresponding actions
|
# Check Cursor version and perform corresponding actions
|
||||||
greater_than_0_45 = check_cursor_version(self.translator)
|
|
||||||
if greater_than_0_45:
|
# greater_than_0_45 = check_cursor_version(self.translator)
|
||||||
print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('reset.detecting_version')} >= 0.45.0,{self.translator.get('reset.patching_getmachineid')}{Style.RESET_ALL}")
|
# if greater_than_0_45:
|
||||||
patch_cursor_get_machine_id(self.translator)
|
# print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('reset.detecting_version')} >= 0.45.0,{self.translator.get('reset.patching_getmachineid')}{Style.RESET_ALL}")
|
||||||
else:
|
# patch_cursor_get_machine_id(self.translator)
|
||||||
print(f"{Fore.YELLOW}{EMOJI['INFO']} {self.translator.get('reset.version_less_than_0_45')}{Style.RESET_ALL}")
|
# else:
|
||||||
|
# print(f"{Fore.YELLOW}{EMOJI['INFO']} {self.translator.get('reset.version_less_than_0_45')}{Style.RESET_ALL}")
|
||||||
|
|
||||||
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('reset.success')}{Style.RESET_ALL}")
|
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('reset.success')}{Style.RESET_ALL}")
|
||||||
print(f"\n{Fore.CYAN}{self.translator.get('reset.new_id')}:{Style.RESET_ALL}")
|
print(f"\n{Fore.CYAN}{self.translator.get('reset.new_id')}:{Style.RESET_ALL}")
|
||||||
|
|||||||
Reference in New Issue
Block a user