PluginProbe
WebTotem Security / 2.4.9
WebTotem Security v2.4.9
3.0.2 3.0.1 3.0.0 trunk 1.0 1.1 1.2 1.3 1.3.1 1.3.2 1.3.3 2.0 2.1 2.1.1 2.1.2 2.1.3 2.1.4 2.1.5 2.1.6 2.1.7 2.1.8 2.1.9 2.2.1 2.2.2 2.2.3 All 110 releases
wt-security / lib / Helper.php

Helper.php in WebTotem Security 2.4.9, at lib/Helper.php

1,364 lines 35.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 if (!defined('WEBTOTEM_INIT') || WEBTOTEM_INIT !== true) {
4 if (!headers_sent()) {
5 header('HTTP/1.1 403 Forbidden');
6 }
7 exit(1);
8 }
9
10 /**
11 * WebTotem Base class for Wordpress.
12 */
13 class WebTotem {
14
15 /**
16 * Returns an URL from the admin dashboard.
17 *
18 * @param string $url
19 * Optional trailing of the URL.
20 * @return string
21 * Full valid URL from the admin dashboard.
22 */
23 public static function adminURL($url = '') {
24 if (self::isMultiSite() and is_super_admin()) {
25 return network_admin_url($url);
26 }
27 return admin_url($url);
28 }
29
30 /**
31 * Check whether the current site is working as a multi-site instance.
32 *
33 * @return bool
34 * Either TRUE or FALSE in case WordPress is being used as a multi-site instance.
35 */
36 public static function isMultiSite() {
37 return (bool) (function_exists('is_multisite') && is_multisite());
38 }
39
40 /**
41 * Returns the md5 hash representing the content of a file.
42 *
43 * @param string $file
44 * Relative path to the file.
45 * @return string
46 * Seven first characters in the hash of the file.
47 */
48 public static function fileVersion($file = '') {
49 return substr(md5_file(WEBTOTEM_PLUGIN_PATH . '/' . $file), 0, 7);
50 }
51
52 /**
53 * Returns the md5 hash representing the content of a file.
54 *
55 * @param string $file
56 * Relative path to the file.
57 * @return string
58 * Seven first characters in the hash of the file.
59 */
60 public static function getImagePath($image) {
61 return WEBTOTEM_URL. '/includes/img/' . $image;
62 }
63
64 /**
65 * Check that the training period has passed for the firewall.
66 *
67 * @param string $created_at
68 * Date when the waf configuration was created.
69 *
70 * @return bool
71 * Returns boolean.
72 */
73 public static function isWafTraining($created_at) {
74 if($created_at) {
75 $when_waf_trained = strtotime('+2 day', strtotime($created_at));
76 $today = strtotime('today');
77
78 return ($when_waf_trained < $today) ? FALSE : TRUE;
79 }
80 return FALSE;
81 }
82
83 /**
84 * Converting a date to the appropriate format.
85 *
86 * @param string $date
87 * Date in any format.
88 * @param string $format
89 * The format to which you want to convert the date.
90 *
91 * @return string
92 * Returns converted Date.
93 */
94 public static function dateFormatter($date, $format = 'M j, Y \/ H:i') {
95 if (!$date) {
96 return __('Unknown', 'wtotem');
97 }
98
99 $time_zone = WebTotemOption::getOption('time_zone_offset');
100 $user_time = ($time_zone) ? strtotime($time_zone . 'hours', strtotime($date)) : strtotime($date);
101
102 return date_i18n($format, $user_time);
103 }
104
105 /**
106 * Get theme mode data.
107 *
108 * @return array
109 * Returns array with current theme data.
110 */
111 public static function getThemeMode() {
112 $theme_mode = WebTotemOption::getSessionOption('theme_mode');
113 return [
114 "is_dark_mode" => $theme_mode == 'dark' ? 'wtotem_theme—dark' : '',
115 "dark_mode_checked" => $theme_mode == 'dark' ? 'checked' : '',
116 ];
117 }
118
119 /**
120 * Get current user language.
121 *
122 * @return string
123 * Returns current language in 2-letter abbreviations
124 */
125 public static function getLanguage() {
126 $current_language = substr(get_bloginfo('language'), 0,2);
127 $language = (in_array($current_language,['ru','en','pl'])) ? $current_language : 'en' ;
128 return $language;
129 }
130
131 /**
132 * Converting a date to the appropriate format.
133 *
134 * @param string|array $days
135 * Number of days or period to convert.
136 *
137 * @return array
138 * Returns an array of two values "from" and "to"
139 */
140 public static function getPeriod($days) {
141
142 if (!$days) {
143 $days = 30;
144 }
145
146 switch ($days) {
147
148 case is_array($days):
149 $to = $days[1] ?: $days[0];
150 $period = [
151 'from' => strtotime(date('Y-m-d 00:00:01', strtotime($days[0]))),
152 'to' => strtotime(date('Y-m-d 23:59:59', strtotime($to))),
153 ];
154 break;
155
156 case $days <= 1:
157 $period = [
158 'from' => strtotime('-24 hours'),
159 'to' => time(),
160 ];
161 break;
162
163 default:
164 $period = [
165 'from' => time() - ($days * 86400),
166 'to' => time(),
167 ];
168 }
169
170 return $period;
171 }
172
173 /**
174 * Convert an array to a string with quotation marks.
175 *
176 * @param array $array
177 * Data array.
178 *
179 * @return string
180 * Array of data converted to string.
181 */
182 public static function convertArrayToString($array) {
183 if(empty($array)){
184 return '';
185 }
186 return '"' . implode('","', $array) . '"';
187 }
188
189 /**
190 * Converting the response to a readable form.
191 *
192 * @param string $message
193 * Message response from the API server to the request.
194 *
195 * @return string|bool
196 * Returns a message.
197 */
198 public static function messageForHuman($message) {
199
200 $definition = $message;
201
202 switch ($message) {
203 case 'HOSTS_LIMIT_EXCEEDED':
204 $definition = __('Limit of adding sites exceeded.', 'wtotem');
205 break;
206
207 case 'USER_ALREADY_REGISTERED':
208 $definition = __('A user with this email already exists.', 'wtotem');
209 break;
210
211 case 'DUPLICATE_HOST':
212 $definition = __('Duplicate host', 'wtotem');
213 break;
214
215 case 'INVALID_DOMAIN_NAME':
216 $definition = __('Invalid Domain Name', 'wtotem');
217 break;
218 default:
219 $definition = str_replace("_", " ", $definition);
220 $definition = ucfirst(strtolower($definition));
221
222 }
223 return $definition;
224 }
225
226 /**
227 * Get the data associated with the status.
228 *
229 * @param string $status
230 * Module or agent status.
231 *
232 * @return array
233 * Returns an array with status data.
234 */
235 public static function getStatusData($status) {
236 $path = self::getImagePath('');
237 $status = ($status == "installed") ? 'working' : $status;
238
239 switch ($status) {
240
241 case 'clean':
242 case 'up':
243 case 'installed':
244 case 'working':
245 $status_data = [
246 'class' => 'is--status--ok',
247 'image' => $path . 'check-mark.svg',
248 'icon' => $path . 'icon_success_status.svg',
249 ];
250 break;
251
252 case 'pending':
253 $status_data = [
254 'class' => 'is--status--pending',
255 'image' => $path . 'loading.svg',
256 'icon' => $path . 'alert-warning.svg',
257 ];
258 break;
259
260 case 'pause':
261 case 'modified':
262 $status_data = [
263 'class' => 'is--status--pending',
264 'image' => $path . 'warning.svg',
265 'icon' => $path . 'alert-warning.svg',
266 ];
267 break;
268
269 case 'expired':
270 case 'no_cert':
271 case 'expires':
272 case 'open_ports':
273 case 'not_supported':
274 case 'not_registered':
275 $status_data = [
276 'class' => 'is--status--warning',
277 'image' => $path . 'warning.svg',
278 'icon' => $path . 'alert-warning.svg',
279 ];
280 break;
281
282 case 'invalid':
283 case 'error':
284 case 'down':
285 case 'expires_today':
286 case 'infected':
287 case 'deface':
288 case 'not_installed':
289 $status_data = [
290 'class' => 'is--status--error',
291 'image' => $path . 'warning.svg',
292 'icon' => $path . 'alert-warning.svg',
293 ];
294 break;
295
296 default:
297 $status_data = [
298 'class' => 'is--status--pending',
299 'image' => $path . 'warning.svg',
300 'icon' => $path . 'alert-warning.svg',
301 ];
302 }
303 $status_data['name'] = $status;
304 $status_data['text'] = self::getStatusText($status);
305 $status_data['tooltips'] = self::getTooltips($status);
306
307 return $status_data;
308 }
309
310 /**
311 * Get a readable status text.
312 *
313 * @param string $status
314 * Module or agent status.
315 *
316 * @return string
317 * Returns the status text in the current language.
318 */
319 public static function getStatusText($status) {
320 $statuses = [
321 'warning' => __('Warning', 'wtotem'),
322 'error' => __('Error', 'wtotem'),
323 'success' => __('Success', 'wtotem'),
324 'info' => __('Info', 'wtotem'),
325 'invalid' => __('Invalid', 'wtotem'),
326 'ok' => __('Everything is OK', 'wtotem'),
327 'expired' => __('Expired', 'wtotem'),
328 'expires' => __('Expires', 'wtotem'),
329 'expires_today' => __('Expires today', 'wtotem'),
330 'missing' => __('Missing', 'wtotem'),
331 'active' => __('Active', 'wtotem'),
332 'inactive' => __('Inactive', 'wtotem'),
333 'pending' => __('Pending', 'wtotem'),
334 'pause' => __('Disabled', 'wtotem'),
335 'available' => __('Available', 'wtotem'),
336 'not_supported' => __('Not supported', 'wtotem'),
337 'not_registered' => __('Not registered', 'wtotem'),
338 'unsupported' => __('Unsupported', 'wtotem'),
339 'clean' => __('Clean', 'wtotem'),
340 'clear' => __('Clear', 'wtotem'),
341 'blacklisted' => __('Infected', 'wtotem'),
342 'miner_detected' => __('Infected', 'wtotem'),
343 'deface' => __('Deface', 'wtotem'),
344 'modified' => __('Modified', 'wtotem'),
345 'detected' => __('Detected', 'wtotem'),
346 'open_ports' => __('Open ports', 'wtotem'),
347 'blocked' => __('Blocked', 'wtotem'),
348 'connected' => __('Connected', 'wtotem'),
349 'attacks_detected' => __('Attacks detected', 'wtotem'),
350 'signature_found' => __('Signature found', 'wtotem'),
351 'file_changes' => __('File changes', 'wtotem'),
352 'no_cert' => __('No cert', 'wtotem'),
353 'down' => __('Down', 'wtotem'),
354 'up' => __('Up', 'wtotem'),
355 'infected' => __('Infected', 'wtotem'),
356 'not_installed' => __('Need to install', 'wtotem'),
357 'agent_not_available' => __('Agent not available', 'wtotem'),
358 'update_error' => __('Update error', 'wtotem'),
359 'session_error' => __('Session Error', 'wtotem'),
360 'internal_error' => __('Internal Error', 'wtotem'),
361 'installing' => __('Installing', 'wtotem'),
362 'installed' => __('Installed', 'wtotem'),
363 'working' => __('Working', 'wtotem'),
364 "critical" => __('Critical', 'wtotem'),
365 "deleted" => __('Deleted', 'wtotem'),
366 "changed" => __('Changed', 'wtotem'),
367 "new" => __('New', 'wtotem'),
368 "scanned" => __('Scanned', 'wtotem'),
369 "quarantine" => __('In quarantine', 'wtotem'),
370 ];
371
372 return (array_key_exists($status, $statuses)) ? $statuses[$status] : $status;
373 }
374
375 /**
376 * Get tooltips text for status.
377 *
378 * @param string $status
379 * Module or agent status.
380 *
381 * @return string
382 * Returns the status tooltip in the current language.
383 */
384 public static function getTooltips($status) {
385 $tooltips = [
386 'invalid' => __('Invalid -The certificate is invalid. Please, make sure that relevant certificate details filled correctly.', 'wtotem'),
387 'expired' => __('Expired - The certificate has expired. Connection is not secure. Please, renew it.', 'wtotem'),
388 'expires' => __('Expires - The certificate expires soon. Please, take actions.', 'wtotem'),
389 'expires_today' => __('Expires today - The certificate expires today. Please, take actions.', 'wtotem'),
390 'error' => __("Error - Something went wrong. Please, contact us, we'll fix the problem.", 'wtotem'),
391 'pending' => __('Pending - System processes your website. Data will be available soon.', 'wtotem'),
392 'pause' => __('Pause - The module is paused.', 'wtotem'),
393 'clean' => __('Everything is OK - Nothing to worry about. Everything is alright.', 'wtotem'),
394 'deface' => __("Deface - Website hacked. Please, contact us, we'll fix the problem.", 'wtotem'),
395 'open_ports' => __('Open ports - Open ports detected. Your website is vulnerable to attacks.', 'wtotem'),
396 'blocked' => __('Blocked - The module is blocked due to billing issues.', 'wtotem'),
397 'no_cert' => __("No cert - You don't have SSL certificate. We recommend you to install it for security concerns.", 'wtotem'),
398 'down' => __('Down - The website is not available for visitors.', 'wtotem'),
399 'up' => __('Up - The website is available for visitors.', 'wtotem'),
400 'infected' => __('Infected - The website site is blacklisted and may have infected files. Please, check antivirus module.', 'wtotem'),
401 'installing' => __('It means that the agent installation is in progress. Usually, it takes up to one hour.', 'wtotem'),
402 'agent_not_available' => __('We cannot locate the agent right now.', 'wtotem'),
403 'update_error' => __('It seems that your agent failed to update due to permissions restrictions.', 'wtotem'),
404 'session_error' => __('This means that the agent did not create a secure session. Possible causes include network issues, wrong server configuration, third-party firewalls. Please contact our support..', 'wtotem'),
405 'internal_error' => __('It means that the server is overloaded or there might be some problems with the connection. Usually, the issue resolves itself within 10-15 minutes. If the status does not change during two hours, please cordially contact our support..', 'wtotem'),
406 'working' => __('Everything is alright.', 'wtotem'),
407 'installed' => __('Everything is alright.', 'wtotem'),
408 'not_installed' => __('You need to install agent manager to activate antivirus and firewall.', 'wtotem'),
409 ];
410
411 return (array_key_exists($status, $tooltips)) ? $tooltips[$status] : '';
412 }
413
414 /**
415 * Converting site data.
416 *
417 * @param array $data
418 * Sites data from WebTotem.
419 *
420 * @return array
421 * Converted data.
422 */
423 public static function allSitesData($data) {
424
425 $local_sites = get_sites();
426 $main_host = WebTotemOption::getMainHost();
427 $domains = [];
428
429 foreach ($local_sites as $site){
430 $domain = untrailingslashit($site->domain . $site->path);
431 $domains[$domain] = $domain;
432 }
433
434 $sites = [];
435 if(array_key_exists('edges', $data)){
436 foreach ($data['edges'] as $site) {
437 $site = $site['node'];
438 // Take sites only from the multisite network.
439 if(array_key_exists($site['hostname'], $domains)) {
440 unset($domains[$site['hostname']]);
441 $sites[] = [
442 'hostname' => $site['hostname'],
443 'title' => $site['title'],
444 'main_host' => $main_host['id'] == $site['id'],
445 'host_id' => $site['id'],
446 'url' => admin_url('admin.php?page=wtotem_dashboard&hid=' . $site['id']),
447 'firewall' => [
448 'status' => self::getStatusData($site['firewall']['status']),
449 ],
450 'antivirus' => [
451 'status' => self::getStatusData($site['antivirus']['status']),
452 ],
453 'stacks' => self::getStacksData($site['maliciousScript']['stack']),
454 'services' => self::getSiteServicesData($site),
455 ];
456 }
457 }
458
459 }
460 return $sites;
461 }
462
463 /**
464 * Converting stacks data.
465 *
466 * @param array $stacks
467 * Stacks data from WebTotem.
468 *
469 * @return array
470 * Converted data.
471 */
472 protected static function getStacksData($stacks) {
473 $apps = file_get_contents(WEBTOTEM_PLUGIN_PATH . '/includes/js/apps.json');
474 $apps = json_decode($apps, true);
475
476 $path = 'https://assets.wtotem.net/images/apps/';
477 $defaultIcon = WEBTOTEM_URL . '/includes/img/defaultTechnologiesIcon.svg';
478
479 $stackList = array_slice($stacks, 0,3);
480 $list = [];
481 foreach ($stackList as $key => $stack){
482 $list[$key] = [
483 'name' => $stack['name'],
484 'icon' => $path . ($apps[$stack['name']]['icon'] ?: $defaultIcon),
485 ];
486 }
487
488 if(count($stacks) <= 3){
489 $other['count'] = 0;
490 $other['names'] = [];
491 } else {
492 $otherStacks = array_slice($stacks, 3);
493 $other['count'] = count($otherStacks);
494 foreach ($otherStacks as $stack){
495 $other['names'][] = $stack['name'];
496 }
497 }
498 if($other['names']){
499 $other['names'] = implode(",", $other['names']);
500 }
501 return ['list' => $list, 'other' => $other];
502 }
503
504 /**
505 * Converting services data.
506 *
507 * @param $data
508 * Site data from WebTotem.
509 *
510 * @return array
511 * Converted data.
512 */
513 protected static function getSiteServicesData($data) {
514
515 $services = [
516 'ssl' => 'ssl',
517 'availability' => 'wa',
518 'reputation' => 'rc',
519 'ports' => 'ps',
520 'deface' => 'dc',
521 'domain' => 'dec',
522 ];
523
524 $list = [];
525 $other['count'] = 0;
526 $other['names'] = [];
527
528 foreach ($services as $key => $service){
529 if(array_key_exists($key, $data) and is_array($data[$key]) and array_key_exists('status', $data[$key])){
530 $status = self::getServiceStatus($data[$key]['status']);
531
532 if(in_array($status['color'], ['red', 'yellow'])){
533 if(count($list) < 2){
534 $color = $status['color'] == 'red' ? 'white/' : '';
535
536 $list[$key] = [
537 'status' => $status,
538 'icon' => 'services/'. $color . $service . '.svg',
539 'name' => self::getServiceName( $service ),
540 ];
541 } else {
542 $other['names'][] = self::getServiceName( $service );
543 $other['count']++;
544 }
545 }
546
547 }
548 }
549 if($other['names']){
550 $other['names'] = implode(",", $other['names']);
551 }
552 return ['list' => $list, 'other' => $other];
553 }
554
555 /**
556 * Get the data associated with the status.
557 *
558 * @param string $status
559 * Module or agent status.
560 *
561 * @return array
562 * Returns an array with status data.
563 */
564 public static function getServiceStatus($status) {
565 switch ($status) {
566
567 case 'expired':
568 case 'invalid':
569 case 'error':
570 case 'expires_today':
571 case 'down':
572 case 'infected':
573 case 'deface':
574 case 'not_installed':
575 case 'quarantine':
576 $status_data = [
577 'color' => 'red',
578 ];
579 break;
580
581 case 'no_cert':
582 case 'expires':
583 case 'open_ports':
584 case 'modified':
585 case 'not_supported':
586 case 'not_registered':
587 case 'blocked':
588 case 'pause':
589 case 'internal_error':
590 case 'update_error':
591 case 'config_error':
592 case 'agent_not_available':
593 case 'session_error':
594 $status_data = [
595 'color' => 'yellow',
596 ];
597 break;
598
599 case 'clean':
600 case 'installed':
601 case 'up':
602 case 'scanned':
603 case 'working':
604 $status_data = [
605 'color' => 'green',
606 ];
607 break;
608
609 case 'deleted':
610 $status_data = [
611 'color' => 'black',
612 ];
613 break;
614
615 case 'installing':
616 case 'pending':
617 default:
618 $status_data = [
619 'color' => 'gray',
620 ];
621 break;
622
623 }
624
625 return $status_data;
626 }
627
628 /**
629 * Get the translation of service.
630 *
631 * @param $service
632 * Service short name.
633 *
634 * @return string
635 * Translation of service.
636 */
637 public static function getServiceName($service){
638 $services = [
639 "wa" => __('Availability', 'wtotem'),
640 "rc" => __('Reputation', 'wtotem'),
641 "ssl" => 'SSL',
642 "cms" => __('Technologies', 'wtotem'),
643 "dc" => __('Deface', 'wtotem'),
644 "ps" => __('Ports', 'wtotem'),
645 "waf" => __('Firewall', 'wtotem'),
646 "av" => __('Antivirus', 'wtotem'),
647 "dec" => __('Domain', 'wtotem'),
648 ];
649 return $services[$service];
650 }
651
652 /**
653 * Get reports with modules list.
654 *
655 * @param array $edges
656 * Data on generated reports.
657 *
658 * @return array
659 * Returns an array with converted data.
660 */
661 public static function getReports(array $edges) {
662 $modulesLang = [
663 'wa' => __('Availability log', 'wtotem'),
664 'dc' => __('Deface log', 'wtotem'),
665 'ps' => __('Port log', 'wtotem'),
666 'rc' => __('Reputation log', 'wtotem'),
667 'sc' => __('Evaluation log', 'wtotem'),
668 'av' => __('Antivirus log', 'wtotem'),
669 'waf' => __('Firewall log', 'wtotem'),
670 ];
671
672 $reports = [];
673
674 foreach ($edges as $edge) {
675 if (in_array(FALSE, $edge["node"])) {
676 $arr = [];
677 foreach ($edge["node"] as $module => $value) {
678 if ($value == TRUE && array_key_exists($module, $modulesLang)) {
679 $arr[] = $modulesLang[$module];
680 }
681 }
682 $modules = implode(", ", $arr);
683 }
684 else {
685 $modules = __('All modules', 'wtotem');
686 }
687
688 $reports[] = [
689 'id' => $edge["node"]['id'],
690 'modules' => $modules,
691 'created_at' => self::dateFormatter($edge["node"]['createdAt']),
692 ];
693 }
694
695 return $reports;
696 }
697
698 /**
699 * Get reputation status description.
700 *
701 * @param string $status
702 * Reputation status.
703 *
704 * @return string
705 * Returns a description of the reputation status
706 */
707 public static function getReputationInfo($status) {
708 switch ($status) {
709 case 'clean':
710 $data = __("Don't worry, your reputation is good", 'wtotem');
711 break;
712
713 case 'infected':
714 $data = __('Oh, your reputation is bad', 'wtotem');
715 break;
716
717 default:
718 $data = __('Information is being updated', 'wtotem');
719 }
720 return $data;
721 }
722
723 /**
724 * Get blacklists entries counts.
725 *
726 * @param string $status
727 * Reputation status.
728 * @param array $virus_list
729 * Sources where the site can be blacklisted.
730 *
731 * @return int
732 * Number of references in blacklists.
733 */
734 public static function blacklistsEntries($status, array $virus_list) {
735 $count = 0;
736 if ($status != "clean") {
737 foreach ($virus_list as &$list) {
738 if (!empty($list['virus']['type'])) {
739 $count++;
740 }
741 }
742 }
743 return $count;
744 }
745
746 /**
747 * Classification of the rating in the letter grades.
748 *
749 * @param int $score
750 * Site rating from 1 to 100.
751 *
752 * @return array
753 * Returns an array of data.
754 */
755 public static function scoreGrading($score) {
756 if ($score < 0 || $score > 100) {
757 return ['grade' => '', 'color' => ''];
758 }
759
760 $scores = [
761 100 => 'A+',
762 90 => 'A',
763 80 => 'A-',
764 70 => 'B+',
765 60 => 'B',
766 50 => 'B-',
767 35 => 'C+',
768 20 => 'C',
769 0 => 'C-',
770 ];
771
772 foreach ($scores as $key => $value) {
773 if ($score >= $key) {
774 $grade = $value;
775 break;
776 }
777 }
778
779 // Set a color depending on the grade.
780 switch ($score) {
781 case $score >= 80:
782 $color = 'green';
783 break;
784
785 case $score >= 50:
786 $color = 'orange';
787 break;
788
789 default:
790 $color = 'red';
791 }
792
793 return ['grade' => $grade, 'color' => $color];
794 }
795
796 /**
797 * Calculate the number of remaining days.
798 *
799 * @param string $date
800 * Expiry date.
801 *
802 * @return string
803 * Returns the number of days before the expiration date.
804 */
805 public static function daysLeft($date) {
806 if ((int) $date === 0) {
807 $days_left = 0;
808 }
809 else {
810 $now = new \DateTime();
811 $expiry_date = new \DateTime();
812 $timestamp = strtotime($date);
813 $expiry_date->setTimestamp($timestamp);
814 $days_left = $expiry_date->diff($now)->format("%a");
815 }
816 return $days_left;
817 }
818
819 /**
820 * Converting the firewall logs.
821 *
822 * @param array $logs_
823 * Firewall logs from WebTotem.
824 *
825 * @return array
826 * Converted array of logs.
827 */
828 public static function wafLogs(array $logs_) {
829 $logs = [];
830 foreach ($logs_ as $key => $log) {
831 $log = $log['node'];
832
833 $logs[$key]['ip'] = $log['ip'];
834 $logs[$key]['request'] = htmlspecialchars(urldecode($log['request']));
835 $logs[$key]['time'] = self::dateFormatter($log['time']);
836 $logs[$key]['country_code'] = strtolower($log['country']);
837 $logs[$key]['country'] = $log['location']['country']['nameEn'];
838 $logs[$key]['blocked'] = $log['blocked'] ? __('Blocked IP', 'wtotem') : __('Not blocked', 'wtotem');
839 }
840 return $logs;
841 }
842
843 /**
844 * Converting firewall data to json for a D3 chart.
845 *
846 * @param array $charts
847 * Charts data from WebTotem.
848 *
849 * @return array
850 * Returns the converted data for chart.
851 */
852 public static function generateWafChart(array $charts) {
853 $sum = 0;
854 foreach ($charts as $chart) {
855 $sum += $chart['attacks'];
856 }
857 if ($sum == 0) {
858 return ['chart' => FALSE, 'count_attacks' => 0, 'count_blocks' => 0];
859 }
860
861 // Get days count.
862 $charts_ = $charts;
863 $first = array_shift($charts_);
864 $last = array_pop($charts_);
865 $days = ceil((strtotime($last['time']) - strtotime($first['time'])) / 86400);
866
867 // Set variables.
868 $count_attacks = $count_blocks = 0;
869
870 foreach ($charts as $chart) {
871 if ($days <= 1) {
872 $time_zone = WebTotemOption::getOption('time_zone_offset');
873 $userTime = ($time_zone) ? strtotime($time_zone . ' hours', strtotime($chart['time'])) : strtotime($chart['time']);
874 }
875 if (($chart['attacks'] and $days == 2) or $days != 2) {
876 $result[] = [
877 'date' => ($days <= 1) ? date("Y-m-d H:00:00", $userTime) : date("Y-m-d", strtotime($chart['time'])),
878 'count' => $chart['blocked'],
879 'attacks' => $chart['attacks'],
880 'blocked' => $chart['blocked'],
881 ];
882 $count_attacks += $chart['attacks'];
883 $count_blocks += $chart['blocked'];
884 }
885 }
886
887 if (!isset($result)) {
888 return [
889 'chart' => FALSE,
890 'count_attacks' => 0,
891 'count_blocks' => 0,
892 ];
893 }
894
895 return [
896 'chart' => json_encode($result),
897 'count_attacks' => $count_attacks,
898 'count_blocks' => $count_blocks,
899 'days' => $days,
900 ];
901 }
902
903 /**
904 * Converting data to json for a D3 chart.
905 *
906 * @param array $charts
907 * Charts data from WebTotem.
908 * @param int $days
909 * The number of days to build the chart.
910 *
911 * @return bool|string
912 * Returns the converted data for chart.
913 */
914 public static function generateChart(array $charts, $days = 7) {
915 $sum = 0;
916 foreach ($charts as $chart) {
917 $sum += $chart['value'];
918 }
919 if ($sum == 0) {
920 return FALSE;
921 }
922
923 $result = [];
924
925 foreach ($charts as $chart) {
926 if ($days <= 1) {
927 $time_zone = WebTotemOption::getOption('time_zone_offset');
928 $userTime = ($time_zone) ? strtotime($time_zone . 'hours', strtotime($chart['time'])) : strtotime($chart['time']);
929 }
930 $result[] = [
931 'date' => ($days <= 1) ? date("Y-m-d H:00:00", $userTime) : date("Y-m-d", strtotime($chart['time'])),
932 'value' => $chart['value'],
933 ];
934 }
935
936 return json_encode($result, TRUE);
937 }
938
939 /**
940 * Converting data to json for a D3 chart.
941 *
942 * @param array $data
943 * Charts data from WebTotem.
944 *
945 * @return array|bool
946 * Returns the converted data for chart.
947 */
948 public static function generateAttacksMapChart(array $data) {
949 $attacks = [];
950 $countries = [];
951 $labels = [];
952 foreach ($data as $value) {
953 $attacks[] = $value['attacks'];
954 $labels[] = self::getCountryName($value['country']);
955 $countries[] = $value['location']['country']['nameEn'];
956 }
957 $result = ['attacks' => $attacks, 'countries' => $countries, 'labels' => $labels];
958
959 if (!$attacks) {
960 return FALSE;
961 }
962
963 return json_encode($result, TRUE);
964 }
965
966 /**
967 * Reassembling the antivirus logs.
968 *
969 * @param array $logs_
970 * Antivirus logs from WebTotem.
971 *
972 * @return array
973 * Reassembled array of logs.
974 */
975 public static function getAntivirusLogs(array $logs_) {
976 $logs = [];
977 foreach ($logs_ as $key => $log) {
978 $log = $log['node'];
979
980 $file_info = new SplFileInfo(urldecode($log['filePath']));
981
982 $log['original_path'] = $log['filePath'];
983 $log['file_path'] = $file_info->getPath() . '/';
984 $log['file_name'] = $file_info->getFilename();
985 $log['time'] = self::dateFormatter($log['time']);
986 $log['permissions_changed'] = $log['permissionsChanged'];
987 $log['status'] = self::getStatusData($log['event']);
988 $log['class'] = 'wt-text--green';
989
990 switch ($log['event']) {
991 case 'modified':
992 case 'quarantine':
993 $log['class'] = "wt-text--yellow";
994 break;
995
996 case 'deleted':
997 $log['class'] = "wt-text--light-gray";
998 break;
999
1000 case 'infected':
1001 $log['class'] = "wt-text--red";
1002 break;
1003 }
1004
1005 $logs[$key] = $log;
1006 }
1007 return $logs;
1008 }
1009
1010 /**
1011 * Reassembling the quarantine logs.
1012 *
1013 * @param array $logs_
1014 * Quarantine logs from WebTotem.
1015 *
1016 * @return array
1017 * Reassembled array of logs.
1018 */
1019 public static function getQuarantineLogs(array $logs_) {
1020 $logs = [];
1021 foreach ($logs_ as $key => $log) {
1022 $logs[$key] = $log;
1023 $logs[$key]['path'] = urldecode($log['path']);
1024 $logs[$key]['date'] = self::dateFormatter($log['date']);
1025 }
1026
1027 return $logs;
1028 }
1029
1030 /**
1031 * Generate an array of IP address data.
1032 *
1033 * @param array $data
1034 * IP addresses data from WebTotem.
1035 * @param string $list_name
1036 * Allow or deny list.
1037 *
1038 * @return array
1039 * Returns array of data.
1040 */
1041 public static function getIpList(array $data, $list_name) {
1042 $list = [];
1043 foreach ($data as $item) {
1044 $list[] = [
1045 'ip' => $item['ip'],
1046 'id' => $item['id'],
1047 'created_at' => self::dateFormatter($item['createdAt']),
1048 'list_name' => $list_name,
1049 ];
1050 }
1051 return $list;
1052 }
1053
1054 /**
1055 * Generate an array of URL address data.
1056 *
1057 * @param array $data
1058 * URL addresses data from WebTotem.
1059 *
1060 * @return array
1061 * Returns array of data.
1062 */
1063 public static function getUrlAllowList(array $data) {
1064 $list = [];
1065 foreach ($data as $item) {
1066 $list[] = [
1067 'url' => $item['url'],
1068 'id' => $item['id'],
1069 'created_at' => self::dateFormatter($item['createdAt']),
1070 'list_name' => 'url_allow',
1071 ];
1072 }
1073 return $list;
1074 }
1075
1076 /**
1077 * Convert IP list to be transferred to WebTotem.
1078 *
1079 * @param string $data
1080 * IP list.
1081 *
1082 * @return string
1083 * Returns the converted string.
1084 */
1085 public static function convertIpListForApi($data) {
1086 if (!$data) {
1087 return FALSE;
1088 }
1089
1090 $ips = preg_split("/(?(?=[\s,])[^.]|^$)/", $data);
1091
1092 if (is_array($ips)) {
1093 $ips_ = '[';
1094 foreach ($ips as $ip) {
1095 if (!empty($ip)) {
1096 $ips_ .= '"' . $ip . '",';
1097 }
1098 }
1099 $ips_ = substr($ips_, 0, -1);
1100 $ips_ .= ']';
1101 }
1102 else {
1103 $ips_ = '"' . $ips . '"';
1104 }
1105
1106 return $ips_;
1107 }
1108
1109 /**
1110 * Get data of the country with the most attacks.
1111 *
1112 * @param array $map
1113 * Map logs from WebTotem.
1114 * @param int $count_attacks
1115 * Total attacks.
1116 *
1117 * @return array
1118 * Returns array of data.
1119 */
1120 public static function getMostAttacksData($map) {
1121
1122 if ($map) {
1123 $most_attacks_key = array_search(max(array_column($map, 'attacks')), array_column($map, 'attacks'));
1124 $total_attacks = array_sum(array_column($map, 'attacks'));
1125
1126 $data['percent'] = ($total_attacks) ? round($map[$most_attacks_key]['attacks'] / $total_attacks * 100) : 0;
1127 $data['country'] = self::getCountryName($map[$most_attacks_key]['country']);
1128 $data['offset'] = 176 / 100 * (100 - $data['percent']);
1129
1130 return $data;
1131 }
1132
1133 return ['percent' => 0, 'country' => FALSE, 'offset' => 0];
1134 }
1135
1136 /**
1137 * Getting the country name by two-letter code.
1138 *
1139 * @param string $key
1140 * Two-letter code.
1141 *
1142 * @return string
1143 * Returns country name.
1144 */
1145 public static function getCountryName($key) {
1146 $countries = WebTotemCountryManager::getStandardList();
1147 $key = (string) $key;
1148
1149 return (array_key_exists($key, $countries)) ? $countries[$key] : $key;
1150 }
1151
1152
1153 /**
1154 * Get configs data.
1155 *
1156 * @param array $array
1157 * Original array.
1158 * @param string $key
1159 * The key to use as an index.
1160 *
1161 * @return array
1162 * Configs data array.
1163 */
1164 public static function getConfigsData(array $array, $key) {
1165 $configs = self::arrayMapIndex($array, $key);
1166
1167 foreach ($configs as $service => $config){
1168 $configs[$service]['checked'] = ($config['isActive']) ? 'checked' : '';
1169 $configs[$service]['notification_checked'] = (isset($config['notifications']) && $config['notifications']) ? 'checked' : '';
1170 }
1171
1172 return $configs;
1173 }
1174
1175 /**
1176 * Get waf setting data.
1177 *
1178 * @param array $settings
1179 * Original array.
1180 *
1181 * @return array
1182 * Configs data array.
1183 */
1184 public static function getWafSettingData(array $settings) {
1185 $_settings['gdn']['checked'] = (isset($settings['gdn']) && !$settings['gdn']) ? '' : 'checked';
1186 $_settings['dos'] = [
1187 'checked' => (isset($settings['dosProtection']) && !$settings['dosProtection']) ? '' : 'checked',
1188 'visually' => (isset($settings['dosProtection']) && !$settings['dosProtection']) ? 'visually-hidden' : '',
1189 ];
1190 $_settings['dos_limit'] = $settings['dosLimit'] ?: 1000;
1191
1192 $_settings['login_attempt'] = [
1193 'checked' => (isset($settings['loginAttemptsProtection']) && !$settings['loginAttemptsProtection']) ? '' : 'checked',
1194 'visually' => (isset($settings['loginAttemptsProtection']) && !$settings['loginAttemptsProtection']) ? 'visually-hidden' : '',
1195 ];
1196 $_settings['login_attempt_limit'] = $settings['loginAttemptsLimit'] ?: 20;
1197
1198 return $_settings;
1199 }
1200
1201 /**
1202 * Replace array indexes by key.
1203 *
1204 * @param array $array
1205 * Original array.
1206 * @param string $key
1207 * The key to use as an index.
1208 *
1209 * @return array
1210 * Returns a new array.
1211 */
1212 public static function arrayMapIndex(array $array, $key) {
1213 $new_array = [];
1214 foreach ($array as $item) {
1215 if (array_key_exists($key, $item)) {
1216 $new_array[$item[$key]] = $item;
1217 }
1218 }
1219 return $new_array;
1220 }
1221
1222 /**
1223 * Generate random string.
1224 *
1225 * @param int $length
1226 * The required length of the string.
1227 *
1228 * @return string
1229 * Returns random string.
1230 */
1231 public static function generateRandomString( int $length = 10): string {
1232 $characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_-';
1233 $charactersLength = strlen($characters);
1234 $randomString = '';
1235 for ($i = 0; $i < $length; $i++) {
1236 $randomString .= $characters[rand(0, $charactersLength - 1)];
1237 }
1238 return $randomString;
1239 }
1240
1241 /**
1242 * Encodes the less than, greater than, ampersand,double quote
1243 * and single quote characters. Will never double encode entities.
1244 *
1245 * @see https://developer.wordpress.org/reference/functions/esc_attr/
1246 *
1247 * @param string $text
1248 * The text which is to be encoded.
1249 *
1250 * @return string
1251 * The encoded text with HTML entities.
1252 */
1253 public static function escape($text = '')
1254 {
1255 return esc_attr($text);
1256 }
1257
1258 /**
1259 * Get notifications array.
1260 *
1261 * @return array
1262 * Returns notifications array.
1263 */
1264 public static function getNotifications() {
1265
1266 $notifications_data = WebTotemOption::getNotificationsData();
1267 $notifications = [];
1268
1269 foreach ($notifications_data as $notification) {
1270 switch ($notification['type']) {
1271 case 'error':
1272 $image = 'alert-error.svg';
1273 $class = 'wtotem_alert__title_red';
1274 break;
1275
1276 case 'warning':
1277 $image = 'alert-warning.svg';
1278 $class = 'wtotem_alert__title_yellow';
1279 break;
1280
1281 case 'success':
1282 $image = 'alert-success.svg';
1283 $class = 'wtotem_alert__title_green';
1284 break;
1285
1286 case 'info':
1287 $image = 'info-blue.svg';
1288 $class = 'wtotem_alert__title_blue';
1289 break;
1290 }
1291
1292 $notifications[] = [
1293 "text" => $notification['notice'],
1294 "id" => self::generateRandomString(8),
1295 "type" => self::getStatusText($notification['type']),
1296 "image" => $image,
1297 "class" => $class,
1298 ];
1299 }
1300
1301 return $notifications;
1302 }
1303
1304 /**
1305 * Get current agent installation statuses.
1306 *
1307 * @param array $agents_statuses
1308 * Agents statuses got from the WebTotem API.
1309 *
1310 * @return array
1311 * Returns an array with agent installation status data.
1312 */
1313 public static function getAgentsStatuses(array $agents_statuses) {
1314 $agents = ['am', 'waf', 'av'];
1315 $installing_statuses = [
1316 'not_installed',
1317 'installing',
1318 'internal_error',
1319 'update_error',
1320 'config_error',
1321 'session_error',
1322 ];
1323
1324 $process_statuses = [];
1325 $option_statuses = [];
1326
1327 foreach ($agents as $agent) {
1328 $status = WebTotemAgentManager::checkInstalledService($agent);
1329 $option_statuses[$agent] = $status['option_status'] ?: FALSE;
1330
1331 if ($agent == 'am') {
1332 if ($status['file_status']) {
1333 $process_statuses[$agent] = 'installed';
1334 }
1335 else {
1336 $process_statuses[$agent] = 'failed';
1337 }
1338 }
1339 else {
1340 if ($status['file_status']) {
1341 if (in_array($agents_statuses[$agent], $installing_statuses)) {
1342 $process_statuses[$agent] = 'installing';
1343 }
1344 elseif ($agents_statuses[$agent] == 'agent_not_available') {
1345 $process_statuses[$agent] = 'failed';
1346 }
1347 else {
1348 $process_statuses[$agent] = 'installed';
1349 }
1350 }
1351 else {
1352 $process_statuses[$agent] = 'installing';
1353 }
1354 }
1355 }
1356
1357 return [
1358 'process_statuses' => $process_statuses,
1359 'option_statuses' => $option_statuses,
1360 ];
1361 }
1362
1363 }
1364