PluginProbe
WebTotem Security / 2.4.18
WebTotem Security v2.4.18
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 2.4.18, at lib/API.php

1,045 lines 39.2 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 * Method for getting an auth token.
23 *
24 * @param string $api_key
25 * Application programming interface key.
26 *
27 * @return bool|string
28 * Returns auth status
29 */
30 public static function auth($api_key) {
31 $domain = WEBTOTEM_SITE_DOMAIN;
32
33 if(substr($api_key, 1, 1) == "-"){
34 $prefix = substr($api_key, 0, 1);
35 if($api_url = self::getApiUrl($prefix)){
36 WebTotemOption::setOptions(['api_url' => $api_url]);
37 } else {
38 WebTotemOption::setNotification('error', __('Invalid API key', 'wtotem'));
39 return FALSE;
40 }
41 $api_key = substr($api_key, 2);
42 }
43
44 if(empty($api_key)) { return FALSE; }
45 $payload = '{"query":"mutation{ guest{ apiKeys{ auth(apiKey:\"' . $api_key . '\", source:\"' . $domain . '\"),{ token{ value, refreshToken, expiresIn } } } } }"}';
46 $result = self::sendRequest($payload, FALSE, TRUE);
47
48 if (isset($result['data']['guest']['apiKeys']['auth']['token']['value'])) {
49 $auth_token = $result['data']['guest']['apiKeys']['auth']['token'];
50 WebTotemOption::login(['token' => $auth_token, 'api_key' => $api_key]);
51 return 'success';
52 } elseif($result['errors'][0]['message'] == 'INVALID_API_KEY') {
53 WebTotemOption::logout();
54 }
55
56 return FALSE;
57 }
58
59 /**
60 * Method for getting API url.
61 *
62 * @param string $prefix
63 *
64 * @return string|bool
65 * API url
66 */
67 public static function getApiUrl($prefix){
68 $urls = [
69 'P' => '.wtotem.com',
70 'C' => '.webtotem.kz',
71 ];
72
73 if(array_key_exists($prefix, $urls)){
74 return 'https://api' . $urls[$prefix] . '/graphql';
75 }
76 return false;
77 }
78
79 /**
80 * Get site info from API server.
81 *
82 * @param string $attempt
83 * Is the request an attempt to get host data.
84 *
85 * @return array
86 * Returns host data.
87 */
88 public static function siteInfo($attempt = FALSE) {
89
90 if(self::isMultiSite()){
91 $host['id'] = WebTotemOption::getSessionOption('host_id');
92
93 if ($host['id']) {
94 return $host;
95 }
96 }
97
98 $host = WebTotemOption::getHost();
99
100 if ($host['id']) {
101 return $host;
102 }
103
104 $all_sites = self::getSites(null, 0);
105 if($all_sites){
106 if(self::isMultiSite()) {
107 $sites = get_sites();
108 foreach ($sites as $site){
109 $domain = untrailingslashit($site->domain . $site->path);
110 self::addSite($domain, $all_sites);
111 }
112
113 if (!$attempt) {
114 return self::siteInfo(TRUE);
115 }
116 }
117 else {
118 $domain = WEBTOTEM_SITE_DOMAIN;
119 return self::addSite($domain, $all_sites);
120 }
121 }
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 * @param array $all_sites
132 * Array with site data on the WebTotem platform.
133 *
134 * @return array
135 * Returns host data.
136 */
137 public static function addSite( $domain, $all_sites) {
138
139 if(function_exists('idn_to_utf8')){
140 $domain = idn_to_utf8($domain);
141 }
142
143 // Checking if the site has been added to the WebTotem.
144 if(array_key_exists('edges', $all_sites)){
145
146 foreach ($all_sites['edges'] as $site){
147 $site = $site['node'];
148 $hostname = untrailingslashit($site['hostname']);
149 // If it added, save site data to DB.
150 if($hostname == $domain or $hostname == 'www.' . $domain){
151 WebTotemOption::setHost($site['hostname'], $site['id']);
152 return [
153 'id' => $site['id'],
154 'name' => $site['hostname'],
155 ];
156 }
157 }
158
159 }
160
161 // If the site is not added then try to add.
162 $payload = '{"variables":{"input":{"title":"' . $domain . '","hostname":"' . $domain . '","configs":{"scheme":"http","port":80,"wa":{},"dec":{},"ps":{}}}},"query":"mutation ($input: CreateSiteInput) { auth { sites { create(input: $input) { id hostname title } } } }"}';
163 $add_site = self::sendRequest($payload, TRUE);
164 if (isset($add_site['errors'])) {
165 WebTotemOption::setNotification('error', __('Failed to add the site to the WebTotem platform.', 'wtotem'));
166 }
167 else {
168 if($host = $add_site['data']['auth']['sites']['create']) {
169 // If it added, save site ID.
170 WebTotemOption::setHost($host['title'], $host['id']);
171 return [
172 'id' => $host['id'],
173 'name' => $host['title'],
174 ];
175 }
176 }
177 return [];
178 }
179
180 /**
181 * Get all sites from API.
182 *
183 * @param string $cursor
184 * Mark for loading data.
185 * @param string $limit
186 * Limit of sites to loading.
187 *
188 * @return array
189 * Returns host data.
190 */
191 public static function getSites($cursor = null, $limit = 15, $filter = false) {
192 $cursor = ($cursor == null) ? 'null' : '\"' . $cursor . '\"';
193 if(!$filter) {
194 $filter = ($limit === 0) ? '' : 'pagination:{ first: ' . $limit . ', cursor: ' . $cursor . ' }';
195 }
196
197 $payload = '{"query":"query getSites { auth { viewer { sites { ...sites } } } } fragment sites on SiteQueries { list(filter: { ' . $filter . ' }) { pageInfo{ hasNextPage endCursor } edges { node { id hostname title createdAt ssl { status } availability { status } reputation { status } ports { status } deface { status } domain { status } antivirus { status } firewall { status } maliciousScript { stack { name } } } } } }"}';
198 $result = self::sendRequest($payload, true);
199
200 if (isset($result['data']['auth']['viewer']['sites']['list']['edges'])) {
201 return $result['data']['auth']['viewer']['sites']['list'];
202 }
203
204 return [];
205 }
206
207 /**
208 * Method to get the agents file names and AM file link.
209 *
210 * @param string $host_id
211 * Host id on WebTotem.
212 *
213 * @return array
214 * Returns agents files data.
215 */
216 public static function getAgentsFiles($host_id) {
217
218 if(WebTotem::isMultiSite()){
219 $all_hosts = WebTotemOption::getOption('all_hosts');
220 $all_hosts = $all_hosts ? json_decode($all_hosts, true) : [];
221
222 $siteIdsArray = $all_hosts ? array_values($all_hosts) : [];
223 $siteIds = $siteIdsArray ? addslashes(WebTotem::convertArrayToString($siteIdsArray)) : '';
224
225 $payload = '{"query":"mutation { auth { am { installMultisite(mainSiteId: \"' . $host_id . '\", siteIds: [' . $siteIds . ']){ downloadLink, amFilename, wafFilename, avFilename } } } }"}';
226 $response = self::sendRequest($payload, TRUE);
227
228 if (isset($response['data']['auth']['am']['installMultisite'])) {
229 return $response['data']['auth']['am']['installMultisite'];
230 }
231 }
232 else {
233 $payload = '{"query":"mutation { auth { am { install(siteId: \"' . $host_id . '\"){ downloadLink, amFilename, wafFilename, avFilename } } } }"}';
234 $response = self::sendRequest($payload, TRUE);
235 if (isset($response['data']['auth']['am']['install'])) {
236 return $response['data']['auth']['am']['install'];
237 }
238 }
239 return [];
240 }
241
242 /**
243 * Add secondary MultiSite host.
244 *
245 * @param $new_sites
246 * An array with sites to add.
247 *
248 * @return void.
249 */
250 public static function addMultiSiteNewSites($new_sites){
251 // Host id of the main site in MultiSite network.
252 $main_host = WebTotemOption::getMainHost();
253
254 foreach ($new_sites as $site){
255 $all_sites = self::getSites(null, 0);
256 $host = self::addSite($site, $all_sites);
257 if(key_exists('id', $host)){
258 $payload = '{"query":"mutation { auth { am { addMultisiteHost(mainSiteId: \"' . $main_host['id'] . '\", siteId: \"' . $host['id'] . '\") } } }"}';
259
260 $result = self::sendRequest($payload, TRUE);
261 if(!$result['errors'][0]['message']){
262 WebTotemOption::setNotification( 'info', __('A new website has been added: ', 'wtotem') . $site);
263 }
264 }
265 }
266 }
267
268 /**
269 * Remove secondary MultiSite host.
270 *
271 * @param $host_id
272 * Host id on WebTotem.
273 *
274 * @return bool
275 * Returns result removing host.
276 */
277 public static function removeMultiSiteHost($host_id){
278 $payload = '{"query":"mutation { auth { am { removeMultisiteHost(siteId: \"' . $host_id . '\") } } }"}';
279 $response = self::sendRequest($payload, TRUE);
280 if (isset($response['data']['auth']['am']['removeSecondaryMultisiteHost'])) {
281 return $response['data']['auth']['am']['removeSecondaryMultisiteHost'];
282 }
283
284 return false;
285 }
286
287 /**
288 * Method to get agents (AM, WAF, AV) statuses.
289 *
290 * @param string $host_id
291 * Host id on WebTotem.
292 *
293 * @return array
294 * Returns agents statuses data.
295 */
296 public static function getAgentsStatusesFromAPI($host_id) {
297 $payload = '{"query":"query ($id: ID!) { auth { viewer { sites { one(id: $id) { agentManager { statuses { am { status } av { status } waf { status } } } } } } } }", "variables":{"id":"' . $host_id . '"}}';
298 $response = self::sendRequest($payload, TRUE);
299
300 if (isset($response['data']['auth']['viewer']['sites']['one']['agentManager']['statuses'])) {
301 return $response['data']['auth']['viewer']['sites']['one']['agentManager']['statuses'];
302 }
303
304 return [];
305 }
306
307 /**
308 * Method to get user time zone.
309 *
310 * @return string|bool
311 * Returns time zone data.
312 */
313 public static function getTimeZone() {
314 $payload = '{"query":"query { auth { viewer{ timezone } } } "}';
315 $response = self::sendRequest($payload, TRUE);
316
317 if (isset($response['data']['auth']['viewer']['timezone'])) {
318 return $response['data']['auth']['viewer']['timezone'];
319 }
320 return FALSE;
321 }
322
323 /**
324 * Method for get all the site security data.
325 *
326 * @param string $host_id
327 * Host id on WebTotem.
328 * @param int|array $days
329 * For what period data is needed.
330 *
331 * @return array
332 * Returns all data.
333 */
334 public static function getAllData($host_id, $days = 7) {
335 $language = WebTotem::getLanguage();
336 $period = WebTotem::getPeriod($days);
337
338 $payload = '{"query":"query($id: ID!, $dateRange: DateRangeInput!, $language: Language!, $dateRangeWeek: DateRangeInput!, $wafLogFilter: WafLogFilter!) { auth { viewer { sites { one(id: $id) { ports { status ip tcp lastTest { time } ignorePorts country } availability { status lastTest { time } responseTime downTime(dateRange: $dateRange) percent(dateRange: $dateRange) } deface { status lastTest { time } words count } domain { status registrar owner email createdDate expiredDate } ssl { status daysLeft expiryDate issueDate } reputation { status lastTest { time } virusList { virus{ type path } antiVirus } } firewall { lastTest { time } logs(wafLogFilter: $wafLogFilter){ edges{ node{ type blocked payload ip proxyIp userAgent description source region signatureId location{ country{ nameEn } } time request status country category } } } map(dateRange: $dateRange) { attacks, country } status chart(dateRange: $dateRange) { time attacks blocked } report(dateRange: $dateRange) { time attacks ip } } serverStatus { info { phpVersion phpServerUser phpServerSoftware phpGatewayInterface phpServerProtocol osInfo cpuCount cpuModel CpuFreq cpuFamily lsCpu maxExecTime mathLibraries } ramChart(dateRange: $dateRangeWeek){ total value time } cpuChart(dateRange: $dateRangeWeek){ value time } discUsage{ total free } status } maliciousScript { lastTest { time } status } scoring( language: $language ){ score lastTest{ time } result{ ip country isHigherThan }} agentManager{ createdAt } antivirus { status stats { changed deleted scanned infected error } lastTest { time } isFirstCheck } } } } } }","variables":{"id":"' . $host_id . '","dateRange":{"to":' . $period['to'] . ',"from":' . $period['from'] . '}, "dateRangeWeek":{"to":' . $period['to'] . ',"from":' . $period['from'] . '}, "wafLogFilter": {"dateRange":{"to":' . $period['to'] . ',"from":' . $period['from'] . '},"order":{"direction":"DESC","field":"time"},"pagination":{"first": 10,"cursor":null}}, "language":"' . $language . '"}}';
339 $response = self::sendRequest($payload, TRUE);
340
341 if (isset($response['data']['auth']['viewer']['sites']['one'])) {
342 return $response['data']['auth']['viewer']['sites']['one'];
343 }
344
345 return [];
346 }
347
348 /**
349 * Method to get firewall data.
350 *
351 * @param string $host_id
352 * Host id on WebTotem.
353 * @param int $limit
354 * Limit on the number of records.
355 * @param string $cursor
356 * Mark for loading data.
357 * @param int|array $days
358 * For what period data is needed.
359 *
360 * @return array
361 * Returns firewall data.
362 */
363 public static function getFirewall($host_id, $limit = 20, $cursor = NULL, $days = 365) {
364 $period = WebTotem::getPeriod($days);
365 $cursor = ($cursor == NULL) ? 'null' : '"' . $cursor . '"';
366
367 $payload = '{"query":"query($id: ID!, $wafLogFilter: WafLogFilter!, $dateRange: DateRangeInput!) { auth { viewer { sites { one(id: $id) { firewall { lastTest { time } status map(dateRange: $dateRange) { attacks, country, location { country { nameEn } } } chart(dateRange: $dateRange) { time attacks blocked } ...FirewallLogFragment } agentManager { createdAt } } } } } } fragment FirewallLogFragment on Waf { logs(wafLogFilter: $wafLogFilter) { edges { cursor node { type blocked payload ip proxyIp userAgent description source region signatureId location { country { nameEn } } time request status country category } } pageInfo { endCursor hasNextPage } } }", "variables":{"dateRange":{"to":' . $period['to'] . ',"from":' . $period['from'] . '},"id":"' . $host_id . '","wafLogFilter":{"dateRange":{"to":' . $period['to'] . ',"from":' . $period['from'] . '},"order":{"direction":"DESC","field":"time"},"pagination":{"first":' . $limit . ',"cursor":' . $cursor . '}}} }';
368 $response = self::sendRequest($payload, TRUE);
369
370 if (isset($response['data']['auth']['viewer']['sites']['one'])) {
371 return $response['data']['auth']['viewer']['sites']['one'];
372 }
373
374 return [];
375 }
376
377 /**
378 * Method to get firewall chart data.
379 *
380 * @param string $host_id
381 * Host id on WebTotem.
382 * @param int $days
383 * For what period data is needed.
384 *
385 * @return array
386 * Returns firewall chart data.
387 */
388 public static function getFirewallChart($host_id, $days = 7) {
389 $period = WebTotem::getPeriod($days);
390
391 $payload = '{ "query":"query($id: ID!, $dateRange: DateRangeInput!) { auth { viewer { sites { one(id: $id) { firewall { lastTest { time } status map(dateRange: $dateRange) { attacks, country, location { country { nameEn } } } chart(dateRange: $dateRange) { time attacks blocked } } } } } } }", "operationName":null,"variables":{"id":"' . $host_id . '","dateRange":{"to":' . $period['to'] . ',"from":' . $period['from'] . '} } }';
392 $response = self::sendRequest($payload, TRUE);
393
394 if (isset($response['data']['auth']['viewer']['sites']['one']['firewall'])) {
395 return $response['data']['auth']['viewer']['sites']['one']['firewall'];
396 }
397
398 return [];
399 }
400
401 /**
402 * Method to set firewall settings.
403 *
404 * @param string $host_id
405 * Host id on WebTotem.
406 * @param array $settings
407 * User-specified settings.
408 *
409 * @return array
410 * Returns information whether the request was successful.
411 */
412 public static function setFirewallSettings($host_id, array $settings) {
413 $payload = '{"variables":{"input": {"siteId": "' . $host_id . '", "gdn": ' . $settings['gdn'] . ', "dosProtection": ' . $settings['dosProtection'] . ', "dosLimit": ' . $settings['dosLimit'] . ', "loginAttemptsProtection": ' . $settings['loginAttemptsProtection'] . ', "loginAttemptsLimit": ' . $settings['loginAttemptsLimit'] . '}},"query":"mutation WafSettings($input: WafSettingsInput!) { auth { sites { waf{ settings(input: $input) { gdn dosProtection loginAttemptsProtection dosLimit loginAttemptsLimit } } } } }"}';
414 return self::sendRequest($payload, TRUE);
415 }
416
417 /**
418 * Method to get antivirus data.
419 *
420 * @param array $params
421 * Parameters for filtering data.
422 *
423 * @return array
424 * Returns antivirus data.
425 */
426 public static function getAntivirus(array $params) {
427
428 $cursor = ($params['cursor']) ? '"' . $params['cursor'] . '"' : 'null';
429 $event = ($params['event']) ? '"' . $params['event'] . '"' : '"new"';
430 $permissions = ($params['permissions']) ? ' "permissionsChanged":true, ' : '';
431 $period = WebTotem::getPeriod($params['days']);
432
433 $payload = '{"operationName":null,"variables":{"id":"' . $params['host_id'] . '","avLogFilter":{' . $permissions . '"event":' . $event . ', "dateRange":{"to":' . $period['to'] . ',"from":' . $period['from'] . '},"order":{"direction":"DESC","field":"time"},"pagination":{"first":' . $params['limit'] . ',"cursor":' . $cursor . '}}},"query":"query ($id: ID!, $avLogFilter: AvLogFilter!) { auth { viewer { sites { one(id: $id) { id ... on Site { configs { ... on AvConfig { isActive id } } } antivirus { quarantine{ id path date } status log(avLogFilter: $avLogFilter) { edges { node { filePath event signatures time permissions permissionsChanged } } pageInfo { endCursor hasNextPage } } lastTest { time } stats { changed deleted scanned infected } } } } } } }"}';
434 $response = self::sendRequest($payload, TRUE);
435
436 if (isset($response['data']['auth']['viewer']['sites']['one']['antivirus'])) {
437 return $response['data']['auth']['viewer']['sites']['one']['antivirus'];
438 }
439 return [];
440 }
441
442 /**
443 * Method to get antivirus last test.
444 *
445 * @param string $host_id
446 * Host id on WebTotem.
447 *
448 * @return array
449 * Returns antivirus last test data.
450 */
451 public static function getAntivirusLastTest($host_id) {
452
453 $payload = '{"variables":{"id":"' . $host_id . '"},"query":"query ($id: ID!) { auth { viewer { sites { one(id: $id) { antivirus { status lastTest { time } } } } } } }"}';
454 $response = self::sendRequest($payload, TRUE);
455
456 if (isset($response['data']['auth']['viewer']['sites']['one']['antivirus'])) {
457 return $response['data']['auth']['viewer']['sites']['one']['antivirus'];
458 }
459 return [];
460 }
461
462 /**
463 * Method to force check services.
464 *
465 * @param string $host_id
466 * Host id on WebTotem.
467 * @param string $service
468 * Service that needs to be checked.
469 *
470 * @return array
471 * Returns information whether the request was successful.
472 */
473 public static function forceCheck($host_id, $service) {
474 $payload = '{"variables":{"id":"' . $host_id . '","service":"' . $service . '"},"query":"mutation ($id: ID!, $service: ForceCheckService!) { auth { sites { forceCheck(siteId: $id, service: $service) } } }"} ';
475 return self::sendRequest($payload, TRUE);
476 }
477
478 /**
479 * Method to export antivirus report.
480 *
481 * @param string $host_id
482 * Host id on WebTotem.
483 * @param int|array $days
484 * For what period data is needed.
485 *
486 * @return array
487 * Returns information whether the request was successful.
488 */
489 public static function avExport($host_id, $days = 30) {
490 $period = WebTotem::getPeriod($days);
491 $payload = '{"variables":{ "input":{"siteId":"' . $host_id . '", "dateRange":{"to":' . $period['to'] . ',"from":' . $period['from'] . '} }},"query":"mutation ($input: AvLogExportInput!) { auth { sites { av { export(input: $input) } } } }"} ';
492 return self::sendRequest($payload, TRUE);
493 }
494
495 /**
496 * Method to get quarantine data.
497 *
498 * @param string $host_id
499 * Host id on WebTotem.
500 *
501 * @return array
502 * Returns quarantine data.
503 */
504 public static function getQuarantineList($host_id) {
505 $payload = '{"query":"query{ auth{ viewer{ sites{ one(id:\"' . $host_id . '\"){ antivirus{ quarantine{ id path date } } } } } } } "}';
506 $response = self::sendRequest($payload, TRUE);
507
508 if (isset($response['data']['auth']['viewer']['sites']['one']['antivirus']['quarantine'])) {
509 return $response['data']['auth']['viewer']['sites']['one']['antivirus']['quarantine'];
510 }
511 return [];
512 }
513
514 /**
515 * Method to move file to quarantine.
516 *
517 * @param string $host_id
518 * Host id on WebTotem.
519 * @param string $path
520 * Path to the file.
521 *
522 * @return array
523 * Returns information whether the request was successful.
524 */
525 public static function moveToQuarantine($host_id, $path) {
526 $payload = '{"query":"mutation{ auth{ sites{ av{ moveToQuarantine(input:{ siteId:\"' . $host_id . '\", path:\"' . $path . '\" }) } } } } "}';
527 return self::sendRequest($payload, TRUE);
528 }
529
530 /**
531 * Method to move file from quarantine.
532 *
533 * @param string $id
534 * Id assigned to the file.
535 *
536 * @return array
537 * Returns information whether the request was successful.
538 */
539 public static function moveFromQuarantine($id) {
540 $payload = '{"query":"mutation{ auth{ sites{ av{ moveFromQuarantine(id: \"' . $id . '\") } } } } "}';
541 return self::sendRequest($payload, TRUE);
542 }
543
544 /**
545 * Method to get server status data.
546 *
547 * @param string $host_id
548 * Host id on WebTotem.
549 * @param int|array $days
550 * For what period data is needed.
551 *
552 * @return array
553 * Returns server status data.
554 */
555 public static function getServerStatusData($host_id, $days = 7) {
556 $period = WebTotem::getPeriod($days);
557 $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'] . '} } }';
558
559 $response = self::sendRequest($payload, TRUE);
560
561 if (isset($response['data']['auth']['viewer']['sites']['one']['serverStatus'])) {
562 return $response['data']['auth']['viewer']['sites']['one']['serverStatus'];
563 }
564
565 return [];
566 }
567
568 /**
569 * Method to remove port from ignore list.
570 *
571 * @param string $host_id
572 * Host id on WebTotem.
573 * @param string $port
574 * User specified port.
575 *
576 * @return array
577 * Returns information whether the request was successful.
578 */
579 public static function removeIgnorePort($host_id, $port) {
580 $payload = '{"variables":{ "input": { "siteId": "' . $host_id . '", "port":' . $port . '} },"query":"mutation($input: IgnorePortInput!) { auth { sites { ps { removeIgnorePort(input: $input) } } } }"} ';
581 return self::sendRequest($payload, TRUE);
582 }
583
584 /**
585 * Method to add port to ignore list.
586 *
587 * @param string $host_id
588 * Host id on WebTotem.
589 * @param string $port
590 * User specified port.
591 *
592 * @return array
593 * Returns information whether the request was successful.
594 */
595 public static function addIgnorePort($host_id, $port) {
596 $payload = '{"variables":{ "input": { "siteId": "' . $host_id . '", "port":' . (int) $port . '} },"query":"mutation($input: IgnorePortInput!) { auth { sites { ps { addIgnorePort(input: $input) } } } }"} ';
597 return self::sendRequest($payload, TRUE);
598 }
599
600 /**
601 * Method to get all ports list.
602 *
603 * @param string $host_id
604 * Host id on WebTotem.
605 *
606 * @return array
607 * Returns ports data.
608 */
609 public static function getAllPortsList($host_id) {
610 $payload = '{"query":"query($id: ID!) { auth { viewer { sites { one(id: $id) { ports { status ip tcp ignorePorts lastTest { time } } } } } } } ","variables":{"id":"' . $host_id . '"}}';
611
612 $response = self::sendRequest($payload, TRUE);
613
614 if (isset($response['data']['auth']['viewer']['sites']['one']['ports'])) {
615 return $response['data']['auth']['viewer']['sites']['one']['ports'];
616 }
617
618 return [];
619 }
620
621 /**
622 * Method to get all reports.
623 *
624 * @param string $host_id
625 * Host id on WebTotem.
626 * @param int $limit
627 * Limit on the number of records.
628 * @param string $cursor
629 * Mark for loading data.
630 *
631 * @return array
632 * Returns reports data.
633 */
634 public static function getAllReports($host_id, $limit = 10, $cursor = NULL) {
635 $cursor = ($cursor == NULL) ? 'null' : '"' . $cursor . '"';
636 $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 } } } } } }"}';
637 $response = self::sendRequest($payload, TRUE);
638
639 if (isset($response['data']['auth']['viewer']['reports']['list']['edges'])) {
640 return $response['data']['auth']['viewer']['reports']['list'];
641 }
642
643 return [];
644 }
645
646 /**
647 * Method to generate report.
648 *
649 * @param string $host_id
650 * Host id on WebTotem.
651 * @param int|array $days
652 * For what period data is needed.
653 * @param array $services
654 * User-specified module settings.
655 *
656 * @return string|bool
657 * Returns report download link.
658 */
659 public static function generateReport($host_id, $days, array $services) {
660 $period = WebTotem::getPeriod($days);
661 $language = WebTotem::getLanguage();
662
663 $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 . '" } } }';
664 $response = self::sendRequest($payload, TRUE);
665
666 if (isset($response['data']['auth']['viewer']['reports']['generate'])) {
667 return $response['data']['auth']['viewer']['reports']['generate'];
668 }
669
670 return FALSE;
671 }
672
673 /**
674 * Method to download report.
675 *
676 * @param string $id
677 * Assigned to the report.
678 *
679 * @return string|bool
680 * Returns report download link.
681 */
682 public static function downloadReport($id) {
683 $payload = '{"query": "query { auth { viewer { reports { download(id: \"' . $id . '\") } } } }"}';
684 $response = self::sendRequest($payload, TRUE);
685
686 if (isset($response['data']['auth']['viewer']['reports']['download'])) {
687 return $response['data']['auth']['viewer']['reports']['download'];
688 }
689
690 return FALSE;
691 }
692
693 /**
694 * Method to get configs data.
695 *
696 * @param string $host_id
697 * Host id on WebTotem.
698 *
699 * @return array|bool
700 * Returns configs data.
701 */
702 public static function getConfigs($host_id) {
703 $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 } } } } } } } "}';
704 $response = self::sendRequest($payload, TRUE);
705
706 if (isset($response['data']['auth']['viewer']['sites']['one']['configs'])) {
707 return $response['data']['auth']['viewer']['sites']['one']['configs'];
708 }
709
710 return FALSE;
711 }
712
713 /**
714 * Method to toggle modules config.
715 *
716 * @param string $service_id
717 * Service id that we enable or disable.
718 *
719 * @return string|bool
720 * Returns information whether the request was successful.
721 */
722 public static function toggleConfigs($service_id) {
723 $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 } } } } } "}';
724 $response = self::sendRequest($payload, TRUE);
725
726 if (isset($response['data']['auth']['configs']['toggle'])) {
727 return $response['data']['auth']['configs']['toggle'];
728 }
729
730 return FALSE;
731 }
732
733 /**
734 * Method to toggle modules notification.
735 *
736 * @param string $host_id
737 * Host id on WebTotem.
738 * @param string $service
739 * Service id in which we enable or disable notifications.
740 *
741 * @return string|bool
742 * Returns information whether the request was successful.
743 */
744 public static function toggleNotifications($host_id, $service) {
745 $payload = '{"query":"mutation{ auth{ sites{ toggleNotifications(siteId: \"' . $host_id . '\", service: ' . $service . ') } } }"}';
746 $response = self::sendRequest($payload, TRUE);
747
748 if (isset($response['data']['auth']['sites']['toggleNotifications'])) {
749 return $response;//['data']['auth']['sites']['toggleNotifications'];
750 }
751
752 return FALSE;
753 }
754
755 /**
756 * Method to get allow/deny ip list.
757 *
758 * @param string $host_id
759 * Host id on WebTotem.
760 *
761 * @return array|bool
762 * Returns ip allow/deny lists.
763 */
764 public static function getIpLists($host_id) {
765 $payload = '{"variables":{ "id": "' . $host_id . '" },"query":"query($id: ID!) { auth { viewer { sites{ one(id: $id){ firewall{ blackList{ id ip createdAt } whiteList{ id ip createdAt } settings{ gdn dosProtection dosLimit loginAttemptsProtection loginAttemptsLimit } } } } } } }"} ';
766 $response = self::sendRequest($payload, TRUE);
767
768 if (isset($response['data']['auth']['viewer']['sites']['one']['firewall'])) {
769 return $response['data']['auth']['viewer']['sites']['one']['firewall'];
770 }
771
772 return [];
773 }
774
775 /**
776 * Method to add ip to allow/deny list.
777 *
778 * @param string $host_id
779 * Host id on WebTotem.
780 * @param string $ips
781 * Ip address list.
782 * @param string $list
783 * Allow or deny list.
784 *
785 * @return bool
786 * Returns information whether the request was successful.
787 */
788 public static function addIpToList($host_id, $ips, $list) {
789
790 if ($ips) {
791 $ips = WebTotem::convertIpListForApi($ips);
792 $payload = '{"variables":{ "input": { "siteId": "' . $host_id . '", "ips": ' . $ips . ', "color": "' . $list . '" } }, "query":"mutation($input: WafListInput!) { auth { sites { waf { addToList(input: $input){ status invalidIPs} } } } }"} ';
793 $response = self::sendRequest($payload, TRUE);
794
795 if (isset($response['data']['auth']['sites']['waf']['addToList'])) {
796 return $response['data']['auth']['sites']['waf']['addToList'];
797 }
798 }
799
800 return FALSE;
801 }
802
803 /**
804 * Method to remove ip from allow/deny list by id.
805 *
806 * @param string $id
807 * Id assignment to ip address.
808 *
809 * @return bool
810 * Returns information whether the request was successful.
811 */
812 public static function removeIpFromList($id) {
813 $payload = '{"variables":{ "id": "' . $id . '" },"query":"mutation($id: ID!) { auth { sites { waf { removeFromList(id: $id) } } } }"} ';
814 $response = self::sendRequest($payload, TRUE);
815
816 if (isset($response['data']['auth']['sites']['waf']['removeFromList'])) {
817 return $response['data']['auth']['sites']['waf']['removeFromList'];
818 }
819
820 return FALSE;
821 }
822
823 /**
824 * Method to get allow url list.
825 *
826 * @param string $host_id
827 * Host id on WebTotem.
828 *
829 * @return array
830 * Returns url allow lists.
831 */
832 public static function getAllowUrlList($host_id) {
833 $payload = '{"query":"query { auth { viewer { sites { one(id: \"' . $host_id . '\"){ firewall{ urlWhiteList{ id url createdAt } } } } } } }"} ';
834 $response = self::sendRequest($payload, TRUE);
835
836 if (isset($response['data']['auth']['viewer']['sites']['one']['firewall']['urlWhiteList'])) {
837 return $response['data']['auth']['viewer']['sites']['one']['firewall']['urlWhiteList'];
838 }
839
840 return [];
841 }
842
843 /**
844 * Method to add url to allow list.
845 *
846 * @param string $host_id
847 * Host id on WebTotem.
848 * @param string $url
849 * User-specified url.
850 *
851 * @return bool|string
852 * Returns information whether the request was successful.
853 */
854 public static function addUrlToAllowList($host_id, $url) {
855 $payload = '{"variables":{ "input": { "siteId": "' . $host_id . '", "url": "' . $url . '" } }, "query":"mutation($input: WafUrlWhiteListInput!) { auth { sites { waf { addToUrlWhiteList(input: $input) } } } }"} ';
856 $response = self::sendRequest($payload, TRUE);
857
858 if (isset($response['data']['auth']['sites']['waf']['addToUrlWhiteList'])) {
859 return $response['data']['auth']['sites']['waf']['addToUrlWhiteList'];
860 }
861
862 return FALSE;
863 }
864
865 /**
866 * Method to remove url from allow list.
867 *
868 * @param string $id
869 * Id assignment to url address.
870 *
871 * @return bool|string
872 * Returns information whether the request was successful.
873 */
874 public static function removeUrlFromAllowList($id) {
875 $payload = '{"variables":{ "id": "' . $id . '" }, "query":"mutation($id: ID!) { auth { sites { waf { removeFromUrlWhiteList(id: $id) } } } }"} ';
876 $response = self::sendRequest($payload, TRUE);
877
878 if (isset($response['data']['auth']['sites']['waf']['removeFromUrlWhiteList'])) {
879 return $response['data']['auth']['sites']['waf']['removeFromUrlWhiteList'];
880 }
881
882 return FALSE;
883 }
884
885 /**
886 * Method to get blocked countries list.
887 *
888 * @param string $host_id
889 * Host id on WebTotem.
890 *
891 * @return array
892 * Returns blocked countries list.
893 */
894 public static function getBlockedCountries($host_id) {
895 $period = WebTotem::getPeriod(7);
896 $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 } } } } } } } } }"}';
897 $response = self::sendRequest($payload, TRUE);
898
899 if (isset($response['data']['auth']['viewer']['sites']['one']['firewall'])) {
900 return $response['data']['auth']['viewer']['sites']['one']['firewall'];
901 }
902
903 return [];
904 }
905
906 /**
907 * Method for synchronizing data on the list of blocked countries.
908 *
909 * @param string $host_id
910 * Host id on WebTotem.
911 * @param array $countries
912 * Array of countries to block.
913 *
914 * @return bool|string
915 * Returns information whether the request was successful.
916 */
917 public static function syncBlockedCountries($host_id, $countries) {
918
919 $countries = $countries ? WebTotem::convertArrayToString($countries) : '';
920 $payload = '{"variables":{ "input": { "siteId": "' . $host_id . '", "countries": [' . $countries . '] } }, "query":"mutation($input: WafBlockedCountriesInput!,) { auth { sites { waf { syncBlockedCountries(input: $input) } } } }"} ';
921 $response = self::sendRequest($payload, TRUE);
922
923 if (isset($response['data']['auth']['sites']['waf']['syncBlockedCountries'])) {
924 return $response['data']['auth']['sites']['waf']['syncBlockedCountries'];
925 }
926
927 return FALSE;
928 }
929
930 /**
931 * Method to get user's email.
932 *
933 * @return string
934 * Returns user's email.
935 */
936 public static function getEmail(){
937 $payload = '{"query":"query { auth { viewer { email } } }"}';
938 $response = self::sendRequest($payload, true);
939
940 return $response['data']['auth']['viewer']['email'];
941 }
942
943 /**
944 * Function sends GraphQL request to API server.
945 *
946 * @param string $payload
947 * Payload to be sent to API server.
948 * @param bool $token
949 * Whether a token is needed when sending a request.
950 * @param bool $repeat
951 * Required to avoid recursion.
952 *
953 * @return array
954 * Returns response from WebTotem API.
955 */
956 protected static function sendRequest($payload, $token = FALSE, $repeat = FALSE) {
957
958 $api_key = WebTotemOption::getOption('api_key');
959
960 // Remote URL where the public WebTotem API service is running.
961 $api_url = WebTotemOption::getOption('api_url');
962 if(!$api_url){
963 $api_url = self::getApiUrl('P');
964 WebTotemOption::setOptions(['api_url' => $api_url]);
965 }
966
967 // Checking whether a token is needed.
968 if ($token) {
969 $auth_token = WebTotemOption::getOption('auth_token');
970 $auth_token_expired = WebTotemOption::getOption('auth_token_expired');
971
972 // Checking whether the token has expired.
973 if ($auth_token_expired <= time() && !$repeat) {
974 $result = self::auth($api_key);
975 if ($result === 'success') {
976 return self::sendRequest($payload, $token, TRUE);
977 }
978 else {
979 if(isset($result['errors'])){
980 $message = WebTotem::messageForHuman($result['errors'][0]['message']);
981 WebTotemOption::setNotification('error', $message);
982 }
983 }
984 }
985 }
986
987 if (function_exists('wp_remote_post')) {
988
989 $args = [
990 'body' => $payload,
991 'timeout' => '60',
992 'sslverify' => false,
993 'headers' => [
994 'Content-Type:application/json',
995 'Content-Type' => 'application/json',
996 'Accept: application/json',
997 'source: WORDPRESS',
998 ],
999 ];
1000
1001 if (isset($auth_token)) {
1002 $auth = "Bearer " . $auth_token;
1003 $args['headers'] = array_merge($args['headers'], ["Authorization" => $auth]);
1004 }
1005
1006 $response = wp_remote_post($api_url, $args);
1007 $response = wp_remote_retrieve_body($response);
1008 $response = json_decode($response, true);
1009
1010 }
1011 else {
1012 $error = 'WP_REMOTE_POST_NOT_EXIST';
1013 }
1014
1015 // Checking if there are errors in the response.
1016 if (isset($response['errors'][0]['message'])) {
1017 $message = WebTotem::messageForHuman($response['errors'][0]['message']);
1018 if (stripos($response['errors'][0]['message'], "INVALID_TOKEN") !== FALSE && !$repeat) {
1019 $response = self::auth($api_key);
1020 if ($response === 'success') {
1021 return self::sendRequest($payload, $token, TRUE);
1022 }
1023 }
1024 elseif(stripos($response['errors'][0]['message'], "USERHOST_NOT_BELONG_TO_USER") !== FALSE){
1025 if(WebTotem::isMultiSite()){
1026 WebTotemOption::clearAllHosts();
1027 WebTotemOption::clearOptions([ 'host_id', 'host_name' ]);
1028 } else {
1029 WebTotemOption::clearOptions([ 'host_id', 'host_name' ]);
1030 }
1031 }
1032 else {
1033 WebTotemOption::setNotification('error', $message);
1034 }
1035 }
1036
1037 if (!empty($error)) {
1038 WebTotemOption::setNotification('error', $error);
1039 }
1040
1041 return $response;
1042 }
1043
1044 }
1045