CH-J ToolsSerververwaltung über SSH
Menü

Speichern im Remote-Editor und Latenzüberwachung

Datei herunterladen

Dieser übersetzte Text wird sprachlich überarbeitet. Vergleichen Sie unklare Stellen mit dem englischen Original.

Ursachen

Der bisherige Editor lud seine Arbeitsdatei in das übergeordnete Verzeichnis des Ziels hoch, in das das SSH-Konto unter /etc oder /var oft nicht schreiben darf. Das Umbenennen per SFTP bot weder einen autorisierten Weg über sudo noch eine Konfliktprüfung gegen den Ausgangszustand, eine Prüfung der Sicherheitsmetadaten oder eine verlässliche Überschreib-Semantik. Seine Fehlerbehandlung löschte die temporäre Kopie und entfernte damit Wiederherstellungsmaterial selbst dann, wenn der Abschluss ungewiss war.

Der Sitzungsstatus zeigte bisher nur den Verbindungszustand. Die Terminalanzeige erhielt weder eine ICMP-Messung noch eine Messung der Antwortzeit des authentifizierten SSH.

Speicherprotokoll

  1. Ein festes SSH-Hilfsprogramm öffnet eine reguläre Datei mit genau einem Hardlink über deskriptorrelative Operationen und O_NOFOLLOW für jede Pfadkomponente. Es erfasst den Inhalt, den SHA-256-Hash, Gerät/Inode, UID, GID, alle Berechtigungsbits, die nanosekundengenauen Änderungs- und Statuszeiten sowie alle lesbaren erweiterten Attribute. Core prüft den Hash und dekodiert striktes UTF-8 unter Beibehaltung eines BOM. Jedes Dokument erhält eine undurchsichtige editId, die auf sein Plugin, seine Terminalsitzung und die Serveridentität beschränkt ist.
  2. Ein nicht privilegierter Vorbereitungsschritt ermittelt das Home-Verzeichnis des authentifizierten Kontos über pwd.getpwuid(os.getuid()), legt $HOME/ch-j-sm/ mit dem Modus 0700 an und erstellt ein privates, exklusives Wiederherstellungsjournal. Ein unsicheres Home-Verzeichnis, ein Arbeitsbereich als symbolischer Link oder ein Arbeitsbereich eines anderen Kontos wird abgelehnt.
  3. Core lädt per SFTP eine versteckte, zufällige 128-Bit-Arbeitsdatei .tmp mit exklusiver Erstellung (wx), Modus 0600 und einem sechzigsekündigen Kanal-/Upload-Zeitlimit hoch. Das Journal enthält das Ziel, den ursprünglichen Ausgangszustand und den erwarteten Hash der Arbeitskopie; es enthält keine Anmeldeinformationen.
  4. Eine einzige SSH-Ausführung (exec) erledigt den gesamten Abschluss, optional über den bestehenden sudo-Ausführer. Das Hilfsprogramm öffnet die private Arbeitskopie sicher, berechnet ihren Hash und schreibt sie auf den Datenträger. Es sperrt den ursprünglichen Inode, prüft dessen Ausgangszustand, erstellt exklusiv eine Zieldatei neben dem Ziel, schreibt den gesamten Inhalt, setzt und prüft die Metadaten, prüft das Original erneut und schreibt den Ersatz auf den Datenträger.
  5. Ein os.replace im selben Verzeichnis ersetzt das Ziel atomar. Das übergeordnete Verzeichnis wird auf den Datenträger geschrieben, und endgültiger Pfad, Hash, Inode und Metadaten werden geprüft. Der ursprüngliche Pfad bleibt bis zum Ersetzen verfügbar. Die Arbeitsdatei wird nie zwischen Dateisystemen verschoben und vom Abschluss nie entfernt.
  6. Nachdem Core einen geprüften Erfolg erhalten hat, prüft eine separate Bereinigung den endgültigen Inhalt und die Sicherheitsmetadaten erneut, bevor sie Arbeitsdatei und Journal entfernt. Schlägt die Bereinigung fehl, wird dennoch ein bestätigtes Speichern mit recoveryAvailable: true gemeldet.

Ein fehlgeschlagener Upload, fehlgeschlagenes sudo, ein Konflikt, ein Metadatenfehler oder ein fehlgeschlagenes Ersetzen behält das Original und sämtliches vorbereitetes Material. Unvollständige Uploads werden als solche gekennzeichnet und können nicht als vollständig bearbeitetes Dokument wiederhergestellt werden. Verlorene SSH-Kommunikation, fehlender Exit-Status, Zeitüberschreitungen und unerwartete Abschlussergebnisse werden als unbekannt gemeldet, nie als gespeichert. Core blockiert weiteres Speichern eines ungewissen Dokuments; es gibt keine automatische Wiederholung des Ersetzens.

Metadaten, Berechtigungen und Sicherheitsgrenzen

