Failed Conditions
Push — v7 ( 1e67af...6a6683 )
by Florent
02:18
created

KeysetAnalyzerCommand::execute()   C

Complexity

Conditions 11
Paths 30

Size

Total Lines 53
Code Lines 35

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 53
rs 6.2926
c 0
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\Console\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
70
                    break;
71
                case in_array($jwk->get('kty'), ['RSA', 'EC', 'OKP']):
72
                    if ($jwk->has('d')) {
73
                        ++$privateKeys;
74
                        if (0 !== $sharedKeys + $publicKeys) {
75
                            $mixedKeys = true;
76
                        }
77
                    } else {
78
                        ++$publicKeys;
79
                        if (0 !== $privateKeys + $sharedKeys) {
80
                            $mixedKeys = true;
81
                        }
82
                    }
83
84
                    break;
85
                default:
86
                    break;
87
            }
88
        }
89
90
        if ($mixedKeys) {
91
            $output->writeln('/!\\ This key set mixes share, public and private keys. You should create one key set per key type. /!\\');
92
        }
93
    }
94
95
    /**
96
     * @param InputInterface $input
97
     *
98
     * @return JWKSet
99
     */
100
    private function getKeyset(InputInterface $input): JWKSet
101
    {
102
        $jwkset = $input->getArgument('jwkset');
103
        $json = json_decode($jwkset, true);
104
        if (is_array($json)) {
105
            return JWKSet::createFromKeyData($json);
106
        } elseif ($this->getContainer()->has($jwkset)) {
107
            $id = $this->getContainer()->get($jwkset);
108
            if ($id instanceof JWKSet) {
109
                return $id;
110
            }
111
        }
112
113
        throw new \InvalidArgumentException('The argument must be a valid JWKSet or a service ID to a JWKSet.');
114
    }
115
}
116