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

JsonResponseFormatter::process()   B

Complexity

Conditions 9
Paths 5

Size

Total Lines 51
Code Lines 34

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 34
dl 0
loc 51
rs 8.0555
c 0
b 0
f 0
cc 9
nc 5
nop 2

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php declare(strict_types=1);
2
3
namespace ncryptf\middleware;
4
5
use Exception;
6
7
use ncryptf\Request;
8
9
use Psr\SimpleCache\CacheInterface;
10
use Psr\Http\Message\StreamInterface;
11
use Psr\Http\Message\MessageInterface;
12
use Psr\Http\Message\ResponseInterface;
13
14
use Psr\Http\Server\MiddlewareInterface;
15
use Fig\Http\Message\StatusCodeInterface;
0 ignored issues
show
Bug introduced by
The type Fig\Http\Message\StatusCodeInterface was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
16
use Psr\Http\Message\ServerRequestInterface;
17
use Psr\Http\Server\RequestHandlerInterface;
18
use Psr\SimpleCache\InvalidArgumentException;
19
20
use ncryptf\middleware\EncryptionKeyInterface;
21
22
final class JsonResponseFormatter implements MiddlewareInterface
23
{
24
    const ENCODING_OPTIONS = JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_PRESERVE_ZERO_FRACTION;
25
26
    /**
27
     * @var EncryptionKeyInterface $key
28
     */
29
    protected $key;
30
31
    /**
32
     * @var CacheInterface $cache
33
     */
34
    protected $cache;
35
36
    /**
37
     * @var array $contentType
38
     */
39
    protected $contentType = [
40
        'application/vnd.25519+json',
41
        'application/vnd.ncryptf+json'
42
    ];
43
44
    /**
45
     * Constructor
46
     * @param EncryptionKeyInterface $key
47
     */
48
    public function __construct(CacheInterface $cache, EncryptionKeyInterface $key)
49
    {
50
        $this->cache = $cache;
51
        $this->key = $key;
52
    }
53
54
    /**
55
     * Processes the request
56
     * @param ServerRequestInterface $request
57
     * @param RequestHandlerInterface $handler
58
     */
59
    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
60
    {
61
        if ($this->checkRequest($request)) {
62
            $response = $handler->handle($request);
63
            $version = $request->getAttribute('ncryptf-version');
64
            $publicKey = $request->getAttribute('ncryptf-request-public-key');
65
            $token = $request->getAttribute('ncryptf-token');
66
            
67
            if ($version === null || $publicKey === null) {
68
                return $response->withStatus(400, 'Unable to encrypt request.');
69
            }
70
71
            if (!($response instanceof MessageInterface)) {
0 ignored issues
show
introduced by
$response is always a sub-type of Psr\Http\Message\MessageInterface.
Loading history...
72
                throw new Exception('Response does not implement MessageInterface.');
73
            }
74
75
            $stream = $response->getBody();
76
            $class = $this->key;
77
            $key = $class::generate();
78
            
79
            $this->cache->set($key->getHashIdentifier(), $key);
80
81
            $r = new Request(
82
                $key->getBoxSecretKey(),
83
                $token === null ? $key->getSignSecretKey() : $token->signature
84
            );
85
86
            $content = $r->encrypt(
87
                (string)$stream,
88
                $publicKey,
89
                $version,
90
                $version === 2 ? null : \random_bytes(SODIUM_CRYPTO_BOX_NONCEBYTES)
91
            );
92
93
            if ($version === 1) {
94
                $response = $response->withHeader('x-sigpubkey', \base64_encode($token === null ? $key->getSignPublicKey() : $token->getSignaturePublicKey()))
95
                    ->withHeader('x-signature', \base64_encode($r->sign((string)$stream)))
96
                    ->withHeader('x-public-key-expiration', $key->getPublicKeyExpiration())
97
                    ->withHeader('x-nonce', \base64_encode($r->getNonce()))
98
                    ->withHeader('x-pubkey', \base64_encode($key->getBoxPublicKey()));
99
            }
100
101
            $stream->rewind();
102
            $stream->write(\base64_encode($content));
103
            return $response->withBody($stream)
104
                ->withHeader('Content-Type', 'application/vnd.ncryptf+json')
105
                ->withHeader('x-hashid', \base64_encode($key->getHashIdentifier()));
106
        }
107
108
        return $handler->handle($request)
109
            ->withHeader('Content-Type', 'application/vnd.ncryptf+json');
110
    }
111
112
    /**
113
     * Check whether the request payload need to be processed
114
     * @param ServerRequestInterface $request
115
     * @return bool
116
     */
117
    private function checkRequest(ServerRequestInterface $request): bool
118
    {
119
        $contentType = $request->getHeaderLine('Accept');
120
        foreach ($this->contentType as $allowedType) {
121
            if (\stripos($contentType, $allowedType) === 0) {
122
                return true;
123
            }
124
        }
125
        return false;
126
    }
127
}
128