Completed
Push — master ( 138995...8cf48b )
by Kris
14s queued 11s
created

AbuseIPDBClient   F

Complexity

Total Complexity 103

Size/Duplication

Total Lines 870
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 460
c 1
b 0
f 0
dl 0
loc 870
rs 2
wmc 103

13 Methods

Rating   Name   Duplication   Size   Complexity  
B checkBlock() 0 74 10
A reportIP() 0 35 3
B loadJsonFile() 0 20 7
F start() 0 83 12
F checkIP() 0 127 29
A printCategories() 0 35 3
C bulkReport() 0 55 11
A fromConfigFile() 0 24 5
B checkForInstall() 0 33 7
B getBlacklist() 0 61 11
A clearIP() 0 31 2
A printConfig() 0 15 2
B printHelp() 0 105 1

How to fix   Complexity   

Complex Class

Complex classes like AbuseIPDBClient often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use AbuseIPDBClient, and based on these observations, apply Extract Interface, too.

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.9
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:','version'];
42
    
43
    /**
44
     * @var string      $version
45
     */
46
    const VERSION = 'v0.9.9'; 
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
     * @param string    $keyPath        The key file path
65
     * 
66
     * @return void
67
     */
68
    public static function start(array $arguments, string $keyPath)
69
    {
70
        // prints help, (no need install) ?
71
        if (self::inArguments($arguments, 'h', 'help')){
72
            self::printBanner();
73
            self::printHelp();
74
            self::safeExit();
75
        }
76
        // prints version?  (note: no short arg)
77
        if (self::inArguments($arguments, 'version', 'version')){
78
            self::printVersion();
79
            self::safeExit();
80
        }
81
82
        // get key path from current script location (supposed in a bin folder)
83
        // and check for install then create a new instance of \ApiHandler
84
        self::$keyPath = $keyPath; // dirname(get_included_files()[0]) . '/../config/key.json';
85
        self::validate( self::checkForInstall(), 'Key file missing.');
86
        try {
87
            self::$api = self::fromConfigFile(self::$keyPath);
88
        } catch (\Exception $e) {
89
            self::error($e->getMessage());
90
            self::printFooter();
91
            self::safeExit(1);
92
        }
93
    
94
        // required at least one valid argument
95
        self::validate( !empty($arguments), 'No valid arguments given. Run abuseipdb --help to get help.');
96
97
98
        // prints config ?
99
        if (self::inArguments($arguments, 'G', 'config')){
100
            self::printConfig();
101
            self::safeExit();
102
        } 
103
104
        // prints catgeories ?
105
        if (self::inArguments($arguments, 'L', 'list')){
106
            self::printCategories();
107
            self::safeExit();
108
        } 
109
        
110
        // check request ?
111
        if (self::inArguments($arguments, 'C', 'check')){
112
            self::checkIP($arguments);
113
            self::safeExit();
114
        }
115
       
116
        // check-block request ?
117
        if (self::inArguments($arguments, 'K', 'check-block')){
118
            self::checkBlock($arguments);
119
            self::safeExit();
120
        }
121
122
        // report request ?
123
        if (self::inArguments($arguments, 'R', 'report')){
124
            self::reportIP($arguments);
125
            self::safeExit();
126
        }
127
128
        // report request ?
129
        if (self::inArguments($arguments, 'V', 'bulk-report')){
130
            self::bulkReport($arguments);
131
            self::safeExit();
132
        }
133
134
        // report request ?
135
        if (self::inArguments($arguments, 'B', 'blacklist')){
136
            self::getBlacklist($arguments);
137
            self::safeExit();
138
        }
139
140
        // report request ?
141
        if (self::inArguments($arguments, 'E', 'clear')){
142
            self::clearIP($arguments);
143
            self::safeExit();
144
        }
145
146
        // no valid arguments given, close program
147
        Console::log();   
148
        self::error('invalid arguments. Run abuseipdb --help to get help.');
149
        self::printFooter();
150
        self::safeExit(1);
151
    }
152
153
    /**
154
     * Get a new instance of ApiHandler with config stored in a Json file
155
     * 
156
     * @access public 
157
     * @static
158
     * @param string    $configPath     The configuration file path
159
     * 
160
     * @return \Kristuff\AbuseIPDB\ApiHandler
161
     * @throws \InvalidArgumentException                        If the given file does not exist
162
     * @throws \Kristuff\AbuseIPDB\InvalidPermissionException   If the given file is not readable 
163
     */
164
    public static function fromConfigFile(string $configPath)
