isLoggedIn()) { header('Location: index.php'); exit; } I18n::init(); $db = Database::getInstance(); $appTitle = $db->getSetting('app_title', 'UniFi Voucher System'); $logoUrl = $db->getSetting('logo_url', ''); $systemUrl = rtrim($db->getSetting('system_url', ''), '/'); $error = ''; $success = ''; if ($_SERVER['REQUEST_METHOD'] === 'POST') { $email = trim($_POST['email'] ?? ''); // Einfacher Throttle: max. 3 Anfragen pro 15 Minuten je Session (gegen Spam) $now = time(); $rl = array_values(array_filter($_SESSION['pwreset_times'] ?? [], fn($t) => ($now - $t) < 900)); if (count($rl) >= 3) { $error = 'Zu viele Anfragen. Bitte warten Sie einige Minuten.'; } elseif (!filter_var($email, FILTER_VALIDATE_EMAIL)) { $error = __('error_email_invalid'); } else { $rl[] = $now; $_SESSION['pwreset_times'] = $rl; $user = $db->fetchOne("SELECT * FROM users WHERE email = ? AND is_active = 1 AND password_hash IS NOT NULL", [$email]); // Always show success (don't reveal whether email exists) if ($user) { try { // Delete old tokens for this user $db->execute("DELETE FROM password_reset_tokens WHERE user_id = ?", [$user['id']]); // Generate token $token = bin2hex(random_bytes(32)); $expiresAt = date('Y-m-d H:i:s', strtotime('+1 hour')); $db->execute( "INSERT INTO password_reset_tokens (user_id, token, expires_at) VALUES (?, ?, ?)", [$user['id'], $token, $expiresAt] ); // Send email $resetUrl = $systemUrl . '/reset_password.php?token=' . $token; $mailer = new Mailer(); $subject = $appTitle . ' – Passwort zurücksetzen'; $body = "Hallo {$user['name']},\n\n" . "Sie haben eine Passwort-Rücksetzung angefordert.\n\n" . "Klicken Sie auf den folgenden Link, um Ihr Passwort zurückzusetzen (gültig für 1 Stunde):\n\n" . $resetUrl . "\n\n" . "Falls Sie dies nicht angefordert haben, ignorieren Sie diese E-Mail.\n\n" . $appTitle; $mailer->sendRaw($user['email'], $subject, $body); // Audit log $db->execute( "INSERT INTO audit_log (user_id, action, entity_type, entity_id, details, ip_address) VALUES (?, 'password_reset', 'user', ?, 'Reset-Link angefordert', ?)", [$user['id'], $user['id'], $_SERVER['REMOTE_ADDR'] ?? ''] ); } catch (Exception $e) { // Silent – don't reveal errors to user } } $success = __('reset_success'); } } ?> <?= __('reset_title') ?> – <?= htmlspecialchars($appTitle) ?>