270 Zeilen
11 KiB
Python
270 Zeilen
11 KiB
Python
"""
|
|
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"
|