umbau 1.0

This commit is contained in:
2026-09-02 20:30:44 +02:00
parent afe6719f51
commit 5c95b21be7
77 changed files with 10733 additions and 1914 deletions

169
FORTSETZUNG_Aufgabe11.md Normal file
View File

@ -0,0 +1,169 @@
# 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):
1. **Copy-Paste**: "kopieren mit markieren des textes und einfuegen mit
rechtsklick, wenn es umsetzbar ist sonst mit Rechtsklickkontextmenu."
2. **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: true` bei der `Terminal`-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, von
`copyOnSelect` nicht beruehrt -- kein neues Verhalten, keine Ueberraschung
fuer bestehende Nutzung).
* **Einfuegen per Rechtsklick**, zweistufig, genau wie gewuenscht:
1. `contextmenu`-Listener auf `this.terminalContainer`
(`_wireClipboard()`) ruft `event.preventDefault()` auf (unterdrueckt
das native Browser-Kontextmenue) und versucht direkt
`navigator.clipboard.readText()` (`_attemptDirectPaste()`). In den
meisten Chromium-Browsern reicht ein Rechtsklick als "transiente
Aktivierung" fuer diese Berechtigung -- Einfuegen passiert dann sofort,
ohne sichtbares Menue.
2. 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.
3. Das eigentliche Einfuegen laeuft ueber `this.term.paste(text)` (xterm.js
v5 API, bestaetigt durch `.paste=`-Vorkommen in `vendor/xterm.js`) --
das ist KEIN separater Codepfad zum normalen Tippen: `paste()` loest
intern denselben `onData`-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/top` an der
Klickposition -- das haette der Server-CSP (`style-src 'self'`, kein
`unsafe-inline`) im echten Browser stillschweigend blockiert (dieselbe
Regel, die JS-gesetzte `element.style`-Aenderungen genauso trifft wie
`style="..."`-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-shell`
gesetzt 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 aus
`dispose()` UND aus `setActive(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 setzt
`this.term.options.theme = ...` (xterm.js v5: `options` ist ein
Getter/Setter-Objekt, bestaetigt durch `OptionsService`/`onOptionChange`
in `vendor/xterm.js` -- kein `setOption()` mehr, das gab es nur bis v4).
* **Persistenz**: `localStorage` (Schluessel `jumphost_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 `localStorage` beim
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 (`{`/`}`) in `app.css` geprueft -- ausgeglichen.
* Voller Regressionslauf ueber alle 23 Testdateien (unveraendert gegenueber
Teil-F-Stufe F5 -- diese Aufgabe aendert ausschliesslich
`static/js/terminal.js` und `static/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.md` Abschnitt 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.