No description
Find a file
friloo 3a09e35097
Some checks are pending
CI / PHP Lint (push) Waiting to run
CI / PHP Lint-1 (push) Waiting to run
CI / Unit Tests & Static Analysis (push) Waiting to run
Release-Paket / ZIP bauen und veröffentlichen (push) Waiting to run
Merge pull request 'Display-Seiten individuell gestalten' (#8) from feature/kiosk-branding into main
2026-09-23 16:59:11 +00:00
.github/workflows Release-Workflow: ZIP bei jedem Merge nach main 2026-09-23 14:50:10 +00:00
admin Display-Seiten individuell gestalten 2026-09-23 16:58:54 +00:00
api API-Reife: Scopes (read/write), Rate-Limit pro Key, OpenAPI-Spec 2026-06-05 20:47:26 +00:00
assets Display-Seiten individuell gestalten 2026-09-23 16:58:54 +00:00
docker Erweiterte Features (2/2): Cleanup/DSGVO, Webhooks, REST-API, Backup, CI, Docker 2026-06-05 19:45:28 +00:00
docs/screenshots Display-Seiten individuell gestalten 2026-09-23 16:58:54 +00:00
includes Display-Seiten individuell gestalten 2026-09-23 16:58:54 +00:00
lang Display-Seiten individuell gestalten 2026-09-23 16:58:54 +00:00
tests Display-Seiten individuell gestalten 2026-09-23 16:58:54 +00:00
tools Display-Seiten individuell gestalten 2026-09-23 16:58:54 +00:00
updater Display-Seiten individuell gestalten 2026-09-23 16:58:54 +00:00
uploads Branding: Farben systemweit einstellbar + Bild-Upload statt nur URLs 2026-09-23 06:27:30 +00:00
.dockerignore Erweiterte Features (2/2): Cleanup/DSGVO, Webhooks, REST-API, Backup, CI, Docker 2026-06-05 19:45:28 +00:00
.gitattributes Release-Workflow: ZIP bei jedem Merge nach main 2026-09-23 14:50:10 +00:00
.gitignore Konsolidierung: Security-Härtung + .gitignore 2026-06-06 05:38:40 +00:00
.htaccess Sicherheits-Header, Werkzeuge und Dokumentation 2026-09-23 06:49:14 +00:00
composer.json README: Projekt liegt auf Forgejo, nicht mehr auf GitHub 2026-09-23 13:58:16 +00:00
config.php Security: OAuth-state, Verschlüsselung, Session-Timeout & weitere Härtung 2026-06-05 18:45:47 +00:00
cron_cleanup.php Webhook-Events & Health-Endpoint 2026-06-05 20:49:06 +00:00
cron_sync.php Webhook-Events & Health-Endpoint 2026-06-05 20:49:06 +00:00
cron_test.php Initial Upload 2026-04-21 17:45:58 +02:00
database.sql Display-Seiten individuell gestalten 2026-09-23 16:58:54 +00:00
docker-compose.yml Sicherheits-Header, Werkzeuge und Dokumentation 2026-09-23 06:49:14 +00:00
Dockerfile Sicherheits-Header, Werkzeuge und Dokumentation 2026-09-23 06:49:14 +00:00
forgot_password.php Barrierefreiheit und mobile Darstellung 2026-09-23 06:38:08 +00:00
health.php Webhook-Events & Health-Endpoint 2026-06-05 20:49:06 +00:00
index.php Display-Seiten: Gäste holen sich den Zugang selbst 2026-09-23 16:51:50 +00:00
install.php Entwicklerhinweis "Entwickelt von Loheide.eu" ergänzen 2026-09-23 11:21:53 +00:00
kiosk.php Display-Seiten individuell gestalten 2026-09-23 16:58:54 +00:00
login.php Entwicklerhinweis "Entwickelt von Loheide.eu" ergänzen 2026-09-23 11:21:53 +00:00
login_simple.php Barrierefreiheit und mobile Darstellung 2026-09-23 06:38:08 +00:00
logout.php Initial Upload 2026-04-21 17:45:58 +02:00
m365_callback.php Security: OAuth-state, Verschlüsselung, Session-Timeout & weitere Härtung 2026-06-05 18:45:47 +00:00
m365_debug.php Alle Frontend-Assets lokal ausliefern statt über CDNs 2026-09-23 06:23:44 +00:00
oidc_callback.php Generisches OIDC-SSO (weitere Auth-Quelle) 2026-06-06 05:47:20 +00:00
phpstan.neon Display-Seiten: Gäste holen sich den Zugang selbst 2026-09-23 16:51:50 +00:00
phpunit.xml.dist E-Mail-Retry, Voucher-Resend, Tageslimit, Docker-Politur 2026-06-05 20:56:26 +00:00
Readme.md Display-Seiten individuell gestalten 2026-09-23 16:58:54 +00:00
reset_password.php Barrierefreiheit und mobile Darstellung 2026-09-23 06:38:08 +00:00
test.php Alle Frontend-Assets lokal ausliefern statt über CDNs 2026-09-23 06:23:44 +00:00
VERSION Display-Seiten individuell gestalten 2026-09-23 16:58:54 +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.

Entwickelt von Loheide.eu

PHP MySQL UniFi OS License Version Tests Repository


Erstellter Voucher mit QR-Code Admin Dashboard

Features

  • 🎟️ Voucher-Erstellung mit sofortiger QR-Code-Anzeige, Druckvorlage und E-Mail-Versand
  • 🖥️ Display-Seiten (Kiosk) öffentliche Seite je Site, an der Gäste sich mit einem Klick selbst einen Zugang holen
  • 🎨 Jede Display-Seite eigenständig gestaltbar Logo, Hintergrundbild, Akzentfarbe, helle oder dunkle Karte
  • 📦 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

Display-Seite für Gäste

Display-Seite im Ruhezustand Display-Seite mit eigenem Bild und Farben
Ausgegebener Zugangscode auf dem Display Display-Seite einrichten
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

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/ gekapselt. Details zur Architektur und eine Rückbau-Anleitung stehen in updater/README.md.


🖥️ Display-Seiten für Gäste

Für Empfang, Lobby oder Tagungsraum lässt sich je Site eine öffentliche Seite anlegen, die auf einem Bildschirm oder Tablet läuft. Gäste tippen auf einen Knopf und bekommen sofort einen eigenen Zugangscode ohne Anmeldung, ohne Personal am Tresen.

Anlegen: Administration → Display-SeitenDisplay-Seite anlegen

Verwaltung der Display-Seiten
Einstellung Wirkung
Site für welchen Standort die Codes erzeugt werden
Voucher-Profil Laufzeit, Geräteanzahl und Bandbreite der Codes (leer = Standardwerte)
Überschrift / Text was auf dem Bildschirm steht
Codes pro Tag Obergrenze je Kalendertag (0 = unbegrenzt)
Wartezeit Abstand zwischen zwei Codes an diesem Display
Anzeigedauer danach springt der Bildschirm automatisch zurück

Jede Seite hat einen eigenen, geheimen Link (kiosk.php?k=…). Er lässt sich kopieren, als QR-Code anzeigen (praktisch, um ihn am Tablet zu öffnen) und jederzeit erneuern der alte Link ist dann sofort ungültig. Den Link nicht öffentlich verbreiten: wer ihn hat, kann im Rahmen der Limits Codes ziehen.

Auf dem Startbildschirm steht zusätzlich ein QR-Code, der auf dieselbe Seite zeigt. Gäste können sie damit am eigenen Handy öffnen praktisch bei Bildschirmen ohne Touch.

Jede Seite eigenständig gestalten

Jede Display-Seite bringt ihr eigenes Erscheinungsbild mit das Hotel am Empfang sieht anders aus als der Tagungsraum nebenan:

Einstellung Wirkung
Logo eigenes Logo auf der Karte (leer = Logo aus den Einstellungen)
Hintergrundbild formatfüllend hinter der Karte, z. B. ein Foto des Hauses
Abdunklung 090 % dunkle Ebene über dem Bild, damit die Karte lesbar bleibt
Akzentfarbe färbt den Knopf dieser Seite (leer = Farbe aus dem Design-Tab)
Karte hell oder dunkel auf Fotos wirkt die dunkle Karte meist ruhiger

Logo und Hintergrund lassen sich direkt hochladen (PNG, JPG, WEBP, GIF, SVG bis 3 MB) oder als URL hinterlegen; beim Löschen einer Display-Seite verschwinden die hochgeladenen Dateien mit.

Die ausgegebenen Codes erscheinen normal in Live Vouchers, im Reporting und im Audit-Log (Aktion „Voucher am Display geholt"), sodass jederzeit nachvollziehbar bleibt, woher ein Zugang stammt.

Display-Seiten funktionieren unabhängig vom globalen öffentlichen Modus der geheime Link ist der Zugang. Webhook-Benachrichtigungen werden für diese Codes bewusst nicht ausgelöst, sonst wäre der Slack-Kanal voll.


⚙️ 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.


🎨 Design-System

Frontend, Login-Seiten, Installer, Updater und der gesamte Admin-Bereich nutzen ein gemeinsames Stylesheet: assets/global.css.

  • Design-Tokens (:root bzw. [data-theme="dark"]) für Flächen, Text, Linien, Markenfarbe, Statusfarben, Radien, Schatten und Layout-Maße
  • Komponenten darauf aufgebaut: Buttons, Formularfelder, Cards, Tabellen, Badges, Alerts, Tabs, Pagination, Modals, Toasts, Statistik-Kacheln, Sidebar/Topbar
  • Dark Mode ausschließlich über Tokens keine !important-Overrides mehr
  • Schriftart Inter (via Google Fonts) mit System-Font-Fallback

Markenfarben ohne Code

Unter Administration → Einstellungen → Design lassen sich Akzentfarbe (hell und dunkel), Markenverlauf und Eckenradius setzen. Abgeleitete Töne Hover, weiche Flächen, Rahmen, Fokusring berechnet das System per color-mix aus der Grundfarbe; eine Farbe genügt also. Eine Live-Vorschau zeigt Button, Badge, Chip und Logo-Kachel sofort im neuen Ton.

Die Werte landen als schlanker :root-Override im Seitenkopf und gelten überall, auch auf Login-Seite, Installer und Updater. Wer lieber in CSS arbeitet, kann dieselben Variablen weiterhin in assets/global.css überschreiben:

:root {
    --accent:         #0f766e;   /* Primärfarbe (Buttons, aktive Navigation) */
    --brand-gradient: linear-gradient(135deg, #0f766e 0%, #0ea5e9 100%);
    --r-lg:           14px;      /* Eckenradius für Cards */
}

Bilder hochladen

Logo, Favicon, Login-Logo und Login-Hintergrund lassen sich direkt hochladen alternativ bleibt das URL-Feld bestehen. Die Dateien landen unter uploads/ (Docker: eigenes Volume, siehe unten). Erlaubt sind PNG, JPG, WEBP, GIF und SVG bis 3 MB; SVGs werden vor dem Speichern von Skripten und externen Verweisen befreit, und im Upload-Ordner sperrt eine .htaccess die PHP-Ausführung.

Assets ohne Drittanbieter

Schrift (Inter), Icons (Font Awesome), Diagramme (Chart.js), QR-Codes und der WYSIWYG-Editor (TinyMCE) liegen unter assets/vendor/ und kommen vom eigenen Server. Das hält Besucher-IPs bei Ihnen und die Oberfläche funktioniert auch dort, wo das Netz keinen Weg nach außen hat. Details und Aktualisierungs-Hinweise: assets/vendor/README.md.

Alle Asset-URLs tragen einen Versionsstempel (?v=…), damit Browser nach einem Update nicht die alten Dateien aus dem Cache verwenden.

Login-Seite individualisieren

Unter Administration → Einstellungen → Login-Seite lässt sich die Anmeldeseite ohne Code-Änderung an das eigene Haus anpassen. Leere Felder verwenden jeweils den Standardwert eine frische Installation sieht also unverändert aus.

Einstellung Wirkung
Linke Bildspalte anzeigen Split-Screen an/aus. Aus = zentrierte Anmeldekarte
Firmenname Name neben dem Logo bzw. in der Fußzeile (leer = Anwendungstitel)
Logo (URL) Eigenes Logo in der Bildspalte (leer = allgemeines Logo)
Überschrift / Beschreibungstext Claim in der Bildspalte
Stichpunkte Liste mit Haken ein Stichpunkt pro Zeile, leer = keine Liste
Fußzeile z. B. © 2026 Muster GmbH · Datenschutz · Impressum
Hintergrundbild (URL) Formatfüllendes Bild der Bildspalte
Verlauf Start-/Endfarbe Farbverlauf, wenn kein Bild gesetzt ist
Abdunklung (%) Dunkle Ebene über dem Bild, damit der Text lesbar bleibt

Über „Vorschau öffnen" lässt sich die Login-Seite als angemeldeter Administrator ansehen (login.php?preview=1), ohne sich abzumelden.


🛡️ 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)

Mitgeliefert wird eine .htaccess im Projektstamm mit Sicherheits-Headern (X-Content-Type-Options, X-Frame-Options, Referrer-Policy, Permissions-Policy und einer Content-Security-Policy). Da alle Assets lokal liegen, erlaubt die CSP nur noch die eigene Herkunft externe Verbindungen bleiben lediglich für hCaptcha offen, falls es aktiviert wird. Ordner wie includes/, tools/, tests/ und uploads/ schützen sich über eigene .htaccess-Dateien.

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:

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; } }
-- 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>"}