165
    {
166
        // check file exists
167
        if (!file_exists($configPath) || !is_file($configPath)){
168
            throw new \InvalidArgumentException('The file [' . $configPath . '] does not exist.');
169
        }
170
171
        // check file is readable
172
        if (!is_readable($configPath)){
173
            throw new InvalidPermissionException('The file [' . $configPath . '] is not readable.');
174
        }
175
176
        $keyConfig = self::loadJsonFile($configPath);
177
        $selfIps = [];
178
        
179
        // Look for other optional config files in the same directory 
180
        $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

180
        $selfIpsConfigPath = /** @scrutinizer ignore-type */ pathinfo($configPath, PATHINFO_DIRNAME) . DIRECTORY_SEPARATOR . 'self_ips.json';
Loading history...
181
        if (file_exists($selfIpsConfigPath)){
182
            $selfIps = self::loadJsonFile($selfIpsConfigPath)->self_ips;
183
        }
184
185
        $app = new SilentApiHandler($keyConfig->api_key, $selfIps);
186
        
187
        return $app;
188
    }
189
190
    /** 
191
     * Load and returns decoded Json from given file  
192
     *
193
     * @access public
194
     * @static
195
	 * @param string    $filePath       The file's full path
196
	 * @param bool      $throwError     Throw error on true or silent process. Default is true
197
     *  
198
	 * @return object|null 
199
     * @throws \Exception
200
     * @throws \LogicException
201
     */
202
    protected static function loadJsonFile(string $filePath, bool $throwError = true)
203
    {
204
        // check file exists
205
        if (!file_exists($filePath) || !is_file($filePath)){
206
           if ($throwError) {
207
                throw new \Exception('Config file not found');
208
           }
209
           return null;  
210
        }
211
212
        // get and parse content
213
        $content = utf8_encode(file_get_contents($filePath));
214
        $json    = json_decode($content);
215
216
        // check for errors
217
        if ($json == null && json_last_error() != JSON_ERROR_NONE && $throwError) {
218
            throw new \LogicException(sprintf("Failed to parse config file Error: '%s'", json_last_error_msg()));
219
        }
220
221
        return $json;        
222
    }
223
224
    /**
225
     * Check for install
226
     * 
227
     * @access protected
228
     * @static
229
     * 
230
     * @return bool
231
     */
232
    protected static function checkForInstall()
233
    {
234
        if (file_exists(self::$keyPath)) {
235
            return true;
236
        }
237
        
238
        // not installed
239
        self::printBanner();
240
        Console::log(' Your config key file was not found. Do you want to create it? ', 'white');
241
        $create =  Console::ask(' Press Y/y to create a config key file: ', 'white');
242
            
243
        if ($create == 'Y' || $create == 'y') {
244
            $key =     Console::ask(' - Please enter your api key: ', 'white');
245
            $create =  Console::ask(' A config file will be created in config/ directory. Press Y/y to continue: ', 'white');
246
            
247
            if ($create == 'Y' || $create == 'y') {
248
                $data = json_encode(['api_key' => $key]);
249
                
250
                if (file_put_contents(self::$keyPath, $data, LOCK_EX) === false){
251
                    self::error('An error occured during writing config file. Make sure to give the appropriate permissions do the config directory.');
252
                    return false;
253
                }
254
255
                // successfull. print message and exit to prevent errors with no arguments 
256
                Console::log();
257
                Console::log(Console::text('  ✓ ', 'green') . Console::text('Your config file has been successfully created.', 'white'));
258
                Console::log('    You can now use abuseipdb.', 'white');
259
                Console::log();
260
                self::safeExit();
261
            }
262
        }
263
        // no key file, not created
264
        return false;    
265
    }
266
 
267
    /**
268
     * Prints the help
269
     * 
270
     * @access protected
271
     * @static
272
     * 
273
     * @return void
274
     */
275
    protected static function printHelp()
