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

456 lines 24.6 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
122 public static function getEmail(){
123 $payload = '{"query":"query { auth { viewer { email __typename } __typename } }"}';
124 $result = self::requestApi($payload, true);
125
126 return $result['data']['auth']['viewer']['email'];
127 }
128
129 public static function getOwnSite($attempt = false)
130 {
131 $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}"}';
132
133 $result = self::requestApi($payload, true);
134 if (isset($result['data']['auth']['viewer']['sites']['list']['edges'])) {
135 //mutator
136 foreach ($result['data']['auth']['viewer']['sites']['list']['edges'] as &$m) {
137 if (isset($m['node']['hostname'])) {
138 $m['node']['hostname'] = WTSEC_LIBRARY_Idn::idn_to_utf8($m['node']['hostname']);
139
140 if (self::isSiteUrl($m['node']['hostname'])) {
141 return $m['node'];
142 }
143 }
144 }
145 $add_site = self::addSite(WTSEC_SITE_URL);
146 if (isset($add_site['errors'])) {
147 return $result['data']['node'] = [];
148 } else {
149 if (!$attempt) {
150 return self::getOwnSite(true);
151 }
152 }
153 }
154 return [];
155 }
156
157 public static function isSiteUrl($url)
158 {
159 return WTSEC_LIBRARY_Idn::idn_to_utf8(WTSEC_SITE_URL) === $url;
160 }
161
162 public static function addSite($url)
163 {
164 $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"}';
165 return self::requestApi($payload, true);
166 }
167
168 public static function getAllChecks($host_id)
169 {
170 $from = time() - (60 * 60 * 24 * 7);
171 $to = time();
172 $from_waf = time() - (60 * 60 * 24 * 30);
173 $language = WTSEC_LANGUAGE;
174 $payload = '{"query":"query($id: ID!, $dateRange: DateRangeInput!, $language: Language!, $dateRangeWeek: 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 } } 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{ statuses{ am{ time } } } antivirus { status stats { changed deleted scaned infected error } lastTest { time } isFirstCheck } } } } } }","variables":{"id":"' . $host_id . '","dateRange":{"to":' . $to . ',"from":' . $from_waf . '}, "dateRangeWeek":{"to":' . $to . ',"from":' . $from . '}, "language":"'.$language.'"}}';
175 $response = self::requestApi($payload, true);
176 if (isset($response['data']['auth']['viewer']['sites']['one'])) {
177 return $response['data']['auth']['viewer']['sites']['one'];
178 }
179 return [];
180 }
181
182 public static function changeStatus($config_id, $host_id)
183 {
184 $payload = '{"query":"\n mutation {\n toggleServiceConfig(\n id: ' . $config_id . '\n userhostId: ' . $host_id . '\n ) {\n isActive\n }\n }\n "}';
185 return self::requestApi($payload, true);
186 }
187
188 public static function serviceConnect($id, $service)
189 {
190 $payload = '{"query":"mutation {\n auth {\n agents{\n check(siteId:\"' . $id . '\",service:' . strtolower($service) . ',plugin:WORDPRESS)\n }\n }\n}\n"}';
191 return self::requestApi($payload, true);
192 }
193
194 public static function generateFile($id, $service)
195 {
196 $payload = '{"query":"mutation {\n auth {\n agents{\n generate(siteId:\"' . $id . '\",service:' . strtolower($service) . '){\n agentName\n }\n }\n }\n}\n"}';
197 return self::requestApi($payload, true);
198 }
199
200 public static function generateAmFile($id)
201 {
202 $payload = '{ "operationName":null, "variables":{}, "query":"mutation { auth { am { install(siteId: \"'.$id.'\"){ downloadLink, amFilename, wafFilename, avFilename } } } }"}';
203 return self::requestApi($payload, true);
204 }
205
206 public static function checkStatus($id, $service)
207 {
208 $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"}';
209 return self::requestApi($payload, true);
210 }
211
212 public static function getAntivirus($host_id, $limit = 10, $cursor = null, $days = 365, $event = 'new')
213 {
214 $from = (is_array($days)) ? $days['from'] : time() - (60 * 60 * 24 * $days);
215 $to = (is_array($days)) ? $days['to'] : 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 permissions permissionsChanged } } pageInfo { endCursor hasNextPage __typename } } lastTest { time } stats { changed deleted scaned infected } } } } } } }"}';
218 return self::requestApi($payload, true);
219 }
220
221 public static function getQuarantineList($host_id)
222 {
223 $payload = '{"query":"query{ auth{ viewer{ sites{ one(id:\"'.$host_id.'\"){ antivirus{ quarantine{ id path date } } } } } } } "}';
224 return self::requestApi($payload, true);
225 }
226
227 public static function moveToQuarantine($host_id, $path)
228 {
229 $payload = '{"query":"mutation{ auth{ sites{ av{ moveToQuarantine(input:{ siteId:\"'.$host_id.'\", path:\"'.$path.'\" }) } } } } "}';
230 return self::requestApi($payload, true);
231 }
232
233 public static function moveFromQuarantine($id)
234 {
235 $payload = '{"query":"mutation{ auth{ sites{ av{ moveFromQuarantine(id: \"'.$id.'\") } } } } "}';
236 return self::requestApi($payload, true);
237 }
238
239 public static function reportsList($host_id, $limit = 10, $cursor = null)
240 {
241 $cursor = ($cursor == null) ? 'null' : '"' . $cursor . '"';
242 $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 } } } } } }"}';
243 return self::requestApi($payload, true);
244 }
245
246 public static function reportGenerate($host_id, $period, $services, $language = "en")
247 {
248 $from = (is_array($period)) ? $period['from'] : time() - (60 * 60 * 24 * $period);
249 $to = (is_array($period)) ? $period['to'] : time();
250 $payload = '{"query":"query ($input: GenerateReportInput) { auth { viewer { reports { generate(input: $input) } } } }", "variables":{ "input": { "siteId": "' . $host_id . '", "from": ' . $from . ', "to": ' . $to . ', "wa": '.$services['wa'].', "dc": '.$services['dc'].', "ps": '.$services['ps'].', "rc": '.$services['rc'].', "sc": '.$services['sc'].', "av": '.$services['av'].', "waf": '.$services['waf'].', "language": "'.$language.'" } } }';
251
252 return self::requestApi($payload, true);
253 }
254
255 public static function reportDownload($id)
256 {
257 $payload = '{"query": "query { auth { viewer { reports { download(id: \"' . $id . '\") } } } }"}';
258 return self::requestApi($payload, true);
259 }
260
261 public static function getConfigs($host_id)
262 {
263 $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 } } } } } } } "}';
264 return self::requestApi($payload, true);
265 }
266
267 public static function toggleConfigs($service_id)
268 {
269 $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 } } } } } "}';
270 return self::requestApi($payload, true);
271 }
272
273 public static function getFirewall($host_id, $limit = 20, $cursor = null, $days = 365)
274 {
275 $from = (is_array($days)) ? $days['from'] : time() - (60 * 60 * 24 * $days);
276 $to = (is_array($days)) ? $days['to'] : time();
277 $cursor = ($cursor == null) ? 'null' : '"'.$cursor.'"';
278
279 $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 }"}';
280 $res = self::requestApi($payload, true);
281
282 return $res;
283 }
284
285 public static function getFirewallChart($host_id, $days = 7)
286 {
287 $to = time();
288 $from_waf = ($days <= 1) ? strtotime(date('Y-m-d 00:00:01')) : time() - (60 * 60 * 24 * $days);
289
290 $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" } } } }';
291 $response = self::requestApi($payload, true);
292 return $response['data']['auth']['viewer']['sites']['one']['firewall']['chart'];
293 }
294
295 public static function getServerStatusChart($host_id, $days = 7)
296 {
297 $to = time();
298 $from = ($days <= 1) ? strtotime(date('Y-m-d 00:00:01')) : time() - (60 * 60 * 24 * $days);
299
300 $payload = '{ "query":"query($id: ID!, $dateRange: DateRangeInput!) { auth { viewer { sites { one(id: $id) { serverStatus { ramChart(dateRange: $dateRange){ total value time } cpuChart(dateRange: $dateRange){ value time } } } } } } }", "variables":{"id":"' . $host_id . '","dateRange":{"to":' . $to . ',"from":' . $from . '} } }';
301
302 $response = self::requestApi($payload, true);
303 return $response['data']['auth']['viewer']['sites']['one']['serverStatus'];
304 }
305
306 public static function getStatusIcon($status)
307 {
308 $statuses = [
309 "clean" => [
310 "text" => WTSEC_LIBRARY_Localization::lmsg('statuses.ok'),
311 "color" => self::getColor("success"),
312 "image" => "check-mark.svg"
313 ],
314 "pending" => [
315 "text" => WTSEC_LIBRARY_Localization::lmsg('statuses.pending'),
316 "color" => self::getColor("grey"),
317 "image" => "loading.svg"
318 ],
319 "pause" => [
320 "text" => WTSEC_LIBRARY_Localization::lmsg('statuses.pause'),
321 "color" => self::getColor("grey"),
322 "image" => "warning.svg"
323 ],
324 "expired" => [
325 "text" => WTSEC_LIBRARY_Localization::lmsg('statuses.expired'),
326 "color" => self::getColor("orange"),
327 "image" => "warning.svg"
328
329 ],
330 "invalid" => [
331 "text" => WTSEC_LIBRARY_Localization::lmsg('statuses.invalid'),
332 "color" => self::getColor("error"),
333 "image" => "warning.svg"
334 ],
335 "no_cert" => [
336 "text" => WTSEC_LIBRARY_Localization::lmsg('statuses.no_cert'),
337 "color" => self::getColor("orange"),
338 "image" => "warning.svg"
339 ],
340 "error" => [
341 "text" => WTSEC_LIBRARY_Localization::lmsg('statuses.error'),
342 "color" => self::getColor("error"),
343 "image" => "warning.svg"
344 ],
345 "expires" => [
346 "text" => WTSEC_LIBRARY_Localization::lmsg('statuses.expires'),
347 "color" => self::getColor("orange"),
348 "image" => "warning.svg"
349 ],
350 "expires_today" => [
351 "text" => WTSEC_LIBRARY_Localization::lmsg('statuses.expires_today'),
352 "color" => self::getColor("error"),
353 "image" => "warning.svg"
354 ],
355 "down" => [
356 "text" => WTSEC_LIBRARY_Localization::lmsg('statuses.down'),
357 "color" => self::getColor("error"),
358 "image" => "warning.svg"
359 ],
360 "up" => [
361 "text" => WTSEC_LIBRARY_Localization::lmsg('statuses.up'),
362 "color" => self::getColor("success"),
363 "image" => "check-mark.svg"
364 ],
365 "infected" => [
366 "text" => WTSEC_LIBRARY_Localization::lmsg('statuses.infected'),
367 "color" => self::getColor("error"),
368 "image" => "warning.svg"
369 ],
370 "open_ports" => [
371 "text" => WTSEC_LIBRARY_Localization::lmsg('statuses.open'),
372 "color" => self::getColor("orange"),
373 "image" => "warning.svg"
374 ],
375 "deface" => [
376 "text" => WTSEC_LIBRARY_Localization::lmsg('statuses.deface'),
377 "color" => self::getColor("error"),
378 "image" => "warning.svg"
379 ],
380 "modified" => [
381 "text" => WTSEC_LIBRARY_Localization::lmsg('statuses.modified'),
382 "color" => self::getColor("grey"),
383 "image" => "warning.svg"
384 ],
385 "not_supported" => [
386 "text" => WTSEC_LIBRARY_Localization::lmsg('statuses.unsupported'),
387 "color" => self::getColor("orange"),
388 "image" => "warning.svg"
389 ],
390 "not_registered" => [
391 "text" => WTSEC_LIBRARY_Localization::lmsg('statuses.not_registered'),
392 "color" => self::getColor("orange"),
393 "image" => "warning.svg"
394 ],
395 "not_installed" => [
396 "text" => WTSEC_LIBRARY_Localization::lmsg('statuses.not_installed'),
397 "color" => self::getColor("error"),
398 "image" => "warning.svg"
399 ],
400 "working" => [
401 "text" => WTSEC_LIBRARY_Localization::lmsg('statuses.working'),
402 "color" => self::getColor("success"),
403 "image" => "check-mark.svg"
404 ],
405 ];
406 if (isset($statuses[$status])) {
407 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>"];
408 } else {
409 return ["image" => "warning.svg", "icon" => "ww-icon--status_unknow", "color" => "ww--status_unknow", "text" => "<span class='ww--status_unknow'>Unknown status</span>"];
410 }
411 }
412
413 public static function getColor($type)
414 {
415 $types = [
416 "green" => "is--status--ok",
417 "red" => "is--status--error",
418 "success" => "is--status--ok",
419 "error" => "is--status--error",
420 "orange" => "is--status--warning",
421 "warning" => "is--status--warning",
422 "grey" => "ww--status_unknow"
423 ];
424 $icon_types = [
425 "green" => "ww-icon--status_ok",
426 "red" => "ww-icon--status_error",
427 "success" => "ww-icon--status_ok",
428 "error" => "ww-icon--status_error",
429 "orange" => "ww-icon--status_warning",
430 "warning" => "ww-icon--status_warning",
431 "grey" => "ww-icon--status_unknow"
432 ];
433 return ["icon" => $icon_types[$type], "color" => $types[$type]];
434 }
435
436 public static function getConfigId($configs)
437 {
438 $id = 0;
439 $is_active = false;
440 foreach ($configs as &$config) {
441 if (!empty($config)) {
442 $id = $config['id'];
443 $is_active = $config['isActive'];
444 break;
445 }
446 }
447 return compact('id', 'is_active');
448 }
449
450 public static function getScore(){
451 return self::requestURL("https://api.wtotem.com/site/score?url=".WTSEC_SITE_URL);
452 }
453
454 }
455
456