diff --git a/main.py b/main.py index 673fed3..a03e753 100644 --- a/main.py +++ b/main.py @@ -220,32 +220,38 @@ async def get_remote_info(ip, user): async def bootstrap_node(ip, user, password): await manager.broadcast(f"🔑 Starte Kopplung für {ip}...") - # Pfad zum lokalen Public Key with open(f"{SSH_KEY}.pub", "r") as f: pub_key = f.read().strip() - # Strategie: Wir versuchen den Key per PowerShell zu setzen (funktioniert bei Win & Linux/Mac oft universeller) - # Dieser Befehl erstellt das Verzeichnis, die Datei und setzt den Key – alles in einer Zeile. - powershell_fix = ( - f'if (!(Test-Path ~\\.ssh)) {{ New-Item -ItemType Directory -Path ~\\.ssh }}; ' - f'Add-Content -Path ~\\.ssh\\authorized_keys -Value "{pub_key}"' - ) + # 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 sshpass, um den Befehl einmalig mit Passwort abzuschicken - setup_cmd = f"sshpass -p '{password}' ssh -o StrictHostKeyChecking=no {user}@{ip} 'powershell -Command \"{powershell_fix}\" || (mkdir -p ~/.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}\"" try: - # Wir führen das Setup aus - proc = subprocess.run(setup_cmd, shell=True, capture_output=True, text=True, timeout=15) - - if proc.returncode != 0: - await manager.broadcast(f"⚠️ Erster Kopplungsversuch für {ip} mit Warnung: {proc.stderr[:50]}...") + proc = subprocess.run(setup_cmd, shell=True, capture_output=True, text=True, timeout=20) + if proc.returncode == 0: + await manager.broadcast(f"✅ Key-Transfer & Rechtekorrektur auf {ip} erfolgreich.") else: - await manager.broadcast(f"✅ Key-Transfer zu {ip} abgeschlossen.") - - except subprocess.TimeoutExpired: - await manager.broadcast(f"❌ Timeout bei Kopplung mit {ip}. Rechner erreichbar?") - return + await manager.broadcast(f"⚠️ Kopplung evtl. unvollständig: {proc.stderr}") + 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...") @@ -391,8 +397,11 @@ async def terminal_websocket(websocket: WebSocket, ip: str): master_fd, slave_fd = pty.openpty() # Wir starten SSH im interaktiven Modus proc = await asyncio.create_subprocess_exec( - "ssh", "-o", "StrictHostKeyChecking=no", "-t", - f"{node['user']}@{ip}", + "ssh", + "-i", SSH_KEY, # <--- Das hier ist entscheidend! + "-o", "StrictHostKeyChecking=no", + "-o", "BatchMode=yes", # Verhindert, dass SSH hängen bleibt, falls der Key doch nicht geht + "-t", f"{node['user']}@{ip}", stdin=slave_fd, stdout=slave_fd, stderr=slave_fd )