Files
deskhub/DeskHub-Webseite/staff/login.php
T
2026-10-19 18:06:00 +00:00

151 lines
7.0 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
require_once __DIR__ . '/../includes/bootstrap.php';
require_once __DIR__ . '/../includes/totp.php';
if (current_staff()) {
redirect('/staff/reports.php');
}
$errors = [];
$need2fa = false;
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
verify_csrf();
$action = $_POST['action'] ?? 'login';
if ($action === 'verify_totp') {
$pendingId = $_SESSION['totp_pending_staff_id'] ?? null;
$code = trim($_POST['totp_code'] ?? '');
if (!$pendingId) {
$errors[] = 'Sitzung abgelaufen. Bitte neu anmelden.';
} else {
$stmt = get_db()->prepare('SELECT * FROM staff WHERE id = ? AND is_active = 1');
$stmt->execute([$pendingId]);
$staff = $stmt->fetch();
if ($staff && totp_verify($staff['totp_secret'], $code)) {
unset($_SESSION['totp_pending_staff_id']);
staff_login($staff);
redirect('/staff/reports.php');
}
$errors[] = 'Ungültiger Code. Bitte erneut versuchen.';
$need2fa = true;
}
} else {
$email = trim($_POST['email'] ?? '');
$pass = $_POST['password'] ?? '';
if (!rate_limit_check('staff_login_attempt', client_ip(), 10, 15)) {
$errors[] = 'Zu viele Anmeldeversuche. Bitte versuchen Sie es in einigen Minuten erneut.';
} elseif ($email && !rate_limit_check('staff_login_email', strtolower($email), 5, 15)) {
// Konto-basierte Sperre – verhindert Brute-Force über wechselnde IPs
$errors[] = 'Zu viele Anmeldeversuche für dieses Konto. Bitte warten Sie einige Minuten.';
} else {
$stmt = get_db()->prepare('SELECT * FROM staff WHERE LOWER(email) = LOWER(?) AND is_active = 1');
$stmt->execute([$email]);
$staff = $stmt->fetch();
if ($staff && password_verify($pass, $staff['password_hash'])) {
// Erfolgreicher Login – Zähler zurücksetzen
rate_limit_reset('staff_login_email', strtolower($email));
if ($staff['totp_enabled']) {
$_SESSION['totp_pending_staff_id'] = $staff['id'];
$need2fa = true;
} else {
staff_login($staff);
redirect('/staff/reports.php');
}
} else {
$errors[] = 'E-Mail-Adresse oder Passwort ist falsch.';
}
}
}
}
$pageTitle = 'Mitarbeiter-Login';
$activePage = '';
// Staff-Header hat Sidebar – für Login-Seite eigenes schlankes HTML
$banner = get_setting('banner_path');
$logo = get_setting('logo_path');
$displayName = get_setting('display_name', config()['site']['name']);
?>
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Mitarbeiter-Login – <?= e($displayName) ?></title>
<link rel="stylesheet" href="/assets/css/style.css?v=<?= @filemtime(__DIR__ . "/../assets/css/style.css") ?: time() ?>">
<?php $customThemeStylesheet = active_custom_theme_stylesheet(); ?>
<?php if ($customThemeStylesheet): ?>
<link rel="stylesheet" href="<?= e($customThemeStylesheet) ?>">
<?php endif; ?>
<link rel="manifest" href="/manifest-staff.php">
<meta name="theme-color" content="#0f6f6a">
<?= site_icon_links() ?>
<script>if('serviceWorker' in navigator){navigator.serviceWorker.register('/sw.js').catch(function(){});}</script>
</head>
<body class="login-page staff-login-page" style="margin:0; display:flex; flex-direction:column; min-height:100vh; background:#16202a <?php if($banner): ?>; background-image:url('<?= e($banner) ?>'); background-size:cover; background-position:center<?php endif; ?>">
<!-- Schlanker Header -->
<header style="background:rgba(14,26,34,.95); border-bottom:1px solid rgba(255,255,255,.08); padding:0 28px; height:56px; display:flex; align-items:center; justify-content:space-between; flex-shrink:0">
<div style="display:flex; align-items:center; gap:12px">
<?php if ($logo): ?>
<img src="<?= e($logo) ?>" alt="" style="height:32px; width:auto">
<?php endif; ?>
<?php if (!$logo || get_setting('logo_hide_name', '0') !== '1'): ?>
<span style="color:#fff; font-weight:700; font-size:.95rem"><?= e($displayName) ?></span>
<?php endif; ?>
</div>
<a href="/login.php" style="color:rgba(255,255,255,.5); font-size:.8rem; text-decoration:none">← Zum Kundenportal</a>
</header>
<!-- Auth-Bereich -->
<div class="login-screen staff-login-screen">
<div class="auth-card login-card staff-login-card">
<h1 style="font-size:1.4rem; font-weight:700; margin-bottom:4px; color:#0f1923">Mitarbeiterbereich</h1>
<div class="sub">Anmeldung für Support-Mitarbeiter und Administratoren.</div>
<?php foreach ($errors as $err): ?>
<div class="flash error"><?= e($err) ?></div>
<?php endforeach; ?>
<?php foreach (get_flashes() as $f): ?>
<div class="flash <?= e($f['type']) ?>"><?= e($f['message']) ?></div>
<?php endforeach; ?>
<?php if ($need2fa): ?>
<p style="font-size:.88rem; color:#64748b; margin-bottom:14px">Bitte geben Sie den 6-stelligen Code aus Ihrer Authenticator-App ein.</p>
<form method="post">
<?= csrf_field() ?>
<input type="hidden" name="action" value="verify_totp">
<label for="totp_code">Authenticator-Code</label>
<input type="text" id="totp_code" name="totp_code" inputmode="numeric" pattern="\d{6}" maxlength="6" required autofocus placeholder="000000" style="letter-spacing:.2em; font-size:1.3rem; text-align:center">
<div class="btn-row">
<button type="submit" class="btn login-submit">Verifizieren</button>
</div>
</form>
<p style="margin-top:14px; font-size:.8rem; text-align:center"><a href="/staff/login.php">← Zurück zum Login</a></p>
<?php else: ?>
<form method="post">
<?= csrf_field() ?>
<input type="hidden" name="action" value="login">
<label for="email">E-Mail-Adresse</label>
<input type="email" id="email" name="email" required autofocus autocomplete="email" autocapitalize="none" autocorrect="off" spellcheck="false">
<label for="password">Passwort</label>
<input type="password" id="password" name="password" required autocomplete="current-password" autocapitalize="none" autocorrect="off" spellcheck="false">
<div style="text-align:right; margin-top:6px">
<a href="/staff/forgot_password.php" style="font-size:.8rem">Passwort vergessen?</a>
</div>
<div class="btn-row">
<button type="submit" class="btn login-submit">Anmelden</button>
</div>
</form>
<?php endif; ?>
</div>
</div>
<!-- Schlanker Footer -->
<footer style="background:rgba(14,26,34,.95); border-top:1px solid rgba(255,255,255,.08); padding:12px 28px; text-align:center; flex-shrink:0">
<span style="color:rgba(255,255,255,.3); font-size:.75rem">Copyright © <?= date('Y') ?> <?= e($displayName) ?> – Alle Rechte vorbehalten.</span>
</footer>
</body>
</html>