Files
intranet/web/intranet_repo/projects/authorization/reset-password-process.php
T

224 lines
8.5 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 /* Name: reset-password-process.php
Beschreibung: Verarbeitung des Passwort-Resets (3 Schritte)
- Schritt 1: OTP generieren und per SMS + Mail senden
- Schritt 2: OTP verifizieren → Reset-Token erzeugen
- Schritt 3: Neues Passwort setzen mit Reset-Token */
$pdo = require_once($_SERVER['DOCUMENT_ROOT']."/intranet_repo/general_files/ini/database.php");
require_once $_SERVER['DOCUMENT_ROOT'].'/intranet_repo/general_files/ini/send_mail.php';
// PostgreSQL-Zeitzone auf PHP-Zeitzone setzen
$pdo->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;
?>