Merge pull request #437 from Nigel1992/fix/433-linux-chrome-visibility

fix: improve Linux Chrome visibility and root user handling
This commit is contained in:
Pin Studios 2025-03-31 12:00:11 +08:00 committed by GitHub
commit 9793b91bc7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 433 additions and 151 deletions

View File

@ -85,28 +85,45 @@ def setup_config(translator=None):
elif sys.platform == "linux":
# Get the actual user's home directory, handling both sudo and normal cases
current_user = os.getenv('USER') or os.getenv('USERNAME') or os.getenv('SUDO_USER')
sudo_user = os.environ.get('SUDO_USER')
current_user = sudo_user if sudo_user else (os.getenv('USER') or os.getenv('USERNAME'))
if not current_user:
current_user = os.path.expanduser('~').split('/')[-1]
actual_home = f"/home/{current_user}"
# Handle sudo case
if sudo_user:
actual_home = f"/home/{sudo_user}"
root_home = "/root"
else:
actual_home = f"/home/{current_user}"
root_home = None
if not os.path.exists(actual_home):
actual_home = os.path.expanduser("~")
# Define base config directory
config_base = os.path.join(actual_home, ".config")
# Try both "Cursor" and "cursor" directory names
# Try both "Cursor" and "cursor" directory names in both user and root locations
cursor_dir = None
for dir_name in ["Cursor", "cursor"]:
test_dir = os.path.join(config_base, dir_name)
if os.path.exists(test_dir):
cursor_dir = test_dir
possible_paths = [
os.path.join(config_base, "Cursor"),
os.path.join(config_base, "cursor"),
os.path.join(root_home, ".config", "Cursor") if root_home else None,
os.path.join(root_home, ".config", "cursor") if root_home else None
]
for path in possible_paths:
if path and os.path.exists(path):
cursor_dir = path
break
if not cursor_dir:
print(f"{Fore.YELLOW}{EMOJI['WARNING']} {translator.get('config.neither_cursor_nor_cursor_directory_found', config_base=config_base)}{Style.RESET_ALL}")
print(f"{Fore.YELLOW}{EMOJI['INFO']} {translator.get('config.please_make_sure_cursor_is_installed_and_has_been_run_at_least_once')}{Style.RESET_ALL}")
print(f"{Fore.YELLOW}{EMOJI['WARNING']} {translator.get('config.neither_cursor_nor_cursor_directory_found', config_base=config_base) if translator else f'Neither Cursor nor cursor directory found in {config_base}'}{Style.RESET_ALL}")
if root_home:
print(f"{Fore.YELLOW}{EMOJI['INFO']} {translator.get('config.also_checked', path=f'{root_home}/.config') if translator else f'Also checked {root_home}/.config'}{Style.RESET_ALL}")
print(f"{Fore.YELLOW}{EMOJI['INFO']} {translator.get('config.please_make_sure_cursor_is_installed_and_has_been_run_at_least_once') if translator else 'Please make sure Cursor is installed and has been run at least once'}{Style.RESET_ALL}")
# Define Linux paths using the found cursor directory
storage_path = os.path.abspath(os.path.join(cursor_dir, "User/globalStorage/storage.json")) if cursor_dir else ""
@ -116,46 +133,50 @@ def setup_config(translator=None):
try:
# Check storage directory
if storage_dir and not os.path.exists(storage_dir):
print(f"{Fore.YELLOW}{EMOJI['WARNING']} {translator.get('config.storage_directory_not_found', storage_dir=storage_dir)}{Style.RESET_ALL}")
print(f"{Fore.YELLOW}{EMOJI['INFO']} {translator.get('config.please_make_sure_cursor_is_installed_and_has_been_run_at_least_once')}{Style.RESET_ALL}")
print(f"{Fore.YELLOW}{EMOJI['WARNING']} {translator.get('config.storage_directory_not_found', storage_dir=storage_dir) if translator else f'Storage directory not found: {storage_dir}'}{Style.RESET_ALL}")
print(f"{Fore.YELLOW}{EMOJI['INFO']} {translator.get('config.please_make_sure_cursor_is_installed_and_has_been_run_at_least_once') if translator else 'Please make sure Cursor is installed and has been run at least once'}{Style.RESET_ALL}")
# Check storage.json with more detailed verification
if storage_path and os.path.exists(storage_path):
# Get file stats
try:
stat = os.stat(storage_path)
print(f"{Fore.GREEN}{EMOJI['INFO']} {translator.get('config.storage_file_found', storage_path=storage_path)}{Style.RESET_ALL}")
print(f"{Fore.GREEN}{EMOJI['INFO']} {translator.get('config.file_size', stat.st_size)}{Style.RESET_ALL}")
print(f"{Fore.GREEN}{EMOJI['INFO']} {translator.get('config.file_permissions', oct(stat.st_mode & 0o777))}{Style.RESET_ALL}")
print(f"{Fore.GREEN}{EMOJI['INFO']} {translator.get('config.file_owner', stat.st_uid)}{Style.RESET_ALL}")
print(f"{Fore.GREEN}{EMOJI['INFO']} {translator.get('config.file_group', stat.st_gid)}{Style.RESET_ALL}")
print(f"{Fore.GREEN}{EMOJI['INFO']} {translator.get('config.storage_file_found', storage_path=storage_path) if translator else f'Storage file found: {storage_path}'}{Style.RESET_ALL}")
print(f"{Fore.GREEN}{EMOJI['INFO']} {translator.get('config.file_size', size=stat.st_size) if translator else f'File size: {stat.st_size} bytes'}{Style.RESET_ALL}")
print(f"{Fore.GREEN}{EMOJI['INFO']} {translator.get('config.file_permissions', permissions=oct(stat.st_mode & 0o777)) if translator else f'File permissions: {oct(stat.st_mode & 0o777)}'}{Style.RESET_ALL}")
print(f"{Fore.GREEN}{EMOJI['INFO']} {translator.get('config.file_owner', owner=stat.st_uid) if translator else f'File owner: {stat.st_uid}'}{Style.RESET_ALL}")
print(f"{Fore.GREEN}{EMOJI['INFO']} {translator.get('config.file_group', group=stat.st_gid) if translator else f'File group: {stat.st_gid}'}{Style.RESET_ALL}")
except Exception as e:
print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('config.error_getting_file_stats', error=str(e))}{Style.RESET_ALL}")
print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('config.error_getting_file_stats', error=str(e)) if translator else f'Error getting file stats: {str(e)}'}{Style.RESET_ALL}")
# Check if file is readable and writable
if not os.access(storage_path, os.R_OK | os.W_OK):
print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('config.permission_denied', storage_path=storage_path)}{Style.RESET_ALL}")
print(f"{Fore.YELLOW}{EMOJI['INFO']} {translator.get('config.try_running', current_user=current_user, storage_path=storage_path)}{Style.RESET_ALL}")
print(f"{Fore.YELLOW}{EMOJI['INFO']} {translator.get('config.and', storage_path=storage_path)}{Style.RESET_ALL}")
print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('config.permission_denied', storage_path=storage_path) if translator else f'Permission denied: {storage_path}'}{Style.RESET_ALL}")
if sudo_user:
print(f"{Fore.YELLOW}{EMOJI['INFO']} {translator.get('config.try_running', command=f'chown {sudo_user}:{sudo_user} {storage_path}') if translator else f'Try running: chown {sudo_user}:{sudo_user} {storage_path}'}{Style.RESET_ALL}")
print(f"{Fore.YELLOW}{EMOJI['INFO']} {translator.get('config.and') if translator else 'And'}: chmod 644 {storage_path}{Style.RESET_ALL}")
else:
print(f"{Fore.YELLOW}{EMOJI['INFO']} {translator.get('config.try_running', command=f'chown {current_user}:{current_user} {storage_path}') if translator else f'Try running: chown {current_user}:{current_user} {storage_path}'}{Style.RESET_ALL}")
print(f"{Fore.YELLOW}{EMOJI['INFO']} {translator.get('config.and') if translator else 'And'}: chmod 644 {storage_path}{Style.RESET_ALL}")
# Try to read the file to verify it's not corrupted
try:
with open(storage_path, 'r') as f:
content = f.read()
if not content.strip():
print(f"{Fore.YELLOW}{EMOJI['WARNING']} {translator.get('config.storage_file_is_empty', storage_path=storage_path)}{Style.RESET_ALL}")
print(f"{Fore.YELLOW}{EMOJI['INFO']} {translator.get('config.please_make_sure_cursor_is_installed_and_has_been_run_at_least_once')}{Style.RESET_ALL}")
print(f"{Fore.YELLOW}{EMOJI['WARNING']} {translator.get('config.storage_file_is_empty', storage_path=storage_path) if translator else f'Storage file is empty: {storage_path}'}{Style.RESET_ALL}")
print(f"{Fore.YELLOW}{EMOJI['INFO']} {translator.get('config.the_file_might_be_corrupted_please_reinstall_cursor') if translator else 'The file might be corrupted, please reinstall Cursor'}{Style.RESET_ALL}")
else:
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {translator.get('config.storage_file_is_valid_and_contains_data')}{Style.RESET_ALL}")
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {translator.get('config.storage_file_is_valid_and_contains_data') if translator else 'Storage file is valid and contains data'}{Style.RESET_ALL}")
except Exception as e:
print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('config.error_reading_storage_file', error=str(e))}{Style.RESET_ALL}")
print(f"{Fore.YELLOW}{EMOJI['INFO']} {translator.get('config.the_file_might_be_corrupted_please_reinstall_cursor')}{Style.RESET_ALL}")
print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('config.error_reading_storage_file', error=str(e)) if translator else f'Error reading storage file: {str(e)}'}{Style.RESET_ALL}")
print(f"{Fore.YELLOW}{EMOJI['INFO']} {translator.get('config.the_file_might_be_corrupted_please_reinstall_cursor') if translator else 'The file might be corrupted. Please reinstall Cursor'}{Style.RESET_ALL}")
elif storage_path:
print(f"{Fore.YELLOW}{EMOJI['WARNING']} {translator.get('config.storage_file_not_found', storage_path=storage_path)}{Style.RESET_ALL}")
print(f"{Fore.YELLOW}{EMOJI['INFO']} {translator.get('config.please_make_sure_cursor_is_installed_and_has_been_run_at_least_once')}{Style.RESET_ALL}")
print(f"{Fore.YELLOW}{EMOJI['WARNING']} {translator.get('config.storage_file_not_found', storage_path=storage_path) if translator else f'Storage file not found: {storage_path}'}{Style.RESET_ALL}")
print(f"{Fore.YELLOW}{EMOJI['INFO']} {translator.get('config.please_make_sure_cursor_is_installed_and_has_been_run_at_least_once') if translator else 'Please make sure Cursor is installed and has been run at least once'}{Style.RESET_ALL}")
except (OSError, IOError) as e:
print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('config.error_checking_linux_paths', error=str(e))}{Style.RESET_ALL}")
print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('config.error_checking_linux_paths', error=str(e)) if translator else f'Error checking Linux paths: {str(e)}'}{Style.RESET_ALL}")
# Define all paths using the found cursor directory
default_config['LinuxPaths'] = {
@ -181,13 +202,13 @@ def setup_config(translator=None):
config.set(section, option, str(value))
config_modified = True
if translator:
print(f"{Fore.YELLOW}{EMOJI['INFO']} {translator.get('register.config_option_added', option=f'{section}.{option}')}{Style.RESET_ALL}")
print(f"{Fore.YELLOW}{EMOJI['INFO']} {translator.get('config.config_option_added', option=f'{section}.{option}') if translator else f'Config option added: {section}.{option}'}{Style.RESET_ALL}")
if config_modified:
with open(config_file, 'w', encoding='utf-8') as f:
config.write(f)
if translator:
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {translator.get('register.config_updated')}{Style.RESET_ALL}")
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {translator.get('config.config_updated') if translator else 'Config updated'}{Style.RESET_ALL}")
else:
for section, options in default_config.items():
config.add_section(section)
@ -197,31 +218,31 @@ def setup_config(translator=None):
with open(config_file, 'w', encoding='utf-8') as f:
config.write(f)
if translator:
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {translator.get('register.config_created')}: {config_file}{Style.RESET_ALL}")
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {translator.get('config.config_created', config_file=config_file) if translator else f'Config created: {config_file}'}{Style.RESET_ALL}")
return config
except Exception as e:
if translator:
print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('register.config_setup_error', error=str(e))}{Style.RESET_ALL}")
print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('config.config_setup_error', error=str(e)) if translator else f'Error setting up config: {str(e)}'}{Style.RESET_ALL}")
return None
def print_config(config, translator=None):
"""Print configuration in a readable format"""
if not config:
print(f"{Fore.YELLOW}{EMOJI['WARNING']} {translator.get('config.config_not_available')}{Style.RESET_ALL}")
print(f"{Fore.YELLOW}{EMOJI['WARNING']} {translator.get('config.config_not_available') if translator else 'Configuration not available'}{Style.RESET_ALL}")
return
print(f"\n{Fore.CYAN}{EMOJI['INFO']} {translator.get('config.configuration')}:{Style.RESET_ALL}")
print(f"\n{Fore.CYAN}{EMOJI['INFO']} {translator.get('config.configuration') if translator else 'Configuration'}:{Style.RESET_ALL}")
print(f"\n{Fore.CYAN}{'' * 70}{Style.RESET_ALL}")
for section in config.sections():
print(f"{Fore.GREEN}[{section}]{Style.RESET_ALL}")
for key, value in config.items(section):
# 对布尔值进行特殊处理,使其显示为彩色
if value.lower() in ('true', 'yes', 'on', '1'):
value_display = f"{Fore.GREEN}{translator.get('config.enabled')}{Style.RESET_ALL}"
value_display = f"{Fore.GREEN}{translator.get('config.enabled') if translator else 'Enabled'}{Style.RESET_ALL}"
elif value.lower() in ('false', 'no', 'off', '0'):
value_display = f"{Fore.RED}{translator.get('config.disabled')}{Style.RESET_ALL}"
value_display = f"{Fore.RED}{translator.get('config.disabled') if translator else 'Disabled'}{Style.RESET_ALL}"
else:
value_display = value
@ -229,7 +250,7 @@ def print_config(config, translator=None):
print(f"\n{Fore.CYAN}{'' * 70}{Style.RESET_ALL}")
config_dir = os.path.join(get_user_documents_path(), ".cursor-free-vip", "config.ini")
print(f"{Fore.CYAN}{EMOJI['INFO']} {translator.get('config.config_directory')}: {config_dir}{Style.RESET_ALL}")
print(f"{Fore.CYAN}{EMOJI['INFO']} {translator.get('config.config_directory') if translator else 'Config Directory'}: {config_dir}{Style.RESET_ALL}")
print()

