WebhookNotificationGateway.php
2.46 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
<?php
namespace Braintree;
class WebhookNotificationGateway
{
    public function __construct($gateway)
    {
        $this->config = $gateway->config;
        $this->config->assertHasAccessTokenOrKeys();
    }
    public function parse($signature, $payload)
    {
        if (is_null($signature)) {
            throw new Exception\InvalidSignature("signature cannot be null");
        }
        if (is_null($payload)) {
            throw new Exception\InvalidSignature("payload cannot be null");
        }
        if (preg_match("/[^A-Za-z0-9+=\/\n]/", $payload) === 1) {
            throw new Exception\InvalidSignature("payload contains illegal characters");
        }
        self::_validateSignature($signature, $payload);
        $xml = base64_decode($payload);
        $attributes = Xml::buildArrayFromXml($xml);
        return WebhookNotification::factory($attributes['notification']);
    }
    public function verify($challenge)
    {
        if (!preg_match('/^[a-f0-9]{20,32}$/', $challenge)) {
            throw new Exception\InvalidChallenge("challenge contains non-hex characters");
        }
        $publicKey = $this->config->getPublicKey();
        $digest = Digest::hexDigestSha1($this->config->getPrivateKey(), $challenge);
        return "{$publicKey}|{$digest}";
    }
    private function _payloadMatches($signature, $payload)
    {
        $payloadSignature = Digest::hexDigestSha1($this->config->getPrivateKey(), $payload);
        return Digest::secureCompare($signature, $payloadSignature);
    }
    private function _validateSignature($signatureString, $payload)
    {
        $signaturePairs = preg_split("/&/", $signatureString);
        $signature = self::_matchingSignature($signaturePairs);
        if (!$signature) {
            throw new Exception\InvalidSignature("no matching public key");
        }
        if (!(self::_payloadMatches($signature, $payload) || self::_payloadMatches($signature, $payload . "\n"))) {
            throw new Exception\InvalidSignature("signature does not match payload - one has been modified");
        }
    }
    private function _matchingSignature($signaturePairs)
    {
        foreach ($signaturePairs as $pair)
        {
            $components = preg_split("/\|/", $pair);
            if ($components[0] == $this->config->getPublicKey()) {
                return $components[1];
            }
        }
        return null;
    }
}
class_alias('Braintree\WebhookNotificationGateway', 'Braintree_WebhookNotificationGateway');