Completed
Push — master ( 1796d9...540fa6 )
by Oliver
15:02
created

ShareCommand::readFile()   A

Complexity

Conditions 5
Paths 5

Size

Total Lines 30

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 30

Importance

Changes 0
Metric Value
dl 0
loc 30
ccs 0
cts 11
cp 0
rs 9.1288
c 0
b 0
f 0
cc 5
nc 5
nop 2
crap 30
1
<?php
2
/**
3
 * Created by PhpStorm.
4
 * User: stefan
5
 * Date: 21.09.14
6
 * Time: 10:28
7
 */
8
9
namespace TQ\Shamir\Console;
10
11
use Symfony\Component\Console\Command\Command;
12
use Symfony\Component\Console\Helper\FormatterHelper;
13
use Symfony\Component\Console\Helper\QuestionHelper;
14
use Symfony\Component\Console\Input\InputArgument;
15
use Symfony\Component\Console\Input\InputInterface;
16
use Symfony\Component\Console\Input\InputOption;
17
use Symfony\Component\Console\Output\OutputInterface;
18
use Symfony\Component\Console\Question\Question;
19
use TQ\Shamir\Secret;
20
use UnexpectedValueException;
21
22
class ShareCommand extends Command
23
{
24
    /**
25
     * @inheritdoc
26
     */
27
    protected function configure(): void
28
    {
29
        $this->setName('shamir:share')->setDescription('Create a shared secret')->addArgument(
30
            'secret',
31
            InputArgument::OPTIONAL,
32
            'The secret to share'
33
        )->addOption(
34
            'file',
35
            'f',
36
            InputOption::VALUE_OPTIONAL,
37
            'File containing secret'
38
        )->addOption(
39
            'shares',
40
            's',
41
            InputOption::VALUE_OPTIONAL,
42
            'The number of shared secrets to generate',
43
            3
44
        )->addOption(
45
            'threshold',
46
            't',
47
            InputOption::VALUE_OPTIONAL,
48
            'The minimum number of shared secrets required to recover',
49
            2
50
        );
51
    }
52
53
    /**
54
     * @inheritdoc
55
     */
56
    protected function execute(InputInterface $input, OutputInterface $output): int
57
    {
58
        $secret = $this->readFile($input, $output);
59
60
        if ($secret === null) {
61
            $secret = $input->getArgument('secret');
62
        }
63
64
        if (empty($secret)) {
65
            /** @var QuestionHelper $dialog */
66
            $helper = $this->getHelper('question');
67
68
            $question = new Question('<question>The secret to share</question>: ');
69
            $secret   = $helper->ask($input, $output, $question);
70
71
            $question = new Question(
72
                '<question>Number of shared secrets to create</question> <comment>[3]</comment>: ', 3
73
            );
74
            $question->setValidator(
75
                static function ($a) {
76
                    if (!is_int($a) && !ctype_digit($a)) {
77
                        throw new UnexpectedValueException('The number of shared secrets must be an integer');
78
                    }
79
80
                    return (int)$a;
81
                }
82
            );
83
            $shares = $helper->ask($input, $output, $question);
84
85
            $question = new Question(
86
                '<question>Number of shared secrets required</question> <comment>[2]</comment>: ', 2
87
            );
88
            $question->setValidator(
89
                function ($a) {
90
                    if (!is_int($a) && !ctype_digit($a)) {
91
                        throw new UnexpectedValueException('The number of shared secrets required must be an integer');
92
                    }
93
94
                    return (int)$a;
95
                }
96
            );
97
            $threshold = $helper->ask($input, $output, $question);
98
        } else {
99
            $shares    = $input->getOption('shares');
100
            $threshold = $input->getOption('threshold');
101
        }
102
103
        $shared = Secret::share($secret, $shares, $threshold);
104
105
        /** @var FormatterHelper $formatter */
106
        $formatter = $this->getHelper('formatter');
107
        $block     = $formatter->formatBlock($shared, 'info', true);
108
        $output->writeln($block);
109
110
        return 0;
111
    }
112
113
    /**
114
     * Check STDIN or file option for input of secret
115
     *
116
     * @param  InputInterface   $input
117
     * @param  OutputInterface  $output
118
     * @return string|null
119
     */
120
    protected function readFile(InputInterface $input, OutputInterface $output): ?string
121
    {
122
        $secret = null;
123
124
        # check if data is given by STDIN
125
        $readStreams   = [STDIN];
126
        $writeStreams  = [];
127
        $exceptStreams = [];
128
        $streamCount   = stream_select($readStreams, $writeStreams, $exceptStreams, 0);
129
130
        if ($streamCount === 1) {
131
            while (!feof(STDIN)) {
132
                $secret .= fread(STDIN, 1024);
133
            }
134
        } else {
135
            $file = $input->getOption('file');
136
137
            if ($file !== null) {
138
                # check for secret in file
139
                if (!is_readable($file)) {
140
                    $output->writeln('<error>ERROR: file "'.$file.'" is not readable.');
141
                    exit(1);
142
                }
143
144
                $secret = file_get_contents($file);
145
            }
146
        }
147
148
        return $secret;
149
    }
150
}
151