Completed
Push — master ( 252a1e...138995 )
by Kris
24s queued 10s
created

AbuseIPDBClient::getBlacklist()   B

Complexity

Conditions 11
Paths 48

Size

Total Lines 61
Code Lines 35

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 11
eloc 35
c 1
b 0
f 0
nc 48
nop 1
dl 0
loc 61
rs 7.3166

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
/**
4
 *     _    _                    ___ ____  ____  ____
5
 *    / \  | |__  _   _ ___  ___|_ _|  _ \|  _ \| __ )
6
 *   / _ \ | '_ \| | | / __|/ _ \| || |_) | | | |  _ \
7
 *  / ___ \| |_) | |_| \__ \  __/| ||  __/| |_| | |_) |
8
 * /_/   \_\_.__/ \__,_|___/\___|___|_|   |____/|____/
9
 *
10
 * This file is part of Kristuff\AbsuseIPDB.
11
 *
12
 * (c) Kristuff <[email protected]>
13
 *
14
 * For the full copyright and license information, please view the LICENSE
15
 * file that was distributed with this source code.
16
 *
17
 * @version    0.9.8
18
 * @copyright  2020-2021 Kristuff
19
 */
20
namespace Kristuff\AbuseIPDB;
21
22
use Kristuff\AbuseIPDB\SilentApiHandler;
23
use Kristuff\Mishell\Console;
24
25
/**
26
 * Class AbuseIPDB
27
 * 
28
 * The main cli program
29
 */
