File size: 3,976 Bytes
494c89b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
"""
Authentication Strategy Pattern

Поддерживает разные методы авторизации:
- AutomatedStrategy: DrissionPage (старый метод, работает для некоторых)
- WebViewStrategy: Реальный браузер с ручным вводом (новый, anti-ban)
- DeviceFlowStrategy: Device flow OAuth (для headless серверов)
"""

from abc import ABC, abstractmethod
from typing import Optional, Dict, Any
from dataclasses import dataclass


@dataclass
class AuthResult:
    """Результат авторизации"""
    success: bool
    access_token: Optional[str] = None
    refresh_token: Optional[str] = None
    expires_in: Optional[int] = None
    profile_arn: Optional[str] = None
    csrf_token: Optional[str] = None
    error: Optional[str] = None
    metadata: Optional[Dict[str, Any]] = None


class AuthStrategy(ABC):
    """Базовый класс для стратегий авторизации"""
    
    @abstractmethod
    def authenticate(self, email: str, password: str, **kwargs) -> AuthResult:
        """
        Выполнить авторизацию
        
        Args:
            email: Email для авторизации
            password: Пароль
            **kwargs: Дополнительные параметры (зависят от стратегии)
            
        Returns:
            AuthResult с токенами или ошибкой
        """
        pass
    
    @abstractmethod
    def get_name(self) -> str:
        """Название стратегии"""
        pass
    
    @abstractmethod
    def requires_manual_input(self) -> bool:
        """Требует ли стратегия ручного ввода от пользователя"""
        pass
    
    @abstractmethod
    def supports_headless(self) -> bool:
        """Поддерживает ли headless режим"""
        pass
    
    def get_ban_risk(self) -> str:
        """Оценка риска бана (low/medium/high)"""
        return "unknown"
    
    def cleanup(self):
        """Очистка ресурсов"""
        pass


class RegistrationStrategy(ABC):
    """Базовый класс для стратегий регистрации"""
    
    @abstractmethod
    def register(self, email: str, name: Optional[str] = None, 
                password: Optional[str] = None, **kwargs) -> Dict[str, Any]:
        """
        Выполнить регистрацию
        
        Args:
            email: Email для регистрации
            name: Имя пользователя (генерируется если не указано)
            password: Пароль (генерируется если не указан)
            **kwargs: Дополнительные параметры
            
        Returns:
            Dict с результатом регистрации
        """
        pass
    
    @abstractmethod
    def get_name(self) -> str:
        """Название стратегии"""
        pass
    
    @abstractmethod
    def requires_manual_input(self) -> bool:
        """Требует ли стратегия ручного ввода от пользователя"""
        pass
    
    @abstractmethod
    def supports_headless(self) -> bool:
        """Поддерживает ли headless режим"""
        pass
    
    def get_ban_risk(self) -> str:
        """Оценка риска бана (low/medium/high)"""
        return "unknown"
    
    def supports_immediate_quota_check(self) -> bool:
        """
        Поддерживает ли стратегия немедленную проверку quota после регистрации.
        
        Для anti-ban стратегий должно быть False!
        """
        return True
    
    def cleanup(self):
        """Очистка ресурсов"""
        pass