🧰 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 <key> oder X-API-Key.

# 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=<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:
    0 3 * * * curl -s "https://ihre-domain.de/cron_cleanup.php?token=IHR_CRON_TOKEN"
    

🐳 Docker

# 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:

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:

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.

Tests und statische Analyse:

composer install
vendor/bin/phpunit          # 29 Tests (Crypto, TOTP, API-Keys, Upload, Ui)
vendor/bin/phpstan analyse  # Level 5

Die Versionsnummer steht in der Datei VERSION im Projektstamm. Sie wird im Admin-Bereich unten in der Seitenleiste angezeigt und benennt das Release-Paket für eine neue Version also dort (und im Badge oben) anheben.

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:

https://git.loheide.cloud/friloo/Unifi-Voucher-Tool

# 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

Fertige Pakete

Jeder Merge nach main erzeugt automatisch ein installierbares ZIP (.github/workflows/release.yml) und hängt es an das rollende Vorab-Release latest-main:

https://git.loheide.cloud/friloo/Unifi-Voucher-Tool/releases

Das Paket enthält nur die Laufzeit-Dateien docs/, tests/, tools/ und die CI-Konfiguration bleiben draußen (rund 1,4 MB). Wird ein Tag v* gepusht, entsteht daraus ein reguläres Release mit derselben Mechanik.

