view('forgot_password', [ 'title' => 'Passwort vergessen', 'submitted' => false ]); } public function submit() { if ($_SERVER['REQUEST_METHOD'] !== 'POST') { header('Location: ' . Config::get('BASE_URL', '/') . 'forgot-password'); exit; } try { Security::checkCsrf($_POST['csrf_token'] ?? ''); // Simple rate limiting in session $now = time(); $recentAttempts = $_SESSION['pwd_reset_attempts'] ?? []; $recentAttempts = array_filter($recentAttempts, function($ts) use ($now) { return ($now - $ts) < 600; // 10 minutes window }); if (count($recentAttempts) >= 5) { throw new Exception('Zu viele Anfragen in kurzer Zeit. Bitte warte einige Minuten, bevor du es erneut versuchst.'); } $recentAttempts[] = $now; $_SESSION['pwd_reset_attempts'] = $recentAttempts; $email = trim(strtolower($_POST['email'] ?? '')); if (!empty($email) && filter_var($email, FILTER_VALIDATE_EMAIL)) { $userModel = $this->model('User'); $user = $userModel->findByEmail($email); if ($user && strtolower($user['status']) === 'active') { require_once __DIR__ . '/../models/PasswordReset.php'; require_once __DIR__ . '/../services/MailService.php'; $pwdResetModel = new PasswordReset(); $token = $pwdResetModel->createToken($email, 1); // 1 hour validity MailService::sendPasswordReset($email, $token); } } $this->view('forgot_password', [ 'title' => 'Anfrage gesendet', 'submitted' => true, 'email' => $email ]); } catch (Exception $e) { Flash::set($e->getMessage(), 'error'); $this->view('forgot_password', [ 'title' => 'Passwort vergessen', 'submitted' => false ]); } } }