feat: Implement Configuration Management and Enhance Browser Setup

- Add `setup_config` function to manage configuration file across platforms
- Extract configuration-related code from `setup_driver` into a separate function
- Implement dynamic Chrome path detection for Windows, macOS, and Linux
- Add configurable Turnstile verification settings
- Update README.md with configuration file details
- Enhance localization support for configuration-related messages
- Improve code maintainability and platform compatibility
This commit is contained in:
yeongpin 2025-03-07 11:18:43 +08:00
parent 6312d66813
commit 02851c9a09
9 changed files with 322 additions and 150 deletions

4
.env
View File

@ -1,2 +1,2 @@
version=1.6.03 version=1.7.01
VERSION=1.6.03 VERSION=1.7.01

View File

@ -1,5 +1,10 @@
# Change Log # Change Log
## 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 | 修復一些問題

View File

@ -86,6 +86,21 @@ 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
```
* 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 +113,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 |

View File

@ -136,7 +136,12 @@
"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"
}, },
"auth": { "auth": {
"title": "Cursor Auth Manager", "title": "Cursor Auth Manager",

View File

@ -136,7 +136,12 @@
"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": "配置已更新"
}, },
"auth": { "auth": {
"title": "Cursor 认证管理器", "title": "Cursor 认证管理器",

View File

@ -117,7 +117,12 @@
"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": "配置已更新"
}, },
"auth": { "auth": {
"title": "Cursor 認證管理器", "title": "Cursor 認證管理器",

View File

@ -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
@ -94,43 +97,181 @@ 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'),
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("--incognito") if os.path.exists(path):
return path
return ""
# 设置随机端口 def get_user_documents_path():
co.set_argument("--no-sandbox") """Get user Documents folder path"""
if sys.platform == "win32":
# 设置随机端口 return os.path.join(os.path.expanduser("~"), "Documents")
co.auto_port() elif sys.platform == "darwin":
return os.path.join(os.path.expanduser("~"), "Documents")
# 使用有头模式(一定要设置为False模擬人類操作) else: # Linux
co.headless(False) # 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 parse_random_time(time_str):
"""解析随机时间范围配置"""
try: try:
# 加载插件 if '-' in time_str:
extension_path = os.path.join(os.getcwd(), "turnstilePatch") min_time, max_time = map(float, time_str.split('-'))
if os.path.exists(extension_path): elif ',' in time_str:
co.set_argument("--allow-extensions-in-incognito") min_time, max_time = map(float, time_str.split(','))
co.add_extension(extension_path) else:
min_time = max_time = float(time_str)
return min_time, max_time
except:
return 1, 3 # 默认值
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'
}
}
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}")
raise
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: else:
print(f"加载插件失败: {e}") print("正在启动浏览器...")
if translator: page = ChromiumPage(co)
print(f"{Fore.CYAN}🚀 {translator.get('register.starting_browser')}{Style.RESET_ALL}") return config, page
else:
print("正在启动浏览器...")
page = ChromiumPage(co)
return 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, translator=None): def handle_turnstile(page, config, translator=None):
"""处理 Turnstile 验证""" """处理 Turnstile 验证"""
try: try:
if translator: if translator:
@ -138,6 +279,11 @@ 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')
min_random_time, max_random_time = parse_random_time(random_time_str)
max_retries = 2 max_retries = 2
retry_count = 0 retry_count = 0
@ -151,7 +297,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 +314,12 @@ def handle_turnstile(page, translator=None):
else: else:
print("检测到验证框...") print("检测到验证框...")
# 随机延时后点击验证 # from config
time.sleep(random.uniform(1, 3)) time.sleep(random.uniform(min_random_time, max_random_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 +341,7 @@ def handle_turnstile(page, translator=None):
print("验证通过!") print("验证通过!")
return True return True
time.sleep(random.uniform(1, 2)) time.sleep(random.uniform(min_random_time, max_random_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,34 +386,51 @@ 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, 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')}")
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") # 等待密码框出现
max_retries = 5
for i in range(max_retries):
try:
# 使用 DrissionPage 的方式查找密码输入框
password_input = page.ele('@type=password', timeout=3)
if password_input:
break
time.sleep(2)
except:
if i == max_retries - 1:
print(f"{Fore.RED}{translator.get('register.password_field_not_found') if translator else '未找到密码输入框'}{Style.RESET_ALL}")
return False
continue
if password_input:
# 清除可能存在的旧值
password_input.click()
time.sleep(0.5)
password_input.input(password)
time.sleep(1)
# 查找并点击提交按钮
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(2)
return True
if translator:
print(f"{Fore.GREEN}{translator.get('register.password_success')}{Style.RESET_ALL}")
else: else:
print(f"{translator.get('register.password_success')}: {password}") print(f"{Fore.RED}{translator.get('register.continue_button_not_found') if translator else '未找到继续按钮'}{Style.RESET_ALL}")
return True return False
else:
print(f"{Fore.RED}{translator.get('register.password_input_failed') if translator else '密码输入失败'}{Style.RESET_ALL}")
return False
except Exception as e: except Exception as e:
if translator: print(f"{Fore.RED}{translator.get('register.password_setting_error', error=str(e)) if translator else f'设置密码时出错: {str(e)}'}{Style.RESET_ALL}")
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): def handle_verification_code(browser_tab, email_tab, controller, email, password, translator=None):
@ -275,8 +438,6 @@ def handle_verification_code(browser_tab, email_tab, controller, email, password
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: # 手动模式
@ -293,13 +454,11 @@ def handle_verification_code(browser_tab, email_tab, controller, email, password
# 处理最后一次 Turnstile 验证 # 处理最后一次 Turnstile 验证
if handle_turnstile(browser_tab, translator): if handle_turnstile(browser_tab, 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:
print(f"{translator.get('register.verification_success')}")
time.sleep(2) 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(3) # 等待页面加载
return True, browser_tab return True, browser_tab
@ -325,23 +484,17 @@ def handle_verification_code(browser_tab, email_tab, controller, email, password
time.sleep(random.uniform(0.1, 0.3)) time.sleep(random.uniform(0.1, 0.3))
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("验证码填写完成")
time.sleep(3) time.sleep(3)
# 处理最后一次 Turnstile 验证 # 处理最后一次 Turnstile 验证
if handle_turnstile(browser_tab, translator): if handle_turnstile(browser_tab, 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:
print("最后一次验证通过!")
time.sleep(2) 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(3) # 等待页面加载
return True, browser_tab return True, browser_tab
@ -362,31 +515,23 @@ def handle_verification_code(browser_tab, email_tab, controller, email, password
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()
@ -400,23 +545,17 @@ def handle_verification_code(browser_tab, email_tab, controller, email, password
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("验证码填写完成")
time.sleep(3) time.sleep(3)
# 处理最后一次 Turnstile 验证 # 处理最后一次 Turnstile 验证
if handle_turnstile(browser_tab, translator): if handle_turnstile(browser_tab, 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:
print("最后一次验证通过!")
time.sleep(2) 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(3) # 等待页面加载
@ -426,8 +565,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 +572,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,25 +634,19 @@ 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, 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:
print("等待页面加载...")
time.sleep(5) time.sleep(5)
# 如果没有提供账号信息,则生成随机信息 # 如果没有提供账号信息,则生成随机信息
@ -538,41 +667,33 @@ def main(email=None, password=None, first_name=None, last_name=None, email_tab=N
if fill_signup_form(page, first_name, last_name, email, translator): if fill_signup_form(page, first_name, last_name, email, 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, 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:
print("\n开始处理验证码...")
if handle_verification_code(page, email_tab, controller, email, password, translator): 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

View File

@ -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()

View File

@ -171,9 +171,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'
@ -330,11 +337,20 @@ class MachineIDResetter:
"~/Library/Application Support/Cursor/User/globalStorage/state.vscdb" "~/Library/Application Support/Cursor/User/globalStorage/state.vscdb"
)) ))
elif sys.platform == "linux": # Linux elif sys.platform == "linux": # Linux
self.db_path = os.path.abspath(os.path.expanduser( # 获取实际用户的主目录
"~/.config/Cursor/User/globalStorage/storage.json" sudo_user = os.environ.get('SUDO_USER')
if sudo_user:
actual_home = f"/home/{sudo_user}"
else:
actual_home = os.path.expanduser("~")
self.db_path = os.path.abspath(os.path.join(
actual_home,
".config/Cursor/User/globalStorage/storage.json"
)) ))
self.sqlite_path = os.path.abspath(os.path.expanduser( self.sqlite_path = os.path.abspath(os.path.join(
"~/.config/Cursor/User/globalStorage/state.vscdb" actual_home,
".config/Cursor/User/globalStorage/state.vscdb"
)) ))
else: else:
raise NotImplementedError(f"Not Supported OS: {sys.platform}") raise NotImplementedError(f"Not Supported OS: {sys.platform}")