Completed
Push — master ( 2bc6ba...1ab902 )
by Francesco
09:17
created

KeyGeneratorCommand::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 6
ccs 4
cts 4
cp 1
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 3
nc 1
nop 1
crap 1
1
<?php
2
3
/*
4
 * This file is part of the MesCryptoBundle package.
5
 *
6
 * (c) Francesco Cartenì <http://www.multimediaexperiencestudio.it/>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace Mes\Security\CryptoBundle\Command;
13
14
use Mes\Security\CryptoBundle\KeyGenerator\KeyGenerator;
15
use Mes\Security\CryptoBundle\Utils\SecretGenerator;
16
use Psr\Log\LogLevel;
17
use Symfony\Component\Console\Helper\DebugFormatterHelper;
18
use Symfony\Component\Console\Helper\QuestionHelper;
19
use Symfony\Component\Console\Input\InputDefinition;
20
use Symfony\Component\Console\Input\InputInterface;
21
use Symfony\Component\Console\Input\InputOption;
22
use Symfony\Component\Console\Output\OutputInterface;
23
use Symfony\Component\Console\Question\ConfirmationQuestion;
24
use Symfony\Component\Console\Question\Question;
25
use Symfony\Component\Filesystem\Filesystem;
26
use Symfony\Component\Process\Process;
27
28
/**
29
 * Class KeyGeneratorCommand.
30
 */
