PluginProbe
WebTotem Security / 2.4.8
WebTotem Security v2.4.8
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.8, at lib/Helper.php

1,373 lines 36.0 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(array_key_exists('edges', $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
537 foreach ($services as $key => $service){
538 if(array_key_exists($key, $data) and is_array($data[$key]) and array_key_exists('status', $data[$key])){
539 $status = self::getServiceStatus($data[$key]['status']);
540
541 if(in_array($status['color'], ['red', 'yellow'])){
542 if(count($list) < 2){
543 $color = $status['color'] == 'red' ? 'white/' : '';
544
545 $list[$key] = [
546 'status' => $status,
547 'icon' => 'services/'. $color . $service . '.svg',
548 'name' => self::getServiceName( $service ),
549 ];
550 } else {
551 $other['names'][] = self::getServiceName( $service );
552 $other['count']++;
553 }
554 }
555
556 }
557 }
558 if($other['names']){
559 $other['names'] = implode(",", $other['names']);
560 }
561 return ['list' => $list, 'other' => $other];
562 }
563
564 /**
565 * Get the data associated with the status.
566 *
567 * @param string $status
568 * Module or agent status.
569 *
570 * @return array
571 * Returns an array with status data.
572 */
573 public static function getServiceStatus($status) {
574 switch ($status) {
575
576 case 'expired':
577 case 'invalid':
578 case 'error':
579 case 'expires_today':
580 case 'down':
581 case 'infected':
582 case 'deface':
583 case 'not_installed':
584 case 'quarantine':
585 $status_data = [
586 'color' => 'red',
587 ];
588 break;
589
590 case 'no_cert':
591 case 'expires':
592 case 'open_ports':
593 case 'modified':
594 case 'not_supported':
595 case 'not_registered':
596 case 'blocked':
597 case 'pause':
598 case 'internal_error':
599 case 'update_error':
600 case 'config_error':
601 case 'agent_not_available':
602 case 'session_error':
603 $status_data = [
604 'color' => 'yellow',
605 ];
606 break;
607
608 case 'clean':
609 case 'installed':
610 case 'up':
611 case 'scanned':
612 case 'working':
613 $status_data = [
614 'color' => 'green',
615 ];
616 break;
617
618 case 'deleted':
619 $status_data = [
620 'color' => 'black',
621 ];
622 break;
623
624 case 'installing':
625 case 'pending':
626 default:
627 $status_data = [
628 'color' => 'gray',
629 ];
630 break;
631
632 }
633
634 return $status_data;
635 }
636
637 /**
638 * Get the translation of service.
639 *
640 * @param $service
641 * Service short name.
642 *
643 * @return string
644 * Translation of service.
645 */
646 public static function getServiceName($service){
647 $services = [
648 "wa" => __('Availability', 'wtotem'),
649 "rc" => __('Reputation', 'wtotem'),
650 "ssl" => 'SSL',
651 "cms" => __('Technologies', 'wtotem'),
652 "dc" => __('Deface', 'wtotem'),
653 "ps" => __('Ports', 'wtotem'),
654 "waf" => __('Firewall', 'wtotem'),
655 "av" => __('Antivirus', 'wtotem'),
656 "dec" => __('Domain', 'wtotem'),
657 ];
658 return $services[$service];
659 }
660
661 /**
662 * Get reports with modules list.
663 *
664 * @param array $edges
665 * Data on generated reports.
666 *
667 * @return array
668 * Returns an array with converted data.
669 */
670 public static function getReports(array $edges) {
671 $modulesLang = [
672 'wa' => __('Availability log', 'wtotem'),
673 'dc' => __('Deface log', 'wtotem'),
674 'ps' => __('Port log', 'wtotem'),
675 'rc' => __('Reputation log', 'wtotem'),
676 'sc' => __('Evaluation log', 'wtotem'),
677 'av' => __('Antivirus log', 'wtotem'),
678 'waf' => __('Firewall log', 'wtotem'),
679 ];
680
681 $reports = [];
682
683 foreach ($edges as $edge) {
684 if (in_array(FALSE, $edge["node"])) {
685 $arr = [];
686 foreach ($edge["node"] as $module => $value) {
687 if ($value == TRUE && array_key_exists($module, $modulesLang)) {
688 $arr[] = $modulesLang[$module];
689 }
690 }
691 $modules = implode(", ", $arr);
692 }
693 else {
694 $modules = __('All modules', 'wtotem');
695 }
696
697 $reports[] = [
698 'id' => $edge["node"]['id'],
699 'modules' => $modules,
700 'created_at' => self::dateFormatter($edge["node"]['createdAt']),
701 ];
702 }
703
704 return $reports;
705 }
706
707 /**
708 * Get reputation status description.
709 *
710 * @param string $status
711 * Reputation status.
712 *
713 * @return string
714 * Returns a description of the reputation status
715 */
716 public static function getReputationInfo($status) {
717 switch ($status) {
718 case 'clean':
719 $data = __("Don't worry, your reputation is good", 'wtotem');
720 break;
721
722 case 'infected':
723 $data = __('Oh, your reputation is bad', 'wtotem');
724 break;
725
726 default:
727 $data = __('Information is being updated', 'wtotem');
728 }
729 return $data;
730 }
731
732 /**
733 * Get blacklists entries counts.
734 *
735 * @param string $status
736 * Reputation status.
737 * @param array $virus_list
738 * Sources where the site can be blacklisted.
739 *
740 * @return int
741 * Number of references in blacklists.
742 */
743 public static function blacklistsEntries($status, array $virus_list) {
744 $count = 0;
745 if ($status != "clean") {
746 foreach ($virus_list as &$list) {
747 if (!empty($list['virus']['type'])) {
748 $count++;
749 }
750 }
751 }
752 return $count;
753 }
754
755 /**
756 * Classification of the rating in the letter grades.
757 *
758 * @param int $score
759 * Site rating from 1 to 100.
760 *
761 * @return array
762 * Returns an array of data.
763 */
764 public static function scoreGrading($score) {
765 if ($score < 0 || $score > 100) {
766 return ['grade' => '', 'color' => ''];
767 }
768
769 $scores = [
770 100 => 'A+',
771 90 => 'A',
772 80 => 'A-',
773 70 => 'B+',
774 60 => 'B',
775 50 => 'B-',
776 35 => 'C+',
777 20 => 'C',
778 0 => 'C-',
779 ];
780
781 foreach ($scores as $key => $value) {
782 if ($score >= $key) {
783 $grade = $value;
784 break;
785 }
786 }
787
788 // Set a color depending on the grade.
789 switch ($score) {
790 case $score >= 80:
791 $color = 'green';
792 break;
793
794 case $score >= 50:
795 $color = 'orange';
796 break;
797
798 default:
799 $color = 'red';
800 }
801
802 return ['grade' => $grade, 'color' => $color];
803 }
804
805 /**
806 * Calculate the number of remaining days.
807 *
808 * @param string $date
809 * Expiry date.
810 *
811 * @return string
812 * Returns the number of days before the expiration date.
813 */
814 public static function daysLeft($date) {
815 if ((int) $date === 0) {
816 $days_left = 0;
817 }
818 else {
819 $now = new \DateTime();
820 $expiry_date = new \DateTime();
821 $timestamp = strtotime($date);
822 $expiry_date->setTimestamp($timestamp);
823 $days_left = $expiry_date->diff($now)->format("%a");
824 }
825 return $days_left;
826 }
827
828 /**
829 * Converting the firewall logs.
830 *
831 * @param array $logs_
832 * Firewall logs from WebTotem.
833 *
834 * @return array
835 * Converted array of logs.
836 */
837 public static function wafLogs(array $logs_) {
838 $logs = [];
839 foreach ($logs_ as $key => $log) {
840 $log = $log['node'];
841
842 $logs[$key]['ip'] = $log['ip'];
843 $logs[$key]['request'] = htmlspecialchars(urldecode($log['request']));
844 $logs[$key]['time'] = self::dateFormatter($log['time']);
845 $logs[$key]['country_code'] = strtolower($log['country']);
846 $logs[$key]['country'] = $log['location']['country']['nameEn'];
847 $logs[$key]['blocked'] = $log['blocked'] ? __('Blocked IP', 'wtotem') : __('Not blocked', 'wtotem');
848 }
849 return $logs;
850 }
851
852 /**
853 * Converting firewall data to json for a D3 chart.
854 *
855 * @param array $charts
856 * Charts data from WebTotem.
857 *
858 * @return array
859 * Returns the converted data for chart.
860 */
861 public static function generateWafChart(array $charts) {
862 $sum = 0;
863 foreach ($charts as $chart) {
864 $sum += $chart['attacks'];
865 }
866 if ($sum == 0) {
867 return ['chart' => FALSE, 'count_attacks' => 0, 'count_blocks' => 0];
868 }
869
870 // Get days count.
871 $charts_ = $charts;
872 $first = array_shift($charts_);
873 $last = array_pop($charts_);
874 $days = ceil((strtotime($last['time']) - strtotime($first['time'])) / 86400);
875
876 // Set variables.
877 $count_attacks = $count_blocks = 0;
878
879 foreach ($charts as $chart) {
880 if ($days <= 1) {
881 $time_zone = WebTotemOption::getOption('time_zone_offset');
882 $userTime = ($time_zone) ? strtotime($time_zone . ' hours', strtotime($chart['time'])) : strtotime($chart['time']);
883 }
884 if (($chart['attacks'] and $days == 2) or $days != 2) {
885 $result[] = [
886 'date' => ($days <= 1) ? date("Y-m-d H:00:00", $userTime) : date("Y-m-d", strtotime($chart['time'])),
887 'count' => $chart['blocked'],
888 'attacks' => $chart['attacks'],
889 'blocked' => $chart['blocked'],
890 ];
891 $count_attacks += $chart['attacks'];
892 $count_blocks += $chart['blocked'];
893 }
894 }
895
896 if (!isset($result)) {
897 return [
898 'chart' => FALSE,
899 'count_attacks' => 0,
900 'count_blocks' => 0,
901 ];
902 }
903
904 return [
905 'chart' => json_encode($result),
906 'count_attacks' => $count_attacks,
907 'count_blocks' => $count_blocks,
908 'days' => $days,
909 ];
910 }
911
912 /**
913 * Converting data to json for a D3 chart.
914 *
915 * @param array $charts
916 * Charts data from WebTotem.
917 * @param int $days
918 * The number of days to build the chart.
919 *
920 * @return bool|string
921 * Returns the converted data for chart.
922 */
923 public static function generateChart(array $charts, $days = 7) {
924 $sum = 0;
925 foreach ($charts as $chart) {
926 $sum += $chart['value'];
927 }
928 if ($sum == 0) {
929 return FALSE;
930 }
931
932 $result = [];
933
934 foreach ($charts as $chart) {
935 if ($days <= 1) {
936 $time_zone = WebTotemOption::getOption('time_zone_offset');
937 $userTime = ($time_zone) ? strtotime($time_zone . 'hours', strtotime($chart['time'])) : strtotime($chart['time']);
938 }
939 $result[] = [
940 'date' => ($days <= 1) ? date("Y-m-d H:00:00", $userTime) : date("Y-m-d", strtotime($chart['time'])),
941 'value' => $chart['value'],
942 ];
943 }
944
945 return json_encode($result, TRUE);
946 }
947
948 /**
949 * Converting data to json for a D3 chart.
950 *
951 * @param array $data
952 * Charts data from WebTotem.
953 *
954 * @return array|bool
955 * Returns the converted data for chart.
956 */
957 public static function generateAttacksMapChart(array $data) {
958 $attacks = [];
959 $countries = [];
960 $labels = [];
961 foreach ($data as $value) {
962 $attacks[] = $value['attacks'];
963 $labels[] = self::getCountryName($value['country']);
964 $countries[] = $value['location']['country']['nameEn'];
965 }
966 $result = ['attacks' => $attacks, 'countries' => $countries, 'labels' => $labels];
967
968 if (!$attacks) {
969 return FALSE;
970 }
971
972 return json_encode($result, TRUE);
973 }
974
975 /**
976 * Reassembling the antivirus logs.
977 *
978 * @param array $logs_
979 * Antivirus logs from WebTotem.
980 *
981 * @return array
982 * Reassembled array of logs.
983 */
984 public static function getAntivirusLogs(array $logs_) {
985 $logs = [];
986 foreach ($logs_ as $key => $log) {
987 $log = $log['node'];
988
989 $file_info = new SplFileInfo(urldecode($log['filePath']));
990
991 $log['original_path'] = $log['filePath'];
992 $log['file_path'] = $file_info->getPath() . '/';
993 $log['file_name'] = $file_info->getFilename();
994 $log['time'] = self::dateFormatter($log['time']);
995 $log['permissions_changed'] = $log['permissionsChanged'];
996 $log['status'] = self::getStatusData($log['event']);
997 $log['class'] = 'wt-text--green';
998
999 switch ($log['event']) {
1000 case 'modified':
1001 case 'quarantine':
1002 $log['class'] = "wt-text--yellow";
1003 break;
1004
1005 case 'deleted':
1006 $log['class'] = "wt-text--light-gray";
1007 break;
1008
1009 case 'infected':
1010 $log['class'] = "wt-text--red";
1011 break;
1012 }
1013
1014 $logs[$key] = $log;
1015 }
1016 return $logs;
1017 }
1018
1019 /**
1020 * Reassembling the quarantine logs.
1021 *
1022 * @param array $logs_
1023 * Quarantine logs from WebTotem.
1024 *
1025 * @return array
1026 * Reassembled array of logs.
1027 */
1028 public static function getQuarantineLogs(array $logs_) {
1029 $logs = [];
1030 foreach ($logs_ as $key => $log) {
1031 $logs[$key] = $log;
1032 $logs[$key]['path'] = urldecode($log['path']);
1033 $logs[$key]['date'] = self::dateFormatter($log['date']);
1034 }
1035
1036 return $logs;
1037 }
1038
1039 /**
1040 * Generate an array of IP address data.
1041 *
1042 * @param array $data
1043 * IP addresses data from WebTotem.
1044 * @param string $list_name
1045 * Allow or deny list.
1046 *
1047 * @return array
1048 * Returns array of data.
1049 */
1050 public static function getIpList(array $data, $list_name) {
1051 $list = [];
1052 foreach ($data as $item) {
1053 $list[] = [
1054 'ip' => $item['ip'],
1055 'id' => $item['id'],
1056 'created_at' => self::dateFormatter($item['createdAt']),
1057 'list_name' => $list_name,
1058 ];
1059 }
1060 return $list;
1061 }
1062
1063 /**
1064 * Generate an array of URL address data.
1065 *
1066 * @param array $data
1067 * URL addresses data from WebTotem.
1068 *
1069 * @return array
1070 * Returns array of data.
1071 */
1072 public static function getUrlAllowList(array $data) {
1073 $list = [];
1074 foreach ($data as $item) {
1075 $list[] = [
1076 'url' => $item['url'],
1077 'id' => $item['id'],
1078 'created_at' => self::dateFormatter($item['createdAt']),
1079 'list_name' => 'url_allow',
1080 ];
1081 }
1082 return $list;
1083 }
1084
1085 /**
1086 * Convert IP list to be transferred to WebTotem.
1087 *
1088 * @param string $data
1089 * IP list.
1090 *
1091 * @return string
1092 * Returns the converted string.
1093 */
1094 public static function convertIpListForApi($data) {
1095 if (!$data) {
1096 return FALSE;
1097 }
1098
1099 $ips = preg_split("/(?(?=[\s,])[^.]|^$)/", $data);
1100
1101 if (is_array($ips)) {
1102 $ips_ = '[';
1103 foreach ($ips as $ip) {
1104 if (!empty($ip)) {
1105 $ips_ .= '"' . $ip . '",';
1106 }
1107 }
1108 $ips_ = substr($ips_, 0, -1);
1109 $ips_ .= ']';
1110 }
1111 else {
1112 $ips_ = '"' . $ips . '"';
1113 }
1114
1115 return $ips_;
1116 }
1117
1118 /**
1119 * Get data of the country with the most attacks.
1120 *
1121 * @param array $map
1122 * Map logs from WebTotem.
1123 * @param int $count_attacks
1124 * Total attacks.
1125 *
1126 * @return array
1127 * Returns array of data.
1128 */
1129 public static function getMostAttacksData($map) {
1130
1131 if ($map) {
1132 $most_attacks_key = array_search(max(array_column($map, 'attacks')), array_column($map, 'attacks'));
1133 $total_attacks = array_sum(array_column($map, 'attacks'));
1134
1135 $data['percent'] = ($total_attacks) ? round($map[$most_attacks_key]['attacks'] / $total_attacks * 100) : 0;
1136 $data['country'] = self::getCountryName($map[$most_attacks_key]['country']);
1137 $data['offset'] = 176 / 100 * (100 - $data['percent']);
1138
1139 return $data;
1140 }
1141
1142 return ['percent' => 0, 'country' => FALSE, 'offset' => 0];
1143 }
1144
1145 /**
1146 * Getting the country name by two-letter code.
1147 *
1148 * @param string $key
1149 * Two-letter code.
1150 *
1151 * @return string
1152 * Returns country name.
1153 */
1154 public static function getCountryName($key) {
1155 $countries = WebTotemCountryManager::getStandardList();
1156 $key = (string) $key;
1157
1158 return (array_key_exists($key, $countries)) ? $countries[$key] : $key;
1159 }
1160
1161
1162 /**
1163 * Get configs data.
1164 *
1165 * @param array $array
1166 * Original array.
1167 * @param string $key
1168 * The key to use as an index.
1169 *
1170 * @return array
1171 * Configs data array.
1172 */
1173 public static function getConfigsData(array $array, $key) {
1174 $configs = self::arrayMapIndex($array, $key);
1175
1176 foreach ($configs as $service => $config){
1177 $configs[$service]['checked'] = ($config['isActive']) ? 'checked' : '';
1178 $configs[$service]['notification_checked'] = (isset($config['notifications']) && $config['notifications']) ? 'checked' : '';
1179 }
1180
1181 return $configs;
1182 }
1183
1184 /**
1185 * Get waf setting data.
1186 *
1187 * @param array $settings
1188 * Original array.
1189 *
1190 * @return array
1191 * Configs data array.
1192 */
1193 public static function getWafSettingData(array $settings) {
1194 $_settings['gdn']['checked'] = (isset($settings['gdn']) && !$settings['gdn']) ? '' : 'checked';
1195 $_settings['dos'] = [
1196 'checked' => (isset($settings['dosProtection']) && !$settings['dosProtection']) ? '' : 'checked',
1197 'visually' => (isset($settings['dosProtection']) && !$settings['dosProtection']) ? 'visually-hidden' : '',
1198 ];
1199 $_settings['dos_limit'] = $settings['dosLimit'] ?: 1000;
1200
1201 $_settings['login_attempt'] = [
1202 'checked' => (isset($settings['loginAttemptsProtection']) && !$settings['loginAttemptsProtection']) ? '' : 'checked',
1203 'visually' => (isset($settings['loginAttemptsProtection']) && !$settings['loginAttemptsProtection']) ? 'visually-hidden' : '',
1204 ];
1205 $_settings['login_attempt_limit'] = $settings['loginAttemptsLimit'] ?: 20;
1206
1207 return $_settings;
1208 }
1209
1210 /**
1211 * Replace array indexes by key.
1212 *
1213 * @param array $array
1214 * Original array.
1215 * @param string $key
1216 * The key to use as an index.
1217 *
1218 * @return array
1219 * Returns a new array.
1220 */
1221 public static function arrayMapIndex(array $array, $key) {
1222 $new_array = [];
1223 foreach ($array as $item) {
1224 if (array_key_exists($key, $item)) {
1225 $new_array[$item[$key]] = $item;
1226 }
1227 }
1228 return $new_array;
1229 }
1230
1231 /**
1232 * Generate random string.
1233 *
1234 * @param int $length
1235 * The required length of the string.
1236 *
1237 * @return string
1238 * Returns random string.
1239 */
1240 public static function generateRandomString( int $length = 10): string {
1241 $characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_-';
1242 $charactersLength = strlen($characters);
1243 $randomString = '';
1244 for ($i = 0; $i < $length; $i++) {
1245 $randomString .= $characters[rand(0, $charactersLength - 1)];
1246 }
1247 return $randomString;
1248 }
1249
1250 /**
1251 * Encodes the less than, greater than, ampersand,double quote
1252 * and single quote characters. Will never double encode entities.
1253 *
1254 * @see https://developer.wordpress.org/reference/functions/esc_attr/
1255 *
1256 * @param string $text
1257 * The text which is to be encoded.
1258 *
1259 * @return string
1260 * The encoded text with HTML entities.
1261 */
1262 public static function escape($text = '')
1263 {
1264 return esc_attr($text);
1265 }
1266
1267 /**
1268 * Get notifications array.
1269 *
1270 * @return array
1271 * Returns notifications array.
1272 */
1273 public static function getNotifications() {
1274
1275 $notifications_data = WebTotemOption::getNotificationsData();
1276 $notifications = [];
1277
1278 foreach ($notifications_data as $notification) {
1279 switch ($notification['type']) {
1280 case 'error':
1281 $image = 'alert-error.svg';
1282 $class = 'wtotem_alert__title_red';
1283 break;
1284
1285 case 'warning':
1286 $image = 'alert-warning.svg';
1287 $class = 'wtotem_alert__title_yellow';
1288 break;
1289
1290 case 'success':
1291 $image = 'alert-success.svg';
1292 $class = 'wtotem_alert__title_green';
1293 break;
1294
1295 case 'info':
1296 $image = 'info-blue.svg';
1297 $class = 'wtotem_alert__title_blue';
1298 break;
1299 }
1300
1301 $notifications[] = [
1302 "text" => $notification['notice'],
1303 "id" => self::generateRandomString(8),
1304 "type" => self::getStatusText($notification['type']),
1305 "image" => $image,
1306 "class" => $class,
1307 ];
1308 }
1309
1310 return $notifications;
1311 }
1312
1313 /**
1314 * Get current agent installation statuses.
1315 *
1316 * @param array $agents_statuses
1317 * Agents statuses got from the WebTotem API.
1318 *
1319 * @return array
1320 * Returns an array with agent installation status data.
1321 */
1322 public static function getAgentsStatuses(array $agents_statuses) {
1323 $agents = ['am', 'waf', 'av'];
1324 $installing_statuses = [
1325 'not_installed',
1326 'installing',
1327 'internal_error',
1328 'update_error',
1329 'config_error',
1330 'session_error',
1331 ];
1332
1333 $process_statuses = [];
1334 $option_statuses = [];
1335
1336 foreach ($agents as $agent) {
1337 $status = WebTotemAgentManager::checkInstalledService($agent);
1338 $option_statuses[$agent] = $status['option_status'] ?: FALSE;
1339
1340 if ($agent == 'am') {
1341 if ($status['file_status']) {
1342 $process_statuses[$agent] = 'installed';
1343 }
1344 else {
1345 $process_statuses[$agent] = 'failed';
1346 }
1347 }
1348 else {
1349 if ($status['file_status']) {
1350 if (in_array($agents_statuses[$agent], $installing_statuses)) {
1351 $process_statuses[$agent] = 'installing';
1352 }
1353 elseif ($agents_statuses[$agent] == 'agent_not_available') {
1354 $process_statuses[$agent] = 'failed';
1355 }
1356 else {
1357 $process_statuses[$agent] = 'installed';
1358 }
1359 }
1360 else {
1361 $process_statuses[$agent] = 'installing';
1362 }
1363 }
1364 }
1365
1366 return [
1367 'process_statuses' => $process_statuses,
1368 'option_statuses' => $option_statuses,
1369 ];
1370 }
1371
1372 }
1373