Response::paid()   B
last analyzed

Complexity

Conditions 5
Paths 11

Size

Total Lines 26
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 30

Importance

Changes 0
Metric Value
dl 0
loc 26
rs 8.439
c 0
b 0
f 0
ccs 0
cts 14
cp 0
cc 5
eloc 17
nc 11
nop 1
crap 30
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) {
0 ignored issues
show
Bug introduced by
The class PaySys\PaySys\Exception does not exist. Did you forget a USE statement, or did you not list all dependencies?

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.

Loading history...
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