PluginProbe
WebTotem Security / 2.4.3
WebTotem Security v2.4.3
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 2.2.4 All 109 releases
wt-security / lib / Helper.php

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

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