Das Hilfsprogramm bewahrt und prüft UID, GID und alle POSIX-Berechtigungsbits einschließlich Ausführbarkeit, setuid, setgid und Sticky-Bit. Erweiterte Attribute von Linux werden Byte für Byte reproduziert, einschließlich POSIX-ACLs, Capabilities und SELinux-Labels. Eigentümer und Dateiinhalt werden vor den Sicherheitsattributen gesetzt, da Schreiben/chown Capabilities oder spezielle Berechtigungsbits löschen kann. Geerbte Attribute des Ziels, die das Original nicht hat, werden entfernt. Die Änderungszeit spiegelt den neuen Schreibvorgang wider und wird nicht vom Original kopiert.

Ein unlesbares oder nicht darstellbares Attribut bricht den Vorgang ab; Metadaten werden nie stillschweigend verworfen. IMA/EVM-Signaturen werden ausdrücklich abgelehnt, weil das Kopieren inhalts-/inode-gebundener Integritätssignaturen diese ungültig machen würde. Symbolische Links im Ziel- oder Home-Pfad, Dateien mit mehreren Hardlinks und nicht reguläre Dateien werden abgelehnt. Es wird kein Überschreiben an Ort und Stelle und kein schwächeres SFTP-Überschreiben als Ausweichlösung verwendet.

Gewöhnliche beschreibbare Speichervorgänge laufen unter dem SSH-Konto. Geschützte Speichervorgänge erfordern ausdrücklich { sudo: true }; ein sudo-Passwort ist bei passwortlosem sudo optional. Passwörter werden geprüft und nur über stdin des Kanals übergeben, nie im Befehl, Journal, in der Arbeitsdatei, im Logger oder in einem entfernten Fehler. Root-SSH-Sitzungen verwenden den bestehenden direkten root-Ausführer. Eine fehlgeschlagene Autorisierung lässt Original und Arbeitskopie unverändert. Alle als root ausgeführten Speichervorgänge (direktes root-SSH oder sudo) lehnen zusätzlich Zielverzeichnisse/Vorgänger ab, die anderen Konten gehören, von ihnen beschreibbar sind oder eine Zugriffs-ACL tragen, statt einem privilegierten, von einem anderen Konto kontrollierten Pfadnamen zu vertrauen.

Das feste Hilfsprogramm läuft mit python3 -I -B: Es ignoriert Python-Pfade des Benutzers, das Arbeitsverzeichnis und Benutzer-Site-Packages und schreibt keinen Bytecode. Pfade und JSON-Argumente werden in Core für die Shell maskiert. Plugins erhalten niemals beliebiges SSH-exec oder SFTP-Handles. Bestehende Sandbox, CSP, Manifest-Berechtigungen, Hostschlüsselprüfung und Aktualisierungsprüfung bleiben in Kraft.

Plugin API und verbleibende Monaco-Integration

Die separat verteilte Oberfläche Monaco/File Manager ist in diesem Checkout nicht enthalten. Ihre UI-Integration, die sudo-Abfrage, die Behandlung ungespeicherter Puffer und die Übersetzungen konnten hier weder umgesetzt noch getestet werden. Die mitgelieferte Plugin-Quelle ist das Plugin Hash & Checksum. Es wurde keine Ersatzquelle für den File Manager erfunden.

Die bestehenden Methoden bleiben verfügbar. Zusätzliche Methoden/Optionen stellen das Preload in der Sandbox und die Laufzeitumgebung mit Berechtigungsprüfung bereit:

const opened = await chjPlugin.files.readText(sessionId, path);
// For a protected read, explicitly pass { sudo: true, sudoPassword }.

const result = await chjPlugin.files.saveText(sessionId, path, editor.getValue(), {
  editId: opened.editId,
  sudo: true,           // Include only after the user authorizes elevation.
  sudoPassword         // Omit for passwordless sudo; never persist this value.
});

if (result.ok && result.value.status === "saved") {
  // Mark this exact submitted editor version as saved. Later edits stay dirty.
} else {
  // Keep the Monaco model dirty. Translate result.error.code/status.
  // result.error.recoveryId/recoveryPath identify retained working material.
}

await chjPlugin.files.closeText(opened.editId);
const recovery = await chjPlugin.files.listRecovery(sessionId);
const copy = await chjPlugin.files.readRecovery(sessionId, recoveryId);
// Review copy.status and copy.text; open a fresh document before another save.
await chjPlugin.files.cleanupRecovery(sessionId, recoveryId);
// Cleanup rejects anything whose target is not currently confirmed.

Wiederherstellungsmethoden akzeptieren ein optionales letztes Argument { sudo: true, sudoPassword }, wenn die Prüfung eines Ziels erhöhte Rechte erfordert. Sie behalten den Arbeitsbereich des authentifizierten Benutzers auch bei Ausführung über sudo. Journale überstehen einen Neustart der Anwendung und eine erneute SSH-Verbindung; die Wiederherstellung wiederholt den Abschluss nie automatisch. Vergleichen Sie einen wiederhergestellten Puffer mit einem frisch geöffneten Ziel, bevor Sie ihn ausdrücklich speichern.

