diff --git a/app/rdp_proxy/ws_tunnel.py b/app/rdp_proxy/ws_tunnel.py index fcc60fa..1056dce 100644 --- a/app/rdp_proxy/ws_tunnel.py +++ b/app/rdp_proxy/ws_tunnel.py @@ -419,6 +419,20 @@ async def rdp_tunnel( host, password.decode(), session_id=session_id, username=cred_row[1], domain=cred_row[2], client_name=f"jumphost-{user.username}", timezone=safe_timezone, ) + if host.get("file_transfer_enabled"): + # Bug-Fix (Live-Test, RDP-Teilstrecke, 2.9.): guacd/FreeRDPs + # "create-drive-path" legt nur das BLATT-Verzeichnis an, keine + # fehlenden Elternverzeichnisse (kein "mkdir -p"). Bisher wurde + # ausschliesslich data_dir/recordings_dir beim Start angelegt + # (siehe app/db.py) -- das Elternverzeichnis .../rdp-drives// + # existierte fuer einen frischen Host nie, wodurch guacd mit + # "Unable to create directory ... No such file or directory" + # abbrach. Deshalb hier explizit VOR dem Tunnelaufbau mit + # parents=True anlegen (blockierendes Datei-I/O -> Thread, wie + # bei _cleanup_rdp_drive_path()). + await asyncio.to_thread( + rdp_drive_path(host_id, session_id).mkdir, parents=True, exist_ok=True + ) tunnel = await open_tunnel( guacd_host=settings.guacd_host, guacd_port=settings.guacd_port, protocol="rdp", params=params, screen_width=width, screen_height=height, dpi=dpi, diff --git a/static/js/admin.js b/static/js/admin.js index d36d3a1..0d2ed8b 100644 --- a/static/js/admin.js +++ b/static/js/admin.js @@ -1325,16 +1325,19 @@ }); const fitAddon = new FitAddon.FitAddon(); term.loadAddon(fitAddon); + term.open(container); // Bug-Fix (Live-Test, F.6/Aufgabe#11, siehe terminal.js _setupTerminal() // fuer die ausfuehrliche Begruendung): DOM-Renderer-Faerbung wird durch // die strikte CSP (style-src 'self') stillschweigend verworfen. Canvas- // Renderer zeichnet stattdessen direkt auf und ist CSP-unabhaengig. + // Muss NACH term.open() geladen werden -- vorher hat der Container noch + // keine echten Masse, das wird dann zu klein angelegt (Live-Test + // am 2.9. gefunden: sah wie eine haengende Markierung aus). try { term.loadAddon(new CanvasAddon.CanvasAddon()); } catch (err) { console.warn("CanvasAddon konnte nicht geladen werden, Fallback auf DOM-Renderer:", err); } - term.open(container); fitAddon.fit(); const proto = window.location.protocol === "https:" ? "wss:" : "ws:"; @@ -1436,16 +1439,19 @@ }); const fitAddon = new FitAddon.FitAddon(); term.loadAddon(fitAddon); + term.open(container); // Bug-Fix (Live-Test, F.6/Aufgabe#11, siehe terminal.js _setupTerminal() // fuer die ausfuehrliche Begruendung): DOM-Renderer-Faerbung wird durch // die strikte CSP (style-src 'self') stillschweigend verworfen. Canvas- // Renderer zeichnet stattdessen direkt auf und ist CSP-unabhaengig. + // Muss NACH term.open() geladen werden -- vorher hat der Container noch + // keine echten Masse, das wird dann zu klein angelegt (Live-Test + // am 2.9. gefunden: sah wie eine haengende Markierung aus). try { term.loadAddon(new CanvasAddon.CanvasAddon()); } catch (err) { console.warn("CanvasAddon konnte nicht geladen werden, Fallback auf DOM-Renderer:", err); } - term.open(container); fitAddon.fit(); const playBtn = document.getElementById("rec-playpause-btn"); diff --git a/static/js/terminal.js b/static/js/terminal.js index 7f18a8f..ac8f3cc 100644 --- a/static/js/terminal.js +++ b/static/js/terminal.js @@ -299,6 +299,7 @@ }); this.fitAddon = new FitAddon.FitAddon(); this.term.loadAddon(this.fitAddon); + this.term.open(this.terminalContainer); // Bug-Fix (Live-Test, F.6/Aufgabe#11): xterm.js' Standard-DOM-Renderer // faerbt Zellen (inkl. Markierungs-Hintergrund) teils per dynamisch // erzeugtem