Completed
Push — master ( 70be8d...b5e6ba )
by Jan
05:24
created

CryptographyServiceTest::provideInvalidKeyPaths()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 7
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 0
1
<?php declare(strict_types = 1);
2
3
namespace SlevomatEET\Cryptography;
4
5
use DateTimeImmutable;
6
use DateTimeZone;
7
use PHPUnit\Framework\Error\Error;
8
use PHPUnit\Framework\TestCase;
9
use SlevomatEET\Formatter;
10
use function base64_encode;
11
12
class CryptographyServiceTest extends TestCase
13
{
14
15
	private const EXPECTED_PKP = 'hdBqjqCTaEfJ6JI06H+c4OLvRGtntcwLlG0fucEkla++g9RLxP55jYlPLFf6Sdpm5jPC+hpBHry98zsPBlbwkcFiWdmgT2VBCtXxrwfRmJQOHNRdWhItDsHC4p45G+KmtC4uJCFAqFNL+E999wevPaS6Q02WktmvWI5+XUZnN75hR+G94oznpJS8T140850/FsYDlvPw0ZVWJwDMBzVrOWWxPSN3SBwa40TjD3dVIMlMC1Bo0NccnFp0y7GxNMSfIzDhF5R4S2Rmawe85znZ0PiHXMkPDhXLLpPx1pNiMsTwfeoEnhEMSU/PjjmLpbUzaRfLwZzgf+7Bl0ZX+/lsqA==';
16
	private const EXPECTED_BKP = 'F049C3F1-165CDCDA-2E35BC3A-FCB5C660-4B84D0B7';
17
	private const PRIVATE_KEY_WITHOUT_PASSWORD_PATH = __DIR__ . '/../../../cert/EET_CA1_Playground-CZ00000019.key';
18
	private const PRIVATE_KEY_WITH_PASSWORD_PATH = __DIR__ . '/../../../cert/EET_CA1_Playground_With_Password-CZ00000019.key';
19
	private const PUBLIC_KEY_PATH = __DIR__ . '/../../../cert/EET_CA1_Playground-CZ00000019.pub';
20
	private const INVALID_KEY_PATH = __DIR__ . '/invalid-certificate.pem';
21
22
	public function testGetCodes(): void
23
	{
24
		$data = $this->getReceiptData();
25
		$crypto = $this->createCryptographyServiceWithoutPassword();
26
27
		$expectedPkp = self::EXPECTED_PKP;
28
		$pkpCode = $crypto->getPkpCode($data);
29
		self::assertSame($expectedPkp, base64_encode($pkpCode));
30
		self::assertSame(self::EXPECTED_BKP, $crypto->getBkpCode($pkpCode));
31
	}
32
33
	/**
34
	 * @dataProvider provideInvalidKeyPaths
35
	 *
36
	 * @param string $privateKeyPath
37
	 * @param string $publicKeyPath
38
	 * @param string $expectedExceptionType
39
	 *
40
	 * @phpstan-param class-string<\Throwable> $expectedExceptionType
41
	 */
42
	public function testInvalidKeyPaths(string $privateKeyPath, string $publicKeyPath, string $expectedExceptionType): void
43
	{
44
		$this->expectException($expectedExceptionType);
45
		new CryptographyService($privateKeyPath, $publicKeyPath);
46
	}
47
48
	/**
49
	 * @return array[]
50
	 */
51
	public function provideInvalidKeyPaths(): array
52
	{
53
		return [
54
			[self::PRIVATE_KEY_WITHOUT_PASSWORD_PATH, './foo/path', PublicKeyFileNotFoundException::class],
55
			['./foo/path', self::PUBLIC_KEY_PATH, PrivateKeyFileNotFoundException::class],
56
		];
57
	}
58
59
	public function testInvalidPrivateKeyInPkpCalculation(): void
60
	{
61
		$cryptoService = new CryptographyService(
62
			self::INVALID_KEY_PATH,
63
			self::PUBLIC_KEY_PATH
64
		);
65
66
		try {
67
			$cryptoService->getPkpCode($this->getReceiptData());
68
			$this->fail();
69
70
		} catch (PrivateKeyFileException $e) {
71
			$this->assertSame(self::INVALID_KEY_PATH, $e->getPrivateKeyFile());
72
		}
73
	}
74
75
	/**
76
	 * @runInSeparateProcess
77
	 */
78
	public function testExceptions2(): void
79
	{
80
		include __DIR__ . '/OpenSslFunctionsMock.php';
81
82
		$cryptoService = $this->createCryptographyServiceWithoutPassword();
83
84
		try {
85
			$cryptoService->getPkpCode($this->getReceiptData());
86
			$this->fail();
87
88
		} catch (SigningFailedException $e) {
89
			$this->assertSame(array_values($this->getReceiptData()), $e->getData());
90
		}
91
	}
92
93
	public function testWSESignatureWithoutPrivateKeyPassword(): void
94
	{
95
		$request = $this->getRequestData();
96
		$crypto = $this->createCryptographyServiceWithoutPassword();
97
98
		$this->assertNotEmpty($crypto->addWSESignature($request));
99
	}
100
101
	public function testWSESignatureWithPrivateKeyPassword(): void
102
	{
103
		$request = $this->getRequestData();
104
		$crypto = $this->createCryptographyServiceWithPassword('eet');
105
106
		$this->assertNotEmpty($crypto->addWSESignature($request));
107
	}
108
109
	public function testWSESignatureWithInvalidPrivateKeyPassword(): void
110
	{
111
		$request = $this->getRequestData();
112
		$crypto = $this->createCryptographyServiceWithPassword('invalid');
113
114
		$this->expectException(Error::class);
115
		$this->expectExceptionMessage('openssl_sign(): supplied key param cannot be coerced into a private key');
116
		$crypto->addWSESignature($request);
117
	}
118
119
	public function testWSESignatureWithInvalidPublicKey(): void
120
	{
121
		$request = $this->getRequestData();
122
		$crypto = new CryptographyService(
123
			self::PRIVATE_KEY_WITHOUT_PASSWORD_PATH,
124
			self::INVALID_KEY_PATH
125
		);
126
127
		$this->expectException(InvalidPublicKeyException::class);
128
		$crypto->addWSESignature($request);
129
	}
130
131
	/**
132
	 * @return mixed[]
133
	 */
134
	private function getReceiptData(): array
135
	{
136
		return [
137
			'dic_popl' => 'CZ00000019',
138
			'id_provoz' => '273',
139
			'id_pokl' => '/5546/RO24',
140
			'porad_cis' => '0/6460/ZQ42',
141
			'dat_trzby' => Formatter::formatDateTime(new DateTimeImmutable('2016-08-05 00:30:12', new DateTimeZone('Europe/Prague'))),
142
			'celk_trzba' => Formatter::formatAmount(3411300),
143
		];
144
	}
145
146
	private function getRequestData(): string
147
	{
148
		$requestTemplate = (string) file_get_contents(__DIR__ . '/CZ00000019.fixture.3.1.xml');
149
150
		$data = $this->getReceiptData();
151
		$data += [
152
			'pkp' => self::EXPECTED_PKP,
153
			'bkp' => self::EXPECTED_BKP,
154
		];
155
156
		$patterns = array_map(static function (string $dataKey): string {
157
			return sprintf('~{%s}~', $dataKey);
158
		}, array_keys($data));
159
		$replacements = array_values($data);
160
161
		return (string) preg_replace($patterns, $replacements, $requestTemplate);
162
	}
163
164
	private function createCryptographyServiceWithoutPassword(): CryptographyService
165
	{
166
		return new CryptographyService(self::PRIVATE_KEY_WITHOUT_PASSWORD_PATH, self::PUBLIC_KEY_PATH);
167
	}
168
169
	private function createCryptographyServiceWithPassword(string $password): CryptographyService
170
	{
171
		return new CryptographyService(
172
			self::PRIVATE_KEY_WITH_PASSWORD_PATH,
173
			self::PUBLIC_KEY_PATH,
174
			$password
175
		);
176
	}
177
178
}
179