File: /home/wbwebdes/domains/uren-registratie.blankevoort.net/public_html/src/Security/SessionHandler.php
<?php
/*
* This file is part of the Kimai time-tracking app.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace App\Security;
use Doctrine\DBAL\Connection;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpFoundation\Session\Storage\Handler\PdoSessionHandler;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
use Symfony\Component\RateLimiter\RateLimiterFactory;
final class SessionHandler extends PdoSessionHandler
{
public function __construct(
Connection $connection,
private readonly RateLimiterFactory $sessionPredictionLimiter,
private readonly RequestStack $requestStack
)
{
parent::__construct($connection->getNativeConnection(), [
'db_table' => 'kimai2_sessions',
'db_id_col' => 'id',
'db_data_col' => 'data',
'db_lifetime_col' => 'lifetime',
'db_time_col' => 'time',
'lock_mode' => PdoSessionHandler::LOCK_ADVISORY,
]);
}
public function garbageCollection(): void
{
$connection = $this->getConnection();
$sql = 'DELETE FROM kimai2_sessions WHERE lifetime < :time';
$stmt = $connection->prepare($sql);
$stmt->bindValue(':time', time(), \PDO::PARAM_INT);
$stmt->execute();
}
public function validateId(#[\SensitiveParameter] string $sessionId): bool
{
$result = parent::validateId($sessionId);
if ($result === false) {
$limiter = $this->sessionPredictionLimiter->create($this->requestStack->getMainRequest()?->getClientIp());
$limit = $limiter->consume();
if (false === $limit->isAccepted()) {
throw new BadRequestHttpException('Too many requests with invalid Session ID. Prediction attack?');
}
usleep(250000); // slow down potential attacks
}
return $result;
}
}