View File

@ -280,7 +280,13 @@
"available_domains_loaded": "Available Domains Loaded: {count}",
"domains_filtered": "Domains Filtered: {count}",
"trying_to_create_email": "Trying to create email: {email}",
"domain_blocked": "Domain Blocked: {domain}"
"domain_blocked": "Domain Blocked: {domain}",
"using_chrome_profile": "Using Chrome profile from: {user_data_dir}",
"no_display_found": "No display found. Make sure X server is running.",
"try_export_display": "Try: export DISPLAY=:0",
"extension_load_error": "Extension Load Error: {error}",
"make_sure_chrome_chromium_is_properly_installed": "Make sure Chrome/Chromium is properly installed",
"try_install_chromium": "Try: sudo apt install chromium-browser"
},
"update": {
"title": "Disable Cursor Auto Update",
@ -498,14 +504,14 @@
"please_make_sure_cursor_is_installed_and_has_been_run_at_least_once": "Please make sure Cursor is installed and has been run at least once",
"storage_directory_not_found": "Storage directory not found: {storage_dir}",
"storage_file_found": "Storage file found: {storage_path}",
"file_size": "File size: {size}",
"file_size": "File size: {size} bytes",
"file_permissions": "File permissions: {permissions}",
"file_owner": "File owner: {owner}",
"file_group": "File group: {group}",
"error_getting_file_stats": "Error getting file stats: {error}",
"permission_denied": "Permission denied: {storage_path}",
"try_running": "Try running 'cursor --help' to check if it's installed",
"and": "and",
"try_running": "Try running: {command}",
"and": "And",
"storage_file_is_empty": "Storage file is empty: {storage_path}",
"the_file_might_be_corrupted_please_reinstall_cursor": "The file might be corrupted, please reinstall Cursor",
"storage_file_not_found": "Storage file not found: {storage_path}",
@ -513,7 +519,64 @@
"config_option_added": "Config option added: {option}",
"config_updated": "Config updated",
"config_created": "Config created: {config_file}",
"config_setup_error": "Error setting up config: {error}"
"config_setup_error": "Error setting up config: {error}",
"storage_file_is_valid_and_contains_data": "Storage file is valid and contains data",
"error_reading_storage_file": "Error reading storage file: {error}",
"also_checked": "Also checked {path}"
},
"oauth": {
"authentication_button_not_found": "Authentication button not found",
"authentication_failed": "Authentication failed: {error}",
"found_cookies": "Found {count} cookies",
"token_extraction_error": "Token extraction error: {error}",
"authentication_successful": "Authentication successful - Email: {email}",
"missing_authentication_data": "Missing authentication data: {data}",
"failed_to_delete_account": "Failed to delete account: {error}",
"invalid_authentication_type": "Invalid authentication type",
"auth_update_success": "Auth update success",
"browser_closed": "Browser closed",
"auth_update_failed": "Auth update failed",
"google_start": "Google start",
"github_start": "Github start",
"usage_count": "Usage count: {usage}",
"account_has_reached_maximum_usage": "Account has reached maximum usage, {deleting}",
"starting_new_authentication_process": "Starting new authentication process...",
"failed_to_delete_expired_account": "Failed to delete expired account",
"could_not_check_usage_count": "Could not check usage count: {error}",
"found_email": "Found email: {email}",
"could_not_find_email": "Could not find email: {error}",
"could_not_find_usage_count": "Could not find usage count: {error}",
"already_on_settings_page": "Already on settings page!",
"failed_to_extract_auth_info": "Failed to extract auth info: {error}",
"no_chrome_profiles_found": "No Chrome profiles found, using Default",
"found_default_chrome_profile": "Found Default Chrome profile",
"using_first_available_chrome_profile": "Using first available Chrome profile: {profile}",
"error_finding_chrome_profile": "Error finding Chrome profile, using Default: {error}",
"initializing_browser_setup": "Initializing browser setup...",
"detected_platform": "Detected platform: {platform}",
"running_as_root_warning": "Running as root is not recommended for browser automation",
"consider_running_without_sudo": "Consider running the script without sudo",
"no_compatible_browser_found": "No compatible browser found. Please install Google Chrome or Chromium.",
"supported_browsers": "Supported browsers for {platform}",
"using_browser_profile": "Using browser profile: {profile}",
"starting_browser": "Starting browser at: {path}",
"browser_setup_completed": "Browser setup completed successfully",
"browser_setup_failed": "Browser setup failed: {error}",
"try_running_without_sudo_admin": "Try running without sudo/administrator privileges",
"redirecting_to_authenticator_cursor_sh": "Redirecting to authenticator.cursor.sh...",
"starting_google_authentication": "Starting Google authentication...",
"starting_github_authentication": "Starting GitHub authentication...",
"waiting_for_authentication": "Waiting for authentication...",
"page_changed_checking_auth": "Page changed, checking auth...",
"status_check_error": "Status check error: {error}",
"authentication_timeout": "Authentication timeout",
"account_is_still_valid": "Account is still valid (Usage: {usage})",
"starting_re_authentication_process": "Starting re-authentication process...",
"starting_new_google_authentication": "Starting new Google authentication...",
"failed_to_delete_account_or_re_authenticate": "Failed to delete account or re-authenticate: {error}",
"navigating_to_authentication_page": "Navigating to authentication page...",
"please_select_your_google_account_to_continue": "Please select your Google account to continue...",
"found_browser_data_directory": "Found browser data directory: {path}",
"authentication_successful_getting_account_info": "Authentication successful, getting account info..."
}
}

