src/EntityManager/UserIpBannedManager.php line 65

Open in your IDE?
  1. <?php
  2. namespace App\EntityManager;
  3. use App\Cache\VisitorCache;
  4. use App\Entity\Repository\UserIpBannedRepository;
  5. use App\Entity\User;
  6. use App\Entity\UserIpBanned;
  7. use Doctrine\ORM\EntityManagerInterface;
  8. use Knp\Component\Pager\PaginatorInterface;
  9. use Psr\SimpleCache\CacheInterface;
  10. use Symfony\Component\HttpFoundation\Request;
  11. use Symfony\Component\HttpFoundation\RequestStack;
  12. use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
  13. use Symfony\Component\Security\Core\Security;
  14. class UserIpBannedManager extends AbstractEntityManager
  15. {
  16.     private $redis;
  17.     private $abkBans;
  18.     private $abkVisitsLimits;
  19.     public function __construct(
  20.         EntityManagerInterface $entityManager,
  21.         TokenStorageInterface $tokenStorage,
  22.         CacheInterface $cache,
  23.         RequestStack $requestStack,
  24.         PaginatorInterface $paginator,
  25.         Security $security,
  26.         \Predis\Client $redis,
  27.         array $abkBans,
  28.         array $abkVisitsLimits
  29.     ) {
  30.         parent::__construct($entityManager$tokenStorage$cache$requestStack$paginator$security);
  31.         $this->redis $redis;
  32.         $this->abkBans $abkBans;
  33.         $this->abkVisitsLimits $abkVisitsLimits;
  34.     }
  35.     private function getRepository(): UserIpBannedRepository
  36.     {
  37.         return $this->entityManager->getRepository(UserIpBanned::class);
  38.     }
  39.     private function createIpBan(string $ipstring $reason)
  40.     {
  41.         $ban = new UserIpBanned();
  42.         $ban->setComment('AUTOBAN : ' $reason)
  43.             ->setIp($ip)
  44.             ->setDomain(gethostbyaddr($ip));
  45.         $this->entityManager->persist($ban);
  46.         $this->entityManager->flush();
  47.         return $ban;
  48.     }
  49.     public function checkBan(Request $request)
  50.     {
  51.         $ipBan $this->getRepository()->getIpBanned($request->getClientIp());
  52.         if ($ipBan == null) {
  53.             $ipBan $this->checkRequest($request);
  54.         }
  55.         if ($ipBan instanceof UserIpBanned) {
  56.             $this->addBlockedHit($ipBan);
  57.         } else {
  58.             $this->checkDailyHits($request);
  59.         }
  60.         return $ipBan instanceof UserIpBanned;
  61.     }
  62.     private function checkRequest(Request $request): ?UserIpBanned
  63.     {
  64.         $getBanReason = function($request) {
  65.             foreach ($this->abkBans['request_parameters'] as $key => $value) {
  66.                 if ($request->get($key) == $value) {
  67.                     return 'tor';
  68.                 }
  69.             }
  70.             $userAgent $request->headers->get('User-Agent');
  71.             foreach ($this->abkBans['user_agents'] as $bannedUserAgent) {
  72.                 if (strpos($userAgent$bannedUserAgent) !== false) {
  73.                     return sprintf('userbrowser=%s'$userAgent);
  74.                 }
  75.             }
  76.             $url $request->getRequestUri();
  77.             foreach ($this->abkBans['urls'] as $bannedUrl) {
  78.                 if (strpos($url$bannedUrl) !== false) {
  79.                     return sprintf('url=%s'$bannedUrl);
  80.                 }
  81.             }
  82.             return null;
  83.         };
  84.         if ($message $getBanReason($request)) {
  85.             return $this->createIpBan($request->getClientIp(), $message);
  86.         }
  87.         
  88.         return null;
  89.     }
  90.     private function checkDailyHits(Request $request)
  91.     {
  92.         $user $this->getUser();
  93.         $allowedRoles null;
  94.         if ($user instanceof User) {
  95.             $allowedRoles array_intersect(User::ADMIN_ASSIGNABLE_ROLES$user->getRoles());
  96.             $hitsKey VisitorCache::keyDailyHitsUser($user->getId());
  97.             $limit $this->abkVisitsLimits['user'];
  98.         } else {
  99.             $hitsKey VisitorCache::keyDailyHitsIp($request->getClientIp());
  100.             $limit $this->abkVisitsLimits['anonymous'];
  101.         }
  102.         $results $this->redis
  103.             ->transaction()
  104.             ->incr($hitsKey)
  105.             ->expire($hitsKey60 60 24)
  106.             ->execute();
  107.         if (!empty($allowedRoles)) {
  108.             return false;
  109.         }
  110.         $blocked $results[0] >= $limit;
  111.         if ($blocked && $user instanceof User) {
  112.             $message sprintf('%s hits limit reached, account temporary blocked.'$limit);
  113.             $adminComment $user->getAdminComment();
  114.             if (!empty($adminComment)) {
  115.                 $user->setAdminComment($adminComment "\r\n" $message);
  116.             } else {
  117.                 $user->setAdminComment($message);
  118.             }
  119.             $user->setDateBlockedUntil(new \DateTime('+8 days'));
  120.             $this->entityManager->persist($user);
  121.             $this->entityManager->flush();
  122.         }
  123.         else if ($blocked && $user == null) {
  124.             $message sprintf('%s hits limit reached, anonymous user.'$limit);
  125.             $this->createIpBan($request->getClientIp(), $message);
  126.         }
  127.         return $blocked;
  128.     }
  129.     public function addBlockedHit(UserIpBanned $ipBan)
  130.     {
  131.         $qb $this->getRepository()->createQueryBuilder('ip');
  132.         $qb->update()
  133.             ->set('ip.hitsblocked'$qb->expr()->sum('ip.hitsblocked'1))
  134.             ->where('ip = :ipban')
  135.             ->setParameter('ipban'$ipBan);
  136.         $qb->getQuery()->execute();
  137.     }
  138. }