mirror of
https://codeberg.org/PostERG/xamxam.git
synced 2026-05-06 19:19:19 +02:00
- lib/AdminAuth.php: new class with requireLogin(), login(), logout(), isAuthenticated(); starts session with hardened cookie params (HttpOnly, SameSite=Strict, Secure, Path=/admin) — also resolves item #8 (session cookie hardening) - requireLogin() auto-authenticates from nginx Basic Auth credentials ($_SERVER['PHP_AUTH_PW']) so the user only sees one browser prompt; falls back to /admin/login.php if the proxy is absent/misconfigured - config/admin_credentials.php: gitignored credential store; define ADMIN_PASSWORD_HASH with a bcrypt hash to enable PHP auth - config/admin_credentials.example.php: template for the above - config/bootstrap.php: auto-loads admin_credentials.php if present - .gitignore: exclude config/admin_credentials.php - public/admin/login.php: fallback login form (shown only when nginx Basic Auth is bypassed / proxy absent) - public/admin/logout.php: session destruction + redirect to login - All 7 admin PHP files: replace session_start() with AdminAuth::requireLogin() (defence-in-depth behind nginx Basic Auth) - public/admin/inc/head.php: Déconnexion button when ADMIN_PASSWORD_HASH is defined - nginx/PHP_AUTH_LAYER.md: documents dual-auth architecture, UX flow, and setup instructions - docs/TODO.SECURITY.md: items #2 and #8 moved to Resolved; priority order updated (all CRITICAL done)
202 lines
7.4 KiB
PHP
202 lines
7.4 KiB
PHP
<?php
|
|
// Bootstrap application
|
|
require_once __DIR__ . "/../../config/bootstrap.php";
|
|
require_once __DIR__ . '/../../lib/AdminAuth.php';
|
|
|
|
// PHP-level auth guard (defence-in-depth behind nginx Basic Auth)
|
|
AdminAuth::requireLogin();
|
|
|
|
// Configure error reporting
|
|
ini_set('display_errors', 0);
|
|
ini_set('log_errors', 1);
|
|
ini_set('error_log', 'error.log');
|
|
|
|
require __DIR__ . '/../../lib/Database.php';
|
|
|
|
// Security: Validate thesis ID parameter
|
|
$thesisId = null;
|
|
$thesis = null;
|
|
$files = [];
|
|
$error = null;
|
|
|
|
if (isset($_GET['id'])) {
|
|
$thesisId = filter_var($_GET['id'], FILTER_VALIDATE_INT);
|
|
|
|
if ($thesisId !== false && $thesisId > 0) {
|
|
try {
|
|
$db = new Database();
|
|
$pdo = $db->getPDO();
|
|
|
|
// Get thesis data
|
|
$thesis = $db->getThesis($thesisId);
|
|
|
|
if (!$thesis) {
|
|
$error = "TFE non trouvé.";
|
|
} else {
|
|
// Get associated files
|
|
$stmt = $pdo->prepare("
|
|
SELECT file_type, file_name, file_size, mime_type, uploaded_at
|
|
FROM thesis_files
|
|
WHERE thesis_id = ?
|
|
ORDER BY file_type, uploaded_at
|
|
");
|
|
$stmt->execute([$thesisId]);
|
|
$files = $stmt->fetchAll();
|
|
}
|
|
} catch (Exception $e) {
|
|
error_log("Error loading thesis: " . $e->getMessage());
|
|
$error = "Erreur lors de la lecture des données.";
|
|
}
|
|
} else {
|
|
error_log("Invalid thesis ID: " . $_GET['id']);
|
|
$error = "Identifiant invalide.";
|
|
}
|
|
} else {
|
|
$error = "Aucun identifiant spécifié.";
|
|
}
|
|
|
|
// Helper function to format file size
|
|
function formatFileSize($bytes) {
|
|
if ($bytes >= 1073741824) {
|
|
return number_format($bytes / 1073741824, 2) . ' GB';
|
|
} elseif ($bytes >= 1048576) {
|
|
return number_format($bytes / 1048576, 2) . ' MB';
|
|
} elseif ($bytes >= 1024) {
|
|
return number_format($bytes / 1024, 2) . ' KB';
|
|
} else {
|
|
return $bytes . ' bytes';
|
|
}
|
|
}
|
|
|
|
// Set page title for header
|
|
$pageTitle = "Merci";
|
|
?>
|
|
<?php require_once __DIR__ . '/inc/head.php'; ?>
|
|
|
|
<main>
|
|
<?php if ($error): ?>
|
|
<div class="error">
|
|
<p>⚠️ <?php echo htmlspecialchars($error); ?></p>
|
|
<p><a href="/admin/add.php">Retour au formulaire</a></p>
|
|
</div>
|
|
|
|
<?php elseif ($thesis): ?>
|
|
<p>d'avoir soumis votre TFE. Les informations ont été enregistrées et sont en attente de traitement.</p>
|
|
|
|
<div class="thesis-info">
|
|
<h2>Récapitulatif de votre soumission</h2>
|
|
|
|
<h3>Informations de base</h3>
|
|
<dl>
|
|
<dt>Identifiant:</dt>
|
|
<dd><strong><?php echo htmlspecialchars($thesis['identifier']); ?></strong></dd>
|
|
|
|
<dt>Titre:</dt>
|
|
<dd><?php echo htmlspecialchars($thesis['title']); ?></dd>
|
|
|
|
<?php if ($thesis['subtitle']): ?>
|
|
<dt>Sous-titre:</dt>
|
|
<dd><?php echo htmlspecialchars($thesis['subtitle']); ?></dd>
|
|
<?php endif; ?>
|
|
|
|
<dt>Auteur·ice(s):</dt>
|
|
<dd><?php echo htmlspecialchars($thesis['authors']); ?></dd>
|
|
|
|
<dt>Année:</dt>
|
|
<dd><?php echo htmlspecialchars($thesis['year']); ?></dd>
|
|
</dl>
|
|
|
|
<h3>Détails académiques</h3>
|
|
<dl>
|
|
<dt>Orientation:</dt>
|
|
<dd><?php echo htmlspecialchars($thesis['orientation'] ?? 'Non spécifié'); ?></dd>
|
|
|
|
<dt>Atelier Pratique:</dt>
|
|
<dd><?php echo htmlspecialchars($thesis['ap_program'] ?? 'Non spécifié'); ?></dd>
|
|
|
|
<dt>Finalité:</dt>
|
|
<dd><?php echo htmlspecialchars($thesis['finality_type'] ?? 'Non spécifié'); ?></dd>
|
|
|
|
<?php if ($thesis['supervisors']): ?>
|
|
<dt>Promoteur·ice(s):</dt>
|
|
<dd><?php echo htmlspecialchars($thesis['supervisors']); ?></dd>
|
|
<?php endif; ?>
|
|
</dl>
|
|
|
|
<h3>Contenu</h3>
|
|
<dl>
|
|
<?php if ($thesis['synopsis']): ?>
|
|
<dt>Synopsis:</dt>
|
|
<dd><?php echo nl2br(htmlspecialchars($thesis['synopsis'])); ?></dd>
|
|
<?php endif; ?>
|
|
|
|
<?php if ($thesis['languages']): ?>
|
|
<dt>Langue(s):</dt>
|
|
<dd><?php echo htmlspecialchars($thesis['languages']); ?></dd>
|
|
<?php endif; ?>
|
|
|
|
<?php if ($thesis['formats']): ?>
|
|
<dt>Format(s):</dt>
|
|
<dd><?php echo htmlspecialchars($thesis['formats']); ?></dd>
|
|
<?php endif; ?>
|
|
|
|
<?php if ($thesis['keywords']): ?>
|
|
<dt>Mots-clés:</dt>
|
|
<dd><?php echo htmlspecialchars($thesis['keywords']); ?></dd>
|
|
<?php endif; ?>
|
|
|
|
<?php if ($thesis['file_size_info']): ?>
|
|
<dt>Durée/Taille:</dt>
|
|
<dd><?php echo htmlspecialchars($thesis['file_size_info']); ?></dd>
|
|
<?php endif; ?>
|
|
|
|
<?php if ($thesis['baiu_link']): ?>
|
|
<dt>Lien:</dt>
|
|
<dd><a href="<?php echo htmlspecialchars($thesis['baiu_link']); ?>" target="_blank" rel="noopener noreferrer">
|
|
<?php echo htmlspecialchars($thesis['baiu_link']); ?>
|
|
</a></dd>
|
|
<?php endif; ?>
|
|
</dl>
|
|
|
|
<?php if (!empty($files)): ?>
|
|
<h3>Fichiers téléversés</h3>
|
|
<table>
|
|
<thead>
|
|
<tr>
|
|
<th>Type</th>
|
|
<th>Nom du fichier</th>
|
|
<th>Taille</th>
|
|
<th>Date</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<?php foreach ($files as $file): ?>
|
|
<tr>
|
|
<td><?php echo htmlspecialchars($file['file_type']); ?></td>
|
|
<td><?php echo htmlspecialchars($file['file_name']); ?></td>
|
|
<td><?php echo formatFileSize($file['file_size']); ?></td>
|
|
<td><?php echo date('d/m/Y H:i', strtotime($file['uploaded_at'])); ?></td>
|
|
</tr>
|
|
<?php endforeach; ?>
|
|
</tbody>
|
|
</table>
|
|
<?php endif; ?>
|
|
|
|
<h3>Statut de publication</h3>
|
|
<p><strong>⏳ En attente</strong> - Votre TFE ne sera publié qu'après la soutenance et l'ajout éventuel d'une note contextuelle par le jury.</p>
|
|
|
|
<p class="submitted-date">
|
|
Soumis le <?php echo date('d/m/Y à H:i', strtotime($thesis['submitted_at'])); ?>
|
|
</p>
|
|
</div>
|
|
|
|
<p><a href="/admin/add.php">Soumettre un autre TFE</a></p>
|
|
|
|
<?php else: ?>
|
|
<p>Aucune donnée à afficher.</p>
|
|
<p><a href="/admin/add.php">Retour au formulaire</a></p>
|
|
<?php endif; ?>
|
|
</main>
|
|
|
|
<?php require_once __DIR__ . '/inc/footer.php'; ?>
|