Sicherheits-Header, Werkzeuge und Dokumentation

Sicherheit:
- .htaccess im Projektstamm mit X-Content-Type-Options, X-Frame-Options,
  Referrer-Policy, Permissions-Policy und einer Content-Security-Policy;
  da alle Assets lokal liegen, erlaubt sie nur noch die eigene Herkunft
  (Ausnahme: hCaptcha, falls aktiviert)
- includes/, tools/, tests/, updater/storage und uploads/ schützen sich
  über eigene .htaccess-Dateien – auch bei Installation im Unterordner
- Docker: AllowOverride All, damit diese Regeln überhaupt greifen, und
  ein Volume für uploads/, damit Logos ein Image-Update überstehen

Werkzeuge:
- tools/screenshots.py erzeugt alle Bilder in docs/screenshots aus der
  Demo-Instanz; tools/README.md beschreibt beides
- Einstellungs-Tabs sind per ?tab=… direkt verlinkbar (serverseitig, also
  auch ohne JavaScript)

Dokumentation: Readme um Markenfarben, Bild-Upload, lokale Assets,
Sicherheits-Header (inkl. Nginx-Entsprechung) und einen Abschnitt
"Entwicklung" ergänzt; Screenshots neu erzeugt, Version 2.6.0.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Friederich Loheide 2026-09-23 06:49:14 +00:00
parent e28527ed91
commit 36e06ac817
30 changed files with 307 additions and 36 deletions

115
Readme.md
View file

@ -8,7 +8,7 @@
![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.5.0-blueviolet)
![Version](https://img.shields.io/badge/Version-2.6.0-blueviolet)
![CI](https://github.com/friloo/unifi-voucher-tool/actions/workflows/ci.yml/badge.svg)
</div>
@ -47,6 +47,11 @@
- 🌍 **Ö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
@ -92,6 +97,11 @@
<img src="docs/screenshots/settings.png" alt="Einstellungen" width="48%">
</div>
<div align="center">
<img src="docs/screenshots/settings-branding.png" alt="Markenfarben einstellen" width="48%">
<img src="docs/screenshots/mobile-vouchers.png" alt="Ansicht auf dem Smartphone" width="22%">
</div>
### REST-API, 2FA & Integrationen
<div align="center">
@ -249,21 +259,44 @@ gemeinsames Stylesheet: **`assets/global.css`**.
- **Dark Mode** ausschließlich über Tokens keine `!important`-Overrides mehr
- **Schriftart** Inter (via Google Fonts) mit System-Font-Fallback
Eigenes Branding lässt sich meist mit wenigen Zeilen umsetzen z. B. in einer
eigenen CSS-Datei oder direkt in `assets/global.css`:
### 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:
```css
:root {
--accent: #0f766e; /* Primärfarbe (Buttons, aktive Navigation) */
--accent-hover: #0d5f59;
--accent-soft: #e6f4f2; /* Flächen für aktive Zustände */
--brand-gradient: linear-gradient(135deg, #0f766e 0%, #0ea5e9 100%);
--r-lg: 14px; /* Eckenradius für Cards */
}
```
Logo und Favicon werden nicht über CSS, sondern unter
**Administration → Einstellungen → Allgemein** gesetzt.
### 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`](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
@ -303,13 +336,30 @@ Das Tool ist auf einen sicheren Standardbetrieb ausgelegt:
| **Sessions** | HttpOnly, SameSite, strict mode + absolutes Timeout |
| **Fehler** | `display_errors` aus, `log_errors` an (kein Info-Leak) |
Empfohlene zusätzliche Härtung am Server:
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
# .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>
> **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
@ -432,6 +482,40 @@ 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)
@ -447,11 +531,14 @@ setzen (`DB_*`, `APP_KEY`).
- [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
---
<div align="center">
**Version 2.5.0** · Autor: **Friederich Loheide** · Lizenz: **MIT**
**Version 2.6.0** · Autor: **Friederich Loheide** · Lizenz: **MIT**
</div>