Compare commits

...

13 Commits

Author SHA1 Message Date
yeongpin
6ac1294bee Add Disable Cursor Auto Update Feature 2025-02-24 11:18:57 +08:00
Pin Studios
fb443592d3 Update README.md 2025-02-21 18:02:22 +08:00
Pin Studios
c30a62b072 Update README.md 2025-02-17 16:30:55 +08:00
Pin Studios
8bc509cccf Update README.md 2025-02-17 16:29:16 +08:00
yeongpin
9f814708d1 Update CHANGELOG.md for v1.3.02 release 2025-02-13 15:33:09 +08:00
Pin Studios
1889f9827a Update README.md 2025-02-13 15:28:00 +08:00
yeongpin
57d2d40e67 update coffee 2025-02-13 15:24:40 +08:00
yeongpin
04fa6ee935 update 2025-02-13 15:07:29 +08:00
yeongpin
ed1e0f787e fixed some env 2025-02-13 15:05:45 +08:00
yeongpin
240716e45f fixed small update 2025-02-13 15:05:20 +08:00
yeongpin
35bbe6c93c update cl 2025-02-13 13:25:32 +08:00
yeongpin
fed50a31cc Add manual Cursor registration with manual email input 2025-02-13 13:24:32 +08:00
yeongpin
57ea4dd25a update changelog 2025-02-13 12:16:54 +08:00
16 changed files with 647 additions and 124 deletions

4
.env
View File

@@ -1,2 +1,2 @@
version=1.2.02 version=1.4.01
VERSION=1.2.02 VERSION=1.4.01

View File

@@ -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.0.9-dev' default: '1.4.01'
permissions: permissions:
contents: write contents: write

View File

@@ -1,5 +1,30 @@
# Change Log # Change Log
## v1.4.01
1. Add Disable Cursor Auto Upgrade | 增加禁用Cursor自動升級
## v1.3.02
1. Add Buy Me a Coffee | 增加請我喝杯咖啡
2. Add PayPal | 增加PayPal
3. Very Small Fix | 非常小的修復
4. Fix main.py option number | 修復main.py選項數量
## v1.3.01
1. Add Manual Email Input | 增加手動輸入郵箱地址
2. Add Manual Code Input | 增加手動輸入驗證碼
3. Fix Cursor Options | 修復Cursor選項
## v1.2.02
1. Add PBlock | 增加PBlock
2. Remove uBlock0.chromium | 移除uBlock0.chromium
3. Optimize the logic of the script | 優化腳本邏輯
4. Optimize Size | 優化大小
## v1.2.01 ## v1.2.01

View File

