Issues (10)

src/Console/ShareCommand.php (1 issue)

1
<?php
2
3
namespace TQ\Shamir\Console;
4
5
use Symfony\Component\Console\Command\Command;
6
use Symfony\Component\Console\Helper\FormatterHelper;
7
use Symfony\Component\Console\Helper\QuestionHelper;
8
use Symfony\Component\Console\Input\InputArgument;
9
use Symfony\Component\Console\Input\InputInterface;
10
use Symfony\Component\Console\Input\InputOption;
11
use Symfony\Component\Console\Output\OutputInterface;
12
use Symfony\Component\Console\Question\Question;
13
use TQ\Shamir\Secret;
14
use UnexpectedValueException;
15
16
class ShareCommand extends Command
17
{
18
    /**
19
     * @inheritdoc
20
     */
21
    protected function configure(): void
22
    {
23
        $this->setName('shamir:share')->setDescription('Create a shared secret')->addArgument(
24
            'secret',
25
            InputArgument::OPTIONAL,
26
            'The secret to share'
27
        )->addOption(
28
            'file',
29
            'f',
30
            InputOption::VALUE_OPTIONAL,
31
            'File containing secret'
32
        )->addOption(
33
            'shares',
34
            's',
35
            InputOption::VALUE_OPTIONAL,
36
            'The number of shared secrets to generate',
37
            3
38
        )->addOption(
39
            'threshold',
40
            't',
41
            InputOption::VALUE_OPTIONAL,
42
            'The minimum number of shared secrets required to recover',
43
            2
44
        );
45
    }
46
47
    /**
48
     * @inheritdoc
49
     */
50
    protected function execute(InputInterface $input, OutputInterface $output): int
51
    {
52
        $secret = $this->readFile($input, $output);
53
54
        if ($secret === null) {
55
            $secret = $input->getArgument('secret');
56
        }
57
58
        if (empty($secret)) {
59
            /** @var QuestionHelper $dialog */
60
            $helper = $this->getHelper('question');
61
62
            $question = new Question('<question>The secret to share</question>: ');
63
            $secret   = $helper->ask($input, $output, $question);
64
65
            $question = new Question(
66
                '<question>Number of shared secrets to create</question> <comment>[3]</comment>: ', 3
67
            );
68
            $question->setValidator(
69
                static function ($a) {
70
                    if (!is_int($a) && !ctype_digit($a)) {
71
                        throw new UnexpectedValueException('The number of shared secrets must be an integer');
72
                    }
73
74
                    return (int)$a;
75
                }
76
            );
77
            $shares = $helper->ask($input, $output, $question);
78
79
            $question = new Question(
80
                '<question>Number of shared secrets required</question> <comment>[2]</comment>: ', 2
81
            );
82
            $question->setValidator(
83
                function ($a) {
84
                    if (!is_int($a) && !ctype_digit($a)) {
85
                        throw new UnexpectedValueException('The number of shared secrets required must be an integer');
86
                    }
87
88
                    return (int)$a;
89
                }
90
            );
91
            $threshold = $helper->ask($input, $output, $question);
92
        } else {
93
            $shares    = $input->getOption('shares');
94
            $threshold = $input->getOption('threshold');
95
        }
96
97
        $shared = Secret::share($secret, $shares, $threshold);
98
99
        /** @var FormatterHelper $formatter */
100
        $formatter = $this->getHelper('formatter');
101
        $block     = $formatter->formatBlock($shared, 'info');
102
        $output->writeln($block);
103
104
        return 0;
105
    }
106
107
    /**
108
     * Check STDIN or file option for input of secret
109
     */
110
    protected function readFile(InputInterface $input, OutputInterface $output): ?string
111
    {
112
        $secret = null;
113
114
        $file = $input->getOption('file');
115
116
        if ($file !== null) {
117
            # check for secret in file
118
            if (!is_readable($file)) {
119
                $output->writeln('<error>ERROR: file "'.$file.'" is not readable.');
120
                exit(1);
0 ignored issues
show
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
121
            }
122
123
            $secret = file_get_contents($file);
124
        } else {
125
            # check if data is given by STDIN
126
            $readStreams   = [STDIN];
127
            $writeStreams  = [];
128
            $exceptStreams = [];
129
            $streamCount   = stream_select($readStreams, $writeStreams, $exceptStreams, 0);
130
131
            if ($streamCount === 1) {
132
                while (!feof(STDIN)) {
133
                    $secret .= fread(STDIN, 1024);
134
                }
135
            }
136
        }
137
138
        return $secret;
139
    }
140
}
141