fix: session boot on POST path, consolidate rate limiter via checkKey()

This commit is contained in:
Pontoporeia
2026-04-16 12:56:06 +02:00
parent a6df3c8c0e
commit e70a65ffb6
3 changed files with 43 additions and 23 deletions

View File

@@ -29,6 +29,9 @@ if (!preg_match('#^\d{8}-[A-Z0-9+/]{8}$#', $slug)) {
exit;
}
// Boot for all requests: starts session, initialises DB, ensures CSRF token.
App::boot();
// ── POST: form submission ─────────────────────────────────────────────────────
if ($_SERVER['REQUEST_METHOD'] === 'POST' && $action === 'submit') {
handleShareLinkSubmission($slug);
@@ -36,7 +39,6 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && $action === 'submit') {
}
// ── GET: render form ─────────────────────────────────────────────────────────
App::boot(); // boot database + CSRF
require_once APP_ROOT . '/src/ShareLink.php';
$shareLinkModel = new ShareLink(Database::getInstance());
@@ -480,7 +482,11 @@ function renderShareLinkForm(string $slug, array $link): void
*/
function handleShareLinkSubmission(string $slug): void
{
session_start();
// Session already started by App::boot() on the GET path; start here
// only if somehow not yet active (e.g. direct POST without prior GET).
if (session_status() === PHP_SESSION_NONE) {
session_start();
}
require_once APP_ROOT . '/src/ShareLink.php';
require_once APP_ROOT . '/src/RateLimit.php';
@@ -496,33 +502,16 @@ function handleShareLinkSubmission(string $slug): void
}
// ── Rate limiting ────────────────────────────────────────────────────────
// Allow max 5 submissions per IP per 10 minutes (per share link)
// 5 submissions per IP per 10 minutes, keyed per share link.
$rateLimitCacheDir = STORAGE_ROOT . '/cache/rate_limit';
if (!is_dir($rateLimitCacheDir)) {
@mkdir($rateLimitCacheDir, 0755, true);
}
$shareRateLimitId = 'share_' . $slug . '_' . ($_SERVER['REMOTE_ADDR'] ?? 'unknown');
$rateLimit = new RateLimit(5, 600, $rateLimitCacheDir);
$shareRateLimitId = 'share_' . $slug . '_' . ($_SERVER['REMOTE_ADDR'] ?? 'unknown');
$rateLimit = new RateLimit(5, 600, $rateLimitCacheDir);
// Use a custom identifier based on slug + IP so each share link is rate-limited independently
$rateLimitFile = $rateLimitCacheDir . '/' . md5($shareRateLimitId) . '.json';
$data = [];
if (file_exists($rateLimitFile)) {
$content = file_get_contents($rateLimitFile);
$data = json_decode($content, true) ?? [];
}
$now = time();
$data = array_filter($data, fn($ts) => ($now - $ts) < 600);
if (count($data) >= 5) {
if (!$rateLimit->checkKey($shareRateLimitId)) {
$_SESSION['_flash_error'] = 'Trop de tentatives. Veuillez réessayer plus tard.';
header('Location: /partage/' . urlencode($slug));
exit;
}
$data[] = $now;
if (is_writable($rateLimitCacheDir)) {
file_put_contents($rateLimitFile, json_encode($data));
}
// ── End rate limiting ────────────────────────────────────────────────────
// Check password verification if link has a password