exec("SET timezone = 'Europe/Berlin'"); if ($_SERVER["REQUEST_METHOD"] !== "POST") { header("Location: reset-password.php"); exit; } $action = $_POST["action"] ?? ''; // ============================================= // SCHRITT 1: OTP anfordern // ============================================= if ($action === "request_otp") { $email = trim($_POST["email"] ?? ''); if (!filter_var($email, FILTER_VALIDATE_EMAIL)) { header("Location: reset-password.php?error=1"); exit; } // Nutzer suchen (muss registriert sein = user_login existiert) $stmt = $pdo->prepare("SELECT ugi.user_id, ugi.phone, ugi.first_name FROM user_general_information ugi INNER JOIN user_login ul ON ugi.user_id = ul.user_id WHERE ugi.mail = ?"); $stmt->execute([$email]); $user = $stmt->fetch(); if (!$user) { header("Location: reset-password.php?error=1"); exit; } if (empty($user['phone'])) { header("Location: reset-password.php?error=2"); exit; } // OTP generieren (6-stellig) $otp = str_pad(random_int(0, 999999), 6, '0', STR_PAD_LEFT); // Ablaufzeit als UNIX-Timestamp speichern (vermeidet Timezone-Probleme) $expires_timestamp = time() + 600; // 10 Minuten $expires_at = date('Y-m-d H:i:s', $expires_timestamp); // Alte OTPs für diesen Nutzer invalidieren $stmt = $pdo->prepare("UPDATE password_reset_otp SET used = 1 WHERE user_id = ? AND used = 0"); $stmt->execute([$user['user_id']]); // Neues OTP speichern $stmt = $pdo->prepare("INSERT INTO password_reset_otp (user_id, otp_code, expires_at) VALUES (?, ?, ?)"); $stmt->execute([$user['user_id'], $otp, $expires_at]); // SMS senden (wie im Seelsorgeplaner) $phone_full = "+49" . $user['phone']; $messageText = "Intranet NAK Reinickendorf\n\nIhr Bestaetigungscode: {$otp}\n\nDer Code ist 10 Minuten gueltig."; $smsData = array( "phone" => $phone_full, "message" => $messageText ); $options = array( 'http' => array( 'header' => "Content-Type: application/json; charset=utf-8", 'method' => 'POST', 'content' => json_encode($smsData, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), 'timeout' => 10, ), ); $context = stream_context_create($options); $smsResult = @file_get_contents(rtrim(intranet_env('SMS_GATEWAY_URL'), '/') . '/send_sms', false, $context); if ($smsResult === FALSE) { header("Location: reset-password.php?error=4"); exit; } // OTP zusätzlich per Mail senden $greeting = !empty($user['first_name']) ? "Hallo {$user['first_name']}" : "Hallo"; $mailBetreff = "Ihr Bestätigungscode"; $mailNachricht = "{$greeting},\n\n"; $mailNachricht .= "Sie haben das Zurücksetzen Ihres Passworts angefordert.\n\n"; $mailNachricht .= "Ihr Bestätigungscode lautet: {$otp}\n\n"; $mailNachricht .= "Der Code ist 10 Minuten gültig.\n\n"; $mailNachricht .= "Falls Sie diese Anfrage nicht gestellt haben, können Sie diese Nachricht ignorieren."; send_intranet_mail($email, $mailBetreff, $mailNachricht); // Telefonnummer maskieren für Anzeige (nur letzte 3 Ziffern zeigen) $phone_masked = str_repeat('*', max(0, strlen($user['phone']) - 3)) . substr($user['phone'], -3); header("Location: reset-password.php?step=verify&uid={$user['user_id']}&phone=" . urlencode($phone_masked)); exit; } // ============================================= // SCHRITT 2: OTP verifizieren → Reset-Token erzeugen // ============================================= if ($action === "verify_otp") { $user_id = (int)($_POST["user_id"] ?? 0); $otp_code = trim($_POST["otp_code"] ?? ''); if ($user_id === 0 || strlen($otp_code) !== 6) { header("Location: reset-password.php?error=3"); exit; } // OTP prüfen – Vergleich mit PHP-Zeit statt DB NOW() $now = date('Y-m-d H:i:s'); $stmt = $pdo->prepare("SELECT id FROM password_reset_otp WHERE user_id = ? AND otp_code = ? AND used = 0 AND expires_at > ?"); $stmt->execute([$user_id, $otp_code, $now]); $otpRecord = $stmt->fetch(); if (!$otpRecord) { header("Location: reset-password.php?step=verify&uid={$user_id}&error=3"); exit; } // OTP als verwendet markieren $stmt = $pdo->prepare("UPDATE password_reset_otp SET used = 1 WHERE id = ?"); $stmt->execute([$otpRecord['id']]); // Einmal-Token für Passwort-Änderung generieren (in Session speichern) $reset_token = bin2hex(random_bytes(32)); if (session_status() == PHP_SESSION_NONE) { session_start(); } $_SESSION['reset_token'] = $reset_token; $_SESSION['reset_user_id'] = $user_id; $_SESSION['reset_token_expires'] = time() + 600; // 10 Minuten header("Location: reset-password.php?step=newpassword&token=" . urlencode($reset_token)); exit; } // ============================================= // SCHRITT 3: Neues Passwort setzen (nach OTP-Verifizierung) // ============================================= if ($action === "set_password") { if (session_status() == PHP_SESSION_NONE) { session_start(); } $reset_token = $_POST["reset_token"] ?? ''; $new_password = $_POST["new_password"] ?? ''; $new_password_confirm = $_POST["new_password_confirm"] ?? ''; // Token validieren if (empty($reset_token) || !isset($_SESSION['reset_token']) || $reset_token !== $_SESSION['reset_token'] || !isset($_SESSION['reset_token_expires']) || $_SESSION['reset_token_expires'] < time()) { // Session-Daten aufräumen unset($_SESSION['reset_token'], $_SESSION['reset_user_id'], $_SESSION['reset_token_expires']); header("Location: reset-password.php?error=7"); exit; } $user_id = (int)$_SESSION['reset_user_id']; // Passwort-Validierung if (strlen($new_password) < 8 || !preg_match("/[a-z]/i", $new_password) || !preg_match("/[0-9]/", $new_password)) { header("Location: reset-password.php?step=newpassword&token=" . urlencode($reset_token) . "&error=5"); exit; } if ($new_password !== $new_password_confirm) { header("Location: reset-password.php?step=newpassword&token=" . urlencode($reset_token) . "&error=6"); exit; } // Neues Passwort setzen $password_hash = password_hash($new_password, PASSWORD_DEFAULT); $stmt = $pdo->prepare("UPDATE user_login SET password_hash = ? WHERE user_id = ?"); $stmt->execute([$password_hash, $user_id]); // User-Daten laden für Mail und Vermerk $stmt = $pdo->prepare("SELECT mail, first_name, last_name FROM user_general_information WHERE user_id = ?"); $stmt->execute([$user_id]); $resetUserData = $stmt->fetch(); if ($resetUserData) { $loginUrl = "https://" . ($_SERVER['HTTP_HOST'] ?? intranet_env('INTRANET_FQDN')) . "/intranet_repo/projects/authorization/login.php"; $greeting = !empty($resetUserData['first_name']) ? "Hallo {$resetUserData['first_name']}" : "Hallo"; $mailBetreff = "Passwort erfolgreich geändert"; $mailNachricht = "{$greeting},\n\n"; $mailNachricht .= "Ihr Passwort für das Intranet der NAK Reinickendorf wurde erfolgreich geändert.\n\n"; $mailNachricht .= "Sie können sich ab sofort mit Ihrem neuen Passwort anmelden."; send_intranet_mail($resetUserData['mail'], $mailBetreff, $mailNachricht, null, "intranet@nak-reinickendorf.de", "Jetzt anmelden", $loginUrl); // Vermerk in erledigte Tasks $userName = trim(($resetUserData['first_name'] ?? '') . ' ' . ($resetUserData['last_name'] ?? '')); if (empty($userName)) $userName = $resetUserData['mail']; $taskSubject = "Passwort selbst zurückgesetzt: {$userName}"; $taskMessage = "{$userName} ({$resetUserData['mail']}) hat das eigene Passwort erfolgreich zurückgesetzt."; $stmt = $pdo->prepare("INSERT INTO admin_messages (type, sender_name, sender_email, subject, message, status, processed_at, created_at) VALUES ('system', ?, ?, ?, ?, 'done', NOW(), NOW())"); $stmt->execute([$userName, $resetUserData['mail'], $taskSubject, $taskMessage]); } // Session-Daten aufräumen unset($_SESSION['reset_token'], $_SESSION['reset_user_id'], $_SESSION['reset_token_expires']); header("Location: login.php?message=1"); exit; } header("Location: reset-password.php"); exit; ?>