# 🎫 UniFi Voucher Management System **Webbasiertes WLAN-Voucher-Management für UniFi OS** – mit Multi-Site-Support, Benutzerverwaltung, Microsoft-365-Login und integriertem Auto-Updater. Entwickelt von **[Loheide.eu](https://loheide.eu)** ![PHP](https://img.shields.io/badge/PHP-7.4%2B-777BB4?logo=php&logoColor=white) ![MySQL](https://img.shields.io/badge/MySQL-5.7%2B%20%2F%20MariaDB-4479A1?logo=mysql&logoColor=white) ![UniFi OS](https://img.shields.io/badge/UniFi%20OS-7.0%2B-0559C9?logo=ubiquiti&logoColor=white) ![License](https://img.shields.io/badge/Lizenz-MIT-green) ![Version](https://img.shields.io/badge/Version-2.6.0-blueviolet) ![Tests](https://img.shields.io/badge/Tests-PHPUnit%20%2B%20PHPStan-brightgreen) [![Repository](https://img.shields.io/badge/Code-git.loheide.cloud-4b3ec4)](https://git.loheide.cloud/friloo/Unifi-Voucher-Tool)
---
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 - 🔒 **2FA (TOTP)** – optional, mit Recovery-Codes & erzwingbarer Admin-Pflicht - 📈 **Reporting** – Auswertungen mit Charts und CSV-/PDF-Export - 🩺 **Health-Endpoint** (`/health.php`) für Monitoring/Uptime - 🔑 **Passwort-Reset** per E-Mail (token-basiert, zeitlich begrenzt) - 🚦 **Bandbreiten- & Datenlimits** pro Voucher/Profil (UniFi QoS) - 🧰 **REST-API mit API-Schlüsseln** – Scopes (read/write), Rate-Limit, OpenAPI-Spec - 🪪 **Single Sign-On** via generisches OpenID Connect (zusätzlich zu M365) - 📲 **SMS-Versand** der Codes (Twilio) · **CSV-Batch-Import** von Vouchern - 🤖 **CAPTCHA** (Rechenaufgabe oder hCaptcha) im öffentlichen Modus - 🗄️ **DB-gestützte Sessions** (opt-in) mit „überall abmelden" - 🔔 **Webhooks** (Slack / Teams / generisch) für Erstellung, Ausfälle, neue Login-IP - 🧹 **Auto-Cleanup & DSGVO** – Aufbewahrungsfristen per Cron - 💾 **Config-Backup & -Restore** (JSON Export/Import) - 🐳 **Docker** – Dockerfile + docker-compose (MariaDB) - 🌍 **Öffentlicher Modus** – optional ohne Login nutzbar (mit CSRF-Schutz & Throttle) - 🎨 **Einheitliches Design-System** – ein Stylesheet für Frontend, Login und Backend (Tokens, Komponenten, Light/Dark) - 🏷️ **Login-Seite individualisierbar** – Firmenname, Logo, Texte, Hintergrundbild bzw. Farbverlauf - 🖌️ **Eigene Markenfarben** – Akzentfarbe, Verlauf und Eckenradius wirken auf die gesamte Oberfläche - ⬆️ **Bild-Upload** für Logo, Favicon und Login-Hintergrund (kein externes Hosting nötig) - 🔒 **Keine externen CDNs** – Schrift, Icons, Diagramme und Editor werden lokal ausgeliefert (DSGVO, Offline-Netze) - ♿ **Barrierearm** – Kontraste nach WCAG AA, Sprungmarke, aria-Beschriftungen, `prefers-reduced-motion` - 📱 **Mobil nutzbar** – Tabellen werden auf schmalen Geräten zu Karten - 🌗 **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 > Alle Screenshots stammen aus der Oberfläche in Version 2.5.0 (neues Design-System). ### Anmeldung & Voucher-Erstellung
Anmeldung Anmeldung mit eigenem Branding
Voucher erstellen Einstellungen der Login-Seite
Voucher-Ergebnis mit QR-Code Bulk-Voucher-Erstellung
### Administration
Dashboard Dashboard im Dark Mode
Live-Voucher-Verwaltung Einstellungen
Markenfarben einstellen Ansicht auf dem Smartphone
### REST-API, 2FA & Integrationen
API-Schlüssel-Verwaltung Integration & Wartung
Zwei-Faktor-Authentifizierung
### Updater & Wartungsmodus
Updater – Ausgangszustand Auto-Updater mit verfügbarem Update
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 ```bash git clone https://git.loheide.cloud/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/`](updater/) gekapselt. > Details zur Architektur und eine Rückbau-Anleitung stehen in > [`updater/README.md`](updater/README.md). --- ## ⚙️ Konfiguration ### `config.php` Wird automatisch durch den Installer erstellt: ```php **Apache:** `AllowOverride All` muss für das Verzeichnis gesetzt sein, sonst > werden die `.htaccess`-Dateien ignoriert. Das mitgelieferte Docker-Image > erledigt das bereits. Für **Nginx** entspricht das: ```nginx add_header X-Content-Type-Options "nosniff" always; add_header X-Frame-Options "SAMEORIGIN" always; add_header Referrer-Policy "strict-origin-when-cross-origin" always; add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self'; frame-ancestors 'self'" always; location ~ ^/(includes|tools|tests)/ { deny all; } location ~ ^/updater/(storage|migrations)/ { deny all; } location ~ ^/(config\.php|database\.sql)$ { deny all; } location ^~ /uploads/ { location ~ \.php$ { deny all; } } ``` ```sql -- 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) ```http # Login POST /api/auth/login Body: {"username": "admin", "password": "password"} Response-Header: X-CSRF-Token: # Voucher erstellen POST /proxy/network/api/s/{site_id}/cmd/hotspot X-CSRF-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": ""} ``` --- ## 🧰 REST-API Voucher lassen sich programmatisch erstellen (z. B. aus Buchungssystemen oder Self-Service-Terminals). Schlüssel werden unter **Administration → API-Schlüssel** verwaltet. Authentifizierung per `Authorization: Bearer ` oder `X-API-Key`. ```bash # Voucher erstellen curl -X POST https://ihre-domain.de/api/vouchers.php \ -H "Authorization: Bearer uvt_…" \ -H "Content-Type: application/json" \ -d '{"site_id":1,"name":"API Gast","max_uses":1,"expire_minutes":480, "qos":{"down":10000,"up":2000,"quota_mb":500}}' # Sites auflisten curl https://ihre-domain.de/api/sites.php -H "X-API-Key: uvt_…" # Voucher einer Site abrufen curl "https://ihre-domain.de/api/vouchers.php?site_id=1" -H "X-API-Key: uvt_…" ``` | Methode | Endpunkt | Zweck | |---|---|---| | `POST` | `/api/vouchers.php` | Voucher erstellen (optional mit QoS-Limits) | | `GET` | `/api/vouchers.php?site_id=` | Voucher einer Site auflisten | | `GET` | `/api/sites.php` | Aktive Sites auflisten | ## 🔒 2FA, Webhooks & Wartung - **2FA:** Unter **Administration → Sicherheit (2FA)** aktivierbar – QR-Code scannen, Code bestätigen. Danach wird bei jeder Anmeldung ein Authenticator- Code abgefragt. - **Webhooks & Trusted-Proxy & Datenhaltung:** unter **Administration → Integration & Wartung** konfigurierbar. - **Auto-Cleanup (DSGVO):** täglicher Cron, löscht abgelaufene Voucher, Audit-Log, Login-Versuche nach einstellbaren Fristen: ```bash 0 3 * * * curl -s "https://ihre-domain.de/cron_cleanup.php?token=IHR_CRON_TOKEN" ``` ## 🐳 Docker ```bash # APP_KEY erzeugen und in docker-compose.yml eintragen: php -r 'echo base64_encode(random_bytes(32))."\n";' docker compose up -d # App auf http://localhost:8080 ``` Das Schema wird beim ersten Start automatisch in MariaDB geladen; danach den Installer (`/install.php`) für den Admin-Account aufrufen oder Config per ENV setzen (`DB_*`, `APP_KEY`). Hochgeladene Logos und Hintergründe liegen im Volume `uploads` und überstehen damit ein Image-Update. Bei eigener Apache-/Nginx-Installation muss `uploads/` für den Webserver beschreibbar sein: ```bash chown -R www-data:www-data uploads updater/storage ``` --- ## 🧪 Entwicklung Für Screenshots und einen schnellen Durchlauf aller Seiten gibt es eine Demo-Instanz **ohne Datenbank** – `Database` und `Auth` werden durch Stubs mit festen Beispieldaten ersetzt: ```bash python3 tools/demo/build.py /tmp/uvt-demo php -S 127.0.0.1:8123 -t /tmp/uvt-demo & # Bilder in docs/screenshots neu erzeugen (benötigt headless Chromium) CHROME_BIN=/usr/bin/chromium python3 tools/screenshots.py ``` Details und die verfügbaren Demo-Zustände: [`tools/README.md`](tools/README.md). Tests und statische Analyse: ```bash composer install vendor/bin/phpunit # 29 Tests (Crypto, TOTP, API-Keys, Upload, Ui) vendor/bin/phpstan analyse # Level 5 ``` Die Pipeline (`.github/workflows/ci.yml`) führt zusätzlich einen Syntax-Check über alle PHP-Dateien aus und prüft, ob `lang/de.php` und `lang/en.php` dieselben Schlüssel enthalten und jeder im Code verwendete Schlüssel existiert. Dieselben Schritte lassen sich lokal ausführen. --- ## 📦 Repository & Mitwirken Der Quellcode liegt auf der eigenen Forgejo-Instanz – **nicht** auf GitHub: **** ```bash # HTTPS git clone https://git.loheide.cloud/friloo/Unifi-Voucher-Tool.git # SSH (Port 2222) git clone ssh://git@git.loheide.cloud:2222/friloo/Unifi-Voucher-Tool.git ``` Fehlerberichte und Änderungsvorschläge laufen über die **Issues** und **Pull Requests** dort. Für die Kommandozeile eignet sich [`tea`](https://gitea.com/gitea/tea), die Gitea-/Forgejo-CLI: ```bash tea pr create # Pull Request öffnen tea issues ls # offene Tickets ansehen ``` > Die Workflows unter `.github/workflows/` werden von Forgejo Actions > mitgelesen; das Badge oben ist bewusst statisch, solange kein Runner > registriert ist. `docker-publish.yml` veröffentlicht nach `ghcr.io` und > stammt noch aus der GitHub-Zeit – für den Forgejo-Betrieb entweder auf die > eigene Registry umstellen oder entfernen. Der **Auto-Updater** ist davon unabhängig: er zieht seine Pakete über `update.loheide.eu` (Channels `stable` und `development`) und nicht direkt aus dem Git-Hoster. --- ## 🗺️ Roadmap - [x] Voucher-Templates (vordefinierte Laufzeiten) - [x] Bulk-Voucher-Erstellung - [x] Mehrsprachigkeit (DE/EN) - [x] Dark Mode - [x] Passwort-Reset - [x] Audit-Log - [x] Auto-Updater mit DB-Migrationen - [x] REST-API mit API-Schlüsseln - [x] 2FA (TOTP), Webhooks, Bandbreitenlimits - [x] Docker-Container - [x] Erweiterte Reporting-Funktionen (CSV/PDF) + Health-Endpoint - [x] 2FA-Recovery-Codes, API-Scopes/Rate-Limit/OpenAPI, Test-Suite (PHPUnit/PHPStan) - [x] Gemeinsames Design-System für Frontend, Login und Backend - [x] Branding über die Oberfläche (Farben, Logo, Login-Seite) - [x] Assets lokal ausliefern (keine Drittanbieter-CDNs) - [x] Vollständige englische Übersetzung des Admin-Bereichs ---
**Version 2.6.0** · Autor: **Friederich Loheide** · Lizenz: **MIT** Entwickelt von **[Loheide.eu](https://loheide.eu)**