Initial commit
Dieser Commit ist enthalten in:
304
licensing/license_validator.py
Normale Datei
304
licensing/license_validator.py
Normale Datei
@ -0,0 +1,304 @@
|
||||
"""
|
||||
Lizenzvalidator - Validiert Lizenzschlüssel und enthält Sicherheitsalgorithmen
|
||||
"""
|
||||
|
||||
import os
|
||||
import logging
|
||||
import hashlib
|
||||
import hmac
|
||||
import base64
|
||||
import json
|
||||
import time
|
||||
import random
|
||||
import string
|
||||
from datetime import datetime, timedelta
|
||||
from typing import Dict, Optional, Tuple, Any, List
|
||||
|
||||
# Konfiguriere Logger
|
||||
logger = logging.getLogger("license_validator")
|
||||
|
||||
class LicenseValidator:
|
||||
"""
|
||||
Validiert Lizenzschlüssel und führt kryptografische Operationen durch.
|
||||
Enthält Platzhaltercode für die Lizenzvalidierung.
|
||||
"""
|
||||
|
||||
# Sicherheitsschlüssel (würde in einer echten Implementierung nicht im Code stehen)
|
||||
SECRET_KEY = "5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8"
|
||||
|
||||
def __init__(self):
|
||||
"""Initialisiert den LicenseValidator."""
|
||||
logger.info("Lizenzvalidator initialisiert")
|
||||
|
||||
def validate_key_format(self, license_key: str) -> bool:
|
||||
"""
|
||||
Prüft, ob der Lizenzschlüssel das richtige Format hat.
|
||||
|
||||
Args:
|
||||
license_key: Der zu prüfende Lizenzschlüssel
|
||||
|
||||
Returns:
|
||||
bool: True, wenn das Format gültig ist, False sonst
|
||||
"""
|
||||
# Einfacher Formatcheck für XXXXX-XXXXX-XXXXX-XXXXX
|
||||
import re
|
||||
return bool(re.match(r'^[A-Z0-9]{5}-[A-Z0-9]{5}-[A-Z0-9]{5}-[A-Z0-9]{5}$', license_key))
|
||||
|
||||
def validate_key_checksum(self, license_key: str) -> bool:
|
||||
"""
|
||||
Prüft, ob die Prüfsumme des Lizenzschlüssels gültig ist.
|
||||
|
||||
Args:
|
||||
license_key: Der zu prüfende Lizenzschlüssel
|
||||
|
||||
Returns:
|
||||
bool: True, wenn die Prüfsumme gültig ist, False sonst
|
||||
"""
|
||||
# Platzhalterimplementierung - in einer echten Implementierung würde hier
|
||||
# eine Prüfsummenberechnung stehen
|
||||
|
||||
# Entferne Bindestriche für die Verarbeitung
|
||||
key_parts = license_key.split('-')
|
||||
if len(key_parts) != 4:
|
||||
return False
|
||||
|
||||
# Einfacher Check: Letzter Buchstabe des ersten Teils ist abhängig von den ersten Buchstaben
|
||||
# der anderen Teile (XOR der ASCII-Werte)
|
||||
try:
|
||||
check_char = key_parts[0][-1]
|
||||
calculated_char = chr(ord(key_parts[1][0]) ^ ord(key_parts[2][0]) ^ ord(key_parts[3][0]))
|
||||
|
||||
# In einer echten Implementierung wäre diese Prüfung viel stärker
|
||||
return check_char == calculated_char
|
||||
except IndexError:
|
||||
return False
|
||||
except Exception as e:
|
||||
logger.error(f"Fehler bei der Prüfsummenberechnung: {e}")
|
||||
return False
|
||||
|
||||
def decrypt_license_data(self, license_key: str) -> Optional[Dict[str, Any]]:
|
||||
"""
|
||||
Entschlüsselt Lizenzinformationen aus dem Schlüssel.
|
||||
|
||||
Args:
|
||||
license_key: Der zu entschlüsselnde Lizenzschlüssel
|
||||
|
||||
Returns:
|
||||
Optional[Dict[str, Any]]: Entschlüsselte Lizenzdaten oder None bei Fehler
|
||||
"""
|
||||
# Platzhalterimplementierung - in einer echten Implementierung würde hier
|
||||
# eine Entschlüsselung stehen
|
||||
|
||||
if not self.validate_key_format(license_key):
|
||||
return None
|
||||
|
||||
# Mock-Daten generieren
|
||||
key_parts = license_key.split('-')
|
||||
|
||||
# Aus dem Schlüssel Informationen "ableiten"
|
||||
try:
|
||||
# Verwende den ersten Teil für die Lizenzart
|
||||
license_type_index = sum(ord(c) for c in key_parts[0]) % 3
|
||||
license_types = ["basic", "premium", "enterprise"]
|
||||
license_type = license_types[license_type_index]
|
||||
|
||||
# Verwende den zweiten Teil für die Gültigkeitsdauer
|
||||
validity_months = (sum(ord(c) for c in key_parts[1]) % 12) + 1
|
||||
|
||||
# Verwende den dritten Teil für die Funktionen
|
||||
features_count = (sum(ord(c) for c in key_parts[2]) % 5) + 1
|
||||
all_features = ["multi_account", "proxy_rotation", "advanced_analytics",
|
||||
"sms_verification", "captcha_solving", "phone_verification",
|
||||
"export", "scheduling"]
|
||||
features = all_features[:features_count]
|
||||
|
||||
# Generiere ein "verschlüsseltes" Token
|
||||
token = hashlib.sha256(license_key.encode()).hexdigest()
|
||||
|
||||
# Aktuelle Zeit für Aktivierung
|
||||
now = datetime.now()
|
||||
activation_date = now.strftime("%Y-%m-%d %H:%M:%S")
|
||||
expiry_date = (now + timedelta(days=30*validity_months)).strftime("%Y-%m-%d %H:%M:%S")
|
||||
|
||||
# Lizenzdaten zusammenstellen
|
||||
license_data = {
|
||||
"license_type": license_type,
|
||||
"features": features,
|
||||
"activation_date": activation_date,
|
||||
"expiry_date": expiry_date,
|
||||
"token": token
|
||||
}
|
||||
|
||||
return license_data
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Fehler bei der Entschlüsselung des Lizenzschlüssels: {e}")
|
||||
return None
|
||||
|
||||
def generate_license_key(self, license_type: str = "basic", validity_months: int = 12,
|
||||
features: List[str] = None) -> str:
|
||||
"""
|
||||
Generiert einen Lizenzschlüssel.
|
||||
|
||||
Args:
|
||||
license_type: Art der Lizenz ("basic", "premium", "enterprise")
|
||||
validity_months: Gültigkeitsdauer in Monaten
|
||||
features: Liste der Funktionen
|
||||
|
||||
Returns:
|
||||
str: Generierter Lizenzschlüssel
|
||||
"""
|
||||
# Platzhalterimplementierung - in einer echten Implementierung würde hier
|
||||
# eine sichere Schlüsselgenerierung stehen
|
||||
|
||||
# Verwende die Eingabeparameter als Seed für die Generierung
|
||||
seed = f"{license_type}{validity_months}{','.join(features or [])}{time.time()}"
|
||||
random.seed(hashlib.md5(seed.encode()).hexdigest())
|
||||
|
||||
# Generiere 4 Teile mit jeweils 5 Zeichen (Großbuchstaben und Zahlen)
|
||||
chars = string.ascii_uppercase + string.digits
|
||||
parts = []
|
||||
|
||||
for _ in range(4):
|
||||
part = ''.join(random.choice(chars) for _ in range(5))
|
||||
parts.append(part)
|
||||
|
||||
# Stelle sicher, dass der letzte Buchstabe des ersten Teils
|
||||
# ein XOR der ersten Buchstaben der anderen Teile ist
|
||||
# (für die einfache Prüfsumme)
|
||||
calc_char = chr(ord(parts[1][0]) ^ ord(parts[2][0]) ^ ord(parts[3][0]))
|
||||
parts[0] = parts[0][:-1] + calc_char
|
||||
|
||||
# Verbinde die Teile mit Bindestrichen
|
||||
license_key = '-'.join(parts)
|
||||
|
||||
return license_key
|
||||
|
||||
def sign_data(self, data: str) -> str:
|
||||
"""
|
||||
Signiert Daten mit dem geheimen Schlüssel.
|
||||
|
||||
Args:
|
||||
data: Zu signierende Daten
|
||||
|
||||
Returns:
|
||||
str: Signatur
|
||||
"""
|
||||
return hmac.new(
|
||||
self.SECRET_KEY.encode(),
|
||||
data.encode(),
|
||||
hashlib.sha256
|
||||
).hexdigest()
|
||||
|
||||
def verify_signature(self, data: str, signature: str) -> bool:
|
||||
"""
|
||||
Überprüft die Signatur von Daten.
|
||||
|
||||
Args:
|
||||
data: Signierte Daten
|
||||
signature: Zu überprüfende Signatur
|
||||
|
||||
Returns:
|
||||
bool: True, wenn die Signatur gültig ist, False sonst
|
||||
"""
|
||||
expected_signature = self.sign_data(data)
|
||||
return hmac.compare_digest(expected_signature, signature)
|
||||
|
||||
def encode_license_data(self, data: Dict[str, Any]) -> str:
|
||||
"""
|
||||
Kodiert Lizenzdaten zur sicheren Übertragung.
|
||||
|
||||
Args:
|
||||
data: Zu kodierende Lizenzdaten
|
||||
|
||||
Returns:
|
||||
str: Kodierte Lizenzdaten
|
||||
"""
|
||||
# Daten in JSON konvertieren
|
||||
json_data = json.dumps(data, sort_keys=True)
|
||||
|
||||
# Signatur hinzufügen
|
||||
signature = self.sign_data(json_data)
|
||||
|
||||
# Zusammen mit der Signatur kodieren
|
||||
combined = f"{json_data}|{signature}"
|
||||
encoded = base64.b64encode(combined.encode()).decode()
|
||||
|
||||
return encoded
|
||||
|
||||
def decode_license_data(self, encoded: str) -> Optional[Dict[str, Any]]:
|
||||
"""
|
||||
Dekodiert und überprüft kodierte Lizenzdaten.
|
||||
|
||||
Args:
|
||||
encoded: Kodierte Lizenzdaten
|
||||
|
||||
Returns:
|
||||
Optional[Dict[str, Any]]: Dekodierte Lizenzdaten oder None bei Fehler
|
||||
"""
|
||||
try:
|
||||
# Dekodieren
|
||||
decoded = base64.b64decode(encoded).decode()
|
||||
|
||||
# In Daten und Signatur aufteilen
|
||||
json_data, signature = decoded.split('|', 1)
|
||||
|
||||
# Signatur überprüfen
|
||||
if not self.verify_signature(json_data, signature):
|
||||
logger.warning("Ungültige Signatur in lizenzierten Daten")
|
||||
return None
|
||||
|
||||
# JSON parsen
|
||||
data = json.loads(json_data)
|
||||
|
||||
return data
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Fehler beim Dekodieren der Lizenzdaten: {e}")
|
||||
return None
|
||||
|
||||
|
||||
# Beispielnutzung, wenn direkt ausgeführt
|
||||
if __name__ == "__main__":
|
||||
# Konfiguriere Logging
|
||||
logging.basicConfig(
|
||||
level=logging.INFO,
|
||||
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
|
||||
)
|
||||
|
||||
# Beispiel für LicenseValidator
|
||||
validator = LicenseValidator()
|
||||
|
||||
# Generiere einen Lizenzschlüssel
|
||||
features = ["multi_account", "proxy_rotation", "advanced_analytics"]
|
||||
key = validator.generate_license_key("premium", 12, features)
|
||||
print(f"Generierter Lizenzschlüssel: {key}")
|
||||
|
||||
# Validiere den Schlüssel
|
||||
is_valid_format = validator.validate_key_format(key)
|
||||
is_valid_checksum = validator.validate_key_checksum(key)
|
||||
print(f"Format gültig: {is_valid_format}")
|
||||
print(f"Prüfsumme gültig: {is_valid_checksum}")
|
||||
|
||||
# Entschlüssele Lizenzdaten
|
||||
license_data = validator.decrypt_license_data(key)
|
||||
if license_data:
|
||||
print("\nEntschlüsselte Lizenzdaten:")
|
||||
for k, v in license_data.items():
|
||||
print(f" {k}: {v}")
|
||||
|
||||
# Beispiel für Kodierung und Dekodierung
|
||||
test_data = {
|
||||
"name": "Test License",
|
||||
"type": "premium",
|
||||
"expires": "2026-01-01"
|
||||
}
|
||||
|
||||
encoded = validator.encode_license_data(test_data)
|
||||
print(f"\nKodierte Daten: {encoded}")
|
||||
|
||||
decoded = validator.decode_license_data(encoded)
|
||||
if decoded:
|
||||
print("\nDekodierte Daten:")
|
||||
for k, v in decoded.items():
|
||||
print(f" {k}: {v}")
|
||||
In neuem Issue referenzieren
Einen Benutzer sperren