276
    {
277
        Console::log(' ' . Console::text('SYNOPSIS:', 'white', 'underline')); 
278
        Console::log(' ' . Console::text('    abuseipdb -C ') . 
279
                           Console::text('ip', 'yellow') . 
280
                           Console::text(' [-d ') . 
281
                           Console::text('days', 'yellow') . 
282
                           Console::text('] [-v] [-l ') . 
283
                           Console::text('limit', 'yellow') . 
284
                           Console::text(']')); 
285
286
        Console::log(' ' . Console::text('    abuseipdb -K ') . 
287
                           Console::text('network', 'yellow') . 
288
                           Console::text(' [-d ') . 
289
                           Console::text('days', 'yellow') . 
290
                           Console::text(']')); 
291
292
        Console::log(' ' . Console::text('    abuseipdb -R ' .
293
                           Console::text('ip', 'yellow') . ' -c ' .
294
                           Console::text('categories', 'yellow') . ' -m ' .
295
                           Console::text('message', 'yellow'))); 
296
297
        Console::log(' ' . Console::text('    abuseipdb -V ' .
298
                           Console::text('path', 'yellow')));
299
300
        Console::log(' ' . Console::text('    abuseipdb -E ' .
301
                           Console::text('ip', 'yellow')));
302
                           
303
        Console::log(' ' . Console::text('    abuseipdb -B ') . 
304
                           Console::text('[-l ') . 
305
                           Console::text('limit', 'yellow') . 
306
                           Console::text('] [-s ') . 
307
                           Console::text('score', 'yellow') . 
308
                           Console::text('] [-p ') . 
309
                           Console::text('', 'yellow') . 
310
                           Console::text(']')); 
311
312
        Console::log(' ' . Console::text('    abuseipdb -L '));
313
        Console::log(' ' . Console::text('    abuseipdb -G '));
314
        Console::log(' ' . Console::text('    abuseipdb -h '));
315
                           
316
        Console::log();    
317
        Console::log(' ' . Console::text('OPTIONS:', 'white', 'underline')); 
318
        Console::log();
319
        Console::log(Console::text('   -h, --help', 'white')); 
320
        Console::log('       Prints the current help. If given, all next arguments are ignored.', 'lightgray');
321
        Console::log();    
322
        Console::log(Console::text('   -G, --config', 'white')); 
323
        Console::log('       Prints the current config. If given, all next arguments are ignored.', 'lightgray');
324
        Console::log();    
325
        Console::log(Console::text('   -L, --list', 'white')); 
326
        Console::log('       Prints the list report categories. If given, all next arguments are ignored.', 'lightgray');
327
        Console::log();    
328
        Console::log(Console::text('   -C, --check ', 'white') . Console::text('ip', 'yellow', 'underline')); 
329
        Console::log('       Performs a check request for the given IP address. A valid IPv4 or IPv6 address is required.', 'lightgray');
330
        Console::log();    
331
        Console::log(Console::text('   -K, --check-block ', 'white') . Console::text('network', 'yellow', 'underline')); 
332
        Console::log('       Performs a check-block request for the given network. A valid subnet (v4 or v6) denoted with ', 'lightgray');
333
        Console::log('       CIDR notation is required.', 'lightgray');
334
        Console::log();    
335
        Console::log(Console::text('   -d, --days ', 'white') . Console::text('days', 'yellow', 'underline')); 
336
        Console::log('       For a check or check-block request, defines the maxAgeDays. Min is 1, max is 365, default is 30.', 'lightgray');
337
        Console::log();    
338
        Console::log(Console::text('   -R, --report ', 'white') . Console::text('ip', 'yellow', 'underline')); 
339
        Console::log('       Performs a report request for the given IP address. A valid IPv4 or IPv6 address is required.', 'lightgray');
340
        Console::log();    
341
        Console::log(Console::text('   -V, --bulk-report ', 'white') . Console::text('path', 'yellow', 'underline')); 
342
        Console::log('       Performs a bulk-report request sending a csv file. A valid file name or full path is required.', 'lightgray');
343
        Console::log();    
344
        Console::log(Console::text('   -E, --clear ', 'white')); 
345
        Console::log('       Remove own reports for the given IP address. A valid IPv4 or IPv6 address is required.', 'lightgray');
346
        Console::log();
347
        Console::log(Console::text('   -c, --categories ', 'white') . Console::text('categories', 'yellow', 'underline')); 
348
        Console::log('       For a report request, defines the report category(ies). Categories must be separate by a comma.', 'lightgray');
349
        Console::log('       Some categories cannot be used alone. A category can be represented by its shortname or by its', 'lightgray');
350
        Console::log(Console::text('       id. Use ','lightgray')  . Console::text('abuseipdb -L', 'white') . Console::text(' to print the categories list.','lightgray'));
351
        Console::log();    
352
        Console::log(Console::text('   -m, --message ', 'white') . Console::text('message', 'yellow', 'underline')); 
353
        Console::log('       For a report request, defines the message to send with report. Message is required for all', 'lightgray');
354
        Console::log('       report requests.', 'lightgray');
355
        Console::log();
356
        Console::log(Console::text('   -B, --blacklist ', 'white')); 
357
        Console::log('       Performs a blacklist request. Default limit is 1000. This limit can ne changed with the', 'lightgray');
358
        Console::log('       ' . Console::text('--limit', 'white') . Console::text(' parameter. ', 'lightgray'));
359
        Console::log();    
360
        Console::log(Console::text('   -l, --limit ', 'white') . Console::text('limit', 'yellow', 'underline')); 
361
        Console::log('       For a blacklist request, defines the limit.', 'lightgray');
362
        Console::log('       For a check request with verbose flag, sets the max number of last reports displayed. Default is 10', 'lightgray');
363
        Console::log('       For a check-block request, sets the max number of IPs displayed. Default is 0 (no limit).', 'lightgray');
364
        Console::log();    
365
        Console::log(Console::text('   -p, --plaintext ', 'white')); 
366
        Console::log('       For a blacklist request, output only ip list as plain text.', 'lightgray');
367
        Console::log();    
368
        Console::log(Console::text('   -s, --score ', 'white')); 
369
        Console::log('       For a blacklist request, sets the confidence score minimum. The confidence minimum ', 'lightgray');
370
        Console::log('       must be between 25 and 100. This parameter is subscriber feature (not honored otherwise, allways 100).', 'lightgray');
371
        Console::log();    
372
        Console::log(Console::text('   -v, --verbose ', 'white')); 
373
        Console::log('       For a check request, display additional fields like the x last reports. This increases ', 'lightgray');
374
        Console::log(Console::text('       request time and response size. Max number of last reports displayed can be changed with the ', 'lightgray'));
375
        Console::log('       ' . Console::text('--limit', 'white') . Console::text(' parameter. ', 'lightgray'));
376
        Console::log();    
377
        Console::log(Console::text('   --version', 'white')); 
378
        Console::log('       Prints the current version. If given, all next arguments are ignored.', 'lightgray');
379
        Console::log();    
380
    }
