diff --git a/main.py b/main.py index a03e753..5973f89 100644 --- a/main.py +++ b/main.py @@ -178,7 +178,7 @@ async def get_remote_info(ip, user): """Versucht Linux/Mac-Infos zu lesen, falls fehlgeschlagen, dann Windows.""" # 1. Versuch: Linux/Mac linux_cmd = "uname -m && (sw_vers -productName 2>/dev/null || grep PRETTY_NAME /etc/os-release 2>/dev/null | cut -d= -f2 || uname -s) && (command -v docker >/dev/null 2>&1 && echo 1 || echo 0)" - ssh_cmd = f"ssh -o StrictHostKeyChecking=no -o ConnectTimeout=3 {user}@{ip} \"{linux_cmd}\"" + ssh_cmd = f"ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o ConnectTimeout=3 {user}@{ip} \"{linux_cmd}\"" try: output = subprocess.check_output(ssh_cmd, shell=True, stderr=subprocess.DEVNULL).decode().strip().split('\n') @@ -194,7 +194,7 @@ async def get_remote_info(ip, user): # 2. Versuch: Windows (CMD) # ver = OS Version, echo %PROCESSOR_ARCHITECTURE% = Arch, where docker = Docker Check win_cmd = 'ver && echo %PROCESSOR_ARCHITECTURE% && (where docker >nul 2>&1 && echo 1 || echo 0)' - ssh_cmd = f"ssh -o StrictHostKeyChecking=no -o ConnectTimeout=3 {user}@{ip} \"{win_cmd}\"" + ssh_cmd = f"ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o ConnectTimeout=3 {user}@{ip} \"{win_cmd}\"" try: output = subprocess.check_output(ssh_cmd, shell=True).decode().strip().split('\n') @@ -218,43 +218,36 @@ async def get_remote_info(ip, user): # --- ERWEITERTES NODE BOOTSTRAPPING (Inventur) --- async def bootstrap_node(ip, user, password): - await manager.broadcast(f"🔑 Starte Kopplung für {ip}...") + await manager.broadcast(f"🔑 Kopple {ip}...") with open(f"{SSH_KEY}.pub", "r") as f: pub_key = f.read().strip() - # Dieses PowerShell-Skript ist der "Universalschlüssel" für Windows: - # 1. Prüft ob Admin-Pfad oder User-Pfad nötig ist - # 2. Schreibt den Key - # 3. Entzieht allen anderen Usern die Rechte an der Datei (Wichtig!) - ps_script = f""" - $key = '{pub_key}'; - $isAdmin = (new-principal -id ((get-item -path "C:\\").GetAccessControl().Owner)).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator); - if ($isAdmin) {{ - $path = "$env:ProgramData\\ssh\\administrators_authorized_keys"; - }} else {{ - $path = "$HOME\\.ssh\\authorized_keys"; - if (!(Test-Path "$HOME\\.ssh")) {{ New-Item -ItemType Directory -Path "$HOME\\.ssh" }}; - }} - $key | Out-File -FilePath $path -Encoding ascii -Append; - icacls.exe $path /inheritance:r /grant "Administrators:F" /grant "SYSTEM:F" /grant "$env:USERNAME:F"; - """ + # Wir nutzen ein absolut minimalistisches Kommando. + # Es erstellt das Verzeichnis (falls nötig) und hängt den Key an. + # Das funktioniert in der Windows CMD und der Linux Bash. + cmd_universal = f'mkdir .ssh & echo {pub_key} >> .ssh/authorized_keys' - # Wir escapen das Skript für die Shell - ps_cmd = ps_script.replace('\n', ' ').strip() - setup_cmd = f"sshpass -p '{password}' ssh -o StrictHostKeyChecking=no {user}@{ip} \"powershell -Command {ps_cmd}\"" + # sshpass direkt mit dem simplen Befehl + setup_cmd = f"sshpass -p '{password}' ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null {user}@{ip} \"{cmd_universal}\"" try: - proc = subprocess.run(setup_cmd, shell=True, capture_output=True, text=True, timeout=20) + # Wir führen es aus. Das "2x Passwort"-Problem kommt oft von TTY-Anfragen. + # Wir unterdrücken das mit -o StrictHostKeyChecking=no + proc = subprocess.run(setup_cmd, shell=True, capture_output=True, text=True, timeout=15) + if proc.returncode == 0: - await manager.broadcast(f"✅ Key-Transfer & Rechtekorrektur auf {ip} erfolgreich.") + await manager.broadcast(f"✅ Key an {ip} übertragen.") else: - await manager.broadcast(f"⚠️ Kopplung evtl. unvollständig: {proc.stderr}") + # Falls 'mkdir' einen Fehler wirft (weil Ordner existiert), ist das egal, + # solange der Key danach drin ist. + await manager.broadcast(f"ℹ️ Info: {ip} antwortet (Key-Check folgt).") + except Exception as e: await manager.broadcast(f"❌ Fehler: {e}") - # Danach folgt deine Inventur (OS/Arch Check)... - await manager.broadcast(f"🔍 Inventur auf {ip} wird durchgeführt...") + # Inventur (get_remote_info) prüft jetzt, ob es wirklich klappt + await manager.broadcast(f"🔍 Teste schlüssellosen Zugriff auf {ip}...") info = await get_remote_info(ip, user) if info: @@ -470,7 +463,7 @@ async def chat_endpoint(websocket: WebSocket): async def run_remote_task(ip, user, cmd): await manager.broadcast(f"🚀 Task: {cmd} auf {ip}") - proc = await asyncio.create_subprocess_shell(f"ssh -o StrictHostKeyChecking=no {user}@{ip} '{cmd}'", stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.STDOUT) + proc = await asyncio.create_subprocess_shell(f"ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null {user}@{ip} '{cmd}'", stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.STDOUT) full_output = "" while True: line = await proc.stdout.readline()