Files
pnpaas-adm/reset-password.php
T

112 lines
5.5 KiB
PHP
Raw Permalink 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
declare(strict_types=1);
require_once __DIR__ . '/includes/bootstrap.php';
pnpaas_session_start();
$token = trim((string)($_GET['token'] ?? $_POST['token'] ?? ''));
$csrfToken = pnpaas_csrf_token();
$error = null;
$success = null;
$validToken = false;
if (preg_match('/^[a-f0-9]{64}$/', $token)) {
try {
$check = pnpaas_db()->prepare(
'SELECT id, user_id FROM password_reset_tokens
WHERE token_hash = :token_hash AND used_at IS NULL AND expires_at > NOW()
LIMIT 1'
);
$check->execute(['token_hash' => hash('sha256', $token)]);
$validToken = is_array($check->fetch());
} catch (Throwable $exception) {
error_log('PnPaaS password reset validation error: ' . $exception->getMessage());
$error = 'Der Zurücksetzungslink ist derzeit nicht verfügbar.';
}
}
if ($_SERVER['REQUEST_METHOD'] === 'POST' && $error === null) {
$password = (string)($_POST['password'] ?? '');
$passwordConfirmation = (string)($_POST['password_confirmation'] ?? '');
if (!pnpaas_valid_csrf((string)($_POST['csrf_token'] ?? ''))) {
$error = 'Die Sitzung ist abgelaufen. Bitte öffnen Sie den Link erneut.';
} elseif (!$validToken) {
$error = 'Der Link ist ungültig oder abgelaufen. Bitte fordern Sie einen neuen Link an.';
} elseif (strlen($password) < 12) {
$error = 'Das Passwort muss mindestens 12 Zeichen lang sein.';
} elseif ($password !== $passwordConfirmation) {
$error = 'Die Passwörter stimmen nicht überein.';
} else {
try {
$db = pnpaas_db();
$db->beginTransaction();
$find = $db->prepare(
'SELECT id, user_id FROM password_reset_tokens
WHERE token_hash = :token_hash AND used_at IS NULL AND expires_at > NOW()
FOR UPDATE'
);
$find->execute(['token_hash' => hash('sha256', $token)]);
$reset = $find->fetch();
if (!is_array($reset)) {
$db->rollBack();
$validToken = false;
$error = 'Der Link ist ungültig oder abgelaufen. Bitte fordern Sie einen neuen Link an.';
} else {
$update = $db->prepare('UPDATE users SET password_hash = :password_hash WHERE id = :user_id AND status = :status');
$update->execute([
'password_hash' => password_hash($password, PASSWORD_DEFAULT),
'user_id' => (int)$reset['user_id'],
'status' => 'active',
]);
$used = $db->prepare('UPDATE password_reset_tokens SET used_at = NOW() WHERE user_id = :user_id');
$used->execute(['user_id' => (int)$reset['user_id']]);
$db->commit();
$success = 'Ihr Passwort wurde geändert. Sie können sich jetzt anmelden.';
$validToken = false;
}
} catch (Throwable $exception) {
if (isset($db) && $db instanceof PDO && $db->inTransaction()) {
$db->rollBack();
}
error_log('PnPaaS password reset update error: ' . $exception->getMessage());
$error = 'Das Passwort konnte nicht geändert werden. Bitte versuchen Sie es erneut.';
}
}
}
?>
<!doctype html>
<html lang="de">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>PnPaaS Neues Passwort</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Montserrat:wght@500;600&family=Open+Sans:wght@400;600;700&display=swap" rel="stylesheet">
<link rel="stylesheet" href="assets/style.css">
</head>
<body class="auth-page">
<main class="auth-card" aria-labelledby="reset-title">
<div class="brand-mark" aria-hidden="true">✦</div>
<p class="eyebrow">PnPaaS Administration</p>
<h1 id="reset-title">Neues Passwort</h1>
<?php if ($error !== null): ?><div class="alert alert-error" role="alert"><?= htmlspecialchars($error, ENT_QUOTES, 'UTF-8') ?></div><?php endif; ?>
<?php if ($success !== null): ?><div class="alert alert-success" role="status"><?= htmlspecialchars($success, ENT_QUOTES, 'UTF-8') ?></div><p class="form-footer"><a href="index.php">Zur Anmeldung</a></p><?php elseif ($validToken): ?>
<p class="intro">Vergeben Sie ein neues Passwort für Ihr Konto.</p>
<form method="post" action="reset-password.php" class="login-form">
<input type="hidden" name="csrf_token" value="<?= htmlspecialchars($csrfToken, ENT_QUOTES, 'UTF-8') ?>">
<input type="hidden" name="token" value="<?= htmlspecialchars($token, ENT_QUOTES, 'UTF-8') ?>">
<label for="password">Neues Passwort</label>
<input id="password" name="password" type="password" autocomplete="new-password" minlength="12" required>
<label for="password_confirmation">Passwort wiederholen</label>
<input id="password_confirmation" name="password_confirmation" type="password" autocomplete="new-password" minlength="12" required>
<button type="submit">Passwort speichern</button>
</form>
<?php elseif ($error === null): ?>
<div class="alert alert-error" role="alert">Der Link ist ungültig oder abgelaufen. Bitte fordern Sie einen neuen Link an.</div>
<p class="form-footer"><a href="forgot-password.php">Neuen Link anfordern</a></p>
<?php endif; ?>
</main>
</body>
</html>