PluginProbe
WebTotem Security / 2.2.2
WebTotem Security v2.2.2
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
wt-security / library / WT.php

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

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