@@ -9,6 +9,7 @@
[![Release](https://img.shields.io/github/v/release/yeongpin/cursor-free-vip?style=flat-square&logo=github&color=blue)](https://github.com/yeongpin/cursor-free-vip/releases/latest) [![Release](https://img.shields.io/github/v/release/yeongpin/cursor-free-vip?style=flat-square&logo=github&color=blue)](https://github.com/yeongpin/cursor-free-vip/releases/latest)
[![License: CC BY-NC-ND 4.0](https://img.shields.io/badge/License-CC_BY--NC--ND_4.0-lightgrey.svg)](https://creativecommons.org/licenses/by-nc-nd/4.0/) [![License: CC BY-NC-ND 4.0](https://img.shields.io/badge/License-CC_BY--NC--ND_4.0-lightgrey.svg)](https://creativecommons.org/licenses/by-nc-nd/4.0/)
[![Stars](https://img.shields.io/github/stars/yeongpin/cursor-free-vip?style=flat-square&logo=github)](https://github.com/yeongpin/cursor-free-vip/stargazers) [![Stars](https://img.shields.io/github/stars/yeongpin/cursor-free-vip?style=flat-square&logo=github)](https://github.com/yeongpin/cursor-free-vip/stargazers)
[![Download](https://img.shields.io/github/downloads/yeongpin/cursor-free-vip/total?style=flat-square&logo=github&color=52c41a)](https://github.com/yeongpin/cursor-free-vip/releases/latest)
</p> </p>
<h4>Support Latest 0.45.11 Version | 支持最新0.45.11版本</h4> <h4>Support Latest 0.45.11 Version | 支持最新0.45.11版本</h4>
@@ -18,7 +19,7 @@ This is a tool to automatically register , support Windows and macOS systems, co
這是一個自動化工具自動註冊除了Google驗證碼),支持 Windows 和 macOS 系統完成Auth驗證重置Cursor的配置。 這是一個自動化工具自動註冊除了Google驗證碼),支持 Windows 和 macOS 系統完成Auth驗證重置Cursor的配置。
<p align="center"> <p align="center">
<img src="./images/new107_2025-01-15_13-53-56.png" alt="new" width="400"/><br> <img src="./images/pronew_2025-02-13_15-01-32.png" alt="new" width="400"/><br>
</p> </p>
##### If you dont have google chrome , you can download it from [here](https://www.google.com/intl/en_pk/chrome/) ##### If you dont have google chrome , you can download it from [here](https://www.google.com/intl/en_pk/chrome/)
@@ -111,6 +112,21 @@ irm https://raw.githubusercontent.com/yeongpin/cursor-free-vip/main/scripts/rese
本工具僅供學習和研究使用,使用本工具所產生的任何後果由使用者自行承擔。 <br> 本工具僅供學習和研究使用,使用本工具所產生的任何後果由使用者自行承擔。 <br>
源代碼靈感來之 | Original code inspiration from [Here](https://github.com/hmhm2022/gpt-cursor-auto)
This tool is only for learning and research purposes, and any consequences arising from the use of this tool are borne by the user. This tool is only for learning and research purposes, and any consequences arising from the use of this tool are borne by the user.
## 💰 Buy Me a Coffee | 請我喝杯咖啡
<div align="center">
<table>
<tr>
<td>
<img src="./images/provi-code.jpg" alt="buy_me_a_coffee" width="280"/><br>
</td>
<td>
<img src="./images/paypal.png" alt="buy_me_a_coffee" width="280"/><br>
</td>
</tr>
</table>
</div>

260
cursor_register_manual.py Normal file
View File

@@ -0,0 +1,260 @@
import os
from colorama import Fore, Style, init
import time
import random
from browser import BrowserManager
from control import BrowserControl
from cursor_auth import CursorAuth
from reset_machine_manual import MachineIDResetter
os.environ["PYTHONVERBOSE"] = "0"
os.environ["PYINSTALLER_VERBOSE"] = "0"
# 初始化colorama
init()
# 定义emoji常量
EMOJI = {
'START': '🚀',
'FORM': '📝',
'VERIFY': '🔄',
'PASSWORD': '🔑',
'CODE': '📱',
'DONE': '',
'ERROR': '',
'WAIT': '',
'SUCCESS': '',
'MAIL': '📧',
'KEY': '🔐',
'UPDATE': '🔄',
'INFO': ''
}
class CursorRegistration:
def __init__(self, translator=None):
self.translator = translator
# 设置为显示模式
os.environ['BROWSER_HEADLESS'] = 'False'
self.browser_manager = BrowserManager()
self.browser = None
self.controller = None
self.sign_up_url = "https://authenticator.cursor.sh/sign-up"
self.settings_url = "https://www.cursor.com/settings"
self.email_address = None
self.signup_tab = None
self.email_tab = None
# 账号信息
self.password = self._generate_password()
self.first_name = self._generate_name()
self.last_name = self._generate_name()
def _generate_password(self, length=12):
"""Generate Random Password"""
chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*"
return ''.join(random.choices(chars, k=length))
def _generate_name(self, length=6):
"""Generate Random Name"""
first_letter = random.choice("ABCDEFGHIJKLMNOPQRSTUVWXYZ")
rest_letters = ''.join(random.choices("abcdefghijklmnopqrstuvwxyz", k=length-1))
return first_letter + rest_letters
def setup_email(self):
"""设置邮箱"""
try:
print(f"{Fore.CYAN}{EMOJI['START']} {self.translator.get('register.manual_email_input') if self.translator else '请输入邮箱地址:'}")
self.email_address = input().strip()
if '@' not in self.email_address:
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('register.invalid_email') if self.translator else '无效的邮箱地址'}{Style.RESET_ALL}")
return False
return True
except Exception as e:
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('register.email_setup_failed', error=str(e))}{Style.RESET_ALL}")
return False
def get_verification_code(self):
"""手动获取验证码"""
try:
print(f"{Fore.CYAN}{EMOJI['CODE']} {self.translator.get('register.manual_code_input') if self.translator else '请输入验证码:'}{Style.RESET_ALL}")
code = input().strip()
if not code.isdigit() or len(code) != 6:
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('register.invalid_code') if self.translator else '无效的验证码'}{Style.RESET_ALL}")
return None
return code
except Exception as e:
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('register.code_input_failed', error=str(e))}{Style.RESET_ALL}")
return None
def register_cursor(self):
"""注册 Cursor"""
browser_tab = None
try:
print(f"{Fore.CYAN}{EMOJI['START']} {self.translator.get('register.register_start')}...{Style.RESET_ALL}")
# 直接使用 new_signup.py 进行注册
from new_signup import main as new_signup_main
# 执行新的注册流程,传入 translator
result, browser_tab = new_signup_main(
email=self.email_address,
password=self.password,
first_name=self.first_name,
last_name=self.last_name,
email_tab=None, # 不需要邮箱标签页
controller=self, # 传入 self 而不是 self.controller
translator=self.translator
)
if result:
# 使用返回的浏览器实例获取账户信息
self.signup_tab = browser_tab # 保存浏览器实例
success = self._get_account_info()
# 获取信息后关闭浏览器
if browser_tab:
try:
browser_tab.quit()
except:
pass
return success
return False
except Exception as e:
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('register.register_process_error', error=str(e))}{Style.RESET_ALL}")
return False
finally:
# 确保在任何情况下都关闭浏览器
if browser_tab:
try:
browser_tab.quit()
except:
pass
def _get_account_info(self):
"""获取账户信息和 Token"""
try:
self.signup_tab.get(self.settings_url)
time.sleep(2)
usage_selector = (
"css:div.col-span-2 > div > div > div > div > "
"div:nth-child(1) > div.flex.items-center.justify-between.gap-2 > "
"span.font-mono.text-sm\\/\\[0\\.875rem\\]"
)
usage_ele = self.signup_tab.ele(usage_selector)
total_usage = "未知"
if usage_ele:
total_usage = usage_ele.text.split("/")[-1].strip()
print(f"{Fore.CYAN}{EMOJI['WAIT']} {self.translator.get('register.get_token')}...{Style.RESET_ALL}")
max_attempts = 30
retry_interval = 2
attempts = 0
while attempts < max_attempts:
try:
cookies = self.signup_tab.cookies()
for cookie in cookies:
if cookie.get("name") == "WorkosCursorSessionToken":
token = cookie["value"].split("%3A%3A")[1]
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('register.token_success')}{Style.RESET_ALL}")
self._save_account_info(token, total_usage)
return True
attempts += 1
if attempts < max_attempts:
print(f"{Fore.YELLOW}{EMOJI['WAIT']} {self.translator.get('register.token_attempt', attempt=attempts, time=retry_interval)}{Style.RESET_ALL}")
time.sleep(retry_interval)
else:
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('register.token_max_attempts', max=max_attempts)}{Style.RESET_ALL}")
except Exception as e:
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('register.token_failed', error=str(e))}{Style.RESET_ALL}")
attempts += 1
if attempts < max_attempts:
print(f"{Fore.YELLOW}{EMOJI['WAIT']} {self.translator.get('register.token_attempt', attempt=attempts, time=retry_interval)}{Style.RESET_ALL}")
time.sleep(retry_interval)
return False
except Exception as e:
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('register.account_error', error=str(e))}{Style.RESET_ALL}")
return False
def _save_account_info(self, token, total_usage):
"""保存账户信息到文件"""
try:
# 先更新认证信息
print(f"{Fore.CYAN}{EMOJI['KEY']} {self.translator.get('register.update_cursor_auth_info')}...{Style.RESET_ALL}")
if self.update_cursor_auth(email=self.email_address, access_token=token, refresh_token=token):
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('register.cursor_auth_info_updated')}...{Style.RESET_ALL}")
else:
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('register.cursor_auth_info_update_failed')}...{Style.RESET_ALL}")
# 重置机器ID
print(f"{Fore.CYAN}{EMOJI['UPDATE']} {self.translator.get('register.reset_machine_id')}...{Style.RESET_ALL}")
resetter = MachineIDResetter(self.translator) # 创建实例时传入translator
if not resetter.reset_machine_ids(): # 直接调用reset_machine_ids方法
raise Exception("Failed to reset machine ID")
# 保存账户信息到文件
with open('cursor_accounts.txt', 'a', encoding='utf-8') as f:
f.write(f"\n{'='*50}\n")
f.write(f"Email: {self.email_address}\n")
f.write(f"Password: {self.password}\n")
f.write(f"Token: {token}\n")
f.write(f"Usage Limit: {total_usage}\n")
f.write(f"{'='*50}\n")
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('register.account_info_saved')}...{Style.RESET_ALL}")
return True
except Exception as e:
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('register.save_account_info_failed', error=str(e))}{Style.RESET_ALL}")
return False
def start(self):
"""启动注册流程"""
try:
if self.setup_email():
if self.register_cursor():
print(f"\n{Fore.GREEN}{EMOJI['DONE']} {self.translator.get('register.cursor_registration_completed')}...{Style.RESET_ALL}")
return True
return False
finally:
# 关闭邮箱标签页
if hasattr(self, 'temp_email'):
try:
self.temp_email.close()
except:
pass
def update_cursor_auth(self, email=None, access_token=None, refresh_token=None):
"""更新Cursor的认证信息的便捷函数"""
auth_manager = CursorAuth(translator=self.translator)
return auth_manager.update_auth(email, access_token, refresh_token)
def main(translator=None):
"""Main function to be called from main.py"""
print(f"\n{Fore.CYAN}{'='*50}{Style.RESET_ALL}")
print(f"{Fore.CYAN}{EMOJI['START']} {translator.get('register.title')}{Style.RESET_ALL}")
print(f"{Fore.CYAN}{'='*50}{Style.RESET_ALL}")
registration = CursorRegistration(translator)
registration.start()
print(f"\n{Fore.CYAN}{'='*50}{Style.RESET_ALL}")
input(f"{EMOJI['INFO']} {translator.get('register.press_enter')}...")
if __name__ == "__main__":
from main import translator as main_translator
main(main_translator)

