Browse Source

refactor: new KMS check model

dev
Dnomd343 3 years ago
parent
commit
511d4b07d5
  1. 5
      .env.example
  2. 2
      functions/Curl.php
  3. 2
      functions/DNS.php
  4. 4
      functions/SqliteDB.php
  5. 354
      models/kmsCheck.php
  6. 11
      models/ntpCheck.php
  7. 4
      models/punycode.php

5
.env.example

@ -14,8 +14,9 @@ REDIS_PREFIX=tgbot
# IP Info # IP Info
ECHOIP_HOST=ip.343.re ECHOIP_HOST=ip.343.re
# KMS Check # KMS Server
KMS_API=https://kms.343.re/ KMS_HOST=kms.343.re
KMS_VLMCS=/usr/bin/vlmcs
# ChinaZ API # ChinaZ API
ICP_KEY= ICP_KEY=

2
functions/Curl.php

@ -1,6 +1,6 @@
<?php <?php
class Curl { class Curl { // Curl模拟http请求
public $ua = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.131 Safari/537.36 Edg/92.0.902.67'; public $ua = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.131 Safari/537.36 Edg/92.0.902.67';
public function get($url, $timeOut = 30) { // curl模拟Get 默认30s超时 public function get($url, $timeOut = 30) { // curl模拟Get 默认30s超时

2
functions/DNS.php

@ -1,6 +1,6 @@
<?php <?php
class DNS { class DNS { // DNS解析功能
public function resolveA($domain) { // DNS解析A记录 public function resolveA($domain) { // DNS解析A记录
$ipAddr = array(); $ipAddr = array();
$rs = dns_get_record(strtolower($domain), DNS_A); $rs = dns_get_record(strtolower($domain), DNS_A);

4
functions/SqliteDB.php

@ -2,10 +2,10 @@
class SqliteDB extends SQLite3 { // Sqlite3数据库 class SqliteDB extends SQLite3 { // Sqlite3数据库
public function __construct($filename) { public function __construct($filename) {
$this->open($filename); $this->open($filename); // 打开数据库连接
} }
public function __destruct() { public function __destruct() {
$this->close(); $this->close(); // 关闭数据库连接
} }
} }

354
models/kmsCheck.php

@ -1,16 +1,16 @@
<?php <?php
class kmsKeys { class kmsKeys { // KMS密钥获取
private $kmsDB = './db/kmsKeys.db'; // KMS密钥数据库 private $db, $kmsDB = './db/kmsKeys.db'; // KMS密钥数据库
private function getVersionName($type, $version_id) { // 获取对应版本的名称
$db = new SqliteDB($this->kmsDB); private function getVersionName($type, $versionId) { // 获取对应版本的名称
$res = $db->query('SELECT * FROM `' . $type . '_version` WHERE version_id=' . $version_id . ';'); $res = $this->db->query('SELECT * FROM `' . $type . '_version` WHERE version_id=' . $versionId . ';');
return $res->fetchArray(SQLITE3_ASSOC)['version_name']; return $res->fetchArray(SQLITE3_ASSOC)['version_name'];
} }
private function getKmsKeys($type) { // 获取所有版本的KMS密钥 private function getKmsKeys($type) { // 获取指定类型的密钥信息 win/win-server
$db = new SqliteDB($this->kmsDB); $this->db = new SqliteDB($this->kmsDB);
$res = $db->query('SELECT * FROM `' . $type . '`;'); $res = $this->db->query('SELECT * FROM `' . $type . '`;');
while ($row = $res->fetchArray(SQLITE3_ASSOC)) { while ($row = $res->fetchArray(SQLITE3_ASSOC)) {
$index = $row['version']; $index = $row['version'];
unset($row['version']); unset($row['version']);
@ -19,110 +19,101 @@ class kmsKeys {
return $data; return $data;
} }
public function getKeys($type) { // 获取指定类型KMS密钥 public function getKeys($type) { // 获取指定类型的各版本及KMS密钥
switch ($type) { switch ($type) {
case '': case '': // win和win-server系列
return $this->getKmsKeys('win') + $this->getKmsKeys('win-server'); return $this->getKmsKeys('win') + $this->getKmsKeys('win-server');
case 'win': case 'win': // win系列
return $this->getKmsKeys('win'); return $this->getKmsKeys('win');
case 'win-server': case 'win-server': // win-server系列
return $this->getKmsKeys('win-server'); return $this->getKmsKeys('win-server');
default: default:
return array(); return array(); // 未知类型 返回空数组
} }
} }
} }
class kmsCheck { class kmsCheck { // KMS服务器检查
private $api; 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() { public function isCache($server) { // 检查KMS服务器是否已缓存
global $env; $redis = new RedisCache('kms');
$this->api = $env['KMS_API']; $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; $server = $host . ':' . $port;
$redis = new redisCache('kms'); $status = $redis->getData($server);
$info = $redis->getData($server); // 查询缓存数据 if (!$status) { // 缓存未命中
if (!$info) { // 缓存未命中 if ($this->getKmsStatus($host, $port)) { // 测试服务器状态
$url = $this->api . 'check?host=' . $host . '&port=' . $port; $status = [ 'status' => 'online' ]; // 服务正常
$info = json_decode(file_get_contents($url), true); // 请求上游接口 } else {
$info['server'] = $server; $status = [ 'status' => 'offline' ]; // 服务掉线
switch ($info['status']) {
case 'ok':
$info['online'] = true;
break;
case 'error':
$info['online'] = false;
break;
default:
return array(
'status' => 'error',
'message' => 'Server error'
);
} }
$info['status'] = 'ok'; $redis->setData($server, json_encode($status), 300); // 缓存5min
unset($info['message']);
$redis->setData($server, json_encode($info), 300); // 缓存5min
} else { // 缓存命中 } else { // 缓存命中
$info = json_decode($info, true); // 使用缓存数据 $status = json_decode($status, true); // 使用缓存数据
} }
return $info; return $status;
} }
} }
class kmsCheckEntry { class kmsCheckEntry { // KMS功能入口
private function isHost($host) { // 判断host是否合法 private function formatCheck($server) { // 输入参数格式检查
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) {
$temp = explode(':', $server); $temp = explode(':', $server);
if (count($temp) === 1) { // 不带:的请求 if (count($temp) === 1) { // 不带:的请求
if ($this->isHost($temp[0])) { if (!(new Domain)->isHost($temp[0])) { return null; } // 错误请求
$host = $server; return array(
$port = 1688; 'host' => $temp[0],
} else { 'port' => 1688
return array( );
'status' => 'error',
'message' => 'Illegal host'
);
}
} else if (count($temp) === 2) { // 带一个:的请求 } else if (count($temp) === 2) { // 带一个:的请求
if ($this->isHost($temp[0])) { if (!(new Domain)->isHost($temp[0])) { return null; } // 错误请求
$host = $temp[0]; if ($temp[1] < 0 || $temp[1] > 65535) { return null; } // 错误请求
} else {
return array(
'status' => 'error',
'message' => 'Illegal host'
);
}
$port = $temp[1];
if ($port < 0 || $port > 65535) {
return array(
'status' => 'error',
'message' => 'Illegal port'
);
}
} else { // 带多个:的请求
return array( return array(
'status' => 'error', 'host' => $temp[0],
'message' => 'Illegal request' 'port' => $temp[1]
); );
} else { // 带多个:的请求
return null; // 错误请求
} }
return array( }
'status' => 'ok',
'host' => $host, private function genMessage($server, $status) { // 生成KMS状态消息
'port' => $port $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) { // 简化版本名称 private function simpStr($str) { // 简化版本名称
@ -130,17 +121,41 @@ class kmsCheckEntry {
return implode('', $match[0]); 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); $kmsKeys = (new kmsKeys)->getKeys($type);
foreach ($kmsKeys as $version => $kmsKey) { foreach ($kmsKeys as $version => $kmsKey) {
$buttons[] = array([ // 生成按钮列表 $buttons[] = array([ // 生成按钮列表
'text' => $version, 'text' => $version,
'callback_data' => '/kms ' . $this->simpStr($version) 'callback_data' => '/kms ' . $type . '|' . $this->simpStr($version)
]); ]);
} }
$buttons[] = array([ $buttons[] = array([
'text' => '<< Go back <<', 'text' => '<< Go back <<',
'callback_data' => '/kms keys' 'callback_data' => '/kms menu' // 加入返回按钮
]); ]);
return array( return array(
'text' => 'Which version did you need?', 'text' => 'Which version did you need?',
@ -150,122 +165,91 @@ class kmsCheckEntry {
); );
} }
private function getKmsKeys($targetVersion) { // 显示指定版本的KMS密钥列表 private function genActiveCmd() { // 生成KMS激活命令
$kmsKeys = (new kmsKeys)->getKeys(''); $kmsHost = $GLOBALS['env']['KMS_HOST'];
foreach ($kmsKeys as $version => $kmsKey) { // 比对压缩以后的名称 $actiCmd = '```' . PHP_EOL . 'slmgr /upk' . PHP_EOL . 'slmgr /ipk {KMS_KEY}' . PHP_EOL;
if ($this->simpStr($version) === $targetVersion) { break; } // 匹配成功 $actiCmd .= 'slmgr /skms ' . $kmsHost . PHP_EOL . 'slmgr /ato' . PHP_EOL . 'slmgr /dlv';
} $actiCmd .= PHP_EOL . '```';
$msg = '*' . $version . ' KMS Keys*' . PHP_EOL . PHP_EOL;
foreach ($kmsKey as $row) {
$msg .= $row['name'] . ':`' . $row['key'] . '`' . PHP_EOL . PHP_EOL;
}
return array( return array(
'text' => $actiCmd,
'parse_mode' => 'Markdown', '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服务器状态 private function genSelectMsg() { // 生成KMS版本选择消息
$content = (new kmsCheck)->kmsStatus($host, $port); return array(
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(
'text' => 'Which one did you need?', 'text' => 'Which one did you need?',
'reply_markup' => json_encode(array( 'reply_markup' => json_encode(array(
'inline_keyboard' => array( 'inline_keyboard' => array( // 功能选择按钮
array([ array([
'text' => 'Windows', 'text' => 'Windows',
'callback_data' => '/kms win' 'callback_data' => '/kms win' // Windows密钥
]), ]),
array([ array([
'text' => 'Windows Server', 'text' => 'Windows Server',
'callback_data' => '/kms win-server' 'callback_data' => '/kms win-server' // Windows Server密钥
]), ]),
array([ array([
'text' => 'Activation Command', '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) { switch ($rawParam) {
case 'keys': case 'menu': // 选择菜单
tgApi::editMessage(array( $message = $this->genSelectMsg();
'message_id' => $tgEnv['messageId'], break;
) + $selectMsg); case 'cmd': // KMS激活命令
return; $message = $this->genActiveCmd();
case 'cmd': break;
tgApi::editMessage(array( case 'win': // Windows激活密钥
'message_id' => $tgEnv['messageId'], case 'win-server': // Windows Server激活密钥
'parse_mode' => 'Markdown', $message = $this->genKmsVersions($rawParam);
'text' => $actiCmd, break;
'reply_markup' => json_encode(array( default:
'inline_keyboard' => array([[ $message = $this->genKmsKeys($rawParam); // 显示密钥列表
'text' => '<< Go back <<',
'callback_data' => '/kms keys'
]])
))
));
return;
case 'win':
case 'win-server':
tgApi::editMessage(array(
'message_id' => $tgEnv['messageId'],
) + $this->getKmsVersions($rawParam));
return;
} }
tgApi::editMessage(array( tgApi::editMessage(array(
'message_id' => $tgEnv['messageId'] 'message_id' => $messageId // 修改源消息内容
) + $this->getKmsKeys($rawParam)); ) + $message);
} }
} }

11
models/ntpCheck.php

@ -1,17 +1,16 @@
<?php <?php
class ntpServer { // 获取NTP服务器列表 class ntpServer { // 获取NTP服务器列表
private $ntpDB = './db/ntpServer.db'; // NTP服务器数据库 private $db, $ntpDB = './db/ntpServer.db'; // NTP服务器数据库
private function getListName($listId) { // 获取对应组的名称 private function getListName($listId) { // 获取对应组的名称
$db = new SqliteDB($this->ntpDB); $res = $this->db->query('SELECT * FROM `ntp_list` WHERE id=' . $listId . ';');
$res = $db->query('SELECT * FROM `ntp_list` WHERE id=' . $listId . ';');
return $res->fetchArray(SQLITE3_ASSOC)['name']; return $res->fetchArray(SQLITE3_ASSOC)['name'];
} }
public function getList() { // 获取所有NTP服务器地址 public function getList() { // 获取所有NTP服务器地址
$db = new SqliteDB($this->ntpDB); $this->db = new SqliteDB($this->ntpDB);
$res = $db->query('SELECT * FROM `ntp_host`;'); $res = $this->db->query('SELECT * FROM `ntp_host`;');
while ($row = $res->fetchArray(SQLITE3_ASSOC)) { while ($row = $res->fetchArray(SQLITE3_ASSOC)) {
$index = $row['list_id']; $index = $row['list_id'];
unset($row['list_id']); unset($row['list_id']);
@ -210,7 +209,7 @@ class ntpCheckEntry { // NTP功能入口
private function sendNtpStatus($host) { // 检查并发送NTP服务器状态 private function sendNtpStatus($host) { // 检查并发送NTP服务器状态
if ((new ntpCheck)->isCache($host)) { // 状态已缓存 if ((new ntpCheck)->isCache($host)) { // 状态已缓存
$servers = (new ntpCheck)->ntpStatus($host); $servers = (new ntpCheck)->ntpStatus($host);
tgApi::sendMarkdown($this->genMessage($host, $servers)); // 查询并发送 tgApi::sendMarkdown($this->genMessage($host, $servers)); // 发送服务器状态
return; return;
} }
$message = tgApi::sendMarkdown('`' . $host . '`' . PHP_EOL . 'NTP Server Checking...'); $message = tgApi::sendMarkdown('`' . $host . '`' . PHP_EOL . 'NTP Server Checking...');

4
models/punycode.php

@ -1,6 +1,6 @@
<?php <?php
class punycodeEntry { class punycodeEntry { // Punycode编码转换入口
private function checkErr($punycode) { // 处理Punycode库错误警告 private function checkErr($punycode) { // 处理Punycode库错误警告
if ($punycode->errFlag) { if ($punycode->errFlag) {
return array( return array(
@ -41,7 +41,7 @@ class punycodeEntry {
} }
} }
if (isset($errMsg)) { // 存在警告 if (isset($errMsg)) { // 存在警告
if (substr($rawParam, 0, 1) !== '.' && substr($rawParam, -1) !== '.') { // 首尾不为. if (substr($rawParam, 0, 1) !== '.' && substr($rawParam, -1) !== '.') { // 首尾不为.时发送警告内容
$msg .= '*Warning:* ' . $errMsg; $msg .= '*Warning:* ' . $errMsg;
} }
} }

Loading…
Cancel
Save