224 lines
8.5 KiB
PHP
224 lines
8.5 KiB
PHP
<?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;
|
||
?>
|