0
0
mirror of https://github.com/yeongpin/cursor-free-vip.git synced 2025-04-24 08:25:23 +00:00

Merge pull request #94 from UntaDotMy/main

feat: Add support for Cursor v0.46.X and improve email service
This commit is contained in:
Pin Studios 2025-02-25 10:35:34 +08:00 committed by GitHub
commit 4c91525082
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 312 additions and 255 deletions

4
.env
View File

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

View File

@ -63,7 +63,7 @@ jobs:
uses: actions/upload-artifact@v4
with:
name: CursorFreeVIP_${{ env.VERSION }}_windows.exe
path: dist/*
path: dist/CursorFreeVIP_${{ env.VERSION }}_windows.exe
build-macos-arm64:
needs: create-tag
@ -90,12 +90,13 @@ jobs:
- name: Build MacOS ARM executable
run: |
pyinstaller build.spec
mv "dist/CursorFreeVIP_${{ env.VERSION }}_mac" "dist/CursorFreeVIP_${{ env.VERSION }}_mac_arm64"
- name: Upload MacOS ARM artifact
uses: actions/upload-artifact@v4
with:
name: CursorFreeVIP_${{ env.VERSION }}_mac_arm64
path: dist/*
path: dist/CursorFreeVIP_${{ env.VERSION }}_mac_arm64
build-linux:
needs: create-tag
@ -120,14 +121,18 @@ jobs:
pip install -r requirements.txt
- name: Build Linux executable
env:
VERSION: ${{ env.VERSION }}
run: |
pyinstaller build.spec
echo "Contents of dist directory:"
ls -la dist/
- name: Upload Linux artifact
uses: actions/upload-artifact@v4
with:
name: CursorFreeVIP_${{ env.VERSION }}_linux
path: dist/*
path: dist/CursorFreeVIP_${{ env.VERSION }}_linux
build-macos-intel:
@ -155,14 +160,16 @@ jobs:
- name: Build MacOS Intel executable
env:
TARGET_ARCH: 'x86_64'
VERSION: ${{ env.VERSION }}
run: |
arch -x86_64 python3 -m PyInstaller build.spec
mv "dist/CursorFreeVIP_${{ env.VERSION }}_mac" "dist/CursorFreeVIP_${{ env.VERSION }}_mac_intel"
- name: Upload MacOS Intel artifact
uses: actions/upload-artifact@v4
with:
name: CursorFreeVIP_${{ env.VERSION }}_mac_intel
path: dist/*
path: dist/CursorFreeVIP_${{ env.VERSION }}_mac_intel
create-release:
@ -182,24 +189,20 @@ jobs:
- name: Prepare release files
run: |
cd artifacts
# 重命名文件为最终的可执行文件名
mv CursorFreeVIP_${{ env.VERSION }}_windows.exe/CursorFreeVIP.exe CursorFreeVIP_${{ env.VERSION }}_windows.exe
mv CursorFreeVIP_${{ env.VERSION }}_mac_arm64/CursorFreeVIP CursorFreeVIP_${{ env.VERSION }}_mac_arm64
mv CursorFreeVIP_${{ env.VERSION }}_linux/CursorFreeVIP CursorFreeVIP_${{ env.VERSION }}_linux
mv CursorFreeVIP_${{ env.VERSION }}_mac_intel/CursorFreeVIP CursorFreeVIP_${{ env.VERSION }}_mac_intel
# 删除空目录
rm -rf */
echo "Contents of artifacts directory:"
ls -la
echo "Contents of subdirectories:"
ls -la */
- name: Create Release
uses: softprops/action-gh-release@v1
with:
tag_name: v${{ env.VERSION }}
files: |
artifacts/CursorFreeVIP_${{ env.VERSION }}_windows.exe
artifacts/CursorFreeVIP_${{ env.VERSION }}_mac_arm64
artifacts/CursorFreeVIP_${{ env.VERSION }}_linux
artifacts/CursorFreeVIP_${{ env.VERSION }}_mac_intel
artifacts/CursorFreeVIP_${{ env.VERSION }}_windows.exe/CursorFreeVIP_${{ env.VERSION }}_windows.exe
artifacts/CursorFreeVIP_${{ env.VERSION }}_mac_arm64/CursorFreeVIP_${{ env.VERSION }}_mac_arm64
artifacts/CursorFreeVIP_${{ env.VERSION }}_linux/CursorFreeVIP_${{ env.VERSION }}_linux
artifacts/CursorFreeVIP_${{ env.VERSION }}_mac_intel/CursorFreeVIP_${{ env.VERSION }}_mac_intel
draft: false
prerelease: false
env:

