Issues (1)

Security Analysis    not enabled

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

src/Bridge/AdyenBridge.php (1 issue)

Severity

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
/*
4
 * This file has been created by developers from BitBag.
5
 * Feel free to contact us once you face any issues or want to start
6
 * another great project.
7
 * You can find more information about us on https://bitbag.shop and write us
8
 * an email on [email protected].
9
 */
10
11
declare(strict_types=1);
12
13
namespace BitBag\SyliusAdyenPlugin\Bridge;
14
15
use Payum\Core\Bridge\Spl\ArrayObject;
16
use Payum\Core\HttpClientInterface;
17
18
final class AdyenBridge implements AdyenBridgeInterface
19
{
20
    /**
21
     * @var array
22
     */
23
    protected $requiredFields = [
24
        'merchantReference' => null,
25
        'paymentAmount' => null,
26
        'currencyCode' => null,
27
        'shipBeforeDate' => null,
28
        'skinCode' => null,
29
        'merchantAccount' => null,
30
        'sessionValidity' => null,
31
        'shopperEmail' => null,
32
    ];
33
34
    /**
35
     * @var array
36
     */
37
    protected $optionalFields = [
38
        'merchantReturnData' => null,
39
        'shopperReference' => null,
40
        'allowedMethods' => null,
41
        'blockedMethods' => null,
42
        'offset' => null,
43
        'shopperStatement' => null,
44
        'recurringContract' => null,
45
        'billingAddressType' => null,
46
        'deliveryAddressType' => null,
47
        'resURL' => null,
48
    ];
49
    /**
50
     * @var array
51
     */
52
    protected $othersFields = [
53
        'brandCode' => null,
54
        'countryCode' => null,
55
        'shopperLocale' => null,
56
        'orderData' => null,
57
        'offerEmail' => null,
58
        'issuerId' => null,
59
    ];
60
61
    /**
62
     * @var array
63
     */
64
    protected $notificationFields = [
65
        'pspReference' => null,
66
        'originalReference' => null,
67
        'merchantAccountCode' => null,
68
        'merchantReference' => null,
69
        'value' => null,
70
        'currency' => null,
71
        'eventCode' => null,
72
        'success' => null,
73
    ];
74
75
    /**
76
     * @var ArrayObject
77
     */
78
    protected $options = [
79
        'skinCode' => null,
80
        'merchantAccount' => null,
81
        'hmacKey' => null,
82
        'environment' => null,
83
        'notification_method' => null,
84
        'notification_hmac' => null,
85
        'default_payment_fields' => [],
86
        'ws_user' => null,
87
        'ws_user_password' => null,
88
    ];
89
90
    /**
91
     * @var \SoapClient|object
92
     */
93
    protected $soapClient;
94
95
    /**
96
     * @param array               $options
97
     * @param HttpClientInterface $client
98
     *
99
     * @throws \Payum\Core\Exception\InvalidArgumentException if an option is invalid
100
     * @throws \Payum\Core\Exception\LogicException if a sandbox is not boolean
101
     */
102
    public function __construct(array $options, HttpClientInterface $client = null)
0 ignored issues
show
The parameter $client is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
103
    {
104
        $options = ArrayObject::ensureArrayObject($options);
105
        $options->defaults($this->options);
106
        $options->validateNotEmpty([
107
            'skinCode',
108
            'merchantAccount',
109
            'hmacKey',
110
            'notification_hmac',
111
            'ws_user',
112
            'ws_user_password',
113
        ]);
114
115
        $this->options = $options;
116
    }
117
118
    /**
119
     * @return string
120
     */
121
    public function getApiEndpoint(): string
122
    {
123
        return sprintf('https://%s.adyen.com/hpp/select.shtml', $this->options['environment']);
124
    }
125
126
    /**
127
     * @param array $params
128
     * @param bool $isNotify
129
     * @param string $hmacKey
130
     *
131
     * @return string
132
     */
133
    public function merchantSig(array $params, bool $isNotify = false, string $hmacKey = 'hmacKey'): string
134
    {
135
        if (false === $isNotify) {
136
            ksort($params, SORT_STRING);
137
        }
138
139
        $escapedPairs = [];
140
141
        foreach ($params as $key => $value) {
142
            $escapedPairs[$key] = str_replace(':','\\:', str_replace('\\', '\\\\', $value));
143
        }
144
145
        if (false === $isNotify) {
146
            $signingString = implode(":", array_merge(array_keys($escapedPairs), array_values($escapedPairs)));
147
        } else {
148
            $signingString = implode(":", array_merge(array_values($escapedPairs)));
149
        }
150
151
        $binaryHmacKey = pack("H*" , $this->options[$hmacKey]);
152
153
        $binaryHmac = hash_hmac('sha256', $signingString, $binaryHmacKey, true);
154
155
        $signature = base64_encode($binaryHmac);
156
157
        return $signature;
158
    }
159
160
    /**
161
     * @param array $params
162
     *
163
     * @return bool
164
     */
165
    public function verifySign(array $params): bool
166
    {
167
        if (empty($params['merchantSig'])) {
168
            return false;
169
        }
170
171
        $merchantSig = $params['merchantSig'];
172
173
        unset($params['merchantSig']);
174
175
        return $merchantSig === $this->merchantSig($params);
176
    }
177
178
    /**
179
     * @param array $params
180
     *
181
     * @return bool
182
     */
183
    public function verifyNotification(array $params): bool
184
    {
185
        if (empty($params['additionalData_hmacSignature'])) {
186
            return false;
187
        }
188
189
        $merchantSig = $params['additionalData_hmacSignature'];
190
191
        $data = [];
192
193
        foreach (array_keys($this->notificationFields) as $fieldKey) {
194
            if (isset($params[$fieldKey])) {
195
                $data[$fieldKey] = $params[$fieldKey];
196
            }
197
        }
198
199
        return $merchantSig === $this->merchantSig($data, true,'notification_hmac');
200
    }
201
202
    /**
203
     * @param array $params
204
     *
205
     * @return string
206
     */
207
    public function createSignatureForNotification(array $params): string
208
    {
209
        $data = [];
210
211
        foreach (array_keys($this->notificationFields) as $fieldKey) {
212
            $data[$fieldKey] = $params[$fieldKey];
213
        }
214
215
        return $this->merchantSig($data, true,'notification_hmac');
216
    }
217
218
    /**
219
     * @param array $params
220
     * @param array $details
221
     *
222
     * @return bool
223
     */
224
    public function verifyRequest(array $params, array $details): bool
225
    {
226
        if (!isset($params['merchantReference']) || empty($params['merchantReference']) ||
227
            !isset($params['authResult']) || empty($params['authResult'])) {
228
            return false;
229
        }
230
231
        if (!isset($details['merchantReference']) || ($details['merchantReference'] !== $params['merchantReference'])) {
232
            return false;
233
        }
234
235
        return $this->verifySign($params);
236
    }
237
238
    /**
239
     * @param array $params
240
     *
241
     * @return array
242
     */
243
    public function prepareFields(array $params): array
244
    {
245
        if (false !== empty($this->options['default_payment_fields'])) {
246
            $params = array_merge($params, (array) $this->options['default_payment_fields']);
247
        }
248
249
        $params['shipBeforeDate'] = date('Y-m-d', strtotime('+1 hour'));
250
        $params['sessionValidity'] = date(DATE_ATOM, strtotime('+1 hour'));
251
252
        $params['skinCode'] = $this->options['skinCode'];
253
        $params['merchantAccount'] = $this->options['merchantAccount'];
254
255
        $supportedParams = array_merge($this->requiredFields, $this->optionalFields, $this->othersFields);
256
257
        $params = array_filter(array_replace(
258
            $supportedParams,
259
            array_intersect_key($params, $supportedParams)
260
        ));
261
262
        $params['merchantSig'] = $this->merchantSig($params);
263
264
        return $params;
265
    }
266
267
    public function createSoapClient(): void
268
    {
269
        $this->soapClient = new \SoapClient(
270
            $this->getWsdl(), [
271
                "login" => $this->options['ws_user'],
272
                "password" => $this->options['ws_user_password'],
273
                "style" => SOAP_DOCUMENT,
274
                "encoding" => SOAP_LITERAL,
275
                "cache_wsdl" => WSDL_CACHE_BOTH,
276
                "trace" => 1
277
            ]
278
        );
279
    }
280
281
    /**
282
     * @return string
283
     */
284
    public function getWsdl(): string
285
    {
286
        return sprintf('https://pal-%s.adyen.com/pal/Payment.wsdl', $this->options['environment']);
287
    }
288
289
    /**
290
     * @return string
291
     */
292
    public function getMerchantAccount(): string
293
    {
294
        return $this->options['merchantAccount'];
295
    }
296
297
    /**
298
     * @param array $modificationAmount
299
     * @param string $originalReference
300
     * @param string $reference
301
     *
302
     * @return \stdClass
303
     */
304
    public function refundAction(
305
        array $modificationAmount,
306
        string $originalReference,
307
        string $reference
308
    ): \stdClass
309
    {
310
        $this->createSoapClient();
311
312
        $data = [
313
            'modificationRequest' => [
314
                'merchantAccount' => $this->getMerchantAccount(),
315
                'modificationAmount' => $modificationAmount,
316
                'originalReference' => $originalReference,
317
                'reference' => $reference,
318
            ]
319
        ];
320
321
        return $this->soapClient->refund($data);
322
    }
323
}
324