Initial commit
Dieser Commit ist enthalten in:
0
licensing/__init__.py
Normale Datei
0
licensing/__init__.py
Normale Datei
BIN
licensing/__pycache__/__init__.cpython-310.pyc
Normale Datei
BIN
licensing/__pycache__/__init__.cpython-310.pyc
Normale Datei
Binäre Datei nicht angezeigt.
BIN
licensing/__pycache__/__init__.cpython-313.pyc
Normale Datei
BIN
licensing/__pycache__/__init__.cpython-313.pyc
Normale Datei
Binäre Datei nicht angezeigt.
BIN
licensing/__pycache__/license_manager.cpython-310.pyc
Normale Datei
BIN
licensing/__pycache__/license_manager.cpython-310.pyc
Normale Datei
Binäre Datei nicht angezeigt.
BIN
licensing/__pycache__/license_manager.cpython-313.pyc
Normale Datei
BIN
licensing/__pycache__/license_manager.cpython-313.pyc
Normale Datei
Binäre Datei nicht angezeigt.
0
licensing/hardware_fingerprint.py
Normale Datei
0
licensing/hardware_fingerprint.py
Normale Datei
450
licensing/license_manager.py
Normale Datei
450
licensing/license_manager.py
Normale Datei
@ -0,0 +1,450 @@
|
||||
"""
|
||||
Lizenzverwaltungsfunktionalität für den Social Media Account Generator.
|
||||
"""
|
||||
|
||||
import os
|
||||
import json
|
||||
import time
|
||||
import uuid
|
||||
import hmac
|
||||
import hashlib
|
||||
import logging
|
||||
import requests
|
||||
from datetime import datetime, timedelta
|
||||
from typing import Dict, List, Any, Optional, Tuple, Union
|
||||
|
||||
logger = logging.getLogger("license_manager")
|
||||
|
||||
class LicenseManager:
|
||||
"""Klasse zur Verwaltung von Softwarelizenzen."""
|
||||
|
||||
CONFIG_FILE = os.path.join("config", "license.json")
|
||||
LICENSE_SERVER_URL = "https://api.example.com/license" # Platzhalter - in der Produktion anpassen
|
||||
|
||||
def __init__(self):
|
||||
"""Initialisiert den LicenseManager und lädt die Konfiguration."""
|
||||
self.license_data = self.load_license_data()
|
||||
self.machine_id = self.get_machine_id()
|
||||
|
||||
# Stelle sicher, dass das Konfigurationsverzeichnis existiert
|
||||
os.makedirs(os.path.dirname(self.CONFIG_FILE), exist_ok=True)
|
||||
|
||||
# Prüfe die Lizenz beim Start
|
||||
self.verify_license()
|
||||
|
||||
def load_license_data(self) -> Dict[str, Any]:
|
||||
"""Lädt die Lizenzdaten aus der Konfigurationsdatei."""
|
||||
if not os.path.exists(self.CONFIG_FILE):
|
||||
return {
|
||||
"key": "",
|
||||
"activation_date": "",
|
||||
"expiry_date": "",
|
||||
"status": "inactive",
|
||||
"status_text": "Keine Lizenz aktiviert",
|
||||
"features": [],
|
||||
"last_online_check": "",
|
||||
"signature": ""
|
||||
}
|
||||
|
||||
try:
|
||||
with open(self.CONFIG_FILE, "r", encoding="utf-8") as f:
|
||||
license_data = json.load(f)
|
||||
|
||||
logger.info(f"Lizenzdaten geladen: Status '{license_data.get('status', 'unbekannt')}'")
|
||||
|
||||
return license_data
|
||||
except Exception as e:
|
||||
logger.error(f"Fehler beim Laden der Lizenzdaten: {e}")
|
||||
return {
|
||||
"key": "",
|
||||
"activation_date": "",
|
||||
"expiry_date": "",
|
||||
"status": "inactive",
|
||||
"status_text": "Fehler beim Laden der Lizenz",
|
||||
"features": [],
|
||||
"last_online_check": "",
|
||||
"signature": ""
|
||||
}
|
||||
|
||||
def save_license_data(self) -> bool:
|
||||
"""Speichert die Lizenzdaten in die Konfigurationsdatei."""
|
||||
try:
|
||||
with open(self.CONFIG_FILE, "w", encoding="utf-8") as f:
|
||||
json.dump(self.license_data, f, indent=2)
|
||||
|
||||
logger.info("Lizenzdaten gespeichert")
|
||||
return True
|
||||
except Exception as e:
|
||||
logger.error(f"Fehler beim Speichern der Lizenzdaten: {e}")
|
||||
return False
|
||||
|
||||
def get_license_info(self) -> Dict[str, Any]:
|
||||
"""Gibt die aktuellen Lizenzdaten zurück."""
|
||||
return self.license_data
|
||||
|
||||
def get_machine_id(self) -> str:
|
||||
"""
|
||||
Generiert eine eindeutige Maschinen-ID.
|
||||
|
||||
Returns:
|
||||
Eindeutige Maschinen-ID
|
||||
"""
|
||||
try:
|
||||
# Versuche, eine eindeutige Hardware-ID zu generieren
|
||||
# In der Produktion sollte dies mit einer robusteren Methode ersetzt werden
|
||||
|
||||
machine_id_file = os.path.join("config", ".machine_id")
|
||||
|
||||
if os.path.exists(machine_id_file):
|
||||
# Bestehende ID laden
|
||||
with open(machine_id_file, "r") as f:
|
||||
return f.read().strip()
|
||||
else:
|
||||
# Neue ID generieren
|
||||
machine_id = str(uuid.uuid4())
|
||||
|
||||
with open(machine_id_file, "w") as f:
|
||||
f.write(machine_id)
|
||||
|
||||
return machine_id
|
||||
except Exception as e:
|
||||
logger.error(f"Fehler bei der Generierung der Maschinen-ID: {e}")
|
||||
|
||||
# Fallback: UUID auf Basis der aktuellen Zeit
|
||||
return str(uuid.uuid5(uuid.NAMESPACE_DNS, f"fallback-{time.time()}"))
|
||||
|
||||
def is_licensed(self) -> bool:
|
||||
"""
|
||||
Überprüft, ob eine gültige Lizenz vorhanden ist.
|
||||
|
||||
Returns:
|
||||
True, wenn eine gültige Lizenz vorhanden ist, sonst False
|
||||
"""
|
||||
# Prüfe den Status der Lizenz
|
||||
if self.license_data["status"] not in ["active", "trial"]:
|
||||
return False
|
||||
|
||||
# Prüfe, ob die Lizenz abgelaufen ist
|
||||
if self.license_data["expiry_date"]:
|
||||
try:
|
||||
expiry_date = datetime.fromisoformat(self.license_data["expiry_date"])
|
||||
|
||||
if datetime.now() > expiry_date:
|
||||
logger.warning("Lizenz ist abgelaufen")
|
||||
self.license_data["status"] = "expired"
|
||||
self.license_data["status_text"] = "Lizenz abgelaufen"
|
||||
self.save_license_data()
|
||||
return False
|
||||
except Exception as e:
|
||||
logger.error(f"Fehler beim Parsen des Ablaufdatums: {e}")
|
||||
return False
|
||||
|
||||
# Prüfe, ob regelmäßige Online-Verifizierung erforderlich ist
|
||||
if self.license_data["last_online_check"]:
|
||||
try:
|
||||
last_check = datetime.fromisoformat(self.license_data["last_online_check"])
|
||||
max_offline_days = 7 # Maximale Tage ohne Online-Check
|
||||
|
||||
if datetime.now() > last_check + timedelta(days=max_offline_days):
|
||||
logger.warning(f"Letzte Online-Überprüfung ist mehr als {max_offline_days} Tage her")
|
||||
|
||||
# Versuche, eine Online-Überprüfung durchzuführen
|
||||
if not self.online_verification():
|
||||
self.license_data["status"] = "verification_required"
|
||||
self.license_data["status_text"] = "Online-Überprüfung erforderlich"
|
||||
self.save_license_data()
|
||||
return False
|
||||
except Exception as e:
|
||||
logger.error(f"Fehler bei der Überprüfung der Online-Verifizierung: {e}")
|
||||
|
||||
# Prüfe die Signatur (in der Produktion sollte dies erweitert werden)
|
||||
if not self.verify_signature():
|
||||
logger.warning("Ungültige Lizenzsignatur")
|
||||
self.license_data["status"] = "invalid"
|
||||
self.license_data["status_text"] = "Ungültige Lizenz (manipuliert)"
|
||||
self.save_license_data()
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def verify_license(self) -> bool:
|
||||
"""
|
||||
Überprüft die aktuelle Lizenz.
|
||||
|
||||
Returns:
|
||||
True, wenn die Lizenz gültig ist, sonst False
|
||||
"""
|
||||
# Lizenzschlüssel vorhanden?
|
||||
if not self.license_data["key"]:
|
||||
logger.info("Kein Lizenzschlüssel vorhanden")
|
||||
self.license_data["status"] = "inactive"
|
||||
self.license_data["status_text"] = "Keine Lizenz aktiviert"
|
||||
self.save_license_data()
|
||||
return False
|
||||
|
||||
return self.is_licensed()
|
||||
|
||||
def create_signature(self, data: str) -> str:
|
||||
"""
|
||||
Erstellt eine Signatur für die angegebenen Daten.
|
||||
|
||||
Args:
|
||||
data: Zu signierende Daten
|
||||
|
||||
Returns:
|
||||
Signatur als Hexadezimalstring
|
||||
"""
|
||||
# In der Produktion sollte ein sicherer Schlüssel verwendet werden
|
||||
secret_key = "development_secret_key"
|
||||
|
||||
# HMAC-SHA256-Signatur erstellen
|
||||
signature = hmac.new(
|
||||
secret_key.encode(),
|
||||
data.encode(),
|
||||
hashlib.sha256
|
||||
).hexdigest()
|
||||
|
||||
return signature
|
||||
|
||||
def verify_signature(self) -> bool:
|
||||
"""
|
||||
Überprüft die Signatur der Lizenzdaten.
|
||||
|
||||
Returns:
|
||||
True, wenn die Signatur gültig ist, sonst False
|
||||
"""
|
||||
if not self.license_data["signature"]:
|
||||
return False
|
||||
|
||||
# Daten für die Signaturprüfung vorbereiten
|
||||
data_to_verify = f"{self.license_data['key']}|{self.machine_id}|{self.license_data['activation_date']}|{self.license_data['expiry_date']}"
|
||||
|
||||
# Signatur erstellen
|
||||
computed_signature = self.create_signature(data_to_verify)
|
||||
|
||||
# Signatur vergleichen
|
||||
return computed_signature == self.license_data["signature"]
|
||||
|
||||
def online_verification(self) -> bool:
|
||||
"""
|
||||
Führt eine Online-Überprüfung der Lizenz durch.
|
||||
|
||||
Returns:
|
||||
True, wenn die Überprüfung erfolgreich war, sonst False
|
||||
"""
|
||||
if not self.license_data["key"]:
|
||||
return False
|
||||
|
||||
try:
|
||||
# Daten für die Lizenzüberprüfung
|
||||
verification_data = {
|
||||
"license_key": self.license_data["key"],
|
||||
"machine_id": self.machine_id,
|
||||
"product_version": "1.0.0", # In der Produktion aus einer Konfiguration laden
|
||||
"timestamp": time.time()
|
||||
}
|
||||
|
||||
# Anfrage an den Lizenzserver senden
|
||||
response = requests.post(
|
||||
self.LICENSE_SERVER_URL + "/verify",
|
||||
json=verification_data,
|
||||
timeout=10
|
||||
)
|
||||
|
||||
if response.status_code == 200:
|
||||
result = response.json()
|
||||
|
||||
if result.get("status") == "active":
|
||||
# Lizenz ist gültig
|
||||
logger.info("Online-Lizenzüberprüfung erfolgreich")
|
||||
|
||||
# Aktualisiere das Datum der letzten Überprüfung
|
||||
self.license_data["last_online_check"] = datetime.now().isoformat()
|
||||
self.save_license_data()
|
||||
|
||||
return True
|
||||
else:
|
||||
# Lizenz ist ungültig
|
||||
logger.warning(f"Lizenz ungültig: {result.get('message', 'Unbekannter Fehler')}")
|
||||
|
||||
self.license_data["status"] = result.get("status", "invalid")
|
||||
self.license_data["status_text"] = result.get("message", "Lizenz ungültig")
|
||||
self.save_license_data()
|
||||
|
||||
return False
|
||||
else:
|
||||
logger.warning(f"Fehler bei der Online-Überprüfung: HTTP {response.status_code}")
|
||||
return False
|
||||
|
||||
except requests.RequestException as e:
|
||||
logger.error(f"Netzwerkfehler bei der Online-Überprüfung: {e}")
|
||||
|
||||
# Bei Verbindungsproblemen sollte die lokale Lizenz weiterhin gültig bleiben
|
||||
# In der Produktion kann hier eine Begrenzung der Offline-Zeit implementiert werden
|
||||
return True
|
||||
except Exception as e:
|
||||
logger.error(f"Unerwarteter Fehler bei der Online-Überprüfung: {e}")
|
||||
return False
|
||||
|
||||
def activate_license(self, license_key: str) -> Tuple[bool, str]:
|
||||
"""
|
||||
Aktiviert eine Lizenz mit dem angegebenen Schlüssel.
|
||||
|
||||
Args:
|
||||
license_key: Zu aktivierender Lizenzschlüssel
|
||||
|
||||
Returns:
|
||||
(Erfolg, Nachricht)
|
||||
"""
|
||||
if not license_key:
|
||||
return False, "Bitte geben Sie einen Lizenzschlüssel ein."
|
||||
|
||||
try:
|
||||
# In der Produktionsumgebung sollte hier eine Online-Aktivierung erfolgen
|
||||
# Für Entwicklungszwecke implementieren wir eine einfache lokale Aktivierung
|
||||
|
||||
# Simulierte Online-Aktivierung
|
||||
activation_data = {
|
||||
"license_key": license_key,
|
||||
"machine_id": self.machine_id,
|
||||
"product_version": "1.0.0",
|
||||
"timestamp": time.time()
|
||||
}
|
||||
|
||||
# Nur für Entwicklung: Prüfe, ob der Lizenzschlüssel bekannt ist
|
||||
if license_key.startswith("DEV-"):
|
||||
# Entwicklungslizenzen haben unbegrenzte Laufzeit
|
||||
expiry_date = (datetime.now() + timedelta(days=365)).isoformat()
|
||||
activation_response = {
|
||||
"status": "active",
|
||||
"message": "Entwicklungslizenz aktiviert",
|
||||
"activation_date": datetime.now().isoformat(),
|
||||
"expiry_date": expiry_date,
|
||||
"features": ["all"]
|
||||
}
|
||||
elif license_key.startswith("TRIAL-"):
|
||||
# Trial-Lizenzen haben begrenzte Laufzeit
|
||||
expiry_date = (datetime.now() + timedelta(days=30)).isoformat()
|
||||
activation_response = {
|
||||
"status": "trial",
|
||||
"message": "Trial-Lizenz aktiviert (30 Tage)",
|
||||
"activation_date": datetime.now().isoformat(),
|
||||
"expiry_date": expiry_date,
|
||||
"features": ["basic"]
|
||||
}
|
||||
else:
|
||||
# Alle anderen Schlüssel simulieren eine Online-Aktivierung
|
||||
try:
|
||||
# Anfrage an den Lizenzserver senden
|
||||
response = requests.post(
|
||||
self.LICENSE_SERVER_URL + "/activate",
|
||||
json=activation_data,
|
||||
timeout=10
|
||||
)
|
||||
|
||||
if response.status_code == 200:
|
||||
activation_response = response.json()
|
||||
else:
|
||||
logger.warning(f"Fehler bei der Lizenzaktivierung: HTTP {response.status_code}")
|
||||
return False, f"Fehler bei der Lizenzaktivierung: HTTP {response.status_code}"
|
||||
except requests.RequestException as e:
|
||||
logger.error(f"Netzwerkfehler bei der Lizenzaktivierung: {e}")
|
||||
return False, f"Netzwerkfehler bei der Lizenzaktivierung: {e}"
|
||||
except Exception as e:
|
||||
logger.error(f"Unerwarteter Fehler bei der Lizenzaktivierung: {e}")
|
||||
return False, f"Unerwarteter Fehler bei der Lizenzaktivierung: {e}"
|
||||
|
||||
# Lizenzdaten aktualisieren
|
||||
self.license_data["key"] = license_key
|
||||
self.license_data["status"] = activation_response.get("status", "inactive")
|
||||
self.license_data["status_text"] = activation_response.get("message", "Unbekannter Status")
|
||||
self.license_data["activation_date"] = activation_response.get("activation_date", datetime.now().isoformat())
|
||||
self.license_data["expiry_date"] = activation_response.get("expiry_date", "")
|
||||
self.license_data["features"] = activation_response.get("features", [])
|
||||
self.license_data["last_online_check"] = datetime.now().isoformat()
|
||||
|
||||
# Signatur erstellen
|
||||
data_to_sign = f"{self.license_data['key']}|{self.machine_id}|{self.license_data['activation_date']}|{self.license_data['expiry_date']}"
|
||||
self.license_data["signature"] = self.create_signature(data_to_sign)
|
||||
|
||||
# Lizenzdaten speichern
|
||||
self.save_license_data()
|
||||
|
||||
logger.info(f"Lizenz '{license_key}' erfolgreich aktiviert: {self.license_data['status_text']}")
|
||||
|
||||
return True, self.license_data["status_text"]
|
||||
|
||||
except Exception as e:
|
||||
error_msg = f"Fehler bei der Lizenzaktivierung: {e}"
|
||||
logger.error(error_msg)
|
||||
return False, error_msg
|
||||
|
||||
def deactivate_license(self) -> Tuple[bool, str]:
|
||||
"""
|
||||
Deaktiviert die aktuelle Lizenz.
|
||||
|
||||
Returns:
|
||||
(Erfolg, Nachricht)
|
||||
"""
|
||||
if not self.license_data["key"]:
|
||||
return False, "Keine Lizenz aktiviert"
|
||||
|
||||
old_key = self.license_data["key"]
|
||||
|
||||
try:
|
||||
# Online-Deaktivierung simulieren
|
||||
deactivation_data = {
|
||||
"license_key": self.license_data["key"],
|
||||
"machine_id": self.machine_id,
|
||||
"timestamp": time.time()
|
||||
}
|
||||
|
||||
# Anfrage für die Produktionsumgebung
|
||||
# response = requests.post(
|
||||
# self.LICENSE_SERVER_URL + "/deactivate",
|
||||
# json=deactivation_data,
|
||||
# timeout=10
|
||||
# )
|
||||
|
||||
# Lizenzdaten zurücksetzen
|
||||
self.license_data = {
|
||||
"key": "",
|
||||
"activation_date": "",
|
||||
"expiry_date": "",
|
||||
"status": "inactive",
|
||||
"status_text": "Keine Lizenz aktiviert",
|
||||
"features": [],
|
||||
"last_online_check": "",
|
||||
"signature": ""
|
||||
}
|
||||
|
||||
# Lizenzdaten speichern
|
||||
self.save_license_data()
|
||||
|
||||
logger.info(f"Lizenz '{old_key}' erfolgreich deaktiviert")
|
||||
|
||||
return True, "Lizenz erfolgreich deaktiviert"
|
||||
|
||||
except Exception as e:
|
||||
error_msg = f"Fehler bei der Lizenzdeaktivierung: {e}"
|
||||
logger.error(error_msg)
|
||||
return False, error_msg
|
||||
|
||||
def has_feature(self, feature_name: str) -> bool:
|
||||
"""
|
||||
Überprüft, ob die aktuelle Lizenz eine bestimmte Funktion unterstützt.
|
||||
|
||||
Args:
|
||||
feature_name: Name der zu überprüfenden Funktion
|
||||
|
||||
Returns:
|
||||
True, wenn die Funktion unterstützt wird, sonst False
|
||||
"""
|
||||
if not self.is_licensed():
|
||||
return False
|
||||
|
||||
# "all" bedeutet, dass alle Funktionen unterstützt werden
|
||||
if "all" in self.license_data["features"]:
|
||||
return True
|
||||
|
||||
return feature_name in self.license_data["features"]
|
||||
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