PluginProbe
WebTotem Security / 2.2.3
WebTotem Security v2.2.3
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 / library / WT.php

WT.php in WebTotem Security 2.2.3, at library/WT.php

403 lines 23.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php defined('ABSPATH') or die("Protected By WT!");
2
3
4 class WTSEC_LIBRARY_WT
5 {
6
7 const URL = "https://api.wtotem.com/graphql";
8 // const URL = "https://api-1.2ke2xgwx4.wtotem.com/graphql";
9 // const URL = "https://api.webtotem.kz/graphql";
10
11 public static function auth($key)
12 {
13 $payload = '{"query":"mutation{ guest{ apiKeys{ auth(apiKey:\"' . $key . '\"),{ token{ value,refreshToken,expiresIn } } } } }"}';
14 return self::requestApi($payload);
15 }
16
17 protected static function requestApi($payload, $token = false, $repeat = false)
18 {
19 if ($token) {
20 $token = WTSEC_LIBRARY_App::getToken();
21 }
22 $args = [
23 'body' => $payload,
24 'timeout' => '60',
25 'sslverify' => false,
26 'headers' => ['Content-Type:application/json', 'Content-Type' => 'application/json', 'source:WORDPRESS', 'Accept: application/json'],
27 ];
28 if (!is_null($token) && $token) {
29 $authorization = "Bearer " . $token;
30 $args['headers'] = array_merge($args['headers'], ["Authorization" => $authorization]);
31 }
32 $response = wp_remote_post(self::URL, $args);
33 $httpcode = wp_remote_retrieve_response_code($response);
34
35 if ($httpcode < 200) {
36 WTSEC_LIBRARY_Session::setNotification("error", WTSEC_LIBRARY_Localization::lmsg('could_not_connect_to_the_server'));
37 }
38 $response = wp_remote_retrieve_body($response);
39 $result = json_decode($response, true);
40 if (isset($result['errors'][0]['message'])) {
41 $message = self::diffMesageForHuman($result['errors'][0]['message']);
42 if (stripos($result['errors'][0]['message'], "token") !== false && !$repeat) {
43 $result = WTSEC_LIBRARY_WT::auth(wtsec_app()->get("api_key"));
44 if (isset($result['data']['guest']['apiKeys']['auth']['token']['value'])) {
45 $token_ = $result['data']['guest']['apiKeys']['auth']['token']['value'];
46 WTSEC_LIBRARY_App::login($token_);
47 return self::requestApi($payload, $token, true);
48 } else {
49 WTSEC_LIBRARY_App::logout();
50 }
51 } else {
52 if ($message !== false) {
53
54 WTSEC_LIBRARY_Session::setNotification("warning", $payload);
55 }
56 }
57 }
58 return $result;
59 }
60
61 public static function diffMesageForHuman($message)
62 {
63 $definition = $message;
64 $excepts = [
65 "RESOURCE_NOT_FOUND", "DUPLICATE_HOST", "INVALID_CREDENTIALS", "INVALID_API_KEY", "Invalid token",
66 ];
67 if (in_array($message, $excepts)) {
68 return false;
69 }
70 switch ($message) {
71 case 'HOSTS_LIMIT_EXCEEDED':
72 $definition = WTSEC_LIBRARY_Localization::lmsg('hosts_limit_exceed');
73 break;
74 case 'Invalid token':
75 $definition = WTSEC_LIBRARY_Localization::lmsg('invalid_token');
76 break;
77 case 'USER_ALREADY_REGISTERED':
78 $definition = WTSEC_LIBRARY_Localization::lmsg('user_already_exist');
79 break;
80 case 'DUPLICATE_HOST':
81 $definition = WTSEC_LIBRARY_Localization::lmsg('duplicate_host');
82 break;
83 case 'INVALID_DOMAIN_NAME':
84 $definition = WTSEC_LIBRARY_Localization::lmsg('invalid_domain_name');
85 break;
86 }
87 return $definition;
88 }
89
90 //del
91 public static function requestURL($url)
92 {
93 $args = [
94 'timeout' => '30',
95 'sslverify' => false,
96 ];
97 $response = wp_remote_get($url, $args);
98 $httpcode = wp_remote_retrieve_response_code($response);
99 if ($httpcode < 200) {
100 WTSEC_LIBRARY_Session::setNotification("error", WTSEC_LIBRARY_Localization::lmsg('could_not_connect_to_the_server')." requestURL");
101 }
102 $response = wp_remote_retrieve_body($response);
103 return $response;
104 }
105
106
107 public static function getFileByUrl($url, $fileName)
108 {
109 $url = $url.'/'.$fileName;
110 $args = [
111 'timeout' => '30',
112 'sslverify' => false,
113 ];
114 $response = wp_remote_get($url, $args);
115 $httpcode = wp_remote_retrieve_response_code($response);
116 if ($httpcode < 200) {
117 WTSEC_LIBRARY_Session::setNotification("error", WTSEC_LIBRARY_Localization::lmsg('could_not_connect_to_the_server')." getFileByUrl");
118 }
119
120 $response = wp_remote_retrieve_body($response);
121 return ["body" => $response, "filename" => $fileName];
122 }
123
124 public static function getOwnSite($attempt = false)
125 {
126 $payload = '{"query":"query getSites { auth { viewer { sites { ...sites __typename } __typename } __typename }}fragment sites on SiteQueries { list(filter: {}) { edges { node { id hostname title ssl { status __typename } availability { status __typename } reputation { status __typename } ports { status __typename } deface { status __typename } domain { status __typename } antivirus { status __typename } firewall { status __typename } maliciousScript { stack { name __typename } __typename } __typename } __typename } __typename } __typename}"}';
127
128 $result = self::requestApi($payload, true);
129 if (isset($result['data']['auth']['viewer']['sites']['list']['edges'])) {
130 //mutator
131 foreach ($result['data']['auth']['viewer']['sites']['list']['edges'] as &$m) {
132 if (isset($m['node']['hostname'])) {
133 $m['node']['hostname'] = WTSEC_LIBRARY_Idn::idn_to_utf8($m['node']['hostname']);
134 // if ($m['node']['id'] == "c2l0ZV8yNTg=") {
135 // return $m['node'];
136 // }
137 if (self::isSiteUrl($m['node']['hostname'])) {
138 return $m['node'];
139 }
140 }
141 }
142 $add_site = self::addSite(WTSEC_SITE_URL);
143 if (isset($add_site['errors'])) {
144 return $result['data']['node'] = [];
145 } else {
146 if (!$attempt) {
147 return self::getOwnSite(true);
148 }
149 }
150 }
151 return [];
152 }
153
154 public static function isSiteUrl($url)
155 {
156 return WTSEC_LIBRARY_Idn::idn_to_utf8(WTSEC_SITE_URL) === $url;
157 }
158
159 public static function addSite($url)
160 {
161 $payload = '{"variables":{"input":{"title":"' . $url . '","hostname":"' . $url . '","configs":{"scheme":"http","port":80,"wa":{},"dec":{},"ps":{}}}},"query":"mutation ($input: CreateSiteInput) {\n auth {\n sites {\n create(input: $input) {\n id\n hostname\n title\n __typename\n }\n __typename\n }\n __typename\n }\n}\n"}';
162 return self::requestApi($payload, true);
163 }
164
165 public static function getAllChecks($host_id)
166 {
167 $from = time() - (60 * 60 * 24);
168 $to = time();
169 $from_waf = time() - (60 * 60 * 24 * 30);
170 $payload = '{"query":"query($id: ID!, $dateRange: DateRangeInput!) { auth { viewer { sites { one(id: $id) { ports { status ip tcp 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 } status chart(dateRange: $dateRange) { time attacks blocked } report(dateRange: $dateRange) { time attacks ip } } maliciousScript { lastTest { time } status } antivirus { status stats { changed deleted scaned infected error } lastTest { time } isFirstCheck } } } } } }","variables":{"id":"' . $host_id . '","dateRange":{"to":' . $to . ',"from":' . $from_waf . '}}}';
171 // $payload = '{"query":"query($id: ID!, $dateRange:DateRangeInput!) {\n auth {\n viewer {\n sites {\n one(id: $id) {\n ports{\n status\n ip\n tcp\n lastTest{\n time\n }\n }\n availability {\n status\n lastTest {\n time\n }\n responseTime\n downTime(dateRange: $dateRange)\n percent(dateRange: $dateRange)\n }\n deface {\n status\n lastTest {\n time\n }\n words\n count\n }\n domain {\n status\n registrar\n owner\n email\n createdDate\n expiredDate\n }\n ports {\n status\n lastTest {\n time\n }\n ip\n tcp\n country\n }\n ssl {\n status\n daysLeft\n expiryDate\n issueDate\n }\n reputation {\n status\n lastTest {\n time\n }\n virusList {\n viruses\n antiVirus\n }\n }\n firewall {\n lastTest { \n time\n } \n status\n logs{\n edges\n{\n node{\n status\n country\n type\n}\n}\n}\n chart(dateRange: $dateRange) {\n time\n attacks\n blocked\n }\n report(dateRange: $dateRange) {\n time\n attacks\n ip\n }\n }\n maliciousScript{\n lastTest{\n time\n }\n status\n }\n antivirus{\n status \n stats { \n changed\n deleted\n scaned\n infected\n error\n } \n lastTest { \n time\n } \n isFirstCheck\n }\n }\n }\n }\n }\n}","variables":{"id":"' . $host_id . '","dateRange":{"to":' . $to . ',"from":' . $from_waf . '}}}';
172 $response = self::requestApi($payload, true);
173 if (isset($response['data']['auth']['viewer']['sites']['one'])) {
174 return $response['data']['auth']['viewer']['sites']['one'];
175 }
176 return [];
177 }
178
179 public static function changeStatus($config_id, $host_id)
180 {
181 $payload = '{"query":"\n mutation {\n toggleServiceConfig(\n id: ' . $config_id . '\n userhostId: ' . $host_id . '\n ) {\n isActive\n }\n }\n "}';
182 return self::requestApi($payload, true);
183 }
184
185 public static function serviceConnect($id, $service)
186 {
187 $payload = '{"query":"mutation {\n auth {\n agents{\n check(siteId:\"' . $id . '\",service:' . strtolower($service) . ',plugin:WORDPRESS)\n }\n }\n}\n"}';
188 return self::requestApi($payload, true);
189 }
190
191 public static function generateFile($id, $service)
192 {
193 $payload = '{"query":"mutation {\n auth {\n agents{\n generate(siteId:\"' . $id . '\",service:' . strtolower($service) . '){\n agentName\n }\n }\n }\n}\n"}';
194 return self::requestApi($payload, true);
195 }
196
197 public static function generateAmFile($id)
198 {
199 $payload = '{ "operationName":null, "variables":{}, "query":"mutation { auth { am { install(siteId: \"'.$id.'\"){ downloadLink, amFilename, wafFilename, avFilename } } } }"}';
200 return self::requestApi($payload, true);
201 }
202
203 public static function checkStatus($id, $service)
204 {
205 $payload = '{"operationName":null,"variables":{"id":"' . $id . '"},"query":"query ($id: ID!) {\n auth {\n viewer {\n sites {\n one(id: $id) {\n ... on Site {\n configs {\n ... on ' . $service . 'Config {\n isActive\n id\n }\n }\n }\n }\n }\n }\n }\n}\n"}';
206 return self::requestApi($payload, true);
207 }
208
209 public static function getAntivirus($host_id, $limit = 10, $cursor = null, $days = 365, $event = 'infected')
210 {
211 $from = (is_array($days)) ? $days['begin'] : time() - (60 * 60 * 24 * $days);
212 $to = (is_array($days)) ? $days['end'] : time();
213 $cursor = ($cursor == null) ? 'null' : '"' . $cursor . '"';
214 $payload = '{"operationName":null,"variables":{"id":"' . $host_id . '","avLogFilter":{"event":"'.$event.'","dateRange":{"to":'.$to.',"from":'.$from.'},"order":{"direction":"DESC","field":"time"},"pagination":{"first":' . $limit . ',"cursor":' . $cursor . '}}},"query":"query ($id: ID!, $avLogFilter: AvLogFilter!) { auth { viewer { sites { one(id: $id) { id ... on Site { configs { ... on AvConfig { isActive id } } } antivirus { status log(avLogFilter: $avLogFilter) { edges { node { filePath matches event signatures time } } pageInfo { endCursor hasNextPage __typename } } lastTest { time } stats { changed deleted scaned infected } } } } } } }"}';
215 return self::requestApi($payload, true);
216 }
217
218 // public static function getOptions($host_id)
219 // {
220 // $payload = '{"query":"query{\nuserHost(id:' . $host_id . '){\n id\n title\n hostname\n stack\n createdAt\n services {\n id\n name\n configs {\n id\n \tdata\n isActive\n }\n }\n }\n}"}';
221 // return self::requestApi($payload, true);
222 // }
223
224 public static function getConfigs($host_id)
225 {
226 $payload = '{"query":"query{ auth{ viewer{ sites{ one(id:\"'.$host_id.'\"){ configs{ ... on WaConfig { id service isActive } ... on AvConfig { id service isActive } ... on DcConfig { id service isActive } ... on DecConfig { id service isActive } ... on RcConfig { id service isActive } ... on CmsConfig { id service isActive } ... on PsConfig { id service isActive } ... on WafConfig { id service isActive } } } } } } } "}';
227 return self::requestApi($payload, true);
228 }
229
230 public static function toggleConfigs($service_id)
231 {
232 $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 } } } } } "}';
233 return self::requestApi($payload, true);
234 }
235
236 public static function getFirewall($host_id, $limit = 20, $cursor = null, $days = 365)
237 {
238 $from = (is_array($days)) ? $days['begin'] : time() - (60 * 60 * 24 * $days);
239 $to = (is_array($days)) ? $days['end'] : time();
240 $cursor = ($cursor == null) ? 'null' : '"'.$cursor.'"';
241
242 $payload = '{"operationName":"FirewallAttackLog","variables":{"dateRange":{"to":'.$to.',"from":'.$from.'},"id":"'.$host_id.'","wafLogFilter":{"dateRange":{"to":'.$to.',"from":'.$from.'},"order":{"direction":"DESC","field":"time"},"pagination":{"first":'.$limit.',"cursor":' . $cursor . '}}},"query":"query FirewallAttackLog($id: ID!, $wafLogFilter: WafLogFilter!, $dateRange: DateRangeInput!) { auth { viewer { sites { one(id: $id) { firewall { lastTest { time } status... FirewallLogFragment map(dateRange: $dateRange) { attacks, country } __typename } __typename } __typename } __typename } __typename } } fragment FirewallLogFragment on Waf { logs(wafLogFilter: $wafLogFilter) { edges { cursor node { type blocked payload ip location { country { nameEn __typename } __typename } time request status country category __typename } __typename } pageInfo { endCursor hasNextPage __typename } __typename } __typename }"}';
243 $res = self::requestApi($payload, true);
244
245 return $res;
246 }
247
248 public static function getFirewallChart($host_id, $days = 7)
249 {
250 $to = time();
251 $from_waf = ($days <= 1) ? strtotime(date('Y-m-d 00:00:01')) : time() - (60 * 60 * 24 * $days);
252
253 $payload = '{ "query":"query($id: ID!, $dateRange: DateRangeInput!, $wafLogFilter: WafLogFilter!) { auth { viewer { sites { one(id: $id) { firewall { lastTest { time } status logs(wafLogFilter: $wafLogFilter) { edges { node { status country type userAgent } } } chart(dateRange: $dateRange) { time attacks blocked } report(dateRange: $dateRange) { time attacks ip } } } } } } }", "operationName":null,"variables":{"id":"' . $host_id . '","dateRange":{"to":' . $to . ',"from":' . $from_waf . '}, "wafLogFilter": { "dateRange": { "from": ' .$from_waf. ', "to": ' .$to. ' }, "pagination": { "cursor": null }, "order": { "direction": "DESC", "field": "time" } } } }';
254
255 return self::requestApi($payload, true);
256 }
257
258 public static function getStatusIcon($status)
259 {
260 $statuses = [
261 "clean" => [
262 "text" => WTSEC_LIBRARY_Localization::lmsg('statuses.ok'),
263 "color" => self::getColor("success"),
264 "image" => "check-mark.svg"
265 ],
266 "pending" => [
267 "text" => WTSEC_LIBRARY_Localization::lmsg('statuses.pending'),
268 "color" => self::getColor("grey"),
269 "image" => "loading.svg"
270 ],
271 "expired" => [
272 "text" => WTSEC_LIBRARY_Localization::lmsg('statuses.expired'),
273 "color" => self::getColor("orange"),
274 "image" => "warning.svg"
275
276 ],
277 "invalid" => [
278 "text" => WTSEC_LIBRARY_Localization::lmsg('statuses.invalid'),
279 "color" => self::getColor("error"),
280 "image" => "warning.svg"
281 ],
282 "no_cert" => [
283 "text" => WTSEC_LIBRARY_Localization::lmsg('statuses.no_cert'),
284 "color" => self::getColor("orange"),
285 "image" => "warning.svg"
286 ],
287 "error" => [
288 "text" => WTSEC_LIBRARY_Localization::lmsg('statuses.error'),
289 "color" => self::getColor("error"),
290 "image" => "warning.svg"
291 ],
292 "expires" => [
293 "text" => WTSEC_LIBRARY_Localization::lmsg('statuses.expires'),
294 "color" => self::getColor("orange"),
295 "image" => "warning.svg"
296 ],
297 "expires_today" => [
298 "text" => WTSEC_LIBRARY_Localization::lmsg('statuses.expires_today'),
299 "color" => self::getColor("error"),
300 "image" => "warning.svg"
301 ],
302 "down" => [
303 "text" => WTSEC_LIBRARY_Localization::lmsg('statuses.down'),
304 "color" => self::getColor("error"),
305 "image" => "warning.svg"
306 ],
307 "up" => [
308 "text" => WTSEC_LIBRARY_Localization::lmsg('statuses.up'),
309 "color" => self::getColor("success"),
310 "image" => "check-mark.svg"
311 ],
312 "infected" => [
313 "text" => WTSEC_LIBRARY_Localization::lmsg('statuses.infected'),
314 "color" => self::getColor("error"),
315 "image" => "warning.svg"
316 ],
317 "open_ports" => [
318 "text" => WTSEC_LIBRARY_Localization::lmsg('statuses.open'),
319 "color" => self::getColor("orange"),
320 "image" => "warning.svg"
321 ],
322 "deface" => [
323 "text" => WTSEC_LIBRARY_Localization::lmsg('statuses.deface'),
324 "color" => self::getColor("error"),
325 "image" => "warning.svg"
326 ],
327 "modified" => [
328 "text" => WTSEC_LIBRARY_Localization::lmsg('statuses.modified'),
329 "color" => self::getColor("grey"),
330 "image" => "warning.svg"
331 ],
332 "not_supported" => [
333 "text" => WTSEC_LIBRARY_Localization::lmsg('statuses.unsupported'),
334 "color" => self::getColor("orange"),
335 "image" => "warning.svg"
336 ],
337 "not_registered" => [
338 "text" => WTSEC_LIBRARY_Localization::lmsg('statuses.not_registered'),
339 "color" => self::getColor("orange"),
340 "image" => "warning.svg"
341 ],
342 "not_installed" => [
343 "text" => WTSEC_LIBRARY_Localization::lmsg('statuses.not_installed'),
344 "color" => self::getColor("error"),
345 "image" => "warning.svg"
346 ],
347 "working" => [
348 "text" => WTSEC_LIBRARY_Localization::lmsg('statuses.working'),
349 "color" => self::getColor("success"),
350 "image" => "check-mark.svg"
351 ],
352 ];
353 if (isset($statuses[$status])) {
354 return ["image" => $statuses[$status]["image"], "icon" => $statuses[$status]["color"]["icon"], "color" => $statuses[$status]["color"]["color"], "text" => "<span class='" . $statuses[$status]["color"]["color"] . "'>" . $statuses[$status]["text"] . "</span>"];
355 } else {
356 return ["image" => "warning.svg", "icon" => "ww-icon--status_unknow", "color" => "ww--status_unknow", "text" => "<span class='ww--status_unknow'>Unknown status</span>"];
357 }
358 }
359
360 public static function getColor($type)
361 {
362 $types = [
363 "green" => "is--status--ok",
364 "red" => "is--status--error",
365 "success" => "is--status--ok",
366 "error" => "is--status--error",
367 "orange" => "is--status--warning",
368 "warning" => "is--status--warning",
369 "grey" => "ww--status_unknow"
370 ];
371 $icon_types = [
372 "green" => "ww-icon--status_ok",
373 "red" => "ww-icon--status_error",
374 "success" => "ww-icon--status_ok",
375 "error" => "ww-icon--status_error",
376 "orange" => "ww-icon--status_warning",
377 "warning" => "ww-icon--status_warning",
378 "grey" => "ww-icon--status_unknow"
379 ];
380 return ["icon" => $icon_types[$type], "color" => $types[$type]];
381 }
382
383 public static function getConfigId($configs)
384 {
385 $id = 0;
386 $is_active = false;
387 foreach ($configs as &$config) {
388 if (!empty($config)) {
389 $id = $config['id'];
390 $is_active = $config['isActive'];
391 break;
392 }
393 }
394 return compact('id', 'is_active');
395 }
396
397 public static function getScore(){
398 return self::requestURL("https://api.wtotem.com/site/score?url=".WTSEC_SITE_URL);
399 }
400
401 }
402
403