3
.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
cursor_accounts.txt
/venv
/__pycache__

View File

@ -1,5 +1,15 @@
# Change Log
## v1.4.03
1. Switch to API-based Registration System | 改用API註冊系統替代瀏覽器操作
2. Add Support for Latest Cursor Version | 增加支持最新版本Cursor
3. Enhance Translation System | 優化多語言翻譯系統
4. Add Database Connection Status Messages | 增加數據庫連接狀態提示
5. Improve Error Handling for Database Operations | 改進數據庫操作的錯誤處理
6. Add New API Integration | 新增API集成
7. Optimize Performance and Stability | 優化性能和穩定性
## v1.4.01
1. Add Disable Cursor Auto Upgrade | 增加禁用Cursor自動升級

View File

@ -12,7 +12,7 @@
[![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>
<h4>Support Latest 0.45.16 Version | 支持最新0.45.16版</h4>
<h4>Support Latest 0.46.3 Version | 支持最新0.46.3</h4>
This is a tool to automatically register , support Windows and macOS systems, complete Auth verification, and reset Cursor's configuration.

View File

@ -31,6 +31,23 @@ class CursorAuth:
"~/Library/Application Support/Cursor/User/globalStorage/state.vscdb"
)
# 检查数据库文件是否存在
if not os.path.exists(self.db_path):
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('auth.db_not_found', path=self.db_path)}{Style.RESET_ALL}")
return
# 检查文件权限
if not os.access(self.db_path, os.R_OK | os.W_OK):
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('auth.db_permission_error')}{Style.RESET_ALL}")
return
try:
self.conn = sqlite3.connect(self.db_path)
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('auth.connected_to_database')}{Style.RESET_ALL}")
except sqlite3.Error as e:
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('auth.db_connection_error', error=str(e))}{Style.RESET_ALL}")
return
def update_auth(self, email=None, access_token=None, refresh_token=None):
conn = None
try:

View File

@ -76,10 +76,9 @@ class CursorRegistration:
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('register.email_create_failed')}{Style.RESET_ALL}")
return False
# 保存邮箱地址和浏览器实例
# 保存邮箱地址
self.email_address = email_address
self.email_tab = self.temp_email # 传递 NewTempEmail 实例而不是 page
self.controller = BrowserControl(self.temp_email.page, self.translator)
self.email_tab = self.temp_email # 传递 NewTempEmail 实例
return True

View File