135
disable_auto_update.py Normal file
View File

@@ -0,0 +1,135 @@
import os
import sys
import platform
import shutil
from colorama import Fore, Style, init
import subprocess
# 初始化 colorama
init()
# 定义 emoji 常量
EMOJI = {
"PROCESS": "🔄",
"SUCCESS": "",
"ERROR": "",
"INFO": "",
"FOLDER": "📁",
"FILE": "📄",
"STOP": "🛑",
"CHECK": "✔️"
}
class AutoUpdateDisabler:
def __init__(self, translator=None):
self.translator = translator
self.system = platform.system()
self.updater_paths = {
"Windows": os.path.join(os.getenv("LOCALAPPDATA", ""), "cursor-updater"),
"Darwin": os.path.expanduser("~/Library/Application Support/cursor-updater"),
"Linux": os.path.expanduser("~/.config/cursor-updater")
}
def _kill_cursor_processes(self):
"""结束所有 Cursor 进程"""
try:
print(f"{Fore.CYAN}{EMOJI['PROCESS']} {self.translator.get('update.killing_processes') if self.translator else '正在结束 Cursor 进程...'}{Style.RESET_ALL}")
if self.system == "Windows":
subprocess.run(['taskkill', '/F', '/IM', 'Cursor.exe', '/T'], capture_output=True)
else:
subprocess.run(['pkill', '-f', 'Cursor'], capture_output=True)
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('update.processes_killed') if self.translator else 'Cursor 进程已结束'}{Style.RESET_ALL}")
return True
except Exception as e:
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('update.kill_process_failed', error=str(e)) if self.translator else f'结束进程失败: {e}'}{Style.RESET_ALL}")
return False
def _remove_updater_directory(self):
"""删除更新程序目录"""
try:
updater_path = self.updater_paths.get(self.system)
if not updater_path:
raise OSError(self.translator.get('update.unsupported_os', system=self.system) if self.translator else f"不支持的操作系统: {self.system}")
print(f"{Fore.CYAN}{EMOJI['FOLDER']} {self.translator.get('update.removing_directory') if self.translator else '正在删除更新程序目录...'}{Style.RESET_ALL}")
if os.path.exists(updater_path):
if os.path.isdir(updater_path):
shutil.rmtree(updater_path)
else:
os.remove(updater_path)
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('update.directory_removed') if self.translator else '更新程序目录已删除'}{Style.RESET_ALL}")
return True
except Exception as e:
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('update.remove_directory_failed', error=str(e)) if self.translator else f'删除目录失败: {e}'}{Style.RESET_ALL}")
return False
def _create_blocking_file(self):
"""创建阻止文件"""
try:
updater_path = self.updater_paths.get(self.system)
if not updater_path:
raise OSError(self.translator.get('update.unsupported_os', system=self.system) if self.translator else f"不支持的操作系统: {self.system}")
print(f"{Fore.CYAN}{EMOJI['FILE']} {self.translator.get('update.creating_block_file') if self.translator else '正在创建阻止文件...'}{Style.RESET_ALL}")
# 创建空文件
open(updater_path, 'w').close()
# 设置只读属性
if self.system == "Windows":
os.system(f'attrib +r "{updater_path}"')
else:
os.chmod(updater_path, 0o444) # 设置为只读
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('update.block_file_created') if self.translator else '阻止文件已创建'}{Style.RESET_ALL}")
return True
except Exception as e:
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('update.create_block_file_failed', error=str(e)) if self.translator else f'创建阻止文件失败: {e}'}{Style.RESET_ALL}")
return False
def disable_auto_update(self):
"""禁用自动更新"""
try:
print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('update.start_disable') if self.translator else '开始禁用自动更新...'}{Style.RESET_ALL}")
# 1. 结束进程
if not self._kill_cursor_processes():
return False
# 2. 删除目录
if not self._remove_updater_directory():
return False
# 3. 创建阻止文件
if not self._create_blocking_file():
return False
print(f"{Fore.GREEN}{EMOJI['CHECK']} {self.translator.get('update.disable_success') if self.translator else '自动更新已禁用'}{Style.RESET_ALL}")
return True
except Exception as e:
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('update.disable_failed', error=str(e)) if self.translator else f'禁用自动更新失败: {e}'}{Style.RESET_ALL}")
return False
def run(translator=None):
"""便捷函数,用于直接调用禁用功能"""
print(f"\n{Fore.CYAN}{'='*50}{Style.RESET_ALL}")
print(f"{Fore.CYAN}{EMOJI['STOP']} {translator.get('update.title') if translator else '禁用 Cursor 自动更新'}{Style.RESET_ALL}")
print(f"{Fore.CYAN}{'='*50}{Style.RESET_ALL}")
disabler = AutoUpdateDisabler(translator)
disabler.disable_auto_update()
print(f"\n{Fore.CYAN}{'='*50}{Style.RESET_ALL}")
input(f"{EMOJI['INFO']} {translator.get('update.press_enter') if translator else '按回车键继续...'}")
if __name__ == "__main__":
from main import translator as main_translator
run(main_translator)

