No description
Find a file
Claude 6e19958a37
Security-, Bugfix- und UX-Überarbeitung auf Basis des Code-Reviews
Sicherheit:
- Bulk-Erstellung serverseitig auf eingeloggte Nutzer beschränkt;
  expire_minutes wird validiert (anonym: nur Default/Template-Werte,
  eingeloggt: max. 1 Jahr)
- IP-basiertes Rate-Limit über neue Tabelle request_throttle
  (Voucher-Erstellung + Passwort-Reset-Anfragen), Session-Fallback
  für Alt-Installationen; Migration 0002
- session_regenerate_id() nach Login, Secure-Cookie-Flag bei HTTPS
- Admin-/Aktiv-Status wird pro Request live aus der DB geprüft
  (Rechteentzug & Deaktivierung wirken sofort); Schutz vor
  Selbst-Degradierung im Benutzer-Edit
- Alle state-ändernden Admin-Aktionen von GET auf POST umgestellt
  (kein CSRF-Token mehr in URLs)
- login_simple.php (Legacy, Debug-Leak) entfernt; cron_test.php nur
  noch für Admins; .htaccess auf Apache-2.4-Syntax inkl. cron_test.php
- M365 Client Secret wird nicht mehr ins Formular zurückgegeben
- Updater: Zip-Slip-/Pfad-Traversal-Schutz, Backup vor dem Anwenden
  mit automatischem Rollback bei Fehlern, AuditLogger-Bug behoben
- cron_sync: Token-Vergleich mit hash_equals; login_attempts-Pruning
- CSV-Export gegen Excel-Formula-Injection abgesichert

Bugfixes:
- M365-Login: Fallback auf userPrincipalName, wenn Graph kein 'mail'
  liefert (Nutzer ohne Exchange-Postfach konnten sich nie anmelden)
- PRG-Pattern überall: F5 erzeugt keine Duplikat-Voucher und
  wiederholt keine Admin-Aktionen (Session-Flash-Messages)
- QR-Code nicht mehr invertiert (schwarz auf weiß, scanbar)
- Bulk-Erstellung nutzt den UniFi 'n'-Parameter: 1 API-Call statt
  n× Login + Voucherlisten-Abruf; exaktes Code-Matching per
  create_time statt "global neuester Voucher"
- Mailer: doppelte Zeilenumbrüche behoben, AUTH nur mit Credentials,
  SMTP-Dot-Stuffing, CLI-sicherer EHLO-Host
- forgot_password: System-URL-Auto-Detect (Reset-Link war sonst
  relativ/kaputt) + Rate-Limit
- Audit-Log-Labels an tatsächliche Action-Keys angepasst;
  Voucher-Erstellung (einzeln & bulk) wird jetzt auditiert
- Site-Edit testet die Verbindung auch ohne Passwortänderung

UX/UI:
- Alert-/Badge-Styles zentral in global.css mit Dark-Mode-Variablen
  (vorher 7× dupliziert mit hart codierten Hellfarben)
- Sticky-Formulare + Tab-Erhalt nach Validierungsfehlern (Bulk),
  Settings kehren nach dem Speichern zum aktiven Tab zurück
- Gültigkeit menschenlesbar (z.B. "8 Stunden" statt "480 Minuten")
- Voucher-Name-Default "Gast/Guest" im öffentlichen Modus
- Favicon auch auf Login-/öffentlichen Seiten
- Verbindungstest-Button pro Site-Karte (Health-Check)
- i18n-Pass: Confirm-Dialoge, Toasts, Fehl-/Erfolgsmeldungen in de/en
- Sprachumschalter ohne fetch+reload (kein Re-Submit-Dialog)
- A11y: Esc schließt Modals, aria-live für Toasts, aria-labels auf
  Icon-Buttons; APP_KEY-Warnbanner im Dashboard
- Dashboard-Sync: set_time_limit passend zur Site-Anzahl;
  Voucher-Sync mit Map statt SELECT pro Voucher

Tooling:
- GitHub-Actions-Workflow: PHP-Lint aller Dateien + de/en-Key-Parität

