6281 lines
268 KiB
Python
6281 lines
268 KiB
Python
|
|
# coding: utf-8
|
|||
|
|
# -------------------------------------------------------------------
|
|||
|
|
# YakPanel
|
|||
|
|
# -------------------------------------------------------------------
|
|||
|
|
# Copyright (c) 2015-2017 YakPanel(www.yakpanel.com) All rights reserved.
|
|||
|
|
# -------------------------------------------------------------------
|
|||
|
|
# Author: hwliang <hwl@yakpanel.com>
|
|||
|
|
# -------------------------------------------------------------------
|
|||
|
|
|
|||
|
|
# ------------------------------
|
|||
|
|
# 网站管理类
|
|||
|
|
#------------------------------
|
|||
|
|
import io,re,public,os,sys,shutil,json,hashlib,socket,time
|
|||
|
|
try:
|
|||
|
|
import OpenSSL
|
|||
|
|
except:
|
|||
|
|
os.system("btpip install pyOpenSSL -I")
|
|||
|
|
import OpenSSL
|
|||
|
|
import base64
|
|||
|
|
try:
|
|||
|
|
from YakPanel import session
|
|||
|
|
except:
|
|||
|
|
pass
|
|||
|
|
from panelRedirect import panelRedirect
|
|||
|
|
import site_dir_auth
|
|||
|
|
import one_key_wp
|
|||
|
|
from ssl_manage import SSLManger
|
|||
|
|
|
|||
|
|
|
|||
|
|
class panelSite(panelRedirect):
|
|||
|
|
siteName = None # 网站名称
|
|||
|
|
sitePath = None # 根目录
|
|||
|
|
sitePort = None # 端口
|
|||
|
|
phpVersion = None # PHP版本
|
|||
|
|
setupPath = None # 安装路径
|
|||
|
|
isWriteLogs = None # 是否写日志
|
|||
|
|
nginx_conf_bak = '/tmp/backup_nginx.conf'
|
|||
|
|
apache_conf_bak = '/tmp/backup_apache.conf'
|
|||
|
|
is_ipv6 = False
|
|||
|
|
|
|||
|
|
def __init__(self):
|
|||
|
|
self.setupPath = public.get_setup_path()
|
|||
|
|
path = self.setupPath + '/panel/vhost/nginx'
|
|||
|
|
if not os.path.exists(path): public.ExecShell("mkdir -p " + path + " && chmod -R 644 " + path)
|
|||
|
|
path = self.setupPath + '/panel/vhost/apache'
|
|||
|
|
if not os.path.exists(path): public.ExecShell("mkdir -p " + path + " && chmod -R 644 " + path)
|
|||
|
|
path = self.setupPath + '/panel/vhost/rewrite'
|
|||
|
|
if not os.path.exists(path): public.ExecShell("mkdir -p " + path + " && chmod -R 644 " + path)
|
|||
|
|
path = self.setupPath + '/stop'
|
|||
|
|
if not os.path.exists(path + '/index.html'):
|
|||
|
|
public.ExecShell('mkdir -p ' + path)
|
|||
|
|
public.ExecShell('wget -O ' + path + '/index.html ' + public.get_url() + '/stop_en.html &')
|
|||
|
|
self.__proxyfile = '{}/data/proxyfile.json'.format(public.get_panel_path())
|
|||
|
|
self.OldConfigFile()
|
|||
|
|
if os.path.exists(self.nginx_conf_bak): os.remove(self.nginx_conf_bak)
|
|||
|
|
if os.path.exists(self.apache_conf_bak): os.remove(self.apache_conf_bak)
|
|||
|
|
self.is_ipv6 = os.path.exists(self.setupPath + '/panel/data/ipv6.pl')
|
|||
|
|
sys.setrecursionlimit(1000000)
|
|||
|
|
self._proxy_path = '/www/server/proxy_project'
|
|||
|
|
self._proxy_config_path = self._proxy_path + '/sites'
|
|||
|
|
|
|||
|
|
# 默认配置文件
|
|||
|
|
def check_default(self):
|
|||
|
|
nginx = self.setupPath + '/panel/vhost/nginx'
|
|||
|
|
httpd = self.setupPath + '/panel/vhost/apache'
|
|||
|
|
httpd_default = '''<VirtualHost *:80>
|
|||
|
|
ServerAdmin webmaster@example.com
|
|||
|
|
DocumentRoot "/www/server/apache/htdocs"
|
|||
|
|
ServerName bt.default.com
|
|||
|
|
<Directory "/www/server/apache/htdocs">
|
|||
|
|
SetOutputFilter DEFLATE
|
|||
|
|
Options FollowSymLinks
|
|||
|
|
AllowOverride All
|
|||
|
|
Order allow,deny
|
|||
|
|
Allow from all
|
|||
|
|
DirectoryIndex index.html
|
|||
|
|
</Directory>
|
|||
|
|
</VirtualHost>'''
|
|||
|
|
|
|||
|
|
listen_ipv6 = ''
|
|||
|
|
if self.is_ipv6: listen_ipv6 = "\n listen [::]:80;"
|
|||
|
|
nginx_default = '''server
|
|||
|
|
{
|
|||
|
|
listen 80;%s
|
|||
|
|
server_name _;
|
|||
|
|
index index.html;
|
|||
|
|
root /www/server/nginx/html;
|
|||
|
|
}''' % listen_ipv6
|
|||
|
|
if not os.path.exists(httpd + '/0.default.conf') and not os.path.exists(
|
|||
|
|
httpd + '/default.conf'): public.writeFile(httpd + '/0.default.conf', httpd_default)
|
|||
|
|
if not os.path.exists(nginx + '/0.default.conf') and not os.path.exists(
|
|||
|
|
nginx + '/default.conf'): public.writeFile(nginx + '/0.default.conf', nginx_default)
|
|||
|
|
|
|||
|
|
# 添加apache端口
|
|||
|
|
def apacheAddPort(self, port):
|
|||
|
|
port = str(port)
|
|||
|
|
filename = self.setupPath + '/apache/conf/extra/httpd-ssl.conf'
|
|||
|
|
if os.path.exists(filename):
|
|||
|
|
ssl_conf = public.readFile(filename)
|
|||
|
|
if ssl_conf:
|
|||
|
|
if ssl_conf.find('Listen 443') != -1:
|
|||
|
|
ssl_conf = ssl_conf.replace('Listen 443', '')
|
|||
|
|
public.writeFile(filename, ssl_conf)
|
|||
|
|
|
|||
|
|
filename = self.setupPath + '/apache/conf/httpd.conf'
|
|||
|
|
if not os.path.exists(filename): return
|
|||
|
|
allConf = public.readFile(filename)
|
|||
|
|
rep = r"Listen\s+([0-9]+)\n"
|
|||
|
|
tmp = re.findall(rep, allConf)
|
|||
|
|
if not tmp: return False
|
|||
|
|
for key in tmp:
|
|||
|
|
if key == port: return False
|
|||
|
|
|
|||
|
|
listen = "\nListen " + tmp[0] + "\n"
|
|||
|
|
listen_ipv6 = ''
|
|||
|
|
# if self.is_ipv6: listen_ipv6 = "\nListen [::]:" + port
|
|||
|
|
allConf = allConf.replace(listen, listen + "Listen " + port + listen_ipv6 + "\n")
|
|||
|
|
public.writeFile(filename, allConf)
|
|||
|
|
return True
|
|||
|
|
|
|||
|
|
# 添加到apache
|
|||
|
|
def apacheAdd(self):
|
|||
|
|
import time
|
|||
|
|
listen = ''
|
|||
|
|
if self.sitePort != '80': self.apacheAddPort(self.sitePort)
|
|||
|
|
acc = public.md5(str(time.time()))[0:8]
|
|||
|
|
try:
|
|||
|
|
httpdVersion = public.readFile(self.setupPath + '/apache/version.pl').strip()
|
|||
|
|
except:
|
|||
|
|
httpdVersion = ""
|
|||
|
|
if httpdVersion == '2.2':
|
|||
|
|
vName = ''
|
|||
|
|
if self.sitePort != '80' and self.sitePort != '443':
|
|||
|
|
vName = "NameVirtualHost *:" + self.sitePort + "\n"
|
|||
|
|
phpConfig = ""
|
|||
|
|
apaOpt = "Order allow,deny\n\t\tAllow from all"
|
|||
|
|
else:
|
|||
|
|
vName = ""
|
|||
|
|
phpConfig = '''
|
|||
|
|
#PHP
|
|||
|
|
<FilesMatch \\.php$>
|
|||
|
|
SetHandler "proxy:%s"
|
|||
|
|
</FilesMatch>
|
|||
|
|
''' % (public.get_php_proxy(self.phpVersion, 'apache'),)
|
|||
|
|
apaOpt = 'Require all granted'
|
|||
|
|
|
|||
|
|
conf = r'''%s<VirtualHost *:%s>
|
|||
|
|
ServerAdmin webmaster@example.com
|
|||
|
|
DocumentRoot "%s"
|
|||
|
|
ServerName %s.%s
|
|||
|
|
ServerAlias %s
|
|||
|
|
#errorDocument 404 /404.html
|
|||
|
|
ErrorLog "%s-error_log"
|
|||
|
|
CustomLog "%s-access_log" combined
|
|||
|
|
|
|||
|
|
#DENY FILES
|
|||
|
|
<Files ~ (\.user.ini|\.htaccess|\.git|\.env|\.svn|\.project|LICENSE|README.md)$>
|
|||
|
|
Order allow,deny
|
|||
|
|
Deny from all
|
|||
|
|
</Files>
|
|||
|
|
%s
|
|||
|
|
#PATH
|
|||
|
|
<Directory "%s">
|
|||
|
|
SetOutputFilter DEFLATE
|
|||
|
|
Options FollowSymLinks
|
|||
|
|
AllowOverride All
|
|||
|
|
%s
|
|||
|
|
DirectoryIndex index.php index.html index.htm default.php default.html default.htm
|
|||
|
|
</Directory>
|
|||
|
|
</VirtualHost>''' % (vName, self.sitePort, self.sitePath, acc, self.siteName, self.siteName,
|
|||
|
|
public.GetConfigValue('logs_path') + '/' + self.siteName,
|
|||
|
|
public.GetConfigValue('logs_path') + '/' + self.siteName, phpConfig, self.sitePath, apaOpt)
|
|||
|
|
|
|||
|
|
htaccess = self.sitePath + '/.htaccess'
|
|||
|
|
if not os.path.exists(htaccess): public.writeFile(htaccess, ' ')
|
|||
|
|
public.ExecShell('chmod -R 644 ' + htaccess)
|
|||
|
|
public.ExecShell('chown -R www:www ' + htaccess)
|
|||
|
|
|
|||
|
|
filename = self.setupPath + '/panel/vhost/apache/' + self.siteName + '.conf'
|
|||
|
|
public.writeFile(filename, conf)
|
|||
|
|
return True
|
|||
|
|
|
|||
|
|
# 添加到nginx
|
|||
|
|
def nginxAdd(self):
|
|||
|
|
listen_ipv6 = ''
|
|||
|
|
if self.is_ipv6: listen_ipv6 = "\n listen [::]:%s;" % self.sitePort
|
|||
|
|
|
|||
|
|
conf = r'''server
|
|||
|
|
{{
|
|||
|
|
listen {listen_port};{listen_ipv6}
|
|||
|
|
server_name {site_name};
|
|||
|
|
index index.php index.html index.htm default.php default.htm default.html;
|
|||
|
|
root {site_path};
|
|||
|
|
|
|||
|
|
#SSL-START {ssl_start_msg}
|
|||
|
|
#error_page 404/404.html;
|
|||
|
|
#SSL-END
|
|||
|
|
|
|||
|
|
#ERROR-PAGE-START {err_page_msg}
|
|||
|
|
error_page 404 /404.html;
|
|||
|
|
error_page 502 /502.html;
|
|||
|
|
#ERROR-PAGE-END
|
|||
|
|
|
|||
|
|
#PHP-INFO-START {php_info_start}
|
|||
|
|
include enable-php-{php_version}.conf;
|
|||
|
|
#PHP-INFO-END
|
|||
|
|
|
|||
|
|
#REWRITE-START {rewrite_start_msg}
|
|||
|
|
include {setup_path}/panel/vhost/rewrite/{site_name}.conf;
|
|||
|
|
#REWRITE-END
|
|||
|
|
|
|||
|
|
{description}
|
|||
|
|
location ~ ^/(\.user.ini|\.htaccess|\.git|\.env|\.svn|\.project|LICENSE|README.md)
|
|||
|
|
{{
|
|||
|
|
return 404;
|
|||
|
|
}}
|
|||
|
|
|
|||
|
|
{description1}
|
|||
|
|
location ~ \.well-known{{
|
|||
|
|
allow all;
|
|||
|
|
}}
|
|||
|
|
|
|||
|
|
#Prohibit putting sensitive files in certificate verification directory
|
|||
|
|
if ( $uri ~ "^/\.well-known/.*\.(php|jsp|py|js|css|lua|ts|go|zip|tar\.gz|rar|7z|sql|bak)$" ) {{
|
|||
|
|
return 403;
|
|||
|
|
}}
|
|||
|
|
|
|||
|
|
location ~ .*\\.(gif|jpg|jpeg|png|bmp|swf)$
|
|||
|
|
{{
|
|||
|
|
expires 30d;
|
|||
|
|
error_log /dev/null;
|
|||
|
|
access_log /dev/null;
|
|||
|
|
}}
|
|||
|
|
|
|||
|
|
location ~ .*\\.(js|css)?$
|
|||
|
|
{{
|
|||
|
|
expires 12h;
|
|||
|
|
error_log /dev/null;
|
|||
|
|
access_log /dev/null;
|
|||
|
|
}}
|
|||
|
|
access_log {log_path}/{site_name}.log;
|
|||
|
|
error_log {log_path}/{site_name}.error.log;
|
|||
|
|
}}'''.format(
|
|||
|
|
listen_port=self.sitePort,
|
|||
|
|
listen_ipv6=listen_ipv6,
|
|||
|
|
site_path=self.sitePath,
|
|||
|
|
ssl_start_msg=public.lang("SSL related configuration, do NOT delete or modify the next line of commented-out 404 rules"),
|
|||
|
|
err_page_msg=public.lang("Error page configuration, allowed to be commented, deleted or modified"),
|
|||
|
|
php_info_start=public.lang("PHP reference configuration, allowed to be commented, deleted or modified"),
|
|||
|
|
php_version=self.phpVersion,
|
|||
|
|
setup_path=self.setupPath,
|
|||
|
|
rewrite_start_msg=public.lang("URL rewrite rule reference, any modification will invalidate the rewrite rules set by the panel"),
|
|||
|
|
description=("# Forbidden files or directories"),
|
|||
|
|
description1=("# Directory verification related settings for one-click application for SSL certificate"),
|
|||
|
|
log_path=public.GetConfigValue('logs_path'),
|
|||
|
|
site_name=self.siteName
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
# 写配置文件
|
|||
|
|
filename = self.setupPath + '/panel/vhost/nginx/' + self.siteName + '.conf'
|
|||
|
|
public.writeFile(filename, conf)
|
|||
|
|
|
|||
|
|
# 生成伪静态文件
|
|||
|
|
urlrewritePath = self.setupPath + '/panel/vhost/rewrite'
|
|||
|
|
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配置文件
|
|||
|
|
def rep_site_config(self, get):
|
|||
|
|
self.siteName = get.siteName
|
|||
|
|
siteInfo = public.M('sites').where('name=?', (self.siteName,)).field('id,path,port').find()
|
|||
|
|
siteInfo['domains'] = public.M('domains').where('pid=?', (siteInfo['id'],)).field('name,port').select()
|
|||
|
|
siteInfo['binding'] = public.M('binding').where('pid=?', (siteInfo['id'],)).field('domain,path').select()
|
|||
|
|
|
|||
|
|
# openlitespeed
|
|||
|
|
def openlitespeed_add_site(self, get, init_args=None):
|
|||
|
|
# 写主配置httpd_config.conf
|
|||
|
|
# 操作默认监听配置
|
|||
|
|
if not self.sitePath:
|
|||
|
|
return public.return_msg_gettext(False, public.lang("Not specify parameter [sitePath]"))
|
|||
|
|
if init_args:
|
|||
|
|
self.siteName = init_args['sitename']
|
|||
|
|
self.phpVersion = init_args['phpv']
|
|||
|
|
self.sitePath = init_args['rundir']
|
|||
|
|
conf_dir = self.setupPath + '/panel/vhost/openlitespeed/'
|
|||
|
|
if not os.path.exists(conf_dir):
|
|||
|
|
os.makedirs(conf_dir)
|
|||
|
|
file = conf_dir + self.siteName + '.conf'
|
|||
|
|
|
|||
|
|
v_h = """
|
|||
|
|
#VHOST_TYPE YP_SITENAME START
|
|||
|
|
virtualhost YP_SITENAME {
|
|||
|
|
vhRoot YP_RUN_PATH
|
|||
|
|
configFile /www/server/panel/vhost/openlitespeed/detail/YP_SITENAME.conf
|
|||
|
|
allowSymbolLink 1
|
|||
|
|
enableScript 1
|
|||
|
|
restrained 1
|
|||
|
|
setUIDMode 0
|
|||
|
|
}
|
|||
|
|
#VHOST_TYPE YP_SITENAME END
|
|||
|
|
"""
|
|||
|
|
self.old_name = self.siteName
|
|||
|
|
if hasattr(get, "dirName"):
|
|||
|
|
self.siteName = self.siteName + "_" + get.dirName
|
|||
|
|
# sub_dir = self.sitePath + "/" + get.dirName
|
|||
|
|
v_h = v_h.replace("VHOST_TYPE", "SUBDIR")
|
|||
|
|
v_h = v_h.replace("YP_SITENAME", self.siteName)
|
|||
|
|
v_h = v_h.replace("YP_RUN_PATH", self.sitePath)
|
|||
|
|
# extp_name = self.siteName + "_" + get.dirName
|
|||
|
|
else:
|
|||
|
|
self.openlitespeed_domain(get)
|
|||
|
|
v_h = v_h.replace("VHOST_TYPE", "VHOST")
|
|||
|
|
v_h = v_h.replace("YP_SITENAME", self.siteName)
|
|||
|
|
v_h = v_h.replace("YP_RUN_PATH", self.sitePath)
|
|||
|
|
# extp_name = self.siteName
|
|||
|
|
public.writeFile(file, v_h, "a+")
|
|||
|
|
# 写vhost
|
|||
|
|
conf = '''docRoot $VH_ROOT
|
|||
|
|
vhDomain $VH_NAME
|
|||
|
|
adminEmails example@example.com
|
|||
|
|
enableGzip 1
|
|||
|
|
enableIpGeo 1
|
|||
|
|
|
|||
|
|
index {
|
|||
|
|
useServer 0
|
|||
|
|
indexFiles index.php,index.html
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
errorlog /www/wwwlogs/$VH_NAME_ols.error_log {
|
|||
|
|
useServer 0
|
|||
|
|
logLevel ERROR
|
|||
|
|
rollingSize 10M
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
accesslog /www/wwwlogs/$VH_NAME_ols.access_log {
|
|||
|
|
useServer 0
|
|||
|
|
logFormat '%{X-Forwarded-For}i %h %l %u %t "%r" %>s %b "%{Referer}i" "%{User-Agent}i"'
|
|||
|
|
logHeaders 5
|
|||
|
|
rollingSize 10M
|
|||
|
|
keepDays 10 compressArchive 1
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
scripthandler {
|
|||
|
|
add lsapi:YP_EXTP_NAME php
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
extprocessor YP_OLS_NAME {
|
|||
|
|
type lsapi
|
|||
|
|
address UDS://tmp/lshttpd/YP_EXTP_NAME.sock
|
|||
|
|
maxConns 20
|
|||
|
|
env LSAPI_CHILDREN=20
|
|||
|
|
initTimeout 600
|
|||
|
|
retryTimeout 0
|
|||
|
|
persistConn 1
|
|||
|
|
pcKeepAliveTimeout 1
|
|||
|
|
respBuffer 0
|
|||
|
|
autoStart 1
|
|||
|
|
path /usr/local/lsws/lsphpYP_PHP_V/bin/lsphp
|
|||
|
|
extUser www
|
|||
|
|
extGroup www
|
|||
|
|
memSoftLimit 2047M
|
|||
|
|
memHardLimit 2047M
|
|||
|
|
procSoftLimit 400
|
|||
|
|
procHardLimit 500
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
phpIniOverride {
|
|||
|
|
php_admin_value open_basedir "/tmp/:YP_RUN_PATH"
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
expires {
|
|||
|
|
enableExpires 1
|
|||
|
|
expiresByType image/*=A43200,text/css=A43200,application/x-javascript=A43200,application/javascript=A43200,font/*=A43200,application/x-font-ttf=A43200
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
rewrite {
|
|||
|
|
enable 1
|
|||
|
|
autoLoadHtaccess 1
|
|||
|
|
include /www/server/panel/vhost/openlitespeed/proxy/YP_OLS_NAME/urlrewrite/*.conf
|
|||
|
|
include /www/server/panel/vhost/apache/redirect/YP_OLS_NAME/*.conf
|
|||
|
|
include /www/server/panel/vhost/openlitespeed/redirect/YP_OLS_NAME/*.conf
|
|||
|
|
}
|
|||
|
|
include /www/server/panel/vhost/openlitespeed/proxy/YP_OLS_NAME/*.conf
|
|||
|
|
'''
|
|||
|
|
open_base_path = self.sitePath
|
|||
|
|
if self.sitePath[-1] != '/':
|
|||
|
|
open_base_path = self.sitePath + '/'
|
|||
|
|
conf = conf.replace('YP_RUN_PATH', open_base_path)
|
|||
|
|
conf = conf.replace('YP_EXTP_NAME', self.siteName)
|
|||
|
|
conf = conf.replace('YP_PHP_V', self.phpVersion)
|
|||
|
|
conf = conf.replace('YP_OLS_NAME', self.siteName)
|
|||
|
|
|
|||
|
|
# 写配置文件
|
|||
|
|
conf_dir = self.setupPath + '/panel/vhost/openlitespeed/detail/'
|
|||
|
|
if not os.path.exists(conf_dir):
|
|||
|
|
os.makedirs(conf_dir)
|
|||
|
|
file = conf_dir + self.siteName + '.conf'
|
|||
|
|
# if hasattr(get,"dirName"):
|
|||
|
|
# file = conf_dir + self.siteName +'_'+get.dirName+ '.conf'
|
|||
|
|
public.writeFile(file, conf)
|
|||
|
|
|
|||
|
|
# 生成伪静态文件
|
|||
|
|
# urlrewritePath = self.setupPath + '/panel/vhost/rewrite'
|
|||
|
|
# urlrewriteFile = urlrewritePath + '/' + self.siteName + '.conf'
|
|||
|
|
# if not os.path.exists(urlrewritePath): os.makedirs(urlrewritePath)
|
|||
|
|
# open(urlrewriteFile, 'w+').close()
|
|||
|
|
return True
|
|||
|
|
|
|||
|
|
# 上传CSV文件
|
|||
|
|
# def upload_csv(self, get):
|
|||
|
|
# import files
|
|||
|
|
# f = files.files()
|
|||
|
|
# get.f_path = '/tmp/multiple_website.csv'
|
|||
|
|
# result = f.upload(get)
|
|||
|
|
# return result
|
|||
|
|
|
|||
|
|
# 处理CSV内容
|
|||
|
|
def __process_cvs(self, key):
|
|||
|
|
import csv
|
|||
|
|
with open('/tmp/multiple_website.csv')as f:
|
|||
|
|
f_csv = csv.reader(f)
|
|||
|
|
# result = [i for i in f_csv]
|
|||
|
|
return [dict(zip(key, i)) for i in [i for i in f_csv if "FTP" not in i]]
|
|||
|
|
|
|||
|
|
# 批量创建网站
|
|||
|
|
def __create_website_mulitiple(self, websites_info, site_path, get):
|
|||
|
|
create_successfully = {}
|
|||
|
|
create_failed = {}
|
|||
|
|
for data in websites_info:
|
|||
|
|
if not data:
|
|||
|
|
continue
|
|||
|
|
try:
|
|||
|
|
domains = data['website'].split(',')
|
|||
|
|
website_name = domains[0].split(':')[0]
|
|||
|
|
data['port'] = '80' if len(domains[0].split(':')) < 2 else domains[0].split(':')[1]
|
|||
|
|
get.webname = json.dumps({"domain": website_name, "domainlist": domains[1:], "count": 0})
|
|||
|
|
get.path = data['path'] if 'path' in data and data['path'] != '0' and data[
|
|||
|
|
'path'] != '1' else site_path + '/' + website_name
|
|||
|
|
get.version = data['version'] if 'version' in data and data['version'] != '0' else '00'
|
|||
|
|
get.ftp = 'true' if 'ftp' in data and data['ftp'] == '1' else False
|
|||
|
|
get.sql = 'true' if 'sql' in data and data['sql'] == '1' else False
|
|||
|
|
get.port = data['port'] if 'port' in data else '80'
|
|||
|
|
get.codeing = 'utf8'
|
|||
|
|
get.type = 'PHP'
|
|||
|
|
get.type_id = '0'
|
|||
|
|
get.ps = ''
|
|||
|
|
create_other = {}
|
|||
|
|
create_other['db_status'] = False
|
|||
|
|
create_other['ftp_status'] = False
|
|||
|
|
if get.sql == 'true':
|
|||
|
|
create_other['db_pass'] = get.datapassword = public.gen_password(16)
|
|||
|
|
create_other['db_user'] = get.datauser = website_name.replace('.', '_')
|
|||
|
|
create_other['db_status'] = True
|
|||
|
|
if get.ftp == 'true':
|
|||
|
|
create_other['ftp_pass'] = get.ftp_password = public.gen_password(16)
|
|||
|
|
create_other['ftp_user'] = get.ftp_username = website_name.replace('.', '_')
|
|||
|
|
create_other['ftp_status'] = True
|
|||
|
|
result = self.AddSite(get, multiple=1)
|
|||
|
|
if 'status' in result:
|
|||
|
|
create_failed[domains[0]] = result['msg']
|
|||
|
|
continue
|
|||
|
|
create_successfully[domains[0]] = create_other
|
|||
|
|
except:
|
|||
|
|
create_failed[domains[0]] = public.lang("There was an error creating, please try again.")
|
|||
|
|
return {'status': True, 'msg': public.lang('Create the website [ {} ] successfully', ','.join(create_successfully)),
|
|||
|
|
'error': create_failed,
|
|||
|
|
'success': create_successfully}
|
|||
|
|
|
|||
|
|
# 批量创建网站
|
|||
|
|
def create_website_multiple(self, get):
|
|||
|
|
'''
|
|||
|
|
@name 批量创建网站
|
|||
|
|
@author zhwen<2020-11-26>
|
|||
|
|
@param create_type txt/csv txt格式为 “网站名|网站路径|是否创建FTP|是否创建数据库|PHP版本” 每个网站一行
|
|||
|
|
"aaa.com:88,bbb.com|/www/wwwserver/aaa.com/或1|1/0|1/0|0/73"
|
|||
|
|
csv格式为 “网站名|网站端口|网站路径|PHP版本|是否创建数据库|是否创建FTP”
|
|||
|
|
@param websites_content "[[aaa.com|80|/www/wwwserver/aaa.com/|1|1|73]...."
|
|||
|
|
'''
|
|||
|
|
key = ['website', 'path', 'ftp', 'sql', 'version']
|
|||
|
|
site_path = public.M('config').getField('sites_path')
|
|||
|
|
if get.create_type == 'txt':
|
|||
|
|
websites_info = [dict(zip(key, i)) for i in
|
|||
|
|
[i.strip().split('|') for i in json.loads(get.websites_content)]]
|
|||
|
|
else:
|
|||
|
|
websites_info = self.__process_cvs(key)
|
|||
|
|
res = self.__create_website_mulitiple(websites_info, site_path, get)
|
|||
|
|
public.serviceReload()
|
|||
|
|
return res
|
|||
|
|
|
|||
|
|
# 检测enable-php-00.conf
|
|||
|
|
def check_php_conf(self):
|
|||
|
|
try:
|
|||
|
|
file = '/www/server/nginx/conf/enable-php.conf'
|
|||
|
|
if public.get_webserver() != "nginx":
|
|||
|
|
return
|
|||
|
|
if os.path.exists(file):
|
|||
|
|
return
|
|||
|
|
php_v = os.listdir('/www/server/php')
|
|||
|
|
if not php_v:
|
|||
|
|
return
|
|||
|
|
conf = public.readFile('/www/server/nginx/conf/enable-php-{}.conf'.format(php_v[0]))
|
|||
|
|
public.writeFile(file,conf)
|
|||
|
|
except:
|
|||
|
|
pass
|
|||
|
|
|
|||
|
|
# 添加站点
|
|||
|
|
def AddSite(self, get, multiple=None):
|
|||
|
|
if not get.path:
|
|||
|
|
return public.return_msg_gettext(False, public.lang("Please fill in the website path"))
|
|||
|
|
if get.path == "/":
|
|||
|
|
return public.return_msg_gettext(False, public.lang("The website path cannot be the root directory [/]"))
|
|||
|
|
rep_email = r"[\w!#$%&'*+/=?^_`{|}~-]+(?:\.[\w!#$%&'*+/=?^_`{|}~-]+)*@(?:[\w](?:[\w-]*[\w])?\.)+[\w](?:[\w-]*[\w])?"
|
|||
|
|
if hasattr(get, 'email'):
|
|||
|
|
if not re.search(rep_email,get.email):
|
|||
|
|
return public.return_msg_gettext(False, public.lang("Please check if the [Email] format correct"))
|
|||
|
|
if hasattr(get,'password') and hasattr(get,'pw_weak'):
|
|||
|
|
l = public.check_password(get.password)
|
|||
|
|
if l == 0 and get.pw_weak == 'off':
|
|||
|
|
return public.return_msg_gettext(False, public.lang("Password very weak, if you are sure to use it, please tick [ Allow weak passwords ]"))
|
|||
|
|
#判断Mysql PHP 没有安装不能继续
|
|||
|
|
if not os.path.exists("/www/server/mysql") or not os.path.exists("/www/server/php"):
|
|||
|
|
return public.return_msg_gettext(False, public.lang("Please install Mysql and PHP first!"))
|
|||
|
|
self.check_default()
|
|||
|
|
self.check_php_conf()
|
|||
|
|
isError = public.checkWebConfig()
|
|||
|
|
if isError != True:
|
|||
|
|
return public.return_msg_gettext(False, 'ERROR: %s<br><br><a style="color:red;">' % public.lang(
|
|||
|
|
'An error was detected in the configuration file. Please solve it before proceeding') + isError.replace("\n", '<br>') + '</a>')
|
|||
|
|
|
|||
|
|
import json,files
|
|||
|
|
|
|||
|
|
get.path = self.__get_site_format_path(get.path)
|
|||
|
|
if not public.check_site_path(get.path):
|
|||
|
|
a,c = public.get_sys_path()
|
|||
|
|
return public.return_msg_gettext(False, public.lang("Please do not set the website root directory to the system main directory:<br> {}", "<br>".join(a+c)))
|
|||
|
|
try:
|
|||
|
|
siteMenu = json.loads(get.webname)
|
|||
|
|
except:
|
|||
|
|
return public.return_msg_gettext(False, public.lang("The format of the webname parameter is incorrect, it should be a parseable JSON string"))
|
|||
|
|
self.siteName = self.ToPunycode(siteMenu['domain'].strip().split(':')[0]).strip().lower()
|
|||
|
|
self.sitePath = self.ToPunycodePath(self.GetPath(get.path.replace(' ', ''))).strip()
|
|||
|
|
self.sitePort = get.port.strip().replace(' ', '')
|
|||
|
|
|
|||
|
|
if self.sitePort == "": get.port = "80"
|
|||
|
|
if not public.checkPort(self.sitePort): return public.return_msg_gettext(False, public.lang("Port range is incorrect! should be between 100-65535"))
|
|||
|
|
for domain in siteMenu['domainlist']:
|
|||
|
|
if not len(domain.split(':')) == 2:
|
|||
|
|
continue
|
|||
|
|
if not public.checkPort(domain.split(':')[1]): return public.return_msg_gettext(False, public.lang("Port range is incorrect! should be between 100-65535"))
|
|||
|
|
|
|||
|
|
if hasattr(get, 'version'):
|
|||
|
|
self.phpVersion = get.version.replace(' ', '')
|
|||
|
|
else:
|
|||
|
|
self.phpVersion = '00'
|
|||
|
|
|
|||
|
|
if not self.phpVersion: self.phpVersion = '00'
|
|||
|
|
|
|||
|
|
php_version = self.GetPHPVersion(get)
|
|||
|
|
is_phpv = False
|
|||
|
|
for php_v in php_version:
|
|||
|
|
if self.phpVersion == php_v['version']:
|
|||
|
|
is_phpv = True
|
|||
|
|
break
|
|||
|
|
if not is_phpv: return public.return_msg_gettext(False, public.lang("Requested PHP version does NOT exist!"))
|
|||
|
|
|
|||
|
|
domain = None
|
|||
|
|
# if siteMenu['count']:
|
|||
|
|
# domain = get.domain.replace(' ','')
|
|||
|
|
#表单验证
|
|||
|
|
if not self.__check_site_path(self.sitePath): return public.return_msg_gettext(False, public.lang("System critical directory cannot be used as site directory"))
|
|||
|
|
if len(self.phpVersion) < 2: return public.return_msg_gettext(False, public.lang("PHP version cannot be empty"))
|
|||
|
|
reg = r"^([\w\-\*]{1,100}\.){1,24}([\w\-]{1,24}|[\w\-]{1,24}\.[\w\-]{1,24})$"
|
|||
|
|
if not re.match(reg, self.siteName): return public.return_msg_gettext(False, public.lang("Format of primary domain is incorrect"))
|
|||
|
|
if self.siteName.find('*') != -1: return public.return_msg_gettext(False, public.lang("Primary domain cannot be wildcard DNS record"))
|
|||
|
|
if self.sitePath[-1] == '.': return public.return_msg_gettext(False, 'DIR_END_WITH', ("'.'",))
|
|||
|
|
|
|||
|
|
if not domain: domain = self.siteName
|
|||
|
|
|
|||
|
|
# 是否重复
|
|||
|
|
sql = public.M('sites')
|
|||
|
|
if sql.where("name=?", (self.siteName,)).count(): return public.return_msg_gettext(False, public.lang("The site you tried to add already exists!"))
|
|||
|
|
opid = public.M('domain').where("name=?", (self.siteName,)).getField('pid')
|
|||
|
|
|
|||
|
|
if opid:
|
|||
|
|
if public.M('sites').where('id=?', (opid,)).count():
|
|||
|
|
return public.return_msg_gettext(False, public.lang("The domain you tried to add already exists!"))
|
|||
|
|
public.M('domain').where('pid=?', (opid,)).delete()
|
|||
|
|
|
|||
|
|
if public.M('binding').where('domain=?', (self.siteName,)).count():
|
|||
|
|
return public.return_msg_gettext(False, public.lang("The domain you tried to add already exists!"))
|
|||
|
|
|
|||
|
|
# 创建根目录
|
|||
|
|
if not os.path.exists(self.sitePath):
|
|||
|
|
try:
|
|||
|
|
os.makedirs(self.sitePath)
|
|||
|
|
except Exception as ex:
|
|||
|
|
return public.return_msg_gettext(False, 'Failed to create site document root, {}', (ex,))
|
|||
|
|
public.ExecShell('chmod -R 755 ' + self.sitePath)
|
|||
|
|
public.ExecShell('chown -R www:www ' + self.sitePath)
|
|||
|
|
|
|||
|
|
# 创建basedir
|
|||
|
|
self.DelUserInI(self.sitePath)
|
|||
|
|
userIni = self.sitePath + '/.user.ini'
|
|||
|
|
if not os.path.exists(userIni):
|
|||
|
|
public.writeFile(userIni, 'open_basedir=' + self.sitePath + '/:/tmp/')
|
|||
|
|
public.ExecShell('chmod 644 ' + userIni)
|
|||
|
|
public.ExecShell('chown root:root ' + userIni)
|
|||
|
|
public.ExecShell('chattr +i ' + userIni)
|
|||
|
|
|
|||
|
|
ngx_open_basedir_path = self.setupPath + '/panel/vhost/open_basedir/nginx'
|
|||
|
|
if not os.path.exists(ngx_open_basedir_path):
|
|||
|
|
os.makedirs(ngx_open_basedir_path, 384)
|
|||
|
|
ngx_open_basedir_file = ngx_open_basedir_path + '/{}.conf'.format(self.siteName)
|
|||
|
|
ngx_open_basedir_body = '''set $bt_safe_dir "open_basedir";
|
|||
|
|
set $bt_safe_open "{}/:/tmp/";'''.format(self.sitePath)
|
|||
|
|
public.writeFile(ngx_open_basedir_file, ngx_open_basedir_body)
|
|||
|
|
|
|||
|
|
# 创建默认文档
|
|||
|
|
index = self.sitePath + '/index.html'
|
|||
|
|
if not os.path.exists(index):
|
|||
|
|
public.writeFile(index, public.readFile('data/defaultDoc.html'))
|
|||
|
|
public.ExecShell('chmod -R 644 ' + index)
|
|||
|
|
public.ExecShell('chown -R www:www ' + index)
|
|||
|
|
|
|||
|
|
# 创建自定义404页
|
|||
|
|
doc404 = self.sitePath + '/404.html'
|
|||
|
|
if not os.path.exists(doc404):
|
|||
|
|
public.writeFile(doc404, public.readFile('data/404.html'))
|
|||
|
|
public.ExecShell('chmod -R 644 ' + doc404)
|
|||
|
|
public.ExecShell('chown -R www:www ' + doc404)
|
|||
|
|
# 创建自定义502页面
|
|||
|
|
doc502 = self.sitePath + '/502.html'
|
|||
|
|
if not os.path.exists(doc502) and os.path.exists('data/502.html'):
|
|||
|
|
public.writeFile(doc502, public.readFile('data/502.html'))
|
|||
|
|
public.ExecShell('chmod -R 644 ' + doc502)
|
|||
|
|
public.ExecShell('chown -R www:www ' + doc502)
|
|||
|
|
|
|||
|
|
# 写入配置
|
|||
|
|
result = self.nginxAdd()
|
|||
|
|
result = self.apacheAdd()
|
|||
|
|
result = self.openlitespeed_add_site(get)
|
|||
|
|
|
|||
|
|
# 检查处理结果
|
|||
|
|
if not result: return public.return_msg_gettext(False, public.lang("Failed to add, write configuraton ERROR!"))
|
|||
|
|
|
|||
|
|
ps = public.xssencode2(get.ps)
|
|||
|
|
# 添加放行端口
|
|||
|
|
if self.sitePort != '80':
|
|||
|
|
import firewalls
|
|||
|
|
get.port = self.sitePort
|
|||
|
|
get.ps = self.siteName
|
|||
|
|
firewalls.firewalls().AddAcceptPort(get)
|
|||
|
|
|
|||
|
|
if not hasattr(get,'type_id'): get.type_id = 0
|
|||
|
|
if not hasattr(get,'project_type'): get.project_type = "PHP"
|
|||
|
|
public.check_domain_cloud(self.siteName)
|
|||
|
|
# 统计wordpress安装次数
|
|||
|
|
if get.project_type == 'WP':
|
|||
|
|
public.count_wp()
|
|||
|
|
#写入数据库
|
|||
|
|
get.pid = sql.table('sites').add('name,path,status,ps,type_id,addtime,project_type',(self.siteName,self.sitePath,'1',ps,get.type_id,public.getDate(),get.project_type))
|
|||
|
|
|
|||
|
|
#添加更多域名
|
|||
|
|
for domain in siteMenu['domainlist']:
|
|||
|
|
get.domain = domain
|
|||
|
|
get.webname = self.siteName
|
|||
|
|
get.id = str(get.pid)
|
|||
|
|
self.AddDomain(get, multiple)
|
|||
|
|
|
|||
|
|
sql.table('domain').add('pid,name,port,addtime', (get.pid, self.siteName, self.sitePort, public.getDate()))
|
|||
|
|
|
|||
|
|
data = {}
|
|||
|
|
data['siteStatus'] = True
|
|||
|
|
data['siteId'] = get.pid
|
|||
|
|
|
|||
|
|
# 添加FTP
|
|||
|
|
data['ftpStatus'] = False
|
|||
|
|
if 'ftp' not in get:
|
|||
|
|
get.ftp = False
|
|||
|
|
if get.ftp == 'true':
|
|||
|
|
import ftp
|
|||
|
|
get.ps = self.siteName
|
|||
|
|
result = ftp.ftp().AddUser(get)
|
|||
|
|
if result['status']:
|
|||
|
|
data['ftpStatus'] = True
|
|||
|
|
data['ftpUser'] = get.ftp_username
|
|||
|
|
data['ftpPass'] = get.ftp_password
|
|||
|
|
|
|||
|
|
# 添加数据库
|
|||
|
|
data['databaseStatus'] = False
|
|||
|
|
if 'sql' not in get:
|
|||
|
|
get.sql = False
|
|||
|
|
if get.sql == 'true' or get.sql == 'MySQL':
|
|||
|
|
import database
|
|||
|
|
if len(get.datauser) > 16: get.datauser = get.datauser[:16]
|
|||
|
|
get.name = get.datauser
|
|||
|
|
get.db_user = get.datauser
|
|||
|
|
get.password = get.datapassword
|
|||
|
|
get.address = '127.0.0.1'
|
|||
|
|
get.ps = self.siteName
|
|||
|
|
result = database.database().AddDatabase(get)
|
|||
|
|
if result['status']:
|
|||
|
|
data['databaseStatus'] = True
|
|||
|
|
data['databaseUser'] = get.datauser
|
|||
|
|
data['databasePass'] = get.datapassword
|
|||
|
|
data['d_id'] = str(public.M('databases').where('pid=?',(get.pid,)).field('id').find()['id'])
|
|||
|
|
if not multiple:
|
|||
|
|
public.serviceReload()
|
|||
|
|
data = self._set_ssl(get, data, siteMenu)
|
|||
|
|
data = self._set_redirect(get, data)
|
|||
|
|
public.write_log_gettext('Site manager', 'Successfully added site [{}]!', (self.siteName,))
|
|||
|
|
return data
|
|||
|
|
|
|||
|
|
def _set_redirect(self, get, data):
|
|||
|
|
try:
|
|||
|
|
if not hasattr(get, 'redirect') and not get.redirect:
|
|||
|
|
data['redirect'] = False
|
|||
|
|
return data
|
|||
|
|
import panelRedirect
|
|||
|
|
get.redirectdomain = json.dumps([get.redirect])
|
|||
|
|
get.sitename = get.webname
|
|||
|
|
get.redirectname = 'Default'
|
|||
|
|
get.redirecttype = '301'
|
|||
|
|
get.holdpath = '1'
|
|||
|
|
get.type = '1'
|
|||
|
|
get.domainorpath = 'domain'
|
|||
|
|
get.redirectpath = ''
|
|||
|
|
if data['ssl']:
|
|||
|
|
get.tourl = 'https://{}'.format(get.tourl)
|
|||
|
|
else:
|
|||
|
|
get.tourl = 'http://{}'.format(get.tourl)
|
|||
|
|
panelRedirect.panelRedirect().CreateRedirect(get)
|
|||
|
|
data['redirect'] = True
|
|||
|
|
except:
|
|||
|
|
data['redirect'] = str(public.get_error_info())
|
|||
|
|
data['redirect'] = True
|
|||
|
|
return data
|
|||
|
|
|
|||
|
|
def _set_ssl(self, get, data, siteMenu):
|
|||
|
|
try:
|
|||
|
|
if get.set_ssl != '1':
|
|||
|
|
data['ssl'] = False
|
|||
|
|
return data
|
|||
|
|
import acme_v2
|
|||
|
|
ssl_domain = siteMenu['domainlist']
|
|||
|
|
ssl_domain.append(self.siteName)
|
|||
|
|
get.id = str(get.pid)
|
|||
|
|
get.auth_to = str(get.pid)
|
|||
|
|
get.auth_type = 'http'
|
|||
|
|
get.auto_wildcard = ''
|
|||
|
|
get.domains = json.dumps(ssl_domain)
|
|||
|
|
result = acme_v2.acme_v2().apply_cert_api(get)
|
|||
|
|
get.type = '1'
|
|||
|
|
get.siteName = self.siteName
|
|||
|
|
get.key = result['private_key']
|
|||
|
|
get.csr = result['cert'] + result['root']
|
|||
|
|
self.SetSSL(get)
|
|||
|
|
data['ssl'] = True
|
|||
|
|
if hasattr(get, 'force_ssl') and get.force_ssl == '1':
|
|||
|
|
get.siteName = self.siteName
|
|||
|
|
self.HttpToHttps(get)
|
|||
|
|
except:
|
|||
|
|
data['ssl'] = str(public.get_error_info())
|
|||
|
|
return data
|
|||
|
|
|
|||
|
|
def __get_site_format_path(self, path):
|
|||
|
|
path = path.replace('//', '/')
|
|||
|
|
if path[-1:] == '/':
|
|||
|
|
path = path[:-1]
|
|||
|
|
return path
|
|||
|
|
|
|||
|
|
def __check_site_path(self, path):
|
|||
|
|
path = self.__get_site_format_path(path)
|
|||
|
|
other_path = public.M('config').where("id=?", ('1',)).field('sites_path,backup_path').find()
|
|||
|
|
if path == other_path['sites_path'] or path == other_path['backup_path']: return False
|
|||
|
|
return True
|
|||
|
|
|
|||
|
|
def delete_website_multiple(self, get):
|
|||
|
|
'''
|
|||
|
|
@name 批量删除网站
|
|||
|
|
@author zhwen<2020-11-17>
|
|||
|
|
@param sites_id "1,2"
|
|||
|
|
@param ftp 0/1
|
|||
|
|
@param database 0/1
|
|||
|
|
@param path 0/1
|
|||
|
|
'''
|
|||
|
|
sites_id = get.sites_id.split(',')
|
|||
|
|
del_successfully = []
|
|||
|
|
del_failed = {}
|
|||
|
|
for site_id in sites_id:
|
|||
|
|
get.id = site_id
|
|||
|
|
get.webname = public.M('sites').where("id=?", (site_id,)).getField('name')
|
|||
|
|
if not get.webname:
|
|||
|
|
continue
|
|||
|
|
try:
|
|||
|
|
self.DeleteSite(get, multiple=1)
|
|||
|
|
del_successfully.append(get.webname)
|
|||
|
|
except:
|
|||
|
|
del_failed[get.webname] = public.lang("There was an error deleting, please try again.")
|
|||
|
|
pass
|
|||
|
|
public.serviceReload()
|
|||
|
|
return {'status': True, 'msg': public.lang('Delete website [{}] successfully', ','.join(del_successfully)),
|
|||
|
|
'error': del_failed,
|
|||
|
|
'success': del_successfully}
|
|||
|
|
|
|||
|
|
# 删除站点
|
|||
|
|
def DeleteSite(self, get: public.dict_obj, multiple=None):
|
|||
|
|
# 请求参数校验
|
|||
|
|
get.validate([
|
|||
|
|
public.validate.Param('id').Require().Integer(),
|
|||
|
|
public.validate.Param('webname').Require().SafePath(),
|
|||
|
|
public.validate.Param('path').Integer(),
|
|||
|
|
], [public.validate.trim_filter()])
|
|||
|
|
|
|||
|
|
proxyconf = self.__read_config(self.__proxyfile)
|
|||
|
|
id = get.id
|
|||
|
|
if public.M('sites').where('id=?', (id,)).count() < 1: return public.return_msg_gettext(False, public.lang("Specified site does NOT exist"))
|
|||
|
|
siteName = get.webname
|
|||
|
|
get.siteName = siteName
|
|||
|
|
self.CloseTomcat(get)
|
|||
|
|
# 删除反向代理
|
|||
|
|
for i in range(len(proxyconf) - 1, -1, -1):
|
|||
|
|
if proxyconf[i]["sitename"] == siteName:
|
|||
|
|
del proxyconf[i]
|
|||
|
|
self.__write_config(self.__proxyfile, proxyconf)
|
|||
|
|
|
|||
|
|
m_path = self.setupPath + '/panel/vhost/nginx/proxy/' + siteName
|
|||
|
|
if os.path.exists(m_path): public.ExecShell("rm -rf %s" % m_path)
|
|||
|
|
|
|||
|
|
m_path = self.setupPath + '/panel/vhost/apache/proxy/' + siteName
|
|||
|
|
if os.path.exists(m_path): public.ExecShell("rm -rf %s" % m_path)
|
|||
|
|
|
|||
|
|
# 删除目录保护
|
|||
|
|
_dir_aith_file = "%s/panel/data/site_dir_auth.json" % self.setupPath
|
|||
|
|
_dir_aith_conf = public.readFile(_dir_aith_file)
|
|||
|
|
if _dir_aith_conf:
|
|||
|
|
try:
|
|||
|
|
_dir_aith_conf = json.loads(_dir_aith_conf)
|
|||
|
|
if siteName in _dir_aith_conf:
|
|||
|
|
del (_dir_aith_conf[siteName])
|
|||
|
|
except:
|
|||
|
|
pass
|
|||
|
|
self.__write_config(_dir_aith_file, _dir_aith_conf)
|
|||
|
|
|
|||
|
|
dir_aith_path = self.setupPath + '/panel/vhost/nginx/dir_auth/' + siteName
|
|||
|
|
if os.path.exists(dir_aith_path): public.ExecShell("rm -rf %s" % dir_aith_path)
|
|||
|
|
|
|||
|
|
dir_aith_path = self.setupPath + '/panel/vhost/apache/dir_auth/' + siteName
|
|||
|
|
if os.path.exists(dir_aith_path): public.ExecShell("rm -rf %s" % dir_aith_path)
|
|||
|
|
|
|||
|
|
# 删除重定向
|
|||
|
|
__redirectfile = "%s/panel/data/redirect.conf" % self.setupPath
|
|||
|
|
redirectconf = self.__read_config(__redirectfile)
|
|||
|
|
for i in range(len(redirectconf) - 1, -1, -1):
|
|||
|
|
if redirectconf[i]["sitename"] == siteName:
|
|||
|
|
del redirectconf[i]
|
|||
|
|
self.__write_config(__redirectfile, redirectconf)
|
|||
|
|
m_path = self.setupPath + '/panel/vhost/nginx/redirect/' + siteName
|
|||
|
|
if os.path.exists(m_path): public.ExecShell("rm -rf %s" % m_path)
|
|||
|
|
m_path = self.setupPath + '/panel/vhost/apache/redirect/' + siteName
|
|||
|
|
if os.path.exists(m_path): public.ExecShell("rm -rf %s" % m_path)
|
|||
|
|
|
|||
|
|
# 删除配置文件
|
|||
|
|
confPath = self.setupPath + '/panel/vhost/nginx/' + siteName + '.conf'
|
|||
|
|
if os.path.exists(confPath): os.remove(confPath)
|
|||
|
|
|
|||
|
|
confPath = self.setupPath + '/panel/vhost/apache/' + siteName + '.conf'
|
|||
|
|
if os.path.exists(confPath): os.remove(confPath)
|
|||
|
|
open_basedir_file = self.setupPath + '/panel/vhost/open_basedir/nginx/' + siteName + '.conf'
|
|||
|
|
if os.path.exists(open_basedir_file): os.remove(open_basedir_file)
|
|||
|
|
|
|||
|
|
# 删除openlitespeed配置
|
|||
|
|
vhost_file = "/www/server/panel/vhost/openlitespeed/{}.conf".format(siteName)
|
|||
|
|
if os.path.exists(vhost_file):
|
|||
|
|
public.ExecShell('rm -f {}*'.format(vhost_file))
|
|||
|
|
vhost_detail_file = "/www/server/panel/vhost/openlitespeed/detail/{}.conf".format(siteName)
|
|||
|
|
if os.path.exists(vhost_detail_file):
|
|||
|
|
public.ExecShell('rm -f {}*'.format(vhost_detail_file))
|
|||
|
|
vhost_ssl_file = "/www/server/panel/vhost/openlitespeed/detail/ssl/{}.conf".format(siteName)
|
|||
|
|
if os.path.exists(vhost_ssl_file):
|
|||
|
|
public.ExecShell('rm -f {}*'.format(vhost_ssl_file))
|
|||
|
|
vhost_sub_file = "/www/server/panel/vhost/openlitespeed/detail/{}_sub.conf".format(siteName)
|
|||
|
|
if os.path.exists(vhost_sub_file):
|
|||
|
|
public.ExecShell('rm -f {}*'.format(vhost_sub_file))
|
|||
|
|
vhost_redirect_file = "/www/server/panel/vhost/openlitespeed/redirect/{}".format(siteName)
|
|||
|
|
if os.path.exists(vhost_redirect_file):
|
|||
|
|
public.ExecShell('rm -rf {}*'.format(vhost_redirect_file))
|
|||
|
|
vhost_proxy_file = "/www/server/panel/vhost/openlitespeed/proxy/{}".format(siteName)
|
|||
|
|
if os.path.exists(vhost_proxy_file):
|
|||
|
|
public.ExecShell('rm -rf {}*'.format(vhost_proxy_file))
|
|||
|
|
|
|||
|
|
# 删除openlitespeed监听配置
|
|||
|
|
self._del_ols_listen_conf(siteName)
|
|||
|
|
|
|||
|
|
# 删除伪静态文件
|
|||
|
|
# filename = confPath+'/rewrite/'+siteName+'.conf'
|
|||
|
|
filename = '/www/server/panel/vhost/rewrite/' + siteName + '.conf'
|
|||
|
|
if os.path.exists(filename):
|
|||
|
|
os.remove(filename)
|
|||
|
|
public.ExecShell("rm -f " + confPath + '/rewrite/' + siteName + "_*")
|
|||
|
|
|
|||
|
|
# 删除日志文件
|
|||
|
|
filename = public.GetConfigValue('logs_path') + '/' + siteName + '*'
|
|||
|
|
public.ExecShell("rm -f " + filename)
|
|||
|
|
|
|||
|
|
# 删除证书
|
|||
|
|
# crtPath = '/etc/letsencrypt/live/'+siteName
|
|||
|
|
# if os.path.exists(crtPath):
|
|||
|
|
# import shutil
|
|||
|
|
# shutil.rmtree(crtPath)
|
|||
|
|
|
|||
|
|
# 删除日志
|
|||
|
|
public.ExecShell("rm -f " + public.GetConfigValue('logs_path') + '/' + siteName + "-*")
|
|||
|
|
|
|||
|
|
# 删除备份
|
|||
|
|
# public.ExecShell("rm -f "+session['config']['backup_path']+'/site/'+siteName+'_*')
|
|||
|
|
|
|||
|
|
# 删除根目录
|
|||
|
|
if 'path' in get:
|
|||
|
|
if get.path == '1':
|
|||
|
|
import files
|
|||
|
|
get.path = self.__get_site_format_path(public.M('sites').where("id=?",(id,)).getField('path'))
|
|||
|
|
if self.__check_site_path(get.path):
|
|||
|
|
if public.M('sites').where("path=?", (get.path,)).count() < 2:
|
|||
|
|
files.files().DeleteDir(get)
|
|||
|
|
get.path = '1'
|
|||
|
|
|
|||
|
|
# 重载配置
|
|||
|
|
if not multiple:
|
|||
|
|
public.serviceReload()
|
|||
|
|
|
|||
|
|
# 从数据库删除
|
|||
|
|
public.M('sites').where("id=?", (id,)).delete()
|
|||
|
|
public.M('binding').where("pid=?", (id,)).delete()
|
|||
|
|
public.M('domain').where("pid=?", (id,)).delete()
|
|||
|
|
public.M('wordpress_onekey').where("s_id=?", (id,)).delete()
|
|||
|
|
public.write_log_gettext('Site manager', 'Successfully deleted site!', (siteName,))
|
|||
|
|
|
|||
|
|
# 是否删除关联数据库
|
|||
|
|
if hasattr(get, 'database'):
|
|||
|
|
if get.database == '1':
|
|||
|
|
find = public.M('databases').where("pid=?", (id,)).field('id,name').find()
|
|||
|
|
if find:
|
|||
|
|
import database
|
|||
|
|
get.name = find['name']
|
|||
|
|
get.id = find['id']
|
|||
|
|
database.database().DeleteDatabase(get)
|
|||
|
|
|
|||
|
|
# 是否删除关联FTP
|
|||
|
|
if hasattr(get, 'ftp'):
|
|||
|
|
if get.ftp == '1':
|
|||
|
|
find = public.M('ftps').where("pid=?", (id,)).field('id,name').find()
|
|||
|
|
if find:
|
|||
|
|
import ftp
|
|||
|
|
get.username = find['name']
|
|||
|
|
get.id = find['id']
|
|||
|
|
ftp.ftp().DeleteUser(get)
|
|||
|
|
|
|||
|
|
return public.return_msg_gettext(True, public.lang("Successfully deleted site!"))
|
|||
|
|
|
|||
|
|
def _del_ols_listen_conf(self, sitename):
|
|||
|
|
conf_dir = '/www/server/panel/vhost/openlitespeed/listen/'
|
|||
|
|
if not os.path.exists(conf_dir):
|
|||
|
|
return False
|
|||
|
|
for i in os.listdir(conf_dir):
|
|||
|
|
file_name = conf_dir + i
|
|||
|
|
if os.path.isdir(file_name):
|
|||
|
|
continue
|
|||
|
|
conf = public.readFile(file_name)
|
|||
|
|
if not conf:
|
|||
|
|
continue
|
|||
|
|
map_rep = r'map\s+{}.*'.format(sitename)
|
|||
|
|
conf = re.sub(map_rep, '', conf)
|
|||
|
|
if "map" not in conf:
|
|||
|
|
public.ExecShell('rm -f {}*'.format(file_name))
|
|||
|
|
continue
|
|||
|
|
public.writeFile(file_name, conf)
|
|||
|
|
|
|||
|
|
# 域名编码转换
|
|||
|
|
def ToPunycode(self, domain):
|
|||
|
|
import re
|
|||
|
|
if sys.version_info[0] == 2: domain = domain.encode('utf8')
|
|||
|
|
tmp = domain.split('.')
|
|||
|
|
newdomain = ''
|
|||
|
|
for dkey in tmp:
|
|||
|
|
if dkey == '*': continue
|
|||
|
|
# 匹配非ascii字符
|
|||
|
|
match = re.search(u"[\x80-\xff]+", dkey)
|
|||
|
|
if not match: match = re.search(u"[\u4e00-\u9fa5]+", dkey)
|
|||
|
|
if not match:
|
|||
|
|
newdomain += dkey + '.'
|
|||
|
|
else:
|
|||
|
|
if sys.version_info[0] == 2:
|
|||
|
|
newdomain += 'xn--' + dkey.decode('utf-8').encode('punycode') + '.'
|
|||
|
|
else:
|
|||
|
|
newdomain += 'xn--' + dkey.encode('punycode').decode('utf-8') + '.'
|
|||
|
|
if tmp[0] == '*': newdomain = "*." + newdomain
|
|||
|
|
return newdomain[0:-1]
|
|||
|
|
|
|||
|
|
# 中文路径处理
|
|||
|
|
def ToPunycodePath(self, path):
|
|||
|
|
if sys.version_info[0] == 2: path = path.encode('utf-8')
|
|||
|
|
if os.path.exists(path): return path
|
|||
|
|
import re
|
|||
|
|
match = re.search(u"[\x80-\xff]+", path)
|
|||
|
|
if not match: match = re.search(u"[\u4e00-\u9fa5]+", path)
|
|||
|
|
if not match: return path
|
|||
|
|
npath = ''
|
|||
|
|
for ph in path.split('/'):
|
|||
|
|
npath += '/' + self.ToPunycode(ph)
|
|||
|
|
return npath.replace('//', '/')
|
|||
|
|
|
|||
|
|
def export_domains(self, args):
|
|||
|
|
'''
|
|||
|
|
@name 导出域名列表
|
|||
|
|
@author hwliang<2020-10-27>
|
|||
|
|
@param args<dict_obj>{
|
|||
|
|
siteName: string<网站名称>
|
|||
|
|
}
|
|||
|
|
@return string
|
|||
|
|
'''
|
|||
|
|
|
|||
|
|
pid = public.M('sites').where('name=?', args.siteName).getField('id')
|
|||
|
|
domains = public.M('domain').where('pid=?', pid).field('name,port').select()
|
|||
|
|
text_data = []
|
|||
|
|
for domain in domains:
|
|||
|
|
text_data.append("{}:{}".format(domain['name'], domain['port']))
|
|||
|
|
data = "\n".join(text_data)
|
|||
|
|
return public.send_file(data, '{}_domains'.format(args.siteName))
|
|||
|
|
|
|||
|
|
def import_domains(self, args):
|
|||
|
|
'''
|
|||
|
|
@name 导入域名
|
|||
|
|
@author hwliang<2020-10-27>
|
|||
|
|
@param args<dict_obj>{
|
|||
|
|
siteName: string<网站名称>
|
|||
|
|
domains: string<域名列表> 每行一个 格式: 域名:端口
|
|||
|
|
}
|
|||
|
|
@return string
|
|||
|
|
'''
|
|||
|
|
|
|||
|
|
domains_tmp = args.domains.split("\n")
|
|||
|
|
get = public.dict_obj()
|
|||
|
|
get.webname = args.siteName
|
|||
|
|
get.id = public.M('sites').where('name=?', args.siteName).getField('id')
|
|||
|
|
domains = []
|
|||
|
|
for domain in domains_tmp:
|
|||
|
|
if public.M('domain').where('name=?', domain.split(':')[0]).count():
|
|||
|
|
continue
|
|||
|
|
domains.append(domain)
|
|||
|
|
|
|||
|
|
get.domain = ','.join(domains)
|
|||
|
|
return self.AddDomain(get)
|
|||
|
|
|
|||
|
|
# 添加域名
|
|||
|
|
def AddDomain(self, get, multiple=None):
|
|||
|
|
# 检查配置文件
|
|||
|
|
isError = public.checkWebConfig()
|
|||
|
|
if isError != True:
|
|||
|
|
return public.return_msg_gettext(False, 'ERROR: %s<br><br><a style="color:red;">' % public.get_msg_gettext(
|
|||
|
|
'An error was detected in the configuration file. Please solve it before proceeding') + isError.replace("\n", '<br>') + '</a>')
|
|||
|
|
|
|||
|
|
if not 'domain' in get: return public.return_msg_gettext(False, public.lang("Please enter the host domain name"))
|
|||
|
|
if len(get.domain) < 3: return public.return_msg_gettext(False, public.lang("Domain cannot be empty!"))
|
|||
|
|
domains = get.domain.replace(' ', '').split(',')
|
|||
|
|
|
|||
|
|
for domain in domains:
|
|||
|
|
if domain == "": continue
|
|||
|
|
domain = domain.strip().split(':')
|
|||
|
|
get.domain = self.ToPunycode(domain[0]).lower()
|
|||
|
|
get.port = '80'
|
|||
|
|
# 判断通配符域名格式
|
|||
|
|
if get.domain.find('*') != -1 and get.domain.find('*.') == -1:
|
|||
|
|
return public.return_msg_gettext(False, public.lang("Domain name format is incorrect!"))
|
|||
|
|
|
|||
|
|
# 判断域名格式
|
|||
|
|
reg = r"^([\w\-\*]{1,100}\.){1,24}([\w\-]{1,24}|[\w\-]{1,24}\.[\w\-]{1,24})$"
|
|||
|
|
if not re.match(reg, get.domain): return public.return_msg_gettext(False, public.lang("Format of domain is invalid!"))
|
|||
|
|
|
|||
|
|
# 获取自定义端口
|
|||
|
|
if len(domain) == 2:
|
|||
|
|
get.port = domain[1]
|
|||
|
|
if get.port == "": get.port = "80"
|
|||
|
|
|
|||
|
|
# 判断端口是否合法
|
|||
|
|
if not public.checkPort(get.port): return public.return_msg_gettext(False, public.lang("Port range is incorrect! should be between 100-65535"))
|
|||
|
|
# 检查域名是否存在
|
|||
|
|
sql = public.M('domain')
|
|||
|
|
opid = sql.where("name=? AND (port=? OR pid=?)", (get.domain, get.port, get.id)).getField('pid')
|
|||
|
|
if opid:
|
|||
|
|
siteName = public.M('sites').where('id=?',(opid,)).getField('name')
|
|||
|
|
if siteName:
|
|||
|
|
return public.return_msg_gettext(False, public.lang("The specified domain name has been bound by the website [{}]", siteName))
|
|||
|
|
sql.where('pid=?', (opid,)).delete()
|
|||
|
|
opid = public.M('binding').where('domain=?', (get.domain,)).getField('pid')
|
|||
|
|
if opid:
|
|||
|
|
siteName = public.M('sites').where('id=?',(opid,)).getField('name')
|
|||
|
|
return public.returnMsg(False, public.lang("The specified domain name has been bound by a subdirectory of the website [{}]!", siteName))
|
|||
|
|
|
|||
|
|
# 写配置文件
|
|||
|
|
self.NginxDomain(get)
|
|||
|
|
try:
|
|||
|
|
self.ApacheDomain(get)
|
|||
|
|
self.openlitespeed_domain(get)
|
|||
|
|
if self._check_ols_ssl(get.webname):
|
|||
|
|
get.port = '443'
|
|||
|
|
self.openlitespeed_domain(get)
|
|||
|
|
get.port = '80'
|
|||
|
|
except:
|
|||
|
|
pass
|
|||
|
|
|
|||
|
|
# 检查实际端口
|
|||
|
|
if len(domain) == 2: get.port = domain[1]
|
|||
|
|
|
|||
|
|
# 添加放行端口
|
|||
|
|
if get.port != '80':
|
|||
|
|
import firewalls
|
|||
|
|
get.ps = get.domain
|
|||
|
|
firewalls.firewalls().AddAcceptPort(get)
|
|||
|
|
|
|||
|
|
# 重载webserver服务
|
|||
|
|
if not multiple:
|
|||
|
|
public.serviceReload()
|
|||
|
|
full_domain = get.domain
|
|||
|
|
if not get.port in ['80','443']: full_domain += ':' + get.port
|
|||
|
|
public.check_domain_cloud(full_domain)
|
|||
|
|
public.write_log_gettext('Site manager', 'Site [{}] added domain [{}] successfully!', (get.webname, get.domain))
|
|||
|
|
sql.table('domain').add('pid,name,port,addtime', (get.id, get.domain, get.port, public.getDate()))
|
|||
|
|
|
|||
|
|
return public.return_msg_gettext(True, public.lang("Successfully added site!"))
|
|||
|
|
|
|||
|
|
# 判断ols_ssl是否已经设置
|
|||
|
|
def _check_ols_ssl(self, webname):
|
|||
|
|
conf = public.readFile('/www/server/panel/vhost/openlitespeed/listen/443.conf')
|
|||
|
|
if conf and webname in conf:
|
|||
|
|
return True
|
|||
|
|
return False
|
|||
|
|
|
|||
|
|
# 添加openlitespeed 80端口监听
|
|||
|
|
def openlitespeed_set_80_domain(self, get, conf):
|
|||
|
|
rep = r'map\s+{}.*'.format(get.webname)
|
|||
|
|
domains = get.webname.strip().split(',')
|
|||
|
|
if conf:
|
|||
|
|
map_tmp = re.search(rep, conf)
|
|||
|
|
if map_tmp:
|
|||
|
|
map_tmp = map_tmp.group()
|
|||
|
|
domains = map_tmp.strip().split(',')
|
|||
|
|
if not public.inArray(domains, get.domain):
|
|||
|
|
new_map = '{},{}'.format(conf, get.domain)
|
|||
|
|
conf = re.sub(rep, new_map, conf)
|
|||
|
|
else:
|
|||
|
|
map_tmp = '\tmap\t{d} {d}\n'.format(d=domains[0])
|
|||
|
|
listen_rep = r"secure\s*0"
|
|||
|
|
conf = re.sub(listen_rep, "secure 0\n" + map_tmp, conf)
|
|||
|
|
return conf
|
|||
|
|
|
|||
|
|
else:
|
|||
|
|
rep_default = 'listener\\s+Default\\{(\n|[\\s\\w\\*\\:\\#\\.\\,])*'
|
|||
|
|
tmp = re.search(rep_default, conf)
|
|||
|
|
# domains = get.webname.strip().split(',')
|
|||
|
|
if tmp:
|
|||
|
|
tmp = tmp.group()
|
|||
|
|
new_map = '\tmap\t{d} {d}\n'.format(d=domains[0])
|
|||
|
|
tmp += new_map
|
|||
|
|
conf = re.sub(rep_default, tmp, conf)
|
|||
|
|
return conf
|
|||
|
|
|
|||
|
|
# openlitespeed写域名配置
|
|||
|
|
def openlitespeed_domain(self, get):
|
|||
|
|
listen_dir = '/www/server/panel/vhost/openlitespeed/listen/'
|
|||
|
|
if not os.path.exists(listen_dir):
|
|||
|
|
os.makedirs(listen_dir)
|
|||
|
|
listen_file = listen_dir + get.port + ".conf"
|
|||
|
|
listen_conf = public.readFile(listen_file)
|
|||
|
|
try:
|
|||
|
|
get.webname = json.loads(get.webname)
|
|||
|
|
get.domain = get.webname['domain'].replace('\r', '')
|
|||
|
|
get.webname = get.domain + "," + ",".join(get.webname["domainlist"])
|
|||
|
|
if get.webname[-1] == ',':
|
|||
|
|
get.webname = get.webname[:-1]
|
|||
|
|
except:
|
|||
|
|
pass
|
|||
|
|
if listen_conf:
|
|||
|
|
# 添加域名
|
|||
|
|
rep = r'map\s+{}.*'.format(get.webname)
|
|||
|
|
map_tmp = re.search(rep, listen_conf)
|
|||
|
|
if map_tmp:
|
|||
|
|
map_tmp = map_tmp.group()
|
|||
|
|
domains = map_tmp.strip().split(',')
|
|||
|
|
if not public.inArray(domains, get.domain):
|
|||
|
|
new_map = '{},{}'.format(map_tmp, get.domain)
|
|||
|
|
listen_conf = re.sub(rep, new_map, listen_conf)
|
|||
|
|
else:
|
|||
|
|
domains = get.webname.strip().split(',')
|
|||
|
|
map_tmp = '\tmap\t{d} {d}'.format(d=domains[0])
|
|||
|
|
listen_rep = r"secure\s*0"
|
|||
|
|
listen_conf = re.sub(listen_rep, "secure 0\n" + map_tmp, listen_conf)
|
|||
|
|
else:
|
|||
|
|
listen_conf = """
|
|||
|
|
listener Default%s{
|
|||
|
|
address *:%s
|
|||
|
|
secure 0
|
|||
|
|
map %s %s
|
|||
|
|
}
|
|||
|
|
""" % (get.port, get.port, get.webname, get.domain)
|
|||
|
|
# 保存配置文件
|
|||
|
|
public.writeFile(listen_file, listen_conf)
|
|||
|
|
return True
|
|||
|
|
|
|||
|
|
# Nginx写域名配置
|
|||
|
|
def NginxDomain(self, get):
|
|||
|
|
file = self.setupPath + '/panel/vhost/nginx/' + get.webname + '.conf'
|
|||
|
|
conf = public.readFile(file)
|
|||
|
|
if not conf: return
|
|||
|
|
|
|||
|
|
# 添加域名
|
|||
|
|
rep = r"server_name\s*(.*);"
|
|||
|
|
tmp = re.search(rep, conf).group()
|
|||
|
|
domains = tmp.replace(';', '').strip().split(' ')
|
|||
|
|
if not public.inArray(domains, get.domain):
|
|||
|
|
newServerName = tmp.replace(';', ' ' + get.domain + ';')
|
|||
|
|
conf = conf.replace(tmp, newServerName)
|
|||
|
|
|
|||
|
|
# 添加端口
|
|||
|
|
rep = r"listen\s+[\[\]\:]*([0-9]+).*;"
|
|||
|
|
tmp = re.findall(rep, conf)
|
|||
|
|
if not public.inArray(tmp, get.port):
|
|||
|
|
listen = re.search(rep, conf).group()
|
|||
|
|
listen_ipv6 = ''
|
|||
|
|
if self.is_ipv6: listen_ipv6 = "\n\t\tlisten [::]:" + get.port + ';'
|
|||
|
|
conf = conf.replace(listen, listen + "\n\t\tlisten " + get.port + ';' + listen_ipv6)
|
|||
|
|
# 保存配置文件
|
|||
|
|
public.writeFile(file, conf)
|
|||
|
|
return True
|
|||
|
|
|
|||
|
|
# Apache写域名配置
|
|||
|
|
def ApacheDomain(self, get):
|
|||
|
|
file = self.setupPath + '/panel/vhost/apache/' + get.webname + '.conf'
|
|||
|
|
conf = public.readFile(file)
|
|||
|
|
if not conf: return
|
|||
|
|
|
|||
|
|
port = get.port
|
|||
|
|
siteName = get.webname
|
|||
|
|
newDomain = get.domain
|
|||
|
|
find = public.M('sites').where("id=?", (get.id,)).field('id,name,path').find()
|
|||
|
|
sitePath = find['path']
|
|||
|
|
siteIndex = 'index.php index.html index.htm default.php default.html default.htm'
|
|||
|
|
|
|||
|
|
# 添加域名
|
|||
|
|
if conf.find('<VirtualHost *:' + port + '>') != -1:
|
|||
|
|
repV = r"<VirtualHost\s+\*\:" + port + ">(.|\n)*</VirtualHost>"
|
|||
|
|
domainV = re.search(repV, conf).group()
|
|||
|
|
rep = r"ServerAlias\s*(.*)\n"
|
|||
|
|
tmp = re.search(rep, domainV).group(0)
|
|||
|
|
domains = tmp.strip().split(' ')
|
|||
|
|
if not public.inArray(domains, newDomain):
|
|||
|
|
rs = tmp.replace("\n", "")
|
|||
|
|
newServerName = rs + ' ' + newDomain + "\n"
|
|||
|
|
myconf = domainV.replace(tmp, newServerName)
|
|||
|
|
conf = re.sub(repV, myconf, conf)
|
|||
|
|
if conf.find('<VirtualHost *:443>') != -1:
|
|||
|
|
repV = r"<VirtualHost\s+\*\:443>(.|\n)*</VirtualHost>"
|
|||
|
|
domainV = re.search(repV, conf).group()
|
|||
|
|
rep = r"ServerAlias\s*(.*)\n"
|
|||
|
|
tmp = re.search(rep, domainV).group(0)
|
|||
|
|
domains = tmp.strip().split(' ')
|
|||
|
|
if not public.inArray(domains, newDomain):
|
|||
|
|
rs = tmp.replace("\n", "")
|
|||
|
|
newServerName = rs + ' ' + newDomain + "\n"
|
|||
|
|
myconf = domainV.replace(tmp, newServerName)
|
|||
|
|
conf = re.sub(repV, myconf, conf)
|
|||
|
|
else:
|
|||
|
|
try:
|
|||
|
|
httpdVersion = public.readFile(self.setupPath + '/apache/version.pl').strip()
|
|||
|
|
except:
|
|||
|
|
httpdVersion = ""
|
|||
|
|
if httpdVersion == '2.2':
|
|||
|
|
vName = ''
|
|||
|
|
if self.sitePort != '80' and self.sitePort != '443':
|
|||
|
|
vName = "NameVirtualHost *:" + port + "\n"
|
|||
|
|
phpConfig = ""
|
|||
|
|
apaOpt = "Order allow,deny\n\t\tAllow from all"
|
|||
|
|
else:
|
|||
|
|
vName = ""
|
|||
|
|
# rep = r"php-cgi-([0-9]{2,3})\.sock"
|
|||
|
|
# version = re.search(rep,conf).groups()[0]
|
|||
|
|
version = public.get_php_version_conf(conf)
|
|||
|
|
if len(version) < 2: return public.return_msg_gettext(False, public.lang("Failed to get PHP version!"))
|
|||
|
|
phpConfig = '''
|
|||
|
|
#PHP
|
|||
|
|
<FilesMatch \\.php$>
|
|||
|
|
SetHandler "proxy:%s"
|
|||
|
|
</FilesMatch>
|
|||
|
|
''' % (public.get_php_proxy(version, 'apache'),)
|
|||
|
|
apaOpt = 'Require all granted'
|
|||
|
|
|
|||
|
|
newconf = r'''<VirtualHost *:%s>
|
|||
|
|
ServerAdmin webmaster@example.com
|
|||
|
|
DocumentRoot "%s"
|
|||
|
|
ServerName %s.%s
|
|||
|
|
ServerAlias %s
|
|||
|
|
#errorDocument 404 /404.html
|
|||
|
|
ErrorLog "%s-error_log"
|
|||
|
|
CustomLog "%s-access_log" combined
|
|||
|
|
%s
|
|||
|
|
|
|||
|
|
#DENY FILES
|
|||
|
|
<Files ~ (\.user.ini|\.htaccess|\.git|\.env|\.svn|\.project|LICENSE|README.md)$>
|
|||
|
|
Order allow,deny
|
|||
|
|
Deny from all
|
|||
|
|
</Files>
|
|||
|
|
|
|||
|
|
#PATH
|
|||
|
|
<Directory "%s">
|
|||
|
|
SetOutputFilter DEFLATE
|
|||
|
|
Options FollowSymLinks
|
|||
|
|
AllowOverride All
|
|||
|
|
%s
|
|||
|
|
DirectoryIndex %s
|
|||
|
|
</Directory>
|
|||
|
|
</VirtualHost>''' % (port, sitePath, siteName, port, newDomain, public.GetConfigValue('logs_path') + '/' + siteName,
|
|||
|
|
public.GetConfigValue('logs_path') + '/' + siteName, phpConfig, sitePath, apaOpt, siteIndex)
|
|||
|
|
conf += "\n\n" + newconf
|
|||
|
|
|
|||
|
|
# 添加端口
|
|||
|
|
if port != '80' and port != '888': self.apacheAddPort(port)
|
|||
|
|
|
|||
|
|
# 保存配置文件
|
|||
|
|
public.writeFile(file, conf)
|
|||
|
|
return True
|
|||
|
|
|
|||
|
|
def delete_domain_multiple(self, get):
|
|||
|
|
'''
|
|||
|
|
@name 批量删除网站
|
|||
|
|
@author zhwen<2020-11-17>
|
|||
|
|
@param id "1"
|
|||
|
|
@param domains_id 1,2,3
|
|||
|
|
'''
|
|||
|
|
domains_id = get.domains_id.split(',')
|
|||
|
|
get.webname = public.M('sites').where("id=?", (get.id,)).getField('name')
|
|||
|
|
del_successfully = []
|
|||
|
|
del_failed = {}
|
|||
|
|
for domain_id in domains_id:
|
|||
|
|
get.domain = public.M('domain').where("id=? and pid=?", (domain_id, get.id)).getField('name')
|
|||
|
|
get.port = str(public.M('domain').where("id=? and pid=?", (domain_id, get.id)).getField('port'))
|
|||
|
|
if not get.webname:
|
|||
|
|
continue
|
|||
|
|
try:
|
|||
|
|
result = self.DelDomain(get, multiple=1)
|
|||
|
|
tmp = get.domain + ':' + get.port
|
|||
|
|
if not result['status']:
|
|||
|
|
del_failed[tmp] = result['msg']
|
|||
|
|
continue
|
|||
|
|
del_successfully.append(tmp)
|
|||
|
|
except:
|
|||
|
|
tmp = get.domain + ':' + get.port
|
|||
|
|
del_failed[tmp] = public.lang("There was an error deleting, please try again.")
|
|||
|
|
pass
|
|||
|
|
public.serviceReload()
|
|||
|
|
return {'status': True, 'msg': public.get_msg_gettext('Delete domain [{}] successfully', (','.join(del_successfully),)),
|
|||
|
|
'error': del_failed,
|
|||
|
|
'success': del_successfully}
|
|||
|
|
|
|||
|
|
# 删除域名
|
|||
|
|
def DelDomain(self, get, multiple=None):
|
|||
|
|
if not 'id' in get: return public.return_msg_gettext(False, public.lang("Please choose a domain name"))
|
|||
|
|
if not 'port' in get: return public.return_msg_gettext(False, public.lang("Please choose a port"))
|
|||
|
|
sql = public.M('domain')
|
|||
|
|
id = get['id']
|
|||
|
|
port = get.port
|
|||
|
|
domain_data = sql.where("pid=? AND name=?", (get.id, get.domain)).field('id,name').find()
|
|||
|
|
|
|||
|
|
if isinstance(domain_data, list):
|
|||
|
|
if not domain_data:
|
|||
|
|
return public.return_message(-1, 0, public.lang("Domain record not found"))
|
|||
|
|
domain_data = domain_data[0]
|
|||
|
|
if not isinstance(domain_data, dict) or not domain_data.get('id'):
|
|||
|
|
return public.return_message(-1, 0, public.lang("Domain record not found"))
|
|||
|
|
domain_count = sql.table('domain').where("pid=?", (id,)).count()
|
|||
|
|
|
|||
|
|
if domain_count <= 1: return public.return_message(-1, 0, public.lang("Last domain cannot be deleted!"))
|
|||
|
|
|
|||
|
|
|
|||
|
|
|
|||
|
|
domain_count = sql.table('domain').where("pid=?", (id,)).count()
|
|||
|
|
if domain_count == 1: return public.return_msg_gettext(False, public.lang("Last domain cannot be deleted!"))
|
|||
|
|
|
|||
|
|
# nginx
|
|||
|
|
file = self.setupPath + '/panel/vhost/nginx/' + get['webname'] + '.conf'
|
|||
|
|
conf = public.readFile(file)
|
|||
|
|
if conf:
|
|||
|
|
# 删除域名
|
|||
|
|
rep = r"server_name\s+(.+);"
|
|||
|
|
match = re.search(rep, conf)
|
|||
|
|
if match:
|
|||
|
|
tmp = match.group()
|
|||
|
|
newServerName = tmp.replace(' ' + get['domain'] + ';', ';')
|
|||
|
|
newServerName = newServerName.replace(' ' + get['domain'] + ' ', ' ')
|
|||
|
|
conf = conf.replace(tmp, newServerName)
|
|||
|
|
else:
|
|||
|
|
public.WriteLog("Site manager", f"No server_name found in the Nginx configuration, the domain {get.domain} is only removed from the database")
|
|||
|
|
|
|||
|
|
# 删除端口
|
|||
|
|
rep = r"listen.*[\s:]+(\d+).*;"
|
|||
|
|
tmp = re.findall(rep, conf)
|
|||
|
|
port_count = sql.table('domain').where('pid=? AND port=?', (get.id, get.port)).count()
|
|||
|
|
if public.inArray(tmp, port) == True and port_count < 2:
|
|||
|
|
rep = r"\n*\s+listen.*[\s:]+" + port + r"\s*;"
|
|||
|
|
conf = re.sub(rep, '', conf)
|
|||
|
|
# 保存配置
|
|||
|
|
public.writeFile(file, conf)
|
|||
|
|
|
|||
|
|
# apache
|
|||
|
|
file = self.setupPath + '/panel/vhost/apache/' + get['webname'] + '.conf'
|
|||
|
|
conf = public.readFile(file)
|
|||
|
|
if conf:
|
|||
|
|
# 删除域名
|
|||
|
|
try:
|
|||
|
|
rep = r"\n*<VirtualHost \*\:" + port + ">(.|\n)*</VirtualHost>"
|
|||
|
|
tmp = re.search(rep, conf).group()
|
|||
|
|
|
|||
|
|
rep1 = "ServerAlias\\s+(.+)\n"
|
|||
|
|
tmp1 = re.findall(rep1, tmp)
|
|||
|
|
tmp2 = tmp1[0].split(' ')
|
|||
|
|
if len(tmp2) < 2:
|
|||
|
|
conf = re.sub(rep, '', conf)
|
|||
|
|
rep = r"NameVirtualHost.+\:" + port + "\n"
|
|||
|
|
conf = re.sub(rep, '', conf)
|
|||
|
|
else:
|
|||
|
|
newServerName = tmp.replace(' ' + get['domain'] + "\n", "\n")
|
|||
|
|
newServerName = newServerName.replace(' ' + get['domain'] + ' ', ' ')
|
|||
|
|
conf = conf.replace(tmp, newServerName)
|
|||
|
|
# 保存配置
|
|||
|
|
public.writeFile(file, conf.strip())
|
|||
|
|
except:
|
|||
|
|
pass
|
|||
|
|
|
|||
|
|
# openlitespeed
|
|||
|
|
self._del_ols_domain(get)
|
|||
|
|
|
|||
|
|
sql.table('domain').where("id=?", (domain_data['id'],)).delete()
|
|||
|
|
public.write_log_gettext('Site manager', 'Site [{}] deleted domain [{}] successfully!', (get.webname, get.domain))
|
|||
|
|
if not multiple:
|
|||
|
|
public.serviceReload()
|
|||
|
|
return public.return_msg_gettext(True, public.lang("Successfully deleted"))
|
|||
|
|
|
|||
|
|
# openlitespeed删除域名
|
|||
|
|
def _del_ols_domain(self, get):
|
|||
|
|
conf_dir = '/www/server/panel/vhost/openlitespeed/listen/'
|
|||
|
|
if not os.path.exists(conf_dir):
|
|||
|
|
return False
|
|||
|
|
for i in os.listdir(conf_dir):
|
|||
|
|
file_name = conf_dir + i
|
|||
|
|
if os.path.isdir(file_name):
|
|||
|
|
continue
|
|||
|
|
conf = public.readFile(file_name)
|
|||
|
|
map_rep = r'map\s+{}\s+(.*)'.format(get.webname)
|
|||
|
|
domains = re.search(map_rep, conf)
|
|||
|
|
if domains:
|
|||
|
|
domains = domains.group(1).split(',')
|
|||
|
|
if get.domain in domains:
|
|||
|
|
domains.remove(get.domain)
|
|||
|
|
if len(domains) == 0:
|
|||
|
|
os.remove(file_name)
|
|||
|
|
continue
|
|||
|
|
else:
|
|||
|
|
domains = ",".join(domains)
|
|||
|
|
map_c = "map\t{} ".format(get.webname) + domains
|
|||
|
|
conf = re.sub(map_rep, map_c, conf)
|
|||
|
|
public.writeFile(file_name, conf)
|
|||
|
|
|
|||
|
|
# 检查域名是否解析
|
|||
|
|
def CheckDomainPing(self, get):
|
|||
|
|
try:
|
|||
|
|
epass = public.GetRandomString(32)
|
|||
|
|
spath = get.path + '/.well-known/pki-validation'
|
|||
|
|
if not os.path.exists(spath): public.ExecShell("mkdir -p '" + spath + "'")
|
|||
|
|
public.writeFile(spath + '/fileauth.txt', epass)
|
|||
|
|
result = public.httpGet(
|
|||
|
|
'http://' + get.domain.replace('*.', '') + '/.well-known/pki-validation/fileauth.txt')
|
|||
|
|
if result == epass: return True
|
|||
|
|
return False
|
|||
|
|
except:
|
|||
|
|
return False
|
|||
|
|
def analyze_ssl(self, csr):
|
|||
|
|
issuer_dic = {}
|
|||
|
|
try:
|
|||
|
|
from cryptography import x509
|
|||
|
|
from cryptography.hazmat.backends import default_backend
|
|||
|
|
cert = x509.load_pem_x509_certificate(csr.encode("utf-8"), default_backend())
|
|||
|
|
issuer = cert.issuer
|
|||
|
|
for i in issuer:
|
|||
|
|
issuer_dic[i.oid._name] = i.value
|
|||
|
|
except:
|
|||
|
|
pass
|
|||
|
|
return issuer_dic
|
|||
|
|
|
|||
|
|
# 保存第三方证书
|
|||
|
|
def SetSSL(self, get):
|
|||
|
|
import ssl_info
|
|||
|
|
ssl_info = ssl_info.ssl_info()
|
|||
|
|
|
|||
|
|
get.key = get.key.strip()
|
|||
|
|
get.csr = get.csr.strip()
|
|||
|
|
issuer = self.analyze_ssl(get.csr)
|
|||
|
|
if issuer.get("organizationName") == "Let's Encrypt":
|
|||
|
|
get.csr += "\n"
|
|||
|
|
|
|||
|
|
siteName = get.siteName
|
|||
|
|
path = '/www/server/panel/vhost/cert/' + siteName
|
|||
|
|
csrpath = path + "/fullchain.pem"
|
|||
|
|
keypath = path + "/privkey.pem"
|
|||
|
|
|
|||
|
|
if (get.key.find('KEY') == -1): return public.return_msg_gettext(False, public.lang("Private Key ERROR, please check!"))
|
|||
|
|
if (get.csr.find('CERTIFICATE') == -1): return public.return_msg_gettext(False, public.lang("Certificate ERROR, please check!"))
|
|||
|
|
public.writeFile('/tmp/cert.pl', get.csr)
|
|||
|
|
if not public.CheckCert('/tmp/cert.pl'): return public.return_msg_gettext(False, public.lang("Error getting certificate"))
|
|||
|
|
#验证格式
|
|||
|
|
# format_status, format_message = ssl_info.verify_format('key',get.key)
|
|||
|
|
# if not format_status:
|
|||
|
|
# return public.returnMsg(False, format_message)
|
|||
|
|
# format_status, format_message = ssl_info.verify_format('cert',get.csr)
|
|||
|
|
# if not format_status:
|
|||
|
|
# return public.returnMsg(False, format_message)
|
|||
|
|
# 验证证书和密钥是否匹配格式是否为pem
|
|||
|
|
check_flag, check_msg = ssl_info.verify_certificate_and_key_match(get.key, get.csr)
|
|||
|
|
if not check_flag: return public.returnMsg(False, check_msg)
|
|||
|
|
# 验证证书链是否完整
|
|||
|
|
check_chain_flag, check_chain_msg = ssl_info.verify_certificate_chain(get.csr)
|
|||
|
|
if not check_chain_flag: return public.returnMsg(False, check_chain_msg)
|
|||
|
|
backup_cert = '/tmp/backup_cert_' + siteName
|
|||
|
|
|
|||
|
|
import shutil
|
|||
|
|
if os.path.exists(backup_cert): shutil.rmtree(backup_cert)
|
|||
|
|
if os.path.exists(path): shutil.move(path, backup_cert)
|
|||
|
|
if os.path.exists(path): shutil.rmtree(path)
|
|||
|
|
|
|||
|
|
public.ExecShell('mkdir -p ' + path)
|
|||
|
|
public.writeFile(keypath, get.key)
|
|||
|
|
public.writeFile(csrpath, get.csr)
|
|||
|
|
|
|||
|
|
# 写入配置文件
|
|||
|
|
result = self.SetSSLConf(get)
|
|||
|
|
if not result['status']: return result
|
|||
|
|
isError = public.checkWebConfig()
|
|||
|
|
|
|||
|
|
if (type(isError) == str):
|
|||
|
|
if os.path.exists(path):
|
|||
|
|
shutil.rmtree(backup_cert)
|
|||
|
|
if os.path.exists(backup_cert):
|
|||
|
|
shutil.move(backup_cert, path)
|
|||
|
|
return public.return_msg_gettext(False, public.lang('ERROR: <br><a style="color:red;">' + isError.replace("\n", '<br>') + '</a>'))
|
|||
|
|
public.serviceReload()
|
|||
|
|
|
|||
|
|
if os.path.exists(path + '/partnerOrderId'): os.remove(path + '/partnerOrderId')
|
|||
|
|
if os.path.exists(path + '/certOrderId'): os.remove(path + '/certOrderId')
|
|||
|
|
p_file = '/etc/letsencrypt/live/' + get.siteName
|
|||
|
|
if os.path.exists(p_file): shutil.rmtree(p_file)
|
|||
|
|
public.write_log_gettext('Site manager', 'Certificate saved!')
|
|||
|
|
|
|||
|
|
# 清理备份证书
|
|||
|
|
if os.path.exists(backup_cert): shutil.rmtree(backup_cert)
|
|||
|
|
return public.return_msg_gettext(True, public.lang("Certificate saved!"))
|
|||
|
|
|
|||
|
|
# 获取运行目录
|
|||
|
|
def GetRunPath(self, get):
|
|||
|
|
if not hasattr(get, 'id'):
|
|||
|
|
if hasattr(get, 'siteName'):
|
|||
|
|
get.id = public.M('sites').where('name=?', (get.siteName,)).getField('id')
|
|||
|
|
else:
|
|||
|
|
get.id = public.M('sites').where('path=?', (get.path,)).getField('id')
|
|||
|
|
if not get.id: return False
|
|||
|
|
if type(get.id) == list: get.id = get.id[0]['id']
|
|||
|
|
result = self.GetSiteRunPath(get)
|
|||
|
|
if 'runPath' in result:
|
|||
|
|
return result['runPath']
|
|||
|
|
return False
|
|||
|
|
|
|||
|
|
# 创建Let's Encrypt免费证书
|
|||
|
|
def CreateLet(self, get):
|
|||
|
|
|
|||
|
|
domains = json.loads(get.domains)
|
|||
|
|
if not len(domains):
|
|||
|
|
return public.return_msg_gettext(False, public.lang("Please choose a domain name"))
|
|||
|
|
|
|||
|
|
file_auth = True
|
|||
|
|
if hasattr(get, 'dnsapi'):
|
|||
|
|
file_auth = False
|
|||
|
|
|
|||
|
|
if not hasattr(get, 'dnssleep'):
|
|||
|
|
get.dnssleep = 10
|
|||
|
|
|
|||
|
|
email = public.M('users').getField('email')
|
|||
|
|
if hasattr(get, 'email'):
|
|||
|
|
if get.email.find('@') == -1:
|
|||
|
|
get.email = email
|
|||
|
|
else:
|
|||
|
|
get.email = get.email.strip()
|
|||
|
|
public.M('users').where('id=?', (1,)).setField('email', get.email)
|
|||
|
|
else:
|
|||
|
|
get.email = email
|
|||
|
|
|
|||
|
|
for domain in domains:
|
|||
|
|
if public.checkIp(domain): continue
|
|||
|
|
if domain.find('*.') >= 0 and file_auth:
|
|||
|
|
return public.return_msg_gettext(False, public.lang("A generic domain name cannot be used to apply for a certificate using [File Validation]!"))
|
|||
|
|
|
|||
|
|
if file_auth:
|
|||
|
|
get.sitename = get.siteName
|
|||
|
|
if self.GetRedirectList(get): return public.return_msg_gettext(False, public.lang("Your site has 301 Redirect on,Please turn it off first!"))
|
|||
|
|
if self.GetProxyList(get): return public.return_msg_gettext(False, public.lang("Sites that have reverse proxy turned on cannot request SSL!"))
|
|||
|
|
data = self.get_site_info(get.siteName)
|
|||
|
|
get.id = data['id']
|
|||
|
|
runPath = self.GetRunPath(get)
|
|||
|
|
if runPath != '/':
|
|||
|
|
if runPath[:1] != '/': runPath = '/' + runPath
|
|||
|
|
else:
|
|||
|
|
runPath = ''
|
|||
|
|
get.site_dir = data['path'] + runPath
|
|||
|
|
|
|||
|
|
else:
|
|||
|
|
dns_api_list = self.GetDnsApi(get)
|
|||
|
|
get.dns_param = None
|
|||
|
|
for dns in dns_api_list:
|
|||
|
|
if dns['name'] == get.dnsapi:
|
|||
|
|
param = []
|
|||
|
|
if not dns['data']: continue
|
|||
|
|
for val in dns['data']:
|
|||
|
|
param.append(val['value'])
|
|||
|
|
get.dns_param = '|'.join(param)
|
|||
|
|
n_list = ['dns', 'dns_bt']
|
|||
|
|
if not get.dnsapi in n_list:
|
|||
|
|
if len(get.dns_param) < 16: return public.return_msg_gettext(False, 'No valid DNSAPI key information found', (get.dnsapi,))
|
|||
|
|
if get.dnsapi == 'dns_bt':
|
|||
|
|
if not os.path.exists('plugin/dns/dns_main.py'):
|
|||
|
|
return public.return_msg_gettext(False, public.lang("Please go to the software store to install [Cloud Resolution] and complete the domain name NS binding."))
|
|||
|
|
|
|||
|
|
self.check_ssl_pack()
|
|||
|
|
try:
|
|||
|
|
import panelLets
|
|||
|
|
public.mod_reload(panelLets)
|
|||
|
|
except Exception as ex:
|
|||
|
|
if str(ex).find('No module named requests') != -1:
|
|||
|
|
public.ExecShell("pip install requests &")
|
|||
|
|
return public.return_msg_gettext(False, public.lang("Missing requests component, please try to repair the panel!"))
|
|||
|
|
return public.return_msg_gettext(False, str(ex))
|
|||
|
|
|
|||
|
|
lets = panelLets.panelLets()
|
|||
|
|
result = lets.apple_lest_cert(get)
|
|||
|
|
if result['status'] and not 'code' in result:
|
|||
|
|
get.onkey = 1
|
|||
|
|
path = '/www/server/panel/cert/' + get.siteName
|
|||
|
|
if os.path.exists(path + '/certOrderId'): os.remove(path + '/certOrderId')
|
|||
|
|
result = self.SetSSLConf(get)
|
|||
|
|
return result
|
|||
|
|
|
|||
|
|
def get_site_info(self, siteName):
|
|||
|
|
data = public.M("sites").where('name=?', siteName).field('id,path,name').find()
|
|||
|
|
return data
|
|||
|
|
|
|||
|
|
# 检测依赖库
|
|||
|
|
def check_ssl_pack(self):
|
|||
|
|
try:
|
|||
|
|
import requests
|
|||
|
|
except:
|
|||
|
|
public.ExecShell('btpip install requests')
|
|||
|
|
try:
|
|||
|
|
import OpenSSL
|
|||
|
|
except:
|
|||
|
|
public.ExecShell('btpip install pyOpenSSL')
|
|||
|
|
|
|||
|
|
# 判断DNS-API是否设置
|
|||
|
|
def Check_DnsApi(self, dnsapi):
|
|||
|
|
dnsapis = self.GetDnsApi(None)
|
|||
|
|
for dapi in dnsapis:
|
|||
|
|
if dapi['name'] == dnsapi:
|
|||
|
|
if not dapi['data']: return True
|
|||
|
|
for d in dapi['data']:
|
|||
|
|
if d['key'] == '': return False
|
|||
|
|
return True
|
|||
|
|
|
|||
|
|
# 获取DNS-API列表
|
|||
|
|
def GetDnsApi(self, get):
|
|||
|
|
api_path = './config/dns_api.json'
|
|||
|
|
api_init = './config/dns_api_init.json'
|
|||
|
|
if not os.path.exists(api_path):
|
|||
|
|
if os.path.exists(api_init):
|
|||
|
|
import shutil
|
|||
|
|
shutil.copyfile(api_init, api_path)
|
|||
|
|
apis = json.loads(public.ReadFile(api_path))
|
|||
|
|
|
|||
|
|
path = '/root/.acme.sh'
|
|||
|
|
if not os.path.exists(path + '/account.conf'): path = "/.acme.sh"
|
|||
|
|
account = public.readFile(path + '/account.conf')
|
|||
|
|
if not account: account = ''
|
|||
|
|
is_write = False
|
|||
|
|
for i in range(len(apis)):
|
|||
|
|
if not apis[i]['data']: continue
|
|||
|
|
for j in range(len(apis[i]['data'])):
|
|||
|
|
if apis[i]['data'][j]['value']: continue
|
|||
|
|
match = re.search(apis[i]['data'][j]['key'] + r"\s*=\s*'(.+)'", account)
|
|||
|
|
if match: apis[i]['data'][j]['value'] = match.groups()[0]
|
|||
|
|
if apis[i]['data'][j]['value']: is_write = True
|
|||
|
|
if is_write: public.writeFile('./config/dns_api.json', json.dumps(apis))
|
|||
|
|
|
|||
|
|
# aa dns api support info
|
|||
|
|
from sslModel.dnsapiModel import main
|
|||
|
|
supports_info = main().dns_support_info()
|
|||
|
|
result = []
|
|||
|
|
for support in supports_info:
|
|||
|
|
for api in apis:
|
|||
|
|
if api['title'] == 'CloudFlare':
|
|||
|
|
if os.path.exists('/www/server/panel/data/cf_limit_api.pl'):
|
|||
|
|
api['API_Limit'] = True
|
|||
|
|
else:
|
|||
|
|
api['API_Limit'] = False
|
|||
|
|
|
|||
|
|
if api['name'] == support['name']:
|
|||
|
|
support['data'] = api.get('data')
|
|||
|
|
result.append(support)
|
|||
|
|
break
|
|||
|
|
else:
|
|||
|
|
result.append(support)
|
|||
|
|
result.sort(key=lambda x: x['title'])
|
|||
|
|
apis.sort(key=lambda x: x['title'])
|
|||
|
|
if result != apis:
|
|||
|
|
public.writeFile('./config/dns_api.json', json.dumps(result))
|
|||
|
|
|
|||
|
|
for index, item in enumerate(apis):
|
|||
|
|
if item.get("title", "") == "Manual resolution":
|
|||
|
|
target_dict = apis.pop(index)
|
|||
|
|
apis.insert(0, target_dict)
|
|||
|
|
break
|
|||
|
|
return apis
|
|||
|
|
|
|||
|
|
# 设置DNS-API
|
|||
|
|
def SetDnsApi(self, get):
|
|||
|
|
pdata = json.loads(get.pdata)
|
|||
|
|
cf_limit_api = "/www/server/panel/data/cf_limit_api.pl"
|
|||
|
|
if 'API_Limit' in pdata and pdata['API_Limit'] == True and not os.path.exists(cf_limit_api):
|
|||
|
|
os.mknod(cf_limit_api)
|
|||
|
|
if 'API_Limit' in pdata and pdata['API_Limit']== False:
|
|||
|
|
if os.path.exists(cf_limit_api):os.remove(cf_limit_api)
|
|||
|
|
apis = json.loads(public.ReadFile('./config/dns_api.json'))
|
|||
|
|
is_write = False
|
|||
|
|
for key in pdata.keys():
|
|||
|
|
for i in range(len(apis)):
|
|||
|
|
if not apis[i]['data']: continue
|
|||
|
|
for j in range(len(apis[i]['data'])):
|
|||
|
|
if apis[i]['data'][j]['key'] != key: continue
|
|||
|
|
apis[i]['data'][j]['value'] = pdata[key]
|
|||
|
|
is_write = True
|
|||
|
|
|
|||
|
|
if is_write: public.writeFile('./config/dns_api.json', json.dumps(apis))
|
|||
|
|
return public.return_msg_gettext(True, public.lang("Setup successfully!"))
|
|||
|
|
|
|||
|
|
# 获取站点所有域名
|
|||
|
|
def GetSiteDomains(self, get):
|
|||
|
|
data = {}
|
|||
|
|
domains = public.M('domain').where('pid=?', (get.id,)).field('name,id').select()
|
|||
|
|
binding = public.M('binding').where('pid=?', (get.id,)).field('domain,id').select()
|
|||
|
|
if type(binding) == str: return binding
|
|||
|
|
for b in binding:
|
|||
|
|
tmp = {}
|
|||
|
|
tmp['name'] = b['domain']
|
|||
|
|
tmp['id'] = b['id']
|
|||
|
|
tmp['binding'] = True
|
|||
|
|
domains.append(tmp)
|
|||
|
|
data['domains'] = domains
|
|||
|
|
data['email'] = public.M('users').where('id=?', (1,)).getField('email')
|
|||
|
|
if data['email'] == '287962566@qq.com': data['email'] = ''
|
|||
|
|
return data
|
|||
|
|
|
|||
|
|
def GetFormatSSLResult(self, result):
|
|||
|
|
try:
|
|||
|
|
import re
|
|||
|
|
rep = "\\s*Domain:.+\n\\s+Type:.+\n\\s+Detail:.+"
|
|||
|
|
tmps = re.findall(rep, result)
|
|||
|
|
|
|||
|
|
statusList = []
|
|||
|
|
for tmp in tmps:
|
|||
|
|
arr = tmp.strip().split('\n')
|
|||
|
|
status = {}
|
|||
|
|
for ar in arr:
|
|||
|
|
tmp1 = ar.strip().split(':')
|
|||
|
|
status[tmp1[0].strip()] = tmp1[1].strip()
|
|||
|
|
if len(tmp1) > 2:
|
|||
|
|
status[tmp1[0].strip()] = tmp1[1].strip() + ':' + tmp1[2]
|
|||
|
|
statusList.append(status)
|
|||
|
|
return statusList
|
|||
|
|
except:
|
|||
|
|
return None
|
|||
|
|
|
|||
|
|
# 获取TLS1.3标记
|
|||
|
|
def get_tls13(self):
|
|||
|
|
nginx_bin = '/www/server/nginx/sbin/nginx'
|
|||
|
|
nginx_v = public.ExecShell(nginx_bin + ' -V 2>&1')[0]
|
|||
|
|
nginx_v_re = re.findall(r"nginx/(\d\.\d+).+OpenSSL\s+(\d\.\d+)",nginx_v,re.DOTALL)
|
|||
|
|
if nginx_v_re:
|
|||
|
|
if nginx_v_re[0][0] in ['1.8','1.9','1.7','1.6','1.5','1.4']:
|
|||
|
|
return ''
|
|||
|
|
if float(nginx_v_re[0][0]) >= 1.15 and float(nginx_v_re[0][-1]) >= 1.1:
|
|||
|
|
return ' TLSv1.3'
|
|||
|
|
else:
|
|||
|
|
_v = re.search(r'nginx/1\.1(5|6|7|8|9).\d',nginx_v)
|
|||
|
|
if not _v:
|
|||
|
|
_v = re.search(r'nginx/1\.2\d\.\d',nginx_v)
|
|||
|
|
openssl_v = public.ExecShell(nginx_bin + ' -V 2>&1|grep OpenSSL')[0].find('OpenSSL 1.1.') != -1
|
|||
|
|
if _v and openssl_v:
|
|||
|
|
return ' TLSv1.3'
|
|||
|
|
return ''
|
|||
|
|
|
|||
|
|
# 获取apache反向代理
|
|||
|
|
def get_apache_proxy(self, conf):
|
|||
|
|
rep = "\n*#Referenced reverse proxy rule, if commented, the configured reverse proxy will be invalid\n+\\s+IncludeOptiona.*"
|
|||
|
|
proxy = re.search(rep, conf)
|
|||
|
|
if proxy:
|
|||
|
|
return proxy.group()
|
|||
|
|
return ""
|
|||
|
|
|
|||
|
|
def _get_site_domains(self, sitename):
|
|||
|
|
site_id = public.M('sites').where('name=?', (sitename,)).field('id').find()
|
|||
|
|
domains = public.M('domain').where('pid=?', (site_id['id'],)).field('name').select()
|
|||
|
|
domains = [d['name'] for d in domains]
|
|||
|
|
return domains
|
|||
|
|
|
|||
|
|
# 设置OLS ssl
|
|||
|
|
def set_ols_ssl(self, get, siteName):
|
|||
|
|
listen_conf = self.setupPath + '/panel/vhost/openlitespeed/listen/443.conf'
|
|||
|
|
conf = public.readFile(listen_conf)
|
|||
|
|
ssl_conf = """
|
|||
|
|
vhssl {
|
|||
|
|
keyFile /www/server/panel/vhost/cert/YP_SSL_DOMAIN/privkey.pem
|
|||
|
|
certFile /www/server/panel/vhost/cert/YP_SSL_DOMAIN/fullchain.pem
|
|||
|
|
certChain 1
|
|||
|
|
sslProtocol 24
|
|||
|
|
ciphers EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH:ECDHE-RSA-AES128-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA128:DHE-RSA-AES128-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES128-GCM-SHA128:ECDHE-RSA-AES128-SHA384:ECDHE-RSA-AES128-SHA128:ECDHE-RSA-AES128-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES128-SHA128:DHE-RSA-AES128-SHA128:DHE-RSA-AES128-SHA:DHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA384:AES128-GCM-SHA128:AES128-SHA128:AES128-SHA128:AES128-SHA:AES128-SHA:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4
|
|||
|
|
enableECDHE 1
|
|||
|
|
renegProtection 1
|
|||
|
|
sslSessionCache 1
|
|||
|
|
enableSpdy 15
|
|||
|
|
enableStapling 1
|
|||
|
|
ocspRespMaxAge 86400
|
|||
|
|
}
|
|||
|
|
"""
|
|||
|
|
ssl_dir = self.setupPath + '/panel/vhost/openlitespeed/detail/ssl/'
|
|||
|
|
if not os.path.exists(ssl_dir):
|
|||
|
|
os.makedirs(ssl_dir)
|
|||
|
|
ssl_file = ssl_dir + '{}.conf'.format(siteName)
|
|||
|
|
if not os.path.exists(ssl_file):
|
|||
|
|
ssl_conf = ssl_conf.replace('YP_SSL_DOMAIN', siteName)
|
|||
|
|
public.writeFile(ssl_file, ssl_conf, "a+")
|
|||
|
|
include_ssl = '\ninclude {}'.format(ssl_file)
|
|||
|
|
detail_file = self.setupPath + '/panel/vhost/openlitespeed/detail/{}.conf'.format(siteName)
|
|||
|
|
public.writeFile(detail_file, include_ssl, 'a+')
|
|||
|
|
if not conf:
|
|||
|
|
conf = """
|
|||
|
|
listener SSL443 {
|
|||
|
|
map YP_OLS_NAME YP_SSL_DOMAIN
|
|||
|
|
address *:443
|
|||
|
|
secure 1
|
|||
|
|
keyFile /www/server/panel/vhost/cert/YP_OLS_NAME/privkey.pem
|
|||
|
|
certFile /www/server/panel/vhost/cert/YP_OLS_NAME/fullchain.pem
|
|||
|
|
certChain 1
|
|||
|
|
sslProtocol 24
|
|||
|
|
ciphers EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH:ECDHE-RSA-AES128-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA128:DHE-RSA-AES128-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES128-GCM-SHA128:ECDHE-RSA-AES128-SHA384:ECDHE-RSA-AES128-SHA128:ECDHE-RSA-AES128-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES128-SHA128:DHE-RSA-AES128-SHA128:DHE-RSA-AES128-SHA:DHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA384:AES128-GCM-SHA128:AES128-SHA128:AES128-SHA128:AES128-SHA:AES128-SHA:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4
|
|||
|
|
enableECDHE 1
|
|||
|
|
renegProtection 1
|
|||
|
|
sslSessionCache 1
|
|||
|
|
enableSpdy 15
|
|||
|
|
enableStapling 1
|
|||
|
|
ocspRespMaxAge 86400
|
|||
|
|
}
|
|||
|
|
"""
|
|||
|
|
|
|||
|
|
else:
|
|||
|
|
rep = r'listener\s*SSL443\s*{'
|
|||
|
|
map = '\n map {s} {s}'.format(s=siteName)
|
|||
|
|
conf = re.sub(rep, 'listener SSL443 {' + map, conf)
|
|||
|
|
domain = ",".join(self._get_site_domains(siteName))
|
|||
|
|
conf = conf.replace('YP_OLS_NAME', siteName).replace('YP_SSL_DOMAIN', domain)
|
|||
|
|
public.writeFile(listen_conf, conf)
|
|||
|
|
|
|||
|
|
def _get_ap_static_security(self, ap_conf):
|
|||
|
|
if not ap_conf: return ''
|
|||
|
|
ap_static_security = re.search('#SECURITY-START(.|\n)*#SECURITY-END', ap_conf)
|
|||
|
|
if ap_static_security:
|
|||
|
|
return ap_static_security.group()
|
|||
|
|
return ''
|
|||
|
|
|
|||
|
|
def write_json_conf(self, siteName,status):
|
|||
|
|
conf_path = "{path}/{site_name}/{site_name}.json".format(
|
|||
|
|
path=self._proxy_config_path,
|
|||
|
|
site_name=siteName
|
|||
|
|
)
|
|||
|
|
try:
|
|||
|
|
proxy_json_conf = json.loads(public.readFile(conf_path))
|
|||
|
|
proxy_json_conf['ssl_info']['ssl_status']=status
|
|||
|
|
#将proxy_json_conf 写入文件
|
|||
|
|
public.WriteFile
|
|||
|
|
except Exception as e:
|
|||
|
|
proxy_json_conf = {}
|
|||
|
|
|
|||
|
|
return public.return_message(0,0,proxy_json_conf)
|
|||
|
|
|
|||
|
|
# 添加SSL配置
|
|||
|
|
def SetSSLConf(self, get):
|
|||
|
|
"""
|
|||
|
|
@name 兼容批量设置
|
|||
|
|
@auther hezhihong
|
|||
|
|
"""
|
|||
|
|
siteName = get.siteName
|
|||
|
|
if not 'first_domain' in get: get.first_domain = siteName
|
|||
|
|
if 'isBatch' in get and siteName !=get.first_domain:get.first_domain=siteName
|
|||
|
|
|
|||
|
|
# Nginx配置
|
|||
|
|
file = self.setupPath + '/panel/vhost/nginx/' + siteName + '.conf'
|
|||
|
|
|
|||
|
|
# Node项目
|
|||
|
|
if not os.path.exists(file): file = self.setupPath + '/panel/vhost/nginx/node_' + siteName + '.conf'
|
|||
|
|
|
|||
|
|
ng_file = file
|
|||
|
|
conf = public.readFile(file)
|
|||
|
|
|
|||
|
|
# 是否为子目录设置SSL
|
|||
|
|
# if hasattr(get,'binding'):
|
|||
|
|
# allconf = conf;
|
|||
|
|
# conf = re.search("#BINDING-"+get.binding+"-START(.|\n)*#BINDING-"+get.binding+"-END",conf).group()
|
|||
|
|
|
|||
|
|
if conf:
|
|||
|
|
if conf.find('ssl_certificate') == -1:
|
|||
|
|
sslStr = """#error_page 404/404.html;
|
|||
|
|
ssl_certificate /www/server/panel/vhost/cert/%s/fullchain.pem;
|
|||
|
|
ssl_certificate_key /www/server/panel/vhost/cert/%s/privkey.pem;
|
|||
|
|
ssl_protocols TLSv1.1 TLSv1.2%s;
|
|||
|
|
ssl_ciphers EECDH+CHACHA20:EECDH+CHACHA20-draft:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES:!MD5;
|
|||
|
|
ssl_prefer_server_ciphers on;
|
|||
|
|
ssl_session_cache shared:SSL:10m;
|
|||
|
|
ssl_session_timeout 10m;
|
|||
|
|
add_header Strict-Transport-Security "max-age=31536000";
|
|||
|
|
error_page 497 https://$host$request_uri;
|
|||
|
|
""" % (get.first_domain, get.first_domain,self.get_tls13())
|
|||
|
|
if (conf.find('ssl_certificate') != -1):
|
|||
|
|
if 'isBatch' not in get:
|
|||
|
|
public.serviceReload()
|
|||
|
|
return public.return_msg_gettext(True, public.lang("SSL turned on!"))
|
|||
|
|
else:
|
|||
|
|
return True
|
|||
|
|
|
|||
|
|
conf = conf.replace('#error_page 404/404.html;', sslStr)
|
|||
|
|
conf = re.sub(r"\s+\#SSL\-END","\n\t\t#SSL-END",conf)
|
|||
|
|
|
|||
|
|
# 添加端口
|
|||
|
|
rep = r"listen.*[\s:]+(\d+).*;"
|
|||
|
|
tmp = re.findall(rep, conf)
|
|||
|
|
if not public.inArray(tmp, '443'):
|
|||
|
|
listen_re = re.search(rep,conf)
|
|||
|
|
if not listen_re:
|
|||
|
|
conf = re.sub(r"server\s*{\s*","server\n{\n\t\tlisten 80;\n\t\t",conf)
|
|||
|
|
listen_re = re.search(rep,conf)
|
|||
|
|
listen = listen_re.group()
|
|||
|
|
versionStr = public.readFile('/www/server/nginx/version.pl')
|
|||
|
|
http2 = ''
|
|||
|
|
if versionStr:
|
|||
|
|
if versionStr.find('1.8.1') == -1 and versionStr.find('1.25') == -1 and versionStr.find('1.26') == -1: http2 = ' http2'
|
|||
|
|
default_site = ''
|
|||
|
|
if conf.find('default_server') != -1: default_site = ' default_server'
|
|||
|
|
|
|||
|
|
listen_ipv6 = ';'
|
|||
|
|
if self.is_ipv6: listen_ipv6 = ";\n\t\tlisten [::]:443 ssl"+http2+default_site+";"
|
|||
|
|
conf = conf.replace(listen,listen + "\n\t\tlisten 443 ssl"+http2 + default_site + listen_ipv6)
|
|||
|
|
shutil.copyfile(file, self.nginx_conf_bak)
|
|||
|
|
|
|||
|
|
public.writeFile(file, conf)
|
|||
|
|
|
|||
|
|
# Apache配置
|
|||
|
|
file = self.setupPath + '/panel/vhost/apache/' + siteName + '.conf'
|
|||
|
|
# if not os.path.exists(file): file = self.setupPath + '/panel/vhost/apache/node_' + siteName + '.conf'
|
|||
|
|
is_node_apache = False
|
|||
|
|
if not os.path.exists(file):
|
|||
|
|
is_node_apache = True
|
|||
|
|
file = self.setupPath + '/panel/vhost/apache/node_' + siteName + '.conf'
|
|||
|
|
conf = public.readFile(file)
|
|||
|
|
ap_static_security = self._get_ap_static_security(conf)
|
|||
|
|
if conf:
|
|||
|
|
ap_proxy = self.get_apache_proxy(conf)
|
|||
|
|
if conf.find('SSLCertificateFile') == -1 and conf.find('VirtualHost') != -1:
|
|||
|
|
find = public.M('sites').where("name=?", (siteName,)).field('id,path').find()
|
|||
|
|
tmp = public.M('domain').where('pid=?', (find['id'],)).field('name').select()
|
|||
|
|
domains = ''
|
|||
|
|
for key in tmp:
|
|||
|
|
domains += key['name'] + ' '
|
|||
|
|
path = (find['path'] + '/' + self.GetRunPath(get)).replace('//', '/')
|
|||
|
|
index = 'index.php index.html index.htm default.php default.html default.htm'
|
|||
|
|
|
|||
|
|
try:
|
|||
|
|
httpdVersion = public.readFile(self.setupPath + '/apache/version.pl').strip()
|
|||
|
|
except:
|
|||
|
|
httpdVersion = ""
|
|||
|
|
if httpdVersion == '2.2':
|
|||
|
|
vName = ""
|
|||
|
|
phpConfig = ""
|
|||
|
|
apaOpt = "Order allow,deny\n\t\tAllow from all"
|
|||
|
|
else:
|
|||
|
|
vName = ""
|
|||
|
|
# rep = r"php-cgi-([0-9]{2,3})\.sock"
|
|||
|
|
# version = re.search(rep, conf).groups()[0]
|
|||
|
|
version = public.get_php_version_conf(conf)
|
|||
|
|
if len(version) < 2:
|
|||
|
|
if 'isBatch' not in get:
|
|||
|
|
return public.return_msg_gettext(False, public.lang("Failed to get PHP version!"))
|
|||
|
|
else:
|
|||
|
|
return False
|
|||
|
|
phpConfig = '''
|
|||
|
|
#PHP
|
|||
|
|
<FilesMatch \\.php$>
|
|||
|
|
SetHandler "proxy:%s"
|
|||
|
|
</FilesMatch>
|
|||
|
|
''' % (public.get_php_proxy(version, 'apache'),)
|
|||
|
|
apaOpt = 'Require all granted'
|
|||
|
|
|
|||
|
|
sslStr = r'''%s<VirtualHost *:443>
|
|||
|
|
ServerAdmin webmaster@example.com
|
|||
|
|
DocumentRoot "%s"
|
|||
|
|
ServerName SSL.%s
|
|||
|
|
ServerAlias %s
|
|||
|
|
#errorDocument 404 /404.html
|
|||
|
|
ErrorLog "%s-error_log"
|
|||
|
|
CustomLog "%s-access_log" combined
|
|||
|
|
%s
|
|||
|
|
#SSL
|
|||
|
|
SSLEngine On
|
|||
|
|
SSLCertificateFile /www/server/panel/vhost/cert/%s/fullchain.pem
|
|||
|
|
SSLCertificateKeyFile /www/server/panel/vhost/cert/%s/privkey.pem
|
|||
|
|
SSLCipherSuite EECDH+CHACHA20:EECDH+CHACHA20-draft:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES:!MD5
|
|||
|
|
SSLProtocol All -SSLv2 -SSLv3 -TLSv1
|
|||
|
|
SSLHonorCipherOrder On
|
|||
|
|
%s
|
|||
|
|
%s
|
|||
|
|
|
|||
|
|
#DENY FILES
|
|||
|
|
<Files ~ (\.user.ini|\.htaccess|\.git|\.svn|\.project|LICENSE|README.md)$>
|
|||
|
|
Order allow,deny
|
|||
|
|
Deny from all
|
|||
|
|
</Files>
|
|||
|
|
|
|||
|
|
#PATH
|
|||
|
|
<Directory "%s">
|
|||
|
|
SetOutputFilter DEFLATE
|
|||
|
|
Options FollowSymLinks
|
|||
|
|
AllowOverride All
|
|||
|
|
%s
|
|||
|
|
DirectoryIndex %s
|
|||
|
|
</Directory>
|
|||
|
|
</VirtualHost>''' % (vName, path, siteName, domains, public.GetConfigValue('logs_path') + '/' + siteName,
|
|||
|
|
public.GetConfigValue('logs_path') + '/' + siteName, ap_proxy, get.first_domain, get.first_domain,
|
|||
|
|
ap_static_security, phpConfig, path, apaOpt, index)
|
|||
|
|
conf = conf + "\n" + sslStr
|
|||
|
|
self.apacheAddPort('443')
|
|||
|
|
shutil.copyfile(file, self.apache_conf_bak)
|
|||
|
|
public.writeFile(file, conf)
|
|||
|
|
if is_node_apache: # 兼容Nodejs项目
|
|||
|
|
from projectModel.nodejsModel import main
|
|||
|
|
m = main()
|
|||
|
|
project_find = m.get_project_find(siteName)
|
|||
|
|
m.set_apache_config(project_find)
|
|||
|
|
# OLS
|
|||
|
|
self.set_ols_ssl(get, siteName)
|
|||
|
|
isError = public.checkWebConfig()
|
|||
|
|
if (isError != True):
|
|||
|
|
if os.path.exists(self.nginx_conf_bak): shutil.copyfile(self.nginx_conf_bak, ng_file)
|
|||
|
|
if os.path.exists(self.apache_conf_bak): shutil.copyfile(self.apache_conf_bak, file)
|
|||
|
|
public.ExecShell("rm -f /tmp/backup_*.conf")
|
|||
|
|
if 'isBatch' not in get:
|
|||
|
|
return public.return_msg_gettext(False,
|
|||
|
|
public.lang("Certificate ERROR, please check!") + ': <br><a style="color:red;">' + isError.replace(
|
|||
|
|
"\n", '<br>') + '</a>')
|
|||
|
|
else:
|
|||
|
|
return False
|
|||
|
|
|
|||
|
|
sql = public.M('firewall')
|
|||
|
|
import firewalls
|
|||
|
|
get.port = '443'
|
|||
|
|
get.ps = 'HTTPS'
|
|||
|
|
if not public.M('firewall').where('port=?', ('443',)).count():
|
|||
|
|
firewalls.firewalls().AddAcceptPort(get)
|
|||
|
|
public.serviceReload()
|
|||
|
|
if 'isBatch' not in get:firewalls.firewalls().AddAcceptPort(get)
|
|||
|
|
if 'isBatch' not in get:public.serviceReload()
|
|||
|
|
self.save_cert(get)
|
|||
|
|
public.write_log_gettext('Site manager', 'Site [{}] turned on SSL successfully!', (siteName,))
|
|||
|
|
result = public.return_msg_gettext(True, 'SSL turned on!')
|
|||
|
|
result['csr'] = public.readFile('/www/server/panel/vhost/cert/' + get.siteName + '/fullchain.pem')
|
|||
|
|
result['key'] = public.readFile('/www/server/panel/vhost/cert/' + get.siteName + '/privkey.pem')
|
|||
|
|
if 'isBatch' not in get:return result
|
|||
|
|
else:return True
|
|||
|
|
|
|||
|
|
def save_cert(self, get):
|
|||
|
|
# try:
|
|||
|
|
import panelSSL
|
|||
|
|
ss = panelSSL.panelSSL()
|
|||
|
|
get.keyPath = '/www/server/panel/vhost/cert/' + get.siteName + '/privkey.pem'
|
|||
|
|
get.certPath = '/www/server/panel/vhost/cert/' + get.siteName + '/fullchain.pem'
|
|||
|
|
return ss.SaveCert(get)
|
|||
|
|
return True
|
|||
|
|
# except:
|
|||
|
|
# return False;
|
|||
|
|
|
|||
|
|
# HttpToHttps
|
|||
|
|
def HttpToHttps(self, get):
|
|||
|
|
siteName = get.siteName
|
|||
|
|
#Nginx配置
|
|||
|
|
file = self.setupPath + '/panel/vhost/nginx/'+siteName+'.conf'
|
|||
|
|
if not os.path.exists(file):
|
|||
|
|
file = self.setupPath + '/panel/vhost/nginx/node_'+siteName+'.conf'
|
|||
|
|
conf = public.readFile(file)
|
|||
|
|
if conf:
|
|||
|
|
if conf.find('ssl_certificate') == -1: return public.return_msg_gettext(False, public.lang("SSL is NOT currently enabled"))
|
|||
|
|
to = """#error_page 404/404.html;
|
|||
|
|
#HTTP_TO_HTTPS_START
|
|||
|
|
if ($server_port !~ 443){
|
|||
|
|
rewrite ^(/.*)$ https://$host$1 permanent;
|
|||
|
|
}
|
|||
|
|
#HTTP_TO_HTTPS_END"""
|
|||
|
|
conf = conf.replace('#error_page 404/404.html;',to)
|
|||
|
|
public.writeFile(file,conf)
|
|||
|
|
|
|||
|
|
file = self.setupPath + '/panel/vhost/apache/'+siteName+'.conf'
|
|||
|
|
if not os.path.exists(file):
|
|||
|
|
file = self.setupPath + '/panel/vhost/apache/node_'+siteName+'.conf'
|
|||
|
|
conf = public.readFile(file)
|
|||
|
|
if conf:
|
|||
|
|
httpTohttos = '''combined
|
|||
|
|
#HTTP_TO_HTTPS_START
|
|||
|
|
<IfModule mod_rewrite.c>
|
|||
|
|
RewriteEngine on
|
|||
|
|
RewriteCond %{SERVER_PORT} !^443$
|
|||
|
|
RewriteRule (.*) https://%{SERVER_NAME}$1 [L,R=301]
|
|||
|
|
</IfModule>
|
|||
|
|
#HTTP_TO_HTTPS_END'''
|
|||
|
|
conf = re.sub('combined', httpTohttos, conf, 1)
|
|||
|
|
public.writeFile(file, conf)
|
|||
|
|
# OLS
|
|||
|
|
conf_dir = '{}/panel/vhost/openlitespeed/redirect/{}/'.format(self.setupPath, siteName)
|
|||
|
|
if not os.path.exists(conf_dir):
|
|||
|
|
os.makedirs(conf_dir)
|
|||
|
|
file = conf_dir + 'force_https.conf'
|
|||
|
|
ols_force_https = '''
|
|||
|
|
#HTTP_TO_HTTPS_START
|
|||
|
|
<IfModule mod_rewrite.c>
|
|||
|
|
RewriteEngine on
|
|||
|
|
RewriteCond %{SERVER_PORT} !^443$
|
|||
|
|
RewriteRule (.*) https://%{SERVER_NAME}$1 [L,R=301]
|
|||
|
|
</IfModule>
|
|||
|
|
#HTTP_TO_HTTPS_END'''
|
|||
|
|
public.writeFile(file, ols_force_https)
|
|||
|
|
public.serviceReload()
|
|||
|
|
return public.return_msg_gettext(True, public.lang("Setup successfully!"))
|
|||
|
|
|
|||
|
|
# CloseToHttps
|
|||
|
|
def CloseToHttps(self, get):
|
|||
|
|
siteName = get.siteName
|
|||
|
|
file = self.setupPath + '/panel/vhost/nginx/' + siteName + '.conf'
|
|||
|
|
if not os.path.exists(file):
|
|||
|
|
file = self.setupPath + '/panel/vhost/nginx/node_'+siteName+'.conf'
|
|||
|
|
conf = public.readFile(file)
|
|||
|
|
if conf:
|
|||
|
|
rep = "\n\\s*#HTTP_TO_HTTPS_START(.|\n){1,300}#HTTP_TO_HTTPS_END"
|
|||
|
|
conf = re.sub(rep, '', conf)
|
|||
|
|
rep = "\\s+if.+server_port.+\n.+\n\\s+\\s*}"
|
|||
|
|
conf = re.sub(rep, '', conf)
|
|||
|
|
public.writeFile(file, conf)
|
|||
|
|
|
|||
|
|
file = self.setupPath + '/panel/vhost/apache/' + siteName + '.conf'
|
|||
|
|
conf = public.readFile(file)
|
|||
|
|
if conf:
|
|||
|
|
rep = "\n\\s*#HTTP_TO_HTTPS_START(.|\n){1,300}#HTTP_TO_HTTPS_END"
|
|||
|
|
conf = re.sub(rep, '', conf)
|
|||
|
|
public.writeFile(file, conf)
|
|||
|
|
# OLS
|
|||
|
|
file = '{}/panel/vhost/openlitespeed/redirect/{}/force_https.conf'.format(self.setupPath, siteName)
|
|||
|
|
public.ExecShell('rm -f {}*'.format(file))
|
|||
|
|
public.serviceReload()
|
|||
|
|
|
|||
|
|
return public.return_msg_gettext(True, public.lang("Setup successfully!"))
|
|||
|
|
|
|||
|
|
# 是否跳转到https
|
|||
|
|
def IsToHttps(self, siteName):
|
|||
|
|
file = self.setupPath + '/panel/vhost/nginx/' + siteName + '.conf'
|
|||
|
|
if not os.path.exists(file):
|
|||
|
|
file = self.setupPath + '/panel/vhost/nginx/node_'+siteName+'.conf'
|
|||
|
|
if not os.path.exists(file): return False
|
|||
|
|
conf = public.readFile(file)
|
|||
|
|
if conf:
|
|||
|
|
if conf.find('HTTP_TO_HTTPS_START') != -1: return True
|
|||
|
|
if conf.find('$server_port !~ 443') != -1: return True
|
|||
|
|
return False
|
|||
|
|
|
|||
|
|
# 清理SSL配置
|
|||
|
|
def CloseSSLConf(self, get):
|
|||
|
|
siteName = get.siteName
|
|||
|
|
|
|||
|
|
file = self.setupPath + '/panel/vhost/nginx/' + siteName + '.conf'
|
|||
|
|
if not os.path.exists(file):
|
|||
|
|
file = self.setupPath + '/panel/vhost/nginx/node_' + siteName + '.conf'
|
|||
|
|
conf = public.readFile(file)
|
|||
|
|
if conf:
|
|||
|
|
rep = "\n\\s*#HTTP_TO_HTTPS_START(.|\n){1,300}#HTTP_TO_HTTPS_END"
|
|||
|
|
conf = re.sub(rep, '', conf)
|
|||
|
|
rep = r"\s+ssl_certificate\s+.+;\s+ssl_certificate_key\s+.+;"
|
|||
|
|
conf = re.sub(rep, '', conf)
|
|||
|
|
rep = "\\s+ssl_protocols\\s+.+;\n"
|
|||
|
|
conf = re.sub(rep, '', conf)
|
|||
|
|
rep = "\\s+ssl_ciphers\\s+.+;\n"
|
|||
|
|
conf = re.sub(rep, '', conf)
|
|||
|
|
rep = "\\s+ssl_prefer_server_ciphers\\s+.+;\n"
|
|||
|
|
conf = re.sub(rep, '', conf)
|
|||
|
|
rep = "\\s+ssl_session_cache\\s+.+;\n"
|
|||
|
|
conf = re.sub(rep, '', conf)
|
|||
|
|
rep = "\\s+ssl_session_timeout\\s+.+;\n"
|
|||
|
|
conf = re.sub(rep, '', conf)
|
|||
|
|
rep = "\\s+ssl_ecdh_curve\\s+.+;\n"
|
|||
|
|
conf = re.sub(rep, '', conf)
|
|||
|
|
rep = "\\s+ssl_session_tickets\\s+.+;\n"
|
|||
|
|
conf = re.sub(rep, '', conf)
|
|||
|
|
rep = "\\s+ssl_stapling\\s+.+;\n"
|
|||
|
|
conf = re.sub(rep, '', conf)
|
|||
|
|
rep = "\\s+ssl_stapling_verify\\s+.+;\n"
|
|||
|
|
conf = re.sub(rep, '', conf)
|
|||
|
|
rep = "\\s+add_header\\s+.+;\n"
|
|||
|
|
conf = re.sub(rep, '', conf)
|
|||
|
|
rep = "\\s+add_header\\s+.+;\n"
|
|||
|
|
conf = re.sub(rep, '', conf)
|
|||
|
|
rep = r"\s+ssl\s+on;"
|
|||
|
|
conf = re.sub(rep, '', conf)
|
|||
|
|
rep = r"\s+error_page\s497.+;"
|
|||
|
|
conf = re.sub(rep, '', conf)
|
|||
|
|
rep = "\\s+if.+server_port.+\n.+\n\\s+\\s*}"
|
|||
|
|
conf = re.sub(rep, '', conf)
|
|||
|
|
rep = r"\s+listen\s+443.*;"
|
|||
|
|
conf = re.sub(rep, '', conf)
|
|||
|
|
rep = r"\s+listen\s+\[::\]:443.*;"
|
|||
|
|
conf = re.sub(rep, '', conf)
|
|||
|
|
public.writeFile(file, conf)
|
|||
|
|
|
|||
|
|
file = self.setupPath + '/panel/vhost/apache/' + siteName + '.conf'
|
|||
|
|
if not os.path.exists(file):
|
|||
|
|
file = self.setupPath + '/panel/vhost/apache/node_' + siteName + '.conf'
|
|||
|
|
conf = public.readFile(file)
|
|||
|
|
if conf:
|
|||
|
|
rep = "\n<VirtualHost \\*\\:443>(.|\n)*<\\/VirtualHost>"
|
|||
|
|
conf = re.sub(rep, '', conf)
|
|||
|
|
rep = "\n\\s*#HTTP_TO_HTTPS_START(.|\n){1,250}#HTTP_TO_HTTPS_END"
|
|||
|
|
conf = re.sub(rep, '', conf)
|
|||
|
|
rep = "NameVirtualHost *:443\n"
|
|||
|
|
conf = conf.replace(rep, '')
|
|||
|
|
public.writeFile(file, conf)
|
|||
|
|
|
|||
|
|
# OLS
|
|||
|
|
ssl_file = self.setupPath + '/panel/vhost/openlitespeed/detail/ssl/{}.conf'.format(siteName)
|
|||
|
|
detail_file = self.setupPath + '/panel/vhost/openlitespeed/detail/' + siteName + '.conf'
|
|||
|
|
force_https = self.setupPath + '/panel/vhost/openlitespeed/redirect/' + siteName
|
|||
|
|
string = 'rm -f {}/force_https.conf*'.format(force_https)
|
|||
|
|
public.ExecShell(string)
|
|||
|
|
detail_conf = public.readFile(detail_file)
|
|||
|
|
if detail_conf:
|
|||
|
|
detail_conf = detail_conf.replace('\ninclude ' + ssl_file, '')
|
|||
|
|
public.writeFile(detail_file, detail_conf)
|
|||
|
|
public.ExecShell('rm -f {}*'.format(ssl_file))
|
|||
|
|
|
|||
|
|
self._del_ols_443_domain(siteName)
|
|||
|
|
partnerOrderId = '/www/server/panel/vhost/cert/' + siteName + '/partnerOrderId'
|
|||
|
|
if os.path.exists(partnerOrderId): public.ExecShell('rm -f ' + partnerOrderId)
|
|||
|
|
p_file = '/etc/letsencrypt/live/' + siteName + '/partnerOrderId'
|
|||
|
|
if os.path.exists(p_file): public.ExecShell('rm -f ' + p_file)
|
|||
|
|
|
|||
|
|
public.write_log_gettext('Site manager', 'Site [{}] turned off SSL successfully!', (siteName,))
|
|||
|
|
public.serviceReload()
|
|||
|
|
return public.return_msg_gettext(True, public.lang("SSL turned off!"))
|
|||
|
|
|
|||
|
|
def _del_ols_443_domain(self, sitename):
|
|||
|
|
file = "/www/server/panel/vhost/openlitespeed/listen/443.conf"
|
|||
|
|
conf = public.readFile(file)
|
|||
|
|
if conf:
|
|||
|
|
rep = '\n\\s*map\\s*{}.*'.format(sitename)
|
|||
|
|
conf = re.sub(rep, '', conf)
|
|||
|
|
if not "map " in conf:
|
|||
|
|
public.ExecShell('rm -f {}*'.format(file))
|
|||
|
|
return
|
|||
|
|
public.writeFile(file, conf)
|
|||
|
|
|
|||
|
|
# 取SSL状态
|
|||
|
|
def GetSSL(self, get):
|
|||
|
|
siteName = get.siteName
|
|||
|
|
path = os.path.join('/www/server/panel/vhost/cert/', siteName)
|
|||
|
|
if not os.path.isfile(os.path.join(path, "fullchain.pem")) and not os.path.isfile(
|
|||
|
|
os.path.join(path, "privkey.pem")):
|
|||
|
|
path = os.path.join('/etc/letsencrypt/live/', siteName)
|
|||
|
|
type = 0
|
|||
|
|
if os.path.exists(path + '/README'): type = 1
|
|||
|
|
if os.path.exists(path + '/partnerOrderId'): type = 2
|
|||
|
|
if os.path.exists(path + '/certOrderId'): type = 3
|
|||
|
|
csrpath = path + "/fullchain.pem" # 生成证书路径
|
|||
|
|
keypath = path + "/privkey.pem" # 密钥文件路径
|
|||
|
|
key = public.readFile(keypath)
|
|||
|
|
csr = public.readFile(csrpath)
|
|||
|
|
file = self.setupPath + '/panel/vhost/' + public.get_webserver() + '/' + siteName + '.conf'
|
|||
|
|
|
|||
|
|
# 是否为node项目
|
|||
|
|
if not os.path.exists(file): file = self.setupPath + '/panel/vhost/' + public.get_webserver() + '/node_' + siteName + '.conf'
|
|||
|
|
|
|||
|
|
if not os.path.exists(file): file = self.setupPath + '/panel/vhost/' + public.get_webserver() + '/java_' + siteName + '.conf'
|
|||
|
|
|
|||
|
|
if not os.path.exists(file): file = self.setupPath + '/panel/vhost/' + public.get_webserver() + '/go_' + siteName + '.conf'
|
|||
|
|
|
|||
|
|
if not os.path.exists(file): file = self.setupPath + '/panel/vhost/' + public.get_webserver() + '/other_' + siteName + '.conf'
|
|||
|
|
|
|||
|
|
if not os.path.exists(file): file = self.setupPath + '/panel/vhost/' + public.get_webserver() + '/python_' + siteName + '.conf'
|
|||
|
|
|
|||
|
|
if not os.path.exists(file): file = self.setupPath + '/panel/vhost/' + public.get_webserver() + '/net_' + siteName + '.conf'
|
|||
|
|
if not os.path.exists(
|
|||
|
|
file): file = self.setupPath + '/panel/vhost/' + public.get_webserver() + '/html_' + siteName + '.conf'
|
|||
|
|
|
|||
|
|
if public.get_webserver() == "openlitespeed":
|
|||
|
|
file = self.setupPath + '/panel/vhost/' + public.get_webserver() + '/detail/' + siteName + '.conf'
|
|||
|
|
conf = public.readFile(file)
|
|||
|
|
if not conf: return public.return_msg_gettext(False, public.lang("The specified website profile does not exist"))
|
|||
|
|
|
|||
|
|
if public.get_webserver() == 'nginx':
|
|||
|
|
keyText = 'ssl_certificate'
|
|||
|
|
elif public.get_webserver() == 'apache':
|
|||
|
|
keyText = 'SSLCertificateFile'
|
|||
|
|
else:
|
|||
|
|
keyText = 'openlitespeed/detail/ssl'
|
|||
|
|
|
|||
|
|
status = True
|
|||
|
|
if (conf.find(keyText) == -1):
|
|||
|
|
status = False
|
|||
|
|
type = -1
|
|||
|
|
|
|||
|
|
toHttps = self.IsToHttps(siteName)
|
|||
|
|
id = public.M('sites').where("name=?", (siteName,)).getField('id')
|
|||
|
|
domains = public.M('domain').where("pid=?", (id,)).field('name').select()
|
|||
|
|
cert_data = {}
|
|||
|
|
if csr:
|
|||
|
|
get.certPath = csrpath
|
|||
|
|
import panelSSL
|
|||
|
|
cert_data = panelSSL.panelSSL().GetCertName(get)
|
|||
|
|
if not cert_data:
|
|||
|
|
cert_data = {
|
|||
|
|
'certificate':0
|
|||
|
|
}
|
|||
|
|
if os.path.isfile(csrpath) and os.path.isfile(keypath):
|
|||
|
|
if key and csr:
|
|||
|
|
cert_hash = SSLManger().ssl_hash(certificate=csr, ignore_errors=True)
|
|||
|
|
if cert_hash is None:
|
|||
|
|
cert_data["id"], cert_data["ps"] = 0, ''
|
|||
|
|
else:
|
|||
|
|
cert_data["id"], cert_data["ps"] = SSLManger().get_cert_info_by_hash(cert_hash)
|
|||
|
|
# 调用save_by_file方法保存证书信息
|
|||
|
|
if cert_data["id"] == -1:
|
|||
|
|
try:
|
|||
|
|
save_result = SSLManger().save_by_file(csrpath, keypath)
|
|||
|
|
cert_data["id"], cert_data["ps"] = SSLManger().get_cert_info_by_hash(cert_hash)
|
|||
|
|
except:
|
|||
|
|
cert_data["id"], cert_data["ps"] = 0, ''
|
|||
|
|
email = public.M('users').where('id=?', (1,)).getField('email')
|
|||
|
|
if email == '287962566@qq.com': email = ''
|
|||
|
|
index = ''
|
|||
|
|
auth_type = 'http'
|
|||
|
|
if status == True:
|
|||
|
|
if type != 1:
|
|||
|
|
import acme_v2
|
|||
|
|
acme = acme_v2.acme_v2()
|
|||
|
|
index = acme.check_order_exists(csrpath)
|
|||
|
|
if index:
|
|||
|
|
if index.find('/') == -1:
|
|||
|
|
auth_type = acme._config['orders'][index]['auth_type']
|
|||
|
|
type = 1
|
|||
|
|
else:
|
|||
|
|
crontab_file = 'vhost/cert/crontab.json'
|
|||
|
|
tmp = public.readFile(crontab_file)
|
|||
|
|
if tmp:
|
|||
|
|
crontab_config = json.loads(tmp)
|
|||
|
|
if siteName in crontab_config:
|
|||
|
|
if 'dnsapi' in crontab_config[siteName]:
|
|||
|
|
auth_type = 'dns'
|
|||
|
|
|
|||
|
|
if os.path.exists(path + '/certOrderId'): type = 3
|
|||
|
|
oid = -1
|
|||
|
|
if type == 3:
|
|||
|
|
oid = int(public.readFile(path + '/certOrderId'))
|
|||
|
|
|
|||
|
|
return {
|
|||
|
|
'status': status, 'oid': oid, 'domain': domains, 'key': key, 'csr': csr, 'type': type,
|
|||
|
|
'httpTohttps': toHttps, 'cert_data': cert_data, 'email': email, "index": index,
|
|||
|
|
'auth_type': auth_type, 'tls_versions': self.get_ssl_protocol(get),
|
|||
|
|
'push': self.get_ssl_push_status(None, siteName, 'ssl', status)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
def get_ssl_push_status(self, get, siteName=None, stype=None, ssl_status=None):
|
|||
|
|
if get:
|
|||
|
|
siteName = get.siteName
|
|||
|
|
result = {'status': False}
|
|||
|
|
selected_data = {
|
|||
|
|
'task_data': {},
|
|||
|
|
'title': "",
|
|||
|
|
'sender': "",
|
|||
|
|
'status': bool(0),
|
|||
|
|
'id': ""
|
|||
|
|
}
|
|||
|
|
task = {}
|
|||
|
|
try:
|
|||
|
|
try:
|
|||
|
|
data = json.loads(public.readFile('{}/data/mod_push_data/task.json'.format(public.get_panel_path())))
|
|||
|
|
except:
|
|||
|
|
return result
|
|||
|
|
for i in data:
|
|||
|
|
if i['source'] == 'site_ssl':
|
|||
|
|
task_data = i.get('task_data', {})
|
|||
|
|
project = task_data.get('project')
|
|||
|
|
if project == siteName:
|
|||
|
|
task = i
|
|||
|
|
break
|
|||
|
|
if project == "all":
|
|||
|
|
task = i
|
|||
|
|
except Exception as e:
|
|||
|
|
return result
|
|||
|
|
|
|||
|
|
if task.get('id'):
|
|||
|
|
selected_data = {
|
|||
|
|
'task_data': task.get('task_data', {}),
|
|||
|
|
'title': task.get('title', ''),
|
|||
|
|
'sender': task.get('sender', []),
|
|||
|
|
'status': task.get('status'),
|
|||
|
|
'id': task.get('id', "")
|
|||
|
|
}
|
|||
|
|
return selected_data
|
|||
|
|
|
|||
|
|
def get_site_push_status(self, get, siteName=None, stype=None):
|
|||
|
|
"""
|
|||
|
|
@获取网站ssl告警通知状态
|
|||
|
|
@param get:
|
|||
|
|
@param siteName 网站名称
|
|||
|
|
@param stype 类型 ssl
|
|||
|
|
"""
|
|||
|
|
import panelPush
|
|||
|
|
if get:
|
|||
|
|
siteName = get.siteName
|
|||
|
|
stype = get.stype
|
|||
|
|
|
|||
|
|
result = {}
|
|||
|
|
result['status'] = False
|
|||
|
|
try:
|
|||
|
|
data = {}
|
|||
|
|
try:
|
|||
|
|
data = json.loads(public.readFile('{}/class/push/push.json'.format(public.get_panel_path())))
|
|||
|
|
except:
|
|||
|
|
pass
|
|||
|
|
|
|||
|
|
if not 'site_push' in data:
|
|||
|
|
return result
|
|||
|
|
|
|||
|
|
ssl_data = data['site_push']
|
|||
|
|
for key in ssl_data.keys():
|
|||
|
|
if ssl_data[key]['type'] != stype:
|
|||
|
|
continue
|
|||
|
|
|
|||
|
|
project = ssl_data[key]['project']
|
|||
|
|
if project in [siteName, 'all']:
|
|||
|
|
ssl_data[key]['id'] = key
|
|||
|
|
ssl_data[key]['s_module'] = 'site_push'
|
|||
|
|
|
|||
|
|
if project == siteName:
|
|||
|
|
result = ssl_data[key]
|
|||
|
|
break
|
|||
|
|
|
|||
|
|
if project == 'all':
|
|||
|
|
result = ssl_data[key]
|
|||
|
|
except:
|
|||
|
|
pass
|
|||
|
|
|
|||
|
|
p_obj = panelPush.panelPush()
|
|||
|
|
return p_obj.get_push_user(result)
|
|||
|
|
|
|||
|
|
def set_site_status_multiple(self,get):
|
|||
|
|
'''
|
|||
|
|
@name 批量设置网站状态
|
|||
|
|
@author zhwen<2020-11-17>
|
|||
|
|
@param sites_id "1,2"
|
|||
|
|
@param status 0/1
|
|||
|
|
'''
|
|||
|
|
sites_id = get.sites_id.split(',')
|
|||
|
|
sites_name = []
|
|||
|
|
errors = {}
|
|||
|
|
day_time = time.time()
|
|||
|
|
for site_id in sites_id:
|
|||
|
|
get.id = site_id
|
|||
|
|
find = public.M('sites').where("id=?", (site_id,)).find()
|
|||
|
|
get.name = find['name']
|
|||
|
|
|
|||
|
|
if get.status == '1':
|
|||
|
|
if find['edate'] != '0000-00-00' and public.to_date("%Y-%m-%d",find['edate']) < day_time:
|
|||
|
|
errors[get.name] = "failed, site has expired"
|
|||
|
|
continue
|
|||
|
|
sites_name.append(get.name)
|
|||
|
|
if get.status == '1':
|
|||
|
|
self.SiteStart(get, multiple=1)
|
|||
|
|
else:
|
|||
|
|
self.SiteStop(get, multiple=1)
|
|||
|
|
public.serviceReload()
|
|||
|
|
if get.status == '1':
|
|||
|
|
return {'status': True, 'msg': public.get_msg_gettext('Enable website [{}] successfully', (','.join(sites_name),)),
|
|||
|
|
'error': {}, 'success': sites_name}
|
|||
|
|
else:
|
|||
|
|
return {'status': True, 'msg': public.get_msg_gettext('Disable website [{}] successfully', (','.join(sites_name),)),
|
|||
|
|
'error': {}, 'success': sites_name}
|
|||
|
|
|
|||
|
|
# 启动站点
|
|||
|
|
def SiteStart(self, get, multiple=None):
|
|||
|
|
id = get.id
|
|||
|
|
Path = self.setupPath + '/stop'
|
|||
|
|
sitePath = public.M('sites').where("id=?", (id,)).getField('path')
|
|||
|
|
|
|||
|
|
# nginx
|
|||
|
|
file = self.setupPath + '/panel/vhost/nginx/' + get.name + '.conf'
|
|||
|
|
conf = public.readFile(file)
|
|||
|
|
if conf:
|
|||
|
|
conf = conf.replace(Path, sitePath)
|
|||
|
|
conf = conf.replace("#include", "include")
|
|||
|
|
public.writeFile(file, conf)
|
|||
|
|
# apache
|
|||
|
|
file = self.setupPath + '/panel/vhost/apache/' + get.name + '.conf'
|
|||
|
|
conf = public.readFile(file)
|
|||
|
|
if conf:
|
|||
|
|
conf = conf.replace(Path, sitePath)
|
|||
|
|
conf = conf.replace("#IncludeOptional", "IncludeOptional")
|
|||
|
|
public.writeFile(file, conf)
|
|||
|
|
|
|||
|
|
# OLS
|
|||
|
|
file = self.setupPath + '/panel/vhost/openlitespeed/' + get.name + '.conf'
|
|||
|
|
conf = public.readFile(file)
|
|||
|
|
if conf:
|
|||
|
|
rep = r'vhRoot\s*{}'.format(Path)
|
|||
|
|
new_content = 'vhRoot {}'.format(sitePath)
|
|||
|
|
conf = re.sub(rep, new_content, conf)
|
|||
|
|
public.writeFile(file, conf)
|
|||
|
|
|
|||
|
|
public.M('sites').where("id=?", (id,)).setField('status', '1')
|
|||
|
|
if not multiple:
|
|||
|
|
public.serviceReload()
|
|||
|
|
public.write_log_gettext('Site manager', 'Site [{}] started!', (get.name,))
|
|||
|
|
return public.return_msg_gettext(True, public.lang("Site started"))
|
|||
|
|
|
|||
|
|
def _process_has_run_dir(self, website_name, website_path, stop_path):
|
|||
|
|
'''
|
|||
|
|
@name 当网站存在允许目录时停止网站需要做处理
|
|||
|
|
@author zhwen<2020-11-17>
|
|||
|
|
@param site_id 1
|
|||
|
|
@param names test,baohu
|
|||
|
|
'''
|
|||
|
|
conf = public.readFile(self.setupPath + '/panel/vhost/nginx/' + website_name + '.conf')
|
|||
|
|
if not conf:
|
|||
|
|
return False
|
|||
|
|
try:
|
|||
|
|
really_path = re.search(r'root\s+(.*);', conf).group(1)
|
|||
|
|
tmp = stop_path + '/' + really_path.replace(website_path + '/', '')
|
|||
|
|
public.ExecShell('mkdir {t} && ln -s {s}/index.html {t}/index.html'.format(t=tmp, s=stop_path))
|
|||
|
|
except:
|
|||
|
|
pass
|
|||
|
|
|
|||
|
|
# 停止站点
|
|||
|
|
def SiteStop(self, get, multiple=None):
|
|||
|
|
path = self.setupPath + '/stop'
|
|||
|
|
id = get.id
|
|||
|
|
site_status = public.M('sites').where("id=?", (id,)).getField('status')
|
|||
|
|
if str(site_status) != '1':
|
|||
|
|
return public.returnMsg(True, public.lang("Site stopped"))
|
|||
|
|
if not os.path.exists(path):
|
|||
|
|
os.makedirs(path)
|
|||
|
|
public.downloadFile('https://node.yakpanel.com/stop_en.html', path + '/index.html')
|
|||
|
|
|
|||
|
|
# if 'This site has been closed by administrator' not in public.readFile(path + '/index.html'):
|
|||
|
|
# public.downloadFile('https://www.yakpanel.com/stop_en.html', path + '/index.html')
|
|||
|
|
|
|||
|
|
binding = public.M('binding').where('pid=?', (id,)).field('id,pid,domain,path,port,addtime').select()
|
|||
|
|
for b in binding:
|
|||
|
|
bpath = path + '/' + b['path']
|
|||
|
|
if not os.path.exists(bpath):
|
|||
|
|
public.ExecShell('mkdir -p ' + bpath)
|
|||
|
|
public.ExecShell('ln -sf ' + path + '/index.html ' + bpath + '/index.html')
|
|||
|
|
|
|||
|
|
sitePath = public.M('sites').where("id=?", (id,)).getField('path')
|
|||
|
|
self._process_has_run_dir(get.name, sitePath, path)
|
|||
|
|
# nginx
|
|||
|
|
file = self.setupPath + '/panel/vhost/nginx/' + get.name + '.conf'
|
|||
|
|
conf = public.readFile(file)
|
|||
|
|
if conf:
|
|||
|
|
src_path = 'root ' + sitePath
|
|||
|
|
dst_path = 'root ' + path
|
|||
|
|
if conf.find(src_path) != -1:
|
|||
|
|
conf = conf.replace(src_path, dst_path)
|
|||
|
|
else:
|
|||
|
|
conf = conf.replace(sitePath, path)
|
|||
|
|
conf = conf.replace("include", "#include")
|
|||
|
|
public.writeFile(file, conf)
|
|||
|
|
|
|||
|
|
# apache
|
|||
|
|
file = self.setupPath + '/panel/vhost/apache/' + get.name + '.conf'
|
|||
|
|
conf = public.readFile(file)
|
|||
|
|
if conf:
|
|||
|
|
conf = conf.replace(sitePath, path)
|
|||
|
|
conf = conf.replace("IncludeOptional", "#IncludeOptional")
|
|||
|
|
public.writeFile(file, conf)
|
|||
|
|
# OLS
|
|||
|
|
file = self.setupPath + '/panel/vhost/openlitespeed/' + get.name + '.conf'
|
|||
|
|
conf = public.readFile(file)
|
|||
|
|
if conf:
|
|||
|
|
rep = r'vhRoot\s*{}'.format(sitePath)
|
|||
|
|
new_content = 'vhRoot {}'.format(path)
|
|||
|
|
conf = re.sub(rep, new_content, conf)
|
|||
|
|
public.writeFile(file, conf)
|
|||
|
|
|
|||
|
|
public.M('sites').where("id=?", (id,)).setField('status', '0')
|
|||
|
|
if not multiple:
|
|||
|
|
public.serviceReload()
|
|||
|
|
public.write_log_gettext('Site manager', 'Site [{}] stopped!', (get.name,))
|
|||
|
|
return public.return_msg_gettext(True, public.lang("Site stopped"))
|
|||
|
|
|
|||
|
|
# 取流量限制值
|
|||
|
|
def GetLimitNet(self, get):
|
|||
|
|
id = get.id
|
|||
|
|
|
|||
|
|
# 取回配置文件
|
|||
|
|
siteName = public.M('sites').where("id=?", (id,)).getField('name')
|
|||
|
|
filename = self.setupPath + '/panel/vhost/nginx/' + siteName + '.conf'
|
|||
|
|
|
|||
|
|
# 站点总并发
|
|||
|
|
data = {}
|
|||
|
|
conf = public.readFile(filename)
|
|||
|
|
try:
|
|||
|
|
rep = r"\s+limit_conn\s+perserver\s+([0-9]+);"
|
|||
|
|
tmp = re.search(rep, conf).groups()
|
|||
|
|
data['perserver'] = int(tmp[0])
|
|||
|
|
|
|||
|
|
# IP并发限制
|
|||
|
|
rep = r"\s+limit_conn\s+perip\s+([0-9]+);"
|
|||
|
|
tmp = re.search(rep, conf).groups()
|
|||
|
|
data['perip'] = int(tmp[0])
|
|||
|
|
|
|||
|
|
# 请求并发限制
|
|||
|
|
rep = r"\s+limit_rate\s+([0-9]+)\w+;"
|
|||
|
|
tmp = re.search(rep, conf).groups()
|
|||
|
|
data['limit_rate'] = int(tmp[0])
|
|||
|
|
except:
|
|||
|
|
data['perserver'] = 0
|
|||
|
|
data['perip'] = 0
|
|||
|
|
data['limit_rate'] = 0
|
|||
|
|
|
|||
|
|
return data
|
|||
|
|
|
|||
|
|
# 设置流量限制
|
|||
|
|
def SetLimitNet(self, get):
|
|||
|
|
if (public.get_webserver() != 'nginx'): return public.return_msg_gettext(False, public.lang("Site Traffic Control only supports Nginx Web Server!"))
|
|||
|
|
|
|||
|
|
id = get.id
|
|||
|
|
if int(get.perserver) < 1 or int(get.perip) < 1 or int(get.perip) < 1:
|
|||
|
|
return public.return_msg_gettext(False, public.lang("Concurrency restrictions, IP restrictions, traffic restrictions must be greater than 0"))
|
|||
|
|
perserver = 'limit_conn perserver ' + get.perserver + ';'
|
|||
|
|
perip = 'limit_conn perip ' + get.perip + ';'
|
|||
|
|
limit_rate = 'limit_rate ' + get.limit_rate + 'k;'
|
|||
|
|
|
|||
|
|
# 取回配置文件
|
|||
|
|
siteName = public.M('sites').where("id=?", (id,)).getField('name')
|
|||
|
|
filename = self.setupPath + '/panel/vhost/nginx/' + siteName + '.conf'
|
|||
|
|
conf = public.readFile(filename)
|
|||
|
|
|
|||
|
|
# 设置共享内存
|
|||
|
|
oldLimit = self.setupPath + '/panel/vhost/nginx/limit.conf'
|
|||
|
|
if (os.path.exists(oldLimit)): os.remove(oldLimit)
|
|||
|
|
limit = self.setupPath + '/nginx/conf/nginx.conf'
|
|||
|
|
nginxConf = public.readFile(limit)
|
|||
|
|
limitConf = "limit_conn_zone $binary_remote_addr zone=perip:10m;\n\t\tlimit_conn_zone $server_name zone=perserver:10m;"
|
|||
|
|
nginxConf = nginxConf.replace("#limit_conn_zone $binary_remote_addr zone=perip:10m;", limitConf)
|
|||
|
|
public.writeFile(limit, nginxConf)
|
|||
|
|
|
|||
|
|
if (conf.find('limit_conn perserver') != -1):
|
|||
|
|
# 替换总并发
|
|||
|
|
rep = r"limit_conn\s+perserver\s+([0-9]+);"
|
|||
|
|
conf = re.sub(rep, perserver, conf)
|
|||
|
|
|
|||
|
|
# 替换IP并发限制
|
|||
|
|
rep = r"limit_conn\s+perip\s+([0-9]+);"
|
|||
|
|
conf = re.sub(rep, perip, conf)
|
|||
|
|
|
|||
|
|
# 替换请求流量限制
|
|||
|
|
rep = r"limit_rate\s+([0-9]+)\w+;"
|
|||
|
|
conf = re.sub(rep, limit_rate, conf)
|
|||
|
|
else:
|
|||
|
|
conf = conf.replace('#error_page 404/404.html;',
|
|||
|
|
"#error_page 404/404.html;\n " + perserver + "\n " + perip + "\n " + limit_rate)
|
|||
|
|
|
|||
|
|
import shutil
|
|||
|
|
shutil.copyfile(filename, self.nginx_conf_bak)
|
|||
|
|
public.writeFile(filename, conf)
|
|||
|
|
isError = public.checkWebConfig()
|
|||
|
|
if (isError != True):
|
|||
|
|
if os.path.exists(self.nginx_conf_bak): shutil.copyfile(self.nginx_conf_bak, filename)
|
|||
|
|
return public.return_msg_gettext(False, public.lang('ERROR: <br><a style="color:red;">' + isError.replace("\n", '<br>') + '</a>'))
|
|||
|
|
|
|||
|
|
public.serviceReload()
|
|||
|
|
public.write_log_gettext('Site manager', 'Site [{}] traffic control turned on!', (siteName,))
|
|||
|
|
return public.return_msg_gettext(True, public.lang("Setup successfully!"))
|
|||
|
|
|
|||
|
|
# 关闭流量限制
|
|||
|
|
def CloseLimitNet(self, get):
|
|||
|
|
id = get.id
|
|||
|
|
# 取回配置文件
|
|||
|
|
siteName = public.M('sites').where("id=?", (id,)).getField('name')
|
|||
|
|
filename = self.setupPath + '/panel/vhost/nginx/' + siteName + '.conf'
|
|||
|
|
conf = public.readFile(filename)
|
|||
|
|
# 清理总并发
|
|||
|
|
rep = r"\s+limit_conn\s+perserver\s+([0-9]+);"
|
|||
|
|
conf = re.sub(rep, '', conf)
|
|||
|
|
|
|||
|
|
# 清理IP并发限制
|
|||
|
|
rep = r"\s+limit_conn\s+perip\s+([0-9]+);"
|
|||
|
|
conf = re.sub(rep, '', conf)
|
|||
|
|
|
|||
|
|
# 清理请求流量限制
|
|||
|
|
rep = r"\s+limit_rate\s+([0-9]+)\w+;"
|
|||
|
|
conf = re.sub(rep, '', conf)
|
|||
|
|
public.writeFile(filename, conf)
|
|||
|
|
public.serviceReload()
|
|||
|
|
public.write_log_gettext('Site manager', 'Site Traffic Control has been turned off!', (siteName,))
|
|||
|
|
return public.return_msg_gettext(True, public.lang("Site Traffic Control has been turned off!"))
|
|||
|
|
|
|||
|
|
# 取301配置状态
|
|||
|
|
def Get301Status(self, get):
|
|||
|
|
siteName = get.siteName
|
|||
|
|
result = {}
|
|||
|
|
domains = ''
|
|||
|
|
id = public.M('sites').where("name=?", (siteName,)).getField('id')
|
|||
|
|
tmp = public.M('domain').where("pid=?", (id,)).field('name').select()
|
|||
|
|
node = public.M('sites').where('id=? and project_type=?', (id, 'Node')).count()
|
|||
|
|
if node:
|
|||
|
|
node = 'node_'
|
|||
|
|
else:
|
|||
|
|
node = ''
|
|||
|
|
for key in tmp:
|
|||
|
|
domains += key['name'] + ','
|
|||
|
|
try:
|
|||
|
|
if (public.get_webserver() == 'nginx'):
|
|||
|
|
conf = public.readFile(self.setupPath + '/panel/vhost/nginx/' + node + siteName + '.conf')
|
|||
|
|
if conf.find('301-START') == -1:
|
|||
|
|
result['domain'] = domains[:-1]
|
|||
|
|
result['src'] = ""
|
|||
|
|
result['status'] = False
|
|||
|
|
result['url'] = "http://"
|
|||
|
|
return result
|
|||
|
|
rep = r"return\s+301\s+((http|https)\://.+);"
|
|||
|
|
arr = re.search(rep, conf).groups()[0]
|
|||
|
|
rep = r"'\^(([\w-]+\.)+[\w-]+)'"
|
|||
|
|
tmp = re.search(rep, conf)
|
|||
|
|
src = ''
|
|||
|
|
if tmp: src = tmp.groups()[0]
|
|||
|
|
elif public.get_webserver() == 'apache':
|
|||
|
|
conf = public.readFile(self.setupPath + '/panel/vhost/apache/' + node + siteName + '.conf')
|
|||
|
|
if conf.find('301-START') == -1:
|
|||
|
|
result['domain'] = domains[:-1]
|
|||
|
|
result['src'] = ""
|
|||
|
|
result['status'] = False
|
|||
|
|
result['url'] = "http://"
|
|||
|
|
return result
|
|||
|
|
rep = r"RewriteRule\s+.+\s+((http|https)\://.+)\s+\["
|
|||
|
|
arr = re.search(rep, conf).groups()[0]
|
|||
|
|
rep = r"\^((\w+\.)+\w+)\s+\[NC"
|
|||
|
|
tmp = re.search(rep, conf)
|
|||
|
|
src = ''
|
|||
|
|
if tmp: src = tmp.groups()[0]
|
|||
|
|
else:
|
|||
|
|
conf = public.readFile(
|
|||
|
|
self.setupPath + '/panel/vhost/openlitespeed/redirect/{s}/{s}.conf'.format(s=siteName))
|
|||
|
|
if not conf:
|
|||
|
|
result['domain'] = domains[:-1]
|
|||
|
|
result['src'] = ""
|
|||
|
|
result['status'] = False
|
|||
|
|
result['url'] = "http://"
|
|||
|
|
return result
|
|||
|
|
rep = r"RewriteRule\s+.+\s+((http|https)\://.+)\s+\["
|
|||
|
|
arr = re.search(rep, conf).groups()[0]
|
|||
|
|
rep = r"\^((\w+\.)+\w+)\s+\[NC"
|
|||
|
|
tmp = re.search(rep, conf)
|
|||
|
|
src = ''
|
|||
|
|
if tmp: src = tmp.groups()[0]
|
|||
|
|
except:
|
|||
|
|
src = ''
|
|||
|
|
arr = 'http://'
|
|||
|
|
|
|||
|
|
result['domain'] = domains[:-1]
|
|||
|
|
result['src'] = src.replace("'", '')
|
|||
|
|
result['status'] = True
|
|||
|
|
if (len(arr) < 3): result['status'] = False
|
|||
|
|
result['url'] = arr
|
|||
|
|
|
|||
|
|
return result
|
|||
|
|
|
|||
|
|
# 设置301配置
|
|||
|
|
def Set301Status(self, get):
|
|||
|
|
siteName = get.siteName
|
|||
|
|
srcDomain = get.srcDomain
|
|||
|
|
toDomain = get.toDomain
|
|||
|
|
type = get.type
|
|||
|
|
rep = r"(http|https)\://.+"
|
|||
|
|
if not re.match(rep, toDomain): return public.return_msg_gettext(False, public.lang("URL address is invalid!"))
|
|||
|
|
|
|||
|
|
# nginx
|
|||
|
|
filename = self.setupPath + '/panel/vhost/nginx/' + siteName + '.conf'
|
|||
|
|
mconf = public.readFile(filename)
|
|||
|
|
if mconf == False: return public.return_msg_gettext(False, public.lang("Configuration file not exist"))
|
|||
|
|
if (srcDomain == 'all'):
|
|||
|
|
conf301 = "\t#301-START\n\t\treturn 301 " + toDomain + "$request_uri;\n\t#301-END"
|
|||
|
|
else:
|
|||
|
|
conf301 = "\t#301-START\n\t\tif ($host ~ '^" + srcDomain + "'){\n\t\t\treturn 301 " + toDomain + "$request_uri;\n\t\t}\n\t#301-END"
|
|||
|
|
if type == '1':
|
|||
|
|
mconf = mconf.replace("#error_page 404/404.html;", "#error_page 404/404.html;\n" + conf301)
|
|||
|
|
else:
|
|||
|
|
rep = "\\s+#301-START(.|\n){1,300}#301-END"
|
|||
|
|
mconf = re.sub(rep, '', mconf)
|
|||
|
|
public.writeFile(filename, mconf)
|
|||
|
|
|
|||
|
|
# apache
|
|||
|
|
filename = self.setupPath + '/panel/vhost/apache/' + siteName + '.conf'
|
|||
|
|
mconf = public.readFile(filename)
|
|||
|
|
if mconf == False: return public.return_msg_gettext(False, public.lang("Configuration file not exist"))
|
|||
|
|
if type == '1':
|
|||
|
|
if (srcDomain == 'all'):
|
|||
|
|
conf301 = "\n\t#301-START\n\t<IfModule mod_rewrite.c>\n\t\tRewriteEngine on\n\t\tRewriteRule ^(.*)$ " + toDomain + "$1 [L,R=301]\n\t</IfModule>\n\t#301-END\n"
|
|||
|
|
else:
|
|||
|
|
conf301 = "\n\t#301-START\n\t<IfModule mod_rewrite.c>\n\t\tRewriteEngine on\n\t\tRewriteCond %{HTTP_HOST} ^" + srcDomain + " [NC]\n\t\tRewriteRule ^(.*) " + toDomain + "$1 [L,R=301]\n\t</IfModule>\n\t#301-END\n"
|
|||
|
|
rep = "combined"
|
|||
|
|
mconf = mconf.replace(rep, rep + "\n\t" + conf301)
|
|||
|
|
else:
|
|||
|
|
rep = "\n\\s+#301-START(.|\n){1,300}#301-END\n*"
|
|||
|
|
mconf = re.sub(rep, '\n\n', mconf, 1)
|
|||
|
|
mconf = re.sub(rep, '\n\n', mconf, 1)
|
|||
|
|
|
|||
|
|
public.writeFile(filename, mconf)
|
|||
|
|
|
|||
|
|
# OLS
|
|||
|
|
conf_dir = self.setupPath + '/panel/vhost/openlitespeed/redirect/{}/'.format(siteName)
|
|||
|
|
if not os.path.exists(conf_dir):
|
|||
|
|
os.makedirs(conf_dir)
|
|||
|
|
file = conf_dir + siteName + '.conf'
|
|||
|
|
if type == '1':
|
|||
|
|
if (srcDomain == 'all'):
|
|||
|
|
conf301 = "#301-START\nRewriteEngine on\nRewriteRule ^(.*)$ " + toDomain + "$1 [L,R=301]#301-END\n"
|
|||
|
|
else:
|
|||
|
|
conf301 = "#301-START\nRewriteEngine on\nRewriteCond %{HTTP_HOST} ^" + srcDomain + " [NC]\nRewriteRule ^(.*) " + toDomain + "$1 [L,R=301]\n#301-END\n"
|
|||
|
|
public.writeFile(file, conf301)
|
|||
|
|
else:
|
|||
|
|
public.ExecShell('rm -f {}*'.format(file))
|
|||
|
|
|
|||
|
|
isError = public.checkWebConfig()
|
|||
|
|
if (isError != True):
|
|||
|
|
return public.return_msg_gettext(False, public.lang('ERROR: <br><a style="color:red;">' + isError.replace("\n", '<br>') + '</a>'))
|
|||
|
|
|
|||
|
|
public.serviceReload()
|
|||
|
|
return public.return_msg_gettext(True, public.lang("Setup successfully!"))
|
|||
|
|
|
|||
|
|
# 取子目录绑定
|
|||
|
|
def GetDirBinding(self, get):
|
|||
|
|
path = public.M('sites').where('id=?', (get.id,)).getField('path')
|
|||
|
|
if not os.path.exists(path):
|
|||
|
|
checks = ['/', '/usr', '/etc']
|
|||
|
|
if path in checks:
|
|||
|
|
data = {}
|
|||
|
|
data['dirs'] = []
|
|||
|
|
data['binding'] = []
|
|||
|
|
return data
|
|||
|
|
public.ExecShell('mkdir -p ' + path)
|
|||
|
|
public.ExecShell('chmod 755 ' + path)
|
|||
|
|
public.ExecShell('chown www:www ' + path)
|
|||
|
|
get.path = path
|
|||
|
|
self.SetDirUserINI(get)
|
|||
|
|
siteName = public.M('sites').where('id=?', (get.id,)).getField('name')
|
|||
|
|
public.write_log_gettext('Site manager', "Site [{}], document root [{}] does NOT exist, recreated!", (siteName, path))
|
|||
|
|
dirnames = []
|
|||
|
|
# 取运行目录
|
|||
|
|
run_path = self.GetRunPath(get)
|
|||
|
|
if run_path: path += run_path
|
|||
|
|
|
|||
|
|
# 遍历目录
|
|||
|
|
if os.path.exists(path):
|
|||
|
|
for filename in os.listdir(path):
|
|||
|
|
try:
|
|||
|
|
json.dumps(filename)
|
|||
|
|
if sys.version_info[0] == 2:
|
|||
|
|
filename = filename.encode('utf-8')
|
|||
|
|
else:
|
|||
|
|
filename.encode('utf-8')
|
|||
|
|
filePath = path + '/' + filename
|
|||
|
|
if os.path.islink(filePath): continue
|
|||
|
|
if os.path.isdir(filePath):
|
|||
|
|
dirnames.append(filename)
|
|||
|
|
except:
|
|||
|
|
pass
|
|||
|
|
|
|||
|
|
data = {}
|
|||
|
|
data['run_path'] = run_path # 运行目录
|
|||
|
|
data['dirs'] = dirnames
|
|||
|
|
data['binding'] = public.M('binding').where('pid=?',(get.id,)).field('id,pid,domain,path,port,addtime').select()
|
|||
|
|
|
|||
|
|
# 标记子目录是否存在
|
|||
|
|
for dname in data['binding']:
|
|||
|
|
_path = os.path.join(path,dname['path'])
|
|||
|
|
if not os.path.exists(_path):
|
|||
|
|
_path = _path.replace(run_path,'')
|
|||
|
|
if not os.path.exists(_path):
|
|||
|
|
dname['path'] += '<a style="color:red;"> >> error: directory does not exist</a>'
|
|||
|
|
else:
|
|||
|
|
dname['path'] = '../' + dname['path']
|
|||
|
|
return data
|
|||
|
|
|
|||
|
|
# 添加子目录绑定
|
|||
|
|
def AddDirBinding(self, get):
|
|||
|
|
import shutil
|
|||
|
|
id = get.id
|
|||
|
|
tmp = get.domain.split(':')
|
|||
|
|
domain = tmp[0].lower()
|
|||
|
|
# 中文域名转码
|
|||
|
|
domain = public.en_punycode(domain)
|
|||
|
|
port = '80'
|
|||
|
|
version = ''
|
|||
|
|
if len(tmp) > 1: port = tmp[1]
|
|||
|
|
if not hasattr(get, 'dirName'): public.return_msg_gettext(False, 'Directory cannot be empty!')
|
|||
|
|
dirName = get.dirName
|
|||
|
|
|
|||
|
|
reg = r"^([\w\-\*]{1,100}\.){1,4}([\w\-]{1,100}|[\w\-]{1,100}\.[\w\-]{1,100})$"
|
|||
|
|
if not re.match(reg, domain): return public.return_msg_gettext(False, public.lang("Format of primary domain is incorrect"))
|
|||
|
|
|
|||
|
|
siteInfo = public.M('sites').where("id=?",(id,)).field('id,path,name').find()
|
|||
|
|
# 实际运行目录
|
|||
|
|
root_path = siteInfo['path']
|
|||
|
|
run_path = self.GetRunPath(get)
|
|||
|
|
if run_path: root_path += run_path
|
|||
|
|
|
|||
|
|
|
|||
|
|
webdir = root_path + '/' + dirName
|
|||
|
|
webdir = webdir.replace('//','/').strip()
|
|||
|
|
if not os.path.exists(webdir): # 如果在运行目录找不到指定子目录,尝试到根目录查找
|
|||
|
|
root_path = siteInfo['path']
|
|||
|
|
webdir = root_path + '/' + dirName
|
|||
|
|
webdir = webdir.replace('//','/').strip()
|
|||
|
|
|
|||
|
|
sql = public.M('binding')
|
|||
|
|
if sql.where("domain=?", (domain,)).count() > 0: return public.return_msg_gettext(False, public.lang("The domain you tried to add already exists!"))
|
|||
|
|
if public.M('domain').where("name=?", (domain,)).count() > 0: return public.return_msg_gettext(False, public.lang("The domain you tried to add already exists!"))
|
|||
|
|
|
|||
|
|
filename = self.setupPath + '/panel/vhost/nginx/' + siteInfo['name'] + '.conf'
|
|||
|
|
nginx_conf_file = filename
|
|||
|
|
conf = public.readFile(filename)
|
|||
|
|
if conf:
|
|||
|
|
listen_ipv6 = ''
|
|||
|
|
if self.is_ipv6: listen_ipv6 = "\n listen [::]:%s;" % port
|
|||
|
|
try:
|
|||
|
|
rep = r"enable-php-(\w{2,5})\.conf"
|
|||
|
|
tmp = re.search(rep,conf)
|
|||
|
|
if not tmp:
|
|||
|
|
rep = r"enable-php-(\d+-wpfastcgi).conf"
|
|||
|
|
tmp = re.search(rep, conf)
|
|||
|
|
except:
|
|||
|
|
return public.returnMsg(False, public.lang("Get enable php config failed!"))
|
|||
|
|
tmp = tmp.groups()
|
|||
|
|
version = tmp[0]
|
|||
|
|
bindingConf = r'''
|
|||
|
|
#BINDING-%s-START
|
|||
|
|
server
|
|||
|
|
{
|
|||
|
|
listen %s;%s
|
|||
|
|
server_name %s;
|
|||
|
|
index index.php index.html index.htm default.php default.htm default.html;
|
|||
|
|
root %s;
|
|||
|
|
|
|||
|
|
include enable-php-%s.conf;
|
|||
|
|
include %s/panel/vhost/rewrite/%s.conf;
|
|||
|
|
%s
|
|||
|
|
location ~ ^/(\.user.ini|\.htaccess|\.git|\.env|\.svn|\.project|LICENSE|README.md)
|
|||
|
|
{
|
|||
|
|
return 404;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
%s
|
|||
|
|
location ~ \.well-known{
|
|||
|
|
allow all;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
location ~ .*\\.(gif|jpg|jpeg|png|bmp|swf)$
|
|||
|
|
{
|
|||
|
|
expires 30d;
|
|||
|
|
error_log /dev/null;
|
|||
|
|
access_log /dev/null;
|
|||
|
|
}
|
|||
|
|
location ~ .*\\.(js|css)?$
|
|||
|
|
{
|
|||
|
|
expires 12h;
|
|||
|
|
error_log /dev/null;
|
|||
|
|
access_log /dev/null;
|
|||
|
|
}
|
|||
|
|
access_log %s.log;
|
|||
|
|
error_log %s.error.log;
|
|||
|
|
}
|
|||
|
|
#BINDING-%s-END''' % (domain, port, listen_ipv6, domain, webdir, version, self.setupPath, siteInfo['name'],
|
|||
|
|
("# Forbidden files or directories"), ("# Directory verification related settings for one-click application for SSL certificate"),
|
|||
|
|
public.GetConfigValue('logs_path') + '/' + siteInfo['name'],
|
|||
|
|
public.GetConfigValue('logs_path') + '/' + siteInfo['name'], domain)
|
|||
|
|
|
|||
|
|
conf += bindingConf
|
|||
|
|
shutil.copyfile(filename, self.nginx_conf_bak)
|
|||
|
|
public.writeFile(filename, conf)
|
|||
|
|
|
|||
|
|
filename = self.setupPath + '/panel/vhost/apache/' + siteInfo['name'] + '.conf'
|
|||
|
|
conf = public.readFile(filename)
|
|||
|
|
if conf:
|
|||
|
|
try:
|
|||
|
|
try:
|
|||
|
|
httpdVersion = public.readFile(self.setupPath + '/apache/version.pl').strip()
|
|||
|
|
except:
|
|||
|
|
httpdVersion = ""
|
|||
|
|
if httpdVersion == '2.2':
|
|||
|
|
phpConfig = ""
|
|||
|
|
apaOpt = "Order allow,deny\n\t\tAllow from all"
|
|||
|
|
else:
|
|||
|
|
# rep = r"php-cgi-([0-9]{2,3})\.sock"
|
|||
|
|
# tmp = re.search(rep,conf).groups()
|
|||
|
|
# version = tmp[0]
|
|||
|
|
version = public.get_php_version_conf(conf)
|
|||
|
|
phpConfig = '''
|
|||
|
|
#PHP
|
|||
|
|
<FilesMatch \\.php>
|
|||
|
|
SetHandler "proxy:%s"
|
|||
|
|
</FilesMatch>
|
|||
|
|
''' % (public.get_php_proxy(version, 'apache'),)
|
|||
|
|
apaOpt = 'Require all granted'
|
|||
|
|
|
|||
|
|
bindingConf = r'''
|
|||
|
|
|
|||
|
|
#BINDING-%s-START
|
|||
|
|
<VirtualHost *:%s>
|
|||
|
|
ServerAdmin webmaster@example.com
|
|||
|
|
DocumentRoot "%s"
|
|||
|
|
ServerAlias %s
|
|||
|
|
#errorDocument 404 /404.html
|
|||
|
|
ErrorLog "%s-error_log"
|
|||
|
|
CustomLog "%s-access_log" combined
|
|||
|
|
%s
|
|||
|
|
|
|||
|
|
#DENY FILES
|
|||
|
|
<Files ~ (\.user.ini|\.htaccess|\.git|\.env|\.svn|\.project|LICENSE|README.md)$>
|
|||
|
|
Order allow,deny
|
|||
|
|
Deny from all
|
|||
|
|
</Files>
|
|||
|
|
|
|||
|
|
#PATH
|
|||
|
|
<Directory "%s">
|
|||
|
|
SetOutputFilter DEFLATE
|
|||
|
|
Options FollowSymLinks
|
|||
|
|
AllowOverride All
|
|||
|
|
%s
|
|||
|
|
DirectoryIndex index.php index.html index.htm default.php default.html default.htm
|
|||
|
|
</Directory>
|
|||
|
|
</VirtualHost>
|
|||
|
|
#BINDING-%s-END''' % (domain, port, webdir, domain, public.GetConfigValue('logs_path') + '/' + siteInfo['name'],
|
|||
|
|
public.GetConfigValue('logs_path') + '/' + siteInfo['name'], phpConfig, webdir, apaOpt, domain)
|
|||
|
|
|
|||
|
|
conf += bindingConf
|
|||
|
|
shutil.copyfile(filename, self.apache_conf_bak)
|
|||
|
|
public.writeFile(filename, conf)
|
|||
|
|
except:
|
|||
|
|
pass
|
|||
|
|
get.webname = siteInfo['name']
|
|||
|
|
get.port = port
|
|||
|
|
self.phpVersion = version
|
|||
|
|
self.siteName = siteInfo['name']
|
|||
|
|
self.sitePath = webdir
|
|||
|
|
listen_file = self.setupPath + "/panel/vhost/openlitespeed/listen/80.conf"
|
|||
|
|
listen_conf = public.readFile(listen_file)
|
|||
|
|
if listen_conf:
|
|||
|
|
rep = r'secure\s*0'
|
|||
|
|
map = '\tmap {}_{} {}'.format(siteInfo['name'], dirName, domain)
|
|||
|
|
listen_conf = re.sub(rep, 'secure 0\n' + map, listen_conf)
|
|||
|
|
public.writeFile(listen_file, listen_conf)
|
|||
|
|
self.openlitespeed_add_site(get)
|
|||
|
|
|
|||
|
|
# 检查配置是否有误
|
|||
|
|
isError = public.checkWebConfig()
|
|||
|
|
if isError != True:
|
|||
|
|
if os.path.exists(self.nginx_conf_bak): shutil.copyfile(self.nginx_conf_bak, nginx_conf_file)
|
|||
|
|
if os.path.exists(self.apache_conf_bak): shutil.copyfile(self.apache_conf_bak, filename)
|
|||
|
|
return public.return_msg_gettext(False, public.lang('ERROR: <br><a style="color:red;">' + isError.replace("\n", '<br>') + '</a>'))
|
|||
|
|
|
|||
|
|
public.M('binding').add('pid,domain,port,path,addtime', (id, domain, port, dirName, public.getDate()))
|
|||
|
|
public.serviceReload()
|
|||
|
|
public.write_log_gettext('Site manager', 'Site [{}] subdirectory [{}] bound to [{}]', (siteInfo['name'], dirName, domain))
|
|||
|
|
return public.return_msg_gettext(True, public.lang("Successfully added"))
|
|||
|
|
|
|||
|
|
def delete_dir_bind_multiple(self, get):
|
|||
|
|
'''
|
|||
|
|
@name 批量删除网站
|
|||
|
|
@author zhwen<2020-11-17>
|
|||
|
|
@param bind_ids 1,2,3
|
|||
|
|
'''
|
|||
|
|
bind_ids = get.bind_ids.split(',')
|
|||
|
|
del_successfully = []
|
|||
|
|
del_failed = {}
|
|||
|
|
for bind_id in bind_ids:
|
|||
|
|
get.id = bind_id
|
|||
|
|
domain = public.M('binding').where("id=?", (get.id,)).getField('domain')
|
|||
|
|
if not domain:
|
|||
|
|
continue
|
|||
|
|
try:
|
|||
|
|
self.DelDirBinding(get, multiple=1)
|
|||
|
|
del_successfully.append(domain)
|
|||
|
|
except:
|
|||
|
|
del_failed[domain] = public.lang("There was an error deleting, please try again.")
|
|||
|
|
pass
|
|||
|
|
public.serviceReload()
|
|||
|
|
return {'status': True, 'msg': public.get_msg_gettext('Delete [{}] subdirectory binding successfully', (','.join(del_successfully),)),
|
|||
|
|
'error': del_failed,
|
|||
|
|
'success': del_successfully}
|
|||
|
|
|
|||
|
|
# 删除子目录绑定
|
|||
|
|
def DelDirBinding(self, get, multiple=None):
|
|||
|
|
id = get.id
|
|||
|
|
binding = public.M('binding').where("id=?", (id,)).field('id,pid,domain,path').find()
|
|||
|
|
siteName = public.M('sites').where("id=?", (binding['pid'],)).getField('name')
|
|||
|
|
|
|||
|
|
# nginx
|
|||
|
|
filename = self.setupPath + '/panel/vhost/nginx/' + siteName + '.conf'
|
|||
|
|
conf = public.readFile(filename)
|
|||
|
|
if conf:
|
|||
|
|
rep = r"\s*.+BINDING-" + binding['domain'] + "-START(.|\n)+BINDING-" + binding['domain'] + "-END"
|
|||
|
|
conf = re.sub(rep, '', conf)
|
|||
|
|
public.writeFile(filename, conf)
|
|||
|
|
|
|||
|
|
# apache
|
|||
|
|
filename = self.setupPath + '/panel/vhost/apache/' + siteName + '.conf'
|
|||
|
|
conf = public.readFile(filename)
|
|||
|
|
if conf:
|
|||
|
|
rep = r"\s*.+BINDING-" + binding['domain'] + "-START(.|\n)+BINDING-" + binding['domain'] + "-END"
|
|||
|
|
conf = re.sub(rep, '', conf)
|
|||
|
|
public.writeFile(filename, conf)
|
|||
|
|
|
|||
|
|
# openlitespeed
|
|||
|
|
filename = self.setupPath + '/panel/vhost/openlitespeed/' + siteName + '.conf'
|
|||
|
|
conf = public.readFile(filename)
|
|||
|
|
rep = "#SUBDIR\\s*{s}_{d}\\s*START(\n|.)+#SUBDIR\\s*{s}_{d}\\s*END".format(s=siteName, d=binding['path'])
|
|||
|
|
if conf:
|
|||
|
|
conf = re.sub(rep, '', conf)
|
|||
|
|
public.writeFile(filename, conf)
|
|||
|
|
# 删除域名,前端需要传域名
|
|||
|
|
get.webname = siteName
|
|||
|
|
get.domain = binding['domain']
|
|||
|
|
self._del_ols_domain(get)
|
|||
|
|
|
|||
|
|
# 清理子域名监听文件
|
|||
|
|
listen_file = self.setupPath + "/panel/vhost/openlitespeed/listen/80.conf"
|
|||
|
|
listen_conf = public.readFile(listen_file)
|
|||
|
|
if listen_conf:
|
|||
|
|
map_reg = r'\s*map\s*{}_{}.*'.format(siteName, binding['path'])
|
|||
|
|
listen_conf = re.sub(map_reg, '', listen_conf)
|
|||
|
|
public.writeFile(listen_file, listen_conf)
|
|||
|
|
# 清理detail文件
|
|||
|
|
detail_file = "{}/panel/vhost/openlitespeed/detail/{}_{}.conf".format(self.setupPath, siteName, binding['path'])
|
|||
|
|
public.ExecShell("rm -f {}*".format(detail_file))
|
|||
|
|
|
|||
|
|
# 从数据库删除绑定
|
|||
|
|
public.M('binding').where("id=?",(id,)).delete()
|
|||
|
|
|
|||
|
|
# 如果没有其它域名绑定同一子目录,则删除该子目录的伪静态规则
|
|||
|
|
if not public.M('binding').where("path=? AND pid=?",(binding['path'],binding['pid'])).count():
|
|||
|
|
filename = self.setupPath + '/panel/vhost/rewrite/' + siteName + '_' + binding['path'] + '.conf'
|
|||
|
|
if os.path.exists(filename): public.ExecShell('rm -rf %s'%filename)
|
|||
|
|
# 是否需要重载服务
|
|||
|
|
if not multiple:
|
|||
|
|
public.serviceReload()
|
|||
|
|
public.write_log_gettext('Site manager', 'Deleted site [{}] subdirectory [{}] binding', (siteName, binding['path']))
|
|||
|
|
return public.return_msg_gettext(True, public.lang("Successfully deleted"))
|
|||
|
|
|
|||
|
|
# 取子目录Rewrite
|
|||
|
|
def GetDirRewrite(self, get):
|
|||
|
|
id = get.id
|
|||
|
|
find = public.M('binding').where("id=?", (id,)).field('id,pid,domain,path').find()
|
|||
|
|
site = public.M('sites').where("id=?", (find['pid'],)).field('id,name,path').find()
|
|||
|
|
|
|||
|
|
if (public.get_webserver() != 'nginx'):
|
|||
|
|
filename = site['path'] + '/' + find['path'] + '/.htaccess'
|
|||
|
|
else:
|
|||
|
|
filename = self.setupPath + '/panel/vhost/rewrite/' + site['name'] + '_' + find['path'] + '.conf'
|
|||
|
|
|
|||
|
|
if hasattr(get, 'add'):
|
|||
|
|
public.writeFile(filename, '')
|
|||
|
|
if public.get_webserver() == 'nginx':
|
|||
|
|
file = self.setupPath + '/panel/vhost/nginx/' + site['name'] + '.conf'
|
|||
|
|
conf = public.readFile(file)
|
|||
|
|
domain = find['domain']
|
|||
|
|
rep = "\n#BINDING-" + domain + "-START(.|\n)+BINDING-" + domain + "-END"
|
|||
|
|
tmp = re.search(rep, conf).group()
|
|||
|
|
dirConf = tmp.replace('rewrite/' + site['name'] + '.conf;',
|
|||
|
|
'rewrite/' + site['name'] + '_' + find['path'] + '.conf;')
|
|||
|
|
conf = conf.replace(tmp, dirConf)
|
|||
|
|
public.writeFile(file, conf)
|
|||
|
|
data = {}
|
|||
|
|
data['status'] = False
|
|||
|
|
if os.path.exists(filename):
|
|||
|
|
data['status'] = True
|
|||
|
|
data['data'] = public.readFile(filename)
|
|||
|
|
data['rlist'] = ['0.default']
|
|||
|
|
webserver = public.get_webserver()
|
|||
|
|
if webserver == "openlitespeed":
|
|||
|
|
webserver = "apache"
|
|||
|
|
for ds in os.listdir('rewrite/' + webserver):
|
|||
|
|
if ds == 'list.txt': continue
|
|||
|
|
data['rlist'].append(ds[0:len(ds) - 5])
|
|||
|
|
data['filename'] = filename
|
|||
|
|
return data
|
|||
|
|
|
|||
|
|
# 取默认文档
|
|||
|
|
def GetIndex(self, get):
|
|||
|
|
id = get.id
|
|||
|
|
Name = public.M('sites').where("id=?", (id,)).getField('name')
|
|||
|
|
file = self.setupPath + '/panel/vhost/' + public.get_webserver() + '/' + Name + '.conf'
|
|||
|
|
if public.get_webserver() == 'openlitespeed':
|
|||
|
|
file = self.setupPath + '/panel/vhost/' + public.get_webserver() + '/detail/' + Name + '.conf'
|
|||
|
|
conf = public.readFile(file)
|
|||
|
|
if conf == False: return public.return_msg_gettext(False, public.lang("Configuration file not exist"))
|
|||
|
|
if public.get_webserver() == 'nginx':
|
|||
|
|
rep = r"\s+index\s+(.+);"
|
|||
|
|
elif public.get_webserver() == 'apache':
|
|||
|
|
rep = "DirectoryIndex\\s+(.+)\n"
|
|||
|
|
else:
|
|||
|
|
rep = "indexFiles\\s+(.+)\n"
|
|||
|
|
if re.search(rep, conf):
|
|||
|
|
tmp = re.search(rep, conf).groups()
|
|||
|
|
if public.get_webserver() == 'openlitespeed':
|
|||
|
|
return tmp[0]
|
|||
|
|
return tmp[0].replace(' ', ',')
|
|||
|
|
return public.return_msg_gettext(False, public.lang("Failed to get, there is no default document in the configuration file"))
|
|||
|
|
|
|||
|
|
# 设置默认文档
|
|||
|
|
def SetIndex(self, get):
|
|||
|
|
id = get.id
|
|||
|
|
|
|||
|
|
Index = get.Index.replace(' ', '')
|
|||
|
|
Index = Index.replace(',,', ',').strip()
|
|||
|
|
if not Index: return public.returnMsg(False, public.lang("Default index file cannot be empty"))
|
|||
|
|
if get.Index.find('.') == -1: return public.return_msg_gettext(False, public.lang("Default Document Format is invalid, e.g., index.html"))
|
|||
|
|
|
|||
|
|
if len(Index) < 3: return public.return_msg_gettext(False, public.lang("Default Document cannot be empty!"))
|
|||
|
|
|
|||
|
|
Name = public.M('sites').where("id=?", (id,)).getField('name')
|
|||
|
|
# 准备指令
|
|||
|
|
Index_L = Index.replace(",", " ")
|
|||
|
|
|
|||
|
|
# nginx
|
|||
|
|
file = self.setupPath + '/panel/vhost/nginx/' + Name + '.conf'
|
|||
|
|
conf = public.readFile(file)
|
|||
|
|
if conf:
|
|||
|
|
rep = r"\s+index\s+.+;"
|
|||
|
|
conf = re.sub(rep, "\n\tindex " + Index_L + ";", conf)
|
|||
|
|
public.writeFile(file, conf)
|
|||
|
|
|
|||
|
|
# apache
|
|||
|
|
file = self.setupPath + '/panel/vhost/apache/' + Name + '.conf'
|
|||
|
|
conf = public.readFile(file)
|
|||
|
|
if conf:
|
|||
|
|
rep = "DirectoryIndex\\s+.+\n"
|
|||
|
|
conf = re.sub(rep, 'DirectoryIndex ' + Index_L + "\n", conf)
|
|||
|
|
public.writeFile(file, conf)
|
|||
|
|
|
|||
|
|
# openlitespeed
|
|||
|
|
file = self.setupPath + '/panel/vhost/openlitespeed/detail/' + Name + '.conf'
|
|||
|
|
conf = public.readFile(file)
|
|||
|
|
if conf:
|
|||
|
|
rep = "indexFiles\\s+.+\n"
|
|||
|
|
Index = Index.split(',')
|
|||
|
|
Index = [i for i in Index if i]
|
|||
|
|
Index = ",".join(Index)
|
|||
|
|
conf = re.sub(rep, 'indexFiles ' + Index + "\n", conf)
|
|||
|
|
public.writeFile(file, conf)
|
|||
|
|
|
|||
|
|
public.serviceReload()
|
|||
|
|
public.write_log_gettext('Site manager', 'Defualt document of site [{}] is [{}]', (Name, Index_L))
|
|||
|
|
return public.return_msg_gettext(True, public.lang("Setup successfully!"))
|
|||
|
|
|
|||
|
|
# 修改物理路径
|
|||
|
|
def SetPath(self, get):
|
|||
|
|
id = get.id
|
|||
|
|
Path = self.GetPath(get.path)
|
|||
|
|
if Path == "" or id == '0': return public.return_msg_gettext(False, public.lang("Directory cannot be empty!"))
|
|||
|
|
|
|||
|
|
if not self.__check_site_path(Path): return public.return_msg_gettext(False, public.lang("System critical directory cannot be used as site directory"))
|
|||
|
|
if not public.check_site_path(Path):
|
|||
|
|
a, c = public.get_sys_path()
|
|||
|
|
return public.return_msg_gettext(False, public.lang("Please do not set the website root directory to the system main directory: <br>{}", "<br>".join(a+c)))
|
|||
|
|
|
|||
|
|
SiteFind = public.M("sites").where("id=?", (id,)).field('path,name').find()
|
|||
|
|
if SiteFind["path"] == Path: return public.return_msg_gettext(False, public.lang("Same as original path, no need to change!"))
|
|||
|
|
Name = SiteFind['name']
|
|||
|
|
file = self.setupPath + '/panel/vhost/nginx/' + Name + '.conf'
|
|||
|
|
conf = public.readFile(file)
|
|||
|
|
if conf:
|
|||
|
|
conf = conf.replace(SiteFind['path'], Path)
|
|||
|
|
public.writeFile(file, conf)
|
|||
|
|
|
|||
|
|
file = self.setupPath + '/panel/vhost/apache/' + Name + '.conf'
|
|||
|
|
conf = public.readFile(file)
|
|||
|
|
if conf:
|
|||
|
|
rep = "DocumentRoot\\s+.+\n"
|
|||
|
|
conf = re.sub(rep, 'DocumentRoot "' + Path + '"\n', conf)
|
|||
|
|
rep = "<Directory\\s+.+\n"
|
|||
|
|
conf = re.sub(rep, '<Directory "' + Path + "\">\n", conf)
|
|||
|
|
public.writeFile(file, conf)
|
|||
|
|
|
|||
|
|
# OLS
|
|||
|
|
file = self.setupPath + '/panel/vhost/openlitespeed/' + Name + '.conf'
|
|||
|
|
conf = public.readFile(file)
|
|||
|
|
if conf:
|
|||
|
|
reg = 'vhRoot.*'
|
|||
|
|
conf = re.sub(reg, 'vhRoot ' + Path, conf)
|
|||
|
|
public.writeFile(file, conf)
|
|||
|
|
|
|||
|
|
# 创建basedir
|
|||
|
|
userIni = Path + '/.user.ini'
|
|||
|
|
if os.path.exists(userIni): public.ExecShell("chattr -i " + userIni)
|
|||
|
|
public.writeFile(userIni, 'open_basedir=' + Path + '/:/tmp/')
|
|||
|
|
public.ExecShell('chmod 644 ' + userIni)
|
|||
|
|
public.ExecShell('chown root:root ' + userIni)
|
|||
|
|
public.ExecShell('chattr +i ' + userIni)
|
|||
|
|
public.set_site_open_basedir_nginx(Name)
|
|||
|
|
|
|||
|
|
public.serviceReload()
|
|||
|
|
public.M("sites").where("id=?",(id,)).setField('path',Path)
|
|||
|
|
public.write_log_gettext('Site manager', 'Successfully changed directory of site [{}]!',(Name,))
|
|||
|
|
self.CheckRunPathExists(id)
|
|||
|
|
return public.return_msg_gettext(True, public.lang("Successfully set"))
|
|||
|
|
|
|||
|
|
def CheckRunPathExists(self,site_id):
|
|||
|
|
'''
|
|||
|
|
@name 检查站点运行目录是否存在
|
|||
|
|
@author hwliang
|
|||
|
|
@param site_id int 站点ID
|
|||
|
|
@return bool
|
|||
|
|
'''
|
|||
|
|
|
|||
|
|
site_info = public.M('sites').where('id=?',(site_id,)).field('name,path').find()
|
|||
|
|
if not site_info: return False
|
|||
|
|
args = public.dict_obj()
|
|||
|
|
args.id = site_id
|
|||
|
|
run_path = self.GetRunPath(args)
|
|||
|
|
site_run_path = site_info['path'] + '/' + run_path
|
|||
|
|
if os.path.exists(site_run_path): return True
|
|||
|
|
args.runPath = '/'
|
|||
|
|
self.SetSiteRunPath(args)
|
|||
|
|
public.WriteLog('TYPE_SITE','Due to modifying the root directory of the website [{}], the original running directory [.{}] does not exist, and the directory has been automatically switched to [./]'.format(site_info['name'],run_path))
|
|||
|
|
return False
|
|||
|
|
|
|||
|
|
#取当前可用PHP版本
|
|||
|
|
def GetPHPVersion(self,get):
|
|||
|
|
|
|||
|
|
phpVersions = public.get_php_versions()
|
|||
|
|
phpVersions.insert(0,'other')
|
|||
|
|
phpVersions.insert(0,'00')
|
|||
|
|
httpdVersion = ""
|
|||
|
|
filename = self.setupPath + '/apache/version.pl'
|
|||
|
|
if os.path.exists(filename): httpdVersion = public.readFile(filename).strip()
|
|||
|
|
|
|||
|
|
if httpdVersion == '2.2': phpVersions = ('00','52','53','54')
|
|||
|
|
if httpdVersion == '2.4':
|
|||
|
|
if '52' in phpVersions: phpVersions.remove('52')
|
|||
|
|
if os.path.exists('/www/server/nginx/sbin/nginx'):
|
|||
|
|
cfile = '/www/server/nginx/conf/enable-php-00.conf'
|
|||
|
|
if not os.path.exists(cfile): public.writeFile(cfile,'')
|
|||
|
|
|
|||
|
|
s_type = getattr(get,'s_type',0)
|
|||
|
|
data = []
|
|||
|
|
for val in phpVersions:
|
|||
|
|
tmp = {}
|
|||
|
|
checkPath = self.setupPath+'/php/'+val+'/bin/php'
|
|||
|
|
if val in ['00','other']: checkPath = '/etc/init.d/bt'
|
|||
|
|
if httpdVersion == '2.2': checkPath = self.setupPath+'/php/'+val+'/libphp5.so'
|
|||
|
|
if os.path.exists(checkPath):
|
|||
|
|
tmp['version'] = val
|
|||
|
|
tmp['name'] = 'PHP-'+val
|
|||
|
|
if val == '00':
|
|||
|
|
tmp['name'] = public.lang("Static")
|
|||
|
|
|
|||
|
|
if val == 'other':
|
|||
|
|
if s_type:
|
|||
|
|
tmp['name'] = 'Customize'
|
|||
|
|
else:
|
|||
|
|
continue
|
|||
|
|
data.append(tmp)
|
|||
|
|
return data
|
|||
|
|
|
|||
|
|
# 取指定站点的PHP版本
|
|||
|
|
def GetSitePHPVersion(self, get):
|
|||
|
|
try:
|
|||
|
|
siteName = get.siteName
|
|||
|
|
data = {}
|
|||
|
|
data['phpversion'] = public.get_site_php_version(siteName)
|
|||
|
|
conf = public.readFile(self.setupPath + '/panel/vhost/' + public.get_webserver() + '/' + siteName + '.conf')
|
|||
|
|
data['tomcat'] = conf.find('#TOMCAT-START')
|
|||
|
|
data['tomcatversion'] = public.readFile(self.setupPath + '/tomcat/version.pl')
|
|||
|
|
data['nodejsversion'] = public.readFile(self.setupPath + '/node.js/version.pl')
|
|||
|
|
data['php_other'] = ''
|
|||
|
|
if data['phpversion'] == 'other':
|
|||
|
|
other_file = '/www/server/panel/vhost/other_php/{}/enable-php-other.conf'.format(siteName)
|
|||
|
|
if os.path.exists(other_file):
|
|||
|
|
conf = public.readFile(other_file)
|
|||
|
|
data['php_other'] = re.findall(r"fastcgi_pass\s+(.+);",conf)[0]
|
|||
|
|
return data
|
|||
|
|
except:
|
|||
|
|
return public.return_msg_gettext(False, public.lang("Apache2.2 does NOT support MultiPHP!,{}", public.get_error_info()))
|
|||
|
|
|
|||
|
|
def set_site_php_version_multiple(self, get):
|
|||
|
|
'''
|
|||
|
|
@name 批量设置PHP版本
|
|||
|
|
@author zhwen<2020-11-17>
|
|||
|
|
@param sites_id "1,2"
|
|||
|
|
@param version 52...74
|
|||
|
|
'''
|
|||
|
|
sites_id = get.sites_id.split(',')
|
|||
|
|
set_phpv_successfully = []
|
|||
|
|
set_phpv_failed = {}
|
|||
|
|
for site_id in sites_id:
|
|||
|
|
get.id = site_id
|
|||
|
|
get.siteName = public.M('sites').where("id=?", (site_id,)).getField('name')
|
|||
|
|
if not get.siteName:
|
|||
|
|
continue
|
|||
|
|
try:
|
|||
|
|
result = self.SetPHPVersion(get, multiple=1)
|
|||
|
|
if not result['status']:
|
|||
|
|
set_phpv_failed[get.siteName] = result['msg']
|
|||
|
|
continue
|
|||
|
|
set_phpv_successfully.append(get.siteName)
|
|||
|
|
except:
|
|||
|
|
set_phpv_failed[get.siteName] = public.lang("There was an error setting, please try again.")
|
|||
|
|
pass
|
|||
|
|
public.serviceReload()
|
|||
|
|
return {'status': True, 'msg': public.get_msg_gettext('Set up website [{}] PHP version successfully', (','.join(set_phpv_successfully),)),
|
|||
|
|
'error': set_phpv_failed,
|
|||
|
|
'success': set_phpv_successfully}
|
|||
|
|
|
|||
|
|
# 设置指定站点的PHP版本
|
|||
|
|
def SetPHPVersion(self, get, multiple=None):
|
|||
|
|
siteName = get.siteName
|
|||
|
|
version = get.version
|
|||
|
|
if version == 'other' and not public.get_webserver() in ['nginx','tengine']:
|
|||
|
|
return public.return_msg_gettext(False, public.lang("Custom PHP configuration only supports Nginx"))
|
|||
|
|
try:
|
|||
|
|
# nginx
|
|||
|
|
file = self.setupPath + '/panel/vhost/nginx/' + siteName + '.conf'
|
|||
|
|
conf = public.readFile(file)
|
|||
|
|
if conf:
|
|||
|
|
wp00 = "/www/server/nginx/conf/enable-php-00-wpfastcgi.conf"
|
|||
|
|
if not os.path.exists(wp00):
|
|||
|
|
public.writeFile(wp00, '')
|
|||
|
|
other_path = '/www/server/panel/vhost/other_php/{}'.format(siteName)
|
|||
|
|
if not os.path.exists(other_path): os.makedirs(other_path)
|
|||
|
|
other_rep = "{}/enable-php-other.conf".format(other_path)
|
|||
|
|
|
|||
|
|
|
|||
|
|
if version == 'other':
|
|||
|
|
dst = other_rep
|
|||
|
|
get.other = get.other.strip()
|
|||
|
|
|
|||
|
|
if not get.other:
|
|||
|
|
return public.return_msg_gettext(False, public.lang("The PHP connection configuration cannot be empty when customizing the version!"))
|
|||
|
|
|
|||
|
|
if not re.match(r"^(\d+\.\d+\.\d+\.\d+:\d+|unix:[\w/\.-]+)$",get.other):
|
|||
|
|
return public.return_msg_gettext(False, public.lang("The PHP connection configuration format is incorrect, please refer to the example!"))
|
|||
|
|
|
|||
|
|
other_tmp = get.other.split(':')
|
|||
|
|
if other_tmp[0] == 'unix':
|
|||
|
|
if not os.path.exists(other_tmp[1]):
|
|||
|
|
return public.return_msg_gettext(False, public.lang("The specified unix socket [{}] does not exist!", other_tmp[1]))
|
|||
|
|
else:
|
|||
|
|
if not public.check_tcp(other_tmp[0],int(other_tmp[1])):
|
|||
|
|
return public.return_msg_gettext(False, public.lang("Unable to connect to [{}], please check whether the machine can connect to the target server", get.other))
|
|||
|
|
|
|||
|
|
other_conf = r'''location ~ [^/]\.php(/|$)
|
|||
|
|
{{
|
|||
|
|
try_files $uri =404;
|
|||
|
|
fastcgi_pass {};
|
|||
|
|
fastcgi_index index.php;
|
|||
|
|
include fastcgi.conf;
|
|||
|
|
include pathinfo.conf;
|
|||
|
|
}}'''.format(get.other)
|
|||
|
|
public.writeFile(other_rep,other_conf)
|
|||
|
|
conf = conf.replace(other_rep,dst)
|
|||
|
|
rep = r"include\s+enable-php-(\w{2,5})\.conf"
|
|||
|
|
tmp = re.search(rep,conf)
|
|||
|
|
if tmp: conf = conf.replace(tmp.group(),'include ' + dst)
|
|||
|
|
elif re.search(r"enable-php-\d+-wpfastcgi.conf",conf):
|
|||
|
|
dst = 'enable-php-{}-wpfastcgi.conf'.format(version)
|
|||
|
|
conf = conf.replace(other_rep,dst)
|
|||
|
|
rep = r"enable-php-\d+-wpfastcgi.conf"
|
|||
|
|
tmp = re.search(rep, conf)
|
|||
|
|
if tmp:conf = conf.replace(tmp.group(),dst)
|
|||
|
|
else:
|
|||
|
|
dst = 'enable-php-'+version+'.conf'
|
|||
|
|
conf = conf.replace(other_rep,dst)
|
|||
|
|
rep = r"enable-php-(\w{2,5})\.conf"
|
|||
|
|
tmp = re.search(rep,conf)
|
|||
|
|
if tmp: conf = conf.replace(tmp.group(),dst)
|
|||
|
|
public.writeFile(file,conf)
|
|||
|
|
try:
|
|||
|
|
import site_dir_auth
|
|||
|
|
site_dir_auth_module = site_dir_auth.SiteDirAuth()
|
|||
|
|
auth_list = site_dir_auth_module.get_dir_auth(get)
|
|||
|
|
if auth_list:
|
|||
|
|
for i in auth_list[siteName]:
|
|||
|
|
auth_name = i['name']
|
|||
|
|
auth_file = "{setup_path}/panel/vhost/nginx/dir_auth/{site_name}/{auth_name}.conf".format(
|
|||
|
|
setup_path=self.setupPath,site_name=siteName,auth_name = auth_name)
|
|||
|
|
if os.path.exists(auth_file):
|
|||
|
|
site_dir_auth_module.change_dir_auth_file_nginx_phpver(siteName,version,auth_name)
|
|||
|
|
except:
|
|||
|
|
pass
|
|||
|
|
|
|||
|
|
#apache
|
|||
|
|
file = self.setupPath + '/panel/vhost/apache/'+siteName+'.conf'
|
|||
|
|
conf = public.readFile(file)
|
|||
|
|
if conf and version != 'other':
|
|||
|
|
rep = r"(unix:/tmp/php-cgi-(\w{2,5})\.sock\|fcgi://localhost|fcgi://127.0.0.1:\d+)"
|
|||
|
|
tmp = re.search(rep,conf).group()
|
|||
|
|
conf = conf.replace(tmp,public.get_php_proxy(version,'apache'))
|
|||
|
|
public.writeFile(file,conf)
|
|||
|
|
#OLS
|
|||
|
|
if version != 'other':
|
|||
|
|
file = self.setupPath + '/panel/vhost/openlitespeed/detail/'+siteName+'.conf'
|
|||
|
|
conf = public.readFile(file)
|
|||
|
|
if conf:
|
|||
|
|
rep = r'lsphp\d+'
|
|||
|
|
tmp = re.search(rep, conf)
|
|||
|
|
if tmp:
|
|||
|
|
conf = conf.replace(tmp.group(), 'lsphp' + version)
|
|||
|
|
public.writeFile(file, conf)
|
|||
|
|
if not multiple:
|
|||
|
|
public.serviceReload()
|
|||
|
|
public.write_log_gettext("Site manager", 'Successfully changed PHP Version of site [{}] to PHP-{}', (siteName, version))
|
|||
|
|
return public.return_msg_gettext(True, 'Successfully changed PHP Version of site [{}] to PHP-{}', (siteName, version))
|
|||
|
|
except:
|
|||
|
|
return public.get_error_info()
|
|||
|
|
return public.return_msg_gettext(False, public.lang("Setup failed, no enable-php-xx related configuration items were found in the website configuration file!"))
|
|||
|
|
|
|||
|
|
# 是否开启目录防御
|
|||
|
|
def GetDirUserINI(self, get):
|
|||
|
|
path = get.path + self.GetRunPath(get)
|
|||
|
|
if not path: return public.return_msg_gettext(False, public.lang("Requested directory does not exist"))
|
|||
|
|
id = get.id
|
|||
|
|
get.name = public.M('sites').where("id=?", (id,)).getField('name')
|
|||
|
|
data = {}
|
|||
|
|
data['logs'] = self.GetLogsStatus(get)
|
|||
|
|
data['userini'] = False
|
|||
|
|
user_ini_file = path + '/.user.ini'
|
|||
|
|
user_ini_conf = public.readFile(user_ini_file)
|
|||
|
|
if user_ini_conf and "open_basedir" in user_ini_conf:
|
|||
|
|
data['userini'] = True
|
|||
|
|
data['runPath'] = self.GetSiteRunPath(get)
|
|||
|
|
data['pass'] = self.GetHasPwd(get)
|
|||
|
|
return data
|
|||
|
|
|
|||
|
|
# 清除多余user.ini
|
|||
|
|
def DelUserInI(self, path, up=0):
|
|||
|
|
useriniPath = path + '/.user.ini'
|
|||
|
|
if os.path.exists(useriniPath):
|
|||
|
|
public.ExecShell('chattr -i ' + useriniPath)
|
|||
|
|
try:
|
|||
|
|
os.remove(useriniPath)
|
|||
|
|
except:
|
|||
|
|
pass
|
|||
|
|
|
|||
|
|
for p1 in os.listdir(path):
|
|||
|
|
try:
|
|||
|
|
npath = path + '/' + p1
|
|||
|
|
if not os.path.isdir(npath): continue
|
|||
|
|
useriniPath = npath + '/.user.ini'
|
|||
|
|
if os.path.exists(useriniPath):
|
|||
|
|
public.ExecShell('chattr -i ' + useriniPath)
|
|||
|
|
os.remove(useriniPath)
|
|||
|
|
if up < 3: self.DelUserInI(npath, up + 1)
|
|||
|
|
except:
|
|||
|
|
continue
|
|||
|
|
return True
|
|||
|
|
|
|||
|
|
# 设置目录防御
|
|||
|
|
def SetDirUserINI(self, get):
|
|||
|
|
path = get.path
|
|||
|
|
runPath = self.GetRunPath(get)
|
|||
|
|
filename = path + runPath + '/.user.ini'
|
|||
|
|
siteName = public.M('sites').where('path=?', (get.path,)).getField('name')
|
|||
|
|
conf = public.readFile(filename)
|
|||
|
|
try:
|
|||
|
|
self._set_ols_open_basedir(get)
|
|||
|
|
public.ExecShell("chattr -i " + filename)
|
|||
|
|
if conf and "open_basedir" in conf:
|
|||
|
|
rep = "\n*open_basedir.*"
|
|||
|
|
conf = re.sub(rep, "", conf)
|
|||
|
|
if not conf:
|
|||
|
|
os.remove(filename)
|
|||
|
|
else:
|
|||
|
|
public.writeFile(filename, conf)
|
|||
|
|
public.ExecShell("chattr +i " + filename)
|
|||
|
|
public.set_site_open_basedir_nginx(siteName)
|
|||
|
|
return public.return_msg_gettext(True, public.lang("Base directory turned off!"))
|
|||
|
|
|
|||
|
|
if conf and "session.save_path" in conf:
|
|||
|
|
rep = r"session.save_path\s*=\s*(.*)"
|
|||
|
|
s_path = re.search(rep, conf).groups(1)[0]
|
|||
|
|
public.writeFile(filename, conf + '\nopen_basedir={}/:/tmp/:{}'.format(path, s_path))
|
|||
|
|
else:
|
|||
|
|
public.writeFile(filename, 'open_basedir={}/:/tmp/'.format(path))
|
|||
|
|
public.ExecShell("chattr +i " + filename)
|
|||
|
|
public.set_site_open_basedir_nginx(siteName)
|
|||
|
|
public.serviceReload()
|
|||
|
|
return public.return_msg_gettext(True, public.lang("Base directory turned on!"))
|
|||
|
|
except Exception as e:
|
|||
|
|
public.ExecShell("chattr +i " + filename)
|
|||
|
|
return str(e)
|
|||
|
|
|
|||
|
|
def _set_ols_open_basedir(self, get):
|
|||
|
|
# 设置ols
|
|||
|
|
try:
|
|||
|
|
sitename = public.M('sites').where("id=?", (get.id,)).getField('name')
|
|||
|
|
# sitename = path.split('/')[-1]
|
|||
|
|
f = "/www/server/panel/vhost/openlitespeed/detail/{}.conf".format(sitename)
|
|||
|
|
c = public.readFile(f)
|
|||
|
|
if not c: return False
|
|||
|
|
if f:
|
|||
|
|
rep = '\nphp_admin_value\\s*open_basedir.*'
|
|||
|
|
result = re.search(rep, c)
|
|||
|
|
s = 'on'
|
|||
|
|
if not result:
|
|||
|
|
s = 'off'
|
|||
|
|
rep = '\n#php_admin_value\\s*open_basedir.*'
|
|||
|
|
result = re.search(rep, c)
|
|||
|
|
result = result.group()
|
|||
|
|
if s == 'on':
|
|||
|
|
c = re.sub(rep, '\n#' + result[1:], c)
|
|||
|
|
else:
|
|||
|
|
result = result.replace('#', '')
|
|||
|
|
c = re.sub(rep, result, c)
|
|||
|
|
public.writeFile(f, c)
|
|||
|
|
except:
|
|||
|
|
pass
|
|||
|
|
|
|||
|
|
# 读配置
|
|||
|
|
def __read_config(self, path):
|
|||
|
|
if not os.path.exists(path):
|
|||
|
|
public.writeFile(path, '[]')
|
|||
|
|
upBody = public.readFile(path)
|
|||
|
|
if not upBody: upBody = '[]'
|
|||
|
|
return json.loads(upBody)
|
|||
|
|
|
|||
|
|
# 写配置
|
|||
|
|
def __write_config(self, path, data):
|
|||
|
|
return public.writeFile(path, json.dumps(data))
|
|||
|
|
|
|||
|
|
# 取某个站点某条反向代理详情
|
|||
|
|
def GetProxyDetals(self, get):
|
|||
|
|
proxyUrl = self.__read_config(self.__proxyfile)
|
|||
|
|
sitename = get.sitename
|
|||
|
|
proxyname = get.proxyname
|
|||
|
|
for i in proxyUrl:
|
|||
|
|
if i["proxyname"] == proxyname and i["sitename"] == sitename:
|
|||
|
|
return i
|
|||
|
|
|
|||
|
|
# 取某个站点反向代理列表
|
|||
|
|
def GetProxyList(self, get):
|
|||
|
|
n = 0
|
|||
|
|
for w in ["nginx", "apache"]:
|
|||
|
|
conf_path = "%s/panel/vhost/%s/%s.conf" % (self.setupPath, w, get.sitename)
|
|||
|
|
old_conf = ""
|
|||
|
|
if os.path.exists(conf_path):
|
|||
|
|
old_conf = public.readFile(conf_path)
|
|||
|
|
rep = "(#PROXY-START(\n|.)+#PROXY-END)"
|
|||
|
|
url_rep = r"proxy_pass (.*);|ProxyPass\s/\s(.*)|Host\s(.*);"
|
|||
|
|
host_rep = r"Host\s(.*);"
|
|||
|
|
if re.search(rep, old_conf):
|
|||
|
|
# 构造代理配置
|
|||
|
|
if w == "nginx":
|
|||
|
|
get.todomain = str(re.search(host_rep, old_conf).group(1))
|
|||
|
|
get.proxysite = str(re.search(url_rep, old_conf).group(1))
|
|||
|
|
else:
|
|||
|
|
get.todomain = ""
|
|||
|
|
get.proxysite = str(re.search(url_rep, old_conf).group(2))
|
|||
|
|
get.proxyname = public.lang("Old proxy")
|
|||
|
|
get.type = 1
|
|||
|
|
get.proxydir = "/"
|
|||
|
|
get.advanced = 0
|
|||
|
|
get.cachetime = 1
|
|||
|
|
get.cache = 0
|
|||
|
|
get.subfilter = "[{\"sub1\":\"\",\"sub2\":\"\"},{\"sub1\":\"\",\"sub2\":\"\"},{\"sub1\":\"\",\"sub2\":\"\"}]"
|
|||
|
|
|
|||
|
|
# proxyname_md5 = self.__calc_md5(get.proxyname)
|
|||
|
|
# 备份并替换老虚拟主机配置文件
|
|||
|
|
public.ExecShell("cp %s %s_bak" % (conf_path, conf_path))
|
|||
|
|
conf = re.sub(rep, "", old_conf)
|
|||
|
|
public.writeFile(conf_path, conf)
|
|||
|
|
if n == 0:
|
|||
|
|
self.CreateProxy(get)
|
|||
|
|
n += 1
|
|||
|
|
# 写入代理配置
|
|||
|
|
# proxypath = "%s/panel/vhost/%s/proxy/%s/%s_%s.conf" % (
|
|||
|
|
# self.setupPath, w, get.sitename, proxyname_md5, get.sitename)
|
|||
|
|
# proxycontent = str(re.search(rep, old_conf).group(1))
|
|||
|
|
# public.writeFile(proxypath, proxycontent)
|
|||
|
|
if n == "1":
|
|||
|
|
public.serviceReload()
|
|||
|
|
proxyUrl = self.__read_config(self.__proxyfile)
|
|||
|
|
sitename = get.sitename
|
|||
|
|
proxylist = []
|
|||
|
|
for i in proxyUrl:
|
|||
|
|
if i["sitename"] == sitename:
|
|||
|
|
proxylist.append(i)
|
|||
|
|
return proxylist
|
|||
|
|
|
|||
|
|
def del_proxy_multiple(self, get):
|
|||
|
|
'''
|
|||
|
|
@name 批量网站到期时间
|
|||
|
|
@author zhwen<2020-11-20>
|
|||
|
|
@param site_id 1
|
|||
|
|
@param proxynames ces,aaa
|
|||
|
|
'''
|
|||
|
|
proxynames = get.proxynames.split(',')
|
|||
|
|
del_successfully = []
|
|||
|
|
del_failed = {}
|
|||
|
|
get.sitename = public.M('sites').where("id=?", (get.site_id,)).getField('name')
|
|||
|
|
for proxyname in proxynames:
|
|||
|
|
if not proxyname:
|
|||
|
|
continue
|
|||
|
|
get.proxyname = proxyname
|
|||
|
|
try:
|
|||
|
|
resule = self.RemoveProxy(get, multiple=1)
|
|||
|
|
if not resule['status']:
|
|||
|
|
del_failed[proxyname] = resule['msg']
|
|||
|
|
del_successfully.append(proxyname)
|
|||
|
|
except:
|
|||
|
|
del_failed[proxyname] = public.lang("There was an error deleting, please try again.")
|
|||
|
|
pass
|
|||
|
|
return {'status': True, 'msg': public.get_msg_gettext('Delete [ {} ] proxy successfully', (','.join(del_failed),)),
|
|||
|
|
'error': del_failed,
|
|||
|
|
'success': del_successfully}
|
|||
|
|
|
|||
|
|
# 删除反向代理
|
|||
|
|
def RemoveProxy(self, get, multiple=None):
|
|||
|
|
conf = self.__read_config(self.__proxyfile)
|
|||
|
|
sitename = get.sitename
|
|||
|
|
proxyname = get.proxyname
|
|||
|
|
for i in range(len(conf)):
|
|||
|
|
c_sitename = conf[i]["sitename"]
|
|||
|
|
c_proxyname = conf[i]["proxyname"]
|
|||
|
|
if c_sitename == sitename and c_proxyname == proxyname:
|
|||
|
|
proxyname_md5 = self.__calc_md5(c_proxyname)
|
|||
|
|
for w in ["apache", "nginx", "openlitespeed"]:
|
|||
|
|
p = "{sp}/panel/vhost/{w}/proxy/{s}/{m}_{s}.conf*".format(sp=self.setupPath, w=w, s=c_sitename,
|
|||
|
|
m=proxyname_md5)
|
|||
|
|
|
|||
|
|
public.ExecShell('rm -f {}'.format(p))
|
|||
|
|
p = "{sp}/panel/vhost/openlitespeed/proxy/{s}/urlrewrite/{m}_{s}.conf*".format(sp=self.setupPath,
|
|||
|
|
m=proxyname_md5,
|
|||
|
|
s=get.sitename)
|
|||
|
|
public.ExecShell('rm -f {}'.format(p))
|
|||
|
|
del conf[i]
|
|||
|
|
self.__write_config(self.__proxyfile, conf)
|
|||
|
|
self.SetNginx(get)
|
|||
|
|
self.SetApache(get.sitename)
|
|||
|
|
if not multiple:
|
|||
|
|
public.serviceReload()
|
|||
|
|
return public.return_msg_gettext(True, public.lang("Successfully deleted"))
|
|||
|
|
|
|||
|
|
# 检查代理是否存在
|
|||
|
|
def __check_even(self, get, action=""):
|
|||
|
|
conf_data = self.__read_config(self.__proxyfile)
|
|||
|
|
for i in conf_data:
|
|||
|
|
if i["sitename"] == get.sitename:
|
|||
|
|
if action == "create":
|
|||
|
|
if i["proxydir"] == get.proxydir or i["proxyname"] == get.proxyname:
|
|||
|
|
return i
|
|||
|
|
else:
|
|||
|
|
if i["proxyname"] != get.proxyname and i["proxydir"] == get.proxydir:
|
|||
|
|
return i
|
|||
|
|
|
|||
|
|
# 检测全局代理和目录代理是否同时存在
|
|||
|
|
def __check_proxy_even(self, get, action=""):
|
|||
|
|
conf_data = self.__read_config(self.__proxyfile)
|
|||
|
|
n = 0
|
|||
|
|
if action == "":
|
|||
|
|
for i in conf_data:
|
|||
|
|
if i["sitename"] == get.sitename:
|
|||
|
|
n += 1
|
|||
|
|
if n == 1:
|
|||
|
|
return
|
|||
|
|
for i in conf_data:
|
|||
|
|
if i["sitename"] == get.sitename:
|
|||
|
|
if i["advanced"] != int(get.advanced):
|
|||
|
|
return i
|
|||
|
|
# 计算proxyname md5
|
|||
|
|
def __calc_md5(self, proxyname):
|
|||
|
|
md5 = hashlib.md5()
|
|||
|
|
md5.update(proxyname.encode('utf-8'))
|
|||
|
|
return md5.hexdigest()
|
|||
|
|
|
|||
|
|
# 检测URL是否可以访问
|
|||
|
|
def __CheckUrl(self, get):
|
|||
|
|
sk = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|||
|
|
sk.settimeout(5)
|
|||
|
|
rep = r"(https?)://([\w\.\-]+):?([\d]+)?"
|
|||
|
|
h = re.search(rep, get.proxysite).group(1)
|
|||
|
|
d = re.search(rep, get.proxysite).group(2)
|
|||
|
|
try:
|
|||
|
|
p = re.search(rep, get.proxysite).group(3)
|
|||
|
|
except:
|
|||
|
|
p = ""
|
|||
|
|
try:
|
|||
|
|
if p:
|
|||
|
|
sk.connect((d, int(p)))
|
|||
|
|
else:
|
|||
|
|
if h == "http":
|
|||
|
|
sk.connect((d, 80))
|
|||
|
|
else:
|
|||
|
|
sk.connect((d, 443))
|
|||
|
|
except:
|
|||
|
|
return public.return_msg_gettext(False, public.lang("Can NOT get target URL"))
|
|||
|
|
|
|||
|
|
# 基本设置检查
|
|||
|
|
def __CheckStart(self, get, action=""):
|
|||
|
|
isError = public.checkWebConfig()
|
|||
|
|
if isinstance(isError,str):
|
|||
|
|
if isError.find('/proxy/') == -1: # 如果是反向代理配置文件本身的错误,跳过
|
|||
|
|
return public.return_msg_gettext(False, public.lang("An error was detected in the configuration file. Please solve it before proceeding"))
|
|||
|
|
if action == "create":
|
|||
|
|
if sys.version_info.major < 3:
|
|||
|
|
if len(get.proxyname) < 3 or len(get.proxyname) > 40:
|
|||
|
|
return public.return_msg_gettext(False, public.lang("Database name cannot be more than 40 characters!"))
|
|||
|
|
else:
|
|||
|
|
if len(get.proxyname.encode("utf-8")) < 3 or len(get.proxyname.encode("utf-8")) > 40:
|
|||
|
|
return public.return_msg_gettext(False, public.lang("Database name cannot be more than 40 characters!"))
|
|||
|
|
if self.__check_even(get, action):
|
|||
|
|
return public.return_msg_gettext(False, public.lang("Specified reverse proxy name or proxy folder already exists"))
|
|||
|
|
# 判断代理,只能有全局代理或目录代理
|
|||
|
|
if self.__check_proxy_even(get, action):
|
|||
|
|
return public.return_msg_gettext(False, public.lang("Cannot set both directory and global proxies"))
|
|||
|
|
# 判断cachetime类型
|
|||
|
|
if get.cachetime:
|
|||
|
|
try:
|
|||
|
|
int(get.cachetime)
|
|||
|
|
except:
|
|||
|
|
return public.return_msg_gettext(False, public.lang("Please enter number"))
|
|||
|
|
|
|||
|
|
rep = r"http(s)?\:\/\/"
|
|||
|
|
# repd = r"http(s)?\:\/\/([a-zA-Z0-9][-a-zA-Z0-9]{0,62}\.)+([a-zA-Z0-9][a-zA-Z0-9]{0,62})+.?"
|
|||
|
|
tod = "[a-zA-Z]+$"
|
|||
|
|
repte = "[\\?\\=\\[\\]\\)\\(\\*\\&\\^\\%\\$\\#\\@\\!\\~\\`{\\}\\>\\<\\,\',\"]+"
|
|||
|
|
# 检测代理目录格式
|
|||
|
|
if re.search(repte, get.proxydir):
|
|||
|
|
return public.return_msg_gettext(False, "PROXY_DIR_ERR", ("?,=,[,],),(,*,&,^,%,$,#,@,!,~,`,{,},>,<,\\,',\"]",))
|
|||
|
|
# 检测发送域名格式
|
|||
|
|
if get.todomain:
|
|||
|
|
if re.search("[\\}\\{\\#\\;\"\']+",get.todomain):
|
|||
|
|
return public.return_msg_gettext(False, public.lang("Sent Domain format error :'+get.todomain+'<br>The following special characters cannot exist [ } { # ; \" \' ] "))
|
|||
|
|
if public.get_webserver() != 'openlitespeed' and not get.todomain:
|
|||
|
|
get.todomain = "$host"
|
|||
|
|
|
|||
|
|
# 检测目标URL格式
|
|||
|
|
if not re.match(rep, get.proxysite):
|
|||
|
|
return public.return_msg_gettext(False, 'Sent domain format ERROR {}', (get.proxysite,))
|
|||
|
|
if re.search(repte, get.proxysite):
|
|||
|
|
return public.return_msg_gettext(False, "PROXY_URL_ERR", ("?,=,[,],),(,*,&,^,%,$,#,@,!,~,`,{,},>,<,\\,',\"]",))
|
|||
|
|
# 检测目标url是否可用
|
|||
|
|
# if re.match(repd, get.proxysite):
|
|||
|
|
# if self.__CheckUrl(get):
|
|||
|
|
# return public.returnMsg(False, public.lang("The target URL cannot be accessed"))
|
|||
|
|
subfilter = json.loads(get.subfilter)
|
|||
|
|
# 检测替换内容
|
|||
|
|
if subfilter:
|
|||
|
|
for s in subfilter:
|
|||
|
|
if not s["sub1"]:
|
|||
|
|
if s["sub2"]:
|
|||
|
|
return public.return_msg_gettext(False, public.lang("Please enter the content to be replaced"))
|
|||
|
|
elif s["sub1"] == s["sub2"]:
|
|||
|
|
return public.return_msg_gettext(False, public.lang("The content to replace cannot be the same as the content to be replaced"))
|
|||
|
|
|
|||
|
|
# 设置Nginx配置
|
|||
|
|
def SetNginx(self, get):
|
|||
|
|
ng_proxyfile = "%s/panel/vhost/nginx/proxy/%s/*.conf" % (self.setupPath, get.sitename)
|
|||
|
|
ng_file = self.setupPath + "/panel/vhost/nginx/" + get.sitename + ".conf"
|
|||
|
|
p_conf = self.__read_config(self.__proxyfile)
|
|||
|
|
cureCache = ''
|
|||
|
|
|
|||
|
|
if public.get_webserver() == 'nginx':
|
|||
|
|
shutil.copyfile(ng_file, '/tmp/ng_file_bk.conf')
|
|||
|
|
|
|||
|
|
# if os.path.exists('/www/server/nginx/src/ngx_cache_purge'):
|
|||
|
|
cureCache += '''
|
|||
|
|
location ~ /purge(/.*) {
|
|||
|
|
proxy_cache_purge cache_one $host$1$is_args$args;
|
|||
|
|
#access_log /www/wwwlogs/%s_purge_cache.log;
|
|||
|
|
}''' % (get.sitename)
|
|||
|
|
if os.path.exists(ng_file):
|
|||
|
|
self.CheckProxy(get)
|
|||
|
|
ng_conf = public.readFile(ng_file)
|
|||
|
|
if not p_conf:
|
|||
|
|
# rep = "%s[\\w\\s\\~\\/\\(\\)\\.\\*\\{\\}\\;\\$\n\\#]+.{1,66}[\\s\\w\\/\\*\\.\\;]+include enable-php-" % public.GetMsg(
|
|||
|
|
# "CLEAR_CACHE")
|
|||
|
|
rep = "%s[\\w\\s\\~\\/\\(\\)\\.\\*\\{\\}\\;\\$\n\\#]+.*\n.*" % ("#Clear cache")
|
|||
|
|
# ng_conf = re.sub(rep, 'include enable-php-', ng_conf)
|
|||
|
|
ng_conf = re.sub(rep, '', ng_conf)
|
|||
|
|
oldconf = '''location ~ .*\\.(gif|jpg|jpeg|png|bmp|swf)$
|
|||
|
|
{
|
|||
|
|
expires 30d;
|
|||
|
|
error_log /dev/null;
|
|||
|
|
access_log /dev/null;
|
|||
|
|
}
|
|||
|
|
location ~ .*\\.(js|css)?$
|
|||
|
|
{
|
|||
|
|
expires 12h;
|
|||
|
|
error_log /dev/null;
|
|||
|
|
access_log /dev/null;
|
|||
|
|
}'''
|
|||
|
|
if "(gif|jpg|jpeg|png|bmp|swf)$" not in ng_conf:
|
|||
|
|
ng_conf = re.sub(r'access_log\s*/www', oldconf + "\n\taccess_log /www",ng_conf)
|
|||
|
|
public.writeFile(ng_file, ng_conf)
|
|||
|
|
return
|
|||
|
|
sitenamelist = []
|
|||
|
|
for i in p_conf:
|
|||
|
|
sitenamelist.append(i["sitename"])
|
|||
|
|
|
|||
|
|
if get.sitename in sitenamelist:
|
|||
|
|
rep = r"include.*\/proxy\/.*\*.conf;"
|
|||
|
|
if not re.search(rep, ng_conf):
|
|||
|
|
rep = "location.+\\(gif[\\w\\|\\$\\(\\)\n\\{\\}\\s\\;\\/\\~\\.\\*\\\\\\?]+access_log\\s+/"
|
|||
|
|
ng_conf = re.sub(rep, 'access_log /', ng_conf)
|
|||
|
|
ng_conf = ng_conf.replace("include enable-php-", "%s\n" % public.get_msg_gettext(
|
|||
|
|
"#Clear cache") + cureCache + "\n\t%s\n\t" % public.get_msg_gettext(
|
|||
|
|
"#Referenced reverse proxy rule, if commented, the configured reverse proxy will be invalid") + "include " + ng_proxyfile + ";\n\n\tinclude enable-php-")
|
|||
|
|
public.writeFile(ng_file, ng_conf)
|
|||
|
|
|
|||
|
|
else:
|
|||
|
|
# rep = "%s[\\w\\s\\~\\/\\(\\)\\.\\*\\{\\}\\;\\$\n\\#]+.{1,66}[\\s\\w\\/\\*\\.\\;]+include enable-php-" % public.GetMsg(
|
|||
|
|
# "CLEAR_CACHE")
|
|||
|
|
rep = "%s[\\w\\s\\~\\/\\(\\)\\.\\*\\{\\}\\;\\$\n\\#]+.*\n.*" % ("#Clear cache")
|
|||
|
|
# ng_conf = re.sub(rep, 'include enable-php-', ng_conf)
|
|||
|
|
ng_conf = re.sub(rep,'',ng_conf)
|
|||
|
|
oldconf = '''location ~ .*\\.(gif|jpg|jpeg|png|bmp|swf)$
|
|||
|
|
{
|
|||
|
|
expires 30d;
|
|||
|
|
error_log /dev/null;
|
|||
|
|
access_log /dev/null;
|
|||
|
|
}
|
|||
|
|
location ~ .*\\.(js|css)?$
|
|||
|
|
{
|
|||
|
|
expires 12h;
|
|||
|
|
error_log /dev/null;
|
|||
|
|
access_log /dev/null;
|
|||
|
|
}'''
|
|||
|
|
if "(gif|jpg|jpeg|png|bmp|swf)$" not in ng_conf:
|
|||
|
|
ng_conf = re.sub(r'access_log\s*/www', oldconf + "\n\taccess_log /www",ng_conf)
|
|||
|
|
public.writeFile(ng_file, ng_conf)
|
|||
|
|
|
|||
|
|
# 设置apache配置
|
|||
|
|
def SetApache(self, sitename):
|
|||
|
|
ap_proxyfile = "%s/panel/vhost/apache/proxy/%s/*.conf" % (self.setupPath, sitename)
|
|||
|
|
ap_file = self.setupPath + "/panel/vhost/apache/" + sitename + ".conf"
|
|||
|
|
p_conf = public.readFile(self.__proxyfile)
|
|||
|
|
|
|||
|
|
if public.get_webserver() == 'apache':
|
|||
|
|
shutil.copyfile(ap_file, '/tmp/ap_file_bk.conf')
|
|||
|
|
|
|||
|
|
if os.path.exists(ap_file):
|
|||
|
|
ap_conf = public.readFile(ap_file)
|
|||
|
|
if p_conf == "[]":
|
|||
|
|
rep = "\n*%s\n+\\s+IncludeOptiona[\\s\\w\\/\\.\\*]+" % ("#Referenced reverse proxy rule, if commented, the configured reverse proxy will be invalid")
|
|||
|
|
ap_conf = re.sub(rep, '', ap_conf)
|
|||
|
|
public.writeFile(ap_file, ap_conf)
|
|||
|
|
return
|
|||
|
|
if sitename in p_conf:
|
|||
|
|
rep = "combined(\n|.)+IncludeOptional.*\\/proxy\\/.*conf"
|
|||
|
|
rep1 = "combined"
|
|||
|
|
if not re.search(rep, ap_conf):
|
|||
|
|
ap_conf = ap_conf.replace(rep1, rep1 + "\n\t%s\n\t" % public.get_msg_gettext(
|
|||
|
|
'#Referenced reverse proxy rule, if commented, the configured reverse proxy will be invalid') + "\n\tIncludeOptional " + ap_proxyfile)
|
|||
|
|
public.writeFile(ap_file, ap_conf)
|
|||
|
|
else:
|
|||
|
|
# rep = "\n*#引用反向代理(\n|.)+IncludeOptional.*\\/proxy\\/.*conf"
|
|||
|
|
rep = "\n*%s\n+\\s+IncludeOptiona[\\s\\w\\/\\.\\*]+" % ("#Referenced reverse proxy rule, if commented, the configured reverse proxy will be invalid")
|
|||
|
|
ap_conf = re.sub(rep, '', ap_conf)
|
|||
|
|
public.writeFile(ap_file, ap_conf)
|
|||
|
|
|
|||
|
|
# 设置OLS
|
|||
|
|
def _set_ols_proxy(self, get):
|
|||
|
|
# 添加反代配置
|
|||
|
|
proxyname_md5 = self.__calc_md5(get.proxyname)
|
|||
|
|
dir_path = "%s/panel/vhost/openlitespeed/proxy/%s/" % (self.setupPath, get.sitename)
|
|||
|
|
if not os.path.exists(dir_path):
|
|||
|
|
os.makedirs(dir_path)
|
|||
|
|
file_path = "{}{}_{}.conf".format(dir_path, proxyname_md5, get.sitename)
|
|||
|
|
reverse_proxy_conf = """
|
|||
|
|
extprocessor %s {
|
|||
|
|
type proxy
|
|||
|
|
address %s
|
|||
|
|
maxConns 1000
|
|||
|
|
pcKeepAliveTimeout 600
|
|||
|
|
initTimeout 600
|
|||
|
|
retryTimeout 0
|
|||
|
|
respBuffer 0
|
|||
|
|
}
|
|||
|
|
""" % (get.proxyname, get.proxysite)
|
|||
|
|
public.writeFile(file_path, reverse_proxy_conf)
|
|||
|
|
# 添加urlrewrite
|
|||
|
|
dir_path = "%s/panel/vhost/openlitespeed/proxy/%s/urlrewrite/" % (self.setupPath, get.sitename)
|
|||
|
|
if not os.path.exists(dir_path):
|
|||
|
|
os.makedirs(dir_path)
|
|||
|
|
file_path = "{}{}_{}.conf".format(dir_path, proxyname_md5, get.sitename)
|
|||
|
|
reverse_urlrewrite_conf = """
|
|||
|
|
RewriteRule ^%s(.*)$ http://%s/$1 [P,E=Proxy-Host:%s]
|
|||
|
|
""" % (get.proxydir, get.proxyname, get.todomain)
|
|||
|
|
public.writeFile(file_path, reverse_urlrewrite_conf)
|
|||
|
|
|
|||
|
|
# 检查伪静态、主配置文件是否有location冲突
|
|||
|
|
def CheckLocation(self, get):
|
|||
|
|
# 伪静态文件路径
|
|||
|
|
rewriteconfpath = "%s/panel/vhost/rewrite/%s.conf" % (self.setupPath, get.sitename)
|
|||
|
|
# 主配置文件路径
|
|||
|
|
nginxconfpath = "%s/nginx/conf/nginx.conf" % (self.setupPath)
|
|||
|
|
# vhost文件
|
|||
|
|
vhostpath = "%s/panel/vhost/nginx/%s.conf" % (self.setupPath, get.sitename)
|
|||
|
|
|
|||
|
|
rep = "location\\s+/[\n\\s]+{"
|
|||
|
|
|
|||
|
|
for i in [rewriteconfpath, nginxconfpath, vhostpath]:
|
|||
|
|
conf = public.readFile(i)
|
|||
|
|
if re.findall(rep, conf):
|
|||
|
|
return public.return_msg_gettext(False, public.lang("A global reverse proxy already exists in the rewrite/nginx master configuration/vhost file"))
|
|||
|
|
|
|||
|
|
# 创建反向代理
|
|||
|
|
def CreateProxy(self, get):
|
|||
|
|
try:
|
|||
|
|
nocheck = get.nocheck
|
|||
|
|
except:
|
|||
|
|
nocheck = ""
|
|||
|
|
if not get.get('proxysite',None):
|
|||
|
|
return public.returnMsg(False, public.lang("Destination URL cannot be empty"))
|
|||
|
|
if not nocheck:
|
|||
|
|
if self.__CheckStart(get, "create"):
|
|||
|
|
return self.__CheckStart(get, "create")
|
|||
|
|
if public.get_webserver() == 'nginx':
|
|||
|
|
if self.CheckLocation(get):
|
|||
|
|
return self.CheckLocation(get)
|
|||
|
|
if not get.proxysite.split('//')[-1]:
|
|||
|
|
return public.returnMsg(False, public.lang("The target URL cannot be [http:// or https://], please fill in the full URL, such as: https://yakpanel.com"))
|
|||
|
|
# project_type = public.M('sites').where('name=?', (get.sitename,)).field('project_type').find()['project_type']
|
|||
|
|
# if project_type == 'WP':
|
|||
|
|
# return public.return_msg_gettext(False, public.lang("Reverse proxies are not currently available for Wordpress sites that use one-click deployment"))
|
|||
|
|
proxyUrl = self.__read_config(self.__proxyfile)
|
|||
|
|
proxyUrl.append({
|
|||
|
|
"proxyname": get.proxyname,
|
|||
|
|
"sitename": get.sitename,
|
|||
|
|
"proxydir": get.proxydir,
|
|||
|
|
"proxysite": get.proxysite,
|
|||
|
|
"todomain": get.todomain,
|
|||
|
|
"type": int(get.type),
|
|||
|
|
"cache": int(get.cache),
|
|||
|
|
"subfilter": json.loads(get.subfilter),
|
|||
|
|
"advanced": int(get.advanced),
|
|||
|
|
"cachetime": int(get.cachetime)
|
|||
|
|
})
|
|||
|
|
self.__write_config(self.__proxyfile, proxyUrl)
|
|||
|
|
self.SetNginx(get)
|
|||
|
|
self.SetApache(get.sitename)
|
|||
|
|
self._set_ols_proxy(get)
|
|||
|
|
status = self.SetProxy(get)
|
|||
|
|
if not status["status"]:
|
|||
|
|
return status
|
|||
|
|
if get.proxydir == '/':
|
|||
|
|
get.version = '00'
|
|||
|
|
get.siteName = get.sitename
|
|||
|
|
self.SetPHPVersion(get)
|
|||
|
|
public.serviceReload()
|
|||
|
|
return public.return_msg_gettext(True, public.lang("Setup successfully!"))
|
|||
|
|
|
|||
|
|
# 取代理配置文件
|
|||
|
|
def GetProxyFile(self, get):
|
|||
|
|
import files
|
|||
|
|
conf = self.__read_config(self.__proxyfile)
|
|||
|
|
sitename = get.sitename
|
|||
|
|
proxyname = get.proxyname
|
|||
|
|
proxyname_md5 = self.__calc_md5(proxyname)
|
|||
|
|
get.path = "%s/panel/vhost/%s/proxy/%s/%s_%s.conf" % (
|
|||
|
|
self.setupPath, get.webserver, sitename, proxyname_md5, sitename)
|
|||
|
|
for i in conf:
|
|||
|
|
if proxyname == i["proxyname"] and sitename == i["sitename"] and i["type"] != 1:
|
|||
|
|
return public.return_msg_gettext(False, public.lang("Proxy suspended"))
|
|||
|
|
f = files.files()
|
|||
|
|
return f.GetFileBody(get), get.path
|
|||
|
|
|
|||
|
|
# 保存代理配置文件
|
|||
|
|
def SaveProxyFile(self, get):
|
|||
|
|
import files
|
|||
|
|
f = files.files()
|
|||
|
|
return f.SaveFileBody(get)
|
|||
|
|
# return public.returnMsg(True, public.lang("Saved successfully"))
|
|||
|
|
|
|||
|
|
# 检查是否存在#Set Nginx Cache
|
|||
|
|
def check_annotate(self, data):
|
|||
|
|
rep = "\n\\s*#Set\\s*Nginx\\s*Cache"
|
|||
|
|
if re.search(rep, data):
|
|||
|
|
return True
|
|||
|
|
|
|||
|
|
def old_proxy_conf(self,conf,ng_conf_file,get):
|
|||
|
|
rep = r'location\s*\~\*.*gif\|png\|jpg\|css\|js\|woff\|woff2\)\$'
|
|||
|
|
if not re.search(rep,conf):
|
|||
|
|
return conf
|
|||
|
|
|
|||
|
|
self.RemoveProxy(get)
|
|||
|
|
self.CreateProxy(get)
|
|||
|
|
return public.readFile(ng_conf_file)
|
|||
|
|
|
|||
|
|
# 修改反向代理
|
|||
|
|
def ModifyProxy(self, get):
|
|||
|
|
if not get.get('proxysite',None):
|
|||
|
|
return public.returnMsg(False, public.lang("Destination URL cannot be empty"))
|
|||
|
|
proxyname_md5 = self.__calc_md5(get.proxyname)
|
|||
|
|
ap_conf_file = "{p}/panel/vhost/apache/proxy/{s}/{n}_{s}.conf".format(
|
|||
|
|
p=self.setupPath, s=get.sitename, n=proxyname_md5)
|
|||
|
|
ng_conf_file = "{p}/panel/vhost/nginx/proxy/{s}/{n}_{s}.conf".format(
|
|||
|
|
p=self.setupPath, s=get.sitename, n=proxyname_md5)
|
|||
|
|
ols_conf_file = "{p}/panel/vhost/openlitespeed/proxy/{s}/urlrewrite/{n}_{s}.conf".format(
|
|||
|
|
p=self.setupPath, s=get.sitename, n=proxyname_md5)
|
|||
|
|
if self.__CheckStart(get):
|
|||
|
|
return self.__CheckStart(get)
|
|||
|
|
conf = self.__read_config(self.__proxyfile)
|
|||
|
|
random_string = public.GetRandomString(8)
|
|||
|
|
for i in range(len(conf)):
|
|||
|
|
if conf[i]["proxyname"] == get.proxyname and conf[i]["sitename"] == get.sitename:
|
|||
|
|
if int(get.type) != 1:
|
|||
|
|
if not os.path.exists(ng_conf_file):
|
|||
|
|
return public.returnMsg(False, public.lang("Please enable the reverse proxy before editing!"))
|
|||
|
|
public.ExecShell("mv {f} {f}_bak".format(f=ap_conf_file))
|
|||
|
|
public.ExecShell("mv {f} {f}_bak".format(f=ng_conf_file))
|
|||
|
|
public.ExecShell("mv {f} {f}_bak".format(f=ols_conf_file))
|
|||
|
|
conf[i]["type"] = int(get.type)
|
|||
|
|
self.__write_config(self.__proxyfile, conf)
|
|||
|
|
public.serviceReload()
|
|||
|
|
return public.return_msg_gettext(True, public.lang("Setup successfully!"))
|
|||
|
|
else:
|
|||
|
|
if os.path.exists(ap_conf_file + "_bak"):
|
|||
|
|
public.ExecShell("mv {f}_bak {f}".format(f=ap_conf_file))
|
|||
|
|
public.ExecShell("mv {f}_bak {f}".format(f=ng_conf_file))
|
|||
|
|
public.ExecShell("mv {f}_bak {f}".format(f=ols_conf_file))
|
|||
|
|
ng_conf = public.readFile(ng_conf_file)
|
|||
|
|
ng_conf = self.old_proxy_conf(ng_conf, ng_conf_file, get)
|
|||
|
|
# 修改nginx配置
|
|||
|
|
# 如果代理URL后缀带有URI则删除URI,正则匹配不支持proxypass处带有uri
|
|||
|
|
php_pass_proxy = get.proxysite
|
|||
|
|
if get.proxysite[-1] == '/' or get.proxysite.count('/') > 2 or '?' in get.proxysite:
|
|||
|
|
php_pass_proxy = re.search(r'(https?\:\/\/[\w\.]+)', get.proxysite).group(0)
|
|||
|
|
ng_conf = re.sub(r"location\s+[\^\~]*\s?%s" % conf[i]["proxydir"], "location ^~ " + get.proxydir, ng_conf)
|
|||
|
|
ng_conf = re.sub(r"proxy_pass\s+%s" % conf[i]["proxysite"], "proxy_pass " + get.proxysite, ng_conf)
|
|||
|
|
ng_conf = re.sub("location\\s+\\~\\*\\s+\\\\.\\(php.*\n\\{\\s*proxy_pass\\s+%s.*" % (php_pass_proxy),
|
|||
|
|
"location ~* \\.(php|jsp|cgi|asp|aspx)$\n{\n\tproxy_pass %s;" % php_pass_proxy,ng_conf)
|
|||
|
|
ng_conf = re.sub("location\\s+\\~\\*\\s+\\\\.\\(gif.*\n\\{\\s*proxy_pass\\s+%s.*" % (php_pass_proxy),
|
|||
|
|
"location ~* \\.(gif|png|jpg|css|js|woff|woff2)$\n{\n\tproxy_pass %s;" % php_pass_proxy,ng_conf)
|
|||
|
|
|
|||
|
|
backslash = ""
|
|||
|
|
if "Host $host" in ng_conf:
|
|||
|
|
backslash = "\\"
|
|||
|
|
|
|||
|
|
ng_conf = re.sub(r"\sHost\s+%s" % backslash + conf[i]["todomain"], " Host " + get.todomain, ng_conf)
|
|||
|
|
cache_rep = r"proxy_cache_valid\s+200\s+304\s+301\s+302\s+\d+m;((\n|.)+expires\s+\d+m;)*"
|
|||
|
|
if int(get.cache) == 1:
|
|||
|
|
if re.search(cache_rep, ng_conf):
|
|||
|
|
expires_rep = "\\{\n\\s+expires\\s+12h;"
|
|||
|
|
ng_conf = re.sub(expires_rep, "{", ng_conf)
|
|||
|
|
ng_conf = re.sub(cache_rep, "proxy_cache_valid 200 304 301 302 {0}m;".format(get.cachetime),
|
|||
|
|
ng_conf)
|
|||
|
|
else:
|
|||
|
|
# ng_cache = """
|
|||
|
|
# proxy_ignore_headers Set-Cookie Cache-Control expires;
|
|||
|
|
# proxy_cache cache_one;
|
|||
|
|
# proxy_cache_key $host$uri$is_args$args;
|
|||
|
|
# proxy_cache_valid 200 304 301 302 %sm;""" % (get.cachetime)
|
|||
|
|
ng_cache = r"""
|
|||
|
|
if ( $uri ~* "\.(gif|png|jpg|css|js|woff|woff2)$" )
|
|||
|
|
{
|
|||
|
|
expires 1m;
|
|||
|
|
}
|
|||
|
|
proxy_ignore_headers Set-Cookie Cache-Control expires;
|
|||
|
|
proxy_cache cache_one;
|
|||
|
|
proxy_cache_key $host$uri$is_args$args;
|
|||
|
|
proxy_cache_valid 200 304 301 302 %sm;""" % (get.cachetime)
|
|||
|
|
if self.check_annotate(ng_conf):
|
|||
|
|
cache_rep = '\n\\s*#Set\\s*Nginx\\s*Cache(.|\n)*no-cache;\\s*\n*\\s*\\}'
|
|||
|
|
ng_conf = re.sub(cache_rep, '\n\t#Set Nginx Cache\n' + ng_cache, ng_conf)
|
|||
|
|
else:
|
|||
|
|
# cache_rep = r'#proxy_set_header\s+Connection\s+"upgrade";'
|
|||
|
|
cache_rep = r"proxy_set_header\s+REMOTE-HOST\s+\$remote_addr;"
|
|||
|
|
ng_conf = re.sub(cache_rep,
|
|||
|
|
r"\n\tproxy_set_header\s+REMOTE-HOST\s+\$remote_addr;\n\t#Set Nginx Cache" + ng_cache,
|
|||
|
|
ng_conf)
|
|||
|
|
else:
|
|||
|
|
no_cache = r"""
|
|||
|
|
#Set Nginx Cache
|
|||
|
|
set $static_file%s 0;
|
|||
|
|
if ( $uri ~* "\.(gif|png|jpg|css|js|woff|woff2)$" )
|
|||
|
|
{
|
|||
|
|
set $static_file%s 1;
|
|||
|
|
expires 1m;
|
|||
|
|
}
|
|||
|
|
if ( $static_file%s = 0 )
|
|||
|
|
{
|
|||
|
|
add_header Cache-Control no-cache;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
#PROXY-END/""" % (random_string, random_string, random_string)
|
|||
|
|
if self.check_annotate(ng_conf):
|
|||
|
|
rep = r'\n\s*#Set\s*Nginx\s*Cache(.|\n)*'
|
|||
|
|
# ng_conf = re.sub(rep,
|
|||
|
|
# "\n\t#Set Nginx Cache\n\tproxy_ignore_headers Set-Cookie Cache-Control expires;\n\tadd_header Cache-Control no-cache;",
|
|||
|
|
# ng_conf)
|
|||
|
|
ng_conf = re.sub(rep,no_cache,ng_conf)
|
|||
|
|
else:
|
|||
|
|
rep = r"\s+proxy_cache\s+cache_one.*[\n\s\w\_\";\$]+m;"
|
|||
|
|
# ng_conf = re.sub(rep,
|
|||
|
|
# r"\n\t#Set Nginx Cache\n\tproxy_ignore_headers Set-Cookie Cache-Control expires;\n\tadd_header Cache-Control no-cache;",
|
|||
|
|
# ng_conf)
|
|||
|
|
ng_conf = re.sub(rep,no_cache,ng_conf)
|
|||
|
|
|
|||
|
|
sub_rep = "sub_filter"
|
|||
|
|
subfilter = json.loads(get.subfilter)
|
|||
|
|
if str(conf[i]["subfilter"]) != str(subfilter) or ng_conf.find('sub_filter_once') == -1:
|
|||
|
|
if re.search(sub_rep, ng_conf):
|
|||
|
|
sub_rep = "\\s+proxy_set_header\\s+Accept-Encoding(.|\n)+off;"
|
|||
|
|
ng_conf = re.sub(sub_rep, "", ng_conf)
|
|||
|
|
|
|||
|
|
# 构造替换字符串
|
|||
|
|
ng_subdata = ''
|
|||
|
|
ng_sub_filter = '''
|
|||
|
|
proxy_set_header Accept-Encoding "";%s
|
|||
|
|
sub_filter_once off;'''
|
|||
|
|
if subfilter:
|
|||
|
|
for s in subfilter:
|
|||
|
|
if not s["sub1"]:
|
|||
|
|
continue
|
|||
|
|
if '"' in s["sub1"]:
|
|||
|
|
s["sub1"] = s["sub1"].replace('"', '\\"')
|
|||
|
|
if '"' in s["sub2"]:
|
|||
|
|
s["sub2"] = s["sub2"].replace('"', '\\"')
|
|||
|
|
ng_subdata += '\n\tsub_filter "%s" "%s";' % (s["sub1"], s["sub2"])
|
|||
|
|
if ng_subdata:
|
|||
|
|
ng_sub_filter = ng_sub_filter % (ng_subdata)
|
|||
|
|
else:
|
|||
|
|
ng_sub_filter = ''
|
|||
|
|
sub_rep = r'#Set\s+Nginx\s+Cache'
|
|||
|
|
ng_conf = re.sub(sub_rep, '#Set Nginx Cache\n' + ng_sub_filter, ng_conf)
|
|||
|
|
|
|||
|
|
# 修改apache配置
|
|||
|
|
ap_conf = public.readFile(ap_conf_file)
|
|||
|
|
ap_conf = re.sub(r"ProxyPass\s+%s\s+%s" % (conf[i]["proxydir"], conf[i]["proxysite"]),
|
|||
|
|
"ProxyPass %s %s" % (get.proxydir, get.proxysite), ap_conf)
|
|||
|
|
ap_conf = re.sub(r"ProxyPassReverse\s+%s\s+%s" % (conf[i]["proxydir"], conf[i]["proxysite"]),
|
|||
|
|
"ProxyPassReverse %s %s" % (get.proxydir, get.proxysite), ap_conf)
|
|||
|
|
# 修改OLS配置
|
|||
|
|
p = "{p}/panel/vhost/openlitespeed/proxy/{s}/{n}_{s}.conf".format(p=self.setupPath, n=proxyname_md5,
|
|||
|
|
s=get.sitename)
|
|||
|
|
c = public.readFile(p)
|
|||
|
|
if c:
|
|||
|
|
rep = r'address\s+(.*)'
|
|||
|
|
new_proxysite = 'address\t{}'.format(get.proxysite)
|
|||
|
|
c = re.sub(rep, new_proxysite, c)
|
|||
|
|
public.writeFile(p, c)
|
|||
|
|
|
|||
|
|
# p = "{p}/panel/vhost/openlitespeed/proxy/{s}/urlrewrite/{n}_{s}.conf".format(p=self.setupPath,n=proxyname_md5,s=get.sitename)
|
|||
|
|
c = public.readFile(ols_conf_file)
|
|||
|
|
if c:
|
|||
|
|
rep = r'RewriteRule\s*\^{}\(\.\*\)\$\s+http://{}/\$1\s*\[P,E=Proxy-Host:{}\]'.format(
|
|||
|
|
conf[i]["proxydir"], get.proxyname, conf[i]["todomain"])
|
|||
|
|
new_content = 'RewriteRule ^{}(.*)$ http://{}/$1 [P,E=Proxy-Host:{}]'.format(get.proxydir,
|
|||
|
|
get.proxyname,
|
|||
|
|
get.todomain)
|
|||
|
|
c = re.sub(rep, new_content, c)
|
|||
|
|
public.writeFile(ols_conf_file, c)
|
|||
|
|
|
|||
|
|
conf[i]["proxydir"] = get.proxydir
|
|||
|
|
conf[i]["proxysite"] = get.proxysite
|
|||
|
|
conf[i]["todomain"] = get.todomain
|
|||
|
|
conf[i]["type"] = int(get.type)
|
|||
|
|
conf[i]["cache"] = int(get.cache)
|
|||
|
|
conf[i]["subfilter"] = json.loads(get.subfilter)
|
|||
|
|
conf[i]["advanced"] = int(get.advanced)
|
|||
|
|
conf[i]["cachetime"] = int(get.cachetime)
|
|||
|
|
|
|||
|
|
public.writeFile(ng_conf_file, ng_conf)
|
|||
|
|
public.writeFile(ap_conf_file, ap_conf)
|
|||
|
|
self.__write_config(self.__proxyfile, conf)
|
|||
|
|
self.SetNginx(get)
|
|||
|
|
self.SetApache(get.sitename)
|
|||
|
|
# self.SetProxy(get)
|
|||
|
|
|
|||
|
|
# if int(get.type) != 1:
|
|||
|
|
# os.system("mv %s %s_bak" % (ap_conf_file, ap_conf_file))
|
|||
|
|
# os.system("mv %s %s_bak" % (ng_conf_file, ng_conf_file))
|
|||
|
|
if not hasattr(get, 'notreload'):
|
|||
|
|
public.serviceReload()
|
|||
|
|
return public.return_msg_gettext(True, public.lang("Setup successfully!"))
|
|||
|
|
|
|||
|
|
# 设置反向代理
|
|||
|
|
|
|||
|
|
def SetProxy(self, get):
|
|||
|
|
sitename = get.sitename # 站点名称
|
|||
|
|
advanced = int(get.advanced)
|
|||
|
|
type = int(get.type)
|
|||
|
|
cache = int(get.cache)
|
|||
|
|
cachetime = int(get.cachetime)
|
|||
|
|
proxysite = get.proxysite
|
|||
|
|
proxydir = get.proxydir
|
|||
|
|
ng_file = self.setupPath + "/panel/vhost/nginx/" + sitename + ".conf"
|
|||
|
|
ap_file = self.setupPath + "/panel/vhost/apache/" + sitename + ".conf"
|
|||
|
|
p_conf = self.__read_config(self.__proxyfile)
|
|||
|
|
random_string = public.GetRandomString(8)
|
|||
|
|
|
|||
|
|
# websocket前置map
|
|||
|
|
map_file = self.setupPath + "/panel/vhost/nginx/0.websocket.conf"
|
|||
|
|
if not os.path.exists(map_file):
|
|||
|
|
map_body = '''map $http_upgrade $connection_upgrade {
|
|||
|
|
default upgrade;
|
|||
|
|
'' close;
|
|||
|
|
}
|
|||
|
|
'''
|
|||
|
|
public.writeFile(map_file,map_body)
|
|||
|
|
|
|||
|
|
# 配置Nginx
|
|||
|
|
# 构造清理缓存连接
|
|||
|
|
|
|||
|
|
# 构造缓存配置
|
|||
|
|
ng_cache = r"""
|
|||
|
|
if ( $uri ~* "\.(gif|png|jpg|css|js|woff|woff2)$" )
|
|||
|
|
{
|
|||
|
|
expires 1m;
|
|||
|
|
}
|
|||
|
|
proxy_ignore_headers Set-Cookie Cache-Control expires;
|
|||
|
|
proxy_cache cache_one;
|
|||
|
|
proxy_cache_key $host$uri$is_args$args;
|
|||
|
|
proxy_cache_valid 200 304 301 302 %sm;""" % (cachetime)
|
|||
|
|
no_cache = r"""
|
|||
|
|
set $static_file%s 0;
|
|||
|
|
if ( $uri ~* "\.(gif|png|jpg|css|js|woff|woff2)$" )
|
|||
|
|
{
|
|||
|
|
set $static_file%s 1;
|
|||
|
|
expires 1m;
|
|||
|
|
}
|
|||
|
|
if ( $static_file%s = 0 )
|
|||
|
|
{
|
|||
|
|
add_header Cache-Control no-cache;
|
|||
|
|
}""" % (random_string,random_string,random_string)
|
|||
|
|
# rep = r"(https?://[\w\.]+)"
|
|||
|
|
# proxysite1 = re.search(rep,get.proxysite).group(1)
|
|||
|
|
ng_proxy = '''
|
|||
|
|
#PROXY-START%s
|
|||
|
|
|
|||
|
|
location %s
|
|||
|
|
{
|
|||
|
|
proxy_pass %s;
|
|||
|
|
proxy_set_header Host %s;
|
|||
|
|
proxy_set_header X-Real-IP $remote_addr;
|
|||
|
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|||
|
|
proxy_set_header REMOTE-HOST $remote_addr;
|
|||
|
|
proxy_set_header Upgrade $http_upgrade;
|
|||
|
|
proxy_set_header Connection $connection_upgrade;
|
|||
|
|
proxy_http_version 1.1;
|
|||
|
|
# proxy_hide_header Upgrade;
|
|||
|
|
%s
|
|||
|
|
|
|||
|
|
add_header X-Cache $upstream_cache_status;
|
|||
|
|
|
|||
|
|
#Set Nginx Cache
|
|||
|
|
%s
|
|||
|
|
%s
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
#PROXY-END%s'''
|
|||
|
|
ng_proxy_cache = ''
|
|||
|
|
proxyname_md5 = self.__calc_md5(get.proxyname)
|
|||
|
|
ng_proxyfile = "%s/panel/vhost/nginx/proxy/%s/%s_%s.conf" % (self.setupPath, sitename, proxyname_md5, sitename)
|
|||
|
|
ng_proxydir = "%s/panel/vhost/nginx/proxy/%s" % (self.setupPath, sitename)
|
|||
|
|
if not os.path.exists(ng_proxydir):
|
|||
|
|
public.ExecShell("mkdir -p %s" % ng_proxydir)
|
|||
|
|
|
|||
|
|
# 构造替换字符串
|
|||
|
|
ng_subdata = ''
|
|||
|
|
ng_sub_filter = '''
|
|||
|
|
proxy_set_header Accept-Encoding "";%s
|
|||
|
|
sub_filter_once off;'''
|
|||
|
|
if get.subfilter:
|
|||
|
|
for s in json.loads(get.subfilter):
|
|||
|
|
if not s["sub1"]:
|
|||
|
|
continue
|
|||
|
|
if '"' in s["sub1"]:
|
|||
|
|
s["sub1"] = s["sub1"].replace('"', '\\"')
|
|||
|
|
if '"' in s["sub2"]:
|
|||
|
|
s["sub2"] = s["sub2"].replace('"', '\\"')
|
|||
|
|
ng_subdata += '\n\tsub_filter "%s" "%s";' % (s["sub1"], s["sub2"])
|
|||
|
|
if ng_subdata:
|
|||
|
|
ng_sub_filter = ng_sub_filter % (ng_subdata)
|
|||
|
|
else:
|
|||
|
|
ng_sub_filter = ''
|
|||
|
|
# 构造反向代理
|
|||
|
|
# 如果代理URL后缀带有URI则删除URI,正则匹配不支持proxypass处带有uri
|
|||
|
|
# php_pass_proxy = get.proxysite
|
|||
|
|
# if get.proxysite[-1] == '/' or get.proxysite.count('/') > 2 or '?' in get.proxysite:
|
|||
|
|
# php_pass_proxy = re.search(r'(https?\:\/\/[\w\.]+)', get.proxysite).group(0)
|
|||
|
|
if advanced == 1:
|
|||
|
|
if proxydir[-1] != '/':
|
|||
|
|
proxydir = '{}/'.format(proxydir)
|
|||
|
|
if proxysite[-1] != '/':
|
|||
|
|
proxysite = '{}/'.format(proxysite)
|
|||
|
|
if type == 1 and cache == 1:
|
|||
|
|
ng_proxy_cache += ng_proxy % (
|
|||
|
|
proxydir, proxydir, proxysite, get.todomain,
|
|||
|
|
("#Persistent connection related configuration"), ng_sub_filter, ng_cache, get.proxydir)
|
|||
|
|
if type == 1 and cache == 0:
|
|||
|
|
ng_proxy_cache += ng_proxy % (
|
|||
|
|
get.proxydir, get.proxydir, proxysite, get.todomain,
|
|||
|
|
("#Persistent connection related configuration"), ng_sub_filter, no_cache,
|
|||
|
|
get.proxydir)
|
|||
|
|
else:
|
|||
|
|
if type == 1 and cache == 1:
|
|||
|
|
ng_proxy_cache += ng_proxy % (
|
|||
|
|
get.proxydir, get.proxydir, get.proxysite, get.todomain,
|
|||
|
|
("#Persistent connection related configuration"), ng_sub_filter, ng_cache, get.proxydir)
|
|||
|
|
if type == 1 and cache == 0:
|
|||
|
|
ng_proxy_cache += ng_proxy % (
|
|||
|
|
get.proxydir, get.proxydir, get.proxysite, get.todomain,
|
|||
|
|
("#Persistent connection related configuration"), ng_sub_filter, no_cache,
|
|||
|
|
get.proxydir)
|
|||
|
|
public.writeFile(ng_proxyfile, ng_proxy_cache)
|
|||
|
|
|
|||
|
|
# APACHE
|
|||
|
|
# 反向代理文件
|
|||
|
|
ap_proxyfile = "%s/panel/vhost/apache/proxy/%s/%s_%s.conf" % (
|
|||
|
|
self.setupPath, get.sitename, proxyname_md5, get.sitename)
|
|||
|
|
ap_proxydir = "%s/panel/vhost/apache/proxy/%s" % (self.setupPath, get.sitename)
|
|||
|
|
if not os.path.exists(ap_proxydir):
|
|||
|
|
public.ExecShell("mkdir -p %s" % ap_proxydir)
|
|||
|
|
ap_proxy = ''
|
|||
|
|
if type == 1:
|
|||
|
|
ap_proxy += '''#PROXY-START%s
|
|||
|
|
<IfModule mod_proxy.c>
|
|||
|
|
ProxyRequests Off
|
|||
|
|
SSLProxyEngine on
|
|||
|
|
ProxyPass %s %s/
|
|||
|
|
ProxyPassReverse %s %s/
|
|||
|
|
</IfModule>
|
|||
|
|
#PROXY-END%s''' % (get.proxydir, get.proxydir, get.proxysite, get.proxydir,
|
|||
|
|
get.proxysite, get.proxydir)
|
|||
|
|
public.writeFile(ap_proxyfile, ap_proxy)
|
|||
|
|
isError = public.checkWebConfig()
|
|||
|
|
if (isError != True):
|
|||
|
|
if public.get_webserver() == "nginx":
|
|||
|
|
shutil.copyfile('/tmp/ng_file_bk.conf', ng_file)
|
|||
|
|
else:
|
|||
|
|
shutil.copyfile('/tmp/ap_file_bk.conf', ap_file)
|
|||
|
|
for i in range(len(p_conf) - 1, -1, -1):
|
|||
|
|
if get.sitename == p_conf[i]["sitename"] and p_conf[i]["proxyname"]:
|
|||
|
|
del p_conf[i]
|
|||
|
|
self.RemoveProxy(get)
|
|||
|
|
return public.return_msg_gettext(False, 'ERROR: %s<br><a style="color:red;">' % public.get_msg_gettext(
|
|||
|
|
'Configuration ERROR') + isError.replace("\n",
|
|||
|
|
'<br>') + '</a>')
|
|||
|
|
return public.return_msg_gettext(True, public.lang("Setup successfully!"))
|
|||
|
|
|
|||
|
|
# 开启缓存
|
|||
|
|
def ProxyCache(self, get):
|
|||
|
|
if public.get_webserver() != 'nginx': return public.return_msg_gettext(False, public.lang("Currently only support Nginx"))
|
|||
|
|
file = self.setupPath + "/panel/vhost/nginx/" + get.siteName + ".conf"
|
|||
|
|
conf = public.readFile(file)
|
|||
|
|
if conf.find('proxy_pass') == -1: return public.return_msg_gettext(False, public.lang("Failed to set"))
|
|||
|
|
if conf.find('#proxy_cache') != -1:
|
|||
|
|
conf = conf.replace('#proxy_cache', 'proxy_cache')
|
|||
|
|
conf = conf.replace('#expires 12h', 'expires 12h')
|
|||
|
|
else:
|
|||
|
|
conf = conf.replace('proxy_cache', '#proxy_cache')
|
|||
|
|
conf = conf.replace('expires 12h', '#expires 12h')
|
|||
|
|
|
|||
|
|
public.writeFile(file, conf)
|
|||
|
|
public.serviceReload()
|
|||
|
|
return public.return_msg_gettext(True, public.lang("Setup successfully!"))
|
|||
|
|
|
|||
|
|
# 检查反向代理配置
|
|||
|
|
def CheckProxy(self, get):
|
|||
|
|
if public.get_webserver() != 'nginx': return True
|
|||
|
|
file = self.setupPath + "/nginx/conf/proxy.conf"
|
|||
|
|
if not os.path.exists(file):
|
|||
|
|
conf = '''proxy_temp_path %s/nginx/proxy_temp_dir;
|
|||
|
|
proxy_cache_path %s/nginx/proxy_cache_dir levels=1:2 keys_zone=cache_one:10m inactive=1d max_size=5g;
|
|||
|
|
client_body_buffer_size 512k;
|
|||
|
|
proxy_connect_timeout 60;
|
|||
|
|
proxy_read_timeout 60;
|
|||
|
|
proxy_send_timeout 60;
|
|||
|
|
proxy_buffer_size 32k;
|
|||
|
|
proxy_buffers 4 64k;
|
|||
|
|
proxy_busy_buffers_size 128k;
|
|||
|
|
proxy_temp_file_write_size 128k;
|
|||
|
|
proxy_next_upstream error timeout invalid_header http_500 http_503 http_404;
|
|||
|
|
proxy_cache cache_one;''' % (self.setupPath, self.setupPath)
|
|||
|
|
public.writeFile(file, conf)
|
|||
|
|
|
|||
|
|
file = self.setupPath + "/nginx/conf/nginx.conf"
|
|||
|
|
conf = public.readFile(file)
|
|||
|
|
if (conf.find('include proxy.conf;') == -1):
|
|||
|
|
rep = r"include\s+mime.types;"
|
|||
|
|
conf = re.sub(rep, "include mime.types;\n\tinclude proxy.conf;", conf)
|
|||
|
|
public.writeFile(file, conf)
|
|||
|
|
|
|||
|
|
def get_project_find(self,project_name):
|
|||
|
|
'''
|
|||
|
|
@name 获取指定项目配置
|
|||
|
|
@author hwliang<2021-08-09>
|
|||
|
|
@param project_name<string> 项目名称
|
|||
|
|
@return dict
|
|||
|
|
'''
|
|||
|
|
project_info = public.M('sites').where('project_type=? AND name=?',('Java',project_name)).find()
|
|||
|
|
if not project_info: return False
|
|||
|
|
project_info['project_config'] = json.loads(project_info['project_config'])
|
|||
|
|
return project_info
|
|||
|
|
|
|||
|
|
|
|||
|
|
#取伪静态规则应用列表
|
|||
|
|
def GetRewriteList(self,get):
|
|||
|
|
if get.siteName.find('node_') == 0:
|
|||
|
|
get.siteName = get.siteName.replace('node_', '')
|
|||
|
|
rewriteList = {}
|
|||
|
|
ws = public.get_webserver()
|
|||
|
|
if ws == "openlitespeed":
|
|||
|
|
ws = "apache"
|
|||
|
|
if ws == 'apache':
|
|||
|
|
get.id = public.M('sites').where("name=?", (get.siteName,)).getField('id')
|
|||
|
|
runPath = self.GetSiteRunPath(get)
|
|||
|
|
if runPath['runPath'].find('/www/server/stop') != -1:
|
|||
|
|
runPath['runPath'] = runPath['runPath'].replace('/www/server/stop', '')
|
|||
|
|
rewriteList['sitePath'] = public.M('sites').where("name=?", (get.siteName,)).getField('path') + runPath[
|
|||
|
|
'runPath']
|
|||
|
|
|
|||
|
|
rewriteList['rewrite'] = []
|
|||
|
|
rewriteList['rewrite'].append('0.' + public.lang("Current"))
|
|||
|
|
for ds in os.listdir('rewrite/' + ws):
|
|||
|
|
if ds == 'list.txt': continue
|
|||
|
|
rewriteList['rewrite'].append(ds[0:len(ds) - 5])
|
|||
|
|
rewriteList['rewrite'] = sorted(rewriteList['rewrite'])
|
|||
|
|
return rewriteList
|
|||
|
|
|
|||
|
|
# 保存伪静态模板
|
|||
|
|
def SetRewriteTel(self, get):
|
|||
|
|
ws = public.get_webserver()
|
|||
|
|
if not get.name:
|
|||
|
|
public.return_msg_gettext(True, 'Please enter a template name')
|
|||
|
|
if ws == "openlitespeed":
|
|||
|
|
ws = "apache"
|
|||
|
|
if sys.version_info[0] == 2: get.name = get.name.encode('utf-8')
|
|||
|
|
filename = 'rewrite/' + ws + '/' + get.name + '.conf'
|
|||
|
|
public.writeFile(filename, get.data)
|
|||
|
|
return public.return_msg_gettext(True, public.lang("New URL rewrite rule has been saved!"))
|
|||
|
|
|
|||
|
|
# 打包
|
|||
|
|
def ToBackup(self, get):
|
|||
|
|
id = get.id
|
|||
|
|
find = public.M('sites').where("id=?", (id,)).field('name,path,id').find()
|
|||
|
|
import time
|
|||
|
|
fileName = find['name'] + '_' + time.strftime('%Y%m%d_%H%M%S', time.localtime()) + '.zip'
|
|||
|
|
backupPath = session['config']['backup_path'] + '/site'
|
|||
|
|
zipName = backupPath + '/' + fileName
|
|||
|
|
if not (os.path.exists(backupPath)): os.makedirs(backupPath)
|
|||
|
|
tmps = '/tmp/panelExec.log'
|
|||
|
|
execStr = "cd '" + find['path'] + "' && zip '" + zipName + "' -x .user.ini -r ./ > " + tmps + " 2>&1"
|
|||
|
|
public.ExecShell(execStr)
|
|||
|
|
sql = public.M('backup').add('type,name,pid,filename,size,addtime',
|
|||
|
|
(0, fileName, find['id'], zipName, 0, public.getDate()))
|
|||
|
|
public.write_log_gettext('Site manager', 'Backup site [{}] succeed!', (find['name'],))
|
|||
|
|
return public.return_msg_gettext(True, public.lang("Backup Succeeded!"))
|
|||
|
|
|
|||
|
|
# 删除备份文件
|
|||
|
|
def DelBackup(self, get):
|
|||
|
|
id = get.id
|
|||
|
|
where = "id=?"
|
|||
|
|
backup_info = public.M('backup').where(where,(id,)).find()
|
|||
|
|
filename = backup_info['filename']
|
|||
|
|
if os.path.exists(filename): os.remove(filename)
|
|||
|
|
name = ''
|
|||
|
|
if filename == 'qiniu':
|
|||
|
|
name = backup_info['name']
|
|||
|
|
public.ExecShell(public.get_python_bin() + " "+self.setupPath + '/panel/script/backup_qiniu.py delete_file ' + name)
|
|||
|
|
|
|||
|
|
pid = backup_info['pid']
|
|||
|
|
site_name = public.M('sites').where('id=?',(pid,)).getField('name')
|
|||
|
|
public.write_log_gettext('Site manager', 'Successfully deleted backup [{}] of site [{}]!', (site_name, filename))
|
|||
|
|
public.M('backup').where(where, (id,)).delete()
|
|||
|
|
return public.return_msg_gettext(True, public.lang("Successfully deleted"))
|
|||
|
|
|
|||
|
|
# 旧版本配置文件处理
|
|||
|
|
def OldConfigFile(self):
|
|||
|
|
# 检查是否需要处理
|
|||
|
|
moveTo = 'data/moveTo.pl'
|
|||
|
|
if os.path.exists(moveTo): return
|
|||
|
|
|
|||
|
|
# 处理Nginx配置文件
|
|||
|
|
filename = self.setupPath + "/nginx/conf/nginx.conf"
|
|||
|
|
if os.path.exists(filename):
|
|||
|
|
conf = public.readFile(filename)
|
|||
|
|
if conf.find('include vhost/*.conf;') != -1:
|
|||
|
|
conf = conf.replace('include vhost/*.conf;', 'include ' + self.setupPath + '/panel/vhost/nginx/*.conf;')
|
|||
|
|
public.writeFile(filename, conf)
|
|||
|
|
|
|||
|
|
self.moveConf(self.setupPath + "/nginx/conf/vhost", self.setupPath + '/panel/vhost/nginx', 'rewrite',
|
|||
|
|
self.setupPath + '/panel/vhost/rewrite')
|
|||
|
|
self.moveConf(self.setupPath + "/nginx/conf/rewrite", self.setupPath + '/panel/vhost/rewrite')
|
|||
|
|
|
|||
|
|
# 处理Apache配置文件
|
|||
|
|
filename = self.setupPath + "/apache/conf/httpd.conf"
|
|||
|
|
if os.path.exists(filename):
|
|||
|
|
conf = public.readFile(filename)
|
|||
|
|
if conf.find('IncludeOptional conf/vhost/*.conf') != -1:
|
|||
|
|
conf = conf.replace('IncludeOptional conf/vhost/*.conf',
|
|||
|
|
'IncludeOptional ' + self.setupPath + '/panel/vhost/apache/*.conf')
|
|||
|
|
public.writeFile(filename, conf)
|
|||
|
|
|
|||
|
|
self.moveConf(self.setupPath + "/apache/conf/vhost", self.setupPath + '/panel/vhost/apache')
|
|||
|
|
|
|||
|
|
# 标记处理记录
|
|||
|
|
public.writeFile(moveTo, 'True')
|
|||
|
|
public.serviceReload()
|
|||
|
|
|
|||
|
|
# 移动旧版本配置文件
|
|||
|
|
def moveConf(self, Path, toPath, Replace=None, ReplaceTo=None):
|
|||
|
|
if not os.path.exists(Path): return
|
|||
|
|
import shutil
|
|||
|
|
|
|||
|
|
letPath = '/etc/letsencrypt/live'
|
|||
|
|
nginxPath = self.setupPath + '/nginx/conf/key'
|
|||
|
|
apachePath = self.setupPath + '/apache/conf/key'
|
|||
|
|
for filename in os.listdir(Path):
|
|||
|
|
# 准备配置文件
|
|||
|
|
name = filename[0:len(filename) - 5]
|
|||
|
|
filename = Path + '/' + filename
|
|||
|
|
conf = public.readFile(filename)
|
|||
|
|
|
|||
|
|
# 替换关键词
|
|||
|
|
if Replace: conf = conf.replace(Replace, ReplaceTo)
|
|||
|
|
ReplaceTo = letPath + name
|
|||
|
|
Replace = 'conf/key/' + name
|
|||
|
|
if conf.find(Replace) != -1: conf = conf.replace(Replace, ReplaceTo)
|
|||
|
|
Replace = 'key/' + name
|
|||
|
|
if conf.find(Replace) != -1: conf = conf.replace(Replace, ReplaceTo)
|
|||
|
|
public.writeFile(filename, conf)
|
|||
|
|
|
|||
|
|
# 提取配置信息
|
|||
|
|
if conf.find('server_name') != -1:
|
|||
|
|
self.formatNginxConf(filename)
|
|||
|
|
elif conf.find('<Directory') != -1:
|
|||
|
|
# self.formatApacheConf(filename)
|
|||
|
|
pass
|
|||
|
|
|
|||
|
|
# 移动文件
|
|||
|
|
shutil.move(filename, toPath + '/' + name + '.conf')
|
|||
|
|
|
|||
|
|
# 转移证书
|
|||
|
|
self.moveKey(nginxPath + '/' + name, letPath + '/' + name)
|
|||
|
|
self.moveKey(apachePath + '/' + name, letPath + '/' + name)
|
|||
|
|
|
|||
|
|
# 删除多余目录
|
|||
|
|
shutil.rmtree(Path)
|
|||
|
|
# 重载服务
|
|||
|
|
public.serviceReload()
|
|||
|
|
|
|||
|
|
# 从Nginx配置文件获取站点信息
|
|||
|
|
def formatNginxConf(self, filename):
|
|||
|
|
|
|||
|
|
# 准备基础信息
|
|||
|
|
name = os.path.basename(filename[0:len(filename) - 5])
|
|||
|
|
if name.find('.') == -1: return
|
|||
|
|
conf = public.readFile(filename)
|
|||
|
|
# 取域名
|
|||
|
|
rep = r"server_name\s+(.+);"
|
|||
|
|
tmp = re.search(rep, conf)
|
|||
|
|
if not tmp: return
|
|||
|
|
domains = tmp.groups()[0].split(' ')
|
|||
|
|
|
|||
|
|
# 取根目录
|
|||
|
|
rep = r"root\s+(.+);"
|
|||
|
|
tmp = re.search(rep, conf)
|
|||
|
|
if not tmp: return
|
|||
|
|
path = tmp.groups()[0]
|
|||
|
|
|
|||
|
|
# 提交到数据库
|
|||
|
|
self.toSiteDatabase(name, domains, path)
|
|||
|
|
|
|||
|
|
# 从Apache配置文件获取站点信息
|
|||
|
|
def formatApacheConf(self, filename):
|
|||
|
|
# 准备基础信息
|
|||
|
|
name = os.path.basename(filename[0:len(filename) - 5])
|
|||
|
|
if name.find('.') == -1: return
|
|||
|
|
conf = public.readFile(filename)
|
|||
|
|
|
|||
|
|
# 取域名
|
|||
|
|
rep = "ServerAlias\\s+(.+)\n"
|
|||
|
|
tmp = re.search(rep, conf)
|
|||
|
|
if not tmp: return
|
|||
|
|
domains = tmp.groups()[0].split(' ')
|
|||
|
|
|
|||
|
|
# 取根目录
|
|||
|
|
rep = u"DocumentRoot\\s+\"(.+)\"\n"
|
|||
|
|
tmp = re.search(rep, conf)
|
|||
|
|
if not tmp: return
|
|||
|
|
path = tmp.groups()[0]
|
|||
|
|
|
|||
|
|
# 提交到数据库
|
|||
|
|
self.toSiteDatabase(name, domains, path)
|
|||
|
|
|
|||
|
|
# 添加到数据库
|
|||
|
|
def toSiteDatabase(self, name, domains, path):
|
|||
|
|
if public.M('sites').where('name=?', (name,)).count() > 0: return
|
|||
|
|
public.M('sites').add('name,path,status,ps,addtime',
|
|||
|
|
(name, path, '1', public.lang("Please enter a note"), public.getDate()))
|
|||
|
|
pid = public.M('sites').where("name=?", (name,)).getField('id')
|
|||
|
|
for domain in domains:
|
|||
|
|
public.M('domain').add('pid,name,port,addtime', (pid, domain, '80', public.getDate()))
|
|||
|
|
|
|||
|
|
# 移动旧版本证书
|
|||
|
|
def moveKey(self, srcPath, dstPath):
|
|||
|
|
if not os.path.exists(srcPath): return
|
|||
|
|
import shutil
|
|||
|
|
os.makedirs(dstPath)
|
|||
|
|
srcKey = srcPath + '/key.key'
|
|||
|
|
srcCsr = srcPath + '/csr.key'
|
|||
|
|
if os.path.exists(srcKey): shutil.move(srcKey, dstPath + '/privkey.pem')
|
|||
|
|
if os.path.exists(srcCsr): shutil.move(srcCsr, dstPath + '/fullchain.pem')
|
|||
|
|
|
|||
|
|
# 路径处理
|
|||
|
|
def GetPath(self, path):
|
|||
|
|
if path[-1] == '/':
|
|||
|
|
return path[0:-1]
|
|||
|
|
return path
|
|||
|
|
|
|||
|
|
# 日志开关
|
|||
|
|
def logsOpen(self, get):
|
|||
|
|
get.name = public.M('sites').where("id=?", (get.id,)).getField('name')
|
|||
|
|
# APACHE
|
|||
|
|
filename = public.GetConfigValue('setup_path') + '/panel/vhost/apache/' + get.name + '.conf'
|
|||
|
|
if os.path.exists(filename):
|
|||
|
|
conf = public.readFile(filename)
|
|||
|
|
if conf.find('#ErrorLog') != -1:
|
|||
|
|
conf = conf.replace("#ErrorLog", "ErrorLog").replace('#CustomLog', 'CustomLog')
|
|||
|
|
else:
|
|||
|
|
conf = conf.replace("ErrorLog", "#ErrorLog").replace('CustomLog', '#CustomLog')
|
|||
|
|
public.writeFile(filename, conf)
|
|||
|
|
|
|||
|
|
# NGINX
|
|||
|
|
filename = public.GetConfigValue('setup_path') + '/panel/vhost/nginx/' + get.name + '.conf'
|
|||
|
|
if os.path.exists(filename):
|
|||
|
|
conf = public.readFile(filename)
|
|||
|
|
rep = public.GetConfigValue('logs_path') + "/" + get.name + ".log"
|
|||
|
|
if conf.find(rep) != -1:
|
|||
|
|
conf = conf.replace(rep, "/dev/null")
|
|||
|
|
else:
|
|||
|
|
# conf = re.sub('}\n\\s+access_log\\s+off', '}\n\taccess_log ' + rep, conf)
|
|||
|
|
conf = conf.replace('access_log /dev/null', 'access_log ' + rep)
|
|||
|
|
public.writeFile(filename, conf)
|
|||
|
|
|
|||
|
|
# OLS
|
|||
|
|
filename = public.GetConfigValue('setup_path') + '/panel/vhost/openlitespeed/detail/' + get.name + '.conf'
|
|||
|
|
conf = public.readFile(filename)
|
|||
|
|
if conf:
|
|||
|
|
rep = "\nerrorlog(.|\n)*compressArchive\\s*1\\s*\n}"
|
|||
|
|
tmp = re.search(rep, conf)
|
|||
|
|
s = 'on'
|
|||
|
|
if not tmp:
|
|||
|
|
s = 'off'
|
|||
|
|
rep = "\n#errorlog(.|\n)*compressArchive\\s*1\\s*\n#}"
|
|||
|
|
tmp = re.search(rep, conf)
|
|||
|
|
tmp = tmp.group()
|
|||
|
|
if tmp:
|
|||
|
|
result = ''
|
|||
|
|
if s == 'on':
|
|||
|
|
for l in tmp.strip().splitlines():
|
|||
|
|
result += "\n#"+l
|
|||
|
|
else:
|
|||
|
|
for l in tmp.splitlines():
|
|||
|
|
result += "\n"+l[1:]
|
|||
|
|
conf = re.sub(rep,"\n"+result.strip(),conf)
|
|||
|
|
public.writeFile(filename,conf)
|
|||
|
|
|
|||
|
|
public.serviceReload()
|
|||
|
|
return public.return_msg_gettext(True, public.lang("Setup successfully!"))
|
|||
|
|
|
|||
|
|
# 取日志状态
|
|||
|
|
def GetLogsStatus(self, get):
|
|||
|
|
if not hasattr(get, 'name') or not get.name:
|
|||
|
|
return True
|
|||
|
|
if isinstance(get.name, list):
|
|||
|
|
site_name = get.name[0] if get.name else ''
|
|||
|
|
elif isinstance(get.name, str):
|
|||
|
|
site_name = get.name
|
|||
|
|
else:
|
|||
|
|
site_name = str(get.name)
|
|||
|
|
site_name = site_name.strip()
|
|||
|
|
if not site_name:
|
|||
|
|
return True
|
|||
|
|
filename = public.GetConfigValue(
|
|||
|
|
'setup_path') + '/panel/vhost/' + public.get_webserver() + '/' + get.name + '.conf'
|
|||
|
|
if public.get_webserver() == 'openlitespeed':
|
|||
|
|
filename = public.GetConfigValue(
|
|||
|
|
'setup_path') + '/panel/vhost/' + public.get_webserver() + '/detail/' + get.name + '.conf'
|
|||
|
|
conf = public.readFile(filename)
|
|||
|
|
if not conf: return True
|
|||
|
|
if conf.find('#ErrorLog') != -1: return False
|
|||
|
|
#if re.search("}\n*\\s*access_log\\s+off", conf):
|
|||
|
|
if conf.find("access_log /dev/null") != -1: return False
|
|||
|
|
if re.search('\n#accesslog', conf):
|
|||
|
|
return False
|
|||
|
|
return True
|
|||
|
|
|
|||
|
|
# 取目录加密状态
|
|||
|
|
def GetHasPwd(self, get):
|
|||
|
|
if not hasattr(get, 'siteName'):
|
|||
|
|
get.siteName = public.M('sites').where('id=?', (get.id,)).getField('name')
|
|||
|
|
get.configFile = self.setupPath + '/panel/vhost/nginx/' + get.siteName + '.conf'
|
|||
|
|
conf = public.readFile(get.configFile)
|
|||
|
|
if type(conf) == bool: return False
|
|||
|
|
if conf.find('#AUTH_START') != -1: return True
|
|||
|
|
return False
|
|||
|
|
|
|||
|
|
# 设置目录加密
|
|||
|
|
def SetHasPwd(self, get):
|
|||
|
|
if public.get_webserver() == 'openlitespeed':
|
|||
|
|
return public.return_msg_gettext(False, public.lang("The current web server is openlitespeed. This function is not supported yet."))
|
|||
|
|
if len(get.username.strip()) < 3 or len(get.password.strip()) < 3: return public.return_msg_gettext(False, public.lang("Username or password cannot be less than 3 digits!"))
|
|||
|
|
|
|||
|
|
if not hasattr(get, 'siteName'):
|
|||
|
|
get.siteName = public.M('sites').where('id=?', (get.id,)).getField('name')
|
|||
|
|
|
|||
|
|
self.CloseHasPwd(get)
|
|||
|
|
filename = public.GetConfigValue('setup_path') + '/pass/' + get.siteName + '.pass'
|
|||
|
|
try:
|
|||
|
|
passconf = get.username + ':' + public.hasPwd(get.password)
|
|||
|
|
except:
|
|||
|
|
return public.returnMsg(False, public.lang("The password fomart is wrong, please do not use special symbols for the first two digits!"))
|
|||
|
|
|
|||
|
|
if get.siteName == 'phpmyadmin':
|
|||
|
|
get.configFile = self.setupPath + '/nginx/conf/nginx.conf'
|
|||
|
|
if os.path.exists(self.setupPath + '/panel/vhost/nginx/phpmyadmin.conf'):
|
|||
|
|
get.configFile = self.setupPath + '/panel/vhost/nginx/phpmyadmin.conf'
|
|||
|
|
else:
|
|||
|
|
get.configFile = self.setupPath + '/panel/vhost/nginx/' + get.siteName + '.conf'
|
|||
|
|
|
|||
|
|
# 处理Nginx配置
|
|||
|
|
conf = public.readFile(get.configFile)
|
|||
|
|
if conf:
|
|||
|
|
rep = '#error_page 404 /404.html;'
|
|||
|
|
if conf.find(rep) == -1: rep = '#error_page 404/404.html;'
|
|||
|
|
data = '''
|
|||
|
|
#AUTH_START
|
|||
|
|
auth_basic "Authorization";
|
|||
|
|
auth_basic_user_file %s;
|
|||
|
|
#AUTH_END''' % (filename,)
|
|||
|
|
conf = conf.replace(rep, rep + data)
|
|||
|
|
public.writeFile(get.configFile, conf)
|
|||
|
|
|
|||
|
|
if get.siteName == 'phpmyadmin':
|
|||
|
|
get.configFile = self.setupPath + '/apache/conf/extra/httpd-vhosts.conf'
|
|||
|
|
if os.path.exists(self.setupPath + '/panel/vhost/apache/phpmyadmin.conf'):
|
|||
|
|
get.configFile = self.setupPath + '/panel/vhost/apache/phpmyadmin.conf'
|
|||
|
|
else:
|
|||
|
|
get.configFile = self.setupPath + '/panel/vhost/apache/' + get.siteName + '.conf'
|
|||
|
|
|
|||
|
|
conf = public.readFile(get.configFile)
|
|||
|
|
if conf:
|
|||
|
|
# 处理Apache配置
|
|||
|
|
rep = 'SetOutputFilter'
|
|||
|
|
if conf.find(rep) != -1:
|
|||
|
|
data = '''#AUTH_START
|
|||
|
|
AuthType basic
|
|||
|
|
AuthName "Authorization "
|
|||
|
|
AuthUserFile %s
|
|||
|
|
Require user %s
|
|||
|
|
#AUTH_END
|
|||
|
|
''' % (filename, get.username)
|
|||
|
|
conf = conf.replace(rep, data + rep)
|
|||
|
|
conf = conf.replace(' Require all granted', " #Require all granted")
|
|||
|
|
public.writeFile(get.configFile, conf)
|
|||
|
|
|
|||
|
|
# 写密码配置
|
|||
|
|
passDir = public.GetConfigValue('setup_path') + '/pass'
|
|||
|
|
if not os.path.exists(passDir): public.ExecShell('mkdir -p ' + passDir)
|
|||
|
|
public.writeFile(filename, passconf)
|
|||
|
|
public.serviceReload()
|
|||
|
|
public.write_log_gettext("Site manager", "Set site [{}] to password authentication required!", (get.siteName,))
|
|||
|
|
return public.return_msg_gettext(True, public.lang("Setup successfully!"))
|
|||
|
|
|
|||
|
|
# 取消目录加密
|
|||
|
|
def CloseHasPwd(self, get):
|
|||
|
|
if not hasattr(get, 'siteName'):
|
|||
|
|
get.siteName = public.M('sites').where('id=?', (get.id,)).getField('name')
|
|||
|
|
|
|||
|
|
if get.siteName == 'phpmyadmin':
|
|||
|
|
get.configFile = self.setupPath + '/nginx/conf/nginx.conf'
|
|||
|
|
else:
|
|||
|
|
get.configFile = self.setupPath + '/panel/vhost/nginx/' + get.siteName + '.conf'
|
|||
|
|
|
|||
|
|
if os.path.exists(get.configFile):
|
|||
|
|
conf = public.readFile(get.configFile)
|
|||
|
|
rep = "\n\\s*#AUTH_START(.|\n){1,200}#AUTH_END"
|
|||
|
|
conf = re.sub(rep, '', conf)
|
|||
|
|
public.writeFile(get.configFile, conf)
|
|||
|
|
|
|||
|
|
if get.siteName == 'phpmyadmin':
|
|||
|
|
get.configFile = self.setupPath + '/apache/conf/extra/httpd-vhosts.conf'
|
|||
|
|
else:
|
|||
|
|
get.configFile = self.setupPath + '/panel/vhost/apache/' + get.siteName + '.conf'
|
|||
|
|
|
|||
|
|
if os.path.exists(get.configFile):
|
|||
|
|
conf = public.readFile(get.configFile)
|
|||
|
|
rep = "\n\\s*#AUTH_START(.|\n){1,200}#AUTH_END"
|
|||
|
|
conf = re.sub(rep, '', conf)
|
|||
|
|
conf = conf.replace(' #Require all granted', " Require all granted")
|
|||
|
|
public.writeFile(get.configFile, conf)
|
|||
|
|
public.serviceReload()
|
|||
|
|
public.write_log_gettext("Site manager", "Cleared password authentication for site [{}]!", (get.siteName,))
|
|||
|
|
return public.return_msg_gettext(True, public.lang("Setup successfully!"))
|
|||
|
|
|
|||
|
|
# 启用tomcat支持
|
|||
|
|
def SetTomcat(self, get):
|
|||
|
|
siteName = get.siteName
|
|||
|
|
name = siteName.replace('.', '_')
|
|||
|
|
|
|||
|
|
rep = r"^(\d{1,3}\.){3,3}\d{1,3}$"
|
|||
|
|
if re.match(rep, siteName): return public.return_msg_gettext(False, public.lang("ERROR, primary domain cannot be IP address!"))
|
|||
|
|
|
|||
|
|
# nginx
|
|||
|
|
filename = self.setupPath + '/panel/vhost/nginx/' + siteName + '.conf'
|
|||
|
|
if os.path.exists(filename):
|
|||
|
|
conf = public.readFile(filename)
|
|||
|
|
if conf.find('#TOMCAT-START') != -1: return self.CloseTomcat(get)
|
|||
|
|
tomcatConf = r'''#TOMCAT-START
|
|||
|
|
location /
|
|||
|
|
{
|
|||
|
|
proxy_pass "http://%s:8080";
|
|||
|
|
proxy_set_header Host %s;
|
|||
|
|
proxy_set_header X-Forwarded-For $remote_addr;
|
|||
|
|
}
|
|||
|
|
location ~ .*\.(gif|jpg|jpeg|bmp|png|ico|txt|js|css)$
|
|||
|
|
{
|
|||
|
|
expires 12h;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
location ~ .*\.war$
|
|||
|
|
{
|
|||
|
|
return 404;
|
|||
|
|
}
|
|||
|
|
#TOMCAT-END
|
|||
|
|
''' % (siteName, siteName)
|
|||
|
|
rep = 'include enable-php'
|
|||
|
|
conf = conf.replace(rep, tomcatConf + rep)
|
|||
|
|
public.writeFile(filename, conf)
|
|||
|
|
|
|||
|
|
# apache
|
|||
|
|
filename = self.setupPath + '/panel/vhost/apache/' + siteName + '.conf'
|
|||
|
|
if os.path.exists(filename):
|
|||
|
|
conf = public.readFile(filename)
|
|||
|
|
if conf.find('#TOMCAT-START') != -1: return self.CloseTomcat(get)
|
|||
|
|
tomcatConf = '''#TOMCAT-START
|
|||
|
|
<IfModule mod_proxy.c>
|
|||
|
|
ProxyRequests Off
|
|||
|
|
SSLProxyEngine on
|
|||
|
|
ProxyPass / http://%s:8080/
|
|||
|
|
ProxyPassReverse / http://%s:8080/
|
|||
|
|
RequestHeader unset Accept-Encoding
|
|||
|
|
ExtFilterDefine fixtext mode=output intype=text/html cmd="/bin/sed 's,:8080,,g'"
|
|||
|
|
SetOutputFilter fixtext
|
|||
|
|
</IfModule>
|
|||
|
|
#TOMCAT-END
|
|||
|
|
''' % (siteName, siteName)
|
|||
|
|
|
|||
|
|
rep = '#PATH'
|
|||
|
|
conf = conf.replace(rep, tomcatConf + rep)
|
|||
|
|
public.writeFile(filename, conf)
|
|||
|
|
path = public.M('sites').where("name=?", (siteName,)).getField('path')
|
|||
|
|
import tomcat
|
|||
|
|
tomcat.tomcat().AddVhost(path, siteName)
|
|||
|
|
public.serviceReload()
|
|||
|
|
public.ExecShell('/etc/init.d/tomcat stop')
|
|||
|
|
public.ExecShell('/etc/init.d/tomcat start')
|
|||
|
|
public.ExecShell('echo "127.0.0.1 ' + siteName + '" >> /etc/hosts')
|
|||
|
|
public.write_log_gettext('TYPE_SITE', 'Turned on Tomcat supporting for site [{}]!', (siteName,))
|
|||
|
|
return public.return_msg_gettext(True, public.lang("Succeeded, please test JSP program!"))
|
|||
|
|
|
|||
|
|
# 关闭tomcat支持
|
|||
|
|
def CloseTomcat(self, get):
|
|||
|
|
if not os.path.exists('/etc/init.d/tomcat'): return False
|
|||
|
|
siteName = get.siteName
|
|||
|
|
name = siteName.replace('.', '_')
|
|||
|
|
|
|||
|
|
# nginx
|
|||
|
|
filename = self.setupPath + '/panel/vhost/nginx/' + siteName + '.conf'
|
|||
|
|
if os.path.exists(filename):
|
|||
|
|
conf = public.readFile(filename)
|
|||
|
|
rep = "\\s*#TOMCAT-START(.|\n)+#TOMCAT-END"
|
|||
|
|
conf = re.sub(rep, '', conf)
|
|||
|
|
public.writeFile(filename, conf)
|
|||
|
|
|
|||
|
|
# apache
|
|||
|
|
filename = self.setupPath + '/panel/vhost/apache/' + siteName + '.conf'
|
|||
|
|
if os.path.exists(filename):
|
|||
|
|
conf = public.readFile(filename)
|
|||
|
|
rep = "\\s*#TOMCAT-START(.|\n)+#TOMCAT-END"
|
|||
|
|
conf = re.sub(rep, '', conf)
|
|||
|
|
public.writeFile(filename, conf)
|
|||
|
|
public.ExecShell('rm -rf ' + self.setupPath + '/panel/vhost/tomcat/' + name)
|
|||
|
|
try:
|
|||
|
|
import tomcat
|
|||
|
|
tomcat.tomcat().DelVhost(siteName)
|
|||
|
|
except:
|
|||
|
|
pass
|
|||
|
|
public.serviceReload()
|
|||
|
|
public.ExecShell('/etc/init.d/tomcat restart')
|
|||
|
|
public.ExecShell("sed -i '/" + siteName + "/d' /etc/hosts")
|
|||
|
|
public.write_log_gettext('Site manager', 'Turned off Tomcat supporting for site [{}]!', (siteName,))
|
|||
|
|
return public.return_msg_gettext(True, public.lang("Tomcat mapping closed!"))
|
|||
|
|
|
|||
|
|
#取当站点前运行目录
|
|||
|
|
def GetSiteRunPath(self,get):
|
|||
|
|
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
|
|||
|
|
# 兼容多服务
|
|||
|
|
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)
|
|||
|
|
rep = r'\s*root\s+(.+);'
|
|||
|
|
path = re.search(rep, conf)
|
|||
|
|
if not path:
|
|||
|
|
return public.return_msg_gettext(False, public.lang("Get Site run path false"))
|
|||
|
|
path = path.groups()[0]
|
|||
|
|
elif webserver == 'apache':
|
|||
|
|
filename = self.setupPath + '/panel/vhost/apache/' + siteName + '.conf'
|
|||
|
|
if os.path.exists(filename):
|
|||
|
|
conf = public.readFile(filename)
|
|||
|
|
rep = '\\s*DocumentRoot\\s*"(.+)"\\s*\n'
|
|||
|
|
path = re.search(rep, conf)
|
|||
|
|
if not path:
|
|||
|
|
return public.return_msg_gettext(False, public.lang("Get Site run path false"))
|
|||
|
|
path = path.groups()[0]
|
|||
|
|
else:
|
|||
|
|
filename = self.setupPath + '/panel/vhost/openlitespeed/' + siteName + '.conf'
|
|||
|
|
if os.path.exists(filename):
|
|||
|
|
conf = public.readFile(filename)
|
|||
|
|
rep = r"vhRoot\s*(.*)"
|
|||
|
|
path = re.search(rep, conf)
|
|||
|
|
if not path:
|
|||
|
|
return public.return_msg_gettext(False, public.lang("Get Site run path false"))
|
|||
|
|
path = path.groups()[0]
|
|||
|
|
data = {}
|
|||
|
|
if sitePath == path:
|
|||
|
|
data['runPath'] = '/'
|
|||
|
|
else:
|
|||
|
|
data['runPath'] = path.replace(sitePath, '')
|
|||
|
|
|
|||
|
|
dirnames = []
|
|||
|
|
dirnames.append('/')
|
|||
|
|
if not os.path.exists(sitePath): os.makedirs(sitePath)
|
|||
|
|
for filename in os.listdir(sitePath):
|
|||
|
|
try:
|
|||
|
|
json.dumps(filename)
|
|||
|
|
if sys.version_info[0] == 2:
|
|||
|
|
filename = filename.encode('utf-8')
|
|||
|
|
else:
|
|||
|
|
filename.encode('utf-8')
|
|||
|
|
filePath = sitePath + '/' + filename
|
|||
|
|
if not os.path.exists(filePath): continue
|
|||
|
|
if os.path.islink(filePath): continue
|
|||
|
|
if os.path.isdir(filePath):
|
|||
|
|
dirnames.append('/' + filename)
|
|||
|
|
except:
|
|||
|
|
pass
|
|||
|
|
|
|||
|
|
data['dirs'] = dirnames
|
|||
|
|
return data
|
|||
|
|
|
|||
|
|
# 设置当前站点运行目录
|
|||
|
|
def SetSiteRunPath(self, get):
|
|||
|
|
siteName = public.M('sites').where('id=?', (get.id,)).getField('name')
|
|||
|
|
sitePath = public.M('sites').where('id=?', (get.id,)).getField('path')
|
|||
|
|
old_run_path = self.GetRunPath(get)
|
|||
|
|
# 处理Nginx
|
|||
|
|
filename = self.setupPath + '/panel/vhost/nginx/' + siteName + '.conf'
|
|||
|
|
if os.path.exists(filename):
|
|||
|
|
conf = public.readFile(filename)
|
|||
|
|
if conf:
|
|||
|
|
rep = r'\s*root\s+(.+);'
|
|||
|
|
tmp = re.search(rep,conf)
|
|||
|
|
if tmp:
|
|||
|
|
path = tmp.groups()[0]
|
|||
|
|
conf = conf.replace(path,sitePath + get.runPath)
|
|||
|
|
public.writeFile(filename,conf)
|
|||
|
|
|
|||
|
|
#处理Apache
|
|||
|
|
filename = self.setupPath + '/panel/vhost/apache/' + siteName + '.conf'
|
|||
|
|
if os.path.exists(filename):
|
|||
|
|
conf = public.readFile(filename)
|
|||
|
|
if conf:
|
|||
|
|
rep = '\\s*DocumentRoot\\s*"(.+)"\\s*\n'
|
|||
|
|
tmp = re.search(rep,conf)
|
|||
|
|
if tmp:
|
|||
|
|
path = tmp.groups()[0]
|
|||
|
|
conf = conf.replace(path,sitePath + get.runPath)
|
|||
|
|
public.writeFile(filename,conf)
|
|||
|
|
# 处理OLS
|
|||
|
|
self._set_ols_run_path(sitePath, get.runPath, siteName)
|
|||
|
|
# self.DelUserInI(sitePath)
|
|||
|
|
# get.path = sitePath;
|
|||
|
|
# self.SetDirUserINI(get);
|
|||
|
|
s_path = sitePath + old_run_path + "/.user.ini"
|
|||
|
|
d_path = sitePath + get.runPath + "/.user.ini"
|
|||
|
|
if s_path != d_path:
|
|||
|
|
public.ExecShell("chattr -i {}".format(s_path))
|
|||
|
|
public.ExecShell("mv {} {}".format(s_path, d_path))
|
|||
|
|
public.ExecShell("chattr +i {}".format(d_path))
|
|||
|
|
|
|||
|
|
public.serviceReload()
|
|||
|
|
return public.return_msg_gettext(True, public.lang("Setup successfully!"))
|
|||
|
|
|
|||
|
|
def _set_ols_run_path(self, site_path, run_path, sitename):
|
|||
|
|
ols_conf_file = "{}/panel/vhost/openlitespeed/{}.conf".format(self.setupPath, sitename)
|
|||
|
|
ols_conf = public.readFile(ols_conf_file)
|
|||
|
|
if not ols_conf:
|
|||
|
|
return
|
|||
|
|
reg = '#VHOST\\s*{s}\\s*START(.|\n)+#VHOST\\s*{s}\\s*END'.format(s=sitename)
|
|||
|
|
tmp = re.search(reg, ols_conf)
|
|||
|
|
if not tmp:
|
|||
|
|
return
|
|||
|
|
reg = r"vhRoot\s*(.*)"
|
|||
|
|
# tmp = re.search(reg,tmp.group())
|
|||
|
|
# if not tmp:
|
|||
|
|
# return
|
|||
|
|
tmp = "vhRoot " + site_path + run_path
|
|||
|
|
ols_conf = re.sub(reg, tmp, ols_conf)
|
|||
|
|
public.writeFile(ols_conf_file, ols_conf)
|
|||
|
|
|
|||
|
|
# 设置默认站点
|
|||
|
|
def SetDefaultSite(self, get):
|
|||
|
|
import time
|
|||
|
|
if public.GetWebServer() in ['openlitespeed']:
|
|||
|
|
return public.returnMsg(False, public.lang("OpenLiteSpeed does not support setting the default site"))
|
|||
|
|
default_site_save = 'data/defaultSite.pl'
|
|||
|
|
# 清理旧的
|
|||
|
|
defaultSite = public.readFile(default_site_save)
|
|||
|
|
http2 = ''
|
|||
|
|
versionStr = public.readFile('/www/server/nginx/version.pl')
|
|||
|
|
if versionStr:
|
|||
|
|
if versionStr.find('1.8.1') == -1 and versionStr.find('1.25') == -1 and versionStr.find('1.26') == -1: http2 = ' http2'
|
|||
|
|
if defaultSite:
|
|||
|
|
path = self.setupPath + '/panel/vhost/nginx/' + defaultSite + '.conf'
|
|||
|
|
if os.path.exists(path):
|
|||
|
|
conf = public.readFile(path)
|
|||
|
|
rep = r"listen\s+80.+;"
|
|||
|
|
conf = re.sub(rep, 'listen 80;', conf, 1)
|
|||
|
|
rep = r"listen\s+\[::\]:80.+;"
|
|||
|
|
conf = re.sub(rep, 'listen [::]:80;', conf, 1)
|
|||
|
|
rep = r"listen\s+443.+;"
|
|||
|
|
conf = re.sub(rep, 'listen 443 ssl' + http2 + ';', conf, 1)
|
|||
|
|
rep = r"listen\s+\[::\]:443.+;"
|
|||
|
|
conf = re.sub(rep, 'listen [::]:443 ssl' + http2 + ';', conf, 1)
|
|||
|
|
public.writeFile(path, conf)
|
|||
|
|
|
|||
|
|
path = self.setupPath + '/apache/htdocs/.htaccess'
|
|||
|
|
if os.path.exists(path): os.remove(path)
|
|||
|
|
|
|||
|
|
if get.name == '0':
|
|||
|
|
if os.path.exists(default_site_save): os.remove(default_site_save)
|
|||
|
|
public.serviceReload()
|
|||
|
|
return public.return_msg_gettext(True, public.lang("Setup successfully!"))
|
|||
|
|
|
|||
|
|
# 处理新的
|
|||
|
|
path = self.setupPath + '/apache/htdocs'
|
|||
|
|
if os.path.exists(path):
|
|||
|
|
conf = '''<IfModule mod_rewrite.c>
|
|||
|
|
RewriteEngine on
|
|||
|
|
RewriteCond %{HTTP_HOST} !^127.0.0.1 [NC]
|
|||
|
|
RewriteRule (.*) http://%s/$1 [L]
|
|||
|
|
</IfModule>'''
|
|||
|
|
conf = conf.replace("%s", get.name)
|
|||
|
|
if get.name == 'off': conf = ''
|
|||
|
|
public.writeFile(path + '/.htaccess', conf)
|
|||
|
|
|
|||
|
|
path = self.setupPath + '/panel/vhost/nginx/' + get.name + '.conf'
|
|||
|
|
if os.path.exists(path):
|
|||
|
|
conf = public.readFile(path)
|
|||
|
|
rep = r"listen\s+80\s*;"
|
|||
|
|
conf = re.sub(rep, 'listen 80 default_server;', conf, 1)
|
|||
|
|
rep = r"listen\s+\[::\]:80\s*;"
|
|||
|
|
conf = re.sub(rep, 'listen [::]:80 default_server;', conf, 1)
|
|||
|
|
rep = r"listen\s+443\s*ssl\s*\w*\s*;"
|
|||
|
|
conf = re.sub(rep, 'listen 443 ssl' + http2 + ' default_server;', conf, 1)
|
|||
|
|
rep = r"listen\s+\[::\]:443\s*ssl\s*\w*\s*;"
|
|||
|
|
conf = re.sub(rep, 'listen [::]:443 ssl' + http2 + ' default_server;', conf, 1)
|
|||
|
|
public.writeFile(path, conf)
|
|||
|
|
|
|||
|
|
path = self.setupPath + '/panel/vhost/nginx/default.conf'
|
|||
|
|
if os.path.exists(path): public.ExecShell('rm -f ' + path)
|
|||
|
|
public.writeFile(default_site_save, get.name)
|
|||
|
|
public.serviceReload()
|
|||
|
|
return public.return_msg_gettext(True, public.lang("Setup successfully!"))
|
|||
|
|
|
|||
|
|
# 取默认站点
|
|||
|
|
def GetDefaultSite(self, get):
|
|||
|
|
data = {}
|
|||
|
|
data['sites'] = public.M('sites').where('project_type=? OR project_type=?',('PHP','WP')).field('name').order('id desc').select()
|
|||
|
|
data['defaultSite'] = public.readFile('data/defaultSite.pl')
|
|||
|
|
return data
|
|||
|
|
|
|||
|
|
# 扫描站点
|
|||
|
|
def CheckSafe(self, get):
|
|||
|
|
import db, time
|
|||
|
|
isTask = '/tmp/panelTask.pl'
|
|||
|
|
if os.path.exists(self.setupPath + '/panel/class/panelSafe.py'):
|
|||
|
|
import py_compile
|
|||
|
|
py_compile.compile(self.setupPath + '/panel/class/panelSafe.py')
|
|||
|
|
get.path = public.M('sites').where('id=?', (get.id,)).getField('path')
|
|||
|
|
execstr = "cd " + public.GetConfigValue(
|
|||
|
|
'setup_path') + "/panel/class && " + public.get_python_bin() + " panelSafe.pyc " + get.path
|
|||
|
|
sql = db.Sql()
|
|||
|
|
sql.table('tasks').add('id,name,type,status,addtime,execstr', (
|
|||
|
|
None, '%s [' % public.lang("Scan directory") + get.path + ']', 'execshell', '0', time.strftime('%Y-%m-%d %H:%M:%S'),
|
|||
|
|
execstr))
|
|||
|
|
public.writeFile(isTask, 'True')
|
|||
|
|
public.write_log_gettext('Installer', 'Added trojan scan task for directory [{}]!', (get.path,))
|
|||
|
|
return public.return_msg_gettext(True, public.lang("Scan Task has in the queue!"))
|
|||
|
|
|
|||
|
|
# 获取结果信息
|
|||
|
|
def GetCheckSafe(self, get):
|
|||
|
|
get.path = public.M('sites').where('id=?', (get.id,)).getField('path')
|
|||
|
|
path = get.path + '/scan.pl'
|
|||
|
|
result = {}
|
|||
|
|
result['data'] = []
|
|||
|
|
result['phpini'] = []
|
|||
|
|
result['userini'] = result['sshd'] = True
|
|||
|
|
result['scan'] = False
|
|||
|
|
result['outime'] = result['count'] = result['error'] = 0
|
|||
|
|
if not os.path.exists(path): return result
|
|||
|
|
import json
|
|||
|
|
return json.loads(public.readFile(path))
|
|||
|
|
|
|||
|
|
# 更新病毒库
|
|||
|
|
def UpdateRulelist(self, get):
|
|||
|
|
try:
|
|||
|
|
conf = public.httpGet(public.getUrl() + '/install/ruleList.conf')
|
|||
|
|
if conf:
|
|||
|
|
public.writeFile(self.setupPath + '/panel/data/ruleList.conf', conf)
|
|||
|
|
return public.return_msg_gettext(True, public.lang("Update Succeeded!"))
|
|||
|
|
return public.return_msg_gettext(False, public.lang("Failed to connect server!"))
|
|||
|
|
except:
|
|||
|
|
return public.return_msg_gettext(False, public.lang("Failed to connect server!"))
|
|||
|
|
|
|||
|
|
def set_site_etime_multiple(self, get):
|
|||
|
|
'''
|
|||
|
|
@name 批量网站到期时间
|
|||
|
|
@author zhwen<2020-11-17>
|
|||
|
|
@param sites_id "1,2"
|
|||
|
|
@param edate 2020-11-18
|
|||
|
|
'''
|
|||
|
|
sites_id = get.sites_id.split(',')
|
|||
|
|
set_edate_successfully = []
|
|||
|
|
set_edate_failed = {}
|
|||
|
|
for site_id in sites_id:
|
|||
|
|
get.id = site_id
|
|||
|
|
site_name = public.M('sites').where("id=?", (site_id,)).getField('name')
|
|||
|
|
if not site_name:
|
|||
|
|
continue
|
|||
|
|
try:
|
|||
|
|
self.SetEdate(get)
|
|||
|
|
set_edate_successfully.append(site_name)
|
|||
|
|
except:
|
|||
|
|
set_edate_failed[site_name] = 'There was an error setting, please try again.'
|
|||
|
|
pass
|
|||
|
|
return {'status': True, 'msg': public.get_msg_gettext('Set the website [{}] expiration time successfully', (','.join(set_edate_successfully),)),
|
|||
|
|
'error': set_edate_failed,
|
|||
|
|
'success': set_edate_successfully}
|
|||
|
|
|
|||
|
|
# 设置到期时间
|
|||
|
|
def SetEdate(self, get):
|
|||
|
|
result = public.M('sites').where('id=?', (get.id,)).setField('edate', get.edate)
|
|||
|
|
siteName = public.M('sites').where('id=?', (get.id,)).getField('name')
|
|||
|
|
public.write_log_gettext('Site manager', 'Set expired date to [{}] for site[{}]!', (get.edate,siteName))
|
|||
|
|
return public.return_msg_gettext(True, public.lang("Successfully set, the site will stop automatically when expires!"))
|
|||
|
|
|
|||
|
|
# 获取防盗链状态
|
|||
|
|
def GetSecurity(self, get):
|
|||
|
|
file = '/www/server/panel/vhost/nginx/' + get.name + '.conf'
|
|||
|
|
conf = public.readFile(file)
|
|||
|
|
|
|||
|
|
if type(conf) == bool: return public.return_msg_gettext(False, public.lang("Configuration file not exist"))
|
|||
|
|
if not isinstance(conf, str) or not conf.strip():
|
|||
|
|
return public.return_msg_gettext(False, public.lang("Configuration file not exist"))
|
|||
|
|
|
|||
|
|
data = {}
|
|||
|
|
if conf.find('SECURITY-START') != -1:
|
|||
|
|
rep = "#SECURITY-START(\n|.)+#SECURITY-END"
|
|||
|
|
tmp = re.search(rep, conf).group()
|
|||
|
|
data['fix'] = re.search(r"\(.+\)\$", tmp).group().replace('(', '').replace(')$', '').replace('|', ',')
|
|||
|
|
try:
|
|||
|
|
data['domains'] = ','.join(
|
|||
|
|
list(set(re.search("valid_referers\\s+none\\s+blocked\\s+(.+);\n", tmp).groups()[0].split())))
|
|||
|
|
except:
|
|||
|
|
data['domains'] = ','.join(list(set(re.search("valid_referers\\s+(.+);\n", tmp).groups()[0].split())))
|
|||
|
|
data['status'] = True
|
|||
|
|
data['none'] = tmp.find('none blocked') != -1
|
|||
|
|
try:
|
|||
|
|
data['return_rule'] = re.findall(r'(return|rewrite)\s+.*(\d{3}|(/.+)\s+(break|last));', conf)[0][
|
|||
|
|
1].replace('break', '').strip()
|
|||
|
|
except:
|
|||
|
|
data['return_rule'] = '404'
|
|||
|
|
else:
|
|||
|
|
data['fix'] = 'jpg,jpeg,gif,png,js,css'
|
|||
|
|
domains = public.M('domain').where('pid=?', (get.id,)).field('name').select()
|
|||
|
|
tmp = []
|
|||
|
|
for domain in domains:
|
|||
|
|
tmp.append(domain['name'])
|
|||
|
|
|
|||
|
|
data['return_rule'] = '404'
|
|||
|
|
data['domains'] = ','.join(tmp)
|
|||
|
|
data['status'] = False
|
|||
|
|
data['none'] = False
|
|||
|
|
return data
|
|||
|
|
|
|||
|
|
# 设置防盗链
|
|||
|
|
def SetSecurity(self, get):
|
|||
|
|
if len(get.fix) < 2: return public.return_msg_gettext(False, public.lang("URL suffix cannot be empty!"))
|
|||
|
|
if len(get.domains) < 3: return public.return_msg_gettext(False, public.lang("Anti-theft chain domain name cannot be empty!"))
|
|||
|
|
file = '/www/server/panel/vhost/nginx/' + get.name + '.conf'
|
|||
|
|
if os.path.exists(file):
|
|||
|
|
conf = public.readFile(file)
|
|||
|
|
if get.status == '1':
|
|||
|
|
if conf.find('SECURITY-START') == -1: return public.return_msg_gettext(False, public.lang("Please turn on the hotlink first!"))
|
|||
|
|
r_key = 'valid_referers none blocked'
|
|||
|
|
d_key = 'valid_referers'
|
|||
|
|
if conf.find(r_key) == -1:
|
|||
|
|
conf = conf.replace(d_key, r_key)
|
|||
|
|
else:
|
|||
|
|
conf = conf.replace(r_key, d_key)
|
|||
|
|
else:
|
|||
|
|
|
|||
|
|
if conf.find('SECURITY-START') != -1:
|
|||
|
|
# 先替换域名部分,防止域名过多导致替换失败
|
|||
|
|
rep = r"\s+valid_referers.+"
|
|||
|
|
conf = re.sub(rep,'',conf)
|
|||
|
|
# 再替换配置部分
|
|||
|
|
rep = "\\s+#SECURITY-START(\n|.){1,500}#SECURITY-END\n?"
|
|||
|
|
conf = re.sub(rep,'\n',conf)
|
|||
|
|
public.write_log_gettext('Site manager', "Hotlink Protection for site [{}] disabled!", (get.name,))
|
|||
|
|
else:
|
|||
|
|
return_rule = 'return 404'
|
|||
|
|
if 'return_rule' in get:
|
|||
|
|
get.return_rule = get.return_rule.strip()
|
|||
|
|
if get.return_rule in ['404', '403', '200', '301', '302', '401', '201']:
|
|||
|
|
return_rule = 'return {}'.format(get.return_rule)
|
|||
|
|
else:
|
|||
|
|
if get.return_rule[0] != '/':
|
|||
|
|
return public.return_msg_gettext(False, public.lang("Response resources should use URI path or HTTP status code, such as: /test.png or 404"))
|
|||
|
|
return_rule = 'rewrite /.* {} break'.format(get.return_rule)
|
|||
|
|
rconf = r'''%s
|
|||
|
|
location ~ .*\.(%s)$
|
|||
|
|
{
|
|||
|
|
expires 30d;
|
|||
|
|
access_log /dev/null;
|
|||
|
|
valid_referers %s;
|
|||
|
|
if ($invalid_referer){
|
|||
|
|
%s;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
#SECURITY-END
|
|||
|
|
include enable-php-''' % (("#SECURITY-START Hotlink protection configuration"), get.fix.strip().replace(',', '|'),
|
|||
|
|
get.domains.strip().replace(',', ' '), return_rule)
|
|||
|
|
conf = re.sub(r"include\s+enable-php-", rconf, conf)
|
|||
|
|
public.write_log_gettext('Site manager', "Hotlink Protection for site [{}] enabled!", (get.name,))
|
|||
|
|
public.writeFile(file, conf)
|
|||
|
|
|
|||
|
|
file = '/www/server/panel/vhost/apache/' + get.name + '.conf'
|
|||
|
|
if os.path.exists(file):
|
|||
|
|
conf = public.readFile(file)
|
|||
|
|
if get.status == '1':
|
|||
|
|
r_key = '#SECURITY-START.*\n RewriteEngine on\n RewriteCond %{HTTP_REFERER} !^$ [NC]\n'
|
|||
|
|
d_key = '#SECURITY-START.*\n RewriteEngine on\n'
|
|||
|
|
if conf.find(r_key) == -1:
|
|||
|
|
conf = conf.replace(d_key, r_key)
|
|||
|
|
else:
|
|||
|
|
if conf.find('SECURITY-START') == -1: return public.return_msg_gettext(False, public.lang("Please turn on anti-theft first!"))
|
|||
|
|
conf = conf.replace(r_key, d_key)
|
|||
|
|
else:
|
|||
|
|
if conf.find('SECURITY-START') != -1:
|
|||
|
|
rep = "#SECURITY-START(\n|.){1,500}#SECURITY-END\n"
|
|||
|
|
conf = re.sub(rep, '', conf)
|
|||
|
|
else:
|
|||
|
|
return_rule = '/404.html [R=404,NC,L]'
|
|||
|
|
if 'return_rule' in get:
|
|||
|
|
get.return_rule = get.return_rule.strip()
|
|||
|
|
if get.return_rule in ['404', '403', '200', '301', '302', '401', '201']:
|
|||
|
|
return_rule = '/{s}.html [R={s},NC,L]'.format(s=get.return_rule)
|
|||
|
|
else:
|
|||
|
|
if get.return_rule[0] != '/':
|
|||
|
|
return public.return_msg_gettext(False, public.lang("Response resources should use URI path or HTTP status code, such as: /test.png or 404"))
|
|||
|
|
return_rule = '{}'.format(get.return_rule)
|
|||
|
|
|
|||
|
|
tmp = " RewriteCond %{HTTP_REFERER} !{DOMAIN} [NC]"
|
|||
|
|
tmps = []
|
|||
|
|
for d in get.domains.split(','):
|
|||
|
|
tmps.append(tmp.replace('{DOMAIN}', d))
|
|||
|
|
domains = "\n".join(tmps)
|
|||
|
|
rconf = "combined\n " + public.get_msg_gettext(
|
|||
|
|
'#SECURITY-START Hotlink protection configuration') + "\n RewriteEngine on\n" + domains + "\n RewriteRule .(" + get.fix.strip().replace(
|
|||
|
|
',', '|') + ") " + return_rule + "\n #SECURITY-END"
|
|||
|
|
conf = conf.replace('combined', rconf)
|
|||
|
|
public.writeFile(file, conf)
|
|||
|
|
# OLS
|
|||
|
|
cond_dir = '/www/server/panel/vhost/openlitespeed/prevent_hotlink/'
|
|||
|
|
if not os.path.exists(cond_dir):
|
|||
|
|
os.makedirs(cond_dir)
|
|||
|
|
file = cond_dir + get.name + '.conf'
|
|||
|
|
if get.status == '1':
|
|||
|
|
conf = r"""
|
|||
|
|
RewriteCond %{HTTP_REFERER} !^$
|
|||
|
|
RewriteCond %{HTTP_REFERER} !YP_SSL_DOMAIN_NAME [NC]
|
|||
|
|
RewriteRule \.(YP_FILE_EXT)$ /404.html [R,NC]
|
|||
|
|
"""
|
|||
|
|
conf = conf.replace('YP_SSL_DOMAIN_NAME', get.domains.replace(',', ' ')).replace('YP_FILE_EXT',
|
|||
|
|
get.fix.replace(',', '|'))
|
|||
|
|
else:
|
|||
|
|
conf = r"""
|
|||
|
|
RewriteCond %{HTTP_REFERER} !YP_SSL_DOMAIN_NAME [NC]
|
|||
|
|
RewriteRule \.(YP_FILE_EXT)$ /404.html [R,NC]
|
|||
|
|
"""
|
|||
|
|
conf = conf.replace('YP_SSL_DOMAIN_NAME', get.domains.replace(',', ' ')).replace('YP_FILE_EXT',
|
|||
|
|
get.fix.replace(',', '|'))
|
|||
|
|
public.writeFile(file, conf)
|
|||
|
|
if get.status == "false":
|
|||
|
|
public.ExecShell('rm -f {}'.format(file))
|
|||
|
|
public.serviceReload()
|
|||
|
|
return public.return_msg_gettext(True, public.lang("Setup successfully!"))
|
|||
|
|
|
|||
|
|
# xss 防御
|
|||
|
|
def xsssec(self,text):
|
|||
|
|
replace_list = {
|
|||
|
|
"<":"<",
|
|||
|
|
">":">",
|
|||
|
|
"'":"'",
|
|||
|
|
'"':""",
|
|||
|
|
}
|
|||
|
|
for k,v in replace_list.items():
|
|||
|
|
text = text.replace(k,v)
|
|||
|
|
return public.xssencode2(text)
|
|||
|
|
|
|||
|
|
# 取网站日志
|
|||
|
|
def GetSiteLogs(self, get):
|
|||
|
|
serverType = public.get_webserver()
|
|||
|
|
if serverType == "nginx":
|
|||
|
|
logPath = '/www/wwwlogs/' + get.siteName + '.log'
|
|||
|
|
elif serverType == 'apache':
|
|||
|
|
logPath = '/www/wwwlogs/' + get.siteName + '-access_log'
|
|||
|
|
else:
|
|||
|
|
logPath = '/www/wwwlogs/' + get.siteName + '_ols.access_log'
|
|||
|
|
if not os.path.exists(logPath): return public.return_msg_gettext(False, public.lang("Log is empty"))
|
|||
|
|
return public.return_msg_gettext(True, self.xsssec(public.GetNumLines(logPath, 1000)))
|
|||
|
|
|
|||
|
|
# 取网站日志
|
|||
|
|
def get_site_err_log(self, get):
|
|||
|
|
serverType = public.get_webserver()
|
|||
|
|
if serverType == "nginx":
|
|||
|
|
logPath = '/www/wwwlogs/' + get.siteName + '.error.log'
|
|||
|
|
elif serverType == 'apache':
|
|||
|
|
logPath = '/www/wwwlogs/' + get.siteName + '-error_log'
|
|||
|
|
else:
|
|||
|
|
logPath = '/www/wwwlogs/' + get.siteName + '_ols.error_log'
|
|||
|
|
if not os.path.exists(logPath): return public.return_msg_gettext(False, public.lang("Log is empty"))
|
|||
|
|
return public.return_msg_gettext(True, self.xsssec(public.GetNumLines(logPath, 1000)))
|
|||
|
|
|
|||
|
|
# 取网站分类
|
|||
|
|
def get_site_types(self, get):
|
|||
|
|
data = public.M("site_types").field("id,name").order("id asc").select()
|
|||
|
|
if not isinstance(data, list):
|
|||
|
|
data = []
|
|||
|
|
data.insert(0, {"id": 0, "name": public.lang("Default category")})
|
|||
|
|
for i in data:
|
|||
|
|
i['name']=public.xss_version(i['name'])
|
|||
|
|
return data
|
|||
|
|
|
|||
|
|
# 添加网站分类
|
|||
|
|
def add_site_type(self, get):
|
|||
|
|
get.name = get.name.strip()
|
|||
|
|
if not get.name: return public.return_msg_gettext(False, public.lang("Category name cannot be empty"))
|
|||
|
|
if len(get.name) > 16: return public.return_msg_gettext(False, public.lang("Category name cannot exceed 16 letters"))
|
|||
|
|
type_sql = public.M('site_types')
|
|||
|
|
if type_sql.count() >= 10: return public.return_msg_gettext(False, public.lang("Add up to 10 categories!"))
|
|||
|
|
if type_sql.where('name=?', (get.name,)).count() > 0: return public.return_msg_gettext(False, public.lang("Specified category name already exists!"))
|
|||
|
|
type_sql.add("name",(public.xssencode2(get.name),))
|
|||
|
|
return public.return_msg_gettext(True, public.lang("Setup successfully!"))
|
|||
|
|
|
|||
|
|
# 删除网站分类
|
|||
|
|
def remove_site_type(self, get):
|
|||
|
|
type_sql = public.M('site_types')
|
|||
|
|
if type_sql.where('id=?', (get.id,)).count() == 0: return public.return_msg_gettext(False, public.lang("Specified category does NOT exist!"))
|
|||
|
|
type_sql.where('id=?', (get.id,)).delete()
|
|||
|
|
public.M("sites").where("type_id=?", (get.id,)).save("type_id", (0,))
|
|||
|
|
return public.return_msg_gettext(True, public.lang("Category deleted!"))
|
|||
|
|
|
|||
|
|
# 修改网站分类名称
|
|||
|
|
def modify_site_type_name(self, get):
|
|||
|
|
get.name = get.name.strip()
|
|||
|
|
if not get.name: return public.return_msg_gettext(False, public.lang("Category name cannot be empty"))
|
|||
|
|
if len(get.name) > 16: return public.return_msg_gettext(False, public.lang("Category name cannot exceed 16 letters"))
|
|||
|
|
type_sql = public.M('site_types')
|
|||
|
|
if type_sql.where('id=?', (get.id,)).count() == 0: return public.return_msg_gettext(False, public.lang("Specified category does NOT exist!"))
|
|||
|
|
type_sql.where('id=?', (get.id,)).setField('name', get.name)
|
|||
|
|
return public.return_msg_gettext(True, public.lang("Successfully modified"))
|
|||
|
|
|
|||
|
|
# 设置指定站点的分类
|
|||
|
|
def set_site_type(self, get):
|
|||
|
|
site_ids = json.loads(get.site_ids)
|
|||
|
|
site_sql = public.M("sites")
|
|||
|
|
for s_id in site_ids:
|
|||
|
|
site_sql.where("id=?", (s_id,)).setField("type_id", get.id)
|
|||
|
|
return public.returnMsg(True, public.lang("Setup successfully!"))
|
|||
|
|
|
|||
|
|
# 设置目录保护
|
|||
|
|
def set_dir_auth(self, get):
|
|||
|
|
sd = site_dir_auth.SiteDirAuth()
|
|||
|
|
return sd.set_dir_auth(get)
|
|||
|
|
|
|||
|
|
def delete_dir_auth_multiple(self, get):
|
|||
|
|
'''
|
|||
|
|
@name 批量目录保护
|
|||
|
|
@author zhwen<2020-11-17>
|
|||
|
|
@param site_id 1
|
|||
|
|
@param names test,baohu
|
|||
|
|
'''
|
|||
|
|
names = get.names.split(',')
|
|||
|
|
del_successfully = []
|
|||
|
|
del_failed = {}
|
|||
|
|
for name in names:
|
|||
|
|
get.name = name
|
|||
|
|
get.id = get.site_id
|
|||
|
|
try:
|
|||
|
|
get.multiple = 1
|
|||
|
|
result = self.delete_dir_auth(get)
|
|||
|
|
if not result['status']:
|
|||
|
|
del_failed[name] = result['msg']
|
|||
|
|
continue
|
|||
|
|
del_successfully.append(name)
|
|||
|
|
except:
|
|||
|
|
del_failed[name] = public.lang("There was an error deleting, please try again.")
|
|||
|
|
public.serviceReload()
|
|||
|
|
return {'status': True, 'msg': public.get_msg_gettext('Delete [ {} ] dir auth successfully', (','.join(del_successfully),)),
|
|||
|
|
'error': del_failed,
|
|||
|
|
'success': del_successfully}
|
|||
|
|
|
|||
|
|
# 删除目录保护
|
|||
|
|
def delete_dir_auth(self, get):
|
|||
|
|
sd = site_dir_auth.SiteDirAuth()
|
|||
|
|
return sd.delete_dir_auth(get)
|
|||
|
|
|
|||
|
|
# 获取目录保护列表
|
|||
|
|
def get_dir_auth(self, get):
|
|||
|
|
sd = site_dir_auth.SiteDirAuth()
|
|||
|
|
return sd.get_dir_auth(get)
|
|||
|
|
|
|||
|
|
# 修改目录保护密码
|
|||
|
|
def modify_dir_auth_pass(self, get):
|
|||
|
|
sd = site_dir_auth.SiteDirAuth()
|
|||
|
|
return sd.modify_dir_auth_pass(get)
|
|||
|
|
|
|||
|
|
def _check_path_total(self,path, limit):
|
|||
|
|
"""
|
|||
|
|
根据路径获取文件/目录大小
|
|||
|
|
@path 文件或者目录路径
|
|||
|
|
return int
|
|||
|
|
"""
|
|||
|
|
|
|||
|
|
if not os.path.exists(path): return 0;
|
|||
|
|
if not os.path.isdir(path): return os.path.getsize(path)
|
|||
|
|
size_total = 0
|
|||
|
|
for nf in os.walk(path):
|
|||
|
|
for f in nf[2]:
|
|||
|
|
filename = nf[0] + '/' + f
|
|||
|
|
if not os.path.exists(filename): continue;
|
|||
|
|
if os.path.islink(filename): continue;
|
|||
|
|
size_total += os.path.getsize(filename)
|
|||
|
|
if size_total >= limit: return limit
|
|||
|
|
return size_total
|
|||
|
|
|
|||
|
|
def get_average_num(self,slist):
|
|||
|
|
"""
|
|||
|
|
@获取平均值
|
|||
|
|
"""
|
|||
|
|
count = len(slist)
|
|||
|
|
limit_size = 1 * 1024 * 1024
|
|||
|
|
if count <= 0: return limit_size
|
|||
|
|
print(slist)
|
|||
|
|
if len(slist) > 1:
|
|||
|
|
slist = sorted(slist)
|
|||
|
|
limit_size =int((slist[0] + slist[-1])/2 * 0.85)
|
|||
|
|
return limit_size
|
|||
|
|
|
|||
|
|
|
|||
|
|
def check_del_data(self,get):
|
|||
|
|
"""
|
|||
|
|
@删除前置检测
|
|||
|
|
@ids = [1,2,3]
|
|||
|
|
"""
|
|||
|
|
ids = json.loads(get['ids'])
|
|||
|
|
slist = {}
|
|||
|
|
result = []
|
|||
|
|
|
|||
|
|
import database
|
|||
|
|
db_data = database.database().get_database_size(ids,True)
|
|||
|
|
limit_size = 50 * 1024 * 1024
|
|||
|
|
f_list_size = [];db_list_size = []
|
|||
|
|
for id in ids:
|
|||
|
|
data = public.M('sites').where("id=?",(id,)).field('id,name,path,addtime').find();
|
|||
|
|
if not data: continue
|
|||
|
|
|
|||
|
|
addtime = public.to_date(times = data['addtime'])
|
|||
|
|
|
|||
|
|
data['st_time'] = addtime
|
|||
|
|
data['limit'] = False
|
|||
|
|
data['backup_count'] = public.M('backup').where("pid=? AND type=?",(data['id'],'0')).count()
|
|||
|
|
f_size = self._check_path_total(data['path'],limit_size)
|
|||
|
|
data['total'] = f_size;
|
|||
|
|
data['score'] = 0
|
|||
|
|
|
|||
|
|
#目录太小不计分
|
|||
|
|
if f_size > 0:
|
|||
|
|
f_list_size.append(f_size)
|
|||
|
|
|
|||
|
|
# 10k 目录不参与排序
|
|||
|
|
if f_size > 10 * 1024: data['score'] = int(time.time() - addtime) + f_size
|
|||
|
|
|
|||
|
|
if data['total'] >= limit_size: data['limit'] = True
|
|||
|
|
data['database'] = False
|
|||
|
|
|
|||
|
|
find = public.M('databases').field('id,pid,name,ps,addtime').where('pid=?',(data['id'],)).find()
|
|||
|
|
if find:
|
|||
|
|
db_addtime = public.to_date(times = find['addtime'])
|
|||
|
|
|
|||
|
|
data['database'] = db_data[find['name']]
|
|||
|
|
data['database']['st_time'] = db_addtime
|
|||
|
|
|
|||
|
|
db_score = 0
|
|||
|
|
db_size = data['database']['total']
|
|||
|
|
|
|||
|
|
if db_size > 0:
|
|||
|
|
db_list_size.append(db_size)
|
|||
|
|
if db_size > 50 * 1024: db_score += int(time.time() - db_addtime) + db_size
|
|||
|
|
|
|||
|
|
data['score'] += db_score
|
|||
|
|
result.append(data)
|
|||
|
|
|
|||
|
|
slist['data'] = sorted(result,key= lambda x:x['score'],reverse=True)
|
|||
|
|
slist['file_size'] = self.get_average_num(f_list_size)
|
|||
|
|
slist['db_size'] = self.get_average_num(db_list_size)
|
|||
|
|
return slist
|
|||
|
|
|
|||
|
|
def get_https_mode(self, get=None):
|
|||
|
|
'''
|
|||
|
|
@name 获取https模式
|
|||
|
|
@author hwliang<2022-01-14>
|
|||
|
|
@return bool False.宽松模式 True.严格模式
|
|||
|
|
'''
|
|||
|
|
web_server = public.get_webserver()
|
|||
|
|
if web_server not in ['nginx', 'apache']:
|
|||
|
|
return False
|
|||
|
|
|
|||
|
|
if web_server == 'nginx':
|
|||
|
|
default_conf_file = "{}/nginx/0.default.conf".format(public.get_vhost_path())
|
|||
|
|
else:
|
|||
|
|
default_conf_file = "{}/apache/0.default.conf".format(public.get_vhost_path())
|
|||
|
|
|
|||
|
|
if not os.path.exists(default_conf_file): return False
|
|||
|
|
default_conf = public.readFile(default_conf_file)
|
|||
|
|
if not default_conf: return False
|
|||
|
|
|
|||
|
|
if default_conf.find('DEFAULT SSL CONFI') != -1: return True
|
|||
|
|
return False
|
|||
|
|
|
|||
|
|
def write_ngx_default_conf_by_ssl(self):
|
|||
|
|
'''
|
|||
|
|
@name 写nginx默认配置文件(含SSL配置)
|
|||
|
|
@author hwliang<2022-01-14>
|
|||
|
|
@return bool
|
|||
|
|
'''
|
|||
|
|
default_conf_body = '''server
|
|||
|
|
{
|
|||
|
|
listen 80;
|
|||
|
|
listen 443 ssl;
|
|||
|
|
server_name _;
|
|||
|
|
index index.html;
|
|||
|
|
root /www/server/nginx/html;
|
|||
|
|
|
|||
|
|
# DEFAULT SSL CONFIG
|
|||
|
|
ssl_certificate /www/server/panel/vhost/cert/0.default/fullchain.pem;
|
|||
|
|
ssl_certificate_key /www/server/panel/vhost/cert/0.default/privkey.pem;
|
|||
|
|
ssl_protocols TLSv1.2 TLSv1.3;
|
|||
|
|
ssl_ciphers EECDH+CHACHA20:EECDH+CHACHA20-draft:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES:!MD5;
|
|||
|
|
ssl_prefer_server_ciphers off;
|
|||
|
|
ssl_session_cache shared:SSL:10m;
|
|||
|
|
ssl_session_timeout 10m;
|
|||
|
|
add_header Strict-Transport-Security "max-age=31536000";
|
|||
|
|
}'''
|
|||
|
|
ngx_default_conf_file = "{}/nginx/0.default.conf".format(public.get_vhost_path())
|
|||
|
|
self.create_default_cert()
|
|||
|
|
return public.writeFile(ngx_default_conf_file, default_conf_body)
|
|||
|
|
|
|||
|
|
def write_ngx_default_conf(self):
|
|||
|
|
'''
|
|||
|
|
@name 写nginx默认配置文件
|
|||
|
|
@author hwliang<2022-01-14>
|
|||
|
|
@return bool
|
|||
|
|
'''
|
|||
|
|
default_conf_body = '''server
|
|||
|
|
{
|
|||
|
|
listen 80;
|
|||
|
|
server_name _;
|
|||
|
|
index index.html;
|
|||
|
|
root /www/server/nginx/html;
|
|||
|
|
}'''
|
|||
|
|
ngx_default_conf_file = "{}/nginx/0.default.conf".format(public.get_vhost_path())
|
|||
|
|
return public.writeFile(ngx_default_conf_file, default_conf_body)
|
|||
|
|
|
|||
|
|
def write_apa_default_conf_by_ssl(self):
|
|||
|
|
'''
|
|||
|
|
@name 写nginx默认配置文件(含SSL配置)
|
|||
|
|
@author hwliang<2022-01-14>
|
|||
|
|
@return bool
|
|||
|
|
'''
|
|||
|
|
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
|
|||
|
|
<Directory "/www/server/apache/htdocs">
|
|||
|
|
SetOutputFilter DEFLATE
|
|||
|
|
Options FollowSymLinks
|
|||
|
|
AllowOverride All
|
|||
|
|
Order allow,deny
|
|||
|
|
Allow from all
|
|||
|
|
DirectoryIndex index.html
|
|||
|
|
</Directory>
|
|||
|
|
</VirtualHost>
|
|||
|
|
<VirtualHost *:{port_443}>
|
|||
|
|
ServerAdmin webmaster@example.com
|
|||
|
|
DocumentRoot "/www/server/apache/htdocs"
|
|||
|
|
ServerName ssl.default.com
|
|||
|
|
|
|||
|
|
# DEFAULT SSL CONFIG
|
|||
|
|
SSLEngine On
|
|||
|
|
SSLCertificateFile /www/server/panel/vhost/cert/0.default/fullchain.pem
|
|||
|
|
SSLCertificateKeyFile /www/server/panel/vhost/cert/0.default/privkey.pem
|
|||
|
|
SSLCipherSuite EECDH+CHACHA20:EECDH+CHACHA20-draft:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES:!MD5
|
|||
|
|
SSLProtocol All -SSLv2 -SSLv3 -TLSv1
|
|||
|
|
SSLHonorCipherOrder On
|
|||
|
|
|
|||
|
|
<Directory "/www/server/apache/htdocs">
|
|||
|
|
SetOutputFilter DEFLATE
|
|||
|
|
Options FollowSymLinks
|
|||
|
|
AllowOverride All
|
|||
|
|
Order allow,deny
|
|||
|
|
Allow from all
|
|||
|
|
DirectoryIndex index.html
|
|||
|
|
</Directory>
|
|||
|
|
</VirtualHost>'''
|
|||
|
|
apa_default_conf_file = "{}/apache/0.default.conf".format(public.get_vhost_path())
|
|||
|
|
self.create_default_cert()
|
|||
|
|
return public.writeFile(apa_default_conf_file, default_conf_body)
|
|||
|
|
|
|||
|
|
def write_apa_default_conf(self):
|
|||
|
|
'''
|
|||
|
|
@name 写apache默认配置文件
|
|||
|
|
@author hwliang<2022-01-14>
|
|||
|
|
@return bool
|
|||
|
|
'''
|
|||
|
|
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
|
|||
|
|
<Directory "/www/server/apache/htdocs">
|
|||
|
|
SetOutputFilter DEFLATE
|
|||
|
|
Options FollowSymLinks
|
|||
|
|
AllowOverride All
|
|||
|
|
Order allow,deny
|
|||
|
|
Allow from all
|
|||
|
|
DirectoryIndex index.html
|
|||
|
|
</Directory>
|
|||
|
|
</VirtualHost>'''
|
|||
|
|
apa_default_conf_file = "{}/apache/0.default.conf".format(public.get_vhost_path())
|
|||
|
|
return public.writeFile(apa_default_conf_file, default_conf_body)
|
|||
|
|
|
|||
|
|
def set_https_mode(self, get=None):
|
|||
|
|
'''
|
|||
|
|
@name 设置https模式
|
|||
|
|
@author hwliang<2022-01-14>
|
|||
|
|
@return dict
|
|||
|
|
'''
|
|||
|
|
web_server = public.get_webserver()
|
|||
|
|
if web_server not in ['nginx', 'apache']:
|
|||
|
|
return public.return_msg_gettext(False, public.lang("This function only supports Nginx/Apache"))
|
|||
|
|
|
|||
|
|
ngx_default_conf_file = "{}/nginx/0.default.conf".format(public.get_vhost_path())
|
|||
|
|
apa_default_conf_file = "{}/apache/0.default.conf".format(public.get_vhost_path())
|
|||
|
|
ngx_default_conf = public.readFile(ngx_default_conf_file)
|
|||
|
|
apa_default_conf = public.readFile(apa_default_conf_file)
|
|||
|
|
status = False
|
|||
|
|
if ngx_default_conf:
|
|||
|
|
if ngx_default_conf.find('DEFAULT SSL CONFIG') != -1:
|
|||
|
|
status = False
|
|||
|
|
self.write_ngx_default_conf()
|
|||
|
|
self.write_apa_default_conf()
|
|||
|
|
else:
|
|||
|
|
status = True
|
|||
|
|
self.write_ngx_default_conf_by_ssl()
|
|||
|
|
self.write_apa_default_conf_by_ssl()
|
|||
|
|
else:
|
|||
|
|
status = True
|
|||
|
|
self.write_ngx_default_conf_by_ssl()
|
|||
|
|
self.write_apa_default_conf_by_ssl()
|
|||
|
|
|
|||
|
|
public.serviceReload()
|
|||
|
|
status_msg = {True: 'Open', False: 'Close'}
|
|||
|
|
msg = public.gettext_msg('Has {} HTTPS strict mode',(status_msg[status],))
|
|||
|
|
public.write_log_gettext('WebSite manager', msg)
|
|||
|
|
return public.return_msg_gettext(True, msg)
|
|||
|
|
|
|||
|
|
def create_default_cert(self):
|
|||
|
|
'''
|
|||
|
|
@name 创建默认SSL证书
|
|||
|
|
@author hwliang<2022-01-14>
|
|||
|
|
@return bool
|
|||
|
|
'''
|
|||
|
|
cert_pem = '/www/server/panel/vhost/cert/0.default/fullchain.pem'
|
|||
|
|
cert_key = '/www/server/panel/vhost/cert/0.default/privkey.pem'
|
|||
|
|
if os.path.exists(cert_pem) and os.path.exists(cert_key): return True
|
|||
|
|
cert_path = os.path.dirname(cert_pem)
|
|||
|
|
if not os.path.exists(cert_path): os.makedirs(cert_path)
|
|||
|
|
import OpenSSL
|
|||
|
|
key = OpenSSL.crypto.PKey()
|
|||
|
|
key.generate_key(OpenSSL.crypto.TYPE_RSA, 2048)
|
|||
|
|
cert = OpenSSL.crypto.X509()
|
|||
|
|
cert.set_serial_number(0)
|
|||
|
|
# cert.get_subject().CN = ''
|
|||
|
|
cert.set_issuer(cert.get_subject())
|
|||
|
|
cert.gmtime_adj_notBefore(0)
|
|||
|
|
cert.gmtime_adj_notAfter(86400 * 3650)
|
|||
|
|
cert.set_pubkey(key)
|
|||
|
|
cert.sign(key, 'md5')
|
|||
|
|
cert_ca = OpenSSL.crypto.dump_certificate(OpenSSL.crypto.FILETYPE_PEM, cert)
|
|||
|
|
private_key = OpenSSL.crypto.dump_privatekey(OpenSSL.crypto.FILETYPE_PEM, key)
|
|||
|
|
if len(cert_ca) > 100 and len(private_key) > 100:
|
|||
|
|
public.writeFile(cert_pem, cert_ca, 'wb+')
|
|||
|
|
public.writeFile(cert_key, private_key, 'wb+')
|
|||
|
|
return True
|
|||
|
|
return False
|
|||
|
|
|
|||
|
|
def get_upload_ssl_list(self, get):
|
|||
|
|
"""
|
|||
|
|
@获取上传证书列表
|
|||
|
|
@siteName string 网站名称
|
|||
|
|
"""
|
|||
|
|
siteName = get['siteName']
|
|||
|
|
path = '{}/vhost/upload_ssl/{}'.format(public.get_panel_path(), siteName)
|
|||
|
|
if not os.path.exists(path): os.makedirs(path)
|
|||
|
|
|
|||
|
|
res = []
|
|||
|
|
for filename in os.listdir(path):
|
|||
|
|
try:
|
|||
|
|
filename = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(int(filename)))
|
|||
|
|
res.append(filename)
|
|||
|
|
except:
|
|||
|
|
pass
|
|||
|
|
return res
|
|||
|
|
|
|||
|
|
# 获取指定证书基本信息
|
|||
|
|
def get_cert_init(self, cert_data, ssl_info=None):
|
|||
|
|
"""
|
|||
|
|
@获取指定证书基本信息
|
|||
|
|
@cert_data string 证书数据
|
|||
|
|
@ssl_info dict 证书信息
|
|||
|
|
"""
|
|||
|
|
try:
|
|||
|
|
result = {}
|
|||
|
|
if ssl_info and ssl_info['ssl_type'] == 'pfx':
|
|||
|
|
x509 = self.__check_pfx_pwd(cert_data, ssl_info['pwd'])[0]
|
|||
|
|
else:
|
|||
|
|
x509 = OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM, cert_data)
|
|||
|
|
# 取产品名称
|
|||
|
|
issuer = x509.get_issuer()
|
|||
|
|
result['issuer'] = ''
|
|||
|
|
if hasattr(issuer, 'CN'):
|
|||
|
|
result['issuer'] = issuer.CN
|
|||
|
|
if not result['issuer']:
|
|||
|
|
is_key = [b'0', '0']
|
|||
|
|
issue_comp = issuer.get_components()
|
|||
|
|
if len(issue_comp) == 1:
|
|||
|
|
is_key = [b'CN', 'CN']
|
|||
|
|
for iss in issue_comp:
|
|||
|
|
if iss[0] in is_key:
|
|||
|
|
result['issuer'] = iss[1].decode()
|
|||
|
|
break
|
|||
|
|
# 取到期时间
|
|||
|
|
result['notAfter'] = self.strf_date(
|
|||
|
|
bytes.decode(x509.get_notAfter())[:-1])
|
|||
|
|
# 取申请时间
|
|||
|
|
result['notBefore'] = self.strf_date(
|
|||
|
|
bytes.decode(x509.get_notBefore())[:-1])
|
|||
|
|
# 取可选名称
|
|||
|
|
result['dns'] = []
|
|||
|
|
for i in range(x509.get_extension_count()):
|
|||
|
|
s_name = x509.get_extension(i)
|
|||
|
|
if s_name.get_short_name() in [b'subjectAltName', 'subjectAltName']:
|
|||
|
|
s_dns = str(s_name).split(',')
|
|||
|
|
for d in s_dns:
|
|||
|
|
result['dns'].append(d.split(':')[1])
|
|||
|
|
subject = x509.get_subject().get_components()
|
|||
|
|
|
|||
|
|
# 取主要认证名称
|
|||
|
|
if len(subject) == 1:
|
|||
|
|
result['subject'] = subject[0][1].decode()
|
|||
|
|
else:
|
|||
|
|
if len(result['dns']) > 0:
|
|||
|
|
result['subject'] = result['dns'][0]
|
|||
|
|
else:
|
|||
|
|
result['subject'] = '';
|
|||
|
|
return result
|
|||
|
|
except:
|
|||
|
|
return False
|
|||
|
|
|
|||
|
|
def strf_date(self, sdate):
|
|||
|
|
"""
|
|||
|
|
@转换证书时间
|
|||
|
|
"""
|
|||
|
|
return time.strftime('%Y-%m-%d', time.strptime(sdate, '%Y%m%d%H%M%S'))
|
|||
|
|
|
|||
|
|
def check_ssl_endtime(self, data, ssl_info=None):
|
|||
|
|
"""
|
|||
|
|
@检查证书是否有效(证书最高有效期不超过1年)
|
|||
|
|
@data string 证书数据
|
|||
|
|
@ssl_info dict 证书信息
|
|||
|
|
"""
|
|||
|
|
info = self.get_cert_init(data, ssl_info)
|
|||
|
|
if info:
|
|||
|
|
end_time = time.mktime(time.strptime(info['notAfter'], "%Y-%m-%d"))
|
|||
|
|
start_time = time.mktime(time.strptime(info['notBefore'], "%Y-%m-%d"))
|
|||
|
|
|
|||
|
|
days = int((end_time - start_time) / 86400)
|
|||
|
|
if days < 400: # 1年有效期+1个月续签时间
|
|||
|
|
return data
|
|||
|
|
return False
|
|||
|
|
|
|||
|
|
# 证书转为pkcs12
|
|||
|
|
def dump_pkcs12(self, key_pem=None, cert_pem=None, ca_pem=None, friendly_name=None):
|
|||
|
|
"""
|
|||
|
|
@证书转为pkcs12
|
|||
|
|
@key_pem string 私钥数据
|
|||
|
|
@cert_pem string 证书数据
|
|||
|
|
@ca_pem string 可选的CA证书数据
|
|||
|
|
@friendly_name string 可选的证书名称
|
|||
|
|
"""
|
|||
|
|
p12 = OpenSSL.crypto.PKCS12()
|
|||
|
|
if cert_pem:
|
|||
|
|
x509 = OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM, cert_pem.encode())
|
|||
|
|
p12.set_certificate(x509)
|
|||
|
|
if key_pem:
|
|||
|
|
p12.set_privatekey(OpenSSL.crypto.load_privatekey(
|
|||
|
|
OpenSSL.crypto.FILETYPE_PEM, key_pem.encode()))
|
|||
|
|
if ca_pem:
|
|||
|
|
p12.set_ca_certificates((OpenSSL.crypto.load_certificate(
|
|||
|
|
OpenSSL.crypto.FILETYPE_PEM, ca_pem.encode()),))
|
|||
|
|
if friendly_name:
|
|||
|
|
p12.set_friendlyname(friendly_name.encode())
|
|||
|
|
return p12
|
|||
|
|
|
|||
|
|
def download_cert(self, get):
|
|||
|
|
"""
|
|||
|
|
@下载证书
|
|||
|
|
@get dict 请求参数
|
|||
|
|
siteName string 网站名称
|
|||
|
|
ssl_type string 证书类型
|
|||
|
|
key string 密钥
|
|||
|
|
pem string 证书数据
|
|||
|
|
pwd string 证书密码
|
|||
|
|
"""
|
|||
|
|
pem = get['pem']
|
|||
|
|
siteName = get['siteName']
|
|||
|
|
ssl_type = get['ssl_type']
|
|||
|
|
|
|||
|
|
rpath = '{}/temp/ssl/'.format(public.get_panel_path())
|
|||
|
|
if os.path.exists(rpath): shutil.rmtree(rpath)
|
|||
|
|
|
|||
|
|
ca_list = []
|
|||
|
|
path = '{}/{}_{}'.format(rpath, siteName, int(time.time()))
|
|||
|
|
if ssl_type == 'pfx':
|
|||
|
|
res = self.__check_pfx_pwd(base64.b64decode(pem), get['pwd'])
|
|||
|
|
p12 = res[1];
|
|||
|
|
x509 = res[0];
|
|||
|
|
get['pwd'] = res[2]
|
|||
|
|
print(get['pwd'])
|
|||
|
|
ca_list = []
|
|||
|
|
for x in p12.get_ca_certificates():
|
|||
|
|
ca_list.insert(0, OpenSSL.crypto.dump_certificate(OpenSSL.crypto.FILETYPE_PEM, x).decode().strip())
|
|||
|
|
ca_cert = '\n'.join(ca_list)
|
|||
|
|
key = OpenSSL.crypto.dump_privatekey(OpenSSL.crypto.FILETYPE_PEM, p12.get_privatekey()).decode().strip()
|
|||
|
|
domain_cert = OpenSSL.crypto.dump_certificate(OpenSSL.crypto.FILETYPE_PEM, x509).decode().strip()
|
|||
|
|
else:
|
|||
|
|
key = get['key']
|
|||
|
|
domain_cert = pem.split('-----END CERTIFICATE-----')[0] + "-----END CERTIFICATE-----\n"
|
|||
|
|
ca_cert = pem.replace(domain_cert, '')
|
|||
|
|
|
|||
|
|
p12 = self.dump_pkcs12(key, '{}\n{}'.format(domain_cert.strip(), ca_cert), ca_cert)
|
|||
|
|
|
|||
|
|
for x in ['IIS', 'Apache', 'Nginx', 'Other']:
|
|||
|
|
d_file = '{}/{}'.format(path, x)
|
|||
|
|
if not os.path.exists(d_file): os.makedirs(d_file)
|
|||
|
|
|
|||
|
|
if x == 'IIS':
|
|||
|
|
public.writeFile2(d_file + '/fullchain.pfx', p12.export(), 'wb+')
|
|||
|
|
public.writeFile(d_file + '/password.txt', get['pwd'])
|
|||
|
|
elif x == 'Apache':
|
|||
|
|
public.writeFile(d_file + '/privkey.key', key)
|
|||
|
|
public.writeFile(d_file + '/root_bundle.crt', ca_cert)
|
|||
|
|
public.writeFile(d_file + '/domain.crt', domain_cert)
|
|||
|
|
else:
|
|||
|
|
public.writeFile(d_file + '/privkey.key', key)
|
|||
|
|
public.writeFile(d_file + '/fullchain.pem', '{}\n{}'.format(domain_cert.strip(), ca_cert))
|
|||
|
|
|
|||
|
|
flist = []
|
|||
|
|
public.get_file_list(path, flist)
|
|||
|
|
|
|||
|
|
zfile = '{}/{}.zip'.format(rpath, os.path.basename(path))
|
|||
|
|
import zipfile
|
|||
|
|
f = zipfile.ZipFile(zfile, 'w', zipfile.ZIP_DEFLATED)
|
|||
|
|
for item in flist:
|
|||
|
|
s_path = item.replace(path, '')
|
|||
|
|
if s_path: f.write(item, s_path)
|
|||
|
|
f.close()
|
|||
|
|
|
|||
|
|
return public.returnMsg(True, zfile);
|
|||
|
|
|
|||
|
|
def check_ssl_info(self, get):
|
|||
|
|
"""
|
|||
|
|
@解析证书信息
|
|||
|
|
@get dict 请求参数
|
|||
|
|
path string 上传文件路径
|
|||
|
|
"""
|
|||
|
|
path = get['path']
|
|||
|
|
if not os.path.exists(path):
|
|||
|
|
return public.returnMsg(False, public.lang("Query failed , does not exist address"))
|
|||
|
|
|
|||
|
|
info = {'root': '', 'cert': '', 'pem': '', 'key': ''}
|
|||
|
|
ssl_info = {'pwd': None, 'ssl_type': None}
|
|||
|
|
for filename in os.listdir(path):
|
|||
|
|
filepath = '{}/{}'.format(path, filename)
|
|||
|
|
ext = filename[-4:]
|
|||
|
|
if ext == '.pfx':
|
|||
|
|
ssl_info['ssl_type'] = 'pfx'
|
|||
|
|
|
|||
|
|
f = open(filepath, 'rb') # pfx为二进制文件
|
|||
|
|
info['pem'] = f.read()
|
|||
|
|
|
|||
|
|
else:
|
|||
|
|
data = public.readFile(filepath)
|
|||
|
|
if filename.find('password') >= 0: # 取pfx密码
|
|||
|
|
ssl_info['pwd'] = re.search('([a-zA-Z0-9]+)', data).groups()[0]
|
|||
|
|
continue
|
|||
|
|
|
|||
|
|
if len(data) < 1024:
|
|||
|
|
continue
|
|||
|
|
|
|||
|
|
if data.find('PRIVATE KEY') >= 0:
|
|||
|
|
info['key'] = data # 取key
|
|||
|
|
|
|||
|
|
if ext == '.pem':
|
|||
|
|
if self.check_ssl_endtime(data):
|
|||
|
|
info['pem'] = data
|
|||
|
|
else:
|
|||
|
|
if data.find('BEGIN CERTIFICATE') >= 0:
|
|||
|
|
if not info['root']:
|
|||
|
|
info['root'] = data
|
|||
|
|
else:
|
|||
|
|
info['cert'] = data
|
|||
|
|
|
|||
|
|
if ssl_info['ssl_type'] == 'pfx':
|
|||
|
|
info['pem'] = self.check_ssl_endtime(info['pem'], ssl_info)
|
|||
|
|
if info['pem']:
|
|||
|
|
info['pem'] = base64.b64encode(info['pem'])
|
|||
|
|
info['key'] = True
|
|||
|
|
else:
|
|||
|
|
if not info['pem']:
|
|||
|
|
# 确认ca证书和域名证书顺序
|
|||
|
|
info['pem'] = self.check_ssl_endtime(info['root'] + "\n" + info['cert'], ssl_info)
|
|||
|
|
if not info['pem']:
|
|||
|
|
info['pem'] = self.check_ssl_endtime(info['cert'] + "\n" + info['root'], ssl_info)
|
|||
|
|
|
|||
|
|
if info['key'] and info['pem']:
|
|||
|
|
return {'key': info['key'], 'pem': info['pem'], 'ssl_type': ssl_info['ssl_type'], 'pwd': ssl_info['pwd']}
|
|||
|
|
return False
|
|||
|
|
|
|||
|
|
def __check_pfx_pwd(self, data, pwd):
|
|||
|
|
"""
|
|||
|
|
@检测pfx证书密码
|
|||
|
|
@data string pfx证书内容
|
|||
|
|
@pwd string 密码
|
|||
|
|
"""
|
|||
|
|
try:
|
|||
|
|
p12 = OpenSSL.crypto.load_pkcs12(data, pwd)
|
|||
|
|
x509 = p12.get_certificate()
|
|||
|
|
except:
|
|||
|
|
pwd = re.search('([a-zA-Z0-9]+)', pwd).groups()[0]
|
|||
|
|
p12 = OpenSSL.crypto.load_pkcs12(data, pwd)
|
|||
|
|
x509 = p12.get_certificate()
|
|||
|
|
return [x509, p12, pwd]
|
|||
|
|
|
|||
|
|
def auto_restart_rph(self,get):
|
|||
|
|
#设置申请或续签SSL时自动停止反向代理、重定向、http to https,申请完成后自动开启
|
|||
|
|
conf_file = '{}/data/stop_rp_when_renew_ssl.pl'.format(public.get_panel_path())
|
|||
|
|
conf = public.readFile(conf_file)
|
|||
|
|
if not conf:
|
|||
|
|
public.writeFile(conf_file,json.dumps([get.sitename]))
|
|||
|
|
try:
|
|||
|
|
conf = json.loads(conf)
|
|||
|
|
if get.sitename not in conf:
|
|||
|
|
conf.append(get.sitename)
|
|||
|
|
public.writeFile(conf_file,json.dumps(conf))
|
|||
|
|
except:
|
|||
|
|
return public.returnMsg(True, public.lang("Error parsing configuration file"))
|
|||
|
|
return public.returnMsg(True, public.lang("Setup successfully"))
|
|||
|
|
|
|||
|
|
def remove_auto_restart_rph(self,get):
|
|||
|
|
#设置申请或续签SSL时自动停止反向代理、重定向、http to https,申请完成后自动开启
|
|||
|
|
conf_file = '{}/data/stop_rp_when_renew_ssl.pl'.format(public.get_panel_path())
|
|||
|
|
conf = public.readFile(conf_file)
|
|||
|
|
if not conf:
|
|||
|
|
return public.returnMsg(False, public.lang("Website [proxy,redirect,http to https] are not set to restart automatically"))
|
|||
|
|
try:
|
|||
|
|
conf = json.loads(conf)
|
|||
|
|
conf.remove(get.sitename)
|
|||
|
|
public.writeFile(conf_file,json.dumps(conf))
|
|||
|
|
except:
|
|||
|
|
return public.returnMsg(False, public.lang("Configuration file parsing error"))
|
|||
|
|
return public.returnMsg(True, public.lang("Setup successfully"))
|
|||
|
|
|
|||
|
|
def get_auto_restart_rph(self,get):
|
|||
|
|
#设置申请或续签SSL时自动停止反向代理、重定向、http to https,申请完成后自动开启
|
|||
|
|
conf_file = '{}/data/stop_rp_when_renew_ssl.pl'.format(public.get_panel_path())
|
|||
|
|
conf = public.readFile(conf_file)
|
|||
|
|
if not conf:
|
|||
|
|
return public.returnMsg(False, public.lang("Website [proxy,redirect,http to https] are not set to restart automatically"))
|
|||
|
|
try:
|
|||
|
|
conf = json.loads(conf)
|
|||
|
|
if get.sitename in conf:
|
|||
|
|
return public.returnMsg(True, public.lang("This website has turn on [proxy,redirect,http to https] auto restart"))
|
|||
|
|
return public.returnMsg(False, public.lang("Website has turn off auto restart"))
|
|||
|
|
except:
|
|||
|
|
return public.returnMsg(False, public.lang("Configuration file parsing error"))
|
|||
|
|
|
|||
|
|
def reset_wp_password(self,get):
|
|||
|
|
return one_key_wp.one_key_wp().reset_wp_password(get)
|
|||
|
|
|
|||
|
|
def is_update (self,get):
|
|||
|
|
return one_key_wp.one_key_wp().is_update(get)
|
|||
|
|
|
|||
|
|
def purge_all_cache(self,get):
|
|||
|
|
return one_key_wp.one_key_wp().purge_all_cache(get)
|
|||
|
|
|
|||
|
|
def set_fastcgi_cache(self,get):
|
|||
|
|
return one_key_wp.one_key_wp().set_fastcgi_cache(get)
|
|||
|
|
|
|||
|
|
def update_wp(self,get):
|
|||
|
|
return one_key_wp.one_key_wp().update_wp(get)
|
|||
|
|
|
|||
|
|
def get_language(self,get):
|
|||
|
|
return one_key_wp.one_key_wp().get_language(get)
|
|||
|
|
|
|||
|
|
def deploy_wp(self,get):
|
|||
|
|
return one_key_wp.one_key_wp().deploy_wp(get)
|
|||
|
|
|
|||
|
|
def get_wp_username(self,get):
|
|||
|
|
return one_key_wp.one_key_wp().get_wp_username(get)
|
|||
|
|
|
|||
|
|
def reset_wp_db(self,get):
|
|||
|
|
return one_key_wp.one_key_wp().reset_wp_db(get)
|
|||
|
|
|
|||
|
|
@staticmethod
|
|||
|
|
def test_domains_api(get):
|
|||
|
|
try:
|
|||
|
|
domains = json.loads(get.domains.strip())
|
|||
|
|
except (json.JSONDecodeError, AttributeError, KeyError):
|
|||
|
|
return public.returnMsg(False, public.lang("parameter error"))
|
|||
|
|
try:
|
|||
|
|
from panelDnsapi import DnsMager
|
|||
|
|
public.print_log("开始测试域名解析---- {}")
|
|||
|
|
# public.print_log("开始测试域名解析---- {}".format(domains[0]))
|
|||
|
|
|
|||
|
|
return DnsMager().test_domains_api(domains)
|
|||
|
|
except:
|
|||
|
|
pass
|
|||
|
|
|
|||
|
|
@staticmethod
|
|||
|
|
def get_ssl_protocol(get):
|
|||
|
|
""" 获取全局TLS版本
|
|||
|
|
@author baozi <202-04-18>
|
|||
|
|
@param:
|
|||
|
|
@return
|
|||
|
|
"""
|
|||
|
|
protocols = {
|
|||
|
|
"TLSv1": False,
|
|||
|
|
"TLSv1.1": True,
|
|||
|
|
"TLSv1.2": True,
|
|||
|
|
"TLSv1.3": False,
|
|||
|
|
}
|
|||
|
|
file_path = public.get_panel_path() + "/data/ssl_protocol.json"
|
|||
|
|
if os.path.exists(file_path):
|
|||
|
|
data = public.readFile(file_path)
|
|||
|
|
if data is not False:
|
|||
|
|
protocols = json.loads(data)
|
|||
|
|
return protocols
|
|||
|
|
|
|||
|
|
return protocols
|
|||
|
|
|
|||
|
|
def site_rname(self, get):
|
|||
|
|
try:
|
|||
|
|
if not (hasattr(get, "id") and hasattr(get, "rname")):
|
|||
|
|
return public.returnMsg(False, public.lang("parameter error"))
|
|||
|
|
id = get.id
|
|||
|
|
rname = get.rname
|
|||
|
|
data = public.M('sites').where("id=?", (id,)).select()
|
|||
|
|
if not data:
|
|||
|
|
return public.returnMsg(False, public.lang("The site does not exist!"))
|
|||
|
|
data = data[0]
|
|||
|
|
name = data['rname'] if 'rname' in data.keys() and data.get('rname', '') else data['name']
|
|||
|
|
if 'rname' not in data.keys():
|
|||
|
|
public.M('sites').execute("ALTER TABLE 'sites' ADD 'rname' text DEFAULT ''", ())
|
|||
|
|
public.M('sites').where('id=?', data['id']).update({'rname': rname})
|
|||
|
|
# public.write_log_gettext('Site manager', 'Website [{}] renamed: [{}]'.format(name, rname))
|
|||
|
|
return public.returnMsg(True, public.lang("Website [{}] renamed: [{}]", name, rname))
|
|||
|
|
except:
|
|||
|
|
import traceback
|
|||
|
|
return public.returnMsg(False, traceback.format_exc())
|