View File

@ -275,7 +275,13 @@
"available_domains_loaded": "获取到 {count} 个可用域名",
"domains_filtered": "过滤后剩餘 {count} 個可用域名",
"trying_to_create_email": "尝试创建邮箱: {email}",
"domain_blocked": "域名被屏蔽: {domain}"
"domain_blocked": "域名被屏蔽: {domain}",
"using_chrome_profile": "使用 Chrome 配置文件: {user_data_dir}",
"no_display_found": "未找到显示器。确保 X 服务器正在运行。",
"try_export_display": "尝试: export DISPLAY=:0",
"extension_load_error": "加载插件失败: {error}",
"make_sure_chrome_chromium_is_properly_installed": "确保 Chrome/Chromium 已正确安装",
"try_install_chromium": "尝试: sudo apt install chromium-browser"
},
"update": {
"title": "禁用 Cursor 自动更新",
@ -499,7 +505,7 @@
"file_group": "文件组",
"error_getting_file_stats": "获取文件统计信息时出错",
"permission_denied": "权限拒绝",
"try_running": "尝试运行 'cursor --help' 检查是否已安装",
"try_running": "尝试运行: {command}",
"and": "和",
"storage_file_is_empty": "存储文件为空",
"the_file_might_be_corrupted_please_reinstall_cursor": "文件可能已损坏,请重新安装 Cursor",
@ -508,7 +514,65 @@
"config_option_added": "添加配置选项",
"config_updated": "配置更新",
"config_created": "配置已创建",
"config_setup_error": "配置设置错误"
"config_setup_error": "配置设置错误",
"storage_file_is_valid_and_contains_data": "存储文件有效且包含数据",
"error_reading_storage_file": "读取存储文件时出错",
"also_checked": "也检查了 {path}"
},
"oauth": {
"authentication_button_not_found": "未找到认证按钮",
"authentication_failed": "认证失败: {error}",
"found_cookies": "找到 {count} 个 Cookie",
"token_extraction_error": "Token 提取错误: {error}",
"authentication_successful": "认证成功 - 邮箱: {email}",
"missing_authentication_data": "缺少认证数据: {data}",
"failed_to_delete_account": "删除账户失败: {error}",
"invalid_authentication_type": "无效的认证类型",
"auth_update_success": "认证更新成功",
"browser_closed": "浏览器已关闭",
"auth_update_failed": "认证更新失败",
"google_start": "Google 开始",
"github_start": "Github 开始",
"usage_count": "使用次数: {usage}",
"account_has_reached_maximum_usage": "账户已达到最大使用量, {deleting}",
"starting_new_authentication_process": "开始新的认证过程...",
"failed_to_delete_expired_account": "删除过期账户失败",
"could_not_check_usage_count": "无法检查使用次数: {error}",
"found_email": "找到邮箱: {email}",
"could_not_find_email": "未找到邮箱: {error}",
"could_not_find_usage_count": "未找到使用次数: {error}",
"already_on_settings_page": "已处于设置页面",
"failed_to_extract_auth_info": "提取认证信息失败: {error}",
"no_chrome_profiles_found": "未找到 Chrome 配置文件, 使用默认配置文件",
"found_default_chrome_profile": "找到默认 Chrome 配置文件",
"using_first_available_chrome_profile": "使用第一个可用的 Chrome 配置文件: {profile}",
"error_finding_chrome_profile": "找不到 Chrome 配置文件, 使用默认配置文件: {error}",
"initializing_browser_setup": "初始化浏览器设置...",
"detected_platform": "检测平台: {platform}",
"running_as_root_warning": "以 root 运行不推荐用于浏览器自动化",
"consider_running_without_sudo": "考虑不使用 sudo 运行脚本",
"no_compatible_browser_found": "未找到兼容的浏览器。请安装 Google Chrome 或 Chromium。",
"supported_browsers": "支持的浏览器: {platform}",
"using_browser_profile": "使用浏览器配置文件: {profile}",
"starting_browser": "正在启动浏览器: {path}",
"browser_setup_completed": "浏览器设置完成",
"browser_setup_failed": "浏览器设置失败: {error}",
"try_running_without_sudo_admin": "尝试不使用 sudo/管理员权限运行",
"redirecting_to_authenticator_cursor_sh": "重定向到 authenticator.cursor.sh...",
"starting_google_authentication": "开始 Google 认证...",
"starting_github_authentication": "开始 Github 认证...",
"waiting_for_authentication": "等待认证...",
"page_changed_checking_auth": "页面改变, 检查认证...",
"status_check_error": "状态检查错误: {error}",
"authentication_timeout": "认证超时",
"account_is_still_valid": "账户仍然有效 (使用量: {usage})",
"starting_re_authentication_process": "开始重新认证过程...",
"starting_new_google_authentication": "开始新的 Google 认证...",
"failed_to_delete_account_or_re_authenticate": "删除账户或重新认证失败: {error}",
"navigating_to_authentication_page": "正在导航到认证页面...",
"please_select_your_google_account_to_continue": "请选择您的 Google 账户以继续...",
"found_browser_data_directory": "找到浏览器数据目录: {path}",
"authentication_successful_getting_account_info": "认证成功, 获取账户信息..."
}
}

View File

