From a66a0e5395476b789c4b22c622219dd97ab6210b Mon Sep 17 00:00:00 2001 From: Nigel1992 Date: Thu, 3 Apr 2025 00:51:04 +0200 Subject: [PATCH 1/4] feat(oauth): add Chrome profile selection feature - Add new menu option to select which Chrome profile to use - Display actual profile names from Chrome's Local State - Add safety warning and confirmation before closing Chrome - Add translations for all supported languages --- locales/bg.json | 12 ++++ locales/de.json | 17 ++++- locales/en.json | 15 ++++- locales/es.json | 14 ++++- locales/fr.json | 12 ++++ locales/nl.json | 33 +++++++--- locales/pt.json | 12 ++++ locales/ru.json | 12 ++++ locales/tr.json | 12 ++++ locales/vi.json | 17 ++++- locales/zh_cn.json | 26 +++++--- locales/zh_tw.json | 26 ++++++-- main.py | 12 +++- oauth_auth.py | 153 +++++++++++++++++++++------------------------ 14 files changed, 260 insertions(+), 113 deletions(-) diff --git a/locales/bg.json b/locales/bg.json index e5478af..5f227f6 100644 --- a/locales/bg.json +++ b/locales/bg.json @@ -388,5 +388,17 @@ "electron_localstorage_files_removed": "Electron localStorage файлове бяха премахнати", "electron_localstorage_files_removal_error": "Грешка при премахване на Electron localStorage файлове: {error}", "removing_electron_localstorage_files_completed": "Премахването на Electron localStorage файлове беше завършено" + }, + "chrome_profile": { + "title": "Избор на Chrome Профил", + "select_profile": "Изберете Chrome профил за използване:", + "profile_list": "Налични профили:", + "default_profile": "Профил по Подразбиране", + "profile": "Профил {number}", + "no_profiles": "Не са намерени Chrome профили", + "error_loading": "Грешка при зареждане на Chrome профили: {error}", + "profile_selected": "Избран профил: {profile}", + "invalid_selection": "Невалиден избор. Моля, опитайте отново", + "warning_chrome_close": "Предупреждение: Това ще затвори всички работещи Chrome процеси" } } \ No newline at end of file diff --git a/locales/de.json b/locales/de.json index fba1188..78b5fae 100644 --- a/locales/de.json +++ b/locales/de.json @@ -6,10 +6,11 @@ "register": "Neues Cursor-Konto Registrieren", "register_google": "Mit Google-Konto Registrieren", "register_github": "Mit GitHub-Konto Registrieren", - "register_manual": "Cursor mit Benutzerdefinierter E-Mail Registrieren", + "register_manual": "Cursor Mit Benutzerdefinierter E-Mail Registrieren", "quit": "Cursor-Anwendung Schließen", "select_language": "Sprache Ändern", - "input_choice": "Bitte Auswahl eingeben ({choices})", + "select_chrome_profile": "Chrome-Profil Auswählen", + "input_choice": "Bitte geben Sie Ihre Auswahl ein ({choices})", "invalid_choice": "Ungültige Auswahl. Bitte eine Nummer von {choices} eingeben", "program_terminated": "Programm wurde vom Benutzer beendet", "error_occurred": "Ein Fehler ist aufgetreten: {error}. Bitte erneut versuchen", @@ -376,5 +377,17 @@ "electron_localstorage_files_removed": "Electron localStorage-Dateien entfernt", "electron_localstorage_files_removal_error": "Fehler beim Entfernen von Electron localStorage-Dateien: {error}", "removing_electron_localstorage_files_completed": "Entfernen von Electron localStorage-Dateien abgeschlossen" + }, + "chrome_profile": { + "title": "Chrome-Profil Auswahl", + "select_profile": "Wählen Sie ein Chrome-Profil zum Verwenden:", + "profile_list": "Verfügbare Profile:", + "default_profile": "Standard-Profil", + "profile": "Profil {number}", + "no_profiles": "Keine Chrome-Profile gefunden", + "error_loading": "Fehler beim Laden der Chrome-Profile: {error}", + "profile_selected": "Ausgewähltes Profil: {profile}", + "invalid_selection": "Ungültige Auswahl. Bitte versuchen Sie es erneut", + "warning_chrome_close": "Warnung: Dies wird alle laufenden Chrome-Prozesse beenden" } } \ No newline at end of file diff --git a/locales/en.json b/locales/en.json index f5e84a8..6868432 100644 --- a/locales/en.json +++ b/locales/en.json @@ -9,6 +9,7 @@ "register_manual": "Register Cursor with Custom Email", "quit": "Close Cursor Application", "select_language": "Change Language", + "select_chrome_profile": "Select Chrome Profile", "input_choice": "Please enter your choice ({choices})", "invalid_choice": "Invalid selection. Please enter a number from {choices}", "program_terminated": "Program was terminated by user", @@ -581,5 +582,17 @@ "warning_could_not_kill_existing_browser_processes": "Warning: Could not kill existing browser processes: {error}", "browser_failed_to_start": "Browser failed to start: {error}", "browser_failed": "Browser failed to start: {error}" + }, + "chrome_profile": { + "title": "Chrome Profile Selection", + "select_profile": "Select a Chrome profile to use:", + "profile_list": "Available profiles:", + "default_profile": "Default Profile", + "profile": "Profile {number}", + "no_profiles": "No Chrome profiles found", + "error_loading": "Error loading Chrome profiles: {error}", + "profile_selected": "Selected profile: {profile}", + "invalid_selection": "Invalid selection. Please try again", + "warning_chrome_close": "Warning: This will close all running Chrome processes" } -} \ No newline at end of file +} \ No newline at end of file diff --git a/locales/es.json b/locales/es.json index 4fa72e1..2890e34 100644 --- a/locales/es.json +++ b/locales/es.json @@ -439,5 +439,17 @@ "completed_successfully": "¡Registro de GitHub + Cursor completado exitosamente!", "registration_encountered_issues": "El registro de GitHub + Cursor encontró problemas.", "check_browser_windows_for_manual_intervention_or_try_again_later": "Revise las ventanas del navegador para intervención manual o intente nuevamente más tarde." - } + }, + "chrome_profile": { + "title": "Selección de Perfil de Chrome", + "select_profile": "Seleccione un perfil de Chrome para usar:", + "profile_list": "Perfiles disponibles:", + "default_profile": "Perfil Predeterminado", + "profile": "Perfil {number}", + "no_profiles": "No se encontraron perfiles de Chrome", + "error_loading": "Error al cargar perfiles de Chrome: {error}", + "profile_selected": "Perfil seleccionado: {profile}", + "invalid_selection": "Selección inválida. Por favor, intente de nuevo", + "warning_chrome_close": "Advertencia: Esto cerrará todos los procesos de Chrome en ejecución" + } } diff --git a/locales/fr.json b/locales/fr.json index bbca221..7a4e908 100644 --- a/locales/fr.json +++ b/locales/fr.json @@ -374,5 +374,17 @@ "electron_localstorage_files_removed": "Fichiers localStorage Electron supprimés", "electron_localstorage_files_removal_error": "Erreur de suppression des fichiers localStorage Electron: {error}", "removing_electron_localstorage_files_completed": "Suppression des fichiers localStorage Electron terminée" + }, + "chrome_profile": { + "title": "Sélection du Profil Chrome", + "select_profile": "Sélectionnez un profil Chrome à utiliser :", + "profile_list": "Profils disponibles :", + "default_profile": "Profil par Défaut", + "profile": "Profil {number}", + "no_profiles": "Aucun profil Chrome trouvé", + "error_loading": "Erreur lors du chargement des profils Chrome : {error}", + "profile_selected": "Profil sélectionné : {profile}", + "invalid_selection": "Sélection invalide. Veuillez réessayer", + "warning_chrome_close": "Attention : Cela fermera tous les processus Chrome en cours d'exécution" } } \ No newline at end of file diff --git a/locales/nl.json b/locales/nl.json index 6472bad..f4d3277 100644 --- a/locales/nl.json +++ b/locales/nl.json @@ -1,15 +1,16 @@ { "menu": { - "title": "Beschikbare opties", - "exit": "Programma afsluiten", - "reset": "Machine-ID resetten", - "register": "Nieuw Cursor-account registreren", - "register_google": "Registreren met Google-account", - "register_github": "Registreren met GitHub-account", - "register_manual": "Cursor registreren met aangepast e-mailadres", - "quit": "Cursor-applicatie sluiten", - "select_language": "Taal wijzigen", - "input_choice": "Voer uw keuze in: {choices}", + "title": "Beschikbare Opties", + "exit": "Programma Afsluiten", + "reset": "Machine ID Resetten", + "register": "Nieuw Cursor Account Registreren", + "register_google": "Registreren met Google Account", + "register_github": "Registreren met GitHub Account", + "register_manual": "Cursor Registreren met Aangepaste E-mail", + "quit": "Cursor Toepassing Sluiten", + "select_language": "Taal Wijzigen", + "select_chrome_profile": "Chrome Profiel Selecteren", + "input_choice": "Voer uw keuze in ({choices})", "invalid_choice": "Ongeldige selectie. Voer een nummer in uit {choices}.", "program_terminated": "Programma is beëindigd door de gebruiker", "error_occurred": "Er is een fout opgetreden: {error}. Probeer het opnieuw.", @@ -374,5 +375,17 @@ "electron_localstorage_files_removed": "Electron localStorage-bestanden verwijderd", "electron_localstorage_files_removal_error": "Fout bij het verwijderen van Electron localStorage-bestanden: {error}", "removing_electron_localstorage_files_completed": "Electron localStorage-bestanden verwijderd" + }, + "chrome_profile": { + "title": "Chrome Profiel Selectie", + "select_profile": "Selecteer een Chrome profiel om te gebruiken:", + "profile_list": "Beschikbare profielen:", + "default_profile": "Standaard Profiel", + "profile": "Profiel {number}", + "no_profiles": "Geen Chrome profielen gevonden", + "error_loading": "Fout bij laden van Chrome profielen: {error}", + "profile_selected": "Geselecteerd profiel: {profile}", + "invalid_selection": "Ongeldige selectie. Probeer het opnieuw", + "warning_chrome_close": "Waarschuwing: Dit zal alle actieve Chrome processen sluiten" } } diff --git a/locales/pt.json b/locales/pt.json index 8e45b51..7af65fe 100644 --- a/locales/pt.json +++ b/locales/pt.json @@ -383,5 +383,17 @@ "electron_localstorage_files_removed": "Arquivos localStorage do Electron removidos", "electron_localstorage_files_removal_error": "Erro ao remover arquivos localStorage do Electron: {error}", "removing_electron_localstorage_files_completed": "Remoção dos arquivos localStorage do Electron concluída" + }, + "chrome_profile": { + "title": "Seleção de Perfil do Chrome", + "select_profile": "Selecione um perfil do Chrome para usar:", + "profile_list": "Perfis disponíveis:", + "default_profile": "Perfil Padrão", + "profile": "Perfil {number}", + "no_profiles": "Nenhum perfil do Chrome encontrado", + "error_loading": "Erro ao carregar perfis do Chrome: {error}", + "profile_selected": "Perfil selecionado: {profile}", + "invalid_selection": "Seleção inválida. Por favor, tente novamente", + "warning_chrome_close": "Aviso: Isso fechará todos os processos do Chrome em execução" } } diff --git a/locales/ru.json b/locales/ru.json index ee0bb28..ee642c4 100644 --- a/locales/ru.json +++ b/locales/ru.json @@ -383,5 +383,17 @@ "electron_localstorage_files_removed": "Файлы localStorage Electron удалены", "electron_localstorage_files_removal_error": "Ошибка удаления файлов localStorage Electron: {error}", "removing_electron_localstorage_files_completed": "Удаление файлов localStorage Electron завершено" + }, + "chrome_profile": { + "title": "Выбор Профиля Chrome", + "select_profile": "Выберите профиль Chrome для использования:", + "profile_list": "Доступные профили:", + "default_profile": "Профиль по умолчанию", + "profile": "Профиль {number}", + "no_profiles": "Профили Chrome не найдены", + "error_loading": "Ошибка загрузки профилей Chrome: {error}", + "profile_selected": "Выбран профиль: {profile}", + "invalid_selection": "Неверный выбор. Пожалуйста, попробуйте снова", + "warning_chrome_close": "Предупреждение: Это закроет все запущенные процессы Chrome" } } \ No newline at end of file diff --git a/locales/tr.json b/locales/tr.json index d24722e..e657fcb 100644 --- a/locales/tr.json +++ b/locales/tr.json @@ -386,5 +386,17 @@ "electron_localstorage_files_removed": "Electron localStorage dosyaları kaldırıldı", "electron_localstorage_files_removal_error": "Electron localStorage dosyaları kaldırılırken hata: {error}", "removing_electron_localstorage_files_completed": "Electron localStorage dosyaları kaldırma işlemi tamamlandı" + }, + "chrome_profile": { + "title": "Chrome Profil Seçimi", + "select_profile": "Kullanılacak Chrome profilini seçin:", + "profile_list": "Mevcut profiller:", + "default_profile": "Varsayılan Profil", + "profile": "Profil {number}", + "no_profiles": "Chrome profili bulunamadı", + "error_loading": "Chrome profilleri yüklenirken hata: {error}", + "profile_selected": "Seçilen profil: {profile}", + "invalid_selection": "Geçersiz seçim. Lütfen tekrar deneyin", + "warning_chrome_close": "Uyarı: Bu işlem tüm çalışan Chrome işlemlerini kapatacaktır" } } diff --git a/locales/vi.json b/locales/vi.json index 6eba332..8a7e729 100644 --- a/locales/vi.json +++ b/locales/vi.json @@ -1,12 +1,15 @@ { "menu": { - "title": "Các Tùy Chọn Khả Dụng", + "title": "Các Tùy Chọn", "exit": "Thoát Chương Trình", "reset": "Đặt Lại ID Máy", "register": "Đăng Ký Tài Khoản Cursor Mới", + "register_google": "Đăng Ký Bằng Tài Khoản Google", + "register_github": "Đăng Ký Bằng Tài Khoản GitHub", "register_manual": "Đăng Ký Cursor Với Email Tùy Chỉnh", "quit": "Đóng Ứng Dụng Cursor", "select_language": "Thay Đổi Ngôn Ngữ", + "select_chrome_profile": "Chọn Hồ Sơ Chrome", "input_choice": "Vui lòng nhập lựa chọn của bạn ({choices})", "invalid_choice": "Lựa chọn không hợp lệ. Vui lòng nhập một số từ {choices}", "program_terminated": "Chương trình đã bị người dùng chấm dứt", @@ -381,5 +384,17 @@ "electron_localstorage_files_removed": "Đã xóa các tệp Electron localStorage", "electron_localstorage_files_removal_error": "Lỗi khi xóa các tệp Electron localStorage: {error}", "removing_electron_localstorage_files_completed": "Đã hoàn tất việc xóa các tệp Electron localStorage" + }, + "chrome_profile": { + "title": "Chọn Hồ Sơ Chrome", + "select_profile": "Chọn hồ sơ Chrome để sử dụng:", + "profile_list": "Các hồ sơ có sẵn:", + "default_profile": "Hồ Sơ Mặc Định", + "profile": "Hồ Sơ {number}", + "no_profiles": "Không tìm thấy hồ sơ Chrome", + "error_loading": "Lỗi khi tải hồ sơ Chrome: {error}", + "profile_selected": "Đã chọn hồ sơ: {profile}", + "invalid_selection": "Lựa chọn không hợp lệ. Vui lòng thử lại", + "warning_chrome_close": "Cảnh báo: Điều này sẽ đóng tất cả các tiến trình Chrome đang chạy" } } \ No newline at end of file diff --git a/locales/zh_cn.json b/locales/zh_cn.json index 1a4d304..f94ce50 100644 --- a/locales/zh_cn.json +++ b/locales/zh_cn.json @@ -2,13 +2,14 @@ "menu": { "title": "可用选项", "exit": "退出程序", - "reset": "重置机器标识", - "register": "注册新 Cursor 账号", - "register_google": "使用 Google 账号注册", - "register_github": "使用 GitHub 账号注册", - "register_manual": "使用自定义邮箱注册", - "quit": "关闭 Cursor 应用", + "reset": "重置机器ID", + "register": "注册新的Cursor账户", + "register_google": "使用Google账户注册", + "register_github": "使用GitHub账户注册", + "register_manual": "使用自定义邮箱注册Cursor", + "quit": "关闭Cursor应用", "select_language": "更改语言", + "select_chrome_profile": "选择Chrome配置文件", "input_choice": "请输入您的选择 ({choices})", "invalid_choice": "选择无效,请输入 {choices} 范围内的数字", "program_terminated": "程序已被用户终止", @@ -576,6 +577,17 @@ "warning_could_not_kill_existing_browser_processes": "警告: 无法杀死现有浏览器进程: {error}", "browser_failed_to_start": "浏览器启动失败: {error}", "browser_failed": "浏览器启动失败: {error}" + }, + "chrome_profile": { + "title": "Chrome配置文件选择", + "select_profile": "选择要使用的Chrome配置文件:", + "profile_list": "可用配置文件:", + "default_profile": "默认配置文件", + "profile": "配置文件 {number}", + "no_profiles": "未找到Chrome配置文件", + "error_loading": "加载Chrome配置文件时出错:{error}", + "profile_selected": "已选择配置文件:{profile}", + "invalid_selection": "选择无效。请重试", + "warning_chrome_close": "警告:这将关闭所有正在运行的Chrome进程" } - } \ No newline at end of file diff --git a/locales/zh_tw.json b/locales/zh_tw.json index ab97eed..1748909 100644 --- a/locales/zh_tw.json +++ b/locales/zh_tw.json @@ -2,11 +2,14 @@ "menu": { "title": "可用選項", "exit": "退出程式", - "reset": "重置機器識別碼", - "register": "註冊新 Cursor 帳號", - "register_manual": "使用自訂郵箱註冊", - "quit": "關閉 Cursor 應用程式", - "select_language": "變更語言", + "reset": "重置機器ID", + "register": "註冊新的Cursor帳戶", + "register_google": "使用Google帳戶註冊", + "register_github": "使用GitHub帳戶註冊", + "register_manual": "使用自定義郵箱註冊Cursor", + "quit": "關閉Cursor應用", + "select_language": "更改語言", + "select_chrome_profile": "選擇Chrome配置檔案", "input_choice": "請輸入您的選擇 ({choices})", "invalid_choice": "選擇無效,請輸入 {choices} 範圍內的數字", "program_terminated": "程式已被使用者終止", @@ -498,7 +501,6 @@ "storage_file_is_valid_and_contains_data": "儲存文件有效且包含數據", "error_reading_storage_file": "讀取儲存文件時出錯", "also_checked": "也檢查了 {path}" - }, "oauth": { "authentication_button_not_found": "未找到認證按鈕", @@ -556,5 +558,17 @@ "warning_could_not_kill_existing_browser_processes": "警告: 無法殺死現有瀏覽器進程: {error}", "browser_failed_to_start": "瀏覽器啟動失敗: {error}", "browser_failed": "瀏覽器啟動失敗: {error}" + }, + "chrome_profile": { + "title": "Chrome配置檔案選擇", + "select_profile": "選擇要使用的Chrome配置檔案:", + "profile_list": "可用配置檔案:", + "default_profile": "預設配置檔案", + "profile": "配置檔案 {number}", + "no_profiles": "未找到Chrome配置檔案", + "error_loading": "載入Chrome配置檔案時出錯:{error}", + "profile_selected": "已選擇配置檔案:{profile}", + "invalid_selection": "選擇無效。請重試", + "warning_chrome_close": "警告:這將關閉所有正在執行的Chrome程序" } } \ No newline at end of file diff --git a/main.py b/main.py index ba7ca89..7a2ad94 100644 --- a/main.py +++ b/main.py @@ -284,7 +284,8 @@ def print_menu(): 9: f"{Fore.GREEN}9{Style.RESET_ALL}. {EMOJI['UPDATE']} {translator.get('menu.disable_auto_update')}", 10: f"{Fore.GREEN}10{Style.RESET_ALL}. {EMOJI['RESET']} {translator.get('menu.totally_reset')}", 11: f"{Fore.GREEN}11{Style.RESET_ALL}. {EMOJI['CONTRIBUTE']} {translator.get('menu.contribute')}", - 12: f"{Fore.GREEN}12{Style.RESET_ALL}. {EMOJI['SETTINGS']} {translator.get('menu.config')}" + 12: f"{Fore.GREEN}12{Style.RESET_ALL}. {EMOJI['SETTINGS']} {translator.get('menu.config')}", + 13: f"{Fore.GREEN}13{Style.RESET_ALL}. {EMOJI['SETTINGS']} {translator.get('menu.select_chrome_profile')}" } # Automatically calculate the number of menu items in the left and right columns @@ -556,7 +557,7 @@ def main(): while True: try: - choice_num = 12 + choice_num = 13 choice = input(f"\n{EMOJI['ARROW']} {Fore.CYAN}{translator.get('menu.input_choice', choices=f'0-{choice_num}')}: {Style.RESET_ALL}") if choice == "0": @@ -613,6 +614,13 @@ def main(): from config import print_config print_config(get_config(), translator) print_menu() + elif choice == "13": + from oauth_auth import OAuthHandler + oauth = OAuthHandler(translator) + user_data_dir = oauth._get_user_data_directory() + if user_data_dir: + oauth._select_profile(user_data_dir) + print_menu() else: print(f"{Fore.RED}{EMOJI['ERROR']} {translator.get('menu.invalid_choice')}{Style.RESET_ALL}") print_menu() diff --git a/oauth_auth.py b/oauth_auth.py index 5da5b16..fafb3f8 100644 --- a/oauth_auth.py +++ b/oauth_auth.py @@ -32,76 +32,81 @@ class OAuthHandler: self.auth_type = auth_type # make sure the auth_type is not None os.environ['BROWSER_HEADLESS'] = 'False' self.browser = None + self.selected_profile = None - def _get_active_profile(self, user_data_dir): - """Find the existing default/active Chrome profile""" + def _get_available_profiles(self, user_data_dir): + """Get list of available Chrome profiles with their names""" try: - # List all profile directories profiles = [] - for item in os.listdir(user_data_dir): - if item == 'Default' or (item.startswith('Profile ') and os.path.isdir(os.path.join(user_data_dir, item))): - profiles.append(item) + profile_names = {} - if not profiles: - print(f"{Fore.YELLOW}{EMOJI['INFO']} {self.translator.get('oauth.no_chrome_profiles_found') if self.translator else 'No Chrome profiles found, using Default'}{Style.RESET_ALL}") - return 'Default' - - # First check if Default profile exists - if 'Default' in profiles: - print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('oauth.found_default_chrome_profile') if self.translator else 'Found Default Chrome profile'}{Style.RESET_ALL}") - return 'Default' - - # If no Default profile, check Local State for last used profile + # Read Local State file to get profile names local_state_path = os.path.join(user_data_dir, 'Local State') if os.path.exists(local_state_path): with open(local_state_path, 'r', encoding='utf-8') as f: local_state = json.load(f) - - # Get info about last used profile - profile_info = local_state.get('profile', {}) - last_used = profile_info.get('last_used', '') - info_cache = profile_info.get('info_cache', {}) - - # Try to find an active profile - for profile in profiles: - profile_path = profile.replace('\\', '/') - if profile_path in info_cache: - #print(f"{Fore.CYAN}{EMOJI['INFO']} Using existing Chrome profile: {profile}{Style.RESET_ALL}") - return profile + info_cache = local_state.get('profile', {}).get('info_cache', {}) + for profile_dir, info in info_cache.items(): + profile_dir = profile_dir.replace('\\', '/') + if profile_dir == 'Default': + profile_names['Default'] = info.get('name', 'Default') + elif profile_dir.startswith('Profile '): + profile_names[profile_dir] = info.get('name', profile_dir) + + # Get list of profile directories + for item in os.listdir(user_data_dir): + if item == 'Default' or (item.startswith('Profile ') and os.path.isdir(os.path.join(user_data_dir, item))): + profiles.append((item, profile_names.get(item, item))) + return sorted(profiles) + except Exception as e: + print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('chrome_profile.error_loading', error=str(e)) if self.translator else f'Error loading Chrome profiles: {e}'}{Style.RESET_ALL}") + return [] + + def _select_profile(self, user_data_dir): + """Let user select a Chrome profile""" + try: + profiles = self._get_available_profiles(user_data_dir) + if not profiles: + print(f"{Fore.YELLOW}{EMOJI['INFO']} {self.translator.get('chrome_profile.no_profiles') if self.translator else 'No Chrome profiles found'}{Style.RESET_ALL}") + return 'Default' - # If no profile found in Local State, use the first available profile - 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] + # Display warning about closing Chrome processes + print(f"\n{Fore.YELLOW}{EMOJI['WARNING']} {self.translator.get('chrome_profile.warning_chrome_close') if self.translator else 'Warning: This will close all running Chrome processes'}{Style.RESET_ALL}") + + print(f"\n{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('chrome_profile.select_profile') if self.translator else 'Select a Chrome profile to use:'}{Style.RESET_ALL}") + print(f"{Fore.CYAN}{self.translator.get('chrome_profile.profile_list') if self.translator else 'Available profiles:'}{Style.RESET_ALL}") + + for i, (profile_dir, profile_name) in enumerate(profiles, 1): + display_name = self.translator.get('chrome_profile.default_profile') if self.translator and profile_dir == 'Default' else \ + profile_name if profile_name else \ + self.translator.get('chrome_profile.profile', number=i) if self.translator else f'Profile {i}' + print(f"{Fore.CYAN}{i}. {display_name} ({profile_dir}){Style.RESET_ALL}") + + while True: + try: + choice = input(f"\n{Fore.CYAN}{self.translator.get('menu.input_choice', choices=f'1-{len(profiles)}') if self.translator else f'Please enter your choice (1-{len(profiles)}): '}{Style.RESET_ALL}") + choice = int(choice) + if 1 <= choice <= len(profiles): + selected = profiles[choice - 1][0] # Get the profile directory name + print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('chrome_profile.profile_selected', profile=selected) if self.translator else f'Selected profile: {selected}'}{Style.RESET_ALL}") + return selected + else: + print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('chrome_profile.invalid_selection') if self.translator else 'Invalid selection. Please try again.'}{Style.RESET_ALL}") + except ValueError: + print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('chrome_profile.invalid_selection') if self.translator else 'Invalid selection. Please try again.'}{Style.RESET_ALL}") except Exception as e: - 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}") + print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('chrome_profile.error_loading', error=str(e)) if self.translator else f'Error loading Chrome profiles: {e}'}{Style.RESET_ALL}") return 'Default' def setup_browser(self): - """Setup browser for OAuth flow using active profile""" + """Setup browser for OAuth flow using selected profile""" try: - print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('oauth.initializing_browser_setup') if self.translator else 'Initializing browser setup...'}{Style.RESET_ALL}") + print(f"{Fore.CYAN}{EMOJI['INFO']} Initializing browser setup...{Style.RESET_ALL}") # Platform-specific initialization platform_name = platform.system().lower() - print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('oauth.detected_platform', platform=platform_name) if self.translator else f'Detected platform: {platform_name}'}{Style.RESET_ALL}") - - # Linux-specific checks - if platform_name == 'linux': - # Check if DISPLAY is set - display = os.environ.get('DISPLAY') - if not display: - print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('oauth.no_display_found') if self.translator else 'No display found. Make sure X server is running.'}{Style.RESET_ALL}") - print(f"{Fore.YELLOW}{EMOJI['INFO']} {self.translator.get('oauth.try_export_display') if self.translator else 'Try: export DISPLAY=:0'}{Style.RESET_ALL}") - return False - - # Check if running as root - if os.geteuid() == 0: - print(f"{Fore.YELLOW}{EMOJI['WARNING']} {self.translator.get('oauth.running_as_root_warning') if self.translator else 'Running as root is not recommended for browser automation'}{Style.RESET_ALL}") - print(f"{Fore.YELLOW}{EMOJI['INFO']} {self.translator.get('oauth.consider_running_without_sudo') if self.translator else 'Consider running the script without sudo'}{Style.RESET_ALL}") - - # Kill existing browser processes - self._kill_browser_processes() + print(f"{Fore.CYAN}{EMOJI['INFO']} Detected platform: {platform_name}{Style.RESET_ALL}") # Get browser paths and user data directory user_data_dir = self._get_user_data_directory() @@ -113,40 +118,22 @@ class OAuthHandler: "- macOS: Google Chrome, Chromium\n" + "- Linux: Google Chrome, Chromium, chromium-browser") - # Get active profile - active_profile = self._get_active_profile(user_data_dir) + # Show warning about closing Chrome first + print(f"\n{Fore.YELLOW}{EMOJI['WARNING']} {self.translator.get('chrome_profile.warning_chrome_close') if self.translator else 'Warning: This will close all running Chrome processes'}{Style.RESET_ALL}") + choice = input(f"{Fore.YELLOW}Continue? (y/N): {Style.RESET_ALL}").lower() + if choice != 'y': + print(f"{Fore.YELLOW}{EMOJI['INFO']} Operation cancelled by user{Style.RESET_ALL}") + return False + + # Kill existing browser processes + self._kill_browser_processes() + + # Let user select a profile + active_profile = self._select_profile(user_data_dir) print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('oauth.using_browser_profile', profile=active_profile) if self.translator else f'Using browser profile: {active_profile}'}{Style.RESET_ALL}") # Configure browser options - co = ChromiumOptions() - - # 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() + co = self._configure_browser_options(chrome_path, user_data_dir, active_profile) 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) From 5bfe653a924e40e8b9ddf529634e82d28674b3fa Mon Sep 17 00:00:00 2001 From: Nigel1992 Date: Thu, 3 Apr 2025 01:00:38 +0200 Subject: [PATCH 2/4] fix(oauth): remove duplicate Chrome warning message --- oauth_auth.py | 50 +++++++++++++++++++++++--------------------------- 1 file changed, 23 insertions(+), 27 deletions(-) diff --git a/oauth_auth.py b/oauth_auth.py index fafb3f8..6d2192a 100644 --- a/oauth_auth.py +++ b/oauth_auth.py @@ -62,42 +62,37 @@ class OAuthHandler: print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('chrome_profile.error_loading', error=str(e)) if self.translator else f'Error loading Chrome profiles: {e}'}{Style.RESET_ALL}") return [] - def _select_profile(self, user_data_dir): - """Let user select a Chrome profile""" + def _select_profile(self): + """Select a Chrome profile to use""" try: - profiles = self._get_available_profiles(user_data_dir) + # Get available profiles + profiles = self._get_available_profiles(self._get_user_data_directory()) if not profiles: print(f"{Fore.YELLOW}{EMOJI['INFO']} {self.translator.get('chrome_profile.no_profiles') if self.translator else 'No Chrome profiles found'}{Style.RESET_ALL}") - return 'Default' - - # Display warning about closing Chrome processes - print(f"\n{Fore.YELLOW}{EMOJI['WARNING']} {self.translator.get('chrome_profile.warning_chrome_close') if self.translator else 'Warning: This will close all running Chrome processes'}{Style.RESET_ALL}") + return False - print(f"\n{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('chrome_profile.select_profile') if self.translator else 'Select a Chrome profile to use:'}{Style.RESET_ALL}") - print(f"{Fore.CYAN}{self.translator.get('chrome_profile.profile_list') if self.translator else 'Available profiles:'}{Style.RESET_ALL}") - - for i, (profile_dir, profile_name) in enumerate(profiles, 1): - display_name = self.translator.get('chrome_profile.default_profile') if self.translator and profile_dir == 'Default' else \ - profile_name if profile_name else \ - self.translator.get('chrome_profile.profile', number=i) if self.translator else f'Profile {i}' - print(f"{Fore.CYAN}{i}. {display_name} ({profile_dir}){Style.RESET_ALL}") + # Display available profiles + print(f"\n{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('chrome_profile.select_prompt') if self.translator else 'Select a Chrome profile to use:'}{Style.RESET_ALL}") + print(f"{Fore.CYAN}{self.translator.get('chrome_profile.available_profiles') if self.translator else 'Available profiles:'}{Style.RESET_ALL}") + for i, (dir_name, display_name) in enumerate(profiles, 1): + print(f"{Fore.CYAN}{i}. {display_name} ({dir_name}){Style.RESET_ALL}") + # Get user selection while True: try: - choice = input(f"\n{Fore.CYAN}{self.translator.get('menu.input_choice', choices=f'1-{len(profiles)}') if self.translator else f'Please enter your choice (1-{len(profiles)}): '}{Style.RESET_ALL}") - choice = int(choice) + choice = int(input(f"\n{Fore.CYAN}{self.translator.get('chrome_profile.enter_choice', choices=f'1-{len(profiles)}') if self.translator else f'Please enter your choice (1-{len(profiles)}): '}{Style.RESET_ALL}")) if 1 <= choice <= len(profiles): - selected = profiles[choice - 1][0] # Get the profile directory name - print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('chrome_profile.profile_selected', profile=selected) if self.translator else f'Selected profile: {selected}'}{Style.RESET_ALL}") - return selected + self.selected_profile = profiles[choice - 1][0] + print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('chrome_profile.selected', profile=self.selected_profile) if self.translator else f'Selected profile: {self.selected_profile}'}{Style.RESET_ALL}") + return True else: - print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('chrome_profile.invalid_selection') if self.translator else 'Invalid selection. Please try again.'}{Style.RESET_ALL}") + print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('chrome_profile.invalid_choice') if self.translator else 'Invalid selection. Please try again.'}{Style.RESET_ALL}") except ValueError: - print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('chrome_profile.invalid_selection') if self.translator else 'Invalid selection. Please try again.'}{Style.RESET_ALL}") + print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('chrome_profile.invalid_choice') if self.translator else 'Invalid selection. Please try again.'}{Style.RESET_ALL}") except Exception as e: - print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('chrome_profile.error_loading', error=str(e)) if self.translator else f'Error loading Chrome profiles: {e}'}{Style.RESET_ALL}") - return 'Default' + print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('chrome_profile.error', error=str(e)) if self.translator else f'Error loading Chrome profiles: {e}'}{Style.RESET_ALL}") + return False def setup_browser(self): """Setup browser for OAuth flow using selected profile""" @@ -129,11 +124,12 @@ class OAuthHandler: self._kill_browser_processes() # Let user select a profile - active_profile = self._select_profile(user_data_dir) - 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}") + if not self._select_profile(): + print(f"{Fore.YELLOW}{EMOJI['INFO']} Operation cancelled by user{Style.RESET_ALL}") + return False # Configure browser options - co = self._configure_browser_options(chrome_path, user_data_dir, active_profile) + co = self._configure_browser_options(chrome_path, user_data_dir, self.selected_profile) 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) From f58bb70d3aef4b0da570c5367aa3a9d2b577f4c0 Mon Sep 17 00:00:00 2001 From: Nigel1992 Date: Thu, 3 Apr 2025 01:01:58 +0200 Subject: [PATCH 3/4] fix(oauth): fix translation keys in Chrome profile selection --- oauth_auth.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/oauth_auth.py b/oauth_auth.py index 6d2192a..fa5fabf 100644 --- a/oauth_auth.py +++ b/oauth_auth.py @@ -72,26 +72,26 @@ class OAuthHandler: return False # Display available profiles - print(f"\n{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('chrome_profile.select_prompt') if self.translator else 'Select a Chrome profile to use:'}{Style.RESET_ALL}") - print(f"{Fore.CYAN}{self.translator.get('chrome_profile.available_profiles') if self.translator else 'Available profiles:'}{Style.RESET_ALL}") + print(f"\n{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('chrome_profile.select_profile') if self.translator else 'Select a Chrome profile to use:'}{Style.RESET_ALL}") + print(f"{Fore.CYAN}{self.translator.get('chrome_profile.profile_list') if self.translator else 'Available profiles:'}{Style.RESET_ALL}") for i, (dir_name, display_name) in enumerate(profiles, 1): print(f"{Fore.CYAN}{i}. {display_name} ({dir_name}){Style.RESET_ALL}") # Get user selection while True: try: - choice = int(input(f"\n{Fore.CYAN}{self.translator.get('chrome_profile.enter_choice', choices=f'1-{len(profiles)}') if self.translator else f'Please enter your choice (1-{len(profiles)}): '}{Style.RESET_ALL}")) + choice = int(input(f"\n{Fore.CYAN}{self.translator.get('menu.input_choice', choices=f'1-{len(profiles)}') if self.translator else f'Please enter your choice (1-{len(profiles)}): '}{Style.RESET_ALL}")) if 1 <= choice <= len(profiles): self.selected_profile = profiles[choice - 1][0] - print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('chrome_profile.selected', profile=self.selected_profile) if self.translator else f'Selected profile: {self.selected_profile}'}{Style.RESET_ALL}") + print(f"{Fore.GREEN}{EMOJI['SUCCESS']} {self.translator.get('chrome_profile.profile_selected', profile=self.selected_profile) if self.translator else f'Selected profile: {self.selected_profile}'}{Style.RESET_ALL}") return True else: - print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('chrome_profile.invalid_choice') if self.translator else 'Invalid selection. Please try again.'}{Style.RESET_ALL}") + print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('chrome_profile.invalid_selection') if self.translator else 'Invalid selection. Please try again.'}{Style.RESET_ALL}") except ValueError: - print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('chrome_profile.invalid_choice') if self.translator else 'Invalid selection. Please try again.'}{Style.RESET_ALL}") + print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('chrome_profile.invalid_selection') if self.translator else 'Invalid selection. Please try again.'}{Style.RESET_ALL}") except Exception as e: - print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('chrome_profile.error', error=str(e)) if self.translator else f'Error loading Chrome profiles: {e}'}{Style.RESET_ALL}") + print(f"{Fore.RED}{EMOJI['ERROR']} {self.translator.get('chrome_profile.error_loading', error=str(e)) if self.translator else f'Error loading Chrome profiles: {e}'}{Style.RESET_ALL}") return False def setup_browser(self): From 671307b53b1a6a09bb536c7a0ef387fb53b708ef Mon Sep 17 00:00:00 2001 From: Nigel1992 Date: Thu, 3 Apr 2025 01:02:57 +0200 Subject: [PATCH 4/4] fix(oauth): remove duplicate browser data directory message --- oauth_auth.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/oauth_auth.py b/oauth_auth.py index fa5fabf..94e8695 100644 --- a/oauth_auth.py +++ b/oauth_auth.py @@ -113,6 +113,8 @@ class OAuthHandler: "- macOS: Google Chrome, Chromium\n" + "- Linux: Google Chrome, Chromium, chromium-browser") + print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('oauth.found_browser_data_directory', path=user_data_dir) if self.translator else f'Found browser data directory: {user_data_dir}'}{Style.RESET_ALL}") + # Show warning about closing Chrome first print(f"\n{Fore.YELLOW}{EMOJI['WARNING']} {self.translator.get('chrome_profile.warning_chrome_close') if self.translator else 'Warning: This will close all running Chrome processes'}{Style.RESET_ALL}") choice = input(f"{Fore.YELLOW}Continue? (y/N): {Style.RESET_ALL}").lower() @@ -191,7 +193,6 @@ class OAuthHandler: # Try each possible path for path in possible_paths: if os.path.exists(path): - print(f"{Fore.CYAN}{EMOJI['INFO']} {self.translator.get('oauth.found_browser_data_directory', path=path) if self.translator else f'Found browser data directory: {path}'}{Style.RESET_ALL}") return path # Create temporary profile if no existing profile found