Passed
Push — 2.x ( faa78c...2f0118 )
by Terry
07:21
created

Report   A

Complexity

Total Complexity 23

Size/Duplication

Total Lines 361
Duplicated Lines 0 %

Importance

Changes 8
Bugs 0 Features 0
Metric Value
eloc 186
c 8
b 0
f 0
dl 0
loc 361
rs 10
wmc 23

10 Methods

Rating   Name   Duplication   Size   Complexity  
A operationTemplateVarsOfComponents() 0 11 6
A fetchActionLogsData() 0 44 4
A operationTemplateVarsOfFilters() 0 10 1
A actionLog() 0 35 3
A operation() 0 44 1
A __construct() 0 3 1
A getCounterDefault() 0 20 1
A getDataDefault() 0 18 3
A getInfoDefault() 0 20 1
B operationTemplateVarsOfStatistics() 0 72 2
1
<?php
2
/**
3
 * This file is part of the Shieldon package.
4
 *
5
 * (c) Terry L. <[email protected]>
6
 *
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 * 
10
 * php version 7.1.0
11
 * 
12
 * @category  Web-security
13
 * @package   Shieldon
14
 * @author    Terry Lin <[email protected]>
15
 * @copyright 2019 terrylinooo
16
 * @license   https://github.com/terrylinooo/shieldon/blob/2.x/LICENSE MIT
17
 * @link      https://github.com/terrylinooo/shieldon
18
 * @see       https://shieldon.io
19
 */
20
21
declare(strict_types=1);
22
23
namespace Shieldon\Firewall\Panel;
24
25
use Psr\Http\Message\ResponseInterface;
26
use Shieldon\Firewall\Panel\BaseController;
27
use Shieldon\Firewall\Log\ActionLogParsedCache;
28
use function Shieldon\Firewall\__;
29
use function Shieldon\Firewall\get_request;
30
31
use ReflectionObject;
32
use function array_merge;
33
use function date;
34
35
/**
36
 * The report controller.
37
 */