@ -2,17 +2,17 @@
"menu": {
"title": "Available Options",
"exit": "Exit Program",
"reset": "Reset Machine Manual",
"register": "Register Cursor",
"register_manual": "Register Cursor With Manual Email",
"quit": "Quit Cursor",
"select_language": "Select Language",
"input_choice": "Enter your choice ({choices})",
"invalid_choice": "Invalid choice. Please try again",
"program_terminated": "Program terminated by user",
"error_occurred": "An error occurred: {error}",
"reset": "Reset Machine ID",
"register": "Register New Cursor Account",
"register_manual": "Register Cursor with Custom Email",
"quit": "Close Cursor Application",
"select_language": "Change Language",
"input_choice": "Please enter your choice ({choices})",
"invalid_choice": "Invalid selection. Please enter a number from {choices}",
"program_terminated": "Program was terminated by user",
"error_occurred": "An error occurred: {error}. Please try again",
"press_enter": "Press Enter to Exit",
"disable_auto_update": "Disable Cursor Auto Update"
"disable_auto_update": "Disable Cursor Auto-Update"
},
"languages": {
"en": "English",
@ -68,21 +68,21 @@
},
"register": {
"title": "Cursor Registration Tool",
"start": "Starting Registration Process",
"handling_turnstile": "Handling Turnstile",
"retry_verification": "Retry Verification",
"detect_turnstile": "Detect Turnstile",
"verification_success": "Verification Success",
"starting_browser": "Starting Browser",
"form_success": "Form Success",
"browser_started": "Browser Started",
"waiting_for_second_verification": "Waiting for Second Verification",
"waiting_for_verification_code": "Waiting for Verification Code",
"password_success": "Password Set Successfully",
"password_error": "Password Set Failed: {error}",
"waiting_for_page_load": "Waiting for Page Load",
"first_verification_passed": "First Verification Passed",
"mailbox": "Successfully Entered Mailbox",
"start": "Starting registration process...",
"handling_turnstile": "Processing security verification...",
"retry_verification": "Retrying verification...",
"detect_turnstile": "Checking security verification...",
"verification_success": "Security verification successful",
"starting_browser": "Opening browser...",
"form_success": "Form submitted successfully",
"browser_started": "Browser opened successfully",
"waiting_for_second_verification": "Waiting for email verification...",
"waiting_for_verification_code": "Waiting for verification code...",
"password_success": "Password set successfully",
"password_error": "Could not set password: {error}. Please try again",
"waiting_for_page_load": "Loading page...",
"first_verification_passed": "Initial verification successful",
"mailbox": "Successfully accessed email inbox",
"register_start": "Start Register",
"form_submitted": "Form Submitted, Start Verification...",
"filling_form": "Fill Form",
@ -145,7 +145,10 @@
"database_connection_closed": "Database Connection Closed",
"database_updated_successfully": "Database Updated Successfully",
"connected_to_database": "Connected to Database",
"updating_pair": "Updating Key-Value Pair"
"updating_pair": "Updating Key-Value Pair",
"db_not_found": "Database file not found at: {path}",
"db_permission_error": "Cannot access database file. Please check permissions",
"db_connection_error": "Failed to connect to database: {error}"
},
"control": {
"generate_email": "Generating New Email",
@ -182,7 +185,7 @@
},
"email": {
"starting_browser": "Starting Browser",
"visiting_site": "Visiting smailpro.com",
"visiting_site": "Visiting mail.tm",
"create_success": "Email Created Successfully",
"create_failed": "Failed to Create Email",
"create_error": "Email Creation Error: {error}",

View File

@ -3,14 +3,14 @@
"title": "可用选项",
"exit": "退出程序",
"reset": "重置机器标识",
"register": "注册 Cursor",
"register_manual": "手动指定邮箱注册 Cursor",
"quit": "退出 Cursor",
"select_language": "选择语言",
"input_choice": "输入选择 ({choices})",
"invalid_choice": "无效选择,请重试",
"program_terminated": "程序被用户终止",
"error_occurred": "发生错误: {error}",
"register": "注册 Cursor 账号",
"register_manual": "使用自定义邮箱注册",
"quit": "关闭 Cursor 应用",
"select_language": "更改语言",
"input_choice": "输入您的选择 ({choices})",
"invalid_choice": "选择无效,请输入 {choices} 范围内的数字",
"program_terminated": "程序被用户终止",
"error_occurred": "发生错误{error},请重试",
"press_enter": "按回车键退出",
"disable_auto_update": "禁用 Cursor 自动更新"
},
@ -68,25 +68,25 @@
},
"register": {
"title": "Cursor 注册工具",
"start": "开始注册流程",
"browser_started": "浏览器已启动",
"password_success": "密码设置成",
"password_error": "密码设置失败: {error}",
"waiting_for_page_load": "等待页面加载",
"mailbox": "成功进入邮箱",
"waiting_for_second_verification": "等待第二阶段验证",
"waiting_for_verification_code": "等待验证码",
"first_verification_passed": "第一阶段验证通过",
"start": "正在启动注册流程...",
"browser_started": "浏览器已成功打开",
"password_success": "密码设置",
"password_error": "无法设置密码:{error},请重试",
"waiting_for_page_load": "页面加载中...",
"mailbox": "已成功访问邮箱",
"waiting_for_second_verification": "等待邮箱验证...",
"waiting_for_verification_code": "等待验证码...",
"first_verification_passed": "初始验证通过",
"register_start": "开始注册流程",
"form_submitted": "表单已提交,开始验证...",
"filling_form": "填写注册信息",
"visiting_url": "访问URL",
"basic_info": "基本信息提交完成",
"handling_turnstile": "处理 Turnstile 验证",
"retry_verification": "重试验证",
"detect_turnstile": "检测 Turnstile 验证",
"verification_success": "验证成功",
"starting_browser": "启动浏览器",
"handling_turnstile": "正在处理安全验证...",
"retry_verification": "正在重试验证...",
"detect_turnstile": "正在检查安全验证...",
"verification_success": "安全验证通过",
"starting_browser": "正在打开浏览器...",
"form_success": "表单提交成功",
"handle_turnstile": "处理 Turnstile 验证",
"no_turnstile": "未检测到 Turnstile 验证",
@ -144,7 +144,10 @@
"connected_to_database": "已连接到数据库",
"database_updated_successfully": "数据库更新成功",
"database_connection_closed": "数据库连接已关闭",
"updating_pair": "更新键值对"
"updating_pair": "更新键值对",
"db_not_found": "未找到数据库文件:{path}",
"db_permission_error": "无法访问数据库文件,请检查权限",
"db_connection_error": "连接数据库失败:{error}"
},
"control": {
"generate_email": "生成新邮箱",
@ -179,7 +182,7 @@
},
"email": {
"starting_browser": "启动浏览器",
"visiting_site": "访问 smailpro.com",
"visiting_site": "访问 mail.tm",
"create_success": "邮箱创建成功",
"create_failed": "邮箱创建失败",
"create_error": "邮箱创建错误: {error}",

View File

@ -1,18 +1,18 @@
{
"menu": {
"title": "可用選項",
"exit": "退出程",
"reset": "重置機器識",
"register": "註冊 Cursor",
"register_manual": "手動指定郵箱註冊 Cursor",
"quit": "退出 Cursor",
"select_language": "選擇語言",
"input_choice": "輸入選擇 ({choices})",
"invalid_choice": "無效選擇,請重試",
"program_terminated": "程序被用戶終止",
"error_occurred": "發生錯誤: {error}",
"press_enter": "按鍵退出",
"disable_auto_update": "用 Cursor 自動更新"
"exit": "退出程",
"reset": "重置機器別碼",
"register": "註冊 Cursor 帳號",
"register_manual": "使用自訂郵箱註冊",
"quit": "關閉 Cursor 應用程式",
"select_language": "變更語言",
"input_choice": "輸入您的選擇 ({choices})",
"invalid_choice": "選擇無效,請輸入 {choices} 範圍內的數字",
"program_terminated": "程式已被使用者終止",
"error_occurred": "發生錯誤{error},請重試",
"press_enter": "按回鍵退出",
"disable_auto_update": "用 Cursor 自動更新"
},
"languages": {
"en": "English",
@ -68,17 +68,24 @@
},
"register": {
"title": "Cursor 註冊工具",
"start": "開始註冊流程",
"mailbox": "成功進入郵箱",
"browser_started": "瀏覽器已啟動",
"waiting_for_page_load": "等待頁面加載",
"password_success": "密碼設置完成",
"password_error": "密碼設置失敗: {error}",
"start": "正在啟動註冊流程...",
"handling_turnstile": "正在處理安全驗證...",
"retry_verification": "正在重試驗證...",
"detect_turnstile": "正在檢查安全驗證...",
"verification_success": "安全驗證通過",
"starting_browser": "正在開啟瀏覽器...",
"form_success": "表單提交成功",
"browser_started": "瀏覽器已成功開啟",
"waiting_for_second_verification": "等待郵箱驗證...",
"waiting_for_verification_code": "等待驗證碼...",
"password_success": "密碼設定成功",
"password_error": "無法設定密碼:{error},請重試",
"waiting_for_page_load": "頁面載入中...",
"first_verification_passed": "初始驗證通過",
"mailbox": "已成功存取郵箱",
"visiting_url": "訪問URL",
"first_verification_passed": "第一階段驗證通過",
"register_start": "開始註冊流程",
"form_submitted": "表單已提交,開始驗證...",
"waiting_for_second_verification": "等待第二階段驗證",
"filling_form": "填寫註冊信息",
"basic_info": "基本信息提交完成",
"handle_turnstile": "處理 Turnstile 驗證",
@ -86,31 +93,6 @@
"turnstile_passed": "驗證通過",
"verification_start": "開始獲取驗證碼",
"waiting_for_verification_code": "等待驗證碼",
"handling_turnstile": "處理 Turnstile 驗證",
"retry_verification": "重試驗證",
"detect_turnstile": "檢測 Turnstile 驗證",
"verification_success": "驗證成功",
"starting_browser": "啟動瀏覽器",
"form_success": "表單提交成功",
"verification_timeout": "獲取驗證碼超時",
"verification_not_found": "未找到驗證碼",
"try_get_code": "第 {attempt} 次嘗試獲取驗證碼 | 剩餘時間: {time}秒",
"get_account": "獲取賬戶信息",
"get_token": "獲取 Cursor Session Token",
"token_success": "Token 獲取成功",
"token_attempt": "第 {attempt} 次嘗試未獲取到 Token{time}秒後重試",
"token_max_attempts": "已達到最大嘗試次數({max}),獲取 Token 失敗",
"token_failed": "獲取 Token 失敗: {error}",
"account_error": "獲取賬戶信息失敗: {error}",
"press_enter": "按回車鍵退出",
"browser_start": "正在啟動瀏覽器",
"open_mailbox": "正在打開郵箱頁面",
"email_error": "獲取郵箱地址失敗",
"setup_error": "郵箱設置出錯: {error}",
"start_getting_verification_code": "開始獲取驗證碼將在60秒內嘗試...",
"get_verification_code_timeout": "獲取驗證碼超時",
"get_verification_code_success": "成功獲取驗證碼",
"try_get_verification_code": "第 {attempt} 次嘗試未獲取到驗證碼,剩餘時間: {remaining_time}秒",
"verification_code_filled": "驗證碼填寫完成",
"login_success_and_jump_to_settings_page": "成功登錄並跳轉到設置頁面",
"detect_login_page": "檢測到登錄頁面,開始登錄...",
@ -144,7 +126,10 @@
"connected_to_database": "已連接到數據庫",
"database_updated_successfully": "數據庫更新成功",
"database_connection_closed": "數據庫連接已關閉",
"updating_pair": "更新鍵值對"
"updating_pair": "更新鍵值對",
"db_not_found": "未找到數據庫文件:{path}",
"db_permission_error": "無法訪問數據庫文件,請檢查權限",
"db_connection_error": "連接數據庫失敗:{error}"
},
"control": {
"generate_email": "生成新郵箱",
@ -179,7 +164,7 @@
},
"email": {
"starting_browser": "啟動瀏覽器",
"visiting_site": "訪問 smailpro.com",
"visiting_site": "訪問 mail.tm",
"create_success": "郵箱創建成功",
"create_failed": "郵箱創建失敗",
"create_error": "郵箱創建錯誤: {error}",

85
main.py
View File

@ -25,43 +25,71 @@ EMOJI = {
class Translator:
def __init__(self):
self.current_language = 'zh_tw' # 默认语言
self.current_language = 'en' # Default language
self.translations = {}
self.fallback_language = 'en' # Fallback language if translation is missing
self.load_translations()
def load_translations(self):
"""加载所有可用的翻译"""
locales_dir = os.path.join(os.path.dirname(__file__), 'locales')
if hasattr(sys, '_MEIPASS'):
locales_dir = os.path.join(sys._MEIPASS, 'locales')
"""Load all available translations"""
try:
locales_dir = os.path.join(os.path.dirname(__file__), 'locales')
if hasattr(sys, '_MEIPASS'):
locales_dir = os.path.join(sys._MEIPASS, 'locales')
for file in os.listdir(locales_dir):
if file.endswith('.json'):
lang_code = file[:-5] # 移除 .json
with open(os.path.join(locales_dir, file), 'r', encoding='utf-8') as f:
self.translations[lang_code] = json.load(f)
if not os.path.exists(locales_dir):
print(f"{Fore.RED}{EMOJI['ERROR']} Locales directory not found{Style.RESET_ALL}")
return
for file in os.listdir(locales_dir):
if file.endswith('.json'):
lang_code = file[:-5] # Remove .json
try:
with open(os.path.join(locales_dir, file), 'r', encoding='utf-8') as f:
self.translations[lang_code] = json.load(f)
except (json.JSONDecodeError, UnicodeDecodeError) as e:
print(f"{Fore.RED}{EMOJI['ERROR']} Error loading {file}: {e}{Style.RESET_ALL}")
continue
except Exception as e:
print(f"{Fore.RED}{EMOJI['ERROR']} Failed to load translations: {e}{Style.RESET_ALL}")
def get(self, key, **kwargs):
"""获取翻译文本"""
"""Get translated text with fallback support"""
try:
# Try current language
result = self._get_translation(self.current_language, key)
if result == key and self.current_language != self.fallback_language:
# Try fallback language if translation not found
result = self._get_translation(self.fallback_language, key)
return result.format(**kwargs) if kwargs else result
except Exception:
return key
def _get_translation(self, lang_code, key):
"""Get translation for a specific language"""
try:
keys = key.split('.')
value = self.translations.get(self.current_language, {})
value = self.translations.get(lang_code, {})
for k in keys:
if isinstance(value, dict):
value = value.get(k, key)
else:
return key # 如果中間值不是字典返回原始key
return value.format(**kwargs) if kwargs else value
return key
return value
except Exception:
return key # 出現任何錯誤時返回原始key
return key
def set_language(self, lang_code):
"""设置当前语言"""
"""Set current language with validation"""
if lang_code in self.translations:
self.current_language = lang_code
return True
return False
def get_available_languages(self):
"""Get list of available languages"""
return list(self.translations.keys())
# 创建翻译器实例
translator = Translator()
@ -79,25 +107,26 @@ def print_menu():
print(f"{Fore.YELLOW}{'' * 40}{Style.RESET_ALL}")
def select_language():
"""语言选择菜单"""
"""Language selection menu"""
print(f"\n{Fore.CYAN}{EMOJI['LANG']} {translator.get('menu.select_language')}:{Style.RESET_ALL}")
print(f"{Fore.YELLOW}{'' * 40}{Style.RESET_ALL}")
languages = translator.get('languages')
for i, (code, name) in enumerate(languages.items()):
print(f"{Fore.GREEN}{i}{Style.RESET_ALL}. {name}")
languages = translator.get_available_languages()
for i, lang in enumerate(languages):
lang_name = translator.get(f"languages.{lang}")
print(f"{Fore.GREEN}{i}{Style.RESET_ALL}. {lang_name}")
try:
choice = input(f"\n{EMOJI['ARROW']} {Fore.CYAN}{translator.get('menu.input_choice', choices='0-' + str(len(languages)-1))}: {Style.RESET_ALL}")
choice = input(f"\n{EMOJI['ARROW']} {Fore.CYAN}{translator.get('menu.input_choice', choices=f'0-{len(languages)-1}')}: {Style.RESET_ALL}")
if choice.isdigit() and 0 <= int(choice) < len(languages):
lang_code = list(languages.keys())[int(choice)]
translator.set_language(lang_code)
translator.set_language(languages[int(choice)])
return True
else:
print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('menu.invalid_choice')}{Style.RESET_ALL}")
return False
except (ValueError, IndexError):
pass
print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('menu.invalid_choice')}{Style.RESET_ALL}")
return False
print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('menu.invalid_choice')}{Style.RESET_ALL}")
return False
def main():
print_logo()
@ -151,4 +180,4 @@ def main():
input(f"{EMOJI['INFO']} {translator.get('menu.press_enter')}...{Style.RESET_ALL}")
if __name__ == "__main__":
main()
main()

View File

@ -3,6 +3,9 @@ import time
import os
import sys
from colorama import Fore, Style, init
import requests
import random
import string
# 初始化 colorama
init()
@ -10,95 +13,73 @@ init()
class NewTempEmail:
def __init__(self, translator=None):
self.translator = translator
self.page = None
self.setup_browser()
# Randomly choose between mail.tm and mail.gw
self.services = [
{"name": "mail.tm", "api_url": "https://api.mail.tm"},
{"name": "mail.gw", "api_url": "https://api.mail.gw"}
]
self.selected_service = random.choice(self.services)
self.api_url = self.selected_service["api_url"]
self.token = None
self.email = None
self.password = None
def get_extension_block(self):
"""获取插件路径"""
root_dir = os.getcwd()
extension_path = os.path.join(root_dir, "PBlock")
def _generate_credentials(self):
"""生成随机用户名和密码"""
username = ''.join(random.choices(string.ascii_lowercase + string.digits, k=10))
password = ''.join(random.choices(string.ascii_letters + string.digits + string.punctuation, k=12))
return username, password
if hasattr(sys, "_MEIPASS"):
extension_path = os.path.join(sys._MEIPASS, "PBlock")
if not os.path.exists(extension_path):
raise FileNotFoundError(f"插件不存在: {extension_path}")
return extension_path
def setup_browser(self):
"""设置浏览器"""
try:
if self.translator:
print(f"{Fore.CYAN} {self.translator.get('email.starting_browser')}{Style.RESET_ALL}")
else:
print(f"{Fore.CYAN} 正在启动浏览器...{Style.RESET_ALL}")
# 创建浏览器选项
co = ChromiumOptions()
co.set_argument("--headless=new")
co.auto_port() # 自动设置端口
# 加载 uBlock 插件
try:
extension_path = self.get_extension_block()
co.set_argument("--allow-extensions-in-incognito")
co.add_extension(extension_path)
except Exception as e:
if self.translator:
print(f"{Fore.YELLOW}⚠️ {self.translator.get('email.extension_load_error')}: {str(e)}{Style.RESET_ALL}")
else:
print(f"{Fore.YELLOW}⚠️ 加载插件失败: {str(e)}{Style.RESET_ALL}")
self.page = ChromiumPage(co)
return True
except Exception as e:
if self.translator:
print(f"{Fore.RED}{self.translator.get('email.browser_start_error')}: {str(e)}{Style.RESET_ALL}")
else:
print(f"{Fore.RED}❌ 启动浏览器失败: {str(e)}{Style.RESET_ALL}")
return False
def create_email(self):
"""创建临时邮箱"""
try:
if self.translator:
print(f"{Fore.CYAN} {self.translator.get('email.visiting_site')}{Style.RESET_ALL}")
print(f"{Fore.CYAN} {self.translator.get('email.visiting_site').replace('mail.tm', self.selected_service['name'])}{Style.RESET_ALL}")
else:
print(f"{Fore.CYAN} 正在访问 smailpro.com...{Style.RESET_ALL}")
print(f"{Fore.CYAN} 正在访问 {self.selected_service['name']}...{Style.RESET_ALL}")
# 访问网站
self.page.get("https://smailpro.com/")
time.sleep(2)
# 点击创建邮箱按钮
create_button = self.page.ele('xpath://button[@title="Create temporary email"]')
if create_button:
create_button.click()
time.sleep(1)
# 获取可用域名列表
domains_response = requests.get(f"{self.api_url}/domains")
if domains_response.status_code != 200:
raise Exception("Failed to get available domains")
# 点击弹窗中的 Create 按钮
modal_create_button = self.page.ele('xpath://button[contains(text(), "Create")]')
if modal_create_button:
modal_create_button.click()
time.sleep(2)
# 获取邮箱地址 - 修改选择器
email_div = self.page.ele('xpath://div[@class="text-base sm:text-lg md:text-xl text-gray-700"]')
if email_div:
email = email_div.text.strip()
if '@' in email: # 验证是否是有效的邮箱地址
if self.translator:
print(f"{Fore.GREEN}{self.translator.get('email.create_success')}: {email}{Style.RESET_ALL}")
else:
print(f"{Fore.GREEN}✅ 创建邮箱成功: {email}{Style.RESET_ALL}")
return email
domains = domains_response.json()["hydra:member"]
if not domains:
raise Exception("No available domains")
# 生成随机用户名和密码
username, password = self._generate_credentials()
self.password = password
# 创建邮箱账户
email = f"{username}@{domains[0]['domain']}"
account_data = {
"address": email,
"password": password
}
create_response = requests.post(f"{self.api_url}/accounts", json=account_data)
if create_response.status_code != 201:
raise Exception("Failed to create account")
# 获取访问令牌
token_data = {
"address": email,
"password": password
}
token_response = requests.post(f"{self.api_url}/token", json=token_data)
if token_response.status_code != 200:
raise Exception("Failed to get access token")
self.token = token_response.json()["token"]
self.email = email
if self.translator:
print(f"{Fore.RED}{self.translator.get('email.create_failed')}{Style.RESET_ALL}")
print(f"{Fore.GREEN} {self.translator.get('email.create_success')}: {email}{Style.RESET_ALL}")
else:
print(f"{Fore.RED}❌ 创建邮箱失败{Style.RESET_ALL}")
return None
print(f"{Fore.GREEN}✅ 创建邮箱成功: {email}{Style.RESET_ALL}")
return email
except Exception as e:
if self.translator:
@ -120,11 +101,11 @@ class NewTempEmail:
else:
print(f"{Fore.CYAN}🔄 正在刷新邮箱...{Style.RESET_ALL}")
# 点击刷新按钮
refresh_button = self.page.ele('xpath://button[@id="refresh"]')
if refresh_button:
refresh_button.click()
time.sleep(2) # 等待刷新完成
# 使用 API 获取最新邮件
headers = {"Authorization": f"Bearer {self.token}"}
response = requests.get(f"{self.api_url}/messages", headers=headers)
if response.status_code == 200:
if self.translator:
print(f"{Fore.GREEN}{self.translator.get('email.refresh_success')}{Style.RESET_ALL}")
else:
@ -132,9 +113,9 @@ class NewTempEmail:
return True
if self.translator:
print(f"{Fore.RED}{self.translator.get('email.refresh_button_not_found')}{Style.RESET_ALL}")
print(f"{Fore.RED}{self.translator.get('email.refresh_failed')}{Style.RESET_ALL}")
else:
print(f"{Fore.RED}未找到刷新按钮{Style.RESET_ALL}")
print(f"{Fore.RED}刷新邮箱失败{Style.RESET_ALL}")
return False
except Exception as e:
@ -147,17 +128,24 @@ class NewTempEmail:
def check_for_cursor_email(self):
"""检查是否有 Cursor 的验证邮件"""
try:
# 查找验证邮件 - 使用更精确的选择器
email_div = self.page.ele('xpath://div[contains(@class, "p-2") and contains(@class, "cursor-pointer") and contains(@class, "bg-white") and contains(@class, "shadow") and .//b[text()="no-reply@cursor.sh"] and .//span[text()="Verify your email address"]]')
if email_div:
if self.translator:
print(f"{Fore.GREEN}{self.translator.get('email.verification_found')}{Style.RESET_ALL}")
else:
print(f"{Fore.GREEN}✅ 找到验证邮件{Style.RESET_ALL}")
# 使用 JavaScript 点击元素
self.page.run_js('arguments[0].click()', email_div)
time.sleep(2) # 等待邮件内容加载
return True
# 使用 API 获取邮件列表
headers = {"Authorization": f"Bearer {self.token}"}
response = requests.get(f"{self.api_url}/messages", headers=headers)
if response.status_code == 200:
messages = response.json()["hydra:member"]
for message in messages:
if message["from"]["address"] == "no-reply@cursor.sh" and "Verify your email address" in message["subject"]:
# 获取邮件内容
message_id = message["id"]
message_response = requests.get(f"{self.api_url}/messages/{message_id}", headers=headers)
if message_response.status_code == 200:
if self.translator:
print(f"{Fore.GREEN}{self.translator.get('email.verification_found')}{Style.RESET_ALL}")
else:
print(f"{Fore.GREEN}✅ 找到验证邮件{Style.RESET_ALL}")
return True
if self.translator:
print(f"{Fore.YELLOW}⚠️ {self.translator.get('email.verification_not_found')}{Style.RESET_ALL}")
else:
@ -174,16 +162,33 @@ class NewTempEmail:
def get_verification_code(self):
"""获取验证码"""
try:
# 查找验证码元素
code_element = self.page.ele('xpath://td//div[contains(@style, "font-size:28px") and contains(@style, "letter-spacing:2px")]')
if code_element:
code = code_element.text.strip()
if code.isdigit() and len(code) == 6:
if self.translator:
print(f"{Fore.GREEN}{self.translator.get('email.verification_code_found')}: {code}{Style.RESET_ALL}")
else:
print(f"{Fore.GREEN}✅ 获取验证码成功: {code}{Style.RESET_ALL}")
return code
# 使用 API 获取邮件列表
headers = {"Authorization": f"Bearer {self.token}"}
response = requests.get(f"{self.api_url}/messages", headers=headers)
if response.status_code == 200:
messages = response.json()["hydra:member"]
for message in messages:
if message["from"]["address"] == "no-reply@cursor.sh" and "Verify your email address" in message["subject"]:
# 获取邮件内容
message_id = message["id"]
message_response = requests.get(f"{self.api_url}/messages/{message_id}", headers=headers)
if message_response.status_code == 200:
# 从邮件内容中提取验证码
email_content = message_response.json()["text"]
# 查找6位数字验证码
import re
code_match = re.search(r'\b\d{6}\b', email_content)
if code_match:
code = code_match.group(0)
if self.translator:
print(f"{Fore.GREEN}{self.translator.get('email.verification_code_found')}: {code}{Style.RESET_ALL}")
else:
print(f"{Fore.GREEN}✅ 获取验证码成功: {code}{Style.RESET_ALL}")
return code
if self.translator:
print(f"{Fore.YELLOW}⚠️ {self.translator.get('email.verification_code_not_found')}{Style.RESET_ALL}")
else:
@ -223,4 +228,4 @@ def main(translator=None):
temp_email.close()
if __name__ == "__main__":
main()
main()