Completed
Push — 23 ( 09d773...16ee8e )
by Harald
11s
created

WebhookNotification::_initialize()   F

Complexity

Conditions 10
Paths 512

Size

Total Lines 43
Code Lines 23

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 10
eloc 23
nc 512
nop 1
dl 0
loc 43
rs 3.2187
c 0
b 0
f 0

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
namespace Braintree;
3
4
class WebhookNotification extends Base
5
{
6
    const SUBSCRIPTION_CANCELED = 'subscription_canceled';
7
    const SUBSCRIPTION_CHARGED_SUCCESSFULLY = 'subscription_charged_successfully';
8
    const SUBSCRIPTION_CHARGED_UNSUCCESSFULLY = 'subscription_charged_unsuccessfully';
9
    const SUBSCRIPTION_EXPIRED = 'subscription_expired';
10
    const SUBSCRIPTION_TRIAL_ENDED = 'subscription_trial_ended';
11
    const SUBSCRIPTION_WENT_ACTIVE = 'subscription_went_active';
12
    const SUBSCRIPTION_WENT_PAST_DUE = 'subscription_went_past_due';
13
    const SUB_MERCHANT_ACCOUNT_APPROVED = 'sub_merchant_account_approved';
14
    const SUB_MERCHANT_ACCOUNT_DECLINED = 'sub_merchant_account_declined';
15
    const TRANSACTION_DISBURSED = 'transaction_disbursed';
16
    const TRANSACTION_SETTLED = 'transaction_settled';
17
    const TRANSACTION_SETTLEMENT_DECLINED = 'transaction_settlement_declined';
18
    const DISBURSEMENT_EXCEPTION = 'disbursement_exception';
19
    const DISBURSEMENT = 'disbursement';
20
    const DISPUTE_OPENED = 'dispute_opened';
21
    const DISPUTE_LOST = 'dispute_lost';
22
    const DISPUTE_WON = 'dispute_won';
23
    const PARTNER_MERCHANT_CONNECTED = 'partner_merchant_connected';
24
    const PARTNER_MERCHANT_DISCONNECTED = 'partner_merchant_disconnected';
25
    const PARTNER_MERCHANT_DECLINED = 'partner_merchant_declined';
26
    const CHECK = 'check';
27
    const ACCOUNT_UPDATER_DAILY_REPORT = 'account_updater_daily_report';
28
29
    public static function parse($signature, $payload)
30
    {
31
        if (preg_match("/[^A-Za-z0-9+=\/\n]/", $payload) === 1) {
32
            throw new Exception\InvalidSignature("payload contains illegal characters");
33
        }
34
35
        Configuration::assertGlobalHasAccessTokenOrKeys();
36
        self::_validateSignature($signature, $payload);
37
38
        $xml = base64_decode($payload);
39
        $attributes = Xml::buildArrayFromXml($xml);
40
        return self::factory($attributes['notification']);
41
    }
42
43
    public static function verify($challenge)
44
    {
45
        if (!preg_match('/^[a-f0-9]{20,32}$/', $challenge)) {
46
            throw new Exception\InvalidChallenge("challenge contains non-hex characters");
47
        }
48
        Configuration::assertGlobalHasAccessTokenOrKeys();
49
        $publicKey = Configuration::publicKey();
50
        $digest = Digest::hexDigestSha1(Configuration::privateKey(), $challenge);
51
        return "{$publicKey}|{$digest}";
52
    }
53
54
    public static function factory($attributes)
55
    {
56
        $instance = new self();
57
        $instance->_initialize($attributes);
58
        return $instance;
59
    }
60
61
    private static function _matchingSignature($signaturePairs)
62
    {
63
        foreach ($signaturePairs as $pair)
64
        {
65
            $components = preg_split("/\|/", $pair);
66
            if ($components[0] == Configuration::publicKey()) {
67
                return $components[1];
68
            }
69
        }
70
71
        return null;
72
    }
73
74
    private static function _payloadMatches($signature, $payload)
75
    {
76
        $payloadSignature = Digest::hexDigestSha1(Configuration::privateKey(), $payload);
77
        return Digest::secureCompare($signature, $payloadSignature);
78
    }
79
80
    private static function _validateSignature($signatureString, $payload)
81
    {
82
        $signaturePairs = preg_split("/&/", $signatureString);
83
        $signature = self::_matchingSignature($signaturePairs);
84
        if (!$signature) {
85
            throw new Exception\InvalidSignature("no matching public key");
86
        }
87
88
        if (!(self::_payloadMatches($signature, $payload) || self::_payloadMatches($signature, $payload . "\n"))) {
89
            throw new Exception\InvalidSignature("signature does not match payload - one has been modified");
90
        }
91
    }
92
93
    protected function _initialize($attributes)
94
    {
95
        $this->_attributes = $attributes;
96
97
        if (isset($attributes['subject']['apiErrorResponse'])) {
98
            $wrapperNode = $attributes['subject']['apiErrorResponse'];
99
        } else {
100
            $wrapperNode = $attributes['subject'];
101
        }
102
103
        if (isset($wrapperNode['subscription'])) {
104
            $this->_set('subscription', Subscription::factory($attributes['subject']['subscription']));
105
        }
106
107
        if (isset($wrapperNode['merchantAccount'])) {
108
            $this->_set('merchantAccount', MerchantAccount::factory($wrapperNode['merchantAccount']));
109
        }
110
111
        if (isset($wrapperNode['transaction'])) {
112
            $this->_set('transaction', Transaction::factory($wrapperNode['transaction']));
113
        }
114
115
        if (isset($wrapperNode['disbursement'])) {
116
            $this->_set('disbursement', Disbursement::factory($wrapperNode['disbursement']));
117
        }
118
119
        if (isset($wrapperNode['partnerMerchant'])) {
120
            $this->_set('partnerMerchant', PartnerMerchant::factory($wrapperNode['partnerMerchant']));
121
        }
122
123
        if (isset($wrapperNode['dispute'])) {
124
            $this->_set('dispute', Dispute::factory($wrapperNode['dispute']));
125
        }
126
127
        if (isset($wrapperNode['accountUpdaterDailyReport'])) {
128
            $this->_set('accountUpdaterDailyReport', AccountUpdaterDailyReport::factory($wrapperNode['accountUpdaterDailyReport']));
129
        }
130
131
        if (isset($wrapperNode['errors'])) {
132
            $this->_set('errors', new Error\ValidationErrorCollection($wrapperNode['errors']));
133
            $this->_set('message', $wrapperNode['message']);
134
        }
135
    }
136
}
137
class_alias('Braintree\WebhookNotification', 'Braintree_WebhookNotification');
138