From e0a7afd8352f797071241a283f7071fde049ca14 Mon Sep 17 00:00:00 2001 From: yeongpin Date: Sat, 22 Mar 2025 16:14:27 +0800 Subject: [PATCH] Update version to 1.7.15 and enhance GitHub + Cursor AI registration automation. Added Turkish language support, improved user confirmation prompts, and optimized logging. Updated CHANGELOG with new features and fixes. --- .env | 4 +- CHANGELOG.md | 16 ++ github_cursor_register.py | 45 ++++- locales/de.json | 7 +- locales/en.json | 30 ++- locales/fr.json | 5 +- locales/nl.json | 7 +- locales/pt.json | 7 +- locales/ru.json | 7 +- locales/tr.json | 7 +- locales/vi.json | 8 +- locales/zh_cn.json | 26 ++- locales/zh_tw.json | 30 ++- main.py | 31 +++- new_signup.py | 374 ++++++++++---------------------------- 15 files changed, 286 insertions(+), 318 deletions(-) diff --git a/.env b/.env index 3fd30cd..d2a1342 100644 --- a/.env +++ b/.env @@ -1,2 +1,2 @@ -version=1.7.14 -VERSION=1.7.14 +version=1.7.15 +VERSION=1.7.15 diff --git a/CHANGELOG.md b/CHANGELOG.md index beaade6..3c31e59 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,21 @@ # Change Log +## v1.7.15 +1. Fix: Cant Verify the User is Human | 修復無法驗證用戶是否為人類 +2. Added temporary email & GitHub + Cursor AI registration automation | 增加临时邮箱 & GitHub + Cursor AI 注册自动化 +3. Added Turkish language support | 增加土耳其语支持 +4. Removed outdated temporary option in Option 2 | 移除选项2中的过期临时添加项 +5. Enhanced machine ID reset (Linux, Windows, macOS), bypasses Cursor free trial detection | 机器 ID 重置支持 Linux/Windows/macOS,绕过 Cursor 免费试用检测 +6. Expanded Cursor AI file detection, deep removal of leftover trial files | 扩展 Cursor AI 文件检测,深度清理残留试用文件 +7. Optimized logging, replaced print with logging module, added verification steps | 日志优化,统一采用 logging 模块,增加验证步骤提示 +8. Added retry mechanism for email verification | 增加邮箱验证重试机制 +9. Automated GitHub OAuth login for Cursor AI | 自动 GitHub OAuth 登录 Cursor AI +10. Saved registered GitHub accounts and timestamps | 保存 GitHub 账户和注册时间戳 +11. Added user confirmation before execution | 添加用户确认步骤,防止误操作 +12. Displayed feature list & warnings before actions | 显示功能与风险警告 +13. Improved Selenium flow and error handling | 增强 Selenium 流程与错误处理 +14. Added Chrome process tracking and cleanup | 增加 Chrome 进程跟踪和清理 + ## v1.7.14 1. Added a Russian locale to program, fixed a typo in readme.md. Also translated other files | 為程式新增了俄語語系,修正了 readme.md 的拼寫錯誤,並翻譯了其他文件。 diff --git a/github_cursor_register.py b/github_cursor_register.py index 3491798..44d984f 100644 --- a/github_cursor_register.py +++ b/github_cursor_register.py @@ -188,16 +188,45 @@ def get_user_confirmation(): else: print("Please enter 'yes' or 'no'.") -def main(): +def main(translator=None): logging.info("Starting GitHub + Cursor AI Registration Automation") - # Display features and warnings - display_features_and_warnings() - - if not get_user_confirmation(): - logging.info("Operation cancelled by user.") - print("❌ Operation cancelled.") - return + # 如果没有提供translator,使用默认英文提示 + if translator is None: + # Display features and warnings in English + display_features_and_warnings() + + if not get_user_confirmation(): + logging.info("Operation cancelled by user.") + print("❌ Operation cancelled.") + return + else: + # 使用translator显示多语言提示 + print(f"\n🚀 {translator.get('github_register.title')}") + print("=====================================") + print(f"{translator.get('github_register.features_header')}:") + print(f" - {translator.get('github_register.feature1')}") + print(f" - {translator.get('github_register.feature2')}") + print(f" - {translator.get('github_register.feature3')}") + print(f" - {translator.get('github_register.feature4')}") + print(f" - {translator.get('github_register.feature5')}") + print(f" - {translator.get('github_register.feature6')}") + print(f"\n⚠️ {translator.get('github_register.warnings_header')}:") + print(f" - {translator.get('github_register.warning1')}") + print(f" - {translator.get('github_register.warning2')}") + print(f" - {translator.get('github_register.warning3')}") + print(f" - {translator.get('github_register.warning4')}") + print("=====================================\n") + + while True: + response = input(f"{translator.get('github_register.confirm')} (yes/no): ").lower().strip() + if response in ['yes', 'y']: + break + elif response in ['no', 'n']: + print(f"❌ {translator.get('github_register.cancelled')}") + return + else: + print(f"{translator.get('github_register.invalid_choice')}") try: # Step 1: Generate temp email diff --git a/locales/de.json b/locales/de.json index c00a5c3..d693a73 100644 --- a/locales/de.json +++ b/locales/de.json @@ -16,7 +16,12 @@ "press_enter": "Drücken Sie Enter zum Beenden", "disable_auto_update": "Cursor Auto-Update Deaktivieren", "lifetime_access_enabled": "LEBENSLANGER ZUGRIFF AKTIVIERT", - "totally_reset": "Cursor Vollständig Zurücksetzen" + "totally_reset": "Cursor Vollständig Zurücksetzen", + "outdate": "Veraltet", + "temp_github_register": "Temporäre GitHub-Registrierung", + "admin_required": "Ausführen als ausführbare Datei, Administratorrechte erforderlich.", + "admin_required_continue": "Mit der aktuellen Version fortfahren...", + "coming_soon": "Bald verfügbar" }, "languages": { "en": "Englisch", diff --git a/locales/en.json b/locales/en.json index 0abfbc7..debce07 100644 --- a/locales/en.json +++ b/locales/en.json @@ -16,7 +16,12 @@ "press_enter": "Press Enter to Exit", "disable_auto_update": "Disable Cursor Auto-Update", "lifetime_access_enabled": "LIFETIME ACCESS ENABLED", - "totally_reset": "Totally Reset Cursor" + "totally_reset": "Totally Reset Cursor", + "outdate": "Outdated", + "temp_github_register": "Temporary GitHub Register", + "admin_required": "Running as executable, administrator privileges required.", + "admin_required_continue": "Continuing without administrator privileges.", + "coming_soon": "Coming Soon" }, "languages": { "en": "English", @@ -382,5 +387,24 @@ "electron_localstorage_files_removed": "Electron localStorage files removed", "electron_localstorage_files_removal_error": "Error removing Electron localStorage files: {error}", "removing_electron_localstorage_files_completed": "Electron localStorage files removal completed" - } -} \ No newline at end of file + }, + "github_register": { + "title": "GitHub + Cursor AI Registration Automation", + "features_header": "Features", + "feature1": "Generates a temporary email using 1secmail.", + "feature2": "Registers a new GitHub account with random credentials.", + "feature3": "Verifies the GitHub email automatically.", + "feature4": "Logs into Cursor AI using GitHub authentication.", + "feature5": "Resets the machine ID to bypass trial detection.", + "feature6": "Saves all credentials to a file.", + "warnings_header": "Warnings", + "warning1": "This script automates account creation, which may violate GitHub/Cursor terms of service.", + "warning2": "Requires internet access and administrative privileges.", + "warning3": "CAPTCHA or additional verification may interrupt automation.", + "warning4": "Use responsibly and at your own risk.", + "confirm": "Are you sure you want to proceed?", + "invalid_choice": "Invalid choice. Please enter 'yes' or 'no'", + "cancelled": "Operation cancelled", + "program_terminated": "Program terminated by user" + } +} \ No newline at end of file diff --git a/locales/fr.json b/locales/fr.json index ddbe640..2c99e0c 100644 --- a/locales/fr.json +++ b/locales/fr.json @@ -16,7 +16,10 @@ "press_enter": "Appuyez sur Entrée pour quitter", "disable_auto_update": "Désactiver la Mise à Jour Automatique de Cursor", "lifetime_access_enabled": "ACCÈS À VIE ACTIVÉ", - "totally_reset": "Réinitialisation Complète de Cursor" + "totally_reset": "Réinitialisation Complète de Cursor", + "outdate": "Obsolete", + "temp_github_register": "Inscription GitHub temporaire", + "coming_soon": "Bientôt" }, "languages": { "en": "Anglais", diff --git a/locales/nl.json b/locales/nl.json index 1d29568..d9f8f71 100644 --- a/locales/nl.json +++ b/locales/nl.json @@ -16,7 +16,10 @@ "press_enter": "Druk op Enter om door te gaan.", "disable_auto_update": "Cursor automatische updates uitschakelen", "lifetime_access_enabled": "Levenslange toegang ingeschakeld", - "totally_reset": "Cursor volledig resetten" + "totally_reset": "Cursor volledig resetten", + "outdate": "Verouderd", + "temp_github_register": "Tijdelijke GitHub-registratie", + "coming_soon": "Binnenkort" }, "languages": { "en": "Engels", @@ -278,7 +281,7 @@ "update_skipped": "Update overgeslagen.", "invalid_choice": "Ongeldige keuze. Voer 'Y' of 'n' in.", "development_version": "Ontwikkelversie {current} > {latest}", - "changelog_title": "Changelog" + "changelog_title": "Wijzigingslogboek" }, "totally_reset": { "title": "Cursor volledig herstellen", diff --git a/locales/pt.json b/locales/pt.json index 78bac3d..c1fdcb3 100644 --- a/locales/pt.json +++ b/locales/pt.json @@ -16,7 +16,10 @@ "press_enter": "Pressione Enter para Sair", "disable_auto_update": "Desativar Atualização Automática do Cursor", "lifetime_access_enabled": "ACESSO VITALÍCIO HABILITADO", - "totally_reset": "Redefinir Cursor Completamente" + "totally_reset": "Redefinir Cursor Completamente", + "outdate": "Obsoleto", + "temp_github_register": "Registro temporário do GitHub", + "coming_soon": "Em breve" }, "languages": { "en": "Inglês", @@ -287,7 +290,7 @@ "update_skipped": "Atualização ignorada.", "invalid_choice": "Escolha inválida. Por favor, digite 'Y' ou 'n'.", "development_version": "Versão de desenvolvimento {current} > {latest}", - "changelog_title": "Registro de mudanças" + "changelog_title": "Registro de alterações" }, "totally_reset": { "title": "Redefinir Cursor Completamente", diff --git a/locales/ru.json b/locales/ru.json index 6d843bd..fcd07c0 100644 --- a/locales/ru.json +++ b/locales/ru.json @@ -16,7 +16,10 @@ "press_enter": "Нажмите Enter для выхода", "disable_auto_update": "Отключить автоматическое обновление Cursor", "lifetime_access_enabled": "ВКЛЮЧЕН ПОЖИЗНЕННЫЙ ДОСТУП", - "totally_reset": "Полностью сбросить Cursor" + "totally_reset": "Полностью сбросить Cursor", + "outdate": "Устаревший", + "temp_github_register": "Временная регистрация GitHub", + "coming_soon": "Скоро" }, "languages": { "en": "Английский", @@ -287,7 +290,7 @@ "update_skipped": "Обновление пропущено.", "invalid_choice": "Неверный выбор. Пожалуйста, введите 'Y' или 'n'.", "development_version": "Версия разработки {current} > {latest}", - "changelog_title": "Журнал изменений" + "changelog_title": "Список изменений" }, "totally_reset": { "title": "Полный сброс Cursor", diff --git a/locales/tr.json b/locales/tr.json index 3090e39..d6ad419 100644 --- a/locales/tr.json +++ b/locales/tr.json @@ -16,7 +16,10 @@ "press_enter": "Çıkmak için Enter'a Basın", "disable_auto_update": "Cursor Otomatik Güncellemeyi Devre Dışı Bırak", "lifetime_access_enabled": "ÖMÜR BOYU ERİŞİM ETKİNLEŞTİRİLDİ", - "totally_reset": "Cursor'ı Tamamen Sıfırla" + "totally_reset": "Cursor'ı Tamamen Sıfırla", + "outdate": "güncel değil", + "temp_github_register": "Geçici GitHub Kaydı", + "coming_soon": "Yakında" }, "languages": { "en": "English", @@ -290,7 +293,7 @@ "update_skipped": "Güncelleme atlanıyor.", "invalid_choice": "Geçersiz seçim. Lütfen 'Y' veya 'n' girin.", "development_version": "Geliştirme Sürümü {current} > {latest}", - "changelog_title": "Değişiklik Günlüğü" + "changelog_title": "Değişiklik günlüğü" }, "totally_reset": { "title": "Cursor'ı Tamamen Sıfırla", diff --git a/locales/vi.json b/locales/vi.json index eb5aafd..c8735bc 100644 --- a/locales/vi.json +++ b/locales/vi.json @@ -14,7 +14,10 @@ "press_enter": "Nhấn Enter để Thoát", "disable_auto_update": "Tắt tự động cập nhật Cursor", "lifetime_access_enabled": "ĐÃ BẬT TRUY CẬP TRỌN ĐỜI", - "totally_reset": "Đặt lại hoàn toàn Cursor" + "totally_reset": "Đặt lại hoàn toàn Cursor", + "outdate": "Quá cũ", + "temp_github_register": "Đăng ký GitHub tạm thời", + "coming_soon": "Sắp ra mắt" }, "languages": { "en": "Tiếng Anh", @@ -93,7 +96,6 @@ "check_version_failed": "Kiểm Tra Phiên Bản Thất Bại: {error}", "stack_trace": "Dấu Vết Ngăn Xếp", "version_too_low": "Phiên Bản Cursor Quá Thấp: {version} < 0.45.0" - }, "register": { "title": "Công Cụ Đăng Ký Cursor", @@ -286,7 +288,7 @@ "update_skipped": "Bỏ Qua Cập Nhật.", "invalid_choice": "Lựa Chọn Không Hợp Lệ. Vui Lòng Nhập 'Y' Hoặc 'n'.", "development_version": "Phiên Bản Phát Triển {current} > {latest}", - "changelog_title": "Changelog" + "changelog_title": "Nhật ký thay đổi" }, "totally_reset": { "title": "Đặt lại hoàn toàn Cursor", diff --git a/locales/zh_cn.json b/locales/zh_cn.json index b87e446..c0af3fa 100644 --- a/locales/zh_cn.json +++ b/locales/zh_cn.json @@ -16,7 +16,12 @@ "press_enter": "按回车键退出", "disable_auto_update": "禁用 Cursor 自动更新", "lifetime_access_enabled": "永久订阅", - "totally_reset": "完全重置 Cursor" + "totally_reset": "完全重置 Cursor", + "outdate": "过时", + "temp_github_register": "临时GitHub注册", + "admin_required": "运行可执行文件,需要管理员权限", + "admin_required_continue": "继续使用当前版本...", + "coming_soon": "即将推出" }, "languages": { "en": "英语", @@ -376,5 +381,24 @@ "electron_localstorage_files_removed": "Electron localStorage 文件已移除", "electron_localstorage_files_removal_error": "移除 Electron localStorage 文件时出错:{error}", "removing_electron_localstorage_files_completed": "Electron localStorage 文件移除完成" + }, + "github_register": { + "title": "GitHub + Cursor AI 注册自动化", + "features_header": "功能", + "feature1": "使用 1secmail 生成临时邮箱", + "feature2": "使用随机凭证注册新的 GitHub 账户", + "feature3": "自动验证 GitHub 邮箱", + "feature4": "使用 GitHub 认证登录 Cursor AI", + "feature5": "重置机器 ID 以绕过试用检测", + "feature6": "保存所有凭证到文件", + "warnings_header": "警告", + "warning1": "此脚本自动化账户创建,可能违反 GitHub/Cursor 服务条款", + "warning2": "需要互联网访问和管理员权限", + "warning3": "CAPTCHA 或额外验证可能会中断自动化", + "warning4": "请负责任地使用,风险自负", + "confirm": "您确定要继续吗?", + "invalid_choice": "无效选择。请输入 'yes' 或 'no'", + "cancelled": "操作已取消", + "program_terminated": "程序已由用户终止" } } \ No newline at end of file diff --git a/locales/zh_tw.json b/locales/zh_tw.json index 6b419d8..0f63376 100644 --- a/locales/zh_tw.json +++ b/locales/zh_tw.json @@ -14,7 +14,12 @@ "press_enter": "按返回鍵退出", "disable_auto_update": "禁用 Cursor 自動更新", "lifetime_access_enabled": "終身訪問已啟用", - "totally_reset": "完全重置 Cursor" + "totally_reset": "完全重置 Cursor", + "outdate": "過時", + "temp_github_register": "臨時GitHub註冊", + "admin_required": "運行可執行文件,需要管理員權限", + "admin_required_continue": "繼續使用當前版本...", + "coming_soon": "即將推出" }, "languages": { "en": "英文", @@ -263,7 +268,7 @@ "update_skipped": "跳過更新。", "invalid_choice": "選擇無效。請輸入 'Y' 或 'n'.", "development_version": "開發版本 {current} > {latest}", - "changelog_title": "更新日志" + "changelog_title": "更新日誌" }, "totally_reset": { "title": "完全重置 Cursor", @@ -355,5 +360,24 @@ "electron_localstorage_files_removed": "已移除 Electron localStorage 檔案", "electron_localstorage_files_removal_error": "移除 Electron localStorage 檔案時出錯:{error}", "removing_electron_localstorage_files_completed": "Electron localStorage 檔案移除完成" - } + }, + "github_register": { + "title": "GitHub + Cursor AI 注册自动化", + "features_header": "功能", + "feature1": "使用 1secmail 生成临时邮箱", + "feature2": "使用随机凭证注册新的 GitHub 账户", + "feature3": "自动验证 GitHub 邮箱", + "feature4": "使用 GitHub 认证登录 Cursor AI", + "feature5": "重置机器 ID 以绕过试用检测", + "feature6": "保存所有凭证到文件", + "warnings_header": "警告", + "warning1": "此脚本自动化账户创建,可能违反 GitHub/Cursor 服务条款", + "warning2": "需要互联网访问和管理员权限", + "warning3": "CAPTCHA 或额外验证可能会中断自动化", + "warning4": "请负责任地使用,风险自负", + "confirm": "您确定要继续吗?", + "invalid_choice": "无效选择。请输入 'yes' 或 'no'", + "cancelled": "操作已取消", + "program_terminated": "程序已由用户终止" + } } \ No newline at end of file diff --git a/main.py b/main.py index 3290a03..5de55e2 100644 --- a/main.py +++ b/main.py @@ -109,6 +109,7 @@ class Translator: 0x0804: 'zh_cn', # Simplified Chinese 0x0422: 'vi', # Vietnamese 0x0419: 'ru', # Russian + 0x0415: 'tr', # Turkish } return language_map.get(layout_id, 'en') @@ -144,6 +145,8 @@ class Translator: return 'pt' elif system_locale.startswith('ru'): return 'ru' + elif system_locale.startswith('tr'): + return 'tr' # Try to get language from LANG environment variable as fallback env_lang = os.getenv('LANG', '').lower() @@ -163,6 +166,8 @@ class Translator: return 'pt' elif 'ru' in env_lang: return 'ru' + elif 'tr' in env_lang: + return 'tr' return 'en' except: @@ -237,16 +242,17 @@ def print_menu(): print(f"{Fore.YELLOW}{'─' * 40}{Style.RESET_ALL}") print(f"{Fore.GREEN}0{Style.RESET_ALL}. {EMOJI['ERROR']} {translator.get('menu.exit')}") print(f"{Fore.GREEN}1{Style.RESET_ALL}. {EMOJI['RESET']} {translator.get('menu.reset')}") - print(f"{Fore.GREEN}2{Style.RESET_ALL}. {EMOJI['SUCCESS']} {translator.get('menu.register')}") + print(f"{Fore.GREEN}2{Style.RESET_ALL}. {EMOJI['SUCCESS']} {translator.get('menu.register')} ({Fore.RED}{translator.get('menu.outdate')}{Style.RESET_ALL})") print(f"{Fore.GREEN}3{Style.RESET_ALL}. 🌟 {translator.get('menu.register_google')}") print(f"{Fore.YELLOW} ┗━━ 🔥 {translator.get('menu.lifetime_access_enabled')} 🔥{Style.RESET_ALL}") print(f"{Fore.GREEN}4{Style.RESET_ALL}. ⭐ {translator.get('menu.register_github')}") print(f"{Fore.YELLOW} ┗━━ 🚀 {translator.get('menu.lifetime_access_enabled')} 🚀{Style.RESET_ALL}") print(f"{Fore.GREEN}5{Style.RESET_ALL}. {EMOJI['SUCCESS']} {translator.get('menu.register_manual')}") - print(f"{Fore.GREEN}6{Style.RESET_ALL}. {EMOJI['ERROR']} {translator.get('menu.quit')}") - print(f"{Fore.GREEN}7{Style.RESET_ALL}. {EMOJI['LANG']} {translator.get('menu.select_language')}") - print(f"{Fore.GREEN}8{Style.RESET_ALL}. {EMOJI['UPDATE']} {translator.get('menu.disable_auto_update')}") - print(f"{Fore.GREEN}9{Style.RESET_ALL}. {EMOJI['RESET']} {translator.get('menu.totally_reset')}") + print(f"{Fore.GREEN}6{Style.RESET_ALL}. {EMOJI['RESET']} {translator.get('menu.temp_github_register')}") + print(f"{Fore.GREEN}7{Style.RESET_ALL}. {EMOJI['ERROR']} {translator.get('menu.quit')}") + print(f"{Fore.GREEN}8{Style.RESET_ALL}. {EMOJI['LANG']} {translator.get('menu.select_language')}") + print(f"{Fore.GREEN}9{Style.RESET_ALL}. {EMOJI['UPDATE']} {translator.get('menu.disable_auto_update')}") + print(f"{Fore.GREEN}10{Style.RESET_ALL}. {EMOJI['RESET']} {translator.get('menu.totally_reset')}") print(f"{Fore.YELLOW}{'─' * 40}{Style.RESET_ALL}") def select_language(): @@ -424,11 +430,11 @@ def check_latest_version(): def main(): # Check for admin privileges if running as executable on Windows only if platform.system() == 'Windows' and is_frozen() and not is_admin(): - print(f"{Fore.YELLOW}{EMOJI['ADMIN']} Running as executable, administrator privileges required.{Style.RESET_ALL}") + print(f"{Fore.YELLOW}{EMOJI['ADMIN']} {translator.get('menu.admin_required')}{Style.RESET_ALL}") if run_as_admin(): sys.exit(0) # Exit after requesting admin privileges else: - print(f"{Fore.YELLOW}{EMOJI['INFO']} Continuing without administrator privileges.{Style.RESET_ALL}") + print(f"{Fore.YELLOW}{EMOJI['INFO']} {translator.get('menu.admin_required_continue')}{Style.RESET_ALL}") print_logo() @@ -470,18 +476,23 @@ def main(): cursor_register_manual.main(translator) print_menu() elif choice == "6": + import github_cursor_register + print(f"{Fore.YELLOW}{EMOJI['INFO']} {translator.get('menu.coming_soon')}{Style.RESET_ALL}") + # github_cursor_register.main(translator) + print_menu() + elif choice == "7": import quit_cursor quit_cursor.quit_cursor(translator) print_menu() - elif choice == "7": + elif choice == "8": if select_language(): print_menu() continue - elif choice == "8": + elif choice == "9": import disable_auto_update disable_auto_update.run(translator) print_menu() - elif choice == "9": + elif choice == "10": import totally_reset_cursor totally_reset_cursor.run(translator) print_menu() diff --git a/new_signup.py b/new_signup.py index 7cfd02a..d78a637 100644 --- a/new_signup.py +++ b/new_signup.py @@ -12,16 +12,32 @@ from config import get_config # Add global variable at the beginning of the file _translator = None +# Add global variable to track our Chrome processes +_chrome_process_ids = [] + def cleanup_chrome_processes(translator=None): - """Clean all Chrome related processes""" - print("\nCleaning Chrome processes...") + """Clean only Chrome processes launched by this script""" + global _chrome_process_ids + + if not _chrome_process_ids: + print("\nNo Chrome processes to clean...") + return + + print("\nCleaning Chrome processes launched by this script...") try: if os.name == 'nt': - os.system('taskkill /F /IM chrome.exe /T 2>nul') - os.system('taskkill /F /IM chromedriver.exe /T 2>nul') + for pid in _chrome_process_ids: + try: + os.system(f'taskkill /F /PID {pid} /T 2>nul') + except: + pass else: - os.system('pkill -f chrome') - os.system('pkill -f chromedriver') + for pid in _chrome_process_ids: + try: + os.kill(pid, signal.SIGTERM) + except: + pass + _chrome_process_ids = [] # Reset the list after cleanup except Exception as e: if translator: print(f"{Fore.RED}❌ {translator.get('register.cleanup_error', error=str(e))}{Style.RESET_ALL}") @@ -39,7 +55,7 @@ def signal_handler(signum, frame): os._exit(0) def simulate_human_input(page, url, config, translator=None): - """Visit URL with human-like behavior""" + """Visit URL""" if translator: print(f"{Fore.CYAN}🚀 {translator.get('register.visiting_url')}: {url}{Style.RESET_ALL}") @@ -47,194 +63,53 @@ def simulate_human_input(page, url, config, translator=None): page.get('about:blank') time.sleep(get_random_wait_time(config, 'page_load_wait')) - # Add random mouse movements before visiting target page - try: - page.run_js(""" - function simulateMouseMovement() { - const points = []; - const numPoints = Math.floor(Math.random() * 10) + 5; - for (let i = 0; i < numPoints; i++) { - points.push({ - x: Math.random() * window.innerWidth, - y: Math.random() * window.innerHeight - }); - } - points.forEach((point, i) => { - setTimeout(() => { - const event = new MouseEvent('mousemove', { - view: window, - bubbles: true, - cancelable: true, - clientX: point.x, - clientY: point.y - }); - document.dispatchEvent(event); - }, i * (Math.random() * 200 + 50)); - }); - } - simulateMouseMovement(); - """) - except: - pass # Ignore if JavaScript execution fails - # Visit target page page.get(url) time.sleep(get_random_wait_time(config, 'page_load_wait')) - - # Add some random scrolling - try: - page.run_js(""" - function simulateHumanScroll() { - const maxScroll = Math.max( - document.body.scrollHeight, - document.documentElement.scrollHeight, - document.body.offsetHeight, - document.documentElement.offsetHeight, - document.body.clientHeight, - document.documentElement.clientHeight - ); - const scrollPoints = []; - const numPoints = Math.floor(Math.random() * 3) + 2; - for (let i = 0; i < numPoints; i++) { - scrollPoints.push(Math.floor(Math.random() * maxScroll)); - } - scrollPoints.sort((a, b) => a - b); - scrollPoints.forEach((point, i) => { - setTimeout(() => { - window.scrollTo({ - top: point, - behavior: 'smooth' - }); - }, i * (Math.random() * 1000 + 500)); - }); - } - simulateHumanScroll(); - """) - except: - pass # Ignore if JavaScript execution fails - -def simulate_human_typing(element, text, config): - """Simulate human-like typing with random delays between keystrokes""" - for char in text: - element.input(char) - # Random delay between keystrokes (30-100ms) - time.sleep(random.uniform(0.03, 0.1)) - time.sleep(get_random_wait_time(config, 'input_wait')) def fill_signup_form(page, first_name, last_name, email, config, translator=None): - """Fill signup form with human-like behavior""" - max_retries = 5 - retry_count = 0 - - while retry_count < max_retries: - try: - if translator: - print(f"{Fore.CYAN}📧 {translator.get('register.filling_form')} (Attempt {retry_count + 1}/{max_retries}){Style.RESET_ALL}") - else: - print(f"\n正在填写注册表单... (Attempt {retry_count + 1}/{max_retries})") - - # Add random initial delay - time.sleep(random.uniform(0.5, 1.5)) - - # Fill first name with human-like typing - first_name_input = page.ele("@name=first_name") - if first_name_input: - simulate_human_typing(first_name_input, first_name, config) - # Add random pause between fields - time.sleep(random.uniform(0.3, 0.8)) - - # Fill last name with human-like typing - last_name_input = page.ele("@name=last_name") - if last_name_input: - simulate_human_typing(last_name_input, last_name, config) - # Add random pause between fields - time.sleep(random.uniform(0.3, 0.8)) - - # Fill email with human-like typing - email_input = page.ele("@name=email") - if email_input: - simulate_human_typing(email_input, email, config) - # Add random pause before submitting - time.sleep(random.uniform(0.5, 1.2)) - - # Move mouse to submit button with human-like movement - submit_button = page.ele("@type=submit") - if submit_button: - try: - # Simulate mouse movement to button - page.run_js(""" - function moveToButton(button) { - const rect = button.getBoundingClientRect(); - const centerX = rect.left + rect.width / 2; - const centerY = rect.top + rect.height / 2; - - // Create a curved path to the button - const startX = Math.random() * window.innerWidth; - const startY = Math.random() * window.innerHeight; - const controlX = (startX + centerX) / 2 + (Math.random() - 0.5) * 100; - const controlY = (startY + centerY) / 2 + (Math.random() - 0.5) * 100; - - const steps = 20; - for (let i = 0; i <= steps; i++) { - const t = i / steps; - const x = Math.pow(1-t, 2) * startX + 2 * (1-t) * t * controlX + Math.pow(t, 2) * centerX; - const y = Math.pow(1-t, 2) * startY + 2 * (1-t) * t * controlY + Math.pow(t, 2) * centerY; - - setTimeout(() => { - const event = new MouseEvent('mousemove', { - view: window, - bubbles: true, - cancelable: true, - clientX: x, - clientY: y - }); - document.dispatchEvent(event); - }, i * (Math.random() * 20 + 10)); - } - } - moveToButton(document.querySelector('button[type="submit"]')); - """) - time.sleep(random.uniform(0.3, 0.6)) - except: - pass # Ignore if JavaScript execution fails - - submit_button.click() - time.sleep(get_random_wait_time(config, 'submit_wait')) - - # Check for human verification error - error_message = page.ele("text:Can't verify the user is human") - if error_message: - if translator: - print(f"{Fore.YELLOW}⚠️ {translator.get('register.human_verify_error')} (Attempt {retry_count + 1}/{max_retries}){Style.RESET_ALL}") - else: - print(f"Can't verify the user is human. Retrying... (Attempt {retry_count + 1}/{max_retries})") - retry_count += 1 - # Add longer random delay between retries - time.sleep(random.uniform(2, 4)) - continue - - if translator: - print(f"{Fore.GREEN}✅ {translator.get('register.form_success')}{Style.RESET_ALL}") - else: - print("Form filled successfully") - return True - - except Exception as e: - if translator: - print(f"{Fore.RED}❌ {translator.get('register.form_error', error=str(e))}{Style.RESET_ALL}") - else: - print(f"Error filling form: {e}") - retry_count += 1 - if retry_count < max_retries: - time.sleep(get_random_wait_time(config, 'verification_retry_wait')) - continue - return False - - if retry_count >= max_retries: + """Fill signup form""" + try: if translator: - print(f"{Fore.RED}❌ {translator.get('register.max_retries_reached')}{Style.RESET_ALL}") + print(f"{Fore.CYAN}📧 {translator.get('register.filling_form')}{Style.RESET_ALL}") else: - print("Maximum retry attempts reached. Registration failed.") + print("\n正在填写注册表单...") + + # Fill first name + first_name_input = page.ele("@name=first_name") + if first_name_input: + first_name_input.input(first_name) + time.sleep(get_random_wait_time(config, 'input_wait')) + + # Fill last name + last_name_input = page.ele("@name=last_name") + if last_name_input: + last_name_input.input(last_name) + time.sleep(get_random_wait_time(config, 'input_wait')) + + # Fill email + email_input = page.ele("@name=email") + if email_input: + email_input.input(email) + time.sleep(get_random_wait_time(config, 'input_wait')) + + # Click submit button + submit_button = page.ele("@type=submit") + if submit_button: + submit_button.click() + time.sleep(get_random_wait_time(config, 'submit_wait')) + + if translator: + print(f"{Fore.GREEN}✅ {translator.get('register.form_success')}{Style.RESET_ALL}") + else: + print("Form filled successfully") + return True + + except Exception as e: + if translator: + print(f"{Fore.RED}❌ {translator.get('register.form_error', error=str(e))}{Style.RESET_ALL}") + else: + print(f"Error filling form: {e}") return False def get_default_chrome_path(): @@ -304,7 +179,9 @@ def get_random_wait_time(config, timing_type='page_load_wait'): return random.uniform(0.1, 0.8) # Return default value when error def setup_driver(translator=None): - """Setup browser driver with randomized fingerprint""" + """Setup browser driver""" + global _chrome_process_ids + try: # Get config config = get_config(translator) @@ -326,42 +203,10 @@ def setup_driver(translator=None): # Use incognito mode co.set_argument("--incognito") - # Randomize browser fingerprint - # Random screen resolution - resolutions = [ - "1920,1080", "1366,768", "1536,864", "1440,900", - "1280,720", "1600,900", "1024,768", "1680,1050" - ] - window_size = random.choice(resolutions) - co.set_argument(f"--window-size={window_size}") - - # Random user agent - user_agents = [ - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36", - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36", - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36" - ] - co.set_argument(f"--user-agent={random.choice(user_agents)}") - - # Random color depth - color_depths = ["24", "30", "48"] - co.set_argument(f"--color-depth={random.choice(color_depths)}") - - # Additional fingerprint randomization - co.set_argument("--disable-blink-features=AutomationControlled") # Hide automation - co.set_argument("--disable-features=IsolateOrigins,site-per-process") - - # Random platform - platforms = ["Win32", "Win64", "MacIntel", "Linux x86_64"] - co.set_argument(f"--platform={random.choice(platforms)}") - - # Random language - languages = ["en-US", "en-GB", "fr-FR", "de-DE", "es-ES", "it-IT"] - co.set_argument(f"--lang={random.choice(languages)}") - # Set random port co.set_argument("--no-sandbox") + + # Set random port co.auto_port() # Use headless mode (must be set to False, simulate human operation) @@ -384,64 +229,35 @@ def setup_driver(translator=None): else: print("Starting browser...") + # Record Chrome processes before launching + before_pids = [] + try: + import psutil + before_pids = [p.pid for p in psutil.process_iter() if 'chrome' in p.name().lower()] + except: + pass + + # Launch browser page = ChromiumPage(co) - # Additional JavaScript-based fingerprint randomization - try: - page.run_js(""" - // Override navigator properties - const originalNavigator = window.navigator; - const navigatorProxy = new Proxy(originalNavigator, { - get: function(target, key) { - switch (key) { - case 'webdriver': - return undefined; - case 'plugins': - return [ - { name: 'Chrome PDF Plugin', filename: 'internal-pdf-viewer' }, - { name: 'Chrome PDF Viewer', filename: 'mhjfbmdgcfjbbpaeojofohoefgiehjai' }, - { name: 'Native Client', filename: 'internal-nacl-plugin' } - ]; - case 'languages': - return ['en-US', 'en']; - default: - return target[key]; - } - } - }); - - // Override permissions - const originalPermissions = window.Permissions; - window.Permissions = new Proxy(originalPermissions, { - get: function(target, key) { - if (key === 'prototype') { - return { - query: async () => ({ state: 'prompt' }) - }; - } - return target[key]; - } - }); - - // Random canvas fingerprint - const originalGetContext = HTMLCanvasElement.prototype.getContext; - HTMLCanvasElement.prototype.getContext = function() { - const context = originalGetContext.apply(this, arguments); - if (context && arguments[0] === '2d') { - const originalFillText = context.fillText; - context.fillText = function() { - const noise = Math.random() * 0.1; - context.rotate(noise); - originalFillText.apply(this, arguments); - context.rotate(-noise); - }; - } - return context; - }; - """) - except: - pass # Ignore if JavaScript execution fails + # Wait a moment for Chrome to fully launch + time.sleep(1) + # Record Chrome processes after launching and find new ones + try: + import psutil + after_pids = [p.pid for p in psutil.process_iter() if 'chrome' in p.name().lower()] + # Find new Chrome processes + new_pids = [pid for pid in after_pids if pid not in before_pids] + _chrome_process_ids.extend(new_pids) + + if _chrome_process_ids: + print(f"Tracking {len(_chrome_process_ids)} Chrome processes") + else: + print(f"{Fore.YELLOW}Warning: No new Chrome processes detected to track{Style.RESET_ALL}") + except Exception as e: + print(f"Warning: Could not track Chrome processes: {e}") + return config, page except Exception as e: @@ -793,7 +609,9 @@ def handle_sign_in(browser_tab, email, password, translator=None): def main(email=None, password=None, first_name=None, last_name=None, email_tab=None, controller=None, translator=None): """Main function, can receive account information, email tab, and translator""" global _translator + global _chrome_process_ids _translator = translator # Save to global variable + _chrome_process_ids = [] # Reset the process IDs list signal.signal(signal.SIGINT, signal_handler) signal.signal(signal.SIGTERM, signal_handler)