diff --git a/README.md b/README.md index 9791cf7..a14a1a0 100644 --- a/README.md +++ b/README.md @@ -7,10 +7,10 @@

-[![Release](https://img.shields.io/endpoint?url=https://www.pinnumber.rr.nu/badges/release/yeongpin/cursor-free-vip)](https://github.com/yeongpin/cursor-free-vip/releases/latest) +[![Release](https://img.shields.io/endpoint?url=https://api.pinstudios.net/api/badges/release/yeongpin/cursor-free-vip)](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/) -[![Stars](https://img.shields.io/endpoint?url=https://www.pinnumber.rr.nu/badges/stars/yeongpin/cursor-free-vip)](https://github.com/yeongpin/cursor-free-vip/stargazers) -[![Downloads](https://img.shields.io/endpoint?url=https://www.pinnumber.rr.nu/badges/downloads/yeongpin/cursor-free-vip/total)](https://github.com/yeongpin/cursor-free-vip/releases/latest) +[![Stars](https://img.shields.io/endpoint?url=https://api.pinstudios.net/api/badges/stars/yeongpin/cursor-free-vip)](https://github.com/yeongpin/cursor-free-vip/stargazers) +[![Downloads](https://img.shields.io/endpoint?url=https://api.pinstudios.net/api/badges/downloads/yeongpin/cursor-free-vip/total)](https://github.com/yeongpin/cursor-free-vip/releases/latest) Buy Me a Coffee

diff --git a/config.py b/config.py index 1d59a21..f59f384 100644 --- a/config.py +++ b/config.py @@ -249,6 +249,13 @@ def setup_config(translator=None): 'product_json_path': os.path.join(cursor_dir, "resources/app/product.json") if cursor_dir else "" } + # Add tempmail_plus configuration + default_config['TempMailPlus'] = { + 'enabled': 'false', + 'email': '', + 'epin': '' + } + # Read existing configuration and merge if os.path.exists(config_file): config.read(config_file, encoding='utf-8') diff --git a/cursor_register_manual.py b/cursor_register_manual.py index ca63813..bf3cf83 100644 --- a/cursor_register_manual.py +++ b/cursor_register_manual.py @@ -6,6 +6,7 @@ from faker import Faker from cursor_auth import CursorAuth from reset_machine_manual import MachineIDResetter from get_user_token import get_token_from_cookie +from config import get_config os.environ["PYTHONVERBOSE"] = "0" os.environ["PYINSTALLER_VERBOSE"] = "0" @@ -102,6 +103,18 @@ class CursorRegistration: try: print(f"{Fore.CYAN}{EMOJI['START']} {self.translator.get('register.register_start')}...{Style.RESET_ALL}") + # Check if tempmail_plus is enabled + config = get_config(self.translator) + email_tab = None + if config and config.has_section('TempMailPlus'): + if config.getboolean('TempMailPlus', 'enabled'): + email = config.get('TempMailPlus', 'email') + epin = config.get('TempMailPlus', 'epin') + if email and epin: + from email_tabs.tempmail_plus_tab import TempMailPlusTab + email_tab = TempMailPlusTab(email, epin) + print(f"{Fore.CYAN}{EMOJI['MAIL']} {self.translator.get('register.using_tempmail_plus')}{Style.RESET_ALL}") + # Use new_signup.py directly for registration from new_signup import main as new_signup_main @@ -111,7 +124,7 @@ class CursorRegistration: password=self.password, first_name=self.first_name, last_name=self.last_name, - email_tab=None, # No email tab needed + email_tab=email_tab, # Pass email_tab if tempmail_plus is enabled controller=self, # Pass self instead of self.controller translator=self.translator ) diff --git a/email_tabs/email_tab_interface.py b/email_tabs/email_tab_interface.py new file mode 100644 index 0000000..d80f0a1 --- /dev/null +++ b/email_tabs/email_tab_interface.py @@ -0,0 +1,27 @@ +from abc import ABC, abstractmethod + +class EmailTabInterface(ABC): + """Email tab interface for handling email verification""" + + @abstractmethod + def refresh_inbox(self) -> None: + """Refresh the email inbox""" + pass + + @abstractmethod + def check_for_cursor_email(self) -> bool: + """Check if there is a verification email from Cursor + + Returns: + bool: True if verification email exists, False otherwise + """ + pass + + @abstractmethod + def get_verification_code(self) -> str: + """Get the verification code from the email + + Returns: + str: The verification code if found, empty string otherwise + """ + pass diff --git a/email_tabs/tempmail_plus_tab.py b/email_tabs/tempmail_plus_tab.py new file mode 100644 index 0000000..4fbea0d --- /dev/null +++ b/email_tabs/tempmail_plus_tab.py @@ -0,0 +1,109 @@ +import requests +import re +from typing import Optional +from .email_tab_interface import EmailTabInterface + +class TempMailPlusTab(EmailTabInterface): + """Implementation of EmailTabInterface for tempmail.plus""" + + def __init__(self, email: str, epin: str): + """Initialize TempMailPlusTab + + Args: + email: The email address to check + epin: The epin token for authentication + """ + self.email = email + self.epin = epin + self.base_url = "https://tempmail.plus/api" + self.headers = { + 'accept': 'application/json', + 'accept-language': 'zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7,zh-TW;q=0.6', + 'cache-control': 'no-cache', + 'pragma': 'no-cache', + 'referer': 'https://tempmail.plus/zh/', + 'sec-ch-ua': '"Google Chrome";v="135", "Not-A.Brand";v="8", "Chromium";v="135"', + 'sec-ch-ua-mobile': '?0', + 'sec-ch-ua-platform': '"macOS"', + 'sec-fetch-dest': 'empty', + 'sec-fetch-mode': 'cors', + 'sec-fetch-site': 'same-origin', + 'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36', + 'x-requested-with': 'XMLHttpRequest' + } + self.cookies = {'email': email} + self._cached_mail_id = None # 缓存mail_id + + def refresh_inbox(self) -> None: + """Refresh the email inbox""" + pass + + def check_for_cursor_email(self) -> bool: + """Check if there is a verification email from Cursor + + Returns: + bool: True if verification email exists, False otherwise + """ + try: + params = { + 'email': self.email, + 'epin': self.epin + } + response = requests.get( + f"{self.base_url}/mails", + params=params, + headers=self.headers, + cookies=self.cookies + ) + response.raise_for_status() + + data = response.json() + if data.get('result') and data.get('mail_list'): + for mail in data['mail_list']: + if 'cursor.sh' in mail.get('from_mail', '') and mail.get('is_new') == True: + self._cached_mail_id = mail.get('mail_id') # 缓存mail_id + return True + return False + except Exception as e: + print(f"检查Cursor邮件失败: {str(e)}") + return False + + def get_verification_code(self) -> str: + """Get the verification code from the email + + Returns: + str: The verification code if found, empty string otherwise + """ + try: + # 如果没有缓存的mail_id,先检查是否有新邮件 + if not self._cached_mail_id: + if not self.check_for_cursor_email(): + return "" + + # 使用缓存的mail_id获取邮件内容 + params = { + 'email': self.email, + 'epin': self.epin + } + response = requests.get( + f"{self.base_url}/mails/{self._cached_mail_id}", + params=params, + headers=self.headers, + cookies=self.cookies + ) + response.raise_for_status() + + data = response.json() + if not data.get('result'): + return "" + + # Extract verification code from text content using regex + text = data.get('text', '') + match = re.search(r'\n\n(\d{6})\n\n', text) + if match: + return match.group(1) + + return "" + except Exception as e: + print(f"获取验证码失败: {str(e)}") + return "" \ No newline at end of file diff --git a/locales/en.json b/locales/en.json index ef4711b..a0977db 100644 --- a/locales/en.json +++ b/locales/en.json @@ -211,7 +211,18 @@ "try_install_browser": "Try installing the browser with your package manager", "tracking_processes": "Tracking {count} {browser} processes", "no_new_processes_detected": "No new {browser} processes detected to track", - "could_not_track_processes": "Could not track {browser} processes: {error}" + "could_not_track_processes": "Could not track {browser} processes: {error}", + "using_tempmail_plus": "Using TempMailPlus for email verification", + "tempmail_plus_enabled": "TempMailPlus is enabled", + "tempmail_plus_disabled": "TempMailPlus is disabled", + "tempmail_plus_config_missing": "TempMailPlus configuration is missing", + "tempmail_plus_email_missing": "TempMailPlus email is not configured", + "tempmail_plus_epin_missing": "TempMailPlus epin is not configured", + "tempmail_plus_initialized": "TempMailPlus initialized successfully", + "tempmail_plus_init_failed": "Failed to initialize TempMailPlus: {error}", + "tempmail_plus_verification_started": "Starting TempMailPlus verification process", + "tempmail_plus_verification_completed": "TempMailPlus verification completed successfully", + "tempmail_plus_verification_failed": "TempMailPlus verification failed: {error}" }, "auth": { "title": "Cursor Auth Manager", diff --git a/locales/zh_cn.json b/locales/zh_cn.json index bba962e..4221f5e 100644 --- a/locales/zh_cn.json +++ b/locales/zh_cn.json @@ -211,7 +211,18 @@ "no_new_processes_detected": "未检测到新的 {browser} 进程", "could_not_track_processes": "无法跟踪 {browser} 进程: {error}", "human_verify_error": "无法验证用户是人类,正在重试...", - "max_retries_reached": "已达到最大重试次数,注册失败。" + "max_retries_reached": "已达到最大重试次数,注册失败。", + "using_tempmail_plus": "使用TempMailPlus进行邮箱验证", + "tempmail_plus_enabled": "TempMailPlus已启用", + "tempmail_plus_disabled": "TempMailPlus已禁用", + "tempmail_plus_config_missing": "TempMailPlus配置缺失", + "tempmail_plus_email_missing": "未配置TempMailPlus邮箱", + "tempmail_plus_epin_missing": "未配置TempMailPlus epin", + "tempmail_plus_initialized": "TempMailPlus初始化成功", + "tempmail_plus_init_failed": "TempMailPlus初始化失败:{error}", + "tempmail_plus_verification_started": "开始TempMailPlus验证流程", + "tempmail_plus_verification_completed": "TempMailPlus验证成功完成", + "tempmail_plus_verification_failed": "TempMailPlus验证失败:{error}" }, "auth": { "title": "Cursor 认证管理器", @@ -649,7 +660,9 @@ "found_chrome_at": "找到 Chrome: {path}", "found_browser_user_data_dir": "找到 {browser} 用户数据目录: {path}", "select_profile": "选择要使用的 {browser} 配置文件:", - "profile_list": "可用 {browser} 配置文件:" + "profile_list": "可用 {browser} 配置文件:", + "chrome_permissions_fixed": "已修复 Chrome 用户数据目录权限", + "chrome_permissions_fix_failed": "修复 Chrome 权限失败: {error}" }, "browser_profile": { "title": "浏览器配置文件选择", diff --git a/locales/zh_tw.json b/locales/zh_tw.json index 3e8bf28..ecd8fa4 100644 --- a/locales/zh_tw.json +++ b/locales/zh_tw.json @@ -212,6 +212,17 @@ "could_not_track_processes": "無法跟踪{瀏覽器}進程:{error}", "human_verify_error": "無法驗證用戶是人類。重試...", "tracking_processes": "跟踪{count} {瀏覽器}進程" + "using_tempmail_plus": "使用TempMailPlus進行郵箱驗證", + "tempmail_plus_enabled": "TempMailPlus已啟用", + "tempmail_plus_disabled": "TempMailPlus已禁用", + "tempmail_plus_config_missing": "TempMailPlus配置缺失", + "tempmail_plus_email_missing": "未配置TempMailPlus郵箱", + "tempmail_plus_epin_missing": "未配置TempMailPlus epin", + "tempmail_plus_initialized": "TempMailPlus初始化成功", + "tempmail_plus_init_failed": "TempMailPlus初始化失敗:{error}", + "tempmail_plus_verification_started": "開始TempMailPlus驗證流程", + "tempmail_plus_verification_completed": "TempMailPlus驗證成功完成", + "tempmail_plus_verification_failed": "TempMailPlus驗證失敗:{error}" }, "auth": { "title": "Cursor 認證管理器", diff --git a/oauth_auth.py b/oauth_auth.py index c30c198..0dcc891 100644 --- a/oauth_auth.py +++ b/oauth_auth.py @@ -483,6 +483,25 @@ class OAuthHandler: print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('oauth.error_configuring_browser_options', error=str(e)) if self.translator else f'Error configuring browser options: {e}'}{Style.RESET_ALL}") raise + def _fix_chrome_permissions(self, user_data_dir): + """Fix permissions for Chrome user data directory""" + try: + if sys.platform == 'darwin': # macOS + import subprocess + import pwd + + # Get current user + current_user = pwd.getpwuid(os.getuid()).pw_name + + # Fix permissions for Chrome directory + chrome_dir = os.path.expanduser('~/Library/Application Support/Google/Chrome') + if os.path.exists(chrome_dir): + subprocess.run(['chmod', '-R', 'u+rwX', chrome_dir]) + subprocess.run(['chown', '-R', f'{current_user}:staff', chrome_dir]) + print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('oauth.chrome_permissions_fixed') if self.translator else 'Fixed Chrome user data directory permissions'}{Style.RESET_ALL}") + except Exception as e: + print(f"{Fore.YELLOW}{EMOJI['WARNING']} {self.translator.get('oauth.chrome_permissions_fix_failed', error=str(e)) if self.translator else f'Failed to fix Chrome permissions: {str(e)}'}{Style.RESET_ALL}") + def handle_google_auth(self): """Handle Google OAuth authentication""" try: @@ -493,6 +512,9 @@ class OAuthHandler: print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('oauth.browser_failed') if self.translator else 'Browser failed to initialize'}{Style.RESET_ALL}") return False, None + # Get user data directory for later use + user_data_dir = self._get_user_data_directory() + # Navigate to auth URL try: print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('oauth.navigating_to_authentication_page') if self.translator else 'Navigating to authentication page...'}{Style.RESET_ALL}") @@ -556,6 +578,8 @@ class OAuthHandler: try: if self.browser: self.browser.quit() + # Fix Chrome permissions after browser is closed + self._fix_chrome_permissions(user_data_dir) except: pass