PluginProbe
WebTotem Security / 2.4.16
WebTotem Security v2.4.16
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.16, at lib/API.php

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