Completed
Push — master ( 16d1e5...1a3f09 )
by Marcel
02:42
created

Verifier::setMonitor()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 2
Bugs 0 Features 0
Metric Value
c 2
b 0
f 0
dl 0
loc 6
ccs 3
cts 3
cp 1
rs 9.4285
cc 1
eloc 3
nc 1
nop 1
crap 1
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\Monitor\BlindMonitor;
9
use UMA\Psr\Http\Message\Monitor\MonitorInterface;
10
use UMA\Psr\Http\Message\Serializer\MessageSerializer;
11
12
class Verifier
13
{
14
    /**
15
     * @var HashCalculator
16
     */
17
    private $calculator;
18
19
    /**
20
     * @var MonitorInterface
21
     */
22
    private $monitor;
23
24
    /**
25
     * @var HeaderValidator
26
     */
27
    private $validator;
28
29 98
    public function __construct(MonitorInterface $monitor = null)
30
    {
31 98
        $this->calculator = new HashCalculator();
32 98
        $this->monitor = null === $monitor ?
33 98
            new BlindMonitor() : $monitor;
34 98
        $this->validator = (new HeaderValidator())
35 98
            ->addRule(Specification::AUTH_HEADER, Specification::AUTH_REGEXP)
36 98
            ->addRule(Specification::NONCE_HEADER, Specification::NONCE_REGEXP)
37 98
            ->addRule(Specification::SIGN_HEADER, Specification::SIGN_REGEXP);
38 98
    }
39
40
    /**
41
     * @param MessageInterface $message
42
     * @param string           $secret
43
     *
44
     * @return bool Signature verification outcome.
45
     *
46
     * @throws \InvalidArgumentException When $message is an implementation of
47
     *                                   MessageInterface that cannot be
48
     *                                   serialized and thus neither verified.
49
     */
50 98
    public function verify(MessageInterface $message, $secret)
51
    {
52 98
        if (false === $matches = $this->validator->conforms($message)) {
53 91
            return false;
54
        }
55
56 77
        $clientSideSignature = $matches[Specification::AUTH_HEADER][1];
57
58 77
        $serverSideSignature = $this->calculator
59 77
            ->hmac(MessageSerializer::serialize($this->withoutUnsignedHeaders($message)), $secret);
60
61 77
        return hash_equals($serverSideSignature, $clientSideSignature) && !$this->monitor->seen($message);
62
    }
63
64
    /**
65
     * @param MessageInterface $message
66
     *
67
     * @return MessageInterface
68
     */
69 77
    private function withoutUnsignedHeaders(MessageInterface $message)
70
    {
71 77
        $signedHeaders = array_filter(explode(',', $message->getHeaderLine(Specification::SIGN_HEADER)));
72
73 77
        foreach (array_keys($message->getHeaders()) as $headerName) {
74 77
            if (!in_array(mb_strtolower($headerName), $signedHeaders)) {
75 77
                $message = $message->withoutHeader($headerName);
76 77
            }
77 77
        }
78
79 77
        return $message;
80
    }
81
}
82