Beim Update einer bestehenden Installation config.php, uploads/ und updater/storage/ nicht überschreiben oder gleich den eingebauten Updater verwenden, der genau diese Pfade schützt.

Voraussetzung ist ein registrierter Forgejo-Actions-Runner; ohne Runner bleiben die Workflows in der Warteschlange stehen. Compose-Datei und Anleitung dafür liegen in tools/runner/.

Mitwirken

Fehlerberichte und Änderungsvorschläge laufen über die Issues und Pull Requests dort. Für die Kommandozeile eignet sich tea, die Gitea-/Forgejo-CLI:

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

  • Voucher-Templates (vordefinierte Laufzeiten)
  • Bulk-Voucher-Erstellung
  • Mehrsprachigkeit (DE/EN)
  • Dark Mode
  • Passwort-Reset
  • Audit-Log
  • Auto-Updater mit DB-Migrationen
  • REST-API mit API-Schlüsseln
  • 2FA (TOTP), Webhooks, Bandbreitenlimits
  • Docker-Container
  • Erweiterte Reporting-Funktionen (CSV/PDF) + Health-Endpoint
  • 2FA-Recovery-Codes, API-Scopes/Rate-Limit/OpenAPI, Test-Suite (PHPUnit/PHPStan)
  • Gemeinsames Design-System für Frontend, Login und Backend
  • Branding über die Oberfläche (Farben, Logo, Login-Seite)
  • Assets lokal ausliefern (keine Drittanbieter-CDNs)
  • Vollständige englische Übersetzung des Admin-Bereichs
  • Display-Seiten: Selbstbedienung für Gäste am Bildschirm

Version 2.8.0 · Autor: Friederich Loheide · Lizenz: MIT

Entwickelt von Loheide.eu