mirror of
https://github.com/yeongpin/cursor-free-vip.git
synced 2025-08-03 04:57:36 +08:00
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:
commit
9793b91bc7
93
config.py
93
config.py
@ -85,28 +85,45 @@ def setup_config(translator=None):
|
|||||||
|
|
||||||
elif sys.platform == "linux":
|
elif sys.platform == "linux":
|
||||||
# Get the actual user's home directory, handling both sudo and normal cases
|
# 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:
|
if not current_user:
|
||||||
current_user = os.path.expanduser('~').split('/')[-1]
|
current_user = os.path.expanduser('~').split('/')[-1]
|
||||||
|
|
||||||
|
# Handle sudo case
|
||||||
|
if sudo_user:
|
||||||
|
actual_home = f"/home/{sudo_user}"
|
||||||
|
root_home = "/root"
|
||||||
|
else:
|
||||||
actual_home = f"/home/{current_user}"
|
actual_home = f"/home/{current_user}"
|
||||||
|
root_home = None
|
||||||
|
|
||||||
if not os.path.exists(actual_home):
|
if not os.path.exists(actual_home):
|
||||||
actual_home = os.path.expanduser("~")
|
actual_home = os.path.expanduser("~")
|
||||||
|
|
||||||
# Define base config directory
|
# Define base config directory
|
||||||
config_base = os.path.join(actual_home, ".config")
|
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
|
cursor_dir = None
|
||||||
for dir_name in ["Cursor", "cursor"]:
|
possible_paths = [
|
||||||
test_dir = os.path.join(config_base, dir_name)
|
os.path.join(config_base, "Cursor"),
|
||||||
if os.path.exists(test_dir):
|
os.path.join(config_base, "cursor"),
|
||||||
cursor_dir = test_dir
|
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
|
break
|
||||||
|
|
||||||
if not cursor_dir:
|
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['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}")
|
||||||
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}")
|
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
|
# 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 ""
|
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:
|
try:
|
||||||
# Check storage directory
|
# Check storage directory
|
||||||
if storage_dir and not os.path.exists(storage_dir):
|
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['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')}{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
|
# Check storage.json with more detailed verification
|
||||||
if storage_path and os.path.exists(storage_path):
|
if storage_path and os.path.exists(storage_path):
|
||||||
# Get file stats
|
# Get file stats
|
||||||
try:
|
try:
|
||||||
stat = os.stat(storage_path)
|
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.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', stat.st_size)}{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', oct(stat.st_mode & 0o777))}{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', stat.st_uid)}{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', stat.st_gid)}{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:
|
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
|
# Check if file is readable and writable
|
||||||
if not os.access(storage_path, os.R_OK | os.W_OK):
|
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.RED}{EMOJI['ERROR']} {translator.get('config.permission_denied', storage_path=storage_path) if translator else f'Permission denied: {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}")
|
if sudo_user:
|
||||||
print(f"{Fore.YELLOW}{EMOJI['INFO']} {translator.get('config.and', storage_path=storage_path)}{Style.RESET_ALL}")
|
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 to read the file to verify it's not corrupted
|
||||||
try:
|
try:
|
||||||
with open(storage_path, 'r') as f:
|
with open(storage_path, 'r') as f:
|
||||||
content = f.read()
|
content = f.read()
|
||||||
if not content.strip():
|
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['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.please_make_sure_cursor_is_installed_and_has_been_run_at_least_once')}{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:
|
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:
|
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.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')}{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:
|
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['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')}{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:
|
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
|
# Define all paths using the found cursor directory
|
||||||
default_config['LinuxPaths'] = {
|
default_config['LinuxPaths'] = {
|
||||||
@ -181,13 +202,13 @@ def setup_config(translator=None):
|
|||||||
config.set(section, option, str(value))
|
config.set(section, option, str(value))
|
||||||
config_modified = True
|
config_modified = True
|
||||||
if translator:
|
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:
|
if config_modified:
|
||||||
with open(config_file, 'w', encoding='utf-8') as f:
|
with open(config_file, 'w', encoding='utf-8') as f:
|
||||||
config.write(f)
|
config.write(f)
|
||||||
if translator:
|
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:
|
else:
|
||||||
for section, options in default_config.items():
|
for section, options in default_config.items():
|
||||||
config.add_section(section)
|
config.add_section(section)
|
||||||
@ -197,31 +218,31 @@ def setup_config(translator=None):
|
|||||||
with open(config_file, 'w', encoding='utf-8') as f:
|
with open(config_file, 'w', encoding='utf-8') as f:
|
||||||
config.write(f)
|
config.write(f)
|
||||||
if translator:
|
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
|
return config
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
if translator:
|
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
|
return None
|
||||||
|
|
||||||
def print_config(config, translator=None):
|
def print_config(config, translator=None):
|
||||||
"""Print configuration in a readable format"""
|
"""Print configuration in a readable format"""
|
||||||
if not config:
|
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
|
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}")
|
print(f"\n{Fore.CYAN}{'─' * 70}{Style.RESET_ALL}")
|
||||||
for section in config.sections():
|
for section in config.sections():
|
||||||
print(f"{Fore.GREEN}[{section}]{Style.RESET_ALL}")
|
print(f"{Fore.GREEN}[{section}]{Style.RESET_ALL}")
|
||||||
for key, value in config.items(section):
|
for key, value in config.items(section):
|
||||||
# 对布尔值进行特殊处理,使其显示为彩色
|
# 对布尔值进行特殊处理,使其显示为彩色
|
||||||
if value.lower() in ('true', 'yes', 'on', '1'):
|
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'):
|
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:
|
else:
|
||||||
value_display = value
|
value_display = value
|
||||||
|
|
||||||
@ -229,7 +250,7 @@ def print_config(config, translator=None):
|
|||||||
|
|
||||||
print(f"\n{Fore.CYAN}{'─' * 70}{Style.RESET_ALL}")
|
print(f"\n{Fore.CYAN}{'─' * 70}{Style.RESET_ALL}")
|
||||||
config_dir = os.path.join(get_user_documents_path(), ".cursor-free-vip", "config.ini")
|
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()
|
print()
|
||||||
|
|
||||||
|
@ -280,7 +280,13 @@
|
|||||||
"available_domains_loaded": "Available Domains Loaded: {count}",
|
"available_domains_loaded": "Available Domains Loaded: {count}",
|
||||||
"domains_filtered": "Domains Filtered: {count}",
|
"domains_filtered": "Domains Filtered: {count}",
|
||||||
"trying_to_create_email": "Trying to create email: {email}",
|
"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": {
|
"update": {
|
||||||
"title": "Disable Cursor Auto 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",
|
"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_directory_not_found": "Storage directory not found: {storage_dir}",
|
||||||
"storage_file_found": "Storage file found: {storage_path}",
|
"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_permissions": "File permissions: {permissions}",
|
||||||
"file_owner": "File owner: {owner}",
|
"file_owner": "File owner: {owner}",
|
||||||
"file_group": "File group: {group}",
|
"file_group": "File group: {group}",
|
||||||
"error_getting_file_stats": "Error getting file stats: {error}",
|
"error_getting_file_stats": "Error getting file stats: {error}",
|
||||||
"permission_denied": "Permission denied: {storage_path}",
|
"permission_denied": "Permission denied: {storage_path}",
|
||||||
"try_running": "Try running 'cursor --help' to check if it's installed",
|
"try_running": "Try running: {command}",
|
||||||
"and": "and",
|
"and": "And",
|
||||||
"storage_file_is_empty": "Storage file is empty: {storage_path}",
|
"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",
|
"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}",
|
"storage_file_not_found": "Storage file not found: {storage_path}",
|
||||||
@ -513,7 +519,64 @@
|
|||||||
"config_option_added": "Config option added: {option}",
|
"config_option_added": "Config option added: {option}",
|
||||||
"config_updated": "Config updated",
|
"config_updated": "Config updated",
|
||||||
"config_created": "Config created: {config_file}",
|
"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..."
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -275,7 +275,13 @@
|
|||||||
"available_domains_loaded": "获取到 {count} 个可用域名",
|
"available_domains_loaded": "获取到 {count} 个可用域名",
|
||||||
"domains_filtered": "过滤后剩餘 {count} 個可用域名",
|
"domains_filtered": "过滤后剩餘 {count} 個可用域名",
|
||||||
"trying_to_create_email": "尝试创建邮箱: {email}",
|
"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": {
|
"update": {
|
||||||
"title": "禁用 Cursor 自动更新",
|
"title": "禁用 Cursor 自动更新",
|
||||||
@ -499,7 +505,7 @@
|
|||||||
"file_group": "文件组",
|
"file_group": "文件组",
|
||||||
"error_getting_file_stats": "获取文件统计信息时出错",
|
"error_getting_file_stats": "获取文件统计信息时出错",
|
||||||
"permission_denied": "权限拒绝",
|
"permission_denied": "权限拒绝",
|
||||||
"try_running": "尝试运行 'cursor --help' 检查是否已安装",
|
"try_running": "尝试运行: {command}",
|
||||||
"and": "和",
|
"and": "和",
|
||||||
"storage_file_is_empty": "存储文件为空",
|
"storage_file_is_empty": "存储文件为空",
|
||||||
"the_file_might_be_corrupted_please_reinstall_cursor": "文件可能已损坏,请重新安装 Cursor",
|
"the_file_might_be_corrupted_please_reinstall_cursor": "文件可能已损坏,请重新安装 Cursor",
|
||||||
@ -508,7 +514,65 @@
|
|||||||
"config_option_added": "添加配置选项",
|
"config_option_added": "添加配置选项",
|
||||||
"config_updated": "配置更新",
|
"config_updated": "配置更新",
|
||||||
"config_created": "配置已创建",
|
"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": "认证成功, 获取账户信息..."
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -254,7 +254,14 @@
|
|||||||
"blocked_domains_loaded_timeout_error": "加載被屏蔽的域名超時錯誤: {error}",
|
"blocked_domains_loaded_timeout_error": "加載被屏蔽的域名超時錯誤: {error}",
|
||||||
"available_domains_loaded": "獲取到 {count} 個可用域名",
|
"available_domains_loaded": "獲取到 {count} 個可用域名",
|
||||||
"domains_filtered": "過濾後剩餘 {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": {
|
"update": {
|
||||||
"title": "禁用 Cursor 自动更新",
|
"title": "禁用 Cursor 自动更新",
|
||||||
@ -478,7 +485,7 @@
|
|||||||
"file_group": "文件組",
|
"file_group": "文件組",
|
||||||
"error_getting_file_stats": "獲取文件統計信息時出錯",
|
"error_getting_file_stats": "獲取文件統計信息時出錯",
|
||||||
"permission_denied": "權限拒絕",
|
"permission_denied": "權限拒絕",
|
||||||
"try_running": "嘗試運行 'cursor --help' 檢查是否已安裝",
|
"try_running": "嘗試運行: {command}",
|
||||||
"and": "和",
|
"and": "和",
|
||||||
"storage_file_is_empty": "儲存文件為空",
|
"storage_file_is_empty": "儲存文件為空",
|
||||||
"the_file_might_be_corrupted_please_reinstall_cursor": "文件可能已損壞,請重新安裝 Cursor",
|
"the_file_might_be_corrupted_please_reinstall_cursor": "文件可能已損壞,請重新安裝 Cursor",
|
||||||
@ -487,7 +494,64 @@
|
|||||||
"config_option_added": "添加配置選項",
|
"config_option_added": "添加配置選項",
|
||||||
"config_updated": "配置更新",
|
"config_updated": "配置更新",
|
||||||
"config_created": "配置已創建",
|
"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": "認證成功, 獲取帳戶信息..."
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -106,11 +106,31 @@ class NewTempEmail:
|
|||||||
|
|
||||||
# 创建浏览器选项
|
# 创建浏览器选项
|
||||||
co = ChromiumOptions()
|
co = ChromiumOptions()
|
||||||
|
|
||||||
|
# Only use headless for non-OAuth operations
|
||||||
|
if not hasattr(self, 'auth_type') or self.auth_type != 'oauth':
|
||||||
co.set_argument("--headless=new")
|
co.set_argument("--headless=new")
|
||||||
|
|
||||||
if sys.platform == "linux":
|
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() # 自动设置端口
|
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}")
|
print(f"{Fore.RED}❌ {self.translator.get('email.browser_start_error')}: {str(e)}{Style.RESET_ALL}")
|
||||||
else:
|
else:
|
||||||
print(f"{Fore.RED}❌ 启动浏览器失败: {str(e)}{Style.RESET_ALL}")
|
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
|
return False
|
||||||
|
|
||||||
def create_email(self):
|
def create_email(self):
|
||||||
|
242
oauth_auth.py
242
oauth_auth.py
@ -21,7 +21,8 @@ EMOJI = {
|
|||||||
'SUCCESS': '✅',
|
'SUCCESS': '✅',
|
||||||
'ERROR': '❌',
|
'ERROR': '❌',
|
||||||
'WAIT': '⏳',
|
'WAIT': '⏳',
|
||||||
'INFO': 'ℹ️'
|
'INFO': 'ℹ️',
|
||||||
|
'WARNING': '⚠️'
|
||||||
}
|
}
|
||||||
|
|
||||||
class OAuthHandler:
|
class OAuthHandler:
|
||||||
@ -42,12 +43,12 @@ class OAuthHandler:
|
|||||||
profiles.append(item)
|
profiles.append(item)
|
||||||
|
|
||||||
if not profiles:
|
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'
|
return 'Default'
|
||||||
|
|
||||||
# First check if Default profile exists
|
# First check if Default profile exists
|
||||||
if 'Default' in profiles:
|
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'
|
return 'Default'
|
||||||
|
|
||||||
# If no Default profile, check Local State for last used profile
|
# If no Default profile, check Local State for last used profile
|
||||||
@ -69,21 +70,35 @@ class OAuthHandler:
|
|||||||
return profile
|
return profile
|
||||||
|
|
||||||
# If no profile found in Local State, use the first available 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]
|
return profiles[0]
|
||||||
|
|
||||||
except Exception as e:
|
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'
|
return 'Default'
|
||||||
|
|
||||||
def setup_browser(self):
|
def setup_browser(self):
|
||||||
"""Setup browser for OAuth flow using active profile"""
|
"""Setup browser for OAuth flow using active profile"""
|
||||||
try:
|
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-specific initialization
|
||||||
platform_name = platform.system().lower()
|
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
|
# Kill existing browser processes
|
||||||
self._kill_browser_processes()
|
self._kill_browser_processes()
|
||||||
@ -93,34 +108,64 @@ class OAuthHandler:
|
|||||||
chrome_path = self._get_browser_path()
|
chrome_path = self._get_browser_path()
|
||||||
|
|
||||||
if not chrome_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" +
|
"- Windows: Google Chrome, Chromium\n" +
|
||||||
"- macOS: Google Chrome, Chromium\n" +
|
"- macOS: Google Chrome, Chromium\n" +
|
||||||
"- Linux: Google Chrome, Chromium, chromium-browser")
|
"- Linux: Google Chrome, Chromium, chromium-browser")
|
||||||
|
|
||||||
# Get active profile
|
# Get active profile
|
||||||
active_profile = self._get_active_profile(user_data_dir)
|
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
|
# 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)
|
self.browser = ChromiumPage(co)
|
||||||
|
|
||||||
# Verify browser launched successfully
|
# Verify browser launched successfully
|
||||||
if not self.browser:
|
if not self.browser:
|
||||||
raise Exception("Failed to initialize browser instance")
|
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
|
return True
|
||||||
|
|
||||||
except Exception as e:
|
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):
|
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):
|
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
|
return False
|
||||||
|
|
||||||
def _kill_browser_processes(self):
|
def _kill_browser_processes(self):
|
||||||
@ -137,7 +182,7 @@ class OAuthHandler:
|
|||||||
|
|
||||||
time.sleep(1) # Wait for processes to close
|
time.sleep(1) # Wait for processes to close
|
||||||
except Exception as e:
|
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):
|
def _get_user_data_directory(self):
|
||||||
"""Get the appropriate user data directory based on platform"""
|
"""Get the appropriate user data directory based on platform"""
|
||||||
@ -163,17 +208,17 @@ class OAuthHandler:
|
|||||||
# Try each possible path
|
# Try each possible path
|
||||||
for path in possible_paths:
|
for path in possible_paths:
|
||||||
if os.path.exists(path):
|
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
|
return path
|
||||||
|
|
||||||
# Create temporary profile if no existing profile found
|
# Create temporary profile if no existing profile found
|
||||||
temp_profile = os.path.join(os.path.expanduser('~'), '.cursor_temp_profile')
|
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)
|
os.makedirs(temp_profile, exist_ok=True)
|
||||||
return temp_profile
|
return temp_profile
|
||||||
|
|
||||||
except Exception as e:
|
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
|
raise
|
||||||
|
|
||||||
def _get_browser_path(self):
|
def _get_browser_path(self):
|
||||||
@ -184,7 +229,7 @@ class OAuthHandler:
|
|||||||
if chrome_path and os.path.exists(chrome_path):
|
if chrome_path and os.path.exists(chrome_path):
|
||||||
return 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
|
# Platform-specific paths
|
||||||
if os.name == 'nt': # Windows
|
if os.name == 'nt': # Windows
|
||||||
@ -216,13 +261,13 @@ class OAuthHandler:
|
|||||||
for path in alt_paths:
|
for path in alt_paths:
|
||||||
expanded_path = os.path.expanduser(path)
|
expanded_path = os.path.expanduser(path)
|
||||||
if os.path.exists(expanded_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 expanded_path
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
except Exception as e:
|
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
|
return None
|
||||||
|
|
||||||
def _configure_browser_options(self, chrome_path, user_data_dir, active_profile):
|
def _configure_browser_options(self, chrome_path, user_data_dir, active_profile):
|
||||||
@ -251,22 +296,22 @@ class OAuthHandler:
|
|||||||
return co
|
return co
|
||||||
|
|
||||||
except Exception as e:
|
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
|
raise
|
||||||
|
|
||||||
def handle_google_auth(self):
|
def handle_google_auth(self):
|
||||||
"""Handle Google OAuth authentication"""
|
"""Handle Google OAuth authentication"""
|
||||||
try:
|
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
|
# Setup browser
|
||||||
if not self.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
|
return False, None
|
||||||
|
|
||||||
# Navigate to auth URL
|
# Navigate to auth URL
|
||||||
try:
|
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")
|
self.browser.get("https://authenticator.cursor.sh/sign-up")
|
||||||
time.sleep(get_random_wait_time(self.config, 'page_load_wait'))
|
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")
|
raise Exception("Could not find Google authentication button")
|
||||||
|
|
||||||
# Click the button and wait for page load
|
# 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()
|
auth_btn.click()
|
||||||
time.sleep(get_random_wait_time(self.config, 'page_load_wait'))
|
time.sleep(get_random_wait_time(self.config, 'page_load_wait'))
|
||||||
|
|
||||||
# Check if we're on account selection page
|
# Check if we're on account selection page
|
||||||
if "accounts.google.com" in self.browser.url:
|
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:
|
try:
|
||||||
self.browser.run_js("""
|
self.browser.run_js(f"""
|
||||||
alert('Please select your Google account to continue with Cursor authentication');
|
alert('{alert_message}');
|
||||||
""")
|
""")
|
||||||
except:
|
except:
|
||||||
pass # Alert is optional
|
pass # Alert is optional
|
||||||
@ -307,14 +353,14 @@ class OAuthHandler:
|
|||||||
# Wait for authentication to complete
|
# Wait for authentication to complete
|
||||||
auth_info = self._wait_for_auth()
|
auth_info = self._wait_for_auth()
|
||||||
if not auth_info:
|
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
|
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
|
return True, auth_info
|
||||||
|
|
||||||
except Exception as e:
|
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
|
return False, None
|
||||||
finally:
|
finally:
|
||||||
try:
|
try:
|
||||||
@ -334,7 +380,7 @@ class OAuthHandler:
|
|||||||
start_time = time.time()
|
start_time = time.time()
|
||||||
check_interval = 2 # Check every 2 seconds
|
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:
|
while time.time() - start_time < max_wait:
|
||||||
try:
|
try:
|
||||||
@ -353,7 +399,7 @@ class OAuthHandler:
|
|||||||
|
|
||||||
if token:
|
if token:
|
||||||
# Get email from settings page
|
# 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")
|
self.browser.get("https://www.cursor.com/settings")
|
||||||
time.sleep(3)
|
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)")
|
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:
|
if email_element:
|
||||||
email = email_element.text
|
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:
|
except:
|
||||||
email = "user@cursor.sh" # Fallback email
|
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)")
|
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:
|
if usage_element:
|
||||||
usage_text = usage_element.text
|
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
|
# Check if account is expired
|
||||||
if usage_text.strip() == "150 / 150":
|
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
|
# Delete current account
|
||||||
if self._delete_current_account():
|
if self._delete_current_account():
|
||||||
# Start new authentication based on auth type
|
# 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":
|
if self.auth_type == "google":
|
||||||
return self.handle_google_auth()
|
return self.handle_google_auth()
|
||||||
else: # github
|
else: # github
|
||||||
return self.handle_github_auth()
|
return self.handle_github_auth()
|
||||||
else:
|
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:
|
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}
|
return {"email": email, "token": token}
|
||||||
|
|
||||||
# Also check URL as backup
|
# Also check URL as backup
|
||||||
if "cursor.com/settings" in self.browser.url:
|
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:
|
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)
|
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
|
return None
|
||||||
|
|
||||||
except Exception as e:
|
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
|
return None
|
||||||
|
|
||||||
def handle_github_auth(self):
|
def handle_github_auth(self):
|
||||||
@ -421,7 +467,7 @@ class OAuthHandler:
|
|||||||
|
|
||||||
# Navigate to auth URL
|
# Navigate to auth URL
|
||||||
try:
|
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")
|
self.browser.get("https://authenticator.cursor.sh/sign-up")
|
||||||
time.sleep(get_random_wait_time(self.config, 'page_load_wait'))
|
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")
|
raise Exception("Could not find GitHub authentication button")
|
||||||
|
|
||||||
# Click the button and wait for page load
|
# 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()
|
auth_btn.click()
|
||||||
time.sleep(get_random_wait_time(self.config, 'page_load_wait'))
|
time.sleep(get_random_wait_time(self.config, 'page_load_wait'))
|
||||||
|
|
||||||
# Wait for authentication to complete
|
# Wait for authentication to complete
|
||||||
auth_info = self._wait_for_auth()
|
auth_info = self._wait_for_auth()
|
||||||
if not auth_info:
|
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
|
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')}{Style.RESET_ALL}")
|
||||||
return True, auth_info
|
return True, auth_info
|
||||||
|
|
||||||
except Exception as e:
|
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
|
return False, None
|
||||||
finally:
|
finally:
|
||||||
try:
|
try:
|
||||||
@ -521,23 +567,23 @@ class OAuthHandler:
|
|||||||
|
|
||||||
# Check if we're on account selection page
|
# Check if we're on account selection page
|
||||||
if auth_type == "google" and "accounts.google.com" in self.browser.url:
|
if auth_type == "google" and "accounts.google.com" in self.browser.url:
|
||||||
alert_js = """
|
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'
|
||||||
alert('Please select your Google account manually to continue with Cursor authentication');
|
|
||||||
"""
|
|
||||||
try:
|
try:
|
||||||
self.browser.run_js(alert_js)
|
self.browser.run_js(f"""
|
||||||
|
alert('{alert_message}');
|
||||||
|
""")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"{Fore.YELLOW}{EMOJI['INFO']} Alert display failed: {str(e)}{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']} Please select your Google account manually to continue with Cursor authentication...{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
|
# Wait for authentication to complete
|
||||||
max_wait = 300 # 5 minutes
|
max_wait = 300 # 5 minutes
|
||||||
start_time = time.time()
|
start_time = time.time()
|
||||||
last_url = self.browser.url
|
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:
|
while time.time() - start_time < max_wait:
|
||||||
try:
|
try:
|
||||||
@ -553,9 +599,9 @@ class OAuthHandler:
|
|||||||
token = value.split("%3A%3A")[-1]
|
token = value.split("%3A%3A")[-1]
|
||||||
|
|
||||||
if token:
|
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
|
# 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")
|
self.browser.get("https://www.cursor.com/settings")
|
||||||
time.sleep(3) # Wait for settings page to load
|
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)")
|
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:
|
if email_element:
|
||||||
actual_email = email_element.text
|
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:
|
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"
|
actual_email = "user@cursor.sh"
|
||||||
|
|
||||||
# Check usage count
|
# 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)")
|
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:
|
if usage_element:
|
||||||
usage_text = usage_element.text
|
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
|
# Check if account is expired
|
||||||
if usage_text.strip() == "150 / 150":
|
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 = """
|
delete_js = """
|
||||||
function deleteAccount() {
|
function deleteAccount() {
|
||||||
@ -610,23 +656,23 @@ class OAuthHandler:
|
|||||||
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} Delete account result: {result}{Style.RESET_ALL}")
|
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} Delete account result: {result}{Style.RESET_ALL}")
|
||||||
|
|
||||||
# Navigate back to auth page and repeat authentication
|
# 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']} {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']} 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}")
|
||||||
|
|
||||||
# Explicitly navigate to the authentication page
|
# Explicitly navigate to the authentication page
|
||||||
self.browser.get("https://authenticator.cursor.sh/sign-up")
|
self.browser.get("https://authenticator.cursor.sh/sign-up")
|
||||||
time.sleep(get_random_wait_time(self.config, 'page_load_wait'))
|
time.sleep(get_random_wait_time(self.config, 'page_load_wait'))
|
||||||
|
|
||||||
# Call handle_google_auth again to repeat the entire process
|
# 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()
|
return self.handle_google_auth()
|
||||||
|
|
||||||
except Exception as e:
|
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:
|
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:
|
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
|
# Remove the browser stay open prompt and input wait
|
||||||
return True, {"email": actual_email, "token": token}
|
return True, {"email": actual_email, "token": token}
|
||||||
@ -634,7 +680,7 @@ class OAuthHandler:
|
|||||||
# Also check URL as backup
|
# Also check URL as backup
|
||||||
current_url = self.browser.url
|
current_url = self.browser.url
|
||||||
if "cursor.com/settings" in current_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)
|
time.sleep(1)
|
||||||
cookies = self.browser.cookies()
|
cookies = self.browser.cookies()
|
||||||
for cookie in 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)")
|
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:
|
if email_element:
|
||||||
actual_email = email_element.text
|
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:
|
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"
|
actual_email = "user@cursor.sh"
|
||||||
|
|
||||||
# Check usage count
|
# 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)")
|
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:
|
if usage_element:
|
||||||
usage_text = usage_element.text
|
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
|
# Check if account is expired
|
||||||
if usage_text.strip() == "150 / 150":
|
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 = """
|
delete_js = """
|
||||||
function deleteAccount() {
|
function deleteAccount() {
|
||||||
@ -696,44 +742,44 @@ class OAuthHandler:
|
|||||||
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} Delete account result: {result}{Style.RESET_ALL}")
|
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} Delete account result: {result}{Style.RESET_ALL}")
|
||||||
|
|
||||||
# Navigate back to auth page and repeat authentication
|
# 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']} {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']} 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}")
|
||||||
|
|
||||||
# Explicitly navigate to the authentication page
|
# Explicitly navigate to the authentication page
|
||||||
self.browser.get("https://authenticator.cursor.sh/sign-up")
|
self.browser.get("https://authenticator.cursor.sh/sign-up")
|
||||||
time.sleep(get_random_wait_time(self.config, 'page_load_wait'))
|
time.sleep(get_random_wait_time(self.config, 'page_load_wait'))
|
||||||
|
|
||||||
# Call handle_google_auth again to repeat the entire process
|
# 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()
|
return self.handle_google_auth()
|
||||||
|
|
||||||
except Exception as e:
|
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:
|
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:
|
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
|
# Remove the browser stay open prompt and input wait
|
||||||
return True, {"email": actual_email, "token": token}
|
return True, {"email": actual_email, "token": token}
|
||||||
elif current_url != last_url:
|
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
|
last_url = current_url
|
||||||
time.sleep(get_random_wait_time(self.config, 'page_load_wait'))
|
time.sleep(get_random_wait_time(self.config, 'page_load_wait'))
|
||||||
except Exception as e:
|
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)
|
time.sleep(1)
|
||||||
continue
|
continue
|
||||||
time.sleep(1)
|
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
|
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
|
return False, None
|
||||||
|
|
||||||
except Exception as e:
|
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
|
return False, None
|
||||||
finally:
|
finally:
|
||||||
if self.browser:
|
if self.browser:
|
||||||
@ -756,7 +802,7 @@ class OAuthHandler:
|
|||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
|
|
||||||
# Debug cookie information
|
# 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
|
email = None
|
||||||
token = None
|
token = None
|
||||||
@ -771,12 +817,12 @@ class OAuthHandler:
|
|||||||
elif "%3A%3A" in value:
|
elif "%3A%3A" in value:
|
||||||
token = value.split("%3A%3A")[-1]
|
token = value.split("%3A%3A")[-1]
|
||||||
except Exception as e:
|
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":
|
elif name == "cursor_email":
|
||||||
email = cookie.get("value")
|
email = cookie.get("value")
|
||||||
|
|
||||||
if email and token:
|
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}
|
return True, {"email": email, "token": token}
|
||||||
else:
|
else:
|
||||||
missing = []
|
missing = []
|
||||||
@ -784,11 +830,11 @@ class OAuthHandler:
|
|||||||
missing.append("email")
|
missing.append("email")
|
||||||
if not token:
|
if not token:
|
||||||
missing.append("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
|
return False, None
|
||||||
|
|
||||||
except Exception as e:
|
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
|
return False, None
|
||||||
|
|
||||||
def _delete_current_account(self):
|
def _delete_current_account(self):
|
||||||
@ -823,14 +869,14 @@ class OAuthHandler:
|
|||||||
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} Delete account result: {result}{Style.RESET_ALL}")
|
print(f"{Fore.GREEN}{EMOJI['SUCCESS']} Delete account result: {result}{Style.RESET_ALL}")
|
||||||
|
|
||||||
# Navigate back to auth page
|
# 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")
|
self.browser.get("https://authenticator.cursor.sh/sign-up")
|
||||||
time.sleep(get_random_wait_time(self.config, 'page_load_wait'))
|
time.sleep(get_random_wait_time(self.config, 'page_load_wait'))
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
except Exception as e:
|
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
|
return False
|
||||||
|
|
||||||
def main(auth_type, translator=None):
|
def main(auth_type, translator=None):
|
||||||
@ -843,13 +889,13 @@ def main(auth_type, translator=None):
|
|||||||
handler = OAuthHandler(translator, auth_type)
|
handler = OAuthHandler(translator, auth_type)
|
||||||
|
|
||||||
if auth_type.lower() == 'google':
|
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()
|
success, auth_info = handler.handle_google_auth()
|
||||||
elif auth_type.lower() == 'github':
|
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()
|
success, auth_info = handler.handle_github_auth()
|
||||||
else:
|
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
|
return False
|
||||||
|
|
||||||
if success and auth_info:
|
if success and auth_info:
|
||||||
@ -860,13 +906,13 @@ def main(auth_type, translator=None):
|
|||||||
access_token=auth_info["token"],
|
access_token=auth_info["token"],
|
||||||
refresh_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
|
# Close the browser after successful authentication
|
||||||
if handler.browser:
|
if handler.browser:
|
||||||
handler.browser.quit()
|
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
|
return True
|
||||||
else:
|
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
|
return False
|
Loading…
x
Reference in New Issue
Block a user