mirror of
https://github.com/aaPanel/aaPanel.git
synced 2026-08-17 21:25:47 +02:00
Update to v7.52.0
This commit is contained in:
+9
-3
@@ -398,7 +398,7 @@ class acme_v2:
|
||||
|
||||
# 构造域名列表
|
||||
def format_domains(self, domains):
|
||||
if type(domains) != list:
|
||||
if not isinstance(domains, list):
|
||||
return []
|
||||
# 是否自动构造通配符
|
||||
if self._auto_wildcard:
|
||||
@@ -2932,7 +2932,7 @@ fullchain.pem Paste into certificate input box
|
||||
from hashlib import md5
|
||||
try:
|
||||
md5_obj = md5()
|
||||
body = f"{auth_to}{domains}"
|
||||
body = f"{auth_to.rstrip('/')}{domains}"
|
||||
md5_obj.update(body.encode("utf-8"))
|
||||
self._log_file = f"{self._log_path}/{md5_obj.hexdigest()}.log"
|
||||
if not os.path.exists(self._log_path):
|
||||
@@ -3077,8 +3077,14 @@ fullchain.pem Paste into certificate input box
|
||||
continue
|
||||
|
||||
# other site ssl
|
||||
site_path = ssl.auth_info.get("auth_to")
|
||||
site_path = ssl.auth_info.get("auth_to").rstrip("/")
|
||||
site_info = public.S("sites").where("path=?", site_path).find()
|
||||
if not site_info:
|
||||
site_name, _ = self.get_site_name_by_domains(ssl.dns)
|
||||
if site_name:
|
||||
site_info = public.S("sites").where("name=?", site_name).find()
|
||||
site_path = site_info.get("path", "") if site_info else site_path
|
||||
|
||||
site_name = site_info.get("name") if site_info else ""
|
||||
if self._check_site(site_path, site_info, ssl):
|
||||
# try http verfication
|
||||
|
||||
+1
-1
@@ -48,7 +48,7 @@ class panelSetup:
|
||||
if ua.find('spider') != -1 or g.ua.find('bot') != -1:
|
||||
return abort(403)
|
||||
|
||||
g.version = '7.49.0'
|
||||
g.version = '7.52.0'
|
||||
g.title = public.GetConfigValue('title')
|
||||
g.uri = request.path
|
||||
g.debug = os.path.exists('data/debug.pl')
|
||||
|
||||
+6
-2
@@ -7,7 +7,7 @@
|
||||
# | Author: hwliang <hwl@aapanel.com>
|
||||
# +-------------------------------------------------------------------
|
||||
import public,db,os,time,re, json
|
||||
from BTPanel import session, cache
|
||||
|
||||
class crontab:
|
||||
field = 'id,name,type,where1,where_hour,where_minute,echo,addtime,status,save,backupTo,sName,sBody,sType,urladdress'
|
||||
field += ",save_local,notice,notice_channel"
|
||||
@@ -148,6 +148,7 @@ class crontab:
|
||||
|
||||
#检查环境
|
||||
def checkBackup(self):
|
||||
from BTPanel import cache
|
||||
if cache.get('check_backup'): return None
|
||||
|
||||
# 检查备份表是否正确
|
||||
@@ -189,7 +190,10 @@ class crontab:
|
||||
return public.return_msg_gettext(False, public.lang("Unable to write to file, please check if [System hardening] is enabled!"))
|
||||
|
||||
public.M('crontab').where('id=?',(id,)).setField('status',status)
|
||||
public.WriteLog('TYPE_CRON',"MODIFY_CRON_STATUS",(cronInfo['name'],str(status_msg[status])))
|
||||
public.WriteLog(
|
||||
'TYPE_CRON',
|
||||
"Modified cron job [{}] status to [{}]".format(cronInfo['name'], str(status_msg[status]))
|
||||
)
|
||||
return public.return_msg_gettext(True, public.lang("Setup successfully!"))
|
||||
|
||||
#修改计划任务
|
||||
|
||||
+1
-1
@@ -198,7 +198,7 @@ class firewalls:
|
||||
else:
|
||||
public.ExecShell('iptables -I INPUT -p tcp -m state --state NEW -m tcp --dport '+port+' -j ACCEPT')
|
||||
if not port in notudps: public.ExecShell('iptables -I INPUT -p tcp -m state --state NEW -m udp --dport '+port+' -j ACCEPT')
|
||||
public.WriteLog("TYPE_FIREWALL", 'FIREWALL_ACCEPT_PORT',(port,))
|
||||
public.WriteLog("TYPE_FIREWALL", 'Successfully accepted port [{}]!'.format(port))
|
||||
addtime = time.strftime('%Y-%m-%d %X',time.localtime())
|
||||
if not is_exists: public.M('firewall').add('port,ps,addtime',(port,ps,addtime))
|
||||
self.FirewallReload()
|
||||
|
||||
+12
-8
@@ -239,13 +239,13 @@ def clear_other_files():
|
||||
public.ExecShell("/etc/init.d/nginx reload")
|
||||
public.ExecShell("/etc/init.d/nginx start")
|
||||
|
||||
dirPath = '/www/server/adminer'
|
||||
if os.path.exists(dirPath):
|
||||
public.ExecShell("rm -rf {}".format(dirPath))
|
||||
# dirPath = '/www/server/adminer'
|
||||
# if os.path.exists(dirPath):
|
||||
# public.ExecShell("rm -rf {}".format(dirPath))
|
||||
|
||||
dirPath = '/www/server/panel/adminer'
|
||||
if os.path.exists(dirPath):
|
||||
public.ExecShell("rm -rf {}".format(dirPath))
|
||||
# dirPath = '/www/server/panel/adminer'
|
||||
# if os.path.exists(dirPath):
|
||||
# public.ExecShell("rm -rf {}".format(dirPath))
|
||||
|
||||
filename = '/www/server/nginx/off'
|
||||
if os.path.exists(filename): os.remove(filename)
|
||||
@@ -285,8 +285,8 @@ def clear_other_files():
|
||||
public.ExecShell('chmod 755 /www;chmod 755 /www/server')
|
||||
if os.path.exists('/www/server/phpmyadmin/pma'):
|
||||
public.ExecShell("rm -rf /www/server/phpmyadmin/pma")
|
||||
if os.path.exists("/www/server/adminer"):
|
||||
public.ExecShell("rm -rf /www/server/adminer")
|
||||
# if os.path.exists("/www/server/adminer"):
|
||||
# public.ExecShell("rm -rf /www/server/adminer")
|
||||
if os.path.exists("/www/server/panel/adminer"):
|
||||
public.ExecShell("rm -rf /www/server/panel/adminer")
|
||||
if os.path.exists('/dev/shm/session.db'):
|
||||
@@ -321,6 +321,9 @@ def sql_pacth():
|
||||
if not public.M('sqlite_master').where('type=? AND name=? AND sql LIKE ?', ('table', 'sites','%edate%')).count():
|
||||
public.M('sites').execute("alter TABLE sites add edate integer DEFAULT '0000-00-00'",())
|
||||
|
||||
if not public.M('sqlite_master').where('type=? AND name=? AND sql LIKE ?', ('table', 'sites', '%service_type%')).count():
|
||||
public.M('sites').execute("alter TABLE sites add service_type TEXT DEFAULT ''", ())
|
||||
|
||||
if not public.M('sqlite_master').where('type=? AND name=? AND sql LIKE ?', ('table', 'sites','%project_type%')).count():
|
||||
public.M('sites').execute("alter TABLE sites add project_type STRING DEFAULT 'PHP'",())
|
||||
|
||||
@@ -765,6 +768,7 @@ def files_set_mode():
|
||||
["/dev/shm/session_py3","","root",600,True],
|
||||
["/dev/shm/session_py2","","root",600,True],
|
||||
["/www/server/phpmyadmin","","root",755,True],
|
||||
["/www/server/adminer","","root",755,True],
|
||||
["/www/server/coll","","root",700,True],
|
||||
["/www/server/panel/init.sh","","root",600,False],
|
||||
["/www/server/panel/license.txt","","root",600,False],
|
||||
|
||||
+215
-89
@@ -1,61 +1,82 @@
|
||||
#coding: utf-8
|
||||
#-------------------------------------------------------------------
|
||||
# coding: utf-8
|
||||
# -------------------------------------------------------------------
|
||||
# aaPanel
|
||||
#-------------------------------------------------------------------
|
||||
# -------------------------------------------------------------------
|
||||
# Copyright (c) 2015-2099 aaPanel(www.aapanel.com) All rights reserved.
|
||||
#-------------------------------------------------------------------
|
||||
# -------------------------------------------------------------------
|
||||
# Author: hwliang <hwl@aapanel.com>
|
||||
#-------------------------------------------------------------------
|
||||
# -------------------------------------------------------------------
|
||||
|
||||
#------------------------------
|
||||
# ------------------------------
|
||||
# HTTP代理模块
|
||||
#------------------------------
|
||||
# ------------------------------
|
||||
|
||||
import requests,os,re,time
|
||||
from BTPanel import request,Response,public,app,get_phpmyadmin_dir,session
|
||||
from http.cookies import SimpleCookie
|
||||
import requests.packages.urllib3.util.connection as urllib3_conn
|
||||
import os
|
||||
import re
|
||||
import socket
|
||||
import time
|
||||
from http.cookies import SimpleCookie
|
||||
|
||||
import requests
|
||||
import urllib3.util.connection as urllib3_conn
|
||||
|
||||
from BTPanel import request, Response, public, app, get_phpmyadmin_dir, session
|
||||
|
||||
|
||||
class HttpProxy:
|
||||
_pma_path = None
|
||||
def get_res_headers(self,p_res):
|
||||
'''
|
||||
|
||||
@staticmethod
|
||||
def _err_resp(msg: str = None):
|
||||
return Response(
|
||||
msg or "something wrong with socket, please cheak and try again...", 500
|
||||
)
|
||||
|
||||
def get_res_headers(self, p_res):
|
||||
"""
|
||||
@name 获取响应头
|
||||
@author hwliang<2022-01-19>
|
||||
@param p_res<Response> requests响应对像
|
||||
@return dict
|
||||
'''
|
||||
"""
|
||||
headers = {}
|
||||
for h in p_res.headers.keys():
|
||||
if h in ['content-encoding', 'Content-Encoding', 'transfer-encoding', 'Transfer-Encoding']: continue
|
||||
if h in ['content-encoding', 'Content-Encoding', 'transfer-encoding', 'Transfer-Encoding']:
|
||||
continue
|
||||
headers[h] = p_res.headers[h]
|
||||
if h in ['location', 'Location']:
|
||||
|
||||
|
||||
# ============ redirect ===================
|
||||
# phpmyadmin
|
||||
if headers[h].find('phpmyadmin_') != -1:
|
||||
if not self._pma_path:
|
||||
if not self._pma_path:
|
||||
self._pma_path = get_phpmyadmin_dir()
|
||||
if self._pma_path:
|
||||
if self._pma_path:
|
||||
self._pma_path = self._pma_path[0]
|
||||
else:
|
||||
self._pma_path = ''
|
||||
headers[h] = headers[h].replace(self._pma_path,'phpmyadmin')
|
||||
headers[h] = headers.get(h, "").replace(self._pma_path, 'phpmyadmin')
|
||||
# adminer
|
||||
elif headers[h].find("adminer_") != -1:
|
||||
from adminer.manager import AdminerManager
|
||||
adminer_dir, _ = AdminerManager().adminer_dir_port
|
||||
headers[h] = headers.get(h, "").replace(adminer_dir, 'adminer')
|
||||
# ============ redirect end ==================
|
||||
|
||||
if headers[h].find('127.0.0.1') != -1:
|
||||
headers[h] = re.sub(r"https?://127.0.0.1(:\d+)?/",request.url_root,headers[h])
|
||||
headers[h] = re.sub(r"https?://127.0.0.1(:\d+)?/", request.url_root, headers[h])
|
||||
if request.url_root.find('https://') == 0:
|
||||
headers[h] = headers[h].replace('http://','https://')
|
||||
headers[h] = headers.get(h, '').replace('http://', 'https://')
|
||||
return headers
|
||||
|
||||
def set_res_headers(self,res,p_res):
|
||||
'''
|
||||
def set_res_headers(self, res, p_res):
|
||||
"""
|
||||
@name 设置响应头
|
||||
@author hwliang<2022-01-19>
|
||||
@param res<Response> flask响应对像
|
||||
@param p_res<Response> requests响应对像
|
||||
@return res<Response>
|
||||
'''
|
||||
"""
|
||||
# from datetime import datetime
|
||||
# cookie_dict = p_res.cookies.get_dict()
|
||||
# expires = datetime.utcnow() + app.permanent_session_lifetime
|
||||
@@ -65,15 +86,15 @@ class HttpProxy:
|
||||
# res.set_cookie(k, cookie_dict[k],
|
||||
# expires=expires, httponly=httponly,
|
||||
# path='/')
|
||||
|
||||
|
||||
return res
|
||||
|
||||
def get_pma_phpversion(self):
|
||||
'''
|
||||
"""
|
||||
@name 获取phpmyadmin的php版本
|
||||
@author hwliang<2022-01-19>
|
||||
@return str
|
||||
'''
|
||||
"""
|
||||
from panelPlugin import panelPlugin
|
||||
pma_status = panelPlugin().getPHPMyAdminStatus()
|
||||
if 'phpversion' in pma_status:
|
||||
@@ -81,11 +102,11 @@ class HttpProxy:
|
||||
return None
|
||||
|
||||
def get_pma_version(self):
|
||||
'''
|
||||
"""
|
||||
@name 获取phpmyadmin的版本
|
||||
@author hwliang<2022-01-19>
|
||||
@return str
|
||||
'''
|
||||
"""
|
||||
pma_vfile = public.get_setup_path() + '/phpmyadmin/version.pl'
|
||||
if not os.path.exists(pma_vfile): return ''
|
||||
pma_version = public.readFile(pma_vfile).strip()
|
||||
@@ -93,11 +114,11 @@ class HttpProxy:
|
||||
return pma_version
|
||||
|
||||
def set_pma_phpversion(self):
|
||||
'''
|
||||
"""
|
||||
@name 设置phpmyadmin兼容的php版本
|
||||
@author hwliang<2022-01-19>
|
||||
@return str
|
||||
'''
|
||||
"""
|
||||
|
||||
pma_version = self.get_pma_version()
|
||||
if not pma_version: return False
|
||||
@@ -105,19 +126,19 @@ class HttpProxy:
|
||||
old_phpversion = self.get_pma_phpversion()
|
||||
if not old_phpversion: return False
|
||||
if pma_version == '4.0':
|
||||
php_versions = ['52','53','54']
|
||||
php_versions = ['52', '53', '54']
|
||||
elif pma_version == '4.4':
|
||||
php_versions = ['54','55','56']
|
||||
php_versions = ['54', '55', '56']
|
||||
elif pma_version == '4.9':
|
||||
php_versions = ['55','56','70','71','72','73','74']
|
||||
php_versions = ['55', '56', '70', '71', '72', '73', '74']
|
||||
elif pma_version == '5.0':
|
||||
php_versions = ['70','71','72','73','74']
|
||||
php_versions = ['70', '71', '72', '73', '74']
|
||||
elif pma_version == '5.1':
|
||||
php_versions = ['71','72','73','74','80']
|
||||
php_versions = ['71', '72', '73', '74', '80']
|
||||
elif pma_version == '5.2':
|
||||
php_versions = ['72','73','74','80','81']
|
||||
php_versions = ['72', '73', '74', '80', '81']
|
||||
elif pma_version == '5.3':
|
||||
php_versions = ['72','73','74','80','81']
|
||||
php_versions = ['72', '73', '74', '80', '81']
|
||||
else:
|
||||
return False
|
||||
|
||||
@@ -138,92 +159,94 @@ class HttpProxy:
|
||||
args = public.dict_obj()
|
||||
args.phpversion = php_version
|
||||
ajax.ajax().setPHPMyAdmin(args)
|
||||
public.WriteLog('Database','The PHP version used by phpMyAdmin has been detected to be incompatible and has been automatically changed to the best compatible version: PHP-' + php_version)
|
||||
public.WriteLog(
|
||||
'Database',
|
||||
'The PHP version used by phpMyAdmin has been detected to be incompatible and has been automatically changed to the best compatible version: PHP-' + php_version
|
||||
)
|
||||
time.sleep(0.5)
|
||||
|
||||
|
||||
def get_request_headers(self):
|
||||
'''
|
||||
"""
|
||||
@name 获取请求头
|
||||
@author hwliang<2022-01-19>
|
||||
@return dict
|
||||
'''
|
||||
"""
|
||||
headers = {}
|
||||
rm_cookies = [app.config['SESSION_COOKIE_NAME'],'bt_user_info','file_recycle_status','ltd_end',
|
||||
'memSize','page_number','pro_end','request_token','serverType','site_model',
|
||||
'sites_path','soft_remarks','load_page','Path','distribution','order']
|
||||
rm_cookies = [app.config['SESSION_COOKIE_NAME'], 'bt_user_info', 'file_recycle_status', 'ltd_end',
|
||||
'memSize', 'page_number', 'pro_end', 'request_token', 'serverType', 'site_model',
|
||||
'sites_path', 'soft_remarks', 'load_page', 'Path', 'distribution', 'order']
|
||||
for k in request.headers.keys():
|
||||
headers[k] = request.headers.get(k)
|
||||
if k == 'Cookie':
|
||||
# noinspection PyUnresolvedReferences
|
||||
cookie_dict = SimpleCookie(headers[k])
|
||||
for rm_cookie in rm_cookies:
|
||||
if rm_cookie in cookie_dict:
|
||||
del(cookie_dict[rm_cookie])
|
||||
headers[k] = cookie_dict.output(header='',sep=';').strip()
|
||||
del (cookie_dict[rm_cookie])
|
||||
headers[k] = cookie_dict.output(header='', sep=';').strip()
|
||||
return headers
|
||||
|
||||
def form_to_dict(self,form):
|
||||
'''
|
||||
def form_to_dict(self, form):
|
||||
"""
|
||||
@name 将表单转为字典
|
||||
@author hwliang<2022-02-18>
|
||||
@param form<request.form> 表单数据
|
||||
@return dict
|
||||
'''
|
||||
"""
|
||||
|
||||
data = {}
|
||||
for k in form.keys():
|
||||
data[k] = form.getlist(k)
|
||||
if len(data[k]) == 1: data[k] = data[k][0]
|
||||
return data
|
||||
|
||||
def proxy(self,proxy_url):
|
||||
'''
|
||||
|
||||
def proxy(self, proxy_url: str, allow_redirects: bool = False):
|
||||
"""
|
||||
@name 代理指定URL地址
|
||||
@author hwliang<2022-01-19>
|
||||
@param proxy_url<string> 被代理的URL地址
|
||||
@return Response
|
||||
'''
|
||||
"""
|
||||
try:
|
||||
urllib3_conn.allowed_gai_family = lambda: socket.AF_INET
|
||||
s_key = 'proxy_{}_{}'.format(app.secret_key,self.get_pma_version())
|
||||
s_key = 'proxy_{}_{}'.format(app.secret_key, self.get_pma_version())
|
||||
|
||||
if not s_key in session:
|
||||
session[s_key] = requests.Session()
|
||||
session[s_key].keep_alive = False
|
||||
session[s_key].headers = {
|
||||
'User-Agent':'BT-Panel',
|
||||
'Connection':'close'
|
||||
'User-Agent': 'BT-Panel',
|
||||
'Connection': 'close'
|
||||
}
|
||||
|
||||
if proxy_url.find('phpmyadmin') != -1:
|
||||
if proxy_url.find('https://') == 0:
|
||||
session[s_key].cookies.update({'pma_lang_https':'zh_CN'})
|
||||
session[s_key].cookies.update({'pma_lang_https': 'zh_CN'})
|
||||
else:
|
||||
session[s_key].cookies.update({'pma_lang':'zh_CN'})
|
||||
session[s_key].cookies.update({'pma_lang': 'zh_CN'})
|
||||
self.set_pma_phpversion()
|
||||
|
||||
if 'Authorization' in request.headers:
|
||||
session[s_key].headers['Authorization'] = request.headers['Authorization']
|
||||
|
||||
try:
|
||||
session[s_key].headers['Host'] = public.en_punycode(request.url_root).replace('http://','').replace('https://','').split('/')[0]
|
||||
except:pass
|
||||
# headers = self.get_request_headers()
|
||||
session[s_key].headers['Host'] = public.en_punycode(
|
||||
request.url_root
|
||||
).replace('http://', '').replace('https://', '').split('/')[0]
|
||||
except:
|
||||
pass
|
||||
headers = None
|
||||
if request.method == 'GET':
|
||||
# 转发GET请求
|
||||
p_res = session[s_key].get(proxy_url,headers=headers,verify=False,allow_redirects=False)
|
||||
p_res = session[s_key].get(
|
||||
proxy_url, headers=headers, verify=False, allow_redirects=allow_redirects
|
||||
)
|
||||
elif request.method == 'POST':
|
||||
# 转发POST请求
|
||||
if request.files: # 如果上传文件
|
||||
if request.files: # 如果上传文件
|
||||
tmp_path = '{}/tmp'.format(public.get_panel_path())
|
||||
if not os.path.exists(tmp_path): os.makedirs(tmp_path,384)
|
||||
|
||||
# 处理请求头
|
||||
if headers:
|
||||
if 'Content-Type' in headers: del(headers['Content-Type'])
|
||||
if 'Content-Length' in headers: del(headers['Content-Length'])
|
||||
|
||||
if not os.path.exists(tmp_path): os.makedirs(tmp_path, 384)
|
||||
|
||||
# 遍历form表单中的所有文件
|
||||
files = {}
|
||||
f_list = {}
|
||||
@@ -231,47 +254,150 @@ class HttpProxy:
|
||||
upload_files = request.files.getlist(key)
|
||||
filename = upload_files[0].filename
|
||||
if not filename: filename = public.GetRandomString(12)
|
||||
tmp_file = '{}/{}'.format(tmp_path,filename)
|
||||
|
||||
|
||||
tmp_file = '{}/{}'.format(tmp_path, filename)
|
||||
|
||||
# 保存上传文件到临时目录
|
||||
with open(tmp_file,'wb') as f:
|
||||
with open(tmp_file, 'wb') as f:
|
||||
for tmp_f in upload_files:
|
||||
f.write(tmp_f.read())
|
||||
f.close()
|
||||
|
||||
|
||||
# 构造文件上传对象
|
||||
f_list[key] = open(tmp_file,'rb')
|
||||
f_list[key] = open(tmp_file, 'rb')
|
||||
files[key] = (filename, f_list[key])
|
||||
|
||||
|
||||
# 删除临时文件
|
||||
if os.path.exists(tmp_file): os.remove(tmp_file)
|
||||
|
||||
|
||||
# 转发上传请求
|
||||
|
||||
p_res = session[s_key].post(proxy_url,self.form_to_dict(request.form),headers=headers,files=files,verify=False,allow_redirects=False)
|
||||
|
||||
|
||||
p_res = session[s_key].post(
|
||||
proxy_url,
|
||||
self.form_to_dict(request.form),
|
||||
headers=headers,
|
||||
files=files,
|
||||
verify=False,
|
||||
allow_redirects=allow_redirects
|
||||
)
|
||||
|
||||
# 释放文件对象
|
||||
for fkey in f_list.keys():
|
||||
f_list[fkey].close()
|
||||
else:
|
||||
p_res = session[s_key].post(proxy_url,self.form_to_dict(request.form),headers=headers,verify=False,allow_redirects=False)
|
||||
p_res = session[s_key].post(
|
||||
proxy_url,
|
||||
self.form_to_dict(request.form),
|
||||
headers=headers,
|
||||
verify=False,
|
||||
allow_redirects=allow_redirects
|
||||
)
|
||||
else:
|
||||
return Response('不支持的请求类型',500)
|
||||
return Response('不支持的请求类型', 500)
|
||||
|
||||
# PHP版本自动切换处理
|
||||
if proxy_url.find('phpmyadmin') != -1 and proxy_url.find('/index.php') != -1:
|
||||
if len(p_res.content) < 1024:
|
||||
if p_res.content.find(b'syntax error, unexpected') != -1 or p_res.content.find(b'offset access syntax with') != -1 or p_res.content.find(b'+ is required') != -1:
|
||||
if p_res.content.find(b'syntax error, unexpected') != -1 or p_res.content.find(
|
||||
b'offset access syntax with') != -1 or p_res.content.find(b'+ is required') != -1:
|
||||
self.set_pma_phpversion()
|
||||
return 'Incompatible PHP version, an attempt has been made to automatically switch to a compatible PHP version, please refresh the page and try again!'
|
||||
elif p_res.content.find(b'<strong>Deprecation Notice</strong>') != -1 and not session.get('set_pma_phpversion'):
|
||||
elif p_res.content.find(b'<strong>Deprecation Notice</strong>') != -1 and not session.get(
|
||||
'set_pma_phpversion'):
|
||||
self.set_pma_phpversion()
|
||||
session['set_pma_phpversion'] = True
|
||||
return 'Incompatible PHP version, an attempt has been made to automatically switch to a compatible PHP version, please refresh the page and try again!'
|
||||
|
||||
res = Response(p_res.content,headers=self.get_res_headers(p_res),content_type=p_res.headers.get('content-type',None),status=p_res.status_code)
|
||||
res = self.set_res_headers(res,p_res)
|
||||
res = Response(
|
||||
p_res.content,
|
||||
headers=self.get_res_headers(p_res),
|
||||
content_type=p_res.headers.get('content-type', None),
|
||||
status=p_res.status_code
|
||||
)
|
||||
res = self.set_res_headers(res, p_res)
|
||||
return res
|
||||
except Exception as ex:
|
||||
return Response(str(ex),500)
|
||||
err_msg = re.sub(r"adminer_\S+", "adminer_...", str(ex))
|
||||
err_msg = re.sub(r"phpmyadmin_\S+", "phpmyadmin_...", err_msg)
|
||||
return Response(err_msg, 500)
|
||||
|
||||
# todo未完善
|
||||
def proxy_socket(self, proxy_url: str, allow_redirects: bool = False):
|
||||
"""
|
||||
@name socket代理
|
||||
@param proxy_url http+unix://<socket_path>/<request_uri>
|
||||
@return Response
|
||||
"""
|
||||
try:
|
||||
if not proxy_url.startswith("http+unix://"):
|
||||
return self._err_resp(
|
||||
"Socket proxy error: proxy_url format error. It should start with 'http+unix://'"
|
||||
)
|
||||
|
||||
from urllib.parse import urlparse, urlunparse, quote
|
||||
try:
|
||||
from requests_unixsocket import Session as ux_Session
|
||||
except ImportError:
|
||||
public.ExecShell("btpip install requests_unixsocket")
|
||||
try:
|
||||
# noinspection PyUnresolvedReferences
|
||||
from requests_unixsocket import Session as ux_Session
|
||||
except:
|
||||
return self._err_resp("The 'requests_unixsocket' module is not installed")
|
||||
parsed_url = urlparse(proxy_url)
|
||||
if parsed_url.scheme == "http+unix":
|
||||
full_path = parsed_url.netloc + parsed_url.path
|
||||
if not full_path.startswith("/"):
|
||||
full_path = "/" + full_path
|
||||
|
||||
socket_ext = ".sock"
|
||||
socket_pos = full_path.find(socket_ext)
|
||||
if socket_pos != -1:
|
||||
socket_path_end = socket_pos + len(socket_ext)
|
||||
socket_path = full_path[:socket_path_end]
|
||||
request_uri = full_path[socket_path_end:]
|
||||
if not request_uri:
|
||||
request_uri = "/"
|
||||
|
||||
encoded_socket_path = quote(socket_path, safe="")
|
||||
# format: http+unix://<socket_path>/<request_uri>
|
||||
proxy_url = urlunparse((
|
||||
parsed_url.scheme,
|
||||
encoded_socket_path,
|
||||
request_uri,
|
||||
parsed_url.params,
|
||||
parsed_url.query,
|
||||
parsed_url.fragment
|
||||
))
|
||||
else:
|
||||
return self._err_resp("Socket proxy error: Invalid socket proxy URL format.")
|
||||
|
||||
sess = ux_Session()
|
||||
headers = self.get_request_headers()
|
||||
if request.method == "GET":
|
||||
p_res = sess.get(
|
||||
proxy_url, headers=headers, timeout=10, allow_redirects=allow_redirects
|
||||
)
|
||||
elif request.method == "POST":
|
||||
data = self.form_to_dict(request.form)
|
||||
files = None
|
||||
if request.files:
|
||||
files = {}
|
||||
for key in request.files:
|
||||
fs = request.files.getlist(key)[0]
|
||||
files[key] = (fs.filename, fs.stream)
|
||||
|
||||
p_res = sess.post(
|
||||
proxy_url, data=data, files=files, headers=headers, timeout=10, allow_redirects=allow_redirects
|
||||
)
|
||||
else:
|
||||
return self._err_resp(f"Unsupported method: {request.method}")
|
||||
|
||||
return Response(
|
||||
p_res.content,
|
||||
status=p_res.status_code,
|
||||
headers=headers,
|
||||
content_type=p_res.headers.get("content-type", None)
|
||||
)
|
||||
|
||||
except Exception as ex:
|
||||
return self._err_resp(f"Socket proxy error: {str(ex)}")
|
||||
|
||||
+22
-8
@@ -5015,11 +5015,17 @@ location %s
|
||||
|
||||
#取当站点前运行目录
|
||||
def GetSiteRunPath(self,get):
|
||||
siteName = public.M('sites').where('id=?',(get.id,)).getField('name')
|
||||
sitePath = public.M('sites').where('id=?',(get.id,)).getField('path')
|
||||
site = public.M('sites').where('id=?',(get.id,)).field('name,path,service_type').find()
|
||||
if not site: return {"runPath": "/", 'dirs': []}
|
||||
siteName = site['name']
|
||||
sitePath = site['path']
|
||||
if not siteName or os.path.isfile(sitePath): return {"runPath":"/",'dirs':[]}
|
||||
path = sitePath
|
||||
if public.get_webserver() == 'nginx':
|
||||
# 兼容多服务
|
||||
webserver = public.get_webserver()
|
||||
if public.get_multi_webservice_status():
|
||||
webserver = site['service_type'] if site['service_type'] else 'nginx'
|
||||
|
||||
if webserver == 'nginx':
|
||||
filename = self.setupPath + '/panel/vhost/nginx/' + siteName + '.conf'
|
||||
if os.path.exists(filename):
|
||||
conf = public.readFile(filename)
|
||||
@@ -5028,7 +5034,7 @@ location %s
|
||||
if not path:
|
||||
return public.return_msg_gettext(False, public.lang("Get Site run path false"))
|
||||
path = path.groups()[0]
|
||||
elif public.get_webserver() == 'apache':
|
||||
elif webserver == 'apache':
|
||||
filename = self.setupPath + '/panel/vhost/apache/' + siteName + '.conf'
|
||||
if os.path.exists(filename):
|
||||
conf = public.readFile(filename)
|
||||
@@ -5720,7 +5726,12 @@ RewriteRule \.(BTPFILE)$ /404.html [R,NC]
|
||||
@author hwliang<2022-01-14>
|
||||
@return bool
|
||||
'''
|
||||
default_conf_body = '''<VirtualHost *:80>
|
||||
port_80 = '80'
|
||||
port_443 = '443'
|
||||
if public.get_multi_webservice_status():
|
||||
port_443 = '8290'
|
||||
port_80 = '8288'
|
||||
default_conf_body = f'''<VirtualHost *:{port_80}>
|
||||
ServerAdmin webmaster@example.com
|
||||
DocumentRoot "/www/server/apache/htdocs"
|
||||
ServerName bt.default.com
|
||||
@@ -5733,7 +5744,7 @@ RewriteRule \.(BTPFILE)$ /404.html [R,NC]
|
||||
DirectoryIndex index.html
|
||||
</Directory>
|
||||
</VirtualHost>
|
||||
<VirtualHost *:443>
|
||||
<VirtualHost *:{port_443}>
|
||||
ServerAdmin webmaster@example.com
|
||||
DocumentRoot "/www/server/apache/htdocs"
|
||||
ServerName ssl.default.com
|
||||
@@ -5765,7 +5776,10 @@ RewriteRule \.(BTPFILE)$ /404.html [R,NC]
|
||||
@author hwliang<2022-01-14>
|
||||
@return bool
|
||||
'''
|
||||
default_conf_body = '''<VirtualHost *:80>
|
||||
port = '80'
|
||||
if public.get_multi_webservice_status():
|
||||
port = '8290'
|
||||
default_conf_body = f'''<VirtualHost *:{port}>
|
||||
ServerAdmin webmaster@example.com
|
||||
DocumentRoot "/www/server/apache/htdocs"
|
||||
ServerName bt.default.com
|
||||
|
||||
@@ -1,11 +1,17 @@
|
||||
# coding: utf-8
|
||||
|
||||
from .fields import *
|
||||
from .manager import Q, QueryProperty
|
||||
from .model import aaModel
|
||||
|
||||
__version__ = "1.1.2"
|
||||
# from .file_model import *
|
||||
|
||||
__version__ = "1.1.3"
|
||||
|
||||
__all__ = [
|
||||
"aaModel", "Q", "QueryProperty",
|
||||
"__version__",
|
||||
# "DictFileModel",
|
||||
# "ListFileModel",
|
||||
"QueryProperty",
|
||||
"aaModel",
|
||||
"Q",
|
||||
] + fields.__all__
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
# coding: utf-8
|
||||
import json
|
||||
import sys
|
||||
import os
|
||||
import sqlite3 as Engine
|
||||
import uuid
|
||||
from functools import reduce
|
||||
from itertools import chain
|
||||
from typing import Optional, TypeVar, Generic, Any, List, Dict, Generator, Iterable
|
||||
|
||||
from public import ExecShell
|
||||
from public.aaModel.fields import COMPARE
|
||||
from public.exceptions import HintException, PanelError
|
||||
from public.sqlite_easy import Db
|
||||
@@ -16,37 +16,48 @@ __all__ = ["aaManager", "Q", "QueryProperty"]
|
||||
M = TypeVar("M", bound="aaModel")
|
||||
|
||||
|
||||
def get_flag() -> bool:
|
||||
import sqlite3
|
||||
# ==================== Patch ==================
|
||||
def _builtin(check_engine: Engine = None) -> bool:
|
||||
if not check_engine:
|
||||
check_engine = Engine
|
||||
try:
|
||||
conn = sqlite3.connect(":memory:")
|
||||
conn = check_engine.connect(":memory:")
|
||||
cursor = conn.cursor()
|
||||
cursor.execute("SELECT json_extract('{\"a\": 1}', '$.a')")
|
||||
cursor.execute("SELECT COUNT(*) FROM json_each('{\"a\":1, \"b\":2}')")
|
||||
conn.close()
|
||||
return True
|
||||
except sqlite3.Error:
|
||||
return False
|
||||
except:
|
||||
return False
|
||||
|
||||
|
||||
def _setup():
|
||||
if get_flag():
|
||||
return
|
||||
def _get_engine() -> tuple[bool, Engine]:
|
||||
try:
|
||||
import pysqlite3
|
||||
sys.modules["sqlite3"] = pysqlite3
|
||||
except ImportError:
|
||||
import pysqlite3 as engine
|
||||
flag = True
|
||||
except:
|
||||
try:
|
||||
ExecShell("btpip install pysqlite3-binary")
|
||||
import pysqlite3
|
||||
sys.modules["sqlite3"] = pysqlite3
|
||||
os.system("btpip install pysqlite3-binary")
|
||||
import pysqlite3 as engine
|
||||
flag = True
|
||||
except:
|
||||
pass
|
||||
engine = Engine
|
||||
flag = False
|
||||
|
||||
return flag, engine
|
||||
|
||||
|
||||
# _setup()
|
||||
_ENGINE = None
|
||||
_INSTEAD = False
|
||||
_ORG = _builtin()
|
||||
|
||||
if not _ORG:
|
||||
_INSTEAD, _ENGINE = _get_engine()
|
||||
else:
|
||||
_ENGINE = Engine
|
||||
|
||||
|
||||
# ==================== Patch End ==================
|
||||
|
||||
|
||||
class QueryProperty:
|
||||
@@ -58,20 +69,13 @@ class QueryProperty:
|
||||
|
||||
|
||||
class Operator:
|
||||
_shared_flag = None
|
||||
|
||||
def __new__(cls, *args, **kwargs):
|
||||
if cls._shared_flag is None:
|
||||
cls._shared_flag = get_flag()
|
||||
return super().__new__(cls)
|
||||
|
||||
def __init__(self, model_class: M, query: Db.query):
|
||||
self._model_class: M = model_class
|
||||
self._query = query
|
||||
self._tb = self._model_class.__table_name__
|
||||
self._fields = self._model_class._get_fields()
|
||||
self._serializes = self._model_class._get_serialized()
|
||||
self._flag = self._shared_flag # fk flag
|
||||
self._flag = _ORG or _INSTEAD # fk flag
|
||||
|
||||
def _q_error(self, key: str, act: str, val: Any, sp_act: tuple):
|
||||
raise HintException(
|
||||
@@ -760,7 +764,10 @@ class aaObjects(Generic[M]):
|
||||
@property
|
||||
def _query(self) -> Db.query:
|
||||
if not self.__q:
|
||||
q = Db(self._model.__db_name__).query()
|
||||
q = Db(
|
||||
db_name=self._model.__db_name__,
|
||||
engine=_ENGINE,
|
||||
).query()
|
||||
self.__q = q.table(self._model.__table_name__)
|
||||
return self.__q
|
||||
|
||||
@@ -856,7 +863,9 @@ class aaMigrate:
|
||||
raise PanelError(f"{self.__model.__class__.__name__} need 'fields'")
|
||||
|
||||
try:
|
||||
self.__client = Db(self.__model.__db_name__)
|
||||
self.__client = Db(
|
||||
db_name=self.__model.__db_name__, engine=_ENGINE
|
||||
)
|
||||
self.__table_exists()
|
||||
self.__index_exists()
|
||||
except Exception as e:
|
||||
|
||||
+231
-34
@@ -1,26 +1,40 @@
|
||||
# 公共模块
|
||||
# @author Zhj<2024/06/15>
|
||||
import base64
|
||||
import binascii
|
||||
import contextlib
|
||||
import json, os, sys, time, re, socket, importlib, binascii, base64, io, string, psutil, requests
|
||||
import fnmatch
|
||||
import gettext
|
||||
import gzip
|
||||
import importlib
|
||||
import json
|
||||
import os
|
||||
import psutil
|
||||
import re
|
||||
import shutil
|
||||
import socket
|
||||
import string
|
||||
import sys
|
||||
import tempfile
|
||||
import threading
|
||||
import time
|
||||
import typing
|
||||
from datetime import datetime
|
||||
from typing import Any, List, Set
|
||||
|
||||
import fcntl
|
||||
import werkzeug.datastructures
|
||||
from typing import Any, List
|
||||
|
||||
import public
|
||||
from .exceptions import PanelError
|
||||
from .validate import Param, trim_filter
|
||||
from .regexplib import match_ipv4, match_ipv6, match_class_private_property, match_safe_path, match_based_host, \
|
||||
find_url_root, search_sql_special_chars
|
||||
from .tools import is_number
|
||||
from .structures import aap_t_simple_result, aap_t_mysql_dump_info, aap_t_http_multipart
|
||||
import gzip
|
||||
import fcntl
|
||||
import shutil
|
||||
import tempfile
|
||||
from datetime import datetime
|
||||
from .regexplib import *
|
||||
from .sqlite_easy import Db, SqliteEasy
|
||||
import threading
|
||||
from .structures import *
|
||||
from .tools import is_number
|
||||
from .validate import Param, trim_filter
|
||||
|
||||
aap_t_simple_result = aap_t_simple_result
|
||||
aap_t_mysql_dump_info = aap_t_mysql_dump_info
|
||||
|
||||
path = "/www/server/panel/BTPanel/languages/language.pl"
|
||||
if os.path.exists(path):
|
||||
@@ -608,11 +622,12 @@ def WriteLog(type, logMsg, args=(), not_web=False):
|
||||
if not _LAN_LOG:
|
||||
_LAN_LOG = json.loads(ReadFile('BTPanel/static/language/' + GetLanguage() + '/log.json'))
|
||||
keys = _LAN_LOG.keys()
|
||||
if type in keys:
|
||||
type = _LAN_LOG[type]
|
||||
if logMsg in keys:
|
||||
logMsg = _LAN_LOG[logMsg]
|
||||
for i in range(len(args)):
|
||||
rep = '{' + str(i + 1) + '}'
|
||||
logMsg = logMsg.replace(rep, args[i])
|
||||
if type in keys: type = _LAN_LOG[type]
|
||||
# try:
|
||||
# if 'login_address' in session:
|
||||
# logMsg = '{} {}'.format(session['login_address'], logMsg)
|
||||
@@ -722,6 +737,27 @@ def getMsg(key, args=()):
|
||||
|
||||
# 获取Web服务器
|
||||
def GetWebServer():
|
||||
# 优先从请求头获取(仅在 Flask 请求上下文中)
|
||||
try:
|
||||
from flask import has_request_context
|
||||
except Exception:
|
||||
has_request_context = lambda: False
|
||||
|
||||
if has_request_context():
|
||||
try:
|
||||
from flask import request
|
||||
header_val = request.headers.get('Aap-Web-Server')
|
||||
if header_val:
|
||||
v = str(header_val).strip().lower()
|
||||
# 支持常见别名
|
||||
if v in ('nginx', 'apache', 'openlitespeed', 'ols'):
|
||||
# 规范化返回 openlitespeed 名称
|
||||
if v == 'ols':
|
||||
return 'openlitespeed'
|
||||
return v
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
nginxSbin = '{}/nginx/sbin/nginx'.format(get_setup_path())
|
||||
apacheBin = '{}/apache/bin/apachectl'.format(get_setup_path())
|
||||
olsBin = '/usr/local/lsws/bin/lswsctrl'
|
||||
@@ -744,16 +780,49 @@ def get_webserver():
|
||||
|
||||
|
||||
def ServiceReload():
|
||||
# 重载Web服务配置
|
||||
if os.path.exists('{}/nginx/sbin/nginx'.format(get_setup_path())):
|
||||
result = ExecShell('/etc/init.d/nginx reload')
|
||||
if result[1].find('nginx.pid') != -1:
|
||||
ExecShell('pkill -9 nginx && sleep 1')
|
||||
ExecShell('/etc/init.d/nginx start')
|
||||
elif os.path.exists('{}/apache/bin/apachectl'.format(get_setup_path())):
|
||||
result = ExecShell('/etc/init.d/httpd reload')
|
||||
# 获取多服务状态和安装路径
|
||||
is_multi = get_multi_webservice_status()
|
||||
setup_path = get_setup_path()
|
||||
|
||||
# 定义服务操作映射
|
||||
services = [
|
||||
(
|
||||
f"{setup_path}/nginx/sbin/nginx",
|
||||
"/etc/init.d/nginx reload",
|
||||
"pkill -9 nginx && sleep 1 && /etc/init.d/nginx start"
|
||||
),
|
||||
(
|
||||
f"{setup_path}/apache/bin/apachectl",
|
||||
"/etc/init.d/httpd reload",
|
||||
None
|
||||
),
|
||||
(
|
||||
"/usr/local/lsws/bin/lswsctrl",
|
||||
"rm -f /tmp/lshttpd/*.sock* && /usr/local/lsws/bin/lswsctrl restart",
|
||||
None
|
||||
)
|
||||
]
|
||||
|
||||
result = None
|
||||
# 多服务模式:遍历所有服务并执行
|
||||
if is_multi:
|
||||
for path, cmd, err_cmd in services:
|
||||
if os.path.exists(path):
|
||||
result = ExecShell(cmd)
|
||||
# 处理nginx pid异常
|
||||
if "nginx" in path and result[1].find("nginx.pid") != -1:
|
||||
result = ExecShell(err_cmd)
|
||||
|
||||
# 单服务模式:找到第一个存在的服务执行
|
||||
else:
|
||||
result = ExecShell('rm -f /tmp/lshttpd/*.sock* && /usr/local/lsws/bin/lswsctrl restart')
|
||||
for path, cmd, err_cmd in services:
|
||||
if os.path.exists(path):
|
||||
result = ExecShell(cmd)
|
||||
# 处理nginx pid异常
|
||||
if "nginx" in path and result[1].find("nginx.pid") != -1:
|
||||
result = ExecShell(err_cmd)
|
||||
break # 只执行第一个匹配的服务
|
||||
|
||||
return result
|
||||
|
||||
|
||||
@@ -1788,10 +1857,18 @@ def checkIp(ip):
|
||||
# 检查端口是否合法
|
||||
def checkPort(port):
|
||||
if not is_number(port): return False
|
||||
ports = ['21', '25', '443', '8080', '888', '8888', '8443', '7800']
|
||||
ports = [
|
||||
'21', '25', '443', '8080', '888', '999', '8888', '8443', '7800', '8188', '8189', '8288', '8289', '8290'
|
||||
]
|
||||
if port in ports: return False
|
||||
intport = int(port)
|
||||
if intport < 1 or intport > 65535: return False
|
||||
|
||||
# 判断端口占用,避免多服务崩溃
|
||||
res = ExecShell(f'lsof -i :{port} -P -n -l -F pnc')
|
||||
if res[0] and port != '80':
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
|
||||
@@ -2213,7 +2290,7 @@ def load_module(pluginCode):
|
||||
|
||||
# 解密数据
|
||||
def auth_decode(data):
|
||||
token = GetToken()
|
||||
token: dict = GetToken()
|
||||
# 是否有生成Token
|
||||
if not token: return returnMsg(False, 'REQUEST_ERR')
|
||||
|
||||
@@ -3184,11 +3261,14 @@ def auto_backup_panel():
|
||||
if os.path.getsize('{}/data/system.db'.format(panel_paeh)) > max_size:
|
||||
ignore_system = 'system.db'
|
||||
os.makedirs(backup_path, 384)
|
||||
import shutil
|
||||
shutil.copytree(panel_paeh + '/data', backup_path + '/data',
|
||||
ignore=shutil.ignore_patterns(ignore_system, ignore_default, 'wp_package_checksums', 'wp_packages','maillog', 'mail'))
|
||||
shutil.copytree(panel_paeh + '/config', backup_path + '/config')
|
||||
shutil.copytree(panel_paeh + '/vhost', backup_path + '/vhost')
|
||||
ignore_list = [
|
||||
ignore_system, ignore_default,
|
||||
'wp_package_checksums', 'wp_packages', 'maillog', 'mail', '*.sock'
|
||||
]
|
||||
cp_dir(f"{panel_paeh}/data", f"{backup_path}/data", ignores=ignore_list)
|
||||
cp_dir(f"{panel_paeh}/config", f"{backup_path}/config")
|
||||
cp_dir(f"{panel_paeh}/vhost", f"{backup_path}/vhost")
|
||||
|
||||
ExecShell("cd {} && zip {} -r {}/".format(b_path, backup_file, day_date))
|
||||
ExecShell("chmod -R 600 {path};chown -R root.root {path}".format(path=backup_file))
|
||||
if os.path.exists(backup_path): shutil.rmtree(backup_path)
|
||||
@@ -3446,6 +3526,9 @@ def get_site_php_version(siteName):
|
||||
@return string
|
||||
'''
|
||||
web_server = get_webserver()
|
||||
if public.get_multi_webservice_status():
|
||||
site = public.M('sites').where('name = ?',siteName).field('service_type').find()
|
||||
web_server = site['service_type'] if site['service_type'] else 'nginx'
|
||||
vhost_path = get_vhost_path()
|
||||
conf = readFile(vhost_path + '/' + web_server + '/' + siteName + '.conf')
|
||||
if web_server == 'openlitespeed':
|
||||
@@ -5371,7 +5454,7 @@ def check_site_path(site_path):
|
||||
try:
|
||||
if site_path in ['/', '/usr', '/dev', '/home', '/media', '/mnt', '/opt', '/tmp', '/var']:
|
||||
return False
|
||||
whites = ['/www/server/tomcat', '/www/server/stop', '/www/server/phpmyadmin']
|
||||
whites = ['/www/server/tomcat', '/www/server/stop', '/www/server/phpmyadmin', '/www/server/adminer']
|
||||
for w in whites:
|
||||
if site_path.find(w) == 0: return True
|
||||
a, error_paths = get_sys_path()
|
||||
@@ -8174,7 +8257,6 @@ def check_area_panel():
|
||||
@name: 检查地区限制
|
||||
@return:
|
||||
'''
|
||||
import contextlib
|
||||
areas_dict = get_limit_area()
|
||||
|
||||
# 关闭状态直接返回false
|
||||
@@ -9445,4 +9527,119 @@ def split_domain_sld(domain: str):
|
||||
if len(parts) <= num_of_tld_parts + 1:
|
||||
return domain, ""
|
||||
else:
|
||||
return ".".join(parts[-num_of_tld_parts-1:]), ".".join(parts[:-num_of_tld_parts-1])
|
||||
return ".".join(parts[-num_of_tld_parts-1:]), ".".join(parts[:-num_of_tld_parts-1])
|
||||
|
||||
# 获取多服务状态
|
||||
def get_multi_webservice_status():
|
||||
nginxSbin = '{}/nginx/sbin/nginx'.format(get_setup_path())
|
||||
apacheBin = '{}/apache/bin/apachectl'.format(get_setup_path())
|
||||
olsBin = '/usr/local/lsws/bin/lswsctrl'
|
||||
|
||||
if os.path.exists(nginxSbin) and (os.path.exists(apacheBin) or os.path.exists(olsBin)):
|
||||
return True
|
||||
return False
|
||||
|
||||
# 获取已存在的服务
|
||||
def get_multi_webservice_list() -> list:
|
||||
nginxSbin = '{}/nginx/sbin/nginx'.format(get_setup_path())
|
||||
apacheBin = '{}/apache/bin/apachectl'.format(get_setup_path())
|
||||
olsBin = '/usr/local/lsws/bin/lswsctrl'
|
||||
|
||||
server_list = []
|
||||
if os.path.exists(nginxSbin):
|
||||
server_list.append('nginx')
|
||||
|
||||
if os.path.exists(apacheBin):
|
||||
server_list.append('apache')
|
||||
|
||||
if os.path.exists(olsBin):
|
||||
server_list.append('openlitespeed')
|
||||
|
||||
return server_list
|
||||
|
||||
# 操作指定web服务
|
||||
def webservice_operation(service: str, type = 'restart') -> bool:
|
||||
"""
|
||||
service 服务名称
|
||||
type 类型:关闭,重启,开启
|
||||
"""
|
||||
try:
|
||||
import system_v2
|
||||
server_restart = system_v2.system()
|
||||
get = public.to_dict_obj({
|
||||
'name': service,
|
||||
'type': type
|
||||
})
|
||||
ok = server_restart.ServiceAdmin(get)
|
||||
|
||||
if ok.get('status') == 0:
|
||||
return True
|
||||
return False
|
||||
except Exception as e:
|
||||
print(e)
|
||||
return False
|
||||
|
||||
# Base64URL 编码
|
||||
def base64url_encode(data: bytes) -> str:
|
||||
import base64
|
||||
return base64.urlsafe_b64encode(data).rstrip(b'=').decode('utf-8')
|
||||
|
||||
# Base64URL 解码
|
||||
def base64url_decode(data: str) -> bytes:
|
||||
import base64
|
||||
padding = '=' * (4 - (len(data) % 4)) if len(data) % 4 != 0 else ''
|
||||
return base64.urlsafe_b64decode(data + padding)
|
||||
|
||||
|
||||
def cp_dir(src: str, dst: str, ignores: List[str] | Set[str] = None, overwrite: bool = True, ) -> None:
|
||||
"""
|
||||
site 递归复制文件夹
|
||||
src: 源路径
|
||||
dst: 目标路径
|
||||
ignore: 忽略的 list
|
||||
overwrite: 存在时是否覆盖
|
||||
|
||||
ps: ignore内的每个对象支持:
|
||||
*:匹配任意数量的任意字符(包括零个字符)。
|
||||
?:匹配任意单个字符。
|
||||
[abc]:匹配序列 abc中的任意字符。
|
||||
[!abc]:匹配不在序列 abc中的任意字符。
|
||||
"""
|
||||
if not os.path.exists(src):
|
||||
return
|
||||
|
||||
overwrite = False if isinstance(overwrite, int) and overwrite == 0 else True
|
||||
ignores = set(ignores) if ignores else set()
|
||||
|
||||
# 确保目标目录存在
|
||||
if not os.path.exists(dst):
|
||||
os.makedirs(dst, 0o755, exist_ok=True)
|
||||
|
||||
def _copy2(src_file: str, dst_file: str):
|
||||
if overwrite or not os.path.exists(dst_file):
|
||||
try:
|
||||
shutil.copy2(src_file, dst_file)
|
||||
except Exception:
|
||||
lock = False
|
||||
try:
|
||||
a, e = ExecShell(f"lsattr -d {dst_file}")
|
||||
if not e and "i" in a:
|
||||
lock = True
|
||||
ExecShell(f"chattr -i {dst_file}")
|
||||
shutil.copy2(src_file, dst_file)
|
||||
except:
|
||||
pass
|
||||
finally:
|
||||
if lock is True and os.path.exists(dst_file):
|
||||
ExecShell(f"chattr +i {dst_file}")
|
||||
|
||||
# 复制源目录下的所有内容到目标目录
|
||||
for item in os.listdir(src):
|
||||
src_item = os.path.join(src, item)
|
||||
dst_item = os.path.join(dst, item)
|
||||
if ignores and any(fnmatch.fnmatch(item, ignore) for ignore in ignores):
|
||||
continue
|
||||
if os.path.isdir(src_item):
|
||||
cp_dir(src_item, dst_item, ignores, overwrite)
|
||||
else:
|
||||
_copy2(src_item, dst_item)
|
||||
|
||||
@@ -1,5 +1,21 @@
|
||||
import re
|
||||
|
||||
|
||||
__all__ = [
|
||||
'match_ipv4',
|
||||
'match_ipv6',
|
||||
'match_safe_path',
|
||||
'match_class_private_property',
|
||||
'match_based_host',
|
||||
'find_url_root',
|
||||
'search_php_first_fatal_error',
|
||||
'search_http_response_status_line',
|
||||
'match_general_version_format',
|
||||
'match_md5_format',
|
||||
'search_sql_special_chars',
|
||||
'match_email',
|
||||
]
|
||||
|
||||
# 匹配IP地址
|
||||
match_ipv4 = re.compile(r'^(?:(?:25[0-5]|(?:2[0-4]|1?\d)?\d)\.){3}(?:25[0-5]|(?:2[0-4]|1?\d)?\d)$')
|
||||
match_ipv6 = re.compile(r'^(?:(?:[0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4})|(?:(?:[0-9a-fA-F]{1,4}:){1,7}:)|(?:(?:[0-9a-fA-F]{1,4}:){6}:[0-9a-fA-F]{1,4})|(?:(?:[0-9a-fA-F]{1,4}:){5}(?::[0-9a-fA-F]{1,4}){1,2})|(?:(?:[0-9a-fA-F]{1,4}:){4}(?::[0-9a-fA-F]{1,4}){1,3})|(?:(?:[0-9a-fA-F]{1,4}:){3}(?::[0-9a-fA-F]{1,4}){1,4})|(?:(?:[0-9a-fA-F]{1,4}:){2}(?::[0-9a-fA-F]{1,4}){1,5})|(?:(?:[0-9a-fA-F]{1,4}:){1}(?::[0-9a-fA-F]{1,4}){1,6})|(?::(?:(?::[0-9a-fA-F]{1,4}){1,7}|:))')
|
||||
|
||||
+15
-12
@@ -887,15 +887,17 @@ class DbConnection:
|
||||
@name Sqlite数据库连接类(相比Db类更加底层)
|
||||
@author Zhj<2022-12-13>
|
||||
'''
|
||||
__slots__ = ['__DB_NAME', '__DB_PATH', '__DB_LOCK_FILE', '__CONN', '__DEBUG_LOG']
|
||||
__slots__ = ['__DB_NAME', '__DB_PATH', '__DB_LOCK_FILE', '__CONN', '__DEBUG_LOG', 'ENGINE']
|
||||
|
||||
def __init__(self, db_name):
|
||||
def __init__(self, db_name, engine=None):
|
||||
'''
|
||||
@name 初始化函数
|
||||
@author Zhj<2022-12-14>
|
||||
@param db_name<string> 数据库名称(全路径 不包含.db)
|
||||
@return void
|
||||
'''
|
||||
|
||||
self.ENGINE = sqlite3 if engine is None else engine
|
||||
self.__DB_NAME = db_name
|
||||
self.__DB_PATH = '{}.db'.format(db_name)
|
||||
|
||||
@@ -961,11 +963,11 @@ class DbConnection:
|
||||
|
||||
# 连接sqlite
|
||||
def connect(self):
|
||||
if isinstance(self.__CONN, sqlite3.Connection):
|
||||
if isinstance(self.__CONN, self.ENGINE.Connection):
|
||||
return self.__CONN
|
||||
|
||||
# 连接数据库(写)
|
||||
self.__CONN = sqlite3.connect(self.__DB_PATH, timeout=15, check_same_thread=False)
|
||||
self.__CONN = self.ENGINE.connect(self.__DB_PATH, timeout=15, check_same_thread=False)
|
||||
self.__CONN.text_factory = str
|
||||
self.__CONN.isolation_level = 'IMMEDIATE'
|
||||
|
||||
@@ -975,7 +977,7 @@ class DbConnection:
|
||||
@name 关闭sqlite连接
|
||||
'''
|
||||
# 关闭sqlite数据库连接
|
||||
if isinstance(self.__CONN, sqlite3.Connection):
|
||||
if isinstance(self.__CONN, self.ENGINE.Connection):
|
||||
try:
|
||||
self.__CONN.close()
|
||||
except BaseException as e:
|
||||
@@ -995,7 +997,7 @@ class DbConnection:
|
||||
@name 提交事务
|
||||
@return bool
|
||||
'''
|
||||
if isinstance(self.__CONN, sqlite3.Connection) and self.__CONN.in_transaction:
|
||||
if isinstance(self.__CONN, self.ENGINE.Connection) and self.__CONN.in_transaction:
|
||||
self.__CONN.commit()
|
||||
return True
|
||||
|
||||
@@ -1007,7 +1009,7 @@ class DbConnection:
|
||||
@name 回滚事务
|
||||
@return bool
|
||||
'''
|
||||
if isinstance(self.__CONN, sqlite3.Connection) and self.__CONN.in_transaction:
|
||||
if isinstance(self.__CONN, self.ENGINE.Connection) and self.__CONN.in_transaction:
|
||||
self.__CONN.rollback()
|
||||
return True
|
||||
|
||||
@@ -1022,9 +1024,9 @@ class DbConnection:
|
||||
try:
|
||||
return fn(*args, **kwargs)
|
||||
except (
|
||||
SystemError, KeyError, sqlite3.InterfaceError, sqlite3.InternalError, sqlite3.OperationalError) as e:
|
||||
SystemError, KeyError, self.ENGINE.InterfaceError, self.ENGINE.InternalError, self.ENGINE.OperationalError) as e:
|
||||
# 数据库操作错误,不是锁协议错误,直接抛出异常
|
||||
if isinstance(e, sqlite3.OperationalError) and str(e) not in ['locking protocol',
|
||||
if isinstance(e, self.ENGINE.OperationalError) and str(e) not in ['locking protocol',
|
||||
'database is locked']:
|
||||
raise e
|
||||
|
||||
@@ -1299,11 +1301,11 @@ class Db:
|
||||
@name Sqlite数据库连接类
|
||||
@author Zhj<2022-07-18>
|
||||
'''
|
||||
__slots__ = ['__DB_NAME', '__DB_CONN', '__AUTO_COMMIT', '__AUTO_VACUUM', '__NEED_VACUUM', '__DEBUG_LOG', '__QUERIES']
|
||||
__slots__ = ['__DB_NAME', '__DB_CONN', '__AUTO_COMMIT', '__AUTO_VACUUM', '__NEED_VACUUM', '__DEBUG_LOG', '__QUERIES', 'ENGINE']
|
||||
|
||||
__DB_ROOT_DIR = '{}/data/'.format(_BASE_DIR)
|
||||
|
||||
def __init__(self, db_name):
|
||||
def __init__(self, db_name, engine=None):
|
||||
'''
|
||||
@name 初始化函数
|
||||
@author Zhj<2022-12-14>
|
||||
@@ -1311,6 +1313,7 @@ class Db:
|
||||
@param brandnew<bool> 是否开启一个全新连接
|
||||
@return void
|
||||
'''
|
||||
self.ENGINE = sqlite3 if engine is None else engine
|
||||
if str(db_name).startswith(':memory:'):
|
||||
self.__DB_NAME = db_name # 内存数据库
|
||||
else:
|
||||
@@ -1340,7 +1343,7 @@ class Db:
|
||||
@author Zhj<2022-07-16>
|
||||
@return self
|
||||
'''
|
||||
self.__DB_CONN = DbConnection(self.__DB_NAME)
|
||||
self.__DB_CONN = DbConnection(db_name=self.__DB_NAME, engine=self.ENGINE)
|
||||
return self
|
||||
|
||||
def close(self):
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
import collections
|
||||
|
||||
__all__ = [
|
||||
'aap_t_simple_result',
|
||||
'aap_t_mysql_dump_info',
|
||||
'aap_t_http_multipart',
|
||||
]
|
||||
|
||||
# Common structures
|
||||
aap_t_simple_result = collections.namedtuple('aap_t_simple_result', ['success', 'msg'])
|
||||
aap_t_mysql_dump_info = collections.namedtuple('aap_t_mysql_dump_info', ['db_name', 'file', 'dump_time'])
|
||||
|
||||
@@ -61,8 +61,9 @@ class userRegister:
|
||||
else:
|
||||
sUrl = '{}/api/user/register_on_panel'.format(public.OfficialApiBase())
|
||||
|
||||
|
||||
aa = public.httpPost(sUrl, params, timeout=60)
|
||||
aa = public.httpPost(sUrl, params, headers={
|
||||
'X-Forwarded-For': public.GetClientIp(),
|
||||
}, timeout=60)
|
||||
data = json.loads(aa)
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user