PluginProbe
WebTotem Security / 2.4.14
WebTotem Security v2.4.14
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.14, at lib/API.php

988 lines 35.6 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 return $response['data']['auth']['am']['installMultisite'];
226 }
227 else {
228 $payload = '{"query":"mutation { auth { am { install(siteId: \"' . $host_id . '\"){ downloadLink, amFilename, wafFilename, avFilename } } } }"}';
229 $response = self::sendRequest($payload, TRUE);
230 return $response['data']['auth']['am']['install'];
231 }
232 }
233
234 /**
235 * Add secondary MultiSite host.
236 *
237 * @param $new_sites
238 * An array with sites to add.
239 *
240 * @return void.
241 */
242 public static function addMultiSiteNewSites($new_sites){
243 // Host id of the main site in MultiSite network.
244 $main_host = WebTotemOption::getMainHost();
245
246 foreach ($new_sites as $site){
247 $all_sites = self::getSites(null, 0);
248 $host = self::addSite($site, $all_sites);
249 if(key_exists('id', $host)){
250 $payload = '{"query":"mutation { auth { am { addMultisiteHost(mainSiteId: \"' . $main_host['id'] . '\", siteId: \"' . $host['id'] . '\") } } }"}';
251
252 $result = self::sendRequest($payload, TRUE);
253 if(!$result['errors'][0]['message']){
254 WebTotemOption::setNotification( 'info', __('A new website has been added: ', 'wtotem') . $site);
255 }
256 }
257 }
258 }
259
260 /**
261 * Remove secondary MultiSite host.
262 *
263 * @param $host_id
264 * Host id on WebTotem.
265 *
266 * @return bool
267 * Returns result removing host.
268 */
269 public static function removeMultiSiteHost($host_id){
270 $payload = '{"query":"mutation { auth { am { removeMultisiteHost(siteId: \"' . $host_id . '\") } } }"}';
271 $response = self::sendRequest($payload, TRUE);
272 return $response['data']['auth']['am']['removeSecondaryMultisiteHost'];
273 }
274
275 /**
276 * Method to get agents (AM, WAF, AV) statuses.
277 *
278 * @param string $host_id
279 * Host id on WebTotem.
280 *
281 * @return array
282 * Returns agents statuses data.
283 */
284 public static function getAgentsStatusesFromAPI($host_id) {
285 $payload = '{"query":"query ($id: ID!) { auth { viewer { sites { one(id: $id) { agentManager { statuses { am { status } av { status } waf { status } } } } } } } }", "variables":{"id":"' . $host_id . '"}}';
286 $response = self::sendRequest($payload, TRUE);
287
288 if (isset($response['data']['auth']['viewer']['sites']['one']['agentManager']['statuses'])) {
289 return $response['data']['auth']['viewer']['sites']['one']['agentManager']['statuses'];
290 }
291
292 return [];
293 }
294
295 /**
296 * Method to get user time zone.
297 *
298 * @return string|bool
299 * Returns time zone data.
300 */
301 public static function getTimeZone() {
302 $payload = '{"query":"query { auth { viewer{ timezone } } } "}';
303 $response = self::sendRequest($payload, TRUE);
304
305 if (isset($response['data']['auth']['viewer']['timezone'])) {
306 return $response['data']['auth']['viewer']['timezone'];
307 }
308 return FALSE;
309 }
310
311 /**
312 * Method for get all the site security data.
313 *
314 * @param string $host_id
315 * Host id on WebTotem.
316 * @param int|array $days
317 * For what period data is needed.
318 *
319 * @return array
320 * Returns all data.
321 */
322 public static function getAllData($host_id, $days = 7) {
323 $language = WebTotem::getLanguage();
324 $period = WebTotem::getPeriod($days);
325
326 $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 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 . '"}}';
327 $response = self::sendRequest($payload, TRUE);
328
329 if (isset($response['data']['auth']['viewer']['sites']['one'])) {
330 return $response['data']['auth']['viewer']['sites']['one'];
331 }
332
333 return [];
334 }
335
336 /**
337 * Method to get firewall data.
338 *
339 * @param string $host_id
340 * Host id on WebTotem.
341 * @param int $limit
342 * Limit on the number of records.
343 * @param string $cursor
344 * Mark for loading data.
345 * @param int|array $days
346 * For what period data is needed.
347 *
348 * @return array
349 * Returns firewall data.
350 */
351 public static function getFirewall($host_id, $limit = 20, $cursor = NULL, $days = 365) {
352 $period = WebTotem::getPeriod($days);
353 $cursor = ($cursor == NULL) ? 'null' : '"' . $cursor . '"';
354
355 $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 . '}}} }';
356 $response = self::sendRequest($payload, TRUE);
357
358 if (isset($response['data']['auth']['viewer']['sites']['one'])) {
359 return $response['data']['auth']['viewer']['sites']['one'];
360 }
361
362 return [];
363 }
364
365 /**
366 * Method to get firewall chart data.
367 *
368 * @param string $host_id
369 * Host id on WebTotem.
370 * @param int $days
371 * For what period data is needed.
372 *
373 * @return array
374 * Returns firewall chart data.
375 */
376 public static function getFirewallChart($host_id, $days = 7) {
377 $period = WebTotem::getPeriod($days);
378
379 $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'] . '} } }';
380 $response = self::sendRequest($payload, TRUE);
381
382 if (isset($response['data']['auth']['viewer']['sites']['one']['firewall'])) {
383 return $response['data']['auth']['viewer']['sites']['one']['firewall'];
384 }
385
386 return [];
387 }
388
389 /**
390 * Method to set firewall settings.
391 *
392 * @param string $host_id
393 * Host id on WebTotem.
394 * @param array $settings
395 * User-specified settings.
396 *
397 * @return array
398 * Returns information whether the request was successful.
399 */
400 public static function setFirewallSettings($host_id, array $settings) {
401 $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 } } } } }"}';
402 return self::sendRequest($payload, TRUE);
403 }
404
405 /**
406 * Method to get antivirus data.
407 *
408 * @param array $params
409 * Parameters for filtering data.
410 *
411 * @return array
412 * Returns antivirus data.
413 */
414 public static function getAntivirus(array $params) {
415
416 $cursor = ($params['cursor']) ? '"' . $params['cursor'] . '"' : 'null';
417 $event = ($params['event']) ? '"' . $params['event'] . '"' : '"new"';
418 $permissions = ($params['permissions']) ? ' "permissionsChanged":true, ' : '';
419 $period = WebTotem::getPeriod($params['days']);
420
421 $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 } } } } } } }"}';
422 $response = self::sendRequest($payload, TRUE);
423
424 if (isset($response['data']['auth']['viewer']['sites']['one']['antivirus'])) {
425 return $response['data']['auth']['viewer']['sites']['one']['antivirus'];
426 }
427 return [];
428 }
429
430 /**
431 * Method to get antivirus last test.
432 *
433 * @param string $host_id
434 * Host id on WebTotem.
435 *
436 * @return array
437 * Returns antivirus last test data.
438 */
439 public static function getAntivirusLastTest($host_id) {
440
441 $payload = '{"variables":{"id":"' . $host_id . '"},"query":"query ($id: ID!) { auth { viewer { sites { one(id: $id) { antivirus { status lastTest { time } } } } } } }"}';
442 $response = self::sendRequest($payload, TRUE);
443
444 if (isset($response['data']['auth']['viewer']['sites']['one']['antivirus'])) {
445 return $response['data']['auth']['viewer']['sites']['one']['antivirus'];
446 }
447 return [];
448 }
449
450 /**
451 * Method to force check services.
452 *
453 * @param string $host_id
454 * Host id on WebTotem.
455 * @param string $service
456 * Service that needs to be checked.
457 *
458 * @return array
459 * Returns information whether the request was successful.
460 */
461 public static function forceCheck($host_id, $service) {
462 $payload = '{"variables":{"id":"' . $host_id . '","service":"' . $service . '"},"query":"mutation ($id: ID!, $service: ForceCheckService!) { auth { sites { forceCheck(siteId: $id, service: $service) } } }"} ';
463 return self::sendRequest($payload, TRUE);
464 }
465
466 /**
467 * Method to export antivirus report.
468 *
469 * @param string $host_id
470 * Host id on WebTotem.
471 * @param int|array $days
472 * For what period data is needed.
473 *
474 * @return array
475 * Returns information whether the request was successful.
476 */
477 public static function avExport($host_id, $days = 30) {
478 $period = WebTotem::getPeriod($days);
479 $payload = '{"variables":{ "input":{"siteId":"' . $host_id . '", "dateRange":{"to":' . $period['to'] . ',"from":' . $period['from'] . '} }},"query":"mutation ($input: AvLogExportInput!) { auth { sites { av { export(input: $input) } } } }"} ';
480 return self::sendRequest($payload, TRUE);
481 }
482
483 /**
484 * Method to get quarantine data.
485 *
486 * @param string $host_id
487 * Host id on WebTotem.
488 *
489 * @return array
490 * Returns quarantine data.
491 */
492 public static function getQuarantineList($host_id) {
493 $payload = '{"query":"query{ auth{ viewer{ sites{ one(id:\"' . $host_id . '\"){ antivirus{ quarantine{ id path date } } } } } } } "}';
494 $response = self::sendRequest($payload, TRUE);
495
496 if (isset($response['data']['auth']['viewer']['sites']['one']['antivirus']['quarantine'])) {
497 return $response['data']['auth']['viewer']['sites']['one']['antivirus']['quarantine'];
498 }
499 return [];
500 }
501
502 /**
503 * Method to move file to quarantine.
504 *
505 * @param string $host_id
506 * Host id on WebTotem.
507 * @param string $path
508 * Path to the file.
509 *
510 * @return array
511 * Returns information whether the request was successful.
512 */
513 public static function moveToQuarantine($host_id, $path) {
514 $payload = '{"query":"mutation{ auth{ sites{ av{ moveToQuarantine(input:{ siteId:\"' . $host_id . '\", path:\"' . $path . '\" }) } } } } "}';
515 return self::sendRequest($payload, TRUE);
516 }
517
518 /**
519 * Method to move file from quarantine.
520 *
521 * @param string $id
522 * Id assigned to the file.
523 *
524 * @return array
525 * Returns information whether the request was successful.
526 */
527 public static function moveFromQuarantine($id) {
528 $payload = '{"query":"mutation{ auth{ sites{ av{ moveFromQuarantine(id: \"' . $id . '\") } } } } "}';
529 return self::sendRequest($payload, TRUE);
530 }
531
532 /**
533 * Method to get server status data.
534 *
535 * @param string $host_id
536 * Host id on WebTotem.
537 * @param int|array $days
538 * For what period data is needed.
539 *
540 * @return array
541 * Returns server status data.
542 */
543 public static function getServerStatusData($host_id, $days = 7) {
544 $period = WebTotem::getPeriod($days);
545 $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'] . '} } }';
546
547 $response = self::sendRequest($payload, TRUE);
548
549 if (isset($response['data']['auth']['viewer']['sites']['one']['serverStatus'])) {
550 return $response['data']['auth']['viewer']['sites']['one']['serverStatus'];
551 }
552
553 return [];
554 }
555
556 /**
557 * Method to remove port from ignore list.
558 *
559 * @param string $host_id
560 * Host id on WebTotem.
561 * @param string $port
562 * User specified port.
563 *
564 * @return array
565 * Returns information whether the request was successful.
566 */
567 public static function removeIgnorePort($host_id, $port) {
568 $payload = '{"variables":{ "input": { "siteId": "' . $host_id . '", "port":' . $port . '} },"query":"mutation($input: IgnorePortInput!) { auth { sites { ps { removeIgnorePort(input: $input) } } } }"} ';
569 return self::sendRequest($payload, TRUE);
570 }
571
572 /**
573 * Method to add port to ignore list.
574 *
575 * @param string $host_id
576 * Host id on WebTotem.
577 * @param string $port
578 * User specified port.
579 *
580 * @return array
581 * Returns information whether the request was successful.
582 */
583 public static function addIgnorePort($host_id, $port) {
584 $payload = '{"variables":{ "input": { "siteId": "' . $host_id . '", "port":' . (int) $port . '} },"query":"mutation($input: IgnorePortInput!) { auth { sites { ps { addIgnorePort(input: $input) } } } }"} ';
585 return self::sendRequest($payload, TRUE);
586 }
587
588 /**
589 * Method to get all ports list.
590 *
591 * @param string $host_id
592 * Host id on WebTotem.
593 *
594 * @return array
595 * Returns ports data.
596 */
597 public static function getAllPortsList($host_id) {
598 $payload = '{"query":"query($id: ID!) { auth { viewer { sites { one(id: $id) { ports { status ip tcp ignorePorts lastTest { time } } } } } } } ","variables":{"id":"' . $host_id . '"}}';
599
600 $response = self::sendRequest($payload, TRUE);
601
602 if (isset($response['data']['auth']['viewer']['sites']['one']['ports'])) {
603 return $response['data']['auth']['viewer']['sites']['one']['ports'];
604 }
605
606 return [];
607 }
608
609 /**
610 * Method to get all reports.
611 *
612 * @param string $host_id
613 * Host id on WebTotem.
614 * @param int $limit
615 * Limit on the number of records.
616 * @param string $cursor
617 * Mark for loading data.
618 *
619 * @return array
620 * Returns reports data.
621 */
622 public static function getAllReports($host_id, $limit = 10, $cursor = NULL) {
623 $cursor = ($cursor == NULL) ? 'null' : '"' . $cursor . '"';
624 $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 } } } } } }"}';
625 $response = self::sendRequest($payload, TRUE);
626
627 if (isset($response['data']['auth']['viewer']['reports']['list']['edges'])) {
628 return $response['data']['auth']['viewer']['reports']['list'];
629 }
630
631 return [];
632 }
633
634 /**
635 * Method to generate report.
636 *
637 * @param string $host_id
638 * Host id on WebTotem.
639 * @param int|array $days
640 * For what period data is needed.
641 * @param array $services
642 * User-specified module settings.
643 *
644 * @return string|bool
645 * Returns report download link.
646 */
647 public static function generateReport($host_id, $days, array $services) {
648 $period = WebTotem::getPeriod($days);
649 $language = WebTotem::getLanguage();
650
651 $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 . '" } } }';
652 $response = self::sendRequest($payload, TRUE);
653
654 if (isset($response['data']['auth']['viewer']['reports']['generate'])) {
655 return $response['data']['auth']['viewer']['reports']['generate'];
656 }
657
658 return FALSE;
659 }
660
661 /**
662 * Method to download report.
663 *
664 * @param string $id
665 * Assigned to the report.
666 *
667 * @return string|bool
668 * Returns report download link.
669 */
670 public static function downloadReport($id) {
671 $payload = '{"query": "query { auth { viewer { reports { download(id: \"' . $id . '\") } } } }"}';
672 $response = self::sendRequest($payload, TRUE);
673
674 if (isset($response['data']['auth']['viewer']['reports']['download'])) {
675 return $response['data']['auth']['viewer']['reports']['download'];
676 }
677
678 return FALSE;
679 }
680
681 /**
682 * Method to get configs data.
683 *
684 * @param string $host_id
685 * Host id on WebTotem.
686 *
687 * @return array|bool
688 * Returns configs data.
689 */
690 public static function getConfigs($host_id) {
691 $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 } } } } } } } "}';
692 $response = self::sendRequest($payload, TRUE);
693
694 if (isset($response['data']['auth']['viewer']['sites']['one']['configs'])) {
695 return $response['data']['auth']['viewer']['sites']['one']['configs'];
696 }
697
698 return FALSE;
699 }
700
701 /**
702 * Method to toggle modules config.
703 *
704 * @param string $service_id
705 * Service id that we enable or disable.
706 *
707 * @return string|bool
708 * Returns information whether the request was successful.
709 */
710 public static function toggleConfigs($service_id) {
711 $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 } } } } } "}';
712 $response = self::sendRequest($payload, TRUE);
713
714 if (isset($response['data']['auth']['configs']['toggle'])) {
715 return $response['data']['auth']['configs']['toggle'];
716 }
717
718 return FALSE;
719 }
720
721 /**
722 * Method to toggle modules notification.
723 *
724 * @param string $host_id
725 * Host id on WebTotem.
726 * @param string $service
727 * Service id in which we enable or disable notifications.
728 *
729 * @return string|bool
730 * Returns information whether the request was successful.
731 */
732 public static function toggleNotifications($host_id, $service) {
733 $payload = '{"query":"mutation{ auth{ sites{ toggleNotifications(siteId: \"' . $host_id . '\", service: ' . $service . ') } } }"}';
734 $response = self::sendRequest($payload, TRUE);
735
736 if (isset($response['data']['auth']['sites']['toggleNotifications'])) {
737 return $response;//['data']['auth']['sites']['toggleNotifications'];
738 }
739
740 return FALSE;
741 }
742
743 /**
744 * Method to get allow/deny ip list.
745 *
746 * @param string $host_id
747 * Host id on WebTotem.
748 *
749 * @return array|bool
750 * Returns ip allow/deny lists.
751 */
752 public static function getIpLists($host_id) {
753 $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 } } } } } } }"} ';
754 $response = self::sendRequest($payload, TRUE);
755
756 if (isset($response['data']['auth']['viewer']['sites']['one']['firewall'])) {
757 return $response['data']['auth']['viewer']['sites']['one']['firewall'];
758 }
759
760 return [];
761 }
762
763 /**
764 * Method to add ip to allow/deny list.
765 *
766 * @param string $host_id
767 * Host id on WebTotem.
768 * @param string $ips
769 * Ip address list.
770 * @param string $list
771 * Allow or deny list.
772 *
773 * @return bool
774 * Returns information whether the request was successful.
775 */
776 public static function addIpToList($host_id, $ips, $list) {
777
778 if ($ips) {
779 $ips = WebTotem::convertIpListForApi($ips);
780 $payload = '{"variables":{ "input": { "siteId": "' . $host_id . '", "ips": ' . $ips . ', "color": "' . $list . '" } }, "query":"mutation($input: WafListInput!) { auth { sites { waf { addToList(input: $input){ status invalidIPs} } } } }"} ';
781 $response = self::sendRequest($payload, TRUE);
782
783 if (isset($response['data']['auth']['sites']['waf']['addToList'])) {
784 return $response['data']['auth']['sites']['waf']['addToList'];
785 }
786 }
787
788 return FALSE;
789 }
790
791 /**
792 * Method to remove ip from allow/deny list by id.
793 *
794 * @param string $id
795 * Id assignment to ip address.
796 *
797 * @return bool
798 * Returns information whether the request was successful.
799 */
800 public static function removeIpFromList($id) {
801 $payload = '{"variables":{ "id": "' . $id . '" },"query":"mutation($id: ID!) { auth { sites { waf { removeFromList(id: $id) } } } }"} ';
802 $response = self::sendRequest($payload, TRUE);
803
804 if (isset($response['data']['auth']['sites']['waf']['removeFromList'])) {
805 return $response['data']['auth']['sites']['waf']['removeFromList'];
806 }
807
808 return FALSE;
809 }
810
811 /**
812 * Method to get allow url list.
813 *
814 * @param string $host_id
815 * Host id on WebTotem.
816 *
817 * @return array
818 * Returns url allow lists.
819 */
820 public static function getAllowUrlList($host_id) {
821 $payload = '{"query":"query { auth { viewer { sites { one(id: \"' . $host_id . '\"){ firewall{ urlWhiteList{ id url createdAt } } } } } } }"} ';
822 $response = self::sendRequest($payload, TRUE);
823
824 if (isset($response['data']['auth']['viewer']['sites']['one']['firewall']['urlWhiteList'])) {
825 return $response['data']['auth']['viewer']['sites']['one']['firewall']['urlWhiteList'];
826 }
827
828 return [];
829 }
830
831 /**
832 * Method to add url to allow list.
833 *
834 * @param string $host_id
835 * Host id on WebTotem.
836 * @param string $url
837 * User-specified url.
838 *
839 * @return bool|string
840 * Returns information whether the request was successful.
841 */
842 public static function addUrlToAllowList($host_id, $url) {
843 $payload = '{"variables":{ "input": { "siteId": "' . $host_id . '", "url": "' . $url . '" } }, "query":"mutation($input: WafUrlWhiteListInput!) { auth { sites { waf { addToUrlWhiteList(input: $input) } } } }"} ';
844 $response = self::sendRequest($payload, TRUE);
845
846 if (isset($response['data']['auth']['sites']['waf']['addToUrlWhiteList'])) {
847 return $response['data']['auth']['sites']['waf']['addToUrlWhiteList'];
848 }
849
850 return FALSE;
851 }
852
853 /**
854 * Method to remove url from allow list.
855 *
856 * @param string $id
857 * Id assignment to url address.
858 *
859 * @return bool|string
860 * Returns information whether the request was successful.
861 */
862 public static function removeUrlFromAllowList($id) {
863 $payload = '{"variables":{ "id": "' . $id . '" }, "query":"mutation($id: ID!) { auth { sites { waf { removeFromUrlWhiteList(id: $id) } } } }"} ';
864 $response = self::sendRequest($payload, TRUE);
865
866 if (isset($response['data']['auth']['sites']['waf']['removeFromUrlWhiteList'])) {
867 return $response['data']['auth']['sites']['waf']['removeFromUrlWhiteList'];
868 }
869
870 return FALSE;
871 }
872
873 /**
874 * Method to get user's email.
875 *
876 * @return string
877 * Returns user's email.
878 */
879 public static function getEmail(){
880 $payload = '{"query":"query { auth { viewer { email __typename } __typename } }"}';
881 $response = self::sendRequest($payload, true);
882
883 return $response['data']['auth']['viewer']['email'];
884 }
885
886 /**
887 * Function sends GraphQL request to API server.
888 *
889 * @param string $payload
890 * Payload to be sent to API server.
891 * @param bool $token
892 * Whether a token is needed when sending a request.
893 * @param bool $repeat
894 * Required to avoid recursion.
895 *
896 * @return array
897 * Returns response from WebTotem API.
898 */
899 protected static function sendRequest($payload, $token = FALSE, $repeat = FALSE) {
900
901 $api_key = WebTotemOption::getOption('api_key');
902
903 // Remote URL where the public WebTotem API service is running.
904 $api_url = WebTotemOption::getOption('api_url');
905 if(!$api_url){
906 $api_url = self::getApiUrl('P');
907 WebTotemOption::setOptions(['api_url' => $api_url]);
908 }
909
910 // Checking whether a token is needed.
911 if ($token) {
912 $auth_token = WebTotemOption::getOption('auth_token');
913 $auth_token_expired = WebTotemOption::getOption('auth_token_expired');
914
915 // Checking whether the token has expired.
916 if ($auth_token_expired <= time() && !$repeat) {
917 $result = self::auth($api_key);
918 if ($result === 'success') {
919 return self::sendRequest($payload, $token, TRUE);
920 }
921 else {
922 if(isset($result['errors'])){
923 $message = WebTotem::messageForHuman($result['errors'][0]['message']);
924 WebTotemOption::setNotification('error', $message);
925 }
926 }
927 }
928 }
929
930 if (function_exists('wp_remote_post')) {
931
932 $args = [
933 'body' => $payload,
934 'timeout' => '60',
935 'sslverify' => false,
936 'headers' => [
937 'Content-Type:application/json',
938 'Content-Type' => 'application/json',
939 'Accept: application/json',
940 'source: WORDPRESS',
941 ],
942 ];
943
944 if (isset($auth_token)) {
945 $auth = "Bearer " . $auth_token;
946 $args['headers'] = array_merge($args['headers'], ["Authorization" => $auth]);
947 }
948
949 $response = wp_remote_post($api_url, $args);
950 $response = wp_remote_retrieve_body($response);
951 $response = json_decode($response, true);
952
953 }
954 else {
955 $error = 'WP_REMOTE_POST_NOT_EXIST';
956 }
957
958 // Checking if there are errors in the response.
959 if (isset($response['errors'][0]['message'])) {
960 $message = WebTotem::messageForHuman($response['errors'][0]['message']);
961 if (stripos($response['errors'][0]['message'], "INVALID_TOKEN") !== FALSE && !$repeat) {
962 $response = self::auth($api_key);
963 if ($response === 'success') {
964 return self::sendRequest($payload, $token, TRUE);
965 }
966 }
967 elseif(stripos($response['errors'][0]['message'], "USERHOST_NOT_BELONG_TO_USER") !== FALSE){
968 if(WebTotem::isMultiSite()){
969 WebTotemOption::clearAllHosts();
970 WebTotemOption::clearOptions([ 'host_id', 'host_name' ]);
971 } else {
972 WebTotemOption::clearOptions([ 'host_id', 'host_name' ]);
973 }
974 }
975 else {
976 WebTotemOption::setNotification('error', $message);
977 }
978 }
979
980 if (!empty($error)) {
981 WebTotemOption::setNotification('error', $error);
982 }
983
984 return $response;
985 }
986
987 }
988