381
382
    /**
383
     * Prints the current config
384
     * 
385
     * @access protected
386
     * @static
387
     * 
388
     * @return void
389
     */
390
    protected static function printConfig()
391
    {
392
        $conf = self::$api->getConfig();
393
394
        self::printTitle(Console::text('  ► Current configuration ', 'darkgray'));
395
        
396
        Console::log(Console::text('  api_key:[', 'white') . Console::text($conf['apiKey'], 'green') . Console::text(']', 'white'));
397
        Console::log(Console::text('  self_ips:', 'white'));
398
        
399
        foreach ($conf['selfIps'] as $ip) {
400
            Console::log(Console::text('    [', 'white') . Console::text($ip, 'green') . Console::text(']', 'white'));   
401
        }
402
403
        Console::log();   
404
        self::printFooter();
405
    }
406
407
    /**
408
     * Prints the report categories list
409
     * 
410
     * @access protected
411
     * @static
412
     * 
413
     * @return void
414
     */
415
    protected static function printCategories()
416
    {
417
        self::printTitle(Console::text('  ► Report categories list ', 'darkgray'));
418
419
        $categories = self::$api->getCategories();
420
        $rowHeaders = [
421
            Console::text('ShortName',      'darkgray') => 15, 
422
            Console::text('Id',             'darkgray') => 2, 
423
            Console::text('Full name',      'darkgray') => 18,
424
            Console::text('Can be alone?',  'darkgray') => 15
425
        ];
426
        Console::$verticalSeparator = '  ';
427
        Console::$verticalInnerSeparator = '  ';
428
        Console::log(Console::tableRowSeparator($rowHeaders, 'darkgray'));
429
        Console::log(Console::tableRow($rowHeaders));      
430
        Console::log(Console::tableRowSeparator($rowHeaders), 'darkgray');
431
        
432
        foreach ($categories as $cat) {
433
            $id = Console::text($cat[1], 'white');
434
            $standalone = $cat[3] ? Console::text('✓', 'green') . Console::text(' true ', 'lightgray') : 
435
                                    Console::text('✗', 'red')   . Console::text(' false', 'darkgray');
436
            $shortName =  Console::text($cat[0], 'white');
437
            $fullName =   Console::text($cat[2], 'lightgray');
438
439
            Console::log(
440
                Console::TableRowStart().  
0 ignored issues
show
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...
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

440
                /** @scrutinizer ignore-type */ Console::TableRowStart().  
Loading history...
441
                Console::TableRowCell( $shortName , 15).  
442
                Console::TableRowCell( $id , 2, Console::ALIGN_CENTER).  
443
                Console::TableRowCell( $fullName , 18).  
444
                Console::TableRowCell( $standalone , 15,  Console::ALIGN_CENTER)  
445
            );
446
        }
447
        //Console::log(Console::tableRowSeparator($rowHeaders), 'darkgray');
448
        Console::log();
449
        self::printFooter();
450
    }
451
452
    /**
453
     * Perform a report request 
454
     * 
455
     * @access protected
456
     * @static
457
     * @param array $arguments
458
     * 
459
     * @return void
460
     */
461
    protected static function reportIP(array $arguments)