BIN
images/paypal.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

BIN
images/provi-code.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 123 KiB

View File

@@ -4,13 +4,15 @@
"exit": "Exit Program", "exit": "Exit Program",
"reset": "Reset Machine Manual", "reset": "Reset Machine Manual",
"register": "Register Cursor", "register": "Register Cursor",
"register_manual": "Register Cursor With Manual Email",
"quit": "Quit Cursor", "quit": "Quit Cursor",
"select_language": "Select Language", "select_language": "Select Language",
"input_choice": "Enter your choice ({choices})", "input_choice": "Enter your choice ({choices})",
"invalid_choice": "Invalid choice. Please try again", "invalid_choice": "Invalid choice. Please try again",
"program_terminated": "Program terminated by user", "program_terminated": "Program terminated by user",
"error_occurred": "An error occurred: {error}", "error_occurred": "An error occurred: {error}",
"press_enter": "Press Enter to Exit" "press_enter": "Press Enter to Exit",
"disable_auto_update": "Disable Cursor Auto Update"
}, },
"languages": { "languages": {
"en": "English", "en": "English",
@@ -123,7 +125,9 @@
"get_email_address": "Get Email Address", "get_email_address": "Get Email Address",
"update_cursor_auth_info": "Update Cursor Auth Info", "update_cursor_auth_info": "Update Cursor Auth Info",
"register_process_error": "Register Process Error: {error}", "register_process_error": "Register Process Error: {error}",
"setting_password": "Setting Password" "setting_password": "Setting Password",
"manual_code_input": "Manual Code Input",
"manual_email_input": "Manual Email Input"
}, },
"auth": { "auth": {
"title": "Cursor Auth Manager", "title": "Cursor Auth Manager",
@@ -193,5 +197,18 @@
"verification_code_not_found": "Verification Code Not Found", "verification_code_not_found": "Verification Code Not Found",
"verification_code_error": "Verification Code Error: {error}", "verification_code_error": "Verification Code Error: {error}",
"address": "Email Address" "address": "Email Address"
},
"update": {
"title": "Disable Cursor Auto Update",
"disable_success": "Auto Update Disabled Successfully",
"disable_failed": "Disable Auto Update Failed: {error}",
"press_enter": "Press Enter to Exit",
"start_disable": "Start Disabling Auto Update",
"killing_processes": "Killing Processes",
"processes_killed": "Processes Killed",
"removing_directory": "Removing Directory",
"directory_removed": "Directory Removed",
"creating_block_file": "Creating Block File",
"block_file_created": "Block File Created"
} }
} }

