Passed
Branch master (eefaca)
by Kris
01:57
created

AbstractClient   A

Complexity

Total Complexity 23

Size/Duplication

Total Lines 207
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 68
c 1
b 0
f 0
dl 0
loc 207
rs 10
wmc 23

6 Methods

Rating   Name   Duplication   Size   Complexity  
A extractApiKeyFromConf() 0 17 5
A extractSelfIpsFromConf() 0 9 3
A createHandler() 0 19 2
A loadConfigFile() 0 20 6
A parseCommand() 0 17 5
A setOutputFormat() 0 6 2
1
<?php declare(strict_types=1);
2
3
/**
4
 *       _                 ___ ___ ___  ___
5
 *  __ _| |__ _  _ ___ ___|_ _| _ \   \| _ )
6
 * / _` | '_ \ || (_-</ -_)| ||  _/ |) | _ \
7
 * \__,_|_.__/\_,_/__/\___|___|_| |___/|___/
8
 * 
9
 * This file is part of Kristuff\AbuseIPDB.
10
 *
11
 * (c) Kristuff <[email protected]>
12
 *
13
 * For the full copyright and license information, please view the LICENSE
14
 * file that was distributed with this source code.
15
 *
16
 * @version    0.9.15
17
 * @copyright  2020-2021 Kristuff
18
 */
19
namespace Kristuff\AbuseIPDB;
20
21
use Kristuff\AbuseIPDB\QuietApiHandler;
22
use Kristuff\Mishell\Program;
23
24
/**
25
 * Class AbstractClient
26
 * 
27
 * Abstract base class for main program
28
 */
