mirror of
https://github.com/aaPanel/aaPanel.git
synced 2026-08-17 21:25:47 +02:00
Since version 7.7.0, we recommend yours update python to 3.12. [+] Using nginx technology to load static files improves access speed [+] Refactor homepage, website, FTP, and database using vue3 [+] Table loading changed to skeleton screen [+] Add Website statistics-v2 professional plug-in [+] Add Home page - top 5 resource occupancy [+] Add protection for Files management (requires Tamper-proof for Enterprise 3.7) [+] Website, FTP, Databases page add program status [+] Add FTP log analysis (only supports Centos) [+] Add password-free login to phpMyAdmin [+] Add Proxy Project in Website (Supported when web service uses Nginx) [+] Add WP Toolkit (Pro version only) [+] Redesigned Docker module [+] Add WP Toolkit Protection [+] Add WP Toolkit Backup and Restore [+] Add WP Toolkit Migrated [+] Add WP Toolkit Clone site (supports new domain and subdomain) [+] Add WP Toolkit Create site from backup of other panel [+] Add WP Toolkit support for Cron automatic backup (only save Local disk) [+] Add WP Toolkit operation log [+] Add Integrity check for WP Toolkit [+] Add WP Toolkit plug-in management and themes management [*] Optimize phpMyAdmin formula access method [*] Optimize Home page PHP display problem [*] Optimize jump to the login interface after the login expires [*] Optimize automatic renewal of SSL at some times [*] Optimize Let's Encrypt to increase application success rate [-] Fix Logs Audit cannot be opened [-] Fix apache URL rewrite issue [-] Fix phpmyadmin installation problem [-] Fix the problem that some servers cannot install software [-] Fix upload file error [-] Fix left menu hiding problem [-] Fix aaPanel Mobile QR code display problem [-] Fix problem that third-party plug-ins are not displayed in the App Store [-] Fix issue where the menu bar is blank when opening new tabs [-] Fixed panel not being accessible in some cases [-] Fix the issue where Curl warning caused the inability to apply for SSL [-] Fix Quota issues for Website, FTP, Databases [-] Fix file interface display problem on mobile terminal
301 lines
13 KiB
Python
301 lines
13 KiB
Python
# coding: utf-8
|
|
# -------------------------------------------------------------------
|
|
# aaPanel
|
|
# -------------------------------------------------------------------
|
|
# Copyright (c) 2015-2099 aaPanel(www.aapanel.com) All rights reserved.
|
|
# -------------------------------------------------------------------
|
|
# Author: wzz <wzz@aapanel.com>
|
|
# -------------------------------------------------------------------
|
|
import json
|
|
import os
|
|
import traceback
|
|
from datetime import datetime
|
|
|
|
import gettext
|
|
_ = gettext.gettext
|
|
# 未处理关键字
|
|
|
|
import public
|
|
from btdockerModelV2 import dk_public as dp
|
|
from btdockerModelV2.dockerBase import dockerBase
|
|
from public.validate import Param
|
|
class main(dockerBase):
|
|
|
|
# 2023/12/27 下午 2:56 创建容器反向代理
|
|
def create_proxy(self, get):
|
|
'''
|
|
@name 创建容器反向代理
|
|
@author wzz <2023/12/27 下午 2:57>
|
|
@param "data":{"参数名":""} <数据类型> 参数描述
|
|
@return dict{"status":True/False,"msg":"提示信息"}
|
|
'''
|
|
|
|
# 校验参数
|
|
try:
|
|
get.validate([
|
|
Param('domain').Require(),
|
|
Param('container_port').Require(),
|
|
Param('container_name').Require(),
|
|
Param('container_id').Require(),
|
|
Param('privateKey').Require(),
|
|
Param('certPem').Require(),
|
|
], [
|
|
public.validate.trim_filter(),
|
|
])
|
|
except Exception as ex:
|
|
public.print_log("error info: {}".format(ex))
|
|
return public.return_message(-1, 0, ex)
|
|
|
|
try:
|
|
if not (os.path.exists('/etc/init.d/nginx') or os.path.exists('/etc/init.d/httpd')):
|
|
return public.return_message(-1, 0, 'nginx or apache server was not detected, please install one first!')
|
|
|
|
# if not hasattr(get, 'domain'):
|
|
# return public.return_message(-1, 0, 'parameter error')
|
|
#
|
|
# if not hasattr(get, 'container_port'):
|
|
# return public.return_message(-1, 0, 'parameter error')
|
|
|
|
self.siteName = get.domain.strip()
|
|
self.check_table_dk_sites()
|
|
if dp.sql('dk_sites').where('container_id=?', (get.container_id,)).order('id desc').find():
|
|
self.close_proxy(get)
|
|
# 2024/2/23 下午 12:05 如果其他地方有这个域名,则禁止添加
|
|
newpid = public.M('domain').where("name=? and port=?", (self.siteName, 80)).getField('pid')
|
|
if newpid:
|
|
result = public.M('sites').where("id=? and ps!=?",
|
|
(newpid, 'Reverse proxy for the container [{}]'.format(get.container_name))).find()
|
|
if result:
|
|
return public.return_message(-1, 0, _(
|
|
'Project Type [{}] Existing Domain: {}'.format(result['project_type'],
|
|
self.siteName)))
|
|
|
|
self.container_port = get.container_port
|
|
if not dp.check_socket(self.container_port):
|
|
return public.return_message(-1, 0, _( "Server port [{}] is not used, please enter the port in use to reverse!".format(self.container_port)))
|
|
|
|
self.sitePath = '/www/wwwroot/' + self.siteName
|
|
|
|
from panelSite import panelSite
|
|
args = public.to_dict_obj({
|
|
'webname': '{"domain":"'+ self.siteName +'","domainlist":[],"count":0}',
|
|
'type': 'docker',
|
|
'port': "80",
|
|
'ps': self.siteName,
|
|
'path': self.sitePath,
|
|
'type_id': 111,
|
|
'version': "00",
|
|
'ftp': False,
|
|
'sql': False,
|
|
})
|
|
panelSite().AddSite(args)
|
|
|
|
args = public.to_dict_obj({
|
|
'type': 1,
|
|
'proxyname': get.container_name + '_dk_proxy',
|
|
'cachetime': 1,
|
|
'proxydir': '/',
|
|
'cache': 0,
|
|
'subfilter': '[{"sub1":"","sub2":""},{"sub1":"","sub2":""},{"sub1":"","sub2":""}]',
|
|
'sitename': self.siteName,
|
|
'advanced': 0,
|
|
'proxysite': 'http://127.0.0.1:' + self.container_port,
|
|
'todomain': '$host',
|
|
})
|
|
import projectModel.proxyModel as proxyModel
|
|
proxyModel = proxyModel.main()
|
|
proxyModel.CreateProxy(args)
|
|
|
|
# 设置面板SSL
|
|
if hasattr(get, "privateKey") and hasattr(get, "certPem"):
|
|
args = public.to_dict_obj({
|
|
'type': '1',
|
|
'siteName': self.siteName,
|
|
'key': get.privateKey,
|
|
'csr': get.certPem,
|
|
})
|
|
panelSite().SetSSL(args)
|
|
|
|
# 写入数据库
|
|
newpid = public.M('domain').where("name=? and port=?", (self.siteName, 80)).getField('pid')
|
|
if newpid:
|
|
# 更新ps和project_type字段
|
|
public.M('sites').where("id=?", (newpid,)).save('ps,project_type', (
|
|
'Reverse proxy for the container [{}]'.format(get.container_name),
|
|
'proxy'))
|
|
|
|
site_pid = dp.sql('dk_sites').add(
|
|
'name,path,ps,addtime,container_id,container_name,container_port',
|
|
(self.siteName, self.sitePath, 'Reverse proxy for the container [{}]'.format(get.container_name),
|
|
datetime.now().strftime("%Y-%m-%d %H:%M:%S"), get.container_id, get.container_name, self.container_port)
|
|
)
|
|
if not site_pid:
|
|
return public.return_message(-1, 0, _( 'Add failure, database cannot be written!'))
|
|
# 检查数据库是否存在
|
|
self.check_table_dk_domain()
|
|
domain_id = dp.sql('dk_domain').where('id=?', (site_pid,)).find()
|
|
if not domain_id:
|
|
dp.sql('dk_domain').add(
|
|
'pid,name,addtime',
|
|
(site_pid, self.siteName, datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
|
|
)
|
|
|
|
return public.return_message(0, 0, _( 'successfully added!'))
|
|
except Exception as e:
|
|
return public.return_message(0, 0, _( 'Add failed, error {}!'.format(str(e))))
|
|
|
|
# 2024/1/2 下午 5:34 获取容器的反向代理信息
|
|
def get_proxy_info(self, get):
|
|
'''
|
|
@name 获取容器的反向代理信息
|
|
@author wzz <2024/1/2 下午 5:34>
|
|
@param "data":{"参数名":""} <数据类型> 参数描述
|
|
@return dict{"status":True/False,"msg":"提示信息"}
|
|
'''
|
|
# 校验参数
|
|
try:
|
|
get.validate([
|
|
Param('container_id').Require(),
|
|
|
|
], [
|
|
public.validate.trim_filter(),
|
|
])
|
|
except Exception as ex:
|
|
public.print_log("error info: {}".format(ex))
|
|
return public.return_message(-1, 0, ex)
|
|
|
|
try:
|
|
# if not hasattr(get, 'container_id'):
|
|
# return public.return_message(-1, 0, 'parameter error')
|
|
|
|
container_id = get.container_id
|
|
self.check_table_dk_sites()
|
|
proxy_info = dp.sql('dk_sites').where('container_id=?', (container_id,)).order('id desc').find()
|
|
# 没找到表
|
|
if isinstance(proxy_info, dict):
|
|
return public.return_message(-1, 0, proxy_info)
|
|
|
|
|
|
|
|
path = '/www/server/panel/vhost/cert/' + proxy_info['name']
|
|
csrpath = path + "/fullchain.pem"
|
|
keypath = path + "/privkey.pem"
|
|
if os.path.exists(csrpath) and os.path.exists(keypath):
|
|
try:
|
|
proxy_info['cert'] = public.readFile(csrpath)
|
|
proxy_info['key'] = public.readFile(keypath)
|
|
except:
|
|
proxy_info['cert'] = ""
|
|
proxy_info['key'] = ""
|
|
|
|
if not proxy_info:
|
|
return public.return_message(-1, 0, _( 'No reverse proxy information was detected!'))
|
|
return public.return_message(0, 0, proxy_info)
|
|
except Exception as ex:
|
|
print(traceback.format_exc())
|
|
public.print_log("error: {}".format(ex))
|
|
return public.return_message(-1, 0, {})
|
|
|
|
# 2024/1/2 下午 5:43 关闭容器的反向代理
|
|
def close_proxy(self, get):
|
|
'''
|
|
@name 关闭容器的反向代理
|
|
@param "data":{"参数名":""} <数据类型> 参数描述
|
|
@return dict{"status":True/False,"msg":"提示信息"}
|
|
'''
|
|
|
|
# 校验参数
|
|
try:
|
|
get.validate([
|
|
Param('container_id').Require().String(),
|
|
], [
|
|
public.validate.trim_filter(),
|
|
])
|
|
except Exception as ex:
|
|
public.print_log("error info: {}".format(ex))
|
|
return public.return_message(-1, 0, ex)
|
|
try:
|
|
# if not hasattr(get, 'container_id'):
|
|
# return public.return_message(-1, 0, 'parameter error!')
|
|
|
|
container_id = get.container_id
|
|
proxy_info = dp.sql('dk_sites').where('container_id=?', (container_id,)).order('id desc').find()
|
|
|
|
if not proxy_info:
|
|
return public.return_message(-1, 0, _( 'No reverse proxy information was detected!'))
|
|
|
|
newpid = public.M('domain').where("name=? and port=?", (proxy_info["name"], 80)).getField('pid')
|
|
if not newpid:
|
|
return public.return_message(-1, 0, _( 'No reverse proxy information was detected!'))
|
|
|
|
result = public.M('sites').where("id=? and ps=?", (newpid, 'Reverse proxy for the container [{}]'.format(proxy_info["container_name"]))).find()
|
|
# 删除反向代理
|
|
import projectModel.proxyModel as proxyModel
|
|
proxyModel = proxyModel.main()
|
|
|
|
args = public.to_dict_obj({
|
|
'id': result['id'],
|
|
'webname': proxy_info['name'],
|
|
'type': 1,
|
|
})
|
|
proxyModel.DeleteSite(args)
|
|
|
|
# 删除站点
|
|
public.M('sites').where("name=?", (proxy_info['name'],)).delete()
|
|
public.M('domain').where("name=?", (proxy_info['name'],)).delete()
|
|
|
|
# 删除数据库记录
|
|
dp.sql('dk_sites').where('container_id=?', (container_id,)).delete()
|
|
dp.sql('dk_domain').where('pid=?', (proxy_info['id'],)).delete()
|
|
|
|
return public.return_message(0, 0, _( 'successfully delete!'))
|
|
except:
|
|
return traceback.format_exc()
|
|
|
|
# 2024/1/2 下午 5:57 获取指定域名的证书内容
|
|
def get_cert_info(self, get):
|
|
'''
|
|
@name 获取指定域名的证书内容
|
|
@author wzz <2024/1/2 下午 5:58>
|
|
@param "data":{"参数名":""} <数据类型> 参数描述
|
|
@return dict{"status":True/False,"msg":"提示信息"}
|
|
'''
|
|
try:
|
|
if not hasattr(get, 'cert_name'): return public.return_message(-1, 0, _( 'parameter error!'))
|
|
cert_name = get.cert_name
|
|
# 2024/1/3 下午 4:50 处理通配符域名,将*.spider.com替换成spider.com
|
|
if cert_name.startswith('*.'):
|
|
cert_name = cert_name.replace('*.', '')
|
|
if not os.path.exists('/www/server/panel/vhost/ssl/{}'.format(cert_name)):
|
|
return public.return_message(-1, 0, _( 'Certificate does not exist!'))
|
|
cert_data = {}
|
|
cert_data['cert_name'] = cert_name
|
|
cert_data['cert'] = public.readFile('/www/server/panel/vhost/ssl/{}/fullchain.pem'.format(cert_name))
|
|
cert_data['key'] = public.readFile('/www/server/panel/vhost/ssl/{}/privkey.pem'.format(cert_name))
|
|
cert_data['info'] = json.loads(
|
|
public.readFile('/www/server/panel/vhost/ssl/{}/info.json'.format(cert_name)))
|
|
return public.return_message(-1, 0, cert_data)
|
|
except:
|
|
return public.return_message(-1, 0, traceback.format_exc())
|
|
|
|
def check_table_dk_domain(self):
|
|
'''
|
|
@name 检查并创建表
|
|
@return dict{"status":True/False,"msg":"提示信息"}
|
|
'''
|
|
if not dp.sql('sqlite_master').where('type=? AND name=?', ('table', 'dk_domain')).count():
|
|
dp.sql('dk_domain').execute(
|
|
"CREATE TABLE `dk_backup` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `pid` INTEGER, `name` TEXT, `addtime` TEXT )",
|
|
()
|
|
)
|
|
|
|
def check_table_dk_sites(self):
|
|
'''
|
|
@name 检查并创建表
|
|
@return dict{"status":True/False,"msg":"提示信息"}
|
|
'''
|
|
if not dp.sql('sqlite_master').where('type=? AND name=?', ('table', 'dk_sites')).count():
|
|
dp.sql('dk_sites').execute(
|
|
"CREATE TABLE `dk_backup` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `name` TEXT, `path` TEXT, `status` TEXT DEFAULT 1, `ps` TEXT, `addtime` TEXT, `type_id` integer DEFAULT 111, `edate` integer DEFAULT '0000-00-00', `project_type` STRING DEFAULT 'dk_proxy', `container_id` TEXT DEFAULT '', `container_name` TEXT DEFAULT '', `container_port` TEXT DEFAULT '')",
|
|
()
|
|
) |