src/Services/Security/IpTools.php line 18

Open in your IDE?
  1. <?php
  2. namespace App\Services\Security;
  3. use Doctrine\Persistence\ManagerRegistry;
  4. use Symfony\Component\HttpFoundation\RequestStack;
  5. use App\Entity\Security\IpAttempt;
  6. use App\Entity\Security\IpBan;
  7. use App\Services\LogTools;
  8. class IpTools
  9. {
  10.     const MAX_LOGIN_FAILURE_ATTEMPTS 25;
  11.     const ATTEMPTS_INTERVAL_SECONDS 60 10;
  12.     const BAN_TIME_SECONDS 60 10;
  13.     public function __construct(ManagerRegistry $doctrineRequestStack $requestStackLogTools $logTools)
  14.     {
  15.         $this->em $doctrine->getManager();
  16.         $this->requestStack $requestStack;
  17.         $this->logTools $logTools;
  18.     }
  19.     public function fail2ban($args)
  20.     {
  21.         $request $this->requestStack->getCurrentRequest();
  22.         if ($request === null)
  23.         {
  24.             return false;
  25.         }
  26.         if (empty($request->getClientIp()))
  27.         {
  28.             return false;
  29.         }
  30.         // Various initialisations
  31.         $username null;
  32.         if (array_key_exists('username'$args))
  33.         {
  34.             $username $args['username'];
  35.         }
  36.         $errors = array();
  37.         // FormErrors
  38.         if (array_key_exists('form_errors'$args))
  39.         {
  40.             foreach ($args['form_errors'] as $key => $error)
  41.             {
  42.                 if ($error->getCause() !== null)
  43.                 {
  44.                     $errors[] = $error->getCause()->getMessageTemplate();
  45.                 }
  46.                 else
  47.                 {
  48.                     $errors[] = $error->getMessage();
  49.                 }
  50.             }
  51.         }
  52.         // Errors, in general
  53.         if (array_key_exists('error'$args))
  54.         {
  55.             $errors[] = $args['error'];
  56.         }
  57.         // Make only one error field
  58.         $errorDisplay null;
  59.         if (count($errors) == 1)
  60.         {
  61.             $errorDisplay $errors[0];
  62.         }
  63.         else
  64.         {
  65.             if (count($errors) > 1)
  66.             {
  67.                 $errorDisplay "";
  68.                 foreach ($errors as $error)
  69.                 {
  70.                     $errorDisplay .= $error;
  71.                     $errorDisplay .= ", ";
  72.                 }
  73.                 $errorDisplay substr($errorDisplay,0,-1);
  74.                 $errorDisplay substr($errorDisplay,0,-1);
  75.             }
  76.         }
  77.         // Get the client IP from the Request Stack
  78.         $ip $request->getClientIp();
  79.         // Get the lastest (according to MAX_LOGIN_FAILURE_ATTEMPTS) attempts
  80.         $ipAttempts $this->em
  81.             ->getRepository(IpAttempt::class)
  82.             ->getLatest($ipself::MAX_LOGIN_FAILURE_ATTEMPTS);
  83.         $ipAttempts array_reverse($ipAttempts);
  84.         // Count them
  85.         $attempts count($ipAttempts);
  86.         // If we have less than the maximum allowed, do nothing
  87.         if ($attempts >= self::MAX_LOGIN_FAILURE_ATTEMPTS)
  88.         {
  89.             // Get oldest entry
  90.             $oldest $ipAttempts[0]->getCreationDate();
  91.             if ($oldest !== null)
  92.             {
  93.                 // Compare it to the present
  94.                 $now = new \DateTime();
  95.                 // Get diff btw old/now in seconds
  96.                 $diff $now->getTimestamp() - $oldest->getTimestamp();
  97.                 
  98.                 // If too recent, ban the ip
  99.                 if ($diff self::ATTEMPTS_INTERVAL_SECONDS)
  100.                 {
  101.                     $ipBan = new IpBan();
  102.                     $ipBan->setIp($ip);
  103.                     $ipBan->setEndDate($now->add(new \DateInterval('PT'.self::BAN_TIME_SECONDS.'S')));
  104.                     $this->em->persist($ipBan);
  105.                 }
  106.             }
  107.         }
  108.         // In all cases log new attempt
  109.         $attempt = new IpAttempt();
  110.         $attempt->setIp($ip);
  111.         $attempt->setUsername($username);
  112.         $attempt->setError($errorDisplay);
  113.         $attempt->setUri($request->getUri());
  114.         $this->em->persist($attempt);
  115.         try
  116.         {
  117.             $this->em->flush();
  118.         }
  119.         catch (\Exception $e)
  120.         {
  121.             // Something went bad
  122.             $this->logTools->errorLog($e->getMessage());
  123.             return false;
  124.         }
  125.         return true;
  126.     }
  127.     public function isBanned($ip)
  128.     {
  129.         $ipBan $this->em
  130.             ->getRepository(IpBan::class)
  131.             ->findOneBy(
  132.                 array('ip'    =>    $ip),
  133.                 array('endDate'    =>    'DESC',)
  134.             );
  135.         if ($ipBan === null)
  136.         {
  137.             return false;
  138.         }
  139.         // Check timestamp
  140.         $now = new \DateTime();
  141.         if ($now->format("YmdHis") <= $ipBan->getEndDate()->format("YmdHis"))
  142.         {
  143.             return true;
  144.         }
  145.         return false;
  146.     }
  147. }