472 Zeilen
17 KiB
Python
472 Zeilen
17 KiB
Python
"""
|
|
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
|
|
from .api_client import LicenseAPIClient
|
|
from .hardware_fingerprint import HardwareFingerprint
|
|
from .session_manager import SessionManager
|
|
|
|
logger = logging.getLogger("license_manager")
|
|
|
|
class LicenseManager:
|
|
"""Klasse zur Verwaltung von Softwarelizenzen."""
|
|
|
|
CONFIG_FILE = os.path.join("config", "license.json")
|
|
|
|
def __init__(self):
|
|
"""Initialisiert den LicenseManager und lädt die Konfiguration."""
|
|
# API Client und andere Komponenten initialisieren
|
|
self.api_client = LicenseAPIClient()
|
|
self.hardware_fingerprint = HardwareFingerprint()
|
|
self.session_manager = SessionManager(self.api_client)
|
|
|
|
self.license_data = self.load_license_data()
|
|
self.machine_id = self.hardware_fingerprint.get_machine_name()
|
|
self.hardware_hash = self.hardware_fingerprint.get_or_create_fingerprint()
|
|
|
|
# Stelle sicher, dass das Konfigurationsverzeichnis existiert
|
|
os.makedirs(os.path.dirname(self.CONFIG_FILE), exist_ok=True)
|
|
|
|
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_id": None,
|
|
"activation_date": "",
|
|
"expiry_date": "",
|
|
"status": "inactive",
|
|
"status_text": "Keine Lizenz aktiviert",
|
|
"features": [],
|
|
"last_online_check": "",
|
|
"max_activations": 0,
|
|
"max_users": 0
|
|
}
|
|
|
|
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_id": None,
|
|
"activation_date": "",
|
|
"expiry_date": "",
|
|
"status": "inactive",
|
|
"status_text": "Fehler beim Laden der Lizenz",
|
|
"features": [],
|
|
"last_online_check": "",
|
|
"max_activations": 0,
|
|
"max_users": 0
|
|
}
|
|
|
|
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 clear_license_data(self) -> None:
|
|
"""Löscht alle Lizenzdaten und setzt auf Standardwerte zurück."""
|
|
self.license_data = {
|
|
"key": "",
|
|
"activation_id": None,
|
|
"activation_date": "",
|
|
"expiry_date": "",
|
|
"status": "inactive",
|
|
"status_text": "Keine Lizenz aktiviert",
|
|
"features": [],
|
|
"last_online_check": "",
|
|
"max_activations": 0,
|
|
"max_users": 0
|
|
}
|
|
self.save_license_data()
|
|
|
|
# Session beenden
|
|
if self.session_manager.is_session_active():
|
|
self.session_manager.end_session()
|
|
|
|
def get_license_info(self) -> Dict[str, Any]:
|
|
"""Gibt die aktuellen Lizenzdaten zurück."""
|
|
return self.license_data
|
|
|
|
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}")
|
|
|
|
return True
|
|
|
|
def online_verification(self) -> bool:
|
|
"""
|
|
Führt eine Online-Verifizierung der Lizenz durch.
|
|
|
|
Returns:
|
|
True, wenn die Online-Verifizierung erfolgreich war, sonst False
|
|
"""
|
|
if not self.license_data.get("activation_id"):
|
|
logger.warning("Keine Aktivierungs-ID vorhanden")
|
|
return False
|
|
|
|
logger.info("Führe Online-Verifizierung durch...")
|
|
|
|
try:
|
|
# API Call für Verifizierung
|
|
result = self.api_client.verify_license(
|
|
license_key=self.license_data["key"],
|
|
hardware_hash=self.hardware_hash,
|
|
machine_id=self.machine_id,
|
|
activation_id=self.license_data["activation_id"],
|
|
app_version="1.0.0"
|
|
)
|
|
|
|
if result.get("success"):
|
|
data = result.get("data", {})
|
|
|
|
# Update license data
|
|
if data.get("valid"):
|
|
self.license_data["last_online_check"] = datetime.now().isoformat()
|
|
self.license_data["status"] = "active"
|
|
self.license_data["status_text"] = "Lizenz aktiv"
|
|
|
|
# Update expiry date if provided
|
|
license_info = data.get("license", {})
|
|
if license_info.get("valid_until"):
|
|
self.license_data["expiry_date"] = license_info["valid_until"]
|
|
|
|
self.save_license_data()
|
|
logger.info("Online-Verifizierung erfolgreich")
|
|
return True
|
|
else:
|
|
logger.warning("Lizenz ist nicht mehr gültig")
|
|
self.license_data["status"] = "invalid"
|
|
self.license_data["status_text"] = data.get("message", "Lizenz ungültig")
|
|
self.save_license_data()
|
|
return False
|
|
else:
|
|
logger.error(f"Online-Verifizierung fehlgeschlagen: {result.get('error')}")
|
|
return False
|
|
|
|
except Exception as e:
|
|
logger.error(f"Fehler bei der Online-Verifizierung: {e}")
|
|
return False
|
|
|
|
def activate_license(self, license_key: str) -> Dict[str, Any]:
|
|
"""
|
|
Aktiviert eine Lizenz mit dem angegebenen Schlüssel.
|
|
|
|
Args:
|
|
license_key: Zu aktivierender Lizenzschlüssel
|
|
|
|
Returns:
|
|
Dictionary mit Erfolg und Nachricht
|
|
"""
|
|
if not license_key:
|
|
return {
|
|
"success": False,
|
|
"error": "Bitte geben Sie einen Lizenzschlüssel ein."
|
|
}
|
|
|
|
logger.info(f"Aktiviere Lizenz: {license_key[:4]}...")
|
|
|
|
try:
|
|
# API Call für Aktivierung
|
|
result = self.api_client.activate_license(
|
|
license_key=license_key,
|
|
hardware_hash=self.hardware_hash,
|
|
machine_name=self.machine_id,
|
|
app_version="1.0.0"
|
|
)
|
|
|
|
if result.get("success"):
|
|
data = result.get("data", {})
|
|
activation = data.get("activation", {})
|
|
|
|
# Speichere Lizenzdaten
|
|
self.license_data["key"] = license_key
|
|
self.license_data["activation_id"] = activation.get("id")
|
|
self.license_data["activation_date"] = activation.get("activated_at", datetime.now().isoformat())
|
|
self.license_data["status"] = "active"
|
|
self.license_data["status_text"] = "Lizenz erfolgreich aktiviert"
|
|
self.license_data["last_online_check"] = datetime.now().isoformat()
|
|
|
|
# Hole zusätzliche Lizenzinfos
|
|
info_result = self.api_client.get_license_info(license_key)
|
|
if info_result.get("success"):
|
|
license_info = info_result.get("data", {}).get("license", {})
|
|
self.license_data["expiry_date"] = license_info.get("valid_until", "")
|
|
self.license_data["max_activations"] = license_info.get("max_activations", 0)
|
|
self.license_data["max_users"] = license_info.get("max_users", 0)
|
|
self.license_data["features"] = self._extract_features(license_info)
|
|
|
|
self.save_license_data()
|
|
|
|
# Starte Session
|
|
session_result = self.session_manager.start_session(
|
|
license_key=license_key,
|
|
activation_id=self.license_data["activation_id"]
|
|
)
|
|
|
|
if not session_result.get("success"):
|
|
logger.warning(f"Session konnte nicht gestartet werden: {session_result.get('error')}")
|
|
|
|
logger.info("Lizenz erfolgreich aktiviert")
|
|
|
|
return {
|
|
"success": True,
|
|
"message": "Lizenz erfolgreich aktiviert",
|
|
"update_available": session_result.get("update_info", {}).get("available", False),
|
|
"latest_version": session_result.get("update_info", {}).get("version")
|
|
}
|
|
|
|
else:
|
|
error = result.get("error", "Unbekannter Fehler")
|
|
status = result.get("status", 0)
|
|
|
|
# Spezifische Fehlermeldungen
|
|
if status == 404:
|
|
error = "Lizenzschlüssel nicht gefunden"
|
|
elif status == 409:
|
|
error = "Lizenz ist bereits auf einem anderen System aktiviert"
|
|
elif status == 422:
|
|
error = "Ungültiges Lizenzformat"
|
|
elif status == 403:
|
|
error = "Lizenz ist deaktiviert oder abgelaufen"
|
|
|
|
logger.error(f"Lizenzaktivierung fehlgeschlagen: {error}")
|
|
|
|
return {
|
|
"success": False,
|
|
"error": error
|
|
}
|
|
|
|
except Exception as e:
|
|
logger.error(f"Fehler bei der Lizenzaktivierung: {e}")
|
|
return {
|
|
"success": False,
|
|
"error": f"Fehler bei der Aktivierung: {str(e)}"
|
|
}
|
|
|
|
def deactivate_license(self) -> Dict[str, Any]:
|
|
"""
|
|
Deaktiviert die aktuelle Lizenz.
|
|
|
|
Returns:
|
|
Dictionary mit Erfolg und Nachricht
|
|
"""
|
|
if not self.is_licensed():
|
|
return {
|
|
"success": False,
|
|
"error": "Keine aktive Lizenz vorhanden"
|
|
}
|
|
|
|
logger.info("Deaktiviere Lizenz...")
|
|
|
|
# Session beenden
|
|
if self.session_manager.is_session_active():
|
|
self.session_manager.end_session()
|
|
|
|
# TODO: API Call für Deaktivierung wenn implementiert
|
|
|
|
# Lokale Daten löschen
|
|
self.clear_license_data()
|
|
|
|
logger.info("Lizenz deaktiviert")
|
|
|
|
return {
|
|
"success": True,
|
|
"message": "Lizenz erfolgreich deaktiviert"
|
|
}
|
|
|
|
def start_session(self) -> bool:
|
|
"""
|
|
Startet eine Session für die aktuelle Lizenz.
|
|
|
|
Returns:
|
|
True wenn erfolgreich, False sonst
|
|
"""
|
|
if not self.is_licensed():
|
|
logger.warning("Keine gültige Lizenz für Session-Start")
|
|
return False
|
|
|
|
result = self.session_manager.start_session(
|
|
license_key=self.license_data["key"],
|
|
activation_id=self.license_data.get("activation_id")
|
|
)
|
|
|
|
return result.get("success", False)
|
|
|
|
def resume_session(self) -> bool:
|
|
"""
|
|
Versucht eine gespeicherte Session fortzusetzen.
|
|
|
|
Returns:
|
|
True wenn erfolgreich, False sonst
|
|
"""
|
|
return self.session_manager.resume_session()
|
|
|
|
def has_feature(self, feature: str) -> bool:
|
|
"""
|
|
Prüft, ob ein Feature in der Lizenz enthalten ist.
|
|
|
|
Args:
|
|
feature: Name des Features
|
|
|
|
Returns:
|
|
True, wenn das Feature verfügbar ist, sonst False
|
|
"""
|
|
if not self.is_licensed():
|
|
return False
|
|
|
|
# "all" bedeutet alle Features verfügbar
|
|
if "all" in self.license_data.get("features", []):
|
|
return True
|
|
|
|
return feature in self.license_data.get("features", [])
|
|
|
|
def _extract_features(self, license_info: Dict[str, Any]) -> List[str]:
|
|
"""
|
|
Extrahiert Features basierend auf dem Lizenztyp.
|
|
|
|
Args:
|
|
license_info: Lizenzinformationen vom Server
|
|
|
|
Returns:
|
|
Liste der verfügbaren Features
|
|
"""
|
|
license_type = license_info.get("type", "basic")
|
|
|
|
# Feature-Mapping basierend auf Lizenztyp
|
|
feature_map = {
|
|
"basic": ["account_creation", "basic_export"],
|
|
"premium": ["account_creation", "basic_export", "multi_account",
|
|
"proxy_rotation", "advanced_export"],
|
|
"enterprise": ["all"]
|
|
}
|
|
|
|
return feature_map.get(license_type, ["account_creation"])
|
|
|
|
def get_status_text(self) -> str:
|
|
"""
|
|
Gibt einen lesbaren Status-Text zurück.
|
|
|
|
Returns:
|
|
Status-Text
|
|
"""
|
|
status = self.license_data.get("status", "inactive")
|
|
|
|
if status == "active":
|
|
if self.license_data.get("expiry_date"):
|
|
try:
|
|
expiry = datetime.fromisoformat(self.license_data["expiry_date"])
|
|
days_left = (expiry - datetime.now()).days
|
|
|
|
if days_left > 0:
|
|
return f"Aktiv (noch {days_left} Tage)"
|
|
else:
|
|
return "Abgelaufen"
|
|
except:
|
|
pass
|
|
return "Aktiv (unbegrenzt)"
|
|
|
|
elif status == "trial":
|
|
if self.license_data.get("expiry_date"):
|
|
try:
|
|
expiry = datetime.fromisoformat(self.license_data["expiry_date"])
|
|
days_left = (expiry - datetime.now()).days
|
|
|
|
if days_left > 0:
|
|
return f"Testversion (noch {days_left} Tage)"
|
|
else:
|
|
return "Testversion abgelaufen"
|
|
except:
|
|
pass
|
|
return "Testversion"
|
|
|
|
return self.license_data.get("status_text", "Keine Lizenz aktiviert")
|
|
|
|
|
|
# Test-Funktion
|
|
if __name__ == "__main__":
|
|
logging.basicConfig(
|
|
level=logging.DEBUG,
|
|
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
|
|
)
|
|
|
|
print("=== License Manager Test ===\n")
|
|
|
|
# License Manager erstellen
|
|
license_mgr = LicenseManager()
|
|
|
|
# Lizenz-Info anzeigen
|
|
print("Aktuelle Lizenz-Info:")
|
|
info = license_mgr.get_license_info()
|
|
print(f" Status: {info.get('status')}")
|
|
print(f" Status-Text: {license_mgr.get_status_text()}")
|
|
print(f" Lizenzschlüssel: {info.get('key', 'Keine')}")
|
|
print(f" Aktivierungs-ID: {info.get('activation_id', 'Keine')}")
|
|
|
|
# Session-Status
|
|
print(f"\nSession aktiv: {license_mgr.session_manager.is_session_active()}")
|
|
|
|
print("\n=== Test abgeschlossen ===") |