0 ? 'Retour au TFE' : 'Retour à l\'accueil'; echo ' ' . htmlspecialchars($title) . ' - XAMXAM

' . htmlspecialchars($title) . '

' . $body . '

' . $backLink . '

'; exit; } // ── Route: GET — show confirmation page ────────────────────────────────────── if ($_SERVER['REQUEST_METHOD'] === 'GET') { $token = isset($_GET['token']) ? trim($_GET['token']) : ''; $thesisId = isset($_GET['thesis']) ? (int)$_GET['thesis'] : 0; if (empty($token) || $thesisId <= 0) { renderError(400, 'Lien invalide', '

Ce lien d\'accès est invalide ou incomplet.

', $thesisId); } // Generate (or reuse) CSRF token in session App::boot(); if (empty($_SESSION['csrf_token'])) { $_SESSION['csrf_token'] = bin2hex(random_bytes(32)); } // Minimal pre-check: does the token exist and look valid? // (Full redemption + one-time mark only happens on POST) $db = Database::getInstance(); $check = $db->getPDO()->prepare( "SELECT fat.expires_at, fr.thesis_id FROM file_access_tokens fat JOIN file_access_requests fr ON fat.request_id = fr.id WHERE fat.token = ? AND fat.is_valid = 1 AND fat.used_at IS NULL AND fat.expires_at > CURRENT_TIMESTAMP AND fr.status = 'approved' AND fr.thesis_id = ? LIMIT 1" ); $check->execute([$token, $thesisId]); $valid = $check->fetch(); if (!$valid) { renderError(403, 'Lien d\'accès invalide ou expiré', '

Ce lien a déjà été utilisé ou a expiré. Veuillez soumettre une nouvelle demande.

', $thesisId); } $csrfToken = $_SESSION['csrf_token']; $safeToken = htmlspecialchars($token, ENT_QUOTES); ?> Activer l'accès - XAMXAM

Activer l'accès aux fichiers

Cliquez sur le bouton ci-dessous pour activer l'accès aux fichiers de ce TFE sur cet appareil.

L'accès sera valide pendant 30 jours sur cet appareil et navigateur.

Token de sécurité invalide. Veuillez réessayer.

'); } $token = isset($_POST['token']) ? trim($_POST['token']) : ''; $thesisId = isset($_POST['thesis_id']) ? (int)$_POST['thesis_id'] : 0; if (empty($token) || $thesisId <= 0) { renderError(400, 'Données invalides', '

Les données du formulaire sont invalides.

'); } $db = Database::getInstance(); // Redeem the one-time token (marks it used, logs audit trail) $ip = $_SERVER['REMOTE_ADDR'] ?? ''; $ua = substr($_SERVER['HTTP_USER_AGENT'] ?? '', 0, 512); $redemption = $db->redeemAccessToken($token, $ip, $ua); if (!$redemption || $redemption['thesis_id'] !== $thesisId) { renderError(403, 'Lien invalide ou déjà utilisé', '

Ce lien d\'accès est invalide, a déjà été utilisé, ou ne correspond pas au TFE demandé.

Si vous avez besoin d\'un nouvel accès, veuillez soumettre une nouvelle demande.

', $thesisId); } // Create a long-lived browser session (separate from the one-time email token) $sessionToken = $db->createAccessSession($redemption['request_id'], 30); // Set HttpOnly, Secure, SameSite=Strict cookie (long-lived session) $cookieName = 'tfe_access_' . $thesisId; $cookieSecure = !empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off'; setcookie($cookieName, $sessionToken, [ 'expires' => time() + 30 * 86400, 'path' => '/', 'domain' => '', 'secure' => $cookieSecure, 'httponly' => true, 'samesite' => 'Strict', ]); // Rotate CSRF token after successful action $_SESSION['csrf_token'] = bin2hex(random_bytes(32)); // Redirect to TFE page (no token in URL) header('Location: /tfe?id=' . $thesisId); exit; } // ── Any other method ────────────────────────────────────────────────────────── http_response_code(405); header('Allow: GET, POST'); echo 'Méthode non autorisée'; exit;