connect fix 3

This commit is contained in:
2026-08-20 23:35:42 +02:00
parent fc32b1e4ef
commit bf2a02679d
14 changed files with 956 additions and 49 deletions

View File

@ -522,6 +522,7 @@
document.getElementById("he-clipboard").checked = host.clipboard_enabled;
document.getElementById("he-filetransfer").checked = host.file_transfer_enabled;
document.getElementById("he-nla").checked = host.rdp_require_nla;
document.getElementById("he-ignorecert").checked = host.rdp_ignore_cert;
document.getElementById("he-active").checked = host.is_active;
const isRdp = host.protocol === "rdp";
@ -529,6 +530,7 @@
document.getElementById("he-rdp-username-box").classList.toggle("hidden", !isRdp);
document.getElementById("he-rdp-domain-box").classList.toggle("hidden", !isRdp);
document.getElementById("he-nla-box").classList.toggle("hidden", !isRdp);
document.getElementById("he-ignorecert-box").classList.toggle("hidden", !isRdp);
document.getElementById("host-detail-ssh").classList.toggle("hidden", isRdp);
document.getElementById("host-detail-rdp").classList.toggle("hidden", !isRdp);
@ -579,6 +581,7 @@
clipboard_enabled: document.getElementById("he-clipboard").checked,
file_transfer_enabled: document.getElementById("he-filetransfer").checked,
rdp_require_nla: document.getElementById("he-nla").checked,
rdp_ignore_cert: document.getElementById("he-ignorecert").checked,
is_active: document.getElementById("he-active").checked,
});
showBanner("Host aktualisiert.", "ok");
@ -595,6 +598,8 @@
document.getElementById("hc-rdp-username-box").classList.toggle("hidden", !isRdp);
document.getElementById("hc-rdp-domain-box").classList.toggle("hidden", !isRdp);
document.getElementById("hc-nla-box").classList.toggle("hidden", !isRdp);
document.getElementById("hc-ignorecert-box").classList.toggle("hidden", !isRdp);
document.getElementById("hc-ignorecert-hint").classList.toggle("hidden", !isRdp);
document.getElementById("hc-port").value = isRdp ? "3389" : "22";
document.getElementById("hc-os-type").value = isRdp ? "windows" : "linux";
});
@ -631,6 +636,7 @@
rdp_username: document.getElementById("hc-rdp-username").value.trim() || null,
rdp_domain: document.getElementById("hc-rdp-domain").value.trim() || null,
rdp_require_nla: document.getElementById("hc-nla").checked,
rdp_ignore_cert: document.getElementById("hc-ignorecert").checked,
clipboard_enabled: document.getElementById("hc-clipboard").checked,
file_transfer_enabled: document.getElementById("hc-filetransfer").checked,
};
@ -706,6 +712,7 @@
el("td", { textContent: k.key_type }),
el("td", { textContent: k.owner_user_id === null ? "-" : String(k.owner_user_id) }),
el("td", { textContent: k.tenant_name }),
el("td", { textContent: k.has_passphrase ? "hinterlegt" : "-" }),
el("td", { textContent: k.created_at }),
el("td", { textContent: k.rotated_at || "-" }),
el("td", {}, [
@ -731,8 +738,46 @@
document.getElementById("ske-label").value = k.label;
document.getElementById("ske-owner").value = k.owner_user_id === null ? "" : String(k.owner_user_id);
document.getElementById("skr-type").value = k.key_type;
document.getElementById("skp-passphrase").value = "";
document.getElementById("ske-passphrase-state").textContent = k.has_passphrase
? "Fuer diesen Schluessel ist eine Passphrase hinterlegt."
: "Fuer diesen Schluessel ist KEINE Passphrase hinterlegt. Ist der Schluessel verschluesselt, schlaegt jeder Verbindungsversuch fehl.";
}
async function saveSshKeyPassphrase(value) {
// Wird gegen das bereits gespeicherte Schluesselmaterial geprueft
// (update_ssh_key in app/admin/routes.py); passt sie nicht, antwortet der
// Server mit 400 und es wird nichts gespeichert.
await sendJson(`/admin/ssh-keys/${editingSshKeyId}`, "PUT", { passphrase: value });
await refreshSshKeys();
const updated = cachedSshKeys.find((k) => k.id === editingSshKeyId);
if (updated) showSshKeyEdit(updated);
}
document.getElementById("ssh-key-passphrase-form").addEventListener("submit", async (ev) => {
ev.preventDefault();
try {
const value = document.getElementById("skp-passphrase").value;
if (!value) {
showBanner("Bitte eine Passphrase eingeben oder 'Passphrase entfernen' verwenden.", "error");
return;
}
await saveSshKeyPassphrase(value);
showBanner("Passphrase gespeichert und gegen den Schluessel geprueft.", "ok");
} catch (err) {
showBanner(err.message, "error");
}
});
document.getElementById("skp-clear-btn").addEventListener("click", async () => {
try {
await saveSshKeyPassphrase(null);
showBanner("Passphrase entfernt.", "ok");
} catch (err) {
showBanner(err.message, "error");
}
});
document.getElementById("ssh-key-edit-form").addEventListener("submit", async (ev) => {
ev.preventDefault();
try {
@ -755,6 +800,7 @@
key_type: document.getElementById("skr-type").value,
private_key_pem: document.getElementById("skr-private").value,
public_key: document.getElementById("skr-public").value,
passphrase: document.getElementById("skr-passphrase").value || null,
});
showBanner("SSH-Key rotiert.", "ok");
ev.target.reset();
@ -775,6 +821,8 @@
key_type: document.getElementById("skc-type").value,
private_key_pem: document.getElementById("skc-private").value,
public_key: document.getElementById("skc-public").value,
// Leeres Feld -> null: der Schluessel gilt dann als unverschluesselt.
passphrase: document.getElementById("skc-passphrase").value || null,
tenant_id: tenantSelect.value ? Number(tenantSelect.value) : null,
};
await sendJson("/admin/ssh-keys", "POST", payload);

View File

@ -21,7 +21,15 @@
const height = Math.round(window.innerHeight - 40);
const dpi = Math.round(window.devicePixelRatio * 96) || 96;
const tunnelUrl = `${proto}//${window.location.host}/ws/rdp/${hostId}?width=${width}&height=${height}&dpi=${dpi}`;
// WICHTIG: die Verbindungsparameter gehoeren NICHT in die Tunnel-URL.
// Guacamole.WebSocketTunnel.connect(data) baut die Socket-URL selbst als
// `tunnelURL + "?" + data` zusammen. Standen die Parameter schon in der
// URL, entstand daraus `...?width=1280&height=800&dpi=96?undefined` -- der
// letzte Query-Parameter war damit kein gueltiger Integer mehr, FastAPI
// wies den WebSocket noch vor dem Routenhandler ab (HTTP 422) und im
// Verbindungslog des Servers tauchte kein einziger Eintrag auf.
const tunnelUrl = `${proto}//${window.location.host}/ws/rdp/${hostId}`;
const connectParams = `width=${width}&height=${height}&dpi=${dpi}`;
const tunnel = new Guacamole.WebSocketTunnel(tunnelUrl);
const client = new Guacamole.Client(tunnel);
@ -32,9 +40,15 @@
const labels = ["Idle", "Verbinde ...", "Warte auf Server ...", "Verbunden", "Trenne ...", "Getrennt"];
statusEl.textContent = labels[state] || `Status ${state}`;
};
client.onerror = (err) => {
statusEl.textContent = "Fehler: " + (err.message || "unbekannt");
const showError = (err) => {
// Der Server gibt den Abbruchgrund als WebSocket-Close-Reason mit
// (siehe _reject() in app/rdp_proxy/ws_tunnel.py); guacamole-common-js
// reicht ihn als Guacamole.Status.message hierher durch.
statusEl.textContent = "Fehler: " + ((err && err.message) || "unbekannt");
statusEl.classList.add("error");
};
client.onerror = showError;
tunnel.onerror = showError;
client.onclipboard = (stream, mimetype) => {
if (!mimetype.startsWith("text/")) return;
@ -48,7 +62,7 @@
};
};
client.connect();
client.connect(connectParams);
window.addEventListener("beforeunload", () => client.disconnect());