Passed
Push — master ( 3c151b...b5e885 )
by Charles
03:04
created

RequestResponseTest   A

Complexity

Total Complexity 23

Size/Duplication

Total Lines 317
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 23
eloc 197
dl 0
loc 317
rs 10
c 0
b 0
f 0

8 Methods

Rating   Name   Duplication   Size   Complexity  
A testv2EncryptDecrypt() 0 18 1
A testVersion() 0 4 1
B testV1EncryptedRequestAndResponse() 0 73 6
A testDecryptEmptyString() 0 16 1
A testv1EncryptDecrypt() 0 26 1
A testPublicKeyExtraction() 0 4 1
B testV2EncryptedRequestAndResponse() 0 62 6
B testUnauthenticatedV2EncryptedRequestAndResponse() 0 56 6
1
<?php declare(strict_types=1);
2
3
namespace ncryptf\Tests;
4
5
use DateTime;
6
use ncryptf\Token;
7
use ncryptf\Request;
8
use ncryptf\Response;
9
use ncryptf\Authorization;
10
use Middlewares\Utils\Factory;
11
use WildWolf\Psr16MemoryCache;
12
use ncryptf\Tests\AbstractTest;
13
use PHPUnit\Framework\TestCase;
14
15
use Middlewares\Utils\Dispatcher;
16
use ncryptf\Tests\mock\EchoResponse;
17
use ncryptf\Tests\mock\EncryptionKey;
18
use ncryptf\Tests\mock\Authentication;
19
use Psr\Http\Message\ResponseInterface;
20
use Psr\Http\Server\MiddlewareInterface;
21
use ncryptf\middleware\JsonRequestParser;
22
use Psr\Http\Message\ServerRequestInterface;
23
use Psr\Http\Server\RequestHandlerInterface;
24
use ncryptf\middleware\JsonResponseFormatter;
25
26
class RequestResponseTest extends AbstractTest
27
{
28
    private $clientKeyPair = [
29
        'secret' => 'bvV/vnfB43spmprI8aBK/Fd8xxSBlx7EhuxfxxTVI2o=',
30
        'public' => 'Ojnr0KQy6GJ6x+eQa+wNwdHejZo8vY5VNyZY5NfwBjU='
31
    ];
32
33
    private $serverKeyPair = [
34
        'secret' => 'gH1+ileX1W5fMeOWue8HxdREnK04u72ybxCQgivWoZ4=',
35
        'public' => 'YU74X2OqHujLVDH9wgEHscD5eyiLPvcugRUZG6R3BB8='
36
    ];
37
38
    private $signatureKeyPair = [
39
        'secret' => '9wdUWlSW2ZQB6ImeUZ5rVqcW+mgQncN1Cr5D2YvFdvEi42NKK/654zGtxTSOcNHPEwtFAz0A4k0hwlIFopZEsQ==',
40
        'public' => 'IuNjSiv+ueMxrcU0jnDRzxMLRQM9AOJNIcJSBaKWRLE='
41
    ];
42
43
    private $nonce = 'bulRnKt/BvwnwiCMBLvdRM5+yNFP38Ut';
44
45
    private $expectedCipher = '1odrjBif71zRcZidfhEzSb80rXGJGB1J3upTb+TwhpxmFjXOXjwSDw45e7p/+FW4Y0/FDuLjHfGghOG0UC7j4xmX8qIVYUdbKCB/dLn34HQ0D0NIM6N9Qj83bpS5XgK1o+luonc0WxqA3tdXTcgkd2D+cSSSotJ/s+5fqN3w5xsKc7rKb1p3MpvRzyEmdNgJCFOk8EErn0bolz9LKyPEO0A2Mnkzr19bDwsgD1DGEYlo0i9KOw06RpaZRz2J+OJ+EveIlQGDdLT8Gh+nv65TOKJqCswOly0=';
46
    private $expectedSignature = 'dcvJclMxEx7pcW/jeVm0mFHGxVksY6h0/vNkZTfVf+wftofnP+yDFdrNs5TtZ+FQ0KEOm6mm9XUMXavLaU9yDg==';
47
48
    private $expectedv2Cipher = '3iWQAm7pUZyrfwb8J8IgjAS73UTOfsjRT9/FLTo569CkMuhiesfnkGvsDcHR3o2aPL2OVTcmWOTX8AY11odrjBif71zRcZidfhEzSb80rXGJGB1J3upTb+TwhpxmFjXOXjwSDw45e7p/+FW4Y0/FDuLjHfGghOG0UC7j4xmX8qIVYUdbKCB/dLn34HQ0D0NIM6N9Qj83bpS5XgK1o+luonc0WxqA3tdXTcgkd2D+cSSSotJ/s+5fqN3w5xsKc7rKb1p3MpvRzyEmdNgJCFOk8EErn0bolz9LKyPEO0A2Mnkzr19bDwsgD1DGEYlo0i9KOw06RpaZRz2J+OJ+EveIlQGDdLT8Gh+nv65TOKJqCswOly0i42NKK/654zGtxTSOcNHPEwtFAz0A4k0hwlIFopZEsXXLyXJTMRMe6XFv43lZtJhRxsVZLGOodP7zZGU31X/sH7aH5z/sgxXazbOU7WfhUNChDpuppvV1DF2ry2lPcg4SwqYwa53inoY2+eCPP4Hkp/PKhSOEMFlWV+dlQirn6GGf5RQSsQ7ti/QCvi/BRIhb3ZHiPptZJZIbYwqIpvYu';
49
50
    private $payload = <<<JSON
51
{
52
    "foo": "bar",
53
    "test": {
54
        "true": false,
55
        "zero": 0.0,
56
        "a": 1,
57
        "b": 3.14,
58
        "nil": null,
59
        "arr": [
60
            "a", "b", "c", "d"
61
        ]
62
    }
63
}
64
JSON;
65
66
    public function testv2EncryptDecrypt()
67
    {
68
        $request = new Request(
69
            \base64_decode($this->clientKeyPair['secret']),
70
            \base64_decode($this->signatureKeyPair['secret'])
71
        );
72
73
        $cipher = $request->encrypt($this->payload, \base64_decode($this->serverKeyPair['public']), 2, \base64_decode($this->nonce));
74
75
        $this->assertEquals($this->expectedv2Cipher, \base64_encode($cipher));
76
77
        $response = new Response(
78
            \base64_decode($this->serverKeyPair['secret'])
79
        );
80
81
        $plain = $response->decrypt($cipher);
82
83
        $this->assertEquals($this->payload, $plain);
84
    }
85
86
    public function testDecryptEmptyString()
87
    {
88
        $request = new Request(
89
            \base64_decode($this->clientKeyPair['secret']),
90
            \base64_decode($this->signatureKeyPair['secret'])
91
        );
92
93
        $cipher = $request->encrypt('', \base64_decode($this->serverKeyPair['public']));
94
95
        $response = new Response(
96
            \base64_decode($this->serverKeyPair['secret'])
97
        );
98
99
        $plain = $response->decrypt($cipher);
100
101
        $this->assertEquals('', $plain);
102
    }
103
104
    public function testv1EncryptDecrypt()
105
    {
106
        $request = new Request(
107
            \base64_decode($this->clientKeyPair['secret']),
108
            \base64_decode($this->signatureKeyPair['secret'])
109
        );
110
111
        $cipher = $request->encrypt($this->payload, \base64_decode($this->serverKeyPair['public']), 1, \base64_decode($this->nonce));
112
113
        $signature = $request->sign($this->payload);
114
115
        $this->assertEquals($this->expectedCipher, \base64_encode($cipher));
116
        $this->assertEquals($this->expectedSignature, \base64_encode($signature));
117
118
        $response = new Response(
119
            \base64_decode($this->serverKeyPair['secret'])
120
        );
121
122
        $plain = $response->decrypt($cipher, \base64_decode($this->clientKeyPair['public']), \base64_decode($this->nonce));
123
124
        $this->assertEquals($this->payload, $plain);
125
126
        $this->assertTrue($response->isSignatureValid(
127
            $this->payload,
128
            $signature,
129
            \base64_decode($this->signatureKeyPair['public'])
130
        ));
131
    }
132
133
    public function testV2EncryptedRequestAndResponse()
134
    {
135
        foreach ($this->testCases as $k => $params) {
136
            $serverKey = EncryptionKey::generate();
137
            $myKey = EncryptionKey::generate();
138
            $cache = Psr16MemoryCache::instance();
139
            $cache->set($serverKey->getHashIdentifier(), $serverKey);
140
141
            $auth = new Authorization($params[0], $params[1], $this->token, new DateTime, $params[2]);
142
            $token = $this->token;
143
144
            $response = Dispatcher::run(
145
                [
146
                    new JsonRequestParser($cache),
147
                    new Authentication,
148
                    function ($request, $next) use ($params) {
0 ignored issues
show
Unused Code introduced by
The import $params is not used and could be removed.

This check looks for imports that have been defined, but are not used in the scope.

Loading history...
149
                        $this->assertInstanceOf('\ncryptf\Token', $request->getAttribute('ncryptf-token'));
150
                        $this->assertEquals(true, \is_array($request->getAttribute('ncryptf-user')));
151
                        return $next->handle($request);
152
                    },
153
                    new JsonResponseFormatter($cache, new EncryptionKey),
154
                    new EchoResponse,
155
                ],
156
                Factory::createServerRequest($params[0], $params[1])
157
                    ->withHeader('Authorization', $auth->getHeader())
158
                    ->withHeader('Content-Type', 'application/vnd.ncryptf+json')
159
                    ->withHeader('Accept', 'application/vnd.ncryptf+json')
160
                    ->withHeader('X-HashId', $serverKey->getHashIdentifier())
161
                    ->withHeader('X-PubKey', \base64_encode($myKey->getBoxPublicKey()))
162
                    ->withBody((function () use ($params, $serverKey, $myKey, $token) {
163
                        $data = \is_array($params[2]) ? \json_encode($params[2]): $params[2];
164
165
                        if (!empty($params[2])) {
166
                            $request = new Request(
167
                                $myKey->getBoxSecretKey(),
168
                                $token->signature
169
                            );
170
171
                            $encryptedData = $request->encrypt(
172
                                $data,
173
                                $serverKey->getBoxPublicKey()
174
                            );
175
                        }
176
                        $stream = fopen('php://memory', 'r+');
177
                        fwrite($stream, empty($params[2]) ? '' : \base64_encode($encryptedData));
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $encryptedData does not seem to be defined for all execution paths leading up to this point.
Loading history...
Bug introduced by
It seems like $stream can also be of type false; however, parameter $handle of fwrite() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

177
                        fwrite(/** @scrutinizer ignore-type */ $stream, empty($params[2]) ? '' : \base64_encode($encryptedData));
Loading history...
178
                        rewind($stream);
0 ignored issues
show
Bug introduced by
It seems like $stream can also be of type false; however, parameter $handle of rewind() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

178
                        rewind(/** @scrutinizer ignore-type */ $stream);
Loading history...
179
                        return new \Zend\Diactoros\Stream($stream);
0 ignored issues
show
Bug introduced by
It seems like $stream can also be of type false; however, parameter $stream of Zend\Diactoros\Stream::__construct() does only seem to accept resource|string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

179
                        return new \Zend\Diactoros\Stream(/** @scrutinizer ignore-type */ $stream);
Loading history...
180
                    })())
181
            );
182
183
            $this->assertSame('application/vnd.ncryptf+json', $response->getHeaderLine('Content-Type'));
184
            $this->assertTrue($response->hasHeader('x-hashid'));
185
186
            $r = new Response(
187
                $myKey->getBoxSecretKey()
188
            );
189
190
            $plaintext = $r->decrypt(
191
                \base64_decode((string)$response->getBody())
192
            );
193
194
            $this->assertEquals(\is_array($params[2]) ? \json_encode($params[2]) : $params[2], $plaintext);
195
        }
196
    }
197
198
    public function testUnauthenticatedV2EncryptedRequestAndResponse()
199
    {
200
        foreach ($this->testCases as $k => $params) {
201
            $serverKey = EncryptionKey::generate();
202
            $myKey = EncryptionKey::generate();
203
            $cache = Psr16MemoryCache::instance();
204
            $cache->set($serverKey->getHashIdentifier(), $serverKey);
205
206
            $auth = new Authorization($params[0], $params[1], $this->token, new DateTime, $params[2]);
207
            $token = $this->token;
208
209
            $response = Dispatcher::run(
210
                [
211
                    new JsonRequestParser($cache),
212
                    new JsonResponseFormatter($cache, new EncryptionKey),
213
                    new EchoResponse,
214
                ],
215
                Factory::createServerRequest($params[0], $params[1])
216
                    ->withHeader('Authorization', $auth->getHeader())
217
                    ->withHeader('Content-Type', 'application/vnd.ncryptf+json')
218
                    ->withHeader('Accept', 'application/vnd.ncryptf+json')
219
                    ->withHeader('X-HashId', $serverKey->getHashIdentifier())
220
                    ->withHeader('X-PubKey', \base64_encode($myKey->getBoxPublicKey()))
221
                    ->withBody((function () use ($params, $serverKey, $myKey, $token) {
222
                        $data = \is_array($params[2]) ? \json_encode($params[2]): $params[2];
223
224
                        if (!empty($params[2])) {
225
                            $request = new Request(
226
                                $myKey->getBoxSecretKey(),
227
                                $token->signature
228
                            );
229
230
                            $encryptedData = $request->encrypt(
231
                                $data,
232
                                $serverKey->getBoxPublicKey()
233
                            );
234
                        }
235
                        $stream = fopen('php://memory', 'r+');
236
                        fwrite($stream, empty($params[2]) ? '' : \base64_encode($encryptedData));
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $encryptedData does not seem to be defined for all execution paths leading up to this point.
Loading history...
Bug introduced by
It seems like $stream can also be of type false; however, parameter $handle of fwrite() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

236
                        fwrite(/** @scrutinizer ignore-type */ $stream, empty($params[2]) ? '' : \base64_encode($encryptedData));
Loading history...
237
                        rewind($stream);
0 ignored issues
show
Bug introduced by
It seems like $stream can also be of type false; however, parameter $handle of rewind() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

237
                        rewind(/** @scrutinizer ignore-type */ $stream);
Loading history...
238
                        return new \Zend\Diactoros\Stream($stream);
0 ignored issues
show
Bug introduced by
It seems like $stream can also be of type false; however, parameter $stream of Zend\Diactoros\Stream::__construct() does only seem to accept resource|string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

238
                        return new \Zend\Diactoros\Stream(/** @scrutinizer ignore-type */ $stream);
Loading history...
239
                    })())
240
            );
241
242
            $this->assertSame('application/vnd.ncryptf+json', $response->getHeaderLine('Content-Type'));
243
            $this->assertTrue($response->hasHeader('x-hashid'));
244
245
            $r = new Response(
246
                $myKey->getBoxSecretKey()
247
            );
248
249
            $plaintext = $r->decrypt(
250
                \base64_decode((string)$response->getBody())
251
            );
252
253
            $this->assertEquals(\is_array($params[2]) ? \json_encode($params[2]) : $params[2], $plaintext);
254
        }
255
    }
256
257
    public function testV1EncryptedRequestAndResponse()
258
    {
259
        foreach ($this->testCases as $k => $params) {
260
            $serverKey = EncryptionKey::generate();
261
            $myKey = EncryptionKey::generate();
262
            $nonce = \random_bytes(24);
263
            $cache = Psr16MemoryCache::instance();
264
            $cache->set($serverKey->getHashIdentifier(), $serverKey);
265
266
            $auth = new Authorization($params[0], $params[1], $this->token, new DateTime, $params[2]);
267
            $token = $this->token;
268
            $response = Dispatcher::run(
269
                [
270
                    new JsonRequestParser($cache),
271
                    new Authentication,
272
                    function ($request, $next) {
273
                        $this->assertInstanceOf('\ncryptf\Token', $request->getAttribute('ncryptf-token'));
274
                        $this->assertEquals(true, \is_array($request->getAttribute('ncryptf-user')));
275
                        return $next->handle($request);
276
                    },
277
                    new JsonResponseFormatter($cache, new EncryptionKey),
278
                    new EchoResponse,
279
                ],
280
                Factory::createServerRequest($params[0], $params[1])
281
                    ->withHeader('Authorization', $auth->getHeader())
282
                    ->withHeader('Content-Type', 'application/vnd.25519+json')
283
                    ->withHeader('Accept', 'application/vnd.25519+json')
284
                    ->withHeader('X-HashId', $serverKey->getHashIdentifier())
285
                    ->withHeader('X-Nonce', \base64_encode($nonce))
286
                    ->withHeader('X-PubKey', \base64_encode($myKey->getBoxPublicKey()))
287
                    ->withBody((function () use ($params, $serverKey, $myKey, $nonce, $token) {
288
                        $data = \is_array($params[2]) ? \json_encode($params[2]): $params[2];
289
290
                        $request = new Request(
291
                            $myKey->getBoxSecretKey(),
292
                            $token->signature
293
                        );
294
295
                        $encryptedData = $request->encrypt(
296
                            $data,
297
                            $serverKey->getBoxPublicKey(),
298
                            1,
299
                            $nonce
300
                        );
301
                        $stream = fopen('php://memory', 'r+');
302
                        fwrite($stream, $data === '' ? '' : \base64_encode($encryptedData));
0 ignored issues
show
Bug introduced by
It seems like $stream can also be of type false; however, parameter $handle of fwrite() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

302
                        fwrite(/** @scrutinizer ignore-type */ $stream, $data === '' ? '' : \base64_encode($encryptedData));
Loading history...
303
                        rewind($stream);
0 ignored issues
show
Bug introduced by
It seems like $stream can also be of type false; however, parameter $handle of rewind() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

303
                        rewind(/** @scrutinizer ignore-type */ $stream);
Loading history...
304
                        return new \Zend\Diactoros\Stream($stream);
0 ignored issues
show
Bug introduced by
It seems like $stream can also be of type false; however, parameter $stream of Zend\Diactoros\Stream::__construct() does only seem to accept resource|string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

304
                        return new \Zend\Diactoros\Stream(/** @scrutinizer ignore-type */ $stream);
Loading history...
305
                    })())
306
            );
307
308
            $this->assertSame(200, $response->getStatusCode());
309
            $this->assertSame('application/vnd.ncryptf+json', $response->getHeaderLine('Content-Type'));
310
            if ($params[2] !== '') {
311
                $this->assertTrue($response->hasHeader('x-hashid'));
312
                $this->assertTrue($response->hasHeader('x-signature'));
313
                $this->assertTrue($response->hasHeader('x-sigpubkey'));
314
                $this->assertTrue($response->hasHeader('x-nonce'));
315
                $this->assertTrue($response->hasHeader('x-pubkey'));
316
                $this->assertTrue($response->hasHeader('x-public-key-expiration'));
317
            }
318
319
            $r = new Response(
320
                $myKey->getBoxSecretKey()
321
            );
322
323
            $plaintext = $r->decrypt(
324
                \base64_decode((string)$response->getBody()),
325
                \base64_decode($response->getHeaderLine('x-pubkey')),
326
                \base64_decode($response->getHeaderLine('x-nonce'))
327
            );
328
329
            $this->assertEquals(\is_array($params[2]) ? \json_encode($params[2]) : $params[2], $plaintext);
330
        }
331
    }
332
333
    public function testPublicKeyExtraction()
334
    {
335
        $publicKey = Response::getPublicKeyFromResponse(\base64_decode($this->expectedv2Cipher));
336
        $this->assertEquals(\base64_decode($this->clientKeyPair['public']), $publicKey);
337
    }
338
339
    public function testVersion()
340
    {
341
        $this->assertEquals(1, Response::getVersion(\base64_decode($this->expectedCipher)));
342
        $this->assertEquals(2, Response::getVersion(\base64_decode($this->expectedv2Cipher)));
343
    }
344
}
345