462
    {
463
        $ip      = self::getArgumentValue($arguments,'R', 'report');
464
        $cats    = self::getArgumentValue($arguments,'c', 'categories');
465
        $message = self::getArgumentValue($arguments,'m', 'message');
466
        
467
        self::printTitle(Console::text('  ► Report IP: ', 'darkgray') . Console::text(escapeshellcmd($ip), 'white'));
468
        self::printTempMessage();
469
470
        // Peforms request 
471
        $timeStart = microtime(true);
472
        $report = self::$api->report($ip, $cats, $message)->getObject();     
473
        $timeEnd = microtime(true);
474
        $time = $timeEnd - $timeStart; // request time
475
        self::clearTempMessage();
476
477
        // check for errors / empty response
478
        if (self::printErrors($report)){
479
            self::printFooter();
480
            self::safeExit(1);
481
        }
482
        
483
        // ✓ Done: print reported IP and confidence score
484
        $score = empty($report->data->abuseConfidenceScore) ? 0 : $report->data->abuseConfidenceScore;
485
        $scoreColor = self::getScoreColor($score);
486
        Console::log(
487
            Console::text('   ✓', 'green') . 
488
            Console::text(' IP: [', 'white') .
489
            Console::text($ip, $scoreColor) .
490
            Console::text('] successfully reported', 'white')
491
        );
492
        Console::log(Console::text('     Confidence score: ', 'white') . self::getScoreBadge($score));
493
494
        Console::log();
495
        self::printFooter($time);
496
    }
497
498
    /**
499
     * Perform a bulk-report request 
500
     * 
501
     * @access protected
502
     * @static
503
     * @param array $arguments
504
     * 
505
     * @return void
506
     */
507
    protected static function bulkReport(array $arguments)
508
    {
509
        $fileName = self::getArgumentValue($arguments,'V', 'bulk-report');
510
511
        self::printTitle(Console::text('  ► Bulk report for file: ', 'darkgray') . Console::text(escapeshellcmd($fileName), 'white'));
512
        self::printTempMessage();
513
514
        // Peforms request 
515
        $timeStart = microtime(true);  
516
        $response = self::$api->bulkReport($fileName)->getObject();     
517
        $timeEnd = microtime(true);      
518
        $time = $timeEnd - $timeStart;  // request time
519
        self::clearTempMessage();
520
521
        // check for errors / empty response
522
        if (self::printErrors($response)){
523
            self::printFooter();
524
            self::safeExit(1);
525
        }
526
527
        // ✓ Done
528
        Console::log(
529
            Console::text('   Bulk report for file: [', 'white') .
530
            Console::text($fileName, 'lightyellow') .
531
            Console::text('] done!', 'white')
532
        );
533
534
        $nbErrorReports = isset($response->data->invalidReports) ? count($response->data->invalidReports) : 0;
535
        $nbSavedReports = isset($response->data->savedReports) ? $response->data->savedReports : 0;
536
        $savedColor = $nbSavedReports > 0 ? 'green' : 'red';
537
        $errorColor = $nbErrorReports > 0 ? 'red' : 'green';
538
        $savedIcon  = $nbSavedReports > 0 ? '✓' : '✗';
539
        $errorIcon  = $nbErrorReports > 0 ? '✗' : '✓';
540
541
        Console::log(Console::text('   ' . $savedIcon, $savedColor) . self::printResult(' Saved reports:    ', $nbSavedReports, $savedColor, '', false));
542
        Console::log(Console::text('   ' . $errorIcon, $errorColor) . self::printResult(' Invalid reports:  ', $nbErrorReports, $errorColor, '', false));
543
544
        if ($nbErrorReports > 0){
545
            $numberDiplayedReports = 0;
546
            $defaultColor = 'lightyellow'; // reset color for last reports
547
        
548
            foreach ($response->data->invalidReports as $report){
549
                $input = $report->input ? escapeshellcmd($report->input) : ''; // in case on blank line, IP is null
550
                $line  = Console::text('      →', 'red');
551
                $line .= self::printResult(' Input:         ', $input, $defaultColor, '', false);
552
                Console::log($line);
553
                self::printResult('        Error:         ', $report->error, $defaultColor);
554
                self::printResult('        Line number:   ', $report->rowNumber, $defaultColor);
555
                
556
                // counter
557
                $numberDiplayedReports++;
558
            }
559
        }
560
        Console::log();
561
        self::printFooter($time);
562
    }
563
564
    /**
565
     * Perform a clear-address request 
566
     * 
567
     * @access protected
568
     * @static
569
     * @param array $arguments
570
     * 
571
     * @return void
572
     */
573
    protected static function clearIP(array $arguments)
