""" 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 ===")