ResponseSignatureMiddleware::__invoke()   C
last analyzed

Complexity

Conditions 7
Paths 3

Size

Total Lines 41
Code Lines 21

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 41
rs 6.7272
c 0
b 0
f 0
cc 7
eloc 21
nc 3
nop 1
1
<?php declare(strict_types = 1);
2
3
namespace Link0\Bunq\Middleware;
4
5
use Link0\Bunq\Domain\Keypair\PublicKey;
6
use Psr\Http\Message\ResponseInterface;
7
8
final class ResponseSignatureMiddleware
9
{
10
    const SIGNATURE_ALGORITHM = OPENSSL_ALGO_SHA256;
11
12
    /**
13
     * @var PublicKey
14
     */
15
    private $publicKey;
16
17
    /**
18
     * @param PublicKey $serverPublicKey
19
     */
20
    public function __construct(PublicKey $serverPublicKey)
21
    {
22
        $this->publicKey = $serverPublicKey;
23
    }
24
25
    /**
26
     * @param ResponseInterface $response
27
     * @return ResponseInterface
28
     * @throws \Exception
29
     */
30
    public function __invoke(ResponseInterface $response)
31
    {
32
        $header = $response->getHeader('X-Bunq-Server-Signature');
33
34
        if (isset($header[0])) {
35
            $serverSignature = $header[0];
36
37
            $signatureData = $response->getStatusCode();
38
39
            $headers = $response->getHeaders();
40
            ksort($headers);
41
42
            foreach ($headers as $header => $values) {
43
                // Skip the server signature itself
44
                if ($header === 'X-Bunq-Server-Signature') {
45
                    continue;
46
                }
47
48
                // Skip all headers that are not X-Bunq-
49
                if (substr($header, 0, 7) !== 'X-Bunq-') {
50
                    continue;
51
                }
52
53
                // Add all header data to verify signature
54
                foreach ($values as $value) {
55
                    $signatureData .= PHP_EOL . $header . ': ' . $value;
56
                }
57
            }
58
59
            $signatureData .= "\n\n";
60
            $signatureData .= (string) $response->getBody();
61
62
            $rawSignature = base64_decode($serverSignature);
63
            $verify = openssl_verify($signatureData, $rawSignature, $this->publicKey, self::SIGNATURE_ALGORITHM);
64
            if ($verify !== 1) {
65
                throw new \Exception("Server signature does not match response");
66
            }
67
        }
68
69
        return $response;
70
    }
71
}
72