mirror of
https://git.axenov.dev/mirrors/cursor-free-vip.git
synced 2025-12-26 05:30:36 +03:00
Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ffd48201fd | ||
|
|
cd4f36725c | ||
|
|
dccb524bd7 | ||
|
|
90e9a5b287 | ||
|
|
66a67fce8b | ||
|
|
0981f00b9c |
2
.github/workflows/build.yml
vendored
2
.github/workflows/build.yml
vendored
@@ -6,7 +6,7 @@ on:
|
||||
version:
|
||||
description: 'Version number (e.g. 1.0.9)'
|
||||
required: true
|
||||
default: '1.5.03'
|
||||
default: '1.7.03'
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
@@ -1,5 +1,14 @@
|
||||
# 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
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
[](https://github.com/yeongpin/cursor-free-vip/releases/latest)
|
||||
|
||||
</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.
|
||||
|
||||
@@ -99,6 +99,11 @@ chromepath = C:\Program Files\Google/Chrome/Application/chrome.exe
|
||||
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>請使用管理員身份運行腳本
|
||||
|
||||
@@ -160,7 +160,7 @@ class CursorRegistration:
|
||||
if usage_ele:
|
||||
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}")
|
||||
max_attempts = 30
|
||||
retry_interval = 2
|
||||
|
||||
@@ -68,7 +68,11 @@
|
||||
"version_less_than_0_45": "Cursor Version < 0.45.0, Skip Patching getMachineId",
|
||||
"detecting_version": "Detecting Cursor Version",
|
||||
"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": {
|
||||
"title": "Cursor Registration Tool",
|
||||
@@ -141,7 +145,9 @@
|
||||
"verification_failed": "Verification Failed",
|
||||
"verification_error": "Verification Error: {error}",
|
||||
"config_option_added": "Config Option Added: {option}",
|
||||
"config_updated": "Config Updated"
|
||||
"config_updated": "Config Updated",
|
||||
"password_submitted": "Password Submitted",
|
||||
"total_usage": "Total Usage: {usage}"
|
||||
},
|
||||
"auth": {
|
||||
"title": "Cursor Auth Manager",
|
||||
|
||||
@@ -68,7 +68,11 @@
|
||||
"version_less_than_0_45": "Cursor版本 < 0.45.0,跳过getMachineId修补",
|
||||
"detecting_version": "检测Cursor版本",
|
||||
"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": {
|
||||
"title": "Cursor 注册工具",
|
||||
@@ -141,7 +145,9 @@
|
||||
"verification_failed": "验证失败",
|
||||
"verification_error": "验证错误: {error}",
|
||||
"config_option_added": "配置项已添加: {option}",
|
||||
"config_updated": "配置已更新"
|
||||
"config_updated": "配置已更新",
|
||||
"password_submitted": "密码已提交",
|
||||
"total_usage": "总使用量: {usage}"
|
||||
},
|
||||
"auth": {
|
||||
"title": "Cursor 认证管理器",
|
||||
|
||||
@@ -68,7 +68,11 @@
|
||||
"version_less_than_0_45": "Cursor版本 < 0.45.0,跳过getMachineId修补",
|
||||
"detecting_version": "檢測Cursor版本",
|
||||
"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": {
|
||||
"title": "Cursor 註冊工具",
|
||||
@@ -122,7 +126,9 @@
|
||||
"verification_failed": "驗證失敗",
|
||||
"verification_error": "驗證錯誤: {error}",
|
||||
"config_option_added": "配置項已添加: {option}",
|
||||
"config_updated": "配置已更新"
|
||||
"config_updated": "配置已更新",
|
||||
"password_submitted": "密碼已提交",
|
||||
"total_usage": "總使用量: {usage}"
|
||||
},
|
||||
"auth": {
|
||||
"title": "Cursor 認證管理器",
|
||||
|
||||
227
new_signup.py
227
new_signup.py
@@ -37,22 +37,20 @@ def signal_handler(signum, frame):
|
||||
cleanup_chrome_processes(_translator)
|
||||
os._exit(0)
|
||||
|
||||
def simulate_human_input(page, url, translator=None):
|
||||
def simulate_human_input(page, url, config, translator=None):
|
||||
"""访问网址"""
|
||||
if translator:
|
||||
print(f"{Fore.CYAN}🚀 {translator.get('register.visiting_url')}: {url}{Style.RESET_ALL}")
|
||||
else:
|
||||
print("正在访问网址...")
|
||||
|
||||
# 先访问空白页面
|
||||
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)
|
||||
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:
|
||||
if translator:
|
||||
@@ -64,25 +62,25 @@ def fill_signup_form(page, first_name, last_name, email, translator=None):
|
||||
first_name_input = page.ele("@name=first_name")
|
||||
if first_name_input:
|
||||
first_name_input.input(first_name)
|
||||
time.sleep(random.uniform(0.5, 1.0))
|
||||
time.sleep(get_random_wait_time(config, 'input_wait'))
|
||||
|
||||
# 填写姓氏
|
||||
last_name_input = page.ele("@name=last_name")
|
||||
if last_name_input:
|
||||
last_name_input.input(last_name)
|
||||
time.sleep(random.uniform(0.5, 1.0))
|
||||
time.sleep(get_random_wait_time(config, 'input_wait'))
|
||||
|
||||
# 填写邮箱
|
||||
email_input = page.ele("@name=email")
|
||||
if email_input:
|
||||
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")
|
||||
if submit_button:
|
||||
submit_button.click()
|
||||
time.sleep(random.uniform(2.0, 3.0))
|
||||
time.sleep(get_random_wait_time(config, 'submit_wait'))
|
||||
|
||||
if translator:
|
||||
print(f"{Fore.GREEN}✅ {translator.get('register.form_success')}{Style.RESET_ALL}")
|
||||
@@ -133,18 +131,35 @@ def get_user_documents_path():
|
||||
return os.path.join("/home", sudo_user, "Documents")
|
||||
return os.path.join(os.path.expanduser("~"), "Documents")
|
||||
|
||||
def parse_random_time(time_str):
|
||||
"""解析随机时间范围配置"""
|
||||
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:
|
||||
if '-' in time_str:
|
||||
min_time, max_time = map(float, time_str.split('-'))
|
||||
elif ',' in time_str:
|
||||
min_time, max_time = map(float, time_str.split(','))
|
||||
else:
|
||||
min_time = max_time = float(time_str)
|
||||
return min_time, max_time
|
||||
if not config.has_section('Timing'):
|
||||
return random.uniform(0.1, 0.8) # 默认值
|
||||
|
||||
if timing_type == 'random':
|
||||
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 1, 3 # 默认值
|
||||
return random.uniform(0.1, 0.8) # 出错时返回默认值
|
||||
|
||||
def setup_config(translator=None):
|
||||
"""Setup configuration file and return config object"""
|
||||
@@ -167,9 +182,48 @@ def setup_config(translator=None):
|
||||
'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
|
||||
@@ -282,7 +336,12 @@ def handle_turnstile(page, config, translator=None):
|
||||
# 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)
|
||||
|
||||
# 解析随机时间范围
|
||||
try:
|
||||
min_time, max_time = map(float, random_time_str.split('-'))
|
||||
except:
|
||||
min_time, max_time = 1, 3 # 默认值
|
||||
|
||||
max_retries = 2
|
||||
retry_count = 0
|
||||
@@ -315,7 +374,7 @@ def handle_turnstile(page, config, translator=None):
|
||||
print("检测到验证框...")
|
||||
|
||||
# from config
|
||||
time.sleep(random.uniform(min_random_time, max_random_time))
|
||||
time.sleep(random.uniform(min_time, max_time))
|
||||
challenge_check.click()
|
||||
time.sleep(turnstile_time) # from config
|
||||
|
||||
@@ -341,7 +400,7 @@ def handle_turnstile(page, config, translator=None):
|
||||
print("验证通过!")
|
||||
return True
|
||||
|
||||
time.sleep(random.uniform(min_random_time, max_random_time))
|
||||
time.sleep(random.uniform(min_time, max_time))
|
||||
|
||||
if translator:
|
||||
print(f"{Fore.RED}❌ {translator.get('register.verification_failed')}{Style.RESET_ALL}")
|
||||
@@ -386,54 +445,53 @@ def generate_password(length=12):
|
||||
chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*"
|
||||
return ''.join(random.choices(chars, k=length))
|
||||
|
||||
def fill_password(page, password: str, translator=None) -> bool:
|
||||
def fill_password(page, password: str, config, translator=None) -> bool:
|
||||
"""
|
||||
填写密码表单
|
||||
"""
|
||||
try:
|
||||
print(f"{Fore.CYAN}🔑 {translator.get('register.setting_password') if translator else '设置密码'}{Style.RESET_ALL}")
|
||||
|
||||
# 等待密码框出现
|
||||
# 等待密码框出现并尝试多次
|
||||
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:
|
||||
submit_button.click()
|
||||
time.sleep(2)
|
||||
return True
|
||||
else:
|
||||
print(f"{Fore.RED}❌ {translator.get('register.continue_button_not_found') if translator else '未找到继续按钮'}{Style.RESET_ALL}")
|
||||
# 检查是否出现错误信息
|
||||
if page.ele("This email is not available."):
|
||||
print(f"{Fore.RED}❌ {translator.get('register.email_used') if translator else '注册失败:邮箱已被使用'}{Style.RESET_ALL}")
|
||||
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:
|
||||
print(f"{Fore.RED}❌ {translator.get('register.password_setting_error', error=str(e)) if translator else f'设置密码时出错: {str(e)}'}{Style.RESET_ALL}")
|
||||
# 查找密码输入框
|
||||
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}")
|
||||
|
||||
# 如果没找到密码框,等待后重试
|
||||
time.sleep(get_random_wait_time(config, 'failed_retry_time'))
|
||||
if i < max_retries - 1: # 不是最后一次尝试时才打印
|
||||
print(f"{Fore.YELLOW}⚠️ {translator.get('register.retry_password', attempt=i+1) if translator else f'第 {i+1} 次尝试设置密码...'}{Style.RESET_ALL}")
|
||||
|
||||
print(f"{Fore.RED}❌ {translator.get('register.password_set_failed') if translator else '密码设置失败:超过重试次数'}{Style.RESET_ALL}")
|
||||
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:
|
||||
if translator:
|
||||
@@ -446,21 +504,21 @@ def handle_verification_code(browser_tab, email_tab, controller, email, password
|
||||
# 在注册页面填写验证码
|
||||
for i, digit in enumerate(verification_code):
|
||||
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')}")
|
||||
time.sleep(3)
|
||||
time.sleep(get_random_wait_time(config, 'verification_success_wait'))
|
||||
|
||||
# 处理最后一次 Turnstile 验证
|
||||
if handle_turnstile(browser_tab, translator):
|
||||
if handle_turnstile(browser_tab, config, translator):
|
||||
if translator:
|
||||
print(f"{Fore.GREEN}✅ {translator.get('register.verification_success')}{Style.RESET_ALL}")
|
||||
time.sleep(2)
|
||||
time.sleep(get_random_wait_time(config, 'verification_retry_wait'))
|
||||
|
||||
# 访问设置页面
|
||||
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")
|
||||
time.sleep(3) # 等待页面加载
|
||||
time.sleep(get_random_wait_time(config, 'settings_page_load_wait'))
|
||||
return True, browser_tab
|
||||
|
||||
return False, None
|
||||
@@ -468,11 +526,11 @@ def handle_verification_code(browser_tab, email_tab, controller, email, password
|
||||
# 自动获取验证码逻辑
|
||||
elif email_tab:
|
||||
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.refresh_inbox()
|
||||
time.sleep(3)
|
||||
time.sleep(get_random_wait_time(config, 'email_refresh_wait'))
|
||||
|
||||
# 检查邮箱是否有验证码邮件
|
||||
if email_tab.check_for_cursor_email():
|
||||
@@ -481,22 +539,23 @@ def handle_verification_code(browser_tab, email_tab, controller, email, password
|
||||
# 在注册页面填写验证码
|
||||
for i, digit in enumerate(verification_code):
|
||||
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:
|
||||
print(f"{Fore.GREEN}✅ {translator.get('register.verification_success')}{Style.RESET_ALL}")
|
||||
time.sleep(3)
|
||||
time.sleep(get_random_wait_time(config, 'verification_success_wait'))
|
||||
|
||||
# 处理最后一次 Turnstile 验证
|
||||
if handle_turnstile(browser_tab, translator):
|
||||
if handle_turnstile(browser_tab, config, translator):
|
||||
if translator:
|
||||
print(f"{Fore.GREEN}✅ {translator.get('register.verification_success')}{Style.RESET_ALL}")
|
||||
time.sleep(2)
|
||||
time.sleep(get_random_wait_time(config, 'verification_retry_wait'))
|
||||
|
||||
# 访问设置页面
|
||||
if translator:
|
||||
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")
|
||||
time.sleep(3) # 等待页面加载
|
||||
time.sleep(get_random_wait_time(config, 'settings_page_load_wait'))
|
||||
return True, browser_tab
|
||||
|
||||
else:
|
||||
@@ -509,9 +568,9 @@ def handle_verification_code(browser_tab, email_tab, controller, email, password
|
||||
# 获取验证码,设置超时
|
||||
verification_code = None
|
||||
max_attempts = 20
|
||||
retry_interval = 10
|
||||
retry_interval = float(config.get('Timing', 'retry_interval', fallback='10')) # 使用配置值
|
||||
start_time = time.time()
|
||||
timeout = 160
|
||||
timeout = float(config.get('Timing', 'max_timeout', fallback='160')) # 使用配置值
|
||||
|
||||
if translator:
|
||||
print(f"{Fore.CYAN}{translator.get('register.start_getting_verification_code')}{Style.RESET_ALL}")
|
||||
@@ -535,29 +594,29 @@ def handle_verification_code(browser_tab, email_tab, controller, email, password
|
||||
|
||||
# 刷新邮箱
|
||||
email_tab.refresh_inbox()
|
||||
time.sleep(retry_interval)
|
||||
time.sleep(get_random_wait_time(config, 'retry_interval')) # 使用 get_random_wait_time
|
||||
|
||||
if verification_code:
|
||||
# 在注册页面填写验证码
|
||||
for i, digit in enumerate(verification_code):
|
||||
browser_tab.ele(f"@data-index={i}").input(digit)
|
||||
time.sleep(random.uniform(0.1, 0.3))
|
||||
time.sleep(get_random_wait_time(config, 'verification_code_input'))
|
||||
|
||||
if translator:
|
||||
print(f"{Fore.GREEN}✅ {translator.get('register.verification_success')}{Style.RESET_ALL}")
|
||||
time.sleep(3)
|
||||
time.sleep(get_random_wait_time(config, 'verification_success_wait'))
|
||||
|
||||
# 处理最后一次 Turnstile 验证
|
||||
if handle_turnstile(browser_tab, translator):
|
||||
if handle_turnstile(browser_tab, config, translator):
|
||||
if translator:
|
||||
print(f"{Fore.GREEN}✅ {translator.get('register.verification_success')}{Style.RESET_ALL}")
|
||||
time.sleep(2)
|
||||
time.sleep(get_random_wait_time(config, 'verification_retry_wait'))
|
||||
|
||||
# 直接访问设置页面
|
||||
if translator:
|
||||
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")
|
||||
time.sleep(3) # 等待页面加载
|
||||
time.sleep(get_random_wait_time(config, 'settings_page_load_wait'))
|
||||
|
||||
# 直接返回成功,让 cursor_register.py 处理账户信息获取
|
||||
return True, browser_tab
|
||||
@@ -644,10 +703,10 @@ def main(email=None, password=None, first_name=None, last_name=None, email_tab=N
|
||||
print(f"\n{Fore.CYAN}{translator.get('register.visiting_url')}: {url}{Style.RESET_ALL}")
|
||||
|
||||
# 访问页面
|
||||
simulate_human_input(page, url, translator)
|
||||
simulate_human_input(page, url, config, translator)
|
||||
if translator:
|
||||
print(f"{Fore.CYAN}{translator.get('register.waiting_for_page_load')}{Style.RESET_ALL}")
|
||||
time.sleep(5)
|
||||
time.sleep(get_random_wait_time(config, 'page_load_wait'))
|
||||
|
||||
# 如果没有提供账号信息,则生成随机信息
|
||||
if not all([email, password, first_name, last_name]):
|
||||
@@ -664,7 +723,7 @@ def main(email=None, password=None, first_name=None, last_name=None, email_tab=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:
|
||||
print(f"\n{Fore.GREEN}{translator.get('register.form_submitted')}{Style.RESET_ALL}")
|
||||
|
||||
@@ -674,7 +733,7 @@ def main(email=None, password=None, first_name=None, last_name=None, email_tab=N
|
||||
print(f"\n{Fore.GREEN}{translator.get('register.first_verification_passed')}{Style.RESET_ALL}")
|
||||
|
||||
# 填写密码
|
||||
if fill_password(page, password, translator):
|
||||
if fill_password(page, password, config, translator):
|
||||
if translator:
|
||||
print(f"\n{Fore.CYAN}{translator.get('register.waiting_for_second_verification')}{Style.RESET_ALL}")
|
||||
time.sleep(2)
|
||||
@@ -683,9 +742,9 @@ def main(email=None, password=None, first_name=None, last_name=None, email_tab=N
|
||||
if handle_turnstile(page, config, translator):
|
||||
if translator:
|
||||
print(f"\n{Fore.CYAN}{translator.get('register.waiting_for_verification_code')}{Style.RESET_ALL}")
|
||||
if handle_verification_code(page, email_tab, controller, email, password, translator):
|
||||
if handle_verification_code(page, email_tab, controller, email, password, config, translator):
|
||||
success = True
|
||||
return True, page # 返回浏览器实例
|
||||
return True, page
|
||||
else:
|
||||
print(f"\n{Fore.RED} {translator.get('register.verification_code_processing_failed') if translator else '验证码处理失败'}{Style.RESET_ALL}")
|
||||
else:
|
||||
|
||||
@@ -10,6 +10,8 @@ import re
|
||||
import tempfile
|
||||
from colorama import Fore, Style, init
|
||||
from typing import Tuple
|
||||
import configparser
|
||||
from new_signup import get_user_documents_path
|
||||
|
||||
# Initialize colorama
|
||||
init()
|
||||
@@ -70,15 +72,42 @@ def get_cursor_machine_id_path(translator=None) -> str:
|
||||
Returns:
|
||||
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
|
||||
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
|
||||
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
|
||||
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:
|
||||
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:
|
||||
"""Get Cursor workbench.desktop.main.js path"""
|
||||
system = platform.system()
|
||||
@@ -318,43 +347,73 @@ class MachineIDResetter:
|
||||
def __init__(self, translator=None):
|
||||
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
|
||||
if sys.platform == "win32": # Windows
|
||||
appdata = os.getenv("APPDATA")
|
||||
if appdata is None:
|
||||
raise EnvironmentError("APPDATA Environment Variable Not Set")
|
||||
self.db_path = os.path.join(
|
||||
appdata, "Cursor", "User", "globalStorage", "storage.json"
|
||||
)
|
||||
self.sqlite_path = os.path.join(
|
||||
appdata, "Cursor", "User", "globalStorage", "state.vscdb"
|
||||
)
|
||||
elif sys.platform == "darwin": # macOS
|
||||
self.db_path = os.path.abspath(os.path.expanduser(
|
||||
"~/Library/Application Support/Cursor/User/globalStorage/storage.json"
|
||||
))
|
||||
self.sqlite_path = os.path.abspath(os.path.expanduser(
|
||||
"~/Library/Application Support/Cursor/User/globalStorage/state.vscdb"
|
||||
))
|
||||
elif sys.platform == "linux": # Linux
|
||||
# 获取实际用户的主目录
|
||||
sudo_user = os.environ.get('SUDO_USER')
|
||||
if sudo_user:
|
||||
actual_home = f"/home/{sudo_user}"
|
||||
else:
|
||||
actual_home = os.path.expanduser("~")
|
||||
|
||||
if not config.has_section('WindowsPaths'):
|
||||
config.add_section('WindowsPaths')
|
||||
config.set('WindowsPaths', 'storage_path', os.path.join(
|
||||
appdata, "Cursor", "User", "globalStorage", "storage.json"
|
||||
))
|
||||
config.set('WindowsPaths', 'sqlite_path', os.path.join(
|
||||
appdata, "Cursor", "User", "globalStorage", "state.vscdb"
|
||||
))
|
||||
|
||||
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.join(
|
||||
actual_home,
|
||||
".config/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
|
||||
if not config.has_section('MacPaths'):
|
||||
config.add_section('MacPaths')
|
||||
config.set('MacPaths', 'storage_path', os.path.abspath(os.path.expanduser(
|
||||
"~/Library/Application Support/Cursor/User/globalStorage/storage.json"
|
||||
)))
|
||||
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
|
||||
if not config.has_section('LinuxPaths'):
|
||||
config.add_section('LinuxPaths')
|
||||
# 获取实际用户的主目录
|
||||
sudo_user = os.environ.get('SUDO_USER')
|
||||
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:
|
||||
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):
|
||||
"""Generate new machine ID"""
|
||||
# Generate new UUID
|
||||
@@ -507,17 +566,22 @@ class MachineIDResetter:
|
||||
# Update system 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
|
||||
greater_than_0_45 = check_cursor_version(self.translator)
|
||||
if greater_than_0_45:
|
||||
print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('reset.detecting_version')} >= 0.45.0,{self.translator.get('reset.patching_getmachineid')}{Style.RESET_ALL}")
|
||||
patch_cursor_get_machine_id(self.translator)
|
||||
else:
|
||||
print(f"{Fore.YELLOW}{EMOJI['INFO']} {self.translator.get('reset.version_less_than_0_45')}{Style.RESET_ALL}")
|
||||
|
||||
# greater_than_0_45 = check_cursor_version(self.translator)
|
||||
# if greater_than_0_45:
|
||||
# print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('reset.detecting_version')} >= 0.45.0,{self.translator.get('reset.patching_getmachineid')}{Style.RESET_ALL}")
|
||||
# patch_cursor_get_machine_id(self.translator)
|
||||
# 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"\n{Fore.CYAN}{self.translator.get('reset.new_id')}:{Style.RESET_ALL}")
|
||||
|
||||
Reference in New Issue
Block a user