@ -254,7 +254,14 @@
"blocked_domains_loaded_timeout_error": "加載被屏蔽的域名超時錯誤: {error}",
"available_domains_loaded": "獲取到 {count} 個可用域名",
"domains_filtered": "過濾後剩餘 {count} 個可用域名",
"trying_to_create_email": "嘗試創建郵箱: {email}"
"trying_to_create_email": "嘗試創建郵箱: {email}",
"domain_blocked": "域名被屏蔽: {domain}",
"using_chrome_profile": "使用 Chrome 配置文件: {user_data_dir}",
"no_display_found": "未找到顯示器。確保 X 伺服器正在運行。",
"try_export_display": "嘗試: export DISPLAY=:0",
"extension_load_error": "加載插件失敗: {error}",
"make_sure_chrome_chromium_is_properly_installed": "確保 Chrome/Chromium 已正確安裝",
"try_install_chromium": "嘗試: sudo apt install chromium-browser"
},
"update": {
"title": "禁用 Cursor 自动更新",
@ -478,7 +485,7 @@
"file_group": "文件組",
"error_getting_file_stats": "獲取文件統計信息時出錯",
"permission_denied": "權限拒絕",
"try_running": "嘗試運行 'cursor --help' 檢查是否已安裝",
"try_running": "嘗試運行: {command}",
"and": "和",
"storage_file_is_empty": "儲存文件為空",
"the_file_might_be_corrupted_please_reinstall_cursor": "文件可能已損壞,請重新安裝 Cursor",
@ -487,7 +494,64 @@
"config_option_added": "添加配置選項",
"config_updated": "配置更新",
"config_created": "配置已創建",
"config_setup_error": "配置設置錯誤"
"config_setup_error": "配置設置錯誤",
"storage_file_is_valid_and_contains_data": "儲存文件有效且包含數據",
"error_reading_storage_file": "讀取儲存文件時出錯",
"also_checked": "也檢查了 {path}"
},
"oauth": {
"authentication_button_not_found": "未找到認證按鈕",
"authentication_failed": "認證失敗: {error}",
"found_cookies": "找到 {count} 個 Cookie",
"token_extraction_error": "Token 提取錯誤: {error}",
"authentication_successful": "認證成功 - 郵箱: {email}",
"missing_authentication_data": "缺少認證數據: {data}",
"failed_to_delete_account": "刪除帳戶失敗: {error}",
"invalid_authentication_type": "無效的認證類型",
"auth_update_success": "認證更新成功",
"browser_closed": "瀏覽器已關閉",
"auth_update_failed": "認證更新失敗",
"google_start": "Google 開始",
"github_start": "Github 開始",
"usage_count": "使用量: {usage}",
"account_has_reached_maximum_usage": "帳戶已達到最大使用量, {deleting}",
"starting_new_authentication_process": "開始新的認證過程...",
"failed_to_delete_expired_account": "刪除過期帳戶失敗",
"could_not_check_usage_count": "無法檢查使用量: {error}",
"found_email": "找到郵箱: {email}",
"could_not_find_email": "未找到郵箱: {error}",
"could_not_find_usage_count": "未找到使用量: {erro r}",
"already_on_settings_page": "已處於設置頁面",
"failed_to_extract_auth_info": "提取認證信息失敗: {error}",
"no_chrome_profiles_found": "未找到 Chrome 配置文件, 使用默認配置文件",
"found_default_chrome_profile": "找到默認 Chrome 配置文件",
"using_first_available_chrome_profile": "使用第一個可用的 Chrome 配置文件: {profile}",
"error_finding_chrome_profile": "找不到 Chrome 配置文件, 使用默認配置文件: {error}",
"initializing_browser_setup": "初始化瀏覽器設置...",
"detected_platform": "檢測平台: {platform}",
"running_as_root_warning": "以 root 運行不推薦用於瀏覽器自動化",
"consider_running_without_sudo": "考慮不使用 sudo 運行腳本",
"no_compatible_browser_found": "未找到兼容的瀏覽器。請安裝 Google Chrome 或 Chromium。",
"supported_browsers": "支持的瀏覽器: {platform}",
"using_browser_profile": "使用瀏覽器配置文件: {profile}",
"starting_browser": "正在啟動瀏覽器: {path}",
"browser_setup_completed": "瀏覽器設置完成成功",
"browser_setup_failed": "瀏覽器設置失敗: {error}",
"try_running_without_sudo_admin": "嘗試不使用 sudo/管理員權限運行",
"redirecting_to_authenticator_cursor_sh": "重定向到 authenticator.cursor.sh...",
"starting_github_authentication": "開始 Github 認證...",
"waiting_for_authentication": "等待認證...",
"page_changed_checking_auth": "頁面改變, 檢查認證...",
"status_check_error": "狀態檢查錯誤: {error}",
"authentication_timeout": "認證超時",
"account_is_still_valid": "帳戶仍然有效 (使用量: {usage})",
"starting_re_authentication_process": "開始重新認證過程...",
"starting_new_google_authentication": "開始新的 Google 認證...",
"failed_to_delete_account_or_re_authenticate": "刪除帳戶或重新認證失敗: {error}",
"navigating_to_authentication_page": "正在導航到認證頁面...",
"please_select_your_google_account_to_continue": "請選擇您的 Google 帳戶以繼續...",
"found_browser_data_directory": "找到瀏覽器數據目錄: {path}",
"authentication_successful_getting_account_info": "認證成功, 獲取帳戶信息..."
}
}

View File

@ -106,11 +106,31 @@ class NewTempEmail:
# 创建浏览器选项
co = ChromiumOptions()
co.set_argument("--headless=new")
# Only use headless for non-OAuth operations
if not hasattr(self, 'auth_type') or self.auth_type != 'oauth':
co.set_argument("--headless=new")
if sys.platform == "linux":
co.set_argument("--no-sandbox")
# Check if DISPLAY is set when not in headless mode
if not co.arguments.get("--headless=new") and not os.environ.get('DISPLAY'):
print(f"{Fore.RED}{self.translator.get('email.no_display_found') if self.translator else 'No display found. Make sure X server is running.'}{Style.RESET_ALL}")
print(f"{Fore.YELLOW} {self.translator.get('email.try_export_display') if self.translator else 'Try: export DISPLAY=:0'}{Style.RESET_ALL}")
return False
co.set_argument("--no-sandbox")
co.set_argument("--disable-dev-shm-usage")
co.set_argument("--disable-gpu")
# If running as root, try to use actual user's Chrome profile
if os.geteuid() == 0:
sudo_user = os.environ.get('SUDO_USER')
if sudo_user:
actual_home = f"/home/{sudo_user}"
user_data_dir = os.path.join(actual_home, ".config", "google-chrome")
if os.path.exists(user_data_dir):
print(f"{Fore.CYAN} {self.translator.get('email.using_chrome_profile', user_data_dir=user_data_dir) if self.translator else f'Using Chrome profile from: {user_data_dir}'}{Style.RESET_ALL}")
co.set_argument(f"--user-data-dir={user_data_dir}")
co.auto_port() # 自动设置端口
@ -132,6 +152,10 @@ class NewTempEmail:
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}")
if sys.platform == "linux":
print(f"{Fore.YELLOW} {self.translator.get('email.make_sure_chrome_chromium_is_properly_installed') if self.translator else 'Make sure Chrome/Chromium is properly installed'}{Style.RESET_ALL}")
print(f"{Fore.YELLOW} {self.translator.get('email.try_install_chromium') if self.translator else 'Try: sudo apt install chromium-browser'}{Style.RESET_ALL}")
return False
def create_email(self):

View File

