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