Sécurité et qualité : headers HTTP, permissions .env, lint PHPStan + PHP-CS-Fixer, réorganisation dossiers, scripts de déploiement
This commit is contained in:
+29
-12
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
// projet : mug.a5l.fr
|
||||
// fichier : pages/login/magic.php
|
||||
// version : 20251011
|
||||
@@ -8,13 +9,17 @@ require_once dirname(__DIR__, 2) . '/vendor/autoload.php';
|
||||
require_once dirname(__DIR__, 2) . '/app/bootstrap.php';
|
||||
require_once dirname(__DIR__, 2) . '/config/config.php';
|
||||
|
||||
use App\Service\AuthService; // si tu as un service pour ouvrir une session
|
||||
// si tu as un service pour ouvrir une session
|
||||
|
||||
if (!function_exists('db')) {
|
||||
function db(): PDO { return \App\Infrastructure\Database::get(); }
|
||||
function db(): PDO
|
||||
{
|
||||
return \App\Infrastructure\Database::get();
|
||||
}
|
||||
}
|
||||
if (!function_exists('url')) {
|
||||
function url(string $path = '/'): string {
|
||||
function url(string $path = '/'): string
|
||||
{
|
||||
$scheme = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? 'https' : 'http';
|
||||
$host = $_SERVER['HTTP_HOST'] ?? 'localhost';
|
||||
return $scheme . '://' . $host . $path;
|
||||
@@ -31,24 +36,32 @@ $pdo = db();
|
||||
$pdo->beginTransaction();
|
||||
try {
|
||||
// récupère lien non consommé et non expiré
|
||||
$sql = "SELECT id, email, token, created_at, expires_at, consumed_at, return_to
|
||||
$sql = 'SELECT id, email, token, created_at, expires_at, consumed_at, return_to
|
||||
FROM auth_magic_links
|
||||
WHERE token = :t
|
||||
FOR UPDATE";
|
||||
FOR UPDATE';
|
||||
$stmt = $pdo->prepare($sql);
|
||||
$stmt->execute([':t' => $token]);
|
||||
$row = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
|
||||
if (!$row) throw new RuntimeException('Lien inconnu.');
|
||||
if ($row['consumed_at'] !== null) throw new RuntimeException('Lien déjà utilisé.');
|
||||
if (strtotime((string)$row['expires_at']) < time()) throw new RuntimeException('Lien expiré.');
|
||||
if (!$row) {
|
||||
throw new RuntimeException('Lien inconnu.');
|
||||
}
|
||||
if ($row['consumed_at'] !== null) {
|
||||
throw new RuntimeException('Lien déjà utilisé.');
|
||||
}
|
||||
if (strtotime((string)$row['expires_at']) < time()) {
|
||||
throw new RuntimeException('Lien expiré.');
|
||||
}
|
||||
|
||||
// consomme le lien
|
||||
$pdo->prepare("UPDATE auth_magic_links SET consumed_at = NOW() WHERE id = :id")->execute([':id' => $row['id']]);
|
||||
$pdo->prepare('UPDATE auth_magic_links SET consumed_at = NOW() WHERE id = :id')->execute([':id' => $row['id']]);
|
||||
$pdo->commit();
|
||||
|
||||
// ouvre une session applicative « anonyme authentifiée par email »
|
||||
if (session_status() !== PHP_SESSION_ACTIVE) session_start();
|
||||
if (session_status() !== PHP_SESSION_ACTIVE) {
|
||||
session_start();
|
||||
}
|
||||
$_SESSION['auth'] = [
|
||||
'method' => 'magic',
|
||||
'email' => (string)$row['email'],
|
||||
@@ -58,11 +71,15 @@ try {
|
||||
|
||||
$dest = $row['return_to'] ?? '/';
|
||||
// sécurité: ne renvoyer que des chemins relatifs
|
||||
if (!is_string($dest) || !str_starts_with($dest, '/')) $dest = '/';
|
||||
if (!is_string($dest) || !str_starts_with($dest, '/')) {
|
||||
$dest = '/';
|
||||
}
|
||||
header('Location: ' . $dest, true, 303);
|
||||
exit;
|
||||
} catch (\Throwable $e) {
|
||||
if ($pdo->inTransaction()) $pdo->rollBack();
|
||||
if ($pdo->inTransaction()) {
|
||||
$pdo->rollBack();
|
||||
}
|
||||
http_response_code(400);
|
||||
echo htmlspecialchars($e->getMessage(), ENT_QUOTES);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user