574
    {
575
        $ip      = self::getArgumentValue($arguments,'E', 'clear');
576
577
        self::printTitle(Console::text('  ► Clear reports for IP: ', 'darkgray') . Console::text(escapeshellcmd($ip), 'white'));
578
579
        // Peforms request 
580
        self::printTempMessage();
581
        $timeStart = microtime(true); // request startime 
582
        $response = self::$api->clearAddress($ip)->getObject();     
583
        $timeEnd = microtime(true);  // request end time 
584
        $time = $timeEnd - $timeStart; // request time
585
        self::clearTempMessage();
586
587
        // check for errors / empty response
588
        if (self::printErrors($response)){
589
            self::printFooter($time);
590
            self::safeExit(1);
591
        }
592
593
        // ✓ Done: print deleted report number 
594
        Console::log(
595
            Console::text('   ✓', 'green') . 
596
            Console::text(' Successfull clear request for IP: [', 'white') .
597
            Console::text($ip, 'lightyellow') .
598
            Console::text(']', 'white')
599
        );
600
        
601
        self::printResult('     Deleted reports: ', $response->data->numReportsDeleted ?? 0, 'lightyellow');
602
        Console::log();
603
        self::printFooter($time);
604
    }
605
606
    /**
607
     * Perform a blacklist request 
608
     * 
609
     * @access protected
610
     * @static
611
     * @param array $arguments
612
     * 
613
     * @return void
614
     */
615
    protected static function getBlacklist(array $arguments)
616
    {
617
        $plainText  = self::inArguments($arguments,'p','plaintext');  
618
619
        if (!$plainText){
620
            self::printTitle(Console::text('  ► Get Blacklist ', 'darkgray'));
621
        }
622
623
        $limit      = self::getNumericParameter($arguments,'l', 'limit', 1000);
624
        $scoreMin   = self::getNumericParameter($arguments,'s', 'score', 100);
625
626
        if (!$plainText){
627
            self::printTempMessage();
628
        }
629
630
        // do request 
631
        $timeStart = microtime(true);           // request startime 
632
        $response = self::$api->blacklist($limit, $plainText, $scoreMin);     // perform request
633
        $timeEnd = microtime(true);                         // request end time 
634
        $time = $timeEnd - $timeStart;                      // request time
635
636
        if (!$plainText){
637
            self::clearTempMessage();
638
        }
639
640
        // response could be json on error, while plaintext flag is set
641
        $decodedResponse = $response->getObject();
642
        
643
        if ($plainText && $response->hasError()){
644
            self::safeExit(1);
645
        }
646
647
        if (!$plainText && self::printErrors($decodedResponse)){
648
            self::printFooter($time);
649
            self::safeExit(1);
650
        }
651
652
        if ($plainText){
653
            // echo response "as is"
654
            Console::log($response->getPlaintext());
655
656
        } else {
657
            // print list
658
            self::printResult('  List generated at: ', self::getDate($decodedResponse->meta->generatedAt), 'lightyellow', '');
659
            Console::log();
660
661
            foreach ($decodedResponse->data as $report){
662
                $score = empty($report->abuseConfidenceScore) ? 0 : $report->abuseConfidenceScore;
663
                $defaultColor = self::getScoreColor($score);
664
665
                $line  = Console::text('    →', $defaultColor);
666
                $line .= self::printResult(' IP: ', $report->ipAddress, $defaultColor, '', false);
667
                $line .= self::printResult(' | Last reported at: ', self::getDate($report->lastReportedAt), $defaultColor, '', false);
668
                $line .= Console::text(' | Confidence score: ', 'white');
669
                $line .= self::getScoreBadge($score);
670
                Console::log($line);
671
            }
672
        
673
            // footer
674
            Console::log();
675
            self::printFooter($time);
676
        }
677
    }
678
679
    /**
680
     * Perform a check-block request 
681
     * 
682
     * @access protected
683
     * @static
684
     * @param array $arguments
685
     * 
686
     * @return void
687
     */
688
    protected static function checkBlock($arguments)
