1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace PaySys\TatraPay\Security; |
4
|
|
|
|
5
|
|
|
use Nette; |
6
|
|
|
use Nette\Utils\Strings; |
7
|
|
|
use PaySys\TatraPay\Configuration; |
8
|
|
|
|
9
|
|
|
|
10
|
1 |
|
final class Response |
11
|
|
|
{ |
12
|
1 |
|
use Nette\SmartObject; |
13
|
|
|
|
14
|
|
|
const PUBLIC_KEYS = "https://moja.tatrabanka.sk/e-commerce/ecdsa_keys.txt"; |
15
|
|
|
|
16
|
|
|
/** @var callable[] function (array $parameters); Occurs on response from bank */ |
17
|
|
|
public $onResponse; |
18
|
|
|
|
19
|
|
|
/** @var callable[] function (array $parameters); Occurs on success payment response from bank */ |
20
|
|
|
public $onSuccess; |
21
|
|
|
|
22
|
|
|
/** @var callable[] function (array $parameters); Occurs on fail payment response from bank */ |
23
|
|
|
public $onFail; |
24
|
|
|
|
25
|
|
|
/** @var callable[] function (array $parameters, \PaySys\PaySys\Exception $e); Occurs on damaged response from bank */ |
26
|
|
|
public $onError; |
27
|
|
|
|
28
|
|
|
/** @var Configuration */ |
29
|
|
|
protected $config; |
30
|
|
|
|
31
|
|
|
/** @var array */ |
32
|
|
|
private $keys; |
33
|
|
|
|
34
|
|
|
public function __construct(Configuration $config) |
35
|
|
|
{ |
36
|
1 |
|
$this->config = $config; |
37
|
1 |
|
} |
38
|
|
|
|
39
|
|
|
public function paid(array $parameters) : bool |
40
|
|
|
{ |
41
|
|
|
try { |
42
|
|
|
$this->checkParameters($parameters); |
43
|
|
|
|
44
|
|
|
if ($parameters['HMAC'] !== $this->getHmac($parameters)) |
45
|
|
|
throw new \PaySys\PaySys\SignatureException('HMAC sign is not valid.'); |
46
|
|
|
|
47
|
|
|
|
48
|
|
|
if (!$this->verified($parameters)) |
49
|
|
|
throw new \PaySys\PaySys\SignatureException('ECDSA sign is not valid.'); |
50
|
|
|
|
51
|
|
|
$this->onResponse($parameters); |
52
|
|
|
|
53
|
|
|
if ($parameters['RES'] === 'OK') { |
54
|
|
|
$this->onSuccess($parameters); |
55
|
|
|
return TRUE; |
56
|
|
|
} else { |
57
|
|
|
$this->onFail($parameters); |
58
|
|
|
return FALSE; |
59
|
|
|
} |
60
|
|
|
} catch (\PaySys\PaySys\Exception $e) { |
|
|
|
|
61
|
|
|
$this->onError($parameters, $e); |
62
|
|
|
throw $e; |
63
|
|
|
} |
64
|
|
|
} |
65
|
|
|
|
66
|
|
|
public function getSignString(array $parameters) : string |
67
|
|
|
{ |
68
|
1 |
|
return $parameters['AMT'] |
69
|
1 |
|
. $parameters['CURR'] |
70
|
1 |
|
. $parameters['VS'] |
71
|
1 |
|
. $parameters['RES'] |
72
|
1 |
|
. $parameters['TID'] |
73
|
1 |
|
. $parameters['TIMESTAMP']; |
74
|
|
|
} |
75
|
|
|
|
76
|
|
|
public function getHmac(array $parameters) : string |
77
|
|
|
{ |
78
|
1 |
|
return hash_hmac("sha256", $this->getSignString($parameters), $this->config->getKey()); |
79
|
|
|
} |
80
|
|
|
|
81
|
|
|
|
82
|
|
|
public function verified(array $parameters) : bool |
83
|
|
|
{ |
84
|
1 |
|
$verified = openssl_verify($this->getSignString($parameters) . $parameters['HMAC'], pack("H*", $parameters['ECDSA']), $this->getPublicKey($parameters['ECDSA_KEY']), "sha256"); |
85
|
|
|
|
86
|
1 |
|
if ($verified === -1) { |
87
|
|
|
throw new \PaySys\PaySys\SignatureException(sprintf("Error while verify bank response: %s", openssl_error_string())); |
88
|
|
|
} else { |
89
|
1 |
|
return $verified; |
90
|
|
|
} |
91
|
|
|
} |
92
|
|
|
|
93
|
|
|
public function setPublicKey(int $id, string $key) : Response |
94
|
|
|
{ |
95
|
1 |
|
$this->keys[$id] = $key; |
96
|
1 |
|
return $this; |
97
|
|
|
} |
98
|
|
|
|
99
|
|
|
public function getPublicKey(int $id) : string |
100
|
|
|
{ |
101
|
1 |
|
if ($this->keys[$id]) |
102
|
1 |
|
return $this->keys[$id]; |
103
|
|
|
|
104
|
|
|
foreach (explode("\r\n\r\n", file_get_contents(self::PUBLIC_KEYS)) as $source) { |
105
|
|
|
preg_match('/KEY_ID: (\d+)/', $source, $tmp); |
106
|
|
|
$key_id = (int) $tmp[1]; |
107
|
|
|
|
108
|
|
|
if ($key_id === $id) { |
109
|
|
|
if ((bool) Strings::match($source, '~VALID+~')) { |
110
|
|
|
|
111
|
|
|
preg_match_all("/-----BEGIN PUBLIC KEY-----(.*)-----END PUBLIC KEY-----/msU", $source, $key); |
112
|
|
|
return $this->keys[id] = Strings::trim($key[0][0]); |
113
|
|
|
|
114
|
|
|
} else { |
115
|
|
|
throw new \PaySys\PaySys\ServerException(sprintf("Key '%d' was revoked.", $id)); |
116
|
|
|
} |
117
|
|
|
} |
118
|
|
|
} |
119
|
|
|
} |
120
|
|
|
|
121
|
|
|
private function checkParameters(array & $parameters) |
122
|
|
|
{ |
123
|
|
|
foreach (['AMT', 'CURR', 'VS', 'RES', 'TID', 'TIMESTAMP', 'HMAC', 'ECDSA_KEY', 'ECDSA'] as $key) { |
124
|
|
|
if (isset($parameters[$key])) { |
125
|
|
|
$parameters[$key] = Strings::trim($parameters[$key]); |
126
|
|
|
} else { |
127
|
|
|
throw new \PaySys\PaySys\ServerException(sprintf("Missing parameter '%s'.", $key)); |
128
|
|
|
} |
129
|
|
|
} |
130
|
|
|
} |
131
|
|
|
} |
132
|
|
|
|
Scrutinizer analyzes your
composer.json
/composer.lock
file if available to determine the classes, and functions that are defined by your dependencies.It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.