Completed
Push — master ( 0eb5fa...37ba08 )
by Marcel
03:22
created

Signer   A

Complexity

Total Complexity 5

Size/Duplication

Total Lines 82
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 5

Test Coverage

Coverage 100%

Importance

Changes 4
Bugs 0 Features 0
Metric Value
wmc 5
c 4
b 0
f 0
lcom 1
cbo 5
dl 0
loc 82
ccs 25
cts 25
cp 1
rs 10

3 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 7 1
A sign() 0 15 1
A withSignedHeadersHeader() 0 18 3
1
<?php
2
3
namespace UMA\Psr\Http\Message\HMAC;
4
5
use Psr\Http\Message\MessageInterface;
6
use Psr\Http\Message\RequestInterface;
7
use UMA\Psr\Http\Message\Internal\HashCalculator;
8
use UMA\Psr\Http\Message\Internal\NonceProvider;
9
use UMA\Psr\Http\Message\Internal\TimeProvider;
10
use UMA\Psr\Http\Message\Serializer\MessageSerializer;
11
12
class Signer
13
{
14
    /**
15
     * @var string
16
     */
17
    private $secret;
18
19
    /**
20
     * @var HashCalculator
21
     */
22
    private $calculator;
23
24
    /**
25
     * @var NonceProvider
26
     */
27
    private $nonceProvider;
28
29
    /**
30
     * @var TimeProvider
31
     */
32
    private $timeProvider;
33
34
    /**
35
     * @param string $secret
36
     */
37 91
    public function __construct($secret)
38
    {
39 91
        $this->secret = $secret;
40 91
        $this->calculator = new HashCalculator();
41 91
        $this->nonceProvider = new NonceProvider();
42 91
        $this->timeProvider = new TimeProvider();
43 91
    }
44
45
    /**
46
     * @param MessageInterface $message
47
     *
48
     * @return MessageInterface The signed message.
49
     *
50
     * @throws \InvalidArgumentException When $message is an implementation of
51
     *                                   MessageInterface that cannot be
52
     *                                   serialized and thus neither signed.
53
     */
54 91
    public function sign(MessageInterface $message)
55
    {
56 91
        $serialization = MessageSerializer::serialize(
57 91
            $preSignedMessage = $this->withSignedHeadersHeader(
58
                $message
59 91
                    ->withHeader(Specification::DATE_HEADER, $this->timeProvider->currentTime())
60 91
                    ->withHeader(Specification::NONCE_HEADER, $this->nonceProvider->randomNonce())
61 91
            )
62 91
        );
63
64 91
        return $preSignedMessage->withHeader(
65 91
            Specification::AUTH_HEADER,
66 91
            Specification::AUTH_PREFIX.$this->calculator->hmac($serialization, $this->secret)
67 91
        );
68
    }
69
70
    /**
71
     * @param MessageInterface $message
72
     *
73
     * @return MessageInterface
74
     */
75 91
    private function withSignedHeadersHeader(MessageInterface $message)
76
    {
77 91
        $headers = array_keys(array_change_key_case($message->getHeaders(), CASE_LOWER));
78 91
        array_push($headers, mb_strtolower(Specification::SIGN_HEADER));
79
80
        // Some of the tested RequestInterface implementations do not include
81
        // the Host header in $message->getHeaders(), so it is explicitly set when needed
82 91
        if ($message instanceof RequestInterface && !in_array('host', $headers)) {
83 18
            array_push($headers, 'host');
84 18
        }
85
86
        // There is no guarantee about the order of the headers returned by
87
        // $message->getHeaders(), so they are explicitly sorted in order
88
        // to produce the exact same string regardless of the underlying implementation
89 91
        sort($headers);
90
91 91
        return $message->withHeader(Specification::SIGN_HEADER, implode(',', $headers));
92
    }
93
}
94