Files
ssh-jumphost/templates/admin.html
2026-08-20 23:35:42 +02:00

679 lines
30 KiB
HTML

<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Jumphost Admin</title>
<link rel="stylesheet" href="/static/css/app.css">
</head>
<body>
<div class="topbar">
<div class="brand">Jumphost &middot; Admin</div>
<div>
<span class="hint" id="whoami"></span>
<a href="/dashboard">Zum Dashboard</a>
<a href="/docs" target="_blank" rel="noopener">API-Dokumentation</a>
<button id="logout-btn">Abmelden</button>
</div>
</div>
<div class="container wide">
<div id="banner-box"></div>
<div class="tabs" id="tabs">
<button type="button" class="tab-btn active" data-tab="users">Benutzer</button>
<button type="button" class="tab-btn" data-tab="groups">Benutzergruppen</button>
<button type="button" class="tab-btn" data-tab="hostgroups">Hostgruppen</button>
<button type="button" class="tab-btn" data-tab="servers">Server</button>
<button type="button" class="tab-btn" data-tab="credentials">Zugangsdaten</button>
<button type="button" class="tab-btn" data-tab="roles">Rollen</button>
<button type="button" class="tab-btn" data-tab="tokens">API-Tokens</button>
<button type="button" class="tab-btn hidden" data-tab="tenants" id="tenants-tab-btn">Mandanten</button>
<button type="button" class="tab-btn hidden" data-tab="sessions" id="sessions-tab-btn">Sessions</button>
<button type="button" class="tab-btn hidden" data-tab="connlog" id="connlog-tab-btn">Verbindungslog</button>
<button type="button" class="tab-btn" data-tab="audit">Audit-Log</button>
</div>
<!-- ================= Benutzer ================= -->
<div class="tab-panel" id="tab-users">
<div class="panel">
<h2>Neuen Benutzer anlegen</h2>
<form id="user-create-form" class="form-grid">
<div>
<label for="uc-username">Benutzername</label>
<input type="text" id="uc-username" required minlength="3" maxlength="64">
</div>
<div>
<label for="uc-password">Initiales Passwort (min. 12 Zeichen)</label>
<input type="text" id="uc-password" required minlength="12" maxlength="256">
</div>
<div class="checkbox-row" id="uc-is-admin-row">
<input type="checkbox" id="uc-is-admin">
<label for="uc-is-admin">Globaler Super-Admin</label>
</div>
<button type="submit">Anlegen</button>
</form>
</div>
<div class="panel">
<h2>Benutzer</h2>
<div class="table-wrap">
<table class="data-table" id="users-table">
<thead>
<tr>
<th>ID</th><th>Benutzername</th><th>Admin</th><th>Aktiv</th>
<th>TOTP</th><th>Mandant</th><th>Erstellt</th><th></th>
</tr>
</thead>
<tbody></tbody>
</table>
</div>
</div>
<div class="panel hidden" id="user-edit-panel">
<h2>Benutzer bearbeiten: <span id="user-edit-name"></span></h2>
<form id="user-edit-form" class="form-grid">
<div class="checkbox-row" id="ue-is-admin-row">
<input type="checkbox" id="ue-is-admin">
<label for="ue-is-admin">Globaler Super-Admin</label>
</div>
<div class="checkbox-row">
<input type="checkbox" id="ue-is-active">
<label for="ue-is-active">Aktiv</label>
</div>
<div>
<label for="ue-new-password">Neues Passwort setzen (optional, min. 12 Zeichen)</label>
<input type="text" id="ue-new-password" minlength="12" maxlength="256">
</div>
<button type="submit">Speichern</button>
</form>
</div>
</div>
<!-- ================= Benutzergruppen ================= -->
<div class="tab-panel hidden" id="tab-groups">
<div class="panel">
<h2>Neue Benutzergruppe anlegen</h2>
<form id="group-create-form" class="form-grid">
<div>
<label for="gc-name">Name</label>
<input type="text" id="gc-name" required maxlength="128">
</div>
<div>
<label for="gc-description">Beschreibung (optional)</label>
<input type="text" id="gc-description" maxlength="1024">
</div>
<div id="gc-tenant-box">
<label for="gc-tenant">Mandant</label>
<select id="gc-tenant" required></select>
</div>
<button type="submit">Anlegen</button>
</form>
</div>
<div class="panel">
<h2>Benutzergruppen</h2>
<p class="hint">Rollen fuer eine Gruppe (= Verbindungen mit der ganzen Gruppe teilen) werden im Tab "Rollen" vergeben.</p>
<div class="table-wrap">
<table class="data-table" id="groups-table">
<thead><tr><th>ID</th><th>Name</th><th>Beschreibung</th><th>Mandant</th><th>Mitglieder</th><th></th></tr></thead>
<tbody></tbody>
</table>
</div>
</div>
<div class="panel hidden" id="group-edit-panel">
<h2>Gruppe bearbeiten: <span id="group-edit-name"></span></h2>
<form id="group-edit-form" class="form-grid">
<div>
<label for="ge-name">Name</label>
<input type="text" id="ge-name" required maxlength="128">
</div>
<div>
<label for="ge-description">Beschreibung</label>
<input type="text" id="ge-description" maxlength="1024">
</div>
<button type="submit">Speichern</button>
</form>
</div>
<div class="panel hidden" id="group-members-panel">
<h2>Mitglieder von <span id="group-members-name"></span></h2>
<div class="table-wrap">
<table class="data-table" id="group-members-table">
<thead><tr><th>User-ID</th><th>Benutzername</th><th>Hinzugefuegt</th><th></th></tr></thead>
<tbody></tbody>
</table>
</div>
<h3>Mitglied hinzufuegen</h3>
<form id="group-member-add-form" class="form-grid">
<div>
<label for="gm-user-select">Benutzer</label>
<select id="gm-user-select" required></select>
</div>
<button type="submit">Hinzufuegen</button>
</form>
</div>
</div>
<!-- ================= Hostgruppen ================= -->
<div class="tab-panel hidden" id="tab-hostgroups">
<div class="panel">
<h2>Neue Hostgruppe anlegen</h2>
<form id="hostgroup-create-form" class="form-grid">
<div>
<label for="hgc-name">Name</label>
<input type="text" id="hgc-name" required maxlength="128">
</div>
<div>
<label for="hgc-description">Beschreibung (optional)</label>
<input type="text" id="hgc-description" maxlength="1024">
</div>
<div id="hgc-tenant-box">
<label for="hgc-tenant">Mandant</label>
<select id="hgc-tenant" required></select>
</div>
<button type="submit">Anlegen</button>
</form>
<h3>Hostgruppen</h3>
<div class="table-wrap">
<table class="data-table" id="hostgroups-table">
<thead><tr><th>ID</th><th>Name</th><th>Beschreibung</th><th>Mandant</th><th></th></tr></thead>
<tbody></tbody>
</table>
</div>
</div>
<div class="panel hidden" id="hostgroup-edit-panel">
<h2>Hostgruppe bearbeiten: <span id="hostgroup-edit-name"></span></h2>
<form id="hostgroup-edit-form" class="form-grid">
<div>
<label for="hge-name">Name</label>
<input type="text" id="hge-name" required maxlength="128">
</div>
<div>
<label for="hge-description">Beschreibung</label>
<input type="text" id="hge-description" maxlength="1024">
</div>
<button type="submit">Speichern</button>
</form>
</div>
</div>
<!-- ================= Server ================= -->
<div class="tab-panel hidden" id="tab-servers">
<div class="panel">
<h2>Neue Verbindung (Host) anlegen</h2>
<form id="host-create-form" class="form-grid">
<div>
<label for="hc-hostgroup">Hostgruppe</label>
<select id="hc-hostgroup" required></select>
</div>
<div>
<label for="hc-hostname">Hostname (Label)</label>
<input type="text" id="hc-hostname" required maxlength="128" pattern="[a-zA-Z0-9][a-zA-Z0-9._-]*">
</div>
<div>
<label for="hc-address">Adresse (IP/DNS)</label>
<input type="text" id="hc-address" required maxlength="255">
</div>
<div>
<label for="hc-protocol">Protokoll</label>
<select id="hc-protocol">
<option value="ssh">SSH</option>
<option value="rdp">RDP</option>
</select>
</div>
<div>
<label for="hc-port">Port</label>
<input type="text" id="hc-port" inputmode="numeric" value="22" required maxlength="5">
</div>
<div>
<label for="hc-os-type">Betriebssystem</label>
<select id="hc-os-type">
<option value="linux">Linux</option>
<option value="windows">Windows</option>
</select>
</div>
<div id="hc-ssh-username-box">
<label for="hc-ssh-username">SSH-Benutzername</label>
<input type="text" id="hc-ssh-username" maxlength="128">
</div>
<div id="hc-rdp-username-box" class="hidden">
<label for="hc-rdp-username">RDP-Benutzername</label>
<input type="text" id="hc-rdp-username" maxlength="128">
</div>
<div id="hc-rdp-domain-box" class="hidden">
<label for="hc-rdp-domain">RDP-Domaene (optional)</label>
<input type="text" id="hc-rdp-domain" maxlength="128">
</div>
<div class="checkbox-row"><input type="checkbox" id="hc-clipboard" checked><label for="hc-clipboard">Zwischenablage erlaubt</label></div>
<div class="checkbox-row"><input type="checkbox" id="hc-filetransfer" checked><label for="hc-filetransfer">Dateitransfer erlaubt</label></div>
<div class="checkbox-row hidden" id="hc-nla-box"><input type="checkbox" id="hc-nla" checked><label for="hc-nla">RDP: NLA erforderlich</label></div>
<div class="checkbox-row hidden" id="hc-ignorecert-box"><input type="checkbox" id="hc-ignorecert" checked><label for="hc-ignorecert">RDP: Serverzertifikat nicht pruefen</label></div>
<p class="hint full-width hidden" id="hc-ignorecert-hint">Windows-Ziele ohne eigene PKI weisen sich mit einem selbstsignierten Zertifikat aus; guacd bricht die Verbindung sonst ab, bevor ein Bild entsteht. Nur deaktivieren, wenn das Ziel ein Zertifikat aus einer dem Jumphost bekannten CA verwendet.</p>
<button type="submit">Verbindung anlegen</button>
</form>
</div>
<div class="panel">
<h2>Vorhandene Hosts</h2>
<div class="table-wrap">
<table class="data-table" id="hosts-table">
<thead>
<tr><th>ID</th><th>Hostname</th><th>Adresse</th><th>Protokoll</th><th>OS</th><th>Hostgruppe</th><th>Mandant</th><th>Status</th><th></th></tr>
</thead>
<tbody></tbody>
</table>
</div>
</div>
<div class="panel hidden" id="host-detail-panel">
<h2>Verbindung: <span id="host-detail-name"></span></h2>
<div id="host-detail-banner"></div>
<h3>Felder bearbeiten</h3>
<form id="host-edit-form" class="form-grid">
<div>
<label for="he-hostname">Hostname (Label)</label>
<input type="text" id="he-hostname" required maxlength="128" pattern="[a-zA-Z0-9][a-zA-Z0-9._-]*">
</div>
<div>
<label for="he-address">Adresse (IP/DNS)</label>
<input type="text" id="he-address" required maxlength="255">
</div>
<div>
<label for="he-port">Port</label>
<input type="text" id="he-port" inputmode="numeric" required maxlength="5">
</div>
<div id="he-ssh-username-box">
<label for="he-ssh-username">SSH-Benutzername</label>
<input type="text" id="he-ssh-username" maxlength="128">
</div>
<div id="he-rdp-username-box" class="hidden">
<label for="he-rdp-username">RDP-Benutzername</label>
<input type="text" id="he-rdp-username" maxlength="128">
</div>
<div id="he-rdp-domain-box" class="hidden">
<label for="he-rdp-domain">RDP-Domaene</label>
<input type="text" id="he-rdp-domain" maxlength="128">
</div>
<div class="checkbox-row"><input type="checkbox" id="he-clipboard"><label for="he-clipboard">Zwischenablage erlaubt</label></div>
<div class="checkbox-row"><input type="checkbox" id="he-filetransfer"><label for="he-filetransfer">Dateitransfer erlaubt</label></div>
<div class="checkbox-row hidden" id="he-nla-box"><input type="checkbox" id="he-nla"><label for="he-nla">RDP: NLA erforderlich</label></div>
<div class="checkbox-row hidden" id="he-ignorecert-box"><input type="checkbox" id="he-ignorecert"><label for="he-ignorecert">RDP: Serverzertifikat nicht pruefen</label></div>
<div class="checkbox-row"><input type="checkbox" id="he-active"><label for="he-active">Aktiv (verbindbar)</label></div>
<button type="submit">Speichern</button>
</form>
<div id="host-detail-ssh">
<h3>SSH-Host-Key</h3>
<p class="hint">Ermittelt den Host-Key EINMALIG ohne Pruefung (bewusste Trust-Entscheidung) und speichert den Fingerprint fuer kuenftiges Pinning. Wird prominent im Audit-Log vermerkt.</p>
<button type="button" class="btn-secondary" id="host-discover-key-btn">Host-Key ermitteln</button>
<div id="host-key-result" class="reveal-box hidden"></div>
<h3>Zugeordnete SSH-Keys</h3>
<div class="table-wrap">
<table class="data-table" id="host-ssh-keys-table">
<thead><tr><th>ID</th><th>Label</th><th></th></tr></thead>
<tbody></tbody>
</table>
</div>
<form id="host-key-map-form" class="form-grid">
<div>
<label for="hkm-key-select">SSH-Key zuordnen</label>
<select id="hkm-key-select" required></select>
</div>
<button type="submit">Zuordnen</button>
</form>
</div>
<div id="host-detail-rdp" class="hidden">
<h3>RDP-Zugangsdaten</h3>
<p class="hint" id="rdp-cred-status"></p>
<form id="host-rdp-cred-form" class="form-grid">
<div class="full-width">
<label for="hrc-password">RDP-Passwort setzen/aendern</label>
<input type="text" id="hrc-password" required maxlength="512">
</div>
<button type="submit">Speichern</button>
</form>
</div>
</div>
</div>
<!-- ================= Zugangsdaten ================= -->
<div class="tab-panel hidden" id="tab-credentials">
<div class="panel">
<h2>Neuen SSH-Key anlegen</h2>
<form id="ssh-key-create-form" class="form-grid">
<div>
<label for="skc-label">Label</label>
<input type="text" id="skc-label" required maxlength="128">
</div>
<div>
<label for="skc-owner">Besitzer (User-ID, optional)</label>
<input type="text" id="skc-owner" inputmode="numeric" maxlength="10">
</div>
<div>
<label for="skc-type">Key-Typ</label>
<select id="skc-type">
<option value="ed25519">ed25519</option>
<option value="rsa-3072">rsa-3072</option>
<option value="rsa-4096">rsa-4096</option>
<option value="ca-cert">ca-cert</option>
</select>
</div>
<div id="skc-tenant-box">
<label for="skc-tenant">Mandant</label>
<select id="skc-tenant" required></select>
</div>
<div class="full-width">
<label for="skc-private">Privater Schluessel (PEM)</label>
<textarea id="skc-private" required></textarea>
</div>
<div class="full-width">
<label for="skc-public">Oeffentlicher Schluessel</label>
<textarea id="skc-public" required></textarea>
</div>
<div class="full-width">
<label for="skc-passphrase">Passphrase (nur bei verschluesseltem Schluessel)</label>
<input type="password" id="skc-passphrase" maxlength="1024" autocomplete="new-password">
<p class="hint">Beginnt der private Schluessel mit "-----BEGIN OPENSSH PRIVATE KEY-----" und wurde er mit einer Passphrase erzeugt, muss sie hier hinterlegt werden -- sonst laesst sich der Schluessel beim Verbindungsaufbau nicht laden. Sie wird wie das Schluesselmaterial selbst AES-256-GCM-verschluesselt gespeichert und niemals wieder ausgegeben. Leer lassen, wenn der Schluessel unverschluesselt ist.</p>
</div>
<button type="submit">Anlegen</button>
</form>
<h3>Vorhandene SSH-Keys</h3>
<div class="table-wrap">
<table class="data-table" id="ssh-keys-table">
<thead><tr><th>ID</th><th>Label</th><th>Typ</th><th>Besitzer</th><th>Mandant</th><th>Passphrase</th><th>Erstellt</th><th>Rotiert</th><th></th></tr></thead>
<tbody></tbody>
</table>
</div>
</div>
<div class="panel hidden" id="ssh-key-edit-panel">
<h2>SSH-Key bearbeiten: <span id="ssh-key-edit-name"></span></h2>
<form id="ssh-key-edit-form" class="form-grid">
<div>
<label for="ske-label">Label</label>
<input type="text" id="ske-label" maxlength="128">
</div>
<div>
<label for="ske-owner">Besitzer (User-ID, leer = keiner)</label>
<input type="text" id="ske-owner" inputmode="numeric" maxlength="10">
</div>
<button type="submit">Speichern (nur Label/Besitzer)</button>
</form>
<h3>Passphrase</h3>
<p class="hint" id="ske-passphrase-state"></p>
<p class="hint">Traegt die Passphrase zu dem bereits gespeicherten Schluessel nach, ohne ihn neu hochzuladen. Sie wird sofort gegen das hinterlegte Schluesselmaterial geprueft -- passt sie nicht, wird nichts gespeichert. Leeres Feld + "Passphrase entfernen" loescht eine hinterlegte Passphrase (nur sinnvoll bei unverschluesseltem Schluessel).</p>
<form id="ssh-key-passphrase-form" class="form-grid">
<div class="full-width">
<label for="skp-passphrase">Passphrase</label>
<input type="password" id="skp-passphrase" maxlength="1024" autocomplete="new-password">
</div>
<button type="submit">Passphrase speichern</button>
<button type="button" id="skp-clear-btn" class="btn-secondary">Passphrase entfernen</button>
</form>
<h3>Schluessel rotieren</h3>
<p class="hint">Ersetzt das Schluesselmaterial vollstaendig (neuer privater + oeffentlicher Schluessel). Bereits zugeordnete Hosts nutzen danach automatisch den neuen Schluessel.</p>
<form id="ssh-key-rotate-form" class="form-grid">
<div>
<label for="skr-type">Key-Typ</label>
<select id="skr-type">
<option value="ed25519">ed25519</option>
<option value="rsa-3072">rsa-3072</option>
<option value="rsa-4096">rsa-4096</option>
<option value="ca-cert">ca-cert</option>
</select>
</div>
<div class="full-width">
<label for="skr-private">Neuer privater Schluessel (PEM)</label>
<textarea id="skr-private" required></textarea>
</div>
<div class="full-width">
<label for="skr-public">Neuer oeffentlicher Schluessel</label>
<textarea id="skr-public" required></textarea>
</div>
<div class="full-width">
<label for="skr-passphrase">Passphrase des neuen Schluessels (optional)</label>
<input type="password" id="skr-passphrase" maxlength="1024" autocomplete="new-password">
</div>
<button type="submit" class="btn-secondary">Rotieren</button>
</form>
</div>
<div class="panel">
<h2>RDP/Windows-Passwoerter</h2>
<p class="hint">Uebersicht aller RDP-Hosts. Passwoerter werden AES-256-GCM-verschluesselt gespeichert und sind nach dem Setzen nicht mehr im Klartext abrufbar.</p>
<div class="table-wrap">
<table class="data-table" id="rdp-creds-table">
<thead><tr><th>Host</th><th>Adresse</th><th>Hostgruppe</th><th>Status</th><th>Zuletzt gesetzt</th><th></th></tr></thead>
<tbody></tbody>
</table>
</div>
</div>
</div>
<!-- ================= Rollen ================= -->
<div class="tab-panel hidden" id="tab-roles">
<div class="panel">
<h2>Rolle(n) an Benutzer vergeben</h2>
<p class="hint">Mehrfachauswahl moeglich -- alle ausgewaehlten Rollen werden in einem Schritt vergeben.</p>
<form id="role-grant-form" class="form-grid">
<div>
<label for="rg-user">Benutzer</label>
<select id="rg-user" required></select>
</div>
<div>
<label for="rg-hostgroup">Hostgruppe</label>
<select id="rg-hostgroup" required></select>
</div>
<div class="full-width">
<label>Rollen</label>
<div class="scope-grid" id="rg-role-grid"></div>
</div>
<div>
<label for="rg-expires">Ablaufdatum (optional, ISO)</label>
<input type="text" id="rg-expires" placeholder="2026-12-31T00:00:00.000Z" maxlength="40">
</div>
<button type="submit">Vergeben</button>
</form>
<div class="table-wrap">
<table class="data-table" id="role-grants-table">
<thead><tr><th>Benutzer</th><th>Hostgruppe</th><th>Rolle</th><th>Ablauf</th><th></th></tr></thead>
<tbody></tbody>
</table>
</div>
</div>
<div class="panel">
<h2>Rolle(n) an Benutzergruppe vergeben (Verbindung mit Gruppe teilen)</h2>
<p class="hint">Volle Rollen-Vererbung: jedes aktuelle und zukuenftige Mitglied der Gruppe erhaelt diese Rollen automatisch. Mehrfachauswahl moeglich.</p>
<form id="group-role-grant-form" class="form-grid">
<div>
<label for="grg-group">Benutzergruppe</label>
<select id="grg-group" required></select>
</div>
<div>
<label for="grg-hostgroup">Hostgruppe</label>
<select id="grg-hostgroup" required></select>
</div>
<div class="full-width">
<label>Rollen</label>
<div class="scope-grid" id="grg-role-grid"></div>
</div>
<div>
<label for="grg-expires">Ablaufdatum (optional, ISO)</label>
<input type="text" id="grg-expires" placeholder="2026-12-31T00:00:00.000Z" maxlength="40">
</div>
<button type="submit">Vergeben</button>
</form>
<div class="table-wrap">
<table class="data-table" id="group-role-grants-table">
<thead><tr><th>Gruppe</th><th>Hostgruppe</th><th>Rolle</th><th>Ablauf</th><th></th></tr></thead>
<tbody></tbody>
</table>
</div>
</div>
</div>
<!-- ================= API-Tokens ================= -->
<div class="tab-panel hidden" id="tab-tokens">
<div class="panel">
<h2>Neues API-Token erstellen</h2>
<p class="hint">Tokens wirken NUR auf die Verwaltungs-API (Benutzer/Hosts/Rollen/...), nie auf SSH-/RDP-Sitzungen selbst. "rw" schliesst "ro" auf derselben Ressource automatisch mit ein. Jedes Token gehoert genau einem Mandanten.</p>
<form id="token-create-form" class="form-grid">
<div>
<label for="tc-label">Bezeichnung</label>
<input type="text" id="tc-label" required maxlength="128">
</div>
<div>
<label for="tc-user">Fuer Benutzer</label>
<select id="tc-user" required></select>
</div>
<div id="tc-tenant-box">
<label for="tc-tenant">Mandant</label>
<select id="tc-tenant" required></select>
</div>
<div>
<label for="tc-expires">Ablaufdatum (optional, ISO)</label>
<input type="text" id="tc-expires" placeholder="2026-12-31T00:00:00.000Z" maxlength="40">
</div>
<div class="full-width">
<label>Scopes</label>
<div class="scope-grid" id="tc-scope-grid"></div>
</div>
<button type="submit">Token erstellen</button>
</form>
<div id="token-reveal-box" class="reveal-box hidden"></div>
</div>
<div class="panel">
<h2>Vorhandene Tokens</h2>
<div class="table-wrap">
<table class="data-table" id="tokens-table">
<thead>
<tr><th>ID</th><th>Bezeichnung</th><th>Benutzer</th><th>Praefix</th><th>Mandant</th><th>Scopes</th><th>Zuletzt genutzt</th><th>Status</th><th></th></tr>
</thead>
<tbody></tbody>
</table>
</div>
</div>
</div>
<!-- ================= Mandanten (nur Super-Admin) ================= -->
<div class="tab-panel hidden" id="tab-tenants">
<div class="panel">
<h2>Neuen Mandanten anlegen</h2>
<form id="tenant-create-form" class="form-grid">
<div>
<label for="tnc-name">Name</label>
<input type="text" id="tnc-name" required maxlength="128">
</div>
<div>
<label for="tnc-description">Beschreibung (optional)</label>
<input type="text" id="tnc-description" maxlength="1024">
</div>
<button type="submit">Anlegen</button>
</form>
<h3>Mandanten</h3>
<div class="table-wrap">
<table class="data-table" id="tenants-table">
<thead><tr><th>ID</th><th>Name</th><th>Beschreibung</th><th>Aktiv</th><th>Hostgruppen</th><th>Benutzergruppen</th><th></th></tr></thead>
<tbody></tbody>
</table>
</div>
</div>
<div class="panel hidden" id="tenant-edit-panel">
<h2>Mandant bearbeiten: <span id="tenant-edit-name"></span></h2>
<form id="tenant-edit-form" class="form-grid">
<div>
<label for="tne-name">Name</label>
<input type="text" id="tne-name" required maxlength="128">
</div>
<div>
<label for="tne-description">Beschreibung</label>
<input type="text" id="tne-description" maxlength="1024">
</div>
<div class="checkbox-row"><input type="checkbox" id="tne-active"><label for="tne-active">Aktiv</label></div>
<button type="submit">Speichern</button>
</form>
</div>
<div class="panel hidden" id="tenant-admins-panel">
<h2>Mandanten-Admins von <span id="tenant-admins-name"></span></h2>
<div class="table-wrap">
<table class="data-table" id="tenant-admins-table">
<thead><tr><th>User-ID</th><th>Benutzername</th><th>Seit</th><th></th></tr></thead>
<tbody></tbody>
</table>
</div>
<h3>Mandanten-Admin hinzufuegen</h3>
<form id="tenant-admin-add-form" class="form-grid">
<div>
<label for="ta-user-select">Benutzer</label>
<select id="ta-user-select" required></select>
</div>
<button type="submit">Hinzufuegen</button>
</form>
</div>
</div>
<!-- ================= Sessions (nur Super-Admin) ================= -->
<div class="tab-panel hidden" id="tab-sessions">
<div class="panel">
<h2>Sitzungen</h2>
<p class="hint">Aktive und historische SSH/RDP-Sitzungen. 'Beenden' trennt eine laufende Sitzung zwangsweise -- funktioniert nur, wenn die Sitzung auf demselben Server-Prozess laeuft, der diese Anfrage bearbeitet.</p>
<div class="checkbox-row">
<input type="checkbox" id="sessions-active-only" checked>
<label for="sessions-active-only">Nur aktive Sitzungen</label>
</div>
<div id="session-recording-box" class="hidden"></div>
<div class="table-wrap">
<table class="data-table" id="sessions-table">
<thead><tr><th>ID</th><th>Benutzer</th><th>Host</th><th>Protokoll</th><th>Start</th><th>Status</th><th>Client-IP</th><th></th></tr></thead>
<tbody></tbody>
</table>
</div>
</div>
</div>
<!-- ================= Verbindungslog (nur Super-Admin) ================= -->
<div class="tab-panel hidden" id="tab-connlog">
<div class="panel">
<h2>Verbindungslog (Live)</h2>
<p class="hint">Live-Mitschnitt der Anwendungslogs dieses Server-Prozesses, inkl. Debug-Details zu SSH/RDP-Verbindungsaufbau. Rein prozesslokal (kein Verlauf vor dem Oeffnen dieses Tabs) und nur fuer Super-Admins sichtbar.</p>
<div class="form-grid">
<div>
<label for="connlog-filter">Filter (Client-seitig)</label>
<input type="text" id="connlog-filter" placeholder="z.B. Hostname oder 'ERROR'">
</div>
<button type="button" class="btn-secondary" id="connlog-clear-btn">Leeren</button>
</div>
<p class="hint">Status: <span id="connlog-status">getrennt</span></p>
<pre id="connlog-output" class="log-view"></pre>
</div>
</div>
<!-- ================= Audit-Log ================= -->
<div class="tab-panel hidden" id="tab-audit">
<div class="panel">
<h2>Audit-Log</h2>
<button type="button" class="btn-secondary" id="audit-verify-btn">Ketten-Integritaet pruefen</button>
<div id="audit-verify-result" class="hidden"></div>
<div class="table-wrap">
<table class="data-table" id="audit-table">
<thead><tr><th>ID</th><th>Zeit</th><th>User-ID</th><th>IP</th><th>Ereignis</th><th>Details</th></tr></thead>
<tbody></tbody>
</table>
</div>
</div>
</div>
</div>
<script src="/static/js/admin.js"></script>
</body>
</html>