PluginProbe
WebTotem Security / 3.0.2
WebTotem Security v3.0.2
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 3.0.2, at lib/Helper.php

1,987 lines 53.7 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 public static function log($notice){
16 file_put_contents(WEBTOTEM_PLUGIN_PATH . '/wtotem_log.txt', date('Y-m-d H:i:s') . ' ' . $notice . PHP_EOL, FILE_APPEND);
17 }
18
19 /**
20 * Returns an URL from the admin dashboard.
21 *
22 * @param string $url
23 * Optional trailing of the URL.
24 * @return string
25 * Full valid URL from the admin dashboard.
26 */
27 public static function adminURL($url = '') {
28 if (self::isMultiSite() and is_super_admin()) {
29 return network_admin_url($url);
30 }
31 return admin_url($url);
32 }
33
34 /**
35 * Define role of current user.
36 *
37 */
38 public static function getUserRole() {
39
40 if (defined('WEBTOTEM_USER_ROLE')) {
41 return true;
42 }
43 $current_user = wp_get_current_user();
44 if ( !($current_user instanceof WP_User) ){
45 $user_role = 0;
46 } else {
47 $roles = $current_user->roles;
48
49 if(in_array('administrator', $roles)) {
50 $user_role = 1;
51 } elseif(in_array('editor', $roles) or current_user_can('publish_posts')) {
52 $user_role = 2;
53 } else {
54 $user_role = 0;
55 }
56 }
57
58 define( 'WEBTOTEM_USER_ROLE', $user_role );
59
60 return true;
61 }
62
63 /**
64 * Check whether the current site is working as a multi-site instance.
65 *
66 * @return bool
67 * Either TRUE or FALSE in case WordPress is being used as a multi-site instance.
68 */
69 public static function isMultiSite() {
70 return (bool) ( (function_exists('is_multisite') && is_multisite()) || (defined('MULTISITE') && MULTISITE == true) );
71 }
72
73
74 /**
75 * Get user email.
76 *
77 * @return string
78 * Returns user email.
79 */
80 public static function getUserEmail() {
81 $email = WebTotemOption::getOption( "user_email" );
82 if(!$email){
83 if(WebTotemOption::isActivated()) {
84 // $email = WebTotemAPI::getEmail();
85 }
86 WebTotemOption::setOptions(['user_email' => $email]);
87 }
88 return $email;
89 }
90
91 /**
92 * Returns the md5 hash representing the content of a file.
93 *
94 * @param string $file
95 * Relative path to the file.
96 * @return string
97 * Seven first characters in the hash of the file.
98 */
99 public static function fileVersion($file = '') {
100 return substr(md5_file(WEBTOTEM_PLUGIN_PATH . '/' . $file), 0, 7);
101 }
102
103 /**
104 * Returns full path to image.
105 *
106 * @param string $image
107 * Relative path to the file.
108 * @return string
109 * Full path to image.
110 */
111 public static function getImagePath($image) {
112 return WEBTOTEM_URL. '/includes/img/' . $image;
113 }
114
115 /**
116 * Checking whether the current domain belongs to the kz domain zone.
117 *
118 * @return bool
119 * true is returned if the domain belongs to the kz domain zone.
120 */
121 public static function isKz() {
122 $is_kz = json_decode(WebTotemOption::getOption('is_kz'), true);
123 if(is_array($is_kz)){
124 return $is_kz['value'];
125 }
126
127 if(function_exists('idn_to_utf')){
128 $host = idn_to_utf8($_SERVER['HTTP_HOST']);
129 } else {
130 $host = $_SERVER['HTTP_HOST'];
131 }
132
133 $parts = explode('.', $host);
134 $domain_zone = $parts[count($parts)-1];
135
136 if($domain_zone === 'kz' or $domain_zone === 'қаз'){
137 $is_kz['value'] = true;
138 } else {
139 $is_kz['value'] = false;
140 }
141
142 WebTotemOption::setOptions(['is_kz' => $is_kz]);
143
144 return $is_kz['value'];
145 }
146
147 /**
148 * Convert object to array.
149 *
150 * @param array $data
151 * Array.
152 * @return array
153 * Returns array.
154 */
155 public static function convertObjectToArray($data){
156
157 if(!is_array($data)) $data = (array)$data;
158 array_walk_recursive($data, function(&$item){
159 if(is_object($item)) $item = (array)$item;
160 });
161
162 return $data;
163 }
164
165 /**
166 * Decodes a Base64URL-encoded string into a regular string.
167 *
168 * Base64URL is a URL-safe variant of Base64 commonly used in JWT and other web standards.
169 * In Base64URL, the '+' and '/' characters are replaced with '-' and '_', and the '=' padding is often omitted.
170 * This function converts Base64URL back to standard Base64 and then decodes it.
171 *
172 * @param string $data The input string encoded in Base64URL format.
173 *
174 * @return string|false Returns the decoded string, or false if decoding fails.
175 */
176 public static function base64UrlDecode($data) {
177 $remainder = strlen($data) % 4;
178 if ($remainder) {
179 $data .= str_repeat('=', 4 - $remainder);
180 }
181 return base64_decode(strtr($data, '-_', '+/'));
182 }
183
184 /**
185 * Removing duplicates by one key.
186 *
187 * @param array $array
188 * Array.
189 * @param string $key
190 * Delete duplicates with the same key.
191 *
192 * @return array
193 * Returns array.
194 */
195 public static function arrayUniqueKey($array, $key) {
196 $tmp = $key_array = array();
197 $i = 0;
198
199 foreach ($array as $val) {
200 if (!in_array($val[$key], $key_array)) {
201 $key_array[$i] = $val[$key];
202 $tmp[$i] = $val;
203 }
204 $i++;
205 }
206 return $tmp;
207 }
208
209 /**
210 * Returns user IP address.
211 *
212 * @return string
213 * Returns user IP address.
214 */
215 public static function getUserIP() {
216 $arr = [
217 'HTTP_CLIENT_IP',
218 'HTTP_X_FORWARDED_FOR',
219 'HTTP_X_FORWARDED',
220 'HTTP_X_CLUSTER_CLIENT_IP',
221 'HTTP_FORWARDED_FOR',
222 'HTTP_FORWARDED',
223 'HTTP_CF_CONNECTING_IP',
224 'REMOTE_ADDR'
225 ];
226
227 foreach ($arr as $key){
228 if (array_key_exists($key, $_SERVER) === true) {
229 foreach (explode(',', $_SERVER[$key]) as $ip) {
230 $ip = trim($ip);
231 $ip = filter_var($ip, FILTER_VALIDATE_IP);
232 if (!empty($ip)) {
233 return $ip;
234 }
235 }
236 }
237 }
238 return false;
239 }
240
241 /**
242 * Convert the file size to а human-readable format.
243 *
244 * @param string $bytes
245 * File size in bytes.
246 * @param string $decimals
247 * The number of characters after the decimal point.
248 *
249 * @return string
250 * Returns the file size in a human-readable format.
251 */
252 public static function humanFilesize($bytes, $decimals = 2) {
253 $factor = floor((strlen($bytes) - 1) / 3);
254 $unit_of_measurement = ($factor > 0) ? substr("KMGT", $factor - 1, 1) : '';
255 $size = sprintf("%.{$decimals}f", $bytes / pow(1024, $factor)) . $unit_of_measurement . 'B';
256 return str_replace(".00", "", $size);
257 }
258
259 /**
260 * Check whether the file is publicly accessible.
261 *
262 * @param string $url
263 * http link to the file.
264 * @param string $path
265 * The path to the file.
266 *
267 * @return bool
268 */
269 public static function isPubliclyAccessible($url, $path) {
270 $response = wp_remote_get($url);
271
272 if ((int) floor(((int) wp_remote_retrieve_response_code($response) / 100)) === 2) {
273 $handle = @fopen($path, 'r');
274 if ($handle) {
275 $contents = fread($handle, 700);
276 fclose($handle);
277 $remoteContents = substr(wp_remote_retrieve_body($response), 0, 700);
278
279 return $contents === $remoteContents;
280 }
281 }
282 return false;
283 }
284
285 /**
286 * Check that the training period has passed for the firewall.
287 *
288 * @return bool
289 * Returns boolean.
290 */
291 public static function isWafTraining() {
292 $created_at = WebTotemOption::getOption('am_created_at');
293 if($created_at) {
294 $when_waf_trained = strtotime('+2 day', strtotime($created_at));
295 $today = strtotime('today');
296
297 return ($when_waf_trained < $today) ? FALSE : TRUE;
298 }
299 return FALSE;
300 }
301
302 /**
303 * Check if the data for the period is available.
304 *
305 * @param string $created_at
306 * Date when the agent manager was created.
307 *
308 * @return array
309 * Returns an array with periods.
310 */
311 public static function isPeriodAvailable() {
312
313 $created_at = WebTotemOption::getOption('am_created_at');
314 if(!$created_at){
315 return [
316 'monthly' => false,
317 'yearly' => false,
318 ];
319 }
320 $diff = strtotime(gmdate("Y-m-d H:i:s")) - strtotime($created_at);
321 $daysCount = floor($diff / 86400);
322
323 return [
324 'monthly' => $daysCount > 7,
325 'yearly' => $daysCount > 30,
326 ];
327
328 }
329
330 /**
331 * Converting a date to the appropriate format.
332 *
333 * @param string $date
334 * Date in any format.
335 * @param string $format
336 * The format to which you want to convert the date.
337 *
338 * @return string
339 * Returns converted Date.
340 * @throws Exception
341 */
342 public static function dateFormatter($date, $format = 'M j, Y \/ H:i') {
343 if (!$date) {
344 return __('Unknown', 'wtotem');
345 }
346
347 if ( is_numeric($date) && (int)$date == $date ){
348 $date = date('Y-m-d H:i', $date);
349 }
350
351 if($wp_timezone = wp_timezone()){
352 $UTC = new DateTimeZone("UTC");
353 $date = new DateTime( $date, $UTC );
354 $date->setTimezone( new DateTimeZone($wp_timezone->getName()) );
355 return date_i18n($format,strtotime($date->format('Y-m-d H:i')));
356 }
357
358 $time_zone = WebTotemOption::getOption('time_zone_offset');
359 $user_time = ($time_zone) ? strtotime($time_zone . 'hours', strtotime($date)) : strtotime($date);
360
361 return date_i18n($format, $user_time);
362 }
363
364 /**
365 * Get theme mode data.
366 *
367 * @return array
368 * Returns array with current theme data.
369 */
370 public static function getThemeMode() {
371 $theme_mode = WebTotemOption::getSessionOption('theme_mode');
372 return [
373 "is_dark_mode" => $theme_mode == 'dark' ? 'wtotem_theme—dark' : '',
374 "dark_mode_checked" => $theme_mode == 'dark' ? 'checked' : '',
375 ];
376 }
377
378 /**
379 * Get current user language.
380 *
381 * @return string
382 * Returns current language in 2-letter abbreviations
383 */
384 public static function getLanguage() {
385 $current_language = substr(get_bloginfo('language'), 0,2);
386 $language = (in_array($current_language,['ru','en','pl'])) ? $current_language : 'en' ;
387 return $language;
388 }
389
390 /**
391 * Converting a date to the appropriate format.
392 *
393 * @param string|array $days
394 * Number of days or period to convert.
395 *
396 * @return array
397 * Returns an array of two values "from" and "to"
398 */
399 public static function getPeriod($days) {
400
401 if (!$days) {
402 $days = 30;
403 }
404
405 switch ($days) {
406
407 case is_array($days):
408 $to = $days[1] ?: $days[0];
409 $period = [
410 'from' => date('Y-m-d 00:00:01', strtotime(self::formatDate($days[0]))),
411 'to' => date('Y-m-d 23:59:59', strtotime(self::formatDate($to))),
412 ];
413 break;
414
415 case $days <= 1:
416 $period = [
417 'from' => date('Y-m-d H:m:i', strtotime('-24 hours')),
418 'to' => date('Y-m-d H:m:i', time()),
419 ];
420 break;
421
422 default:
423 $period = [
424 'from' => date('Y-m-d H:m:i', time() - ($days * 86400)),
425 'to' => date('Y-m-d H:m:i'),
426 ];
427 }
428
429 return $period;
430 }
431
432 /**
433 * Converting a date from "j M, Y" format to 'd-m-Y' format.
434 *
435 * @return string
436 * Returns date in new format
437 */
438 public static function formatDate($date){
439 $month = [
440 'Jan' => 'Янв',
441 'Feb' => 'Фев',
442 'Mar' => 'Мар',
443 'Apr' => 'Апр',
444 'May' => 'Май',
445 'Jun' => 'Июн',
446 'Jul' => 'Июл',
447 'Aug' => 'Авг',
448 'Sep' => 'Сен',
449 'Oct' => 'Окт',
450 'Nov' => 'Ноя',
451 'Dec' => 'Дек',
452 ];
453
454 foreach ($month as $key => $value) {
455 if (strpos($date, $value)) {
456 $date = str_replace($value, $key, $date);
457 }
458 }
459
460 $pattern = '/^(\d{1,2})\s+([a-zA-Z]+),\s+(\d{4})$/';
461
462 if (preg_match($pattern, $date, $matches)) {
463 $monthNumber = date_parse($matches[2])['month'];
464
465 return sprintf('%02d-%02d-%04d', $matches[1], $monthNumber, $matches[3]);
466 }
467
468 return $date;
469
470 }
471
472 /**
473 * Convert an array to a string with quotation marks.
474 *
475 * @param array $array
476 * Data array.
477 *
478 * @return string
479 * Array of data converted to string.
480 */
481 public static function convertArrayToString($array) {
482 if(empty($array)){
483 return '';
484 }
485 return '"' . implode('","', $array) . '"';
486 }
487
488 /**
489 * Converting the response to a readable form.
490 *
491 * @param string $message
492 * Message response from the API server to the request.
493 *
494 * @return string|bool
495 * Returns a message.
496 */
497 public static function messageForHuman($message) {
498
499 $definition = $message;
500
501 switch ($message) {
502 case 'HOSTS_LIMIT_EXCEEDED':
503 $definition = __('Limit of adding sites exceeded.', 'wtotem');
504 break;
505
506 case 'USER_ALREADY_REGISTERED':
507 $definition = __('A user with this email already exists.', 'wtotem');
508 break;
509
510 case 'DUPLICATE_HOST':
511 $definition = __('Duplicate host', 'wtotem');
512 break;
513
514 case 'INVALID_DOMAIN_NAME':
515 $definition = __('Invalid Domain Name', 'wtotem');
516 break;
517 default:
518 $definition = str_replace("_", " ", $definition);
519 $definition = ucfirst(strtolower($definition));
520
521 }
522 return $definition;
523 }
524
525 /**
526 * Get the data associated with the status.
527 *
528 * @param string $status
529 * Module or agent status.
530 *
531 * @return array
532 * Returns an array with status data.
533 */
534 public static function getStatusData($status) {
535 $path = self::getImagePath('');
536 $status = ($status == "installed") ? 'working' : $status;
537
538 switch ($status) {
539
540 case 'clean':
541 case 'up':
542 case 'installed':
543 case 'available':
544 case 'enable':
545 case 'working':
546 case 'good':
547 $status_data = [
548 'class' => 'is--status--ok',
549 'image' => $path . 'check-mark.svg',
550 'icon' => $path . 'icon_success_status.svg',
551 ];
552 break;
553
554 case 'pending':
555 $status_data = [
556 'class' => 'is--status--pending',
557 'image' => $path . 'loading.svg',
558 'icon' => $path . 'alert-warning.svg',
559 ];
560 break;
561
562 case 'pause':
563 case 'modified':
564 $status_data = [
565 'class' => 'is--status--pending',
566 'image' => $path . 'warning.svg',
567 'icon' => $path . 'alert-warning.svg',
568 ];
569 break;
570
571 case 'expired':
572 case 'no_cert':
573 case 'expires':
574 case 'open_ports':
575 case 'warning':
576 case 'not_supported':
577 case 'not_registered':
578 $status_data = [
579 'class' => 'is--status--warning',
580 'image' => $path . 'warning.svg',
581 'icon' => $path . 'alert-warning.svg',
582 ];
583 break;
584
585 case 'invalid':
586 case 'revoked':
587 case 'untrusted':
588 case 'not_found':
589 case 'wrong_host':
590 case 'error':
591 case 'down':
592 case 'expires_today':
593 case 'infected':
594 case 'deface':
595 case 'not_installed':
596 $status_data = [
597 'class' => 'is--status--error',
598 'image' => $path . 'warning.svg',
599 'icon' => $path . 'alert-warning.svg',
600 ];
601 break;
602
603 default:
604 $status_data = [
605 'class' => 'is--status--pending',
606 'image' => $path . 'warning.svg',
607 'icon' => $path . 'alert-warning.svg',
608 ];
609 }
610 $status_data['name'] = $status;
611 $status_data['text'] = self::getStatusText($status);
612 $status_data['tooltips'] = self::getTooltips($status);
613
614 return $status_data;
615 }
616
617 /**
618 * Get a readable status text.
619 *
620 * @param string $status
621 * Module or agent status.
622 *
623 * @return string
624 * Returns the status text in the current language.
625 */
626 public static function getStatusText($status) {
627 $statuses = [
628 'warning' => __('Warning', 'wtotem'),
629 'error' => __('Error', 'wtotem'),
630 'success' => __('Success', 'wtotem'),
631 'info' => __('Info', 'wtotem'),
632 'invalid' => __('Invalid', 'wtotem'),
633 'ok' => __('Everything is OK', 'wtotem'),
634 'expired' => __('Expired', 'wtotem'),
635 'expires' => __('Expires', 'wtotem'),
636 'expires_today' => __('Expires today', 'wtotem'),
637 'missing' => __('Missing', 'wtotem'),
638 'active' => __('Active', 'wtotem'),
639 'inactive' => __('Inactive', 'wtotem'),
640 'pending' => __('Pending', 'wtotem'),
641 'pause' => __('Disabled', 'wtotem'),
642 'available' => __('Available', 'wtotem'),
643 'not_supported' => __('Not supported', 'wtotem'),
644 'not_registered' => __('Not registered', 'wtotem'),
645 'unsupported' => __('Unsupported', 'wtotem'),
646 'clean' => __('Clean', 'wtotem'),
647 'clear' => __('Clear', 'wtotem'),
648 'blacklisted' => __('Infected', 'wtotem'),
649 'miner_detected' => __('Infected', 'wtotem'),
650 'deface' => __('Deface', 'wtotem'),
651 'modified' => __('Modified', 'wtotem'),
652 'detected' => __('Detected', 'wtotem'),
653 'open_ports' => __('Open ports', 'wtotem'),
654 'blocked' => __('Blocked', 'wtotem'),
655 'connected' => __('Connected', 'wtotem'),
656 'attacks_detected' => __('Attacks detected', 'wtotem'),
657 'signature_found' => __('Signature found', 'wtotem'),
658 'file_changes' => __('File changes', 'wtotem'),
659 'no_cert' => __('No cert', 'wtotem'),
660 'down' => __('Down', 'wtotem'),
661 'up' => __('Up', 'wtotem'),
662 'infected' => __('Infected', 'wtotem'),
663 'not_installed' => __('Need to install', 'wtotem'),
664 'agent_not_available' => __('Agent not available', 'wtotem'),
665 'update_error' => __('Update error', 'wtotem'),
666 'session_error' => __('Session Error', 'wtotem'),
667 'internal_error' => __('Internal Error', 'wtotem'),
668 'installing' => __('Installing', 'wtotem'),
669 'installed' => __('Installed', 'wtotem'),
670 'working' => __('Working', 'wtotem'),
671 "critical" => __('Critical', 'wtotem'),
672 "deleted" => __('Deleted', 'wtotem'),
673 "changed" => __('Changed', 'wtotem'),
674 "new" => __('New', 'wtotem'),
675 "scanned" => __('Scanned', 'wtotem'),
676 "quarantine" => __('In quarantine', 'wtotem'),
677 "good" => __('Good', 'wtotem'),
678 "wrong_host" => __('Wrong host', 'wtotem'),
679 "revoked" => __('Revoked', 'wtotem'),
680 "untrusted" => __('Untrusted', 'wtotem'),
681 "not_found" => __('Not found', 'wtotem'),
682 "enable" => __('Enable', 'wtotem'),
683 ];
684
685 return (array_key_exists($status, $statuses)) ? $statuses[$status] : $status;
686 }
687
688 /**
689 * Get tooltips text for status.
690 *
691 * @param string $status
692 * Module or agent status.
693 *
694 * @return string
695 * Returns the status tooltip in the current language.
696 */
697 public static function getTooltips($status) {
698 $tooltips = [
699 'invalid' => __('Invalid -The certificate is invalid. Please, make sure that relevant certificate details filled correctly.', 'wtotem'),
700 'expired' => __('Expired - The certificate has expired. Connection is not secure. Please, renew it.', 'wtotem'),
701 'expires' => __('Expires - The certificate expires soon. Please, take actions.', 'wtotem'),
702 'expires_today' => __('Expires today - The certificate expires today. Please, take actions.', 'wtotem'),
703 'error' => __("Error - Something went wrong. Please, contact us, we'll fix the problem.", 'wtotem'),
704 'pending' => __('Pending - System processes your website. Data will be available soon.', 'wtotem'),
705 'pause' => __('Pause - The module is paused.', 'wtotem'),
706 'clean' => __('Everything is OK - Nothing to worry about. Everything is alright.', 'wtotem'),
707 'deface' => __("Deface - Website hacked. Please, contact us, we'll fix the problem.", 'wtotem'),
708 'open_ports' => __('Open ports - Open ports detected. Your website is vulnerable to attacks.', 'wtotem'),
709 'blocked' => __('Blocked - The module is blocked due to billing issues.', 'wtotem'),
710 'no_cert' => __("No cert - You don't have SSL certificate. We recommend you to install it for security concerns.", 'wtotem'),
711 'down' => __('Down - The website is not available for visitors.', 'wtotem'),
712 'up' => __('Up - The website is available for visitors.', 'wtotem'),
713 'infected' => __('Infected - The website site is blacklisted and may have infected files. Please, check antivirus module.', 'wtotem'),
714 'installing' => __('It means that the agent installation is in progress. Usually, it takes up to one hour.', 'wtotem'),
715 'agent_not_available' => __('We cannot locate the agent right now.', 'wtotem'),
716 'update_error' => __('It seems that your agent failed to update due to permissions restrictions.', 'wtotem'),
717 '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'),
718 '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'),
719 'working' => __('Everything is alright.', 'wtotem'),
720 'installed' => __('Everything is alright.', 'wtotem'),
721 'available' => __('Everything is alright.', 'wtotem'),
722 'not_installed' => __('You need to install agent manager to activate antivirus and firewall.', 'wtotem'),
723 'enable' => __('Enabled — the module is active; information is being collected and updated.', 'wtotem'),
724
725 ];
726
727 return (array_key_exists($status, $tooltips)) ? $tooltips[$status] : '';
728 }
729
730 /**
731 * Converting site data.
732 *
733 * @param array $data
734 * Sites data from WebTotem.
735 *
736 * @return array
737 * Converted data.
738 */
739 public static function allSitesData($data) {
740
741 $local_sites = get_sites();
742 $main_host = WebTotemOption::getMainHost();
743 $domains = [];
744
745 foreach ($local_sites as $site){
746 $domain = untrailingslashit($site->domain . $site->path);
747 $domains[$domain] = $domain;
748 }
749
750 $sites = [];
751 foreach ((array) $data as $site) {
752 if (!is_array($site) || empty($site['name'])) {
753 continue;
754 }
755
756 // Take sites only from the multisite network.
757 if (!array_key_exists($site['name'], $domains)) {
758 continue;
759 }
760
761 unset($domains[$site['name']]);
762
763 $modules = self::getHostModuleStatuses($site);
764
765 $sites[] = [
766 'hostname' => $site['name'],
767 'title' => $site['name'],
768 'main_host' => $main_host['id'] == $site['id'],
769 'host_id' => $site['id'],
770 'url' => admin_url('admin.php?page=wtotem_dashboard&hid=' . $site['id']),
771 'firewall' => [
772 'status' => self::getStatusData($modules['waf'] ?? ''),
773 ],
774 'antivirus' => [
775 'status' => self::getStatusData($modules['av'] ?? ''),
776 ],
777 'stacks' => self::getStacksData([]),
778 'services' => self::getSiteServicesData(self::getHostServices($site, $modules)),
779 ];
780 }
781
782 return $sites;
783 }
784
785 /**
786 * Index a host's module statuses by module name.
787 *
788 * @param array $host
789 * A single host entry from the hosts endpoint.
790 *
791 * @return array
792 * Module name => status.
793 */
794 protected static function getHostModuleStatuses(array $host) {
795 $statuses = [];
796
797 foreach ($host['modules'] ?? [] as $module) {
798 if (!empty($module['name'])) {
799 $statuses[$module['name']] = $module['status'] ?? '';
800 }
801 }
802
803 return $statuses;
804 }
805
806 /**
807 * Shape a host entry the way getSiteServicesData() expects it.
808 *
809 * @param array $host
810 * A single host entry from the hosts endpoint.
811 * @param array $modules
812 * Module name => status, as returned by getHostModuleStatuses().
813 *
814 * @return array
815 * Service name => ['status' => ...].
816 */
817 protected static function getHostServices(array $host, array $modules) {
818 $map = [
819 'ssl' => 'ssl',
820 'availability' => 'wa',
821 'reputation' => 'rc',
822 'ports' => 'ps',
823 'deface' => 'dc',
824 'domain' => 'dec',
825 ];
826
827 $services = [];
828 foreach ($map as $key => $module_name) {
829 if (isset($modules[$module_name])) {
830 $services[$key] = ['status' => $modules[$module_name]];
831 }
832 }
833
834 if (isset($host['ssl_result']['status'])) {
835 $services['ssl'] = ['status' => $host['ssl_result']['status']];
836 }
837
838 if (isset($host['reputation_result']['status'])) {
839 $services['reputation'] = ['status' => $host['reputation_result']['status']];
840 }
841
842 if (isset($host['availability_result']['last_status'])) {
843 $services['availability'] = ['status' => $host['availability_result']['last_status']];
844 }
845
846 return $services;
847 }
848
849 /**
850 * Converting stacks data.
851 *
852 * @param array $stacks
853 * Stacks data from WebTotem.
854 *
855 * @return array
856 * Converted data.
857 */
858 protected static function getStacksData($stacks) {
859 if (!$stacks) {
860 return ['list' => [], 'other' => ['count' => 0, 'names' => []]];
861 }
862
863 $apps = file_get_contents(WEBTOTEM_PLUGIN_PATH . '/includes/js/apps.json');
864 $apps = json_decode($apps, true);
865
866 $path = 'https://assets.wtotem.net/images/apps/';
867 $defaultIcon = WEBTOTEM_URL . '/includes/img/defaultTechnologiesIcon.svg';
868
869 $stackList = array_slice($stacks, 0,3);
870 $list = [];
871 foreach ($stackList as $key => $stack){
872 $list[$key] = [
873 'name' => $stack['name'],
874 'icon' => $path . ($apps[$stack['name']]['icon'] ?: $defaultIcon),
875 ];
876 }
877
878 if(count($stacks) <= 3){
879 $other['count'] = 0;
880 $other['names'] = [];
881 } else {
882 $otherStacks = array_slice($stacks, 3);
883 $other['count'] = count($otherStacks);
884 foreach ($otherStacks as $stack){
885 $other['names'][] = $stack['name'];
886 }
887 }
888 if($other['names']){
889 $other['names'] = implode(",", $other['names']);
890 }
891 return ['list' => $list, 'other' => $other];
892 }
893
894 /**
895 * Converting services data.
896 *
897 * @param $data
898 * Site data from WebTotem.
899 *
900 * @return array
901 * Converted data.
902 */
903 protected static function getSiteServicesData($data) {
904
905 $services = [
906 'ssl' => 'ssl',
907 'availability' => 'wa',
908 'reputation' => 'rc',
909 'ports' => 'ps',
910 'deface' => 'dc',
911 'domain' => 'dec',
912 ];
913
914 $list = [];
915 $other['count'] = 0;
916 $other['names'] = [];
917
918 foreach ($services as $key => $service){
919 if(array_key_exists($key, $data) and is_array($data[$key]) and array_key_exists('status', $data[$key])){
920 $status = self::getServiceStatus($data[$key]['status']);
921
922 if(in_array($status['color'], ['red', 'yellow'])){
923 if(count($list) < 2){
924 $color = $status['color'] == 'red' ? 'white/' : '';
925
926 $list[$key] = [
927 'status' => $status,
928 'icon' => 'services/'. $color . $service . '.svg',
929 'name' => self::getServiceName( $service ),
930 ];
931 } else {
932 $other['names'][] = self::getServiceName( $service );
933 $other['count']++;
934 }
935 }
936
937 }
938 }
939 if($other['names']){
940 $other['names'] = implode(",", $other['names']);
941 }
942 return ['list' => $list, 'other' => $other];
943 }
944
945 /**
946 * Get the data associated with the status.
947 *
948 * @param string $status
949 * Module or agent status.
950 *
951 * @return array
952 * Returns an array with status data.
953 */
954 public static function getServiceStatus($status) {
955 switch ($status) {
956
957 case 'expired':
958 case 'invalid':
959 case 'error':
960 case 'expires_today':
961 case 'down':
962 case 'infected':
963 case 'deface':
964 case 'not_installed':
965 case 'quarantine':
966 $status_data = [
967 'color' => 'red',
968 ];
969 break;
970
971 case 'no_cert':
972 case 'expires':
973 case 'open_ports':
974 case 'modified':
975 case 'not_supported':
976 case 'not_registered':
977 case 'blocked':
978 case 'pause':
979 case 'internal_error':
980 case 'update_error':
981 case 'config_error':
982 case 'agent_not_available':
983 case 'session_error':
984 $status_data = [
985 'color' => 'yellow',
986 ];
987 break;
988
989 case 'clean':
990 case 'installed':
991 case 'up':
992 case 'scanned':
993 case 'working':
994 $status_data = [
995 'color' => 'green',
996 ];
997 break;
998
999 case 'deleted':
1000 $status_data = [
1001 'color' => 'black',
1002 ];
1003 break;
1004
1005 case 'installing':
1006 case 'pending':
1007 default:
1008 $status_data = [
1009 'color' => 'gray',
1010 ];
1011 break;
1012
1013 }
1014
1015 return $status_data;
1016 }
1017
1018 /**
1019 * Get the translation of service.
1020 *
1021 * @param $service
1022 * Service short name.
1023 *
1024 * @return string
1025 * Translation of service.
1026 */
1027 public static function getServiceName($service){
1028 $services = [
1029 "wa" => __('Availability', 'wtotem'),
1030 "rc" => __('Reputation', 'wtotem'),
1031 "ssl" => 'SSL',
1032 "cms" => __('Technologies', 'wtotem'),
1033 "dc" => __('Deface', 'wtotem'),
1034 "ps" => __('Ports', 'wtotem'),
1035 "waf" => __('Firewall', 'wtotem'),
1036 "av" => __('Antivirus', 'wtotem'),
1037 "dec" => __('Domain', 'wtotem'),
1038 ];
1039 return $services[$service];
1040 }
1041
1042 /**
1043 * Get reputation status description.
1044 *
1045 * @param string $status
1046 * Reputation status.
1047 *
1048 * @return string
1049 * Returns a description of the reputation status
1050 */
1051 public static function getReputationInfo($status) {
1052 switch ($status) {
1053 case 'clean':
1054 $data = __("Don't worry, your reputation is good", 'wtotem');
1055 break;
1056
1057 case 'infected':
1058 $data = __('Oh, your reputation is bad', 'wtotem');
1059 break;
1060
1061 default:
1062 $data = __('Information is being updated', 'wtotem');
1063 }
1064 return $data;
1065 }
1066
1067 /**
1068 * Get blacklists entries counts.
1069 *
1070 * @param string $status
1071 * Reputation status.
1072 * @param array $virus_list
1073 * Sources where the site can be blacklisted.
1074 *
1075 * @return int
1076 * Number of references in blacklists.
1077 */
1078 public static function blacklistsEntries($status, array $virus_list) {
1079 $count = 0;
1080 if ($status != "clean") {
1081 foreach ($virus_list as &$list) {
1082 if (!empty($list['virus']['type'])) {
1083 $count++;
1084 }
1085 }
1086 }
1087 return $count;
1088 }
1089
1090 /**
1091 * Classification of the rating in the letter grades.
1092 *
1093 * @param int $score
1094 * Site rating from 1 to 100.
1095 *
1096 * @return array
1097 * Returns an array of data.
1098 */
1099 public static function scoreGrading($score) {
1100 if ($score < 0 || $score > 100) {
1101 return ['grade' => '', 'color' => ''];
1102 }
1103
1104 $scores = [
1105 100 => 'A+',
1106 90 => 'A',
1107 80 => 'A-',
1108 70 => 'B+',
1109 60 => 'B',
1110 50 => 'B-',
1111 35 => 'C+',
1112 20 => 'C',
1113 0 => 'C-',
1114 ];
1115
1116 foreach ($scores as $key => $value) {
1117 if ($score >= $key) {
1118 $grade = $value;
1119 break;
1120 }
1121 }
1122
1123 // Set a color depending on the grade.
1124 switch ($score) {
1125 case $score >= 80:
1126 $color = 'green';
1127 break;
1128
1129 case $score >= 50:
1130 $color = 'orange';
1131 break;
1132
1133 default:
1134 $color = 'red';
1135 }
1136
1137 return ['grade' => $grade, 'color' => $color];
1138 }
1139
1140 /**
1141 * Calculate the number of remaining days.
1142 *
1143 * @param string $date
1144 * Expiry date.
1145 *
1146 * @return string
1147 * Returns the number of days before the expiration date.
1148 */
1149 public static function daysLeft($date) {
1150 if ((int) $date === 0) {
1151 $days_left = 0;
1152 }
1153 else {
1154 $now = new \DateTime();
1155 $expiry_date = new \DateTime();
1156 $timestamp = strtotime($date);
1157 $expiry_date->setTimestamp($timestamp);
1158 $days_left = $expiry_date->diff($now)->format("%a");
1159 }
1160 return $days_left;
1161 }
1162
1163 /**
1164 * Converting the firewall logs.
1165 *
1166 * @param array $logs_
1167 * Firewall logs from WebTotem.
1168 *
1169 * @return array
1170 * Converted array of logs.
1171 */
1172 public static function wafLogs(array $logs_) {
1173 $logs = [];
1174 foreach ($logs_ as $key => $log) {
1175
1176 $logs[$key]['ip'] = $log['ip'];
1177 $logs[$key]['request'] = urldecode($log['request']);
1178 $logs[$key]['time'] = self::dateFormatter($log['date']);
1179 $logs[$key]['country_code'] = strtoupper($log['country']);
1180 $logs[$key]['country'] = self::getCountryName($log['country']);
1181 $logs[$key]['blocked'] = $log['blocked'] ? __('Blocked', 'wtotem') : __('Not blocked', 'wtotem');
1182
1183 $more = [
1184 'ip' => $log['ip'],
1185 'proxy_ip' => $log['proxy_ip'],
1186 'source' => $log['source'],
1187 'request' => urldecode($log['request']),
1188 'user_agent' => $log['user_agent'],
1189 'time' => self::dateFormatter($log['date']),
1190 'type' => $log['type'],
1191 'category' => $log['signature_category'],
1192 'country' => self::getCountryName($log['country']),
1193 'payload' => urldecode($log['payload']),
1194 'hostname' => urldecode($log['hostname']),
1195 'is_trusted' => urldecode($log['is_trusted']),
1196 ];
1197
1198 $logs[$key]['more'] = json_encode($more);
1199 }
1200 return $logs;
1201 }
1202
1203 /**
1204 * Converting firewall data to json for a D3 chart.
1205 *
1206 * @param array $charts
1207 * Charts data from WebTotem.
1208 *
1209 * @return array
1210 * Returns the converted data for chart.
1211 */
1212 public static function generateWafChart(array $charts) {
1213 $sum = 0;
1214 foreach ($charts as $chart) {
1215 $sum += $chart['total_attacks'];
1216 }
1217 if ($sum == 0) {
1218 return [
1219 'chart' => FALSE,
1220 'count_attacks' => 0,
1221 'count_blocks' => 0,
1222 'days' => 0,
1223 ];
1224 }
1225
1226
1227 // Set variables.
1228 $count_attacks = $count_blocks = 0;
1229
1230 foreach ($charts as $chart) {
1231 $result[$chart["type"]] = $chart["statistics"];
1232 }
1233
1234 if (!isset($result)) {
1235 return [
1236 'chart' => FALSE,
1237 'count_attacks' => 0,
1238 'count_blocks' => 0,
1239 'days' => 0,
1240 ];
1241 }
1242
1243 return [
1244 'chart' => json_encode($result),
1245 'count_attacks' => $count_attacks,
1246 'count_blocks' => $count_blocks,
1247 ];
1248 }
1249
1250 /**
1251 * Converting data to json for a D3 chart.
1252 *
1253 * @param array $charts
1254 * Charts data from WebTotem.
1255 * @param int $days
1256 * The number of days to build the chart.
1257 *
1258 * @return bool|string
1259 * Returns the converted data for chart.
1260 */
1261 public static function generateChart(array $charts, $days = 7) {
1262 $sum = 0;
1263 foreach ($charts as $chart) {
1264 $sum += $chart['value'];
1265 }
1266 if ($sum == 0) {
1267 return FALSE;
1268 }
1269
1270 $result = [];
1271
1272 foreach ($charts as $chart) {
1273 if ($days <= 1) {
1274 $time_zone = WebTotemOption::getOption('time_zone_offset');
1275 $userTime = ($time_zone) ? strtotime($time_zone . 'hours', strtotime($chart['time'])) : strtotime($chart['time']);
1276 }
1277 $result[] = [
1278 'date' => ($days <= 1) ? date("Y-m-d H:00:00", $userTime) : date("Y-m-d", strtotime($chart['time'])),
1279 'value' => $chart['value'],
1280 ];
1281 }
1282
1283 return json_encode($result, TRUE);
1284 }
1285
1286 /**
1287 * Converting data to json for a D3 chart.
1288 *
1289 * @param array $data
1290 * Charts data from WebTotem.
1291 *
1292 * @return array|bool
1293 * Returns the converted data for chart.
1294 */
1295 public static function generateAttacksMapChart(array $data) {
1296 $attacks = [];
1297 $countries = [];
1298 $labels = [];
1299 foreach ($data as $value) {
1300 $attacks[] = $value['total_attack'];
1301 $labels[] = self::getCountryName($value['name']);
1302 $countries[] = self::getCountryName($value['name'], 'en-US');
1303 }
1304 $result = ['attacks' => $attacks, 'countries' => $countries, 'labels' => $labels];
1305
1306 if (!$attacks) {
1307 return FALSE;
1308 }
1309
1310 return json_encode($result, TRUE);
1311 }
1312
1313 /**
1314 * Reassembling the antivirus logs.
1315 *
1316 * @param array $logs_
1317 * Antivirus logs from WebTotem.
1318 *
1319 * @return array
1320 * Reassembled array of logs.
1321 */
1322 public static function getAntivirusLogsData(array $logs_) {
1323 if(!$logs_){
1324 return [];
1325 }
1326 $logs = [];
1327 foreach ($logs_ as $key => $log) {
1328
1329 if(isset($log['infectedNum']) and $log['infectedNum']){
1330 $log['status_info'] = 'infected';
1331 $log['status_name'] = __('Infected', 'wtotem');
1332 } else {
1333 $log['status_info'] = 'clean';
1334 $log['status_name'] = __('Clean', 'wtotem');
1335 }
1336
1337 $log['date'] = self::dateFormatter($log['date'], 'd M Y');
1338 $log['data'] = json_encode($log);
1339
1340 $logs[$key] = $log;
1341 }
1342 return $logs;
1343 }
1344
1345 /**
1346 * Reassembling the Infected Files logs.
1347 *
1348 * @param array $logs_
1349 * Antivirus logs from WebTotem.
1350 *
1351 * @return array
1352 * Reassembled array of Infected Files logs.
1353 */
1354 public static function getInfectedFilesData(array $logs_) {
1355 $logs = [];
1356 foreach ($logs_ as $key => $log) {
1357 $full_path = urldecode($log['name']);
1358 $log['file_name'] = $name = basename($full_path);
1359 $log['file_path'] = str_replace($name, "", $full_path);
1360
1361 $logs[$key] = $log;
1362 }
1363 return $logs;
1364 }
1365
1366 /**
1367 * Reassembling the antivirus logs.
1368 *
1369 * @param array $logs_
1370 * Antivirus logs from WebTotem.
1371 *
1372 * @return array
1373 * Reassembled array of logs.
1374 */
1375 public static function getAntivirusAlerts(array $logs_) {
1376 $logs = [];
1377 foreach ($logs_ as $key => $log) {
1378
1379 switch ($log['type']) {
1380 case 'file':
1381 $log['type_text'] = "Suspicious file";
1382 break;
1383
1384 case 'skippedPaths':
1385 $log['type_text'] = "Unscanned Paths";
1386 break;
1387
1388 default:
1389 $log['type_text'] = $log['type'];
1390 }
1391
1392 $logs[$key] = $log;
1393 }
1394 return $logs;
1395 }
1396
1397 /**
1398 * Get open path data.
1399 *
1400 * @param array $_ports
1401 * Open ports array.
1402 *
1403 * @return array
1404 * Reassembled array of open ports.
1405 */
1406 public static function getOpenPortsData($ports) {
1407 if(!$ports){
1408 return [];
1409 }
1410 foreach ($ports as $key => $port) {
1411 $summary = '';
1412 if($port['cves']){
1413 foreach ($port['cves'] as $item){
1414 $summary .= '<p>' . $item['summary'] . '</p>';
1415 }
1416 }
1417 $ports[$key]['cve_summary'] = $summary;
1418 }
1419 return $ports;
1420 }
1421
1422
1423 /**
1424 * Reassembling the Quarantine logs.
1425 *
1426 * @param array $list_
1427 * Quarantine path list from WebTotem.
1428 *
1429 * @return array
1430 * Reassembled array of Quarantine logs.
1431 */
1432 public static function getQuarantineListData(array $list_) {
1433 if(!$list_){
1434 return [];
1435 }
1436 $list = [];
1437
1438 foreach ($list_ as $key => $log) {
1439
1440 $full_path = urldecode($log['name']);
1441 $log['path'] = $full_path;
1442 $log['file_name'] = $name = basename($full_path);
1443 $log['file_path'] = str_replace($name, "", $full_path);
1444
1445 $list[$key] = $log;
1446 }
1447 return $list;
1448 }
1449
1450 /**
1451 * Generate an array of IP address data.
1452 *
1453 * @param array $data
1454 * IP addresses data from WebTotem.
1455 * @param string $list_name
1456 * Allow or deny list.
1457 *
1458 * @return array
1459 * Returns array of data.
1460 */
1461 public static function getIpList(array $data, $list_name) {
1462 $list = [];
1463 foreach ($data as $item) {
1464 $list[] = [
1465 'ip' => $item,
1466 'list_name' => $list_name,
1467 ];
1468 }
1469 return $list;
1470 }
1471
1472 /**
1473 * Convert IP list to be transferred to WebTotem.
1474 *
1475 * @param string $data
1476 * IP list.
1477 *
1478 * @return string
1479 * Returns the converted string.
1480 */
1481 public static function convertIpListForApi($data) {
1482 if (!$data) {
1483 return FALSE;
1484 }
1485
1486 return preg_split("/(?(?=[\s,])[^.]|^$)/", $data);
1487
1488 }
1489 /**
1490 * Validate Ip or Cidr.
1491 *
1492 * @param string $input
1493 * IP address. (IPv4 / IPv6 + CIDR)
1494 *
1495 * @return bool
1496 * Returns the converted string.
1497 */
1498 public static function validateIpOrCidr(string $input): bool {
1499
1500 if (strpos($input, '/') !== false) {
1501 [$ip, $mask] = explode('/', $input, 2);
1502
1503 if (!filter_var($ip, FILTER_VALIDATE_IP)) {
1504 return false;
1505 }
1506
1507 if (!ctype_digit($mask)) {
1508 return false;
1509 }
1510
1511 $mask = (int)$mask;
1512
1513 if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) {
1514 return $mask >= 0 && $mask <= 32;
1515 }
1516
1517 if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {
1518 return $mask >= 0 && $mask <= 128;
1519 }
1520
1521 return false;
1522 }
1523
1524 return filter_var($input, FILTER_VALIDATE_IP) !== false;
1525 }
1526
1527 /**
1528 * Get data of the country with the most attacks.
1529 *
1530 * @param array $map
1531 * Map logs from WebTotem.
1532 *
1533 * @return array
1534 * Returns array of data.
1535 */
1536 public static function getMostAttacksData($map) {
1537
1538 if ($map) {
1539 $most_attacks_key = array_search(max(array_column($map, 'total_attack')), array_column($map, 'total_attack'));
1540 $total_attacks = array_sum(array_column($map, 'total_attack'));
1541
1542 $data['percent'] = ($total_attacks) ? round($map[$most_attacks_key]['total_attack'] / $total_attacks * 100) : 0;
1543 $data['country'] = self::getCountryName($map[$most_attacks_key]['name']);
1544 $data['offset'] = 176 / 100 * (100 - $data['percent']);
1545
1546 return $data;
1547 }
1548
1549 return ['percent' => 0, 'country' => FALSE, 'offset' => 0];
1550 }
1551
1552 /**
1553 * Getting the country name by two-letter code.
1554 *
1555 * @param string $key
1556 * Two-letter code.
1557 *
1558 * @return string
1559 * Returns country name.
1560 */
1561 public static function getCountryName($key, $lang = false) {
1562 if($lang == 'en-US'){
1563 $countries = WebTotemCountryManager::getCountiesNameByCode();
1564 } else {
1565 $countries = WebTotemCountryManager::getStandardList();
1566 }
1567 $key = (string) $key;
1568
1569 return (array_key_exists($key, $countries)) ? $countries[$key] : $key;
1570 }
1571
1572 /**
1573 * Get configs data.
1574 *
1575 * @param array $array
1576 * Original array.
1577 * @param string $key
1578 * The key to use as an index.
1579 *
1580 * @return array
1581 * Configs data array.
1582 */
1583 public static function getConfigsData(array $array, $key) {
1584 $configs = self::arrayMapIndex($array, $key);
1585
1586 foreach ($configs as $service => $config){
1587 $configs[$service]['checked'] = ($config['isActive']) ? 'checked' : '';
1588 $configs[$service]['notification_checked'] = (isset($config['notifications']) && $config['notifications']) ? 'checked' : '';
1589 }
1590
1591 return $configs;
1592 }
1593
1594 /**
1595 * Get waf setting data.
1596 *
1597 * @param array $settings
1598 * Original array.
1599 *
1600 * @return array
1601 * Configs data array.
1602 */
1603 public static function getWafSettingData(array $settings) {
1604 $_settings['gdn']['checked'] = (isset($settings['global_defense_network']) && !$settings['global_defense_network']) ? '' : 'checked';
1605 $_settings['dos'] = [
1606 'checked' => (isset($settings['dos_protect']) && !$settings['dos_protect']) ? '' : 'checked',
1607 'visually' => (isset($settings['dos_protect']) && !$settings['dos_protect']) ? 'visually-hidden' : '',
1608 ];
1609 $_settings['dos_limit'] = $settings['dos_limit'] ?: 1000;
1610
1611 $_settings['login_attempt'] = [
1612 'checked' => (isset($settings['login_protect']) && !$settings['login_protect']) ? '' : 'checked',
1613 'visually' => (isset($settings['login_protect']) && !$settings['login_protect']) ? 'visually-hidden' : '',
1614 ];
1615 $_settings['login_attempt_limit'] = $settings['login_attempt_limit'] ?: 20;
1616
1617 return $_settings;
1618 }
1619
1620 /**
1621 * Get plugin settings data.
1622 *
1623 * @return array
1624 * Configs data array.
1625 */
1626 public static function getPluginSettingsData() {
1627
1628 $settings = WebTotemOption::getPluginSettings();
1629 $_settings = $settings;
1630
1631 $_settings['hide_wp_version_checked'] = (array_key_exists('hide_wp_version', $settings) and $settings['hide_wp_version']) ? 'checked' : '';
1632 $_settings['disable_user_enumeration_checked'] = (array_key_exists('disable_user_enumeration', $settings) and $settings['disable_user_enumeration']) ? 'checked' : '';
1633 $_settings['recaptcha_checked'] = (array_key_exists('recaptcha', $settings) and $settings['recaptcha']) ? 'checked' : '';
1634 $_settings['two_factor_checked'] = (array_key_exists('two_factor', $settings) and $settings['two_factor']) ? 'checked' : '';
1635
1636 return $_settings;
1637 }
1638
1639 /**
1640 * Replace array indexes by key.
1641 *
1642 * @param array $array
1643 * Original array.
1644 * @param string $key
1645 * The key to use as an index.
1646 *
1647 * @return array
1648 * Returns a new array.
1649 */
1650 public static function arrayMapIndex(array $array, $key) {
1651 $new_array = [];
1652 foreach ($array as $item) {
1653 if (array_key_exists($key, $item)) {
1654 $new_array[$item[$key]] = $item;
1655 }
1656 }
1657 return $new_array;
1658 }
1659
1660 /**
1661 * Generate random string.
1662 *
1663 * @param int $length
1664 * The required length of the string.
1665 *
1666 * @return string
1667 * Returns random string.
1668 */
1669 public static function generateRandomString( int $length = 10): string {
1670 $characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_-';
1671 $charactersLength = strlen($characters);
1672 $randomString = '';
1673 for ($i = 0; $i < $length; $i++) {
1674 $randomString .= $characters[rand(0, $charactersLength - 1)];
1675 }
1676 return $randomString;
1677 }
1678
1679 /**
1680 * Encodes the less than, greater than, ampersand,double quote
1681 * and single quote characters. Will never double encode entities.
1682 *
1683 * @see https://developer.wordpress.org/reference/functions/esc_attr/
1684 *
1685 * @param string $text
1686 * The text which is to be encoded.
1687 *
1688 * @return string
1689 * The encoded text with HTML entities.
1690 */
1691 public static function escape($text = '') {
1692 return esc_attr($text);
1693 }
1694
1695 /**
1696 * Throw generic exception.
1697 *
1698 * @throws Exception
1699 *
1700 * @param string $message
1701 * Error or information message.
1702 * @param string $type
1703 * Either info or error.
1704 *
1705 * @return bool
1706 * False all the time, used for debug.
1707 */
1708 public static function throwException($message, $type = 'error') {
1709 if (defined('WTOTEM_THROW_EXCEPTIONS') && WTOTEM_THROW_EXCEPTIONS === true && is_string($message) ) {
1710 $message = str_replace( '<strong>WebTotem:</strong>', ($type === 'error' ? __('Error:', 'wtotem') : __('Info:', 'wtotem')), $message );
1711 throw new Exception($message, $type === 'error' ? 157 : 333);
1712 }
1713 return false;
1714 }
1715
1716 /**
1717 * Get audit logs data
1718 *
1719 * @return array
1720 */
1721 public static function getAuditLogs($data, $dates_count) {
1722 $logs = [];
1723 foreach ($data as $datum){
1724 $date_time = strtotime($datum['created_at']);
1725 $date = self::dateFormatter($date_time, 'M j, Y');
1726
1727 $logs[$date]['date'] = $date;
1728 $logs[$date]['count'] = $dates_count[$date];
1729 $logs[$date]['logs'][] = [
1730 'time' => self::dateFormatter($date_time,'H:i'),
1731 'user_name' => $datum['user_name'],
1732 'status' => $datum['status'],
1733 'title' => $datum['title'],
1734 'event' => $datum['event'],
1735 'description' => $datum['description'],
1736 'ip' => $datum['ip'],
1737 'viewed' => (int) !$datum['viewed']
1738 ];
1739 }
1740 return $logs;
1741 }
1742
1743 /**
1744 * Get confidential files data
1745 *
1746 * @return array
1747 */
1748 public static function getConfidentialFiles($data) {
1749 foreach ($data as $key => $datum){
1750 $data[$key]['modified_at'] = date_i18n('M j, Y \/ H:i', strtotime($datum['modified_at']));
1751 $data[$key]['size'] = self::humanFilesize($datum['size']);
1752 $data[$key]['name'] = urldecode($datum['name']);
1753 $data[$key]['path'] = urldecode($datum['path']);
1754 }
1755 return $data;
1756 }
1757
1758 /**
1759 * Get confidential files data
1760 *
1761 * @return array
1762 */
1763 public static function prepareLinksData($data) {
1764 foreach ($data as $key => $datum){
1765
1766 $content = $datum['content'];
1767 $source = $datum['source'];
1768 if(strpos($content, 'http://') !== 0 and strpos($content, 'https://') !== 0 and strpos($content, '//') !== 0){
1769 $match = substr_count($content, '../');
1770 $content = str_replace("../", "", $content);
1771 $content = ltrim($content, '/');
1772
1773 for($i=0; $i < 1+$match; $i++){
1774 $source = substr($source, 0, strrpos($source, "/"));
1775 }
1776 $data[$key]['link'] = $source . '/' . $content;
1777 } else {
1778 $data[$key]['link'] = $content;
1779 }
1780 }
1781 return $data;
1782 }
1783
1784
1785 /**
1786 * Building navigation and forming a template
1787 *
1788 * @param integer $limit
1789 * number of entries per 1 page
1790 * @param integer $count_all
1791 * total number of all entries
1792 * @param integer $currentPage
1793 * the number of the page being viewed
1794 * @param integer $nextPrev
1795 * Show the "Forward" and "Back" buttons
1796 * @return mixed
1797 * Generated navigation template ready for output
1798 */
1799 public static function paginationBuild($limit, $count_all, $currentPage = 1, $nextPrev = true) {
1800 if( $limit < 1 OR $count_all <= $limit ) return '';
1801 $count_pages = ceil( $count_all / $limit );
1802
1803 $spread = 3;
1804 $separator = "<i>...</i>";
1805 $wrap = "<div class=\"wtotem_pagination\">{pages}</div>";
1806
1807 $nextTitle = '';
1808 $prevTitle = '';
1809
1810 $currentPage = intval( $currentPage );
1811 if( $currentPage < 1 ) $currentPage = 1;
1812
1813 $shift_start = max( $currentPage - $spread, 2 );
1814 $shift_end = min( $currentPage + $spread, $count_pages-1 );
1815 if( $shift_end < $spread * 2 ) {
1816 $shift_end = min( $spread * 2, $count_pages-1 );
1817 }
1818 if( $shift_end == $count_pages - 1 AND $shift_start > 3 ) {
1819 $shift_start = max( 3, min( $count_pages - $spread * 2 + 1, $shift_start ) );
1820 }
1821
1822 $list = self::getPaginationItem( 1, $currentPage );
1823
1824 if ($shift_start == 3) {
1825 $list .= self::getPaginationItem( 2, $currentPage );
1826 } elseif ( $shift_start > 3 ) {
1827 $list .= $separator;
1828 }
1829
1830 for( $i = $shift_start; $i <= $shift_end; $i++ ) {
1831 $list .= self::getPaginationItem( $i, $currentPage );
1832 }
1833
1834 $last_page = $count_pages - 1;
1835 if( $shift_end == $last_page-1 ){
1836 $list .= self::getPaginationItem( $last_page, $currentPage );
1837 } elseif( $shift_end < $last_page ) {
1838 $list .= $separator;
1839 }
1840
1841 $list .= self::getPaginationItem( $count_pages, $currentPage );
1842
1843 if( $nextPrev ) {
1844 $list = self::getPaginationItem(
1845 $currentPage > 1 ? $currentPage - 1 : 0,
1846 $currentPage,
1847 $nextTitle)
1848 . $list
1849 . self::getPaginationItem(
1850 $currentPage < $count_pages ? $currentPage + 1 : 0,
1851 $currentPage,
1852 $prevTitle
1853 );
1854 }
1855
1856 return str_replace( "{pages}", $list, $wrap );
1857 }
1858
1859 /**
1860 * Button/Link Formation
1861 * @param int $page_num
1862 * page number
1863 * @param string $currentPage
1864 * current page
1865 * @param string $page_name
1866 * if specified, the text will be displayed instead of the page number
1867 * @return string
1868 * span block with active page or link.
1869 */
1870 public static function getPaginationItem( $page_num, $currentPage, $page_name = '' ) {
1871 if($page_num === 0){return '';}
1872 $page_name = $page_name ?: $page_num;
1873
1874 if( $currentPage == $page_num ) {
1875 return "<span class=\"wtotem_pagination__number wtotem_pagination__number_active\">{$page_name}</span>";
1876 } else {
1877 return "<a href=\"#\" data-page=\"{$page_num}\" class=\"wtotem_pagination__number\">{$page_name}</a>";
1878 }
1879 }
1880
1881 /**
1882 * Get notifications array.
1883 *
1884 * @return array
1885 * Returns notifications array.
1886 */
1887 public static function getNotifications() {
1888
1889 $notifications_data = WebTotemOption::getNotificationsData();
1890 $notifications = [];
1891
1892 foreach ($notifications_data as $notification) {
1893 switch ($notification['type']) {
1894 case 'error':
1895 $image = 'alert-error.svg';
1896 $class = 'wtotem_alert__title_red';
1897 break;
1898
1899 case 'warning':
1900 $image = 'alert-warning.svg';
1901 $class = 'wtotem_alert__title_yellow';
1902 break;
1903
1904 case 'success':
1905 $image = 'alert-success.svg';
1906 $class = 'wtotem_alert__title_green';
1907 break;
1908
1909 case 'info':
1910 $image = 'info-blue.svg';
1911 $class = 'wtotem_alert__title_blue';
1912 break;
1913 }
1914
1915 $notifications[] = [
1916 "text" => $notification['notice'],
1917 "id" => self::generateRandomString(8),
1918 "type" => self::getStatusText($notification['type']),
1919 "type_raw" => $notification['type'],
1920 "image" => $image,
1921 "class" => $class,
1922 ];
1923 }
1924
1925 return $notifications;
1926 }
1927
1928 /**
1929 * Get current agent installation statuses.
1930 *
1931 * @param array $agents_statuses
1932 * Agents statuses got from the WebTotem API.
1933 *
1934 * @return array
1935 * Returns an array with agent installation status data.
1936 */
1937 public static function getAgentsStatuses(array $agents_statuses) {
1938 $agents = ['am', 'waf', 'av'];
1939 $installing_statuses = [
1940 'not_available',
1941 'internal_error',
1942 'update_error',
1943 'config_error',
1944 'session_error',
1945 ];
1946
1947 $process_statuses = [];
1948 $option_statuses = [];
1949
1950 foreach ($agents as $agent) {
1951 $status = WebTotemAgentManager::checkInstalledService($agent);
1952 $option_statuses[$agent] = $status['option_status'] ?: FALSE;
1953
1954 if ($agent == 'am') {
1955 if ($status['file_status']) {
1956 $process_statuses[$agent] = 'available';
1957 }
1958 else {
1959 $process_statuses[$agent] = 'failed';
1960 }
1961 }
1962 else {
1963 if ($status['file_status']) {
1964 if (in_array($agents_statuses[$agent], $installing_statuses)) {
1965 $process_statuses[$agent] = 'installing';
1966 }
1967 elseif ($agents_statuses[$agent] == 'not_available') {
1968 $process_statuses[$agent] = 'failed';
1969 }
1970 else {
1971 $process_statuses[$agent] = 'available';
1972 }
1973 }
1974 else {
1975 $process_statuses[$agent] = 'installing';
1976 }
1977 }
1978 }
1979
1980 return [
1981 'process_statuses' => $process_statuses,
1982 'option_statuses' => $option_statuses,
1983 ];
1984 }
1985
1986 }
1987