View File

@@ -4,13 +4,15 @@
"exit": "退出程序", "exit": "退出程序",
"reset": "重置机器标识", "reset": "重置机器标识",
"register": "注册 Cursor", "register": "注册 Cursor",
"register_manual": "手动指定邮箱注册 Cursor",
"quit": "退出 Cursor", "quit": "退出 Cursor",
"select_language": "选择语言", "select_language": "选择语言",
"input_choice": "输入选择 ({choices})", "input_choice": "输入选择 ({choices})",
"invalid_choice": "无效选择,请重试", "invalid_choice": "无效选择,请重试",
"program_terminated": "程序被用户终止", "program_terminated": "程序被用户终止",
"error_occurred": "发生错误: {error}", "error_occurred": "发生错误: {error}",
"press_enter": "按回车键退出" "press_enter": "按回车键退出",
"disable_auto_update": "禁用 Cursor 自动更新"
}, },
"languages": { "languages": {
"en": "English", "en": "English",
@@ -123,7 +125,9 @@
"get_email_address": "获取邮箱地址", "get_email_address": "获取邮箱地址",
"register_process_error": "注册流程错误: {error}", "register_process_error": "注册流程错误: {error}",
"update_cursor_auth_info": "更新Cursor认证信息", "update_cursor_auth_info": "更新Cursor认证信息",
"setting_password": "设置密码" "setting_password": "设置密码",
"manual_code_input": "手动输入验证码",
"manual_email_input": "手动输入邮箱"
}, },
"auth": { "auth": {
"title": "Cursor 认证管理器", "title": "Cursor 认证管理器",
@@ -190,5 +194,18 @@
"verification_code_not_found": "未找到验证码", "verification_code_not_found": "未找到验证码",
"verification_code_error": "验证码错误: {error}", "verification_code_error": "验证码错误: {error}",
"address": "邮箱地址" "address": "邮箱地址"
},
"update": {
"title": "禁用 Cursor 自动更新",
"disable_success": "自动更新禁用成功",
"disable_failed": "禁用自动更新失败: {error}",
"press_enter": "按回车键退出",
"start_disable": "开始禁用自动更新",
"killing_processes": "杀死进程",
"processes_killed": "进程已杀死",
"removing_directory": "删除目录",
"directory_removed": "目录已删除",
"creating_block_file": "创建阻止文件",
"block_file_created": "阻止文件已创建"
} }
} }

