Issues (224)

src/Console/Command/Verify.php (2 issues)

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 Fidry\Console\Command\Command;
18
use Fidry\Console\Command\Configuration;
19
use Fidry\Console\ExitCode;
20
use Fidry\Console\IO;
0 ignored issues
show
The type Fidry\Console\IO 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...
21
use KevinGH\Box\Phar\PharInfo;
22
use Symfony\Component\Console\Input\InputArgument;
23
use Symfony\Component\Filesystem\Path;
24
use Throwable;
25
use Webmozart\Assert\Assert;
26
use function realpath;
27
use function sprintf;
28
29
/**
30
 * @private
31
 */
32
final class Verify implements Command
33
{
34
    private const PHAR_ARG = 'phar';
35
36
    public function getConfiguration(): Configuration
37
    {
38
        return new Configuration(
39
            'verify',
40
            '🔐️  Verifies the PHAR signature',
41
            <<<'HELP'
42
                The <info>%command.name%</info> command will verify the signature of the PHAR.
43
44
                <question>Why would I require that box handle the verification process?</question>
45
46
                If you meet all the following conditions:
47
                 - The <comment>openssl</comment> extension is not installed
48
                 - You need to verify a PHAR signed using a private key
49
50
                Box supports verifying private key signed PHARs without using
51
                either extensions. <error>Note however, that the entire PHAR will need
52
                to be read into memory before the verification can be performed.</error>
53
                HELP,
54
            [
55
                new InputArgument(
56
                    self::PHAR_ARG,
57
                    InputArgument::REQUIRED,
58
                    'The PHAR file',
59
                ),
60
            ],
61
        );
62
    }
63
64
    public function execute(IO $io): int
65
    {
66
        $pharFilePath = self::getPharFilePath($io);
67
68
        $io->newLine();
69
        $io->writeln(
70
            sprintf(
71
                '🔐️  Verifying the PHAR "<comment>%s</comment>"',
72
                $pharFilePath,
73
            ),
74
        );
75
        $io->newLine();
76
77
        [$verified, $signature, $throwable] = self::verifyPhar($pharFilePath);
78
79
        if (false === $verified || false === $signature) {
80
            return self::failVerification($throwable, $io);
81
        }
82
83
        $io->writeln('<info>The PHAR passed verification.</info>');
84
85
        $io->newLine();
86
        $io->writeln(
87
            sprintf(
88
                '%s signature: <info>%s</info>',
89
                $signature['hash_type'],
90
                $signature['hash'],
91
            ),
92
        );
93
94
        return ExitCode::SUCCESS;
95
    }
96
97
    private static function getPharFilePath(IO $io): string
98
    {
99
        $pharPath = Path::canonicalize(
100
            $io->getTypedArgument(self::PHAR_ARG)->asNonEmptyString(),
101
        );
102
103
        Assert::file($pharPath);
104
105
        $pharRealPath = realpath($pharPath);
106
107
        return false === $pharRealPath ? $pharPath : $pharRealPath;
108
    }
109
110
    /**
111
     * @return array{bool, array{hash: string, hash_type:string}|false, Throwable|null}
0 ignored issues
show
Documentation Bug introduced by
The doc comment array{bool, array{hash: ...|false, Throwable|null} at position 2 could not be parsed: Expected ':' at position 2, but found 'bool'.
Loading history...
112
     */
113
    private static function verifyPhar(string $pharFilePath): array
114
    {
115
        $verified = false;
116
        $signature = false;
117
        $throwable = null;
118
119
        try {
120
            $pharInfo = new PharInfo($pharFilePath);
121
122
            $verified = true;
123
            $signature = $pharInfo->getSignature();
124
        } catch (Throwable $throwable) {
125
            // Continue
126
        }
127
128
        return [
129
            $verified,
130
            $signature,
131
            $throwable,
132
        ];
133
    }
134
135
    private static function failVerification(?Throwable $throwable, IO $io): int
136
    {
137
        $message = null !== $throwable && '' !== $throwable->getMessage()
138
            ? $throwable->getMessage()
139
            : 'Unknown reason.';
140
141
        $io->writeln(
142
            sprintf(
143
                '<error>The PHAR failed the verification: %s</error>',
144
                $message,
145
            ),
146
        );
147
148
        if (null !== $throwable && $io->isDebug()) {
149
            throw $throwable;
150
        }
151
152
        return ExitCode::FAILURE;
153
    }
154
}
155