[FÁZE-2][auth] Přidána stránka pro žádost o obnovu hesla
This commit is contained in:
@@ -0,0 +1,196 @@
|
|||||||
|
<?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>
|
||||||
Reference in New Issue
Block a user