JsonResponseFormatter::formatJson()   C
last analyzed

Complexity

Conditions 13
Paths 36

Size

Total Lines 82
Code Lines 55

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 13
eloc 55
nc 36
nop 1
dl 0
loc 82
rs 6.6166
c 0
b 0
f 0

How to fix   Long Method    Complexity   

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 yrc\web\ncryptf;
4
5
use ncryptf\Request;
6
use ncryptf\Response;
7
use yrc\models\redis\EncryptionKey;
8
use yii\web\NotAcceptableHttpException;
9
use yii\web\HttpException;
10
use Yii;
11
12
use Exception;
13
14
class JsonResponseFormatter extends \yrc\web\JsonResponseFormatter
15
{
16
    /**
17
     * Take the response generated by JsonResponseFormatter and encrypt it
18
     * @param array $response
19
     */
20
    protected function formatJson($response)
21
    {
22
        // Generate a new encryption key
23
        $key = EncryptionKey::generate();
24
        $request = Yii::$app->request;
0 ignored issues
show
Documentation Bug introduced by
It seems like Yii::app->request can also be of type yii\web\Request. However, the property $request is declared as type yii\console\Request. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
25
        if ($request->method === 'GET' && $request->getRawBody() === '' && $request->getHeaders()->get('Content-Type') === 'application/json') {
26
            $headerExtractionVersion = 1;
27
        } else {
28
            $headerExtractionVersion = Response::getVersion(\base64_decode($request->getRawBody()));
29
        }
30
31
        $headers = $response->getHeaders();
32
33
        if ($headerExtractionVersion === 2) {
34
            $rawPublic = Response::getPublicKeyFromResponse(\base64_decode($request->getRawBody()));
35
            $version = 2;
36
        } else {
37
            $public = $request->getHeaders()->get('x-pubkey', null);
38
            $version = 1;
39
40
            if ($public === null) {
0 ignored issues
show
introduced by
The condition $public === null is always false.
Loading history...
41
                $response->statusCode = 400;
42
                $response->content = '';
43
                $response->getHeaders('x-reason', Yii::t('yrc', 'Accept: application/vnd.ncryptf+json requires x-pubkey header to be set.'));
44
                return;
45
            }
46
47
            $rawPublic = \base64_decode($public);
0 ignored issues
show
Bug introduced by
It seems like $public can also be of type array; however, parameter $data of base64_decode() does only seem to accept 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

47
            $rawPublic = \base64_decode(/** @scrutinizer ignore-type */ $public);
Loading history...
48
            if (strlen($rawPublic) !== 32) {
49
                $response->statusCode = 400;
50
                $headers->set('x-reason', Yii::t('yrc', 'Public key is not 32 bytes in length.'));
51
                return;
52
            }
53
        }
54
55
        // Upgrade GET request with empty bodies
56
        if ($request->method === 'GET' && $request->getRawBody() === '') {
57
            $version = 2;
58
        }
59
60
        parent::formatJson($response);
0 ignored issues
show
Bug introduced by
$response of type array is incompatible with the type yrc\web\Response expected by parameter $response of yrc\web\JsonResponseFormatter::formatJson(). ( Ignorable by Annotation )

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

60
        parent::formatJson(/** @scrutinizer ignore-type */ $response);
Loading history...
61
        $headers->set('Content-Type', 'application/vnd.ncryptf+json; charset=UTF-8');
62
63
        if (!Yii::$app->user->isGuest) {
64
            $token = Yii::$app->user->getIdentity()->getToken();
0 ignored issues
show
Bug introduced by
The method getIdentity() does not exist on null. ( Ignorable by Annotation )

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

64
            $token = Yii::$app->user->/** @scrutinizer ignore-call */ getIdentity()->getToken();

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
65
66
            if ($token === null) {
67
                $response->statusCode = 406;
68
                $response->content = '';
69
                Yii::warning([
70
                    'message' => 'Could not fetch token keypair. Unable to generate encrypted response.'
71
                ], 'yrc');
72
                return;
73
            }
74
75
            $r = new Request(
76
                $key->getBoxSecretKey(),
77
                \base64_decode($token->secret_sign_kp)
78
            );
79
80
            $nonce = \random_bytes(SODIUM_CRYPTO_BOX_NONCEBYTES);
81
82
            $content = $r->encrypt(
83
                $response->content,
84
                $rawPublic,
85
                $version,
86
                $version === 2 ? null : $nonce
87
            );
88
89
            if ($version === 1) {
90
                $signature = $r->sign($response->content);
91
                // Sign the raw response and send the signature alongside the header
92
                $headers->set('x-sigpubkey', \base64_encode($token->getSignPublicKey()));
93
                $headers->set('x-signature', \base64_encode($signature));
94
                $headers->set('x-pubkey-expiration', $key->getPublicKeyExpiration());
95
                $headers->set('x-nonce', \base64_encode($nonce));
96
                $headers->set('x-pubkey', \base64_encode($key->getBoxPublicKey()));
97
            }
98
99
            $headers->set('x-hashid', $key->hash);
100
            $response->content = \base64_encode($content);
101
            return;
102
        }
103
    }
104
}
105