Englische Übersetzungen für die restlichen Admin-Seiten
API-Schlüssel, Integration & Wartung, Voucher-Import, Backup & Restore, Reporting, Sicherheit (2FA) und Audit-Log waren fest auf Deutsch verdrahtet, obwohl in der Kopfzeile ein DE/EN-Umschalter sitzt. Diese Seiten laufen jetzt komplett über lang/de.php bzw. lang/en.php. - rund 200 neue Sprachschlüssel, beide Dateien deckungsgleich - Aktionsnamen im Audit-Log werden übersetzt statt fest ausgegeben - Bestätigungsdialoge und Statusmeldungen in JavaScript ebenfalls - admin/security.php initialisiert jetzt I18n und setzt <html lang> passend zur Auswahl Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
30d0ce3a23
commit
850a04d628
16 changed files with 580 additions and 196 deletions
|
|
@ -6,8 +6,11 @@ ini_set('log_errors', 1);
|
|||
require_once __DIR__ . '/../config.php';
|
||||
require_once __DIR__ . '/../includes/Database.php';
|
||||
require_once __DIR__ . '/../includes/Auth.php';
|
||||
require_once __DIR__ . '/../includes/I18n.php';
|
||||
require_once __DIR__ . '/../includes/Ui.php';
|
||||
|
||||
I18n::init();
|
||||
|
||||
$auth = new Auth();
|
||||
$auth->requireLogin();
|
||||
|
||||
|
|
@ -25,20 +28,20 @@ $setupRequired = isset($_GET['setup_required']);
|
|||
// 2FA aktivieren (Code bestaetigen)
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['enable_totp'])) {
|
||||
if (!$auth->validateCsrfToken($_POST['csrf_token'] ?? '')) {
|
||||
$error = 'Ungültiges Sicherheits-Token';
|
||||
$error = __('sec_token_invalid');
|
||||
} else {
|
||||
$secret = $_SESSION['totp_setup_secret'] ?? '';
|
||||
$code = trim($_POST['code'] ?? '');
|
||||
if ($secret === '') {
|
||||
$error = 'Setup abgelaufen, bitte erneut starten.';
|
||||
$error = __('sec_setup_expired');
|
||||
} elseif (!Totp::verify($secret, $code)) {
|
||||
$error = 'Code ungültig. Bitte erneut versuchen.';
|
||||
$error = __('sec_code_invalid');
|
||||
} else {
|
||||
$backupCodes = $auth->enableTotp($user['id'], $secret);
|
||||
unset($_SESSION['totp_setup_secret']);
|
||||
$totpEnabled = true;
|
||||
$user = $auth->getCurrentUser();
|
||||
$success = 'Zwei-Faktor-Authentifizierung wurde aktiviert. Bitte Recovery-Codes sicher speichern!';
|
||||
$success = __('sec_enabled');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -46,32 +49,32 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['enable_totp'])) {
|
|||
// Überall abmelden (andere Sessions beenden)
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['logout_others'])) {
|
||||
if (!$auth->validateCsrfToken($_POST['csrf_token'] ?? '')) {
|
||||
$error = 'Ungültiges Sicherheits-Token';
|
||||
$error = __('sec_token_invalid');
|
||||
} else {
|
||||
$auth->logoutOtherSessions();
|
||||
$success = 'Alle anderen Sitzungen wurden beendet.';
|
||||
$success = __('sec_sessions_closed');
|
||||
}
|
||||
}
|
||||
|
||||
// Recovery-Codes neu erzeugen
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['regen_codes'])) {
|
||||
if (!$auth->validateCsrfToken($_POST['csrf_token'] ?? '')) {
|
||||
$error = 'Ungültiges Sicherheits-Token';
|
||||
$error = __('sec_token_invalid');
|
||||
} elseif (!empty($user['totp_enabled'])) {
|
||||
$backupCodes = $auth->regenerateBackupCodes($user['id']);
|
||||
$user = $auth->getCurrentUser();
|
||||
$success = 'Neue Recovery-Codes erzeugt. Die alten sind jetzt ungültig.';
|
||||
$success = __('sec_codes_new');
|
||||
}
|
||||
}
|
||||
|
||||
// 2FA deaktivieren
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['disable_totp'])) {
|
||||
if (!$auth->validateCsrfToken($_POST['csrf_token'] ?? '')) {
|
||||
$error = 'Ungültiges Sicherheits-Token';
|
||||
$error = __('sec_token_invalid');
|
||||
} else {
|
||||
$auth->disableTotp($user['id']);
|
||||
$totpEnabled = false;
|
||||
$success = 'Zwei-Faktor-Authentifizierung wurde deaktiviert.';
|
||||
$success = __('sec_disabled');
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -88,11 +91,11 @@ $dbSessions = $db->getSetting('session_driver', 'php') === 'db';
|
|||
$activeSessions = $dbSessions ? $auth->activeSessionCount() : 0;
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<html lang="<?= I18n::getLanguage() ?>">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Zwei-Faktor-Authentifizierung – <?= htmlspecialchars($appTitle) ?></title>
|
||||
<title><?= __('sec_title') ?> – <?= htmlspecialchars($appTitle) ?></title>
|
||||
<?php if (!$totpEnabled && $hasPassword): ?>
|
||||
<?= Ui::script('assets/vendor/qrcodejs/qrcode.min.js', '../') ?>
|
||||
<?php endif; ?>
|
||||
|
|
@ -103,21 +106,21 @@ $activeSessions = $dbSessions ? $auth->activeSessionCount() : 0;
|
|||
<div class="focus-head">
|
||||
<span class="focus-icon"><i class="fas fa-shield-halved"></i></span>
|
||||
<div>
|
||||
<h1>Zwei-Faktor-Authentifizierung</h1>
|
||||
<p class="sub">Konto: <?= htmlspecialchars($user['email']) ?></p>
|
||||
<h1><?= __('sec_title') ?></h1>
|
||||
<p class="sub"><?= __('sec_account') ?> <?= htmlspecialchars($user['email']) ?></p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php if ($setupRequired && !$totpEnabled): ?>
|
||||
<div class="alert alert-error">Aus Sicherheitsgründen ist 2FA für Administratoren verpflichtend. Bitte jetzt einrichten.</div>
|
||||
<div class="alert alert-error"><?= __('sec_required_hint') ?></div>
|
||||
<?php endif; ?>
|
||||
<?php if ($error): ?><div class="alert alert-error"><?= htmlspecialchars($error) ?></div><?php endif; ?>
|
||||
<?php if ($success): ?><div class="alert alert-ok"><?= htmlspecialchars($success) ?></div><?php endif; ?>
|
||||
|
||||
<?php if (!empty($backupCodes)): ?>
|
||||
<div class="codes-box">
|
||||
<strong><i class="fas fa-key"></i> Recovery-Codes</strong>
|
||||
<p>Bewahren Sie diese sicher auf. Jeder Code funktioniert <em>einmal</em>, falls Sie keinen Zugriff auf Ihre App haben.</p>
|
||||
<strong><i class="fas fa-key"></i> <?= __('sec_recovery_codes') ?></strong>
|
||||
<p><?= __('sec_recovery_hint') ?></p>
|
||||
<div class="codes">
|
||||
<?php foreach ($backupCodes as $c): ?><span><?= htmlspecialchars($c) ?></span><?php endforeach; ?>
|
||||
</div>
|
||||
|
|
@ -125,34 +128,34 @@ $activeSessions = $dbSessions ? $auth->activeSessionCount() : 0;
|
|||
<?php endif; ?>
|
||||
|
||||
<?php if (!$hasPassword): ?>
|
||||
<div class="status off"><i class="fas fa-circle-minus"></i> Nicht verfügbar</div>
|
||||
<p class="sub">Ihr Konto meldet sich über Microsoft 365 an. 2FA wird dort in Ihrem Microsoft-Konto verwaltet.</p>
|
||||
<div class="status off"><i class="fas fa-circle-minus"></i> <?= __('sec_unavailable') ?></div>
|
||||
<p class="sub"><?= __('sec_m365_hint') ?></p>
|
||||
<?php elseif ($totpEnabled): ?>
|
||||
<div class="status on"><i class="fas fa-circle-check"></i> Aktiv</div>
|
||||
<p class="sub">Bei jeder Anmeldung wird zusätzlich ein Code aus Ihrer Authenticator-App abgefragt.<br>
|
||||
Verbleibende Recovery-Codes: <strong><?= (int)$auth->backupCodesRemaining($user) ?></strong></p>
|
||||
<div class="status on"><i class="fas fa-circle-check"></i> <?= __('sec_active') ?></div>
|
||||
<p class="sub"><?= __('sec_active_hint') ?><br>
|
||||
<?= __('sec_codes_left') ?> <strong><?= (int)$auth->backupCodesRemaining($user) ?></strong></p>
|
||||
<form method="post" style="margin-bottom:10px;">
|
||||
<input type="hidden" name="csrf_token" value="<?= htmlspecialchars($csrf) ?>">
|
||||
<button type="submit" name="regen_codes" class="btn btn-secondary btn-lg btn-block">Recovery-Codes neu erzeugen</button>
|
||||
<button type="submit" name="regen_codes" class="btn btn-secondary btn-lg btn-block"><?= __('sec_regen_codes') ?></button>
|
||||
</form>
|
||||
<form method="post" onsubmit="return confirm('2FA wirklich deaktivieren?');">
|
||||
<form method="post" onsubmit="return confirm('<?= __('sec_disable_confirm') ?>');">
|
||||
<input type="hidden" name="csrf_token" value="<?= htmlspecialchars($csrf) ?>">
|
||||
<button type="submit" name="disable_totp" class="btn btn-danger btn-lg btn-block">2FA deaktivieren</button>
|
||||
<button type="submit" name="disable_totp" class="btn btn-danger btn-lg btn-block"><?= __('sec_disable') ?></button>
|
||||
</form>
|
||||
<?php else: ?>
|
||||
<div class="status off"><i class="fas fa-circle-minus"></i> Inaktiv</div>
|
||||
<div class="status off"><i class="fas fa-circle-minus"></i> <?= __('sec_inactive') ?></div>
|
||||
<ol>
|
||||
<li>Authenticator-App öffnen (Google Authenticator, Authy, Microsoft Authenticator …)</li>
|
||||
<li>QR-Code scannen <em>oder</em> Secret manuell eingeben</li>
|
||||
<li>Den angezeigten 6-stelligen Code unten eingeben</li>
|
||||
<li><?= __('sec_step_1') ?></li>
|
||||
<li><?= __('sec_step_2') ?></li>
|
||||
<li><?= __('sec_step_3') ?></li>
|
||||
</ol>
|
||||
<div class="qr"><div id="qrcode"></div></div>
|
||||
<div class="secret"><?= htmlspecialchars($setupSecret) ?></div>
|
||||
<form method="post">
|
||||
<input type="hidden" name="csrf_token" value="<?= htmlspecialchars($csrf) ?>">
|
||||
<label for="code">6-stelliger Code</label>
|
||||
<label for="code"><?= __('sec_code_label') ?></label>
|
||||
<input type="text" id="code" name="code" class="code-input" inputmode="numeric" pattern="[0-9]*" maxlength="6" autocomplete="one-time-code" required placeholder="123456">
|
||||
<button type="submit" name="enable_totp" class="btn btn-primary btn-lg btn-block" style="margin-top:14px;">2FA aktivieren</button>
|
||||
<button type="submit" name="enable_totp" class="btn btn-primary btn-lg btn-block" style="margin-top:14px;"><?= __('sec_enable') ?></button>
|
||||
</form>
|
||||
<script>
|
||||
new QRCode(document.getElementById('qrcode'), {
|
||||
|
|
@ -165,14 +168,14 @@ $activeSessions = $dbSessions ? $auth->activeSessionCount() : 0;
|
|||
|
||||
<?php if ($dbSessions): ?>
|
||||
<hr>
|
||||
<p class="sub">Aktive Sitzungen: <strong><?= (int)$activeSessions ?></strong></p>
|
||||
<form method="post" onsubmit="return confirm('Alle anderen Sitzungen abmelden?');">
|
||||
<p class="sub"><?= __('sec_sessions') ?> <strong><?= (int)$activeSessions ?></strong></p>
|
||||
<form method="post" onsubmit="return confirm('<?= __('sec_logout_others_confirm') ?>');">
|
||||
<input type="hidden" name="csrf_token" value="<?= htmlspecialchars($csrf) ?>">
|
||||
<button type="submit" name="logout_others" class="btn btn-secondary btn-lg btn-block">Auf allen anderen Geräten abmelden</button>
|
||||
<button type="submit" name="logout_others" class="btn btn-secondary btn-lg btn-block"><?= __('sec_logout_others') ?></button>
|
||||
</form>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="auth-links"><a class="back-link" href="../index.php"><i class="fas fa-arrow-left"></i> Zurück</a></div>
|
||||
<div class="auth-links"><a class="back-link" href="../index.php"><i class="fas fa-arrow-left"></i> <?= __('nav_back') ?></a></div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue