ComposerSecurityCheck   A
last analyzed

Complexity

Total Complexity 21

Size/Duplication

Total Lines 210
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 4

Test Coverage

Coverage 95%

Importance

Changes 0
Metric Value
wmc 21
lcom 1
cbo 4
dl 0
loc 210
ccs 76
cts 80
cp 0.95
rs 10
c 0
b 0
f 0

10 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 5 1
A handle() 0 4 1
B hardWork() 0 25 2
A notifyResult() 0 12 4
A notify() 0 8 2
A notifyOK() 0 5 1
A notifyKO() 0 5 1
A sendEmail() 0 7 2
A findFilesComposerLock() 0 15 3
B checkFile() 0 33 4
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
        //print to console
115 16
        $this->table($this->headersTableConsole, $this->tableVulnerabilities);
116
117
        //send email
118 16
        if (!$tuttoOk || $nomailok == '' || strtolower($nomailok) != 'true') {
119 14
            $this->sendEmail($mail, $tuttoOk);
120 14
        }
121
122 16
        $this->notify($tuttoOk);
123 16
    }
124
125
126 16
    private function notify($result)
127
    {
128 16
        if ($result) {
129 10
            return $this->notifyOK();
130
        }
131
132 6
        $this->notifyKO();
133 6
    }
134
135 10
    private function notifyOK()
136
    {
137 10
        $esito = Config::get('composer-security-check.mailSubjectSuccess');
138 10
        $this->line($esito);
139 10
    }
140
141 6
    private function notifyKO()
142
    {
143 6
        $esito = Config::get('composer-security-check.mailSubjetcAlarm');
144 6
        $this->error($esito);
145 6
    }
146
147
    /**
148
     * @param $mail
149
     * @param $tuttoOk
150
     */
151 14
    private function sendEmail($mail, $tuttoOk)
152
    {
153 14
        if ($mail != '') {
154 14
            $email = new MailHelper($this);
155 14
            $email->sendEmail($tuttoOk, $mail, $this->tableVulnerabilities);
156 14
        }
157 14
    }
158
159
    /**
160
     *
161
     * @param $path
162
     * @return array of composer.lock file
163
     */
164 18
    private function findFilesComposerLock($path)
165
    {
166 18
        $file = new FileHelper();
167 18
        $lockFiles = array();
168 18
        foreach ($file->adjustPath($path) as $item) {
169 18
            $lockFiles = array_merge($lockFiles, $file->findFiles($item, 'composer.lock'));
170 18
        }
171
172
173 18
        if (!is_array($lockFiles)) {
174
            $lockFiles = array();
175
        }
176
177 18
        return $lockFiles;
178
    }
179
180
    /**
181
     * @param $fileLock
182
     * @param $whitelist
183
     * @return bool
184
     */
185 16
    private function checkFile($fileLock, $whitelist)
186
    {
187 16
        $this->line("Analizing: $fileLock ...");
188
189 16
        $this->tableVulnerabilities[] = [
190 16
            'name' => $fileLock,
191 16
            'version' => '',
192 16
            'advisories' => '',
193
            'isOk' => ''
194 16
        ];
195
196 16
        $sensiolab = new SensiolabHelper($this->guzzle, $this);
197 16
        $response = $sensiolab->getSensiolabVulnerabilties($fileLock);
198
199 16
        if (($response === null) | !is_array($response)) {
200
            $this->error("Errore Response not vaild or null.");
201
            return true;
202
        }
203 16
        if (count($response) == 0) {
204 8
            return true;
205
        }
206 10
        $this->error("Trovate " . count($response) . " vulnerabilita' in $fileLock");
207
208 10
        $tuttoOk = in_array(rtrim(str_replace('\\', '/', $fileLock), 'composer.lock'), $whitelist);
209
210 10
        foreach ($response as $key => $vulnerability) {
211
212 10
            $this->tableVulnerabilities = array_merge($this->tableVulnerabilities,
213 10
                $sensiolab->checkResponse($key, $vulnerability, $tuttoOk));
214 10
        }
215
216 10
        return $tuttoOk;
217
    }
218
219
}
220
221