Merge origin/main: Review-Branch mit v2.4.0-Features zusammenführen

Konfliktauflösung kombiniert beide Seiten:
- Auth: Secure-Cookie-Flag + DB-Session-Handler (main)
- UniFiController: createVouchers (n-Parameter, 1 API-Call) + QoS-Optionen (main)
- index.php: IP-Rate-Limit/PRG/Sticky-Forms + CAPTCHA/SMS/QoS/Tageslimit (main)
- users.php: 2FA-Reset (main) auf POST+PRG umgestellt wie übrige Aktionen
- forgot_password: Session-Throttle (main) + IP-Throttle kombiniert
- Eigene Migrationen wegen Nummernkollision auf 0005/0006 umbenannt

https://claude.ai/code/session_01KKVpVPJjrTKGoRgpJcySD4
This commit is contained in:
Claude 2026-06-09 20:03:32 +00:00
commit 1a2f86ed3d
No known key found for this signature in database
65 changed files with 3136 additions and 32 deletions

View file

@ -165,6 +165,17 @@ if ($_SERVER['REQUEST_METHOD']==='POST' && isset($_POST['toggle_user'])) {
} else { $error = __('error_csrf'); }
}
// 2FA eines Benutzers zurücksetzen (Admin-Hilfe bei verlorenem Authenticator)
// POST + PRG wie die uebrigen state-aendernden Aktionen
if ($_SERVER['REQUEST_METHOD']==='POST' && isset($_POST['reset_2fa'])) {
if ($auth->validateCsrfToken($_POST['csrf_token'] ?? '')) {
$auth->disableTotp((int)$_POST['reset_2fa']);
flashSet('2FA des Benutzers wurde zurückgesetzt.');
header('Location: users.php');
exit;
} else { $error = __('error_csrf'); }
}
if (empty($success) && empty($error) && ($flash = flashGet())) {
$success = $flash['message'];
}
@ -326,6 +337,17 @@ $currentPage = 'users';
</button>
</form>
<?php endif; ?>
<?php if (!empty($user['totp_enabled'])): ?>
<form method="post" style="display:inline;"
onsubmit="return confirm('2FA für <?= htmlspecialchars($user['email'], ENT_QUOTES) ?> zurücksetzen?')">
<input type="hidden" name="csrf_token" value="<?= $auth->getCsrfToken() ?>">
<input type="hidden" name="reset_2fa" value="<?= $user['id'] ?>">
<button type="submit" class="btn btn-secondary btn-sm"
title="2FA zurücksetzen" aria-label="2FA zurücksetzen">
<i class="fas fa-user-shield"></i>
</button>
</form>
<?php endif; ?>
<form method="post" style="display:inline;"
onsubmit="return confirm('<?= addslashes(__('confirm_delete_user')) ?>')">
<input type="hidden" name="csrf_token" value="<?= $auth->getCsrfToken() ?>">