9.8 KiB
Fortsetzungsdokument: Aufgabe #11 (SSH Copy-Paste + Terminal-Farben)
Stand: 2026-09-02, Code-Stand abgeschlossen und regressionsfrei verifiziert;
Live-Browser-Test weiterhin ausstehend (siehe Abschnitt 3 + Nachtrag in
Abschnitt 4 -- dieselbe Einschraenkung wie bei Teil F).
Repo: ssh_jumphost, erreichbar ueber die device_bash-Bridge unter
$HOME/mnt/ssh_jumphost.
Einordnung: Aufgabe #11 ist vom Nutzer nachtraeglich hinzugefuegt worden,
nicht Teil von Umsetzungsauftrag_Sonnet5.md und hatte bis zu dieser Session
keine Detail-Spec -- nur das Stichwort "SSH Copy-Paste + Terminal-Farben"
(siehe FORTSETZUNG_Teil_C.md/_D.md/_F.md). Das Scope wurde zu Beginn
dieser Session per Rueckfrage geklaert (zwei AskUserQuestion-Antworten):
- Copy-Paste: "kopieren mit markieren des textes und einfuegen mit rechtsklick, wenn es umsetzbar ist sonst mit Rechtsklickkontextmenu."
- Terminal-Farben: "Vom Benutzer waehlbar."
Beides betrifft ausschliesslich SSH (static/js/terminal.js,
SshTerminalSession) -- RDP hat ueber Guacamole bereits eine eigene,
funktionierende Zwischenablage-Anbindung (onclipboard in rdp.js) und war
nie Teil der Aufgabe (Titel: "SSH Copy-Paste").
1) SSH Copy-Paste
- Kopieren:
copyOnSelect: truebei derTerminal-Konstruktion (_setupTerminal()). xterm.js kopiert eine Markierung damit sofort in die System-Zwischenablage -- kein Strg+C/Cmd+C mehr noetig. Strg+C OHNE Markierung bleibt unveraendert SIGINT (xterm.js' Standardverhalten, voncopyOnSelectnicht beruehrt -- kein neues Verhalten, keine Ueberraschung fuer bestehende Nutzung). - Einfuegen per Rechtsklick, zweistufig, genau wie gewuenscht:
contextmenu-Listener aufthis.terminalContainer(_wireClipboard()) ruftevent.preventDefault()auf (unterdrueckt das native Browser-Kontextmenue) und versucht direktnavigator.clipboard.readText()(_attemptDirectPaste()). In den meisten Chromium-Browsern reicht ein Rechtsklick als "transiente Aktivierung" fuer diese Berechtigung -- Einfuegen passiert dann sofort, ohne sichtbares Menue.- Schlaegt das fehl (kein
navigator.clipboard, Berechtigung verweigert -- typischerweise Firefox/Safari ausserhalb einer frischen Klick-Geste, oder unsicherer Kontext), erscheint ersatzweise ein winziges Kontextmenue mit einem "Einfuegen"-Eintrag (_showPasteMenu()). Dessen Klick ist selbst wieder eine frische Benutzergeste und hat dadurch nochmal bessere Chancen auf die Berechtigung. Schlaegt auch das fehl, zeigt der Status-Bereich der Sitzung einen erklaerenden Hinweis ("... bitte Strg+Umschalt+V verwenden") statt eines stillen No-Ops. - Das eigentliche Einfuegen laeuft ueber
this.term.paste(text)(xterm.js v5 API, bestaetigt durch.paste=-Vorkommen invendor/xterm.js) -- das ist KEIN separater Codepfad zum normalen Tippen:paste()loest intern denselbenonData-Callback aus wie eine Tastatureingabe, geht also automatisch durch die bestehende WS-"input"-Sendefunktion.
- CSP-Falle vermieden: der erste Entwurf positionierte das
Ruecksicherungs-Kontextmenue ueber
menu.style.left/topan der Klickposition -- das haette der Server-CSP (style-src 'self', keinunsafe-inline) im echten Browser stillschweigend blockiert (dieselbe Regel, die JS-gesetzteelement.style-Aenderungen genauso trifft wiestyle="..."-Attribute, siehe app.css-Kopfkommentar zu.hidden). Ersetzt durch vier feste CSS-Klassen (.term-paste-menu-{top,bottom}x{left,right}, app.css), die je nach Klick-Viertel von.session-shellgesetzt werden -- keine Pixelgenauigkeit, aber vollstaendig CSP-konform und konsistent mit der einzigen im ganzen Projekt verwendeten Sichtbarkeits-/Positionierungstechnik (Klassen, nie.style). - Aufraeumen:
_closePasteMenu()entfernt das Menue plus seine Dokument-Listener (Klick-daneben/Escape/Scroll) -- aufgerufen ausdispose()UND aussetActive(false)(ein Umschalten auf eine andere Sitzung soll kein Geister-Kontextmenue im Hintergrund hinterlassen).
2) Terminal-Farben (vom Benutzer waehlbar)
- Vier feste Farbschemata (
TERMINAL_THEMES, Modul-Konstante): Standard (dunkel, bisheriges Verhalten unveraendert als Vorgabe), Dunkel/kontrastreich, Solarized Dark, Solarized Light. Bewusst eine kleine feste Auswahl statt eines vollen Theme-Editors -- deckt "vom Benutzer waehlbar" ab, ohne eine neue Einstellungsseite einzufuehren. <select class="theme-select">in der Sitzungs-Toolbar (zwischen "Dateitransfer" und dem Status-Text). Aenderung setztthis.term.options.theme = ...(xterm.js v5:optionsist ein Getter/Setter-Objekt, bestaetigt durchOptionsService/onOptionChangeinvendor/xterm.js-- keinsetOption()mehr, das gab es nur bis v4).- Persistenz:
localStorage(Schluesseljumphost_terminal_theme"), rein clientseitig, kein Server-Roundtrip -- konsistent mit der ueblichen Behandlung reiner Darstellungspraeferenzen. Bewusst KEIN neues DB-Feld/ keine neue Migration: die Wahl ist eine Eigenschaft des Browsers/Nutzers vor Ort, keine sicherheits- oder audit-relevante Einstellung. Try/catch um jeden Zugriff (privater Modus/blockierter Speicher faellt dann einfach auf das Standardschema zurueck, kein Fehler). - Scope-Grenze, bewusst so belassen: die Wahl gilt fuer NEUE
Sitzungen ab dem Zeitpunkt der Aenderung (liest
localStoragebeim Sitzungsaufbau in_setupTerminal()) -- sie synchronisiert sich NICHT live in andere, gerade schon offene Sitzungen (F4: mehrere gleichzeitige Instanzen moeglich). Dieselbe Klasse von Eventual-Consistency wie an mehreren anderen Stellen im Projekt bereits akzeptiert (z.B. keine Live-Aktualisierung der Sitzungsliste zwischen Tabs,FORTSETZUNG_Teil_F.md). Ein Wechsel-Knopf in jeder einzelnen Toolbar ist bewusst so belassen statt einer neuen globalen Einstellungsseite -- kein Mehrwert gegenueber "einmal in einer beliebigen Sitzung waehlen, gilt danach ueberall".
3) Verifikation
-
node --check static/js/terminal.js-- fehlerfrei. -
CSS-Klammerbalance (
{/}) inapp.cssgeprueft -- ausgeglichen. -
Voller Regressionslauf ueber alle 23 Testdateien (unveraendert gegenueber Teil-F-Stufe F5 -- diese Aufgabe aendert ausschliesslich
static/js/terminal.jsundstatic/css/app.css, keine Python-Datei, keine Migration, kein Template):Gruppe Ergebnis csp_compliance/teil_f_schritt2/teil_f_schritt3/teil_f_schritt5 22 passed, 0 failed admin_crud/admin_groups_tokens/audit_chain/auth_flow/phase9 36 passed, 1 failed passwords_totp/pentest_security/phase10/phase11 37 passed, 2 failed phase12/phase13 22 passed, 6 failed phase14/phase15/rbac/teil_d_schritt5/teil_d_schritt6/session_recorder/session_reaper 29 passed, 9 failed Summe 146 passed, 18 failed, 164 total Identisch zu Teil F Stufe F5 -- dieselben 18 laengst bekannten, dokumentierten Fehlschlaege (
FORTSETZUNG_Teil_C.md), null neue Regressionen. -
Kein Live-Browser-Test moeglich (dieselbe Sandbox-Einschraenkung wie bei Teil F, siehe
FORTSETZUNG_Teil_F.mdAbschnitt 6): weder das direkte Rechtsklick-Einfuegen (haengt vom tatsaechlichen Berechtigungsverhalten des jeweiligen Browsers ab, nicht vollstaendig durch Code-Lesen verifizierbar) noch das Ruecksicherungs-Kontextmenue noch die visuelle Wirkung der vier Farbschemata wurden tatsaechlich im Browser durchgeklickt. Empfehlung: bei Gelegenheit einmal in einem echten Chromium- UND einem echten Firefox-Fenster gegenstesten (Chromium deckt den Direktpfad ab, Firefox eher den Menue-Fallback) -- am besten zusammen mit dem noch ausstehenden F.6-Live-Test aus Teil F, da beide dieselbe echte SSH-Zielumgebung brauchen.
4) Nachtrag: Rueckfrage zum urspruenglichen Symptom
Bei der Klaerung des Scopes (Abschnitt oben) kam in einer spaeteren Rueckfrage eine praezisere Beschreibung des urspruenglichen Problems: "Ich konnte in der SSH-Sitzung nichts mit der linken Maustaste markieren" -- und zwar an einem GANZ NORMALEN Shell-Prompt, nicht in einem Vollbild-Programm mit eigener Maussteuerung (tmux/vim/htop/...). Das schliesst die naheliegendste Erklaerung ("Mausklicks gehen an ein Programm wie tmux, nicht an die lokale Markierung -- kein Bug, Standardverhalten jedes Terminals") fuer DIESEN konkreten Fall aus.
Wahrscheinlichste Erklaerung (kein Live-Test moeglich, daher nicht
absicherbar): xterm.js unterstuetzt Markieren-per-Ziehen schon immer nativ,
unabhaengig von copyOnSelect -- das war also vermutlich nie kaputt. Ohne
copyOnSelect (Zustand VOR dieser Session) landet eine Markierung aber
NICHT automatisch in der Zwischenablage; der naheliegende Reflex Strg+C
loest bei xterm.js ohne Markierung SIGINT aus (unveraendertes
Standardverhalten) -- aus Nutzersicht sieht das exakt so aus wie "Markieren
geht nicht", obwohl technisch nur der Kopiervorgang danach fehlte. Genau das
behebt copyOnSelect: true (Abschnitt 1 oben): Ziehen MARKIERT UND kopiert
in einem Schritt, ganz ohne Strg+C.
Zusaetzlich ergaenzt, unabhaengig vom obigen Verdacht: ein
title-Tooltip auf .session-terminal erklaert das (bereits vorher
bestehende, unveraenderte) Shift+Ziehen-Verhalten fuer den Fall, dass doch
einmal ein Vollbild-Programm mit eigener Maussteuerung im Spiel ist -- rein
zusaetzliche Dokumentation direkt in der Oberflaeche, kein neuer Codepfad,
kein Risiko fuer bestehendes Verhalten.
Weiterhin nicht abschliessend geklaert ohne Live-Test: ob
copyOnSelect: true das urspruenglich beschriebene Symptom tatsaechlich
vollstaendig behebt, kann nur der Nutzer selbst durch Ausprobieren
bestaetigen (Text im Terminal markieren, dann an anderer Stelle einfuegen --
sollte jetzt ohne Strg+C funktionieren). Sollte es weiterhin nicht gehen,
ist das ein Hinweis auf eine andere, noch nicht gefundene Ursache und
braucht eine zweite Runde.