Completed
Push — master ( b57c0c...6948b2 )
by Marcel
02:57
created

Verifier   A

Complexity

Total Complexity 11

Size/Duplication

Total Lines 96
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 4

Test Coverage

Coverage 100%

Importance

Changes 6
Bugs 0 Features 0
Metric Value
wmc 11
c 6
b 0
f 0
lcom 1
cbo 4
dl 0
loc 96
ccs 30
cts 30
cp 1
rs 10

5 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 7 1
A setMaximumDelay() 0 6 1
A verify() 0 17 4
A withoutUnsignedHeaders() 0 12 3
A delayed() 0 7 2
1
<?php
2
3
namespace UMA\Psr\Http\Message\HMAC;
4
5
use Psr\Http\Message\MessageInterface;
6
use UMA\Psr\Http\Message\Internal\HashCalculator;
7
use UMA\Psr\Http\Message\Internal\HeaderValidator;
8
use UMA\Psr\Http\Message\Serializer\MessageSerializer;
9
10
class Verifier
11
{
12
    /**
13
     * @var HashCalculator
14
     */
15
    private $calculator;
16
17
    /**
18
     * @var null|int
19
     */
20
    private $maxDelay = null;
21
22
    /**
23
     * @var HeaderValidator
24
     */
25
    private $validator;
26
27 92
    public function __construct()
28
    {
29 92
        $this->calculator = new HashCalculator();
30 92
        $this->validator = (new HeaderValidator())
31 92
            ->addRule(Specification::AUTH_HEADER, Specification::AUTH_REGEXP)
32 92
            ->addRule(Specification::SIGN_HEADER, Specification::SIGN_REGEXP);
33 92
    }
34
35
    /**
36
     * @param int $maxDelay
37
     *
38
     * @return Verifier
39
     */
40 1
    public function setMaximumDelay($maxDelay)
41
    {
42 1
        $this->maxDelay = $maxDelay;
43
44 1
        return $this;
45
    }
46
47
    /**
48
     * @param MessageInterface $message
49
     * @param string           $secret
50
     *
51
     * @return bool Signature verification outcome.
52
     *
53
     * @throws \InvalidArgumentException When $message is an implementation of
54
     *                                   MessageInterface that cannot be
55
     *                                   serialized and thus neither verified.
56
     */
57 92
    public function verify(MessageInterface $message, $secret)
58
    {
59 92
        if (false === $matches = $this->validator->conforms($message)) {
60 91
            return false;
61
        }
62
63 71
        $clientSideSignature = $matches[Specification::AUTH_HEADER][1];
64
65 71
        $serverSideSignature = $this->calculator
66 71
            ->hmac(MessageSerializer::serialize($this->withoutUnsignedHeaders($message)), $secret);
67
68 71
        if (!hash_equals($serverSideSignature, $clientSideSignature) || $this->delayed($message)) {
69 71
            return false;
70
        }
71
72 71
        return true;
73
    }
74
75
    /**
76
     * @param MessageInterface $message
77
     *
78
     * @return MessageInterface
79
     */
80 71
    private function withoutUnsignedHeaders(MessageInterface $message)
81
    {
82 71
        $signedHeaders = array_filter(explode(',', $message->getHeaderLine(Specification::SIGN_HEADER)));
83
84 71
        foreach ($message->getHeaders() as $name => $value) {
85 71
            if (!in_array(mb_strtolower($name), $signedHeaders)) {
86 71
                $message = $message->withoutHeader($name);
87 71
            }
88 71
        }
89
90 71
        return $message;
91
    }
92
93
    /**
94
     * @param MessageInterface $message
95
     *
96
     * @return bool
97
     */
98 71
    private function delayed(MessageInterface $message)
99
    {
100 71
        $currentTimestamp = (new \DateTime('now', new \DateTimeZone('GMT')))->getTimestamp();
101 71
        $messageTimestamp = (new \DateTime($message->getHeaderLine(Specification::DATE_HEADER)))->getTimestamp();
102
103 71
        return is_int($this->maxDelay) && $currentTimestamp - $messageTimestamp > $this->maxDelay;
104
    }
105
}
106