BanListener.php 2.68 KB
Newer Older
Emma's avatar
Emma committed
1 2
<?php

Emma's avatar
Emma committed
3
namespace App\EventListener;
Emma's avatar
Emma committed
4

Emma's avatar
Emma committed
5 6 7
use App\Controller\BanLandingPageController;
use App\Entity\User;
use App\Repository\IpBanRepository;
Emma's avatar
Emma committed
8
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
Emma's avatar
Emma committed
9
use Symfony\Component\HttpFoundation\Request;
Emma's avatar
Emma committed
10 11
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\HttpKernel\KernelEvents;
Emma's avatar
Emma committed
12 13
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
Emma's avatar
Emma committed
14 15 16 17 18 19

/**
 * Show the user a landing page if they are banned.
 */
final class BanListener implements EventSubscriberInterface {
    /**
Emma's avatar
Emma committed
20
     * @var IpBanRepository
Emma's avatar
Emma committed
21 22 23
     */
    private $repository;

Emma's avatar
Emma committed
24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
    /**
     * @var AuthorizationCheckerInterface
     */
    private $authorizationChecker;

    /**
     * @var TokenStorageInterface
     */
    private $tokenStorage;

    public function __construct(
        IpBanRepository $repository,
        AuthorizationCheckerInterface $authorizationChecker,
        TokenStorageInterface $tokenStorage
    ) {
Emma's avatar
Emma committed
39
        $this->repository = $repository;
Emma's avatar
Emma committed
40 41
        $this->authorizationChecker = $authorizationChecker;
        $this->tokenStorage = $tokenStorage;
Emma's avatar
Emma committed
42 43 44 45 46
    }

    public function onKernelRequest(GetResponseEvent $event) {
        $request = $event->getRequest();

Emma's avatar
Emma committed
47 48 49 50 51
        // Don't check for bans on subrequests or requests that are 'safe' (i.e.
        // they're considered read-only). As only POST/PUT/etc. requests should
        // result in the state of the application mutating, banned users should
        // not be able to do any damage with GET/HEAD requests.
        if (!$event->isMasterRequest() || $request->isMethodSafe(false)) {
Emma's avatar
Emma committed
52 53 54
            return;
        }

Emma's avatar
Emma committed
55 56 57 58 59 60 61 62 63 64
        if ($this->authorizationChecker->isGranted('ROLE_USER')) {
            /* @var User $user */
            $user = $this->tokenStorage->getToken()->getUser();

            if ($user->isBanned()) {
                $this->setController($request);

                return;
            }

65
            if ($user->isTrustedOrAdmin()) {
Emma's avatar
Emma committed
66 67 68 69 70
                // don't check for ip bans
                return;
            }
        }

Emma's avatar
Emma committed
71
        if ($this->repository->ipIsBanned($request->getClientIp())) {
Emma's avatar
Emma committed
72
            $this->setController($request);
Emma's avatar
Emma committed
73 74 75
        }
    }

Emma's avatar
Emma committed
76 77 78 79
    private function setController(Request $request) {
        $request->attributes->set('_controller', BanLandingPageController::class);
    }

Emma's avatar
Emma committed
80 81 82 83 84
    /**
     * {@inheritdoc}
     */
    public static function getSubscribedEvents() {
        return [
Emma's avatar
Emma committed
85 86 87
            // the priority must be less than 8, as the token storage won't be
            // populated otherwise!
            KernelEvents::REQUEST => ['onKernelRequest', 4],
Emma's avatar
Emma committed
88 89 90
        ];
    }
}