Failed Conditions
Push — v7 ( 859ab9...badffc )
by Florent
02:23
created

KeysetAnalyzerCommand::execute()   C

Complexity

Conditions 11
Paths 30

Size

Total Lines 51
Code Lines 35

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
dl 0
loc 51
rs 5.7333
c 1
b 0
f 0
cc 11
eloc 35
nc 30
nop 2

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
2
3
declare(strict_types=1);
4
5
/*
6
 * The MIT License (MIT)
7
 *
8
 * Copyright (c) 2014-2017 Spomky-Labs
9
 *
10
 * This software may be modified and distributed under the terms
11
 * of the MIT license.  See the LICENSE file for details.
12
 */
13
14
namespace Jose\Bundle\KeyManagement\Command;
15
16
use Jose\Component\Core\JWKSet;
17
use Jose\Component\KeyManagement\KeyAnalyzer\JWKAnalyzerManager;
18
use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand;
19
use Symfony\Component\Console\Input\InputArgument;
20
use Symfony\Component\Console\Input\InputInterface;
21
use Symfony\Component\Console\Output\OutputInterface;
22
23
final class KeysetAnalyzerCommand extends ContainerAwareCommand
24
{
25
    /**
26
     * {@inheritdoc}
27
     */
28
    protected function configure()
29
    {
30
        $this
31
            ->setName('keyset:analyze')
32
            ->setDescription('JWKSet quality analyzer.')
33
            ->setHelp('This command will analyze a JWKSet object and find security issues.')
34
            ->addArgument('jwkset', InputArgument::REQUIRED, 'The JWKSet object')
35
        ;
36
    }
37
38
    /**
39
     * {@inheritdoc}
40
     */
41
    protected function execute(InputInterface $input, OutputInterface $output)
42
    {
43
        /** @var JWKAnalyzerManager $analyzerManager */
44
        $analyzerManager = $this->getContainer()->get(JWKAnalyzerManager::class);
45
        $jwkset = $this->getKeyset($input);
46
47
        $privateKeys = 0;
48
        $publicKeys = 0;
49
        $sharedKeys = 0;
50
        $mixedKeys = false;
51
52
        foreach($jwkset as $kid => $jwk) {
53
            $output->writeln(sprintf('Analysing key with index/kid "%s"', $kid));
54
            $messages = $analyzerManager->analyze($jwk);
0 ignored issues
show
Bug introduced by
It seems like $jwk defined by $jwk on line 52 can be null; however, Jose\Component\KeyManage...lyzerManager::analyze() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
55
            if (!empty($messages)) {
56
                foreach ($messages as $message) {
57
                    $output->writeln('    '.$message);
58
                }
59
            } else {
60
                $output->writeln('    No issue with this key');
61
            }
62
63
            switch (true) {
64
                case 'oct' === $jwk->get('kty'):
65
                    $sharedKeys++;
66
                    if (0 !== $privateKeys+$publicKeys) {
67
                        $mixedKeys = true;
68
                    }
69
                    break;
70
                case in_array($jwk->get('kty'), ['RSA', 'EC', 'OKP']):
71
                    if ($jwk->has('d')) {
72
                        $privateKeys++;
73
                        if (0 !== $sharedKeys+$publicKeys) {
74
                            $mixedKeys = true;
75
                        }
76
                    } else {
77
                        $publicKeys++;
78
                        if (0 !== $privateKeys+$sharedKeys) {
79
                            $mixedKeys = true;
80
                        }
81
                    }
82
                    break;
83
                default:
84
                    break;
85
            }
86
        }
87
88
        if ($mixedKeys) {
89
            $output->writeln('/!\\ This key set mixes share, public and private keys. You should create one key set per key type. /!\\');
90
        }
91
    }
92
93
    /**
94
     * @param InputInterface $input
95
     *
96
     * @return JWKSet
97
     */
98
    private function getKeyset(InputInterface $input): JWKSet
99
    {
100
        $jwkset = $input->getArgument('jwkset');
101
        $json = json_decode($jwkset, true);
102
        if (is_array($json)) {
103
            return JWKSet::createFromKeyData($json);
104
        } elseif ($this->getContainer()->has($jwkset)) {
105
            $id = $this->getContainer()->get($jwkset);
106
            if ($id instanceof JWKSet) {
107
                return $id;
108
            }
109
        }
110
111
        throw new \InvalidArgumentException('The argument must be a valid JWKSet or a service ID to a JWKSet.');
112
    }
113
}
114