Files

74 lines
3.6 KiB
PHP

<?php
//************************************************************************************************************
// live/auth.php - Ouverture d'une session Live (synthèse §49).
// Appelé via https://b<N>.ship2net.fr/_auth?ticket=... (routeur Traefik dédié, SANS ForwardAuth), juste après le
// clic sur "Live" dans le portail. Consomme le ticket (60 s, usage unique, lié au bateau), crée une session et pose
// le cookie HttpOnly propre au sous-domaine du bateau, puis renvoie vers l'application.
//************************************************************************************************************
require_once(__DIR__."/commun.php");
$id_bateau = Bateau_depuis_hote($_SERVER['HTTP_HOST'] ?? '');
$ticket = $_GET['ticket'] ?? '';
if ($id_bateau == 0 || !is_string($ticket) || preg_match('/^[0-9a-f]{64}$/', $ticket) !== 1)
{
Page_refus(400, "Lien Live invalide", "Ce lien n'est pas valide. Ouvrez le Live depuis la page du bateau, sur le portail.");
}
try
{
$db = Connexion_live();
// Purge des tickets et sessions périmés depuis plus d'un jour (ici : appelé rarement, à chaque ouverture de session) :
$db->query("DELETE FROM TB_Tickets_live WHERE Expiration < NOW() - INTERVAL 1 DAY");
$db->query("DELETE FROM TB_Sessions_live WHERE Expiration < NOW() - INTERVAL 1 DAY");
// Consommation du ticket : toutes les conditions DANS la mise à jour (usage unique, même en cas de requêtes simultanées) :
$empreinte_ticket = hash('sha256', $ticket);
$stmt = $db->prepare("UPDATE TB_Tickets_live SET Date_utilisation=NOW()
WHERE Empreinte=? AND ID_Bateau=? AND Date_utilisation IS NULL AND Expiration > NOW()");
$stmt->bind_param('si', $empreinte_ticket, $id_bateau);
$stmt->execute();
$consomme = ($stmt->affected_rows == 1);
$stmt->close();
if (!$consomme) Page_refus(403, "Lien Live expiré", "Ce lien a expiré ou a déjà été utilisé. Ouvrez à nouveau le Live depuis la page du bateau, sur le portail.");
$stmt = $db->prepare("SELECT ID_Shipmember FROM TB_Tickets_live WHERE Empreinte=?");
$stmt->bind_param('s', $empreinte_ticket);
$stmt->execute();
$id_shipmember = (int)$stmt->get_result()->fetch_row()[0];
$stmt->close();
if (!Droit_live($db, $id_shipmember, $id_bateau)) Page_refus(403, "Accès refusé", "Vous n'avez pas (ou plus) accès à ce bateau.");
// Durée de session (TB_Configuration, heures) :
$duree = DUREE_SESSION_LIVE_DEFAUT;
$resultat = $db->query("SELECT Valeur FROM TB_Configuration WHERE Nom='Duree_session_live' AND Validite=1");
if ($ligne = $resultat->fetch_row()) $duree = max(1, (int)$ligne[0]);
// Création de la session : seule l'empreinte de la valeur du cookie est enregistrée :
$valeur_cookie = bin2hex(random_bytes(32));
$empreinte_session = hash('sha256', $valeur_cookie);
$stmt = $db->prepare("INSERT INTO TB_Sessions_live (Empreinte, ID_Shipmember, ID_Bateau, Expiration) VALUES (?, ?, ?, NOW() + INTERVAL ? HOUR)");
$stmt->bind_param('siii', $empreinte_session, $id_shipmember, $id_bateau, $duree);
$stmt->execute();
$stmt->close();
$db->close();
}
catch (Throwable $e)
{
error_log("live/auth.php : ".$e->getMessage());
Page_refus(503, "Service momentanément indisponible", "Le Live ne peut pas être ouvert pour l'instant. Réessayez dans quelques instants.");
}
// Cookie propre à CE sous-domaine (pas d'attribut domain), inaccessible au code de la page (HttpOnly) :
setcookie(NOM_COOKIE_LIVE, $valeur_cookie, [
'expires' => time() + $duree * 3600,
'path' => '/',
'secure' => true,
'httponly' => true,
'samesite' => 'Lax',
]);
header('Cache-Control: no-store');
header('Location: /', true, 303); // L'URL du ticket disparaît de la barre d'adresse
exit();