689
    {
690
        $network  = self::getArgumentValue($arguments,'K', 'check-block');
691
692
        self::printTitle(Console::text('  ► Check network: ', 'darkgray') . Console::text(escapeshellcmd($network), 'white') . Console::text('', 'darkgray'));
693
694
        $maxAge   = self::getNumericParameter($arguments, 'd', 'days', 30);
695
        $limit    = self::getNumericParameter($arguments,'l', 'limit', 0); // 0 mean no limit
696
697
        self::printTempMessage();
698
699
        $timeStart = microtime(true);                                       
700
        $check = self::$api->checkBlock($network, $maxAge)->getObject();
701
        $timeEnd = microtime(true);
702
        $time = $timeEnd - $timeStart; // request time
703
        self::clearTempMessage();
704
705
        // check for errors / empty response
706
        if (self::printErrors($check)){
707
            self::printFooter($time);
708
            self::safeExit(1);
709
        }
710
711
        self::printResult(Console::pad('   Network Address:', 23), $check->data->networkAddress, 'lightyellow');
712
        self::printResult(Console::pad('   Netmask:', 23), $check->data->netmask, 'lightyellow');
713
        self::printResult(Console::pad('   Min Address:', 23), $check->data->minAddress, 'lightyellow');
714
        self::printResult(Console::pad('   Max Address:', 23), $check->data->maxAddress, 'lightyellow');
715
        self::printResult(Console::pad('   Possible Hosts:', 23), $check->data->numPossibleHosts, 'lightyellow');
716
        self::printResult(Console::pad('   Address SpaceDesc:', 23), $check->data->addressSpaceDesc, 'lightyellow');
717
718
        // print reported addresses
719
        $nbReports = isset($check->data->reportedAddress) ? count($check->data->reportedAddress) : 0;
720
        
721
        if ($nbReports > 0){
722
            self::printResult(Console::pad('   Reported addresses:', 23), $nbReports, 'lightyellow');
723
            $numberDiplayedReports = 0;
724
            $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...
725
        
726
            foreach ($check->data->reportedAddress as $report){
727
                $score = empty($report->abuseConfidenceScore) ? 0 : $report->abuseConfidenceScore;
728
                $defaultColor = self::getScoreColor($score); // color based on score
729
730
                $line  = Console::text('   →', $defaultColor);
731
                $line .= self::printResult(' IP: ', $report->ipAddress, $defaultColor, '', false);
732
                $line .= self::printResult(' Country: ', $report->countryCode , $defaultColor, '', false);
733
                $line .= Console::text(' | Confidence score: ', 'white');
734
                $line .= self::getScoreBadge($score);
735
                $line .= self::printResult(' Total reports: ', $report->numReports, $defaultColor, '', false);
736
                $line .= self::printResult(' Last reported at: ', self::getDate($report->mostRecentReport), $defaultColor, '', false);
737
                Console::log($line);
738
739
                // counter
740
                $numberDiplayedReports++;
741
742
                if ($numberDiplayedReports === $limit || $numberDiplayedReports === $nbReports) {
743
                    $line  = Console::text('      (', 'white');
744
                    $line .= Console::text($numberDiplayedReports, 'lightyellow');
745
                    $line .= Console::text('/', 'white');
746
                    $line .= Console::text($nbReports, 'lightyellow');
747
                    $line .= Console::text($numberDiplayedReports > 1 ? ' IPs displayed)': ' IP displayed)', 'white');
748
                    Console::log($line);
749
                    break;
750
                }
751
            }
752
753
        } else {
754
            // no reports
755
            $day = $maxAge > 1 ? 'in last '. $maxAge . ' days': ' today';
756
            Console::log( Console::text('    ✓', 'green') . Console::text(' No IP reported ' . $day));
757
        }
758
759
        // footer
760
        Console::log();
761
        self::printFooter($time);
762
    }
763
764
    /**
765
     * Perform a check request 
766
     * 
767
     * @access protected
768
     * @static
769
     * @param array $arguments
770
     * 
771
     * @return void
772
     */
773
    protected static function checkIP($arguments)
