PluginProbe
WebTotem Security / 2.1.8
WebTotem Security v2.1.8
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.1.8, at library/WT.php

392 lines 23.4 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 const URL = "https://api.wtotem.com/graphql";
7 // const URL = "https://api-1.2ke2xgwx4.wtotem.com/graphql";
8
9 public static function auth($key)
10 {
11 $payload = '{"query":"mutation{\n guest{\n apiKeys{\n auth(apiKey:\"' . $key . '\"),{\n token{\n value,refreshToken,expiresIn\n }\n }\n }\n }\n}"}';
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' => '30',
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')." requestApi");
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)
105 {
106 $args = [
107 'timeout' => '30',
108 'sslverify' => false,
109 ];
110 $response = wp_remote_get($url, $args);
111 $httpcode = wp_remote_retrieve_response_code($response);
112 if ($httpcode < 200) {
113 WTSEC_LIBRARY_Session::setNotification("error", WTSEC_LIBRARY_Localization::lmsg('could_not_connect_to_the_server')." getFileByUrl");
114 }
115 $filename = null;
116 $metas = explode(";",$response['headers']["content-disposition"]);
117 foreach ($metas as $meta){
118 if(stripos($meta,"filename") !== false){
119 $filename = trim(str_replace(["filename=","=","\""],"",$meta));
120 }
121 }
122 $response = wp_remote_retrieve_body($response);
123 return ["body" => $response, "filename" => $filename];
124 }
125
126 public static function getOwnSite($attempt = false)
127 {
128 $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}"}';
129
130 $result = self::requestApi($payload, true);
131 if (isset($result['data']['auth']['viewer']['sites']['list']['edges'])) {
132 //mutator
133 foreach ($result['data']['auth']['viewer']['sites']['list']['edges'] as &$m) {
134 if (isset($m['node']['hostname'])) {
135 $m['node']['hostname'] = WTSEC_LIBRARY_Idn::idn_to_utf8($m['node']['hostname']);
136 // if ($m['node']['id'] == "c2l0ZV8yNTg=") {
137 // return $m['node'];
138 // }
139 if (self::isSiteUrl($m['node']['hostname'])) {
140 return $m['node'];
141 }
142 }
143 }
144 $add_site = self::addSite(WTSEC_SITE_URL);
145 if (isset($add_site['errors'])) {
146 return $result['data']['node'] = [];
147 } else {
148 if (!$attempt) {
149 return self::getOwnSite(true);
150 }
151 }
152 }
153 return [];
154 }
155
156 public static function isSiteUrl($url)
157 {
158 return WTSEC_LIBRARY_Idn::idn_to_utf8(WTSEC_SITE_URL) === $url;
159 }
160
161 public static function addSite($url)
162 {
163 $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"}';
164 return self::requestApi($payload, true);
165 }
166
167 public static function getAllChecks($host_id)
168 {
169 $from = time() - (60 * 60 * 24);
170 $to = time();
171 $from_waf = time() - (60 * 60 * 24 * 7);
172 $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 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 . '}}}';
173 // $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 . '}}}';
174 $response = self::requestApi($payload, true);
175 if (isset($response['data']['auth']['viewer']['sites']['one'])) {
176 return $response['data']['auth']['viewer']['sites']['one'];
177 }
178 return [];
179 }
180
181 public static function changeStatus($config_id, $host_id)
182 {
183 $payload = '{"query":"\n mutation {\n toggleServiceConfig(\n id: ' . $config_id . '\n userhostId: ' . $host_id . '\n ) {\n isActive\n }\n }\n "}';
184 return self::requestApi($payload, true);
185 }
186
187 public static function serviceConnect($id, $service)
188 {
189 $payload = '{"query":"mutation {\n auth {\n agents{\n check(siteId:\"' . $id . '\",service:' . strtolower($service) . ',plugin:WORDPRESS)\n }\n }\n}\n"}';
190 return self::requestApi($payload, true);
191 }
192
193 public static function generateFile($id, $service)
194 {
195 $payload = '{"query":"mutation {\n auth {\n agents{\n generate(siteId:\"' . $id . '\",service:' . strtolower($service) . '){\n agentName\n }\n }\n }\n}\n"}';
196 return self::requestApi($payload, true);
197 }
198
199 public static function generateAmFile($id)
200 {
201 $payload = '{"operationName":null,"variables":{},"query":"mutation {\n auth {\n am {\n install(siteId: \"'.$id.'\")\n }\n }\n}\n"}';
202 return self::requestApi($payload, true);
203 }
204
205 public static function checkStatus($id, $service)
206 {
207 $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"}';
208 return self::requestApi($payload, true);
209 }
210
211
212 public static function getAntivirus($host_id, $limit = 10, $cursor = null, $days = 365, $event = 'infected')
213 {
214 $from = (is_array($days)) ? $days['begin'] : time() - (60 * 60 * 24 * $days);
215 $to = (is_array($days)) ? $days['end'] : time();
216 $cursor = ($cursor == null) ? 'null' : '"' . $cursor . '"';
217 $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 } } } } } } }"}';
218 return self::requestApi($payload, true);
219 }
220
221 public static function getOptions($host_id)
222 {
223 $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}"}';
224 return self::requestApi($payload, true);
225 }
226
227 public static function getFirewall($host_id, $limit = 20, $cursor = null, $days = 365)
228 {
229 $from = (is_array($days)) ? $days['begin'] : time() - (60 * 60 * 24 * $days);
230 $to = (is_array($days)) ? $days['end'] : time();
231 $cursor = ($cursor == null) ? 'null' : '"'.$cursor.'"';
232
233 $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 }"}';
234 $res = self::requestApi($payload, true);
235
236 return $res;
237 }
238
239 public static function getFirewallChart($host_id, $days = 7)
240 {
241 $to = time();
242 $from_waf = ($days <= 1) ? strtotime(date('Y-m-d 00:00:01')) : time() - (60 * 60 * 24 * $days);
243
244 $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" } } } }';
245
246 return self::requestApi($payload, true);
247 }
248
249 public static function getStatusIcon($status)
250 {
251 $statuses = [
252 "clean" => [
253 "text" => WTSEC_LIBRARY_Localization::lmsg('statuses.ok'),
254 "color" => self::getColor("success"),
255 "image" => "check-mark.svg"
256 ],
257 "pending" => [
258 "text" => WTSEC_LIBRARY_Localization::lmsg('statuses.pending'),
259 "color" => self::getColor("grey"),
260 "image" => "loading.svg"
261 ],
262 "expired" => [
263 "text" => WTSEC_LIBRARY_Localization::lmsg('statuses.expired'),
264 "color" => self::getColor("orange"),
265 "image" => "warning.svg"
266
267 ],
268 "invalid" => [
269 "text" => WTSEC_LIBRARY_Localization::lmsg('statuses.invalid'),
270 "color" => self::getColor("error"),
271 "image" => "warning.svg"
272 ],
273 "no_cert" => [
274 "text" => WTSEC_LIBRARY_Localization::lmsg('statuses.no_cert'),
275 "color" => self::getColor("orange"),
276 "image" => "warning.svg"
277 ],
278 "error" => [
279 "text" => WTSEC_LIBRARY_Localization::lmsg('statuses.error'),
280 "color" => self::getColor("error"),
281 "image" => "warning.svg"
282 ],
283 "expires" => [
284 "text" => WTSEC_LIBRARY_Localization::lmsg('statuses.expires'),
285 "color" => self::getColor("orange"),
286 "image" => "warning.svg"
287 ],
288 "expires_today" => [
289 "text" => WTSEC_LIBRARY_Localization::lmsg('statuses.expires_today'),
290 "color" => self::getColor("error"),
291 "image" => "warning.svg"
292 ],
293 "down" => [
294 "text" => WTSEC_LIBRARY_Localization::lmsg('statuses.down'),
295 "color" => self::getColor("error"),
296 "image" => "warning.svg"
297 ],
298 "up" => [
299 "text" => WTSEC_LIBRARY_Localization::lmsg('statuses.up'),
300 "color" => self::getColor("success"),
301 "image" => "check-mark.svg"
302 ],
303 "infected" => [
304 "text" => WTSEC_LIBRARY_Localization::lmsg('statuses.infected'),
305 "color" => self::getColor("error"),
306 "image" => "warning.svg"
307 ],
308 "open_ports" => [
309 "text" => WTSEC_LIBRARY_Localization::lmsg('statuses.open'),
310 "color" => self::getColor("orange"),
311 "image" => "warning.svg"
312 ],
313 "deface" => [
314 "text" => WTSEC_LIBRARY_Localization::lmsg('statuses.deface'),
315 "color" => self::getColor("error"),
316 "image" => "warning.svg"
317 ],
318 "modified" => [
319 "text" => WTSEC_LIBRARY_Localization::lmsg('statuses.modified'),
320 "color" => self::getColor("grey"),
321 "image" => "warning.svg"
322 ],
323 "not_supported" => [
324 "text" => WTSEC_LIBRARY_Localization::lmsg('statuses.unsupported'),
325 "color" => self::getColor("orange"),
326 "image" => "warning.svg"
327 ],
328 "not_registered" => [
329 "text" => WTSEC_LIBRARY_Localization::lmsg('statuses.not_registered'),
330 "color" => self::getColor("orange"),
331 "image" => "warning.svg"
332 ],
333 "not_installed" => [
334 "text" => WTSEC_LIBRARY_Localization::lmsg('statuses.not_installed'),
335 "color" => self::getColor("error"),
336 "image" => "warning.svg"
337 ],
338 "working" => [
339 "text" => WTSEC_LIBRARY_Localization::lmsg('statuses.working'),
340 "color" => self::getColor("success"),
341 "image" => "check-mark.svg"
342 ],
343 ];
344 if (isset($statuses[$status])) {
345 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>"];
346 } else {
347 return ["image" => "warning.svg", "icon" => "ww-icon--status_unknow", "color" => "ww--status_unknow", "text" => "<span class='ww--status_unknow'>Unknown status</span>"];
348 }
349 }
350
351 public static function getColor($type)
352 {
353 $types = [
354 "green" => "is--status--ok",
355 "red" => "is--status--error",
356 "success" => "is--status--ok",
357 "error" => "is--status--error",
358 "orange" => "is--status--warning",
359 "warning" => "is--status--warning",
360 "grey" => "ww--status_unknow"
361 ];
362 $icon_types = [
363 "green" => "ww-icon--status_ok",
364 "red" => "ww-icon--status_error",
365 "success" => "ww-icon--status_ok",
366 "error" => "ww-icon--status_error",
367 "orange" => "ww-icon--status_warning",
368 "warning" => "ww-icon--status_warning",
369 "grey" => "ww-icon--status_unknow"
370 ];
371 return ["icon" => $icon_types[$type], "color" => $types[$type]];
372 }
373
374 public static function getConfigId($configs)
375 {
376 $id = 0;
377 $is_active = false;
378 foreach ($configs as &$config) {
379 if (!empty($config)) {
380 $id = $config['id'];
381 $is_active = $config['isActive'];
382 break;
383 }
384 }
385 return compact('id', 'is_active');
386 }
387
388 public static function getScore(){
389 return self::requestURL("https://api.wtotem.com/site/score?url=".WTSEC_SITE_URL);
390 }
391
392 }