Files
MSPPPPaM/auth/reset_hesla.php
T

196 lines
6.2 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
// ============================================================
// OBNOVA HESLA KROK 1
// ============================================================
// Uživatel zadá svůj email. Pokud existuje v DB, odešleme mu
// email s odkazem na stránku pro zadání nového hesla.
//
// DŮLEŽITÉ: Vždy zobrazíme stejnou hlášku bez ohledu na to,
// zda email v DB existuje nebo ne. Útočník tak nezjistí,
// které emaily jsou v systému registrovány.
// ============================================================
require_once __DIR__ . '/config.php';
require_once __DIR__ . '/db.php';
require_once __DIR__ . '/mail.php';
session_name(SESSION_NAZEV);
session_set_cookie_params([
'lifetime' => 0,
'path' => '/',
'httponly' => true,
'samesite' => 'Strict',
// 'secure' => true,
]);
session_start();
// Pokud je uživatel přihlášen, přesměrujeme ho
if (isset($_SESSION['uzivatel_id'])) {
header('Location: ' . AUTH_REDIRECT_PO_PRIHLASENI);
exit;
}
// ------------------------------------------------------------
// CSRF TOKEN
// ------------------------------------------------------------
if (empty($_SESSION['csrf_token'])) {
$_SESSION['csrf_token'] = bin2hex(random_bytes(32));
}
$csrf_token = $_SESSION['csrf_token'];
// ------------------------------------------------------------
// ZPRACOVÁNÍ FORMULÁŘE
// ------------------------------------------------------------
// Tuto hlášku zobrazíme vždy po odeslání formuláře
// bez ohledu na to, zda email existuje
$zprava_po_odeslani = 'Pokud je zadaný email registrován, '
. 'přijde ti na něj odkaz pro obnovu hesla. '
. 'Odkaz bude platný 1 hodinu.';
$odeslano = false;
$chyba = '';
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
// -- Ověření CSRF tokenu ----------------------------------
$csrf_z_formulare = $_POST['csrf_token'] ?? '';
if (!hash_equals($csrf_token, $csrf_z_formulare)) {
$chyba = 'Neplatný požadavek. Zkuste stránku obnovit a zkusit znovu.';
}
if (empty($chyba)) {
$email = trim($_POST['email'] ?? '');
if (empty($email) || !filter_var($email, FILTER_VALIDATE_EMAIL)) {
$chyba = 'Zadejte platnou emailovou adresu.';
}
}
if (empty($chyba)) {
// Vyhledáme uživatele v DB
$stmt = $pdo->prepare("
SELECT `id`
FROM `" . DB_TABULKA_UZIVATELE . "`
WHERE `email` = :email
LIMIT 1
");
$stmt->execute([':email' => $email]);
$uzivatel = $stmt->fetch();
if ($uzivatel) {
// -- Uživatel existuje vytvoříme reset token ----
// Smažeme případné staré (nepoužité) tokeny tohoto uživatele
$stmt2 = $pdo->prepare("
DELETE FROM `" . DB_TABULKA_RESET . "`
WHERE `uzivatel_id` = :uzivatel_id
");
$stmt2->execute([':uzivatel_id' => $uzivatel['id']]);
// Vygenerujeme nový token
// Do emailu jde plaintext, do DB jde jen hash
$token = bin2hex(random_bytes(32)); // 64 znaků hex
$token_hash = password_hash($token, PASSWORD_DEFAULT);
$expiruje = date('Y-m-d H:i:s', time() + 3600); // 1 hodina
$stmt3 = $pdo->prepare("
INSERT INTO `" . DB_TABULKA_RESET . "`
(`uzivatel_id`, `token_hash`, `expiruje`)
VALUES
(:uzivatel_id, :token_hash, :expiruje)
");
$stmt3->execute([
':uzivatel_id' => $uzivatel['id'],
':token_hash' => $token_hash,
':expiruje' => $expiruje,
]);
$reset_id = $pdo->lastInsertId();
// Sestavíme odkaz pro obnovu hesla
// Odkaz obsahuje ID záznamu a plaintext token
$odkaz = PROJEKT_URL . '/auth/nove_heslo.php'
. '?id=' . urlencode($reset_id)
. '&token=' . urlencode($token);
// Odešleme email
$predmet = 'Obnova hesla ' . PROJEKT_NAZEV;
$text = "Ahoj,\n\n"
. "požádal(a) jsi o obnovu hesla na " . PROJEKT_NAZEV . ".\n\n"
. "Pro nastavení nového hesla klikni na tento odkaz:\n"
. $odkaz . "\n\n"
. "Odkaz je platný 1 hodinu.\n\n"
. "Pokud jsi o obnovu hesla nežádal(a), tento email ignoruj.\n\n"
. PROJEKT_NAZEV;
odesli_mail($email, $predmet, $text);
}
// Zobrazíme stejnou hlášku bez ohledu na existenci emailu
$odeslano = true;
}
}
// ------------------------------------------------------------
// HTML VÝSTUP
// ------------------------------------------------------------
?>
<!DOCTYPE html>
<html lang="cs">
<head>
<meta charset="UTF-8">
<title>Obnova hesla <?php echo htmlspecialchars(PROJEKT_NAZEV); ?></title>
<?php if (AUTH_CSS !== ''): ?>
<link rel="stylesheet" href="<?php echo htmlspecialchars(AUTH_CSS); ?>">
<?php endif; ?>
</head>
<body>
<h1>Obnova hesla</h1>
<h2><?php echo htmlspecialchars(PROJEKT_NAZEV); ?></h2>
<?php if ($odeslano): ?>
<p><?php echo htmlspecialchars($zprava_po_odeslani); ?></p>
<p><a href="<?php echo htmlspecialchars(AUTH_LOGIN_URL); ?>">Zpět na přihlášení</a></p>
<?php else: ?>
<?php if (!empty($chyba)): ?>
<p><strong>Chyba: <?php echo htmlspecialchars($chyba); ?></strong></p>
<?php endif; ?>
<p>Zadej svůj email a pošleme ti odkaz pro obnovu hesla.</p>
<form method="POST" action="">
<input type="hidden" name="csrf_token" value="<?php echo htmlspecialchars($csrf_token); ?>">
<p>
<label for="email">Email:</label><br>
<input
type="email"
id="email"
name="email"
required
autocomplete="email"
>
</p>
<p>
<button type="submit">Odeslat odkaz pro obnovu hesla</button>
</p>
</form>
<p><a href="<?php echo htmlspecialchars(AUTH_LOGIN_URL); ?>">Zpět na přihlášení</a></p>
<?php endif; ?>
</body>
</html>