View File

@@ -4,13 +4,15 @@
"exit": "退出程序", "exit": "退出程序",
"reset": "重置機器標識", "reset": "重置機器標識",
"register": "註冊 Cursor", "register": "註冊 Cursor",
"register_manual": "手動指定郵箱註冊 Cursor",
"quit": "退出 Cursor", "quit": "退出 Cursor",
"select_language": "選擇語言", "select_language": "選擇語言",
"input_choice": "輸入選擇 ({choices})", "input_choice": "輸入選擇 ({choices})",
"invalid_choice": "無效選擇,請重試", "invalid_choice": "無效選擇,請重試",
"program_terminated": "程序被用戶終止", "program_terminated": "程序被用戶終止",
"error_occurred": "發生錯誤: {error}", "error_occurred": "發生錯誤: {error}",
"press_enter": "按回車鍵退出" "press_enter": "按回車鍵退出",
"disable_auto_update": "禁用 Cursor 自動更新"
}, },
"languages": { "languages": {
"en": "English", "en": "English",
@@ -123,7 +125,9 @@
"get_email_address": "獲取郵箱地址", "get_email_address": "獲取郵箱地址",
"register_process_error": "註冊流程錯誤: {error}", "register_process_error": "註冊流程錯誤: {error}",
"update_cursor_auth_info": "更新Cursor認證信息", "update_cursor_auth_info": "更新Cursor認證信息",
"setting_password": "設置密碼" "setting_password": "設置密碼",
"manual_code_input": "手動輸入驗證碼",
"manual_email_input": "手動輸入郵箱地址"
}, },
"auth": { "auth": {
"title": "Cursor 認證管理器", "title": "Cursor 認證管理器",
@@ -190,6 +194,18 @@
"verification_code_not_found": "未找到驗證碼", "verification_code_not_found": "未找到驗證碼",
"verification_code_error": "驗證碼錯誤: {error}", "verification_code_error": "驗證碼錯誤: {error}",
"address": "郵箱地址" "address": "郵箱地址"
} },
"update": {
"title": "禁用 Cursor 自动更新",
"disable_success": "自動更新禁用成功",
"disable_failed": "禁用自動更新失敗: {error}",
"press_enter": "按回車鍵退出",
"start_disable": "開始禁用自動更新",
"killing_processes": "殺死進程",
"processes_killed": "進程已殺死",
"removing_directory": "刪除目錄",
"directory_removed": "目錄已刪除",
"creating_block_file": "創建阻止文件",
"block_file_created": "阻止文件已創建"
}
} }

View File

