Passed
Pull Request — master (#400)
by Théo
03:00
created

Verify::execute()   C

Complexity

Conditions 10
Paths 180

Size

Total Lines 70
Code Lines 41

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 41
dl 0
loc 70
rs 6.9999
c 0
b 0
f 0
cc 10
nc 180
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
 * This file is part of the box project.
7
 *
8
 * (c) Kevin Herrera <[email protected]>
9
 *     Théo Fidry <[email protected]>
10
 *
11
 * This source file is subject to the MIT license that is bundled
12
 * with this source code in the file LICENSE.
13
 */
14
15
namespace KevinGH\Box\Console\Command;
16
17
use Assert\Assertion;
18
use function file_exists;
19
use KevinGH\Box\Console\IO\IO;
20
use function KevinGH\Box\create_temporary_phar;
21
use function KevinGH\Box\FileSystem\copy;
22
use function KevinGH\Box\FileSystem\remove;
23
use Phar;
24
use function realpath;
25
use function sprintf;
26
use Symfony\Component\Console\Input\InputArgument;
27
use Throwable;
28
29
/**
30
 * @private
31
 */
32
final class Verify extends BaseCommand
33
{
34
    private const PHAR_ARG = 'phar';
35
36
    /**
37
     * {@inheritdoc}
38
     */
39
    protected function configure(): void
40
    {
41
        $this->setName('verify');
42
        $this->setDescription('🔐️  Verifies the PHAR signature');
43
        $this->setHelp(
44
            <<<'HELP'
45
The <info>%command.name%</info> command will verify the signature of the PHAR.
46
47
<question>Why would I require that box handle the verification process?</question>
48
49
If you meet all of the following conditions:
50
 - The <comment>openssl</comment> extension is not installed
51
 - You need to verify a PHAR signed using a private key
52
53
Box supports verifying private key signed PHARs without using
54
either extensions. <error>Note however, that the entire PHAR will need
55
to be read into memory before the verification can be performed.</error>
56
HELP
57
        );
58
        $this->addArgument(
59
            self::PHAR_ARG,
60
            InputArgument::REQUIRED,
61
            'The PHAR file'
62
        );
63
    }
64
65
    /**
66
     * {@inheritdoc}
67
     */
68
    protected function executeCommand(IO $io): int
69
    {
70
        $pharPath = $io->getInput()->getArgument(self::PHAR_ARG);
71
72
        Assertion::file($pharPath);
0 ignored issues
show
Bug introduced by
It seems like $pharPath can also be of type string[]; however, parameter $value of Assert\Assertion::file() 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

72
        Assertion::file(/** @scrutinizer ignore-type */ $pharPath);
Loading history...
73
74
        $pharPath = false !== realpath($pharPath) ? realpath($pharPath) : $pharPath;
75
76
        $io->newLine();
77
        $io->writeln(
78
            sprintf(
79
                '🔐️  Verifying the PHAR "<comment>%s</comment>"',
80
                $pharPath
81
            )
82
        );
83
        $io->newLine();
84
85
        $tmpPharPath = create_temporary_phar($pharPath);
86
87
        if (file_exists($pharPubKey = $pharPath.'.pubkey')) {
88
            copy($pharPubKey, $tmpPharPath.'.pubkey');
89
        }
90
91
        $verified = false;
92
        $signature = null;
93
        $throwable = null;
94
95
        try {
96
            $phar = new Phar($tmpPharPath);
97
98
            $verified = true;
99
            $signature = $phar->getSignature();
100
        } catch (Throwable $throwable) {
101
            // Continue
102
        } finally {
103
            remove($tmpPharPath);
104
        }
105
106
        if (false === $verified || null === $signature) {
107
            return $this->failVerification($throwable, $io);
108
        }
109
110
        $io->writeln('<info>The PHAR passed verification.</info>');
111
112
        $io->newLine();
113
        $io->writeln(
114
            sprintf(
115
                '%s signature: <info>%s</info>',
116
                $signature['hash_type'],
117
                $signature['hash']
118
            )
119
        );
120
121
        return 0;
122
    }
123
124
    private function failVerification(?Throwable $throwable, IO $io): int
125
    {
126
        $message = null !== $throwable && '' !== $throwable->getMessage()
127
            ? $throwable->getMessage()
128
            : 'Unknown reason.'
129
        ;
130
131
        $io->writeln(
132
            sprintf(
133
                '<error>The PHAR failed the verification: %s</error>',
134
                $message
135
            )
136
        );
137
138
        if (null !== $throwable && $io->isDebug()) {
139
            throw $throwable;
140
        }
141
142
        return 1;
143
    }
144
}
145