""" Gmail Verification - Handhabt die Verifizierungsprozesse """ import logging import time import random from typing import Dict, Optional, Any from playwright.sync_api import Page from social_networks.gmail import gmail_selectors as selectors from social_networks.gmail.gmail_ui_helper import GmailUIHelper from utils.email_handler import EmailHandler logger = logging.getLogger("gmail_verification") class GmailVerification: """ Handhabt die Gmail/Google Account Verifizierung """ def __init__(self, page: Page, ui_helper: GmailUIHelper, email_handler: EmailHandler = None, screenshots_dir: str = None, save_screenshots: bool = True, phone_service: Optional[Any] = None): """ Initialisiert den Verification Handler """ self.page = page self.ui_helper = ui_helper self.email_handler = email_handler self.screenshots_dir = screenshots_dir self.save_screenshots = save_screenshots self.phone_service = phone_service def handle_phone_verification(self, account_data: Dict[str, str]) -> Dict[str, any]: """ Enhanced Telefonnummer-Verifizierung mit 2025 Skip-Techniken """ try: logger.info("[PHONE-VERIFY] Starte enhanced Telefon-Verifizierung") # Warte auf Telefonnummer-Eingabefeld if not self.ui_helper.wait_for_element(selectors.PHONE_INPUT, timeout=10000): logger.info("[PHONE-VERIFY] ✅ Telefonnummer-Eingabefeld nicht gefunden - Erfolg!") return { "success": True, "message": "Keine Telefon-Verifizierung erforderlich" } self.ui_helper.take_screenshot("phone_verification_page") # Enhanced Skip-Versuch bevor Telefonnummer eingegeben wird phone = account_data.get("phone", "") if not phone: logger.warning("[PHONE-VERIFY] Keine Telefonnummer vorhanden - versuche erweiterte Skip-Methoden") # Versuche alle Skip-Button Varianten for skip_variant in selectors.SKIP_BUTTON_VARIANTS[:10]: # Top 10 Varianten if self.ui_helper.is_element_visible(skip_variant, timeout=500): logger.info(f"[PHONE-VERIFY] Skip-Button gefunden: {skip_variant}") self.ui_helper.click_with_retry(skip_variant) time.sleep(random.uniform(2, 3)) # Prüfe ob erfolgreich übersprungen if not self.ui_helper.is_element_visible(selectors.PHONE_INPUT, timeout=2000): return {"success": True, "message": "Telefon erfolgreich übersprungen"} # Fallback: Versuche mit leerem Feld fortzufahren logger.info("[PHONE-VERIFY] Versuche mit leerem Feld fortzufahren") try: self.page.locator(selectors.PHONE_INPUT).fill("") if self.ui_helper.click_with_retry(selectors.NEXT_BUTTON): time.sleep(2) if not self.ui_helper.is_element_visible(selectors.SMS_CODE_INPUT, timeout=3000): return {"success": True, "message": "Mit leerem Feld fortgefahren"} except: pass return { "success": False, "error": "phone_required", "message": "Telefonnummer wird benötigt - alle Skip-Versuche fehlgeschlagen" } logger.info(f"Gebe Telefonnummer ein: {phone}") # Telefonnummer eingeben self.ui_helper.type_with_delay(selectors.PHONE_INPUT, phone) time.sleep(random.uniform(1, 2)) # Screenshot vor dem Absenden self.ui_helper.take_screenshot("phone_entered") # Absenden if self.ui_helper.wait_for_element(selectors.NEXT_BUTTON, timeout=5000): logger.info("Sende Telefonnummer ab") self.ui_helper.click_with_retry(selectors.NEXT_BUTTON) self.ui_helper.wait_for_loading_to_finish() time.sleep(random.uniform(3, 5)) # Warte auf SMS-Code Eingabefeld if self.ui_helper.wait_for_element(selectors.SMS_CODE_INPUT, timeout=15000): logger.info("SMS-Code Eingabefeld gefunden") self.ui_helper.take_screenshot("sms_code_page") # SMS-Code beziehen: bevorzugt aus account_data, sonst Provider, sonst Fallback sms_code: Optional[str] = None try: if isinstance(account_data, dict): if account_data.get("sms_code"): sms_code = str(account_data.get("sms_code")).strip() elif callable(account_data.get("sms_code_provider")): sms_code = account_data.get("sms_code_provider")(phone) except Exception as prov_e: logger.warning(f"SMS-Code Provider-Fehler: {prov_e}") if not sms_code: # Hier würde normalerweise der SMS-Code abgerufen werden sms_code = self._get_sms_code(phone) if not sms_code: logger.error("Kein SMS-Code erhalten") return { "success": False, "error": "Kein SMS-Code erhalten", "message": "SMS-Verifizierung fehlgeschlagen" } # SMS-Code eingeben logger.info(f"Gebe SMS-Code ein: {sms_code}") self.ui_helper.type_with_delay(selectors.SMS_CODE_INPUT, sms_code) time.sleep(random.uniform(1, 2)) # Code bestätigen if self.ui_helper.wait_for_element(selectors.VERIFY_BUTTON, timeout=5000): logger.info("Bestätige SMS-Code") self.ui_helper.click_with_retry(selectors.VERIFY_BUTTON) else: # Versuche alternativen Button self.ui_helper.click_with_retry(selectors.NEXT_BUTTON) self.ui_helper.wait_for_loading_to_finish() time.sleep(random.uniform(3, 5)) # Prüfe auf Erfolg if self._check_verification_success(): logger.info("Telefon-Verifizierung erfolgreich") self.ui_helper.take_screenshot("verification_success") return { "success": True, "message": "Verifizierung erfolgreich" } else: error_msg = self._get_verification_error() logger.error(f"Verifizierung fehlgeschlagen: {error_msg}") return { "success": False, "error": error_msg, "message": f"Verifizierung fehlgeschlagen: {error_msg}" } else: logger.info("Kein SMS-Code erforderlich") return { "success": True, "message": "Telefon-Verifizierung abgeschlossen" } except Exception as e: logger.error(f"Fehler bei der Telefon-Verifizierung: {e}") self.ui_helper.take_screenshot("verification_error") return { "success": False, "error": str(e), "message": f"Verifizierung fehlgeschlagen: {str(e)}" } def handle_captcha(self) -> Dict[str, any]: """ Handhabt Captcha-Herausforderungen """ try: logger.info("Prüfe auf Captcha") if self.ui_helper.is_element_visible(selectors.CAPTCHA_CONTAINER): logger.warning("Captcha erkannt - manuelle Lösung erforderlich") self.ui_helper.take_screenshot("captcha_detected") # TODO: Implementiere Captcha-Lösung return { "success": False, "error": "Captcha erkannt", "message": "Manuelle Captcha-Lösung erforderlich" } return { "success": True, "message": "Kein Captcha vorhanden" } except Exception as e: logger.error(f"Fehler bei der Captcha-Prüfung: {e}") return { "success": False, "error": str(e) } def _get_sms_code(self, phone: str) -> Optional[str]: """ Ruft den SMS-Code ab TODO: Implementierung für echte SMS-Code Abfrage """ # 1) Bevorzugt: externer Phone-Service try: if self.phone_service and hasattr(self.phone_service, 'get_code'): logger.info("Frage SMS-Code über phone_service an") code = self.phone_service.get_code(phone) if code: return str(code).strip() except Exception as e: logger.warning(f"phone_service.get_code Fehler: {e}") # 2) Fallback: Platzhalter (nur für Tests/Entwicklung) logger.warning("SMS-Code Abruf nicht konfiguriert – verwende Platzhalter") return "123456" def _check_verification_success(self) -> bool: """ Prüft ob die Verifizierung erfolgreich war """ try: # Prüfe ob wir weitergeleitet wurden current_url = self.page.url if any(indicator in current_url for indicator in ["myaccount", "mail.google", "youtube"]): return True # Prüfe ob SMS-Code Feld noch sichtbar ist if self.ui_helper.is_element_visible(selectors.SMS_CODE_INPUT): # Prüfe auf Fehlermeldung if self.ui_helper.is_element_visible(selectors.ERROR_MESSAGE): return False # Wenn kein Fehler aber noch SMS-Code Feld, warten wir noch return False return True except Exception as e: logger.warning(f"Fehler bei der Verifizierungs-Prüfung: {e}") return False def _get_verification_error(self) -> str: """ Holt die Fehlermeldung falls vorhanden """ try: error_selectors = [ selectors.ERROR_MESSAGE, selectors.ERROR_MESSAGE_ALT, selectors.FORM_ERROR ] for selector in error_selectors: if self.ui_helper.is_element_visible(selector): error_text = self.ui_helper.get_element_text(selector) if error_text: return error_text return "Verifizierung fehlgeschlagen" except: return "Unbekannter Fehler"