38
class Report extends BaseController
39
{
40
    /**
41
     *   Public methods       | Desctiotion
42
     *  ----------------------|---------------------------------------------
43
     *   operation            | The page for operating status.
44
     *   actionLog            | The page for displaying action logs.
45
     *  ----------------------|---------------------------------------------
46
     */
47
48
    /**
49
     * Constructor
50
     */
51
    public function __construct() 
52
    {
53
        parent::__construct();
54
    }
55
56
    /**
57
     * Operation status.
58
     *
59
     * @return ResponseInterface
60
     */
61
    public function operation(): ResponseInterface
62
    {
63
        $data = [];
64
65
        $data = $this->operationTemplateVarsOfComponents($data);
66
        $data = $this->operationTemplateVarsOfFilters($data);
67
        $data = $this->operationTemplateVarsOfStatistics($data);
68
69
        $reasons = [
70
            $this->kernel::REASON_MANUAL_BAN              => __('panel', 'reason_manual_ban', 'Added manually by administrator'),
71
            $this->kernel::REASON_IS_SEARCH_ENGINE        => __('panel', 'reason_is_search_engine', 'Search engine bot'),
72
            $this->kernel::REASON_IS_GOOGLE               => __('panel', 'reason_is_google', 'Google bot'),
73
            $this->kernel::REASON_IS_BING                 => __('panel', 'reason_is_bing', 'Bing bot'),
74
            $this->kernel::REASON_IS_YAHOO                => __('panel', 'reason_is_yahoo', 'Yahoo bot'),
75
            $this->kernel::REASON_TOO_MANY_SESSIONS       => __('panel', 'reason_too_many_sessions', 'Too many sessions'),
76
            $this->kernel::REASON_TOO_MANY_ACCESSES       => __('panel', 'reason_too_many_accesses', 'Too many accesses'),
77
            $this->kernel::REASON_EMPTY_JS_COOKIE         => __('panel', 'reason_empty_js_cookie', 'Cannot create JS cookies'),
78
            $this->kernel::REASON_EMPTY_REFERER           => __('panel', 'reason_empty_referer', 'Empty referrer'),
79
            $this->kernel::REASON_REACHED_LIMIT_DAY       => __('panel', 'reason_reached_limit_day', 'Daily limit reached'),
80
            $this->kernel::REASON_REACHED_LIMIT_HOUR      => __('panel', 'reason_reached_limit_hour', 'Hourly limit reached'),
81
            $this->kernel::REASON_REACHED_LIMIT_MINUTE    => __('panel', 'reason_reached_limit_minute', 'Minutely limit reached'),
82
            $this->kernel::REASON_REACHED_LIMIT_SECOND    => __('panel', 'reason_reached_limit_second', 'Secondly limit reached'),
83
            $this->kernel::REASON_INVALID_IP              => __('panel', 'reason_invalid_ip', 'Invalid IP address.'),
84
            $this->kernel::REASON_DENY_IP                 => __('panel', 'reason_deny_ip', 'Denied by IP component.'),
85
            $this->kernel::REASON_ALLOW_IP                => __('panel', 'reason_allow_ip', 'Allowed by IP component.'),
86
            $this->kernel::REASON_COMPONENT_IP            => __('panel', 'reason_component_ip', 'Denied by IP component.'),
87
            $this->kernel::REASON_COMPONENT_RDNS          => __('panel', 'reason_component_rdns', 'Denied by RDNS component.'),
88
            $this->kernel::REASON_COMPONENT_HEADER        => __('panel', 'reason_component_header', 'Denied by Header component.'),
89
            $this->kernel::REASON_COMPONENT_USERAGENT     => __('panel', 'reason_component_useragent', 'Denied by User-agent component.'),
90
            $this->kernel::REASON_COMPONENT_TRUSTED_ROBOT => __('panel', 'reason_component_trusted_robot', 'Identified as fake search engine.'),
91
        ];
92
93
        $types = [
94
            $this->kernel::ACTION_DENY             => 'DENY',
95
            $this->kernel::ACTION_ALLOW            => 'ALLOW',
96
            $this->kernel::ACTION_TEMPORARILY_DENY => 'CAPTCHA',
97
        ];
98
99
        $data['reason_mapping'] = $reasons;
100
        $data['type_mapping'] = $types;
101
102
        $data['title'] = __('panel', 'title_operation_status', 'Operation Status');
103
104
        return $this->renderPage('panel/operation_status', $data);
105
    }
106
107
    /**
108
     * Action logs
109
     *
110
     * @return ResponseInterface
111
     */
112
    public function actionLog(): ResponseInterface
113
    {
114
        $getParams = get_request()->getQueryParams();
115
116
        $type = $getParams['tab'] ?? 'today';
117
118
        $validTabs = [
119
            'yesterday',
120
            'this_month',
121
            'last_month',
122
            'past_seven_days',
123
            'today',
124
        ];
125
126
        if (!in_array($type, $validTabs)) {
127
            // @codeCoverageIgnoreStart
128
            $type = 'today';
129
            // @codeCoverageIgnoreEnd
130
        }
131
132
        $data = [];
133
        $data['last_cached_time'] = '';
134
135
        if (!empty($this->parser)) {
136
            $result = $this->fetchActionLogsData($type);
137
            $data = array_merge($data, $result);
138
        }
139
140
        $data['page_availability'] = $this->pageAvailability['logs'];;
141
142
        $data['page_url'] = $this->url('report/actionLog');
143
144
        $data['title'] = __('panel', 'title_action_logs', 'Action Logs');
145
146
        return $this->renderPage('panel/action_log_' . $type, $data);
147
    }
148
149
    /**
150
     * Fetch the log data.
151
     *
152
     * @param string $type The date type.
153
     *
154
     * @return array
155
     */
156
    private function fetchActionLogsData($type = 'today'): array
157
    {
158
        $data = [];
159
160
        $logCacheHandler = new ActionLogParsedCache($this->parser->getDirectory());
161
162
        $ipDetailsCachedData = $logCacheHandler->get($type);
163
164
        // If we have cached data then we don't need to parse them again.
165
        // This will save a lot of time in parsing logs.
166
        if (!empty($ipDetailsCachedData)) {
167
168
            $data['ip_details'] = $ipDetailsCachedData['ip_details'];
169
            $data['period_data'] = $ipDetailsCachedData['period_data'];
170
            $data['last_cached_time'] = date('Y-m-d H:i:s', $ipDetailsCachedData['time']);
171
172
            if ('today' === $type) {
173
                $ipDetailsCachedData = $logCacheHandler->get('past_seven_hours');
174
                $data['past_seven_hours'] = $ipDetailsCachedData['period_data'];
175
            }
176
177
        } else {
178
179
            $this->parser->prepare($type);
180
181
            $data['ip_details'] = $this->parser->getIpData();
182
            $data['period_data'] = $this->parser->getParsedPeriodData();
183
184
            $logCacheHandler->save($type, $data);
185
186
            if ('today' === $type) {
187
                $this->parser->prepare('past_seven_hours');
188
                $data['past_seven_hours'] = $this->parser->getParsedPeriodData();
189
190
                $logCacheHandler->save(
191
                    'past_seven_hours',
192
                    [
193
                        'period_data' => $data['past_seven_hours']
194
                    ]
195
                );
196
            }
197
        }
198
199
        return $data;
200
    }
201
202
    /**
203
     * Template variables of the section Components in page Operation.
204
     *
205
     * @param array $data The template varibles.
206
     *
207
     * @return array
208
     */
209
    private function operationTemplateVarsOfComponents(array $data = []): array
210
    {
211
        $data['components'] = [
212
            'Ip'         => (!empty($this->kernel->component['Ip']))         ? true : false,
213
            'TrustedBot' => (!empty($this->kernel->component['TrustedBot'])) ? true : false,
214
            'Header'     => (!empty($this->kernel->component['Header']))     ? true : false,
215
            'Rdns'       => (!empty($this->kernel->component['Rdns']))       ? true : false,
216
            'UserAgent'  => (!empty($this->kernel->component['UserAgent']))  ? true : false,
217
        ];
218
219
        return $data;
220
    }
221
222
    /**
223
     * Template variables of the section Filters in the page Operation.
224
     *
225
     * @param array $data The template varibles.
226
     *
227
     * @return array
228
     */
229
    private function operationTemplateVarsOfFilters(array $data = []): array
230
    {
231
        $reflection = new ReflectionObject($this->kernel);
232
        $t = $reflection->getProperty('filterStatus');
233
        $t->setAccessible(true);
234
        $filterStatus = $t->getValue($this->kernel);
235
236
        $data['filters'] = $filterStatus;
237
238
        return $data;
239
    }
240
241
    /**
242
     * Template variables of the counters for statistics in the page Operation.
243
     *
244
     * @param array $data The template varibles.
245
     *
246
     * @return array
247
     */
248
    private function operationTemplateVarsOfStatistics(array $data = []): array
0 ignored issues
show
Unused Code introduced by
The parameter $data is not used and could be removed. ( Ignorable by Annotation )

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

248
    private function operationTemplateVarsOfStatistics(/** @scrutinizer ignore-unused */ array $data = []): array

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
249
    {
250
        $ruleList = $this->kernel->driver->getAll('rule');
251
252
        $data = $this->getDataDefault();
253
        $counter = $this->getCounterDefault();
254
        $info = $this->getInfoDefault();
255
256
        // @codeCoverageIgnoreStart
257
        foreach ($ruleList as $ruleInfo) {
258
            $reason = $ruleInfo['reason']; 
259
            $counter[$reason]++;
260
            $info[$reason][] = $ruleInfo;
261
        }
262
        // @codeCoverageIgnoreEnd
263
264
        $a = $counter[$this->kernel::REASON_DENY_IP];
265
        $b = $counter[$this->kernel::REASON_COMPONENT_IP];
266
        $c = $info[$this->kernel::REASON_DENY_IP];
267
        $d = $info[$this->kernel::REASON_COMPONENT_IP];
268
        $data['component_ip'] = $a + $b;
269
        $data['rule_list']['ip'] = array_merge_recursive($c, $d);
270
271
        $a = $counter[$this->kernel::REASON_COMPONENT_RDNS];
272
        $b = $info[$this->kernel::REASON_COMPONENT_RDNS];
273
        $data['component_rdns'] = $a;
274
        $data['rule_list']['rdns'] = $b;
275
276
        $a = $counter[$this->kernel::REASON_COMPONENT_HEADER];
277
        $b = $info[$this->kernel::REASON_COMPONENT_HEADER];
278
        $data['component_header'] = $a;
279
        $data['rule_list']['header'] = $b;
280
281
        $a = $counter[$this->kernel::REASON_COMPONENT_USERAGENT];
282
        $b = $info[$this->kernel::REASON_COMPONENT_USERAGENT];
283
        $data['component_useragent'] = $a;
284
        $data['rule_list']['useragent'] = $b;
285
286
        $a = $counter[$this->kernel::REASON_COMPONENT_TRUSTED_ROBOT];
287
        $b = $info[$this->kernel::REASON_COMPONENT_TRUSTED_ROBOT];
288
        $data['component_trustedbot'] = $a;
289
        $data['rule_list']['trustedbot'] = $b;
290
291
        $a = $counter[$this->kernel::REASON_TOO_MANY_ACCESSES];
292
        $b = $counter[$this->kernel::REASON_REACHED_LIMIT_DAY];
293
        $c = $counter[$this->kernel::REASON_REACHED_LIMIT_HOUR];
294
        $d = $counter[$this->kernel::REASON_REACHED_LIMIT_MINUTE];
295
        $e = $counter[$this->kernel::REASON_REACHED_LIMIT_SECOND];
296
        $f = $info[$this->kernel::REASON_DENY_IP];
297
        $g = $info[$this->kernel::REASON_REACHED_LIMIT_DAY];
298
        $h = $info[$this->kernel::REASON_REACHED_LIMIT_HOUR];
299
        $i = $info[$this->kernel::REASON_REACHED_LIMIT_MINUTE];
300
        $j = $info[$this->kernel::REASON_REACHED_LIMIT_SECOND];
301
        $data['filter_frequency'] = $a + $b + $c + $d + $e;
302
        $data['rule_list']['frequency'] = array_merge_recursive($f, $g, $h, $i, $j);
303
304
        $a = $counter[$this->kernel::REASON_EMPTY_REFERER];
305
        $b = $info[$this->kernel::REASON_EMPTY_REFERER];
306
        $data['filter_referer'] = $a;
307
        $data['rule_list']['referer'] = $b;
308
309
        $a = $counter[$this->kernel::REASON_EMPTY_JS_COOKIE];
310
        $b = $info[$this->kernel::REASON_EMPTY_JS_COOKIE];
311
        $data['filter_cookie'] = $a;
312
        $data['rule_list']['cookie'] = $b;
313
314
        $a = $counter[$this->kernel::REASON_TOO_MANY_SESSIONS];
315
        $b = $info[$this->kernel::REASON_TOO_MANY_SESSIONS];
316
        $data['filter_session'] = $a;
317
        $data['rule_list']['session'] = $b;
318
319
        return $data;
320
    }
321
322
    /**
323
     * Get data default.
324
     *
325
     * @return array
326
     */
327
    private function getDataDefault(): array
328
    {
329
        $data = [];
330
331
        $components = ['ip', 'rdns', 'header', 'useragent', 'trustedbot'];
332
        $filters = ['cookie', 'referer', 'session', 'frequency'];
333
334
        foreach ($components as $v) {
335
            $data["component_$v"] = 0;
336
            $data['rule_list'][$v] = [];
337
        }
338
339
        foreach ($filters as $v) {
340
            $data["filter_$v"] = 0;
341
            $data['rule_list'][$v] = [];
342
        }
343
344
        return $data;
345
    }
346
347
    /**
348
     * Get counter default.
349
     *
350
     * @return array
351
     */
352
    private function getCounterDefault(): array
353
    {
354
        $counter = [];
355
356
        $counter[$this->kernel::REASON_DENY_IP]                 = 0;
357
        $counter[$this->kernel::REASON_COMPONENT_IP]            = 0;
358
        $counter[$this->kernel::REASON_COMPONENT_RDNS]          = 0;
359
        $counter[$this->kernel::REASON_COMPONENT_HEADER]        = 0;
360
        $counter[$this->kernel::REASON_COMPONENT_USERAGENT]     = 0;
361
        $counter[$this->kernel::REASON_COMPONENT_TRUSTED_ROBOT] = 0;
362
        $counter[$this->kernel::REASON_TOO_MANY_ACCESSES]       = 0;
363
        $counter[$this->kernel::REASON_REACHED_LIMIT_DAY]       = 0;
364
        $counter[$this->kernel::REASON_REACHED_LIMIT_HOUR]      = 0;
365
        $counter[$this->kernel::REASON_REACHED_LIMIT_MINUTE]    = 0;
366
        $counter[$this->kernel::REASON_REACHED_LIMIT_SECOND]    = 0;
367
        $counter[$this->kernel::REASON_EMPTY_REFERER]           = 0;
368
        $counter[$this->kernel::REASON_EMPTY_JS_COOKIE]         = 0;
369
        $counter[$this->kernel::REASON_TOO_MANY_SESSIONS]       = 0;
370
371
        return $counter;
372
    }
373
374
    /**
375
     * Get info default.
376
     *
377
     * @return array
378
     */
379
    private function getInfoDefault(): array
380
    {
381
        $info = [];
382
383
        $info[$this->kernel::REASON_DENY_IP]                 = [];
384
        $info[$this->kernel::REASON_COMPONENT_IP]            = [];
385
        $info[$this->kernel::REASON_COMPONENT_RDNS]          = [];
386
        $info[$this->kernel::REASON_COMPONENT_HEADER]        = [];
387
        $info[$this->kernel::REASON_COMPONENT_USERAGENT]     = [];
388
        $info[$this->kernel::REASON_COMPONENT_TRUSTED_ROBOT] = [];
389
        $info[$this->kernel::REASON_DENY_IP]                 = [];
390
        $info[$this->kernel::REASON_REACHED_LIMIT_DAY]       = [];
391
        $info[$this->kernel::REASON_REACHED_LIMIT_HOUR]      = [];
392
        $info[$this->kernel::REASON_REACHED_LIMIT_MINUTE]    = [];
393
        $info[$this->kernel::REASON_REACHED_LIMIT_SECOND]    = [];
394
        $info[$this->kernel::REASON_EMPTY_REFERER]           = [];
395
        $info[$this->kernel::REASON_EMPTY_JS_COOKIE]         = [];
396
        $info[$this->kernel::REASON_TOO_MANY_SESSIONS]       = [];
397
398
        return $info;
399
    }
400
}
401