SecHeadersCheckCommand   A
last analyzed

Complexity

Total Complexity 11

Size/Duplication

Total Lines 100
Duplicated Lines 0 %

Test Coverage

Coverage 0%

Importance

Changes 0
Metric Value
wmc 11
eloc 49
dl 0
loc 100
c 0
b 0
f 0
ccs 0
cts 52
cp 0
rs 10

7 Methods

Rating   Name   Duplication   Size   Complexity  
A execute() 0 11 2
A scanHeadersFromStdIn() 0 11 1
A __construct() 0 8 1
A configure() 0 13 1
A scanHeadersFromURL() 0 12 1
A getHeadersFromStdIn() 0 11 3
A getScanResult() 0 11 2
1
<?php declare(strict_types=1);
2
3
/**
4
 * @license  http://opensource.org/licenses/mit-license.php MIT
5
 * @link     https://github.com/nicoSWD
6
 * @author   Nicolas Oelgart <[email protected]>
7
 */
8
namespace nicoSWD\SecHeaderCheck\Application\Command;
9
10
use nicoSWD\SecHeaderCheck\Application\UseCase\ScanHeaders\ScanURLRequest;
11
use nicoSWD\SecHeaderCheck\Application\UseCase\ScanHeaders\ScanURLResponse;
12
use nicoSWD\SecHeaderCheck\Application\UseCase\ScanHeaders\ScanURLUseCase;
13
use nicoSWD\SecHeaderCheck\Application\UseCase\SecurityHeaders\ScanHeadersRequest;
14
use nicoSWD\SecHeaderCheck\Application\UseCase\SecurityHeaders\ScanHeadersResponse;
15
use nicoSWD\SecHeaderCheck\Application\UseCase\SecurityHeaders\ScanHeadersUseCase;
16
use Symfony\Component\Console\Command\Command;
17
use Symfony\Component\Console\Input\InputArgument;
18
use Symfony\Component\Console\Input\InputInterface;
19
use Symfony\Component\Console\Input\InputOption;
20
use Symfony\Component\Console\Output\OutputInterface;
21
22
final class SecHeadersCheckCommand extends Command
23
{
24
    private const STATUS_ERROR = 1;
25
    private const STATUS_SUCCESS = 0;
26
27
    /** @var ScanURLUseCase */
28
    private $scanURLUseCase;
29
    /** @var ScanHeadersUseCase */
30
    private $scanHeadersUseCase;
31
32
    public function __construct(
33
        ScanURLUseCase $scanURLUseCase,
34
        ScanHeadersUseCase $scanHeadersUseCase
35
    ) {
36
        parent::__construct();
37
38
        $this->scanURLUseCase = $scanURLUseCase;
39
        $this->scanHeadersUseCase = $scanHeadersUseCase;
40
    }
41
42
    protected function configure()
43
    {
44
        $this->setName('nicoswd:security-header-check')
45
            ->setDescription('Check a site\'s security headers')
46
            ->addArgument('url', InputArgument::OPTIONAL, 'URL to check')
47
            ->addOption('ignore-redirects', 'r', InputOption::VALUE_OPTIONAL, 'Ignore redirects', false)
48
            ->addOption('output-format', 'o', InputOption::VALUE_OPTIONAL, 'Output format', 'console')
49
            ->addOption('target-score', 't', InputOption::VALUE_OPTIONAL, 'Target score', '5')
50
            ->addOption('show-all-headers', 'a', InputOption::VALUE_OPTIONAL, 'Show all headers', false)
51
            // Ideas...
52
            ->addOption('silent', 's', InputOption::VALUE_OPTIONAL, 'No output, just fail on error', false)
53
            ->addOption('config', 'c', InputOption::VALUE_OPTIONAL, 'Load config file', '')
54
            ->addOption('print-score', 'p', InputOption::VALUE_OPTIONAL, 'Only output the score', '')
55
        ;
56
    }
57
58
    protected function execute(InputInterface $input, OutputInterface $output)
59
    {
60
        $scanResult = $this->getScanResult($input);
61
62
        $output->writeln($scanResult->output);
63
64
        if ($scanResult->hitTargetScore) {
65
            return self::STATUS_SUCCESS;
66
        }
67
68
        return self::STATUS_ERROR;
69
    }
70
71
    protected function scanHeadersFromURL(InputInterface $input): ScanURLResponse
72
    {
73
        $scanRequest = new ScanURLRequest();
74
        $scanRequest->url = $input->getArgument('url');
75
        $scanRequest->outputFormat = $input->getOption('output-format');
76
        $scanRequest->targetScore = (float) $input->getOption('target-score');
77
        $scanRequest->followRedirects = $input->getOption('ignore-redirects') === false;
78
        $scanRequest->showAllHeaders = $input->getOption('show-all-headers') !== false;
79
80
        $scanResult = $this->scanURLUseCase->execute($scanRequest);
81
82
        return $scanResult;
83
    }
84
85
    private function scanHeadersFromStdIn(InputInterface $input): ScanHeadersResponse
86
    {
87
        $scanRequest = new ScanHeadersRequest();
88
        $scanRequest->headers = $this->getHeadersFromStdIn();
89
        $scanRequest->outputFormat = $input->getOption('output-format');
90
        $scanRequest->targetScore = (float) $input->getOption('target-score');
91
        $scanRequest->showAllHeaders = $input->getOption('show-all-headers') !== false;
92
93
        $scanResult = $this->scanHeadersUseCase->execute($scanRequest);
94
95
        return $scanResult;
96
    }
97
98
    private function getHeadersFromStdIn(): string
99
    {
100
        $headers = '';
101
102
        if (ftell(STDIN) === 0) {
103
            while (!feof(STDIN)) {
104
                $headers .= fread(STDIN, 1024);
105
            }
106
        }
107
108
        return $headers;
109
    }
110
111
    private function getScanResult(InputInterface $input)
112
    {
113
        $url = $input->getArgument('url');
114
115
        if ($url) {
116
            $scanResult = $this->scanHeadersFromURL($input);
117
        } else {
118
            $scanResult = $this->scanHeadersFromStdIn($input);
119
        }
120
121
        return $scanResult;
122
    }
123
}
124