1.Part of the log output function uses websocket to enhance the interactive experience

2.The page is displayed when the adjustment panel is wrong
3.App store add common plug-in display
4.Adjust the sessionid name to a non-fixed name
5.Panel CSRF defense mechanism covers panel websocket communication
6.Adjust the font size of the panel list
7.Adjust the panel pop-up window (add a close button to cancel the automatic closing time)
8.Optimize the front/back end of the file manager
9.Add the entrance of the MailServer Rspamd
10.Refactor the debug module
11.Other known bug fixes
This commit is contained in:
jose
2021-08-25 17:52:38 +08:00
parent 23dc81abf7
commit 4936a99e17
46 changed files with 5003 additions and 2365 deletions
+94 -20
View File
@@ -10,14 +10,79 @@
from gevent import monkey
monkey.patch_all()
import os,sys,ssl
if os.path.exists("/www/server/panel/class/BTPanel"):
os.system("rm -rf /www/server/panel/class/BTPanel")
os.chdir('/www/server/panel')
_PATH = '/www/server/panel'
os.chdir(_PATH)
if not 'class/' in sys.path:
sys.path.insert(0,'class/')
from BTPanel import app,sys,public
is_debug = os.path.exists('data/debug.pl')
if is_debug:
import pyinotify,time,logging,re
logging.basicConfig(level=logging.DEBUG,format="[%(asctime)s][%(levelname)s] - %(message)s")
logger = logging.getLogger()
class PanelEventHandler(pyinotify.ProcessEvent):
_exts = ['py','html','BT-Panel','so']
_explude_patts = [
re.compile('{}/plugin/.+'.format(_PATH)),
re.compile('{}/(tmp|temp)/.+'.format(_PATH))
]
_lsat_time = 0
def is_ext(self,filename):
fname = os.path.basename(filename)
result = fname.split('.')[-1] in self._exts
if not result: return False
for e in self._explude_patts:
if e.match(filename): return False
return True
def panel_reload(self,filename,in_type):
stime = time.time()
if stime - self._lsat_time < 2:
return
self._lsat_time = stime
logger.debug('File detected: {} -> {}'.format(filename,in_type))
fname = os.path.basename(filename)
if fname in ['task.py','BT-Task']:
logger.debug('Background task...')
public.ExecShell("{} {}/BT-Task".format(public.get_python_bin(),_PATH))
logger.debug('Background task started!')
else:
logger.debug('Restarting panel...')
public.ExecShell("bash {}/init.sh reload &>/dev/null &".format(_PATH))
def process_IN_CREATE(self, event):
if not self.is_ext(event.pathname): return
self.panel_reload(event.pathname,'[Create]')
def process_IN_DELETE(self,event):
if not self.is_ext(event.pathname): return
self.panel_reload(event.pathname,'[Delete]')
def process_IN_MODIFY(self,event):
if not self.is_ext(event.pathname): return
self.panel_reload(event.pathname,'[Modify]')
def debug_event():
logger.debug('Launch the panel in debug mode')
logger.debug('Listening port0.0.0.0:{}'.format(public.readFile('data/port.pl')))
event = PanelEventHandler()
watchManager = pyinotify.WatchManager()
mode = pyinotify.IN_CREATE | pyinotify.IN_DELETE | pyinotify.IN_MODIFY
watchManager.add_watch(_PATH, mode, auto_add=True, rec=True)
notifier = pyinotify.Notifier(watchManager, event)
notifier.loop()
if __name__ == '__main__':
pid_file = "{}/logs/panel.pid".format(_PATH)
if os.path.exists(pid_file):
public.ExecShell("kill -9 {}".format(public.readFile(pid_file)))
pid = os.fork()
if pid: sys.exit(0)
@@ -25,7 +90,7 @@ if __name__ == '__main__':
_pid = os.fork()
if _pid:
public.writeFile('logs/panel.pid',str(_pid))
public.writeFile(pid_file,str(_pid))
sys.exit(0)
sys.stdout.flush()
@@ -38,7 +103,7 @@ if __name__ == '__main__':
HOST = "0:0:0:0:0:0:0:0"
f.close()
is_debug = os.path.exists('data/debug.pl')
keyfile = 'ssl/privateKey.pem'
certfile = 'ssl/certificate.pem'
is_ssl = False
@@ -57,21 +122,30 @@ if __name__ == '__main__':
job.setDaemon(True)
job.start()
if is_debug:
ssl_context = None
if is_ssl: ssl_context=(certfile,keyfile)
app.run(host=HOST,port=PORT,threaded=True,debug=True,ssl_context=ssl_context)
if is_ssl:
ssl_context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
ssl_context.load_cert_chain(certfile=certfile,keyfile=keyfile)
ssl_context.options = (ssl.OP_NO_SSLv2 | ssl.OP_NO_SSLv3 | ssl.OP_NO_TLSv1 | ssl.OP_NO_TLSv1_1)
ssl_context.set_ciphers("ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE")
from gevent.pywsgi import WSGIServer
from geventwebsocket.handler import WebSocketHandler
if is_ssl:
http_server = WSGIServer((HOST, PORT), app,handler_class=WebSocketHandler,ssl_context = ssl_context)
else:
from gevent.pywsgi import WSGIServer
from geventwebsocket.handler import WebSocketHandler
http_server = WSGIServer((HOST, PORT), app,handler_class=WebSocketHandler)
if is_debug:
try:
dev = threading.Thread(target=debug_event)
dev.setDaemon(True)
dev.start()
except:
pass
http_server.serve_forever()
if is_ssl:
ssl_context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
ssl_context.load_cert_chain(certfile=certfile,keyfile=keyfile)
ssl_context.options |= (ssl.OP_NO_SSLv2 | ssl.OP_NO_SSLv3)
ssl_context.set_ciphers("ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE")
http_server = WSGIServer((HOST, PORT), app,handler_class=WebSocketHandler,ssl_context = ssl_context)
else:
http_server = WSGIServer((HOST, PORT), app,handler_class=WebSocketHandler)
http_server.serve_forever()
+492 -147
View File
@@ -6,9 +6,11 @@
# +-------------------------------------------------------------------
# | Author: hwliang <hwl@bt.cn>
# +-------------------------------------------------------------------
import logging
import sys
import json
import os
import threading
import time
import re
import uuid
@@ -18,7 +20,7 @@ if not 'class/' in sys.path:
sys.path.insert(0,'class/')
from flask import Config, Flask, session, render_template, send_file, request, redirect, g, make_response, \
render_template_string, abort, Response as Resp
render_template_string, abort, stream_with_context,Response as Resp
from cachelib import SimpleCache
from werkzeug.wrappers import Response
from flask_session import Session
@@ -32,8 +34,11 @@ import public
app = Flask(__name__, template_folder="templates/{}".format(public.GetConfigValue('template')))
Compress(app)
sockets = Sockets(app)
#import db
# 注册HOOK
hooks = {}
if not hooks:
public.check_hooks()
# import db
dns_client = None
app.config['DEBUG'] = os.path.exists('data/debug.pl')
@@ -52,12 +57,12 @@ if os.path.exists(basic_auth_conf):
app.secret_key = uuid.UUID(int=uuid.getnode()).hex[-12:]
local_ip = None
my_terms = {}
app.config['SESSION_MEMCACHED'] = SimpleCache()
app.config['SESSION_MEMCACHED'] = SimpleCache(1000,86400)
app.config['SESSION_TYPE'] = 'memcached'
app.config['SESSION_PERMANENT'] = True
app.config['SESSION_USE_SIGNER'] = True
app.config['SESSION_KEY_PREFIX'] = 'BT_:'
app.config['SESSION_COOKIE_NAME'] = "SESSIONID"
app.config['SESSION_COOKIE_NAME'] = public.md5(app.secret_key)
app.config['PERMANENT_SESSION_LIFETIME'] = 86400 * 30
Session(app)
@@ -130,8 +135,8 @@ if admin_path in admin_path_checks: admin_path = '/bt'
@app.before_request
def request_check():
g.request_time = time.time()
#路由和URI长度过滤
if len(request.path) > 128: return abort(403)
# 路由和URI长度过滤
if len(request.path) > 256: return abort(403)
if len(request.url) > 1024: return abort(403)
if request.path in ['/service_status']: return
@@ -143,13 +148,24 @@ def request_check():
if len(k) > 48: return abort(403)
if len(pdata[k]) > 256: return abort(403)
if session.get('debug') == 1: return
if app.config['BASIC_AUTH_OPEN']:
if request.path in ['/public', '/download', '/mail_sys', '/hook', '/down', '/check_bind',
'/get_app_bind_status']: return
auth = request.authorization
if not comm.get_sk(): return
if not auth: return send_authenticated()
tips = '_bt.cn'
if public.md5(auth.username.strip() + tips) != app.config['BASIC_AUTH_USERNAME'] \
or public.md5(auth.password.strip() + tips) != app.config['BASIC_AUTH_PASSWORD']:
return send_authenticated()
if not request.path in ['/safe', '/hook', '/public', '/mail_sys', '/down']:
ip_check = public.check_ip_panel()
if ip_check: return ip_check
if request.path.find('/static/') != -1 or request.path == '/code':
if not 'login' in session and not 'admin_auth' in session and not 'down' in session:
session.clear()
return abort(401)
domain_check = public.check_domain_panel()
if domain_check: return domain_check
@@ -158,15 +174,14 @@ def request_check():
if request.args.get('action') in not_networks:
return public.returnJson(False,'INIT_REQUEST_CHECK_LOCAL_ERR'),json_header
if app.config['BASIC_AUTH_OPEN']:
if request.path in ['/public','/download','/mail_sys','/hook','/down','/check_bind','/get_app_bind_status']: return
auth = request.authorization
if not comm.get_sk(): return
if not auth: return send_authenticated()
tips = '_bt.cn'
if public.md5(auth.username.strip() + tips) != app.config['BASIC_AUTH_USERNAME'] \
or public.md5(auth.password.strip() + tips) != app.config['BASIC_AUTH_PASSWORD']:
return send_authenticated()
if request.path in ['/','/site','/ftp','/database','/soft','/control','/firewall','/files','/xterm','/crontab','/config']:
licenes = 'data/licenes.pl'
if request.path in ['/'] and not os.path.exists(licenes):
return
# if not public.is_bind():
# return redirect('/bind',302)
#Flask 请求结束勾子
@app.teardown_request
@@ -180,9 +195,10 @@ def request_end(reques = None):
if g.api_request:
session.clear()
#Flask 404页面勾子
# Flask 404页面勾子
@app.errorhandler(404)
def notfound(e):
def error_404(e):
errorStr = '''<html>
<head><title>404 Not Found</title></head>
<body>
@@ -195,6 +211,36 @@ def notfound(e):
}
return Response(errorStr,status=404,headers=headers)
# Flask 500页面勾子
@app.errorhandler(500)
def error_500(e):
ss = '''404 Not Found: The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again.
During handling of the above exception, another exception occurred:'''
error_info = public.get_error_info().strip().split(ss)[-1].strip()
if error_info.find("`GLIBC_2.14'") != -1:
public.downloadFile('https://download.bt.cn/auth/libAuth_gcc_4.4.7_x{}.so'.format(public.get_sysbit()),'/www/server/panel/class/libAuth.x86-64.so')
error_info += "\n已尝试自动修复此问题,请刷新页面重试!"
request_info = '''REQUEST_DATE: {request_date}
PAN_VERSION: {panel_version}
OS_VERSION: {os_version}
REMOTE_ADDR: {remote_addr}
REQUEST_URI: {method} {full_path}
REQUEST_FORM: {request_form}
USER_AGENT: {user_agent}'''.format(
request_date = public.getDate(),
remote_addr = public.GetClientIp(),
method = request.method,
full_path = request.full_path,
request_form = request.form.to_dict(),
user_agent = request.headers.get('User-Agent'),
panel_version = public.get_panel_version(),
os_version = public.get_os_version()
)
result = public.readFile('/www/server/panel/BTPanel/templates/default/panel_error.html').format(error_title=error_info.split("\n")[-1],request_info = request_info,error_msg=error_info)
return Resp(result,500)
# ===================================Flask HOOK========================#
@@ -227,55 +273,6 @@ def xterm():
defs = ('get_host_list','get_host_find','modify_host','create_host','remove_host','set_sort','get_command_list','create_command','get_command_find','modify_command','remove_command')
return publicObject(ssh_host_admin,defs,None)
#@app.route('/webssh')
@sockets.route('/webssh')
def webssh(ws):
#宝塔终端连接
comReturn = comm.local()
if comReturn: return comReturn
#ws = request.environ.get('wsgi.websocket')
if not ws: return 'False'
get = ws.receive()
if not get: return
get = json.loads(get)
import ssh_terminal
sp = ssh_terminal.ssh_host_admin()
if 'host' in get:
ssh_info = {}
ssh_info['host'] = get['host'].strip()
if 'port' in get:
ssh_info['port'] = int(get['port'])
if 'username' in get:
ssh_info['username'] = get['username'].strip()
if 'password' in get:
ssh_info['password'] = get['password'].strip()
if 'pkey' in get:
ssh_info['pkey'] = get['pkey'].strip()
if get['host'] in ['127.0.0.1','localhost'] and 'port' not in ssh_info:
ssh_info = sp.get_ssh_info('127.0.0.1')
if not ssh_info: ssh_info = sp.get_ssh_info('localhost')
if not ssh_info: ssh_info = {"host":"127.0.0.1"}
ssh_info['port'] = public.get_ssh_port()
else:
ssh_info = sp.get_ssh_info('127.0.0.1')
if not ssh_info: ssh_info = sp.get_ssh_info('localhost')
if not ssh_info: ssh_info = {"host":"127.0.0.1"}
ssh_info['port'] = public.get_ssh_port()
if not ssh_info['host'] in ['127.0.0.1','localhost']:
if not 'username' in ssh_info:
ssh_info = sp.get_ssh_info(ssh_info['host'])
if not ssh_info:
ws.send(public.getMsg('SSH_LOGIN_ERR7'))
return
p = ssh_terminal.ssh_terminal()
p.run(ws,ssh_info)
del(p)
if not ws.closed:
ws.close()
return 'False'
@app.route('/site',methods=method_all)
def site(pdata = None):
@@ -483,21 +480,22 @@ def firewall(pdata = None):
'AddAcceptPort','DelAcceptPort','SetSshStatus','SetPing','SetSshPort','GetSshInfo')
return publicObject(firewallObject,defs,None,pdata)
@app.route('/ssh_security',methods=method_all)
def ssh_security(pdata = None):
#SSH安全
@app.route('/ssh_security', methods=method_all)
def ssh_security(pdata=None):
# SSH安全
comReturn = comm.local()
if comReturn: return comReturn
if request.method == method_get[0] and not pdata:
data = {}
data['lan'] = public.GetLan('firewall')
data['js_random'] = get_js_random()
return render_template( 'firewall.html',data=data)
return render_template('firewall.html', data=data)
import ssh_security
firewallObject = ssh_security.ssh_security()
defs = ('san_ssh_security', 'set_password', 'set_sshkey', 'stop_key', 'get_config',
'stop_password', 'get_key', 'return_ip', 'add_return_ip', 'del_return_ip', 'start_jian', 'stop_jian',
'get_jian', 'get_logs','set_root','stop_root')
'get_jian', 'get_logs','set_root','stop_root','start_auth_method','stop_auth_method','get_auth_method','check_so_file','get_so_file')
return publicObject(firewallObject, defs, None, pdata)
@@ -573,6 +571,20 @@ def abnormal(pdata=None):
)
return publicObject(dataObject, defs, None, pdata)
@app.route('/project/<mod_name>/<def_name>', methods=method_all)
def project(mod_name,def_name):
comReturn = comm.local()
if comReturn: return comReturn
from panelProjectController import ProjectController
project_obj = ProjectController()
defs = ('model',)
get = get_input()
get.action = 'model'
get.mod_name = mod_name
get.def_name = def_name
return publicObject(project_obj,defs,None,get)
@app.route('/files',methods=method_all)
def files(pdata = None):
#文件管理
@@ -662,7 +674,7 @@ def config(pdata = None):
return render_template( 'config.html',data=data)
import config
defs = (
'set_backup_notification','get_panel_ssl_status','set_file_deny', 'del_file_deny', 'get_file_deny',
'set_empty','set_backup_notification','get_panel_ssl_status','set_file_deny', 'del_file_deny', 'get_file_deny',
'get_httpd_access_log_format_parameter','set_httpd_format_log_to_website','get_httpd_access_log_format',
'del_httpd_access_log_format','add_httpd_access_log_format','get_nginx_access_log_format_parameter',
'set_format_log_to_website','get_nginx_access_log_format','del_nginx_access_log_format',
@@ -775,7 +787,7 @@ def plugin(pdata = None):
if comReturn: return comReturn
import panelPlugin
pluginObject = panelPlugin.panelPlugin()
defs = ('check_install_limit','set_score','get_score','update_zip','input_zip','export_zip','add_index','remove_index','sort_index',
defs = ('get_usually_plugin','check_install_limit','set_score','get_score','update_zip','input_zip','export_zip','add_index','remove_index','sort_index',
'install_plugin','uninstall_plugin','get_soft_find','get_index_list','get_soft_list','get_cloud_list',
'check_deps','flush_cache','GetCloudWarning','install','unInstall','getPluginList','getPluginInfo','get_make_args','add_make_args',
'getPluginStatus','setPluginStatus','a','getCloudPlugin','getConfigHtml','savePluginSort','del_make_args','set_make_args')
@@ -889,9 +901,7 @@ def login():
is_auth_path = False
if admin_path != '/bt' and os.path.exists(admin_path_file) and not 'admin_auth' in session:
is_auth_path = True
num_key = public.md5(public.GetClientIp() + '_auth_path')
# if not public.get_error_num(num_key,20): return public.returnMsg(False,'AUTH_FAILED1')
#登录输入验证
# 登录输入验证
if request.method == method_post[0]:
v_list = ['username','password','code','vcode','cdn_url']
for v in v_list:
@@ -949,14 +959,12 @@ def login():
referer_path = referer_tmp[-1]
if referer_path == '':
referer_path = referer_tmp[-2]
if route_path != '/'+referer_path:
public.set_error_num(num_key)
#return abort(404)
if route_path != '/' + referer_path:
data = {}
data['lan'] = public.getLan('close')
return render_template('autherr.html',data=data)
return render_template('autherr.html', data=data)
session['admin_auth'] = True
public.set_error_num(num_key,True)
comReturn = common.panelSetup().init()
if comReturn: return comReturn
@@ -1071,20 +1079,22 @@ def down(token=None,fname=None):
if not re.match(r"^\w+$",args.file_password):
return public.ReturnJson(False,'WRONG_PASSWD'),json_header
if re.match(r"^\d+$",args.file_password):
args.file_password += '.0'
args.file_password = str(int(args.file_password))
args.file_password += ".0"
if args.file_password != str(find['password']):
return public.ReturnJson(False,'WRONG_PASSWD'),json_header
session[token] = 1
session['down'] = True
else:
pdata = {
"to_path":"",
"src_path": find['filename'],
"password":True,
"filename":find['filename'].split('/')[-1],
"total":find['total'],
"token":find['token'],
"expire":public.format_date(times=find['expire'])
"to_path":"",
"src_path": find['filename'],
"password":True,
"filename":find['filename'].split('/')[-1],
"ps": find['ps'],
"total":find['total'],
"token":find['token'],
"expire":public.format_date(times=find['expire'])
}
session['down'] = True
return render_template('down.html',data = pdata)
@@ -1291,7 +1301,8 @@ def panel_other(name=None,fun = None,stype=None):
data = panelPHP.panelPHP(name).exec_php_script(args)
r_type = type(data)
if r_type == Response: return data
if r_type in [Response,Resp]:
return data
#处理响应
if stype == 'json': #响应JSON
@@ -1383,6 +1394,38 @@ Disallow: /
'''
return robots,{'Content-Type':'text/plain'}
@app.route('/rspamd', defaults={'path': ''},methods=method_all)
@app.route('/rspamd/<path:path>',methods=method_all)
def proxy_rspamd_requests(path):
comReturn = comm.local()
if comReturn: return comReturn
param = str(request.url).split('?')
param = "" if len(param) < 2 else param[-1]
import requests
headers = {}
for h in request.headers.keys():
headers[h] = request.headers[h]
if request.method == "GET":
if re.search("\.(js|css)$",path):
return send_file('/usr/share/rspamd/www/rspamd/'+path,conditional=True,add_etags=True)
if path == "/":
return send_file('/usr/share/rspamd/www/rspamd/',conditional=True,add_etags=True)
url = "http://127.0.0.1:11334/rspamd/" + path + "?" +param
for i in ['stat','auth','neighbours','list_extractors','list_transforms','graph','maps','actions','symbols','history','errors','check_selector','saveactions','savesymbols','getmap']:
if i in path:
url = "http://127.0.0.1:11334/" + path + "?" +param
req = requests.get(url, headers=headers,stream = True)
return Resp(stream_with_context(req.iter_content()), content_type = req.headers['content-type'])
else:
url = "http://127.0.0.1:11334/" + path
for i in request.form.keys():
data = '{}='.format(i)
# public.writeFile('/tmp/2',data+"\n","a+")
req = requests.post(url,data=data,headers=headers,stream = True)
return Resp(stream_with_context(req.iter_content()), content_type = req.headers['content-type'])
#==================================================#
@@ -1405,6 +1448,7 @@ def get_dir_down(filename,token,find):
pdata = files.files().GetDir(args)
pdata['token'] = token
pdata['ps'] = find['ps']
pdata['src_path'] = find['filename']
pdata['to_path'] = to_path
if find['expire'] < (time.time() + (86400 * 365 * 10)):
@@ -1455,34 +1499,19 @@ def get_phpmyadmin_dir():
class run_exec:
#模块访问对像
def run(self,toObject,defs,get):
# 模块访问对像
def run(self, toObject, defs, get):
result = None
for key in defs:
if key == get.action:
fun = 'toObject.'+key+'(get)'
if hasattr(get,'html') or hasattr(get,'s_module'):
result = eval(fun)
else:
result = eval(fun)
r_type = type(result)
if r_type == Resp: return result
result = public.GetJson(result),json_header
break
if not result:
result = public.ReturnJson(False,'ARGS_ERR'),json_header
if g.is_aes:
result = public.aes_encrypt(result[0],g.aes_key),json_header
else:
# if os.path.exists('pyenv/bin/python') and sys.version_info[0] == 3:
# if not os.path.exists('data/debug.pl'):
# x_token = request.headers.get('x-http-token')
# if x_token:
# aes_pwd = x_token[:8] + x_token[40:48]
# result = "BT-CRT"+public.aes_encrypt(result[0],aes_pwd),{'Content-Type':'text/plain; charset=utf-8'}
pass
return result
if not get.action in defs: return public.ReturnJson(False, 'ARGS_ERR'), json_header
result = getattr(toObject,get.action)(get)
if not hasattr(get, 'html') and not hasattr(get, 's_module'):
r_type = type(result)
if r_type in [Response,Resp]: return result
result = public.GetJson(result), json_header
if g.is_aes:
result = public.aes_encrypt(result[0], g.aes_key), json_header
return result
def check_csrf():
@@ -1497,29 +1526,39 @@ def check_csrf():
if cookie_token != session['request_token']: return False
return True
def publicObject(toObject,defs,action=None,get = None):
#模块访问前置检查
if 'request_token' in session and 'login' in session:
if not check_csrf(): return public.ReturnJson(False,'INIT_CSRF_ERR'),json_header
if not get: get = get_input()
if action: get.action = action
def publicObject(toObject, defs, action=None, get=None):
try:
# 模块访问前置检查
if 'request_token' in session and 'login' in session:
if not check_csrf(): return public.ReturnJson(False, 'INIT_CSRF_ERR'), json_header
if hasattr(get,'path'):
get.path = get.path.replace('//','/').replace('\\','/')
if get.path.find('./') != -1: return public.ReturnJson(False,'INIT_PATH_NOT_SAFE'),json_header
if not get: get = get_input()
if action: get.action = action
if hasattr(get, 'path'):
get.path = get.path.replace('//', '/').replace('\\', '/')
if get.path.find('./') != -1: return public.ReturnJson(False, 'INIT_PATH_NOT_SAFE'), json_header
if get.path.find('->') != -1:
get.path = get.path.split('->')[0].strip()
if hasattr(get,'sfile'):
get.sfile = get.sfile.replace('//','/').replace('\\','/')
if hasattr(get,'dfile'):
get.dfile = get.dfile.replace('//','/').replace('\\','/')
get.path = public.xssdecode(get.path)
if hasattr(get, 'filename'):
get.filename = public.xssdecode(get.filename)
if hasattr(toObject,'site_path_check'):
if not toObject.site_path_check(get): return public.ReturnJson(False,'INIT_ACCEPT_NOT'),json_header
return run_exec().run(toObject,defs,get)
if hasattr(get, 'sfile'):
get.sfile = get.sfile.replace('//', '/').replace('\\', '/')
get.sfile = public.xssdecode(get.sfile)
if hasattr(get, 'dfile'):
get.dfile = get.dfile.replace('//', '/').replace('\\', '/')
get.dfile = public.xssdecode(get.dfile)
if hasattr(toObject, 'site_path_check'):
if not toObject.site_path_check(get): return public.ReturnJson(False, 'INIT_ACCEPT_NOT'), json_header
return run_exec().run(toObject, defs, get)
except:
return error_500(None)
def check_login(http_token=None):
#检查是否登录面板
@@ -1569,8 +1608,8 @@ def get_pd():
tmp3 = public.to_string([60, 115, 112, 97, 110, 32, 99, 108, 97, 115, 115, 61, 34, 98,
116, 112, 114, 111, 45, 102, 114, 101, 101, 34, 32, 111, 110, 99, 108, 105, 99, 107,
61, 34, 98, 116, 46, 115, 111, 102, 116, 46, 114, 101, 110, 101, 119, 95, 112, 114,
111, 40, 41, 34, 32, 116, 105, 116, 108, 101, 61, 34, 28857, 20987, 21319, 32423,
21040, 21830, 19994, 29256, 34, 62, 20813, 36153, 29256, 60, 47, 115, 112, 97, 110, 62])
111, 40, 41, 34, 32, 116, 105, 116, 108, 101, 61, 34, 67,108,105,99,107,32,116,111,32,
103,101,116,32,80,82,79, 34, 62, 20813, 36153, 29256, 60, 47, 115, 112, 97, 110, 62])
elif tmp == -2:
tmp3 = public.to_string([60, 115, 112, 97, 110, 32, 99, 108, 97, 115, 115, 61, 34, 98, 116,
112, 114, 111, 45, 103, 114, 97, 121, 34, 62, 60, 115, 112, 97, 110, 32,
@@ -1609,8 +1648,8 @@ def get_pd():
tmp3 = public.to_string([60, 115, 112, 97, 110, 32, 99, 108, 97, 115, 115, 61, 34, 98, 116, 112,
114, 111, 45, 103, 114, 97, 121, 34, 32, 111, 110, 99, 108, 105, 99, 107,
61, 34, 98, 116, 46, 115, 111, 102, 116, 46, 114, 101, 110, 101, 119, 95, 112,
114, 111, 40, 41, 34, 32, 116, 105, 116, 108, 101, 61, 34, 28857,
20987, 21319, 32423, 21040, 19987, 19994, 29256, 34, 62, 70, 82,
114, 111, 40, 41, 34, 32, 116, 105, 116, 108, 101, 61, 34, 67,108,105,99,107,32,116,
111,32,103,101,116,32,80,82,79, 34, 62, 70, 82,
69, 69, 60, 47, 115, 112, 97, 110, 62])
else:
tmp3 = public.to_string([60, 115, 112, 97, 110, 32, 99, 108, 97, 115, 115, 61, 34, 98, 116, 108, 116,
@@ -1675,17 +1714,9 @@ def get_input():
for key in request.args.keys():
data[key] = str(request.args.get(key,''))
try:
# x_token = request.headers.get('x-http-token')
# if x_token:
# aes_pwd = x_token[:8] + x_token[40:48]
for key in request.form.keys():
if key in exludes: continue
data[key] = str(request.form.get(key,''))
# if x_token:
# if len(data[key]) > 5:
# if data[key][:6] == 'BT-CRT':
# data[key] = public.aes_decrypt(data[key][6:],aes_pwd)
data[key] = str(request.form.get(key, ''))
except:
try:
post = request.form.to_dict()
@@ -1728,6 +1759,320 @@ def check_token(data):
#======================公共方法区域END============================#
# --------------------- websocket START -------------------------- #
@sockets.route('/workorder_client')
def workorder_client(ws):
comReturn = comm.local()
if comReturn: return comReturn
get = ws.receive()
get = json.loads(get)
if not check_csrf_websocket(ws,get):
return
import panelWorkorder
toObject = panelWorkorder.panelWorkorder()
get = get_input()
toObject.client(ws, get)
@sockets.route('/ws_panel')
def ws_panel(ws):
'''
@name 面板接口ws入口
@author hwliang<2021-07-24>
@param ws<ws_parameter> websocket会话对像
@return void
'''
comReturn = comm.local()
if comReturn: return comReturn
get = ws.receive()
get = json.loads(get)
if not check_csrf_websocket(ws,get): return
while True:
pdata = ws.receive()
if pdata is '{}': break
data = json.loads(pdata)
get = public.to_dict_obj(data)
get._ws = ws
p = threading.Thread(target=ws_panel_thread,args=(get,))
p.start()
def ws_panel_thread(get):
'''
@name 面板管理ws线程
@author hwliang<2021-07-24>
@param get<dict> 请求参数
@return void
'''
if not hasattr(get, 'ws_callback'):
get._ws.send(public.getJson(public.return_status_code(1001, 'ws_callback')))
return
if not hasattr(get, 'mod_name'):
get._ws.send(public.getJson(public.return_status_code(1001, 'mod_name')))
return
if not hasattr(get, 'def_name'):
get._ws.send(public.getJson(public.return_status_code(1001, 'def_name')))
return
get.mod_name = get.mod_name.strip()
get.def_name = get.def_name.strip()
check_str = '{}{}'.format(get.mod_name, get.def_name)
if not re.match("^\w+$", check_str) or get.mod_name in ['public', 'common', 'db', 'db_mysql', 'downloadFile',
'jobs']:
get._ws.send(public.getJson(public.return_status_code(1000, '不安全的mod_name,def_name参数内容')))
return
if not hasattr(get, 'args'):
get._ws.send(public.getJson(public.return_status_code(1001, 'args')))
return
mod_file = '{}/{}.py'.format(public.get_class_path(), get.mod_name)
if not os.path.exists(mod_file):
get._ws.send(public.getJson(public.return_status_code(1000, '指定模块{}不存在'.format(get.mod_name))))
return
_obj = public.get_script_object(mod_file)
if not _obj:
get._ws.send(public.getJson(public.return_status_code(1000, '指定模块{}不存在'.format(get.mod_name))))
return
_cls = getattr(_obj, get.mod_name)
if not _cls:
get._ws.send(
public.getJson(public.return_status_code(1000, '{}模块中没有找到{}对像'.format(get.mod_name, get.mod_name))))
return
_def = getattr(_cls(), get.def_name)
if not _def:
get._ws.send(
public.getJson(public.return_status_code(1000, '{}对像中没有找到{}方法'.format(get.mod_name, get.def_name))))
return
result = {
'callback': get.ws_callback,
'result': _def(public.to_dict_obj(get.args))
}
get._ws.send(public.getJson(result))
@sockets.route('/ws_project')
def ws_project(ws):
'''
@name 项目管理ws入口
@author hwliang<2021-07-24>
@param ws<ws_parameter> websocket会话对像
@return void
'''
comReturn = comm.local()
if comReturn: return comReturn
get = ws.receive()
get = json.loads(get)
if not check_csrf_websocket(ws,get): return
from panelProjectController import ProjectController
project_obj = ProjectController()
while True:
pdata = ws.receive()
if pdata in '{}': break
get = public.to_dict_obj(json.loads(pdata))
get._ws = ws
p = threading.Thread(target=ws_project_thread, args=(project_obj, get))
p.start()
def ws_project_thread(_obj, get):
'''
@name 项目管理ws线程
@author hwliang<2021-07-24>
@param _obj<ProjectController> 项目管理控制器对像
@param get<dict> 请求参数
@return void
'''
if not hasattr(get, 'ws_callback'):
get._ws.send(public.getJson(public.return_status_code(1001, 'ws_callback')))
return
result = {
'callback': get.ws_callback,
'result': _obj.model(get)
}
get._ws.send(public.getJson(result))
import subprocess
sock_pids = {}
@sockets.route('/sock_shell')
def sock_shell(ws):
'''
@name 执行指定命令,实时输出命令执行结果
@author hwliang<2021-07-19>
@return void
示例:
p = new WebSocket('ws://192.168.1.247:8888/sock_shell')
p.send('ping www.bt.cn -c 100')
'''
comReturn = comm.local()
if comReturn:
ws.send(str(comReturn))
return
kill_closed()
get = ws.receive()
get = json.loads(get)
if not check_csrf_websocket(ws,get): return
t = None
try:
while True:
cmdstring = ws.receive()
if cmdstring in ['stop', 'error'] or not cmdstring:
break
t = threading.Thread(target=sock_recv, args=(cmdstring, ws))
t.start()
kill_closed()
except:
kill_closed()
def kill_closed():
'''
@name 关闭已关闭的连接
@author hwliang<2021-07-24>
@return void
'''
global sock_pids
import psutil
pids = psutil.pids()
keys = sock_pids.copy().keys()
for pid in keys:
logging.debug("PID: {} , sock_stat: {}".format(pid, sock_pids[pid].closed))
if not sock_pids[pid].closed: continue
if pid in pids:
try:
p = psutil.Process(pid)
for cp in p.children():
cp.kill()
p.kill()
logging.debug("killed: {}".format(pid))
sock_pids.pop(pid)
except:
pass
else:
sock_pids.pop(pid)
def sock_recv(cmdstring, ws):
global sock_pids
try:
p = subprocess.Popen(cmdstring + " 2>&1", close_fds=True, shell=True, bufsize=4096, stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
sock_pids[p.pid] = ws
kill_closed()
while p.poll() is None:
ws.send(p.stdout.readline().decode())
ws.send(p.stdout.read().decode())
except:
kill_closed()
@app.route('/close_sock_shell', methods=method_all)
def close_sock_shell():
'''
@name 关闭指定命令
@author hwliang<2021-07-19>
@param cmdstring<string> 完整命令行
@return dict
示例:
$.post('/close_sock_shell',{cmdstring:'ping www.bt.cn -c 100'})
'''
comReturn = comm.local()
if comReturn: return comReturn
args = get_input()
cmdstring = args.cmdstring.strip()
skey = public.md5(cmdstring)
pid = cache.get(skey)
if not pid:
return json.dumps(public.return_data(False, [], error_msg='指定sock已终止!')), json_header
os.kill(pid, 9)
cache.delete(skey)
return json.dumps(public.return_data(True, '操作成功!')), json_header
def check_csrf_websocket(ws,args):
'''
@name 检查websocket是否被csrf攻击
@author hwliang<2021-07-24>
@param ws<WebSocket> websocket对像
@return void
'''
if g.is_aes: return True
is_success = True
if not 'x-http-token' in args:
is_success = False
if is_success:
if session['request_token_head'] != args['x-http-token']:
is_success = False
# if is_success:
# cookie_token = request.cookies.get('request_token')
# if cookie_token != session['request_token']:
# is_success = False
if not is_success:
ws.send('token error')
return False
return True
@sockets.route('/webssh')
def webssh(ws):
# 宝塔终端连接
comReturn = comm.local()
if comReturn:
ws.send(str(comReturn))
return
if not ws: return 'False'
get = ws.receive()
if not get: return
get = json.loads(get)
if not check_csrf_websocket(ws,get):
return
import ssh_terminal
sp = ssh_terminal.ssh_host_admin()
if 'host' in get:
ssh_info = {}
ssh_info['host'] = get['host'].strip()
if 'port' in get:
ssh_info['port'] = int(get['port'])
if 'username' in get:
ssh_info['username'] = get['username'].strip()
if 'password' in get:
ssh_info['password'] = get['password'].strip()
if 'pkey' in get:
ssh_info['pkey'] = get['pkey'].strip()
if get['host'] in ['127.0.0.1', 'localhost'] and 'port' not in ssh_info:
ssh_info = sp.get_ssh_info('127.0.0.1')
if not ssh_info: ssh_info = sp.get_ssh_info('localhost')
if not ssh_info: ssh_info = {"host": "127.0.0.1"}
ssh_info['port'] = public.get_ssh_port()
else:
ssh_info = sp.get_ssh_info('127.0.0.1')
if not ssh_info: ssh_info = sp.get_ssh_info('localhost')
if not ssh_info: ssh_info = {"host": "127.0.0.1"}
ssh_info['port'] = public.get_ssh_port()
if not ssh_info['host'] in ['127.0.0.1', 'localhost']:
if not 'username' in ssh_info:
ssh_info = sp.get_ssh_info(ssh_info['host'])
if not ssh_info:
ws.send('The specified host information is not found, please add it again!')
return
p = ssh_terminal.ssh_terminal()
p.run(ws, ssh_info)
del (p)
if not ws.closed:
ws.close()
return 'False'
# --------------------- websocket END -------------------------- #
+83 -2
View File
@@ -1815,7 +1815,19 @@ html .menu .menu_exit:hover {
.bt-w-con {
margin-left: 170px;
position: relative
position: relative;
padding: 7px 15px;
}
.bt-w-con .bt-w-item{
height: 100%;
display:none;
}
.bt-w-con .bt-w-item.active{
display:block;
}
.taskcon{
height: 500px;
overflow: auto;
}
.mes_channel .bt-w-con {
margin-left: 110px;
@@ -3115,7 +3127,6 @@ html .menu .menu_exit:hover {
vertical-align: middle;
padding: 5px 10px;
height: 40px;
font-size: 12.5px;
box-sizing: border-box;
}
.table>tbody{
@@ -9934,6 +9945,16 @@ select[name="network-io"]{
margin-left: 5px;
vertical-align: middle;
}
.command_output_pre{
white-space: pre-line;
background: rgb(51, 51, 51);
color: rgb(236, 236, 236);
box-sizing: border-box;
margin: 0;
border: none;
border-radius: 1px;
}
/*批量创建站点end*/
.custom_layer .layui-layer-content .tab-body .tab-con{
@@ -10288,3 +10309,63 @@ background:url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iODIiIGhlaWdodD0iODIiIHh
margin-right: 10px;
}
/* 企业版支付end */
.commonly_software{
height: 28px;
line-height: 28px;
margin-bottom: 15px;
color:#666;
}
.commonly_software .commonly_software_title{
display: inline-block;
padding-left: 5px;
padding-right: 15px;
}
.commonly_software .commonly_software_list{
display: inline-block;
}
.commonly_software .commonly_software_list .item{
display: inline-block;
margin-right: 10px;
padding: 0 10px;
cursor: pointer;
border-radius: 3px;
transition: all 500ms;
position: relative;
}
.commonly_software .commonly_software_list .item:hover{
color: #20A53A;
background-color: #f5f5f5;
}
.commonly_software .commonly_software_list .item img{
max-width: 22px;
margin-right: 5px;
image-rendering: -webkit-optimize-contrast;
vertical-align: middle;
margin-top: -2.5px;
}
.commonly_software .commonly_software_list .item span{
display: inline-block;
font-size: 12px;
color:#666;
}
.pro_introduce_content .item{
position: relative;
}
.pro_introduce_content .item .success_icon{
position: absolute;
display: block;
left: 0;
top: 50%;
margin-top: -8px;
width: 6px;
height: 12px;
border: solid #20a532;
border-width: 0 1.5px 1.5px 0;
transform: rotate(45deg);
}
.pro_introduce_content .item span:nth-child(2){
padding-left: 14px;
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

+163 -167
View File
@@ -883,177 +883,173 @@ $(".dropdown ul li a").click(function(){
})
//备份
function toBackup(type){
var sMsg = "";
switch(type){
case 'sites':
sMsg = lan.crontab.backup_site;
sType = "sites";
break;
case 'databases':
sMsg = lan.crontab.backup_database;
sType = "databases";
break;
case 'logs':
sMsg = lan.crontab.backup_log;
sType = "sites";
break;
case 'path':
sMsg = lan.crontab.dir_bak;
sType = "sites";
break;
}
var data='type='+sType
$.post('/crontab?action=GetDataList',data,function(rdata){
$(".planname input[name='name']").attr('readonly','true').css({"background-color":"#f6f6f6","color":"#666"});
if(type != 'path'){
var sOpt = "",sOptBody = '';
if(rdata.data.length == 0){
$(".planname input[name='name']").val('');
layer.msg(lan.public.list_empty,{icon:2})
return
}
for(var i=0;i<rdata.data.length;i++){
if(i==0){
$(".planname input[name='name']").val(sMsg+'['+rdata.data[i].name+']');
}
sOpt += '<li><a role="menuitem" tabindex="-1" href="javascript:;" value="'+rdata.data[i].name+'">'+rdata.data[i].name+'['+rdata.data[i].ps+']</a></li>';
}
sOptBody ='<div class="dropdown pull-left mr20">\
<button class="btn btn-default dropdown-toggle" type="button" id="backdata" data-toggle="dropdown" style="width:auto">\
<b id="sName" val="'+rdata.data[0].name+'">'+rdata.data[0].name+'['+rdata.data[0].ps+']</b> <span class="caret"></span>\
</button>\
<ul class="dropdown-menu" role="menu" aria-labelledby="backdata">\
<li><a role="menuitem" tabindex="-1" href="javascript:;" value="ALL">'+lan.public.all+'</a></li>\
'+sOpt+'\
</ul>\
</div>'
}else{
$(".planname input[name='name']").val(sMsg+'[/www/wwwroot/]');
sOptBody = '<div class="info-r" style="display: inline-block;float: left;margin-right: 25px;"><input id="inputPath" class="bt-input-text mr5" type="text" name="path" value="/www/wwwroot/" placeholder="'+lan.crontab.dir_bak+'" style="width:208px;height:33px;"><span class="glyphicon glyphicon-folder-open cursor" onclick="bt.select_path(\'inputPath\')"></span></div>'
setCookie('default_dir_path','/www/wwwroot/');
setCookie('path_dir_change','/www/wwwroot/');
setInterval(function(){
if(getCookie('path_dir_change') != getCookie('default_dir_path')){
var path_dir_change = getCookie('path_dir_change')
$(".planname input").val(lan.crontab.dir_bak+'['+getCookie('path_dir_change')+']');
setCookie('default_dir_path',path_dir_change);
}
},500);
}
var orderOpt = ''
for (var i=0;i<rdata.orderOpt.length;i++){
orderOpt += '<li><a role="menuitem" tabindex="-1" href="javascript:;" value="'+rdata.orderOpt[i].value+'">'+rdata.orderOpt[i].name+'</a></li>'
}
var sBody = sOptBody + '<div class="textname pull-left mr20">'+lan.crontab.backup_to+'</div>\
<div class="dropdown planBackupTo pull-left mr20">\
<button class="btn btn-default dropdown-toggle" type="button" id="excode" data-toggle="dropdown" style="width:auto;">\
<b val="localhost">'+lan.crontab.disk+'</b> <span class="caret"></span>\
</button>\
<ul class="dropdown-menu" role="menu" aria-labelledby="excode">\
<li><a role="menuitem" tabindex="-1" href="javascript:;" value="localhost">'+lan.crontab.disk+'</a></li>\
'+ orderOpt +'\
</ul>\
</div>\
<div class="textname pull-left mr20">'+lan.crontab.save_new+'</div><div class="plan_hms pull-left mr20 bt-input-text">\
<span><input type="number" name="save" id="save" value="3" maxlength="4" max="100" min="1"></span>\
<span class="name">'+lan.crontab.copies+'</span>\
</div>';
if (type == 'sites' || type == 'path' || type == 'databases') {
$.post('/config?action=get_settings',data,function(rdata){
var messageChannelDom = '', messageChannelBtnText = '', channelInitVal = ''
if(rdata.user_mail.user_name && rdata.dingding.dingding) {
messageChannelBtnText = 'All'
channelInitVal= 'user_name,dingding'
messageChannelDom = '<li><a role="menuitem" tabindex="-1" href="javascript:;" value="dingding,mail">All</a></li><li><a role="menuitem" tabindex="-1" href="javascript:;" value="dingding">钉钉</a></li><li><a role="menuitem" tabindex="-1" href="javascript:;" value="mail">Email</a></li>'
} else if(!rdata.user_mail.user_name && !rdata.dingding.dingding){
messageChannelBtnText = 'No Data'
channelInitVal= ''
messageChannelDom += '<li><a role="menuitem" tabindex="-1" href="javascript:;" value="">No Data</a></li>'
} else if(rdata.dingding.dingding) {
messageChannelBtnText = '钉钉'
channelInitVal= 'dingding'
messageChannelDom += '<li><a role="menuitem" tabindex="-1" href="javascript:;" value="dingding">钉钉</a></li>'
} else if(rdata.user_mail.user_name) {
messageChannelBtnText = 'Email'
channelInitVal= 'mail'
messageChannelDom += '<li><a role="menuitem" tabindex="-1" href="javascript:;" value="mail">Email</a></li>'
}
sBody += '<p class="clearfix plan">\
<div class="typename pull-left mr20 text-right" style="font-size: 14px;">Backup reminder</div>\
<div class="dropdown planBackupTo pull-left mr20" style="display:'+ (type === 'logs'?'none':'inline-block') +'" id="notice">\
<button class="btn btn-default dropdown-toggle" type="button" id="excode" data-toggle="dropdown" style="width:180px;">\
<b val="0">No notice</b> <span class="caret"></span>\
</button>\
<ul class="dropdown-menu" role="menu" aria-labelledby="excode">\
<li><a role="menuitem" tabindex="-1" href="javascript:;" value="0">No notice</a></li>\
<li><a role="menuitem" tabindex="-1" href="javascript:;" value="1">Notify on failure</a></li>\
</ul>\
</div>\
var sMsg = "";
switch(type){
case 'sites':
sMsg = lan.crontab.backup_site;
sType = "sites";
break;
case 'databases':
sMsg = lan.crontab.backup_database;
sType = "databases";
break;
case 'logs':
sMsg = lan.crontab.backup_log;
sType = "sites";
break;
case 'path':
sMsg = lan.crontab.dir_bak;
sType = "sites";
break;
}
var data='type='+sType
$.post('/crontab?action=GetDataList',data,function(rdata){
$(".planname input[name='name']").attr('readonly','true').css({"background-color":"#f6f6f6","color":"#666"});
if(type != 'path'){
var sOpt = "",sOptBody = '';
if(rdata.data.length == 0){
layer.msg(lan.public.list_empty,{icon:2})
return
}
for(var i=0;i<rdata.data.length;i++){
if(type === 'logs'){
$(".planname input[name='name']").val(sMsg+'[ALL]');
}else{
if(i ==0){
$(".planname input[name='name']").val(sMsg+'['+rdata.data[i].name+']');
}
}
sOpt += '<li><a role="menuitem" tabindex="-1" href="javascript:;" value="'+rdata.data[i].name+'">'+rdata.data[i].name+'['+rdata.data[i].ps+']</a></li>';
}
sOptBody ='<div class="dropdown pull-left mr20">\
<button class="btn btn-default dropdown-toggle" type="button" id="backdata" data-toggle="dropdown" style="width:auto">\
<b id="sName" val="'+ (type === 'logs'?'ALL':rdata.data[0].name) +'">'+ (type === 'logs'?'ALL':(rdata.data[0].name +'['+rdata.data[0].ps+']')) +'</b> <span class="caret"></span>\
</button>\
<ul class="dropdown-menu" role="menu" aria-labelledby="backdata">\
<li><a role="menuitem" tabindex="-1" href="javascript:;" value="ALL">'+lan.public.all+'</a></li>\
'+sOpt+'\
</ul>\
</div>'
}else{
$(".planname input[name='name']").val(sMsg+'[/www/wwwroot/]');
sOptBody = '<div class="info-r" style="display: inline-block;float: left;margin-right: 25px;"><input id="inputPath" class="bt-input-text mr5" type="text" name="path" value="/www/wwwroot/" placeholder="'+lan.crontab.dir_bak+'" style="width:208px;height:33px;"><span class="glyphicon glyphicon-folder-open cursor" onclick="ChangePath(&quot;inputPath&quot;)"></span></div>'
setCookie('default_dir_path','/www/wwwroot/');
setCookie('path_dir_change','/www/wwwroot/');
setInterval(function(){
if(getCookie('path_dir_change') != getCookie('default_dir_path')){
var path_dir_change = getCookie('path_dir_change')
$(".planname input").val(lan.crontab.dir_bak+'['+getCookie('path_dir_change')+']');
setCookie('default_dir_path',path_dir_change);
}
},500);
}
var orderOpt = ''
for (var i=0;i<rdata.orderOpt.length;i++){
orderOpt += '<li><a role="menuitem" tabindex="-1" href="javascript:;" value="'+rdata.orderOpt[i].value+'">'+rdata.orderOpt[i].name+'</a></li>'
}
var save_num = 3;
if(type === 'logs'){
$('#cycle b').attr('val','day').text(lan.crontab.daily);
$('.planweek').hide();
$('[name="hour"]').val(0);
$('[name="minute"]').val(1);
// $('#implement').parent().after('<div class="clearfix plan" id="logs_tips"><span class="typename controls c4 pull-left f14 text-right mr20">提示</span><div style="line-height:34px">根据网络安全法第二十一条规定,网络日志应留存不少于六个月。</div></div>')
save_num = 180;
}else{
$('#logs_tips').remove();
}
var sBody = sOptBody + '<div class="textname pull-left mr20" style="display:'+ (type === 'logs'?'none':'inline-block') +'">'+lan.crontab.backup_to+'</div>\
<div class="dropdown planBackupTo pull-left mr20" style="display:'+ (type === 'logs'?'none':'inline-block') +'" id="saveAddServerDiskToLocal">\
<button class="btn btn-default dropdown-toggle" type="button" id="excode" data-toggle="dropdown" style="width:auto;">\
<b val="localhost">'+lan.crontab.disk+'</b> <span class="caret"></span>\
</button>\
<ul class="dropdown-menu" role="menu" aria-labelledby="excode">\
<li><a role="menuitem" tabindex="-1" href="javascript:;" value="localhost">'+lan.crontab.disk+'</a></li>\
'+ orderOpt +'\
</ul>\
</div>\
<div class="textname pull-left mr20">'+lan.crontab.save_new+'</div><div class="plan_hms pull-left mr20 bt-input-text">\
<span><input type="number" name="save" id="save" value="'+save_num+'" maxlength="4" max="100" min="1"></span>\
</div>';
if (type == 'sites' || type == 'path' || type == 'databases') {
$.post('/config?action=get_settings',data,function(rdata){
var messageChannelDom = '', messageChannelBtnText = '', channelInitVal = ''
if(rdata.user_mail.user_name && rdata.dingding.dingding) {
messageChannelBtnText = 'ALL'
channelInitVal= 'user_name,dingding'
messageChannelDom = '<li><a role="menuitem" tabindex="-1" href="javascript:;" value="dingding,mail">ALL</a></li><li><a role="menuitem" tabindex="-1" href="javascript:;" value="dingding">钉钉</a></li><li><a role="menuitem" tabindex="-1" href="javascript:;" value="mail">邮箱</a></li>'
} else if(!rdata.user_mail.user_name && !rdata.dingding.dingding){
messageChannelBtnText = 'No Data'
channelInitVal= ''
messageChannelDom += '<li><a role="menuitem" tabindex="-1" href="javascript:;" value="">No Data</a></li>'
} else if(rdata.dingding.dingding) {
messageChannelBtnText = '钉钉'
channelInitVal= 'dingding'
messageChannelDom += '<li><a role="menuitem" tabindex="-1" href="javascript:;" value="dingding">钉钉</a></li>'
} else if(rdata.user_mail.user_name) {
messageChannelBtnText = 'Email'
channelInitVal= 'mail'
messageChannelDom += '<li><a role="menuitem" tabindex="-1" href="javascript:;" value="mail">Email</a></li>'
}
sBody += '<p class="clearfix plan">\
<div class="textname pull-left mr20" style="width: 120px;text-align: right; font-size: 14px;">Backup reminder</div>\
<div class="dropdown planBackupTo pull-left mr20" style="display:'+ (type === 'logs'?'none':'inline-block') +'" id="notice">\
<button class="btn btn-default dropdown-toggle" type="button" id="excode" data-toggle="dropdown" style="width:180px;">\
<b val="0">No notice</b> <span class="caret"></span>\
</button>\
<ul class="dropdown-menu" role="menu" aria-labelledby="excode">\
<li><a role="menuitem" tabindex="-1" href="javascript:;" value="0">No notice</a></li>\
<li><a role="menuitem" tabindex="-1" href="javascript:;" value="1">Notify on failure</a></li>\
</ul>\
</div>\
<div class="textname pull-left mr20" style="font-size: 14px;display:none;" id="messageChannelBox">Notification</div>\
<div class="dropdown planBackupTo pull-left mr20" style="display:none;" id="notice_channel">\
<button class="btn btn-default dropdown-toggle" type="button" id="excode" data-toggle="dropdown" style="width:auto;">\
<b val="'+channelInitVal+'">'+ messageChannelBtnText +'</b> <span class="caret"></span>\
</button>\
<ul class="dropdown-menu" role="menu" aria-labelledby="excode">\
'+messageChannelDom+'\
</ul>\
</div>\
</div>\
<a role="menuitem" tabindex="-1" href="javascript:;" onclick="open_three_channel_auth()" value="0" style="color: #20a53a;">Set notifications</a>\
<span id="selnoticeBox" onclick="selSave_local()"><input type="checkbox" value="0" style="margin-left: 20px;margin-right: 10px;" id="save_local">Keep local backup</span>\
</p>';
if(type == 'sites' || type == "path") {
sBody += '<p class="clearfix plan">\
<div class="typename pull-left mr20 text-right" style="font-size: 14px;">'+lan.crontab.exclusion_rule+'</div>\
<div class="dropdown planBackupTo pull-left mr20">\
<span><textarea style=" height: 120px;width:500px;line-height:22px;" class="bt-input-text" type="text" name="sBody" id="exclude" placeholder="'+lan.crontab.exclusion_rule_tips+'\ndata/config.php\nstatic/upload\n *.log\n"></textarea></span>\
</div>\
</p>';
}
$("#implement").html(sBody);
getselectname();
})
}else{
$("#implement").html('<div></div>');
sBody += '<p class="clearfix plan">\
<div class="typename pull-left mr20 text-right" style="font-size: 14px;">'+lan.crontab.exclusion_rule+'</div>\
<div class="dropdown planBackupTo pull-left mr20">\
<span><textarea style=" height: 120px;width:500px;line-height:22px;" class="bt-input-text" type="text" name="sBody" id="exclude" placeholder="'+lan.crontab.exclusion_rule_tips+'\ndata/config.php\nstatic/upload\n *.log\n"></textarea></span>\
</div>\
</p>';
$("#implement").html(sBody);
}
$("#implement").on('click','.dropdown ul li a',function(ev){
var val = $(this).attr('value');
console.log(val)
$("#sName").attr({'value':val}).text($(this).text())
$(".planname input[name='name']").val(sMsg+'['+val+']');
});
if(type == "path"){
$('.planname input').attr('readonly',false).removeAttr('style');
}
$("#exclude").focus(function(){
var _this = $(this), tips = _this.attr('placeholder'),
tipss = ''+lan.crontab.exclusion_rule_tips+'</br>data/config.php</br>static/upload</br> *.log</br>';
_this.attr('placeholder', '');
var loadT = layer.tips(tipss, _this, {
tips: [1, '#20a53a'],
time: 0,
area: _this[0].clientWidth + 'px'
});
$(this).one('blur', function () {
$(this).attr('placeholder', tips);
layer.close(loadT);
});
});
});
<div class="textname pull-left mr20" style="font-size: 14px;display:none;" id="messageChannelBox">Notification</div>\
<div class="dropdown planBackupTo pull-left mr20" style="display:none;" id="notice_channel">\
<button class="btn btn-default dropdown-toggle" type="button" id="excode" data-toggle="dropdown" style="width:auto;">\
<b val="'+channelInitVal+'">'+ messageChannelBtnText +'</b> <span class="caret"></span>\
</button>\
<ul class="dropdown-menu" role="menu" aria-labelledby="excode">\
'+messageChannelDom+'\
</ul>\
</div>\
</div>\
<a role="menuitem" tabindex="-1" href="javascript:;" onclick="open_three_channel_auth()" value="0" style="color: #20a53a;">Set notifications</a>\
<span id="selnoticeBox" onclick="selSave_local()" style="display:none;"><input type="checkbox" value="0" style="margin-left: 20px;margin-right: 10px;" id="save_local">Keep local backup</span>\
</p>';
if(type == 'sites' || type == "path") {
sBody += '<p class="clearfix plan">\
<div class="textname pull-left mr20" style="width: 120px;text-align: right; font-size: 14px;">'+lan.crontab.exclusion_rule+'</div>\
<div class="dropdown planBackupTo pull-left mr20">\
<span><textarea style=" height: 100px;width:300px;line-height:22px;" class="bt-input-text" type="text" name="sBody" id="exclude" placeholder="'+lan.crontab.exclusion_rule_tips+'\ndata/config.php\nstatic/upload\n *.log\n"></textarea></span>\
</div>\
</p>';
}
$("#implement").html(sBody);
getselectnoticename();
})
} else {
$("#implement").html('<div></div>');
sBody += '<p class="clearfix plan">\
<div class="textname pull-left mr20" style="width: 120px;text-align: right; font-size: 14px;">'+lan.crontab.exclusion_rule+'</div>\
<div class="dropdown planBackupTo pull-left mr20">\
<span><textarea style=" height: 100px;width:300px;line-height:22px;" class="bt-input-text" type="text" name="sBody" id="exclude" placeholder="'+lan.crontab.exclusion_rule_tips+'\ndata/config.php\nstatic/upload\n *.log\n"></textarea></span>\
</div>\
</p>';
$("#implement").html(sBody);
getselectname();
}
$("#implement").on('click','.dropdown ul li a',function(ev){
var sName = $("#sName").attr("val");
if(!sName) return;
$(".planname input[name='name']").val(sMsg+'['+sName+']');
});
if(type == "path"){
$('.planname input').attr('readonly',false).removeAttr('style');
}
});
}
//下拉菜单名称
+6 -5
View File
@@ -298,12 +298,14 @@ var bt_file = {
if(that.uploading){
layer.confirm('Do you want to cancel the upload of files? It need to delete the uploaded files manually. Continue?',{title:'Cancel file upload',icon:0},function(indexs){
$('.upload_file_body').addClass('active').html('<span>Please drag the file here</span>')
$('.file_upload_info').css('display','none').siblings().css('display','block')
that.filesList.length = 0
});
return false;
}else{
$('.upload_file_body').addClass('active').html('<span>Please drag the file here</span>')
that.filesList.length = 0
$('.file_upload_info').css('display','none').siblings().css('display','block')
return false;
}
},
@@ -609,7 +611,6 @@ var bt_file = {
that.loadT.close();
}
})
$('.file_search_config').addClass('hide')
e.stopPropagation();
})
$('.search_path_views').on('click','.file_search_config label',function(e){
@@ -4416,13 +4417,13 @@ var bt_file = {
});
return (paths+path).replace('//','/');
},
/**
* @descripttion 取扩展名
* @return: 返回扩展名
*/
get_ext_name:function(fileName){
var extArr = fileName.split(".");
var extArr = fileName.split(".");
var exts = ["folder", "folder-unempty", "sql", "c", "cpp", "cs", "flv", "css", "js", "htm", "html", "java", "log", "mht", "php", "url", "xml", "ai", "bmp", "cdr", "gif", "ico", "jpeg", "jpg", "JPG", "png", "psd", "webp", "ape", "avi", "mkv", "mov", "mp3", "mp4", "mpeg", "mpg", "rm", "rmvb", "swf", "wav", "webm", "wma", "wmv", "rtf", "docx", "fdf", "potm", "pptx", "txt", "xlsb", "xlsx", "7z", "cab", "iso", "rar", "zip", "gz", "bt", "file", "apk", "bookfolder", "folder-empty", "fromchromefolder", "documentfolder", "fromphonefolder", "mix", "musicfolder", "picturefolder", "videofolder", "sefolder", "access", "mdb", "accdb", "fla", "doc", "docm", "dotx", "dotm", "dot", "pdf", "ppt", "pptm", "pot", "xls", "csv", "xlsm"];
var extLastName = extArr[extArr.length - 1];
for(var i=0; i<exts.length; i++){
@@ -4457,7 +4458,7 @@ var bt_file = {
/**
* @descripttion: 路径过滤
* @return: 无返回值
*/
*/
path_check:function(path) {
path = path.replace('//', '/');
if (path === '/') return path;
@@ -4524,7 +4525,7 @@ var bt_file = {
if (callback) callback(res);
});
})
},
/**
+1 -5
View File
File diff suppressed because one or more lines are too long
+268 -46
View File
@@ -1386,7 +1386,7 @@ var aceEditor = {
},
// 获取文件列表
get_file_dir_list:function(obj,callback){
var loadT = layer.msg('正在获取文件内容,请稍后...',{time: 0,icon: 16,shade: [0.3, '#000']}),_this = this;
var loadT = layer.msg('Getting file content, please wait...',{time: 0,icon: 16,shade: [0.3, '#000']}),_this = this;
if(obj['p'] === undefined) obj['p'] = 1;
if(obj['showRow'] === undefined) obj['showRow'] = 200;
if(obj['sort'] === undefined) obj['sort'] = 'name';
@@ -2219,6 +2219,28 @@ function ajax_encrypt(request){
}
}
// function ajaxSetup() {
// var my_headers = {};
// var request_token_ele = document.getElementById("request_token_head");
// if (request_token_ele) {
// var request_token = request_token_ele.getAttribute('token');
// if (request_token) {
// my_headers['x-http-token'] = request_token
// }
// }
// request_token_cookie = getCookie('request_token');
// if (request_token_cookie) {
// my_headers['x-cookie-token'] = request_token_cookie
// }
//
// if (my_headers) {
// $.ajaxSetup({
// headers: my_headers,
// // dataFilter: ajax_decrypt,
// // beforeSend: ajax_encrypt
// });
// }
// }
function ajaxSetup() {
var my_headers = {};
var request_token_ele = document.getElementById("request_token_head");
@@ -2234,12 +2256,65 @@ function ajaxSetup() {
}
if (my_headers) {
$.ajaxSetup({
$.ajaxSetup({
headers: my_headers,
error: function(jqXHR, textStatus, errorThrown) {
if(!jqXHR.responseText) return;
if(typeof(String.prototype.trim) === "undefined"){
String.prototype.trim = function()
{
return String(this).replace(/^\s+|\s+$/g, '');
};
}
error_key = 'We need to make sure this has a favicon so that the debugger does';
error_find = jqXHR.responseText.indexOf(error_key)
if(jqXHR.status == 500 && (jqXHR.responseText.indexOf('An error occurred while the panel was running') != -1 || error_find != -1)){
// if(jqXHR.responseText.indexOf('请先绑定宝塔帐号!') != -1){
// bt.pub.bind_btname(function(){
// window.location.reload();
// });
// return;
// }
if(error_find != -1){
var error_body = jqXHR.responseText.split('<!--')[2].replace('-->','')
var tmp = error_body.split('During handling of the above exception, another exception occurred:')
error_body = tmp[tmp.length-1];
var error_msg = '<div>\
<h3 style="margin-bottom: 10px;">出错了面板运行时发生错误</h3>\
<pre style="height:635px;word-wrap: break-word;white-space: pre-wrap;margin: 0 0 0px">'+error_body.trim()+'</pre>\
<ul class="help-info-text">\
<li style="list-style: none;"><b>很抱歉面板运行时意外发生错误请尝试按以下顺序尝试解除此错误</b></li>\
<li style="list-style: none;">1[首页]右上角点击修复面板并退出面板重新登录</li>\
<li style="list-style: none;">2如上述尝试未能解除此错误请截图此窗口到宝塔论坛发贴寻求帮助, 论坛地址<a class="btlink" href="https://www.bt.cn/bbs" target="_blank">https://www.bt.cn/bbs</a></li>\
</ul>\
</div>'
}else{
var error_msg = jqXHR.responseText;
}
$(".layui-layer-padding").parents('.layer-anim').remove();
$(".layui-layer-shade").remove();
setTimeout(function(){
layer.open({
title: false,
content: error_msg,
closeBtn:2,
area: ["1000px","800px"],
btn:false,
shadeClose:false,
shade:0.3,
success:function(){
$('pre').scrollTop(100000000000)
}
});
},100)
}
}
// dataFilter: ajax_decrypt,
// beforeSend: ajax_encrypt
});
}
}
}
ajaxSetup();
@@ -3171,20 +3246,12 @@ function ActionTask() {
})
}
function RemoveTask(b) {
var a = layer.msg(lan.public.the_del, {
icon: 16,
time: 0,
shade: [0.3, "#000"]
});
$.post("/files?action=RemoveTask", "id=" + b, function(c) {
layer.close(a);
layer.msg(c.msg, {
icon: c.status ? 1 : 5
});
}).error(function() {
layer.msg(lan.bt.task_close, { icon: 1 });
});
function RemoveTask(id) {
var loadT = bt.load(lan.public.the_del);
bt.send('RemoveTask','files/RemoveTask',{id:id},function(res){
bt.msg(res)
reader_realtime_tasks()
})
}
function GetTaskList(a) {
@@ -3692,30 +3759,183 @@ function getSpeed(sele) {
});
}
//消息盒子
function messagebox() {
layer.open({
type: 1,
title: lan.bt.task_title,
area: "750px",
closeBtn: 2,
shadeClose: false,
content: '<div class="bt-form">\
<div class="bt-w-main">\
<div class="bt-w-menu">\
<p class="bgw" id="taskList" onclick="tasklist()">' + lan.bt.task_list + '(<span class="task_count">0</span>)</p>\
<p onclick="remind()">' + lan.bt.task_msg + '(<span class="msg_count">0</span>)</p>\
<p onclick="execLog()">' + lan.public.exec_log + '</p>\
</div>\
<div class="bt-w-con pd15">\
<div class="taskcon"></div>\
</div>\
</div>\
</div>'
});
$(".bt-w-menu p").click(function() {
$(this).addClass("bgw").siblings().removeClass("bgw");
});
tasklist();
function messagebox(){
layer.open({
type: 1,
title: lan.bt.task_title,
area: "680px",
closeBtn: 2,
shadeClose: false,
content: '<div class="bt-form">' +
'<div class="bt-w-main">' +
'<div class="bt-w-menu">' +
'<p class="bgw">'+ lan.bt.task_list +' (<span id="taskNum">0</span>)</p>' +
'<p>'+ lan.bt.task_msg +' (<span id="taskCompleteNum">0</span>)</p>' +
'<p>'+lan.public.exec_log+'</p>' +
'</div>' +
'<div class="bt-w-con pd15">' +
'<div class="bt-w-item active" id="command_install_list"><ul class="cmdlist"></ul></div>'+
'<div class="bt-w-item" id="messageContent"></div>'+
'<div class="bt-w-item"><pre id="execLog" class="command_output_pre" style="height: 530px;"></pre></div>'+
'</div>' +
'</div>' +
'</div>',
success: function(layers,indexs){
$(layers).find('.bt-w-menu p').on('click',function(){
var index = $(this).index()
$(this).addClass('bgw').siblings().removeClass('bgw');
$(layers).find('.bt-w-con .bt-w-item:eq('+ index +')').addClass('active').siblings().removeClass('active');
switch (index) {
case 0:
reader_realtime_tasks()
break;
case 1:
reader_message_list()
break;
case 2:
var loadT = bt.load('正在获取执行日志,请稍后...')
bt.send('GetExecLog','files/GetExecLog',{},function(res){
loadT.close();
var exec_log = $('#execLog');
console.log(exec_log)
exec_log.html(res)
exec_log[0].scrollTop = exec_log[0].scrollHeight
})
break;
}
})
reader_realtime_tasks()
setTimeout(function(){
reader_realtime_tasks()
},1000)
reader_message_list()
}
});
}
function get_message_data(page,callback){
if(typeof page === "function") callback = page,page = 1;
var loadT = bt.load('正在获取消息列表,请稍后...');
bt.send("getData","data/getData",{
tojs:'reader_message_list',
table:'tasks',
result:'2,4,6,8',
limit:'11',
search:'1',
p:page
},function(res){
loadT.close();
if(callback) callback(res);
})
}
function reader_message_list(page){
get_message_data(page,function(res){
var html = "",f = false,task_count = 0;
for (var i = 0; i < res.data.length; i++) {
var item = res.data[i];
if (item.status !== '1') {
task_count ++;
continue;
}
html += '<tr><td><div class="titlename c3">' + item.name + '</span><span class="rs-status">【' + lan.bt.task_ok + '】<span><span class="rs-time">' + lan.bt.time + (item.end - item.start) + lan.bt.s + '</span></div></td><td class="text-right c3">' + item.addtime + '</td></tr>'
}
var con = '<div class="divtable"><table class="table table-hover">\
<thead><tr><th>'+ lan.bt.task_name + '</th><th class="text-right">' + lan.bt.task_time + '</th></tr></thead>\
<tbody id="remind">'+ html + '</tbody>\
</table></div>\
<div class="mtb15" style="height:32px">\
<div class="pull-left buttongroup" style="display:none;"><button class="btn btn-default btn-sm mr5 rs-del" disabled="disabled">'+ lan.public.del + '</button><button class="btn btn-default btn-sm mr5 rs-read" disabled="disabled">' + lan.bt.task_tip_read + '</button><button class="btn btn-default btn-sm">' + lan.bt.task_tip_all + '</button></div>\
<div id="taskPage" class="page"></div>\
</div>';
var msg_count = res.page.match(/\'Pcount\'>.+<\/span>/)[0].replace(/[^0-9]/ig, "");
$("#taskCompleteNum").text(parseInt(msg_count) - task_count);
$("#messageContent").html(con);
$("#taskPage").html(res.page);
})
}
function get_realtime_tasks(callback){
bt.send('GetTaskSpeed','files/GetTaskSpeed',{},function(res){
if(callback) callback(res)
})
}
var initTime = null,messageBoxWssock = null;
function reader_realtime_tasks(refresh){
get_realtime_tasks(function(res){
var command_install_list = $('#command_install_list'),
loading = 'data:image/gif;base64,R0lGODlhDgACAIAAAHNzcwAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQFDgABACwAAAAAAgACAAACAoRRACH5BAUOAAEALAQAAAACAAIAAAIChFEAIfkEBQ4AAQAsCAAAAAIAAgAAAgKEUQAh+QQJDgABACwAAAAADgACAAACBoyPBpu9BQA7',
html = '',
message = res.msg,
task = res.task;
$('#taskNum').html(typeof res.task === "undefined"?0:res.task.length);
if(typeof res.task === "undefined"){
html = '<div style="padding:5px;">'+lan.bt.task_not_list+'</div><div style="position: fixed;bottom: 15px;">' + lan.public.task_long_time_not_exec + '</div>'
command_install_list.html(html)
}else{
var shell = '', message_split = message.split("\n");
for(var j = 0; j < message_split.length; j++) {
shell += message_split[j] + "</br>";
}
if(command_install_list.find('li').length){
if(command_install_list.find('li').length > res.task.length) command_install_list.find('li:eq(0)').remove();
if(task[0].status !== '0' && !command_install_list.find('pre').length) command_install_list.find('li:eq(0)').append('<pre class=\'cmd command_output_pre\'>' + shell +'</pre>')
messageBoxWssock.el = command_install_list.find('pre');
}else{
for (var i = 0; i < task.length; i++) {
var item = task[i], task_html = '', del_task = '<a style="color:green" onclick="RemoveTask(' + item.id + ')" href="javascript:;">'+ lan.public.del +'</a>',loading_img = "<img src='"+ loading +"'/>";
if(item.status === '-1' && item.type === 'download'){
task_html = "<div class='line-progress' style='width:" + message.pre + "%'></div><span class='titlename'>" + item.name + "<a style='margin-left:130px;'>" + (ToSize(message.used) + "/" + ToSize(message.total)) + "</a></span><span class='com-progress'>" + message.pre + "%</span><span class='state'>"+ lan.bt.task_downloading +" "+ loading_img +" | "+ del_task +"</span>";
}else{
task_html += '<span class="titlename">' + item.name + '</span>';
task_html += '<span class="state">';
if(item.status !== "-1"){
task_html += lan.bt.task_sleep + ' | ' + del_task;
}else{
var is_scan = item.name.indexOf("扫描") !== -1;
task_html += (is_scan?lan.bt.task_scan:lan.bt.task_install) + ' ' + loading_img + ' | ' + del_task;
}
task_html += "</span>";
if(item.type !== "download" && item.status === "-1"){
task_html += '<pre class=\'cmd command_output_pre\'>' + shell +'</pre>'
}
}
html += "<li>"+ task_html +"</li>";
}
command_install_list.find('ul').append(html);
}
if(task[0].status === '0'){
setTimeout(function(){
reader_realtime_tasks(true)
},100)
}
if(command_install_list.find('pre').length){
var pre = command_install_list.find('pre')
pre.scrollTop(pre[0].scrollHeight)
}
if(!refresh){
messageBoxWssock = bt_tools.command_line_output({
el:'#command_install_list .command_output_pre',
area:['100%','200px'],
shell:'tail -n 100 -f /tmp/panelExec.log',
message:function(res){
if(res.indexOf('|-Successify ---Script execution completed---') > -1){
setTimeout(function(){
reader_realtime_tasks(true)
reader_message_list()
},100)
}
}
}
);
}
}
})
}
//取执行日志
@@ -3986,7 +4206,9 @@ var Term = {
},
//连接服务器成功
on_open:function(ws_event){
Term.send(JSON.stringify(Term.ssh_info || {}))
var http_token = $("#request_token_head").attr('token');
Term.send(JSON.stringify({'x-http-token':http_token}))
if(JSON.stringify(Term.ssh_info) !== '{}') Term.send(JSON.stringify(Term.ssh_info))
// Term.term.FitAddon.fit();
// Term.resize();
// var f_path = $("#fileInputPath").val();
@@ -4166,10 +4388,10 @@ var Term = {
// },
run: function (ssh_info) {
if($("#panel_debug").attr("data") == 'True') {
layer.msg('Error: unable to create websocket connection, please close 【Developer mode】 on the settings page!',{icon:2,time:5000});
return;
}
// if($("#panel_debug").attr("data") == 'True') {
// layer.msg('Error: unable to create websocket connection, please close 【Developer mode】 on the settings page!',{icon:2,time:5000});
// return;
// }
var loadT = layer.msg('It is loading the files required by the terminal. Please wait...', { icon: 16, time: 0, shade: 0.3 });
loadScript([
"/static/js/xterm.js"
+24 -10
View File
@@ -517,9 +517,7 @@ var bt = {
}
if (callback) callback(rdata);
}).error(function(e, f) {
if (callback) callback('error');
});
})
}
},
linux_format_param: function(param) {
@@ -551,11 +549,11 @@ var bt = {
var btnObj = {
title: config.title ? config.title : false,
shadeClose: config.shadeClose ? config.shadeClose : true,
closeBtn: config.closeBtn ? config.closeBtn : 0,
closeBtn: config.closeBtn ? config.closeBtn : 2,
scrollbar: true,
shade: 0.3,
shade: 0.3
};
if (!config.hasOwnProperty('time')) config.time = 2000;
if (!config.hasOwnProperty('time')) config.time = 0;
if (typeof config.msg == 'string' && bt.contains(config.msg, 'ERROR')) config.time = 0;
if (config.hasOwnProperty('icon')) {
@@ -572,7 +570,7 @@ var bt = {
if (config.msg) msg += config.msg;
if (config.msg_error) msg += config.msg_error;
if (config.msg_solve) msg += config.msg_solve;
if(config.status) $.extend(btnObj,{closeBtn:0,time:2000});
layer.msg(msg, btnObj);
},
confirm: function(config, callback, callback1) {
@@ -3886,7 +3884,10 @@ bt.soft = {
bt.soft.pro.get_product_discount_by(config.pid,function(rdata){
//rdata = {"36": {"discount": 1, "did": 0, "price": 3564, "name": "正常", "sprice": 3564}, "24": {"discount": 1, "did": 0, "price": 2376, "name": "正常", "sprice": 2376}, "12": {"discount": 1, "did": 0, "price": 1188, "name": "正常", "sprice": 1188}, "6": {"discount": 1, "did": 0, "price": 594, "name": "正常", "sprice": 594}, "3": {"discount": 1, "did": 0, "price": 297, "name": "正常", "sprice": 297}, "1": {"discount": 1, "did": 0, "price": 99, "name": "正常", "sprice": 99}, "pid": "100000045"};
if(typeof rdata.status === "boolean"){
if(!rdata.status) return false;
if(!rdata.status) {
bt.msg({status:false, msg:rdata.msg})
return false;
}
}
that.product_cache[config.pid] = rdata;
setTimeout(function(){ delete that.product_cache[config.pid] },60000);
@@ -4020,7 +4021,8 @@ bt.soft = {
if (rdata.status === false){
bt.set_cookie('force', 1);
if (soft) soft.flush_cache();
layer.msg(rdata.msg, { icon: 2 });
// layer.msg(rdata.msg, { icon: 2 });
bt.msg({status:false,msg:rdata.msg})
return;
}
config.pay = parseInt($('#libPay-mode .pay-cycle-btn.active').data('condition'));
@@ -4484,7 +4486,8 @@ bt.soft = {
if (rdata.status === false) {
bt.set_cookie('force', 1);
if (soft) soft.flush_cache();
layer.msg(rdata.msg, { icon: 2 });
// layer.msg(rdata.msg, { icon: 2 });
bt.msg({status:false,msg:rdata.msg})
return;
}
$(".pay-wx").html('');
@@ -5833,6 +5836,17 @@ bt.site = {
if (callback) callback(rdata);
})
},
get_site_error_logs: function (siteName, callback) {
var loading = bt.load();
bt.send('get_site_errlog', 'site/get_site_errlog', {
siteName: siteName
}, function (rdata) {
loading.close();
if (rdata.status !== true) rdata.msg = '';
if (rdata.msg == '') rdata.msg = lan.public_backup.no_log;
if (callback) callback(rdata);
})
},
get_site_ssl: function(siteName, callback) {
var loadT = bt.load(lan.site.the_msg);
bt.send('GetSSL', 'site/GetSSL', { siteName: siteName }, function(rdata) {
+151 -82
View File
@@ -68,7 +68,7 @@ var site_table = bt_tools.table({
$('.site-menu p:eq(8)').click();
},500);
}},
{title:lan.site.operate,type:'group',width:118,align:'right',group:[
{title:lan.site.operate,type:'group',width:119,align:'right',group:[
{
title:'WAF',
event:function(row,index,ev,key,that){
@@ -302,7 +302,7 @@ var site_table = bt_tools.table({
if(checked) param[$(this).attr('name')] = checked?1:0;
})
if(callback) callback(param);
},"<div class='options bacth_options'><span class='item'><label><input type='checkbox' name='ftp'><span>FTP</span></label></span><span class='item'><label><input type='checkbox' name='database'><span>" + lan.site.database + "</span></label></span><span class='item'><label><input type='checkbox' name='path'><span>" + lan.site.root_dir + "</span></label></span></div>");
},"<div class='options bacth_options'><span class='item'><label><input type='checkbox' name='ftp'><span>FTP</span></label></span><span class='item'><label><input type='checkbox' name='database'><span>" + lan.site.database + "</span></label></span><span class='item' ><label style='margin-right:0'><input type='checkbox' name='path'><span>" + lan.site.root_dir + "</span></label></span></div>");
}
}
],
@@ -662,54 +662,9 @@ var site = {
})
}, 1000);
},
// add_site: function(callback) {
// bt.site.add_site(function(rdata) {
// if (rdata.siteStatus) {
// if(callback) callback(rdata);
// //site.get_list();
// var html = '';
// var ftpData = '';
// if (rdata.ftpStatus) {
// var list = [];
// list.push({ title: lan.site.user, val: rdata.ftpUser });
// list.push({ title: lan.site.password, val: rdata.ftpPass });
// var item = {};
// item.title = lan.site.ftp;
// item.list = list;
// ftpData = bt.render_ps(item);
// }
// var sqlData = '';
// if (rdata.databaseStatus) {
// var list = [];
// list.push({ title: lan.site.database_name, val: rdata.databaseUser });
// list.push({ title: lan.site.user, val: rdata.databaseUser });
// list.push({ title: lan.site.password, val: rdata.databasePass });
// var item = {};
// item.title = lan.site.database_txt;
// item.list = list;
// sqlData = bt.render_ps(item);
// }
// if (ftpData == '' && sqlData == '') {
// bt.msg({ msg: lan.site.success_txt, icon: 1 })
// } else {
// bt.open({
// type: 1,
// area: '600px',
// title: lan.site.success_txt,
// closeBtn: 2,
// shadeClose: false,
// content: "<div class='success-msg'><div class='pic'><img src='/static/img/success-pic.png'></div><div class='suc-con'>" + ftpData + sqlData + "</div></div>"
// });
// if ($(".success-msg").height() < 150) {
// $(".success-msg").find("img").css({ "width": "150px", "margin-top": "30px" });
// }
// }
// } else {
// bt.msg(rdata);
// }
// })
// },
/**
* @description 添加站点
*/
add_site: function (callback) {
var add_web = bt_tools.form({
data:{}, //用于存储初始值和编辑时的赋值内容
@@ -1032,6 +987,11 @@ var site = {
},
yes:function(indexs){
var formValue = !web_tab.active?add_web.$get_form_value():bath_web.$get_form_value();
console.log(formValue)
if(formValue.webname === ''){
bt.msg({status:false,msg:'The website domain name cannot be empty!'})
return false;
}
if(!web_tab.active){ // 创建站点
var loading = bt.load();
add_web.$get_form_element(true);
@@ -1866,6 +1826,7 @@ var site = {
var pdata = {
php_version: $("select[name='php_version']").val(),
composer_args: $("select[name='composer_args']").val(),
composer_cmd: $("input[name='composer_cmd']").val(),
repo: $("select[name='repo']").val(),
path: $("input[name='composer_path']").val(),
user: $("select[name='composer_user']").val()
@@ -1939,6 +1900,11 @@ var site = {
'<option value="update">Update</option>' +
'</select>' +
'</div></div>' +
'<div class="line"><span style="width: 105px;" class="tname">Extra commands</span><div class="info-r">' +
'<input style="width:275px;" class="bt-input-text" id="composer_cmd" name="composer_cmd" placeholder="App name or full Composer command" type="text" value="" />' +
'</div></div>' +
'<div class="line"><span style="width: 105px;" class="tname">Source</span><div class="info-r">' +
'<select class="bt-input-text" name="repo" style="width:180px;">' +
'<option value="repos.packagist">Official(packagist.org)</option>' +
@@ -1961,6 +1927,7 @@ var site = {
'<li>UserThe default user www, unless your website is run with root privileges, it is not recommended to use the root user to execute composer</li>' +
'<li>Sourcesource of composer</li>' +
'<li>ParametersInstall (install dependent package), Update (upgrade dependent package), please select as needed</li>' +
'<li>Extra commands: If this is empty, it will be executed according to the conf in composer.json, Supported fill in the complete composer command</li>' +
'<li>PHP versionThe PHP version used to execute composer, it is recommended to try the default, if the installation fails, try to choose another PHP version</li>' +
'<li>Composer versionComposer version, you can click [Upgrade Composer] on the right to upgrade Composer to the latest stable version</li>' +
'</ul>'
@@ -3427,17 +3394,104 @@ var site = {
o.title = o.name;
versions.push(o);
}
// var data = {
// items: [
// {
// title: 'PHP版本',
// name: 'versions',
// value: sdata.phpversion,
// type: 'select',
// items: versions ,
// ps:'<input class="bt-input-text other-version" style="margin-right: 10px;width:300px;color: #000;" type="text" value="'+sdata.php_other+'" placeholder="连接配置,如:1.1.1.1:9001或unix:/tmp/php.sock" />'
// },
// {
// text: '切换',
// name: 'btn_change_phpversion',
// type: 'button',
// callback: function(pdata) {
// var other = $('.other-version').val();
// if(pdata.versions == 'other' && other == ''){
// layer.msg('自定义PHP版本时,PHP连接配置不能为空');
// $('.other-version').focus();
// return;
// }
// bt.site.set_phpversion(web.name, pdata.versions, other, function(ret) {
// if (ret.status) {
// var versions = $('[name="versions"]').val();
// versions = versions.slice(0, versions.length - 1) + '.' + versions.slice(-1);
// if (versions == '0.0') versions = '静态';
// site_table.$refresh_table_list(true);
// site.reload()
// setTimeout(function() {
// bt.msg(ret);
// }, 1000);
// }else{
// bt.msg(ret);
// }
// })
// }
// }
// ]
// }
// var _form_data = bt.render_form_line(data);
// var _html = $(_form_data.html);
// _html.append(bt.render_help([lan.site.switch_php_help1, lan.site.switch_php_help2, lan.site.switch_php_help3]));
// $('#webedit-con').append(_html);
// bt.render_clicks(_form_data.clicks);
// $('#webedit-con').append('<div class="user_pw_tit" style="margin-top: 2px;padding-top: 11px;border-top: #ccc 1px dashed;"><span class="tit">' + lan.site.session_off + '</span><span class="btswitch-p ml5" style="margin-bottom: 0;display: inline-block;vertical-align: middle;"><input class="btswitch btswitch-ios" id="session_switch" type="checkbox"><label class="btswitch-btn session-btn" for="session_switch" ></label></span></div><div class="user_pw" style="margin-top: 10px; display: block;"></div>' + bt.render_help([lan.site.independent_storage]));
// function get_session_status() {
// var loading = bt.load('Getting session status...');
// bt.send('get_php_session_path', 'config/get_php_session_path', { id: web.id }, function(tdata) {
// loading.close();
// $('#session_switch').prop("checked", tdata);
// })
// };
// get_session_status()
// $('#session_switch').click(function() {
// var val = $(this).prop('checked');
// bt.send('set_php_session_path', 'config/set_php_session_path', { id: web.id, act: val ? 1 : 0 }, function(rdata) {
// get_session_status();
// bt.msg(rdata)
// });
// })
var data = {
items: [
{ title: lan.site.php_ver, name: 'versions', value: sdata.phpversion, type: 'select', items: versions },
{
text: lan.site.switch,
title: 'PHP version',
name: 'versions',
value: sdata.phpversion,
type: 'select',
items: versions ,
ps:'<input class="bt-input-text other-version" style="margin-right: 10px;width:300px;color: #000;" type="text" value="'+sdata.php_other+'" placeholder="e.g:1.1.1.1:9001 or unix:/tmp/php.sock" />'
},
{
text: 'Switch',
name: 'btn_change_phpversion',
type: 'button',
callback: function(pdata) {
bt.site.set_phpversion(web.name, pdata.versions, function(ret) {
if (ret.status) site.reload(8)
bt.msg(ret);
var other = $('.other-version').val();
if(pdata.versions == 'other' && other == ''){
layer.msg('When customizing the PHP version, the PHP connection configuration cannot be empty');
$('.other-version').focus();
return;
}
bt.site.set_phpversion(web.name, pdata.versions, other, function(ret) {
if (ret.status) {
var versions = $('[name="versions"]').val();
versions = versions.slice(0, versions.length - 1) + '.' + versions.slice(-1);
if (versions == '0.0') versions = 'Static';
site_table.$refresh_table_list(true);
site.reload()
setTimeout(function() {
bt.msg(ret);
}, 1000);
}else{
bt.msg(ret);
}
})
}
}
@@ -3445,13 +3499,30 @@ var site = {
}
var _form_data = bt.render_form_line(data);
var _html = $(_form_data.html);
_html.append(bt.render_help([lan.site.switch_php_help1, lan.site.switch_php_help2, lan.site.switch_php_help3]));
_html.append(bt.render_help(['Select the version according to your program requirements', 'Try not to use PHP5.2 unless you have to, as this can reduce your server security', 'PHP7 does not support the MySQL extension. The default installation is mysqli and mysql-pdo',"[Customize] You can customize the PHP connection information by selecting the available PHP connection configuration","[Customize] Currently only support NGINX","Support TCP or UNIX configuration. Example: 192.168.1.25:9001 or unix:/tmp/php8.sock"]));
$('#webedit-con').append(_html);
bt.render_clicks(_form_data.clicks);
$('#webedit-con').append('<div class="user_pw_tit" style="margin-top: 2px;padding-top: 11px;border-top: #ccc 1px dashed;"><span class="tit">' + lan.site.session_off + '</span><span class="btswitch-p ml5" style="margin-bottom: 0;display: inline-block;vertical-align: middle;"><input class="btswitch btswitch-ios" id="session_switch" type="checkbox"><label class="btswitch-btn session-btn" for="session_switch" ></label></span></div><div class="user_pw" style="margin-top: 10px; display: block;"></div>' + bt.render_help([lan.site.independent_storage]));
if(sdata.phpversion != 'other'){
$('#webedit-con').append('<div class="user_pw_tit" style="margin-top: 2px;padding-top: 11px;border-top: #ccc 1px dashed;"><span class="tit">' + lan.site.session_off + '</span><span class="btswitch-p"style="display: inline-flex;"><input class="btswitch btswitch-ios" id="session_switch" type="checkbox"><label class="btswitch-btn session-btn" for="session_switch" ></label></span></div><div class="user_pw" style="margin-top: 10px; display: block;"></div>' +
bt.render_help(['When enabled, session files will be stored in a separate folder, not in a common storage location with other sites', 'Do not enable this option if you are saving sessions to caches such as memcache/redis in your PHP configuration']));
}
if(sdata.phpversion != 'other'){
$('.other-version').hide();
}
setTimeout(function(){
$('select[name="versions"]').change(function(){
var phpversion = $(this).val();
console.log(phpversion);
if(phpversion == 'other'){
$('.other-version').show();
}else{
$('.other-version').hide();
}
});
},500);
function get_session_status() {
var loading = bt.load('Getting session status...');
var loading = bt.load('Please wait while getting session status');
bt.send('get_php_session_path', 'config/get_php_session_path', { id: web.id }, function(tdata) {
loading.close();
$('#session_switch').prop("checked", tdata);
@@ -3461,9 +3532,11 @@ var site = {
$('#session_switch').click(function() {
var val = $(this).prop('checked');
bt.send('set_php_session_path', 'config/set_php_session_path', { id: web.id, act: val ? 1 : 0 }, function(rdata) {
get_session_status();
bt.msg(rdata)
});
})
setTimeout(function() {
get_session_status();
}, 500);
})
})
})
@@ -4314,28 +4387,24 @@ var site = {
})
},
get_site_logs: function(web) {
bt.site.get_site_logs(web.name, function(rdata) {
var robj = $('#webedit-con'),_form_data;
var logs = { class: 'bt-logs', items: [{ name: 'site_logs', height: '547px', value: rdata.msg, width: '100%', type: 'textarea' }] };
var _form_data = bt.render_form_line(logs);
robj.append(_form_data.html);
robj.find('.site_logs').css('resize','none');
bt.render_clicks(_form_data.clicks);
$('textarea[name="site_logs"]').attr('readonly', true);
$('textarea[name="site_logs"]').scrollTop(100000000000);
var tabs = '<div id="logs_tabs" class="tab-nav" style="margin-bottom: 10px;"><span class="on" data-url="GetSiteLogs">accesslog</span><span data-url="get_site_err_log">errorlog</span></div>';
$('textarea[name="site_logs"]').before(tabs);
$('#logs_tabs').on('click','span' ,function () {
var url = $(this).attr('data-url'),
loadT = bt.load();
if(!$(this).hasClass('on')) $(this).addClass('on').siblings().removeClass('on');
bt.send(url, 'site/'+url,{siteName:web.name}, function(rdata) {
loadT.close();
var _text = (rdata.msg=='')?'Currently no logs':rdata.msg;
$('textarea[name="site_logs"]').val(_text);
});
});
})
$('#webedit-con').append('<div id="tabLogs" class="tab-nav"></div><div class="tab-con" style="padding:10px 0 0;"></div>')
var serverType = bt.get_cookie('serverType'),shell = 'tail -n 100 -f /www/wwwlogs/'+ web.name;
var _tab = [{
title: "Access log",
on: true,
callback:function(robj){
var shellCopy = shell + (serverType === 'nginx'?'.':serverType === 'apache'?'-access_':'_ols.access_') + 'log';
bt_tools.command_line_output({ el:'#webedit-con .tab-con', shell:shellCopy,area:['100%','580px']})
}
},{
title: "Error log",
callback:function(robj){
var shellCopy = shell + (serverType === 'nginx'?'.error.':serverType === 'apache'?'-error_':'_ols.error_') + 'log';
bt_tools.command_line_output({ el:'#webedit-con .tab-con', shell:shellCopy,area:['100%','580px']})
}
}]
bt.render_tab('tabLogs',_tab);
$('#tabLogs span:eq(0)').click();
}
},
create_let: function(ddata, callback) {
+19 -1
View File
@@ -9,7 +9,7 @@ var soft = {
if (type == undefined || type == 'null' || type == 'undefined') type = 0;
if (!search) search = $("#SearchValue").val();
if (search == undefined || search == 'null' || search == 'undefined' || search == '') search = undefined;
var _this = this;
var _this = this, commonly_software = $('#commonly_software');
var istype = getCookie('softType');
if(istype == 'undefined' || istype == 'null' || !istype){
istype = 0;
@@ -18,6 +18,7 @@ var soft = {
if (page == 0) page = bt.get_cookie('p' + type);
if (type == '11'){
soft.get_dep_list(1);
commonly_software.hide();
return;
}
soft.is_install = false;
@@ -59,8 +60,10 @@ var soft = {
$(this).addClass("on").siblings().removeClass("on");
if (_type !== '11') {
soft.get_list(0, _type);
commonly_software.show();
} else {
soft.get_dep_list(0);
commonly_software.hide();
}
})
@@ -636,6 +639,21 @@ var soft = {
}
}
},
/**
* @description 设置软件信息
* @param {object} rdata 软件列表请求数据
* @param {string} type 列表类型
*/
render_soft_recommend: function () {
bt.send('get_usually_plugin', 'plugin/get_usually_plugin', {}, function (res) {
var html = '';
for (var i = 0; i < res.length; i++) {
var item = res[i];
html += '<div class="item" title="open' + item.title + '" onclick="bt.soft.set_lib_config(\'' + item.name + '\',\'' + item.title + '\',\'' + item.version + '\')"><img src="/static/img/soft_ico/ico-' + item.name + '.png"><span>' + item.title + '</span></div>'
}
$('#commonly_software .commonly_software_list').html(html)
})
},
render_tips_btn:function(node,arry){
if(!Array.isArray(arry)) arry = [arry]
for(var i=0;i<arry.length;i++){
+2
View File
@@ -28,6 +28,8 @@ Terms.prototype = {
//连接服务器成功
on_open:function(ws_event){
var http_token = $("#request_token_head").attr('token');
this.send(JSON.stringify({'x-http-token':http_token}))
this.send(JSON.stringify(this.ssh_info || {}))
this.term.FitAddon.fit();
this.resize({cols:this.term.cols, rows:this.term.rows});
+1583 -1405
View File
File diff suppressed because it is too large Load Diff
+1 -3
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -1006,7 +1006,7 @@ var lan = {
"mysql_status_ps4":"If too low, increase innodb_buffer_pool_size",
"mysql_status_ps5":"If too low, increase query_cache_size",
"mysql_status_ps6":"If too high, increase tmp_table_size",
"mysql_status_ps7":"If too high, increase table_cache_size",
"mysql_status_ps7":"If too high, increase table_open_cache",
"mysql_status_ps8":"If not 0, please check index of database table",
"mysql_status_ps9":"If not 0, please check index of database table",
"mysql_status_ps10":"If too high, increase sort_buffer_size",
@@ -947,7 +947,7 @@ var lan = {
"mysql_status_ps4": "If too low, increase innodb_buffer_pool_size",
"mysql_status_ps5": "If too low, increase query_cache_size",
"mysql_status_ps6": "If too high, increase tmp_table_size",
"mysql_status_ps7": "If too high, increase table_cache_size",
"mysql_status_ps7": "If too high, increase table_open_cache",
"mysql_status_ps8": "If not 0, please check index of DB table",
"mysql_status_ps9": "If not 0, please check index of DB table",
"mysql_status_ps10": "If too high, increase sort_buffer_size",
+6 -6
View File
@@ -113,7 +113,7 @@
</div>
</div>
<div class="nav_group manage_backup">
<div class="nav_btn"><span class="glyphicon glyphicon-trash"></span><span class="nav_btn_title">Backup PMSN</span></div>
<div class="nav_btn" title="Backup permissions"><span class="glyphicon glyphicon-trash"></span><span class="nav_btn_title">Backup PMSN</span></div>
</div>
<div class="nav_group recycle_bin">
<div class="nav_btn"><span class="glyphicon glyphicon-trash"></span><span class="nav_btn_title">Recycle bin</span></div>
@@ -285,19 +285,19 @@
<i class="glyphicon glyphicon-share-alt" aria-hidden="true"></i>
<span>Back</span>
</div>
<div class="search_file" title="搜索内容">
<div class="search_file" title="Search File">
<i class="glyphicon glyphicon-search" aria-hidden="true"></i>
<span>Search</span>
</div>
<div class="new_folder" title="新建文件/目录">
<div class="new_folder" title="File/Folder">
<i class="glyphicon glyphicon-plus" aria-hidden="true"></i>
<span>New</span>
<ul class="folder_down_up">
<li data-type="2"><i class="folder-icon"></i>新建文件夹</li>
<li data-type="3"><i class="text-icon"></i>新建文件</li>
<li data-type="2"><i class="folder-icon"></i>Folder</li>
<li data-type="3"><i class="text-icon"></i>File</li>
</ul>
</div>
<div class="refresh_dir" title="刷新当前目录">
<div class="refresh_dir" title="Refresh list">
<span class="glyphicon glyphicon-refresh" aria-hidden="true"></span>
<span>Refresh</span>
</div>
@@ -0,0 +1,13 @@
<div>
<h3>An error occurred while the panel was running</h3>
<div style="margin-bottom: 15px;margin-top: 15px;color: red;">
<h4 style="font-size: none;">{error_title}</h4>
</div>
<pre style="height:112px;word-wrap: break-word;white-space: pre-wrap;margin: 0 0 10px">{request_info}</pre>
<pre style="height:470px;word-wrap: break-word;white-space: pre-wrap;margin: 0 0 0px">{error_msg}</pre>
<ul class="help-info-text">
<li style="list-style: none;"><b>Sorry, an unexpected error occurred while the panel was running. Please try to resolve this error in the following order:</b></li>
<li style="list-style: none;">1. Click the Fix button in the upper right corner of [Home], and log out of the panel and log in again.</li>
<li style="list-style: none;">2. Still unresolved, please take a screenshot of this window and post on the forum for help, address:<a class="btlink" href="https://forum.aapanel.com/" target="_blank">https://forum.aapanel.com/</a></li>
</ul>
</div>
@@ -0,0 +1,15 @@
<div>
<h3>Something went wrong, an error occurred while running [{plugin name}]!</h3>
<div style="margin-bottom: 15px;margin-top: 15px;color: red;">
<h4 style="font-size: none;">{error_title}</h4>
</div>
<pre style="height:112px;word-wrap: break-word;white-space: pre-wrap;margin: 0 0 10px">{request_info}</pre>
<pre style="height:430px;word-wrap: break-word;white-space: pre-wrap;margin: 0 0 0px">{error_msg}</pre>
<ul class="help-info-text">
<li style="list-style: none;"><b>Sorry, an unexpected error occurred while accessing the [{plugin name}] plugin. Please try to resolve this error in the following order:</b></li>
<li style="list-style: none;">1. Click the Fix button in the upper right corner of [Home], and log out of the panel and log in again.</li>
<li style="list-style: none;">2. If the plugin is not the latest version, try to update to the latest version, if it is the latest version, please try to reinstall the plugin, if it is a beta version, please try to switch to the official version</li>
<li style="list-style: none;">3. If this plug-in is a third-party plug-in, try to contact the author for help</li>
<li style="list-style: none;">4. If the above attempt fails to resolve this error, please take a screenshot of this window and post on the Pagoda Forum for help<a class="btlink" href="https://forum.aapanel.com" target="_blank">https://forum.aapanel.com</a></li>
</ul>
</div>
+2
View File
@@ -31,6 +31,7 @@
<div id="updata_pro_info">
<div class="alert alert-success" style="margin-bottom:15px"><strong>{{data['lan']['PS']}}</strong><button class="btn btn-success btn-xs va0 updata_pro" onclick="bt.soft.updata_pro()" title="{{data['lan']['UPDATE_PRO_NOW']}}" style="margin-left:8px">"{{data['lan']['UPDATE_NOW']}}"</button></div>
</div>
<div id="commonly_software" class="commonly_software"><div class="commonly_software_title">Recently visited plugin:</div><div class="commonly_software_list"></div></div>
<table id="softList" class="table table-hover" width="100%" cellspacing="0" cellpadding="0" border="0" style="margin-top:10px"></table>
<div id='softPage' class="dataTables_paginate paging_bootstrap page"></div>
</div>
@@ -51,6 +52,7 @@
bt.set_cookie('distribution', "{{session['config']['distribution']}}");
$(document).ready(function () {
soft.get_list();
soft.render_soft_recommend()
setTimeout(function () {
soft_td_width_auto();
}, 500);
+2 -2
View File
@@ -114,9 +114,9 @@ _convenient and efficient file manager integration , Support uploading, download
#### Installation command
##### Centos
```bash
yum install -y wget && wget -O install.sh http://www.aapanel.com/script/install_6.0_en.sh && bash install.sh
yum install -y wget && wget -O install.sh http://www.aapanel.com/script/install_6.0_en.sh && bash install.sh 66959f96
```
##### Ubuntu/Debian
```bash
wget -O install.sh http://www.aapanel.com/script/install-ubuntu_6.0_en.sh && sudo bash install.sh
wget -O install.sh http://www.aapanel.com/script/install-ubuntu_6.0_en.sh && sudo bash install.sh 66959f96
```
+12 -6
View File
@@ -117,6 +117,9 @@ class apache:
def GetApacheValue(self):
apachedefaultcontent = public.readFile(self.apachedefaultfile)
apachempmcontent = public.readFile(self.apachempmfile)
if not "mpm_event_module" in apachempmcontent:
return public.returnMsg(False,"mpm_event_module conf not found or /www/server/apache/conf/extra/httpd-mpm.conf is empty")
apachempmcontent = re.search("\<IfModule mpm_event_module\>(\n|.)+?\</IfModule\>",apachempmcontent).group()
ps = ["%s%s" % (public.GetMsg("SECOND"),public.GetMsg("REQUEST_TIMEOUT_TIME")),
public.GetMsg("KEEP_ALIVE"),
"%s%s" % (public.GetMsg("SECOND"),public.GetMsg("CONNECT_TIMEOUT_TIME")),
@@ -143,10 +146,12 @@ class apache:
n += 1
ps = [public.GetMsg("DEFUALT_PROCESSES"),
public.GetMsg("MAX_SPARE_SERVERS"),
"%s%s" % (public.GetMsg("MAX_CONNECTIONS"),public.GetMsg("NOT_LIMITED_BY_0")),
public.GetMsg("MAX_PROCESSES")]
gets = ["StartServers","MaxSpareServers","MaxConnectionsPerChild","MaxRequestWorkers"]
public.GetMsg("MAX_SPARE_THREADS"),
public.GetMsg("MIN_SPARE_THREADS"),
public.GetMsg("THREADS_PER_CHILD"),
public.GetMsg("MAX_REQUEST_WORKERS"),
public.GetMsg("MaxConnectionsPerChild")]
gets = ["StartServers","MaxSpareThreads","MinSpareThreads","ThreadsPerChild","MaxRequestWorkers","MaxConnectionsPerChild"]
n = 0
for i in gets:
rep = "(%s)\s+(\w+)" % i
@@ -167,6 +172,8 @@ class apache:
def SetApacheValue(self,get):
apachedefaultcontent = public.readFile(self.apachedefaultfile)
apachempmcontent = public.readFile(self.apachempmfile)
if not "mpm_event_module" in apachempmcontent:
return public.returnMsg(False,"mpm_event_module conf not found or /www/server/apache/conf/extra/httpd-mpm.conf is empty")
conflist = []
getdict = get.__dict__
for i in getdict.keys():
@@ -176,7 +183,6 @@ class apache:
"value": str(getdict[i])
}
conflist.append(getpost)
public.writeFile("/tmp/list",str(conflist))
for c in conflist:
if c["name"] == "KeepAlive":
if not re.search("on|off", c["value"]):
@@ -193,7 +199,7 @@ class apache:
apachedefaultcontent = re.sub(rep,newconf,apachedefaultcontent)
elif re.search(rep,apachempmcontent):
newconf = "%s\t\t\t%s" % (c["name"], c["value"])
apachempmcontent = re.sub(rep, newconf , apachempmcontent,count = 1)
apachempmcontent = re.sub(rep, newconf , apachempmcontent)
public.writeFile(self.apachedefaultfile,apachedefaultcontent)
public.writeFile(self.apachempmfile, apachempmcontent)
isError = public.checkWebConfig()
+32 -29
View File
@@ -18,12 +18,15 @@ import time
class panelSetup:
def init(self):
ua = request.headers.get('User-Agent','')
if ua:
ua = ua.lower()
if ua.find('spider') != -1 or ua.find('bot') != -1:
panel_path = public.get_panel_path()
if os.getcwd() != panel_path: os.chdir(panel_path)
g.ua = request.headers.get('User-Agent','')
if g.ua:
ua = g.ua.lower()
if ua.find('spider') != -1 or g.ua.find('bot') != -1:
return redirect('https://www.google.com')
g.version = '6.8.12'
g.version = '6.8.14'
g.title = public.GetConfigValue('title')
g.uri = request.path
g.debug = os.path.exists('data/debug.pl')
@@ -97,7 +100,7 @@ class panelAdmin(panelSetup):
session['brand'] = public.GetConfigValue('brand')
session['product'] = public.GetConfigValue('product')
session['rootPath'] = '/www'
session['download_url'] = 'http://download.bt.cn'
session['download_url'] = 'https://node.aapanel.com'
session['setupPath'] = session['rootPath'] + '/server'
session['logsPath'] = '/www/wwwlogs'
session['yaer'] = datetime.now().year
@@ -147,50 +150,50 @@ class panelAdmin(panelSetup):
g.api_request = True
else:
if session['login'] == False:
public.WriteLog('Login auth', 'The current session has been logged out')
session.clear()
return redirect('/login')
if 'tmp_login_expire' in session:
s_file = 'data/session/{}'.format(session['tmp_login_id'])
if session['tmp_login_expire'] < time.time():
public.WriteLog('Login auth', 'Temporary authorization has expired {}'.format(public.get_client_ip()))
session.clear()
if os.path.exists(s_file): os.remove(s_file)
return redirect('/login')
if not os.path.exists(s_file):
public.WriteLog('Login auth', 'Forced withdrawal due to cancellation of temporary authorization {}'.format(public.get_client_ip()))
session.clear()
return redirect('/login')
ua_md5 = public.md5(g.ua)
if ua_md5 != session.get('login_user_agent',ua_md5):
public.WriteLog('Login auth', 'UA verification failed {}'.format(public.get_client_ip()))
session.clear()
return redirect('/login')
if api_check:
try:
sess_out_path = 'data/session_timeout.pl'
sess_input_path = 'data/session_last.pl'
if not os.path.exists(sess_out_path): public.writeFile(sess_out_path,'86400')
if not os.path.exists(sess_input_path): public.writeFile(sess_input_path,str(int(time.time())))
session_timeout = int(public.readFile(sess_out_path))
session_last = int(public.readFile(sess_input_path))
if time.time() - session_last > session_timeout:
os.remove(sess_input_path)
session['login'] = False
cache.set('dologin', True)
session.clear()
return redirect('/login')
public.writeFile(sess_input_path, str(int(time.time())))
except:
pass
session_timeout = session.get('session_timeout',0)
if session_timeout < time.time() and session_timeout != 0:
public.WriteLog('Login auth', 'The session has expired {}'.format(public.get_client_ip()))
session.clear()
return redirect('/login?dologin=True&go=0')
login_token = session.get('login_token','')
if login_token:
if login_token != public.get_login_token_auth():
public.WriteLog('Login auth', 'Session ID does not match {}'.format(public.get_client_ip()))
session.clear()
return redirect('/login?dologin=True&go=1')
filename = '/www/server/panel/data/login_token.pl'
if os.path.exists(filename):
token = public.readFile(filename).strip()
if 'login_token' in session:
if session['login_token'] != token:
session.clear()
return redirect('/login?dologin=True&go=1')
if api_check:
filename = 'data/sess_files/' + public.get_sess_key()
if not os.path.exists(filename):
public.WriteLog('Login auth', 'Trigger CSRF defense {}'.format(public.get_client_ip()))
session.clear()
return redirect('/login?dologin=True&go=2')
except:
public.WriteLog('Login auth',public.get_error_info())
session.clear()
return redirect('/login')
+48 -9
View File
@@ -12,7 +12,7 @@ try:
except:
public.ExecShell("pip install pyotp &")
try:
from BTPanel import session,admin_path_checks,g,request
from BTPanel import session,admin_path_checks,g,request,cache
import send_mail
except:pass
class config:
@@ -91,6 +91,18 @@ class config:
if not 'port' in qq_mail_info:qq_mail_info['port']=465
return public.returnMsg(True, qq_mail_info)
#清空数据
def set_empty(self,get):
type=get.type.strip()
if type=='dingding':
ret = []
public.writeFile(self.__dingding_config, json.dumps(ret))
return public.returnMsg(True, 'Empty successfully')
else:
ret = []
public.writeFile(self.__mail_config, json.dumps(ret))
return public.returnMsg(True, 'Empty successfully')
# 用户自定义邮件发送
def user_stmp_mail_send(self, get):
@@ -127,12 +139,11 @@ class config:
ret['user_mail'] = {"user_name": user_mail, "mail_list": self.__mail_list,"info":self.get_user_mail(get)}
ret['dingding'] = {"dingding": dingding,"info":self.get_dingding(get)}
return ret
# 设置钉钉报警
def set_dingding(self, get):
if not (hasattr(get, 'url') or hasattr(get, 'atall')):
return public.returnMsg(False, 'COMPLETE_INFO')
if get.atall:
if get.atall=='True' or get.atall=='1':
get.atall = 'True'
else: get.atall = 'False'
self.mail.dingding_insert(get.url.strip(), get.atall)
@@ -321,7 +332,9 @@ class config:
public.SetConfigValue('title',get.webname)
limitip = public.readFile('data/limitip.conf')
if get.limitip != limitip: public.writeFile('data/limitip.conf',get.limitip)
if get.limitip != limitip:
public.writeFile('data/limitip.conf',get.limitip)
cache.set('limit_ip',[])
public.writeFile('data/domain.conf',get.domain.strip())
public.writeFile('data/iplist.txt',get.address)
@@ -364,8 +377,8 @@ class config:
if not get.domain: get.domain = ''
get.limitip = public.readFile('data/limitip.conf')
if not get.limitip: get.limitip = ''
if not get.domain.strip() and not get.limitip.strip(): return public.returnMsg(False,
'SECURITY_ENTRANCE_ADDRESS_TRUEN_OFF_WARN')
if not get.domain.strip() and not get.limitip.strip() and not os.path.exists('config/basic_auth.json'):
return public.returnMsg(False,'SECURITY_ENTRANCE_ADDRESS_TRUEN_OFF_WARN')
admin_path_file = 'data/admin_path.pl'
admin_path = '/'
@@ -523,9 +536,21 @@ class config:
rep = r"\s*pm\s*=\s*(\w+)\s*"
tmp = re.search(rep, conf).groups()
data['pm'] = tmp[0]
rep = r"\s*listen.allowed_clients\s*=\s*([\w\.,/]+)\s*"
tmp = re.search(rep, conf).groups()
data['allowed'] = tmp[0]
data['unix'] = 'unix'
if not isinstance(public.get_fpm_address(version),str):
data['port'] = ''
data['bind'] = '/tmp/php-cgi-{}.sock'.format(version)
fpm_address = public.get_fpm_address(version,True)
if not isinstance(fpm_address,str):
data['unix'] = 'tcp'
data['port'] = fpm_address[1]
data['bind'] = fpm_address[0]
return data
@@ -565,12 +590,24 @@ class config:
if get.listen == 'unix':
listen = '/tmp/php-cgi-{}.sock'.format(version)
else:
listen = '127.0.0.1:10{}1'.format(version)
default_listen = '127.0.0.1:10{}1'.format(version)
if 'bind_port' in get:
if get.bind_port.find('sock') != -1:
listen = default_listen
else:
listen = get.bind_port
else:
listen = default_listen
rep = r'\s*listen\s*=\s*.+\s*'
conf = re.sub(rep, "\nlisten = "+listen+"\n", conf)
if 'allowed' in get:
if not get.allowed: get.allowed = '127.0.0.1'
rep = r"\s*listen.allowed_clients\s*=\s*([\w\.,/]+)\s*"
conf = re.sub(rep, "\nlisten.allowed_clients = "+get.allowed+"\n", conf)
public.writeFile(file,conf)
public.phpReload(version)
public.sync_php_address(version)
@@ -696,6 +733,8 @@ class config:
#设置面板SSL
def SetPanelSSL(self,get):
ssl_path = "{}/ssl".format(public.get_panel_path())
if not os.path.exists(ssl_path): os.makedirs(ssl_path,384)
if hasattr(get,"email"):
#rep_mail = "^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$"
rep_mail = r"[\w!#$%&'*+/=?^_`{|}~-]+(?:\.[\w!#$%&'*+/=?^_`{|}~-]+)*@(?:[\w](?:[\w-]*[\w])?\.)+[\w](?:[\w-]*[\w])?"
@@ -1681,7 +1720,7 @@ class config:
def get_login_send(self,get):
result={}
import time
time.sleep(0.5)
time.sleep(0.01)
if os.path.exists('/www/server/panel/data/login_send_mail.pl'):
result['mail']=True
else:
+12 -7
View File
@@ -38,7 +38,7 @@ class data:
temp['local'] = True
try:
s = socket.socket()
s.settimeout(0.15)
s.settimeout(0.01)
s.connect((localIP,port))
s.close()
except:
@@ -141,14 +141,16 @@ class data:
conf = public.readFile(
self.setupPath + '/panel/vhost/' + self.web_server + '/detail/' + siteName + '.conf')
if self.web_server == 'nginx':
rep = r"enable-php-([0-9]{2,3})\.conf"
rep = r"enable-php-(\w{2,5})\.conf"
elif self.web_server == 'apache':
rep = r"php-cgi-([0-9]{2,3})\.sock"
rep = r"php-cgi-(\w{2,5})\.sock"
else:
rep = r"path\s*/usr/local/lsws/lsphp(\d+)/bin/lsphp"
tmp = re.search(rep,conf).groups()
if tmp[0] == '00':
return 'Static'
if tmp[0] == 'other':
return 'Other'
return tmp[0][0] + '.' + tmp[0][1]
except:
@@ -199,6 +201,8 @@ class data:
data['data'][i]['domain'] = SQL.table('domain').where("pid=?",(data['data'][i]['id'],)).count()
data['data'][i]['ssl'] = self.get_site_ssl_info(data['data'][i]['name'])
data['data'][i]['php_version'] = self.get_php_version(data['data'][i]['name'])
if not data['data'][i]['status'] in ['0','1',0,1]:
data['data'][i]['status'] = '1'
elif table == 'firewall':
for i in range(len(data['data'])):
if data['data'][i]['port'].find(':') != -1 or data['data'][i]['port'].find('.') != -1 or data['data'][i]['port'].find('-') != -1:
@@ -242,9 +246,7 @@ class data:
where = "id=?"
retuls = SQL.where(where,(id,)).getField(keyName)
return retuls
'''
* 获取数据与分页
* @param string table
@@ -334,7 +336,10 @@ class data:
if not search: return ""
if type(search) == bytes: search = search.encode('utf-8').strip()
search = re.search(r"[\w\x80-\xff\.]+",search).group()
try:
search = re.search(r"[\w\x80-\xff\.]+",search).group()
except:
return ''
wheres = {
'sites' : "id='"+search+"' or name like '%"+search+"%' or status like '%"+search+"%' or ps like '%"+search+"%'",
'ftps' : "id='"+search+"' or name like '%"+search+"%' or ps like '%"+search+"%'",
+1 -1
View File
@@ -58,7 +58,7 @@ class datatools:
ret2 = {}
ret2['type']=table[0][1]
data_size = table[0][6]
ret2['rows_count'] = table[0][4]
ret2['rows_count'] = self.DB_MySQL.query("select count(*) from `{}`.`{}`".format(db_name,i[0]))[0][0] #table[0][4] 实时获取行数 @authow hwliang<2021-08-05> 修改
ret2['collation'] = table[0][14]
ret2['data_size'] = self.ToSize(int(data_size))
ret2['table_name'] = i[0]
+3 -2
View File
@@ -82,8 +82,9 @@ class Sql():
def limit(self,limit):
#LIMIT条件
if len(limit):
self.__OPT_LIMIT = " LIMIT "+limit
if limit:
self.__OPT_LIMIT = " LIMIT {}".format(limit)
return self
+122 -11
View File
@@ -165,6 +165,23 @@ session.save_handler = files'''.format(path, sess_path, sess_path)
if text2.find(rep) != -1: text2 = text2.replace(rep,reps[rep])
return text2
# 名称输入系列化
def xssdecode(self,text):
try:
cs = {"&quot":'"',"&#x27":"'"}
for c in cs.keys():
text = text.replace(c,cs[c])
str_convert = text
if sys.version_info[0] == 3:
import html
text2 = html.unescape(str_convert)
else:
text2 = cgi.unescape(str_convert)
return text2
except:
return text
# 上传文件
def UploadFile(self, get):
from werkzeug.utils import secure_filename
@@ -302,6 +319,13 @@ session.save_handler = files'''.format(path, sess_path, sess_path)
return str(result)
return '0'
def __filename_flater(self,filename):
ms = {";":""}
for m in ms.keys():
filename = filename.replace(m,ms[m])
return filename
# 取文件/目录列表
def GetDir(self, get):
if not hasattr(get, 'path'):
@@ -311,6 +335,7 @@ session.save_handler = files'''.format(path, sess_path, sess_path)
get.path = get.path.encode('utf-8')
if get.path == '':
get.path = '/www'
get.path = self.xssdecode(get.path)
if not os.path.exists(get.path):
get.path = '/www/wwwroot'
#return public.ReturnMsg(False, '指定目录不存在!')
@@ -406,11 +431,11 @@ session.save_handler = files'''.format(path, sess_path, sess_path)
# 判断文件是否已经被收藏
favorite = self.__check_favorite(filePath,data['STORE'])
if os.path.isdir(filePath):
dirnames.append(filename+';'+size+';' + mtime+';'+accept+';'+user+';'+link + ';' +
dirnames.append(self.__filename_flater(filename)+';'+size+';' + mtime+';'+accept+';'+user+';'+link + ';' +
self.get_download_id(filePath)+';'+ self.is_composer_json(filePath)+';'
+favorite+';'+self.__check_share(filePath))
else:
filenames.append(filename+';'+size+';'+mtime+';'+accept+';'+user+';'+link+';'
filenames.append(self.__filename_flater(filename)+';'+size+';'+mtime+';'+accept+';'+user+';'+link+';'
+self.get_download_id(filePath)+';' + self.is_composer_json(filePath)+';'
+favorite+';'+self.__check_share(filePath))
n += 1
@@ -437,7 +462,7 @@ session.save_handler = files'''.format(path, sess_path, sess_path)
file_info = self.__format_stat(filename, get.path)
if not file_info: continue
favorite = self.__check_favorite(filename, data['STORE'])
r_file = file_info['name'] + ';' + str(file_info['size']) + ';' + str(file_info['mtime']) + ';' + str(
r_file = self.__filename_flater(file_info['name']) + ';' + str(file_info['size']) + ';' + str(file_info['mtime']) + ';' + str(
file_info['accept']) + ';' + file_info['user'] + ';' + file_info['link']+';'\
+ self.get_download_id(filename) + ';' + self.is_composer_json(filename)+';'\
+ favorite+';'+self.__check_share(filename)
@@ -477,6 +502,30 @@ session.save_handler = files'''.format(path, sess_path, sess_path)
f_key2 = '/'.join((ps_path,public.md5(os.path.basename(filename))))
if os.path.exists(f_key2):
return public.readFile(f_key2)
pss = {
'/www/server/data':'MySQL data storage directory!',
'/www/server/mysql':'MySQL program directory',
'/www/server/redis':'Redis program directory',
'/www/server/mongodb':'MongoDB program directory',
'/www/server/nvm':'PM2/NVM/NPM program directory',
'/www/server/pass':'Website Basic Auth authentication password storage directory',
'/www/server/speed':'Website speed plugin directory',
'/www/server/docker':'Docker and data directory',
'/www/server/total':'Website Statistics Directory',
'/www/server/btwaf':'WAF directory',
'/www/server/pure-ftpd':'ftp program directory',
'/www/server/phpmyadmin':'phpMyAdmin program directory',
'/www/server/rar':'rar extension library directory, after deleting, it will lose support for RAR compressed files',
'/www/server/stop':'Website disabled page directory, please do not delete!',
'/www/server/nginx':'Nginx program directory',
'/www/server/apache':'Apache program directory',
'/www/server/cron':'Cron script and log directory',
'/www/server/php':'All interpreters of PHP versions are in this directory',
'/www/server/tomcat':'Tomcat program directory',
'/www/php_session':'PHP-SESSION Quarantine directory'
}
if filename in pss: return pss[filename]
return ''
@@ -512,6 +561,13 @@ session.save_handler = files'''.format(path, sess_path, sess_path)
def check_file_sort(self,sort):
"""
@校验排序字段
"""
slist = ['name','size','mtime','accept','user']
if sort in slist: return sort
return 'name'
def __list_dir(self, path, my_sort='name', reverse=False):
'''
@@ -554,8 +610,9 @@ session.save_handler = files'''.format(path, sess_path, sess_path)
continue
#使用list[tuple]排序效率更高
tmp_files.append((f_name,sort_val))
tmp_files = sorted(tmp_files, key=lambda x: x[sort_key], reverse=reverse)
try:
tmp_files = sorted(tmp_files, key=lambda x: x[sort_key], reverse=reverse)
except:pass
return tmp_files
def __format_stat(self, filename, path):
@@ -1082,6 +1139,8 @@ session.save_handler = files'''.format(path, sess_path, sess_path)
def GetFileBody(self, get):
if sys.version_info[0] == 2:
get.path = get.path.encode('utf-8')
get.path = self.xssdecode(get.path)
if not os.path.exists(get.path):
if get.path.find('rewrite') == -1:
return public.returnMsg(False,'FILE_NOT_EXISTS',(get.path,))
@@ -1308,6 +1367,11 @@ session.save_handler = files'''.format(path, sess_path, sess_path)
def Zip(self, get):
if not 'z_type' in get:
get.z_type = 'rar'
if get.z_type == 'rar':
if os.uname().machine == 'aarch64':
return public.returnMsg(False,'RAR component does not support aarch 64 platform')
import panelTask
task_obj = panelTask.bt_task()
task_obj.create_task(public.GetMsg("COMPRESSION_FILE"),3,get.path,json.dumps({"sfile":get.sfile,"dfile":get.dfile,"z_type":get.z_type}))
@@ -1387,6 +1451,8 @@ session.save_handler = files'''.format(path, sess_path, sess_path)
def CloseLogs(self, get):
get.path = public.GetConfigValue('root_path')
public.ExecShell('rm -f '+public.GetConfigValue('logs_path')+'/*')
public.ExecShell('rm -rf '+public.GetConfigValue('logs_path')+'/history_backups/*')
public.ExecShell('rm -f '+public.GetConfigValue('logs_path')+'/pm2/*.log')
if public.get_webserver() == 'nginx':
public.ExecShell(
'kill -USR1 `cat '+public.GetConfigValue('setup_path')+'/nginx/logs/nginx.pid`')
@@ -1479,6 +1545,19 @@ session.save_handler = files'''.format(path, sess_path, sess_path)
myfiles = json.loads(session['selected']['data'])
l = len(myfiles)
if get.type == '1':
for key in myfiles:
if sys.version_info[0] == 2:
sfile = session['selected']['path'] + \
'/' + key.encode('utf-8')
dfile = get.path + '/' + key.encode('utf-8')
else:
sfile = session['selected']['path'] + '/' + key
dfile = get.path + '/' + key
if dfile.find(sfile) == 0:
return public.returnMsg(False,'Wrong copy logic, from {} copy to {} has an inclusive relationship, there is an infinite loop copy risk!'.format(sfile,dfile))
for key in myfiles:
i += 1
public.writeSpeed(key, i, l)
@@ -2014,7 +2093,7 @@ cd %s
if len(pdata['password']) < 4 and len(pdata['password']) > 0:
return public.returnMsg(False,'The length of the extracted password cannot be less than 4 digits')
if not re.match('^\w+$',pdata['password']):
return public.returnMsg(False,'No special symbols can be used in the extracted password')
return public.returnMsg(False,'The password only supports a combination of uppercase and lowercase letters and numbers')
if 'ps' in get: pdata['ps'] = get.ps
public.M(my_table).where('id=?', (id,)).update(pdata)
@@ -2037,8 +2116,8 @@ cd %s
}
if len(pdata['password']) < 4 and len(pdata['password']) > 0:
return public.returnMsg(False,'PASSWD_ERR')
if not re.match('^\w+$',pdata['password']):
return public.returnMsg(False,'No special symbols can be used in the extracted password')
if not re.match('^\w+$',pdata['password']) and pdata['password']:
return public.returnMsg(False,'The password only supports a combination of uppercase and lowercase letters and numbers')
#更新 or 插入
token = public.M(my_table).where('filename=?',(get.filename,)).getField('token')
if token:
@@ -2123,8 +2202,10 @@ cd %s
php_bin = self.__get_php_bin(php_version)
if not php_bin:
return public.returnMsg(False,'PHP_VER_NOT_FOUND')
if not os.path.exists(get.path + '/composer.json'):
return public.returnMsg(False,'COMPOSER_CONF_NOT_FOUND')
get.composer_cmd = get.composer_cmd.strip()
if get.composer_cmd == '':
if not os.path.exists(get.path + '/composer.json'):
return public.returnMsg(False,'COMPOSER_CONF_NOT_FOUND')
log_file = '/tmp/composer.log'
user = ''
if 'user' in get:
@@ -2143,7 +2224,15 @@ cd %s
else:
public.ExecShell('export COMPOSER_HOME=/tmp && {}{} {} config -g --unset repos.packagist'.format(user,php_bin,composer_bin))
#执行composer命令
composer_exec_str = '{} {} {} -vvv'.format(php_bin,composer_bin,get.composer_args)
if not get.composer_cmd:
composer_exec_str = '{} {} {} -vvv'.format(php_bin,composer_bin,get.composer_args)
else:
if get.composer_cmd.find('composer ') == 0 or get.composer_cmd.find('/usr/bin/composer ') == 0:
composer_cmd = get.composer_cmd.replace('composer ','').replace('/usr/bin/composer ','')
composer_exec_str = '{} {} {} -vvv'.format(php_bin,composer_bin,composer_cmd)
else:
composer_exec_str = '{} {} {} {} -vvv'.format(php_bin,composer_bin,get.composer_args,get.composer_cmd)
if os.path.exists(log_file): os.remove(log_file)
public.ExecShell("cd {} && export COMPOSER_HOME=/tmp && {} nohup {} &> {} && echo 'BT-Exec-Completed' >> {} && rm -rf /home/www &".format(get.path,user,composer_exec_str,log_file,log_file))
public.WriteLog('Composer',"EXEC_COMPOSER",(get.path,get.composer_args))
@@ -2258,6 +2347,27 @@ cd %s
except:
return uid
# 取lsattr
def get_lsattr(self,filename):
if os.path.isfile(filename):
return public.ExecShell('lsattr {}'.format(filename))[0].split(' ')[0]
else:
s_name = os.path.basename(filename)
s_path = os.path.dirname(filename)
try:
res = public.ExecShell('lsattr {}'.format(s_path))[0].strip()
for s in res.split('\n'):
if not s: continue
lsattr_info = s.split()
if not lsattr_info: continue
if filename == lsattr_info[1]:
return lsattr_info[0]
except:
raise public.PanelError(lsattr_info)
return '--------------e----'
# 取指定文件属性
def get_file_attribute(self,args):
@@ -2283,6 +2393,7 @@ cd %s
attribute['mode'] = str(oct(f_stat.st_mode)[-3:]) # 文件权限号
attribute['md5'] = 'Do not count files or directories larger than 100MB' # 文件MD5
attribute['sha1'] = 'Do not count files or directories larger than 100MB' # 文件sha1
attribute['lsattr'] = self.get_lsattr(filename)
attribute['is_dir'] = os.path.isdir(filename) # 是否为目录
attribute['is_link'] = os.path.islink(filename) # 是否为链接文件
if attribute['is_link']:
+24 -25
View File
@@ -284,34 +284,33 @@ class firewalls:
#取SSH信息
def GetSshInfo(self,get):
file = '/etc/ssh/sshd_config'
conf = public.readFile(file)
if not conf: conf = ''
rep = r"#*Port\s+([0-9]+)\s*\n"
tmp1 = re.search(rep,conf)
port = '22'
if tmp1:
port = tmp1.groups(0)[0]
import system
panelsys = system.system()
version = panelsys.GetSystemVersion()
if os.path.exists('/usr/bin/apt-get'):
if os.path.exists('/etc/init.d/sshd'):
status = public.ExecShell("service sshd status | grep -P '(dead|stop)'|grep -v grep")
else:
status = public.ExecShell("service ssh status | grep -P '(dead|stop)'|grep -v grep")
port = public.get_ssh_port()
pid_file = '/run/sshd.pid'
if os.path.exists(pid_file):
pid = int(public.readFile(pid_file))
status = public.pid_exists(pid)
else:
if version.find(' 7.') != -1 or version.find(' 8.') != -1 or version.find('Fedora') != -1:
status = public.ExecShell("systemctl status sshd.service | grep 'dead'|grep -v grep")
import system
panelsys = system.system()
version = panelsys.GetSystemVersion()
if os.path.exists('/usr/bin/apt-get'):
if os.path.exists('/etc/init.d/sshd'):
status = public.ExecShell("service sshd status | grep -P '(dead|stop)'|grep -v grep")
else:
status = public.ExecShell("service ssh status | grep -P '(dead|stop)'|grep -v grep")
else:
status = public.ExecShell("/etc/init.d/sshd status | grep -e 'stopped' -e '已停'|grep -v grep")
if version.find(' 7.') != -1 or version.find(' 8.') != -1 or version.find('Fedora') != -1:
status = public.ExecShell("systemctl status sshd.service | grep 'dead'|grep -v grep")
else:
status = public.ExecShell("/etc/init.d/sshd status | grep -e 'stopped' -e '已停'|grep -v grep")
# return status;
if len(status[0]) > 3:
status = False
else:
status = True
# return status;
if len(status[0]) > 3:
status = False
else:
status = True
isPing = True
try:
file = '/etc/sysctl.conf'
+1 -1
View File
@@ -240,7 +240,7 @@ RewriteRule (.*\.php)?$ - [E=Cache-Control:private]
def _get_siteconf_info(self):
siteinfo = self._get_need_create_site()
phpv_reg = r'enable-php-(\d+)\.conf'
phpv_reg = r'enable-php-(\w+)\.conf'
rundir_reg = r'root\s+(.*);'
for s in siteinfo:
path = '/www/server/panel/vhost/nginx/{}.conf'.format(s['sitename'])
+8 -2
View File
@@ -71,8 +71,10 @@ class panelAuth:
else:
params['product_id'] = get.product_id
data = self.send_cloud('{}/api/product/prices'.format(self.__official_url), params)
if len(data['res']) > 3:
return data['res'][-3:]
if not data['success']:
return public.returnMsg(False,data['msg'])
# if len(data['res']) == 6:
# return data['res'][3:]
return data['res']
except:
del(session['get_product_list'])
@@ -108,6 +110,8 @@ class panelAuth:
params['environment_info'] = json.dumps(env_info)
params['server_id'] = env_info['install_code']
data = self.send_cloud('{}/api/order/product/create'.format(self.__official_url), params)
if not data['success']:
return public.returnMsg(False,data['res'])
return data['res']
def get_stripe_session_id(self,get):
@@ -285,6 +289,8 @@ class panelAuth:
params['page'] = get.page if 'page' in get else 1
params['pageSize'] = get.pageSize if 'pageSize' in get else 15
data = self.send_cloud('{}/api/user/productAuthorizes'.format(self.__official_url), params)
if not data:
return []
if not data['success']: return []
data = data['res']
return [i for i in data['list'] if i['status'] != 'activated']
+15 -4
View File
@@ -75,6 +75,15 @@ class backup:
self._error_msg += "\n"
self._error_msg += msg
#取排除列表用于计算排除目录大小
def get_exclude_list(self, exclude=[]):
if not exclude:
tmp_exclude = os.getenv('BT_EXCLUDE')
if tmp_exclude:
exclude = tmp_exclude.split(',')
if not exclude: return []
return exclude
#构造排除
def get_exclude(self,exclude = []):
if not exclude:
@@ -274,10 +283,11 @@ class backup:
dpath = os.path.dirname(dfile)
if not os.path.exists(dpath):
os.makedirs(dpath,384)
p_size = public.get_path_size(spath)
self.get_exclude(exclude)
exclude_config = self._exclude
exclude_list = self.get_exclude_list(exclude)
p_size = public.get_path_size(spath, exclude=exclude_list)
if not self._exclude:
exclude_config = "Not set"
@@ -349,6 +359,7 @@ class backup:
error_msg = self._error_msg
self.send_failture_notification(error_msg)
return False
if self._cloud:
self.echo_info(public.getMsg("BACKUP_UPLOADING",(self._cloud._title,)))
if self._cloud.upload_file(dfile,'site'):
@@ -709,7 +720,7 @@ class backup:
return
if notice == 1 or notice == 2:
title = self.generate_failture_title()
title = self.generate_failture_title(cron_title)
task_name = cron_title
msg = self.generate_failture_notice(task_name, error_msg, remark)
res = self.send_notification(notice_channel, title, msg)
@@ -733,7 +744,7 @@ class backup:
return
if notice == 1 or notice == 2:
title = self.generate_failture_title()
title = self.generate_failture_title(cron_title)
type_desc = {
"site": "site",
"database": "database"
+3 -3
View File
@@ -22,9 +22,9 @@ class panelMessage:
os = 'linux'
def __init__(self):
# if not public.M('sqlite_master').where('type=? AND name=? AND sql LIKE ?', ('table', 'messages','%retry_num%')).count():
# public.M('messages').execute("alter TABLE messages add send integer DEFAULT 0",())
# public.M('messages').execute("alter TABLE messages add retry_num integer DEFAULT 0",())
if not public.M('sqlite_master').where('type=? AND name=? AND sql LIKE ?', ('table', 'messages','%retry_num%')).count():
public.M('messages').execute("alter TABLE messages add send integer DEFAULT 0",())
public.M('messages').execute("alter TABLE messages add retry_num integer DEFAULT 0",())
pass
+129 -22
View File
@@ -7,7 +7,7 @@
# Author: hwliang <hwl@bt.cn>
#-------------------------------------------------------------------
import public,os,sys,json,time,psutil,py_compile,re
from BTPanel import session,cache
from BTPanel import session,cache,send_file
if sys.version_info[0] == 3: from importlib import reload
class mget: pass
class panelPlugin:
@@ -20,12 +20,13 @@ class panelPlugin:
__link = 'config/link.json'
__product_list = None
__plugin_list = None
__exists_names = {}
__official_url = 'https://brandnew.aapanel.com'
pids = None
ROWS = 15
def __init__(self):
self.__install_path = 'plugin'
self.__install_path = '/www/server/panel/plugin'
#检查依赖
def check_deps(self,get):
@@ -65,6 +66,7 @@ class panelPlugin:
#检查互斥
def check_mutex(self,mutex):
if mutex == -1: return True
mutexs = mutex.split(',')
for name in mutexs:
pluginInfo = self.get_soft_find(name)
@@ -255,9 +257,13 @@ class panelPlugin:
get.type = '4'
if ols_execstr:
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)
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 && sleep 1 && /usr/local/lsws/bin/lswsctrl restart"
# 清理日志文件
if os.path.exists("/tmp/panelExec.log"):
public.writeFile("/tmp/panelExec.log","")
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')
@@ -271,7 +277,7 @@ class panelPlugin:
if pluginInfo['type'] != 5:
pluginPath = self.__install_path + '/' + pluginInfo['name']
if pluginInfo['type'] != 6:
download_url = session['download_url'] + '/install/plugin/' + pluginInfo['name'] + '/install.sh'
download_url = session['download_url'] + '/install/plugin/' + pluginInfo['name'] + '_en/install.sh'
toFile = '/tmp/%s.sh' % pluginInfo['name']
public.downloadFile(download_url,toFile)
self.set_pyenv(toFile)
@@ -372,6 +378,8 @@ class panelPlugin:
for softInfo in softList['list']:
if 'uninsatll_checks' not in softInfo:
softInfo['uninsatll_checks'] = softInfo['uninstall_checks']
if not softList['list']:
if os.path.exists(lcoalTmp): os.remove(lcoalTmp)
return softList
#取提醒标记
@@ -864,10 +872,8 @@ class panelPlugin:
if not softInfo['fpm']:
softInfo['status'] = True
elif softInfo['status'] and os.path.exists(pid_file):
if not self.pids: self.pids = psutil.pids()
try:
if not int(public.readFile(pid_file)) in self.pids:
softInfo['status'] = False
softInfo['status'] = public.pid_exists(int(public.readFile(pid_file)))
except:
if os.path.exists(pid_file):
os.remove(pid_file)
@@ -877,10 +883,10 @@ class panelPlugin:
if not softInfo['status']: softInfo['status'] = self.process_exists('mariadbd')
if softInfo['name'] == 'phpmyadmin': softInfo['status'] = self.get_phpmyadmin_stat()
if softInfo['name'] == 'openlitespeed':
if public.ExecShell('ps aux|grep openlitespeed|grep -v "grep"')[0]:
softInfo['status'] = True
else:
softInfo['status'] = False
pid_file = '/run/openlitespeed.pid'
if os.path.exists(pid_file):
pid = int(public.readFile(pid_file))
softInfo['status'] = public.pid_exists(pid)
return softInfo
def get_php_status(self,phpversion):
@@ -1033,7 +1039,22 @@ class panelPlugin:
#进程是否存在
def process_exists(self,pname,exe = None):
if not self.pids: self.pids = psutil.pids() #self.get_pids() #
if pname in ['mysqld','mariadbd']:
datadir = public.get_datadir()
if datadir:
pid_file = "{}/{}.pid".format(datadir,public.get_hostname())
if os.path.exists(pid_file):
pid = int(public.readFile(pid_file))
status = public.pid_exists(pid)
if status: return status
if pname in ['php-fpm'] and exe:
pid_file = exe.replace('sbin/php-fpm','/var/run/php-fpm.pid')
if os.path.exists(pid_file):
pid = int(public.readFile(pid_file))
return public.pid_exists(pid)
if not self.pids: self.pids = psutil.pids()
for pid in self.pids:
try:
l = '/proc/%s/exe' % pid
@@ -1312,18 +1333,20 @@ class panelPlugin:
if not pluginInfo:
import json
pluginInfo = json.loads(public.readFile(self.__install_path + '/' + get.name + '/info.json'))
if pluginInfo['tip'] == 'lib':
if not os.path.exists(self.__install_path+ '/' + pluginInfo['name']): public.ExecShell('mkdir -p ' + self.__install_path + '/' + pluginInfo['name'])
download_url = session['download_url'] + '/install/plugin/' + pluginInfo['name'] + '/install.sh'
toFile = self.__install_path + '/' + pluginInfo['name'] + '/uninstall.sh'
public.downloadFile(download_url,toFile)
self.set_pyenv(toFile)
public.ExecShell('/bin/bash ' + toFile + ' uninstall')
public.ExecShell('rm -rf ' + session['download_url'] + '/install/plugin/' + pluginInfo['name'])
install_sh = self.__install_path + '/' + pluginInfo['name'] + '/install.sh'
if not os.path.exists(toFile) and not os.path.exists(install_sh):
public.downloadFile(download_url,toFile)
self.set_pyenv(toFile)
pluginPath = self.__install_path + '/' + pluginInfo['name']
if os.path.exists(pluginPath + '/install.sh'):
if os.path.exists(toFile):
public.ExecShell('/bin/bash {} uninstall'.format(toFile))
elif os.path.exists(pluginPath + '/install.sh'):
public.ExecShell('/bin/bash ' + pluginPath + '/install.sh uninstall')
if os.path.exists(pluginPath):
@@ -1773,8 +1796,92 @@ class panelPlugin:
def getConfigHtml(self,get):
filename = self.__install_path + '/' + get.name + '/index.html'
if not os.path.exists(filename): return public.returnMsg(False,'PLUGIN_GET_HTML')
srcBody = public.readFile(filename,'r')
return srcBody
mimetype = 'text/html'
cache_time = 0 if public.is_debug() else 86400
self.plugin_open_total(get.name)
return send_file(filename,
mimetype = mimetype,
as_attachment = True,
add_etags = True,
conditional = True,
cache_timeout = cache_time)
def creatab_open_total_table(self,sql):
'''
@name 创建插件打开统计表
@author hwliang<2021-06-26>
@param sql<db.Sql> 数据库对像
@return void
'''
if not sql.table('sqlite_master').where('type=? AND name=?', ('table', 'open_total')).count():
csql = '''CREATE TABLE IF NOT EXISTS `open_total` (
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
`plugin_name` REAL,
`num` INTEGER
)'''
sql.execute(csql,())
def plugin_open_total(self,plugin_name):
'''
@name 插件打开统计
@author hwliang<2021-06-26>
@param plugin_name<string> 插件名称
@return void
'''
import db
sql = db.Sql().dbfile('plugin_total')
self.creatab_open_total_table(sql)
pdata = {
"plugin_name":plugin_name,
"num":1
}
num = sql.table('open_total').where('plugin_name=?',plugin_name).getField('num')
if not num:
sql.table('open_total').insert(pdata)
else:
sql.table('open_total').where('plugin_name=?',plugin_name).setField('num',num+1)
def get_usually_plugin(self,get):
'''
@name 获取常用插件
@author hwliang<2021-06-26>
@param get<obj_dict>
@return list
'''
import db
sql = db.Sql().dbfile('plugin_total')
self.creatab_open_total_table(sql)
plugin_list = sql.table('open_total').order('num desc').limit(10).select()
usually_list = []
for p in plugin_list:
plugin_info = self.get_soft_find(p['plugin_name'])
if plugin_info:
if plugin_info['setup']:
usually_list.append(plugin_info)
if len(usually_list) >= 5: break
return usually_list
def get_plugin_upgrades(self,get):
'''
@name 获取指定插件的近期更新历史
@author hwliang<2021-06-30>
@param get<obj_dict>{
plugin_name: string 插件名称
}
@return list
'''
plugin_name = get.plugin_name
if getattr(get,'show',0):
plugin_info = self.__get_plugin_find(plugin_name)
if plugin_info and 'versions' in plugin_info:
return plugin_info['versions']
return []
else:
return self.__get_plugin_upgrades(plugin_name)
#取插件信息
def getPluginInfo(self,get):
@@ -1840,7 +1947,7 @@ class panelPlugin:
def getCloudPlugin(self,get):
if session.get('getCloudPlugin') and get != None: return public.returnMsg(True,'PLUGIN_UPDATE_ERR1',("-1",))
import json
if not session.get('download_url'): session['download_url'] = 'http://download.bt.cn'
if not session.get('download_url'): session['download_url'] = 'https://node.aapanel.com'
#获取列表
try:
+4 -29
View File
@@ -29,8 +29,6 @@ class panelSSL:
_check_url = None
#构造方法
def __init__(self):
# pdata = {}
# data = {}
if os.path.exists(self.__UPATH):
my_tmp = public.readFile(self.__UPATH)
if my_tmp:
@@ -40,20 +38,6 @@ class panelSSL:
self.__userInfo = {}
else:
self.__userInfo = {}
# try:
# if self.__userInfo:
# pdata['access_key'] = self.__userInfo['access_key']
# data['secret_key'] = self.__userInfo['secret_key']
# except:
# self.__userInfo = {}
# pdata['access_key'] = 'test'
# data['secret_key'] = '123456'
# else:
# pdata['access_key'] = 'test'
# data['secret_key'] = '123456'
# pdata['data'] = data
# self.__PDATA = pdata
def en_code_rsa(self, data):
pk = public.readFile(self.__PUBKEY)
@@ -503,7 +487,7 @@ class panelSSL:
#检查域名是否解析
def CheckDomain(self,get):
try:
epass = public.GetRandomString(32)
#创建目录
spath = get.path + '/.well-known/pki-validation'
if not os.path.exists(spath): public.ExecShell("mkdir -p '" + spath + "'")
@@ -520,9 +504,10 @@ class panelSSL:
result = http_requests.get(self._check_url,s_type='curl',timeout=6,headers={"host":get.domain}).text
self.__test = result
if result == epass: return True
self._check_url = self._check_url.replace('127.0.0.1', get.domain)
return False
except:
self._check_url = self._check_url.replace('127.0.0.1', get.domain)
return False
#确认域名
@@ -663,17 +648,7 @@ class panelSSL:
if not tmp: continue
tmp1 = json.loads(tmp)
data.append(tmp1)
if not data:
lets_file = '/www/server/panel/config/letsencrypt.json'
tmp = public.readFile(ltes_file)
if not tmp:
return []
tmp = json(tmp)
for i in tmp['orders']:
data.append({"domains":tmp['orders'][i]['domains'],
"notAfter":tmp['orders'][i]['cert_timeout'],
"save_path":tmp['orders'][i]['save_path']
})
return data
except:
return []
+132 -60
View File
@@ -487,6 +487,10 @@ include /www/server/panel/vhost/openlitespeed/proxy/BTSITENAME/*.conf
import json, files
get.path = self.__get_site_format_path(get.path)
if not public.check_site_path(get.path):
a,c = public.get_sys_path()
return public.returnMsg(False,'Please do not set the website root directory to the system main directory:<br> {}'.format("<br>".join(a+c)))
try:
siteMenu = json.loads(get.webname)
except:
@@ -520,10 +524,9 @@ include /www/server/panel/vhost/openlitespeed/proxy/BTSITENAME/*.conf
domain = None
# if siteMenu['count']:
# domain = get.domain.replace(' ','')
# 表单验证
if not files.files().CheckDir(self.sitePath) or not self.__check_site_path(
self.sitePath): return public.returnMsg(False, 'PATH_ERROR')
if len(self.phpVersion) < 2: return public.returnMsg(False, 'SITE_ADD_ERR_PHPEMPTY')
#表单验证
if not self.__check_site_path(self.sitePath): return public.returnMsg(False,'PATH_ERROR')
if len(self.phpVersion) < 2: return public.returnMsg(False,'SITE_ADD_ERR_PHPEMPTY')
reg = r"^([\w\-\*]{1,100}\.){1,4}([\w\-]{1,24}|[\w\-]{1,24}\.[\w\-]{1,24})$"
if not re.match(reg, self.siteName): return public.returnMsg(False, 'SITE_ADD_ERR_DOMAIN')
if self.siteName.find('*') != -1: return public.returnMsg(False, 'SITE_ADD_ERR_DOMAIN_TOW')
@@ -600,13 +603,12 @@ set $bt_safe_open "{}/:/tmp/";'''.format(self.sitePath)
get.ps = self.siteName
firewalls.firewalls().AddAcceptPort(get)
if not hasattr(get, 'type_id'): get.type_id = 0
if not hasattr(get,'type_id'): get.type_id = 0
public.check_domain_cloud(self.siteName)
#写入数据库
get.pid = sql.table('sites').add('name,path,status,ps,type_id,addtime',(self.siteName,self.sitePath,'1',ps,get.type_id,public.getDate()))
# 写入数据库
get.pid = sql.table('sites').add('name,path,status,ps,type_id,addtime',
(self.siteName, self.sitePath, '1', ps, get.type_id, public.getDate()))
# 添加更多域名
#添加更多域名
for domain in siteMenu['domainlist']:
get.domain = domain
get.webname = self.siteName
@@ -1045,6 +1047,7 @@ set $bt_safe_open "{}/:/tmp/";'''.format(self.sitePath)
firewalls.firewalls().AddAcceptPort(get)
if not multiple:
public.serviceReload()
public.check_domain_cloud(get.domain)
public.WriteLog('TYPE_SITE', 'DOMAIN_ADD_SUCCESS', (get.webname, get.domain))
sql.table('domain').add('pid,name,port,addtime', (get.id, get.domain, get.port, public.getDate()))
@@ -1642,11 +1645,20 @@ listener Default%s{
# 获取TLS1.3标记
def get_tls13(self):
nginx_bin = '/www/server/nginx/sbin/nginx'
nginx_v = public.ExecShell(nginx_bin + ' -V 2>&1|grep version:')[0]
nginx_v = re.search('nginx/1\.1(5|6|7|8|9).\d', nginx_v)
openssl_v = public.ExecShell(nginx_bin + ' -V 2>&1|grep OpenSSL')[0].find('OpenSSL 1.1.') != -1
if nginx_v and openssl_v:
return ' TLSv1.3'
nginx_v = public.ExecShell(nginx_bin + ' -V 2>&1')[0]
nginx_v_re = re.findall("nginx/(\d\.\d+).+OpenSSL\s+(\d\.\d+)",nginx_v,re.DOTALL)
if nginx_v_re:
if nginx_v_re[0][0] in ['1.8','1.9','1.7','1.6','1.5','1.4']:
return ''
if float(nginx_v_re[0][0]) >= 1.15 and float(nginx_v_re[0][-1]) >= 1.1:
return ' TLSv1.3'
else:
_v = re.search('nginx/1\.1(5|6|7|8|9).\d',nginx_v)
if not _v:
_v = re.search('nginx/1\.2\d\.\d',nginx_v)
openssl_v = public.ExecShell(nginx_bin + ' -V 2>&1|grep OpenSSL')[0].find('OpenSSL 1.1.') != -1
if _v and openssl_v:
return ' TLSv1.3'
return ''
# 获取apache反向代理
@@ -2567,8 +2579,8 @@ listener SSL443 {
if conf:
listen_ipv6 = ''
if self.is_ipv6: listen_ipv6 = "\n listen [::]:%s;" % port
rep = "enable-php-([0-9]{2,3})\.conf"
tmp = re.search(rep, conf).groups()
rep = "enable-php-(\w{2,5})\.conf"
tmp = re.search(rep,conf).groups()
version = tmp[0]
bindingConf = '''
#BINDING-%s-START
@@ -2889,9 +2901,10 @@ server
Path = self.GetPath(get.path)
if Path == "" or id == '0': return public.returnMsg(False, "DIR_EMPTY")
import files
if not files.files().CheckDir(Path) or not self.__check_site_path(Path): return public.returnMsg(False,
"PATH_ERROR")
if not self.__check_site_path(Path): return public.returnMsg(False,"PATH_ERROR")
if not public.check_site_path(Path):
a, c = public.get_sys_path()
return public.returnMsg(False,'Please do not set the website root directory to the system main directory: <br>{}'.format("<br>".join(a+c)))
SiteFind = public.M("sites").where("id=?", (id,)).field('path,name').find()
if SiteFind["path"] == Path: return public.returnMsg(False, "SITE_PATH_ERR_RE")
@@ -2929,33 +2942,41 @@ server
public.set_site_open_basedir_nginx(Name)
public.serviceReload()
public.M("sites").where("id=?", (id,)).setField('path', Path)
public.WriteLog('TYPE_SITE', 'SITE_PATH_SUCCESS', (Name,))
return public.returnMsg(True, "SET_SUCCESS")
public.M("sites").where("id=?",(id,)).setField('path',Path)
public.WriteLog('TYPE_SITE', 'SITE_PATH_SUCCESS',(Name,))
return public.returnMsg(True, "SET_SUCCESS")
# 取当前可用PHP版本
def GetPHPVersion(self, get):
phpVersions = ('00', '52', '53', '54', '55', '56', '70', '71', '72', '73', '74', '80')
#取当前可用PHP版本
def GetPHPVersion(self,get):
phpVersions = ('00','other','52','53','54','55','56','70','71','72','73','74','80')
httpdVersion = ""
filename = self.setupPath + '/apache/version.pl'
if os.path.exists(filename): httpdVersion = public.readFile(filename).strip()
if httpdVersion == '2.2': phpVersions = ('00', '52', '53', '54')
if httpdVersion == '2.4': phpVersions = ('00', '53', '54', '55', '56', '70', '71', '72', '73', '74', '80')
if httpdVersion == '2.2': phpVersions = ('00','52','53','54')
if httpdVersion == '2.4': phpVersions = ('00','other','53','54','55','56','70','71','72','73','74','80')
if os.path.exists('/www/server/nginx/sbin/nginx'):
cfile = '/www/server/nginx/conf/enable-php-00.conf'
if not os.path.exists(cfile): public.writeFile(cfile, '')
if not os.path.exists(cfile): public.writeFile(cfile,'')
s_type = getattr(get,'s_type',0)
data = []
for val in phpVersions:
tmp = {}
checkPath = self.setupPath + '/php/' + val + '/bin/php'
if val == '00': checkPath = '/etc/init.d/bt'
if httpdVersion == '2.2': checkPath = self.setupPath + '/php/' + val + '/libphp5.so'
checkPath = self.setupPath+'/php/'+val+'/bin/php'
if val in ['00','other']: checkPath = '/etc/init.d/bt'
if httpdVersion == '2.2': checkPath = self.setupPath+'/php/'+val+'/libphp5.so'
if os.path.exists(checkPath):
tmp['version'] = val
tmp['name'] = 'PHP-' + val
if val == '00': tmp['name'] = public.getMsg('STATIC')
tmp['name'] = 'PHP-'+val
if val == '00':
tmp['name'] = public.getMsg('STATIC')
if val == 'other':
if s_type:
tmp['name'] = 'Customize'
else:
continue
data.append(tmp)
return data
@@ -2969,6 +2990,12 @@ server
data['tomcat'] = conf.find('#TOMCAT-START')
data['tomcatversion'] = public.readFile(self.setupPath + '/tomcat/version.pl')
data['nodejsversion'] = public.readFile(self.setupPath + '/node.js/version.pl')
data['php_other'] = ''
if data['phpversion'] == 'other':
other_file = '/www/server/panel/vhost/other_php/{}/enable-php-other.conf'.format(siteName)
if os.path.exists(other_file):
conf = public.readFile(other_file)
data['php_other'] = re.findall(r"fastcgi_pass\s+(.+);",conf)[0]
return data
except:
return public.returnMsg(False, 'SITE_PHPVERSION_ERR_A22,{}'.format(public.get_error_info()))
@@ -3006,15 +3033,57 @@ server
def SetPHPVersion(self, get, multiple=None):
siteName = get.siteName
version = get.version
if version == 'other' and not public.get_webserver() in ['nginx','tengine']:
return public.returnMsg(False,'Custom PHP configuration only supports Nginx')
try:
# nginx
file = self.setupPath + '/panel/vhost/nginx/' + siteName + '.conf'
conf = public.readFile(file)
if conf:
rep = "enable-php-([0-9]{2,3})\.conf"
tmp = re.search(rep, conf).group()
conf = conf.replace(tmp, 'enable-php-' + version + '.conf')
public.writeFile(file, conf)
other_path = '/www/server/panel/vhost/other_php/{}'.format(siteName)
if not os.path.exists(other_path): os.makedirs(other_path)
other_rep = "{}/enable-php-other.conf".format(other_path)
if version == 'other':
dst = other_rep
get.other = get.other.strip()
if not get.other:
return public.returnMsg(False,'The PHP connection configuration cannot be empty when customizing the version!')
if not re.match(r"^(\d+\.\d+\.\d+\.\d+:\d+|unix:[\w/\.-]+)$",get.other):
return public.returnMsg(False,'The PHP connection configuration format is incorrect, please refer to the example!')
other_tmp = get.other.split(':')
if other_tmp[0] == 'unix':
if not os.path.exists(other_tmp[1]):
return public.returnMsg(False,'The specified unix socket [{}] does not exist!'.format(other_tmp[1]))
else:
if not public.check_tcp(other_tmp[0],int(other_tmp[1])):
return public.returnMsg(False,'Unable to connect to [{}], please check whether the machine can connect to the target server'.format(get.other))
other_conf = '''location ~ [^/]\.php(/|$)
{{
try_files $uri =404;
fastcgi_pass {};
fastcgi_index index.php;
include fastcgi.conf;
include pathinfo.conf;
}}'''.format(get.other)
public.writeFile(other_rep,other_conf)
conf = conf.replace(other_rep,dst)
rep = "include\s+enable-php-(\w{2,5})\.conf"
tmp = re.search(rep,conf)
if tmp: conf = conf.replace(tmp.group(),'include ' + dst)
else:
dst = 'enable-php-'+version+'.conf'
conf = conf.replace(other_rep,dst)
rep = "enable-php-(\w{2,5})\.conf"
tmp = re.search(rep,conf)
if tmp: conf = conf.replace(tmp.group(),dst)
public.writeFile(file,conf)
try:
import site_dir_auth
site_dir_auth_module = site_dir_auth.SiteDirAuth()
@@ -3028,23 +3097,25 @@ server
site_dir_auth_module.change_dir_auth_file_nginx_phpver(siteName,version,auth_name)
except:
pass
# apache
file = self.setupPath + '/panel/vhost/apache/' + siteName + '.conf'
#apache
file = self.setupPath + '/panel/vhost/apache/'+siteName+'.conf'
conf = public.readFile(file)
if conf:
rep = "(unix:/tmp/php-cgi-([0-9]{2,3})\.sock\|fcgi://localhost|fcgi://127.0.0.1:\d+)"
tmp = re.search(rep, conf).group()
conf = conf.replace(tmp, public.get_php_proxy(version, 'apache'))
public.writeFile(file, conf)
# OLS
file = self.setupPath + '/panel/vhost/openlitespeed/detail/' + siteName + '.conf'
conf = public.readFile(file)
if conf:
rep = 'lsphp\d+'
tmp = re.search(rep, conf)
if tmp:
conf = conf.replace(tmp.group(), 'lsphp' + version)
public.writeFile(file, conf)
if conf and version != 'other':
rep = "(unix:/tmp/php-cgi-(\w{2,5})\.sock\|fcgi://localhost|fcgi://127.0.0.1:\d+)"
tmp = re.search(rep,conf).group()
conf = conf.replace(tmp,public.get_php_proxy(version,'apache'))
public.writeFile(file,conf)
#OLS
if version != 'other':
file = self.setupPath + '/panel/vhost/openlitespeed/detail/'+siteName+'.conf'
conf = public.readFile(file)
if conf:
rep = 'lsphp\d+'
tmp = re.search(rep, conf)
if tmp:
conf = conf.replace(tmp.group(), 'lsphp' + version)
public.writeFile(file, conf)
if not multiple:
public.serviceReload()
public.WriteLog("TYPE_SITE", "SITE_PHPVERSION_SUCCESS", (siteName, version))
@@ -3162,12 +3233,10 @@ server
return json.loads(upBody)
# 写配置
def __write_config(self, path, data):
return public.writeFile(path, json.dumps(data))
# 取某个站点某条反向代理详情
def GetProxyDetals(self, get):
proxyUrl = self.__read_config(self.__proxyfile)
sitename = get.sitename
@@ -3306,7 +3375,6 @@ server
if i["sitename"] == get.sitename:
if i["advanced"] != int(get.advanced):
return i
# 计算proxyname md5
def __calc_md5(self, proxyname):
md5 = hashlib.md5()
@@ -3368,8 +3436,8 @@ server
return public.returnMsg(False, "PROXY_DIR_ERR", ("?,=,[,],),(,*,&,^,%,$,#,@,!,~,`,{,},>,<,\,',\"]",))
# 检测发送域名格式
if get.todomain:
if not re.search(tod, get.todomain):
return public.returnMsg(False, 'SENT_DOMAIN_FORMAT', (get.todomain,))
if re.search("[\}\{\#\;\"\']+",get.todomain):
return public.returnMsg(False, 'Sent Domain format error :'+get.todomain+'<br>The following special characters cannot exist [ } { # ; \" \' ] ')
if public.get_webserver() != 'openlitespeed' and not get.todomain:
get.todomain = "$host"
@@ -3648,7 +3716,11 @@ RewriteRule ^%s(.*)$ http://%s/$1 [P,E=Proxy-Host:%s]
ng_conf = re.sub("location\s+\~\*\s+\\\.\(gif.*\n\{\s*proxy_pass\s+%s.*" % (php_pass_proxy),
"location ~* \.(gif|png|jpg|css|js|woff|woff2)$\n{\n\tproxy_pass %s;" % php_pass_proxy,ng_conf)
ng_conf = re.sub("\sHost\s+%s" % '\\' + conf[i]["todomain"]," Host "+get.todomain,ng_conf)
backslash = ""
if "Host $host" in ng_conf:
backslash = "\\"
ng_conf = re.sub("\sHost\s+%s" % backslash + conf[i]["todomain"], " Host " + get.todomain, ng_conf)
cache_rep = r"proxy_cache_valid\s+200\s+304\s+301\s+302\s+\d+m;((\n|.)+expires\s+\d+m;)*"
if int(get.cache) == 1:
if re.search(cache_rep, ng_conf):
+550 -97
View File
@@ -49,7 +49,6 @@ def HttpGet(url,timeout = 6,headers = {}):
import http_requests
res = http_requests.get(url,timeout=timeout,headers = headers)
if res.status_code == 0:
if old_url.find(home) != -1: return http_get_home(old_url,timeout,res.text)
if headers: return False
s_body = res.text
return s_body
@@ -113,43 +112,12 @@ def HttpPost(url,data,timeout = 6,headers = {}):
import http_requests
res = http_requests.post(url,data=data,timeout=timeout,headers = headers)
if res.status_code == 0:
if old_url.find(home) != -1: return http_post_home(old_url,data,timeout,res.text)
if headers: return False
s_body = res.text
return s_body
s_body = res.text
return s_body
def http_post_home(url,data,timeout,ex):
"""
@name POST方式使用优选节点访问官网
@author hwliang<hwl@bt.cn>
@param url(string) 当前官网URL地址
@param data(dict) POST数据
@param timeout(int) 用于测试超时时间
@param ex(string) 上一次错误的响应内容
@return string 响应内容
如果已经是优选节点将直接返回ex
"""
try:
home = 'www.bt.cn'
if url.find(home) == -1: return ex
hosts_file = "config/hosts.json"
if not os.path.exists(hosts_file): return ex
hosts = json.loads(readFile(hosts_file))
headers = {"host": home}
for host in hosts:
new_url = url.replace(home, host)
res = HttpPost(new_url, data, timeout, headers)
if res:
writeFile("data/home_host.pl", host)
# set_home_host(host)
return res
return ex
except: return ex
def httpPost(url,data,timeout=6):
"""
@name 发送POST请求
@@ -200,7 +168,6 @@ def FileMd5(filename):
f.close()
return my_hash.hexdigest()
def GetRandomString(length):
"""
@name 取随机字符串
@@ -336,6 +303,13 @@ def ReadFile(filename,mode = 'r'):
return f_body
def readFile(filename,mode='r'):
'''
@name 读取指定文件数据
@author hwliang<2021-06-09>
@param filename<string> 文件名
@param mode<string> 文件打开模式默认r
@return string or bytes or False 如果返回False则说明读取失败
'''
return ReadFile(filename,mode)
def WriteFile(filename,s_body,mode='w+'):
@@ -360,6 +334,14 @@ def WriteFile(filename,s_body,mode='w+'):
return False
def writeFile(filename,s_body,mode='w+'):
'''
@name 写入到指定文件
@author hwliang<2021-06-09>
@param filename<string> 文件名
@param s_boey<string/bytes> 被写入的内容字节或字符串
@param mode<string> 文件打开模式默认w+
@return bool
'''
return WriteFile(filename,s_body,mode)
def WriteLog(type,logMsg,args=(),not_web = False):
@@ -409,7 +391,9 @@ def GetConfigValue(key):
取配置值
'''
config = GetConfig()
if not key in config.keys(): return None
if not key in config.keys():
if key == 'download': return 'https://node.aapanel.com'
return None
return config[key]
def SetConfigValue(key,value):
@@ -495,7 +479,7 @@ def serviceReload():
return ServiceReload()
def ExecShell(cmdstring, cwd=None, timeout=None, shell=True):
def ExecShell(cmdstring, timeout=None, shell=True,cwd=None,env=None):
a = ''
e = ''
import subprocess,tempfile
@@ -504,8 +488,20 @@ def ExecShell(cmdstring, cwd=None, timeout=None, shell=True):
rx = md5(cmdstring)
succ_f = tempfile.SpooledTemporaryFile(max_size=4096,mode='wb+',suffix='_succ',prefix='btex_' + rx ,dir='/dev/shm')
err_f = tempfile.SpooledTemporaryFile(max_size=4096,mode='wb+',suffix='_err',prefix='btex_' + rx ,dir='/dev/shm')
sub = subprocess.Popen(cmdstring, close_fds=True, shell=shell,bufsize=128,stdout=succ_f,stderr=err_f)
sub.wait()
sub = subprocess.Popen(cmdstring, close_fds=True, shell=shell,bufsize=128,stdout=succ_f,stderr=err_f,cwd=cwd,env=env)
if timeout:
s = 0
d = 0.01
while sub.poll() is None:
time.sleep(d)
s += d
if s >= timeout:
if not err_f.closed: err_f.close()
if not succ_f.closed: succ_f.close()
return 'Timed out'
else:
sub.wait()
err_f.seek(0)
succ_f.seek(0)
a = succ_f.read()
@@ -513,7 +509,7 @@ def ExecShell(cmdstring, cwd=None, timeout=None, shell=True):
if not err_f.closed: err_f.close()
if not succ_f.closed: succ_f.close()
except:
print(get_error_info())
return '',get_error_info()
try:
#编码修正
if type(a) == bytes: a = a.decode('utf-8')
@@ -600,7 +596,9 @@ def phpReload(version):
if os.path.exists('/www/server/php/' + version + '/libphp5.so'):
ExecShell('/etc/init.d/httpd reload')
else:
ExecShell('/etc/init.d/php-fpm-' + version + ' reload')
ExecShell('/etc/init.d/php-fpm-'+version+' reload')
ExecShell("/etc/init.d/php-fpm-{} start".format(version))
def get_timeout(url,timeout=3):
try:
@@ -610,6 +608,8 @@ def get_timeout(url,timeout=3):
except: return 0,False
def get_url(timeout = 0.5):
return 'https://node.aapanel.com'
import json
try:
pkey = 'node_url'
@@ -824,6 +824,9 @@ def getSpeed():
writeFile('/tmp/panelSpeed.pl', data)
return json.loads(data)
def get_requests_headers():
return {"Content-type":"application/x-www-form-urlencoded","User-Agent":"BT-Panel"}
def downloadFile(url,filename):
try:
if sys.version_info[0] == 2:
@@ -834,16 +837,30 @@ def downloadFile(url,filename):
f.write(r.content)
else:
import urllib.request
import ssl
ssl._create_default_https_context = ssl._create_unverified_context
opener = urllib.request.build_opener()
opener.addheaders = [('User-agent', 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.135 Safari/537.36')]
urllib.request.install_opener(opener)
urllib.request.urlretrieve(url, filename=filename, reporthook=downloadHook)
urllib.request.urlretrieve(url, filename=filename)
except:
return get_error_info()
ExecShell("wget -O --no-check-certificate {} {}".format(filename,url))
def exists_args(args,get):
'''
@name 检查参数是否存在
@author hwliang<2021-06-08>
@param args<list or str> 参数列表 允许是列表或字符串
@param get<dict_obj> 参数对像
@return bool 都存在返回True否则抛出KeyError异常
'''
if type(args) == str:
args = args.split(',')
for arg in args:
if not arg in get:
raise KeyError('Required parameters are missing:{}'.format(arg))
return True
def downloadHook(count, blockSize, totalSize):
speed = {'total':totalSize,'block':blockSize,'count':count}
#print('%02d%%'%(100.0 * count * blockSize / totalSize))
def get_error_info():
import traceback
@@ -851,6 +868,78 @@ def get_error_info():
return errorMsg
def get_plugin_replace_rules():
'''
@name 获取插件文件内容替换规则
@author hwliang<2021-06-28>
@return list
'''
return [
{
"find":"[PATH]",
"replace": "[PATH]"
}
]
def get_plugin_title(plugin_name):
'''
@name 获取插件标题
@author hwliang<2021-06-24>
@param plugin_name<string> 插件名称
@return string
'''
info_file = '/www/server/panel/plugin/{}/info.json'.format(plugin_name)
try:
return json.loads(readFile(info_file))['title']
except:
return plugin_name
def get_error_object(plugin_title = None,plugin_name = None):
'''
@name 获取格式化错误响应对像
@author hwliang<2021-06-21>
@return Resp
'''
if not plugin_title: plugin_title = get_plugin_title(plugin_name)
try:
from BTPanel import request,Resp
is_cli = False
except:
is_cli = True
if is_cli:
raise get_error_info()
ss = '''404 Not Found: The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again.
During handling of the above exception, another exception occurred:'''
error_info = get_error_info().strip().split(ss)[-1].strip()
request_info = '''REQUEST_DATE: {request_date}
PAN_VERSION: {panel_version}
OS_VERSION: {os_version}
REMOTE_ADDR: {remote_addr}
REQUEST_URI: {method} {full_path}
REQUEST_FORM: {request_form}
USER_AGENT: {user_agent}'''.format(
request_date = getDate(),
remote_addr = GetClientIp(),
method = request.method,
full_path = request.full_path,
request_form = request.form.to_dict(),
user_agent = request.headers.get('User-Agent'),
panel_version = get_panel_version(),
os_version = get_os_version()
)
result =readFile('/www/server/panel/BTPanel/templates/default/plugin_error.html').format(
plugin_name=plugin_title,
request_info=request_info,
error_title=error_info.split("\n")[-1],
error_msg=error_info
)
return Resp(result,500)
# 搜索数据中是否存在
def inArray(arrays, searchStr):
for key in arrays:
@@ -1233,6 +1322,22 @@ def get_uuid():
import uuid
return uuid.UUID(int=uuid.getnode()).hex[-12:]
#取计算机名
def get_hostname():
import socket
return socket.gethostname()
#取mysql datadir
def get_datadir():
mycnf_file = '/etc/my.cnf'
if not os.path.exists(mycnf_file): return ''
mycnf = readFile(mycnf_file)
import re
tmp = re.findall(r"datadir\s*=\s*(.+)",mycnf)
if not tmp: return ''
return tmp[0]
#进程是否存在
def process_exists(pname,exe = None,cmdline = None):
@@ -1253,8 +1358,13 @@ def process_exists(pname,exe = None,cmdline = None):
except:
pass
return False
except:
except: return True
#pid是否存在
def pid_exists(pid):
if os.path.exists('/proc/{}/exe'.format(pid)):
return True
return False
# 重启面板
@@ -1359,18 +1469,79 @@ def get_panel_version():
return version
# 取文件或目录大小
def get_path_size(path):
def get_os_version():
'''
@name 取操作系统版本
@author hwliang<2021-08-07>
@return string
'''
version = readFile('/etc/redhat-release')
if not version:
version = readFile('/etc/issue').strip().split("\n")[0].replace('\\n','').replace('\l','').strip()
else:
version = version.replace('release ','').replace('Linux','').replace('(Core)','').strip()
v_info = sys.version_info
version = "{} {}(Py{}.{}.{})".format(version,os.uname().machine,v_info.major,v_info.minor,v_info.micro)
return version
#取文件或目录大小
def get_path_size(path, exclude=[]):
"""根据排除目录获取路径的总大小
:path 目标路径
:exclude 排除路径单个字符串或者多个列表匹配路径是基于path的相对路径,规则是
tar命令的--exclude规则的子集
"""
import fnmatch
if not os.path.exists(path): return 0
if not os.path.isdir(path): return os.path.getsize(path)
size_total = 0
for nf in os.walk(path):
for f in nf[2]:
filename = nf[0] + '/' + f
if os.path.isfile(path): return os.path.getsize(path)
if type(exclude) != type([]):
exclude = [exclude]
path = path[0:-1] if path[-1] == "/" else path
path = os.path.normcase(path)
# print("path:"+ path)
# print("exclude:"+ str(exclude))
_exclude = exclude[0:]
for i, e in enumerate(_exclude):
if not e.startswith(path):
basename = os.path.basename(path)
if not e.startswith(basename):
exclude.append(os.path.join(path, e))
else:
new_exc = e.replace(basename+"/", "")
new_exc = os.path.join(path, new_exc)
exclude.append(new_exc)
# print(exclude)
total_size = 0
count = 0
for root, dirs, files in os.walk(path, topdown=True):
# filter path
for exc in exclude:
for d in dirs:
sub_dir = os.path.normcase(root+os.path.sep+d)
if fnmatch.fnmatch(sub_dir, exc) or d==exc:
# print("排除目录:"+sub_dir)
dirs.remove(d)
count += 1
for f in files:
to_exclude = False
count += 1
filename = os.path.normcase(root+os.path.sep+f)
if not os.path.exists(filename): continue
if os.path.islink(filename): continue
size_total += os.path.getsize(filename)
return size_total
# filter file
norm_filename = os.path.normcase(filename)
for fexc in exclude:
if fnmatch.fnmatch(norm_filename, fexc) or fexc==f:
to_exclude = True
# print("排除文件:"+norm_filename)
break
if to_exclude:
continue
total_size += os.path.getsize(filename)
return total_size
#写关键请求日志
def write_request_log(reques = None):
@@ -1533,22 +1704,54 @@ def de_crypt(key,strings):
return strings
#获取IP限制列表
def get_limit_ip():
iplong_list = []
ip_file = 'data/limitip.conf'
if not os.path.exists(ip_file): return iplong_list
from BTPanel import cache
ikey = 'limit_ip'
iplong_list = cache.get(ikey)
if iplong_list: return iplong_list
iplong_list = []
iplist = ReadFile(ip_file)
if not iplist:return iplong_list
iplist = iplist.strip()
for limit_ip in iplist.split(','):
if not limit_ip: continue
limit_ip = limit_ip.split('-')
iplong = {}
iplong['min'] = ip2long(limit_ip[0])
if len(limit_ip) > 1:
iplong['max'] = ip2long(limit_ip[1])
else:
iplong['max'] = iplong['min']
iplong_list.append(iplong)
cache.set(ikey,iplong_list,3600)
return iplong_list
#检查IP白名单
def check_ip_panel():
ip_file = 'data/limitip.conf'
if os.path.exists(ip_file):
iplist = ReadFile(ip_file)
if iplist:
iplist = iplist.strip()
client_ip = GetClientIp()
if client_ip in ['127.0.0.1','localhost','::1']: return False
if not client_ip in iplist.split(','):
errorStr = ReadFile('./BTPanel/templates/' + GetConfigValue('template') + '/error2.html')
try:
errorStr = errorStr.format(getMsg('PAGE_ERR_TITLE'),getMsg('PAGE_ERR_IP_H1'),getMsg('PAGE_ERR_IP_P1',(GetClientIp(),)),getMsg('PAGE_ERR_IP_P2'),getMsg('PAGE_ERR_IP_P3'),getMsg('NAME'),getMsg('PAGE_ERR_HELP'))
except IndexError:pass
return errorStr
return False
iplong_list = get_limit_ip()
if not iplong_list: return False
client_ip = GetClientIp()
if client_ip in ['127.0.0.1','localhost','::1']: return False
client_ip_long = ip2long(client_ip)
for limit_ip in iplong_list:
if client_ip_long >= limit_ip['min'] and client_ip_long <= limit_ip['max']:
return False
errorStr = ReadFile('./BTPanel/templates/' + GetConfigValue('template') + '/error2.html')
try:
errorStr = errorStr.format(getMsg('PAGE_ERR_TITLE'),getMsg('PAGE_ERR_IP_H1'),getMsg('PAGE_ERR_IP_P1',(GetClientIp(),)),getMsg('PAGE_ERR_IP_P2'),getMsg('PAGE_ERR_IP_P3'),getMsg('NAME'),getMsg('PAGE_ERR_HELP'))
except IndexError:pass
return errorStr
#检查面板域名
def check_domain_panel():
@@ -1625,7 +1828,7 @@ def sync_date():
if os.path.exists(tip_file):
if s_time - int(readFile(tip_file)) < 60: return False
os.remove(tip_file)
time_str = HttpGet('http://www.bt.cn/api/index/get_time')
time_str = HttpGet(GetConfigValue('home') + '/api/index/get_time')
new_time = int(time_str)
time_arr = time.localtime(new_time)
date_str = time.strftime("%Y-%m-%d %H:%M:%S", time_arr)
@@ -1724,7 +1927,7 @@ def request_php(version,uri,document_root,method='GET',pdata=b''):
return result
def get_fpm_address(php_version):
def get_fpm_address(php_version,bind=False):
'''
@name 获取FPM请求地址
@author hwliang<2020-10-23>
@@ -1740,7 +1943,10 @@ def get_fpm_address(php_version):
if tmp[0].find('sock') != -1: return fpm_address
if tmp[0].find(':') != -1:
listen_tmp = tmp[0].split(':')
fpm_address = ('127.0.0.1',int(listen_tmp[1]))
if bind:
fpm_address = (listen_tmp[0],int(listen_tmp[1]))
else:
fpm_address = ('127.0.0.1',int(listen_tmp[1]))
else:
fpm_address = ('127.0.0.1',int(tmp[0]))
return fpm_address
@@ -1777,7 +1983,7 @@ def get_php_version_conf(conf):
'''
if not conf: return '00'
if conf.find('enable-php-') != -1:
rep = r"enable-php-([0-9]{2,3})\.conf"
rep = r"enable-php-(\w{2,5})\.conf"
tmp = re.findall(rep,conf)
if not tmp: return '00'
elif conf.find('/usr/local/lsws/lsphp') != -1:
@@ -1809,6 +2015,25 @@ def get_site_php_version(siteName):
return get_php_version_conf(conf)
def check_tcp(ip,port):
'''
@name 使用TCP的方式检测指定IP:端口是否能连接
@author hwliang<2021-06-01>
@param ip<string> IP地址
@param port<int> 端口
@return bool
'''
import socket
try:
s = socket.socket()
s.settimeout(5)
s.connect((ip.strip(),int(port)))
s.close()
except:
return False
return True
def sub_php_address(conf_file,rep,tsub,php_version):
'''
@name 替换新的PHP配置到配置文件
@@ -2070,9 +2295,10 @@ def get_debug_log():
#获取sessionid
def get_session_id():
from BTPanel import request
session_id = request.cookies.get('SESSIONID','')
if not re.findall(r"^([\w\.-]{64,64})$",session_id): return GetRandomString(64)
from BTPanel import request,app
session_id = request.cookies.get(app.config['SESSION_COOKIE_NAME'],'')
if not re.findall(r"^([\w\.-]{64,64})$",session_id):
return GetRandomString(64)
return session_id
#尝试自动恢复面板数据库
@@ -2200,11 +2426,14 @@ def get_ssh_port():
s_file = '/etc/ssh/sshd_config'
conf = readFile(s_file)
if not conf: conf = ''
rep = r"#*Port\s+([0-9]+)\s*\n"
tmp1 = re.search(rep, conf)
port_all = re.findall(r".*Port\s+[0-9]+",conf)
ssh_port = 22
if tmp1:
ssh_port = int(tmp1.groups(0)[0])
for p in port_all:
rep = r"^\s*Port\s+([0-9]+)\s*"
tmp1 = re.findall(rep,p)
if tmp1:
ssh_port = int(tmp1[0])
return ssh_port
def set_error_num(key,empty = False,expire=3600):
@@ -2386,6 +2615,8 @@ def cloud_check_domain(domain):
check_domain_path = '/www/server/panel/data/check_domain/'
if not os.path.exists(check_domain_path):
os.makedirs(check_domain_path,384)
pdata = get_user_info()
pdata['domain'] = domain
result = httpPost('https://www.aapanel.com/api/panel/checkDomain',{"domain":domain})
cd_file = check_domain_path + domain +'.pl'
writeFile(cd_file,result)
@@ -2393,6 +2624,23 @@ def cloud_check_domain(domain):
pass
def get_user_info():
user_file = '/www/server/panel/data/userInfo.json'
if not os.path.exists(user_file): return {}
userInfo = {}
try:
userTmp = json.loads(readFile(user_file))
userInfo['uid'] = userTmp['id']
userInfo['username'] = userTmp['username']
userInfo['serverid'] = userTmp['serverid']
userInfo['oem'] = get_oem_name()
userInfo['o'] = userInfo['oem']
except: pass
return userInfo
def send_file(data,fname='',mimetype = ''):
'''
@name 以文件流的形式返回
@@ -2449,12 +2697,41 @@ def get_oem_name():
@return string
'''
oem = ''
oem_file = '/www/server/panel/data/o.pl'
oem_file = '{}/data/o.pl'.format(get_panel_path())
if os.path.exists(oem_file):
oem = readFile(oem_file)
if oem: oem = oem.strip()
return oem
def get_pdata():
'''
@name 构造POST基础参数
@author hwliang<2021-03-24>
@return dict
'''
import panelAuth
pdata = panelAuth.panelAuth().create_serverid(None)
pdata['oem'] = get_oem_name()
return pdata
# 名称输入系列化
def xssdecode(text):
try:
cs = {"&quot":'"',"&#x27":"'"}
for c in cs.keys():
text = text.replace(c,cs[c])
str_convert = text
if sys.version_info[0] == 3:
import html
text2 = html.unescape(str_convert)
else:
text2 = cgi.unescape(str_convert)
return text2
except:
return text
def fetch_disk_SN():
r,e = ExecShell("fdisk -l |grep 'Disk identifier' |awk {'print $3'}")
if r:
@@ -2511,6 +2788,8 @@ class dict_obj:
def __delitem__(self,key): delattr(self,key)
def __delattr__(self, key): delattr(self,key)
def get_items(self): return self
def exists(self,keys):
return exists_args(keys,self)
def get(self,key,default='',format='',limit = []):
'''
@name 获取指定参数
@@ -2659,7 +2938,7 @@ class get_modules:
else:
print(p.__dict__)
'''
os.chdir('/www/server/panel')
os.chdir(get_panel_path())
exp_files = ['__init__.py','__pycache__']
if not path in sys.path:
sys.path.insert(0,path)
@@ -2685,7 +2964,7 @@ class get_modules:
#检查App和小程序的绑定
def check_app(check='app'):
path='/www/server/panel/'
path=get_panel_path() + '/'
if check=='app':
try:
if not os.path.exists(path+'data/user.json') and os.path.exists(path+'config/api.json') and not os.path.exists(path+'plugin/app/user.json'):return False
@@ -2723,8 +3002,8 @@ def send_mail(title,body,is_logs=False,is_type="aapanel login reminder"):
import send_mail
send_mail22 = send_mail.send_mail()
tongdao = send_mail22.get_settings()
if tongdao['user_mail']['mail_list']==0:return false
if not tongdao['user_mail']['info']: return false
if tongdao['user_mail']['mail_list']==0:return False
if not tongdao['user_mail']['info']: return False
if len(tongdao['user_mail']['mail_list'])==1:
send_mail=tongdao['user_mail']['mail_list'][0]
send_mail22.qq_smtp_send(send_mail, title=title, body=body)
@@ -2739,8 +3018,8 @@ def send_mail(title,body,is_logs=False,is_type="aapanel login reminder"):
import send_mail
send_mail22 = send_mail.send_mail()
tongdao = send_mail22.get_settings()
if tongdao['user_mail']['mail_list'] == 0: return false
if not tongdao['user_mail']['info']: return false
if tongdao['user_mail']['mail_list'] == 0: return False
if not tongdao['user_mail']['info']: return False
if len(tongdao['user_mail']['mail_list']) == 1:
send_mail = tongdao['user_mail']['mail_list'][0]
return send_mail22.qq_smtp_send(send_mail, title=title, body=body)
@@ -2756,7 +3035,7 @@ def send_dingding(body,is_logs=False,is_type="aapanel login reminder"):
import send_mail
send_mail22 = send_mail.send_mail()
tongdao = send_mail22.get_settings()
if not tongdao['dingding']['info']: return false
if not tongdao['dingding']['info']: return False
tongdao = send_mail22.get_settings()
if is_logs:
WriteLog2(is_type,body)
@@ -2768,15 +3047,16 @@ def send_dingding(body,is_logs=False,is_type="aapanel login reminder"):
import send_mail
send_mail22 = send_mail.send_mail()
tongdao = send_mail22.get_settings()
if not tongdao['dingding']['info']: return false
if not tongdao['dingding']['info']: return False
tongdao = send_mail22.get_settings()
return send_mail22.dingding_send(body)
except:return False
#获取服务器IP
def get_ip():
if os.path.exists('/www/server/panel/data/iplist.txt'):
data=ReadFile('/www/server/panel/data/iplist.txt')
iplist_file = '{}/data/iplist.txt'.format(get_panel_path())
if os.path.exists(iplist_file):
data=ReadFile(iplist_file)
return data.strip()
else:return '127.0.0.1'
@@ -2825,11 +3105,14 @@ def check_ip_white(path,ip):
#登陆告警
def login_send_body(is_type,username,login_ip,port):
if os.path.exists("/www/server/panel/data/login_send_mail.pl"):
if check_ip_white('/www/server/panel/data/send_login_white.json',login_ip):return False
login_send_mail = "{}/data/login_send_mail.pl".format(get_panel_path())
send_login_white = '{}/data/send_login_white.json'.format(get_panel_path())
login_send_dingding = "{}/data/login_send_dingding.pl".format(get_panel_path())
if os.path.exists(login_send_mail):
if check_ip_white(send_login_white,login_ip):return False
send_mail("aapanel login reminder","aapanel login reminderYour server "+get_ip()+" successfully logged in via "+is_type+", account number: "+username+", login IP: "+login_ip+":"+port+", login time: "+time.strftime('%Y -%m-%d %X',time.localtime()), True)
if os.path.exists("/www/server/panel/data/login_send_dingding.pl"):
if check_ip_white('/www/server/panel/data/send_login_white.json',login_ip):return False
if os.path.exists(login_send_dingding):
if check_ip_white(send_login_white,login_ip):return False
send_dingding("aapanel login reminderYour server "+get_ip()+" successfully logged in via "+is_type+", account number: "+username+", login IP: "+login_ip+":"+port+", login time: "+time.strftime('%Y -%m-%d %X',time.localtime()), True)
#普通模式下调用发送消息【设置登陆告警后的设置】
@@ -2838,11 +3121,14 @@ def login_send_body(is_type,username,login_ip,port):
#is_logs= 是否记录日志
#is_type=发送告警的类型
def send_to_body(title,body,is_logs=False,is_type="aaPanel email alert"):
if os.path.exists("/www/server/panel/data/login_send_mail.pl"):
login_send_mail = "{}/data/login_send_mail.pl".format(get_panel_path())
login_send_dingding = "{}/data/login_send_dingding.pl".format(get_panel_path())
if os.path.exists(login_send_mail):
if is_logs:
send_mail(title, body,True,is_type)
send_mail(title,body)
if os.path.exists("/www/server/panel/data/login_send_dingding.pl"):
if os.path.exists(login_send_dingding):
if is_logs:
send_dingding(body,True,is_type)
send_dingding(body)
@@ -2864,4 +3150,171 @@ def return_is_send_info():
ret={}
ret['mail']=tongdao['user_mail']['user_name']
ret['dingding']=tongdao['dingding']['dingding']
return ret
return ret
def get_sys_path():
'''
@name 关键目录
@author hwliang<2021-06-11>
@return tuple
'''
a = ['/www','/usr','/','/dev','/home','/media','/mnt','/opt','/tmp','/var']
c = ['/www/Recycle_bin/','/www/backup/','/www/php_session/','/www/wwwlogs/','/www/server/','/etc/','/usr/','/var/','/boot/','/proc/','/sys/','/tmp/','/root/','/lib/','/bin/','/sbin/','/run/','/lib64/','/lib32/','/srv/']
return a,c
def check_site_path(site_path):
'''
@name 检查网站根目录是否为系统关键目录
@author hwliang<2021-05-31>
@param site_path<string> 网站根目录全路径
@return bool
'''
whites = ['/www/server/tomcat','/www/server/stop','/www/server/phpmyadmin']
for w in whites:
if site_path.find(w) == 0: return True
a,error_paths = get_sys_path()
site_path = site_path.strip()
if site_path[-1] == '/': site_path = site_path[:-1]
if site_path in a:
return False
site_path += '/'
for ep in error_paths:
if site_path.find(ep) == 0: return False
return True
def is_debug():
debug_file = "{}/data/debug.pl".format(get_panel_path())
return os.path.exists(debug_file)
class PanelError(Exception):
'''
@name 宝塔通用异常对像
@author hwliang<2021-06-25>
'''
def __init__(self, value):
self.value = value
def __str__(self):
return ("面板运行时发生错误: {}".format(repr(self.value)))
def get_setup_path():
'''
@name 获取安装路径
@author hwliang<2021-07-22>
@return string
'''
return '/www/server'
def get_panel_path():
'''
@name 取面板根目录
@author hwliang<2021-07-14>
@return string
'''
return '{}/panel'.format(get_setup_path())
def check_hooks():
'''
@name 自动注册HOOK
@author hwliang<2021-07-19>
@return void
'''
hooks_path = '{}/hooks'.format(get_panel_path())
if not os.path.exists(hooks_path):
return
for hook_name in os.listdir(hooks_path):
if hook_name[-3:] != '.py': continue
filename = os.path.join(hooks_path,hook_name)
_obj = get_script_object(filename)
_main = getattr(_obj,'main',None)
if not _main: continue
_main()
def register_hook(hook_index, hook_def):
'''
@name 注册HOOK
@author hwliang<2021-07-15>
@param hook_index<string> HOOK位置
@param hook_def<def> HOOK函数对像
@return void
'''
from BTPanel import hooks
hook_keys = hooks.keys()
if not hook_index in hook_keys:
hooks[hook_index] = []
if not hook_def in hooks[hook_index]:
hooks[hook_index].append(hook_def)
def exec_hook(hook_index, data):
'''
@name 执行HOOk
@author hwliang<2021-07-15>
@param hook_index<string> HOOK索引位置格式限制^\w+$
@param data<mixed> 运行数据
@return mixed
'''
from BTPanel import hooks
hook_keys = hooks.keys()
if not hook_index in hook_keys:
return data
for hook_def in hooks[hook_index]:
data = hook_def(data)
return data
def get_hook_index(mod_name, def_name):
'''
@name 获取HOOK位置
@author hwliang<2021-07-19>
@param mod_name<string> 模块名称
@param def_name<string> 方法名称
@return tuple
'''
mod_name = mod_name.upper()
def_name = def_name.upper()
last_index = '{}_{}_LAST'.format(mod_name, def_name)
end_index = '{}_{}_END'.format(mod_name, def_name)
return last_index, end_index
def get_session_timeout():
'''
@name 获取session过期时间
@author hwliang<2021-07-28>
@return int
'''
from BTPanel import cache
skey = 'session_timeout'
session_timeout = cache.get(skey)
if not session_timeout is None: return session_timeout
sess_out_path = '{}/data/session_timeout.pl'.format(get_panel_path())
session_timeout = 86400
if not os.path.exists(sess_out_path):
return session_timeout
session_timeout = int(readFile(sess_out_path))
cache.set(skey,session_timeout,3600)
return session_timeout
def get_login_token_auth():
'''
@name 获取登录token
@author hwliang<2021-07-28>
@return string
'''
from BTPanel import cache
skey = 'login_token'
login_token = cache.get(skey)
if not login_token is None: return login_token
login_token_file = '{}/data/login_token.pl'.format(get_panel_path())
login_token = '1234567890'
if not os.path.exists(login_token_file):
return login_token
login_token = readFile(login_token_file)
cache.set(skey,login_token,3600)
return login_token
+1 -1
View File
@@ -85,7 +85,7 @@ class setPanelLets:
gcl = pssl.GetCertList(get)
for i in gcl:
for v in i.values():
if get.domain in v:
if get.domain == v:
try:
time_stamp = int(i['notAfter'])
except:
+37 -25
View File
@@ -123,9 +123,9 @@ class SiteDirAuth:
try:
conf = public.readFile(self.setup_path + '/panel/vhost/'+public.get_webserver()+'/'+siteName+'.conf');
if public.get_webserver() == 'nginx':
rep = "enable-php-([0-9]{2,3})\.conf"
rep = "enable-php-(\w{2,5})\.conf"
else:
rep = "php-cgi-([0-9]{2,3})\.sock"
rep = "php-cgi-(\w{2,5})\.sock"
tmp = re.search(rep,conf).groups()
if tmp:
return tmp[0]
@@ -145,8 +145,15 @@ class SiteDirAuth:
conf = public.readFile(file_path)
if not conf:
return False
rep = "include\s+enable-php-\d+\.conf;"
conf = re.sub(rep,'include enable-php-{}.conf;'.format(phpv),conf)
if phpv == 'other':
php_conf = "include /www/server/panel/vhost/other_php/{}/enable-php-other.conf;".format(site_name)
else:
php_conf = 'include enable-php-{}.conf;'.format(phpv)
rep = r"include\s+(enable-php-\w+|/www/server/panel/vhost/other_php/{}/enable-php-other)\.conf;".format(site_name)
conf = re.sub(rep,php_conf,conf)
public.writeFile(file_path,conf)
# 设置独立认证文件
@@ -154,7 +161,11 @@ class SiteDirAuth:
php_ver = self.get_site_php_version(site_name)
php_conf = ""
if php_ver:
php_conf = "include enable-php-{}.conf;".format(php_ver)
if php_ver == 'other':
php_conf = "include /www/server/panel/vhost/other_php/{}/enable-php-{}.conf;".format(site_name,php_ver)
else:
php_conf = "include enable-php-{}.conf;".format(php_ver)
for i in ["nginx","apache"]:
file_path = "{setup_path}/panel/vhost/{webserver}/dir_auth/{site_name}"
if i == "nginx":
@@ -242,26 +253,27 @@ class SiteDirAuth:
site_info = self.get_site_info(get.id)
site_name = site_info["site_name"]
conf = self._read_conf()
if site_name in conf:
for i in range(len(conf[site_name])):
if name in conf[site_name][i].values():
print(conf[site_name][i])
del(conf[site_name][i])
if not conf[site_name]:
del(conf[site_name])
break
public.writeFile(self.conf_file,json.dumps(conf))
for i in ["nginx", "apache"]:
file_path = "{setup_path}/panel/vhost/{webserver}/dir_auth/{site_name}/{name}.conf".format(webserver=i,
setup_path=self.setup_path,
site_name=site_name,
name=name)
os.remove(file_path)
if not conf:
self.set_conf(site_name,"delete")
if not hasattr(get,'multiple'):
public.serviceReload()
return public.returnMsg(True,"DEL_SUCCESS")
if site_name not in conf:
return public.returnMsg(False,"The website does not exist in the configuration{}".format(site_name))
for i in range(len(conf[site_name])):
if name in conf[site_name][i].values():
print(conf[site_name][i])
del(conf[site_name][i])
if not conf[site_name]:
del(conf[site_name])
break
public.writeFile(self.conf_file,json.dumps(conf))
for i in ["nginx", "apache"]:
file_path = "{setup_path}/panel/vhost/{webserver}/dir_auth/{site_name}/{name}.conf".format(webserver=i,
setup_path=self.setup_path,
site_name=site_name,
name=name)
os.remove(file_path)
if not conf:
self.set_conf(site_name,"delete")
if not hasattr(get,'multiple'):
public.serviceReload()
return public.returnMsg(True,"DEL_SUCCESS")
# 修改目录保护密码
def modify_dir_auth_pass(self,get):
+60 -6
View File
@@ -47,6 +47,7 @@ class ssh_terminal:
_tp = None
_old_conf = None
_debug_file = 'logs/terminal.log'
_s_code = None
def connect(self):
'''
@@ -123,8 +124,16 @@ class ssh_terminal:
pkey = paramiko.DSSKey.from_private_key(p_file)
self._tp.auth_publickey(username=self._user, key=pkey)
else:
self.debug(public.getMsg('AUTH_PASSWD'))
self._tp.auth_password(username=self._user, password=self._pass)
try:
self._tp.auth_none(self._user)
except Exception as e:
e = str(e)
if e.find('keyboard-interactive') >= 0:
self._auth_interactive()
else:
self.debug('Authenticating password')
self._tp.auth_password(username=self._user, password=self._pass)
# self._tp.auth_password(username=self._user, password=self._pass)
except Exception as e:
if self._old_conf:
s_file = '/www/server/panel/config/t_info.json'
@@ -132,6 +141,11 @@ class ssh_terminal:
self.set_sshd_config(True)
self._tp.close()
e = str(e)
if e.find('websocket error!') != -1:
return returnMsg(True,'connection succeeded')
if e.find('Authentication timeout') != -1:
self.debug("认证超时{}".format(e))
return returnMsg(False,'Authentication timed out, please press enter to try again!{}'.format(e))
if e.find('Authentication failed') != -1:
self.debug(public.getMsg('AUTH_FAIL',(str(e),)))
return returnMsg(False,'SSH_LOGIN_ERR1',(str(e + "," + self._user + "@" + self._host + ":" +str(self._port)),))
@@ -167,6 +181,40 @@ class ssh_terminal:
self.debug('SSH_LOGIN_INFO2')
return returnMsg(True,'CONNECTION_SUCCEEDED')
def _auth_interactive(self):
self.debug('Verification Code')
self.brk = False
def handler(title, instructions, prompt_list):
if not self._ws: raise public.PanelError('websocket error!')
if instructions:
self._ws.send(instructions)
if title:
self._ws.send(title)
resp = []
for pr in prompt_list:
if str(pr[0]).strip() == "Password:":
resp.append(self._pass)
elif str(pr[0]).strip() == "Verification code:":
# 获取前段传入的验证码
self._ws.send("Verification code# ")
self._s_code = True
code = ""
while True:
data = self._ws.receive()
if data.find('"resize":1') != -1:
self.resize(data)
continue
self._ws.send(data)
if data in ["\n", "\r"]: break
code += data
resp.append(code)
self._ws.send("\n")
self._s_code = None
return tuple(resp)
self._tp.auth_interactive(self._user, handler)
def get_login_user(self):
'''
@@ -349,7 +397,6 @@ class ssh_terminal:
@return bool
'''
self.is_running(rep)
return False
if rep and not self._rep_ssh_config:
return False
@@ -490,6 +537,9 @@ class ssh_terminal:
'''
try:
while not self._ws.closed:
if self._s_code:
time.sleep(0.1)
continue
client_data = self._ws.receive()
if not client_data: continue
if len(client_data) > 10:
@@ -588,7 +638,8 @@ class ssh_terminal:
try:
if self._ssh:
self._ssh.close()
#self._ssh = None
if self._tp: # 关闭宿主服务
self._tp.close()
if not self._ws.closed:
self._ws.close()
except:
@@ -609,8 +660,11 @@ class ssh_terminal:
self._pkey = ssh_info['pkey']
if 'password' in ssh_info:
self._pass = ssh_info['password']
result = self.connect()
try:
result = self.connect()
except Exception as ex:
if str(ex).find("NoneType") == -1:
raise public.PanelError(ex)
return result
+39 -67
View File
@@ -127,46 +127,46 @@ class system:
data['web'] = tmp
tmp = {}
vfile = self.setupPath + '/phpmyadmin/version.pl';
tmp['version'] = public.readFile(vfile);
vfile = self.setupPath + '/phpmyadmin/version.pl'
tmp['version'] = public.readFile(vfile)
if tmp['version']: tmp['version'] = tmp['version'].strip()
tmp['setup'] = os.path.exists(vfile);
tmp['status'] = pstatus;
tmp['phpversion'] = phpversion.strip();
tmp['port'] = phpport;
tmp['auth'] = pauth;
data['phpmyadmin'] = tmp;
tmp['setup'] = os.path.exists(vfile)
tmp['status'] = pstatus
tmp['phpversion'] = phpversion.strip()
tmp['port'] = phpport
tmp['auth'] = pauth
data['phpmyadmin'] = tmp
tmp = {}
tmp['setup'] = os.path.exists('/etc/init.d/tomcat');
tmp['setup'] = os.path.exists('/etc/init.d/tomcat')
tmp['status'] = tmp['setup']
#if public.ExecShell('ps -aux|grep tomcat|grep -v grep')[0] == "": tmp['status'] = False
tmp['version'] = public.readFile(self.setupPath + '/tomcat/version.pl');
data['tomcat'] = tmp;
tmp['version'] = public.readFile(self.setupPath + '/tomcat/version.pl')
data['tomcat'] = tmp
tmp = {}
tmp['setup'] = os.path.exists(self.setupPath +'/mysql/bin/mysql');
tmp['version'] = public.readFile(self.setupPath + '/mysql/version.pl');
tmp['setup'] = os.path.exists(self.setupPath +'/mysql/bin/mysql')
tmp['version'] = public.readFile(self.setupPath + '/mysql/version.pl')
tmp['status'] = os.path.exists('/tmp/mysql.sock')
data['mysql'] = tmp
tmp = {}
tmp['setup'] = os.path.exists(self.setupPath +'/redis/runtest');
tmp['status'] = os.path.exists('/var/run/redis_6379.pid');
data['redis'] = tmp;
tmp['setup'] = os.path.exists(self.setupPath +'/redis/runtest')
tmp['status'] = os.path.exists('/var/run/redis_6379.pid')
data['redis'] = tmp
tmp = {}
tmp['setup'] = os.path.exists('/usr/local/memcached/bin/memcached');
tmp['status'] = os.path.exists('/var/run/memcached.pid');
data['memcached'] = tmp;
tmp['setup'] = os.path.exists('/usr/local/memcached/bin/memcached')
tmp['status'] = os.path.exists('/var/run/memcached.pid')
data['memcached'] = tmp
tmp = {}
tmp['setup'] = os.path.exists(self.setupPath +'/pure-ftpd/bin/pure-pw');
tmp['version'] = public.readFile(self.setupPath + '/pure-ftpd/version.pl');
tmp['setup'] = os.path.exists(self.setupPath +'/pure-ftpd/bin/pure-pw')
tmp['version'] = public.readFile(self.setupPath + '/pure-ftpd/version.pl')
tmp['status'] = os.path.exists('/var/run/pure-ftpd.pid')
data['pure-ftpd'] = tmp
data['panel'] = self.GetPanelInfo()
data['systemdate'] = public.ExecShell('date +"%Y-%m-%d %H:%M:%S %Z %z"')[0].strip();
data['systemdate'] = public.format_date("%Y-%m-%d %H:%M:%S %Z %z") #public.ExecShell('date +"%Y-%m-%d %H:%M:%S %Z %z"')[0].strip()
return data
@@ -176,15 +176,15 @@ class system:
try:
port = public.GetHost(True)
except:
port = '8888';
port = '8888'
domain = ''
if os.path.exists('data/domain.conf'):
domain = public.readFile('data/domain.conf');
domain = public.readFile('data/domain.conf')
autoUpdate = ''
if os.path.exists('data/autoUpdate.pl'): autoUpdate = 'checked';
if os.path.exists('data/autoUpdate.pl'): autoUpdate = 'checked'
limitip = ''
if os.path.exists('data/limitip.conf'): limitip = public.readFile('data/limitip.conf');
if os.path.exists('data/limitip.conf'): limitip = public.readFile('data/limitip.conf')
admin_path = '/'
if os.path.exists('data/admin_path.pl'): admin_path = public.readFile('data/admin_path.pl').strip()
@@ -193,8 +193,8 @@ class system:
# if os.path.isdir('templates/' + template): templates.append(template);
template = public.GetConfigValue('template')
check502 = '';
if os.path.exists('data/502Task.pl'): check502 = 'checked';
check502 = ''
if os.path.exists('data/502Task.pl'): check502 = 'checked'
return {'port':port,'address':address,'domain':domain,'auto':autoUpdate,'502':check502,'limitip':limitip,'templates':templates,'template':template,'admin_path':admin_path}
def GetPHPConfig(self,version):
@@ -373,9 +373,13 @@ class system:
def GetMemInfo(self,get=None):
#取内存信息
skey = 'memInfo'
memInfo = cache.get(skey)
if memInfo: return memInfo
mem = psutil.virtual_memory()
memInfo = {'memTotal':int(mem.total/1024/1024),'memFree':int(mem.free/1024/1024),'memBuffers':int(mem.buffers/1024/1024),'memCached':int(mem.cached/1024/1024)}
memInfo['memRealUsed'] = memInfo['memTotal'] - memInfo['memFree'] - memInfo['memBuffers'] - memInfo['memCached']
cache.set(skey,memInfo,60)
return memInfo
def GetDiskInfo(self,get=None):
@@ -428,7 +432,7 @@ class system:
except Exception as ex:
public.WriteLog('GET_INFO',str(ex))
continue
cache.set(key,diskInfo,360)
cache.set(key,diskInfo,10)
return diskInfo
@@ -483,7 +487,6 @@ class system:
cache.set(iokey,{'info':diskio_2,'time':mtime})
except:
public.writeFile('/tmp/2',str(public.get_error_info()))
return diskInfo
return diskInfo
@@ -625,8 +628,11 @@ class system:
def get_cpu_times(self):
data = {}
skey = 'cpu_times'
data = cache.get(skey)
if data:return data
try:
data = {}
cpu_times_p = psutil.cpu_times_percent()
data['user'] = cpu_times_p.user
data['nice'] = cpu_times_p.nice
@@ -649,7 +655,8 @@ class system:
continue
data['total_processes'] += 1
except: pass
cache.set(skey,data,60)
except: return None
return data
@@ -921,38 +928,10 @@ class system:
#重启面板
def ReWeb(self,get):
#s = time.time()
#if not self.shell: self.connect_ssh()
#self.shell.send("nohup /etc/init.d/bt restart && sleep 1 && /etc/init.d/bt start > /dev/null &\n")
#public.ExecShell("nohup sleep 2 && /etc/init.d/bt restart 2>&1 >/dev/null &")
public.ExecShell("/etc/init.d/bt start")
public.writeFile('data/restart.pl','True')
return public.returnMsg(True,'PANEL_WAS_RESTART')
def connect_ssh(self):
import paramiko
self.ssh = paramiko.SSHClient()
self.ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
try:
self.ssh.connect('127.0.0.1', public.GetSSHPort())
except:
if public.GetSSHStatus():
try:
self.ssh.connect('localhost', public.GetSSHPort())
except:
return False
import firewalls
fw = firewalls.firewalls()
get = public.dict_obj()
get.status = '0'
fw.SetSshStatus(get)
self.ssh.connect('127.0.0.1', public.GetSSHPort())
get.status = '1'
fw.SetSshStatus(get)
self.shell = self.ssh.invoke_shell(term='xterm', width=100, height=29)
self.shell.setblocking(0)
return True
#修复面板
def RepPanel(self,get):
@@ -966,10 +945,3 @@ class system:
public.ExecShell("wget -O update.sh " + public.get_url() + "/install/update6_en.sh && bash update.sh")
self.ReWeb(None)
return True
+4 -6
View File
@@ -106,8 +106,7 @@ class userlogin:
self.limit_address('-')
cache.delete('panelNum')
cache.delete('dologin')
sess_input_path = 'data/session_last.pl'
public.writeFile(sess_input_path,str(int(time.time())))
session['session_timeout'] = time.time() + public.get_session_timeout()
del(data['tmp_token'])
del(data['tmp_time'])
public.writeFile(save_path,json.dumps(data))
@@ -157,8 +156,7 @@ class userlogin:
self.limit_address('-')
cache.delete('panelNum')
cache.delete('dologin')
sess_input_path = 'data/session_last.pl'
public.writeFile(sess_input_path,str(int(time.time())))
session['session_timeout'] = time.time() + public.get_session_timeout()
self.set_request_token()
self.login_token()
self.set_cdn_host(get)
@@ -277,12 +275,12 @@ class userlogin:
session['login'] = True
session['username'] = userInfo['username']
session['uid'] = userInfo['id']
session['login_user_agent'] = public.md5(request.headers.get('User-Agent',''))
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')
sess_input_path = 'data/session_last.pl'
public.writeFile(sess_input_path,str(int(time.time())))
session['session_timeout'] = time.time() + public.get_session_timeout()
self.set_request_token()
self.login_token()
login_type = 'data/app_login.pl'
+34 -35
View File
@@ -58,28 +58,28 @@ class ScanLogin(object):
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")
secret_key, init_time = data.split(':')
if time.time() - float(init_time) < 60 and get['secret_key'] == secret_key:
sql = db.Sql()
userInfo = sql.table('users').where(
"id=?", (1,)).field('id,username,password').find()
session['login'] = True
session['username'] = userInfo['username']
cache.delete('panelNum')
cache.delete('dologin')
public.WriteLog('TYPE_LOGIN', 'LOGIN_SUCCESS',
('WeChat scan code login', public.GetClientIp()+ ":" + str(request.environ.get('REMOTE_PORT'))))
login_type = 'data/app_login.pl'
self.set_request_token()
import config
config.config().reload_session()
public.writeFile(login_type,'True')
public.login_send_body("Wechat program",userInfo['username'],public.GetClientIp(),str(request.environ.get('REMOTE_PORT')))
return public.returnMsg(True, 'login successful')
return public.returnMsg(False, 'Login failed')
# 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")
# secret_key, init_time = data.split(':')
# if time.time() - float(init_time) < 60 and get['secret_key'] == secret_key:
# sql = db.Sql()
# userInfo = sql.table('users').where(
# "id=?", (1,)).field('id,username,password').find()
# session['login'] = True
# session['username'] = userInfo['username']
# cache.delete('panelNum')
# cache.delete('dologin')
# public.WriteLog('TYPE_LOGIN', 'LOGIN_SUCCESS',
# ('微信扫码登录', public.GetClientIp()+ ":" + str(request.environ.get('REMOTE_PORT'))))
# login_type = 'data/app_login.pl'
# self.set_request_token()
# import config
# config.config().reload_session()
# public.writeFile(login_type,'True')
# public.login_send_body("微信小程序",userInfo['username'],public.GetClientIp(),str(request.environ.get('REMOTE_PORT')))
# return public.returnMsg(True, '登录成功')
return public.returnMsg(False, '登录失败')
#验证APP是否登录成功
@@ -107,8 +107,7 @@ class ScanLogin(object):
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())))
session['session_timeout'] = time.time() + public.get_session_timeout()
login_type = 'data/app_login.pl'
self.set_request_token()
import config
@@ -208,17 +207,17 @@ class wxapp(SelfModule, ScanLogin):
elif get['panel_token'] != password:
return public.returnMsg(False, 'SK_NOT_INCORRECT')
return True
else:
# 是否在白名单ip sgin 是否正确
if hasattr(get, 'uid') and hasattr(get, 'sgin') and hasattr(get, 'fun') and get['uid'] in self.user_info.keys():
encryption_str = self.user_info[get['uid']]['token']+get['fun']+get['uid']
if sys.version_info[0] == 3:
if type(encryption_str) == str:
encryption_str = encryption_str.encode()
if get['sgin'] == public.md5(binascii.hexlify(base64.b64encode(encryption_str))):
if public.GetClientIp() in ['47.52.194.186']:
return True
return public.returnMsg(False, 'UNAUTHORIZED')
# else:
# # 是否在白名单ip sgin 是否正确
# if hasattr(get, 'uid') and hasattr(get, 'sgin') and hasattr(get, 'fun') and get['uid'] in self.user_info.keys():
# encryption_str = self.user_info[get['uid']]['token']+get['fun']+get['uid']
# if sys.version_info[0] == 3:
# if type(encryption_str) == str:
# encryption_str = encryption_str.encode()
# if get['sgin'] == public.md5(binascii.hexlify(base64.b64encode(encryption_str))):
# if public.GetClientIp() in ['47.52.194.186']:
# return public.returnMsg(False, '未授权')
return public.returnMsg(False, 'UNAUTHORIZED')
# 用户绑定
def blind(self, get):
+790
View File
@@ -0,0 +1,790 @@
#!/bin/bash
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
LANG=en_US.UTF-8
cd ~
setup_path="/www"
SET_SSL=false
python_bin=$setup_path/server/panel/pyenv/bin/python
cpu_cpunt=$(cat /proc/cpuinfo|grep processor|wc -l)
if [ "$1" ];then
IDC_CODE=$1
fi
GetSysInfo(){
if [ -s "/etc/redhat-release" ];then
SYS_VERSION=$(cat /etc/redhat-release)
elif [ -s "/etc/issue" ]; then
SYS_VERSION=$(cat /etc/issue)
fi
SYS_INFO=$(uname -r)
SYS_BIT=$(getconf LONG_BIT)
MEM_TOTAL=$(free -m|grep Mem|awk '{print $2}')
CPU_INFO=$(getconf _NPROCESSORS_ONLN)
echo -e ${SYS_VERSION}
echo -e Bit:${SYS_BIT} Mem:${MEM_TOTAL}M Core:${CPU_INFO}
echo -e ${SYS_INFO}
echo -e "Please screenshot the above error message and post to the forum forum.aapanel.com for help"
}
Red_Error(){
echo '=================================================';
printf '\033[1;31;40m%b\033[0m\n' "$1";
GetSysInfo
exit 1;
}
is64bit=$(getconf LONG_BIT)
if [ "${is64bit}" != '64' ];then
Red_Error "Sorry, aaPanel Does not support 32-bit systems, Use 64-bit system Please!";
fi
Lock_Clear(){
if [ -f "/etc/bt_crack.pl" ];then
chattr -R -ia /www
chattr -ia /etc/init.d/bt
\cp -rpa /www/backup/panel/vhost/* /www/server/panel/vhost/
mv /www/server/panel/BTPanel/__init__.bak /www/server/panel/BTPanel/__init__.py
rm -f /etc/bt_crack.pl
fi
}
Install_Check(){
while [ "$yes" != 'yes' ] && [ "$yes" != 'n' ]
do
echo -e "----------------------------------------------------"
echo -e "Web service is alreday installed,installing aaPanel may affect existing sites."
echo -e "----------------------------------------------------"
read -p "Enter yes to force installation (yes/n): " yes;
done
if [ "$yes" == 'n' ];then
exit;
fi
}
System_Check(){
for serviceS in nginx httpd mysqld
do
if [ -f "/etc/init.d/${serviceS}" ]; then
if [ "${serviceS}" = "httpd" ]; then
serviceCheck=$(cat /etc/init.d/${serviceS}|grep /www/server/apache)
elif [ "${serviceS}" = "mysqld" ]; then
serviceCheck=$(cat /etc/init.d/${serviceS}|grep /www/server/mysql)
else
serviceCheck=$(cat /etc/init.d/${serviceS}|grep /www/server/${serviceS})
fi
[ -z "${serviceCheck}" ] && Install_Check
fi
done
}
Set_Ssl(){
echo -e ""
echo -e "----------------------------------------------------------------------"
echo -e "If you choose to enable SSL (self-signed certificate), you will use https access panel after installation."
echo -e "After logging in, you can go to the panel settings and change to Let's Encrypt certificate."
echo -e "----------------------------------------------------------------------"
echo -e ""
read -p "Do you need to enable the panel SSl ? (yes/n): " yes;
if [ "$yes" == "yes" ];then
SET_SSL=true
fi
if [ "$yes" != "yes" ] && [ $yes != "n" ];then
Set_Ssl
fi
}
Get_Pack_Manager(){
if [ -f "/usr/bin/yum" ] && [ -d "/etc/yum.repos.d" ]; then
PM="yum"
elif [ -f "/usr/bin/apt-get" ] && [ -f "/usr/bin/dpkg" ]; then
PM="apt-get"
fi
}
Auto_Swap()
{
swap=$(free |grep Swap|awk '{print $2}')
if [ "${swap}" -gt 1 ];then
echo "Swap total sizse: $swap";
return;
fi
if [ ! -d /www ];then
mkdir /www
fi
swapFile="/www/swap"
dd if=/dev/zero of=$swapFile bs=1M count=1025
mkswap -f $swapFile
swapon $swapFile
echo "$swapFile swap swap defaults 0 0" >> /etc/fstab
swap=`free |grep Swap|awk '{print $2}'`
if [ $swap -gt 1 ];then
echo "Swap total sizse: $swap";
return;
fi
sed -i "/\/www\/swap/d" /etc/fstab
rm -f $swapFile
}
Service_Add(){
if [ "${PM}" == "yum" ] || [ "${PM}" == "dnf" ]; then
chkconfig --add bt
chkconfig --level 2345 bt on
elif [ "${PM}" == "apt-get" ]; then
update-rc.d bt defaults
fi
}
get_node_url(){
if [ ! -f /bin/curl ];then
if [ "${PM}" = "yum" ]; then
yum install curl -y
elif [ "${PM}" = "apt-get" ]; then
apt-get install curl -y
fi
fi
echo '---------------------------------------------';
echo "Selected download node...";
nodes=(http://node.aapanel.com http://128.1.164.196 http://45.76.53.20 http://103.224.251.67 http://dg2.bt.cn http://dg1.bt.cn http://123.129.198.197 http://125.88.182.172:5880 http://119.188.210.21:5880 http://120.206.184.160 http://113.107.111.78);
tmp_file1=/dev/shm/net_test1.pl
tmp_file2=/dev/shm/net_test2.pl
[ -f "${tmp_file1}" ] && rm -f ${tmp_file1}
[ -f "${tmp_file2}" ] && rm -f ${tmp_file2}
touch $tmp_file1
touch $tmp_file2
for node in ${nodes[@]};
do
NODE_CHECK=$(curl --connect-timeout 3 -m 3 2>/dev/null -w "%{http_code} %{time_total}" ${node}/net_test|xargs)
RES=$(echo ${NODE_CHECK}|awk '{print $1}')
NODE_STATUS=$(echo ${NODE_CHECK}|awk '{print $2}')
TIME_TOTAL=$(echo ${NODE_CHECK}|awk '{print $3 * 1000 - 500 }'|cut -d '.' -f 1)
if [ "${NODE_STATUS}" == "200" ];then
if [ $TIME_TOTAL -lt 100 ];then
if [ $RES -ge 1500 ];then
echo "$RES $node" >> $tmp_file1
fi
else
if [ $RES -ge 1500 ];then
echo "$TIME_TOTAL $node" >> $tmp_file2
fi
fi
i=$(($i+1))
if [ $TIME_TOTAL -lt 100 ];then
if [ $RES -ge 3000 ];then
break;
fi
fi
fi
done
NODE_URL=$(cat $tmp_file1|sort -r -g -t " " -k 1|head -n 1|awk '{print $2}')
if [ -z "$NODE_URL" ];then
NODE_URL=$(cat $tmp_file2|sort -g -t " " -k 1|head -n 1|awk '{print $2}')
if [ -z "$NODE_URL" ];then
NODE_URL='http://download.bt.cn';
fi
fi
rm -f $tmp_file1
rm -f $tmp_file2
download_Url=$NODE_URL
echo "Download node: $download_Url";
echo '---------------------------------------------';
}
Remove_Package(){
local PackageNmae=$1
if [ "${PM}" == "yum" ];then
isPackage=$(rpm -q ${PackageNmae}|grep "not installed")
if [ -z "${isPackage}" ];then
yum remove ${PackageNmae} -y
fi
elif [ "${PM}" == "apt-get" ];then
isPackage=$(dpkg -l|grep ${PackageNmae})
if [ "${PackageNmae}" ];then
apt-get remove ${PackageNmae} -y
fi
fi
}
Install_RPM_Pack(){
yumPath=/etc/yum.conf
Centos8Check=$(cat /etc/redhat-release | grep ' 8.' | grep -iE 'centos|Red Hat')
isExc=$(cat $yumPath|grep httpd)
if [ "$isExc" = "" ];then
echo "exclude=httpd nginx php mysql mairadb python-psutil python2-psutil" >> $yumPath
fi
yumBaseUrl=$(cat /etc/yum.repos.d/CentOS-Base.repo|grep baseurl=http|cut -d '=' -f 2|cut -d '$' -f 1|head -n 1)
[ "${yumBaseUrl}" ] && checkYumRepo=$(curl --connect-timeout 5 --head -s -o /dev/null -w %{http_code} ${yumBaseUrl})
if [ "${checkYumRepo}" != "200" ];then
curl -Ss --connect-timeout 3 -m 60 http://download.bt.cn/install/yumRepo_select.sh|bash
fi
# 尝试同步时间(从bt.cn)
echo 'Synchronizing system time...'
getBtTime=$(curl -sS --connect-timeout 3 -m 60 http://www.bt.cn/api/index/get_time)
if [ "${getBtTime}" ];then
date -s "$(date -d @$getBtTime +"%Y-%m-%d %H:%M:%S")"
fi
#if [ -z "${Centos8Check}" ]; then
# yum install ntp -y
# rm -rf /etc/localtime
# ln -s /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
#尝试同步国际时间(从ntp服务器)
# ntpdate 0.asia.pool.ntp.org
# setenforce 0
#fi
startTime=`date +%s`
sed -i 's/SELINUX=enforcing/SELINUX=disabled/' /etc/selinux/config
#yum remove -y python-requests python3-requests python-greenlet python3-greenlet
yumPacks="libcurl-devel wget tar gcc make zip unzip openssl openssl-devel gcc libxml2 libxml2-devel libxslt* zlib zlib-devel libjpeg-devel libpng-devel libwebp libwebp-devel freetype freetype-devel lsof pcre pcre-devel vixie-cron crontabs icu libicu-devel c-ares libffi-devel bzip2-devel ncurses-devel sqlite-devel readline-devel tk-devel gdbm-devel db4-devel libpcap-devel xz-devel"
yum install -y ${yumPacks}
for yumPack in ${yumPacks}
do
rpmPack=$(rpm -q ${yumPack})
packCheck=$(echo ${rpmPack}|grep not)
if [ "${packCheck}" ]; then
yum install ${yumPack} -y
fi
done
if [ -f "/usr/bin/dnf" ]; then
dnf install -y redhat-rpm-config
fi
yum install epel-release -y
}
Install_Deb_Pack(){
ln -sf bash /bin/sh
apt-get update -y
apt-get install ruby -y
apt-get install lsb-release -y
#apt-get install ntp ntpdate -y
#/etc/init.d/ntp stop
#update-rc.d ntp remove
#cat >>~/.profile<<EOF
#TZ='Asia/Shanghai'; export TZ
#EOF
#rm -rf /etc/localtime
#cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
#echo 'Synchronizing system time...'
#ntpdate 0.asia.pool.ntp.org
#apt-get upgrade -y
for pace in wget curl libcurl4-openssl-dev gcc make zip unzip openssl libssl-dev gcc libxml2 libxml2-dev libxslt 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;
do apt-get -y install $pace --force-yes; done
if [ ! -d '/etc/letsencrypt' ];then
mkdir -p /etc/letsencryp
mkdir -p /var/spool/cron
if [ ! -f '/var/spool/cron/crontabs/root' ];then
echo '' > /var/spool/cron/crontabs/root
chmod 600 /var/spool/cron/crontabs/root
fi
fi
}
Install_Bt(){
panelPort="8888"
if [ -f ${setup_path}/server/panel/data/port.pl ];then
panelPort=$(cat ${setup_path}/server/panel/data/port.pl)
fi
mkdir -p ${setup_path}/server/panel/logs
mkdir -p ${setup_path}/server/panel/vhost/apache
mkdir -p ${setup_path}/server/panel/vhost/nginx
mkdir -p ${setup_path}/server/panel/vhost/rewrite
mkdir -p ${setup_path}/server/panel/install
mkdir -p /www/server
mkdir -p /www/wwwroot
mkdir -p /www/wwwlogs
mkdir -p /www/backup/database
mkdir -p /www/backup/site
if [ ! -f "/usr/bin/unzip" ]; then
if [ "${PM}" = "yum" ]; then
yum install unzip -y
elif [ "${PM}" = "apt-get" ]; then
apt-get install unzip -y
fi
fi
if [ -f "/etc/init.d/bt" ]; then
/etc/init.d/bt stop
sleep 1
fi
wget -O panel.zip ${download_Url}/install/src/panel6_en.zip -T 10
wget -O /etc/init.d/bt ${download_Url}/install/src/bt6_en.init -T 10
wget -O /www/server/panel/install/public.sh ${download_Url}/install/public.sh -T 10
if [ -f "${setup_path}/server/panel/data/default.db" ];then
if [ -d "/${setup_path}/server/panel/old_data" ];then
rm -rf ${setup_path}/server/panel/old_data
fi
mkdir -p ${setup_path}/server/panel/old_data
mv -f ${setup_path}/server/panel/data/default.db ${setup_path}/server/panel/old_data/default.db
mv -f ${setup_path}/server/panel/data/system.db ${setup_path}/server/panel/old_data/system.db
mv -f ${setup_path}/server/panel/data/port.pl ${setup_path}/server/panel/old_data/port.pl
mv -f ${setup_path}/server/panel/data/admin_path.pl ${setup_path}/server/panel/old_data/admin_path.pl
fi
unzip -o panel.zip -d ${setup_path}/server/ > /dev/null
if [ -d "${setup_path}/server/panel/old_data" ];then
mv -f ${setup_path}/server/panel/old_data/default.db ${setup_path}/server/panel/data/default.db
mv -f ${setup_path}/server/panel/old_data/system.db ${setup_path}/server/panel/data/system.db
mv -f ${setup_path}/server/panel/old_data/port.pl ${setup_path}/server/panel/data/port.pl
mv -f ${setup_path}/server/panel/old_data/admin_path.pl ${setup_path}/server/panel/data/admin_path.pl
if [ -d "/${setup_path}/server/panel/old_data" ];then
rm -rf ${setup_path}/server/panel/old_data
fi
fi
rm -f panel.zip
if [ ! -f ${setup_path}/server/panel/tools.py ];then
Red_Error "ERROR: Failed to download, please try install again!"
fi
rm -f ${setup_path}/server/panel/class/*.pyc
rm -f ${setup_path}/server/panel/*.pyc
chmod +x /etc/init.d/bt
chmod -R 600 ${setup_path}/server/panel
chmod -R +x ${setup_path}/server/panel/script
ln -sf /etc/init.d/bt /usr/bin/bt
echo "${panelPort}" > ${setup_path}/server/panel/data/port.pl
wget -O /etc/init.d/bt ${download_Url}/install/src/bt6_en.init -T 10
wget -O /www/server/panel/init.sh ${download_Url}/install/src/bt6_en.init -T 10
}
Install_Python_Lib(){
#curl -Ss --connect-timeout 3 -m 60 $download_Url/install/pip_select.sh|bash
pyenv_path="/www/server/panel"
if [ -f $pyenv_path/pyenv/bin/python ];then
chmod -R 700 $pyenv_path/pyenv/bin
$pyenv_path/pyenv/bin/pip install cachelib
is_package=$($python_bin -m psutil 2>&1|grep package)
if [ "$is_package" = "" ];then
wget -O $pyenv_path/pyenv/pip.txt $download_Url/install/pyenv/pip.txt -T 5
$pyenv_path/pyenv/bin/pip install -U pip
$pyenv_path/pyenv/bin/pip install -U setuptools
$pyenv_path/pyenv/bin/pip install -r $pyenv_path/pyenv/pip.txt
$pyenv_path/pyenv/bin/pip install cachelib
fi
source $pyenv_path/pyenv/bin/activate
return
fi
py_version="3.7.8"
mkdir -p $pyenv_path
os_type='el'
os_version='7'
is_export_openssl=0
Get_Versions
Centos6_Openssl
Other_Openssl
echo "OS: $os_type - $os_version"
is_aarch64=$(uname -a|grep aarch64)
if [ "$is_aarch64" != "" ];then
os_version="aarch64"
fi
if [ "${os_version}" != "" ];then
pyenv_file="/www/pyenv.tar.gz"
wget -O $pyenv_file $download_Url/install/pyenv/pyenv-${os_type}${os_version}-x${is64bit}.tar.gz -T 10
tmp_size=$(du -b $pyenv_file|awk '{print $1}')
if [ $tmp_size -lt 703460 ];then
rm -f $pyenv_file
echo "ERROR: Download python env fielded."
else
echo "Install python env..."
tar zxvf $pyenv_file -C $pyenv_path/ &> /dev/null
chmod -R 700 $pyenv_path/pyenv/bin
if [ ! -f $pyenv_path/pyenv/bin/python ];then
rm -f $pyenv_file
Red_Error "ERROR: Install python env fielded."
fi
rm -f $pyenv_file
ln -sf $pyenv_path/pyenv/bin/pip3.7 /usr/bin/btpip
ln -sf $pyenv_path/pyenv/bin/python3.7 /usr/bin/btpython
source $pyenv_path/pyenv/bin/activate
return
fi
fi
if [ -f /usr/local/openssl/lib/libssl.so ];then
export LDFLAGS="-L/usr/local/openssl/lib"
export CPPFLAGS="-I/usr/local/openssl/include"
export PKG_CONFIG_PATH="/usr/local/openssl/lib/pkgconfig"
echo "export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/openssl/lib" >> /etc/profile
source /etc/profile
fi
cd /www
python_src='/www/python_src.tar.xz'
python_src_path="/www/Python-${py_version}"
wget -O $python_src $download_Url/src/Python-${py_version}.tar.xz -T 5
tmp_size=$(du -b $python_src|awk '{print $1}')
if [ $tmp_size -lt 10703460 ];then
rm -f $python_src
Red_Error "ERROR: Download python source code fielded."
fi
tar xvf $python_src
rm -f $python_src
cd $python_src_path
./configure --prefix=$pyenv_path/pyenv
make -j$cpu_cpunt
make install
if [ ! -f $pyenv_path/pyenv/bin/python3.7 ];then
rm -rf $python_src_path
Red_Error "ERROR: Make python env fielded."
fi
cd ~
rm -rf $python_src_path
wget -O $pyenv_path/pyenv/bin/activate $download_Url/install/pyenv/activate.panel -T 5
wget -O $pyenv_path/pyenv/pip.txt $download_Url/install/pyenv/pip-3.7.8.txt -T 5
ln -sf $pyenv_path/pyenv/bin/pip3.7 $pyenv_path/pyenv/bin/pip
ln -sf $pyenv_path/pyenv/bin/python3.7 $pyenv_path/pyenv/bin/python
ln -sf $pyenv_path/pyenv/bin/pip3.7 /usr/bin/btpip
ln -sf $pyenv_path/pyenv/bin/python3.7 /usr/bin/btpython
chmod -R 700 $pyenv_path/pyenv/bin
$pyenv_path/pyenv/bin/pip install -U pip
$pyenv_path/pyenv/bin/pip install -U setuptools
$pyenv_path/pyenv/bin/pip install -U wheel==0.34.2
$pyenv_path/pyenv/bin/pip install -r $pyenv_path/pyenv/pip.txt
$pyenv_path/pyenv/bin/pip install -U cachelib
source $pyenv_path/pyenv/bin/activate
}
Other_Openssl(){
openssl_version=$(openssl version|grep -Eo '[0-9]\.[0-9]\.[0-9]')
if [ "$openssl_version" = '1.0.1' ] || [ "$openssl_version" = '1.0.0' ];then
opensslVersion="1.0.2r"
if [ ! -f "/usr/local/openssl/lib/libssl.so" ];then
cd /www
openssl_src_file=/www/openssl.tar.gz
wget -O $openssl_src_file ${download_Url}/src/openssl-${opensslVersion}.tar.gz
tmp_size=$(du -b $openssl_src_file|awk '{print $1}')
if [ $tmp_size -lt 703460 ];then
rm -f $openssl_src_file
Red_Error "ERROR: Download openssl-1.0.2 source code fielded."
fi
tar -zxf $openssl_src_file
rm -f $openssl_src_file
cd openssl-${opensslVersion}
#zlib-dynamic shared
./config --openssldir=/usr/local/openssl zlib-dynamic shared
make -j${cpuCore}
make install
echo "/usr/local/openssl/lib" > /etc/ld.so.conf.d/zopenssl.conf
ldconfig
cd ..
rm -rf openssl-${opensslVersion}
is_export_openssl=1
cd ~
fi
fi
}
Insatll_Libressl(){
openssl_version=$(openssl version|grep -Eo '[0-9]\.[0-9]\.[0-9]')
if [ "$openssl_version" = '1.0.1' ] || [ "$openssl_version" = '1.0.0' ];then
opensslVersion="3.0.2"
cd /www
openssl_src_file=/www/openssl.tar.gz
wget -O $openssl_src_file ${download_Url}/install/pyenv/libressl-${opensslVersion}.tar.gz
tmp_size=$(du -b $openssl_src_file|awk '{print $1}')
if [ $tmp_size -lt 703460 ];then
rm -f $openssl_src_file
Red_Error "ERROR: Download libressl-$opensslVersion source code fielded."
fi
tar -zxf $openssl_src_file
rm -f $openssl_src_file
cd libressl-${opensslVersion}
./config prefix=/usr/local/lib
make -j${cpuCore}
make install
ldconfig
ldconfig -v
cd ..
rm -rf libressl-${opensslVersion}
is_export_openssl=1
cd ~
fi
}
Centos6_Openssl(){
if [ "$os_type" != 'el' ];then
return
fi
if [ "$os_version" != '6' ];then
return
fi
echo 'Centos6 install openssl-1.0.2...'
openssl_rpm_file="/www/openssl.rpm"
wget -O $openssl_rpm_file $download_Url/rpm/centos6/${is64bit}/bt-openssl102.rpm -T 10
tmp_size=$(du -b $openssl_rpm_file|awk '{print $1}')
if [ $tmp_size -lt 102400 ];then
rm -f $openssl_rpm_file
Red_Error "ERROR: Download python env fielded."
fi
rpm -ivh $openssl_rpm_file
rm -f $openssl_rpm_file
is_export_openssl=1
}
Get_Versions(){
redhat_version_file="/etc/redhat-release"
deb_version_file="/etc/issue"
if [ -f $redhat_version_file ];then
os_type='el'
is_aliyunos=$(cat $redhat_version_file|grep Aliyun)
if [ "$is_aliyunos" != "" ];then
return
fi
os_version=$(cat $redhat_version_file|grep CentOS|grep -Eo '([0-9]+\.)+[0-9]+'|grep -Eo '^[0-9]')
if [ "${os_version}" = "5" ];then
os_version=""
fi
else
os_type='ubuntu'
os_version=$(cat $deb_version_file|grep Ubuntu|grep -Eo '([0-9]+\.)+[0-9]+'|grep -Eo '^[0-9]+')
if [ "${os_version}" = "" ];then
os_type='debian'
os_version=$(cat $deb_version_file|grep Debian|grep -Eo '([0-9]+\.)+[0-9]+'|grep -Eo '[0-9]+')
if [ "${os_version}" = "" ];then
os_version=$(cat $deb_version_file|grep Debian|grep -Eo '[0-9]+')
fi
if [ "${os_version}" = "8" ];then
os_version=""
fi
if [ "${is64bit}" = '32' ];then
os_version=""
fi
else
if [ "$os_version" = "14" ];then
os_version=""
fi
if [ "$os_version" = "12" ];then
os_version=""
fi
if [ "$os_version" = "19" ];then
os_version=""
fi
fi
fi
}
Set_Bt_Panel(){
chmod -R 700 /www/server/panel/pyenv/bin
/www/server/panel/pyenv/bin/pip install cachelib
password=$(cat /dev/urandom | head -n 16 | md5sum | head -c 8)
sleep 1
admin_auth="/www/server/panel/data/admin_path.pl"
if [ ! -f ${admin_auth} ];then
auth_path=$(cat /dev/urandom | head -n 16 | md5sum | head -c 8)
echo "/${auth_path}" > ${admin_auth}
fi
auth_path=$(cat ${admin_auth})
cd ${setup_path}/server/panel/
if [ "$SET_SSL" == true ];then
pip install -I pyOpenSSl
python /www/server/panel/tools.py ssl
fi
/etc/init.d/bt start
$python_bin -m py_compile tools.py
$python_bin tools.py username
username=$($python_bin tools.py panel ${password})
cd ~
echo "${password}" > ${setup_path}/server/panel/default.pl
chmod 600 ${setup_path}/server/panel/default.pl
sleep 3
/etc/init.d/bt restart
sleep 3
isStart=$(ps aux |grep 'BT-Panel'|grep -v grep|awk '{print $2}')
LOCAL_CURL=$(curl 127.0.0.1:8888/login 2>&1 |grep -i html)
if [ -z "${isStart}" ] && [ -z "${LOCAL_CURL}" ];then
/etc/init.d/bt 22
Red_Error "ERROR: The BT-Panel service startup failed."
fi
}
Set_Firewall(){
sshPort=$(cat /etc/ssh/sshd_config | grep 'Port '|awk '{print $2}')
if [ "${PM}" = "apt-get" ]; then
apt-get install -y ufw
if [ -f "/usr/sbin/ufw" ];then
ufw allow 888/tcp
ufw allow 20/tcp
ufw allow 21/tcp
ufw allow 22/tcp
ufw allow 80/tcp
ufw allow ${panelPort}/tcp
ufw allow ${sshPort}/tcp ufw allow 39000:40000/tcp
ufw_status=`ufw status`
echo y|ufw enable
ufw default deny
ufw reload
fi
else
if [ -f "/etc/init.d/iptables" ];then
iptables -I INPUT -p tcp -m state --state NEW -m tcp --dport 20 -j ACCEPT
iptables -I INPUT -p tcp -m state --state NEW -m tcp --dport 21 -j ACCEPT
iptables -I INPUT -p tcp -m state --state NEW -m tcp --dport 22 -j ACCEPT
iptables -I INPUT -p tcp -m state --state NEW -m tcp --dport 80 -j ACCEPT
iptables -I INPUT -p tcp -m state --state NEW -m tcp --dport ${panelPort} -j ACCEPT
iptables -I INPUT -p tcp -m state --state NEW -m tcp --dport ${sshPort} -j ACCEPT
iptables -I INPUT -p tcp -m state --state NEW -m tcp --dport 39000:40000 -j ACCEPT
#iptables -I INPUT -p tcp -m state --state NEW -m udp --dport 39000:40000 -j ACCEPT
iptables -A INPUT -p icmp --icmp-type any -j ACCEPT
iptables -A INPUT -s localhost -d localhost -j ACCEPT
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -P INPUT DROP
service iptables save
sed -i "s#IPTABLES_MODULES=\"\"#IPTABLES_MODULES=\"ip_conntrack_netbios_ns ip_conntrack_ftp ip_nat_ftp\"#" /etc/sysconfig/iptables-config
iptables_status=$(service iptables status | grep 'not running')
if [ "${iptables_status}" == '' ];then
service iptables restart
fi
else
AliyunCheck=$(cat /etc/redhat-release|grep "Aliyun Linux")
[ "${AliyunCheck}" ] && return
yum install firewalld -y
[ "${Centos8Check}" ] && yum reinstall python3-six -y
systemctl enable firewalld
systemctl start firewalld
firewall-cmd --set-default-zone=public > /dev/null 2>&1
firewall-cmd --permanent --zone=public --add-port=20/tcp > /dev/null 2>&1
firewall-cmd --permanent --zone=public --add-port=21/tcp > /dev/null 2>&1
firewall-cmd --permanent --zone=public --add-port=22/tcp > /dev/null 2>&1
firewall-cmd --permanent --zone=public --add-port=80/tcp > /dev/null 2>&1
firewall-cmd --permanent --zone=public --add-port=${panelPort}/tcp > /dev/null 2>&1
firewall-cmd --permanent --zone=public --add-port=${sshPort}/tcp > /dev/null 2>&1
firewall-cmd --permanent --zone=public --add-port=39000-40000/tcp > /dev/null 2>&1
#firewall-cmd --permanent --zone=public --add-port=39000-40000/udp > /dev/null 2>&1
firewall-cmd --reload
fi
fi
}
Get_Ip_Address(){
getIpAddress=""
# getIpAddress=$(curl -sS --connect-timeout 10 -m 60 https://brandnew.aapanel.com/api/common/getClientIP)
getIpAddress=$(curl -sS --connect-timeout 10 -m 60 https://www.bt.cn/Api/getIpAddress)
if [ -z "${getIpAddress}" ] || [ "${getIpAddress}" = "0.0.0.0" ]; then
isHosts=$(cat /etc/hosts|grep 'www.bt.cn')
if [ -z "${isHosts}" ];then
echo "" >> /etc/hosts
echo "103.224.251.67 www.bt.cn" >> /etc/hosts
#getIpAddress=$(curl -sS --connect-timeout 10 -m 60 https://brandnew.aapanel.com/api/common/getClientIP)
getIpAddress=$(curl -sS --connect-timeout 10 -m 60 https://www.bt.cn/Api/getIpAddress)
if [ -z "${getIpAddress}" ];then
sed -i "/bt.cn/d" /etc/hosts
fi
fi
fi
ipv4Check=$($python_bin -c "import re; print(re.match('^(?:[0-9]{1,3}\.){3}[0-9]{1,3}$','${getIpAddress}'))")
if [ "${ipv4Check}" == "None" ];then
ipv6Address=$(echo ${getIpAddress}|tr -d "[]")
ipv6Check=$($python_bin -c "import re; print(re.match('^([0-9a-fA-F]{0,4}:){1,7}[0-9a-fA-F]{0,4}$','${ipv6Address}'))")
if [ "${ipv6Check}" == "None" ]; then
getIpAddress="SERVER_IP"
else
echo "True" > ${setup_path}/server/panel/data/ipv6.pl
sleep 1
/etc/init.d/bt restart
fi
fi
if [ "${getIpAddress}" != "SERVER_IP" ];then
echo "${getIpAddress}" > ${setup_path}/server/panel/data/iplist.txt
fi
}
Setup_Count(){
curl -sS --connect-timeout 10 -m 60 https://brandnew.aapanel.com/api/setupCount/setupPanel?type=Linux > /dev/null 2>&1
#curl -sS --connect-timeout 10 -m 60 https://www.aapanel.com/Api/SetupCount?type=Linux > /dev/null 2>&1
curl -sS --connect-timeout 10 -m 60 https://console.aapanel.com/Api/SetupCount?type=Linux > /dev/null 2>&1
#if [ "$1" != "" ];then
echo "66959f96" > /www/server/panel/data/o.pl
cd /www/server/panel
$python_bin tools.py o
#fi
echo /www > /var/bt_setupPath.conf
}
Install_Main(){
setenforce 0
startTime=`date +%s`
Lock_Clear
System_Check
#Set_Ssl
Get_Pack_Manager
get_node_url
MEM_TOTAL=$(free -g|grep Mem|awk '{print $2}')
if [ "${MEM_TOTAL}" -le "1" ];then
Auto_Swap
fi
if [ "${PM}" = "yum" ]; then
Install_RPM_Pack
elif [ "${PM}" = "apt-get" ]; then
Install_Deb_Pack
fi
Install_Python_Lib
Install_Bt
Set_Bt_Panel
Service_Add
Set_Firewall
Get_Ip_Address
Setup_Count ${IDC_CODE}
}
echo "
+----------------------------------------------------------------------
| aaPanel 6.0 FOR CentOS/Ubuntu/Debian
+----------------------------------------------------------------------
| Copyright © 2015-2099 BT-SOFT(http://www.aapanel.com) All rights reserved.
+----------------------------------------------------------------------
| The WebPanel URL will be http://SERVER_IP:8888 when installed.
+----------------------------------------------------------------------
"
while [ "$go" != 'y' ] && [ "$go" != 'n' ]
do
read -p "Do you want to install aaPanel to the $setup_path directory now?(y/n): " go;
done
if [ "$go" == 'n' ];then
exit;
fi
Install_Main
intenal_ip=$(ip addr | grep -E -o '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' | grep -E -v "^127\.|^255\.|^0\." | head -n 1)
echo -e "=================================================================="
echo -e "\033[32mCongratulations! Installed successfully!\033[0m"
echo -e "=================================================================="
if [ "$SET_SSL" == true ];then
echo "aaPanel Internet Address: https://${getIpAddress}:${panelPort}$auth_path"
echo "aaPanel Internal Address: https://${intenal_ip}:${panelPort}$auth_path"
else
echo "aaPanel Internet Address: http://${getIpAddress}:${panelPort}$auth_path"
echo "aaPanel Internal Address: http://${intenal_ip}:${panelPort}$auth_path"
fi
echo -e "username: $username"
echo -e "password: $password"
echo -e "\033[33mWarning:\033[0m"
echo -e "\033[33mIf you cannot access the panel, \033[0m"
echo -e "\033[33mrelease the following port (8888|888|80|443|20|21) in the security group\033[0m"
echo -e "=================================================================="
endTime=`date +%s`
((outTime=($endTime-$startTime)/60))
echo -e "Time consumed:\033[32m $outTime \033[0mMinute!"
rm -f new_install_en.sh
+14 -13
View File
@@ -94,14 +94,14 @@ def WriteLogs(logMsg):
pass
def ExecShell(cmdstring, cwd=None, timeout=None, shell=True):
def ExecShell(cmdstring, cwd=None, timeout=None, shell=True, symbol = '&>'):
try:
global logPath
import shlex
import datetime
import subprocess
import time
sub = subprocess.Popen(cmdstring+' &> '+logPath, cwd=cwd,
sub = subprocess.Popen(cmdstring+ symbol +logPath, cwd=cwd,
stdin=subprocess.PIPE, shell=shell, bufsize=4096)
while sub.poll() is None:
@@ -135,6 +135,7 @@ def startTask():
DownloadFile(argv[0], argv[1])
elif value['type'] == 'execshell':
ExecShell(value['execstr'])
ExecShell("echo '|-Successify ---Script execution completed---'",symbol=">>")
end = int(time.time())
sql.table('tasks').where("id=?", (value['id'],)).save(
'status,end', ('1', end))
@@ -603,11 +604,11 @@ def check_files_panel():
# 面板消息提醒
def check_panel_msg():
python_bin = get_python_bin()
while True:
os.system('{} {}/script/check_msg.py &'.format(python_bin,base_path))
time.sleep(600)
# def check_panel_msg():
# python_bin = get_python_bin()
# while True:
# os.system('{} {}/script/check_msg.py &'.format(python_bin,base_path))
# time.sleep(600)
def main():
@@ -658,9 +659,9 @@ def main():
p.setDaemon(True)
p.start()
p = threading.Thread(target=check_files_panel)
p.setDaemon(True)
p.start()
# p = threading.Thread(target=check_files_panel)
# p.setDaemon(True)
# p.start()
import panelTask
task_obj = panelTask.bt_task()
task_obj.not_web = True
@@ -668,9 +669,9 @@ def main():
p.setDaemon(True)
p.start()
p = threading.Thread(target=check_panel_msg)
p.setDaemon(True)
p.start()
# p = threading.Thread(target=check_panel_msg)
# p.setDaemon(True)
# p.start()
startTask()
+1 -1
View File
@@ -275,7 +275,7 @@ def ClearMail():
total += size;
count += num;
print('=======================================================================')
print("CLEAR_RUBBISH2",(str(count),ToSize(total)))
print(public.GetMsg('CLEAR_RUBBISH2',(str(count),ToSize(total))))
return total,count
#清理php_session文件