Unifi-Voucher-Tool/lang/de.php
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

344 lines
16 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
return [
// Navigation
'nav_dashboard' => 'Dashboard',
'nav_sites' => 'Sites verwalten',
'nav_users' => 'Benutzer verwalten',
'nav_vouchers' => 'Live Vouchers',
'nav_templates' => 'Voucher-Profile',
'nav_audit_log' => 'Audit-Log',
'nav_settings' => 'Einstellungen',
'nav_update' => 'System-Update',
'nav_back' => 'Zurück zur Startseite',
'nav_administration'=> 'Administration',
// Common buttons
'btn_save' => 'Speichern',
'btn_cancel' => 'Abbrechen',
'btn_add' => 'Hinzufügen',
'btn_edit' => 'Bearbeiten',
'btn_delete' => 'Löschen',
'btn_create' => 'Erstellen',
'btn_close' => 'Schließen',
'btn_back' => 'Zurück',
'btn_login' => 'Anmelden',
'btn_logout' => 'Abmelden',
'btn_refresh' => 'Aktualisieren',
'btn_export_csv' => 'CSV exportieren',
'btn_print' => 'Ausdrucken',
'btn_send' => 'Senden',
'btn_test' => 'Testen',
'btn_generate' => 'Generieren',
'btn_copy' => 'Kopieren',
'btn_new_code' => 'Weiteren Code erstellen',
// Common labels
'label_name' => 'Name',
'label_email' => 'E-Mail',
'label_password' => 'Passwort',
'label_status' => 'Status',
'label_actions' => 'Aktionen',
'label_created' => 'Erstellt',
'label_site' => 'Standort',
'label_sites' => 'Sites',
'label_role' => 'Rolle',
'label_code' => 'Code',
'label_note' => 'Notiz',
'label_usage' => 'Nutzung',
'label_expires' => 'Gültigkeit',
'label_devices' => 'Geräte',
'label_duration' => 'Dauer',
'label_description' => 'Beschreibung',
'label_language' => 'Sprache',
// Status texts
'status_active' => 'Aktiv',
'status_inactive' => 'Inaktiv',
'status_valid' => 'Gültig',
'status_used' => 'Verwendet',
'status_expired' => 'Abgelaufen',
'status_admin' => 'Admin',
'status_user' => 'Benutzer',
'status_public' => 'Öffentlich',
'status_all' => 'Alle',
// Dashboard
'dashboard_title' => 'Dashboard',
'dashboard_subtitle'=> 'Übersicht über Ihr UniFi Voucher System',
'dashboard_active_sites' => 'Aktive Sites',
'dashboard_users' => 'Benutzer',
'dashboard_valid' => 'Gültige Vouchers',
'dashboard_used' => 'Verwendet',
'dashboard_expired' => 'Abgelaufen',
'dashboard_total' => 'Gesamt',
'dashboard_live_refresh' => 'Live aktualisieren',
'dashboard_trend' => 'Voucher-Trend (Letzte 7 Tage)',
'dashboard_top_users'=> 'Top 5 Benutzer (Letzte 30 Tage)',
'dashboard_recent' => 'Letzte Vouchers (aus Datenbank)',
'dashboard_creator' => 'Ersteller',
'dashboard_public' => 'Öffentlich',
'dashboard_vouchers_per_site' => 'Live: Vouchers pro Site',
'dashboard_no_data' => 'Noch keine Daten verfügbar',
'dashboard_no_vouchers' => 'Noch keine Vouchers erstellt',
// Voucher creation
'voucher_name_label' => 'Voucher-Name *',
'voucher_name_hint' => 'z.B. Besprechung UL, Vertretername Firma XY',
'voucher_devices_label' => 'Wie viele Geräte dürfen sich einloggen? *',
'voucher_site_label' => 'Standort *',
'voucher_site_select' => 'Bitte wählen...',
'voucher_email_send' => 'Code per E-Mail versenden',
'voucher_email_label' => 'E-Mail-Adresse des Empfängers',
'voucher_email_hint' => 'gast@example.com',
'voucher_create_btn' => 'Voucher erstellen',
'voucher_creating' => 'Erstelle Voucher...',
'voucher_success_title' => '✓ Ihr Zugangs-Code',
'voucher_validity' => 'Gültig für {duration} ab Erstellung',
'voucher_qr_label' => 'QR-Code scannen zum Verbinden',
'voucher_print_btn' => 'Code ausdrucken',
'voucher_no_sites' => 'Keine verfügbaren Sites gefunden.',
'voucher_no_sites_admin'=> 'Klicken Sie hier, um Sites anzulegen',
'voucher_no_sites_user' => 'Ihr Konto hat noch keinen Site-Zugriff. Bitte kontaktieren Sie Ihren Administrator, um Berechtigungen zu erhalten.',
'voucher_template_select'=> '-- Kein Profil (manuell) --',
'voucher_template_label'=> 'Schnellprofil (optional)',
// Bulk creation
'bulk_tab' => 'Einzeln',
'bulk_tab_bulk' => 'Mehrere auf einmal',
'bulk_quantity' => 'Anzahl Vouchers',
'bulk_quantity_hint'=> 'Wie viele Vouchers sollen erstellt werden?',
'bulk_name_prefix' => 'Name / Präfix',
'bulk_create_btn' => '{count} Vouchers erstellen',
'bulk_creating' => 'Erstelle {count} Vouchers...',
'bulk_success' => '{count} Vouchers erfolgreich erstellt!',
'bulk_print_all' => 'Alle ausdrucken',
'bulk_results' => 'Erstellte Vouchers ({count})',
// Templates
'templates_title' => 'Voucher-Profile',
'templates_subtitle'=> 'Vordefinierte Voucher-Konfigurationen',
'templates_add' => 'Neues Profil',
'templates_name' => 'Profilname',
'templates_devices' => 'Max. Geräte',
'templates_duration'=> 'Gültigkeit (Minuten)',
'templates_desc' => 'Beschreibung (optional)',
'templates_none' => 'Noch keine Profile vorhanden.',
'templates_add_hint'=> 'Erstellen Sie Profile für häufig verwendete Voucher-Konfigurationen.',
'templates_edit' => 'Profil bearbeiten',
'templates_added' => 'Profil erfolgreich erstellt!',
'templates_updated' => 'Profil erfolgreich aktualisiert!',
'templates_deleted' => 'Profil erfolgreich gelöscht!',
// Users
'users_title' => 'Benutzer verwalten',
'users_add' => 'Neuer Benutzer',
'users_all' => 'Alle Benutzer',
'users_site_access' => 'Site-Zugriffe',
'users_last_login' => 'Letzter Login',
'users_never' => 'Noch nie',
'users_you' => 'Sie',
'users_all_sites' => 'Alle Sites',
'users_none' => 'Keine',
'users_add_title' => 'Neuen Benutzer anlegen',
'users_edit_title' => 'Benutzer bearbeiten',
'users_admin_check' => 'Administrator-Rechte',
'users_admin_hint' => 'Admins haben Zugriff auf alle Sites und Einstellungen',
'users_password_hint'=> 'Mindestens 8 Zeichen',
'users_site_hint' => 'Wählen Sie die Sites, auf die dieser Benutzer Zugriff haben soll',
'users_no_sites' => 'Keine Sites verfügbar. Bitte zuerst Sites anlegen.',
'users_added' => 'Benutzer erfolgreich erstellt!',
'users_updated' => 'Benutzer erfolgreich aktualisiert!',
'users_deleted' => 'Benutzer erfolgreich gelöscht!',
'users_notified' => ' Benachrichtigung wurde versendet.',
'users_none_found' => 'Noch keine Benutzer vorhanden',
'users_save' => 'Benutzer anlegen',
'users_save_edit' => 'Änderungen speichern',
'users_reset_pw' => 'Passwort-Reset-Link senden',
// Sites
'sites_title' => 'Sites verwalten',
'sites_add' => 'Neue Site hinzufügen',
'sites_add_title' => 'Neue Site hinzufügen',
'sites_edit_title' => 'Site bearbeiten',
'sites_name' => 'Site-Name *',
'sites_site_id' => 'UniFi Site ID *',
'sites_controller' => 'Controller URL *',
'sites_username' => 'Benutzername *',
'sites_password' => 'Passwort *',
'sites_password_edit'=> 'Neues Passwort',
'sites_password_hint'=> 'Nur ausfüllen wenn Sie das Passwort ändern möchten',
'sites_public' => 'Öffentlicher Zugriff (ohne Login nutzbar)',
'sites_none' => 'Noch keine Sites konfiguriert. Fügen Sie Ihre erste Site hinzu!',
'sites_added' => 'Site erfolgreich hinzugefügt!',
'sites_updated' => 'Site erfolgreich aktualisiert!',
'sites_deleted' => 'Site erfolgreich gelöscht!',
'sites_testing' => 'Verbindung wird getestet...',
'sites_deactivate' => 'Deaktivieren',
'sites_activate' => 'Aktivieren',
// Voucher admin list
'vouchers_title' => 'Live Voucher-Verwaltung',
'vouchers_subtitle' => 'Vouchers werden direkt vom UniFi Controller abgerufen',
'vouchers_select_site'=> 'Site auswählen',
'vouchers_select_hint'=> '-- Site auswählen --',
'vouchers_last_sync'=> 'Letzte Sync',
'vouchers_no_sites' => 'Keine aktiven Sites vorhanden',
'vouchers_search' => 'Suchen (Code, Name...)',
'vouchers_filter_all'=> 'Alle',
'vouchers_filter_valid'=> 'Gültig',
'vouchers_filter_used'=> 'Verwendet',
'vouchers_filter_expired'=> 'Abgelaufen',
'vouchers_none' => 'Keine Vouchers gefunden.',
'vouchers_per_page' => 'pro Seite',
'vouchers_page_of' => 'Seite {current} von {total}',
// Audit Log
'audit_title' => 'Audit-Log',
'audit_subtitle' => 'Alle System-Aktionen im Überblick',
'audit_action' => 'Aktion',
'audit_user' => 'Benutzer',
'audit_details' => 'Details',
'audit_ip' => 'IP-Adresse',
'audit_time' => 'Zeitpunkt',
'audit_entity' => 'Objekt',
'audit_filter_all' => 'Alle Aktionen',
'audit_none' => 'Keine Einträge gefunden.',
'audit_filter' => 'Filter',
// Settings
'settings_title' => 'Einstellungen',
'settings_subtitle' => 'System-Konfiguration und Personalisierung',
'settings_tab_general' => 'Allgemein',
'settings_tab_defaults' => 'Voucher-Standards',
'settings_tab_cron' => 'Cron-Sync',
'settings_tab_m365' => 'Microsoft 365',
'settings_tab_smtp' => 'SMTP',
'settings_tab_templates_email' => 'Templates',
'settings_tab_system' => 'System',
'settings_tab_password' => 'Passwort',
'settings_saved' => 'Einstellungen erfolgreich gespeichert!',
'settings_app_title' => 'Anwendungs-Titel *',
'settings_logo_url' => 'Logo-URL',
'settings_favicon_url' => 'Favicon-URL',
'settings_favicon_hint' => 'Icon im Browser-Tab (.ico, .png, .svg)',
'settings_instr_header' => 'Anleitung - Überschrift',
'settings_instr_text' => 'Anleitung - Text',
'settings_public_access'=> 'Öffentlicher Zugriff',
'settings_default_expire' => 'Standard-Gültigkeit (Minuten)',
'settings_default_expire_hint'=> 'Standard-Ablaufzeit für neue Vouchers (480 = 8 Stunden)',
'settings_default_devices' => 'Standard-Geräteanzahl',
'settings_default_devices_hint'=> 'Vorausgefüllter Wert im Voucher-Formular',
'settings_max_devices' => 'Maximale Geräteanzahl',
'settings_max_devices_hint' => 'Maximaler Wert, den ein Benutzer auswählen kann',
'settings_pw_current' => 'Aktuelles Passwort',
'settings_pw_new' => 'Neues Passwort',
'settings_pw_confirm' => 'Passwort bestätigen',
'settings_pw_changed' => 'Passwort erfolgreich geändert!',
'settings_pw_minlength' => 'Mindestens 8 Zeichen',
// Login / Auth
'login_title' => 'Anmelden',
'login_subtitle' => 'Melden Sie sich an, um fortzufahren',
'login_email' => 'E-Mail',
'login_password' => 'Passwort',
'login_btn' => 'Anmelden',
'login_ms' => 'Mit Microsoft anmelden',
'login_local' => 'Mit Benutzername und Passwort anmelden',
'login_back' => '← Zurück zur Code-Erstellung',
'login_forgot' => 'Passwort vergessen?',
'login_error_empty' => 'Bitte E-Mail und Passwort eingeben',
'login_error_rate' => 'Zu viele Fehlversuche. Bitte warten Sie 10 Minuten.',
'login_error_creds' => 'Ungültige E-Mail oder Passwort',
// Password Reset
'reset_title' => 'Passwort vergessen',
'reset_subtitle' => 'Geben Sie Ihre E-Mail ein wir senden Ihnen einen Reset-Link.',
'reset_email_label' => 'E-Mail-Adresse',
'reset_send_btn' => 'Reset-Link senden',
'reset_success' => 'Falls ein Konto mit dieser E-Mail existiert, erhalten Sie in Kürze eine E-Mail.',
'reset_back_login' => '← Zurück zum Login',
'reset_new_pw' => 'Neues Passwort festlegen',
'reset_new_pw_label'=> 'Neues Passwort',
'reset_confirm_label'=> 'Passwort bestätigen',
'reset_set_btn' => 'Passwort festlegen',
'reset_invalid' => 'Ungültiger oder abgelaufener Reset-Link.',
'reset_done' => 'Ihr Passwort wurde erfolgreich geändert.',
// Errors
'error_csrf' => 'Ungültiges Sicherheits-Token',
'error_login_req' => 'Sie müssen angemeldet sein',
'error_no_permission'=> 'Keine Berechtigung für diese Aktion',
'error_not_found' => 'Nicht gefunden',
'error_name_req' => 'Bitte geben Sie einen Namen ein',
'error_site_req' => 'Bitte wählen Sie einen Standort',
'error_devices_range'=> 'Anzahl der Geräte muss zwischen 1 und {max} liegen',
'error_email_invalid'=> 'Ungültige E-Mail-Adresse',
'error_site_no_perm'=> 'Keine Berechtigung für diese Site',
'error_site_not_found'=> 'Site nicht gefunden',
'error_voucher_invalid'=> 'UniFi hat keinen gültigen Voucher zurückgegeben',
'error_connection' => 'Verbindung zum UniFi Controller fehlgeschlagen',
'error_fill_all' => 'Bitte füllen Sie alle Pflichtfelder aus',
// Hello / User
'hello' => 'Hallo, {name}',
'minutes_short' => 'Min.',
'hours_short' => 'Std.',
'never' => 'Noch nie',
'unknown' => 'Unbekannt',
'or' => 'oder',
// Durations (human readable)
'dur_minutes' => '{n} Minuten',
'dur_hour_one' => '1 Stunde',
'dur_hours' => '{n} Stunden',
'dur_day_one' => '1 Tag',
'dur_days' => '{n} Tage',
// Voucher creation (messages)
'voucher_created_ok' => 'Voucher erfolgreich erstellt!',
'voucher_created_mail' => 'Voucher erstellt. E-Mail versendet.',
'voucher_name_default' => 'Gast',
'voucher_deleted' => 'Voucher erfolgreich gelöscht!',
'voucher_delete_failed'=> 'Voucher konnte nicht gelöscht werden',
'error_rate_limited' => 'Zu viele Anfragen. Bitte warten Sie einen Moment.',
// Clipboard / UI
'toast_copied' => 'Kopiert!',
'click_to_copy' => 'Klicken zum Kopieren',
'copy_hint' => 'Code anklicken zum Kopieren',
'loading' => 'Lade…',
'syncing' => 'Synchronisiere…',
'vouchers_loaded' => '{count} Vouchers geladen',
// Confirm dialogs
'confirm_delete_user' => 'Benutzer wirklich löschen?',
'confirm_delete_site' => 'Möchten Sie diese Site wirklich löschen?',
'confirm_delete_template' => 'Profil wirklich löschen?',
'confirm_delete_voucher' => 'Voucher wirklich löschen?',
'confirm_send_reset' => 'Passwort-Reset-Link senden an {email}?',
'confirm_delete_token' => 'Token wirklich löschen?',
// Admin messages
'users_status_updated' => 'Benutzer-Status aktualisiert!',
'sites_status_updated' => 'Site-Status aktualisiert!',
'error_self_delete' => 'Sie können sich nicht selbst löschen',
'error_self_deactivate' => 'Sie können sich nicht selbst deaktivieren',
'error_self_demote' => 'Sie können sich nicht selbst die Administrator-Rechte entziehen',
'error_pw_mismatch' => 'Passwörter stimmen nicht überein',
'error_pw_current' => 'Aktuelles Passwort ist falsch',
'error_email_exists' => 'E-Mail bereits vorhanden',
'error_user_create' => 'Benutzer konnte nicht erstellt werden',
'reset_link_sent' => 'Passwort-Reset-Link wurde an {email} gesendet.',
'reset_link_failed' => 'Benutzer nicht gefunden oder kein lokales Passwort.',
'cron_token_generated' => 'Neuer Cron-Token wurde generiert!',
'cron_token_deleted' => 'Cron-Token wurde gelöscht!',
'm365_secret_hint' => 'Leer lassen = nicht ändern. Zum Deaktivieren des M365-Logins die Client ID leeren.',
// Site connection test
'site_test_btn' => 'Verbindung testen',
'site_test_ok' => 'Verbindung erfolgreich',
'site_test_fail' => 'Verbindung fehlgeschlagen',
// System warnings
'crypto_warning' => 'Verschlüsselung inaktiv: In der config.php ist kein gültiger APP_KEY gesetzt. UniFi-Passwörter werden im Klartext gespeichert. Bei einem Serverumzug mit verändertem APP_KEY schlagen Controller-Logins still fehl.',
];