312 Zeilen
10 KiB
Python
312 Zeilen
10 KiB
Python
"""
|
||
Hardware Fingerprint Generator fuer die Lizenzierung.
|
||
Erstellt einen eindeutigen Hardware-Hash basierend auf System-Eigenschaften.
|
||
"""
|
||
|
||
import hashlib
|
||
import platform
|
||
import socket
|
||
import uuid
|
||
import os
|
||
import subprocess
|
||
import logging
|
||
from typing import List, Optional
|
||
|
||
logger = logging.getLogger("hardware_fingerprint")
|
||
|
||
|
||
class HardwareFingerprint:
|
||
"""Generiert und verwaltet Hardware-Fingerprints f<>r die Lizenzierung."""
|
||
|
||
FINGERPRINT_FILE = os.path.join("config", ".hardware_id")
|
||
|
||
def __init__(self):
|
||
"""Initialisiert den Fingerprint-Generator."""
|
||
os.makedirs("config", exist_ok=True)
|
||
|
||
def get_mac_address(self) -> Optional[str]:
|
||
"""
|
||
Holt die MAC-Adresse der prim<69>ren Netzwerkkarte.
|
||
|
||
Returns:
|
||
MAC-Adresse als String oder None
|
||
"""
|
||
try:
|
||
# UUID-basierte MAC-Adresse (funktioniert cross-platform)
|
||
mac = ':'.join(['{:02x}'.format((uuid.getnode() >> ele) & 0xff)
|
||
for ele in range(0,8*6,8)][::-1])
|
||
if mac != "00:00:00:00:00:00":
|
||
return mac
|
||
except Exception as e:
|
||
logger.warning(f"Fehler beim Abrufen der MAC-Adresse: {e}")
|
||
return None
|
||
|
||
def get_cpu_info(self) -> str:
|
||
"""
|
||
Holt CPU-Informationen.
|
||
|
||
Returns:
|
||
CPU-Info als String
|
||
"""
|
||
try:
|
||
# Platform-unabh<62>ngige CPU-Info
|
||
cpu_info = platform.processor()
|
||
if not cpu_info:
|
||
cpu_info = platform.machine()
|
||
return cpu_info or "unknown"
|
||
except Exception as e:
|
||
logger.warning(f"Fehler beim Abrufen der CPU-Info: {e}")
|
||
return "unknown"
|
||
|
||
def get_system_uuid(self) -> Optional[str]:
|
||
"""
|
||
Versucht die System-UUID zu ermitteln.
|
||
|
||
Returns:
|
||
System-UUID als String oder None
|
||
"""
|
||
try:
|
||
# Windows
|
||
if platform.system() == "Windows":
|
||
try:
|
||
output = subprocess.check_output(
|
||
"wmic csproduct get UUID",
|
||
shell=True,
|
||
stderr=subprocess.DEVNULL
|
||
).decode()
|
||
lines = output.strip().split('\n')
|
||
if len(lines) > 1:
|
||
uuid_str = lines[1].strip()
|
||
if uuid_str and uuid_str != "FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF":
|
||
return uuid_str
|
||
except:
|
||
pass
|
||
|
||
# Linux
|
||
elif platform.system() == "Linux":
|
||
try:
|
||
with open("/sys/class/dmi/id/product_uuid", "r") as f:
|
||
uuid_str = f.read().strip()
|
||
if uuid_str:
|
||
return uuid_str
|
||
except:
|
||
pass
|
||
|
||
# Alternative f<>r Linux
|
||
try:
|
||
with open("/etc/machine-id", "r") as f:
|
||
return f.read().strip()
|
||
except:
|
||
pass
|
||
|
||
# macOS
|
||
elif platform.system() == "Darwin":
|
||
try:
|
||
output = subprocess.check_output(
|
||
["ioreg", "-rd1", "-c", "IOPlatformExpertDevice"],
|
||
stderr=subprocess.DEVNULL
|
||
).decode()
|
||
for line in output.split('\n'):
|
||
if 'IOPlatformUUID' in line:
|
||
uuid_str = line.split('"')[-2]
|
||
if uuid_str:
|
||
return uuid_str
|
||
except:
|
||
pass
|
||
|
||
except Exception as e:
|
||
logger.warning(f"Fehler beim Abrufen der System-UUID: {e}")
|
||
|
||
return None
|
||
|
||
def get_disk_serial(self) -> Optional[str]:
|
||
"""
|
||
Versucht die Seriennummer der Systemfestplatte zu ermitteln.
|
||
|
||
Returns:
|
||
Disk Serial als String oder None
|
||
"""
|
||
try:
|
||
if platform.system() == "Windows":
|
||
try:
|
||
output = subprocess.check_output(
|
||
"wmic diskdrive get serialnumber",
|
||
shell=True,
|
||
stderr=subprocess.DEVNULL
|
||
).decode()
|
||
lines = output.strip().split('\n')
|
||
for line in lines[1:]:
|
||
serial = line.strip()
|
||
if serial and serial != "SerialNumber":
|
||
return serial
|
||
except:
|
||
pass
|
||
|
||
elif platform.system() == "Linux":
|
||
try:
|
||
# Versuche verschiedene Methoden
|
||
for device in ["/dev/sda", "/dev/nvme0n1", "/dev/vda"]:
|
||
if os.path.exists(device):
|
||
try:
|
||
output = subprocess.check_output(
|
||
["sudo", "hdparm", "-I", device],
|
||
stderr=subprocess.DEVNULL
|
||
).decode()
|
||
for line in output.split('\n'):
|
||
if 'Serial Number:' in line:
|
||
return line.split(':')[1].strip()
|
||
except:
|
||
pass
|
||
except:
|
||
pass
|
||
|
||
except Exception as e:
|
||
logger.warning(f"Fehler beim Abrufen der Disk-Serial: {e}")
|
||
|
||
return None
|
||
|
||
def generate_hardware_hash(self) -> str:
|
||
"""
|
||
Generiert einen eindeutigen Hardware-Hash basierend auf verschiedenen
|
||
System-Eigenschaften.
|
||
|
||
Returns:
|
||
Hardware-Hash als String
|
||
"""
|
||
components = []
|
||
|
||
# 1. Hostname (immer verf<72>gbar)
|
||
hostname = socket.gethostname()
|
||
components.append(f"HOST:{hostname}")
|
||
|
||
# 2. MAC-Adresse
|
||
mac = self.get_mac_address()
|
||
if mac:
|
||
components.append(f"MAC:{mac}")
|
||
|
||
# 3. CPU-Info
|
||
cpu = self.get_cpu_info()
|
||
components.append(f"CPU:{cpu}")
|
||
|
||
# 4. System-UUID
|
||
sys_uuid = self.get_system_uuid()
|
||
if sys_uuid:
|
||
components.append(f"UUID:{sys_uuid}")
|
||
|
||
# 5. Disk Serial
|
||
disk_serial = self.get_disk_serial()
|
||
if disk_serial:
|
||
components.append(f"DISK:{disk_serial}")
|
||
|
||
# 6. Platform-Info
|
||
components.append(f"PLATFORM:{platform.system()}-{platform.machine()}")
|
||
|
||
# 7. Username (als Fallback)
|
||
try:
|
||
username = os.getlogin()
|
||
components.append(f"USER:{username}")
|
||
except:
|
||
pass
|
||
|
||
# Kombiniere alle Komponenten
|
||
fingerprint_data = "|".join(sorted(components))
|
||
|
||
# Erstelle SHA256 Hash
|
||
hash_object = hashlib.sha256(fingerprint_data.encode())
|
||
hardware_hash = hash_object.hexdigest()
|
||
|
||
logger.info(f"Hardware-Fingerprint generiert mit {len(components)} Komponenten")
|
||
logger.debug(f"Komponenten: {components}")
|
||
|
||
return hardware_hash
|
||
|
||
def get_or_create_fingerprint(self) -> str:
|
||
"""
|
||
Holt den gespeicherten Fingerprint oder erstellt einen neuen.
|
||
|
||
Returns:
|
||
Hardware-Fingerprint als String
|
||
"""
|
||
# Pr<50>fe ob bereits ein Fingerprint existiert
|
||
if os.path.exists(self.FINGERPRINT_FILE):
|
||
try:
|
||
with open(self.FINGERPRINT_FILE, 'r') as f:
|
||
stored_hash = f.read().strip()
|
||
if stored_hash:
|
||
logger.info("Gespeicherten Hardware-Fingerprint gefunden")
|
||
return stored_hash
|
||
except Exception as e:
|
||
logger.warning(f"Fehler beim Lesen des gespeicherten Fingerprints: {e}")
|
||
|
||
# Generiere neuen Fingerprint
|
||
hardware_hash = self.generate_hardware_hash()
|
||
|
||
# Speichere f<>r zuk<75>nftige Verwendung
|
||
try:
|
||
with open(self.FINGERPRINT_FILE, 'w') as f:
|
||
f.write(hardware_hash)
|
||
logger.info("Hardware-Fingerprint gespeichert")
|
||
except Exception as e:
|
||
logger.error(f"Fehler beim Speichern des Fingerprints: {e}")
|
||
|
||
return hardware_hash
|
||
|
||
def get_machine_name(self) -> str:
|
||
"""
|
||
Gibt den Maschinennamen zur<75>ck.
|
||
|
||
Returns:
|
||
Maschinenname
|
||
"""
|
||
try:
|
||
return socket.gethostname()
|
||
except:
|
||
return "Unknown-PC"
|
||
|
||
def get_system_info(self) -> dict:
|
||
"""
|
||
Sammelt detaillierte System-Informationen.
|
||
|
||
Returns:
|
||
Dictionary mit System-Infos
|
||
"""
|
||
return {
|
||
"hostname": self.get_machine_name(),
|
||
"platform": platform.system(),
|
||
"platform_release": platform.release(),
|
||
"platform_version": platform.version(),
|
||
"architecture": platform.machine(),
|
||
"processor": self.get_cpu_info(),
|
||
"python_version": platform.python_version(),
|
||
"mac_address": self.get_mac_address(),
|
||
"system_uuid": self.get_system_uuid()
|
||
}
|
||
|
||
|
||
# Test-Funktion
|
||
if __name__ == "__main__":
|
||
logging.basicConfig(
|
||
level=logging.DEBUG,
|
||
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
|
||
)
|
||
|
||
print("=== Hardware Fingerprint Test ===\n")
|
||
|
||
fingerprint = HardwareFingerprint()
|
||
|
||
# System-Info anzeigen
|
||
print("System-Informationen:")
|
||
info = fingerprint.get_system_info()
|
||
for key, value in info.items():
|
||
print(f" {key}: {value}")
|
||
|
||
# Fingerprint generieren
|
||
print("\nHardware-Fingerprint:")
|
||
hw_hash = fingerprint.get_or_create_fingerprint()
|
||
print(f" Hash: {hw_hash}")
|
||
print(f" L<>nge: {len(hw_hash)} Zeichen")
|
||
|
||
# Maschinenname
|
||
print(f"\nMaschinenname: {fingerprint.get_machine_name()}")
|
||
|
||
print("\n=== Test abgeschlossen ===") |