Passed
Pull Request — master (#165)
by
unknown
08:11
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
    /**
44
     * Purchase Invoice.
45
     *
46
     * @return string
47
     *
48
     * @throws PurchaseFailedException
49
     * @throws \SoapFault
50
     */
51
    public function purchase()
52
    {
53
        if (!empty($this->invoice->getDetails()['description'])) {
54
            $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...
55
        } else {
56
            $description = $this->settings->description;
57
        }
58
59
        $amountToPay = $this->invoice->getAmount() * 10; // convert to rial
60
        $token = $this->generateAuthenticationEnvelope($this->settings->publicKey, $this->settings->terminalId, $this->settings->password, $amountToPay);
61
        
62
        $data = [];
63
        $data["request"] = [
64
            'amount' => $amountToPay,
65
            'acceptorId' => $this->settings->acceptorId,
66
            "billInfo" => null,
67
            "paymentId" => null,
68
            "requestId" => (string) crc32($this->invoice->getUuid()),
69
            "requestTimestamp" => time(),
70
            "revertUri" => $this->settings->callbackUrl,
71
            "terminalId" => $this->settings->terminalId,
72
            "transactionType" => "Purchase"
73
        ];
74
        $data['authenticationEnvelope'] = $token;
75
76
        $data_string = json_encode($data);
77
        $ch = curl_init($this->settings->apiPurchaseUrl);
78
        curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
79
        curl_setopt($ch, CURLOPT_POSTFIELDS, $data_string);
80
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
81
        curl_setopt($ch, CURLOPT_SSL_CIPHER_LIST, 'DEFAULT@SECLEVEL=1');
82
        curl_setopt($ch, CURLOPT_HTTPHEADER, array(
83
            'Content-Type: application/json',
84
            'Content-Length: ' . strlen($data_string)
85
        ));
86
        $result = curl_exec($ch);
87
        curl_close($ch);
88
        $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

88
        $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

88
        $response = json_decode($result, /** @scrutinizer ignore-type */ JSON_OBJECT_AS_ARRAY);
Loading history...
89
90
        $responseCode = isset($response["responseCode"]) ? $response["responseCode"] : null;
91
        if ($responseCode == "00") {
92
            $this->invoice->transactionId($response['result']['token']);
93
        } else {
94
            // error has happened
95
            $errors = isset($response['errors']) ? json_encode($response['errors']) : null;
96
            $message = $errors ?? 'خطا در هنگام درخواست برای پرداخت رخ داده است.';
97
            throw new PurchaseFailedException($message);
98
        }
99
100
        // return the transaction's id
101
        return $this->invoice->getTransactionId();
102
    }
103
104
    /**
105
     * Pay the Invoice
106
     *
107
     * @return RedirectionForm
108
     */
109
    public function pay() : RedirectionForm
110
    {
111
        $payUrl = $this->settings->apiPaymentUrl;
112
113
        return $this->redirectWithForm(
114
            $payUrl,
115
            [
116
                'tokenIdentity' => $this->invoice->getTransactionId()
117
            ],
118
            'POST'
119
        );
120
    }
121
122
    /**
123
     * Verify payment
124
     *
125
     * @return ReceiptInterface
126
     *
127
     * @throws InvalidPaymentException
128
     * @throws \SoapFault
129
     */
130
    public function verify() : ReceiptInterface
131
    {
132
        $data = array(
133
            "terminalId" => $this->settings->terminalId,
134
            "retrievalReferenceNumber" => $_POST['retrievalReferenceNumber'],
135
            "systemTraceAuditNumber" => $_POST['systemTraceAuditNumber'],
136
            "tokenIdentity" => $_POST['token'],
137
        );
138
        $data_string = json_encode($data);
139
140
        $ch = curl_init($this->settings->apiVerificationUrl);
141
        curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
142
        curl_setopt($ch, CURLOPT_POSTFIELDS, $data_string);
143
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
144
        curl_setopt($ch, CURLOPT_SSL_CIPHER_LIST, 'DEFAULT@SECLEVEL=1');
145
        curl_setopt($ch, CURLOPT_HTTPHEADER, array(
146
            'Content-Type: application/json',
147
            'Content-Length: ' . strlen($data_string)
148
        ));
149
150
        $result = curl_exec($ch);
151
        curl_close($ch);
152
    
153
        $response = json_decode($result, JSON_OBJECT_AS_ARRAY);
0 ignored issues
show
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

153
        $response = json_decode($result, /** @scrutinizer ignore-type */ JSON_OBJECT_AS_ARRAY);
Loading history...
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

153
        $response = json_decode(/** @scrutinizer ignore-type */ $result, JSON_OBJECT_AS_ARRAY);
Loading history...
154
155
        if (($response['responseCode'] != "00") || ($response['stauts'] == false)) {
156
            $this->notVerified($response['responseCode']);
157
        }
158
159
        return $this->createReceipt($data['retrievalReferenceNumber']);
160
    }
161
162
    /**
163
     * Generate the payment's receipt
164
     *
165
     * @param $referenceId
166
     *
167
     * @return Receipt
168
     */
169
    protected function createReceipt($referenceId)
170
    {
171
        $receipt = new Receipt('irankish', $referenceId);
172
173
        return $receipt;
174
    }
175
176
    /**
177
     * Trigger an exception
178
     *
179
     * @param $status
180
     * @throws InvalidPaymentException
181
     */
182
    private function notVerified($status)
183
    {
184
        $translations = array(
185
            110 => 'دارنده کارت انصراف داده است',
186
            120 => 'موجودی حساب کافی نمی باشد',
187
            121 => 'مبلغ تراکنشهای کارت بیش از حد مجاز است',
188
            130 => 'اطلاعات کارت نادرست می باشد',
189
            131 => 'رمز کارت اشتباه است',
190
            132 => 'کارت مسدود است',
191
            133 => 'کارت منقضی شده است',
192
            140 => 'زمان مورد نظر به پایان رسیده است',
193
            150 => 'خطای داخلی بانک به وجود آمده است',
194
            160 => 'خطای انقضای کارت به وجود امده یا اطلاعات CVV2 اشتباه است',
195
            166 => 'بانک صادر کننده کارت شما مجوز انجام تراکنش را صادر نکرده است',
196
            167 => 'خطا در مبلغ تراکنش',
197
            200 => 'مبلغ تراکنش بیش از حدنصاب مجاز',
198
            201 => 'مبلغ تراکنش بیش از حدنصاب مجاز برای روز کاری',
199
            202 => 'مبلغ تراکنش بیش از حدنصاب مجاز برای ماه کاری',
200
            203 => 'تعداد تراکنشهای مجاز از حد نصاب گذشته است',
201
            499 => 'خطای سیستمی ، لطفا مجددا تالش فرمایید',
202
            500 => 'خطا در تایید تراکنش های خرد شده',
203
            501 => 'خطا در تایید تراکتش ، ویزگی تایید خودکار',
204
            502 => 'آدرس آی پی نا معتبر',
205
            503 => 'پذیرنده در حالت تستی می باشد ، مبلغ نمی تواند بیش از حد مجاز تایین شده برای پذیرنده تستی باشد',
206
            504 => 'خطا در بررسی الگوریتم شناسه پرداخت',
207
            505 => 'مدت زمان الزم برای انجام تراکنش تاییدیه به پایان رسیده است',
208
            506 => 'ذیرنده یافت نشد',
209
            507 => 'توکن نامعتبر/طول عمر توکن منقضی شده است',
210
            508 => 'توکن مورد نظر یافت نشد و یا منقضی شده است',
211
            509 => 'خطا در پارامترهای اجباری خرید تسهیم شده',
212
            510 => 'خطا در تعداد تسهیم | مبالغ کل تسهیم مغایر با مبلغ کل ارائه شده | خطای شماره ردیف تکراری',
213
            511 => 'حساب مسدود است',
214
            512 => 'حساب تعریف نشده است',
215
            513 => 'شماره تراکنش تکراری است',
216
            514 => 'پارامتر های ضروری برای طرح آسان خرید تامین نشده است',
217
            515 => 'کارت مبدا تراکنش مجوز انجام عملیات در طرح آسان خرید را ندارد',
218
            -20 => 'در درخواست کارکتر های غیر مجاز وجو دارد',
219
            -30 => 'تراکنش قبلا برگشت خورده است',
220
            -50 => 'طول رشته درخواست غیر مجاز است',
221
            -51 => 'در در خواست خطا وجود دارد',
222
            -80 => 'تراکنش مورد نظر یافت نشد',
223
            -81 => ' خطای داخلی بانک',
224
            -90 => 'تراکنش قبلا تایید شده است',
225
            -91 => 'تراکنش قبال تایید شده | مدت زمان انتضار برای تایید به پایان رسیده است'
226
        );
227
        if (array_key_exists($status, $translations)) {
228
            throw new InvalidPaymentException($translations[$status]);
229
        } else {
230
            throw new InvalidPaymentException('خطای ناشناخته ای رخ داده است.');
231
        }
232
    }
233
234
    /**
235
     * generats authentication envelope
236
     *
237
     * @param string $pub_key
238
     * @param string $terminalID
239
     * @param string $password
240
     * @param string|integer $amount
241
     * @return array
242
     */
243
    private function generateAuthenticationEnvelope($pub_key, $terminalID, $password, $amount)
244
    {
245
        $data = $terminalID . $password . str_pad($amount, 12, '0', STR_PAD_LEFT) . '00';
246
        $data = hex2bin($data);
247
        $AESSecretKey = openssl_random_pseudo_bytes(16);
248
        $ivlen = openssl_cipher_iv_length($cipher = "AES-128-CBC");
249
        $iv = openssl_random_pseudo_bytes($ivlen);
250
        $ciphertext_raw = openssl_encrypt($data, $cipher, $AESSecretKey, $options = OPENSSL_RAW_DATA, $iv);
251
        $hmac = hash('sha256', $ciphertext_raw, true);
252
        $crypttext = '';
253
254
        openssl_public_encrypt($AESSecretKey . $hmac, $crypttext, $pub_key);
255
256
        return array(
257
            "data" => bin2hex($crypttext),
258
            "iv" => bin2hex($iv),
259
        );
260
    }
261
}
262