@ -21,7 +21,8 @@ EMOJI = {
'SUCCESS': '',
'ERROR': '',
'WAIT': '',
'INFO': ''
'INFO': '',
'WARNING': '⚠️'
}
class OAuthHandler:
@ -42,12 +43,12 @@ class OAuthHandler:
profiles.append(item)
if not profiles:
print(f"{Fore.YELLOW}{EMOJI['INFO']} No Chrome profiles found, using Default{Style.RESET_ALL}")
print(f"{Fore.YELLOW}{EMOJI['INFO']} {self.translator.get('oauth.no_chrome_profiles_found') if self.translator else 'No Chrome profiles found, using Default'}{Style.RESET_ALL}")
return 'Default'
# First check if Default profile exists
if 'Default' in profiles:
print(f"{Fore.CYAN}{EMOJI['INFO']} Found Default Chrome profile{Style.RESET_ALL}")
print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('oauth.found_default_chrome_profile') if self.translator else 'Found Default Chrome profile'}{Style.RESET_ALL}")
return 'Default'
# If no Default profile, check Local State for last used profile
@ -69,21 +70,35 @@ class OAuthHandler:
return profile
# If no profile found in Local State, use the first available profile
print(f"{Fore.CYAN}{EMOJI['INFO']} Using first available Chrome profile: {profiles[0]}{Style.RESET_ALL}")
print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('oauth.using_first_available_chrome_profile', profile=profiles[0]) if self.translator else f'Using first available Chrome profile: {profiles[0]}'}{Style.RESET_ALL}")
return profiles[0]
except Exception as e:
print(f"{Fore.YELLOW}{EMOJI['INFO']} Error finding Chrome profile, using Default: {str(e)}{Style.RESET_ALL}")
print(f"{Fore.YELLOW}{EMOJI['INFO']} {self.translator.get('oauth.error_finding_chrome_profile', error=str(e)) if self.translator else f'Error finding Chrome profile, using Default: {str(e)}'}{Style.RESET_ALL}")
return 'Default'
def setup_browser(self):
"""Setup browser for OAuth flow using active profile"""
try:
print(f"{Fore.CYAN}{EMOJI['INFO']} Initializing browser setup...{Style.RESET_ALL}")
print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('oauth.initializing_browser_setup') if self.translator else 'Initializing browser setup...'}{Style.RESET_ALL}")
# Platform-specific initialization
platform_name = platform.system().lower()
print(f"{Fore.CYAN}{EMOJI['INFO']} Detected platform: {platform_name}{Style.RESET_ALL}")
print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('oauth.detected_platform', platform=platform_name) if self.translator else f'Detected platform: {platform_name}'}{Style.RESET_ALL}")
# Linux-specific checks
if platform_name == 'linux':
# Check if DISPLAY is set
display = os.environ.get('DISPLAY')
if not display:
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('oauth.no_display_found') if self.translator else 'No display found. Make sure X server is running.'}{Style.RESET_ALL}")
print(f"{Fore.YELLOW}{EMOJI['INFO']} {self.translator.get('oauth.try_export_display') if self.translator else 'Try: export DISPLAY=:0'}{Style.RESET_ALL}")
return False
# Check if running as root
if os.geteuid() == 0:
print(f"{Fore.YELLOW}{EMOJI['WARNING']} {self.translator.get('oauth.running_as_root_warning') if self.translator else 'Running as root is not recommended for browser automation'}{Style.RESET_ALL}")
print(f"{Fore.YELLOW}{EMOJI['INFO']} {self.translator.get('oauth.consider_running_without_sudo') if self.translator else 'Consider running the script without sudo'}{Style.RESET_ALL}")
# Kill existing browser processes
self._kill_browser_processes()
@ -93,34 +108,64 @@ class OAuthHandler:
chrome_path = self._get_browser_path()
if not chrome_path:
raise Exception(f"No compatible browser found. Please install Google Chrome or Chromium.\nSupported browsers for {platform_name}:\n" +
raise Exception(f"{self.translator.get('oauth.no_compatible_browser_found') if self.translator else 'No compatible browser found. Please install Google Chrome or Chromium.'}\n{self.translator.get('oauth.supported_browsers', platform=platform_name)}\n" +
"- Windows: Google Chrome, Chromium\n" +
"- macOS: Google Chrome, Chromium\n" +
"- Linux: Google Chrome, Chromium, chromium-browser")
# Get active profile
active_profile = self._get_active_profile(user_data_dir)
print(f"{Fore.CYAN}{EMOJI['INFO']} Using browser profile: {active_profile}{Style.RESET_ALL}")
print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('oauth.using_browser_profile', profile=active_profile) if self.translator else f'Using browser profile: {active_profile}'}{Style.RESET_ALL}")
# Configure browser options
co = self._configure_browser_options(chrome_path, user_data_dir, active_profile)
co = ChromiumOptions()
print(f"{Fore.CYAN}{EMOJI['INFO']} Starting browser at: {chrome_path}{Style.RESET_ALL}")
# Never use headless mode for OAuth flows
co.headless(False)
# Platform-specific options
if os.name == 'linux':
co.set_argument('--no-sandbox')
co.set_argument('--disable-dev-shm-usage')
co.set_argument('--disable-gpu')
# If running as root, try to use actual user's Chrome profile
if os.geteuid() == 0:
sudo_user = os.environ.get('SUDO_USER')
if sudo_user:
actual_home = f"/home/{sudo_user}"
user_data_dir = os.path.join(actual_home, ".config", "google-chrome")
if os.path.exists(user_data_dir):
print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('oauth.using_chrome_profile_from', user_data_dir=user_data_dir) if self.translator else f'Using Chrome profile from: {user_data_dir}'}{Style.RESET_ALL}")
co.set_argument(f"--user-data-dir={user_data_dir}")
# Set paths and profile
co.set_paths(browser_path=chrome_path, user_data_path=user_data_dir)
co.set_argument(f'--profile-directory={active_profile}')
# Basic options
co.set_argument('--no-first-run')
co.set_argument('--no-default-browser-check')
# co.auto_port()
print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('oauth.starting_browser', path=chrome_path) if self.translator else f'Starting browser at: {chrome_path}'}{Style.RESET_ALL}")
self.browser = ChromiumPage(co)
# Verify browser launched successfully
if not self.browser:
raise Exception("Failed to initialize browser instance")
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} Browser setup completed successfully{Style.RESET_ALL}")
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('oauth.browser_setup_completed') if self.translator else 'Browser setup completed successfully'}{Style.RESET_ALL}")
return True
except Exception as e:
print(f"{Fore.RED}{EMOJI['ERROR']} Browser setup failed: {str(e)}{Style.RESET_ALL}")
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('oauth.browser_setup_failed', error=str(e)) if self.translator else f'Browser setup failed: {str(e)}'}{Style.RESET_ALL}")
if "DevToolsActivePort file doesn't exist" in str(e):
print(f"{Fore.YELLOW}{EMOJI['INFO']} Try running with administrator/root privileges{Style.RESET_ALL}")
print(f"{Fore.YELLOW}{EMOJI['INFO']} {self.translator.get('oauth.try_running_without_sudo_admin') if self.translator else 'Try running without sudo/administrator privileges'}{Style.RESET_ALL}")
elif "Chrome failed to start" in str(e):
print(f"{Fore.YELLOW}{EMOJI['INFO']} Make sure Chrome/Chromium is properly installed{Style.RESET_ALL}")
print(f"{Fore.YELLOW}{EMOJI['INFO']} {self.translator.get('oauth.make_sure_chrome_chromium_is_properly_installed') if self.translator else 'Make sure Chrome/Chromium is properly installed'}{Style.RESET_ALL}")
if platform_name == 'linux':
print(f"{Fore.YELLOW}{EMOJI['INFO']} {self.translator.get('oauth.try_install_chromium') if self.translator else 'Try: sudo apt install chromium-browser'}{Style.RESET_ALL}")
return False
def _kill_browser_processes(self):
@ -137,7 +182,7 @@ class OAuthHandler:
time.sleep(1) # Wait for processes to close
except Exception as e:
print(f"{Fore.YELLOW}{EMOJI['INFO']} Warning: Could not kill existing browser processes: {e}{Style.RESET_ALL}")
print(f"{Fore.YELLOW}{EMOJI['INFO']} {self.translator.get('oauth.warning_could_not_kill_existing_browser_processes', error=str(e)) if self.translator else f'Warning: Could not kill existing browser processes: {e}'}{Style.RESET_ALL}")
def _get_user_data_directory(self):
"""Get the appropriate user data directory based on platform"""
@ -163,17 +208,17 @@ class OAuthHandler:
# Try each possible path
for path in possible_paths:
if os.path.exists(path):
print(f"{Fore.CYAN}{EMOJI['INFO']} Found browser data directory: {path}{Style.RESET_ALL}")
print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('oauth.found_browser_data_directory', path=path) if self.translator else f'Found browser data directory: {path}'}{Style.RESET_ALL}")
return path
# Create temporary profile if no existing profile found
temp_profile = os.path.join(os.path.expanduser('~'), '.cursor_temp_profile')
print(f"{Fore.YELLOW}{EMOJI['INFO']} Creating temporary profile at: {temp_profile}{Style.RESET_ALL}")
print(f"{Fore.YELLOW}{EMOJI['INFO']} {self.translator.get('oauth.creating_temporary_profile', path=temp_profile) if self.translator else f'Creating temporary profile at: {temp_profile}'}{Style.RESET_ALL}")
os.makedirs(temp_profile, exist_ok=True)
return temp_profile
except Exception as e:
print(f"{Fore.RED}{EMOJI['ERROR']} Error getting user data directory: {e}{Style.RESET_ALL}")
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('oauth.error_getting_user_data_directory', error=str(e)) if self.translator else f'Error getting user data directory: {e}'}{Style.RESET_ALL}")
raise
def _get_browser_path(self):
@ -184,7 +229,7 @@ class OAuthHandler:
if chrome_path and os.path.exists(chrome_path):
return chrome_path
print(f"{Fore.YELLOW}{EMOJI['INFO']} Searching for alternative browser installations...{Style.RESET_ALL}")
print(f"{Fore.YELLOW}{EMOJI['INFO']} {self.translator.get('oauth.searching_for_alternative_browser_installations') if self.translator else 'Searching for alternative browser installations...'}{Style.RESET_ALL}")
# Platform-specific paths
if os.name == 'nt': # Windows
@ -216,13 +261,13 @@ class OAuthHandler:
for path in alt_paths:
expanded_path = os.path.expanduser(path)
if os.path.exists(expanded_path):
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} Found browser at: {expanded_path}{Style.RESET_ALL}")
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('oauth.found_browser_at', path=expanded_path) if self.translator else f'Found browser at: {expanded_path}'}{Style.RESET_ALL}")
return expanded_path
return None
except Exception as e:
print(f"{Fore.RED}{EMOJI['ERROR']} Error finding browser path: {e}{Style.RESET_ALL}")
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('oauth.error_finding_browser_path', error=str(e)) if self.translator else f'Error finding browser path: {e}'}{Style.RESET_ALL}")
return None
def _configure_browser_options(self, chrome_path, user_data_dir, active_profile):
@ -251,22 +296,22 @@ class OAuthHandler:
return co
except Exception as e:
print(f"{Fore.RED}{EMOJI['ERROR']} Error configuring browser options: {e}{Style.RESET_ALL}")
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 handle_google_auth(self):
"""Handle Google OAuth authentication"""
try:
print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('oauth.google_start')}{Style.RESET_ALL}")
print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('oauth.google_start') if self.translator else 'Starting Google OAuth authentication...'}{Style.RESET_ALL}")
# Setup browser
if not self.setup_browser():
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('oauth.browser_failed')}{Style.RESET_ALL}")
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
# Navigate to auth URL
try:
print(f"{Fore.CYAN}{EMOJI['INFO']} Navigating to authentication page...{Style.RESET_ALL}")
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}")
self.browser.get("https://authenticator.cursor.sh/sign-up")
time.sleep(get_random_wait_time(self.config, 'page_load_wait'))
@ -290,16 +335,17 @@ class OAuthHandler:
raise Exception("Could not find Google authentication button")
# Click the button and wait for page load
print(f"{Fore.CYAN}{EMOJI['INFO']} Starting Google authentication...{Style.RESET_ALL}")
print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('oauth.starting_google_authentication') if self.translator else 'Starting Google authentication...'}{Style.RESET_ALL}")
auth_btn.click()
time.sleep(get_random_wait_time(self.config, 'page_load_wait'))
# Check if we're on account selection page
if "accounts.google.com" in self.browser.url:
print(f"{Fore.CYAN}{EMOJI['INFO']} Please select your Google account to continue...{Style.RESET_ALL}")
print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('oauth.please_select_your_google_account_to_continue') if self.translator else 'Please select your Google account to continue...'}{Style.RESET_ALL}")
alert_message = self.translator.get('oauth.please_select_your_google_account_to_continue') if self.translator else 'Please select your Google account to continue with Cursor authentication'
try:
self.browser.run_js("""
alert('Please select your Google account to continue with Cursor authentication');
self.browser.run_js(f"""
alert('{alert_message}');
""")
except:
pass # Alert is optional
@ -307,14 +353,14 @@ class OAuthHandler:
# Wait for authentication to complete
auth_info = self._wait_for_auth()
if not auth_info:
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('oauth.timeout')}{Style.RESET_ALL}")
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('oauth.timeout') if self.translator else 'Timeout'}{Style.RESET_ALL}")
return False, None
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('oauth.success')}{Style.RESET_ALL}")
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('oauth.success') if self.translator else 'Success'}{Style.RESET_ALL}")
return True, auth_info
except Exception as e:
print(f"{Fore.RED}{EMOJI['ERROR']} Authentication error: {str(e)}{Style.RESET_ALL}")
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('oauth.authentication_error', error=str(e)) if self.translator else f'Authentication error: {str(e)}'}{Style.RESET_ALL}")
return False, None
finally:
try:
@ -334,7 +380,7 @@ class OAuthHandler:
start_time = time.time()
check_interval = 2 # Check every 2 seconds
print(f"{Fore.CYAN}{EMOJI['WAIT']} Waiting for authentication (timeout: 5 minutes)...{Style.RESET_ALL}")
print(f"{Fore.CYAN}{EMOJI['WAIT']} {self.translator.get('oauth.waiting_for_authentication', timeout='5 minutes') if self.translator else 'Waiting for authentication (timeout: 5 minutes)'}{Style.RESET_ALL}")
while time.time() - start_time < max_wait:
try:
@ -353,7 +399,7 @@ class OAuthHandler:
if token:
# Get email from settings page
print(f"{Fore.CYAN}{EMOJI['INFO']} Authentication successful, getting account info...{Style.RESET_ALL}")
print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('oauth.authentication_successful_getting_account_info') if self.translator else 'Authentication successful, getting account info...'}{Style.RESET_ALL}")
self.browser.get("https://www.cursor.com/settings")
time.sleep(3)
@ -362,7 +408,7 @@ class OAuthHandler:
email_element = self.browser.ele("css:div[class='flex w-full flex-col gap-2'] div:nth-child(2) p:nth-child(2)")
if email_element:
email = email_element.text
print(f"{Fore.CYAN}{EMOJI['INFO']} Found email: {email}{Style.RESET_ALL}")
print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('oauth.found_email', email=email) if self.translator else f'Found email: {email}'}{Style.RESET_ALL}")
except:
email = "user@cursor.sh" # Fallback email
@ -371,42 +417,42 @@ class OAuthHandler:
usage_element = self.browser.ele("css:div[class='flex flex-col gap-4 lg:flex-row'] div:nth-child(1) div:nth-child(1) span:nth-child(2)")
if usage_element:
usage_text = usage_element.text
print(f"{Fore.CYAN}{EMOJI['INFO']} Usage count: {usage_text}{Style.RESET_ALL}")
print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('oauth.usage_count', usage=usage_text) if self.translator else f'Usage count: {usage_text}'}{Style.RESET_ALL}")
# Check if account is expired
if usage_text.strip() == "150 / 150":
print(f"{Fore.YELLOW}{EMOJI['INFO']} Account has reached maximum usage, creating new account...{Style.RESET_ALL}")
print(f"{Fore.YELLOW}{EMOJI['INFO']} {self.translator.get('oauth.account_has_reached_maximum_usage', creating_new_account='creating new account') if self.translator else 'Account has reached maximum usage, creating new account...'}{Style.RESET_ALL}")
# Delete current account
if self._delete_current_account():
# Start new authentication based on auth type
print(f"{Fore.CYAN}{EMOJI['INFO']} Starting new authentication process...{Style.RESET_ALL}")
print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('oauth.starting_new_authentication_process') if self.translator else 'Starting new authentication process...'}{Style.RESET_ALL}")
if self.auth_type == "google":
return self.handle_google_auth()
else: # github
return self.handle_github_auth()
else:
print(f"{Fore.RED}{EMOJI['ERROR']} Failed to delete expired account{Style.RESET_ALL}")
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('oauth.failed_to_delete_expired_account') if self.translator else 'Failed to delete expired account'}{Style.RESET_ALL}")
except Exception as e:
print(f"{Fore.YELLOW}{EMOJI['INFO']} Could not check usage count: {str(e)}{Style.RESET_ALL}")
print(f"{Fore.YELLOW}{EMOJI['INFO']} {self.translator.get('oauth.could_not_check_usage_count', error=str(e)) if self.translator else f'Could not check usage count: {str(e)}'}{Style.RESET_ALL}")
return {"email": email, "token": token}
# Also check URL as backup
if "cursor.com/settings" in self.browser.url:
print(f"{Fore.CYAN}{EMOJI['INFO']} Detected successful login{Style.RESET_ALL}")
print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('oauth.detected_successful_login') if self.translator else 'Detected successful login'}{Style.RESET_ALL}")
except Exception as e:
print(f"{Fore.YELLOW}{EMOJI['INFO']} Waiting for authentication... ({str(e)}){Style.RESET_ALL}")
print(f"{Fore.YELLOW}{EMOJI['INFO']} {self.translator.get('oauth.waiting_for_authentication', error=str(e)) if self.translator else f'Waiting for authentication... ({str(e)})'}{Style.RESET_ALL}")
time.sleep(check_interval)
print(f"{Fore.RED}{EMOJI['ERROR']} Authentication timeout{Style.RESET_ALL}")
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('oauth.authentication_timeout') if self.translator else 'Authentication timeout'}{Style.RESET_ALL}")
return None
except Exception as e:
print(f"{Fore.RED}{EMOJI['ERROR']} Error while waiting for authentication: {str(e)}{Style.RESET_ALL}")
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('oauth.error_waiting_for_authentication', error=str(e)) if self.translator else f'Error while waiting for authentication: {str(e)}'}{Style.RESET_ALL}")
return None
def handle_github_auth(self):
@ -421,7 +467,7 @@ class OAuthHandler:
# Navigate to auth URL
try:
print(f"{Fore.CYAN}{EMOJI['INFO']} Navigating to authentication page...{Style.RESET_ALL}")
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}")
self.browser.get("https://authenticator.cursor.sh/sign-up")
time.sleep(get_random_wait_time(self.config, 'page_load_wait'))
@ -445,21 +491,21 @@ class OAuthHandler:
raise Exception("Could not find GitHub authentication button")
# Click the button and wait for page load
print(f"{Fore.CYAN}{EMOJI['INFO']} Starting GitHub authentication...{Style.RESET_ALL}")
print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('oauth.starting_github_authentication') if self.translator else 'Starting GitHub authentication...'}{Style.RESET_ALL}")
auth_btn.click()
time.sleep(get_random_wait_time(self.config, 'page_load_wait'))
# Wait for authentication to complete
auth_info = self._wait_for_auth()
if not auth_info:
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('oauth.timeout')}{Style.RESET_ALL}")
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('oauth.timeout') if self.translator else 'Timeout'}{Style.RESET_ALL}")
return False, None
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('oauth.success')}{Style.RESET_ALL}")
return True, auth_info
except Exception as e:
print(f"{Fore.RED}{EMOJI['ERROR']} Authentication error: {str(e)}{Style.RESET_ALL}")
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('oauth.authentication_error', error=str(e)) if self.translator else f'Authentication error: {str(e)}'}{Style.RESET_ALL}")
return False, None
finally:
try:
@ -521,23 +567,23 @@ class OAuthHandler:
# Check if we're on account selection page
if auth_type == "google" and "accounts.google.com" in self.browser.url:
alert_js = """
alert('Please select your Google account manually to continue with Cursor authentication');
"""
alert_message = self.translator.get('oauth.please_select_your_google_account_to_continue') if self.translator else 'Please select your Google account to continue with Cursor authentication'
try:
self.browser.run_js(alert_js)
self.browser.run_js(f"""
alert('{alert_message}');
""")
except Exception as e:
print(f"{Fore.YELLOW}{EMOJI['INFO']} Alert display failed: {str(e)}{Style.RESET_ALL}")
print(f"{Fore.CYAN}{EMOJI['INFO']} Please select your Google account manually to continue with Cursor authentication...{Style.RESET_ALL}")
print(f"{Fore.YELLOW}{EMOJI['INFO']} {self.translator.get('oauth.alert_display_failed', error=str(e)) if self.translator else f'Alert display failed: {str(e)}'}{Style.RESET_ALL}")
print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('oauth.please_select_your_google_account_manually_to_continue_with_cursor_authentication') if self.translator else 'Please select your Google account manually to continue with Cursor authentication...'}{Style.RESET_ALL}")
print(f"{Fore.CYAN}{EMOJI['INFO']} Waiting for authentication to complete...{Style.RESET_ALL}")
print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('oauth.waiting_for_authentication_to_complete') if self.translator else 'Waiting for authentication to complete...'}{Style.RESET_ALL}")
# Wait for authentication to complete
max_wait = 300 # 5 minutes
start_time = time.time()
last_url = self.browser.url
print(f"{Fore.CYAN}{EMOJI['WAIT']} Checking authentication status...{Style.RESET_ALL}")
print(f"{Fore.CYAN}{EMOJI['WAIT']} {self.translator.get('oauth.checking_authentication_status') if self.translator else 'Checking authentication status...'}{Style.RESET_ALL}")
while time.time() - start_time < max_wait:
try:
@ -553,9 +599,9 @@ class OAuthHandler:
token = value.split("%3A%3A")[-1]
if token:
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} Authentication successful!{Style.RESET_ALL}")
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('oauth.authentication_successful') if self.translator else 'Authentication successful!'}{Style.RESET_ALL}")
# Navigate to settings page
print(f"{Fore.CYAN}{EMOJI['INFO']} Navigating to settings page...{Style.RESET_ALL}")
print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('oauth.navigating_to_settings_page') if self.translator else 'Navigating to settings page...'}{Style.RESET_ALL}")
self.browser.get("https://www.cursor.com/settings")
time.sleep(3) # Wait for settings page to load
@ -564,9 +610,9 @@ class OAuthHandler:
email_element = self.browser.ele("css:div[class='flex w-full flex-col gap-2'] div:nth-child(2) p:nth-child(2)")
if email_element:
actual_email = email_element.text
print(f"{Fore.CYAN}{EMOJI['INFO']} Found email: {actual_email}{Style.RESET_ALL}")
print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('oauth.found_email', email=actual_email) if self.translator else f'Found email: {actual_email}'}{Style.RESET_ALL}")
except Exception as e:
print(f"{Fore.YELLOW}{EMOJI['INFO']} Could not find email: {str(e)}{Style.RESET_ALL}")
print(f"{Fore.YELLOW}{EMOJI['INFO']} {self.translator.get('oauth.could_not_find_email', error=str(e)) if self.translator else f'Could not find email: {str(e)}'}{Style.RESET_ALL}")
actual_email = "user@cursor.sh"
# Check usage count
@ -574,11 +620,11 @@ class OAuthHandler:
usage_element = self.browser.ele("css:div[class='flex flex-col gap-4 lg:flex-row'] div:nth-child(1) div:nth-child(1) span:nth-child(2)")
if usage_element:
usage_text = usage_element.text
print(f"{Fore.CYAN}{EMOJI['INFO']} Usage count: {usage_text}{Style.RESET_ALL}")
print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('oauth.usage_count', usage=usage_text) if self.translator else f'Usage count: {usage_text}'}{Style.RESET_ALL}")
# Check if account is expired
if usage_text.strip() == "150 / 150":
print(f"{Fore.YELLOW}{EMOJI['INFO']} Account has reached maximum usage, deleting...{Style.RESET_ALL}")
print(f"{Fore.YELLOW}{EMOJI['INFO']} {self.translator.get('oauth.account_has_reached_maximum_usage', deleting='deleting') if self.translator else 'Account has reached maximum usage, deleting...'}{Style.RESET_ALL}")
delete_js = """
function deleteAccount() {
@ -610,23 +656,23 @@ class OAuthHandler:
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} Delete account result: {result}{Style.RESET_ALL}")
# Navigate back to auth page and repeat authentication
print(f"{Fore.CYAN}{EMOJI['INFO']} Starting re-authentication process...{Style.RESET_ALL}")
print(f"{Fore.CYAN}{EMOJI['INFO']} Redirecting to authenticator.cursor.sh...{Style.RESET_ALL}")
print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('oauth.starting_re_authentication_process') if self.translator else 'Starting re-authentication process...'}{Style.RESET_ALL}")
print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('oauth.redirecting_to_authenticator_cursor_sh') if self.translator else 'Redirecting to authenticator.cursor.sh...'}{Style.RESET_ALL}")
# Explicitly navigate to the authentication page
self.browser.get("https://authenticator.cursor.sh/sign-up")
time.sleep(get_random_wait_time(self.config, 'page_load_wait'))
# Call handle_google_auth again to repeat the entire process
print(f"{Fore.CYAN}{EMOJI['INFO']} Starting new Google authentication...{Style.RESET_ALL}")
print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('oauth.starting_new_google_authentication') if self.translator else 'Starting new Google authentication...'}{Style.RESET_ALL}")
return self.handle_google_auth()
except Exception as e:
print(f"{Fore.RED}{EMOJI['ERROR']} Failed to delete account or re-authenticate: {str(e)}{Style.RESET_ALL}")
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('oauth.failed_to_delete_account_or_re_authenticate', error=str(e)) if self.translator else f'Failed to delete account or re-authenticate: {str(e)}'}{Style.RESET_ALL}")
else:
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} Account is still valid (Usage: {usage_text}){Style.RESET_ALL}")
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('oauth.account_is_still_valid', usage=usage_text) if self.translator else f'Account is still valid (Usage: {usage_text})'}{Style.RESET_ALL}")
except Exception as e:
print(f"{Fore.YELLOW}{EMOJI['INFO']} Could not find usage count: {str(e)}{Style.RESET_ALL}")
print(f"{Fore.YELLOW}{EMOJI['INFO']} {self.translator.get('oauth.could_not_find_usage_count', error=str(e)) if self.translator else f'Could not find usage count: {str(e)}'}{Style.RESET_ALL}")
# Remove the browser stay open prompt and input wait
return True, {"email": actual_email, "token": token}
@ -634,7 +680,7 @@ class OAuthHandler:
# Also check URL as backup
current_url = self.browser.url
if "cursor.com/settings" in current_url:
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} Already on settings page!{Style.RESET_ALL}")
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('oauth.already_on_settings_page') if self.translator else 'Already on settings page!'}{Style.RESET_ALL}")
time.sleep(1)
cookies = self.browser.cookies()
for cookie in cookies:
@ -650,9 +696,9 @@ class OAuthHandler:
email_element = self.browser.ele("css:div[class='flex w-full flex-col gap-2'] div:nth-child(2) p:nth-child(2)")
if email_element:
actual_email = email_element.text
print(f"{Fore.CYAN}{EMOJI['INFO']} Found email: {actual_email}{Style.RESET_ALL}")
print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('oauth.found_email', email=actual_email) if self.translator else f'Found email: {actual_email}'}{Style.RESET_ALL}")
except Exception as e:
print(f"{Fore.YELLOW}{EMOJI['INFO']} Could not find email: {str(e)}{Style.RESET_ALL}")
print(f"{Fore.YELLOW}{EMOJI['INFO']} {self.translator.get('oauth.could_not_find_email', error=str(e)) if self.translator else f'Could not find email: {str(e)}'}{Style.RESET_ALL}")
actual_email = "user@cursor.sh"
# Check usage count
@ -660,11 +706,11 @@ class OAuthHandler:
usage_element = self.browser.ele("css:div[class='flex flex-col gap-4 lg:flex-row'] div:nth-child(1) div:nth-child(1) span:nth-child(2)")
if usage_element:
usage_text = usage_element.text
print(f"{Fore.CYAN}{EMOJI['INFO']} Usage count: {usage_text}{Style.RESET_ALL}")
print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('oauth.usage_count', usage=usage_text) if self.translator else f'Usage count: {usage_text}'}{Style.RESET_ALL}")
# Check if account is expired
if usage_text.strip() == "150 / 150":
print(f"{Fore.YELLOW}{EMOJI['INFO']} Account has reached maximum usage, deleting...{Style.RESET_ALL}")
print(f"{Fore.YELLOW}{EMOJI['INFO']} {self.translator.get('oauth.account_has_reached_maximum_usage', deleting='deleting') if self.translator else 'Account has reached maximum usage, deleting...'}{Style.RESET_ALL}")
delete_js = """
function deleteAccount() {
@ -696,44 +742,44 @@ class OAuthHandler:
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} Delete account result: {result}{Style.RESET_ALL}")
# Navigate back to auth page and repeat authentication
print(f"{Fore.CYAN}{EMOJI['INFO']} Starting re-authentication process...{Style.RESET_ALL}")
print(f"{Fore.CYAN}{EMOJI['INFO']} Redirecting to authenticator.cursor.sh...{Style.RESET_ALL}")
print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('oauth.starting_re_authentication_process') if self.translator else 'Starting re-authentication process...'}{Style.RESET_ALL}")
print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('oauth.redirecting_to_authenticator_cursor_sh') if self.translator else 'Redirecting to authenticator.cursor.sh...'}{Style.RESET_ALL}")
# Explicitly navigate to the authentication page
self.browser.get("https://authenticator.cursor.sh/sign-up")
time.sleep(get_random_wait_time(self.config, 'page_load_wait'))
# Call handle_google_auth again to repeat the entire process
print(f"{Fore.CYAN}{EMOJI['INFO']} Starting new Google authentication...{Style.RESET_ALL}")
print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('oauth.starting_new_google_authentication') if self.translator else 'Starting new Google authentication...'}{Style.RESET_ALL}")
return self.handle_google_auth()
except Exception as e:
print(f"{Fore.RED}{EMOJI['ERROR']} Failed to delete account or re-authenticate: {str(e)}{Style.RESET_ALL}")
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('oauth.failed_to_delete_account_or_re_authenticate', error=str(e)) if self.translator else f'Failed to delete account or re-authenticate: {str(e)}'}{Style.RESET_ALL}")
else:
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} Account is still valid (Usage: {usage_text}){Style.RESET_ALL}")
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('oauth.account_is_still_valid', usage=usage_text) if self.translator else f'Account is still valid (Usage: {usage_text})'}{Style.RESET_ALL}")
except Exception as e:
print(f"{Fore.YELLOW}{EMOJI['INFO']} Could not find usage count: {str(e)}{Style.RESET_ALL}")
print(f"{Fore.YELLOW}{EMOJI['INFO']} {self.translator.get('oauth.could_not_find_usage_count', error=str(e)) if self.translator else f'Could not find usage count: {str(e)}'}{Style.RESET_ALL}")
# Remove the browser stay open prompt and input wait
return True, {"email": actual_email, "token": token}
elif current_url != last_url:
print(f"{Fore.CYAN}{EMOJI['INFO']} Page changed, checking auth...{Style.RESET_ALL}")
print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('oauth.page_changed_checking_auth') if self.translator else 'Page changed, checking auth...'}{Style.RESET_ALL}")
last_url = current_url
time.sleep(get_random_wait_time(self.config, 'page_load_wait'))
except Exception as e:
print(f"{Fore.YELLOW}{EMOJI['INFO']} Status check error: {str(e)}{Style.RESET_ALL}")
print(f"{Fore.YELLOW}{EMOJI['INFO']} {self.translator.get('oauth.status_check_error', error=str(e)) if self.translator else f'Status check error: {str(e)}'}{Style.RESET_ALL}")
time.sleep(1)
continue
time.sleep(1)
print(f"{Fore.RED}{EMOJI['ERROR']} Authentication timeout{Style.RESET_ALL}")
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('oauth.authentication_timeout') if self.translator else 'Authentication timeout'}{Style.RESET_ALL}")
return False, None
print(f"{Fore.RED}{EMOJI['ERROR']} Authentication button not found{Style.RESET_ALL}")
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('oauth.authentication_button_not_found') if self.translator else 'Authentication button not found'}{Style.RESET_ALL}")
return False, None
except Exception as e:
print(f"{Fore.RED}{EMOJI['ERROR']} Authentication failed: {str(e)}{Style.RESET_ALL}")
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('oauth.authentication_failed', error=str(e)) if self.translator else f'Authentication failed: {str(e)}'}{Style.RESET_ALL}")
return False, None
finally:
if self.browser:
@ -756,7 +802,7 @@ class OAuthHandler:
time.sleep(1)
# Debug cookie information
print(f"{Fore.CYAN}{EMOJI['INFO']} Found {len(cookies)} cookies{Style.RESET_ALL}")
print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('oauth.found_cookies', count=len(cookies)) if self.translator else f'Found {len(cookies)} cookies'}{Style.RESET_ALL}")
email = None
token = None
@ -771,12 +817,12 @@ class OAuthHandler:
elif "%3A%3A" in value:
token = value.split("%3A%3A")[-1]
except Exception as e:
print(f"{Fore.YELLOW}{EMOJI['INFO']} Token extraction error: {str(e)}{Style.RESET_ALL}")
print(f"{Fore.YELLOW}{EMOJI['INFO']} {self.translator.get('oauth.token_extraction_error', error=str(e)) if self.translator else f'Token extraction error: {str(e)}'}{Style.RESET_ALL}")
elif name == "cursor_email":
email = cookie.get("value")
if email and token:
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} Authentication successful - Email: {email}{Style.RESET_ALL}")
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('oauth.authentication_successful', email=email) if self.translator else f'Authentication successful - Email: {email}'}{Style.RESET_ALL}")
return True, {"email": email, "token": token}
else:
missing = []
@ -784,11 +830,11 @@ class OAuthHandler:
missing.append("email")
if not token:
missing.append("token")
print(f"{Fore.RED}{EMOJI['ERROR']} Missing authentication data: {', '.join(missing)}{Style.RESET_ALL}")
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('oauth.missing_authentication_data', data=', '.join(missing)) if self.translator else f'Missing authentication data: {", ".join(missing)}'}{Style.RESET_ALL}")
return False, None
except Exception as e:
print(f"{Fore.RED}{EMOJI['ERROR']} Failed to extract auth info: {str(e)}{Style.RESET_ALL}")
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('oauth.failed_to_extract_auth_info', error=str(e)) if self.translator else f'Failed to extract auth info: {str(e)}'}{Style.RESET_ALL}")
return False, None
def _delete_current_account(self):
@ -823,14 +869,14 @@ class OAuthHandler:
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} Delete account result: {result}{Style.RESET_ALL}")
# Navigate back to auth page
print(f"{Fore.CYAN}{EMOJI['INFO']} Redirecting to authenticator.cursor.sh...{Style.RESET_ALL}")
print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('oauth.redirecting_to_authenticator_cursor_sh') if self.translator else 'Redirecting to authenticator.cursor.sh...'}{Style.RESET_ALL}")
self.browser.get("https://authenticator.cursor.sh/sign-up")
time.sleep(get_random_wait_time(self.config, 'page_load_wait'))
return True
except Exception as e:
print(f"{Fore.RED}{EMOJI['ERROR']} Failed to delete account: {str(e)}{Style.RESET_ALL}")
print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('oauth.failed_to_delete_account', error=str(e)) if self.translator else f'Failed to delete account: {str(e)}'}{Style.RESET_ALL}")
return False
def main(auth_type, translator=None):
@ -843,13 +889,13 @@ def main(auth_type, translator=None):
handler = OAuthHandler(translator, auth_type)
if auth_type.lower() == 'google':
print(f"{Fore.CYAN}{EMOJI['INFO']} {translator.get('oauth.google_start')}{Style.RESET_ALL}")
print(f"{Fore.CYAN}{EMOJI['INFO']} {translator.get('oauth.google_start') if translator else 'Google start'}{Style.RESET_ALL}")
success, auth_info = handler.handle_google_auth()
elif auth_type.lower() == 'github':
print(f"{Fore.CYAN}{EMOJI['INFO']} {translator.get('oauth.github_start')}{Style.RESET_ALL}")
print(f"{Fore.CYAN}{EMOJI['INFO']} {translator.get('oauth.github_start') if translator else 'Github start'}{Style.RESET_ALL}")
success, auth_info = handler.handle_github_auth()
else:
print(f"{Fore.RED}{EMOJI['ERROR']} Invalid authentication type{Style.RESET_ALL}")
print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('oauth.invalid_authentication_type') if translator else 'Invalid authentication type'}{Style.RESET_ALL}")
return False
if success and auth_info:
@ -860,13 +906,13 @@ def main(auth_type, translator=None):
access_token=auth_info["token"],
refresh_token=auth_info["token"]
):
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {translator.get('oauth.auth_update_success')}{Style.RESET_ALL}")
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {translator.get('oauth.auth_update_success') if translator else 'Auth update success'}{Style.RESET_ALL}")
# Close the browser after successful authentication
if handler.browser:
handler.browser.quit()
print(f"{Fore.CYAN}{EMOJI['INFO']} Browser closed{Style.RESET_ALL}")
print(f"{Fore.CYAN}{EMOJI['INFO']} {translator.get('oauth.browser_closed') if translator else 'Browser closed'}{Style.RESET_ALL}")
return True
else:
print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('oauth.auth_update_failed')}{Style.RESET_ALL}")
print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('oauth.auth_update_failed') if translator else 'Auth update failed'}{Style.RESET_ALL}")
return False