update 6.2.0

This commit is contained in:
jose
2019-08-14 15:32:00 +08:00
parent 1ea4c504cb
commit c86a5c2466
31 changed files with 2140 additions and 209 deletions
+92 -55
View File
@@ -64,7 +64,7 @@ app.config['SESSION_PERMANENT'] = True
app.config['SESSION_USE_SIGNER'] = True
app.config['SESSION_KEY_PREFIX'] = 'BT_:'
app.config['SESSION_COOKIE_NAME'] = "BT_PANEL_6"
app.config['PERMANENT_SESSION_LIFETIME'] = 86400 * 7
app.config['PERMANENT_SESSION_LIFETIME'] = 86400
Session(app)
if s_sqlite: sdb.create_all()
@@ -81,7 +81,7 @@ cache.set('p_token','bmac_' + public.Md5(public.get_mac_address()))
admin_path_file = 'data/admin_path.pl'
admin_path = '/'
if os.path.exists(admin_path_file): admin_path = public.readFile(admin_path_file).strip()
admin_path_checks = ['/','/san','/monitor','/abnormal','/close','/task','/login','/config','/site','/sites','ftp','/public','/database','/data','/download_file','/control','/crontab','/firewall','/files','config','/soft','/ajax','/system','/panel_data','/code','/ssl','/plugin','/wxapp','/hook','/safe','/yield','/downloadApi','/pluginApi','/auth','/download','/cloud','/webssh','/connect_event','/panel']
admin_path_checks = ['/','/san','/bak','/monitor','/abnormal','/close','/task','/login','/config','/site','/sites','ftp','/public','/database','/data','/download_file','/control','/crontab','/firewall','/files','config','/soft','/ajax','/system','/panel_data','/code','/ssl','/plugin','/wxapp','/hook','/safe','/yield','/downloadApi','/pluginApi','/auth','/download','/cloud','/webssh','/connect_event','/panel']
if admin_path in admin_path_checks: admin_path = '/bt'
@app.route('/service_status',methods = method_get)
@@ -90,7 +90,17 @@ def service_status():
@app.before_request
def basic_auth_check():
def request_check():
if not request.path in ['/safe','/hook','/public']:
ip_check = public.check_ip_panel()
if ip_check: return ip_check
domain_check = public.check_domain_panel()
if domain_check: return domain_check
if public.is_local():
not_networks = ['uninstall_plugin','install_plugin','UpdatePanel']
if request.args.get('action') in not_networks:
return public.returnJson(False,'This feature is not available in offline mode!'),json_header
if app.config['BASIC_AUTH_OPEN']:
if request.path in ['/public','/download']: return;
auth = request.authorization
@@ -101,10 +111,16 @@ def basic_auth_check():
return send_authenticated()
@app.teardown_request
def request_end(reques = None):
not_acts = ['GetTaskSpeed','GetNetWork','check_pay_status','get_re_order_status','get_order_stat']
key = request.args.get('action')
if not key in not_acts and request.full_path.find('/static/') == -1: public.write_request_log()
def send_authenticated():
global local_ip
if not local_ip: local_ip = public.GetLocalIp()
return Response('', 401,{'WWW-Authenticate': 'Basic realm="%s"' % local_ip})
return Response('', 401,{'WWW-Authenticate': 'Basic realm="%s"' % local_ip.strip()})
@app.route('/',methods=method_all)
def home():
@@ -117,6 +133,7 @@ def home():
data['databaseCount'] = public.M('databases').count()
data['lan'] = public.GetLan('index')
data['724'] = public.format_date("%m%d") == '0724'
public.auto_backup_panel()
return render_template( 'index.html',data = data)
@app.route('/close',methods=method_get)
@@ -303,14 +320,14 @@ def firewall(pdata = None):
defs = ('GetList','AddDropAddress','DelDropAddress','FirewallReload','SetFirewallStatus','AddAcceptPort','DelAcceptPort','SetSshStatus','SetPing','SetSshPort','GetSshInfo')
return publicObject(firewallObject,defs,None,pdata);
#@app.route('/firewall_new',methods=method_all)
@app.route('/firewall_new',methods=method_all)
def firewall_new(pdata = None):
comReturn = comm.local()
if comReturn: return comReturn
if request.method == method_get[0] and not pdata:
data = {}
data['lan'] = public.GetLan('firewall')
return render_template( 'firewall.html',data=data)
return render_template( 'firewall_new.html',data=data)
import firewall_new
firewallObject = firewall_new.firewalls()
defs = ('GetList','AddDropAddress','DelDropAddress','FirewallReload','SetFirewallStatus','AddAcceptPort','DelAcceptPort','SetSshStatus','SetPing','SetSshPort','GetSshInfo','AddSpecifiesIp','DelSpecifiesIp')
@@ -337,6 +354,18 @@ def san_baseline(pdata=None):
return publicObject(dataObject, defs, None, pdata)
@app.route('/bak', methods=method_all)
def backup_bak(pdata=None):
comReturn = comm.local()
if comReturn: return comReturn
import backup_bak
dataObject = backup_bak.backup_bak()
defs = ('get_sites', 'get_databases', 'backup_database', 'backup_site', 'backup_path', 'get_database_progress',
'get_site_progress', 'down','get_down_progress','download_path','backup_site_all','get_all_site_progress','backup_date_all','get_all_date_progress')
return publicObject(dataObject, defs, None, pdata)
@app.route('/abnormal', methods=method_all)
def abnormal(pdata=None):
comReturn = comm.local()
@@ -357,7 +386,7 @@ def files(pdata = None):
import files
filesObject = files.files()
defs = ('CheckExistsFiles','GetExecLog','GetSearch','ExecShell','GetExecShellMsg','UploadFile','GetDir','CreateFile','CreateDir','DeleteDir','DeleteFile',
'CopyFile','CopyDir','MvFile','GetFileBody','SaveFileBody','Zip','UnZip','SearchFiles','upload',
'CopyFile','CopyDir','MvFile','GetFileBody','SaveFileBody','Zip','UnZip','SearchFiles','upload','read_history',
'GetFileAccess','SetFileAccess','GetDirSize','SetBatchData','BatchPaste','install_rar','get_path_size',
'DownloadFile','GetTaskSpeed','CloseLogs','InstallSoft','UninstallSoft','SaveTmpFile','GetTmpFile',
'RemoveTask','ActionTask','Re_Recycle_bin','Get_Recycle_bin','Del_Recycle_bin','Close_Recycle_bin','Recycle_bin')
@@ -416,9 +445,11 @@ def config(pdata = None):
if data['basic_auth']['open']: data['basic_auth']['value'] = public.GetMsg("OPEN")
data['debug'] = ''
if app.config['DEBUG']: data['debug'] = 'checked'
data['is_local'] = ''
if public.is_local(): data['is_local'] = 'checked'
return render_template( 'config.html',data=data)
import config
defs = ('get_cert_source','set_debug','get_panel_error_logs','clean_panel_error_logs','get_basic_auth_stat','set_basic_auth','get_cli_php_version','get_tmp_token','set_cli_php_version','DelOldSession', 'GetSessionCount', 'SetSessionConf', 'GetSessionConf','get_ipv6_listen','set_ipv6_status','GetApacheValue','SetApacheValue','GetNginxValue','SetNginxValue','get_token','set_token','set_admin_path','is_pro','get_php_config','get_config','SavePanelSSL','GetPanelSSL','GetPHPConf','SetPHPConf','GetPanelList','AddPanelInfo','SetPanelInfo','DelPanelInfo','ClickPanelInfo','SetPanelSSL','SetTemplates','Set502','setPassword','setUsername','setPanel','setPathInfo','setPHPMaxSize','getFpmConfig','setFpmConfig','setPHPMaxTime','syncDate','setPHPDisable','SetControl','ClosePanel','AutoUpdatePanel','SetPanelLock')
defs = ('get_cert_source','set_local','set_debug','get_panel_error_logs','clean_panel_error_logs','get_basic_auth_stat','set_basic_auth','get_cli_php_version','get_tmp_token','set_cli_php_version','DelOldSession', 'GetSessionCount', 'SetSessionConf', 'GetSessionConf','get_ipv6_listen','set_ipv6_status','GetApacheValue','SetApacheValue','GetNginxValue','SetNginxValue','get_token','set_token','set_admin_path','is_pro','get_php_config','get_config','SavePanelSSL','GetPanelSSL','GetPHPConf','SetPHPConf','GetPanelList','AddPanelInfo','SetPanelInfo','DelPanelInfo','ClickPanelInfo','SetPanelSSL','SetTemplates','Set502','setPassword','setUsername','setPanel','setPathInfo','setPHPMaxSize','getFpmConfig','setFpmConfig','setPHPMaxTime','syncDate','setPHPDisable','SetControl','ClosePanel','AutoUpdatePanel','SetPanelLock')
return publicObject(config.config(),defs,None,pdata);
@app.route('/ajax',methods=method_all)
@@ -517,8 +548,16 @@ def plugin(pdata = None):
def panel_public():
get = get_input();
get.client_ip = public.GetClientIp();
if not hasattr(get,'name'): get.name = ''
if not public.path_safe_check("%s/%s" % (get.name,get.fun)): return abort(404)
if get.fun in ['scan_login','login_qrcode','set_login','is_scan_ok','blind']:
if get.fun in ['scan_login', 'login_qrcode', 'set_login', 'is_scan_ok', 'blind','static']:
if get.fun == 'static':
if not public.path_safe_check("%s" % (get.filename)): return abort(404)
s_file = '/www/server/panel/BTPanel/static/' + get.filename
if s_file.find('..') != -1 or s_file.find('./') != -1: return abort(404)
if not os.path.exists(s_file): return abort(404)
return send_file(s_file, conditional=True, add_etags=True)
#检查是否验证过安全入口
if get.fun in ['login_qrcode','is_scan_ok']:
global admin_check_auth,admin_path,route_path,admin_path_file
@@ -555,28 +594,9 @@ def send_favicon():
@app.route('/<name>/<fun>',methods=method_all)
@app.route('/<name>/<fun>/<path:stype>',methods=method_all)
def panel_other(name=None,fun = None,stype=None):
#插件公共动态路由 <name: 插件名称, fun: 被访问的插件方法名, stype:fun=static时则为文件相对于插件static目录下的路径> 访问方式:http://面板地址:端口/插件名称/插件方法.响应类型(html|json)
'''
插件静态文件存储目录: static (允许多级目录,请不要将重要文件放在静态目录),访问方式:http://面板地址:端口/插件名称/static/相对于static的文件路径 如:http://demo.cn:8888/demo/static/js/test.js
插件模板文件存储目录: templates (请不要在里面创建二级目录) 使用模板方法: http://demo.cn:8888/demo/get_logs.html
插件模板文件格式:方法名.html (支持jinja2语法,但无法使用extends语句),请在被访问的方法中返回一个dict,它将被当作data参数传入到模板变量
响应JSON数据: 示例: http://demo.cn:8888/demo/get_logs.json 注意:此处会将插件方法中返回的数据自动转换成JSON字符串响应
直接响应: 示例:http://demo.cn:8888/demo/get_logs ,此时直接响应插件方法返回的数据,注意: 支持 int、float、string、list、redirect对象
'''
#前置准备
if not name: name = 'coll'
if not public.path_safe_check("%s/%s/%s" % (name,fun,stype)): return abort(404)
#是否响应面板默认静态文件
if name == 'static':
s_file = '/www/server/panel/BTPanel/static/' + fun + '/' + stype
if s_file.find('..') != -1 or s_file.find('./') != -1: return abort(404)
if not os.path.exists(s_file): return abort(404)
return send_file(s_file,conditional=True,add_etags=True)
if name.find('./') != -1 or not re.match("^[\w-]+$",name): return public.returnJson(False,public.GetMsg("REQUEST_ERR")),json_header
if name.find('./') != -1 or not re.match("^[\w-]+$",name): return abort(404)
if not name: return public.returnJson(False,public.GetMsg("PLUGIN_INPUT_A")),json_header
p_path = '/www/server/panel/plugin/' + name
if not os.path.exists(p_path): return abort(404)
@@ -584,10 +604,12 @@ def panel_other(name=None,fun = None,stype=None):
#是否响插件应静态文件
if fun == 'static':
if stype.find('./') != -1 or not os.path.exists(p_path + '/static'): return public.returnJson(False,public.GetMsg("REQUEST_ERR")),json_header
if stype.find('./') != -1 or not os.path.exists(p_path + '/static'): return abort(404)
s_file = p_path + '/static/' + stype
if s_file.find('..') != -1: return abort(404)
if not os.path.exists(s_file): return public.returnJson(False,'The specified file does not exist ['+stype+']'),json_header
if not re.match("^[\w\./-]+$",s_file): return abort(404)
if not public.path_safe_check(s_file): return abort(404)
if not os.path.exists(s_file): return abort(404)
return send_file(s_file,conditional=True,add_etags=True)
#准备参数
@@ -603,26 +625,29 @@ def panel_other(name=None,fun = None,stype=None):
#初始化插件对象
try:
sys.path.append(p_path);
plugin_main = __import__(name+'_main')
try:
if sys.version_info[0] == 2:
reload(plugin_main)
else:
from imp import reload
reload(plugin_main)
except:pass
plu = eval('plugin_main.' + name + '_main()')
if not hasattr(plu, fun): return public.returnJson(False, public.GetMsg("SPECIFY_METHOD")), json_header
is_php = os.path.exists(p_path + '/index.php')
if not is_php:
sys.path.append(p_path);
plugin_main = __import__(name+'_main')
try:
if sys.version_info[0] == 2:
reload(plugin_main)
else:
from imp import reload
reload(plugin_main)
except:pass
plu = eval('plugin_main.' + name + '_main()')
if not hasattr(plu,fun): return public.returnJson(False,'SPECIFY_METHOD'),json_header
#检查访问权限
comReturn = comm.local()
if comReturn:
if not hasattr(plu, '_check'): return public.returnJson(False, public.GetMsg("SPECIFY_PLUG_ERR")), json_header
checks = plu._check(args)
r_type = type(checks)
if r_type == Response: return checks
if r_type != bool or not checks: return public.getJson(checks),json_header
if not is_php:
if not hasattr(plu,'_check'): return public.returnJson(False,'SPECIFY_PLUG_ERR'),json_header
checks = plu._check(args)
r_type = type(checks)
if r_type == Response: return checks
if r_type != bool or not checks: return public.getJson(checks),json_header
#初始化面板数据
comm.setSession()
@@ -637,7 +662,14 @@ def panel_other(name=None,fun = None,stype=None):
return public.returnMsg(False,public.to_string([24744, 26410, 36141, 20080, 91, 37, 115, 93, 25110, 25480, 26435, 24050, 21040, 26399, 33]) % (plugins.get_title_byname(args),))
#执行插件方法
data = eval('plu.'+fun+'(args)')
if not is_php:
data = eval('plu.'+fun+'(args)')
else:
import panelPHP
args.s = fun
args.name = name
data = panelPHP.panelPHP(name).exec_php_script(args)
r_type = type(data)
if r_type == Response: return data
@@ -785,6 +817,7 @@ def download():
filename = request.args.get('filename')
if not filename: return public.ReturnJson(False,"INIT_ARGS_ERR"),json_header
if filename in ['alioss','qiniu','upyun','txcos','ftp']: return panel_cloud()
if filename in ['gdrive','gcloud_storage']: return "Google storage products do not currently support downloads"
if not os.path.exists(filename): return public.ReturnJson(False,"FILE_NOT_EXISTS"),json_header
mimetype = "application/octet-stream"
extName = filename.split('.')[-1]
@@ -943,11 +976,10 @@ def publicObject(toObject,defs,action=None,get = None):
if get.path.find('..') != -1: return public.ReturnJson(False,public.GetMsg("UNSAFE_PATH")),json_header
if get.path.find('->') != -1:
get.path = get.path.split('->')[0].strip();
not_acts = ['GetTaskSpeed','GetNetWork','check_pay_status','get_re_order_status','get_order_stat']
for key in defs:
if key == get.action:
fun = 'toObject.'+key+'(get)'
if not key in not_acts: public.write_request_log()
if hasattr(get,'html') or hasattr(get,'s_module'):
return eval(fun)
else:
@@ -967,10 +999,11 @@ def check_login(http_token=None):
def get_pd():
tmp = -1
#tmp1 = cache.get(public.to_string([112, 108, 117, 103, 105, 110, 95, 115, 111, 102, 116, 95, 108, 105, 115, 116]))
#if not tmp1:
import panelPlugin
tmp1 = panelPlugin.panelPlugin().get_cloud_list()
try:
import panelPlugin
tmp1 = panelPlugin.panelPlugin().get_cloud_list()
except:
tmp1 = None
if tmp1:
tmp = tmp1[public.to_string([112,114,111])]
else:
@@ -1018,9 +1051,13 @@ def notfound(e):
@app.errorhandler(500)
def internalerror(e):
#if str(e).find('Permanent Redirect') != -1: return e
errorStr = public.ReadFile('./BTPanel/templates/' + public.GetConfigValue('template') + '/error.html')
try:
errorStr = errorStr.format(public.getMsg('PAGE_ERR_500_TITLE'),public.getMsg('PAGE_ERR_500_H1'),public.getMsg('PAGE_ERR_500_P1'),public.getMsg('NAME'),public.getMsg('PAGE_ERR_HELP'))
if not app.config['DEBUG']:
errorStr = errorStr.format(public.getMsg('PAGE_ERR_500_TITLE'),public.getMsg('PAGE_ERR_500_H1'),public.getMsg('PAGE_ERR_500_P1'),public.getMsg('NAME'),public.getMsg('PAGE_ERR_HELP'))
else:
errorStr = errorStr.format(public.getMsg('PAGE_ERR_500_TITLE'),str(e),'<pre>'+public.get_error_info() + '</pre>','The above debugging information is only displayed in developer mode','Version: ' + public.version())
except IndexError:pass
return errorStr,500
+381 -14
View File
@@ -1368,27 +1368,25 @@ html .menu .menu_exit:hover {
left: 0
}
.left,
.right {
width: 100px;
height: 100px;
background: #ccc;
border-radius: 50%;
position: absolute;
top: 0;
left: 0
}
/*.left,*/
/*.right {*/
/* width: 100px;*/
/* height: 100px;*/
/* background: #ccc;*/
/* border-radius: 50%;*/
/* position: absolute;*/
/* top: 0;*/
/* left: 0*/
/*}*/
.pie_right,
.right {
.pie_right {
clip: rect(0, auto, auto, 50px);
transition: transform 1s ease-in 0s;
-webkit-transition: -webkit-transform 1s ease-in 0s;
-moz-transition: -moz-transform 1s ease-in 0s
}
.pie_left,
.left {
.pie_left {
clip: rect(0, 50px, auto, 0);
transition: transform .4s ease-in 1s;
-webkit-transition: -webkit-transform .4s ease-in 1s;
@@ -2308,6 +2306,11 @@ html .menu .menu_exit:hover {
.setting-con .btn_tips{
display: inline-block;
position: relative;
z-index: 10
}
.setting-con p .set-info {
margin-left: 20px
}
.set-submit {
@@ -5223,3 +5226,367 @@ select[disabled]{
.ssl_cert_from>.line .line .info-r{
margin-bottom:0;
}
#ace_conter{
background: #444;
height: 100%;
overflow: hidden;
/*background: url('/static/img/resize_corner.png') no-repeat;*/
}
.ace_overall {
width: 100%;
display: inline-block;
position: relative;
}
.ace_catalogue {
display: none;
float: left;
width: 250px;
position: absolute;
z-index: 99;
height: 45px;
background: #333;
}
.ace_catalogue_sidebar {
display: none;
height: 100%;
width: 10px;
background: #444;
cursor: col-resize;
position: absolute;
left: 240px;
top: 90px;
}
.ace_catalogue_sidebar img {
position: absolute;
top: 50%;
width: 10px;
margin-top: -20px;
}
.ace_catalogue_title {
height: 45px;
line-height: 45px;
padding-left: 20px;
color: #fff;
}
.ace_conter_menu {
height: 40px;
position: relative;
background: #292929;
overflow: auto;
}
.ace_editor {
font-size: 15px;
}
.ace_editors {
position: absolute;
top: 40px;
right: 0;
bottom: 35px;
left: 0px;
font-size: 13px;
display: none;
}
.ace_editors.active {
display: block;
}
.ace_header {
position: relative;
height: 35px;
background: #565656;
/* transition: all 500ms; */
}
.ace_header span {
float: left;
height: 35px;
line-height: 35px;
padding: 0 15px;
font-size: 13px;
text-align: center;
color: #fff;
border-right: 1px solid #4c4c4c;
cursor: pointer;
}
.ace_header span .glyphicon {
margin-right: 5px;
vertical-align: text-top;
}
.ace_header span:hover {
background: #2f2f2f;
}
.ace_header .pull-down{
display: inline-block;
position: absolute;
z-index: 999;
right: 0;
height: 35px;
line-height: 35px;
padding: 0 14px;
font-size: 15px;
color: #fff;
background: #292929;
cursor: pointer;
}
.ace_editor_main {
position: relative;
background: #444;
}
.ace_editor_main_storey {
position: absolute;
z-index: 999;
width: 100%;
height: 5px;
background: linear-gradient(rgba(0, 0, 0, 0.3), rgba(255, 255, 255, 0));
}
.ace_conter_menu .item {
display: inline-block;
float: left;
font-size: 15px;
max-width: 350px;
padding: 0 35px 0 10px;
height: 40px;
box-sizing: border-box;
position: relative;
color: #ececec;
cursor: pointer;
border-right: 1px solid #191919;
}
.ace_conter_menu .item:hover {
background: #313131;
}
.ace_conter_menu .item:hover .icon-tool {
display: block;
}
.ace_conter_menu .item.active {
color: #fff;
background: #404040;
border-bottom: 2px solid #20a53a;
}
.ace_conter_menu .item.active .icon-tool {
display: block;
}
.ace_conter_menu .item span {
display: inline-block;
line-height: 40px;
height: 40px;
margin: 0 10px 0 0;
}
.ace_conter_menu .item .icon_file {
color: #ff9800;
font-weight: 500;
margin-left: 10px;
}
.ace_conter_menu .item .icon-tool.fa-circle {
display: block;
}
.ace_conter_menu .item .icon-tool {
display: none;
position: absolute;
right: 15px;
top: 13px;
transition: all 1000ms;
font-size: 14px;
}
.ace_editor_add {
float: left;
height: 40px;
padding: 9px 15px;
font-size: 17px;
color: #ddd;
cursor: pointer;
transition: all 500ms;
}
.ace_editor_add:hover {
background-color: #505050
}
/* 关闭视图-开始 */
.ace-clear-form {
padding-top: 25px;
}
.ace-clear-form .line {
margin-left: 20px;
}
.clear-title {
font-size: 15px;
color: #333;
}
.clear-tips {
font-size: 13px;
color: #666;
}
.clear-tips,
.clear-title {
padding-left: 80px;
}
.clear-icon {
width: 30px;
height: 30px;
background-image: url(/static/layer/skin/default/icon.png);
background-position: 0 0;
position: absolute;
left: 30px;
top: 28px;
}
/* 取消按钮组 */
.ace-clear-btn {
padding: 8px 20px 15px;
text-align: right;
position: absolute;
bottom: 0;
width: 100%;
}
.ace-clear-btn .btn-default:hover {
color: #fff;
background-color: #d9534f;
border-color: #d43f3a;
}
/* 关闭视图-结束 */
.ace_conter_toolbar {
height: 35px;
line-height: 35px;
bottom: 0;
text-align: right;
margin-right: 15px;
position: relative;
z-index: 999;
background: #444;
font-size: 0;
overflow: hidden;
}
.ace_conter_toolbar .pull-left,
.ace_conter_toolbar .pull-right{
height: 35px;
}
.ace_conter_toolbar .pull-left span ,
.ace_conter_toolbar .pull-right span {
color: #fff;
display: inline-block;
border-right: 1px solid #505050;
padding: 0 15px;
cursor: pointer;
transition: all 500ms;
font-size: 13px;
}
.ace_conter_toolbar .pull-left span{
border-right:0;
cursor: default;
}
.ace_conter_toolbar .pull-left span i,
.ace_conter_toolbar .pull-right span i {
font-style: normal;
}
.ace_conter_toolbar .pull-right span:hover {
background: #717171;
}
.ace_toolbar_menu {
position: absolute;
z-index: 9999;
top: 40px;
left: 50%;
margin-left: -200px;
background: #444444;
width: 400px;
padding: 15px 0;
box-shadow: 0px 0px 2px 0px #000;
}
.ace_toolbar_menu .menu-conter {
margin: 0 15px 15px;
position: relative;
}
.ace_toolbar_menu .menu-conter .fa {
display: none;
position: absolute;
right: 10px;
top: 7px;
font-size: 18px;
color: #fff;
cursor: pointer;
}
.ace_toolbar_menu input {
width: 100%;
height: 35px;
background: #444;
border: 1px solid #7d7d7d;
color: #fff;
padding: 0px 10px;
outline: none;
}
.ace_toolbar_menu input:focus{
border: 1px solid #fff;
}
.ace_toolbar_menu .menu-item ul {
overflow: auto;
max-height: 300px;
}
.ace_toolbar_menu .menu-item li {
padding: 0 20px;
height: 35px;
line-height: 35px;
color: #fff;
cursor: pointer;
transition: all 500ms;
position: relative;
}
.ace_toolbar_menu .menu-item li.active,
.ace_toolbar_menu .menu-item li.active:hover {
background: #666;
}
.ace_toolbar_menu .menu-item li:hover {
background: #505050;
}
.ace_toolbar_menu .icon-link {
margin-left: 15px;
color: #20a53a;
}
.ace_toolbar_menu .menu-item .icon {
position: absolute;
right: 25px;
}
.ace_toolbar_menu .menu-title {
padding: 0 0 5px 20px;
border-bottom: 1px solid #666666;
color: #9e9e9e;
}
.make_transist {
-webkit-transition: all .2s ease-in-out;
-moz-transition: all .2s ease-in-out;
-o-transition: all .2s ease-in-out;
-ms-transition: all .2s ease-in-out;
transition: all .2s ease-in-out
}
.ace_conter_search{
display: none;
}
.helps_conter{
padding: 25px;
overflow: hidden;
}
.helps_conter .helps_item{
margin-bottom: 10px;
display: inline-block;
border-left: 3px solid #20a53a;
padding-left: 5px;
font-size: 15px;
}
.helps_conter .helps_box{
margin-bottom: 20px;
font-size: 14px;
padding-left: 10px;
line-height: 25px;
}
.helps_left{
width: 50%;
float: left;
padding:15px;
}
.cursor-row,.cursor-line{
margin:5px;
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 364 B

+20 -1
View File
@@ -347,11 +347,30 @@ function SetDebug() {
layer.msg(rdata.msg, { icon: rdata.status ? 1 : 2 });
});
},function () {
console.log('index.html');
$("#panelDebug").prop('checked',debug_stat);
});
}
function set_local() {
var status_s = { false: 'Open', true: 'Close' }
var debug_stat = $("#panelLocal").prop('checked');
bt.confirm({
title: status_s[debug_stat] + "Offline mode",
msg: "Do you really want "+ status_s[debug_stat] + "offline mode?",
cancel: function () {
$("#panelLocal").prop('checked',debug_stat);
}}, function () {
var loadT = layer.msg(lan.public.the, { icon: 16, time: 0, shade: [0.3, '#000'] });
$.post('/config?action=set_local', {}, function (rdata) {
layer.close(loadT);
if (rdata.status) layer.closeAll();
layer.msg(rdata.msg, { icon: rdata.status ? 1 : 2 });
});
},function () {
$("#panelLocal").prop('checked',debug_stat);
});
}
if(window.location.protocol.indexOf('https') != -1){
$("#panelSSL").prop('checked',true);
}
+3 -3
View File
@@ -446,7 +446,7 @@ function GetFiles(Path,sort) {
bodyZip = "<a class='btlink' href='javascript:;' onclick=\"UnZip('" + rdata.PATH +"/" +fmp[0] + "'," + displayZip + ")\">"+lan.files.file_menu_unzip+"</a> | ";
}
if(isText(fmp[0])){
bodyZip = "<a class='btlink' href='javascript:;' onclick=\"OnlineEditFile(0,'" + rdata.PATH +"/"+ fmp[0] + "')\">"+lan.files.file_menu_edit+"</a> | ";
bodyZip = "<a class='btlink' href='javascript:;' onclick=\"openEditorView(0,'" + rdata.PATH +"/"+ fmp[0] + "')\">"+lan.files.file_menu_edit+"</a> | ";
}
if(isImage(fmp[0])){
download = "<a class='btlink' href='javascript:;' onclick=\"GetImage('" + rdata.PATH +"/"+ fmp[0] + "')\">"+lan.files.file_menu_img+"</a> | ";
@@ -895,7 +895,7 @@ function CreateFile(type, path) {
});
if(rdata.status){
GetFiles($("#DirPathPlace input").val());
OnlineEditFile(0,path + '/' + fileName);
openEditorView(0,path + '/' + fileName);
}
});
return;
@@ -1571,7 +1571,7 @@ function RClick(type,path,name){
// options.items.push({ text: '播放', onclick: function () { GetPlay(path) } }, { text: lan.files.file_menu_down, onclick: function () { GetFileBytes(path) } }, { text: lan.files.file_menu_del, onclick: function () { DeleteFile(path) } });
//}
else if(isText(type)){
options.items.push({text: lan.files.file_menu_edit, onclick: function() {OnlineEditFile(0,path)}},{text: lan.files.file_menu_down, onclick: function() {GetFileBytes(path)}},{text: lan.files.file_menu_del, onclick: function() {DeleteFile(path)}});
options.items.push({text: lan.files.file_menu_edit, onclick: function() {openEditorView(0,path)}},{text: lan.files.file_menu_down, onclick: function() {GetFileBytes(path)}},{text: lan.files.file_menu_del, onclick: function() {DeleteFile(path)}});
}
else if(displayZip != -1){
options.items.push({text: lan.files.file_menu_unzip, onclick: function() {UnZip(path,displayZip)}},{text: lan.files.file_menu_down, onclick: function() {GetFileBytes(path)}},{text: lan.files.file_menu_del, onclick: function() {DeleteFile(path)}});
+17 -2
View File
@@ -135,6 +135,21 @@ var index = {
layer.closeAll('tips');
})
$('.cpubox').hover(function () {
var _this = $(this);
var d = _this.parents('ul').data('data').cpu;
var crs = '';
var n1 = 0;
for (var i = 0; i < d[2].length; i++) {
n1++;
crs += 'CPU-' + i + ": " + d[2][i] + '%' + (n1 % 2 == 0?'</br>':' | ');
}
layer.tips(d[3] +"</br>"+ crs, _this.find('.cicle'), { time: 0, tips: [1, '#999'] });
}, function () {
layer.closeAll('tips');
});
$(".mem-release").hover(function () {
$(this).addClass("shine_green");
if (!($(this).hasClass("mem-action"))) {
@@ -446,7 +461,7 @@ var index = {
closeBtn: 2,
content: '<div class="setchmod bt-form">\
<div class="update_title"><i class="layui-layer-ico layui-layer-ico1"></i><span>'+lan.index.last_version_now+'</span></div>\
<div class="update_version">'+lan.index.this_version+'<a href="http://www.bt.cn/bbs/forum.php?mod=viewthread&tid=19376" target="_blank" class="btlink" title="'+lan.index.check_this_version_log+'">'+lan.index.bt_linux+ (rdata.msg.is_beta == 1 ? lan.index.test_version+' ' + rdata.msg.beta.version : lan.index.final_version+' ' + rdata.msg.version) + '</a>&nbsp;&n'+ lan.index.release_time + (rdata.msg.is_beta == 1 ? rdata.msg.beta.uptime : rdata.msg.uptime) + '</div>\
<div class="update_version">'+lan.index.this_version+'<a href="https://forum.aapanel.com/d/9-aapanel-linux-panel-6-1-5-installation-tutorial/36" target="_blank" class="btlink" title="'+lan.index.check_this_version_log+'">'+lan.index.bt_linux+ (rdata.msg.is_beta == 1 ? lan.index.test_version+' ' + rdata.msg.beta.version : lan.index.final_version+' ' + rdata.msg.version) + '</a>&nbsp;&n'+ lan.index.release_time + (rdata.msg.is_beta == 1 ? rdata.msg.beta.uptime : rdata.msg.uptime) + '</div>\
<div class="bt-form-submit-btn">\
<button type="button" class="btn btn-danger btn-sm btn-title" onclick="layer.closeAll()">'+ lan.public.cancel + '</button>\
<button type="button" class="btn btn-success btn-sm btn-title btn_update_panel" onclick="layer.closeAll()">'+ lan.public.know + '</button>\
@@ -484,7 +499,7 @@ var index = {
content: '<div class="setchmod bt-form" style="padding-bottom:50px;">\
<div class="update_title"><i class="layui-layer-ico layui-layer-ico0"></i><span>'+lan.index.have_new_version+'</span></div>\
<div class="update_conter">\
<div class="update_version">'+lan.index.last_version+'<a href="https://www.bt.cn/bbs/forum.php?mod=forumdisplay&fid=36" target="_blank" class="btlink" title="'+lan.index.check_version_log+'">'+lan.index.bt_linux+ (is_beta === 1 ? lan.index.test_version : lan.index.final_version) + rdata.version + '</a>&nbsp;&nbsp;'+lan.index.update_date + (result.msg.is_beta == 1 ? result.msg.beta.uptime : result.msg.uptime) + '</div>\
<div class="update_version">'+lan.index.last_version+'<a href="https://forum.aapanel.com/d/9-aapanel-linux-panel-6-1-5-installation-tutorial/36" target="_blank" class="btlink" title="'+lan.index.check_version_log+'">'+lan.index.bt_linux+ (is_beta === 1 ? lan.index.test_version : lan.index.final_version) + rdata.version + '</a>&nbsp;&nbsp;'+lan.index.update_date + (result.msg.is_beta == 1 ? result.msg.beta.uptime : result.msg.uptime) + '</div>\
<div class="update_logs">'+ rdata.updateMsg + '</div>\
</div>\
<!--div class="update_conter">\
+842 -2
View File
@@ -4,6 +4,846 @@ $(document).ready(function() {
});
});
function openEditorView(type,path){
var paths = path.split('/'),_fileName = paths[paths.length -1], _aceTmplate = document.getElementById("aceTmplate").innerHTML;
_aceTmplate = _aceTmplate.replace(/\<\\\/script\>/g,'</script>');
if(aceEditor.editor !== null){
if(aceEditor.isAceView == false){
aceEditor.isAceView = true;
$('.aceEditors .layui-layer-max').click()
}
for(var i=0;i<aceEditor.pathAarry.length;i++){
if(path === aceEditor.pathAarry[i]){
layer.msg('File is open',{icon:0});
return false;
}
}
aceEditor.openEditorView(path);
return false;
}
var r = layer.open({
type: 1,
maxmin: true,
shade:false,
area: ['80%','80%'],
title: "Online text editor",
skin:'aceEditors',
zIndex:19999,
content: _aceTmplate,
success:function(layero,index){
aceEditor.layer_view = index;
aceEditor.ace_active = '';
aceEditor.eventEditor();
ace.require("/ace/ext/language_tools");
ace.config.set("modePath", "/static/ace");
ace.config.set("workerPath", "/static/ace");
ace.config.set("themePath", "/static/ace");
aceEditor.openEditorView(path);
$('.aceEditors .layui-layer-min').click(function (e){
aceEditor.isAceView = false;
setTimeout(function(){
var _id = $('.ace_conter_menu .active').attr('data-id');
aceEditor.editor['ace_editor_'+_id].ace.resize();
},105);
});
$('.aceEditors .layui-layer-max').click(function (e){
setTimeout(function(){
aceEditor.setEditorView();
var _id = $('.ace_conter_menu .active').attr('data-id');
aceEditor.editor['ace_editor_'+_id].ace.resize();
},105);
});
},
cancel:function(){
for(var item in aceEditor.editor){
if(aceEditor.editor[item].fileType == 1){
layer.open({
type: 1,
area: ['400px', '180px'],
title: 'Save Tips',
content: '<div class="ace-clear-form">\
<div class="clear-icon"></div>\
<div class="clear-title">Detected that the file was not saved, did you save the file change?</div>\
<div class="clear-tips">If you don\'t save, the changes will be lost!</div>\
<div class="ace-clear-btn" style="">\
<button type="button" class="btn btn-sm btn-default" style="float:left" data-type="2">Dont save</button>\
<button type="button" class="btn btn-sm btn-default" style="margin-right:10px;" data-type="1">Cancel</button>\
<button type="button" class="btn btn-sm btn-success" data-type="0">Save</button>\
</div>\
</div>',
success: function (layers, indexs) {
$('.ace-clear-btn button').click(function(){
var _type = $(this).attr('data-type');
switch(_type){
case '2':
aceEditor.editor = null;
layer.closeAll();
break;
case '1':
layer.close(indexs);
break;
case '0':
var _arry = [],editor = aceEditor['editor'];
for(var item in editor){
_arry.push({
path: editor[item]['path'],
data: editor[item]['ace'].getValue(),
encoding: editor[item]['encoding'],
})
}
aceEditor.saveAllFileBody(_arry,function(){
$('.ace_conter_menu>.item').each(function (el,indexx) {
var _id = $(this).attr('data-id');
$(this).find('i').removeClass('glyphicon-exclamation-sign').addClass('glyphicon-remove').attr('data-file-state','0')
aceEditor.editor['ace_editor_'+_id].fileType = 0;
});
aceEditor.editor = null;
aceEditor.pathAarry = [];
layer.closeAll();
});
break;
}
});
}
});
return false;
}
}
aceEditor.editor = null;
aceEditor.pathAarry = [];
aceEditor.editorLength = 0;
}
});
}
var aceEditor = {
layer_view:'',
editor: null,
supportedModes: {
Apache_Conf: ["^htaccess|^htgroups|^htpasswd|^conf|htaccess|htgroups|htpasswd"],
BatchFile: ["bat|cmd"],
C_Cpp: ["cpp|c|cc|cxx|h|hh|hpp|ino"],
CSharp: ["cs"],
CSS: ["css"],
Dockerfile: ["^Dockerfile"],
golang: ["go"],
HTML: ["html|htm|xhtml|vue|we|wpy"],
Java: ["java"],
JavaScript: ["js|jsm|jsx"],
'JSON': ["json"],
JSP: ["jsp"],
LESS: ["less"],
Lua: ["lua"],
Makefile: ["^Makefile|^GNUmakefile|^makefile|^OCamlMakefile|make"],
Markdown: ["md|markdown"],
MySQL: ["mysql"],
Nginx: ["nginx|conf"],
INI: ["ini|conf|cfg|prefs"],
ObjectiveC: ["m|mm"],
Perl: ["pl|pm"],
Perl6: ["p6|pl6|pm6"],
pgSQL: ["pgsql"],
PHP_Laravel_blade: ["blade.php"],
PHP: ["php|inc|phtml|shtml|php3|php4|php5|phps|phpt|aw|ctp|module"],
Powershell: ["ps1"],
Python: ["py"],
R: ["r"],
Ruby: ["rb|ru|gemspec|rake|^Guardfile|^Rakefile|^Gemfile"],
Rust: ["rs"],
SASS: ["sass"],
SCSS: ["scss"],
SH: ["sh|bash|^.bashrc"],
SQL: ["sql"],
SQLServer: ["sqlserver"],
Swift: ["swift"],
Text: ["txt"],
Typescript: ["ts|typescript|str"],
VBScript: ["vbs|vb"],
Verilog: ["v|vh|sv|svh"],
XML: ["xml|rdf|rss|wsdl|xslt|atom|mathml|mml|xul|xbl|xaml"],
YAML: ["yaml|yml"]
},
nameOverrides: {
ObjectiveC: "Objective-C",
CSharp: "C#",
golang: "Go",
C_Cpp: "C and C++",
PHP_Laravel_blade: "PHP (Blade Template)",
Perl6: "Perl 6",
},
pathAarry:[],
encodingList: ['UTF-8', 'GBK', 'GB2312', 'BIG5'],
themeList: [
'chrome',
'clouds',
'crimson_editor',
'ambiance',
'chaos',
'monokai'
],
editorTheme: 'monokai', // 编辑器主题
editorLength: 0,
isAceView:true,
ace_active:'',
// aceEditor:'',
// 事件编辑器-方法,事件绑定
eventEditor: function () {
var _this = this;
$(window).resize(function(){
var _id = $('.ace_conter_menu .active').attr('data-id');
aceEditor.editor['ace_editor_'+_id].ace.resize();
_this.setEditorView()
})
// 显示工具条
$('.ace_header .pull-down').click(function(){
if($(this).find('i').hasClass('glyphicon-menu-down')){
$('.ace_header').css({'marginTop':'-35px','height':'0'});
$(this).css({'top':'35px','height':'40px','line-height':'40px'});
$(this).find('i').addClass('glyphicon-menu-up').removeClass('glyphicon-menu-down');
}else{
$('.ace_header').removeAttr('style');
$(this).removeAttr('style');
$(this).find('i').addClass('glyphicon-menu-down').removeClass('glyphicon-menu-up');
}
_this.setEditorView();
});
// 切换TAB视图
$('.ace_conter_menu').on('click', '.item', function (e) {
var _id = $(this).attr('data-id');
$('.item_tab_'+ _id).addClass('active').siblings().removeClass('active');
$('#ace_editor_'+ _id).addClass('active').siblings().removeClass('active');
_this.ace_active = _id;
_this.currentStatusBar(_id);
e.stopPropagation();
});
// 移上TAB按钮变化,仅文件被修改后
$('.ace_conter_menu').on('mouseover', '.item .icon-tool', function () {
var type = $(this).attr('data-file-state');
if (type != '0') {
$(this).removeClass('glyphicon-exclamation-sign').addClass('glyphicon-remove');
}
});
// 移出tab按钮变化,仅文件被修改后
$('.ace_conter_menu').on('mouseout', '.item .icon-tool', function () {
var type = $(this).attr('data-file-state');
if (type != '0') {
$(this).removeClass('glyphicon-remove').addClass('glyphicon-exclamation-sign');
}
});
// 关闭编辑视图
$('.ace_conter_menu').on('click', '.item .icon-tool', function (e) {
var file_type = $(this).attr('data-file-state');
var file_title = $(this).attr('data-title');
var _path = $(this).parent().attr('title');
var _id = $(this).parent().attr('data-id');
switch (file_type) {
// 直接关闭
case '0':
_this.removeEditor(_id);
break;
// 未保存
case '1':
var loadT = layer.open({
type: 1,
area: ['400px', '180px'],
title: 'Tips',
content: '<div class="ace-clear-form">\
<div class="clear-icon"></div>\
<div class="clear-title">Do you want to save changes to &nbsp' + file_title + '&nbsp?</div>\
<div class="clear-tips">If you don\'t save, the changes will be lost!</div>\
<div class="ace-clear-btn" style="">\
<button type="button" class="btn btn-sm btn-default" style="float:left" data-type="2">Dont save</button>\
<button type="button" class="btn btn-sm btn-default" style="margin-right:10px;" data-type="1">Cancel</button>\
<button type="button" class="btn btn-sm btn-success" data-type="0">Save</button>\
</div>\
</div>',
success: function (layers, index) {
$('.ace-clear-btn .btn').click(function () {
var _type = $(this).attr('data-type');
switch (_type) {
case '0': //保存文件
console.log()
_this.saveFileBody({
path:_path,
data:editor_item.ace.getValue(),
encoding:editor_item.ace.getValue()
},function(){
layer.msg(res.msg, {icon: 1});
editor_item.fileType = 0;
$('.item_tab_' + editor_item.id + ' .icon-tool').attr('data-file-state', '0').removeClass('glyphicon-exclamation-sign').addClass('glyphicon-remove');
});
break;
case '1': //关闭视图
layer.close(index);
break;
case '2': //取消保存
_this.removeEditor(_id);
layer.close(index);
break;
}
});
}
});
break;
}
e.stopPropagation();
});
// 新建编辑器视图
$('.ace_editor_add').click(function () {
_this.addEditor();
});
// 底部状态栏功能按钮
$('.ace_conter_toolbar .pull-right span').click(function (e) {
var _type = $(this).attr('data-type'),_id = $(this).attr('data-id'),_item = _this.editor['ace_editor_'+_id],_icon = '<span class="icon"><i class="glyphicon glyphicon-ok" aria-hidden="true"></i></span>';
$('.ace_toolbar_menu').show();
switch (_type) {
case 'cursor':
$('.ace_toolbar_menu').hide();
break;
case 'tab':
$('.ace_toolbar_menu .menu-tabs').show().siblings().hide();
$('.tabsType').find(_item.softTabs?'[data-value="nbsp"]':'[data-value="tabs"]').addClass('active').append(_icon);
$('.tabsSize [data-value="'+ _item.tabSize +'"]').addClass('active').append(_icon);
$('.menu-tabs li').click(function(e){
var _val = $(this).attr('data-value');
if($(this).parent().hasClass('tabsType')){
_item.ace.getSession().setUseSoftTabs(_val == 'nbsp');
_item.softTabs = _val == 'nbsp';
}else{
_item.ace.getSession().setTabSize(_val);
_item.tabSize = _val;
}
$(this).siblings().removeClass('active').find('.icon').remove();
$(this).addClass('active').append(_icon);
_this.currentStatusBar(_id);
e.stopPropagation();
e.preventDefault();
});
break;
case 'encoding':
$('.ace_toolbar_menu .menu-encoding').show().siblings().hide();
_this.setEncodingType();
$('.menu-encoding ul li').click(function (e) {
layer.msg('Set file encoding: ' + $(this).attr('data-value'));
$('.ace_conter_toolbar [data-type="encoding"]').html('coding: <i>'+ $(this).attr('data-value') +'</i>');
$(this).addClass('active').append(_icon).siblings().removeClass('active').find('span').remove();
_item.encoding = $(this).attr('data-value');
});
break;
case 'lang':
$('.ace_toolbar_menu').hide();
layer.msg('Switching language mode is not supported at this time, so stay tuned!',{icon:6});
// $('.ace_toolbar_menu .menu-files').show().siblings().hide();
// _this.getRelevanceList(_item.fileName);
break;
}
$('.ace_toolbar_menu').click(function(e){
e.stopPropagation();
e.preventDefault();
});
$(document).click(function(e){
$('.ace_toolbar_menu').hide();
$('.ace_toolbar_menu .menu-tabs,.ace_toolbar_menu .menu-encoding,.ace_toolbar_menu .menu-files').hide();
})
e.stopPropagation();
e.preventDefault();
});
// 搜索内容键盘事件
$('.menu-files .menu-input').keyup(function () {
_this.searchRelevance($(this).val());
if($(this).val != ''){
$(this).next().show();
}else{
$(this).next().hide();
}
});
// 清除搜索内容事件
$('.menu-files .menu-conter .fa').click(function(){
$('.menu-files .menu-input').val('').next().hide();
_this.searchRelevance()
});
// 状态
$('.ace_header span').click(function () {
var type = $(this).attr('class'),editor_item = _this.editor['ace_editor_'+ _this.ace_active ];
switch(type){
case 'saveFile': //保存当时文件
_this.saveFileBody({
path: editor_item.path,
data: editor_item.ace.getValue(),
encoding: editor_item.encoding
}, function (res) {
layer.msg(res.msg, {icon: 1});
editor_item.fileType = 0;
$('.item_tab_' + editor_item.id + ' .icon-tool').attr('data-file-state', '0').removeClass('glyphicon-exclamation-sign').addClass('glyphicon-remove');
});
break;
case 'saveFileAll': //保存全部
var loadT = layer.open({
type: 1,
area: ['350px', '180px'],
title: 'Tips',
content: '<div class="ace-clear-form">\
<div class="clear-icon"></div>\
<div class="clear-title">Do you want to save changes to all files?</div>\
<div class="clear-tips">If you don\'t save, the changes will be lost!</div>\
<div class="ace-clear-btn" style="">\
<button type="button" class="btn btn-sm btn-default clear-btn" style="margin-right:10px;" >Cancel</button>\
<button type="button" class="btn btn-sm btn-success save-all-btn">Save</button>\
</div>\
</div>',
success: function (layers, index) {
$('.clear-btn').click(function(){
layer.close(index);
});
$('.save-all-btn').click(function(){
var _arry = [],editor = aceEditor['editor'];
for(var item in editor){
_arry.push({
path: editor[item]['path'],
data: editor[item]['ace'].getValue(),
encoding: editor[item]['encoding'],
})
}
_this.saveAllFileBody(_arry,function(){
$('.ace_conter_menu>.item').each(function (el,index) {
var _id = $(this).attr('data-id');
$(this).find('i').attr('data-file-state','0').removeClass('glyphicon-exclamation-sign').addClass('glyphicon-remove')
aceEditor.editor['ace_editor_'+_id].fileType = 0;
});
layer.close(index);
});
});
}
});
break;
case 'refreshs': //刷新文件
if(editor_item.fileType === 0 ){
aceEditor.getFileBody({path:editor_item.path},function(res){
editor_item.ace.setValue(res.data);
editor_item.fileType = 0;
$('.item_tab_' + editor_item.id + ' .icon-tool').attr('data-file-state', '0').removeClass('glyphicon-exclamation-sign').addClass('glyphicon-remove');
layer.msg('Refresh successfully',{icon:1});
});
return false;
}
var loadT = layer.open({
type: 1,
area: ['350px', '180px'],
title: 'Tips',
content: '<div class="ace-clear-form">\
<div class="clear-icon"></div>\
<div class="clear-title">Whether to refresh the current file</div>\
<div class="clear-tips">Refreshing the current file will overwrite the current modification and continue!</div>\
<div class="ace-clear-btn" style="">\
<button type="button" class="btn btn-sm btn-default clear-btn" style="margin-right:10px;" >Cancel</button>\
<button type="button" class="btn btn-sm btn-success save-all-btn">Save</button>\
</div>\
</div>',
success: function (layers, index) {
$('.clear-btn').click(function(){
layer.close(index);
});
$('.save-all-btn').click(function(){
aceEditor.getFileBody({path:editor_item.path},function(res){
layer.close(index);
editor_item.ace.setValue(res.data);
editor_item.fileType == 0;
$('.item_tab_' + editor_item.id + ' .icon-tool').attr('data-file-state', '0').removeClass('glyphicon-exclamation-sign').addClass('glyphicon-remove');
layer.msg('Refresh successfully',{icon:1});
});
});
}
});
break;
// 搜索
case 'searchs':
break;
// 替换
case 'replaces':
break;
// 字体
case 'fontSize':
layer.open({
type:1,
area:['400px','300px'],
title:'Tips',
btn:['Save','Cancel'],
content:'<div class="ace-fontSize">\
<div class="line"><div class="">Font style</div><div class=""></div></div>\
<div class="line"><div class="">font size</div><div class=""><input type="text" />px</div></div>\
</div>',
yes:function(layers,index){
},
btn1:function(layers,index){
}
});
break;
case 'themes':
layer.msg('The theme feature is under development, so stay tuned!',{icon:6});
break;
case 'helps':
layer.open({
type:1,
area:'1300px',
title:'Help',
content:'<div class="helps_conter">\
<div class="helps_left">\
<div class="helps_item">Common shortcuts:</div>\
<div class="helps_box">\
ctrl+s&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Save</br>\
ctrl+a&nbsp;&nbsp;Select all&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ctrl+x&nbsp;&nbsp;Cut</br>\
ctrl+c&nbsp;&nbsp;Copy&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ctrl+v&nbsp;&nbsp;Paste</br>\
ctrl+z&nbsp;&nbsp;Cancel&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ctrl+y&nbsp;&nbsp;Anti-cancel</br>\
ctrl+f&nbsp;&nbsp;Find&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ctrl+alt+f&nbsp;&nbsp;Replace</br>\
win+alt+0&nbsp;&nbsp;Collapse all</br>\
win+alt+shift+0&nbsp;&nbsp;Expand all</br>\
esc&nbsp;&nbsp;[Exit the search and cancel the automatic prompt...]</br>\
ctrl-shift-s&nbsp;&nbsp;Preview</br>\
ctrl-shift-e&nbsp;&nbsp;Show & close function\
</div>\
<div class="helps_item">Select:</div>\
<div class="helps_box">\
Mouse frame selection -- drag</br>\
shift+home/end/up/left/down/right</br>\
shift+pageUp/PageDown&nbsp;&nbsp;Scroll up and down</br>\
ctrl+shift+ home/end&nbsp;&nbsp;Current cursor to the end of the head</br>\
alt+ Mouse drag&nbsp;&nbsp;Block selection</br>\
ctrl+alt+g&nbsp;&nbsp;Batch select current and enter multi-tab editing</br>\
</div>\
</div>\
<div class="helps_left">\
<div class="helps_item">Cursor movement:</div>\
<div class="helps_box">\
home/end/up/left/down/right</br>\
ctrl+home/end&nbsp;&nbsp;Cursor moves to the beginning/end of the document</br>\
ctrl+p&nbsp;&nbsp;Jump to the matching tag</br>\
pageUp/PageDown&nbsp;&nbsp;Cursor up and down</br>\
alt+left/right&nbsp;&nbsp;Cursor moves to the top of the line</br>\
shift+left/right&nbsp;&nbsp;Cursor moves to the beginning & end of the line</br>\
ctrl+l&nbsp;&nbsp;Jump to the specified line</br>\
ctrl+alt+up/down&nbsp;&nbsp;Add cursor to the top (bottom)</br>\
</div>\
<div class="helps_item">Edit:</div>\
<div class="helps_box">\
ctrl+/&nbsp;&nbsp;Comment & Uncomment&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ctrl+alt+a&nbsp;&nbsp;Align left and right</br>\
table&nbsp;&nbsp;Tab alignment&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;shift+table&nbsp;&nbsp;Overall advancement table</br>\
delete&nbsp;&nbsp;Delete&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ctrl+d&nbsp;&nbsp;Delete entire line</br>\
ctrl+delete&nbsp;&nbsp;Delete the word on the right side of the line</br>\
ctrl/shift+backspace&nbsp;&nbsp;Delete the word on the left</br>\
alt+shift+up/down&nbsp;&nbsp;Copy the line and add it to the top (below)</br>\
alt+delete&nbsp;&nbsp;Delete the right side of the cursor</br>\
alt+up/down&nbsp;&nbsp;The current line is swapped with the previous line (the next line)</br>\
ctrl+shift+d&nbsp;&nbsp;Copy the line and add it below</br>\
ctrl+delete&nbsp;&nbsp;Delete the word on the right</br>\
ctrl+shift+u&nbsp;&nbsp;Convert to lowercase</br>\
ctrl+u&nbsp;&nbsp;Convert selected content to uppercase</br>\
</div>\
</div>\
</div>'
});
break;
}
});
// 选择语言
this.setEditorView();
},
// 设置搜索视图
setSearchView:function(){
},
// 设置替换视图
setReplaceView:function(){
},
// 设置编辑器视图
setEditorView:function () {
var page_height = $('.aceEditors').height();
var ace_header = $('.ace_header').height();
var ace_conter_menu = $('.ace_conter_menu').height();
var ace_conter_toolbar = $('.ace_conter_toolbar').height();
var _height = page_height - ace_header - ace_conter_menu - ace_conter_toolbar - 42;
$('.ace_conter_editor').height(_height);
},
// 获取文件编码列表
getEncodingList: function (type) {
var _option = '';
for (var i = 0; i < this.encodingList.length; i++) {
var item = this.encodingList[i] == type.toUpperCase();
_option += '<li data- data-value="' + this.encodingList[i] + '" ' + (item ? 'class="active"' : '') + '>' + this.encodingList[i] + (item ?'<span class="icon"><i class="glyphicon glyphicon-ok" aria-hidden="true"></i></span>' : '') + '</li>';
}
$('.menu-encoding ul').html(_option);
},
// 获取文件关联列表
getRelevanceList: function (fileName) {
var _option = '', _top = 0, fileType = this.getFileType(fileName), _set_tops = 0;
for (var name in this.supportedModes) {
var data = this.supportedModes[name],item = (name == fileType.name);
_option += '<li data-height="' + _top + '" data-rule="' + this.supportedModes[name] + '" data-value="' + name + '" ' + (item ? 'class="active"' : '') + '>' + (this.nameOverrides[name] || name) + (item ?'<span class="icon"><i class="glyphicon glyphicon-ok" aria-hidden="true"></i></span>' : '') + '</li>'
if (item) _set_tops = _top
_top += 35;
}
$('.menu-files ul').html(_option);
$('.menu-files ul').scrollTop(_set_tops);
},
// 搜索文件关联
searchRelevance: function (search) {
if(search == undefined) search = '';
$('.menu-files ul li').each(function (index, el) {
var val = $(this).attr('data-value').toLowerCase(),
rule = $(this).attr('data-rule'),
suffixs = rule.split('|'),
_suffixs = false;
search = search.toLowerCase();
for (var i = 0; i < suffixs.length; i++) {
if (suffixs[i].indexOf(search) > -1) _suffixs = true
}
if (search == '') {
$(this).removeAttr('style');
} else {
if (val.indexOf(search) == -1) {
$(this).attr('style', 'display:none');
} else {
$(this).removeAttr('style');
}
if (_suffixs) $(this).removeAttr('style')
}
});
},
// 设置编码类型
setEncodingType: function (encode) {
this.getEncodingList('UTF-8');
$('.menu-encoding ul li').click(function (e) {
layer.msg('Set file encoding' + $(this).attr('data-value'));
$(this).addClass('active').append('<span class="icon"><i class="glyphicon glyphicon-ok" aria-hidden="true"></i></span>').siblings().removeClass('active').find('span').remove();
});
},
// 更新状态栏
currentStatusBar: function(id){
var _editor = this.editor['ace_editor_'+id];
$('.ace_conter_toolbar [data-type="path"]').html('Dir<i>'+ _editor.path +'</i>');
$('.ace_conter_toolbar [data-type="tab"]').html(_editor.softTabs?'Space<i>'+ _editor.tabSize +'</i>':'Tab length<i>'+ _editor.tabSize +'</i>');
$('.ace_conter_toolbar [data-type="encoding"]').html('coding<i>'+ _editor.encoding.toUpperCase() +'</i>');
$('.ace_conter_toolbar [data-type="lang"]').html('Language<i>'+ _editor.type +'</i>');
$('.ace_conter_toolbar span').attr('data-id',id);
_editor.ace.resize();
},
// 创建ACE编辑器-对象
creationEditor: function (obj, callabck) {
var _this = this;
$('#ace_editor_' + obj.id).text(obj.data || '');
if(this.editor == null) this.editor = {}
this.editor['ace_editor_' + obj.id] = {
ace: ace.edit("ace_editor_" + obj.id, {
theme: "ace/theme/monokai", //主题
mode: "ace/mode/" + (obj.fileName != undefined ? obj.mode : 'text'), // 语言类型
wrap: true,
showInvisibles:false,
showPrintMargin: false,
enableBasicAutocompletion: true,
enableSnippets: true,
enableLiveAutocompletion: true,
useSoftTabs:false,
tabSize:4,
keyboardHandler:'sublime'
}), //ACE编辑器对象
id: obj.id,
wrap: true, //是否换行
path:obj.path,
tabSize:4,
softTabs:false,
fileName:obj.fileName,
enableSnippets: true, //是否代码提示
encoding: (obj.encoding != undefined ? obj.encoding : 'utf-8'), //编码类型
mode: (obj.fileName != undefined ? obj.mode : 'text'), //语言类型
type:obj.type,
fileType: 0, //文件状态
historys: obj.historys
};
var ACE = this.editor['ace_editor_' + obj.id];
ACE.ace.moveCursorTo(0, 0); //设置鼠标焦点
ACE.ace.resize(); //设置自适应
ACE.ace.commands.addCommand({
name: 'Save document',
bindKey: {
win: 'Ctrl-S',
mac: 'Command-S'
},
exec: function (editor) {
// 保存文件
_this.saveFileBody({
path: ACE.path,
data: editor.getValue(),
encoding: ACE.encoding
}, function (res) {
layer.msg(res.msg, {icon: 1});
ACE.fileType = 0;
$('.item_tab_' + ACE.id + ' .icon-tool').attr('data-file-state', '0').removeClass('glyphicon-exclamation-sign').addClass('glyphicon-remove');
});
},
readOnly: false // 如果不需要使用只读模式,这里设置false
});
// 获取光标位置
ACE.ace.getSession().selection.on('changeCursor', function(e) {
var _cursor = ACE.ace.selection.getCursor();
$('[data-type="cursor"]').html('Row<i class="cursor-row">'+ (_cursor.row + 1) +'</i>,Column<i class="cursor-line">'+ _cursor.column +'</i>');
});
// 触发修改内容
ACE.ace.getSession().on('change', function (editor) {
$('.item_tab_' + ACE.id + ' .icon-tool').addClass('glyphicon-exclamation-sign').removeClass('glyphicon-remove').attr('data-file-state', '1');
ACE.fileType = 1;
});
this.currentStatusBar(ACE.id);
},
// 获取文件模型
getFileType: function (fileName) {
var filenames = fileName.split('.')[1],modesByName = {};
for (var name in this.supportedModes) {
var data = this.supportedModes[name];
var suffixs = data[0].split('|');
var filename = name.toLowerCase()
for (var i = 0; i < suffixs.length; i++) {
if (filenames == suffixs[i]){
return { name: name,mode: filename }
}
}
}
return {name:'Text',mode:'text'}
},
// 新建编辑器视图-方法
addEditor: function () {
var _index = this.editorLength,_id = bt.get_random(8);
$('.ace_conter_menu .item').removeClass('active');
$('.ace_conter_editor .ace_editors').removeClass('active');
$('.ace_conter_menu .ace_editor_add').before('<div class="item active item_tab_'+_id+'" data-type="text" data-id="'+_id+'" data-index="'+ _index +'">\
<span class="icon_file"><i class="fa fa-code" aria-hidden="true"></i></span>\
<span>Untitled-'+_index+'</span>\
<i class="fa fa-circle icon-tool" aria-hidden="true" data-file-state="1" data-title="Untitled-'+ _index +'"></i>\
</div>');
$('.ace_conter_editor').append('<div id="ace_editor_'+_id+'" class="ace_editors active"></div>');
$('#ace_editor_' + _id).siblings().removeClass('active');
this.creationEditor({ id: _id });
this.editorLength = this.editorLength + 1;
},
// 删除编辑器视图-方法
removeEditor: function (id) {
if ($('.item_tab_' + id).next('.item').length == 0) {
$('.item_tab_' + id).prev('.item').addClass('active');
$('#ace_editor_' + id).prev('.ace_editor').addClass('active');
this.ace_active = $('.item_tab_' + id).prev('.item').attr('data-id');
} else {
$('.item_tab_' + id).next('.item').addClass('active');
$('#ace_editor_' + id).next('.ace_editor').addClass('active');
this.ace_active = $('.item_tab_' + id).next('.item').attr('data-id');
}
$('.item_tab_' + id).remove();
$('#ace_editor_' + id).remove();
for(var i=0;i<aceEditor.pathAarry.length;i++){
if(aceEditor.pathAarry[i] == this.editor['ace_editor_' + id].path){
aceEditor.pathAarry.splice(i,1);
}
}
delete this.editor['ace_editor_' + id];
this.editorLength --;
if(this.editorLength === 0){
this.ace_active = '';
this.pathAarry = [];
$('.layui-layer-close').click();
}else{
this.currentStatusBar(this.ace_active);
}
},
// 打开编辑器文件-方法
openEditorView: function (path) {
if(path == undefined) return false;
// 文件类型(type,列如:JavaScript 、文件模型(mode,列如:text)、文件标识(id,列如:x8AmsnYn)、文件编号(index,列如:0)、文件路径 (path,列如:/www/root/)
var _this = this,paths = path.split('/'),_fileName = paths[paths.length - 1],_fileType = this.getFileType(_fileName),_type = _fileType.name,_mode = _fileType.mode,_id = bt.get_random(8),_index = this.editorLength;
this.getFileBody({path: path}, function (res) {
_this.pathAarry.push(path);
$('.ace_conter_menu .item').removeClass('active');
$('.ace_conter_editor .ace_editors').removeClass('active');
$('.ace_conter_menu .ace_editor_add').before('<div class="item active item_tab_' + _id +'" title="'+ path +'" data-type="'+ _type +'" data-mode="'+ _mode +'" data-id="'+ _id +'" data-index="'+ _index +'" data-fileName="'+ _fileName +'">\
<span class="icon_file"><img src="/static/img/iconfont_code.png" style="width:16px;" /></span><span>' + _fileName + '</span>\
<i class="glyphicon glyphicon-remove icon-tool" aria-hidden="true" data-file-state="0" data-title="' + _fileName + '"></i>\
</div>');
$('.ace_conter_editor').append('<div id="ace_editor_'+_id +'" class="ace_editors active"></div>');
_this.ace_active = _id;
_this.editorLength = _this.editorLength + 1;
_this.creationEditor({id: _id,fileName: _fileName,path: path,mode:_mode,encoding: res.encoding,data: res.data,type:_type,historys:res.historys});
});
},
// 获取收藏夹列表-方法
getFavoriteList: function () {},
// 获取文件列表-请求
getFileList: function () {},
// 获取文件内容-请求
getFileBody: function (obj, callback) {
var loadT = layer.msg('Getting file content, please wait...',{time: 0,icon: 16,shade: [0.3, '#000']}),_this = this;
$.post("/files?action=GetFileBody", "path=" + encodeURIComponent(obj.path), function(res) {
layer.close(loadT);
if (!res.status) {
if(_this.editorLength == 0) layer.closeAll();
layer.msg(res.msg, {icon: 2});
return false;
}else{
if(!aceEditor.isAceView){
var _path = obj.path.split('/');
layer.msg('Opened file ['+ (_path[_path.length-1]) +']');
}
}
if (callback) callback(res);
});
},
// 保存文件内容-请求
saveFileBody: function (obj, callback) {
var loadT = layer.msg('Saving file content, please wait...', {time: 0,icon: 16,shade: [0.3, '#000']});
$.post("/files?action=SaveFileBody","data=" + encodeURIComponent(obj.data) + "&path=" + encodeURIComponent(obj.path) + "&encoding=" + obj.encoding, function(res) {
layer.close(loadT);
if (callback) callback(res)
});
},
// 递归保存文件
saveAllFileBody:function(arry,num,callabck) {
var _this = this;
if(typeof num == "function"){
callabck = num; num = 0;
}else if(typeof num == "undefined"){
num = 0;
}
if(num == arry.length){
if(callabck) callabck();
layer.msg('All saved successfully',{icon:1});
return false;
}
aceEditor.saveFileBody({
path: arry[num].path,
data: arry[num].data,
encoding: arry[num].encoding
},function(){
num = num + 1;
aceEditor.saveAllFileBody(arry,num,callabck);
});
}
}
var my_headers = {};
var request_token_ele = document.getElementById("request_token_head");
if (request_token_ele) {
@@ -699,11 +1539,11 @@ function SafeMessage(j, h, g, f) {
$("#toSubmit").click(function() {
var a = $("#vcodeResult").val().replace(/ /g, "");
if(a == undefined || a == "") {
layer.msg(lan.index.input_calc_result);
layer.msg(lan.public.input_calc_result);
return
}
if(a != getCookie("vcodesum")) {
layer.msg(lan.index.input_calc_result);
layer.msg(lan.public.input_calc_result);
return
}
layer.close(mess);
+1 -1
View File
@@ -173,7 +173,7 @@ var site = {
},
{ field: 'addtime', title: lan.site.backup_time },
{
field: 'opt', title: lan.site.operation, align: 'right', templet: function (item) {
field: 'opt', title: lan.site.operate, align: 'right', templet: function (item) {
var _opt = '<a class="btlink" href="/download?filename=' + item.filename + '&amp;name=' + item.name + '" target="_blank">'+lan.site.download+'</a> | ';
_opt += '<a class="btlink" herf="javascrpit:;" onclick="bt.site.del_backup(\'' + item.id + '\',\'' + id + '\',\'' + siteName + '\')">'+lan.site.del+'</a>'
return _opt;
+1 -1
View File
@@ -495,7 +495,7 @@ var soft = {
return;
}
var f = fs[0]
if (f.type !== 'application/x-zip-compressed' && f.type !== 'application/zip') {
if (f.type.indexOf('zip') == -1) {
layer.msg('Only supports files in zip format!');
return;
}
+7
View File
@@ -45,6 +45,13 @@
<label class='btswitch-btn' for='panelDebug' onclick="SetDebug()"></label>
</div>
</div>
<div class="ss-text pull-left mr50">
<em title="after Open, The panel will stop connecting to the cloud, and the software installation, uninstallation, panel update and other functions will not be available.">Offline mode</em>
<div class='ssh-item'>
<input class='btswitch btswitch-ios' id='panelLocal' type='checkbox' {{data['is_local']}}>
<label class='btswitch-btn' for='panelLocal' onclick="set_local()"></label>
</div>
</div>
</div>
</div>
<div class="setbox bgw mtb15">
+110
View File
@@ -57,10 +57,120 @@
<li onclick="javascript:Batch(3);"><a style="cursor: pointer;">{{data['lan']['L4']}}</a></li>
<li onclick="javascript:Batch(4);"><a style="cursor: pointer;">{{data['lan']['L5']}}</a></li>
</ul>
<!--<link rel="stylesheet" href="./static/ace/font-awesome/css/font-awesome.min.css">-->
<script type="text/tmplate" id="aceTmplate">
<div id="ace_conter">
<div class="ace_header">
<span class="saveFile"><i class="glyphicon glyphicon-floppy-disk" aria-hidden="true"></i>Save</span>
<span class="saveFileAll"><i class="glyphicon glyphicon-duplicate" aria-hidden="true"></i>Save All</span>
<span class="refreshs"><i class="glyphicon glyphicon-refresh" aria-hidden="true"></i>Refresh</span>
<!-- <span class="searchs"><i class="fa fa-search" aria-hidden="true"></i>搜索</span>
<span class="replaces"><i class="fa fa-random" aria-hidden="true"></i>替换</span>
<span class="fontSize"><i class="fa fa-text-height" aria-hidden="true"></i>字体</span> -->
<!-- <span class="themes"><i class="fa fa-tachometer" aria-hidden="true"></i>主题</span> -->
<span class="helps"><i class="glyphicon glyphicon-question-sign" aria-hidden="true"></i>Help</span>
<div class="pull-down" title="Hide toolbar"><i class="glyphicon glyphicon-menu-down" aria-hidden="true"></i></div>
</div>
<div class="ace_overall">
<!-- 编辑器目录 -->
<div class="ace_catalogue">
<div class="ace_catalogue_title">Favorites</div>
<div class="ace_catalogue_list">
<ul class="cd-accordion-menu animated">
<li class="has-children">
<input type="checkbox" name ="group-1" id="group-1" checked>
<label for="group-1">Group 1</label>
<ul>
<li class="has-children">
<input type="checkbox" name ="sub-group-1" id="sub-group-1">
<label for="sub-group-1">Sub Group 1</label>
<ul>
<li><a href="#0">Image</a></li>
<li><a href="#0">Image</a></li>
<li><a href="#0">Image</a></li>
</ul>
</li>
<li class="has-children">
<input type="checkbox" name ="sub-group-2" id="sub-group-2">
<label for="sub-group-2">Sub Group 2</label>
<ul>
<li class="has-children">
<input type="checkbox" name ="sub-group-level-3" id="sub-group-level-3">
<label for="sub-group-level-3">Sub Group Level 3</label>
<ul>
<li><a href="#0">Image</a></li>
<li><a href="#0">Image</a></li>
</ul>
</li>
<li><a href="#0">Image</a></li>
</ul>
</li>
<li><a href="#0">Image</a></li>
<li><a href="#0">Image</a></li>
</ul>
</li>
</ul>
</div>
</div>
<!-- 编辑内容 -->
<!-- <div class="ace_catalogue_sidebar"><img src="/static/img/col-resize.png" /></div> -->
<div class="ace_editor_main">
<div class="ace_conter_menu">
<div class="ace_editor_add" style="display:none;"><i class="fa fa-plus-square" aria-hidden="true"></i></div>
</div>
<div class="ace_editor_main_storey"></div>
<div class="ace_conter_editor"></div>
<div class="ace_conter_toolbar">
<div class="pull-left">
<span data-type="path"></span>
</div>
<div class="pull-right">
<span data-type="cursor"></span>
<span data-type="tab"></span>
<span data-type="encoding"></span>
<span data-type="lang"></span>
<!--<span data-type="history"></span>-->
</div>
</div>
</div>
<div class="ace_toolbar_menu" style="display: none;">
<div class="menu-item menu-tabs" style="display: none;">
<div class="menu-title">Set tabs</div>
<ul class="tabsType">
<li data-value="nbsp">Indent using spaces</li>
<li data-value="tabs">Indent using "Tab"</li>
</ul>
<div class="menu-title" style="margin-top:15px">Set the tab length</div>
<ul class="tabsSize">
<li data-value="1">1</li>
<li data-value="2">2</li>
<li data-value="3">3</li>
<li data-value="4">4</li>
<li data-value="5">5</li>
<li data-value="6">6</li>
<li data-value="7">7</li>
<li data-value="8">8</li>
</ul>
</div>
<div class="menu-item menu-encoding" style="display: none;">
<div class="menu-title">Set file save encoding format</div>
<ul></ul>
</div>
<div class="menu-item menu-files" style="display: none;">
<div class="menu-conter"><input type="text" class="menu-input" placeholder="Input language mode"><i class="fa fa-close" aria-hidden="true"></i></div>
<div class="menu-title">Set file language association</div>
<ul></ul>
</div>
</div>
</div>
</div>
</script>
<script src="/static/js/jquery-ui.min.js"></script>
<script src="/static/js/jquery.contextify.min.js"></script>
<script src="/static/js/files.js?date={{g.version}}"></script>
<script src="/static/js/upload.js?date={{g.version}}"></script>
<script type="text/javascript" src="./static/ace/ace.js"></script>
<script type="text/javascript" src="./static/ace/ext-language_tools.js"></script>
<script type="text/javascript">
setTimeout(function(){
GetDisk();
+351
View File
@@ -0,0 +1,351 @@
{% extends "layout.html" %}
{% block content %}
<style>
.weblog {
font-size: 14px;
display: inline-block;
line-height: 30px;
}
.weblog em {
font-style: normal;
color: #666;
margin: 0 15px;
font-size:12px;
}
.weblog span {
margin-right: 10px;
}
.weblog a {
color: #20a53a;
}
.firewall-port-box{
margin-bottom:15px;
}
</style>
<div class="main-content">
<div class="container-fluid" style="padding-bottom: 50px;">
<div class="pos-box bgw mtb15">
<div class="position f14 c9 pull-left">
<a class="plr10 c4" href="/">{{data['lan']['H1']}}</a>/<span class="plr10 c4">{{data['lan']['H2']}}</span>
</div>
<div class="search pull-right">
<form target="hid" onsubmit='firewall.get_log_list(1,$("#SearchValue").prop("value"))'>
<input type="text" id="SearchValue" class="ser-text pull-left" placeholder="{{data['lan']['SEARCH']}}" />
<button type="button" class="ser-sub pull-left" onclick='firewall.get_log_list(1,$("#SearchValue").prop("value"))'></button>
</form>
<iframe name='hid' id="hid" style="display:none"></iframe>
</div>
</div>
<div class="safe container-fluid bgw mtb15 pd15">
<div class="mr50 pull-left">
<form>
<div class="ss-text pull-left">
<em>{{data['lan']['BTN1']}}</em>
<div class='ssh-item' id="in_safe">
<input class='btswitch btswitch-ios' id='sshswitch' type='checkbox' checked><label class='btswitch-btn sshswitch' for='sshswitch' ></label>
</div>
</div>
</form>
</div>
<div class="mr50 pull-left">
<div class="ss-text pull-left mr5">
<em>{{data['lan']['BTN2']}}</em>
<input type="text" class="bt-input-text" id="mstscPort" value="" />
</div>
<div class="ss-text pull-left">
<button id="mstscSubmit" onclick='bt.firewall.set_mstsc($("#mstscPort").prop("value"))' class="btn btn-default btn-sm" type="button">{{data['lan']['BTN3']}}</button>
</div>
</div>
<div class="mr50 pull-left" style="border-right: 1px solid #ccc; padding-right: 40px;">
<div class="ss-text pull-left">
<em>{{data['lan']['BTN4']}}</em>
<div class='ssh-item' id="isPing">
<input class='btswitch btswitch-ios' id='noping' type='checkbox' checked><label class='btswitch-btn noping' for='noping' ></label>
</div>
</div>
</div>
<div class="weblog">
<span class="f12 c5">{{data['lan']['S1']}}</span><a href="javascript:openPath('{{session['logsPath']}}');">{{session['logsPath']}}</a><em id="logSize">0KB</em>
<button class="btn btn-default btn-sm" onclick="firewall.clear_logs_files();">{{data['lan']['BTN5']}}</button>
</div>
</div>
<div class="white-black-ip bgw mtb15">
<div class="black-ip">
<div class="def-log">
<div class="title c6 plr15">
<h3 class="f16">{{data['lan']['H3']}}</h3>
</div>
<div class="divtable pd15">
<div class="firewall-port-box">
<select id="firewalldType" class="bt-input-text c5 mr5" name="type" style="width:120px;">
<option value="port">{{data['lan']['F1']}}</option>
<option value="address">{{data['lan']['F2']}}</option>
<option value="ip_port">Specify IP release port</option>
</select>
<select id="type_pool" class="bt-input-text c5 mr5" name="type" style="width:80px;">
<option value="tcp">TCP</option>
<option value="udp">UDP</option>
</select>
<input type="text" class="bt-input-text mr5" style="width: 117px;" id="AcceptPort" placeholder="{{data['lan']['F3']}}">
<input type="text" class="bt-input-text mr5" style="width: 150px;display:none;" id="AcceptAddress" placeholder="被放行的IP地址">
<input type="text" class="bt-input-text mr5" id="Ps" placeholder="{{data['lan']['F4']}}">
<button id="toAccept" onclick="firewall.add_accept_port()" class="btn btn-default btn-sm va0" type="button">{{data['lan']['F5']}}</button>
<span id="f-ps" class="c9" style="margin-left: 10px;">{{data['lan']['F6']}}</span>
</div>
<div class="tablescroll">
<table id="firewallBody" class="table table-hover" style="min-width: 640px;border: 0 none;">
</table>
</div>
<div class="dataTables_paginate paging_bootstrap page firewallBody" style="margin-bottom:0">
</div>
</div>
</div>
</div>
</div>
<div class="white-black-ip bgw mtb15">
<div class="black-ip">
<div class="def-log">
<div class="title c6 plr15">
<h3 class="f16">{{data['lan']['H4']}}</h3>
<a class="btn btn-default btn-sm va0" onclick="bt.firewall.clear_logs(function(){firewall.get_log_list()});">{{data['lan']['BTN5']}}</a>
<span class="btn btn-default btn-sm" style="position: absolute;right: 30px;margin-top: 10px;" onclick="firewall.get_panel_error_logs()">面板运行日志</span>
</div>
<div class="divtable pd15">
<div class="tablescroll">
<table id="logsBody" class="table table-hover" style="min-width: 640px;border: 0 none;">
</table>
</div>
<div class="dataTables_paginate paging_bootstrap page logsBody" style="margin-bottom:0">
</div>
</div>
</div>
</div>
</div>
</div>
</div>
{% endblock %}
{% block scripts %}
<script type="text/javascript">
var firewall = {
get_init:function(){
firewall.flush_init();
firewall.get_list();
firewall.get_log_list();
firewall.get_logs_size();
$('.sshswitch').click(function(){
var status = $("#sshswitch").prop("checked")==true?1:0;
bt.firewall.set_mstsc_status(status,function(rdata){
if(rdata===-1){
if(status){
$("#sshswitch").prop("checked","checked")
}else{
$("#sshswitch").removeAttr('checked');
}
}else{
bt.msg(rdata);
firewall.flush_init();
}
})
})
$('.noping').click(function(){
var status = $("#noping").prop("checked")==true?1:0;
bt.firewall.ping(status,function(rdata){
if(rdata===-1){
if(status){
$("#noping").prop("checked","checked")
}else{
$("#noping").removeAttr('checked');
}
}else{
bt.msg(rdata);
firewall.flush_init();
}
})
})
$("#firewalldType").change(function(){
var type = $(this).val();
var w = '120px';
var p = lan.firewall.port;
var t = lan.firewall.accept;
var m = lan.firewall.port_ps;
$("#AcceptAddress").hide();
if (type == 'address') {
w = '150px';
p = lan.firewall.ip;
t = lan.firewall.drop;
m = lan.firewall.ip_ps;
} else if (type === 'ip_port') {
$("#AcceptAddress").show();
m = 'NOTE: Only specified IP addresses are allowed to access a port. For example: Only 192.168.0.1 is allowed to access port 8080.';
}
$("#AcceptPort").css("width",w);
$("#AcceptPort").attr('placeholder',p);
$("#toAccept").html(t);
$("#f-ps").html(m);
});
},
flush_init:function(){
bt.firewall.get_ssh_info(function(rdata){
if(!rdata.status){
$("#mstscSubmit").attr('disabled','disabled')
$("#mstscPort").attr('disabled','disabled')
$('#sshswitch').removeAttr('checked');
}
else{
$("#mstscSubmit").removeAttr('disabled')
$("#mstscPort").removeAttr('disabled')
$('#sshswitch').attr('checked','checked');
}
if(rdata.ping){
$('#noping').removeAttr('checked');
}else{
$('#noping').attr('checked','checked');
}
$("#mstscPort").val(rdata.port);
})
},
get_logs_size:function(){
bt.firewall.get_logs_size(function(rdata){
$("#logSize").text(rdata);
})
},
clear_logs_files:function(){
bt.firewall.clear_logs_files(function(rdata){
$("#logSize").text(rdata);
bt.msg({msg:lan.firewall.empty,icon:1});
})
},
add_accept_port:function(){
var type = $("#firewalldType").val();
var port = $("#AcceptPort").val();
var ps = $("#Ps").val();
bt.firewall.add_accept_port(type,port,ps,function(rdata){
if(rdata.status){
firewall.get_list();
$("#AcceptPort").val('');
$("#Ps").val('');
}
bt.msg(rdata);
})
},
remove_accept_port: function (id,port) {
bt.firewall.del_accept_port(id, port, function (rdata) {
if (rdata.status) {
firewall.get_list();
}
bt.msg(rdata);
})
},
get_list:function(page,search){
if(page==undefined) page=1;
$.post('/firewall_new?action=GetList', { p: page, search: search,collback:'firewall.get_list' }, function (rdata) {
$('.firewallBody').html(rdata.page);
var ports_ps = { "3306": "MySQL service default port", "888": "phpMyAdmin default port", "22": "SSH remote service", "20": "FTP active mode data port", "21": "FTP protocol default port", "39000-40000": "FTP passive mode port range", "30000-40000": "FTP passive mode port range","11211":"Memcached service port","873":"Rsync data synchronization service","8888":"aaPanel Linux panel default port"}
var _tab = bt.render({
table:'#firewallBody',
columns:[
{ field: 'id', title: "{{data['lan']['TH1']}}"},
{ field: 'port', title: "{{data['lan']['TH2']}}",templet:function(item){
var _ps = lan.firewall.accept_port;
if(bt.contains(item.port,'.')){
_ps = lan.firewall.drop_ip;
}
_ps += ':['+item.port+']'
return _ps;
}},
{ field: 'status', title: "{{data['lan']['TH3']}}",templet:function(item){
var status = '';
switch(item.status){
case 0:
status = lan.firewall.status_not;
break;
case 1:
status = lan.firewall.status_net;
break;
default:
status = lan.firewall.status_ok;
break;
}
return status;
},help:'https://www.bt.cn/bbs/thread-4708-1-1.html'},
{ field: 'addtime', title: "{{data['lan']['TH4']}}"},
{ field: 'ps', title: "{{data['lan']['TH5']}}", templet: function (item) {
if (item.port in ports_ps) return ports_ps[item.port];
return item.ps;
}},
{ field: 'opt',align:'right',width:50, title: "{{data['lan']['TH6']}}",templet:function(item){
return '<a href="javascript:;" class="btlink" onclick="firewall.remove_accept_port('+item.id+',\''+item.port+'\')">Delete</a>';
}}
],
data:rdata.data
})
})
},
get_log_list:function(page,search){
if (page == undefined) page = 1;
if (search == undefined) search = $("#SearchValue").val();
bt.firewall.get_log_list(page,search,function(rdata){
$('.logsBody').html(rdata.page);
var _tab = bt.render({
table:'#logsBody',
columns:[
{ field: 'id', title: "{{data['lan']['LTH1']}}"},
{ field: 'type', title: "{{data['lan']['LTH2']}}"},
{ field: 'log', title: "{{data['lan']['LTH3']}}"},
{ field: 'addtime', title: "{{data['lan']['LTH4']}}"}
],
data:rdata.data
})
})
},
//查看面板运行日志
get_panel_error_logs: function () {
layer.msg(lan.public.the_get, { icon: 16, time: 0, shade: [0.3, '#000'] });
$.post('/config?action=get_panel_error_logs', {}, function (rdata) {
layer.closeAll();
if (!rdata.status) {
layer.msg(rdata.msg, { icon: 2 });
return;
};
layer.open({
type: 1,
title: 'Panel run log',
area: ['700px', '490px'],
shadeClose: false,
closeBtn: 2,
content: '<div class="setchmod bt-form pb70">'
+ '<pre class="crontab-log" style="overflow: auto; border: 0px none; line-height:23px;padding: 15px; margin: 0px; white-space: pre-wrap; height: 405px; background-color: rgb(51,51,51);color:#f1f1f1;border-radius:0px;font-family: \"微软雅黑\"">' + (rdata.msg == '' ? 'Current log is empty' : rdata.msg) + '</pre>'
+ '<div class="bt-form-submit-btn" style="margin-top: 0px;">'
+ '<button type="button" class="btn btn-danger btn-sm btn-title" style="margin-right:15px;" onclick="firewall.clean_panel_error_logs()">' + lan.public.empty + '</button>'
+ '<button type="button" class="btn btn-success btn-sm btn-title" onclick="layer.closeAll()">' + lan.public.close + '</button>'
+ '</div>'
+ '</div>'
});
setTimeout(function () {
$("#crontab-log").text(rdata.msg);
var div = document.getElementsByClassName('crontab-log')[0]
div.scrollTop = div.scrollHeight;
}, 200)
}).error(function () {
layer.closeAll();
layer.msg('Unable to get log!', { icon: 2 });
});
},
//清空面板错误日志
clean_panel_error_logs:function() {
layer.msg(lan.public.the_get, { icon: 16, time: 0, shade: [0.3, '#000'] });
$.post('/config?action=clean_panel_error_logs', {}, function (rdata) {
layer.closeAll();
layer.msg(rdata.msg, { icon: 1 });
});
}
}
firewall.get_init();
</script>
{% endblock %}
+7 -46
View File
@@ -27,7 +27,7 @@ class panelSetup:
if ua:
ua = ua.lower();
if ua.find('spider') != -1 or ua.find('bot') != -1: return redirect('https://www.baidu.com');
g.version = '6.1.5'
g.version = '6.2.0'
g.title = public.GetConfigValue('title')
g.uri = request.path
session['version'] = g.version;
@@ -42,36 +42,18 @@ class panelAdmin(panelSetup):
def local(self):
result = panelSetup().init()
if result: return result
result = self.checkLimitIp()
if result: return result
result = self.setSession();
if result: return result
result = self.checkClose();
if result: return result
result = self.checkWebType();
if result: return result
result = self.checkDomain();
result = self.check_login();
if result: return result
result = self.checkConfig();
#self.checkSafe();
self.GetOS();
#检查IP白名单
def checkAddressWhite(self):
token = self.GetToken();
if not token: return redirect('/login');
if not request.remote_addr in token['address']: return redirect('/login');
#检查IP限制
def checkLimitIp(self):
if os.path.exists('data/limitip.conf'):
iplist = public.ReadFile('data/limitip.conf')
if iplist:
iplist = iplist.strip();
if not request.remote_addr in iplist.split(','): return redirect('/login')
#设置基础Session
def setSession(self):
session['menus'] = sorted(json.loads(public.ReadFile('config/menu.json')),key=lambda x:x['sort'])
@@ -114,8 +96,8 @@ class panelAdmin(panelSetup):
if os.path.exists('data/close.pl'):
return redirect('/close');
#检查域名绑定
def checkDomain(self):
#检查登录
def check_login(self):
try:
api_check = True
if not 'login' in session:
@@ -123,10 +105,6 @@ class panelAdmin(panelSetup):
if api_check: return api_check
else:
if session['login'] == False: return redirect('/login')
tmp = public.GetHost()
domain = public.ReadFile('data/domain.conf')
if domain:
if(tmp.strip().lower() != domain.strip().lower()): return redirect('/login')
if api_check:
try:
sess_out_path = 'data/session_timeout.pl'
@@ -176,24 +154,7 @@ class panelAdmin(panelSetup):
session['config']['email'] = public.M('users').where("id=?",('1',)).getField('email');
if not 'address' in session:
session['address'] = public.GetLocalIp()
def checkSafe(self):
mods = ['/','/site','/ftp','/database','/plugin','/soft','/public'];
if not os.path.exists('/www/server/panel/data/userInfo.json'):
if 'vip' in session: del(session.vip);
if not request.path in mods: return True
if 'vip' in session: return True
import panelAuth
data = panelAuth.panelAuth().get_order_status(None);
try:
if data['status'] == True:
session.vip = data
return True
return redirect('/vpro');
except:pass
return False
#获取操作系统类型
def GetOS(self):
if not 'server_os' in session:
+14 -1
View File
@@ -939,6 +939,19 @@ class config:
else:
t_str = 'Open'
public.writeFile(debug_path,'True')
public.WriteLog('TYPE_PANEL','%sDeveloper mode(debug)' % t_str)
public.WriteLog('TYPE_PANEL','%s Developer mode(debug)' % t_str)
public.restart_panel()
return public.returnMsg(True,'Successful setup!')
#设置离线模式
def set_local(self,get):
d_path = 'data/not_network.pl'
if os.path.exists(d_path):
t_str = 'Close'
os.remove(d_path)
else:
t_str = 'Open'
public.writeFile(d_path,'True')
public.WriteLog('TYPE_PANEL','%s Offline mode' % t_str)
return public.returnMsg(True,'Successful setup!')
+1 -1
View File
@@ -363,7 +363,7 @@ class crontab:
shell=wheres[type]
except:
if type == 'toUrl':
shell = head + "curl -sS --connect-timeout 10 -m 60 '" + param['urladdress']+"'";
shell = head + "curl -sS --connect-timeout 10 -m 3600 '" + param['urladdress']+"'";
else:
shell=head+param['sBody'].replace("\r\n","\n")
+4 -4
View File
@@ -102,7 +102,7 @@ class database(datatool.datatools):
if "libmysqlclient" in mysqlMsg:
result = self.rep_lnk()
os.system("pip uninstall mysql-python -y")
os.system("pip install mysql-python")
os.system("pip install pymysql")
public.writeFile('data/restart.pl','True')
return public.returnMsg(False,"MYSQL_FIX_WITH_AUTO_ERR")
return None
@@ -299,7 +299,7 @@ SetLink
def SetupPassword(self,get):
password = get['password'].strip()
try:
rep = "^[\w@\.]+$"
rep = "^[\w@\.\?\-\_\>\<\~\!\#\$\%\^\&\*\(\)]+$"
if not re.match(rep, password): return public.returnMsg(False, 'DATABASE_NAME_ERR_T')
mysql_root = public.M('config').where("id=?",(1,)).getField('mysql_root')
#修改MYSQL
@@ -343,7 +343,7 @@ SetLink
id = get['id']
name = public.M('databases').where('id=?',(id,)).getField('name');
rep = "^[\w@\.]+$"
rep = "^[\w@\.\?\-\_\>\<\~\!\#\$\%\^\&\*\(\)]+$"
if len(re.search(rep, newpassword).groups()) > 0: return public.returnMsg(False, 'DATABASE_NAME_ERR_T')
#修改MYSQL
@@ -447,7 +447,7 @@ SetLink
tmpFile = tmpFile.replace('.' + ext, '.sql')
tmpFile = tmpFile.replace('tar.', '')
backupPath = session['config']['backup_path'] + '/database'
if ext == 'zip':
public.ExecShell("cd " + backupPath + " && unzip " + file)
else:
+42 -6
View File
@@ -707,7 +707,8 @@ class files:
else:
data['data'] = srcBody.decode('utf-8')
data['encoding'] = u'utf-8';
if hasattr(get,'filename'): get.path = get.filename
data['historys'] = self.get_history(get.path)
return data;
except Exception as ex:
return public.returnMsg(False,'INCOMPATIBLE_FILECODE',(str(ex)),)
@@ -744,12 +745,14 @@ class files:
pass
if get.encoding == 'ascii':get.encoding = 'utf-8';
self.save_history(get.path)
if sys.version_info[0] == 2:
data = data.encode(get.encoding,errors='ignore');
fp = open(get.path,'w+')
else:
data = data.encode(get.encoding,errors='ignore').decode(get.encoding);
fp = open(get.path,'w+',encoding=get.encoding)
fp.write(data)
fp.close()
@@ -767,7 +770,39 @@ class files:
except Exception as ex:
return public.returnMsg(False,'FILE_SAVE_ERR' + str(ex));
#保存历史副本
def save_history(self,filename):
try:
save_path = ('/www/backup/file_history/' + filename).replace('//','/')
if not os.path.exists(save_path): os.makedirs(save_path,384)
public.writeFile(save_path + '/' + str(int(time.time())),public.readFile(filename,'rb'),'wb')
his_list = sorted(os.listdir(save_path))
num = public.readFile('data/history_num.pl')
if not num:
num = 10
else:
num = int(num)
d_num = len(his_list)
for i in range(d_num):
if d_num <= num: break;
rm_file = save_path + '/' + his_list[i]
if os.path.exists(rm_file): os.remove(rm_file)
except:pass
#取历史副本
def get_history(self,filename):
try:
save_path = ('/www/backup/file_history/' + filename).replace('//','/')
if not os.path.exists(save_path): return []
return sorted(os.listdir(save_path))
except: return []
#读取指定历史副本
def read_history(self,args):
save_path = ('/www/backup/file_history/' + args.filename).replace('//','/')
args.path = save_path + '/' + args.history
return self.GetFileBody(args)
#文件压缩
def Zip(self,get) :
if not 'z_type' in get: get.z_type = 'rar'
@@ -821,10 +856,11 @@ class files:
def SetFileAccept(self,filename):
os.system('chown -R www:www ' + filename)
os.system('chmod -R 644 ' + filename)
if os.path.isfile(filename):
os.system('chmod -R 644 ' + filename)
else:
os.system('chmod -R 755 ' + filename)
#取目录大小
def GetDirSize(self,get):
if sys.version_info[0] == 2: get.path = get.path.encode('utf-8');
+11
View File
@@ -89,6 +89,17 @@ class firewalls:
data['accept'][i]['address'],addtime))
except:
return public.get_error_info()
count = public.M('firewall').count();
data = {}
data['page'] = public.get_page(count,int(get.p),12,get.collback)
data['data'] = public.M('firewall').limit(data['page']['shift'] + ',' + data['page']['row']).order('id desc').select()
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:
data['data'][i]['status'] = -1;
else:
data['data'][i]['status'] = public.check_port_stat(int(data['data'][i]['port']));
data['page'] = data['page']['page']
return data
except Exception as ex:
return public.get_error_info()
+2 -1
View File
@@ -110,13 +110,14 @@ class firewalls:
#添加放行端口
def AddAcceptPort(self,get):
import re
src_port = get.port
get.port = get.port.replace('-',':')
rep = "^\d{1,5}(:\d{1,5})?$"
if not re.search(rep,get.port): return public.returnMsg(False,'PORT_CHECK_RANGE');
import time
port = get.port
ps = get.ps
if public.M('firewall').where("port=?",(port,)).count() > 0: return public.returnMsg(False,'FIREWALL_PORT_EXISTS')
if public.M('firewall').where("port=? or port=?",(port,src_port)).count() > 0: return public.returnMsg(False,'FIREWALL_PORT_EXISTS')
notudps = ['80','443','8888','888','39000:40000','21','22']
if self.__isUfw:
public.ExecShell('ufw allow ' + port + '/tcp');
+36 -1
View File
@@ -49,6 +49,9 @@ def control_init():
if md51 != md52:
import shutil
shutil.copyfile(src_file,init_file)
if os.path.getsize(init_file) < 10:
os.system("chattr -i " + init_file)
os.system("\cp -arf %s %s" % (src_file,init_file))
except:pass
public.writeFile('/var/bt_setupPath.conf','/www')
public.ExecShell(c)
@@ -63,7 +66,39 @@ def control_init():
public.ExecShell("chown -R root:root /www/server/panel/config")
#disable_putenv('putenv')
clean_session()
set_crond()
#set_crond()
clean_max_log('/www/server/panel/plugin/rsync/lsyncd.log')
remove_tty1()
clean_hook_log()
#清理webhook日志
def clean_hook_log():
path = '/www/server/panel/plugin/webhook/script'
if not os.path.exists(path): return False
for name in os.listdir(path):
if name[-4:] != ".log": continue;
clean_max_log(path+'/' + name,524288)
#清理大日志
def clean_max_log(log_file,max_size = 104857600,old_line = 100):
if not os.path.exists(log_file): return False
if os.path.getsize(log_file) > max_size:
try:
old_body = public.GetNumLines(log_file,old_line)
public.writeFile(log_file,old_body)
except:
print(public.get_error_info())
#删除tty1
def remove_tty1():
file_path = '/etc/systemd/system/getty@tty1.service'
if not os.path.exists(file_path): return False
if not os.path.islink(file_path): return False
if os.readlink(file_path) != '/dev/null': return False
try:
os.remove(file_path)
except:pass
#默认禁用指定PHP函数
def disable_putenv(fun_name):
+15 -13
View File
@@ -20,19 +20,21 @@ class panelAuth:
__product_id = '100000011';
def create_serverid(self,get):
userPath = 'data/userInfo.json';
if not os.path.exists(userPath): return public.returnMsg(False,'LOGIN_FIRST');
tmp = public.readFile(userPath);
if len(tmp) < 2: tmp = '{}'
data = json.loads(tmp);
if not data: return public.returnMsg(False,'LOGIN_FIRST');
if not hasattr(data,'serverid'):
s1 = self.get_mac_address() + self.get_hostname()
s2 = self.get_cpuname();
serverid = public.md5(s1) + public.md5(s2);
data['serverid'] = serverid;
public.writeFile(userPath,json.dumps(data));
return data;
try:
userPath = 'data/userInfo.json';
if not os.path.exists(userPath): return public.returnMsg(False,'LOGIN_FIRST');
tmp = public.readFile(userPath);
if len(tmp) < 2: tmp = '{}'
data = json.loads(tmp);
if not data: return public.returnMsg(False,'LOGIN_FIRST');
if not hasattr(data,'serverid'):
s1 = self.get_mac_address() + self.get_hostname()
s2 = self.get_cpuname();
serverid = public.md5(s1) + public.md5(s2);
data['serverid'] = serverid;
public.writeFile(userPath,json.dumps(data));
return data;
except: return public.returnMsg(False,'LOGIN_FIRST');
def create_plugin_other_order(self,get):
+3 -3
View File
@@ -83,15 +83,15 @@ class panelLets:
def get_error(self,error):
if error.find("Max checks allowed") >= 0 :
return "CA server verification timed out, please wait 5-10 minutes and try again."
return "CA can't verify your domain name, please check if the domain name resolution is correct, or wait 5-10 minutes and try again."
elif error.find("Max retries exceeded with") >= 0:
return "The CA server connection timed out, please make sure the server network is unobstructed."
return "The CA server connection timed out, please try again later."
elif error.find("The domain name belongs") >= 0:
return "The domain name does not belong to this DNS service provider. Please ensure that the domain name is filled in correctly."
elif error.find('login token ID is invalid') >=0:
return 'The DNS server connection failed. Please check if the key is correct.'
elif "too many certificates already issued for exact set of domains" in error or "Error creating new account :: too many registrations for this IP" in error:
return '<h2>The signing failed, and the number of attempts to apply for a certificate today has reached the limit!</h2>'
return '<h2>You have failed more than 5 verifications in 1 hour. Please wait 1 hour and try again.</h2>'
elif "DNS problem: NXDOMAIN looking up A for" in error or "No valid IP addresses found for" in error or "Invalid response from" in error:
return '<h2>The signing failed, the domain name resolution error, or the resolution is not valid, or the domain name is not filed!</h2>'
elif error.find('TLS Web Server Authentication') != -1:
+6 -2
View File
@@ -260,7 +260,7 @@ class panelPlugin:
import panelAuth
pdata = panelAuth.panelAuth().create_serverid(None)
listTmp = public.httpPost(cloudUrl,pdata,10)
if len(listTmp) < 200:
if not listTmp or len(listTmp) < 200:
listTmp = public.readFile(lcoalTmp)
try:
softList = json.loads(listTmp)
@@ -1554,7 +1554,11 @@ class panelPlugin:
try:
if not public.path_safe_check("%s/%s" % (get.name,get.s)): return public.returnMsg(False,'PLUGIN_INPUT_C');
path = self.__install_path + '/' + get.name
if not os.path.exists(path + '/'+get.name+'_main.py'): return public.returnMsg(False,'PLUGIN_INPUT_B');
if not os.path.exists(path + '/'+get.name+'_main.py'):
if os.path.exists(path+'/index.php'):
import panelPHP
return panelPHP.panelPHP(get.name).exec_php_script(get)
return public.returnMsg(False,'PLUGIN_INPUT_B');
if not self.check_accept(get):return public.returnMsg(False,public.to_string([24744, 26410, 36141, 20080, 91, 37, 115, 93, 25110, 25480, 26435, 24050, 21040, 26399, 33]) % (self.get_title_byname(get),))
sys.path.append(path);
plugin_main = __import__(get.name+'_main');
+8 -4
View File
@@ -31,10 +31,14 @@ class panelSSL:
self.__userInfo = {}
else:
self.__userInfo = {}
if self.__userInfo:
pdata['access_key'] = self.__userInfo['access_key'];
data['secret_key'] = self.__userInfo['secret_key'];
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';
+27 -11
View File
@@ -759,7 +759,7 @@ class panelSite(panelRedirect):
sql.table('domain').where("id=?",(find['id'],)).delete();
public.WriteLog('TYPE_SITE', 'DOMAIN_DEL_SUCCESS',(get.webname,get.domain));
public.serviceReload();
public.serviceReload()
return public.returnMsg(True,'DEL_SUCCESS');
#检查域名是否解析
@@ -856,7 +856,7 @@ class panelSite(panelRedirect):
for domain in domains:
if public.checkIp(domain): continue;
if domain.find('*.') >=0 and not file_auth:
if domain.find('*.') >= 0 and file_auth:
return public.returnMsg(False, 'A generic domain name cannot be used to apply for a certificate using [File Validation]!');
if file_auth:
@@ -901,7 +901,7 @@ class panelSite(panelRedirect):
return result
def get_site_info(self,siteName):
data = public.M("sites").where('name=?',siteName).field('path,name').find()
data = public.M("sites").where('name=?',siteName).field('id,path,name').find()
return data
@@ -2439,6 +2439,11 @@ server
return f.SaveFileBody(get)
# return public.returnMsg(True, '保存成功')
# 检查是否存在#Set Nginx Cache
def check_annotate(self,data):
rep = "\n\s*#Set\s*Nginx\s*Cache"
if re.search(rep,data):
return True
# 修改反向代理
def ModifyProxy(self, get):
@@ -2477,17 +2482,26 @@ server
proxy_cache cache_one;
proxy_cache_key $host$uri$is_args$args;
proxy_cache_valid 200 304 301 302 %sm;""" % (get.cachetime)
cache_rep = '#proxy_set_header\s+Connection\s+"upgrade";'
ng_conf = re.sub(cache_rep,'#proxy_set_header Connection "upgrade";\n'+ng_cache,ng_conf)
if self.check_annotate(ng_conf):
cache_rep = '\n\s*#Set\s*Nginx\s*Cache(.|\n)*no-cache;'
ng_conf = re.sub(cache_rep,'\n\t#Set Nginx Cache\n'+ng_cache,ng_conf)
else:
cache_rep = '#proxy_set_header\s+Connection\s+"upgrade";'
ng_conf = re.sub(cache_rep, '\n\t#proxy_set_header Connection "upgrade";\n\t#Set Nginx Cache' + ng_cache,
ng_conf)
else:
rep = '\s+proxy_cache\s+cache_one.*[\n\s\w\_\";\$]+m;'
ng_conf = re.sub(rep, "", ng_conf)
if self.check_annotate(ng_conf):
rep = '\n\s*#Set\s*Nginx\s*Cache(.|\n)*1m;'
ng_conf = re.sub(rep, "\n\t#Set Nginx Cache\n\tadd_header Cache-Control no-cache;", ng_conf)
else:
rep = '\s+proxy_cache\s+cache_one.*[\n\s\w\_\";\$]+m;'
ng_conf = re.sub(rep, '\n\t#Set Nginx Cache\n\tadd_header Cache-Control no-cache;', ng_conf)
sub_rep = "sub_filter"
subfilter = json.loads(get.subfilter)
if str(proxyUrl[i]["subfilter"]) != str(subfilter):
if re.search(sub_rep, ng_conf):
sub_rep = "\s+proxy_set_header\s+Accept-Encoding.*[\n\s\w\_\";]+off;"
sub_rep = "\s+proxy_set_header\s+Accept-Encoding(.|\n)+off;"
ng_conf = re.sub(sub_rep,"",ng_conf)
# 构造替换字符串
@@ -2582,8 +2596,9 @@ location %s
#proxy_http_version 1.1;
#proxy_set_header Upgrade $http_upgrade;
#proxy_set_header Connection "upgrade";
add_header X-Cache $upstream_cache_status;
#Set Nginx Cache
%s
%s
}
@@ -2617,14 +2632,14 @@ location %s
get.proxydir, get.proxydir,get.proxysite, get.todomain, public.GetMsg("NGINX_PERSISTENCE") ,ng_sub_filter, ng_cache ,get.proxydir)
if type == 1 and cache == 0:
ng_proxy_cache += ng_proxy % (
get.proxydir, get.proxydir, get.proxysite, get.todomain, public.GetMsg("NGINX_PERSISTENCE") ,ng_sub_filter,'' ,get.proxydir)
get.proxydir, get.proxydir, get.proxysite, get.todomain, public.GetMsg("NGINX_PERSISTENCE") ,ng_sub_filter,'\tadd_header Cache-Control no-cache;' ,get.proxydir)
else:
if type == 1 and cache == 1:
ng_proxy_cache += ng_proxy % (
get.proxydir, get.proxydir, get.proxysite, get.todomain, public.GetMsg("NGINX_PERSISTENCE") ,ng_sub_filter, ng_cache, get.proxydir)
if type == 1 and cache == 0:
ng_proxy_cache += ng_proxy % (
get.proxydir, get.proxydir, get.proxysite, get.todomain, public.GetMsg("NGINX_PERSISTENCE") ,ng_sub_filter, '', get.proxydir)
get.proxydir, get.proxydir, get.proxysite, get.todomain, public.GetMsg("NGINX_PERSISTENCE") ,ng_sub_filter, '\tadd_header Cache-Control no-cache;', get.proxydir)
public.writeFile(ng_proxyfile, ng_proxy_cache)
@@ -3348,6 +3363,7 @@ location %s
#设置防盗链
def SetSecurity(self,get):
if len(get.fix) < 2: return public.returnMsg(False,'URL_SUFFIX_NOT_EMPTY!');
if len(get.domains) < 3: return public.returnMsg(False,'Anti-theft chain domain name cannot be empty!');
file = '/www/server/panel/vhost/nginx/' + get.name + '.conf';
if os.path.exists(file):
conf = public.readFile(file);
+7 -1
View File
@@ -133,6 +133,7 @@ class bt_task:
down_file = downloadFile.downloadFile()
down_file.logPath = log_file
print(down_file.DownloadFile(task_shell,other))
os.system("chown www.www {}".format(other))
elif task_type == 2: #解压文件
zip_info = json.loads(other)
self._unzip(task_shell,zip_info['dfile'],zip_info['password'],log_file)
@@ -379,7 +380,12 @@ class bt_task:
#设置权限
def set_file_accept(self,filename):
os.system('chown -R www:www ' + filename)
os.system('chmod -R 755 ' + filename)
# os.system('chmod -R 755 ' + filename)
a = 'find {filename} -type d |xargs chmod 0755'.format(filename=filename)
public.writeFile("/tmp/2",str(a))
os.system(a)
os.system('find {filename} -type f |xargs chmod 0644'.format(filename=filename))
#检查敏感目录
def check_dir(self,path):
+93 -24
View File
@@ -29,6 +29,8 @@ def HttpGet(url,timeout = 6,headers = {}):
@timeout 超时时间默认60秒
return string
"""
if is_local(): return False
home = 'www.bt.cn'
host_home = 'data/home_host.pl'
old_url = url
@@ -104,6 +106,7 @@ def HttpPost(url,data,timeout = 6,headers = {}):
@timeout 超时时间默认60秒
return string
"""
if is_local(): return False
home = 'www.bt.cn'
host_home = 'data/home_host.pl'
old_url = url
@@ -1289,25 +1292,22 @@ def get_path_size(path):
size_total += os.path.getsize(filename)
return size_total
# 写关键请求日志
def write_request_log():
#写关键请求日志
def write_request_log(reques = None):
try:
log_path = '/www/server/panel/logs/request'
log_file = getDate(format='%Y-%m-%d') + '.json'
if not os.path.exists(log_path): os.makedirs(log_path)
from flask import request
log_data = {}
log_data['date'] = getDate()
log_data['ip'] = GetClientIp()
log_data['method'] = request.method
log_data['uri'] = request.full_path
log_data['user-agent'] = request.headers.get('User-Agent')
WriteFile(log_path + '/' + log_file, json.dumps(log_data) + "\n", 'a+')
except:
pass
log_data = []
log_data.append(getDate())
log_data.append(GetClientIp())
log_data.append(request.method)
log_data.append(request.full_path)
log_data.append(request.headers.get('User-Agent'))
WriteFile(log_path + '/' + log_file,json.dumps(log_data) + "\n",'a+')
except: pass
# 重载模块
def mod_reload(mode):
@@ -1337,9 +1337,11 @@ def set_own(filename, user, group=None):
from pwd import getpwnam
try:
user_info = getpwnam(user)
# user_info = getpwnam('www')
user = user_info.pw_uid
if group:
user_info = getpwnam(group)
# user_info = getpwnam('www')
group = user_info.pw_gid
except:
# 如果指定用户或组不存在,则使用www
@@ -1433,18 +1435,85 @@ def de_crypt(key,strings):
return strings
# 取通用对象
#检查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();
if not GetClientIp() 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
#检查面板域名
def check_domain_panel():
tmp = GetHost()
domain = ReadFile('data/domain.conf')
if domain:
if tmp.strip().lower() != domain.strip().lower():
errorStr = ReadFile('./BTPanel/templates/' + GetConfigValue('template') + '/error2.html')
try:
errorStr = errorStr.format(getMsg('PAGE_ERR_TITLE'),getMsg('PAGE_ERR_DOMAIN_H1'),getMsg('PAGE_ERR_DOMAIN_P1'),getMsg('PAGE_ERR_DOMAIN_P2'),getMsg('PAGE_ERR_DOMAIN_P3'),getMsg('NAME'),getMsg('PAGE_ERR_HELP'))
except IndexError:pass
return errorStr
return False
#是否离线模式
def is_local():
s_file = '/www/server/panel/data/not_network.pl'
return os.path.exists(s_file)
#自动备份面板数据
def auto_backup_panel():
b_path = '/www/backup/panel'
backup_path = b_path + '/' + format_date('%Y-%m-%d')
panel_paeh = '/www/server/panel'
if os.path.exists(backup_path): return True
os.makedirs(backup_path,384)
import shutil
shutil.copytree(panel_paeh + '/data',backup_path + '/data')
shutil.copytree(panel_paeh + '/config',backup_path + '/config')
time_now = time.time() - (86400 * 15)
for f in os.listdir(b_path):
try:
if time.mktime(time.strptime(f, "%Y-%m-%d")) < time_now:
path = b_path + '/' + f
if os.path.exists(path): shutil.rmtree(path)
except: continue
#检查端口状态
def check_port_stat(port):
import socket
localIP = '127.0.0.1';
temp = {}
temp['port'] = port;
temp['local'] = True;
try:
s = socket.socket()
s.settimeout(0.15)
s.connect((localIP,port))
s.close()
except:
temp['local'] = False;
result = 0;
if temp['local']: result +=2;
return result;
#取通用对象
class dict_obj:
def __contains__(self, key):
return getattr(self, key, None)
def __setitem__(self, key, value): setattr(self, key, value)
def __getitem__(self, key): return getattr(self, key, None)
def __delitem__(self, key): delattr(self, key)
def __delattr__(self, key): delattr(self, key)
return getattr(self,key,None)
def __setitem__(self, key, value): setattr(self,key,value)
def __getitem__(self, key): return getattr(self,key,None)
def __delitem__(self,key): delattr(self,key)
def __delattr__(self, key): delattr(self,key)
def get_items(self): return self
+4 -1
View File
@@ -273,7 +273,10 @@ class system:
#取CPU信息
cpuCount = psutil.cpu_count()
used = self.get_cpu_percent()
return used,cpuCount
used_all = psutil.cpu_percent(percpu=True)
cpu_name = public.getCpuType()
return used,cpuCount,used_all,cpu_name
def GetCpuInfo_new(self):
cpuCount = psutil.cpu_count()
+6 -5
View File
@@ -12,9 +12,9 @@ os.chdir("/www/server/panel")
sys.path.append('class/')
import public
print ('==================================================================')
print( '★['+time.strftime("%Y/%m/%d %H:%M:%S")+']切割日志')
print( '★['+time.strftime("%Y/%m/%d %H:%M:%S")+']Cutting log')
print ('==================================================================')
print ('|--当前保留最新的['+sys.argv[2]+']')
print ('|--Currently retaining the latest ['+sys.argv[2]+'] copies')
logsPath = '/www/wwwlogs/'
is_nginx = False
if os.path.exists('/www/server/nginx/logs/nginx.pid'): is_nginx = True
@@ -24,7 +24,7 @@ if not is_nginx: px = '-access_log'
def split_logs(oldFileName,num):
global logsPath
if not os.path.exists(oldFileName):
print('|---'+oldFileName+'文件不存在!')
print('|---'+oldFileName+'file does not exist!')
return
logs=sorted(glob.glob(oldFileName+"_*"))
@@ -34,11 +34,12 @@ def split_logs(oldFileName,num):
for i in range(count):
if i>num: break;
os.remove(logs[i])
print('|---多余日志['+logs[i]+']已删除!')
print('|---Extra log ['+logs[i]+'] has been deleted!')
newFileName=oldFileName+'_'+time.strftime("%Y-%m-%d_%H%M%S")+'.log'
shutil.move(oldFileName,newFileName)
print('|---已切割日志到:'+newFileName)
os.system("gzip %s" % newFileName)
print('|---The log has been cut to: '+newFileName+'.gz')
def split_all(save):
sites = public.M('sites').field('name').select()
+6 -5
View File
@@ -12,9 +12,9 @@ os.chdir("/www/server/panel")
sys.path.append('class/')
import public
print ('==================================================================')
print( '★['+time.strftime("%Y/%m/%d %H:%M:%S")+']切割日志')
print( '★['+time.strftime("%Y/%m/%d %H:%M:%S")+']Cutting log')
print ('==================================================================')
print ('|--当前保留最新的['+sys.argv[2]+']')
print ('|--Currently retaining the latest ['+sys.argv[2]+'] copies')
logsPath = '/www/wwwlogs/'
is_nginx = False
if os.path.exists('/www/server/nginx/logs/nginx.pid'): is_nginx = True
@@ -24,7 +24,7 @@ if not is_nginx: px = '-access_log'
def split_logs(oldFileName,num):
global logsPath
if not os.path.exists(oldFileName):
print('|---'+oldFileName+'文件不存在!')
print('|---'+oldFileName+'file does not exist!')
return
logs=sorted(glob.glob(oldFileName+"_*"))
@@ -34,11 +34,12 @@ def split_logs(oldFileName,num):
for i in range(count):
if i>num: break;
os.remove(logs[i])
print('|---多余日志['+logs[i]+']已删除!')
print('|---The extra log ['+logs[i]+'] has been deleted!')
newFileName=oldFileName+'_'+time.strftime("%Y-%m-%d_%H%M%S")+'.log'
shutil.move(oldFileName,newFileName)
print('|---已切割日志到:'+newFileName)
os.system("gzip %s" % newFileName)
print('|---The log has been cut to:'+newFileName+'.gz')
def split_all(save):
sites = public.M('sites').field('name').select()
+23 -1
View File
@@ -1,3 +1,4 @@
#!/bin/python
#coding: utf-8
# +-------------------------------------------------------------------
# | 宝塔Linux面板
@@ -438,6 +439,8 @@ def panel_status():
panel_url = pool + '127.0.0.1:' + port + '/service_status'
panel_pid = get_panel_pid()
n = 0
s = 0
v = 0
while True:
time.sleep(1)
if not panel_pid: panel_pid = get_panel_pid()
@@ -455,6 +458,25 @@ def panel_status():
continue
n += 1
v += 1
if v > 10:
v = 0
log_path = panel_path + '/logs/error.log'
if os.path.exists(log_path):
e_body = public.GetNumLines(log_path,10)
if e_body:
if e_body.find('PyWSGIServer.do_close') != -1 or e_body.find('Expected GET method:')!=-1 or e_body.find('Invalid HTTP method:') != -1 or e_body.find('table session') != -1:
result = public.httpGet(panel_url)
if result != 'True':
if e_body.find('table session') != -1:
sess_file = '/dev/shm/session.db'
if os.path.exists(sess_file): os.remove(sess_file)
os.system("/etc/init.d/bt reload &")
time.sleep(10)
result = public.httpGet(panel_url)
if result == 'True':
public.WriteLog('TYPE_SOFE','Checked to panel service exception, has been automatically restored!')
if n > 18000:
n = 0
@@ -465,7 +487,7 @@ def panel_status():
os.system("/etc/init.d/bt reload &")
result = public.httpGet(panel_url)
if result == 'True':
public.WriteLog('守护程序','检查到面板服务异常,已自动恢复!')
public.WriteLog('TYPE_SOFE','Checked to panel service exception, has been automatically restored!')
time.sleep(10)
continue