mirror of
https://github.com/flucont/btcloud.git
synced 2026-02-22 00:57:22 +08:00
Compare commits
No commits in common. "1.5" and "main" have entirely different histories.
122
README.md
122
README.md
@ -1,56 +1,66 @@
|
|||||||
# 宝塔面板第三方云端
|
# 宝塔面板第三方云端
|
||||||
这是一个用php开发的宝塔面板第三方云端站点程序。
|
这是一个用php开发的宝塔面板第三方云端站点程序。
|
||||||
|
|
||||||
你可以使用此程序搭建属于自己的宝塔面板第三方云端,实现最新版宝塔面板私有化部署,不与宝塔官方接口通信,满足隐私安全合规需求。同时还可以去除面板强制绑定账号,DIY面板功能等。
|
你可以使用此程序搭建属于自己的宝塔面板第三方云端,实现最新版宝塔面板私有化部署,不与宝塔官方接口通信,满足隐私安全合规需求。同时还可以去除面板强制绑定账号,DIY面板功能等。
|
||||||
|
|
||||||
网站后台管理可一键同步宝塔官方的插件列表与增量更新插件包,还有云端使用记录、IP黑白名单、操作日志、定时任务等功能。
|
网站后台管理可一键同步宝塔官方的插件列表与增量更新插件包,还有云端使用记录、IP黑白名单、操作日志、定时任务等功能。
|
||||||
|
|
||||||
本项目自带的宝塔安装包和更新包是7.9.5最新版,已修改适配此第三方云端,并且全开源,无so等加密文件。
|
本项目自带 **宝塔Linux面板**、**宝塔Windows面板**、**aaPanel面板**、**宝塔云监控** 的最新版安装包和更新包,已修改适配此第三方云端,并且全开源,无.so等加密文件。
|
||||||
|
|
||||||
觉得该项目不错的可以给个Star~
|
觉得该项目不错的可以给个Star~
|
||||||
|
|
||||||
## 声明
|
## 声明
|
||||||
|
|
||||||
1.此项目只能以自用为目的,不得侵犯堡塔公司及其他第三方的知识产权和其他合法权利。
|
1.此项目只能以自用为目的,不得侵犯堡塔公司及其他第三方的知识产权和其他合法权利。
|
||||||
|
|
||||||
2.搭建使用此项目必须有一定的编程和Linux运维基础,纯小白不建议使用。
|
2.搭建使用此项目必须有一定的编程和Linux运维基础,纯小白不建议使用。
|
||||||
|
|
||||||
## 环境要求
|
## 环境要求
|
||||||
|
|
||||||
* `PHP` >= 7.4
|
* `PHP` >= 7.4
|
||||||
* `MySQL` >= 5.6
|
* `MySQL` >= 5.6
|
||||||
* `fileinfo`扩展
|
* `fileinfo`扩展
|
||||||
* `ZipArchive`扩展
|
* `ZipArchive`扩展
|
||||||
|
|
||||||
## 部署方法
|
## 部署方法
|
||||||
|
|
||||||
- [下载最新版的Release包](https://github.com/flucont/btcloud/releases)
|
- [下载最新版的Release包](https://github.com/flucont/btcloud/releases)
|
||||||
- 如果是下载的源码包,需要执行 `composer install --no-dev` 安装依赖,如果是下载的Release包,则不需要
|
- 如果是下载的源码包,需要执行 `composer install --no-dev` 安装依赖,如果是下载的Release包,则不需要
|
||||||
- 设置网站运行目录为`public`
|
- 设置网站运行目录为`public`
|
||||||
- 设置伪静态为`ThinkPHP`
|
- 设置伪静态为`ThinkPHP`
|
||||||
- 访问网站,会自动跳转到安装页面,根据提示安装完成
|
- 访问网站,会自动跳转到安装页面,根据提示安装完成
|
||||||
|
|
||||||
## 使用方法
|
## 使用方法
|
||||||
|
|
||||||
- 在`批量替换工具`,执行页面显示的命令,可将bt安装包、更新包和脚本文件里面的`http://www.example.com`批量替换成当前网站的网址。
|
- 在`批量替换工具`,执行页面显示的命令,可将bt安装包、更新包和脚本文件里面的`http://www.example.com`批量替换成当前网站的网址。
|
||||||
- 在`系统基本设置`修改宝塔面板接口设置。你需要准备一个使用官方最新脚本安装并绑定账号的宝塔面板,用于获取最新插件列表及插件包。并根据界面提示安装好专用插件。
|
- 在`系统基本设置`修改宝塔面板接口设置。你需要准备一个使用官方最新脚本安装并绑定账号的宝塔面板,用于获取最新插件列表及插件包。并根据界面提示安装好专用插件。
|
||||||
- 在`定时任务设置`执行所显示的命令从宝塔官方获取最新的插件列表并批量下载插件包(增量更新)。当然你也可以去插件列表,一个一个点击下载。
|
- 在`定时任务设置`执行所显示的命令从宝塔官方获取最新的插件列表并批量下载插件包(增量更新)。当然你也可以去插件列表,一个一个点击下载。
|
||||||
- 访问网站`/download`查看使用此第三方云端的一键安装脚本。
|
- 访问网站`/download`查看使用此第三方云端的一键安装脚本。
|
||||||
|
|
||||||
## 其他
|
## 更新方法
|
||||||
|
|
||||||
- [Linux面板官方更新包修改记录](./wiki/update.md)
|
- [下载最新版的Release包](https://github.com/flucont/btcloud/releases)
|
||||||
|
- 上传覆盖除data文件夹以外的全部文件
|
||||||
- [Windows面板官方更新包修改记录](./wiki/updatewin.md)
|
- 后台使用批量替换工具->获取最新插件列表->修改软件版本设置里面的版本号
|
||||||
|
|
||||||
- 宝塔面板官方版与此第三方云端版对比:
|
## 其他
|
||||||
|
|
||||||
| | 官方版 | 此第三方云端版 |
|
- [Linux面板官方更新包修改记录](./wiki/update.md)
|
||||||
| ---------- | ------------------------------------------------------------ | -------------------------------------------------- |
|
|
||||||
| 版本更新 | 支持 | 支持 |
|
- [Windows面板官方更新包修改记录](./wiki/updatewin.md)
|
||||||
| 面板广告 | 有广告 | 无广告 |
|
|
||||||
| 是否全开源 | 没有全开源 | 全开源 |
|
- [aaPanel面板官方更新包修改记录](./wiki/aapanel.md)
|
||||||
| 资源占用 | 各种统计上报等任务,资源占用略高 | 去除了很多无用的定时任务,资源占较少 |
|
|
||||||
| 兼容性 | 由于编译的so文件有系统架构限制,兼容的系统仅限已编译的so对应的系统架构 | 由于全开源,没有已编译的so文件,因此无系统架构限制 |
|
- [宝塔云监控安装包修改记录](./wiki/btmonitor.md)
|
||||||
|
|
||||||
|
- 宝塔面板官方版与此第三方云端版对比:
|
||||||
|
|
||||||
|
| | 官方版 | 此第三方云端版 |
|
||||||
|
| ---------- | ------------------------------------------------------------ | -------------------------------------------------- |
|
||||||
|
| 版本更新 | 支持 | 支持 |
|
||||||
|
| 面板广告 | 有广告 | 无广告 |
|
||||||
|
| 是否全开源 | 没有全开源 | 全开源 |
|
||||||
|
| 资源占用 | 各种统计上报等任务,资源占用略高 | 去除了很多无用的定时任务,资源占较少 |
|
||||||
|
| 兼容性 | 由于编译的so文件有系统架构限制,兼容的系统仅限已编译的so对应的系统架构 | 由于全开源,没有已编译的so文件,因此无系统架构限制 |
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
77
app/command/Clean.php
Normal file
77
app/command/Clean.php
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
<?php
|
||||||
|
declare (strict_types = 1);
|
||||||
|
|
||||||
|
namespace app\command;
|
||||||
|
|
||||||
|
use think\console\Command;
|
||||||
|
use think\console\Input;
|
||||||
|
use think\console\input\Argument;
|
||||||
|
use think\console\input\Option;
|
||||||
|
use think\console\Output;
|
||||||
|
use think\facade\Db;
|
||||||
|
use think\facade\Config;
|
||||||
|
use app\lib\Plugins;
|
||||||
|
|
||||||
|
class Clean extends Command
|
||||||
|
{
|
||||||
|
protected function configure()
|
||||||
|
{
|
||||||
|
$this->setName('clean')
|
||||||
|
->setDescription('the clean command');
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function execute(Input $input, Output $output)
|
||||||
|
{
|
||||||
|
$res = Db::name('config')->cache('configs',0)->column('value','key');
|
||||||
|
Config::set($res, 'sys');
|
||||||
|
|
||||||
|
if(config_get('bt_url')){
|
||||||
|
$this->clean_plugins($input, $output, 'Linux');
|
||||||
|
}
|
||||||
|
if(config_get('wbt_url')){
|
||||||
|
$this->clean_plugins($input, $output, 'Windows');
|
||||||
|
}
|
||||||
|
|
||||||
|
config_set('cleantime', date('Y-m-d H:i:s'));
|
||||||
|
}
|
||||||
|
|
||||||
|
private function clean_plugins(Input $input, Output $output, $os){
|
||||||
|
$data_dir = get_data_dir($os) . 'plugins/';
|
||||||
|
$file_list = [];
|
||||||
|
$json_arr = Plugins::get_plugin_list($os);
|
||||||
|
if(count($json_arr['list']) == 0) return;
|
||||||
|
foreach($json_arr['list'] as $plugin){
|
||||||
|
foreach($plugin['versions'] as $version){
|
||||||
|
$ver = $version['m_version'].'.'.$version['version'];
|
||||||
|
if(!isset($version['download'])){
|
||||||
|
$file_list[] = $plugin['name'].'-'.$ver;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$count = 0;
|
||||||
|
$dir = opendir($data_dir.'package');
|
||||||
|
while(false !== ( $file = readdir($dir)) ) {
|
||||||
|
if($file == '.' || $file == '..') continue;
|
||||||
|
$name = str_replace('.zip', '', $file);
|
||||||
|
if(!in_array($name, $file_list)){
|
||||||
|
$filepath = $data_dir . 'package/' . $file;
|
||||||
|
unlink($filepath);
|
||||||
|
$count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$output->writeln($os.'成功清理'.$count.'个历史版本插件包');
|
||||||
|
|
||||||
|
$count = 0;
|
||||||
|
$dir = opendir($data_dir.'folder');
|
||||||
|
while(false !== ( $file = readdir($dir)) ) {
|
||||||
|
if($file == '.' || $file == '..') continue;
|
||||||
|
if(!in_array($file, $file_list)){
|
||||||
|
$filepath = $data_dir . 'folder/' . $file;
|
||||||
|
deleteDir($filepath);
|
||||||
|
$count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$output->writeln($os.'成功清理'.$count.'个历史版本插件目录');
|
||||||
|
}
|
||||||
|
}
|
||||||
386
app/command/CleanViteJs.php
Normal file
386
app/command/CleanViteJs.php
Normal file
@ -0,0 +1,386 @@
|
|||||||
|
<?php
|
||||||
|
declare (strict_types = 1);
|
||||||
|
|
||||||
|
namespace app\command;
|
||||||
|
|
||||||
|
use think\console\Command;
|
||||||
|
use think\console\Input;
|
||||||
|
use think\console\input\Argument;
|
||||||
|
use think\console\input\Option;
|
||||||
|
use think\console\Output;
|
||||||
|
use think\facade\Db;
|
||||||
|
use think\facade\Config;
|
||||||
|
use app\lib\Plugins;
|
||||||
|
|
||||||
|
class CleanViteJs extends Command
|
||||||
|
{
|
||||||
|
protected function configure()
|
||||||
|
{
|
||||||
|
$this->setName('cleanvitejs')
|
||||||
|
->addArgument('dir', Argument::REQUIRED, '/BTPanel/static/vite/js/路径')
|
||||||
|
->setDescription('处理宝塔面板vite/js文件');
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function execute(Input $input, Output $output)
|
||||||
|
{
|
||||||
|
$dir = trim($input->getArgument('dir'));
|
||||||
|
if(!file_exists($dir)){
|
||||||
|
$output->writeln('目录不存在');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
//$this->handlefile($dir.'/DockerImages.js');
|
||||||
|
$this->checkdir($dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getExtendCode($content, $part, $n = 1, $startChar = '{', $endChar = '}'){
|
||||||
|
if(!$part) return false;
|
||||||
|
$length = strlen($content);
|
||||||
|
$start = strpos($content, $part);
|
||||||
|
if($start===false)return false;
|
||||||
|
$end = $start+strlen($part);
|
||||||
|
$start--;
|
||||||
|
$c = 0;
|
||||||
|
for($i=$start;$i>=0;$i--){
|
||||||
|
if(substr($content,$i,1) == $startChar) $c++;
|
||||||
|
if(substr($content,$i,1) == $endChar) $c--;
|
||||||
|
if($c == $n){
|
||||||
|
$start = $i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$c = 0;
|
||||||
|
for($i=$end;$i<=$length;$i++){
|
||||||
|
if(substr($content,$i,1) == $endChar) $c++;
|
||||||
|
if(substr($content,$i,1) == $startChar) $c--;
|
||||||
|
if($c == $n){
|
||||||
|
$end = $i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return substr($content, $start, $end - $start + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getExtendFunction($content, $part, $startChar = '(', $endChar = ')'){
|
||||||
|
$code = $this->getExtendCode($content, $part, 1, $startChar, $endChar);
|
||||||
|
if(!$code) return false;
|
||||||
|
$start = strpos($content, $code) - 1;
|
||||||
|
$end = $start + strlen($code);
|
||||||
|
for($i=$start;$i>=0;$i--){
|
||||||
|
$char = substr($content,$i,1);
|
||||||
|
if(!ctype_alpha($char)&&$char!='_'){
|
||||||
|
$start = $i+1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(substr($content,$start-1,1) == ',') $start--;
|
||||||
|
else if(substr($content,$end+1,1) == ',') $end++;
|
||||||
|
return substr($content, $start, $end - $start + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function checkdir($basedir){
|
||||||
|
if($dh=opendir($basedir)){
|
||||||
|
while (($file=readdir($dh)) !== false){
|
||||||
|
if($file != '.' && $file != '..'){
|
||||||
|
if(!is_dir($basedir.'/'.$file) && substr($file,-3)=='.js'){
|
||||||
|
$this->handlefile($basedir.'/'.$file);
|
||||||
|
}else if(!is_dir($basedir.'/'.$file) && substr($file,-4)=='.map'){
|
||||||
|
unlink($basedir.'/'.$file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
closedir($dh);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function str_replace_once($needle, $replace, $haystack) {
|
||||||
|
$pos = strpos($haystack, $needle);
|
||||||
|
if ($pos === false) {
|
||||||
|
return $haystack;
|
||||||
|
}
|
||||||
|
return substr_replace($haystack, $replace, $pos, strlen($needle));
|
||||||
|
}
|
||||||
|
|
||||||
|
private function handlefile($filepath){
|
||||||
|
//echo $filepath."\n";
|
||||||
|
$file = file_get_contents($filepath);
|
||||||
|
if(!$file)return;
|
||||||
|
|
||||||
|
$flag = false;
|
||||||
|
|
||||||
|
if(strpos($file, 'window.location.protocol.indexOf("https")>=0')!==false){ //index
|
||||||
|
$file = str_replace('window.location.protocol.indexOf("https")>=0', '!0', $file);
|
||||||
|
$code = $this->getExtendCode($file, 'isGetCoupon:', 2);
|
||||||
|
if($code){
|
||||||
|
$file = str_replace($code, '{}', $file);
|
||||||
|
}
|
||||||
|
$file = preg_replace('!recommendShow:\w+,!', 'recommendShow:!1,', $file, 1);
|
||||||
|
$code = $this->getExtendCode($file, '"打开需求反馈"', 1, '[', ']');
|
||||||
|
if($code){
|
||||||
|
$file = str_replace($code, '[]', $file);
|
||||||
|
}
|
||||||
|
$flag = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(strpos($file, '"点击打开调查问卷"')!==false){ //index
|
||||||
|
$code = $this->getExtendCode($file, '"点击打开调查问卷"', 2);
|
||||||
|
if($code){
|
||||||
|
$file = str_replace($code, '{}', $file);
|
||||||
|
}
|
||||||
|
$flag = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(strpos($file, '您有{0}个优惠券待领取')!==false){ //win-index
|
||||||
|
$code = $this->getExtendCode($file, 'isGetCoupon:', 2);
|
||||||
|
if($code){
|
||||||
|
$file = str_replace($code, '{}', $file);
|
||||||
|
}
|
||||||
|
$flag = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(strpos($file, '论坛求助')!==false && strpos($file, '"/other/customer-qrcode.png"')!==false){ //main
|
||||||
|
$code = $this->getExtendCode($file, '"微信公众号"', 1);
|
||||||
|
$code = $this->getExtendFunction($file, $code);
|
||||||
|
$start = strpos($file, $code) - 1;
|
||||||
|
for($i=$start;$i>=0;$i--){
|
||||||
|
if(substr($file,$i,1) == ','){
|
||||||
|
$start = $i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$code = $this->getExtendCode($file, '"/other/customer-qrcode.png"', 2);
|
||||||
|
$code = $this->getExtendFunction($file, $code);
|
||||||
|
$end = strpos($file, $code)+strlen($code);
|
||||||
|
$code = substr($file, $start, $end - $start);
|
||||||
|
$file = str_replace($code, '', $file);
|
||||||
|
$flag = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(strpos($file, 'useNegotiate')!==false){ //utils
|
||||||
|
$code = $this->getExtendCode($file, 'createPeerConnection()', 1);
|
||||||
|
if($code){
|
||||||
|
$file = str_replace($code, '{}', $file);
|
||||||
|
}
|
||||||
|
$file = preg_replace('!computed\(\(\)=>"calc"===\w+\.\w+\.type\)!', '!1', $file);
|
||||||
|
$file = preg_replace('!computed\(\(\)=>"input"===\w+\.\w+\.type\)!', '!1', $file);
|
||||||
|
$file = preg_replace('!computed\(function\(\)\{return"calc"===\w+\.\w+\.type\}\)!', '!1', $file);
|
||||||
|
$file = preg_replace('!computed\(function\(\)\{return"input"===\w+\.\w+\.type\}\)!', '!1', $file);
|
||||||
|
$file = preg_replace('!computed\(\(\)=>\w+\.\w+\.type==="calc"\)!', '!1', $file);
|
||||||
|
$file = preg_replace('!computed\(\(\)=>\w+\.\w+\.type==="input"\)!', '!1', $file);
|
||||||
|
$file = preg_replace('!computed\(function\(\)\{return\w+\.\w+\.type==="calc"\}\)!', '!1', $file);
|
||||||
|
$file = preg_replace('!computed\(function\(\)\{return\w+\.\w+\.type==="input"\}\)!', '!1', $file);
|
||||||
|
$code = $this->getExtendCode($file, '"自动部署"', 2);
|
||||||
|
if($code){
|
||||||
|
$file = str_replace($code.',', '', $file);
|
||||||
|
$file = str_replace($code, '', $file);
|
||||||
|
}
|
||||||
|
$flag = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(strpos($file, '"sqlserver管理"')!==false && strpos($file, '"iis管理"')!==false){ //win-utils
|
||||||
|
$file = preg_replace('!"calc"===\w+\.\w+\.type!', '!1', $file);
|
||||||
|
$file = preg_replace('!"input"===\w+\.\w+\.type!', '!1', $file);
|
||||||
|
$flag = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(strpos($file, '请冷静几秒钟,确认以下要删除的数据')!==false && strpos($file, '"计算结果:"')!==false){ //site
|
||||||
|
$code = $this->getExtendCode($file, '"计算结果:"', 1, '[', ']');
|
||||||
|
$code = $this->getExtendFunction($file, $code);
|
||||||
|
$file = str_replace($code, '', $file);
|
||||||
|
$file = preg_replace('!\w+\.sum===\w+\.addend1\+\w+\.addend2!', '!0', $file);
|
||||||
|
$file = preg_replace('!value=\!0,(\w+)\.value=5;!', 'value=!1,$1.value=0;', $file);
|
||||||
|
$flag = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(strpos($file, '"left-waf"')!==false && strpos($file, '"iconWaf"')!==false){ //site.table
|
||||||
|
$code = $this->getExtendCode($file, '"left-waf"');
|
||||||
|
$code = $this->getExtendCode($file, $code, 1, '[', ']');
|
||||||
|
$code = $this->getExtendFunction($file, $code);
|
||||||
|
$file = str_replace($code, '""', $file);
|
||||||
|
$flag = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(strpos($file, 'svgtofont-left-waf')!==false && strpos($file, '"iconWaf"')!==false){ //site.table
|
||||||
|
$code = $this->getExtendCode($file, 'svgtofont-left-waf');
|
||||||
|
$code = $this->getExtendCode($file, $code, 1, '[', ']');
|
||||||
|
$code = $this->getExtendFunction($file, $code);
|
||||||
|
$file = str_replace($code, '""', $file);
|
||||||
|
$flag = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(strpos($file, 'label:"商用SSL证书"')!==false){ //site-ssl
|
||||||
|
$code = $this->getExtendFunction($file, 'label:"商用SSL证书"', '{', '}');
|
||||||
|
$file = str_replace($code, '', $file);
|
||||||
|
$code = $this->getExtendFunction($file, 'label:"测试证书"', '{', '}');
|
||||||
|
if($code){
|
||||||
|
$file = str_replace($code, '', $file);
|
||||||
|
}
|
||||||
|
$code = $this->getExtendFunction($file, 'label:"宝塔证书"', '{', '}');
|
||||||
|
if($code){
|
||||||
|
$file = str_replace($code, '', $file);
|
||||||
|
}
|
||||||
|
$code = $this->getExtendCode($file, '"购买商业证书"', 2);
|
||||||
|
if($code){
|
||||||
|
$code2 = str_replace('"busSslList"', '"letsEncryptList"', $code);
|
||||||
|
$code2 = str_replace($this->getExtendFunction($code, '"购买商业证书"'), '', $code2);
|
||||||
|
$file = str_replace($code, $code2, $file);
|
||||||
|
}
|
||||||
|
$file = str_replace('.value="busSslList"', '.value="letsEncryptList"', $file);
|
||||||
|
$flag = true;
|
||||||
|
}
|
||||||
|
if(strpos($file, '"busSslList"')!==false && strpos($filepath, '/useStore')){ //site-ssl
|
||||||
|
$file = str_replace('"busSslList"', '"currentCertInfo"', $file);
|
||||||
|
$flag = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(strpos($file, '"商用SSL"')!==false){ //ssl
|
||||||
|
$code = $this->getExtendFunction($file, '"商用SSL"', '{', '}');
|
||||||
|
$file = str_replace($code, '', $file);
|
||||||
|
$code = $this->getExtendFunction($file, '"宝塔证书"', '{', '}');
|
||||||
|
if($code){
|
||||||
|
$file = str_replace($code, '', $file);
|
||||||
|
}
|
||||||
|
for($i=0;$i<3;$i++){
|
||||||
|
$code = $this->getExtendCode($file, ',"联系客服"', 2, '[', ']');
|
||||||
|
if($code){
|
||||||
|
$file = str_replace($code, '[]', $file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$flag = true;
|
||||||
|
}
|
||||||
|
if(strpos($file, '"SSL-CERTIFICATE-STORE"')!==false){ //ssl
|
||||||
|
$file = str_replace('("ssl")', '("encrypt")', $file);
|
||||||
|
$flag = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(strpos($file, '"商业证书"')!==false && strpos($file, 'name:"busSslList"')!==false && strpos($file, 'IIS配置')!==false){ //win-ssl
|
||||||
|
$code = $this->getExtendFunction($file, 'name:"busSslList"', '{', '}');
|
||||||
|
$file = str_replace($code, '', $file);
|
||||||
|
$code = $this->getExtendFunction($file, 'name:"trustAsiaList"', '{', '}');
|
||||||
|
$file = str_replace($code, '', $file);
|
||||||
|
$file = $this->str_replace_once('"busSslList"', '"currentCertInfo"', $file);
|
||||||
|
$flag = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(strpos($file, '如果您希望添加其它Docker应用')!==false){
|
||||||
|
$code = $this->getExtendCode($file, '如果您希望添加其它Docker应用', 1, '[', ']');
|
||||||
|
$code = $this->getExtendFunction($file, $code);
|
||||||
|
$file = str_replace($code, '', $file);
|
||||||
|
$flag = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(strpos($file, '"recom-view"')!==false){ //soft
|
||||||
|
$code = $this->getExtendCode($file, '"recom-view"');
|
||||||
|
$code = $this->getExtendFunction($file, $code);
|
||||||
|
$file = str_replace($code, '', $file);
|
||||||
|
$flag = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(strpos($file, '"打开插件文件目录"')!==false && strpos($file, '"(续费)"')!==false){ //soft.table
|
||||||
|
$code = $this->getExtendFunction($file, '"(续费)"');
|
||||||
|
$file = str_replace($code, '""', $file);
|
||||||
|
$code = $this->getExtendCode($file, 'activity_id:47', 2);
|
||||||
|
if($code){
|
||||||
|
$file = str_replace($code, '{}', $file);
|
||||||
|
}
|
||||||
|
$flag = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(strpos($file, 'path:"register"')!==false){ //domain
|
||||||
|
$code = $this->getExtendCode($file, 'path:"register"');
|
||||||
|
$file = str_replace($code.',', '', $file);
|
||||||
|
$flag = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
for($i=0;$i<5;$i++){
|
||||||
|
$code = $this->getExtendCode($file, ',"需求反馈"', 1, '[', ']');
|
||||||
|
if($code){
|
||||||
|
if(strpos($code, 'svgtofont-desired')){
|
||||||
|
$file = str_replace($code, '[]', $file);
|
||||||
|
}else{
|
||||||
|
$code = $this->getExtendFunction($code, ',"需求反馈"');
|
||||||
|
$file = str_replace($code, '', $file);
|
||||||
|
}
|
||||||
|
$flag = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$code = $this->getExtendCode($file, '("需求反馈",-1)', 1, '[', ']');
|
||||||
|
if($code){
|
||||||
|
$file = str_replace($code, '[]', $file);
|
||||||
|
$flag = true;
|
||||||
|
}
|
||||||
|
$code = $this->getExtendCode($file, '(" 需求反馈 ",-1)', 1, '[', ']');
|
||||||
|
if($code){
|
||||||
|
$file = str_replace($code, '[]', $file);
|
||||||
|
$flag = true;
|
||||||
|
}
|
||||||
|
$code = $this->getExtendFunction($file, 'label:"需求反馈",', '{', '}');
|
||||||
|
if($code){
|
||||||
|
$file = str_replace($code, '', $file);
|
||||||
|
$flag = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(strpos($file, '暂无搜索结果,<span class="text-primary cursor-pointer NpsDialog">提交需求反馈</span>')!==false){
|
||||||
|
$file = str_replace('暂无搜索结果,<span class="text-primary cursor-pointer NpsDialog">提交需求反馈</span>', '暂无搜索结果', $file);
|
||||||
|
$flag = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(strpos($file, 'getReceiveCoupon()')!==false){ //aapanel-优惠券
|
||||||
|
$code = $this->getExtendCode($file, 'getReceiveCoupon()');
|
||||||
|
$file = str_replace($code, '{}', $file);
|
||||||
|
$flag = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(strpos($file, '"Site.DelSite.index_1"')!==false){ //aapanel-site
|
||||||
|
$code = $this->getExtendCode($file, '"Site.DelSite.index_10"', 3, '(', ')');
|
||||||
|
if($code){
|
||||||
|
$code = $this->getExtendFunction($file, $code);
|
||||||
|
$file = str_replace($code, '', $file);
|
||||||
|
$file = preg_replace('@\w+\.value!==\w+\.value\+\w+\.value@', '!1', $file);
|
||||||
|
$file = preg_replace('@null==\w+\.value\|\|null==\w+\.value@', '!1', $file);
|
||||||
|
$file = str_replace('disabled:!0', 'disabled:!1', $file);
|
||||||
|
$flag = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(strpos($file, '"Component.Confirm.index_4"')!==false){ //aapanel-public
|
||||||
|
$code = $this->getExtendCode($file, '"Component.Confirm.index_4"', 2, '(', ')');
|
||||||
|
if($code){
|
||||||
|
$code = $this->getExtendFunction($file, $code);
|
||||||
|
$file = str_replace($code, '', $file);
|
||||||
|
$file = preg_replace('@\w+\.value===\w+\.value\+\w+\.value@', '!0', $file);
|
||||||
|
$flag = true;
|
||||||
|
}
|
||||||
|
$code = $this->getExtendCode($file, '"Component.Confirm.index_1"', 1, '(', ')');
|
||||||
|
if($code){
|
||||||
|
$code = $this->getExtendFunction($file, $code);
|
||||||
|
$file = str_replace($code, '', $file);
|
||||||
|
$file = preg_replace('@\w+\.value===\w+\.value\?@', '!0?', $file);
|
||||||
|
$flag = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(strpos($file, '"Component.Feedback.index_7"')!==false){ //aapanel-需求反馈
|
||||||
|
$code = $this->getExtendCode($file, '"Component.Feedback.index_7"', 2);
|
||||||
|
if($code){
|
||||||
|
$code = $this->getExtendFunction($file, $code);
|
||||||
|
$file = str_replace($code, '', $file);
|
||||||
|
$flag = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(strpos($file, '"Soft.index_16"')!==false){ //aapanel-soft
|
||||||
|
$code = $this->getExtendCode($file, '"Soft.index_16"', 2);
|
||||||
|
if($code){
|
||||||
|
$file = str_replace($code, '{}', $file);
|
||||||
|
$flag = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!$flag) return;
|
||||||
|
if(file_put_contents($filepath, $file)){
|
||||||
|
echo '文件:'.$filepath.' 处理成功'."\n";
|
||||||
|
}else{
|
||||||
|
echo '文件:'.$filepath.' 处理失败,可能无写入权限'."\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -45,37 +45,34 @@ class DecryptFile extends Command
|
|||||||
$output->writeln($e->getMessage());
|
$output->writeln($e->getMessage());
|
||||||
}
|
}
|
||||||
}elseif($type == 'module'){
|
}elseif($type == 'module'){
|
||||||
try{
|
$this->decode_module_file($output, $file);
|
||||||
$res = Plugins::decode_module_file($file);
|
|
||||||
if($res == 2){
|
|
||||||
$output->writeln('文件解密失败!');
|
|
||||||
}elseif($res == 1){
|
|
||||||
$output->writeln('文件解密成功!');
|
|
||||||
}
|
|
||||||
}catch(\Exception $e){
|
|
||||||
$output->writeln($e->getMessage());
|
|
||||||
}
|
|
||||||
}elseif($type == 'classdir'){
|
}elseif($type == 'classdir'){
|
||||||
$file = rtrim($file, '/');
|
$file = rtrim($file, '/');
|
||||||
if(!file_exists($file.'/common.py')){
|
if(file_exists($file.'/common.py')){
|
||||||
|
$class_v = 1;
|
||||||
|
}elseif(file_exists($file.'/common_v2.py')){
|
||||||
|
$class_v = 2;
|
||||||
|
}else{
|
||||||
$output->writeln('当前路径非宝塔面板class目录');
|
$output->writeln('当前路径非宝塔面板class目录');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
$dirs = glob($file.'/*Model');
|
$dirs = glob($file.'/*Model'.($class_v == 2 ? 'V2' : ''));
|
||||||
foreach($dirs as $dir){
|
foreach($dirs as $dir){
|
||||||
if(!is_dir($dir))continue;
|
if(!is_dir($dir))continue;
|
||||||
$files = glob($dir.'/*Model.py');
|
$files = glob($dir.'/*Model.py');
|
||||||
foreach($files as $file){
|
foreach($files as $filepath){
|
||||||
try{
|
$this->decode_module_file($output, $filepath);
|
||||||
$res = Plugins::decode_module_file($file);
|
}
|
||||||
if($res == 2){
|
}
|
||||||
$output->writeln('文件解密失败:'.$file);
|
if($class_v == 2){
|
||||||
}elseif($res == 1){
|
$filepath = $file.'/wp_toolkit/core.py';
|
||||||
$output->writeln('文件解密成功:'.$file);
|
if(file_exists($filepath)){
|
||||||
}
|
$this->decode_module_file($output, $filepath);
|
||||||
}catch(\Exception $e){
|
}
|
||||||
$output->writeln($e->getMessage().':'.$file);
|
}else{
|
||||||
}
|
$filepath = $file.'/public/authorization.py';
|
||||||
|
if(file_exists($filepath)){
|
||||||
|
$this->decode_module_file($output, $filepath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}elseif($type == 'all'){
|
}elseif($type == 'all'){
|
||||||
@ -95,21 +92,24 @@ class DecryptFile extends Command
|
|||||||
$this->scan_all_file($input, $output, $filepath);
|
$this->scan_all_file($input, $output, $filepath);
|
||||||
}
|
}
|
||||||
elseif(substr($filepath, -3) == '.py') {
|
elseif(substr($filepath, -3) == '.py') {
|
||||||
try{
|
$this->decode_module_file($output, $filepath);
|
||||||
$res = Plugins::decode_module_file($filepath);
|
|
||||||
if($res == 2){
|
|
||||||
$output->writeln('文件解密失败:'.$filepath);
|
|
||||||
}elseif($res == 1){
|
|
||||||
$output->writeln('文件解密成功:'.$filepath);
|
|
||||||
}
|
|
||||||
}catch(\Exception $e){
|
|
||||||
$output->writeln($e->getMessage().':'.$filepath);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
closedir($dir);
|
closedir($dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function decode_module_file(Output $output, $filepath){
|
||||||
|
try{
|
||||||
|
$res = Plugins::decode_module_file($filepath);
|
||||||
|
if($res == 2){
|
||||||
|
$output->writeln('文件解密失败:'.$filepath);
|
||||||
|
}elseif($res == 1){
|
||||||
|
$output->writeln('文件解密成功:'.$filepath);
|
||||||
|
}
|
||||||
|
}catch(\Exception $e){
|
||||||
|
$output->writeln($e->getMessage().':'.$filepath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -25,12 +25,15 @@ class UpdateAll extends Command
|
|||||||
$res = Db::name('config')->cache('configs',0)->column('value','key');
|
$res = Db::name('config')->cache('configs',0)->column('value','key');
|
||||||
Config::set($res, 'sys');
|
Config::set($res, 'sys');
|
||||||
|
|
||||||
if(config_get('bt_url')){
|
if(!config_get('bt_type') && config_get('bt_url') || config_get('bt_type')==1 && config_get('bt_surl')){
|
||||||
$this->process_plugins($input, $output, 'Linux');
|
$this->process_plugins($input, $output, 'Linux');
|
||||||
}
|
}
|
||||||
if(config_get('wbt_url')){
|
if(!config_get('wbt_type') && config_get('wbt_url') || config_get('wbt_type')==1 && config_get('wbt_surl')){
|
||||||
$this->process_plugins($input, $output, 'Windows');
|
$this->process_plugins($input, $output, 'Windows');
|
||||||
}
|
}
|
||||||
|
if(!config_get('enbt_type') && config_get('enbt_url') || config_get('enbt_type')==1 && config_get('enbt_surl')){
|
||||||
|
$this->process_plugins($input, $output, 'en');
|
||||||
|
}
|
||||||
|
|
||||||
config_set('runtime', date('Y-m-d H:i:s'));
|
config_set('runtime', date('Y-m-d H:i:s'));
|
||||||
}
|
}
|
||||||
@ -43,12 +46,19 @@ class UpdateAll extends Command
|
|||||||
|
|
||||||
$count = 0;
|
$count = 0;
|
||||||
|
|
||||||
$type = intval(config_get($os=='Windows'?'updateall_type_win':'updateall_type'));
|
if($os=='Windows'){
|
||||||
|
$type = intval(config_get('updateall_type_win'));
|
||||||
|
}elseif($os=='en'){
|
||||||
|
$type = intval(config_get('updateall_type_en'));
|
||||||
|
}else{
|
||||||
|
$type = intval(config_get('updateall_type'));
|
||||||
|
}
|
||||||
|
|
||||||
$json_arr = Plugins::get_plugin_list($os);
|
$json_arr = Plugins::get_plugin_list($os);
|
||||||
//循环下载缺少的插件
|
//循环下载缺少的插件
|
||||||
foreach($json_arr['list'] as $plugin){
|
foreach($json_arr['list'] as $plugin){
|
||||||
if($type == 0 && ($plugin['type']==8 || $plugin['type']==12) || $type == 1 && $plugin['type']==12 || $plugin['type']==10 || $plugin['type']==5) continue;
|
if($type == 0 && ($plugin['type']==8 || $plugin['type']==12) || $type == 1 && $plugin['type']==12 || $plugin['type']==10 || $plugin['type']==5) continue;
|
||||||
|
if(in_array($plugin['name'], \app\lib\BtPlugins::$skip_plugins)) continue;
|
||||||
|
|
||||||
foreach($plugin['versions'] as $version){
|
foreach($plugin['versions'] as $version){
|
||||||
$ver = $version['m_version'].'.'.$version['version'];
|
$ver = $version['m_version'].'.'.$version['version'];
|
||||||
@ -103,16 +113,4 @@ class UpdateAll extends Command
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private function download_plugin_image(Input $input, Output $output, $fname){
|
|
||||||
try{
|
|
||||||
Plugins::download_plugin_other($fname);
|
|
||||||
$output->writeln('下载图片: '.$fname.' 成功');
|
|
||||||
return true;
|
|
||||||
}catch(\Exception $e){
|
|
||||||
$output->writeln($fname.' '.$e->getMessage());
|
|
||||||
errorlog($fname.' '.$e->getMessage());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
144
app/common.php
144
app/common.php
@ -3,7 +3,13 @@
|
|||||||
use think\facade\Db;
|
use think\facade\Db;
|
||||||
|
|
||||||
function get_data_dir($os = 'Linux'){
|
function get_data_dir($os = 'Linux'){
|
||||||
return app()->getRootPath().'data/'.($os == 'Windows' ? 'win/' : '');
|
if($os == 'en'){
|
||||||
|
return app()->getRootPath().'data/en/';
|
||||||
|
}elseif($os == 'Windows'){
|
||||||
|
return app()->getRootPath().'data/win/';
|
||||||
|
}else{
|
||||||
|
return app()->getRootPath().'data/';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -180,8 +186,144 @@ function checkIfActive($string) {
|
|||||||
return null;
|
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){
|
function errorlog($msg){
|
||||||
$handle = fopen(app()->getRootPath()."record.txt", 'a');
|
$handle = fopen(app()->getRootPath()."record.txt", 'a');
|
||||||
fwrite($handle, date('Y-m-d H:i:s')."\t".$msg."\r\n");
|
fwrite($handle, date('Y-m-d H:i:s')."\t".$msg."\r\n");
|
||||||
fclose($handle);
|
fclose($handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
function licenseEncrypt($data, $key){
|
||||||
|
$iv = substr($key, 0, 16);
|
||||||
|
return openssl_encrypt($data, 'AES-256-CBC', $key, 0, $iv);
|
||||||
|
}
|
||||||
|
|
||||||
|
function licenseDecrypt($data, $key){
|
||||||
|
$iv = substr($key, 0, 16);
|
||||||
|
return openssl_decrypt($data, 'AES-256-CBC', $key, 0, $iv);
|
||||||
|
}
|
||||||
|
|
||||||
|
function generateKeyPairs(){
|
||||||
|
$pkey_dir = app()->getRootPath().'data/config/';
|
||||||
|
$public_key_path = $pkey_dir.'public_key.pem';
|
||||||
|
$private_key_path = $pkey_dir.'private_key.pem';
|
||||||
|
if(file_exists($public_key_path) && file_exists($private_key_path)){
|
||||||
|
return [file_get_contents($public_key_path), file_get_contents($private_key_path)];
|
||||||
|
}
|
||||||
|
$pkey_config = ['private_key_bits'=>4096];
|
||||||
|
$pkey_res = openssl_pkey_new($pkey_config);
|
||||||
|
$private_key = '';
|
||||||
|
openssl_pkey_export($pkey_res, $private_key, null, $pkey_config);
|
||||||
|
$pkey_details = openssl_pkey_get_details($pkey_res);
|
||||||
|
if(!$pkey_details) return false;
|
||||||
|
$public_key = $pkey_details['key'];
|
||||||
|
file_put_contents($public_key_path, $public_key);
|
||||||
|
file_put_contents($private_key_path, $private_key);
|
||||||
|
return [$public_key, $private_key];
|
||||||
|
}
|
||||||
|
|
||||||
|
function pemToBase64($pem){
|
||||||
|
$lines = explode("\n", $pem);
|
||||||
|
$encoded = '';
|
||||||
|
foreach ($lines as $line) {
|
||||||
|
if (trim($line) != '' && strpos($line, '-----BEGIN') === false && strpos($line, '-----END') === false) {
|
||||||
|
$encoded .= trim($line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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 = <<<EOF
|
||||||
|
[req]
|
||||||
|
req_extensions = extension_section
|
||||||
|
x509_extensions = extension_section
|
||||||
|
distinguished_name = dn
|
||||||
|
|
||||||
|
[dn]
|
||||||
|
|
||||||
|
[extension_section]
|
||||||
|
basicConstraints = CA:FALSE
|
||||||
|
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
|
||||||
|
subjectAltName = @alt_names
|
||||||
|
|
||||||
|
[alt_names]
|
||||||
|
EOF;
|
||||||
|
$ip_index = 1;
|
||||||
|
$dns_index = 1;
|
||||||
|
foreach ($domainList as $value) {
|
||||||
|
if(empty($value)) continue;
|
||||||
|
if(filter_var($value, FILTER_VALIDATE_IP)){
|
||||||
|
$opensslConfigContent .= sprintf("\nIP.%d = %s", $ip_index, $value);
|
||||||
|
$ip_index++;
|
||||||
|
}else{
|
||||||
|
$opensslConfigContent .= sprintf("\nDNS.%d = %s", $dns_index, $value);
|
||||||
|
$dns_index++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!file_put_contents($opensslConfigFile, $opensslConfigContent)) return false;
|
||||||
|
|
||||||
|
// 生成域名证书的私钥和 CSR
|
||||||
|
$domainPrivateKey = openssl_pkey_new([
|
||||||
|
'private_key_bits' => 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];
|
||||||
|
}
|
||||||
|
|
||||||
|
function deleteDir($dir){
|
||||||
|
$rd = opendir($dir);
|
||||||
|
if (!$rd) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (($file = readdir($rd)) !== false) {
|
||||||
|
if ($file == '.' || $file == '..') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$file = $dir . '/' . $file;
|
||||||
|
|
||||||
|
if (is_dir($file)) {
|
||||||
|
deleteDir($file);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
unlink($file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
closedir($rd);
|
||||||
|
rmdir($dir);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
@ -1,388 +1,466 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace app\controller;
|
namespace app\controller;
|
||||||
|
|
||||||
use app\BaseController;
|
use app\BaseController;
|
||||||
use think\facade\Db;
|
use think\facade\Db;
|
||||||
use think\facade\View;
|
use think\facade\View;
|
||||||
use think\facade\Request;
|
use think\facade\Request;
|
||||||
use think\facade\Cache;
|
use think\facade\Cache;
|
||||||
use app\lib\Btapi;
|
use app\lib\Btapi;
|
||||||
use app\lib\Plugins;
|
use app\lib\Plugins;
|
||||||
|
|
||||||
class Admin extends BaseController
|
class Admin extends BaseController
|
||||||
{
|
{
|
||||||
public function verifycode()
|
public function verifycode()
|
||||||
{
|
{
|
||||||
return captcha();
|
return captcha();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function login(){
|
public function login(){
|
||||||
if(request()->islogin){
|
if(request()->islogin){
|
||||||
return redirect('/admin');
|
return redirect('/admin');
|
||||||
}
|
}
|
||||||
if(request()->isAjax()){
|
if(request()->isAjax()){
|
||||||
$username = input('post.username',null,'trim');
|
$username = input('post.username',null,'trim');
|
||||||
$password = input('post.password',null,'trim');
|
$password = input('post.password',null,'trim');
|
||||||
$code = input('post.code',null,'trim');
|
$code = input('post.code',null,'trim');
|
||||||
|
|
||||||
if(empty($username) || empty($password)){
|
if(empty($username) || empty($password)){
|
||||||
return json(['code'=>-1, 'msg'=>'用户名或密码不能为空']);
|
return json(['code'=>-1, 'msg'=>'用户名或密码不能为空']);
|
||||||
}
|
}
|
||||||
if(!captcha_check($code)){
|
if(!captcha_check($code)){
|
||||||
return json(['code'=>-1, 'msg'=>'验证码错误']);
|
return json(['code'=>-1, 'msg'=>'验证码错误']);
|
||||||
}
|
}
|
||||||
if($username == config_get('admin_username') && $password == config_get('admin_password')){
|
if($username == config_get('admin_username') && $password == config_get('admin_password')){
|
||||||
Db::name('log')->insert(['uid' => 0, 'action' => '登录后台', 'data' => 'IP:'.$this->clientip, 'addtime' => date("Y-m-d H:i:s")]);
|
Db::name('log')->insert(['uid' => 0, 'action' => '登录后台', 'data' => 'IP:'.$this->clientip, 'addtime' => date("Y-m-d H:i:s")]);
|
||||||
$session = md5($username.config_get('admin_password'));
|
$session = md5($username.config_get('admin_password'));
|
||||||
$expiretime = time()+2562000;
|
$expiretime = time()+2562000;
|
||||||
$token = authcode("{$username}\t{$session}\t{$expiretime}", 'ENCODE', config_get('syskey'));
|
$token = authcode("{$username}\t{$session}\t{$expiretime}", 'ENCODE', config_get('syskey'));
|
||||||
cookie('admin_token', $token, ['expire' => $expiretime, 'httponly' => true]);
|
cookie('admin_token', $token, ['expire' => $expiretime, 'httponly' => true]);
|
||||||
config_set('admin_lastlogin', date('Y-m-d H:i:s'));
|
config_set('admin_lastlogin', date('Y-m-d H:i:s'));
|
||||||
return json(['code'=>0]);
|
return json(['code'=>0]);
|
||||||
}else{
|
}else{
|
||||||
return json(['code'=>-1, 'msg'=>'用户名或密码错误']);
|
return json(['code'=>-1, 'msg'=>'用户名或密码错误']);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return view();
|
return view();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function logout()
|
public function logout()
|
||||||
{
|
{
|
||||||
cookie('admin_token', null);
|
cookie('admin_token', null);
|
||||||
return redirect('/admin/login');
|
return redirect('/admin/login');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function index()
|
public function index()
|
||||||
{
|
{
|
||||||
$stat = ['total'=>0, 'free'=>0, 'pro'=>0, 'ltd'=>0, 'third'=>0];
|
$stat = ['total'=>0, 'free'=>0, 'pro'=>0, 'ltd'=>0, 'third'=>0];
|
||||||
$json_arr = Plugins::get_plugin_list();
|
$json_arr = Plugins::get_plugin_list();
|
||||||
if($json_arr){
|
if($json_arr){
|
||||||
foreach($json_arr['list'] as $plugin){
|
foreach($json_arr['list'] as $plugin){
|
||||||
$stat['total']++;
|
$stat['total']++;
|
||||||
if($plugin['type']==10) $stat['third']++;
|
if($plugin['type']==10) $stat['third']++;
|
||||||
elseif($plugin['type']==12) $stat['ltd']++;
|
elseif($plugin['type']==12) $stat['ltd']++;
|
||||||
elseif($plugin['type']==8) $stat['pro']++;
|
elseif($plugin['type']==8) $stat['pro']++;
|
||||||
elseif($plugin['type']==5 || $plugin['type']==6 || $plugin['type']==7) $stat['free']++;
|
elseif($plugin['type']==5 || $plugin['type']==6 || $plugin['type']==7) $stat['free']++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$stat['runtime'] = Db::name('config')->where('key','runtime')->value('value') ?? '<font color="red">未运行</font>';
|
$stat['runtime'] = Db::name('config')->where('key','runtime')->value('value') ?? '<font color="red">未运行</font>';
|
||||||
$stat['record_total'] = Db::name('record')->count();
|
$stat['record_total'] = Db::name('record')->count();
|
||||||
$stat['record_isuse'] = Db::name('record')->whereTime('usetime', '>=', strtotime('-7 days'))->count();
|
$stat['record_isuse'] = Db::name('record')->whereTime('usetime', '>=', strtotime('-7 days'))->count();
|
||||||
View::assign('stat', $stat);
|
View::assign('stat', $stat);
|
||||||
|
|
||||||
$tmp = 'version()';
|
$tmp = 'version()';
|
||||||
$mysqlVersion = Db::query("select version()")[0][$tmp];
|
$mysqlVersion = Db::query("select version()")[0][$tmp];
|
||||||
$info = [
|
$info = [
|
||||||
'framework_version' => app()::VERSION,
|
'framework_version' => app()::VERSION,
|
||||||
'php_version' => PHP_VERSION,
|
'php_version' => PHP_VERSION,
|
||||||
'mysql_version' => $mysqlVersion,
|
'mysql_version' => $mysqlVersion,
|
||||||
'software' => $_SERVER['SERVER_SOFTWARE'],
|
'software' => $_SERVER['SERVER_SOFTWARE'],
|
||||||
'os' => php_uname(),
|
'os' => php_uname(),
|
||||||
'date' => date("Y-m-d H:i:s"),
|
'date' => date("Y-m-d H:i:s"),
|
||||||
];
|
];
|
||||||
View::assign('info', $info);
|
View::assign('info', $info);
|
||||||
return view();
|
return view();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function set(){
|
public function set(){
|
||||||
if(request()->isAjax()){
|
if(request()->isAjax()){
|
||||||
$params = Request::param();
|
$params = Request::param();
|
||||||
|
|
||||||
foreach ($params as $key => $value) {
|
foreach ($params as $key => $value) {
|
||||||
config_set($key, $value);
|
config_set($key, $value);
|
||||||
}
|
}
|
||||||
cache('configs', NULL);
|
cache('configs', NULL);
|
||||||
return json(['code'=>0]);
|
return json(['code'=>0]);
|
||||||
}
|
}
|
||||||
$mod = input('param.mod', 'sys');
|
$mod = input('param.mod', 'sys');
|
||||||
View::assign('mod', $mod);
|
View::assign('mod', $mod);
|
||||||
View::assign('conf', config('sys'));
|
View::assign('conf', config('sys'));
|
||||||
$runtime = Db::name('config')->where('key','runtime')->value('value') ?? '<font color="red">未运行</font>';
|
$runtime = Db::name('config')->where('key','runtime')->value('value') ?? '<font color="red">未运行</font>';
|
||||||
View::assign('runtime', $runtime);
|
View::assign('runtime', $runtime);
|
||||||
return view();
|
View::assign('is_user_www', isset($_SERVER['USER']) && $_SERVER['USER'] == 'www');
|
||||||
}
|
return view();
|
||||||
|
}
|
||||||
public function setaccount(){
|
|
||||||
$params = Request::param();
|
public function setaccount(){
|
||||||
if(isset($params['username']))$params['username']=trim($params['username']);
|
$params = Request::param();
|
||||||
if(isset($params['oldpwd']))$params['oldpwd']=trim($params['oldpwd']);
|
if(isset($params['username']))$params['username']=trim($params['username']);
|
||||||
if(isset($params['newpwd']))$params['newpwd']=trim($params['newpwd']);
|
if(isset($params['oldpwd']))$params['oldpwd']=trim($params['oldpwd']);
|
||||||
if(isset($params['newpwd2']))$params['newpwd2']=trim($params['newpwd2']);
|
if(isset($params['newpwd']))$params['newpwd']=trim($params['newpwd']);
|
||||||
|
if(isset($params['newpwd2']))$params['newpwd2']=trim($params['newpwd2']);
|
||||||
if(empty($params['username'])) return json(['code'=>-1, 'msg'=>'用户名不能为空']);
|
|
||||||
|
if(empty($params['username'])) return json(['code'=>-1, 'msg'=>'用户名不能为空']);
|
||||||
config_set('admin_username', $params['username']);
|
|
||||||
|
config_set('admin_username', $params['username']);
|
||||||
if(!empty($params['oldpwd']) && !empty($params['newpwd']) && !empty($params['newpwd2'])){
|
|
||||||
if(config_get('admin_password') != $params['oldpwd']){
|
if(!empty($params['oldpwd']) && !empty($params['newpwd']) && !empty($params['newpwd2'])){
|
||||||
return json(['code'=>-1, 'msg'=>'旧密码不正确']);
|
if(config_get('admin_password') != $params['oldpwd']){
|
||||||
}
|
return json(['code'=>-1, 'msg'=>'旧密码不正确']);
|
||||||
if($params['newpwd'] != $params['newpwd2']){
|
}
|
||||||
return json(['code'=>-1, 'msg'=>'两次新密码输入不一致']);
|
if($params['newpwd'] != $params['newpwd2']){
|
||||||
}
|
return json(['code'=>-1, 'msg'=>'两次新密码输入不一致']);
|
||||||
config_set('admin_password', $params['newpwd']);
|
}
|
||||||
}
|
config_set('admin_password', $params['newpwd']);
|
||||||
cache('configs', NULL);
|
}
|
||||||
cookie('admin_token', null);
|
cache('configs', NULL);
|
||||||
return json(['code'=>0]);
|
cookie('admin_token', null);
|
||||||
}
|
return json(['code'=>0]);
|
||||||
|
}
|
||||||
public function testbturl(){
|
|
||||||
$bt_url = input('post.bt_url');
|
public function testbturl(){
|
||||||
$bt_key = input('post.bt_key');
|
$bt_type = input('post.bt_type/d');
|
||||||
if(!$bt_url || !$bt_key)return json(['code'=>-1, 'msg'=>'参数不能为空']);
|
|
||||||
$btapi = new Btapi($bt_url, $bt_key);
|
if($bt_type == 1){
|
||||||
$result = $btapi->get_config();
|
$bt_surl = input('post.bt_surl');
|
||||||
if($result && isset($result['status']) && ($result['status']==1 || isset($result['sites_path']))){
|
if(!$bt_surl)return json(['code'=>-1, 'msg'=>'参数不能为空']);
|
||||||
$result = $btapi->get_user_info();
|
$res = get_curl($bt_surl . 'api/SetupCount');
|
||||||
if($result && isset($result['username'])){
|
if(strpos($res, 'ok')!==false){
|
||||||
return json(['code'=>0, 'msg'=>'面板连接测试成功!']);
|
return json(['code'=>0, 'msg'=>'第三方云端连接测试成功!']);
|
||||||
}else{
|
}else{
|
||||||
return json(['code'=>-1, 'msg'=>'面板连接测试成功,但未安装专用插件']);
|
return json(['code'=>-1, 'msg'=>'第三方云端连接测试失败']);
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
return json(['code'=>-1, 'msg'=>isset($result['msg'])?$result['msg']:'面板地址无法连接']);
|
$bt_url = input('post.bt_url');
|
||||||
}
|
$bt_key = input('post.bt_key');
|
||||||
}
|
$os = input('post.os');
|
||||||
|
if(!$bt_url || !$bt_key)return json(['code'=>-1, 'msg'=>'参数不能为空']);
|
||||||
public function plugins(){
|
$btapi = new Btapi($bt_url, $bt_key);
|
||||||
$typelist = [];
|
if ($os == 'win') {
|
||||||
$json_arr = Plugins::get_plugin_list();
|
$result = $btapi->get_config_go();
|
||||||
if($json_arr){
|
if($result && isset($result['config'])){
|
||||||
foreach($json_arr['type'] as $type){
|
$result = $btapi->get_user_info();
|
||||||
$typelist[$type['id']] = $type['title'];
|
if($result && isset($result['username'])){
|
||||||
}
|
return json(['code'=>0, 'msg'=>'面板连接测试成功!']);
|
||||||
}
|
}else{
|
||||||
View::assign('typelist', $typelist);
|
return json(['code'=>-1, 'msg'=>'面板连接测试成功,但未安装专用插件/未登录账号']);
|
||||||
return view();
|
}
|
||||||
}
|
}else{
|
||||||
|
return json(['code'=>-1, 'msg'=>isset($result['msg'])?$result['msg']:'面板地址无法连接']);
|
||||||
public function pluginswin(){
|
}
|
||||||
$typelist = [];
|
} else {
|
||||||
$json_arr = Plugins::get_plugin_list('Windows');
|
$result = $btapi->get_config();
|
||||||
if($json_arr){
|
if($result && isset($result['status']) && ($result['status']==1 || isset($result['sites_path']))){
|
||||||
foreach($json_arr['type'] as $type){
|
$result = $btapi->get_user_info();
|
||||||
$typelist[$type['id']] = $type['title'];
|
if($result && isset($result['username'])){
|
||||||
}
|
return json(['code'=>0, 'msg'=>'面板连接测试成功!']);
|
||||||
}
|
}else{
|
||||||
View::assign('typelist', $typelist);
|
return json(['code'=>-1, 'msg'=>'面板连接测试成功,但未安装专用插件/未登录账号']);
|
||||||
return view();
|
}
|
||||||
}
|
}else{
|
||||||
|
return json(['code'=>-1, 'msg'=>isset($result['msg'])?$result['msg']:'面板地址无法连接']);
|
||||||
public function plugins_data(){
|
}
|
||||||
$type = input('post.type/d');
|
}
|
||||||
$keyword = input('post.keyword', null, 'trim');
|
}
|
||||||
$os = input('get.os');
|
}
|
||||||
if(!$os) $os = 'Linux';
|
|
||||||
|
public function plugins(){
|
||||||
$json_arr = Plugins::get_plugin_list($os);
|
$typelist = [];
|
||||||
if(!$json_arr) return json([]);
|
$json_arr = Plugins::get_plugin_list();
|
||||||
|
if($json_arr){
|
||||||
$typelist = [];
|
foreach($json_arr['type'] as $type){
|
||||||
foreach($json_arr['type'] as $row){
|
if($type['title'] == '一键部署') continue;
|
||||||
$typelist[$row['id']] = $row['title'];
|
$typelist[$type['id']] = $type['title'];
|
||||||
}
|
}
|
||||||
|
}
|
||||||
$list = [];
|
View::assign('typelist', $typelist);
|
||||||
foreach($json_arr['list'] as $plugin){
|
View::assign('skip_plugins', \app\lib\BtPlugins::$skip_plugins);
|
||||||
if($type > 0 && $plugin['type']!=$type) continue;
|
return view();
|
||||||
if(!empty($keyword) && $keyword != $plugin['name'] && stripos($plugin['title'], $keyword)===false) continue;
|
}
|
||||||
$versions = [];
|
|
||||||
foreach($plugin['versions'] as $version){
|
public function pluginswin(){
|
||||||
$ver = $version['m_version'].'.'.$version['version'];
|
$typelist = [];
|
||||||
if(isset($version['download'])){
|
$json_arr = Plugins::get_plugin_list('Windows');
|
||||||
$status = false;
|
if($json_arr){
|
||||||
if(file_exists(get_data_dir().'plugins/other/'.$version['download'])){
|
foreach($json_arr['type'] as $type){
|
||||||
$status = true;
|
if($type['title'] == '一键部署') continue;
|
||||||
}
|
$typelist[$type['id']] = $type['title'];
|
||||||
$versions[] = ['status'=>$status, 'type'=>1, 'version'=>$ver, 'download'=>$version['download'], 'md5'=>$version['md5']];
|
}
|
||||||
}else{
|
}
|
||||||
$status = false;
|
View::assign('typelist', $typelist);
|
||||||
if(file_exists(get_data_dir($os).'plugins/package/'.$plugin['name'].'-'.$ver.'.zip')){
|
return view();
|
||||||
$status = true;
|
}
|
||||||
}
|
|
||||||
$versions[] = ['status'=>$status, 'type'=>0, 'version'=>$ver];
|
public function pluginsen(){
|
||||||
}
|
$typelist = [];
|
||||||
}
|
$json_arr = Plugins::get_plugin_list('en');
|
||||||
if($plugin['name'] == 'obs') $plugin['ps'] = substr($plugin['ps'],0,strpos($plugin['ps'],'<a '));
|
if($json_arr){
|
||||||
$list[] = [
|
foreach($json_arr['type'] as $type){
|
||||||
'id' => $plugin['id'],
|
if($type['title'] == '一键部署') continue;
|
||||||
'name' => $plugin['name'],
|
$typelist[$type['id']] = $type['title'];
|
||||||
'title' => $plugin['title'],
|
}
|
||||||
'type' => $plugin['type'],
|
}
|
||||||
'typename' => $typelist[$plugin['type']],
|
View::assign('typelist', $typelist);
|
||||||
'desc' => str_replace('target="_blank"','target="_blank" rel="noopener noreferrer"',$plugin['ps']),
|
return view();
|
||||||
'price' => $plugin['price'],
|
}
|
||||||
'author' => isset($plugin['author']) ? $plugin['author'] : '官方',
|
|
||||||
'versions' => $versions
|
public function plugins_data(){
|
||||||
];
|
$type = input('post.type/d');
|
||||||
}
|
$keyword = input('post.keyword', null, 'trim');
|
||||||
return json($list);
|
$os = input('get.os');
|
||||||
}
|
if(!$os) $os = 'Linux';
|
||||||
|
|
||||||
public function download_plugin(){
|
$json_arr = Plugins::get_plugin_list($os);
|
||||||
$name = input('post.name', null, 'trim');
|
if(!$json_arr) return json([]);
|
||||||
$version = input('post.version', null, 'trim');
|
|
||||||
$os = input('post.os');
|
$typelist = [];
|
||||||
if(!$os) $os = 'Linux';
|
foreach($json_arr['type'] as $row){
|
||||||
if(!$name || !$version) return json(['code'=>-1, 'msg'=>'参数不能为空']);
|
$typelist[$row['id']] = $row['title'];
|
||||||
try{
|
}
|
||||||
Plugins::download_plugin($name, $version, $os);
|
|
||||||
Db::name('log')->insert(['uid' => 0, 'action' => '下载插件', 'data' => $name.'-'.$version.' os:'.$os, 'addtime' => date("Y-m-d H:i:s")]);
|
$list = [];
|
||||||
return json(['code'=>0,'msg'=>'下载成功']);
|
foreach($json_arr['list'] as $plugin){
|
||||||
}catch(\Exception $e){
|
if($type > 0 && $plugin['type']!=$type) continue;
|
||||||
return json(['code'=>-1, 'msg'=>$e->getMessage()]);
|
if(!empty($keyword) && $keyword != $plugin['name'] && stripos($plugin['title'], $keyword)===false) continue;
|
||||||
}
|
$versions = [];
|
||||||
}
|
foreach($plugin['versions'] as $version){
|
||||||
|
$ver = $version['m_version'].'.'.$version['version'];
|
||||||
public function refresh_plugins(){
|
if(isset($version['download'])){
|
||||||
$os = input('get.os');
|
$status = false;
|
||||||
if(!$os) $os = 'Linux';
|
if(file_exists(get_data_dir().'plugins/other/'.$version['download'])){
|
||||||
try{
|
$status = true;
|
||||||
Plugins::refresh_plugin_list($os);
|
}
|
||||||
Db::name('log')->insert(['uid' => 0, 'action' => '刷新插件列表', 'data' => '刷新'.$os.'插件列表成功', 'addtime' => date("Y-m-d H:i:s")]);
|
$versions[] = ['status'=>$status, 'type'=>1, 'version'=>$ver, 'download'=>$version['download'], 'md5'=>$version['md5']];
|
||||||
return json(['code'=>0,'msg'=>'获取最新插件列表成功!']);
|
}else{
|
||||||
}catch(\Exception $e){
|
$status = false;
|
||||||
return json(['code'=>-1, 'msg'=>$e->getMessage()]);
|
if(file_exists(get_data_dir($os).'plugins/package/'.$plugin['name'].'-'.$ver.'.zip')){
|
||||||
}
|
$status = true;
|
||||||
}
|
}
|
||||||
|
$versions[] = ['status'=>$status, 'type'=>0, 'version'=>$ver];
|
||||||
public function record(){
|
}
|
||||||
return view();
|
}
|
||||||
}
|
if($plugin['name'] == 'obs') $plugin['ps'] = substr($plugin['ps'],0,strpos($plugin['ps'],'<a '));
|
||||||
|
$list[] = [
|
||||||
public function record_data(){
|
'id' => $plugin['id'],
|
||||||
$ip = input('post.ip', null, 'trim');
|
'name' => $plugin['name'],
|
||||||
$offset = input('post.offset/d');
|
'title' => $plugin['title'],
|
||||||
$limit = input('post.limit/d');
|
'type' => $plugin['type'],
|
||||||
|
'typename' => isset($typelist[$plugin['type']]) ? $typelist[$plugin['type']] : '未知',
|
||||||
$select = Db::name('record');
|
'desc' => str_replace('target="_blank"','target="_blank" rel="noopener noreferrer"',$plugin['ps']),
|
||||||
if(!empty($ip)){
|
'price' => $plugin['price'],
|
||||||
$select->where('ip', $ip);
|
'author' => isset($plugin['author']) ? $plugin['author'] : '官方',
|
||||||
}
|
'versions' => $versions
|
||||||
$total = $select->count();
|
];
|
||||||
$rows = $select->order('id','desc')->limit($offset, $limit)->select();
|
}
|
||||||
|
return json($list);
|
||||||
return json(['total'=>$total, 'rows'=>$rows]);
|
}
|
||||||
}
|
|
||||||
|
public function download_plugin(){
|
||||||
public function log(){
|
$name = input('post.name', null, 'trim');
|
||||||
return view();
|
$version = input('post.version', null, 'trim');
|
||||||
}
|
$os = input('post.os');
|
||||||
|
if(!$os) $os = 'Linux';
|
||||||
public function log_data(){
|
if(!$name || !$version) return json(['code'=>-1, 'msg'=>'参数不能为空']);
|
||||||
$action = input('post.action', null, 'trim');
|
try{
|
||||||
$offset = input('post.offset/d');
|
Plugins::download_plugin($name, $version, $os);
|
||||||
$limit = input('post.limit/d');
|
Db::name('log')->insert(['uid' => 0, 'action' => '下载插件', 'data' => $name.'-'.$version.' os:'.$os, 'addtime' => date("Y-m-d H:i:s")]);
|
||||||
|
return json(['code'=>0,'msg'=>'下载成功']);
|
||||||
$select = Db::name('log');
|
}catch(\Exception $e){
|
||||||
if(!empty($action)){
|
return json(['code'=>-1, 'msg'=>$e->getMessage()]);
|
||||||
$select->where('action', $action);
|
}
|
||||||
}
|
}
|
||||||
$total = $select->count();
|
|
||||||
$rows = $select->order('id','desc')->limit($offset, $limit)->select();
|
public function refresh_plugins(){
|
||||||
|
$os = input('get.os');
|
||||||
return json(['total'=>$total, 'rows'=>$rows]);
|
if(!$os) $os = 'Linux';
|
||||||
}
|
try{
|
||||||
|
Plugins::refresh_plugin_list($os);
|
||||||
public function list(){
|
Db::name('log')->insert(['uid' => 0, 'action' => '刷新插件列表', 'data' => '刷新'.$os.'插件列表成功', 'addtime' => date("Y-m-d H:i:s")]);
|
||||||
$type = input('param.type', 'black');
|
return json(['code'=>0,'msg'=>'获取最新插件列表成功!']);
|
||||||
View::assign('type', $type);
|
}catch(\Exception $e){
|
||||||
View::assign('typename', $type=='white'?'白名单':'黑名单');
|
return json(['code'=>-1, 'msg'=>$e->getMessage()]);
|
||||||
return view();
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function list_data(){
|
public function record(){
|
||||||
$type = input('param.type', 'black');
|
return view();
|
||||||
$ip = input('post.ip', null, 'trim');
|
}
|
||||||
$offset = input('post.offset/d');
|
|
||||||
$limit = input('post.limit/d');
|
public function record_data(){
|
||||||
|
$ip = input('post.ip', null, 'trim');
|
||||||
$tablename = $type == 'black' ? 'black' : 'white';
|
$offset = input('post.offset/d');
|
||||||
$select = Db::name($tablename);
|
$limit = input('post.limit/d');
|
||||||
if(!empty($ip)){
|
|
||||||
$select->where('ip', $ip);
|
$select = Db::name('record');
|
||||||
}
|
if(!empty($ip)){
|
||||||
$total = $select->count();
|
$select->where('ip', $ip);
|
||||||
$rows = $select->order('id','desc')->limit($offset, $limit)->select();
|
}
|
||||||
|
$total = $select->count();
|
||||||
return json(['total'=>$total, 'rows'=>$rows]);
|
$rows = $select->order('id','desc')->limit($offset, $limit)->select();
|
||||||
}
|
|
||||||
|
return json(['total'=>$total, 'rows'=>$rows]);
|
||||||
public function list_op(){
|
}
|
||||||
$type = input('param.type', 'black');
|
|
||||||
$tablename = $type == 'black' ? 'black' : 'white';
|
public function log(){
|
||||||
$act = input('post.act', null);
|
return view();
|
||||||
if($act == 'get'){
|
}
|
||||||
$id = input('post.id/d');
|
|
||||||
if(!$id) return json(['code'=>-1, 'msg'=>'no id']);
|
public function log_data(){
|
||||||
$data = Db::name($tablename)->where('id', $id)->find();
|
$action = input('post.action', null, 'trim');
|
||||||
return json(['code'=>0, 'data'=>$data]);
|
$offset = input('post.offset/d');
|
||||||
}elseif($act == 'add'){
|
$limit = input('post.limit/d');
|
||||||
$ip = input('post.ip', null, 'trim');
|
|
||||||
if(!$ip) return json(['code'=>-1, 'msg'=>'IP不能为空']);
|
$select = Db::name('log');
|
||||||
if(Db::name($tablename)->where('ip', $ip)->find()){
|
if(!empty($action)){
|
||||||
return json(['code'=>-1, 'msg'=>'该IP已存在']);
|
$select->where('action', $action);
|
||||||
}
|
}
|
||||||
Db::name($tablename)->insert([
|
$total = $select->count();
|
||||||
'ip' => $ip,
|
$rows = $select->order('id','desc')->limit($offset, $limit)->select();
|
||||||
'enable' => 1,
|
|
||||||
'addtime' => date("Y-m-d H:i:s")
|
return json(['total'=>$total, 'rows'=>$rows]);
|
||||||
]);
|
}
|
||||||
return json(['code'=>0, 'msg'=>'succ']);
|
|
||||||
}elseif($act == 'edit'){
|
public function list(){
|
||||||
$id = input('post.id/d');
|
$type = input('param.type', 'black');
|
||||||
$ip = input('post.ip', null, 'trim');
|
View::assign('type', $type);
|
||||||
if(!$id || !$ip) return json(['code'=>-1, 'msg'=>'IP不能为空']);
|
View::assign('typename', $type=='white'?'白名单':'黑名单');
|
||||||
if(Db::name($tablename)->where('ip', $ip)->where('id', '<>', $id)->find()){
|
return view();
|
||||||
return json(['code'=>-1, 'msg'=>'该IP已存在']);
|
}
|
||||||
}
|
|
||||||
Db::name($tablename)->where('id', $id)->update([
|
public function list_data(){
|
||||||
'ip' => $ip
|
$type = input('param.type', 'black');
|
||||||
]);
|
$ip = input('post.ip', null, 'trim');
|
||||||
return json(['code'=>0, 'msg'=>'succ']);
|
$offset = input('post.offset/d');
|
||||||
}elseif($act == 'enable'){
|
$limit = input('post.limit/d');
|
||||||
$id = input('post.id/d');
|
|
||||||
$enable = input('post.enable/d');
|
$tablename = $type == 'black' ? 'black' : 'white';
|
||||||
if(!$id) return json(['code'=>-1, 'msg'=>'no id']);
|
$select = Db::name($tablename);
|
||||||
Db::name($tablename)->where('id', $id)->update([
|
if(!empty($ip)){
|
||||||
'enable' => $enable
|
$select->where('ip', $ip);
|
||||||
]);
|
}
|
||||||
return json(['code'=>0, 'msg'=>'succ']);
|
$total = $select->count();
|
||||||
}elseif($act == 'del'){
|
$rows = $select->order('id','desc')->limit($offset, $limit)->select();
|
||||||
$id = input('post.id/d');
|
|
||||||
if(!$id) return json(['code'=>-1, 'msg'=>'no id']);
|
return json(['total'=>$total, 'rows'=>$rows]);
|
||||||
Db::name($tablename)->where('id', $id)->delete();
|
}
|
||||||
return json(['code'=>0, 'msg'=>'succ']);
|
|
||||||
}
|
public function list_op(){
|
||||||
return json(['code'=>-1, 'msg'=>'no act']);
|
$type = input('param.type', 'black');
|
||||||
}
|
$tablename = $type == 'black' ? 'black' : 'white';
|
||||||
|
$act = input('post.act', null);
|
||||||
public function deplist(){
|
if($act == 'get'){
|
||||||
$deplist_linux = get_data_dir().'config/deployment_list.json';
|
$id = input('post.id/d');
|
||||||
$deplist_win = get_data_dir('Windows').'config/deployment_list.json';
|
if(!$id) return json(['code'=>-1, 'msg'=>'no id']);
|
||||||
$deplist_linux_time = file_exists($deplist_linux) ? date("Y-m-d H:i:s", filemtime($deplist_linux)) : '不存在';
|
$data = Db::name($tablename)->where('id', $id)->find();
|
||||||
$deplist_win_time = file_exists($deplist_win) ? date("Y-m-d H:i:s", filemtime($deplist_win)) : '不存在';
|
return json(['code'=>0, 'data'=>$data]);
|
||||||
View::assign('deplist_linux_time', $deplist_linux_time);
|
}elseif($act == 'add'){
|
||||||
View::assign('deplist_win_time', $deplist_win_time);
|
$ip = input('post.ip', null, 'trim');
|
||||||
return view();
|
if(!$ip) return json(['code'=>-1, 'msg'=>'IP不能为空']);
|
||||||
}
|
if(Db::name($tablename)->where('ip', $ip)->find()){
|
||||||
|
return json(['code'=>-1, 'msg'=>'该IP已存在']);
|
||||||
public function refresh_deplist(){
|
}
|
||||||
$os = input('get.os');
|
Db::name($tablename)->insert([
|
||||||
if(!$os) $os = 'Linux';
|
'ip' => $ip,
|
||||||
try{
|
'enable' => 1,
|
||||||
Plugins::refresh_deplist($os);
|
'addtime' => date("Y-m-d H:i:s")
|
||||||
Db::name('log')->insert(['uid' => 0, 'action' => '刷新一键部署列表', 'data' => '刷新'.$os.'一键部署列表成功', 'addtime' => date("Y-m-d H:i:s")]);
|
]);
|
||||||
return json(['code'=>0,'msg'=>'获取最新一键部署列表成功!']);
|
return json(['code'=>0, 'msg'=>'succ']);
|
||||||
}catch(\Exception $e){
|
}elseif($act == 'edit'){
|
||||||
return json(['code'=>-1, 'msg'=>$e->getMessage()]);
|
$id = input('post.id/d');
|
||||||
}
|
$ip = input('post.ip', null, 'trim');
|
||||||
}
|
if(!$id || !$ip) return json(['code'=>-1, 'msg'=>'IP不能为空']);
|
||||||
|
if(Db::name($tablename)->where('ip', $ip)->where('id', '<>', $id)->find()){
|
||||||
public function cleancache(){
|
return json(['code'=>-1, 'msg'=>'该IP已存在']);
|
||||||
Cache::clear();
|
}
|
||||||
return json(['code'=>0,'msg'=>'succ']);
|
Db::name($tablename)->where('id', $id)->update([
|
||||||
}
|
'ip' => $ip
|
||||||
|
]);
|
||||||
|
return json(['code'=>0, 'msg'=>'succ']);
|
||||||
|
}elseif($act == 'enable'){
|
||||||
|
$id = input('post.id/d');
|
||||||
|
$enable = input('post.enable/d');
|
||||||
|
if(!$id) return json(['code'=>-1, 'msg'=>'no id']);
|
||||||
|
Db::name($tablename)->where('id', $id)->update([
|
||||||
|
'enable' => $enable
|
||||||
|
]);
|
||||||
|
return json(['code'=>0, 'msg'=>'succ']);
|
||||||
|
}elseif($act == 'del'){
|
||||||
|
$id = input('post.id/d');
|
||||||
|
if(!$id) return json(['code'=>-1, 'msg'=>'no id']);
|
||||||
|
Db::name($tablename)->where('id', $id)->delete();
|
||||||
|
return json(['code'=>0, 'msg'=>'succ']);
|
||||||
|
}
|
||||||
|
return json(['code'=>-1, 'msg'=>'no act']);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function deplist(){
|
||||||
|
$deplist_linux = get_data_dir().'config/deployment_list.json';
|
||||||
|
$deplist_win = get_data_dir('Windows').'config/deployment_list.json';
|
||||||
|
$deplist_linux_time = file_exists($deplist_linux) ? date("Y-m-d H:i:s", filemtime($deplist_linux)) : '不存在';
|
||||||
|
$deplist_win_time = file_exists($deplist_win) ? date("Y-m-d H:i:s", filemtime($deplist_win)) : '不存在';
|
||||||
|
View::assign('deplist_linux_time', $deplist_linux_time);
|
||||||
|
View::assign('deplist_win_time', $deplist_win_time);
|
||||||
|
return view();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function refresh_deplist(){
|
||||||
|
$os = input('get.os');
|
||||||
|
if(!$os) $os = 'Linux';
|
||||||
|
try{
|
||||||
|
Plugins::refresh_deplist($os);
|
||||||
|
Db::name('log')->insert(['uid' => 0, 'action' => '刷新一键部署列表', 'data' => '刷新'.$os.'一键部署列表成功', 'addtime' => date("Y-m-d H:i:s")]);
|
||||||
|
return json(['code'=>0,'msg'=>'获取最新一键部署列表成功!']);
|
||||||
|
}catch(\Exception $e){
|
||||||
|
return json(['code'=>-1, 'msg'=>$e->getMessage()]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function cleancache(){
|
||||||
|
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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
@ -8,13 +8,13 @@ class Index extends BaseController
|
|||||||
{
|
{
|
||||||
public function index()
|
public function index()
|
||||||
{
|
{
|
||||||
return 'Server is ok';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
public function download()
|
public function download()
|
||||||
{
|
{
|
||||||
if(config_get('download_page') == '0' && !request()->islogin){
|
if(config_get('download_page') == '0' && !request()->islogin){
|
||||||
return redirect('/admin/login');
|
return 'need login';
|
||||||
}
|
}
|
||||||
View::assign('siteurl', request()->root(true));
|
View::assign('siteurl', request()->root(true));
|
||||||
return view();
|
return view();
|
||||||
|
|||||||
308
app/lib/BtPlugins.php
Normal file
308
app/lib/BtPlugins.php
Normal file
@ -0,0 +1,308 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace app\lib;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
use ZipArchive;
|
||||||
|
|
||||||
|
class BtPlugins
|
||||||
|
{
|
||||||
|
private $btapi;
|
||||||
|
private $os;
|
||||||
|
|
||||||
|
//需屏蔽的插件名称列表
|
||||||
|
public static $block_plugins = ['dns', 'bt_boce', 'ssl_verify', 'firewall', 'KylinOperatingSystem', 'KingdeeApusicDistributedCache', 'BorlandCacheServer', 'GBase8s', 'KingdeeApusicLoadBalancer', 'BorlandWebServer'];
|
||||||
|
public static $skip_plugins = ['php_filter', 'enterprise_backup', 'tamper_drive'];
|
||||||
|
|
||||||
|
public function __construct($os){
|
||||||
|
$this->os = $os;
|
||||||
|
if($os == 'en'){
|
||||||
|
$bt_url = config_get('enbt_url');
|
||||||
|
$bt_key = config_get('enbt_key');
|
||||||
|
}elseif($os == 'Windows'){
|
||||||
|
$bt_url = config_get('wbt_url');
|
||||||
|
$bt_key = config_get('wbt_key');
|
||||||
|
}else{
|
||||||
|
$bt_url = config_get('bt_url');
|
||||||
|
$bt_key = config_get('bt_key');
|
||||||
|
}
|
||||||
|
if(!$bt_url || !$bt_key) throw new Exception('请先配置好宝塔面板接口信息');
|
||||||
|
$this->btapi = new Btapi($bt_url, $bt_key);
|
||||||
|
}
|
||||||
|
|
||||||
|
//获取插件列表
|
||||||
|
public function get_plugin_list(){
|
||||||
|
$result = $this->btapi->get_plugin_list();
|
||||||
|
if($result && isset($result['list']) && isset($result['type'])){
|
||||||
|
if(empty($result['list']) || empty($result['type'])){
|
||||||
|
throw new Exception('获取插件列表失败:插件列表为空');
|
||||||
|
}
|
||||||
|
$newlist = [];
|
||||||
|
foreach($result['list'] as $item){
|
||||||
|
if(!in_array($item['name'], self::$block_plugins)) $newlist[] = $item;
|
||||||
|
}
|
||||||
|
$result['list'] = $newlist;
|
||||||
|
return $result;
|
||||||
|
}else{
|
||||||
|
throw new Exception('获取插件列表失败:'.(isset($result['msg'])?$result['msg']:'面板连接失败'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//下载插件(自动判断是否第三方)
|
||||||
|
public function download_plugin($plugin_name, $version, $plugin_info){
|
||||||
|
if($plugin_info['type'] == 10 && isset($plugin_info['versions'][0]['download'])){
|
||||||
|
if($plugin_info['price'] == 0){
|
||||||
|
$this->btapi->create_plugin_other_order($plugin_info['id']);
|
||||||
|
}
|
||||||
|
$fname = $plugin_info['versions'][0]['download'];
|
||||||
|
$filemd5 = $plugin_info['versions'][0]['md5'];
|
||||||
|
$this->download_plugin_other($fname, $filemd5);
|
||||||
|
if(isset($plugin_info['min_image']) && strpos($plugin_info['min_image'], 'fname=')){
|
||||||
|
$fname = substr($plugin_info['min_image'], strpos($plugin_info['min_image'], '?fname=')+7);
|
||||||
|
$this->download_plugin_other($fname);
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
$this->download_plugin_package($plugin_name, $version);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//下载插件包
|
||||||
|
private function download_plugin_package($plugin_name, $version){
|
||||||
|
$filepath = get_data_dir($this->os).'plugins/package/'.$plugin_name.'-'.$version.'.zip';
|
||||||
|
$result = $this->btapi->get_plugin_filename($plugin_name, $version);
|
||||||
|
if($result && isset($result['status'])){
|
||||||
|
if($result['status'] == true){
|
||||||
|
$filename = $result['filename'];
|
||||||
|
$this->download_file($filename, $filepath);
|
||||||
|
if(file_exists($filepath)){
|
||||||
|
$zip = new ZipArchive;
|
||||||
|
if ($zip->open($filepath) === true)
|
||||||
|
{
|
||||||
|
$plugins_dir = get_data_dir($this->os).'plugins/folder/'.$plugin_name.'-'.$version;
|
||||||
|
$zip->extractTo($plugins_dir, $plugin_name.'/'.$plugin_name.'_main.py');
|
||||||
|
$zip->close();
|
||||||
|
$main_filepath = $plugins_dir.'/'.$plugin_name.'/'.$plugin_name.'_main.py';
|
||||||
|
if(file_exists($main_filepath) && filesize($main_filepath)>10){
|
||||||
|
if(!strpos(file_get_contents($main_filepath), 'import ')){ //加密py文件,需要解密
|
||||||
|
$this->decode_plugin_main($plugin_name, $version, $main_filepath);
|
||||||
|
$this->noauth_plugin_main($main_filepath);
|
||||||
|
$zip->open($filepath, ZipArchive::CREATE);
|
||||||
|
$zip->addFile($main_filepath, $plugin_name.'/'.$plugin_name.'_main.py');
|
||||||
|
$zip->close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
deleteDir($plugins_dir);
|
||||||
|
}else{
|
||||||
|
unlink($filepath);
|
||||||
|
throw new Exception('插件包解压缩失败');
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}else{
|
||||||
|
throw new Exception('下载插件包失败,本地文件不存在');
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
throw new Exception('下载插件包失败:'.($result['msg']?$result['msg']:'未知错误'));
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
throw new Exception('下载插件包失败,接口返回错误');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//下载插件主程序文件
|
||||||
|
public function download_plugin_main($plugin_name, $version){
|
||||||
|
$filepath = get_data_dir($this->os).'plugins/main/'.$plugin_name.'-'.$version.'.dat';
|
||||||
|
$result = $this->btapi->get_plugin_main_filename($plugin_name, $version);
|
||||||
|
if($result && isset($result['status'])){
|
||||||
|
if($result['status'] == true){
|
||||||
|
$filename = $result['filename'];
|
||||||
|
$this->download_file($filename, $filepath);
|
||||||
|
if(file_exists($filepath)){
|
||||||
|
return true;
|
||||||
|
}else{
|
||||||
|
throw new Exception('下载插件主程序文件失败,本地文件不存在');
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
throw new Exception('下载插件主程序文件失败:'.($result['msg']?$result['msg']:'未知错误'));
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
throw new Exception('下载插件主程序文件失败,接口返回错误');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//解密并下载插件主程序文件
|
||||||
|
private function decode_plugin_main($plugin_name, $version, $main_filepath){
|
||||||
|
if($this->decode_plugin_main_local($main_filepath)) return true;
|
||||||
|
$result = $this->btapi->get_decode_plugin_main($plugin_name, $version);
|
||||||
|
if($result && isset($result['status'])){
|
||||||
|
if($result['status'] == true){
|
||||||
|
$filename = $result['filename'];
|
||||||
|
$this->download_file($filename, $main_filepath);
|
||||||
|
return true;
|
||||||
|
}else{
|
||||||
|
throw new Exception('解密插件主程序文件失败:'.($result['msg']?$result['msg']:'未知错误'));
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
throw new Exception('解密插件主程序文件失败,接口返回错误');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//本地解密插件主程序文件
|
||||||
|
public function decode_plugin_main_local($main_filepath){
|
||||||
|
$userinfo = $this->btapi->get_user_info();
|
||||||
|
if(isset($userinfo['uid'])){
|
||||||
|
$src = file_get_contents($main_filepath);
|
||||||
|
if($src===false)throw new Exception('文件打开失败');
|
||||||
|
if(!$src || strpos($src, 'import ')!==false)return true;
|
||||||
|
$uid = $userinfo['uid'];
|
||||||
|
$serverid = $userinfo['serverid'];
|
||||||
|
$key = md5(substr($serverid, 10, 16).$uid.$serverid);
|
||||||
|
$iv = md5($key.$serverid);
|
||||||
|
$key = substr($key, 8, 16);
|
||||||
|
$iv = substr($iv, 8, 16);
|
||||||
|
$data_arr = explode("\n", $src);
|
||||||
|
$de_text = '';
|
||||||
|
foreach($data_arr as $data){
|
||||||
|
$data = trim($data);
|
||||||
|
if(!empty($data)){
|
||||||
|
$tmp = openssl_decrypt($data, 'aes-128-cbc', $key, 0, $iv);
|
||||||
|
if($tmp !== false) $de_text .= $tmp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(!empty($de_text) && strpos($de_text, 'import ')!==false){
|
||||||
|
file_put_contents($main_filepath, $de_text);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}else{
|
||||||
|
throw new Exception('解密插件主程序文件失败,获取用户信息失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//去除插件主程序文件授权校验
|
||||||
|
private function noauth_plugin_main($main_filepath){
|
||||||
|
$data = file_get_contents($main_filepath);
|
||||||
|
if(!$data) return false;
|
||||||
|
|
||||||
|
$data = str_replace('\'http://www.bt.cn/api/panel/get_soft_list_test', 'public.GetConfigValue(\'home\')+\'/api/panel/get_soft_list_test', $data);
|
||||||
|
$data = str_replace('\'https://www.bt.cn/api/panel/get_soft_list_test', 'public.GetConfigValue(\'home\')+\'/api/panel/get_soft_list_test', $data);
|
||||||
|
$data = str_replace('\'http://www.bt.cn/api/panel/get_soft_list', 'public.GetConfigValue(\'home\')+\'/api/panel/get_soft_list', $data);
|
||||||
|
$data = str_replace('\'https://www.bt.cn/api/panel/get_soft_list', 'public.GetConfigValue(\'home\')+\'/api/panel/get_soft_list', $data);
|
||||||
|
$data = str_replace('\'http://www.bt.cn/api/panel/notpro', 'public.GetConfigValue(\'home\')+\'/api/panel/notpro', $data);
|
||||||
|
$data = str_replace('\'https://www.bt.cn/api/panel/notpro', 'public.GetConfigValue(\'home\')+\'/api/panel/notpro', $data);
|
||||||
|
|
||||||
|
$data = str_replace('\'http://www.bt.cn/api/wpanel/get_soft_list_test', 'public.GetConfigValue(\'home\')+\'/api/wpanel/get_soft_list_test', $data);
|
||||||
|
$data = str_replace('\'https://www.bt.cn/api/wpanel/get_soft_list_test', 'public.GetConfigValue(\'home\')+\'/api/wpanel/get_soft_list_test', $data);
|
||||||
|
$data = str_replace('\'http://www.bt.cn/api/wpanel/get_soft_list', 'public.GetConfigValue(\'home\')+\'/api/wpanel/get_soft_list', $data);
|
||||||
|
$data = str_replace('\'https://www.bt.cn/api/wpanel/get_soft_list', 'public.GetConfigValue(\'home\')+\'/api/wpanel/get_soft_list', $data);
|
||||||
|
$data = str_replace('\'http://www.bt.cn/api/wpanel/notpro', 'public.GetConfigValue(\'home\')+\'/api/wpanel/notpro', $data);
|
||||||
|
$data = str_replace('\'https://www.bt.cn/api/wpanel/notpro', 'public.GetConfigValue(\'home\')+\'/api/wpanel/notpro', $data);
|
||||||
|
|
||||||
|
$data = str_replace('"https://www.bt.cn/api/bt_waf/get_malicious', 'public.GetConfigValue(\'home\')+"/api/bt_waf/get_malicious', $data);
|
||||||
|
$data = str_replace('\'http://www.bt.cn/api/bt_waf/getSpiders', 'public.GetConfigValue(\'home\')+\'/api/bt_waf/getSpiders', $data);
|
||||||
|
$data = str_replace('\'https://www.bt.cn/api/bt_waf/getSpiders', 'public.GetConfigValue(\'home\')+\'/api/bt_waf/getSpiders', $data);
|
||||||
|
$data = str_replace('\'http://www.bt.cn/api/bt_waf/addSpider', 'public.GetConfigValue(\'home\')+\'/api/bt_waf/addSpider', $data);
|
||||||
|
$data = str_replace('\'https://www.bt.cn/api/bt_waf/addSpider', 'public.GetConfigValue(\'home\')+\'/api/bt_waf/addSpider', $data);
|
||||||
|
$data = str_replace('\'https://www.bt.cn/api/bt_waf/getVulScanInfoList', 'public.GetConfigValue(\'home\')+\'/api/bt_waf/getVulScanInfoList', $data);
|
||||||
|
$data = str_replace('\'https://www.bt.cn/api/bt_waf/reportInterceptFail', 'public.GetConfigValue(\'home\')+\'/api/bt_waf/reportInterceptFail', $data);
|
||||||
|
$data = str_replace('"https://www.bt.cn/api/bt_waf/reportInterceptFail', 'public.GetConfigValue(\'home\')+"/api/bt_waf/reportInterceptFail', $data);
|
||||||
|
$data = str_replace('\'https://www.bt.cn/api/v2/contact/nps/questions', 'public.GetConfigValue(\'home\')+\'/panel/notpro', $data);
|
||||||
|
$data = str_replace('\'https://www.bt.cn/api/v2/contact/nps/submit', 'public.GetConfigValue(\'home\')+\'/panel/notpro', $data);
|
||||||
|
$data = str_replace('\'http://www.bt.cn/api/Auth', 'public.GetConfigValue(\'home\')+\'/api/Auth', $data);
|
||||||
|
$data = str_replace('\'https://www.bt.cn/api/Auth', 'public.GetConfigValue(\'home\')+\'/api/Auth', $data);
|
||||||
|
|
||||||
|
$data = str_replace('\'https://brandnew.aapanel.com/api/panel/getSoftList', 'public.OfficialApiBase()+\'/api/panel/getSoftList', $data);
|
||||||
|
|
||||||
|
file_put_contents($main_filepath, $data);
|
||||||
|
}
|
||||||
|
|
||||||
|
//下载插件其他文件
|
||||||
|
private function download_plugin_other($fname, $filemd5 = null){
|
||||||
|
$filepath = get_data_dir().'plugins/other/'.$fname;
|
||||||
|
@mkdir(dirname($filepath), 0777, true);
|
||||||
|
$result = $this->btapi->get_plugin_other_filename($fname);
|
||||||
|
if($result && isset($result['status'])){
|
||||||
|
if($result['status'] == true){
|
||||||
|
$filename = $result['filename'];
|
||||||
|
$this->download_file($filename, $filepath);
|
||||||
|
if(file_exists($filepath)){
|
||||||
|
if($filemd5 && md5_file($filepath) != $filemd5){
|
||||||
|
$msg = filesize($filepath) < 300 ? file_get_contents($filepath) : '插件文件MD5校验失败';
|
||||||
|
@unlink($filepath);
|
||||||
|
throw new Exception($msg);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}else{
|
||||||
|
throw new Exception('下载插件文件失败,本地文件不存在');
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
throw new Exception('下载插件文件失败:'.($result['msg']?$result['msg']:'未知错误'));
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
throw new Exception('下载插件文件失败,接口返回错误');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//下载文件
|
||||||
|
private function download_file($filename, $filepath){
|
||||||
|
try{
|
||||||
|
$this->btapi->download($filename, $filepath);
|
||||||
|
}catch(Exception $e){
|
||||||
|
@unlink($filepath);
|
||||||
|
//宝塔bug小文件下载失败,改用base64下载
|
||||||
|
$result = $this->btapi->get_file($filename);
|
||||||
|
if($result && isset($result['status']) && $result['status']==true){
|
||||||
|
$filedata = base64_decode($result['data']);
|
||||||
|
if(strlen($filedata) < 4096 && substr($filedata,0,1)=='{' && substr($filedata,-1,1)=='}'){
|
||||||
|
$arr = json_decode($filedata, true);
|
||||||
|
if($arr){
|
||||||
|
throw new Exception('获取文件失败:'.($arr['msg']?$arr['msg']:'未知错误'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(!$filedata){
|
||||||
|
throw new Exception('获取文件失败:文件内容为空');
|
||||||
|
}
|
||||||
|
file_put_contents($filepath, $filedata);
|
||||||
|
}elseif($result){
|
||||||
|
throw new Exception('获取文件失败:'.($result['msg']?$result['msg']:'未知错误'));
|
||||||
|
}else{
|
||||||
|
throw new Exception('获取文件失败:未知错误');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//获取一键部署列表
|
||||||
|
public function get_deplist(){
|
||||||
|
$result = $this->btapi->get_deplist();
|
||||||
|
if($result && isset($result['list']) && isset($result['type'])){
|
||||||
|
if(empty($result['list']) || empty($result['type'])){
|
||||||
|
throw new Exception('获取一键部署列表失败:一键部署列表为空');
|
||||||
|
}
|
||||||
|
return $result;
|
||||||
|
}else{
|
||||||
|
throw new Exception('获取一键部署列表失败:'.(isset($result['msg'])?$result['msg']:'面板连接失败'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//获取蜘蛛IP列表
|
||||||
|
public function btwaf_getspiders(){
|
||||||
|
$result = $this->btapi->btwaf_getspiders();
|
||||||
|
if(isset($result['status']) && $result['status']){
|
||||||
|
return $result['data'];
|
||||||
|
}else{
|
||||||
|
throw new Exception(isset($result['msg'])?$result['msg']:'获取失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//获取堡塔恶意情报IP库
|
||||||
|
public function btwaf_getmalicious(){
|
||||||
|
$result = $this->btapi->btwaf_getmalicious();
|
||||||
|
if(isset($result['success'])){
|
||||||
|
return $result;
|
||||||
|
}elseif(isset($result['msg'])){
|
||||||
|
throw new Exception($result['msg']);
|
||||||
|
}else{
|
||||||
|
throw new Exception(isset($result['res'])?$result['res']:'获取失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -1,230 +1,266 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace app\lib;
|
namespace app\lib;
|
||||||
|
|
||||||
use Exception;
|
use Exception;
|
||||||
|
|
||||||
class Btapi
|
class Btapi
|
||||||
{
|
{
|
||||||
private $BT_KEY; //接口密钥
|
private $BT_KEY; //接口密钥
|
||||||
private $BT_PANEL; //面板地址
|
private $BT_PANEL; //面板地址
|
||||||
|
|
||||||
public function __construct($bt_panel, $bt_key){
|
public function __construct($bt_panel, $bt_key){
|
||||||
$this->BT_PANEL = $bt_panel;
|
$this->BT_PANEL = $bt_panel;
|
||||||
$this->BT_KEY = $bt_key;
|
$this->BT_KEY = $bt_key;
|
||||||
}
|
}
|
||||||
|
|
||||||
//获取面板配置信息
|
//获取面板配置信息
|
||||||
public function get_config(){
|
public function get_config(){
|
||||||
$url = $this->BT_PANEL.'/config?action=get_config';
|
$url = $this->BT_PANEL.'/config?action=get_config';
|
||||||
|
|
||||||
$p_data = $this->GetKeyData();
|
$p_data = $this->GetKeyData();
|
||||||
|
|
||||||
$result = $this->curl($url,$p_data);
|
$result = $this->curl($url,$p_data);
|
||||||
|
|
||||||
$data = json_decode($result,true);
|
$data = json_decode($result,true);
|
||||||
return $data;
|
return $data;
|
||||||
}
|
}
|
||||||
|
|
||||||
//获取已登录用户信息
|
public function get_config_go(){
|
||||||
public function get_user_info(){
|
$url = $this->BT_PANEL.'/panel/get_config';
|
||||||
$url = $this->BT_PANEL.'/plugin?action=a&name=kaixin&s=get_user_info';
|
|
||||||
|
$p_data = $this->GetKeyData();
|
||||||
$p_data = $this->GetKeyData();
|
|
||||||
|
$result = $this->curl($url,$p_data);
|
||||||
$result = $this->curl($url,$p_data);
|
|
||||||
|
$data = json_decode($result,true);
|
||||||
$data = json_decode($result,true);
|
return $data;
|
||||||
return $data;
|
}
|
||||||
}
|
|
||||||
|
//获取已登录用户信息
|
||||||
//从云端获取插件列表
|
public function get_user_info(){
|
||||||
public function get_plugin_list(){
|
$url = $this->BT_PANEL.'/plugin?action=a&name=kaixin&s=get_user_info';
|
||||||
$url = $this->BT_PANEL.'/plugin?action=a&name=kaixin&s=get_plugin_list';
|
|
||||||
|
$p_data = $this->GetKeyData();
|
||||||
$p_data = $this->GetKeyData();
|
|
||||||
|
$result = $this->curl($url,$p_data);
|
||||||
$result = $this->curl($url,$p_data);
|
|
||||||
|
$data = json_decode($result,true);
|
||||||
$data = json_decode($result,true);
|
return $data;
|
||||||
return $data;
|
}
|
||||||
}
|
|
||||||
|
//从云端获取插件列表
|
||||||
//下载插件包,返回文件路径
|
public function get_plugin_list(){
|
||||||
public function get_plugin_filename($plugin_name, $version){
|
$url = $this->BT_PANEL.'/plugin?action=a&name=kaixin&s=get_plugin_list';
|
||||||
$url = $this->BT_PANEL.'/plugin?action=a&name=kaixin&s=download_plugin';
|
|
||||||
|
$p_data = $this->GetKeyData();
|
||||||
$p_data = $this->GetKeyData();
|
|
||||||
$p_data['plugin_name'] = $plugin_name;
|
$result = $this->curl($url,$p_data);
|
||||||
$p_data['version'] = $version;
|
|
||||||
|
$data = json_decode($result,true);
|
||||||
$result = $this->curl($url,$p_data);
|
return $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';
|
||||||
//下载插件主程序文件,返回文件路径
|
|
||||||
public function get_plugin_main_filename($plugin_name, $version){
|
$p_data = $this->GetKeyData();
|
||||||
$url = $this->BT_PANEL.'/plugin?action=a&name=kaixin&s=download_plugin_main';
|
$p_data['plugin_name'] = $plugin_name;
|
||||||
|
$p_data['version'] = $version;
|
||||||
$p_data = $this->GetKeyData();
|
|
||||||
$p_data['plugin_name'] = $plugin_name;
|
$result = $this->curl($url,$p_data);
|
||||||
$p_data['version'] = $version;
|
|
||||||
|
$data = json_decode($result,true);
|
||||||
$result = $this->curl($url,$p_data);
|
return $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';
|
||||||
//解密插件主程序py代码,返回文件路径
|
|
||||||
public function get_decode_plugin_main($plugin_name, $version){
|
$p_data = $this->GetKeyData();
|
||||||
$url = $this->BT_PANEL.'/plugin?action=a&name=kaixin&s=decode_plugin_main';
|
$p_data['plugin_name'] = $plugin_name;
|
||||||
|
$p_data['version'] = $version;
|
||||||
$p_data = $this->GetKeyData();
|
|
||||||
$p_data['plugin_name'] = $plugin_name;
|
$result = $this->curl($url,$p_data);
|
||||||
$p_data['version'] = $version;
|
|
||||||
|
$data = json_decode($result,true);
|
||||||
$result = $this->curl($url,$p_data);
|
return $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';
|
||||||
//下载插件其他文件,返回文件路径
|
|
||||||
public function get_plugin_other_filename($fname){
|
$p_data = $this->GetKeyData();
|
||||||
$url = $this->BT_PANEL.'/plugin?action=a&name=kaixin&s=download_plugin_other';
|
$p_data['plugin_name'] = $plugin_name;
|
||||||
|
$p_data['version'] = $version;
|
||||||
$p_data = $this->GetKeyData();
|
|
||||||
$p_data['fname'] = $fname;
|
$result = $this->curl($url,$p_data);
|
||||||
|
|
||||||
$result = $this->curl($url,$p_data);
|
$data = json_decode($result,true);
|
||||||
|
return $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';
|
||||||
public function download($filename, $localpath){
|
|
||||||
$url = $this->BT_PANEL.'/download';
|
$p_data = $this->GetKeyData();
|
||||||
|
$p_data['fname'] = $fname;
|
||||||
$p_data = $this->GetKeyData();
|
|
||||||
$p_data['filename'] = $filename;
|
$result = $this->curl($url,$p_data);
|
||||||
|
|
||||||
$result = $this->curl_download($url.'?'.http_build_query($p_data), $localpath);
|
$data = json_decode($result,true);
|
||||||
|
return $data;
|
||||||
return $result;
|
}
|
||||||
}
|
|
||||||
|
//下载文件
|
||||||
//获取文件base64
|
public function download($filename, $localpath){
|
||||||
public function get_file($filename){
|
$url = $this->BT_PANEL.'/download';
|
||||||
$url = $this->BT_PANEL.'/plugin?action=a&name=kaixin&s=get_file';
|
|
||||||
|
$p_data = $this->GetKeyData();
|
||||||
$p_data = $this->GetKeyData();
|
$p_data['filename'] = $filename;
|
||||||
$p_data['filename'] = $filename;
|
|
||||||
|
$result = $this->curl_download($url.'?'.http_build_query($p_data), $localpath);
|
||||||
$result = $this->curl($url,$p_data);
|
|
||||||
|
return $result;
|
||||||
$data = json_decode($result,true);
|
}
|
||||||
return $data;
|
|
||||||
}
|
//获取文件base64
|
||||||
|
public function get_file($filename){
|
||||||
//购买第三方插件
|
$url = $this->BT_PANEL.'/plugin?action=a&name=kaixin&s=get_file';
|
||||||
public function create_plugin_other_order($pid){
|
|
||||||
$url = $this->BT_PANEL.'/auth?action=create_plugin_other_order';
|
$p_data = $this->GetKeyData();
|
||||||
|
$p_data['filename'] = $filename;
|
||||||
$p_data = $this->GetKeyData();
|
|
||||||
$p_data['pid'] = $pid;
|
$result = $this->curl($url,$p_data);
|
||||||
$p_data['cycle'] = '999';
|
|
||||||
$p_data['type'] = '0';
|
$data = json_decode($result,true);
|
||||||
|
return $data;
|
||||||
$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();
|
||||||
public function get_deplist(){
|
$p_data['pid'] = $pid;
|
||||||
$url = $this->BT_PANEL.'/plugin?action=a&name=kaixin&s=get_deplist';
|
$p_data['cycle'] = '999';
|
||||||
|
$p_data['type'] = '0';
|
||||||
$p_data = $this->GetKeyData();
|
|
||||||
|
$result = $this->curl($url,$p_data);
|
||||||
$result = $this->curl($url,$p_data);
|
|
||||||
|
$data = json_decode($result,true);
|
||||||
$data = json_decode($result,true);
|
return $data;
|
||||||
return $data;
|
}
|
||||||
}
|
|
||||||
|
//获取一键部署列表
|
||||||
|
public function get_deplist(){
|
||||||
private function GetKeyData(){
|
$url = $this->BT_PANEL.'/plugin?action=a&name=kaixin&s=get_deplist';
|
||||||
$now_time = time();
|
|
||||||
$p_data = array(
|
$p_data = $this->GetKeyData();
|
||||||
'request_token' => md5($now_time.''.md5($this->BT_KEY)),
|
|
||||||
'request_time' => $now_time
|
$result = $this->curl($url,$p_data);
|
||||||
);
|
|
||||||
return $p_data;
|
$data = json_decode($result,true);
|
||||||
}
|
return $data;
|
||||||
|
}
|
||||||
|
|
||||||
private function curl($url, $data = null, $timeout = 60)
|
//BTWAF-获取蜘蛛列表
|
||||||
{
|
public function btwaf_getspiders(){
|
||||||
//定义cookie保存位置
|
$url = $this->BT_PANEL.'/plugin?action=a&name=kaixin&s=btwaf_getspiders';
|
||||||
$cookie_file=app()->getRuntimePath().md5($this->BT_PANEL).'.cookie';
|
|
||||||
if(!file_exists($cookie_file)){
|
$p_data = $this->GetKeyData();
|
||||||
touch($cookie_file);
|
|
||||||
}
|
$result = $this->curl($url,$p_data);
|
||||||
|
$result = str_replace("\u0000", '', $result);
|
||||||
$ch = curl_init();
|
|
||||||
curl_setopt($ch, CURLOPT_URL, $url);
|
$data = json_decode($result,true);
|
||||||
curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
|
return $data;
|
||||||
if($data){
|
}
|
||||||
curl_setopt($ch, CURLOPT_POST, 1);
|
|
||||||
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
|
//BTWAF-获取堡塔恶意情报IP库
|
||||||
}
|
public function btwaf_getmalicious(){
|
||||||
curl_setopt($ch, CURLOPT_COOKIEJAR, $cookie_file);
|
$url = $this->BT_PANEL.'/plugin?action=a&name=kaixin&s=btwaf_getmalicious';
|
||||||
curl_setopt($ch, CURLOPT_COOKIEFILE, $cookie_file);
|
|
||||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
|
$p_data = $this->GetKeyData();
|
||||||
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
|
|
||||||
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
|
$result = $this->curl($url,$p_data);
|
||||||
$output = curl_exec($ch);
|
|
||||||
curl_close($ch);
|
$data = json_decode($result,true);
|
||||||
return $output;
|
return $data;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function curl_download($url, $localpath, $timeout = 300)
|
|
||||||
{
|
private function GetKeyData(){
|
||||||
//定义cookie保存位置
|
$now_time = time();
|
||||||
$cookie_file=app()->getRuntimePath().md5($this->BT_PANEL).'.cookie';
|
$p_data = array(
|
||||||
if(!file_exists($cookie_file)){
|
'request_token' => md5($now_time.''.md5($this->BT_KEY)),
|
||||||
touch($cookie_file);
|
'request_time' => $now_time
|
||||||
}
|
);
|
||||||
|
return $p_data;
|
||||||
$ch = curl_init();
|
}
|
||||||
curl_setopt($ch, CURLOPT_URL, $url);
|
|
||||||
curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
|
|
||||||
curl_setopt($ch, CURLOPT_COOKIEJAR, $cookie_file);
|
private function curl($url, $data = null, $timeout = 60)
|
||||||
curl_setopt($ch, CURLOPT_COOKIEFILE, $cookie_file);
|
{
|
||||||
$fp = fopen($localpath, 'w+');
|
//定义cookie保存位置
|
||||||
curl_setopt($ch, CURLOPT_FILE, $fp);
|
$cookie_file=app()->getRuntimePath().md5($this->BT_PANEL).'.cookie';
|
||||||
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
|
if(!file_exists($cookie_file)){
|
||||||
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
|
touch($cookie_file);
|
||||||
curl_exec($ch);
|
}
|
||||||
if (curl_errno($ch)) {
|
|
||||||
$message = curl_error($ch);
|
$ch = curl_init();
|
||||||
curl_close($ch);
|
curl_setopt($ch, CURLOPT_URL, $url);
|
||||||
fclose($fp);
|
curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
|
||||||
throw new Exception('下载文件失败:'.$message);
|
if($data){
|
||||||
}
|
curl_setopt($ch, CURLOPT_POST, 1);
|
||||||
$httpcode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
|
||||||
if($httpcode>299){
|
}
|
||||||
curl_close($ch);
|
curl_setopt($ch, CURLOPT_COOKIEJAR, $cookie_file);
|
||||||
fclose($fp);
|
curl_setopt($ch, CURLOPT_COOKIEFILE, $cookie_file);
|
||||||
throw new Exception('下载文件失败:HTTPCODE-'.$httpcode);
|
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
|
||||||
}
|
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
|
||||||
curl_close($ch);
|
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
|
||||||
fclose($fp);
|
$output = curl_exec($ch);
|
||||||
return true;
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -1,347 +1,218 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace app\lib;
|
namespace app\lib;
|
||||||
|
|
||||||
use Exception;
|
use Exception;
|
||||||
use ZipArchive;
|
use ZipArchive;
|
||||||
|
|
||||||
class Plugins
|
class Plugins
|
||||||
{
|
{
|
||||||
|
|
||||||
private static function get_btapi($os){
|
private static function get_btapi($os){
|
||||||
if($os == 'Windows'){
|
if(self::is_third($os)){
|
||||||
$bt_url = config_get('wbt_url');
|
return new ThirdPlugins($os);
|
||||||
$bt_key = config_get('wbt_key');
|
}else{
|
||||||
}else{
|
return new BtPlugins($os);
|
||||||
$bt_url = config_get('bt_url');
|
}
|
||||||
$bt_key = config_get('bt_key');
|
}
|
||||||
}
|
|
||||||
if(!$bt_url || !$bt_key) throw new Exception('请先配置好宝塔面板接口信息');
|
private static function is_third($os){
|
||||||
$btapi = new Btapi($bt_url, $bt_key);
|
if($os == 'en'){
|
||||||
return $btapi;
|
$type = config_get('enbt_type');
|
||||||
}
|
}elseif($os == 'Windows'){
|
||||||
|
$type = config_get('wbt_type');
|
||||||
//刷新插件列表
|
}else{
|
||||||
public static function refresh_plugin_list($os = 'Linux'){
|
$type = config_get('bt_type');
|
||||||
$btapi = self::get_btapi($os);
|
}
|
||||||
$result = $btapi->get_plugin_list();
|
return $type == 1;
|
||||||
if($result && isset($result['list']) && isset($result['type'])){
|
}
|
||||||
if(empty($result['list']) || empty($result['type'])){
|
|
||||||
throw new Exception('获取插件列表失败:插件列表为空');
|
//刷新插件列表
|
||||||
}
|
public static function refresh_plugin_list($os = 'Linux'){
|
||||||
self::save_plugin_list($result, $os);
|
$btapi = self::get_btapi($os);
|
||||||
}else{
|
$result = $btapi->get_plugin_list();
|
||||||
throw new Exception('获取插件列表失败:'.(isset($result['msg'])?$result['msg']:'面板连接失败'));
|
self::save_plugin_list($result, $os);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
//保存插件列表
|
||||||
//保存插件列表
|
private static function save_plugin_list($data, $os){
|
||||||
private static function save_plugin_list($data, $os){
|
$data['ip'] = '127.0.0.1';
|
||||||
$data['ip'] = '127.0.0.1';
|
if($os == 'en'){
|
||||||
$data['serverid'] = '';
|
$data['serverId'] = '';
|
||||||
$data['beta'] = 0;
|
$data['aln'] = self::get_aln();
|
||||||
$data['uid'] = 1;
|
$data['pro'] = 0;
|
||||||
$data['skey'] = '';
|
$data['pro_authorization_sn'] = '0';
|
||||||
$list = [];
|
if(!empty($data['authorization_map'])){
|
||||||
foreach($data['list'] as $plugin){
|
foreach($data['authorization_map'] as $code => &$plugin){
|
||||||
if(isset($plugin['endtime'])) $plugin['endtime'] = 0;
|
if($code != '0' && isset($plugin['end_time'])) $plugin['end_time'] = 0;
|
||||||
$list[] = $plugin;
|
}
|
||||||
}
|
}
|
||||||
$data['list'] = $list;
|
if(isset($data['expansions']['mail'])){
|
||||||
$data['ltd'] = strtotime('+10 year');
|
$data['expansions']['mail']['total'] = 2000000;
|
||||||
$json_file = get_data_dir($os).'config/plugin_list.json';
|
$data['expansions']['mail']['available'] = 2000000;
|
||||||
if(!file_put_contents($json_file, json_encode($data))){
|
}
|
||||||
throw new Exception('保存插件列表失败,文件无写入权限');
|
}else{
|
||||||
}
|
$data['serverid'] = '';
|
||||||
}
|
$data['aln'] = self::get_aln();
|
||||||
|
$data['beta'] = 0;
|
||||||
//获取插件列表
|
$data['uid'] = 1;
|
||||||
public static function get_plugin_list($os = 'Linux'){
|
$data['skey'] = '';
|
||||||
$json_file = get_data_dir($os).'config/plugin_list.json';
|
$data['pro'] = -1;
|
||||||
if(file_exists($json_file)){
|
$data['ltd'] = strtotime('+10 year');
|
||||||
$data = file_get_contents($json_file);
|
}
|
||||||
$json_arr = json_decode($data, true);
|
foreach($data['list'] as &$plugin){
|
||||||
if($json_arr){
|
if(isset($plugin['endtime'])) $plugin['endtime'] = 0;
|
||||||
return $json_arr;
|
}
|
||||||
}
|
$json_file = get_data_dir($os).'config/plugin_list.json';
|
||||||
}
|
if(!file_put_contents($json_file, json_encode($data))){
|
||||||
return false;
|
throw new Exception('保存插件列表失败,文件无写入权限');
|
||||||
}
|
}
|
||||||
|
}
|
||||||
//获取一个插件信息
|
|
||||||
public static function get_plugin_info($name, $os = 'Linux'){
|
//多账号数量
|
||||||
$json_arr = self::get_plugin_list($os);
|
private static function get_aln($count = '9999'){
|
||||||
if(!$json_arr) return null;
|
$key = 'FB8upo8XMgP5by54';
|
||||||
foreach($json_arr['list'] as $plugin){
|
$iv = 'lOrrq3lNEURZNdK7';
|
||||||
if($plugin['name'] == $name){
|
return openssl_encrypt($count, 'aes-128-cbc', $key, 0, $iv);
|
||||||
return $plugin;
|
}
|
||||||
}
|
|
||||||
}
|
//获取插件列表
|
||||||
return null;
|
public static function get_plugin_list($os = 'Linux'){
|
||||||
}
|
$json_file = get_data_dir($os).'config/plugin_list.json';
|
||||||
|
if(file_exists($json_file)){
|
||||||
//下载插件(自动判断是否第三方)
|
$data = file_get_contents($json_file);
|
||||||
public static function download_plugin($plugin_name, $version, $os = 'Linux'){
|
$json_arr = json_decode($data, true);
|
||||||
$plugin_info = Plugins::get_plugin_info($plugin_name, $os);
|
if($json_arr){
|
||||||
if(!$plugin_info) throw new Exception('未找到该插件信息');
|
return $json_arr;
|
||||||
if($plugin_info['type'] == 10 && isset($plugin_info['versions'][0]['download'])){
|
}
|
||||||
if($plugin_info['price'] == 0){
|
}
|
||||||
$btapi = self::get_btapi($os);
|
return false;
|
||||||
$btapi->create_plugin_other_order($plugin_info['id']);
|
}
|
||||||
}
|
|
||||||
$fname = $plugin_info['versions'][0]['download'];
|
//获取一个插件信息
|
||||||
$filemd5 = $plugin_info['versions'][0]['md5'];
|
public static function get_plugin_info($name, $os = 'Linux'){
|
||||||
Plugins::download_plugin_other($fname, $filemd5, $os);
|
$json_arr = self::get_plugin_list($os);
|
||||||
if(isset($plugin_info['min_image']) && strpos($plugin_info['min_image'], 'fname=')){
|
if(!$json_arr) return null;
|
||||||
$fname = substr($plugin_info['min_image'], strpos($plugin_info['min_image'], '?fname=')+7);
|
foreach($json_arr['list'] as $plugin){
|
||||||
Plugins::download_plugin_other($fname, null, $os);
|
if($plugin['name'] == $name){
|
||||||
}
|
return $plugin;
|
||||||
}else{
|
}
|
||||||
Plugins::download_plugin_package($plugin_name, $version, $os);
|
}
|
||||||
}
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
//下载插件包
|
//下载插件(自动判断是否第三方)
|
||||||
public static function download_plugin_package($plugin_name, $version, $os = 'Linux'){
|
public static function download_plugin($plugin_name, $version, $os = 'Linux'){
|
||||||
$filepath = get_data_dir($os).'plugins/package/'.$plugin_name.'-'.$version.'.zip';
|
$plugin_info = Plugins::get_plugin_info($plugin_name, $os);
|
||||||
$btapi = self::get_btapi($os);
|
if(!$plugin_info) throw new Exception('未找到该插件信息');
|
||||||
$result = $btapi->get_plugin_filename($plugin_name, $version);
|
$btapi = self::get_btapi($os);
|
||||||
if($result && isset($result['status'])){
|
$btapi->download_plugin($plugin_name, $version, $plugin_info);
|
||||||
if($result['status'] == true){
|
}
|
||||||
$filename = $result['filename'];
|
|
||||||
self::download_file($btapi, $filename, $filepath);
|
//下载插件主程序文件
|
||||||
if(file_exists($filepath)){
|
public static function download_plugin_main($plugin_name, $version, $os = 'Linux'){
|
||||||
$zip = new ZipArchive;
|
$btapi = self::get_btapi($os);
|
||||||
if ($zip->open($filepath) === true)
|
$btapi->download_plugin_main($plugin_name, $version);
|
||||||
{
|
}
|
||||||
$zip->extractTo(get_data_dir($os).'plugins/folder/'.$plugin_name.'-'.$version);
|
|
||||||
$zip->close();
|
//本地解密插件主程序文件
|
||||||
$main_filepath = get_data_dir($os).'plugins/folder/'.$plugin_name.'-'.$version.'/'.$plugin_name.'/'.$plugin_name.'_main.py';
|
public static function decode_plugin_main_local($main_filepath, $os = 'Linux'){
|
||||||
if(file_exists($main_filepath) && filesize($main_filepath)>10){
|
$btapi = new BtPlugins($os);
|
||||||
if(!strpos(file_get_contents($main_filepath), 'import ')){ //加密py文件,需要解密
|
return $btapi->decode_plugin_main_local($main_filepath);
|
||||||
self::decode_plugin_main($plugin_name, $version, $main_filepath, $os);
|
}
|
||||||
self::noauth_plugin_main($main_filepath);
|
|
||||||
$zip->open($filepath, ZipArchive::CREATE);
|
//本地解密模块文件
|
||||||
$zip->addFile($main_filepath, $plugin_name.'/'.$plugin_name.'_main.py');
|
public static function decode_module_file($filepath){
|
||||||
$zip->close();
|
$src = file_get_contents($filepath);
|
||||||
}
|
if($src===false)throw new Exception('文件打开失败');
|
||||||
}
|
if(!$src || strpos($src, 'import ')!==false)return 0;
|
||||||
}else{
|
$key = 'Z2B87NEAS2BkxTrh';
|
||||||
throw new Exception('插件包解压缩失败');
|
$iv = 'WwadH66EGWpeeTT6';
|
||||||
}
|
$data_arr = explode("\n", $src);
|
||||||
return true;
|
$de_text = '';
|
||||||
}else{
|
foreach($data_arr as $data){
|
||||||
throw new Exception('下载插件包失败,本地文件不存在');
|
$data = trim($data);
|
||||||
}
|
if(!empty($data)){
|
||||||
}else{
|
$tmp = openssl_decrypt($data, 'aes-128-cbc', $key, 0, $iv);
|
||||||
throw new Exception('下载插件包失败:'.($result['msg']?$result['msg']:'未知错误'));
|
if($tmp !== false) $de_text .= $tmp;
|
||||||
}
|
}
|
||||||
}else{
|
}
|
||||||
throw new Exception('下载插件包失败,接口返回错误');
|
if(!empty($de_text) && strpos($de_text, 'import ')!==false){
|
||||||
}
|
file_put_contents($filepath, $de_text);
|
||||||
}
|
return 1;
|
||||||
|
}
|
||||||
//下载插件主程序文件
|
return 2;
|
||||||
public static function download_plugin_main($plugin_name, $version, $os = 'Linux'){
|
}
|
||||||
$filepath = get_data_dir($os).'plugins/main/'.$plugin_name.'-'.$version.'.dat';
|
|
||||||
$btapi = self::get_btapi($os);
|
//刷新一键部署列表
|
||||||
$result = $btapi->get_plugin_main_filename($plugin_name, $version);
|
public static function refresh_deplist($os = 'Linux'){
|
||||||
if($result && isset($result['status'])){
|
$btapi = self::get_btapi($os);
|
||||||
if($result['status'] == true){
|
$result = $btapi->get_deplist();
|
||||||
$filename = $result['filename'];
|
$json_file = get_data_dir($os).'config/deployment_list.json';
|
||||||
self::download_file($btapi, $filename, $filepath);
|
if(!file_put_contents($json_file, json_encode($result))){
|
||||||
if(file_exists($filepath)){
|
throw new Exception('保存一键部署列表失败,文件无写入权限');
|
||||||
return true;
|
}
|
||||||
}else{
|
}
|
||||||
throw new Exception('下载插件主程序文件失败,本地文件不存在');
|
|
||||||
}
|
//获取一键部署列表
|
||||||
}else{
|
public static function get_deplist($os = 'Linux'){
|
||||||
throw new Exception('下载插件主程序文件失败:'.($result['msg']?$result['msg']:'未知错误'));
|
$json_file = get_data_dir($os).'config/deployment_list.json';
|
||||||
}
|
if(file_exists($json_file)){
|
||||||
}else{
|
$data = file_get_contents($json_file);
|
||||||
throw new Exception('下载插件主程序文件失败,接口返回错误');
|
$json_arr = json_decode($data, true);
|
||||||
}
|
if($json_arr){
|
||||||
}
|
return $json_arr;
|
||||||
|
}
|
||||||
//解密并下载插件主程序文件
|
}
|
||||||
public static function decode_plugin_main($plugin_name, $version, $main_filepath, $os = 'Linux'){
|
return false;
|
||||||
if(self::decode_plugin_main_local($main_filepath, $os)) return true;
|
}
|
||||||
$btapi = self::get_btapi($os);
|
|
||||||
$result = $btapi->get_decode_plugin_main($plugin_name, $version);
|
//获取蜘蛛IP列表
|
||||||
if($result && isset($result['status'])){
|
public static function btwaf_getspiders(){
|
||||||
if($result['status'] == true){
|
$result = cache('btwaf_getspiders');
|
||||||
$filename = $result['filename'];
|
if($result){
|
||||||
self::download_file($btapi, $filename, $main_filepath);
|
return $result;
|
||||||
return true;
|
}
|
||||||
}else{
|
$btapi = self::get_btapi('Linux');
|
||||||
throw new Exception('解密插件主程序文件失败:'.($result['msg']?$result['msg']:'未知错误'));
|
$result = $btapi->btwaf_getspiders();
|
||||||
}
|
cache('btwaf_getspiders', $result, 3600 * 24 * 3);
|
||||||
}else{
|
return $result;
|
||||||
throw new Exception('解密插件主程序文件失败,接口返回错误');
|
}
|
||||||
}
|
|
||||||
}
|
//分类获取蜘蛛IP列表
|
||||||
|
public static function get_spider($type){
|
||||||
//本地解密插件主程序文件
|
$result = cache('get_spider_'.$type);
|
||||||
public static function decode_plugin_main_local($main_filepath, $os = 'Linux'){
|
if($result){
|
||||||
$btapi = self::get_btapi($os);
|
return $result;
|
||||||
$userinfo = $btapi->get_user_info();
|
}
|
||||||
if(isset($userinfo['uid'])){
|
$url = 'https://www.bt.cn/api/panel/get_spider?spider='.$type;
|
||||||
$src = file_get_contents($main_filepath);
|
$data = get_curl($url);
|
||||||
if($src===false)throw new Exception('文件打开失败');
|
$result = json_decode($data, true);
|
||||||
if(!$src || strpos($src, 'import ')!==false)return true;
|
if(!$result) return [];
|
||||||
$uid = $userinfo['uid'];
|
cache('get_spider_'.$type, $result, 3600 * 24);
|
||||||
$serverid = $userinfo['serverid'];
|
return $result;
|
||||||
$key = md5(substr($serverid, 10, 16).$uid.$serverid);
|
}
|
||||||
$iv = md5($key.$serverid);
|
|
||||||
$key = substr($key, 8, 16);
|
//获取堡塔恶意情报IP库
|
||||||
$iv = substr($iv, 8, 16);
|
public static function btwaf_getmalicious(){
|
||||||
$data_arr = explode("\n", $src);
|
$btapi = self::get_btapi('Linux');
|
||||||
$de_text = '';
|
$result = $btapi->btwaf_getmalicious();
|
||||||
foreach($data_arr as $data){
|
return $result;
|
||||||
$data = trim($data);
|
}
|
||||||
if(!empty($data) && strlen($data)!=24){
|
|
||||||
$tmp = openssl_decrypt($data, 'aes-128-cbc', $key, 0, $iv);
|
//加密插件列表
|
||||||
if($tmp) $de_text .= $tmp;
|
public static function encrypt_plugin_list($list, $server_id, $uid){
|
||||||
}
|
$data = json_encode($list);
|
||||||
}
|
$block_size = 51200;
|
||||||
if(!empty($de_text) && strpos($de_text, 'import ')!==false){
|
$key = md5(substr($server_id, 10, 16) . $uid . $server_id);
|
||||||
file_put_contents($main_filepath, $de_text);
|
$iv = md5($key . $server_id);
|
||||||
return true;
|
$key = substr($key, 8, 16);
|
||||||
}
|
$iv = substr($iv, 8, 16);
|
||||||
return false;
|
$encrypted_content = '';
|
||||||
}else{
|
foreach (str_split($data, $block_size) as $block) {
|
||||||
throw new Exception('解密插件主程序文件失败,获取用户信息失败');
|
$encrypted_content .= openssl_encrypt($block, 'aes-128-cbc', $key, 0, $iv) . "\n";
|
||||||
}
|
}
|
||||||
}
|
return $encrypted_content;
|
||||||
|
}
|
||||||
public static function decode_module_file($filepath){
|
|
||||||
$src = file_get_contents($filepath);
|
|
||||||
if($src===false)throw new Exception('文件打开失败');
|
|
||||||
if(!$src || strpos($src, 'import ')!==false)return 0;
|
|
||||||
$key = 'Z2B87NEAS2BkxTrh';
|
|
||||||
$iv = 'WwadH66EGWpeeTT6';
|
|
||||||
$data_arr = explode("\n", $src);
|
|
||||||
$de_text = '';
|
|
||||||
foreach($data_arr as $data){
|
|
||||||
$data = trim($data);
|
|
||||||
if(!empty($data)){
|
|
||||||
$tmp = openssl_decrypt($data, 'aes-128-cbc', $key, 0, $iv);
|
|
||||||
if($tmp) $de_text .= $tmp;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(!empty($de_text) && strpos($de_text, 'import ')!==false){
|
|
||||||
file_put_contents($filepath, $de_text);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
//去除插件主程序文件授权校验
|
|
||||||
public static function noauth_plugin_main($main_filepath){
|
|
||||||
$data = file_get_contents($main_filepath);
|
|
||||||
if(!$data) return false;
|
|
||||||
|
|
||||||
$data = str_replace('\'http://www.bt.cn/api/panel/get_soft_list_test', 'public.GetConfigValue(\'home\')+\'/api/panel/get_soft_list_test', $data);
|
|
||||||
$data = str_replace('\'https://www.bt.cn/api/panel/get_soft_list_test', 'public.GetConfigValue(\'home\')+\'/api/panel/get_soft_list_test', $data);
|
|
||||||
$data = str_replace('\'http://www.bt.cn/api/panel/get_soft_list', 'public.GetConfigValue(\'home\')+\'/api/panel/get_soft_list', $data);
|
|
||||||
$data = str_replace('\'https://www.bt.cn/api/panel/get_soft_list', 'public.GetConfigValue(\'home\')+\'/api/panel/get_soft_list', $data);
|
|
||||||
$data = str_replace('\'http://www.bt.cn/api/panel/notpro', 'public.GetConfigValue(\'home\')+\'/api/panel/notpro', $data);
|
|
||||||
$data = str_replace('\'https://www.bt.cn/api/panel/notpro', 'public.GetConfigValue(\'home\')+\'/api/panel/notpro', $data);
|
|
||||||
|
|
||||||
$data = str_replace('\'http://www.bt.cn/api/wpanel/get_soft_list_test', 'public.GetConfigValue(\'home\')+\'/api/wpanel/get_soft_list_test', $data);
|
|
||||||
$data = str_replace('\'https://www.bt.cn/api/wpanel/get_soft_list_test', 'public.GetConfigValue(\'home\')+\'/api/wpanel/get_soft_list_test', $data);
|
|
||||||
$data = str_replace('\'http://www.bt.cn/api/wpanel/get_soft_list', 'public.GetConfigValue(\'home\')+\'/api/wpanel/get_soft_list', $data);
|
|
||||||
$data = str_replace('\'https://www.bt.cn/api/wpanel/get_soft_list', 'public.GetConfigValue(\'home\')+\'/api/wpanel/get_soft_list', $data);
|
|
||||||
$data = str_replace('\'http://www.bt.cn/api/wpanel/notpro', 'public.GetConfigValue(\'home\')+\'/api/wpanel/notpro', $data);
|
|
||||||
$data = str_replace('\'https://www.bt.cn/api/wpanel/notpro', 'public.GetConfigValue(\'home\')+\'/api/wpanel/notpro', $data);
|
|
||||||
|
|
||||||
file_put_contents($main_filepath, $data);
|
|
||||||
}
|
|
||||||
|
|
||||||
//下载插件其他文件
|
|
||||||
public static function download_plugin_other($fname, $filemd5 = null, $os = 'Linux'){
|
|
||||||
$filepath = get_data_dir().'plugins/other/'.$fname;
|
|
||||||
@mkdir(dirname($filepath), 0777, true);
|
|
||||||
$btapi = self::get_btapi($os);
|
|
||||||
$result = $btapi->get_plugin_other_filename($fname);
|
|
||||||
if($result && isset($result['status'])){
|
|
||||||
if($result['status'] == true){
|
|
||||||
$filename = $result['filename'];
|
|
||||||
self::download_file($btapi, $filename, $filepath);
|
|
||||||
if(file_exists($filepath)){
|
|
||||||
if($filemd5 && md5_file($filepath) != $filemd5){
|
|
||||||
$msg = filesize($filepath) < 300 ? file_get_contents($filepath) : '插件文件MD5校验失败';
|
|
||||||
@unlink($filepath);
|
|
||||||
throw new Exception($msg);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}else{
|
|
||||||
throw new Exception('下载插件文件失败,本地文件不存在');
|
|
||||||
}
|
|
||||||
}else{
|
|
||||||
throw new Exception('下载插件文件失败:'.($result['msg']?$result['msg']:'未知错误'));
|
|
||||||
}
|
|
||||||
}else{
|
|
||||||
throw new Exception('下载插件文件失败,接口返回错误');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//下载文件
|
|
||||||
private static function download_file($btapi, $filename, $filepath){
|
|
||||||
try{
|
|
||||||
$btapi->download($filename, $filepath);
|
|
||||||
}catch(Exception $e){
|
|
||||||
@unlink($filepath);
|
|
||||||
//宝塔bug小文件下载失败,改用base64下载
|
|
||||||
$result = $btapi->get_file($filename);
|
|
||||||
if($result && isset($result['status']) && $result['status']==true){
|
|
||||||
$filedata = base64_decode($result['data']);
|
|
||||||
if(strlen($filedata) < 4096 && substr($filedata,0,1)=='{' && substr($filedata,-1,1)=='}'){
|
|
||||||
$arr = json_decode($filedata, true);
|
|
||||||
if($arr){
|
|
||||||
throw new Exception('获取文件失败:'.($arr['msg']?$arr['msg']:'未知错误'));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(!$filedata){
|
|
||||||
throw new Exception('获取文件失败:文件内容为空');
|
|
||||||
}
|
|
||||||
file_put_contents($filepath, $filedata);
|
|
||||||
}elseif($result){
|
|
||||||
throw new Exception('获取文件失败:'.($result['msg']?$result['msg']:'未知错误'));
|
|
||||||
}else{
|
|
||||||
throw new Exception('获取文件失败:未知错误');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//刷新一键部署列表
|
|
||||||
public static function refresh_deplist($os = 'Linux'){
|
|
||||||
$btapi = self::get_btapi($os);
|
|
||||||
$result = $btapi->get_deplist();
|
|
||||||
if($result && isset($result['list']) && isset($result['type'])){
|
|
||||||
if(empty($result['list']) || empty($result['type'])){
|
|
||||||
throw new Exception('获取一键部署列表失败:一键部署列表为空');
|
|
||||||
}
|
|
||||||
$json_file = get_data_dir($os).'config/deployment_list.json';
|
|
||||||
if(!file_put_contents($json_file, json_encode($result))){
|
|
||||||
throw new Exception('保存一键部署列表失败,文件无写入权限');
|
|
||||||
}
|
|
||||||
}else{
|
|
||||||
throw new Exception('获取一键部署列表失败:'.(isset($result['msg'])?$result['msg']:'面板连接失败'));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//获取一键部署列表
|
|
||||||
public static function get_deplist($os = 'Linux'){
|
|
||||||
$json_file = get_data_dir($os).'config/deployment_list.json';
|
|
||||||
if(file_exists($json_file)){
|
|
||||||
$data = file_get_contents($json_file);
|
|
||||||
$json_arr = json_decode($data, true);
|
|
||||||
if($json_arr){
|
|
||||||
return $json_arr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
226
app/lib/ThirdPlugins.php
Normal file
226
app/lib/ThirdPlugins.php
Normal file
@ -0,0 +1,226 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace app\lib;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
use ZipArchive;
|
||||||
|
|
||||||
|
class ThirdPlugins
|
||||||
|
{
|
||||||
|
private $url;
|
||||||
|
private $os;
|
||||||
|
|
||||||
|
public function __construct($os)
|
||||||
|
{
|
||||||
|
$this->os = $os;
|
||||||
|
if($os == 'en'){
|
||||||
|
$url = config_get('enbt_surl');
|
||||||
|
}elseif($os == 'Windows'){
|
||||||
|
$url = config_get('wbt_surl');
|
||||||
|
}else{
|
||||||
|
$url = config_get('bt_surl');
|
||||||
|
}
|
||||||
|
if(!$url) throw new Exception('请先配置好第三方云端首页URL');
|
||||||
|
$this->url = $url;
|
||||||
|
}
|
||||||
|
|
||||||
|
//获取插件列表
|
||||||
|
public function get_plugin_list()
|
||||||
|
{
|
||||||
|
if($this->os == 'en'){
|
||||||
|
$url = $this->url . 'api/panel/getSoftListEn';
|
||||||
|
}elseif($this->os == 'Windows'){
|
||||||
|
$url = $this->url . 'api/wpanel/get_soft_list';
|
||||||
|
}else{
|
||||||
|
$url = $this->url . 'api/panel/get_soft_list';
|
||||||
|
}
|
||||||
|
$res = $this->curl($url);
|
||||||
|
$result = json_decode($res, true);
|
||||||
|
if($result && isset($result['list']) && isset($result['type'])){
|
||||||
|
if(empty($result['list']) || empty($result['type'])){
|
||||||
|
throw new Exception('获取插件列表失败:插件列表为空');
|
||||||
|
}
|
||||||
|
return $result;
|
||||||
|
}else{
|
||||||
|
throw new Exception('获取插件列表失败:'.(isset($result['msg'])?$result['msg']:'第三方云端连接失败'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//下载插件(自动判断是否第三方)
|
||||||
|
public function download_plugin($plugin_name, $version, $plugin_info){
|
||||||
|
if($plugin_info['type'] == 10 && isset($plugin_info['versions'][0]['download'])){
|
||||||
|
$fname = $plugin_info['versions'][0]['download'];
|
||||||
|
$filemd5 = $plugin_info['versions'][0]['md5'];
|
||||||
|
$this->download_plugin_other($fname, $filemd5);
|
||||||
|
if(isset($plugin_info['min_image']) && strpos($plugin_info['min_image'], 'fname=')){
|
||||||
|
$fname = substr($plugin_info['min_image'], strpos($plugin_info['min_image'], '?fname=')+7);
|
||||||
|
$this->download_plugin_other($fname);
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
$this->download_plugin_package($plugin_name, $version);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//下载插件包
|
||||||
|
private function download_plugin_package($plugin_name, $version){
|
||||||
|
$filepath = get_data_dir($this->os).'plugins/package/'.$plugin_name.'-'.$version.'.zip';
|
||||||
|
|
||||||
|
$url = $this->url . 'down/download_plugin';
|
||||||
|
$post = ['name'=>$plugin_name, 'version'=>$version, 'os'=>$this->os];
|
||||||
|
$this->curl_download($url, $post, $filepath);
|
||||||
|
|
||||||
|
if(file_exists($filepath)){
|
||||||
|
$handle = fopen($filepath, "rb");
|
||||||
|
$file_head = fread($handle, 4);
|
||||||
|
fclose($handle);
|
||||||
|
if(bin2hex($file_head) === '504b0304'){
|
||||||
|
$zip = new ZipArchive;
|
||||||
|
if ($zip->open($filepath) === true)
|
||||||
|
{
|
||||||
|
$zip->close();
|
||||||
|
return true;
|
||||||
|
}else{
|
||||||
|
@unlink($filepath);
|
||||||
|
throw new Exception('插件包解压缩失败');
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
$handle = fopen($filepath, "rb");
|
||||||
|
$errmsg = htmlspecialchars(fgets($handle));
|
||||||
|
fclose($handle);
|
||||||
|
@unlink($filepath);
|
||||||
|
throw new Exception('下载插件包失败:'.($errmsg?$errmsg:'未知错误'));
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
throw new Exception('下载插件包失败,本地文件不存在');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//下载插件主程序文件
|
||||||
|
public function download_plugin_main($plugin_name, $version){
|
||||||
|
$filepath = get_data_dir($this->os).'plugins/main/'.$plugin_name.'-'.$version.'.dat';
|
||||||
|
|
||||||
|
$url = $this->url . 'down/download_plugin_main';
|
||||||
|
$post = ['name'=>$plugin_name, 'version'=>$version, 'os'=>$this->os];
|
||||||
|
$this->curl_download($url, $post, $filepath);
|
||||||
|
|
||||||
|
if(file_exists($filepath)){
|
||||||
|
$line = count(file($filepath));
|
||||||
|
if($line > 3) return true;
|
||||||
|
|
||||||
|
$handle = fopen($filepath, "rb");
|
||||||
|
$errmsg = htmlspecialchars(fgets($handle));
|
||||||
|
fclose($handle);
|
||||||
|
@unlink($filepath);
|
||||||
|
throw new Exception('下载插件主程序文件失败:'.($errmsg?$errmsg:'未知错误'));
|
||||||
|
}else{
|
||||||
|
throw new Exception('下载插件主程序文件失败,本地文件不存在');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//下载插件其他文件
|
||||||
|
private function download_plugin_other($fname, $filemd5 = null){
|
||||||
|
$filepath = get_data_dir().'plugins/other/'.$fname;
|
||||||
|
@mkdir(dirname($filepath), 0777, true);
|
||||||
|
|
||||||
|
$url = $this->url . 'api/Pluginother/get_file?fname='.urlencode($fname);
|
||||||
|
$this->curl_download($url, false, $filepath);
|
||||||
|
|
||||||
|
if(file_exists($filepath)){
|
||||||
|
$handle = fopen($filepath, "rb");
|
||||||
|
$file_head = fread($handle, 15);
|
||||||
|
fclose($handle);
|
||||||
|
if($file_head === '{"status":false'){
|
||||||
|
$res = file_get_contents($filepath);
|
||||||
|
$result = json_decode($res, true);
|
||||||
|
@unlink($filepath);
|
||||||
|
throw new Exception('下载插件文件失败:'.($result?$result['msg']:'未知错误'));
|
||||||
|
}
|
||||||
|
if($filemd5 && md5_file($filepath) != $filemd5){
|
||||||
|
$msg = filesize($filepath) < 300 ? file_get_contents($filepath) : '插件文件MD5校验失败';
|
||||||
|
@unlink($filepath);
|
||||||
|
throw new Exception($msg);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}else{
|
||||||
|
throw new Exception('下载插件文件失败,本地文件不存在');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//获取一键部署列表
|
||||||
|
public function get_deplist(){
|
||||||
|
$url = $this->url . 'api/panel/get_deplist';
|
||||||
|
$post = ['os' => $this->os];
|
||||||
|
$res = $this->curl($url, http_build_query($post));
|
||||||
|
$result = json_decode($res, true);
|
||||||
|
if($result && isset($result['list']) && isset($result['type'])){
|
||||||
|
if(empty($result['list']) || empty($result['type'])){
|
||||||
|
throw new Exception('获取一键部署列表失败:一键部署列表为空');
|
||||||
|
}
|
||||||
|
return $result;
|
||||||
|
}else{
|
||||||
|
throw new Exception('获取一键部署列表失败:'.(isset($result['msg'])?$result['msg']:'第三方云端连接失败'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//获取蜘蛛IP列表
|
||||||
|
public function btwaf_getspiders(){
|
||||||
|
$url = $this->url . 'api/bt_waf/getSpiders';
|
||||||
|
$res = $this->curl($url);
|
||||||
|
$result = json_decode($res, true);
|
||||||
|
if(isset($result['status']) && !$result['status']){
|
||||||
|
throw new Exception(isset($result['msg'])?$result['msg']:'获取失败');
|
||||||
|
}else{
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//获取堡塔恶意情报IP库
|
||||||
|
public function btwaf_getmalicious(){
|
||||||
|
$url = $this->url . 'api/bt_waf/get_malicious';
|
||||||
|
$res = $this->curl($url);
|
||||||
|
$result = json_decode($res, true);
|
||||||
|
if(isset($result['success'])){
|
||||||
|
return $result;
|
||||||
|
}else{
|
||||||
|
throw new Exception(isset($result['res'])?$result['res']:'获取失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function curl($url, $post = 0){
|
||||||
|
$ua = "Mozilla/5.0 (BtCloud; ".request()->root(true).")";
|
||||||
|
return get_curl($url, $post, 0, 0, 0, $ua);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function curl_download($url, $post, $localpath, $timeout = 300)
|
||||||
|
{
|
||||||
|
$ch = curl_init();
|
||||||
|
curl_setopt($ch, CURLOPT_URL, $url);
|
||||||
|
curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
|
||||||
|
$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_setopt($ch, CURLOPT_USERAGENT, "Mozilla/5.0 (BtCloud; ".request()->root(true).")");
|
||||||
|
if($post){
|
||||||
|
curl_setopt($ch, CURLOPT_POST, 1);
|
||||||
|
curl_setopt($ch, CURLOPT_POSTFIELDS, $post);
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
1
app/lib/cn.json
Normal file
1
app/lib/cn.json
Normal file
File diff suppressed because one or more lines are too long
@ -1,26 +1,26 @@
|
|||||||
<?php
|
<?php
|
||||||
declare (strict_types=1);
|
declare (strict_types=1);
|
||||||
|
|
||||||
namespace app\middleware;
|
namespace app\middleware;
|
||||||
|
|
||||||
|
|
||||||
class AuthAdmin
|
class AuthAdmin
|
||||||
{
|
{
|
||||||
public function handle($request, \Closure $next)
|
public function handle($request, \Closure $next)
|
||||||
{
|
{
|
||||||
$islogin = false;
|
$islogin = false;
|
||||||
$cookie = cookie('admin_token');
|
$cookie = cookie('admin_token');
|
||||||
if($cookie){
|
if($cookie){
|
||||||
$token=authcode($cookie, 'DECODE', config_get('syskey'));
|
$token=authcode($cookie, 'DECODE', config_get('syskey'));
|
||||||
if($token){
|
if($token){
|
||||||
list($user, $sid, $expiretime) = explode("\t", $token);
|
list($user, $sid, $expiretime) = explode("\t", $token);
|
||||||
$session=md5(config_get('admin_username').config_get('admin_password'));
|
$session=md5(config_get('admin_username').config_get('admin_password'));
|
||||||
if($session==$sid && $expiretime>time()) {
|
if($session==$sid && $expiretime>time()) {
|
||||||
$islogin = true;
|
$islogin = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
request()->islogin = $islogin;
|
request()->islogin = $islogin;
|
||||||
return $next($request);
|
return $next($request);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,19 +1,19 @@
|
|||||||
<?php
|
<?php
|
||||||
declare (strict_types=1);
|
declare (strict_types=1);
|
||||||
|
|
||||||
namespace app\middleware;
|
namespace app\middleware;
|
||||||
|
|
||||||
|
|
||||||
class CheckAdmin
|
class CheckAdmin
|
||||||
{
|
{
|
||||||
public function handle($request, \Closure $next)
|
public function handle($request, \Closure $next)
|
||||||
{
|
{
|
||||||
if (!request()->islogin) {
|
if (!request()->islogin) {
|
||||||
if ($request->isAjax() || !$request->isGet()) {
|
if ($request->isAjax() || !$request->isGet()) {
|
||||||
return json(['code'=>-1, 'msg'=>'未登录'])->code(401);
|
return json(['code'=>-1, 'msg'=>'未登录'])->code(401);
|
||||||
}
|
}
|
||||||
return redirect((string)url('/admin/login'));
|
return redirect((string)url('/admin/login'));
|
||||||
}
|
}
|
||||||
return $next($request);
|
return $next($request);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,6 +5,7 @@ namespace app\middleware;
|
|||||||
|
|
||||||
use think\facade\Db;
|
use think\facade\Db;
|
||||||
use think\facade\Config;
|
use think\facade\Config;
|
||||||
|
use think\facade\View;
|
||||||
|
|
||||||
class LoadConfig
|
class LoadConfig
|
||||||
{
|
{
|
||||||
@ -31,6 +32,7 @@ class LoadConfig
|
|||||||
$res = Db::name('config')->cache('configs',0)->column('value','key');
|
$res = Db::name('config')->cache('configs',0)->column('value','key');
|
||||||
Config::set($res, 'sys');
|
Config::set($res, 'sys');
|
||||||
|
|
||||||
|
View::assign('cdnpublic', 'https://s4.zstatic.net/ajax/libs/');
|
||||||
return $next($request)->header([
|
return $next($request)->header([
|
||||||
'Cache-Control' => 'no-store, no-cache, must-revalidate',
|
'Cache-Control' => 'no-store, no-cache, must-revalidate',
|
||||||
'Pragma' => 'no-cache',
|
'Pragma' => 'no-cache',
|
||||||
|
|||||||
@ -1,24 +1,24 @@
|
|||||||
<?php
|
<?php
|
||||||
declare (strict_types=1);
|
declare (strict_types=1);
|
||||||
|
|
||||||
namespace app\middleware;
|
namespace app\middleware;
|
||||||
|
|
||||||
use think\facade\View;
|
use think\facade\View;
|
||||||
|
|
||||||
class RefererCheck
|
class RefererCheck
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* 处理请求
|
* 处理请求
|
||||||
*
|
*
|
||||||
* @param \think\Request $request
|
* @param \think\Request $request
|
||||||
* @param \Closure $next
|
* @param \Closure $next
|
||||||
* @return Response
|
* @return Response
|
||||||
*/
|
*/
|
||||||
public function handle($request, \Closure $next)
|
public function handle($request, \Closure $next)
|
||||||
{
|
{
|
||||||
if(!checkRefererHost()){
|
if(!checkRefererHost()){
|
||||||
return response('Access Denied', 403);
|
return response('Access Denied', 403);
|
||||||
}
|
}
|
||||||
return $next($request);
|
return $next($request);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
31
app/script/cacert.sh
Normal file
31
app/script/cacert.sh
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
OPENSSL_CHECK=$(which openssl)
|
||||||
|
if [ "$?" != "0" ]; then
|
||||||
|
echo "未安装OpenSSL"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ! -f ca.key ] && [ ! -f ca.crt ]; then
|
||||||
|
openssl genrsa -out ca.key 2048
|
||||||
|
openssl req -new -x509 -utf8 -days 3650 -extensions v3_ca -subj "/C=CN/O=宝塔面板/CN=宝塔面板" -key ca.key -out ca.crt
|
||||||
|
fi
|
||||||
|
|
||||||
|
openssl genrsa -out server.key 2048
|
||||||
|
openssl req -new -nodes -key server.key -subj "/C=CN/O=BTPanel/CN=BTPanel" -out server.csr
|
||||||
|
openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out server.crt -days 3650 -extensions req_ext
|
||||||
|
|
||||||
|
cat ca.crt >> 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根证书成功"
|
||||||
@ -1,19 +1,27 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
Linux_Version="7.9.6"
|
Linux_Version="11.5.0"
|
||||||
Windows_Version="7.7.0"
|
Windows_Version="8.2.2"
|
||||||
|
Aapanel_Version="7.0.25"
|
||||||
|
Btm_Version="2.3.3"
|
||||||
|
|
||||||
FILES=(
|
FILES=(
|
||||||
public/install/src/panel6.zip
|
public/install/src/panel6.zip
|
||||||
public/install/update/LinuxPanel-${Linux_Version}.zip
|
public/install/update/LinuxPanel-${Linux_Version}.zip
|
||||||
public/install/install_6.0.sh
|
public/install/install_panel.sh
|
||||||
public/install/update_panel.sh
|
public/install/update_panel.sh
|
||||||
public/install/update6.sh
|
public/install/update6.sh
|
||||||
public/win/install/panel_update.py
|
public/win/install/panel_update.py
|
||||||
public/win/panel/panel_${Windows_Version}.zip
|
|
||||||
public/win/panel/data/api.py
|
|
||||||
public/win/panel/data/setup.py
|
public/win/panel/data/setup.py
|
||||||
|
public/install/src/bt-monitor-${Btm_Version}.zip
|
||||||
|
public/install/install_btmonitor.sh
|
||||||
|
public/install/update_btmonitor.sh
|
||||||
|
public/install/src/panel_7_en.zip
|
||||||
|
public/install/update/LinuxPanel_EN-${Aapanel_Version}.zip
|
||||||
|
public/install/install_7.0_en.sh
|
||||||
|
public/install/update_7.x_en.sh
|
||||||
)
|
)
|
||||||
|
PL_FILE="public/install/update/LinuxPanel-${Linux_Version}.pl"
|
||||||
|
|
||||||
DIR=$1
|
DIR=$1
|
||||||
SITEURL=$2
|
SITEURL=$2
|
||||||
@ -71,6 +79,10 @@ do
|
|||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
|
HASH=$(sha256sum "${DIR}public/install/update/LinuxPanel-${Linux_Version}.zip" | awk '{print $1}')
|
||||||
|
TIMESTAMP=$(date +%s)
|
||||||
|
printf '{"hash": "%s", "update_time": "%s"}' "$HASH" "$TIMESTAMP" > "${DIR}${PL_FILE}"
|
||||||
|
|
||||||
echo "=========================="
|
echo "=========================="
|
||||||
echo "处理完成"
|
echo "处理完成"
|
||||||
echo "=========================="
|
echo "=========================="
|
||||||
|
|||||||
@ -1,49 +1,49 @@
|
|||||||
{extend name="admin/layout" /}
|
{extend name="admin/layout" /}
|
||||||
{block name="title"}一键部署列表{/block}
|
{block name="title"}一键部署列表{/block}
|
||||||
{block name="main"}
|
{block name="main"}
|
||||||
<div class="container" style="padding-top:70px;">
|
<div class="container" style="padding-top:70px;">
|
||||||
<div class="col-sm-12 col-md-10 col-lg-8 center-block" style="float: none;">
|
<div class="col-sm-12 col-md-10 col-lg-8 center-block" style="float: none;">
|
||||||
<div class="panel panel-primary">
|
<div class="panel panel-primary">
|
||||||
<div class="panel-heading"><h3 class="panel-title">一键部署列表</h3></div>
|
<div class="panel-heading"><h3 class="panel-title">一键部署列表</h3></div>
|
||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
<div class="list-group">
|
<div class="list-group">
|
||||||
<div class="list-group-item list-group-item-warning">Linux面板</div>
|
<div class="list-group-item list-group-item-warning">Linux面板</div>
|
||||||
<div class="list-group-item" style="line-height:35px">列表文件更新时间:<font color="blue">{$deplist_linux_time}</font><a href="javascript:refresh_deplist('Linux')" class="btn btn-success pull-right"><i class="fa fa-refresh"></i>重新获取</a></div>
|
<div class="list-group-item" style="line-height:35px">列表文件更新时间:<font color="blue">{$deplist_linux_time}</font><a href="javascript:refresh_deplist('Linux')" class="btn btn-success pull-right"><i class="fa fa-refresh"></i>重新获取</a></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="list-group">
|
<div class="list-group">
|
||||||
<div class="list-group-item list-group-item-warning">Windows面板</div>
|
<div class="list-group-item list-group-item-warning">Windows面板</div>
|
||||||
<div class="list-group-item" style="line-height:35px">列表文件更新时间:<font color="blue">{$deplist_win_time}</font><a href="javascript:refresh_deplist('Windows')" class="btn btn-success pull-right"><i class="fa fa-refresh"></i>重新获取</a></div>
|
<div class="list-group-item" style="line-height:35px">列表文件更新时间:<font color="blue">{$deplist_win_time}</font><a href="javascript:refresh_deplist('Windows')" class="btn btn-success pull-right"><i class="fa fa-refresh"></i>重新获取</a></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<script src="//cdn.staticfile.org/layer/3.5.1/layer.js"></script>
|
<script src="{$cdnpublic}layer/3.5.1/layer.js"></script>
|
||||||
<script>
|
<script>
|
||||||
function refresh_deplist(os){
|
function refresh_deplist(os){
|
||||||
var confirm = layer.confirm('是否确定从宝塔官方获取最新一键部署列表?', {
|
var confirm = layer.confirm('是否确定从宝塔官方获取最新一键部署列表?', {
|
||||||
btn: ['确定','取消']
|
btn: ['确定','取消']
|
||||||
}, function(){
|
}, function(){
|
||||||
layer.close(confirm)
|
layer.close(confirm)
|
||||||
var ii = layer.msg('正在获取一键部署列表,请稍候...', {icon: 16, shade:0.1, time: 0});
|
var ii = layer.msg('正在获取一键部署列表,请稍候...', {icon: 16, shade:0.1, time: 0});
|
||||||
$.ajax({
|
$.ajax({
|
||||||
type : 'GET',
|
type : 'GET',
|
||||||
url : '/admin/refresh_deplist?os='+os,
|
url : '/admin/refresh_deplist?os='+os,
|
||||||
dataType : 'json',
|
dataType : 'json',
|
||||||
success : function(data) {
|
success : function(data) {
|
||||||
layer.close(ii)
|
layer.close(ii)
|
||||||
if(data.code == 0){
|
if(data.code == 0){
|
||||||
layer.alert(data.msg, {icon:1}, function(){window.location.reload()});
|
layer.alert(data.msg, {icon:1}, function(){window.location.reload()});
|
||||||
}else{
|
}else{
|
||||||
layer.alert(data.msg, {icon:2});
|
layer.alert(data.msg, {icon:2});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
error:function(data){
|
error:function(data){
|
||||||
layer.close(ii)
|
layer.close(ii)
|
||||||
layer.msg('服务器错误', {icon:2});
|
layer.msg('服务器错误', {icon:2});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}, function(){
|
}, function(){
|
||||||
layer.close(confirm)
|
layer.close(confirm)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
{/block}
|
{/block}
|
||||||
@ -1,60 +1,60 @@
|
|||||||
{extend name="admin/layout" /}
|
{extend name="admin/layout" /}
|
||||||
{block name="title"}宝塔第三方云端管理中心{/block}
|
{block name="title"}宝塔第三方云端管理中心{/block}
|
||||||
{block name="main"}
|
{block name="main"}
|
||||||
<style>
|
<style>
|
||||||
.table>tbody>tr>td{white-space: normal;}
|
.table>tbody>tr>td{white-space: normal;}
|
||||||
.query-title {
|
.query-title {
|
||||||
background-color:#f5fafe;
|
background-color:#f5fafe;
|
||||||
word-break: keep-all;
|
word-break: keep-all;
|
||||||
}
|
}
|
||||||
.query-result{
|
.query-result{
|
||||||
word-break: break-all;
|
word-break: break-all;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
<div class="container" style="padding-top:70px;">
|
<div class="container" style="padding-top:70px;">
|
||||||
<div class="col-xs-12 col-sm-10 col-md-8 center-block" style="float: none;">
|
<div class="col-xs-12 col-sm-10 col-md-8 center-block" style="float: none;">
|
||||||
<div class="panel panel-primary">
|
<div class="panel panel-primary">
|
||||||
<div class="panel-heading"><h3 class="panel-title">后台管理首页</h3></div>
|
<div class="panel-heading"><h3 class="panel-title">后台管理首页</h3></div>
|
||||||
<div class="list-group">
|
<div class="list-group">
|
||||||
<div class="list-group-item"><span class="glyphicon glyphicon-stats"></span> <b>宝塔插件统计:</b>共有 {$stat.total} 个,其中免费插件 {$stat.free} 个,专业版插件 {$stat.pro} 个,企业版插件 {$stat.ltd} 个,第三方插件 {$stat.third} 个</div>
|
<div class="list-group-item"><span class="glyphicon glyphicon-stats"></span> <b>宝塔插件统计:</b>共有 {$stat.total} 个,其中免费插件 {$stat.free} 个,专业版插件 {$stat.pro} 个,企业版插件 {$stat.ltd} 个,第三方插件 {$stat.third} 个</div>
|
||||||
<div class="list-group-item"><span class="glyphicon glyphicon-tint"></span> <b>使用记录统计:</b>历史总共数量:{$stat.record_total},正在使用数量:{$stat.record_isuse}</div>
|
<div class="list-group-item"><span class="glyphicon glyphicon-tint"></span> <b>使用记录统计:</b>历史总共数量:{$stat.record_total},正在使用数量:{$stat.record_isuse}</div>
|
||||||
<div class="list-group-item"><span class="glyphicon glyphicon-time"></span> <b>任务运行情况:</b>上次运行时间:{$stat.runtime|raw} <a href="/admin/set/mod/task" class="btn btn-xs btn-info">查看详情</a></div>
|
<div class="list-group-item"><span class="glyphicon glyphicon-time"></span> <b>任务运行情况:</b>上次运行时间:{$stat.runtime|raw} <a href="/admin/set/mod/task" class="btn btn-xs btn-info">查看详情</a></div>
|
||||||
<div class="list-group-item"><span class="glyphicon glyphicon-cog"></span> <b>常用功能入口:</b><a href="/admin/plugins" class="btn btn-xs btn-default">插件列表</a> <a href="/admin/record" class="btn btn-xs btn-default">使用记录</a> <a href="/admin/list" class="btn btn-xs btn-default">黑白名单</a> <a href="/download" class="btn btn-xs btn-default" target="_blank">安装脚本</a></div>
|
<div class="list-group-item"><span class="glyphicon glyphicon-cog"></span> <b>常用功能入口:</b><a href="/admin/plugins" class="btn btn-xs btn-default">插件列表</a> <a href="/admin/record" class="btn btn-xs btn-default">使用记录</a> <a href="/admin/list" class="btn btn-xs btn-default">黑白名单</a> <a href="/download" class="btn btn-xs btn-default" target="_blank">安装脚本</a></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="panel panel-info">
|
<div class="panel panel-info">
|
||||||
<div class="panel-heading">
|
<div class="panel-heading">
|
||||||
<h3 class="panel-title">服务器信息</h3>
|
<h3 class="panel-title">服务器信息</h3>
|
||||||
</div>
|
</div>
|
||||||
<table class="table table-bordered">
|
<table class="table table-bordered">
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="query-title">框架版本</td>
|
<td class="query-title">框架版本</td>
|
||||||
<td class="query-result">{$info.framework_version}</td>
|
<td class="query-result">{$info.framework_version}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="query-title">PHP版本</td>
|
<td class="query-title">PHP版本</td>
|
||||||
<td class="query-result">{$info.php_version}</td>
|
<td class="query-result">{$info.php_version}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="query-title">MySQL版本</td>
|
<td class="query-title">MySQL版本</td>
|
||||||
<td class="query-result">{$info.mysql_version}</td>
|
<td class="query-result">{$info.mysql_version}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="query-title">WEB软件</td>
|
<td class="query-title">WEB软件</td>
|
||||||
<td class="query-result">{$info.software}</td>
|
<td class="query-result">{$info.software}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="query-title">操作系统</td>
|
<td class="query-title">操作系统</td>
|
||||||
<td class="query-result">{$info.os}</td>
|
<td class="query-result">{$info.os}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="query-title">服务器时间</td>
|
<td class="query-title">服务器时间</td>
|
||||||
<td class="query-result">{$info.date}</td>
|
<td class="query-result">{$info.date}</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{/block}
|
{/block}
|
||||||
@ -1,73 +1,78 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="zh-cn">
|
<html lang="zh-cn">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<meta name="renderer" content="webkit">
|
<meta name="renderer" content="webkit">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no" />
|
||||||
<title>{block name="title"}标题{/block}</title>
|
<title>{block name="title"}标题{/block}</title>
|
||||||
<link href="//cdn.staticfile.org/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet" />
|
<link href="{$cdnpublic}twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet" />
|
||||||
<link href="//cdn.staticfile.org/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet" />
|
<link href="{$cdnpublic}font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet" />
|
||||||
<link href="/static/css/bootstrap-table.css" rel="stylesheet" />
|
<link href="/static/css/bootstrap-table.css" rel="stylesheet" />
|
||||||
<script src="//cdn.staticfile.org/modernizr/2.8.3/modernizr.min.js"></script>
|
<script src="{$cdnpublic}modernizr/2.8.3/modernizr.min.js"></script>
|
||||||
<script src="//cdn.staticfile.org/jquery/2.1.4/jquery.min.js"></script>
|
<script src="{$cdnpublic}jquery/2.1.4/jquery.min.js"></script>
|
||||||
<script src="//cdn.staticfile.org/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script>
|
<script src="{$cdnpublic}twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script>
|
||||||
<!--[if lt IE 9]>
|
<!--[if lt IE 9]>
|
||||||
<script src="//cdn.staticfile.org/html5shiv/3.7.3/html5shiv.min.js"></script>
|
<script src="{$cdnpublic}html5shiv/3.7.3/html5shiv.min.js"></script>
|
||||||
<script src="//cdn.staticfile.org/respond.js/1.4.2/respond.min.js"></script>
|
<script src="{$cdnpublic}respond.js/1.4.2/respond.min.js"></script>
|
||||||
<![endif]-->
|
<![endif]-->
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<nav class="navbar navbar-fixed-top navbar-default">
|
<nav class="navbar navbar-fixed-top navbar-default">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="navbar-header">
|
<div class="navbar-header">
|
||||||
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar"
|
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar"
|
||||||
aria-expanded="false" aria-controls="navbar">
|
aria-expanded="false" aria-controls="navbar">
|
||||||
<span class="sr-only">导航按钮</span>
|
<span class="sr-only">导航按钮</span>
|
||||||
<span class="icon-bar"></span>
|
<span class="icon-bar"></span>
|
||||||
<span class="icon-bar"></span>
|
<span class="icon-bar"></span>
|
||||||
<span class="icon-bar"></span>
|
<span class="icon-bar"></span>
|
||||||
</button>
|
</button>
|
||||||
<a class="navbar-brand" href="./">宝塔第三方云端管理中心</a>
|
<a class="navbar-brand" href="/admin">宝塔第三方云端管理中心</a>
|
||||||
</div><!-- /.navbar-header -->
|
</div><!-- /.navbar-header -->
|
||||||
<div id="navbar" class="collapse navbar-collapse">
|
<div id="navbar" class="collapse navbar-collapse">
|
||||||
<ul class="nav navbar-nav navbar-right">
|
<ul class="nav navbar-nav navbar-right">
|
||||||
<li class="{:checkIfActive('index')}">
|
<li class="{:checkIfActive('index')}">
|
||||||
<a href="/admin"><i class="fa fa-home"></i> 后台首页</a>
|
<a href="/admin"><i class="fa fa-home"></i> 后台首页</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="{:checkIfActive('plugins,pluginswin,deplist')}">
|
<li class="{:checkIfActive('plugins,pluginswin,pluginsen,deplist')}">
|
||||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown"><i class="fa fa-cubes"></i> 插件列表<b class="caret"></b></a>
|
<a href="#" class="dropdown-toggle" data-toggle="dropdown"><i class="fa fa-cubes"></i> 插件列表<b class="caret"></b></a>
|
||||||
<ul class="dropdown-menu">
|
<ul class="dropdown-menu">
|
||||||
<li class="{:checkIfActive('plugins')}"><a href="/admin/plugins">Linux面板</a></li>
|
<li class="{:checkIfActive('plugins')}"><a href="/admin/plugins">Linux面板</a></li>
|
||||||
<li class="{:checkIfActive('pluginswin')}"><a href="/admin/pluginswin">Windows面板</a></li>
|
<li class="{:checkIfActive('pluginswin')}"><a href="/admin/pluginswin">Windows面板</a></li>
|
||||||
<li class="{:checkIfActive('deplist')}"><a href="/admin/deplist">一键部署列表</a></li>
|
<li class="{:checkIfActive('pluginsen')}"><a href="/admin/pluginsen">aaPanel面板</a></li>
|
||||||
</ul>
|
<li class="{:checkIfActive('deplist')}"><a href="/admin/deplist">一键部署列表</a></li>
|
||||||
</li>
|
</ul>
|
||||||
<li class="{:checkIfActive('record')}">
|
</li>
|
||||||
<a href="/admin/record"><i class="fa fa-list"></i> 使用记录</a>
|
<li class="{:checkIfActive('record')}">
|
||||||
</li>
|
<a href="/admin/record"><i class="fa fa-list"></i> 使用记录</a>
|
||||||
<li class="{:checkIfActive('list')}">
|
</li>
|
||||||
<a href="/admin/list"><i class="fa fa-globe"></i> 黑白名单</a>
|
<li class="{:checkIfActive('list')}">
|
||||||
</li>
|
<a href="/admin/list"><i class="fa fa-globe"></i> 黑白名单</a>
|
||||||
<li class="{:checkIfActive('log')}">
|
</li>
|
||||||
<a href="/admin/log"><i class="fa fa-calendar"></i> 操作日志</a>
|
<li class="{:checkIfActive('log')}">
|
||||||
</li>
|
<a href="/admin/log"><i class="fa fa-calendar"></i> 操作日志</a>
|
||||||
<li class="{:checkIfActive('set')}">
|
</li>
|
||||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown"><i class="fa fa-cog"></i> 系统设置<b
|
<li class="{:checkIfActive('ssl')}">
|
||||||
class="caret"></b></a>
|
<a href="/admin/ssl"><i class="fa fa-expeditedssl"></i> 自签SSL</a>
|
||||||
<ul class="dropdown-menu">
|
</li>
|
||||||
<li><a href="/admin/set">系统基本设置</a></li>
|
<li class="{:checkIfActive('set')}">
|
||||||
<li><a href="/admin/set/mod/task">定时任务设置</a></li>
|
<a href="#" class="dropdown-toggle" data-toggle="dropdown"><i class="fa fa-cog"></i> 系统设置<b
|
||||||
<li><a href="/admin/set/mod/tools">批量替换工具</a></li>
|
class="caret"></b></a>
|
||||||
<li><a href="/admin/set/mod/account">管理账号设置</a></li>
|
<ul class="dropdown-menu">
|
||||||
</ul>
|
<li><a href="/admin/set">软件版本设置</a></li>
|
||||||
</li>
|
<li><a href="/admin/set/mod/api">面板接口设置</a></li>
|
||||||
<li>
|
<li><a href="/admin/set/mod/task">自动更新插件设置</a></li>
|
||||||
<a href="/admin/logout" onclick="return confirm('确定退出登录吗?')"><i class="fa fa-power-off"></i> 退出登录</a>
|
<li><a href="/admin/set/mod/tools">替换与清理工具</a></li>
|
||||||
</li>
|
<li><a href="/admin/set/mod/account">管理账号设置</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</div><!-- /.navbar-collapse -->
|
</li>
|
||||||
</div><!-- /.container -->
|
<li>
|
||||||
</nav><!-- /.navbar -->
|
<a href="/admin/logout" onclick="return confirm('确定退出登录吗?')"><i class="fa fa-power-off"></i> 退出登录</a>
|
||||||
{block name="main"}主内容{/block}
|
</li>
|
||||||
</body>
|
</ul>
|
||||||
|
</div><!-- /.navbar-collapse -->
|
||||||
|
</div><!-- /.container -->
|
||||||
|
</nav><!-- /.navbar -->
|
||||||
|
{block name="main"}主内容{/block}
|
||||||
|
</body>
|
||||||
</html>
|
</html>
|
||||||
@ -1,209 +1,209 @@
|
|||||||
{extend name="admin/layout" /}
|
{extend name="admin/layout" /}
|
||||||
{block name="title"}黑白名单{/block}
|
{block name="title"}黑白名单{/block}
|
||||||
{block name="main"}
|
{block name="main"}
|
||||||
<style>
|
<style>
|
||||||
.alert{margin-bottom: 5px;}
|
.alert{margin-bottom: 5px;}
|
||||||
</style>
|
</style>
|
||||||
<div class="container" style="padding-top:70px;">
|
<div class="container" style="padding-top:70px;">
|
||||||
<div class="col-xs-12 col-md-10 center-block" style="float: none;">
|
<div class="col-xs-12 col-md-10 center-block" style="float: none;">
|
||||||
|
|
||||||
<ul class="nav nav-tabs">
|
<ul class="nav nav-tabs">
|
||||||
<li class="{if $type=='black'}active{/if}"><a href="/admin/list">黑名单列表</a></li><li class="{if $type=='white'}active{/if}"><a href="/admin/list/type/white">白名单列表</a></li>
|
<li class="{if $type=='black'}active{/if}"><a href="/admin/list">黑名单列表</a></li><li class="{if $type=='white'}active{/if}"><a href="/admin/list/type/white">白名单列表</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
{if $type=='black' && config_get('whitelist')=='1'}
|
{if $type=='black' && config_get('whitelist')=='1'}
|
||||||
<div class="alert alert-warning">提示:当前为白名单模式,黑名单列表里面的记录不会生效。</div>
|
<div class="alert alert-warning">提示:当前为白名单模式,黑名单列表里面的记录不会生效。</div>
|
||||||
{/if}
|
{/if}
|
||||||
{if $type=='white' && config_get('whitelist')=='0'}
|
{if $type=='white' && config_get('whitelist')=='0'}
|
||||||
<div class="alert alert-warning">提示:当前未开启白名单模式,白名单列表里面的记录不会生效。</div>
|
<div class="alert alert-warning">提示:当前未开启白名单模式,白名单列表里面的记录不会生效。</div>
|
||||||
{/if}
|
{/if}
|
||||||
{if $type=='black'}
|
{if $type=='black'}
|
||||||
<div class="alert alert-info">添加到黑名单列表中的服务器IP将无法使用此云端</div>
|
<div class="alert alert-info">添加到黑名单列表中的服务器IP将无法使用此云端</div>
|
||||||
{/if}
|
{/if}
|
||||||
{if $type=='white'}
|
{if $type=='white'}
|
||||||
<div class="alert alert-info">只有添加到白名单列表中的服务器IP才可以使用此云端</div>
|
<div class="alert alert-info">只有添加到白名单列表中的服务器IP才可以使用此云端</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<div id="searchToolbar">
|
<div id="searchToolbar">
|
||||||
<form onsubmit="return searchSubmit()" method="GET" class="form-inline">
|
<form onsubmit="return searchSubmit()" method="GET" class="form-inline">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label>搜索</label>
|
<label>搜索</label>
|
||||||
<input type="text" class="form-control" name="ip" placeholder="服务器IP">
|
<input type="text" class="form-control" name="ip" placeholder="服务器IP">
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<button class="btn btn-primary" type="submit"><i class="fa fa-search"></i>搜索</button>
|
<button class="btn btn-primary" type="submit"><i class="fa fa-search"></i> 搜索</button>
|
||||||
<a href="javascript:searchClear()" class="btn btn-default"><i class="fa fa-repeat"></i>重置</a>
|
<a href="javascript:searchClear()" class="btn btn-default"><i class="fa fa-repeat"></i> 重置</a>
|
||||||
<a href="javascript:add_item()" class="btn btn-success"><i class="fa fa-plus"></i>添加</a>
|
<a href="javascript:add_item()" class="btn btn-success"><i class="fa fa-plus"></i> 添加</a>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<table id="listTable">
|
<table id="listTable">
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<script src="//cdn.staticfile.org/layer/3.5.1/layer.js"></script>
|
<script src="{$cdnpublic}layer/3.5.1/layer.js"></script>
|
||||||
<script src="//cdn.staticfile.org/bootstrap-table/1.20.2/bootstrap-table.min.js"></script>
|
<script src="{$cdnpublic}bootstrap-table/1.19.1/bootstrap-table.min.js"></script>
|
||||||
<script src="//cdn.staticfile.org/bootstrap-table/1.20.2/extensions/page-jump-to/bootstrap-table-page-jump-to.min.js"></script>
|
<script src="{$cdnpublic}bootstrap-table/1.19.1/extensions/page-jump-to/bootstrap-table-page-jump-to.min.js"></script>
|
||||||
<script src="/static/js/custom.js"></script>
|
<script src="/static/js/custom.js"></script>
|
||||||
<script>
|
<script>
|
||||||
function setEnable(id,enable) {
|
function setEnable(id,enable) {
|
||||||
$.ajax({
|
$.ajax({
|
||||||
type : 'POST',
|
type : 'POST',
|
||||||
url : '/admin/list_op/type/{$type}',
|
url : '/admin/list_op/type/{$type}',
|
||||||
data: { act:'enable', id:id, enable:enable},
|
data: { act:'enable', id:id, enable:enable},
|
||||||
dataType : 'json',
|
dataType : 'json',
|
||||||
success : function(data) {
|
success : function(data) {
|
||||||
if(data.code == 0){
|
if(data.code == 0){
|
||||||
searchSubmit();
|
searchSubmit();
|
||||||
}else{
|
}else{
|
||||||
layer.msg(data.msg, {icon:2, time:1500});
|
layer.msg(data.msg, {icon:2, time:1500});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
error:function(data){
|
error:function(data){
|
||||||
layer.msg('服务器错误');
|
layer.msg('服务器错误');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function add_item(){
|
function add_item(){
|
||||||
layer.open({
|
layer.open({
|
||||||
area: ['360px'],
|
area: ['360px'],
|
||||||
title: '添加IP{$typename}',
|
title: '添加IP{$typename}',
|
||||||
content: '<div class="form-group"><input type="text" class="form-control" name="item_input" placeholder="请输入服务器IP" value=""></div>',
|
content: '<div class="form-group"><input type="text" class="form-control" name="item_input" placeholder="请输入服务器IP" value=""></div>',
|
||||||
yes: function(){
|
yes: function(){
|
||||||
var ip = $("input[name='item_input']").val();
|
var ip = $("input[name='item_input']").val();
|
||||||
$.ajax({
|
$.ajax({
|
||||||
type : 'POST',
|
type : 'POST',
|
||||||
url : '/admin/list_op/type/{$type}',
|
url : '/admin/list_op/type/{$type}',
|
||||||
data: { act:'add', ip:ip},
|
data: { act:'add', ip:ip},
|
||||||
dataType : 'json',
|
dataType : 'json',
|
||||||
success : function(data) {
|
success : function(data) {
|
||||||
if(data.code == 0){
|
if(data.code == 0){
|
||||||
layer.msg('添加成功', {icon:1, time:800});
|
layer.msg('添加成功', {icon:1, time:800});
|
||||||
searchSubmit();
|
searchSubmit();
|
||||||
}else{
|
}else{
|
||||||
layer.alert(data.msg, {icon: 2});
|
layer.alert(data.msg, {icon: 2});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
error:function(data){
|
error:function(data){
|
||||||
layer.msg('服务器错误');
|
layer.msg('服务器错误');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
shadeClose: true
|
shadeClose: true
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function edit_item(id){
|
function edit_item(id){
|
||||||
$.ajax({
|
$.ajax({
|
||||||
type : 'POST',
|
type : 'POST',
|
||||||
url : '/admin/list_op/type/{$type}',
|
url : '/admin/list_op/type/{$type}',
|
||||||
data: { act:'get', id:id},
|
data: { act:'get', id:id},
|
||||||
dataType : 'json',
|
dataType : 'json',
|
||||||
success : function(data) {
|
success : function(data) {
|
||||||
if(data.code == 0){
|
if(data.code == 0){
|
||||||
layer.open({
|
layer.open({
|
||||||
area: ['360px'],
|
area: ['360px'],
|
||||||
title: '编辑IP{$typename}',
|
title: '编辑IP{$typename}',
|
||||||
content: '<div class="form-group"><input type="text" class="form-control" name="item_input" placeholder="请输入服务器IP" value="'+data.data.ip+'"></div>',
|
content: '<div class="form-group"><input type="text" class="form-control" name="item_input" placeholder="请输入服务器IP" value="'+data.data.ip+'"></div>',
|
||||||
yes: function(){
|
yes: function(){
|
||||||
var ip = $("input[name='item_input']").val();
|
var ip = $("input[name='item_input']").val();
|
||||||
$.ajax({
|
$.ajax({
|
||||||
type : 'POST',
|
type : 'POST',
|
||||||
url : '/admin/list_op/type/{$type}',
|
url : '/admin/list_op/type/{$type}',
|
||||||
data: { act:'edit', id:id, ip:ip},
|
data: { act:'edit', id:id, ip:ip},
|
||||||
dataType : 'json',
|
dataType : 'json',
|
||||||
success : function(data) {
|
success : function(data) {
|
||||||
if(data.code == 0){
|
if(data.code == 0){
|
||||||
layer.msg('修改成功', {icon:1, time:800});
|
layer.msg('修改成功', {icon:1, time:800});
|
||||||
searchSubmit();
|
searchSubmit();
|
||||||
}else{
|
}else{
|
||||||
layer.alert(data.msg, {icon: 2});
|
layer.alert(data.msg, {icon: 2});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
error:function(data){
|
error:function(data){
|
||||||
layer.msg('服务器错误');
|
layer.msg('服务器错误');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
shadeClose: true
|
shadeClose: true
|
||||||
});
|
});
|
||||||
}else{
|
}else{
|
||||||
layer.alert(data.msg, {icon: 2});
|
layer.alert(data.msg, {icon: 2});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
error:function(data){
|
error:function(data){
|
||||||
layer.msg('服务器错误');
|
layer.msg('服务器错误');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function del_item(id) {
|
function del_item(id) {
|
||||||
if(confirm('是否确定删除此记录?')){
|
if(confirm('是否确定删除此记录?')){
|
||||||
$.ajax({
|
$.ajax({
|
||||||
type : 'POST',
|
type : 'POST',
|
||||||
url : '/admin/list_op/type/{$type}',
|
url : '/admin/list_op/type/{$type}',
|
||||||
data: { act:'del', id:id},
|
data: { act:'del', id:id},
|
||||||
dataType : 'json',
|
dataType : 'json',
|
||||||
success : function(data) {
|
success : function(data) {
|
||||||
if(data.code == 0){
|
if(data.code == 0){
|
||||||
layer.msg('删除成功!', {icon:1, time:800});
|
layer.msg('删除成功!', {icon:1, time:800});
|
||||||
searchSubmit();
|
searchSubmit();
|
||||||
}else{
|
}else{
|
||||||
layer.alert(data.msg, {icon:2});
|
layer.alert(data.msg, {icon:2});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
error:function(data){
|
error:function(data){
|
||||||
layer.msg('服务器错误');
|
layer.msg('服务器错误');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$(document).ready(function(){
|
$(document).ready(function(){
|
||||||
updateToolbar();
|
updateToolbar();
|
||||||
const defaultPageSize = 15;
|
const defaultPageSize = 15;
|
||||||
const pageNumber = typeof window.$_GET['pageNumber'] != 'undefined' ? parseInt(window.$_GET['pageNumber']) : 1;
|
const pageNumber = typeof window.$_GET['pageNumber'] != 'undefined' ? parseInt(window.$_GET['pageNumber']) : 1;
|
||||||
const pageSize = typeof window.$_GET['pageSize'] != 'undefined' ? parseInt(window.$_GET['pageSize']) : defaultPageSize;
|
const pageSize = typeof window.$_GET['pageSize'] != 'undefined' ? parseInt(window.$_GET['pageSize']) : defaultPageSize;
|
||||||
|
|
||||||
$("#listTable").bootstrapTable({
|
$("#listTable").bootstrapTable({
|
||||||
url: '/admin/list_data/type/{$type}',
|
url: '/admin/list_data/type/{$type}',
|
||||||
pageNumber: pageNumber,
|
pageNumber: pageNumber,
|
||||||
pageSize: pageSize,
|
pageSize: pageSize,
|
||||||
classes: 'table table-striped table-hover table-bottom-border',
|
classes: 'table table-striped table-hover table-bottom-border',
|
||||||
columns: [
|
columns: [
|
||||||
{
|
{
|
||||||
field: 'id',
|
field: 'id',
|
||||||
title: 'ID',
|
title: 'ID',
|
||||||
formatter: function(value, row, index) {
|
formatter: function(value, row, index) {
|
||||||
return '<b>'+value+'</b>';
|
return '<b>'+value+'</b>';
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
field: 'ip',
|
field: 'ip',
|
||||||
title: '服务器IP'
|
title: '服务器IP'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
field: 'enable',
|
field: 'enable',
|
||||||
title: '是否生效',
|
title: '是否生效',
|
||||||
formatter: function(value, row, index) {
|
formatter: function(value, row, index) {
|
||||||
return value?'<a href="javascript:setEnable('+row.id+',0)"><font color=green><i class="fa fa-check-circle"></i>已生效</font></a>':'<a href="javascript:setEnable('+row.id+',1)"><font color=red><i class="fa fa-times-circle"></i>未生效</font></a>';
|
return value?'<a href="javascript:setEnable('+row.id+',0)"><font color=green><i class="fa fa-check-circle"></i>已生效</font></a>':'<a href="javascript:setEnable('+row.id+',1)"><font color=red><i class="fa fa-times-circle"></i>未生效</font></a>';
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
field: 'addtime',
|
field: 'addtime',
|
||||||
title: '添加时间'
|
title: '添加时间'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
field: '',
|
field: '',
|
||||||
title: '操作',
|
title: '操作',
|
||||||
formatter: function(value, row, index) {
|
formatter: function(value, row, index) {
|
||||||
return '<a href="javascript:edit_item('+row.id+')" class="btn btn-xs btn-info">编辑</a> <a href="javascript:del_item('+row.id+')" class="btn btn-xs btn-danger">删除</a>';
|
return '<a href="javascript:edit_item('+row.id+')" class="btn btn-xs btn-info">编辑</a> <a href="javascript:del_item('+row.id+')" class="btn btn-xs btn-danger">删除</a>';
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
{/block}
|
{/block}
|
||||||
@ -1,74 +1,74 @@
|
|||||||
{extend name="admin/layout" /}
|
{extend name="admin/layout" /}
|
||||||
{block name="title"}操作日志{/block}
|
{block name="title"}操作日志{/block}
|
||||||
{block name="main"}
|
{block name="main"}
|
||||||
<style>
|
<style>
|
||||||
</style>
|
</style>
|
||||||
<div class="container" style="padding-top:70px;">
|
<div class="container" style="padding-top:70px;">
|
||||||
<div class="col-xs-12 col-md-10 center-block" style="float: none;">
|
<div class="col-xs-12 col-md-10 center-block" style="float: none;">
|
||||||
|
|
||||||
<div id="searchToolbar">
|
<div id="searchToolbar">
|
||||||
<form onsubmit="return searchSubmit()" method="GET" class="form-inline">
|
<form onsubmit="return searchSubmit()" method="GET" class="form-inline">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label>搜索</label>
|
<label>搜索</label>
|
||||||
<input type="text" class="form-control" name="action" placeholder="操作类型">
|
<input type="text" class="form-control" name="action" placeholder="操作类型">
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<button class="btn btn-primary" type="submit"><i class="fa fa-search"></i>搜索</button>
|
<button class="btn btn-primary" type="submit"><i class="fa fa-search"></i> 搜索</button>
|
||||||
<a href="javascript:searchClear()" class="btn btn-default"><i class="fa fa-repeat"></i>重置</a>
|
<a href="javascript:searchClear()" class="btn btn-default"><i class="fa fa-repeat"></i> 重置</a>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<table id="listTable">
|
<table id="listTable">
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<script src="//cdn.staticfile.org/layer/3.5.1/layer.js"></script>
|
<script src="{$cdnpublic}layer/3.5.1/layer.js"></script>
|
||||||
<script src="//cdn.staticfile.org/bootstrap-table/1.20.2/bootstrap-table.min.js"></script>
|
<script src="{$cdnpublic}bootstrap-table/1.19.1/bootstrap-table.min.js"></script>
|
||||||
<script src="//cdn.staticfile.org/bootstrap-table/1.20.2/extensions/page-jump-to/bootstrap-table-page-jump-to.min.js"></script>
|
<script src="{$cdnpublic}bootstrap-table/1.19.1/extensions/page-jump-to/bootstrap-table-page-jump-to.min.js"></script>
|
||||||
<script src="/static/js/custom.js"></script>
|
<script src="/static/js/custom.js"></script>
|
||||||
<script>
|
<script>
|
||||||
|
|
||||||
$(document).ready(function(){
|
$(document).ready(function(){
|
||||||
updateToolbar();
|
updateToolbar();
|
||||||
const defaultPageSize = 20;
|
const defaultPageSize = 20;
|
||||||
const pageNumber = typeof window.$_GET['pageNumber'] != 'undefined' ? parseInt(window.$_GET['pageNumber']) : 1;
|
const pageNumber = typeof window.$_GET['pageNumber'] != 'undefined' ? parseInt(window.$_GET['pageNumber']) : 1;
|
||||||
const pageSize = typeof window.$_GET['pageSize'] != 'undefined' ? parseInt(window.$_GET['pageSize']) : defaultPageSize;
|
const pageSize = typeof window.$_GET['pageSize'] != 'undefined' ? parseInt(window.$_GET['pageSize']) : defaultPageSize;
|
||||||
|
|
||||||
$("#listTable").bootstrapTable({
|
$("#listTable").bootstrapTable({
|
||||||
url: '/admin/log_data',
|
url: '/admin/log_data',
|
||||||
pageNumber: pageNumber,
|
pageNumber: pageNumber,
|
||||||
pageSize: pageSize,
|
pageSize: pageSize,
|
||||||
classes: 'table table-striped table-hover table-bottom-border',
|
classes: 'table table-striped table-hover table-bottom-border',
|
||||||
columns: [
|
columns: [
|
||||||
{
|
{
|
||||||
field: 'id',
|
field: 'id',
|
||||||
title: 'ID',
|
title: 'ID',
|
||||||
formatter: function(value, row, index) {
|
formatter: function(value, row, index) {
|
||||||
return '<b>'+value+'</b>';
|
return '<b>'+value+'</b>';
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
field: 'uid',
|
field: 'uid',
|
||||||
title: '操作人',
|
title: '操作人',
|
||||||
formatter: function(value, row, index) {
|
formatter: function(value, row, index) {
|
||||||
return value==1?'<font color="green">定时任务</font>':'<font color="blue">管理员</font>';
|
return value==1?'<font color="green">定时任务</font>':'<font color="blue">管理员</font>';
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
field: 'action',
|
field: 'action',
|
||||||
title: '操作类型'
|
title: '操作类型'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
field: 'data',
|
field: 'data',
|
||||||
title: '操作详情',
|
title: '操作详情',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
field: 'addtime',
|
field: 'addtime',
|
||||||
title: '操作时间'
|
title: '操作时间'
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
{/block}
|
{/block}
|
||||||
@ -1,100 +1,100 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="zh-cn">
|
<html lang="zh-cn">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8"/>
|
<meta charset="utf-8"/>
|
||||||
<meta name="renderer" content="webkit">
|
<meta name="renderer" content="webkit">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1"/>
|
<meta name="viewport" content="width=device-width, initial-scale=1"/>
|
||||||
<title>管理员登录</title>
|
<title>管理员登录</title>
|
||||||
<link href="//cdn.staticfile.org/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet"/>
|
<link href="{$cdnpublic}twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet"/>
|
||||||
<script src="//cdn.staticfile.org/modernizr/2.8.3/modernizr.min.js"></script>
|
<script src="{$cdnpublic}modernizr/2.8.3/modernizr.min.js"></script>
|
||||||
<script src="//cdn.staticfile.org/jquery/2.1.4/jquery.min.js"></script>
|
<script src="{$cdnpublic}jquery/2.1.4/jquery.min.js"></script>
|
||||||
<!--[if lt IE 9]>
|
<!--[if lt IE 9]>
|
||||||
<script src="//cdn.staticfile.org/html5shiv/3.7.3/html5shiv.min.js"></script>
|
<script src="{$cdnpublic}html5shiv/3.7.3/html5shiv.min.js"></script>
|
||||||
<script src="//cdn.staticfile.org/respond.js/1.4.2/respond.min.js"></script>
|
<script src="{$cdnpublic}respond.js/1.4.2/respond.min.js"></script>
|
||||||
<![endif]-->
|
<![endif]-->
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<nav class="navbar navbar-fixed-top navbar-default">
|
<nav class="navbar navbar-fixed-top navbar-default">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="navbar-header">
|
<div class="navbar-header">
|
||||||
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
|
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
|
||||||
<span class="sr-only">导航按钮</span>
|
<span class="sr-only">导航按钮</span>
|
||||||
<span class="icon-bar"></span>
|
<span class="icon-bar"></span>
|
||||||
<span class="icon-bar"></span>
|
<span class="icon-bar"></span>
|
||||||
<span class="icon-bar"></span>
|
<span class="icon-bar"></span>
|
||||||
</button>
|
</button>
|
||||||
<a class="navbar-brand" href="./">宝塔第三方云端管理中心</a>
|
<a class="navbar-brand" href="./">Cloud</a>
|
||||||
</div><!-- /.navbar-header -->
|
</div><!-- /.navbar-header -->
|
||||||
<div id="navbar" class="collapse navbar-collapse">
|
<div id="navbar" class="collapse navbar-collapse">
|
||||||
<ul class="nav navbar-nav navbar-right">
|
<ul class="nav navbar-nav navbar-right">
|
||||||
<li class="active">
|
<li class="active">
|
||||||
<a href="#"><span class="glyphicon glyphicon-user"></span> 登录</a>
|
<a href="#"><span class="glyphicon glyphicon-user"></span> 登录</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div><!-- /.navbar-collapse -->
|
</div><!-- /.navbar-collapse -->
|
||||||
</div><!-- /.container -->
|
</div><!-- /.container -->
|
||||||
</nav><!-- /.navbar -->
|
</nav><!-- /.navbar -->
|
||||||
<div class="container" style="padding-top:70px;">
|
<div class="container" style="padding-top:70px;">
|
||||||
<div class="col-xs-12 col-sm-10 col-md-8 col-lg-6 center-block" style="float: none;">
|
<div class="col-xs-12 col-sm-10 col-md-8 col-lg-6 center-block" style="float: none;">
|
||||||
<div class="panel panel-primary">
|
<div class="panel panel-primary">
|
||||||
<div class="panel-heading"><h3 class="panel-title">管理员登录</h3></div>
|
<div class="panel-heading"><h3 class="panel-title">管理员登录</h3></div>
|
||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
<form class="form-horizontal" role="form" onsubmit="return submitlogin()">
|
<form class="form-horizontal" role="form" onsubmit="return submitlogin()">
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<span class="input-group-addon"><span class="glyphicon glyphicon-user"></span></span>
|
<span class="input-group-addon"><span class="glyphicon glyphicon-user"></span></span>
|
||||||
<input type="text" name="user" value="" class="form-control input-lg" placeholder="用户名" required="required"/>
|
<input type="text" name="user" value="" class="form-control input-lg" placeholder="用户名" required="required"/>
|
||||||
</div><br/>
|
</div><br/>
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<span class="input-group-addon"><span class="glyphicon glyphicon-lock"></span></span>
|
<span class="input-group-addon"><span class="glyphicon glyphicon-lock"></span></span>
|
||||||
<input type="password" name="pass" class="form-control input-lg" placeholder="密码" required="required"/>
|
<input type="password" name="pass" class="form-control input-lg" placeholder="密码" required="required"/>
|
||||||
</div><br/>
|
</div><br/>
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<span class="input-group-addon"><span class="glyphicon glyphicon-adjust"></span></span>
|
<span class="input-group-addon"><span class="glyphicon glyphicon-adjust"></span></span>
|
||||||
<input type="text" class="form-control input-lg" name="code" placeholder="输入验证码" autocomplete="off" required>
|
<input type="text" class="form-control input-lg" name="code" placeholder="输入验证码" autocomplete="off" required>
|
||||||
<span class="input-group-addon" style="padding: 0">
|
<span class="input-group-addon" style="padding: 0">
|
||||||
<img src="/admin/verifycode" height="45" id="verifycode" onclick="this.src='/admin/verifycode?r='+Math.random();" title="点击更换验证码">
|
<img src="/admin/verifycode" height="45" id="verifycode" onclick="this.src='/admin/verifycode?r='+Math.random();" title="点击更换验证码">
|
||||||
</span>
|
</span>
|
||||||
</div><br/>
|
</div><br/>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="col-xs-12"><input type="submit" value="立即登录" class="btn btn-primary btn-block btn-lg"/></div>
|
<div class="col-xs-12"><input type="submit" value="立即登录" class="btn btn-primary btn-block btn-lg"/></div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<script src="//cdn.staticfile.org/layer/3.5.1/layer.js"></script>
|
<script src="{$cdnpublic}layer/3.5.1/layer.js"></script>
|
||||||
<script>
|
<script>
|
||||||
function submitlogin(){
|
function submitlogin(){
|
||||||
var user = $("input[name='user']").val();
|
var user = $("input[name='user']").val();
|
||||||
var pass = $("input[name='pass']").val();
|
var pass = $("input[name='pass']").val();
|
||||||
var code = $("input[name='code']").val();
|
var code = $("input[name='code']").val();
|
||||||
if(user=='' || pass==''){layer.alert('用户名或密码不能为空!');return false;}
|
if(user=='' || pass==''){layer.alert('用户名或密码不能为空!');return false;}
|
||||||
var ii = layer.load(2);
|
var ii = layer.load(2);
|
||||||
$.ajax({
|
$.ajax({
|
||||||
type : 'POST',
|
type : 'POST',
|
||||||
url : '{:request()->url()}',
|
url : '{:request()->url()}',
|
||||||
data: {username:user, password:pass, code:code},
|
data: {username:user, password:pass, code:code},
|
||||||
dataType : 'json',
|
dataType : 'json',
|
||||||
success : function(data) {
|
success : function(data) {
|
||||||
layer.close(ii);
|
layer.close(ii);
|
||||||
if(data.code == 0){
|
if(data.code == 0){
|
||||||
layer.msg('登录成功,正在跳转', {icon: 1,shade: 0.01,time: 15000});
|
layer.msg('登录成功,正在跳转', {icon: 1,shade: 0.01,time: 15000});
|
||||||
window.location.href='/admin';
|
window.location.href='/admin';
|
||||||
}else{
|
}else{
|
||||||
if(data.msg.indexOf('验证码')==-1){
|
if(data.msg.indexOf('验证码')==-1){
|
||||||
$("#verifycode").attr('src', '/admin/verifycode?r='+Math.random())
|
$("#verifycode").attr('src', '/admin/verifycode?r='+Math.random())
|
||||||
}
|
}
|
||||||
layer.alert(data.msg, {icon: 2});
|
layer.alert(data.msg, {icon: 2});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
error:function(data){
|
error:function(data){
|
||||||
layer.close(ii);
|
layer.close(ii);
|
||||||
layer.msg('服务器错误');
|
layer.msg('服务器错误');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
@ -1,214 +1,282 @@
|
|||||||
{extend name="admin/layout" /}
|
{extend name="admin/layout" /}
|
||||||
{block name="title"}插件列表{/block}
|
{block name="title"}插件列表{/block}
|
||||||
{block name="main"}
|
{block name="main"}
|
||||||
<style>
|
<style>
|
||||||
td{overflow: hidden;text-overflow: ellipsis;white-space: nowrap;max-width:340px;}
|
td{overflow: hidden;text-overflow: ellipsis;white-space: nowrap;max-width:340px;}
|
||||||
.bt-ico-ask {
|
.bt-ico-ask {
|
||||||
border: 1px solid #fb7d00;
|
border: 1px solid #fb7d00;
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
color: #fb7d00;
|
color: #fb7d00;
|
||||||
cursor: help;
|
cursor: help;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
font-family: arial;
|
font-family: arial;
|
||||||
font-size: 11px;
|
font-size: 11px;
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
height: 16px;
|
height: 16px;
|
||||||
line-height: 16px;
|
line-height: 16px;
|
||||||
margin-left: 5px;
|
margin-left: 5px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
width: 16px
|
width: 16px
|
||||||
}
|
}
|
||||||
.bt-ico-ask:hover {
|
.bt-ico-ask:hover {
|
||||||
background-color: #fb7d00;
|
background-color: #fb7d00;
|
||||||
color: #fff
|
color: #fff
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
<div class="modal fade" id="help" tabindex="-1" role="dialog">
|
<div class="modal fade" id="help" tabindex="-1" role="dialog">
|
||||||
<div class="modal-dialog" role="document">
|
<div class="modal-dialog" role="document">
|
||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||||
<span aria-hidden="true">×</span>
|
<span aria-hidden="true">×</span>
|
||||||
</button>
|
</button>
|
||||||
<h4 class="modal-title">帮助</h4>
|
<h4 class="modal-title">帮助</h4>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
<p>“版本与状态”一列中,红色的按钮代表本地不存在该版本插件包,需要点击下载;绿色的按钮代表已存在。</p>
|
<p>“版本与状态”一列中,红色的按钮代表本地不存在该版本插件包,需要点击下载;绿色的按钮代表已存在。</p>
|
||||||
<p>官方插件包本地存储路径是/data/plugins/package/软件标识-版本号.zip,第三方插件包路径是/data/plugins/other/other/,对于部分包含二次验证的插件可以自行修改。</p>
|
<p>官方插件包本地存储路径是/data/plugins/package/软件标识-版本号.zip,第三方插件包路径是/data/plugins/other/other/,对于部分包含二次验证的插件可以自行修改。</p>
|
||||||
<p>点击【重新获取】按钮会从宝塔官方获取最新插件列表,但是插件包需要手动点击下载。如果需要批量下载插件包,可查看<a href="/admin/set/mod/task">定时任务设置</a></p>
|
<p>若对接的服务器网速较慢,可能会导致下载失败,提示"服务器错误",可稍等一会,进入对接服务器/tmp/plugins目录下载插件包,将_改成-,并上传到本站/data/plugins/package目录下。</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
<button type="button" class="btn btn-default" data-dismiss="modal">关闭</button>
|
<button type="button" class="btn btn-default" data-dismiss="modal">关闭</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="container" style="padding-top:70px;">
|
<div class="container" style="padding-top:70px;">
|
||||||
<div class="col-xs-12 center-block" style="float: none;">
|
<div class="col-xs-12 center-block" style="float: none;">
|
||||||
|
|
||||||
<div id="searchToolbar">
|
<div id="searchToolbar">
|
||||||
<form onsubmit="return searchSubmit()" method="GET" class="form-inline">
|
<form onsubmit="return searchSubmit()" method="GET" class="form-inline">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label>搜索</label>
|
<label>搜索</label>
|
||||||
<input type="text" class="form-control" name="keyword" placeholder="应用名称">
|
<input type="text" class="form-control" name="keyword" placeholder="应用名称">
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<select name="type" class="form-control"><option value="0">全部插件</option>
|
<select name="type" class="form-control"><option value="0">全部插件</option>
|
||||||
{foreach $typelist as $k=>$v}<option value="{$k}">{$v}</option>{/foreach} </select>
|
{foreach $typelist as $k=>$v}<option value="{$k}">{$v}</option>{/foreach} </select>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<button class="btn btn-primary" type="submit"><i class="fa fa-search"></i>搜索</button>
|
<button class="btn btn-primary" type="submit"><i class="fa fa-search"></i> 搜索</button>
|
||||||
<a href="javascript:searchClear()" class="btn btn-default"><i class="fa fa-repeat"></i>重置</a>
|
<a href="javascript:searchClear()" class="btn btn-default"><i class="fa fa-repeat"></i> 重置</a>
|
||||||
<a href="javascript:refresh_plugins()" class="btn btn-success"><i class="fa fa-refresh"></i>重新获取</a>
|
<a href="javascript:refresh_plugins()" class="btn btn-success"><i class="fa fa-refresh"></i> 刷新列表</a>
|
||||||
<button type="button" class="btn btn-default" data-toggle="modal" data-target="#help"><i class="fa fa-info-circle"></i>帮助</button>
|
<a href="javascript:download_plugins()" class="btn btn-warning" id="batch_down" style="display:none;"><i class="fa fa-download"></i> 批量下载</a>
|
||||||
</div>
|
<button type="button" class="btn btn-default" data-toggle="modal" data-target="#help"><i class="fa fa-info-circle"></i> 帮助</button>
|
||||||
</form>
|
</div>
|
||||||
</div>
|
</form>
|
||||||
|
</div>
|
||||||
<table id="listTable">
|
|
||||||
</table>
|
<table id="listTable">
|
||||||
</div>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
<script src="//cdn.staticfile.org/layer/3.5.1/layer.js"></script>
|
</div>
|
||||||
<script src="//cdn.staticfile.org/bootstrap-table/1.20.2/bootstrap-table.min.js"></script>
|
<script src="{$cdnpublic}layer/3.5.1/layer.js"></script>
|
||||||
<script src="//cdn.staticfile.org/bootstrap-table/1.20.2/extensions/page-jump-to/bootstrap-table-page-jump-to.min.js"></script>
|
<script src="{$cdnpublic}bootstrap-table/1.19.1/bootstrap-table.min.js"></script>
|
||||||
<script src="/static/js/custom.js"></script>
|
<script src="{$cdnpublic}bootstrap-table/1.19.1/extensions/page-jump-to/bootstrap-table-page-jump-to.min.js"></script>
|
||||||
<script>
|
<script src="/static/js/custom.js"></script>
|
||||||
|
<script>
|
||||||
function download_version(name, version, status){
|
var skip_plugins = {:json_encode($skip_plugins)};
|
||||||
if(status == true){
|
function download_version(name, version, status){
|
||||||
var confirm = layer.confirm('是否确定重新下载'+version+'版本插件包?', {
|
if(status == true){
|
||||||
btn: ['确定','取消']
|
var confirm = layer.confirm('是否确定重新下载'+version+'版本插件包?', {
|
||||||
}, function(){
|
btn: ['确定','取消']
|
||||||
download_plugin(name, version)
|
}, function(){
|
||||||
}, function(){
|
download_plugin(name, version)
|
||||||
layer.close(confirm)
|
}, function(){
|
||||||
});
|
layer.close(confirm)
|
||||||
}else{
|
});
|
||||||
download_plugin(name, version)
|
}else{
|
||||||
}
|
download_plugin(name, version)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
function download_plugin(name, version){
|
|
||||||
var ii = layer.msg('正在下载,请稍候...', {icon: 16, shade:0.1, time: 0});
|
function download_plugin(name, version){
|
||||||
$.ajax({
|
var ii = layer.msg('正在下载,请稍候...', {icon: 16, shade:0.1, time: 0});
|
||||||
type : 'POST',
|
$.ajax({
|
||||||
url : '/admin/download_plugin',
|
type : 'POST',
|
||||||
data: { name:name, version:version},
|
url : '/admin/download_plugin',
|
||||||
dataType : 'json',
|
data: { name:name, version:version},
|
||||||
success : function(data) {
|
dataType : 'json',
|
||||||
layer.close(ii)
|
success : function(data) {
|
||||||
if(data.code == 0){
|
layer.close(ii)
|
||||||
layer.alert(data.msg, {icon:1}, function(){layer.closeAll();searchSubmit();});
|
if(data.code == 0){
|
||||||
}else{
|
layer.alert(data.msg, {icon:1}, function(){layer.closeAll();searchSubmit();});
|
||||||
layer.alert(data.msg, {icon:2});
|
}else{
|
||||||
}
|
layer.alert(data.msg, {icon:2});
|
||||||
},
|
}
|
||||||
error:function(data){
|
},
|
||||||
layer.close(ii)
|
error:function(data){
|
||||||
layer.msg('服务器错误', {icon:2});
|
layer.close(ii)
|
||||||
}
|
layer.msg('服务器错误', {icon:2});
|
||||||
});
|
}
|
||||||
}
|
});
|
||||||
|
}
|
||||||
function refresh_plugins(){
|
|
||||||
var confirm = layer.confirm('是否确定从宝塔官方获取最新插件列表?', {
|
function refresh_plugins(){
|
||||||
btn: ['确定','取消']
|
var confirm = layer.confirm('是否确定从宝塔官方获取最新插件列表?', {
|
||||||
}, function(){
|
btn: ['确定','取消']
|
||||||
layer.close(confirm)
|
}, function(){
|
||||||
var ii = layer.msg('正在获取插件列表,请稍候...', {icon: 16, shade:0.1, time: 0});
|
layer.close(confirm)
|
||||||
$.ajax({
|
var ii = layer.msg('正在获取插件列表,请稍候...', {icon: 16, shade:0.1, time: 0});
|
||||||
type : 'GET',
|
$.ajax({
|
||||||
url : '/admin/refresh_plugins',
|
type : 'GET',
|
||||||
dataType : 'json',
|
url : '/admin/refresh_plugins',
|
||||||
success : function(data) {
|
dataType : 'json',
|
||||||
layer.close(ii)
|
success : function(data) {
|
||||||
if(data.code == 0){
|
layer.close(ii)
|
||||||
layer.alert(data.msg, {icon:1}, function(){layer.closeAll();searchSubmit();});
|
if(data.code == 0){
|
||||||
}else{
|
layer.alert(data.msg, {icon:1}, function(){layer.closeAll();searchSubmit();});
|
||||||
layer.alert(data.msg, {icon:2});
|
}else{
|
||||||
}
|
layer.alert(data.msg, {icon:2});
|
||||||
},
|
}
|
||||||
error:function(data){
|
},
|
||||||
layer.close(ii)
|
error:function(data){
|
||||||
layer.msg('服务器错误', {icon:2});
|
layer.close(ii)
|
||||||
}
|
layer.msg('服务器错误', {icon:2});
|
||||||
});
|
}
|
||||||
}, function(){
|
});
|
||||||
layer.close(confirm)
|
}, function(){
|
||||||
});
|
layer.close(confirm)
|
||||||
}
|
});
|
||||||
|
}
|
||||||
function searchByType(type){
|
|
||||||
$("input[name=keyword]").val('');
|
function download_plugins(){
|
||||||
$("select[name=type]").val(type);
|
var confirm = layer.confirm('批量下载当前分类下未下载的插件包', {
|
||||||
searchSubmit()
|
btn: ['确定','取消']
|
||||||
}
|
}, function(){
|
||||||
|
layer.close(confirm)
|
||||||
$(document).ready(function(){
|
$.downloadCount = 0;
|
||||||
updateToolbar();
|
$.preDownloadCount = $.preDownload.length;
|
||||||
const defaultPageSize = 20;
|
download_item();
|
||||||
|
}, function(){
|
||||||
$("#listTable").bootstrapTable({
|
layer.close(confirm)
|
||||||
url: '/admin/plugins_data',
|
});
|
||||||
pageNumber: 1,
|
}
|
||||||
pageSize: 15,
|
|
||||||
sidePagination: 'client',
|
function download_item(){
|
||||||
classes: 'table table-striped table-hover table-bottom-border',
|
if($.preDownload.length == 0){
|
||||||
columns: [
|
layer.alert('成功下载'+$.downloadCount+'个插件包!', {icon:1}, function(){layer.closeAll();searchSubmit();});
|
||||||
{
|
return;
|
||||||
field: 'name',
|
}
|
||||||
title: '软件标识',
|
var plugin = $.preDownload[0];
|
||||||
formatter: function(value, row, index) {
|
if(skip_plugins.indexOf(plugin.name) != -1){
|
||||||
return '<b>'+value+'</b>';
|
$.preDownload.shift();
|
||||||
}
|
download_item();
|
||||||
},
|
return;
|
||||||
{
|
}
|
||||||
field: 'title',
|
$.downloadCount++;
|
||||||
title: '软件名称'
|
var ii = layer.msg('['+$.downloadCount+'/'+$.preDownloadCount+']正在下载'+plugin.name+'-'+plugin.version, {icon: 16, shade:0.1, time: 0});
|
||||||
},
|
$.ajax({
|
||||||
{
|
type : 'POST',
|
||||||
field: 'type',
|
url : '/admin/download_plugin',
|
||||||
title: '软件分类',
|
data: { name:plugin.name, version:plugin.version},
|
||||||
formatter: function(value, row, index) {
|
dataType : 'json',
|
||||||
return '<a href="javascript:searchByType('+value+')" title="查看该分类下的插件">'+row.typename+'</a>';
|
success : function(data) {
|
||||||
}
|
layer.close(ii)
|
||||||
},
|
if(data.code == 0){
|
||||||
{
|
$.preDownload.shift();
|
||||||
field: 'desc',
|
download_item();
|
||||||
title: '说明',
|
}else{
|
||||||
},
|
layer.alert(data.msg, {icon:2});
|
||||||
{
|
}
|
||||||
field: 'price',
|
},
|
||||||
title: '价格',
|
error:function(data){
|
||||||
formatter: function(value, row, index) {
|
layer.close(ii)
|
||||||
return value > 0 ? '<span style="color:#fc6d26">¥'+value+'</span>' : '免费';
|
layer.msg('服务器错误', {icon:2});
|
||||||
}
|
}
|
||||||
},
|
});
|
||||||
{
|
}
|
||||||
field: 'author',
|
|
||||||
title: '开发商'
|
function searchByType(type){
|
||||||
},
|
$("input[name=keyword]").val('');
|
||||||
{
|
$("select[name=type]").val(type);
|
||||||
field: 'versions',
|
searchSubmit()
|
||||||
title: '版本与状态',
|
}
|
||||||
formatter: function(value, row, index) {
|
|
||||||
var html = '';
|
$(document).ready(function(){
|
||||||
if(row.type == 5){
|
updateToolbar();
|
||||||
html += '<a href="javascript:" class="btn btn-xs btn-success" disabled>无需下载</a>';
|
const defaultPageSize = 20;
|
||||||
}else{
|
|
||||||
$.each(value, function(index,item){
|
$("#listTable").bootstrapTable({
|
||||||
if(item.status)
|
url: '/admin/plugins_data',
|
||||||
html += '<a href="javascript:download_version(\''+row.name+'\',\''+item.version+'\','+item.status+')" class="btn btn-xs btn-success">'+item.version+'</a> ';
|
pageNumber: 1,
|
||||||
else
|
pageSize: 15,
|
||||||
html += '<a href="javascript:download_version(\''+row.name+'\',\''+item.version+'\','+item.status+')" class="btn btn-xs btn-danger">'+item.version+'</a> ';
|
sidePagination: 'client',
|
||||||
})
|
classes: 'table table-striped table-hover table-bottom-border',
|
||||||
}
|
columns: [
|
||||||
return html
|
{
|
||||||
}
|
field: 'name',
|
||||||
},
|
title: '软件标识',
|
||||||
],
|
formatter: function(value, row, index) {
|
||||||
})
|
return '<b>'+value+'</b>';
|
||||||
})
|
}
|
||||||
</script>
|
},
|
||||||
|
{
|
||||||
|
field: 'title',
|
||||||
|
title: '软件名称'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'type',
|
||||||
|
title: '软件分类',
|
||||||
|
formatter: function(value, row, index) {
|
||||||
|
return '<a href="javascript:searchByType('+value+')" title="查看该分类下的插件">'+row.typename+'</a>';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'desc',
|
||||||
|
title: '说明',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'price',
|
||||||
|
title: '价格',
|
||||||
|
formatter: function(value, row, index) {
|
||||||
|
return value > 0 ? '<span style="color:#fc6d26">¥'+value+'</span>' : '免费';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'author',
|
||||||
|
title: '开发商'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'versions',
|
||||||
|
title: '版本与状态',
|
||||||
|
formatter: function(value, row, index) {
|
||||||
|
var html = '';
|
||||||
|
if(row.type == 5){
|
||||||
|
html += '<a href="javascript:" class="btn btn-xs btn-success" disabled>无需下载</a>';
|
||||||
|
}else{
|
||||||
|
$.each(value, function(index,item){
|
||||||
|
if(item.status)
|
||||||
|
html += '<a href="javascript:download_version(\''+row.name+'\',\''+item.version+'\','+item.status+')" class="btn btn-xs btn-success">'+item.version+'</a> ';
|
||||||
|
else
|
||||||
|
html += '<a href="javascript:download_version(\''+row.name+'\',\''+item.version+'\','+item.status+')" class="btn btn-xs btn-danger">'+item.version+'</a> ';
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return html
|
||||||
|
}
|
||||||
|
},
|
||||||
|
],
|
||||||
|
onLoadSuccess: function(data){
|
||||||
|
$.preDownload = [];
|
||||||
|
var type = $("select[name=type] option:selected").text();
|
||||||
|
if(type != '全部插件' && type != '运行环境' && type != '第三方应用'){
|
||||||
|
$("#batch_down").show();
|
||||||
|
if(data.length > 0){
|
||||||
|
$.each(data, function(index, plugin){
|
||||||
|
if(plugin.versions.length > 0){
|
||||||
|
$.each(plugin.versions, function(index, version){
|
||||||
|
if(!version.status){
|
||||||
|
$.preDownload.push({name:plugin.name, version:version.version})
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
$("#batch_down").hide();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
</script>
|
||||||
{/block}
|
{/block}
|
||||||
276
app/view/admin/pluginsen.html
Normal file
276
app/view/admin/pluginsen.html
Normal file
@ -0,0 +1,276 @@
|
|||||||
|
{extend name="admin/layout" /}
|
||||||
|
{block name="title"}插件列表{/block}
|
||||||
|
{block name="main"}
|
||||||
|
<style>
|
||||||
|
td{overflow: hidden;text-overflow: ellipsis;white-space: nowrap;max-width:340px;}
|
||||||
|
.bt-ico-ask {
|
||||||
|
border: 1px solid #fb7d00;
|
||||||
|
border-radius: 8px;
|
||||||
|
color: #fb7d00;
|
||||||
|
cursor: help;
|
||||||
|
display: inline-block;
|
||||||
|
font-family: arial;
|
||||||
|
font-size: 11px;
|
||||||
|
font-style: normal;
|
||||||
|
height: 16px;
|
||||||
|
line-height: 16px;
|
||||||
|
margin-left: 5px;
|
||||||
|
text-align: center;
|
||||||
|
width: 16px
|
||||||
|
}
|
||||||
|
.bt-ico-ask:hover {
|
||||||
|
background-color: #fb7d00;
|
||||||
|
color: #fff
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<div class="modal fade" id="help" tabindex="-1" role="dialog">
|
||||||
|
<div class="modal-dialog" role="document">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||||
|
<span aria-hidden="true">×</span>
|
||||||
|
</button>
|
||||||
|
<h4 class="modal-title">帮助</h4>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<p>“版本与状态”一列中,红色的按钮代表本地不存在该版本插件包,需要点击下载;绿色的按钮代表已存在。</p>
|
||||||
|
<p>官方插件包本地存储路径是/data/en/plugins/package/软件标识-版本号.zip,第三方插件包路径是/data/plugins/other/other/,对于部分包含二次验证的插件可以自行修改。</p>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-default" data-dismiss="modal">关闭</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="container" style="padding-top:70px;">
|
||||||
|
<div class="col-xs-12 center-block" style="float: none;">
|
||||||
|
|
||||||
|
<div id="searchToolbar">
|
||||||
|
<form onsubmit="return searchSubmit()" method="GET" class="form-inline">
|
||||||
|
<div class="form-group">
|
||||||
|
<label>搜索</label>
|
||||||
|
<input type="text" class="form-control" name="keyword" placeholder="应用名称">
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<select name="type" class="form-control"><option value="0">全部插件</option>
|
||||||
|
{foreach $typelist as $k=>$v}<option value="{$k}">{$v}</option>{/foreach} </select>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<button class="btn btn-primary" type="submit"><i class="fa fa-search"></i> 搜索</button>
|
||||||
|
<a href="javascript:searchClear()" class="btn btn-default"><i class="fa fa-repeat"></i> 重置</a>
|
||||||
|
<a href="javascript:refresh_plugins()" class="btn btn-success"><i class="fa fa-refresh"></i> 刷新列表</a>
|
||||||
|
<a href="javascript:download_plugins()" class="btn btn-warning" id="batch_down" style="display:none;"><i class="fa fa-download"></i> 批量下载</a>
|
||||||
|
<button type="button" class="btn btn-default" data-toggle="modal" data-target="#help"><i class="fa fa-info-circle"></i> 帮助</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<table id="listTable">
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script src="{$cdnpublic}layer/3.5.1/layer.js"></script>
|
||||||
|
<script src="{$cdnpublic}bootstrap-table/1.19.1/bootstrap-table.min.js"></script>
|
||||||
|
<script src="{$cdnpublic}bootstrap-table/1.19.1/extensions/page-jump-to/bootstrap-table-page-jump-to.min.js"></script>
|
||||||
|
<script src="/static/js/custom.js"></script>
|
||||||
|
<script>
|
||||||
|
|
||||||
|
function download_version(name, version, status){
|
||||||
|
if(status == true){
|
||||||
|
var confirm = layer.confirm('是否确定重新下载'+version+'版本插件包?', {
|
||||||
|
btn: ['确定','取消']
|
||||||
|
}, function(){
|
||||||
|
download_plugin(name, version)
|
||||||
|
}, function(){
|
||||||
|
layer.close(confirm)
|
||||||
|
});
|
||||||
|
}else{
|
||||||
|
download_plugin(name, version)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function download_plugin(name, version){
|
||||||
|
var ii = layer.msg('正在下载,请稍候...', {icon: 16, shade:0.1, time: 0});
|
||||||
|
$.ajax({
|
||||||
|
type : 'POST',
|
||||||
|
url : '/admin/download_plugin',
|
||||||
|
data: { name:name, version:version, os:'en'},
|
||||||
|
dataType : 'json',
|
||||||
|
success : function(data) {
|
||||||
|
layer.close(ii)
|
||||||
|
if(data.code == 0){
|
||||||
|
layer.alert(data.msg, {icon:1}, function(){layer.closeAll();searchSubmit();});
|
||||||
|
}else{
|
||||||
|
layer.alert(data.msg, {icon:2});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error:function(data){
|
||||||
|
layer.close(ii)
|
||||||
|
layer.msg('服务器错误', {icon:2});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function refresh_plugins(){
|
||||||
|
var confirm = layer.confirm('是否确定从宝塔官方获取最新插件列表?', {
|
||||||
|
btn: ['确定','取消']
|
||||||
|
}, function(){
|
||||||
|
layer.close(confirm)
|
||||||
|
var ii = layer.msg('正在获取插件列表,请稍候...', {icon: 16, shade:0.1, time: 0});
|
||||||
|
$.ajax({
|
||||||
|
type : 'GET',
|
||||||
|
url : '/admin/refresh_plugins?os=en',
|
||||||
|
dataType : 'json',
|
||||||
|
success : function(data) {
|
||||||
|
layer.close(ii)
|
||||||
|
if(data.code == 0){
|
||||||
|
layer.alert(data.msg, {icon:1}, function(){layer.closeAll();searchSubmit();});
|
||||||
|
}else{
|
||||||
|
layer.alert(data.msg, {icon:2});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error:function(data){
|
||||||
|
layer.close(ii)
|
||||||
|
layer.msg('服务器错误', {icon:2});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}, function(){
|
||||||
|
layer.close(confirm)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function download_plugins(){
|
||||||
|
var confirm = layer.confirm('批量下载当前分类下未下载的插件包', {
|
||||||
|
btn: ['确定','取消']
|
||||||
|
}, function(){
|
||||||
|
layer.close(confirm)
|
||||||
|
$.downloadCount = 0;
|
||||||
|
$.preDownloadCount = $.preDownload.length;
|
||||||
|
download_item();
|
||||||
|
}, function(){
|
||||||
|
layer.close(confirm)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function download_item(){
|
||||||
|
if($.preDownload.length == 0){
|
||||||
|
layer.alert('成功下载'+$.downloadCount+'个插件包!', {icon:1}, function(){layer.closeAll();searchSubmit();});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$.downloadCount++;
|
||||||
|
var plugin = $.preDownload[0];
|
||||||
|
var ii = layer.msg('['+$.downloadCount+'/'+$.preDownloadCount+']正在下载'+plugin.name+'-'+plugin.version, {icon: 16, shade:0.1, time: 0});
|
||||||
|
$.ajax({
|
||||||
|
type : 'POST',
|
||||||
|
url : '/admin/download_plugin',
|
||||||
|
data: { name:plugin.name, version:plugin.version, os:'en'},
|
||||||
|
dataType : 'json',
|
||||||
|
success : function(data) {
|
||||||
|
layer.close(ii)
|
||||||
|
if(data.code == 0){
|
||||||
|
$.preDownload.shift();
|
||||||
|
download_item();
|
||||||
|
}else{
|
||||||
|
layer.alert(data.msg, {icon:2});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error:function(data){
|
||||||
|
layer.close(ii)
|
||||||
|
layer.msg('服务器错误', {icon:2});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function searchByType(type){
|
||||||
|
$("input[name=keyword]").val('');
|
||||||
|
$("select[name=type]").val(type);
|
||||||
|
searchSubmit()
|
||||||
|
}
|
||||||
|
|
||||||
|
$(document).ready(function(){
|
||||||
|
updateToolbar();
|
||||||
|
const defaultPageSize = 20;
|
||||||
|
|
||||||
|
$("#listTable").bootstrapTable({
|
||||||
|
url: '/admin/plugins_data?os=en',
|
||||||
|
pageNumber: 1,
|
||||||
|
pageSize: 15,
|
||||||
|
sidePagination: 'client',
|
||||||
|
classes: 'table table-striped table-hover table-bottom-border',
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
field: 'name',
|
||||||
|
title: '软件标识',
|
||||||
|
formatter: function(value, row, index) {
|
||||||
|
return '<b>'+value+'</b>';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'title',
|
||||||
|
title: '软件名称'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'type',
|
||||||
|
title: '软件分类',
|
||||||
|
formatter: function(value, row, index) {
|
||||||
|
return '<a href="javascript:searchByType('+value+')" title="查看该分类下的插件">'+row.typename+'</a>';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'desc',
|
||||||
|
title: '说明',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'price',
|
||||||
|
title: '价格',
|
||||||
|
formatter: function(value, row, index) {
|
||||||
|
return value > 0 ? '<span style="color:#fc6d26">¥'+value+'</span>' : '免费';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'author',
|
||||||
|
title: '开发商'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'versions',
|
||||||
|
title: '版本与状态',
|
||||||
|
formatter: function(value, row, index) {
|
||||||
|
var html = '';
|
||||||
|
if(row.type == 5 || row.name == 'mail_sys' || row.name == 'dns_manager'){
|
||||||
|
html += '<a href="javascript:" class="btn btn-xs btn-success" disabled>无需下载</a>';
|
||||||
|
}else{
|
||||||
|
$.each(value, function(index,item){
|
||||||
|
if(item.status)
|
||||||
|
html += '<a href="javascript:download_version(\''+row.name+'\',\''+item.version+'\','+item.status+')" class="btn btn-xs btn-success">'+item.version+'</a> ';
|
||||||
|
else
|
||||||
|
html += '<a href="javascript:download_version(\''+row.name+'\',\''+item.version+'\','+item.status+')" class="btn btn-xs btn-danger">'+item.version+'</a> ';
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return html
|
||||||
|
}
|
||||||
|
},
|
||||||
|
],
|
||||||
|
onLoadSuccess: function(data){
|
||||||
|
$.preDownload = [];
|
||||||
|
var type = $("select[name=type] option:selected").text();
|
||||||
|
if(type != '全部插件' && type != '运行环境' && type != '第三方应用'){
|
||||||
|
$("#batch_down").show();
|
||||||
|
if(data.length > 0){
|
||||||
|
$.each(data, function(index, plugin){
|
||||||
|
if(plugin.versions.length > 0 && plugin.name!='mail_sys' && plugin.name!='dns_manager'){
|
||||||
|
$.each(plugin.versions, function(index, version){
|
||||||
|
if(!version.status){
|
||||||
|
$.preDownload.push({name:plugin.name, version:version.version})
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
$("#batch_down").hide();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
{/block}
|
||||||
@ -1,214 +1,276 @@
|
|||||||
{extend name="admin/layout" /}
|
{extend name="admin/layout" /}
|
||||||
{block name="title"}插件列表{/block}
|
{block name="title"}插件列表{/block}
|
||||||
{block name="main"}
|
{block name="main"}
|
||||||
<style>
|
<style>
|
||||||
td{overflow: hidden;text-overflow: ellipsis;white-space: nowrap;max-width:340px;}
|
td{overflow: hidden;text-overflow: ellipsis;white-space: nowrap;max-width:340px;}
|
||||||
.bt-ico-ask {
|
.bt-ico-ask {
|
||||||
border: 1px solid #fb7d00;
|
border: 1px solid #fb7d00;
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
color: #fb7d00;
|
color: #fb7d00;
|
||||||
cursor: help;
|
cursor: help;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
font-family: arial;
|
font-family: arial;
|
||||||
font-size: 11px;
|
font-size: 11px;
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
height: 16px;
|
height: 16px;
|
||||||
line-height: 16px;
|
line-height: 16px;
|
||||||
margin-left: 5px;
|
margin-left: 5px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
width: 16px
|
width: 16px
|
||||||
}
|
}
|
||||||
.bt-ico-ask:hover {
|
.bt-ico-ask:hover {
|
||||||
background-color: #fb7d00;
|
background-color: #fb7d00;
|
||||||
color: #fff
|
color: #fff
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
<div class="modal fade" id="help" tabindex="-1" role="dialog">
|
<div class="modal fade" id="help" tabindex="-1" role="dialog">
|
||||||
<div class="modal-dialog" role="document">
|
<div class="modal-dialog" role="document">
|
||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||||
<span aria-hidden="true">×</span>
|
<span aria-hidden="true">×</span>
|
||||||
</button>
|
</button>
|
||||||
<h4 class="modal-title">帮助</h4>
|
<h4 class="modal-title">帮助</h4>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
<p>“版本与状态”一列中,红色的按钮代表本地不存在该版本插件包,需要点击下载;绿色的按钮代表已存在。</p>
|
<p>“版本与状态”一列中,红色的按钮代表本地不存在该版本插件包,需要点击下载;绿色的按钮代表已存在。</p>
|
||||||
<p>官方插件包本地存储路径是/data/win/plugins/package/软件标识-版本号.zip,第三方插件包路径是/data/plugins/other/other/,对于部分包含二次验证的插件可以自行修改。</p>
|
<p>官方插件包本地存储路径是/data/win/plugins/package/软件标识-版本号.zip,第三方插件包路径是/data/plugins/other/other/,对于部分包含二次验证的插件可以自行修改。</p>
|
||||||
<p>点击【重新获取】按钮会从宝塔官方获取最新插件列表,但是插件包需要手动点击下载。如果需要批量下载插件包,可查看<a href="/admin/set/mod/task">定时任务设置</a></p>
|
</div>
|
||||||
</div>
|
<div class="modal-footer">
|
||||||
<div class="modal-footer">
|
<button type="button" class="btn btn-default" data-dismiss="modal">关闭</button>
|
||||||
<button type="button" class="btn btn-default" data-dismiss="modal">关闭</button>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div class="container" style="padding-top:70px;">
|
||||||
<div class="container" style="padding-top:70px;">
|
<div class="col-xs-12 center-block" style="float: none;">
|
||||||
<div class="col-xs-12 center-block" style="float: none;">
|
|
||||||
|
<div id="searchToolbar">
|
||||||
<div id="searchToolbar">
|
<form onsubmit="return searchSubmit()" method="GET" class="form-inline">
|
||||||
<form onsubmit="return searchSubmit()" method="GET" class="form-inline">
|
<div class="form-group">
|
||||||
<div class="form-group">
|
<label>搜索</label>
|
||||||
<label>搜索</label>
|
<input type="text" class="form-control" name="keyword" placeholder="应用名称">
|
||||||
<input type="text" class="form-control" name="keyword" placeholder="应用名称">
|
</div>
|
||||||
</div>
|
<div class="form-group">
|
||||||
<div class="form-group">
|
<select name="type" class="form-control"><option value="0">全部插件</option>
|
||||||
<select name="type" class="form-control"><option value="0">全部插件</option>
|
{foreach $typelist as $k=>$v}<option value="{$k}">{$v}</option>{/foreach} </select>
|
||||||
{foreach $typelist as $k=>$v}<option value="{$k}">{$v}</option>{/foreach} </select>
|
</div>
|
||||||
</div>
|
<div class="form-group">
|
||||||
<div class="form-group">
|
<button class="btn btn-primary" type="submit"><i class="fa fa-search"></i> 搜索</button>
|
||||||
<button class="btn btn-primary" type="submit"><i class="fa fa-search"></i>搜索</button>
|
<a href="javascript:searchClear()" class="btn btn-default"><i class="fa fa-repeat"></i> 重置</a>
|
||||||
<a href="javascript:searchClear()" class="btn btn-default"><i class="fa fa-repeat"></i>重置</a>
|
<a href="javascript:refresh_plugins()" class="btn btn-success"><i class="fa fa-refresh"></i> 刷新列表</a>
|
||||||
<a href="javascript:refresh_plugins()" class="btn btn-success"><i class="fa fa-refresh"></i>重新获取</a>
|
<a href="javascript:download_plugins()" class="btn btn-warning" id="batch_down" style="display:none;"><i class="fa fa-download"></i> 批量下载</a>
|
||||||
<button type="button" class="btn btn-default" data-toggle="modal" data-target="#help"><i class="fa fa-info-circle"></i>帮助</button>
|
<button type="button" class="btn btn-default" data-toggle="modal" data-target="#help"><i class="fa fa-info-circle"></i> 帮助</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<table id="listTable">
|
<table id="listTable">
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<script src="//cdn.staticfile.org/layer/3.5.1/layer.js"></script>
|
<script src="{$cdnpublic}layer/3.5.1/layer.js"></script>
|
||||||
<script src="//cdn.staticfile.org/bootstrap-table/1.20.2/bootstrap-table.min.js"></script>
|
<script src="{$cdnpublic}bootstrap-table/1.19.1/bootstrap-table.min.js"></script>
|
||||||
<script src="//cdn.staticfile.org/bootstrap-table/1.20.2/extensions/page-jump-to/bootstrap-table-page-jump-to.min.js"></script>
|
<script src="{$cdnpublic}bootstrap-table/1.19.1/extensions/page-jump-to/bootstrap-table-page-jump-to.min.js"></script>
|
||||||
<script src="/static/js/custom.js"></script>
|
<script src="/static/js/custom.js"></script>
|
||||||
<script>
|
<script>
|
||||||
|
|
||||||
function download_version(name, version, status){
|
function download_version(name, version, status){
|
||||||
if(status == true){
|
if(status == true){
|
||||||
var confirm = layer.confirm('是否确定重新下载'+version+'版本插件包?', {
|
var confirm = layer.confirm('是否确定重新下载'+version+'版本插件包?', {
|
||||||
btn: ['确定','取消']
|
btn: ['确定','取消']
|
||||||
}, function(){
|
}, function(){
|
||||||
download_plugin(name, version)
|
download_plugin(name, version)
|
||||||
}, function(){
|
}, function(){
|
||||||
layer.close(confirm)
|
layer.close(confirm)
|
||||||
});
|
});
|
||||||
}else{
|
}else{
|
||||||
download_plugin(name, version)
|
download_plugin(name, version)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function download_plugin(name, version){
|
function download_plugin(name, version){
|
||||||
var ii = layer.msg('正在下载,请稍候...', {icon: 16, shade:0.1, time: 0});
|
var ii = layer.msg('正在下载,请稍候...', {icon: 16, shade:0.1, time: 0});
|
||||||
$.ajax({
|
$.ajax({
|
||||||
type : 'POST',
|
type : 'POST',
|
||||||
url : '/admin/download_plugin',
|
url : '/admin/download_plugin',
|
||||||
data: { name:name, version:version, os:'Windows'},
|
data: { name:name, version:version, os:'Windows'},
|
||||||
dataType : 'json',
|
dataType : 'json',
|
||||||
success : function(data) {
|
success : function(data) {
|
||||||
layer.close(ii)
|
layer.close(ii)
|
||||||
if(data.code == 0){
|
if(data.code == 0){
|
||||||
layer.alert(data.msg, {icon:1}, function(){layer.closeAll();searchSubmit();});
|
layer.alert(data.msg, {icon:1}, function(){layer.closeAll();searchSubmit();});
|
||||||
}else{
|
}else{
|
||||||
layer.alert(data.msg, {icon:2});
|
layer.alert(data.msg, {icon:2});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
error:function(data){
|
error:function(data){
|
||||||
layer.close(ii)
|
layer.close(ii)
|
||||||
layer.msg('服务器错误', {icon:2});
|
layer.msg('服务器错误', {icon:2});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function refresh_plugins(){
|
function refresh_plugins(){
|
||||||
var confirm = layer.confirm('是否确定从宝塔官方获取最新插件列表?', {
|
var confirm = layer.confirm('是否确定从宝塔官方获取最新插件列表?', {
|
||||||
btn: ['确定','取消']
|
btn: ['确定','取消']
|
||||||
}, function(){
|
}, function(){
|
||||||
layer.close(confirm)
|
layer.close(confirm)
|
||||||
var ii = layer.msg('正在获取插件列表,请稍候...', {icon: 16, shade:0.1, time: 0});
|
var ii = layer.msg('正在获取插件列表,请稍候...', {icon: 16, shade:0.1, time: 0});
|
||||||
$.ajax({
|
$.ajax({
|
||||||
type : 'GET',
|
type : 'GET',
|
||||||
url : '/admin/refresh_plugins?os=Windows',
|
url : '/admin/refresh_plugins?os=Windows',
|
||||||
dataType : 'json',
|
dataType : 'json',
|
||||||
success : function(data) {
|
success : function(data) {
|
||||||
layer.close(ii)
|
layer.close(ii)
|
||||||
if(data.code == 0){
|
if(data.code == 0){
|
||||||
layer.alert(data.msg, {icon:1}, function(){layer.closeAll();searchSubmit();});
|
layer.alert(data.msg, {icon:1}, function(){layer.closeAll();searchSubmit();});
|
||||||
}else{
|
}else{
|
||||||
layer.alert(data.msg, {icon:2});
|
layer.alert(data.msg, {icon:2});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
error:function(data){
|
error:function(data){
|
||||||
layer.close(ii)
|
layer.close(ii)
|
||||||
layer.msg('服务器错误', {icon:2});
|
layer.msg('服务器错误', {icon:2});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}, function(){
|
}, function(){
|
||||||
layer.close(confirm)
|
layer.close(confirm)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function searchByType(type){
|
function download_plugins(){
|
||||||
$("input[name=keyword]").val('');
|
var confirm = layer.confirm('批量下载当前分类下未下载的插件包', {
|
||||||
$("select[name=type]").val(type);
|
btn: ['确定','取消']
|
||||||
searchSubmit()
|
}, function(){
|
||||||
}
|
layer.close(confirm)
|
||||||
|
$.downloadCount = 0;
|
||||||
$(document).ready(function(){
|
$.preDownloadCount = $.preDownload.length;
|
||||||
updateToolbar();
|
download_item();
|
||||||
const defaultPageSize = 20;
|
}, function(){
|
||||||
|
layer.close(confirm)
|
||||||
$("#listTable").bootstrapTable({
|
});
|
||||||
url: '/admin/plugins_data?os=Windows',
|
}
|
||||||
pageNumber: 1,
|
|
||||||
pageSize: 15,
|
function download_item(){
|
||||||
sidePagination: 'client',
|
if($.preDownload.length == 0){
|
||||||
classes: 'table table-striped table-hover table-bottom-border',
|
layer.alert('成功下载'+$.downloadCount+'个插件包!', {icon:1}, function(){layer.closeAll();searchSubmit();});
|
||||||
columns: [
|
return;
|
||||||
{
|
}
|
||||||
field: 'name',
|
$.downloadCount++;
|
||||||
title: '软件标识',
|
var plugin = $.preDownload[0];
|
||||||
formatter: function(value, row, index) {
|
var ii = layer.msg('['+$.downloadCount+'/'+$.preDownloadCount+']正在下载'+plugin.name+'-'+plugin.version, {icon: 16, shade:0.1, time: 0});
|
||||||
return '<b>'+value+'</b>';
|
$.ajax({
|
||||||
}
|
type : 'POST',
|
||||||
},
|
url : '/admin/download_plugin',
|
||||||
{
|
data: { name:plugin.name, version:plugin.version, os:'Windows'},
|
||||||
field: 'title',
|
dataType : 'json',
|
||||||
title: '软件名称'
|
success : function(data) {
|
||||||
},
|
layer.close(ii)
|
||||||
{
|
if(data.code == 0){
|
||||||
field: 'type',
|
$.preDownload.shift();
|
||||||
title: '软件分类',
|
download_item();
|
||||||
formatter: function(value, row, index) {
|
}else{
|
||||||
return '<a href="javascript:searchByType('+value+')" title="查看该分类下的插件">'+row.typename+'</a>';
|
layer.alert(data.msg, {icon:2});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
error:function(data){
|
||||||
field: 'desc',
|
layer.close(ii)
|
||||||
title: '说明',
|
layer.msg('服务器错误', {icon:2});
|
||||||
},
|
}
|
||||||
{
|
});
|
||||||
field: 'price',
|
}
|
||||||
title: '价格',
|
|
||||||
formatter: function(value, row, index) {
|
function searchByType(type){
|
||||||
return value > 0 ? '<span style="color:#fc6d26">¥'+value+'</span>' : '免费';
|
$("input[name=keyword]").val('');
|
||||||
}
|
$("select[name=type]").val(type);
|
||||||
},
|
searchSubmit()
|
||||||
{
|
}
|
||||||
field: 'author',
|
|
||||||
title: '开发商'
|
$(document).ready(function(){
|
||||||
},
|
updateToolbar();
|
||||||
{
|
const defaultPageSize = 20;
|
||||||
field: 'versions',
|
|
||||||
title: '版本与状态',
|
$("#listTable").bootstrapTable({
|
||||||
formatter: function(value, row, index) {
|
url: '/admin/plugins_data?os=Windows',
|
||||||
var html = '';
|
pageNumber: 1,
|
||||||
if(row.type == 5){
|
pageSize: 15,
|
||||||
html += '<a href="javascript:" class="btn btn-xs btn-success" disabled>无需下载</a>';
|
sidePagination: 'client',
|
||||||
}else{
|
classes: 'table table-striped table-hover table-bottom-border',
|
||||||
$.each(value, function(index,item){
|
columns: [
|
||||||
if(item.status)
|
{
|
||||||
html += '<a href="javascript:download_version(\''+row.name+'\',\''+item.version+'\','+item.status+')" class="btn btn-xs btn-success">'+item.version+'</a> ';
|
field: 'name',
|
||||||
else
|
title: '软件标识',
|
||||||
html += '<a href="javascript:download_version(\''+row.name+'\',\''+item.version+'\','+item.status+')" class="btn btn-xs btn-danger">'+item.version+'</a> ';
|
formatter: function(value, row, index) {
|
||||||
})
|
return '<b>'+value+'</b>';
|
||||||
}
|
}
|
||||||
return html
|
},
|
||||||
}
|
{
|
||||||
},
|
field: 'title',
|
||||||
],
|
title: '软件名称'
|
||||||
})
|
},
|
||||||
})
|
{
|
||||||
</script>
|
field: 'type',
|
||||||
|
title: '软件分类',
|
||||||
|
formatter: function(value, row, index) {
|
||||||
|
return '<a href="javascript:searchByType('+value+')" title="查看该分类下的插件">'+row.typename+'</a>';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'desc',
|
||||||
|
title: '说明',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'price',
|
||||||
|
title: '价格',
|
||||||
|
formatter: function(value, row, index) {
|
||||||
|
return value > 0 ? '<span style="color:#fc6d26">¥'+value+'</span>' : '免费';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'author',
|
||||||
|
title: '开发商'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'versions',
|
||||||
|
title: '版本与状态',
|
||||||
|
formatter: function(value, row, index) {
|
||||||
|
var html = '';
|
||||||
|
if(row.type == 5){
|
||||||
|
html += '<a href="javascript:" class="btn btn-xs btn-success" disabled>无需下载</a>';
|
||||||
|
}else{
|
||||||
|
$.each(value, function(index,item){
|
||||||
|
if(item.status)
|
||||||
|
html += '<a href="javascript:download_version(\''+row.name+'\',\''+item.version+'\','+item.status+')" class="btn btn-xs btn-success">'+item.version+'</a> ';
|
||||||
|
else
|
||||||
|
html += '<a href="javascript:download_version(\''+row.name+'\',\''+item.version+'\','+item.status+')" class="btn btn-xs btn-danger">'+item.version+'</a> ';
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return html
|
||||||
|
}
|
||||||
|
},
|
||||||
|
],
|
||||||
|
onLoadSuccess: function(data){
|
||||||
|
$.preDownload = [];
|
||||||
|
var type = $("select[name=type] option:selected").text();
|
||||||
|
if(type != '全部插件' && type != '运行环境' && type != '第三方应用'){
|
||||||
|
$("#batch_down").show();
|
||||||
|
if(data.length > 0){
|
||||||
|
$.each(data, function(index, plugin){
|
||||||
|
if(plugin.versions.length > 0){
|
||||||
|
$.each(plugin.versions, function(index, version){
|
||||||
|
if(!version.status){
|
||||||
|
$.preDownload.push({name:plugin.name, version:version.version})
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
$("#batch_down").hide();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
</script>
|
||||||
{/block}
|
{/block}
|
||||||
@ -1,67 +1,67 @@
|
|||||||
{extend name="admin/layout" /}
|
{extend name="admin/layout" /}
|
||||||
{block name="title"}使用记录{/block}
|
{block name="title"}使用记录{/block}
|
||||||
{block name="main"}
|
{block name="main"}
|
||||||
<style>
|
<style>
|
||||||
</style>
|
</style>
|
||||||
<div class="container" style="padding-top:70px;">
|
<div class="container" style="padding-top:70px;">
|
||||||
<div class="col-xs-12 col-md-10 center-block" style="float: none;">
|
<div class="col-xs-12 col-md-10 center-block" style="float: none;">
|
||||||
|
|
||||||
<div id="searchToolbar">
|
<div id="searchToolbar">
|
||||||
<form onsubmit="return searchSubmit()" method="GET" class="form-inline">
|
<form onsubmit="return searchSubmit()" method="GET" class="form-inline">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label>搜索</label>
|
<label>搜索</label>
|
||||||
<input type="text" class="form-control" name="ip" placeholder="服务器IP">
|
<input type="text" class="form-control" name="ip" placeholder="服务器IP">
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<button class="btn btn-primary" type="submit"><i class="fa fa-search"></i>搜索</button>
|
<button class="btn btn-primary" type="submit"><i class="fa fa-search"></i> 搜索</button>
|
||||||
<a href="javascript:searchClear()" class="btn btn-default"><i class="fa fa-repeat"></i>重置</a>
|
<a href="javascript:searchClear()" class="btn btn-default"><i class="fa fa-repeat"></i> 重置</a>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<table id="listTable">
|
<table id="listTable">
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<script src="//cdn.staticfile.org/layer/3.5.1/layer.js"></script>
|
<script src="{$cdnpublic}layer/3.5.1/layer.js"></script>
|
||||||
<script src="//cdn.staticfile.org/bootstrap-table/1.20.2/bootstrap-table.min.js"></script>
|
<script src="{$cdnpublic}bootstrap-table/1.19.1/bootstrap-table.min.js"></script>
|
||||||
<script src="//cdn.staticfile.org/bootstrap-table/1.20.2/extensions/page-jump-to/bootstrap-table-page-jump-to.min.js"></script>
|
<script src="{$cdnpublic}bootstrap-table/1.19.1/extensions/page-jump-to/bootstrap-table-page-jump-to.min.js"></script>
|
||||||
<script src="/static/js/custom.js"></script>
|
<script src="/static/js/custom.js"></script>
|
||||||
<script>
|
<script>
|
||||||
|
|
||||||
$(document).ready(function(){
|
$(document).ready(function(){
|
||||||
updateToolbar();
|
updateToolbar();
|
||||||
const defaultPageSize = 15;
|
const defaultPageSize = 15;
|
||||||
const pageNumber = typeof window.$_GET['pageNumber'] != 'undefined' ? parseInt(window.$_GET['pageNumber']) : 1;
|
const pageNumber = typeof window.$_GET['pageNumber'] != 'undefined' ? parseInt(window.$_GET['pageNumber']) : 1;
|
||||||
const pageSize = typeof window.$_GET['pageSize'] != 'undefined' ? parseInt(window.$_GET['pageSize']) : defaultPageSize;
|
const pageSize = typeof window.$_GET['pageSize'] != 'undefined' ? parseInt(window.$_GET['pageSize']) : defaultPageSize;
|
||||||
|
|
||||||
$("#listTable").bootstrapTable({
|
$("#listTable").bootstrapTable({
|
||||||
url: '/admin/record_data',
|
url: '/admin/record_data',
|
||||||
pageNumber: pageNumber,
|
pageNumber: pageNumber,
|
||||||
pageSize: pageSize,
|
pageSize: pageSize,
|
||||||
classes: 'table table-striped table-hover table-bottom-border',
|
classes: 'table table-striped table-hover table-bottom-border',
|
||||||
columns: [
|
columns: [
|
||||||
{
|
{
|
||||||
field: 'id',
|
field: 'id',
|
||||||
title: 'ID',
|
title: 'ID',
|
||||||
formatter: function(value, row, index) {
|
formatter: function(value, row, index) {
|
||||||
return '<b>'+value+'</b>';
|
return '<b>'+value+'</b>';
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
field: 'ip',
|
field: 'ip',
|
||||||
title: '服务器IP'
|
title: '服务器IP'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
field: 'addtime',
|
field: 'addtime',
|
||||||
title: '首次安装时间',
|
title: '首次安装时间',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
field: 'usetime',
|
field: 'usetime',
|
||||||
title: '最后使用时间'
|
title: '最后使用时间'
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
{/block}
|
{/block}
|
||||||
@ -1,322 +1,571 @@
|
|||||||
{extend name="admin/layout" /}
|
{extend name="admin/layout" /}
|
||||||
{block name="title"}系统设置{/block}
|
{block name="title"}系统设置{/block}
|
||||||
{block name="main"}
|
{block name="main"}
|
||||||
<div class="container" style="padding-top:70px;">
|
<div class="container" style="padding-top:70px;">
|
||||||
{if $mod=='sys'}
|
{if $mod=='sys'}
|
||||||
<div class="col-sm-12 col-md-6 center-block">
|
<div class="col-sm-12 col-md-6 center-block">
|
||||||
<div class="panel panel-primary">
|
<div class="panel panel-success">
|
||||||
<div class="panel-heading"><h3 class="panel-title">系统基本设置</h3></div>
|
<div class="panel-heading"><h3 class="panel-title">系统基本设置</h3></div>
|
||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
<form onsubmit="return saveSetting(this)" method="post" class="form" role="form">
|
<form onsubmit="return saveSetting(this)" method="post" class="form" role="form">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label>是否开启白名单模式:</label><br/>
|
<label>是否开启白名单模式:</label><br/>
|
||||||
<select class="form-control" name="whitelist" default="{:config_get('whitelist')}"><option value="0">关闭</option><option value="1">开启</option></select>
|
<select class="form-control" name="whitelist" default="{:config_get('whitelist')}"><option value="0">关闭</option><option value="1">开启</option></select>
|
||||||
<font color="green">开启白名单模式后,只有在<a href="/admin/list/type/white" target="_blank">白名单列表</a>中的服务器IP才能使用此云端</font>
|
<font color="green">开启白名单模式后,只有在<a href="/admin/list/type/white" target="_blank">白名单列表</a>中的服务器IP才能使用此云端</font>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label>安装脚本展示页面开关:</label>
|
<label>安装脚本展示页面开关:</label>
|
||||||
<select class="form-control" name="download_page" default="{:config_get('download_page')}"><option value="0">关闭</option><option value="1">开启</option></select>
|
<select class="form-control" name="download_page" default="{:config_get('download_page')}"><option value="0">关闭</option><option value="1">开启</option></select>
|
||||||
<font color="green">页面地址:<a href="/download" target="_blank">/download</a>,开启后可以公开访问,否则只能管理员访问</font>
|
<font color="green">页面地址:<a href="/download" target="_blank">/download</a>,开启后可以公开访问,否则只能管理员访问</font>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group text-center">
|
||||||
<label>宝塔Linux面板最新版本号:</label>
|
<input type="submit" name="submit" value="保存" class="btn btn-success btn-block"/>
|
||||||
<input type="text" name="new_version" value="{:config_get('new_version')}" class="form-control"/>
|
</div>
|
||||||
<font color="green">用于一键更新脚本获取最新版本号,以及检测更新接口。并确保已在/public/install/update/放置对应版本更新包</font>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
</div>
|
||||||
<label>宝塔Linux面板更新日志:</label>
|
<div class="panel panel-info">
|
||||||
<textarea class="form-control" name="update_msg" rows="5" placeholder="支持HTML代码">{:config_get('update_msg')}</textarea>
|
<div class="panel-heading"><h3 class="panel-title">Linux面板版本设置</h3></div>
|
||||||
<font color="green">用于检测更新接口返回</font>
|
<div class="panel-body">
|
||||||
</div>
|
<form onsubmit="return saveSetting(this)" method="post" class="form" role="form">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label>宝塔Linux面板更新日期:</label>
|
<label>宝塔Linux面板最新版本号:</label>
|
||||||
<input type="date" name="update_date" value="{:config_get('update_date')}" class="form-control"/>
|
<input type="text" name="new_version" value="{:config_get('new_version')}" class="form-control"/>
|
||||||
<font color="green">用于检测更新接口返回</font>
|
<font color="green">用于一键更新脚本获取最新版本号,以及检测更新接口。并确保已在/public/install/update/放置对应版本更新包</font>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label>宝塔Windows面板最新版本号:</label>
|
<label>宝塔Linux面板更新日志:</label>
|
||||||
<input type="text" name="new_version_win" value="{:config_get('new_version_win')}" class="form-control"/>
|
<textarea class="form-control" name="update_msg" rows="5" placeholder="支持HTML代码">{:config_get('update_msg')}</textarea>
|
||||||
<font color="green">用于一键更新脚本获取最新版本号,以及检测更新接口。并确保已在/public/win/panel/放置对应版本更新包</font>
|
<font color="green">用于检测更新接口返回</font>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label>宝塔Windows面板更新日志:</label>
|
<label>宝塔Linux面板更新日期:</label>
|
||||||
<textarea class="form-control" name="update_msg_win" rows="5" placeholder="支持HTML代码">{:config_get('update_msg_win')}</textarea>
|
<input type="date" name="update_date" value="{:config_get('update_date')}" class="form-control"/>
|
||||||
<font color="green">用于检测更新接口返回</font>
|
<font color="green">用于检测更新接口返回</font>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group text-center">
|
||||||
<label>宝塔Windows面板更新日期:</label>
|
<input type="submit" name="submit" value="保存" class="btn btn-success btn-block"/>
|
||||||
<input type="date" name="update_date_win" value="{:config_get('update_date_win')}" class="form-control"/>
|
</div>
|
||||||
<font color="green">用于检测更新接口返回</font>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group text-center">
|
</div>
|
||||||
<input type="submit" name="submit" value="保存" class="btn btn-success btn-block"/>
|
<div class="panel panel-info">
|
||||||
</div>
|
<div class="panel-heading"><h3 class="panel-title">Windows面板版本设置</h3></div>
|
||||||
</form>
|
<div class="panel-body">
|
||||||
</div>
|
<form onsubmit="return saveSetting(this)" method="post" class="form" role="form">
|
||||||
</div>
|
<div class="form-group">
|
||||||
</div>
|
<label>宝塔Windows面板最新版本号:</label>
|
||||||
<div class="col-sm-12 col-md-6 center-block">
|
<input type="text" name="new_version_win" value="{:config_get('new_version_win')}" class="form-control"/>
|
||||||
<div class="panel panel-primary">
|
<font color="green">用于一键更新脚本获取最新版本号,以及检测更新接口。并确保已在/public/win/panel/放置对应版本更新包</font>
|
||||||
<div class="panel-heading"><h3 class="panel-title">宝塔Linux面板接口设置</h3></div>
|
</div>
|
||||||
<div class="panel-body">
|
<div class="form-group">
|
||||||
<form onsubmit="return saveSetting(this)" method="post" class="form" role="form">
|
<label>宝塔Windows面板更新日志:</label>
|
||||||
<p>以下宝塔面板请使用官方最新脚本安装并绑定账号,用于获取最新插件列表及插件包</p>
|
<textarea class="form-control" name="update_msg_win" rows="5" placeholder="支持HTML代码">{:config_get('update_msg_win')}</textarea>
|
||||||
<p><a href="/static/file/kaixin.zip">下载专用插件(Linux)</a>,在面板【软件商店】->【第三方应用】,点击【导入插件】,导入该专用插件。</p>
|
<font color="green">用于检测更新接口返回</font>
|
||||||
<div class="form-group">
|
</div>
|
||||||
<label>宝塔面板URL:</label><br/>
|
<div class="form-group">
|
||||||
<input type="text" name="bt_url" value="{:config_get('bt_url')}" class="form-control"/>
|
<label>宝塔Windows面板更新日期:</label>
|
||||||
<font color="green">填写规则如:<u>http://192.168.1.1:8888</u> ,不要带其他后缀</font>
|
<input type="date" name="update_date_win" value="{:config_get('update_date_win')}" class="form-control"/>
|
||||||
</div>
|
<font color="green">用于检测更新接口返回</font>
|
||||||
<div class="form-group">
|
</div>
|
||||||
<label>宝塔面板接口密钥:</label>
|
<div class="form-group text-center">
|
||||||
<input type="text" name="bt_key" value="{:config_get('bt_key')}" class="form-control"/>
|
<input type="submit" name="submit" value="保存" class="btn btn-success btn-block"/>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group text-center">
|
</form>
|
||||||
<button type="button" class="btn btn-info btn-block" id="testbturl">测试连接</button>
|
</div>
|
||||||
<input type="submit" name="submit" value="保存" class="btn btn-success btn-block"/>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
<div class="col-sm-12 col-md-6 center-block">
|
||||||
</div>
|
<div class="panel panel-info">
|
||||||
</div>
|
<div class="panel-heading"><h3 class="panel-title">云监控版本设置</h3></div>
|
||||||
<div class="panel panel-primary">
|
<div class="panel-body">
|
||||||
<div class="panel-heading"><h3 class="panel-title">宝塔Windows面板接口设置</h3></div>
|
<form onsubmit="return saveSetting(this)" method="post" class="form" role="form">
|
||||||
<div class="panel-body">
|
<div class="form-group">
|
||||||
<form onsubmit="return saveSetting(this)" method="post" class="form" role="form">
|
<label>宝塔云监控最新版本号:</label>
|
||||||
<p>以下宝塔面板请使用官方最新脚本安装并绑定账号,用于获取最新插件列表及插件包</p>
|
<input type="text" name="new_version_btm" value="{:config_get('new_version_btm')}" class="form-control"/>
|
||||||
<p><a href="/static/file/win/kaixin.zip">下载专用插件(Win)</a>,在面板【软件商店】->【第三方应用】,点击【导入插件】,导入该专用插件。</p>
|
<font color="green">用于一键更新脚本获取最新版本号,以及检测更新接口。并确保已在/public/install/src/放置对应版本更新包</font>
|
||||||
<div class="form-group">
|
</div>
|
||||||
<label>宝塔面板URL:</label><br/>
|
<div class="form-group">
|
||||||
<input type="text" name="wbt_url" value="{:config_get('wbt_url')}" class="form-control"/>
|
<label>宝塔云监控更新日志:</label>
|
||||||
<font color="green">填写规则如:<u>http://192.168.1.1:8888</u> ,不要带其他后缀</font>
|
<textarea class="form-control" name="update_msg_btm" rows="3" placeholder="支持HTML代码">{:config_get('update_msg_btm')}</textarea>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label>宝塔面板接口密钥:</label>
|
<label>宝塔云监控更新日期:</label>
|
||||||
<input type="text" name="wbt_key" value="{:config_get('wbt_key')}" class="form-control"/>
|
<input type="date" name="update_date_btm" value="{:config_get('update_date_btm')}" class="form-control"/>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group text-center">
|
<div class="form-group text-center">
|
||||||
<button type="button" class="btn btn-info btn-block" id="testbturl2">测试连接</button>
|
<input type="submit" name="submit" value="保存" class="btn btn-success btn-block"/>
|
||||||
<input type="submit" name="submit" value="保存" class="btn btn-success btn-block"/>
|
</div>
|
||||||
</div>
|
</form>
|
||||||
</form>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div class="panel panel-info">
|
||||||
</div>
|
<div class="panel-heading"><h3 class="panel-title">aaPanel面板版本设置</h3></div>
|
||||||
{elseif $mod=='task'}
|
<div class="panel-body">
|
||||||
<div class="col-sm-12 col-md-6 center-block">
|
<form onsubmit="return saveSetting(this)" method="post" class="form" role="form">
|
||||||
<div class="panel panel-success">
|
<div class="form-group">
|
||||||
<div class="panel-heading"><h3 class="panel-title">定时任务说明</h3></div>
|
<label>aaPanel面板最新版本号:</label>
|
||||||
<div class="panel-body">
|
<input type="text" name="new_version_en" value="{:config_get('new_version_en')}" class="form-control"/>
|
||||||
<form onsubmit="return saveSetting(this)" method="post" class="form" role="form">
|
<font color="green">用于一键更新脚本获取最新版本号,以及检测更新接口。并确保已在/public/install/update/放置对应版本更新包</font>
|
||||||
<div class="alert alert-info">使用以下命令可以从宝塔官方获取最新的插件列表并批量下载插件包(增量更新)。<br/>你也可以将此命令添加到crontab以使此云端的插件保持最新,建议1天执行1次。</div>
|
</div>
|
||||||
<div class="alert alert-danger">使用命令执行之后,可能会导致 /data 目录下文件权限不对,后台插件列表下载插件覆盖会报错,需要手动循环设置 /data 目录权限。</div>
|
<div class="form-group">
|
||||||
<div class="alert alert-warning">上次运行时间:{$runtime|raw}</div>
|
<label>aaPanel面板更新日志:</label>
|
||||||
<div class="list-group-item">php {:app()->getRootPath()}think updateall</div><br/>
|
<textarea class="form-control" name="update_msg_en" rows="5" placeholder="支持HTML代码">{:config_get('update_msg_en')}</textarea>
|
||||||
</form>
|
<font color="green">用于检测更新接口返回</font>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div class="form-group">
|
||||||
</div>
|
<label>aaPanel面板更新日期:</label>
|
||||||
<div class="col-sm-12 col-md-6 center-block">
|
<input type="date" name="update_date_en" value="{:config_get('update_date_en')}" class="form-control"/>
|
||||||
<div class="panel panel-info">
|
<font color="green">用于检测更新接口返回</font>
|
||||||
<div class="panel-heading"><h3 class="panel-title">定时任务设置</h3></div>
|
</div>
|
||||||
<div class="panel-body">
|
<div class="form-group text-center">
|
||||||
<form onsubmit="return saveSetting(this)" method="post" class="form" role="form">
|
<input type="submit" name="submit" value="保存" class="btn btn-success btn-block"/>
|
||||||
<div class="form-group">
|
</div>
|
||||||
<label>Linux面板批量下载插件范围:</label><br/>
|
</form>
|
||||||
<select class="form-control" name="updateall_type" default="{:config_get('updateall_type')}"><option value="0">仅免费插件</option><option value="1">免费插件+专业版插件</option><option value="2">免费插件+专业版插件+企业版插件</option></select><font color="green">(批量下载不包含所有第三方插件,第三方插件需要去手动下载。)</font>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
</div>
|
||||||
<label>Windows面板批量下载插件范围:</label><br/>
|
{elseif $mod=='api'}
|
||||||
<select class="form-control" name="updateall_type_win" default="{:config_get('updateall_type_win')}"><option value="0">仅免费插件</option><option value="1">免费插件+专业版插件</option><option value="2">免费插件+专业版插件+企业版插件</option></select><font color="green">(批量下载不包含所有第三方插件,第三方插件需要去手动下载。)</font>
|
<div class="col-sm-12 col-md-6 center-block">
|
||||||
</div>
|
<div class="panel panel-info">
|
||||||
<div class="form-group text-center">
|
<div class="panel-heading"><h3 class="panel-title">宝塔Linux面板接口设置</h3></div>
|
||||||
<input type="submit" name="submit" value="保存" class="btn btn-success btn-block"/>
|
<div class="panel-body">
|
||||||
</div>
|
<form onsubmit="return saveSetting(this)" method="post" class="form" role="form">
|
||||||
</form>
|
<div class="form-group">
|
||||||
</div>
|
<label>对接方式:</label><br/>
|
||||||
</div>
|
<select class="form-control" name="bt_type" default="{:config_get('bt_type')}"><option value="0">对接宝塔面板接口</option><option value="1">对接其他第三方云端</option></select>
|
||||||
</div>
|
</div><hr/>
|
||||||
{elseif $mod=='account'}
|
<div id="bt_type_0" style="{if config_get('bt_type')==1}display:none;{/if}">
|
||||||
<div class="col-xs-12 col-sm-8 col-lg-6 center-block" style="float: none;">
|
<p>以下宝塔面板请使用官方最新脚本安装并绑定账号,用于获取插件列表及插件包</p>
|
||||||
<div class="panel panel-primary">
|
<p><a href="/static/file/kaixin.zip">下载专用插件(Linux)</a>,在面板【软件商店】->【第三方应用】,点击【导入插件】,导入该专用插件。</p>
|
||||||
<div class="panel-heading"><h3 class="panel-title">管理账号设置</h3></div>
|
<div class="form-group">
|
||||||
<div class="panel-body">
|
<label>宝塔面板URL:</label><br/>
|
||||||
<form onsubmit="return saveAccount(this)" method="post" class="form" role="form">
|
<input type="text" name="bt_url" value="{:config_get('bt_url')}" class="form-control"/>
|
||||||
<div class="form-group">
|
<font color="green">填写规则如:<u>http://192.168.1.1:8888</u> ,不要带其他后缀</font>
|
||||||
<label>用户名:</label><br/>
|
</div>
|
||||||
<input type="text" name="username" value="{:config_get('admin_username')}" class="form-control" required/>
|
<div class="form-group">
|
||||||
</div>
|
<label>宝塔面板接口密钥:</label>
|
||||||
<div class="form-group">
|
<input type="text" name="bt_key" value="{:config_get('bt_key')}" class="form-control"/>
|
||||||
<label>旧密码:</label>
|
</div>
|
||||||
<input type="password" name="oldpwd" value="" class="form-control" placeholder="请输入当前的管理员密码"/>
|
</div>
|
||||||
</div>
|
<div id="bt_type_1" style="{if !config_get('bt_type')}display:none;{/if}">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label>新密码:</label>
|
<label>第三方云端首页URL:</label><br/>
|
||||||
<input type="password" name="newpwd" value="" class="form-control" placeholder="不修改请留空"/>
|
<input type="text" name="bt_surl" value="{:config_get('bt_surl')}" class="form-control"/>
|
||||||
</div>
|
<font color="green">填写规则如:<u>http://www.example.com/</u> ,必须以/结尾</font>
|
||||||
<div class="form-group">
|
</div>
|
||||||
<label>重输密码:</label>
|
</div>
|
||||||
<input type="password" name="newpwd2" value="" class="form-control" placeholder="不修改请留空"/>
|
<div class="form-group text-center">
|
||||||
</div>
|
<button type="button" class="btn btn-info btn-block" id="testbturl">测试连接</button>
|
||||||
<div class="form-group text-center">
|
<input type="submit" name="submit" value="保存" class="btn btn-success btn-block"/>
|
||||||
<input type="submit" name="submit" value="保存" class="btn btn-success btn-block"/>
|
</div>
|
||||||
</div>
|
</form>
|
||||||
<a href="javascript:cleancache()" class="btn btn-default btn-sm btn-block">清理缓存</a>
|
</div>
|
||||||
</form>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div class="col-sm-12 col-md-6 center-block">
|
||||||
{elseif $mod=='tools'}
|
<div class="panel panel-info">
|
||||||
<div class="col-sm-12 col-md-10 col-lg-8 center-block" style="float: none;">
|
<div class="panel-heading"><h3 class="panel-title">宝塔Windows面板接口设置</h3></div>
|
||||||
<div class="panel panel-primary">
|
<div class="panel-body">
|
||||||
<div class="panel-heading"><h3 class="panel-title">批量替换工具</h3></div>
|
<form onsubmit="return saveSetting(this)" method="post" class="form" role="form">
|
||||||
<div class="panel-body">
|
<div class="form-group">
|
||||||
<form onsubmit="return saveAccount(this)" method="post" class="form" role="form">
|
<label>对接方式:</label><br/>
|
||||||
<div class="alert alert-info" style="word-break:break-all;">使用以下命令可以将bt安装包、更新包和脚本文件里面的<code>http://www.example.com</code>批量替换成当前网址<code>{:request()->root(true)}</code>,每次更新版本后只需要执行一次即可。</div>
|
<select class="form-control" name="wbt_type" default="{:config_get('wbt_type')}"><option value="0">对接宝塔面板接口</option><option value="1">对接其他第三方云端</option></select>
|
||||||
<div class="list-group-item" style="word-break:break-all;">cd {:app()->getRootPath()}app/script && chmod +x convert.sh && ./convert.sh {:app()->getRootPath()} {:request()->root(true)}</div><br/>
|
</div><hr/>
|
||||||
</form>
|
<div id="wbt_type_0" style="{if config_get('wbt_type')==1}display:none;{/if}">
|
||||||
</div>
|
<p>以下宝塔面板请使用官方最新脚本安装并绑定账号,用于获取插件列表及插件包</p>
|
||||||
</div>
|
<p><a href="/static/file/win/kaixin.zip">下载专用插件(Win)</a>,上传到 /BtSoft/panel/plugin/ 解压,即可在软件商店已安装列表看到。</p>
|
||||||
{/if}
|
<div class="form-group">
|
||||||
<script src="//cdn.staticfile.org/layer/3.5.1/layer.js"></script>
|
<label>宝塔面板URL:</label><br/>
|
||||||
<script>
|
<input type="text" name="wbt_url" value="{:config_get('wbt_url')}" class="form-control"/>
|
||||||
$(document).ready(function(){
|
<font color="green">填写规则如:<u>http://192.168.1.1:8888</u> ,不要带其他后缀</font>
|
||||||
var items = $("select[default]");
|
</div>
|
||||||
for (i = 0; i < items.length; i++) {
|
<div class="form-group">
|
||||||
$(items[i]).val($(items[i]).attr("default")||0);
|
<label>宝塔面板接口密钥:</label>
|
||||||
}
|
<input type="text" name="wbt_key" value="{:config_get('wbt_key')}" class="form-control"/>
|
||||||
$("#testbturl").click(function(){
|
</div>
|
||||||
var bt_url = $("input[name=bt_url]").val();
|
</div>
|
||||||
var bt_key = $("input[name=bt_key]").val();
|
<div id="wbt_type_1" style="{if !config_get('wbt_type')}display:none;{/if}">
|
||||||
if(bt_url == ''){
|
<div class="form-group">
|
||||||
layer.alert('宝塔面板URL不能为空');return;
|
<label>第三方云端首页URL:</label><br/>
|
||||||
}
|
<input type="text" name="wbt_surl" value="{:config_get('wbt_surl')}" class="form-control"/>
|
||||||
if(bt_url.indexOf('http://')==-1 && bt_url.indexOf('https://')==-1){
|
<font color="green">填写规则如:<u>http://www.example.com/</u> ,必须以/结尾</font>
|
||||||
layer.alert('宝塔面板URL不正确');return;
|
</div>
|
||||||
}
|
</div>
|
||||||
if(bt_key == ''){
|
<div class="form-group text-center">
|
||||||
layer.alert('宝塔面板接口密钥不能为空');return;
|
<button type="button" class="btn btn-info btn-block" id="testbturl2">测试连接</button>
|
||||||
}
|
<input type="submit" name="submit" value="保存" class="btn btn-success btn-block"/>
|
||||||
var ii = layer.load(2, {shade:[0.1,'#fff']});
|
</div>
|
||||||
$.ajax({
|
</form>
|
||||||
type : 'POST',
|
</div>
|
||||||
url : '/admin/testbturl',
|
</div>
|
||||||
data : {bt_url:bt_url, bt_key:bt_key},
|
</div>
|
||||||
dataType : 'json',
|
<div class="col-sm-12 col-md-6 center-block">
|
||||||
success : function(data) {
|
<div class="panel panel-info">
|
||||||
layer.close(ii);
|
<div class="panel-heading"><h3 class="panel-title">aaPanel面板接口设置</h3></div>
|
||||||
if(data.code == 0){
|
<div class="panel-body">
|
||||||
layer.msg(data.msg, {icon: 1, time:1000})
|
<form onsubmit="return saveSetting(this)" method="post" class="form" role="form">
|
||||||
}else{
|
<div class="form-group">
|
||||||
layer.alert(data.msg, {icon: 2})
|
<label>对接方式:</label><br/>
|
||||||
}
|
<select class="form-control" name="enbt_type" default="{:config_get('enbt_type')}"><option value="0">对接aaPanel面板接口</option><option value="1">对接其他第三方云端</option></select>
|
||||||
},
|
</div><hr/>
|
||||||
error:function(data){
|
<div id="enbt_type_0" style="{if config_get('enbt_type')==1}display:none;{/if}">
|
||||||
layer.close(ii);
|
<p>以下aaPanel面板请使用官方最新脚本安装并绑定账号,用于获取插件列表及插件包</p>
|
||||||
layer.msg('服务器错误');
|
<p><a href="/static/file/en/kaixin.zip">下载专用插件(aaPanel)</a>,在面板【软件商店】->【第三方应用】,点击【导入插件】,导入该专用插件。</p>
|
||||||
}
|
<div class="form-group">
|
||||||
});
|
<label>aaPanel面板URL:</label><br/>
|
||||||
})
|
<input type="text" name="enbt_url" value="{:config_get('enbt_url')}" class="form-control"/>
|
||||||
$("#testbturl2").click(function(){
|
<font color="green">填写规则如:<u>http://192.168.1.1:8888</u> ,不要带其他后缀</font>
|
||||||
var wbt_url = $("input[name=wbt_url]").val();
|
</div>
|
||||||
var wbt_key = $("input[name=wbt_key]").val();
|
<div class="form-group">
|
||||||
if(wbt_url == ''){
|
<label>aaPanel面板接口密钥:</label>
|
||||||
layer.alert('宝塔面板URL不能为空');return;
|
<input type="text" name="enbt_key" value="{:config_get('enbt_key')}" class="form-control"/>
|
||||||
}
|
</div>
|
||||||
if(wbt_url.indexOf('http://')==-1 && wbt_url.indexOf('https://')==-1){
|
</div>
|
||||||
layer.alert('宝塔面板URL不正确');return;
|
<div id="enbt_type_1" style="{if !config_get('enbt_type')}display:none;{/if}">
|
||||||
}
|
<div class="form-group">
|
||||||
if(wbt_key == ''){
|
<label>第三方云端首页URL:</label><br/>
|
||||||
layer.alert('宝塔面板接口密钥不能为空');return;
|
<input type="text" name="enbt_surl" value="{:config_get('enbt_surl')}" class="form-control"/>
|
||||||
}
|
<font color="green">填写规则如:<u>http://www.example.com/</u> ,必须以/结尾</font>
|
||||||
var ii = layer.load(2, {shade:[0.1,'#fff']});
|
</div>
|
||||||
$.ajax({
|
</div>
|
||||||
type : 'POST',
|
<div class="form-group text-center">
|
||||||
url : '/admin/testbturl',
|
<button type="button" class="btn btn-info btn-block" id="testbturl3">测试连接</button>
|
||||||
data : {bt_url:wbt_url, bt_key:wbt_key},
|
<input type="submit" name="submit" value="保存" class="btn btn-success btn-block"/>
|
||||||
dataType : 'json',
|
</div>
|
||||||
success : function(data) {
|
</form>
|
||||||
layer.close(ii);
|
</div>
|
||||||
if(data.code == 0){
|
</div>
|
||||||
layer.msg(data.msg, {icon: 1, time:1000})
|
</div>
|
||||||
}else{
|
<script>
|
||||||
layer.alert(data.msg, {icon: 2})
|
$("select[name='bt_type']").change(function(){
|
||||||
}
|
if($(this).val() == 1){
|
||||||
},
|
$("#bt_type_0").hide();
|
||||||
error:function(data){
|
$("#bt_type_1").show();
|
||||||
layer.close(ii);
|
}else{
|
||||||
layer.msg('服务器错误');
|
$("#bt_type_0").show();
|
||||||
}
|
$("#bt_type_1").hide();
|
||||||
});
|
}
|
||||||
})
|
});
|
||||||
})
|
$("select[name='wbt_type']").change(function(){
|
||||||
function saveSetting(obj){
|
if($(this).val() == 1){
|
||||||
var ii = layer.load(2, {shade:[0.1,'#fff']});
|
$("#wbt_type_0").hide();
|
||||||
$.ajax({
|
$("#wbt_type_1").show();
|
||||||
type : 'POST',
|
}else{
|
||||||
url : '/admin/set',
|
$("#wbt_type_0").show();
|
||||||
data : $(obj).serialize(),
|
$("#wbt_type_1").hide();
|
||||||
dataType : 'json',
|
}
|
||||||
success : function(data) {
|
});
|
||||||
layer.close(ii);
|
$("select[name='enbt_type']").change(function(){
|
||||||
if(data.code == 0){
|
if($(this).val() == 1){
|
||||||
layer.alert('设置保存成功!', {
|
$("#enbt_type_0").hide();
|
||||||
icon: 1,
|
$("#enbt_type_1").show();
|
||||||
closeBtn: false
|
}else{
|
||||||
}, function(){
|
$("#enbt_type_0").show();
|
||||||
window.location.reload()
|
$("#enbt_type_1").hide();
|
||||||
});
|
}
|
||||||
}else{
|
});
|
||||||
layer.alert(data.msg, {icon: 2})
|
</script>
|
||||||
}
|
{elseif $mod=='task'}
|
||||||
},
|
<div class="col-sm-12 col-md-6 center-block">
|
||||||
error:function(data){
|
<div class="panel panel-success">
|
||||||
layer.close(ii);
|
<div class="panel-heading"><h3 class="panel-title">自动更新插件说明</h3></div>
|
||||||
layer.msg('服务器错误');
|
<div class="panel-body">
|
||||||
}
|
<form onsubmit="return saveSetting(this)" method="post" class="form" role="form">
|
||||||
});
|
<div class="alert alert-info">使用以下命令可以从宝塔官方获取最新的插件列表并批量下载插件包(增量更新)。<br/>你也可以将此命令添加到crontab以使此云端的插件保持最新,建议1天执行1次。</div>
|
||||||
return false;
|
{if $is_user_www}<div class="alert alert-danger">注:计划任务执行用户必须选择www用户</div>{/if}
|
||||||
}
|
<div class="alert alert-warning">上次运行时间:{$runtime|raw}</div>
|
||||||
function saveAccount(obj){
|
<div class="list-group-item">php {:app()->getRootPath()}think updateall</div><br/>
|
||||||
var ii = layer.load(2, {shade:[0.1,'#fff']});
|
</form>
|
||||||
$.ajax({
|
</div>
|
||||||
type : 'POST',
|
</div>
|
||||||
url : '/admin/setaccount',
|
</div>
|
||||||
data : $(obj).serialize(),
|
<div class="col-sm-12 col-md-6 center-block">
|
||||||
dataType : 'json',
|
<div class="panel panel-info">
|
||||||
success : function(data) {
|
<div class="panel-heading"><h3 class="panel-title">自动更新插件设置</h3></div>
|
||||||
layer.close(ii);
|
<div class="panel-body">
|
||||||
if(data.code == 0){
|
<form onsubmit="return saveSetting(this)" method="post" class="form" role="form">
|
||||||
layer.alert('管理账号保存成功!请重新登录。', {
|
<div class="form-group">
|
||||||
icon: 1,
|
<label>Linux面板批量下载插件范围:</label><br/>
|
||||||
closeBtn: false
|
<select class="form-control" name="updateall_type" default="{:config_get('updateall_type')}"><option value="0">仅免费插件</option><option value="1">免费插件+专业版插件</option><option value="2">免费插件+专业版插件+企业版插件</option></select><font color="green">(批量下载不包含所有第三方插件,第三方插件需要去手动下载。)</font>
|
||||||
}, function(){
|
</div>
|
||||||
window.location.reload()
|
<div class="form-group">
|
||||||
});
|
<label>Windows面板批量下载插件范围:</label><br/>
|
||||||
}else{
|
<select class="form-control" name="updateall_type_win" default="{:config_get('updateall_type_win')}"><option value="0">仅免费插件</option><option value="1">免费插件+专业版插件</option><option value="2">免费插件+专业版插件+企业版插件</option></select><font color="green">(批量下载不包含所有第三方插件,第三方插件需要去手动下载。)</font>
|
||||||
layer.alert(data.msg, {icon: 2})
|
</div>
|
||||||
}
|
<div class="form-group">
|
||||||
},
|
<label>aaPanel面板批量下载插件范围:</label><br/>
|
||||||
error:function(data){
|
<select class="form-control" name="updateall_type_en" default="{:config_get('updateall_type_en')}"><option value="0">仅免费插件</option><option value="1">免费插件+专业版插件</option><option value="2">免费插件+专业版插件+企业版插件</option></select><font color="green">(批量下载不包含所有第三方插件,第三方插件需要去手动下载。)</font>
|
||||||
layer.close(ii);
|
</div>
|
||||||
layer.msg('服务器错误');
|
<div class="form-group text-center">
|
||||||
}
|
<input type="submit" name="submit" value="保存" class="btn btn-success btn-block"/>
|
||||||
});
|
</div>
|
||||||
return false;
|
</form>
|
||||||
}
|
</div>
|
||||||
function cleancache(){
|
</div>
|
||||||
var ii = layer.load(2, {shade:[0.1,'#fff']});
|
</div>
|
||||||
$.ajax({
|
{elseif $mod=='account'}
|
||||||
type : 'GET',
|
<div class="col-xs-12 col-sm-8 col-lg-6 center-block" style="float: none;">
|
||||||
url : '/admin/cleancache',
|
<div class="panel panel-primary">
|
||||||
dataType : 'json',
|
<div class="panel-heading"><h3 class="panel-title">管理账号设置</h3></div>
|
||||||
success : function(data) {
|
<div class="panel-body">
|
||||||
layer.close(ii);
|
<form onsubmit="return saveAccount(this)" method="post" class="form" role="form">
|
||||||
layer.msg('清理缓存成功', {icon: 1});
|
<div class="form-group">
|
||||||
},
|
<label>用户名:</label><br/>
|
||||||
error:function(data){
|
<input type="text" name="username" value="{:config_get('admin_username')}" class="form-control" required/>
|
||||||
layer.close(ii);
|
</div>
|
||||||
layer.msg('服务器错误');
|
<div class="form-group">
|
||||||
}
|
<label>旧密码:</label>
|
||||||
});
|
<input type="password" name="oldpwd" value="" class="form-control" placeholder="请输入当前的管理员密码"/>
|
||||||
}
|
</div>
|
||||||
</script>
|
<div class="form-group">
|
||||||
|
<label>新密码:</label>
|
||||||
|
<input type="password" name="newpwd" value="" class="form-control" placeholder="不修改请留空"/>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label>重输密码:</label>
|
||||||
|
<input type="password" name="newpwd2" value="" class="form-control" placeholder="不修改请留空"/>
|
||||||
|
</div>
|
||||||
|
<div class="form-group text-center">
|
||||||
|
<input type="submit" name="submit" value="保存" class="btn btn-success btn-block"/>
|
||||||
|
</div>
|
||||||
|
<a href="javascript:cleancache()" class="btn btn-default btn-sm btn-block">清理缓存</a>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{elseif $mod=='tools'}
|
||||||
|
<div class="col-sm-12 col-md-10 col-lg-8 center-block" style="float: none;">
|
||||||
|
<div class="panel panel-primary">
|
||||||
|
<div class="panel-heading"><h3 class="panel-title">批量替换工具</h3></div>
|
||||||
|
<div class="panel-body">
|
||||||
|
<form onsubmit="return saveAccount(this)" method="post" class="form" role="form">
|
||||||
|
<div class="alert alert-info" style="word-break:break-all;">使用以下命令可以将bt安装包、更新包和脚本文件里面的<code>http://www.example.com</code>批量替换成当前网址<code>{:request()->root(true)}</code>,每次更新版本后只需要执行一次即可。</div>
|
||||||
|
<div class="list-group-item" style="word-break:break-all;">cd {:app()->getRootPath()}app/script && chmod +x convert.sh && ./convert.sh {:app()->getRootPath()} {:request()->root(true)}</div><br/>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="panel panel-primary">
|
||||||
|
<div class="panel-heading"><h3 class="panel-title">清理旧版本插件工具</h3></div>
|
||||||
|
<div class="panel-body">
|
||||||
|
<form onsubmit="return saveAccount(this)" method="post" class="form" role="form">
|
||||||
|
<div class="alert alert-info" style="word-break:break-all;">使用以下命令可清理旧版本的插件文件,以释放空间占用。</div>
|
||||||
|
<div class="list-group-item" style="word-break:break-all;">php {:app()->getRootPath()}think clean</div><br/>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
<script src="{$cdnpublic}layer/3.5.1/layer.js"></script>
|
||||||
|
<script>
|
||||||
|
$(document).ready(function(){
|
||||||
|
var items = $("select[default]");
|
||||||
|
for (i = 0; i < items.length; i++) {
|
||||||
|
$(items[i]).val($(items[i]).attr("default")||0);
|
||||||
|
}
|
||||||
|
$("#testbturl").click(function(){
|
||||||
|
var bt_type = $("select[name=bt_type]").val();
|
||||||
|
if(bt_type == '1'){
|
||||||
|
var bt_surl = $("input[name=bt_surl]").val();
|
||||||
|
if(bt_surl == ''){
|
||||||
|
layer.alert('第三方云端URL不能为空');return;
|
||||||
|
}
|
||||||
|
if(bt_surl.indexOf('http://')==-1 && bt_surl.indexOf('https://')==-1){
|
||||||
|
layer.alert('第三方云端URL不正确');return;
|
||||||
|
}
|
||||||
|
var postdata = {bt_type:bt_type, bt_surl:bt_surl};
|
||||||
|
}else{
|
||||||
|
var bt_url = $("input[name=bt_url]").val();
|
||||||
|
var bt_key = $("input[name=bt_key]").val();
|
||||||
|
if(bt_url == ''){
|
||||||
|
layer.alert('宝塔面板URL不能为空');return;
|
||||||
|
}
|
||||||
|
if(bt_url.indexOf('http://')==-1 && bt_url.indexOf('https://')==-1){
|
||||||
|
layer.alert('宝塔面板URL不正确');return;
|
||||||
|
}
|
||||||
|
if(bt_key == ''){
|
||||||
|
layer.alert('宝塔面板接口密钥不能为空');return;
|
||||||
|
}
|
||||||
|
var postdata = {os:'linux', bt_type:bt_type, bt_url:bt_url, bt_key:bt_key};
|
||||||
|
}
|
||||||
|
var ii = layer.load(2, {shade:[0.1,'#fff']});
|
||||||
|
$.ajax({
|
||||||
|
type : 'POST',
|
||||||
|
url : '/admin/testbturl',
|
||||||
|
data : postdata,
|
||||||
|
dataType : 'json',
|
||||||
|
success : function(data) {
|
||||||
|
layer.close(ii);
|
||||||
|
if(data.code == 0){
|
||||||
|
layer.msg(data.msg, {icon: 1, time:1000})
|
||||||
|
}else{
|
||||||
|
layer.alert(data.msg, {icon: 2})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error:function(data){
|
||||||
|
layer.close(ii);
|
||||||
|
layer.msg('服务器错误');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
})
|
||||||
|
$("#testbturl2").click(function(){
|
||||||
|
var wbt_type = $("select[name=wbt_type]").val();
|
||||||
|
if(wbt_type == '1'){
|
||||||
|
var wbt_surl = $("input[name=wbt_surl]").val();
|
||||||
|
if(wbt_surl == ''){
|
||||||
|
layer.alert('第三方云端URL不能为空');return;
|
||||||
|
}
|
||||||
|
if(wbt_surl.indexOf('http://')==-1 && wbt_surl.indexOf('https://')==-1){
|
||||||
|
layer.alert('第三方云端URL不正确');return;
|
||||||
|
}
|
||||||
|
var postdata = {bt_type:wbt_type, bt_surl:wbt_surl};
|
||||||
|
}else{
|
||||||
|
var wbt_url = $("input[name=wbt_url]").val();
|
||||||
|
var wbt_key = $("input[name=wbt_key]").val();
|
||||||
|
if(wbt_url == ''){
|
||||||
|
layer.alert('宝塔面板URL不能为空');return;
|
||||||
|
}
|
||||||
|
if(wbt_url.indexOf('http://')==-1 && wbt_url.indexOf('https://')==-1){
|
||||||
|
layer.alert('宝塔面板URL不正确');return;
|
||||||
|
}
|
||||||
|
if(wbt_key == ''){
|
||||||
|
layer.alert('宝塔面板接口密钥不能为空');return;
|
||||||
|
}
|
||||||
|
var postdata = {os:'win', bt_type:wbt_type, bt_url:wbt_url, bt_key:wbt_key};
|
||||||
|
}
|
||||||
|
var ii = layer.load(2, {shade:[0.1,'#fff']});
|
||||||
|
$.ajax({
|
||||||
|
type : 'POST',
|
||||||
|
url : '/admin/testbturl',
|
||||||
|
data : postdata,
|
||||||
|
dataType : 'json',
|
||||||
|
success : function(data) {
|
||||||
|
layer.close(ii);
|
||||||
|
if(data.code == 0){
|
||||||
|
layer.msg(data.msg, {icon: 1, time:1000})
|
||||||
|
}else{
|
||||||
|
layer.alert(data.msg, {icon: 2})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error:function(data){
|
||||||
|
layer.close(ii);
|
||||||
|
layer.msg('服务器错误');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
})
|
||||||
|
$("#testbturl3").click(function(){
|
||||||
|
var enbt_type = $("select[name=enbt_type]").val();
|
||||||
|
if(enbt_type == '1'){
|
||||||
|
var enbt_surl = $("input[name=enbt_surl]").val();
|
||||||
|
if(enbt_surl == ''){
|
||||||
|
layer.alert('第三方云端URL不能为空');return;
|
||||||
|
}
|
||||||
|
if(enbt_surl.indexOf('http://')==-1 && enbt_surl.indexOf('https://')==-1){
|
||||||
|
layer.alert('第三方云端URL不正确');return;
|
||||||
|
}
|
||||||
|
var postdata = {bt_type:enbt_type, bt_surl:enbt_surl};
|
||||||
|
}else{
|
||||||
|
var enbt_url = $("input[name=enbt_url]").val();
|
||||||
|
var enbt_key = $("input[name=enbt_key]").val();
|
||||||
|
if(enbt_url == ''){
|
||||||
|
layer.alert('宝塔面板URL不能为空');return;
|
||||||
|
}
|
||||||
|
if(enbt_url.indexOf('http://')==-1 && enbt_url.indexOf('https://')==-1){
|
||||||
|
layer.alert('宝塔面板URL不正确');return;
|
||||||
|
}
|
||||||
|
if(enbt_key == ''){
|
||||||
|
layer.alert('宝塔面板接口密钥不能为空');return;
|
||||||
|
}
|
||||||
|
var postdata = {os:'en', bt_type:enbt_type, bt_url:enbt_url, bt_key:enbt_key};
|
||||||
|
}
|
||||||
|
var ii = layer.load(2, {shade:[0.1,'#fff']});
|
||||||
|
$.ajax({
|
||||||
|
type : 'POST',
|
||||||
|
url : '/admin/testbturl',
|
||||||
|
data : postdata,
|
||||||
|
dataType : 'json',
|
||||||
|
success : function(data) {
|
||||||
|
layer.close(ii);
|
||||||
|
if(data.code == 0){
|
||||||
|
layer.msg(data.msg, {icon: 1, time:1000})
|
||||||
|
}else{
|
||||||
|
layer.alert(data.msg, {icon: 2})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error:function(data){
|
||||||
|
layer.close(ii);
|
||||||
|
layer.msg('服务器错误');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
})
|
||||||
|
})
|
||||||
|
function saveSetting(obj){
|
||||||
|
var ii = layer.load(2, {shade:[0.1,'#fff']});
|
||||||
|
$.ajax({
|
||||||
|
type : 'POST',
|
||||||
|
url : '/admin/set',
|
||||||
|
data : $(obj).serialize(),
|
||||||
|
dataType : 'json',
|
||||||
|
success : function(data) {
|
||||||
|
layer.close(ii);
|
||||||
|
if(data.code == 0){
|
||||||
|
layer.alert('设置保存成功!', {
|
||||||
|
icon: 1,
|
||||||
|
closeBtn: false
|
||||||
|
}, function(){
|
||||||
|
window.location.reload()
|
||||||
|
});
|
||||||
|
}else{
|
||||||
|
layer.alert(data.msg, {icon: 2})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error:function(data){
|
||||||
|
layer.close(ii);
|
||||||
|
layer.msg('服务器错误');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
function saveAccount(obj){
|
||||||
|
var ii = layer.load(2, {shade:[0.1,'#fff']});
|
||||||
|
$.ajax({
|
||||||
|
type : 'POST',
|
||||||
|
url : '/admin/setaccount',
|
||||||
|
data : $(obj).serialize(),
|
||||||
|
dataType : 'json',
|
||||||
|
success : function(data) {
|
||||||
|
layer.close(ii);
|
||||||
|
if(data.code == 0){
|
||||||
|
layer.alert('管理账号保存成功!请重新登录。', {
|
||||||
|
icon: 1,
|
||||||
|
closeBtn: false
|
||||||
|
}, function(){
|
||||||
|
window.location.reload()
|
||||||
|
});
|
||||||
|
}else{
|
||||||
|
layer.alert(data.msg, {icon: 2})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error:function(data){
|
||||||
|
layer.close(ii);
|
||||||
|
layer.msg('服务器错误');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
function cleancache(){
|
||||||
|
var ii = layer.load(2, {shade:[0.1,'#fff']});
|
||||||
|
$.ajax({
|
||||||
|
type : 'GET',
|
||||||
|
url : '/admin/cleancache',
|
||||||
|
dataType : 'json',
|
||||||
|
success : function(data) {
|
||||||
|
layer.close(ii);
|
||||||
|
layer.msg('清理缓存成功', {icon: 1});
|
||||||
|
},
|
||||||
|
error:function(data){
|
||||||
|
layer.close(ii);
|
||||||
|
layer.msg('服务器错误');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
</script>
|
||||||
{/block}
|
{/block}
|
||||||
86
app/view/admin/ssl.html
Normal file
86
app/view/admin/ssl.html
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
{extend name="admin/layout" /}
|
||||||
|
{block name="title"}自签名SSL证书生成{/block}
|
||||||
|
{block name="main"}
|
||||||
|
<style>
|
||||||
|
.control-label[is-required]:before {
|
||||||
|
content: "*";
|
||||||
|
color: #f56c6c;
|
||||||
|
margin-right: 4px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<div class="container" style="padding-top:70px;">
|
||||||
|
<div class="col-sm-12 col-md-10 col-lg-8 center-block" style="float: none;">
|
||||||
|
<div class="panel panel-primary">
|
||||||
|
<div class="panel-heading"><h3 class="panel-title">自签名SSL证书生成</h3></div>
|
||||||
|
<div class="panel-body">
|
||||||
|
{if $isca}
|
||||||
|
<div class="alert alert-warning" style="word-break:break-all;">下载CA证书并导入,可解决浏览器不安全提醒。<br/>Windows:<a href="/ssl/baota_root.pfx">baota_root.pfx</a>(密码为空),Mac/Linux:<a href="/ssl/baota_root.crt">baota_root.crt</a></div>
|
||||||
|
<form onsubmit="return makeSSL(this)" method="post" class="form" role="form">
|
||||||
|
<div class="form-group">
|
||||||
|
<label is-required="true" class="control-label">域名列表:</label>
|
||||||
|
<textarea class="form-control" name="domain_list" rows="6" placeholder="每行一个域名/IP,支持通配符" required></textarea>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="control-label">通用名称:</label>
|
||||||
|
<input type="text" name="common_name" value="" placeholder="留空则为域名列表第一个域名" class="form-control"/>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label is-required="true" class="control-label">有效天数:</label>
|
||||||
|
<input type="number" name="validity" value="3650" class="form-control" required/>
|
||||||
|
</div>
|
||||||
|
<div class="form-group text-center">
|
||||||
|
<input type="submit" name="submit" value="生成自签名证书" class="btn btn-success btn-block"/>
|
||||||
|
</div>
|
||||||
|
<div class="form-group row" id="result" style="display:none;">
|
||||||
|
<div class="col-md-6">
|
||||||
|
<label class="control-label">SSL证书:</label>
|
||||||
|
<textarea class="form-control" name="ssl_cert" rows="5" onclick="copy(this)" title="点击复制"></textarea>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6">
|
||||||
|
<label class="control-label">SSL证书私钥:</label>
|
||||||
|
<textarea class="form-control" name="ssl_key" rows="5" onclick="copy(this)" title="点击复制"></textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
{else}
|
||||||
|
<div class="alert alert-danger" role="alert">你还没有生成CA证书,无法生成SSL证书!</div>
|
||||||
|
<div class="alert alert-info" style="word-break:break-all;">执行以下命令,生成自签名CA证书。然后,可通过接口或当前页面生成SSL证书,用于面板访问。</div>
|
||||||
|
<div class="list-group-item" style="word-break:break-all;">cd {:app()->getRootPath()}app/script && chmod +x cacert.sh && ./cacert.sh</div><br/>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script src="{$cdnpublic}layer/3.5.1/layer.js"></script>
|
||||||
|
<script>
|
||||||
|
function makeSSL(obj){
|
||||||
|
var ii = layer.load(2, {shade:[0.1,'#fff']});
|
||||||
|
$.ajax({
|
||||||
|
type : 'POST',
|
||||||
|
url : '/admin/ssl',
|
||||||
|
data : $(obj).serialize(),
|
||||||
|
dataType : 'json',
|
||||||
|
success : function(data) {
|
||||||
|
layer.close(ii);
|
||||||
|
if(data.code == 0){
|
||||||
|
$("textarea[name='ssl_cert']").val(data.cert);
|
||||||
|
$("textarea[name='ssl_key']").val(data.key);
|
||||||
|
$("#result").show();
|
||||||
|
layer.msg('SSL证书生成成功', {icon:1, time:800});
|
||||||
|
}else{
|
||||||
|
layer.alert(data.msg, {icon: 2})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error:function(data){
|
||||||
|
layer.close(ii);
|
||||||
|
layer.msg('服务器错误');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
function copy(obj){
|
||||||
|
if($(obj).val() == '') return;
|
||||||
|
$(obj).select();
|
||||||
|
document.execCommand("Copy");
|
||||||
|
layer.msg('复制成功', {icon:1, time:500});
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
{/block}
|
||||||
@ -1,60 +1,60 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||||
<title>温馨提示</title>
|
<title>温馨提示</title>
|
||||||
<meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width">
|
<meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width">
|
||||||
<meta name="renderer" content="webkit"/>
|
<meta name="renderer" content="webkit"/>
|
||||||
<style type="text/css">
|
<style type="text/css">
|
||||||
*{box-sizing:border-box;margin:0;padding:0;font-family:Lantinghei SC,Open Sans,Arial,Hiragino Sans GB,Microsoft YaHei,"微软雅黑",STHeiti,WenQuanYi Micro Hei,SimSun,sans-serif;-webkit-font-smoothing:antialiased}
|
*{box-sizing:border-box;margin:0;padding:0;font-family:Lantinghei SC,Open Sans,Arial,Hiragino Sans GB,Microsoft YaHei,"微软雅黑",STHeiti,WenQuanYi Micro Hei,SimSun,sans-serif;-webkit-font-smoothing:antialiased}
|
||||||
body{padding:70px 0;background:#edf1f4;font-weight:400;font-size:1pc;-webkit-text-size-adjust:none;color:#333}
|
body{padding:70px 0;background:#edf1f4;font-weight:400;font-size:1pc;-webkit-text-size-adjust:none;color:#333}
|
||||||
a{outline:0;color:#3498db;text-decoration:none;cursor:pointer}
|
a{outline:0;color:#3498db;text-decoration:none;cursor:pointer}
|
||||||
.system-message{margin:20px 5%;padding:40px 20px;background:#fff;box-shadow:1px 1px 1px hsla(0,0%,39%,.1);text-align:center}
|
.system-message{margin:20px 5%;padding:40px 20px;background:#fff;box-shadow:1px 1px 1px hsla(0,0%,39%,.1);text-align:center}
|
||||||
.system-message h1{margin:0;margin-bottom:9pt;color:#444;font-weight:400;font-size:40px}
|
.system-message h1{margin:0;margin-bottom:9pt;color:#444;font-weight:400;font-size:40px}
|
||||||
.system-message .jump,.system-message .image{margin:20px 0;padding:0;padding:10px 0;font-weight:400}
|
.system-message .jump,.system-message .image{margin:20px 0;padding:0;padding:10px 0;font-weight:400}
|
||||||
.system-message .jump{font-size:14px}
|
.system-message .jump{font-size:14px}
|
||||||
.system-message .jump a{color:#333}
|
.system-message .jump a{color:#333}
|
||||||
.system-message p{font-size:9pt;line-height:20px}
|
.system-message p{font-size:9pt;line-height:20px}
|
||||||
.system-message .btn{display:inline-block;margin-right:10px;width:138px;height:2pc;border:1px solid #44a0e8;border-radius:30px;color:#44a0e8;text-align:center;font-size:1pc;line-height:2pc;margin-bottom:5px;}
|
.system-message .btn{display:inline-block;margin-right:10px;width:138px;height:2pc;border:1px solid #44a0e8;border-radius:30px;color:#44a0e8;text-align:center;font-size:1pc;line-height:2pc;margin-bottom:5px;}
|
||||||
.success .btn{border-color:#69bf4e;color:#69bf4e}
|
.success .btn{border-color:#69bf4e;color:#69bf4e}
|
||||||
.error .btn{border-color:#ff8992;color:#ff8992}
|
.error .btn{border-color:#ff8992;color:#ff8992}
|
||||||
.info .btn{border-color:#3498db;color:#3498db}
|
.info .btn{border-color:#3498db;color:#3498db}
|
||||||
.copyright p{width:100%;color:#919191;text-align:center;font-size:10px}
|
.copyright p{width:100%;color:#919191;text-align:center;font-size:10px}
|
||||||
.system-message .btn-grey{border-color:#bbb;color:#bbb}
|
.system-message .btn-grey{border-color:#bbb;color:#bbb}
|
||||||
.clearfix:after{clear:both;display:block;visibility:hidden;height:0;content:"."}
|
.clearfix:after{clear:both;display:block;visibility:hidden;height:0;content:"."}
|
||||||
@media (max-width:768px){body {padding:20px 0;}}
|
@media (max-width:768px){body {padding:20px 0;}}
|
||||||
@media (max-width:480px){.system-message h1{font-size:30px;}}
|
@media (max-width:480px){.system-message h1{font-size:30px;}}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div class="system-message {$code}">
|
<div class="system-message {$code}">
|
||||||
<div class="image">
|
<div class="image">
|
||||||
<img src="/static/images/{$code}.svg" alt="" width="150" />
|
<img src="/static/images/{$code}.svg" alt="" width="150" />
|
||||||
</div>
|
</div>
|
||||||
<h1>{$msg}</h1>
|
<h1>{$msg}</h1>
|
||||||
{if $url}
|
{if $url}
|
||||||
<p class="jump">
|
<p class="jump">
|
||||||
页面将在 <span id="wait">{$wait}</span> 秒后自动跳转
|
页面将在 <span id="wait">{$wait}</span> 秒后自动跳转
|
||||||
</p>
|
</p>
|
||||||
{/if}
|
{/if}
|
||||||
<p class="clearfix">
|
<p class="clearfix">
|
||||||
<a href="javascript:history.go(-1);" class="btn btn-grey">返回上一页</a>
|
<a href="javascript:history.go(-1);" class="btn btn-grey">返回上一页</a>
|
||||||
{if $url}
|
{if $url}
|
||||||
<a href="{$url}" class="btn btn-primary">立即跳转</a>
|
<a href="{$url}" class="btn btn-primary">立即跳转</a>
|
||||||
{/if}
|
{/if}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
(function () {
|
(function () {
|
||||||
var wait = document.getElementById('wait');
|
var wait = document.getElementById('wait');
|
||||||
var interval = setInterval(function () {
|
var interval = setInterval(function () {
|
||||||
var time = --wait.innerHTML;
|
var time = --wait.innerHTML;
|
||||||
if (time <= 0) {
|
if (time <= 0) {
|
||||||
location.href = "{$url}";
|
location.href = "{$url}";
|
||||||
clearInterval(interval);
|
clearInterval(interval);
|
||||||
}
|
}
|
||||||
}, 1000);
|
}, 1000);
|
||||||
})();
|
})();
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
@ -1,211 +1,306 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<meta name="renderer" content="webkit" />
|
<meta name="renderer" content="webkit" />
|
||||||
<meta name="force-rendering" content="webkit" />
|
<meta name="force-rendering" content="webkit" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no" />
|
||||||
<title>宝塔面板安装脚本</title>
|
<title>宝塔面板安装脚本</title>
|
||||||
<link rel="stylesheet" type="text/css" href="/static/css/sanren.css" />
|
<link rel="stylesheet" type="text/css" href="/static/css/sanren.css" />
|
||||||
<link rel="stylesheet" type="text/css" href="/static/css/style.css" />
|
<link rel="stylesheet" type="text/css" href="/static/css/style.css" />
|
||||||
<link rel="stylesheet" type="text/css" href="/static/css/download.css" />
|
<link rel="stylesheet" type="text/css" href="/static/css/download.css" />
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div class="down-main">
|
<div class="down-main">
|
||||||
<div class="d1">
|
<div class="d1">
|
||||||
<div class="wrap">
|
<div class="wrap">
|
||||||
<div class="i1t textcenter">
|
<div class="i1t textcenter">
|
||||||
<h1 class="disflex flex_center flex_lrcenter textcenter">宝塔面板安装脚本<img class="ml10" src="/static/images/i1ico_03.png"></h1>
|
<h1 class="disflex flex_center flex_lrcenter textcenter">宝塔面板安装脚本<img class="ml10" src="/static/images/i1ico_03.png"></h1>
|
||||||
<div class="text20 mt_25 wap_mt15 textcenter cl8">
|
<div class="text20 mt_25 wap_mt15 textcenter cl8">
|
||||||
<p>2分钟装好面板,一键管理服务器</p>
|
<p>2分钟装好面板,一键管理服务器</p>
|
||||||
<p>集成LAMP/LNMP环境安装,网站、FTP、数据库、文件管理、软件安装等功能</p>
|
<p>集成LAMP/LNMP环境安装,网站、FTP、数据库、文件管理、软件安装等功能</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="disflex flex_lrcenter mt_50 install-list">
|
<div class="disflex flex_lrcenter mt_50 install-list">
|
||||||
<div class="install-box linux">
|
<div class="install-box linux">
|
||||||
<div class="img">
|
<div class="img">
|
||||||
<img src="/static/images/prd_1_03.png">
|
<img src="/static/images/prd_1_03.png">
|
||||||
</div>
|
</div>
|
||||||
<div class="cont">
|
<div class="cont">
|
||||||
<div class="top">
|
<div class="top">
|
||||||
<div class="title">Linux面板 {:config_get('new_version')}</div>
|
<div class="title">Linux面板 {:config_get('new_version')}</div>
|
||||||
<div class="desc">
|
<div class="desc">
|
||||||
支持Centos、Ubuntu、Deepin、Debian、Fedora等Linux系统。
|
支持Centos、Ubuntu、Deepin、Debian、Fedora等Linux系统。
|
||||||
<a class="link" href="https://demo.bt.cn/login" target="_blank" style="margin-left: 5px; font-weight: 700" rel="noreferrer">查看演示</a>
|
<a class="link" href="https://demo.bt.cn/login" target="_blank" style="margin-left: 5px; font-weight: 700" rel="noreferrer">查看演示</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="mark">
|
<div class="mark">
|
||||||
<span>2分钟装好</span>
|
<span>2分钟装好</span>
|
||||||
<span>阿里云推荐</span>
|
<span>阿里云推荐</span>
|
||||||
<span>腾讯云推荐</span>
|
<span>腾讯云推荐</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="bottom">
|
<div class="bottom">
|
||||||
<a class="btn" href="javascript:;" id="goInstallLinux">查看安装脚本</a>
|
<a class="btn" href="javascript:;" id="goInstallLinux">查看安装脚本</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="install-box windows">
|
{if config_get('new_version_win')}<div class="install-box windows">
|
||||||
<div class="img">
|
<div class="img">
|
||||||
<img src="/static/images/prd_2_03.png">
|
<img src="/static/images/prd_2_03.png">
|
||||||
</div>
|
</div>
|
||||||
<div class="cont">
|
<div class="cont">
|
||||||
<div class="top">
|
<div class="top">
|
||||||
<div class="title">Windows面板 {:config_get('new_version_win')}</div>
|
<div class="title">Windows面板 {:config_get('new_version_win')}</div>
|
||||||
<div class="desc">支持Windows Server 2008 R2/2012/2016/2019,64位系统</div>
|
<div class="desc">支持Windows Server 2008 R2/2012/2016/2019/2022,64位系统</div>
|
||||||
<div class="mark">
|
<div class="mark">
|
||||||
<span>操作简单</span>
|
<span>操作简单</span>
|
||||||
<span>使用方便</span>
|
<span>使用方便</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="bottom">
|
<div class="bottom">
|
||||||
<a class="btn" href="javascript:;" id="goInstallWindows">查看安装方法</a>
|
<a class="btn" href="javascript:;" id="goInstallWindows">查看安装方法</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>{/if}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
{if config_get('new_version_btm') || config_get('new_version_en')}<div class="disflex flex_lrcenter mt_30 install-list">
|
||||||
</div>
|
{if config_get('new_version_win')}<div class="install-box monitor">
|
||||||
</div>
|
<div class="img">
|
||||||
<div class="d2" id="instal-linux">
|
<img src="/static/images/bt_monitor.png" style="height: 96px;"/>
|
||||||
<div class="wrap">
|
</div>
|
||||||
<div class="wrap-title linux-title">
|
<div class="cont">
|
||||||
<div class="text">Linux面板{:config_get('new_version')}安装脚本</div>
|
<div class="top">
|
||||||
</div>
|
<div class="title">云安全监控</div>
|
||||||
<div class="desc">
|
<div class="desc">多机跨平台安全管理和监控</div>
|
||||||
使用 SSH 连接工具,如
|
</div>
|
||||||
<a class="link" href="https://www.putty.org/" target="_blank" rel="noreferrer">PUTTY</a>
|
<div class="bottom">
|
||||||
连接到您的 Linux 服务器后,
|
<a class="btn" href="javascript:;" id="goInstallMonitor">查看安装脚本</a>
|
||||||
<a class="link" href="https://www.bt.cn/bbs/thread-50002-1-1.html" target="_blank" rel="noreferrer">挂载磁盘</a>
|
</div>
|
||||||
,根据系统执行相应命令开始安装:
|
</div>
|
||||||
</div>
|
</div>{/if}
|
||||||
<div class="install-code">
|
{if config_get('new_version_en')}<div class="install-box monitor">
|
||||||
<span class="osname">Centos安装脚本</span>
|
<div class="img">
|
||||||
<div class="code-cont">
|
<img src="/static/images/aapanel.png" style="height: 96px;"/>
|
||||||
<div class="command" title="点击复制Centos安装脚本">yum install -y wget && wget -O install.sh {$siteurl}/install/install_6.0.sh && sh install.sh</div>
|
</div>
|
||||||
<span class="ico-copy" title="点击复制Centos安装脚本" data-clipboard-text="yum install -y wget && wget -O install.sh {$siteurl}/install/install_6.0.sh && sh install.sh">复制</span>
|
<div class="cont">
|
||||||
</div>
|
<div class="top">
|
||||||
</div>
|
<div class="title">aaPanel {:config_get('new_version_en')}</div>
|
||||||
<div class="install-code">
|
<div class="desc">宝塔面板国际版</div>
|
||||||
<span class="osname">Ubuntu/Debian安装脚本</span>
|
</div>
|
||||||
<div class="code-cont">
|
<div class="bottom">
|
||||||
<div class="command" title="点击复制Ubuntu/Debian安装脚本">wget -O install.sh {$siteurl}/install/install_6.0.sh && bash install.sh</div>
|
<a class="btn" href="javascript:;" id="goInstallAaPanel">查看安装脚本</a>
|
||||||
<span class="ico-copy" title="点击复制Ubuntu/Debian安装脚本" data-clipboard-text="wget -O install.sh {$siteurl}/install/install_6.0.sh && bash install.sh">复制</span>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>{/if}
|
||||||
<div class="install-code">
|
</div>{/if}
|
||||||
<span class="osname">一键更新脚本</span>
|
</div>
|
||||||
<div class="code-cont">
|
</div>
|
||||||
<div class="command" title="点击复制一键更新脚本">curl {$siteurl}/install/update6.sh|bash</div>
|
</div>
|
||||||
<span class="ico-copy" title="点击复制一键更新脚本" data-clipboard-text="curl {$siteurl}/install/update6.sh|bash">复制</span>
|
<div class="d2" id="instal-linux">
|
||||||
</div>
|
<div class="wrap">
|
||||||
</div>
|
<div class="wrap-title linux-title">
|
||||||
<div class="tips" style="color: orangered; font-weight: 700">
|
<div class="text">Linux面板{:config_get('new_version')}安装脚本</div>
|
||||||
<p>注意:必须为没装过其它环境如Apache/Nginx/php/MySQL的新系统,推荐使用centos 7.X的系统安装宝塔面板</p>
|
</div>
|
||||||
<p style="text-indent: 3em">推荐使用Chrome、火狐、edge浏览器,国产浏览器请使用极速模式访问面板登录地址</p>
|
<div class="desc">
|
||||||
<p style="text-indent: 3em">如果使用过官方版或其他第三方云端的版本,使用一键更新脚本即可切换到此云端</p>
|
使用 SSH 连接工具,如
|
||||||
</div>
|
<a class="link" href="https://www.putty.org/" target="_blank" rel="noreferrer">PUTTY</a>
|
||||||
</div>
|
连接到您的 Linux 服务器后,
|
||||||
</div>
|
<a class="link" href="https://www.bt.cn/bbs/thread-50002-1-1.html" target="_blank" rel="noreferrer">挂载磁盘</a>
|
||||||
<div class="d4" id="instal-windows">
|
,根据系统执行相应命令开始安装:
|
||||||
<div class="wrap">
|
</div>
|
||||||
<div class="wrap-title">
|
<div class="install-code">
|
||||||
<div class="text">Windows面板{:config_get('new_version_win')}安装方法</div>
|
<span class="osname">Centos安装脚本</span>
|
||||||
</div>
|
<div class="code-cont">
|
||||||
<div class="desc">
|
<div class="command" title="点击复制Centos安装脚本">yum install -y wget && wget -O install.sh {$siteurl}/install/install_panel.sh && sh install.sh</div>
|
||||||
<p>1、使用<a class="link" href="https://download.bt.cn/win/panel/BtSoft.zip" target="_blank" rel="noreferrer">官方安装程序</a>进行安装,安装完先不要进入面板。</p>
|
<span class="ico-copy" title="点击复制Centos安装脚本" data-clipboard-text="yum install -y wget && wget -O install.sh {$siteurl}/install/install_panel.sh && sh install.sh">复制</span>
|
||||||
<p>2、在命令提示符(cmd)输入以下一键更新命令,然后重启面板。</p>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="install-code">
|
<div class="install-code">
|
||||||
<div class="code-cont">
|
<span class="osname">Ubuntu/Debian安装脚本</span>
|
||||||
<div class="command" title="点击复制一键更新命令">wget {$siteurl}/win/panel/data/setup.py -O C:/update.py && "C:\Program Files\python\python.exe" C:/update.py update_panel {:config_get('new_version_win')}</div>
|
<div class="code-cont">
|
||||||
<span class="ico-copy" title="点击复制一键更新命令" data-clipboard-text="wget {$siteurl}/win/panel/data/setup.py -O C:/update.py && "C:\Program Files\python\python.exe" C:/update.py update_panel {:config_get('new_version_win')}">复制</span>
|
<div class="command" title="点击复制Ubuntu/Debian安装脚本">wget -O install.sh {$siteurl}/install/install_panel.sh && bash install.sh</div>
|
||||||
</div>
|
<span class="ico-copy" title="点击复制Ubuntu/Debian安装脚本" data-clipboard-text="wget -O install.sh {$siteurl}/install/install_panel.sh && bash install.sh">复制</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="tips" style="color: orangered; font-weight: 700">
|
</div>
|
||||||
<p>注意:仅支持Windows Server 2008 R2/2012/2016/2019,64位系统(中文简体),且未安装其它环境</p>
|
<div class="install-code">
|
||||||
</div>
|
<span class="osname">一键更新脚本</span>
|
||||||
</div>
|
<div class="code-cont">
|
||||||
</div>
|
<div class="command" title="点击复制一键更新脚本">curl {$siteurl}/install/update6.sh|bash</div>
|
||||||
<div class="animate-bg"></div>
|
<span class="ico-copy" title="点击复制一键更新脚本" data-clipboard-text="curl {$siteurl}/install/update6.sh|bash">复制</span>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
<div class="foot">
|
<div class="tips" style="color: orangered; font-weight: 700">
|
||||||
<div class="wrap">
|
<p>注意:必须为没装过其它环境如Apache/Nginx/php/MySQL的新系统,推荐使用centos 7.X的系统安装宝塔面板</p>
|
||||||
<div class="fb textcenter">
|
<p style="text-indent: 3em">推荐使用Chrome、火狐、edge浏览器,国产浏览器请使用极速模式访问面板登录地址</p>
|
||||||
<div class="fb1 textcenter">
|
<p style="text-indent: 3em">如果使用过官方版或其他第三方云端的版本,使用一键更新脚本即可切换到此云端</p>
|
||||||
<a href="http://www.bt.cn/new/agreement_open.html" target="_blank" rel="noreferrer">《开源许可协议》</a>
|
</div>
|
||||||
<i>丨</i>
|
</div>
|
||||||
<a href="http://www.bt.cn/new/agreement_user.html" target="_blank" rel="noreferrer">《用户协议》</a>
|
</div>
|
||||||
<i>丨</i>
|
{if config_get('new_version_win')}
|
||||||
<a href="http://www.bt.cn/new/agreement_privacy.html" target="_blank" rel="noreferrer">《隐私声明》</a>
|
<div class="d4" id="instal-windows" style="background-color: #edf6ef;">
|
||||||
</div>
|
<div class="wrap">
|
||||||
<div class="fb2 mt_15">
|
<div class="wrap-title">
|
||||||
<p>
|
<div class="text">Windows面板{:config_get('new_version_win')}安装方法</div>
|
||||||
Copyright © 2022 宝塔面板安装脚本
|
</div>
|
||||||
</p>
|
<div class="desc">
|
||||||
</div>
|
<p>1、使用<a class="link" href="https://download.bt.cn/win/panel/go/BtSoft.exe" target="_blank" rel="noreferrer">官方安装程序</a>进行安装,安装完先不要进入面板。</p>
|
||||||
</div>
|
<p>2、在命令提示符(cmd)输入以下一键更新命令,然后重启面板。</p>
|
||||||
</div>
|
<p>3、打开面板后,绑定账号时输入任意账号密码即可。</p>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="install-code">
|
||||||
<script src="//cdn.staticfile.org/jquery/3.6.0/jquery.min.js" type="text/javascript" charset="utf-8"></script>
|
<div class="code-cont">
|
||||||
<script src="//cdn.staticfile.org/layer/3.5.1/layer.js" type="text/javascript" charset="utf-8"></script>
|
<div class="command" title="点击复制一键更新命令">wget {$siteurl}/win/install/panel_update.py -O C:/update.py && "C:\Program Files\python\python.exe" C:/update.py {:config_get('new_version_win')}</div>
|
||||||
|
<span class="ico-copy" title="点击复制一键更新命令" data-clipboard-text="wget {$siteurl}/win/install/panel_update.py -O C:/update.py && "C:\Program Files\python\python.exe" C:/update.py {:config_get('new_version_win')}">复制</span>
|
||||||
<script type="text/javascript" src="//cdn.staticfile.org/clipboard.js/1.7.1/clipboard.min.js"></script>
|
</div>
|
||||||
<script type="text/javascript" src="/static/js/dx.js"></script>
|
</div>
|
||||||
<script>
|
<div class="tips" style="color: orangered; font-weight: 700">
|
||||||
$(function () {
|
<p>注意:支持Windows Server 2012/Windows 8及以上系统,且未安装其它环境</p>
|
||||||
var userId = '';
|
</div>
|
||||||
|
</div>
|
||||||
// 复制安装命令
|
</div>{/if}
|
||||||
var clipboard = new Clipboard('.ico-copy', {
|
{if config_get('new_version_btm')}
|
||||||
text: function (element) {
|
<div class="d4" id="instal-monitor">
|
||||||
return $(element).prev().text();
|
<div class="wrap">
|
||||||
},
|
<div class="wrap-title">
|
||||||
});
|
<div class="text" style="margin-right: 12px;">云安全监控{:config_get('new_version_btm')}安装脚本</div>
|
||||||
clipboard
|
</div>
|
||||||
.on('success', function (e) {
|
<div class="desc">
|
||||||
layer.msg(e.trigger.title + '成功', { icon: 1 });
|
使用 SSH 连接工具,如
|
||||||
})
|
<a class="link" href="https://www.putty.org/" target="_blank" rel="noreferrer">PUTTY</a>
|
||||||
.on('error', function (e) {
|
连接到您的 Linux 服务器后,根据系统执行相应命令开始安装:
|
||||||
layer.msg('复制失败,请手动选中文本Ctrl+c复制内容', { icon: 2 });
|
</div>
|
||||||
});
|
<div class="install-code">
|
||||||
|
<span class="osname">云安全监控安装脚本</span>
|
||||||
$('.install-code .command').click(function () {
|
<div class="code-cont">
|
||||||
$(this).next('.ico-copy').click();
|
<div class="command" title="点击复制安装脚本">curl -sS {$siteurl}/install/install_btmonitor.sh -o /tmp/install_btmonitor.sh && bash /tmp/install_btmonitor.sh</div>
|
||||||
});
|
<span class="ico-copy" title="点击复制安装脚本" data-clipboard-text="curl -sS {$siteurl}/install/install_btmonitor.sh -o /tmp/install_btmonitor.sh && bash /tmp/install_btmonitor.sh">复制</span>
|
||||||
|
</div>
|
||||||
$('#goInstallLinux').click(function () {
|
</div>
|
||||||
scrollTop('#instal-linux');
|
<div class="install-code">
|
||||||
});
|
<span class="osname">云安全监控更新脚本</span>
|
||||||
|
<div class="code-cont">
|
||||||
$('#goInstallWindows').click(function () {
|
<div class="command" title="点击复制更新脚本">curl {$siteurl}/install/update_btmonitor.sh|bash</div>
|
||||||
scrollTop('#instal-windows');
|
<span class="ico-copy" title="点击复制更新脚本" data-clipboard-text="curl {$siteurl}/install/update_btmonitor.sh|bash">复制</span>
|
||||||
});
|
</div>
|
||||||
|
</div>
|
||||||
$('#goInstallCloud').click(function () {
|
<div class="tips" style="color: orangered; font-weight: 700">
|
||||||
scrollTop('#instal-cloud');
|
<p>注意:安装完成后推荐使用Chrome、火狐、edge浏览器,国产浏览器(极速模式)访问登录系统</p>
|
||||||
});
|
</div>
|
||||||
|
</div>
|
||||||
function GetRequest() {
|
</div>{/if}
|
||||||
var url = location.search;
|
{if config_get('new_version_en')}
|
||||||
//获取url中"?"符后的字串
|
<div class="d4" id="instal-aapanel" style="background-color: #edf6ef;">
|
||||||
var theRequest = new Object();
|
<div class="wrap">
|
||||||
if (url.indexOf('?') != -1) {
|
<div class="wrap-title">
|
||||||
var str = url.substr(1);
|
<div class="text">aaPanel {:config_get('new_version_en')} install script</div>
|
||||||
}
|
</div>
|
||||||
return str;
|
<div class="desc">
|
||||||
}
|
<p>It is recommended that you use Ubuntu22.04 to install aaPanel</p>
|
||||||
if (GetRequest() == 'bt') {
|
</div>
|
||||||
scrollTop('#instal-linux');
|
<div class="install-code">
|
||||||
}
|
<span class="osname">Instarll script</span>
|
||||||
|
<div class="code-cont">
|
||||||
// 滚动到指定位置
|
<div class="command" title="Copy successfully, please paste it to the server installation">URL={$siteurl}/install/install_7.0_en.sh && if [ -f /usr/bin/curl ];then curl -ksSO $URL ;else wget -O install_7.0_en.sh $URL;fi;bash install_7.0_en.sh</div>
|
||||||
function scrollTop(el) {
|
<span class="ico-copy" title="Copy successfully, please paste it to the server installation" data-clipboard-text="URL={$siteurl}/install/install_7.0_en.sh && if [ -f /usr/bin/curl ];then curl -ksSO $URL ;else wget -O install_7.0_en.sh $URL;fi;bash install_7.0_en.sh">复制</span>
|
||||||
var headHeight = 0;
|
</div>
|
||||||
$('html, body').animate({ scrollTop: $(el).offset().top - headHeight }, { duration: 200, easing: 'swing' });
|
</div>
|
||||||
}
|
<div class="install-code">
|
||||||
});
|
<span class="osname">Upgrade script</span>
|
||||||
</script>
|
<div class="code-cont">
|
||||||
|
<div class="command" title="Copy successfully, please paste it to the server installation">curl {$siteurl}/install/update_7.x_en.sh|bash</div>
|
||||||
</body>
|
<span class="ico-copy" title="Copy successfully, please paste it to the server installation" data-clipboard-text="curl {$siteurl}/install/update_7.x_en.sh|bash">复制</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>{/if}
|
||||||
|
<div class="animate-bg"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="foot">
|
||||||
|
<div class="wrap">
|
||||||
|
<div class="fb textcenter">
|
||||||
|
<div class="fb1 textcenter">
|
||||||
|
<a href="http://www.bt.cn/new/agreement_open.html" target="_blank" rel="noreferrer">《开源许可协议》</a>
|
||||||
|
<i>丨</i>
|
||||||
|
<a href="http://www.bt.cn/new/agreement_user.html" target="_blank" rel="noreferrer">《用户协议》</a>
|
||||||
|
<i>丨</i>
|
||||||
|
<a href="http://www.bt.cn/new/agreement_privacy.html" target="_blank" rel="noreferrer">《隐私声明》</a>
|
||||||
|
</div>
|
||||||
|
<div class="fb2 mt_15">
|
||||||
|
<p>
|
||||||
|
Copyright © {:date('Y')} 宝塔面板安装脚本
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script src="{$cdnpublic}jquery/3.6.0/jquery.min.js" type="text/javascript" charset="utf-8"></script>
|
||||||
|
<script src="{$cdnpublic}layer/3.5.1/layer.js" type="text/javascript" charset="utf-8"></script>
|
||||||
|
|
||||||
|
<script type="text/javascript" src="{$cdnpublic}clipboard.js/1.7.1/clipboard.min.js"></script>
|
||||||
|
<script type="text/javascript" src="/static/js/dx.js"></script>
|
||||||
|
<script>
|
||||||
|
$(function () {
|
||||||
|
var userId = '';
|
||||||
|
|
||||||
|
// 复制安装命令
|
||||||
|
var clipboard = new Clipboard('.ico-copy', {
|
||||||
|
text: function (element) {
|
||||||
|
return $(element).prev().text();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
clipboard
|
||||||
|
.on('success', function (e) {
|
||||||
|
layer.msg(e.trigger.title + '成功', { icon: 1 });
|
||||||
|
})
|
||||||
|
.on('error', function (e) {
|
||||||
|
layer.msg('复制失败,请手动选中文本Ctrl+c复制内容', { icon: 2 });
|
||||||
|
});
|
||||||
|
|
||||||
|
$('.install-code .command').click(function () {
|
||||||
|
$(this).next('.ico-copy').click();
|
||||||
|
});
|
||||||
|
|
||||||
|
$('#goInstallLinux').click(function () {
|
||||||
|
scrollTop('#instal-linux');
|
||||||
|
});
|
||||||
|
|
||||||
|
$('#goInstallWindows').click(function () {
|
||||||
|
scrollTop('#instal-windows');
|
||||||
|
});
|
||||||
|
|
||||||
|
$('#goInstallCloud').click(function () {
|
||||||
|
scrollTop('#instal-cloud');
|
||||||
|
});
|
||||||
|
|
||||||
|
$('#goInstallMonitor').click(function () {
|
||||||
|
scrollTop('#instal-monitor');
|
||||||
|
});
|
||||||
|
|
||||||
|
$('#goInstallAaPanel').click(function () {
|
||||||
|
scrollTop('#instal-aapanel');
|
||||||
|
});
|
||||||
|
|
||||||
|
function GetRequest() {
|
||||||
|
var url = location.search;
|
||||||
|
//获取url中"?"符后的字串
|
||||||
|
var theRequest = new Object();
|
||||||
|
if (url.indexOf('?') != -1) {
|
||||||
|
var str = url.substr(1);
|
||||||
|
}
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
if (GetRequest() == 'bt') {
|
||||||
|
scrollTop('#instal-linux');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 滚动到指定位置
|
||||||
|
function scrollTop(el) {
|
||||||
|
var headHeight = 0;
|
||||||
|
$('html, body').animate({ scrollTop: $(el).offset().top - headHeight }, { duration: 200, easing: 'swing' });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
</body>
|
||||||
</html>
|
</html>
|
||||||
@ -1,268 +1,268 @@
|
|||||||
<!doctype html>
|
<!doctype html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
<title>宝塔第三方云端 - 安装程序</title>
|
<title>宝塔第三方云端 - 安装程序</title>
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no" />
|
||||||
<meta name="renderer" content="webkit">
|
<meta name="renderer" content="webkit">
|
||||||
<style>
|
<style>
|
||||||
body {
|
body {
|
||||||
background: #f1f6fd;
|
background: #f1f6fd;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
line-height: 1.5;
|
line-height: 1.5;
|
||||||
-webkit-font-smoothing: antialiased;
|
-webkit-font-smoothing: antialiased;
|
||||||
-moz-osx-font-smoothing: grayscale;
|
-moz-osx-font-smoothing: grayscale;
|
||||||
}
|
}
|
||||||
|
|
||||||
body, input, button {
|
body, input, button {
|
||||||
font-family: 'Source Sans Pro', 'Helvetica Neue', Helvetica, 'Microsoft Yahei', Arial, sans-serif;
|
font-family: 'Source Sans Pro', 'Helvetica Neue', Helvetica, 'Microsoft Yahei', Arial, sans-serif;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
color: #7E96B3;
|
color: #7E96B3;
|
||||||
}
|
}
|
||||||
|
|
||||||
.container {
|
.container {
|
||||||
max-width: 480px;
|
max-width: 480px;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
a {
|
a {
|
||||||
color: #4e73df;
|
color: #4e73df;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
a:hover {
|
a:hover {
|
||||||
text-decoration: underline;
|
text-decoration: underline;
|
||||||
}
|
}
|
||||||
|
|
||||||
h1 {
|
h1 {
|
||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
h2 {
|
h2 {
|
||||||
font-size: 28px;
|
font-size: 28px;
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
color: #3C5675;
|
color: #3C5675;
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
form {
|
form {
|
||||||
margin-top: 40px;
|
margin-top: 40px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.form-group {
|
.form-group {
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.form-group .form-field:first-child input {
|
.form-group .form-field:first-child input {
|
||||||
border-top-left-radius: 4px;
|
border-top-left-radius: 4px;
|
||||||
border-top-right-radius: 4px;
|
border-top-right-radius: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.form-group .form-field:last-child input {
|
.form-group .form-field:last-child input {
|
||||||
border-bottom-left-radius: 4px;
|
border-bottom-left-radius: 4px;
|
||||||
border-bottom-right-radius: 4px;
|
border-bottom-right-radius: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.form-field input {
|
.form-field input {
|
||||||
background: #fff;
|
background: #fff;
|
||||||
margin: 0 0 2px;
|
margin: 0 0 2px;
|
||||||
border: 2px solid transparent;
|
border: 2px solid transparent;
|
||||||
transition: background 0.2s, border-color 0.2s, color 0.2s;
|
transition: background 0.2s, border-color 0.2s, color 0.2s;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
padding: 15px 15px 15px 180px;
|
padding: 15px 15px 15px 180px;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
.form-field input:focus {
|
.form-field input:focus {
|
||||||
border-color: #4e73df;
|
border-color: #4e73df;
|
||||||
background: #fff;
|
background: #fff;
|
||||||
color: #444;
|
color: #444;
|
||||||
outline: none;
|
outline: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.form-field label {
|
.form-field label {
|
||||||
float: left;
|
float: left;
|
||||||
width: 160px;
|
width: 160px;
|
||||||
text-align: right;
|
text-align: right;
|
||||||
margin-right: -160px;
|
margin-right: -160px;
|
||||||
position: relative;
|
position: relative;
|
||||||
margin-top: 15px;
|
margin-top: 15px;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
opacity: 0.7;
|
opacity: 0.7;
|
||||||
}
|
}
|
||||||
|
|
||||||
button, .btn {
|
button, .btn {
|
||||||
background: #3C5675;
|
background: #3C5675;
|
||||||
color: #fff;
|
color: #fff;
|
||||||
border: 0;
|
border: 0;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
padding: 15px 30px;
|
padding: 15px 30px;
|
||||||
-webkit-appearance: none;
|
-webkit-appearance: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
button[disabled] {
|
button[disabled] {
|
||||||
opacity: 0.5;
|
opacity: 0.5;
|
||||||
}
|
}
|
||||||
|
|
||||||
.form-buttons {
|
.form-buttons {
|
||||||
height: 52px;
|
height: 52px;
|
||||||
line-height: 52px;
|
line-height: 52px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.form-buttons .btn {
|
.form-buttons .btn {
|
||||||
margin-right: 5px;
|
margin-right: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#error, .error, #success, .success, #warmtips, .warmtips {
|
#error, .error, #success, .success, #warmtips, .warmtips {
|
||||||
background: #D83E3E;
|
background: #D83E3E;
|
||||||
color: #fff;
|
color: #fff;
|
||||||
padding: 15px 20px;
|
padding: 15px 20px;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#success {
|
#success {
|
||||||
background: #3C5675;
|
background: #3C5675;
|
||||||
}
|
}
|
||||||
|
|
||||||
#error a, .error a {
|
#error a, .error a {
|
||||||
color: white;
|
color: white;
|
||||||
text-decoration: underline;
|
text-decoration: underline;
|
||||||
}
|
}
|
||||||
|
|
||||||
#warmtips {
|
#warmtips {
|
||||||
background: #fff;
|
background: #fff;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
color: #3C5675;
|
color: #3C5675;
|
||||||
border: 2px solid #4e73df;
|
border: 2px solid #4e73df;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
}
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<h1>
|
<h1>
|
||||||
<svg t="1660545699809" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4887" width="100px" height="100px">
|
<svg t="1660545699809" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4887" width="100px" height="100px">
|
||||||
<path d="M811.4 418.7C765.6 297.9 648.9 212 512.2 212S258.8 297.8 213 418.6C127.3 441.1 64 519.1 64 612c0 110.5 89.5 200 199.9 200h496.2C870.5 812 960 722.5 960 612c0-92.7-63.1-170.7-148.6-193.3z m36.3 281c-23.4 23.4-54.5 36.3-87.6 36.3H263.9c-33.1 0-64.2-12.9-87.6-36.3-23.4-23.4-36.3-54.6-36.3-87.7 0-28 9.1-54.3 26.2-76.3 16.7-21.3 40.2-36.8 66.1-43.7l37.9-9.9 13.9-36.6c8.6-22.8 20.6-44.1 35.7-63.4 14.9-19.2 32.6-35.9 52.4-49.9 41.1-28.9 89.5-44.2 140-44.2s98.9 15.3 140 44.2c19.9 14 37.5 30.8 52.4 49.9 15.1 19.3 27.1 40.7 35.7 63.4l13.8 36.5 37.8 10c54.3 14.5 92.1 63.8 92.1 120 0 33.1-12.9 64.3-36.3 87.7z" p-id="4888" fill="#4e73df"></path>
|
<path d="M811.4 418.7C765.6 297.9 648.9 212 512.2 212S258.8 297.8 213 418.6C127.3 441.1 64 519.1 64 612c0 110.5 89.5 200 199.9 200h496.2C870.5 812 960 722.5 960 612c0-92.7-63.1-170.7-148.6-193.3z m36.3 281c-23.4 23.4-54.5 36.3-87.6 36.3H263.9c-33.1 0-64.2-12.9-87.6-36.3-23.4-23.4-36.3-54.6-36.3-87.7 0-28 9.1-54.3 26.2-76.3 16.7-21.3 40.2-36.8 66.1-43.7l37.9-9.9 13.9-36.6c8.6-22.8 20.6-44.1 35.7-63.4 14.9-19.2 32.6-35.9 52.4-49.9 41.1-28.9 89.5-44.2 140-44.2s98.9 15.3 140 44.2c19.9 14 37.5 30.8 52.4 49.9 15.1 19.3 27.1 40.7 35.7 63.4l13.8 36.5 37.8 10c54.3 14.5 92.1 63.8 92.1 120 0 33.1-12.9 64.3-36.3 87.7z" p-id="4888" fill="#4e73df"></path>
|
||||||
</svg>
|
</svg>
|
||||||
</h1>
|
</h1>
|
||||||
<h2>宝塔第三方云端 - 安装程序</h2>
|
<h2>宝塔第三方云端 - 安装程序</h2>
|
||||||
<div>
|
<div>
|
||||||
|
|
||||||
<form method="post">
|
<form method="post">
|
||||||
<div id="error" style="display:none"></div>
|
<div id="error" style="display:none"></div>
|
||||||
<div id="success" style="display:none"></div>
|
<div id="success" style="display:none"></div>
|
||||||
<div id="warmtips" style="display:none"><p>安装完成后,你还需要进行以下操作:</p><p>1、在后台使用批量替换工具,执行命令一键替换压缩包与安装脚本中的域名。</p><p></p>2、在后台配置面板对接,同步插件列表与插件包。</p></div>
|
<div id="warmtips" style="display:none"><p>安装完成后,你还需要进行以下操作:</p><p>1、在后台使用批量替换工具,执行命令一键替换压缩包与安装脚本中的域名。</p><p></p>2、在后台配置面板对接,同步插件列表与插件包。</p></div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="form-field">
|
<div class="form-field">
|
||||||
<label>MySQL 数据库地址</label>
|
<label>MySQL 数据库地址</label>
|
||||||
<input type="text" name="mysql_host" value="localhost" required="">
|
<input type="text" name="mysql_host" value="localhost" required="">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-field">
|
<div class="form-field">
|
||||||
<label>MySQL 数据库端口</label>
|
<label>MySQL 数据库端口</label>
|
||||||
<input type="number" name="mysql_port" value="3306">
|
<input type="number" name="mysql_port" value="3306">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-field">
|
<div class="form-field">
|
||||||
<label>MySQL 用户名</label>
|
<label>MySQL 用户名</label>
|
||||||
<input type="text" name="mysql_user" value="" required="">
|
<input type="text" name="mysql_user" value="" required="">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-field">
|
<div class="form-field">
|
||||||
<label>MySQL 密码</label>
|
<label>MySQL 密码</label>
|
||||||
<input type="text" name="mysql_pwd" value="" required="">
|
<input type="text" name="mysql_pwd" value="" required="">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-field">
|
<div class="form-field">
|
||||||
<label>MySQL 数据库名</label>
|
<label>MySQL 数据库名</label>
|
||||||
<input type="text" name="mysql_name" value="" required="">
|
<input type="text" name="mysql_name" value="" required="">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-field">
|
<div class="form-field">
|
||||||
<label>MySQL 数据表前缀</label>
|
<label>MySQL 数据表前缀</label>
|
||||||
<input type="text" name="mysql_prefix" value="cloud_">
|
<input type="text" name="mysql_prefix" value="cloud_">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="form-field">
|
<div class="form-field">
|
||||||
<label>管理员用户名</label>
|
<label>管理员用户名</label>
|
||||||
<input type="text" name="admin_username" value="admin" required=""/>
|
<input type="text" name="admin_username" value="admin" required=""/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-field">
|
<div class="form-field">
|
||||||
<label>管理员密码</label>
|
<label>管理员密码</label>
|
||||||
<input type="text" name="admin_password" value="123456" required="">
|
<input type="text" name="admin_password" value="123456" required="">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-buttons">
|
<div class="form-buttons">
|
||||||
<!--@formatter:off-->
|
<!--@formatter:off-->
|
||||||
<button type="submit" >点击安装</button>
|
<button type="submit" >点击安装</button>
|
||||||
<!--@formatter:on-->
|
<!--@formatter:on-->
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<script src="//cdn.staticfile.org/jquery/2.1.4/jquery.min.js"></script>
|
<script src="//lf6-cdn-tos.bytecdntp.com/cdn/expire-1-M/jquery/2.1.4/jquery.min.js"></script>
|
||||||
<script>
|
<script>
|
||||||
$(function () {
|
$(function () {
|
||||||
$('form').on('submit', function (e) {
|
$('form').on('submit', function (e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
var form = this;
|
var form = this;
|
||||||
var $error = $("#error");
|
var $error = $("#error");
|
||||||
var $success = $("#success");
|
var $success = $("#success");
|
||||||
var $button = $(this).find('button')
|
var $button = $(this).find('button')
|
||||||
.text("安装中...")
|
.text("安装中...")
|
||||||
.prop('disabled', true);
|
.prop('disabled', true);
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: "",
|
url: "",
|
||||||
type: "POST",
|
type: "POST",
|
||||||
dataType: "json",
|
dataType: "json",
|
||||||
data: $(this).serialize(),
|
data: $(this).serialize(),
|
||||||
success: function (ret) {
|
success: function (ret) {
|
||||||
if (ret.code == 1) {
|
if (ret.code == 1) {
|
||||||
$error.hide();
|
$error.hide();
|
||||||
$(".form-group", form).remove();
|
$(".form-group", form).remove();
|
||||||
$button.remove();
|
$button.remove();
|
||||||
$("#success").text(ret.msg).show();
|
$("#success").text(ret.msg).show();
|
||||||
$("#warmtips").show();
|
$("#warmtips").show();
|
||||||
|
|
||||||
$buttons = $(".form-buttons", form);
|
$buttons = $(".form-buttons", form);
|
||||||
$('<a class="btn" href="/admin" style="background:#4e73df">进入后台</a>').appendTo($buttons);
|
$('<a class="btn" href="/admin" style="background:#4e73df">进入后台</a>').appendTo($buttons);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
$error.show().text(ret.msg);
|
$error.show().text(ret.msg);
|
||||||
$button.prop('disabled', false).text("点击安装");
|
$button.prop('disabled', false).text("点击安装");
|
||||||
$("html,body").animate({
|
$("html,body").animate({
|
||||||
scrollTop: 0
|
scrollTop: 0
|
||||||
}, 500);
|
}, 500);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
error: function (xhr) {
|
error: function (xhr) {
|
||||||
$error.show().text(xhr.responseText);
|
$error.show().text(xhr.responseText);
|
||||||
$button.prop('disabled', false).text("点击安装");
|
$button.prop('disabled', false).text("点击安装");
|
||||||
$("html,body").animate({
|
$("html,body").animate({
|
||||||
scrollTop: 0
|
scrollTop: 0
|
||||||
}, 500);
|
}, 500);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
@ -7,5 +7,7 @@ return [
|
|||||||
'commands' => [
|
'commands' => [
|
||||||
'updateall' => 'app\command\UpdateAll',
|
'updateall' => 'app\command\UpdateAll',
|
||||||
'decrypt' => 'app\command\DecryptFile',
|
'decrypt' => 'app\command\DecryptFile',
|
||||||
|
'clean' => 'app\command\Clean',
|
||||||
|
'cleanvitejs' => 'app\command\CleanViteJs',
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
|
|||||||
0
data/config/.gitkeep
Normal file
0
data/config/.gitkeep
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
0
data/en/config/.gitkeep
Normal file
0
data/en/config/.gitkeep
Normal file
0
data/en/plugins/folder/.gitkeep
Normal file
0
data/en/plugins/folder/.gitkeep
Normal file
0
data/en/plugins/main/.gitkeep
Normal file
0
data/en/plugins/main/.gitkeep
Normal file
0
data/en/plugins/package/.gitkeep
Normal file
0
data/en/plugins/package/.gitkeep
Normal file
0
data/win/config/.gitkeep
Normal file
0
data/win/config/.gitkeep
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
22
install.sql
22
install.sql
@ -1,7 +1,7 @@
|
|||||||
DROP TABLE IF EXISTS `cloud_config`;
|
DROP TABLE IF EXISTS `cloud_config`;
|
||||||
CREATE TABLE `cloud_config` (
|
CREATE TABLE `cloud_config` (
|
||||||
`key` varchar(32) NOT NULL,
|
`key` varchar(32) NOT NULL,
|
||||||
`value` varchar(255) DEFAULT NULL,
|
`value` varchar(1000) DEFAULT NULL,
|
||||||
PRIMARY KEY (`key`)
|
PRIMARY KEY (`key`)
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||||
|
|
||||||
@ -12,12 +12,18 @@ INSERT INTO `cloud_config` (`key`, `value`) VALUES
|
|||||||
('bt_key', ''),
|
('bt_key', ''),
|
||||||
('whitelist', '0'),
|
('whitelist', '0'),
|
||||||
('download_page', '1'),
|
('download_page', '1'),
|
||||||
('new_version', '7.9.6'),
|
('new_version', '11.5.0'),
|
||||||
('update_msg', '暂无更新日志'),
|
('update_msg', '暂无更新日志'),
|
||||||
('update_date', '2022-11-29'),
|
('update_date', '2026-01-19'),
|
||||||
('new_version_win', '7.7.0'),
|
('new_version_win', '8.5.1'),
|
||||||
('update_msg_win', '暂无更新日志'),
|
('update_msg_win', '暂无更新日志'),
|
||||||
('update_date_win', '2022-09-09'),
|
('update_date_win', '2026-01-19'),
|
||||||
|
('new_version_en', '7.0.25'),
|
||||||
|
('update_msg_en', '暂无更新日志'),
|
||||||
|
('update_date_en', '2025-09-10'),
|
||||||
|
('new_version_btm', '2.3.3'),
|
||||||
|
('update_msg_btm', '暂无更新日志'),
|
||||||
|
('update_date_btm', '2025-08-12'),
|
||||||
('updateall_type', '0'),
|
('updateall_type', '0'),
|
||||||
('syskey', 'UqP94LtI8eWAIgCP');
|
('syskey', 'UqP94LtI8eWAIgCP');
|
||||||
|
|
||||||
@ -25,7 +31,7 @@ INSERT INTO `cloud_config` (`key`, `value`) VALUES
|
|||||||
DROP TABLE IF EXISTS `cloud_black`;
|
DROP TABLE IF EXISTS `cloud_black`;
|
||||||
CREATE TABLE `cloud_black` (
|
CREATE TABLE `cloud_black` (
|
||||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||||
`ip` varchar(20) NOT NULL,
|
`ip` varchar(50) NOT NULL,
|
||||||
`enable` tinyint(1) NOT NULL DEFAULT '1',
|
`enable` tinyint(1) NOT NULL DEFAULT '1',
|
||||||
`addtime` datetime NOT NULL,
|
`addtime` datetime NOT NULL,
|
||||||
PRIMARY KEY (`id`),
|
PRIMARY KEY (`id`),
|
||||||
@ -35,7 +41,7 @@ CREATE TABLE `cloud_black` (
|
|||||||
DROP TABLE IF EXISTS `cloud_white`;
|
DROP TABLE IF EXISTS `cloud_white`;
|
||||||
CREATE TABLE `cloud_white` (
|
CREATE TABLE `cloud_white` (
|
||||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||||
`ip` varchar(20) NOT NULL,
|
`ip` varchar(50) NOT NULL,
|
||||||
`enable` tinyint(1) NOT NULL DEFAULT '1',
|
`enable` tinyint(1) NOT NULL DEFAULT '1',
|
||||||
`addtime` datetime NOT NULL,
|
`addtime` datetime NOT NULL,
|
||||||
PRIMARY KEY (`id`),
|
PRIMARY KEY (`id`),
|
||||||
@ -45,7 +51,7 @@ CREATE TABLE `cloud_white` (
|
|||||||
DROP TABLE IF EXISTS `cloud_record`;
|
DROP TABLE IF EXISTS `cloud_record`;
|
||||||
CREATE TABLE `cloud_record` (
|
CREATE TABLE `cloud_record` (
|
||||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||||
`ip` varchar(20) NOT NULL,
|
`ip` varchar(50) NOT NULL,
|
||||||
`addtime` datetime NOT NULL,
|
`addtime` datetime NOT NULL,
|
||||||
`usetime` datetime NOT NULL,
|
`usetime` datetime NOT NULL,
|
||||||
PRIMARY KEY (`id`),
|
PRIMARY KEY (`id`),
|
||||||
|
|||||||
@ -1,909 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
|
|
||||||
export PATH
|
|
||||||
LANG=en_US.UTF-8
|
|
||||||
|
|
||||||
Btapi_Url='http://www.example.com'
|
|
||||||
Check_Api=$(curl -Ss --connect-timeout 5 -m 2 $Btapi_Url/api/SetupCount)
|
|
||||||
if [ "$Check_Api" != 'ok' ];then
|
|
||||||
Red_Error "此宝塔第三方云端无法连接,因此安装过程已中止!";
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ $(whoami) != "root" ];then
|
|
||||||
echo "请使用root权限执行宝塔安装命令!"
|
|
||||||
exit 1;
|
|
||||||
fi
|
|
||||||
|
|
||||||
is64bit=$(getconf LONG_BIT)
|
|
||||||
if [ "${is64bit}" != '64' ];then
|
|
||||||
Red_Error "抱歉, 当前面板版本不支持32位系统, 请使用64位系统或安装宝塔5.9!";
|
|
||||||
fi
|
|
||||||
|
|
||||||
Centos6Check=$(cat /etc/redhat-release | grep ' 6.' | grep -iE 'centos|Red Hat')
|
|
||||||
if [ "${Centos6Check}" ];then
|
|
||||||
echo "Centos6不支持安装宝塔面板,请更换Centos7/8安装宝塔面板"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
UbuntuCheck=$(cat /etc/issue|grep Ubuntu|awk '{print $2}'|cut -f 1 -d '.')
|
|
||||||
if [ "${UbuntuCheck}" ] && [ "${UbuntuCheck}" -lt "16" ];then
|
|
||||||
echo "Ubuntu ${UbuntuCheck}不支持安装宝塔面板,建议更换Ubuntu18/20安装宝塔面板"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
cd ~
|
|
||||||
setup_path="/www"
|
|
||||||
python_bin=$setup_path/server/panel/pyenv/bin/python
|
|
||||||
cpu_cpunt=$(cat /proc/cpuinfo|grep processor|wc -l)
|
|
||||||
|
|
||||||
if [ "$1" ];then
|
|
||||||
IDC_CODE=$1
|
|
||||||
fi
|
|
||||||
|
|
||||||
GetSysInfo(){
|
|
||||||
if [ -s "/etc/redhat-release" ];then
|
|
||||||
SYS_VERSION=$(cat /etc/redhat-release)
|
|
||||||
elif [ -s "/etc/issue" ]; then
|
|
||||||
SYS_VERSION=$(cat /etc/issue)
|
|
||||||
fi
|
|
||||||
SYS_INFO=$(uname -a)
|
|
||||||
SYS_BIT=$(getconf LONG_BIT)
|
|
||||||
MEM_TOTAL=$(free -m|grep Mem|awk '{print $2}')
|
|
||||||
CPU_INFO=$(getconf _NPROCESSORS_ONLN)
|
|
||||||
|
|
||||||
echo -e ${SYS_VERSION}
|
|
||||||
echo -e Bit:${SYS_BIT} Mem:${MEM_TOTAL}M Core:${CPU_INFO}
|
|
||||||
echo -e ${SYS_INFO}
|
|
||||||
|
|
||||||
if [ -z "${os_version}" ];then
|
|
||||||
echo -e "============================================"
|
|
||||||
echo -e "检测到为非常用系统安装,建议更换至Centos-7或Debian-10+或Ubuntu-20+系统安装宝塔面板"
|
|
||||||
echo -e "详情请查看系统兼容表:https://docs.qq.com/sheet/DUm54VUtyTVNlc21H?tab=BB08J2"
|
|
||||||
echo -e "特殊情况可通过以下联系方式寻求安装协助情况"
|
|
||||||
fi
|
|
||||||
|
|
||||||
is64bit=$(getconf LONG_BIT)
|
|
||||||
if [ "${is64bit}" == '32' ];then
|
|
||||||
echo -e "宝塔面板不支持32位系统进行安装,请使用64位系统/服务器架构进行安装宝塔"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
S390X_CHECK=$(uname -a|grep s390x)
|
|
||||||
if [ "${S390X_CHECK}" ];then
|
|
||||||
echo -e "宝塔面板不支持s390x架构进行安装,请使用64位系统/服务器架构进行安装宝塔"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo -e "============================================"
|
|
||||||
echo -e "请截图以上报错信息发帖至论坛www.bt.cn/bbs求助"
|
|
||||||
}
|
|
||||||
Red_Error(){
|
|
||||||
echo '=================================================';
|
|
||||||
printf '\033[1;31;40m%b\033[0m\n' "$@";
|
|
||||||
GetSysInfo
|
|
||||||
exit 1;
|
|
||||||
}
|
|
||||||
Lock_Clear(){
|
|
||||||
if [ -f "/etc/bt_crack.pl" ];then
|
|
||||||
chattr -R -ia /www
|
|
||||||
chattr -ia /etc/init.d/bt
|
|
||||||
\cp -rpa /www/backup/panel/vhost/* /www/server/panel/vhost/
|
|
||||||
mv /www/server/panel/BTPanel/__init__.bak /www/server/panel/BTPanel/__init__.py
|
|
||||||
rm -f /etc/bt_crack.pl
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
Install_Check(){
|
|
||||||
if [ "${INSTALL_FORCE}" ];then
|
|
||||||
return
|
|
||||||
fi
|
|
||||||
echo -e "----------------------------------------------------"
|
|
||||||
echo -e "检查已有其他Web/mysql环境,安装宝塔可能影响现有站点及数据"
|
|
||||||
echo -e "Web/mysql service is alreday installed,Can't install panel"
|
|
||||||
echo -e "----------------------------------------------------"
|
|
||||||
echo -e "已知风险/Enter yes to force installation"
|
|
||||||
read -p "输入yes强制安装: " yes;
|
|
||||||
if [ "$yes" != "yes" ];then
|
|
||||||
echo -e "------------"
|
|
||||||
echo "取消安装"
|
|
||||||
exit;
|
|
||||||
fi
|
|
||||||
INSTALL_FORCE="true"
|
|
||||||
}
|
|
||||||
System_Check(){
|
|
||||||
MYSQLD_CHECK=$(ps -ef |grep mysqld|grep -v grep|grep -v /www/server/mysql)
|
|
||||||
PHP_CHECK=$(ps -ef|grep php-fpm|grep master|grep -v /www/server/php)
|
|
||||||
NGINX_CHECK=$(ps -ef|grep nginx|grep master|grep -v /www/server/nginx)
|
|
||||||
HTTPD_CHECK=$(ps -ef |grep -E 'httpd|apache'|grep -v /www/server/apache|grep -v grep)
|
|
||||||
if [ "${PHP_CHECK}" ] || [ "${MYSQLD_CHECK}" ] || [ "${NGINX_CHECK}" ] || [ "${HTTPD_CHECK}" ];then
|
|
||||||
Install_Check
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
Get_Pack_Manager(){
|
|
||||||
if [ -f "/usr/bin/yum" ] && [ -d "/etc/yum.repos.d" ]; then
|
|
||||||
PM="yum"
|
|
||||||
elif [ -f "/usr/bin/apt-get" ] && [ -f "/usr/bin/dpkg" ]; then
|
|
||||||
PM="apt-get"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
Auto_Swap()
|
|
||||||
{
|
|
||||||
swap=$(free |grep Swap|awk '{print $2}')
|
|
||||||
if [ "${swap}" -gt 1 ];then
|
|
||||||
echo "Swap total sizse: $swap";
|
|
||||||
return;
|
|
||||||
fi
|
|
||||||
if [ ! -d /www ];then
|
|
||||||
mkdir /www
|
|
||||||
fi
|
|
||||||
swapFile="/www/swap"
|
|
||||||
dd if=/dev/zero of=$swapFile bs=1M count=1025
|
|
||||||
mkswap -f $swapFile
|
|
||||||
swapon $swapFile
|
|
||||||
echo "$swapFile swap swap defaults 0 0" >> /etc/fstab
|
|
||||||
swap=`free |grep Swap|awk '{print $2}'`
|
|
||||||
if [ $swap -gt 1 ];then
|
|
||||||
echo "Swap total sizse: $swap";
|
|
||||||
return;
|
|
||||||
fi
|
|
||||||
|
|
||||||
sed -i "/\/www\/swap/d" /etc/fstab
|
|
||||||
rm -f $swapFile
|
|
||||||
}
|
|
||||||
Service_Add(){
|
|
||||||
if [ "${PM}" == "yum" ] || [ "${PM}" == "dnf" ]; then
|
|
||||||
chkconfig --add bt
|
|
||||||
chkconfig --level 2345 bt on
|
|
||||||
Centos9Check=$(cat /etc/redhat-release |grep ' 9')
|
|
||||||
if [ "${Centos9Check}" ];then
|
|
||||||
wget -O /usr/lib/systemd/system/btpanel.service ${download_Url}/init/systemd/btpanel.service
|
|
||||||
systemctl enable btpanel
|
|
||||||
fi
|
|
||||||
elif [ "${PM}" == "apt-get" ]; then
|
|
||||||
update-rc.d bt defaults
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
Set_Centos_Repo(){
|
|
||||||
HUAWEI_CHECK=$(cat /etc/motd |grep "Huawei Cloud")
|
|
||||||
if [ "${HUAWEI_CHECK}" ] && [ "${is64bit}" == "64" ];then
|
|
||||||
\cp -rpa /etc/yum.repos.d/ /etc/yumBak
|
|
||||||
sed -i 's/mirrorlist/#mirrorlist/g' /etc/yum.repos.d/CentOS-*.repo
|
|
||||||
sed -i 's|#baseurl=http://mirror.centos.org|baseurl=http://vault.epel.cloud|g' /etc/yum.repos.d/CentOS-*.repo
|
|
||||||
rm -f /etc/yum.repos.d/epel.repo
|
|
||||||
rm -f /etc/yum.repos.d/epel-*
|
|
||||||
fi
|
|
||||||
ALIYUN_CHECK=$(cat /etc/motd|grep "Alibaba Cloud ")
|
|
||||||
if [ "${ALIYUN_CHECK}" ] && [ "${is64bit}" == "64" ] && [ ! -f "/etc/yum.repos.d/Centos-vault-8.5.2111.repo" ];then
|
|
||||||
rename '.repo' '.repo.bak' /etc/yum.repos.d/*.repo
|
|
||||||
wget https://mirrors.aliyun.com/repo/Centos-vault-8.5.2111.repo -O /etc/yum.repos.d/Centos-vault-8.5.2111.repo
|
|
||||||
wget https://mirrors.aliyun.com/repo/epel-archive-8.repo -O /etc/yum.repos.d/epel-archive-8.repo
|
|
||||||
sed -i 's/mirrors.cloud.aliyuncs.com/url_tmp/g' /etc/yum.repos.d/Centos-vault-8.5.2111.repo && sed -i 's/mirrors.aliyun.com/mirrors.cloud.aliyuncs.com/g' /etc/yum.repos.d/Centos-vault-8.5.2111.repo && sed -i 's/url_tmp/mirrors.aliyun.com/g' /etc/yum.repos.d/Centos-vault-8.5.2111.repo
|
|
||||||
sed -i 's/mirrors.aliyun.com/mirrors.cloud.aliyuncs.com/g' /etc/yum.repos.d/epel-archive-8.repo
|
|
||||||
fi
|
|
||||||
MIRROR_CHECK=$(cat /etc/yum.repos.d/CentOS-Linux-AppStream.repo |grep "[^#]mirror.centos.org")
|
|
||||||
if [ "${MIRROR_CHECK}" ] && [ "${is64bit}" == "64" ];then
|
|
||||||
\cp -rpa /etc/yum.repos.d/ /etc/yumBak
|
|
||||||
sed -i 's/mirrorlist/#mirrorlist/g' /etc/yum.repos.d/CentOS-*.repo
|
|
||||||
sed -i 's|#baseurl=http://mirror.centos.org|baseurl=http://vault.epel.cloud|g' /etc/yum.repos.d/CentOS-*.repo
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
get_node_url(){
|
|
||||||
if [ ! -f /bin/curl ];then
|
|
||||||
if [ "${PM}" = "yum" ]; then
|
|
||||||
yum install curl -y
|
|
||||||
elif [ "${PM}" = "apt-get" ]; then
|
|
||||||
apt-get install curl -y
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -f "/www/node.pl" ];then
|
|
||||||
download_Url=$(cat /www/node.pl)
|
|
||||||
echo "Download node: $download_Url";
|
|
||||||
echo '---------------------------------------------';
|
|
||||||
return
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo '---------------------------------------------';
|
|
||||||
echo "Selected download node...";
|
|
||||||
nodes=(http://dg2.bt.cn http://dg1.bt.cn http://download.bt.cn http://125.90.93.52:5880 http://36.133.1.8:5880 http://123.129.198.197 http://103.179.243.14:5880 http://128.1.164.196);
|
|
||||||
|
|
||||||
if [ "$1" ];then
|
|
||||||
nodes=($(echo ${nodes[*]}|sed "s#${1}##"))
|
|
||||||
fi
|
|
||||||
|
|
||||||
tmp_file1=/dev/shm/net_test1.pl
|
|
||||||
tmp_file2=/dev/shm/net_test2.pl
|
|
||||||
[ -f "${tmp_file1}" ] && rm -f ${tmp_file1}
|
|
||||||
[ -f "${tmp_file2}" ] && rm -f ${tmp_file2}
|
|
||||||
touch $tmp_file1
|
|
||||||
touch $tmp_file2
|
|
||||||
for node in ${nodes[@]};
|
|
||||||
do
|
|
||||||
NODE_CHECK=$(curl --connect-timeout 3 -m 3 2>/dev/null -w "%{http_code} %{time_total}" ${node}/net_test|xargs)
|
|
||||||
RES=$(echo ${NODE_CHECK}|awk '{print $1}')
|
|
||||||
NODE_STATUS=$(echo ${NODE_CHECK}|awk '{print $2}')
|
|
||||||
TIME_TOTAL=$(echo ${NODE_CHECK}|awk '{print $3 * 1000 - 500 }'|cut -d '.' -f 1)
|
|
||||||
if [ "${NODE_STATUS}" == "200" ];then
|
|
||||||
if [ $TIME_TOTAL -lt 100 ];then
|
|
||||||
if [ $RES -ge 1500 ];then
|
|
||||||
echo "$RES $node" >> $tmp_file1
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
if [ $RES -ge 1500 ];then
|
|
||||||
echo "$TIME_TOTAL $node" >> $tmp_file2
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
i=$(($i+1))
|
|
||||||
if [ $TIME_TOTAL -lt 100 ];then
|
|
||||||
if [ $RES -ge 3000 ];then
|
|
||||||
break;
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
NODE_URL=$(cat $tmp_file1|sort -r -g -t " " -k 1|head -n 1|awk '{print $2}')
|
|
||||||
if [ -z "$NODE_URL" ];then
|
|
||||||
NODE_URL=$(cat $tmp_file2|sort -g -t " " -k 1|head -n 1|awk '{print $2}')
|
|
||||||
if [ -z "$NODE_URL" ];then
|
|
||||||
NODE_URL='http://download.bt.cn';
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
rm -f $tmp_file1
|
|
||||||
rm -f $tmp_file2
|
|
||||||
download_Url=$NODE_URL
|
|
||||||
echo "Download node: $download_Url";
|
|
||||||
echo '---------------------------------------------';
|
|
||||||
}
|
|
||||||
Remove_Package(){
|
|
||||||
local PackageNmae=$1
|
|
||||||
if [ "${PM}" == "yum" ];then
|
|
||||||
isPackage=$(rpm -q ${PackageNmae}|grep "not installed")
|
|
||||||
if [ -z "${isPackage}" ];then
|
|
||||||
yum remove ${PackageNmae} -y
|
|
||||||
fi
|
|
||||||
elif [ "${PM}" == "apt-get" ];then
|
|
||||||
isPackage=$(dpkg -l|grep ${PackageNmae})
|
|
||||||
if [ "${PackageNmae}" ];then
|
|
||||||
apt-get remove ${PackageNmae} -y
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
Install_RPM_Pack(){
|
|
||||||
yumPath=/etc/yum.conf
|
|
||||||
Centos8Check=$(cat /etc/redhat-release | grep ' 8.' | grep -iE 'centos|Red Hat')
|
|
||||||
if [ "${Centos8Check}" ];then
|
|
||||||
Set_Centos_Repo
|
|
||||||
fi
|
|
||||||
isExc=$(cat $yumPath|grep httpd)
|
|
||||||
if [ "$isExc" = "" ];then
|
|
||||||
echo "exclude=httpd nginx php mysql mairadb python-psutil python2-psutil" >> $yumPath
|
|
||||||
fi
|
|
||||||
|
|
||||||
#SYS_TYPE=$(uname -a|grep x86_64)
|
|
||||||
#yumBaseUrl=$(cat /etc/yum.repos.d/CentOS-Base.repo|grep baseurl=http|cut -d '=' -f 2|cut -d '$' -f 1|head -n 1)
|
|
||||||
#[ "${yumBaseUrl}" ] && checkYumRepo=$(curl --connect-timeout 5 --head -s -o /dev/null -w %{http_code} ${yumBaseUrl})
|
|
||||||
#if [ "${checkYumRepo}" != "200" ] && [ "${SYS_TYPE}" ];then
|
|
||||||
# curl -Ss --connect-timeout 3 -m 60 http://download.bt.cn/install/yumRepo_select.sh|bash
|
|
||||||
#fi
|
|
||||||
|
|
||||||
#尝试同步时间(从bt.cn)
|
|
||||||
echo 'Synchronizing system time...'
|
|
||||||
getBtTime=$(curl -sS --connect-timeout 3 -m 60 http://www.bt.cn/api/index/get_time)
|
|
||||||
if [ "${getBtTime}" ];then
|
|
||||||
date -s "$(date -d @$getBtTime +"%Y-%m-%d %H:%M:%S")"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -z "${Centos8Check}" ]; then
|
|
||||||
yum install ntp -y
|
|
||||||
rm -rf /etc/localtime
|
|
||||||
ln -s /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
|
|
||||||
|
|
||||||
#尝试同步国际时间(从ntp服务器)
|
|
||||||
ntpdate 0.asia.pool.ntp.org
|
|
||||||
setenforce 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
startTime=`date +%s`
|
|
||||||
|
|
||||||
sed -i 's/SELINUX=enforcing/SELINUX=disabled/' /etc/selinux/config
|
|
||||||
#yum remove -y python-requests python3-requests python-greenlet python3-greenlet
|
|
||||||
yumPacks="libcurl-devel wget tar gcc make zip unzip openssl openssl-devel gcc libxml2 libxml2-devel libxslt* zlib zlib-devel libjpeg-devel libpng-devel libwebp libwebp-devel freetype freetype-devel lsof pcre pcre-devel vixie-cron crontabs icu libicu-devel c-ares libffi-devel bzip2-devel ncurses-devel sqlite-devel readline-devel tk-devel gdbm-devel db4-devel libpcap-devel xz-devel qrencode"
|
|
||||||
yum install -y ${yumPacks}
|
|
||||||
|
|
||||||
for yumPack in ${yumPacks}
|
|
||||||
do
|
|
||||||
rpmPack=$(rpm -q ${yumPack})
|
|
||||||
packCheck=$(echo ${rpmPack}|grep not)
|
|
||||||
if [ "${packCheck}" ]; then
|
|
||||||
yum install ${yumPack} -y
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
if [ -f "/usr/bin/dnf" ]; then
|
|
||||||
dnf install -y redhat-rpm-config
|
|
||||||
fi
|
|
||||||
|
|
||||||
ALI_OS=$(cat /etc/redhat-release |grep "Alibaba Cloud Linux release 3")
|
|
||||||
if [ -z "${ALI_OS}" ];then
|
|
||||||
yum install epel-release -y
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
Install_Deb_Pack(){
|
|
||||||
ln -sf bash /bin/sh
|
|
||||||
UBUNTU_22=$(cat /etc/issue|grep "Ubuntu 22")
|
|
||||||
if [ "${UBUNTU_22}" ];then
|
|
||||||
apt-get remove needrestart -y
|
|
||||||
fi
|
|
||||||
ALIYUN_CHECK=$(cat /etc/motd|grep "Alibaba Cloud ")
|
|
||||||
if [ "${ALIYUN_CHECK}" ] && [ "${UBUNTU_22}" ];then
|
|
||||||
apt-get remove libicu70 -y
|
|
||||||
fi
|
|
||||||
apt-get update -y
|
|
||||||
apt-get install bash -y
|
|
||||||
if [ -f "/usr/bin/bash" ];then
|
|
||||||
ln -sf /usr/bin/bash /bin/sh
|
|
||||||
fi
|
|
||||||
apt-get install ruby -y
|
|
||||||
apt-get install lsb-release -y
|
|
||||||
#apt-get install ntp ntpdate -y
|
|
||||||
#/etc/init.d/ntp stop
|
|
||||||
#update-rc.d ntp remove
|
|
||||||
#cat >>~/.profile<<EOF
|
|
||||||
#TZ='Asia/Shanghai'; export TZ
|
|
||||||
#EOF
|
|
||||||
#rm -rf /etc/localtime
|
|
||||||
#cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
|
|
||||||
#echo 'Synchronizing system time...'
|
|
||||||
#ntpdate 0.asia.pool.ntp.org
|
|
||||||
#apt-get upgrade -y
|
|
||||||
LIBCURL_VER=$(dpkg -l|grep libcurl4|awk '{print $3}')
|
|
||||||
if [ "${LIBCURL_VER}" == "7.68.0-1ubuntu2.8" ];then
|
|
||||||
apt-get remove libcurl4 -y
|
|
||||||
apt-get install curl -y
|
|
||||||
fi
|
|
||||||
|
|
||||||
debPacks="wget curl libcurl4-openssl-dev gcc make zip unzip tar openssl libssl-dev gcc libxml2 libxml2-dev zlib1g zlib1g-dev libjpeg-dev libpng-dev lsof libpcre3 libpcre3-dev cron net-tools swig build-essential libffi-dev libbz2-dev libncurses-dev libsqlite3-dev libreadline-dev tk-dev libgdbm-dev libdb-dev libdb++-dev libpcap-dev xz-utils git qrencode";
|
|
||||||
apt-get install -y $debPacks --force-yes
|
|
||||||
|
|
||||||
for debPack in ${debPacks}
|
|
||||||
do
|
|
||||||
packCheck=$(dpkg -l|grep ${debPack})
|
|
||||||
if [ "$?" -ne "0" ] ;then
|
|
||||||
apt-get install -y $debPack
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
if [ ! -d '/etc/letsencrypt' ];then
|
|
||||||
mkdir -p /etc/letsencryp
|
|
||||||
mkdir -p /var/spool/cron
|
|
||||||
if [ ! -f '/var/spool/cron/crontabs/root' ];then
|
|
||||||
echo '' > /var/spool/cron/crontabs/root
|
|
||||||
chmod 600 /var/spool/cron/crontabs/root
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
Get_Versions(){
|
|
||||||
redhat_version_file="/etc/redhat-release"
|
|
||||||
deb_version_file="/etc/issue"
|
|
||||||
if [ -f $redhat_version_file ];then
|
|
||||||
os_type='el'
|
|
||||||
is_aliyunos=$(cat $redhat_version_file|grep Aliyun)
|
|
||||||
if [ "$is_aliyunos" != "" ];then
|
|
||||||
return
|
|
||||||
fi
|
|
||||||
os_version=$(cat $redhat_version_file|grep CentOS|grep -Eo '([0-9]+\.)+[0-9]+'|grep -Eo '^[0-9]')
|
|
||||||
if [ "${os_version}" = "5" ];then
|
|
||||||
os_version=""
|
|
||||||
fi
|
|
||||||
if [ -z "${os_version}" ];then
|
|
||||||
os_version=$(cat /etc/redhat-release |grep Stream|grep -oE 8)
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
os_type='ubuntu'
|
|
||||||
os_version=$(cat $deb_version_file|grep Ubuntu|grep -Eo '([0-9]+\.)+[0-9]+'|grep -Eo '^[0-9]+')
|
|
||||||
if [ "${os_version}" = "" ];then
|
|
||||||
os_type='debian'
|
|
||||||
os_version=$(cat $deb_version_file|grep Debian|grep -Eo '([0-9]+\.)+[0-9]+'|grep -Eo '[0-9]+')
|
|
||||||
if [ "${os_version}" = "" ];then
|
|
||||||
os_version=$(cat $deb_version_file|grep Debian|grep -Eo '[0-9]+')
|
|
||||||
fi
|
|
||||||
if [ "${os_version}" = "8" ];then
|
|
||||||
os_version=""
|
|
||||||
fi
|
|
||||||
if [ "${is64bit}" = '32' ];then
|
|
||||||
os_version=""
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
if [ "$os_version" = "14" ];then
|
|
||||||
os_version=""
|
|
||||||
fi
|
|
||||||
if [ "$os_version" = "12" ];then
|
|
||||||
os_version=""
|
|
||||||
fi
|
|
||||||
if [ "$os_version" = "19" ];then
|
|
||||||
os_version=""
|
|
||||||
fi
|
|
||||||
if [ "$os_version" = "21" ];then
|
|
||||||
os_version=""
|
|
||||||
fi
|
|
||||||
if [ "$os_version" = "20" ];then
|
|
||||||
os_version2004=$(cat /etc/issue|grep 20.04)
|
|
||||||
if [ -z "${os_version2004}" ];then
|
|
||||||
os_version=""
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
Install_Python_Lib(){
|
|
||||||
curl -Ss --connect-timeout 3 -m 60 $download_Url/install/pip_select.sh|bash
|
|
||||||
pyenv_path="/www/server/panel"
|
|
||||||
if [ -f $pyenv_path/pyenv/bin/python ];then
|
|
||||||
is_ssl=$($python_bin -c "import ssl" 2>&1|grep cannot)
|
|
||||||
$pyenv_path/pyenv/bin/python3.7 -V
|
|
||||||
if [ $? -eq 0 ] && [ -z "${is_ssl}" ];then
|
|
||||||
chmod -R 700 $pyenv_path/pyenv/bin
|
|
||||||
is_package=$($python_bin -m psutil 2>&1|grep package)
|
|
||||||
if [ "$is_package" = "" ];then
|
|
||||||
wget -O $pyenv_path/pyenv/pip.txt $download_Url/install/pyenv/pip.txt -T 5
|
|
||||||
$pyenv_path/pyenv/bin/pip install -U pip
|
|
||||||
$pyenv_path/pyenv/bin/pip install -U setuptools==65.5.0
|
|
||||||
$pyenv_path/pyenv/bin/pip install -r $pyenv_path/pyenv/pip.txt
|
|
||||||
fi
|
|
||||||
source $pyenv_path/pyenv/bin/activate
|
|
||||||
chmod -R 700 $pyenv_path/pyenv/bin
|
|
||||||
return
|
|
||||||
else
|
|
||||||
rm -rf $pyenv_path/pyenv
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
is_loongarch64=$(uname -a|grep loongarch64)
|
|
||||||
if [ "$is_loongarch64" != "" ] && [ -f "/usr/bin/yum" ];then
|
|
||||||
yumPacks="python3-devel python3-pip python3-psutil python3-gevent python3-pyOpenSSL python3-paramiko python3-flask python3-rsa python3-requests python3-six python3-websocket-client"
|
|
||||||
yum install -y ${yumPacks}
|
|
||||||
for yumPack in ${yumPacks}
|
|
||||||
do
|
|
||||||
rpmPack=$(rpm -q ${yumPack})
|
|
||||||
packCheck=$(echo ${rpmPack}|grep not)
|
|
||||||
if [ "${packCheck}" ]; then
|
|
||||||
yum install ${yumPack} -y
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
pip3 install -U pip
|
|
||||||
pip3 install Pillow psutil pyinotify pycryptodome upyun oss2 pymysql qrcode qiniu redis pymongo Cython configparser cos-python-sdk-v5 supervisor gevent-websocket pyopenssl
|
|
||||||
pip3 install flask==1.1.4
|
|
||||||
pip3 install Pillow -U
|
|
||||||
|
|
||||||
pyenv_bin=/www/server/panel/pyenv/bin
|
|
||||||
mkdir -p $pyenv_bin
|
|
||||||
ln -sf /usr/local/bin/pip3 $pyenv_bin/pip
|
|
||||||
ln -sf /usr/local/bin/pip3 $pyenv_bin/pip3
|
|
||||||
ln -sf /usr/local/bin/pip3 $pyenv_bin/pip3.7
|
|
||||||
|
|
||||||
if [ -f "/usr/bin/python3.7" ];then
|
|
||||||
ln -sf /usr/bin/python3.7 $pyenv_bin/python
|
|
||||||
ln -sf /usr/bin/python3.7 $pyenv_bin/python3
|
|
||||||
ln -sf /usr/bin/python3.7 $pyenv_bin/python3.7
|
|
||||||
elif [ -f "/usr/bin/python3.6" ]; then
|
|
||||||
ln -sf /usr/bin/python3.6 $pyenv_bin/python
|
|
||||||
ln -sf /usr/bin/python3.6 $pyenv_bin/python3
|
|
||||||
ln -sf /usr/bin/python3.6 $pyenv_bin/python3.7
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo > $pyenv_bin/activate
|
|
||||||
|
|
||||||
return
|
|
||||||
fi
|
|
||||||
|
|
||||||
py_version="3.7.8"
|
|
||||||
mkdir -p $pyenv_path
|
|
||||||
echo "True" > /www/disk.pl
|
|
||||||
if [ ! -w /www/disk.pl ];then
|
|
||||||
Red_Error "ERROR: Install python env fielded." "ERROR: /www目录无法写入,请检查目录/用户/磁盘权限!"
|
|
||||||
fi
|
|
||||||
os_type='el'
|
|
||||||
os_version='7'
|
|
||||||
is_export_openssl=0
|
|
||||||
Get_Versions
|
|
||||||
|
|
||||||
echo "OS: $os_type - $os_version"
|
|
||||||
is_aarch64=$(uname -a|grep aarch64)
|
|
||||||
if [ "$is_aarch64" != "" ];then
|
|
||||||
is64bit="aarch64"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -f "/www/server/panel/pymake.pl" ];then
|
|
||||||
os_version=""
|
|
||||||
rm -f /www/server/panel/pymake.pl
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ "${os_version}" != "" ];then
|
|
||||||
pyenv_file="/www/pyenv.tar.gz"
|
|
||||||
wget -O $pyenv_file $download_Url/install/pyenv/pyenv-${os_type}${os_version}-x${is64bit}.tar.gz -T 10
|
|
||||||
if [ "$?" != "0" ];then
|
|
||||||
get_node_url $download_Url
|
|
||||||
wget -O $pyenv_file $download_Url/install/pyenv/pyenv-${os_type}${os_version}-x${is64bit}.tar.gz -T 10
|
|
||||||
fi
|
|
||||||
tmp_size=$(du -b $pyenv_file|awk '{print $1}')
|
|
||||||
if [ $tmp_size -lt 703460 ];then
|
|
||||||
rm -f $pyenv_file
|
|
||||||
echo "ERROR: Download python env fielded."
|
|
||||||
else
|
|
||||||
echo "Install python env..."
|
|
||||||
tar zxvf $pyenv_file -C $pyenv_path/ > /dev/null
|
|
||||||
chmod -R 700 $pyenv_path/pyenv/bin
|
|
||||||
if [ ! -f $pyenv_path/pyenv/bin/python ];then
|
|
||||||
rm -f $pyenv_file
|
|
||||||
Red_Error "ERROR: Install python env fielded." "ERROR: 下载宝塔运行环境失败,请尝试重新安装!"
|
|
||||||
fi
|
|
||||||
$pyenv_path/pyenv/bin/python3.7 -V
|
|
||||||
if [ $? -eq 0 ];then
|
|
||||||
rm -f $pyenv_file
|
|
||||||
ln -sf $pyenv_path/pyenv/bin/pip3.7 /usr/bin/btpip
|
|
||||||
ln -sf $pyenv_path/pyenv/bin/python3.7 /usr/bin/btpython
|
|
||||||
source $pyenv_path/pyenv/bin/activate
|
|
||||||
return
|
|
||||||
else
|
|
||||||
rm -f $pyenv_file
|
|
||||||
rm -rf $pyenv_path/pyenv
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
cd /www
|
|
||||||
python_src='/www/python_src.tar.xz'
|
|
||||||
python_src_path="/www/Python-${py_version}"
|
|
||||||
wget -O $python_src $download_Url/src/Python-${py_version}.tar.xz -T 5
|
|
||||||
tmp_size=$(du -b $python_src|awk '{print $1}')
|
|
||||||
if [ $tmp_size -lt 10703460 ];then
|
|
||||||
rm -f $python_src
|
|
||||||
Red_Error "ERROR: Download python source code fielded." "ERROR: 下载宝塔运行环境失败,请尝试重新安装!"
|
|
||||||
fi
|
|
||||||
tar xvf $python_src
|
|
||||||
rm -f $python_src
|
|
||||||
cd $python_src_path
|
|
||||||
./configure --prefix=$pyenv_path/pyenv
|
|
||||||
make -j$cpu_cpunt
|
|
||||||
make install
|
|
||||||
if [ ! -f $pyenv_path/pyenv/bin/python3.7 ];then
|
|
||||||
rm -rf $python_src_path
|
|
||||||
Red_Error "ERROR: Make python env fielded." "ERROR: 编译宝塔运行环境失败!"
|
|
||||||
fi
|
|
||||||
cd ~
|
|
||||||
rm -rf $python_src_path
|
|
||||||
wget -O $pyenv_path/pyenv/bin/activate $download_Url/install/pyenv/activate.panel -T 5
|
|
||||||
wget -O $pyenv_path/pyenv/pip.txt $download_Url/install/pyenv/pip-3.7.8.txt -T 5
|
|
||||||
ln -sf $pyenv_path/pyenv/bin/pip3.7 $pyenv_path/pyenv/bin/pip
|
|
||||||
ln -sf $pyenv_path/pyenv/bin/python3.7 $pyenv_path/pyenv/bin/python
|
|
||||||
ln -sf $pyenv_path/pyenv/bin/pip3.7 /usr/bin/btpip
|
|
||||||
ln -sf $pyenv_path/pyenv/bin/python3.7 /usr/bin/btpython
|
|
||||||
chmod -R 700 $pyenv_path/pyenv/bin
|
|
||||||
$pyenv_path/pyenv/bin/pip install -U pip
|
|
||||||
$pyenv_path/pyenv/bin/pip install -U setuptools==65.5.0
|
|
||||||
$pyenv_path/pyenv/bin/pip install -U wheel==0.34.2
|
|
||||||
$pyenv_path/pyenv/bin/pip install -r $pyenv_path/pyenv/pip.txt
|
|
||||||
source $pyenv_path/pyenv/bin/activate
|
|
||||||
|
|
||||||
is_gevent=$($python_bin -m gevent 2>&1|grep -oE package)
|
|
||||||
is_psutil=$($python_bin -m psutil 2>&1|grep -oE package)
|
|
||||||
if [ "${is_gevent}" != "${is_psutil}" ];then
|
|
||||||
Red_Error "ERROR: psutil/gevent install failed!"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
Install_Bt(){
|
|
||||||
panelPort="8888"
|
|
||||||
if [ -f ${setup_path}/server/panel/data/port.pl ];then
|
|
||||||
panelPort=$(cat ${setup_path}/server/panel/data/port.pl)
|
|
||||||
else
|
|
||||||
RE_NUM=$(expr $RANDOM % 3)
|
|
||||||
if [ "${RE_NUM}" == "1" ];then
|
|
||||||
panelPort=$(expr $RANDOM % 55535 + 10000)
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
mkdir -p ${setup_path}/server/panel/logs
|
|
||||||
mkdir -p ${setup_path}/server/panel/vhost/apache
|
|
||||||
mkdir -p ${setup_path}/server/panel/vhost/nginx
|
|
||||||
mkdir -p ${setup_path}/server/panel/vhost/rewrite
|
|
||||||
mkdir -p ${setup_path}/server/panel/install
|
|
||||||
mkdir -p /www/server
|
|
||||||
mkdir -p /www/wwwroot
|
|
||||||
mkdir -p /www/wwwlogs
|
|
||||||
mkdir -p /www/backup/database
|
|
||||||
mkdir -p /www/backup/site
|
|
||||||
|
|
||||||
if [ ! -d "/etc/init.d" ];then
|
|
||||||
mkdir -p /etc/init.d
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -f "/etc/init.d/bt" ]; then
|
|
||||||
/etc/init.d/bt stop
|
|
||||||
sleep 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
wget -O /etc/init.d/bt ${download_Url}/install/src/bt6.init -T 10
|
|
||||||
wget -O /www/server/panel/install/public.sh ${Btapi_Url}/install/public.sh -T 10
|
|
||||||
wget -O panel.zip ${Btapi_Url}/install/src/panel6.zip -T 10
|
|
||||||
|
|
||||||
if [ -f "${setup_path}/server/panel/data/default.db" ];then
|
|
||||||
if [ -d "/${setup_path}/server/panel/old_data" ];then
|
|
||||||
rm -rf ${setup_path}/server/panel/old_data
|
|
||||||
fi
|
|
||||||
mkdir -p ${setup_path}/server/panel/old_data
|
|
||||||
d_format=$(date +"%Y%m%d_%H%M%S")
|
|
||||||
\cp -arf ${setup_path}/server/panel/data/default.db ${setup_path}/server/panel/data/default_backup_${d_format}.db
|
|
||||||
mv -f ${setup_path}/server/panel/data/default.db ${setup_path}/server/panel/old_data/default.db
|
|
||||||
mv -f ${setup_path}/server/panel/data/system.db ${setup_path}/server/panel/old_data/system.db
|
|
||||||
mv -f ${setup_path}/server/panel/data/port.pl ${setup_path}/server/panel/old_data/port.pl
|
|
||||||
mv -f ${setup_path}/server/panel/data/admin_path.pl ${setup_path}/server/panel/old_data/admin_path.pl
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ ! -f "/usr/bin/unzip" ]; then
|
|
||||||
if [ "${PM}" = "yum" ]; then
|
|
||||||
yum install unzip -y
|
|
||||||
elif [ "${PM}" = "apt-get" ]; then
|
|
||||||
apt-get update
|
|
||||||
apt-get install unzip -y
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
unzip -o panel.zip -d ${setup_path}/server/ > /dev/null
|
|
||||||
|
|
||||||
if [ -d "${setup_path}/server/panel/old_data" ];then
|
|
||||||
mv -f ${setup_path}/server/panel/old_data/default.db ${setup_path}/server/panel/data/default.db
|
|
||||||
mv -f ${setup_path}/server/panel/old_data/system.db ${setup_path}/server/panel/data/system.db
|
|
||||||
mv -f ${setup_path}/server/panel/old_data/port.pl ${setup_path}/server/panel/data/port.pl
|
|
||||||
mv -f ${setup_path}/server/panel/old_data/admin_path.pl ${setup_path}/server/panel/data/admin_path.pl
|
|
||||||
if [ -d "/${setup_path}/server/panel/old_data" ];then
|
|
||||||
rm -rf ${setup_path}/server/panel/old_data
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ ! -f ${setup_path}/server/panel/tools.py ] || [ ! -f ${setup_path}/server/panel/BT-Panel ];then
|
|
||||||
ls -lh panel.zip
|
|
||||||
Red_Error "ERROR: Failed to download, please try install again!" "ERROR: 下载宝塔失败,请尝试重新安装!"
|
|
||||||
fi
|
|
||||||
|
|
||||||
rm -f panel.zip
|
|
||||||
rm -f ${setup_path}/server/panel/class/*.pyc
|
|
||||||
rm -f ${setup_path}/server/panel/*.pyc
|
|
||||||
|
|
||||||
chmod +x /etc/init.d/bt
|
|
||||||
chmod -R 600 ${setup_path}/server/panel
|
|
||||||
chmod -R +x ${setup_path}/server/panel/script
|
|
||||||
ln -sf /etc/init.d/bt /usr/bin/bt
|
|
||||||
echo "${panelPort}" > ${setup_path}/server/panel/data/port.pl
|
|
||||||
wget -O /etc/init.d/bt ${download_Url}/install/src/bt7.init -T 10
|
|
||||||
wget -O /www/server/panel/init.sh ${download_Url}/install/src/bt7.init -T 10
|
|
||||||
wget -O /www/server/panel/data/softList.conf ${download_Url}/install/conf/softList.conf
|
|
||||||
|
|
||||||
rm -f /www/server/panel/class/*.so
|
|
||||||
if [ ! -f /www/server/panel/data/not_workorder.pl ]; then
|
|
||||||
echo "True" > /www/server/panel/data/not_workorder.pl
|
|
||||||
fi
|
|
||||||
if [ ! -f /www/server/panel/data/userInfo.json ]; then
|
|
||||||
echo "{\"uid\":1,\"username\":\"Administrator\",\"address\":\"127.0.0.1\",\"serverid\":\"1\",\"access_key\":\"test\",\"secret_key\":\"123456\",\"ukey\":\"123456\",\"state\":1}" > /www/server/panel/data/userInfo.json
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
Set_Bt_Panel(){
|
|
||||||
Run_User="www"
|
|
||||||
wwwUser=$(cat /etc/passwd|cut -d ":" -f 1|grep ^www$)
|
|
||||||
if [ "${wwwUser}" != "www" ];then
|
|
||||||
groupadd ${Run_User}
|
|
||||||
useradd -s /sbin/nologin -g ${Run_User} ${Run_User}
|
|
||||||
fi
|
|
||||||
|
|
||||||
password=$(cat /dev/urandom | head -n 16 | md5sum | head -c 8)
|
|
||||||
sleep 1
|
|
||||||
admin_auth="/www/server/panel/data/admin_path.pl"
|
|
||||||
if [ ! -f ${admin_auth} ];then
|
|
||||||
auth_path=$(cat /dev/urandom | head -n 16 | md5sum | head -c 8)
|
|
||||||
echo "/${auth_path}" > ${admin_auth}
|
|
||||||
fi
|
|
||||||
chmod -R 700 $pyenv_path/pyenv/bin
|
|
||||||
/www/server/panel/pyenv/bin/pip3 install pymongo
|
|
||||||
/www/server/panel/pyenv/bin/pip3 install psycopg2-binary
|
|
||||||
/www/server/panel/pyenv/bin/pip3 install flask -U
|
|
||||||
/www/server/panel/pyenv/bin/pip3 install flask-sock
|
|
||||||
auth_path=$(cat ${admin_auth})
|
|
||||||
cd ${setup_path}/server/panel/
|
|
||||||
/etc/init.d/bt start
|
|
||||||
$python_bin -m py_compile tools.py
|
|
||||||
$python_bin tools.py username
|
|
||||||
username=$($python_bin tools.py panel ${password})
|
|
||||||
cd ~
|
|
||||||
echo "${password}" > ${setup_path}/server/panel/default.pl
|
|
||||||
chmod 600 ${setup_path}/server/panel/default.pl
|
|
||||||
sleep 3
|
|
||||||
/etc/init.d/bt restart
|
|
||||||
sleep 3
|
|
||||||
isStart=$(ps aux |grep 'BT-Panel'|grep -v grep|awk '{print $2}')
|
|
||||||
LOCAL_CURL=$(curl 127.0.0.1:8888/login 2>&1 |grep -i html)
|
|
||||||
if [ -z "${isStart}" ] && [ -z "${LOCAL_CURL}" ];then
|
|
||||||
/etc/init.d/bt 22
|
|
||||||
cd /www/server/panel/pyenv/bin
|
|
||||||
touch t.pl
|
|
||||||
ls -al python3.7 python
|
|
||||||
lsattr python3.7 python
|
|
||||||
Red_Error "ERROR: The BT-Panel service startup failed." "ERROR: 宝塔启动失败"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
Set_Firewall(){
|
|
||||||
sshPort=$(cat /etc/ssh/sshd_config | grep 'Port '|awk '{print $2}')
|
|
||||||
if [ "${PM}" = "apt-get" ]; then
|
|
||||||
apt-get install -y ufw
|
|
||||||
if [ -f "/usr/sbin/ufw" ];then
|
|
||||||
ufw allow 20/tcp
|
|
||||||
ufw allow 21/tcp
|
|
||||||
ufw allow 22/tcp
|
|
||||||
ufw allow 80/tcp
|
|
||||||
ufw allow 443/tcp
|
|
||||||
ufw allow 888/tcp
|
|
||||||
ufw allow ${panelPort}/tcp
|
|
||||||
ufw allow ${sshPort}/tcp
|
|
||||||
ufw allow 39000:40000/tcp
|
|
||||||
ufw_status=`ufw status`
|
|
||||||
echo y|ufw enable
|
|
||||||
ufw default deny
|
|
||||||
ufw reload
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
if [ -f "/etc/init.d/iptables" ];then
|
|
||||||
iptables -I INPUT -p tcp -m state --state NEW -m tcp --dport 20 -j ACCEPT
|
|
||||||
iptables -I INPUT -p tcp -m state --state NEW -m tcp --dport 21 -j ACCEPT
|
|
||||||
iptables -I INPUT -p tcp -m state --state NEW -m tcp --dport 22 -j ACCEPT
|
|
||||||
iptables -I INPUT -p tcp -m state --state NEW -m tcp --dport 80 -j ACCEPT
|
|
||||||
iptables -I INPUT -p tcp -m state --state NEW -m tcp --dport 443 -j ACCEPT
|
|
||||||
iptables -I INPUT -p tcp -m state --state NEW -m tcp --dport ${panelPort} -j ACCEPT
|
|
||||||
iptables -I INPUT -p tcp -m state --state NEW -m tcp --dport ${sshPort} -j ACCEPT
|
|
||||||
iptables -I INPUT -p tcp -m state --state NEW -m tcp --dport 39000:40000 -j ACCEPT
|
|
||||||
#iptables -I INPUT -p tcp -m state --state NEW -m udp --dport 39000:40000 -j ACCEPT
|
|
||||||
iptables -A INPUT -p icmp --icmp-type any -j ACCEPT
|
|
||||||
iptables -A INPUT -s localhost -d localhost -j ACCEPT
|
|
||||||
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
|
|
||||||
iptables -P INPUT DROP
|
|
||||||
service iptables save
|
|
||||||
sed -i "s#IPTABLES_MODULES=\"\"#IPTABLES_MODULES=\"ip_conntrack_netbios_ns ip_conntrack_ftp ip_nat_ftp\"#" /etc/sysconfig/iptables-config
|
|
||||||
iptables_status=$(service iptables status | grep 'not running')
|
|
||||||
if [ "${iptables_status}" == '' ];then
|
|
||||||
service iptables restart
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
AliyunCheck=$(cat /etc/redhat-release|grep "Aliyun Linux")
|
|
||||||
[ "${AliyunCheck}" ] && return
|
|
||||||
yum install firewalld -y
|
|
||||||
[ "${Centos8Check}" ] && yum reinstall python3-six -y
|
|
||||||
systemctl enable firewalld
|
|
||||||
systemctl start firewalld
|
|
||||||
firewall-cmd --set-default-zone=public > /dev/null 2>&1
|
|
||||||
firewall-cmd --permanent --zone=public --add-port=20/tcp > /dev/null 2>&1
|
|
||||||
firewall-cmd --permanent --zone=public --add-port=21/tcp > /dev/null 2>&1
|
|
||||||
firewall-cmd --permanent --zone=public --add-port=22/tcp > /dev/null 2>&1
|
|
||||||
firewall-cmd --permanent --zone=public --add-port=80/tcp > /dev/null 2>&1
|
|
||||||
firewall-cmd --permanent --zone=public --add-port=443/tcp > /dev/null 2>&1
|
|
||||||
firewall-cmd --permanent --zone=public --add-port=${panelPort}/tcp > /dev/null 2>&1
|
|
||||||
firewall-cmd --permanent --zone=public --add-port=${sshPort}/tcp > /dev/null 2>&1
|
|
||||||
firewall-cmd --permanent --zone=public --add-port=39000-40000/tcp > /dev/null 2>&1
|
|
||||||
#firewall-cmd --permanent --zone=public --add-port=39000-40000/udp > /dev/null 2>&1
|
|
||||||
firewall-cmd --reload
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
Get_Ip_Address(){
|
|
||||||
getIpAddress=""
|
|
||||||
getIpAddress=$(curl -sS --connect-timeout 10 -m 60 https://www.bt.cn/Api/getIpAddress)
|
|
||||||
if [ -z "${getIpAddress}" ] || [ "${getIpAddress}" = "0.0.0.0" ]; then
|
|
||||||
isHosts=$(cat /etc/hosts|grep 'www.bt.cn')
|
|
||||||
if [ -z "${isHosts}" ];then
|
|
||||||
echo "" >> /etc/hosts
|
|
||||||
echo "116.213.43.206 www.bt.cn" >> /etc/hosts
|
|
||||||
getIpAddress=$(curl -sS --connect-timeout 10 -m 60 https://www.bt.cn/Api/getIpAddress)
|
|
||||||
if [ -z "${getIpAddress}" ];then
|
|
||||||
sed -i "/bt.cn/d" /etc/hosts
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
ipv4Check=$($python_bin -c "import re; print(re.match('^(?:[0-9]{1,3}\.){3}[0-9]{1,3}$','${getIpAddress}'))")
|
|
||||||
if [ "${ipv4Check}" == "None" ];then
|
|
||||||
ipv6Address=$(echo ${getIpAddress}|tr -d "[]")
|
|
||||||
ipv6Check=$($python_bin -c "import re; print(re.match('^([0-9a-fA-F]{0,4}:){1,7}[0-9a-fA-F]{0,4}$','${ipv6Address}'))")
|
|
||||||
if [ "${ipv6Check}" == "None" ]; then
|
|
||||||
getIpAddress="SERVER_IP"
|
|
||||||
else
|
|
||||||
echo "True" > ${setup_path}/server/panel/data/ipv6.pl
|
|
||||||
sleep 1
|
|
||||||
/etc/init.d/bt restart
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ "${getIpAddress}" != "SERVER_IP" ];then
|
|
||||||
echo "${getIpAddress}" > ${setup_path}/server/panel/data/iplist.txt
|
|
||||||
fi
|
|
||||||
LOCAL_IP=$(ip addr | grep -E -o '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' | grep -E -v "^127\.|^255\.|^0\." | head -n 1)
|
|
||||||
}
|
|
||||||
Setup_Count(){
|
|
||||||
curl -sS --connect-timeout 10 -m 60 https://www.bt.cn/Api/SetupCount?type=Linux\&o=$1 > /dev/null 2>&1
|
|
||||||
if [ "$1" != "" ];then
|
|
||||||
echo $1 > /www/server/panel/data/o.pl
|
|
||||||
cd /www/server/panel
|
|
||||||
$python_bin tools.py o
|
|
||||||
fi
|
|
||||||
echo /www > /var/bt_setupPath.conf
|
|
||||||
}
|
|
||||||
Install_Main(){
|
|
||||||
startTime=`date +%s`
|
|
||||||
Lock_Clear
|
|
||||||
System_Check
|
|
||||||
Get_Pack_Manager
|
|
||||||
get_node_url
|
|
||||||
|
|
||||||
MEM_TOTAL=$(free -g|grep Mem|awk '{print $2}')
|
|
||||||
if [ "${MEM_TOTAL}" -le "1" ];then
|
|
||||||
Auto_Swap
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ "${PM}" = "yum" ]; then
|
|
||||||
Install_RPM_Pack
|
|
||||||
elif [ "${PM}" = "apt-get" ]; then
|
|
||||||
Install_Deb_Pack
|
|
||||||
fi
|
|
||||||
|
|
||||||
Install_Python_Lib
|
|
||||||
Install_Bt
|
|
||||||
|
|
||||||
|
|
||||||
Set_Bt_Panel
|
|
||||||
Service_Add
|
|
||||||
Set_Firewall
|
|
||||||
|
|
||||||
Get_Ip_Address
|
|
||||||
Setup_Count ${IDC_CODE}
|
|
||||||
}
|
|
||||||
|
|
||||||
echo "
|
|
||||||
+----------------------------------------------------------------------
|
|
||||||
| Bt-WebPanel FOR CentOS/Ubuntu/Debian
|
|
||||||
+----------------------------------------------------------------------
|
|
||||||
| Copyright © 2015-2099 BT-SOFT(http://www.bt.cn) All rights reserved.
|
|
||||||
+----------------------------------------------------------------------
|
|
||||||
| The WebPanel URL will be http://SERVER_IP:8888 when installed.
|
|
||||||
+----------------------------------------------------------------------
|
|
||||||
| 为了您的正常使用,请确保使用全新或纯净的系统安装宝塔面板,不支持已部署项目/环境的系统安装
|
|
||||||
+----------------------------------------------------------------------
|
|
||||||
"
|
|
||||||
while [ "$go" != 'y' ] && [ "$go" != 'n' ]
|
|
||||||
do
|
|
||||||
read -p "Do you want to install Bt-Panel to the $setup_path directory now?(y/n): " go;
|
|
||||||
done
|
|
||||||
|
|
||||||
if [ "$go" == 'n' ];then
|
|
||||||
exit;
|
|
||||||
fi
|
|
||||||
|
|
||||||
ARCH_LINUX=$(cat /etc/os-release |grep "Arch Linux")
|
|
||||||
if [ "${ARCH_LINUX}" ] && [ -f "/usr/bin/pacman" ];then
|
|
||||||
pacman -Sy
|
|
||||||
pacman -S curl wget unzip firewalld openssl pkg-config make gcc cmake libxml2 libxslt libvpx gd libsodium oniguruma sqlite libzip autoconf inetutils sudo --noconfirm
|
|
||||||
fi
|
|
||||||
|
|
||||||
Install_Main
|
|
||||||
|
|
||||||
echo > /www/server/panel/data/bind.pl
|
|
||||||
echo -e "=================================================================="
|
|
||||||
echo -e "\033[32mCongratulations! Installed successfully!\033[0m"
|
|
||||||
echo -e "=================================================================="
|
|
||||||
echo "外网面板地址: http://${getIpAddress}:${panelPort}${auth_path}"
|
|
||||||
echo "内网面板地址: http://${LOCAL_IP}:${panelPort}${auth_path}"
|
|
||||||
echo -e "username: $username"
|
|
||||||
echo -e "password: $password"
|
|
||||||
echo -e "\033[33mIf you cannot access the panel,\033[0m"
|
|
||||||
echo -e "\033[33mrelease the following panel port [${panelPort}] in the security group\033[0m"
|
|
||||||
echo -e "\033[33m若无法访问面板,请检查防火墙/安全组是否有放行面板[${panelPort}]端口\033[0m"
|
|
||||||
echo -e "=================================================================="
|
|
||||||
|
|
||||||
endTime=`date +%s`
|
|
||||||
((outTime=($endTime-$startTime)/60))
|
|
||||||
echo -e "Time consumed:\033[32m $outTime \033[0mMinute!"
|
|
||||||
|
|
||||||
2048
public/install/install_7.0_en.sh
Normal file
2048
public/install/install_7.0_en.sh
Normal file
File diff suppressed because it is too large
Load Diff
910
public/install/install_btmonitor.sh
Normal file
910
public/install/install_btmonitor.sh
Normal file
@ -0,0 +1,910 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
#########################
|
||||||
|
|
||||||
|
# 广东堡塔安全技术有限公司
|
||||||
|
# author: 赤井秀一
|
||||||
|
# mail: 1021266737@qq.com
|
||||||
|
|
||||||
|
#########################
|
||||||
|
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
|
||||||
|
export PATH
|
||||||
|
LANG=en_US.UTF-8
|
||||||
|
|
||||||
|
Btapi_Url='http://www.example.com'
|
||||||
|
|
||||||
|
is64bit=$(getconf LONG_BIT)
|
||||||
|
if [ "${is64bit}" != '64' ];then
|
||||||
|
echo -e "\033[31m 抱歉, 堡塔云监控系统不支持32位系统, 请使用64位系统! \033[0m"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
S390X_CHECK=$(uname -a|grep s390x)
|
||||||
|
if [ "${S390X_CHECK}" ];then
|
||||||
|
echo -e "\033[31m 抱歉, 堡塔云监控系统不支持s390x架构进行安装,请使用x86_64服务器架构 \033[0m"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
is_aarch64=$(uname -a|grep aarch64)
|
||||||
|
if [ "${is_aarch64}" != "" ];then
|
||||||
|
echo -e "\033[31m 抱歉, 堡塔云监控系统暂不支持aarch64架构进行安装,请使用x86_64服务器架构 \033[0m"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
Command_Exists() {
|
||||||
|
command -v "$@" >/dev/null 2>&1
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
GetSysInfo(){
|
||||||
|
if [ -s "/etc/redhat-release" ];then
|
||||||
|
SYS_VERSION=$(cat /etc/redhat-release)
|
||||||
|
elif [ -s "/etc/issue" ]; then
|
||||||
|
SYS_VERSION=$(cat /etc/issue)
|
||||||
|
fi
|
||||||
|
SYS_INFO=$(uname -a)
|
||||||
|
SYS_BIT=$(getconf LONG_BIT)
|
||||||
|
MEM_TOTAL=$(free -m|grep Mem|awk '{print $2}')
|
||||||
|
CPU_INFO=$(getconf _NPROCESSORS_ONLN)
|
||||||
|
|
||||||
|
echo -e ${SYS_VERSION}
|
||||||
|
echo -e Bit:${SYS_BIT} Mem:${MEM_TOTAL}M Core:${CPU_INFO}
|
||||||
|
echo -e ${SYS_INFO}
|
||||||
|
echo -e "请截图以上报错信息发帖至论坛www.bt.cn/bbs求助"
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Red_Error(){
|
||||||
|
echo '=================================================';
|
||||||
|
printf '\033[1;31;40m%b\033[0m\n' "$@";
|
||||||
|
GetSysInfo
|
||||||
|
exit 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
monitor_path="/www/server/bt-monitor"
|
||||||
|
run_bin="/www/server/bt-monitor/BT-MONITOR"
|
||||||
|
if [ ! -d "/www/server" ];then
|
||||||
|
mkdir -p /www/server
|
||||||
|
fi
|
||||||
|
old_dir="/www/server/old_btmonitor"
|
||||||
|
|
||||||
|
cd ~
|
||||||
|
setup_path="/www"
|
||||||
|
python_bin=$setup_path/server/bt-monitor/pyenv/bin/python
|
||||||
|
cpu_cpunt=$(cat /proc/cpuinfo|grep processor|wc -l)
|
||||||
|
|
||||||
|
get_node_url(){
|
||||||
|
if [ ! -f /bin/curl ];then
|
||||||
|
if [ "${PM}" = "yum" ]; then
|
||||||
|
yum install curl -y
|
||||||
|
elif [ "${PM}" = "apt-get" ]; then
|
||||||
|
apt-get install curl -y
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -f "/www/node.pl" ];then
|
||||||
|
download_Url=$(cat /www/node.pl)
|
||||||
|
echo "Download node: $download_Url";
|
||||||
|
echo '---------------------------------------------';
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo '---------------------------------------------';
|
||||||
|
echo "Selected download node...";
|
||||||
|
# nodes=(http://dg2.bt.cn http://dg1.bt.cn http://125.90.93.52:5880 http://36.133.1.8:5880 http://123.129.198.197 http://38.34.185.130 http://116.213.43.206:5880 http://128.1.164.196);
|
||||||
|
#nodes=(http://dg2.bt.cn http://dg1.bt.cn http://125.90.93.52:5880 http://36.133.1.8:5880 http://123.129.198.197 http://116.213.43.206:5880 http://128.1.164.196);
|
||||||
|
nodes=(https://dg2.bt.cn https://dg1.bt.cn https://download.bt.cn);
|
||||||
|
tmp_file1=/dev/shm/net_test1.pl
|
||||||
|
tmp_file2=/dev/shm/net_test2.pl
|
||||||
|
[ -f "${tmp_file1}" ] && rm -f ${tmp_file1}
|
||||||
|
[ -f "${tmp_file2}" ] && rm -f ${tmp_file2}
|
||||||
|
touch $tmp_file1
|
||||||
|
touch $tmp_file2
|
||||||
|
for node in ${nodes[@]};
|
||||||
|
do
|
||||||
|
NODE_CHECK=$(curl --connect-timeout 3 -m 3 2>/dev/null -w "%{http_code} %{time_total}" ${node}/net_test|xargs)
|
||||||
|
RES=$(echo ${NODE_CHECK}|awk '{print $1}')
|
||||||
|
NODE_STATUS=$(echo ${NODE_CHECK}|awk '{print $2}')
|
||||||
|
TIME_TOTAL=$(echo ${NODE_CHECK}|awk '{print $3 * 1000 - 500 }'|cut -d '.' -f 1)
|
||||||
|
if [ "${NODE_STATUS}" == "200" ];then
|
||||||
|
if [ $TIME_TOTAL -lt 100 ];then
|
||||||
|
if [ $RES -ge 1500 ];then
|
||||||
|
echo "$RES $node" >> $tmp_file1
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
if [ $RES -ge 1500 ];then
|
||||||
|
echo "$TIME_TOTAL $node" >> $tmp_file2
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
i=$(($i+1))
|
||||||
|
if [ $TIME_TOTAL -lt 100 ];then
|
||||||
|
if [ $RES -ge 3000 ];then
|
||||||
|
break;
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
NODE_URL=$(cat $tmp_file1|sort -r -g -t " " -k 1|head -n 1|awk '{print $2}')
|
||||||
|
if [ -z "$NODE_URL" ];then
|
||||||
|
NODE_URL=$(cat $tmp_file2|sort -g -t " " -k 1|head -n 1|awk '{print $2}')
|
||||||
|
if [ -z "$NODE_URL" ];then
|
||||||
|
NODE_URL='https://download.bt.cn';
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
rm -f $tmp_file1
|
||||||
|
rm -f $tmp_file2
|
||||||
|
download_Url=$NODE_URL
|
||||||
|
echo "Download node: $download_Url";
|
||||||
|
echo '---------------------------------------------';
|
||||||
|
}
|
||||||
|
|
||||||
|
Get_Versions(){
|
||||||
|
redhat_version_file="/etc/redhat-release"
|
||||||
|
deb_version_file="/etc/issue"
|
||||||
|
if [ -f $redhat_version_file ];then
|
||||||
|
os_type='el'
|
||||||
|
is_aliyunos=$(cat $redhat_version_file|grep Aliyun)
|
||||||
|
if [ "$is_aliyunos" != "" ];then
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
os_version=$(cat $redhat_version_file|grep CentOS|grep -Eo '([0-9]+\.)+[0-9]+'|grep -Eo '^[0-9]')
|
||||||
|
if [ "${os_version}" = "5" ];then
|
||||||
|
os_version=""
|
||||||
|
fi
|
||||||
|
if [ -z "${os_version}" ];then
|
||||||
|
os_version=$(cat /etc/redhat-release |grep Stream|grep -oE 8)
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
os_type='ubuntu'
|
||||||
|
os_version=$(cat $deb_version_file|grep Ubuntu|grep -Eo '([0-9]+\.)+[0-9]+'|grep -Eo '^[0-9]+')
|
||||||
|
if [ "${os_version}" = "" ];then
|
||||||
|
os_type='debian'
|
||||||
|
os_version=$(cat $deb_version_file|grep Debian|grep -Eo '([0-9]+\.)+[0-9]+'|grep -Eo '[0-9]+')
|
||||||
|
if [ "${os_version}" = "" ];then
|
||||||
|
os_version=$(cat $deb_version_file|grep Debian|grep -Eo '[0-9]+')
|
||||||
|
fi
|
||||||
|
if [ "${os_version}" = "8" ];then
|
||||||
|
os_version=""
|
||||||
|
fi
|
||||||
|
if [ "${is64bit}" = '32' ];then
|
||||||
|
os_version=""
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
if [ "$os_version" = "14" ];then
|
||||||
|
os_version=""
|
||||||
|
fi
|
||||||
|
if [ "$os_version" = "12" ];then
|
||||||
|
os_version=""
|
||||||
|
fi
|
||||||
|
if [ "$os_version" = "19" ];then
|
||||||
|
os_version=""
|
||||||
|
fi
|
||||||
|
if [ "$os_version" = "21" ];then
|
||||||
|
os_version=""
|
||||||
|
fi
|
||||||
|
if [ "$os_version" = "20" ];then
|
||||||
|
os_version2004=$(cat /etc/issue|grep 20.04)
|
||||||
|
if [ -z "${os_version2004}" ];then
|
||||||
|
os_version=""
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
Install_Python_Lib(){
|
||||||
|
curl -Ss --connect-timeout 3 -m 60 $download_Url/install/pip_select.sh|bash
|
||||||
|
pyenv_path="/www/server/bt-monitor"
|
||||||
|
if [ -f $pyenv_path/pyenv/bin/python ];then
|
||||||
|
is_ssl=$($python_bin -c "import ssl" 2>&1|grep cannot)
|
||||||
|
$pyenv_path/pyenv/bin/python3.7 -V
|
||||||
|
if [ $? -eq 0 ] && [ -z "${is_ssl}" ];then
|
||||||
|
chmod -R 700 $pyenv_path/pyenv/bin
|
||||||
|
is_package=$($python_bin -m psutil 2>&1|grep package)
|
||||||
|
if [ "$is_package" = "" ];then
|
||||||
|
wget -O $pyenv_path/pyenv/pip.txt $download_Url/install/pyenv/pip.txt -t 5 -T 10
|
||||||
|
$pyenv_path/pyenv/bin/pip install -U pip
|
||||||
|
$pyenv_path/pyenv/bin/pip install -U setuptools
|
||||||
|
$pyenv_path/pyenv/bin/pip install -r $pyenv_path/pyenv/pip.txt
|
||||||
|
$pyenv_path/pyenv/bin/pip install -U flask==2.2.0
|
||||||
|
$pyenv_path/pyenv/bin/pip install flask_sock
|
||||||
|
$pyenv_path/pyenv/bin/pip install cachelib
|
||||||
|
$pyenv_path/pyenv/bin/pip install py7zr
|
||||||
|
$pyenv_path/pyenv/bin/pip install backports.lzma
|
||||||
|
$pyenv_path/pyenv/bin/pip install pandas
|
||||||
|
$pyenv_path/pyenv/bin/pip install msgpack
|
||||||
|
$pyenv_path/pyenv/bin/pip install simple-websocket==0.10.0
|
||||||
|
fi
|
||||||
|
source $pyenv_path/pyenv/bin/activate
|
||||||
|
chmod -R 700 $pyenv_path/pyenv/bin
|
||||||
|
return
|
||||||
|
else
|
||||||
|
rm -rf $pyenv_path/pyenv
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
py_version="3.7.9"
|
||||||
|
if [ ! -d "$pyenv_path" ]; then
|
||||||
|
mkdir -p $pyenv_path
|
||||||
|
fi
|
||||||
|
echo "True" > /www/disk.pl
|
||||||
|
if [ ! -w /www/disk.pl ];then
|
||||||
|
Red_Error "ERROR: Install python env fielded." "ERROR: /www目录无法写入,请检查目录/用户/磁盘权限!"
|
||||||
|
fi
|
||||||
|
os_type='el'
|
||||||
|
os_version='7'
|
||||||
|
is_export_openssl=0
|
||||||
|
Get_Versions
|
||||||
|
|
||||||
|
echo "OS: $os_type - $os_version"
|
||||||
|
is_aarch64=$(uname -a|grep aarch64)
|
||||||
|
if [ "$is_aarch64" != "" ];then
|
||||||
|
is64bit="aarch64"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -f "/www/server/bt-monitor/pymake.pl" ];then
|
||||||
|
os_version=""
|
||||||
|
rm -f /www/server/bt-monitor/pymake.pl
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ $os_type =~ "debian" ]] || [[ $os_type =~ "ubuntu" ]]; then
|
||||||
|
isbtm="-btm"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "${os_version}" != "" ];then
|
||||||
|
pyenv_file="/www/pyenv.tar.gz"
|
||||||
|
wget -O $pyenv_file $download_Url/install/pyenv/pyenv-${os_type}${os_version}-x${is64bit}${isbtm}.tar.gz -t 5 -T 10
|
||||||
|
|
||||||
|
tmp_size=$(du -b $pyenv_file|awk '{print $1}')
|
||||||
|
if [ $tmp_size -lt 703460 ];then
|
||||||
|
rm -f $pyenv_file
|
||||||
|
echo "ERROR: Download python env fielded."
|
||||||
|
else
|
||||||
|
echo "Install python env..."
|
||||||
|
tar zxvf $pyenv_file -C $pyenv_path/ > /dev/null
|
||||||
|
chmod -R 700 $pyenv_path/pyenv/bin
|
||||||
|
rm -rf $pyenv_path/pyenv/bin/python
|
||||||
|
ln -sf $pyenv_path/pyenv/bin/python3.7 $pyenv_path/pyenv/bin/python
|
||||||
|
$pyenv_path/pyenv/bin/python -m pip install --upgrade --force-reinstall pip
|
||||||
|
$pyenv_path/pyenv/bin/pip install -U flask==2.2.0
|
||||||
|
$pyenv_path/pyenv/bin/pip install flask_sock
|
||||||
|
$pyenv_path/pyenv/bin/pip install cachelib
|
||||||
|
$pyenv_path/pyenv/bin/pip install py7zr
|
||||||
|
$pyenv_path/pyenv/bin/pip install backports.lzma
|
||||||
|
$pyenv_path/pyenv/bin/pip install pandas
|
||||||
|
$pyenv_path/pyenv/bin/pip install msgpack
|
||||||
|
$pyenv_path/pyenv/bin/pip install simple-websocket==0.10.0
|
||||||
|
if [ ! -f $pyenv_path/pyenv/bin/python ];then
|
||||||
|
rm -f $pyenv_file
|
||||||
|
Red_Error "ERROR: Install python env fielded." "ERROR: 下载堡塔云监控主控端运行环境失败,请尝试重新安装!"
|
||||||
|
fi
|
||||||
|
$pyenv_path/pyenv/bin/python3.7 -V
|
||||||
|
if [ $? -eq 0 ];then
|
||||||
|
rm -f $pyenv_file
|
||||||
|
ln -sf $pyenv_path/pyenv/bin/pip3.7 /usr/bin/btmpip
|
||||||
|
ln -sf $pyenv_path/pyenv/bin/python3.7 /usr/bin/btmpython
|
||||||
|
source $pyenv_path/pyenv/bin/activate
|
||||||
|
return
|
||||||
|
else
|
||||||
|
rm -f $pyenv_file
|
||||||
|
rm -rf $pyenv_path/pyenv
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
cd /www
|
||||||
|
python_src='/www/python_src.tar.xz'
|
||||||
|
python_src_path="/www/Python-${py_version}"
|
||||||
|
wget -O $python_src $download_Url/src/Python-${py_version}.tar.xz -t 5 -T 10
|
||||||
|
tmp_size=$(du -b $python_src|awk '{print $1}')
|
||||||
|
if [ $tmp_size -lt 10703460 ];then
|
||||||
|
rm -f $python_src
|
||||||
|
Red_Error "ERROR: Download python source code fielded." "ERROR: 下载堡塔云监控主控端运行环境失败,请尝试重新安装!"
|
||||||
|
fi
|
||||||
|
tar xvf $python_src
|
||||||
|
rm -f $python_src
|
||||||
|
cd $python_src_path
|
||||||
|
./configure --prefix=$pyenv_path/pyenv
|
||||||
|
make -j$cpu_cpunt
|
||||||
|
make install
|
||||||
|
if [ ! -f $pyenv_path/pyenv/bin/python3.7 ];then
|
||||||
|
rm -rf $python_src_path
|
||||||
|
Red_Error "ERROR: Make python env fielded." "ERROR: 编译堡塔云监控主控端运行环境失败!"
|
||||||
|
fi
|
||||||
|
cd ~
|
||||||
|
rm -rf $python_src_path
|
||||||
|
wget -O $pyenv_path/pyenv/bin/activate $download_Url/install/pyenv/activate.panel -t 5 -T 10
|
||||||
|
wget -O $pyenv_path/pyenv/pip.txt $download_Url/install/pyenv/pip-3.7.8.txt -t 5 -T 10
|
||||||
|
ln -sf $pyenv_path/pyenv/bin/pip3.7 $pyenv_path/pyenv/bin/pip
|
||||||
|
ln -sf $pyenv_path/pyenv/bin/python3.7 $pyenv_path/pyenv/bin/python
|
||||||
|
ln -sf $pyenv_path/pyenv/bin/pip3.7 /usr/bin/btmpip
|
||||||
|
ln -sf $pyenv_path/pyenv/bin/python3.7 /usr/bin/btmpython
|
||||||
|
chmod -R 700 $pyenv_path/pyenv/bin
|
||||||
|
$pyenv_path/pyenv/bin/pip install -U pip
|
||||||
|
$pyenv_path/pyenv/bin/pip install -U setuptools
|
||||||
|
$pyenv_path/pyenv/bin/pip install -U wheel==0.34.2
|
||||||
|
$pyenv_path/pyenv/bin/pip install -r $pyenv_path/pyenv/pip.txt
|
||||||
|
$pyenv_path/pyenv/bin/pip install -U flask==2.2.0
|
||||||
|
$pyenv_path/pyenv/bin/pip install flask_sock
|
||||||
|
$pyenv_path/pyenv/bin/pip install cachelib
|
||||||
|
$pyenv_path/pyenv/bin/pip install py7zr
|
||||||
|
$pyenv_path/pyenv/bin/pip install backports.lzma
|
||||||
|
$pyenv_path/pyenv/bin/pip install pandas
|
||||||
|
$pyenv_path/pyenv/bin/pip install msgpack
|
||||||
|
$pyenv_path/pyenv/bin/pip install simple-websocket==0.10.0
|
||||||
|
source $pyenv_path/pyenv/bin/activate
|
||||||
|
|
||||||
|
is_gevent=$($python_bin -m gevent 2>&1|grep -oE package)
|
||||||
|
is_psutil=$($python_bin -m psutil 2>&1|grep -oE package)
|
||||||
|
if [ "${is_gevent}" != "${is_psutil}" ];then
|
||||||
|
Red_Error "ERROR: psutil/gevent install failed!"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
Install_Monitor(){
|
||||||
|
ulimit -n 1000001
|
||||||
|
tee -a /etc/security/limits.conf << EOF
|
||||||
|
* hard nofile 1000001
|
||||||
|
* soft nofile 1000001
|
||||||
|
root hard nofile 1000001
|
||||||
|
root soft nofile 1000001
|
||||||
|
EOF
|
||||||
|
sysctl -p
|
||||||
|
panelPort="806"
|
||||||
|
|
||||||
|
if [ ! -d "/etc/init.d" ];then
|
||||||
|
mkdir -p /etc/init.d
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -f "/etc/init.d/btm" ]; then
|
||||||
|
/etc/init.d/btm stop
|
||||||
|
sleep 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -f "/www/server/bt-monitor/sqlite-server.sh" ]; then
|
||||||
|
chmod +x /www/server/bt-monitor/sqlite-server.sh
|
||||||
|
/www/server/bt-monitor/sqlite-server.sh stop
|
||||||
|
sleep 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
version="2.1.7"
|
||||||
|
file_name="bt-monitor"
|
||||||
|
agent_src="bt-monitor.zip"
|
||||||
|
|
||||||
|
cd ~
|
||||||
|
version=`curl -sf ${Btapi_Url}/bt_monitor/latest_version |awk -F '\"version\"' '{print $2}'|awk -F ':' '{print $2}'|awk -F '"' '{print $2}'`
|
||||||
|
if [ -z $version ]; then
|
||||||
|
version="2.0.6"
|
||||||
|
fi
|
||||||
|
if [ "$re_install" == "1" ]; then
|
||||||
|
new_dir="/www/server/new_btmonitor"
|
||||||
|
if [ ! -d "$new_dir" ];then
|
||||||
|
mkdir -p $new_dir
|
||||||
|
fi
|
||||||
|
wget -O $agent_src ${Btapi_Url}/install/src/$file_name-$version.zip -t 5 -T 10
|
||||||
|
unzip -o $agent_src -d $new_dir/ > /dev/null
|
||||||
|
if [ ! -f $new_dir/BT-MONITOR ];then
|
||||||
|
ls -lh $agent_src
|
||||||
|
Red_Error "ERROR: Failed to download, please try install again!" "ERROR: 下载堡塔云监控主控端失败,请尝试重新安装!"
|
||||||
|
fi
|
||||||
|
|
||||||
|
rm -rf $new_dir/config
|
||||||
|
rm -rf $new_dir/data
|
||||||
|
rm -rf $new_dir/ssl
|
||||||
|
\cp -r $new_dir/* $monitor_path/
|
||||||
|
rm -rf $new_dir
|
||||||
|
else
|
||||||
|
wget -O $agent_src ${Btapi_Url}/install/src/$file_name-$version.zip -t 5 -T 10
|
||||||
|
if [ ! -d "$monitor_path" ]; then
|
||||||
|
mkdir -p $monitor_path
|
||||||
|
fi
|
||||||
|
unzip -o $agent_src -d $monitor_path/ > /dev/null
|
||||||
|
if [ ! -f $run_bin ];then
|
||||||
|
ls -lh $agent_src
|
||||||
|
Red_Error "ERROR: Failed to download, please try install again!" "ERROR: 下载堡塔云监控主控端失败,请尝试重新安装!"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
rm -rf $agent_src
|
||||||
|
chmod +x $monitor_path/BT-MONITOR
|
||||||
|
chmod +x $monitor_path/tools.py
|
||||||
|
wget -O /etc/init.d/btm ${download_Url}/init/btmonitor.init -t 5 -T 10
|
||||||
|
tmp_size=$(du -b "/etc/init.d/btm"|awk '{print $1}')
|
||||||
|
if [ ${tmp_size} == 0 ]; then
|
||||||
|
\cp -r $monitor_path/init.sh /etc/init.d/btm
|
||||||
|
fi
|
||||||
|
if [ ! -f "/etc/init.d/btm" ];then
|
||||||
|
\cp -r $monitor_path/init.sh /etc/init.d/btm
|
||||||
|
fi
|
||||||
|
|
||||||
|
chmod +x /etc/init.d/btm
|
||||||
|
ln -sf /etc/init.d/btm /usr/bin/btm
|
||||||
|
|
||||||
|
if [ ! -f $monitor_path/data/user.json ]; then
|
||||||
|
echo "{\"uid\":1,\"username\":\"Administrator\",\"ip\":\"127.0.0.1\",\"server_id\":\"1\",\"access_key\":\"test\",\"secret_key\":\"123456\"}" > $monitor_path/data/user.json
|
||||||
|
fi
|
||||||
|
if [ -f $monitor_path/core/include/c_loader/PluginLoader.so ]; then
|
||||||
|
rm -f $monitor_path/core/include/c_loader/PluginLoader.so
|
||||||
|
fi
|
||||||
|
if [ -f $monitor_path/sqlite_server/PluginLoader.so ]; then
|
||||||
|
rm -f $monitor_path/sqlite_server/PluginLoader.so
|
||||||
|
fi
|
||||||
|
if [ -f $monitor_path/hook_import/PluginLoader.so ]; then
|
||||||
|
rm -f $monitor_path/hook_import/PluginLoader.so
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
Start_Monitor(){
|
||||||
|
/etc/init.d/btm start
|
||||||
|
if [ "$?" != "0" ]; then
|
||||||
|
#echo "堡塔云监控主控端启动失败!"
|
||||||
|
tail $monitor_path/logs/error.log
|
||||||
|
Red_Error "堡塔云监控主控端启动失败!"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "正在初始化云监控主控端..."
|
||||||
|
if [ "$re_install" == "1" ] || [ "$re_install" == "2" ]; then
|
||||||
|
user_pass=`$setup_path/server/bt-monitor/tools.py reset_pwd`
|
||||||
|
password=`echo $user_pass |awk '{print $3}'`
|
||||||
|
else
|
||||||
|
user_pass=`$monitor_path/tools.py create_admin`
|
||||||
|
password=`echo $user_pass |awk -F " " '{print $5}'`
|
||||||
|
for ((i=1; i<=5; i++));do
|
||||||
|
if [ -z "$password" ]; then
|
||||||
|
sleep 7
|
||||||
|
rm -f /tmp/bt_monitor.lock
|
||||||
|
user_pass=`$monitor_path/tools.py create_admin`
|
||||||
|
password=`echo $user_pass |awk -F " " '{print $5}'`
|
||||||
|
else
|
||||||
|
i=5
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
if [[ "$password" == "" ]];then
|
||||||
|
Red_Error "ERROR: 初始化云监控主控端失败,请尝试重新安装!"
|
||||||
|
fi
|
||||||
|
|
||||||
|
c_path=$(cat /www/server/bt-monitor/config/config.json |awk -F '\"admin_path\"' '{print $2}'|awk -F ":" '{print $2}'|awk -F '"' '{print $2}')
|
||||||
|
adminpath=$(echo $c_path|awk -F ',' '{print $1}')
|
||||||
|
|
||||||
|
if [ -d "/usr/bin/btmonitoragent" ];then
|
||||||
|
rm -rf /usr/bin/btmonitoragent
|
||||||
|
fi
|
||||||
|
|
||||||
|
date_f=`date '+%Y%m%d_%H%M%S'`
|
||||||
|
md5_pl=`echo $date_f | md5sum | head -c 32`
|
||||||
|
token_pl=`cat $monitor_path/config/token.pl 2>&1`
|
||||||
|
if [ "$token_pl" == ' ' ] || [ ! -f $monitor_path/config/token.pl ]; then
|
||||||
|
echo "$md5_pl" > $monitor_path/config/token.pl
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "正在给本机安装云监控被控端,请等待..."
|
||||||
|
sleep 15
|
||||||
|
curl -sSO ${download_Url}/install/btmonitoragent.sh && bash btmonitoragent.sh https://127.0.0.1:806 $md5_pl
|
||||||
|
target_dir="/usr/local/btmonitoragent"
|
||||||
|
if [ ! -f "$target_dir/BT-MonitorAgent" ];then
|
||||||
|
tail -n 10 ${monitor_path}/logs/error.log
|
||||||
|
echo ""
|
||||||
|
ps aux|grep -v grep|grep ${monitor_path}
|
||||||
|
netstat -tulnp|grep ${panelPort}
|
||||||
|
/etc/init.d/btm restart
|
||||||
|
if [ "$?" -eq 0 ]; then
|
||||||
|
echo -e "\033[31m安装云监控被控端失败,正在尝试重新安装!\033[0m"
|
||||||
|
sleep 15
|
||||||
|
curl -sSO ${download_Url}/install/btmonitoragent.sh && bash btmonitoragent.sh https://127.0.0.1:806 $md5_pl
|
||||||
|
if [ ! -f "$target_dir/BT-MonitorAgent" ];then
|
||||||
|
Red_Error "ERROR: 安装云监控被控端失败,请尝试重新安装!"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
Red_Error "ERROR: 安装云监控被控端失败,请尝试重新安装!"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
/etc/init.d/btm restart > /dev/null 2>&1
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Set_Firewall(){
|
||||||
|
sshPort=$(cat /etc/ssh/sshd_config | grep 'Port '|awk '{print $2}')
|
||||||
|
if [ "${PM}" = "apt-get" ]; then
|
||||||
|
apt-get install -y ufw
|
||||||
|
if [ -f "/usr/sbin/ufw" ];then
|
||||||
|
ufw allow 22/tcp
|
||||||
|
ufw allow ${panelPort}/tcp
|
||||||
|
ufw allow ${sshPort}/tcp
|
||||||
|
ufw_status=`ufw status`
|
||||||
|
echo y|ufw enable
|
||||||
|
ufw default deny
|
||||||
|
ufw reload
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
if [ -f "/etc/init.d/iptables" ];then
|
||||||
|
iptables -I INPUT -p tcp -m state --state NEW -m tcp --dport 22 -j ACCEPT
|
||||||
|
iptables -I INPUT -p tcp -m state --state NEW -m tcp --dport ${panelPort} -j ACCEPT
|
||||||
|
iptables -I INPUT -p tcp -m state --state NEW -m tcp --dport ${sshPort} -j ACCEPT
|
||||||
|
iptables -A INPUT -p icmp --icmp-type any -j ACCEPT
|
||||||
|
iptables -A INPUT -s localhost -d localhost -j ACCEPT
|
||||||
|
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
|
||||||
|
iptables -P INPUT DROP
|
||||||
|
service iptables save
|
||||||
|
sed -i "s#IPTABLES_MODULES=\"\"#IPTABLES_MODULES=\"ip_conntrack_netbios_ns ip_conntrack_ftp ip_nat_ftp\"#" /etc/sysconfig/iptables-config
|
||||||
|
iptables_status=$(service iptables status | grep 'not running')
|
||||||
|
if [ "${iptables_status}" == '' ];then
|
||||||
|
service iptables restart
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
AliyunCheck=$(cat /etc/redhat-release|grep "Aliyun Linux")
|
||||||
|
[ "${AliyunCheck}" ] && return
|
||||||
|
yum install firewalld -y
|
||||||
|
[ "${Centos8Check}" ] && yum reinstall python3-six -y
|
||||||
|
systemctl enable firewalld
|
||||||
|
systemctl start firewalld
|
||||||
|
firewall-cmd --set-default-zone=public > /dev/null 2>&1
|
||||||
|
firewall-cmd --permanent --zone=public --add-port=22/tcp > /dev/null 2>&1
|
||||||
|
firewall-cmd --permanent --zone=public --add-port=${panelPort}/tcp > /dev/null 2>&1
|
||||||
|
firewall-cmd --permanent --zone=public --add-port=${sshPort}/tcp > /dev/null 2>&1
|
||||||
|
firewall-cmd --reload
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
Service_Add(){
|
||||||
|
if [ $Command_Exists systemctl ]; then
|
||||||
|
wget -O /usr/lib/systemd/system/btm.service ${download_Url}/init/systemd/btmonitor.service -t 5 -T 10
|
||||||
|
systemctl daemon-reload
|
||||||
|
systemctl enable btm
|
||||||
|
else
|
||||||
|
if [ "${PM}" == "yum" ] || [ "${PM}" == "dnf" ]; then
|
||||||
|
chkconfig --add btm
|
||||||
|
chkconfig --level 2345 btm on
|
||||||
|
elif [ "${PM}" == "apt-get" ]; then
|
||||||
|
update-rc.d btm defaults
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
Service_Del(){
|
||||||
|
if [ $Command_Exists systemctl ]; then
|
||||||
|
rm -rf /usr/lib/systemd/system/btm.service
|
||||||
|
systemctl disable btm
|
||||||
|
else
|
||||||
|
if [ "${PM}" == "yum" ] || [ "${PM}" == "dnf" ]; then
|
||||||
|
chkconfig --del btm
|
||||||
|
chkconfig --level 2345 btm off
|
||||||
|
elif [ "${PM}" == "apt-get" ]; then
|
||||||
|
update-rc.d btm remove
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
Get_Ip_Address(){
|
||||||
|
getIpAddress=""
|
||||||
|
getIpAddress=$(curl -sS --connect-timeout 10 -m 60 https://www.bt.cn/Api/getIpAddress)
|
||||||
|
if [ -z "${getIpAddress}" ] || [ "${getIpAddress}" = "0.0.0.0" ]; then
|
||||||
|
isHosts=$(cat /etc/hosts|grep 'www.bt.cn')
|
||||||
|
if [ -z "${isHosts}" ];then
|
||||||
|
echo "" >> /etc/hosts
|
||||||
|
echo "116.213.43.206 www.bt.cn" >> /etc/hosts
|
||||||
|
getIpAddress=$(curl -sS --connect-timeout 10 -m 60 https://www.bt.cn/Api/getIpAddress)
|
||||||
|
if [ -z "${getIpAddress}" ];then
|
||||||
|
sed -i "/bt.cn/d" /etc/hosts
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
ipv4Check=$($python_bin -c "import re; print(re.match('^(?:[0-9]{1,3}\.){3}[0-9]{1,3}$','${getIpAddress}'))")
|
||||||
|
if [ "${ipv4Check}" == "None" ];then
|
||||||
|
ipv6Address=$(echo ${getIpAddress}|tr -d "[]")
|
||||||
|
ipv6Check=$($python_bin -c "import re; print(re.match('^([0-9a-fA-F]{0,4}:){1,7}[0-9a-fA-F]{0,4}$','${ipv6Address}'))")
|
||||||
|
if [ "${ipv6Check}" == "None" ]; then
|
||||||
|
getIpAddress="SERVER_IP"
|
||||||
|
else
|
||||||
|
echo "True" > ${setup_path}/server/bt-monitor/data/ipv6.pl
|
||||||
|
sleep 1
|
||||||
|
/etc/init.d/btm restart
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "${getIpAddress}" != "SERVER_IP" ];then
|
||||||
|
echo "${getIpAddress}" > ${setup_path}/server/bt-monitor/data/iplist.txt
|
||||||
|
fi
|
||||||
|
LOCAL_IP=$(ip addr | grep -E -o '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' | grep -E -v "^127\.|^255\.|^0\." | head -n 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
System_Check(){
|
||||||
|
if [ -f "$monitor_path/BT-MONITOR" ] || [ -f "$monitor_path/tools.py" ] || [ -f "/etc/init.d/btm" ];then
|
||||||
|
Install_Check
|
||||||
|
elif [ -d "$old_dir" ];then
|
||||||
|
Rev_Install_Check
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
Install_Check(){
|
||||||
|
echo -e "----------------------------------------------------"
|
||||||
|
echo -e "检测到已存在堡塔云监控系统,请按照选项选择安装方式!"
|
||||||
|
echo -e "1) 覆盖安装:保存原有监控配置及数据并安装堡塔云监控"
|
||||||
|
echo -e "\033[33m2) 全新安装:清空原有监控配置及数据并安装堡塔云监控\033[0m"
|
||||||
|
echo -e "----------------------------------------------------"
|
||||||
|
read -p "请输入对应选项[1|2]进行安装或输入任意内容退出安装: " yes;
|
||||||
|
if [ "$yes" == "1" ]; then
|
||||||
|
re_install="1"
|
||||||
|
echo "即将卸载并重装本机的堡塔云监控被控端..."
|
||||||
|
Uninstall_agent
|
||||||
|
elif [ "$yes" == "2" ]; then
|
||||||
|
Backup_Monitor
|
||||||
|
echo "即将卸载并重装本机的堡塔云监控被控端..."
|
||||||
|
Uninstall_agent
|
||||||
|
else
|
||||||
|
echo -e "------------"
|
||||||
|
echo "取消安装"
|
||||||
|
exit;
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
Rev_Install_Check(){
|
||||||
|
echo -e "----------------------------------------------------"
|
||||||
|
echo -e "\033[33m检测到上一次卸载云监控时保留的旧数据,请按照选项选择安装方式!\033[0m"
|
||||||
|
echo -e "1) 还原以前的备份并安装堡塔云监控系统!"
|
||||||
|
echo -e "2) 不使用原有备份,全新安装堡塔云监控系统!"
|
||||||
|
echo -e "----------------------------------------------------"
|
||||||
|
read -p "请输入对应选项[1|2]进行安装或输入任意内容退出安装: " yes;
|
||||||
|
if [ "$yes" == "1" ]; then
|
||||||
|
re_install="2"
|
||||||
|
echo "开始安装堡塔云监控系统并还原数据..."
|
||||||
|
elif [ "$yes" == "2" ]; then
|
||||||
|
echo "开始全新安装堡塔云监控系统..."
|
||||||
|
else
|
||||||
|
echo -e "------------"
|
||||||
|
echo "取消安装"
|
||||||
|
exit;
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
Backup_Monitor(){
|
||||||
|
if [ -f "/etc/init.d/btm" ]; then
|
||||||
|
/etc/init.d/btm stop
|
||||||
|
sleep 1
|
||||||
|
fi
|
||||||
|
if [ ! -d "${old_dir}" ];then
|
||||||
|
mkdir -p ${old_dir}
|
||||||
|
else
|
||||||
|
mv ${old_dir} ${old_dir}_$(date +%Y_%m_%d_%H_%M_%S)
|
||||||
|
mkdir -p ${old_dir}
|
||||||
|
fi
|
||||||
|
|
||||||
|
mv ${monitor_path}/data ${old_dir}/data
|
||||||
|
mv ${monitor_path}/config ${old_dir}/config
|
||||||
|
mv ${monitor_path}/ssl ${old_dir}/ssl
|
||||||
|
}
|
||||||
|
|
||||||
|
Reinstall_Monitor(){
|
||||||
|
rm -rf $monitor_path/data
|
||||||
|
rm -rf $monitor_path/config
|
||||||
|
rm -rf $monitor_path/ssl
|
||||||
|
mv $old_dir/data $monitor_path/data
|
||||||
|
mv $old_dir/config $monitor_path/config
|
||||||
|
mv $old_dir/ssl $monitor_path/ssl
|
||||||
|
rm -rf $old_dir
|
||||||
|
}
|
||||||
|
|
||||||
|
Get_Pack_Manager(){
|
||||||
|
if [ -f "/usr/bin/yum" ] && [ -d "/etc/yum.repos.d" ]; then
|
||||||
|
PM="yum"
|
||||||
|
elif [ -f "/usr/bin/apt-get" ] && [ -f "/usr/bin/dpkg" ]; then
|
||||||
|
PM="apt-get"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
Install_RPM_Pack(){
|
||||||
|
yumPacks="wget curl unzip gcc gcc-c++ make libcurl-devel openssl-devel xz-devel python-backports-lzma xz crontabs zlib zlib-devel sqlite-devel libffi-devel bzip2-devel lsof net-tools p7zip-full"
|
||||||
|
yum install -y ${yumPacks}
|
||||||
|
|
||||||
|
for yumPack in ${yumPacks}
|
||||||
|
do
|
||||||
|
rpmPack=$(rpm -q ${yumPack})
|
||||||
|
packCheck=$(echo ${rpmPack}|grep not)
|
||||||
|
if [ "${packCheck}" ]; then
|
||||||
|
yum install ${yumPack} -y
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
Install_Deb_Pack(){
|
||||||
|
debPacks="wget curl unzip gcc g++ make cron libcurl4-openssl-dev libssl-dev liblzma-dev xz-utils libffi-dev libbz2-dev libsqlite3-dev libreadline-dev libgdbm-dev python3-bsddb3 tk-dev ncurses-dev uuid-dev zlib1g zlib1g-dev lsof net-tools p7zip-full sqlite3";
|
||||||
|
apt-get update -y
|
||||||
|
apt-get install -y $debPacks --force-yes
|
||||||
|
|
||||||
|
for debPack in ${debPacks}
|
||||||
|
do
|
||||||
|
packCheck=$(dpkg -l ${debPack})
|
||||||
|
if [ "$?" -ne "0" ] ;then
|
||||||
|
apt-get install -y $debPack
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
Check_Sys_Write(){
|
||||||
|
echo "正在检测系统关键目录是否可写"
|
||||||
|
if [ ! -d "/etc/init.d" ];then
|
||||||
|
mkdir -p /etc/init.d
|
||||||
|
fi
|
||||||
|
|
||||||
|
Get_Pack_Manager
|
||||||
|
if [ "$PM" == "yum" ]; then
|
||||||
|
read_dir="/usr/lib/systemd/system/ /etc/init.d/ /var/spool/cron/"
|
||||||
|
else
|
||||||
|
read_dir="/usr/lib/systemd/system/ /etc/init.d/ /var/spool/cron/crontabs/"
|
||||||
|
fi
|
||||||
|
|
||||||
|
touch /tmp/btm_install_test_111.pl
|
||||||
|
for dir in ${read_dir[@]}
|
||||||
|
do
|
||||||
|
if [[ -d "$dir" ]]; then
|
||||||
|
#touch $dir/btm_install_test_111.pl
|
||||||
|
if [[ ! -f "/tmp/btm_install_test_111.pl" ]]; then
|
||||||
|
echo "建立测试 /tmp/btm_install_test_111.pl 文件失败"
|
||||||
|
state=0
|
||||||
|
else
|
||||||
|
\cp /tmp/btm_install_test_111.pl $dir/btm_install_test_111.pl
|
||||||
|
fi
|
||||||
|
state=$(echo $?)
|
||||||
|
if [[ "$state" != "0" ]];then
|
||||||
|
echo -e "\033[31m错误:检测到系统关键目录不可写! $read_dir \033[0m"
|
||||||
|
echo "1、如果安装了[宝塔系统加固],请先临时关闭"
|
||||||
|
echo "2、如果安装了云锁,请临时关闭[系统加固、文件防护]功能"
|
||||||
|
echo "3、如果安装了安全狗,请临时关闭[系统防护]功能"
|
||||||
|
echo "4、如果使用了其它安全软件,请先卸载 "
|
||||||
|
echo -e "5、如果使用了禁止写入命令,请执行命令取消禁止写入:\n chattr -iaR $read_dir "
|
||||||
|
|
||||||
|
if [ $(whoami) != "root" ];then
|
||||||
|
echo -e "6、检测到非root用户安装,请尝试以下解决方案:\n 1.请切换到root用户安装 \n 2.尝试执行以下安装命令:\n sudo bash $0 $@"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo -e "\033[31m解决以上问题后,请尝试重新安装! \033[0m"
|
||||||
|
echo -e "如果无法解决请截图以上报错信息发帖至论坛www.bt.cn/bbs求助"
|
||||||
|
exit 1
|
||||||
|
else
|
||||||
|
rm -f $dir/btm_install_test_111.pl
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
Check_Sys_Packs(){
|
||||||
|
echo "正在检查系统中是否存在必备的依赖包"
|
||||||
|
Packs="wget curl unzip gcc make"
|
||||||
|
if [ -f /usr/bin/which ];then
|
||||||
|
for pack in ${Packs[@]}
|
||||||
|
do
|
||||||
|
check_pack=$(which $pack)
|
||||||
|
#echo $check_pack
|
||||||
|
if [[ "$check_pack" == "" ]]; then
|
||||||
|
echo -e "\033[31mERROR: $pack 命令不存在,尝试以下解决方法:\033[0m"
|
||||||
|
if [ "$PM" == "yum" ]; then
|
||||||
|
echo 1、使用命令重新安装依赖包:yum reinstall -y ${Packs}
|
||||||
|
else
|
||||||
|
echo 1、使用命令重新安装依赖包:apt-get reinstall -y ${Packs}
|
||||||
|
fi
|
||||||
|
echo -e "2、检查系统源是否可用?尝试更换可用的源参考教程:\n https://www.bt.cn/bbs/thread-58005-1-1.html "
|
||||||
|
echo ""
|
||||||
|
echo -e "\033[31m解决以上问题后,请尝试重新安装! \033[0m"
|
||||||
|
echo -e "如果无法解决请截图以上报错信息发帖至论坛www.bt.cn/bbs求助"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
Install_Main(){
|
||||||
|
startTime=`date +%s`
|
||||||
|
Check_Sys_Write "$@"
|
||||||
|
System_Check
|
||||||
|
Get_Pack_Manager
|
||||||
|
get_node_url
|
||||||
|
|
||||||
|
if [ "$PM" == "yum" ]; then
|
||||||
|
Install_RPM_Pack
|
||||||
|
else
|
||||||
|
Install_Deb_Pack
|
||||||
|
fi
|
||||||
|
Check_Sys_Packs
|
||||||
|
Install_Python_Lib
|
||||||
|
Install_Monitor
|
||||||
|
Set_Firewall
|
||||||
|
Get_Ip_Address
|
||||||
|
Service_Add
|
||||||
|
if [ "$re_install" == "2" ]; then
|
||||||
|
Reinstall_Monitor
|
||||||
|
fi
|
||||||
|
Start_Monitor
|
||||||
|
}
|
||||||
|
|
||||||
|
Uninstall_Monitor(){
|
||||||
|
pkill BT-MONITOR
|
||||||
|
/etc/init.d/btm stop
|
||||||
|
|
||||||
|
if [ -f "/www/server/bt-monitor/sqlite-server.sh" ]; then
|
||||||
|
chmod +x /www/server/bt-monitor/sqlite-server.sh
|
||||||
|
/www/server/bt-monitor/sqlite-server.sh stop
|
||||||
|
sleep 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
Service_Del
|
||||||
|
|
||||||
|
rm -rf $monitor_path
|
||||||
|
rm -rf /usr/bin/btm
|
||||||
|
rm -rf /etc/init.d/btm
|
||||||
|
|
||||||
|
echo -e "堡塔云监控主控端卸载成功!"
|
||||||
|
}
|
||||||
|
|
||||||
|
Uninstall_agent(){
|
||||||
|
get_node_url
|
||||||
|
if [ -f "/tmp/btmonitoragent.sh" ];then
|
||||||
|
rm -rf /tmp/btmonitoragent.sh
|
||||||
|
fi
|
||||||
|
curl -o /tmp/btmonitoragent.sh -sSO ${download_Url}/install/btmonitoragent.sh && bash /tmp/btmonitoragent.sh uninstall
|
||||||
|
}
|
||||||
|
|
||||||
|
action="${1}"
|
||||||
|
if [ "$action" == "uninstall" ];then
|
||||||
|
echo -e "----------------------------------------------------"
|
||||||
|
echo -e "\033[33m检测到您正在卸载堡塔云监控系统,请按照选项选择卸载方式!\033[0m"
|
||||||
|
echo -e "1) 备份数据后卸载:保存原有监控配置及数据并卸载堡塔云监控系统"
|
||||||
|
echo -e "2) 完全卸载:清空原有监控配置及数据并卸载堡塔云监控系统"
|
||||||
|
echo -e "----------------------------------------------------"
|
||||||
|
read -p "请输入对应选项[1|2]进行卸载或输入任意内容退出卸载: " yes;
|
||||||
|
if [ "$yes" == "1" ]; then
|
||||||
|
Backup_Monitor
|
||||||
|
echo -e "----------------------------------------------------"
|
||||||
|
echo -e "\033[33m已备份原有监控数据至: ${old_dir}\033[0m"
|
||||||
|
elif [ "$yes" == "2" ]; then
|
||||||
|
echo "正在清空堡塔云监控系统数据..."
|
||||||
|
else
|
||||||
|
echo -e "------------"
|
||||||
|
echo "取消卸载"
|
||||||
|
exit;
|
||||||
|
fi
|
||||||
|
Uninstall_agent
|
||||||
|
Uninstall_Monitor
|
||||||
|
exit 0
|
||||||
|
else
|
||||||
|
echo "
|
||||||
|
+----------------------------------------------------------------------
|
||||||
|
| Bt-Monitor FOR CentOS/Ubuntu/Debian
|
||||||
|
+----------------------------------------------------------------------
|
||||||
|
| Copyright © 2015-2099 BT-SOFT(https://www.bt.cn) All rights reserved.
|
||||||
|
+----------------------------------------------------------------------
|
||||||
|
| The Monitor URL will be https://SERVER_IP:806 when installed.
|
||||||
|
+----------------------------------------------------------------------
|
||||||
|
"
|
||||||
|
while [ "$go" != 'y' ] && [ "$go" != 'n' ]
|
||||||
|
do
|
||||||
|
read -p "Do you want to install Bt-Monitor to the $setup_path directory now?(y/n): " go;
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ "$go" == 'n' ];then
|
||||||
|
exit;
|
||||||
|
fi
|
||||||
|
Install_Main "$@"
|
||||||
|
#curl -o /dev/null -fsSL --connect-time 10 "https://api.bt.cn/bt_monitor/setup_count?cloud_type=1&token=$md5_pl&src_code=$1"
|
||||||
|
#curl -o /dev/null -fsSL --connect-time 10 "https://api.bt.cn/bt_monitor/setup_count?cloud_type=1&token=$md5_pl&src_code=$1&status=1"
|
||||||
|
|
||||||
|
fi
|
||||||
|
echo -e "=================================================================="
|
||||||
|
echo -e "\033[32m堡塔云监控主控端安装完成! Installed successfully!\033[0m"
|
||||||
|
echo -e "=================================================================="
|
||||||
|
echo "外网访问地址: https://${getIpAddress}:${panelPort}${adminpath}"
|
||||||
|
echo "内网访问地址: https://${LOCAL_IP}:${panelPort}${adminpath}"
|
||||||
|
echo -e "username: admin"
|
||||||
|
echo -e "password: $password"
|
||||||
|
echo -e "\033[33mIf you cannot access the Monitor,\033[0m"
|
||||||
|
echo -e "\033[33mrelease the following Monitor port [${panelPort}] in the security group\033[0m"
|
||||||
|
echo -e "\033[33m若无法访问堡塔云监控主控端,请检查防火墙/安全组是否有放行[${panelPort}]端口\033[0m"
|
||||||
|
echo -e "=================================================================="
|
||||||
|
|
||||||
|
endTime=`date +%s`
|
||||||
|
((outTime=($endTime-$startTime)/60))
|
||||||
|
echo -e "Time consumed:\033[32m $outTime \033[0mMinute!"
|
||||||
|
rm -f install_btmonitor.sh
|
||||||
1744
public/install/install_panel.sh
Normal file
1744
public/install/install_panel.sh
Normal file
File diff suppressed because it is too large
Load Diff
@ -9,8 +9,35 @@ export PATH
|
|||||||
export LANG=en_US.UTF-8
|
export LANG=en_US.UTF-8
|
||||||
export LANGUAGE=en_US:en
|
export LANGUAGE=en_US:en
|
||||||
|
|
||||||
|
NODE_FILE_CHECK=$(cat /www/server/panel/data/node.json |grep 125.88.182.172)
|
||||||
|
if [ "${NODE_FILE_CHECK}" ];then
|
||||||
|
rm -f /www/server/panel/data/node.json
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -f "/www/server/panel/install/d_node.pl" ];then
|
||||||
|
LOCAL_DATE=$(date +%Y-%m-%d)
|
||||||
|
FILE_DATE=$(stat /www/server/panel/install/d_node.pl|grep Change|awk '{print $2}')
|
||||||
|
if [ "${LOCAL_DATE}" != "${FILE_DATE}" ];then
|
||||||
|
rm -f /www/server/panel/install/d_node.pl
|
||||||
|
else
|
||||||
|
test_url=$(cat /www/server/panel/install/d_node.pl)
|
||||||
|
HTTP_CHECK=$(curl --connect-timeout 3 -m 3 2>/dev/null -w "%{http_code} %{time_total}" ${test_url}/net_test|xargs|awk '{print $2}')
|
||||||
|
if [ "${HTTP_CHECK}" == "200" ];then
|
||||||
|
NODE_URL=$test_url
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
get_node_url(){
|
get_node_url(){
|
||||||
nodes=(http://dg2.bt.cn http://dg1.bt.cn http://36.133.1.8:5880 http://123.129.198.197 http://38.34.185.130 http://116.213.43.206:5880 http://128.1.164.196);
|
nodes=(https://dg2.bt.cn https://download.bt.cn https://ctcc1-node.bt.cn https://cmcc1-node.bt.cn https://ctcc2-node.bt.cn https://hk1-node.bt.cn https://na1-node.bt.cn https://jp1-node.bt.cn https://cf1-node.aapanel.com);
|
||||||
|
|
||||||
|
if [ -f "/www/server/panel/data/domestic_ip.pl" ];then
|
||||||
|
nodes=(https://dg2.bt.cn https://download.bt.cn https://ctcc1-node.bt.cn https://cmcc1-node.bt.cn https://ctcc2-node.bt.cn https://hk1-node.bt.cn);
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -f "/www/server/panel/data/foreign_ip.pl" ];then
|
||||||
|
nodes=(https://cf1-node.aapanel.com https://dg2.bt.cn https://na1-node.bt.cn https://jp1-node.bt.cn https://download.bt.cn https://ctcc1-node.bt.cn https://ctcc2-node.bt.cn https://hk1-node.bt.cn);
|
||||||
|
fi
|
||||||
|
|
||||||
if [ "$1" ];then
|
if [ "$1" ];then
|
||||||
nodes=($(echo ${nodes[*]}|sed "s#${1}##"))
|
nodes=($(echo ${nodes[*]}|sed "s#${1}##"))
|
||||||
@ -24,12 +51,16 @@ get_node_url(){
|
|||||||
touch $tmp_file2
|
touch $tmp_file2
|
||||||
for node in ${nodes[@]};
|
for node in ${nodes[@]};
|
||||||
do
|
do
|
||||||
NODE_CHECK=$(curl --connect-timeout 3 -m 3 2>/dev/null -w "%{http_code} %{time_total}" ${node}/net_test|xargs)
|
if [ "${node}" == "https://cf1-node.aapanel.com" ];then
|
||||||
|
NODE_CHECK=$(curl --connect-timeout 3 -m 3 2>/dev/null -w "%{http_code} %{time_total}" ${node}/1net_test|xargs)
|
||||||
|
else
|
||||||
|
NODE_CHECK=$(curl --connect-timeout 3 -m 3 2>/dev/null -w "%{http_code} %{time_total}" ${node}/net_test|xargs)
|
||||||
|
fi
|
||||||
RES=$(echo ${NODE_CHECK}|awk '{print $1}')
|
RES=$(echo ${NODE_CHECK}|awk '{print $1}')
|
||||||
NODE_STATUS=$(echo ${NODE_CHECK}|awk '{print $2}')
|
NODE_STATUS=$(echo ${NODE_CHECK}|awk '{print $2}')
|
||||||
TIME_TOTAL=$(echo ${NODE_CHECK}|awk '{print $3 * 1000 - 500 }'|cut -d '.' -f 1)
|
TIME_TOTAL=$(echo ${NODE_CHECK}|awk '{print $3 * 1000 - 500 }'|cut -d '.' -f 1)
|
||||||
if [ "${NODE_STATUS}" == "200" ];then
|
if [ "${NODE_STATUS}" == "200" ];then
|
||||||
if [ $TIME_TOTAL -lt 100 ];then
|
if [ $TIME_TOTAL -lt 300 ];then
|
||||||
if [ $RES -ge 1500 ];then
|
if [ $RES -ge 1500 ];then
|
||||||
echo "$RES $node" >> $tmp_file1
|
echo "$RES $node" >> $tmp_file1
|
||||||
fi
|
fi
|
||||||
@ -40,8 +71,8 @@ get_node_url(){
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
i=$(($i+1))
|
i=$(($i+1))
|
||||||
if [ $TIME_TOTAL -lt 100 ];then
|
if [ $TIME_TOTAL -lt 300 ];then
|
||||||
if [ $RES -ge 3000 ];then
|
if [ $RES -ge 2390 ];then
|
||||||
break;
|
break;
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
@ -52,7 +83,7 @@ get_node_url(){
|
|||||||
if [ -z "$NODE_URL" ];then
|
if [ -z "$NODE_URL" ];then
|
||||||
NODE_URL=$(cat $tmp_file2|sort -g -t " " -k 1|head -n 1|awk '{print $2}')
|
NODE_URL=$(cat $tmp_file2|sort -g -t " " -k 1|head -n 1|awk '{print $2}')
|
||||||
if [ -z "$NODE_URL" ];then
|
if [ -z "$NODE_URL" ];then
|
||||||
NODE_URL='http://download.bt.cn';
|
NODE_URL='https://download.bt.cn';
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
rm -f $tmp_file1
|
rm -f $tmp_file1
|
||||||
@ -108,7 +139,7 @@ send_check(){
|
|||||||
chmod +x /etc/init.d/bt
|
chmod +x /etc/init.d/bt
|
||||||
p_path2=/www/server/panel/class/common.py
|
p_path2=/www/server/panel/class/common.py
|
||||||
p_version=$(cat $p_path2|grep "version = "|awk '{print $3}'|tr -cd [0-9.])
|
p_version=$(cat $p_path2|grep "version = "|awk '{print $3}'|tr -cd [0-9.])
|
||||||
curl -sS --connect-timeout 3 -m 60 http://www.bt.cn/api/panel/notpro?version=$p_version
|
curl -sS --connect-timeout 3 -m 60 http://www.example.com/api/panel/notpro?version=$p_version
|
||||||
NODE_URL=""
|
NODE_URL=""
|
||||||
exit 0;
|
exit 0;
|
||||||
}
|
}
|
||||||
@ -147,3 +178,4 @@ if [ ! $NODE_URL ];then
|
|||||||
get_node_url
|
get_node_url
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
BIN
public/install/src/panel_7_en.zip
Normal file
BIN
public/install/src/panel_7_en.zip
Normal file
Binary file not shown.
BIN
public/install/update/LinuxPanel-11.5.0.zip
Normal file
BIN
public/install/update/LinuxPanel-11.5.0.zip
Normal file
Binary file not shown.
Binary file not shown.
BIN
public/install/update/LinuxPanel_EN-7.0.25.zip
Normal file
BIN
public/install/update/LinuxPanel_EN-7.0.25.zip
Normal file
Binary file not shown.
148
public/install/update/update_prep_script.sh
Normal file
148
public/install/update/update_prep_script.sh
Normal file
@ -0,0 +1,148 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
#===============================================================================
|
||||||
|
# 宝塔面板更新预准备脚本
|
||||||
|
# 功能:在面板更新时,提前准备,避免面板更新失败
|
||||||
|
# 说明:接收两个参数:1.更新的面板版本号 2.更新的版本是否为稳定版 3.执行时机(prepare, after)
|
||||||
|
# prepare: 在下载面板文件之前就运行的内容
|
||||||
|
# after: 在替换文件之后,运行重启之前执行的内容
|
||||||
|
# 支持:CentOS/RHEL、Ubuntu、Debian系统
|
||||||
|
#===============================================================================
|
||||||
|
|
||||||
|
UPDATE_VERSION="" # 版本号, 形如: 11.2.3
|
||||||
|
UPDATE_VER_MAJOR="" # 主版本号 -> 11
|
||||||
|
UPDATE_VER_MINOR="" # 次版本号 -> 2
|
||||||
|
UPDATE_VER_MICRO="" # 小版本号 -> 3
|
||||||
|
IS_STABLE=false # 默认不是稳定版而是正式版本
|
||||||
|
OPPORTUNITY="prepare"
|
||||||
|
|
||||||
|
PANEL_PATH="/www/server/panel"
|
||||||
|
|
||||||
|
# 输出成功信息, 必须输出 "BT-Panel Update Ready" 才证明预处理成功
|
||||||
|
function success() {
|
||||||
|
local message=$1
|
||||||
|
if [ -n "$message" ]; then
|
||||||
|
echo "$message"
|
||||||
|
fi
|
||||||
|
echo "BT-Panel Update Ready"
|
||||||
|
}
|
||||||
|
|
||||||
|
# 获取当前版本号
|
||||||
|
function get_now_version() {
|
||||||
|
local common_file="$PANEL_PATH/class/common.py"
|
||||||
|
if [ ! -f "$common_file" ]; then
|
||||||
|
echo "" # 文件不存在时返回空字符串
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
# 形如:g.version = '11.2.0'
|
||||||
|
local version_str=$(grep -E '^\s+g.version\s*=\s*.*$' "$PANEL_PATH/class/common.py" | cut -d "=" -f2 )
|
||||||
|
# 形如:'11.2.0'
|
||||||
|
local version=$(echo "$version_str" | sed -n "s/.*['\"]\(.*\)['\"].*/\1/p" )
|
||||||
|
echo "$version"
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
# 解析参数
|
||||||
|
function parse_arguments() {
|
||||||
|
if [ -z "$1" ]; then
|
||||||
|
echo "Error: 请指定接下来的更新版本号"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if echo "$1" | grep -qE '^[0-9]+\.[0-9]+\.[0-9]+$'; then
|
||||||
|
:
|
||||||
|
else
|
||||||
|
echo "Error: 请指定正确的版本号"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
UPDATE_VERSION=$1
|
||||||
|
UPDATE_VER_MAJOR=$(echo $UPDATE_VERSION | cut -d. -f1)
|
||||||
|
UPDATE_VER_MINOR=$(echo $UPDATE_VERSION | cut -d. -f2)
|
||||||
|
UPDATE_VER_MICRO=$(echo $UPDATE_VERSION | cut -d. -f3)
|
||||||
|
case "$2" in
|
||||||
|
1|True|true) # 稳定版
|
||||||
|
IS_STABLE=true
|
||||||
|
;;
|
||||||
|
0|False|false) # 非稳定版
|
||||||
|
IS_STABLE=false
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
IS_STABLE=false
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
case "$3" in
|
||||||
|
prepare)
|
||||||
|
OPPORTUNITY="prepare"
|
||||||
|
;;
|
||||||
|
after)
|
||||||
|
OPPORTUNITY="after"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
OPPORTUNITY="prepare"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
# 默认处理,什么都不做
|
||||||
|
function nothing_do() {
|
||||||
|
local version=$1
|
||||||
|
# 输出成功信息
|
||||||
|
success "已完成[BT-Panel-$version]处理"
|
||||||
|
}
|
||||||
|
|
||||||
|
function replace_bt_command() {
|
||||||
|
local init_path="${PANEL_PATH}/init.sh"
|
||||||
|
if [ -f "$init_path" ]; then
|
||||||
|
\cp -a "$init_path" /etc/init.d/bt
|
||||||
|
chmod +x /etc/init.d/bt
|
||||||
|
else
|
||||||
|
echo "Error: $init_path 文件不存在"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
function prepare_main() {
|
||||||
|
echo "开始处理预更新..."
|
||||||
|
local now_version=$(get_now_version)
|
||||||
|
if [ $? -eq 0 ]; then
|
||||||
|
echo "当前版本:$now_version, 目标版本:$UPDATE_VERSION"
|
||||||
|
else
|
||||||
|
echo "获取当前版本失败"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
case "$UPDATE_VER_MAJOR.$UPDATE_VER_MINOR.$UPDATE_VER_MICRO" in
|
||||||
|
11.3.*)
|
||||||
|
nothing_do $UPDATE_VERSION
|
||||||
|
;;
|
||||||
|
* )
|
||||||
|
nothing_do $UPDATE_VERSION
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
function after_main() {
|
||||||
|
echo "启动预检测..."
|
||||||
|
case "$UPDATE_VER_MAJOR.$UPDATE_VER_MINOR.$UPDATE_VER_MICRO" in
|
||||||
|
11.3.*)
|
||||||
|
replace_bt_command
|
||||||
|
success "已完成[BT-Panel-$UPDATE_VERSION]启动检查处理"
|
||||||
|
;;
|
||||||
|
* )
|
||||||
|
nothing_do $UPDATE_VERSION
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
# 主函数
|
||||||
|
function main() {
|
||||||
|
if [ "$OPPORTUNITY" = "prepare" ]; then
|
||||||
|
prepare_main
|
||||||
|
elif [ "$OPPORTUNITY" = "after" ]; then
|
||||||
|
after_main
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# 主函数入口
|
||||||
|
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
|
||||||
|
parse_arguments $@
|
||||||
|
main
|
||||||
|
fi
|
||||||
@ -12,23 +12,24 @@ if [ ! -d /www/server/panel/BTPanel ];then
|
|||||||
exit 0;
|
exit 0;
|
||||||
fi
|
fi
|
||||||
|
|
||||||
public_file=/www/server/panel/install/public.sh
|
if [ ! -f "/www/server/panel/pyenv/bin/python3" ];then
|
||||||
publicFileMd5=$(md5sum ${public_file} 2>/dev/null|awk '{print $1}')
|
echo "============================================="
|
||||||
md5check="f6ccaaec227577b87a22bf162004667b"
|
echo "错误, 当前面板过旧/py-2.7/无pyenv环境,无法升级至最新版面板"
|
||||||
if [ "${publicFileMd5}" != "${md5check}" ]; then
|
echo "请截图发帖至论坛www.bt.cn/bbs求助"
|
||||||
wget -O Tpublic.sh $Btapi_Url/install/public.sh -T 20;
|
exit 0;
|
||||||
publicFileMd5=$(md5sum Tpublic.sh 2>/dev/null|awk '{print $1}')
|
|
||||||
if [ "${publicFileMd5}" == "${md5check}" ]; then
|
|
||||||
\cp -rpa Tpublic.sh $public_file
|
|
||||||
fi
|
|
||||||
rm -f Tpublic.sh
|
|
||||||
fi
|
fi
|
||||||
. $public_file
|
|
||||||
|
|
||||||
Centos8Check=$(cat /etc/redhat-release | grep ' 8.' | grep -iE 'centos|Red Hat')
|
if [ -f "/etc/redhat-release" ];then
|
||||||
if [ "${Centos8Check}" ];then
|
Centos6Check=$(cat /etc/redhat-release | grep ' 6.' | grep -iE 'centos|Red Hat')
|
||||||
if [ ! -f "/usr/bin/python" ] && [ -f "/usr/bin/python3" ] && [ ! -d "/www/server/panel/pyenv" ]; then
|
if [ "${Centos6Check}" ];then
|
||||||
ln -sf /usr/bin/python3 /usr/bin/python
|
echo "Centos6不支持升级宝塔面板,建议备份数据重装更换Centos7/8安装宝塔面板"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
Centos8Check=$(cat /etc/redhat-release | grep ' 8.' | grep -iE 'centos|Red Hat')
|
||||||
|
if [ "${Centos8Check}" ];then
|
||||||
|
if [ ! -f "/usr/bin/python" ] && [ -f "/usr/bin/python3" ] && [ ! -d "/www/server/panel/pyenv" ]; then
|
||||||
|
ln -sf /usr/bin/python3 /usr/bin/python
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@ -38,22 +39,87 @@ if [ -f $env_path ];then
|
|||||||
mypip="/www/server/panel/pyenv/bin/pip"
|
mypip="/www/server/panel/pyenv/bin/pip"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
download_Url=$NODE_URL
|
if [ -f "/www/server/panel/data/down_url.pl" ];then
|
||||||
|
D_NODE_URL=$(cat /www/server/panel/data/down_url.pl|grep bt.cn)
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "${D_NODE_URL}" ];then
|
||||||
|
D_NODE_URL="download.bt.cn"
|
||||||
|
fi
|
||||||
|
|
||||||
|
download_Url=$D_NODE_URL
|
||||||
|
|
||||||
|
|
||||||
|
Set_Centos7_Repo(){
|
||||||
|
if [ -f "/etc/yum.repos.d/docker-ce.repo" ];then
|
||||||
|
mv /etc/yum.repos.d/docker-ce.repo /etc/yum.repos.d/docker-ce.repo_backup
|
||||||
|
fi
|
||||||
|
MIRROR_CHECK=$(cat /etc/yum.repos.d/CentOS-Base.repo |grep "[^#]mirror.centos.org")
|
||||||
|
if [ "${MIRROR_CHECK}" ] && [ "${is64bit}" == "64" ];then
|
||||||
|
\cp -rpa /etc/yum.repos.d/ /etc/yumBak
|
||||||
|
sed -i 's/mirrorlist/#mirrorlist/g' /etc/yum.repos.d/CentOS-*.repo
|
||||||
|
sed -i 's|#baseurl=http://mirror.centos.org|baseurl=http://vault.epel.cloud|g' /etc/yum.repos.d/CentOS-*.repo
|
||||||
|
fi
|
||||||
|
|
||||||
|
TSU_MIRROR_CHECK=$(cat /etc/yum.repos.d/CentOS-Base.repo |grep "tuna.tsinghua.edu.cn")
|
||||||
|
if [ "${TSU_MIRROR_CHECK}" ];then
|
||||||
|
\cp -rpa /etc/yum.repos.d/ /etc/yumBak
|
||||||
|
sed -i 's/mirrorlist/#mirrorlist/g' /etc/yum.repos.d/CentOS-*.repo
|
||||||
|
sed -i 's|#baseurl=https://mirrors.tuna.tsinghua.edu.cn|baseurl=http://vault.epel.cloud|g' /etc/yum.repos.d/CentOS-*.repo
|
||||||
|
sed -i 's|#baseurl=http://mirrors.tuna.tsinghua.edu.cn|baseurl=http://vault.epel.cloud|g' /etc/yum.repos.d/CentOS-*.repo
|
||||||
|
fi
|
||||||
|
|
||||||
|
ALI_CLOUD_CHECK=$(grep Alibaba /etc/motd)
|
||||||
|
Tencent_Cloud=$(cat /etc/hostname |grep -E VM-[0-9]+-[0-9]+)
|
||||||
|
if [ "${ALI_CLOUD_CHECK}" ] || [ "${Tencent_Cloud}" ];then
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
yum install tree -y
|
||||||
|
if [ "$?" != "0" ] ;then
|
||||||
|
TAR_CHECK=$(which tree)
|
||||||
|
if [ "$?" == "0" ] ;then
|
||||||
|
\cp -rpa /etc/yum.repos.d/ /etc/yumBak
|
||||||
|
if [ -z "${download_Url}" ];then
|
||||||
|
download_Url="http://download.bt.cn"
|
||||||
|
fi
|
||||||
|
curl -Ss --connect-timeout 5 -m 60 -O ${download_Url}/src/el7repo.tar.gz
|
||||||
|
rm -f /etc/yum.repos.d/*.repo
|
||||||
|
tar -xvzf el7repo.tar.gz -C /etc/yum.repos.d/
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
yum install tree -y
|
||||||
|
if [ "$?" != "0" ] ;then
|
||||||
|
sed -i "s/vault.epel.cloud/mirrors.cloud.tencent.com/g" /etc/yum.repos.d/*.repo
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
if [ -f "/etc/redhat-release" ];then
|
||||||
|
Centos7Check=$(cat /etc/redhat-release | grep ' 7.' | grep -iE 'centos|Red Hat')
|
||||||
|
if [ "${Centos7Check}" ];then
|
||||||
|
Set_Centos7_Repo
|
||||||
|
fi
|
||||||
|
fi
|
||||||
setup_path=/www
|
setup_path=/www
|
||||||
version=$(curl -Ss --connect-timeout 5 -m 2 $Btapi_Url/api/panel/get_version)
|
version=$(curl -Ss --connect-timeout 5 -m 2 $Btapi_Url/api/panel/get_version)
|
||||||
if [ "$version" = '' ];then
|
if [ -z "$version" ];then
|
||||||
version='7.9.6'
|
version='9.5.0'
|
||||||
fi
|
fi
|
||||||
armCheck=$(uname -m|grep arm)
|
armCheck=$(uname -m|grep arm)
|
||||||
if [ "${armCheck}" ];then
|
if [ "${armCheck}" ];then
|
||||||
version='7.7.0'
|
version='7.7.0'
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if [ "$1" ];then
|
||||||
|
version=$1
|
||||||
|
fi
|
||||||
wget -T 5 -O /tmp/panel.zip $Btapi_Url/install/update/LinuxPanel-${version}.zip
|
wget -T 5 -O /tmp/panel.zip $Btapi_Url/install/update/LinuxPanel-${version}.zip
|
||||||
dsize=$(du -b /tmp/panel.zip|awk '{print $1}')
|
dsize=$(du -b /tmp/panel.zip|awk '{print $1}')
|
||||||
if [ $dsize -lt 10240 ];then
|
if [ $dsize -lt 10240 ];then
|
||||||
echo "获取更新包失败,请稍后更新或联系宝塔运维"
|
echo "获取更新包失败,请稍后更新或联系宝塔运维"
|
||||||
exit;
|
exit;
|
||||||
fi
|
fi
|
||||||
|
|
||||||
unzip -o /tmp/panel.zip -d $setup_path/server/ > /dev/null
|
unzip -o /tmp/panel.zip -d $setup_path/server/ > /dev/null
|
||||||
rm -f /tmp/panel.zip
|
rm -f /tmp/panel.zip
|
||||||
cd $setup_path/server/panel/
|
cd $setup_path/server/panel/
|
||||||
@ -63,16 +129,52 @@ if [ "${check_bt}" = "" ];then
|
|||||||
wget -O /etc/init.d/bt $download_Url/install/src/bt7.init -T 20
|
wget -O /etc/init.d/bt $download_Url/install/src/bt7.init -T 20
|
||||||
chmod +x /etc/init.d/bt
|
chmod +x /etc/init.d/bt
|
||||||
fi
|
fi
|
||||||
|
echo "=============================================================="
|
||||||
|
echo "正在修复面板依赖问题"
|
||||||
rm -f /www/server/panel/*.pyc
|
rm -f /www/server/panel/*.pyc
|
||||||
rm -f /www/server/panel/class/*.pyc
|
rm -f /www/server/panel/class/*.pyc
|
||||||
#pip install flask_sqlalchemy
|
#pip install flask_sqlalchemy
|
||||||
#pip install itsdangerous==0.24
|
#pip install itsdangerous==0.24
|
||||||
|
|
||||||
pip_list=$($mypip list)
|
if [ -f "/www/server/panel/pyenv/bin/pip3" ];then
|
||||||
request_v=$(echo "$pip_list"|grep requests)
|
btpip_path="/www/server/panel/pyenv/bin/pip3"
|
||||||
if [ "$request_v" = "" ];then
|
FlaskV=$($btpip_path list 2>/dev/null|grep "Flask " |awk '{print $2}'|cut -f 1 -d .)
|
||||||
$mypip install requests
|
piplist_count=$($btpip_path list 2>/dev/null|wc -l)
|
||||||
|
if [ "${FlaskV}" -le "2" ] && [ "${piplist_count}" -le "118" ];then
|
||||||
|
echo "检测到面板运行环境过老,正常尝试修复面板依赖"
|
||||||
|
pyenv_path="/www/server/panel"
|
||||||
|
wget -O $pyenv_path/pyenv/pip.txt $download_Url/install/pyenv/pip-3.7.16.txt -T 5
|
||||||
|
$pyenv_path/pyenv/bin/pip install -U pip
|
||||||
|
$pyenv_path/pyenv/bin/pip install -U setuptools==65.5.0
|
||||||
|
$pyenv_path/pyenv/bin/pip install -U wheel==0.34.2
|
||||||
|
$pyenv_path/pyenv/bin/pip install -r $pyenv_path/pyenv/pip.txt
|
||||||
|
echo "依赖修复完成,如面板仍无法正常访问,请联系宝塔官方人员进行求助"
|
||||||
|
fi
|
||||||
|
|
||||||
|
#wget -O pip-packs.txt $download_Url/install/pyenv/pip-packs.txt
|
||||||
|
#PIP_PACKS=$(cat pip-packs.txt)
|
||||||
|
#for P_PACK in ${PIP_PACKS};
|
||||||
|
#do
|
||||||
|
# btpip show ${P_PACK} > /dev/null 2>&1
|
||||||
|
# if [ "$?" == "1" ];then
|
||||||
|
# btpip install ${P_PACK}
|
||||||
|
# fi
|
||||||
|
#done
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
pip_list=$($mypip list 2>&1)
|
||||||
|
request_v=$(btpip list 2>/dev/null|grep "requests "|awk '{print $2}'|cut -d '.' -f 2)
|
||||||
|
if [ "$request_v" = "" ] || [ "${request_v}" -gt "28" ];then
|
||||||
|
$mypip install requests==2.27.1
|
||||||
|
$mypip install chardet==4.0.0
|
||||||
|
fi
|
||||||
|
|
||||||
|
NATSORT_C=$(echo $pip_list|grep natsort)
|
||||||
|
if [ -z "${NATSORT_C}" ];then
|
||||||
|
btpip install natsort
|
||||||
|
fi
|
||||||
|
|
||||||
openssl_v=$(echo "$pip_list"|grep pyOpenSSL)
|
openssl_v=$(echo "$pip_list"|grep pyOpenSSL)
|
||||||
if [ "$openssl_v" = "" ];then
|
if [ "$openssl_v" = "" ];then
|
||||||
$mypip install pyOpenSSL
|
$mypip install pyOpenSSL
|
||||||
@ -87,12 +189,68 @@ pymysql=$(echo "$pip_list"|grep pymysql)
|
|||||||
if [ "$pymysql" = "" ];then
|
if [ "$pymysql" = "" ];then
|
||||||
$mypip install pymysql
|
$mypip install pymysql
|
||||||
fi
|
fi
|
||||||
|
GEVENT_V=$(btpip list 2> /dev/null|grep "gevent "|awk '{print $2}'|cut -f 1 -d '.')
|
||||||
|
if [ "${GEVENT_V}" -le "1" ];then
|
||||||
|
/www/server/panel/pyenv/bin/pip3 install -I gevent
|
||||||
|
fi
|
||||||
|
|
||||||
|
BROTLI_C=$(btpip list 2> /dev/null |grep Brotli)
|
||||||
|
if [ -z "$BROTLI_C" ]; then
|
||||||
|
btpip install brotli
|
||||||
|
fi
|
||||||
|
|
||||||
|
PYMYSQL_C=$(btpip list 2> /dev/null |grep PyMySQL)
|
||||||
|
if [ -z "$PYMYSQL_C" ]; then
|
||||||
|
btpip install PyMySQL
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
PY_CRPYT=$(btpip list 2> /dev/null |grep cryptography|awk '{print $2}'|cut -f 1 -d '.')
|
||||||
|
if [ "${PY_CRPYT}" -le "10" ];then
|
||||||
|
btpip install pyOpenSSL==24.1.0
|
||||||
|
btpip install cryptography==42.0.5
|
||||||
|
fi
|
||||||
|
|
||||||
|
PYMYSQL_SSL_CHECK=$(btpython -c "import pymysql" 2>&1|grep "AttributeError: module 'cryptography.hazmat.bindings._rust.openssl'")
|
||||||
|
if [ "${PYMYSQL_SSL_CHECK}" ];then
|
||||||
|
btpip uninstall pyopenssl cryptography -y
|
||||||
|
btpip install pyopenssl cryptography
|
||||||
|
fi
|
||||||
|
|
||||||
|
btpip uninstall enum34 -y
|
||||||
|
|
||||||
|
btpip install asn1crypto==1.5.1 cbor2==5.4.6
|
||||||
|
|
||||||
|
GEOIP_C=$(echo $pip_list|grep geoip2)
|
||||||
|
if [ -z "${GEOIP_C}" ];then
|
||||||
|
btpip install geoip2==4.7.0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# PANDAS_C=$(echo $pip_list|grep pandas)
|
||||||
|
# if [ -z "${PANDAS_C}" ];then
|
||||||
|
# btpip install pandas
|
||||||
|
# fi
|
||||||
|
|
||||||
pymysql=$(echo "$pip_list"|grep pycryptodome)
|
pymysql=$(echo "$pip_list"|grep pycryptodome)
|
||||||
if [ "$pymysql" = "" ];then
|
if [ "$pymysql" = "" ];then
|
||||||
$mypip install pycryptodome
|
$mypip install pycryptodome
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
echo "修复面板依赖完成!"
|
||||||
|
echo "==========================================="
|
||||||
|
|
||||||
|
echo "安装基础网站流量统计程序..."
|
||||||
|
wget -O site_new_total.sh ${download_Url}/site_total/install.sh &> /dev/null
|
||||||
|
bash site_new_total.sh &> /dev/null
|
||||||
|
rm -f site_new_total.sh
|
||||||
|
echo "安装基础网站流量统计程序完成"
|
||||||
|
|
||||||
|
|
||||||
|
RE_UPDATE=$(cat /www/server/panel/data/db/update)
|
||||||
|
if [ "$RE_UPDATE" -ge "4" ];then
|
||||||
|
echo "2" > /www/server/panel/data/db/update
|
||||||
|
fi
|
||||||
|
|
||||||
#psutil=$(echo "$pip_list"|grep psutil|awk '{print $2}'|grep '5.7.')
|
#psutil=$(echo "$pip_list"|grep psutil|awk '{print $2}'|grep '5.7.')
|
||||||
#if [ "$psutil" = "" ];then
|
#if [ "$psutil" = "" ];then
|
||||||
# $mypip install -U psutil
|
# $mypip install -U psutil
|
||||||
@ -106,8 +264,27 @@ if [ ! -f /www/server/panel/data/not_workorder.pl ]; then
|
|||||||
echo "True" > /www/server/panel/data/not_workorder.pl
|
echo "True" > /www/server/panel/data/not_workorder.pl
|
||||||
fi
|
fi
|
||||||
if [ ! -f /www/server/panel/data/userInfo.json ]; then
|
if [ ! -f /www/server/panel/data/userInfo.json ]; then
|
||||||
echo "{\"uid\":1,\"username\":\"Administrator\",\"address\":\"127.0.0.1\",\"serverid\":\"1\",\"access_key\":\"test\",\"secret_key\":\"123456\",\"ukey\":\"123456\",\"state\":1}" > /www/server/panel/data/userInfo.json
|
echo "{\"uid\":1,\"username\":\"Administrator\",\"address\":\"127.0.0.1\",\"access_key\":\"test\",\"secret_key\":\"123456\",\"ukey\":\"123456\",\"state\":1}" > /www/server/panel/data/userInfo.json
|
||||||
fi
|
fi
|
||||||
|
if [ ! -f /www/server/panel/data/panel_nps.pl ]; then
|
||||||
|
echo "" > /www/server/panel/data/panel_nps.pl
|
||||||
|
fi
|
||||||
|
if [ ! -f /www/server/panel/data/btwaf_nps.pl ]; then
|
||||||
|
echo "" > /www/server/panel/data/btwaf_nps.pl
|
||||||
|
fi
|
||||||
|
if [ ! -f /www/server/panel/data/tamper_proof_nps.pl ]; then
|
||||||
|
echo "" > /www/server/panel/data/tamper_proof_nps.pl
|
||||||
|
fi
|
||||||
|
if [ ! -f /www/server/panel/data/total_nps.pl ]; then
|
||||||
|
echo "" > /www/server/panel/data/total_nps.pl
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "==========================================="
|
||||||
|
echo "正在更新面板文件..............."
|
||||||
|
sleep 1
|
||||||
|
echo "更新完成!"
|
||||||
|
echo "如在终端中执行此命令,请手动刷新面板页面"
|
||||||
|
echo "==========================================="
|
||||||
|
|
||||||
chattr -i /etc/init.d/bt
|
chattr -i /etc/init.d/bt
|
||||||
chmod +x /etc/init.d/bt
|
chmod +x /etc/init.d/bt
|
||||||
|
|||||||
1021
public/install/update_7.x_en.sh
Normal file
1021
public/install/update_7.x_en.sh
Normal file
File diff suppressed because it is too large
Load Diff
452
public/install/update_btmonitor.sh
Normal file
452
public/install/update_btmonitor.sh
Normal file
@ -0,0 +1,452 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
|
||||||
|
export PATH
|
||||||
|
LANG=en_US.UTF-8
|
||||||
|
|
||||||
|
Btapi_Url='http://www.example.com'
|
||||||
|
|
||||||
|
monitor_path="/www/server/bt-monitor"
|
||||||
|
run_bin="/www/server/bt-monitor/BT-MONITOR"
|
||||||
|
is64bit=$(getconf LONG_BIT)
|
||||||
|
|
||||||
|
if [ ! -d $monitor_path ]; then
|
||||||
|
echo "没有安装云监控,请执行下面的命令安装堡塔云监控!"
|
||||||
|
echo "curl -sSO ${Btapi_Url}/install/install_btmonitor.sh && bash install_btmonitor.sh"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
cd ~
|
||||||
|
setup_path="/www"
|
||||||
|
|
||||||
|
if [ -f "/etc/init.d/btm" ]; then
|
||||||
|
/etc/init.d/btm stop
|
||||||
|
sleep 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -f "/www/server/bt-monitor/sqlite-server.sh" ]; then
|
||||||
|
chmod +x /www/server/bt-monitor/sqlite-server.sh
|
||||||
|
/www/server/bt-monitor/sqlite-server.sh stop
|
||||||
|
sleep 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
get_node_url(){
|
||||||
|
if [ ! -f /bin/curl ];then
|
||||||
|
if [ "${PM}" = "yum" ]; then
|
||||||
|
yum install curl -y
|
||||||
|
elif [ "${PM}" = "apt-get" ]; then
|
||||||
|
apt-get install curl -y
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -f "/www/node.pl" ];then
|
||||||
|
download_Url=$(cat /www/node.pl)
|
||||||
|
echo "Download node: $download_Url";
|
||||||
|
echo '---------------------------------------------';
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo '---------------------------------------------';
|
||||||
|
echo "Selected download node...";
|
||||||
|
# nodes=(http://dg2.bt.cn http://dg1.bt.cn http://125.90.93.52:5880 http://36.133.1.8:5880 http://123.129.198.197 http://38.34.185.130 http://116.213.43.206:5880 http://128.1.164.196);
|
||||||
|
#nodes=(http://dg2.bt.cn http://dg1.bt.cn http://125.90.93.52:5880 http://36.133.1.8:5880 http://123.129.198.197 http://116.213.43.206:5880);
|
||||||
|
nodes=(https://dg2.bt.cn https://dg1.bt.cn https://download.bt.cn);
|
||||||
|
tmp_file1=/dev/shm/net_test1.pl
|
||||||
|
tmp_file2=/dev/shm/net_test2.pl
|
||||||
|
[ -f "${tmp_file1}" ] && rm -f ${tmp_file1}
|
||||||
|
[ -f "${tmp_file2}" ] && rm -f ${tmp_file2}
|
||||||
|
touch $tmp_file1
|
||||||
|
touch $tmp_file2
|
||||||
|
for node in ${nodes[@]};
|
||||||
|
do
|
||||||
|
NODE_CHECK=$(curl --connect-timeout 3 -m 3 2>/dev/null -w "%{http_code} %{time_total}" ${node}/net_test|xargs)
|
||||||
|
RES=$(echo ${NODE_CHECK}|awk '{print $1}')
|
||||||
|
NODE_STATUS=$(echo ${NODE_CHECK}|awk '{print $2}')
|
||||||
|
TIME_TOTAL=$(echo ${NODE_CHECK}|awk '{print $3 * 1000 - 500 }'|cut -d '.' -f 1)
|
||||||
|
if [ "${NODE_STATUS}" == "200" ];then
|
||||||
|
if [ $TIME_TOTAL -lt 100 ];then
|
||||||
|
if [ $RES -ge 1500 ];then
|
||||||
|
echo "$RES $node" >> $tmp_file1
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
if [ $RES -ge 1500 ];then
|
||||||
|
echo "$TIME_TOTAL $node" >> $tmp_file2
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
i=$(($i+1))
|
||||||
|
if [ $TIME_TOTAL -lt 100 ];then
|
||||||
|
if [ $RES -ge 3000 ];then
|
||||||
|
break;
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
NODE_URL=$(cat $tmp_file1|sort -r -g -t " " -k 1|head -n 1|awk '{print $2}')
|
||||||
|
if [ -z "$NODE_URL" ];then
|
||||||
|
NODE_URL=$(cat $tmp_file2|sort -g -t " " -k 1|head -n 1|awk '{print $2}')
|
||||||
|
if [ -z "$NODE_URL" ];then
|
||||||
|
NODE_URL='https://download.bt.cn';
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
rm -f $tmp_file1
|
||||||
|
rm -f $tmp_file2
|
||||||
|
download_Url=$NODE_URL
|
||||||
|
echo "Download node: $download_Url";
|
||||||
|
echo '---------------------------------------------';
|
||||||
|
}
|
||||||
|
|
||||||
|
Get_Versions(){
|
||||||
|
redhat_version_file="/etc/redhat-release"
|
||||||
|
deb_version_file="/etc/issue"
|
||||||
|
if [ -f $redhat_version_file ];then
|
||||||
|
os_type='el'
|
||||||
|
is_aliyunos=$(cat $redhat_version_file|grep Aliyun)
|
||||||
|
if [ "$is_aliyunos" != "" ];then
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
os_version=$(cat $redhat_version_file|grep CentOS|grep -Eo '([0-9]+\.)+[0-9]+'|grep -Eo '^[0-9]')
|
||||||
|
if [ "${os_version}" = "5" ];then
|
||||||
|
os_version=""
|
||||||
|
fi
|
||||||
|
if [ -z "${os_version}" ];then
|
||||||
|
os_version=$(cat /etc/redhat-release |grep Stream|grep -oE 8)
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
os_type='ubuntu'
|
||||||
|
os_version=$(cat $deb_version_file|grep Ubuntu|grep -Eo '([0-9]+\.)+[0-9]+'|grep -Eo '^[0-9]+')
|
||||||
|
if [ "${os_version}" = "" ];then
|
||||||
|
os_type='debian'
|
||||||
|
os_version=$(cat $deb_version_file|grep Debian|grep -Eo '([0-9]+\.)+[0-9]+'|grep -Eo '[0-9]+')
|
||||||
|
if [ "${os_version}" = "" ];then
|
||||||
|
os_version=$(cat $deb_version_file|grep Debian|grep -Eo '[0-9]+')
|
||||||
|
fi
|
||||||
|
if [ "${os_version}" = "8" ];then
|
||||||
|
os_version=""
|
||||||
|
fi
|
||||||
|
if [ "${is64bit}" = '32' ];then
|
||||||
|
os_version=""
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
if [ "$os_version" = "14" ];then
|
||||||
|
os_version=""
|
||||||
|
fi
|
||||||
|
if [ "$os_version" = "12" ];then
|
||||||
|
os_version=""
|
||||||
|
fi
|
||||||
|
if [ "$os_version" = "19" ];then
|
||||||
|
os_version=""
|
||||||
|
fi
|
||||||
|
if [ "$os_version" = "21" ];then
|
||||||
|
os_version=""
|
||||||
|
fi
|
||||||
|
if [ "$os_version" = "20" ];then
|
||||||
|
os_version2004=$(cat /etc/issue|grep 20.04)
|
||||||
|
if [ -z "${os_version2004}" ];then
|
||||||
|
os_version=""
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
Install_Python_Lib(){
|
||||||
|
curl -Ss --connect-timeout 3 -m 60 $download_Url/install/pip_select.sh|bash
|
||||||
|
pyenv_path="/www/server/bt-monitor"
|
||||||
|
if [ -f $pyenv_path/pyenv/bin/python ];then
|
||||||
|
is_ssl=$($python_bin -c "import ssl" 2>&1|grep cannot)
|
||||||
|
$pyenv_path/pyenv/bin/python3.7 -V
|
||||||
|
if [ $? -eq 0 ] && [ -z "${is_ssl}" ];then
|
||||||
|
chmod -R 700 $pyenv_path/pyenv/bin
|
||||||
|
is_package=$($python_bin -m psutil 2>&1|grep package)
|
||||||
|
if [ "$is_package" = "" ];then
|
||||||
|
wget -O $pyenv_path/pyenv/pip.txt $download_Url/install/pyenv/pip.txt -t 5 -T 10
|
||||||
|
$pyenv_path/pyenv/bin/pip install -U pip
|
||||||
|
$pyenv_path/pyenv/bin/pip install -U setuptools
|
||||||
|
$pyenv_path/pyenv/bin/pip install -r $pyenv_path/pyenv/pip.txt
|
||||||
|
$pyenv_path/pyenv/bin/pip install -U flask==2.2.0
|
||||||
|
$pyenv_path/pyenv/bin/pip install flask_sock
|
||||||
|
$pyenv_path/pyenv/bin/pip install cachelib
|
||||||
|
$pyenv_path/pyenv/bin/pip install py7zr
|
||||||
|
$pyenv_path/pyenv/bin/pip install backports.lzma
|
||||||
|
fi
|
||||||
|
source $pyenv_path/pyenv/bin/activate
|
||||||
|
chmod -R 700 $pyenv_path/pyenv/bin
|
||||||
|
return
|
||||||
|
else
|
||||||
|
rm -rf $pyenv_path/pyenv
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
py_version="3.7.9"
|
||||||
|
if [ ! -d "$pyenv_path" ]; then
|
||||||
|
mkdir -p $pyenv_path
|
||||||
|
fi
|
||||||
|
echo "True" > /www/disk.pl
|
||||||
|
if [ ! -w /www/disk.pl ];then
|
||||||
|
Red_Error "ERROR: Install python env fielded." "ERROR: /www目录无法写入,请检查目录/用户/磁盘权限!"
|
||||||
|
fi
|
||||||
|
os_type='el'
|
||||||
|
os_version='7'
|
||||||
|
is_export_openssl=0
|
||||||
|
Get_Versions
|
||||||
|
|
||||||
|
echo "OS: $os_type - $os_version"
|
||||||
|
is_aarch64=$(uname -a|grep aarch64)
|
||||||
|
if [ "$is_aarch64" != "" ];then
|
||||||
|
is64bit="aarch64"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -f "/www/server/bt-monitor/pymake.pl" ];then
|
||||||
|
os_version=""
|
||||||
|
rm -f /www/server/bt-monitor/pymake.pl
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ $os_type =~ "debian" ]] || [[ $os_type =~ "ubuntu" ]]; then
|
||||||
|
isbtm="-btm"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "${os_version}" != "" ];then
|
||||||
|
pyenv_file="/www/pyenv.tar.gz"
|
||||||
|
wget -O $pyenv_file $download_Url/install/pyenv/pyenv-${os_type}${os_version}-x${is64bit}${isbtm}.tar.gz -t 5 -T 10
|
||||||
|
tmp_size=$(du -b $pyenv_file|awk '{print $1}')
|
||||||
|
if [ $tmp_size -lt 703460 ];then
|
||||||
|
rm -f $pyenv_file
|
||||||
|
echo "ERROR: Download python env fielded."
|
||||||
|
else
|
||||||
|
echo "Install python env..."
|
||||||
|
tar zxvf $pyenv_file -C $pyenv_path/ > /dev/null
|
||||||
|
chmod -R 700 $pyenv_path/pyenv/bin
|
||||||
|
rm -rf $pyenv_path/pyenv/bin/python
|
||||||
|
ln -sf $pyenv_path/pyenv/bin/python3.7 $pyenv_path/pyenv/bin/python
|
||||||
|
$pyenv_path/pyenv/bin/python -m pip install --upgrade --force-reinstall pip
|
||||||
|
$pyenv_path/pyenv/bin/pip install -U flask==2.2.0
|
||||||
|
$pyenv_path/pyenv/bin/pip install flask_sock
|
||||||
|
$pyenv_path/pyenv/bin/pip install cachelib
|
||||||
|
$pyenv_path/pyenv/bin/pip install py7zr
|
||||||
|
$pyenv_path/pyenv/bin/pip install backports.lzma
|
||||||
|
if [ ! -f $pyenv_path/pyenv/bin/python ];then
|
||||||
|
rm -f $pyenv_file
|
||||||
|
Red_Error "ERROR: Install python env fielded." "ERROR: 下载堡塔云监控运行环境失败,请尝试重新安装!"
|
||||||
|
fi
|
||||||
|
$pyenv_path/pyenv/bin/python3.7 -V
|
||||||
|
if [ $? -eq 0 ];then
|
||||||
|
rm -f $pyenv_file
|
||||||
|
ln -sf $pyenv_path/pyenv/bin/pip3.7 /usr/bin/btmpip
|
||||||
|
ln -sf $pyenv_path/pyenv/bin/python3.7 /usr/bin/btmpython
|
||||||
|
source $pyenv_path/pyenv/bin/activate
|
||||||
|
return
|
||||||
|
else
|
||||||
|
rm -f $pyenv_file
|
||||||
|
rm -rf $pyenv_path/pyenv
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
cd /www
|
||||||
|
python_src='/www/python_src.tar.xz'
|
||||||
|
python_src_path="/www/Python-${py_version}"
|
||||||
|
wget -O $python_src $download_Url/src/Python-${py_version}.tar.xz -t 5 -T 10
|
||||||
|
tmp_size=$(du -b $python_src|awk '{print $1}')
|
||||||
|
if [ $tmp_size -lt 10703460 ];then
|
||||||
|
rm -f $python_src
|
||||||
|
Red_Error "ERROR: Download python source code fielded." "ERROR: 下载堡塔云监控运行环境失败,请尝试重新安装!"
|
||||||
|
fi
|
||||||
|
tar xvf $python_src
|
||||||
|
rm -f $python_src
|
||||||
|
cd $python_src_path
|
||||||
|
./configure --prefix=$pyenv_path/pyenv
|
||||||
|
make -j$cpu_cpunt
|
||||||
|
make install
|
||||||
|
if [ ! -f $pyenv_path/pyenv/bin/python3.7 ];then
|
||||||
|
rm -rf $python_src_path
|
||||||
|
Red_Error "ERROR: Make python env fielded." "ERROR: 编译堡塔云监控运行环境失败!"
|
||||||
|
fi
|
||||||
|
cd ~
|
||||||
|
rm -rf $python_src_path
|
||||||
|
wget -O $pyenv_path/pyenv/bin/activate $download_Url/install/pyenv/activate.panel -t 5 -T 10
|
||||||
|
wget -O $pyenv_path/pyenv/pip.txt $download_Url/install/pyenv/pip-3.7.8.txt -t 5 -T 10
|
||||||
|
ln -sf $pyenv_path/pyenv/bin/pip3.7 $pyenv_path/pyenv/bin/pip
|
||||||
|
ln -sf $pyenv_path/pyenv/bin/python3.7 $pyenv_path/pyenv/bin/python
|
||||||
|
ln -sf $pyenv_path/pyenv/bin/pip3.7 /usr/bin/btmpip
|
||||||
|
ln -sf $pyenv_path/pyenv/bin/python3.7 /usr/bin/btmpython
|
||||||
|
chmod -R 700 $pyenv_path/pyenv/bin
|
||||||
|
$pyenv_path/pyenv/bin/pip install -U pip
|
||||||
|
$pyenv_path/pyenv/bin/pip install -U setuptools
|
||||||
|
$pyenv_path/pyenv/bin/pip install -U wheel==0.34.2
|
||||||
|
$pyenv_path/pyenv/bin/pip install -r $pyenv_path/pyenv/pip.txt
|
||||||
|
$pyenv_path/pyenv/bin/pip install -U flask==2.2.0
|
||||||
|
$pyenv_path/pyenv/bin/pip install flask_sock
|
||||||
|
$pyenv_path/pyenv/bin/pip install cachelib
|
||||||
|
$pyenv_path/pyenv/bin/pip install py7zr
|
||||||
|
$pyenv_path/pyenv/bin/pip install backports.lzma
|
||||||
|
source $pyenv_path/pyenv/bin/activate
|
||||||
|
|
||||||
|
is_gevent=$($python_bin -m gevent 2>&1|grep -oE package)
|
||||||
|
is_psutil=$($python_bin -m psutil 2>&1|grep -oE package)
|
||||||
|
if [ "${is_gevent}" != "${is_psutil}" ];then
|
||||||
|
Red_Error "ERROR: psutil/gevent install failed!"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
Install_Monitor(){
|
||||||
|
version="2.3.0"
|
||||||
|
file_name="bt-monitor"
|
||||||
|
agent_src="bt-monitor.zip"
|
||||||
|
|
||||||
|
cd ~
|
||||||
|
version=`curl -sf ${Btapi_Url}/bt_monitor/latest_version |awk -F '\"version\"' '{print $2}'|awk -F ':' '{print $2}'|awk -F '"' '{print $2}'`
|
||||||
|
if [ -z $version ]; then
|
||||||
|
version="2.3.0"
|
||||||
|
fi
|
||||||
|
new_dir="/www/server/new_btmonitor"
|
||||||
|
if [ ! -d "$new_dir" ];then
|
||||||
|
mkdir -p $new_dir
|
||||||
|
fi
|
||||||
|
if [ ! -z "$action" ]; then
|
||||||
|
# 例如:sh update_btmonitor.sh /root/demo.zip
|
||||||
|
if [[ "$action" =~ "zip" ]]; then
|
||||||
|
version="指定版本"
|
||||||
|
unzip -o $action -d $new_dir/
|
||||||
|
else
|
||||||
|
wget -O $agent_src ${Btapi_Url}/install/src/$file_name-$version.zip -t 5 -T 10
|
||||||
|
unzip -o $agent_src -d $new_dir/ > /dev/null
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
wget -O $agent_src ${Btapi_Url}/install/src/$file_name-$version.zip -t 5 -T 10
|
||||||
|
unzip -o $agent_src -d $new_dir/ > /dev/null
|
||||||
|
fi
|
||||||
|
if [ ! -f $new_dir/BT-MONITOR ];then
|
||||||
|
ls -lh $agent_src
|
||||||
|
Red_Error "ERROR: Failed to download, please try install again!" "ERROR: 下载堡塔云监控失败,请尝试重新安装!"
|
||||||
|
fi
|
||||||
|
|
||||||
|
rm -rf $new_dir/config
|
||||||
|
rm -rf $new_dir/data
|
||||||
|
rm -rf $new_dir/ssl
|
||||||
|
\cp -r $new_dir/* $monitor_path/
|
||||||
|
rm -rf $agent_src
|
||||||
|
rm -rf $new_dir
|
||||||
|
chmod +x $monitor_path/BT-MONITOR
|
||||||
|
chmod +x $monitor_path/tools.py
|
||||||
|
wget -O /etc/init.d/btm ${download_Url}/init/btmonitor.init -t 5 -T 10
|
||||||
|
chmod +x /etc/init.d/btm
|
||||||
|
ln -sf /etc/init.d/btm /usr/bin/btm
|
||||||
|
|
||||||
|
if [ ! -f $monitor_path/data/user.json ]; then
|
||||||
|
echo "{\"uid\":1,\"username\":\"Administrator\",\"ip\":\"127.0.0.1\",\"server_id\":\"1\",\"access_key\":\"test\",\"secret_key\":\"123456\"}" > $monitor_path/data/user.json
|
||||||
|
fi
|
||||||
|
if [ -f $monitor_path/core/include/c_loader/PluginLoader.so ]; then
|
||||||
|
rm -f $monitor_path/core/include/c_loader/PluginLoader.so
|
||||||
|
fi
|
||||||
|
if [ -f $monitor_path/sqlite_server/PluginLoader.so ]; then
|
||||||
|
rm -f $monitor_path/sqlite_server/PluginLoader.so
|
||||||
|
fi
|
||||||
|
if [ -f $monitor_path/hook_import/PluginLoader.so ]; then
|
||||||
|
rm -f $monitor_path/hook_import/PluginLoader.so
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
Service_Add(){
|
||||||
|
if [ $Command_Exists systemctl ]; then
|
||||||
|
wget -O /usr/lib/systemd/system/btm.service ${download_Url}/init/systemd/btmonitor.service -t 5 -T 10
|
||||||
|
systemctl daemon-reload
|
||||||
|
systemctl enable btm
|
||||||
|
else
|
||||||
|
if [ "${PM}" == "yum" ] || [ "${PM}" == "dnf" ]; then
|
||||||
|
chkconfig --add btm
|
||||||
|
chkconfig --level 2345 btm on
|
||||||
|
elif [ "${PM}" == "apt-get" ]; then
|
||||||
|
update-rc.d btm defaults
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
Start_Monitor(){
|
||||||
|
/etc/init.d/btm start
|
||||||
|
if [ "$?" != "0" ]; then
|
||||||
|
echo "堡塔云监控启动失败!"
|
||||||
|
tail $monitor_path/logs/error.log
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo "已成功升级到[$version]${Ver}";
|
||||||
|
}
|
||||||
|
|
||||||
|
GetSysInfo(){
|
||||||
|
if [ -s "/etc/redhat-release" ];then
|
||||||
|
SYS_VERSION=$(cat /etc/redhat-release)
|
||||||
|
elif [ -s "/etc/issue" ]; then
|
||||||
|
SYS_VERSION=$(cat /etc/issue)
|
||||||
|
fi
|
||||||
|
SYS_INFO=$(uname -a)
|
||||||
|
SYS_BIT=$(getconf LONG_BIT)
|
||||||
|
MEM_TOTAL=$(free -m|grep Mem|awk '{print $2}')
|
||||||
|
CPU_INFO=$(getconf _NPROCESSORS_ONLN)
|
||||||
|
|
||||||
|
echo -e ${SYS_VERSION}
|
||||||
|
echo -e Bit:${SYS_BIT} Mem:${MEM_TOTAL}M Core:${CPU_INFO}
|
||||||
|
echo -e ${SYS_INFO}
|
||||||
|
echo -e "请截图以上报错信息发帖至论坛www.bt.cn/bbs求助"
|
||||||
|
}
|
||||||
|
|
||||||
|
Red_Error(){
|
||||||
|
echo '=================================================';
|
||||||
|
printf '\033[1;31;40m%b\033[0m\n' "$@";
|
||||||
|
GetSysInfo
|
||||||
|
exit 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Install_RPM_Pack(){
|
||||||
|
yumPacks="wget curl unzip gcc gcc-c++ make libcurl-devel openssl-devel xz-devel python-backports-lzma xz"
|
||||||
|
yum install -y ${yumPacks}
|
||||||
|
|
||||||
|
for yumPack in ${yumPacks}
|
||||||
|
do
|
||||||
|
rpmPack=$(rpm -q ${yumPack})
|
||||||
|
packCheck=$(echo ${rpmPack}|grep not)
|
||||||
|
if [ "${packCheck}" ]; then
|
||||||
|
yum install ${yumPack} -y
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
Install_Deb_Pack(){
|
||||||
|
apt-get update -y
|
||||||
|
debPacks="wget curl unzip gcc g++ make libcurl4-openssl-dev libssl-dev liblzma-dev xz-utils libffi-dev libbz2-dev libsqlite3-dev libreadline-dev libgdbm-dev python3-bsddb3 tk-dev ncurses-dev uuid-dev";
|
||||||
|
apt-get install -y $debPacks --force-yes
|
||||||
|
|
||||||
|
for debPack in ${debPacks}
|
||||||
|
do
|
||||||
|
packCheck=$(dpkg -l ${debPack})
|
||||||
|
if [ "$?" -ne "0" ] ;then
|
||||||
|
apt-get install -y $debPack
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
Get_Pack_Manager(){
|
||||||
|
if [ -f "/usr/bin/yum" ] && [ -d "/etc/yum.repos.d" ]; then
|
||||||
|
PM="yum"
|
||||||
|
elif [ -f "/usr/bin/apt-get" ] && [ -f "/usr/bin/dpkg" ]; then
|
||||||
|
PM="apt-get"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
Update_Monitor(){
|
||||||
|
Get_Pack_Manager
|
||||||
|
get_node_url
|
||||||
|
if [ $PM = "yum" ]; then
|
||||||
|
Install_RPM_Pack
|
||||||
|
else
|
||||||
|
Install_Deb_Pack
|
||||||
|
fi
|
||||||
|
if [ "$action" == "update_py" ]; then
|
||||||
|
Install_Python_Lib
|
||||||
|
fi
|
||||||
|
Install_Monitor
|
||||||
|
Service_Add
|
||||||
|
Start_Monitor
|
||||||
|
}
|
||||||
|
|
||||||
|
action=${1}
|
||||||
|
Update_Monitor
|
||||||
@ -14,10 +14,14 @@ if [ "${is64bit}" != '64' ];then
|
|||||||
echo "退出、不做任何操作"
|
echo "退出、不做任何操作"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
Centos6Check=$(cat /etc/redhat-release | grep ' 6.' | grep -iE 'centos|Red Hat')
|
||||||
|
if [ "${Centos6Check}" ];then
|
||||||
|
echo "Centos6不支持升级宝塔面板,建议备份数据重装更换Centos7/8安装宝塔面板"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
Btapi_Url='http://www.example.com'
|
Btapi_Url='http://www.example.com'
|
||||||
|
|
||||||
|
|
||||||
up_plugin=0
|
up_plugin=0
|
||||||
|
|
||||||
download_file(){
|
download_file(){
|
||||||
@ -70,7 +74,7 @@ select_node(){
|
|||||||
get_version(){
|
get_version(){
|
||||||
version=$(curl -Ss --connect-timeout 5 -m 2 $Btapi_Url/api/panel/get_version)
|
version=$(curl -Ss --connect-timeout 5 -m 2 $Btapi_Url/api/panel/get_version)
|
||||||
if [ "$version" = '' ];then
|
if [ "$version" = '' ];then
|
||||||
version='7.9.6'
|
version='7.9.9'
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -78,7 +82,7 @@ install_pack(){
|
|||||||
if [ -f /usr/bin/yum ];then
|
if [ -f /usr/bin/yum ];then
|
||||||
yum install libcurl-devel libffi-devel zlib-devel bzip2-devel openssl-devel ncurses-devel sqlite-devel readline-devel tk-devel gdbm-devel db4-devel libpcap-devel xz-devel -y
|
yum install libcurl-devel libffi-devel zlib-devel bzip2-devel openssl-devel ncurses-devel sqlite-devel readline-devel tk-devel gdbm-devel db4-devel libpcap-devel xz-devel -y
|
||||||
else
|
else
|
||||||
apt install libcurl4-openssl-dev net-tools swig build-essential libffi-dev zlib1g.dev libbz2-dev libssl-dev libncurses-dev libsqlite3-dev libreadline-dev tk-dev libgdbm-dev libdb-dev libdb++-dev libpcap-dev xz-utils -y
|
apt install libcurl4-openssl-dev net-tools swig build-essential libffi-dev zlib1g-dev libbz2-dev libssl-dev libncurses-dev libsqlite3-dev libreadline-dev tk-dev libgdbm-dev libdb-dev libdb++-dev libpcap-dev xz-utils -y
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -87,25 +91,71 @@ install_python(){
|
|||||||
pyenv_path="/www/server/panel"
|
pyenv_path="/www/server/panel"
|
||||||
python_bin=$pyenv_path/pyenv/bin/python
|
python_bin=$pyenv_path/pyenv/bin/python
|
||||||
if [ -f $pyenv_path/pyenv/bin/python ];then
|
if [ -f $pyenv_path/pyenv/bin/python ];then
|
||||||
is_err=$($pyenv_path/pyenv/bin/python3.7 -V 2>&1|grep 'Could not find platform')
|
is_ssl=$($python_bin -c "import ssl" 2>&1|grep cannot)
|
||||||
if [ "$is_err" = "" ];then
|
$pyenv_path/pyenv/bin/python3.7 -V
|
||||||
|
if [ $? -eq 0 ] && [ -z "${is_ssl}" ];then
|
||||||
chmod -R 700 $pyenv_path/pyenv/bin
|
chmod -R 700 $pyenv_path/pyenv/bin
|
||||||
is_package=$($python_bin -m psutil 2>&1|grep package)
|
is_package=$($python_bin -m psutil 2>&1|grep package)
|
||||||
if [ "$is_package" = "" ];then
|
if [ "$is_package" = "" ];then
|
||||||
wget -O $pyenv_path/pyenv/pip.txt $download_Url/install/pyenv/pip.txt -T 5
|
wget -O $pyenv_path/pyenv/pip.txt $download_Url/install/pyenv/pip-3.7.16.txt -T 15
|
||||||
$pyenv_path/pyenv/bin/pip install -U pip
|
$pyenv_path/pyenv/bin/pip install -U pip
|
||||||
$pyenv_path/pyenv/bin/pip install -U setuptools
|
$pyenv_path/pyenv/bin/pip install -U setuptools==65.5.0
|
||||||
$pyenv_path/pyenv/bin/pip install -r $pyenv_path/pyenv/pip.txt
|
$pyenv_path/pyenv/bin/pip install -r $pyenv_path/pyenv/pip.txt
|
||||||
fi
|
fi
|
||||||
source $pyenv_path/pyenv/bin/activate
|
source $pyenv_path/pyenv/bin/activate
|
||||||
|
chmod -R 700 $pyenv_path/pyenv/bin
|
||||||
return
|
return
|
||||||
else
|
else
|
||||||
rm -rf $pyenv_path/pyenv
|
rm -rf $pyenv_path/pyenv
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
is_loongarch64=$(uname -a|grep loongarch64)
|
||||||
|
if [ "$is_loongarch64" != "" ] && [ -f "/usr/bin/yum" ];then
|
||||||
|
yumPacks="python3-devel python3-pip python3-psutil python3-gevent python3-pyOpenSSL python3-paramiko python3-flask python3-rsa python3-requests python3-six python3-websocket-client"
|
||||||
|
yum install -y ${yumPacks}
|
||||||
|
for yumPack in ${yumPacks}
|
||||||
|
do
|
||||||
|
rpmPack=$(rpm -q ${yumPack})
|
||||||
|
packCheck=$(echo ${rpmPack}|grep not)
|
||||||
|
if [ "${packCheck}" ]; then
|
||||||
|
yum install ${yumPack} -y
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
pip3 install -U pip
|
||||||
|
pip3 install Pillow psutil pyinotify pycryptodome upyun oss2 pymysql qrcode qiniu redis pymongo Cython configparser cos-python-sdk-v5 supervisor gevent-websocket pyopenssl
|
||||||
|
pip3 install flask==1.1.4
|
||||||
|
pip3 install Pillow -U
|
||||||
|
|
||||||
|
pyenv_bin=/www/server/panel/pyenv/bin
|
||||||
|
mkdir -p $pyenv_bin
|
||||||
|
ln -sf /usr/local/bin/pip3 $pyenv_bin/pip
|
||||||
|
ln -sf /usr/local/bin/pip3 $pyenv_bin/pip3
|
||||||
|
ln -sf /usr/local/bin/pip3 $pyenv_bin/pip3.7
|
||||||
|
|
||||||
|
if [ -f "/usr/bin/python3.7" ];then
|
||||||
|
ln -sf /usr/bin/python3.7 $pyenv_bin/python
|
||||||
|
ln -sf /usr/bin/python3.7 $pyenv_bin/python3
|
||||||
|
ln -sf /usr/bin/python3.7 $pyenv_bin/python3.7
|
||||||
|
elif [ -f "/usr/bin/python3.6" ]; then
|
||||||
|
ln -sf /usr/bin/python3.6 $pyenv_bin/python
|
||||||
|
ln -sf /usr/bin/python3.6 $pyenv_bin/python3
|
||||||
|
ln -sf /usr/bin/python3.6 $pyenv_bin/python3.7
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo > $pyenv_bin/activate
|
||||||
|
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
install_pack
|
install_pack
|
||||||
py_version="3.7.9"
|
py_version="3.7.16"
|
||||||
mkdir -p $pyenv_path
|
mkdir -p $pyenv_path
|
||||||
|
echo "True" > /www/disk.pl
|
||||||
|
if [ ! -w /www/disk.pl ];then
|
||||||
|
Red_Error "ERROR: Install python env fielded." "ERROR: /www目录无法写入,请检查目录/用户/磁盘权限!"
|
||||||
|
fi
|
||||||
os_type='el'
|
os_type='el'
|
||||||
os_version='7'
|
os_version='7'
|
||||||
is_export_openssl=0
|
is_export_openssl=0
|
||||||
@ -115,42 +165,48 @@ install_python(){
|
|||||||
echo "OS: $os_type - $os_version"
|
echo "OS: $os_type - $os_version"
|
||||||
is_aarch64=$(uname -a|grep aarch64)
|
is_aarch64=$(uname -a|grep aarch64)
|
||||||
if [ "$is_aarch64" != "" ];then
|
if [ "$is_aarch64" != "" ];then
|
||||||
os_version="aarch64"
|
is64bit="aarch64"
|
||||||
fi
|
fi
|
||||||
up_plugin=1
|
up_plugin=1
|
||||||
|
|
||||||
if [ -f "/www/server/panel/pymake.pl" ];then
|
if [ -f "/www/server/panel/pymake.pl" ];then
|
||||||
os_version=""
|
os_version=""
|
||||||
rm -f /www/server/panel/pymake.pl
|
rm -f /www/server/panel/pymake.pl
|
||||||
fi
|
fi
|
||||||
|
echo "==============================================="
|
||||||
|
echo "正在下载面板运行环境,请稍等..............."
|
||||||
|
echo "==============================================="
|
||||||
if [ "${os_version}" != "" ];then
|
if [ "${os_version}" != "" ];then
|
||||||
pyenv_file="/www/pyenv.tar.gz"
|
pyenv_file="/www/pyenv.tar.gz"
|
||||||
wget -O $pyenv_file $download_Url/install/pyenv/pyenv-${os_type}${os_version}-x${is64bit}.tar.gz -T 10
|
wget -O $pyenv_file $download_Url/install/pyenv/pyenv-${os_type}${os_version}-x${is64bit}.tar.gz -T 20
|
||||||
|
if [ "$?" != "0" ];then
|
||||||
|
get_node_url $download_Url
|
||||||
|
wget -O $pyenv_file $download_Url/install/pyenv/pyenv-${os_type}${os_version}-x${is64bit}.tar.gz -T 20
|
||||||
|
fi
|
||||||
tmp_size=$(du -b $pyenv_file|awk '{print $1}')
|
tmp_size=$(du -b $pyenv_file|awk '{print $1}')
|
||||||
if [ $tmp_size -lt 703460 ];then
|
if [ $tmp_size -gt 703460 ];then
|
||||||
rm -f $pyenv_file
|
|
||||||
echo "ERROR: Download python env fielded."
|
|
||||||
else
|
|
||||||
echo "Install python env..."
|
echo "Install python env..."
|
||||||
tar zxvf $pyenv_file -C $pyenv_path/ &> /dev/null
|
tar zxvf $pyenv_file -C $pyenv_path/ > /dev/null
|
||||||
chmod -R 700 $pyenv_path/pyenv/bin
|
chmod -R 700 $pyenv_path/pyenv/bin
|
||||||
if [ ! -f $pyenv_path/pyenv/bin/python ];then
|
if [ -f $pyenv_path/pyenv/bin/python ];then
|
||||||
rm -f $pyenv_file
|
$pyenv_path/pyenv/bin/python3.7 -V
|
||||||
Red_Error "ERROR: Install python env fielded."
|
if [ $? -eq 0 ];then
|
||||||
fi
|
rm -f $pyenv_file
|
||||||
is_err=$($pyenv_path/pyenv/bin/python3.7 -V 2>&1|grep 'Could not find platform')
|
ln -sf $pyenv_path/pyenv/bin/pip3.7 /usr/bin/btpip
|
||||||
if [ "$is_err" = "" ];then
|
ln -sf $pyenv_path/pyenv/bin/python3.7 /usr/bin/btpython
|
||||||
rm -f $pyenv_file
|
source $pyenv_path/pyenv/bin/activate
|
||||||
ln -sf $pyenv_path/pyenv/bin/pip3.7 /usr/bin/btpip
|
return
|
||||||
ln -sf $pyenv_path/pyenv/bin/python3.7 /usr/bin/btpython
|
else
|
||||||
sync_python_lib
|
rm -f $pyenv_file
|
||||||
source $pyenv_path/pyenv/bin/activate
|
rm -rf $pyenv_path/pyenv
|
||||||
return
|
fi
|
||||||
else
|
else
|
||||||
|
rm -f $pyenv_file
|
||||||
rm -rf $pyenv_path/pyenv
|
rm -rf $pyenv_path/pyenv
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
rm -f $pyenv_file
|
||||||
|
echo "预编译环境下载失败,开始编译安装Python..."
|
||||||
fi
|
fi
|
||||||
if [ -f /usr/local/openssl/lib/libssl.so ];then
|
if [ -f /usr/local/openssl/lib/libssl.so ];then
|
||||||
export LDFLAGS="-L/usr/local/openssl/lib"
|
export LDFLAGS="-L/usr/local/openssl/lib"
|
||||||
@ -162,11 +218,11 @@ install_python(){
|
|||||||
cd /www
|
cd /www
|
||||||
python_src='/www/python_src.tar.xz'
|
python_src='/www/python_src.tar.xz'
|
||||||
python_src_path="/www/Python-${py_version}"
|
python_src_path="/www/Python-${py_version}"
|
||||||
wget -O $python_src $download_Url/src/Python-${py_version}.tar.xz -T 5
|
wget -O $python_src $download_Url/src/Python-${py_version}.tar.xz -T 15
|
||||||
tmp_size=$(du -b $python_src|awk '{print $1}')
|
tmp_size=$(du -b $python_src|awk '{print $1}')
|
||||||
if [ $tmp_size -lt 10703460 ];then
|
if [ $tmp_size -lt 10703460 ];then
|
||||||
rm -f $python_src
|
rm -f $python_src
|
||||||
Red_Error "ERROR: Download python source code fielded."
|
Red_Error "ERROR: Download python source code fielded." "ERROR: 下载宝塔运行环境失败,请尝试重新安装!"
|
||||||
fi
|
fi
|
||||||
tar xvf $python_src
|
tar xvf $python_src
|
||||||
rm -f $python_src
|
rm -f $python_src
|
||||||
@ -176,22 +232,45 @@ install_python(){
|
|||||||
make install
|
make install
|
||||||
if [ ! -f $pyenv_path/pyenv/bin/python3.7 ];then
|
if [ ! -f $pyenv_path/pyenv/bin/python3.7 ];then
|
||||||
rm -rf $python_src_path
|
rm -rf $python_src_path
|
||||||
Red_Error "ERROR: Make python env fielded."
|
Red_Error "ERROR: Make python env fielded." "ERROR: 编译宝塔运行环境失败!"
|
||||||
fi
|
fi
|
||||||
cd ~
|
cd ~
|
||||||
rm -rf $python_src_path
|
rm -rf $python_src_path
|
||||||
wget -O $pyenv_path/pyenv/bin/activate $download_Url/install/pyenv/activate.panel -T 5
|
wget -O $pyenv_path/pyenv/bin/activate $download_Url/install/pyenv/activate.panel -T 5
|
||||||
wget -O $pyenv_path/pyenv/pip.txt $download_Url/install/pyenv/pip.txt -T 5
|
wget -O $pyenv_path/pyenv/pip.txt $download_Url/install/pyenv/pip-3.7.16.txt -T 5
|
||||||
ln -sf $pyenv_path/pyenv/bin/pip3.7 $pyenv_path/pyenv/bin/pip
|
ln -sf $pyenv_path/pyenv/bin/pip3.7 $pyenv_path/pyenv/bin/pip
|
||||||
ln -sf $pyenv_path/pyenv/bin/python3.7 $pyenv_path/pyenv/bin/python
|
ln -sf $pyenv_path/pyenv/bin/python3.7 $pyenv_path/pyenv/bin/python
|
||||||
ln -sf $pyenv_path/pyenv/bin/pip3.7 /usr/bin/btpip
|
ln -sf $pyenv_path/pyenv/bin/pip3.7 /usr/bin/btpip
|
||||||
ln -sf $pyenv_path/pyenv/bin/python3.7 /usr/bin/btpython
|
ln -sf $pyenv_path/pyenv/bin/python3.7 /usr/bin/btpython
|
||||||
chmod -R 700 $pyenv_path/pyenv/bin
|
chmod -R 700 $pyenv_path/pyenv/bin
|
||||||
$pyenv_path/pyenv/bin/pip install -U pip
|
$pyenv_path/pyenv/bin/pip install -U pip
|
||||||
$pyenv_path/pyenv/bin/pip install -U setuptools
|
$pyenv_path/pyenv/bin/pip install -U setuptools==65.5.0
|
||||||
|
$pyenv_path/pyenv/bin/pip install -U wheel==0.34.2
|
||||||
$pyenv_path/pyenv/bin/pip install -r $pyenv_path/pyenv/pip.txt
|
$pyenv_path/pyenv/bin/pip install -r $pyenv_path/pyenv/pip.txt
|
||||||
sync_python_lib
|
|
||||||
|
wget -O pip-packs.txt $download_Url/install/pyenv/pip-packs.txt
|
||||||
|
echo "正在后台安装pip依赖请稍等.........."
|
||||||
|
PIP_PACKS=$(cat pip-packs.txt)
|
||||||
|
for P_PACK in ${PIP_PACKS};
|
||||||
|
do
|
||||||
|
btpip show ${P_PACK} > /dev/null 2>&1
|
||||||
|
if [ "$?" == "1" ];then
|
||||||
|
btpip install ${P_PACK}
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
rm -f pip-packs.txt
|
||||||
|
|
||||||
source $pyenv_path/pyenv/bin/activate
|
source $pyenv_path/pyenv/bin/activate
|
||||||
|
|
||||||
|
btpip install psutil
|
||||||
|
btpip install gevent
|
||||||
|
|
||||||
|
is_gevent=$($python_bin -m gevent 2>&1|grep -oE package)
|
||||||
|
is_psutil=$($python_bin -m psutil 2>&1|grep -oE package)
|
||||||
|
if [ "${is_gevent}" != "${is_psutil}" ];then
|
||||||
|
Red_Error "ERROR: psutil/gevent install failed!"
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
sync_python_lib(){
|
sync_python_lib(){
|
||||||
@ -333,9 +412,29 @@ update_panel(){
|
|||||||
|
|
||||||
chattr -i /etc/init.d/bt
|
chattr -i /etc/init.d/bt
|
||||||
chmod +x /etc/init.d/bt
|
chmod +x /etc/init.d/bt
|
||||||
if [ $up_plugin = 1 ];then
|
|
||||||
$pyenv_bin/python /www/server/panel/tools.py update_to6
|
# Install additional pip dependencies even if python already exists
|
||||||
fi
|
pyenv_path="/www/server/panel"
|
||||||
|
if [ ! -f "/www/server/panel/pyenv/n.pl" ];then
|
||||||
|
btpip install docxtpl==0.16.7
|
||||||
|
$pyenv_path/pyenv/bin/pip3 install pymongo
|
||||||
|
$pyenv_path/pyenv/bin/pip3 install psycopg2-binary
|
||||||
|
$pyenv_path/pyenv/bin/pip3 install flask -U
|
||||||
|
$pyenv_path/pyenv/bin/pip3 install flask-sock
|
||||||
|
$pyenv_path/pyenv/bin/pip3 install -I gevent
|
||||||
|
btpip install simple-websocket==0.10.0
|
||||||
|
btpip install natsort
|
||||||
|
btpip uninstall enum34 -y
|
||||||
|
btpip install geoip2==4.7.0
|
||||||
|
btpip install brotli
|
||||||
|
btpip install PyMySQL
|
||||||
|
fi
|
||||||
|
btpip install -I pyOpenSSl 2>/dev/null
|
||||||
|
# if [ $up_plugin = 1 ];then
|
||||||
|
# $pyenv_bin/python /www/server/panel/tools.py update_to6
|
||||||
|
# fi
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
update_start(){
|
update_start(){
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
BIN
public/static/file/en/kaixin.zip
Normal file
BIN
public/static/file/en/kaixin.zip
Normal file
Binary file not shown.
Binary file not shown.
BIN
public/static/images/aapanel.png
Normal file
BIN
public/static/images/aapanel.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 94 KiB |
BIN
public/static/images/bt_monitor.png
Normal file
BIN
public/static/images/bt_monitor.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 206 KiB |
@ -5,7 +5,6 @@
|
|||||||
# | Copyright (c) 2015-2020 宝塔软件(http://www.bt.cn) All rights reserved.
|
# | Copyright (c) 2015-2020 宝塔软件(http://www.bt.cn) All rights reserved.
|
||||||
# +-------------------------------------------------------------------
|
# +-------------------------------------------------------------------
|
||||||
# | Author: 沐落 <cjx@bt.cn>
|
# | Author: 沐落 <cjx@bt.cn>
|
||||||
|
|
||||||
# | 面板升级安装公共类
|
# | 面板升级安装公共类
|
||||||
# +-------------------------------------------------------------------
|
# +-------------------------------------------------------------------
|
||||||
|
|
||||||
@ -13,97 +12,250 @@ import os, sys
|
|||||||
panelPath = os.getenv('BT_PANEL')
|
panelPath = os.getenv('BT_PANEL')
|
||||||
os.chdir(panelPath)
|
os.chdir(panelPath)
|
||||||
sys.path.insert(0,panelPath + "/class/")
|
sys.path.insert(0,panelPath + "/class/")
|
||||||
import public,time,re,shutil,platform
|
import public,time,re,shutil,platform,socket
|
||||||
|
try:
|
||||||
|
import ctypes
|
||||||
|
except ImportError:
|
||||||
|
ctypes = None
|
||||||
|
|
||||||
class panel_update:
|
class panel_update:
|
||||||
|
|
||||||
|
__cloud_url = 'http://www.example.com'
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
def _check_admin_privileges(self):
|
||||||
|
try:
|
||||||
|
# 方法1: 使用ctypes检查管理员权限
|
||||||
|
if ctypes:
|
||||||
|
is_admin = ctypes.windll.shell32.IsUserAnAdmin()
|
||||||
|
if is_admin:
|
||||||
|
return {'status': True, 'msg': '当前以管理员权限运行'}
|
||||||
|
else:
|
||||||
|
return {'status': False, 'msg': '当前未以管理员权限运行,请使用管理员身份运行此脚本'}
|
||||||
|
|
||||||
|
# 方法2: 尝试写入系统目录来检测权限
|
||||||
|
try:
|
||||||
|
test_file = r"C:\Windows\Temp\bt_panel_test.tmp"
|
||||||
|
with open(test_file, 'w') as f:
|
||||||
|
f.write('test')
|
||||||
|
os.remove(test_file)
|
||||||
|
return {'status': True, 'msg': '当前以管理员权限运行'}
|
||||||
|
except (IOError, OSError):
|
||||||
|
return {'status': False, 'msg': '当前未以管理员权限运行,请使用管理员身份运行此脚本'}
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
return {'status': False, 'msg': f'检测管理员权限时发生错误: {str(e)}'}
|
||||||
|
|
||||||
|
def _pre_update_checks(self):
|
||||||
|
try:
|
||||||
|
ip_address = self._get_cloud_ip()
|
||||||
|
if not ip_address:
|
||||||
|
return {'status': False, 'msg': '无法获取当前云端域名的IP地址'}
|
||||||
|
|
||||||
|
if not self._verify_api(ip_address):
|
||||||
|
return {'status': False, 'msg': '当前云端无法访问,可能未绑定api.bt.cn和www.bt.cn域名'}
|
||||||
|
|
||||||
|
if not self._update_hosts(ip_address):
|
||||||
|
return {'status': False, 'msg': '修改hosts文件失败'}
|
||||||
|
|
||||||
|
return {'status': True, 'msg': '升级前检查通过'}
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
return {'status': False, 'msg': f'升级前检查异常: {str(e)}'}
|
||||||
|
|
||||||
|
def _get_cloud_ip(self):
|
||||||
|
domain = re.findall(r'://([^/:]+)', self.__cloud_url)[0]
|
||||||
|
try:
|
||||||
|
ip_address = socket.gethostbyname(domain)
|
||||||
|
return ip_address
|
||||||
|
except Exception as e:
|
||||||
|
print(f"获取{domain} IP失败: {str(e)}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
def _verify_api(self, ip_address):
|
||||||
|
try:
|
||||||
|
api_url = f"http://{ip_address}/api/SetupCount"
|
||||||
|
headers = {"Host": "api.bt.cn", "User-Agent": "BT-Panel"}
|
||||||
|
response = public.HttpGet(api_url, headers=headers, timeout=10)
|
||||||
|
if response and response.strip() == "ok":
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
print(f"请求云端验证失败,响应: {response}")
|
||||||
|
return False
|
||||||
|
except Exception as e:
|
||||||
|
print(f"请求云端验证异常: {str(e)}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
def _update_hosts(self, ip_address):
|
||||||
|
hosts_path = r"C:\Windows\System32\drivers\etc\hosts"
|
||||||
|
|
||||||
|
try:
|
||||||
|
if os.path.exists(hosts_path):
|
||||||
|
content = public.readFile(hosts_path)
|
||||||
|
else:
|
||||||
|
content = ""
|
||||||
|
|
||||||
|
lines = content.split('\n')
|
||||||
|
new_lines = []
|
||||||
|
|
||||||
|
for line in lines:
|
||||||
|
stripped_line = line.strip()
|
||||||
|
if not stripped_line or stripped_line.startswith('#'):
|
||||||
|
new_lines.append(line)
|
||||||
|
continue
|
||||||
|
|
||||||
|
if 'api.bt.cn' in line or 'www.bt.cn' in line:
|
||||||
|
continue
|
||||||
|
|
||||||
|
new_lines.append(line)
|
||||||
|
|
||||||
|
new_lines.append(f"{ip_address} api.bt.cn")
|
||||||
|
new_lines.append(f"{ip_address} www.bt.cn")
|
||||||
|
|
||||||
|
new_content = '\n'.join(new_lines)
|
||||||
|
result = public.writeFile(hosts_path, new_content)
|
||||||
|
|
||||||
|
if result:
|
||||||
|
print(f"修改hosts文件成功")
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
print("修改hosts文件失败")
|
||||||
|
return False
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"修改hosts文件异常: {str(e)}")
|
||||||
|
return False
|
||||||
|
|
||||||
def UpdatePanel(self,version):
|
def UpdatePanel(self,version):
|
||||||
"""
|
"""
|
||||||
更新面板到指定版本
|
更新Go面板到指定版本
|
||||||
@version 面板版本号
|
@version 面板版本号
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import public
|
import public
|
||||||
|
|
||||||
|
admin_check = self._check_admin_privileges()
|
||||||
|
if not admin_check['status']:
|
||||||
|
return public.returnMsg(False, admin_check['msg'])
|
||||||
|
|
||||||
|
result = self._pre_update_checks()
|
||||||
|
if not result['status']:
|
||||||
|
return public.returnMsg(False, result['msg'])
|
||||||
|
|
||||||
setupPath = os.getenv('BT_SETUP')
|
setupPath = os.getenv('BT_SETUP')
|
||||||
loacl_path = setupPath + '/panel.zip'
|
loacl_path = setupPath + '/panel.zip'
|
||||||
tmpPath = "{}/temp/panel".format(setupPath)
|
tmpPath = "{}/temp/panel".format(setupPath)
|
||||||
|
|
||||||
httpUrl = 'http://www.example.com'
|
|
||||||
try:
|
try:
|
||||||
downUrl = httpUrl + '/win/panel/panel_' + version + '.zip';
|
downUrl = self.__cloud_url + '/win/panel/panel_' + version + '.zip';
|
||||||
if os.path.exists(loacl_path): os.remove(loacl_path)
|
if os.path.exists(loacl_path): os.remove(loacl_path)
|
||||||
|
|
||||||
public.downloadFileByWget(downUrl,loacl_path);
|
public.downloadFileByWget(downUrl,loacl_path);
|
||||||
|
|
||||||
if os.path.getsize(loacl_path) < 1048576: return public.returnMsg(False,"PANEL_UPDATE_ERR_DOWN");
|
if os.path.getsize(loacl_path) < 1048576: return public.returnMsg(False,"PANEL_UPDATE_ERR_DOWN");
|
||||||
|
|
||||||
except :
|
except :
|
||||||
|
|
||||||
print(public.get_error_info())
|
print(public.get_error_info())
|
||||||
return public.returnMsg(False,"修复失败,无法连接到下载节点.");
|
return public.returnMsg(False,"更新失败,无法连接到下载节点.");
|
||||||
|
|
||||||
|
|
||||||
#处理临时文件目录
|
#处理临时文件目录
|
||||||
tcPath = '{}\class'.format(tmpPath)
|
tcPath = '{}\class'.format(tmpPath)
|
||||||
if os.path.exists(tmpPath): shutil.rmtree(tmpPath,True)
|
if os.path.exists(tmpPath): shutil.rmtree(tmpPath,True)
|
||||||
if not os.path.exists(tmpPath): os.makedirs(tmpPath)
|
if not os.path.exists(tmpPath): os.makedirs(tmpPath)
|
||||||
|
|
||||||
import zipfile
|
import zipfile
|
||||||
zip_file = zipfile.ZipFile(loacl_path)
|
zip_file = zipfile.ZipFile(loacl_path)
|
||||||
for names in zip_file.namelist():
|
for names in zip_file.namelist():
|
||||||
zip_file.extract(names,tmpPath)
|
zip_file.extract(names,tmpPath)
|
||||||
zip_file.close()
|
zip_file.close()
|
||||||
|
|
||||||
for name in os.listdir(tcPath):
|
os.system('net stop btPanel')
|
||||||
try:
|
|
||||||
if name.find('win_amd64.pyd') >=0:
|
|
||||||
oldName = os.path.join(tcPath,name);
|
|
||||||
lName = name.split('.')[0] + '.pyd'
|
|
||||||
newName = os.path.join(tcPath,lName)
|
|
||||||
if not os.path.exists(newName):os.rename(oldName,newName)
|
|
||||||
|
|
||||||
except :pass
|
|
||||||
|
|
||||||
#过滤文件
|
#过滤文件
|
||||||
file_list = ['config/config.json','config/index.json','data/libList.conf','data/plugin.json']
|
file_list = ['config/config.json','config/index.json','data/libList.conf','data/plugin.json']
|
||||||
for ff_path in file_list:
|
for ff_path in file_list:
|
||||||
if os.path.exists(tmpPath + '/' + ff_path): os.remove(tmpPath + '/' + ff_path)
|
if os.path.exists(tmpPath + '/' + ff_path): os.remove(tmpPath + '/' + ff_path)
|
||||||
|
|
||||||
|
if self.is_2008():
|
||||||
|
public.rmdir("{}/class/public".format(tmpPath))
|
||||||
|
public.rmdir("{}/class/BTPanel.py".format(tmpPath))
|
||||||
|
return public.returnMsg(False,"Windows 2008无法使用最新版本。")
|
||||||
|
|
||||||
public.mod_reload(public)
|
public.mod_reload(public)
|
||||||
import public
|
import public
|
||||||
|
|
||||||
#兼容不同版本工具箱
|
#兼容不同版本工具箱
|
||||||
public.kill('BtTools.exe')
|
public.kill('BtTools.exe')
|
||||||
toolPath = tmpPath + '/script/BtTools.exe'
|
toolPath = tmpPath + '/script/BtTools.exe'
|
||||||
if os.path.exists(toolPath):os.remove(toolPath)
|
if os.path.exists(toolPath):os.remove(toolPath)
|
||||||
|
|
||||||
s_ver = platform.platform()
|
s_ver = platform.platform()
|
||||||
net_v = '45'
|
|
||||||
if s_ver.find('2008') >= 0: net_v = '20'
|
|
||||||
public.writeFile('{}/data/net'.format(panelPath),net_v)
|
|
||||||
public.downloadFileByWget(httpUrl + '/win/panel/BtTools' + net_v + '.exe',toolPath);
|
|
||||||
|
|
||||||
cPath = '{}/panel/class'.format(setupPath)
|
cPath = '{}/panel/class'.format(setupPath)
|
||||||
os.system("del /s {}\*.pyc".format(public.to_path(cPath)))
|
os.system("del /s {}\*.pyc".format(public.to_path(cPath)))
|
||||||
os.system("del /s {}\*.pyt".format(public.to_path(cPath)))
|
os.system("del /s {}\*.pyt".format(public.to_path(cPath)))
|
||||||
for name in os.listdir(cPath):
|
os.system("del /s {}\*_amd64.pyd".format(public.to_path(cPath)))
|
||||||
|
|
||||||
|
for name in os.listdir(cPath):
|
||||||
try:
|
try:
|
||||||
if name.find('.pyd') >=0:
|
if name.find('.pyd') >=0:
|
||||||
oldName = os.path.join(cPath,name)
|
oldName = os.path.join(cPath,name)
|
||||||
newName = os.path.join(cPath,public.GetRandomString(8) + '.pyt')
|
newName = os.path.join(cPath,public.GetRandomString(8) + '.pyt')
|
||||||
os.rename(oldName,newName)
|
os.rename(oldName,newName)
|
||||||
if name.find('.dll') >= 0:
|
if name.find('.dll') >= 0:
|
||||||
oldName = os.path.join(cPath,name)
|
oldName = os.path.join(cPath,name)
|
||||||
public.rmdir(oldName)
|
public.rmdir(oldName)
|
||||||
|
|
||||||
except : pass
|
except : pass
|
||||||
|
|
||||||
#处理面板程序目录文件
|
#处理面板程序目录文件
|
||||||
os.system("del /s {}\*.pyc".format(public.to_path(cPath)))
|
os.system("del /s {}\*.pyc".format(public.to_path(cPath)))
|
||||||
os.system("del /s {}\*.pyt".format(public.to_path(cPath)))
|
os.system("del /s {}\*.pyt".format(public.to_path(cPath)))
|
||||||
|
os.system("del /s {}\*.del".format(public.to_path(panelPath)))
|
||||||
|
|
||||||
|
for name in os.listdir(panelPath):
|
||||||
|
try:
|
||||||
|
if name.find('.exe') >=0:
|
||||||
|
oldName = os.path.join(panelPath,name)
|
||||||
|
newName = oldName + '.del'
|
||||||
|
os.rename(oldName,newName)
|
||||||
|
except : pass
|
||||||
|
|
||||||
os.system("echo f|xcopy /s /c /e /y /r {} {}".format(public.to_path(tmpPath),public.to_path(panelPath)))
|
os.system("echo f|xcopy /s /c /e /y /r {} {}".format(public.to_path(tmpPath),public.to_path(panelPath)))
|
||||||
|
|
||||||
return public.returnMsg(True,"升级面板成功,重启面板后生效.");
|
panel_file = '{}/btPanel.exe'.format(panelPath)
|
||||||
|
if os.path.exists(panel_file):
|
||||||
|
os.system("sc stop btPanel")
|
||||||
|
os.system("sc stop btTask")
|
||||||
|
time.sleep(2)
|
||||||
|
os.system("sc delete btPanel")
|
||||||
|
os.system("sc delete btTask")
|
||||||
|
|
||||||
|
os.system("{} --services install".format(public.to_path(panel_file)))
|
||||||
|
time.sleep(2)
|
||||||
|
os.system("{} --task install".format(public.to_path(panel_file)))
|
||||||
|
|
||||||
|
os.system("sc start btPanel")
|
||||||
|
os.system("sc start btTask")
|
||||||
|
|
||||||
|
if os.path.exists('C:/update.py'): os.remove('C:/update.py')
|
||||||
|
|
||||||
|
return public.returnMsg(True,"升级面板成功.")
|
||||||
|
|
||||||
|
def is_2008(self):
|
||||||
|
"""
|
||||||
|
判断是否2008系统
|
||||||
|
"""
|
||||||
|
os_ver = public.ReadReg("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", "ProductName")
|
||||||
|
if os_ver.find('2008') >= 0: return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
version = sys.argv[1]
|
||||||
|
if not version:
|
||||||
|
version = "8.4.6"
|
||||||
|
result = panel_update().UpdatePanel(version)
|
||||||
|
print(result['msg'])
|
||||||
|
|||||||
@ -1,164 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
"""
|
|
||||||
requests.api
|
|
||||||
~~~~~~~~~~~~
|
|
||||||
|
|
||||||
This module implements the Requests API.
|
|
||||||
|
|
||||||
:copyright: (c) 2012 by Kenneth Reitz.
|
|
||||||
:license: Apache2, see LICENSE for more details.
|
|
||||||
"""
|
|
||||||
|
|
||||||
from . import sessions
|
|
||||||
|
|
||||||
|
|
||||||
def request(method, url, **kwargs):
|
|
||||||
if url.find('https://api.bt.cn/') != -1:
|
|
||||||
url = url.replace('https://api.bt.cn/', 'http://www.example.com/')
|
|
||||||
|
|
||||||
"""Constructs and sends a :class:`Request <Request>`.
|
|
||||||
|
|
||||||
:param method: method for the new :class:`Request` object: ``GET``, ``OPTIONS``, ``HEAD``, ``POST``, ``PUT``, ``PATCH``, or ``DELETE``.
|
|
||||||
:param url: URL for the new :class:`Request` object.
|
|
||||||
:param params: (optional) Dictionary, list of tuples or bytes to send
|
|
||||||
in the query string for the :class:`Request`.
|
|
||||||
:param data: (optional) Dictionary, list of tuples, bytes, or file-like
|
|
||||||
object to send in the body of the :class:`Request`.
|
|
||||||
:param json: (optional) A JSON serializable Python object to send in the body of the :class:`Request`.
|
|
||||||
:param headers: (optional) Dictionary of HTTP Headers to send with the :class:`Request`.
|
|
||||||
:param cookies: (optional) Dict or CookieJar object to send with the :class:`Request`.
|
|
||||||
:param files: (optional) Dictionary of ``'name': file-like-objects`` (or ``{'name': file-tuple}``) for multipart encoding upload.
|
|
||||||
``file-tuple`` can be a 2-tuple ``('filename', fileobj)``, 3-tuple ``('filename', fileobj, 'content_type')``
|
|
||||||
or a 4-tuple ``('filename', fileobj, 'content_type', custom_headers)``, where ``'content-type'`` is a string
|
|
||||||
defining the content type of the given file and ``custom_headers`` a dict-like object containing additional headers
|
|
||||||
to add for the file.
|
|
||||||
:param auth: (optional) Auth tuple to enable Basic/Digest/Custom HTTP Auth.
|
|
||||||
:param timeout: (optional) How many seconds to wait for the server to send data
|
|
||||||
before giving up, as a float, or a :ref:`(connect timeout, read
|
|
||||||
timeout) <timeouts>` tuple.
|
|
||||||
:type timeout: float or tuple
|
|
||||||
:param allow_redirects: (optional) Boolean. Enable/disable GET/OPTIONS/POST/PUT/PATCH/DELETE/HEAD redirection. Defaults to ``True``.
|
|
||||||
:type allow_redirects: bool
|
|
||||||
:param proxies: (optional) Dictionary mapping protocol to the URL of the proxy.
|
|
||||||
:param verify: (optional) Either a boolean, in which case it controls whether we verify
|
|
||||||
the server's TLS certificate, or a string, in which case it must be a path
|
|
||||||
to a CA bundle to use. Defaults to ``True``.
|
|
||||||
:param stream: (optional) if ``False``, the response content will be immediately downloaded.
|
|
||||||
:param cert: (optional) if String, path to ssl client cert file (.pem). If Tuple, ('cert', 'key') pair.
|
|
||||||
:return: :class:`Response <Response>` object
|
|
||||||
:rtype: requests.Response
|
|
||||||
|
|
||||||
Usage::
|
|
||||||
|
|
||||||
>>> import requests
|
|
||||||
>>> req = requests.request('GET', 'https://httpbin.org/get')
|
|
||||||
>>> req
|
|
||||||
<Response [200]>
|
|
||||||
"""
|
|
||||||
|
|
||||||
# By using the 'with' statement we are sure the session is closed, thus we
|
|
||||||
# avoid leaving sockets open which can trigger a ResourceWarning in some
|
|
||||||
# cases, and look like a memory leak in others.
|
|
||||||
with sessions.Session() as session:
|
|
||||||
return session.request(method=method, url=url, **kwargs)
|
|
||||||
|
|
||||||
|
|
||||||
def get(url, params=None, **kwargs):
|
|
||||||
r"""Sends a GET request.
|
|
||||||
|
|
||||||
:param url: URL for the new :class:`Request` object.
|
|
||||||
:param params: (optional) Dictionary, list of tuples or bytes to send
|
|
||||||
in the query string for the :class:`Request`.
|
|
||||||
:param \*\*kwargs: Optional arguments that ``request`` takes.
|
|
||||||
:return: :class:`Response <Response>` object
|
|
||||||
:rtype: requests.Response
|
|
||||||
"""
|
|
||||||
|
|
||||||
kwargs.setdefault('allow_redirects', True)
|
|
||||||
return request('get', url, params=params, **kwargs)
|
|
||||||
|
|
||||||
|
|
||||||
def options(url, **kwargs):
|
|
||||||
r"""Sends an OPTIONS request.
|
|
||||||
|
|
||||||
:param url: URL for the new :class:`Request` object.
|
|
||||||
:param \*\*kwargs: Optional arguments that ``request`` takes.
|
|
||||||
:return: :class:`Response <Response>` object
|
|
||||||
:rtype: requests.Response
|
|
||||||
"""
|
|
||||||
|
|
||||||
kwargs.setdefault('allow_redirects', True)
|
|
||||||
return request('options', url, **kwargs)
|
|
||||||
|
|
||||||
|
|
||||||
def head(url, **kwargs):
|
|
||||||
r"""Sends a HEAD request.
|
|
||||||
|
|
||||||
:param url: URL for the new :class:`Request` object.
|
|
||||||
:param \*\*kwargs: Optional arguments that ``request`` takes. If
|
|
||||||
`allow_redirects` is not provided, it will be set to `False` (as
|
|
||||||
opposed to the default :meth:`request` behavior).
|
|
||||||
:return: :class:`Response <Response>` object
|
|
||||||
:rtype: requests.Response
|
|
||||||
"""
|
|
||||||
|
|
||||||
kwargs.setdefault('allow_redirects', False)
|
|
||||||
return request('head', url, **kwargs)
|
|
||||||
|
|
||||||
|
|
||||||
def post(url, data=None, json=None, **kwargs):
|
|
||||||
r"""Sends a POST request.
|
|
||||||
|
|
||||||
:param url: URL for the new :class:`Request` object.
|
|
||||||
:param data: (optional) Dictionary, list of tuples, bytes, or file-like
|
|
||||||
object to send in the body of the :class:`Request`.
|
|
||||||
:param json: (optional) json data to send in the body of the :class:`Request`.
|
|
||||||
:param \*\*kwargs: Optional arguments that ``request`` takes.
|
|
||||||
:return: :class:`Response <Response>` object
|
|
||||||
:rtype: requests.Response
|
|
||||||
"""
|
|
||||||
|
|
||||||
return request('post', url, data=data, json=json, **kwargs)
|
|
||||||
|
|
||||||
|
|
||||||
def put(url, data=None, **kwargs):
|
|
||||||
r"""Sends a PUT request.
|
|
||||||
|
|
||||||
:param url: URL for the new :class:`Request` object.
|
|
||||||
:param data: (optional) Dictionary, list of tuples, bytes, or file-like
|
|
||||||
object to send in the body of the :class:`Request`.
|
|
||||||
:param json: (optional) json data to send in the body of the :class:`Request`.
|
|
||||||
:param \*\*kwargs: Optional arguments that ``request`` takes.
|
|
||||||
:return: :class:`Response <Response>` object
|
|
||||||
:rtype: requests.Response
|
|
||||||
"""
|
|
||||||
|
|
||||||
return request('put', url, data=data, **kwargs)
|
|
||||||
|
|
||||||
|
|
||||||
def patch(url, data=None, **kwargs):
|
|
||||||
r"""Sends a PATCH request.
|
|
||||||
|
|
||||||
:param url: URL for the new :class:`Request` object.
|
|
||||||
:param data: (optional) Dictionary, list of tuples, bytes, or file-like
|
|
||||||
object to send in the body of the :class:`Request`.
|
|
||||||
:param json: (optional) json data to send in the body of the :class:`Request`.
|
|
||||||
:param \*\*kwargs: Optional arguments that ``request`` takes.
|
|
||||||
:return: :class:`Response <Response>` object
|
|
||||||
:rtype: requests.Response
|
|
||||||
"""
|
|
||||||
|
|
||||||
return request('patch', url, data=data, **kwargs)
|
|
||||||
|
|
||||||
|
|
||||||
def delete(url, **kwargs):
|
|
||||||
r"""Sends a DELETE request.
|
|
||||||
|
|
||||||
:param url: URL for the new :class:`Request` object.
|
|
||||||
:param \*\*kwargs: Optional arguments that ``request`` takes.
|
|
||||||
:return: :class:`Response <Response>` object
|
|
||||||
:rtype: requests.Response
|
|
||||||
"""
|
|
||||||
|
|
||||||
return request('delete', url, **kwargs)
|
|
||||||
@ -22,7 +22,7 @@ def readReg(path,key):
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
panelPath = readReg(r'SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\宝塔面板','PanelPath')
|
panelPath = readReg(r'SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\宝塔面板','PanelPath')
|
||||||
if not panelPath:
|
if not panelPath:
|
||||||
panelPath = os.getenv('BT_PANEL')
|
panelPath = os.getenv('BT_PANEL')
|
||||||
if not panelPath: exit();
|
if not panelPath: exit();
|
||||||
|
|
||||||
@ -44,11 +44,11 @@ class Sql():
|
|||||||
__OPT_FIELD = "*" # field条件
|
__OPT_FIELD = "*" # field条件
|
||||||
__OPT_PARAM = () # where值
|
__OPT_PARAM = () # where值
|
||||||
__LOCK = panelPath + '/data/sqlite_lock.pl'
|
__LOCK = panelPath + '/data/sqlite_lock.pl'
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.__DB_FILE = panelPath + '/data/default.db'
|
self.__DB_FILE = panelPath + '/data/default.db'
|
||||||
|
|
||||||
def __GetConn(self):
|
def __GetConn(self):
|
||||||
#取数据库对象
|
#取数据库对象
|
||||||
try:
|
try:
|
||||||
if self.__DB_CONN == None:
|
if self.__DB_CONN == None:
|
||||||
@ -62,8 +62,8 @@ class Sql():
|
|||||||
#设置表名
|
#设置表名
|
||||||
self.__DB_TABLE = table
|
self.__DB_TABLE = table
|
||||||
return self
|
return self
|
||||||
|
|
||||||
|
|
||||||
def where(self,where,param):
|
def where(self,where,param):
|
||||||
#WHERE条件
|
#WHERE条件
|
||||||
if where:
|
if where:
|
||||||
@ -73,7 +73,7 @@ class Sql():
|
|||||||
|
|
||||||
def __to_tuple(self,param):
|
def __to_tuple(self,param):
|
||||||
#将参数转换为tuple
|
#将参数转换为tuple
|
||||||
if type(param) != tuple:
|
if type(param) != tuple:
|
||||||
if type(param) == list:
|
if type(param) == list:
|
||||||
param = tuple(param)
|
param = tuple(param)
|
||||||
else:
|
else:
|
||||||
@ -85,7 +85,7 @@ class Sql():
|
|||||||
if not pdata: return False
|
if not pdata: return False
|
||||||
keys,param = self.__format_pdata(pdata)
|
keys,param = self.__format_pdata(pdata)
|
||||||
return self.save(keys,param)
|
return self.save(keys,param)
|
||||||
|
|
||||||
#构造数据
|
#构造数据
|
||||||
def __format_pdata(self,pdata):
|
def __format_pdata(self,pdata):
|
||||||
keys = pdata.keys()
|
keys = pdata.keys()
|
||||||
@ -98,17 +98,17 @@ class Sql():
|
|||||||
#FIELD条件
|
#FIELD条件
|
||||||
if len(field):
|
if len(field):
|
||||||
self.__OPT_FIELD = field
|
self.__OPT_FIELD = field
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def getField(self,keyName):
|
def getField(self,keyName):
|
||||||
#取回指定字段
|
#取回指定字段
|
||||||
|
|
||||||
result = self.field(keyName).select()
|
result = self.field(keyName).select()
|
||||||
print(result)
|
print(result)
|
||||||
if len(result) != 0:
|
if len(result) != 0:
|
||||||
return result[0][keyName]
|
return result[0][keyName]
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def __format_field(self,field):
|
def __format_field(self,field):
|
||||||
import re
|
import re
|
||||||
fields = []
|
fields = []
|
||||||
@ -159,16 +159,16 @@ class Sql():
|
|||||||
return data
|
return data
|
||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
return "error: " + str(ex)
|
return "error: " + str(ex)
|
||||||
|
|
||||||
def setField(self,keyName,keyValue):
|
def setField(self,keyName,keyValue):
|
||||||
#更新指定字段
|
#更新指定字段
|
||||||
return self.save(keyName,(keyValue,))
|
return self.save(keyName,(keyValue,))
|
||||||
|
|
||||||
def commit(self):
|
def commit(self):
|
||||||
self.__close()
|
self.__close()
|
||||||
self.__DB_CONN.commit()
|
self.__DB_CONN.commit()
|
||||||
|
|
||||||
|
|
||||||
def save(self,keys,param):
|
def save(self,keys,param):
|
||||||
#更新数据
|
#更新数据
|
||||||
self.write_lock()
|
self.write_lock()
|
||||||
@ -180,7 +180,7 @@ class Sql():
|
|||||||
opt += key + "=?,"
|
opt += key + "=?,"
|
||||||
opt = opt[0:len(opt)-1]
|
opt = opt[0:len(opt)-1]
|
||||||
sql = "UPDATE " + self.__DB_TABLE + " SET " + opt+self.__OPT_WHERE
|
sql = "UPDATE " + self.__DB_TABLE + " SET " + opt+self.__OPT_WHERE
|
||||||
|
|
||||||
#处理拼接WHERE与UPDATE参数
|
#处理拼接WHERE与UPDATE参数
|
||||||
tmp = list(self.__to_tuple(param))
|
tmp = list(self.__to_tuple(param))
|
||||||
for arg in self.__OPT_PARAM:
|
for arg in self.__OPT_PARAM:
|
||||||
@ -193,8 +193,8 @@ class Sql():
|
|||||||
return result.rowcount
|
return result.rowcount
|
||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
return "error: " + str(ex)
|
return "error: " + str(ex)
|
||||||
|
|
||||||
|
|
||||||
def execute(self,sql,param = ()):
|
def execute(self,sql,param = ()):
|
||||||
#执行SQL语句返回受影响行
|
#执行SQL语句返回受影响行
|
||||||
self.write_lock()
|
self.write_lock()
|
||||||
@ -225,7 +225,7 @@ class Sql():
|
|||||||
def rm_lock(self):
|
def rm_lock(self):
|
||||||
if os.path.exists(self.__LOCK):
|
if os.path.exists(self.__LOCK):
|
||||||
os.remove(self.__LOCK)
|
os.remove(self.__LOCK)
|
||||||
|
|
||||||
def query(self,sql,param = ()):
|
def query(self,sql,param = ()):
|
||||||
#执行SQL语句返回数据集
|
#执行SQL语句返回数据集
|
||||||
self.__GetConn()
|
self.__GetConn()
|
||||||
@ -236,7 +236,7 @@ class Sql():
|
|||||||
return data
|
return data
|
||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
return "error: " + str(ex)
|
return "error: " + str(ex)
|
||||||
|
|
||||||
def __close(self):
|
def __close(self):
|
||||||
#清理条件属性
|
#清理条件属性
|
||||||
self.__OPT_WHERE = ""
|
self.__OPT_WHERE = ""
|
||||||
@ -244,8 +244,8 @@ class Sql():
|
|||||||
self.__OPT_ORDER = ""
|
self.__OPT_ORDER = ""
|
||||||
self.__OPT_LIMIT = ""
|
self.__OPT_LIMIT = ""
|
||||||
self.__OPT_PARAM = ()
|
self.__OPT_PARAM = ()
|
||||||
|
|
||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
#释放资源
|
#释放资源
|
||||||
try:
|
try:
|
||||||
@ -254,7 +254,7 @@ class Sql():
|
|||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
def GetLocalIp():
|
def GetLocalIp():
|
||||||
"""
|
"""
|
||||||
取本地外网IP
|
取本地外网IP
|
||||||
@ -264,17 +264,16 @@ def GetLocalIp():
|
|||||||
filename = panelPath + '/data/iplist.txt'
|
filename = panelPath + '/data/iplist.txt'
|
||||||
ipaddress = readFile(filename)
|
ipaddress = readFile(filename)
|
||||||
if not ipaddress:
|
if not ipaddress:
|
||||||
|
|
||||||
url = 'http://pv.sohu.com/cityjson?ie=utf-8'
|
url = 'http://www.example.com/api/getIpAddress';
|
||||||
str = httpGet(url)
|
str = httpGet(url)
|
||||||
ipaddress = re.search('\d+.\d+.\d+.\d+',str).group(0)
|
|
||||||
writeFile(filename,ipaddress)
|
writeFile(filename,ipaddress)
|
||||||
|
|
||||||
ipaddress = re.search('\d+.\d+.\d+.\d+',ipaddress).group(0);
|
ipaddress = re.search('\d+.\d+.\d+.\d+',ipaddress).group(0);
|
||||||
return ipaddress
|
return ipaddress
|
||||||
except:
|
except:
|
||||||
try:
|
try:
|
||||||
url = 'http://www.example.com/api/getIpAddress';
|
url = 'https://www.bt.cn/Api/getIpAddress';
|
||||||
str = httpGet(url)
|
str = httpGet(url)
|
||||||
writeFile(filename,ipaddress)
|
writeFile(filename,ipaddress)
|
||||||
return str
|
return str
|
||||||
@ -302,12 +301,12 @@ def start_service(name):
|
|||||||
while get_server_status(name) == 0:
|
while get_server_status(name) == 0:
|
||||||
try:
|
try:
|
||||||
win32serviceutil.StartService(name)
|
win32serviceutil.StartService(name)
|
||||||
time.sleep(1);
|
time.sleep(1);
|
||||||
except : time.sleep(1);
|
except : time.sleep(1);
|
||||||
timeout += 1
|
timeout += 1
|
||||||
if timeout > 10:break
|
if timeout > 10:break
|
||||||
|
|
||||||
if get_server_status(name) != 0:
|
if get_server_status(name) != 0:
|
||||||
return True,None
|
return True,None
|
||||||
return False,'操作失败,10秒内未完成启动服务【{}】'.format(name)
|
return False,'操作失败,10秒内未完成启动服务【{}】'.format(name)
|
||||||
except :
|
except :
|
||||||
@ -319,12 +318,12 @@ def stop_service(name):
|
|||||||
while get_server_status(name) == 1:
|
while get_server_status(name) == 1:
|
||||||
try:
|
try:
|
||||||
win32serviceutil.StopService(name)
|
win32serviceutil.StopService(name)
|
||||||
time.sleep(1);
|
time.sleep(1);
|
||||||
except : time.sleep(1);
|
except : time.sleep(1);
|
||||||
timeout += 1
|
timeout += 1
|
||||||
if timeout > 10:break
|
if timeout > 10:break
|
||||||
|
|
||||||
if get_server_status(name) != 1:
|
if get_server_status(name) != 1:
|
||||||
return True,None
|
return True,None
|
||||||
return False,'操作失败,10秒内未完成启动服务【{}】'.format(name)
|
return False,'操作失败,10秒内未完成启动服务【{}】'.format(name)
|
||||||
except :
|
except :
|
||||||
@ -364,15 +363,15 @@ def downloadFileByWget(url,filename):
|
|||||||
if os.path.exists(logPath): os.remove(logPath)
|
if os.path.exists(logPath): os.remove(logPath)
|
||||||
except : pass
|
except : pass
|
||||||
loacl_path = '{}/script/wget.exe'.format(panelPath)
|
loacl_path = '{}/script/wget.exe'.format(panelPath)
|
||||||
if not os.path.exists(loacl_path): downloadFile(get_url()+'/win/panel/data/wget.exe',loacl_path)
|
if not os.path.exists(loacl_path): downloadFile(get_url()+'/win/panel/data/wget.exe',loacl_path)
|
||||||
|
|
||||||
if os.path.getsize(loacl_path) < 10:
|
if os.path.getsize(loacl_path) < 10:
|
||||||
os.remove(loacl_path)
|
os.remove(loacl_path)
|
||||||
downloadFile(url,filename)
|
downloadFile(url,filename)
|
||||||
else:
|
else:
|
||||||
shell = "{} {} -O {} -t 5 -T 60 --no-check-certificate --auth-no-challenge --force-directorie > {} 2>&1".format(loacl_path,url,filename,logPath)
|
shell = "{} {} -O {} -t 5 -T 60 --no-check-certificate --auth-no-challenge --force-directorie > {} 2>&1".format(loacl_path,url,filename,logPath)
|
||||||
os.system(shell)
|
os.system(shell)
|
||||||
|
|
||||||
num = 0
|
num = 0
|
||||||
re_size = 0
|
re_size = 0
|
||||||
while num <= 5:
|
while num <= 5:
|
||||||
@ -382,17 +381,17 @@ def downloadFileByWget(url,filename):
|
|||||||
break;
|
break;
|
||||||
else:
|
else:
|
||||||
re_size = cr_size
|
re_size = cr_size
|
||||||
time.sleep(0.5)
|
time.sleep(0.5)
|
||||||
num += 1
|
num += 1
|
||||||
|
|
||||||
if os.path.exists(filename):
|
if os.path.exists(filename):
|
||||||
if os.path.getsize(filename) < 1:
|
if os.path.getsize(filename) < 1:
|
||||||
os.remove(filename)
|
os.remove(filename)
|
||||||
downloadFile(url,filename)
|
downloadFile(url,filename)
|
||||||
else:
|
else:
|
||||||
downloadFile(url,filename)
|
downloadFile(url,filename)
|
||||||
|
|
||||||
def writeFile(filename,s_body,mode='w+',encoding = 'utf-8'):
|
def writeFile(filename,s_body,mode='w+',encoding = 'utf-8'):
|
||||||
try:
|
try:
|
||||||
fp = open(filename, mode,encoding = encoding);
|
fp = open(filename, mode,encoding = encoding);
|
||||||
fp.write(s_body)
|
fp.write(s_body)
|
||||||
@ -402,7 +401,7 @@ def writeFile(filename,s_body,mode='w+',encoding = 'utf-8'):
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
def readFile(filename,mode = 'r'):
|
def readFile(filename,mode = 'r'):
|
||||||
|
|
||||||
import os,chardet
|
import os,chardet
|
||||||
if not os.path.exists(filename): return False
|
if not os.path.exists(filename): return False
|
||||||
if not os.path.isfile(filename): return False
|
if not os.path.isfile(filename): return False
|
||||||
@ -425,15 +424,15 @@ def readFile(filename,mode = 'r'):
|
|||||||
encoding = 'ansi'
|
encoding = 'ansi'
|
||||||
fp = open(filename, mode,encoding = encoding)
|
fp = open(filename, mode,encoding = encoding)
|
||||||
f_body = fp.read()
|
f_body = fp.read()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if f_body[0] == '\ufeff':
|
if f_body[0] == '\ufeff':
|
||||||
#处理带bom格式
|
#处理带bom格式
|
||||||
new_code = chardet.detect(f_body.encode(encoding))["encoding"]
|
new_code = chardet.detect(f_body.encode(encoding))["encoding"]
|
||||||
f_body = f_body.encode(encoding).decode(new_code);
|
f_body = f_body.encode(encoding).decode(new_code);
|
||||||
except : pass
|
except : pass
|
||||||
|
|
||||||
fp.close()
|
fp.close()
|
||||||
return f_body
|
return f_body
|
||||||
|
|
||||||
def httpGet(url,timeout = 60,headers = {}):
|
def httpGet(url,timeout = 60,headers = {}):
|
||||||
@ -445,11 +444,11 @@ def httpGet(url,timeout = 60,headers = {}):
|
|||||||
req = urllib.request.Request(url,headers = headers)
|
req = urllib.request.Request(url,headers = headers)
|
||||||
response = urllib.request.urlopen(req,timeout = timeout)
|
response = urllib.request.urlopen(req,timeout = timeout)
|
||||||
result = response.read()
|
result = response.read()
|
||||||
if type(result) == bytes:
|
if type(result) == bytes:
|
||||||
try:
|
try:
|
||||||
result = result.decode('utf-8')
|
result = result.decode('utf-8')
|
||||||
except :
|
except :
|
||||||
result = result.decode('gb2312')
|
result = result.decode('gb2312')
|
||||||
return result
|
return result
|
||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
if headers: return False
|
if headers: return False
|
||||||
@ -470,9 +469,9 @@ def httpPost(url, data, timeout=60, headers={}):
|
|||||||
|
|
||||||
return result
|
return result
|
||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
|
|
||||||
return str(ex);
|
return str(ex);
|
||||||
|
|
||||||
|
|
||||||
def get_timeout(url,timeout=3):
|
def get_timeout(url,timeout=3):
|
||||||
|
|
||||||
@ -484,10 +483,10 @@ def get_timeout(url,timeout=3):
|
|||||||
|
|
||||||
def get_url(timeout = 0.5):
|
def get_url(timeout = 0.5):
|
||||||
import json
|
import json
|
||||||
try:
|
try:
|
||||||
#
|
#
|
||||||
node_list = [{"protocol":"http://","address":"dg1.bt.cn","port":"80","ping":500},{"protocol":"http://","address":"dg2.bt.cn","port":"80","ping":500},{"protocol":"http://","address":"node.aapanel.com","port":"80","ping":500},{"protocol":"http://","address":"download.bt.cn","port":"80","ping":500}]
|
node_list = [{"protocol":"http://","address":"dg2.bt.cn","port":"80","ping":500},{"protocol":"http://","address":"dg1.bt.cn","port":"80","ping":500},{"protocol":"http://","address":"download.bt.cn","port":"80","ping":500},{"protocol":"http://","address":"hk1-node.bt.cn","port":"80","ping":500},{"protocol":"http://","address":"na1-node.bt.cn","port":"80","ping":500},{"protocol":"http://","address":"jp1-node.bt.cn","port":"80","ping":500}]
|
||||||
|
|
||||||
mnode1 = []
|
mnode1 = []
|
||||||
mnode2 = []
|
mnode2 = []
|
||||||
mnode3 = []
|
mnode3 = []
|
||||||
@ -510,12 +509,12 @@ def get_url(timeout = 0.5):
|
|||||||
mnode = sorted(mnode3,key= lambda x:x['net'],reverse=True)
|
mnode = sorted(mnode3,key= lambda x:x['net'],reverse=True)
|
||||||
else: #终选中等延迟,中等带宽
|
else: #终选中等延迟,中等带宽
|
||||||
mnode = sorted(mnode2,key= lambda x:x['ping'],reverse=False)
|
mnode = sorted(mnode2,key= lambda x:x['ping'],reverse=False)
|
||||||
|
|
||||||
if not mnode: return 'http://download.bt.cn'
|
if not mnode: return 'https://download.bt.cn'
|
||||||
#return mnode[0]['protocol'] + mnode[0]['address'] + ':' + mnode[0]['port']
|
#return mnode[0]['protocol'] + mnode[0]['address'] + ':' + mnode[0]['port']
|
||||||
return "https://" + mnode[0]['address']
|
return "https://" + mnode[0]['address']
|
||||||
except:
|
except:
|
||||||
return 'http://download.bt.cn'
|
return 'https://download.bt.cn'
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -529,12 +528,12 @@ def del_file_access(filename,user):
|
|||||||
sd = win32security.GetFileSecurity(filename, win32security.DACL_SECURITY_INFORMATION)
|
sd = win32security.GetFileSecurity(filename, win32security.DACL_SECURITY_INFORMATION)
|
||||||
dacl = sd.GetSecurityDescriptorDacl()
|
dacl = sd.GetSecurityDescriptorDacl()
|
||||||
ace_count = dacl.GetAceCount()
|
ace_count = dacl.GetAceCount()
|
||||||
|
|
||||||
for i in range(ace_count ,0 ,-1):
|
for i in range(ace_count ,0 ,-1):
|
||||||
try:
|
try:
|
||||||
data = {}
|
data = {}
|
||||||
data['rev'], data['access'], usersid = dacl.GetAce(i-1)
|
data['rev'], data['access'], usersid = dacl.GetAce(i-1)
|
||||||
data['user'],data['group'], data['type'] = win32security.LookupAccountSid('', usersid)
|
data['user'],data['group'], data['type'] = win32security.LookupAccountSid('', usersid)
|
||||||
if data['user'].lower() == user.lower(): dacl.DeleteAce(i-1) #删除旧的dacl
|
if data['user'].lower() == user.lower(): dacl.DeleteAce(i-1) #删除旧的dacl
|
||||||
if data['user'].lower() == 'users': dacl.DeleteAce(i-1) #删除旧的dacl
|
if data['user'].lower() == 'users': dacl.DeleteAce(i-1) #删除旧的dacl
|
||||||
|
|
||||||
@ -542,35 +541,35 @@ def del_file_access(filename,user):
|
|||||||
try:
|
try:
|
||||||
#处理拒绝访问
|
#处理拒绝访问
|
||||||
dacl.DeleteAce(i-1)
|
dacl.DeleteAce(i-1)
|
||||||
except : pass
|
except : pass
|
||||||
sd.SetSecurityDescriptorDacl(1, dacl, 0)
|
sd.SetSecurityDescriptorDacl(1, dacl, 0)
|
||||||
win32security.SetFileSecurity(filename, win32security.DACL_SECURITY_INFORMATION, sd)
|
win32security.SetFileSecurity(filename, win32security.DACL_SECURITY_INFORMATION, sd)
|
||||||
except :
|
except :
|
||||||
pass
|
pass
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def set_file_access(filename,user,access):
|
def set_file_access(filename,user,access):
|
||||||
try:
|
try:
|
||||||
sd = win32security.GetFileSecurity(filename, win32security.DACL_SECURITY_INFORMATION)
|
sd = win32security.GetFileSecurity(filename, win32security.DACL_SECURITY_INFORMATION)
|
||||||
dacl = sd.GetSecurityDescriptorDacl()
|
dacl = sd.GetSecurityDescriptorDacl()
|
||||||
ace_count = dacl.GetAceCount()
|
ace_count = dacl.GetAceCount()
|
||||||
|
|
||||||
for i in range(ace_count, 0,-1):
|
for i in range(ace_count, 0,-1):
|
||||||
try:
|
try:
|
||||||
data = {}
|
data = {}
|
||||||
data['rev'], data['access'], usersid = dacl.GetAce(i-1)
|
data['rev'], data['access'], usersid = dacl.GetAce(i-1)
|
||||||
data['user'],data['group'], data['type'] = win32security.LookupAccountSid('', usersid)
|
data['user'],data['group'], data['type'] = win32security.LookupAccountSid('', usersid)
|
||||||
if data['user'].lower() == user.lower(): dacl.DeleteAce(i-1) #删除旧的dacl
|
if data['user'].lower() == user.lower(): dacl.DeleteAce(i-1) #删除旧的dacl
|
||||||
if data['user'].lower() == 'users': dacl.DeleteAce(i-1) #删除旧的dacl
|
if data['user'].lower() == 'users': dacl.DeleteAce(i-1) #删除旧的dacl
|
||||||
|
|
||||||
except :
|
except :
|
||||||
pass
|
pass
|
||||||
try:
|
try:
|
||||||
userx, domain, type = win32security.LookupAccountName("", user)
|
userx, domain, type = win32security.LookupAccountName("", user)
|
||||||
except :
|
except :
|
||||||
userx, domain, type = win32security.LookupAccountName("", 'IIS APPPOOL\\' + user)
|
userx, domain, type = win32security.LookupAccountName("", 'IIS APPPOOL\\' + user)
|
||||||
if access > 0: dacl.AddAccessAllowedAceEx(win32security.ACL_REVISION, 3, access, userx)
|
if access > 0: dacl.AddAccessAllowedAceEx(win32security.ACL_REVISION, 3, access, userx)
|
||||||
|
|
||||||
sd.SetSecurityDescriptorDacl(1, dacl, 0)
|
sd.SetSecurityDescriptorDacl(1, dacl, 0)
|
||||||
win32security.SetFileSecurity(filename, win32security.DACL_SECURITY_INFORMATION, sd)
|
win32security.SetFileSecurity(filename, win32security.DACL_SECURITY_INFORMATION, sd)
|
||||||
return True,None
|
return True,None
|
||||||
@ -582,24 +581,24 @@ def ExecShell(cmdstring, cwd=None, timeout=None, shell=True):
|
|||||||
cmdstring_list = cmdstring
|
cmdstring_list = cmdstring
|
||||||
else:
|
else:
|
||||||
cmdstring_list = shlex.split(cmdstring)
|
cmdstring_list = shlex.split(cmdstring)
|
||||||
|
|
||||||
if timeout:
|
if timeout:
|
||||||
end_time = datetime.datetime.now() + datetime.timedelta(seconds=timeout)
|
end_time = datetime.datetime.now() + datetime.timedelta(seconds=timeout)
|
||||||
|
|
||||||
sub = subprocess.Popen(cmdstring_list, cwd=cwd, stdin=subprocess.PIPE,shell=shell,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
|
sub = subprocess.Popen(cmdstring_list, cwd=cwd, stdin=subprocess.PIPE,shell=shell,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
|
||||||
while sub.poll() is None:
|
while sub.poll() is None:
|
||||||
time.sleep(0.1)
|
time.sleep(0.1)
|
||||||
if timeout:
|
if timeout:
|
||||||
if end_time <= datetime.datetime.now():
|
if end_time <= datetime.datetime.now():
|
||||||
raise Exception("Timeout:%s"%cmdstring)
|
raise Exception("Timeout:%s"%cmdstring)
|
||||||
a,e = sub.communicate()
|
a,e = sub.communicate()
|
||||||
if type(a) == bytes:
|
if type(a) == bytes:
|
||||||
try:
|
try:
|
||||||
a = a.decode('utf-8')
|
a = a.decode('utf-8')
|
||||||
except :
|
except :
|
||||||
a = a.decode('gb2312','ignore')
|
a = a.decode('gb2312','ignore')
|
||||||
|
|
||||||
if type(e) == bytes:
|
if type(e) == bytes:
|
||||||
try:
|
try:
|
||||||
e = e.decode('utf-8')
|
e = e.decode('utf-8')
|
||||||
except :
|
except :
|
||||||
@ -626,7 +625,7 @@ def GetRandomString1(length):
|
|||||||
strings += chars[random.randint(0, chrlen)]
|
strings += chars[random.randint(0, chrlen)]
|
||||||
return strings
|
return strings
|
||||||
|
|
||||||
def GetRandomString2(length):
|
def GetRandomString2(length):
|
||||||
from random import Random
|
from random import Random
|
||||||
strings = ''
|
strings = ''
|
||||||
chars = '!@#$%^&*()_+.,?[]-='
|
chars = '!@#$%^&*()_+.,?[]-='
|
||||||
@ -637,7 +636,7 @@ def GetRandomString2(length):
|
|||||||
return strings
|
return strings
|
||||||
|
|
||||||
def chdck_salt():
|
def chdck_salt():
|
||||||
|
|
||||||
sql = Sql()
|
sql = Sql()
|
||||||
sql.table('users').execute("ALTER TABLE 'users' ADD 'salt' TEXT",())
|
sql.table('users').execute("ALTER TABLE 'users' ADD 'salt' TEXT",())
|
||||||
|
|
||||||
@ -657,7 +656,7 @@ def md5(strings):
|
|||||||
"""
|
"""
|
||||||
import hashlib
|
import hashlib
|
||||||
m = hashlib.md5()
|
m = hashlib.md5()
|
||||||
|
|
||||||
m.update(strings.encode('utf-8'))
|
m.update(strings.encode('utf-8'))
|
||||||
return m.hexdigest()
|
return m.hexdigest()
|
||||||
|
|
||||||
@ -673,18 +672,18 @@ def password_salt(password,username=None,uid=None):
|
|||||||
salt = sql.table('users').where('id=?',(uid,)).getField('salt')
|
salt = sql.table('users').where('id=?',(uid,)).getField('salt')
|
||||||
return md5(md5(password+'_bt.cn')+salt)
|
return md5(md5(password+'_bt.cn')+salt)
|
||||||
|
|
||||||
def check_user(username):
|
def check_user(username):
|
||||||
resume = 0
|
resume = 0
|
||||||
while True:
|
while True:
|
||||||
data, total, resume = win32net.NetUserEnum(None, 3, win32netcon.FILTER_NORMAL_ACCOUNT, resume)
|
data, total, resume = win32net.NetUserEnum(None, 3, win32netcon.FILTER_NORMAL_ACCOUNT, resume)
|
||||||
for user in data:
|
for user in data:
|
||||||
if user['name'] == username: return True
|
if user['name'] == username: return True
|
||||||
if not resume: break
|
if not resume: break
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def add_user(username,password,ps):
|
def add_user(username,password,ps):
|
||||||
try:
|
try:
|
||||||
if not check_user(username):
|
if not check_user(username):
|
||||||
d = {}
|
d = {}
|
||||||
d['name'] = username
|
d['name'] = username
|
||||||
d['password'] = password
|
d['password'] = password
|
||||||
@ -692,7 +691,7 @@ def add_user(username,password,ps):
|
|||||||
d['flags'] = win32netcon.UF_NORMAL_ACCOUNT | win32netcon.UF_SCRIPT
|
d['flags'] = win32netcon.UF_NORMAL_ACCOUNT | win32netcon.UF_SCRIPT
|
||||||
d['priv'] = win32netcon.USER_PRIV_USER
|
d['priv'] = win32netcon.USER_PRIV_USER
|
||||||
win32net.NetUserAdd(None, 1, d)
|
win32net.NetUserAdd(None, 1, d)
|
||||||
|
|
||||||
#设置用户允许登录服务
|
#设置用户允许登录服务
|
||||||
handle = win32security.LsaOpenPolicy(None, win32security.POLICY_ALL_ACCESS)
|
handle = win32security.LsaOpenPolicy(None, win32security.POLICY_ALL_ACCESS)
|
||||||
sid_obj, domain, tmp = win32security.LookupAccountName(None, username)
|
sid_obj, domain, tmp = win32security.LookupAccountName(None, username)
|
||||||
@ -713,25 +712,25 @@ def add_user_bywww():
|
|||||||
|
|
||||||
pwd = GetRandomString(64) + GetRandomString1(32) + GetRandomString2(32)
|
pwd = GetRandomString(64) + GetRandomString1(32) + GetRandomString2(32)
|
||||||
status,error = add_user('www',pwd,'用于启动宝塔安装的程序,删除后会导致部分软件无法启动,请勿删除')
|
status,error = add_user('www',pwd,'用于启动宝塔安装的程序,删除后会导致部分软件无法启动,请勿删除')
|
||||||
if not status:
|
if not status:
|
||||||
writeFile(error_path,error)
|
writeFile(error_path,error)
|
||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def add_user_bymysql():
|
def add_user_bymysql():
|
||||||
|
|
||||||
pwd = GetRandomString(64) + GetRandomString1(32) + GetRandomString2(32)
|
pwd = GetRandomString(64) + GetRandomString1(32) + GetRandomString2(32)
|
||||||
status,error = add_user('mysql',pwd,'用于启动宝塔安装的程序,删除后会导致部分软件无法启动,请勿删除')
|
status,error = add_user('mysql',pwd,'用于启动宝塔安装的程序,删除后会导致部分软件无法启动,请勿删除')
|
||||||
if not status:
|
if not status:
|
||||||
writeFile(error_path,error)
|
writeFile(error_path,error)
|
||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def getIP(url):
|
def getIP(url):
|
||||||
import socket,re
|
import socket,re
|
||||||
|
|
||||||
tmp = re.search('http://(.+)\:\d*',url)
|
tmp = re.search('http://(.+)\:\d*',url)
|
||||||
if tmp:
|
if tmp:
|
||||||
domain = tmp.groups()[0]
|
domain = tmp.groups()[0]
|
||||||
myaddr = socket.getaddrinfo(domain, 'http')
|
myaddr = socket.getaddrinfo(domain, 'http')
|
||||||
return myaddr[0][4][0]
|
return myaddr[0][4][0]
|
||||||
@ -756,14 +755,14 @@ def add_panel_dir():
|
|||||||
]
|
]
|
||||||
|
|
||||||
is_break = False
|
is_break = False
|
||||||
for sobj in slist:
|
for sobj in slist:
|
||||||
if not os.path.exists(sobj[0]):
|
if not os.path.exists(sobj[0]):
|
||||||
os.makedirs(sobj[0])
|
os.makedirs(sobj[0])
|
||||||
n = 0
|
n = 0
|
||||||
while n < 5:
|
while n < 5:
|
||||||
if os.path.exists(sobj[0]): break
|
if os.path.exists(sobj[0]): break
|
||||||
|
|
||||||
os.makedirs(sobj[0])
|
os.makedirs(sobj[0])
|
||||||
time.sleep(0.5)
|
time.sleep(0.5)
|
||||||
n += 1
|
n += 1
|
||||||
|
|
||||||
@ -773,17 +772,17 @@ def add_panel_dir():
|
|||||||
|
|
||||||
del_file_access(sobj[0],'users')
|
del_file_access(sobj[0],'users')
|
||||||
|
|
||||||
for user in sobj[1]:
|
for user in sobj[1]:
|
||||||
n = 0
|
n = 0
|
||||||
while n < 3:
|
while n < 3:
|
||||||
status,error = set_file_access(sobj[0],user,2032127)
|
status,error = set_file_access(sobj[0],user,2032127)
|
||||||
if status: break
|
if status: break
|
||||||
time.sleep(0.5)
|
time.sleep(0.5)
|
||||||
|
|
||||||
if not status:
|
if not status:
|
||||||
writeFile(error_path,"目录{}设置{}权限设置错误 -> {}".format(sobj[0],user,error))
|
writeFile(error_path,"目录{}设置{}权限设置错误 -> {}".format(sobj[0],user,error))
|
||||||
break
|
break
|
||||||
|
|
||||||
del_file_access(setupPath,'users')
|
del_file_access(setupPath,'users')
|
||||||
url = get_url()
|
url = get_url()
|
||||||
|
|
||||||
@ -793,18 +792,18 @@ def add_panel_dir():
|
|||||||
download_url = '{}/win/panel/data/{}'.format(url,f_name)
|
download_url = '{}/win/panel/data/{}'.format(url,f_name)
|
||||||
|
|
||||||
n = 0
|
n = 0
|
||||||
while n < 10:
|
while n < 10:
|
||||||
n += 1;
|
n += 1;
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if os.path.exists(local_path) and os.path.getsize(local_path) < 10: os.remove(local_path)
|
if os.path.exists(local_path) and os.path.getsize(local_path) < 10: os.remove(local_path)
|
||||||
if not os.path.exists(local_path): downloadFileByWget(download_url,local_path)
|
if not os.path.exists(local_path): downloadFileByWget(download_url,local_path)
|
||||||
if os.path.getsize(local_path) and os.path.getsize(local_path) > 10: break;
|
if os.path.getsize(local_path) and os.path.getsize(local_path) > 10: break;
|
||||||
|
|
||||||
writeFile(error_path,'download {} error ->> {} \r\n {}'.format(f_name,download_url,""))
|
writeFile(error_path,'download {} error ->> {} \r\n {}'.format(f_name,download_url,""))
|
||||||
except :
|
except :
|
||||||
ip = getIP(url)
|
ip = getIP(url)
|
||||||
writeFile(error_path,'download {} error ->> {} \r\n connect {} \r\n {}'.format(ip,f_name,download_url,get_error_info()))
|
writeFile(error_path,'download {} error ->> {} \r\n connect {} \r\n {}'.format(ip,f_name,download_url,get_error_info()))
|
||||||
|
|
||||||
if n > 5: return False
|
if n > 5: return False
|
||||||
time.sleep(0.2)
|
time.sleep(0.2)
|
||||||
@ -816,9 +815,9 @@ def add_panel_dir():
|
|||||||
|
|
||||||
def unzip(src_path,dst_path):
|
def unzip(src_path,dst_path):
|
||||||
import zipfile
|
import zipfile
|
||||||
zip_file = zipfile.ZipFile(src_path)
|
zip_file = zipfile.ZipFile(src_path)
|
||||||
for names in zip_file.namelist():
|
for names in zip_file.namelist():
|
||||||
zip_file.extract(names,dst_path)
|
zip_file.extract(names,dst_path)
|
||||||
zip_file.close()
|
zip_file.close()
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@ -834,44 +833,44 @@ def download_panel(file_list = []):
|
|||||||
#下载面板
|
#下载面板
|
||||||
loacl_path = setupPath + '/panel.zip'
|
loacl_path = setupPath + '/panel.zip'
|
||||||
tmpPath = "{}/temp/panel".format(setupPath)
|
tmpPath = "{}/temp/panel".format(setupPath)
|
||||||
if os.path.exists(loacl_path): os.remove(loacl_path)
|
if os.path.exists(loacl_path): os.remove(loacl_path)
|
||||||
if os.path.exists(tmpPath): shutil.rmtree(tmpPath,True)
|
if os.path.exists(tmpPath): shutil.rmtree(tmpPath,True)
|
||||||
if not os.path.exists(tmpPath): os.makedirs(tmpPath)
|
if not os.path.exists(tmpPath): os.makedirs(tmpPath)
|
||||||
|
|
||||||
p_ver = sys.argv[2]
|
p_ver = sys.argv[2]
|
||||||
downUrl = url + '/win/panel/panel_' + p_ver + '.zip';
|
downUrl = url + '/win/panel/panel_' + p_ver + '.zip';
|
||||||
downloadFileByWget(downUrl,loacl_path);
|
downloadFileByWget(downUrl,loacl_path);
|
||||||
unzip(loacl_path,tmpPath)
|
unzip(loacl_path,tmpPath)
|
||||||
|
|
||||||
for ff_path in file_list:
|
for ff_path in file_list:
|
||||||
if os.path.exists(tmpPath + '/' + ff_path): os.remove(tmpPath + '/' + ff_path)
|
if os.path.exists(tmpPath + '/' + ff_path): os.remove(tmpPath + '/' + ff_path)
|
||||||
|
|
||||||
tcPath = '{}\class'.format(tmpPath)
|
tcPath = '{}\class'.format(tmpPath)
|
||||||
for name in os.listdir(tcPath):
|
for name in os.listdir(tcPath):
|
||||||
try:
|
try:
|
||||||
if name.find('win_amd64.pyd') >=0:
|
if name.find('win_amd64.pyd') >=0:
|
||||||
oldName = os.path.join(tcPath,name);
|
oldName = os.path.join(tcPath,name);
|
||||||
lName = name.split('.')[0] + '.pyd'
|
lName = name.split('.')[0] + '.pyd'
|
||||||
newName = os.path.join(tcPath,lName)
|
newName = os.path.join(tcPath,lName)
|
||||||
if not os.path.exists(newName):os.rename(oldName,newName)
|
if not os.path.exists(newName):os.rename(oldName,newName)
|
||||||
except :pass
|
except :pass
|
||||||
|
|
||||||
cPath = '{}/panel/class'.format(setupPath)
|
cPath = '{}/panel/class'.format(setupPath)
|
||||||
|
|
||||||
if os.path.exists(cPath):
|
if os.path.exists(cPath):
|
||||||
os.system("del /s {}\*.pyc".format(to_path(cPath)))
|
os.system("del /s {}\*.pyc".format(to_path(cPath)))
|
||||||
os.system("del /s {}\*.pyt".format(to_path(cPath)))
|
os.system("del /s {}\*.pyt".format(to_path(cPath)))
|
||||||
for name in os.listdir(cPath):
|
for name in os.listdir(cPath):
|
||||||
try:
|
try:
|
||||||
if name.find('.pyd') >=0:
|
if name.find('.pyd') >=0:
|
||||||
oldName = os.path.join(cPath,name)
|
oldName = os.path.join(cPath,name)
|
||||||
newName = os.path.join(cPath,GetRandomString(8) + '.pyt')
|
newName = os.path.join(cPath,GetRandomString(8) + '.pyt')
|
||||||
os.rename(oldName,newName)
|
os.rename(oldName,newName)
|
||||||
except : pass
|
except : pass
|
||||||
os.system("del /s {}\*.pyc".format(to_path(cPath)))
|
os.system("del /s {}\*.pyc".format(to_path(cPath)))
|
||||||
os.system("del /s {}\*.pyt".format(to_path(cPath)))
|
os.system("del /s {}\*.pyt".format(to_path(cPath)))
|
||||||
|
|
||||||
os.system("xcopy /s /c /e /y /r {} {}".format(to_path(tmpPath),to_path(panelPath)))
|
os.system("xcopy /s /c /e /y /r {} {}".format(to_path(tmpPath),to_path(panelPath)))
|
||||||
try:
|
try:
|
||||||
os.remove(loacl_path)
|
os.remove(loacl_path)
|
||||||
except : pass
|
except : pass
|
||||||
@ -880,27 +879,11 @@ def download_panel(file_list = []):
|
|||||||
shutil.rmtree(tmpPath,True)
|
shutil.rmtree(tmpPath,True)
|
||||||
except : pass
|
except : pass
|
||||||
|
|
||||||
s_ver = platform.platform()
|
s_ver = platform.platform()
|
||||||
net_v = '45'
|
net_v = '45'
|
||||||
if s_ver.find('2008') >= 0: net_v = '20'
|
if s_ver.find('2008') >= 0: net_v = '20'
|
||||||
writeFile('{}/data/net'.format(setupPath),net_v)
|
writeFile('{}/data/net'.format(setupPath),net_v)
|
||||||
|
|
||||||
not_workorder_path = '{}/data/not_workorder.pl'.format(panelPath)
|
|
||||||
if not os.path.exists(not_workorder_path):
|
|
||||||
writeFile(not_workorder_path,'True')
|
|
||||||
bind_path = '{}/data/bind_path.pl'.format(panelPath)
|
|
||||||
if os.path.exists(bind_path):
|
|
||||||
os.remove(bind_path)
|
|
||||||
userinfo_path = '{}/data/userInfo.json'.format(panelPath)
|
|
||||||
if not os.path.exists(userinfo_path):
|
|
||||||
writeFile(userinfo_path,'{"uid":1,"username":"Administrator","address":"127.0.0.1","serverid":"1","access_key":"test","secret_key":"123456","ukey":"123456","state":1}')
|
|
||||||
|
|
||||||
local_path = '{}/temp/api.py'.format(setupPath)
|
|
||||||
downloadFileByWget('{}/win/panel/data/api.py'.format(url),local_path)
|
|
||||||
if os.path.exists(local_path):
|
|
||||||
os.remove('C:/Program Files/python/Lib/site-packages/requests/api.py')
|
|
||||||
shutil.move(local_path,'C:/Program Files/python/Lib/site-packages/requests')
|
|
||||||
|
|
||||||
local_path = '{}/script/BtTools.exe'.format(panelPath)
|
local_path = '{}/script/BtTools.exe'.format(panelPath)
|
||||||
downloadFileByWget('{}/win/panel/BtTools{}.exe'.format(url,net_v),local_path)
|
downloadFileByWget('{}/win/panel/BtTools{}.exe'.format(url,net_v),local_path)
|
||||||
if os.path.getsize(local_path) > 128:
|
if os.path.getsize(local_path) > 128:
|
||||||
@ -910,7 +893,7 @@ def download_panel(file_list = []):
|
|||||||
try:
|
try:
|
||||||
from gevent import monkey
|
from gevent import monkey
|
||||||
except :
|
except :
|
||||||
os.system('"C:\Program Files\python\python.exe" -m pip install gevent')
|
os.system('"C:\Program Files\python\python.exe" -m pip install gevent')
|
||||||
except :
|
except :
|
||||||
writeFile(error_path,get_error_info())
|
writeFile(error_path,get_error_info())
|
||||||
|
|
||||||
@ -918,7 +901,7 @@ def update_panel():
|
|||||||
|
|
||||||
file_list = ['config/config.json','config/index.json','data/libList.conf','data/plugin.json']
|
file_list = ['config/config.json','config/index.json','data/libList.conf','data/plugin.json']
|
||||||
download_panel(file_list)
|
download_panel(file_list)
|
||||||
|
|
||||||
py_path = 'C:/Program Files/python/python.exe'
|
py_path = 'C:/Program Files/python/python.exe'
|
||||||
|
|
||||||
ExecShell("\"{}\" {}/panel/runserver.py --startup auto install".format(py_path,setupPath))
|
ExecShell("\"{}\" {}/panel/runserver.py --startup auto install".format(py_path,setupPath))
|
||||||
@ -929,7 +912,7 @@ def update_panel():
|
|||||||
def init_panel_data():
|
def init_panel_data():
|
||||||
try:
|
try:
|
||||||
sql = Sql()
|
sql = Sql()
|
||||||
username = sql.table('users').where('id=?',(1,)).getField('username')
|
username = sql.table('users').where('id=?',(1,)).getField('username')
|
||||||
if username == 'admin':
|
if username == 'admin':
|
||||||
username = GetRandomString(8)
|
username = GetRandomString(8)
|
||||||
password = GetRandomString(8)
|
password = GetRandomString(8)
|
||||||
@ -937,12 +920,12 @@ def init_panel_data():
|
|||||||
|
|
||||||
sql.table('users').where('id=?',(1,)).setField('username',username)
|
sql.table('users').where('id=?',(1,)).setField('username',username)
|
||||||
pwd = password_salt(md5(password),uid=1)
|
pwd = password_salt(md5(password),uid=1)
|
||||||
|
|
||||||
result = sql.table('users').where('id=?',(1,)).setField('password',pwd)
|
result = sql.table('users').where('id=?',(1,)).setField('password',pwd)
|
||||||
|
|
||||||
backup_path = panelPath[:2] + '/backup'
|
backup_path = panelPath[:2] + '/backup'
|
||||||
www_path = panelPath[:2] + '/wwwroot'
|
www_path = panelPath[:2] + '/wwwroot'
|
||||||
|
|
||||||
if not os.path.exists(backup_path): os.makedirs(backup_path)
|
if not os.path.exists(backup_path): os.makedirs(backup_path)
|
||||||
if not os.path.exists(www_path): os.makedirs(www_path)
|
if not os.path.exists(www_path): os.makedirs(www_path)
|
||||||
|
|
||||||
@ -953,11 +936,11 @@ def init_panel_data():
|
|||||||
if not os.path.exists(bind_path): writeFile(bind_path,'True')
|
if not os.path.exists(bind_path): writeFile(bind_path,'True')
|
||||||
|
|
||||||
admin_path = panelPath+ '/data/admin_path.pl'
|
admin_path = panelPath+ '/data/admin_path.pl'
|
||||||
if not os.path.exists(admin_path): writeFile(admin_path,"/" + GetRandomString(8))
|
if not os.path.exists(admin_path): writeFile(admin_path,"/" + GetRandomString(8))
|
||||||
|
|
||||||
port_path = panelPath+ '/data/port.pl'
|
port_path = panelPath+ '/data/port.pl'
|
||||||
if not os.path.exists(port_path): writeFile(port_path,'8888')
|
if not os.path.exists(port_path): writeFile(port_path,'8888')
|
||||||
|
|
||||||
recycle_bin_db = panelPath+ '/data/recycle_bin_db.pl'
|
recycle_bin_db = panelPath+ '/data/recycle_bin_db.pl'
|
||||||
if not os.path.exists(recycle_bin_db): writeFile(recycle_bin_db,'True')
|
if not os.path.exists(recycle_bin_db): writeFile(recycle_bin_db,'True')
|
||||||
|
|
||||||
@ -975,26 +958,26 @@ def init_panel_data():
|
|||||||
except :
|
except :
|
||||||
writeFile(error_path,get_error_info())
|
writeFile(error_path,get_error_info())
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def add_panel_services(num = 0):
|
def add_panel_services(num = 0):
|
||||||
try:
|
try:
|
||||||
py_path = 'C:/Program Files/python/python.exe'
|
py_path = 'C:/Program Files/python/python.exe'
|
||||||
|
|
||||||
delete_server('btPanel')
|
delete_server('btPanel')
|
||||||
ret = ExecShell("\"{}\" {}/panel/runserver.py --startup auto install".format(py_path,setupPath))
|
ret = ExecShell("\"{}\" {}/panel/runserver.py --startup auto install".format(py_path,setupPath))
|
||||||
|
|
||||||
delete_server('btTask')
|
delete_server('btTask')
|
||||||
ExecShell("\"{}\" {}/panel/task.py --startup auto install".format(py_path,setupPath))
|
ret1 = ExecShell("\"{}\" {}/panel/task.py --startup auto install".format(py_path,setupPath))
|
||||||
|
|
||||||
if get_server_status('btPanel') < 0 or get_server_status('btTask') < 0:
|
if get_server_status('btPanel') < 0 or get_server_status('btTask') < 0:
|
||||||
if num <= 0 :
|
if num <= 0 :
|
||||||
localPath = setupPath + "/temp/Time_Zones.reg";
|
localPath = setupPath + "/temp/Time_Zones.reg";
|
||||||
downloadFileByWget(get_url() + '/win/panel/data/Time_Zones.reg',localPath)
|
downloadFileByWget(get_url() + '/win/panel/data/Time_Zones.reg',localPath)
|
||||||
ExecShell("regedit /s " + localPath)
|
ExecShell("regedit /s " + localPath)
|
||||||
|
|
||||||
add_panel_services(1)
|
add_panel_services(1)
|
||||||
else:
|
else:
|
||||||
writeFile(error_path,ret[0] + ret[1])
|
writeFile(error_path,ret[0] + ret[1] + ret1[0] + ret1[1])
|
||||||
else:
|
else:
|
||||||
os.system('sc failure btPanel reset=1800 actions=restart/60000/restart/120000/restart/30000')
|
os.system('sc failure btPanel reset=1800 actions=restart/60000/restart/120000/restart/30000')
|
||||||
os.system('sc failure btTask reset=1800 actions=restart/60000/restart/120000/restart/30000')
|
os.system('sc failure btTask reset=1800 actions=restart/60000/restart/120000/restart/30000')
|
||||||
@ -1005,9 +988,9 @@ def add_panel_services(num = 0):
|
|||||||
|
|
||||||
|
|
||||||
def add_firewall_byport():
|
def add_firewall_byport():
|
||||||
|
|
||||||
conf = ExecShell('netsh advfirewall firewall show rule "宝塔面板"')[0]
|
conf = ExecShell('netsh advfirewall firewall show rule "宝塔面板"')[0]
|
||||||
if conf.lower().find('tcp') == -1:
|
if conf.lower().find('tcp') == -1:
|
||||||
ExecShell("netsh advfirewall firewall add rule name=宝塔面板 dir=in action=allow protocol=tcp localport=8888");
|
ExecShell("netsh advfirewall firewall add rule name=宝塔面板 dir=in action=allow protocol=tcp localport=8888");
|
||||||
ExecShell("netsh advfirewall firewall add rule name=网站访问端口 dir=in action=allow protocol=tcp localport=80");
|
ExecShell("netsh advfirewall firewall add rule name=网站访问端口 dir=in action=allow protocol=tcp localport=80");
|
||||||
ExecShell("netsh advfirewall firewall add rule name=远程桌面 dir=in action=allow protocol=tcp localport=3389");
|
ExecShell("netsh advfirewall firewall add rule name=远程桌面 dir=in action=allow protocol=tcp localport=3389");
|
||||||
@ -1029,8 +1012,8 @@ def get_error_log():
|
|||||||
return error
|
return error
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
stype = sys.argv[1];
|
stype = sys.argv[1];
|
||||||
if not stype in ['get_error_log']:
|
if not stype in ['get_error_log']:
|
||||||
if os.path.exists(error_path): os.remove(error_path)
|
if os.path.exists(error_path): os.remove(error_path)
|
||||||
result = eval('{}()'.format(stype))
|
result = eval('{}()'.format(stype))
|
||||||
print(result)
|
print(result)
|
||||||
|
|||||||
BIN
public/win/panel/panel_8.5.1.zip
Normal file
BIN
public/win/panel/panel_8.5.1.zip
Normal file
Binary file not shown.
@ -7,14 +7,33 @@ Route::get('/download', 'index/download');
|
|||||||
|
|
||||||
|
|
||||||
Route::any('/panel/get_plugin_list', 'api/get_plugin_list');
|
Route::any('/panel/get_plugin_list', 'api/get_plugin_list');
|
||||||
|
Route::any('/panel/get_plugin_auth', 'api/get_plugin_auth');
|
||||||
Route::any('/wpanel/get_plugin_list', 'api/get_plugin_list_win');
|
Route::any('/wpanel/get_plugin_list', 'api/get_plugin_list_win');
|
||||||
|
Route::any('/wpanel/get_plugin_auth', 'api/get_plugin_auth_win');
|
||||||
Route::post('/down/download_plugin', 'api/download_plugin');
|
Route::post('/down/download_plugin', 'api/download_plugin');
|
||||||
Route::post('/down/download_plugin_main', 'api/download_plugin_main');
|
Route::post('/down/download_plugin_main', 'api/download_plugin_main');
|
||||||
Route::post('/panel/get_soft_list_status', 'api/return_success');
|
Route::post('/panel/get_soft_list_status', 'api/return_success');
|
||||||
Route::post('/panel/get_unbinding', 'api/return_success');
|
Route::post('/panel/get_unbinding', 'api/return_success');
|
||||||
Route::post('/bt_cert', 'api/return_error');
|
Route::post('/wpanel/get_unbinding', 'api/return_success');
|
||||||
|
Route::post('/bt_cert', 'api/bt_cert');
|
||||||
Route::post('/Auth/GetAuthToken', 'api/get_auth_token');
|
Route::post('/Auth/GetAuthToken', 'api/get_auth_token');
|
||||||
Route::post('/Auth/GetBindCode', 'api/return_error');
|
Route::post('/Auth/GetBindCode', 'api/return_error');
|
||||||
|
Route::post('/auth/GetUserGiveAway', 'api/get_user_give_away');
|
||||||
|
Route::any('/bt_monitor/update_history', 'api/btm_update_history');
|
||||||
|
Route::any('/bt_monitor/latest_version', 'api/btm_latest_version');
|
||||||
|
Route::any('/bt_waf/get_malicious_ip', 'api/get_malicious_ip_list');
|
||||||
|
Route::any('/bt_waf/daily_count_v2', 'api/get_ssl_list');
|
||||||
|
Route::any('/bt_waf/latest_version', 'api/btwaf_latest_version');
|
||||||
|
|
||||||
|
Route::group('authorization', function () {
|
||||||
|
Route::post('/login', 'api/authorization_login');
|
||||||
|
Route::post('/info', 'api/authorization_info');
|
||||||
|
Route::post('/info_v2', 'api/authorization_info');
|
||||||
|
Route::post('/update_license', 'api/update_license');
|
||||||
|
Route::post('/get_unactivated_licenses', 'api/get_ssl_list');
|
||||||
|
Route::post('/is_obtained_btw_trial', 'api/is_obtained_btw_trial');
|
||||||
|
Route::miss('api/return_error');
|
||||||
|
});
|
||||||
|
|
||||||
Route::group('api', function () {
|
Route::group('api', function () {
|
||||||
Route::any('/panel/get_soft_list', 'api/get_plugin_list');
|
Route::any('/panel/get_soft_list', 'api/get_plugin_list');
|
||||||
@ -24,6 +43,9 @@ Route::group('api', function () {
|
|||||||
Route::get('/getUpdateLogs', 'api/get_update_logs');
|
Route::get('/getUpdateLogs', 'api/get_update_logs');
|
||||||
Route::get('/panel/get_version', 'api/get_version');
|
Route::get('/panel/get_version', 'api/get_version');
|
||||||
Route::get('/wpanel/get_version', 'api/get_version_win');
|
Route::get('/wpanel/get_version', 'api/get_version_win');
|
||||||
|
Route::get('/panel/get_panel_version', 'api/get_panel_version');
|
||||||
|
Route::any('/panel/get_panel_version_v2', 'api/get_panel_version_v2');
|
||||||
|
Route::any('/panel/get_panel_version_v3', 'api/get_panel_version_v2');
|
||||||
Route::get('/SetupCount', 'api/setup_count');
|
Route::get('/SetupCount', 'api/setup_count');
|
||||||
Route::any('/panel/updateLinux', 'api/check_update');
|
Route::any('/panel/updateLinux', 'api/check_update');
|
||||||
Route::any('/wpanel/updateWindows', 'api/check_update_win');
|
Route::any('/wpanel/updateWindows', 'api/check_update_win');
|
||||||
@ -34,15 +56,17 @@ Route::group('api', function () {
|
|||||||
Route::get('/index/get_win_date', 'api/get_win_date');
|
Route::get('/index/get_win_date', 'api/get_win_date');
|
||||||
Route::get('/panel/is_pro', 'api/is_pro');
|
Route::get('/panel/is_pro', 'api/is_pro');
|
||||||
Route::get('/getIpAddress', 'api/get_ip_address');
|
Route::get('/getIpAddress', 'api/get_ip_address');
|
||||||
|
Route::get('/GetAD', 'api/return_empty');
|
||||||
Route::post('/Auth/GetAuthToken', 'api/get_auth_token');
|
Route::post('/Auth/GetAuthToken', 'api/get_auth_token');
|
||||||
Route::post('/Auth/GetBindCode', 'api/return_error');
|
Route::post('/Auth/GetBindCode', 'api/return_error');
|
||||||
Route::post('/Auth/GetSSLList', 'api/get_ssl_list');
|
Route::post('/Auth/GetSSLList', 'api/get_ssl_list');
|
||||||
Route::post('/Cert/get_order_list', 'api/return_empty_array');
|
Route::post('/Cert/get_order_list', 'api/return_empty_array');
|
||||||
Route::post('/Cert/get_product_list', 'api/return_success');
|
Route::post('/Cert/get_product_list', 'api/return_success');
|
||||||
Route::get('/Pluginother/get_file', 'api/download_plugin_other');
|
Route::get('/Pluginother/get_file', 'api/download_plugin_other');
|
||||||
|
Route::get('/isCN', 'api/check_cnip');
|
||||||
|
|
||||||
Route::post('/Pluginother/create_order', 'api/return_error');
|
Route::post('/Pluginother/create_order', 'api/return_success');
|
||||||
Route::post('/Pluginother/renew_order', 'api/return_error');
|
Route::post('/Pluginother/renew_order', 'api/return_success');
|
||||||
Route::post('/Pluginother/order_stat', 'api/return_empty');
|
Route::post('/Pluginother/order_stat', 'api/return_empty');
|
||||||
Route::post('/Pluginother/re_order_stat', 'api/return_empty');
|
Route::post('/Pluginother/re_order_stat', 'api/return_empty');
|
||||||
Route::post('/Pluginother/create_order_okey', 'api/return_empty');
|
Route::post('/Pluginother/create_order_okey', 'api/return_empty');
|
||||||
@ -82,6 +106,9 @@ Route::group('api', function () {
|
|||||||
Route::get('/panel/notpro', 'api/return_empty');
|
Route::get('/panel/notpro', 'api/return_empty');
|
||||||
Route::post('/Btdeployment/get_deplist', 'api/get_deplist');
|
Route::post('/Btdeployment/get_deplist', 'api/get_deplist');
|
||||||
Route::post('/panel/get_deplist', 'api/get_deplist');
|
Route::post('/panel/get_deplist', 'api/get_deplist');
|
||||||
|
Route::post('/ip/info', 'api/get_ip_info');
|
||||||
|
Route::post('/ip/info_json', 'api/get_ip_info');
|
||||||
|
Route::post('/panel/get_ip_info', 'api/get_ip_info');
|
||||||
|
|
||||||
Route::post('/LinuxBeta', 'api/return_error');
|
Route::post('/LinuxBeta', 'api/return_error');
|
||||||
Route::post('/panel/apple_beta', 'api/return_error');
|
Route::post('/panel/apple_beta', 'api/return_error');
|
||||||
@ -93,6 +120,54 @@ Route::group('api', function () {
|
|||||||
Route::get('/panel/get_beta_logs', 'api/get_beta_logs');
|
Route::get('/panel/get_beta_logs', 'api/get_beta_logs');
|
||||||
Route::get('/wpanel/get_beta_logs', 'api/get_beta_logs');
|
Route::get('/wpanel/get_beta_logs', 'api/get_beta_logs');
|
||||||
|
|
||||||
|
Route::post('/v2/common_v1_authorization/get_pricing', 'api/return_error2');
|
||||||
|
Route::post('/v2/common_v2_authorization/get_pricing', 'api/return_error2');
|
||||||
|
Route::post('/v2/synchron', 'api/return_error2');
|
||||||
|
Route::post('/v2/product/email/user_surplus', 'api/email_user_surplus');
|
||||||
|
Route::post('/v2/product/email', 'api/return_error2');
|
||||||
|
|
||||||
|
Route::any('/bt_waf/getSpiders', 'api/btwaf_getspiders');
|
||||||
|
Route::any('/bt_waf/get_malicious', 'api/btwaf_getmalicious');
|
||||||
|
Route::post('/bt_waf/addSpider', 'api/return_empty');
|
||||||
|
Route::post('/bt_waf/getVulScanInfoList', 'api/return_empty');
|
||||||
|
Route::post('/bt_waf/reportInterceptFail', 'api/return_empty');
|
||||||
|
Route::any('/bt_waf/get_system_malicious', 'api/return_error2');
|
||||||
|
Route::any('/panel/get_spider', 'api/get_spider');
|
||||||
|
|
||||||
|
Route::post('/Auth/GetSocre', 'api/get_ssl_list');
|
||||||
|
Route::post('/Auth/SetSocre', 'api/get_ssl_list');
|
||||||
|
Route::post('/Auth/SubmitScore', 'api/get_ssl_list');
|
||||||
|
|
||||||
|
Route::post('/Cert_cloud_deploy/get_cert_list', 'api/return_success');
|
||||||
|
Route::post('/Cert_cloud_deploy/del_cert', 'api/return_success');
|
||||||
|
|
||||||
|
Route::any('/panel/getSoftList', 'api/get_plugin_list_en');
|
||||||
|
Route::any('/panel/getSoftListEn', 'api/get_plugin_list_en');
|
||||||
|
Route::post('/panel/download_plugin', 'api/download_plugin_en');
|
||||||
|
Route::get('/plugin/download', 'api/download_plugin_other');
|
||||||
|
Route::get('/common/getClientIP', 'api/get_ip_address');
|
||||||
|
Route::post('/panel/checkDomain', 'api/check_domain');
|
||||||
|
Route::get('/panel/getBetaVersionLogs', 'api/get_beta_logs');
|
||||||
|
Route::any('/panel/updateLinuxEn', 'api/check_update_en');
|
||||||
|
Route::post('/user/verifyToken', 'api/return_success');
|
||||||
|
Route::post('/panel/nps/check', 'api/nps_check');
|
||||||
|
Route::post('/panel/nps/questions', 'api/nps_questions');
|
||||||
|
Route::post('/panel/nps/submit', 'api/nps_submit');
|
||||||
|
Route::post('/panel/submit_feature_invoked_bulk', 'api/return_success');
|
||||||
|
Route::post('/panel/submit_expand_pack_used', 'api/return_success');
|
||||||
|
Route::get('/panel/getLatestOfficialVersion', 'api/get_version_en');
|
||||||
|
Route::post('/cert/user/list', 'api/nps_questions');
|
||||||
|
Route::post('/v2/user/wx_web/bound_wx_accounts', 'api/nps_questions');
|
||||||
|
|
||||||
|
Route::post('/Auth/GetCloudToken', 'api/get_auth_token');
|
||||||
|
Route::post('/cloudtro/version_info', 'api/cloudc_version_info');
|
||||||
|
Route::post('/cloudtro/get_version', 'api/cloudc_get_version');
|
||||||
|
Route::post('/cloudtro/get_product_order_status_v1', 'api/cloudc_order_status');
|
||||||
|
|
||||||
|
Route::miss('api/return_error');
|
||||||
|
});
|
||||||
|
|
||||||
|
Route::group('newapi', function () {
|
||||||
Route::miss('api/return_error');
|
Route::miss('api/return_error');
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -107,6 +182,7 @@ Route::group('admin', function () {
|
|||||||
Route::post('/testbturl', 'admin/testbturl');
|
Route::post('/testbturl', 'admin/testbturl');
|
||||||
Route::get('/plugins', 'admin/plugins');
|
Route::get('/plugins', 'admin/plugins');
|
||||||
Route::get('/pluginswin', 'admin/pluginswin');
|
Route::get('/pluginswin', 'admin/pluginswin');
|
||||||
|
Route::get('/pluginsen', 'admin/pluginsen');
|
||||||
Route::post('/plugins_data', 'admin/plugins_data');
|
Route::post('/plugins_data', 'admin/plugins_data');
|
||||||
Route::post('/download_plugin', 'admin/download_plugin');
|
Route::post('/download_plugin', 'admin/download_plugin');
|
||||||
Route::get('/refresh_plugins', 'admin/refresh_plugins');
|
Route::get('/refresh_plugins', 'admin/refresh_plugins');
|
||||||
@ -120,6 +196,7 @@ Route::group('admin', function () {
|
|||||||
Route::get('/deplist', 'admin/deplist');
|
Route::get('/deplist', 'admin/deplist');
|
||||||
Route::get('/refresh_deplist', 'admin/refresh_deplist');
|
Route::get('/refresh_deplist', 'admin/refresh_deplist');
|
||||||
Route::get('/cleancache', 'admin/cleancache');
|
Route::get('/cleancache', 'admin/cleancache');
|
||||||
|
Route::any('/ssl', 'admin/ssl');
|
||||||
|
|
||||||
})->middleware(\app\middleware\CheckAdmin::class);
|
})->middleware(\app\middleware\CheckAdmin::class);
|
||||||
|
|
||||||
|
|||||||
129
wiki/aapanel.md
Normal file
129
wiki/aapanel.md
Normal file
@ -0,0 +1,129 @@
|
|||||||
|
# aapanel面板官方更新包修改记录
|
||||||
|
|
||||||
|
查询最新版本号:https://brandnew.aapanel.com/api/panel/getLatestOfficialVersion
|
||||||
|
|
||||||
|
官方更新包下载链接:http://download.bt.cn/install/update/LinuxPanel_EN-版本号.zip
|
||||||
|
|
||||||
|
假设搭建的宝塔第三方云端网址是 http://www.example.com
|
||||||
|
|
||||||
|
- 将class文件夹里面所有的.so文件删除
|
||||||
|
|
||||||
|
- 将aapanel/PluginLoader.py复制到class文件夹
|
||||||
|
|
||||||
|
- 批量解密模块文件:执行 php think decrypt classdir <面板class文件夹路径>
|
||||||
|
|
||||||
|
php think decrypt classdir <面板class_v2文件夹路径>
|
||||||
|
|
||||||
|
- 全局搜索替换 https://wafapi2.aapanel.com => http://www.example.com(需排除task.py、ipsModel.py、js文件),https://wafapi.aapanel.com => http://www.example.com
|
||||||
|
|
||||||
|
- 全局搜索替换 https://node.aapanel.com/install/update_7.x_en.sh => http://www.example.com/install/update_7.x_en.sh
|
||||||
|
|
||||||
|
https://node.aapanel.com/install/update_pro_en.sh => http://www.example.com/install/update_7.x_en.sh
|
||||||
|
|
||||||
|
- 搜索并删除提交异常报告的代码 bt_error/index.php
|
||||||
|
|
||||||
|
- class/ajax.py、class_v2/ajax_v2.py 文件:
|
||||||
|
|
||||||
|
\#是否执行升级程序 下面的 public.get_url() 改成 public.OfficialApiBase()
|
||||||
|
|
||||||
|
__official_url = 'https://www.aapanel.com' 改成 http://www.example.com
|
||||||
|
|
||||||
|
class/jobs.py、class_v2/jobs_v2.py 文件:
|
||||||
|
|
||||||
|
\#尝试升级到独立环境 下面的 public.get_url() 改成 public.OfficialApiBase()
|
||||||
|
|
||||||
|
class/system.py、class_v2/system_v2.py 文件:
|
||||||
|
|
||||||
|
RepPanel和UpdatePro方法内的 public.get_url() 改成 public.OfficialApiBase()
|
||||||
|
|
||||||
|
- class/public/common.py
|
||||||
|
|
||||||
|
def OfficialApiBase(): 改成 return 'http://www.example.com'
|
||||||
|
|
||||||
|
def load_soft_list 去除 if force 部分
|
||||||
|
|
||||||
|
plugin_list_data = PluginLoader.get_plugin_list(0) 部分改成 plugin_list_data = PluginLoader.get_plugin_list(force)
|
||||||
|
|
||||||
|
在 def check_domain_cloud(domain): 这一行下面加上 return
|
||||||
|
|
||||||
|
在 def count_wp(): 这一行下面加上 return
|
||||||
|
|
||||||
|
在 def err_collect 这一行下面加上 return
|
||||||
|
|
||||||
|
在 def get_improvement(): 这一行下面加上 return False
|
||||||
|
|
||||||
|
在free_login_area方法内get_free_ips_area替换成get_ips_area
|
||||||
|
|
||||||
|
在login_send_body方法内,free_login_area(login_ip=server_ip_area的server_ip_area改成login_ip
|
||||||
|
|
||||||
|
在 def write_request_log(reques=None): 这一行下面加上 return
|
||||||
|
|
||||||
|
- class/panelPlugin.py、class_v2/panel_plugin_v2.py 文件,set_pyenv方法内,temp_file = public.readFile(filename)这行代码下面加上
|
||||||
|
|
||||||
|
```python
|
||||||
|
temp_file = temp_file.replace('http://download.bt.cn/install/public.sh', 'http://www.example.com/install/public.sh')
|
||||||
|
temp_file = temp_file.replace('https://download.bt.cn/install/public.sh', 'http://www.example.com/install/public.sh')
|
||||||
|
```
|
||||||
|
|
||||||
|
- class_v2/btdockerModelV2/flush_plugin.py 文件,删除clear_hosts()一行
|
||||||
|
|
||||||
|
- install/install_soft.sh 在. 执行之前加入以下代码
|
||||||
|
|
||||||
|
```shell
|
||||||
|
sed -i "s/http:\/\/download.bt.cn\/install\/public.sh/http:\/\/www.example.com\/install\/public.sh/" $name.sh
|
||||||
|
sed -i "s/https:\/\/download.bt.cn\/install\/public.sh/http:\/\/www.example.com\/install\/public.sh/" $name.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
- install/public.sh 用官网最新版的[public.sh](http://download.bt.cn/install/public.sh)替换,并去除最下面bt_check一行
|
||||||
|
|
||||||
|
- 去除无用的定时任务:task.py 文件 删除以下几行
|
||||||
|
|
||||||
|
"check_site_monitor": check_site_monitor,
|
||||||
|
|
||||||
|
"update_software_list": update_software_list,
|
||||||
|
|
||||||
|
"malicious_file_scanning": malicious_file_scanning,
|
||||||
|
|
||||||
|
"check_panel_msg": check_panel_msg,
|
||||||
|
|
||||||
|
"check_panel_auth": check_panel_auth,
|
||||||
|
|
||||||
|
"count_ssh_logs": count_ssh_logs,
|
||||||
|
|
||||||
|
"update_vulnerabilities": update_vulnerabilities,
|
||||||
|
|
||||||
|
"refresh_dockerapps": refresh_dockerapps,
|
||||||
|
|
||||||
|
"submit_email_statistics": submit_email_statistics,
|
||||||
|
|
||||||
|
"submit_module_call_statistics": submit_module_call_statistics,
|
||||||
|
|
||||||
|
"mailsys_domain_blecklisted_alarm": mailsys_domain_blecklisted_alarm,
|
||||||
|
|
||||||
|
- [可选]去除各种计算题:将bt.js里面的内容复制到 BTPanel/static/vite/oldjs/public_backup.js 末尾
|
||||||
|
|
||||||
|
- [可选]去除创建网站自动创建的垃圾文件:在class/panelSite.py、class_v2/panel_site_v2.py,分别删除
|
||||||
|
|
||||||
|
htaccess = self.sitePath + '/.htaccess'
|
||||||
|
|
||||||
|
index = self.sitePath + '/index.html'
|
||||||
|
|
||||||
|
doc404 = self.sitePath + '/404.html'
|
||||||
|
|
||||||
|
这3行及分别接下来的4行代码
|
||||||
|
|
||||||
|
- [可选]关闭未绑定域名提示页面:在class/panelSite.py、class_v2/panel_site_v2.py,root /www/server/nginx/html改成return 400
|
||||||
|
|
||||||
|
- [可选]上传文件默认选中覆盖,在BTPanel/static/vite/oldjs/upload-drog.js,id="all_operation"加checked属性
|
||||||
|
|
||||||
|
- [可选] BTPanel/static/vite/oldjs/site.js,优化SSL证书配置页面
|
||||||
|
|
||||||
|
- [可选]新版vite页面去除需求反馈、各种广告、计算题等,执行 php think cleanvitejs <面板BTPanel/static/js路径>
|
||||||
|
|
||||||
|
- 新增简体中文语言:修改BTPanel/languages/settings.json,并增加 zh/server.json、all/zh.json
|
||||||
|
|
||||||
|
|
||||||
|
解压安装包[panel_7_en.zip](http://download.bt.cn/install/src/panel_7_en.zip),将更新包改好的文件覆盖到里面,然后重新打包,即可更新安装包。(
|
||||||
|
|
||||||
|
别忘了删除class文件夹里面所有的.so文件)
|
||||||
|
|
||||||
45
wiki/btmonitor.md
Normal file
45
wiki/btmonitor.md
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
# 宝塔云监控安装包修改记录
|
||||||
|
|
||||||
|
查询最新版本号:https://api.bt.cn/bt_monitor/latest_version
|
||||||
|
|
||||||
|
安装包下载链接:http://download.bt.cn/install/src/bt-monitor-版本号.zip
|
||||||
|
|
||||||
|
- 删除core/include/c_loader/PluginLoader.so,hook_import/PluginLoader.so,将btmonitor/PluginLoader.py复制到这个文件夹
|
||||||
|
|
||||||
|
- 批量解密源码:执行 php think decrypt all <源码根目录>
|
||||||
|
|
||||||
|
极少数文件解密失败是正常现象可无视
|
||||||
|
|
||||||
|
- 全局搜索替换 https://api.bt.cn => http://www.example.com(需排除/bt_monitor/latest_agent_version、/bt_monitor/ip_info)
|
||||||
|
|
||||||
|
- 全局搜索替换 https://www.bt.cn/api/ => http://www.example.com/api/
|
||||||
|
|
||||||
|
- core/include/public.py 在
|
||||||
|
|
||||||
|
```python
|
||||||
|
def GetConfigValue(key):
|
||||||
|
```
|
||||||
|
|
||||||
|
这一行下面加上
|
||||||
|
|
||||||
|
```python
|
||||||
|
if key == 'home': return 'http://www.example.com'
|
||||||
|
```
|
||||||
|
|
||||||
|
def write_request_log(reques = None): 这一行下面加上 return
|
||||||
|
|
||||||
|
- core/include/basic_monitor.py
|
||||||
|
|
||||||
|
在 def report_module_logs(self, force=False): 这一行下面加上 return
|
||||||
|
|
||||||
|
在 def report_daily_active(self, force=False): 这一行下面加上 return
|
||||||
|
|
||||||
|
- modules/configModule/main.py
|
||||||
|
|
||||||
|
https://download.bt.cn => http://www.example.com
|
||||||
|
|
||||||
|
- update/update_btmonitor.sh 修改Install_Monitor方法内的download_Url变量
|
||||||
|
|
||||||
|
- init.sh https://download.bt.cn => http://www.example.com
|
||||||
|
|
||||||
|
- 减少压缩包体积:删除 static/js/ 目录下的map文件
|
||||||
@ -1,122 +0,0 @@
|
|||||||
#coding: utf-8
|
|
||||||
import public,os,sys,json
|
|
||||||
|
|
||||||
#获取插件列表(0/1)
|
|
||||||
def get_plugin_list(force = 0):
|
|
||||||
api_root_url = 'https://api.bt.cn'
|
|
||||||
api_url = api_root_url+ '/panel/get_plugin_list'
|
|
||||||
cache_file = 'data/plugin_list.json'
|
|
||||||
|
|
||||||
if force==0 and os.path.exists(cache_file):
|
|
||||||
jsonData = public.readFile(cache_file)
|
|
||||||
softList = json.loads(jsonData)
|
|
||||||
else:
|
|
||||||
try:
|
|
||||||
jsonData = public.HttpGet(api_url)
|
|
||||||
except Exception as ex:
|
|
||||||
raise public.error_conn_cloud(str(ex))
|
|
||||||
softList = json.loads(jsonData)
|
|
||||||
if type(softList)!=dict or 'list' not in softList: raise Exception('云端插件列表获取失败')
|
|
||||||
public.writeFile(cache_file, jsonData)
|
|
||||||
return softList
|
|
||||||
|
|
||||||
#获取授权状态() 返回:0.免费版 1.专业版 2.企业版 -1.获取失败
|
|
||||||
def get_auth_state():
|
|
||||||
try:
|
|
||||||
softList = get_plugin_list()
|
|
||||||
if softList['ltd'] > -1:
|
|
||||||
return 2
|
|
||||||
elif softList['pro'] > -1:
|
|
||||||
return 1
|
|
||||||
else:
|
|
||||||
return 0
|
|
||||||
except:
|
|
||||||
return -1
|
|
||||||
|
|
||||||
#执行插件方法(插件名,方法名,参数)
|
|
||||||
def plugin_run(plugin_name, def_name, args):
|
|
||||||
if not plugin_name or not def_name: return public.returnMsg(False,'插件名称和插件方法名称不能为空!')
|
|
||||||
if not path_check(plugin_name) or not path_check(def_name): return public.returnMsg(False,'插件名或方法名不能包含特殊符号!')
|
|
||||||
p_path = public.get_plugin_path(plugin_name)
|
|
||||||
if not os.path.exists(p_path + '/index.php') and not os.path.exists(p_path + '/%s_main.py' % plugin_name): return public.returnMsg(False,'插件不存在!')
|
|
||||||
|
|
||||||
is_php = os.path.exists(p_path + '/index.php')
|
|
||||||
if not is_php:
|
|
||||||
public.package_path_append(p_path)
|
|
||||||
plugin_main = __import__(plugin_name + '_main')
|
|
||||||
try:
|
|
||||||
if sys.version_info[0] == 2:
|
|
||||||
reload(plugin_main)
|
|
||||||
else:
|
|
||||||
from imp import reload
|
|
||||||
reload(plugin_main)
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
plu = eval('plugin_main.' + plugin_name + '_main()')
|
|
||||||
if not hasattr(plu, def_name):
|
|
||||||
return public.returnMsg(False,'在[%s]插件中找不到[%s]方法' % (plugin_name,def_name))
|
|
||||||
|
|
||||||
if 'plugin_get_object' in args and args.plugin_get_object == 1:
|
|
||||||
if not is_php:
|
|
||||||
return getattr(plu, def_name)
|
|
||||||
else:
|
|
||||||
return None
|
|
||||||
else:
|
|
||||||
if not is_php:
|
|
||||||
data = eval('plu.' + def_name + '(args)')
|
|
||||||
else:
|
|
||||||
import panelPHP
|
|
||||||
args.s = def_name
|
|
||||||
args.name = plugin_name
|
|
||||||
data = panelPHP.panelPHP(plugin_name).exec_php_script(args)
|
|
||||||
return data
|
|
||||||
|
|
||||||
#执行模块方法(模块名,方法名,参数)
|
|
||||||
def module_run(mod_name, def_name, args):
|
|
||||||
if not mod_name or not def_name: return public.returnMsg(False,'模块名称和模块方法名称不能为空!')
|
|
||||||
if not path_check(mod_name) or not path_check(def_name): return public.returnMsg(False,'模块名或方法名不能包含特殊符号!')
|
|
||||||
|
|
||||||
if 'model_index' in args:
|
|
||||||
if args.model_index:
|
|
||||||
mod_file = "{}/{}Model/{}Model.py".format(public.get_class_path(),args.model_index,mod_name)
|
|
||||||
else:
|
|
||||||
mod_file = "{}/projectModel/{}Model.py".format(public.get_class_path(),mod_name)
|
|
||||||
else:
|
|
||||||
module_list = get_module_list()
|
|
||||||
for module_dir in module_list:
|
|
||||||
mod_file = "{}/{}/{}Model.py".format(public.get_class_path(),module_dir,mod_name)
|
|
||||||
if os.path.exists(mod_file): break
|
|
||||||
|
|
||||||
if not os.path.exists(mod_file):
|
|
||||||
return public.returnMsg(False,'模块[%s]不存在' % mod_name)
|
|
||||||
|
|
||||||
def_object = public.get_script_object(mod_file)
|
|
||||||
if not def_object: return public.returnMsg(False,'模块[%s]不存在!' % mod_name)
|
|
||||||
try:
|
|
||||||
run_object = getattr(def_object.main(),def_name,None)
|
|
||||||
except:
|
|
||||||
return public.returnMsg(False,'模块入口实例化失败' % mod_name)
|
|
||||||
if not run_object: return public.returnMsg(False,'在[%s]模块中找不到[%s]方法' % (mod_name,def_name))
|
|
||||||
if 'module_get_object' in args and args.module_get_object == 1:
|
|
||||||
return run_object
|
|
||||||
result = run_object(args)
|
|
||||||
return result
|
|
||||||
|
|
||||||
#获取模块文件夹列表
|
|
||||||
def get_module_list():
|
|
||||||
list = []
|
|
||||||
class_path = public.get_class_path()
|
|
||||||
f_list = os.listdir(class_path)
|
|
||||||
for fname in f_list:
|
|
||||||
f_path = class_path+'/'+fname
|
|
||||||
if os.path.isdir(f_path) and len(fname) > 6 and fname.find('.') == -1 and fname.find('Model') != -1:
|
|
||||||
list.append(fname)
|
|
||||||
return list
|
|
||||||
|
|
||||||
#检查路径是否合法
|
|
||||||
def path_check(path):
|
|
||||||
list = ["./","..",",",";",":","?","'","\"","<",">","|","\\","\n","\r","\t","\b","\a","\f","\v","*","%","&","$","#","@","!","~","`","^","(",")","+","=","{","}","[","]"]
|
|
||||||
for i in path:
|
|
||||||
if i in list:
|
|
||||||
return False
|
|
||||||
return True
|
|
||||||
408
wiki/files/aapanel/PluginLoader.py
Normal file
408
wiki/files/aapanel/PluginLoader.py
Normal file
@ -0,0 +1,408 @@
|
|||||||
|
#coding: utf-8
|
||||||
|
# +-------------------------------------------------------------------
|
||||||
|
# | 宝塔Linux面板
|
||||||
|
# +-------------------------------------------------------------------
|
||||||
|
# | Copyright (c) 2015-2099 宝塔软件(http://bt.cn) All rights reserved.
|
||||||
|
# +-------------------------------------------------------------------
|
||||||
|
# | Author: hwliang <hwl@bt.cn>
|
||||||
|
# +-------------------------------------------------------------------
|
||||||
|
|
||||||
|
#+--------------------------------------------------------------------
|
||||||
|
#| 插件和模块加载器
|
||||||
|
#+--------------------------------------------------------------------
|
||||||
|
|
||||||
|
import public,os,sys,json,hashlib
|
||||||
|
|
||||||
|
def plugin_run(plugin_name,def_name,args):
|
||||||
|
'''
|
||||||
|
@name 执行插件方法
|
||||||
|
@param plugin_name<string> 插件名称
|
||||||
|
@param def_name<string> 方法名称
|
||||||
|
@param args<dict_obj> 参数对像
|
||||||
|
@return mixed
|
||||||
|
'''
|
||||||
|
if not plugin_name or not def_name: return public.returnMsg(False,'parameter incorrect: module_name and def_name cannot be empty.')
|
||||||
|
|
||||||
|
# 获取插件目录
|
||||||
|
plugin_path = public.get_plugin_path(plugin_name)
|
||||||
|
is_php = os.path.exists(os.path.join(plugin_path,'index.php'))
|
||||||
|
|
||||||
|
# 检查插件目录是否合法
|
||||||
|
if is_php:
|
||||||
|
plugin_file = os.path.join(plugin_path,'index.php')
|
||||||
|
else:
|
||||||
|
plugin_file = os.path.join(plugin_path, plugin_name + '_main.py')
|
||||||
|
if not public.path_safe_check(plugin_file): return public.returnMsg(False,'parameter incorrect: module_name and def_name cannot contains special symbols.')
|
||||||
|
|
||||||
|
# 检查插件入口文件是否存在
|
||||||
|
if not os.path.exists(plugin_file): return public.returnMsg(False,'plugin not found')
|
||||||
|
|
||||||
|
# 添加插件目录到系统路径
|
||||||
|
public.sys_path_append(plugin_path)
|
||||||
|
|
||||||
|
if not is_php:
|
||||||
|
# 引用插件入口文件
|
||||||
|
_name = "{}_main".format(plugin_name)
|
||||||
|
plugin_main = __import__(_name)
|
||||||
|
|
||||||
|
# 检查类名是否符合规范
|
||||||
|
if not hasattr(plugin_main,_name):
|
||||||
|
return public.returnMsg(False,'plugin class name is invalid')
|
||||||
|
|
||||||
|
try:
|
||||||
|
if sys.version_info[0] == 2:
|
||||||
|
reload(plugin_main)
|
||||||
|
else:
|
||||||
|
from imp import reload
|
||||||
|
reload(plugin_main)
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# 实例化插件类
|
||||||
|
plugin_obj = getattr(plugin_main,_name)()
|
||||||
|
|
||||||
|
# 检查方法是否存在
|
||||||
|
if not hasattr(plugin_obj,def_name):
|
||||||
|
return public.returnMsg(False,'not find method [%s] in plugin [%s]' % (def_name,plugin_name))
|
||||||
|
|
||||||
|
if args is not None and 'plugin_get_object' in args and args.plugin_get_object == 1:
|
||||||
|
return getattr(plugin_obj, def_name)
|
||||||
|
|
||||||
|
# 执行方法
|
||||||
|
return getattr(plugin_obj,def_name)(args)
|
||||||
|
else:
|
||||||
|
if args is not None and 'plugin_get_object' in args and args.plugin_get_object == 1:
|
||||||
|
return None
|
||||||
|
import panelPHP
|
||||||
|
args.s = def_name
|
||||||
|
args.name = plugin_name
|
||||||
|
return panelPHP.panelPHP(plugin_name).exec_php_script(args)
|
||||||
|
|
||||||
|
|
||||||
|
def get_module_list():
|
||||||
|
'''
|
||||||
|
@name 获取模块列表
|
||||||
|
@return list
|
||||||
|
'''
|
||||||
|
module_list = []
|
||||||
|
class_path = public.get_class_path()
|
||||||
|
for name in os.listdir(class_path):
|
||||||
|
path = os.path.join(class_path,name)
|
||||||
|
# 过滤无效文件
|
||||||
|
if not name or name.endswith('.py') or name[0] == '.' or not name.endswith('Model') or os.path.isfile(path):continue
|
||||||
|
module_list.append(name)
|
||||||
|
return module_list
|
||||||
|
|
||||||
|
def module_run(module_name,def_name,args):
|
||||||
|
'''
|
||||||
|
@name 执行模块方法
|
||||||
|
@param module_name<string> 模块名称
|
||||||
|
@param def_name<string> 方法名称
|
||||||
|
@param args<dict_obj> 参数对像
|
||||||
|
@return mixed
|
||||||
|
'''
|
||||||
|
if not module_name or not def_name: return public.returnMsg(False,'parameter incorrect: module_name and def_name cannot be empty.')
|
||||||
|
model_index = args.get('model_index',None)
|
||||||
|
class_path = public.get_class_path()
|
||||||
|
panel_path = public.get_panel_path()
|
||||||
|
|
||||||
|
module_file = None
|
||||||
|
if 'model_index' in args:
|
||||||
|
# 新模块目录
|
||||||
|
if model_index in ['mod']:
|
||||||
|
module_file = os.path.join(panel_path,'mod','project',module_name + 'Mod.py')
|
||||||
|
elif model_index:
|
||||||
|
# 旧模块目录
|
||||||
|
module_file = os.path.join(class_path,model_index+"Model",module_name + 'Model.py')
|
||||||
|
else:
|
||||||
|
module_file = os.path.join(class_path,"projectModel",module_name + 'Model.py')
|
||||||
|
else:
|
||||||
|
# 如果没指定模块名称,则遍历所有模块目录
|
||||||
|
module_list = get_module_list()
|
||||||
|
for name in module_list:
|
||||||
|
module_file = os.path.join(class_path,name,module_name + 'Model.py')
|
||||||
|
if os.path.exists(module_file): break
|
||||||
|
|
||||||
|
# 判断模块入口文件是否存在
|
||||||
|
if not os.path.exists(module_file):
|
||||||
|
return public.returnMsg(False,'module file [%s] not exist' % module_name)
|
||||||
|
|
||||||
|
# 判断模块路径是否合法
|
||||||
|
if not public.path_safe_check(module_file):
|
||||||
|
return public.returnMsg(False,'parameter incorrect: module_name and def_name cannot contains special symbols.')
|
||||||
|
|
||||||
|
def_object = public.get_script_object(module_file)
|
||||||
|
if not def_object: return public.returnMsg(False,'module [%s] not found' % module_name)
|
||||||
|
|
||||||
|
# 模块实例化并返回方法对象
|
||||||
|
try:
|
||||||
|
run_object = getattr(def_object.main(),def_name,None)
|
||||||
|
except:
|
||||||
|
return public.returnMsg(False,'module [%s] failed to instance class' % module_name)
|
||||||
|
if not run_object: return public.returnMsg(False,'not found method [%s] in module [%s]' % (def_name,module_name))
|
||||||
|
|
||||||
|
if 'module_get_object' in args and args.module_get_object == 1:
|
||||||
|
return run_object
|
||||||
|
|
||||||
|
# 执行方法
|
||||||
|
result = run_object(args)
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def get_plugin_list(upgrade_force = False):
|
||||||
|
'''
|
||||||
|
@name 获取插件列表
|
||||||
|
@param upgrade_force<bool> 是否强制重新获取列表
|
||||||
|
@return dict
|
||||||
|
'''
|
||||||
|
|
||||||
|
api_root_url = public.OfficialApiBase()
|
||||||
|
api_url = api_root_url+ '/api/panel/getSoftListEn'
|
||||||
|
panel_path = public.get_panel_path()
|
||||||
|
data_path = os.path.join(panel_path,'data')
|
||||||
|
|
||||||
|
if not os.path.exists(data_path):
|
||||||
|
os.makedirs(data_path,384)
|
||||||
|
|
||||||
|
plugin_list = {}
|
||||||
|
plugin_list_file = os.path.join(data_path,'plugin_list.json')
|
||||||
|
if os.path.exists(plugin_list_file) and not upgrade_force:
|
||||||
|
plugin_list_body = public.readFile(plugin_list_file)
|
||||||
|
try:
|
||||||
|
plugin_list = json.loads(plugin_list_body)
|
||||||
|
except:
|
||||||
|
plugin_list = {}
|
||||||
|
|
||||||
|
if not os.path.exists(plugin_list_file) or upgrade_force or not plugin_list:
|
||||||
|
try:
|
||||||
|
res = public.HttpGet(api_url)
|
||||||
|
except Exception as ex:
|
||||||
|
raise public.error_conn_cloud(str(ex))
|
||||||
|
if not res: raise Exception(False,'failed to get soft list')
|
||||||
|
|
||||||
|
plugin_list = json.loads(res)
|
||||||
|
if type(plugin_list)!=dict or 'list' not in plugin_list:
|
||||||
|
if type(plugin_list)==str:
|
||||||
|
raise Exception(plugin_list)
|
||||||
|
else:
|
||||||
|
raise Exception('failed to parse soft list')
|
||||||
|
content = json.dumps(plugin_list)
|
||||||
|
public.writeFile(plugin_list_file,content)
|
||||||
|
|
||||||
|
plugin_bin_file = os.path.join(data_path,'plugin_bin.pl')
|
||||||
|
encode_content = __encode_plugin_list(content)
|
||||||
|
if encode_content:
|
||||||
|
public.writeFile(plugin_bin_file,encode_content)
|
||||||
|
|
||||||
|
return plugin_list
|
||||||
|
|
||||||
|
def __encode_plugin_list(content):
|
||||||
|
try:
|
||||||
|
userInfo = public.get_user_info()
|
||||||
|
if not userInfo or 'server_id' not in userInfo: return None
|
||||||
|
block_size = 51200
|
||||||
|
uid = str(userInfo['uid'])
|
||||||
|
server_id = userInfo['server_id']
|
||||||
|
key = server_id[10:26] + uid + server_id
|
||||||
|
key = hashlib.md5(key.encode()).hexdigest()
|
||||||
|
iv = key + server_id
|
||||||
|
iv = hashlib.md5(iv.encode()).hexdigest()
|
||||||
|
key = key[8:24]
|
||||||
|
iv = iv[8:24]
|
||||||
|
blocks = [content[i:i + block_size] for i in range(0, len(content), block_size)]
|
||||||
|
encrypted_content = ''
|
||||||
|
for block in blocks:
|
||||||
|
encrypted_content += __aes_encrypt(block, key, iv) + '\n'
|
||||||
|
return encrypted_content
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
return None
|
||||||
|
|
||||||
|
def get_module(filename):
|
||||||
|
if not filename: return public.returnMsg(False,'parameter error: get_module(filename<str>)')
|
||||||
|
if filename[0:2] == './': return public.returnMsg(False,'filename cannot be relative path.')
|
||||||
|
if not public.path_safe_check(filename): return public.returnMsg(False,'filename cannot contains special symbols.')
|
||||||
|
if not os.path.exists(filename): return public.returnMsg(False,'file does not exist')
|
||||||
|
return __get_class_module(filename)
|
||||||
|
|
||||||
|
def __get_class_module(filename):
|
||||||
|
_obj = sys.modules.get(filename, None)
|
||||||
|
if _obj: return _obj
|
||||||
|
_code = public.readFile(filename)
|
||||||
|
if _code.find('import') == -1:
|
||||||
|
en_arr = _code.split('\n')
|
||||||
|
de_text = ''
|
||||||
|
for data in en_arr:
|
||||||
|
data = str.strip(data)
|
||||||
|
if not data: continue
|
||||||
|
de_text += __aes_decrypt_module(data)
|
||||||
|
_code = de_text
|
||||||
|
if not _code or _code.find('import') == -1:
|
||||||
|
return public.returnMsg(False,'load failed: decode error')
|
||||||
|
_code_object = compile(_code, filename, 'exec')
|
||||||
|
from types import ModuleType
|
||||||
|
_obj = sys.modules.setdefault(filename, ModuleType(filename))
|
||||||
|
_obj.__file__ = filename
|
||||||
|
_obj.__package__ = ''
|
||||||
|
exec(_code_object, _obj.__dict__)
|
||||||
|
return _obj
|
||||||
|
|
||||||
|
def start_total():
|
||||||
|
'''
|
||||||
|
@name 启动统计服务
|
||||||
|
@return dict
|
||||||
|
'''
|
||||||
|
pass
|
||||||
|
|
||||||
|
def get_soft_list(args):
|
||||||
|
'''
|
||||||
|
@name 获取软件列表
|
||||||
|
@param args<dict_obj> 参数对像
|
||||||
|
@return dict
|
||||||
|
'''
|
||||||
|
pass
|
||||||
|
|
||||||
|
def db_encrypt(data):
|
||||||
|
'''
|
||||||
|
@name 数据库加密
|
||||||
|
@param args<dict_obj> 参数对像
|
||||||
|
@return dict
|
||||||
|
'''
|
||||||
|
try:
|
||||||
|
key = __get_db_sgin()
|
||||||
|
iv = __get_db_iv()
|
||||||
|
str_arr = data.split('\n')
|
||||||
|
res_str = ''
|
||||||
|
for data in str_arr:
|
||||||
|
if not data: continue
|
||||||
|
res_str += __aes_encrypt(data, key, iv)
|
||||||
|
except:
|
||||||
|
res_str = data
|
||||||
|
result = {
|
||||||
|
'status' : True,
|
||||||
|
'msg' : res_str
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
|
||||||
|
def db_decrypt(data):
|
||||||
|
'''
|
||||||
|
@name 数据库解密
|
||||||
|
@param args<dict_obj> 参数对像
|
||||||
|
@return dict
|
||||||
|
'''
|
||||||
|
try:
|
||||||
|
key = __get_db_sgin()
|
||||||
|
iv = __get_db_iv()
|
||||||
|
str_arr = data.split('\n')
|
||||||
|
res_str = ''
|
||||||
|
for data in str_arr:
|
||||||
|
if not data: continue
|
||||||
|
res_str += __aes_decrypt(data, key, iv)
|
||||||
|
except:
|
||||||
|
res_str = data
|
||||||
|
result = {
|
||||||
|
'status' : True,
|
||||||
|
'msg' : res_str
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
|
||||||
|
def __get_db_sgin():
|
||||||
|
keystr = '3gP7+k_7lSNg3$+Fj!PKW+6$KYgHtw#R'
|
||||||
|
key = ''
|
||||||
|
for i in range(31):
|
||||||
|
if i & 1 == 0:
|
||||||
|
key += keystr[i]
|
||||||
|
return key
|
||||||
|
|
||||||
|
def __get_db_iv():
|
||||||
|
div_file = "{}/data/div.pl".format(public.get_panel_path())
|
||||||
|
if not os.path.exists(div_file):
|
||||||
|
str = public.GetRandomString(16)
|
||||||
|
str = __aes_encrypt_module(str)
|
||||||
|
div = public.get_div(str)
|
||||||
|
public.WriteFile(div_file, div)
|
||||||
|
if os.path.exists(div_file):
|
||||||
|
div = public.ReadFile(div_file)
|
||||||
|
div = __aes_decrypt_module(div)
|
||||||
|
else:
|
||||||
|
keystr = '4jHCpBOFzL4*piTn^-4IHBhj-OL!fGlB'
|
||||||
|
div = ''
|
||||||
|
for i in range(31):
|
||||||
|
if i & 1 == 0:
|
||||||
|
div += keystr[i]
|
||||||
|
return div
|
||||||
|
|
||||||
|
def __aes_encrypt_module(data):
|
||||||
|
key = 'Z2B87NEAS2BkxTrh'
|
||||||
|
iv = 'WwadH66EGWpeeTT6'
|
||||||
|
return __aes_encrypt(data, key, iv)
|
||||||
|
|
||||||
|
def __aes_decrypt_module(data):
|
||||||
|
key = 'Z2B87NEAS2BkxTrh'
|
||||||
|
iv = 'WwadH66EGWpeeTT6'
|
||||||
|
return __aes_decrypt(data, key, iv)
|
||||||
|
|
||||||
|
def __aes_decrypt(data, key, iv):
|
||||||
|
from Crypto.Cipher import AES
|
||||||
|
import base64
|
||||||
|
encodebytes = base64.decodebytes(data.encode('utf-8'))
|
||||||
|
aes = AES.new(key.encode('utf-8'), AES.MODE_CBC, iv.encode('utf-8'))
|
||||||
|
de_text = aes.decrypt(encodebytes)
|
||||||
|
unpad = lambda s: s[0:-s[-1]]
|
||||||
|
de_text = unpad(de_text)
|
||||||
|
return de_text.decode('utf-8')
|
||||||
|
|
||||||
|
def __aes_encrypt(data, key, iv):
|
||||||
|
from Crypto.Cipher import AES
|
||||||
|
import base64
|
||||||
|
data = (lambda s: s + (16 - len(s) % 16) * chr(16 - len(s) % 16).encode('utf-8'))(data.encode('utf-8'))
|
||||||
|
aes = AES.new(key.encode('utf8'), AES.MODE_CBC, iv.encode('utf8'))
|
||||||
|
encryptedbytes = aes.encrypt(data)
|
||||||
|
en_text = base64.b64encode(encryptedbytes)
|
||||||
|
return en_text.decode('utf-8')
|
||||||
|
|
||||||
|
def plugin_end():
|
||||||
|
'''
|
||||||
|
@name 插件到期处理
|
||||||
|
@return dict
|
||||||
|
'''
|
||||||
|
pass
|
||||||
|
|
||||||
|
def daemon_task():
|
||||||
|
'''
|
||||||
|
@name 后台任务守护
|
||||||
|
@return dict
|
||||||
|
'''
|
||||||
|
pass
|
||||||
|
|
||||||
|
def daemon_panel():
|
||||||
|
'''
|
||||||
|
@name 面板守护
|
||||||
|
@return dict
|
||||||
|
'''
|
||||||
|
pass
|
||||||
|
|
||||||
|
def flush_auth_key():
|
||||||
|
'''
|
||||||
|
@name 刷新授权密钥
|
||||||
|
@return dict
|
||||||
|
'''
|
||||||
|
pass
|
||||||
|
|
||||||
|
def get_auth_state():
|
||||||
|
'''
|
||||||
|
@name 获取授权状态
|
||||||
|
@return 返回:0.免费版 1.专业版 2.企业版 -1.获取失败
|
||||||
|
'''
|
||||||
|
try:
|
||||||
|
softList = get_plugin_list()
|
||||||
|
if softList['ltd'] > -1:
|
||||||
|
return 2
|
||||||
|
elif softList['pro'] > -1:
|
||||||
|
return 1
|
||||||
|
else:
|
||||||
|
return 0
|
||||||
|
except:
|
||||||
|
return -1
|
||||||
|
|
||||||
|
|
||||||
83
wiki/files/aapanel/bt.js
Normal file
83
wiki/files/aapanel/bt.js
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
/*
|
||||||
|
*宝塔面板去除各种计算题与延时等待
|
||||||
|
*/
|
||||||
|
if("undefined" != typeof bt && bt.hasOwnProperty("show_confirm")){
|
||||||
|
bt.show_confirm = function(title, msg, fun, error) {
|
||||||
|
layer.open({
|
||||||
|
type: 1,
|
||||||
|
title: title,
|
||||||
|
area: "350px",
|
||||||
|
closeBtn: 2,
|
||||||
|
shadeClose: true,
|
||||||
|
btn: [lan['public'].ok, lan['public'].cancel],
|
||||||
|
content: "<div class='bt-form webDelete pd20'>\
|
||||||
|
<p>" + msg + "</p>" + (error || '') + "\
|
||||||
|
</div>",
|
||||||
|
yes: function (index, layero) {
|
||||||
|
layer.close(index);
|
||||||
|
if (fun) fun();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if("undefined" != typeof bt && bt.hasOwnProperty("prompt_confirm")){
|
||||||
|
bt.prompt_confirm = function (title, msg, callback) {
|
||||||
|
layer.open({
|
||||||
|
type: 1,
|
||||||
|
title: title,
|
||||||
|
area: "480px",
|
||||||
|
closeBtn: 2,
|
||||||
|
btn: ['OK', 'Cancel'],
|
||||||
|
content: "<div class='bt-form promptDelete pd20'>\
|
||||||
|
<p>" + msg + "</p>\
|
||||||
|
</div>",
|
||||||
|
yes: function (layers, index) {
|
||||||
|
layer.close(layers)
|
||||||
|
if (callback) callback()
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if("undefined" != typeof bt && bt.hasOwnProperty("compute_confirm")){
|
||||||
|
bt.compute_confirm = function (config, callback) {
|
||||||
|
layer.open({
|
||||||
|
type: 1,
|
||||||
|
title: config.title,
|
||||||
|
area: '430px',
|
||||||
|
closeBtn: 2,
|
||||||
|
shadeClose: true,
|
||||||
|
btn: [lan['public'].ok, lan['public'].cancel],
|
||||||
|
content:
|
||||||
|
'<div class="bt-form hint_confirm pd30">\
|
||||||
|
<div class="hint_title">\
|
||||||
|
<i class="hint-confirm-icon"></i>\
|
||||||
|
<div class="hint_con">' +
|
||||||
|
config.msg +
|
||||||
|
'</div>\
|
||||||
|
</div>\
|
||||||
|
</div>',
|
||||||
|
yes: function (layers, index) {
|
||||||
|
layer.close(layers)
|
||||||
|
if (callback) callback()
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function SafeMessage(j, h, g, f) {
|
||||||
|
if (f == undefined) f = '';
|
||||||
|
var mess = layer.open({
|
||||||
|
type: 1,
|
||||||
|
title: j,
|
||||||
|
area: "350px",
|
||||||
|
closeBtn: 2,
|
||||||
|
shadeClose: true,
|
||||||
|
content: "<div class='bt-form webDelete pd20 pb70'><p>" + h + "</p>" + f + "<div class='bt-form-submit-btn'><button type='button' class='btn btn-danger btn-sm bt-cancel'>"+lan.public.cancel+"</button> <button type='button' id='toSubmit' class='btn btn-success btn-sm' >"+lan.public.ok+"</button></div></div>"
|
||||||
|
});
|
||||||
|
$(".bt-cancel").click(function(){
|
||||||
|
layer.close(mess);
|
||||||
|
});
|
||||||
|
$("#toSubmit").click(function() {
|
||||||
|
layer.close(mess);
|
||||||
|
g();
|
||||||
|
})
|
||||||
|
}
|
||||||
420
wiki/files/bt.js
420
wiki/files/bt.js
@ -1,420 +0,0 @@
|
|||||||
/*
|
|
||||||
*宝塔面板去除各种计算题与延时等待
|
|
||||||
*/
|
|
||||||
if("undefined" != typeof bt && bt.hasOwnProperty("show_confirm")){
|
|
||||||
bt.show_confirm = function(title, msg, callback, error) {
|
|
||||||
layer.open({
|
|
||||||
type: 1,
|
|
||||||
title: title,
|
|
||||||
area: "365px",
|
|
||||||
closeBtn: 2,
|
|
||||||
shadeClose: true,
|
|
||||||
btn: [lan['public'].ok, lan['public'].cancel],
|
|
||||||
content: "<div class='bt-form webDelete pd20'>\
|
|
||||||
<p style='font-size:13px;word-break: break-all;margin-bottom: 5px;'>" + msg + "</p>" + (error || '') + "\
|
|
||||||
</div>",
|
|
||||||
yes: function (index, layero) {
|
|
||||||
layer.close(index);
|
|
||||||
if (callback) callback();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if("undefined" != typeof bt && bt.hasOwnProperty("prompt_confirm")){
|
|
||||||
bt.prompt_confirm = function (title, msg, callback) {
|
|
||||||
layer.open({
|
|
||||||
type: 1,
|
|
||||||
title: title,
|
|
||||||
area: "350px",
|
|
||||||
closeBtn: 2,
|
|
||||||
btn: ['确认', '取消'],
|
|
||||||
content: "<div class='bt-form promptDelete pd20'>\
|
|
||||||
<p>" + msg + "</p>\
|
|
||||||
</div>",
|
|
||||||
yes: function (layers, index) {
|
|
||||||
layer.close(layers)
|
|
||||||
if (callback) callback()
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if("undefined" != typeof database && database.hasOwnProperty("del_database")){
|
|
||||||
database.del_database = function (wid, dbname, obj, callback) {
|
|
||||||
var is_db_type = false, del_data = []
|
|
||||||
if (typeof wid === 'object') {
|
|
||||||
del_data = wid
|
|
||||||
is_db_type = wid.some(function (item) {
|
|
||||||
return item.db_type > 0
|
|
||||||
})
|
|
||||||
var ids = [];
|
|
||||||
for (var i = 0; i < wid.length; i++) {
|
|
||||||
ids.push(wid[i].id);
|
|
||||||
}
|
|
||||||
wid = ids
|
|
||||||
}
|
|
||||||
var type = $('.database-pos .tabs-item.active').data('type'),
|
|
||||||
title = '',
|
|
||||||
tips = '';
|
|
||||||
title = typeof dbname === "function" ? '批量删除数据库' : '删除数据库 - [ ' + dbname + ' ]';
|
|
||||||
tips = is_db_type || !recycle_bin_db_open || type !== 'mysql' ? '<span class="color-red">当前列表存在彻底删除后无法恢复的数据库</span>,请仔细查看列表,以防误删,是否继续操作?' : '当前列表数据库将迁移至数据库回收站,如需彻底删除请前往数据库回收站,是否继续操作?'
|
|
||||||
var arrs = wid instanceof Array ? wid : [wid]
|
|
||||||
var ids = JSON.stringify(arrs),
|
|
||||||
countDown = 9;
|
|
||||||
if (arrs.length == 1) countDown = 4
|
|
||||||
var loadT = bt.load('正在检测数据库数据信息,请稍候...'),
|
|
||||||
param = { url: 'database/' + bt.data.db_tab_name + '/check_del_data', data: { data: JSON.stringify({ ids: ids }) } }
|
|
||||||
if (bt.data.db_tab_name == 'mysql') param = { url: 'database?action=check_del_data', data: { ids: ids } }
|
|
||||||
bt_tools.send(param, function (res) {
|
|
||||||
loadT.close()
|
|
||||||
layer.open({
|
|
||||||
type: 1,
|
|
||||||
title: title,
|
|
||||||
area: '740px',
|
|
||||||
skin: 'verify_site_layer_info',
|
|
||||||
closeBtn: 2,
|
|
||||||
shadeClose: true,
|
|
||||||
content: '<div class="check_delete_site_main hint_confirm pd30">' +
|
|
||||||
"<div class='hint_title'>\
|
|
||||||
<i class=\'hint-confirm-icon\'></i>\
|
|
||||||
<div class=\'hint_con\'>"+ tips + "</div>\
|
|
||||||
</div>"+
|
|
||||||
'<div id="check_layer_content" class="ptb15">' +
|
|
||||||
'</div>' +
|
|
||||||
'<div class="check_layer_message">' +
|
|
||||||
(is_db_type ? '<span class="color-red">注意:远程数据库暂不支持数据库回收站,选中的数据库将彻底删除</span><br>' : '') +
|
|
||||||
(!recycle_bin_db_open ? '<span class="color-red">风险操作:当前数据库回收站未开启,删除数据库将永久消失</span><br>' : '')
|
|
||||||
+ '<span class="color-red">请仔细阅读以上要删除信息,防止数据库被误删</span></div>' +
|
|
||||||
'</div>',
|
|
||||||
btn: ['下一步', lan.public.cancel],
|
|
||||||
success: function (layers) {
|
|
||||||
setTimeout(function () { $(layers).css('top', ($(window).height() - $(layers).height()) / 2); }, 50)
|
|
||||||
var rdata = res.data,
|
|
||||||
newTime = parseInt(new Date().getTime() / 1000),
|
|
||||||
t_icon = ' <span class="glyphicon glyphicon-info-sign" style="color: red;width:15px;height: 15px;;vertical-align: middle;"></span>';
|
|
||||||
for (var j = 0; j < rdata.length; j++) {
|
|
||||||
for (var i = 0; i < del_data.length; i++) {
|
|
||||||
if (rdata[j].id == del_data[i].id) {
|
|
||||||
var is_time_rule = (newTime - rdata[j].st_time) > (86400 * 30) && (rdata[j].total > 1024 * 10),
|
|
||||||
is_database_rule = res.db_size <= rdata[j].total,
|
|
||||||
database_time = bt.format_data(rdata[j].st_time, 'yyyy-MM-dd'),
|
|
||||||
database_size = bt.format_size(rdata[j].total);
|
|
||||||
var f_size = database_size
|
|
||||||
var t_size = '注意:此数据库较大,可能为重要数据,请谨慎操作.\n数据库:' + database_size;
|
|
||||||
if (rdata[j].total < 2048) t_size = '注意事项:当前数据库不为空,可能为重要数据,请谨慎操作.\n数据库:' + database_size;
|
|
||||||
if (rdata[j].total === 0) t_size = '';
|
|
||||||
rdata[j]['t_size'] = t_size
|
|
||||||
rdata[j]['f_size'] = f_size
|
|
||||||
rdata[j]['database_time'] = database_time
|
|
||||||
rdata[j]['is_time_rule'] = is_time_rule
|
|
||||||
rdata[j]['is_database_rule'] = is_database_rule
|
|
||||||
rdata[j]['db_type'] = del_data[i].db_type
|
|
||||||
rdata[j]['conn_config'] = del_data[i].conn_config
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var filterData = rdata.filter(function (el) {
|
|
||||||
return ids.indexOf(el.id) != -1
|
|
||||||
})
|
|
||||||
bt_tools.table({
|
|
||||||
el: '#check_layer_content',
|
|
||||||
data: filterData,
|
|
||||||
height: '300px',
|
|
||||||
column: [
|
|
||||||
{ fid: 'name', title: '数据库名称' },
|
|
||||||
{
|
|
||||||
title: '数据库大小', template: function (row) {
|
|
||||||
return '<span class="' + (row.is_database_rule ? 'warning' : '') + '" style="width: 110px;" title="' + row.t_size + '">' + row.f_size + (row.is_database_rule ? t_icon : '') + '</span>'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '数据库位置', template: function (row) {
|
|
||||||
var type_column = '-'
|
|
||||||
switch (row.db_type) {
|
|
||||||
case 0:
|
|
||||||
type_column = '本地数据库'
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
case 2:
|
|
||||||
type_column = '远程数据库'
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return '<span style="width: 110px;" title="' + type_column + '">' + type_column + '</span>'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '创建时间', template: function (row) {
|
|
||||||
return '<span ' + (is_time_rule && row.total != 0 ? 'class="warning"' : '') + ' title="' + (row.is_time_rule && row.total != 0 ? '重要:此数据库创建时间较早,可能为重要数据,请谨慎操作.' : '') + '时间:' + row.database_time + '">' + row.database_time + '</span>'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '删除结果', align: 'right', template: function (row, index, ev, _that) {
|
|
||||||
var _html = ''
|
|
||||||
switch (row.db_type) {
|
|
||||||
case 0:
|
|
||||||
_html = type !== 'mysql' ? '彻底删除' : (!recycle_bin_db_open ? '彻底删除' : '移至回收站')
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
case 2:
|
|
||||||
_html = '彻底删除'
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return '<span style="width: 110px;" class="' + (_html === '彻底删除' ? 'warning' + (row.db_type > 0 ? ' remote_database' : '') : '') + '">' + _html + '</span>'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
success: function () {
|
|
||||||
if ($('.remote_database').length) {
|
|
||||||
$('.remote_database').each(function (index, el) {
|
|
||||||
var id = $(el).parent().parent().parent().index()
|
|
||||||
$('#check_layer_content tbody tr').eq(id).css('background-color', '#ff00000a')
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
},
|
|
||||||
yes: function (indes, layers) {
|
|
||||||
title = typeof dbname === "function" ? '二次验证信息,批量删除数据库' : '二次验证信息,删除数据库 - [ ' + dbname + ' ]';
|
|
||||||
if (type !== 'mysql') {
|
|
||||||
tips = '<span class="color-red">当前数据库暂不支持数据库回收站,删除后将无法恢复</span>,此操作不可逆,是否继续操作?';
|
|
||||||
} else {
|
|
||||||
tips = is_db_type ? '<span class="color-red">远程数据库不支持数据库回收站,删除后将无法恢复</span>,此操作不可逆,是否继续操作?' : recycle_bin_db_open ? '删除后如需彻底删除请前往数据库回收站,是否继续操作?' : '删除后可能会影响业务使用,此操作不可逆,是否继续操作?'
|
|
||||||
}
|
|
||||||
layer.open({
|
|
||||||
type: 1,
|
|
||||||
title: title,
|
|
||||||
icon: 0,
|
|
||||||
skin: 'delete_site_layer',
|
|
||||||
area: "530px",
|
|
||||||
closeBtn: 2,
|
|
||||||
shadeClose: true,
|
|
||||||
content: "<div class=\'bt-form webDelete hint_confirm pd30\' id=\'site_delete_form\'>" +
|
|
||||||
"<div class='hint_title'>\
|
|
||||||
<i class=\'hint-confirm-icon\'></i>\
|
|
||||||
<div class=\'hint_con\'>"+ tips + "</div>\
|
|
||||||
</div>"+
|
|
||||||
"<div style=\'color:red;margin:18px 0 18px 18px;font-size:14px;font-weight: bold;\'>注意:数据无价,请谨慎操作!!!" + (type === 'mysql' && !recycle_bin_db_open ? '<br>风险操作:当前数据库回收站未开启,删除数据库将永久消失!' : '') + "</div>"+
|
|
||||||
"</div>",
|
|
||||||
btn: ['确认删除', '取消删除'],
|
|
||||||
yes: function (indexs) {
|
|
||||||
var data = {
|
|
||||||
id: wid,
|
|
||||||
name: dbname
|
|
||||||
};
|
|
||||||
if (typeof dbname === "function") {
|
|
||||||
delete data.id;
|
|
||||||
delete data.name;
|
|
||||||
}
|
|
||||||
layer.close(indexs)
|
|
||||||
layer.close(indes)
|
|
||||||
if (typeof dbname === "function") {
|
|
||||||
dbname(data)
|
|
||||||
} else {
|
|
||||||
data.id = data.id[0]
|
|
||||||
bt.database.del_database(data, function (rdata) {
|
|
||||||
layer.closeAll()
|
|
||||||
if (callback) callback(rdata);
|
|
||||||
bt.msg(rdata);
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if("undefined" != typeof site && site.hasOwnProperty("del_site")){
|
|
||||||
site.del_site = function (wid, wname, callback) {
|
|
||||||
title = typeof wname === "function" ? '批量删除站点' : '删除站点 [ ' + wname + ' ]';
|
|
||||||
layer.open({
|
|
||||||
type: 1,
|
|
||||||
title: title,
|
|
||||||
icon: 0,
|
|
||||||
skin: 'delete_site_layer',
|
|
||||||
area: "440px",
|
|
||||||
closeBtn: 2,
|
|
||||||
shadeClose: true,
|
|
||||||
content: "<div class=\'bt-form webDelete pd30\' id=\'site_delete_form\'>" +
|
|
||||||
'<i class="layui-layer-ico layui-layer-ico0"></i>' +
|
|
||||||
"<div class=\'f13 check_title\'>是否要删除关联的FTP、数据库、站点目录!</div>" +
|
|
||||||
"<div class=\"check_type_group\">" +
|
|
||||||
"<label><input type=\"checkbox\" name=\"ftp\"><span>FTP</span></label>" +
|
|
||||||
"<label><input type=\"checkbox\" name=\"database\"><span>数据库</span>" + (!recycle_bin_db_open ? '<span class="glyphicon glyphicon-info-sign" style="color: red"></span>' : '') + "</label>" +
|
|
||||||
"<label><input type=\"checkbox\" name=\"path\"><span>站点目录</span>" + (!recycle_bin_open ? '<span class="glyphicon glyphicon-info-sign" style="color: red"></span>' : '') + "</label>" +
|
|
||||||
"</div>" +
|
|
||||||
"</div>",
|
|
||||||
btn: [lan.public.ok, lan.public.cancel],
|
|
||||||
success: function (layers, indexs) {
|
|
||||||
$(layers).find('.check_type_group label').hover(function () {
|
|
||||||
var name = $(this).find('input').attr('name');
|
|
||||||
if (name === 'database' && !recycle_bin_db_open) {
|
|
||||||
layer.tips('风险操作:当前数据库回收站未开启,删除数据库将永久消失!', this, { tips: [1, 'red'], time: 0 })
|
|
||||||
} else if (name === 'path' && !recycle_bin_open) {
|
|
||||||
layer.tips('风险操作:当前文件回收站未开启,删除站点目录将永久消失!', this, { tips: [1, 'red'], time: 0 })
|
|
||||||
}
|
|
||||||
}, function () {
|
|
||||||
layer.closeAll('tips');
|
|
||||||
});
|
|
||||||
},
|
|
||||||
yes: function (indexs) {
|
|
||||||
var data = { id: wid, webname: wname };
|
|
||||||
$('#site_delete_form input[type=checkbox]').each(function (index, item) {
|
|
||||||
if ($(item).is(':checked')) data[$(item).attr('name')] = 1
|
|
||||||
})
|
|
||||||
var is_database = data.hasOwnProperty('database'), is_path = data.hasOwnProperty('path'), is_ftp = data.hasOwnProperty('ftp');
|
|
||||||
if ((!is_database && !is_path) && (!is_ftp || is_ftp)) {
|
|
||||||
if (typeof wname === "function") {
|
|
||||||
wname(data)
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
bt.site.del_site(data, function (rdata) {
|
|
||||||
layer.close(indexs);
|
|
||||||
if (callback) callback(rdata);
|
|
||||||
bt.msg(rdata);
|
|
||||||
})
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if (typeof wname === "function") {
|
|
||||||
delete data.id;
|
|
||||||
delete data.webname;
|
|
||||||
}
|
|
||||||
layer.close(indexs)
|
|
||||||
var ids = JSON.stringify(wid instanceof Array ? wid : [wid]), countDown = typeof wname === 'string' ? 4 : 9;
|
|
||||||
title = typeof wname === "function" ? '二次验证信息,批量删除站点' : '二次验证信息,删除站点 [ ' + wname + ' ]';
|
|
||||||
var loadT = bt.load('正在检测站点数据信息,请稍候...')
|
|
||||||
bt.send('check_del_data', 'site/check_del_data', { ids: ids }, function (res) {
|
|
||||||
loadT.close()
|
|
||||||
layer.open({
|
|
||||||
type: 1,
|
|
||||||
title: title,
|
|
||||||
closeBtn: 2,
|
|
||||||
skin: 'verify_site_layer_info',
|
|
||||||
area: '740px',
|
|
||||||
content: '<div class="check_delete_site_main pd30">' +
|
|
||||||
'<i class="layui-layer-ico layui-layer-ico0"></i>' +
|
|
||||||
'<div class="check_layer_title">堡塔温馨提示您,请冷静几秒钟,确认以下要删除的数据。</div>' +
|
|
||||||
'<div class="check_layer_content">' +
|
|
||||||
'<div class="check_layer_item">' +
|
|
||||||
'<div class="check_layer_site"></div>' +
|
|
||||||
'<div class="check_layer_database"></div>' +
|
|
||||||
'</div>' +
|
|
||||||
'</div>' +
|
|
||||||
'<div class="check_layer_error ' + (is_database && data['database'] && !recycle_bin_db_open ? '' : 'hide') + '"><span class="glyphicon glyphicon-info-sign"></span>风险事项:当前未开启数据库回收站功能,删除数据库后,数据库将永久消失!</div>' +
|
|
||||||
'<div class="check_layer_error ' + (is_path && data['path'] && !recycle_bin_open ? '' : 'hide') + '"><span class="glyphicon glyphicon-info-sign"></span>风险事项:当前未开启文件回收站功能,删除站点目录后,站点目录将永久消失!</div>' +
|
|
||||||
'<div class="check_layer_message"><span style="color:red">注意:请仔细阅读以上要删除信息,防止网站数据被误删</span></div>' +
|
|
||||||
'</div>',
|
|
||||||
// recycle_bin_db_open &&
|
|
||||||
// recycle_bin_open &&
|
|
||||||
btn: ['确认删除', '取消删除'],
|
|
||||||
success: function (layers) {
|
|
||||||
var html = '', rdata = res.data;
|
|
||||||
for (var i = 0; i < rdata.length; i++) {
|
|
||||||
var item = rdata[i], newTime = parseInt(new Date().getTime() / 1000),
|
|
||||||
t_icon = '<span class="glyphicon glyphicon-info-sign" style="color: red;width:15px;height: 15px;;vertical-align: middle;"></span>';
|
|
||||||
|
|
||||||
site_html = (function (item) {
|
|
||||||
if (!is_path) return ''
|
|
||||||
var is_time_rule = (newTime - item.st_time) > (86400 * 30) && (item.total > 1024 * 10),
|
|
||||||
is_path_rule = res.file_size <= item.total,
|
|
||||||
dir_time = bt.format_data(item.st_time, 'yyyy-MM-dd'),
|
|
||||||
dir_size = bt.format_size(item.total);
|
|
||||||
|
|
||||||
var f_html = '<i ' + (is_path_rule ? 'class="warning"' : '') + ' style = "vertical-align: middle;" > ' + (item.limit ? '大于50MB' : dir_size) + '</i> ' + (is_path_rule ? t_icon : '');
|
|
||||||
var f_title = (is_path_rule ? '注意:此目录较大,可能为重要数据,请谨慎操作.\n' : '') + '目录:' + item.path + '(' + (item.limit ? '大于' : '') + dir_size + ')';
|
|
||||||
|
|
||||||
return '<div class="check_layer_site">' +
|
|
||||||
'<span title="站点:' + item.name + '">站点名:' + item.name + '</span>' +
|
|
||||||
'<span title="' + f_title + '" >目录:<span style="vertical-align: middle;max-width: 160px;width: auto;">' + item.path + '</span> (' + f_html + ')</span>' +
|
|
||||||
'<span title="' + (is_time_rule ? '注意:此站点创建时间较早,可能为重要数据,请谨慎操作.\n' : '') + '时间:' + dir_time + '">创建时间:<i ' + (is_time_rule ? 'class="warning"' : '') + '>' + dir_time + '</i></span>' +
|
|
||||||
'</div>'
|
|
||||||
}(item)),
|
|
||||||
database_html = (function (item) {
|
|
||||||
if (!is_database || !item.database) return '';
|
|
||||||
var is_time_rule = (newTime - item.st_time) > (86400 * 30) && (item.total > 1024 * 10),
|
|
||||||
is_database_rule = res.db_size <= item.database.total,
|
|
||||||
database_time = bt.format_data(item.database.st_time, 'yyyy-MM-dd'),
|
|
||||||
database_size = bt.format_size(item.database.total);
|
|
||||||
|
|
||||||
var f_size = '<i ' + (is_database_rule ? 'class="warning"' : '') + ' style = "vertical-align: middle;" > ' + database_size + '</i> ' + (is_database_rule ? t_icon : '');
|
|
||||||
var t_size = '注意:此数据库较大,可能为重要数据,请谨慎操作.\n数据库:' + database_size;
|
|
||||||
|
|
||||||
return '<div class="check_layer_database">' +
|
|
||||||
'<span title="数据库:' + item.database.name + '">数据库:' + item.database.name + '</span>' +
|
|
||||||
'<span title="' + t_size + '">大小:' + f_size + '</span>' +
|
|
||||||
'<span title="' + (is_time_rule && item.database.total != 0 ? '重要:此数据库创建时间较早,可能为重要数据,请谨慎操作.' : '') + '时间:' + database_time + '">创建时间:<i ' + (is_time_rule && item.database.total != 0 ? 'class="warning"' : '') + '>' + database_time + '</i></span>' +
|
|
||||||
'</div>'
|
|
||||||
}(item))
|
|
||||||
if ((site_html + database_html) !== '') html += '<div class="check_layer_item">' + site_html + database_html + '</div>';
|
|
||||||
}
|
|
||||||
if (html === '') html = '<div style="text-align: center;width: 100%;height: 100%;line-height: 300px;font-size: 15px;">无数据</div>'
|
|
||||||
$('.check_layer_content').html(html)
|
|
||||||
},
|
|
||||||
yes: function (indes, layers) {
|
|
||||||
if (typeof wname === "function") {
|
|
||||||
wname(data)
|
|
||||||
} else {
|
|
||||||
bt.site.del_site(data, function (rdata) {
|
|
||||||
layer.closeAll()
|
|
||||||
if (rdata.status) site.get_list();
|
|
||||||
if (callback) callback(rdata);
|
|
||||||
bt.msg(rdata);
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if("undefined" != typeof bt && bt.hasOwnProperty("firewall") && bt.firewall.hasOwnProperty("add_accept_port")){
|
|
||||||
bt.firewall.add_accept_port = function(type, port, ps, callback) {
|
|
||||||
var action = "AddDropAddress";
|
|
||||||
if (type == 'port') {
|
|
||||||
ports = port.split(':');
|
|
||||||
if (port.indexOf('-') != -1) ports = port.split('-');
|
|
||||||
for (var i = 0; i < ports.length; i++) {
|
|
||||||
if (!bt.check_port(ports[i])) {
|
|
||||||
layer.msg('可用端口范围:1-65535', { icon: 2 });
|
|
||||||
// layer.msg(lan.firewall.port_err, {
|
|
||||||
// icon: 5
|
|
||||||
// });
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
action = "AddAcceptPort";
|
|
||||||
}
|
|
||||||
|
|
||||||
loading = bt.load();
|
|
||||||
bt.send(action, 'firewall/' + action, { port: port, type: type, ps: ps }, function(rdata) {
|
|
||||||
loading.close();
|
|
||||||
if (callback) callback(rdata);
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
function SafeMessage(j, h, g, f) {
|
|
||||||
if(f == undefined) {
|
|
||||||
f = ""
|
|
||||||
}
|
|
||||||
var mess = layer.open({
|
|
||||||
type: 1,
|
|
||||||
title: j,
|
|
||||||
area: "350px",
|
|
||||||
closeBtn: 2,
|
|
||||||
shadeClose: true,
|
|
||||||
content: "<div class='bt-form webDelete pd20 pb70'><p>" + h + "</p>" + f + "<div class='bt-form-submit-btn'><button type='button' class='btn btn-danger btn-sm bt-cancel'>"+lan.public.cancel+"</button> <button type='button' id='toSubmit' class='btn btn-success btn-sm' >"+lan.public.ok+"</button></div></div>"
|
|
||||||
});
|
|
||||||
$(".bt-cancel").click(function(){
|
|
||||||
layer.close(mess);
|
|
||||||
});
|
|
||||||
$("#toSubmit").click(function() {
|
|
||||||
layer.close(mess);
|
|
||||||
g();
|
|
||||||
})
|
|
||||||
}
|
|
||||||
$(document).ready(function () {
|
|
||||||
if($('#updata_pro_info').length>0){
|
|
||||||
$('#updata_pro_info').html('');
|
|
||||||
bt.set_cookie('productPurchase', 1);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
103
wiki/files/btmonitor/PluginLoader.py
Normal file
103
wiki/files/btmonitor/PluginLoader.py
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
#coding: utf-8
|
||||||
|
import os,sys,json
|
||||||
|
|
||||||
|
#执行模块方法(模块名,方法名,参数)
|
||||||
|
def module_run(module_name, def_name, def_args):
|
||||||
|
if not module_name or not def_name: return returnMsg(False,'模块名称和模块方法名称不能为空!')
|
||||||
|
if not path_check(module_name) or not path_check(def_name): return returnMsg(False,'模块名或方法名不能包含特殊符号!')
|
||||||
|
|
||||||
|
panel_path = get_panel_path()
|
||||||
|
filename = "{}/modules/{}Module/{}Module.py".format(panel_path,module_name,module_name)
|
||||||
|
if not os.path.exists(filename):
|
||||||
|
filename = "{}/modules/{}Module/main.py".format(panel_path,module_name)
|
||||||
|
if not os.path.exists(filename):
|
||||||
|
filename = "{}/plugin/{}/main.py".format(panel_path,module_name)
|
||||||
|
if not os.path.exists(filename):
|
||||||
|
filename = "{}/plugin/{}/{}Plugin.py".format(panel_path,module_name,module_name)
|
||||||
|
if not os.path.exists(filename):
|
||||||
|
return returnMsg(False,'指定模块或插件不存在')
|
||||||
|
|
||||||
|
_obj = get_script_object(filename)
|
||||||
|
if not _obj: return returnMsg(False,'模块加载失败: %s' % module_name)
|
||||||
|
if hasattr(_obj, "items") and hasattr(_obj, "setdefault"):
|
||||||
|
return _obj
|
||||||
|
|
||||||
|
class_name = "main"
|
||||||
|
if not hasattr(_obj, class_name):
|
||||||
|
return returnMsg(False,'找不到入口类: %s' % class_name)
|
||||||
|
|
||||||
|
class_obj = getattr(_obj,class_name, None)
|
||||||
|
if not class_obj:
|
||||||
|
return returnMsg(False,'获取入口类失败' % module_name)
|
||||||
|
|
||||||
|
try:
|
||||||
|
class_func = class_obj()
|
||||||
|
except:
|
||||||
|
return returnMsg(False,'模块入口实例化失败' % module_name)
|
||||||
|
|
||||||
|
if not hasattr(class_func, def_name):
|
||||||
|
return returnMsg(False,'在[%s]模块中找不到[%s]方法' % (class_name,def_name))
|
||||||
|
|
||||||
|
def_func = getattr(class_func, def_name, None)
|
||||||
|
if not def_func:
|
||||||
|
return returnMsg(False,'获取方法失败')
|
||||||
|
|
||||||
|
if 'module_get_object' in def_args:
|
||||||
|
return def_func
|
||||||
|
|
||||||
|
result = def_func(def_args)
|
||||||
|
return result
|
||||||
|
|
||||||
|
#获取指定模块对象(文件全路径)
|
||||||
|
def get_module(filename):
|
||||||
|
if not filename: return returnMsg(False,'模块路径不能为空!')
|
||||||
|
if "./" in filename: return returnMsg(False,'模块路径不能为相对路径')
|
||||||
|
return get_script_object(filename)
|
||||||
|
|
||||||
|
def get_panel_path():
|
||||||
|
return '/www/server/bt-monitor'
|
||||||
|
|
||||||
|
def returnMsg(status,msg,args = ()):
|
||||||
|
return {'status':status,'msg':msg}
|
||||||
|
|
||||||
|
def get_script_object(filename):
|
||||||
|
_obj = sys.modules.get(filename,None)
|
||||||
|
if _obj: return _obj
|
||||||
|
from types import ModuleType
|
||||||
|
_obj = sys.modules.setdefault(filename, ModuleType(filename))
|
||||||
|
_code = readFile(filename)
|
||||||
|
_code_object = compile(_code,filename, 'exec')
|
||||||
|
_obj.__file__ = filename
|
||||||
|
_obj.__package__ = ''
|
||||||
|
exec(_code_object, _obj.__dict__)
|
||||||
|
return _obj
|
||||||
|
|
||||||
|
def readFile(filename,mode = 'r'):
|
||||||
|
import os
|
||||||
|
if not os.path.exists(filename): return False
|
||||||
|
fp = None
|
||||||
|
try:
|
||||||
|
fp = open(filename, mode)
|
||||||
|
f_body = fp.read()
|
||||||
|
except Exception as ex:
|
||||||
|
if sys.version_info[0] != 2:
|
||||||
|
try:
|
||||||
|
fp = open(filename, mode,encoding="utf-8")
|
||||||
|
f_body = fp.read()
|
||||||
|
except:
|
||||||
|
fp = open(filename, mode,encoding="GBK")
|
||||||
|
f_body = fp.read()
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
finally:
|
||||||
|
if fp and not fp.closed:
|
||||||
|
fp.close()
|
||||||
|
return f_body
|
||||||
|
|
||||||
|
#检查路径是否合法
|
||||||
|
def path_check(path):
|
||||||
|
list = ["./","..",",",";",":","?","'","\"","<",">","|","\\","\n","\r","\t","\b","\a","\f","\v","*","%","&","$","#","@","!","~","`","^","(",")","+","=","{","}","[","]"]
|
||||||
|
for i in path:
|
||||||
|
if i in list:
|
||||||
|
return False
|
||||||
|
return True
|
||||||
400
wiki/files/linux/PluginLoader.py
Normal file
400
wiki/files/linux/PluginLoader.py
Normal file
@ -0,0 +1,400 @@
|
|||||||
|
#coding: utf-8
|
||||||
|
# +-------------------------------------------------------------------
|
||||||
|
# | 宝塔Linux面板
|
||||||
|
# +-------------------------------------------------------------------
|
||||||
|
# | Copyright (c) 2015-2099 宝塔软件(http://bt.cn) All rights reserved.
|
||||||
|
# +-------------------------------------------------------------------
|
||||||
|
# | Author: hwliang <hwl@bt.cn>
|
||||||
|
# +-------------------------------------------------------------------
|
||||||
|
|
||||||
|
#+--------------------------------------------------------------------
|
||||||
|
#| 插件和模块加载器
|
||||||
|
#+--------------------------------------------------------------------
|
||||||
|
|
||||||
|
import public,os,sys,json,hashlib
|
||||||
|
|
||||||
|
def plugin_run(plugin_name,def_name,args):
|
||||||
|
'''
|
||||||
|
@name 执行插件方法
|
||||||
|
@param plugin_name<string> 插件名称
|
||||||
|
@param def_name<string> 方法名称
|
||||||
|
@param args<dict_obj> 参数对像
|
||||||
|
@return mixed
|
||||||
|
'''
|
||||||
|
if not plugin_name or not def_name: return public.returnMsg(False,'插件名称和插件方法名称不能为空!')
|
||||||
|
|
||||||
|
# 获取插件目录
|
||||||
|
plugin_path = public.get_plugin_path(plugin_name)
|
||||||
|
is_php = os.path.exists(os.path.join(plugin_path,'index.php'))
|
||||||
|
|
||||||
|
# 检查插件目录是否合法
|
||||||
|
if is_php:
|
||||||
|
plugin_file = os.path.join(plugin_path,'index.php')
|
||||||
|
else:
|
||||||
|
plugin_file = os.path.join(plugin_path, plugin_name + '_main.py')
|
||||||
|
if not public.path_safe_check(plugin_file): return public.returnMsg(False,'插件路径不合法')
|
||||||
|
|
||||||
|
# 检查插件入口文件是否存在
|
||||||
|
if not os.path.exists(plugin_file): return public.returnMsg(False,'指定插件入口文件不存在')
|
||||||
|
|
||||||
|
# 添加插件目录到系统路径
|
||||||
|
public.sys_path_append(plugin_path)
|
||||||
|
|
||||||
|
if not is_php:
|
||||||
|
# 引用插件入口文件
|
||||||
|
_name = "{}_main".format(plugin_name)
|
||||||
|
plugin_main = __import__(_name)
|
||||||
|
|
||||||
|
# 检查类名是否符合规范
|
||||||
|
if not hasattr(plugin_main,_name):
|
||||||
|
return public.returnMsg(False,'指定插件入口文件不符合规范')
|
||||||
|
|
||||||
|
try:
|
||||||
|
if sys.version_info[0] == 2:
|
||||||
|
reload(plugin_main)
|
||||||
|
else:
|
||||||
|
from imp import reload
|
||||||
|
reload(plugin_main)
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# 实例化插件类
|
||||||
|
plugin_obj = getattr(plugin_main,_name)()
|
||||||
|
|
||||||
|
# 检查方法是否存在
|
||||||
|
if not hasattr(plugin_obj,def_name):
|
||||||
|
return public.returnMsg(False,'在[%s]插件中找不到[%s]方法' % (plugin_name,def_name))
|
||||||
|
|
||||||
|
if args is not None and 'plugin_get_object' in args and args.plugin_get_object == 1:
|
||||||
|
return getattr(plugin_obj, def_name)
|
||||||
|
|
||||||
|
# 执行方法
|
||||||
|
return getattr(plugin_obj,def_name)(args)
|
||||||
|
else:
|
||||||
|
if args is not None and 'plugin_get_object' in args and args.plugin_get_object == 1:
|
||||||
|
return None
|
||||||
|
import panelPHP
|
||||||
|
args.s = def_name
|
||||||
|
args.name = plugin_name
|
||||||
|
return panelPHP.panelPHP(plugin_name).exec_php_script(args)
|
||||||
|
|
||||||
|
|
||||||
|
def get_module_list():
|
||||||
|
'''
|
||||||
|
@name 获取模块列表
|
||||||
|
@return list
|
||||||
|
'''
|
||||||
|
module_list = []
|
||||||
|
class_path = public.get_class_path()
|
||||||
|
for name in os.listdir(class_path):
|
||||||
|
path = os.path.join(class_path,name)
|
||||||
|
# 过滤无效文件
|
||||||
|
if not name or name.endswith('.py') or name[0] == '.' or not name.endswith('Model') or os.path.isfile(path):continue
|
||||||
|
module_list.append(name)
|
||||||
|
return module_list
|
||||||
|
|
||||||
|
def module_run(module_name,def_name,args):
|
||||||
|
'''
|
||||||
|
@name 执行模块方法
|
||||||
|
@param module_name<string> 模块名称
|
||||||
|
@param def_name<string> 方法名称
|
||||||
|
@param args<dict_obj> 参数对像
|
||||||
|
@return mixed
|
||||||
|
'''
|
||||||
|
if not module_name or not def_name: return public.returnMsg(False,'模块名称和模块方法名称不能为空!')
|
||||||
|
model_index = args.get('model_index',None)
|
||||||
|
class_path = public.get_class_path()
|
||||||
|
panel_path = public.get_panel_path()
|
||||||
|
|
||||||
|
module_file = None
|
||||||
|
if 'model_index' in args:
|
||||||
|
# 新模块目录
|
||||||
|
if model_index in ['mod']:
|
||||||
|
module_file = os.path.join(panel_path,'mod','project',module_name + 'Mod.py')
|
||||||
|
elif model_index:
|
||||||
|
# 旧模块目录
|
||||||
|
module_file = os.path.join(class_path,model_index+"Model",module_name + 'Model.py')
|
||||||
|
else:
|
||||||
|
module_file = os.path.join(class_path,"projectModel",module_name + 'Model.py')
|
||||||
|
else:
|
||||||
|
# 如果没指定模块名称,则遍历所有模块目录
|
||||||
|
module_list = get_module_list()
|
||||||
|
for name in module_list:
|
||||||
|
module_file = os.path.join(class_path,name,module_name + 'Model.py')
|
||||||
|
if os.path.exists(module_file): break
|
||||||
|
|
||||||
|
# 判断模块入口文件是否存在
|
||||||
|
if not os.path.exists(module_file):
|
||||||
|
return public.returnMsg(False,'模块[%s]不存在' % module_name)
|
||||||
|
|
||||||
|
# 判断模块路径是否合法
|
||||||
|
if not public.path_safe_check(module_file):
|
||||||
|
return public.returnMsg(False,'模块路径不合法')
|
||||||
|
|
||||||
|
def_object = public.get_script_object(module_file)
|
||||||
|
if not def_object: return public.returnMsg(False,'模块[%s]不存在' % module_name)
|
||||||
|
|
||||||
|
# 模块实例化并返回方法对象
|
||||||
|
try:
|
||||||
|
run_object = getattr(def_object.main(),def_name,None)
|
||||||
|
except:
|
||||||
|
return public.returnMsg(False,'模块[%s]入口实例化失败' % module_name)
|
||||||
|
if not run_object: return public.returnMsg(False,'在[%s]模块中找不到[%s]方法' % (module_name,def_name))
|
||||||
|
|
||||||
|
if 'module_get_object' in args and args.module_get_object == 1:
|
||||||
|
return run_object
|
||||||
|
|
||||||
|
# 执行方法
|
||||||
|
result = run_object(args)
|
||||||
|
return result
|
||||||
|
|
||||||
|
def get_module(filename: str):
|
||||||
|
'''
|
||||||
|
@name 获取模块对象
|
||||||
|
@param filename<string> 模块文件名
|
||||||
|
@return object
|
||||||
|
'''
|
||||||
|
if not filename: return None
|
||||||
|
|
||||||
|
if filename[0:2] == './':
|
||||||
|
return public.returnMsg(False,'不能是相对路径')
|
||||||
|
|
||||||
|
if not public.path_safe_check(filename):
|
||||||
|
return public.returnMsg(False,'模块路径不合法')
|
||||||
|
|
||||||
|
if not os.path.exists(filename):
|
||||||
|
return public.returnMsg(False,'模块文件不存在' % filename)
|
||||||
|
|
||||||
|
def_object = public.get_script_object(filename)
|
||||||
|
if not def_object: return public.returnMsg(False,'模块[%s]不存在' % filename)
|
||||||
|
|
||||||
|
return def_object.main()
|
||||||
|
|
||||||
|
def get_plugin_list(upgrade_force = False):
|
||||||
|
'''
|
||||||
|
@name 获取插件列表
|
||||||
|
@param upgrade_force<bool> 是否强制重新获取列表
|
||||||
|
@return dict
|
||||||
|
'''
|
||||||
|
|
||||||
|
api_root_url = 'https://api.bt.cn'
|
||||||
|
api_url = api_root_url+ '/panel/get_plugin_list'
|
||||||
|
panel_path = public.get_panel_path()
|
||||||
|
data_path = os.path.join(panel_path,'data')
|
||||||
|
|
||||||
|
if not os.path.exists(data_path):
|
||||||
|
os.makedirs(data_path,384)
|
||||||
|
|
||||||
|
plugin_list = {}
|
||||||
|
plugin_list_file = os.path.join(data_path,'plugin_list.json')
|
||||||
|
if os.path.exists(plugin_list_file) and not upgrade_force:
|
||||||
|
plugin_list_body = public.readFile(plugin_list_file)
|
||||||
|
try:
|
||||||
|
plugin_list = json.loads(plugin_list_body)
|
||||||
|
except:
|
||||||
|
plugin_list = {}
|
||||||
|
|
||||||
|
if not os.path.exists(plugin_list_file) or upgrade_force or not plugin_list:
|
||||||
|
try:
|
||||||
|
res = public.HttpGet(api_url)
|
||||||
|
except Exception as ex:
|
||||||
|
raise public.error_conn_cloud(str(ex))
|
||||||
|
if not res: raise Exception(False,'云端插件列表获取失败')
|
||||||
|
|
||||||
|
plugin_list = json.loads(res)
|
||||||
|
if type(plugin_list)!=dict or 'list' not in plugin_list:
|
||||||
|
if type(plugin_list)==str:
|
||||||
|
raise Exception(plugin_list)
|
||||||
|
else:
|
||||||
|
raise Exception('云端插件列表获取失败')
|
||||||
|
content = json.dumps(plugin_list)
|
||||||
|
public.writeFile(plugin_list_file,content)
|
||||||
|
|
||||||
|
plugin_bin_file = os.path.join(data_path,'plugin_bin.pl')
|
||||||
|
encode_content = __encode_plugin_list(content)
|
||||||
|
if encode_content:
|
||||||
|
public.writeFile(plugin_bin_file,encode_content)
|
||||||
|
|
||||||
|
return plugin_list
|
||||||
|
|
||||||
|
def __encode_plugin_list(content):
|
||||||
|
try:
|
||||||
|
userInfo = public.get_user_info()
|
||||||
|
if not userInfo or 'serverid' not in userInfo: return None
|
||||||
|
block_size = 51200
|
||||||
|
uid = str(userInfo['uid'])
|
||||||
|
server_id = userInfo['serverid']
|
||||||
|
key = server_id[10:26] + uid + server_id
|
||||||
|
key = hashlib.md5(key.encode()).hexdigest()
|
||||||
|
iv = key + server_id
|
||||||
|
iv = hashlib.md5(iv.encode()).hexdigest()
|
||||||
|
key = key[8:24]
|
||||||
|
iv = iv[8:24]
|
||||||
|
blocks = [content[i:i + block_size] for i in range(0, len(content), block_size)]
|
||||||
|
encrypted_content = ''
|
||||||
|
for block in blocks:
|
||||||
|
encrypted_content += __aes_encrypt(block, key, iv) + '\n'
|
||||||
|
return encrypted_content
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
return None
|
||||||
|
|
||||||
|
def start_total():
|
||||||
|
'''
|
||||||
|
@name 启动统计服务
|
||||||
|
@return dict
|
||||||
|
'''
|
||||||
|
pass
|
||||||
|
|
||||||
|
def get_soft_list(args):
|
||||||
|
'''
|
||||||
|
@name 获取软件列表
|
||||||
|
@param args<dict_obj> 参数对像
|
||||||
|
@return dict
|
||||||
|
'''
|
||||||
|
pass
|
||||||
|
|
||||||
|
def db_encrypt(data):
|
||||||
|
'''
|
||||||
|
@name 数据库加密
|
||||||
|
@param args<dict_obj> 参数对像
|
||||||
|
@return dict
|
||||||
|
'''
|
||||||
|
try:
|
||||||
|
key = __get_db_sgin()
|
||||||
|
iv = __get_db_iv()
|
||||||
|
str_arr = data.split('\n')
|
||||||
|
res_str = ''
|
||||||
|
for data in str_arr:
|
||||||
|
if not data: continue
|
||||||
|
res_str += __aes_encrypt(data, key, iv)
|
||||||
|
except:
|
||||||
|
res_str = data
|
||||||
|
result = {
|
||||||
|
'status' : True,
|
||||||
|
'msg' : res_str
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
|
||||||
|
def db_decrypt(data):
|
||||||
|
'''
|
||||||
|
@name 数据库解密
|
||||||
|
@param args<dict_obj> 参数对像
|
||||||
|
@return dict
|
||||||
|
'''
|
||||||
|
try:
|
||||||
|
key = __get_db_sgin()
|
||||||
|
iv = __get_db_iv()
|
||||||
|
str_arr = data.split('\n')
|
||||||
|
res_str = ''
|
||||||
|
for data in str_arr:
|
||||||
|
if not data: continue
|
||||||
|
res_str += __aes_decrypt(data, key, iv)
|
||||||
|
except:
|
||||||
|
res_str = data
|
||||||
|
result = {
|
||||||
|
'status' : True,
|
||||||
|
'msg' : res_str
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
|
||||||
|
def __get_db_sgin():
|
||||||
|
keystr = '3gP7+k_7lSNg3$+Fj!PKW+6$KYgHtw#R'
|
||||||
|
key = ''
|
||||||
|
for i in range(31):
|
||||||
|
if i & 1 == 0:
|
||||||
|
key += keystr[i]
|
||||||
|
return key
|
||||||
|
|
||||||
|
def __get_db_iv():
|
||||||
|
div_file = "{}/data/div.pl".format(public.get_panel_path())
|
||||||
|
if not os.path.exists(div_file):
|
||||||
|
str = public.GetRandomString(16)
|
||||||
|
str = __aes_encrypt_module(str)
|
||||||
|
div = public.get_div(str)
|
||||||
|
public.WriteFile(div_file, div)
|
||||||
|
if os.path.exists(div_file):
|
||||||
|
div = public.ReadFile(div_file)
|
||||||
|
div = __aes_decrypt_module(div)
|
||||||
|
else:
|
||||||
|
keystr = '4jHCpBOFzL4*piTn^-4IHBhj-OL!fGlB'
|
||||||
|
div = ''
|
||||||
|
for i in range(31):
|
||||||
|
if i & 1 == 0:
|
||||||
|
div += keystr[i]
|
||||||
|
return div
|
||||||
|
|
||||||
|
def __aes_encrypt_module(data):
|
||||||
|
key = 'Z2B87NEAS2BkxTrh'
|
||||||
|
iv = 'WwadH66EGWpeeTT6'
|
||||||
|
return __aes_encrypt(data, key, iv)
|
||||||
|
|
||||||
|
def __aes_decrypt_module(data):
|
||||||
|
key = 'Z2B87NEAS2BkxTrh'
|
||||||
|
iv = 'WwadH66EGWpeeTT6'
|
||||||
|
return __aes_decrypt(data, key, iv)
|
||||||
|
|
||||||
|
def __aes_decrypt(data, key, iv):
|
||||||
|
from Crypto.Cipher import AES
|
||||||
|
import base64
|
||||||
|
encodebytes = base64.decodebytes(data.encode('utf-8'))
|
||||||
|
aes = AES.new(key.encode('utf-8'), AES.MODE_CBC, iv.encode('utf-8'))
|
||||||
|
de_text = aes.decrypt(encodebytes)
|
||||||
|
unpad = lambda s: s[0:-s[-1]]
|
||||||
|
de_text = unpad(de_text)
|
||||||
|
return de_text.decode('utf-8')
|
||||||
|
|
||||||
|
def __aes_encrypt(data, key, iv):
|
||||||
|
from Crypto.Cipher import AES
|
||||||
|
import base64
|
||||||
|
data = (lambda s: s + (16 - len(s) % 16) * chr(16 - len(s) % 16).encode('utf-8'))(data.encode('utf-8'))
|
||||||
|
aes = AES.new(key.encode('utf8'), AES.MODE_CBC, iv.encode('utf8'))
|
||||||
|
encryptedbytes = aes.encrypt(data)
|
||||||
|
en_text = base64.b64encode(encryptedbytes)
|
||||||
|
return en_text.decode('utf-8')
|
||||||
|
|
||||||
|
def plugin_end():
|
||||||
|
'''
|
||||||
|
@name 插件到期处理
|
||||||
|
@return dict
|
||||||
|
'''
|
||||||
|
pass
|
||||||
|
|
||||||
|
def daemon_task():
|
||||||
|
'''
|
||||||
|
@name 后台任务守护
|
||||||
|
@return dict
|
||||||
|
'''
|
||||||
|
pass
|
||||||
|
|
||||||
|
def daemon_panel():
|
||||||
|
'''
|
||||||
|
@name 面板守护
|
||||||
|
@return dict
|
||||||
|
'''
|
||||||
|
pass
|
||||||
|
|
||||||
|
def flush_auth_key():
|
||||||
|
'''
|
||||||
|
@name 刷新授权密钥
|
||||||
|
@return dict
|
||||||
|
'''
|
||||||
|
pass
|
||||||
|
|
||||||
|
def get_auth_state():
|
||||||
|
'''
|
||||||
|
@name 获取授权状态
|
||||||
|
@return 返回:0.免费版 1.专业版 2.企业版 -1.获取失败
|
||||||
|
'''
|
||||||
|
try:
|
||||||
|
softList = get_plugin_list()
|
||||||
|
if softList['ltd'] > -1:
|
||||||
|
return 2
|
||||||
|
elif softList['pro'] > -1:
|
||||||
|
return 1
|
||||||
|
else:
|
||||||
|
return 0
|
||||||
|
except:
|
||||||
|
return -1
|
||||||
|
|
||||||
|
|
||||||
110
wiki/files/linux/bt.js
Normal file
110
wiki/files/linux/bt.js
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
/*
|
||||||
|
*宝塔面板去除各种计算题与延时等待
|
||||||
|
*/
|
||||||
|
if("undefined" != typeof bt && bt.hasOwnProperty("show_confirm")){
|
||||||
|
bt.show_confirm = function(title, msg, callback, error) {
|
||||||
|
layer.open({
|
||||||
|
type: 1,
|
||||||
|
title: title,
|
||||||
|
area: "365px",
|
||||||
|
closeBtn: 2,
|
||||||
|
shadeClose: true,
|
||||||
|
btn: [lan['public'].ok, lan['public'].cancel],
|
||||||
|
content: "<div class='bt-form webDelete pd20'>\
|
||||||
|
<p style='font-size:13px;word-break: break-all;margin-bottom: 5px;'>" + msg + "</p>" + (error || '') + "\
|
||||||
|
</div>",
|
||||||
|
yes: function (index, layero) {
|
||||||
|
layer.close(index);
|
||||||
|
if (callback) callback();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if("undefined" != typeof bt && bt.hasOwnProperty("prompt_confirm")){
|
||||||
|
bt.prompt_confirm = function (title, msg, callback) {
|
||||||
|
layer.open({
|
||||||
|
type: 1,
|
||||||
|
title: title,
|
||||||
|
area: "350px",
|
||||||
|
closeBtn: 2,
|
||||||
|
btn: ['确认', '取消'],
|
||||||
|
content: "<div class='bt-form promptDelete pd20'>\
|
||||||
|
<p>" + msg + "</p>\
|
||||||
|
</div>",
|
||||||
|
yes: function (layers, index) {
|
||||||
|
layer.close(layers)
|
||||||
|
if (callback) callback()
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if("undefined" != typeof bt && bt.hasOwnProperty("compute_confirm")){
|
||||||
|
bt.compute_confirm = function (config, callback) {
|
||||||
|
layer.open({
|
||||||
|
type: 1,
|
||||||
|
title: config.title,
|
||||||
|
area: '430px',
|
||||||
|
closeBtn: 2,
|
||||||
|
shadeClose: true,
|
||||||
|
btn: [lan['public'].ok, lan['public'].cancel],
|
||||||
|
content:
|
||||||
|
'<div class="bt-form hint_confirm pd30">\
|
||||||
|
<div class="hint_title">\
|
||||||
|
<i class="hint-confirm-icon"></i>\
|
||||||
|
<div class="hint_con">' +
|
||||||
|
config.msg +
|
||||||
|
'</div>\
|
||||||
|
</div>\
|
||||||
|
</div>',
|
||||||
|
yes: function (layers, index) {
|
||||||
|
layer.close(layers)
|
||||||
|
if (callback) callback()
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if("undefined" != typeof bt && bt.hasOwnProperty("input_confirm")){
|
||||||
|
bt.input_confirm = function (config, callback) {
|
||||||
|
layer.open({
|
||||||
|
type: 1,
|
||||||
|
title: config.title,
|
||||||
|
area: '430px',
|
||||||
|
closeBtn: 2,
|
||||||
|
shadeClose: true,
|
||||||
|
btn: [lan['public'].ok, lan['public'].cancel],
|
||||||
|
content:
|
||||||
|
'<div class="bt-form hint_confirm pd30">\
|
||||||
|
<div class="hint_title">\
|
||||||
|
<i class="hint-confirm-icon"></i>\
|
||||||
|
<div class="hint_con">' +
|
||||||
|
config.msg +
|
||||||
|
'</div>\
|
||||||
|
</div>\
|
||||||
|
</div>',
|
||||||
|
yes: function (layers, index) {
|
||||||
|
layer.close(layers);
|
||||||
|
if (callback) callback();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(window.hasOwnProperty("SafeMessage")){
|
||||||
|
window.SafeMessage = function(j, h, g, f) {
|
||||||
|
if (f == undefined) f = '';
|
||||||
|
var mess = layer.open({
|
||||||
|
type: 1,
|
||||||
|
title: j,
|
||||||
|
area: "350px",
|
||||||
|
closeBtn: 2,
|
||||||
|
shadeClose: true,
|
||||||
|
content: "<div class='bt-form webDelete pd20 pb70'><p>" + h + "</p>" + f + "<div class='bt-form-submit-btn'><button type='button' class='btn btn-danger btn-sm bt-cancel'>"+lan.public.cancel+"</button> <button type='button' id='toSubmit' class='btn btn-success btn-sm' >"+lan.public.ok+"</button></div></div>"
|
||||||
|
});
|
||||||
|
$(".bt-cancel").click(function(){
|
||||||
|
layer.close(mess);
|
||||||
|
});
|
||||||
|
$("#toSubmit").click(function() {
|
||||||
|
layer.close(mess);
|
||||||
|
g();
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -16,7 +16,11 @@ def get_plugin_list(force = 0):
|
|||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
raise public.error_conn_cloud(str(ex))
|
raise public.error_conn_cloud(str(ex))
|
||||||
softList = json.loads(jsonData)
|
softList = json.loads(jsonData)
|
||||||
if type(softList)!=dict or 'list' not in softList: raise Exception('云端插件列表获取失败')
|
if type(softList)!=dict or 'list' not in softList:
|
||||||
|
if type(softList)==str:
|
||||||
|
raise Exception(softList)
|
||||||
|
else:
|
||||||
|
raise Exception('云端插件列表获取失败')
|
||||||
public.writeFile(cache_file, jsonData)
|
public.writeFile(cache_file, jsonData)
|
||||||
return softList
|
return softList
|
||||||
|
|
||||||
|
|||||||
@ -1,202 +1,394 @@
|
|||||||
/*
|
/*
|
||||||
*宝塔面板去除各种计算题与延时等待
|
*宝塔面板去除各种计算题与延时等待
|
||||||
*/
|
*/
|
||||||
if("undefined" != typeof bt && bt.hasOwnProperty("show_confirm")){
|
if("undefined" != typeof bt && bt.hasOwnProperty("show_confirm")){
|
||||||
bt.show_confirm = function(title, msg, fun, error) {
|
bt.show_confirm = function(title, msg, fun, error) {
|
||||||
if (error == undefined) {
|
if (error == undefined) {
|
||||||
error = ""
|
error = ""
|
||||||
}
|
}
|
||||||
var mess = layer.open({
|
var mess = layer.open({
|
||||||
type: 1,
|
type: 1,
|
||||||
title: title,
|
title: title,
|
||||||
area: "350px",
|
area: "350px",
|
||||||
closeBtn: 2,
|
closeBtn: 2,
|
||||||
shadeClose: true,
|
shadeClose: true,
|
||||||
content: "<div class='bt-form webDelete pd20 pb70'><p>" + msg + "</p>" + error + "<div class='bt-form-submit-btn'><button type='button' class='btn btn-danger btn-sm bt-cancel'>" + lan.public.cancel + "</button> <button type='button' id='toSubmit' class='btn btn-success btn-sm' >" + lan.public.ok + "</button></div></div>"
|
content: "<div class='bt-form webDelete pd20 pb70'><p>" + msg + "</p>" + error + "<div class='bt-form-submit-btn'><button type='button' class='btn btn-danger btn-sm bt-cancel'>" + lan.public.cancel + "</button> <button type='button' id='toSubmit' class='btn btn-success btn-sm' >" + lan.public.ok + "</button></div></div>"
|
||||||
});
|
});
|
||||||
$(".bt-cancel").click(function () {
|
$(".bt-cancel").click(function () {
|
||||||
layer.close(mess);
|
layer.close(mess);
|
||||||
});
|
});
|
||||||
$("#toSubmit").click(function () {
|
$("#toSubmit").click(function () {
|
||||||
layer.close(mess);
|
layer.close(mess);
|
||||||
fun();
|
fun();
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if("undefined" != typeof bt && bt.hasOwnProperty("prompt_confirm")){
|
if("undefined" != typeof bt && bt.hasOwnProperty("prompt_confirm")){
|
||||||
bt.prompt_confirm = function (title, msg, callback) {
|
bt.prompt_confirm = function (title, msg, callback) {
|
||||||
layer.open({
|
layer.open({
|
||||||
type: 1,
|
type: 1,
|
||||||
title: title,
|
title: title,
|
||||||
area: "350px",
|
area: "350px",
|
||||||
closeBtn: 2,
|
closeBtn: 2,
|
||||||
btn: ['确认', '取消'],
|
btn: ['确认', '取消'],
|
||||||
content: "<div class='bt-form promptDelete pd20'>\
|
content: "<div class='bt-form promptDelete pd20'>\
|
||||||
<p>" + msg + "</p>\
|
<p>" + msg + "</p>\
|
||||||
</div>",
|
</div>",
|
||||||
yes: function (layers, index) {
|
yes: function (layers, index) {
|
||||||
layer.close(layers)
|
layer.close(layers)
|
||||||
if (callback) callback()
|
if (callback) callback()
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if("undefined" != typeof database && database.hasOwnProperty("del_database")){
|
if("undefined" != typeof bt && bt.hasOwnProperty("compute_confirm")){
|
||||||
database.del_database = function (wid, dbname,obj, callback) {
|
bt.compute_confirm = function (config, callback) {
|
||||||
var tips = '是否确认【删除数据库】,删除后可能会影响业务使用!';
|
layer.open({
|
||||||
if(obj && obj.db_type > 0) tips = '远程数据库不支持数据库回收站,删除后将无法恢复,请谨慎操作';
|
type: 1,
|
||||||
var title = typeof dbname === "function" ?'批量删除数据库':'删除数据库 [ '+ dbname +' ]';
|
title: config.title,
|
||||||
layer.open({
|
area: '430px',
|
||||||
type:1,
|
closeBtn: 2,
|
||||||
title:title,
|
shadeClose: true,
|
||||||
icon:0,
|
btn: [lan['public'].ok, lan['public'].cancel],
|
||||||
skin:'delete_site_layer',
|
content:
|
||||||
area: "530px",
|
'<div class="bt-form hint_confirm pd30">\
|
||||||
closeBtn: 2,
|
<div class="hint_title">\
|
||||||
shadeClose: true,
|
<i class="hint-confirm-icon"></i>\
|
||||||
content:"<div class=\'bt-form webDelete pd30\' id=\'site_delete_form\'>" +
|
<div class="hint_con">' +
|
||||||
"<i class=\'layui-layer-ico layui-layer-ico0\'></i>" +
|
config.msg +
|
||||||
"<div class=\'f13 check_title\' style=\'margin-bottom: 20px;\'>"+tips+"</div>" +
|
'</div>\
|
||||||
"<div style=\'color:red;margin:18px 0 18px 18px;font-size:14px;font-weight: bold;\'>注意:数据无价,请谨慎操作!!!"+(!recycle_bin_db_open?'<br>风险操作:当前数据库回收站未开启,删除数据库将永久消失!':'')+"</div>" +
|
</div>\
|
||||||
"</div>",
|
</div>',
|
||||||
btn:[lan.public.ok,lan.public.cancel],
|
yes: function (layers, index) {
|
||||||
yes:function(indexs){
|
layer.close(layers)
|
||||||
var data = {id: wid,name: dbname};
|
if (callback) callback()
|
||||||
if(typeof dbname === "function"){
|
}
|
||||||
delete data.id;
|
});
|
||||||
delete data.name;
|
}
|
||||||
}
|
}
|
||||||
layer.close(indexs)
|
if("undefined" != typeof bt && bt.hasOwnProperty("input_confirm")){
|
||||||
if(typeof dbname === "function"){
|
bt.input_confirm = function (config, callback) {
|
||||||
dbname(data)
|
layer.open({
|
||||||
}else{
|
type: 1,
|
||||||
bt.database.del_database(data, function (rdata) {
|
title: config.title,
|
||||||
layer.closeAll()
|
area: '430px',
|
||||||
if (rdata.status) database_table.$refresh_table_list(true);
|
closeBtn: 2,
|
||||||
if (callback) callback(rdata);
|
shadeClose: true,
|
||||||
bt.msg(rdata);
|
btn: [lan['public'].ok, lan['public'].cancel],
|
||||||
})
|
content:
|
||||||
}
|
'<div class="bt-form hint_confirm pd30">\
|
||||||
}
|
<div class="hint_title">\
|
||||||
})
|
<i class="hint-confirm-icon"></i>\
|
||||||
}
|
<div class="hint_con">' +
|
||||||
}
|
config.msg +
|
||||||
if("undefined" != typeof site && site.hasOwnProperty("del_site")){
|
'</div>\
|
||||||
site.del_site = function(wid, wname, callback) {
|
</div>\
|
||||||
var title = typeof wname === "function" ?'批量删除站点':'删除站点 [ '+ wname +' ]';
|
</div>',
|
||||||
layer.open({
|
yes: function (layers, index) {
|
||||||
type:1,
|
layer.close(layers);
|
||||||
title:title,
|
if (callback) callback();
|
||||||
icon:0,
|
},
|
||||||
skin:'delete_site_layer',
|
});
|
||||||
area: "440px",
|
}
|
||||||
closeBtn: 2,
|
}
|
||||||
shadeClose: true,
|
if("undefined" != typeof database && database.hasOwnProperty("del_database")){
|
||||||
content:"<div class=\'bt-form webDelete pd30\' id=\'site_delete_form\'>" +
|
database.del_database = function (wid, dbname,obj, callback) {
|
||||||
'<i class="layui-layer-ico layui-layer-ico0"></i>' +
|
var title = '',
|
||||||
"<div class=\'f13 check_title\'>是否要删除关联的FTP、数据库、站点目录!</div>" +
|
tips = '是否确认【删除数据库】,删除后可能会影响业务使用!';
|
||||||
"<div class=\"check_type_group\">" +
|
if(obj && obj.db_type > 0) tips = '远程数据库不支持数据库回收站,删除后将无法恢复,请谨慎操作';
|
||||||
"<label><input type=\"checkbox\" name=\"ftp\"><span>FTP</span></label>" +
|
title = typeof dbname === "function" ?'批量删除数据库':'删除数据库 [ '+ dbname +' ]';
|
||||||
"<label><input type=\"checkbox\" name=\"database\"><span>数据库</span>"+ (!recycle_bin_db_open?'<span class="glyphicon glyphicon-info-sign" style="color: red"></span>':'') +"</label>" +
|
layer.open({
|
||||||
"<label><input type=\"checkbox\" name=\"path\"><span>站点目录</span>"+ (!recycle_bin_open?'<span class="glyphicon glyphicon-info-sign" style="color: red"></span>':'') +"</label>" +
|
type:1,
|
||||||
"</div>"+
|
title:title,
|
||||||
"</div>",
|
icon:0,
|
||||||
btn:[lan.public.ok,lan.public.cancel],
|
skin:'delete_site_layer',
|
||||||
success:function(layers,indexs){
|
area: "530px",
|
||||||
$(layers).find('.check_type_group label').hover(function () {
|
closeBtn: 2,
|
||||||
var name = $(this).find('input').attr('name');
|
shadeClose: true,
|
||||||
if (name === 'data' && !recycle_bin_db_open) {
|
content:"<div class=\'bt-form webDelete pd30\' id=\'site_delete_form\'>" +
|
||||||
layer.tips('风险操作:当前数据库回收站未开启,删除数据库将永久消失!', this, { tips: [1, 'red'], time: 0 })
|
"<i class=\'layui-layer-ico layui-layer-ico0\'></i>" +
|
||||||
} else if (name === 'path' && !recycle_bin_open) {
|
"<div class=\'f13 check_title\' style=\'margin-bottom: 20px;\'>"+tips+"</div>" +
|
||||||
layer.tips('风险操作:当前文件回收站未开启,删除站点目录将永久消失!', this, { tips: [1, 'red'], time: 0 })
|
"<div style=\'color:red;margin:18px 0 18px 18px;font-size:14px;font-weight: bold;\'>注意:数据无价,请谨慎操作!!!"+(!recycle_bin_db_open?'<br>风险操作:当前数据库回收站未开启,删除数据库将永久消失!':'')+"</div>" +
|
||||||
}
|
"</div>",
|
||||||
}, function () {
|
btn:[lan.public.ok,lan.public.cancel],
|
||||||
layer.closeAll('tips');
|
yes:function(indexs){
|
||||||
})
|
var data = {id: wid,name: dbname};
|
||||||
},
|
if(typeof dbname === "function"){
|
||||||
yes:function(indexs){
|
delete data.id;
|
||||||
var data = {id: wid,webname: wname};
|
delete data.name;
|
||||||
$('#site_delete_form input[type=checkbox]').each(function (index, item) {
|
}
|
||||||
if($(item).is(':checked')) data[$(item).attr('name')] = 1
|
layer.close(indexs)
|
||||||
})
|
var arrs = wid instanceof Array ? wid : [wid]
|
||||||
var is_database = data.hasOwnProperty('database'),is_path = data.hasOwnProperty('path'),is_ftp = data.hasOwnProperty('ftp');
|
var ids = JSON.stringify(arrs), countDown = 9;
|
||||||
if((!is_database && !is_path) && (!is_ftp || is_ftp)){
|
if (arrs.length == 1) countDown = 4
|
||||||
if(typeof wname === "function"){
|
title = typeof dbname === "function" ?'二次验证信息,批量删除数据库':'二次验证信息,删除数据库 [ ' + dbname + ' ]';
|
||||||
wname(data)
|
var loadT = bt.load('正在检测数据库数据信息,请稍后...')
|
||||||
return false;
|
|
||||||
}
|
bt_tools.send({url:'database/'+bt.data.db_tab_name+'/check_del_data',data:{data:JSON.stringify({ids: ids})}},function(res){
|
||||||
bt.site.del_site(data, function (rdata) {
|
loadT.close()
|
||||||
layer.close(indexs);
|
layer.open({
|
||||||
if (callback) callback(rdata);
|
type:1,
|
||||||
bt.msg(rdata);
|
title:title,
|
||||||
})
|
closeBtn: 2,
|
||||||
return false
|
skin: 'verify_site_layer_info',
|
||||||
}
|
area: '740px',
|
||||||
if(typeof wname === "function"){
|
content: '<div class="check_delete_site_main pd30">' +
|
||||||
delete data.id;
|
'<i class="layui-layer-ico layui-layer-ico0"></i>' +
|
||||||
delete data.webname;
|
'<div class="check_layer_title">堡塔温馨提示您,请冷静几秒钟,确认是否要删除以下数据。</div>' +
|
||||||
}
|
'<div class="check_layer_content">' +
|
||||||
layer.close(indexs)
|
'<div class="check_layer_item">' +
|
||||||
if(typeof wname === "function"){
|
'<div class="check_layer_site"></div>' +
|
||||||
console.log(data)
|
'<div class="check_layer_database"></div>' +
|
||||||
wname(data)
|
'</div>' +
|
||||||
}else{
|
'</div>' +
|
||||||
bt.site.del_site(data, function (rdata) {
|
'<div class="check_layer_error ' + (recycle_bin_db_open ? 'hide' : '') + '"><span class="glyphicon glyphicon-info-sign"></span>风险事项:当前未开启数据库回收站功能,删除数据库后,数据库将永久消失!</div>' +
|
||||||
layer.closeAll()
|
'<div class="check_layer_message"><span style="color:red">注意:请仔细阅读以上要删除信息,防止数据库被误删</span></div>' +
|
||||||
if (rdata.status) site.get_list();
|
'</div>',
|
||||||
if (callback) callback(rdata);
|
btn: ['确认删除', '取消删除'],
|
||||||
bt.msg(rdata);
|
success: function (layers) {
|
||||||
})
|
var html = '', rdata = res.data;
|
||||||
}
|
var filterData = rdata.filter(function(el){
|
||||||
}
|
return ids.indexOf(el.id) != -1
|
||||||
})
|
})
|
||||||
}
|
for (var i = 0; i < filterData.length; i++) {
|
||||||
}
|
var item = filterData[i], newTime = parseInt(new Date().getTime() / 1000),
|
||||||
if("undefined" != typeof bt && bt.hasOwnProperty("firewall") && bt.firewall.hasOwnProperty("add_accept_port")){
|
t_icon = '<span class="glyphicon glyphicon-info-sign" style="color: red;width:15px;height: 15px;;vertical-align: middle;"></span>';
|
||||||
bt.firewall.add_accept_port = function(type, port, ps, callback) {
|
|
||||||
var action = "AddDropAddress";
|
database_html = (function(item){
|
||||||
if (type == 'port') {
|
var is_time_rule = (newTime - item.st_time) > (86400 * 30) && (item.total > 1024 * 10),
|
||||||
ports = port.split(':');
|
is_database_rule = res.db_size <= item.total,
|
||||||
if (port.indexOf('-') != -1) ports = port.split('-');
|
database_time = bt.format_data(item.st_time, 'yyyy-MM-dd'),
|
||||||
for (var i = 0; i < ports.length; i++) {
|
database_size = bt.format_size(item.total);
|
||||||
if (!bt.check_port(ports[i])) {
|
|
||||||
layer.msg(lan.firewall.port_err, { icon: 5 });
|
var f_size = '<i ' + (is_database_rule ? 'class="warning"' : '') + ' style = "vertical-align: middle;" > ' + database_size + '</i> ' + (is_database_rule ? t_icon : '');
|
||||||
return;
|
var t_size = '注意:此数据库较大,可能为重要数据,请谨慎操作.\n数据库:' + database_size;
|
||||||
}
|
|
||||||
}
|
return '<div class="check_layer_database">' +
|
||||||
action = "AddAcceptPort";
|
'<span title="数据库:' + item.name + '">数据库:' + item.name + '</span>' +
|
||||||
}
|
'<span title="' + t_size+'">大小:' + f_size +'</span>' +
|
||||||
|
'<span title="' + (is_time_rule && item.total != 0 ? '重要:此数据库创建时间较早,可能为重要数据,请谨慎操作.' : '') + '时间:' + database_time+'">创建时间:<i ' + (is_time_rule && item.total != 0 ? 'class="warning"' : '') + '>' + database_time + '</i></span>' +
|
||||||
loading = bt.load();
|
'</div>'
|
||||||
bt.send(action, 'firewall/' + action, { port: port, type: type, ps: ps }, function(rdata) {
|
}(item))
|
||||||
loading.close();
|
if(database_html !== '') html += '<div class="check_layer_item">' + database_html +'</div>';
|
||||||
if (callback) callback(rdata);
|
}
|
||||||
})
|
if(html === '') html = '<div style="text-align: center;width: 100%;height: 100%;line-height: 300px;font-size: 15px;">无数据</div>'
|
||||||
}
|
$('.check_layer_content').html(html)
|
||||||
}
|
},
|
||||||
function SafeMessage(j, h, g, f) {
|
yes:function(indes,layers){
|
||||||
if(f == undefined) {
|
if(typeof dbname === "function"){
|
||||||
f = ""
|
dbname(data)
|
||||||
}
|
}else{
|
||||||
var mess = layer.open({
|
bt.database.del_database(data, function (rdata) {
|
||||||
type: 1,
|
layer.closeAll()
|
||||||
title: j,
|
if (rdata.status) database_table.$refresh_table_list(true);
|
||||||
area: "350px",
|
if (callback) callback(rdata);
|
||||||
closeBtn: 2,
|
bt.msg(rdata);
|
||||||
shadeClose: true,
|
})
|
||||||
content: "<div class='bt-form webDelete pd20 pb70'><p>" + h + "</p>" + f + "<div class='bt-form-submit-btn'><button type='button' class='btn btn-danger btn-sm bt-cancel'>"+lan.public.cancel+"</button> <button type='button' id='toSubmit' class='btn btn-success btn-sm' >"+lan.public.ok+"</button></div></div>"
|
}
|
||||||
});
|
}
|
||||||
$(".bt-cancel").click(function(){
|
})
|
||||||
layer.close(mess);
|
})
|
||||||
});
|
}
|
||||||
$("#toSubmit").click(function() {
|
})
|
||||||
layer.close(mess);
|
}
|
||||||
g();
|
}
|
||||||
})
|
if("undefined" != typeof site && site.hasOwnProperty("del_site")){
|
||||||
}
|
site.del_site = function(wid, wname, callback) {
|
||||||
$(document).ready(function () {
|
var title = typeof wname === "function" ? '批量删除站点' : '删除站点 [ ' + wname + ' ]';
|
||||||
if($('#updata_pro_info').length>0){
|
recycle_bin_open = bt.get_cookie("is_recycle") || bt.get_cookie("is_recycle") == null ? true : false
|
||||||
$('#updata_pro_info').html('');
|
layer.open({
|
||||||
bt.set_cookie('productPurchase', 1);
|
type: 1,
|
||||||
}
|
title: title,
|
||||||
|
icon: 0,
|
||||||
|
skin: 'delete_site_layer',
|
||||||
|
area: "440px",
|
||||||
|
closeBtn: 2,
|
||||||
|
shadeClose: true,
|
||||||
|
content: "<div class=\'bt-form webDelete pd30\' id=\'site_delete_form\'>" +
|
||||||
|
'<i class="layui-layer-ico layui-layer-ico0"></i>' +
|
||||||
|
"<div class=\'f13 check_title\'>是否要删除关联的FTP、数据库、站点目录!</div>" +
|
||||||
|
"<div class=\"check_type_group\">" +
|
||||||
|
"<label><input type=\"checkbox\" name=\"ftp\"><span>FTP</span></label>" +
|
||||||
|
"<label><input type=\"checkbox\" name=\"database\"><span>数据库</span>" + (!recycle_bin_db_open ? '<span class="glyphicon glyphicon-info-sign" style="color: red"></span>' : '') + "</label>" +
|
||||||
|
"<label><input type=\"checkbox\" name=\"path\"><span>站点目录</span>" + (!recycle_bin_open ? '<span class="glyphicon glyphicon-info-sign" style="color: red"></span>' : '') + "</label>" +
|
||||||
|
"</div>" +
|
||||||
|
"</div>",
|
||||||
|
btn: [lan.public.ok, lan.public.cancel],
|
||||||
|
success: function (layers, indexs) {
|
||||||
|
$(layers).find('.check_type_group label').hover(function () {
|
||||||
|
var name = $(this).find('input').attr('name');
|
||||||
|
if (name === 'data' && !recycle_bin_db_open) {
|
||||||
|
layer.tips('风险操作:当前数据库回收站未开启,删除数据库将永久消失!', this, { tips: [1, 'red'], time: 0 })
|
||||||
|
} else if (name === 'path' && !recycle_bin_open) {
|
||||||
|
layer.tips('风险操作:当前文件回收站未开启,删除站点目录将永久消失!', this, { tips: [1, 'red'], time: 0 })
|
||||||
|
}
|
||||||
|
}, function () {
|
||||||
|
layer.closeAll('tips');
|
||||||
|
})
|
||||||
|
},
|
||||||
|
yes: function (indexs) {
|
||||||
|
var data = { id: wid, webname: wname };
|
||||||
|
$('#site_delete_form input[type=checkbox]').each(function (index, item) {
|
||||||
|
if ($(item).is(':checked')) data[$(item).attr('name')] = 1
|
||||||
|
})
|
||||||
|
var is_database = data.hasOwnProperty('database'), is_path = data.hasOwnProperty('path'), is_ftp = data.hasOwnProperty('ftp');
|
||||||
|
if ((!is_database && !is_path) && (!is_ftp || is_ftp)) {
|
||||||
|
if (typeof wname === "function") {
|
||||||
|
wname(data)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
bt.site.del_site(data, function (rdata) {
|
||||||
|
layer.close(indexs);
|
||||||
|
if (callback) callback(rdata);
|
||||||
|
bt.msg(rdata);
|
||||||
|
})
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if (typeof wname === "function") {
|
||||||
|
delete data.id;
|
||||||
|
delete data.webname;
|
||||||
|
}
|
||||||
|
layer.close(indexs)
|
||||||
|
var arrs = wid instanceof Array ? wid : [wid]
|
||||||
|
var ids = JSON.stringify(arrs), countDown = 9;
|
||||||
|
if (arrs.length == 1) countDown = 4
|
||||||
|
title = typeof wname === "function" ? '二次验证信息,批量删除站点' : '二次验证信息,删除站点 [ ' + wname + ' ]';
|
||||||
|
var loadT = bt.load('正在检测站点数据信息,请稍后...')
|
||||||
|
bt.send('check_del_data', 'site/check_del_data', { ids: ids }, function (res) {
|
||||||
|
loadT.close()
|
||||||
|
layer.open({
|
||||||
|
type: 1,
|
||||||
|
title: title,
|
||||||
|
closeBtn: 2,
|
||||||
|
skin: 'verify_site_layer_info',
|
||||||
|
area: '740px',
|
||||||
|
content: '<div class="check_delete_site_main pd30">' +
|
||||||
|
'<i class="layui-layer-ico layui-layer-ico0"></i>' +
|
||||||
|
'<div class="check_layer_title">堡塔温馨提示您,请冷静几秒钟,确认以下要删除的数据。</div>' +
|
||||||
|
'<div class="check_layer_content">' +
|
||||||
|
'<div class="check_layer_item">' +
|
||||||
|
'<div class="check_layer_site"></div>' +
|
||||||
|
'<div class="check_layer_database"></div>' +
|
||||||
|
'</div>' +
|
||||||
|
'</div>' +
|
||||||
|
'<div class="check_layer_error ' + (data.database && recycle_bin_db_open ? 'hide' : '') + '"><span class="glyphicon glyphicon-info-sign"></span>风险事项:当前未开启数据库回收站功能,删除数据库后,数据库将永久消失!</div>' +
|
||||||
|
'<div class="check_layer_error ' + (data.path && recycle_bin_open ? 'hide' : '') + '"><span class="glyphicon glyphicon-info-sign"></span>风险事项:当前未开启文件回收站功能,删除站点目录后,站点目录将永久消失!</div>' +
|
||||||
|
'<div class="check_layer_message"><span style="color:red">注意:请仔细阅读以上要删除信息,防止网站数据被误删</span></div>' +
|
||||||
|
'</div>',
|
||||||
|
// recycle_bin_db_open &&
|
||||||
|
// recycle_bin_open &&
|
||||||
|
btn: ['确认删除', '取消删除'],
|
||||||
|
success: function (layers) {
|
||||||
|
var html = '', rdata = res.data;
|
||||||
|
for (var i = 0; i < rdata.length; i++) {
|
||||||
|
var item = rdata[i], newTime = parseInt(new Date().getTime() / 1000),
|
||||||
|
t_icon = '<span class="glyphicon glyphicon-info-sign" style="color: red;width:15px;height: 15px;;vertical-align: middle;"></span>';
|
||||||
|
|
||||||
|
site_html = (function (item) {
|
||||||
|
if (!is_path) return ''
|
||||||
|
var is_time_rule = (newTime - item.st_time) > (86400 * 30) && (item.total > 1024 * 10),
|
||||||
|
is_path_rule = res.file_size <= item.total,
|
||||||
|
dir_time = bt.format_data(item.st_time, 'yyyy-MM-dd'),
|
||||||
|
dir_size = bt.format_size(item.total);
|
||||||
|
|
||||||
|
var f_html = '<i ' + (is_path_rule ? 'class="warning"' : '') + ' style = "vertical-align: middle;" > ' + dir_size + '</i> ' + (is_path_rule ? t_icon : '');
|
||||||
|
var f_title = (is_path_rule ? '注意:此目录较大,可能为重要数据,请谨慎操作.\n' : '') + '目录:' + item.path + '(' + (item.limit ? '大于' : '') + dir_size + ')';
|
||||||
|
|
||||||
|
return '<div class="check_layer_site">' +
|
||||||
|
'<span title="站点:' + item.name + '">站点名:' + item.name + '</span>' +
|
||||||
|
'<span title="' + f_title + '" >目录:<span style="vertical-align: middle;max-width: 160px;width: auto;">' + item.path + '</span> (' + f_html + ')</span>' +
|
||||||
|
'<span title="' + (is_time_rule ? '注意:此站点创建时间较早,可能为重要数据,请谨慎操作.\n' : '') + '时间:' + dir_time + '">创建时间:<i ' + (is_time_rule ? 'class="warning"' : '') + '>' + dir_time + '</i></span>' +
|
||||||
|
'</div>'
|
||||||
|
}(item)),
|
||||||
|
database_html = (function (item) {
|
||||||
|
if (!is_database || !item.database) return '';
|
||||||
|
var is_time_rule = (newTime - item.st_time) > (86400 * 30) && (item.total > 1024 * 10),
|
||||||
|
is_database_rule = res.db_size <= item.database.total,
|
||||||
|
database_time = bt.format_data(item.database.st_time, 'yyyy-MM-dd'),
|
||||||
|
database_size = bt.format_size(item.database.total);
|
||||||
|
|
||||||
|
var f_size = '<i ' + (is_database_rule ? 'class="warning"' : '') + ' style = "vertical-align: middle;" > ' + database_size + '</i> ' + (is_database_rule ? t_icon : '');
|
||||||
|
var t_size = '注意:此数据库较大,可能为重要数据,请谨慎操作.\n数据库:' + database_size;
|
||||||
|
|
||||||
|
return '<div class="check_layer_database">' +
|
||||||
|
'<span title="数据库:' + item.database.name + '">数据库:' + item.database.name + '</span>' +
|
||||||
|
'<span title="' + t_size + '">大小:' + f_size + '</span>' +
|
||||||
|
'<span title="' + (is_time_rule && item.database.total != 0 ? '重要:此数据库创建时间较早,可能为重要数据,请谨慎操作.' : '') + '时间:' + database_time + '">创建时间:<i ' + (is_time_rule && item.database.total != 0 ? 'class="warning"' : '') + '>' + database_time + '</i></span>' +
|
||||||
|
'</div>'
|
||||||
|
}(item))
|
||||||
|
if ((site_html + database_html) !== '') html += '<div class="check_layer_item">' + site_html + database_html + '</div>';
|
||||||
|
}
|
||||||
|
if (html === '') html = '<div style="text-align: center;width: 100%;height: 100%;line-height: 300px;font-size: 15px;">无数据</div>'
|
||||||
|
$('.check_layer_content').html(html)
|
||||||
|
},
|
||||||
|
yes: function (indes, layers) {
|
||||||
|
if (typeof wname === "function") {
|
||||||
|
wname(data)
|
||||||
|
} else {
|
||||||
|
bt.site.del_site(data, function (rdata) {
|
||||||
|
layer.closeAll()
|
||||||
|
if (rdata.status) site.get_list();
|
||||||
|
if (callback) callback(rdata);
|
||||||
|
bt.msg(rdata);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
if(bt.get_cookie("is_recycle") || bt.get_cookie("is_recycle")==null){
|
||||||
|
$('[name="path"]').attr('checked',true)
|
||||||
|
}else{
|
||||||
|
$('[name="path"]').removeProp('checked');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if("undefined" != typeof bt && bt.hasOwnProperty("firewall") && bt.firewall.hasOwnProperty("add_accept_port")){
|
||||||
|
bt.firewall.add_accept_port = function(type, port, ps, callback) {
|
||||||
|
var action = "AddDropAddress";
|
||||||
|
if (type == 'port') {
|
||||||
|
ports = port.split(':');
|
||||||
|
if (port.indexOf('-') != -1) ports = port.split('-');
|
||||||
|
for (var i = 0; i < ports.length; i++) {
|
||||||
|
if (!bt.check_port(ports[i])) {
|
||||||
|
layer.msg(lan.firewall.port_err, { icon: 5 });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
action = "AddAcceptPort";
|
||||||
|
}
|
||||||
|
|
||||||
|
loading = bt.load();
|
||||||
|
bt.send(action, 'firewall/' + action, { port: port, type: type, ps: ps }, function(rdata) {
|
||||||
|
loading.close();
|
||||||
|
if (callback) callback(rdata);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function SafeMessage(j, h, g, f) {
|
||||||
|
if(f == undefined) {
|
||||||
|
f = ""
|
||||||
|
}
|
||||||
|
var mess = layer.open({
|
||||||
|
type: 1,
|
||||||
|
title: j,
|
||||||
|
area: "350px",
|
||||||
|
closeBtn: 2,
|
||||||
|
shadeClose: true,
|
||||||
|
content: "<div class='bt-form webDelete pd20 pb70'><p>" + h + "</p>" + f + "<div class='bt-form-submit-btn'><button type='button' class='btn btn-danger btn-sm bt-cancel'>"+lan.public.cancel+"</button> <button type='button' id='toSubmit' class='btn btn-success btn-sm' >"+lan.public.ok+"</button></div></div>"
|
||||||
|
});
|
||||||
|
$(".bt-cancel").click(function(){
|
||||||
|
layer.close(mess);
|
||||||
|
});
|
||||||
|
$("#toSubmit").click(function() {
|
||||||
|
layer.close(mess);
|
||||||
|
g();
|
||||||
|
})
|
||||||
|
}
|
||||||
|
$(document).ready(function () {
|
||||||
|
if($('#updata_pro_info').length>0){
|
||||||
|
$('#updata_pro_info').html('');
|
||||||
|
bt.set_cookie('productPurchase', 1);
|
||||||
|
}
|
||||||
})
|
})
|
||||||
258
wiki/update.md
258
wiki/update.md
@ -1,110 +1,148 @@
|
|||||||
# Linux面板官方更新包修改记录
|
# Linux面板官方更新包修改记录
|
||||||
|
|
||||||
查询最新版本号:https://www.bt.cn/api/panel/get_version?is_version=1
|
查询最新版本号:https://www.bt.cn/api/panel/get_version?is_version=1
|
||||||
|
|
||||||
官方更新包下载链接:http://download.bt.cn/install/update/LinuxPanel-版本号.zip
|
官方更新包下载链接:http://download.bt.cn/install/update/LinuxPanel-版本号.zip
|
||||||
|
|
||||||
假设搭建的宝塔第三方云端网址是 http://www.example.com
|
假设搭建的宝塔第三方云端网址是 http://www.example.com
|
||||||
|
|
||||||
- 将class文件夹里面所有的.so文件删除
|
- 将class文件夹里面所有的.so文件删除
|
||||||
|
|
||||||
- 将PluginLoader.py复制到class文件夹
|
- 将linux/PluginLoader.py复制到class文件夹
|
||||||
|
|
||||||
- 批量解密模块文件:执行 php think decrypt classdir <面板class文件夹路径>
|
- 批量解密模块文件:执行 php think decrypt classdir <面板class文件夹路径>
|
||||||
|
|
||||||
- 全局搜索替换 https://api.bt.cn => http://www.example.com
|
- 全局搜索替换 https://api.bt.cn => http://www.example.com
|
||||||
|
|
||||||
- 全局搜索替换 https://www.bt.cn/api/ => http://www.example.com/api/(需排除clearModel.py、scanningModel.py、ipsModel.py)
|
- 全局搜索替换 https://www.bt.cn/api/ => http://www.example.com/api/(需排除clearModel.py、scanningModel.py、ipsModel.py、domainMod.py、js文件)
|
||||||
|
|
||||||
- class/panelAuth.py 替换 http://www.bt.cn/api/ => http://www.example.com/api/
|
- 全局搜索替换 http://www.bt.cn/api/ => http://www.example.com/api/(需排除js文件)
|
||||||
|
|
||||||
- 全局搜索替换 http://download.bt.cn/install/update6.sh => http://www.example.com/install/update6.sh
|
- 全局搜索替换 https://www.bt.cn/newapi/ => http://www.example.com/newapi/
|
||||||
|
|
||||||
- class/ajax.py 文件 \#是否执行升级程序 下面的 public.get_url() 改成 public.GetConfigValue('home')
|
- 全局搜索替换 https://download.bt.cn/install/update6.sh => http://www.example.com/install/update6.sh
|
||||||
|
|
||||||
class/jobs.py 文件 \#尝试升级到独立环境 下面的 public.get_url() 改成 public.GetConfigValue('home')
|
http://download.bt.cn/install/update6.sh => http://www.example.com/install/update6.sh
|
||||||
|
|
||||||
class/system.py 文件 RepPanel和UpdatePro方法内的 public.get_url() 改成 public.GetConfigValue('home')
|
http://download.bt.cn/install/update/ => http://www.example.com/install/update/
|
||||||
|
|
||||||
- class/public.py 在
|
- 搜索并删除提交异常报告的代码 bt_error/index.php
|
||||||
|
|
||||||
```python
|
- class/ajax.py 文件 \# 是否执行升级程序 下面的 public.get_url() 改成 public.GetConfigValue('home')
|
||||||
def GetConfigValue(key):
|
|
||||||
```
|
class/jobs.py 文件 \#尝试升级到独立环境 下面的 public.get_url() 改成 public.GetConfigValue('home')
|
||||||
|
|
||||||
这一行下面加上
|
class/system.py 文件 RepPanel和UpdatePro方法内的 public.get_url() 改成 public.GetConfigValue('home')
|
||||||
|
|
||||||
```python
|
- class/public.py 在
|
||||||
if key == 'home': return 'http://www.example.com'
|
|
||||||
```
|
```python
|
||||||
|
def GetConfigValue(key):
|
||||||
在 def is_bind(): 这一行下面加上 return True
|
```
|
||||||
|
|
||||||
在 def check_domain_cloud(domain): 这一行下面加上 return
|
这一行下面加上
|
||||||
|
|
||||||
在 def get_improvement(): 这一行下面加上 return False
|
```python
|
||||||
|
if key == 'home': return 'http://www.example.com'
|
||||||
在free_login_area方法内get_free_ips_area替换成get_ips_area
|
```
|
||||||
|
|
||||||
- class/panelPlugin.py 文件,download_icon方法内替换 public.GetConfigValue('home') => 'https://www.bt.cn'
|
在 def is_bind(): 这一行下面加上 return True
|
||||||
|
|
||||||
删除public.total_keyword(get.query)这一行
|
在 def check_domain_cloud(domain): 这一行下面加上 return
|
||||||
|
|
||||||
set_pyenv方法内,temp_file = public.readFile(filename)这行代码下面加上
|
在 def err_collect 这一行下面加上 return
|
||||||
|
|
||||||
```python
|
在 def get_improvement(): 这一行下面加上 return False
|
||||||
temp_file = temp_file.replace('wget -O Tpublic.sh', '#wget -O Tpublic.sh')
|
|
||||||
temp_file = temp_file.replace('\cp -rpa Tpublic.sh', '#\cp -rpa Tpublic.sh')
|
在free_login_area方法内get_free_ips_area替换成get_ips_area
|
||||||
temp_file = temp_file.replace('http://download.bt.cn/install/public.sh', 'http://www.example.com/install/public.sh')
|
|
||||||
```
|
在get_free_ip_info方法内,获取IP的部分改成res = get_ips_area([address])
|
||||||
|
|
||||||
- install/install_soft.sh 在bash执行之前加入以下代码
|
在login_send_body方法内,free_login_area(login_ip=server_ip_area的server_ip_area改成login_ip
|
||||||
|
|
||||||
```shell
|
- class/panelPlugin.py 文件
|
||||||
sed -i "s/http:\/\/download.bt.cn\/install\/public.sh/http:\/\/www.example.com\/install\/public.sh/" lib.sh
|
|
||||||
sed -i "/wget -O Tpublic.sh/d" $name.sh
|
__set_pyenv方法内,temp_file = public.readFile(filename)这行代码下面加上
|
||||||
```
|
|
||||||
|
```python
|
||||||
- install/public.sh 用官网最新版的[public.sh](http://download.bt.cn/install/public.sh)替换,并去除最下面bt_check一行
|
temp_file = temp_file.replace('http://download.bt.cn/install/public.sh', 'http://www.example.com/install/public.sh')
|
||||||
|
temp_file = temp_file.replace('https://download.bt.cn/install/public.sh', 'http://www.example.com/install/public.sh')
|
||||||
- 去除无用的定时任务:task.py 文件 删除以下几行
|
```
|
||||||
|
|
||||||
"update_software_list": update_software_list,
|
def check_status(self, softInfo): 方法最后一行加上
|
||||||
|
|
||||||
"check_panel_msg": check_panel_msg,
|
```python
|
||||||
|
if 'endtime' in softInfo:
|
||||||
PluginLoader.daemon_panel()
|
softInfo['endtime'] = time.time() + 86400 * 3650
|
||||||
|
```
|
||||||
- 去除WebRTC连接:BTPanel/static/js/public.js 删除stun.start();这一行
|
|
||||||
|
plugin_bin.pl 改成 plugin_list.json
|
||||||
- 去除首页广告:BTPanel/static/js/index.js 文件删除最下面index.recommend_paid_version()这一行
|
|
||||||
|
删除 public.total_keyword(get.query)
|
||||||
- 去除首页自动检测更新,避免频繁请求云端:BTPanel/static/js/index.js 文件注释掉bt.system.check_update这一段代码外的setTimeout
|
|
||||||
|
删除 public.run_thread(self.get_cloud_list_status, args=(get,))
|
||||||
- 去除内页广告:BTPanel/templates/default/layout.html 删除getPaymentStatus();这一行
|
|
||||||
|
删除 public.run_thread(self.is_verify_unbinding, args=(get,))
|
||||||
- [可选]去除各种计算题:复制bt.js到 BTPanel/static/ ,在 BTPanel/templates/default/layout.html 的\</body\>前面加入
|
|
||||||
|
- class/plugin_deployment.py 文件,__setup_php_environment方法和GetJarPath方法内替换 public.GetConfigValue('home') => 'https://www.bt.cn'
|
||||||
```javascript
|
|
||||||
<script src="/static/bt.js"></script>
|
- class/config.py 文件,get_nps方法内data['nps'] = False改成True,get_nps_new方法下面加上 return public.returnMsg(False, "获取问卷失败")
|
||||||
```
|
|
||||||
|
def err_collection(self, get): 这一行下面加上 return public.returnMsg(True, "OK")
|
||||||
- [可选]去除创建网站自动创建的垃圾文件:在class/panelSite.py,分别删除
|
|
||||||
|
- class/push/site_push.py 文件,'https://www.bt.cn' => 'http://www.example.com'
|
||||||
htaccess = self.sitePath+'/.htaccess'
|
|
||||||
|
- script/flush_plugin.py 文件,删除clear_hosts()一行
|
||||||
index = self.sitePath+'/index.html'
|
|
||||||
|
- script/reload_check.py 文件,在第2行插入sys.exit()
|
||||||
doc404 = self.sitePath+'/404.html'
|
|
||||||
|
- script/local_fix.sh 文件,${D_NODE_URL}替换成www.example.com
|
||||||
这3行及分别接下来的4行代码
|
|
||||||
|
- script/upgrade_panel_optimized.py 文件,def get_home_node(url): 下面加上return url
|
||||||
- [可选]关闭未绑定域名提示页面:在class/panelSite.py,root /www/server/nginx/html改成return 400
|
|
||||||
|
- install/install_soft.sh 在. 执行之前加入以下代码
|
||||||
- [可选]关闭自动生成访问日志:在 BTPanel/\_\_init\_\_.py 删除public.write_request_log()这一行
|
|
||||||
|
```shell
|
||||||
|
sed -i "s/http:\/\/download.bt.cn\/install\/public.sh/http:\/\/www.example.com\/install\/public.sh/" $name.sh
|
||||||
解压安装包panel6.zip,将更新包改好的文件覆盖到里面,然后重新打包,即可更新安装包。(
|
sed -i "s/https:\/\/download.bt.cn\/install\/public.sh/http:\/\/www.example.com\/install\/public.sh/" $name.sh
|
||||||
|
```
|
||||||
别忘了删除class文件夹里面所有的.so文件)
|
|
||||||
|
- install/public.sh 用官网最新版的[public.sh](http://download.bt.cn/install/public.sh)替换,并去除最下面bt_check一行
|
||||||
|
|
||||||
|
- 去除无用的定时任务:task.py 文件 删除以下几行
|
||||||
|
|
||||||
|
check_panel_msg,
|
||||||
|
|
||||||
|
refresh_domain_cache,
|
||||||
|
|
||||||
|
task_ssh_error_count,
|
||||||
|
|
||||||
|
- [可选]去除各种计算题:复制bt.js到 BTPanel/static/ ,在 BTPanel/templates/default/software.html 的 \<script\>window.vite_public_request_token 前面加入
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
<script src="/static/bt.js"></script>
|
||||||
|
```
|
||||||
|
|
||||||
|
- [可选]去除创建网站自动创建的垃圾文件:在class/panelSite.py,分别删除
|
||||||
|
|
||||||
|
htaccess = self.sitePath + '/.htaccess'
|
||||||
|
|
||||||
|
index = self.sitePath + '/index.html'
|
||||||
|
|
||||||
|
doc404 = self.sitePath + '/404.html'
|
||||||
|
|
||||||
|
这3行及分别接下来的4行代码
|
||||||
|
|
||||||
|
def get_view_title_content(self, get): 下面加上 return public.returnMsg(True, '')
|
||||||
|
|
||||||
|
- [可选]关闭未绑定域名提示页面:在class/panelSite.py,root /www/server/nginx/html改成return 400
|
||||||
|
|
||||||
|
- [可选]关闭自动生成访问日志:在 BTPanel/\_\_init\_\_.py 删除public.write_request_log这一行
|
||||||
|
|
||||||
|
- [可选]新版vite页面去除需求反馈、各种广告、计算题等,执行 php think cleanvitejs <面板BTPanel/static/js路径>
|
||||||
|
|
||||||
|
|
||||||
|
解压安装包[panel6.zip](http://download.bt.cn/install/src/panel6.zip),将更新包改好的文件覆盖到里面,然后重新打包,即可更新安装包。(
|
||||||
|
|
||||||
|
别忘了删除class文件夹里面所有的.so文件)
|
||||||
|
|
||||||
|
|||||||
@ -1,76 +1,10 @@
|
|||||||
# Windows面板官方更新包修改记录
|
# Windows面板官方更新包修改记录
|
||||||
|
|
||||||
查询最新版本号:https://www.bt.cn/api/wpanel/get_version?is_version=1
|
查询最新版本号:https://www.bt.cn/api/wpanel/get_version?is_version=1
|
||||||
|
|
||||||
官方更新包下载链接:http://download.bt.cn/win/panel/panel_版本号.zip
|
官方更新包下载链接:http://download.bt.cn/win/panel/panel_版本号.zip
|
||||||
|
|
||||||
假设搭建的宝塔第三方云端网址是 http://www.example.com
|
- 使用16进制编辑器打开btPanel.exe,将 https://api.bt.cn 替换成 http://api.bt.cn/ ,将 https://www.bt.cn 替换成 http://www.bt.cn/ ,然后将api.bt.cn替换成任意其他域名,将第二个www.bt.cn替换成任意其他域名。
|
||||||
|
- 批量解密模块文件:执行 php think decrypt classdir <面板class文件夹路径>
|
||||||
Windows版宝塔由于加密文件太多,无法全部解密,因此无法做到全开源。
|
- 新版vite页面去除需求反馈、各种广告、计算题等,执行 php think cleanvitejs <面板assets/static/js路径>
|
||||||
|
|
||||||
- 删除PluginLoader.pyd,将win/PluginLoader.py复制到class文件夹
|
|
||||||
|
|
||||||
- 全局搜索替换 https://api.bt.cn => http://www.example.com
|
|
||||||
|
|
||||||
- 全局搜索替换 https://www.bt.cn/api/ => http://www.example.com/api/(需排除ipsModel.py)
|
|
||||||
|
|
||||||
- 全局搜索替换 http://www.bt.cn/api/ => http://www.example.com/api/
|
|
||||||
|
|
||||||
- 全局搜索替换 http://download.bt.cn/win/panel/data/setup.py => http://www.example.com/win/panel/data/setup.py
|
|
||||||
|
|
||||||
- class/panel_update.py 文件 public.get_url() => 'http://www.example.com'
|
|
||||||
|
|
||||||
- class/public.py 在
|
|
||||||
|
|
||||||
```python
|
|
||||||
def GetConfigValue(key):
|
|
||||||
```
|
|
||||||
|
|
||||||
这一行下面加上
|
|
||||||
|
|
||||||
```python
|
|
||||||
if key == 'home': return 'http://www.example.com'
|
|
||||||
```
|
|
||||||
|
|
||||||
在 def is_bind(): 这一行下面加上 return True
|
|
||||||
|
|
||||||
在 def check_domain_cloud(domain): 这一行下面加上 return
|
|
||||||
|
|
||||||
在 get_update_file() 方法里面 get_url() => GetConfigValue('home')
|
|
||||||
|
|
||||||
- class/plugin_deployment.py 文件 get_icon 和 SetupPackage 方法内,替换 public.GetConfigValue('home') => 'https://www.bt.cn'
|
|
||||||
|
|
||||||
- 去除无用的定时任务:task.py 文件
|
|
||||||
|
|
||||||
删除 p = threading.Thread(target=check_files_panel) 以及下面2行
|
|
||||||
|
|
||||||
删除 p = threading.Thread(target=check_panel_msg) 以及下面2行
|
|
||||||
|
|
||||||
删除 p = threading.Thread(target=update_software_list) 以及下面2行
|
|
||||||
|
|
||||||
- 去除面板日志上报:script/site_task.py 文件
|
|
||||||
|
|
||||||
- 删除最下面 logs_analysis() 这1行
|
|
||||||
|
|
||||||
- 去除首页广告:BTPanel/static/js/index.js 文件删除最下面index.recommend_paid_version()这一行
|
|
||||||
|
|
||||||
- 去除首页自动检测更新,避免频繁请求云端:BTPanel/static/js/index.js 文件注释掉bt.system.check_update这一段代码外的setTimeout
|
|
||||||
|
|
||||||
- [可选]去除各种计算题:复制win/bt.js到 BTPanel/static/ ,在 BTPanel/templates/default/layout.html 的尾部加入
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
<script src="/static/bt.js"></script>
|
|
||||||
```
|
|
||||||
|
|
||||||
- [可选]去除创建网站自动创建的垃圾文件:class/panelSite.py 文件
|
|
||||||
|
|
||||||
删除 htaccess = self.sitePath + '/.htaccess' 以及下面2行
|
|
||||||
|
|
||||||
删除 index = self.sitePath + '/index.html' 以及下面6行
|
|
||||||
|
|
||||||
删除 doc404 = self.sitePath + '/404.html' 以及下面6行
|
|
||||||
|
|
||||||
删除 if not os.path.exists(self.sitePath + '/.htaccess') 这一行
|
|
||||||
|
|
||||||
- [可选]关闭自动生成访问日志:在 BTPanel/\_\_init\_\_.py 删除public.write_request_log()这一行
|
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user