mirror of
https://github.com/flucont/btcloud.git
synced 2025-10-14 22:47:11 +00:00
Compare commits
8 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
2c9f84c121 | ||
![]() |
ab81af3b94 | ||
![]() |
98f9ca0e5b | ||
![]() |
50cfdaa06f | ||
![]() |
ae4ed95573 | ||
![]() |
e98206ce0c | ||
![]() |
8946b4fd11 | ||
![]() |
5bd1670955 |
@@ -5,7 +5,7 @@
|
||||
|
||||
网站后台管理可一键同步宝塔官方的插件列表与增量更新插件包,还有云端使用记录、IP黑白名单、操作日志、定时任务等功能。
|
||||
|
||||
本项目自带的宝塔安装包和更新包是7.9.3最新版,已修改适配此第三方云端,并且全开源,无so等加密文件。
|
||||
本项目自带的宝塔安装包和更新包是7.9.5最新版,已修改适配此第三方云端,并且全开源,无so等加密文件。
|
||||
|
||||
觉得该项目不错的可以给个Star~
|
||||
|
||||
|
115
app/command/DecryptFile.php
Normal file
115
app/command/DecryptFile.php
Normal file
@@ -0,0 +1,115 @@
|
||||
<?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 DecryptFile extends Command
|
||||
{
|
||||
protected function configure()
|
||||
{
|
||||
$this->setName('decrypt')
|
||||
->addArgument('type', Argument::REQUIRED, '文件类型,plugin:插件文件,module:模块文件,classdir:宝塔class目录,all:所有py文件')
|
||||
->addArgument('file', Argument::REQUIRED, '文件路径')
|
||||
->addArgument('os', Argument::OPTIONAL, '操作系统:Windows/Linux')
|
||||
->setDescription('解密宝塔面板python文件');
|
||||
}
|
||||
|
||||
protected function execute(Input $input, Output $output)
|
||||
{
|
||||
$type = trim($input->getArgument('type'));
|
||||
$file = trim($input->getArgument('file'));
|
||||
|
||||
if(!file_exists($file)){
|
||||
$output->writeln('文件不存在');
|
||||
return;
|
||||
}
|
||||
|
||||
if($type == 'plugin'){
|
||||
$os = trim($input->getArgument('os'));
|
||||
try{
|
||||
if(Plugins::decode_plugin_main_local($file, $os)){
|
||||
$output->writeln('文件解密成功!');
|
||||
}else{
|
||||
$output->writeln('文件解密失败!');
|
||||
}
|
||||
}catch(\Exception $e){
|
||||
$output->writeln($e->getMessage());
|
||||
}
|
||||
}elseif($type == 'module'){
|
||||
try{
|
||||
$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'){
|
||||
$file = rtrim($file, '/');
|
||||
if(!file_exists($file.'/common.py')){
|
||||
$output->writeln('当前路径非宝塔面板class目录');
|
||||
return;
|
||||
}
|
||||
$dirs = glob($file.'/*Model');
|
||||
foreach($dirs as $dir){
|
||||
if(!is_dir($dir))continue;
|
||||
$files = glob($dir.'/*Model.py');
|
||||
foreach($files as $file){
|
||||
try{
|
||||
$res = Plugins::decode_module_file($file);
|
||||
if($res == 2){
|
||||
$output->writeln('文件解密失败:'.$file);
|
||||
}elseif($res == 1){
|
||||
$output->writeln('文件解密成功:'.$file);
|
||||
}
|
||||
}catch(\Exception $e){
|
||||
$output->writeln($e->getMessage().':'.$file);
|
||||
}
|
||||
}
|
||||
}
|
||||
}elseif($type == 'all'){
|
||||
$file = rtrim($file, '/');
|
||||
$this->scan_all_file($input, $output, $file);
|
||||
}else{
|
||||
$output->writeln('未知文件类型');
|
||||
}
|
||||
}
|
||||
|
||||
private function scan_all_file(Input $input, Output $output, $path) {
|
||||
$dir = opendir($path);
|
||||
while(false !== ( $file = readdir($dir)) ) {
|
||||
if (( $file != '.' ) && ( $file != '..' )) {
|
||||
$filepath = $path . '/' . $file;
|
||||
if ( is_dir($filepath) ) {
|
||||
$this->scan_all_file($input, $output, $filepath);
|
||||
}
|
||||
elseif(substr($filepath, -3) == '.py') {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
closedir($dir);
|
||||
}
|
||||
|
||||
|
||||
}
|
@@ -272,6 +272,12 @@ class Api extends BaseController
|
||||
return json($json_arr);
|
||||
}
|
||||
|
||||
//获取宝塔SSL列表
|
||||
public function get_ssl_list(){
|
||||
$data = bin2hex('[]');
|
||||
return json(['status'=>true, 'msg'=>'', 'data'=>$data]);
|
||||
}
|
||||
|
||||
public function return_success(){
|
||||
return json(['status'=>true, 'msg'=>1, 'data'=>(object)[]]);
|
||||
}
|
||||
|
@@ -52,6 +52,8 @@ class Install extends BaseController
|
||||
$sqls=file_get_contents(app()->getRootPath().'install.sql');
|
||||
$sqls=explode(';', $sqls);
|
||||
$sqls[]="REPLACE INTO `".$mysql_prefix."config` VALUES ('syskey', '".random(16)."')";
|
||||
$sqls[]="REPLACE INTO `".$mysql_prefix."config` VALUES ('admin_username', '".addslashes($admin_username)."')";
|
||||
$sqls[]="REPLACE INTO `".$mysql_prefix."config` VALUES ('admin_password', '".addslashes($admin_password)."')";
|
||||
$success=0;$error=0;$errorMsg=null;
|
||||
foreach ($sqls as $value) {
|
||||
$value=trim($value);
|
||||
|
@@ -187,6 +187,8 @@ class Plugins
|
||||
$userinfo = $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);
|
||||
@@ -202,7 +204,7 @@ class Plugins
|
||||
if($tmp) $de_text .= $tmp;
|
||||
}
|
||||
}
|
||||
if(!empty($de_text)){
|
||||
if(!empty($de_text) && strpos($de_text, 'import ')!==false){
|
||||
file_put_contents($main_filepath, $de_text);
|
||||
return true;
|
||||
}
|
||||
@@ -212,6 +214,28 @@ class Plugins
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
@@ -1,7 +1,7 @@
|
||||
#!/bin/bash
|
||||
|
||||
Linux_Version="7.9.3"
|
||||
Windows_Version="7.6.0"
|
||||
Linux_Version="7.9.6"
|
||||
Windows_Version="7.8.0"
|
||||
|
||||
FILES=(
|
||||
public/install/src/panel6.zip
|
||||
|
@@ -2,6 +2,7 @@
|
||||
{block name="title"}宝塔第三方云端管理中心{/block}
|
||||
{block name="main"}
|
||||
<style>
|
||||
.table>tbody>tr>td{white-space: normal;}
|
||||
.query-title {
|
||||
background-color:#f5fafe;
|
||||
word-break: keep-all;
|
||||
|
@@ -70,12 +70,14 @@ function submitlogin(){
|
||||
var pass = $("input[name='pass']").val();
|
||||
var code = $("input[name='code']").val();
|
||||
if(user=='' || pass==''){layer.alert('用户名或密码不能为空!');return false;}
|
||||
$.ajax({
|
||||
var ii = layer.load(2);
|
||||
$.ajax({
|
||||
type : 'POST',
|
||||
url : '{:request()->url()}',
|
||||
data: {username:user, password:pass, code:code},
|
||||
dataType : 'json',
|
||||
success : function(data) {
|
||||
layer.close(ii);
|
||||
if(data.code == 0){
|
||||
layer.msg('登录成功,正在跳转', {icon: 1,shade: 0.01,time: 15000});
|
||||
window.location.href='/admin';
|
||||
@@ -87,6 +89,7 @@ function submitlogin(){
|
||||
}
|
||||
},
|
||||
error:function(data){
|
||||
layer.close(ii);
|
||||
layer.msg('服务器错误');
|
||||
}
|
||||
});
|
||||
|
@@ -6,5 +6,6 @@ return [
|
||||
// 指令定义
|
||||
'commands' => [
|
||||
'updateall' => 'app\command\UpdateAll',
|
||||
'decrypt' => 'app\command\DecryptFile',
|
||||
],
|
||||
];
|
||||
|
0
data/plugins/folder/.gitkeep
Normal file
0
data/plugins/folder/.gitkeep
Normal file
0
data/plugins/main/.gitkeep
Normal file
0
data/plugins/main/.gitkeep
Normal file
0
data/plugins/other/other/.gitkeep
Normal file
0
data/plugins/other/other/.gitkeep
Normal file
0
data/plugins/package/.gitkeep
Normal file
0
data/plugins/package/.gitkeep
Normal file
0
data/win/plugins/folder/.gitkeep
Normal file
0
data/win/plugins/folder/.gitkeep
Normal file
0
data/win/plugins/main/.gitkeep
Normal file
0
data/win/plugins/main/.gitkeep
Normal file
0
data/win/plugins/package/.gitkeep
Normal file
0
data/win/plugins/package/.gitkeep
Normal file
@@ -12,12 +12,12 @@ INSERT INTO `cloud_config` (`key`, `value`) VALUES
|
||||
('bt_key', ''),
|
||||
('whitelist', '0'),
|
||||
('download_page', '1'),
|
||||
('new_version', '7.9.3'),
|
||||
('new_version', '7.9.6'),
|
||||
('update_msg', '暂无更新日志'),
|
||||
('update_date', '2022-07-13'),
|
||||
('new_version_win', '7.6.0'),
|
||||
('update_date', '2022-11-29'),
|
||||
('new_version_win', '7.8.0'),
|
||||
('update_msg_win', '暂无更新日志'),
|
||||
('update_date_win', '2022-06-01'),
|
||||
('update_date_win', '2022-12-08'),
|
||||
('updateall_type', '0'),
|
||||
('syskey', 'UqP94LtI8eWAIgCP');
|
||||
|
||||
|
@@ -54,6 +54,27 @@ GetSysInfo(){
|
||||
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(){
|
||||
@@ -97,6 +118,33 @@ System_Check(){
|
||||
Install_Check
|
||||
fi
|
||||
}
|
||||
Set_Ssl(){
|
||||
echo -e ""
|
||||
echo -e "----------------------------------------------------------------------"
|
||||
echo -e "为了您的面板使用安全,建议您开启面板SSL,开启后请使用https访问宝塔面板"
|
||||
echo -e "输入y回车即开启面板SSL并进行下一步安装"
|
||||
echo -e "输入n回车跳过面板SSL配置,直接进行安装"
|
||||
echo -e "10秒后将跳过SSL配置,直接进行面板安装"
|
||||
echo -e "----------------------------------------------------------------------"
|
||||
echo -e ""
|
||||
read -t 10 -p "是否确定开启面板SSL ? (y/n): " yes
|
||||
|
||||
if [ $? != 0 ];then
|
||||
SET_SSL=false
|
||||
else
|
||||
case "$yes" in
|
||||
y)
|
||||
SET_SSL=true
|
||||
;;
|
||||
n)
|
||||
SET_SSL=false
|
||||
rm -f /www/server/panel/data/ssl.pl
|
||||
;;
|
||||
*)
|
||||
Set_Ssl
|
||||
esac
|
||||
fi
|
||||
}
|
||||
Get_Pack_Manager(){
|
||||
if [ -f "/usr/bin/yum" ] && [ -d "/etc/yum.repos.d" ]; then
|
||||
PM="yum"
|
||||
@@ -183,7 +231,7 @@ get_node_url(){
|
||||
|
||||
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=(https://dg2.bt.cn https://dg1.bt.cn https://download.bt.cn);
|
||||
|
||||
if [ "$1" ];then
|
||||
nodes=($(echo ${nodes[*]}|sed "s#${1}##"))
|
||||
@@ -225,7 +273,7 @@ get_node_url(){
|
||||
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';
|
||||
NODE_URL='https://download.bt.cn';
|
||||
fi
|
||||
fi
|
||||
rm -f $tmp_file1
|
||||
@@ -287,7 +335,7 @@ Install_RPM_Pack(){
|
||||
|
||||
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"
|
||||
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}
|
||||
@@ -313,7 +361,15 @@ Install_Deb_Pack(){
|
||||
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
|
||||
@@ -333,7 +389,7 @@ Install_Deb_Pack(){
|
||||
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";
|
||||
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}
|
||||
@@ -418,7 +474,7 @@ Install_Python_Lib(){
|
||||
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
|
||||
$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
|
||||
@@ -552,7 +608,7 @@ Install_Python_Lib(){
|
||||
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
|
||||
$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
|
||||
@@ -568,10 +624,7 @@ Install_Bt(){
|
||||
if [ -f ${setup_path}/server/panel/data/port.pl ];then
|
||||
panelPort=$(cat ${setup_path}/server/panel/data/port.pl)
|
||||
else
|
||||
RE_NUM=$(expr $RANDOM % 5)
|
||||
if [ "${RE_NUM}" == "1" ];then
|
||||
panelPort=$(expr $RANDOM % 55535 + 10000)
|
||||
fi
|
||||
panelPort=$(expr $RANDOM % 55535 + 10000)
|
||||
fi
|
||||
mkdir -p ${setup_path}/server/panel/logs
|
||||
mkdir -p ${setup_path}/server/panel/vhost/apache
|
||||
@@ -672,11 +725,19 @@ Set_Bt_Panel(){
|
||||
auth_path=$(cat /dev/urandom | head -n 16 | md5sum | head -c 8)
|
||||
echo "/${auth_path}" > ${admin_auth}
|
||||
fi
|
||||
auth_path=$(cat /dev/urandom | head -n 16 | md5sum | head -c 8)
|
||||
echo "/${auth_path}" > ${admin_auth}
|
||||
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/
|
||||
if [ "$SET_SSL" == true ]; then
|
||||
btpip install -I pyOpenSSl
|
||||
btpython /www/server/panel/tools.py ssl
|
||||
fi
|
||||
/etc/init.d/bt start
|
||||
$python_bin -m py_compile tools.py
|
||||
$python_bin tools.py username
|
||||
@@ -688,7 +749,7 @@ Set_Bt_Panel(){
|
||||
/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)
|
||||
LOCAL_CURL=$(curl 127.0.0.1:${panelPort}/login 2>&1 |grep -i html)
|
||||
if [ -z "${isStart}" ] && [ -z "${LOCAL_CURL}" ];then
|
||||
/etc/init.d/bt 22
|
||||
cd /www/server/panel/pyenv/bin
|
||||
@@ -766,7 +827,6 @@ Get_Ip_Address(){
|
||||
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
|
||||
@@ -802,6 +862,7 @@ Setup_Count(){
|
||||
echo /www > /var/bt_setupPath.conf
|
||||
}
|
||||
Install_Main(){
|
||||
#Set_Ssl
|
||||
startTime=`date +%s`
|
||||
Lock_Clear
|
||||
System_Check
|
||||
@@ -839,6 +900,8 @@ echo "
|
||||
+----------------------------------------------------------------------
|
||||
| The WebPanel URL will be http://SERVER_IP:8888 when installed.
|
||||
+----------------------------------------------------------------------
|
||||
| 为了您的正常使用,请确保使用全新或纯净的系统安装宝塔面板,不支持已部署项目/环境的系统安装
|
||||
+----------------------------------------------------------------------
|
||||
"
|
||||
while [ "$go" != 'y' ] && [ "$go" != 'n' ]
|
||||
do
|
||||
@@ -857,21 +920,31 @@ fi
|
||||
|
||||
Install_Main
|
||||
|
||||
PANEL_SSL=$(cat /www/server/panel/data/ssl.pl 2> /dev/null)
|
||||
if [ "${PANEL_SSL}" == "True" ];then
|
||||
HTTP_S="https"
|
||||
else
|
||||
HTTP_S="http"
|
||||
fi
|
||||
|
||||
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 "外网面板地址: ${HTTP_S}://${getIpAddress}:${panelPort}${auth_path}"
|
||||
echo "内网面板地址: ${HTTP_S}://${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"
|
||||
if [ "${HTTP_S}" == "https" ];then
|
||||
echo -e "\033[33m因已开启面板自签证书,访问面板会提示不匹配证书,请参考以下链接配置证书\033[0m"
|
||||
echo -e "\033[33mhttps://www.bt.cn/bbs/thread-105443-1-1.html\033[0m"
|
||||
fi
|
||||
echo -e "=================================================================="
|
||||
|
||||
endTime=`date +%s`
|
||||
((outTime=($endTime-$startTime)/60))
|
||||
echo -e "Time consumed:\033[32m $outTime \033[0mMinute!"
|
||||
|
||||
|
||||
|
@@ -10,7 +10,7 @@ export LANG=en_US.UTF-8
|
||||
export LANGUAGE=en_US:en
|
||||
|
||||
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://dg1.bt.cn https://download.bt.cn https://hk1-node.bt.cn https://na1-node.bt.cn https://jp1-node.bt.cn);
|
||||
|
||||
if [ "$1" ];then
|
||||
nodes=($(echo ${nodes[*]}|sed "s#${1}##"))
|
||||
@@ -52,7 +52,7 @@ get_node_url(){
|
||||
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';
|
||||
NODE_URL='https://download.bt.cn';
|
||||
fi
|
||||
fi
|
||||
rm -f $tmp_file1
|
||||
@@ -108,7 +108,7 @@ send_check(){
|
||||
chmod +x /etc/init.d/bt
|
||||
p_path2=/www/server/panel/class/common.py
|
||||
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 https://www.bt.cn/api/panel/notpro?version=$p_version
|
||||
NODE_URL=""
|
||||
exit 0;
|
||||
}
|
||||
@@ -147,3 +147,4 @@ if [ ! $NODE_URL ];then
|
||||
get_node_url
|
||||
fi
|
||||
|
||||
|
||||
|
Binary file not shown.
Binary file not shown.
@@ -42,7 +42,7 @@ download_Url=$NODE_URL
|
||||
setup_path=/www
|
||||
version=$(curl -Ss --connect-timeout 5 -m 2 $Btapi_Url/api/panel/get_version)
|
||||
if [ "$version" = '' ];then
|
||||
version='7.9.3'
|
||||
version='7.9.6'
|
||||
fi
|
||||
armCheck=$(uname -m|grep arm)
|
||||
if [ "${armCheck}" ];then
|
||||
|
@@ -70,7 +70,7 @@ select_node(){
|
||||
get_version(){
|
||||
version=$(curl -Ss --connect-timeout 5 -m 2 $Btapi_Url/api/panel/get_version)
|
||||
if [ "$version" = '' ];then
|
||||
version='7.9.3'
|
||||
version='7.9.6'
|
||||
fi
|
||||
}
|
||||
|
||||
|
Binary file not shown.
@@ -22,7 +22,7 @@ def readReg(path,key):
|
||||
return False
|
||||
|
||||
panelPath = readReg(r'SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\宝塔面板','PanelPath')
|
||||
if not panelPath:
|
||||
if not panelPath:
|
||||
panelPath = os.getenv('BT_PANEL')
|
||||
if not panelPath: exit();
|
||||
|
||||
@@ -44,11 +44,11 @@ class Sql():
|
||||
__OPT_FIELD = "*" # field条件
|
||||
__OPT_PARAM = () # where值
|
||||
__LOCK = panelPath + '/data/sqlite_lock.pl'
|
||||
|
||||
|
||||
def __init__(self):
|
||||
self.__DB_FILE = panelPath + '/data/default.db'
|
||||
|
||||
def __GetConn(self):
|
||||
|
||||
def __GetConn(self):
|
||||
#取数据库对象
|
||||
try:
|
||||
if self.__DB_CONN == None:
|
||||
@@ -62,8 +62,8 @@ class Sql():
|
||||
#设置表名
|
||||
self.__DB_TABLE = table
|
||||
return self
|
||||
|
||||
|
||||
|
||||
|
||||
def where(self,where,param):
|
||||
#WHERE条件
|
||||
if where:
|
||||
@@ -73,7 +73,7 @@ class Sql():
|
||||
|
||||
def __to_tuple(self,param):
|
||||
#将参数转换为tuple
|
||||
if type(param) != tuple:
|
||||
if type(param) != tuple:
|
||||
if type(param) == list:
|
||||
param = tuple(param)
|
||||
else:
|
||||
@@ -85,7 +85,7 @@ class Sql():
|
||||
if not pdata: return False
|
||||
keys,param = self.__format_pdata(pdata)
|
||||
return self.save(keys,param)
|
||||
|
||||
|
||||
#构造数据
|
||||
def __format_pdata(self,pdata):
|
||||
keys = pdata.keys()
|
||||
@@ -98,17 +98,17 @@ class Sql():
|
||||
#FIELD条件
|
||||
if len(field):
|
||||
self.__OPT_FIELD = field
|
||||
return self
|
||||
return self
|
||||
|
||||
def getField(self,keyName):
|
||||
#取回指定字段
|
||||
|
||||
|
||||
result = self.field(keyName).select()
|
||||
print(result)
|
||||
if len(result) != 0:
|
||||
return result[0][keyName]
|
||||
return result
|
||||
|
||||
|
||||
def __format_field(self,field):
|
||||
import re
|
||||
fields = []
|
||||
@@ -159,16 +159,16 @@ class Sql():
|
||||
return data
|
||||
except Exception as ex:
|
||||
return "error: " + str(ex)
|
||||
|
||||
|
||||
def setField(self,keyName,keyValue):
|
||||
#更新指定字段
|
||||
return self.save(keyName,(keyValue,))
|
||||
return self.save(keyName,(keyValue,))
|
||||
|
||||
def commit(self):
|
||||
self.__close()
|
||||
self.__DB_CONN.commit()
|
||||
|
||||
|
||||
|
||||
|
||||
def save(self,keys,param):
|
||||
#更新数据
|
||||
self.write_lock()
|
||||
@@ -180,7 +180,7 @@ class Sql():
|
||||
opt += key + "=?,"
|
||||
opt = opt[0:len(opt)-1]
|
||||
sql = "UPDATE " + self.__DB_TABLE + " SET " + opt+self.__OPT_WHERE
|
||||
|
||||
|
||||
#处理拼接WHERE与UPDATE参数
|
||||
tmp = list(self.__to_tuple(param))
|
||||
for arg in self.__OPT_PARAM:
|
||||
@@ -193,8 +193,8 @@ class Sql():
|
||||
return result.rowcount
|
||||
except Exception as ex:
|
||||
return "error: " + str(ex)
|
||||
|
||||
|
||||
|
||||
|
||||
def execute(self,sql,param = ()):
|
||||
#执行SQL语句返回受影响行
|
||||
self.write_lock()
|
||||
@@ -225,7 +225,7 @@ class Sql():
|
||||
def rm_lock(self):
|
||||
if os.path.exists(self.__LOCK):
|
||||
os.remove(self.__LOCK)
|
||||
|
||||
|
||||
def query(self,sql,param = ()):
|
||||
#执行SQL语句返回数据集
|
||||
self.__GetConn()
|
||||
@@ -236,7 +236,7 @@ class Sql():
|
||||
return data
|
||||
except Exception as ex:
|
||||
return "error: " + str(ex)
|
||||
|
||||
|
||||
def __close(self):
|
||||
#清理条件属性
|
||||
self.__OPT_WHERE = ""
|
||||
@@ -244,8 +244,8 @@ class Sql():
|
||||
self.__OPT_ORDER = ""
|
||||
self.__OPT_LIMIT = ""
|
||||
self.__OPT_PARAM = ()
|
||||
|
||||
|
||||
|
||||
|
||||
def close(self):
|
||||
#释放资源
|
||||
try:
|
||||
@@ -254,7 +254,7 @@ class Sql():
|
||||
except:
|
||||
pass
|
||||
|
||||
|
||||
|
||||
def GetLocalIp():
|
||||
"""
|
||||
取本地外网IP
|
||||
@@ -264,17 +264,16 @@ def GetLocalIp():
|
||||
filename = panelPath + '/data/iplist.txt'
|
||||
ipaddress = readFile(filename)
|
||||
if not ipaddress:
|
||||
|
||||
url = 'http://pv.sohu.com/cityjson?ie=utf-8'
|
||||
|
||||
url = 'http://www.example.com/api/getIpAddress';
|
||||
str = httpGet(url)
|
||||
ipaddress = re.search('\d+.\d+.\d+.\d+',str).group(0)
|
||||
writeFile(filename,ipaddress)
|
||||
|
||||
|
||||
ipaddress = re.search('\d+.\d+.\d+.\d+',ipaddress).group(0);
|
||||
return ipaddress
|
||||
except:
|
||||
try:
|
||||
url = 'http://www.example.com/api/getIpAddress';
|
||||
url = 'https://www.bt.cn/Api/getIpAddress';
|
||||
str = httpGet(url)
|
||||
writeFile(filename,ipaddress)
|
||||
return str
|
||||
@@ -302,12 +301,12 @@ def start_service(name):
|
||||
while get_server_status(name) == 0:
|
||||
try:
|
||||
win32serviceutil.StartService(name)
|
||||
time.sleep(1);
|
||||
except : time.sleep(1);
|
||||
time.sleep(1);
|
||||
except : time.sleep(1);
|
||||
timeout += 1
|
||||
if timeout > 10:break
|
||||
|
||||
if get_server_status(name) != 0:
|
||||
if get_server_status(name) != 0:
|
||||
return True,None
|
||||
return False,'操作失败,10秒内未完成启动服务【{}】'.format(name)
|
||||
except :
|
||||
@@ -319,12 +318,12 @@ def stop_service(name):
|
||||
while get_server_status(name) == 1:
|
||||
try:
|
||||
win32serviceutil.StopService(name)
|
||||
time.sleep(1);
|
||||
except : time.sleep(1);
|
||||
time.sleep(1);
|
||||
except : time.sleep(1);
|
||||
timeout += 1
|
||||
if timeout > 10:break
|
||||
|
||||
if get_server_status(name) != 1:
|
||||
if get_server_status(name) != 1:
|
||||
return True,None
|
||||
return False,'操作失败,10秒内未完成启动服务【{}】'.format(name)
|
||||
except :
|
||||
@@ -364,15 +363,15 @@ def downloadFileByWget(url,filename):
|
||||
if os.path.exists(logPath): os.remove(logPath)
|
||||
except : pass
|
||||
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:
|
||||
os.remove(loacl_path)
|
||||
downloadFile(url,filename)
|
||||
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)
|
||||
|
||||
|
||||
num = 0
|
||||
re_size = 0
|
||||
while num <= 5:
|
||||
@@ -382,17 +381,17 @@ def downloadFileByWget(url,filename):
|
||||
break;
|
||||
else:
|
||||
re_size = cr_size
|
||||
time.sleep(0.5)
|
||||
time.sleep(0.5)
|
||||
num += 1
|
||||
|
||||
if os.path.exists(filename):
|
||||
if os.path.exists(filename):
|
||||
if os.path.getsize(filename) < 1:
|
||||
os.remove(filename)
|
||||
downloadFile(url,filename)
|
||||
else:
|
||||
downloadFile(url,filename)
|
||||
|
||||
def writeFile(filename,s_body,mode='w+',encoding = 'utf-8'):
|
||||
def writeFile(filename,s_body,mode='w+',encoding = 'utf-8'):
|
||||
try:
|
||||
fp = open(filename, mode,encoding = encoding);
|
||||
fp.write(s_body)
|
||||
@@ -402,7 +401,7 @@ def writeFile(filename,s_body,mode='w+',encoding = 'utf-8'):
|
||||
return False
|
||||
|
||||
def readFile(filename,mode = 'r'):
|
||||
|
||||
|
||||
import os,chardet
|
||||
if not os.path.exists(filename): return False
|
||||
if not os.path.isfile(filename): return False
|
||||
@@ -425,15 +424,15 @@ def readFile(filename,mode = 'r'):
|
||||
encoding = 'ansi'
|
||||
fp = open(filename, mode,encoding = encoding)
|
||||
f_body = fp.read()
|
||||
|
||||
|
||||
try:
|
||||
if f_body[0] == '\ufeff':
|
||||
if f_body[0] == '\ufeff':
|
||||
#处理带bom格式
|
||||
new_code = chardet.detect(f_body.encode(encoding))["encoding"]
|
||||
f_body = f_body.encode(encoding).decode(new_code);
|
||||
except : pass
|
||||
|
||||
fp.close()
|
||||
except : pass
|
||||
|
||||
fp.close()
|
||||
return f_body
|
||||
|
||||
def httpGet(url,timeout = 60,headers = {}):
|
||||
@@ -445,11 +444,11 @@ def httpGet(url,timeout = 60,headers = {}):
|
||||
req = urllib.request.Request(url,headers = headers)
|
||||
response = urllib.request.urlopen(req,timeout = timeout)
|
||||
result = response.read()
|
||||
if type(result) == bytes:
|
||||
if type(result) == bytes:
|
||||
try:
|
||||
result = result.decode('utf-8')
|
||||
except :
|
||||
result = result.decode('gb2312')
|
||||
result = result.decode('gb2312')
|
||||
return result
|
||||
except Exception as ex:
|
||||
if headers: return False
|
||||
@@ -470,9 +469,9 @@ def httpPost(url, data, timeout=60, headers={}):
|
||||
|
||||
return result
|
||||
except Exception as ex:
|
||||
|
||||
|
||||
return str(ex);
|
||||
|
||||
|
||||
|
||||
def get_timeout(url,timeout=3):
|
||||
|
||||
@@ -484,10 +483,10 @@ def get_timeout(url,timeout=3):
|
||||
|
||||
def get_url(timeout = 0.5):
|
||||
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 = []
|
||||
mnode2 = []
|
||||
mnode3 = []
|
||||
@@ -510,12 +509,12 @@ def get_url(timeout = 0.5):
|
||||
mnode = sorted(mnode3,key= lambda x:x['net'],reverse=True)
|
||||
else: #终选中等延迟,中等带宽
|
||||
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 "https://" + mnode[0]['address']
|
||||
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)
|
||||
dacl = sd.GetSecurityDescriptorDacl()
|
||||
ace_count = dacl.GetAceCount()
|
||||
|
||||
for i in range(ace_count ,0 ,-1):
|
||||
|
||||
for i in range(ace_count ,0 ,-1):
|
||||
try:
|
||||
data = {}
|
||||
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() == 'users': dacl.DeleteAce(i-1) #删除旧的dacl
|
||||
|
||||
@@ -542,35 +541,35 @@ def del_file_access(filename,user):
|
||||
try:
|
||||
#处理拒绝访问
|
||||
dacl.DeleteAce(i-1)
|
||||
except : pass
|
||||
except : pass
|
||||
sd.SetSecurityDescriptorDacl(1, dacl, 0)
|
||||
win32security.SetFileSecurity(filename, win32security.DACL_SECURITY_INFORMATION, sd)
|
||||
except :
|
||||
pass
|
||||
return True
|
||||
|
||||
def set_file_access(filename,user,access):
|
||||
def set_file_access(filename,user,access):
|
||||
try:
|
||||
sd = win32security.GetFileSecurity(filename, win32security.DACL_SECURITY_INFORMATION)
|
||||
dacl = sd.GetSecurityDescriptorDacl()
|
||||
ace_count = dacl.GetAceCount()
|
||||
|
||||
for i in range(ace_count, 0,-1):
|
||||
for i in range(ace_count, 0,-1):
|
||||
try:
|
||||
data = {}
|
||||
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() == 'users': dacl.DeleteAce(i-1) #删除旧的dacl
|
||||
|
||||
|
||||
except :
|
||||
pass
|
||||
try:
|
||||
userx, domain, type = win32security.LookupAccountName("", user)
|
||||
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)
|
||||
|
||||
|
||||
sd.SetSecurityDescriptorDacl(1, dacl, 0)
|
||||
win32security.SetFileSecurity(filename, win32security.DACL_SECURITY_INFORMATION, sd)
|
||||
return True,None
|
||||
@@ -582,24 +581,24 @@ def ExecShell(cmdstring, cwd=None, timeout=None, shell=True):
|
||||
cmdstring_list = cmdstring
|
||||
else:
|
||||
cmdstring_list = shlex.split(cmdstring)
|
||||
|
||||
|
||||
if 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:
|
||||
time.sleep(0.1)
|
||||
if timeout:
|
||||
if end_time <= datetime.datetime.now():
|
||||
raise Exception("Timeout:%s"%cmdstring)
|
||||
a,e = sub.communicate()
|
||||
if type(a) == bytes:
|
||||
if type(a) == bytes:
|
||||
try:
|
||||
a = a.decode('utf-8')
|
||||
except :
|
||||
except :
|
||||
a = a.decode('gb2312','ignore')
|
||||
|
||||
if type(e) == bytes:
|
||||
if type(e) == bytes:
|
||||
try:
|
||||
e = e.decode('utf-8')
|
||||
except :
|
||||
@@ -626,7 +625,7 @@ def GetRandomString1(length):
|
||||
strings += chars[random.randint(0, chrlen)]
|
||||
return strings
|
||||
|
||||
def GetRandomString2(length):
|
||||
def GetRandomString2(length):
|
||||
from random import Random
|
||||
strings = ''
|
||||
chars = '!@#$%^&*()_+.,?[]-='
|
||||
@@ -637,7 +636,7 @@ def GetRandomString2(length):
|
||||
return strings
|
||||
|
||||
def chdck_salt():
|
||||
|
||||
|
||||
sql = Sql()
|
||||
sql.table('users').execute("ALTER TABLE 'users' ADD 'salt' TEXT",())
|
||||
|
||||
@@ -657,7 +656,7 @@ def md5(strings):
|
||||
"""
|
||||
import hashlib
|
||||
m = hashlib.md5()
|
||||
|
||||
|
||||
m.update(strings.encode('utf-8'))
|
||||
return m.hexdigest()
|
||||
|
||||
@@ -673,18 +672,18 @@ def password_salt(password,username=None,uid=None):
|
||||
salt = sql.table('users').where('id=?',(uid,)).getField('salt')
|
||||
return md5(md5(password+'_bt.cn')+salt)
|
||||
|
||||
def check_user(username):
|
||||
def check_user(username):
|
||||
resume = 0
|
||||
while True:
|
||||
data, total, resume = win32net.NetUserEnum(None, 3, win32netcon.FILTER_NORMAL_ACCOUNT, resume)
|
||||
for user in data:
|
||||
if user['name'] == username: return True
|
||||
if not resume: break
|
||||
return False
|
||||
return False
|
||||
|
||||
def add_user(username,password,ps):
|
||||
try:
|
||||
if not check_user(username):
|
||||
if not check_user(username):
|
||||
d = {}
|
||||
d['name'] = username
|
||||
d['password'] = password
|
||||
@@ -692,7 +691,7 @@ def add_user(username,password,ps):
|
||||
d['flags'] = win32netcon.UF_NORMAL_ACCOUNT | win32netcon.UF_SCRIPT
|
||||
d['priv'] = win32netcon.USER_PRIV_USER
|
||||
win32net.NetUserAdd(None, 1, d)
|
||||
|
||||
|
||||
#设置用户允许登录服务
|
||||
handle = win32security.LsaOpenPolicy(None, win32security.POLICY_ALL_ACCESS)
|
||||
sid_obj, domain, tmp = win32security.LookupAccountName(None, username)
|
||||
@@ -713,25 +712,25 @@ def add_user_bywww():
|
||||
|
||||
pwd = GetRandomString(64) + GetRandomString1(32) + GetRandomString2(32)
|
||||
status,error = add_user('www',pwd,'用于启动宝塔安装的程序,删除后会导致部分软件无法启动,请勿删除')
|
||||
if not status:
|
||||
if not status:
|
||||
writeFile(error_path,error)
|
||||
return False
|
||||
return True
|
||||
|
||||
def add_user_bymysql():
|
||||
|
||||
|
||||
pwd = GetRandomString(64) + GetRandomString1(32) + GetRandomString2(32)
|
||||
status,error = add_user('mysql',pwd,'用于启动宝塔安装的程序,删除后会导致部分软件无法启动,请勿删除')
|
||||
if not status:
|
||||
if not status:
|
||||
writeFile(error_path,error)
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def getIP(url):
|
||||
import socket,re
|
||||
|
||||
tmp = re.search('http://(.+)\:\d*',url)
|
||||
if tmp:
|
||||
if tmp:
|
||||
domain = tmp.groups()[0]
|
||||
myaddr = socket.getaddrinfo(domain, 'http')
|
||||
return myaddr[0][4][0]
|
||||
@@ -756,14 +755,14 @@ def add_panel_dir():
|
||||
]
|
||||
|
||||
is_break = False
|
||||
for sobj in slist:
|
||||
for sobj in slist:
|
||||
if not os.path.exists(sobj[0]):
|
||||
os.makedirs(sobj[0])
|
||||
os.makedirs(sobj[0])
|
||||
n = 0
|
||||
while n < 5:
|
||||
if os.path.exists(sobj[0]): break
|
||||
|
||||
os.makedirs(sobj[0])
|
||||
os.makedirs(sobj[0])
|
||||
time.sleep(0.5)
|
||||
n += 1
|
||||
|
||||
@@ -773,17 +772,17 @@ def add_panel_dir():
|
||||
|
||||
del_file_access(sobj[0],'users')
|
||||
|
||||
for user in sobj[1]:
|
||||
for user in sobj[1]:
|
||||
n = 0
|
||||
while n < 3:
|
||||
while n < 3:
|
||||
status,error = set_file_access(sobj[0],user,2032127)
|
||||
if status: break
|
||||
if status: break
|
||||
time.sleep(0.5)
|
||||
|
||||
if not status:
|
||||
writeFile(error_path,"目录{}设置{}权限设置错误 -> {}".format(sobj[0],user,error))
|
||||
break
|
||||
|
||||
|
||||
del_file_access(setupPath,'users')
|
||||
url = get_url()
|
||||
|
||||
@@ -793,18 +792,18 @@ def add_panel_dir():
|
||||
download_url = '{}/win/panel/data/{}'.format(url,f_name)
|
||||
|
||||
n = 0
|
||||
while n < 10:
|
||||
while n < 10:
|
||||
n += 1;
|
||||
|
||||
try:
|
||||
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 os.path.getsize(local_path) and os.path.getsize(local_path) > 10: break;
|
||||
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 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 :
|
||||
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
|
||||
time.sleep(0.2)
|
||||
@@ -816,9 +815,9 @@ def add_panel_dir():
|
||||
|
||||
def unzip(src_path,dst_path):
|
||||
import zipfile
|
||||
zip_file = zipfile.ZipFile(src_path)
|
||||
for names in zip_file.namelist():
|
||||
zip_file.extract(names,dst_path)
|
||||
zip_file = zipfile.ZipFile(src_path)
|
||||
for names in zip_file.namelist():
|
||||
zip_file.extract(names,dst_path)
|
||||
zip_file.close()
|
||||
return True
|
||||
|
||||
@@ -834,44 +833,44 @@ def download_panel(file_list = []):
|
||||
#下载面板
|
||||
loacl_path = setupPath + '/panel.zip'
|
||||
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 not os.path.exists(tmpPath): os.makedirs(tmpPath)
|
||||
|
||||
|
||||
p_ver = sys.argv[2]
|
||||
downUrl = url + '/win/panel/panel_' + p_ver + '.zip';
|
||||
downloadFileByWget(downUrl,loacl_path);
|
||||
unzip(loacl_path,tmpPath)
|
||||
|
||||
downloadFileByWget(downUrl,loacl_path);
|
||||
unzip(loacl_path,tmpPath)
|
||||
|
||||
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)
|
||||
for name in os.listdir(tcPath):
|
||||
try:
|
||||
for name in os.listdir(tcPath):
|
||||
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)
|
||||
lName = name.split('.')[0] + '.pyd'
|
||||
newName = os.path.join(tcPath,lName)
|
||||
if not os.path.exists(newName):os.rename(oldName,newName)
|
||||
except :pass
|
||||
|
||||
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 {}\*.pyt".format(to_path(cPath)))
|
||||
for name in os.listdir(cPath):
|
||||
try:
|
||||
if name.find('.pyd') >=0:
|
||||
if name.find('.pyd') >=0:
|
||||
oldName = os.path.join(cPath,name)
|
||||
newName = os.path.join(cPath,GetRandomString(8) + '.pyt')
|
||||
os.rename(oldName,newName)
|
||||
newName = os.path.join(cPath,GetRandomString(8) + '.pyt')
|
||||
os.rename(oldName,newName)
|
||||
except : pass
|
||||
os.system("del /s {}\*.pyc".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:
|
||||
os.remove(loacl_path)
|
||||
except : pass
|
||||
@@ -880,7 +879,7 @@ def download_panel(file_list = []):
|
||||
shutil.rmtree(tmpPath,True)
|
||||
except : pass
|
||||
|
||||
s_ver = platform.platform()
|
||||
s_ver = platform.platform()
|
||||
net_v = '45'
|
||||
if s_ver.find('2008') >= 0: net_v = '20'
|
||||
writeFile('{}/data/net'.format(setupPath),net_v)
|
||||
@@ -910,7 +909,7 @@ def download_panel(file_list = []):
|
||||
try:
|
||||
from gevent import monkey
|
||||
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 :
|
||||
writeFile(error_path,get_error_info())
|
||||
|
||||
@@ -918,7 +917,7 @@ def update_panel():
|
||||
|
||||
file_list = ['config/config.json','config/index.json','data/libList.conf','data/plugin.json']
|
||||
download_panel(file_list)
|
||||
|
||||
|
||||
py_path = 'C:/Program Files/python/python.exe'
|
||||
|
||||
ExecShell("\"{}\" {}/panel/runserver.py --startup auto install".format(py_path,setupPath))
|
||||
@@ -929,7 +928,7 @@ def update_panel():
|
||||
def init_panel_data():
|
||||
try:
|
||||
sql = Sql()
|
||||
username = sql.table('users').where('id=?',(1,)).getField('username')
|
||||
username = sql.table('users').where('id=?',(1,)).getField('username')
|
||||
if username == 'admin':
|
||||
username = GetRandomString(8)
|
||||
password = GetRandomString(8)
|
||||
@@ -937,12 +936,12 @@ def init_panel_data():
|
||||
|
||||
sql.table('users').where('id=?',(1,)).setField('username',username)
|
||||
pwd = password_salt(md5(password),uid=1)
|
||||
|
||||
|
||||
result = sql.table('users').where('id=?',(1,)).setField('password',pwd)
|
||||
|
||||
backup_path = panelPath[:2] + '/backup'
|
||||
www_path = panelPath[:2] + '/wwwroot'
|
||||
|
||||
|
||||
if not os.path.exists(backup_path): os.makedirs(backup_path)
|
||||
if not os.path.exists(www_path): os.makedirs(www_path)
|
||||
|
||||
@@ -953,11 +952,11 @@ def init_panel_data():
|
||||
if not os.path.exists(bind_path): writeFile(bind_path,'True')
|
||||
|
||||
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'
|
||||
if not os.path.exists(port_path): writeFile(port_path,'8888')
|
||||
|
||||
|
||||
recycle_bin_db = panelPath+ '/data/recycle_bin_db.pl'
|
||||
if not os.path.exists(recycle_bin_db): writeFile(recycle_bin_db,'True')
|
||||
|
||||
@@ -975,26 +974,26 @@ def init_panel_data():
|
||||
except :
|
||||
writeFile(error_path,get_error_info())
|
||||
return False
|
||||
|
||||
|
||||
def add_panel_services(num = 0):
|
||||
try:
|
||||
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))
|
||||
|
||||
|
||||
delete_server('btTask')
|
||||
ExecShell("\"{}\" {}/panel/task.py --startup auto install".format(py_path,setupPath))
|
||||
|
||||
if get_server_status('btPanel') < 0 or get_server_status('btTask') < 0:
|
||||
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 num <= 0 :
|
||||
localPath = setupPath + "/temp/Time_Zones.reg";
|
||||
downloadFileByWget(get_url() + '/win/panel/data/Time_Zones.reg',localPath)
|
||||
ExecShell("regedit /s " + localPath)
|
||||
|
||||
add_panel_services(1)
|
||||
add_panel_services(1)
|
||||
else:
|
||||
writeFile(error_path,ret[0] + ret[1])
|
||||
writeFile(error_path,ret[0] + ret[1] + ret1[0] + ret1[1])
|
||||
else:
|
||||
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')
|
||||
@@ -1005,9 +1004,9 @@ def add_panel_services(num = 0):
|
||||
|
||||
|
||||
def add_firewall_byport():
|
||||
|
||||
|
||||
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=80");
|
||||
ExecShell("netsh advfirewall firewall add rule name=远程桌面 dir=in action=allow protocol=tcp localport=3389");
|
||||
@@ -1029,8 +1028,8 @@ def get_error_log():
|
||||
return error
|
||||
|
||||
if __name__ == "__main__":
|
||||
stype = sys.argv[1];
|
||||
if not stype in ['get_error_log']:
|
||||
stype = sys.argv[1];
|
||||
if not stype in ['get_error_log']:
|
||||
if os.path.exists(error_path): os.remove(error_path)
|
||||
result = eval('{}()'.format(stype))
|
||||
print(result)
|
||||
|
Binary file not shown.
@@ -36,6 +36,9 @@ Route::group('api', function () {
|
||||
Route::get('/getIpAddress', 'api/get_ip_address');
|
||||
Route::post('/Auth/GetAuthToken', 'api/get_auth_token');
|
||||
Route::post('/Auth/GetBindCode', 'api/return_error');
|
||||
Route::post('/Auth/GetSSLList', 'api/get_ssl_list');
|
||||
Route::post('/Cert/get_order_list', 'api/return_empty_array');
|
||||
Route::post('/Cert/get_product_list', 'api/return_success');
|
||||
Route::get('/Pluginother/get_file', 'api/download_plugin_other');
|
||||
|
||||
Route::post('/Pluginother/create_order', 'api/return_error');
|
||||
|
@@ -36,6 +36,7 @@ def get_auth_state():
|
||||
#执行插件方法(插件名,方法名,参数)
|
||||
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,'插件不存在!')
|
||||
|
||||
@@ -73,12 +74,21 @@ def plugin_run(plugin_name, def_name, args):
|
||||
#执行模块方法(模块名,方法名,参数)
|
||||
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
|
||||
|
||||
mod_file = "{}/projectModel/{}Model.py".format(public.get_class_path(),mod_name)
|
||||
if not os.path.exists(mod_file):
|
||||
mod_file = "{}/databaseModel/{}Model.py".format(public.get_class_path(),mod_name)
|
||||
if not os.path.exists(mod_file):
|
||||
return public.returnMsg(False,'模块[%s]不存在' % mod_name)
|
||||
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)
|
||||
@@ -92,3 +102,21 @@ def module_run(mod_name, def_name, args):
|
||||
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
|
||||
|
363
wiki/files/bt.js
363
wiki/files/bt.js
@@ -39,86 +39,231 @@ if("undefined" != typeof bt && bt.hasOwnProperty("prompt_confirm")){
|
||||
}
|
||||
}
|
||||
if("undefined" != typeof database && database.hasOwnProperty("del_database")){
|
||||
database.del_database = function (wid, dbname,obj, callback) {
|
||||
title = '',
|
||||
tips = '是否确认【删除数据库】,删除后可能会影响业务使用!';
|
||||
if(obj && obj.db_type > 0) tips = '远程数据库不支持数据库回收站,删除后将无法恢复,请谨慎操作';
|
||||
var title = typeof dbname === "function" ?'批量删除数据库':'删除数据库 [ '+ dbname +' ]';
|
||||
layer.open({
|
||||
type:1,
|
||||
title:title,
|
||||
icon:0,
|
||||
skin:'delete_site_layer',
|
||||
area: "530px",
|
||||
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\' style=\'margin-bottom: 20px;\'>"+tips+"</div>" +
|
||||
"<div style=\'color:red;margin:18px 0 18px 18px;font-size:14px;font-weight: bold;\'>注意:数据无价,请谨慎操作!!!"+(!recycle_bin_db_open?'<br>风险操作:当前数据库回收站未开启,删除数据库将永久消失!':'')+"</div>" +
|
||||
"</div>",
|
||||
btn:[lan.public.ok,lan.public.cancel],
|
||||
yes:function(indexs){
|
||||
var data = {id: wid,name: dbname};
|
||||
if(typeof dbname === "function"){
|
||||
delete data.id;
|
||||
delete data.name;
|
||||
}
|
||||
layer.close(indexs)
|
||||
if(typeof dbname === "function"){
|
||||
dbname(data)
|
||||
}else{
|
||||
bt.database.del_database(data, function (rdata) {
|
||||
layer.closeAll()
|
||||
if (callback) callback(rdata);
|
||||
bt.msg(rdata);
|
||||
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) {
|
||||
var title = typeof wname === "function" ?'批量删除站点':'删除站点 [ '+ wname +' ]';
|
||||
site.del_site = function (wid, wname, callback) {
|
||||
title = typeof wname === "function" ? '批量删除站点' : '删除站点 [ ' + wname + ' ]';
|
||||
layer.open({
|
||||
type:1,
|
||||
title:title,
|
||||
icon:0,
|
||||
skin:'delete_site_layer',
|
||||
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\'>" +
|
||||
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>"+
|
||||
"<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(){
|
||||
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})
|
||||
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(){
|
||||
}, function () {
|
||||
layer.closeAll('tips');
|
||||
})
|
||||
});
|
||||
},
|
||||
yes:function(indexs){
|
||||
var data = {id: wid,webname: wname};
|
||||
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
|
||||
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"){
|
||||
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;
|
||||
}
|
||||
@@ -129,22 +274,95 @@ if("undefined" != typeof site && site.hasOwnProperty("del_site")){
|
||||
})
|
||||
return false
|
||||
}
|
||||
if(typeof wname === "function"){
|
||||
if (typeof wname === "function") {
|
||||
delete data.id;
|
||||
delete data.webname;
|
||||
}
|
||||
layer.close(indexs)
|
||||
if(typeof wname === "function"){
|
||||
console.log(data)
|
||||
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);
|
||||
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);
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -157,7 +375,10 @@ if("undefined" != typeof bt && bt.hasOwnProperty("firewall") && bt.firewall.hasO
|
||||
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 });
|
||||
layer.msg('可用端口范围:1-65535', { icon: 2 });
|
||||
// layer.msg(lan.firewall.port_err, {
|
||||
// icon: 5
|
||||
// });
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
122
wiki/files/win/PluginLoader.py
Normal file
122
wiki/files/win/PluginLoader.py
Normal file
@@ -0,0 +1,122 @@
|
||||
#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+ '/wpanel/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:
|
||||
sys.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
|
@@ -1,60 +0,0 @@
|
||||
#coding: utf-8
|
||||
import public,os,sys,json
|
||||
|
||||
class Plugin:
|
||||
name = False
|
||||
p_path = None
|
||||
is_php = False
|
||||
plu = None
|
||||
__api_root_url = 'https://api.bt.cn'
|
||||
__api_url = __api_root_url+ '/wpanel/get_plugin_list'
|
||||
__cache_file = 'data/plugin_list.json'
|
||||
|
||||
def __init__(self, name):
|
||||
self.name = name
|
||||
self.p_path = public.get_plugin_path(name)
|
||||
self.is_php = os.path.exists(self.p_path + '/index.php')
|
||||
|
||||
def get_plugin_list(self, force = False):
|
||||
if force==False and os.path.exists(self.__cache_file):
|
||||
jsonData = public.readFile(self.__cache_file)
|
||||
softList = json.loads(jsonData)
|
||||
else:
|
||||
try:
|
||||
jsonData = public.HttpGet(self.__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(self.__cache_file, jsonData)
|
||||
|
||||
return softList
|
||||
|
||||
def isdef(self, fun):
|
||||
if not self.is_php:
|
||||
sys.path.append(self.p_path)
|
||||
plugin_main = __import__(self.name + '_main')
|
||||
try:
|
||||
from imp import reload
|
||||
reload(plugin_main)
|
||||
except:
|
||||
pass
|
||||
self.plu = eval('plugin_main.' + self.name + '_main()')
|
||||
if not hasattr(self.plu, fun):
|
||||
if self.name == 'btwaf' and fun == 'index':
|
||||
raise Exception("未购买")
|
||||
return False
|
||||
return True
|
||||
|
||||
def exec_fun(self, args):
|
||||
fun = args.s
|
||||
if not self.is_php:
|
||||
plu = self.plu
|
||||
data = eval('plu.' + fun + '(args)')
|
||||
else:
|
||||
import panelPHP
|
||||
args.s = fun
|
||||
args.name = self.name
|
||||
data = panelPHP.panelPHP(self.name).exec_php_script(args)
|
||||
return data
|
||||
|
@@ -10,9 +10,13 @@
|
||||
|
||||
- 将PluginLoader.py复制到class文件夹
|
||||
|
||||
- 批量解密模块文件:执行 php think decrypt classdir <面板class文件夹路径>
|
||||
|
||||
- 全局搜索替换 https://api.bt.cn => http://www.example.com
|
||||
|
||||
- 全局搜索替换 https://www.bt.cn/api/ => http://www.example.com/api/(需排除clearModel.py)
|
||||
- 全局搜索替换 https://www.bt.cn/api/ => http://www.example.com/api/(需排除clearModel.py、scanningModel.py、ipsModel.py)
|
||||
|
||||
- class/panelAuth.py 替换 http://www.bt.cn/api/ => http://www.example.com/api/
|
||||
|
||||
- 全局搜索替换 http://download.bt.cn/install/update6.sh => http://www.example.com/install/update6.sh
|
||||
|
||||
@@ -38,16 +42,22 @@
|
||||
|
||||
在 def check_domain_cloud(domain): 这一行下面加上 return
|
||||
|
||||
在 def get_improvement(): 这一行下面加上 return False
|
||||
|
||||
在free_login_area方法内get_free_ips_area替换成get_ips_area
|
||||
|
||||
- class/panelPlugin.py 文件,download_icon方法内替换 public.GetConfigValue('home') => 'https://www.bt.cn'
|
||||
|
||||
- class/panelPlugin.py 文件,set_pyenv方法内,temp_file = public.readFile(filename)这行代码下面加上
|
||||
删除public.total_keyword(get.query)这一行
|
||||
|
||||
set_pyenv方法内,temp_file = public.readFile(filename)这行代码下面加上
|
||||
|
||||
```python
|
||||
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')
|
||||
temp_file = temp_file.replace('http://download.bt.cn/install/public.sh', 'http://www.example.com/install/public.sh')
|
||||
```
|
||||
|
||||
|
||||
- install/install_soft.sh 在bash执行之前加入以下代码
|
||||
|
||||
```shell
|
||||
@@ -61,18 +71,18 @@
|
||||
|
||||
"update_software_list": update_software_list,
|
||||
|
||||
"check_files_panel": check_files_panel,
|
||||
|
||||
"check_panel_msg": check_panel_msg,
|
||||
|
||||
- 去除面板日志上报:script/site_task.py 文件
|
||||
PluginLoader.daemon_panel()
|
||||
|
||||
删除最下面 logs_analysis() 这1行
|
||||
- 去除WebRTC连接:BTPanel/static/js/public.js 删除stun.start();这一行
|
||||
|
||||
- 去除首页广告:BTPanel/static/js/index.js 文件删除最下面index.recommend_paid_version()这一行
|
||||
|
||||
- 去除首页自动检测更新,避免频繁请求云端:BTPanel/static/js/index.js 文件注释掉bt.system.check_update这一段代码外的setTimeout
|
||||
|
||||
- 去除内页广告:BTPanel/templates/default/layout.html 删除getPaymentStatus();这一行
|
||||
|
||||
- [可选]去除各种计算题:复制bt.js到 BTPanel/static/ ,在 BTPanel/templates/default/layout.html 的\</body\>前面加入
|
||||
|
||||
```javascript
|
||||
|
@@ -8,11 +8,11 @@
|
||||
|
||||
Windows版宝塔由于加密文件太多,无法全部解密,因此无法做到全开源。
|
||||
|
||||
- 删除pluginAuth.cp38-win_amd64.pyd,将win/pluginAuth.py复制到class文件夹
|
||||
- 删除PluginLoader.pyd,将win/PluginLoader.py复制到class文件夹
|
||||
|
||||
- 全局搜索替换 https://api.bt.cn => http://www.example.com
|
||||
|
||||
- 全局搜索替换 https://www.bt.cn/api/ => http://www.example.com/api/
|
||||
- 全局搜索替换 https://www.bt.cn/api/ => http://www.example.com/api/(需排除ipsModel.py)
|
||||
|
||||
- 全局搜索替换 http://www.bt.cn/api/ => http://www.example.com/api/
|
||||
|
||||
@@ -50,7 +50,7 @@ Windows版宝塔由于加密文件太多,无法全部解密,因此无法做
|
||||
|
||||
- 去除面板日志上报:script/site_task.py 文件
|
||||
|
||||
删除最下面 logs_analysis() 这1行
|
||||
- 删除最下面 logs_analysis() 这1行
|
||||
|
||||
- 去除首页广告:BTPanel/static/js/index.js 文件删除最下面index.recommend_paid_version()这一行
|
||||
|
||||
@@ -72,5 +72,5 @@ Windows版宝塔由于加密文件太多,无法全部解密,因此无法做
|
||||
|
||||
删除 if not os.path.exists(self.sitePath + '/.htaccess') 这一行
|
||||
|
||||
|
||||
- [可选]关闭自动生成访问日志:在 BTPanel/\_\_init\_\_.py 删除public.write_request_log()这一行
|
||||
|
||||
|
Reference in New Issue
Block a user