Files
dyndns-server/manage.sh
T
Stefan Hacker 91993eb487 F-10/F-11 + Verwaltungsskript
- F-10 Open Redirect: is_safe_url()-Pruefung des next-Parameters beim Login;
  login_required gibt next weiter, Login-Formular traegt es als Hidden-Feld.
  Externe/protokoll-relative Ziele werden ignoriert -> Dashboard.
- F-11 Info-Leak: eigene Fehlerseiten (400/403/404/405/500) ohne Framework-
  Hinweis oder Stacktrace (templates/error.html).
- manage.sh: 'unlock' (Brute-Force-Sperren aufheben) und 'reset-password'
  (Admin-Passwort setzen/zufaellig erzeugen) via docker-compose run.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-06 15:49:04 +02:00

103 lines
2.6 KiB
Bash
Executable File

#!/usr/bin/env sh
# Verwaltungsskript für den DynDNS Manager:
# - Login-/DynDNS-Sperren aufheben (Brute-Force-Lockout)
# - Admin-Passwort zurücksetzen
#
# Läuft über einen kurzlebigen Container (docker-compose run --rm) und greift
# damit auf dieselbe SQLite-DB (./data) zu — funktioniert auch, wenn der
# laufende Container gerade gestoppt ist.
set -eu
SERVICE=dyndns
# In das Skriptverzeichnis wechseln (dort liegt die docker-compose.yml)
cd "$(dirname "$0")"
# docker compose v2 ("docker compose") oder v1 ("docker-compose")?
if docker compose version >/dev/null 2>&1; then
DC="docker compose"
elif command -v docker-compose >/dev/null 2>&1; then
DC="docker-compose"
else
echo "Fehler: weder 'docker compose' noch 'docker-compose' gefunden." >&2
exit 1
fi
usage() {
cat <<EOF
Verwaltung DynDNS Manager
$0 unlock [IP]
Hebt Login-/DynDNS-Sperren auf. Ohne IP werden ALLE Sperren entfernt,
mit IP nur die Einträge dieser Client-IP (Login und DynDNS).
$0 reset-password [BENUTZER] [PASSWORT]
Setzt das Admin-Passwort. BENUTZER ist standardmäßig "admin".
Ohne PASSWORT wird ein sicheres Zufallspasswort erzeugt und angezeigt.
Beispiele:
$0 unlock
$0 unlock 203.0.113.7
$0 reset-password
$0 reset-password admin MeinNeuesPW
EOF
}
case "${1:-}" in
unlock)
IP="${2:-}"
$DC run --rm -T -e IP="$IP" "$SERVICE" python - <<'PY'
import os
from database import get_db
ip = os.environ.get('IP', '').strip()
db = get_db()
if ip:
cur = db.execute("DELETE FROM login_attempts WHERE ip = ? OR ip = ?",
('login:' + ip, 'dyndns:' + ip))
else:
cur = db.execute("DELETE FROM login_attempts")
db.commit()
n = cur.rowcount
db.close()
print(f"{n} Sperr-Eintrag/Einträge entfernt" + (f" für {ip}." if ip else " (alle)."))
PY
;;
reset-password)
RESET_USER="${2:-admin}"
RESET_PW="${3:-}"
$DC run --rm -T -e RESET_USER="$RESET_USER" -e RESET_PW="$RESET_PW" "$SERVICE" python - <<'PY'
import os
import secrets
from database import get_db
from werkzeug.security import generate_password_hash
user = os.environ.get('RESET_USER') or 'admin'
pw = os.environ.get('RESET_PW') or ''
generated = False
if not pw:
pw = secrets.token_urlsafe(12)
generated = True
db = get_db()
cur = db.execute("UPDATE admin_users SET password_hash = ? WHERE username = ?",
(generate_password_hash(pw), user))
db.commit()
n = cur.rowcount
db.close()
if n == 0:
raise SystemExit(f"FEHLER: Admin-Benutzer '{user}' nicht gefunden.")
print(f"Passwort für '{user}' gesetzt.")
if generated:
print(f"Neues Passwort: {pw}")
PY
;;
*)
usage
exit 1
;;
esac