29
abstract class AbstractClient extends ShellErrorHandler
30
{
31
    /**
32
     * @var string      
33
     */
34
    const SHORT_ARGUMENTS = "o:GLBK:C:d:R:c:m:l:E:V:hvs:";
35
36
    /**
37
     * @var string      
38
     */
39
    const LONG_ARGUMENTS = ['output:', 'config', 'list', 'blacklist', 'check:', 'check-block:', 'days:', 'report:', 'categories:', 'message:', 'limit:', 'clear:',' bulk-report:', 'help', 'verbose', 'score:', 'version'];
40
    
41
    /**
42
     * @var string
43
     */
44
    const VERSION = 'v0.9.15'; 
45
46
    /**
47
     * @var QuietApiHandler
48
     */
49
    protected static $api = null; 
50
51
    /**
52
     * @var string
53
     */
54
    protected static $configPath = __DIR__.'/../config';
55
56
    /**
57
     * @var array
58
     */
59
    protected static $basicCommands = [
60
        ['h',           'help',         'printHelp'],
61
        ['version',     'version',      'printVersion'],    // no short arg
62
        ['L',           'list',         'printCategories'],
63
    ];
64
    
65
    /**
66
     * @var array
67
     */
68
    protected static $mainCommands = [
69
        ['G',           'config',       'printConfig'], // require handler 
70
        ['C',           'check',        'checkIP'],
71
        ['K',           'check-block',  'checkBlock'],
72
        ['R',           'report',       'reportIP'],
73
        ['V',           'bulk-report',  'bulkReport'],
74
        ['B',           'blacklist',    'getBlacklist'],
75
        ['E',           'clear',        'clearIP'],
76
    ];
77
78
    /**
79
     * Parse command 
80
     * 
81
     * @access public 
82
     * @static
83
     * @param array     $arguments   
84
     * 
85
     * @return bool     true is the command has been found, otherwise false
86
     */
87
    protected static function parseCommand(array $arguments): bool
88
    {
89
        foreach(self::$basicCommands as $cmd){
90
            if (self::inArguments($arguments, $cmd[0], $cmd[1])){
91
                call_user_func(__NAMESPACE__.'\AbuseIPDBClient::'.$cmd[2], null);
92
                return true;
93
            }
94
        }
95
        foreach(self::$mainCommands as $cmd){
96
            if (self::inArguments($arguments, $cmd[0], $cmd[1])){
97
                self::createHandler();
98
                self::setOutputFormat($arguments);                    
99
                call_user_func(__NAMESPACE__.'\AbuseIPDBClient::'.$cmd[2], $arguments);
100
                return true;
101
            }
102
        }
103
        return false;
104
    }
105
106
    /**
107
     * Get and register output format
108
     *  
109
     * @access protected
110
     * @static
111
     * @param array         $arguments      The list of arguments     
112
     * 
113
     * @return void   
114
     * 
115
     */
116
    protected static function setOutputFormat(array $arguments): void
117
    {
118
        $given = self::getArgumentValue($arguments, 'o', 'output') ?? 'default';
119
        $output = empty($given) ? 'default' : $given; 
120
        self::validate(in_array($output, ['default', 'json', 'plaintext']), 'Invalid output argument given.');
121
        self::$outputFormat = $output ;
122
    }
123
124
    /**
125
     * Create and register ApiHandler
126
     * 
127
     * @access protected 
128
     * @static
129
     * 
130
     * @return void
131
     * @throws \InvalidArgumentException                        If the given file does not exist
132
     * @throws \Kristuff\AbuseIPDB\InvalidPermissionException   If the given file is not readable 
133
     */
134
    protected static function createHandler(): void
135
    {
136
        try {
137
            $mainConfPath  = self::$configPath . DIRECTORY_SEPARATOR . 'conf.ini';
138
            $localConfPath = self::$configPath . DIRECTORY_SEPARATOR . 'local.ini';
139
140
            // Check main file exists and is readable
141
            // Even if a local file exists, main file must be here (throws ex otherwise)
142
            $mainConfigArray  = self::loadConfigFile($mainConfPath, true);
143
            $localConfigArray = self::loadConfigFile($localConfPath);
144
145
            $selfIps = self::extractSelfIpsFromConf($mainConfigArray, $localConfigArray);
146
            $apiKey  = self::extractApiKeyFromConf($mainConfigArray, $localConfigArray);
147
            
148
            self::$api =  new QuietApiHandler($apiKey, $selfIps);
149
        } catch (\Exception $e) {
150
            self::error($e->getMessage());
151
            self::printFooter();
152
            Program::exit(1);
153
        }
154
    }
155
156
    /**
157
     * Extract self ip list from configuration array
158
     * 
159
     * @access protected 
160
     * @static
161
     * @param array    $conf        The main configuration array
162
     * @param array    $local       The local configuration array
163
     * 
164
     * @return array
165
     */
166
    protected static function extractSelfIpsFromConf(array $conf, array $localConf): array
167
    {
168
        if (array_key_exists('self_ips', $localConf)){
169
            return array_map('trim', explode(',', $localConf['self_ips']));
170
        }
171
        if (array_key_exists('self_ips', $conf)){
172
            return array_map('trim', explode(',', $conf['self_ips']));
173
        }
174
        return [];
175
    }
176
177
    /**
178
     * Extract the api key from configuration array
179
     * 
180
     * @access protected 
181
     * @static
182
     * @param array    $conf        The configuration array
183
     * 
184
     * @return array
185
     */
186
    protected static function extractApiKeyFromConf(array $conf, $localConf): string
187
    {
188
        $key = '';
189
190
        if (array_key_exists('api_key', $localConf)){
191
            $key = $localConf['api_key'];
192
        }
193
        
194
        if (empty($key) && array_key_exists('api_key', $conf)){
195
            $key = $conf['api_key'];
196
        }
197
198
        if (empty($key)){
199
            throw new \RuntimeException('Api key is missing.');
200
        }
201
202
        return $key;
203
    }
204
205
    /**
206
     * Load a config file
207
     * 
208
     * @access protected 
209
     * @static
210
     * @param string    $path        The configuration file path
211
     * @param bool      $mandatory   If true, throw ex when the file does not exist.
212
     * 
213
     * @return array
214
     * @throws \RuntimeException                                
215
     */
216
    protected static function loadConfigFile(string $path, bool $mandatory = false): array
217
    {
218
        if (file_exists($path) && is_file($path)){
219
220
            // If main file or a local file is not readable then throws ex.
221
            if (!is_readable($path)){
222
                throw new \RuntimeException('The configuration file ['.$path.'] is not readable.');
223
            }
224
225
            $conf = parse_ini_file($path, false);  // load without sections...
226
            if ($conf === false){
227
                throw new \RuntimeException('Unable to read configuration file ['.$path.'].');
228
            }
229
            return $conf;
230
        }
231
232
        if ($mandatory){
233
            throw new \RuntimeException('The configuration file ['.$path.'] does not exist.');
234
        }
235
        return [];
236
    }
237
}