From 511d4b07d5051ddeddbcaf800c3063d0d37b92ee Mon Sep 17 00:00:00 2001 From: Dnomd343 Date: Sat, 21 Aug 2021 17:49:03 +0800 Subject: [PATCH] refactor: new KMS check model --- .env.example | 5 +- functions/Curl.php | 2 +- functions/DNS.php | 2 +- functions/SqliteDB.php | 4 +- models/kmsCheck.php | 354 ++++++++++++++++++++--------------------- models/ntpCheck.php | 11 +- models/punycode.php | 4 +- 7 files changed, 183 insertions(+), 199 deletions(-) diff --git a/.env.example b/.env.example index ad9a482..41ac348 100644 --- a/.env.example +++ b/.env.example @@ -14,8 +14,9 @@ REDIS_PREFIX=tgbot # IP Info ECHOIP_HOST=ip.343.re -# KMS Check -KMS_API=https://kms.343.re/ +# KMS Server +KMS_HOST=kms.343.re +KMS_VLMCS=/usr/bin/vlmcs # ChinaZ API ICP_KEY= diff --git a/functions/Curl.php b/functions/Curl.php index 8793280..d7904b0 100644 --- a/functions/Curl.php +++ b/functions/Curl.php @@ -1,6 +1,6 @@ open($filename); + $this->open($filename); // 打开数据库连接 } public function __destruct() { - $this->close(); + $this->close(); // 关闭数据库连接 } } diff --git a/models/kmsCheck.php b/models/kmsCheck.php index 560755b..bedfbe0 100644 --- a/models/kmsCheck.php +++ b/models/kmsCheck.php @@ -1,16 +1,16 @@ kmsDB); - $res = $db->query('SELECT * FROM `' . $type . '_version` WHERE version_id=' . $version_id . ';'); - return $res->fetchArray(SQLITE3_ASSOC)['version_name']; +class kmsKeys { // KMS密钥获取 + private $db, $kmsDB = './db/kmsKeys.db'; // KMS密钥数据库 + + private function getVersionName($type, $versionId) { // 获取对应版本的名称 + $res = $this->db->query('SELECT * FROM `' . $type . '_version` WHERE version_id=' . $versionId . ';'); + return $res->fetchArray(SQLITE3_ASSOC)['version_name']; } - private function getKmsKeys($type) { // 获取所有版本的KMS密钥 - $db = new SqliteDB($this->kmsDB); - $res = $db->query('SELECT * FROM `' . $type . '`;'); + private function getKmsKeys($type) { // 获取指定类型的密钥信息 win/win-server + $this->db = new SqliteDB($this->kmsDB); + $res = $this->db->query('SELECT * FROM `' . $type . '`;'); while ($row = $res->fetchArray(SQLITE3_ASSOC)) { $index = $row['version']; unset($row['version']); @@ -19,110 +19,101 @@ class kmsKeys { return $data; } - public function getKeys($type) { // 获取指定类型KMS密钥 + public function getKeys($type) { // 获取指定类型的各版本及KMS密钥 switch ($type) { - case '': + case '': // win和win-server系列 return $this->getKmsKeys('win') + $this->getKmsKeys('win-server'); - case 'win': + case 'win': // win系列 return $this->getKmsKeys('win'); - case 'win-server': + case 'win-server': // win-server系列 return $this->getKmsKeys('win-server'); default: - return array(); + return array(); // 未知类型 返回空数组 } } } -class kmsCheck { - private $api; +class kmsCheck { // KMS服务器检查 + private function getKmsStatus($host, $port) { // 获取KMS服务器状态 + if(filter_var($host, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) { + $host = '[' . $host . ']'; // IPv6地址需用中括号包围 + } + $cmd = $GLOBALS['env']['KMS_VLMCS'] . ' '; + $cmd .= $host . ':' . $port; // 加入目标服务器信息 + $raw = shell_exec($cmd . ' -G temp'); // 执行vlmcs测试 + preg_match_all('/Sending activation request \(KMS V6\)/', $raw, $match); + return (count($match[0]) === 6) ? true : false; // 返回KMS服务器状态 + } - public function __construct() { - global $env; - $this->api = $env['KMS_API']; + public function isCache($server) { // 检查KMS服务器是否已缓存 + $redis = new RedisCache('kms'); + $status = $redis->getData($server); + return (!$status) ? false : true; } - public function kmsStatus($host, $port) { + public function kmsStatus($host, $port) { // 检测KMS服务器状态 + $redis = new RedisCache('kms'); $server = $host . ':' . $port; - $redis = new redisCache('kms'); - $info = $redis->getData($server); // 查询缓存数据 - if (!$info) { // 缓存未命中 - $url = $this->api . 'check?host=' . $host . '&port=' . $port; - $info = json_decode(file_get_contents($url), true); // 请求上游接口 - $info['server'] = $server; - switch ($info['status']) { - case 'ok': - $info['online'] = true; - break; - case 'error': - $info['online'] = false; - break; - default: - return array( - 'status' => 'error', - 'message' => 'Server error' - ); + $status = $redis->getData($server); + if (!$status) { // 缓存未命中 + if ($this->getKmsStatus($host, $port)) { // 测试服务器状态 + $status = [ 'status' => 'online' ]; // 服务正常 + } else { + $status = [ 'status' => 'offline' ]; // 服务掉线 } - $info['status'] = 'ok'; - unset($info['message']); - $redis->setData($server, json_encode($info), 300); // 缓存5min + $redis->setData($server, json_encode($status), 300); // 缓存5min } else { // 缓存命中 - $info = json_decode($info, true); // 使用缓存数据 + $status = json_decode($status, true); // 使用缓存数据 } - return $info; + return $status; } } -class kmsCheckEntry { - private function isHost($host) { // 判断host是否合法 - preg_match('/^(?=^.{3,255}$)[a-zA-Z0-9][-a-zA-Z0-9]{0,62}(\.[a-zA-Z0-9][-a-zA-Z0-9]{0,62})+$/', $host, $match); - if (count($match) !== 0) { // 域名 - if (!is_numeric(substr($host, -1))) { return true; } // 域名最后一位不为数字 - } - if (filter_var($host, \FILTER_VALIDATE_IP, \FILTER_FLAG_IPV4)) { // IPv4地址 - return true; - } - return false; - } - - private function formatCheck($server) { +class kmsCheckEntry { // KMS功能入口 + private function formatCheck($server) { // 输入参数格式检查 $temp = explode(':', $server); if (count($temp) === 1) { // 不带:的请求 - if ($this->isHost($temp[0])) { - $host = $server; - $port = 1688; - } else { - return array( - 'status' => 'error', - 'message' => 'Illegal host' - ); - } + if (!(new Domain)->isHost($temp[0])) { return null; } // 错误请求 + return array( + 'host' => $temp[0], + 'port' => 1688 + ); } else if (count($temp) === 2) { // 带一个:的请求 - if ($this->isHost($temp[0])) { - $host = $temp[0]; - } else { - return array( - 'status' => 'error', - 'message' => 'Illegal host' - ); - } - $port = $temp[1]; - if ($port < 0 || $port > 65535) { - return array( - 'status' => 'error', - 'message' => 'Illegal port' - ); - } - } else { // 带多个:的请求 + if (!(new Domain)->isHost($temp[0])) { return null; } // 错误请求 + if ($temp[1] < 0 || $temp[1] > 65535) { return null; } // 错误请求 return array( - 'status' => 'error', - 'message' => 'Illegal request' + 'host' => $temp[0], + 'port' => $temp[1] ); + } else { // 带多个:的请求 + return null; // 错误请求 } - return array( - 'status' => 'ok', - 'host' => $host, - 'port' => $port - ); + } + + private function genMessage($server, $status) { // 生成KMS状态消息 + $msg = '`' . $server . '`' . PHP_EOL; + if ($status['status'] === 'online') { + return $msg . 'KMS服务*正常运行*'; // 服务正常 + } else { + return $msg . 'KMS服务*无法使用*'; // 服务异常 + } + } + + private function sendKmsStatus($host, $port) { // 检查并发送KMS服务器状态 + $server = $host . ':' . $port; + if ((new kmsCheck)->isCache($server)) { // 状态已缓存 + $status = (new kmsCheck)->kmsStatus($host, $port); + tgApi::sendMarkdown($this->genMessage($server, $status)); // 发送服务器状态 + return; + } + $message = tgApi::sendMarkdown('`' . $server . '`' . PHP_EOL . 'KMS服务检测中...'); + $messageId = json_decode($message, true)['result']['message_id']; // 未缓存 发送缓冲消息 + $status = (new kmsCheck)->kmsStatus($host, $port); // 发起查询 + tgApi::editMessage(array( // 返回查询结果 + 'parse_mode' => 'Markdown', + 'message_id' => $messageId, + 'text' => $this->genMessage($server, $status) + )); } private function simpStr($str) { // 简化版本名称 @@ -130,17 +121,41 @@ class kmsCheckEntry { return implode('', $match[0]); } - private function getKmsVersions($type) { // 获取win或win-server的版本列表 + private function genKmsKeys($targetVersion) { // 显示指定版本的KMS密钥列表 + $content = explode('|', $targetVersion); + $type = $content[0]; // 获取类型 win/win-server + $targetVersion = $content[1]; // 获取目标版本 + $kmsKeys = (new kmsKeys)->getKeys($type); // 获取该类型的所有版本 + foreach ($kmsKeys as $version => $kmsKey) { // 比对压缩以后的名称 + if ($this->simpStr($version) === $targetVersion) { break; } // 匹配成功 + } + $msg = '*' . $version . ' KMS Keys*' . PHP_EOL . PHP_EOL; + foreach ($kmsKey as $row) { + $msg .= $row['name'] . ':`' . $row['key'] . '`' . PHP_EOL . PHP_EOL; + } + return array( + 'text' => $msg, + 'parse_mode' => 'Markdown', + 'reply_markup' => json_encode(array( // 返回按钮 + 'inline_keyboard' => array([[ + 'text' => '<< Go back <<', + 'callback_data' => '/kms ' . $type + ]]) + )) + ); + } + + private function genKmsVersions($type) { // 获取版本列表 win/win-server $kmsKeys = (new kmsKeys)->getKeys($type); foreach ($kmsKeys as $version => $kmsKey) { $buttons[] = array([ // 生成按钮列表 'text' => $version, - 'callback_data' => '/kms ' . $this->simpStr($version) + 'callback_data' => '/kms ' . $type . '|' . $this->simpStr($version) ]); } $buttons[] = array([ 'text' => '<< Go back <<', - 'callback_data' => '/kms keys' + 'callback_data' => '/kms menu' // 加入返回按钮 ]); return array( 'text' => 'Which version did you need?', @@ -150,122 +165,91 @@ class kmsCheckEntry { ); } - private function getKmsKeys($targetVersion) { // 显示指定版本的KMS密钥列表 - $kmsKeys = (new kmsKeys)->getKeys(''); - foreach ($kmsKeys as $version => $kmsKey) { // 比对压缩以后的名称 - if ($this->simpStr($version) === $targetVersion) { break; } // 匹配成功 - } - $msg = '*' . $version . ' KMS Keys*' . PHP_EOL . PHP_EOL; - foreach ($kmsKey as $row) { - $msg .= $row['name'] . ':`' . $row['key'] . '`' . PHP_EOL . PHP_EOL; - } + private function genActiveCmd() { // 生成KMS激活命令 + $kmsHost = $GLOBALS['env']['KMS_HOST']; + $actiCmd = '```' . PHP_EOL . 'slmgr /upk' . PHP_EOL . 'slmgr /ipk {KMS_KEY}' . PHP_EOL; + $actiCmd .= 'slmgr /skms ' . $kmsHost . PHP_EOL . 'slmgr /ato' . PHP_EOL . 'slmgr /dlv'; + $actiCmd .= PHP_EOL . '```'; return array( + 'text' => $actiCmd, 'parse_mode' => 'Markdown', - 'text' => $msg + 'reply_markup' => json_encode(array( // 返回按钮 + 'inline_keyboard' => array([[ + 'text' => '<< Go back <<', + 'callback_data' => '/kms menu' + ]]) + )) ); } - private function checkKms($host, $port) { // 检查KMS服务器状态 - $content = (new kmsCheck)->kmsStatus($host, $port); - if ($content['status'] === 'ok') { - if ($content['online'] === true) { - return array( - 'parse_mode' => 'Markdown', - 'text' => '`' . $content['server'] . '`' . PHP_EOL . 'KMS服务*正常运行*' - ); - } else { - return array( - 'parse_mode' => 'Markdown', - 'text' => '`' . $content['server'] . '`' . PHP_EOL . 'KMS服务*无法使用*' - ); - } - } else { - return array( - 'text' => $content['message'] - ); - } - } - - public function query($rawParam) { // kmsCheck查询入口 - if ($rawParam == '' || $rawParam === 'help') { // 显示使用说明 - tgApi::sendMessage(array( - 'parse_mode' => 'Markdown', - 'text' => '*Usage:* `/kms IP/Domain[:port]`', - 'reply_markup' => json_encode(array( // 获取KMS密钥按钮 - 'inline_keyboard' => array([[ - 'text' => 'Get KMS Keys', - 'callback_data' => '/kms keys' - ]]) - )) - )); - return; - } - $check = $this->formatCheck($rawParam); - if ($check['status'] === 'error') { // 输入格式有误 - tgApi::sendText($check['message']); - return; - } - $message = tgApi::sendMarkdown('`' . $rawParam . '`' . PHP_EOL . 'KMS服务检测中...'); - $message = json_decode($message, true); - fastcgi_finish_request(); // 断开连接 - tgApi::editMessage(array( - 'message_id' => $message['result']['message_id'], - ) + $this->checkKms($check['host'], $check['port'])); // 发起查询并返回结果 - } - - public function callback($rawParam) { // kmsCheck回调入口 - global $tgEnv; - $selectMsg = array( + private function genSelectMsg() { // 生成KMS版本选择消息 + return array( 'text' => 'Which one did you need?', 'reply_markup' => json_encode(array( - 'inline_keyboard' => array( + 'inline_keyboard' => array( // 功能选择按钮 array([ 'text' => 'Windows', - 'callback_data' => '/kms win' + 'callback_data' => '/kms win' // Windows密钥 ]), array([ 'text' => 'Windows Server', - 'callback_data' => '/kms win-server' + 'callback_data' => '/kms win-server' // Windows Server密钥 ]), array([ 'text' => 'Activation Command', - 'callback_data' => '/kms cmd' + 'callback_data' => '/kms cmd' // 激活命令 ]) ) )) ); - $actiCmd = '```' . PHP_EOL . 'slmgr /upk' . PHP_EOL . 'slmgr /ipk {KMS_KEY}' . PHP_EOL; - $actiCmd .= 'slmgr /skms {KMS_HOST}' . PHP_EOL . 'slmgr /ato' . PHP_EOL . 'slmgr /dlv'; - $actiCmd .= PHP_EOL . '```'; + } + + private function sendHelp() { // 发送使用说明 + $helpMessage = array( + 'parse_mode' => 'Markdown', + 'text' => '*Usage:* `/kms IP/Domain[:port]`', + 'reply_markup' => json_encode(array( // 加入 获取KMS密钥 按钮 + 'inline_keyboard' => array([[ + 'text' => 'Get KMS Keys', + 'callback_data' => '/kms menu' + ]]) + )) + ); + tgApi::sendMessage($helpMessage); + } + + public function query($rawParam) { // KMS测试查询入口 + if ($rawParam == '' || $rawParam === 'help') { // 显示使用说明 + $this->sendHelp(); + return; + } + $server = $this->formatCheck($rawParam); + if ($server === null) { + tgApi::sendText('Illegal request'); // 输入格式错误 + return; + } + $this->sendKmsStatus($server['host'], $server['port']); // 检查并发送KMS服务器状态 + } + + public function callback($rawParam) { // KMS测试回调入口 + $messageId = $GLOBALS['tgEnv']['messageId']; switch ($rawParam) { - case 'keys': - tgApi::editMessage(array( - 'message_id' => $tgEnv['messageId'], - ) + $selectMsg); - return; - case 'cmd': - tgApi::editMessage(array( - 'message_id' => $tgEnv['messageId'], - 'parse_mode' => 'Markdown', - 'text' => $actiCmd, - 'reply_markup' => json_encode(array( - 'inline_keyboard' => array([[ - 'text' => '<< Go back <<', - 'callback_data' => '/kms keys' - ]]) - )) - )); - return; - case 'win': - case 'win-server': - tgApi::editMessage(array( - 'message_id' => $tgEnv['messageId'], - ) + $this->getKmsVersions($rawParam)); - return; + case 'menu': // 选择菜单 + $message = $this->genSelectMsg(); + break; + case 'cmd': // KMS激活命令 + $message = $this->genActiveCmd(); + break; + case 'win': // Windows激活密钥 + case 'win-server': // Windows Server激活密钥 + $message = $this->genKmsVersions($rawParam); + break; + default: + $message = $this->genKmsKeys($rawParam); // 显示密钥列表 } tgApi::editMessage(array( - 'message_id' => $tgEnv['messageId'] - ) + $this->getKmsKeys($rawParam)); + 'message_id' => $messageId // 修改源消息内容 + ) + $message); } } diff --git a/models/ntpCheck.php b/models/ntpCheck.php index 1359e81..c48f994 100644 --- a/models/ntpCheck.php +++ b/models/ntpCheck.php @@ -1,17 +1,16 @@ ntpDB); - $res = $db->query('SELECT * FROM `ntp_list` WHERE id=' . $listId . ';'); + $res = $this->db->query('SELECT * FROM `ntp_list` WHERE id=' . $listId . ';'); return $res->fetchArray(SQLITE3_ASSOC)['name']; } public function getList() { // 获取所有NTP服务器地址 - $db = new SqliteDB($this->ntpDB); - $res = $db->query('SELECT * FROM `ntp_host`;'); + $this->db = new SqliteDB($this->ntpDB); + $res = $this->db->query('SELECT * FROM `ntp_host`;'); while ($row = $res->fetchArray(SQLITE3_ASSOC)) { $index = $row['list_id']; unset($row['list_id']); @@ -210,7 +209,7 @@ class ntpCheckEntry { // NTP功能入口 private function sendNtpStatus($host) { // 检查并发送NTP服务器状态 if ((new ntpCheck)->isCache($host)) { // 状态已缓存 $servers = (new ntpCheck)->ntpStatus($host); - tgApi::sendMarkdown($this->genMessage($host, $servers)); // 查询并发送 + tgApi::sendMarkdown($this->genMessage($host, $servers)); // 发送服务器状态 return; } $message = tgApi::sendMarkdown('`' . $host . '`' . PHP_EOL . 'NTP Server Checking...'); diff --git a/models/punycode.php b/models/punycode.php index 1c4d7ae..9dabd8c 100644 --- a/models/punycode.php +++ b/models/punycode.php @@ -1,6 +1,6 @@ errFlag) { return array( @@ -41,7 +41,7 @@ class punycodeEntry { } } if (isset($errMsg)) { // 存在警告 - if (substr($rawParam, 0, 1) !== '.' && substr($rawParam, -1) !== '.') { // 首尾不为. + if (substr($rawParam, 0, 1) !== '.' && substr($rawParam, -1) !== '.') { // 首尾不为.时发送警告内容 $msg .= '*Warning:* ' . $errMsg; } }