Update changes
Dieser Commit ist enthalten in:
@ -295,21 +295,22 @@ class UsernameGenerator:
|
||||
Generierter Benutzername
|
||||
"""
|
||||
# Verschiedene Muster für zufällige Benutzernamen
|
||||
# ANTI-DETECTION: Keine verdächtigen Patterns wie "user" + Zahlen
|
||||
patterns = [
|
||||
# Adjektiv + Substantiv
|
||||
# Adjektiv + Substantiv (z.B. "happytiger")
|
||||
lambda: random.choice(self.adjectives) + random.choice(self.nouns),
|
||||
|
||||
# Substantiv + Zahlen
|
||||
lambda: random.choice(self.nouns) + "".join(random.choices(string.digits, k=random.randint(1, 4))),
|
||||
|
||||
# Adjektiv + Substantiv + Zahlen
|
||||
lambda: random.choice(self.adjectives) + random.choice(self.nouns) + "".join(random.choices(string.digits, k=random.randint(1, 3))),
|
||||
|
||||
# Substantiv + Unterstrich + Substantiv
|
||||
lambda: random.choice(self.nouns) + ("_" if "_" in policy["allowed_chars"] else "") + random.choice(self.nouns),
|
||||
|
||||
# Benutzer + Zahlen
|
||||
lambda: "user" + "".join(random.choices(string.digits, k=random.randint(3, 6)))
|
||||
|
||||
# Substantiv + Jahr (z.B. "eagle1995")
|
||||
lambda: random.choice(self.nouns) + str(random.randint(1985, 2005)),
|
||||
|
||||
# Adjektiv + Substantiv + 2 Ziffern (z.B. "coolwolf42")
|
||||
lambda: random.choice(self.adjectives) + random.choice(self.nouns) + str(random.randint(10, 99)),
|
||||
|
||||
# Substantiv + Unterstrich + Adjektiv (z.B. "tiger_happy")
|
||||
lambda: random.choice(self.nouns) + ("_" if "_" in policy["allowed_chars"] else "") + random.choice(self.adjectives),
|
||||
|
||||
# Adjektiv + Substantiv mit Punkt (z.B. "happy.tiger") - falls erlaubt
|
||||
lambda: random.choice(self.adjectives) + ("." if "." in policy["allowed_chars"] else "") + random.choice(self.nouns),
|
||||
]
|
||||
|
||||
# Zufälliges Muster auswählen und Benutzernamen generieren
|
||||
@ -417,49 +418,221 @@ class UsernameGenerator:
|
||||
policy: Optional[Dict[str, Any]] = None) -> Tuple[bool, str]:
|
||||
"""
|
||||
Überprüft, ob ein Benutzername den Richtlinien entspricht.
|
||||
|
||||
|
||||
Args:
|
||||
username: Zu überprüfender Benutzername
|
||||
platform: Name der Plattform
|
||||
policy: Optionale Richtlinie (sonst wird die der Plattform verwendet)
|
||||
|
||||
|
||||
Returns:
|
||||
(Gültigkeit, Fehlermeldung)
|
||||
"""
|
||||
# Richtlinie bestimmen
|
||||
if not policy:
|
||||
policy = self.get_platform_policy(platform)
|
||||
|
||||
|
||||
# Länge prüfen
|
||||
if len(username) < policy["min_length"]:
|
||||
return False, f"Benutzername ist zu kurz (mindestens {policy['min_length']} Zeichen erforderlich)"
|
||||
|
||||
|
||||
if len(username) > policy["max_length"]:
|
||||
return False, f"Benutzername ist zu lang (maximal {policy['max_length']} Zeichen erlaubt)"
|
||||
|
||||
|
||||
# Erlaubte Zeichen prüfen
|
||||
for char in username:
|
||||
if char not in policy["allowed_chars"]:
|
||||
return False, f"Unerlaubtes Zeichen: '{char}'"
|
||||
|
||||
|
||||
# Anfangszeichen prüfen
|
||||
if username[0] not in policy["allowed_start_chars"]:
|
||||
return False, f"Benutzername darf nicht mit '{username[0]}' beginnen"
|
||||
|
||||
|
||||
# Endzeichen prüfen
|
||||
if username[-1] not in policy["allowed_end_chars"]:
|
||||
return False, f"Benutzername darf nicht mit '{username[-1]}' enden"
|
||||
|
||||
|
||||
# Aufeinanderfolgende Sonderzeichen prüfen
|
||||
if not policy["allowed_consecutive_special"]:
|
||||
special_chars = set(policy["allowed_chars"]) - set(string.ascii_letters + string.digits)
|
||||
for i in range(len(username) - 1):
|
||||
if username[i] in special_chars and username[i+1] in special_chars:
|
||||
return False, "Keine aufeinanderfolgenden Sonderzeichen erlaubt"
|
||||
|
||||
|
||||
# Disallowed words
|
||||
for word in policy["disallowed_words"]:
|
||||
if word.lower() in username.lower():
|
||||
return False, f"Der Benutzername darf '{word}' nicht enthalten"
|
||||
|
||||
return True, "Benutzername ist gültig"
|
||||
|
||||
# ANTI-DETECTION: Prüfe auf verdächtige Bot-Patterns
|
||||
if self._has_suspicious_pattern(username):
|
||||
return False, "Benutzername enthält verdächtiges Bot-Pattern"
|
||||
|
||||
return True, "Benutzername ist gültig"
|
||||
|
||||
# ==========================================================================
|
||||
# ANTI-DETECTION: Verdächtige Pattern-Erkennung
|
||||
# ==========================================================================
|
||||
|
||||
def _has_suspicious_pattern(self, username: str) -> bool:
|
||||
"""
|
||||
Prüft, ob ein Benutzername verdächtige Bot-Patterns enthält.
|
||||
|
||||
Diese Methode erkennt Benutzernamen-Muster, die häufig von Bots
|
||||
verwendet werden und daher von Plattformen leicht erkannt werden.
|
||||
|
||||
Args:
|
||||
username: Zu prüfender Benutzername
|
||||
|
||||
Returns:
|
||||
True wenn verdächtig, False wenn ok
|
||||
"""
|
||||
username_lower = username.lower()
|
||||
|
||||
# Liste verdächtiger Patterns (Regex)
|
||||
suspicious_patterns = [
|
||||
# Plattform-spezifische Bot-Prefixe
|
||||
r'^fb_', # Facebook Bot-Pattern
|
||||
r'^ig_', # Instagram Bot-Pattern
|
||||
r'^tw_', # Twitter Bot-Pattern
|
||||
r'^tt_', # TikTok Bot-Pattern
|
||||
|
||||
# Offensichtliche Bot/Test-Prefixe
|
||||
r'^bot_', # Offensichtlicher Bot
|
||||
r'^test_', # Test-Account
|
||||
r'^temp_', # Temporär
|
||||
r'^fake_', # Offensichtlich fake
|
||||
r'^new_', # Neu (suspekt)
|
||||
r'^auto_', # Automatisierung
|
||||
|
||||
# Notfall/Backup-Patterns (aus altem Code)
|
||||
r'_emergency_', # Notfall-Pattern
|
||||
r'_backup_', # Backup-Pattern
|
||||
r'^emergency_', # Emergency am Anfang
|
||||
r'^backup_', # Backup am Anfang
|
||||
|
||||
# Generische Bot-Patterns
|
||||
r'^user\d{4,}$', # user + 4+ Ziffern am Ende (z.B. user12345)
|
||||
r'^account\d+', # account + Zahlen
|
||||
r'^profile\d+', # profile + Zahlen
|
||||
|
||||
# Verdächtige Zahlenfolgen
|
||||
r'\d{8,}', # 8+ aufeinanderfolgende Ziffern
|
||||
r'^[a-z]{1,2}\d{6,}$', # 1-2 Buchstaben + 6+ Ziffern
|
||||
|
||||
# Timestamp-basierte Patterns
|
||||
r'\d{10,}', # Unix-Timestamp-ähnlich (10+ Ziffern)
|
||||
r'_\d{13}_', # Millisekunden-Timestamp in der Mitte
|
||||
|
||||
# Generische Suffixe die auf Bots hindeuten
|
||||
r'_gen$', # Generator-Suffix
|
||||
r'_bot$', # Bot-Suffix
|
||||
r'_auto$', # Auto-Suffix
|
||||
r'_spam$', # Spam-Suffix
|
||||
]
|
||||
|
||||
for pattern in suspicious_patterns:
|
||||
if re.search(pattern, username_lower):
|
||||
logger.debug(f"Verdächtiges Pattern gefunden: {pattern} in '{username}'")
|
||||
return True
|
||||
|
||||
# Zusätzliche Heuristiken
|
||||
|
||||
# Prüfe auf zu viele Unterstriche (>2 ist verdächtig)
|
||||
if username_lower.count('_') > 2:
|
||||
logger.debug(f"Zu viele Unterstriche in '{username}'")
|
||||
return True
|
||||
|
||||
# Prüfe auf repetitive Zeichen (z.B. "aaaa" oder "1111")
|
||||
for i in range(len(username_lower) - 3):
|
||||
if username_lower[i] == username_lower[i+1] == username_lower[i+2] == username_lower[i+3]:
|
||||
logger.debug(f"Repetitive Zeichen in '{username}'")
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def generate_realistic_username(self, first_name: str = "", last_name: str = "",
|
||||
platform: str = "default") -> str:
|
||||
"""
|
||||
Generiert einen realistischen Benutzernamen ohne verdächtige Patterns.
|
||||
|
||||
Diese Methode ist speziell für Anti-Detection optimiert und generiert
|
||||
Benutzernamen, die wie echte menschliche Benutzernamen aussehen.
|
||||
|
||||
Args:
|
||||
first_name: Vorname (optional)
|
||||
last_name: Nachname (optional)
|
||||
platform: Zielplattform
|
||||
|
||||
Returns:
|
||||
Realistischer Benutzername
|
||||
"""
|
||||
policy = self.get_platform_policy(platform)
|
||||
|
||||
# Realistische Patterns (wie echte Menschen sie wählen)
|
||||
realistic_patterns = []
|
||||
|
||||
if first_name:
|
||||
first_name_clean = re.sub(r'[^a-z]', '', first_name.lower())
|
||||
|
||||
# Pattern 1: vorname + Geburtsjahr (z.B. "max1995")
|
||||
realistic_patterns.append(
|
||||
lambda fn=first_name_clean: f"{fn}{random.randint(1985, 2005)}"
|
||||
)
|
||||
|
||||
# Pattern 2: vorname + Nachname-Initial + 2 Ziffern (z.B. "maxm92")
|
||||
if last_name:
|
||||
last_initial = last_name[0].lower() if last_name else ''
|
||||
realistic_patterns.append(
|
||||
lambda fn=first_name_clean, li=last_initial: f"{fn}{li}{random.randint(10, 99)}"
|
||||
)
|
||||
|
||||
# Pattern 3: vorname.nachname (z.B. "max.mustermann")
|
||||
if last_name:
|
||||
last_name_clean = re.sub(r'[^a-z]', '', last_name.lower())
|
||||
realistic_patterns.append(
|
||||
lambda fn=first_name_clean, ln=last_name_clean: f"{fn}.{ln}"
|
||||
)
|
||||
|
||||
# Pattern 4: vorname_adjektiv (z.B. "max_sunny")
|
||||
realistic_patterns.append(
|
||||
lambda fn=first_name_clean: f"{fn}_{random.choice(self.adjectives)}"
|
||||
)
|
||||
|
||||
# Pattern 5: adjektiv_vorname_jahr (z.B. "sunny_max_93")
|
||||
realistic_patterns.append(
|
||||
lambda fn=first_name_clean: f"{random.choice(self.adjectives)}_{fn}_{random.randint(85, 99)}"
|
||||
)
|
||||
|
||||
# Fallback-Patterns ohne Namen
|
||||
realistic_patterns.extend([
|
||||
# adjektiv + tier (z.B. "happytiger")
|
||||
lambda: f"{random.choice(self.adjectives)}{random.choice(self.nouns)}",
|
||||
|
||||
# adjektiv + tier + 2 Ziffern (z.B. "coolwolf42")
|
||||
lambda: f"{random.choice(self.adjectives)}{random.choice(self.nouns)}{random.randint(10, 99)}",
|
||||
|
||||
# tier + jahr (z.B. "eagle1995")
|
||||
lambda: f"{random.choice(self.nouns)}{random.randint(1985, 2005)}",
|
||||
])
|
||||
|
||||
# Versuche bis zu 20 mal einen gültigen, nicht-verdächtigen Namen zu generieren
|
||||
for _ in range(20):
|
||||
pattern_func = random.choice(realistic_patterns)
|
||||
username = pattern_func()
|
||||
|
||||
# Länge anpassen
|
||||
if len(username) > policy["max_length"]:
|
||||
username = username[:policy["max_length"]]
|
||||
if len(username) < policy["min_length"]:
|
||||
username += str(random.randint(10, 99))
|
||||
|
||||
# Validieren (inkl. Pattern-Check)
|
||||
valid, _ = self.validate_username(username, policy=policy)
|
||||
if valid:
|
||||
logger.info(f"Realistischer Benutzername generiert: {username}")
|
||||
return username
|
||||
|
||||
# Absoluter Fallback
|
||||
fallback = f"{random.choice(self.adjectives)}{random.choice(self.nouns)}{random.randint(10, 99)}"
|
||||
logger.warning(f"Fallback-Benutzername verwendet: {fallback}")
|
||||
return fallback
|
||||
In neuem Issue referenzieren
Einen Benutzer sperren