diff --git a/app/common.php b/app/common.php index c4fe7a3..8c148a6 100644 --- a/app/common.php +++ b/app/common.php @@ -180,6 +180,11 @@ function checkIfActive($string) { return null; } +function checkDomain($domain){ + if(empty($domain) || !preg_match('/^[-$a-z0-9_*.]{2,512}$/i', $domain) || (stripos($domain, '.') === false) || substr($domain, -1) == '.' || substr($domain, 0 ,1) == '.' || substr($domain, 0 ,1) == '*' && substr($domain, 1 ,1) != '.' || substr_count($domain, '*')>1 || strpos($domain, '*')>0 || strlen($domain)<4) return false; + return true; +} + function errorlog($msg){ $handle = fopen(app()->getRootPath()."record.txt", 'a'); fwrite($handle, date('Y-m-d H:i:s')."\t".$msg."\r\n"); @@ -224,4 +229,69 @@ function pemToBase64($pem){ } } return $encoded; +} + +function makeSelfSignSSL(string $commonName, array $domainList, $validity = 3650){ + // 加载 CA 证书和私钥 + $dir = app()->getBasePath().'script/'; + $caCert = file_get_contents($dir.'ca.crt'); + $caPrivateKey = file_get_contents($dir.'ca.key'); + + $opensslConfigFile = sys_get_temp_dir().'/openssl'.time().mt_rand(1000, 9999).'.cnf'; + $opensslConfigContent = << 2048, + 'private_key_type' => OPENSSL_KEYTYPE_RSA, + ]); + if(!$domainPrivateKey) return false; + + $csrConfig = ['digest_alg' => 'sha256', 'config' => $opensslConfigFile]; + + $domainCsr = openssl_csr_new([ + 'commonName' => $commonName + ], $domainPrivateKey, $csrConfig); + if(!$domainCsr) return false; + + // 生成域名证书 + $domainCertificate = openssl_csr_sign($domainCsr, $caCert, $caPrivateKey, $validity, $csrConfig); + if(!$domainCertificate) return false; + + // 导出域名证书 + openssl_x509_export($domainCertificate, $certificate); + openssl_pkey_export($domainPrivateKey, $privateKey); + $certificate .= $caCert; + + unlink($opensslConfigFile); + + return ['cert' => $certificate, 'key' => $privateKey]; } \ No newline at end of file diff --git a/app/controller/Admin.php b/app/controller/Admin.php index de74655..b0f393e 100644 --- a/app/controller/Admin.php +++ b/app/controller/Admin.php @@ -400,4 +400,37 @@ class Admin extends BaseController Cache::clear(); return json(['code'=>0,'msg'=>'succ']); } + + public function ssl(){ + if(request()->isAjax()){ + $domain_list = input('post.domain_list', null, 'trim'); + $common_name = input('post.common_name', null, 'trim'); + $validity = input('post.validity/d'); + if(empty($domain_list) || empty($validity)){ + return json(['code'=>-1, 'msg'=>'参数不能为空']); + } + $array = explode("\n", $domain_list); + $domain_list = []; + foreach($array as $domain){ + $domain = trim($domain); + if(empty($domain)) continue; + if(!checkDomain($domain)) return json(['code'=>-1, 'msg'=>'域名或IP格式不正确:'.$domain]); + $domain_list[] = $domain; + } + if(empty($domain_list)) return json(['code'=>-1, 'msg'=>'域名列表不能为空']); + if(empty($common_name)) $common_name = $domain_list[0]; + $result = makeSelfSignSSL($common_name, $domain_list, $validity); + if(!$result){ + return json(['code'=>-1, 'msg'=>'生成证书失败']); + } + return json(['code'=>0, 'msg'=>'生成证书成功', 'cert'=>$result['cert'], 'key'=>$result['key']]); + } + + $dir = app()->getBasePath().'script/'; + $ssl_path = app()->getRootPath().'public/ssl/baota_root.pfx'; + $ssl_path_mac = app()->getRootPath().'public/ssl/baota_root.crt'; + $isca = file_exists($dir.'ca.crt') && file_exists($dir.'ca.key') && file_exists($ssl_path) && file_exists($ssl_path_mac); + View::assign('isca', $isca); + return view(); + } } \ No newline at end of file diff --git a/app/controller/Api.php b/app/controller/Api.php index f6e1093..64d5143 100644 --- a/app/controller/Api.php +++ b/app/controller/Api.php @@ -464,4 +464,31 @@ class Api extends BaseController fclose($handle); return json(['status'=>false, 'msg'=>'不支持当前操作']); } + + //生成自签名SSL证书 + public function bt_cert(){ + $data = input('post.data'); + $param = json_decode($data, true); + if(!$param || !isset($param['domain'])) return json(['status'=>false, 'msg'=>'参数错误']); + + $dir = app()->getBasePath().'script/'; + $ssl_path = app()->getRootPath().'public/ssl/baota_root.pfx'; + $isca = file_exists($dir.'ca.crt') && file_exists($dir.'ca.key') && file_exists($ssl_path); + if(!$isca) return json(['status'=>false, 'msg'=>'CA证书不存在']); + + $domain = $param['domain']; + if(empty($domain)) return json(['status'=>false, 'msg'=>'域名不能为空']); + $domain_list = explode(',', $domain); + foreach($domain_list as $d){ + if(!checkDomain($d)) return json(['status'=>false, 'msg'=>'域名或IP格式不正确:'.$d]); + } + $common_name = $domain_list[0]; + $validity = 3650; + $result = makeSelfSignSSL($common_name, $domain_list, $validity); + if(!$result){ + return json(['status'=>false, 'msg'=>'生成证书失败']); + } + $ca_pfx = base64_encode(file_get_contents($ssl_path)); + return json(['status'=>true, 'msg'=>'生成证书成功', 'cert'=>$result['cert'], 'key'=>$result['key'], 'pfx'=>$ca_pfx, 'password'=>'']); + } } \ No newline at end of file diff --git a/app/lib/Btapi.php b/app/lib/Btapi.php index 56de844..c494666 100644 --- a/app/lib/Btapi.php +++ b/app/lib/Btapi.php @@ -1,243 +1,243 @@ -BT_PANEL = $bt_panel; - $this->BT_KEY = $bt_key; - } - - //获取面板配置信息 - public function get_config(){ - $url = $this->BT_PANEL.'/config?action=get_config'; - - $p_data = $this->GetKeyData(); - - $result = $this->curl($url,$p_data); - - $data = json_decode($result,true); - return $data; - } - - //获取已登录用户信息 - public function get_user_info(){ - $url = $this->BT_PANEL.'/plugin?action=a&name=kaixin&s=get_user_info'; - - $p_data = $this->GetKeyData(); - - $result = $this->curl($url,$p_data); - - $data = json_decode($result,true); - return $data; - } - - //从云端获取插件列表 - public function get_plugin_list(){ - $url = $this->BT_PANEL.'/plugin?action=a&name=kaixin&s=get_plugin_list'; - - $p_data = $this->GetKeyData(); - - $result = $this->curl($url,$p_data); - - $data = json_decode($result,true); - return $data; - } - - //下载插件包,返回文件路径 - public function get_plugin_filename($plugin_name, $version){ - $url = $this->BT_PANEL.'/plugin?action=a&name=kaixin&s=download_plugin'; - - $p_data = $this->GetKeyData(); - $p_data['plugin_name'] = $plugin_name; - $p_data['version'] = $version; - - $result = $this->curl($url,$p_data); - - $data = json_decode($result,true); - return $data; - } - - //下载插件主程序文件,返回文件路径 - public function get_plugin_main_filename($plugin_name, $version){ - $url = $this->BT_PANEL.'/plugin?action=a&name=kaixin&s=download_plugin_main'; - - $p_data = $this->GetKeyData(); - $p_data['plugin_name'] = $plugin_name; - $p_data['version'] = $version; - - $result = $this->curl($url,$p_data); - - $data = json_decode($result,true); - return $data; - } - - //解密插件主程序py代码,返回文件路径 - public function get_decode_plugin_main($plugin_name, $version){ - $url = $this->BT_PANEL.'/plugin?action=a&name=kaixin&s=decode_plugin_main'; - - $p_data = $this->GetKeyData(); - $p_data['plugin_name'] = $plugin_name; - $p_data['version'] = $version; - - $result = $this->curl($url,$p_data); - - $data = json_decode($result,true); - return $data; - } - - //下载插件其他文件,返回文件路径 - public function get_plugin_other_filename($fname){ - $url = $this->BT_PANEL.'/plugin?action=a&name=kaixin&s=download_plugin_other'; - - $p_data = $this->GetKeyData(); - $p_data['fname'] = $fname; - - $result = $this->curl($url,$p_data); - - $data = json_decode($result,true); - return $data; - } - - //下载文件 - public function download($filename, $localpath){ - $url = $this->BT_PANEL.'/download'; - - $p_data = $this->GetKeyData(); - $p_data['filename'] = $filename; - - $result = $this->curl_download($url.'?'.http_build_query($p_data), $localpath); - - return $result; - } - - //获取文件base64 - public function get_file($filename){ - $url = $this->BT_PANEL.'/plugin?action=a&name=kaixin&s=get_file'; - - $p_data = $this->GetKeyData(); - $p_data['filename'] = $filename; - - $result = $this->curl($url,$p_data); - - $data = json_decode($result,true); - return $data; - } - - //购买第三方插件 - public function create_plugin_other_order($pid){ - $url = $this->BT_PANEL.'/auth?action=create_plugin_other_order'; - - $p_data = $this->GetKeyData(); - $p_data['pid'] = $pid; - $p_data['cycle'] = '999'; - $p_data['type'] = '0'; - - $result = $this->curl($url,$p_data); - - $data = json_decode($result,true); - return $data; - } - - //获取一键部署列表 - public function get_deplist(){ - $url = $this->BT_PANEL.'/plugin?action=a&name=kaixin&s=get_deplist'; - - $p_data = $this->GetKeyData(); - - $result = $this->curl($url,$p_data); - - $data = json_decode($result,true); - return $data; - } - - //BTWAF-获取蜘蛛列表 - public function btwaf_getspiders(){ - $url = $this->BT_PANEL.'/plugin?action=a&name=kaixin&s=btwaf_getspiders'; - - $p_data = $this->GetKeyData(); - - $result = $this->curl($url,$p_data); - $result = str_replace("\u0000", '', $result); - - $data = json_decode($result,true); - return $data; - } - - - private function GetKeyData(){ - $now_time = time(); - $p_data = array( - 'request_token' => md5($now_time.''.md5($this->BT_KEY)), - 'request_time' => $now_time - ); - return $p_data; - } - - - private function curl($url, $data = null, $timeout = 60) - { - //定义cookie保存位置 - $cookie_file=app()->getRuntimePath().md5($this->BT_PANEL).'.cookie'; - if(!file_exists($cookie_file)){ - touch($cookie_file); - } - - $ch = curl_init(); - curl_setopt($ch, CURLOPT_URL, $url); - curl_setopt($ch, CURLOPT_TIMEOUT, $timeout); - if($data){ - curl_setopt($ch, CURLOPT_POST, 1); - curl_setopt($ch, CURLOPT_POSTFIELDS, $data); - } - curl_setopt($ch, CURLOPT_COOKIEJAR, $cookie_file); - curl_setopt($ch, CURLOPT_COOKIEFILE, $cookie_file); - curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); - curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); - curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); - $output = curl_exec($ch); - curl_close($ch); - return $output; - } - - private function curl_download($url, $localpath, $timeout = 300) - { - //定义cookie保存位置 - $cookie_file=app()->getRuntimePath().md5($this->BT_PANEL).'.cookie'; - if(!file_exists($cookie_file)){ - touch($cookie_file); - } - - $ch = curl_init(); - curl_setopt($ch, CURLOPT_URL, $url); - curl_setopt($ch, CURLOPT_TIMEOUT, $timeout); - curl_setopt($ch, CURLOPT_COOKIEJAR, $cookie_file); - curl_setopt($ch, CURLOPT_COOKIEFILE, $cookie_file); - $fp = fopen($localpath, 'w+'); - curl_setopt($ch, CURLOPT_FILE, $fp); - curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); - curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); - curl_exec($ch); - if (curl_errno($ch)) { - $message = curl_error($ch); - curl_close($ch); - fclose($fp); - throw new Exception('下载文件失败:'.$message); - } - $httpcode = curl_getinfo($ch, CURLINFO_HTTP_CODE); - if($httpcode>299){ - curl_close($ch); - fclose($fp); - throw new Exception('下载文件失败:HTTPCODE-'.$httpcode); - } - curl_close($ch); - fclose($fp); - return true; - } +BT_PANEL = $bt_panel; + $this->BT_KEY = $bt_key; + } + + //获取面板配置信息 + public function get_config(){ + $url = $this->BT_PANEL.'/config?action=get_config'; + + $p_data = $this->GetKeyData(); + + $result = $this->curl($url,$p_data); + + $data = json_decode($result,true); + return $data; + } + + //获取已登录用户信息 + public function get_user_info(){ + $url = $this->BT_PANEL.'/plugin?action=a&name=kaixin&s=get_user_info'; + + $p_data = $this->GetKeyData(); + + $result = $this->curl($url,$p_data); + + $data = json_decode($result,true); + return $data; + } + + //从云端获取插件列表 + public function get_plugin_list(){ + $url = $this->BT_PANEL.'/plugin?action=a&name=kaixin&s=get_plugin_list'; + + $p_data = $this->GetKeyData(); + + $result = $this->curl($url,$p_data); + + $data = json_decode($result,true); + return $data; + } + + //下载插件包,返回文件路径 + public function get_plugin_filename($plugin_name, $version){ + $url = $this->BT_PANEL.'/plugin?action=a&name=kaixin&s=download_plugin'; + + $p_data = $this->GetKeyData(); + $p_data['plugin_name'] = $plugin_name; + $p_data['version'] = $version; + + $result = $this->curl($url,$p_data); + + $data = json_decode($result,true); + return $data; + } + + //下载插件主程序文件,返回文件路径 + public function get_plugin_main_filename($plugin_name, $version){ + $url = $this->BT_PANEL.'/plugin?action=a&name=kaixin&s=download_plugin_main'; + + $p_data = $this->GetKeyData(); + $p_data['plugin_name'] = $plugin_name; + $p_data['version'] = $version; + + $result = $this->curl($url,$p_data); + + $data = json_decode($result,true); + return $data; + } + + //解密插件主程序py代码,返回文件路径 + public function get_decode_plugin_main($plugin_name, $version){ + $url = $this->BT_PANEL.'/plugin?action=a&name=kaixin&s=decode_plugin_main'; + + $p_data = $this->GetKeyData(); + $p_data['plugin_name'] = $plugin_name; + $p_data['version'] = $version; + + $result = $this->curl($url,$p_data); + + $data = json_decode($result,true); + return $data; + } + + //下载插件其他文件,返回文件路径 + public function get_plugin_other_filename($fname){ + $url = $this->BT_PANEL.'/plugin?action=a&name=kaixin&s=download_plugin_other'; + + $p_data = $this->GetKeyData(); + $p_data['fname'] = $fname; + + $result = $this->curl($url,$p_data); + + $data = json_decode($result,true); + return $data; + } + + //下载文件 + public function download($filename, $localpath){ + $url = $this->BT_PANEL.'/download'; + + $p_data = $this->GetKeyData(); + $p_data['filename'] = $filename; + + $result = $this->curl_download($url.'?'.http_build_query($p_data), $localpath); + + return $result; + } + + //获取文件base64 + public function get_file($filename){ + $url = $this->BT_PANEL.'/plugin?action=a&name=kaixin&s=get_file'; + + $p_data = $this->GetKeyData(); + $p_data['filename'] = $filename; + + $result = $this->curl($url,$p_data); + + $data = json_decode($result,true); + return $data; + } + + //购买第三方插件 + public function create_plugin_other_order($pid){ + $url = $this->BT_PANEL.'/auth?action=create_plugin_other_order'; + + $p_data = $this->GetKeyData(); + $p_data['pid'] = $pid; + $p_data['cycle'] = '999'; + $p_data['type'] = '0'; + + $result = $this->curl($url,$p_data); + + $data = json_decode($result,true); + return $data; + } + + //获取一键部署列表 + public function get_deplist(){ + $url = $this->BT_PANEL.'/plugin?action=a&name=kaixin&s=get_deplist'; + + $p_data = $this->GetKeyData(); + + $result = $this->curl($url,$p_data); + + $data = json_decode($result,true); + return $data; + } + + //BTWAF-获取蜘蛛列表 + public function btwaf_getspiders(){ + $url = $this->BT_PANEL.'/plugin?action=a&name=kaixin&s=btwaf_getspiders'; + + $p_data = $this->GetKeyData(); + + $result = $this->curl($url,$p_data); + $result = str_replace("\u0000", '', $result); + + $data = json_decode($result,true); + return $data; + } + + + private function GetKeyData(){ + $now_time = time(); + $p_data = array( + 'request_token' => md5($now_time.''.md5($this->BT_KEY)), + 'request_time' => $now_time + ); + return $p_data; + } + + + private function curl($url, $data = null, $timeout = 60) + { + //定义cookie保存位置 + $cookie_file=app()->getRuntimePath().md5($this->BT_PANEL).'.cookie'; + if(!file_exists($cookie_file)){ + touch($cookie_file); + } + + $ch = curl_init(); + curl_setopt($ch, CURLOPT_URL, $url); + curl_setopt($ch, CURLOPT_TIMEOUT, $timeout); + if($data){ + curl_setopt($ch, CURLOPT_POST, 1); + curl_setopt($ch, CURLOPT_POSTFIELDS, $data); + } + curl_setopt($ch, CURLOPT_COOKIEJAR, $cookie_file); + curl_setopt($ch, CURLOPT_COOKIEFILE, $cookie_file); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); + curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); + $output = curl_exec($ch); + curl_close($ch); + return $output; + } + + private function curl_download($url, $localpath, $timeout = 300) + { + //定义cookie保存位置 + $cookie_file=app()->getRuntimePath().md5($this->BT_PANEL).'.cookie'; + if(!file_exists($cookie_file)){ + touch($cookie_file); + } + + $ch = curl_init(); + curl_setopt($ch, CURLOPT_URL, $url); + curl_setopt($ch, CURLOPT_TIMEOUT, $timeout); + curl_setopt($ch, CURLOPT_COOKIEJAR, $cookie_file); + curl_setopt($ch, CURLOPT_COOKIEFILE, $cookie_file); + $fp = fopen($localpath, 'w+'); + curl_setopt($ch, CURLOPT_FILE, $fp); + curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); + curl_exec($ch); + if (curl_errno($ch)) { + $message = curl_error($ch); + curl_close($ch); + fclose($fp); + throw new Exception('下载文件失败:'.$message); + } + $httpcode = curl_getinfo($ch, CURLINFO_HTTP_CODE); + if($httpcode>299){ + curl_close($ch); + fclose($fp); + throw new Exception('下载文件失败:HTTPCODE-'.$httpcode); + } + curl_close($ch); + fclose($fp); + return true; + } } \ No newline at end of file diff --git a/app/middleware/AuthAdmin.php b/app/middleware/AuthAdmin.php index f4ab3cc..378bf99 100644 --- a/app/middleware/AuthAdmin.php +++ b/app/middleware/AuthAdmin.php @@ -1,26 +1,26 @@ -time()) { - $islogin = true; - } - } - } - request()->islogin = $islogin; - return $next($request); - } -} +time()) { + $islogin = true; + } + } + } + request()->islogin = $islogin; + return $next($request); + } +} diff --git a/app/middleware/CheckAdmin.php b/app/middleware/CheckAdmin.php index 6240ad5..f744199 100644 --- a/app/middleware/CheckAdmin.php +++ b/app/middleware/CheckAdmin.php @@ -1,19 +1,19 @@ -islogin) { - if ($request->isAjax() || !$request->isGet()) { - return json(['code'=>-1, 'msg'=>'未登录'])->code(401); - } - return redirect((string)url('/admin/login')); - } - return $next($request); - } -} +islogin) { + if ($request->isAjax() || !$request->isGet()) { + return json(['code'=>-1, 'msg'=>'未登录'])->code(401); + } + return redirect((string)url('/admin/login')); + } + return $next($request); + } +} diff --git a/app/middleware/LoadConfig.php b/app/middleware/LoadConfig.php index 37e3712..4555b32 100644 --- a/app/middleware/LoadConfig.php +++ b/app/middleware/LoadConfig.php @@ -5,6 +5,7 @@ namespace app\middleware; use think\facade\Db; use think\facade\Config; +use think\facade\View; class LoadConfig { @@ -31,6 +32,7 @@ class LoadConfig $res = Db::name('config')->cache('configs',0)->column('value','key'); Config::set($res, 'sys'); + View::assign('cdnpublic', '//lf6-cdn-tos.bytecdntp.com/cdn/expire-1-M/'); return $next($request)->header([ 'Cache-Control' => 'no-store, no-cache, must-revalidate', 'Pragma' => 'no-cache', diff --git a/app/middleware/RefererCheck.php b/app/middleware/RefererCheck.php index 056a4d0..7282761 100644 --- a/app/middleware/RefererCheck.php +++ b/app/middleware/RefererCheck.php @@ -1,24 +1,24 @@ -> server.crt + +openssl pkcs12 -export -out baota_root.pfx -inkey server.key -in server.crt -password pass: +if [ "$?" != "0" ]; then + echo "生成CA根证书失败" + exit 1 +fi + +mkdir -p ../../public/ssl +\cp baota_root.pfx ../../public/ssl/baota_root.pfx +\cp ca.crt ../../public/ssl/baota_root.crt +rm -f server.crt server.key server.csr + +echo "生成CA根证书成功" diff --git a/app/view/admin/deplist.html b/app/view/admin/deplist.html index 6fb984a..703c681 100644 --- a/app/view/admin/deplist.html +++ b/app/view/admin/deplist.html @@ -16,7 +16,7 @@ - + - - + + + @@ -51,6 +51,9 @@
  • 操作日志
  • +
  • + 自签SSL +
  • 系统设置 diff --git a/app/view/admin/list.html b/app/view/admin/list.html index 79b8a99..d3099bc 100644 --- a/app/view/admin/list.html +++ b/app/view/admin/list.html @@ -42,9 +42,9 @@ - - - + + + - - + + + - + + + @@ -63,7 +63,7 @@ - + - - + + + - - + + + - - + + + + + +{/block} \ No newline at end of file diff --git a/app/view/dispatch_jump.html b/app/view/dispatch_jump.html index 69d6246..7e7452b 100644 --- a/app/view/dispatch_jump.html +++ b/app/view/dispatch_jump.html @@ -1,60 +1,60 @@ - - - - - 温馨提示 - - - - - -
    -
    - -
    -

    {$msg}

    - {if $url} -

    - 页面将在 {$wait} 秒后自动跳转 -

    - {/if} -

    - 返回上一页 - {if $url} - 立即跳转 - {/if} -

    -
    - - + + + + + 温馨提示 + + + + + +
    +
    + +
    +

    {$msg}

    + {if $url} +

    + 页面将在 {$wait} 秒后自动跳转 +

    + {/if} +

    + 返回上一页 + {if $url} + 立即跳转 + {/if} +

    +
    + + \ No newline at end of file diff --git a/app/view/index/download.html b/app/view/index/download.html index 88b1e23..32b8e67 100644 --- a/app/view/index/download.html +++ b/app/view/index/download.html @@ -193,10 +193,10 @@ - - + + - + +