Compare commits
2
Commits
2b05d012ee
...
8577cd24cd
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8577cd24cd | ||
|
|
877903bd77 |
+67
-16
@@ -4224,6 +4224,7 @@ def settings_import_export():
|
||||
"settings_import_export.html",
|
||||
export_sections=EXPORT_SECTIONS,
|
||||
admin_only_sections=IMPORT_EXPORT_ADMIN_ONLY_SECTIONS,
|
||||
export_section_hints=EXPORT_SECTION_HINTS,
|
||||
)
|
||||
|
||||
|
||||
@@ -5435,16 +5436,26 @@ def _merge_known_hosts_content(new_content):
|
||||
EXPORT_SECTIONS = [
|
||||
("devices", "Clients"),
|
||||
("switches", "Switche"),
|
||||
("credentials", "Zugangsdaten (inkl. bekannter SSH-Host-Keys aus known_hosts)"),
|
||||
("users", "Benutzer (lokal)"),
|
||||
("groups", "Custom-Gruppen"),
|
||||
("ldap", "LDAP/AD-Einstellungen"),
|
||||
("dhcp", "DHCP-Einstellungen"),
|
||||
("nginx", "NGINX-Einstellungen (Domain, Ports, SSL/HSTS — ohne Zertifikat/Schlüssel)"),
|
||||
("logs", "Auditlog (alle aktuell in der Datenbank vorhandenen Einträge)"),
|
||||
("credentials", "Zugangsdaten"),
|
||||
("users", "Benutzer"),
|
||||
("groups", "Gruppen"),
|
||||
("ldap", "LDAP/AD"),
|
||||
("dhcp", "DHCP"),
|
||||
("nginx", "NGINX"),
|
||||
("logs", "Auditlog"),
|
||||
]
|
||||
EXPORT_SECTION_LABELS = dict(EXPORT_SECTIONS)
|
||||
|
||||
# Zusätzlicher Hinweistext je Kategorie fürs "i"-Icon neben dem Label
|
||||
# (siehe _hint_icon.html) -- nur für Kategorien mit erklärungsbedürftigem
|
||||
# Zusatzverhalten, das über den reinen Namen hinausgeht.
|
||||
EXPORT_SECTION_HINTS = {
|
||||
"users": "Nur lokale Konten. AD/LDAP-Benutzer werden NICHT gesichert — sie werden über Active Directory verwaltet, nicht über diese App, und legen sich beim nächsten Login automatisch wieder an.",
|
||||
"credentials": "Enthält zusätzlich den Inhalt von known_hosts (bereits bestätigte SSH-Host-Keys) — wird beim Import ergänzend (nicht überschreibend) eingespielt.",
|
||||
"nginx": "Enthält Domain, Ports und SSL/HSTS-Schalter sowie — falls vorhanden — das aktuell hinterlegte TLS-Zertifikat und den privaten Schlüssel selbst.",
|
||||
"logs": "Alle aktuell in der Datenbank vorhandenen Einträge (bereits archivierte Auditlog-Tage liegen als eigene Dateien unter Verlauf und sind kein Teil dieses Exports).",
|
||||
}
|
||||
|
||||
IMPORT_EXPORT_ADMIN_ONLY_SECTIONS = {"users", "groups", "ldap"}
|
||||
|
||||
LDAP_SETTING_KEYS = [
|
||||
@@ -5580,17 +5591,31 @@ NGINX_SETTING_KEYS = ["nginx_server_name", "nginx_http_port", "nginx_https_port"
|
||||
|
||||
|
||||
def _export_nginx(conn):
|
||||
"""Exportiert nur portable Konfiguration (Domain, Ports, SSL/HSTS-
|
||||
Schalter) -- bewusst OHNE ssl_source, TLS-Zertifikat/Schlüssel oder
|
||||
Let's-Encrypt-/certbot-Zustand: das sind entweder host-gebundene reale
|
||||
Dateien (TESM_SSL_CERT_PATH/TESM_SSL_KEY_PATH) oder eine ACME-
|
||||
Registrierung für genau diesen Host/diese Domain, kein portabler
|
||||
Einstellungswert (gleiche Begründung wie bei avatar_filename in
|
||||
_export_users())."""
|
||||
"""Exportiert Domain/Ports/SSL-HSTS-Schalter sowie, falls vorhanden,
|
||||
das aktuell hinterlegte TLS-Zertifikat+Schlüssel selbst (Base64, da
|
||||
JSON keine Binärdaten kann) -- anders als bei avatar_filename ist das
|
||||
hier sinnvoll: Zertifikat/Schlüssel liegen bereits vollständig auf
|
||||
diesem Host vor und lassen sich 1:1 auf ein Zielsystem übertragen,
|
||||
genau wie andere Geheimnisse (Zugangsdaten-Passwörter, LDAP-Bind-
|
||||
Passwort), die ebenfalls im Klartext in den -- als Ganzes
|
||||
passphrasenverschlüsselten -- Export wandern. Bewusst AUSGESCHLOSSEN
|
||||
bleibt trotzdem jeglicher Let's-Encrypt-/certbot-Zustand (ssl_source,
|
||||
ACME-Konto, Renewal-Timer): das ist an genau diesen Host und dessen
|
||||
Domain-Registrierung gebunden und kann nicht mitziehen -- ein Import
|
||||
setzt ssl_source deshalb immer auf "upload", siehe _import_nginx()."""
|
||||
settings_data = {k: get_setting(k) for k in NGINX_SETTING_KEYS if get_setting(k) not in (None, "")}
|
||||
if not settings_data:
|
||||
data = {"settings": settings_data}
|
||||
try:
|
||||
if os.path.isfile(TESM_SSL_CERT_PATH) and os.path.isfile(TESM_SSL_KEY_PATH):
|
||||
with open(TESM_SSL_CERT_PATH, "rb") as f:
|
||||
data["cert_pem"] = base64.b64encode(f.read()).decode("ascii")
|
||||
with open(TESM_SSL_KEY_PATH, "rb") as f:
|
||||
data["key_pem"] = base64.b64encode(f.read()).decode("ascii")
|
||||
except OSError:
|
||||
pass
|
||||
if not (settings_data or "cert_pem" in data):
|
||||
return None
|
||||
return {"settings": settings_data}
|
||||
return data
|
||||
|
||||
|
||||
def _export_logs(conn):
|
||||
@@ -5835,6 +5860,31 @@ def _import_nginx(conn, data):
|
||||
(key, value),
|
||||
)
|
||||
n += 1
|
||||
if data.get("cert_pem") and data.get("key_pem"):
|
||||
try:
|
||||
cert_bytes = base64.b64decode(data["cert_pem"])
|
||||
key_bytes = base64.b64decode(data["key_pem"])
|
||||
ok, _msg, _info = _validate_cert_key_pair(cert_bytes, key_bytes)
|
||||
if ok:
|
||||
os.makedirs(TESM_SSL_DIR, exist_ok=True)
|
||||
with open(TESM_SSL_CERT_PATH, "wb") as f:
|
||||
f.write(cert_bytes)
|
||||
with open(TESM_SSL_KEY_PATH, "wb") as f:
|
||||
f.write(key_bytes)
|
||||
os.chmod(TESM_SSL_KEY_PATH, 0o600)
|
||||
os.chmod(TESM_SSL_CERT_PATH, 0o644)
|
||||
# ACME-/certbot-Zustand kommt bewusst nie mit (siehe
|
||||
# _export_nginx) -- nach dem Import ist es technisch nur
|
||||
# noch ein hochgeladenes Zertifikat, keine automatische
|
||||
# Verlängerung mehr, auch wenn es ursprünglich per Let's
|
||||
# Encrypt ausgestellt wurde.
|
||||
conn.execute(
|
||||
"INSERT INTO settings (key, value) VALUES ('ssl_source', 'upload') "
|
||||
"ON CONFLICT(key) DO UPDATE SET value=excluded.value"
|
||||
)
|
||||
n += 1
|
||||
except (OSError, ValueError, TypeError):
|
||||
pass
|
||||
return n
|
||||
|
||||
|
||||
@@ -5983,6 +6033,7 @@ def settings_import_preview(token):
|
||||
import_preview={"token": token, "sections": preview_sections},
|
||||
export_sections=EXPORT_SECTIONS,
|
||||
admin_only_sections=IMPORT_EXPORT_ADMIN_ONLY_SECTIONS,
|
||||
export_section_hints=EXPORT_SECTION_HINTS,
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -82,6 +82,7 @@
|
||||
{% if key not in admin_only_sections or current_user.is_admin %}checked{% endif %}
|
||||
{% if key in admin_only_sections and not current_user.is_admin %}disabled{% endif %}>
|
||||
{{ label }}
|
||||
{% if export_section_hints and key in export_section_hints %}{{ hi.hint_icon(export_section_hints[key], label) }}{% endif %}
|
||||
{% if key in admin_only_sections %}<span class="pill user" style="font-size:10px; padding:2px 7px;">Nur Admin</span>{% endif %}
|
||||
</label>
|
||||
{% endfor %}
|
||||
|
||||
Reference in New Issue
Block a user