Passed
Pull Request — master (#182)
by Hashem
02:45
created

Irankish::generateAuthenticationEnvelope()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 16
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 12
c 1
b 0
f 0
nc 1
nop 4
dl 0
loc 16
rs 9.8666
1
<?php
2
3
namespace Shetabit\Multipay\Drivers\Irankish;
4
5
use Shetabit\Multipay\Abstracts\Driver;
6
use Shetabit\Multipay\Exceptions\InvalidPaymentException;
7
use Shetabit\Multipay\Exceptions\PurchaseFailedException;
8
use Shetabit\Multipay\Contracts\ReceiptInterface;
9
use Shetabit\Multipay\Invoice;
10
use Shetabit\Multipay\Receipt;
11
use Shetabit\Multipay\RedirectionForm;
12
use Shetabit\Multipay\Request;
13
14
class Irankish extends Driver
15
{
16
    /**
17
     * Invoice
18
     *
19
     * @var Invoice
20
     */
21
    protected $invoice;
22
23
    /**
24
     * Driver settings
25
     *
26
     * @var object
27
     */
28
    protected $settings;
29
30
    /**
31
     * Irankish constructor.
32
     * Construct the class with the relevant settings.
33
     *
34
     * @param Invoice $invoice
35
     * @param $settings
36
     */
37
    public function __construct(Invoice $invoice, $settings)
38
    {
39
        $this->invoice($invoice);
40
        $this->settings = (object) $settings;
41
    }
42
43
    private function generateAuthenticationEnvelope($pubKey, $terminalID, $password, $amount)
44
    {
45
        $data = $terminalID . $password . str_pad($amount, 12, '0', STR_PAD_LEFT) . '00';
46
        $data = hex2bin($data);
47
        $AESSecretKey = openssl_random_pseudo_bytes(16);
48
        $ivlen = openssl_cipher_iv_length($cipher = "AES-128-CBC");
49
        $iv = openssl_random_pseudo_bytes($ivlen);
50
        $ciphertext_raw = openssl_encrypt($data, $cipher, $AESSecretKey, $options = OPENSSL_RAW_DATA, $iv);
51
        $hmac = hash('sha256', $ciphertext_raw, true);
52
        $crypttext = '';
53
54
        openssl_public_encrypt($AESSecretKey . $hmac, $crypttext, $pubKey);
55
56
        return array(
57
            "data" => bin2hex($crypttext),
58
            "iv" => bin2hex($iv),
59
        );
60
    }
61
62
    /**
63
     * Purchase Invoice.
64
     *
65
     * @return string
66
     *
67
     * @throws PurchaseFailedException
68
     * @throws \SoapFault
69
     */
70
    public function purchase()
71
    {
72
        if (!empty($this->invoice->getDetails()['description'])) {
73
            $description = $this->invoice->getDetails()['description'];
0 ignored issues
show
Unused Code introduced by
The assignment to $description is dead and can be removed.
Loading history...
74
        } else {
75
            $description = $this->settings->description;
76
        }
77
78
        $pubKey = $this->settings->pubKey;
79
        $terminalID = $this->settings->terminalId;
80
        $password = $this->settings->password;
81
        $amount = $this->invoice->getAmount() * 10;
82
83
        $token = $this->generateAuthenticationEnvelope($pubKey, $terminalID, $password, $amount);
84
85
        $data = [];
86
        $data['request'] = [
87
            'acceptorId' => $this->settings->acceptorId,
88
            'amount' => $this->invoice->getAmount() * 10, // convert to rial
89
            'billInfo' => null,
90
            "paymentId" => null,
91
            "requestId" => uniqid(),
92
            "requestTimestamp" => time(),
93
            "revertUri" => $this->settings->callbackUrl,
94
            "terminalId" => $this->settings->terminalId,
95
            "transactionType" => "Purchase",
96
        ];
97
        $data['authenticationEnvelope'] = $token;
98
        $dataString = json_encode($data);
99
100
        $ch = curl_init($this->settings->apiPurchaseUrl);
101
        curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
102
        curl_setopt($ch, CURLOPT_POSTFIELDS, $dataString);
103
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
104
        curl_setopt($ch, CURLOPT_HTTPHEADER, array(
105
            'Content-Type: application/json',
106
            'Content-Length: ' . strlen($dataString)
107
        ));
108
109
        $result = curl_exec($ch);
110
        curl_close($ch);
111
112
        $response = json_decode($result, JSON_OBJECT_AS_ARRAY);
0 ignored issues
show
Bug introduced by
It seems like $result can also be of type true; however, parameter $json of json_decode() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

112
        $response = json_decode(/** @scrutinizer ignore-type */ $result, JSON_OBJECT_AS_ARRAY);
Loading history...
Bug introduced by
Shetabit\Multipay\Driver...sh\JSON_OBJECT_AS_ARRAY of type integer is incompatible with the type boolean|null expected by parameter $associative of json_decode(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

112
        $response = json_decode($result, /** @scrutinizer ignore-type */ JSON_OBJECT_AS_ARRAY);
Loading history...
113
114
        if (!$response || $response["responseCode"] != "00") {
115
            // error has happened
116
            $message = $response["description"] ?? 'خطا در هنگام درخواست برای پرداخت رخ داده است.';
117
            throw new PurchaseFailedException($message);
118
        }
119
120
        $this->invoice->transactionId($response['result']['token']);
121
122
        // return the transaction's id
123
        return $this->invoice->getTransactionId();
124
    }
125
126
    /**
127
     * Pay the Invoice
128
     *
129
     * @return RedirectionForm
130
     */
131
    public function pay() : RedirectionForm
132
    {
133
        $payUrl = $this->settings->apiPaymentUrl;
134
135
        return $this->redirectWithForm(
136
            $payUrl,
137
            [
138
                'tokenIdentity' => $this->invoice->getTransactionId()
139
            ],
140
            'POST'
141
        );
142
    }
143
144
    /**
145
     * Verify payment
146
     *
147
     * @return ReceiptInterface
148
     *
149
     * @throws InvalidPaymentException
150
     */
151
    public function verify() : ReceiptInterface
152
    {
153
        $status = Request::input('responseCode');
154
        if (Request::input('responseCode') != "00") {
155
            return $this->notVerified($status);
156
        }
157
158
        $data = [
159
            'terminalId' => $this->settings->terminalId,
160
            'retrievalReferenceNumber' => Request::input('retrievalReferenceNumber'),
161
            'systemTraceAuditNumber' => Request::input('systemTraceAuditNumber'),
162
            'tokenIdentity' => Request::input('token'),
163
        ];
164
165
        $dataString = json_encode($data);
166
167
        $ch = curl_init($this->settings->apiVerificationUrl);
168
        curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
169
        curl_setopt($ch, CURLOPT_POSTFIELDS, $dataString);
170
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
171
        curl_setopt($ch, CURLOPT_HTTPHEADER, array(
172
            'Content-Type: application/json',
173
            'Content-Length: ' . strlen($dataString)
174
        ));
175
176
        $result = curl_exec($ch);
177
        if ($result === false || !$data['retrievalReferenceNumber']) {
178
            $this->notVerified($status);
179
        }
180
        curl_close($ch);
181
182
        $response = json_decode($result, JSON_OBJECT_AS_ARRAY);
0 ignored issues
show
Bug introduced by
It seems like $result can also be of type true; however, parameter $json of json_decode() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

182
        $response = json_decode(/** @scrutinizer ignore-type */ $result, JSON_OBJECT_AS_ARRAY);
Loading history...
Bug introduced by
Shetabit\Multipay\Driver...sh\JSON_OBJECT_AS_ARRAY of type integer is incompatible with the type boolean|null expected by parameter $associative of json_decode(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

182
        $response = json_decode($result, /** @scrutinizer ignore-type */ JSON_OBJECT_AS_ARRAY);
Loading history...
Unused Code introduced by
The assignment to $response is dead and can be removed.
Loading history...
183
184
        return $this->createReceipt($data['retrievalReferenceNumber']);
185
    }
186
187
    /**
188
     * Generate the payment's receipt
189
     *
190
     * @param $referenceId
191
     *
192
     * @return Receipt
193
     */
194
    protected function createReceipt($referenceId)
195
    {
196
        return new Receipt('irankish', $referenceId);
197
    }
198
199
    /**
200
     * Trigger an exception
201
     *
202
     * @param $status
203
     * @throws InvalidPaymentException
204
     */
205
    private function notVerified($status)
206
    {
207
        $translations = [
208
            5 => 'از انجام تراکنش صرف نظر شد',
209
            17 => 'از انجام تراکنش صرف نظر شد',
210
            3 => 'پذیرنده فروشگاهی نامعتبر است',
211
            64 => 'مبلغ تراکنش نادرست است، جمع مبالغ تقسیم وجوه برابر مبلغ کل تراکنش نمی باشد',
212
            94 => 'تراکنش تکراری است',
213
            25 => 'تراکنش اصلی یافت نشد',
214
            77 => 'روز مالی تراکنش نا معتبر است',
215
            63 => 'کد اعتبار سنجی پیام نا معتبر است',
216
            97 => 'کد تولید کد اعتبار سنجی نا معتبر است',
217
            30 => 'فرمت پیام نادرست است',
218
            86 => 'شتاب در حال  Off Sign است',
219
            55 => 'رمز کارت نادرست است',
220
            40 => 'عمل درخواستی پشتیبانی نمی شود',
221
            57 => 'انجام تراکنش مورد درخواست توسط پایانه انجام دهنده مجاز نمی باشد',
222
            58 => 'انجام تراکنش مورد درخواست توسط پایانه انجام دهنده مجاز نمی باشد',
223
//            63 => 'تمهیدات امنیتی نقض گردیده است',
224
            96 => 'قوانین سامانه نقض گردیده است ، خطای داخلی سامانه',
225
            2 => 'تراکنش قبال برگشت شده است',
226
            54 => 'تاریخ انقضا کارت سررسید شده است',
227
            62 => 'کارت محدود شده است',
228
            75 => 'تعداد دفعات ورود رمز اشتباه از حد مجاز فراتر رفته است',
229
            14 => 'اطالعات کارت صحیح نمی باشد',
230
            51 => 'موجودی حساب کافی نمی باشد',
231
            56 => 'اطالعات کارت یافت نشد',
232
            61 => 'مبلغ تراکنش بیش از حد مجاز است',
233
            65 => 'تعداد دفعات انجام تراکنش بیش از حد مجاز است',
234
            78 => 'کارت فعال نیست',
235
            79 => 'حساب متصل به کارت بسته یا دارای اشکال است',
236
            42 => 'کارت یا حساب مبدا در وضعیت پذیرش نمی باشد',
237
//            42 => 'کارت یا حساب مقصد در وضعیت پذیرش نمی باشد',
238
            31 => 'عدم تطابق کد ملی خریدار با دارنده کارت',
239
            98 => 'سقف استفاده از رمز دوم ایستا به پایان رسیده است',
240
            901 => 'درخواست نا معتبر است )Tokenization(',
241
            902 => 'پارامترهای اضافی درخواست نامعتبر می باشد )Tokenization(',
242
            903 => 'شناسه پرداخت نامعتبر می باشد )Tokenization(',
243
            904 => 'اطالعات مرتبط با قبض نا معتبر می باشد )Tokenization(',
244
            905 => 'شناسه درخواست نامعتبر می باشد )Tokenization(',
245
            906 => 'درخواست تاریخ گذشته است )Tokenization(',
246
            907 => 'آدرس بازگشت نتیجه پرداخت نامعتبر می باشد )Tokenization(',
247
            909 => 'پذیرنده نامعتبر می باشد)Tokenization(',
248
            910 => 'پارامترهای مورد انتظار پرداخت تسهیمی تامین نگردیده است)Tokenization(',
249
            911 => 'پارامترهای مورد انتظار پرداخت تسهیمی نا معتبر یا دارای اشکال می باشد)Tokenization(',
250
            912 => 'تراکنش درخواستی برای پذیرنده فعال نیست )Tokenization(',
251
            913 => 'تراکنش تسهیم برای پذیرنده فعال نیست )Tokenization(',
252
            914 => 'آدرس آی پی دریافتی درخواست نا معتبر می باشد',
253
            915 => 'شماره پایانه نامعتبر می باشد )Tokenization(',
254
            916 => 'شماره پذیرنده نا معتبر می باشد )Tokenization(',
255
            917 => 'نوع تراکنش اعالم شده در خواست نا معتبر می باشد )Tokenization(',
256
            918 => 'پذیرنده فعال نیست)Tokenization(',
257
            919 => 'مبالغ تسهیمی ارائه شده با توجه به قوانین حاکم بر وضعیت تسهیم پذیرنده ، نا معتبر است )Tokenization(',
258
            920 => 'شناسه نشانه نامعتبر می باشد',
259
            921 => 'شناسه نشانه نامعتبر و یا منقضی شده است',
260
            922 => 'نقض امنیت درخواست )Tokenization(',
261
            923 => 'ارسال شناسه پرداخت در تراکنش قبض مجاز نیست)Tokenization(',
262
            928 => 'مبلغ مبادله شده نا معتبر می باشد)Tokenization(',
263
            929 => 'شناسه پرداخت ارائه شده با توجه به الگوریتم متناظر نا معتبر می باشد)Tokenization(',
264
            930 => 'کد ملی ارائه شده نا معتبر می باشد)Tokenization('
265
        ];
266
        if (array_key_exists($status, $translations)) {
267
            throw new InvalidPaymentException($translations[$status]);
268
        } else {
269
            throw new InvalidPaymentException('خطای ناشناخته ای رخ داده است.');
270
        }
271
    }
272
}
273