774
    {
775
        $ip                 = self::getArgumentValue($arguments,'C', 'check');
776
777
        self::printTitle(Console::text('  ► Check IP: ', 'darkgray') . Console::text(escapeshellcmd($ip), 'white') . Console::text('', 'darkgray'));
778
779
        $verbose            = self::inArguments($arguments,'v', 'verbose');
780
        $maxAge             = self::getNumericParameter($arguments, 'd', 'days', 30);
781
        $maxReportsNumber   = self::getNumericParameter($arguments,'l', 'limit', 10);
782
783
        self::printTempMessage();
784
785
        $timeStart = microtime(true);                                           
786
        $check = self::$api->check($ip, $maxAge, $verbose)->getObject();        
787
        $timeEnd = microtime(true);                                              
788
        $time = $timeEnd - $timeStart; // request time
789
        self::clearTempMessage();
790
791
        // check for errors / empty response
792
        if (self::printErrors($check)){
793
            self::printFooter($time);
794
            self::safeExit(1);
795
        }
796
797
        // score and data color (depending of abuseConfidenceScore)
798
        $score = empty($check->data->abuseConfidenceScore) ? 0 : $check->data->abuseConfidenceScore;
799
        $defaultColor = self::getScoreColor($score);
800
        $line = Console::text(Console::pad('   Confidence score:', 23), 'white');
801
        $line .= self::getScoreBadge($score);
802
        Console::log($line);
803
      
804
//      self::printResult('   isPublic', $check->data->isPublic, $defaultColor);
805
//      self::printResult('   ipVersion', $check->data->ipVersion, $defaultColor);
806
        $line = self::printResult(Console::pad('   Whitelisted:', 23), $check->data->isWhitelisted ? 'true': 'false', $defaultColor, '', false);
807
        $line .= $check->data->isWhitelisted ? Console::text(' ★', 'green') : ''; 
808
        Console::log($line);
809
       
810
        self::printResult(Console::pad('   Country code:', 23), $check->data->countryCode, $defaultColor);
811
        
812
        if (!empty($check->data->countryName)){
813
            self::printResult(Console::pad('   Country name:', 23), $check->data->countryName, $defaultColor);
814
        }
815
816
        self::printResult(Console::pad('   ISP:', 23), $check->data->isp, $defaultColor);
817
818
        if ($check->data->usageType){
819
            $line = self::printResult(Console::pad('   Usage type:', 23), $check->data->usageType, $defaultColor, '', false);
820
            $line .= $check->data->usageType === 'Reserved' ? Console::text(' ◆', 'green') : '';
821
            Console::log($line);
822
        }
823
824
        $hostames = implode(', ', array_filter($check->data->hostnames)) ?? null;
825
        if (!empty($hostames)){
826
            self::printResult(Console::pad('   Hostname(s):', 23), $hostames, $defaultColor);
827
        }
828
829
        self::printResult(Console::pad('   Domain:', 23), $check->data->domain, $defaultColor);
830
831
        $nbReport = $check->data->totalReports && is_numeric($check->data->totalReports) ? intval($check->data->totalReports) : 0;
832
        
833
        if ($nbReport > 0 ){
834
            $line  = self::printResult(Console::pad('   Total reports:', 23), $nbReport, $defaultColor, '', false);
835
            $line .= self::printResult(' from ', $check->data->numDistinctUsers, $defaultColor, '', false);
836
            $line .= Console::text($nbReport > 0 ? ' distinct users': ' user', 'white');
837
            Console::log($line);
838
839
        } else {
840
            // no reports
841
            $day = $maxAge > 1 ? 'in last '. $maxAge . ' days': ' today';
842
            Console::log( Console::text('   ✓', 'green') . Console::text(' Not reported ' . $day));
843
        }
844
        
845
        if (!empty($check->data->lastReportedAt)){
846
            self::printResult(Console::pad('   Last reported at:', 23), self::getDate($check->data->lastReportedAt), $defaultColor);
847
        }
848
849
        // print last reports
850
        if ($verbose){
851
            $nbLastReports = isset($check->data->reports) ? count($check->data->reports) : 0;
852
            
853
            if ($nbLastReports > 0){
854
                Console::log('   Last reports:', 'white');
855
                $numberDiplayedReports = 0;
856
                $defaultColor = 'lightyellow'; // reset color for last reports
857
            
858
                foreach ($check->data->reports as $lastReport){
859
                    $categories = [];
860
                    foreach (array_filter($lastReport->categories) as $catId){
861
                        $cat = self::$api->getCategoryNamebyId($catId)[0];
862
                        if ($cat !== false) {
863
                            $categories[] = $cat;
864
                        }
865
                    }
866
867
                    $line  = Console::text('    →', $defaultColor);
868
                    $line .= self::printResult(' reported at: ', self::getDate($lastReport->reportedAt), $defaultColor, '', false);
869
              //    $line .= self::printResult(' by user: ', $lastReport->reporterId, $defaultColor, '', false);
870
                    if (isset($lastReport->reporterCountryCode) && isset($lastReport->reporterCountryName)){
871
                        $line .= Console::text(' from: ', 'white');
872
                        $line .= self::printResult('', $lastReport->reporterCountryCode, $defaultColor, '', false);
873
                        $line .= Console::text(' - ', 'white');
874
                        $line .= self::printResult('', $lastReport->reporterCountryName, $defaultColor, '', false);
875
                    }
876
                    $line .= Console::text(' with categor' .  (count($categories) > 1 ? "ies: " : "y: "), 'white');
877
                    foreach ($categories as $key => $cat) {
878
                        $line .= Console::text($key==0 ? '' : ',' , 'white') . Console::text($cat, $defaultColor);
879
                    }
880
                    Console::log($line);
881
882
                    // counter
883
                    $numberDiplayedReports++;
884
                    if ($numberDiplayedReports === $maxReportsNumber || $numberDiplayedReports === $nbLastReports) {
885
                        $line  = Console::text('      (', 'white');
886
                        $line .= Console::text($numberDiplayedReports, $defaultColor);
887
                        $line .= Console::text('/', 'white');
888
                        $line .= Console::text($nbLastReports, $defaultColor);
889
                        $line .= Console::text($numberDiplayedReports > 1 ? ' reports displayed)': ' report displayed)', 'white');
890
                        Console::log($line);
891
                        break;
892
                    }
893
                }
894
            }
895
        }
896
897
        // footer
898
        Console::log();
899
        self::printFooter($time);
900
    }
901
902
}