Completed
Push — master ( 7c30e2...607b79 )
by Jeff
26s queued 11s
created

DKIMSetupCommand::getDomain()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 13
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 6
c 1
b 0
f 0
nc 2
nop 2
dl 0
loc 13
rs 10
1
<?php
2
3
declare(strict_types=1);
4
/**
5
 * This file is part of the mailserver-admin package.
6
 * (c) Jeffrey Boehm <https://github.com/jeboehm/mailserver-admin>
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 */
10
11
namespace App\Command;
12
13
use App\Entity\Domain;
14
use App\Service\DKIM\FormatterService;
15
use App\Service\DKIM\KeyGenerationService;
16
use Doctrine\ORM\EntityManagerInterface;
17
use Symfony\Component\Console\Command\Command;
18
use Symfony\Component\Console\Helper\QuestionHelper;
19
use Symfony\Component\Console\Input\InputInterface;
20
use Symfony\Component\Console\Input\InputOption;
21
use Symfony\Component\Console\Output\OutputInterface;
22
use Symfony\Component\Console\Question\ConfirmationQuestion;
23
24
class DKIMSetupCommand extends Command
25
{
26
    private $manager;
27
    private $keyGenerationService;
28
    private $formatterService;
29
30
    public function __construct(
31
        ?string $name = null,
32
        EntityManagerInterface $manager,
33
        KeyGenerationService $keyGenerationService,
34
        FormatterService $formatterService
35
    ) {
36
        parent::__construct($name);
37
38
        $this->manager = $manager;
39
        $this->keyGenerationService = $keyGenerationService;
40
        $this->formatterService = $formatterService;
41
    }
42
43
    protected function configure(): void
44
    {
45
        $this
46
            ->setName('dkim:setup')
47
            ->addArgument('domain')
48
            ->addOption('enable', null, InputOption::VALUE_NONE, 'Enable DKIM signing for outgoing mails.')
49
            ->addOption('regenerate', null, InputOption::VALUE_NONE, 'Regenerate private key.')
50
            ->addOption('selector', null, InputOption::VALUE_REQUIRED, 'Set DKIM selector.');
51
    }
52
53
    protected function execute(InputInterface $input, OutputInterface $output): int
54
    {
55
        $domain = $this->getDomain($input, $output);
56
57
        if (!$domain) {
0 ignored issues
show
introduced by
$domain is of type App\Entity\Domain, thus it always evaluated to true.
Loading history...
58
            return 1;
59
        }
60
61
        $regenerateKey = (bool) $input->getOption('regenerate');
62
63
        if ($regenerateKey && !$this->warnOnKeyRegeneration($input, $output, $domain)) {
64
            return 1;
65
        }
66
67
        if (empty($domain->getDkimPrivateKey())) {
68
            $regenerateKey = true;
69
        }
70
71
        $selector = $input->getOption('selector') ?: \date('Y');
72
73
        if ($regenerateKey) {
74
            $keyPair = $this->keyGenerationService->createKeyPair();
75
            $domain->setDkimPrivateKey($keyPair->getPrivate());
76
        }
77
78
        $domain->setDkimSelector($selector);
79
        $domain->setDkimEnabled((bool) $input->getOption('enable'));
80
81
        $expectedDnsRecord = $this->formatterService->getTXTRecord(
82
            $this->keyGenerationService->extractPublicKey($domain->getDkimPrivateKey()),
83
            KeyGenerationService::DIGEST_ALGORITHM
84
        );
85
86
        $this->manager->flush();
87
88
        $output->writeln(sprintf('<info>Add the following TXT record to %s.%s:</info>', $selector, $domain->getName()));
89
        $output->writeln('');
90
        $output->writeln($expectedDnsRecord);
91
        $output->writeln('');
92
93
        if ($domain->getDkimEnabled()) {
94
            $output->writeln('<info>DKIM is enabled.</info>');
95
        }
96
97
        return 0;
98
    }
99
100
    private function getDomain(InputInterface $input, OutputInterface $output): ?Domain
101
    {
102
        $name = $input->getArgument('domain');
103
        /** @var Domain $domain */
104
        $domain = $this->manager->getRepository(Domain::class)->findOneBy(['name' => $name]);
105
106
        if (!$domain) {
0 ignored issues
show
introduced by
$domain is of type App\Entity\Domain, thus it always evaluated to true.
Loading history...
107
            $output->writeln(sprintf('<error>Domain "%s" was not found.</error>', $name));
108
109
            return null;
110
        }
111
112
        return $domain;
113
    }
114
115
    private function warnOnKeyRegeneration(InputInterface $input, OutputInterface $output, Domain $domain): bool
0 ignored issues
show
Unused Code introduced by
The parameter $domain is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

115
    private function warnOnKeyRegeneration(InputInterface $input, OutputInterface $output, /** @scrutinizer ignore-unused */ Domain $domain): bool

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
116
    {
117
        /** @var QuestionHelper $questionHelper */
118
        $questionHelper = $this->getHelper('question');
119
        $result = $questionHelper->ask(
120
            $input,
121
            $output,
122
            new ConfirmationQuestion(
123
                '<question>If you regenerate your private key, you\'ll have to update your DNS settings. Continue?</question>'
124
            )
125
        );
126
127
        if (!$result) {
128
            $output->writeln('Aborting.');
129
130
            return false;
131
        }
132
133
        return true;
134
    }
135
}
136