' +
'
' +
- '' + lan.files.unzip_name + '
' +
- '
' + lan.files.unzip_to + '
' + umpass +
- '
' + lan.files.unzip_coding + '
' +
+ '
' + lan.files.unzip_to + '
' + umpass +
+ '
' + lan.files.unzip_coding + '' +
diff --git a/BTPanel/static/js/public.js b/BTPanel/static/js/public.js
index ebaf3610..df85a86d 100644
--- a/BTPanel/static/js/public.js
+++ b/BTPanel/static/js/public.js
@@ -651,7 +651,7 @@ var aceEditor = {
$('.ace_dir_tools').on('click','.upper_level',function(){
var _paths = $(this).attr('data-menu-path');
_this.reader_file_dir_menu({path:_paths,is_empty:true});
- $('.ace_catalogue_title').html('目录:'+ _paths).attr('title',_paths);
+ $('.ace_catalogue_title').html('Directory: '+ _paths).attr('title',_paths);
});
// 新建文件(文件目录主菜单)
$('.ace_dir_tools').on('click','.new_folder',function(e){
diff --git a/BTPanel/static/js/site.js b/BTPanel/static/js/site.js
index 43d9ea94..b97288e2 100644
--- a/BTPanel/static/js/site.js
+++ b/BTPanel/static/js/site.js
@@ -1404,11 +1404,11 @@ var site = {
}
});
$('#ols').on('click', function() {
- private.toggle();
- checked = private.is(':hidden') ? false : true;
+ var loadT = bt.load();
bt.send('switch_ols_private_cache', 'config/switch_ols_private_cache', { id: web.id }, function(res) {
- var loadT = bt.load();
loadT.close();
+ private.toggle();
+ checked = private.is(':hidden') ? false : true;
bt.msg(res);
if (checked) {
bt.send('get_ols_private_cache', 'config/get_ols_private_cache', { id: web.id }, function(fdata) {
@@ -1514,7 +1514,7 @@ var site = {
callback: function(obj) {
if (bt.os == 'Linux') {
var spath = filename;
- if (obj.val() != lan.site.rewritename) spath = '/www/server/panel/rewrite/' + webserver + '/' + obj.val() + '.conf';
+ if (obj.val() != lan.site.rewritename) spath = '/www/server/panel/rewrite/' + (webserver == 'openlitespeed'?'apache':webserver) + '/' + obj.val() + '.conf';
bt.files.get_file_body(spath, function(ret) {
editor.setValue(ret.data);
})
@@ -1635,7 +1635,8 @@ var site = {
This is primary configuration file of the site, do NOT modify it at will if you do not know configuration rules.\
';
$("#webedit-con").html(con);
- var config = bt.aceEditor({ el: 'siteConfigBody', path: '/www/server/panel/vhost/' + bt.get_cookie('serverType') + '/' + web.name + '.conf' })
+ var webserve = bt.get_cookie('serverType'),
+ config = bt.aceEditor({ el: 'siteConfigBody', path: '/www/server/panel/vhost/' + (webserve == 'openlitespeed' ? (webserve + '/detail') : webserve) + '/' + web.name + '.conf' });
$("#OnlineEditFileBtn").click(function(e) {
bt.saveEditor(config);
});
@@ -3141,7 +3142,7 @@ var site = {
content: "
"
})
setTimeout(function() {
- var webcache = bt.get_cookie('serverType') == 'openlitespeed' ? { title: 'LSCache', callback: site.edit.ols_cache } : '';
+ var webcache = bt.get_cookie('serverType') == 'openlitespeed' ? { title: 'LS-Cache', callback: site.edit.ols_cache } : '';
var menus = [
{ title: lan.site.domain_man, callback: site.edit.set_domains },
{ title: lan.site.site_menu_1, callback: site.edit.set_dirbind },
diff --git a/BTPanel/static/js/soft.js b/BTPanel/static/js/soft.js
index 2af2ff51..6a87bb1b 100644
--- a/BTPanel/static/js/soft.js
+++ b/BTPanel/static/js/soft.js
@@ -98,7 +98,31 @@ var soft = {
click_opt += ' onclick="soft.set_soft_config(\'' + item.name + '\')" ';
}
}
- if (rdata.apache22 && item.name.indexOf('php-') >= 0 && $.inArray(item.name, phps) == -1) click_opt = ' title="' + lan.soft.ap2_2_not_support + '"';
+ var is_php5 = item.name.indexOf('php-5') >= 0,
+ webcache = bt.get_cookie('serverType') == 'openlitespeed' ? true : false,
+ distribution = bt.get_cookie('distribution');
+ if (webcache) {
+ switch (distribution) {
+ case 'centos8':
+ if (is_php5 || item.name == 'php-7.0') {
+ click_opt = ' title="' + lan.soft.ap2_2_not_support + '"';
+ }
+ break;
+ case 'centos7':
+ if (item.name == 'php-5.2') {
+ click_opt = ' title="' + lan.soft.ap2_2_not_support + '"';
+ }
+ break;
+ default:
+ if (is_php5) {
+ click_opt = ' title="' + lan.soft.ap2_2_not_support + '"';
+ }
+ break;
+ }
+ }else if (rdata.apache22 && item.name.indexOf('php-') >= 0 && $.inArray(item.name, phps) == -1){
+ click_opt = ' title="' + lan.soft.ap2_2_not_support + '"';
+ }
+ //if (rdata.apache22 && item.name.indexOf('php-') >= 0 && $.inArray(item.name, phps) == -1) click_opt = ' title="' + lan.soft.ap2_2_not_support + '"';
return '
' + item.title + ' ' + version + '';
}
},
@@ -254,73 +278,116 @@ var soft = {
var is_php = item.name.indexOf('php-') >= 0,
is_php5 = item.name.indexOf('php-5') >= 0,
webcache = bt.get_cookie('serverType') == 'openlitespeed' ? true : false,
- distribution = bt.get_cookie('distribution'),
- redhat = rdata.Redhat;
- if (rdata.apache22 && is_php && $.inArray(item.name, phps) == -1) {
- if (item.setup) {
- option = '
' + lan.soft.uninstall + '';
- } else {
+ distribution = bt.get_cookie('distribution');
+ if (webcache && is_php) {
+ if ((is_php5 || item.name == 'php-7.0') && distribution=='centos8') {
option = '
' + lan.soft.not_comp + '';
- }
- } else if (rdata.apache24 && item.name == 'php-5.2') {
- if (item.setup) {
- option = '
' + lan.soft.uninstall + '';
- } else {
+ }else if (distribution=='centos7'&&item.name == 'php-5.2') {
option = '
' + lan.soft.not_comp + '';
- }
- } else {
- if (item.setup && item.task == '1') {
- if (pay_opt == '') {
- if (item.versions.length > 1) {
- for (var i = 0; i < item.versions.length; i++) {
- var min_version = item.versions[i]
- var ret = bt.check_version(item.version, min_version.m_version + '.' + min_version.version);
- if (ret > 0) {
- if (ret == 2) option += '
' + lan.soft.update + ' | ';
- break;
+ }else{
+ if (is_php5) {
+ option = '
' + lan.soft.not_comp + '';
+ } else {
+ if (item.setup && item.task == '1') {
+ if (pay_opt == '') {
+ if (item.versions.length > 1) {
+ for (var i = 0; i < item.versions.length; i++) {
+ var min_version = item.versions[i]
+ var ret = bt.check_version(item.version, min_version.m_version + '.' + min_version.version);
+ if (ret > 0) {
+ if (ret == 2) option += '
' + lan.soft.update + ' | ';
+ break;
+ }
+ }
+ } else {
+ var min_version = item.versions[0];
+ var cloud_version = min_version.m_version + '.' + min_version.version;
+ if (item.version != cloud_version) option += '
' + lan.soft.update + ' | ';
}
+ if (item.admin) {
+ option += '
' + lan.soft.setup + ' | ';
+ } else {
+ option += '
' + lan.soft.setup + ' | ';
+ }
+ } else {
+ option = pay_opt + ' | ' + option;
+ }
+ option += '
' + lan.soft.uninstall + '';
+ } else if (item.task == '-1') {
+ option = '
' + lan.soft.installing + '';
+ soft.is_install = true;
+ } else if (item.task == '0') {
+ option = '
' + lan.soft.wait_install + '';
+ soft.is_install = true;
+ } else if (item.task == '-2') {
+ option = '
Updating';
+ soft.is_install = true;
+ } else {
+ if (pay_opt) {
+ option = pay_opt;
+ } else {
+ option = '
' + lan.soft.install + '';
+ }
+ }
+ }
+ }
+ }else {
+ if (rdata.apache22 && is_php && $.inArray(item.name, phps) == -1) {
+ if (item.setup) {
+ option = '
' + lan.soft.uninstall + '';
+ } else {
+ option = '
' + lan.soft.not_comp + '';
+ }
+ } else if (rdata.apache24 && item.name == 'php-5.2') {
+ if (item.setup) {
+ option = '
' + lan.soft.uninstall + '';
+ } else {
+ option = '
' + lan.soft.not_comp + '';
+ }
+ } else {
+ if (item.setup && item.task == '1') {
+ if (pay_opt == '') {
+ if (item.versions.length > 1) {
+ for (var i = 0; i < item.versions.length; i++) {
+ var min_version = item.versions[i]
+ var ret = bt.check_version(item.version, min_version.m_version + '.' + min_version.version);
+ if (ret > 0) {
+ if (ret == 2) option += '
' + lan.soft.update + ' | ';
+ break;
+ }
+ }
+ } else {
+ var min_version = item.versions[0];
+ var cloud_version = min_version.m_version + '.' + min_version.version;
+ if (item.version != cloud_version) option += '
' + lan.soft.update + ' | ';
+ }
+ if (item.admin) {
+ option += '
' + lan.soft.setup + ' | ';
+ } else {
+ option += '
' + lan.soft.setup + ' | ';
}
} else {
- var min_version = item.versions[0];
- var cloud_version = min_version.m_version + '.' + min_version.version;
- if (item.version != cloud_version) option += '
' + lan.soft.update + ' | ';
+ option = pay_opt + ' | ' + option;
}
- if (item.admin) {
- option += '
' + lan.soft.setup + ' | ';
+ option += '
' + lan.soft.uninstall + '';
+ } else if (item.task == '-1') {
+ option = '
' + lan.soft.installing + '';
+ soft.is_install = true;
+ } else if (item.task == '0') {
+ option = '
' + lan.soft.wait_install + '';
+ soft.is_install = true;
+ } else if (item.task == '-2') {
+ option = '
Updating';
+ soft.is_install = true;
+ } else {
+ if (pay_opt) {
+ option = pay_opt;
} else {
- option += '
' + lan.soft.setup + ' | ';
+ option = '
' + lan.soft.install + '';
}
- } else {
- option = pay_opt + ' | ' + option;
- }
- option += '
' + lan.soft.uninstall + '';
- } else if (item.task == '-1') {
- option = '
' + lan.soft.installing + '';
- soft.is_install = true;
- } else if (item.task == '0') {
- option = '
' + lan.soft.wait_install + '';
- soft.is_install = true;
- } else if (item.task == '-2') {
- option = '
Updating';
- soft.is_install = true;
- } else {
- if (pay_opt) {
- option = pay_opt;
- } else {
- option = '
' + lan.soft.install + '';
}
}
}
- if (webcache && is_php5) {
- if (!redhat) {
- option = '
' + lan.soft.not_comp + '';
- } else if (item.name == 'php-5.2'){
- option = '
' + lan.soft.not_comp + '';
- }
- }
- if (distribution=='centos8' && item.name == 'php-7.0') {
- option = '
' + lan.soft.not_comp + '';
- }
return option;
}
}
@@ -2747,13 +2814,15 @@ var soft = {
type: 'button',
width: '62px',
callback: function(ldata) {
- var datal = {};
+ var datal = {},
+ loadP = bt.load();
delete ldata.btn_fresh;
delete ldata.btn_save;
ldata['enableGzipCompress']=$("#enableGzipCompress").prop('checked')?1:0;
ldata = JSON.stringify(ldata);
datal = { array: ldata };
bt.send('set_ols_value', 'config/set_ols_value', datal, function(res) {
+ loadP.close();
soft.get_tab_contents(key, obj);
bt.msg(res);
});
@@ -2877,7 +2946,7 @@ function soft_td_width_auto() {
} else {
thead_width = winWidth / 3.5;
}
- $('#softList thead th:eq(2)').width(thead_width);
+ //$('#softList thead th:eq(2)').width(thead_width);
$('#softList tbody tr td:nth-child(8n+2)>span').width(thead_width + 75);
}
diff --git a/BTPanel/templates/default/layout.html b/BTPanel/templates/default/layout.html
index b050f93e..286b2fa3 100644
--- a/BTPanel/templates/default/layout.html
+++ b/BTPanel/templates/default/layout.html
@@ -89,7 +89,7 @@
{{session['config']['sites_path']}} {% block content %}{% endblock %}
diff --git a/class/ajax.py b/class/ajax.py
index a4814fb9..96967d1e 100644
--- a/class/ajax.py
+++ b/class/ajax.py
@@ -654,7 +654,7 @@ class ajax:
public.writeFile(p_file,'')
phpinfo = public.request_php(get.version,'/phpinfo.php',p_file,'')
if os.path.exists(p_file): os.remove(p_file)
- return phpinfo.decode();
+ return phpinfo.decode()
#清理日志
def delClose(self,get):
@@ -868,7 +868,7 @@ class ajax:
if get.port in rulePort:
return public.returnMsg(False,'AJAX_PHPMYADMIN_PORT_ERR')
if public.get_webserver() == 'nginx':
- rep = "listen\s+([0-9]+)\s*;"
+ rep = r"listen\s+([0-9]+)\s*;"
oldPort = re.search(rep,conf).groups()[0]
conf = re.sub(rep,'listen ' + get.port + ';\n',conf)
elif public.get_webserver() == 'apache':
@@ -937,7 +937,7 @@ class ajax:
return public.returnMsg(True,'SOFT_PHPMYADMIN_STATUS',(msg,))
#except:
#return public.returnMsg(False,'ERROR');
-
+
def ToPunycode(self,get):
import re;
get.domain = get.domain.encode('utf8')
diff --git a/class/common.py b/class/common.py
index 3f91b2a9..c2269524 100644
--- a/class/common.py
+++ b/class/common.py
@@ -34,7 +34,7 @@ class panelSetup:
ua = ua.lower()
if ua.find('spider') != -1 or ua.find('bot') != -1:
return redirect('https://www.google.com')
- g.version = '6.7.2'
+ g.version = '6.7.5'
g.title = public.GetConfigValue('title')
g.uri = request.path
if not os.path.exists('data/debug.pl'):
diff --git a/class/config.py b/class/config.py
index ccce0ade..04f563e9 100644
--- a/class/config.py
+++ b/class/config.py
@@ -415,6 +415,8 @@ class config:
ols_php_path = '/usr/local/lsws/lsphp' + get.version + '/etc/php.ini'
if not os.path.exists(filename): return public.returnMsg(False,'PHP_NOT_EXISTS')
for file in [filename,ols_php_path]:
+ if not os.path.exists(file):
+ continue
phpini = public.readFile(file)
rep = r"disable_functions\s*=\s*.*\n"
phpini = re.sub(rep, 'disable_functions = ' + get.disable_functions + "\n", phpini)
diff --git a/class/data.py b/class/data.py
index 6746045a..afb368fa 100644
--- a/class/data.py
+++ b/class/data.py
@@ -45,34 +45,36 @@ class data:
return result
def get_site_ssl_info(self,siteName):
- s_file = 'vhost/nginx/{}.conf'.format(siteName)
- is_apache = False
- if not os.path.exists(s_file):
- s_file = 'vhost/apache/{}.conf'.format(siteName)
- is_apache = True
+ try:
+ s_file = 'vhost/nginx/{}.conf'.format(siteName)
+ is_apache = False
+ if not os.path.exists(s_file):
+ s_file = 'vhost/apache/{}.conf'.format(siteName)
+ is_apache = True
- if not os.path.exists(s_file):
- return -1
+ if not os.path.exists(s_file):
+ return -1
- s_conf = public.readFile(s_file)
- if not s_conf: return -1
- ssl_file = None
- if is_apache:
- if s_conf.find('SSLCertificateFile') == -1:
- return -1
- s_tmp = re.findall(r"SSLCertificateFile\s+(.+\.pem)",s_conf)
- if not s_tmp: return -1
- ssl_file = s_tmp[0]
- else:
- if s_conf.find('ssl_certificate') == -1:
- return -1
- s_tmp = re.findall(r"ssl_certificate\s+(.+\.pem);",s_conf)
- if not s_tmp: return -1
- ssl_file = s_tmp[0]
- ssl_info = public.get_cert_data(ssl_file)
- if not ssl_info: return -1
- ssl_info['endtime'] = int(int(time.mktime(time.strptime(ssl_info['notAfter'], "%Y-%m-%d")) - time.time()) / 86400)
- return ssl_info
+ s_conf = public.readFile(s_file)
+ if not s_conf: return -1
+ ssl_file = None
+ if is_apache:
+ if s_conf.find('SSLCertificateFile') == -1:
+ return -1
+ s_tmp = re.findall(r"SSLCertificateFile\s+(.+\.pem)",s_conf)
+ if not s_tmp: return -1
+ ssl_file = s_tmp[0]
+ else:
+ if s_conf.find('ssl_certificate') == -1:
+ return -1
+ s_tmp = re.findall(r"ssl_certificate\s+(.+\.pem);",s_conf)
+ if not s_tmp: return -1
+ ssl_file = s_tmp[0]
+ ssl_info = public.get_cert_data(ssl_file)
+ if not ssl_info: return -1
+ ssl_info['endtime'] = int(int(time.mktime(time.strptime(ssl_info['notAfter'], "%Y-%m-%d")) - time.time()) / 86400)
+ return ssl_info
+ except: return -1
#return "{}:{}".format(ssl_info['issuer'],ssl_info['notAfter'])
diff --git a/class/database.py b/class/database.py
index cf846167..81246b14 100644
--- a/class/database.py
+++ b/class/database.py
@@ -118,6 +118,7 @@ ssl-key=/www/server/data/server-key.pem
if "ssl-ca" not in conf:
conf = re.sub('\[mysqld\]','[mysqld]'+ssl_conf,conf)
public.writeFile(conf_file,conf)
+ public.ExecShell('chown mysql.mysql /www/server/data/*.pem')
return public.returnMsg(True,"Open successfully, take effect after manually restarting the database")
# 检查mysqlssl状态
@@ -646,6 +647,11 @@ SetLink
#设置数据库权限
def SetDatabaseAccess(self,get):
+ ssl = ""
+ if hasattr(get,'ssl'):
+ ssl = get.ssl
+ if ssl == "REQUIRE SSL" and not self.check_mysql_ssl_status(get):
+ return public.returnMsg(False,'SSL is not enabled in the database, please open it in the Mysql manager first')
name = get['name']
db_name = public.M('databases').where('username=?',(name,)).getField('name')
access = get['access']
@@ -657,9 +663,6 @@ SetLink
users = mysql_obj.query("select Host from mysql.user where User='" + name + "' AND Host!='localhost'")
for us in users:
mysql_obj.execute("drop user '" + name + "'@'" + us[0] + "'")
- ssl = ""
- if hasattr(get,'ssl'):
- ssl = get.ssl
self.__CreateUsers(db_name,name,password,access,ssl)
return public.returnMsg(True, 'SET_SUCCESS')
diff --git a/class/files.py b/class/files.py
index 96109edc..87550610 100644
--- a/class/files.py
+++ b/class/files.py
@@ -1742,27 +1742,27 @@ cd %s
self.set_store_data(data)
return public.returnMsg(True,'Successfully deleted!')
- #单文件木马扫描
- def file_webshell_check(self,get):
- if not 'filename' in get: return public.returnMsg(True, 'file does not exist!')
- import webshell_check
- if webshell_check.webshell_check().upload_file_url(get.filename.strip()):
- return public.returnMsg(False,'This file is webshell [ %s ]'%get.filename.strip().split('/')[-1])
- else:
- return public.returnMsg(True, 'no risk')
-
- #目录扫描木马
- def dir_webshell_check(self,get):
- if not 'path' in get: return public.returnMsg(False, 'Please enter a valid directory!')
- path=get.path.strip()
- if os.path.exists(path):
- #启动消息队列
- exec_shell = public.get_python_bin() + ' /www/server/panel/class/webshell_check.py dir %s mail'%path
- task_name = "Scan Trojan files for directory %s"%path
- import panelTask
- task_obj = panelTask.bt_task()
- task_obj.create_task(task_name, 0, exec_shell)
- return public.returnMsg(True, 'Starting Trojan killing process. Details will be in the panel security log')
+ # #单文件木马扫描
+ # def file_webshell_check(self,get):
+ # if not 'filename' in get: return public.returnMsg(True, 'file does not exist!')
+ # import webshell_check
+ # if webshell_check.webshell_check().upload_file_url(get.filename.strip()):
+ # return public.returnMsg(False,'This file is webshell [ %s ]'%get.filename.strip().split('/')[-1])
+ # else:
+ # return public.returnMsg(True, 'no risk')
+ #
+ # #目录扫描木马
+ # def dir_webshell_check(self,get):
+ # if not 'path' in get: return public.returnMsg(False, 'Please enter a valid directory!')
+ # path=get.path.strip()
+ # if os.path.exists(path):
+ # #启动消息队列
+ # exec_shell = public.get_python_bin() + ' /www/server/panel/class/webshell_check.py dir %s mail'%path
+ # task_name = "Scan Trojan files for directory %s"%path
+ # import panelTask
+ # task_obj = panelTask.bt_task()
+ # task_obj.create_task(task_name, 0, exec_shell)
+ # return public.returnMsg(True, 'Starting Trojan killing process. Details will be in the panel security log')
# 获取下载地址列表
def get_download_url_list(self, get):
diff --git a/class/jobs.py b/class/jobs.py
index c1c14f04..bfb81f28 100644
--- a/class/jobs.py
+++ b/class/jobs.py
@@ -100,7 +100,7 @@ def control_init():
public.ExecShell(c)
p_file = 'class/plugin2.so'
if os.path.exists(p_file): public.ExecShell("rm -f class/*.so")
- public.ExecShell("chmod -R 600 /www/server/panel/data;chmod -R 600 /www/server/panel/config;chmod -R 700 /www/server/cron;chmod -R 600 /www/server/cron/*.log;chown -R root:root /www/server/panel/data;chown -R root:root /www/server/panel/config")
+ public.ExecShell("chmod -R 600 /www/server/panel/data;chmod -R 600 /www/server/panel/config;chmod -R 700 /www/server/cron;chmod -R 600 /www/server/cron/*.log;chown -R root:root /www/server/panel/data;chown -R root:root /www/server/panel/config;chown -R root:root /www/server/phpmyadmin;chmod -R 755 /www/server/phpmyadmin")
#disable_putenv('putenv')
clean_session()
#set_crond()
diff --git a/class/panelApi.py b/class/panelApi.py
index 17959070..02cd56a7 100644
--- a/class/panelApi.py
+++ b/class/panelApi.py
@@ -30,6 +30,17 @@ class panelApi:
del(data['key'])
return data
+
+ def login_for_app(self,get):
+ from BTPanel import cache
+ tid = get.tid
+ if(len(tid) != 12): return public.returnMsg(False,'Invalid login key')
+ session_id = cache.get(tid)
+ if not session_id: return public.returnMsg(False,'The specified key does not exist or has expired')
+ if(len(session_id) != 64): return public.returnMsg(False,'Invalid login key')
+ cache.set(session_id,'True',120)
+ return public.returnMsg(True,'Scan code successfully, log in!')
+
def get_api_config(self):
tmp = public.ReadFile(self.save_path)
if not tmp or not os.path.exists(self.save_path):
diff --git a/class/panelPHP.py b/class/panelPHP.py
index 3fadaf92..5e3793f0 100644
--- a/class/panelPHP.py
+++ b/class/panelPHP.py
@@ -90,7 +90,8 @@ class panelPHP:
shutil.copy(src_php_ini,php_ini)
#解除所有禁用函数
php_ini_body = public.readFile(php_ini)
- php_ini_body = re.sub("disable_functions\s*=.*","disable_functions = ",php_ini_body)
+ php_ini_body = re.sub(r"disable_functions\s*=.*","disable_functions = ",php_ini_body)
+ php_ini_body = re.sub(r".*bt_filter.+","",php_ini_body)
public.writeFile(php_ini,php_ini_body)
return php_path + php_v + '/bin/php -c ' + php_ini
diff --git a/class/panelPlugin.py b/class/panelPlugin.py
index 5de234d6..7aaadb65 100644
--- a/class/panelPlugin.py
+++ b/class/panelPlugin.py
@@ -153,26 +153,6 @@ class panelPlugin:
check_result = self.check_install_limit(get)
if check_result:
return check_result
- # p_node = '/www/server/panel/install/public.sh'
- # if os.path.exists(p_node):
- # if len(public.readFile(p_node)) < 100: os.remove(p_node)
- # if not pluginInfo: return public.returnMsg(False,'INIT_PLUGIN_NOT_EXISTS')
- # if not self.check_mutex(pluginInfo['mutex']): return public.returnMsg(False,'UNINSTALL_FIRST' , (pluginInfo['mutex'],))
- # if not hasattr(get,'id'):
- # if not self.check_dependnet(pluginInfo['dependnet']): return public.returnMsg(False,'DEP_PAGE' , (pluginInfo['dependnet'],))
- # if 'version' in get:
- # for versionInfo in pluginInfo['versions']:
- # if versionInfo['m_version'] != get.version: continue
- # if not 'type' in get: get.type = '0'
- # if int(get.type) > 4: get.type = '0'
- # if get.type == '0':
- # if not self.check_cpu_limit(versionInfo['cpu_limit']): return public.returnMsg(False,'At least [{0}] CPU cores are required to install'.format(versionInfo['cpu_limit']))
- # if not self.check_mem_limit(versionInfo['mem_limit']): return public.returnMsg(False,'At least [{0} MB] memory is required to install'.format(versionInfo['mem_limit']))
- # if not self.check_os_limit(versionInfo['os_limit']):
- # m_ps = {0:public.GetMsg("ALL"),1:"Centos",2:"Ubuntu/Debian"}
- # return public.returnMsg(False,'ONLY_SUP_SYS' , (m_ps[int(versionInfo['os_limit'])],))
- # if not hasattr(get,'id'):
- # if not self.check_dependnet(versionInfo['dependnet']): return public.returnMsg(False,'DEP_PAGE' , (versionInfo['dependnet'],))
if pluginInfo['type'] != 5:
result = self.install_sync(pluginInfo,get)
@@ -235,7 +215,7 @@ class panelPlugin:
if get.version == '1.8': return public.returnMsg(False,'NOT_SUP_NG1.8')
if get.sName.find('php-') != -1:get.sName = get.sName.split('-')[0]
ols_execstr = ""
- if "php" == get.sName:
+ if "php" == get.sName and os.path.exists('/usr/local/lsws'):
ols_sName = 'php-ols'
ols_version = get.version.replace('.','')
ols_execstr = " &> /tmp/panelExec.log && /bin/bash install_soft.sh {} {} " + ols_sName + " " + ols_version
@@ -255,7 +235,7 @@ class panelPlugin:
ols_execstr = ols_execstr.format(get.type,mtype)
execstr = "cd /www/server/panel/install && /bin/bash install_soft.sh {} {} {} {} {}".format(get.type,mtype,get.sName,get.version,ols_execstr)
if get.sName == "phpmyadmin":
- execstr += "&> /tmp/panelExec.log && /usr/local/lsws/bin/lswsctrl restart"
+ execstr += "&> /tmp/panelExec.log && sleep 1 && /usr/local/lsws/bin/lswsctrl restart"
public.M('tasks').add('id,name,type,status,addtime,execstr',(None, mmsg + '['+get.sName+'-'+get.version+']','execshell','0',time.strftime('%Y-%m-%d %H:%M:%S'),execstr))
cache.delete('install_task')
public.writeFile('/tmp/panelTask.pl','True')
@@ -700,16 +680,21 @@ class panelPlugin:
if not os.path.exists(self.__index): public.writeFile(self.__index,'[]')
indexList = json.loads(public.ReadFile(self.__index))
if sName in indexList: return public.returnMsg(False,'DONT_ADD_AGAIN')
-
if len(indexList) >= 12:
softList = self.get_cloud_list(get)['list']
for softInfo in softList:
+ # return softList
+ if softInfo['name'] == 'php':
+ for i in softInfo['versions']:
+ php_v = 'php-'+ i['m_version']
+ if not os.path.exists('/www/server/php/{}'.format(i['m_version']))\
+ and php_v in indexList:
+ indexList.remove(php_v)
if softInfo['name'] in indexList:
new_softInfo = self.check_status(softInfo)
if not new_softInfo['setup']: indexList.remove(softInfo['name'])
public.writeFile(self.__index,json.dumps(indexList))
if len(indexList) >= 12: return public.returnMsg(False,'HP_DIS_MOST')
-
indexList.append(sName)
public.writeFile(self.__index,json.dumps(indexList))
return public.returnMsg(True,'ADD_SUCCESS')
diff --git a/class/panelRedirect.py b/class/panelRedirect.py
index 902fee29..a7036e6d 100644
--- a/class/panelRedirect.py
+++ b/class/panelRedirect.py
@@ -154,11 +154,9 @@ class panelRedirect:
#检测名称是否重复
if sys.version_info.major < 3:
if len(get.redirectname) < 3 or len(get.redirectname) > 15:
- print("NAME_LEN")
return public.returnMsg(False, 'NAME_LEN')
else:
if len(get.redirectname.encode("utf-8")) < 3 or len(get.redirectname.encode("utf-8")) > 15:
- print("NAME_LEN")
return public.returnMsg(False, 'NAME_LEN')
if self.__CheckRedirect(get.sitename,get.redirectname):
return public.returnMsg(False, 'REDIRECT_EXIST')
diff --git a/class/panelSite.py b/class/panelSite.py
index c9f5ee6c..32d59768 100644
--- a/class/panelSite.py
+++ b/class/panelSite.py
@@ -329,7 +329,7 @@ extprocessor BTSITENAME {
}
phpIniOverride {
-php_admin_value open_basedir "/tmp:$VH_ROOT"
+php_admin_value open_basedir "/tmp/:BT_RUN_PATH"
}
expires {
@@ -346,6 +346,10 @@ rewrite {
}
include /www/server/panel/vhost/openlitespeed/proxy/BTSITENAME/*.conf
'''
+ open_base_path = self.sitePath
+ if self.sitePath[-1] != '/':
+ open_base_path = self.sitePath + '/'
+ conf = conf.replace('BT_RUN_PATH',open_base_path)
conf = conf.replace('BT_EXTP_NAME',self.siteName)
conf = conf.replace('BTPHPV',self.phpVersion)
conf = conf.replace('BTSITENAME',self.siteName)
@@ -1128,7 +1132,7 @@ listener Default%s{
result = self.GetSiteRunPath(get)
if 'runPath' in result:
return result['runPath']
- return False
+ return result
# 创建Let's Encrypt免费证书
@@ -2109,20 +2113,6 @@ listener SSL443 {
public.writeFile(file,conf301)
else:
public.ExecShell('rm -f {}*'.format(file))
- # mconf = public.readFile(filename)
- # if mconf == False: return public.returnMsg(False,'The specified configuration file does not exist!')
- # if type == '1':
- # if(srcDomain == 'all'):
- # conf301 = "\n\t#301-START\n\tRewriteEngine on\n\tRewriteRule ^(.*)$ "+toDomain+"$1 [L,R=301]\n\t#301-END\n"
- # else:
- # conf301 = "\n\t#301-START\n\tRewriteEngine on\n\tRewriteCond %{HTTP_HOST} ^"+srcDomain+" [NC]\n\tRewriteRule ^(.*) "+toDomain+"$1 [L,R=301]\n\t#301-END\n"
- # rep = "autoLoadHtaccess\s*1"
- # mconf = mconf.replace(rep,rep + "\n\t" + conf301)
- # else:
- # rep = "\n\s+#301-START(.|\n){1,300}#301-END\n*"
- # mconf = re.sub(rep, '\n\n', mconf,1)
- # mconf = re.sub(rep, '\n\n', mconf,1)
- # public.writeFile(filename,mconf)
isError = public.checkWebConfig()
if(isError != True):
@@ -2501,10 +2491,12 @@ server
public.writeFile(file,conf)
# OLS
- file = self.setupPath + '/panel/vhost/apache/' + Name + '.conf'
+ file = self.setupPath + '/panel/vhost/openlitespeed/' + Name + '.conf'
conf = public.readFile(file)
if conf:
- sitname = Path.split('/')[-2]
+ reg = 'vhRoot.*'
+ conf = re.sub(reg,'vhRoot '+Path,conf)
+ public.writeFile(file,conf)
#创建basedir
userIni = Path + '/.user.ini'
@@ -3026,11 +3018,6 @@ extprocessor %s {
}
""" % (get.proxyname,get.proxysite)
public.writeFile(file_path,reverse_proxy_conf)
- # detail_file = "%s/panel/vhost/openlitespeed/detail/%s.conf" % (self.setupPath,get.sitename)
- # detail_conf = public.readFile(detail_file)
- # if detail_conf:
- # include_conf = "\ninclude %s/panel/vhost/openlitespeed/proxy/%s/*.conf" % (self.setupPath,get.sitename)
- # public.writeFile(detail_file,include_conf,"a+")
# 添加urlrewrite
dir_path = "%s/panel/vhost/openlitespeed/proxy/%s/urlrewrite/" % (self.setupPath, get.sitename)
if not os.path.exists(dir_path):
@@ -3040,16 +3027,6 @@ extprocessor %s {
RewriteRule ^%s(.*)$ http://%s/$1 [P,E=Proxy-Host:%s]
""" % (get.proxydir,get.proxyname,get.todomain)
public.writeFile(file_path,reverse_urlrewrite_conf)
- # detail_file = "%s/panel/vhost/openlitespeed/detail/%s.conf" % (self.setupPath,get.sitename)
- # detail_conf = public.readFile(detail_file)
- # if detail_conf:
- # include_conf = "\n include %s/panel/vhost/openlitespeed/proxy/%s/urlrewrite/*.conf" % (self.setupPath,get.sitename)
- # rep = "autoLoadHtaccess\s+1"
- # tmp = re.search(rep,detail_conf).group()
- # tmp = tmp + include_conf
- # detail_conf = re.sub(rep,tmp,detail_conf)
- # public.writeFile(detail_file,detail_conf)
-
# 检查伪静态、主配置文件是否有location冲突
def CheckLocation(self,get):
diff --git a/class/public.py b/class/public.py
index d33ae040..17fb4720 100644
--- a/class/public.py
+++ b/class/public.py
@@ -533,19 +533,43 @@ def phpReload(version):
else:
ExecShell('/etc/init.d/php-fpm-' + version + ' reload')
+def get_timeout(url,timeout=3):
+ try:
+ start = time.time()
+ result = int(httpGet(url,timeout))
+ return result,int((time.time() - start) * 1000 - 500)
+ except: return 0,False
+
def get_url(timeout = 0.5):
import json
try:
nodeFile = 'data/node.json'
node_list = json.loads(readFile(nodeFile))
- mnode = None
+ mnode1 = []
+ mnode2 = []
+ mnode3 = []
for node in node_list:
- node['ping'] = get_timeout(node['protocol'] + node['address'] + ':' + node['port'] + '/check.txt')
+ node['net'],node['ping'] = get_timeout(node['protocol'] + node['address'] + ':' + node['port'] + '/net_test',1)
if not node['ping']: continue
- if not mnode: mnode = node
- if node['ping'] < mnode['ping']: mnode = node
- if mnode['ping'] < 50: break
- return mnode['protocol'] + mnode['address'] + ':' + mnode['port']
+ if node['ping'] < 100: #当响应时间<100ms且可用带宽大于1500KB时
+ if node['net'] > 1500:
+ mnode1.append(node)
+ elif node['net'] > 1000:
+ mnode3.append(node)
+ else:
+ if node['net'] > 1000: #当响应时间>=100ms且可用带宽大于1000KB时
+ mnode2.append(node)
+ if node['ping'] < 100:
+ if node['net'] > 3000: break #有节点可用带宽大于3000时,不再检查其它节点
+ if mnode1: #优选低延迟高带宽
+ mnode = sorted(mnode1,key= lambda x:x['net'],reverse=True)
+ elif mnode3: #备选低延迟,中等带宽
+ 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'
+ return mnode[0]['protocol'] + mnode[0]['address'] + ':' + mnode[0]['port']
except:
return 'http://download.bt.cn'
@@ -840,14 +864,6 @@ def hasPwd(password):
import crypt
return crypt.crypt(password,password)
-def get_timeout(url,timeout=3):
- try:
- start = time.time()
- result = httpGet(url,timeout)
- if result != 'True': return False
- return int((time.time() - start) * 1000)
- except: return False
-
def getDate(format='%Y-%m-%d %X'):
# 取格式时间
return time.strftime(format, time.localtime())
@@ -1723,6 +1739,30 @@ def get_linux_distribution():
distribution = 'centos7'
return distribution
+def long2ip(ips):
+ '''
+ @name 将整数转换为IP地址
+ @author hwliang<2020-06-11>
+ @param ips string(ip地址整数)
+ @return ipv4
+ '''
+ i1 = int(ips / (2 ** 24))
+ i2 = int((ips - i1 * ( 2 ** 24 )) / ( 2 ** 16 ))
+ i3 = int(((ips - i1 * ( 2 ** 24 )) - i2 * ( 2 ** 16 )) / ( 2 ** 8))
+ i4 = int(((ips - i1 * ( 2 ** 24 )) - i2 * ( 2 ** 16 )) - i3 * ( 2 ** 8))
+ return "{}.{}.{}.{}".format(i1,i2,i3,i4)
+
+def ip2long(ip):
+ '''
+ @name 将IP地址转换为整数
+ @author hwliang<2020-06-11>
+ @param ip string(ipv4)
+ @return long
+ '''
+ ips = ip.split('.')
+ if len(ips) != 4: return 0
+ iplong = 2 ** 24 * int(ips[0]) + 2 ** 16 * int(ips[1]) + 2 ** 8 * int(ips[2]) + int(ips[3])
+ return iplong
#取通用对象
class dict_obj:
diff --git a/class/ssh_security.py b/class/ssh_security.py
index 418e2b23..790c0992 100644
--- a/class/ssh_security.py
+++ b/class/ssh_security.py
@@ -244,6 +244,12 @@ class ssh_security:
'addtime desc').select()
return data
+ def get_server_ip(self):
+ if os.path.exists('/www/server/panel/data/iplist.txt'):
+ data=public.ReadFile('/www/server/panel/data/iplist.txt')
+ return data.strip()
+ else:return '127.0.0.1'
+
#登陆的情况下
def login(self):
@@ -256,10 +262,14 @@ class ssh_security:
ip = ["127.0.0.1"]
if len(ip[0])==0:return False
try:
+ import time
+ mDate = time.strftime('%Y-%m-%d %X', time.localtime())
if ip[0] in self.__ip_data:
+ if public.M('logs').where('type=? addtime', ('SSH security',mDate,)).count():return False
public.WriteLog('SSH security', 'The server {} login IP is {}, login user is root'.format(public.GetLocalIp(),ip[0]))
return False
else:
+ if public.M('logs').where('type=? addtime', ('SSH security', mDate,)).count(): return False
self.send_mail_data('Server {} login alarm'.format(public.GetLocalIp()),'There is a login alarm on the server {}, the login IP is {}, the login user is root'.format(public.GetLocalIp(),ip[0]))
public.WriteLog('SSH security','There is a login alarm on the server {}, the login IP is {}, login user is root'.format(public.GetLocalIp(),ip [0]))
return True
@@ -438,7 +448,9 @@ if __name__ == '__main__':
import sys
type = sys.argv[1]
if type=='login':
- aa = ssh_security()
- aa.login()
+ try:
+ aa = ssh_security()
+ aa.login()
+ except:pass
else:
pass
diff --git a/class/userlogin.py b/class/userlogin.py
index 8368dba2..2ad2154e 100644
--- a/class/userlogin.py
+++ b/class/userlogin.py
@@ -30,7 +30,7 @@ class userlogin:
userInfo = u_info
if 'code' in session:
if session['code'] and not 'is_verify_password' in session:
- if not hasattr(post, 'code'): return public.returnMsg(False,'Verification code can not be empty!')
+ if not hasattr(post, 'code'): return public.returnJson(False,'Verification code can not be empty!')
if not public.checkCode(post.code):
public.WriteLog('TYPE_LOGIN','LOGIN_ERR_CODE',('****','****',public.GetClientIp()))
return public.returnJson(False,'CODE_ERR'),json_header
@@ -218,7 +218,7 @@ class userlogin:
session['login'] = True
session['username'] = userInfo['username']
session['uid'] = userInfo['id']
- public.WriteLog('TYPE_LOGIN','LOGIN_SUCCESS',(userInfo['username'],public.GetClientIp()))
+ public.WriteLog('TYPE_LOGIN','LOGIN_SUCCESS',(userInfo['username'],public.GetClientIp()+ ":" + str(request.environ.get('REMOTE_PORT'))))
self.limit_address('-')
cache.delete('panelNum')
cache.delete('dologin')
@@ -226,6 +226,9 @@ class userlogin:
public.writeFile(sess_input_path,str(int(time.time())))
self.set_request_token()
self.login_token()
+ login_type = 'data/app_login.pl'
+ if os.path.exists(login_type):
+ os.remove(login_type)
return public.returnJson(True,'LOGIN_SUCCESS'),json_header
except Exception as ex:
stringEx = str(ex)
diff --git a/class/webshell_check.py b/class/webshell_check.py
index bddfab85..efbfb59b 100644
--- a/class/webshell_check.py
+++ b/class/webshell_check.py
@@ -1,319 +1,319 @@
-# coding: utf-8
-# +-------------------------------------------------------------------
-# | 宝塔Linux面板 x6
-# +-------------------------------------------------------------------
-# | Copyright (c) 2015-2017 宝塔软件(http://bt.cn) All rights reserved.
-# +-------------------------------------------------------------------
-# | Author: lkqiang
-# +-------------------------------------------------------------------
-# +--------------------------------------------------------------------
-# | 宝塔webshell 内置扫描
-# +--------------------------------------------------------------------
-
-import public, hashlib, os, sys, json, time, re
-import send_mail
-
-
-class webshell_check:
- __PATH = '/www/server/panel/data/'
- __mail_config = '/www/server/panel/data/stmp_mail.json'
- __mail_list_data = '/www/server/panel/data/mail_list.json'
- __dingding_config = '/www/server/panel/data/dingding.json'
- __mail_list = []
- __weixin_user = []
-
- def __init__(self):
- self.mail = send_mail.send_mail()
- if not os.path.exists(self.__mail_list_data):
- ret = []
- public.writeFile(self.__mail_list_data, json.dumps(ret))
- else:
- try:
- mail_data = json.loads(public.ReadFile(self.__mail_list_data))
- self.__mail_list = mail_data
- except:
- ret = []
- public.writeFile(self.__mail_list_data, json.dumps(ret))
- if not os.path.exists(self.__PATH + 'webshell_rule.json'):
- rule = ["@\\$\\_\\(\\$\\_", "\\$\\_=\"\"", "\\${'\\_'",
- "@preg\\_replace\\((\")*\\/(\\S)*\\/e(\")*,\\$_POST\\[\\S*\\]", "base64\\_decode\\(\\$\\_",
- "'e'\\.'v'\\.'a'\\.'l'", "\"e\"\\.\"v\"\\.\"a\"\\.\"l\"", "\"e\"\\.\"v\"\\.\"a\"\\.\"l\"",
- "\\$(\\w)+\\(\"\\/(\\S)+\\/e", "\\(array\\)\\$_(POST|GET|REQUEST|COOKIE)", "\\$(\\w)+\\(\\${",
- "@\\$\\_=", "\\$\\_=\\$\\_", "chr\\((\\d)+\\)\\.chr\\((\\d)+\\)", "phpjm\\.net", "cha88\\.cn",
- "c99shell", "phpspy", "Scanners", "cmd\\.php", "str_rot13", "webshell", "EgY_SpIdEr",
- "tools88\\.com", "SECFORCE", "eval\\(('|\")\\?>", "preg_replace\\(\"\\/\\.\\*\\/e\"",
- "assert\\(('|\"|\\s*)\\$", "eval\\(gzinflate\\(", "gzinflate\\(base64_decode\\(",
- "eval\\(base64_decode\\(", "eval\\(gzuncompress\\(", "ies\",gzuncompress\\(\\$",
- "eval\\(gzdecode\\(", "eval\\(str_rot13\\(", "gzuncompress\\(base64_decode\\(",
- "base64_decode\\(gzuncompress\\(", "eval\\(('|\"|\\s*)\\$_(POST|GET|REQUEST|COOKIE)",
- "assert\\(('|\"|\\s*)\\$_(POST|GET|REQUEST|COOKIE)",
- "require\\(('|\"|\\s*)\\$_(POST|GET|REQUEST|COOKIE)",
- "require_once\\(('|\"|\\s*)\\$_(POST|GET|REQUEST|COOKIE)",
- "include\\(('|\"|\\s*)\\$_(POST|GET|REQUEST|COOKIE)",
- "include_once\\(('|\"|\\s*)\\$_(POST|GET|REQUEST|COOKIE)", "call_user_func\\((\"|')assert(\"|')",
- "call_user_func\\(('|\"|\\s*)\\$_(POST|GET|REQUEST|COOKIE)",
- "\\$_(POST|GET|REQUEST|COOKIE)\\[([^\\]]+)\\]\\(('|\"|\\s*)\\$_(POST|GET|REQUEST|COOKIE)\\[",
- "echo\\(file_get_contents\\(('|\"|\\s*)\\$_(POST|GET|REQUEST|COOKIE)",
- "file_put_contents\\(('|\"|\\s*)\\$_(POST|GET|REQUEST|COOKIE)\\[([^\\]]+)\\],('|\"|\\s*)\\$_(POST|GET|REQUEST|COOKIE)",
- "fputs\\(fopen\\((.+),('|\")w('|\")\\),('|\"|\\s*)\\$_(POST|GET|REQUEST|COOKIE)\\[",
- "SetHandlerapplication\\/x-httpd-php", "php_valueauto_prepend_file", "php_valueauto_append_file"]
- public.WriteFile(self.__PATH + 'webshell_rule.json', json.dumps(rule))
-
- # 返回配置邮件地址
- def return_mail_list(self):
- return self.__mail_list
-
- # 查看自定义邮箱配置
- def get_user_mail(self):
- qq_mail_info = json.loads(public.ReadFile(self.__mail_config))
- if len(qq_mail_info) == 0:
- return False
- return qq_mail_info
-
- # 查看钉钉
- def get_dingding(self):
- qq_mail_info = json.loads(public.ReadFile(self.__dingding_config))
- if len(qq_mail_info) == 0:
- return False
- return qq_mail_info
-
- # 查看能使用的告警通道
- def get_settings(self):
- qq_mail_info = json.loads(public.ReadFile(self.__mail_config))
- if len(qq_mail_info) == 0:
- user_mail = False
- else:
- user_mail = True
- dingding_info = json.loads(public.ReadFile(self.__dingding_config))
- if len(dingding_info) == 0:
- dingding = False
- else:
- dingding = True
- ret = {}
- ret['user_mail'] = {"user_name": user_mail, "mail_list": self.__mail_list, "info": self.get_user_mail()}
- ret['dingding'] = {"dingding": dingding, "info": self.get_dingding()}
- return ret
-
- # 返回站点
- def return_site(self):
- data = public.M('sites').field('name,path').select()
- ret = {}
- for i in data:
- ret[i['name']] = i['path']
- return public.returnMsg(True, ret)
-
- # 获取规则
- def get_rule(self):
- ret = []
- if os.path.exists(self.__PATH + 'webshell_rule.json'):
- try:
- data = json.loads(public.ReadFile(self.__PATH + 'webshell_rule.json'))
- return data
- except:
- return False
- else:
- return False
-
- def get_dir(self, path):
- return_data = []
- data2 = []
- [[return_data.append(os.path.join(root, file)) for file in files] for root, dirs, files in os.walk(path)]
- for i in return_data:
- if str(i.lower())[-4:] == '.php':
- data2.append(i)
- return data2
-
- # 目录
- def getdir_list(self, path_data):
- if os.path.exists(str(path_data)):
- return self.get_dir(path_data)
- else:
- return False
-
- # 扫描
- def scan(self, filelist, rule):
- import time
- time_data = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
- ret = []
- data2 = []
- for file in filelist:
- try:
- data = open(file).read()
- for r in rule:
- if re.compile(r).findall(data):
- result = {}
- result[file] = r
- ret.append(result)
- data = ("%s [!] %s %s \n" % (time_data, file, r))
- data2.append(file)
- except:print('%s File opening failed! !! Skipping'%file)
- return data2
-
- # 上传webshell
- def upload_shell(self, data):
- if len(data) == 0: return []
- return_data = []
- for i in data:
- if self.upload_file_url(i):
- return_data.append(i)
- return return_data
-
- def san_dir(self, path, send='mail'):
- file = self.getdir_list(path)
- if not file: return exit( "Directory does not exist")
- rule = self.get_rule()
- if not rule: return exit("Rule is empty or rule file is wrong")
- result = self.scan(file, rule)
- return_data = self.upload_shell(result)
- tongdao = self.get_settings()
- if len(return_data) >= 1:
- if send == 'dingding':
- if tongdao['dingding']:
- msg="Webshell killing found the Trojan in the % s directory as follows:%s"%(path,return_data)
- self.mail.dingding_send(msg)
- elif send == 'mail':
- if tongdao['user_mail']:
-
- title = "Webshell killing found the Trojan in the % s directory as follows" % (path)
- body = "Webshell search and found that the Trojan exists in the %s directory as follows: %s" % (path, return_data)
- if len(self.__mail_list)==0:
- if tongdao['user_mail']['user_name']:
- self.mail.qq_smtp_send(str(tongdao['user_mail']['info']['qq_mail']), title=title, body=body)
- else:
- for i in self.__mail_list:
- if tongdao['user_mail']['user_name']:
- self.mail.qq_smtp_send(str(i), title=title, body=body)
- return return_data
-
- def send_san_dir(self, path, send):
- file = self.getdir_list(path)
- if not file: return exit( "Directory does not exist")
- rule = self.get_rule()
- if not rule: return exit("Rule is empty or rule file is wrong")
- result = self.scan(file, rule)
- return_data = self.upload_shell(result)
- tongdao = self.get_settings()
- if len(return_data) >= 1:
- if send == 'dingding':
- if tongdao['dingding']:
- msg="Webshell search and found that the Trojan exists in the %s directory as follows: %s"%(path,return_data)
- self.mail.dingding_send(msg)
- elif send == 'mail':
- if tongdao['user_mail']:
- title = "Webshell killing found the Trojan in the %s directory as follows" % (path)
- body = "Webshell search and found that the Trojan exists in the %s directory as follows: %s" % (path, return_data)
- if len(self.__mail_list)==0:
- self.mail.qq_smtp_send(str(tongdao['user_mail']['info']['qq_mail']), title=title, body=body)
- else:
- for i in self.__mail_list:
- self.mail.qq_smtp_send(str(i), title=title, body=body)
- return return_data
-
- def upload_file_url(self, filename):
- try:
- if os.path.exists(filename):
- data = public.ExecShell(
- '/usr/local/curl/bin/curl https://scanner.baidu.com/enqueue -F archive=@%s' % filename)
- data = json.loads(data[0])
- time.sleep(3)
- import http_requests
- default_headers = {
- 'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36'
- }
- data_list = http_requests.get(url=data['url'], headers=default_headers, verify=False)
- data2 = data_list.json()
- if 'data' in data2[0]:
- if len(data2[0]['data']) >= 1:
- if 'descr' in data2[0]['data'][0]:
- if 'WebShell' in data2[0]['data'][0]['descr']:
- print('%s file is a Trojan'%filename)
- self.send_baota2(filename)
- return True
- return False
- else:
- return False
- except:
- return False
-
- def read_file_md5(self, filename):
- if os.path.exists(filename):
- with open(filename, 'rb') as fp:
- data = fp.read()
- file_md5 = hashlib.md5(data).hexdigest()
- return file_md5
- else:
- return False
-
- def send_baota2(self, filename):
- cloudUrl = 'http://www.bt.cn/api/panel/btwaf_submit'
- pdata = {'codetxt': public.ReadFile(filename), 'md5': self.read_file_md5(filename), 'type': '0',
- 'host_ip': public.GetLocalIp(), 'size': os.path.getsize(filename)}
- ret = public.httpPost(cloudUrl, pdata)
- return True
-
- def send_baota(self, filename):
- if not os.path.exists(filename): return False
- cloudUrl = 'http://www.bt.cn/api/panel/btwaf_submit'
- pdata = {'codetxt': public.ReadFile(filename), 'md5': self.read_file_md5(filename), 'type': '0',
- 'host_ip': public.GetLocalIp(), 'size': os.path.getsize(filename)}
- ret = public.httpPost(cloudUrl, pdata)
- if ret == '1':
- return self.check_webshell(filename)
- elif ret == '-1':
- return self.check_webshell(filename)
- else:
- return False
-
- def check_webshell(self, filename):
- if not os.path.exists(filename): return False
- cloudUrl = 'http://www.bt.cn/api/panel/btwaf_check_file'
- pdata = {'md5': self.read_file_md5(filename), 'size': os.path.getsize(filename)}
- ret = public.httpPost(cloudUrl, pdata)
- if ret == '0':
- return False
- elif ret == '1':
- return False
- elif ret == '-1':
- return False
- else:
- return False
-
- def __get_md5(self, s):
- m = hashlib.md5()
- m.update(s.encode('utf-8'))
- return m.hexdigest()
-
-
-if __name__ == "__main__":
- public.WriteFile('/www/server/panel/data/webshell_data.json', json.dumps([]))
- type = sys.argv[1]
- path = sys.argv[2]
- send = sys.argv[3]
- os.chdir("/www/server/panel")
- import sys
- sys.path.append('class')
- import public
- aa = webshell_check()
- print('Start scanning webshell')
- start_time=time.time()
- if type == 'dir':
- data = aa.san_dir(path)
- public.WriteFile('/www/server/panel/data/webshell_data.json', json.dumps(data))
- localtime = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
- if len(data) >= 1:
- public.WriteLog('aaPanel built-in webshell killing','Killing the %s directory found the following Trojan %s'%(path,data))
- else:
- public.WriteLog('aaPanel built-in webshell killing','Checking and killing [ %s ] directory did not find any risks'%(path))
- elif type=='site':
- data = public.M('sites').where('name=?', (path,)).field('name,id,path').select()
- localtime = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
- if len(data) >= 1:
- path = data[0]['path']
- ##木马返回在这里
- data = aa.send_san_dir(path, send)
- if len(data) >= 1:
- public.WriteLog('aaPanel built-in webshell killing', 'Killing the %s directory found the following Trojan %s' % (path, data))
- else:
- public.WriteLog('aaPanel built-in webshell killing','Checking and killing [ %s ] directory did not find any risks'%(path))
-
-
+# # coding: utf-8
+# # +-------------------------------------------------------------------
+# # | 宝塔Linux面板 x6
+# # +-------------------------------------------------------------------
+# # | Copyright (c) 2015-2017 宝塔软件(http://bt.cn) All rights reserved.
+# # +-------------------------------------------------------------------
+# # | Author: lkqiang
+# # +-------------------------------------------------------------------
+# # +--------------------------------------------------------------------
+# # | 宝塔webshell 内置扫描
+# # +--------------------------------------------------------------------
+#
+# import public, hashlib, os, sys, json, time, re
+# import send_mail
+#
+#
+# class webshell_check:
+# __PATH = '/www/server/panel/data/'
+# __mail_config = '/www/server/panel/data/stmp_mail.json'
+# __mail_list_data = '/www/server/panel/data/mail_list.json'
+# __dingding_config = '/www/server/panel/data/dingding.json'
+# __mail_list = []
+# __weixin_user = []
+#
+# def __init__(self):
+# self.mail = send_mail.send_mail()
+# if not os.path.exists(self.__mail_list_data):
+# ret = []
+# public.writeFile(self.__mail_list_data, json.dumps(ret))
+# else:
+# try:
+# mail_data = json.loads(public.ReadFile(self.__mail_list_data))
+# self.__mail_list = mail_data
+# except:
+# ret = []
+# public.writeFile(self.__mail_list_data, json.dumps(ret))
+# if not os.path.exists(self.__PATH + 'webshell_rule.json'):
+# rule = ["@\\$\\_\\(\\$\\_", "\\$\\_=\"\"", "\\${'\\_'",
+# "@preg\\_replace\\((\")*\\/(\\S)*\\/e(\")*,\\$_POST\\[\\S*\\]", "base64\\_decode\\(\\$\\_",
+# "'e'\\.'v'\\.'a'\\.'l'", "\"e\"\\.\"v\"\\.\"a\"\\.\"l\"", "\"e\"\\.\"v\"\\.\"a\"\\.\"l\"",
+# "\\$(\\w)+\\(\"\\/(\\S)+\\/e", "\\(array\\)\\$_(POST|GET|REQUEST|COOKIE)", "\\$(\\w)+\\(\\${",
+# "@\\$\\_=", "\\$\\_=\\$\\_", "chr\\((\\d)+\\)\\.chr\\((\\d)+\\)", "phpjm\\.net", "cha88\\.cn",
+# "c99shell", "phpspy", "Scanners", "cmd\\.php", "str_rot13", "webshell", "EgY_SpIdEr",
+# "tools88\\.com", "SECFORCE", "eval\\(('|\")\\?>", "preg_replace\\(\"\\/\\.\\*\\/e\"",
+# "assert\\(('|\"|\\s*)\\$", "eval\\(gzinflate\\(", "gzinflate\\(base64_decode\\(",
+# "eval\\(base64_decode\\(", "eval\\(gzuncompress\\(", "ies\",gzuncompress\\(\\$",
+# "eval\\(gzdecode\\(", "eval\\(str_rot13\\(", "gzuncompress\\(base64_decode\\(",
+# "base64_decode\\(gzuncompress\\(", "eval\\(('|\"|\\s*)\\$_(POST|GET|REQUEST|COOKIE)",
+# "assert\\(('|\"|\\s*)\\$_(POST|GET|REQUEST|COOKIE)",
+# "require\\(('|\"|\\s*)\\$_(POST|GET|REQUEST|COOKIE)",
+# "require_once\\(('|\"|\\s*)\\$_(POST|GET|REQUEST|COOKIE)",
+# "include\\(('|\"|\\s*)\\$_(POST|GET|REQUEST|COOKIE)",
+# "include_once\\(('|\"|\\s*)\\$_(POST|GET|REQUEST|COOKIE)", "call_user_func\\((\"|')assert(\"|')",
+# "call_user_func\\(('|\"|\\s*)\\$_(POST|GET|REQUEST|COOKIE)",
+# "\\$_(POST|GET|REQUEST|COOKIE)\\[([^\\]]+)\\]\\(('|\"|\\s*)\\$_(POST|GET|REQUEST|COOKIE)\\[",
+# "echo\\(file_get_contents\\(('|\"|\\s*)\\$_(POST|GET|REQUEST|COOKIE)",
+# "file_put_contents\\(('|\"|\\s*)\\$_(POST|GET|REQUEST|COOKIE)\\[([^\\]]+)\\],('|\"|\\s*)\\$_(POST|GET|REQUEST|COOKIE)",
+# "fputs\\(fopen\\((.+),('|\")w('|\")\\),('|\"|\\s*)\\$_(POST|GET|REQUEST|COOKIE)\\[",
+# "SetHandlerapplication\\/x-httpd-php", "php_valueauto_prepend_file", "php_valueauto_append_file"]
+# public.WriteFile(self.__PATH + 'webshell_rule.json', json.dumps(rule))
+#
+# # 返回配置邮件地址
+# def return_mail_list(self):
+# return self.__mail_list
+#
+# # 查看自定义邮箱配置
+# def get_user_mail(self):
+# qq_mail_info = json.loads(public.ReadFile(self.__mail_config))
+# if len(qq_mail_info) == 0:
+# return False
+# return qq_mail_info
+#
+# # 查看钉钉
+# def get_dingding(self):
+# qq_mail_info = json.loads(public.ReadFile(self.__dingding_config))
+# if len(qq_mail_info) == 0:
+# return False
+# return qq_mail_info
+#
+# # 查看能使用的告警通道
+# def get_settings(self):
+# qq_mail_info = json.loads(public.ReadFile(self.__mail_config))
+# if len(qq_mail_info) == 0:
+# user_mail = False
+# else:
+# user_mail = True
+# dingding_info = json.loads(public.ReadFile(self.__dingding_config))
+# if len(dingding_info) == 0:
+# dingding = False
+# else:
+# dingding = True
+# ret = {}
+# ret['user_mail'] = {"user_name": user_mail, "mail_list": self.__mail_list, "info": self.get_user_mail()}
+# ret['dingding'] = {"dingding": dingding, "info": self.get_dingding()}
+# return ret
+#
+# # 返回站点
+# def return_site(self):
+# data = public.M('sites').field('name,path').select()
+# ret = {}
+# for i in data:
+# ret[i['name']] = i['path']
+# return public.returnMsg(True, ret)
+#
+# # 获取规则
+# def get_rule(self):
+# ret = []
+# if os.path.exists(self.__PATH + 'webshell_rule.json'):
+# try:
+# data = json.loads(public.ReadFile(self.__PATH + 'webshell_rule.json'))
+# return data
+# except:
+# return False
+# else:
+# return False
+#
+# def get_dir(self, path):
+# return_data = []
+# data2 = []
+# [[return_data.append(os.path.join(root, file)) for file in files] for root, dirs, files in os.walk(path)]
+# for i in return_data:
+# if str(i.lower())[-4:] == '.php':
+# data2.append(i)
+# return data2
+#
+# # 目录
+# def getdir_list(self, path_data):
+# if os.path.exists(str(path_data)):
+# return self.get_dir(path_data)
+# else:
+# return False
+#
+# # 扫描
+# def scan(self, filelist, rule):
+# import time
+# time_data = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
+# ret = []
+# data2 = []
+# for file in filelist:
+# try:
+# data = open(file).read()
+# for r in rule:
+# if re.compile(r).findall(data):
+# result = {}
+# result[file] = r
+# ret.append(result)
+# data = ("%s [!] %s %s \n" % (time_data, file, r))
+# data2.append(file)
+# except:print('%s File opening failed! !! Skipping'%file)
+# return data2
+#
+# # 上传webshell
+# def upload_shell(self, data):
+# if len(data) == 0: return []
+# return_data = []
+# for i in data:
+# if self.upload_file_url(i):
+# return_data.append(i)
+# return return_data
+#
+# def san_dir(self, path, send='mail'):
+# file = self.getdir_list(path)
+# if not file: return exit( "Directory does not exist")
+# rule = self.get_rule()
+# if not rule: return exit("Rule is empty or rule file is wrong")
+# result = self.scan(file, rule)
+# return_data = self.upload_shell(result)
+# tongdao = self.get_settings()
+# if len(return_data) >= 1:
+# if send == 'dingding':
+# if tongdao['dingding']:
+# msg="Webshell killing found the Trojan in the % s directory as follows:%s"%(path,return_data)
+# self.mail.dingding_send(msg)
+# elif send == 'mail':
+# if tongdao['user_mail']:
+#
+# title = "Webshell killing found the Trojan in the % s directory as follows" % (path)
+# body = "Webshell search and found that the Trojan exists in the %s directory as follows: %s" % (path, return_data)
+# if len(self.__mail_list)==0:
+# if tongdao['user_mail']['user_name']:
+# self.mail.qq_smtp_send(str(tongdao['user_mail']['info']['qq_mail']), title=title, body=body)
+# else:
+# for i in self.__mail_list:
+# if tongdao['user_mail']['user_name']:
+# self.mail.qq_smtp_send(str(i), title=title, body=body)
+# return return_data
+#
+# def send_san_dir(self, path, send):
+# file = self.getdir_list(path)
+# if not file: return exit( "Directory does not exist")
+# rule = self.get_rule()
+# if not rule: return exit("Rule is empty or rule file is wrong")
+# result = self.scan(file, rule)
+# return_data = self.upload_shell(result)
+# tongdao = self.get_settings()
+# if len(return_data) >= 1:
+# if send == 'dingding':
+# if tongdao['dingding']:
+# msg="Webshell search and found that the Trojan exists in the %s directory as follows: %s"%(path,return_data)
+# self.mail.dingding_send(msg)
+# elif send == 'mail':
+# if tongdao['user_mail']:
+# title = "Webshell killing found the Trojan in the %s directory as follows" % (path)
+# body = "Webshell search and found that the Trojan exists in the %s directory as follows: %s" % (path, return_data)
+# if len(self.__mail_list)==0:
+# self.mail.qq_smtp_send(str(tongdao['user_mail']['info']['qq_mail']), title=title, body=body)
+# else:
+# for i in self.__mail_list:
+# self.mail.qq_smtp_send(str(i), title=title, body=body)
+# return return_data
+#
+# def upload_file_url(self, filename):
+# try:
+# if os.path.exists(filename):
+# data = public.ExecShell(
+# '/usr/local/curl/bin/curl https://scanner.baidu.com/enqueue -F archive=@%s' % filename)
+# data = json.loads(data[0])
+# time.sleep(3)
+# import http_requests
+# default_headers = {
+# 'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36'
+# }
+# data_list = http_requests.get(url=data['url'], headers=default_headers, verify=False)
+# data2 = data_list.json()
+# if 'data' in data2[0]:
+# if len(data2[0]['data']) >= 1:
+# if 'descr' in data2[0]['data'][0]:
+# if 'WebShell' in data2[0]['data'][0]['descr']:
+# print('%s file is a Trojan'%filename)
+# self.send_baota2(filename)
+# return True
+# return False
+# else:
+# return False
+# except:
+# return False
+#
+# def read_file_md5(self, filename):
+# if os.path.exists(filename):
+# with open(filename, 'rb') as fp:
+# data = fp.read()
+# file_md5 = hashlib.md5(data).hexdigest()
+# return file_md5
+# else:
+# return False
+#
+# def send_baota2(self, filename):
+# cloudUrl = 'http://www.bt.cn/api/panel/btwaf_submit'
+# pdata = {'codetxt': public.ReadFile(filename), 'md5': self.read_file_md5(filename), 'type': '0',
+# 'host_ip': public.GetLocalIp(), 'size': os.path.getsize(filename)}
+# ret = public.httpPost(cloudUrl, pdata)
+# return True
+#
+# def send_baota(self, filename):
+# if not os.path.exists(filename): return False
+# cloudUrl = 'http://www.bt.cn/api/panel/btwaf_submit'
+# pdata = {'codetxt': public.ReadFile(filename), 'md5': self.read_file_md5(filename), 'type': '0',
+# 'host_ip': public.GetLocalIp(), 'size': os.path.getsize(filename)}
+# ret = public.httpPost(cloudUrl, pdata)
+# if ret == '1':
+# return self.check_webshell(filename)
+# elif ret == '-1':
+# return self.check_webshell(filename)
+# else:
+# return False
+#
+# def check_webshell(self, filename):
+# if not os.path.exists(filename): return False
+# cloudUrl = 'http://www.bt.cn/api/panel/btwaf_check_file'
+# pdata = {'md5': self.read_file_md5(filename), 'size': os.path.getsize(filename)}
+# ret = public.httpPost(cloudUrl, pdata)
+# if ret == '0':
+# return False
+# elif ret == '1':
+# return False
+# elif ret == '-1':
+# return False
+# else:
+# return False
+#
+# def __get_md5(self, s):
+# m = hashlib.md5()
+# m.update(s.encode('utf-8'))
+# return m.hexdigest()
+#
+#
+# if __name__ == "__main__":
+# public.WriteFile('/www/server/panel/data/webshell_data.json', json.dumps([]))
+# type = sys.argv[1]
+# path = sys.argv[2]
+# send = sys.argv[3]
+# os.chdir("/www/server/panel")
+# import sys
+# sys.path.append('class')
+# import public
+# aa = webshell_check()
+# print('Start scanning webshell')
+# start_time=time.time()
+# if type == 'dir':
+# data = aa.san_dir(path)
+# public.WriteFile('/www/server/panel/data/webshell_data.json', json.dumps(data))
+# localtime = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
+# if len(data) >= 1:
+# public.WriteLog('aaPanel built-in webshell killing','Killing the %s directory found the following Trojan %s'%(path,data))
+# else:
+# public.WriteLog('aaPanel built-in webshell killing','Checking and killing [ %s ] directory did not find any risks'%(path))
+# elif type=='site':
+# data = public.M('sites').where('name=?', (path,)).field('name,id,path').select()
+# localtime = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
+# if len(data) >= 1:
+# path = data[0]['path']
+# ##木马返回在这里
+# data = aa.send_san_dir(path, send)
+# if len(data) >= 1:
+# public.WriteLog('aaPanel built-in webshell killing', 'Killing the %s directory found the following Trojan %s' % (path, data))
+# else:
+# public.WriteLog('aaPanel built-in webshell killing','Checking and killing [ %s ] directory did not find any risks'%(path))
+#
+#
diff --git a/class/wxapp.py b/class/wxapp.py
index 9f98478a..229acf49 100644
--- a/class/wxapp.py
+++ b/class/wxapp.py
@@ -15,7 +15,7 @@ import json
import time
import binascii
import base64
-from BTPanel import session,cache
+from BTPanel import session,cache,request
class ScanLogin(object):
# 扫码登录面板
@@ -32,15 +32,25 @@ class ScanLogin(object):
self.app_path+'login.pl').split(':')
if time.time() - float(init_time) < 60:
return public.returnMsg(True, key)
+ session_id = public.get_session_id()
+ if cache.get(session_id) == 'True':
+ return public.returnMsg(True, 'Scan QRCORE successfully')
return public.returnMsg(False, '')
# 返回二维码地址
def login_qrcode(self, get):
- qrcode_str = 'https://app.bt.cn/app.html?&panel_url='+public.getPanelAddr()+'&v=' + public.GetRandomString(3)+'?login';
+ tid = public.GetRandomString(12)
+ qrcode_str = 'https://app.bt.cn/app.html?&panel_url='+public.getPanelAddr()+'&v=' + public.GetRandomString(3)+'?login&tid=' + tid
+ cache.set(tid,public.get_session_id(),360)
+ cache.set(public.get_session_id(),tid,360)
return public.returnMsg(True, qrcode_str)
# 设置登录状态
def set_login(self, get):
+ session_id = public.get_session_id()
+ if cache.get(session_id) == 'True':
+ return self.check_app_login(get)
+
if os.path.exists(self.app_path+"login.pl"):
data = public.readFile(self.app_path+'login.pl')
public.ExecShell('rm ' + self.app_path+"login.pl")
@@ -53,10 +63,32 @@ class ScanLogin(object):
session['username'] = userInfo['username']
cache.delete('panelNum')
cache.delete('dologin')
- public.WriteLog('TYPE_LOGIN', 'LOGIN_SUCCESS1',
- (public.GetMsg("WECHAT_SCAN_QRCORE"), public.GetClientIp()))
- return public.returnMsg(True, 'LOGIN_SUCCESS')
- return public.returnMsg(False, 'LOGIN_FAIL')
+ public.WriteLog('TYPE_LOGIN', 'LOGIN_SUCCESS',
+ ('WeChat scan code login', public.GetClientIp()+ ":" + str(request.environ.get('REMOTE_PORT'))))
+ login_type = 'data/app_login.pl'
+ public.writeFile(login_type,'True')
+ return public.returnMsg(True, 'login successful')
+ return public.returnMsg(False, 'Login failed')
+
+
+ #验证APP是否登录成功
+ def check_app_login(self,get):
+ session_id = public.get_session_id()
+ if cache.get(session_id) != 'True':
+ return public.returnMsg(False,'Wait for the app to scan the code and log in')
+ cache.delete(session_id)
+ userInfo = public.M('users').where("id=?",(1,)).field('id,username').find()
+ session['login'] = True
+ session['username'] = userInfo['username']
+ session['tmp_login'] = True
+ public.WriteLog('TYPE_LOGIN','APP scan code login, account: {}, login IP: {}'.format(userInfo['username'],public.GetClientIp()+ ":" + str(request.environ.get('REMOTE_PORT'))))
+ cache.delete('panelNum')
+ cache.delete('dologin')
+ sess_input_path = 'data/session_last.pl'
+ public.writeFile(sess_input_path,str(int(time.time())))
+ login_type = 'data/app_login.pl'
+ public.writeFile(login_type,'True')
+ return public.returnMsg(True,'login successful!')
class SelfModule():
'''
diff --git a/config/config.json b/config/config.json
index d5228ae4..ffa66a58 100644
--- a/config/config.json
+++ b/config/config.json
@@ -1 +1 @@
-{"product": "Linux panel", "setup_path": "/www/server", "openlitespeed_path": "/usr/local", "language": "English", "title": "aaPanel Linux panel", "brand": "aaPanel", "root_path": "/www", "template": "default", "logs_path": "/www/wwwlogs", "home": "http://www.bt.cn", "recycle_bin": true}
+{"product": "Linux panel", "setup_path": "/www/server", "openlitespeed_path": "/usr/local", "language": "English", "title": "aaPanel Linux panel", "brand": "aaPanel", "root_path": "/www", "template": "default", "logs_path": "/www/wwwlogs", "home": "https://console.aapanel.com", "recycle_bin": true}
diff --git a/data/node.json b/data/node.json
index cdf0becc..54be8df0 100644
--- a/data/node.json
+++ b/data/node.json
@@ -1,10 +1,46 @@
[
+ {
+ "protocol": "http://",
+ "address": "128.1.164.196",
+ "port": "80",
+ "ping": 500
+ },
{
"protocol": "http://",
"address": "103.224.251.67",
"port": "80",
"ping": 500
},
+ {
+ "protocol": "http://",
+ "address": "45.76.53.20",
+ "port": "80",
+ "ping": 500
+ },
+ {
+ "protocol": "http://",
+ "address": "dg2.bt.cn",
+ "port": "80",
+ "ping": 500
+ },
+ {
+ "protocol": "http://",
+ "address": "dg1.bt.cn",
+ "port": "80",
+ "ping": 500
+ },
+ {
+ "protocol": "http://",
+ "address": "125.88.182.172",
+ "port": "5880",
+ "ping": 500
+ },
+ {
+ "protocol": "http://",
+ "address": "123.129.198.197",
+ "port": "5880",
+ "ping": 500
+ },
{
"protocol": "http://",
"address": "119.188.210.21",
@@ -13,13 +49,13 @@
},
{
"protocol": "http://",
- "address": "45.32.116.160",
- "port": "80",
+ "address": "113.107.111.78",
+ "port": "5880",
"ping": 500
},
{
"protocol": "http://",
- "address": "128.1.164.196",
+ "address": "45.32.116.160",
"port": "80",
"ping": 500
}