Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
21 / 21
100.00% covered (success)
100.00%
4 / 4
CRAP
100.00% covered (success)
100.00%
1 / 1
VerifyCsrfToken
100.00% covered (success)
100.00%
21 / 21
100.00% covered (success)
100.00%
4 / 4
12
100.00% covered (success)
100.00%
1 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 process
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
3
 isReading
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
1
 tokensMatch
100.00% covered (success)
100.00%
12 / 12
100.00% covered (success)
100.00%
1 / 1
7
1<?php
2
3declare(strict_types=1);
4
5namespace Engelsystem\Middleware;
6
7use Engelsystem\Http\Exceptions\HttpAuthExpired;
8use Psr\Http\Message\ResponseInterface;
9use Psr\Http\Message\ServerRequestInterface;
10use Psr\Http\Server\MiddlewareInterface;
11use Psr\Http\Server\RequestHandlerInterface;
12use Symfony\Component\HttpFoundation\Session\SessionInterface;
13
14class VerifyCsrfToken implements MiddlewareInterface
15{
16    public function __construct(protected SessionInterface $session)
17    {
18    }
19
20    /**
21     * Verify csrf tokens
22     */
23    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
24    {
25        if (
26            $this->isReading($request)
27            || $this->tokensMatch($request)
28        ) {
29            return $handler->handle($request);
30        }
31
32        throw new HttpAuthExpired('Authentication Token Mismatch');
33    }
34
35    protected function isReading(ServerRequestInterface $request): bool
36    {
37        return in_array(
38            $request->getMethod(),
39            ['GET', 'HEAD', 'OPTIONS']
40        );
41    }
42
43    protected function tokensMatch(ServerRequestInterface $request): bool
44    {
45        $token = null;
46        $body = $request->getParsedBody();
47        $header = $request->getHeader('X-CSRF-TOKEN');
48
49        if (is_array($body) && isset($body['_token'])) {
50            $token = $body['_token'];
51        }
52
53        if (!empty($header)) {
54            $header = array_shift($header);
55        }
56
57        $token = $token ?: $header;
58        $sessionToken = $this->session->get('_token');
59
60        return is_string($token)
61            && is_string($sessionToken)
62            && hash_equals($sessionToken, $token);
63    }
64}