PluginProbe
WebTotem Security / 2.4.10
WebTotem Security v2.4.10
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.10, at lib/Helper.php

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