# 🎫 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)**






---
---
## ✨ 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
### Administration
### REST-API, 2FA & Integrationen
### Updater & 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://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:
> 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
vendor/bin/phpstan analyse
```
## 🗺️ 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)**