mirror of
https://github.com/aaPanel/aaPanel.git
synced 2026-09-06 17:47:39 +02:00
Add panel SSL own certificate to fill in the entry
Fixed known bugs Panel Feature Modification Points to note after updating the panel: 1. The default port of the panel is changed to 7800 (Port 8888 has been flooded) 2. Panel entry error will prompt 404 3. After the panel is bound to the domain name, if the domain access is not used,it will return 401 4. After the panel is set to authorize IP access, other IP access panels will return 401 5. The website welcome page is changed to the nginx welcome page 6. Change the stop page to Nginx 404 page
This commit is contained in:
+33
-33
@@ -13,7 +13,7 @@ import os
|
||||
import threading
|
||||
import time
|
||||
import re
|
||||
import uuid
|
||||
import psutil
|
||||
panel_path = '/www/server/panel'
|
||||
if not os.name in ['nt']:
|
||||
os.chdir(panel_path)
|
||||
@@ -56,7 +56,8 @@ if os.path.exists(basic_auth_conf):
|
||||
except: pass
|
||||
|
||||
#初始化SESSION服务
|
||||
app.secret_key = uuid.UUID(int=uuid.getnode()).hex[-12:]
|
||||
# app.secret_key = uuid.UUID(int=uuid.getnode()).hex[-12:]
|
||||
app.secret_key = public.md5(str(os.uname())+str(psutil.boot_time()))
|
||||
local_ip = None
|
||||
my_terms = {}
|
||||
app.config['SESSION_MEMCACHED'] = SimpleCache(1000,86400)
|
||||
@@ -145,8 +146,8 @@ if admin_path in admin_path_checks: admin_path = '/bt'
|
||||
def request_check():
|
||||
g.request_time = time.time()
|
||||
# 路由和URI长度过滤
|
||||
if len(request.path) > 256: return abort(403)
|
||||
if len(request.url) > 1024: return abort(403)
|
||||
if len(request.path) > 256: return abort(404)
|
||||
if len(request.url) > 1024: return abort(404)
|
||||
|
||||
if request.path in ['/service_status']: return
|
||||
|
||||
@@ -154,8 +155,8 @@ def request_check():
|
||||
if request.path in ['/login','/safe','/hook','/public','/down','/get_app_bind_status','/check_bind']:
|
||||
pdata = request.form.to_dict()
|
||||
for k in pdata.keys():
|
||||
if len(k) > 48: return abort(403)
|
||||
if len(pdata[k]) > 256: return abort(403)
|
||||
if len(k) > 48: return abort(404)
|
||||
if len(pdata[k]) > 256: return abort(404)
|
||||
if session.get('debug') == 1: return
|
||||
|
||||
if app.config['BASIC_AUTH_OPEN']:
|
||||
@@ -171,13 +172,13 @@ def request_check():
|
||||
|
||||
if not request.path in ['/safe', '/hook', '/public', '/mail_sys', '/down']:
|
||||
ip_check = public.check_ip_panel()
|
||||
if ip_check: return ip_check
|
||||
if ip_check: return abort(401)
|
||||
|
||||
if request.path.find('/static/') != -1 or request.path == '/code':
|
||||
if not 'login' in session and not 'admin_auth' in session and not 'down' in session:
|
||||
return abort(401)
|
||||
domain_check = public.check_domain_panel()
|
||||
if domain_check: return domain_check
|
||||
if domain_check: return abort(401)
|
||||
if public.is_local():
|
||||
not_networks = ['uninstall_plugin','install_plugin','UpdatePanel']
|
||||
if request.args.get('action') in not_networks:
|
||||
@@ -1016,7 +1017,8 @@ def login():
|
||||
if route_path != '/' + referer_path:
|
||||
data = {}
|
||||
data['lan'] = public.getLan('close')
|
||||
return render_template('autherr.html', data=data)
|
||||
return abort(404)
|
||||
# return render_template('autherr.html', data=data)
|
||||
|
||||
session['admin_auth'] = True
|
||||
comReturn = common.panelSetup().init()
|
||||
@@ -1040,9 +1042,7 @@ def login():
|
||||
else:
|
||||
data['hosts'] = json.dumps(data['hosts'])
|
||||
data['app_login'] = os.path.exists('data/app_login.pl')
|
||||
return render_template(
|
||||
'login.html',
|
||||
data=data )
|
||||
return render_template('login.html',data=data )
|
||||
|
||||
@app.route('/close',methods=method_get)
|
||||
def close():
|
||||
@@ -1052,16 +1052,16 @@ def close():
|
||||
data['lan'] = public.getLan('close')
|
||||
return render_template('close.html',data=data)
|
||||
|
||||
@app.route('/tips',methods=method_get)
|
||||
def tips():
|
||||
#提示页面
|
||||
return render_template('tips.html')
|
||||
# @app.route('/tips',methods=method_get)
|
||||
# def tips():
|
||||
# #提示页面
|
||||
# return render_template('tips.html')
|
||||
|
||||
|
||||
@app.route('/get_app_bind_status', methods=method_all)
|
||||
def get_app_bind_status(pdata=None):
|
||||
# APP绑定状态查询
|
||||
if not public.check_app('app_bind'):return public.returnMsg(False, 'API_DISABLED')
|
||||
if not public.check_app('app_bind'):return abort(404)
|
||||
import panelApi
|
||||
api_object = panelApi.panelApi()
|
||||
return json.dumps(api_object.get_app_bind_status(get_input())),json_header
|
||||
@@ -1070,12 +1070,12 @@ def get_app_bind_status(pdata=None):
|
||||
@app.route('/check_bind', methods=method_all)
|
||||
def check_bind(pdata=None):
|
||||
# APP绑定查询
|
||||
if not public.check_app('app_bind'):return public.returnMsg(False, 'API_DISABLED')
|
||||
if not public.check_app('app_bind'):return abort(404)
|
||||
import panelApi
|
||||
api_object = panelApi.panelApi()
|
||||
return json.dumps(api_object.check_bind(get_input())),json_header
|
||||
|
||||
@app.route('/code')
|
||||
@app.route('/code',methods=method_get)
|
||||
def code():
|
||||
if not 'code' in session:
|
||||
return ''
|
||||
@@ -1196,13 +1196,13 @@ def panel_public():
|
||||
if not public.get_error_num(num_key, 10):
|
||||
return public.returnMsg(False, 'AUTH_FAILED')
|
||||
if not hasattr(get, 'name'): get.name = ''
|
||||
if not hasattr(get, 'fun'): return abort(403)
|
||||
if not public.path_safe_check("%s/%s" % (get.name, get.fun)): return abort(403)
|
||||
if not hasattr(get, 'fun'): return abort(404)
|
||||
if not public.path_safe_check("%s/%s" % (get.name, get.fun)): return abort(404)
|
||||
if get.fun in ['login_qrcode', 'is_scan_ok','set_login']:
|
||||
# 检查是否验证过安全入口
|
||||
global admin_check_auth, admin_path, route_path, admin_path_file
|
||||
if admin_path != '/bt' and os.path.exists(admin_path_file) and not 'admin_auth' in session:
|
||||
return abort(403)
|
||||
return abort(404)
|
||||
#验证是否绑定了设备
|
||||
if not public.check_app('app'):return public.returnMsg(False,'UNBOUND_USER')
|
||||
import wxapp
|
||||
@@ -1361,10 +1361,10 @@ def panel_hook():
|
||||
#webhook接口
|
||||
get = get_input()
|
||||
if not os.path.exists('plugin/webhook'):
|
||||
return public.getJson(public.returnMsg(False,'INIT_WEBHOOK_ERR'))
|
||||
return abort(404)
|
||||
public.package_path_append('plugin/webhook')
|
||||
import webhook_main
|
||||
session.clear()
|
||||
#session.clear()
|
||||
return public.getJson(webhook_main.webhook_main().RunHook(get))
|
||||
|
||||
@app.route('/install',methods=method_all)
|
||||
@@ -1406,13 +1406,13 @@ def install():
|
||||
data['username'] = get.bt_username
|
||||
return render_template( 'install.html',data = data)
|
||||
|
||||
@app.route('/robots.txt',methods=method_all)
|
||||
def panel_robots():
|
||||
#爬虫规则响应接口
|
||||
robots = '''User-agent: *
|
||||
Disallow: /
|
||||
'''
|
||||
return robots,{'Content-Type':'text/plain'}
|
||||
# @app.route('/robots.txt',methods=method_all)
|
||||
# def panel_robots():
|
||||
# #爬虫规则响应接口
|
||||
# robots = '''User-agent: *
|
||||
# Disallow: /
|
||||
# '''
|
||||
# return robots,{'Content-Type':'text/plain'}
|
||||
|
||||
|
||||
@app.route('/rspamd', defaults={'path': ''},methods=method_all)
|
||||
@@ -1603,7 +1603,7 @@ def get_pd():
|
||||
tmp1 = None
|
||||
if tmp1:
|
||||
tmp = tmp1[public.to_string([112,114,111])]
|
||||
ltd = tmp1.get('ltd',-1)
|
||||
ltd = tmp1.get('ltd', -1)
|
||||
else:
|
||||
ltd = -1
|
||||
tmp4 = cache.get(public.to_string([112, 95, 116, 111, 107, 101, 110]))
|
||||
@@ -1690,7 +1690,7 @@ def send_authenticated():
|
||||
#发送http认证信息
|
||||
request_host = public.GetHost()
|
||||
result = Response('', 401,{'WWW-Authenticate': 'Basic realm="%s"' % request_host.strip()})
|
||||
if not 'login' in session and not 'admin_auth' in session: session.clear()
|
||||
# if not 'login' in session and not 'admin_auth' in session: session.clear()
|
||||
return result
|
||||
|
||||
|
||||
|
||||
+81
-25
@@ -1818,9 +1818,13 @@ html .menu .menu_exit:hover {
|
||||
}
|
||||
|
||||
.bt-w-con {
|
||||
position: relative;
|
||||
margin-left: 170px;
|
||||
position: relative;
|
||||
padding: 7px 15px;
|
||||
padding: 7px 15px;
|
||||
}
|
||||
.bt-w-con.webedit-con {
|
||||
height: 100%;
|
||||
overflow-y: auto;
|
||||
}
|
||||
.bt-w-con .bt-w-item{
|
||||
height: 100%;
|
||||
@@ -2579,7 +2583,7 @@ html .menu .menu_exit:hover {
|
||||
.changepath .path-top .place span {
|
||||
color: #444;
|
||||
font-size: 12px;
|
||||
font-weight: bold
|
||||
font-weight: bold;
|
||||
display: inline-block;
|
||||
width: 450px;
|
||||
white-space: pre;
|
||||
@@ -2589,38 +2593,56 @@ html .menu .menu_exit:hover {
|
||||
}
|
||||
|
||||
.changepath .path-con-left {
|
||||
width: 130px;
|
||||
height: 450px;
|
||||
float: left;
|
||||
width: 150px;
|
||||
height: 450px;
|
||||
border-right: #aaa 1px solid;
|
||||
padding-top: 5px
|
||||
padding: 12px 0;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.changepath .path-con-left dl {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin-bottom: 0;
|
||||
padding-left: 12px;
|
||||
}
|
||||
|
||||
.changepath .path-con-left dl dt {
|
||||
background: url("../img/ico-computer.png") no-repeat left center;
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
padding-left: 23px;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding-left: 22px;
|
||||
background: url("../img/ico-computer.png") no-repeat left top;
|
||||
font-size: 14px;
|
||||
font-weight: normal;
|
||||
margin-left: 10px
|
||||
}
|
||||
|
||||
.changepath .path-con-left dl dd {
|
||||
line-height: 30px;
|
||||
padding-left: 12px;
|
||||
cursor: pointer
|
||||
width: 100%;
|
||||
line-height: 16px;
|
||||
padding-left: 6px;
|
||||
padding-right: 6px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.changepath .path-con-left dl dd + dd {
|
||||
margin-top: 12px;
|
||||
}
|
||||
|
||||
.changepath .path-con-left dl dd span {
|
||||
color: #666
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.changepath .path-con-left dl dd span:first-child {
|
||||
display: inline-block;
|
||||
margin-right: 6px;
|
||||
}
|
||||
|
||||
.changepath .path-con-right{
|
||||
float: left;
|
||||
width: 530px;
|
||||
height: 450px;
|
||||
overflow: auto;
|
||||
width: 550px
|
||||
}
|
||||
|
||||
.changepath .path-con-right .default li {
|
||||
@@ -2817,6 +2839,7 @@ html .menu .menu_exit:hover {
|
||||
}
|
||||
|
||||
.tab-con {
|
||||
position: relative;
|
||||
overflow: auto;
|
||||
padding: 10px
|
||||
}
|
||||
@@ -5543,9 +5566,9 @@ select[disabled]{
|
||||
}
|
||||
.user_set_info .btswitch-p{
|
||||
width: 165px;
|
||||
display: inline-block;
|
||||
text-align: left;
|
||||
margin-left: 0px;
|
||||
display: inline-block;
|
||||
text-align: left;
|
||||
margin-left: 0px;
|
||||
}
|
||||
.ssl_cert_from label{
|
||||
font-weight: 400;
|
||||
@@ -5553,14 +5576,18 @@ select[disabled]{
|
||||
vertical-align: top;
|
||||
}
|
||||
.ssl_cert_from .details{
|
||||
padding-top:10px;
|
||||
padding-top:15px;
|
||||
width:80%;
|
||||
margin:0 auto;
|
||||
}
|
||||
.ssl_cert_from .details input {
|
||||
margin-top: 1px;
|
||||
}
|
||||
.ssl_cert_from .details label {
|
||||
margin-top: 0!important;
|
||||
}
|
||||
.ssl_cert_from .details a{
|
||||
float: right;
|
||||
position: relative;
|
||||
top: 3px;
|
||||
}
|
||||
|
||||
.ssl_cert_from>.line .line {
|
||||
@@ -9617,7 +9644,7 @@ select[name="network-io"]{
|
||||
}
|
||||
|
||||
.tootls_group{
|
||||
height:30px;
|
||||
min-height:30px;
|
||||
line-height: 30px;
|
||||
}
|
||||
.tootls_group::after {
|
||||
@@ -9803,7 +9830,7 @@ select[name="network-io"]{
|
||||
display: none;
|
||||
box-shadow: 0 1px 5px rgba(0, 0, 0, .5);
|
||||
border-radius: 1px;
|
||||
width: 100%;
|
||||
/* width: 100%; */
|
||||
z-index: 999;
|
||||
background-color: #fff;
|
||||
max-height: 200px;
|
||||
@@ -10946,4 +10973,33 @@ background:url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iODIiIGhlaWdodD0iODIiIHh
|
||||
.delete_site_layer .webDelete .vcode input:active{
|
||||
border-color:#20a53a !important;
|
||||
}
|
||||
/*END*/
|
||||
/*END*/
|
||||
|
||||
/*网址项目管理*/
|
||||
.mask_layer{
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: rgb(255 255 255 / 60%);
|
||||
z-index: 9998;
|
||||
}
|
||||
.mask_layer .prompt_description{
|
||||
width:450px;
|
||||
height:60px;
|
||||
line-height:60px;
|
||||
text-align: center;
|
||||
position:absolute;
|
||||
left:50%;
|
||||
top:50%;
|
||||
margin-top: -25px;
|
||||
margin-left:-225px;
|
||||
background: #fff;
|
||||
box-shadow: 1px 1px 50px rgb(0 0 0 / 30%);
|
||||
border: 1px solid #eee;
|
||||
border-radius:2px;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
/*end*/
|
||||
|
||||
+208
-91
@@ -378,7 +378,10 @@ function bindBTName(a,type){
|
||||
p1 = $("#p1").val();
|
||||
p2 = $("#p2").val();
|
||||
var loadT = layer.msg(lan.config.token_get,{icon:16,time:0,shade: [0.3, '#000']});
|
||||
$.post(" /ssl?action=GetToken", "username=" + p1 + "&password=" + p2, function(b){
|
||||
$.post(" /ssl?action=GetToken", {
|
||||
username: p1,
|
||||
password: p2
|
||||
}, function(b){
|
||||
bt.clear_cookie('bt_user_info')
|
||||
layer.close(loadT);
|
||||
layer.msg(b.msg, {icon: b.status?1:2});
|
||||
@@ -464,89 +467,172 @@ function setPanelSSL(){
|
||||
})
|
||||
}
|
||||
else {
|
||||
bt.send('get_cert_source', 'config/get_cert_source', {}, function (rdata) {
|
||||
layer.close(loadT);
|
||||
var sdata = rdata;
|
||||
var _data = {
|
||||
title: 'Panel SSL',
|
||||
area: '630px',
|
||||
class:'ssl_cert_from',
|
||||
list: [
|
||||
{
|
||||
html:'<div><i class="layui-layer-ico layui-layer-ico3"></i><h3>'+lan.config.ssl_open_ps+'</h3><ul><li style="color:red;">'+lan.config.ssl_open_ps_1+'</li><li>'+lan.config.ssl_open_ps_2+'</li><li>'+lan.config.ssl_open_ps_3+'</li></ul></div>'
|
||||
},
|
||||
{
|
||||
title: 'Cert Type',
|
||||
name: 'cert_type',
|
||||
type: 'select',
|
||||
width: '200px',
|
||||
value: sdata.cert_type,
|
||||
items: [{value: '1', title: 'Self-signed certificate'}, {value: '2', title: 'Let\'s Encrypt'}],
|
||||
callback: function (obj) {
|
||||
var subid = obj.attr('name') + '_subid';
|
||||
$('#' + subid).remove();
|
||||
if (obj.val() == '2') {
|
||||
var _tr = bt.render_form_line({
|
||||
title: 'Admin E-Mail',
|
||||
name: 'email',
|
||||
width: '320px',
|
||||
placeholder: 'Admin E-Mail',
|
||||
value: sdata.email
|
||||
});
|
||||
obj.parents('div.line').append('<div class="line" id=' + subid + '>' + _tr.html + '</div>');
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
html:'<div class="details"><input type="checkbox" id="checkSSL" /><label style="font-weight: 400;margin: 3px 5px 0px;" for="checkSSL">'+lan.config.ssl_open_ps_4+'</label><a target="_blank" class="btlink" href="https://forum.aapanel.com/d/167-common-problems-after-opening-the-panel-certificate">'+lan.config.ssl_open_ps_5+'</a></p></div>'
|
||||
}
|
||||
bt.send('get_cert_source', 'config/get_cert_source', {}, function (rdata) {
|
||||
layer.close(loadT);
|
||||
var sdata = rdata;
|
||||
var _data = {
|
||||
title: 'Panel SSL',
|
||||
area: '630px',
|
||||
class: 'ssl_cert_from ssl_cert_panel_from',
|
||||
list: [
|
||||
{
|
||||
html: '\
|
||||
<div style="position: relative; width: 90%; margin: 0 auto;">\
|
||||
<i class="layui-layer-ico layui-layer-ico3" style="left: 0;"></i>\
|
||||
<h3 style="margin-left: 45px;">' + lan.config.ssl_open_ps + '</h3>\
|
||||
<ul style="width: 100%;">\
|
||||
<li style="color:red;">' + lan.config.ssl_open_ps_1 + '</li>\
|
||||
<li>' + lan.config.ssl_open_ps_2 + '</li>\
|
||||
<li>If panel is not accessible, you can click the <a class="btlink" href="https://forum.aapanel.com/d/167-common-problems-after-opening-the-panel-certificate" target="_blank">link</a> below to find solutions</li>\
|
||||
</ul>\
|
||||
</div>\
|
||||
'
|
||||
},
|
||||
{
|
||||
title: 'Cert Type',
|
||||
name: 'cert_type',
|
||||
type: 'select',
|
||||
width: '260px',
|
||||
// value: sdata.cert_type,
|
||||
value: '3',
|
||||
items: [
|
||||
{value: '1', title: 'Self-signed certificate'},
|
||||
{value: '2', title: 'Let\'s Encrypt'},
|
||||
{value: '3', title: 'I have certficate'}
|
||||
],
|
||||
callback: function (obj) {
|
||||
var set_height = function () {
|
||||
var layer_box = $('.ssl_cert_from').parents('.layui-layer');
|
||||
var window_height = $(window).height();
|
||||
var height = layer_box.height();
|
||||
var top = (window_height - height) / 2;
|
||||
layer_box.css({
|
||||
'top': top + 'px'
|
||||
});
|
||||
}
|
||||
var subid = obj.attr('name') + '_subid';
|
||||
var keyid = obj.attr('name') + '_keyid';
|
||||
$('#' + subid).remove();
|
||||
$('#' + keyid).remove();
|
||||
if (obj.val() == '1') {
|
||||
set_height();
|
||||
}
|
||||
if (obj.val() == '2') {
|
||||
var _tr = bt.render_form_line({
|
||||
title: 'E-Mail',
|
||||
name: 'email',
|
||||
width: '260px',
|
||||
placeholder: 'Admin E-Mail',
|
||||
value: sdata.email
|
||||
});
|
||||
obj.parents('div.line').append('<div class="line" id=' + subid + '>' + _tr.html + '</div>');
|
||||
set_height();
|
||||
}
|
||||
if (obj.val() == '3') {
|
||||
var loadT = layer.msg(lan.config.get_cert, {icon: 16, time: 0, shade: [0.3, '#000']});
|
||||
$.post('/config?action=GetPanelSSL', {}, function (cert) {
|
||||
layer.close(loadT);
|
||||
if (cert.privateKey === 'false') {
|
||||
cert.privateKey = 'paste your Private key (KEY) here';
|
||||
}
|
||||
if (cert.certPem === 'false') {
|
||||
cert.certPem = 'paste your Certificate (CRT/PEM) here';
|
||||
}
|
||||
obj.parents('div.line').append('\
|
||||
<div class="myKeyCon" id="' + keyid + '" style="margin: 0 auto; padding: 16px 0 0;">\
|
||||
<div class="ssl-con-key pull-left">Key<br>\
|
||||
<textarea id="key" class="bt-input-text">' + cert.privateKey + '</textarea>\
|
||||
</div>\
|
||||
<div class="ssl-con-key pull-right">Certificate (in pem format)<br>\
|
||||
<textarea id="csr" class="bt-input-text">' + cert.certPem + '</textarea>\
|
||||
</div>\
|
||||
<div style="clear: both;"></div>\
|
||||
</div>\
|
||||
');
|
||||
set_height();
|
||||
});
|
||||
}
|
||||
$('.ssl_cert_from .line .tname').css('width', '75px');
|
||||
}
|
||||
},
|
||||
{
|
||||
html: '\
|
||||
<div class="details" style="width: 80%;">\
|
||||
<input type="checkbox" id="checkSSL" />\
|
||||
<label style="font-weight: 400;" for="checkSSL">' + lan.config.ssl_open_ps_4 + '</label>\
|
||||
<a class="btlink" style="top: 0;" href="https://forum.aapanel.com/d/167-common-problems-after-opening-the-panel-certificate" target="_blank">' + lan.config.ssl_open_ps_5 + '</a>\
|
||||
</div>\
|
||||
'
|
||||
}
|
||||
|
||||
],
|
||||
btns: [
|
||||
{
|
||||
title: 'Close', name: 'close', callback: function (rdata, load, callback) {
|
||||
load.close();
|
||||
$("#panelSSL").prop("checked", false);
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Submit', name: 'submit', css: 'btn-success', callback: function (rdata, load, callback) {
|
||||
if(!$('#checkSSL').is(':checked')){
|
||||
bt.msg({status:false,msg:'Please confirm the risk first!'})
|
||||
return;
|
||||
}
|
||||
var confirm = layer.confirm('Whether to open the panel SSL certificate', {title:'Tips',btn: ['Confirm','Cancel'],icon:0,closeBtn:2}, function() {
|
||||
var loading = bt.load();
|
||||
bt.send('SetPanelSSL', 'config/SetPanelSSL', rdata, function (rdata) {
|
||||
loading.close()
|
||||
if (rdata.status) {
|
||||
layer.msg(rdata.msg,{icon:1});
|
||||
$.get('/system?action=ReWeb', function () {
|
||||
});
|
||||
setTimeout(function () {
|
||||
window.location.href = ((window.location.protocol.indexOf('https') != -1) ? 'http://' : 'https://') + window.location.host + window.location.pathname;
|
||||
}, 1500);
|
||||
}
|
||||
else {
|
||||
layer.msg(rdata.msg,{icon:2});
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
],
|
||||
btns: [
|
||||
{
|
||||
title: 'Close', name: 'close', callback: function (rdata, load, callback) {
|
||||
load.close();
|
||||
$("#panelSSL").prop("checked", false);
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Submit',
|
||||
name: 'submit',
|
||||
css: 'btn-success',
|
||||
callback: function (rdata, load, callback) {
|
||||
if (!$('#checkSSL').is(':checked')) return bt.msg({
|
||||
status: false,
|
||||
msg: 'Please confirm the risk first!'
|
||||
});
|
||||
layer.confirm('Whether to open the panel SSL certificate', {
|
||||
title: 'Tips',
|
||||
btn: ['Confirm', 'Cancel'],
|
||||
icon: 0,
|
||||
closeBtn: 2
|
||||
}, function () {
|
||||
var loading = bt.load();
|
||||
var type = $('select[name="cert_type"]').val();
|
||||
if (type == '3') {
|
||||
SavePanelSSL({
|
||||
loading: false,
|
||||
callback: function (res) {
|
||||
SetPanelSSL(rdata, function (res) {
|
||||
loading.close();
|
||||
});
|
||||
}
|
||||
});
|
||||
} else {
|
||||
SetPanelSSL(rdata, function (rdata) {
|
||||
loading.close();
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
],
|
||||
end: function () {
|
||||
$("#panelSSL").prop("checked", false);
|
||||
}
|
||||
};
|
||||
}
|
||||
],
|
||||
end: function () {
|
||||
$("#panelSSL").prop("checked", false);
|
||||
}
|
||||
};
|
||||
var _bs = bt.render_form(_data);
|
||||
setTimeout(function () {
|
||||
$('.cert_type' + _bs).trigger('change')
|
||||
}, 200);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
var _bs = bt.render_form(_data);
|
||||
setTimeout(function () {
|
||||
$('.cert_type' + _bs).trigger('change')
|
||||
}, 200);
|
||||
});
|
||||
}
|
||||
function SetPanelSSL(rdata, callback) {
|
||||
bt.send('SetPanelSSL', 'config/SetPanelSSL', rdata, function (rdata) {
|
||||
if (callback) callback(rdata);
|
||||
if (rdata.status) {
|
||||
$.get('/system?action=ReWeb');
|
||||
layer.msg(rdata.msg, {icon: 1, time: 1500}, function () {
|
||||
window.location.href = ((window.location.protocol.indexOf('https') != -1) ? 'http://' : 'https://') + window.location.host + window.location.pathname;
|
||||
});
|
||||
} else {
|
||||
layer.msg(rdata.msg, {icon: 2});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function GetPanelSSL(){
|
||||
@@ -582,18 +668,49 @@ function GetPanelSSL(){
|
||||
});
|
||||
}
|
||||
|
||||
function SavePanelSSL(){
|
||||
// function SavePanelSSL(){
|
||||
// var data = {
|
||||
// privateKey:$("#key").val(),
|
||||
// certPem:$("#csr").val()
|
||||
// }
|
||||
// var loadT = layer.msg(lan.config.ssl_msg,{icon:16,time:0,shade: [0.3, '#000']});
|
||||
// $.post('/config?action=SavePanelSSL',data,function(rdata){
|
||||
// layer.close(loadT);
|
||||
// if(rdata.status){
|
||||
// layer.closeAll();
|
||||
// }
|
||||
// layer.msg(rdata.msg,{icon:rdata.status?1:2});
|
||||
// });
|
||||
// }
|
||||
|
||||
function SavePanelSSL(option) {
|
||||
option = option || {
|
||||
loading: true
|
||||
};
|
||||
var privateKey = $("#key").val().trim();
|
||||
var certPem = $("#csr").val().trim();
|
||||
if (privateKey === 'false') return layer.msg('Please paste your Private key (KEY) here', {icon: 2});
|
||||
if (certPem === 'false') return layer.msg('Please paste your Certificate (CRT/PEM) here', {icon: 2});
|
||||
var data = {
|
||||
privateKey:$("#key").val(),
|
||||
certPem:$("#csr").val()
|
||||
privateKey: privateKey,
|
||||
certPem: certPem
|
||||
}
|
||||
var loadT = layer.msg(lan.config.ssl_msg,{icon:16,time:0,shade: [0.3, '#000']});
|
||||
$.post('/config?action=SavePanelSSL',data,function(rdata){
|
||||
layer.close(loadT);
|
||||
if(rdata.status){
|
||||
layer.closeAll();
|
||||
}
|
||||
layer.msg(rdata.msg,{icon:rdata.status?1:2});
|
||||
var loadT;
|
||||
if (option.loading) {
|
||||
loadT = layer.msg(lan.config.ssl_msg, {icon: 16, time: 0, shade: [0.3, '#000']});
|
||||
}
|
||||
$.post('/config?action=SavePanelSSL', data, function (rdata) {
|
||||
if (option.loading) layer.close(loadT);
|
||||
if (rdata.status) {
|
||||
if (option.callback) {
|
||||
option.callback(rdata);
|
||||
} else {
|
||||
layer.closeAll();
|
||||
layer.msg(rdata.msg, {icon: 1});
|
||||
}
|
||||
} else {
|
||||
layer.msg(rdata.msg, {icon: 2});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -15,19 +15,28 @@ function GetLogs(id){
|
||||
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: \"'+lan.crontab.microsoft_yahei+'\"">'+ (rdata.msg == '' ? lan.crontab.log_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="CloseLogs('+id+')">'+lan.public.empty+'</button>'
|
||||
+'<button type="button" class="btn btn-success btn-sm btn-title" onclick="layer.closeAll()">'+lan.public.close+'</button>'
|
||||
+'</div>'
|
||||
+'</div>'
|
||||
content:'<div class="setchmod bt-form pb70" style="padding-top: 0;">\
|
||||
<pre class="crontab-log" style="overflow: auto; border: 0 none; line-height:23px;padding: 15px; margin: 0;white-space: pre-wrap; height: 405px; background-color: rgb(51,51,51);color:#f1f1f1;border-radius:0;"></pre>\
|
||||
<div class="bt-form-submit-btn" style="margin-top: 0">\
|
||||
<button type="button" class="btn btn-danger btn-sm btn-title" id="clearLogs" style="margin-right:15px;">'+ lan.public.empty +'</button>\
|
||||
<button type="button" class="btn btn-success btn-sm btn-title" onclick="layer.closeAll()">'+ lan.public.close +'</button>\
|
||||
</div>\
|
||||
</div>',
|
||||
success: function () {
|
||||
var log_body = rdata.msg === '' ? 'The current log is empty':rdata.msg,setchmod = $(".setchmod pre"),crontab_log = $('.crontab-log')[0]
|
||||
setchmod.text(log_body);
|
||||
crontab_log.scrollTop = crontab_log.scrollHeight;
|
||||
$('#clearLogs').on('click',function (){
|
||||
CloseLogs(id);
|
||||
});
|
||||
}
|
||||
});
|
||||
setTimeout(function(){
|
||||
$("#crontab-log").text(rdata.msg);
|
||||
var div = document.getElementsByClassName('crontab-log')[0]
|
||||
div.scrollTop = div.scrollHeight;
|
||||
},200)
|
||||
// setTimeout(function(){
|
||||
// $("#crontab-log").text(rdata.msg);
|
||||
// var div = document.getElementsByClassName('crontab-log')[0]
|
||||
// div.scrollTop = div.scrollHeight;
|
||||
// },200)
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -24,15 +24,27 @@ var database = {
|
||||
column:[
|
||||
{ fid: 'id', type: 'checkbox', width: 30 },
|
||||
{
|
||||
fid: 'name', title: lan.database.add_name, width: '20%'
|
||||
fid: 'name',
|
||||
width: 120,
|
||||
title: lan.database.add_name,
|
||||
template: function (item) {
|
||||
return '<span class="limit-text-length" style="width: 120px;" title="' + item.name + '">' + item.name + '</span>';
|
||||
}
|
||||
},
|
||||
{
|
||||
fid: 'username', title: lan.database.user, sort: function () {
|
||||
fid: 'username',
|
||||
width: 120,
|
||||
title: lan.database.user,
|
||||
sort: function () {
|
||||
database_table.$refresh_table_list(true);
|
||||
},
|
||||
template: function (item) {
|
||||
return '<span class="limit-text-length" style="width: 120px;" title="' + item.username + '">' + item.username + '</span>';
|
||||
}
|
||||
},
|
||||
{
|
||||
fid:'password',
|
||||
width: 200,
|
||||
title:lan.database.add_pass,
|
||||
type:'password',
|
||||
copy:true,
|
||||
@@ -151,12 +163,15 @@ var database = {
|
||||
title: 'Sync all',
|
||||
style: {'margin-left':'30px'},
|
||||
event: function () {
|
||||
database.sync_to_database(1)
|
||||
database.sync_to_database(0)
|
||||
}
|
||||
},{
|
||||
title: 'Get DB from server',
|
||||
event: function () {
|
||||
database.sync_to_database(1)
|
||||
// database.sync_to_database(1)
|
||||
bt.database.sync_database(function (rdata) {
|
||||
if (rdata.status) that.database_table.$refresh_table_list(true);
|
||||
});
|
||||
}
|
||||
}]
|
||||
},{
|
||||
@@ -164,7 +179,7 @@ var database = {
|
||||
positon: ['left', 'bottom'],
|
||||
placeholder: 'Select batch operation',
|
||||
buttonValue: 'Execute',
|
||||
disabledSelectValue: 'Select the website to execute!!',
|
||||
disabledSelectValue: 'Select the DB to execute!!',
|
||||
selectList: [{
|
||||
title:'Sync to Server',
|
||||
url:'/database?action=SyncToDatabases&type=1',
|
||||
|
||||
+108
-67
@@ -217,7 +217,33 @@ var bt_file = {
|
||||
btn:['Upload','Cancel','Clear'],
|
||||
title: 'Upload files to【'+ bt.get_cookie('Path') +'】--- Support breakpoint renewal',
|
||||
skin:'file_dir_uploads',
|
||||
content:'<div style="padding:15px 15px 10px 15px;"><div class="upload_btn_groud"><div class="btn-group"><button type="button" class="btn btn-primary btn-sm upload_file_btn">Upload file</button><button type="button" class="btn btn-primary btn-sm dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"><span class="caret"></span><span class="sr-only">Toggle Dropdown</span></button><ul class="dropdown-menu"><li><a href="#" data-type="file">Upload file</a></li><li><a href="#" data-type="dir">Upload path</a></li></ul></div><div class="file_upload_info" style="display:none;"><span>Total process <i class="uploadProgress"></i>, uploading <i class="uploadNumber"></i>,</span><span style="display:none">Upload fail <i class="uploadError"></i></span><span>Speed <i class="uploadSpeed">Getting</i>,</span><span>Expect time <i class="uploadEstimate">Getting</i></span><i></i></div></div><div class="upload_file_body '+ (html==''?'active':'') +'">'+ (html!=''?('<ul class="dropUpLoadFileHead" style="padding-right:'+ (is_show?'15':'0') +'px"><li class="fileTitle"><span class="filename">File name</span><span class="filesize">File size</span><span class="fileStatus">File status</span></li></ul><ul class="dropUpLoadFile list-list">'+ html +'</ul>'):'<span>Please drag the file here'+ (!that.is_webkit?'<i style="display: block;font-style: normal;margin-top: 10px;color: red;font-size: 17px;">The current browser does not support drag upload. Commend to use Chrome browser or WebKit kernel for browsing</i>':'') +'</span>') +'</div></div>',
|
||||
content:'\
|
||||
<div style="padding:15px 15px 10px 15px;">\
|
||||
<div class="upload_btn_groud">\
|
||||
<div class="btn-group">\
|
||||
<button type="button" class="btn btn-primary btn-sm upload_file_btn">Upload file</button>\
|
||||
<button type="button" class="btn btn-primary btn-sm dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"><span class="caret"></span><span class="sr-only">Toggle Dropdown</span></button>\
|
||||
<ul class="dropdown-menu">\
|
||||
<li>\
|
||||
<a href="#" data-type="file">Upload file</a>\
|
||||
</li>\
|
||||
<li>\
|
||||
<a href="#" data-type="dir">Upload path</a>\
|
||||
</li>\
|
||||
</ul>\
|
||||
</div>\
|
||||
<div class="file_upload_info" style="display:none;">\
|
||||
<span>Total process <i class="uploadProgress"></i>, uploading <i class="uploadNumber"></i>,</span>\
|
||||
<span style="display:none">Upload fail <i class="uploadError"></i></span>\
|
||||
<span>Speed <i class="uploadSpeed">Getting</i>,</span>\
|
||||
<span>Expect time <i class="uploadEstimate">Getting</i></span>\
|
||||
<i></i>\
|
||||
</div>\
|
||||
</div>\
|
||||
<div class="upload_file_body '+ (html==''?'active':'') +'">'+ (html!=''?('<ul class="dropUpLoadFileHead" style="padding-right:'+ (is_show?'15':'0') +'px"><li class="fileTitle"><span class="filename">File name</span><span class="filesize">File size</span><span class="fileStatus">File status</span></li></ul><ul class="dropUpLoadFile list-list">'+ html +'</ul>') :'<span>Please drag the file here'+ (!that.is_webkit?'<i style="display: block;font-style: normal;margin-top: 10px;color: red;font-size: 17px;">The current browser does not support drag upload. Commend to use Chrome browser or WebKit kernel for browsing</i>':'') +'</span>') +'\
|
||||
</div>\
|
||||
</div>\
|
||||
',
|
||||
success:function(layers){
|
||||
$('#mask_layer').hide();
|
||||
layers.find('.layui-layer-btn2').css('float', 'left');
|
||||
@@ -294,18 +320,18 @@ var bt_file = {
|
||||
layer.close(index);
|
||||
}
|
||||
},
|
||||
btn3:function(index, layero){
|
||||
if(that.uploading){
|
||||
btn3: function (index, layero) {
|
||||
if (that.uploading) {
|
||||
layer.confirm('Do you want to cancel the upload of files? It need to delete the uploaded files manually. Continue?',{title:'Cancel file upload',icon:0},function(indexs){
|
||||
$('.upload_file_body').addClass('active').html('<span>Please drag the file here</span>')
|
||||
$('.file_upload_info').css('display','none').siblings().css('display','block')
|
||||
$('.file_upload_info').css('display','none').siblings().css('display','inline-block');
|
||||
that.filesList.length = 0
|
||||
});
|
||||
return false;
|
||||
}else{
|
||||
$('.upload_file_body').addClass('active').html('<span>Please drag the file here</span>')
|
||||
that.filesList.length = 0
|
||||
$('.file_upload_info').css('display','none').siblings().css('display','block')
|
||||
} else {
|
||||
$('.upload_file_body').addClass('active').html('<span>Please drag the file here</span>');
|
||||
that.filesList.length = 0;
|
||||
$('.file_upload_info').css('display','none').siblings().css('display','inline-block')
|
||||
return false;
|
||||
}
|
||||
},
|
||||
@@ -1742,7 +1768,7 @@ var bt_file = {
|
||||
var page = $(res.PAGE);
|
||||
page.append('<span class="Pcount-item">per page<select class="showRow">'+ select_page_num +'</select>item(s)</span>');
|
||||
$('.filePage').html('<div class="page_num">Total '+ rdata.is_dir_num +' directory, '+ (that.file_list.length - rdata.is_dir_num) +'file(s), size:<a href="javascript:;" class="btlink" id="file_all_size">Click to calculate</a></div>' + page[0].outerHTML);
|
||||
if(data.is_operating && that.file_operating[that.file_pointer] != res.PATH){
|
||||
if(data && data.is_operating && that.file_operating[that.file_pointer] != res.PATH){
|
||||
next_path = that.file_operating[that.file_pointer + 1];
|
||||
if(typeof next_path != "undefined" && next_path != res.PATH) that.file_operating.splice(that.file_pointer+1);
|
||||
that.file_operating.push(res.PATH);
|
||||
@@ -3062,71 +3088,72 @@ var bt_file = {
|
||||
/**
|
||||
* @description 回收站渲染列表
|
||||
* @return void
|
||||
*/
|
||||
*/
|
||||
render_recycle_list: function() {
|
||||
var that = this;
|
||||
$('#recycle_table').empty()
|
||||
var recycle_list = bt_tools.table({
|
||||
el:'#recycle_table',
|
||||
url:'/files?action=Get_Recycle_bin',
|
||||
height:480,
|
||||
dataFilter:function(res){
|
||||
el: '#recycle_table',
|
||||
url: '/files?action=Get_Recycle_bin',
|
||||
height: 488,
|
||||
dataFilter: function (res) {
|
||||
var files = [];
|
||||
switch($('.re-con-menu p.on').index()){
|
||||
case 0:
|
||||
for (let i = 0; i < res.dirs.length; i++){
|
||||
const item = res.dirs[i];
|
||||
files.push($.extend(item,{type:'folder'}));
|
||||
}
|
||||
for (let j = 0; j < res.files.length; j++){
|
||||
const item = res.files[j],ext_list = item.dname.split('.') ,ext = that.determine_file_type(ext_list[ext_list.length - 1]);
|
||||
if(item.name.indexOf('BTDB_') > -1) {
|
||||
for (var i = 0; i < res.dirs.length; i++){
|
||||
var item = res.dirs[i];
|
||||
if (item.name.indexOf('BTDB_') > -1) {
|
||||
item.dname = item.dname.replace('BTDB_', '');
|
||||
item.name = item.name.replace('BTDB_', '');
|
||||
files.push($.extend(item,{type:'files'}));
|
||||
}else if(ext == 'images'){
|
||||
} else {
|
||||
var item = res.dirs[i];
|
||||
files.push($.extend(item,{type:'folder'}));
|
||||
}
|
||||
}
|
||||
for (var j = 0; j < res.files.length; j++){
|
||||
var item = res.files[j],ext_list = item.dname.split('.') ,ext = that.determine_file_type(ext_list[ext_list.length - 1]);
|
||||
if(ext == 'images'){
|
||||
files.push($.extend(item,{type:ext}));
|
||||
}else{
|
||||
files.push($.extend(item,{type:'files'}));
|
||||
}
|
||||
}
|
||||
break;
|
||||
break;
|
||||
case 1:
|
||||
for (let i = 0; i < res.dirs.length; i++){
|
||||
const item = res.dirs[i];
|
||||
files.push($.extend(item,{type:'files'}));
|
||||
for (var i = 0; i < res.dirs.length; i++){
|
||||
var item = res.dirs[i];
|
||||
files.push($.extend(item,{type:'folder'}));
|
||||
}
|
||||
break;
|
||||
break;
|
||||
case 2:
|
||||
for (let j = 0; j < res.files.length; j++){
|
||||
const item = res.files[j],ext_list = item.dname.split('.') ,ext = that.determine_file_type(ext_list[ext_list.length - 1]);
|
||||
for (var j = 0; j < res.files.length; j++){
|
||||
var item = res.files[j],ext_list = item.dname.split('.') ,ext = that.determine_file_type(ext_list[ext_list.length - 1]);
|
||||
if(item.name.indexOf('BTDB') == -1) files.push($.extend(item,{type:ext}));
|
||||
}
|
||||
break;
|
||||
break;
|
||||
case 3:
|
||||
for (let j = 0; j < res.files.length; j++){
|
||||
const item = res.files[j],ext_list = item.dname.split('.') ,ext = that.determine_file_type(ext_list[ext_list.length - 1]);
|
||||
for (var j = 0; j < res.files.length; j++){
|
||||
var item = res.files[j],ext_list = item.dname.split('.') ,ext = that.determine_file_type(ext_list[ext_list.length - 1]);
|
||||
if(ext == 'images') files.push($.extend(item,{type:ext}));
|
||||
}
|
||||
|
||||
break;
|
||||
break;
|
||||
case 4:
|
||||
for (let j = 0; j < res.files.length; j++){
|
||||
const item = res.files[j],ext_list = item.dname.split('.') ,ext = that.determine_file_type(ext_list[ext_list.length - 1]);
|
||||
for (var j = 0; j < res.files.length; j++){
|
||||
var item = res.files[j],ext_list = item.dname.split('.') ,ext = that.determine_file_type(ext_list[ext_list.length - 1]);
|
||||
if(ext != 'images' && ext != 'compress' && ext != 'video' && item.name.indexOf('BTDB') == -1) files.push($.extend(item,{type:ext}));
|
||||
}
|
||||
break;
|
||||
break;
|
||||
case 5:
|
||||
for (let j = 0; j < res.files.length; j++){
|
||||
const item = res.files[j];
|
||||
if(item.name.indexOf('BTDB_') > -1){
|
||||
for (var j = 0; j < res.dirs.length; j++){
|
||||
var item = res.dirs[j];
|
||||
if (item.name.indexOf('BTDB_') > -1) {
|
||||
item.dname = item.dname.replace('BTDB_','');
|
||||
item.name = item.name.replace('BTDB_','');
|
||||
console.log()
|
||||
files.push($.extend(item,{type:'files'}));
|
||||
}
|
||||
}
|
||||
break;
|
||||
break;
|
||||
}
|
||||
$('#Set_Recycle_bin').attr('checked', res.status);
|
||||
$('#Set_Recycle_bin_db').attr('checked', res.status_db);
|
||||
@@ -3134,33 +3161,47 @@ var bt_file = {
|
||||
},
|
||||
column:[
|
||||
{type:'checkbox',class:'',width:18},
|
||||
{fid:'name',title:lan.files.recycle_bin_th1,width:155,template:function(row){
|
||||
return '<div class="text-overflow" style="width:150px" title="'+ row.name +'"><i class="file_icon file_'+ row.type +'"></i><span style="width:100px">'+ row.name +'</span></div>';
|
||||
{fid:'name',title:lan.files.recycle_bin_th1, width: 150, template:function(row){
|
||||
return '<div style="display: flex; align-items: center;" title="'+ row.name +'"><i class="file_icon file_'+ row.type +'"></i><span style="flex: 1; width: 0;" class="text-overflow">'+ row.name +'</span></div>';
|
||||
}},
|
||||
{fid:'dname',title:lan.files.recycle_bin_th2,template:function(row){
|
||||
return '<span class="text-overflow" style="min-width:150px" title="'+ row.dname +'">'+ row.dname +'</span>';
|
||||
{fid:'dname',title:lan.files.recycle_bin_th2, width: 150, template:function(row){
|
||||
return '<div style="display: flex;" title="'+ row.dname +'"><span style="flex: 1; width: 0;" class="text-overflow">'+ row.dname +'</span></div>';
|
||||
}},
|
||||
{fid:'size',title:lan.files.recycle_bin_th3,width:85,template:function(row){
|
||||
return '<span class="text-overflow" title="'+ row.size +'">'+ bt.format_size(row.size) +'</span>';
|
||||
return '<span class="limit-text-length" title="'+ row.size +'">'+ bt.format_size(row.size) +'</span>';
|
||||
}},
|
||||
{fid:'time',title:lan.files.recycle_bin_th4,width:180,template:function(row, index){
|
||||
return '<span title="'+ row.time +'">'+ bt.format_data(row.time) + '</span>'
|
||||
}},
|
||||
{type:'group',align:'right',width:250,title:lan.files.recycle_bin_th5,group:[{
|
||||
title:lan.files.recycle_bin_re,
|
||||
event:function(row, index, ev, key, that){
|
||||
bt_file.ReRecycleBin(row.rname,function(){
|
||||
that.$delete_table_row(index);
|
||||
});
|
||||
{
|
||||
fid: 'time',
|
||||
title: lan.files.recycle_bin_th4,
|
||||
width: 130,
|
||||
template:function(row, index){
|
||||
return '<span title="'+ row.time +'">'+ bt.format_data(row.time) + '</span>'
|
||||
}
|
||||
},{
|
||||
title:lan.files.recycle_bin_del,
|
||||
event:function(row, index, ev, key, that){
|
||||
bt_file.DelRecycleBin(row.rname,function(){
|
||||
that.$delete_table_row(index);
|
||||
});
|
||||
}
|
||||
}]}
|
||||
},
|
||||
{
|
||||
type: 'group',
|
||||
align: 'right',
|
||||
width: 170,
|
||||
title: lan.files.recycle_bin_th5,
|
||||
group: [
|
||||
{
|
||||
title: lan.files.recycle_bin_re,
|
||||
event: function (row, index, ev, key, that) {
|
||||
bt_file.ReRecycleBin(row.rname, function () {
|
||||
that.$delete_table_row(index);
|
||||
});
|
||||
}
|
||||
},
|
||||
{
|
||||
title:lan.files.recycle_bin_del,
|
||||
event: function (row, index, ev, key, that) {
|
||||
bt_file.DelRecycleBin(row.rname, function () {
|
||||
that.$delete_table_row(index);
|
||||
});
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
tootls: [{ // 批量操作
|
||||
type: 'batch',//batch_btn
|
||||
@@ -3203,7 +3244,7 @@ var bt_file = {
|
||||
var html = '';
|
||||
for(var i=0;i<list.length;i++){
|
||||
var item = list[i];
|
||||
html += '<tr><td>'+ item.name +'</td><td><div style="float:right;"><span style="color:'+ (item.request.status?'#20a53a':'red') +'">'+ (item.request.status?'Successfully deleted':'Failed to delete') +'</span></div></td></tr>';
|
||||
html += '<tr><td><span class="limit-text-length" style="width: 170px;" title="'+ item.name +'">'+ item.name +'</span></td><td class="text-right"><span style="color:'+ (item.request.status?'#20a53a':'red') +'">'+ (item.request.status?'Successfully deleted':'Failed to delete') +'</span></td></tr>';
|
||||
}
|
||||
recycle_list.$batch_success_table({title:'Delete multiple files',th:'File name',html:html});
|
||||
recycle_list.$refresh_table_list(true);
|
||||
@@ -3831,7 +3872,7 @@ var bt_file = {
|
||||
+ '<div class="line"><span class="tname">Share name</span><div class="info-r"><input name="ps" class="bt-input-text mr5" type="text" placeholder="No sharing name" style="width:270px" value="'+ data.filename +'"></div></div>'
|
||||
+ '<div class="line"><span class="tname">Expiration date</span><div class="info-r">'
|
||||
+'<label class="checkbox_grourd"><input type="radio" name="expire" value="24" checked><span> A Day</span></label>'
|
||||
+'<label class="checkbox_grourd"><input type="radio" name="expire" value="168"><span> A Deek</span></label>'
|
||||
+'<label class="checkbox_grourd"><input type="radio" name="expire" value="168"><span> A Week</span></label>'
|
||||
+'<label class="checkbox_grourd"><input type="radio" name="expire" value="1130800"><span> Permanent</span></label>'
|
||||
+'</div></div>'
|
||||
+ '<div class="line"><span class="tname">Extraction code</span><div class="info-r"><input name="password" class="bt-input-text mr5" placeholder="No code if it is empty" type="text" style="width:195px" value=""><button type="button" id="random_paw" class="btn btn-success btn-sm btn-title">Random</button></div></div>'
|
||||
@@ -5042,7 +5083,7 @@ var bt_file = {
|
||||
* @return 返回匹配结果
|
||||
*/
|
||||
match_unqualified_string:function(item){
|
||||
var containSpecial = RegExp(/[(\ )(\*)(\|)(\\)(\:)(\")(\/)(\<)(\>)(\?)(\)]+/);
|
||||
var containSpecial = RegExp(/[(\*)(\|)(\\)(\:)(\")(\/)(\<)(\>)(\?)(\)]+/);
|
||||
return containSpecial.test(item)
|
||||
},
|
||||
/**
|
||||
|
||||
@@ -3667,7 +3667,7 @@ function bindBTPanel(a, type, ip, btid, url, user, pw) {
|
||||
var gurl = "/config?action=AddPanelInfo";
|
||||
var btaddress = $("#btaddress").val();
|
||||
if (!btaddress.match(/^(http|https)+:\/\/([\w-]+\.)+[\w-]+:\d+/)) {
|
||||
layer.msg(lan.bt.panel_err_format + '<p>http://192.168.0.1:8888</p>', { icon: 5, time: 5000 });
|
||||
layer.msg(lan.bt.panel_err_format + '<p>http://192.168.0.1:7800</p>', { icon: 5, time: 5000 });
|
||||
return;
|
||||
}
|
||||
var btuser = encodeURIComponent($("#btuser").val());
|
||||
@@ -4837,7 +4837,7 @@ acme = {
|
||||
|
||||
//一键申请
|
||||
//domain 域名列表 []
|
||||
//auth_type 验证类型 dns/http
|
||||
//auth_type 验证类型 model/http
|
||||
//auth_to 验证路径 网站根目录或dnsapi
|
||||
//auto_wildcard 是否自动组合通配符 1.是 0.否 默认0
|
||||
apply_cert: function(domains, auth_type, auth_to, auto_wildcard, callback) {
|
||||
|
||||
@@ -320,34 +320,23 @@ var bt = {
|
||||
* @param success {function} 成功后的回调
|
||||
*/
|
||||
select_path: function(id, type,success,default_path) {
|
||||
_this = this;
|
||||
_this.set_cookie("SetName", "");
|
||||
if(typeof type !== 'string') success = type,type = 'dir';
|
||||
var loadT = bt.open({
|
||||
type: 1,
|
||||
area: "680px",
|
||||
title: type === 'all' ? 'Select directories or files' : lan.bt.dir,
|
||||
closeBtn: 2,
|
||||
shift: 5,
|
||||
content: "<div class='changepath'><div class='path-top'><button type='button' id='btn_back' class='btn btn-default btn-sm'><span class='glyphicon glyphicon-share-alt'></span> " + lan.public.return+"</button><div class='place' id='PathPlace'>" + lan.bt.path + ":<span></span></div></div><div class='path-con'><div class='path-con-left'><dl><dt id='changecomlist' >" + lan.bt.comp + "</dt></dl></div><div class='path-con-right'><ul class='default' id='computerDefautl'></ul><div class='file-list divtable'><table class='table table-hover' style='border:0 none'><thead><tr class='file-list-head'><th width='5%'></th><th width='38%'>" + lan.bt.filename + "</th><th width='24%'>" + lan.bt.etime + "</th><th width='8%'>" + lan.bt.access + "</th><th width='15%'>" + lan.bt.own + "</th></tr></thead><tbody id='tbody' class='list-list'></tbody></table></div></div></div></div><div class='getfile-btn' style='margin-top:0'><button type='button' class='btn btn-default btn-sm pull-left' onclick='CreateFolder()'>" + lan.bt.adddir + "</button><button type='button' class='btn btn-danger btn-sm mr5' onclick=\"layer.close(getCookie('ChangePath'))\">" + lan.public.close + "</button> <button type='button' id='bt_select' class='btn btn-success btn-sm' >" + lan.bt.path_ok + "</button></div>",
|
||||
success: function() {
|
||||
$('#btn_back').click(function() {
|
||||
var path = $("#PathPlace").find("span").text();
|
||||
path = bt.rtrim(bt.format_path(path), '/');
|
||||
var back_path = bt.get_file_path(path);
|
||||
_this.get_file_list(back_path, type);
|
||||
})
|
||||
//选择
|
||||
$('#bt_select').click(function() {
|
||||
var path = bt.format_path($("#PathPlace").find("span").text());
|
||||
if ($('#tbody tr').hasClass('active')) {
|
||||
path = $('#tbody tr.active .bt_open_dir').attr('path');
|
||||
}
|
||||
path = bt.rtrim(path, '/');
|
||||
$("#" + id).val(path).change();
|
||||
$("." + id).val(path).change();
|
||||
loadT.close();
|
||||
})
|
||||
_this = this;
|
||||
_this.set_cookie("SetName", "");
|
||||
if(typeof type !== 'string') success = type,type = 'dir';
|
||||
var loadT = bt.open({
|
||||
type: 1,
|
||||
area: "680px",
|
||||
title: type === 'all' ? 'Select directories or files' : lan.bt.dir,
|
||||
closeBtn: 2,
|
||||
shift: 5,
|
||||
content: "<div class='changepath'><div class='path-top'><button type='button' id='btn_back' class='btn btn-default btn-sm'><span class='glyphicon glyphicon-share-alt'></span> " + lan.public.return+"</button><div class='place' id='PathPlace'>" + lan.bt.path + ":<span></span></div></div><div class='path-con'><div class='path-con-left'><dl><dt id='changecomlist' >" + lan.bt.comp + "</dt></dl></div><div class='path-con-right'><ul class='default' id='computerDefautl'></ul><div class='file-list divtable'><table class='table table-hover' style='border:0 none'><thead><tr class='file-list-head'><th width='5%'></th><th width='38%'>" + lan.bt.filename + "</th><th width='24%'>" + lan.bt.etime + "</th><th width='8%'>" + lan.bt.access + "</th><th width='15%'>" + lan.bt.own + "</th></tr></thead><tbody id='tbody' class='list-list'></tbody></table></div></div></div></div><div class='getfile-btn' style='margin-top:0'><button type='button' class='btn btn-default btn-sm pull-left' onclick='CreateFolder()'>" + lan.bt.adddir + "</button><button type='button' class='btn btn-danger btn-sm mr5' onclick=\"layer.close(getCookie('ChangePath'))\">" + lan.public.close + "</button> <button type='button' id='bt_select' class='btn btn-success btn-sm' >" + lan.bt.path_ok + "</button></div>",
|
||||
success: function() {
|
||||
$('#btn_back').click(function() {
|
||||
var path = $("#PathPlace").find("span").text();
|
||||
path = bt.rtrim(bt.format_path(path), '/');
|
||||
var back_path = bt.get_file_path(path);
|
||||
_this.get_file_list(back_path, type);
|
||||
})
|
||||
//选择
|
||||
$('#bt_select').on('click',function () {
|
||||
var path = bt.format_path($("#PathPlace").find("span").text());
|
||||
@@ -413,7 +402,7 @@ var bt = {
|
||||
var d = '',a = '',disk = rdata.DISK;
|
||||
if (disk != undefined) {
|
||||
for (var f = 0; f < disk.length; f++) {
|
||||
a += "<dd class=\"bt_open_dir\" path =\"" + disk[f].path + "\"><span class='glyphicon glyphicon-hdd'></span> " + disk[f].path + "</dd>"
|
||||
a += "<dd class=\"bt_open_dir size_ellipsis\" title='" + disk[f].path + "' path =\"" + disk[f].path + "\"><span class='glyphicon glyphicon-hdd'></span><span class='text'>" + disk[f].path + "</span></dd>"
|
||||
}
|
||||
$("#changecomlist").html(a)
|
||||
}
|
||||
@@ -1746,7 +1735,7 @@ bt.index = {
|
||||
x = q[0].split(" ")[1];
|
||||
if(p=='pure-ftpd') p = 'pureftpd';
|
||||
if(p=='php') p = 'php-'+x;
|
||||
if(p=='dns-server') p = 'dns_manager';
|
||||
if(p=='model-server') p = 'dns_manager';
|
||||
if(p=='mail-server') p = 'mail_sys';
|
||||
|
||||
s = "sName=" + p + "&version=" + x + "&type=" + v + "&id=" + (t + 1);
|
||||
@@ -5460,8 +5449,8 @@ bt.database = {
|
||||
var loadT = bt.load(lan.database.sync_the);
|
||||
bt.send('SyncGetDatabases', 'database/SyncGetDatabases', {}, function(rdata) {
|
||||
loadT.close();
|
||||
if (callback) callback(rdata);
|
||||
bt.msg(rdata);
|
||||
if (callback) callback(rdata);
|
||||
});
|
||||
},
|
||||
sync_to_database: function(data, callback) {
|
||||
@@ -5771,9 +5760,9 @@ bt.site = {
|
||||
})
|
||||
}
|
||||
},
|
||||
set_phpversion: function(siteName, version, callback) {
|
||||
set_phpversion: function(siteName, version, other, callback) {
|
||||
var loading = bt.load();
|
||||
bt.send('SetPHPVersion', 'site/SetPHPVersion', { siteName: siteName, version: version }, function(rdata) {
|
||||
bt.send('SetPHPVersion', 'site/SetPHPVersion', { siteName: siteName, version: version, other: other }, function(rdata) {
|
||||
loading.close();
|
||||
if (callback) callback(rdata);
|
||||
})
|
||||
|
||||
+31
-15
@@ -6,14 +6,22 @@ $('#cutMode span').on('click',function(){
|
||||
switch(index){
|
||||
case 0:
|
||||
$('#bt_site_table').empty();
|
||||
if(!isSetup) $('.site_table_view .mask_layer').removeClass('hide').find('.prompt_description').html('Web server is not installed,<a href="javascript:;" class="btlink" onclick="bt.soft.install(\'nginx\')">Install Nginx</a> | <a href="javascript:;" class="btlink" onclick="bt.soft.install(\'apache\')">Install Apache</a>');
|
||||
if (!isSetup) {
|
||||
// layer.msg('Web server is not installed<br/><a href="javascript:;" class="btlink" onclick="bt.soft.install(\'nginx\')">Install Nginx</a> | <a href="javascript:;" class="btlink" onclick="bt.soft.install(\'apache\')">Install Apache</a>', { icon: 7, shade: [0.3, '#000'], time: 0 });
|
||||
$('#bt_site_table+.mask_layer').removeClass('hide').find('.prompt_description').html('Web server is not installed, <a href="javascript:;" class="btlink" onclick="bt.soft.install(\'nginx\')">Install Nginx</a> | <a href="javascript:;" class="btlink" onclick="bt.soft.install(\'apache\')">Install Apache</a>');
|
||||
}
|
||||
site.php_table_view();
|
||||
site.get_types();
|
||||
break;
|
||||
case 1:
|
||||
$('#bt_node_table').empty();
|
||||
$.get('/plugin?action=getConfigHtml',{name: "nodejs"},function(res){
|
||||
if(typeof res !== 'string') $('.site_table_view .mask_layer').removeClass('hide').find('.prompt_description').html('Node version manager is not installed,<a href="javascript:;" class="btlink" onclick="bt.soft.install(\'nodejs\')">Click install</a>');
|
||||
// if(typeof res !== 'string') $('.site_table_view .mask_layer').removeClass('hide').find('.prompt_description').html('Node version manager is not installed,<a href="javascript:;" class="btlink" onclick="bt.soft.install(\'nodejs\')">Click install</a>');
|
||||
if (typeof res !== 'string') {
|
||||
$('#bt_node_table+.mask_layer').removeClass('hide').find('.prompt_description').html('Node version manager is not installed,<a href="javascript:;" class="btlink" onclick="bt.soft.install(\'nodejs\')">Click install</a>');
|
||||
} else {
|
||||
$('#bt_node_table+.mask_layer').addClass('hide');
|
||||
}
|
||||
})
|
||||
site.node_porject_view();
|
||||
break;
|
||||
@@ -60,7 +68,7 @@ var site = {
|
||||
var project_script = $("[data-name=\'project_script\']");
|
||||
if(formData.project_script === ''){
|
||||
if($("#project_script_two").length === 0){
|
||||
project_script.parent().after('<div class="inlineBlock"><input type="text" name="project_script_two" id="project_script_two" placeholder="Please select the startup file and startup command, it cannot be empty" class="mt5 bt-input-text mr10 " style="width:420px;" value="" /><span class="glyphicon glyphicon-folder-open cursor" onclick="bt.select_path(\'project_script_two\',\'file\',null,\''+path+'\')" style="margin-right: 18px;"></span></div>')
|
||||
project_script.parent().after('<div class="inlineBlock"><input type="text" name="project_script_two" id="project_script_two" placeholder="Please select the startup file and startup command, it cannot be empty" class="mt5 bt-input-text mr10 " style="width:420px;" value="" /><span class="glyphicon glyphicon-folder-open cursor" onclick="bt.select_path(\'project_script_two\',\'all\',null,\''+path+'\')" style="margin-right: 18px;"></span></div>')
|
||||
}
|
||||
}else{
|
||||
project_script.parent().next().remove();
|
||||
@@ -1521,6 +1529,7 @@ var site = {
|
||||
});
|
||||
},
|
||||
php_table_view:function(){
|
||||
$('#bt_site_table').empty();
|
||||
var site_table = bt_tools.table({
|
||||
el:'#bt_site_table',
|
||||
url:'/data?action=getData',
|
||||
@@ -1545,7 +1554,7 @@ var site = {
|
||||
site.web_edit(row,true);
|
||||
},
|
||||
template: function (row, index) {
|
||||
return '<a class="btlink" style="display: inline-block; width: 110px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;" href="javascript:;" title="' + row.name + '">' + row.name + '</a>';
|
||||
return '<div style="display: flex;"><a class="btlink size_ellipsis" style="flex: 1; width: 0;" href="javascript:;" title="' + row.name + '">' + row.name + '</a></div>';
|
||||
}
|
||||
},
|
||||
{fid:'status',title:lan.site.status,sort:true,width:85,config:{icon:true,list:[['1',lan.site.running_text,'bt_success','glyphicon-play'],['0',lan.site.stopped,'bt_danger','glyphicon-pause']]},type:'status',event:function(row,index,ev,key,that){
|
||||
@@ -1576,7 +1585,7 @@ var site = {
|
||||
openPath(row.path);
|
||||
},
|
||||
template: function (row, index) {
|
||||
return '<a class="btlink" style="display: inline-block; width: 150px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;" href="javascript:;" title="' + row.path + '">' + row.path + '</a>';
|
||||
return '<div style="display: flex;"><a class="btlink size_ellipsis" style="flex: 1; width: 0;" href="javascript:;" title="' + row.path + '">' + row.path + '</a></div>';
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -1726,19 +1735,21 @@ var site = {
|
||||
confirmVerify:false, //是否提示验证方式
|
||||
paramName:'sites_id', //列表参数名,可以为空
|
||||
paramId:'id', // 需要传入批量的id
|
||||
theadName:'Name'
|
||||
theadName:'Name',
|
||||
refresh: true
|
||||
},{
|
||||
title:lan.site.backup_website,
|
||||
url:'/site?action=ToBackup',
|
||||
paramId:'id',
|
||||
load:true,
|
||||
theadName:'Name',
|
||||
refresh: true,
|
||||
callback:function(that){ // 手动执行,data参数包含所有选中的站点
|
||||
that.start_batch({},function(list){
|
||||
var html = '';
|
||||
for(var i=0;i<list.length;i++){
|
||||
var item = list[i];
|
||||
html += '<tr><td>'+ item.name +'</td><td><div style="float:right;"><span style="color:'+ (item.request.status?'#20a53a':'red') +'">'+ item.request.msg +'</span></div></td></tr>';
|
||||
html += '<tr><td><span style="width: 150px;" class="limit-text-length" title="' + item.name + '">'+ item.name +'</span></td><td class="text-right"><span style="color:'+ (item.request.status?'#20a53a':'red') +'">'+ item.request.msg +'</span></td></tr>';
|
||||
}
|
||||
site_table.$batch_success_table({title:'Batch backup',th:'Site name',html:html});
|
||||
site_table.$refresh_table_list(true);
|
||||
@@ -1750,6 +1761,7 @@ var site = {
|
||||
paramName:'sites_id', //列表参数名,可以为空
|
||||
paramId:'id', // 需要传入批量的id
|
||||
theadName:'Name',
|
||||
refresh: true,
|
||||
confirm:{
|
||||
title:'Batch set expired date',
|
||||
content:'<div class="line"><span class="tname">Expired date</span><div class="info-r "><input name="edate" id="site_edate" class="bt-input-text mr5" placeholder="yyyy-MM-dd" type="text"></div></div>',
|
||||
@@ -1787,6 +1799,7 @@ var site = {
|
||||
paramName:'sites_id', //列表参数名,可以为空
|
||||
paramId:'id', // 需要传入批量的id
|
||||
theadName:'Name',
|
||||
refresh: true,
|
||||
confirm:{
|
||||
title:'Batch set php version',
|
||||
area:'420px',
|
||||
@@ -1809,6 +1822,7 @@ var site = {
|
||||
url:'/site?action=set_site_type',
|
||||
paramName:'site_ids', //列表参数名,可以为空
|
||||
paramId:'id', // 需要传入批量的id
|
||||
refresh: true,
|
||||
beforeRequest:function(list){
|
||||
var arry = [];
|
||||
$.each(list,function(index,item){
|
||||
@@ -1833,6 +1847,7 @@ var site = {
|
||||
}
|
||||
},
|
||||
tips:false,
|
||||
refresh: true,
|
||||
success:function(res,list,that){
|
||||
var html = '';
|
||||
$.each(list,function(index,item){
|
||||
@@ -1847,6 +1862,7 @@ var site = {
|
||||
// paramName:'sites_id', //列表参数名,可以为空
|
||||
// paramId:'id', //需要传入批量的id
|
||||
// theadName:'Name',
|
||||
refresh: true,
|
||||
param: function (row) {
|
||||
return {
|
||||
id: row.id,
|
||||
@@ -2166,7 +2182,6 @@ var site = {
|
||||
site.get_list(0,'', val);
|
||||
$(".site_type button").removeClass('btn-success').addClass('btn-default');
|
||||
$(this).addClass('btn-success');
|
||||
|
||||
})
|
||||
if (callback) callback(rdata);
|
||||
});
|
||||
@@ -2391,7 +2406,7 @@ var site = {
|
||||
var html = '';
|
||||
for (var i = 0; i < list.length; i++) {
|
||||
var item = list[i];
|
||||
html += '<tr><td><span class="text-overflow" title="' + item.name + '">' + item.name + '</span></td><td><div style="float:right;"><span style="color:' + (item.request.status ? '#20a53a' : 'red') + '">' + item.request.msg + '</span></div></td></tr>';
|
||||
html += '<tr><td><span style="width: 150px;" class="limit-text-length" title="' + item.name + '">' + item.name + '</span></td><td class="text-right"><span style="color:' + (item.request.status ? '#20a53a' : 'red') + '">' + item.request.msg + '</span></td></tr>';
|
||||
}
|
||||
backup_table.$batch_success_table({ title: 'Delete site backups in bulk', th: 'file name', html: html });
|
||||
backup_table.$refresh_table_list(true);
|
||||
@@ -3954,7 +3969,8 @@ var site = {
|
||||
paramId:'id',
|
||||
paramName:'domains_id',
|
||||
theadName:'Domain',
|
||||
confirmVerify:false //是否提示验证方式
|
||||
confirmVerify:false, //是否提示验证方式
|
||||
refresh: true
|
||||
}
|
||||
}]
|
||||
});
|
||||
@@ -4859,8 +4875,8 @@ var site = {
|
||||
var versions = $('[name="versions"]').val();
|
||||
versions = versions.slice(0, versions.length - 1) + '.' + versions.slice(-1);
|
||||
if (versions == '0.0') versions = 'Static';
|
||||
site_table.$refresh_table_list(true);
|
||||
site.reload()
|
||||
site.php_table_view();
|
||||
site.reload();
|
||||
setTimeout(function() {
|
||||
bt.msg(ret);
|
||||
}, 1000);
|
||||
@@ -4887,7 +4903,7 @@ var site = {
|
||||
setTimeout(function(){
|
||||
$('select[name="versions"]').change(function(){
|
||||
var phpversion = $(this).val();
|
||||
console.log(phpversion);
|
||||
// console.log(phpversion);
|
||||
if(phpversion == 'other'){
|
||||
$('.other-version').show();
|
||||
}else{
|
||||
@@ -5859,7 +5875,7 @@ var site = {
|
||||
title: lan.site.website_change + '[' + item.name + '] -- ' + lan.site.addtime + '[' + item.addtime + ']',
|
||||
closeBtn: 2,
|
||||
shift: 0,
|
||||
content: "<div class='bt-form'><div class='bt-w-menu site-menu pull-left' style='height: 100%;'></div><div id='webedit-con' class='bt-w-con webedit-con pd15'></div></div>"
|
||||
content: "<div class='bt-form clearfix'><div class='bt-w-menu site-menu pull-left' style='height: 100%;'></div><div id='webedit-con' class='bt-w-con webedit-con pd15'></div></div>"
|
||||
})
|
||||
setTimeout(function() {
|
||||
var webcache = bt.get_cookie('serverType') == 'openlitespeed' ? { title: 'LS-Cache', callback: site.edit.ols_cache } : '';
|
||||
@@ -6016,7 +6032,7 @@ var site = {
|
||||
title: "Let's Encrypt",
|
||||
callback: function(robj) {
|
||||
robj = $('#webedit-con .tab-con')
|
||||
console.log(robj,'obj');
|
||||
// console.log(robj,'obj');
|
||||
acme.get_account_info(function(let_user) {});
|
||||
acme.id = web.id;
|
||||
if (rdata.status && rdata.type == 1) {
|
||||
|
||||
@@ -213,15 +213,14 @@ var bt_tools = {
|
||||
* @return void
|
||||
*/
|
||||
$batch_success_table: function (config) {
|
||||
console.log(1);
|
||||
var _that = this,length = $(config.html).length;
|
||||
bt.open({
|
||||
type: 1,
|
||||
title: config.title,
|
||||
area: config.area || ['400px', '350px'],
|
||||
area: config.area || ['400px'],
|
||||
shadeClose: false,
|
||||
closeBtn: 2,
|
||||
content: config.content || '<div class="batch_title"><span class><span class="batch_icon"></span><span class="batch_text">' + config.title + ' '+lan['public'].success+'</span></span></div><div class="'+ (length > 4?'fiexd_thead':'') +' batch_tabel divtable" style="margin: 15px 30px 15px 30px;overflow: auto;height: 200px;"><table class="table table-hover"><thead><tr><th>' + config.th + '</th><th style="text-align:right;width:170px;">'+lan['public'].result+'</th></tr></thead><tbody>' + config.html + '</tbody></table></div>',
|
||||
content: config.content || '<div class="batch_title"><span class><span class="batch_icon"></span><span class="batch_text">' + config.title + ' '+lan['public'].success+'</span></span></div><div class="'+ (length > 4?'fiexd_thead':'') +' batch_tabel divtable" style="margin: 15px 30px 15px 30px;overflow: auto;max-height: 195px; border: 1px solid #ddd;"><table style="border: none;" class="table table-hover"><thead><tr><th>' + config.th + '</th><th style="text-align:right;width:170px;">'+lan['public'].result+'</th></tr></thead><tbody>' + config.html + '</tbody></table></div>',
|
||||
success: function () {
|
||||
if(length > 4) _that.$fixed_table_thead('.fiexd_thead');
|
||||
}
|
||||
@@ -2321,10 +2320,10 @@ var bt_tools = {
|
||||
bt.open({
|
||||
type: 1,
|
||||
title: config.title,
|
||||
area: config.area || ['400px', '350px'],
|
||||
area: config.area || ['400px'],
|
||||
shadeClose: false,
|
||||
closeBtn: 2,
|
||||
content: config.content || '<div class="batch_title"><span class><span class="batch_icon"></span><span class="batch_text">' + config.title + ' '+lan['public'].success+'</span></span></div><div class="'+ (length > 4?'fiexd_thead':'') +' batch_tabel divtable" style="margin: 15px 30px 15px 30px;overflow: auto;height: 200px;"><table class="table table-hover"><thead><tr><th>' + config.th + '</th><th style="text-align:right;width:170px;">'+lan['public'].result+'</th></tr></thead><tbody>' + config.html + '</tbody></table></div>',
|
||||
content: config.content || '<div class="batch_title"><span class><span class="batch_icon"></span><span class="batch_text">' + config.title + ' '+lan['public'].success+'</span></span></div><div class="'+ (length > 4?'fiexd_thead':'') +' batch_tabel divtable" style="margin: 15px 30px 15px 30px;overflow: auto;max-height: 195px; border: 1px solid #ddd; border-bottom: none;"><table style="border: none;" class="table table-hover"><thead><tr><th>' + config.th + '</th><th style="text-align:right;width:170px;">'+lan['public'].result+'</th></tr></thead><tbody>' + config.html + '</tbody></table></div>',
|
||||
success: function () {
|
||||
if(length > 4) _that.$fixed_table_thead('.fiexd_thead');
|
||||
}
|
||||
|
||||
@@ -120,9 +120,9 @@
|
||||
"MYSQL_CHECK_ERR":"In MySQL configuration file detected and auto fixed an error, which may cause mysqld service unable to start!",
|
||||
"SYS_EXEC_ERR":"Execution failed: {1}",
|
||||
"SYS_EXEC_SUCCESS":"{1} execution succeeded",
|
||||
"LOGIN_ERR_CODE":"<a style='color:red;'>Verification code is incorrect</a>, Username:{1}, Verification Code:{2}, Login IP:{3}",
|
||||
"LOGIN_ERR_PASS":"<a style='color:red;'>Password is incorrect</a>, Username:{1}, Password:{2}, Login IP:{3}",
|
||||
"LOGIN_SUCCESS":"<a style='color:green;'>Login succeed</a>, Username:{1}, Login IP:{2}",
|
||||
"LOGIN_ERR_CODE":"Verification code is incorrect, Username:{1}, Verification Code:{2}, Login IP:{3}",
|
||||
"LOGIN_ERR_PASS":"Password is incorrect, Username:{1}, Password:{2}, Login IP:{3}",
|
||||
"LOGIN_SUCCESS":"Login succeed, Username: {1}, Login IP: {2}",
|
||||
"SET_API": "API configuration",
|
||||
"P_CONF": "Panel settings",
|
||||
"MODIFY_CRON_STATUS": "Modified cron job [{1}] status to [{2}]",
|
||||
|
||||
@@ -36,11 +36,12 @@
|
||||
<div class="tab-con" style="padding:10px 0;overflow: inherit;">
|
||||
<div class="tab-con-block">
|
||||
<div id="bt_site_table"></div>
|
||||
<div class="mask_layer hide"><div class="prompt_description"></div></div>
|
||||
</div>
|
||||
<div class="tab-con-block ">
|
||||
<div class="tab-con-block">
|
||||
<div id="bt_node_table"></div>
|
||||
<div class="mask_layer hide"><div class="prompt_description"></div></div>
|
||||
</div>
|
||||
<div class="mask_layer hide"><div class="prompt_description"></div></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -102,10 +102,4 @@
|
||||
<script type="text/javascript" src="/static/js/clipboard.min.js"></script>
|
||||
<script type="text/javascript" src="/static/js/xterm.js"></script>
|
||||
<script type="text/javascript" src="/static/js/term.js"></script>
|
||||
<script type="text/javascript">
|
||||
if($("#panel_debug").attr("data") == 'True') {
|
||||
layer.msg('The current mode is developer mode. Can not support SSH. Please turn it off in the 【Settings】 page!',{icon:7,shade: [0.3, '#000'],time:0});
|
||||
$(".layui-layer-shade").css("margin-left", "180px");
|
||||
}
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
@@ -1,122 +1,28 @@
|
||||
**Introduction:**
|
||||
#aaPanel Docker Deployment
|
||||
The docker image is officially released by aaPanel
|
||||
|
||||
aaPanel is the International version for BAOTA panel(www.bt.cn) There have millions servers had installed BAOTA panel since 2014 in China.
|
||||
aaPanel, a simple but powerful control panel, can manage the web server through web-based GUI(Graphical User Interface).
|
||||
aaPanel provides the one-click function such as one-click install LNMP/LAMP developing environment and software.
|
||||
Our main goal is helping users to save the time of deploying, thus users just focus on their own project that is fine.
|
||||
|
||||
**History:**
|
||||
|
||||
_The founding R & D team of BaoTa has 5 people, all of whom have 5 to 10 years of experience in idc related industries._
|
||||
|
||||
_When everyone discusses together and works in the schedule or their own use, they find that there is no such thing in the field of servers._
|
||||
|
||||
_The company specializes in developing relevant software for ordinary users, especially those who do not know much about technology._
|
||||
|
||||
_We found that for many users, operating the server is not easy, it is necessary to consult others, take time to search for answers, and even pay for simple questions._
|
||||
|
||||
_There will be many pits involved in the cost. Some auxiliary software itself is more difficult than using the server._
|
||||
|
||||
_Even this kind of painful point is itchiness. With the development of cloud servers, the number of server users has increased by several orders of magnitude._
|
||||
|
||||
_The preparatory work for the establishment of the pagoda began at the end of 2014, and began to develop and test software in the first half of 2015._
|
||||
|
||||
_At this stage, the pagoda brand was officially launched in 2016 and bt.cn was used as the official website._
|
||||
|
||||
_In 2017, BaoTa tried to enter the overseas market, but because the number of people could not keep up, he decided to temporarily abandon the overseas market and focus on China._
|
||||
|
||||
_In 2019, due to the gradual growth of BaoTa users, which has become the hosting control panel used by the most webmasters in China, it is decided to enter the overseas market and develop related plug-ins that are suitable for foreign friends___
|
||||
|
||||
**What can it do:**
|
||||
|
||||
_aaPanel is a server management software that supports the Linux system._
|
||||
|
||||
_It can easily manage the server through the Web terminal, improving the operation and maintenance efficiency._
|
||||
|
||||
**For example:**
|
||||
|
||||
|
||||
_create and manage websites, FTP, and databases, with visual file manager, visual software manager, visual CPU, memory, flow monitoring chart, scheduled tasks and other functions._
|
||||
|
||||
_aaPanel has extremely fast and convenient one-key configuration and management, one-click configuration of server environment (LAMP / LNMP / Tomcat / Node.js /OpenLiteSpeed), one-click deployment of SSL, remote backup;_
|
||||
|
||||
_provide SSH open and close services, SSH port changes, ping prohibited , Firewall port release and operation log viewing; CPU, memory, disk IO, network IO data monitoring, you can set the number of days to record and save and view the data of a certain day;_
|
||||
|
||||
_scheduled tasks can be added and executed periodically, support SHELL script, provide website, database backup And log cutting, and support one-click backup to another cloud storage space, or other cloud storage space; through the web interface, you can easily manage the server software used for installation, as well as practical extension plug-ins;_
|
||||
|
||||
_convenient and efficient file manager integration , Support uploading, downloading, packaging, decompression and file editing and viewing._
|
||||
Maintained by: [aaPanel](https://www.aapanel.com)
|
||||
|
||||
|
||||
|
||||
**Over 2,100,000 servers have installed aaPanel in Asia**
|
||||
##How to use
|
||||
|
||||
**HomePage:**
|
||||
`$docker run -d -p 8886:8888 -p 22:21 -p 443:443 -p 80:80 -p 889:888 -v ~/website_data:/www/wwwroot -v ~/mysql_data:/www/server/data -v ~/vhost:/www/server/panel/vhost aapanel/aapanel:lib`
|
||||
|
||||

|
||||
Now you can access aaPanel at http://youripaddress:8886/ from your host system.
|
||||
|
||||
**WebSite Manager:**
|
||||
Default username:`aapanel`
|
||||
|
||||

|
||||
Default password:`aapanel123`
|
||||
|
||||
**FTP Manager**
|
||||
####Port usage analysis
|
||||
Control Panel : 8888
|
||||
Phpmyadmin : 888
|
||||
|
||||

|
||||
####Dir usage analysis
|
||||
Website data : /www/wwwroot
|
||||
Mysql data : /www/server/data
|
||||
Vhost file : /www/server/panel/vhost
|
||||
|
||||
**DataBase Manager**
|
||||
**Note: after the deployment is complete, please immediately modify the user name and password in the panel settings and add the installation entry**
|
||||
|
||||

|
||||
|
||||
**File Manager**
|
||||
|
||||

|
||||
|
||||
**Cron Manager**
|
||||
|
||||

|
||||
|
||||
**Monitory**
|
||||
|
||||

|
||||
|
||||
**Security**
|
||||
|
||||

|
||||
|
||||
**Software**
|
||||
|
||||

|
||||
|
||||
**Online editor**
|
||||
|
||||

|
||||
|
||||
**Share files with your friends**
|
||||
|
||||

|
||||
|
||||
**Send link password or QR code to your friends**
|
||||
|
||||

|
||||
|
||||
**Your friend opens the link effect you shared**
|
||||
|
||||

|
||||
|
||||
|
||||
[User Manual](https://doc.aapanel.com/web/#/3?page_id=117 "User Manual")
|
||||
|
||||
|
||||
##### Home Page:https://www.aapanel.com/
|
||||
##### Forum Page:https://forum.aapanel.com/
|
||||
##### Feedback: https://forum.aapanel.com/
|
||||
##### Bug submission:https://forum.aapanel.com/
|
||||
|
||||
#### Installation command:
|
||||
##### Centos
|
||||
```bash
|
||||
yum install -y wget && wget -O install.sh http://www.aapanel.com/script/install_6.0_en.sh && bash install.sh 66959f96
|
||||
```
|
||||
##### Ubuntu/Debian
|
||||
```bash
|
||||
wget -O install.sh http://www.aapanel.com/script/install-ubuntu_6.0_en.sh && sudo bash install.sh 66959f96
|
||||
```
|
||||
|
||||
+155
-8
@@ -60,6 +60,7 @@ class acme_v2:
|
||||
_dnsapi_file = 'config/dns_api.json'
|
||||
_save_path = 'vhost/letsencrypt'
|
||||
_conf_file = 'config/letsencrypt.json'
|
||||
_stop_rp_file = '{}/data/stop_rp_when_renew_ssl.pl'.format(public.get_panel_path())
|
||||
_by_panel = None
|
||||
|
||||
def __init__(self):
|
||||
@@ -1331,15 +1332,95 @@ fullchain.pem Paste into certificate input box
|
||||
if not os.path.exists(args.auth_to):
|
||||
return public.returnMsg(False, 'ACME_DIR_ERR')
|
||||
|
||||
check_result = self.check_auth_env(args)
|
||||
check_result = self.check_auth_env(args, check=True)
|
||||
if check_result: return check_result
|
||||
|
||||
if args.auto_wildcard == '1':
|
||||
self._auto_wildcard = True
|
||||
return self.apply_cert(json.loads(args.domains), args.auth_type, args.auth_to)
|
||||
res = self.apply_cert(json.loads(args.domains), args.auth_type, args.auth_to)
|
||||
if os.path.exists(self._stop_rp_file):
|
||||
self.turnon_redirect_proxy_httptohttps(args)
|
||||
return res
|
||||
|
||||
def turnon_redirect_proxy_httptohttps(self,args):
|
||||
import panelSite
|
||||
s = panelSite.panelSite()
|
||||
if not 'siteName' in args:
|
||||
args.siteName = public.M('sites').where('id=?', (args.id,)).getField('name')
|
||||
args.sitename = args.siteName
|
||||
self.turnon_redirect(args,s)
|
||||
self.turnon_proxy(args, s)
|
||||
self.turnon_httptohttps(args,s)
|
||||
public.serviceReload()
|
||||
|
||||
def turnon_httptohttps(self,args,s):
|
||||
conf_file = '{}/data/stop_httptohttps.pl'.format(public.get_panel_path())
|
||||
if os.path.exists(conf_file):
|
||||
write_log('|-开启http to https')
|
||||
s.HttpToHttps(args)
|
||||
try:
|
||||
os.remove(conf_file)
|
||||
except:
|
||||
pass
|
||||
|
||||
def turnon_proxy(self,args,s):
|
||||
conf_file = '{}/data/stop_p_tmp.pl'.format(public.get_panel_path())
|
||||
if not os.path.exists(conf_file):
|
||||
return
|
||||
write_log('|-开启反向代理')
|
||||
conf = json.loads(public.readFile(conf_file))
|
||||
data = s.GetProxyList(args)
|
||||
for x in data:
|
||||
if x['sitename'] not in conf:
|
||||
continue
|
||||
if x['proxyname'] not in conf[x['sitename']]:
|
||||
continue
|
||||
args.type = 1
|
||||
args.advanced = x['advanced']
|
||||
args.cache = x['cache']
|
||||
args.cachetime = x['cachetime']
|
||||
args.proxydir = x['proxydir']
|
||||
args.proxyname = x['proxyname']
|
||||
args.proxysite = x['proxysite']
|
||||
args.sitename = x['sitename']
|
||||
args.subfilter = json.dumps(x['subfilter'])
|
||||
args.todomain = x['todomain']
|
||||
s.ModifyProxy(args)
|
||||
try:
|
||||
os.remove(conf_file)
|
||||
except:
|
||||
pass
|
||||
|
||||
def turnon_redirect(self,args,s):
|
||||
conf_file = '{}/data/stop_r_tmp.pl'.format(public.get_panel_path())
|
||||
if not os.path.exists(conf_file):
|
||||
return
|
||||
write_log('|-开启重定向')
|
||||
conf = json.loads(public.readFile(conf_file))
|
||||
data = s.GetRedirectList(args)
|
||||
for x in data:
|
||||
if x['sitename'] not in conf:
|
||||
continue
|
||||
if x['redirectname'] not in conf[x['sitename']]:
|
||||
continue
|
||||
args.type = 1
|
||||
args.sitename = x['sitename']
|
||||
args.holdpath = x['holdpath']
|
||||
args.redirectname = x['redirectname']
|
||||
args.redirecttype = x['redirecttype']
|
||||
args.domainorpath = x['domainorpath']
|
||||
args.redirectpath = x['redirectpath']
|
||||
args.redirectdomain = json.dumps(x['redirectdomain'])
|
||||
args.tourl = x['tourl']
|
||||
s.ModifyRedirect(args)
|
||||
try:
|
||||
os.remove(conf_file)
|
||||
except:
|
||||
pass
|
||||
|
||||
#检查认证环境
|
||||
def check_auth_env(self,args):
|
||||
def check_auth_env(self,args,check = None):
|
||||
if not check:
|
||||
return
|
||||
for domain in json.loads(args.domains):
|
||||
if public.checkIp(domain): continue
|
||||
if domain.find('*.') >=0 and args.auth_type in ['http','tls']:
|
||||
@@ -1348,26 +1429,80 @@ fullchain.pem Paste into certificate input box
|
||||
s = panelSite.panelSite()
|
||||
if args.auth_type in ['http','tls']:
|
||||
try:
|
||||
rp_conf = public.readFile(self._stop_rp_file)
|
||||
try:
|
||||
if rp_conf:
|
||||
rp_conf = json.loads(rp_conf)
|
||||
except:
|
||||
write_log('|-Failed to parse configuration file')
|
||||
if not 'siteName' in args:
|
||||
args.siteName = public.M('sites').where('id=?',(args.id,)).getField('name')
|
||||
args.sitename = args.siteName
|
||||
data = s.GetRedirectList(args)
|
||||
# 检查重定向是否开启
|
||||
if type(data) == list:
|
||||
redirect_tmp = {args.sitename:[]}
|
||||
for x in data:
|
||||
if x['type']: return public.returnMsg(False, 'SITE_SSL_ERR_301')
|
||||
if rp_conf and x['sitename'] in rp_conf:
|
||||
if str(x['type']) == '0':
|
||||
continue
|
||||
args.type = 0
|
||||
args.sitename = x['sitename']
|
||||
args.holdpath = x['holdpath']
|
||||
args.redirectname = x['redirectname']
|
||||
args.redirecttype = x['redirecttype']
|
||||
args.domainorpath = x['domainorpath']
|
||||
args.redirectpath = x['redirectpath']
|
||||
args.redirectdomain = json.dumps(x['redirectdomain'])
|
||||
args.tourl = x['tourl']
|
||||
args.notreload = True
|
||||
write_log("|- Turning off redirection {}".format(args.redirectname))
|
||||
s.ModifyRedirect(args)
|
||||
redirect_tmp[args.sitename].append(x['redirectname'])
|
||||
else:
|
||||
if x['type']: return public.returnMsg(False, 'SITE_SSL_ERR_301')
|
||||
if redirect_tmp[args.sitename]:
|
||||
public.writeFile('{}/data/stop_r_tmp.pl'.format(public.get_panel_path()),json.dumps(redirect_tmp))
|
||||
data = s.GetProxyList(args)
|
||||
# 检查反向代理是否开启
|
||||
if type(data) == list:
|
||||
proxy_tmp = {args.sitename: []}
|
||||
for x in data:
|
||||
if x['type']: return public.returnMsg(False,'ACME_PROXY_ERR')
|
||||
if rp_conf and x['sitename'] in rp_conf:
|
||||
if str(x['type']) == '0':
|
||||
continue
|
||||
args.type = 0
|
||||
args.advanced = x['advanced']
|
||||
args.cache = x['cache']
|
||||
args.cachetime = x['cachetime']
|
||||
args.proxydir = x['proxydir']
|
||||
args.proxyname = x['proxyname']
|
||||
args.proxysite = x['proxysite']
|
||||
args.sitename = x['sitename']
|
||||
args.subfilter = json.dumps(x['subfilter'])
|
||||
args.todomain = x['todomain']
|
||||
args.notreload = True
|
||||
s.ModifyProxy(args)
|
||||
write_log("|- Turning off proxy {}".format(args.proxyname))
|
||||
proxy_tmp[args.sitename].append(x['proxyname'])
|
||||
else:
|
||||
if x['type']: return public.returnMsg(False,'ACME_PROXY_ERR')
|
||||
if proxy_tmp[args.sitename]:
|
||||
public.writeFile('{}/data/stop_p_tmp.pl'.format(public.get_panel_path()),json.dumps(proxy_tmp))
|
||||
# 检查旧重定向是否开启
|
||||
data = s.Get301Status(args)
|
||||
if data['status']:
|
||||
return public.returnMsg(False,'SITE_SSL_ERR_3011')
|
||||
#判断是否强制HTTPS
|
||||
if s.IsToHttps(args.siteName):
|
||||
return public.returnMsg(False, 'ACME_FORCE_SSL_ERR')
|
||||
if os.path.exists(self._stop_rp_file):
|
||||
if rp_conf and args.siteName in rp_conf:
|
||||
write_log("|- Turning off http to https")
|
||||
s.CloseToHttps(args)
|
||||
public.writeFile('{}/data/stop_httptohttps.pl'.format(public.get_panel_path()), '')
|
||||
else:
|
||||
return public.returnMsg(False, 'ACME_FORCE_SSL_ERR')
|
||||
public.serviceReload()
|
||||
except:
|
||||
return False
|
||||
else:
|
||||
@@ -1511,7 +1646,7 @@ fullchain.pem Paste into certificate input box
|
||||
# 是否到了最大重试次数
|
||||
if 'retry_count' in self._config['orders'][i]:
|
||||
if self._config['orders'][i]['retry_count'] >= 3:
|
||||
write_log('|-Skip the domain name this time: {}, this certificate will not be renewed due to failure to renew 3 times in a row'.format(self._config['orders'][i]['domains']))
|
||||
write_log('|-Skip the domain name this time: {}, this certificate will not be renewed due to failure to renew 3 times in a row, (The number of errors will be reset after manual renewal and success)'.format(self._config['orders'][i]['domains']))
|
||||
continue
|
||||
|
||||
# 加入到续签订单
|
||||
@@ -1524,7 +1659,17 @@ fullchain.pem Paste into certificate input box
|
||||
n = 0
|
||||
self.get_apis()
|
||||
cert = None
|
||||
args = public.to_dict_obj({})
|
||||
for index in order_index:
|
||||
args.domains = json.dumps(self._config['orders'][index]['domains'])
|
||||
args.auth_type = self._config['orders'][index]['auth_type']
|
||||
args.auth_to = self._config['orders'][index]['auth_to']
|
||||
sitename = args.auth_to.split('/')[-1]
|
||||
if not sitename:
|
||||
sitename = self._config['orders'][index]['auth_to'].split('/')[-2]
|
||||
args.siteName = sitename
|
||||
write_log('|-Renew the visa certificate and start checking the environment')
|
||||
self.check_auth_env(args,check=True)
|
||||
n += 1
|
||||
write_log(public.getMsg("ACME_RENEWING",(str(n),str(self._config['orders'][index]['domains']))))
|
||||
write_log(public.getMsg('ACME_CREAT_ORDER'))
|
||||
@@ -1558,6 +1703,8 @@ fullchain.pem Paste into certificate input box
|
||||
self.save_config()
|
||||
cert['status'] = True
|
||||
cert['msg'] = public.getMsg('ACME_RENEW_SUCCESS')
|
||||
if os.path.exists(self._stop_rp_file):
|
||||
self.turnon_redirect_proxy_httptohttps(args)
|
||||
write_log(public.getMsg('ACME_RENEW_SUCCESS1'))
|
||||
except Exception as e:
|
||||
if str(e).find('请稍候重试') == -1: # 受其它证书影响和连接CA失败的的不记录重试次数
|
||||
|
||||
+1
-1
@@ -698,7 +698,7 @@ class ajax:
|
||||
|
||||
# 下载云端php扩展配置
|
||||
def _get_cloud_phplib(self):
|
||||
if not session.get('download_url'): session['download_url'] = 'http://download.bt.cn'
|
||||
if not session.get('download_url'): session['download_url'] = 'http://node.aapanel.com'
|
||||
download_url = session['download_url'] + '/install/lib/phplib_en.json'
|
||||
tstr = public.httpGet(download_url)
|
||||
data = json.loads(tstr)
|
||||
|
||||
+2
-2
@@ -26,7 +26,7 @@ class panelSetup:
|
||||
ua = g.ua.lower()
|
||||
if ua.find('spider') != -1 or g.ua.find('bot') != -1:
|
||||
return redirect('https://www.google.com')
|
||||
g.version = '6.8.17'
|
||||
g.version = '6.8.21'
|
||||
g.title = public.GetConfigValue('title')
|
||||
g.uri = request.path
|
||||
g.debug = os.path.exists('data/debug.pl')
|
||||
@@ -150,7 +150,7 @@ class panelAdmin(panelSetup):
|
||||
if not 'login' in session:
|
||||
api_check = self.get_sk()
|
||||
if api_check:
|
||||
session.clear()
|
||||
#session.clear()
|
||||
return api_check
|
||||
g.api_request = True
|
||||
else:
|
||||
|
||||
+57
-16
@@ -31,10 +31,12 @@ class database(datatool.datatools):
|
||||
if ssl == "REQUIRE SSL" and not self.check_mysql_ssl_status(get):
|
||||
return public.returnMsg(False,'MYSQL_SSL_ERR')
|
||||
data_name = get['name'].strip().lower()
|
||||
if not data_name: return public.returnMsg(False, 'The database name cannot be empty')
|
||||
if self.CheckRecycleBin(data_name): return public.returnMsg(False,'DATABASE_DEL_RECYCLE_BIN',(data_name,))
|
||||
if len(data_name) > 64: return public.returnMsg(False, 'DATABASE_NAME_LEN')
|
||||
reg = r"^[\w\.-]+$"
|
||||
username = get.db_user.strip()
|
||||
if not username: return public.returnMsg(False,'The database user name cannot be empty')
|
||||
if not re.match(reg, data_name): return public.returnMsg(False,'DATABASE_NAME_ERR_T')
|
||||
if not re.match(reg, username): return public.returnMsg(False,'DATABASE_NAME_ERR')
|
||||
if not hasattr(get,'db_user'): get.db_user = data_name
|
||||
@@ -50,6 +52,8 @@ class database(datatool.datatools):
|
||||
if sql.where("name=?",(data_name)).count(): return public.returnMsg(False,'DATABASE_NAME_EXISTS')
|
||||
if sql.where("username=?", (username)).count(): return public.returnMsg(False, 'DATABASE_USERNAME_EXISTS')
|
||||
address = get['address'].strip()
|
||||
if address in ['','ip']: return public.returnMsg(False,'If the access permission is [Specified IP], you need to enter the IP address!')
|
||||
|
||||
user = '是'
|
||||
password = data_pwd
|
||||
|
||||
@@ -102,16 +106,21 @@ openssl x509 -sha1 -req -in server-req.pem -days 3650 -CA ca.pem -CAkey ca-key.p
|
||||
openssl req -sha1 -newkey rsa:2048 -days 3650 -nodes -subj "/C=CA/ST=CA/L=CA/O=CA/OU=CA/CN={ip}" -keyout client-key.pem > client-req.pem
|
||||
openssl rsa -in client-key.pem -out client-key.pem
|
||||
openssl x509 -sha1 -req -in client-req.pem -days 3650 -CA ca.pem -CAkey ca-key.pem -set_serial 01 > client-cert.pem
|
||||
tar -zcvf ssl.zip client-cert.pem client-key.pem ca.pem
|
||||
zip -q ssl.zip client-cert.pem client-key.pem ca.pem
|
||||
""".format(ip=ip)
|
||||
public.ExecShell(openssl_command)
|
||||
|
||||
# 写入mysqlssl到配置
|
||||
def write_ssl_to_mysql(self,get):
|
||||
ssl_conf = """
|
||||
ssl-ca=/www/server/data/ca.pem
|
||||
ssl-cert=/www/server/data/server-cert.pem
|
||||
ssl-key=/www/server/data/server-key.pem
|
||||
# ssl_conf = """
|
||||
# ssl-ca=/www/server/data/ca.pem
|
||||
# ssl-cert=/www/server/data/server-cert.pem
|
||||
# ssl-key=/www/server/data/server-key.pem
|
||||
# """
|
||||
ssl_original_path = """
|
||||
ssl-ca=/www/server/mysql/mysql-test/std_data/cacert.pem
|
||||
ssl-cert=/www/server/mysql/mysql-test/std_data//server-cert.pem
|
||||
ssl-key=/www/server/mysql/mysql-test/std_data/server-key.pem
|
||||
"""
|
||||
conf_file = "/etc/my.cnf"
|
||||
conf = public.readFile(conf_file)
|
||||
@@ -120,22 +129,37 @@ ssl-key=/www/server/data/server-key.pem
|
||||
if self.check_mysql_ssl_status(get):
|
||||
reg = "ssl-ca=/www.*\n.*\n.*server-key.pem\n"
|
||||
conf = re.sub(reg,"",conf)
|
||||
if os.path.exists('/www/server/mysql/mysql-test/std_data/server-cert.pem'):
|
||||
conf = re.sub('\[mysqld\]', '[mysqld]\nskip_ssl', conf)
|
||||
public.writeFile(conf_file,conf)
|
||||
return public.returnMsg(True,"SET_SUCCESS")
|
||||
self._create_mysql_ssl()
|
||||
# create_ssl = None
|
||||
# for i in ['5.5','5.6','10.1','10.2','10.3']:
|
||||
# if i not in public.readFile('/www/server/mysql/version_check.pl'):
|
||||
# continue
|
||||
# create_ssl = True
|
||||
# if create_ssl:
|
||||
# self._create_mysql_ssl()
|
||||
if "ssl-ca" not in conf:
|
||||
conf = re.sub('\[mysqld\]','[mysqld]'+ssl_conf,conf)
|
||||
conf = re.sub('\[mysqld\]','[mysqld]'+ssl_original_path,conf)
|
||||
conf = re.sub('skip_ssl\n', '', conf)
|
||||
public.writeFile(conf_file,conf)
|
||||
public.ExecShell('chown mysql.mysql /www/server/data/*.pem')
|
||||
# public.ExecShell('chown mysql.mysql /www/server/data/*.pem')
|
||||
return public.returnMsg(True,"MYSQL_SSL_OPEN_SUCCESS")
|
||||
|
||||
# 检查mysqlssl状态
|
||||
def check_mysql_ssl_status(self,get):
|
||||
mysql_obj = panelMysql.panelMysql()
|
||||
result = mysql_obj.query("show variables like 'have_ssl';")
|
||||
if result and result[0][1] == "YES":
|
||||
return True
|
||||
return False
|
||||
if not os.path.exists('/www/server/data/ssl.zip'):
|
||||
if os.path.exists('/www/server/mysql/mysql-test/std_data/client-cert.pem'):
|
||||
public.ExecShell("cd /www/server/mysql/mysql-test/std_data/ && zip -q /www/server/data/ssl.zip client-cert.pem client-key.pem cacert.pem")
|
||||
try:
|
||||
if result and result[0][1] == "YES":
|
||||
return True
|
||||
return False
|
||||
except:
|
||||
return False
|
||||
|
||||
#判断数据库是否存在—从MySQL
|
||||
def database_exists_for_mysql(self,mysql_obj,dataName):
|
||||
@@ -163,8 +187,10 @@ ssl-key=/www/server/data/server-key.pem
|
||||
#检查是否在回收站
|
||||
def CheckRecycleBin(self,name):
|
||||
try:
|
||||
u_name = self.db_name_to_unicode(name)
|
||||
for n in os.listdir('/www/Recycle_bin'):
|
||||
if n.find('BTDB_'+name+'_t_') != -1: return True
|
||||
if n.find('BTDB_'+u_name+'_t_') != -1: return True
|
||||
return False
|
||||
except:
|
||||
return False
|
||||
@@ -320,7 +346,18 @@ SetLink
|
||||
except Exception as ex:
|
||||
public.WriteLog("TYPE_DATABASE",'DATABASE_DEL_ERR',(get.name , str(ex)))
|
||||
return public.returnMsg(False,'DEL_ERROR')
|
||||
|
||||
|
||||
|
||||
def db_name_to_unicode(self,name):
|
||||
'''
|
||||
@name 中文数据库名转换为Unicode编码
|
||||
@author hwliang<2021-12-20>
|
||||
@param name<string> 数据库名
|
||||
@return name<string> Unicode编码的数据库名
|
||||
'''
|
||||
name = name.replace('.','@002e')
|
||||
return name.encode("unicode_escape").replace(b"\\u",b"@").decode()
|
||||
|
||||
#删除数据库到回收站
|
||||
def DeleteToRecycleBin(self,name):
|
||||
import json
|
||||
@@ -333,11 +370,13 @@ SetLink
|
||||
panelMysql.panelMysql().execute("flush privileges")
|
||||
rPath = '/www/Recycle_bin/'
|
||||
data['rmtime'] = int(time.time())
|
||||
rm_path = '{}/BTDB_{}_t_{}'.format(rPath,name,data['rmtime'])
|
||||
u_name = self.db_name_to_unicode(name)
|
||||
rm_path = '{}/BTDB_{}_t_{}'.format(rPath,u_name,data['rmtime'])
|
||||
if os.path.exists(rm_path): rm_path += '.1'
|
||||
rm_config_file = '{}/config.json'.format(rm_path)
|
||||
datadir = public.get_datadir()
|
||||
db_path = '{}/{}'.format(datadir,name)
|
||||
|
||||
db_path = '{}/{}'.format(datadir,u_name)
|
||||
if not os.path.exists(db_path):
|
||||
return public.returnMsg(False,'Means that the database data does not exist!')
|
||||
|
||||
@@ -387,7 +426,8 @@ SetLink
|
||||
else:
|
||||
re_config_file = filename + '/config.json'
|
||||
data = json.loads(public.readFile(re_config_file))
|
||||
db_path = "{}/{}".format(public.get_datadir(),data['name'])
|
||||
u_name = self.db_name_to_unicode(data['name'])
|
||||
db_path = "{}/{}".format(public.get_datadir(),u_name)
|
||||
if os.path.exists(db_path):
|
||||
return public.returnMsg(False,'There is a database with the same name in the current database. To ensure data security, stop recovery!')
|
||||
_isdir = True
|
||||
@@ -766,7 +806,8 @@ SetLink
|
||||
return public.returnMsg(False,'SSL is not enabled in the database, please open it in the Mysql manager first')
|
||||
name = get['name']
|
||||
db_name = public.M('databases').where('username=?',(name,)).getField('name')
|
||||
access = get['access']
|
||||
access = get['access'].strip()
|
||||
if access in ['']: return public.returnMsg(False,'The IP address cannot be empty!')
|
||||
password = public.M('databases').where("username=?",(name,)).getField('password')
|
||||
mysql_obj = panelMysql.panelMysql()
|
||||
result = mysql_obj.query("show databases")
|
||||
|
||||
@@ -42,7 +42,13 @@ class FileExecuteDeny:
|
||||
if not conf:
|
||||
return False
|
||||
data = re.findall('BEGIN_DENY_.*',conf)
|
||||
deny_name = [i.split('_')[-1] for i in data]
|
||||
deny_name = []
|
||||
for i in data:
|
||||
tmp = i.split('_')
|
||||
if len(tmp) > 2:
|
||||
deny_name.append('_'.join(tmp[2:]))
|
||||
else:
|
||||
deny_name.append(tmp[-1])
|
||||
result = []
|
||||
for i in deny_name:
|
||||
reg = '#BEGIN_DENY_{}\n\s*location\s*\~\*\s*\^(.*)\.\*.*\((.*)\)\$'.format(i)
|
||||
@@ -56,7 +62,13 @@ class FileExecuteDeny:
|
||||
if not conf:
|
||||
return False
|
||||
data = re.findall('BEGIN_DENY_.*',conf)
|
||||
deny_name = [i.split('_')[-1] for i in data]
|
||||
deny_name = []
|
||||
for i in data:
|
||||
tmp = i.split('_')
|
||||
if len(tmp) > 2:
|
||||
deny_name.append('_'.join(tmp[2:]))
|
||||
else:
|
||||
deny_name.append(tmp[-1])
|
||||
result = []
|
||||
for i in deny_name:
|
||||
reg = '#BEGIN_DENY_{}\n\s*<Directory\s*\~\s*"(.*)\.\*.*\((.*)\)\$'.format(i)
|
||||
@@ -70,7 +82,13 @@ class FileExecuteDeny:
|
||||
if not conf:
|
||||
return False
|
||||
data = re.findall('BEGIN_DENY_.*',conf)
|
||||
deny_name = [i.split('_')[-1] for i in data]
|
||||
deny_name = []
|
||||
for i in data:
|
||||
tmp = i.split('_')
|
||||
if len(tmp) > 2:
|
||||
deny_name.append('_'.join(tmp[2:]))
|
||||
else:
|
||||
deny_name.append(tmp[-1])
|
||||
result = []
|
||||
for i in deny_name:
|
||||
reg = '#BEGIN_DENY_{}\n\s*rules\s*RewriteRule\s*\^(.*)\.\*.*\((.*)\)\$'.format(i)
|
||||
|
||||
@@ -197,7 +197,7 @@ class firewalls:
|
||||
types=get.type
|
||||
type_list=['tcp','udp']
|
||||
if types not in type_list:return public.returnMsg(False, 'FIREWALL_PORT_EXISTS')
|
||||
notudps = ['80', '443', '8888', '888', '39000:40000', '21', '22']
|
||||
notudps = ['80', '443', '8888', '888', '39000:40000', '21', '22', '7800']
|
||||
if port in notudps:flag=True
|
||||
#return public.M('firewall').where("port=?", (port,)).count()
|
||||
if types=='tcp':
|
||||
@@ -314,7 +314,7 @@ class firewalls:
|
||||
#return public.returnMsg(False,'演示服务器,禁止此操作!');
|
||||
port = get.port
|
||||
if int(port) < 22 or int(port) > 65535: return public.returnMsg(False,'FIREWALL_SSH_PORT_ERR');
|
||||
ports = ['21','25','80','443','8080','888','8888'];
|
||||
ports = ['21','25','80','443','8080','888','8888', '7800']
|
||||
if port in ports: return public.returnMsg(False,'');
|
||||
|
||||
file = '/etc/ssh/sshd_config'
|
||||
@@ -419,7 +419,7 @@ class firewalls:
|
||||
|
||||
if protocol not in protocol_list: return public.returnMsg(False, 'FIREWALL_PORT_EXISTS')
|
||||
|
||||
notudps = ['80', '443', '8888', '888', '39000:40000', '21', '22']
|
||||
notudps = ['80', '443', '8888', '888', '39000:40000', '21', '22','7800']
|
||||
if ports in notudps: flag = True
|
||||
|
||||
# sql 查询
|
||||
|
||||
+2
-2
@@ -141,7 +141,7 @@ class firewalls:
|
||||
ps = public.xssencode(get.ps)
|
||||
is_exists = public.M('firewall').where("port=? or port=?",(port,src_port)).count()
|
||||
if is_exists: return public.returnMsg(False,'FIREWALL_PORT_EXISTS')
|
||||
notudps = ['80','443','8888','888','39000:40000','21','22']
|
||||
notudps = ['80','443','8888','888','39000:40000','21','22','7800']
|
||||
if self.__isUfw:
|
||||
public.ExecShell('ufw allow ' + port + '/tcp')
|
||||
if not port in notudps: public.ExecShell('ufw allow ' + port + '/udp')
|
||||
@@ -255,7 +255,7 @@ class firewalls:
|
||||
def SetSshPort(self,get):
|
||||
port = get.port
|
||||
if int(port) < 22 or int(port) > 65535: return public.returnMsg(False,'FIREWALL_SSH_PORT_ERR')
|
||||
ports = ['21','25','80','443','8080','888','8888']
|
||||
ports = ['21','25','80','443','8080','888','8888','7800']
|
||||
if port in ports: return public.returnMsg(False,'DONT_USE_PORT')
|
||||
file = '/etc/ssh/sshd_config'
|
||||
conf = public.readFile(file)
|
||||
|
||||
@@ -286,9 +286,20 @@ class MemcachedSessionInterface(SessionInterface):
|
||||
session_id = self._get_signer(app).sign(want_bytes(session.sid))
|
||||
else:
|
||||
session_id = session.sid
|
||||
from BTPanel import request,g
|
||||
from BTPanel import request, g, get_input
|
||||
if 'auth_error' in g: return
|
||||
if request.path == '/': return
|
||||
if request.path in ['/', '/tips','/robots.txt']: return
|
||||
if request.path in ['/public']:
|
||||
get = get_input()
|
||||
if 'get_ping' in get: return
|
||||
if response.status_code in [401]: return
|
||||
|
||||
if request.full_path.find('/login?tmp_token=') != 0:
|
||||
if response.status_code not in [200, 308]: return
|
||||
else:
|
||||
if response.status_code not in [302, 301]: return
|
||||
if secure: samesite = 'None'
|
||||
|
||||
if response.status_code not in [200,302]: return
|
||||
if not request.cookies.get(app.session_cookie_name):
|
||||
if request.full_path.find('/login?tmp_token=') == 0:
|
||||
|
||||
@@ -94,6 +94,8 @@ class panelApi:
|
||||
return 1
|
||||
|
||||
def get_bind_status(self,args):
|
||||
if not public.cache_get("get_bind_status"):
|
||||
public.cache_set("get_bind_status",1,60)
|
||||
bind = self.get_bind_token(args.bind_token)
|
||||
return bind
|
||||
|
||||
|
||||
+10
-10
@@ -139,7 +139,7 @@ class backup:
|
||||
if not diskInfo: return '',0,0
|
||||
_root = None
|
||||
for d in diskInfo:
|
||||
if d['path'] == '/':
|
||||
if d['path'] == '/':
|
||||
_root = d
|
||||
continue
|
||||
if re.match("^{}/.+".format(d['path']),dfile):
|
||||
@@ -148,7 +148,7 @@ class backup:
|
||||
return _root['path'],float(_root['size'][2]) * 1024,int(_root['inodes'][2])
|
||||
return '',0,0
|
||||
|
||||
#备份指定目录
|
||||
#备份指定目录
|
||||
def backup_path(self,spath,dfile = None,exclude=[],save=3):
|
||||
|
||||
error_msg = ""
|
||||
@@ -166,7 +166,7 @@ class backup:
|
||||
if not dfile:
|
||||
fname = 'path_{}_{}.tar.gz'.format(dirname,public.format_date("%Y%m%d_%H%M%S"))
|
||||
dfile = os.path.join(self._path,'path',fname)
|
||||
|
||||
|
||||
if not self.backup_path_to(spath,dfile,exclude):
|
||||
if self._error_msg:
|
||||
error_msg = self._error_msg
|
||||
@@ -241,7 +241,7 @@ class backup:
|
||||
self.echo_end()
|
||||
return dfile
|
||||
|
||||
|
||||
|
||||
#清理过期备份文件
|
||||
def delete_old(self,backups,save,data_type = None):
|
||||
if type(backups) == str:
|
||||
@@ -299,13 +299,13 @@ class backup:
|
||||
p_size = public.get_path_size(spath, exclude=exclude_list)
|
||||
if not self._exclude:
|
||||
exclude_config = "Not set"
|
||||
|
||||
|
||||
if siteName:
|
||||
self.echo_info(public.getMsg('BACKUP_SITE',(siteName,)))
|
||||
self.echo_info(public.getMsg('WEBSITE_DIR',(spath,)))
|
||||
else:
|
||||
self.echo_info(public.getMsg('BACKUP_DIR',(spath,)))
|
||||
|
||||
|
||||
self.echo_info(public.getMsg(
|
||||
"DIR_SIZE",
|
||||
(str(public.to_size(p_size),))
|
||||
@@ -513,7 +513,7 @@ class backup:
|
||||
dfile = os.path.join(self._path,'database',fname)
|
||||
else:
|
||||
fname = os.path.basename(dfile)
|
||||
|
||||
|
||||
dpath = os.path.dirname(dfile)
|
||||
if not os.path.exists(dpath):
|
||||
os.makedirs(dpath,384)
|
||||
@@ -529,7 +529,7 @@ class backup:
|
||||
self.echo_error(error_msg)
|
||||
self.send_failture_notification(error_msg)
|
||||
return False
|
||||
|
||||
|
||||
if p_size == None:
|
||||
error_msg = public.getMsg('DB_BACKUP_ERR',(db_name,))
|
||||
self.echo_error(error_msg)
|
||||
@@ -561,7 +561,7 @@ class backup:
|
||||
self.echo_error(error_msg)
|
||||
self.send_failture_notification(error_msg)
|
||||
return False
|
||||
|
||||
|
||||
stime = time.time()
|
||||
self.echo_info(public.getMsg("EXPORT_DB",(public.format_date(times=stime),)))
|
||||
if os.path.exists(dfile):
|
||||
@@ -877,4 +877,4 @@ class backup:
|
||||
print(e)
|
||||
return False
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -535,7 +535,7 @@ class Dns_com(object):
|
||||
pass
|
||||
|
||||
def get_dns_obj(self):
|
||||
p_path = '/www/server/panel/plugin/dns'
|
||||
p_path = '/www/server/panel/plugin/model'
|
||||
if not os.path.exists(p_path +'/dns_main.py'): return None
|
||||
sys.path.insert(0,p_path)
|
||||
import dns_main
|
||||
|
||||
+1
-1
@@ -601,7 +601,7 @@ class FPM(object):
|
||||
'DOCUMENT_ROOT': self.document_root,
|
||||
'SERVER_PROTOCOL' : 'HTTP/1.1',
|
||||
'REMOTE_ADDR': '127.0.0.1',
|
||||
'REMOTE_PORT': '8888',
|
||||
'REMOTE_PORT': '7800',
|
||||
'SERVER_ADDR': '127.0.0.1',
|
||||
'SERVER_PORT': '80',
|
||||
'SERVER_NAME': 'BT-Panel'
|
||||
|
||||
+78
-67
@@ -159,6 +159,9 @@ class panelPlugin:
|
||||
def install_plugin(self,get):
|
||||
if not self.check_sys_write(): return public.returnMsg(False,'CANT_WRITE_SYS_DIR')
|
||||
if not 'sName' in get: return public.returnMsg(False,'Please specify the software name!')
|
||||
#处理ols还不支持php81的情况
|
||||
if get.sName == "php-8.1" and public.get_webserver() == 'openlitespeed':
|
||||
return public.returnMsg(False, 'Sorry, currently OLS official does not support php8.1')
|
||||
pluginInfo = self.get_soft_find(get.sName)
|
||||
get.pluginInfo = pluginInfo
|
||||
check_result = self.check_install_limit(get)
|
||||
@@ -314,81 +317,89 @@ class panelPlugin:
|
||||
|
||||
#从云端取列表
|
||||
def get_cloud_list(self,get=None):
|
||||
lcoalTmp = 'data/plugin.json'
|
||||
softList = None
|
||||
listTmp = public.readFile(lcoalTmp)
|
||||
try:
|
||||
if listTmp: softList = json.loads(listTmp)
|
||||
except:
|
||||
if os.path.exists(lcoalTmp): os.remove(lcoalTmp)
|
||||
lcoalTmp = 'data/plugin.json'
|
||||
softList = None
|
||||
listTmp = public.readFile(lcoalTmp)
|
||||
force_refresh = 0
|
||||
try:
|
||||
if listTmp: softList = json.loads(listTmp)
|
||||
if 'success' in softList and not softList['success']:
|
||||
if os.path.exists(lcoalTmp): os.remove(lcoalTmp)
|
||||
force_refresh = 1
|
||||
except:
|
||||
if os.path.exists(lcoalTmp): os.remove(lcoalTmp)
|
||||
|
||||
if 'init' in get:
|
||||
if softList:
|
||||
if 'success' not in softList:
|
||||
return softList
|
||||
if 'init' in get:
|
||||
if softList:
|
||||
if 'success' not in softList:
|
||||
return softList
|
||||
|
||||
focre = 0
|
||||
if hasattr(get,'force'): focre = int(get.force)
|
||||
if 'focre_cloud' in session:
|
||||
if session['focre_cloud']:
|
||||
focre = 1
|
||||
session['focre_cloud'] = False
|
||||
focre = 0
|
||||
if hasattr(get,'force'): focre = int(get.force)
|
||||
if 'focre_cloud' in session:
|
||||
if session['focre_cloud']:
|
||||
focre = 1
|
||||
session['focre_cloud'] = False
|
||||
|
||||
if not 'init_cloud' in session:
|
||||
if not 'init_cloud' in session:
|
||||
focre = 1
|
||||
session['init_cloud'] = True
|
||||
|
||||
if not softList or focre > 0:
|
||||
self.clean_panel_log()
|
||||
# cloudUrl = 'https://console.aapanel.com/api/panel/get_soft_list'
|
||||
cloudUrl = '{}/api/panel/getSoftList'.format(self.__official_url)
|
||||
import panelAuth
|
||||
import requests
|
||||
pdata = panelAuth.panelAuth().create_serverid(None)
|
||||
# listTmp = public.httpPost(cloudUrl,pdata,6)
|
||||
url_headers={}
|
||||
if 'token' in pdata:
|
||||
url_headers = {"authorization": "bt {}".format(pdata['token'])}
|
||||
pdata['environment_info'] = json.dumps(public.fetch_env_info())
|
||||
listTmp = requests.post(cloudUrl, params=pdata, headers=url_headers,verify=False)
|
||||
listTmp=listTmp.json()
|
||||
if not listTmp:
|
||||
listTmp = public.readFile(lcoalTmp)
|
||||
if force_refresh == 1:
|
||||
focre = 1
|
||||
if not softList or focre > 0:
|
||||
self.clean_panel_log()
|
||||
# cloudUrl = 'https://console.aapanel.com/api/panel/get_soft_list'
|
||||
cloudUrl = '{}/api/panel/getSoftList'.format(self.__official_url)
|
||||
import panelAuth
|
||||
import requests
|
||||
pdata = panelAuth.panelAuth().create_serverid(None)
|
||||
# listTmp = public.httpPost(cloudUrl,pdata,6)
|
||||
url_headers={}
|
||||
if 'token' in pdata:
|
||||
url_headers = {"authorization": "bt {}".format(pdata['token'])}
|
||||
pdata['environment_info'] = json.dumps(public.fetch_env_info())
|
||||
listTmp = requests.post(cloudUrl, params=pdata, headers=url_headers,verify=False)
|
||||
listTmp=listTmp.json()
|
||||
if not listTmp:
|
||||
listTmp = public.readFile(lcoalTmp)
|
||||
try:
|
||||
softList = listTmp
|
||||
except: pass
|
||||
if softList: public.writeFile(lcoalTmp,json.dumps(softList))
|
||||
public.ExecShell('rm -f /tmp/bmac_*')
|
||||
public.run_thread(self.getCloudPHPExt)
|
||||
# 专业版和企业版到期提醒,aaPanel目前没有先注释
|
||||
# self.expire_msg(softList)
|
||||
try:
|
||||
softList = listTmp
|
||||
except: pass
|
||||
if softList: public.writeFile(lcoalTmp,json.dumps(softList))
|
||||
public.ExecShell('rm -f /tmp/bmac_*')
|
||||
public.run_thread(self.getCloudPHPExt)
|
||||
# 专业版和企业版到期提醒,aaPanel目前没有先注释
|
||||
# self.expire_msg(softList)
|
||||
try:
|
||||
public.writeFile("/tmp/" + cache.get('p_token'),str(softList['pro']))
|
||||
except:pass
|
||||
sType = 0
|
||||
try:
|
||||
if hasattr(get,'type'): sType = int(get['type'])
|
||||
public.writeFile("/tmp/" + cache.get('p_token'),str(softList['pro']))
|
||||
except:pass
|
||||
sType = 0
|
||||
try:
|
||||
if hasattr(get,'type'): sType = int(get['type'])
|
||||
if hasattr(get,'query'):
|
||||
if get.query: sType = 0
|
||||
except:pass
|
||||
softList['list'] = self.get_local_plugin(softList['list'])
|
||||
softList['list'] = self.get_types(softList['list'],sType)
|
||||
if hasattr(get,'query'):
|
||||
if get.query: sType = 0
|
||||
except:pass
|
||||
softList['list'] = self.get_local_plugin(softList['list'])
|
||||
softList['list'] = self.get_types(softList['list'],sType)
|
||||
if hasattr(get,'query'):
|
||||
if get.query:
|
||||
get.query = get.query.lower()
|
||||
tmpList = []
|
||||
for softInfo in softList['list']:
|
||||
if softInfo['name'].lower().find(get.query) != -1 or \
|
||||
softInfo['title'].lower().find(get.query) != -1 or \
|
||||
softInfo['ps'].lower().find(get.query) != -1:
|
||||
tmpList.append(softInfo)
|
||||
softList['list'] = tmpList
|
||||
for softInfo in softList['list']:
|
||||
if 'uninsatll_checks' not in softInfo:
|
||||
softInfo['uninsatll_checks'] = softInfo['uninstall_checks']
|
||||
if not softList['list']:
|
||||
if os.path.exists(lcoalTmp): os.remove(lcoalTmp)
|
||||
return softList
|
||||
if get.query:
|
||||
get.query = get.query.lower()
|
||||
tmpList = []
|
||||
for softInfo in softList['list']:
|
||||
if softInfo['name'].lower().find(get.query) != -1 or \
|
||||
softInfo['title'].lower().find(get.query) != -1 or \
|
||||
softInfo['ps'].lower().find(get.query) != -1:
|
||||
tmpList.append(softInfo)
|
||||
softList['list'] = tmpList
|
||||
for softInfo in softList['list']:
|
||||
if 'uninsatll_checks' not in softInfo:
|
||||
softInfo['uninsatll_checks'] = softInfo['uninstall_checks']
|
||||
if not softList['list']:
|
||||
if os.path.exists(lcoalTmp): os.remove(lcoalTmp)
|
||||
return softList
|
||||
except:
|
||||
pass
|
||||
|
||||
#取提醒标记
|
||||
def get_level_msg(self,level,s_time,endtime):
|
||||
|
||||
@@ -359,7 +359,8 @@ class panelRedirect:
|
||||
self.SetRedirect(get)
|
||||
self.SetRedirectNginx(get)
|
||||
self.SetRedirectApache(get.sitename)
|
||||
public.serviceReload()
|
||||
if not hasattr(get,'notreload'):
|
||||
public.serviceReload()
|
||||
return public.returnMsg(True, 'EDIT_SUCCESS')
|
||||
|
||||
def del_redirect_multiple(self,get):
|
||||
|
||||
@@ -0,0 +1,388 @@
|
||||
#coding: utf-8
|
||||
#-------------------------------------------------------------------
|
||||
# 宝塔Linux面板
|
||||
#-------------------------------------------------------------------
|
||||
# Copyright (c) 2015-2099 宝塔软件(http:#bt.cn) All rights reserved.
|
||||
#-------------------------------------------------------------------
|
||||
# Author: hwliang <hwl@bt.cn>
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
#------------------------------
|
||||
# 开机自启模块
|
||||
#------------------------------
|
||||
|
||||
import os,sys,time,json,psutil,re
|
||||
import public
|
||||
import signal
|
||||
|
||||
class panelRun:
|
||||
__panel_path = public.get_panel_path()
|
||||
__run_config_path = '{}/config/run_config'.format(__panel_path)
|
||||
__run_pids_path = '{}/logs/run_pids'.format(__panel_path)
|
||||
__run_logs_path = '{}/logs/run_logs'.format(__panel_path)
|
||||
__log_name = '开机启动项'
|
||||
|
||||
|
||||
def __init__(self):
|
||||
if not os.path.exists(self.__run_config_path):
|
||||
os.makedirs(self.__run_config_path)
|
||||
if not os.path.exists(self.__run_pids_path):
|
||||
os.makedirs(self.__run_pids_path)
|
||||
|
||||
def get_run_list(self,get):
|
||||
'''
|
||||
@name 获取启动配置列表
|
||||
@author hwliang<2021-08-06>
|
||||
@param get<dict_obj>{
|
||||
run_type: string<启动类型>
|
||||
}
|
||||
@return list
|
||||
'''
|
||||
run_type = None
|
||||
if 'run_type' in get:
|
||||
run_type = get['run_type']
|
||||
run_list = []
|
||||
for run_name in os.listdir(self.__run_config_path):
|
||||
run_file = '{}/{}'.format(self.__run_config_path,run_name)
|
||||
if not os.path.isfile(run_file):
|
||||
continue
|
||||
|
||||
run_info = json.loads(public.readFile(run_file))
|
||||
if run_type:
|
||||
if run_info['run_type'] != run_type: continue
|
||||
|
||||
|
||||
run_list.append(run_info)
|
||||
|
||||
return run_list
|
||||
|
||||
|
||||
def get_run_info(self,get = None,run_name = None):
|
||||
'''
|
||||
@name 获取启动配置信息
|
||||
@author hwliang<2021-08-06>
|
||||
@param get<dict_obj>{
|
||||
run_name: string<启动项名称>
|
||||
}
|
||||
@return dict
|
||||
'''
|
||||
if get: run_name = get['run_name']
|
||||
run_file = '{}/{}'.format(self.__run_config_path,run_name)
|
||||
if not os.path.isfile(run_file):
|
||||
return public.returnMsg(False,'启动配置不存在!')
|
||||
|
||||
run_info = json.loads(public.readFile(run_file))
|
||||
return run_info
|
||||
|
||||
|
||||
def create_run(self,get):
|
||||
'''
|
||||
@name 创建启动配置
|
||||
@author hwliang<2021-08-06>
|
||||
@param get<dict_obj>{
|
||||
run_title: string<启动项显示标题>
|
||||
run_name: string<启动项名称> 格式:\w
|
||||
run_type: string<启动类型> python shell php node java等,也可以是一个可执行文件的路径 或直接为空
|
||||
run_path: string<运行目录>
|
||||
run_script: string<启动脚本>
|
||||
run_script_args: string<启动脚本参数>
|
||||
run_env: list<启动环境变量>
|
||||
}
|
||||
@return dict
|
||||
'''
|
||||
run_name = get['run_name']
|
||||
run_title = get['run_title']
|
||||
run_type = get['run_type']
|
||||
run_path = get['run_path']
|
||||
run_script = get['run_script']
|
||||
run_script_args = get['run_script_args']
|
||||
run_env = json.loads(get['run_env'])
|
||||
if not os.path.exists(run_path):
|
||||
return public.returnMsg(False,'指定运行目录{}不存在!'.format(run_path))
|
||||
|
||||
if not re.match(r'^\w+$',run_name):
|
||||
return public.returnMsg(False, '启动项名称格式不正确,支持:[a-zA-Z0-9_]!')
|
||||
|
||||
run_file = '{}/{}'.format(self.__run_config_path,run_name)
|
||||
if os.path.exists(run_file):
|
||||
return public.returnMsg(False,'启动配置已存在!')
|
||||
|
||||
run_info = {
|
||||
'run_title': run_title,
|
||||
'run_name': run_name,
|
||||
'run_path': run_path,
|
||||
'run_script': run_script,
|
||||
'run_env':run_env,
|
||||
'run_status': 1
|
||||
}
|
||||
run_info = json.dumps(run_info)
|
||||
public.writeFile(run_file,run_info)
|
||||
public.WriteLog(self.__log_name,'创建启动项[]成功!'.format(run_title))
|
||||
return public.returnMsg(True,'创建成功!')
|
||||
|
||||
|
||||
def modify_run(self,get):
|
||||
'''
|
||||
@name 修改启动配置
|
||||
@author hwliang<2021-08-06>
|
||||
@param get<dict_obj>{
|
||||
run_name: string<启动项名称>
|
||||
run_title: string<启动项显示标题>
|
||||
run_type: string<启动类型>
|
||||
run_path: string<启动路径>
|
||||
run_script: string<启动脚本>
|
||||
run_script_args: string<启动脚本参数>
|
||||
}
|
||||
@return dict
|
||||
'''
|
||||
|
||||
run_name = get['run_name']
|
||||
run_title = get['run_title']
|
||||
run_type = get['run_type']
|
||||
run_path = get['run_path']
|
||||
run_script = get['run_script']
|
||||
run_script_args = get['run_script_args']
|
||||
run_env = json.loads(get['run_env'])
|
||||
|
||||
if not os.path.exists(run_path):
|
||||
return public.returnMsg(False,'指定运行目录{}不存在!'.format(run_path))
|
||||
|
||||
if not re.match(r'^\w+$',run_name):
|
||||
return public.returnMsg(False, '启动项名称格式不正确,支持:[a-zA-Z0-9_]!')
|
||||
|
||||
|
||||
run_file = '{}/{}'.format(self.__run_config_path,run_name)
|
||||
if not os.path.exists(run_file):
|
||||
return public.returnMsg(False,'启动配置不存在!')
|
||||
|
||||
run_info = json.loads(public.readFile(run_file))
|
||||
run_info['run_title'] = run_title
|
||||
run_info['run_path'] = run_path
|
||||
run_info['run_script'] = run_script
|
||||
run_info['run_env'] = run_env
|
||||
run_info = json.dumps(run_info)
|
||||
public.writeFile(run_file,run_info)
|
||||
public.WriteLog(self.__log_name,'修改启动项[]成功!'.format(run_title))
|
||||
return public.returnMsg(True,'修改成功!')
|
||||
|
||||
|
||||
def remove_run(self,get):
|
||||
'''
|
||||
@name 删除启动配置
|
||||
@author hwliang<2021-08-06>
|
||||
@param get<dict_obj>{
|
||||
run_name: string<启动项名称>
|
||||
}
|
||||
@return dict
|
||||
'''
|
||||
run_name = get['run_name']
|
||||
run_file = '{}/{}'.format(self.__run_config_path,run_name)
|
||||
if not os.path.isfile(run_file):
|
||||
return public.returnMsg(False,'启动配置不存在!')
|
||||
|
||||
os.remove(run_file)
|
||||
public.WriteLog(self.__log_name,'删除启动项[]成功!'.format(run_name))
|
||||
return public.returnMsg(True,'删除成功!')
|
||||
|
||||
def set_run_status(self,get):
|
||||
'''
|
||||
@name 设置启动项状态
|
||||
@author hwliang<2021-08-06>
|
||||
@param get<dict_obj>{
|
||||
run_name: string<启动项名称>
|
||||
run_status: int<启动项状态>
|
||||
}
|
||||
@return dict
|
||||
'''
|
||||
run_name = get['run_name']
|
||||
run_status = get['run_status']
|
||||
|
||||
run_file = '{}/{}'.format(self.__run_config_path,run_name)
|
||||
if not os.path.isfile(run_file):
|
||||
return public.returnMsg(False,'启动配置不存在!')
|
||||
|
||||
run_info = json.loads(public.readFile(run_file))
|
||||
run_info['run_status'] = run_status
|
||||
run_info = json.dumps(run_info)
|
||||
public.writeFile(run_file,run_info)
|
||||
public.WriteLog(self.__log_name,'设置启动项[]状态成功!'.format(run_info['title']))
|
||||
return public.returnMsg(True,'设置成功!')
|
||||
|
||||
|
||||
def stop_run(self,run_name = None):
|
||||
'''
|
||||
@name 关闭启动进程
|
||||
@author hwliang<2021-08-06>
|
||||
@param run_name: string<启动项名称>
|
||||
@return dict
|
||||
'''
|
||||
pid = self.get_run_pid(run_name)
|
||||
if not pid: return True
|
||||
os.kill(pid,signal.SIGKILL)
|
||||
public.WriteLog(self.__log_name,'关闭启动项[]成功!'.format(run_name))
|
||||
return True
|
||||
|
||||
|
||||
def pid_exists(self,pid):
|
||||
'''
|
||||
@name 检测PID是否存在
|
||||
@author hwliang<2021-08-06>
|
||||
@param pid int<PID>
|
||||
@return bool
|
||||
'''
|
||||
if not isinstance(pid,int):
|
||||
pid = int(pid)
|
||||
if pid == 0:
|
||||
return True
|
||||
if not os.path.exists('/proc/{}'.format(pid)):
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def get_run_pid(self,run_name):
|
||||
'''
|
||||
@name 获取启动项PID
|
||||
@author hwliang<2021-08-06>
|
||||
@param run_name string<启动项名称>
|
||||
@return dict
|
||||
'''
|
||||
pid_file = '{}/{}.pid'.format(self.__run_pids_path,run_name)
|
||||
if not os.path.exists(pid_file):
|
||||
return None
|
||||
|
||||
run_pid = int(public.readFile(pid_file))
|
||||
if run_pid is 0:
|
||||
return None
|
||||
|
||||
if not self.pid_exists(run_pid):
|
||||
return None
|
||||
return run_pid
|
||||
|
||||
|
||||
def get_run_status(self,run_name):
|
||||
'''
|
||||
@name 获取启动项状态
|
||||
@author hwliang<2021-08-06>
|
||||
@param run_name string<启动项名称>
|
||||
@return dict
|
||||
'''
|
||||
pid = self.get_run_pid(run_name)
|
||||
if not pid: return public.returnMsg(False,'未启动')
|
||||
process_info = self.get_process_info(pid)
|
||||
if not process_info: return public.returnMsg(False,'无法获取进程信息')
|
||||
return process_info
|
||||
|
||||
def get_process_info(self,pid):
|
||||
'''
|
||||
@name 获取进程信息
|
||||
@author hwliang<2021-08-06>
|
||||
@param pid int<PID>
|
||||
@return dict
|
||||
'''
|
||||
process_info = {}
|
||||
p = psutil.Process(pid)
|
||||
status_ps = {'sleeping':'睡眠','running':'活动'}
|
||||
with p.oneshot():
|
||||
p_mem = p.memory_full_info()
|
||||
if p_mem.uss + p_mem.rss + p_mem.pss + p_mem.data == 0: return False
|
||||
pio = p.io_counters()
|
||||
p_cpus= p.cpu_times()
|
||||
p_state = p.status()
|
||||
if p_state in status_ps: p_state = status_ps[p_state]
|
||||
process_info['exe'] = p.exe()
|
||||
process_info['name'] = p.name()
|
||||
process_info['pid'] = pid
|
||||
process_info['ppid'] = p.ppid()
|
||||
process_info['create_time'] = int(p.create_time())
|
||||
process_info['status'] = p_state
|
||||
process_info['user'] = p.username()
|
||||
process_info['memory_used'] = p_mem.uss
|
||||
# process_info['cpu_percent'] = self.get_cpu_percent(str(pid),p_cpus,self.new_info['cpu_time'])
|
||||
process_info['io_write_bytes'] = pio.write_bytes
|
||||
process_info['io_read_bytes'] = pio.read_bytes
|
||||
# process_info['io_write_speed'] = self.get_io_write(str(pid),pio.write_bytes)
|
||||
# process_info['io_read_speed'] = self.get_io_read(str(pid),pio.read_bytes)
|
||||
process_info['connects'] = self.get_connects(pid)
|
||||
process_info['threads'] = p.num_threads()
|
||||
return process_info
|
||||
|
||||
|
||||
def get_connects(self,pid):
|
||||
'''
|
||||
@name 获取进程连接数
|
||||
@author hwliang<2021-08-06>
|
||||
@param pid int<PID>
|
||||
@return dict
|
||||
'''
|
||||
connects = 0
|
||||
if pid == 1: return connects
|
||||
tp = '/proc/' + str(pid) + '/fd/'
|
||||
if not os.path.exists(tp): return connects
|
||||
for d in os.listdir(tp):
|
||||
fname = tp + d
|
||||
if os.path.islink(fname):
|
||||
l = os.readlink(fname)
|
||||
if l.find('socket:') != -1: connects += 1
|
||||
return connects
|
||||
|
||||
def is_run(self,run_name):
|
||||
'''
|
||||
@name 检测启动项是否在运行
|
||||
@author hwliang<2021-08-06>
|
||||
@param run_name string<启动项名称>
|
||||
@return bool
|
||||
'''
|
||||
pid = self.get_run_pid(run_name)
|
||||
if not pid: return False
|
||||
return True
|
||||
|
||||
|
||||
def get_script_pid(self,run_info):
|
||||
'''
|
||||
@name 获取脚本进程PID
|
||||
@author hwliang<2021-08-06>
|
||||
@param run_info dict<脚本文件路径>
|
||||
@return int<PID>
|
||||
'''
|
||||
script_last = run_info['run_script'].split(' ')[0]
|
||||
for pid in psutil.pids():
|
||||
p = psutil.Process(pid)
|
||||
if p.exe() == script_last and p.cwd() == run_info['run_path']:
|
||||
return pid
|
||||
return None
|
||||
|
||||
|
||||
def start_run(self,run_name):
|
||||
'''
|
||||
@name 启动指定启动项
|
||||
@author hwliang<2021-08-06>
|
||||
@param run_name string<启动项名称>
|
||||
@return bool
|
||||
'''
|
||||
run_info = self.get_run_info(run_name)
|
||||
if not run_info: return False
|
||||
|
||||
log_file = '{}/{}.log'.format(self.__run_logs_path,run_name)
|
||||
pid_file = '{}/{}.pid'.format(self.__run_pids_path,run_name)
|
||||
public.ExecShell("nohup {} 2>&1 >> {} & $! > {}".format(run_info['run_script'],log_file,pid_file),cwd=run_info['run_path'],env=run_info['run_env'])[0]
|
||||
time.sleep(1)
|
||||
pid = self.get_script_pid(run_info)
|
||||
public.writeFile(pid_file,str(pid))
|
||||
public.WriteLog(self.__log_name, '开机启动{}成功, PID: {}'.format(run_name,pid))
|
||||
return True
|
||||
|
||||
|
||||
def start(self):
|
||||
'''
|
||||
@name 启动所有启动项
|
||||
@author hwliang<2021-08-06>
|
||||
@param
|
||||
@return bool
|
||||
'''
|
||||
run_list = self.get_run_list(public.dict_obj())
|
||||
for run_name in run_list:
|
||||
if not self.is_run(run_name):
|
||||
self.start_run(run_name)
|
||||
return True
|
||||
|
||||
|
||||
+8
-1
@@ -736,6 +736,10 @@ class panelSSL:
|
||||
if iss[0] in is_key:
|
||||
result['issuer'] = iss[1].decode()
|
||||
break
|
||||
if not result['issuer']:
|
||||
if hasattr(issuer, 'O'):
|
||||
result['issuer'] = issuer.O
|
||||
|
||||
# 取到期时间
|
||||
result['notAfter'] = self.strf_date(
|
||||
bytes.decode(x509.get_notAfter())[:-1])
|
||||
@@ -760,7 +764,10 @@ class panelSSL:
|
||||
if sub[0] == b'CN':
|
||||
result['subject'] = sub[1].decode()
|
||||
break
|
||||
result['dns'].append(result['subject'])
|
||||
# result['dns'].append(result['subject'])
|
||||
if 'subject' in result:
|
||||
result['dns'].append(result['subject'])
|
||||
|
||||
else:
|
||||
result['subject'] = result['dns'][0]
|
||||
return result
|
||||
|
||||
+8
-5
@@ -1890,7 +1890,8 @@ listener SSL443 {
|
||||
import firewalls
|
||||
get.port = '443'
|
||||
get.ps = 'HTTPS'
|
||||
firewalls.firewalls().AddAcceptPort(get)
|
||||
if not public.M('firewall').where('port=?', ('443',)).count():
|
||||
firewalls.firewalls().AddAcceptPort(get)
|
||||
public.serviceReload()
|
||||
self.save_cert(get)
|
||||
public.WriteLog('TYPE_SITE', 'SITE_SSL_OPEN_SUCCESS', (siteName,))
|
||||
@@ -2974,13 +2975,13 @@ server
|
||||
|
||||
#取当前可用PHP版本
|
||||
def GetPHPVersion(self,get):
|
||||
phpVersions = ('00','other','52','53','54','55','56','70','71','72','73','74','80')
|
||||
phpVersions = ('00','other','52','53','54','55','56','70','71','72','73','74','80','81')
|
||||
httpdVersion = ""
|
||||
filename = self.setupPath + '/apache/version.pl'
|
||||
if os.path.exists(filename): httpdVersion = public.readFile(filename).strip()
|
||||
|
||||
if httpdVersion == '2.2': phpVersions = ('00','52','53','54')
|
||||
if httpdVersion == '2.4': phpVersions = ('00','other','53','54','55','56','70','71','72','73','74','80')
|
||||
if httpdVersion == '2.4': phpVersions = ('00','other','53','54','55','56','70','71','72','73','74','80','81')
|
||||
if os.path.exists('/www/server/nginx/sbin/nginx'):
|
||||
cfile = '/www/server/nginx/conf/enable-php-00.conf'
|
||||
if not os.path.exists(cfile): public.writeFile(cfile,'')
|
||||
@@ -3647,7 +3648,8 @@ RewriteRule ^%s(.*)$ http://%s/$1 [P,E=Proxy-Host:%s]
|
||||
if public.get_webserver() == 'nginx':
|
||||
if self.CheckLocation(get):
|
||||
return self.CheckLocation(get)
|
||||
|
||||
if not get.proxysite.split('//')[-1]:
|
||||
return public.returnMsg(False, 'The target URL cannot be [http:// or https://], please fill in the full URL, such as: https://aapanel.com')
|
||||
proxyUrl = self.__read_config(self.__proxyfile)
|
||||
proxyUrl.append({
|
||||
"proxyname": get.proxyname,
|
||||
@@ -3890,7 +3892,8 @@ RewriteRule ^%s(.*)$ http://%s/$1 [P,E=Proxy-Host:%s]
|
||||
# if int(get.type) != 1:
|
||||
# os.system("mv %s %s_bak" % (ap_conf_file, ap_conf_file))
|
||||
# os.system("mv %s %s_bak" % (ng_conf_file, ng_conf_file))
|
||||
public.serviceReload()
|
||||
if not hasattr(get, 'notreload'):
|
||||
public.serviceReload()
|
||||
return public.returnMsg(True, 'EDIT_SUCCESS')
|
||||
|
||||
# 设置反向代理
|
||||
|
||||
+27
-22
@@ -613,7 +613,7 @@ def GetHost(port = False):
|
||||
try:
|
||||
if host_tmp.find(':') == -1: host_tmp += ':80'
|
||||
except:
|
||||
host_tmp = "127.0.0.1:8888"
|
||||
host_tmp = "127.0.0.1:7800"
|
||||
h = host_tmp.split(':')
|
||||
if port: return h[-1]
|
||||
if len(h) > 2:
|
||||
@@ -621,9 +621,15 @@ def GetHost(port = False):
|
||||
return h
|
||||
return h[0]
|
||||
|
||||
|
||||
|
||||
|
||||
def GetClientIp():
|
||||
from flask import request
|
||||
return request.remote_addr.replace('::ffff:', '')
|
||||
ipaddr = request.remote_addr.replace('::ffff:','')
|
||||
if not check_ip(ipaddr): return '未知IP地址'
|
||||
return ipaddr
|
||||
|
||||
|
||||
def get_client_ip():
|
||||
return GetClientIp()
|
||||
@@ -1044,7 +1050,7 @@ def checkIp(ip):
|
||||
#检查端口是否合法
|
||||
def checkPort(port):
|
||||
if not re.match("^\d+$",port): return False
|
||||
ports = ['21','25','443','8080','888','8888','8443']
|
||||
ports = ['21','25','443','8080','888','8888','8443','7800']
|
||||
if port in ports: return False
|
||||
intport = int(port)
|
||||
if intport < 1 or intport > 65535: return False
|
||||
@@ -1254,7 +1260,7 @@ def CheckPort(port,other=None):
|
||||
if type(port) == str: port = int(port)
|
||||
if port < 1 or port > 65535: return False
|
||||
if other:
|
||||
checks = [22, 20, 21, 8888, 3306, 11211, 888, 25]
|
||||
checks = [22, 20, 21, 8888, 3306, 11211, 888, 25,7800]
|
||||
if port in checks: return False
|
||||
return True
|
||||
|
||||
@@ -1823,12 +1829,12 @@ def check_ip_panel():
|
||||
for limit_ip in iplong_list:
|
||||
if client_ip_long >= limit_ip['min'] and client_ip_long <= limit_ip['max']:
|
||||
return False
|
||||
|
||||
errorStr = ReadFile('./BTPanel/templates/' + GetConfigValue('template') + '/error2.html')
|
||||
try:
|
||||
errorStr = errorStr.format(getMsg('PAGE_ERR_TITLE'),getMsg('PAGE_ERR_IP_H1'),getMsg('PAGE_ERR_IP_P1',(GetClientIp(),)),getMsg('PAGE_ERR_IP_P2'),getMsg('PAGE_ERR_IP_P3'),getMsg('NAME'),getMsg('PAGE_ERR_HELP'))
|
||||
except IndexError:pass
|
||||
return errorStr
|
||||
return 404
|
||||
# errorStr = ReadFile('./BTPanel/templates/' + GetConfigValue('template') + '/error2.html')
|
||||
# try:
|
||||
# errorStr = errorStr.format(getMsg('PAGE_ERR_TITLE'),getMsg('PAGE_ERR_IP_H1'),getMsg('PAGE_ERR_IP_P1',(GetClientIp(),)),getMsg('PAGE_ERR_IP_P2'),getMsg('PAGE_ERR_IP_P3'),getMsg('NAME'),getMsg('PAGE_ERR_HELP'))
|
||||
# except IndexError:pass
|
||||
# return errorStr
|
||||
|
||||
#检查面板域名
|
||||
def check_domain_panel():
|
||||
@@ -1838,11 +1844,12 @@ def check_domain_panel():
|
||||
client_ip = GetClientIp()
|
||||
if client_ip in ['127.0.0.1','localhost','::1']: return False
|
||||
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:pass
|
||||
return errorStr
|
||||
return 404
|
||||
# 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:pass
|
||||
# return errorStr
|
||||
return False
|
||||
|
||||
#是否离线模式
|
||||
@@ -3054,13 +3061,8 @@ def check_app(check='app'):
|
||||
path=get_panel_path() + '/'
|
||||
if check=='app':
|
||||
try:
|
||||
if not os.path.exists(path+'data/user.json') and os.path.exists(path+'config/api.json') and not os.path.exists(path+'plugin/app/user.json'):return False
|
||||
if os.path.exists(path+'plugin/app/user.json'):
|
||||
wxapp = json.loads(readFile(path+'plugin/app/user.json'))
|
||||
if wxapp:return True
|
||||
if os.path.exists(path+'data/user.json'):
|
||||
app_info = json.loads(readFile(path+'data/user.json'))
|
||||
if app_info:return True
|
||||
if not os.path.exists("/www/server/panel/plugin/btapp/btapp_main.py"): return False
|
||||
if not os.path.exists(path+'config/api.json'):return False
|
||||
if os.path.exists(path+'config/api.json'):
|
||||
btapp_info = json.loads(readFile(path+'config/api.json'))
|
||||
if not btapp_info['open']:return False
|
||||
@@ -3071,6 +3073,8 @@ def check_app(check='app'):
|
||||
except:
|
||||
return False
|
||||
elif check=='app_bind':
|
||||
if not cache_get('get_bind_status'):return False
|
||||
if not os.path.exists("/www/server/panel/plugin/btapp/btapp_main.py"):return False
|
||||
if not os.path.exists(path + 'config/api.json'):return False
|
||||
btapp_info = json.loads(readFile(path +'config/api.json'))
|
||||
if not btapp_info: return False
|
||||
@@ -3082,6 +3086,7 @@ def check_app(check='app'):
|
||||
if not app_info: return False
|
||||
return True
|
||||
|
||||
|
||||
#宝塔邮件报警
|
||||
def send_mail(title,body,is_logs=False,is_type="aapanel login reminder"):
|
||||
if is_logs:
|
||||
|
||||
@@ -37,7 +37,7 @@ def check_run():
|
||||
'''
|
||||
|
||||
if public.M('crontab').where('sType=? AND sName=?',('database','ALL')).count():
|
||||
return True,'无风险'
|
||||
return True,'Risk-free'
|
||||
|
||||
db_list = public.M('databases').field('name').select()
|
||||
|
||||
|
||||
@@ -63,4 +63,4 @@ def check_run():
|
||||
return True,'Fail2ban is enabled'
|
||||
except: pass
|
||||
|
||||
return False,'当前MySQL端口: {},可被任意服务器访问,这可能导致MySQL被暴力破解,存在安全隐患'.format(port_tmp[0])
|
||||
return False,'MySQL port: {}, can be accessed by any server, which may cause MySQL to be cracked by brute force, posing security risks'.format(port_tmp[0])
|
||||
|
||||
@@ -37,7 +37,7 @@ def check_run():
|
||||
port = public.readFile(port_file)
|
||||
if not port: return True,'Rick-free'
|
||||
port = int(port)
|
||||
if port != 8888:
|
||||
if port != 8888 and port != 7800:
|
||||
return True,'Rick-free'
|
||||
return False,'The panel port is the default port ({}), which may cause unnecessary security risks'.format(port)
|
||||
|
||||
|
||||
@@ -49,7 +49,7 @@ def check_run():
|
||||
if not is_strong_password(redis_pass):
|
||||
return False, 'Redis access password is too simple, and there are security risks'
|
||||
|
||||
return True,'无风险'
|
||||
return True,'Risk-free'
|
||||
|
||||
|
||||
def is_strong_password(password):
|
||||
|
||||
@@ -71,7 +71,7 @@ class setPanelLets:
|
||||
return public.returnMsg(False, "Failed to apply for a certificate, please try to manually apply for a certificate for the panel domain name on the site management page")
|
||||
get.key = cert_info['private_key']
|
||||
get.csr = cert_info['cert'] + cert_info['root']
|
||||
return self._deploy_cert(get)
|
||||
return public.returnMsg(True, self._deploy_cert(get))
|
||||
|
||||
# 部署证书
|
||||
def _deploy_cert(self,get):
|
||||
@@ -223,6 +223,8 @@ class setPanelLets:
|
||||
return public.returnMsg(True, 'Panel lets set successfully')
|
||||
if not create_site:
|
||||
create_lets = self.__create_lets(get)
|
||||
if not create_lets['status']:
|
||||
return create_lets
|
||||
if create_lets['msg']:
|
||||
domain_cert = self.__check_cert_dir(get)
|
||||
self.copy_cert(domain_cert)
|
||||
|
||||
+14
-14
@@ -14,7 +14,7 @@ def main():
|
||||
CLOUDFLARE_EMAIL=example@example.com \
|
||||
CLOUDFLARE_API_KEY=api-key \
|
||||
sewer \
|
||||
--dns cloudflare \
|
||||
--model cloudflare \
|
||||
--domain example.com \
|
||||
--action run
|
||||
|
||||
@@ -23,7 +23,7 @@ def main():
|
||||
CLOUDFLARE_API_KEY=api-key \
|
||||
sewer \
|
||||
--account_key /path/to/your/account.key \
|
||||
--dns cloudflare \
|
||||
--model cloudflare \
|
||||
--domain example.com \
|
||||
--action renew
|
||||
"""
|
||||
@@ -34,7 +34,7 @@ def main():
|
||||
CLOUDFLARE_EMAIL=example@example.com \
|
||||
CLOUDFLARE_API_KEY=api-key \
|
||||
sewer \
|
||||
--dns cloudflare \
|
||||
--model cloudflare \
|
||||
--domain example.com \
|
||||
--action run""",
|
||||
)
|
||||
@@ -59,7 +59,7 @@ def main():
|
||||
eg: --certificate_key /home/mycertificate.key",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--dns",
|
||||
"--model",
|
||||
type=str,
|
||||
required=True,
|
||||
choices=[
|
||||
@@ -72,7 +72,7 @@ def main():
|
||||
"dnspod",
|
||||
"duckdns",
|
||||
],
|
||||
help="The name of the dns provider that you want to use.",
|
||||
help="The name of the model provider that you want to use.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--domain",
|
||||
@@ -195,7 +195,7 @@ def main():
|
||||
dns_class = CloudFlareDns(
|
||||
CLOUDFLARE_EMAIL=CLOUDFLARE_EMAIL, CLOUDFLARE_API_KEY=CLOUDFLARE_API_KEY
|
||||
)
|
||||
logger.info("chosen_dns_provider. Using {0} as dns provider.".format(dns_provider))
|
||||
logger.info("chosen_dns_provider. Using {0} as model provider.".format(dns_provider))
|
||||
except KeyError as e:
|
||||
logger.error("ERROR:: Please supply {0} as an environment variable.".format(str(e)))
|
||||
raise
|
||||
@@ -210,7 +210,7 @@ def main():
|
||||
dns_class = AuroraDns(
|
||||
AURORA_API_KEY=AURORA_API_KEY, AURORA_SECRET_KEY=AURORA_SECRET_KEY
|
||||
)
|
||||
logger.info("chosen_dns_provider. Using {0} as dns provider.".format(dns_provider))
|
||||
logger.info("chosen_dns_provider. Using {0} as model provider.".format(dns_provider))
|
||||
except KeyError as e:
|
||||
logger.error("ERROR:: Please supply {0} as an environment variable.".format(str(e)))
|
||||
raise
|
||||
@@ -228,7 +228,7 @@ def main():
|
||||
ACME_DNS_API_KEY=ACME_DNS_API_KEY,
|
||||
ACME_DNS_API_BASE_URL=ACME_DNS_API_BASE_URL,
|
||||
)
|
||||
logger.info("chosen_dns_provider. Using {0} as dns provider.".format(dns_provider))
|
||||
logger.info("chosen_dns_provider. Using {0} as model provider.".format(dns_provider))
|
||||
except KeyError as e:
|
||||
logger.error("ERROR:: Please supply {0} as an environment variable.".format(str(e)))
|
||||
raise
|
||||
@@ -240,7 +240,7 @@ def main():
|
||||
aliyun_secret = os.environ["ALIYUN_AK_SECRET"]
|
||||
aliyun_endpoint = os.environ.get("ALIYUN_ENDPOINT", "cn-beijing")
|
||||
dns_class = AliyunDns(aliyun_ak, aliyun_secret, aliyun_endpoint)
|
||||
logger.info("chosen_dns_provider. Using {0} as dns provider.".format(dns_provider))
|
||||
logger.info("chosen_dns_provider. Using {0} as model provider.".format(dns_provider))
|
||||
except KeyError as e:
|
||||
logger.error("ERROR:: Please supply {0} as an environment variable.".format(str(e)))
|
||||
raise
|
||||
@@ -251,7 +251,7 @@ def main():
|
||||
he_username = os.environ["HURRICANE_USERNAME"]
|
||||
he_password = os.environ["HURRICANE_PASSWORD"]
|
||||
dns_class = HurricaneDns(he_username, he_password)
|
||||
logger.info("chosen_dns_provider. Using {0} as dns provider.".format(dns_provider))
|
||||
logger.info("chosen_dns_provider. Using {0} as model provider.".format(dns_provider))
|
||||
except KeyError as e:
|
||||
logger.error("ERROR:: Please supply {0} as an environment variable.".format(str(e)))
|
||||
raise
|
||||
@@ -262,7 +262,7 @@ def main():
|
||||
RACKSPACE_USERNAME = os.environ["RACKSPACE_USERNAME"]
|
||||
RACKSPACE_API_KEY = os.environ["RACKSPACE_API_KEY"]
|
||||
dns_class = RackspaceDns(RACKSPACE_USERNAME, RACKSPACE_API_KEY)
|
||||
logger.info("chosen_dns_prover. Using {0} as dns provider. ".format(dns_provider))
|
||||
logger.info("chosen_dns_prover. Using {0} as model provider. ".format(dns_provider))
|
||||
except KeyError as e:
|
||||
logger.error("ERROR:: Please supply {0} as an environment variable.".format(str(e)))
|
||||
raise
|
||||
@@ -273,7 +273,7 @@ def main():
|
||||
DNSPOD_ID = os.environ["DNSPOD_ID"]
|
||||
DNSPOD_API_KEY = os.environ["DNSPOD_API_KEY"]
|
||||
dns_class = DNSPodDns(DNSPOD_ID, DNSPOD_API_KEY)
|
||||
logger.info("chosen_dns_prover. Using {0} as dns provider. ".format(dns_provider))
|
||||
logger.info("chosen_dns_prover. Using {0} as model provider. ".format(dns_provider))
|
||||
except KeyError as e:
|
||||
logger.error("ERROR:: Please supply {0} as an environment variable.".format(str(e)))
|
||||
raise
|
||||
@@ -284,12 +284,12 @@ def main():
|
||||
duckdns_token = os.environ["DUCKDNS_TOKEN"]
|
||||
|
||||
dns_class = DuckDNSDns(duckdns_token=duckdns_token)
|
||||
logger.info("chosen_dns_provider. Using {0} as dns provider.".format(dns_provider))
|
||||
logger.info("chosen_dns_provider. Using {0} as model provider.".format(dns_provider))
|
||||
except KeyError as e:
|
||||
logger.error("ERROR:: Please supply {0} as an environment variable.".format(str(e)))
|
||||
raise
|
||||
else:
|
||||
raise ValueError("The dns provider {0} is not recognised.".format(dns_provider))
|
||||
raise ValueError("The model provider {0} is not recognised.".format(dns_provider))
|
||||
|
||||
client = Client(
|
||||
domain_name=domain,
|
||||
|
||||
@@ -291,7 +291,7 @@ class Client(object):
|
||||
self.logger.info("apply_for_cert_issuance")
|
||||
identifiers = []
|
||||
for domain_name in self.all_domain_names:
|
||||
identifiers.append({"type": "dns", "value": domain_name})
|
||||
identifiers.append({"type": "model", "value": domain_name})
|
||||
|
||||
payload = {"identifiers": identifiers}
|
||||
url = self.ACME_NEW_ORDER_URL
|
||||
@@ -354,7 +354,7 @@ class Client(object):
|
||||
domain = "*." + domain
|
||||
|
||||
for i in res["challenges"]:
|
||||
if i["type"] == "dns-01":
|
||||
if i["type"] == "model-01":
|
||||
dns_challenge = i
|
||||
dns_token = dns_challenge["token"]
|
||||
dns_challenge_url = dns_challenge["url"]
|
||||
@@ -684,7 +684,7 @@ class Client(object):
|
||||
)
|
||||
|
||||
# for a case where you want certificates for *.example.com and example.com
|
||||
# you have to create both dns records AND then respond to the challenge.
|
||||
# you have to create both model records AND then respond to the challenge.
|
||||
# see issues/83
|
||||
for i in responders:
|
||||
# Make sure the authorization is in a status where we can submit a challenge
|
||||
|
||||
@@ -62,7 +62,7 @@ class AcmeDnsDns(common.BaseDns):
|
||||
# raise error so that we do not continue to make calls to ACME
|
||||
# server
|
||||
raise ValueError(
|
||||
"Error creating acme-dns dns record: status_code={status_code} response={response}".format(
|
||||
"Error creating acme-model model record: status_code={status_code} response={response}".format(
|
||||
status_code=update_acmedns_dns_record_response.status_code,
|
||||
response=self.log_response(update_acmedns_dns_record_response),
|
||||
)
|
||||
@@ -71,5 +71,5 @@ class AcmeDnsDns(common.BaseDns):
|
||||
|
||||
def delete_dns_record(self, domain_name, domain_dns_value):
|
||||
self.logger.info("delete_dns_record")
|
||||
# acme-dns doesn't support this
|
||||
# acme-model doesn't support this
|
||||
self.logger.info("delete_dns_record_success")
|
||||
|
||||
@@ -31,7 +31,7 @@ class _ResponseForAliyun(object):
|
||||
class AliyunDns(common.BaseDns):
|
||||
def __init__(self, key, secret, endpoint="cn-beijing", debug=False):
|
||||
"""
|
||||
aliyun dns client
|
||||
aliyun model client
|
||||
:param str key: access key
|
||||
:param str secret: access sceret
|
||||
:param str endpoint: endpoint
|
||||
@@ -162,7 +162,7 @@ class AliyunDns(common.BaseDns):
|
||||
|
||||
def create_dns_record(self, domain_name, domain_dns_value):
|
||||
"""
|
||||
create a dns record
|
||||
create a model record
|
||||
:param str domain_name: the value sewer client passed in, like *.menduo.example.com
|
||||
:param str domain_dns_value: the value sewer client passed in.
|
||||
:return _ResponseForAliyun:
|
||||
@@ -200,7 +200,7 @@ class AliyunDns(common.BaseDns):
|
||||
self.logger.warning(msg)
|
||||
return
|
||||
|
||||
self.logger.info("start to delete dns record, id: %s", record_id)
|
||||
self.logger.info("start to delete model record, id: %s", record_id)
|
||||
|
||||
request = DeleteDomainRecordRequest.DeleteDomainRecordRequest()
|
||||
request.set_RecordId(record_id)
|
||||
|
||||
@@ -29,10 +29,10 @@ class BaseDns(object):
|
||||
|
||||
def create_dns_record(self, domain_name, domain_dns_value):
|
||||
"""
|
||||
Method that creates/adds a dns TXT record for a domain/subdomain name on
|
||||
Method that creates/adds a model TXT record for a domain/subdomain name on
|
||||
a chosen DNS provider.
|
||||
|
||||
:param domain_name: :string: The domain/subdomain name whose dns record ought to be
|
||||
:param domain_name: :string: The domain/subdomain name whose model record ought to be
|
||||
created/added on a chosen DNS provider.
|
||||
:param domain_dns_value: :string: The value/content of the TXT record that will be
|
||||
created/added for the given domain/subdomain
|
||||
@@ -46,16 +46,16 @@ class BaseDns(object):
|
||||
whose name is '_acme-challenge' + '.' + domain_name + '.' (ie: _acme-challenge.example.com. )
|
||||
and whose value/content is HAJA_4MkowIFByHhFaP8u035skaM91lTKplKld
|
||||
|
||||
Using a dns client like dig(https://linux.die.net/man/1/dig) to do a dns lookup should result
|
||||
Using a model client like dig(https://linux.die.net/man/1/dig) to do a model lookup should result
|
||||
in something like:
|
||||
dig TXT _acme-challenge.example.com
|
||||
...
|
||||
;; ANSWER SECTION:
|
||||
_acme-challenge.example.com. 120 IN TXT "HAJA_4MkowIFByHhFaP8u035skaM91lTKplKld"
|
||||
_acme-challenge.singularity.brandur.org. 120 IN TXT "9C0DqKC_4MkowIFByHhFaP8u0Zv4z7Wz2IHM91lTKec"
|
||||
Optionally, you may also use an online dns client like: https://toolbox.googleapps.com/apps/dig/#TXT/
|
||||
Optionally, you may also use an online model client like: https://toolbox.googleapps.com/apps/dig/#TXT/
|
||||
|
||||
Please consult your dns provider on how/format of their DNS TXT records.
|
||||
Please consult your model provider on how/format of their DNS TXT records.
|
||||
You may also want to consult the cloudflare DNS implementation that is found in this repository.
|
||||
"""
|
||||
self.logger.info("create_dns_record")
|
||||
@@ -63,10 +63,10 @@ class BaseDns(object):
|
||||
|
||||
def delete_dns_record(self, domain_name, domain_dns_value):
|
||||
"""
|
||||
Method that deletes/removes a dns TXT record for a domain/subdomain name on
|
||||
Method that deletes/removes a model TXT record for a domain/subdomain name on
|
||||
a chosen DNS provider.
|
||||
|
||||
:param domain_name: :string: The domain/subdomain name whose dns record ought to be
|
||||
:param domain_name: :string: The domain/subdomain name whose model record ought to be
|
||||
deleted/removed on a chosen DNS provider.
|
||||
:param domain_dns_value: :string: The value/content of the TXT record that will be
|
||||
deleted/removed for the given domain/subdomain
|
||||
|
||||
@@ -62,7 +62,7 @@ class DNSPodDns(common.BaseDns):
|
||||
# raise error so that we do not continue to make calls to ACME
|
||||
# server
|
||||
raise ValueError(
|
||||
"Error creating dnspod dns record: status_code={status_code} response={response}".format(
|
||||
"Error creating dnspod model record: status_code={status_code} response={response}".format(
|
||||
status_code=create_dnspod_dns_record_response["status"]["code"],
|
||||
response=create_dnspod_dns_record_response["status"]["message"],
|
||||
)
|
||||
|
||||
@@ -49,7 +49,7 @@ class DuckDNSDns(common.BaseDns):
|
||||
# raise error so that we do not continue to make calls to DuckDNS
|
||||
# server
|
||||
raise ValueError(
|
||||
"Error creating DuckDNS dns record: status_code={status_code} response={response}".format(
|
||||
"Error creating DuckDNS model record: status_code={status_code} response={response}".format(
|
||||
status_code=update_duckdns_dns_record_response.status_code,
|
||||
response=normalized_response,
|
||||
)
|
||||
|
||||
@@ -47,11 +47,11 @@ class RackspaceDns(common.BaseDns):
|
||||
data = find_rackspace_api_details_response.json()
|
||||
api_token = data["access"]["token"]["id"]
|
||||
url_data = next(
|
||||
(item for item in data["access"]["serviceCatalog"] if item["type"] == "rax:dns"), None
|
||||
(item for item in data["access"]["serviceCatalog"] if item["type"] == "rax:model"), None
|
||||
)
|
||||
if url_data is None:
|
||||
raise ValueError(
|
||||
"Error finding url data for the rackspace dns api in the response from the identity server"
|
||||
"Error finding url data for the rackspace model api in the response from the identity server"
|
||||
)
|
||||
else:
|
||||
api_base_url = url_data["endpoints"][0]["publicURL"] + "/"
|
||||
@@ -91,7 +91,7 @@ class RackspaceDns(common.BaseDns):
|
||||
)
|
||||
if find_dns_zone_id_response.status_code != 200:
|
||||
raise ValueError(
|
||||
"Error getting rackspace dns domain info: status_code={status_code} response={response}".format(
|
||||
"Error getting rackspace model domain info: status_code={status_code} response={response}".format(
|
||||
status_code=find_dns_zone_id_response.status_code,
|
||||
response=self.log_response(find_dns_zone_id_response),
|
||||
)
|
||||
@@ -102,7 +102,7 @@ class RackspaceDns(common.BaseDns):
|
||||
)
|
||||
if domain_data is None:
|
||||
raise ValueError(
|
||||
"Error finding information for {dns_zone} in dns response data:\n{response_data})".format(
|
||||
"Error finding information for {dns_zone} in model response data:\n{response_data})".format(
|
||||
dns_zone=self.RACKSPACE_DNS_ZONE,
|
||||
response_data=self.log_response(find_dns_zone_id_response),
|
||||
)
|
||||
@@ -124,7 +124,7 @@ class RackspaceDns(common.BaseDns):
|
||||
self.logger.debug(url)
|
||||
if find_dns_record_id_response.status_code != 200:
|
||||
raise ValueError(
|
||||
"Error finding dns records for {dns_zone}: status_code={status_code} response={response}".format(
|
||||
"Error finding model records for {dns_zone}: status_code={status_code} response={response}".format(
|
||||
dns_zone=self.RACKSPACE_DNS_ZONE,
|
||||
status_code=find_dns_record_id_response.status_code,
|
||||
response=self.log_response(find_dns_record_id_response),
|
||||
@@ -152,21 +152,21 @@ class RackspaceDns(common.BaseDns):
|
||||
callback_url_response = requests.get(callback_url, headers=self.RACKSPACE_HEADERS)
|
||||
if time.time() > start_time + self.HTTP_TIMEOUT:
|
||||
raise ValueError(
|
||||
"Timed out polling callbackurl for dns record status. Last status_code={status_code} last response={response}".format(
|
||||
"Timed out polling callbackurl for model record status. Last status_code={status_code} last response={response}".format(
|
||||
status_code=callback_url_response.status_code,
|
||||
response=self.log_response(callback_url_response),
|
||||
)
|
||||
)
|
||||
if callback_url_response.status_code != 200:
|
||||
raise Exception(
|
||||
"Could not get dns record status from callback url. Status code ={status_code}. response={response}".format(
|
||||
"Could not get model record status from callback url. Status code ={status_code}. response={response}".format(
|
||||
status_code=callback_url_response.status_code,
|
||||
response=self.log_response(callback_url_response),
|
||||
)
|
||||
)
|
||||
if callback_url_response.json()["status"] == "ERROR":
|
||||
raise Exception(
|
||||
"Error in creating/deleting dns record: status_Code={status_code}. response={response}".format(
|
||||
"Error in creating/deleting model record: status_Code={status_code}. response={response}".format(
|
||||
status_code=callback_url_response.status_code,
|
||||
response=self.log_response(callback_url_response),
|
||||
)
|
||||
@@ -196,13 +196,13 @@ class RackspaceDns(common.BaseDns):
|
||||
)
|
||||
if create_rackspace_dns_record_response.status_code != 202:
|
||||
raise ValueError(
|
||||
"Error creating rackspace dns record: status_code={status_code} response={response}".format(
|
||||
"Error creating rackspace model record: status_code={status_code} response={response}".format(
|
||||
status_code=create_rackspace_dns_record_response.status_code,
|
||||
response=create_rackspace_dns_record_response.text,
|
||||
)
|
||||
)
|
||||
# response=self.log_response(create_rackspace_dns_record_response)))
|
||||
# After posting the dns record we want created, the response gives us a url to check that will
|
||||
# After posting the model record we want created, the response gives us a url to check that will
|
||||
# update when the job is done
|
||||
callback_url = create_rackspace_dns_record_response.json()["callbackUrl"]
|
||||
self.poll_callback_url(callback_url)
|
||||
@@ -228,7 +228,7 @@ class RackspaceDns(common.BaseDns):
|
||||
)
|
||||
if delete_dns_record_response.status_code != 202:
|
||||
raise ValueError(
|
||||
"Error deleting rackspace dns record: status_code={status_code} response={response}".format(
|
||||
"Error deleting rackspace model record: status_code={status_code} response={response}".format(
|
||||
status_code=delete_dns_record_response.status_code,
|
||||
response=self.log_response(delete_dns_record_response),
|
||||
)
|
||||
|
||||
@@ -252,7 +252,7 @@ class ACMEclient(object):
|
||||
print("Apply for a certificate")
|
||||
identifiers = []
|
||||
for domain_name in self.all_domain_names:
|
||||
identifiers.append({"type": "dns", "value": domain_name})
|
||||
identifiers.append({"type": "model", "value": domain_name})
|
||||
payload = {"identifiers": identifiers}
|
||||
url = self.ACME_NEW_ORDER_URL
|
||||
apply_for_cert_issuance_response = self.make_signed_acme_request(url=url, payload=payload)
|
||||
@@ -299,7 +299,7 @@ class ACMEclient(object):
|
||||
if wildcard:
|
||||
domain = "*." + domain
|
||||
for i in res["challenges"]:
|
||||
if i["type"] == "dns-01":
|
||||
if i["type"] == "model-01":
|
||||
dns_challenge = i
|
||||
dns_token = dns_challenge["token"]
|
||||
dns_challenge_url = dns_challenge["url"]
|
||||
@@ -364,7 +364,7 @@ class ACMEclient(object):
|
||||
if authorization_status in desired_status:
|
||||
break
|
||||
else:
|
||||
print("Failed to verify dns txt wait {} seconds to re-verify dns, returned information:".format(self.ACME_AUTH_STATUS_WAIT_PERIOD))
|
||||
print("Failed to verify model txt wait {} seconds to re-verify model, returned information:".format(self.ACME_AUTH_STATUS_WAIT_PERIOD))
|
||||
print(check_authorization_status_response.json())
|
||||
public.WriteFile(os.path.join(ssl_home_path, "check_authorization_status_response"), check_authorization_status_response.text, mode="w")
|
||||
# 等待
|
||||
@@ -806,7 +806,7 @@ class AliyunDns(object):
|
||||
msg = public.GetMsg("CANT_FIND_RECORDID"), domain_name
|
||||
print(msg)
|
||||
return
|
||||
print("start to delete dns record, id: ", record_id)
|
||||
print("start to delete model record, id: ", record_id)
|
||||
randomint = random.randint(11111111111111, 99999999999999)
|
||||
now = datetime.datetime.utcnow()
|
||||
otherStyleTime = now.strftime("%Y-%m-%dT%H:%M:%SZ")
|
||||
@@ -901,7 +901,7 @@ class Dns_com(object):
|
||||
def create_dns_record(self, domain_name, domain_dns_value):
|
||||
root, _, acme_txt = extract_zone(domain_name)
|
||||
print("create_dns_record,", acme_txt, domain_dns_value)
|
||||
result = public.ExecShell('''{} /www/server/panel/plugin/dns/dns_main.py add_txt {} {}'''.format(public.get_python_bin(),acme_txt + '.' + root, domain_dns_value))
|
||||
result = public.ExecShell('''{} /www/server/panel/plugin/model/dns_main.py add_txt {} {}'''.format(public.get_python_bin(),acme_txt + '.' + root, domain_dns_value))
|
||||
if result[0].strip() == "False":
|
||||
sys.exit(json.dumps({"data": public.GetMsg("BT_DNSRES_ERR")}))
|
||||
print("create_dns_record_end")
|
||||
@@ -909,7 +909,7 @@ class Dns_com(object):
|
||||
def delete_dns_record(self, domain_name, domain_dns_value):
|
||||
root, _, acme_txt = extract_zone(domain_name)
|
||||
print("delete_dns_record start: ", acme_txt, domain_dns_value)
|
||||
public.ExecShell('''{} /www/server/panel/plugin/dns/dns_main.py remove_txt {} {}'''.format(public.get_python_bin() ,acme_txt + '.' + root, domain_dns_value))
|
||||
public.ExecShell('''{} /www/server/panel/plugin/model/dns_main.py remove_txt {} {}'''.format(public.get_python_bin() ,acme_txt + '.' + root, domain_dns_value))
|
||||
print("delete_dns_record_success")
|
||||
|
||||
|
||||
@@ -939,9 +939,9 @@ if __name__ == "__main__":#dns调用验证脚本
|
||||
dns_class = AliyunDns(key=key, secret=secret)
|
||||
elif dnsapi == "dns_cx": # CloudXns
|
||||
dns_class = CloudxnsDns(key=key, secret=secret)
|
||||
elif dnsapi == "dns_bt": # dns.com
|
||||
elif dnsapi == "dns_bt": # model.com
|
||||
dns_class = Dns_com()
|
||||
elif dnsapi == "dns": # 手动的
|
||||
elif dnsapi == "model": # 手动的
|
||||
dns_class = Dns_Manual()
|
||||
Manual = 1
|
||||
domain_alt_names = data['domain_alt_names'].split(",")
|
||||
|
||||
@@ -62,6 +62,8 @@ class SiteDirAuth:
|
||||
:param get:
|
||||
:return:
|
||||
'''
|
||||
if len(get.username) < 3 or len(get.password) < 3:
|
||||
return public.returnMsg(False, 'The account number or password cannot be less than 3 characters')
|
||||
name = get.name
|
||||
site_dir = get.site_dir
|
||||
if public.get_webserver() == "openlitespeed":
|
||||
|
||||
@@ -182,11 +182,15 @@ class ssh_security:
|
||||
|
||||
################## SSH 登陆报警设置 ####################################
|
||||
def send_mail_data(self,title,body,type='mail'):
|
||||
import threading
|
||||
if type=='mail':
|
||||
if self.__mail_config['user_mail']['user_name']:
|
||||
if len(self.__mail_config['user_mail']['mail_list'])>=1:
|
||||
for i in self.__mail_config['user_mail']['mail_list']:
|
||||
self.__mail.qq_smtp_send(i, title, body)
|
||||
t = threading.Thread(target=self.__mail.qq_smtp_send,args=(i, title, body))
|
||||
t.setDaemon(True)
|
||||
t.start()
|
||||
# self.__mail.qq_smtp_send(i, title, body)
|
||||
elif type=='dingding':
|
||||
if self.__mail_config['dingding']['dingding']:
|
||||
self.__mail.dingding_send(title+body)
|
||||
|
||||
+2
-1
@@ -411,6 +411,8 @@ class system:
|
||||
for tmp in temp1:
|
||||
n += 1
|
||||
try:
|
||||
if ',' in tmp:
|
||||
tmp = re.sub(',\d+','',tmp)
|
||||
inodes = tempInodes1[n-1].split()
|
||||
disk = re.findall(r"^(.+)\s+([\w\.]+)\s+([\w\.]+)\s+([\w\.]+)\s+([\w\.]+)\s+([\d%]{2,4})\s+(/.{0,100})$",tmp.strip())
|
||||
if disk: disk = disk[0]
|
||||
@@ -902,7 +904,6 @@ class system:
|
||||
public.ExecShell('/etc/init.d/nginx start')
|
||||
if get.type != 'test':
|
||||
public.WriteLog("TYPE_SOFT", 'SYS_EXEC_SUCCESS',(execStr,))
|
||||
|
||||
if len(result[1]) > 1 and get.name != 'pure-ftpd' and get.name != 'redis': return public.returnMsg(False, '<p>Warning message: <p>' + result[1].replace('\n','<br>'))
|
||||
return public.returnMsg(True,'SYS_EXEC_SUCCESS')
|
||||
|
||||
|
||||
+7
-6
@@ -177,12 +177,13 @@ class userlogin:
|
||||
domain = public.readFile('data/domain.conf')
|
||||
|
||||
if domain:
|
||||
if(public.GetHost().lower() != domain.strip().lower()):
|
||||
errorStr = public.ReadFile('./BTPanel/templates/' + public.GetConfigValue('template') + '/error2.html')
|
||||
try:
|
||||
errorStr = errorStr.format(public.getMsg('PAGE_ERR_TITLE'),public.getMsg('PAGE_ERR_DOMAIN_H1'),public.getMsg('PAGE_ERR_DOMAIN_P1'),public.getMsg('PAGE_ERR_DOMAIN_P2'),public.getMsg('PAGE_ERR_DOMAIN_P3'),public.getMsg('NAME'),public.getMsg('PAGE_ERR_HELP'))
|
||||
except IndexError:pass
|
||||
return errorStr
|
||||
if(public.GetHost().lower() != domain.strip().lower()):
|
||||
return 404
|
||||
# errorStr = public.ReadFile('./BTPanel/templates/' + public.GetConfigValue('template') + '/error2.html')
|
||||
# try:
|
||||
# errorStr = errorStr.format(public.getMsg('PAGE_ERR_TITLE'),public.getMsg('PAGE_ERR_DOMAIN_H1'),public.getMsg('PAGE_ERR_DOMAIN_P1'),public.getMsg('PAGE_ERR_DOMAIN_P2'),public.getMsg('PAGE_ERR_DOMAIN_P3'),public.getMsg('NAME'),public.getMsg('PAGE_ERR_HELP'))
|
||||
# except IndexError:pass
|
||||
# return errorStr
|
||||
if os.path.exists('data/limitip.conf'):
|
||||
iplist = public.readFile('data/limitip.conf')
|
||||
if iplist:
|
||||
|
||||
+4
-2
@@ -30,7 +30,7 @@ class wxapp():
|
||||
def is_scan_ok(self, get):
|
||||
if os.path.exists(self.app_path+"app_login_check.pl"):
|
||||
key, init_time = public.readFile(self.app_path+'app_login_check.pl').split(':')
|
||||
if time.time() - float(init_time) > 180:
|
||||
if time.time() - float(init_time) > 60:
|
||||
return public.returnMsg(False, 'QRCORE_EXPIRE')
|
||||
session_id = public.get_session_id()
|
||||
if cache.get(session_id) == 'True':
|
||||
@@ -70,7 +70,9 @@ class wxapp():
|
||||
secret_key, init_time = data.split(':')
|
||||
if len(session_id)!=64:return public.returnMsg(False,'Waiting for APP scan code login 2')
|
||||
if len(secret_key)!=64:return public.returnMsg(False,'Waiting for APP scan code login 2')
|
||||
if time.time() - float(init_time) < 180 and session_id != secret_key:
|
||||
if time.time() - float(init_time) > 60:
|
||||
return public.returnMsg(False,'Waiting for APP scan code login')
|
||||
if session_id != secret_key:
|
||||
return public.returnMsg(False,'Waiting for APP scan code login')
|
||||
cache.delete(session_id)
|
||||
userInfo = public.M('users').where("id=?",(1,)).field('id,username').find()
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
[ "103.224.251.67","128.1.164.196","45.76.53.20","[2001:19f0:7001:54fc:5400:2ff:fe9b:97f9]", "158.247.208.19"]
|
||||
["128.1.164.196","45.76.53.20","[2001:19f0:7001:54fc:5400:2ff:fe9b:97f9]", "158.247.208.19"]
|
||||
+4
-23
@@ -1,26 +1,7 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
|
||||
<title>404</title>
|
||||
<style>
|
||||
body{
|
||||
background-color:#444;
|
||||
font-size:14px;
|
||||
}
|
||||
h3{
|
||||
font-size:60px;
|
||||
color:#eee;
|
||||
text-align:center;
|
||||
padding-top:30px;
|
||||
font-weight:normal;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<head><title>404 Not Found</title></head>
|
||||
<body>
|
||||
<h3>404, the file you requested does not exist!</h3>
|
||||
<center><h1>404 Not Found</h1></center>
|
||||
<hr><center>nginx</center>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
+18
-19
@@ -1,24 +1,23 @@
|
||||
<!doctype html>
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Congratulations, the site was created successfully!</title>
|
||||
<link rel="stylesheet" href="//cdn.bootcss.com/bootstrap/3.3.4/css/bootstrap.min.css">
|
||||
<script src="//cdn.bootcss.com/jquery/1.11.2/jquery.min.js"></script>
|
||||
<script src="//cdn.bootcss.com/bootstrap/3.3.4/js/bootstrap.min.js"></script>
|
||||
<title>Welcome to nginx!</title>
|
||||
<style>
|
||||
html { color-scheme: light dark; }
|
||||
body { width: 35em; margin: 0 auto;
|
||||
font-family: Tahoma, Verdana, Arial, sans-serif; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container" style="margin-top:9%;">
|
||||
<div class="jumbotron">
|
||||
<div class="panel panel-success">
|
||||
<div class="panel-heading"><h1>Congratulations, the site was created successfully!</h1></div>
|
||||
</div>
|
||||
<p><h3>The site was created successfully and this page is automatically generated by the system.</h3></p>
|
||||
<p><li>This page is index.html in the FTP root directory.</li></p>
|
||||
<p><li>You can delete or overwrite this page</li></p>
|
||||
<p><li>For FTP related information, please check the background of the pagoda.</li></p>
|
||||
<p><li>We provide you with a comprehensive data backup function, please go to the background to set up</li></p>
|
||||
</div>
|
||||
</div>
|
||||
<h1>Welcome to nginx!</h1>
|
||||
<p>If you see this page, the nginx web server is successfully installed and
|
||||
working. Further configuration is required.</p>
|
||||
|
||||
<p>For online documentation and support please refer to
|
||||
<a href="http://nginx.org/">nginx.org</a>.<br/>
|
||||
Commercial support is available at
|
||||
<a href="http://nginx.com/">nginx.com</a>.</p>
|
||||
|
||||
<p><em>Thank you for using nginx.</em></p>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
||||
+15
-31
@@ -1,39 +1,23 @@
|
||||
<!doctype html>
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Site not found</title>
|
||||
<title>Welcome to nginx!</title>
|
||||
<style>
|
||||
*{margin:0;padding:0;color:#444}
|
||||
body{font-size:14px;font-family:"宋体"}
|
||||
.main{width:600px;margin:10% auto;}
|
||||
.title{background: #20a53a;color: #fff;font-size: 16px;height: 40px;line-height: 40px;padding-left: 20px;}
|
||||
.content{background-color:#f3f7f9; height:300px;border:1px dashed #c6d9b6;padding:20px}
|
||||
.t1{border-bottom: 1px dashed #c6d9b6;color: #ff4000;font-weight: bold; margin: 0 0 20px; padding-bottom: 18px;}
|
||||
.t2{margin-bottom:8px; font-weight:bold}
|
||||
ol{margin:0 0 20px 22px;padding:0;}
|
||||
ol li{line-height:30px}
|
||||
html { color-scheme: light dark; }
|
||||
body { width: 35em; margin: 0 auto;
|
||||
font-family: Tahoma, Verdana, Arial, sans-serif; }
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="main">
|
||||
<div class="title">Site not found</div>
|
||||
<div class="content">
|
||||
<p class="t1">Your request did not find this site in the web server!</p>
|
||||
<p class="t2">Probable cause: </p>
|
||||
<ol>
|
||||
<li>Did not bind this domain name or IP to this site!</li>
|
||||
<li>Configuration file not in effect!</li>
|
||||
</ol>
|
||||
<p class="t2">How to solve: </p>
|
||||
<ol>
|
||||
<li>Check whether already bound to the site, if true, try reloading the Web services.</li>
|
||||
<li>Check if the port is correct.</li>
|
||||
<li>If you are using a CDN product, try clearing the CDN cache.</li>
|
||||
<li>For ordinary website visitors, please contact the webadmin.</li>
|
||||
</ol>
|
||||
</div>
|
||||
</div>
|
||||
<h1>Welcome to nginx!</h1>
|
||||
<p>If you see this page, the nginx web server is successfully installed and
|
||||
working. Further configuration is required.</p>
|
||||
|
||||
<p>For online documentation and support please refer to
|
||||
<a href="http://nginx.org/">nginx.org</a>.<br/>
|
||||
Commercial support is available at
|
||||
<a href="http://nginx.com/">nginx.com</a>.</p>
|
||||
|
||||
<p><em>Thank you for using nginx.</em></p>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -11,12 +11,6 @@
|
||||
"port": "80",
|
||||
"ping": 500
|
||||
},
|
||||
{
|
||||
"protocol": "http://",
|
||||
"address": "103.224.251.67",
|
||||
"port": "5880",
|
||||
"ping": 500
|
||||
},
|
||||
{
|
||||
"protocol": "http://",
|
||||
"address": "45.76.53.20",
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
8888
|
||||
7800
|
||||
@@ -316,7 +316,7 @@ case "$1" in
|
||||
auth_path=$(cat $panel_path/data/admin_path.pl)
|
||||
fi
|
||||
if [ "$address" = "" ];then
|
||||
address=$(curl -sS --connect-timeout 10 -m 60 https://www.bt.cn/Api/getIpAddress)
|
||||
address=$(curl -sS --connect-timeout 10 -m 60 https://www.aapanel.com/api/common/getClientIP)
|
||||
fi
|
||||
pool=http
|
||||
if [ -f $panel_path/data/ssl.pl ];then
|
||||
@@ -331,7 +331,7 @@ case "$1" in
|
||||
echo -e "password: $password"
|
||||
echo -e "\033[33mWarning:\033[0m"
|
||||
echo -e "\033[33mIf you cannot access the panel, \033[0m"
|
||||
echo -e "\033[33mrelease the following port (8888|888|80|443|20|21) in the security group\033[0m"
|
||||
echo -e "\033[33mrelease the following port (7800|888|80|443|20|21) in the security group\033[0m"
|
||||
echo -e "=================================================================="
|
||||
;;
|
||||
*)
|
||||
|
||||
@@ -16,3 +16,4 @@ gevent-websocket>=0.10.1
|
||||
pyopenssl>=19.0
|
||||
cryptography>=2.7
|
||||
six>=1.12.0
|
||||
pyOpenSSL>=21.0.0
|
||||
+1
-1
@@ -5,7 +5,7 @@ f.close()
|
||||
if bt_port:
|
||||
bt_port.strip()
|
||||
else:
|
||||
bt_port = 8888
|
||||
bt_port = 7800
|
||||
bind = []
|
||||
if os.path.exists('data/ipv6.pl'):
|
||||
bind.append('[0:0:0:0:0:0:0:0]:%s' % bt_port)
|
||||
|
||||
@@ -0,0 +1,303 @@
|
||||
#coding: utf-8
|
||||
#-------------------------------------------------------------------
|
||||
# 宝塔Linux面板
|
||||
#-------------------------------------------------------------------
|
||||
# Copyright (c) 2015-2099 宝塔软件(http://bt.cn) All rights reserved.
|
||||
#-------------------------------------------------------------------
|
||||
# Author: hwliang<hwl@bt.cn>
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
import sys
|
||||
import time
|
||||
import os
|
||||
import struct
|
||||
|
||||
os.chdir('/www/server/panel')
|
||||
if 'class/' in sys.path: sys.path.insert(0,"class/")
|
||||
import copy
|
||||
try:
|
||||
import pcap
|
||||
except ImportError:
|
||||
if os.path.exists('/usr/bin/apt'):
|
||||
os.system("apt install libpcap-dev")
|
||||
elif os.path.exists('/usr/bin/dnf'):
|
||||
os.system("dnf install libpcap-devel")
|
||||
elif os.path.exists('/usr/bin/yum'):
|
||||
os.system("yum install libpcap-devel")
|
||||
os.system("btpip install pypcap")
|
||||
try:
|
||||
import pcap
|
||||
except ImportError:
|
||||
print("pypcap module install failed.")
|
||||
sys.exit()
|
||||
|
||||
|
||||
class process_network_total:
|
||||
__pid_file = 'logs/process_network_total.pid'
|
||||
__inode_list = {}
|
||||
__net_process_list = {}
|
||||
__net_process_size = {}
|
||||
__last_stat = 0
|
||||
__last_write_time = 0
|
||||
__end_time = 0
|
||||
|
||||
def start(self,timeout = 0):
|
||||
'''
|
||||
@name 启动进程网络监控
|
||||
@author hwliang<2021-09-13>
|
||||
@param timeout<int> 结束时间(秒),0表示持久运行,默认为0
|
||||
@return void
|
||||
'''
|
||||
stime = time.time()
|
||||
self.__end_time = timeout + stime
|
||||
self.__last_stat = stime
|
||||
try:
|
||||
p = pcap.pcap() # 监听所有网卡
|
||||
p.setfilter('tcp') # 只监听TCP数据包
|
||||
for p_time,p_data in p:
|
||||
self.handle_packet(p_data)
|
||||
# 过期停止监听
|
||||
if timeout > 0:
|
||||
if p_time > self.__end_time:
|
||||
self.rm_pid_file()
|
||||
break
|
||||
except:
|
||||
self.rm_pid_file()
|
||||
|
||||
def handle_packet(self, pcap_data):
|
||||
'''
|
||||
@name 处理pcap数据包
|
||||
@author hwliang<2021-09-12>
|
||||
@param pcap_data<bytes> pcap数据包
|
||||
@return void
|
||||
'''
|
||||
# 获取IP协议头
|
||||
ip_header = pcap_data[14:34]
|
||||
# 解析src/dst地址
|
||||
src_ip = ip_header[12:16]
|
||||
dst_ip = ip_header[16:20]
|
||||
# 解析sport/dport端口
|
||||
src_port = pcap_data[34:36]
|
||||
dst_port = pcap_data[36:38]
|
||||
|
||||
src = src_ip + b':' + src_port
|
||||
dst = dst_ip + b':' + dst_port
|
||||
# 计算数据包长度
|
||||
pack_size = len(pcap_data)
|
||||
# 统计进程流量
|
||||
self.total_net_process(dst,src,pack_size)
|
||||
|
||||
def total_net_process(self,dst,src,pack_size):
|
||||
'''
|
||||
@name 统计进程流量
|
||||
@author hwliang<2021-09-13>
|
||||
@param dst<bytes> 目标地址
|
||||
@param src<bytes> 源地址
|
||||
@param pack_size<int> 数据包长度
|
||||
@return void
|
||||
'''
|
||||
self.get_tcp_stat()
|
||||
direction = None
|
||||
mtime = time.time()
|
||||
if dst in self.__net_process_list:
|
||||
pid = self.__net_process_list[dst]
|
||||
direction = 'down'
|
||||
elif src in self.__net_process_list:
|
||||
pid = self.__net_process_list[src]
|
||||
direction = 'up'
|
||||
else:
|
||||
if mtime - self.__last_stat > 3:
|
||||
self.__last_stat = mtime
|
||||
self.get_tcp_stat(True)
|
||||
if dst in self.__net_process_list:
|
||||
pid = self.__net_process_list[dst]
|
||||
direction = 'down'
|
||||
elif src in self.__net_process_list:
|
||||
pid = self.__net_process_list[src]
|
||||
direction = 'up'
|
||||
|
||||
if not direction: return False
|
||||
if not pid: return False
|
||||
if not pid in self.__net_process_size:
|
||||
self.__net_process_size[pid] = {}
|
||||
self.__net_process_size[pid]['down'] = 0
|
||||
self.__net_process_size[pid]['up'] = 0
|
||||
self.__net_process_size[pid]['up_package'] = 0
|
||||
self.__net_process_size[pid]['down_package'] = 0
|
||||
|
||||
self.__net_process_size[pid][direction] += pack_size
|
||||
self.__net_process_size[pid][direction + '_package'] += 1
|
||||
|
||||
# 写入到文件
|
||||
if mtime - self.__last_write_time > 1:
|
||||
self.__last_write_time = mtime
|
||||
self.write_net_process()
|
||||
|
||||
def write_net_process(self):
|
||||
'''
|
||||
@name 写入进程流量
|
||||
@author hwliang<2021-09-13>
|
||||
@return void
|
||||
'''
|
||||
w_file = '/dev/shm/bt_net_process'
|
||||
process_size = copy.deepcopy(self.__net_process_size)
|
||||
net_process = []
|
||||
for pid in process_size.keys():
|
||||
net_process.append(str(pid) + " " + str(process_size[pid]['down']) + " " + str(process_size[pid]['up']) + " " + str(process_size[pid]['down_package']) + " " + str(process_size[pid]['up_package']))
|
||||
|
||||
f = open(w_file,'w+',encoding='utf-8')
|
||||
f.write('\n'.join(net_process))
|
||||
f.close()
|
||||
|
||||
def hex_to_ip(self, hex_ip):
|
||||
'''
|
||||
@name 将16进制的IP地址转换为字符串IP地址
|
||||
@author hwliang<2021-09-13>
|
||||
@param hex_ip<string> 16进制的IP地址:16进程端口
|
||||
@return tuple(ip<str>,port<int>) IP地址,端口
|
||||
'''
|
||||
hex_ip,hex_port = hex_ip.split(':')
|
||||
ip = '.'.join([str(int(hex_ip[i:i+2], 16)) for i in range(0, len(hex_ip), 2)][::-1])
|
||||
port = int(hex_port, 16)
|
||||
return ip,port
|
||||
|
||||
def get_tcp_stat(self,force = False):
|
||||
'''
|
||||
@name 获取当前TCP连接状态表
|
||||
@author hwliang<2021-09-13>
|
||||
@param force<bool> 是否强制刷新
|
||||
@return dict
|
||||
'''
|
||||
if not force and self.__net_process_list: return self.__net_process_list
|
||||
self.__net_process_list = {}
|
||||
tcp_stat_file = '/proc/net/tcp'
|
||||
tcp_stat = open(tcp_stat_file, 'rb')
|
||||
tcp_stat_list = tcp_stat.read().decode('utf-8').split('\n')
|
||||
tcp_stat.close()
|
||||
tcp_stat_list = tcp_stat_list[1:]
|
||||
if force: self.get_process_inodes(force)
|
||||
for i in tcp_stat_list:
|
||||
tcp_tmp = i.split()
|
||||
if len(tcp_tmp) < 10: continue
|
||||
inode = tcp_tmp[9]
|
||||
if inode == '0': continue
|
||||
local_ip,local_port = self.hex_to_ip(tcp_tmp[1])
|
||||
if local_ip == '127.0.0.1': continue
|
||||
remote_ip,remote_port = self.hex_to_ip(tcp_tmp[2])
|
||||
if local_ip == remote_ip: continue
|
||||
if remote_ip == '0.0.0.0': continue
|
||||
|
||||
pid = self.inode_to_pid(inode,force)
|
||||
if not pid: continue
|
||||
|
||||
key = self.get_ip_pack(local_ip) + b':' + self.get_port_pack(local_port)
|
||||
self.__net_process_list[key] = pid
|
||||
return self.__net_process_list
|
||||
|
||||
|
||||
def get_port_pack(self,port):
|
||||
'''
|
||||
@name 将端口转换为字节流
|
||||
@author hwliang<2021-09-13>
|
||||
@param port<int> 端口
|
||||
@return bytes
|
||||
'''
|
||||
return struct.pack('H',int(port))[::-1]
|
||||
|
||||
def get_ip_pack(self,ip):
|
||||
'''
|
||||
@name 将IP地址转换为字节流
|
||||
@author hwliang<2021-09-13>
|
||||
@param ip<str> IP地址
|
||||
@return bytes
|
||||
'''
|
||||
ip_arr = ip.split('.')
|
||||
ip_pack = b''
|
||||
for i in ip_arr:
|
||||
ip_pack += struct.pack('B',int(i))
|
||||
return ip_pack
|
||||
|
||||
def inode_to_pid(self,inode,force = False):
|
||||
'''
|
||||
@name 将inode转换为进程ID
|
||||
@author hwliang<2021-09-13>
|
||||
@param inode<string> inode
|
||||
@param force<bool> 是否强制刷新
|
||||
@return int
|
||||
'''
|
||||
inode_list = self.get_process_inodes()
|
||||
if inode in inode_list:
|
||||
return inode_list[inode]
|
||||
return None
|
||||
|
||||
def get_process_inodes(self,force = False):
|
||||
'''
|
||||
@name 获取进程inode列表
|
||||
@author hwliang<2021-09-13>
|
||||
@param force<bool> 是否强制刷新
|
||||
@return dict
|
||||
'''
|
||||
if not force and self.__inode_list: return self.__inode_list
|
||||
proc_path = '/proc'
|
||||
inode_list = {}
|
||||
for pid in os.listdir(proc_path):
|
||||
try:
|
||||
if not pid.isdigit(): continue
|
||||
inode_path = proc_path + '/' + pid + '/fd'
|
||||
for fd in os.listdir(inode_path):
|
||||
try:
|
||||
fd_file = inode_path + '/' + fd
|
||||
fd_link = os.readlink(fd_file)
|
||||
if fd_link.startswith('socket:['):
|
||||
inode = fd_link[8:-1]
|
||||
inode_list[inode] = pid
|
||||
except:
|
||||
continue
|
||||
except:
|
||||
continue
|
||||
self.__inode_list = inode_list
|
||||
return inode_list
|
||||
|
||||
def get_process_name(self,pid):
|
||||
'''
|
||||
@name 获取进程名称
|
||||
@author hwliang<2021-09-13>
|
||||
@param pid<str> 进程ID
|
||||
@return str
|
||||
'''
|
||||
pid_path = '/proc/' + pid + '/comm'
|
||||
if not os.path.exists(pid_path): return ''
|
||||
pid_file = open(pid_path, 'rb')
|
||||
pid_name = pid_file.read().decode('utf-8').strip()
|
||||
pid_file.close()
|
||||
return pid_name
|
||||
|
||||
|
||||
def write_pid(self):
|
||||
'''
|
||||
@name 写入进程ID到PID文件
|
||||
@author hwliang<2021-09-13>
|
||||
@return void
|
||||
'''
|
||||
self_pid = os.getpid()
|
||||
pid_file = open(self.__pid_file,'w')
|
||||
pid_file.write(str(self_pid))
|
||||
pid_file.close()
|
||||
|
||||
def rm_pid_file(self):
|
||||
'''
|
||||
@name 删除进程pid文件
|
||||
@author hwliang<2021-09-13>
|
||||
@return void
|
||||
'''
|
||||
if os.path.exists(self.__pid_file):
|
||||
os.remove(self.__pid_file)
|
||||
|
||||
if __name__ == '__main__':
|
||||
if len(sys.argv) > 1:
|
||||
timeout = int(sys.argv[-1])
|
||||
else:
|
||||
timeout = 0
|
||||
p = process_network_total()
|
||||
p.write_pid()
|
||||
p.start(timeout)
|
||||
@@ -0,0 +1,60 @@
|
||||
#coding: utf-8
|
||||
#-------------------------------------------------------------------
|
||||
# 宝塔Linux面板
|
||||
#-------------------------------------------------------------------
|
||||
# Copyright (c) 2015-2099 宝塔软件(http:#bt.cn) All rights reserved.
|
||||
#-------------------------------------------------------------------
|
||||
# Author: hwliang <hwl@bt.cn>
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
#------------------------------
|
||||
# 项目开机自启调用脚本
|
||||
#------------------------------
|
||||
import os,sys
|
||||
panel_path = '/www/server/panel'
|
||||
os.chdir(panel_path)
|
||||
if not 'class/' in sys.path: sys.path.insert(0,'class/')
|
||||
import public,time,psutil
|
||||
|
||||
|
||||
def project_model_auto_run():
|
||||
'''
|
||||
@name 项目模型自启调用
|
||||
@author hwliang<2021-08-09>
|
||||
@return bool
|
||||
'''
|
||||
project_model_path = '{}/projectModel'.format(public.get_class_path())
|
||||
if not os.path.exists(project_model_path): return False
|
||||
for mod_name in os.listdir(project_model_path):
|
||||
if mod_name in ['base.py','__init__.py']: continue
|
||||
mod_file = "{}/{}".format(project_model_path,mod_name)
|
||||
if not os.path.exists(mod_file): continue
|
||||
if not os.path.isfile(mod_file): continue
|
||||
|
||||
tmp_mod = public.get_script_object(mod_file)
|
||||
if not hasattr(tmp_mod,'main'): continue
|
||||
|
||||
run_object = getattr(tmp_mod.main(),'auto_run',None)
|
||||
if run_object: run_object()
|
||||
|
||||
|
||||
def start():
|
||||
run_tips = '/dev/shm/bt_auto_run.pl'
|
||||
boot_time = psutil.boot_time()
|
||||
stime = time.time()
|
||||
if os.path.exists(run_tips):
|
||||
last_time = int(public.readFile(run_tips))
|
||||
if boot_time < last_time: return False
|
||||
if stime - 3600 > boot_time: return False
|
||||
|
||||
# --------------------- 调用自启动程序 ---------------------
|
||||
|
||||
project_model_auto_run()
|
||||
|
||||
# --------------------- 结束调用 ---------------------
|
||||
|
||||
public.writeFile(run_tips,str(int(stime)))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
start()
|
||||
@@ -0,0 +1,30 @@
|
||||
<VirtualHost *:{port}>
|
||||
ServerAdmin {server_admin}
|
||||
DocumentRoot "{site_path}"
|
||||
ServerName {server_name}
|
||||
ServerAlias {domains}
|
||||
#errorDocument 404 /404.html
|
||||
ErrorLog "{log_path}/{project_name}-error_log"
|
||||
CustomLog "{log_path}/{project_name}-access_log" combined
|
||||
|
||||
{ssl_config}
|
||||
|
||||
#DENY FILES
|
||||
<Files ~ (\.user.ini|\.htaccess|\.git|\.svn|\.project|LICENSE|README.md|package.json|package-lock.json|\.env)$>
|
||||
Order allow,deny
|
||||
Deny from all
|
||||
</Files>
|
||||
|
||||
#SSL
|
||||
ProxyPass /.well-known/ !
|
||||
Alias /.well-known/ /www/wwwroot/java_node_ssl/
|
||||
|
||||
# HTTP reverse proxy related settings begin >>>
|
||||
<IfModule mod_proxy.c>
|
||||
ProxyRequests Off
|
||||
SSLProxyEngine on
|
||||
ProxyPass / {url}/
|
||||
ProxyPassReverse / {url}/
|
||||
</IfModule>
|
||||
# End of HTTP reverse proxy related settings <<<
|
||||
</VirtualHost>
|
||||
@@ -0,0 +1,57 @@
|
||||
server
|
||||
{{
|
||||
{listen_ports}
|
||||
server_name {domains};
|
||||
index index.html index.htm default.htm default.html;
|
||||
# root {site_path};
|
||||
|
||||
#SSL-START SSL related configuration
|
||||
#error_page 404/404.html;
|
||||
{ssl_config}
|
||||
#SSL-END
|
||||
|
||||
#ERROR-PAGE-START Error page related configuration
|
||||
#error_page 404 /404.html;
|
||||
#error_page 502 /502.html;
|
||||
#ERROR-PAGE-END
|
||||
|
||||
|
||||
#REWRITE-START Pseudo-static related configuration
|
||||
include {panel_path}/vhost/rewrite/node_{project_name}.conf;
|
||||
#REWRITE-END
|
||||
|
||||
#Files or directories forbidden to access
|
||||
location ~ ^/(\.user.ini|\.htaccess|\.git|\.svn|\.project|LICENSE|README.md|package.json|package-lock.json|\.env|node_modules) {{
|
||||
return 404;
|
||||
}}
|
||||
|
||||
#One-click application for SSL certificate verification directory related settings
|
||||
location /.well-known/ {{
|
||||
root {site_path};
|
||||
}}
|
||||
|
||||
# HTTP reverse proxy related settings begin >>>
|
||||
location ~ /purge(/.*) {{
|
||||
proxy_cache_purge cache_one {host}$request_uri$is_args$args;
|
||||
}}
|
||||
|
||||
location / {{
|
||||
proxy_pass {url};
|
||||
proxy_set_header Host {host};
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header REMOTE-HOST $remote_addr;
|
||||
add_header X-Cache $upstream_cache_status;
|
||||
|
||||
proxy_connect_timeout 30s;
|
||||
proxy_read_timeout 86400s;
|
||||
proxy_send_timeout 30s;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
}}
|
||||
# End of HTTP reverse proxy related settings <<<
|
||||
|
||||
access_log {log_path}/{project_name}.log;
|
||||
error_log {log_path}/{project_name}.error.log;
|
||||
}}
|
||||
Reference in New Issue
Block a user