Completed
Push — master ( b72f51...37b25d )
by Lorenzo
07:09
created

ComposerSecurityCheck::findFilesComposerLock()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 15
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 3.072

Importance

Changes 4
Bugs 1 Features 1
Metric Value
c 4
b 1
f 1
dl 0
loc 15
ccs 8
cts 10
cp 0.8
rs 9.4285
cc 3
eloc 8
nc 4
nop 1
crap 3.072
1
<?php
2
3
namespace Padosoft\LaravelComposerSecurity;
4
5
use Illuminate\Console\Command;
6
use GuzzleHttp\Client;
7
use Config;
8
9
10
class ComposerSecurityCheck extends Command
11
{
12
    /**
13
     * The name and signature of the console command.
14
     *
15
     * @var string
16
     */
17
    protected $signature = 'composer-security:check
18
                            {path? : path where find composer.lock, you can use * as jolly character i.e. "/var/www/*/*/", use quotation marks}
19
                            {--M|mail= : If you want send result to email}
20
                            {--N|nomailok=false : True if you want send result to email only for alarm, false is default}
21
                            {--w|whitelist= : If you want exclude from alarm some paths, divide by ","}';
22
23
    /**
24
     * The console command description.
25
     *
26
     * @var string
27
     */
28
    protected $description = <<<EOF
29
The <info>composer-security:check</info> command looks for every composer.lock file in the given path
30
and foreach composer.lock check for security issues in the project dependencies:
31
<info>php composer-security:check</info>
32
If you omit path argument, command look into current folder.
33
You can also pass the path as an argument:
34
<info>php composer-security:check /path/to/my/repos</info>
35
You can use <info>*</info> in path argument as jolly character i.e. <info>/var/www/*/*/</info>
36
By default, the command displays the result in console, but you can also
37
send an html email by using the <info>--mail</info> option:
38
<info>php composer-security:check /path/to/my/repos [email protected]</info>
39
EOF;
40
41
42
    /**
43
     * @var Client an istance of GuzzleHttp\Client
44
     */
45
    protected $guzzle;
46
47
    /**
48
     * @var array
49
     */
50
    protected $headersTableConsole = ['name', 'version', 'title', 'whitelist'];
51
52
    /**
53
     * @var array
54
     */
55
    protected $tableVulnerabilities = [];
56
57
    /**
58
     * Create a new command instance.
59
     *
60
     * @param Client $objguzzle
61
     */
62 18
    public function __construct(Client $objguzzle)
63
    {
64 18
        $this->guzzle = $objguzzle;
65 18
        parent::__construct();
66 18
    }
67
68
    /**
69
     * Execute the console command.
70
     *
71
     * @return mixed
72
     */
73 16
    public function handle()
74
    {
75 16
        $this->hardWork($this->argument(), $this->option());
76 16
    }
77
78
    /**
79
     * @param $argument
80
     * @param $option
81
     */
82 16
    private function hardWork($argument, $option)
83
    {
84 16
        $path = $argument['path'];
85 16
        $this->line('path: <info>' . $path . '</info>.\nCheck composer.lock files...');
86 16
        $lockFiles = $this->findFilesComposerLock($path);
87 16
        $this->line('Find <info>' . count($lockFiles) . '</info> composer.lock files.');
88
89 16
        $this->tableVulnerabilities = [];
90 16
        $tuttoOk = true;
91 16
        $numLock = 0;
92
93 16
        $whitelist = FileHelper::adjustPath($option['whitelist']);
94
95 16
        foreach ($lockFiles as $fileLock) {
96
97 16
            $this->line("Analizing <info>" . ($numLock + 1) . "</info> di <info>" . count($lockFiles) . "</info>");
98
99 16
            $tuttoOk = $this->checkFile($fileLock, $whitelist);
100
101 16
            $numLock++;
102 16
        }
103
104 16
        $this->notifyResult($option['mail'], $option['nomailok'], $tuttoOk);
105
106 16
    }
107
108
    /**
109
     * @param $mail
110
     * @param $tuttoOk
111
     */
112 16
    private function notifyResult($mail, $nomailok, $tuttoOk)
113
    {
114
115
        //print to console
116 16
        $this->table($this->headersTableConsole, $this->tableVulnerabilities);
117
118 16
        $nomailok_bool = false;
119
120 16
        if ($nomailok!='' && strtolower($nomailok)=='true') {
121 4
            $nomailok_bool = true;
122 4
        }
123
124
        //send email
125 16
        if(!$nomailok_bool || !$tuttoOk) {
126 14
            $this->sendEmail($mail, $tuttoOk);
127 14
        }
128
129 16
        if ($tuttoOk) {
130 10
            return $this->notifyOK();
131
        }
132
133 6
        $this->notifyKO();
134 6
    }
135
136
137 10
    private function notifyOK()
138
    {
139 10
        $esito = Config::get('composer-security-check.mailSubjectSuccess');
140 10
        $this->line($esito);
141 10
    }
142
143 6
    private function notifyKO()
144
    {
145 6
        $esito = Config::get('composer-security-check.mailSubjetcAlarm');
146 6
        $this->error($esito);
147 6
    }
148
149
    /**
150
     * @param $mail
151
     * @param $tuttoOk
152
     */
153 14
    private function sendEmail($mail, $tuttoOk)
154
    {
155 14
        if ($mail != '') {
156 14
            $email = new MailHelper($this);
157 14
            $email->sendEmail($tuttoOk, $mail, $this->tableVulnerabilities);
158 14
        }
159 14
    }
160
161
    /**
162
     *
163
     * @param $path
164
     * @return array of composer.lock file
165
     */
166 18
    private function findFilesComposerLock($path)
167
    {
168 18
        $file = new FileHelper();
169 18
        $lockFiles = array();
170 18
        foreach ($file->adjustPath($path) as $item) {
171 18
            $lockFiles = array_merge($lockFiles,$file->findFiles($item, 'composer.lock'));
172 18
        }
173
174
175 18
        if(!is_array($lockFiles)){
176
            $lockFiles = array();
177
        }
178
179 18
        return $lockFiles;
180
    }
181
182
    /**
183
     * @param $fileLock
184
     * @param $whitelist
185
     * @return bool
186
     */
187 16
    private function checkFile($fileLock, $whitelist)
188
    {
189 16
        $this->line("Analizing: $fileLock ...");
190
191 16
        $this->tableVulnerabilities[] = [
192 16
            'name' => $fileLock,
193 16
            'version' => '',
194 16
            'advisories' => '',
195
            'isOk' => ''
196 16
        ];
197
198 16
        $sensiolab = new SensiolabHelper($this->guzzle, $this);
199 16
        $response = $sensiolab->getSensiolabVulnerabilties($fileLock);
200
201 16
        if (($response === null) | !is_array($response)) {
202
            $this->error("Errore Response not vaild or null.");
203
            return true;
204
        }
205 16
        if (count($response) == 0) {
206 8
            return true;
207
        }
208 10
        $this->error("Trovate " . count($response) . " vulnerabilita' in $fileLock");
209
210 10
        $tuttoOk = in_array(rtrim(str_replace('\\', '/', $fileLock), 'composer.lock'), $whitelist);
211
212 10
        foreach ($response as $key => $vulnerability) {
213
214 10
            $this->tableVulnerabilities = array_merge($this->tableVulnerabilities, $sensiolab->checkResponse($key, $vulnerability, $tuttoOk));
215 10
        }
216
217 10
        return $tuttoOk;
218
    }
219
220
}
221
222