PluginProbe
WebTotem Security / 2.4.31
WebTotem Security v2.4.31
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
← All changes | lib/Helper.php +387 -333 trunk2.4.31 View file →
@@ -11,12 +11,8 @@
11 11 * WebTotem Base class for Wordpress.
12 12 */
13 13 class WebTotem {
14 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 15 /**
20 16 * Returns an URL from the admin dashboard.
21 17 *
22 18 * @param string $url
@@ -80,9 +76,9 @@
80 76 public static function getUserEmail() {
81 77 $email = WebTotemOption::getOption( "user_email" );
82 78 if(!$email){
83 79 if(WebTotemOption::isActivated()) {
84 -// $email = WebTotemAPI::getEmail();
80 + $email = WebTotemAPI::getEmail();
85 81 }
86 82 WebTotemOption::setOptions(['user_email' => $email]);
87 83 }
88 84 return $email;
@@ -161,27 +157,8 @@
161 157
162 158 return $data;
163 159 }
164 160
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 161 /**
185 162 * Removing duplicates by one key.
186 163 *
187 164 * @param array $array
@@ -284,13 +261,15 @@
284 261
285 262 /**
286 263 * Check that the training period has passed for the firewall.
287 264 *
265 + * @param string $created_at
266 + * Date when the waf configuration was created.
267 + *
288 268 * @return bool
289 269 * Returns boolean.
290 270 */
291 - public static function isWafTraining() {
292 - $created_at = WebTotemOption::getOption('am_created_at');
271 + public static function isWafTraining($created_at) {
293 272 if($created_at) {
294 273 $when_waf_trained = strtotime('+2 day', strtotime($created_at));
295 274 $today = strtotime('today');
296 275
@@ -307,17 +286,10 @@
307 286 *
308 287 * @return array
309 288 * Returns an array with periods.
310 289 */
311 - public static function isPeriodAvailable() {
290 + public static function isPeriodAvailable($created_at) {
312 291
313 - $created_at = WebTotemOption::getOption('am_created_at');
314 - if(!$created_at){
315 - return [
316 - 'monthly' => false,
317 - 'yearly' => false,
318 - ];
319 - }
320 292 $diff = strtotime(gmdate("Y-m-d H:i:s")) - strtotime($created_at);
321 293 $daysCount = floor($diff / 86400);
322 294
323 295 return [
@@ -406,24 +378,24 @@
406 378
407 379 case is_array($days):
408 380 $to = $days[1] ?: $days[0];
409 381 $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))),
382 + 'from' => strtotime(date('Y-m-d 00:00:01', strtotime(self::formatDate($days[0])))),
383 + 'to' => strtotime(date('Y-m-d 23:59:59', strtotime(self::formatDate($to)))),
412 384 ];
413 385 break;
414 386
415 387 case $days <= 1:
416 388 $period = [
417 - 'from' => date('Y-m-d H:m:i', strtotime('-24 hours')),
418 - 'to' => date('Y-m-d H:m:i', time()),
389 + 'from' => strtotime('-24 hours'),
390 + 'to' => time(),
419 391 ];
420 392 break;
421 393
422 394 default:
423 395 $period = [
424 - 'from' => date('Y-m-d H:m:i', time() - ($days * 86400)),
425 - 'to' => date('Y-m-d H:m:i'),
396 + 'from' => time() - ($days * 86400),
397 + 'to' => time(),
426 398 ];
427 399 }
428 400
429 401 return $period;
@@ -539,10 +511,8 @@
539 511
540 512 case 'clean':
541 513 case 'up':
542 514 case 'installed':
543 - case 'available':
544 - case 'enable':
545 515 case 'working':
546 516 case 'good':
547 517 $status_data = [
548 518 'class' => 'is--status--ok',
@@ -678,9 +648,8 @@
678 648 "wrong_host" => __('Wrong host', 'wtotem'),
679 649 "revoked" => __('Revoked', 'wtotem'),
680 650 "untrusted" => __('Untrusted', 'wtotem'),
681 651 "not_found" => __('Not found', 'wtotem'),
682 - "enable" => __('Enable', 'wtotem'),
683 652 ];
684 653
685 654 return (array_key_exists($status, $statuses)) ? $statuses[$status] : $status;
686 655 }
@@ -717,12 +686,9 @@
717 686 '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 687 '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 688 'working' => __('Everything is alright.', 'wtotem'),
720 689 'installed' => __('Everything is alright.', 'wtotem'),
721 - 'available' => __('Everything is alright.', 'wtotem'),
722 690 '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 691 ];
726 692
727 693 return (array_key_exists($status, $tooltips)) ? $tooltips[$status] : '';
728 694 }
@@ -747,107 +713,37 @@
747 713 $domains[$domain] = $domain;
748 714 }
749 715
750 716 $sites = [];
751 - foreach ((array) $data as $site) {
752 - if (!is_array($site) || empty($site['name'])) {
753 - continue;
717 + if(array_key_exists('edges', $data)){
718 + foreach ($data['edges'] as $site) {
719 + $site = $site['node'];
720 + // Take sites only from the multisite network.
721 + if(array_key_exists($site['hostname'], $domains)) {
722 + unset($domains[$site['hostname']]);
723 + $sites[] = [
724 + 'hostname' => $site['hostname'],
725 + 'title' => $site['title'],
726 + 'main_host' => $main_host['id'] == $site['id'],
727 + 'host_id' => $site['id'],
728 + 'url' => admin_url('admin.php?page=wtotem_dashboard&hid=' . $site['id']),
729 + 'firewall' => [
730 + 'status' => self::getStatusData($site['firewall']['status']),
731 + ],
732 + 'antivirus' => [
733 + 'status' => self::getStatusData($site['antivirus']['status']),
734 + ],
735 + 'stacks' => self::getStacksData($site['maliciousScript']['stack']),
736 + 'services' => self::getSiteServicesData($site),
737 + ];
738 + }
754 739 }
755 740
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 741 }
781 -
782 742 return $sites;
783 743 }
784 744
785 745 /**
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 746 * Converting stacks data.
851 747 *
852 748 * @param array $stacks
853 749 * Stacks data from WebTotem.
@@ -855,12 +751,8 @@
855 751 * @return array
856 752 * Converted data.
857 753 */
858 754 protected static function getStacksData($stacks) {
859 - if (!$stacks) {
860 - return ['list' => [], 'other' => ['count' => 0, 'names' => []]];
861 - }
862 -
863 755 $apps = file_get_contents(WEBTOTEM_PLUGIN_PATH . '/includes/js/apps.json');
864 756 $apps = json_decode($apps, true);
865 757
866 758 $path = 'https://assets.wtotem.net/images/apps/';
@@ -1039,8 +931,54 @@
1039 931 return $services[$service];
1040 932 }
1041 933
1042 934 /**
935 + * Get reports with modules list.
936 + *
937 + * @param array $edges
938 + * Data on generated reports.
939 + *
940 + * @return array
941 + * Returns an array with converted data.
942 + */
943 + public static function getReports(array $edges) {
944 + $modulesLang = [
945 + 'wa' => __('Availability log', 'wtotem'),
946 + 'dc' => __('Deface log', 'wtotem'),
947 + 'ps' => __('Port log', 'wtotem'),
948 + 'rc' => __('Reputation log', 'wtotem'),
949 + 'sc' => __('Evaluation log', 'wtotem'),
950 + 'av' => __('Antivirus log', 'wtotem'),
951 + 'waf' => __('Firewall log', 'wtotem'),
952 + ];
953 +
954 + $reports = [];
955 +
956 + foreach ($edges as $edge) {
957 + if (in_array(FALSE, $edge["node"])) {
958 + $arr = [];
959 + foreach ($edge["node"] as $module => $value) {
960 + if ($value == TRUE && array_key_exists($module, $modulesLang)) {
961 + $arr[] = $modulesLang[$module];
962 + }
963 + }
964 + $modules = implode(", ", $arr);
965 + }
966 + else {
967 + $modules = __('All modules', 'wtotem');
968 + }
969 +
970 + $reports[] = [
971 + 'id' => $edge["node"]['id'],
972 + 'modules' => $modules,
973 + 'created_at' => self::dateFormatter($edge["node"]['createdAt']),
974 + ];
975 + }
976 +
977 + return $reports;
978 + }
979 +
980 + /**
1043 981 * Get reputation status description.
1044 982 *
1045 983 * @param string $status
1046 984 * Reputation status.
@@ -1171,29 +1109,28 @@
1171 1109 */
1172 1110 public static function wafLogs(array $logs_) {
1173 1111 $logs = [];
1174 1112 foreach ($logs_ as $key => $log) {
1113 + $log = $log['node'];
1175 1114
1176 1115 $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');
1116 + $logs[$key]['request'] = htmlspecialchars(urldecode($log['request']));
1117 + $logs[$key]['time'] = self::dateFormatter($log['time']);
1118 + $logs[$key]['country_code'] = strtolower($log['country']);
1119 + $logs[$key]['country'] = $log['location']['country']['nameEn'];
1120 + $logs[$key]['blocked'] = $log['blocked'] ? __('Blocked IP', 'wtotem') : __('Not blocked', 'wtotem');
1182 1121
1183 1122 $more = [
1184 1123 'ip' => $log['ip'],
1185 - 'proxy_ip' => $log['proxy_ip'],
1124 + 'proxy_ip' => $log['proxyIp'],
1186 1125 'source' => $log['source'],
1187 - 'request' => urldecode($log['request']),
1188 - 'user_agent' => $log['user_agent'],
1189 - 'time' => self::dateFormatter($log['date']),
1126 + 'request' => htmlspecialchars(urldecode($log['request'])),
1127 + 'user_agent' => $log['userAgent'],
1128 + 'time' => self::dateFormatter($log['time']),
1190 1129 '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']),
1130 + 'category' => $log['category'],
1131 + 'country' => $log['location']['country']['nameEn'],
1132 + 'payload' => htmlspecialchars(urldecode($log['payload'])),
1196 1133 ];
1197 1134
1198 1135 $logs[$key]['more'] = json_encode($more);
1199 1136 }
@@ -1211,25 +1148,38 @@
1211 1148 */
1212 1149 public static function generateWafChart(array $charts) {
1213 1150 $sum = 0;
1214 1151 foreach ($charts as $chart) {
1215 - $sum += $chart['total_attacks'];
1152 + $sum += $chart['attacks'];
1216 1153 }
1217 1154 if ($sum == 0) {
1218 - return [
1219 - 'chart' => FALSE,
1220 - 'count_attacks' => 0,
1221 - 'count_blocks' => 0,
1222 - 'days' => 0,
1223 - ];
1155 + return ['chart' => FALSE, 'count_attacks' => 0, 'count_blocks' => 0];
1224 1156 }
1225 1157
1158 + // Get days count.
1159 + $charts_ = $charts;
1160 + $first = array_shift($charts_);
1161 + $last = array_pop($charts_);
1162 + $days = ceil((strtotime($last['time']) - strtotime($first['time'])) / 86400);
1226 1163
1227 1164 // Set variables.
1228 1165 $count_attacks = $count_blocks = 0;
1229 1166
1230 1167 foreach ($charts as $chart) {
1231 - $result[$chart["type"]] = $chart["statistics"];
1168 + if ($days <= 1) {
1169 + $time_zone = WebTotemOption::getOption('time_zone_offset');
1170 + $userTime = ($time_zone) ? strtotime($time_zone . ' hours', strtotime($chart['time'])) : strtotime($chart['time']);
1171 + }
1172 + if (($chart['attacks'] and $days == 2) or $days != 2) {
1173 + $result[] = [
1174 + 'date' => ($days <= 1) ? date("Y-m-d H:00:00", $userTime) : date("Y-m-d", strtotime($chart['time'])),
1175 + 'count' => $chart['blocked'],
1176 + 'attacks' => $chart['attacks'],
1177 + 'blocked' => $chart['blocked'],
1178 + ];
1179 + $count_attacks += $chart['attacks'];
1180 + $count_blocks += $chart['blocked'];
1181 + }
1232 1182 }
1233 1183
1234 1184 if (!isset($result)) {
1235 1185 return [
@@ -1235,9 +1185,9 @@
1235 1185 return [
1236 1186 'chart' => FALSE,
1237 1187 'count_attacks' => 0,
1238 1188 'count_blocks' => 0,
1239 - 'days' => 0,
1189 + 'days' => 0,
1240 1190 ];
1241 1191 }
1242 1192
1243 1193 return [
@@ -1243,8 +1193,9 @@
1243 1193 return [
1244 1194 'chart' => json_encode($result),
1245 1195 'count_attacks' => $count_attacks,
1246 1196 'count_blocks' => $count_blocks,
1197 + 'days' => $days,
1247 1198 ];
1248 1199 }
1249 1200
1250 1201 /**
@@ -1296,11 +1247,11 @@
1296 1247 $attacks = [];
1297 1248 $countries = [];
1298 1249 $labels = [];
1299 1250 foreach ($data as $value) {
1300 - $attacks[] = $value['total_attack'];
1301 - $labels[] = self::getCountryName($value['name']);
1302 - $countries[] = self::getCountryName($value['name'], 'en-US');
1251 + $attacks[] = $value['attacks'];
1252 + $labels[] = self::getCountryName($value['country']);
1253 + $countries[] = $value['location']['country']['nameEn'];
1303 1254 }
1304 1255 $result = ['attacks' => $attacks, 'countries' => $countries, 'labels' => $labels];
1305 1256
1306 1257 if (!$attacks) {
@@ -1309,91 +1260,51 @@
1309 1260
1310 1261 return json_encode($result, TRUE);
1311 1262 }
1312 1263
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) {
1264 + /**
1265 + * Reassembling the antivirus logs.
1266 + *
1267 + * @param array $logs_
1268 + * Antivirus logs from WebTotem.
1269 + *
1270 + * @return array
1271 + * Reassembled array of logs.
1272 + */
1273 + public static function getAntivirusLogs(array $logs_) {
1274 + $logs = [];
1275 + foreach ($logs_ as $key => $log) {
1276 + $log = $log['node'];
1328 1277
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 - }
1278 + $file_info = new SplFileInfo(urldecode($log['filePath']));
1336 1279
1337 - $log['date'] = self::dateFormatter($log['date'], 'd M Y');
1338 - $log['data'] = json_encode($log);
1280 + $log['original_path'] = $log['filePath'];
1281 + $log['file_path'] = $file_info->getPath() . '/';
1282 + $log['file_name'] = $file_info->getFilename();
1283 + $log['time'] = self::dateFormatter($log['time']);
1284 + $log['permissions_changed'] = $log['permissionsChanged'];
1285 + $log['status'] = self::getStatusData($log['event']);
1286 + $log['class'] = 'wt-text--green';
1339 1287
1340 - $logs[$key] = $log;
1341 - }
1342 - return $logs;
1343 - }
1288 + switch ($log['event']) {
1289 + case 'modified':
1290 + case 'quarantine':
1291 + $log['class'] = "wt-text--yellow";
1292 + break;
1344 1293
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);
1294 + case 'deleted':
1295 + $log['class'] = "wt-text--light-gray";
1296 + break;
1360 1297
1361 - $logs[$key] = $log;
1362 - }
1363 - return $logs;
1364 - }
1298 + case 'infected':
1299 + $log['class'] = "wt-text--red";
1300 + break;
1301 + }
1365 1302
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;
1303 + $logs[$key] = $log;
1395 1304 }
1305 + return $logs;
1306 + }
1396 1307
1397 1308 /**
1398 1309 * Get open path data.
1399 1310 *
@@ -1408,10 +1319,10 @@
1408 1319 return [];
1409 1320 }
1410 1321 foreach ($ports as $key => $port) {
1411 1322 $summary = '';
1412 - if($port['cves']){
1413 - foreach ($port['cves'] as $item){
1323 + if($port['cveList']){
1324 + foreach ($port['cveList'] as $item){
1414 1325 $summary .= '<p>' . $item['summary'] . '</p>';
1415 1326 }
1416 1327 }
1417 1328 $ports[$key]['cve_summary'] = $summary;
@@ -1419,35 +1330,28 @@
1419 1330 return $ports;
1420 1331 }
1421 1332
1422 1333
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 = [];
1334 + /**
1335 + * Reassembling the quarantine logs.
1336 + *
1337 + * @param array $logs_
1338 + * Quarantine logs from WebTotem.
1339 + *
1340 + * @return array
1341 + * Reassembled array of logs.
1342 + */
1343 + public static function getQuarantineLogs(array $logs_) {
1344 + $logs = [];
1345 + foreach ($logs_ as $key => $log) {
1346 + $logs[$key] = $log;
1347 + $logs[$key]['path'] = urldecode($log['path']);
1348 + $logs[$key]['date'] = self::dateFormatter($log['date']);
1349 + }
1437 1350
1438 - foreach ($list_ as $key => $log) {
1351 + return $logs;
1352 + }
1439 1353
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 1354 /**
1451 1355 * Generate an array of IP address data.
1452 1356 *
1453 1357 * @param array $data
@@ -1461,9 +1365,11 @@
1461 1365 public static function getIpList(array $data, $list_name) {
1462 1366 $list = [];
1463 1367 foreach ($data as $item) {
1464 1368 $list[] = [
1465 - 'ip' => $item,
1369 + 'ip' => $item['ip'],
1370 + 'id' => $item['id'],
1371 + 'created_at' => self::dateFormatter($item['createdAt']),
1466 1372 'list_name' => $list_name,
1467 1373 ];
1468 1374 }
1469 1375 return $list;
@@ -1469,8 +1375,30 @@
1469 1375 return $list;
1470 1376 }
1471 1377
1472 1378 /**
1379 + * Generate an array of URL address data.
1380 + *
1381 + * @param array $data
1382 + * URL addresses data from WebTotem.
1383 + *
1384 + * @return array
1385 + * Returns array of data.
1386 + */
1387 + public static function getUrlAllowList(array $data) {
1388 + $list = [];
1389 + foreach ($data as $item) {
1390 + $list[] = [
1391 + 'url' => $item['url'],
1392 + 'id' => $item['id'],
1393 + 'created_at' => self::dateFormatter($item['createdAt']),
1394 + 'list_name' => 'url_allow',
1395 + ];
1396 + }
1397 + return $list;
1398 + }
1399 +
1400 + /**
1473 1401 * Convert IP list to be transferred to WebTotem.
1474 1402 *
1475 1403 * @param string $data
1476 1404 * IP list.
@@ -1482,48 +1410,26 @@
1482 1410 if (!$data) {
1483 1411 return FALSE;
1484 1412 }
1485 1413
1486 - return preg_split("/(?(?=[\s,])[^.]|^$)/", $data);
1414 + $ips = preg_split("/(?(?=[\s,])[^.]|^$)/", $data);
1487 1415
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;
1416 + if (is_array($ips)) {
1417 + $ips_ = '[';
1418 + foreach ($ips as $ip) {
1419 + if (!empty($ip)) {
1420 + $ips_ .= '"' . $ip . '",';
1522 1421 }
1422 + }
1423 + $ips_ = substr($ips_, 0, -1);
1424 + $ips_ .= ']';
1425 + }
1426 + else {
1427 + $ips_ = '"' . $ips . '"';
1428 + }
1523 1429
1524 - return filter_var($input, FILTER_VALIDATE_IP) !== false;
1525 - }
1430 + return $ips_;
1431 + }
1526 1432
1527 1433 /**
1528 1434 * Get data of the country with the most attacks.
1529 1435 *
@@ -1535,13 +1441,13 @@
1535 1441 */
1536 1442 public static function getMostAttacksData($map) {
1537 1443
1538 1444 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'));
1445 + $most_attacks_key = array_search(max(array_column($map, 'attacks')), array_column($map, 'attacks'));
1446 + $total_attacks = array_sum(array_column($map, 'attacks'));
1541 1447
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']);
1448 + $data['percent'] = ($total_attacks) ? round($map[$most_attacks_key]['attacks'] / $total_attacks * 100) : 0;
1449 + $data['country'] = self::getCountryName($map[$most_attacks_key]['country']);
1544 1450 $data['offset'] = 176 / 100 * (100 - $data['percent']);
1545 1451
1546 1452 return $data;
1547 1453 }
@@ -1548,8 +1454,35 @@
1548 1454
1549 1455 return ['percent' => 0, 'country' => FALSE, 'offset' => 0];
1550 1456 }
1551 1457
1458 + /**
1459 + * Get data on the three most attacking countries.
1460 + *
1461 + * @param array $map
1462 + * Map logs from WebTotem.
1463 + *
1464 + * @return array
1465 + * Returns array of data.
1466 + */
1467 + public static function getTreeMostAttacksData($map) {
1468 + $total_attacks = array_sum(array_column($map, 'attacks'));
1469 +
1470 + if ($map) {
1471 + array_multisort (array_column($map, 'attacks'), SORT_DESC, $map);
1472 + $data = array_slice($map, 0, 3);
1473 +
1474 + foreach ($data as $key => $value){
1475 + $data[$key]['percent'] = round($value['attacks'] / $total_attacks * 100);
1476 + $data[$key]['country'] = self::getCountryName($value['country']);
1477 + }
1478 +
1479 + return $data;
1480 + }
1481 +
1482 + return [];
1483 + }
1484 +
1552 1485 /**
1553 1486 * Getting the country name by two-letter code.
1554 1487 *
1555 1488 * @param string $key
@@ -1557,14 +1490,10 @@
1557 1490 *
1558 1491 * @return string
1559 1492 * Returns country name.
1560 1493 */
1561 - public static function getCountryName($key, $lang = false) {
1562 - if($lang == 'en-US'){
1563 - $countries = WebTotemCountryManager::getCountiesNameByCode();
1564 - } else {
1565 - $countries = WebTotemCountryManager::getStandardList();
1566 - }
1494 + public static function getCountryName($key) {
1495 + $countries = WebTotemCountryManager::getStandardList();
1567 1496 $key = (string) $key;
1568 1497
1569 1498 return (array_key_exists($key, $countries)) ? $countries[$key] : $key;
1570 1499 }
@@ -1600,20 +1529,20 @@
1600 1529 * @return array
1601 1530 * Configs data array.
1602 1531 */
1603 1532 public static function getWafSettingData(array $settings) {
1604 - $_settings['gdn']['checked'] = (isset($settings['global_defense_network']) && !$settings['global_defense_network']) ? '' : 'checked';
1533 + $_settings['gdn']['checked'] = (isset($settings['gdn']) && !$settings['gdn']) ? '' : 'checked';
1605 1534 $_settings['dos'] = [
1606 - 'checked' => (isset($settings['dos_protect']) && !$settings['dos_protect']) ? '' : 'checked',
1607 - 'visually' => (isset($settings['dos_protect']) && !$settings['dos_protect']) ? 'visually-hidden' : '',
1535 + 'checked' => (isset($settings['dosProtection']) && !$settings['dosProtection']) ? '' : 'checked',
1536 + 'visually' => (isset($settings['dosProtection']) && !$settings['dosProtection']) ? 'visually-hidden' : '',
1608 1537 ];
1609 - $_settings['dos_limit'] = $settings['dos_limit'] ?: 1000;
1538 + $_settings['dos_limit'] = $settings['dosLimit'] ?: 1000;
1610 1539
1611 1540 $_settings['login_attempt'] = [
1612 - 'checked' => (isset($settings['login_protect']) && !$settings['login_protect']) ? '' : 'checked',
1613 - 'visually' => (isset($settings['login_protect']) && !$settings['login_protect']) ? 'visually-hidden' : '',
1541 + 'checked' => (isset($settings['loginAttemptsProtection']) && !$settings['loginAttemptsProtection']) ? '' : 'checked',
1542 + 'visually' => (isset($settings['loginAttemptsProtection']) && !$settings['loginAttemptsProtection']) ? 'visually-hidden' : '',
1614 1543 ];
1615 - $_settings['login_attempt_limit'] = $settings['login_attempt_limit'] ?: 20;
1544 + $_settings['login_attempt_limit'] = $settings['loginAttemptsLimit'] ?: 20;
1616 1545
1617 1546 return $_settings;
1618 1547 }
1619 1548
@@ -1628,9 +1557,8 @@
1628 1557 $settings = WebTotemOption::getPluginSettings();
1629 1558 $_settings = $settings;
1630 1559
1631 1560 $_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 1561 $_settings['recaptcha_checked'] = (array_key_exists('recaptcha', $settings) and $settings['recaptcha']) ? 'checked' : '';
1634 1562 $_settings['two_factor_checked'] = (array_key_exists('two_factor', $settings) and $settings['two_factor']) ? 'checked' : '';
1635 1563
1636 1564 return $_settings;
@@ -1739,8 +1667,131 @@
1739 1667 }
1740 1668 return $logs;
1741 1669 }
1742 1670
1671 + /**
1672 + * Update user's plugins cve data
1673 + *
1674 + * @return void
1675 + */
1676 + public static function updateCveData() {
1677 + require_once ABSPATH . 'wp-admin/includes/plugin.php';
1678 + $all_plugins = get_plugins();
1679 +
1680 + $list = [];
1681 + foreach ($all_plugins as $plugin) {
1682 + if($plugin['TextDomain'] and $plugin['Version']){
1683 + $list[] = '{"technology": "' . $plugin['TextDomain'] . '", "version": "' . $plugin['Version'] . '"}';
1684 + }
1685 + }
1686 + $list = implode(', ', $list ?? []);
1687 + $cve_list = WebTotem::arrayMapIndex(WebTotemAPI::getCVE($list), 'technology');
1688 +
1689 + $update_plugins = get_site_transient( 'update_plugins' );
1690 + $update_plugins = WebTotem::convertObjectToArray($update_plugins->response);
1691 +
1692 + $values = '';
1693 + WebTotemDB::deleteData([], 'plugins_cve_list');
1694 + foreach ($all_plugins as $key => $plugin) {
1695 + if(array_key_exists($plugin['TextDomain'], $cve_list)){
1696 + $new_version = $update_plugins[$key]['new_version'] ?? 0;
1697 + foreach ($cve_list[$plugin['TextDomain']]['cves'] as $cve){
1698 + $cve['published'] = self::dateFormatter($cve['published'], 'Y-m-d');
1699 + $values .= sprintf("('%s','%s','%s','%s','%s','%s'),",
1700 + $cve['cve_id'],
1701 + $plugin['Name'],
1702 + $plugin['TextDomain'],
1703 + $plugin['Version'],
1704 + $new_version,
1705 + json_encode($cve)
1706 + );
1707 + }
1708 +
1709 + }
1710 + }
1711 +
1712 + if($values){
1713 + $values = substr_replace($values, ";", -1);
1714 + $columns = '(cve_id, plugin_name, slug, plugin_version, new_version, cve_data )';
1715 + WebTotemDB::setRows('plugins_cve_list', $columns, $values);
1716 + }
1717 +
1718 + }
1719 +
1720 + public static function getPluginVersionFromRepository($slug) {
1721 + $url = "https://api.wordpress.org/plugins/info/1.2/?action=plugin_information&request[slugs][]={$slug}";
1722 + $response = wp_remote_get($url); // WPOrg API call
1723 + $plugins = json_decode($response['body']);
1724 +
1725 + // traverse $response object
1726 + foreach($plugins as $key => $plugin) {
1727 + $version = $plugin->version;
1728 + }
1729 + return $version;
1730 + }
1731 +
1732 + /**
1733 + * Update user's plugins cve data
1734 + *
1735 + * @return bool
1736 + */
1737 + public static function updateCveDataByPluginName($plugin_data) {
1738 + if(!$plugin_data['TextDomain'] or !$plugin_data['Version']){
1739 + return false;
1740 + }
1741 +
1742 + $list = WebTotemAPI::getCVE('{"technology": "' . $plugin_data['TextDomain'] . '", "version": "' . $plugin_data['Version'] . '"}');
1743 + $cve_list = WebTotem::arrayMapIndex($list, 'technology');
1744 +
1745 + $values = '';
1746 + WebTotemDB::deleteData(['slug' => $plugin_data['TextDomain']], 'plugins_cve_list');
1747 + if(array_key_exists($plugin_data['TextDomain'], $cve_list) and $cve_list[$plugin_data['TextDomain']]['cves']){
1748 + $has_new_version = WebTotem::getPluginVersionFromRepository($plugin_data['TextDomain']);
1749 + foreach ($cve_list[$plugin_data['TextDomain']]['cves'] as $cve){
1750 + $cve['published'] = self::dateFormatter($cve['published'], 'Y-m-d');
1751 + $values .= sprintf("('%s','%s','%s','%s','%s','%s'),",
1752 + $cve['cve_id'],
1753 + $plugin_data['Name'],
1754 + $plugin_data['TextDomain'],
1755 + $plugin_data['Version'],
1756 + ($has_new_version and $has_new_version != $plugin_data['Version']) ? $has_new_version : 0,
1757 + json_encode($cve)
1758 + );
1759 + }
1760 + $values = substr_replace($values, ";", -1);
1761 + $columns = '(cve_id, plugin_name, slug, plugin_version, new_version, cve_data)';
1762 + WebTotemDB::setRows('plugins_cve_list', $columns, $values);
1763 + }
1764 +
1765 + return true;
1766 + }
1767 +
1768 + public static function get_plugin_info($plugin_slug) {
1769 + include_once(ABSPATH . 'wp-admin/includes/plugin.php');
1770 +
1771 + $all_plugins = get_plugins();
1772 + $plugin_file = "$plugin_slug/$plugin_slug.php";
1773 +
1774 + if (isset($all_plugins[$plugin_file])) {
1775 + $plugin_info = $all_plugins[$plugin_file];
1776 + return $plugin_info;
1777 + } else {
1778 + return false;
1779 + }
1780 + }
1781 +
1782 + /**
1783 + * Get confidential files data
1784 + *
1785 + * @return array
1786 + */
1787 + public static function preparePluginsCveList($data) {
1788 + foreach ($data as $key => $datum){
1789 + $data[$key]['cve_data'] = json_decode($datum['cve_data'], true);
1790 + $data[$key]['cve_data']['published'] = self::dateFormatter($data[$key]['cve_data']['published'], 'M j, Y');
1791 + }
1792 + return $data;
1793 + }
1743 1794 /**
1744 1795 * Get confidential files data
1745 1796 *
1746 1797 * @return array
@@ -1843,14 +1894,16 @@
1843 1894 if( $nextPrev ) {
1844 1895 $list = self::getPaginationItem(
1845 1896 $currentPage > 1 ? $currentPage - 1 : 0,
1846 1897 $currentPage,
1847 - $nextTitle)
1898 + $nextTitle,
1899 + true )
1848 1900 . $list
1849 1901 . self::getPaginationItem(
1850 1902 $currentPage < $count_pages ? $currentPage + 1 : 0,
1851 1903 $currentPage,
1852 - $prevTitle
1904 + $prevTitle,
1905 + true
1853 1906 );
1854 1907 }
1855 1908
1856 1909 return str_replace( "{pages}", $list, $wrap );
@@ -1936,9 +1989,10 @@
1936 1989 */
1937 1990 public static function getAgentsStatuses(array $agents_statuses) {
1938 1991 $agents = ['am', 'waf', 'av'];
1939 1992 $installing_statuses = [
1940 - 'not_available',
1993 + 'not_installed',
1994 + 'installing',
1941 1995 'internal_error',
1942 1996 'update_error',
1943 1997 'config_error',
1944 1998 'session_error',
@@ -1952,9 +2006,9 @@
1952 2006 $option_statuses[$agent] = $status['option_status'] ?: FALSE;
1953 2007
1954 2008 if ($agent == 'am') {
1955 2009 if ($status['file_status']) {
1956 - $process_statuses[$agent] = 'available';
2010 + $process_statuses[$agent] = 'installed';
1957 2011 }
1958 2012 else {
1959 2013 $process_statuses[$agent] = 'failed';
1960 2014 }
@@ -1963,13 +2017,13 @@
1963 2017 if ($status['file_status']) {
1964 2018 if (in_array($agents_statuses[$agent], $installing_statuses)) {
1965 2019 $process_statuses[$agent] = 'installing';
1966 2020 }
1967 - elseif ($agents_statuses[$agent] == 'not_available') {
2021 + elseif ($agents_statuses[$agent] == 'agent_not_available') {
1968 2022 $process_statuses[$agent] = 'failed';
1969 2023 }
1970 2024 else {
1971 - $process_statuses[$agent] = 'available';
2025 + $process_statuses[$agent] = 'installed';
1972 2026 }
1973 2027 }
1974 2028 else {
1975 2029 $process_statuses[$agent] = 'installing';