249 lines
7.8 KiB
PHP
249 lines
7.8 KiB
PHP
<?php
|
||
// ============================================================
|
||
// PŘIHLAŠOVACÍ STRÁNKA
|
||
// ============================================================
|
||
|
||
require_once __DIR__ . '/config.php';
|
||
require_once __DIR__ . '/db.php';
|
||
|
||
// Spuštění session (stejné nastavení jako v auth.php)
|
||
session_name(SESSION_NAZEV);
|
||
session_set_cookie_params([
|
||
'lifetime' => 0,
|
||
'path' => '/',
|
||
'httponly' => true,
|
||
'samesite' => 'Strict',
|
||
// 'secure' => true,
|
||
]);
|
||
session_start();
|
||
|
||
// Pokud je uživatel již přihlášen, přesměrujeme ho rovnou dál
|
||
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
|
||
// ------------------------------------------------------------
|
||
|
||
$chyba = '';
|
||
$email_hodnota = '';
|
||
|
||
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 přihlásit se znovu.';
|
||
}
|
||
|
||
if (empty($chyba)) {
|
||
|
||
$email = trim($_POST['email'] ?? '');
|
||
$heslo = $_POST['heslo'] ?? '';
|
||
$zapamatovat = isset($_POST['zapamatovat']);
|
||
|
||
$email_hodnota = htmlspecialchars($email);
|
||
|
||
if (empty($email) || empty($heslo)) {
|
||
$chyba = 'Zadejte email a heslo.';
|
||
}
|
||
}
|
||
|
||
if (empty($chyba)) {
|
||
|
||
// -- Kontrola brute force -----------------------------
|
||
$ip = $_SERVER['REMOTE_ADDR'] ?? '0.0.0.0';
|
||
$okno_od = date('Y-m-d H:i:s', time() - BRUTE_OKNO);
|
||
|
||
$stmt = $pdo->prepare("
|
||
SELECT COUNT(*) AS pocet
|
||
FROM `" . DB_TABULKA_BRUTE . "`
|
||
WHERE (`ip_adresa` = :ip OR `email` = :email)
|
||
AND `cas` > :okno_od
|
||
");
|
||
$stmt->execute([
|
||
':ip' => $ip,
|
||
':email' => $email,
|
||
':okno_od' => $okno_od,
|
||
]);
|
||
$pocet_pokusu = $stmt->fetch()['pocet'];
|
||
|
||
if ($pocet_pokusu >= BRUTE_MAX_POKUSU) {
|
||
$chyba = 'Příliš mnoho neúspěšných pokusů. Zkuste to prosím za chvíli.';
|
||
}
|
||
}
|
||
|
||
if (empty($chyba)) {
|
||
|
||
// -- Ověření emailu a hesla v DB ----------------------
|
||
$stmt = $pdo->prepare("
|
||
SELECT `id`, `email`, `heslo`, `admin`
|
||
FROM `" . DB_TABULKA_UZIVATELE . "`
|
||
WHERE `email` = :email
|
||
LIMIT 1
|
||
");
|
||
$stmt->execute([':email' => $email]);
|
||
$uzivatel = $stmt->fetch();
|
||
|
||
// I když uživatel neexistuje, zavoláme password_verify na fiktivní
|
||
// hash – aby útočník nemohl podle doby odpovědi poznat, zda email existuje
|
||
$fiktivni_hash = '$2y$10$abcdefghijklmnopqrstuuABCDEFGHIJKLMNOPQRSTUVWXYZ01234';
|
||
$hash_k_overeni = $uzivatel ? $uzivatel['heslo'] : $fiktivni_hash;
|
||
$heslo_ok = password_verify($heslo, $hash_k_overeni);
|
||
|
||
if (!$uzivatel || !$heslo_ok) {
|
||
|
||
// Zapíšeme neúspěšný pokus
|
||
$stmt2 = $pdo->prepare("
|
||
INSERT INTO `" . DB_TABULKA_BRUTE . "`
|
||
(`ip_adresa`, `email`)
|
||
VALUES
|
||
(:ip, :email)
|
||
");
|
||
$stmt2->execute([
|
||
':ip' => $ip,
|
||
':email' => $email,
|
||
]);
|
||
|
||
$chyba = 'Nesprávný email nebo heslo.';
|
||
|
||
} else {
|
||
|
||
// -- Přihlášení úspěšné ---------------------------
|
||
session_regenerate_id(true);
|
||
|
||
$_SESSION['uzivatel_id'] = $uzivatel['id'];
|
||
$_SESSION['email'] = $uzivatel['email'];
|
||
$_SESSION['admin'] = (bool) $uzivatel['admin'];
|
||
$_SESSION['posledni_aktivita'] = time();
|
||
$_SESSION['csrf_token'] = bin2hex(random_bytes(32));
|
||
|
||
// -- Remember me ----------------------------------
|
||
if ($zapamatovat) {
|
||
|
||
$selector = bin2hex(random_bytes(16));
|
||
$token = bin2hex(random_bytes(32));
|
||
$token_hash = password_hash($token, PASSWORD_DEFAULT);
|
||
$expiruje = date('Y-m-d H:i:s', time() + REMEMBER_EXPIRACE);
|
||
|
||
$stmt3 = $pdo->prepare("
|
||
INSERT INTO `" . DB_TABULKA_TOKENY . "`
|
||
(`uzivatel_id`, `selector`, `token_hash`, `expiruje`)
|
||
VALUES
|
||
(:uzivatel_id, :selector, :token_hash, :expiruje)
|
||
");
|
||
$stmt3->execute([
|
||
':uzivatel_id' => $uzivatel['id'],
|
||
':selector' => $selector,
|
||
':token_hash' => $token_hash,
|
||
':expiruje' => $expiruje,
|
||
]);
|
||
|
||
$cookie_expirace = time() + REMEMBER_EXPIRACE;
|
||
setcookie('auth_selector', $selector, [
|
||
'expires' => $cookie_expirace,
|
||
'path' => '/',
|
||
'httponly' => true,
|
||
'samesite' => 'Strict',
|
||
// 'secure' => true,
|
||
]);
|
||
setcookie('auth_token', $token, [
|
||
'expires' => $cookie_expirace,
|
||
'path' => '/',
|
||
'httponly' => true,
|
||
'samesite' => 'Strict',
|
||
// 'secure' => true,
|
||
]);
|
||
}
|
||
|
||
// -- Přesměrování po přihlášení -------------------
|
||
$redirect = $_SESSION['redirect_po_prihlaseni'] ?? AUTH_REDIRECT_PO_PRIHLASENI;
|
||
unset($_SESSION['redirect_po_prihlaseni']);
|
||
|
||
header('Location: ' . $redirect);
|
||
exit;
|
||
}
|
||
}
|
||
}
|
||
|
||
// ------------------------------------------------------------
|
||
// HTML VÝSTUP
|
||
// ------------------------------------------------------------
|
||
?>
|
||
<!DOCTYPE html>
|
||
<html lang="cs">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<title>Přihlášení – <?php echo htmlspecialchars(PROJEKT_NAZEV); ?></title>
|
||
<?php if (AUTH_CSS !== ''): ?>
|
||
<link rel="stylesheet" href="<?php echo htmlspecialchars(AUTH_CSS); ?>">
|
||
<?php endif; ?>
|
||
</head>
|
||
<body>
|
||
|
||
<h1>Přihlášení</h1>
|
||
<h2><?php echo htmlspecialchars(PROJEKT_NAZEV); ?></h2>
|
||
|
||
<?php if (!empty($chyba)): ?>
|
||
<p><strong>Chyba: <?php echo htmlspecialchars($chyba); ?></strong></p>
|
||
<?php endif; ?>
|
||
|
||
<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"
|
||
value="<?php echo $email_hodnota; ?>"
|
||
required
|
||
autocomplete="email"
|
||
>
|
||
</p>
|
||
|
||
<p>
|
||
<label for="heslo">Heslo:</label><br>
|
||
<input
|
||
type="password"
|
||
id="heslo"
|
||
name="heslo"
|
||
required
|
||
autocomplete="current-password"
|
||
>
|
||
</p>
|
||
|
||
<p>
|
||
<label>
|
||
<input type="checkbox" name="zapamatovat" value="1">
|
||
Zapamatovat si mě
|
||
</label>
|
||
</p>
|
||
|
||
<p>
|
||
<button type="submit">Přihlásit se</button>
|
||
</p>
|
||
|
||
</form>
|
||
|
||
<?php if (REGISTRACE_OTEVRENA): ?>
|
||
<p><a href="<?php echo htmlspecialchars(AUTH_REGISTRACE_URL); ?>">Nemáš účet? Zaregistruj se.</a></p>
|
||
<?php endif; ?>
|
||
|
||
<p><a href="<?php echo htmlspecialchars(AUTH_RESET_URL); ?>">Zapomněl jsi heslo?</a></p>
|
||
|
||
</body>
|
||
</html>
|