# coding: utf-8
import time
import os
import sys
from urllib.parse import urlparse
import mw
import re
import json
import shutil
from flask import request
class site_api:
siteName = None # 网站名称
sitePath = None # 根目录
sitePort = None # 端口
phpVersion = None # PHP版本
setupPath = None # 安装路径
vhostPath = None
logsPath = None
passPath = None
rewritePath = None
redirectPath = None
sslDir = None # ssl目录
sslLetsDir = None # lets ssl目录
def __init__(self):
# nginx conf
self.setupPath = mw.getServerDir() + '/web_conf'
self.vhostPath = vhost = self.setupPath + '/nginx/vhost'
if not os.path.exists(vhost):
mw.execShell("mkdir -p " + vhost + " && chmod -R 755 " + vhost)
self.rewritePath = rewrite = self.setupPath + '/nginx/rewrite'
if not os.path.exists(rewrite):
mw.execShell("mkdir -p " + rewrite + " && chmod -R 755 " + rewrite)
self.passPath = passwd = self.setupPath + '/nginx/pass'
if not os.path.exists(passwd):
mw.execShell("mkdir -p " + passwd + " && chmod -R 755 " + passwd)
self.redirectPath = redirect = self.setupPath + '/nginx/redirect'
if not os.path.exists(redirect):
mw.execShell("mkdir -p " + redirect +
" && chmod -R 755 " + redirect)
self.proxyPath = proxy = self.setupPath + '/nginx/proxy'
if not os.path.exists(proxy):
mw.execShell("mkdir -p " + proxy + " && chmod -R 755 " + proxy)
self.logsPath = mw.getRootDir() + '/wwwlogs'
# ssl conf
self.sslDir = self.setupPath + '/ssl'
self.sslLetsDir = self.setupPath + '/letsencrypt'
if not os.path.exists(self.sslLetsDir):
mw.execShell("mkdir -p " + self.sslLetsDir +
" && chmod -R 755 " + self.sslLetsDir)
##### ----- start ----- ###
def listApi(self):
limit = request.form.get('limit', '10')
p = request.form.get('p', '1')
type_id = request.form.get('type_id', '')
start = (int(p) - 1) * (int(limit))
siteM = mw.M('sites')
if type_id != '' and type_id == '-1' and type_id == '0':
siteM.where('type_id=?', (type_id))
_list = siteM.field('id,name,path,status,ps,addtime,edate').limit(
(str(start)) + ',' + limit).order('id desc').select()
for i in range(len(_list)):
_list[i]['backup_count'] = mw.M('backup').where(
"pid=? AND type=?", (_list[i]['id'], 0)).count()
_ret = {}
_ret['data'] = _list
count = siteM.count()
_page = {}
_page['count'] = count
_page['tojs'] = 'getWeb'
_page['p'] = p
_page['row'] = limit
_ret['page'] = mw.getPage(_page)
return mw.getJson(_ret)
def setDefaultSiteApi(self):
name = request.form.get('name', '')
import time
# 清理旧的
default_site = mw.readFile('data/default_site.pl')
if default_site:
path = self.getHostConf(default_site)
if os.path.exists(path):
conf = mw.readFile(path)
rep = "listen\s+80.+;"
conf = re.sub(rep, 'listen 80;', conf, 1)
rep = "listen\s+443.+;"
conf = re.sub(rep, 'listen 443 ssl;', conf, 1)
mw.writeFile(path, conf)
path = self.getHostConf(name)
if os.path.exists(path):
conf = mw.readFile(path)
rep = "listen\s+80\s*;"
conf = re.sub(rep, 'listen 80 default_server;', conf, 1)
rep = "listen\s+443\s*ssl\s*\w*\s*;"
conf = re.sub(rep, 'listen 443 ssl default_server;', conf, 1)
mw.writeFile(path, conf)
mw.writeFile('data/default_site.pl', name)
mw.restartWeb()
return mw.returnJson(True, '设置成功!')
def getDefaultSiteApi(self):
data = {}
data['sites'] = mw.M('sites').field(
'name').order('id desc').select()
data['default_site'] = mw.readFile('data/default_site.pl')
return mw.getJson(data)
def setPsApi(self):
mid = request.form.get('id', '')
ps = request.form.get('ps', '')
if mw.M('sites').where("id=?", (mid,)).setField('ps', ps):
return mw.returnJson(True, '修改成功!')
return mw.returnJson(False, '修改失败!')
def stopApi(self):
mid = request.form.get('id', '')
name = request.form.get('name', '')
return self.stop(mid, name)
def stop(self, mid, name):
path = self.setupPath + '/stop'
if not os.path.exists(path):
os.makedirs(path)
default_text = 'The website has been closed!!!'
mw.writeFile(path + '/index.html', default_text)
binding = mw.M('binding').where('pid=?', (mid,)).field(
'id,pid,domain,path,port,addtime').select()
for b in binding:
bpath = path + '/' + b['path']
if not os.path.exists(bpath):
mw.execShell('mkdir -p ' + bpath)
mw.execShell('ln -sf ' + path +
'/index.html ' + bpath + '/index.html')
sitePath = mw.M('sites').where("id=?", (mid,)).getField('path')
# nginx
file = self.getHostConf(name)
conf = mw.readFile(file)
if conf:
conf = conf.replace(sitePath, path)
mw.writeFile(file, conf)
mw.M('sites').where("id=?", (mid,)).setField('status', '0')
mw.restartWeb()
msg = mw.getInfo('网站[{1}]已被停用!', (name,))
mw.writeLog('网站管理', msg)
return mw.returnJson(True, '站点已停用!')
def startApi(self):
mid = request.form.get('id', '')
name = request.form.get('name', '')
path = self.setupPath + '/stop'
sitePath = mw.M('sites').where("id=?", (mid,)).getField('path')
# nginx
file = self.getHostConf(name)
conf = mw.readFile(file)
if conf:
conf = conf.replace(path, sitePath)
mw.writeFile(file, conf)
mw.M('sites').where("id=?", (mid,)).setField('status', '1')
mw.restartWeb()
msg = mw.getInfo('网站[{1}]已被启用!', (name,))
mw.writeLog('网站管理', msg)
return mw.returnJson(True, '站点已启用!')
def getBackupApi(self):
limit = request.form.get('limit', '')
p = request.form.get('p', '')
mid = request.form.get('search', '')
find = mw.M('sites').where("id=?", (mid,)).field(
"id,name,path,status,ps,addtime,edate").find()
start = (int(p) - 1) * (int(limit))
_list = mw.M('backup').where('pid=?', (mid,)).field('id,type,name,pid,filename,size,addtime').limit(
(str(start)) + ',' + limit).order('id desc').select()
_ret = {}
_ret['data'] = _list
count = mw.M('backup').where("id=?", (mid,)).count()
info = {}
info['count'] = count
info['tojs'] = 'getBackup'
info['p'] = p
info['row'] = limit
_ret['page'] = mw.getPage(info)
_ret['site'] = find
return mw.getJson(_ret)
def toBackupApi(self):
mid = request.form.get('id', '')
find = mw.M('sites').where(
"id=?", (mid,)).field('name,path,id').find()
fileName = find['name'] + '_' + \
time.strftime('%Y%m%d_%H%M%S', time.localtime()) + '.zip'
backupPath = mw.getBackupDir() + '/site'
zipName = backupPath + '/' + fileName
if not (os.path.exists(backupPath)):
os.makedirs(backupPath)
tmps = mw.getRunDir() + '/tmp/panelExec.log'
execStr = "cd '" + find['path'] + "' && zip '" + \
zipName + "' -r ./* > " + tmps + " 2>&1"
# print execStr
mw.execShell(execStr)
if os.path.exists(zipName):
fsize = os.path.getsize(zipName)
else:
fsize = 0
sql = mw.M('backup').add('type,name,pid,filename,size,addtime',
(0, fileName, find['id'], zipName, fsize, mw.getDate()))
msg = mw.getInfo('备份网站[{1}]成功!', (find['name'],))
mw.writeLog('网站管理', msg)
return mw.returnJson(True, '备份成功!')
def delBackupApi(self):
mid = request.form.get('id', '')
filename = mw.M('backup').where(
"id=?", (mid,)).getField('filename')
if os.path.exists(filename):
os.remove(filename)
name = mw.M('backup').where("id=?", (mid,)).getField('name')
msg = mw.getInfo('删除网站[{1}]的备份[{2}]成功!', (name, filename))
mw.writeLog('网站管理', msg)
mw.M('backup').where("id=?", (mid,)).delete()
return mw.returnJson(True, '站点删除成功!')
def getPhpVersionApi(self):
return self.getPhpVersion()
def setPhpVersionApi(self):
siteName = request.form.get('siteName', '')
version = request.form.get('version', '')
# nginx
file = self.getHostConf(siteName)
conf = mw.readFile(file)
if conf:
rep = "enable-php-(.*)\.conf"
tmp = re.search(rep, conf).group()
conf = conf.replace(tmp, 'enable-php-' + version + '.conf')
mw.writeFile(file, conf)
msg = mw.getInfo('成功切换网站[{1}]的PHP版本为PHP-{2}', (siteName, version))
mw.writeLog("网站管理", msg)
mw.restartWeb()
return mw.returnJson(True, msg)
def getDomainApi(self):
pid = request.form.get('pid', '')
return self.getDomain(pid)
# 获取站点所有域名
def getSiteDomainsApi(self):
pid = request.form.get('id', '')
data = {}
domains = mw.M('domain').where(
'pid=?', (pid,)).field('name,id').select()
binding = mw.M('binding').where(
'pid=?', (pid,)).field('domain,id').select()
if type(binding) == str:
return binding
for b in binding:
tmp = {}
tmp['name'] = b['domain']
tmp['id'] = b['id']
domains.append(tmp)
data['domains'] = domains
data['email'] = mw.M('users').getField('email')
if data['email'] == 'midoks@163.com':
data['email'] = ''
return mw.returnJson(True, 'OK', data)
def getDirBindingApi(self):
mid = request.form.get('id', '')
path = mw.M('sites').where('id=?', (mid,)).getField('path')
if not os.path.exists(path):
checks = ['/', '/usr', '/etc']
if path in checks:
data = {}
data['dirs'] = []
data['binding'] = []
return mw.returnJson(True, 'OK', data)
os.system('mkdir -p ' + path)
os.system('chmod 755 ' + path)
os.system('chown www:www ' + path)
siteName = mw.M('sites').where(
'id=?', (get.id,)).getField('name')
mw.writeLog(
'网站管理', '站点[' + siteName + '],根目录[' + path + ']不存在,已重新创建!')
dirnames = []
for filename in os.listdir(path):
try:
filePath = path + '/' + filename
if os.path.islink(filePath):
continue
if os.path.isdir(filePath):
dirnames.append(filename)
except:
pass
data = {}
data['dirs'] = dirnames
data['binding'] = mw.M('binding').where('pid=?', (mid,)).field(
'id,pid,domain,path,port,addtime').select()
return mw.returnJson(True, 'OK', data)
def getDirUserIniApi(self):
mid = request.form.get('id', '')
path = mw.M('sites').where('id=?', (mid,)).getField('path')
name = mw.M('sites').where("id=?", (mid,)).getField('name')
data = {}
data['logs'] = self.getLogsStatus(name)
data['runPath'] = self.getSiteRunPath(mid)
data['userini'] = False
if os.path.exists(path + '/.user.ini'):
data['userini'] = True
if data['runPath']['runPath'] != '/':
if os.path.exists(path + data['runPath']['runPath'] + '/.user.ini'):
data['userini'] = True
data['pass'] = self.getHasPwd(name)
data['path'] = path
data['name'] = name
return mw.returnJson(True, 'OK', data)
def setDirUserIniApi(self):
path = request.form.get('path', '')
runPath = request.form.get('runPath', '')
filename = path + '/.user.ini'
if os.path.exists(filename):
self.delUserInI(path)
mw.execShell("which chattr && chattr -i " + filename)
os.remove(filename)
return mw.returnJson(True, '已清除防跨站设置!')
self.setDirUserINI(path, runPath)
mw.execShell("which chattr && chattr +i " + filename)
return mw.returnJson(True, '已打开防跨站设置!')
def setRewriteApi(self):
data = request.form.get('data', '')
path = request.form.get('path', '')
encoding = request.form.get('encoding', '')
if not os.path.exists(path):
mw.writeFile(path, '')
mw.backFile(path)
mw.writeFile(path, data)
isError = mw.checkWebConfig()
if(type(isError) == str):
mw.restoreFile(path)
return mw.returnJson(False, 'ERROR:
' + isError.replace("\n", '
') + '')
mw.restartWeb()
return mw.returnJson(True, '设置成功!')
def setRewriteTplApi(self):
data = request.form.get('data', '')
name = request.form.get('name', '')
path = mw.getRunDir() + "/rewrite/nginx/" + name + ".conf"
if os.path.exists(path):
return mw.returnJson(False, '模版已经存在!')
if data == "":
return mw.returnJson(False, '模版内容不能为空!')
ok = mw.writeFile(path, data)
if not ok:
return mw.returnJson(False, '模版保持失败!')
return mw.returnJson(True, '设置模板成功!')
def logsOpenApi(self):
mid = request.form.get('id', '')
name = mw.M('sites').where("id=?", (mid,)).getField('name')
# NGINX
filename = self.getHostConf(name)
if os.path.exists(filename):
conf = mw.readFile(filename)
rep = self.logsPath + "/" + name + ".log"
if conf.find(rep) != -1:
conf = conf.replace(rep + " main", "off")
else:
conf = conf.replace('access_log off',
'access_log ' + rep + " main")
mw.writeFile(filename, conf)
mw.restartWeb()
return mw.returnJson(True, '操作成功!')
def getCertListApi(self):
try:
vpath = self.sslDir
if not os.path.exists(vpath):
os.system('mkdir -p ' + vpath)
data = []
for d in os.listdir(vpath):
# keyPath = self.sslDir + siteName + '/privkey.pem'
# certPath = self.sslDir + siteName + '/fullchain.pem'
keyPath = vpath + '/' + d + '/privkey.pem'
certPath = vpath + '/' + d + '/fullchain.pem'
if os.path.exists(keyPath) and os.path.exists(certPath):
self.saveCert(keyPath, certPath)
mpath = vpath + '/' + d + '/info.json'
if not os.path.exists(mpath):
continue
tmp = mw.readFile(mpath)
if not tmp:
continue
tmp1 = json.loads(tmp)
data.append(tmp1)
return mw.returnJson(True, 'OK', data)
except:
return mw.returnJson(True, 'OK', [])
def deleteSslApi(self):
site_name = request.form.get('site_name', '')
ssl_type = request.form.get('ssl_type', '')
path = self.sslDir + '/' + site_name
csr_path = path + '/fullchain.pem' # 生成证书路径
file = self.getHostConf(site_name)
content = mw.readFile(file)
key_text = 'ssl_certificate'
status = True
if content.find(key_text) == -1:
status = False
if ssl_type == 'now':
if status:
return mw.returnJson(False, '使用中,先关闭再删除')
if os.path.exists(path):
mw.execShell('rm -rf ' + path)
else:
return mw.returnJson(False, '还未申请!')
elif ssl_type == 'lets':
ssl_lets_dir = self.sslLetsDir + '/' + site_name
csr_lets_path = ssl_lets_dir + '/fullchain.pem' # 生成证书路径
if mw.md5(mw.readFile(csr_lets_path)) == mw.md5(mw.readFile(csr_path)):
return mw.returnJson(False, '使用中,先关闭再删除')
mw.execShell('rm -rf ' + ssl_lets_dir)
elif ssl_type == 'acme':
ssl_acme_dir = mw.getAcmeDir() + '/' + site_name
csr_acme_path = ssl_acme_dir + '/fullchain.cer' # 生成证书路径
if mw.md5(mw.readFile(csr_acme_path)) == mw.md5(mw.readFile(csr_path)):
return mw.returnJson(False, '使用中,先关闭再删除')
mw.execShell('rm -rf ' + ssl_acme_dir)
# mw.restartWeb()
return mw.returnJson(True, '删除成功')
def getSslApi(self):
site_name = request.form.get('site_name', '')
ssl_type = request.form.get('ssl_type', '')
path = self.sslDir + '/' + site_name
file = self.getHostConf(site_name)
content = mw.readFile(file)
key_text = 'ssl_certificate'
status = True
stype = 0
if content.find(key_text) == -1:
status = False
stype = -1
to_https = self.isToHttps(site_name)
sid = mw.M('sites').where("name=?", (site_name,)).getField('id')
domains = mw.M('domain').where("pid=?", (sid,)).field('name').select()
csr_path = path + '/fullchain.pem' # 生成证书路径
key_path = path + '/privkey.pem' # 密钥文件路径
cert_data = None
if ssl_type == 'lets':
csr_path = self.sslLetsDir + '/' + site_name + '/fullchain.pem' # 生成证书路径
key_path = self.sslLetsDir + '/' + site_name + '/privkey.pem' # 密钥文件路径
elif ssl_type == 'acme':
csr_path = mw.getAcmeDir() + '/' + site_name + '/fullchain.cer' # 生成证书路径
key_path = mw.getAcmeDir() + '/' + site_name + '/' + \
site_name + '.key' # 密钥文件路径
key = mw.readFile(key_path)
csr = mw.readFile(csr_path)
cert_data = self.getCertName(csr_path)
data = {
'status': status,
'domain': domains,
'key': key,
'csr': csr,
'type': stype,
'httpTohttps': to_https,
'cert_data': cert_data,
}
return mw.returnJson(True, 'OK', data)
def setSslApi(self):
siteName = request.form.get('siteName', '')
key = request.form.get('key', '')
csr = request.form.get('csr', '')
path = self.sslDir + '/' + siteName
if not os.path.exists(path):
mw.execShell('mkdir -p ' + path)
csrpath = path + "/fullchain.pem" # 生成证书路径
keypath = path + "/privkey.pem" # 密钥文件路径
if(key.find('KEY') == -1):
return mw.returnJson(False, '秘钥错误,请检查!')
if(csr.find('CERTIFICATE') == -1):
return mw.returnJson(False, '证书错误,请检查!')
mw.writeFile('/tmp/cert.pl', csr)
if not mw.checkCert('/tmp/cert.pl'):
return mw.returnJson(False, '证书错误,请粘贴正确的PEM格式证书!')
mw.backFile(keypath)
mw.backFile(csrpath)
mw.writeFile(keypath, key)
mw.writeFile(csrpath, csr)
# 写入配置文件
result = self.setSslConf(siteName)
if not result['status']:
return mw.getJson(result)
isError = mw.checkWebConfig()
if(type(isError) == str):
mw.restoreFile(keypath)
mw.restoreFile(csrpath)
return mw.returnJson(False, 'ERROR:
' + isError.replace("\n", '
') + '')
mw.writeLog('网站管理', '证书已保存!')
mw.restartWeb()
return mw.returnJson(True, '证书已保存!')
def setCertToSiteApi(self):
certName = request.form.get('certName', '')
siteName = request.form.get('siteName', '')
try:
path = self.sslDir + '/' + siteName.strip()
if not os.path.exists(path):
return mw.returnJson(False, '证书不存在!')
result = self.setSslConf(siteName)
if not result['status']:
return mw.getJson(result)
mw.restartWeb()
mw.writeLog('网站管理', '证书已部署!')
return mw.returnJson(True, '证书已部署!')
except Exception as ex:
return mw.returnJson(False, '设置错误:' + str(ex))
def removeCertApi(self):
certName = request.form.get('certName', '')
try:
path = self.sslDir + '/' + certName
if not os.path.exists(path):
return mw.returnJson(False, '证书已不存在!')
os.system("rm -rf " + path)
return mw.returnJson(True, '证书已删除!')
except:
return mw.returnJson(False, '删除失败!')
def closeSslConfApi(self):
siteName = request.form.get('siteName', '')
file = self.getHostConf(siteName)
conf = mw.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+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 = "\s+ssl\s+on;"
conf = re.sub(rep, '', conf)
rep = "\s+error_page\s497.+;"
conf = re.sub(rep, '', conf)
rep = "\s+if.+server_port.+\n.+\n\s+\s*}"
conf = re.sub(rep, '', conf)
rep = "\s+listen\s+443.*;"
conf = re.sub(rep, '', conf)
rep = "\s+listen\s+\[\:\:\]\:443.*;"
conf = re.sub(rep, '', conf)
mw.writeFile(file, conf)
msg = mw.getInfo('网站[{1}]关闭SSL成功!', (siteName,))
mw.writeLog('网站管理', msg)
mw.restartWeb()
return mw.returnJson(True, 'SSL已关闭!')
def deploySslApi(self):
site_name = request.form.get('site_name', '')
ssl_type = request.form.get('ssl_type', '')
path = self.sslDir + '/' + site_name
csr_path = path + '/fullchain.pem' # 生成证书路径
key_path = path + '/privkey.pem' # 生成证书路径
if ssl_type == 'lets':
ssl_lets_dir = self.sslLetsDir + '/' + site_name
lets_csrpath = ssl_lets_dir + '/fullchain.pem'
lets_keypath = ssl_lets_dir + '/privkey.pem'
if mw.md5(mw.readFile(lets_csrpath)) == mw.md5(mw.readFile(csr_path)):
return mw.returnJson(False, '已部署Lets')
else:
mw.buildSoftLink(lets_csrpath, csr_path, True)
mw.buildSoftLink(lets_keypath, key_path, True)
mw.execShell('echo "lets" > "' + path + '/README"')
elif ssl_type == 'acme':
ssl_acme_dir = mw.getAcmeDir() + '/' + site_name
acme_csrpath = ssl_acme_dir + '/fullchain.cer'
acme_keypath = ssl_acme_dir + '/' + site_name + '.key'
if mw.md5(mw.readFile(acme_csrpath)) == mw.md5(mw.readFile(csr_path)):
return mw.returnJson(False, '已部署ACME')
else:
mw.buildSoftLink(acme_csrpath, csr_path, True)
mw.buildSoftLink(acme_keypath, key_path, True)
mw.execShell('echo "lets" > "' + path + '/README"')
result = self.setSslConf(siteName)
if not result['status']:
return mw.getJson(result)
return mw.returnJson(True, '部署成功')
def getLetLogsApi(self):
log_file = mw.getRunDir() + '/logs/letsencrypt.log'
if not os.path.exists(log_file):
mw.execShell('touch ' + log_file)
return mw.returnJson(True, 'OK', log_file)
def createLetApi(self):
siteName = request.form.get('siteName', '')
domains = request.form.get('domains', '')
force = request.form.get('force', '')
renew = request.form.get('renew', '')
email_args = request.form.get('email', '')
domains = json.loads(domains)
email = mw.M('users').getField('email')
if email_args.strip() != '':
mw.M('users').setField('email', email_args)
email = email_args
if not len(domains):
return mw.returnJson(False, '请选择域名')
file = self.getHostConf(siteName)
if os.path.exists(file):
siteConf = mw.readFile(file)
if siteConf.find('301-END') != -1:
return mw.returnJson(False, '检测到您的站点做了301重定向设置,请先关闭重定向!')
# 检测存在反向代理
data_path = self.getProxyDataPath(siteName)
data_content = mw.readFile(data_path)
if data_content != False:
try:
data = json.loads(data_content)
except:
pass
for proxy in data:
proxy_dir = "{}/{}".format(self.proxyPath, siteName)
proxy_dir_file = proxy_dir + '/' + proxy['id'] + '.conf'
if os.path.exists(proxy_dir_file):
return mw.returnJson(False, '检测到您的站点做了反向代理设置,请先关闭反向代理!')
auth_to = self.getSitePath(siteName)
to_args = {
'domains': domains,
'auth_type': 'http',
'auth_to': auth_to,
}
import cert_api
data = cert_api.cert_api().applyCertApi(to_args)
if not data['status']:
msg = data['msg']
if type(data['msg']) != str:
msg = data['msg'][0]
emsg = data['msg'][1]['challenges'][0]['error']
msg = msg + '
响应状态:' + str(emsg['status']) + '
错误类型:' + emsg[ 'type'] + '
错误代码:' + emsg['detail'] + '
' return mw.returnJson(data['status'], msg, data['msg']) src_letpath = mw.getServerDir() + '/web_conf/letsencrypt/' + siteName src_csrpath = src_letpath + "/fullchain.pem" # 生成证书路径 src_keypath = src_letpath + "/privkey.pem" # 密钥文件路径 dst_letpath = self.sslDir + '/' + siteName dst_csrpath = dst_letpath + '/fullchain.pem' dst_keypath = dst_letpath + '/privkey.pem' if not os.path.exists(dst_letpath): mw.execShell('mkdir -p ' + dst_letpath) mw.execShell('ln -sf "' + src_csrpath + '" "' + dst_csrpath + '"') mw.execShell('ln -sf "' + src_keypath + '" "' + dst_keypath + '"') mw.execShell('echo "let" > "' + dst_letpath + '/README"') # 写入配置文件 result = self.setSslConf(siteName) if not result['status']: return mw.getJson(result) result['csr'] = mw.readFile(src_csrpath) result['key'] = mw.readFile(src_keypath) return mw.returnJson(data['status'], data['msg'], result) def getAcmeLogsApi(self): log_file = mw.getRunDir() + '/logs/acme.log' if not os.path.exists(log_file): mw.execShell('touch ' + log_file) return mw.returnJson(True, 'OK', log_file) def createAcmeApi(self): siteName = request.form.get('siteName', '') domains = request.form.get('domains', '') force = request.form.get('force', '') renew = request.form.get('renew', '') email_args = request.form.get('email', '') domains = json.loads(domains) email = mw.M('users').getField('email') if email_args.strip() != '': mw.M('users').setField('email', email_args) email = email_args if not len(domains): return mw.returnJson(False, '请选择域名') file = self.getHostConf(siteName) if os.path.exists(file): siteConf = mw.readFile(file) if siteConf.find('301-END') != -1: return mw.returnJson(False, '检测到您的站点做了301重定向设置,请先关闭重定向!') # 检测存在反向代理 data_path = self.getProxyDataPath(siteName) data_content = mw.readFile(data_path) if data_content != False: try: data = json.loads(data_content) except: pass for proxy in data: proxy_dir = "{}/{}".format(self.proxyPath, siteName) proxy_dir_file = proxy_dir + '/' + proxy['id'] + '.conf' if os.path.exists(proxy_dir_file): return mw.returnJson(False, '检测到您的站点做了反向代理设置,请先关闭反向代理!') siteInfo = mw.M('sites').where( 'name=?', (siteName,)).field('id,name,path').find() path = self.getSitePath(siteName) srcPath = siteInfo['path'] # 检测acme是否安装 acme_dir = mw.getAcmeDir() if not os.path.exists(acme_dir): try: mw.execShell("curl -sS curl https://get.acme.sh | sh") except: pass if not os.path.exists(acme_dir): return mw.returnJson(False, '尝试自动安装ACME失败,请通过以下命令尝试手动安装安装命令: curl https://get.acme.sh | sh
') # 避免频繁执行 checkAcmeRun = mw.execShell('ps -ef|grep acme.sh |grep -v grep') if checkAcmeRun[0] != '': return mw.returnJson(False, '正在申请或更新SSL中...') if force == 'true': force_bool = True if renew == 'true': execStr = acme_dir + "/acme.sh --renew --yes-I-know-dns-manual-mode-enough-go-ahead-please" else: execStr = acme_dir + "/acme.sh --issue --force" # 确定主域名顺序 domainsTmp = [] if siteName in domains: domainsTmp.append(siteName) for domainTmp in domains: if domainTmp == siteName: continue domainsTmp.append(domainTmp) domains = domainsTmp domainCount = 0 for domain in domains: if mw.checkIp(domain): continue if domain.find('*.') != -1: return mw.returnJson(False, '泛域名不能使用【文件验证】的方式申请证书!') execStr += ' -w ' + path execStr += ' -d ' + domain domainCount += 1 if domainCount == 0: return mw.returnJson(False, '请选择域名(不包括IP地址与泛域名)!') log_file = mw.getRunDir() + '/logs/acme.log' mw.writeFile(log_file, "开始ACME申请...\n", "wb+") cmd = 'export ACCOUNT_EMAIL=' + email + ' && ' + \ execStr + ' >> ' + log_file # print(domains) # print(cmd) result = mw.execShell(cmd) src_path = acme_dir + '/' + domains[0] src_cert = src_path + '/fullchain.cer' src_key = src_path + '/' + domains[0] + '.key' msg = '签发失败,您尝试申请证书的失败次数已达上限!1、检查域名是否绑定到对应站点
\2、检查域名是否正确解析到本服务器,或解析还未完全生效
\3、如果您的站点设置了反向代理,或使用了CDN,请先将其关闭
\4、如果您的站点设置了301重定向,请先将其关闭
\5、如果以上检查都确认没有问题,请尝试更换DNS服务商
' if not os.path.exists(src_cert.replace("\*", "*")): data = {} data['err'] = result data['out'] = result[0] data['msg'] = msg data['result'] = {} if result[1].find('new-authz error:') != -1: data['result'] = json.loads( re.search("{.+}", result[1]).group()) if data['result']['status'] == 429: data['msg'] = msg data['status'] = False return mw.getJson(data) dst_path = self.sslDir + '/' + siteName dst_cert = dst_path + "/fullchain.pem" # 生成证书路径 dst_key = dst_path + "/privkey.pem" # 密钥文件路径 if not os.path.exists(dst_path): mw.execShell("mkdir -p " + dst_path) mw.execShell('ln -sf "' + src_cert + '" "' + dst_cert + '"') mw.execShell('ln -sf "' + src_key + '" "' + dst_key + '"') mw.execShell('echo "acme" > "' + dst_path + '/README"') # 写入配置文件 result = self.setSslConf(siteName) if not result['status']: return mw.getJson(result) result['csr'] = mw.readFile(src_cert) result['key'] = mw.readFile(src_key) mw.restartWeb() return mw.returnJson(True, '证书已更新!', result) def httpToHttpsApi(self): siteName = request.form.get('siteName', '') file = self.getHostConf(siteName) conf = mw.readFile(file) if conf: if conf.find('ssl_certificate') == -1: return mw.returnJson(False, '当前未开启SSL') 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) mw.writeFile(file, conf) mw.restartWeb() return mw.returnJson(True, '设置成功!证书也要设置好哟!') def closeToHttpsApi(self): siteName = request.form.get('siteName', '') file = self.getHostConf(siteName) conf = mw.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) mw.writeFile(file, conf) mw.restartWeb() return mw.returnJson(True, '关闭HTTPS跳转成功!') def getIndexApi(self): sid = request.form.get('id', '') data = {} index = self.getIndex(sid) data['index'] = index return mw.getJson(data) def setIndexApi(self): sid = request.form.get('id', '') index = request.form.get('index', '') return self.setIndex(sid, index) def getLimitNetApi(self): sid = request.form.get('id', '') return self.getLimitNet(sid) def saveLimitNetApi(self): sid = request.form.get('id', '') perserver = request.form.get('perserver', '') perip = request.form.get('perip', '') limit_rate = request.form.get('limit_rate', '') return self.saveLimitNet(sid, perserver, perip, limit_rate) def closeLimitNetApi(self): sid = request.form.get('id', '') return self.closeLimitNet(sid) def getSecurityApi(self): sid = request.form.get('id', '') name = request.form.get('name', '') return self.getSecurity(sid, name) def setSecurityApi(self): fix = request.form.get('fix', '') domains = request.form.get('domains', '') status = request.form.get('status', '') name = request.form.get('name', '') sid = request.form.get('id', '') return self.setSecurity(sid, name, fix, domains, status) def getLogsApi(self): siteName = request.form.get('siteName', '') return self.getLogs(siteName) def getErrorLogsApi(self): siteName = request.form.get('siteName', '') return self.getErrorLogs(siteName) def getSitePhpVersionApi(self): siteName = request.form.get('siteName', '') return self.getSitePhpVersion(siteName) def getHostConfApi(self): siteName = request.form.get('siteName', '') host = self.getHostConf(siteName) return mw.getJson({'host': host}) def getRewriteConfApi(self): siteName = request.form.get('siteName', '') rewrite = self.getRewriteConf(siteName) return mw.getJson({'rewrite': rewrite}) def getRewriteTplApi(self): tplname = request.form.get('tplname', '') file = mw.getRunDir() + '/rewrite/nginx/' + tplname + '.conf' if not os.path.exists(file): return mw.returnJson(False, '模版不存在!') return mw.returnJson(True, 'OK', file) def getRewriteListApi(self): rlist = self.getRewriteList() return mw.getJson(rlist) def getRootDirApi(self): data = {} data['dir'] = mw.getWwwDir() return mw.getJson(data) def setEndDateApi(self): sid = request.form.get('id', '') edate = request.form.get('edate', '') return self.setEndDate(sid, edate) def addApi(self): webname = request.form.get('webinfo', '') ps = request.form.get('ps', '') path = request.form.get('path', '') version = request.form.get('version', '') port = request.form.get('port', '') return self.add(webname, port, ps, path, version) def checkWebStatusApi(self): ''' 创建站点检查web服务 ''' if not mw.isInstalledWeb(): return mw.returnJson(False, '请安装并启动OpenResty服务!') # 这个快点 pid = mw.getServerDir() + '/openresty/nginx/logs/nginx.pid' if not os.path.exists(pid): return mw.returnJson(False, '请启动OpenResty服务!') # path = mw.getServerDir() + '/openresty/init.d/openresty' # data = mw.execShell(path + " status") # if data[0].strip().find('stopped') != -1: # return mw.returnJson(False, '请启动OpenResty服务!') # import plugins_api # data = plugins_api.plugins_api().run('openresty', 'status') # if data[0].strip() == 'stop': # return mw.returnJson(False, '请启动OpenResty服务!') return mw.returnJson(True, 'OK') def addDomainApi(self): isError = mw.checkWebConfig() if isError != True: return mw.returnJson(False, 'ERROR: 检测到配置文件有错误,请先排除后再操作