Cbs::computeMac()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 7
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 4
1
<?php
2
/*
3
 * This file is part of the Laravel Cbs package.
4
 *
5
 * (c) Edward Paul <[email protected]>
6
 *
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 */
10
11
namespace Infinitypaul\Cbs;
12
13
use GuzzleHttp\Client;
14
use Illuminate\Support\Facades\Config;
15
use Infinitypaul\Cbs\Exceptions\InvalidPostException;
16
use Infinitypaul\Cbs\Exceptions\NotSetException;
17
18
class Cbs
19
{
20
    /**
21
     * Issue Secret Key from CBS.
22
     * @var string
23
     */
24
    protected $secretKey;
25
26
    /**
27
     * Issue Client ID from CBS.
28
     * @var string
29
     */
30
    protected $clientId;
31
32
    /**
33
     * Issue URL from CBS.
34
     * @var string
35
     */
36
    protected $baseUrl;
37
38
    /**
39
     * Issue Revenue Head from CBS.
40
     * @var int
41
     */
42
    protected $revenueHeads;
43
44
    /**
45
     * Issue Category ID from CBS Admin.
46
     * @var int
47
     */
48
    protected $categoryId;
49
50
    /**
51
     *  Response from requests made to CBS.
52
     * @var mixed
53
     */
54
    protected $response;
55
56
    /**
57
     *  Hashed Key.
58
     * @var mixed
59
     */
60
    protected $signature;
61
62
    /**
63
     * Payment Url - CBS payment page.
64
     * @var string
65
     */
66
    protected $url;
67
68
    /**
69
     *  Response from CBS.
70
     * @var mixed
71
     */
72
    protected $invoice = [];
73
74
    /**
75
     * Instance of Client.
76
     * @var Client
77
     */
78
    protected $client;
79
80
    public function __construct()
81
    {
82
        $this->setUrl();
83
        $this->setConstant();
84
        $this->checkConstant();
85
    }
86
87
    public function setUrl()
88
    {
89
        $this->baseUrl = Config::get('mode') === 'test' ? Config::get('cbs.testUrl') : Config::get('cbs.liveURL');
90
    }
91
92
    /**
93
     * Get secret key from CBS config file.
94
     */
95
    public function setConstant()
96
    {
97
        $this->secretKey = Config::get('cbs.secret');
98
        $this->clientId = Config::get('cbs.clientId');
99
        $this->revenueHeads = Config::get('cbs.revenueHead');
100
        $this->categoryId = Config::get('cbs.categoryId');
101
    }
102
103
    protected function checkConstant()
104
    {
105
        if (! $this->revenueHeads) {
106
            throw new NotSetException('Set Your Revenue Head');
107
        }
108
        if (! $this->clientId) {
109
            throw new NotSetException('Set Your Client Id');
110
        }
111
        if (! $this->secretKey) {
112
            throw new NotSetException('Set Your Secret Id');
113
        }
114
        if (! $this->categoryId) {
115
            throw new NotSetException('Set Your Category Id');
116
        }
117
        if (! $this->baseUrl) {
118
            throw new NotSetException('Set Your Test and Live Base Url');
119
        }
120
    }
121
122
    protected function setSignature($amount, $callback)
123
    {
124
        $amount = number_format((float) $amount, 2, '.', '');
125
        $string = $this->revenueHeads.$amount.$callback.$this->clientId;
126
        //dd($string);
127
        $this->signature = base64_encode(hash_hmac('sha256', $string, $this->secretKey, true));
128
        $this->setRequestOptions();
129
    }
130
131
    /**
132
     * Set options for making the Client request.
133
     */
134
    private function setRequestOptions()
135
    {
136
        $this->client = new Client([
137
            'base_uri' => $this->baseUrl,
138
            'headers' => [
139
                'Content-Type' => 'application/json',
140
                'Accept' => 'application/json',
141
                'CLIENTID' => $this->clientId,
142
                'Signature' => $this->signature,
143
            ],
144
        ]);
145
    }
146
147
    /**
148
     * @param $relativeUri
149
     * @param string $method
150
     * @param array $body
151
     *
152
     * @return \Infinitypaul\Cbs\Cbs
153
     * @throws \Infinitypaul\Cbs\Exceptions\NotSetException
154
     */
155
    private function setHttpResponse($relativeUri, $method, $body = [])
156
    {
157
        if (is_null($method)) {
158
            throw new NotSetException('Empty Method Not Allowed');
159
        }
160
        $this->response = $this->client->{strtolower($method)}(
161
            $this->baseUrl.$relativeUri,
162
            ['body' => json_encode($body)]
163
        );
164
165
        return $this;
166
    }
167
168
    private function getResponse()
169
    {
170
        return json_decode($this->response->getBody(), true);
171
    }
172
173
    protected function setUser($data)
174
    {
175
        if (isset($data['payerID'])) {
176
            $user = ['PayerId' => $data['payerID']];
177
        } else {
178
            $user = [
179
                'Recipient' => $data['full_name'],
180
                'Email' => $data['email'],
181
                'Address' => $data['address'],
182
                'PhoneNumber' => $data['mobile_number'],
183
                'TaxPayerIdentificationNumber' => isset($data['tin']) ? $data['tin'] : '',
184
            ];
185
        }
186
187
        return [
188
            'TaxEntity' => $user,
189
            'Amount' => intval($data['amount']),
190
            'InvoiceDescription' => $data['description'],
191
            'CategoryId' => $this->categoryId,
192
        ];
193
    }
194
195
    /**
196
     * Initiate a payment request to Cbs
197
     * Included the option to pass the payload to this method for situations
198
     * when the payload is built on the fly (not passed to the controller from a view).
199
     *
200
     * @param array $data
201
     *
202
     * @return \Infinitypaul\Cbs\Cbs
203
     * @throws \Infinitypaul\Cbs\Exceptions\NotSetException
204
     */
205
    public function generateInvoice($data)
206
    {
207
        if (empty($data)) {
208
            $TaxEntityInvoice = $this->setUser(request()->toArray());
209
            $callback = request()->callback;
210
            $quantity = request()->quantity;
211
            $ExternalRefNumber = request()->has('externalRefNumber') ? request()->externalRefNumber : null;
212
        } else {
213
            $TaxEntityInvoice = $this->setUser($data);
214
            $callback = $data['callback'];
215
            $quantity = $data['quantity'];
216
            $ExternalRefNumber = isset($data['externalRefNumber']) ? $data['externalRefNumber'] : null;
217
        }
218
219
        $data = [
220
            'RevenueHeadId' => $this->revenueHeads,
221
            'TaxEntityInvoice' => $TaxEntityInvoice,
222
            'CallBackURL' => $callback,
223
            'RequestReference' => ReferenceNumber::getHashedToken(),
224
            'Quantity' => $quantity,
225
            'ExternalRefNumber' => $ExternalRefNumber,
226
227
        ];
228
229
        $this->setSignature($TaxEntityInvoice['Amount'], $callback);
230
        array_filter($data);
231
232
        $this->setHttpResponse('/api/v1/invoice/create', 'POST', $data);
233
234
        return $this;
235
    }
236
237
    /**
238
     * Set the invoice data from the callback response.
239
     *
240
     * @param array $data
241
     *
242
     * @return \Infinitypaul\Cbs\Cbs
243
     * @throws \Infinitypaul\Cbs\Exceptions\NotSetException
244
     */
245
    public function setInvoice($data = [])
246
    {
247
        $this->generateInvoice($data);
248
        $this->invoice = $this->getResponse();
249
250
        return $this;
251
    }
252
253
    /**
254
     * Get the invoice data from the callback response.
255
     */
256
    public function getData()
257
    {
258
        return $this->invoice;
259
    }
260
261
    /**
262
     * Get the invoice payment url from the callback response.
263
     */
264
    public function redirectNow()
265
    {
266
        return redirect($this->invoice['ResponseObject']['PaymentURL']);
267
    }
268
269
    /**
270
     * Compute Mac Address.
271
     *
272
     * @param $invoiceNumber
273
     * @param $paymentRef
274
     * @param $amount
275
     *
276
     *
277
     * @param $RequestReference
278
     *
279
     * @return string
280
     */
281
    protected function computeMac($invoiceNumber, $paymentRef, $amount, $RequestReference)
282
    {
283
        $amount = number_format((float) $amount, 2, '.', '');
284
        $string = $invoiceNumber.$paymentRef.$amount.$RequestReference;
285
286
        return base64_encode(hash_hmac('sha256', $string, $this->secretKey, true));
287
    }
288
289
    /**
290
     * Get Payment details if the transaction was verified successfully.
291
     *
292
     * @throws \Infinitypaul\Cbs\Exceptions\InvalidPostException
293
     */
294
    public function getPaymentData()
295
    {
296
        $mac = $this->computeMac(request()->InvoiceNumber, request()->PaymentRef, request()->AmountPaid, request()->RequestReference);
297
        if ($mac != request()->Mac) {
298
            throw new InvalidPostException('Invalid Call');
299
        } else {
300
            return response()->json(request()->toArray());
0 ignored issues
show
Bug introduced by
The method json does only exist in Illuminate\Contracts\Routing\ResponseFactory, but not in Illuminate\Http\Response.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
301
        }
302
    }
303
}
304