mirror of
https://github.com/aaPanel/aaPanel.git
synced 2026-09-13 04:57:38 +02:00
File management adds video playback
File sharing adds directory sharing and video playback functions Optimize file sharing UI Publish system firewall plugin Release Amazon storage plugin Other details adjustment
This commit is contained in:
+128
-46
@@ -144,7 +144,9 @@ admin_path_checks = [
|
||||
'/panel',
|
||||
'/acme',
|
||||
'/down',
|
||||
'/api'
|
||||
'/api',
|
||||
'/tips',
|
||||
'/message'
|
||||
]
|
||||
if admin_path in admin_path_checks: admin_path = '/bt'
|
||||
|
||||
@@ -210,7 +212,7 @@ def reload_mod():
|
||||
|
||||
@app.before_request
|
||||
def request_check():
|
||||
if not public.path_safe_check(request.path): return abort(404)
|
||||
#if not public.path_safe_check(request.path): return abort(404)
|
||||
if request.path in ['/service_status']: return
|
||||
|
||||
if not request.path in ['/safe','/hook','/public','/mail_sys','/down']:
|
||||
@@ -218,7 +220,7 @@ def request_check():
|
||||
if ip_check: return ip_check
|
||||
|
||||
if request.path.find('/static/') != -1 or request.path == '/code':
|
||||
if not 'login' in session and not 'admin_auth' in session:
|
||||
if not 'login' in session and not 'admin_auth' in session and not 'down' in session:
|
||||
session.clear()
|
||||
return abort(401)
|
||||
domain_check = public.check_domain_panel()
|
||||
@@ -272,6 +274,11 @@ 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')
|
||||
|
||||
|
||||
route_path = os.path.join(admin_path,'')
|
||||
if route_path[-1] == '/': route_path = route_path[:-1]
|
||||
if route_path[0] != '/': route_path = '/' + route_path
|
||||
@@ -395,7 +402,7 @@ def FtpPort():
|
||||
try:
|
||||
file = public.GetConfigValue('setup_path')+'/pure-ftpd/etc/pure-ftpd.conf'
|
||||
conf = public.readFile(file)
|
||||
rep = "\n#?\s*Bind\s+[0-9]+\.[0-9]+\.[0-9]+\.+[0-9]+,([0-9]+)"
|
||||
rep = r"\n#?\s*Bind\s+[0-9]+\.[0-9]+\.[0-9]+\.+[0-9]+,([0-9]+)"
|
||||
port = re.search(rep,conf).groups()[0]
|
||||
except:
|
||||
port='21'
|
||||
@@ -466,6 +473,15 @@ def acme(pdata = None):
|
||||
'get_auths','auth_domain','check_auth_status','download_cert','apply_cert','renew_cert','apply_cert_api','apply_dns_auth')
|
||||
return publicObject(acme_v2_object,defs,None,pdata)
|
||||
|
||||
@app.route('/message/<action>',methods=method_all)
|
||||
def message(action = None):
|
||||
comReturn = comm.local()
|
||||
if comReturn: return comReturn
|
||||
import panelMessage
|
||||
message_object = panelMessage.panelMessage()
|
||||
defs = ('get_messages','get_message_find','create_message','status_message','remove_message','get_messages_all')
|
||||
return publicObject(message_object,defs,action,None)
|
||||
|
||||
@app.route('/api',methods=method_all)
|
||||
def api(pdata = None):
|
||||
comReturn = comm.local()
|
||||
@@ -520,8 +536,8 @@ def ssh_security(pdata = None):
|
||||
return render_template( 'firewall.html',data=data)
|
||||
import ssh_security
|
||||
firewallObject = ssh_security.ssh_security()
|
||||
defs = ('get_logs','san_ssh_security','set_password','set_sshkey','stop_key','get_config',
|
||||
'stop_password','get_key','return_ip','add_return_ip','del_return_ip','start_jian','stop_jian','get_jian')
|
||||
defs = ('san_ssh_security','set_password','set_sshkey','stop_key','get_config',
|
||||
'stop_password','get_key','return_ip','add_return_ip','del_return_ip','start_jian','stop_jian','get_jian','get_logs')
|
||||
return publicObject(firewallObject,defs,None,pdata)
|
||||
|
||||
|
||||
@@ -612,7 +628,7 @@ def files(pdata = None):
|
||||
'CheckExistsFiles','GetExecLog','GetSearch','ExecShell','GetExecShellMsg','exec_git','exec_composer','create_download_url',
|
||||
'UploadFile','GetDir','CreateFile','CreateDir','DeleteDir','DeleteFile','get_download_url_list','remove_download_url','modify_download_url',
|
||||
'CopyFile','CopyDir','MvFile','GetFileBody','SaveFileBody','Zip','UnZip','get_download_url_find',
|
||||
'SearchFiles','upload','read_history','re_history','auto_save_temp','get_auto_save_body',
|
||||
'SearchFiles','upload','read_history','re_history','auto_save_temp','get_auto_save_body','get_videos',
|
||||
'GetFileAccess','SetFileAccess','GetDirSize','SetBatchData','BatchPaste','install_rar','get_path_size',
|
||||
'DownloadFile','GetTaskSpeed','CloseLogs','InstallSoft','UninstallSoft','SaveTmpFile','get_composer_version','exec_composer','update_composer',
|
||||
'GetTmpFile','del_files_store','add_files_store','get_files_store','del_files_store_types','add_files_store_types','exec_git',
|
||||
@@ -807,6 +823,13 @@ def plugin(pdata = None):
|
||||
@app.route('/public',methods=method_all)
|
||||
def panel_public():
|
||||
get = get_input()
|
||||
try:
|
||||
import panelWaf
|
||||
panelWaf_data = panelWaf.panelWaf()
|
||||
if panelWaf_data.is_sql(get.__dict__):return 'ERROR'
|
||||
if panelWaf_data.is_xss(get.__dict__):return 'ERROR'
|
||||
except:
|
||||
pass
|
||||
get.client_ip = public.GetClientIp()
|
||||
if not hasattr(get,'name'): get.name = ''
|
||||
if not hasattr(get,'fun'): return abort(404)
|
||||
@@ -1064,50 +1087,109 @@ def download():
|
||||
if filename in ['alioss','qiniu','upyun','txcos','ftp']: return panel_cloud()
|
||||
if filename in ['gdrive','gcloud_storage']: return "Google storage products do not currently support downloads"
|
||||
if not os.path.exists(filename): return public.ReturnJson(False,"FILE_NOT_EXISTS"),json_header
|
||||
mimetype = "application/octet-stream"
|
||||
extName = filename.split('.')[-1]
|
||||
if extName in ['png','gif','jpeg','jpg']: mimetype = None
|
||||
return send_file(filename,mimetype=mimetype,
|
||||
as_attachment=True,
|
||||
attachment_filename=os.path.basename(filename),
|
||||
cache_timeout=0)
|
||||
|
||||
@app.route('/down/<token>',methods=method_all)
|
||||
def down(token=None,mdown=None):
|
||||
try:
|
||||
if not token: return abort(404)
|
||||
if len(token) != 12: return abort(404)
|
||||
if not re.match(r"^\w+$",token): return abort(404)
|
||||
find = public.M('download_token').where('token=?',(token,)).find()
|
||||
if not find: return abort(404)
|
||||
if time.time() > int(find['expire']): return abort(404)
|
||||
if not os.path.exists(find['filename']): return abort(404)
|
||||
if find['password']:
|
||||
args = get_input()
|
||||
if 'file_password' in args:
|
||||
if not re.match(r"^\w+$",args.file_password):
|
||||
return public.ReturnJson(False,'wrong password!'),json_header
|
||||
if not args.file_password == find['password']:
|
||||
return public.ReturnJson(False,'wrong password!'),json_header
|
||||
else:
|
||||
pdata = {
|
||||
"password":True,
|
||||
"filename":find['filename'].split('/')[-1],
|
||||
"total":find['total'],
|
||||
"token":find['token'],
|
||||
"expire":find['expire']
|
||||
}
|
||||
return render_template('down.html',data = pdata)
|
||||
|
||||
filename = find['filename']
|
||||
if request.args.get('play') == 'true':
|
||||
import panelVideo
|
||||
start, end = panelVideo.get_range(request)
|
||||
return panelVideo.partial_response(filename, start, end)
|
||||
else:
|
||||
mimetype = "application/octet-stream"
|
||||
extName = filename.split('.')[-1]
|
||||
if extName in ['png','gif','jpeg','jpg']: mimetype = None
|
||||
return send_file(filename,mimetype=mimetype,
|
||||
as_attachment=True,
|
||||
attachment_filename=os.path.basename(filename),
|
||||
cache_timeout=0)
|
||||
except: return abort(404)
|
||||
as_attachment=True,
|
||||
attachment_filename=os.path.basename(filename),
|
||||
cache_timeout=0)
|
||||
|
||||
def get_dir_down(filename,token,find):
|
||||
import files
|
||||
args = public.dict_obj()
|
||||
args.path = filename
|
||||
to_path = filename.replace(find['filename'],'').strip('/')
|
||||
|
||||
if request.args.get('play') == 'true':
|
||||
pdata = files.files().get_videos(args)
|
||||
return public.GetJson(pdata),json_header
|
||||
else:
|
||||
pdata = files.files().GetDir(args)
|
||||
pdata['token'] = token
|
||||
pdata['src_path'] = find['filename']
|
||||
pdata['to_path'] = to_path
|
||||
pdata['expire'] = public.format_date(times=find['expire'])
|
||||
pdata['filename'] = (find['filename'].split('/')[-1] + '/' + to_path).strip('/')
|
||||
return render_template('down.html',data = pdata,to_size=public.to_size)
|
||||
|
||||
@app.route('/down/<token>',methods=method_all)
|
||||
def down(token=None,fname=None):
|
||||
try:
|
||||
fname = request.args.get('fname')
|
||||
if fname:
|
||||
if(len(fname) > 256): return abort(404)
|
||||
if fname: fname = fname.strip('/')
|
||||
if not token: return abort(404)
|
||||
if len(token) != 12: return abort(404)
|
||||
if not request.args.get('play') in ['true',None,'']:
|
||||
return abort(404)
|
||||
|
||||
if not re.match(r"^\w+$",token): return abort(404)
|
||||
find = public.M('download_token').where('token=?',(token,)).find()
|
||||
|
||||
if not find: return abort(404)
|
||||
if time.time() > int(find['expire']): return abort(404)
|
||||
|
||||
if not os.path.exists(find['filename']): return abort(404)
|
||||
if find['password'] and not token in session:
|
||||
args = get_input()
|
||||
if 'file_password' in args:
|
||||
if not re.match(r"^\w+$",args.file_password):
|
||||
return public.ReturnJson(False,'Wrong password!'),json_header
|
||||
if re.match(r"^\d+$",args.file_password):
|
||||
args.file_password += '.0'
|
||||
if args.file_password != str(find['password']):
|
||||
return public.ReturnJson(False,'Wrong password!'),json_header
|
||||
session[token] = 1
|
||||
session['down'] = True
|
||||
else:
|
||||
pdata = {
|
||||
"to_path":"",
|
||||
"src_path": find['filename'],
|
||||
"password":True,
|
||||
"filename":find['filename'].split('/')[-1],
|
||||
"total":find['total'],
|
||||
"token":find['token'],
|
||||
"expire":public.format_date(times=find['expire'])
|
||||
}
|
||||
return render_template('down.html',data = pdata)
|
||||
if not find['password']:
|
||||
session[token] = 1
|
||||
|
||||
if session[token] != 1:
|
||||
return abort(404)
|
||||
|
||||
filename = find['filename']
|
||||
if fname:
|
||||
filename = os.path.join(filename,fname)
|
||||
if not public.path_safe_check(fname,False): return abort(404)
|
||||
if os.path.isdir(filename):
|
||||
return get_dir_down(filename,token,find)
|
||||
else:
|
||||
if os.path.isdir(filename):
|
||||
return get_dir_down(filename,token,find)
|
||||
|
||||
if request.args.get('play') == 'true':
|
||||
import panelVideo
|
||||
start, end = panelVideo.get_range(request)
|
||||
return panelVideo.partial_response(filename, start, end)
|
||||
else:
|
||||
mimetype = "application/octet-stream"
|
||||
extName = filename.split('.')[-1]
|
||||
if extName in ['png','gif','jpeg','jpg']: mimetype = None
|
||||
return send_file(filename,mimetype=mimetype,
|
||||
as_attachment=True,
|
||||
attachment_filename=os.path.basename(filename),
|
||||
cache_timeout=0)
|
||||
except:
|
||||
return abort(404)
|
||||
|
||||
|
||||
@app.route('/cloud',methods=method_get)
|
||||
|
||||
@@ -1137,10 +1137,8 @@ html .menu .menu_exit:hover {
|
||||
border-bottom: 1px solid #e6e6e6;
|
||||
color: #666;
|
||||
font-weight: normal;
|
||||
padding: 5px 10px;
|
||||
height: 35px;
|
||||
padding: 8px;
|
||||
font-size: 12.5px;
|
||||
box-sizing: content-box;
|
||||
}
|
||||
.divtable .table_toolbar{
|
||||
left: 8px;
|
||||
@@ -6697,4 +6695,41 @@ select[disabled]{
|
||||
}
|
||||
.php_info_group:last-child{
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
#btvideo{
|
||||
display: inline-block;
|
||||
height: 360px;
|
||||
}
|
||||
.video-list{
|
||||
display: inline-block;
|
||||
width: 250px;
|
||||
height: 360px;
|
||||
overflow: auto;
|
||||
}
|
||||
.video-list .video-avt{
|
||||
background-color: #e8e8e8;
|
||||
}
|
||||
.movie_pay .layui-layer-content{
|
||||
overflow: hidden !important;
|
||||
}
|
||||
.video-list .video-avt td a,
|
||||
.video-list .video-avt td{
|
||||
color: #20a53a;
|
||||
}
|
||||
.video-list tr td{
|
||||
border-top: 0px;
|
||||
border-bottom: 1px solid #ddd;
|
||||
}
|
||||
.video-list tr:hover{
|
||||
cursor: pointer;
|
||||
}
|
||||
#btvideo video{
|
||||
outline: none;
|
||||
padding: 0;
|
||||
display: block;
|
||||
background-color: #000;
|
||||
}
|
||||
.minText{
|
||||
white-space: nowrap;
|
||||
}
|
||||
+89
-32
@@ -473,7 +473,8 @@ function GetFiles(Path, sort) {
|
||||
if (getCookie("rank") == "a") {
|
||||
$("#set_list").addClass("active");
|
||||
$("#set_icon").removeClass("active");
|
||||
Body += "<tr class='folderBoxTr' data-composer='"+fmp[7]+"' data-path='" + rdata.PATH + "/" + fmp[0] + "' filetype='dir'>\
|
||||
if (rdata.PATH=='/') rdata.PATH = '';
|
||||
Body += "<tr class='folderBoxTr' fileshare='"+ fmp[6] +"' data-composer='"+fmp[7]+"' data-path='" + rdata.PATH + "/" + fmp[0] + "' filetype='dir'>\
|
||||
<td><input type='checkbox' name='id' value='" + fmp[0] + "'></td>\
|
||||
<td class='column-name'><span class='cursor' onclick=\"GetFiles('" + rdata.PATH + "/" + fmp[0] + "')\"><span class='ico ico-folder'></span><a class='text' title='" + fmp[0] + fmp[5] + "'>" + cnametext + fileMsg + "</a></span></td>\
|
||||
<td><a class='btlink " + (rdata.PATH + '/' + fmp[0]).replace(/[^\w]/g, '-') + "' onclick=\"get_path_size('" + rdata.PATH + "/" + fmp[0] + "')\">" + lan.files.calc_click + "</a></td>\
|
||||
@@ -491,7 +492,7 @@ function GetFiles(Path, sort) {
|
||||
} else {
|
||||
$("#set_icon").addClass("active");
|
||||
$("#set_list").removeClass("active");
|
||||
Body += "<div class='file folderBox menufolder' data-path='" + rdata.PATH + "/" + fmp[0] + "' filetype='dir' title='" + lan.files.file_name + ":" + fmp[0] + " " + lan.files.file_size + ":" + ToSize(fmp[1]) + " " + lan.files.file_etime + ":" + getLocalTime(fmp[2]) + " " + lan.files.file_auth + ":" + fmp[3] + " " + lan.files.file_own + ":" + fmp[4] + "'>\
|
||||
Body += "<div class='file folderBox menufolder' fileshare='"+ fmp[6] +"' data-path='" + rdata.PATH + "/" + fmp[0] + "' filetype='dir' title='" + lan.files.file_name + ":" + fmp[0] + " " + lan.files.file_size + ":" + ToSize(fmp[1]) + " " + lan.files.file_etime + ":" + getLocalTime(fmp[2]) + " " + lan.files.file_auth + ":" + fmp[3] + " " + lan.files.file_own + ":" + fmp[4] + "'>\
|
||||
<input type='checkbox' name='id' value='" + fmp[0] + "'>\
|
||||
<div class='ico ico-folder' ondblclick=\"GetFiles('" + rdata.PATH + "/" + fmp[0] + "')\"></div>\
|
||||
<div class='titleBox' onclick=\"GetFiles('" + rdata.PATH + "/" + fmp[0] + "')\"><span class='tname'>" + fmp[0] + "</span></div>\
|
||||
@@ -524,6 +525,9 @@ function GetFiles(Path, sort) {
|
||||
if (isText(fmp[0])) {
|
||||
bodyZip = "<a class='btlink' href='javascript:;' onclick=\"openEditorView(0,'" + rdata.PATH + "/" + fmp[0] + "')\">" + lan.files.file_menu_edit + "</a> | ";
|
||||
}
|
||||
if (isVideo(fmp[0])) {
|
||||
bodyZip = "<a class='btlink' href='javascript:;' onclick=\"GetPlay('" + rdata.PATH + "/" + fmp[0] + "')\">Play</a> | ";
|
||||
}
|
||||
if (isImage(fmp[0])) {
|
||||
download = "<a class='btlink' href='javascript:;' onclick=\"GetImage('" + rdata.PATH + "/" + fmp[0] + "')\">" + lan.files.file_menu_img + "</a> | ";
|
||||
} else {
|
||||
@@ -568,7 +572,7 @@ function GetFiles(Path, sort) {
|
||||
<a class='btlink' href='javascript:;' onclick=\"DeleteFile('" + rdata.PATH + "/" + fmp[0] + "')\">" + lan.files.file_menu_del + "</a>\
|
||||
</span></td></tr>";
|
||||
} else {
|
||||
Body += "<div class='file folderBox menufile' data-path='" + rdata.PATH + "/" + fmp[0] + "' filetype='" + fmp[0] + "' title='" + lan.files.file_name + ":" + fmp[0] + " " + lan.files.file_size + ":" + ToSize(fmp[1]) + " " + lan.files.file_etime + ":" + getLocalTime(fmp[2]) + " " + lan.files.file_auth + ":" + fmp[3] + " " + lan.files.file_own + ":" + fmp[4] + "'>\
|
||||
Body += "<div class='file folderBox menufile' fileshare='"+ fmp[6] +"' data-path='" + rdata.PATH + "/" + fmp[0] + "' filetype='" + fmp[0] + "' title='" + lan.files.file_name + ":" + fmp[0] + " " + lan.files.file_size + ":" + ToSize(fmp[1]) + " " + lan.files.file_etime + ":" + getLocalTime(fmp[2]) + " " + lan.files.file_auth + ":" + fmp[3] + " " + lan.files.file_own + ":" + fmp[4] + "'>\
|
||||
<input type='checkbox' name='id' value='" + fmp[0] + "'>\
|
||||
<div class='ico ico-" + (GetExtName(fmp[0])) + "'></div>\
|
||||
<div class='titleBox'><span class='tname'>" + fmp[0] + "</span></div>\
|
||||
@@ -600,11 +604,11 @@ function GetFiles(Path, sort) {
|
||||
<tr>\
|
||||
<th width="30"><input type="checkbox" id="setBox" placeholder=""></th>\
|
||||
<th><a style="cursor: pointer;" class="btlink" onclick="GetFiles(' + p + ',\'name\')">' + lan.files.file_name + ((data['sort'] === 'name' || !data['sort']) ? sort_icon : '') + '</a></th>\
|
||||
<th><a style="cursor: pointer;" class="btlink" onclick="GetFiles(' + p + ',\'size\')">' + lan.files.file_size + ((data['sort'] === 'size') ? sort_icon : '') + '</a></th>\
|
||||
<th><a style="cursor: pointer;" class="btlink" onclick="GetFiles(' + p + ',\'mtime\')">' + lan.files.file_etime + ((data['sort'] === 'mtime') ? sort_icon : '') + '</a></th>\
|
||||
<th><a style="cursor: pointer;" class="btlink" onclick="GetFiles(' + p + ',\'accept\')">' + lan.files.file_auth + ((data['sort'] === 'accept') ? sort_icon : '') + '</a></th>\
|
||||
<th><a style="cursor: pointer;" class="btlink" onclick="GetFiles(' + p + ',\'user\')">' + lan.files.file_own + ((data['sort'] === 'user') ? sort_icon : '') + '</a></th>\
|
||||
<th style="text-align: right;" width="405">' + lan.files.file_act + '</th>\
|
||||
<th><a style="cursor: pointer;display: inline-block;min-width: 58px;" class="btlink" onclick="GetFiles(' + p + ',\'size\')">' + lan.files.file_size + ((data['sort'] === 'size') ? sort_icon : '') + '</a></th>\
|
||||
<th><a style="cursor: pointer;" class="btlink minText" onclick="GetFiles(' + p + ',\'mtime\')">' + lan.files.file_etime + ((data['sort'] === 'mtime') ? sort_icon : '') + '</a></th>\
|
||||
<th><a style="cursor: pointer;" class="btlink minText" onclick="GetFiles(' + p + ',\'accept\')">' + lan.files.file_auth + ((data['sort'] === 'accept') ? sort_icon : '') + '</a></th>\
|
||||
<th><a style="cursor: pointer;" class="btlink minText" onclick="GetFiles(' + p + ',\'user\')">' + lan.files.file_own + ((data['sort'] === 'user') ? sort_icon : '') + '</a></th>\
|
||||
<th style="text-align: right;" width="430">' + lan.files.file_act + '</th>\
|
||||
</tr>\
|
||||
</thead>\
|
||||
<tbody id="filesBody" class="list-list">' + Body + '</tbody>\
|
||||
@@ -639,7 +643,7 @@ function GetFiles(Path, sort) {
|
||||
<ul class="dropdown-menu">'
|
||||
|
||||
for (var i = 0; i < rdata.STORE.length; i++) {
|
||||
shtml += '<li class="file-types" title="' + rdata.STORE[i].path + '"><div style="width:200px"><span class="ico ' + (rdata.STORE[i].type === 'file' ? 'ico-file' : 'ico-folder') + '"></span><a href="javascript:;" style="display: inline-block;width:150px;overflow: hidden;text-overflow: ellipsis;vertical-align: top;" onclick="' + (rdata.STORE[i].type === 'file' ? 'openEditorView(0,\'' + rdata.STORE[i].path + '\')' : 'GetFiles(\'' + rdata.STORE[i].path + '\')') + '">' + rdata.STORE[i].name + '</a></div>';
|
||||
shtml += '<li class="file-types" title="' + rdata.STORE[i].path + '"><div style="width:200px"><span class="ico ' + (rdata.STORE[i].type === 'file' ? 'ico-file' : 'ico-folder') + '"></span><a href="javascript:;" style="display: inline-block;width:150px;overflow: hidden;text-overflow: ellipsis;vertical-align: top;white-space: nowrap;" onclick="' + (rdata.STORE[i].type === 'file' ? 'openEditorView(0,\'' + rdata.STORE[i].path + '\')' : 'GetFiles(\'' + rdata.STORE[i].path + '\')') + '">' + rdata.STORE[i].name + '</a></div>';
|
||||
}
|
||||
shtml += '<li style="text-align: center;"><a href="javascript: ;" onclick="set_file_store(\'' + rdata.PATH + '\')">+ Management</a></li></ul></div>'
|
||||
|
||||
@@ -723,8 +727,12 @@ function GetFiles(Path, sort) {
|
||||
if (e.which == 3) {
|
||||
if (count <= 1) {
|
||||
var a = $(this);
|
||||
a.contextify(RClick(a.attr("filetype"), a.attr("data-path"), a.find("input").val(), rdata, a.attr('fileshare'),a.attr('data-composer')));
|
||||
} else {
|
||||
a.contextify(RClick(a.attr("filetype"), a.attr("data-path"), a.find("input").val(), rdata,a.attr('fileshare'),a.attr('data-composer')));
|
||||
$(this).find('input').prop("checked", true);
|
||||
$(this).addClass('ui-selected');
|
||||
$(this).siblings().removeClass('ui-selected').find('input').prop("checked", false);
|
||||
}
|
||||
else {
|
||||
RClickAll(e);
|
||||
}
|
||||
}
|
||||
@@ -773,7 +781,7 @@ function php_file_webshell(file) {
|
||||
}
|
||||
|
||||
function auto_table_width() {
|
||||
var oldTable = $(window).height() - $('#tipTools')[0].getBoundingClientRect().height - $('#filePage')[0].getBoundingClientRect().height - $('.footer')[0].getBoundingClientRect().height - 121;
|
||||
var oldTable = $(window).height() - $('#tipTools')[0].getBoundingClientRect().height - $('#filePage')[0].getBoundingClientRect().height - $('.footer')[0].getBoundingClientRect().height - 111;
|
||||
var oldTable_heigth = $('.oldTable table').height();
|
||||
$('.oldTable thead th').each(function (index, el) {
|
||||
var table_th = $('.oldTable thead th').length;
|
||||
@@ -1655,21 +1663,63 @@ function GetImage(fileName) {
|
||||
$(".layui-layer").css("top", "30%");
|
||||
}
|
||||
|
||||
// function GetPlay(fileName) {
|
||||
// var imgUrl = '/download?filename=' + fileName;
|
||||
// layer.open({
|
||||
// type: 1,
|
||||
// closeBtn: 2,
|
||||
// title: 'Play [' + fileName + ']',
|
||||
// area: '500px',
|
||||
// shadeClose: false,
|
||||
// content: '<div class="showpicdiv"><video src="' + imgUrl + '" controls="controls" autoplay="autoplay" width="100%" type="video/mp4">\
|
||||
// Your browser does not support the video tag.\
|
||||
// </video></div>'
|
||||
// });
|
||||
// $(".layui-layer").css("top", "30%");
|
||||
// }
|
||||
function play_file(obj,filename) {
|
||||
console.log($('#btvideo video').attr('data-filename'),filename)
|
||||
if($('#btvideo video').attr('data-filename')== filename) return false;
|
||||
var imgUrl = '/download?filename=' + filename + '&play=true';
|
||||
var v = '<video src="' + imgUrl +'" controls="controls" data-fileName="'+ filename +'" autoplay="autoplay" width="640" height="360">\
|
||||
Your browser does not support Video Tags.\
|
||||
</video>'
|
||||
$("#btvideo").html(v);
|
||||
var p_tmp = filename.split('/')
|
||||
$(".btvideo-title").html(p_tmp[p_tmp.length-1]);
|
||||
$(".video-avt").removeClass('video-avt');
|
||||
$(obj).parents('tr').addClass('video-avt');
|
||||
}
|
||||
function GetPlay(fileName) {
|
||||
var old_filename = fileName;
|
||||
var imgUrl = '/download?filename=' + fileName;
|
||||
var p_tmp = fileName.split('/')
|
||||
var path = p_tmp.slice(0, p_tmp.length - 1).join('/')
|
||||
layer.open({
|
||||
type: 1,
|
||||
closeBtn: 2,
|
||||
title: 'Play [' + fileName + ']',
|
||||
area: '500px',
|
||||
// maxmin:true,
|
||||
title: 'Playing [<a class="btvideo-title">' + p_tmp[p_tmp.length-1] + '</a>]',
|
||||
area: ["890px","402px"],
|
||||
shadeClose: false,
|
||||
content: '<div class="showpicdiv"><video src="' + imgUrl + '" controls="controls" autoplay="autoplay" width="100%" type="video/mp4">\
|
||||
Your browser does not support the video tag.\
|
||||
</video></div>'
|
||||
skin:'movie_pay',
|
||||
content: '<div id="btvideo"><video type="" src="' + imgUrl + '&play=true" data-filename="'+ fileName +'" controls="controls" autoplay="autoplay" width="640" height="360">\
|
||||
Your browser does not support Video Tags.\
|
||||
</video></div><div class="video-list"></div>',
|
||||
success: function () {
|
||||
$.post('/files?action=get_videos', { path: path }, function (rdata) {
|
||||
var video_list = '<table class="table table-hover" style=""><thead style="display: none;"><tr><th style="word-break: break-all;word-wrap:break-word;width:165px;">File name</th><th style="width:65px" style="text-align:right;">Size</th></tr></thead>';
|
||||
for (var i = 0; i < rdata.length; i++) {
|
||||
var filename = path + '/' + rdata[i].name
|
||||
video_list += '<tr class="' + ((filename === old_filename) ? 'video-avt' :'') + '"><td style="word-break: break-all;word-wrap:break-word;width:150px" onclick="play_file(this,\'' + filename + '\')" title="File: ' + filename + '\ntype: ' + rdata[i].type + '"><a>'
|
||||
+ rdata[i].name + '</a></td><td style="font-size: 8px;text-align:right;width:65px;">' + ToSize(rdata[i].size) + '</td></tr>';
|
||||
}
|
||||
video_list += '</table>';
|
||||
$('.video-list').html(video_list);
|
||||
});
|
||||
}
|
||||
});
|
||||
$(".layui-layer").css("top", "30%");
|
||||
}
|
||||
|
||||
function GetFileBytes(fileName, fileSize) {
|
||||
window.open('/download?filename=' + encodeURIComponent(fileName));
|
||||
}
|
||||
@@ -2648,9 +2698,9 @@ function RClick(type, path, name, file_store, file_share,data_composer) {
|
||||
}
|
||||
})
|
||||
}
|
||||
//else if (isVideo(type)) {
|
||||
// options.items.push({ text: '播放', onclick: function () { GetPlay(path) } }, { text: lan.files.file_menu_down, onclick: function () { GetFileBytes(path) } }, { text: lan.files.file_menu_del, onclick: function () { DeleteFile(path) } });
|
||||
//}
|
||||
else if (isVideo(type)) {
|
||||
options.items.push({ text: 'Play', onclick: function () { GetPlay(path) } }, { text: lan.files.file_menu_down, onclick: function () { GetFileBytes(path) } }, { text: lan.files.file_menu_del, onclick: function () { DeleteFile(path) } });
|
||||
}
|
||||
else if (isText(type)) {
|
||||
options.items.push({
|
||||
text: lan.files.file_menu_edit,
|
||||
@@ -2715,15 +2765,21 @@ function RClick(type, path, name, file_store, file_share,data_composer) {
|
||||
}
|
||||
});
|
||||
}
|
||||
if (type !== 'dir') {
|
||||
options.items.push({
|
||||
text: 'Share',
|
||||
onclick: function () {
|
||||
create_download_url(name, path, file_share)
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// if (type !== 'dir') {
|
||||
// options.items.push({
|
||||
// text: 'Share',
|
||||
// onclick: function () {
|
||||
// create_download_url(name, path, file_share)
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
// if(type !== 'dir'){
|
||||
// options.items.push({ text: 'Share', onclick: function () { create_download_url(name,path,file_share) } });
|
||||
// }
|
||||
|
||||
options.items.push({ text: 'Share', onclick: function () {
|
||||
create_download_url(name,path,file_share) } });
|
||||
|
||||
if( type === 'dir' && data_composer === '1'){
|
||||
options.items.push({ text: 'Composer', onclick: function () { exec_composer(name,path) } });
|
||||
}
|
||||
@@ -2839,9 +2895,10 @@ function show_composer_log(){
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function create_download_url(fileName, path, fileShare) {
|
||||
fileShare = parseInt(fileShare);
|
||||
if (fileShare != 0) {
|
||||
if(fileShare != 0) {
|
||||
$.post('/files?action=get_download_url_find', {
|
||||
id: fileShare
|
||||
}, function (rdata) {
|
||||
|
||||
@@ -1175,7 +1175,7 @@ var aceEditor = {
|
||||
_this = this;
|
||||
var loadT = layer.open({
|
||||
type: 1,
|
||||
area: ['400px', '180px'],
|
||||
area: ['400px', '200px'],
|
||||
title: lan.public.restore_history_files,
|
||||
content: '<div class="ace-clear-form">\
|
||||
<div class="clear-icon"></div>\
|
||||
|
||||
@@ -2016,7 +2016,7 @@ var soft = {
|
||||
{
|
||||
field: 'opt',
|
||||
title: lan.public.action,
|
||||
width: 50,
|
||||
width: 60,
|
||||
templet: function(item) {
|
||||
var opt = '<a class="btlink lib-install" data-name="' + item.name + '" data-title="' + item.title + '" href="javascript:;">' + lan.soft.install + '</a>'
|
||||
if (item['task'] == '-1' && item.phpversions.indexOf(version) != -1) {
|
||||
|
||||
+1239
-17
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
+20
-9
@@ -666,9 +666,6 @@ class ajax:
|
||||
else:
|
||||
conf_file = "/www/server/panel/vhost/apache/phpmyadmin.conf"
|
||||
rep = "Listen\s*(\d+)"
|
||||
# else:
|
||||
# conf_file = "/www/server/panel/vhost/openlitespeed/listen/888.conf"
|
||||
# rep = "address\s+\*:(\d+)"
|
||||
return {"conf_file":conf_file,"rep":rep}
|
||||
|
||||
# 设置phpmyadmin路径
|
||||
@@ -1063,15 +1060,29 @@ class ajax:
|
||||
|
||||
#取PHP-FPM日志
|
||||
def GetFpmLogs(self,get):
|
||||
path = '/www/server/php/' + get.version + '/var/log/php-fpm.log'
|
||||
if not os.path.exists(path): return public.returnMsg(False,'AJAX_LOG_FILR_NOT_EXISTS')
|
||||
return public.returnMsg(True,public.GetNumLines(path,1000))
|
||||
import re
|
||||
fpm_path = '/www/server/php/' + get.version + '/etc/php-fpm.conf'
|
||||
if not os.path.exists(fpm_path): return public.returnMsg(False,'AJAX_LOG_FILR_NOT_EXISTS')
|
||||
fpm_conf = public.readFile(fpm_path)
|
||||
log_tmp = re.findall(r"error_log\s*=\s*(.+)",fpm_conf)
|
||||
if not log_tmp: return public.returnMsg(False,'AJAX_LOG_FILR_NOT_EXISTS')
|
||||
log_file = log_tmp[0].strip()
|
||||
if log_file.find('var/log') == 0:
|
||||
log_file = '/www/server/php/' +get.version + '/'+ log_file
|
||||
return public.returnMsg(True,public.GetNumLines(log_file,1000))
|
||||
|
||||
#取PHP慢日志
|
||||
def GetFpmSlowLogs(self,get):
|
||||
path = '/www/server/php/' + get.version + '/var/log/slow.log'
|
||||
if not os.path.exists(path): return public.returnMsg(False,'AJAX_LOG_FILR_NOT_EXISTS')
|
||||
return public.returnMsg(True,public.GetNumLines(path,1000))
|
||||
import re
|
||||
fpm_path = '/www/server/php/' + get.version + '/etc/php-fpm.conf'
|
||||
if not os.path.exists(fpm_path): return public.returnMsg(False,'AJAX_LOG_FILR_NOT_EXISTS')
|
||||
fpm_conf = public.readFile(fpm_path)
|
||||
log_tmp = re.findall(r"slowlog\s*=\s*(.+)",fpm_conf)
|
||||
if not log_tmp: return public.returnMsg(False,'AJAX_LOG_FILR_NOT_EXISTS')
|
||||
log_file = log_tmp[0].strip()
|
||||
if log_file.find('var/log') == 0:
|
||||
log_file = '/www/server/php/' +get.version + '/'+ log_file
|
||||
return public.returnMsg(True,public.GetNumLines(log_file,1000))
|
||||
|
||||
#取指定日志
|
||||
def GetOpeLogs(self,get):
|
||||
|
||||
+1
-1
@@ -34,7 +34,7 @@ class panelSetup:
|
||||
ua = ua.lower()
|
||||
if ua.find('spider') != -1 or ua.find('bot') != -1:
|
||||
return redirect('https://www.google.com')
|
||||
g.version = '6.6.9'
|
||||
g.version = '6.7.0'
|
||||
g.title = public.GetConfigValue('title')
|
||||
g.uri = request.path
|
||||
if not os.path.exists('data/debug.pl'):
|
||||
|
||||
+4
-4
@@ -103,7 +103,7 @@ class Sql():
|
||||
i=0
|
||||
tmp1 = {}
|
||||
for key in fields:
|
||||
tmp1[key] = row[i]
|
||||
tmp1[key.strip('`')] = row[i]
|
||||
i += 1
|
||||
tmp.append(tmp1)
|
||||
del(tmp1)
|
||||
@@ -127,7 +127,7 @@ class Sql():
|
||||
import re
|
||||
fields = []
|
||||
for key in field:
|
||||
s_as = re.search('\s+as\s+',key,flags=re.IGNORECASE)
|
||||
s_as = re.search(r'\s+as\s+',key,flags=re.IGNORECASE)
|
||||
if s_as:
|
||||
as_tip = s_as.group()
|
||||
key = key.split(as_tip)[1]
|
||||
@@ -139,13 +139,13 @@ class Sql():
|
||||
tmp_cols = self.query('PRAGMA table_info('+self.__DB_TABLE+')',())
|
||||
cols = []
|
||||
for col in tmp_cols:
|
||||
if len(col) > 2: cols.append(col[1])
|
||||
if len(col) > 2: cols.append('`' + col[1] + '`')
|
||||
if len(cols) > 0: self.__OPT_FIELD = ','.join(cols)
|
||||
|
||||
def getField(self,keyName):
|
||||
#取回指定字段
|
||||
try:
|
||||
result = self.field(keyName).select();
|
||||
result = self.field(keyName).select()
|
||||
if len(result) != 0:
|
||||
return result[0][keyName]
|
||||
return result
|
||||
|
||||
+30
-11
@@ -353,7 +353,7 @@ session.save_handler = files'''.format(path, sess_path, sess_path)
|
||||
size = str(stat.st_size)
|
||||
if os.path.isdir(filePath):
|
||||
dirnames.append(filename+';'+size+';' +
|
||||
mtime+';'+accept+';'+user+';'+link + ';0;' + self.is_composer_json(filePath))
|
||||
mtime+';'+accept+';'+user+';'+link + ';' +self.get_download_id(filePath)+';'+ self.is_composer_json(filePath))
|
||||
else:
|
||||
filenames.append(filename+';'+size+';'+mtime+';'+accept+';'+user+';'+link+';'+self.get_download_id(filePath))
|
||||
n += 1
|
||||
@@ -502,6 +502,27 @@ session.save_handler = files'''.format(path, sess_path, sess_path)
|
||||
filename = filename.replace(tmp_path, '')
|
||||
return filename + ';' + size + ';' + mtime + ';' + accept + ';' + user + ';' + link+';'+ down_url
|
||||
|
||||
#获取指定目录下的所有视频或音频文件
|
||||
def get_videos(self,args):
|
||||
path = args.path.strip()
|
||||
v_data = []
|
||||
if not os.path.exists(path): return v_data
|
||||
import mimetypes
|
||||
for fname in os.listdir(path):
|
||||
try:
|
||||
filename = os.path.join(path,fname)
|
||||
if not os.path.exists(filename): continue
|
||||
if not os.path.isfile(filename): continue
|
||||
v_tmp = {}
|
||||
v_tmp['name'] = fname
|
||||
v_tmp['type'] = mimetypes.guess_type(filename)[0]
|
||||
v_tmp['size'] = os.path.getsize(filename)
|
||||
if not v_tmp['type'].split('/')[0] in ['video']:
|
||||
continue
|
||||
v_data.append(v_tmp)
|
||||
except:continue
|
||||
return sorted(v_data,key=lambda x:x['name'])
|
||||
|
||||
# 计算文件数量
|
||||
def GetFilesCount(self, path, search):
|
||||
if os.path.isfile(path):
|
||||
@@ -1814,19 +1835,17 @@ cd %s
|
||||
# 生成下载地址
|
||||
def create_download_url(self, get):
|
||||
if not os.path.exists(get.filename):
|
||||
return public.returnMsg(False, 'The specified file does not exist!')
|
||||
if not os.path.isfile(get.filename):
|
||||
return public.returnMsg(False, 'Cannot generate download address for directory!')
|
||||
return public.returnMsg(False,'The specified file does not exist!')
|
||||
my_table = 'download_token'
|
||||
mtime = int(time.time())
|
||||
pdata = {
|
||||
"filename": get.filename, # 文件名
|
||||
"token": public.GetRandomString(12), # 12位随机密钥,用于URL
|
||||
"expire": mtime + (int(get.expire) * 3600), # 过期时间
|
||||
"ps": get.ps, # 备注
|
||||
"total": 0, # 下载计数
|
||||
"password": get.password, # 提取密码
|
||||
"addtime": mtime # 添加时间
|
||||
"filename": get.filename, #文件名
|
||||
"token": public.GetRandomString(12), #12位随机密钥,用于URL
|
||||
"expire": mtime + (int(get.expire) * 3600), #过期时间
|
||||
"ps":get.ps, #备注
|
||||
"total":0, #下载计数
|
||||
"password":str(get.password), #提取密码
|
||||
"addtime": mtime #添加时间
|
||||
}
|
||||
# 更新 or 插入
|
||||
token = public.M(my_table).where('filename=?', (get.filename,)).getField('token')
|
||||
|
||||
@@ -46,6 +46,18 @@ def control_init():
|
||||
`password` REAL,
|
||||
`ps` REAL,
|
||||
`addtime` INTEGER
|
||||
)'''
|
||||
sql.execute(csql,())
|
||||
|
||||
|
||||
if not sql.table('sqlite_master').where('type=? AND name=?', ('table', 'messages')).count():
|
||||
csql = '''CREATE TABLE IF NOT EXISTS `messages` (
|
||||
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
`level` TEXT,
|
||||
`msg` TEXT,
|
||||
`state` INTEGER DEFAULT 0,
|
||||
`expire` INTEGER,
|
||||
`addtime` INTEGER
|
||||
)'''
|
||||
sql.execute(csql,())
|
||||
|
||||
|
||||
+7
-10
@@ -19,7 +19,7 @@ import time
|
||||
os.chdir('/www/server/panel')
|
||||
sys.path.insert(0,'class/')
|
||||
import public
|
||||
_VERSION = 1.3
|
||||
_VERSION = 1.4
|
||||
|
||||
class backup:
|
||||
_path = None
|
||||
@@ -28,8 +28,7 @@ class backup:
|
||||
_inode_min = 10
|
||||
_db_mysql = None
|
||||
_cloud = None
|
||||
_local_backdir = None
|
||||
_is_save_local = not os.path.exists('data/is_save_local_backup.pl')
|
||||
_is_save_local = os.path.exists('data/is_save_local_backup.pl')
|
||||
def __init__(self,cloud_object = None):
|
||||
'''
|
||||
@name 数据备份对象
|
||||
@@ -196,7 +195,7 @@ class backup:
|
||||
num = len(backups) - int(save)
|
||||
if num > 0:
|
||||
self._get_local_backdir()
|
||||
self.echo_info('-' * 90)
|
||||
self.echo_info('-' * 88)
|
||||
for backup in backups:
|
||||
#处理目录备份到远程的情况
|
||||
if backup['filename'].find('|') != -1:
|
||||
@@ -305,7 +304,7 @@ class backup:
|
||||
|
||||
filename = dfile
|
||||
if self._cloud:
|
||||
filename = self._cloud._name
|
||||
filename = dfile + '|' + self._cloud._name + '|' + fname
|
||||
|
||||
pdata = {
|
||||
'type': 0,
|
||||
@@ -326,7 +325,7 @@ class backup:
|
||||
if not self._cloud:
|
||||
backups = public.M('backup').where("type=? and pid=? and filename LIKE '%/%'",('0',pid)).field('id,name,filename').select()
|
||||
else:
|
||||
backups = public.M('backup').where('type=? and pid=? and filename=?',('0',pid,filename)).field('id,name,filename').select()
|
||||
backups = public.M('backup').where('type=? and pid=? and filename LIKE "%{}%"'.format(self._cloud._name),('0',pid)).field('id,name,filename').select()
|
||||
|
||||
self.delete_old(backups,save,'site')
|
||||
self.echo_end()
|
||||
@@ -425,7 +424,7 @@ class backup:
|
||||
|
||||
filename = dfile
|
||||
if self._cloud:
|
||||
filename = self._cloud._name
|
||||
filename = dfile + '|' + self._cloud._name + '|' + fname
|
||||
self.echo_info("Database has been backed up to: {}".format(dfile))
|
||||
if os.path.exists(self._err_log):
|
||||
os.remove(self._err_log)
|
||||
@@ -452,9 +451,7 @@ class backup:
|
||||
if not self._cloud:
|
||||
backups = public.M('backup').where("type=? and pid=? and filename LIKE '%/%'",('1',pid)).field('id,name,filename').select()
|
||||
else:
|
||||
backups = public.M('backup').where('type=? and pid=? and filename=?',('1',pid,filename)).field('id,name,filename').select()
|
||||
|
||||
self.echo_info(str(backups))
|
||||
backups = public.M('backup').where('type=? and pid=? and filename LIKE "%{}%"'.format(self._cloud._name),('1',pid)).field('id,name,filename').select()
|
||||
self.delete_old(backups,save,'database')
|
||||
self.echo_end()
|
||||
return dfile
|
||||
|
||||
@@ -0,0 +1,134 @@
|
||||
#coding: utf-8
|
||||
# +-------------------------------------------------------------------
|
||||
# | 宝塔Linux面板
|
||||
# +-------------------------------------------------------------------
|
||||
# | Copyright (c) 2015-2099 宝塔软件(http://bt.cn) All rights reserved.
|
||||
# +-------------------------------------------------------------------
|
||||
# | Author: 黄文良 <2020-05-18>
|
||||
# +-------------------------------------------------------------------
|
||||
|
||||
# +-------------------------------------------------------------------
|
||||
# | 消息提醒
|
||||
# +-------------------------------------------------------------------
|
||||
import os,sys,time
|
||||
import public
|
||||
class panelMessage:
|
||||
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def get_messages(self,args = None):
|
||||
'''
|
||||
@name 获取消息列表
|
||||
@author 黄文良 <2020-05-18>
|
||||
@return list
|
||||
'''
|
||||
data = public.M('messages').where('state=? and expire>?',(1,int(time.time()))).order("id desc").select()
|
||||
return data
|
||||
|
||||
def get_messages_all(self,args = None):
|
||||
'''
|
||||
@name 获取所有消息列表
|
||||
@author 黄文良 <2020-05-18>
|
||||
@return list
|
||||
'''
|
||||
data = public.M('messages').order("id desc").select()
|
||||
return data
|
||||
|
||||
def get_message_find(self,args = None,id = None):
|
||||
'''
|
||||
@name 获取指定消息
|
||||
@author 黄文良 <2020-05-18>
|
||||
@param args dict_obj{
|
||||
id: 消息标识
|
||||
}
|
||||
@return dict
|
||||
'''
|
||||
if args:
|
||||
id = int(args.id)
|
||||
data = public.M('messages').where('id=?',id).find()
|
||||
return data
|
||||
|
||||
|
||||
def create_message(self,args = None,level=None,msg=None,expire=None):
|
||||
'''
|
||||
@name 创建新的消息
|
||||
@author 黄文良 <2020-05-18>
|
||||
@param args dict_obj{
|
||||
level: 消息级别(info/warning/danger/error),
|
||||
msg: 消息内容
|
||||
expire: 过期时间
|
||||
}
|
||||
@return dict
|
||||
'''
|
||||
if args:
|
||||
level = args.level
|
||||
msg = args.msg
|
||||
expire = args.expire
|
||||
pdata = {
|
||||
"level":level,
|
||||
"msg":msg,
|
||||
"state":1,
|
||||
"expire":int(time.time()) + (int(expire) * 86400),
|
||||
"addtime": int(time.time())
|
||||
}
|
||||
|
||||
public.M('messages').insert(pdata)
|
||||
return public.returnMsg(True,'Created successfully!')
|
||||
|
||||
def status_message(self,args = None,id = None,state = None):
|
||||
'''
|
||||
@name 设置消息状态
|
||||
@author 黄文良 <2020-05-18>
|
||||
@param args dict_obj{
|
||||
id: 消息标识,
|
||||
state: 消息状态(0.已忽略, 1.正常)
|
||||
}
|
||||
@return dict
|
||||
'''
|
||||
if args:
|
||||
id = int(args.id)
|
||||
state = int(args.state)
|
||||
public.M('messages').where('id=?',id).setField('state',state)
|
||||
return public.returnMsg(True,'Set up successfully!')
|
||||
|
||||
|
||||
def remove_message(self,args = None,id = None):
|
||||
'''
|
||||
@name 删除指定消息
|
||||
@author 黄文良 <2020-05-18>
|
||||
@param args dict_obj{
|
||||
id: 消息标识
|
||||
}
|
||||
@return dict
|
||||
'''
|
||||
if args:
|
||||
id = int(args.id)
|
||||
public.M('messages').where('id=?',id).delete()
|
||||
return public.returnMsg(True,'Successfully deleted!')
|
||||
|
||||
def remove_message_level(self,level):
|
||||
'''
|
||||
@name 删除指定消息
|
||||
@author 黄文良 <2020-05-18>
|
||||
@param level string(指定级别或标识)
|
||||
@return bool
|
||||
'''
|
||||
public.M('messages').where('(level=? or level=? or level=? or level=?) and state=?',(level,level+'15',level+'7',level+'3',1)).delete()
|
||||
return True
|
||||
|
||||
def is_level(self,level):
|
||||
'''
|
||||
@name 指定消息是否忽略
|
||||
@author 黄文良 <2020-05-18>
|
||||
@param level string(指定级别或标识)
|
||||
@return bool
|
||||
'''
|
||||
if public.M('messages').where('level=? and state=?',(level,0)).count():
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
|
||||
|
||||
|
||||
+82
-8
@@ -82,6 +82,7 @@ class panelPlugin:
|
||||
names = dep.split('|')
|
||||
for name in names:
|
||||
pluginInfo = self.get_soft_find(name)
|
||||
if not pluginInfo: return True
|
||||
if pluginInfo['setup'] == True:
|
||||
status = True
|
||||
break
|
||||
@@ -330,6 +331,7 @@ class panelPlugin:
|
||||
if softList: public.writeFile(lcoalTmp,json.dumps(softList))
|
||||
public.ExecShell('rm -f /tmp/bmac_*')
|
||||
self.getCloudPHPExt(get)
|
||||
self.expire_msg(softList)
|
||||
try:
|
||||
public.writeFile("/tmp/" + cache.get('p_token'),str(softList['pro']))
|
||||
except:pass
|
||||
@@ -353,6 +355,78 @@ class panelPlugin:
|
||||
softList['list'] = tmpList
|
||||
return softList
|
||||
|
||||
#取提醒标记
|
||||
def get_level_msg(self,level,s_time,endtime):
|
||||
'''
|
||||
level 提醒标记
|
||||
s_time 当前时间戳
|
||||
endtime 到期时间戳
|
||||
'''
|
||||
expire_day = (endtime - s_time) / 86400
|
||||
if expire_day < 15 and expire_day > 7:
|
||||
level = level + '15'
|
||||
elif expire_day < 7 and expire_day > 3:
|
||||
level = level + '7'
|
||||
elif expire_day < 3 and expire_day > 0:
|
||||
level = level + '3'
|
||||
return level,expire_day
|
||||
|
||||
#添加到期提醒
|
||||
def add_expire_msg(self,title,level,name,expire_day,pid,endtime):
|
||||
'''
|
||||
title 软件标题
|
||||
level 提醒标记
|
||||
name 软件名称
|
||||
expire_day 剩余天数
|
||||
'''
|
||||
import panelMessage #引用消息提醒模块
|
||||
pm = panelMessage.panelMessage()
|
||||
pm.remove_message_level(level) #删除旧的提醒
|
||||
if expire_day > 15: return False
|
||||
if pm.is_level(level): #是否忽略
|
||||
if level != name: #到期还是即将到期
|
||||
msg_last = '您的【{}】授权还有{}天到期'.format(title,int(expire_day))
|
||||
else:
|
||||
msg_last = '您的【{}】授权已到期'.format(title)
|
||||
pl_msg = 'true'
|
||||
if name in ['pro','ltd']:
|
||||
pl_msg = 'false'
|
||||
renew_msg = '<a class="btlink" onclick="bt.soft.product_pay_view({name:\'%s\',pid:%s,limit:\'%s\',plugin:%s,renew:%s});">立即续费</a>' % (title,pid,name,pl_msg,endtime)
|
||||
pm.create_message(level=level,expire=7,msg="{},为了不影响您正常使用【{}】功能,请及时续费,{}".format(msg_last,title,renew_msg))
|
||||
return True
|
||||
return False
|
||||
|
||||
#到期提醒
|
||||
def expire_msg(self,data):
|
||||
'''
|
||||
data 插件列表
|
||||
'''
|
||||
s_time = time.time()
|
||||
is_plugin = True
|
||||
#企业版到期提醒
|
||||
if not data['ltd'] in [-1]:
|
||||
level,expire_day = self.get_level_msg('ltd',s_time,data['ltd'])
|
||||
self.add_expire_msg('企业版',level,'ltd',expire_day,100000032,data['ltd'])
|
||||
return True
|
||||
|
||||
#专业版到期提醒
|
||||
if not data['pro'] in [-1,0]:
|
||||
level,expire_day = self.get_level_msg('pro',s_time,data['pro'])
|
||||
self.add_expire_msg('专业版',level,'pro',expire_day,100000011,data['pro'])
|
||||
is_plugin = False
|
||||
|
||||
#单独购买的插件到期提醒
|
||||
for p in data['list']:
|
||||
#跳过非企业版或专业版插件
|
||||
if not p['type'] in [8,12]: continue
|
||||
#已经是专业版的情况下跳过专业版插件
|
||||
if not is_plugin and p['type'] == 8: continue
|
||||
if not p['endtime'] in [-1,0]:
|
||||
level,expire_day = self.get_level_msg(p['name'],s_time,p['endtime'])
|
||||
self.add_expire_msg(p['title'],level,p['name'],expire_day,p['pid'],p['endtime'])
|
||||
return True
|
||||
|
||||
|
||||
#提交用户评分
|
||||
def set_score(self,args):
|
||||
try:
|
||||
@@ -1484,7 +1558,7 @@ class panelPlugin:
|
||||
phpport = '888'
|
||||
if os.path.exists(configFile):
|
||||
conf = public.readFile(configFile)
|
||||
rep = "listen\s+([0-9]+)\s*;"
|
||||
rep = r"listen\s+([0-9]+)\s*;"
|
||||
rtmp = re.search(rep,conf)
|
||||
if rtmp:
|
||||
phpport = rtmp.groups()[0]
|
||||
@@ -1494,23 +1568,23 @@ class panelPlugin:
|
||||
configFile = setupPath + '/nginx/conf/enable-php.conf'
|
||||
if not os.path.exists(configFile): public.writeFile(configFile,public.readFile(setupPath + '/nginx/conf/enable-php-54.conf'))
|
||||
conf = public.readFile(configFile)
|
||||
rep = "php-cgi-([0-9]+)\.sock"
|
||||
rep = r"php-cgi-([0-9]+)\.sock"
|
||||
rtmp = re.search(rep,conf)
|
||||
if rtmp:
|
||||
phpversion = rtmp.groups()[0]
|
||||
else:
|
||||
rep = "php-cgi.*\.sock"
|
||||
rep = r"php-cgi.*\.sock"
|
||||
public.writeFile(configFile,conf)
|
||||
phpversion = '54'
|
||||
|
||||
configFile = setupPath + '/apache/conf/extra/httpd-vhosts.conf'
|
||||
if os.path.exists(configFile):
|
||||
conf = public.readFile(configFile)
|
||||
rep = "php-cgi-([0-9]+)\.sock"
|
||||
rep = r"php-cgi-([0-9]+)\.sock"
|
||||
rtmp = re.search(rep,conf)
|
||||
if rtmp:
|
||||
phpversion = rtmp.groups()[0]
|
||||
rep = "Listen\s+([0-9]+)\s*\n"
|
||||
rep = r"Listen\s+([0-9]+)\s*\n"
|
||||
rtmp = re.search(rep,conf)
|
||||
if rtmp:
|
||||
phpport = rtmp.groups()[0]
|
||||
@@ -1572,20 +1646,20 @@ class panelPlugin:
|
||||
phpfpm = public.readFile(file)
|
||||
data = {}
|
||||
try:
|
||||
rep = "upload_max_filesize\s*=\s*([0-9]+)M"
|
||||
rep = r"upload_max_filesize\s*=\s*([0-9]+)M"
|
||||
tmp = re.search(rep,phpini).groups()
|
||||
data['max'] = tmp[0]
|
||||
except:
|
||||
data['max'] = '50'
|
||||
try:
|
||||
rep = "request_terminate_timeout\s*=\s*([0-9]+)\n"
|
||||
rep = r"request_terminate_timeout\s*=\s*([0-9]+)\n"
|
||||
tmp = re.search(rep,phpfpm).groups()
|
||||
data['maxTime'] = tmp[0]
|
||||
except:
|
||||
data['maxTime'] = 0
|
||||
|
||||
try:
|
||||
rep = u"\n;*\s*cgi\.fix_pathinfo\s*=\s*([0-9]+)\s*\n"
|
||||
rep = r"\n;*\s*cgi\.fix_pathinfo\s*=\s*([0-9]+)\s*\n"
|
||||
tmp = re.search(rep,phpini).groups()
|
||||
|
||||
if tmp[0] == '1':
|
||||
|
||||
@@ -226,6 +226,8 @@ class panelSite(panelRedirect):
|
||||
urlrewriteFile = urlrewritePath+'/'+self.siteName+'.conf'
|
||||
if not os.path.exists(urlrewritePath): os.makedirs(urlrewritePath)
|
||||
open(urlrewriteFile,'w+').close()
|
||||
if not os.path.exists(urlrewritePath):
|
||||
public.writeFile(urlrewritePath,'')
|
||||
return True
|
||||
|
||||
#重新生成nginx配置文件
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
#coding: utf-8
|
||||
# +-------------------------------------------------------------------
|
||||
# | 宝塔Linux面板
|
||||
# +-------------------------------------------------------------------
|
||||
# | Copyright (c) 2015-2099 宝塔软件(http://bt.cn) All rights reserved.
|
||||
# +-------------------------------------------------------------------
|
||||
# | Author: 黄文良 <2020-05-18>
|
||||
# +-------------------------------------------------------------------
|
||||
|
||||
# +-------------------------------------------------------------------
|
||||
# | 流媒体模块
|
||||
# +-------------------------------------------------------------------
|
||||
|
||||
import os,sys,re
|
||||
import mimetypes
|
||||
import public
|
||||
from BTPanel import Response
|
||||
|
||||
def get_buff_size(file_size):
|
||||
buff_size = 2097152
|
||||
if file_size < 104857600:
|
||||
buff_size = 2097152
|
||||
elif file_size < 524288000:
|
||||
buff_size = 4194304
|
||||
elif file_size < 1073741824:
|
||||
buff_size = 8388608
|
||||
else:
|
||||
buff_size = 10485760
|
||||
return buff_size
|
||||
|
||||
def partial_response(path, start, end=None):
|
||||
if not os.path.exists(path):
|
||||
return Response("file not fount!",404)
|
||||
file_size = os.path.getsize(path)
|
||||
buff_size = get_buff_size(file_size)
|
||||
|
||||
if end is None:
|
||||
end = start + buff_size - 1
|
||||
end = min(end, file_size - 1)
|
||||
end = min(end, start + buff_size - 1)
|
||||
length = end - start + 1
|
||||
|
||||
with open(path, 'rb') as fd:
|
||||
fd.seek(start)
|
||||
bytes = fd.read(length)
|
||||
assert len(bytes) == length
|
||||
|
||||
response = Response(bytes,206,mimetype=mimetypes.guess_type(path)[0],direct_passthrough=True,)
|
||||
response.headers.add('Content-Range', 'bytes {0}-{1}/{2}'.format(start, end, file_size,),)
|
||||
response.headers.add('Accept-Ranges', 'bytes')
|
||||
return response
|
||||
|
||||
def get_range(request):
|
||||
range = request.headers.get('Range')
|
||||
m = None
|
||||
if range:
|
||||
m = re.match(r'bytes=(?P<start>\d+)-(?P<end>\d+)?', range)
|
||||
if m:
|
||||
start = m.group('start')
|
||||
end = m.group('end')
|
||||
start = int(start)
|
||||
if end is not None:
|
||||
end = int(end)
|
||||
return start, end
|
||||
else:
|
||||
return 0, None
|
||||
|
||||
|
||||
+44
-146
@@ -1,151 +1,49 @@
|
||||
#!/usr/bin/python
|
||||
#coding: utf-8
|
||||
# Author: <梁凯强>1249648969@qq.com
|
||||
# panelWaf.py
|
||||
# code: 面板基础安全类
|
||||
# +-------------------------------------------------------------------
|
||||
# | 宝塔Linux面板
|
||||
# +-------------------------------------------------------------------
|
||||
# | Copyright (c) 2015-2017 宝塔软件(http:#bt.cn) All rights reserved.
|
||||
# +-------------------------------------------------------------------
|
||||
# | Author: 黄文良 <287962566@qq.com>
|
||||
# +-------------------------------------------------------------------
|
||||
|
||||
import re,json,sys,public,os
|
||||
class panelWaf:
|
||||
__ConfigFile = '/www/server/nginx/waf/config.lua'
|
||||
__WafConfigPath = '/www/server/panel/vhost/wafconf'
|
||||
#获取配置项
|
||||
def GetConfig(self,get):
|
||||
data = {}
|
||||
try:
|
||||
conf = public.readFile(self.__ConfigFile);
|
||||
configs = ["attacklog","UrlDeny","Redirect","CookieMatch","postMatch","whiteModule","CCDeny","CCrate"];
|
||||
#遍历单一配置
|
||||
for key in configs:
|
||||
rep = key + "\s*=\s*\"([\w\/]+)\"\s*\n"
|
||||
data[key] = re.search(rep,conf).groups()[0]
|
||||
#遍历列表
|
||||
configs = ["black_fileExt","ipWhitelist","ipBlocklist"];
|
||||
for key in configs:
|
||||
rep = key + "\s*=\s*(.+)\n";
|
||||
data[key] = json.loads(re.search(rep,conf).groups()[0].replace("{","[").replace("}","]"));
|
||||
|
||||
get.name = 'whiteurl';
|
||||
data['uriWhite'] = self.GetWafConf(get);
|
||||
except:
|
||||
pass;
|
||||
data['status'] = self.GetStatus();
|
||||
return data;
|
||||
|
||||
#取状态
|
||||
def GetStatus(self):
|
||||
path = "/www/server/nginx/conf/nginx.conf";
|
||||
if not os.path.exists(path): return public.returnMsg(False,'WAF_NOT_NGINX');
|
||||
conf = public.readFile(path);
|
||||
status = 1;
|
||||
if conf.find("#include luawaf.conf;") != -1: status = 0;
|
||||
if conf.find("luawaf.conf;") == -1: status = -1;
|
||||
return status;
|
||||
|
||||
#更新规则
|
||||
def updateWaf(self,get):
|
||||
names = ['args','cookie','post','url','user-agent'];
|
||||
furl = 'http://download.bt.cn/install/waf/wafconf'
|
||||
fpath = '/www/server/panel/vhost/wafconf'
|
||||
for name in names:
|
||||
public.downloadFile(furl + '/' + name,fpath + '/' + name);
|
||||
public.serviceReload();
|
||||
return public.returnMsg(True,'WAF_UPDATE')
|
||||
|
||||
#设置状态
|
||||
def SetStatus(self,get):
|
||||
path = "/www/server/nginx/conf/nginx.conf";
|
||||
if not os.path.exists(path): return public.returnMsg(False,'WAF_NOT_NGINX');
|
||||
conf = public.readFile(path);
|
||||
status = self.GetStatus()
|
||||
if status == -1: return public.returnMsg(False,'WAF_NOT_NGINX_VERSION');
|
||||
if status == 0:
|
||||
conf = conf.replace('#include luawaf.conf;',"include luawaf.conf;");
|
||||
else:
|
||||
conf = conf.replace('include luawaf.conf;',"#include luawaf.conf;");
|
||||
|
||||
public.writeFile(path,conf);
|
||||
public.serviceReload();
|
||||
return public.returnMsg(True,"SET_SUCCESS");
|
||||
|
||||
|
||||
|
||||
#设置配置项
|
||||
def SetConfigString(self,get):
|
||||
conf = public.readFile(self.__ConfigFile);
|
||||
rep = get.name + "\s*=\s*\"[\w\/]+\"\s*\n"
|
||||
conf = re.sub(rep,get.name + '="' + get.value.strip() + '"\n',conf)
|
||||
public.writeFile(self.__ConfigFile,conf);
|
||||
public.serviceReload();
|
||||
return public.returnMsg(True,"SET_SUCCESS");
|
||||
|
||||
#设置配置项列表
|
||||
def SetConfigList(self,get):
|
||||
conf = public.readFile(self.__ConfigFile);
|
||||
rep = get.name + "\s*=\s*(.+)\n";
|
||||
keyList = json.loads(re.search(rep,conf).groups()[0].replace("{","[").replace("}","]"));
|
||||
if get.name != 'black_fileExt':
|
||||
rep2 = "\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}";
|
||||
if not re.search(rep2,get.value): return public.returnMsg(False,"WAF_CONF_ERR");
|
||||
if get.act == 'del':
|
||||
if not get.value in keyList: return public.returnMsg(False,"WAF_CONF_NOT_EXISTS");
|
||||
tmp = []
|
||||
for t in keyList:
|
||||
if t == get.value: continue;
|
||||
tmp.append(t);
|
||||
keyList = tmp;
|
||||
else:
|
||||
if get.value in keyList:return public.returnMsg(False,"WAF_CONF_EXISTS");
|
||||
keyList.append(get.value.strip());
|
||||
keyStr = json.dumps(keyList).replace("[","{").replace("]","}");
|
||||
conf = re.sub(rep,get.name + "=" + keyStr + "\n",conf);
|
||||
public.writeFile(self.__ConfigFile,conf);
|
||||
public.serviceReload();
|
||||
return public.returnMsg(True,"SUCCESS");
|
||||
|
||||
#获取指定规则列表
|
||||
def GetWafConf(self,get):
|
||||
path = self.__WafConfigPath + '/' + get.name;
|
||||
if not os.path.exists(path): return public.returnMsg(False,"WAF_CONF_NOT_EXISTS");
|
||||
data = public.readFile(path).split("\n")
|
||||
return data;
|
||||
|
||||
#设置指定规则列表
|
||||
def SetWafConf(self,get):
|
||||
path = self.__WafConfigPath + '/' + get.name;
|
||||
if not os.path.exists(path): return public.returnMsg(False,"WAF_CONF_NOT_EXISTS");
|
||||
data = public.readFile(path).split("\n")
|
||||
if get.act == "del":
|
||||
if not get.value in data: return public.returnMsg(False,"WAF_CONF_NOT_EXISTS");
|
||||
tmp = []
|
||||
for t in data:
|
||||
if get.value == t: continue;
|
||||
tmp.append(t);
|
||||
data = tmp;
|
||||
else:
|
||||
if get.value in data: return public.returnMsg(False,"WAF_CONF_EXISTS");
|
||||
data.append(get.value);
|
||||
conf = ""
|
||||
|
||||
for v in data:
|
||||
conf += v + "\n";
|
||||
|
||||
public.writeFile(path,conf[:-1]);
|
||||
public.serviceReload();
|
||||
return public.returnMsg(True,"SUCCESS");
|
||||
|
||||
#取日志
|
||||
|
||||
|
||||
flag_file='/www/server/panel/data/tmp1.json'
|
||||
|
||||
if __name__ == "__main__":
|
||||
if len(sys.argv) > 1:
|
||||
p = panelWaf();
|
||||
if sys.argv[1] == 'add' or sys.argv[1] == 'del':
|
||||
print p.SetConfigList(sys.argv[2],sys.argv[3],sys.argv[1]);
|
||||
else:
|
||||
print p.SetConfigString(sys.argv[1],sys.argv[2]);
|
||||
print GetConfig();
|
||||
try:
|
||||
import libinjection
|
||||
except:
|
||||
if not os.path.exists(flag_file):
|
||||
public.WriteFile(flag_file,'1')
|
||||
else:
|
||||
count_size=public.ReadFile(flag_file)
|
||||
if count_size.strip().isdigit():
|
||||
if int(count_size.strip())>= 5:
|
||||
exit(False)
|
||||
else:
|
||||
public.WriteFile(flag_file, str(int(count_size.strip())+1))
|
||||
else:public.WriteFile(flag_file,'1')
|
||||
if os.path.exists('/www/server/panel/pyenv/bin/python3'):
|
||||
public.ExecShell('/www/server/panel/pyenv/bin/pip install Cython')
|
||||
public.ExecShell('/www/server/panel/pyenv/bin/pip install libinjection-python')
|
||||
else:
|
||||
public.ExecShell('pip install Cython')
|
||||
public.ExecShell('pip install libinjection-python')
|
||||
|
||||
class panelWaf:
|
||||
##json_data => {"username":"admin","password":"123456!@#$%%^"}
|
||||
def is_sql(self,json_data):
|
||||
for i in json_data:
|
||||
try:
|
||||
if type(json_data[i])==str:
|
||||
if libinjection.is_sql_injection(json_data[i])['is_sqli']:
|
||||
return True
|
||||
except:continue
|
||||
else:return False
|
||||
|
||||
##json_data => {"username":"admin","password":"123456!@#$%%^"}
|
||||
def is_xss(self,json_data):
|
||||
for i in json_data:
|
||||
try:
|
||||
if type(json_data[i]) == str:
|
||||
if libinjection.is_xss(json_data[i])['is_xss']:
|
||||
return True
|
||||
except:continue
|
||||
else:return False
|
||||
+1
-1
@@ -40,7 +40,7 @@ function get_info(){
|
||||
//文件与字符串处理库
|
||||
$data['5io_string'] = array();
|
||||
$data['5io_string']['Xmlrpc'] = get_extension_funcs('xmlrpc')?true:false;
|
||||
$data['5io_string']['FileInfo'] = get_extension_funcs('fileinfo')?true:false;
|
||||
$data['5io_string']['FileInfo'] = in_array('fileinfo',$data['modules'])?true:false;
|
||||
$data['5io_string']['Ftp'] = get_extension_funcs('ftp')?true:false;
|
||||
$data['5io_string']['Mbstring'] = get_extension_funcs('mbstring')?true:false;
|
||||
$data['5io_string']['bz2'] = in_array('bz2',$data['modules']);
|
||||
|
||||
+13
-8
@@ -239,7 +239,7 @@ def GetJson(data):
|
||||
from json import dumps
|
||||
if data == bytes: data = data.decode('utf-8')
|
||||
try:
|
||||
return dumps(data)
|
||||
return dumps(data,ensure_ascii=False)
|
||||
except:
|
||||
return dumps(returnMsg(False,"Wrong response: %s" % str(data)))
|
||||
|
||||
@@ -665,6 +665,7 @@ def getPanelAddr():
|
||||
|
||||
# 字节单位转换
|
||||
def to_size(size):
|
||||
if not size: return '0.00 b'
|
||||
size = float(size)
|
||||
d = ('b','KB','MB','GB','TB')
|
||||
s = d[0]
|
||||
@@ -1307,12 +1308,13 @@ def set_own(filename, user, group=None):
|
||||
return True
|
||||
|
||||
#校验路径安全
|
||||
def path_safe_check(path):
|
||||
checks = ['..', './', '\\', '%', '$', '^', '&', '*', '~', '@', '#']
|
||||
def path_safe_check(path,force=True):
|
||||
checks = ['..','./','\\','%','$','^','&','*','~','#','"',"'",';','|','{','}','`']
|
||||
for c in checks:
|
||||
if path.find(c) != -1: return False
|
||||
rep = r"^[\w\s\.\/-]+$"
|
||||
if not re.match(rep,path): return False
|
||||
if force:
|
||||
rep = r"^[\w\s\.\/-]+$"
|
||||
if not re.match(rep,path): return False
|
||||
return True
|
||||
|
||||
#取数据库字符集
|
||||
@@ -1629,9 +1631,12 @@ def import_cdn_plugin():
|
||||
|
||||
|
||||
def get_cdn_hosts():
|
||||
if import_cdn_plugin(): return []
|
||||
import static_cdn_main
|
||||
return static_cdn_main.static_cdn_main().get_hosts(None)
|
||||
try:
|
||||
if import_cdn_plugin(): return []
|
||||
import static_cdn_main
|
||||
return static_cdn_main.static_cdn_main().get_hosts(None)
|
||||
except:
|
||||
return []
|
||||
|
||||
def get_cdn_url():
|
||||
try:
|
||||
|
||||
@@ -203,6 +203,6 @@ class setPanelLets:
|
||||
self.__save_cert_source(domain, get.email)
|
||||
return public.returnMsg(True, 'Panel lets set successfully')
|
||||
else:
|
||||
return create_lets
|
||||
return public.returnMsg(False, create_lets)
|
||||
else:
|
||||
return create_site
|
||||
return public.returnMsg(False, create_site)
|
||||
|
||||
Reference in New Issue
Block a user