https://claude.ai/code/session_01KKVpVPJjrTKGoRgpJcySD4
2026-06-09 19:43:13 +00:00
.github/workflows Security-, Bugfix- und UX-Überarbeitung auf Basis des Code-Reviews 2026-06-09 19:43:13 +00:00
admin Security-, Bugfix- und UX-Überarbeitung auf Basis des Code-Reviews 2026-06-09 19:43:13 +00:00
assets Security-, Bugfix- und UX-Überarbeitung auf Basis des Code-Reviews 2026-06-09 19:43:13 +00:00
docs/screenshots Updater-Migration für Feature-Tabellen + README um neue Features erweitern 2026-06-05 19:16:55 +00:00
includes Security-, Bugfix- und UX-Überarbeitung auf Basis des Code-Reviews 2026-06-09 19:43:13 +00:00
lang Security-, Bugfix- und UX-Überarbeitung auf Basis des Code-Reviews 2026-06-09 19:43:13 +00:00
updater Security-, Bugfix- und UX-Überarbeitung auf Basis des Code-Reviews 2026-06-09 19:43:13 +00:00
config.php Security: OAuth-state, Verschlüsselung, Session-Timeout & weitere Härtung 2026-06-05 18:45:47 +00:00
cron_sync.php Security-, Bugfix- und UX-Überarbeitung auf Basis des Code-Reviews 2026-06-09 19:43:13 +00:00
cron_test.php Security-, Bugfix- und UX-Überarbeitung auf Basis des Code-Reviews 2026-06-09 19:43:13 +00:00
database.sql Security-, Bugfix- und UX-Überarbeitung auf Basis des Code-Reviews 2026-06-09 19:43:13 +00:00
forgot_password.php Security-, Bugfix- und UX-Überarbeitung auf Basis des Code-Reviews 2026-06-09 19:43:13 +00:00
index.php Security-, Bugfix- und UX-Überarbeitung auf Basis des Code-Reviews 2026-06-09 19:43:13 +00:00
install.php Security-, Bugfix- und UX-Überarbeitung auf Basis des Code-Reviews 2026-06-09 19:43:13 +00:00
login.php Security-, Bugfix- und UX-Überarbeitung auf Basis des Code-Reviews 2026-06-09 19:43:13 +00:00
logout.php Initial Upload 2026-04-21 17:45:58 +02:00
m365_callback.php Security-, Bugfix- und UX-Überarbeitung auf Basis des Code-Reviews 2026-06-09 19:43:13 +00:00
m365_debug.php Security: OAuth-state, Verschlüsselung, Session-Timeout & weitere Härtung 2026-06-05 18:45:47 +00:00
Readme.md Updater-Migration für Feature-Tabellen + README um neue Features erweitern 2026-06-05 19:16:55 +00:00
reset_password.php Security-, Bugfix- und UX-Überarbeitung auf Basis des Code-Reviews 2026-06-09 19:43:13 +00:00
test.php Security: OAuth-state, Verschlüsselung, Session-Timeout & weitere Härtung 2026-06-05 18:45:47 +00:00

🎫 UniFi Voucher Management System

Webbasiertes WLAN-Voucher-Management für UniFi OS mit Multi-Site-Support, Benutzerverwaltung, Microsoft-365-Login und integriertem Auto-Updater.

PHP MySQL UniFi OS License Version


Erstellter Voucher mit QR-Code Admin Dashboard

Features

  • 🎟️ Voucher-Erstellung mit sofortiger QR-Code-Anzeige, Druckvorlage und E-Mail-Versand
  • 📦 Bulk-Erstellung bis zu 20 Vouchers auf einmal, inkl. Sammeldruck-Layout
  • 🧩 Voucher-Profile/Templates vordefinierte Laufzeiten & Gerätelimits per Schnellauswahl
  • 🏢 Multi-Site-Support beliebig viele UniFi-Standorte zentral verwalten
  • 👥 Benutzerverwaltung mit granularer Site-Zugriffskontrolle
  • 🔐 Authentifizierung via lokale Accounts oder Microsoft 365 OAuth
  • 🔑 Passwort-Reset per E-Mail (token-basiert, zeitlich begrenzt)
  • 🌍 Öffentlicher Modus optional ohne Login nutzbar (mit CSRF-Schutz & Throttle)
  • 🌗 Dark Mode umschaltbar, Einstellung wird im Browser gespeichert
  • 🌐 Mehrsprachig Deutsch / Englisch per Umschalter (lang/)
  • 📱 Responsive Admin-Layout mit Hamburger-Menü & Sidebar-Overlay
  • 📊 Admin-Dashboard mit Live-Statistiken und Sync-Funktion
  • 📝 Audit-Log nachvollziehbare Protokollierung von Login & Änderungen (mit Filter)
  • 📥 CSV-Export aller Vouchers pro Site
  • 🔄 Integrierter Auto-Updater Updates & DB-Migrationen per Klick aus dem Admin-Bereich
  • 🛡️ Security-by-default: CSRF-Schutz, bcrypt-Passwörter, Prepared Statements, Login-Rate-Limiting, OAuth-State-Validierung, Verschlüsselung sensibler Daten