30
class AbuseIPDBClient extends ShellUtils
31
{
32
33
    /**
34
     * @var string      
35
     */
36
    const SHORT_ARGUMENTS = "GLBK:C:d:R:c:m:l:pE:V:hvs:";
37
38
    /**
39
     * @var string      
40
     */
41
    const LONG_ARGUMENTS = ['config', 'list', 'blacklist', 'check:', 'check-block:', 'days:', 'report:', 'categories:', 'message:', 'limit:', 'plaintext', 'clear:','bulk-report:', 'help', 'verbose', 'score:'];
42
    
43
    /**
44
     * @var string      $version
45
     */
46
    const VERSION = 'v0.9.8'; 
47
48
    /**
49
     * @var SilentApiHandler  $api
50
     */
51
    private static $api = null; 
52
53
    /**
54
     * @var string      $keyPath
55
     */
56
    private static $keyPath = __DIR__ .'/../config/key.json';
57
58
    /**
59
     * The entry point of our app 
60
     * 
61
     * @access public
62
     * @static
63
     * @param array $arguments
64
     * 
65
     * @return void
66
     */
67
    public static function start($arguments)
68
    {
69
        // get key path from current script location (supposed in a bin folder)
70
        self::$keyPath = dirname(get_included_files()[0]) . '/../config/key.json';
71
72
        // check for install
73
        self::validate( self::checkForInstall(), 'Key file missing.');
74
75
        // Create a new instance of \ApiHandler with the given config file
76
        try {
77
            self::$api = self::fromConfigFile(self::$keyPath);
78
        } catch (\Exception $e) {
79
            self::error($e->getMessage());
80
            self::printFooter();
81
            exit(1);
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
82
        }
83
    
84
        // required at least one valid argument
85
        self::validate( !empty($arguments), 'No valid arguments given. Run abuseipdb --help to get help.');
86
87
         // prints help ?
88
         if (self::inArguments($arguments, 'h', 'help')){
89
            self::printBanner();
90
            self::printHelp();
91
            exit(0);
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
92
        }
93
94
        // prints config ?
95
        if (self::inArguments($arguments, 'G', 'config')){
96
            self::printConfig();
97
            exit(0);
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
98
        } 
99
100
        // prints catgeories ?
101
        if (self::inArguments($arguments, 'L', 'list')){
102
            self::printCategories();
103
            exit(0);
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
104
        } 
105
        
106
        // check request ?
107
        if (self::inArguments($arguments, 'C', 'check')){
108
            self::checkIP($arguments);
109
            exit(0);
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
110
        }
111
       
112
        // check-block request ?
113
        if (self::inArguments($arguments, 'K', 'check-block')){
114
            self::checkBlock($arguments);
115
            exit(0);
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
116
        }
117
118
        // report request ?
119
        if (self::inArguments($arguments, 'R', 'report')){
120
            self::reportIP($arguments);
121
            exit(0);
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
122
        }
123
124
        // report request ?
125
        if (self::inArguments($arguments, 'V', 'bulk-report')){
126
            self::bulkReport($arguments);
127
            exit(0);
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
128
        }
129
130
        // report request ?
131
        if (self::inArguments($arguments, 'B', 'blacklist')){
132
            self::getBlacklist($arguments);
133
            exit(0);
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
134
        }
135
136
        // report request ?
137
        if (self::inArguments($arguments, 'E', 'clear')){
138
            self::clearIP($arguments);
139
            exit(0);
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
140
        }
141
142
        // no valid arguments given, close program
143
        Console::log();   
144
        self::error('invalid arguments. Run abuseipdb --help to get help.');
145
        self::printFooter();
146
        exit(1);
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
147
    }
148
149
    /**
150
     * Get a new instance of ApiHandler with config stored in a Json file
151
     * 
152
     * @access public 
153
     * @static
154
     * @param string    $configPath     The configuration file path
155
     * 
156
     * @return \Kristuff\AbuseIPDB\ApiHandler
157
     * @throws \InvalidArgumentException                        If the given file does not exist
158
     * @throws \Kristuff\AbuseIPDB\InvalidPermissionException   If the given file is not readable 
159
     */
160
    public static function fromConfigFile(string $configPath)
161
    {
162
        // check file exists
163
        if (!file_exists($configPath) || !is_file($configPath)){
164
            throw new \InvalidArgumentException('The file [' . $configPath . '] does not exist.');
165
        }
166
167
        // check file is readable
168
        if (!is_readable($configPath)){
169
            throw new InvalidPermissionException('The file [' . $configPath . '] is not readable.');
170
        }
171
172
        $keyConfig = self::loadJsonFile($configPath);
173
        $selfIps = [];
174
        
175
        // Look for other optional config files in the same directory 
176
        $selfIpsConfigPath = pathinfo($configPath, PATHINFO_DIRNAME) . DIRECTORY_SEPARATOR . 'self_ips.json';
0 ignored issues
show
Bug introduced by
Are you sure pathinfo($configPath, Kr...eIPDB\PATHINFO_DIRNAME) of type array|string can be used in concatenation? ( Ignorable by Annotation )

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

176
        $selfIpsConfigPath = /** @scrutinizer ignore-type */ pathinfo($configPath, PATHINFO_DIRNAME) . DIRECTORY_SEPARATOR . 'self_ips.json';
Loading history...
177
        if (file_exists($selfIpsConfigPath)){
178
            $selfIps = self::loadJsonFile($selfIpsConfigPath)->self_ips;
179
        }
180
181
        $app = new SilentApiHandler($keyConfig->api_key, $selfIps);
182
        
183
        return $app;
184
    }
185
186
    /** 
187
     * Load and returns decoded Json from given file  
188
     *
189
     * @access public
190
     * @static
191
	 * @param string    $filePath       The file's full path
192
	 * @param bool      $throwError     Throw error on true or silent process. Default is true
193
     *  
194
	 * @return object|null 
195
     * @throws \Exception
196
     * @throws \LogicException
197
     */
198
    protected static function loadJsonFile(string $filePath, bool $throwError = true)
199
    {
200
        // check file exists
201
        if (!file_exists($filePath) || !is_file($filePath)){
202
           if ($throwError) {
203
                throw new \Exception('Config file not found');
204
           }
205
           return null;  
206
        }
207
208
        // get and parse content
209
        $content = utf8_encode(file_get_contents($filePath));
210
        $json    = json_decode($content);
211
212
        // check for errors
213
        if ($json == null && json_last_error() != JSON_ERROR_NONE && $throwError) {
214
            throw new \LogicException(sprintf("Failed to parse config file Error: '%s'", json_last_error_msg()));
215
        }
216
217
        return $json;        
218
    }
219
220
    /**
221
     * Check for install
222
     * 
223
     * @access protected
224
     * @static
225
     * 
226
     * @return bool
227
     */
228
    protected static function checkForInstall()
229
    {
230
        if (file_exists(self::$keyPath)) {
231
            return true;
232
        }
233
        
234
        // not installed
235
        self::printBanner();
236
        Console::log(' Your config key file was not found. Do you want to create it? ', 'white');
237
        $create =  Console::ask(' Press Y/y to create a config key file: ', 'white');
238
            
239
        if ($create == 'Y' || $create == 'y') {
240
            $key =     Console::ask(' - Please enter your api key: ', 'white');
241
            $create =  Console::ask(' A config file will be created in config/ directory. Press Y/y to continue: ', 'white');
242
            
243
            if ($create == 'Y' || $create == 'y') {
244
                $data = json_encode(['api_key' => $key]);
245
                
246
                if (file_put_contents(self::$keyPath, $data, LOCK_EX) === false){
247
                    self::error('An error occured during writing config file. Make sure to give the appropriate permissions do the config directory.');
248
                    return false;
249
                }
250
251
                // successfull. print message and exit to prevent errors with no arguments 
252
                Console::log();
253
                Console::log(Console::text('  ✓ ', 'green') . Console::text('Your config file has been successfully created.', 'white'));
254
                Console::log('    You can now use abuseipdb.', 'white');
255
                Console::log();
256
                exit(0);
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
257
            }
258
        }
259
        // no key file, not created
260
        return false;    
261
    }
262
 
263
    /**
264
     * Prints the help
265
     * 
266
     * @access protected
267
     * @static
268
     * 
269
     * @return void
270
     */
271
    protected static function printHelp()
272
    {
273
        Console::log(' ' . Console::text('SYNOPSIS:', 'white', 'underline')); 
274
        Console::log(' ' . Console::text('    abuseipdb -C ') . 
275
                           Console::text('ip', 'yellow') . 
276
                           Console::text(' [-d ') . 
277
                           Console::text('days', 'yellow') . 
278
                           Console::text('] [-v] [-l ') . 
279
                           Console::text('limit', 'yellow') . 
280
                           Console::text(']')); 
281
282
        Console::log(' ' . Console::text('    abuseipdb -K ') . 
283
                           Console::text('network', 'yellow') . 
284
                           Console::text(' [-d ') . 
285
                           Console::text('days', 'yellow') . 
286
                           Console::text(']')); 
287
288
        Console::log(' ' . Console::text('    abuseipdb -R ' .
289
                           Console::text('ip', 'yellow') . ' -c ' .
290
                           Console::text('categories', 'yellow') . ' -m ' .
291
                           Console::text('message', 'yellow'))); 
292
293
        Console::log(' ' . Console::text('    abuseipdb -V ' .
294
                           Console::text('path', 'yellow')));
295
296
        Console::log(' ' . Console::text('    abuseipdb -E ' .
297
                           Console::text('ip', 'yellow')));
298
                           
299
        Console::log(' ' . Console::text('    abuseipdb -B ') . 
300
                           Console::text('[-l ') . 
301
                           Console::text('limit', 'yellow') . 
302
                           Console::text('] [-s ') . 
303
                           Console::text('score', 'yellow') . 
304
                           Console::text('] [-p ') . 
305
                           Console::text('', 'yellow') . 
306
                           Console::text(']')); 
307
308
        Console::log(' ' . Console::text('    abuseipdb -L '));
309
        Console::log(' ' . Console::text('    abuseipdb -G '));
310
        Console::log(' ' . Console::text('    abuseipdb -h '));
311
                           
312
        Console::log();    
313
        Console::log(' ' . Console::text('OPTIONS:', 'white', 'underline')); 
314
        Console::log();
315
        Console::log(Console::text('   -h, --help', 'white')); 
316
        Console::log('       Prints the current help. If given, all next arguments are ignored.', 'lightgray');
317
        Console::log();    
318
        Console::log(Console::text('   -G, --config', 'white')); 
319
        Console::log('       Prints the current config. If given, all next arguments are ignored.', 'lightgray');
320
        Console::log();    
321
        Console::log(Console::text('   -L, --list', 'white')); 
322
        Console::log('       Prints the list report categories. If given, all next arguments are ignored.', 'lightgray');
323
        Console::log();    
324
        Console::log(Console::text('   -C, --check ', 'white') . Console::text('ip', 'yellow', 'underline')); 
325
        Console::log('       Performs a check request for the given IP address. A valid IPv4 or IPv6 address is required.', 'lightgray');
326
        Console::log();    
327
        Console::log(Console::text('   -K, --check-block ', 'white') . Console::text('network', 'yellow', 'underline')); 
328
        Console::log('       Performs a check-block request for the given network. A valid subnet (v4 or v6) denoted with ', 'lightgray');
329
        Console::log('       CIDR notation is required.', 'lightgray');
330
        Console::log();    
331
        Console::log(Console::text('   -d, --days ', 'white') . Console::text('days', 'yellow', 'underline')); 
332
        Console::log('       For a check or check-block request, defines the maxAgeDays. Min is 1, max is 365, default is 30.', 'lightgray');
333
        Console::log();    
334
        Console::log(Console::text('   -R, --report ', 'white') . Console::text('ip', 'yellow', 'underline')); 
335
        Console::log('       Performs a report request for the given IP address. A valid IPv4 or IPv6 address is required.', 'lightgray');
336
        Console::log();    
337
        Console::log(Console::text('   -V, --bulk-report ', 'white') . Console::text('path', 'yellow', 'underline')); 
338
        Console::log('       Performs a bulk-report request sending a csv file. A valid file name or full path is required.', 'lightgray');
339
        Console::log();    
340
        Console::log(Console::text('   -E, --clear ', 'white')); 
341
        Console::log('       Remove own reports for the given IP address. A valid IPv4 or IPv6 address is required.', 'lightgray');
342
        Console::log();
343
        Console::log(Console::text('   -c, --categories ', 'white') . Console::text('categories', 'yellow', 'underline')); 
344
        Console::log('       For a report request, defines the report category(ies). Categories must be separate by a comma.', 'lightgray');
345
        Console::log('       Some categories cannot be used alone. A category can be represented by its shortname or by its', 'lightgray');
346
        Console::log(Console::text('       id. Use ','lightgray')  . Console::text('abuseipdb -L', 'white') . Console::text(' to print the categories list.','lightgray'));
347
        Console::log();    
348
        Console::log(Console::text('   -m, --message ', 'white') . Console::text('message', 'yellow', 'underline')); 
349
        Console::log('       For a report request, defines the message to send with report. Message is required for all', 'lightgray');
350
        Console::log('       report requests.', 'lightgray');
351
        Console::log();
352
        Console::log(Console::text('   -B, --blacklist ', 'white')); 
353
        Console::log('       Performs a blacklist request. Default limit is 1000. This limit can ne changed with the', 'lightgray');
354
        Console::log('       ' . Console::text('--limit', 'white') . Console::text(' parameter. ', 'lightgray'));
355
        Console::log();    
356
        Console::log(Console::text('   -l, --limit ', 'white') . Console::text('limit', 'yellow', 'underline')); 
357
        Console::log('       For a blacklist request, defines the limit.', 'lightgray');
358
        Console::log('       For a check request with verbose flag, sets the max number of last reports displayed. Default is 10', 'lightgray');
359
        Console::log('       For a check-block request, sets the max number of IPs displayed. Default is 0 (no limit).', 'lightgray');
360
        Console::log();    
361
        Console::log(Console::text('   -p, --plaintext ', 'white')); 
362
        Console::log('       For a blacklist request, output only ip list as plain text.', 'lightgray');
363
        Console::log();    
364
        Console::log(Console::text('   -s, --score ', 'white')); 
365
        Console::log('       For a blacklist request, sets the confidence score minimum. The confidence minimum ', 'lightgray');
366
        Console::log('       must be between 25 and 100. This parameter is subscriber feature (not honored otherwise, allways 100).', 'lightgray');
367
        Console::log();    
368
        Console::log(Console::text('   -v, --verbose ', 'white')); 
369
        Console::log('       For a check request, display additional fields like the x last reports. This increases ', 'lightgray');
370
        Console::log(Console::text('       request time and response size. Max number of last reports displayed can be changed with the ', 'lightgray'));
371
        Console::log('       ' . Console::text('--limit', 'white') . Console::text(' parameter. ', 'lightgray'));
372
        Console::log();    
373
    }
374
375
    /**
376
     * Prints the current config
377
     * 
378
     * @access protected
379
     * @static
380
     * 
381
     * @return void
382
     */
383
    protected static function printConfig()
384
    {
385
        $conf = self::$api->getConfig();
386
387
        self::printTitle(Console::text('  ► Current configuration ', 'darkgray'));
388
        
389
        Console::log(Console::text('  api_key:[', 'white') . Console::text($conf['apiKey'], 'green') . Console::text(']', 'white'));
390
        Console::log(Console::text('  self_ips:', 'white'));
391
        
392
        foreach ($conf['selfIps'] as $ip) {
393
            Console::log(Console::text('    [', 'white') . Console::text($ip, 'green') . Console::text(']', 'white'));   
394
        }
395
396
        Console::log();   
397
        self::printFooter();
398
    }
399
400
    /**
401
     * Prints the report categories list
402
     * 
403
     * @access protected
404
     * @static
405
     * 
406
     * @return void
407
     */
408
    protected static function printCategories()
409
    {
410
        self::printTitle(Console::text('  ► Report categories list ', 'darkgray'));
411
412
        $categories = self::$api->getCategories();
413
        $rowHeaders = [
414
            Console::text('ShortName',      'darkgray') => 15, 
415
            Console::text('Id',             'darkgray') => 2, 
416
            Console::text('Full name',      'darkgray') => 18,
417
            Console::text('Can be alone?',  'darkgray') => 15
418
        ];
419
        Console::$verticalSeparator = '  ';
420
        Console::$verticalInnerSeparator = '  ';
421
        Console::log(Console::tableRowSeparator($rowHeaders, 'darkgray'));
422
        Console::log(Console::tableRow($rowHeaders));      
423
        Console::log(Console::tableRowSeparator($rowHeaders), 'darkgray');
424
        
425
        foreach ($categories as $cat) {
426
            $id = Console::text($cat[1], 'white');
427
            $standalone = $cat[3] ? Console::text('✓', 'green') . Console::text(' true ', 'lightgray') : 
428
                                    Console::text('✗', 'red')   . Console::text(' false', 'darkgray');
429
            $shortName =  Console::text($cat[0], 'white');
430
            $fullName =   Console::text($cat[2], 'lightgray');
431
432
            Console::log(
433
                Console::TableRowStart().  
0 ignored issues
show
Bug introduced by
Are you sure Kristuff\Mishell\Console::TableRowStart() of type void can be used in concatenation? ( Ignorable by Annotation )

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

433
                /** @scrutinizer ignore-type */ Console::TableRowStart().  
Loading history...
Bug introduced by
Are you sure the usage of Kristuff\Mishell\Console::TableRowStart() targeting Kristuff\Mishell\ShellTa...rinter::tableRowStart() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
434
                Console::TableRowCell( $shortName , 15).  
435
                Console::TableRowCell( $id , 2, Console::ALIGN_CENTER).  
436
                Console::TableRowCell( $fullName , 18).  
437
                Console::TableRowCell( $standalone , 15,  Console::ALIGN_CENTER)  
438
            );
439
        }
440
        //Console::log(Console::tableRowSeparator($rowHeaders), 'darkgray');
441
        Console::log();
442
        self::printFooter();
443
    }
444
445
    /**
446
     * Perform a report request 
447
     * 
448
     * @access protected
449
     * @static
450
     * @param array $arguments
451
     * 
452
     * @return void
453
     */
454
    protected static function reportIP(array $arguments)
455
    {
456
        $ip      = self::getArgumentValue($arguments,'R', 'report');
457
        $cats    = self::getArgumentValue($arguments,'c', 'categories');
458
        $message = self::getArgumentValue($arguments,'m', 'message');
459
        
460
        self::printTitle(Console::text('  ► Report IP: ', 'darkgray') . Console::text(escapeshellcmd($ip), 'white'));
461
        self::printTempMessage();
462
463
        // Peforms request 
464
        $timeStart = microtime(true);
465
        $report = self::$api->report($ip, $cats, $message)->getObject();     
466
        $timeEnd = microtime(true);
467
        $time = $timeEnd - $timeStart; // request time
468
        self::clearTempMessage();
469
470
        // check for errors / empty response
471
        if (self::printErrors($report)){
472
            self::printFooter();
473
            exit(1);
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
474
        }
475
        
476
        // ✓ Done: print reported IP and confidence score
477
        $score = empty($report->data->abuseConfidenceScore) ? 0 : $report->data->abuseConfidenceScore;
478
        $scoreColor = self::getScoreColor($score);
479
        Console::log(
480
            Console::text('   ✓', 'green') . 
481
            Console::text(' IP: [', 'white') .
482
            Console::text($ip, $scoreColor) .
483
            Console::text('] successfully reported', 'white')
484
        );
485
        Console::log(Console::text('     Confidence score: ', 'white') . self::getScoreBadge($score));
486
487
        Console::log();
488
        self::printFooter($time);
489
    }
490
491
    /**
492
     * Perform a bulk-report request 
493
     * 
494
     * @access protected
495
     * @static
496
     * @param array $arguments
497
     * 
498
     * @return void
499
     */
500
    protected static function bulkReport(array $arguments)
501
    {
502
        $fileName = self::getArgumentValue($arguments,'V', 'bulk-report');
503
504
        self::printTitle(Console::text('  ► Bulk report for file: ', 'darkgray') . Console::text(escapeshellcmd($fileName), 'white'));
505
        self::printTempMessage();
506
507
        // Peforms request 
508
        $timeStart = microtime(true);  
509
        $response = self::$api->bulkReport($fileName)->getObject();     
510
        $timeEnd = microtime(true);      
511
        $time = $timeEnd - $timeStart;  // request time
512
        self::clearTempMessage();
513
514
        // check for errors / empty response
515
        if (self::printErrors($response)){
516
            self::printFooter();
517
            exit(1);
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
518
        }
519
520
        // ✓ Done
521
        Console::log(
522
            Console::text('   Bulk report for file: [', 'white') .
523
            Console::text($fileName, 'lightyellow') .
524
            Console::text('] done!', 'white')
525
        );
526
527
        $nbErrorReports = isset($response->data->invalidReports) ? count($response->data->invalidReports) : 0;
528
        $nbSavedReports = isset($response->data->savedReports) ? $response->data->savedReports : 0;
529
        $savedColor = $nbSavedReports > 0 ? 'green' : 'red';
530
        $errorColor = $nbErrorReports > 0 ? 'red' : 'green';
531
        $savedIcon  = $nbSavedReports > 0 ? '✓' : '✗';
532
        $errorIcon  = $nbErrorReports > 0 ? '✗' : '✓';
533
534
        Console::log(Console::text('   ' . $savedIcon, $savedColor) . self::printResult(' Saved reports:    ', $nbSavedReports, $savedColor, '', false));
535
        Console::log(Console::text('   ' . $errorIcon, $errorColor) . self::printResult(' Invalid reports:  ', $nbErrorReports, $errorColor, '', false));
536
537
        if ($nbErrorReports > 0){
538
            $numberDiplayedReports = 0;
539
            $defaultColor = 'lightyellow'; // reset color for last reports
540
        
541
            foreach ($response->data->invalidReports as $report){
542
                $input = $report->input ? escapeshellcmd($report->input) : ''; // in case on blank line, IP is null
543
                $line  = Console::text('      →', 'red');
544
                $line .= self::printResult(' Input:         ', $input, $defaultColor, '', false);
545
                Console::log($line);
546
                self::printResult('        Error:         ', $report->error, $defaultColor);
547
                self::printResult('        Line number:   ', $report->rowNumber, $defaultColor);
548
                
549
                // counter
550
                $numberDiplayedReports++;
551
            }
552
        }
553
        Console::log();
554
        self::printFooter($time);
555
    }
556
557
    /**
558
     * Perform a clear-address request 
559
     * 
560
     * @access protected
561
     * @static
562
     * @param array $arguments
563
     * 
564
     * @return void
565
     */
566
    protected static function clearIP(array $arguments)
567
    {
568
        $ip      = self::getArgumentValue($arguments,'E', 'clear');
569
570
        self::printTitle(Console::text('  ► Clear reports for IP: ', 'darkgray') . Console::text(escapeshellcmd($ip), 'white'));
571
572
        // Peforms request 
573
        self::printTempMessage();
574
        $timeStart = microtime(true); // request startime 
575
        $response = self::$api->clearAddress($ip)->getObject();     
576
        $timeEnd = microtime(true);  // request end time 
577
        $time = $timeEnd - $timeStart; // request time
578
        self::clearTempMessage();
579
580
        // check for errors / empty response
581
        if (self::printErrors($response)){
582
            self::printFooter($time);
583
            exit(1);
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
584
        }
585
586
        // ✓ Done: print deleted report number 
587
        Console::log(
588
            Console::text('   ✓', 'green') . 
589
            Console::text(' Successfull clear request for IP: [', 'white') .
590
            Console::text($ip, 'lightyellow') .
591
            Console::text(']', 'white')
592
        );
593
        
594
        self::printResult('     Deleted reports: ', $response->data->numReportsDeleted ?? 0, 'lightyellow');
595
        Console::log();
596
        self::printFooter($time);
597
    }
598
599
    /**
600
     * Perform a blacklist request 
601
     * 
602
     * @access protected
603
     * @static
604
     * @param array $arguments
605
     * 
606
     * @return void
607
     */
608
    protected static function getBlacklist(array $arguments)
609
    {
610
        $plainText  = self::inArguments($arguments,'p','plaintext');  
611
612
        if (!$plainText){
613
            self::printTitle(Console::text('  ► Get Blacklist ', 'darkgray'));
614
        }
615
616
        $limit      = self::getNumericParameter($arguments,'l', 'limit', 1000);
617
        $scoreMin   = self::getNumericParameter($arguments,'s', 'score', 100);
618
619
        if (!$plainText){
620
            self::printTempMessage();
621
        }
622
623
        // do request 
624
        $timeStart = microtime(true);           // request startime 
625
        $response = self::$api->blacklist($limit, $plainText, $scoreMin);     // perform request
626
        $timeEnd = microtime(true);                         // request end time 
627
        $time = $timeEnd - $timeStart;                      // request time
628
629
        if (!$plainText){
630
            self::clearTempMessage();
631
        }
632
633
        // response could be json on error, while plaintext flag is set
634
        $decodedResponse = $response->getObject();
635
        
636
        if ($plainText && $response->hasError()){
637
            exit(1);
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
638
        }
639
640
        if (!$plainText && self::printErrors($decodedResponse)){
641
            self::printFooter($time);
642
            exit(1);
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
643
        }
644
645
        if ($plainText){
646
            // echo response "as is"
647
            Console::log($response->getPlaintext());
648
649
        } else {
650
            // print list
651
            self::printResult('  List generated at: ', self::getDate($decodedResponse->meta->generatedAt), 'lightyellow', '');
652
            Console::log();
653
654
            foreach ($decodedResponse->data as $report){
655
                $score = empty($report->abuseConfidenceScore) ? 0 : $report->abuseConfidenceScore;
656
                $defaultColor = self::getScoreColor($score);
657
658
                $line  = Console::text('    →', $defaultColor);
659
                $line .= self::printResult(' IP: ', $report->ipAddress, $defaultColor, '', false);
660
                $line .= self::printResult(' | Last reported at: ', self::getDate($report->lastReportedAt), $defaultColor, '', false);
661
                $line .= Console::text(' | Confidence score: ', 'white');
662
                $line .= self::getScoreBadge($score);
663
                Console::log($line);
664
            }
665
        
666
            // footer
667
            Console::log();
668
            self::printFooter($time);
669
        }
670
    }
671
672
    /**
673
     * Perform a check-block request 
674
     * 
675
     * @access protected
676
     * @static
677
     * @param array $arguments
678
     * 
679
     * @return void
680
     */
681
    protected static function checkBlock($arguments)
682
    {
683
        $network  = self::getArgumentValue($arguments,'K', 'check-block');
684
685
        self::printTitle(Console::text('  ► Check network: ', 'darkgray') . Console::text(escapeshellcmd($network), 'white') . Console::text('', 'darkgray'));
686
687
        $maxAge   = self::getNumericParameter($arguments, 'd', 'days', 30);
688
        $limit    = self::getNumericParameter($arguments,'l', 'limit', 0); // 0 mean no limit
689
690
        self::printTempMessage();
691
692
        $timeStart = microtime(true);                                       
693
        $check = self::$api->checkBlock($network, $maxAge)->getObject();
694
        $timeEnd = microtime(true);
695
        $time = $timeEnd - $timeStart; // request time
696
        self::clearTempMessage();
697
698
        // check for errors / empty response
699
        if (self::printErrors($check)){
700
            self::printFooter($time);
701
            exit(1);
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
702
        }
703
704
        self::printResult(Console::pad('   Network Address:', 23), $check->data->networkAddress, 'lightyellow');
705
        self::printResult(Console::pad('   Netmask:', 23), $check->data->netmask, 'lightyellow');
706
        self::printResult(Console::pad('   Min Address:', 23), $check->data->minAddress, 'lightyellow');
707
        self::printResult(Console::pad('   Max Address:', 23), $check->data->maxAddress, 'lightyellow');
708
        self::printResult(Console::pad('   Possible Hosts:', 23), $check->data->numPossibleHosts, 'lightyellow');
709
        self::printResult(Console::pad('   Address SpaceDesc:', 23), $check->data->addressSpaceDesc, 'lightyellow');
710
711
        // print reported addresses
712
        $nbReports = isset($check->data->reportedAddress) ? count($check->data->reportedAddress) : 0;
713
        
714
        if ($nbReports > 0){
715
            self::printResult(Console::pad('   Reported addresses:', 23), $nbReports, 'lightyellow');
716
            $numberDiplayedReports = 0;
717
            $defaultColor = 'lightyellow'; // reset color for last reports
0 ignored issues
show
Unused Code introduced by
The assignment to $defaultColor is dead and can be removed.
Loading history...
718
        
719
            foreach ($check->data->reportedAddress as $report){
720
                $score = empty($report->abuseConfidenceScore) ? 0 : $report->abuseConfidenceScore;
721
                $defaultColor = self::getScoreColor($score); // color based on score
722
723
                $line  = Console::text('   →', $defaultColor);
724
                $line .= self::printResult(' IP: ', $report->ipAddress, $defaultColor, '', false);
725
                $line .= self::printResult(' Country: ', $report->countryCode , $defaultColor, '', false);
726
                $line .= Console::text(' | Confidence score: ', 'white');
727
                $line .= self::getScoreBadge($score);
728
                $line .= self::printResult(' Total reports: ', $report->numReports, $defaultColor, '', false);
729
                $line .= self::printResult(' Last reported at: ', self::getDate($report->mostRecentReport), $defaultColor, '', false);
730
                Console::log($line);
731
732
                // counter
733
                $numberDiplayedReports++;
734
735
                if ($numberDiplayedReports === $limit || $numberDiplayedReports === $nbReports) {
736
                    $line  = Console::text('      (', 'white');
737
                    $line .= Console::text($numberDiplayedReports, 'lightyellow');
738
                    $line .= Console::text('/', 'white');
739
                    $line .= Console::text($nbReports, 'lightyellow');
740
                    $line .= Console::text($numberDiplayedReports > 1 ? ' IPs displayed)': ' IP displayed)', 'white');
741
                    Console::log($line);
742
                    break;
743
                }
744
            }
745
746
        } else {
747
            // no reports
748
            $day = $maxAge > 1 ? 'in last '. $maxAge . ' days': ' today';
749
            Console::log( Console::text('    ✓', 'green') . Console::text(' No IP reported ' . $day));
750
        }
751
752
        // footer
753
        Console::log();
754
        self::printFooter($time);
755
    }
756
757
    /**
758
     * Perform a check request 
759
     * 
760
     * @access protected
761
     * @static
762
     * @param array $arguments
763
     * 
764
     * @return void
765
     */
766
    protected static function checkIP($arguments)
767
    {
768
        $ip                 = self::getArgumentValue($arguments,'C', 'check');
769
770
        self::printTitle(Console::text('  ► Check IP: ', 'darkgray') . Console::text(escapeshellcmd($ip), 'white') . Console::text('', 'darkgray'));
771
772
        $verbose            = self::inArguments($arguments,'v', 'verbose');
773
        $maxAge             = self::getNumericParameter($arguments, 'd', 'days', 30);
774
        $maxReportsNumber   = self::getNumericParameter($arguments,'l', 'limit', 10);
775
776
        self::printTempMessage();
777
778
        $timeStart = microtime(true);                                           
779
        $check = self::$api->check($ip, $maxAge, $verbose)->getObject();        
780
        $timeEnd = microtime(true);                                              
781
        $time = $timeEnd - $timeStart; // request time
782
        self::clearTempMessage();
783
784
        // check for errors / empty response
785
        if (self::printErrors($check)){
786
            self::printFooter($time);
787
            exit(1);
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
788
        }
789
790
        // score and data color (depending of abuseConfidenceScore)
791
        $score = empty($check->data->abuseConfidenceScore) ? 0 : $check->data->abuseConfidenceScore;
792
        $defaultColor = self::getScoreColor($score);
793
        $line = Console::text(Console::pad('   Confidence score:', 23), 'white');
794
        $line .= self::getScoreBadge($score);
795
        Console::log($line);
796
      
797
//      self::printResult('   isPublic', $check->data->isPublic, $defaultColor);
798
//      self::printResult('   ipVersion', $check->data->ipVersion, $defaultColor);
799
        $line = self::printResult(Console::pad('   Whitelisted:', 23), $check->data->isWhitelisted ? 'true': 'false', $defaultColor, '', false);
800
        $line .= $check->data->isWhitelisted ? Console::text(' ★', 'green') : ''; 
801
        Console::log($line);
802
       
803
        self::printResult(Console::pad('   Country code:', 23), $check->data->countryCode, $defaultColor);
804
        
805
        if (!empty($check->data->countryName)){
806
            self::printResult(Console::pad('   Country name:', 23), $check->data->countryName, $defaultColor);
807
        }
808
809
        self::printResult(Console::pad('   ISP:', 23), $check->data->isp, $defaultColor);
810
811
        if ($check->data->usageType){
812
            $line = self::printResult(Console::pad('   Usage type:', 23), $check->data->usageType, $defaultColor, '', false);
813
            $line .= $check->data->usageType === 'Reserved' ? Console::text(' ◆', 'green') : '';
814
            Console::log($line);
815
        }
816
817
        $hostames = implode(', ', array_filter($check->data->hostnames)) ?? null;
818
        if (!empty($hostames)){
819
            self::printResult(Console::pad('   Hostname(s):', 23), $hostames, $defaultColor);
820
        }
821
822
        self::printResult(Console::pad('   Domain:', 23), $check->data->domain, $defaultColor);
823
824
        $nbReport = $check->data->totalReports && is_numeric($check->data->totalReports) ? intval($check->data->totalReports) : 0;
825
        
826
        if ($nbReport > 0 ){
827
            $line  = self::printResult(Console::pad('   Total reports:', 23), $nbReport, $defaultColor, '', false);
828
            $line .= self::printResult(' from ', $check->data->numDistinctUsers, $defaultColor, '', false);
829
            $line .= Console::text($nbReport > 0 ? ' distinct users': ' user', 'white');
830
            Console::log($line);
831
832
        } else {
833
            // no reports
834
            $day = $maxAge > 1 ? 'in last '. $maxAge . ' days': ' today';
835
            Console::log( Console::text('   ✓', 'green') . Console::text(' Not reported ' . $day));
836
        }
837
        
838
        if (!empty($check->data->lastReportedAt)){
839
            self::printResult(Console::pad('   Last reported at:', 23), self::getDate($check->data->lastReportedAt), $defaultColor);
840
        }
841
842
        // print last reports
843
        if ($verbose){
844
            $nbLastReports = isset($check->data->reports) ? count($check->data->reports) : 0;
845
            
846
            if ($nbLastReports > 0){
847
                Console::log('   Last reports:', 'white');
848
                $numberDiplayedReports = 0;
849
                $defaultColor = 'lightyellow'; // reset color for last reports
850
            
851
                foreach ($check->data->reports as $lastReport){
852
                    $categories = [];
853
                    foreach (array_filter($lastReport->categories) as $catId){
854
                        $cat = self::$api->getCategoryNamebyId($catId)[0];
855
                        if ($cat !== false) {
856
                            $categories[] = $cat;
857
                        }
858
                    }
859
860
                    $line  = Console::text('    →', $defaultColor);
861
                    $line .= self::printResult(' reported at: ', self::getDate($lastReport->reportedAt), $defaultColor, '', false);
862
              //    $line .= self::printResult(' by user: ', $lastReport->reporterId, $defaultColor, '', false);
863
                    if (isset($lastReport->reporterCountryCode) && isset($lastReport->reporterCountryName)){
864
                        $line .= Console::text(' from: ', 'white');
865
                        $line .= self::printResult('', $lastReport->reporterCountryCode, $defaultColor, '', false);
866
                        $line .= Console::text(' - ', 'white');
867
                        $line .= self::printResult('', $lastReport->reporterCountryName, $defaultColor, '', false);
868
                    }
869
                    $line .= Console::text(' with categor' .  (count($categories) > 1 ? "ies: " : "y: "), 'white');
870
                    foreach ($categories as $key => $cat) {
871
                        $line .= Console::text($key==0 ? '' : ',' , 'white') . Console::text($cat, $defaultColor);
872
                    }
873
                    Console::log($line);
874
875
                    // counter
876
                    $numberDiplayedReports++;
877
                    if ($numberDiplayedReports === $maxReportsNumber || $numberDiplayedReports === $nbLastReports) {
878
                        $line  = Console::text('      (', 'white');
879
                        $line .= Console::text($numberDiplayedReports, $defaultColor);
880
                        $line .= Console::text('/', 'white');
881
                        $line .= Console::text($nbLastReports, $defaultColor);
882
                        $line .= Console::text($numberDiplayedReports > 1 ? ' reports displayed)': ' report displayed)', 'white');
883
                        Console::log($line);
884
                        break;
885
                    }
886
                }
887
            }
888
        }
889
890
        // footer
891
        Console::log();
892
        self::printFooter($time);
893
    }
894
895
}