31
class KeyGeneratorCommand extends AbstractCommand
32
{
33
    private $secret;
34
    private $wantsToSaveSecret;
35
36
    /**
37
     * @var QuestionHelper
38
     */
39
    private $helper;
40
41
    /**
42
     * @var SecretGenerator
43
     */
44
    private $generator;
45
46
    /**
47
     * KeyGeneratorCommand constructor.
48
     *
49
     * @param SecretGenerator $generator
50
     */
51 3
    public function __construct(SecretGenerator $generator)
52
    {
53 3
        $this->generator = $generator;
54
55 3
        parent::__construct();
56 3
    }
57
58
    /**
59
     * {@inheritdoc}
60
     */
61 3
    protected function initialize(InputInterface $input, OutputInterface $output)
62
    {
63 3
        parent::initialize($input, $output);
64
65 3
        $this->helper = $this->getHelperSet()
66 3
                             ->get('question');
67
68 3
        $this->symfonyStyle = $this->getStyle($input, $output);
69 3
    }
70
71
    /**
72
     * {@inheritdoc}
73
     */
74 3
    protected function configure()
75
    {
76 3
        $this->setName('mes:crypto:generate-key')
77 3
             ->setDefinition($this->createDefinition())
78 3
             ->setDescription('Generates an encoded key with or without authentication secret')
79 3
             ->setHelp(<<<'EOF'
80 3
The <info>%command.name%</info> generates an encoded key with or without authentication secret and optionally it saves the printable key and the secret in a ini format .crypto file.
81
82
<info>%command.full_name%</info>
83
84
or
85
86
<info>%command.full_name%</info> --dir /path/to/dir/key.crypto
87
EOF
88
             );
89 3
    }
90
91
    /**
92
     * {@inheritdoc}
93
     */
94 3
    protected function interact(InputInterface $input, OutputInterface $output)
95
    {
96 3
        $dir = $input->getOption('dir');
97
98 3
        $this->writeSection($output, 'Welcome to the Key Generator');
99
100 3
        $question = new ConfirmationQuestion($this->getQuestion('Do you want to generate a key with an authentication secret?', 'yes'), true);
101 3
        $wantsToGenerateSecret = $this->helper->ask($input, $output, $question);
102
103 3
        if ($wantsToGenerateSecret) {
104 3
            $random = $this->generator->generateRandomSecret();
105 3
            $this->symfonyStyle->newLine();
106 3
            $question = new Question($this->getQuestion('Insert your authentication secret or use this one randomly generated', $random), $random);
107
            $question->setValidator(function ($secret) {
108 3
                if (!ctype_print($secret)) {
109 1
                    throw new \RuntimeException(sprintf('The authentication secret is not printable', $secret));
110
                }
111
112 3
                return $secret;
113 3
            });
114 3
            $this->secret = $this->helper->ask($input, $output, $question);
115
116 3
            if (null !== $dir) {
117 1
                $this->symfonyStyle->newLine();
118 1
                $question = new ConfirmationQuestion($this->getQuestion(sprintf('Do you want to save this authentication secret in <comment>%s</comment> as well?', $dir), 'yes'), true);
119 1
                $this->wantsToSaveSecret = $this->helper->ask($input, $output, $question);
120
            }
121
        }
122
123
        // Summary
124 3
        $output->writeln(array(
125 3
            '',
126 3
            $this->createBlock('Summary before key generation', 'bg=blue;fg-white'),
127 3
            '',
128 3
            $this->secret ? sprintf('You are going to generate a key with <info>%s</info> authentication secret %s', $this->secret, $dir ? "in <info>$dir</info>" : '') : sprintf('You are going to generate a key without authentication secret %s', $dir ? "in <info>$dir</info>" : ''),
129
        ));
130 3
    }
131
132
    /**
133
     * {@inheritdoc}
134
     */
135 3
    protected function execute(InputInterface $input, OutputInterface $output)
136
    {
137 3
        $logger = $this->getLogger($output);
138 3
        $dir = $input->getOption('dir');
139 3
        $secret = $this->secret;
140
141
        // Conditions
142 3
        $secretIsExternalCondition = (true === $this->wantsToSaveSecret);
143
144 3
        if ($input->isInteractive()) {
145 3
            $this->symfonyStyle->newLine();
146 3
            $question = new ConfirmationQuestion($this->getQuestion('Do you confirm key generation?', 'yes'), true);
147 3
            if (!($this->helper->ask($input, $output, $question))) {
148 1
                $this->symfonyStyle->newLine();
149 1
                $this->symfonyStyle->error('Command aborted');
150
151 1
                return 1;
152
            }
153
        }
154
155 1
        if ($dir) {
156 1
            $this->log($logger, "The encoded key will be saved in {$dir}\n", LogLevel::INFO);
157
        }
158
159 1
        if ($secret) {
160 1
            $this->log($logger, "The encoded key will be generated with secret: {$secret}\n", LogLevel::INFO);
161
        }
162
163 1
        $keyGenerator = new KeyGenerator();
164
165 1
        $this->writeSection($output, 'Generating key'.($secret ? ' with authentication secret' : '').($dir ? " in $dir" : ''));
166
167 1
        $encodedKey = $keyGenerator->generate($secret)
168 1
                                   ->getEncoded();
169
170 1
        $this->log($logger, "The encoded key has been generated with the following sequence:\n{$encodedKey}\n", LogLevel::INFO);
171
172 1
        if (null !== $dir) {
173 1
            $secretLine = null;
174 1
            if ($secretIsExternalCondition) {
175
                $secretLine = <<<EOT
176 1
secret = $secret
177
EOT;
178
            }
179
180 1
            $f = new Filesystem();
181 1
            $filename = basename($dir);
182 1
            $f->dumpFile($dir, <<<EOT
183 1
; $filename
184
[crypto]
185 1
key = $encodedKey
186 1
$secretLine
187
EOT
188
            );
189
190 1
            $this->log($logger, "The encoded key saved in {$dir}\n", LogLevel::INFO);
191
        }
192
193 1
        $this->writeResults($output, array(
194 1
            'key' => $encodedKey,
195 1
            'dir' => $dir,
196 1
            'secret' => $secret,
197
        ));
198
199 1
        $this->log($logger, 'The key generation process has been completed.', LogLevel::INFO);
200
201 1
        return 0;
202
    }
203
204
    /**
205
     * {@inheritdoc}
206
     */
207 1
    protected function writeResults(OutputInterface $output, $options)
208
    {
209 1
        $this->writeSection($output, 'Summary after key generation');
210
211 1
        $output->writeln(array(
212 1
            '<info>Key</info>',
213 1
            str_repeat('=', 3),
214 1
            $options['key'],
215 1
            '',
216 1
            '<info>Directory</info>',
217 1
            str_repeat('=', 9),
218 1
            $options['dir'] ?: "No directory defined\n",
219 1
            '<info>Secret</info>',
220 1
            str_repeat('=', 6),
221 1
            $options['secret'] ?: '',
222
        ));
223
224 1
        if (!empty($options['dir']) && $output->isDebug()) {
225
226
            /** @var DebugFormatterHelper */
227 1
            $dh = $this->getHelperSet()
228 1
                       ->get('debug_formatter');
229
230 1
            $process = new Process("ls -la {$options['dir']} | grep \".crypto\"");
231
232 1
            $output->writeln(array(
233 1
                '',
234 1
                $dh->start(spl_object_hash($process), "Find {$options['dir']}", 'START'),
235
            ));
236
237 1
            $process->run(function ($type, $buffer) use ($process, $output, $dh) {
238 1
                $output->writeln($dh->progress(spl_object_hash($process), $buffer, Process::ERR === $type));
239 1
            });
240
241 1
            $output->writeln(array(
242 1
                $dh->stop(spl_object_hash($process), 'Everything is OK!', $process->isSuccessful()),
243
            ));
244
        }
245 1
    }
246
247
    /**
248
     * @return InputDefinition
249
     */
250 3
    protected function createDefinition()
251
    {
252 3
        return new InputDefinition(array(
253 3
            new InputOption('dir', 'd', InputOption::VALUE_REQUIRED, 'The path to the file which stores the encoded key'),
254
        ));
255
    }
256
}
257