📸 Screenshots

Anmeldung & Voucher-Erstellung

Login mit Microsoft 365 Voucher erstellen Voucher-Ergebnis

Bulk-Erstellung & Dark Mode

Bulk-Voucher-Erstellung Dashboard im Dark Mode

Administration & Updater

Dashboard Auto-Updater
Updater – Ausgangszustand Wartungsmodus

📋 Anforderungen

Komponente Version
PHP 7.4+ (mit PDO, PDO_MySQL, cURL, mbstring, JSON; empfohlen: OpenSSL/libsodium, Zip)
Datenbank MySQL 5.7+ / MariaDB 10.2+
Webserver Apache / Nginx
UniFi Network Application 7.0+ mit UniFi OS (z. B. UDM, UDR, UniFi OS Server)

🚀 Installation

git clone https://github.com/friloo/unifi-voucher-tool.git
cd unifi-voucher-tool
  1. Dateien auf den Webserver hochladen
  2. https://ihre-domain.de/install.php öffnen
  3. Den 5-Schritte-Assistenten durchlaufen:
    1. Datenbank-Verbindungsdaten
    2. Administrator-Account
    3. Allgemeine Einstellungen (Titel, Logo, öffentlicher Zugriff)
    4. Microsoft 365 Integration (optional)
    5. Installation abschließen
  4. install.php nach erfolgreicher Installation löschen

🔒 Der Installer erzeugt automatisch einen zufälligen APP_KEY (für die Verschlüsselung der UniFi-Passwörter) und eine .htaccess, die sensible Dateien sperrt. Ein erneuter Aufruf von install.php?reinstall=1 ist nur für angemeldete Administratoren möglich.

