validateSearchOrderRequiredAttributes()   B
last analyzed

Complexity

Conditions 5
Paths 6

Size

Total Lines 28
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 1 Features 0
Metric Value
c 1
b 1
f 0
dl 0
loc 28
rs 8.439
cc 5
eloc 13
nc 6
nop 2
1
<?php
2
3
namespace ActionM\WebMoneyMerchant;
4
5
use Illuminate\Http\Request;
6
use Illuminate\Support\Facades\Validator;
7
use ActionM\WebMoneyMerchant\Events\WebMoneyMerchantEvent;
8
use ActionM\WebMoneyMerchant\Exceptions\InvalidConfiguration;
9
10
class WebMoneyMerchant
11
{
12
    public function __construct()
13
    {
14
    }
15
16
    /**
17
     * Allow the access, if the ip address is in the whitelist.
18
     * @param $ip
19
     * @return bool
20
     */
21
    public function allowIP($ip)
22
    {
23
        // Allow the local ip or any other ip address
24
        if ($ip == '127.0.0.1' || in_array('*', config('webmoney-merchant.allowed_ips'))) {
25
            return true;
26
        }
27
28
        return in_array($ip, config('webmoney-merchant.allowed_ips'));
29
    }
30
31
    /**
32
     * Generates the '403' error code.
33
     * @param $message
34
     * @return mixed
35
     */
36
    public function responseError($message)
37
    {
38
        return abort(403, $message);
39
    }
40
41
    /**
42
     * Returns the 'YES' success message.
43
     * @return string
44
     */
45
    public function responseOK()
46
    {
47
        return 'YES';
48
    }
49
50
    /**
51
     * Fills in the event details to pass the title and request params as array.
52
     * @param $event_type
53
     * @param $event_title
54
     * @param Request $request
55
     */
56
    public function eventFillAndSend($event_type, $event_title, Request $request)
57
    {
58
        $event_details = [
59
            'title' => 'WebMoneyMerchant: '.$event_title,
60
            'ip' => $request->ip(),
61
            'request' => $request->all(),
62
        ];
63
64
        event(
65
            new WebMoneyMerchantEvent($event_type, $event_details)
66
        );
67
    }
68
69
    /**
70
     * Calculates the signature for the order form.
71
     * @param $LMI_PAYMENT_AMOUNT
72
     * @param $LMI_PAYMENT_NO
73
     * @return string
74
     */
75
    public function getFormSignature($LMI_PAYMENT_AMOUNT, $LMI_PAYMENT_NO)
76
    {
77
        $hashStr = config('webmoney-merchant.WM_LMI_PAYEE_PURSE').';'.$LMI_PAYMENT_AMOUNT.';'.$LMI_PAYMENT_NO.';'.config('webmoney-merchant.WM_LMI_SECRET_X20').';';
78
79
        return hash('sha256', $hashStr);
80
    }
81
82
    /**
83
     * Returns the hash for the params from WebMoneyMerchant.
84
     * @param Request $request
85
     * @return string
86
     */
87
    public function getSignature(Request $request)
88
    {
89
        $hashStr =
90
            $request->get('LMI_PAYEE_PURSE').
91
            $request->get('LMI_PAYMENT_AMOUNT').
92
            $request->get('LMI_PAYMENT_NO').
93
            $request->get('LMI_MODE').
94
            $request->get('LMI_SYS_INVS_NO').
95
            $request->get('LMI_SYS_TRANS_NO').
96
            $request->get('LMI_SYS_TRANS_DATE').
97
            config('webmoney-merchant.WM_LMI_SECRET_KEY').
98
            $request->get('LMI_PAYER_PURSE').
99
            $request->get('LMI_PAYER_WM');
100
101
        return hash('sha256', $hashStr);
102
    }
103
104
    /**
105
     * Generates the order array with required fields for the order form.
106
     * @param $payment_amount
107
     * @param $payment_no
108
     * @param $item_name
109
     * @return array
110
     */
111
    public function generateWebMoneyMerchantOrderWithRequiredFields($payment_amount, $payment_no, $item_name)
112
    {
113
        $order = [
114
            'PAYMENT_AMOUNT' => $payment_amount,
115
            'PAYMENT_NO' => $payment_no,
116
            'ITEM_NAME' => base64_encode($item_name),
117
        ];
118
119
        $this->requiredOrderParamsCheck($order);
120
121
        return $order;
122
    }
123
124
    /**
125
     * Checks required order params for the order form and raise an exception if it fails.
126
     * @param $order
127
     * @throws InvalidConfiguration
128
     */
129
    public function requiredOrderParamsCheck($order)
130
    {
131
        $required_fields = [
132
            'PAYMENT_AMOUNT',
133
            'PAYMENT_NO',
134
            'ITEM_NAME',
135
        ];
136
137
        foreach ($required_fields as $key => $value) {
138
            if (! array_key_exists($value, $order) || empty($order[$value])) {
139
                throw InvalidConfiguration::generatePaymentFormOrderParamsNotSet($value);
140
            }
141
        }
142
143
        // Checks if PAYMENT_NO is numeric.
144
        if (! is_numeric($order['PAYMENT_NO'])) {
145
            throw InvalidConfiguration::generatePaymentFormOrderInvalidPaymentNo('PAYMENT_NO');
146
        }
147
148
        // Checks if PAYMENT_NO > 0 and < 2147483647
149
        if (intval($order['PAYMENT_NO']) < 1 || intval($order['PAYMENT_NO']) > 2147483647) {
150
            throw InvalidConfiguration::generatePaymentFormOrderInvalidPaymentNo($order['PAYMENT_NO']);
151
        }
152
    }
153
154
    /**
155
     * Generates html forms from view with payment buttons
156
     * Note: you can customise the view via artisan:publish.
157
     * @param $payment_amount
158
     * @param $payment_no
159
     * @param $item_name
160
     * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
161
     */
162
    public function generatePaymentForm($payment_amount, $payment_no, $item_name)
163
    {
164
        $order = $this->generateWebMoneyMerchantOrderWithRequiredFields($payment_amount, $payment_no, $item_name);
165
166
        $this->requiredOrderParamsCheck($order);
167
168
        /* WM Merchant accepts windows-1251; use only latin characters for the product name*/
169
        $payment_fields = [];
170
        $payment_fields['LMI_PAYMENT_AMOUNT'] = $order['PAYMENT_AMOUNT'];
171
        $payment_fields['LMI_PAYMENT_NO'] = $order['PAYMENT_NO'];
172
        $payment_fields['LMI_PAYMENT_DESC_BASE64'] = $order['ITEM_NAME'];
173
        $payment_fields['LOCALE'] = config('webmoney-merchant.locale');
174
        $payment_fields['LMI_PAYEE_PURSE'] = config('webmoney-merchant.WM_LMI_PAYEE_PURSE');
175
        $payment_fields['LMI_PAYMENTFORM_SIGN'] = $this->getFormSignature($payment_fields['LMI_PAYMENT_AMOUNT'], $payment_fields['LMI_PAYMENT_NO']);
176
177
        return view('webmoney-merchant::payment_form', compact('payment_fields'));
178
    }
179
180
    /**
181
     * Validates the request params from WebMoneyMerchant.
182
     * @param Request $request
183
     * @return bool
184
     */
185
    public function validate(Request $request)
186
    {
187
        $validator = Validator::make($request->all(), [
188
            'LMI_PAYEE_PURSE' => 'required',
189
            'LMI_PAYMENT_AMOUNT' => 'required',
190
            'LMI_PAYMENT_NO' => 'required',
191
            'LMI_PAYER_IP' => 'required',
192
            'LMI_HASH' => 'required',
193
            'LMI_HASH2' => 'required',
194
        ]);
195
196
        if ($validator->fails()) {
197
            return false;
198
        }
199
200
        return true;
201
    }
202
203
    /**
204
     * Validates the payee purse from WebMoneyMerchant.
205
     * @param Request $request
206
     * @return bool
207
     */
208
    public function validatePayeePurse(Request $request)
209
    {
210
        if ($request->get('LMI_PAYEE_PURSE') != config('webmoney-merchant.WM_LMI_PAYEE_PURSE')) {
211
            return false;
212
        }
213
214
        return true;
215
    }
216
217
    /**
218
     * Validates the request signature from WebMoneyMerchant.
219
     * @param Request $request
220
     * @return bool
221
     */
222
    public function validateSignature(Request $request)
223
    {
224
        $sign = $this->getSignature($request);
225
226
        if (mb_strtoupper($request->get('LMI_HASH')) != mb_strtoupper($sign)) {
227
            return false;
228
        }
229
230
        return true;
231
    }
232
233
    /**
234
     * Validates the allowed ip, request params and signature from WebMoneyMerchant.
235
     * @param Request $request
236
     * @return bool
237
     */
238
    public function validateOrderRequestFromGate(Request $request)
239
    {
240
        if (! $this->AllowIP($request->ip()) || ! $this->validate($request) || ! $this->validatePayeePurse($request) || ! $this->validateSignature($request)) {
241
            $this->eventFillAndSend('webmoneymerchant.error', 'validateOrderRequestFromGate', $request);
242
243
            return false;
244
        }
245
246
        return true;
247
    }
248
249
    /**
250
     * Validates the required attributes of the found order.
251
     * @param Request $request
252
     * @param $order
253
     * @return bool
254
     */
255
    public function validateSearchOrderRequiredAttributes(Request $request, $order)
256
    {
257
        if (! $order) {
258
            $this->eventFillAndSend('webmoneymerchant.error', 'orderNotFound', $request);
259
260
            return false;
261
        }
262
263
        // Checks required found order attributes.
264
        $attr = ['WEBMONEY_orderStatus', 'WEBMONEY_orderSum'];
265
266
        foreach ($attr as $k => $value) {
267
            if (! $order->getAttribute($value)) {
268
                $this->eventFillAndSend('webmoneymerchant.error', $value.'Invalid', $request);
269
270
                return false;
271
            }
272
        }
273
274
        // Compares order attributes with request params.
275
        if ($order->getAttribute('WEBMONEY_orderSum') != $request->input('LMI_PAYMENT_AMOUNT')) {
276
            $this->eventFillAndSend('webmoneymerchant.error', $value.'Invalid', $request);
0 ignored issues
show
Bug introduced by
The variable $value seems to be defined by a foreach iteration on line 266. Are you sure the iterator is never empty, otherwise this variable is not defined?

It seems like you are relying on a variable being defined by an iteration:

foreach ($a as $b) {
}

// $b is defined here only if $a has elements, for example if $a is array()
// then $b would not be defined here. To avoid that, we recommend to set a
// default value for $b.


// Better
$b = 0; // or whatever default makes sense in your context
foreach ($a as $b) {
}

// $b is now guaranteed to be defined here.
Loading history...
277
278
            return false;
279
        }
280
281
        return true;
282
    }
283
284
    /**
285
     * Calls SearchOrderFilter and check return order params.
286
     * @param Request $request
287
     * @return bool
288
     * @throws InvalidConfiguration
289
     */
290
    public function callFilterSearchOrder(Request $request)
291
    {
292
        $callable = config('webmoney-merchant.searchOrderFilter');
293
294
        if (! is_callable($callable)) {
295
            throw InvalidConfiguration::searchOrderFilterInvalid();
296
        }
297
298
        /*
299
         *  SearchOrderFilter
300
         *  Searches the order in the database and return the order details.
301
         *  Must return the array with:
302
         *
303
         *  orderStatus
304
         *  orderSum
305
         */
306
307
        $order = $callable($request, $request->input('LMI_PAYMENT_NO'));
308
309
        if (! $this->validateSearchOrderRequiredAttributes($request, $order)) {
310
            return false;
311
        }
312
313
        return $order;
314
    }
315
316
    /**
317
     * Calls PaidOrderFilter if the order is not paid.
318
     * @param Request $request
319
     * @param $order
320
     * @return mixed
321
     * @throws InvalidConfiguration
322
     */
323
    public function callFilterPaidOrder(Request $request, $order)
324
    {
325
        $callable = config('webmoney-merchant.paidOrderFilter');
326
327
        if (! is_callable($callable)) {
328
            throw InvalidConfiguration::orderPaidFilterInvalid();
329
        }
330
331
        // Unset the custom order attributes; for Eloquent support.
332
        unset($order['WEBMONEY_orderSum'], $order['WEBMONEY_orderStatus']);
333
334
        // Runs the `PaidOrderFilter` callback.
335
        return $callable($request, $order);
336
    }
337
338
    /**
339
     * Runs WebMoneyMerchant::payOrderFromGate($request) when the request from WebMoney Merchant has been received.
340
     * @param Request $request
341
     * @return mixed
342
     */
343
    public function payOrderFromGate(Request $request)
344
    {
345
        if (! $request->has('LMI_HASH')) {
346
            return 'OK';
347
        }
348
349
        if ($request->has('LMI_PREREQUEST')) {
350
            return 'YES';
351
        }
352
353
        // Validates the request params from the WebMoney Merchant server.
354
        if (! $this->validateOrderRequestFromGate($request)) {
355
            $this->eventFillAndSend('webmoneymerchant.error', 'validateOrderRequestFromGate', $request);
356
357
            return $this->responseError('validateOrderRequestFromGate');
358
        }
359
360
        // Searches and returns the order
361
        $order = $this->callFilterSearchOrder($request);
362
363
        if (! $order) {
364
            $this->eventFillAndSend('webmoneymerchant.error', 'searchOrderFilter', $request);
365
366
            return $this->responseError('searchOrderFilter');
367
        }
368
369
        // If the current order status is `paid`.
370
        // Sends the notification and returns the success response.
371
        if (mb_strtolower($order->WEBMONEY_orderStatus) === 'paid') {
372
            $this->eventFillAndSend('webmoneymerchant.info', 'The order is already paid', $request);
373
374
            return $this->responseError('The order is already paid');
375
        }
376
377
        // The current order is paid on WebMoney Merchant and not paid in the database.
378
379
        $this->eventFillAndSend('webmoneymerchant.success', 'paid order', $request);
380
381
        // PaidOrderFilter - update the order into the DB as paid & other actions.
382
        // If it returns false, then some error has occurred.
383
        if (! $this->callFilterPaidOrder($request, $order)) {
384
            $this->eventFillAndSend('webmoneymerchant.error', 'callFilterPaidOrder', $request);
385
386
            return $this->responseError('callFilterPaidOrder');
387
        }
388
389
        // The order is paid on WebMoney Merchant and updated in the database.
390
        return $this->responseOK();
391
    }
392
}
393