@@ -28,7 +28,7 @@ CURSOR_LOGO = f"""
{Fore.GREEN} {Fore.GREEN}
Author: Pin Studios | yeongpin Author: Pin Studios | yeongpin
{Fore.RED} {Fore.RED}
Press 4 to change language | 按下 4 键切换语言 Press 5 to change language | 按下 5 键切换语言
{Style.RESET_ALL} {Style.RESET_ALL}
""" """

21
main.py
View File

@@ -19,7 +19,8 @@ EMOJI = {
"RESET": "🔄", "RESET": "🔄",
"MENU": "📋", "MENU": "📋",
"ARROW": "", "ARROW": "",
"LANG": "🌐" "LANG": "🌐",
"UPDATE": "🔄"
} }
class Translator: class Translator:
@@ -71,8 +72,10 @@ def print_menu():
print(f"{Fore.GREEN}0{Style.RESET_ALL}. {EMOJI['ERROR']} {translator.get('menu.exit')}") print(f"{Fore.GREEN}0{Style.RESET_ALL}. {EMOJI['ERROR']} {translator.get('menu.exit')}")
print(f"{Fore.GREEN}1{Style.RESET_ALL}. {EMOJI['RESET']} {translator.get('menu.reset')}") print(f"{Fore.GREEN}1{Style.RESET_ALL}. {EMOJI['RESET']} {translator.get('menu.reset')}")
print(f"{Fore.GREEN}2{Style.RESET_ALL}. {EMOJI['SUCCESS']} {translator.get('menu.register')}") print(f"{Fore.GREEN}2{Style.RESET_ALL}. {EMOJI['SUCCESS']} {translator.get('menu.register')}")
print(f"{Fore.GREEN}3{Style.RESET_ALL}. {EMOJI['ERROR']} {translator.get('menu.quit')}") print(f"{Fore.GREEN}3{Style.RESET_ALL}. {EMOJI['SUCCESS']} {translator.get('menu.register_manual')}")
print(f"{Fore.GREEN}4{Style.RESET_ALL}. {EMOJI['LANG']} {translator.get('menu.select_language')}") print(f"{Fore.GREEN}4{Style.RESET_ALL}. {EMOJI['ERROR']} {translator.get('menu.quit')}")
print(f"{Fore.GREEN}5{Style.RESET_ALL}. {EMOJI['LANG']} {translator.get('menu.select_language')}")
print(f"{Fore.GREEN}6{Style.RESET_ALL}. {EMOJI['UPDATE']} {translator.get('menu.disable_auto_update')}")
print(f"{Fore.YELLOW}{'' * 40}{Style.RESET_ALL}") print(f"{Fore.YELLOW}{'' * 40}{Style.RESET_ALL}")
def select_language(): def select_language():
@@ -102,7 +105,7 @@ def main():
while True: while True:
try: try:
choice = input(f"\n{EMOJI['ARROW']} {Fore.CYAN}{translator.get('menu.input_choice', choices='0-4')}: {Style.RESET_ALL}") choice = input(f"\n{EMOJI['ARROW']} {Fore.CYAN}{translator.get('menu.input_choice', choices='0-6')}: {Style.RESET_ALL}")
if choice == "0": if choice == "0":
print(f"\n{Fore.YELLOW}{EMOJI['INFO']} {translator.get('menu.exit')}...{Style.RESET_ALL}") print(f"\n{Fore.YELLOW}{EMOJI['INFO']} {translator.get('menu.exit')}...{Style.RESET_ALL}")
@@ -117,13 +120,21 @@ def main():
cursor_register.main(translator) cursor_register.main(translator)
break break
elif choice == "3": elif choice == "3":
import cursor_register_manual
cursor_register_manual.main(translator)
break
elif choice == "4":
import quit_cursor import quit_cursor
quit_cursor.quit_cursor(translator) quit_cursor.quit_cursor(translator)
break break
elif choice == "4": elif choice == "5":
if select_language(): if select_language():
print_menu() print_menu()
continue continue
elif choice == "6":
import disable_auto_update
disable_auto_update.run(translator)
break
else: else:
print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('menu.invalid_choice')}{Style.RESET_ALL}") print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('menu.invalid_choice')}{Style.RESET_ALL}")
print_menu() print_menu()

View File

@@ -275,23 +275,126 @@ def handle_verification_code(browser_tab, email_tab, controller, email, password
else: else:
print("\n等待并获取验证码...") print("\n等待并获取验证码...")
# 添加调试信息 # 检查是否使用手动输入验证码
print(f"\n{Fore.CYAN}DEBUG: email_tab exists: {email_tab is not None}{Style.RESET_ALL}") if hasattr(controller, 'get_verification_code') and email_tab is None: # 手动模式
verification_code = controller.get_verification_code()
time.sleep(5) # 等待验证码邮件
# 使用已有的 email_tab 刷新邮箱
email_tab.refresh_inbox()
time.sleep(3)
# 检查邮箱是否有验证码邮件
if email_tab.check_for_cursor_email():
verification_code = email_tab.get_verification_code()
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(random.uniform(0.1, 0.3))
print("验证码填写完成")
time.sleep(3)
# 处理最后一次 Turnstile 验证
if handle_turnstile(browser_tab, translator):
if translator:
print(f"{translator.get('register.verification_success')}")
else:
print("最后一次验证通过!")
time.sleep(2)
# 访问设置页面
print("访问设置页面...")
browser_tab.get("https://www.cursor.com/settings")
time.sleep(3) # 等待页面加载
return True, browser_tab
return False, None
# 自动获取验证码逻辑
elif email_tab:
print("等待验证码邮件...")
time.sleep(5) # 等待验证码邮件
# 使用已有的 email_tab 刷新邮箱
email_tab.refresh_inbox()
time.sleep(3)
# 检查邮箱是否有验证码邮件
if email_tab.check_for_cursor_email():
verification_code = email_tab.get_verification_code()
if verification_code:
# 在注册页面填写验证码
for i, digit in enumerate(verification_code):
browser_tab.ele(f"@data-index={i}").input(digit)
time.sleep(random.uniform(0.1, 0.3))
if translator:
print(f"{Fore.GREEN}{translator.get('register.verification_success')}{Style.RESET_ALL}")
else:
print("验证码填写完成")
time.sleep(3)
# 处理最后一次 Turnstile 验证
if handle_turnstile(browser_tab, translator):
if translator:
print(f"{Fore.GREEN}{translator.get('register.verification_success')}{Style.RESET_ALL}")
else:
print("最后一次验证通过!")
time.sleep(2)
# 访问设置页面
if translator:
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")
time.sleep(3) # 等待页面加载
return True, browser_tab
else:
if translator:
print(f"{Fore.RED}{translator.get('register.verification_failed')}{Style.RESET_ALL}")
else:
print("最后一次验证失败")
return False, None
# 获取验证码,设置超时
verification_code = None
max_attempts = 20
retry_interval = 10
start_time = time.time()
timeout = 160
if translator:
print(f"{Fore.CYAN}{translator.get('register.start_getting_verification_code')}{Style.RESET_ALL}")
else:
print("开始获取验证码...")
for attempt in range(max_attempts):
# 检查是否超时
if time.time() - start_time > timeout:
if translator:
print(f"{Fore.RED}{translator.get('register.verification_timeout')}{Style.RESET_ALL}")
else:
print("获取验证码超时...")
break
verification_code = controller.get_verification_code()
if verification_code:
if translator:
print(f"{Fore.GREEN}{translator.get('register.verification_success')}{Style.RESET_ALL}")
else:
print(f"成功获取验证码: {verification_code}")
break
remaining_time = int(timeout - (time.time() - start_time))
if translator:
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()
time.sleep(retry_interval)
if verification_code:
# 在注册页面填写验证码
for i, digit in enumerate(verification_code):
browser_tab.ele(f"@data-index={i}").input(digit)
time.sleep(random.uniform(0.1, 0.3))
if translator: 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: else:
@@ -306,105 +409,32 @@ def handle_verification_code(browser_tab, email_tab, controller, email, password
print("最后一次验证通过!") 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: else:
print("访问设置页面...") 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
else:
print("最后一次验证失败")
return False
return False # 直接返回成功,让 cursor_register.py 处理账户信息获取
return True, browser_tab
# 获取验证码,设置超时
verification_code = None
max_attempts = 20
retry_interval = 10
start_time = time.time()
timeout = 160
if translator:
print(f"{Fore.CYAN}{translator.get('register.start_getting_verification_code')}{Style.RESET_ALL}")
else:
print("开始获取验证码...")
for attempt in range(max_attempts):
# 检查是否超时
if time.time() - start_time > timeout:
if translator:
print(f"{Fore.RED}{translator.get('register.verification_timeout')}{Style.RESET_ALL}")
else: else:
print("获取验证码超时...") if translator:
break print(f"{Fore.RED}{translator.get('register.verification_failed')}{Style.RESET_ALL}")
else:
print("最后一次验证失败")
return False, None
verification_code = controller.get_verification_code() return False, None
if verification_code:
if translator:
print(f"{Fore.GREEN}{translator.get('register.verification_success')}{Style.RESET_ALL}")
else:
print(f"成功获取验证码: {verification_code}")
break
remaining_time = int(timeout - (time.time() - start_time))
if translator:
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()
time.sleep(retry_interval)
if verification_code:
# 在注册页面填写验证码
for i, digit in enumerate(verification_code):
browser_tab.ele(f"@data-index={i}").input(digit)
time.sleep(random.uniform(0.1, 0.3))
if translator:
print(f"{Fore.GREEN}{translator.get('register.verification_success')}{Style.RESET_ALL}")
else:
print("验证码填写完成")
time.sleep(3)
# 处理最后一次 Turnstile 验证
if handle_turnstile(browser_tab, translator):
if translator:
print(f"{Fore.GREEN}{translator.get('register.verification_success')}{Style.RESET_ALL}")
else:
print("最后一次验证通过!")
time.sleep(2)
# 直接访问设置页面
if translator:
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")
time.sleep(3) # 等待页面加载
# 直接返回成功,让 cursor_register.py 处理账户信息获取
return True
else:
if translator:
print(f"{Fore.RED}{translator.get('register.verification_failed')}{Style.RESET_ALL}")
else:
print("最后一次验证失败")
return False
return False
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: else:
print(f"处理验证码时出错: {e}") print(f"处理验证码时出错: {e}")
return False return False, None
def handle_sign_in(browser_tab, email, password, translator=None): def handle_sign_in(browser_tab, email, password, translator=None):
"""处理登录流程""" """处理登录流程"""
@@ -530,12 +560,8 @@ def main(email=None, password=None, first_name=None, last_name=None, email_tab=N
else: else:
print("\n开始处理验证码...") print("\n开始处理验证码...")
if handle_verification_code(page, email_tab, controller, email, password, translator): if handle_verification_code(page, email_tab, controller, email, password, translator):
if translator:
print(f"\n{Fore.GREEN}{translator.get('register.verification_success')}{Style.RESET_ALL}")
else:
print("\n注册流程完成!")
success = True success = True
return True, page # 返回成功状态和浏览器实例 return True, page # 返回浏览器实例
else: else:
print("\n验证码处理失败") print("\n验证码处理失败")
else: else:

View File

@@ -16,10 +16,10 @@ class NewTempEmail:
def get_extension_block(self): def get_extension_block(self):
"""获取插件路径""" """获取插件路径"""
root_dir = os.getcwd() root_dir = os.getcwd()
extension_path = os.path.join(root_dir, "uBlock0.chromium") extension_path = os.path.join(root_dir, "PBlock")
if hasattr(sys, "_MEIPASS"): if hasattr(sys, "_MEIPASS"):
extension_path = os.path.join(sys._MEIPASS, "uBlock0.chromium") extension_path = os.path.join(sys._MEIPASS, "PBlock")
if not os.path.exists(extension_path): if not os.path.exists(extension_path):
raise FileNotFoundError(f"插件不存在: {extension_path}") raise FileNotFoundError(f"插件不存在: {extension_path}")