Sites konfigurieren

  1. Administration → Sites verwalten → Neue Site hinzufügen
  2. Felder ausfüllen:
    • Name: Anzeigename (z. B. „Hauptgebäude")
    • Site ID: UniFi Site ID (meist default)
    • Controller URL: https://unifi.example.com:11443
    • Benutzername / Passwort: UniFi Admin-Zugangsdaten
  3. Verbindung testen klicken, dann speichern

Voucher erstellen

  1. Startseite öffnen (Login je nach Konfiguration optional)
  2. Voucher-Name, Anzahl Geräte und Standort wählen
  3. Voucher erstellen Code und QR-Code werden sofort angezeigt
  4. Code per E-Mail senden oder ausdrucken

🔄 Auto-Updater

Das System bringt einen vollständig integrierten Updater mit, der Quellcode und Datenbank-Migrationen über einen zentralen Update-Proxy nachzieht ganz ohne SSH oder manuelles git pull.

[diese Instanz]  ←HTTPS→  [Update-Proxy]  ←pull→  [Git-Repo]

Aufruf: Administration → System-Update (/admin/update.php)

  • 🔍 „Auf Updates prüfen" zeigt verfügbare Versionen inkl. Changelog
  • ⬇️ „Update installieren" spielt das Update ein mit Wartungsseite, geschützten Pfaden (config.php, Uploads, …), automatischen DB-Migrationen und OPcache-Reset
  • 🔀 Channel-Auswahl zwischen stable und development
  • 📊 Migrations-Status in einem eigenen Tab inkl. Button „Ausstehende Migrationen ausführen" (legt z. B. neue Tabellen für bestehende Installationen an, ohne dass ein Code-Update nötig ist)

Während eines Updates wird die Anwendung kurz in den Wartungsmodus versetzt:

Wartungsmodus

Der Updater ist vollständig isoliert im Ordner updater/ gekapselt. Details zur Architektur und eine Rückbau-Anleitung stehen in updater/README.md.


⚙️ Konfiguration

config.php

Wird automatisch durch den Installer erstellt:

<?php
define('DB_HOST', 'localhost');
define('DB_NAME', 'unifi_voucher');
define('DB_USER', 'username');
define('DB_PASS', 'password');
define('APP_KEY', '...');            // Schlüssel für Verschlüsselung-at-rest
define('SESSION_LIFETIME', 3600);    // Session-Timeout in Sekunden
date_default_timezone_set('Europe/Berlin');

Microsoft 365 OAuth (optional)

  1. Im Azure Portal eine App-Registrierung anlegen
  2. Umleitungs-URI: https://ihre-domain.de/m365_callback.php
  3. API-Berechtigungen: openid, profile, email, User.Read
  4. Client ID, Client Secret und Tenant ID in Administration → Einstellungen eintragen

Cron-Job (empfohlen)

Automatische Synchronisation alle 30 Minuten:

*/30 * * * * curl -s "https://ihre-domain.de/cron_sync.php?token=IHR_CRON_TOKEN"

Den Token finden Sie unter Administration → Einstellungen → Cron.


🛡️ Sicherheit

Das Tool ist auf einen sicheren Standardbetrieb ausgelegt:

Schutz Umsetzung
Passwörter bcrypt (password_hash) für Accounts
UniFi-Passwörter Verschlüsselt-at-rest (AES-256-GCM / libsodium) über APP_KEY
SQL-Injection Durchgängig Prepared Statements (PDO)
CSRF Token für alle schreibenden Aktionen auch im öffentlichen Modus
OAuth state-Validierung gegen Login-CSRF
Brute-Force Login-Rate-Limiting + Throttle der öffentlichen Voucher-Erstellung
Sessions HttpOnly, SameSite, strict mode + absolutes Timeout
Fehler display_errors aus, log_errors an (kein Info-Leak)

Empfohlene zusätzliche Härtung am Server:

# .htaccess  sensible Dateien sperren (wird vom Installer erzeugt)
<FilesMatch "^(config\.php|database\.sql|install\.php|test\.php|m365_debug\.php|.*\.md)$">
    Require all denied
</FilesMatch>
-- Dedizierter Datenbank-Benutzer mit minimalen Rechten
CREATE USER 'unifi_voucher'@'localhost' IDENTIFIED BY 'sicheres_passwort';
GRANT SELECT, INSERT, UPDATE, DELETE ON unifi_voucher.* TO 'unifi_voucher'@'localhost';

🩺 Problembehandlung

Login funktioniert nicht
  • Datenbankverbindung und PHP-Session-Konfiguration prüfen
  • Fehler werden ins PHP-Error-Log geschrieben (nicht mehr in den Browser)
UniFi-Verbindung schlägt fehl
  • Controller-URL im Browser testen
  • Port 11443 für UniFi OS verwenden (nicht 8443)
  • Benutzername, Passwort und Site ID prüfen
  • cURL-Extension muss aktiviert sein
UniFi OS: HTTP 404 oder 401
  • Login-Endpunkt ist /api/auth/login (nicht /api/login)
  • API-Pfade benötigen Präfix /proxy/network/api/s/{site}/...
  • Älterer UniFi Network Controller (ohne UniFi OS) wird ab Version 2.1.0 nicht mehr unterstützt
Microsoft 365 Login funktioniert nicht
  • Redirect URI in Azure AD prüfen
  • Client ID, Secret und Tenant ID kontrollieren
  • Diagnose unter m365_debug.php (nur als Admin erreichbar)

📡 API-Dokumentation (UniFi OS)

# Login
POST /api/auth/login
Body: {"username": "admin", "password": "password"}
Response-Header: X-CSRF-Token: <token>

# Voucher erstellen
POST /proxy/network/api/s/{site_id}/cmd/hotspot
X-CSRF-Token: <token>
Body: {"cmd": "create-voucher", "expire": 480, "n": 1, "note": "Name", "quota": 1}

# Vouchers abrufen
GET /proxy/network/api/s/{site_id}/stat/voucher

# Voucher löschen
POST /proxy/network/api/s/{site_id}/cmd/hotspot
Body: {"cmd": "delete-voucher", "_id": "<voucher_id>"}

🗺️ Roadmap

  • Voucher-Templates (vordefinierte Laufzeiten)
  • Bulk-Voucher-Erstellung
  • Mehrsprachigkeit (DE/EN)
  • Dark Mode
  • Passwort-Reset
  • Audit-Log
  • Auto-Updater mit DB-Migrationen
  • Erweiterte Reporting-Funktionen
  • Docker-Container

Version 2.1.0 · Autor: Friederich Loheide · Lizenz: MIT