From df6dabf58b5cf2fd4e24cfd6739bd736ab68f3ff Mon Sep 17 00:00:00 2001 From: fds2610-bot Date: Fri, 22 May 2026 11:48:26 +0200 Subject: [PATCH] Feature: APP_KEY Status & Generator in den Einstellungen --- Changes.md | 8 ++ public/index.php | 1 + src/Controllers/SettingsController.php | 6 ++ src/Views/settings/form.php | 108 +++++++++++++++++++++++++ 4 files changed, 123 insertions(+) diff --git a/Changes.md b/Changes.md index 5d35524..d56b75f 100644 --- a/Changes.md +++ b/Changes.md @@ -2,6 +2,14 @@ --- +## 2026-05-22 – Feature: APP_KEY Status & Generator in den Einstellungen + +- Neuer Settings-Bereich unter dem Betriebsmodus zeigt Status des Verschlüsselungsschlüssels (`APP_KEY`): **Gesetzt** (grün, 64 Hex-Zeichen valide), **Ungültig** (falsches Format) oder **Fehlt** (leer) +- Bei fehlendem oder ungültigem Schlüssel: Button „Neuen Schlüssel generieren" → POST `/settings/generate-app-key` liefert `bin2hex(random_bytes(32))`, Anzeige im Code-Block mit Copy-Button +- Schlüssel wird nicht persistiert (Container hat keinen Schreibzugriff auf `.env`); Anleitung im UI: kopieren → in `.env` eintragen → `docker compose restart web` + +--- + ## 2026-05-22 – UI: Einheitliche Icon-Buttons für Bearbeiten/Ansehen/Löschen - **Bleistift-Icon** (transparent, ohne Hintergrund – Stil der Direktverbindungs-Kacheln) ersetzt alle „Bearbeiten"- und „Öffnen"-Buttons in `accounts/list`, `customers/show`, `customers/list`, `suppliers/list`, `useradmin/list`, `assets/list`, `belege/list`, `invoices/list`, `invoices/show` diff --git a/public/index.php b/public/index.php index 3782600..70407de 100644 --- a/public/index.php +++ b/public/index.php @@ -159,6 +159,7 @@ $router->post('/settings/mail-template', fn($p) => (new SettingsController())->m $router->post('/settings/mail-test', fn($p) => (new SettingsController())->mailTest($p)); $router->post('/settings/logo', fn($p) => (new SettingsController())->uploadLogo($p)); $router->post('/settings/logo/delete', fn($p) => (new SettingsController())->deleteLogo($p)); +$router->post('/settings/generate-app-key', fn($p) => (new SettingsController())->generateAppKey($p)); $router->get('/settings/bankimport', fn($p) => (new SettingsController())->bankImport($p)); $router->post('/settings/bankimport/suggest', fn($p) => (new SettingsController())->storeSuggestion($p)); $router->post('/settings/bankimport/create', fn($p) => (new SettingsController())->createBankImportFormat($p)); diff --git a/src/Controllers/SettingsController.php b/src/Controllers/SettingsController.php index 2eaf2da..5e87042 100644 --- a/src/Controllers/SettingsController.php +++ b/src/Controllers/SettingsController.php @@ -139,6 +139,12 @@ class SettingsController extends BaseController View::redirect('/settings', 'Logo gelöscht.'); } + public function generateAppKey(array $params): void + { + header('Content-Type: application/json'); + echo json_encode(['key' => bin2hex(random_bytes(32))]); + } + public function bankImport(array $params): void { $formats = BankSource::all('csv'); diff --git a/src/Views/settings/form.php b/src/Views/settings/form.php index e457f00..70a6df9 100644 --- a/src/Views/settings/form.php +++ b/src/Views/settings/form.php @@ -176,6 +176,71 @@ + + +
+
+
App-Verschlüsselungsschlüssel
+ + Gesetzt + + Ungültig + + Fehlt + +
+
+

+ + ✓ APP_KEY ist gültig (64-stellige Hex-Zeichenkette).
+ Wird zum Verschlüsseln sensibler Felder (PayPal-Signature, FinTS-PIN) genutzt. + Niemals ändern – sonst sind alle bestehenden verschlüsselten Werte verloren. + + ✗ APP_KEY ist gesetzt, aber kein gültiges Format (erwartet: 64 Hex-Zeichen).
+ Bitte prüfen und korrigieren. + + ✗ APP_KEY ist nicht gesetzt.
+ Ohne Schlüssel können keine Bank-Direktverbindungen mit PIN/Secret gespeichert werden. + +

+ + + + + + +
+
+
KI-Kontierungsvorschlag
@@ -544,4 +609,47 @@ document.getElementById('btn-mail-text-save')?.addEventListener('click', functio }) .finally(function () { btn.disabled = false; }); }); + +document.getElementById('btn-generate-app-key')?.addEventListener('click', function () { + const btn = this; + const result = document.getElementById('app-key-result'); + const out = document.getElementById('app-key-value'); + btn.disabled = true; + fetch('/settings/generate-app-key', { method: 'POST' }) + .then(r => r.json()) + .then(data => { + if (data && data.key) { + out.textContent = data.key; + result.style.display = 'block'; + btn.style.display = 'none'; + } else { + alert('Schlüssel konnte nicht erzeugt werden.'); + btn.disabled = false; + } + }) + .catch(() => { + alert('Netzwerkfehler beim Erzeugen des Schlüssels.'); + btn.disabled = false; + }); +}); + +document.getElementById('btn-copy-app-key')?.addEventListener('click', function () { + const out = document.getElementById('app-key-value'); + const txt = out.textContent || ''; + if (!txt) return; + const btn = this; + const restore = btn.innerHTML; + navigator.clipboard.writeText(txt) + .then(() => { + btn.textContent = '✓'; + setTimeout(() => { btn.innerHTML = restore; }, 1500); + }) + .catch(() => { + const range = document.createRange(); + range.selectNodeContents(out); + const sel = window.getSelection(); + sel.removeAllRanges(); + sel.addRange(range); + }); +});