feat(satellite): gespeicherte Zugangsdaten anzeigen, Passwort per Auge, FritzBox-Benutzer ermitteln
Das Zugangsdaten-Formular war beim erneuten Oeffnen leer, obwohl der Satellit alles gespeichert hatte. Satellit: - sat_creds_list mit ip liefert je Typ die Felder ohne Geheimnisse (Benutzer, Port, SNMP-Version/v3-Stufe) und has_<feld> fuer Passwoerter; mit reveal (nur zusammen mit ip) auch die Geheimnisse dieses Geraets. - sat_creds_set behaelt ein gespeichertes Geheimnis, wenn das Feld nicht mitgeschickt wird — Benutzer aendern, ohne das Passwort neu zu tippen. Diagnostic-Server: Antworten mit Klartext (revealed) gehen nur an den Browser, der gefragt hat, nicht an alle offenen Tabs. Formular: Benutzer/Port/Version stehen beim Oeffnen drin, Passwoerter als "•••••• gespeichert"; 👁 holt sie im Klartext bzw. schaltet um. Leeres Passwortfeld = gespeichertes behalten. FritzBox: "Benutzer ermitteln" (nur bei als FritzBox erkannten Geraeten) liest login_sid.lua?version=2 — die Box nennt ihre Benutzer ohne Anmeldung; eingetragen wird der zuletzt angemeldete. Getestet: Satelliten-Logik per Unit-Test, Formular in headless Chromium (Anzeige, Speichern ohne Passwort, Auge, Benutzer ermitteln). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
+19
-2
@@ -836,6 +836,9 @@ function satelliteList() {
|
||||
}));
|
||||
}
|
||||
|
||||
// requestId → Browser-Socket, der Klartext-Zugangsdaten angefordert hat
|
||||
const credsRevealWaiters = new Map();
|
||||
|
||||
function broadcastSatellites() {
|
||||
broadcast({ type: "sat_update", satellites: satelliteList() });
|
||||
}
|
||||
@@ -1425,7 +1428,16 @@ function connectRVS(forcePlain) {
|
||||
location: p.location || "", devices: p.devices || [] });
|
||||
} else if (msg.type === "sat_creds_list_result" || msg.type === "sat_creds_result") {
|
||||
// Credential-Store-Antworten eines Satelliten → an den Browser.
|
||||
broadcast({ type: msg.type, payload: msg.payload || {} });
|
||||
// Mit Klartext-Passwoertern (Auge im Formular) NUR an den Browser, der
|
||||
// gefragt hat — nie an alle offenen Diagnostic-Tabs.
|
||||
const p = msg.payload || {};
|
||||
if (p.revealed) {
|
||||
const asker = credsRevealWaiters.get(p.requestId);
|
||||
credsRevealWaiters.delete(p.requestId);
|
||||
if (asker && asker.readyState === WebSocket.OPEN) asker.send(JSON.stringify({ type: msg.type, payload: p }));
|
||||
} else {
|
||||
broadcast({ type: msg.type, payload: p });
|
||||
}
|
||||
} else if (msg.type === "worker_hello") {
|
||||
// Ein Compute-Worker (GPU-Dienst) meldet sich mit seiner Identitaet.
|
||||
const p = msg.payload || {};
|
||||
@@ -3411,8 +3423,13 @@ wss.on("connection", (ws) => {
|
||||
requestId: "dn_" + Date.now() },
|
||||
timestamp: Date.now() });
|
||||
} else if (msg.action === "sat_creds_list") {
|
||||
const requestId = "dc_" + Date.now() + "_" + Math.random().toString(36).slice(2, 8);
|
||||
if (msg.reveal) {
|
||||
credsRevealWaiters.set(requestId, ws);
|
||||
setTimeout(() => credsRevealWaiters.delete(requestId), 30000);
|
||||
}
|
||||
sendToRVS_raw({ type: "sat_creds_list",
|
||||
payload: { satellite: msg.satellite || "", requestId: "dc_" + Date.now() },
|
||||
payload: { satellite: msg.satellite || "", ip: msg.ip || "", reveal: !!msg.reveal, requestId },
|
||||
timestamp: Date.now() });
|
||||
} else if (msg.action === "sat_creds_set") {
|
||||
sendToRVS_raw({ type: "sat_creds_set",
|
||||
|
||||
Reference in New Issue
Block a user