files.read schützt Lesen, Prüfen und Freigeben von Handles. files.write schützt Speichern und Bereinigen der Wiederherstellung. writeText lehnt bei bestehenden Plugins im Fehlerfall weiterhin ab; saveText gibt eine strukturierte Hülle { ok, value/error } zurück, weil Electron eigene Eigenschaften abgelehnter Error-Objekte verwirft. Ein älterer Aufruf von writeText mit drei Argumenten kann den Ausgangszustand eines einzigen geöffneten Dokuments verwenden. Mehrere aktive Dokumente für denselben Pfad erfordern editId; mehrdeutige ältere Aufrufe schlagen sicher fehl, statt den Ausgangszustand eines anderen Dokuments zu wählen. Plugins sollten ungenutzte Handles freigeben.

Die externe Oberfläche muss das Speichern sofort anzeigen, Puffer bei Fehlern als ungespeichert behalten, sudo erst nach Berechtigungs-/Authentifizierungsfehlern anbieten, Konflikte ohne Überschreiben anzeigen und nach Verbindungsverlust oder unbekanntem Ergebnis eine Wiederherstellung anbieten. Sie muss diese Zustände auf Tschechisch, Deutsch und Englisch übersetzen. Vorgeschlagene Zustandstexte:

Zustand Tschechisch Deutsch Englisch
Speichern Ukládání… Wird gespeichert… Saving…
Bestätigt Uloženo Gespeichert Saved
Fehler Uložení selhalo Speichern fehlgeschlagen Save failed
Sudo erforderlich Vyžadováno oprávnění sudo sudo-Autorisierung erforderlich Sudo authorization required
Konflikt Původní soubor byl změněn Originaldatei wurde geändert Original file changed
Getrennt Spojení bylo přerušeno Verbindung unterbrochen Connection lost
Unbekannt Výsledek uložení není znám Speicherergebnis unbekannt Save result unknown
Wiederherstellung Obnova je dostupná Wiederherstellung verfügbar Recovery available

Latenzdefinitionen und Lebenszyklus

Ping ist die Latenz, die eine tatsächliche clientseitige ICMP-Echo-Antwort von der aufgelösten IP-Adresse meldet, die SSH verwendet. Core ruft das Ping-Programm der Plattform asynchron mit einem festen Argument-Array auf, ohne Shell und ohne Start mit Administratorrechten. Die Argumente für Linux, macOS (einschließlich ping6) und Windows werden getrennt gewählt. Blockiertes ICMP, ein fehlendes Programm, eine Zeitüberschreitung, ungültige Ausgabe oder eine Windows-Antwort nur mit Obergrenze wie <1ms ergeben einen nicht verfügbaren Wert, keine erfundene Zahl.

SSH RTT ist die monotone Dauer performance.now() einer festen exec-Anfrage true über den bestehenden authentifizierten SSH-Client. Sie umfasst Kanalaufbau, Verarbeitung auf dem Server und Zustellung der Antwort; sie ist weder reine Netzwerk-RTT noch die Dauer der SSH-Anmeldung. Der übersetzte Tooltip der Anzeige erklärt diesen Unterschied.

Die Überwachung beginnt, sobald das Terminal verbunden ist. Messungen laufen parallel und asynchron mit einem Zeitlimit von fünf Sekunden pro Anfrage/Prozess. Die nächste Messung wird zwölf Sekunden nach Abschluss der vorherigen geplant, sodass sich nichts überschneidet. Das Trennen bricht ICMP ab, löscht Timer, bricht ausstehende SSH-Arbeit ab und löscht die Werte. Identitätsprüfungen der Einträge verhindern, dass eine frühere Verbindung nach dem erneuten Verbinden Werte veröffentlicht. Ein ICMP-Fehler ändert nie den Zustand der SSH-Verbindung.

Die Latenz wird im bestehenden Ereignis state bzw. in den IPC-Daten von ssh:state übertragen:

latency: { pingMs: 24.1, sshRttMs: 31.25, measuredAt: "…" }

Nicht verfügbare Zahlen sind null. Die kompakte Terminalanzeige verwendet Millisekunden, einen lokalisierten Text für Nichtverfügbarkeit und Beschriftungen auf Tschechisch/Deutsch/Englisch. Beim Trennen wird sie ausgeblendet. Es waren keine zusätzlichen Ausführungsrechte im Renderer und keine IPC-Anfrage nötig.

Prüfung und betriebliche Grenzen

Der Benutzer verlangte, die Änderungen im bestehenden Arbeitsbaum zu belassen, derzeit feature/hash-checksum-plugin; es gab keinen Branch-Wechsel und keine unbeteiligte Bereinigung.

Für diese Aufgabe geänderte Dateien