This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | namespace Omnipay\Gtpay\Message; |
||
3 | |||
4 | use Omnipay\Gtpay\Exception\FailedPaymentException; |
||
5 | use Omnipay\Gtpay\Exception\ValidationException; |
||
6 | |||
7 | class ResponseDataValidator |
||
8 | { |
||
9 | /** |
||
10 | * @var \Omnipay\Common\Message\RequestInterface | AbstractRequest |
||
11 | */ |
||
12 | private $request; |
||
13 | |||
14 | private $data; |
||
15 | |||
16 | private $response; |
||
17 | |||
18 | 10 | public function __construct(CompletePurchaseResponse $response) |
|
19 | { |
||
20 | 10 | $this->request = $response->getRequest(); |
|
21 | 10 | $this->data = $response->getData(); |
|
22 | 10 | $this->response = $response; |
|
23 | 10 | } |
|
24 | |||
25 | 10 | public function validateTransactionRef($expectedRef, $returnedRef) |
|
26 | { |
||
27 | 10 | if (!$expectedRef || !$returnedRef) { |
|
28 | return false; |
||
29 | } |
||
30 | 10 | return self::compareStrings($expectedRef, $returnedRef); |
|
31 | } |
||
32 | |||
33 | 10 | public static function compareStrings($one, $two) |
|
34 | { |
||
35 | 10 | return strnatcasecmp($one, $two) === 0; |
|
36 | } |
||
37 | |||
38 | 8 | public function verifyHashValue($gatewayHash, $expectedHash) |
|
39 | { |
||
40 | 8 | return self::compareStrings($gatewayHash, $expectedHash); |
|
41 | } |
||
42 | |||
43 | /** |
||
44 | * checks if amount paid is identical to amount due |
||
45 | * @param float $gatewayAmount Amount returned by the gateway |
||
46 | * @param float $dueAmount Expected Amount to be returned |
||
47 | * @return bool |
||
48 | */ |
||
49 | 2 | public function verifyCorrectAmount($gatewayAmount, $dueAmount) |
|
50 | { |
||
51 | 2 | $gatewayAmount = floatval($gatewayAmount); |
|
52 | 2 | $dueAmount = floatval($dueAmount); |
|
53 | |||
54 | 2 | return abs($dueAmount - $gatewayAmount)< 0.0001; |
|
55 | } |
||
56 | |||
57 | /** |
||
58 | * @todo move most of this into a validator class |
||
59 | * @throws FailedPaymentException |
||
60 | * @throws ValidationException |
||
61 | */ |
||
62 | 10 | public function validate() |
|
63 | { |
||
64 | 10 | $statusCode = $this->data['gtpay_tranx_status_code']; |
|
65 | |||
66 | 10 | if (!$this->validateTransactionRef( |
|
67 | 10 | $this->request->getTransactionId(), |
|
68 | 10 | $this->data['gtpay_tranx_id'] |
|
69 | ) |
||
70 | ) { |
||
71 | 1 | throw $this->determineException(sprintf( |
|
72 | 1 | "Invalid Transaction ref: %s", |
|
73 | 1 | $this->data['gtpay_tranx_id'] |
|
74 | 1 | ), $statusCode); |
|
75 | } |
||
76 | |||
77 | 9 | if (self::compareStrings(CompletePurchaseResponse::CANCELED_GATEWAY_CODE, $statusCode) |
|
78 | ) { |
||
79 | 1 | throw $this->determineException("Customer Cancellation", $statusCode); |
|
80 | } |
||
81 | |||
82 | 8 | if (!$this->verifyHashValue( |
|
83 | 8 | $this->data['gtpay_full_verification_hash'], |
|
84 | 8 | $this->getFullVerificationHash($statusCode) |
|
85 | )) { |
||
86 | 1 | $msg = "Data incompatibility reported. Please contact support"; |
|
87 | 1 | throw $this->determineException($msg, $statusCode); |
|
88 | } |
||
89 | 7 | if (!self::compareStrings($this->data['gtpay_cust_id'], $this->request->getCustomerId())) { |
|
0 ignored issues
–
show
|
|||
90 | 1 | $msg = "Received Customer Id: {$this->data['gtpay_cust_id']} does not match expected Customer Id"; |
|
91 | 1 | throw $this->determineException($msg, $statusCode); |
|
92 | } |
||
93 | 6 | if (!self::compareStrings($this->data['site_redirect_url'], $this->request->getNotifyUrl())) { |
|
94 | 1 | throw $this->determineException("Redirect Url is wrong.", $statusCode); |
|
95 | } |
||
96 | 5 | } |
|
97 | |||
98 | 4 | public function successValidate() |
|
99 | { |
||
100 | |||
101 | 4 | if (isset($this->data['TransactionCurrency'])) { |
|
102 | 1 | if (!self::compareStrings($this->data['TransactionCurrency'], $this->request->getCurrency())) { |
|
103 | 1 | throw new ValidationException("Transaction currency does not match expected currency."); |
|
104 | } |
||
105 | } |
||
106 | |||
107 | 3 | if (!self::compareStrings($this->data['MertID'], $this->request->getMerchantId())) { |
|
0 ignored issues
–
show
It seems like you code against a concrete implementation and not the interface
Omnipay\Common\Message\RequestInterface as the method getMerchantId() does only exist in the following implementations of said interface: Omnipay\Gtpay\Message\AbstractRequest , Omnipay\Gtpay\Message\CompletePurchaseRequest , Omnipay\Gtpay\Message\PurchaseRequest .
Let’s take a look at an example: interface User
{
/** @return string */
public function getPassword();
}
class MyUser implements User
{
public function getPassword()
{
// return something
}
public function getDisplayName()
{
// return some name.
}
}
class AuthSystem
{
public function authenticate(User $user)
{
$this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
// do something.
}
}
In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break. Available Fixes
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types
inside the if block in such a case.
![]() |
|||
108 | 1 | throw new ValidationException("Wrong Merchant ID returned."); |
|
109 | } |
||
110 | 2 | if (!$this->verifyCorrectAmount($this->data['Amount'], $this->request->getAmountInteger())) { |
|
111 | 1 | throw new ValidationException( |
|
112 | 1 | sprintf( |
|
113 | 1 | "Incorrect Amount Paid. Expected Amount: %s, Amount Paid: %s", |
|
114 | 1 | $this->response->formatIntegerAmount($this->request->getAmountInteger()), |
|
115 | 1 | $this->response->formatIntegerAmount($this->data['Amount']) |
|
116 | ) |
||
117 | ); |
||
118 | } |
||
119 | 1 | } |
|
120 | |||
121 | /** |
||
122 | * Distinguishes between exceptions that have a failed status code from the gateway |
||
123 | * and exceptions when the status code indicates success. The later may indicate fraud. |
||
124 | * For validation exception, you may want to consider sending an email to admin as further investigation |
||
125 | * may be required |
||
126 | * @param $msg |
||
127 | * @param $statusCode |
||
128 | * @return FailedPaymentException|ValidationException |
||
129 | */ |
||
130 | 5 | private function determineException($msg, $statusCode) |
|
131 | { |
||
132 | 5 | if ($this->response->hasSuccessCode($statusCode)) { |
|
133 | 4 | return new ValidationException($msg); |
|
134 | } else { |
||
135 | 1 | return new FailedPaymentException($msg); |
|
136 | } |
||
137 | } |
||
138 | |||
139 | 8 | public function getFullVerificationHash($statusCode) |
|
140 | { |
||
141 | 8 | $rawString = $this->response->getTransactionId(). |
|
142 | 8 | $this->response->getGatewayAmountInteger(). |
|
143 | 8 | $statusCode. |
|
144 | 8 | $this->response->getGatewayNumericCurrency(). |
|
145 | 8 | $this->request->getHashKey(); |
|
0 ignored issues
–
show
It seems like you code against a concrete implementation and not the interface
Omnipay\Common\Message\RequestInterface as the method getHashKey() does only exist in the following implementations of said interface: Omnipay\Gtpay\Message\AbstractRequest , Omnipay\Gtpay\Message\CompletePurchaseRequest , Omnipay\Gtpay\Message\PurchaseRequest .
Let’s take a look at an example: interface User
{
/** @return string */
public function getPassword();
}
class MyUser implements User
{
public function getPassword()
{
// return something
}
public function getDisplayName()
{
// return some name.
}
}
class AuthSystem
{
public function authenticate(User $user)
{
$this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
// do something.
}
}
In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break. Available Fixes
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types
inside the if block in such a case.
![]() |
|||
146 | 8 | return hash('sha512', $rawString); |
|
147 | } |
||
148 | } |
||
149 |
Let’s take a look at an example:
In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.
Available Fixes
Change the type-hint for the parameter:
Add an additional type-check:
Add the method to the interface: