PluginProbe
WebTotem Security / 3.0.0
WebTotem Security v3.0.0
3.0.1 3.0.0 trunk 1.0 1.1 1.2 1.3 1.3.1 1.3.2 1.3.3 2.0 2.1 2.1.1 2.1.2 2.1.3 2.1.4 2.1.5 2.1.6 2.1.7 2.1.8 2.1.9 2.2.1 2.2.2 2.2.3 2.2.4 All 109 releases
wt-security / lib / API.php

API.php in WebTotem Security 3.0.0, at lib/API.php

1,288 lines 40.1 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 die("Protected By WebTotem!");
8 }
9
10 /**
11 * WebTotem API class.
12 *
13 * Mostly contains wrappers for API methods. Check and send methods.
14 *
15 * @version 1.0
16 * @copyright (C) 2022 WebTotem team (http://wtotem.com)
17 * @license GNU/GPL: http://www.gnu.org/copyleft/gpl.html
18 */
19 class WebTotemAPI extends WebTotem
20 {
21
22 /**
23 * Method for getting an auth token.
24 *
25 * @param string $api_key
26 * Application programming interface key.
27 *
28 * @return bool|string
29 * Returns auth status
30 */
31 public static function auth($api_key, $repeat = FALSE)
32 {
33 $domain = WEBTOTEM_SITE_DOMAIN;
34
35 if (empty($api_key)) {
36 return FALSE;
37 }
38
39 $data = ['api_key' => $api_key, 'site' => $domain];
40 $result = self::sendRequest('auth/sign-in/api-key', $data, 'POST', FALSE, TRUE);
41
42 if($result === null){
43 WebTotemOption::setNotification('warning' , __('Authorization failed. The server may be temporarily unavailable', 'wtotem'));
44 }
45
46 if (isset($result['access_token'])) {
47 $auth_token = $result['access_token'];
48 if(!WebTotemOption::isActivated()){
49 WebTotemOption::login(['token' => $auth_token, 'api_key' => $api_key]);
50 WebTotemAgentManager::postdelete();
51 } else {
52 WebTotemOption::refreshToken($auth_token);
53 }
54
55 return 'success';
56 } elseif (isset($result['message']) and $result['message'] == 'invalid credentials') {
57 WebTotemOption::logout();
58 }
59
60 if($repeat == false){
61 //self::checkEndpoint();
62 return self::auth($api_key, true);
63 }
64
65 return FALSE;
66 }
67
68 /**
69 * Method for getting API url.
70 *
71 * @return string|bool
72 * API url
73 */
74 public static function getApiUrl()
75 {
76 return 'https://app.wtotem.com';
77 }
78
79
80 /**
81 * Get site info from API server.
82 *
83 * @param string $attempt
84 * Is the request an attempt to get host data.
85 *
86 * @return array
87 * Returns host data.
88 */
89 public static function siteInfo($attempt = FALSE)
90 {
91 if (self::isMultiSite()) {
92 $host['id'] = WebTotemOption::getSessionOption('host_id');
93 $host['name'] = WebTotemOption::getSessionOption('host_name');
94
95 if ($host['id']) {
96 return $host;
97 }
98 }
99
100 $host = WebTotemOption::getHost();
101
102 if ($host['id']) {
103 return $host;
104 }
105
106 // if (self::isMultiSite()) {
107 // $sites = get_sites();
108 // foreach ($sites as $site) {
109 // $domain = untrailingslashit($site->domain . $site->path);
110 // self::addSite($domain);
111 // }
112 //
113 // if (!$attempt) {
114 // return self::siteInfo(TRUE);
115 // }
116 // } else {
117 // $domain = WEBTOTEM_SITE_DOMAIN;
118 // return self::addSite($domain);
119 // }
120 $domain = WEBTOTEM_SITE_DOMAIN;
121 return self::addSite($domain);
122
123 // return [];
124 }
125
126 /**
127 * Method for adding a site to the WebTotem platform.
128 *
129 * @param string $domain
130 * Domain to add.
131 *
132 * @return array
133 * Returns host data.
134 */
135 public static function addSite($domain)
136 {
137 if (function_exists('idn_to_utf8')) {
138 $domain = idn_to_utf8($domain);
139 }
140
141 // Checking if the site has been added to the WebTotem.
142 if(!$host = self::getHostID($domain)){
143 $host = self::getHostID('www.' . $domain);
144 }
145
146 if($host['id']){
147 return [
148 'id' => $host['id'],
149 'name' => $host['hostname'],
150 ];
151 }
152
153 // If the site is not added then try to add.
154 $data = ['hosts' => [$domain]];
155 $response = self::sendRequest('hosts', $data, 'POST', TRUE);
156
157 if (isset($response['message'])) {
158 WebTotemOption::setNotification('error', __('Failed to add the site to the WebTotem platform.', 'wtotem'));
159 } else {
160 if ($response['data']['added']) {
161 // If it added, save site ID.
162 $host = self::getHostID($domain);
163 WebTotemOption::setHost($domain, $host['id']);
164 return [
165 'id' => $host['id'],
166 'name' => $host['hostname'],
167 ];
168 }
169 }
170 return [];
171 }
172
173 /**
174 * Get all sites from API.
175 *
176 * @param string $page_num
177 * Mark for loading data.
178 * @param string $limit
179 * Limit of sites to loading.
180 *
181 * @return array
182 * Returns host data.
183 */
184 public static function getSites($page_num = 1, $page_size = 15, $status = 'active')
185 {
186 $result = self::sendRequest('hosts', ['page_num' => $page_num, 'page_size' => $page_size, 'status' => $status], 'GET', TRUE);
187
188 if (isset($result['Data'])) {
189 return $result['Data'];
190 }
191
192 return [];
193 }
194
195 /**
196 * Check the site's presence in the list on the API side.
197 *
198 * @param string $site
199 * The domain we want to check.
200 *
201 * @return array
202 * Returns host data.
203 */
204 public static function getHostID($site)
205 {
206 $result = self::sendRequest('hosts/id', ['hostname' => $site], 'GET', TRUE);
207
208 if (isset($result['data'])) {
209 WebTotemOption::setOptions(['config_id' => $result['data']['config_id']]);
210 return ['id' => $result['data']['host_id'], 'hostname' => $site];
211 }
212
213 return ['id' => '', 'hostname' => ''];
214 }
215
216
217 /**
218 * Method to get the agents file names and AM file link.
219 *
220 * @param string $host_id
221 * Host id on WebTotem.
222 *
223 * @return array
224 * Returns agents files data.
225 */
226 public static function getAgentsFiles($host_id)
227 {
228
229 // if (WebTotem::isMultiSite()) {
230 // $all_hosts = WebTotemOption::getOption('all_hosts');
231 // $all_hosts = $all_hosts ? json_decode($all_hosts, true) : [];
232 //
233 // $siteIdsArray = $all_hosts ? array_values($all_hosts) : [];
234 // $siteIds = $siteIdsArray ? addslashes(WebTotem::convertArrayToString($siteIdsArray)) : '';
235 //
236 // $payload = '{"query":"mutation { auth { am { installMultisite(mainSiteId: \"' . $host_id . '\", siteIds: [' . $siteIds . ']){ downloadLink, amFilename, wafFilename, avFilename } } } }"}';
237 // $response = self::sendRequest($payload, TRUE);
238 //
239 // if (isset($response['data']['auth']['am']['installMultisite'])) {
240 // return $response['data']['auth']['am']['installMultisite'];
241 // }
242 // } else {
243 $response = self::sendRequest('/agents/' . $host_id . '/install', [], 'POST', TRUE);
244
245 if (isset($response['data'])) {
246 return $response['data'];
247 }
248 // }
249 return [];
250 }
251
252 /**
253 * Add secondary MultiSite host.
254 *
255 * @param $new_sites
256 * An array with sites to add.
257 *
258 * @return void.
259 */
260 public static function addMultiSiteNewSites($new_sites)
261 {
262
263 }
264
265 /**
266 * Get the date of creation of the site.
267 *
268 * @param string $site
269 * The domain we want to check.
270 *
271 * @return string|bool
272 * Returns host data.
273 */
274 public static function getGetSiteAddedDate($site)
275 {
276 $payload = '{"query": "query getSites { auth { viewer { sites { list(filter: { search: \"'. $site .'\" }) { edges{ node{ createdAt } } } } } } }" }';
277 $result = self::sendRequest($payload, true);
278
279 if (isset($result['data']['auth']['viewer']['sites']['list']['edges'][0]['node']['createdAt'])) {
280 return $result['data']['auth']['viewer']['sites']['list']['edges'][0]['node']['createdAt'];
281 }
282
283 return false;
284 }
285
286 /**
287 * Remove secondary MultiSite host.
288 *
289 * @param $host_id
290 * Host id on WebTotem.
291 *
292 * @return bool
293 * Returns result removing host.
294 */
295 public static function removeMultiSiteHost($host_id)
296 {
297
298 return false;
299 }
300
301 /**
302 * Method to get agents (AM, WAF, AV) statuses.
303 *
304 * @return array
305 * Returns agents statuses data.
306 */
307 public static function getAgentsStatusesFromAPI()
308 {
309 $config_id = WebTotemOption::getOption('config_id');
310 $response = self::sendRequest('/agents/' . $config_id . '/status', [], 'GET', TRUE);
311
312 if (isset($response['data'])) {
313 return $response['data'];
314 }
315
316 return [];
317 }
318
319 /**
320 * Method to get user time zone.
321 *
322 * @return string|bool
323 * Returns time zone data.
324 */
325 public static function getTimeZone()
326 {
327 $payload = '{"query":"query { auth { viewer{ timezone } } } "}';
328 $response = self::sendRequest($payload, TRUE);
329
330 if (isset($response['data']['auth']['viewer']['timezone'])) {
331 return $response['data']['auth']['viewer']['timezone'];
332 }
333 return FALSE;
334 }
335
336 /**
337 * Method for get monitoring data.
338 *
339 * @param string $host_id
340 * Host id on WebTotem.
341 * @param int|array $days
342 * For what period data is needed.
343 *
344 * @return array
345 * Returns all data.
346 */
347 public static function getMonitoringData($host_id, $days = 7)
348 {
349 $response = self::sendRequest('/dashboard/monitoring/' . $host_id . '/results', [], 'GET', TRUE);
350
351 if (isset($response['data'])) {
352 return $response['data'];
353 }
354
355 return [];
356 }
357
358
359 /**
360 * Method for get all the site security data.
361 *
362 * @param string $host_id
363 * Host id on WebTotem.
364 *
365 * @return array
366 * Returns all data.
367 */
368 public static function getMonitoring($host_id)
369 {
370
371 $payload = '{"query":"query($id: ID!) { auth { viewer { sites { one(id: $id) { domain { lastScanResult { isTaken hasSite redirectLink isLocal protection ips { ip location } status time } } sslResults{ results{ certStatus certIssuerName certExpiryDate certIssueDate } } ssl { status daysLeft expiryDate issueDate } reputation { status lastTest { time } virusList { virus{ type path } antiVirus } } } } } } }","variables":{"id":"' . $host_id . '"}}';
372 $response = self::sendRequest($payload, TRUE);
373
374 if (isset($response['data']['auth']['viewer']['sites']['one'])) {
375 return $response['data']['auth']['viewer']['sites']['one'];
376 }
377
378 return [];
379 }
380
381 /**
382 * Method to get firewall data.
383 *
384 * @param int $limit
385 * Limit on the number of records.
386 * @param string $page
387 * Page for loading data.
388 * @param int|array $days
389 * For what period data is needed.
390 *
391 * @return array
392 * Returns firewall data.
393 */
394 public static function getFirewall($limit = 20, $page = 1, $days = 365)
395 {
396 $period = WebTotem::getPeriod($days);
397
398 $config_id = WebTotemOption::getOption('config_id');
399 $response = self::sendRequest('/dashboard/firewall/' . $config_id . '/logs', [
400 'page_num' => $page,
401 'page_size' => $limit,
402 'from' => $period['from'],
403 'to' => $period['to']
404 ], 'GET', TRUE);
405
406
407 if (isset($response['data'])) {
408 return $response['data'];
409 }
410
411 return [];
412 }
413
414 /**
415 * Method to get firewall chart data.
416 *
417 * @param int $days
418 * For what period data is needed.
419 *
420 * @return array
421 * Returns firewall chart data.
422 */
423 public static function getFirewallStatistics($days = 7)
424 {
425 $period = WebTotem::getPeriod($days);
426
427 $config_id = WebTotemOption::getOption('config_id');
428 $response = self::sendRequest('/dashboard/firewall/' . $config_id . '/statistics', [
429 'from' => $period['from'],
430 'to' => $period['to']
431 ], 'GET', TRUE);
432
433
434 if (isset($response['data'])) {
435 return $response['data'];
436 }
437
438 return [];
439 }
440
441 /**
442 * Method to get firewall settings.
443 *
444 * @return array
445 * Returns information whether the request was successful.
446 */
447 public static function getFirewallSettings()
448 {
449 $config_id = WebTotemOption::getOption('config_id');
450 $response = self::sendRequest('/dashboard/firewall/' . $config_id . '/configs', [], 'GET', TRUE);
451 if (isset($response['data'])) {
452 return $response['data'];
453 }
454
455 return [];
456 }
457
458 /**
459 * Method to set firewall settings.
460 *
461 * @param array $settings
462 * User-specified settings.
463 *
464 * @return array
465 * Returns information whether the request was successful.
466 */
467 public static function setFirewallSettings(array $settings)
468 {
469 $config_id = WebTotemOption::getOption('config_id');
470 return self::sendRequest('/dashboard/firewall/' . $config_id . '/configs', $settings, 'PATCH', TRUE);
471 }
472
473
474 /**
475 * Method to get antivirus history data.
476 *
477 * @param int $page_num
478 * Page number.
479 * @param int $page_size
480 * Number of entries per page.
481 *
482 * @return array
483 * Returns antivirus history data.
484 */
485 public static function getAntivirusHistory($page_num = 1, $page_size = 10)
486 {
487 $config_id = WebTotemOption::getOption('config_id');
488 $response = self::sendRequest('/dashboard/antivirus/' . $config_id . '/history', [
489 'page_num' => $page_num,
490 'page_size' => $page_size
491 ], 'GET', TRUE);
492
493 if (isset($response['data'])) {
494 return $response['data'];
495 }
496 return [];
497 }
498
499 /**
500 * Method to get antivirus history details data.
501 *
502 * @param int $scan_id
503 * Scan ID.
504 * @param int $page_num
505 * Page number.
506 * @param int $page_size
507 * Number of entries per page.
508 *
509 * @return array
510 * Returns antivirus history data.
511 */
512 public static function getAntivirusHistoryDetails($scan_id, $page_num = 1, $page_size = 10)
513 {
514 $config_id = WebTotemOption::getOption('config_id');
515 $response = self::sendRequest('/dashboard/antivirus/' . $config_id . '/history/' . $scan_id . '/details', [
516 'page_num' => $page_num,
517 'page_size' => $page_size
518 ], 'GET', TRUE);
519
520
521 if (isset($response['data'])) {
522 return $response['data'];
523 }
524 return [];
525 }
526
527 /**
528 * Method to get quarantine data.
529 *
530 * @param int $page_num
531 * Page number.
532 * @param int $page_size
533 * Number of entries per page.
534 *
535 * @return array
536 * Returns quarantine data.
537 */
538 public static function getAntivirusCurrentDetails($page_num = 1, $page_size = 5)
539 {
540 $config_id = WebTotemOption::getOption('config_id');
541 $response = self::sendRequest('/dashboard/antivirus/' . $config_id . '/current/details', [
542 'page_num' => $page_num,
543 'page_size' => $page_size
544 ], 'GET', TRUE);
545
546 if (isset($response['data'])) {
547 return $response['data'];
548 }
549 return [];
550 }
551
552
553 /**
554 * Method to force check Antivirus.
555 *
556 * @return mixed
557 * Returns information whether the request was successful.
558 */
559 public static function forceCheckAV()
560 {
561 $config_id = WebTotemOption::getOption('config_id');
562 return self::sendRequest('/dashboard/antivirus/' . $config_id . '/check', [], 'POST', TRUE);
563 }
564
565
566 /**
567 * Method to force check services.
568 *
569 * @param string $host_id
570 * Host id on WebTotem.
571 * @param string $module_name
572 * Service that needs to be checked.
573 *
574 * @return array
575 * Returns information whether the request was successful.
576 */
577 public static function forceCheck($host_id, $module_name)
578 {
579 return self::sendRequest('/dashboard/hosts/' . $host_id . '/check', ['module_name' => $module_name], 'POST', TRUE);
580 }
581
582 /**
583 * Method to get quarantine data.
584 *
585 * @param int $page_num
586 * Page number.
587 * @param int $page_size
588 * Number of entries per page.
589 *
590 * @return array
591 * Returns quarantine data.
592 */
593 public static function getQuarantineList($page_num = 1, $page_size = 5)
594 {
595 $config_id = WebTotemOption::getOption('config_id');
596 $response = self::sendRequest('/dashboard/antivirus/' . $config_id . '/quarantine', [
597 'page_num' => $page_num,
598 'page_size' => $page_size
599 ], 'GET', TRUE);
600
601 if (isset($response['data'])) {
602 return $response['data'];
603 }
604 return [];
605 }
606
607 /**
608 * Method to move file to quarantine.
609 *
610 * @param string $path
611 * Path to the file.
612 *
613 * @return array
614 * Returns information whether the request was successful.
615 */
616 public static function moveToQuarantine($path)
617 {
618 $config_id = WebTotemOption::getOption('config_id');
619
620 return self::sendRequest('/dashboard/antivirus/' . $config_id . '/quarantine/' . $path . '/to-quarantine',
621 [], 'POST', TRUE);
622 }
623
624 /**
625 * Method to move file from quarantine.
626 *
627 * @param string $path
628 * Path to the file.
629 *
630 * @return array
631 * Returns information whether the request was successful.
632 */
633 public static function moveFromQuarantine($path)
634 {
635 $config_id = WebTotemOption::getOption('config_id');
636 return self::sendRequest('/dashboard/antivirus/' . $config_id . '/quarantine/' . $path . '/from-quarantine',
637 [], 'POST', TRUE);
638 }
639
640 /**
641 * Method to get server status data.
642 *
643 * @param string $host_id
644 * Host id on WebTotem.
645 * @param int|array $days
646 * For what period data is needed.
647 *
648 * @return array
649 * Returns server status data.
650 */
651 public static function getServerStatusData($host_id, $days = 7)
652 {
653 $period = WebTotem::getPeriod($days);
654 $payload = '{ "query":"query($id: ID!, $dateRange: DateRangeInput!) { auth { viewer { sites { one(id: $id) { serverStatus { info { phpVersion phpServerUser phpServerSoftware phpGatewayInterface phpServerProtocol osInfo cpuCount cpuModel CpuFreq cpuFamily lsCpu maxExecTime mathLibraries } ramChart(dateRange: $dateRange){ total value time } cpuChart(dateRange: $dateRange){ value time } } } } } } }", "variables":{"id":"' . $host_id . '","dateRange":{"to":' . $period['to'] . ',"from":' . $period['from'] . '} } }';
655
656 $response = self::sendRequest($payload, TRUE);
657
658 if (isset($response['data']['auth']['viewer']['sites']['one']['serverStatus'])) {
659 return $response['data']['auth']['viewer']['sites']['one']['serverStatus'];
660 }
661
662 return [];
663 }
664
665 /**
666 * Method to remove port from ignore list.
667 *
668 * @param string $host_id
669 * Host id on WebTotem.
670 * @param string $port
671 * User specified port.
672 *
673 * @return array
674 * Returns information whether the request was successful.
675 */
676 public static function removeIgnorePort($host_id, $port)
677 {
678 $payload = '{"variables":{ "input": { "siteId": "' . $host_id . '", "port":' . $port . '} },"query":"mutation($input: IgnorePortInput!) { auth { sites { ps { removeIgnorePort(input: $input) } } } }"} ';
679 return self::sendRequest($payload, TRUE);
680 }
681
682 /**
683 * Method to add port to ignore list.
684 *
685 * @param string $host_id
686 * Host id on WebTotem.
687 * @param string $port
688 * User specified port.
689 *
690 * @return array
691 * Returns information whether the request was successful.
692 */
693 public static function addIgnorePort($host_id, $port)
694 {
695 $payload = '{"variables":{ "input": { "siteId": "' . $host_id . '", "port":' . (int)$port . '} },"query":"mutation($input: IgnorePortInput!) { auth { sites { ps { addIgnorePort(input: $input) } } } }"} ';
696 return self::sendRequest($payload, TRUE);
697 }
698
699 /**
700 * Method to get all ports list.
701 *
702 * @param string $host_id
703 * Host id on WebTotem.
704 *
705 * @return array
706 * Returns ports data.
707 */
708 public static function getAllPortsList($host_id)
709 {
710 $payload = '{"query":"query($id: ID!) { auth { viewer { sites { one(id: $id) { ports { status lastTest { time } ignorePorts TCPResults{ port technology version cveList{id summary } } UDPResults { port technology version cveList{id summary } } } } } } } } ","variables":{"id":"' . $host_id . '"}}';
711
712 $response = self::sendRequest($payload, TRUE);
713
714 if (isset($response['data']['auth']['viewer']['sites']['one']['ports'])) {
715 return $response['data']['auth']['viewer']['sites']['one']['ports'];
716 }
717
718 return [];
719 }
720
721 /**
722 * Method to get all ports list.
723 *
724 * @param string $host_id
725 * Host id on WebTotem.
726 *
727 * @return array
728 * Returns ports data.
729 */
730 public static function getOpenPaths($host_id)
731 {
732 $payload = '{"query":"query($id: ID!) { auth { viewer { sites { one(id: $id) { openPathSearch { time paths { httpCode severity path } } } } } } } ","variables":{"id":"' . $host_id . '"}}';
733
734 $response = self::sendRequest($payload, TRUE);
735
736 if (isset($response['data']['auth']['viewer']['sites']['one']['openPathSearch'])) {
737 return $response['data']['auth']['viewer']['sites']['one']['openPathSearch'];
738 }
739
740 return [];
741 }
742
743 /**
744 * Method to get all reports.
745 *
746 * @param string $host_id
747 * Host id on WebTotem.
748 * @param int $limit
749 * Limit on the number of records.
750 * @param string $cursor
751 * Mark for loading data.
752 *
753 * @return array
754 * Returns reports data.
755 */
756 public static function getAllReports($host_id, $limit = 10, $cursor = NULL)
757 {
758 $cursor = ($cursor == NULL) ? 'null' : '"' . $cursor . '"';
759 $payload = '{"variables":{"filter": { "order": { "direction": "DESC", "field": "created_at"}, "siteId":"' . $host_id . '", "pagination":{"first":' . $limit . ', "cursor":' . $cursor . '} } },"query":"query ReportsQuery($filter: ReportListFilter!) { auth { viewer { reports { list(filter: $filter) { edges { node { id site { hostname } createdAt wa dc ps rc sc av waf } cursor } pageInfo { endCursor hasNextPage } } } } } }"}';
760 $response = self::sendRequest($payload, TRUE);
761
762 if (isset($response['data']['auth']['viewer']['reports']['list']['edges'])) {
763 return $response['data']['auth']['viewer']['reports']['list'];
764 }
765
766 return [];
767 }
768
769 /**
770 * Method to generate report.
771 *
772 * @param string $host_id
773 * Host id on WebTotem.
774 * @param int|array $days
775 * For what period data is needed.
776 * @param array $services
777 * User-specified module settings.
778 *
779 * @return string|bool
780 * Returns report download link.
781 */
782 public static function generateReport(string $host_id, $days, array $services)
783 {
784 $period = WebTotem::getPeriod($days);
785 $language = WebTotem::getLanguage();
786
787 $payload = '{"query":"query ($input: GenerateReportInput) { auth { viewer { reports { generate(input: $input) } } } }", "variables":{ "input": { "siteId": "' . $host_id . '", "from": ' . $period['from'] . ', "to": ' . $period['to'] . ', "wa": ' . $services['wa'] . ', "dc": ' . $services['dc'] . ', "ps": ' . $services['ps'] . ', "rc": ' . $services['rc'] . ', "sc": ' . $services['sc'] . ', "av": ' . $services['av'] . ', "waf": ' . $services['waf'] . ', "language": "' . $language . '" } } }';
788 $response = self::sendRequest($payload, TRUE);
789
790 if (isset($response['data']['auth']['viewer']['reports']['generate'])) {
791 return $response['data']['auth']['viewer']['reports']['generate'];
792 }
793
794 return FALSE;
795 }
796
797 /**
798 * Method to download report.
799 *
800 * @param string $id
801 * Assigned to the report.
802 *
803 * @return string|bool
804 * Returns report download link.
805 */
806 public static function downloadReport($id)
807 {
808 $payload = '{"query": "query { auth { viewer { reports { download(id: \"' . $id . '\") } } } }"}';
809 $response = self::sendRequest($payload, TRUE);
810
811 if (isset($response['data']['auth']['viewer']['reports']['download'])) {
812 return $response['data']['auth']['viewer']['reports']['download'];
813 }
814
815 return FALSE;
816 }
817
818 /**
819 * Method to get configs data.
820 *
821 * @param string $host_id
822 * Host id on WebTotem.
823 *
824 * @return array|bool
825 * Returns configs data.
826 */
827 public static function getConfigs($host_id)
828 {
829 $payload = '{"query":"query{ auth{ viewer{ sites{ one(id:\"' . $host_id . '\"){ configs{ ... on WaConfig { id service isActive notifications } ... on WafConfig { id service isActive notifications } ... on AvConfig { id service isActive notifications } ... on DcConfig { id service isActive notifications } ... on DecConfig { id service isActive } ... on RcConfig { id service isActive notifications} ... on CmsConfig { id service isActive } ... on PsConfig { id service isActive notifications } ... on SsConfig { id service isActive } ... on ScConfig { id service isActive } } } } } } } "}';
830 $response = self::sendRequest($payload, TRUE);
831
832 if (isset($response['data']['auth']['viewer']['sites']['one']['configs'])) {
833 return $response['data']['auth']['viewer']['sites']['one']['configs'];
834 }
835
836 return FALSE;
837 }
838
839 /**
840 * Method to toggle modules config.
841 *
842 * @param string $service_id
843 * Service id that we enable or disable.
844 *
845 * @return string|bool
846 * Returns information whether the request was successful.
847 */
848 public static function toggleConfigs($service_id)
849 {
850 $payload = '{"query":"mutation{ auth{ configs{ toggle(id: \"' . $service_id . '\"){ ... on WaConfig { service isActive } ... on AvConfig { service isActive } ... on DcConfig { service isActive } ... on DecConfig { service isActive } ... on RcConfig { service isActive } ... on CmsConfig { service isActive } ... on PsConfig { service isActive } ... on WafConfig { service isActive } } } } } "}';
851 $response = self::sendRequest($payload, TRUE);
852
853 if (isset($response['data']['auth']['configs']['toggle'])) {
854 return $response['data']['auth']['configs']['toggle'];
855 }
856
857 return FALSE;
858 }
859
860 /**
861 * Method to toggle modules notification.
862 *
863 * @param string $host_id
864 * Host id on WebTotem.
865 * @param string $service
866 * Service id in which we enable or disable notifications.
867 *
868 * @return string|bool
869 * Returns information whether the request was successful.
870 */
871 public static function toggleNotifications($host_id, $service)
872 {
873 $payload = '{"query":"mutation{ auth{ sites{ toggleNotifications(siteId: \"' . $host_id . '\", service: ' . $service . ') } } }"}';
874 $response = self::sendRequest($payload, TRUE);
875
876 if (isset($response['data']['auth']['sites']['toggleNotifications'])) {
877 return $response;//['data']['auth']['sites']['toggleNotifications'];
878 }
879
880 return FALSE;
881 }
882
883 /**
884 * Method to get allow/deny ip list.
885 *
886 * @param string $type
887 * Type of ip list
888 *
889 * @return array|bool
890 * Returns ip allow/deny lists.
891 */
892 public static function getIpLists($type = 'blacklist')
893 {
894 $config_id = WebTotemOption::getOption('config_id');
895 $response = self::sendRequest('/dashboard/firewall/' . $config_id . '/configs/iplist', [
896 'type' => $type,
897 ], 'GET', TRUE);
898
899 if (isset($response['data'])) {
900 return $response['data'];
901 }
902
903 return [];
904 }
905
906 /**
907 * Method to add ip to allow/deny list.
908 *
909 * @param string $ip
910 * Ip address.
911 * @param string $type
912 * Allow or deny type.
913 *
914 * @return bool
915 * Returns information whether the request was successful.
916 */
917 public static function addIpToList($ips, $type)
918 {
919 $config_id = WebTotemOption::getOption('config_id');
920 self::sendRequest('/dashboard/firewall/' . $config_id . '/configs/iplist?type=' . $type, [
921 'ip' => array_filter($ips),
922 ], 'POST', TRUE);
923
924 return true;
925 }
926
927 /**
928 * Method to remove ip from allow/deny list by id.
929 *
930 * @param string $ip
931 * Ip address.
932 * @param string $type
933 * Allow or deny type.
934 *
935 * @return bool
936 * Returns information whether the request was successful.
937 */
938 public static function removeIpFromList($ip, $type)
939 {
940 $config_id = WebTotemOption::getOption('config_id');
941 self::sendRequest('/dashboard/firewall/' . $config_id . '/configs/iplist?type=' . $type, [
942 'ip' => $ip,
943 ], 'DELETE', TRUE);
944
945 return true;
946 }
947
948 /**
949 * Method to get allow url list.
950 *
951 * @param string $host_id
952 * Host id on WebTotem.
953 *
954 * @return array
955 * Returns url allow lists.
956 */
957 public static function getAllowUrlList($host_id)
958 {
959 $payload = '{"query":"query { auth { viewer { sites { one(id: \"' . $host_id . '\"){ firewall{ urlWhiteList{ id url createdAt } } } } } } }"} ';
960 $response = self::sendRequest($payload, TRUE);
961
962 if (isset($response['data']['auth']['viewer']['sites']['one']['firewall']['urlWhiteList'])) {
963 return $response['data']['auth']['viewer']['sites']['one']['firewall']['urlWhiteList'];
964 }
965
966 return [];
967 }
968
969 /**
970 * Method to add url to allow list.
971 *
972 * @param string $host_id
973 * Host id on WebTotem.
974 * @param string $url
975 * User-specified url.
976 *
977 * @return bool|string
978 * Returns information whether the request was successful.
979 */
980 public static function addUrlToAllowList($host_id, $url)
981 {
982 $payload = '{"variables":{ "input": { "siteId": "' . $host_id . '", "url": "' . $url . '" } }, "query":"mutation($input: WafUrlWhiteListInput!) { auth { sites { waf { addToUrlWhiteList(input: $input) } } } }"} ';
983 $response = self::sendRequest($payload, TRUE);
984
985 if (isset($response['data']['auth']['sites']['waf']['addToUrlWhiteList'])) {
986 return $response['data']['auth']['sites']['waf']['addToUrlWhiteList'];
987 }
988
989 return FALSE;
990 }
991
992 /**
993 * Method to remove url from allow list.
994 *
995 * @param string $id
996 * Id assignment to url address.
997 *
998 * @return bool|string
999 * Returns information whether the request was successful.
1000 */
1001 public static function removeUrlFromAllowList($id)
1002 {
1003 $payload = '{"variables":{ "id": "' . $id . '" }, "query":"mutation($id: ID!) { auth { sites { waf { removeFromUrlWhiteList(id: $id) } } } }"} ';
1004 $response = self::sendRequest($payload, TRUE);
1005
1006 if (isset($response['data']['auth']['sites']['waf']['removeFromUrlWhiteList'])) {
1007 return $response['data']['auth']['sites']['waf']['removeFromUrlWhiteList'];
1008 }
1009
1010 return FALSE;
1011 }
1012
1013 /**
1014 * Method to get blocked countries list.
1015 *
1016 * @param string $host_id
1017 * Host id on WebTotem.
1018 *
1019 * @return array
1020 * Returns blocked countries list.
1021 */
1022 public static function getBlockedCountries($host_id)
1023 {
1024 $period = WebTotem::getPeriod(7);
1025 $payload = '{"variables":{"dateRange":{"to":' . $period['to'] . ',"from":' . $period['from'] . '}} , "query":"query($dateRange: DateRangeInput!){ auth { viewer { sites { one(id: \"' . $host_id . '\"){ firewall{ blockedCountries map(dateRange: $dateRange) { attacks, country, location { country { nameEn } } } } } } } } }"}';
1026 $response = self::sendRequest($payload, TRUE);
1027
1028 if (isset($response['data']['auth']['viewer']['sites']['one']['firewall'])) {
1029 return $response['data']['auth']['viewer']['sites']['one']['firewall'];
1030 }
1031
1032 return [];
1033 }
1034
1035 /**
1036 * Method for synchronizing data on the list of blocked countries.
1037 *
1038 * @param string $host_id
1039 * Host id on WebTotem.
1040 * @param array $countries
1041 * Array of countries to block.
1042 *
1043 * @return bool|string
1044 * Returns information whether the request was successful.
1045 */
1046 public static function syncBlockedCountries($host_id, $countries)
1047 {
1048
1049 $countries = $countries ? WebTotem::convertArrayToString($countries) : '';
1050 $payload = '{"variables":{ "input": { "siteId": "' . $host_id . '", "countries": [' . $countries . '] } }, "query":"mutation($input: WafBlockedCountriesInput!) { auth { sites { waf { syncBlockedCountries(input: $input) } } } }"} ';
1051 $response = self::sendRequest($payload, TRUE);
1052
1053 if (isset($response['data']['auth']['sites']['waf']['syncBlockedCountries'])) {
1054 return $response['data']['auth']['sites']['waf']['syncBlockedCountries'];
1055 }
1056
1057 return FALSE;
1058 }
1059
1060 /**
1061 * Method to get user's email.
1062 *
1063 * @return string
1064 * Returns user's email.
1065 */
1066 public static function getEmail()
1067 {
1068 $payload = '{"query":"query { auth { viewer { email } } }"}';
1069 $response = self::sendRequest($payload, true);
1070
1071 return $response['data']['auth']['viewer']['email'];
1072 }
1073
1074 /**
1075 * Method to get user's email.
1076 *
1077 * @param string $plugin_list
1078 * List of plugins and their versions.
1079 *
1080 * @return array
1081 * Returns cve list.
1082 */
1083 public static function getCVE($plugin_list)
1084 {
1085 $payload = '{"variables":{ "params": [' . $plugin_list . '] }, "query":"query searchByTechnologyAndVersion($params: [SearchByTechnologyAndVersionInput!]) { auth { viewer { cve { searchByTechnologyAndVersion(params: $params) { cves { cve_id id summary published reference } technology version } } } } }"}';
1086 $response = self::sendRequest($payload, true);
1087
1088 if (isset($response['data']['auth']['viewer']['cve']['searchByTechnologyAndVersion'])) {
1089 return $response['data']['auth']['viewer']['cve']['searchByTechnologyAndVersion'];
1090 }
1091
1092 return [];
1093 }
1094
1095 /**
1096 * Method to get user's feedback.
1097 *
1098 * @return array
1099 */
1100 public static function getFeedback()
1101 {
1102 return self::sendFeedbackRequest("GET");
1103 }
1104
1105 /**
1106 * Method to set user's feedback.
1107 *
1108 * @return array
1109 */
1110 public static function setFeedback($data)
1111 {
1112 return self::sendFeedbackRequest("POST", $data);
1113 }
1114
1115 /**
1116 * Function sends data request to endpoint.
1117 *
1118 * @param array $data
1119 * Data array to be sent to endpoint.
1120 *
1121 * @return array
1122 * Returns response from WebTotem endpoint.
1123 */
1124 protected static function sendFeedbackRequest($method, $data = [])
1125 {
1126 $url = 'https://nps.wtotem.com/user-score';
1127 $email = WebTotem::getUserEmail();
1128
1129 if (!$email) {
1130 return [];
1131 }
1132
1133 if ($method == "GET") {
1134
1135 $args = [
1136 'timeout' => '30',
1137 'sslverify' => FALSE,
1138 ];
1139
1140 $response = wp_remote_get($url . '?email=' . urlencode($email), $args);
1141
1142 } else {
1143 $data['email'] = $email;
1144 $data['platform'] = 'WORDPRESS';
1145 $data = json_encode($data);
1146
1147 $args = [
1148 'body' => $data,
1149 'timeout' => '30',
1150 'sslverify' => FALSE,
1151 'headers' => [
1152 'Content-Type' => 'application/json',
1153 ],
1154 ];
1155
1156 $response = wp_remote_post($url, $args);
1157 }
1158
1159
1160 $http_code = wp_remote_retrieve_response_code($response);
1161
1162 if ($http_code < 200) {
1163 // WebTotemOption::setNotification('error', __('Could not connect to feedback endpoint.', 'wtotem'));
1164 return [];
1165 }
1166
1167 $response_body = wp_remote_retrieve_body($response);
1168 return json_decode($response_body, true);
1169 }
1170
1171 /**
1172 * Sends a REST API request to the WebTotem API server.
1173 *
1174 * @param string $endpoint
1175 * REST API endpoint (e.g., 'scan', 'status', etc.).
1176 * @param array $data
1177 * Associative array of data to send as JSON body or query parameters.
1178 * @param string $method
1179 * HTTP method: GET, POST, PUT, DELETE (default is POST).
1180 * @param bool $useToken
1181 * Whether to include the auth token.
1182 * @param bool $retry
1183 * Used to prevent recursion on token renewal.
1184 *
1185 * @return array|null
1186 * API response as an associative array, or null on failure.
1187 */
1188 protected static function sendRequest($endpoint, $data = [], $method = 'POST', $useToken = false, $retry = false)
1189 {
1190 $api_key = WebTotemOption::getOption('api_key');
1191
1192 // Get or initialize the API URL.
1193 $api_url = WebTotemOption::getOption('api_url');
1194 if (!$api_url) {
1195 $api_url = self::getApiUrl();
1196 WebTotemOption::setOptions(['api_url' => $api_url]);
1197 }
1198
1199 $auth_token = null;
1200 if ($useToken) {
1201 $auth_token = WebTotemOption::getOption('auth_token');
1202 $auth_token_expired = WebTotemOption::getOption('auth_token_expired');
1203
1204 if ($auth_token_expired <= time() && !$retry) {
1205 $result = self::auth($api_key);
1206 if ($result === 'success') {
1207 return self::sendRequest($endpoint, $data, $method, $useToken, true);
1208 } elseif (isset($result['message'])) {
1209 $message = WebTotem::messageForHuman($result['message']);
1210 // WebTotemOption::setNotification('info', '$endpoint: ' . $endpoint);
1211 WebTotemOption::setNotification('error', $message);
1212 }
1213 }
1214 }
1215
1216 $url = rtrim($api_url, '/') . '/api/v1/' . ltrim($endpoint, '/');
1217
1218 $args = [
1219 'timeout' => 60,
1220 'sslverify' => false,
1221 'headers' => [
1222 'Accept' => 'application/json',
1223 'Content-Type' => 'application/json',
1224 'source' => 'WORDPRESS',
1225 ],
1226 ];
1227
1228 if ($auth_token) {
1229 $args['headers']['Authorization'] = "Bearer $auth_token";
1230 }
1231
1232 if (strtoupper($method) === 'GET') {
1233 $url = add_query_arg($data, $url);
1234 } else {
1235 $args['body'] = json_encode($data);
1236 }
1237
1238 $response = wp_remote_request($url, array_merge($args, ['method' => strtoupper($method)]));
1239
1240 $errors = ['status' => false];
1241 if (is_wp_error($response)) {
1242 $errors = [
1243 'status' => true,
1244 'message' => 'SERVER UNAVAILABLE: ' . $response->get_error_message(),
1245 ];
1246 }
1247
1248 $body = wp_remote_retrieve_body($response);
1249 $decoded = json_decode($body, true);
1250
1251 if (isset($decoded['message']) or $errors['status']) {
1252 $errorMessage = $errors['status'] ? $errors['message'] : $decoded['message'];
1253
1254 if (stripos($errorMessage, "Password expired") !== false) {
1255 wtotem_error_page(['errors' => 'PASSWORD_EXPIRED']);
1256 exit();
1257 } elseif (stripos($errorMessage, "API_KEY_DEACTIVATED") !== false) {
1258 wtotem_error_page(['errors' => 'TARIFF_EXPIRED']);
1259 exit();
1260 }
1261
1262 $message = WebTotem::messageForHuman($errorMessage);
1263 if ($errorMessage == "invalid credentials" && !$retry) {
1264
1265 if (self::auth($api_key) === 'success') {
1266
1267 return self::sendRequest($endpoint, $data, $method, $useToken, true);
1268 }
1269 } elseif (stripos($errorMessage, "USERHOST_NOT_BELONG_TO_USER") !== false) {
1270 if (WebTotem::isMultiSite()) {
1271 WebTotemOption::clearAllHosts();
1272 }
1273 WebTotemOption::clearOptions(['host_id', 'host_name']);
1274 } else {
1275 // WebTotemOption::setNotification('info', '$endpoint: ' . $endpoint);
1276 WebTotemOption::setNotification('error', $message);
1277 }
1278 }
1279
1280 // if (empty($decoded)) {
1281 // self::checkEndpoint();
1282 // }
1283
1284 return $decoded;
1285 }
1286
1287 }
1288