Simple Linux Panel
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
mdserver-web/class/core/site_api.py

1527 lines
60 KiB

6 years ago
# coding: utf-8
import time
import os
import sys
import public
import re
import json
import pwd
6 years ago
import shutil
6 years ago
sys.path.append("/usr/local/lib/python2.7/site-packages")
import psutil
6 years ago
from flask import request
6 years ago
class site_api:
6 years ago
siteName = None # 网站名称
sitePath = None # 根目录
sitePort = None # 端口
phpVersion = None # PHP版本
6 years ago
6 years ago
setupPath = None # 安装路径
vhostPath = None
6 years ago
logsPath = None
6 years ago
passPath = None
6 years ago
rewritePath = None
sslDir = None # ssl目录
6 years ago
6 years ago
def __init__(self):
6 years ago
# nginx conf
self.setupPath = public.getServerDir() + '/web_conf'
self.vhostPath = vh = self.setupPath + '/nginx/vhost'
if not os.path.exists(vh):
public.execShell("mkdir -p " + vh + " && chmod -R 755 " + vh)
self.rewritePath = rw = self.setupPath + '/nginx/rewrite'
6 years ago
if not os.path.exists(rw):
public.execShell("mkdir -p " + rw + " && chmod -R 755 " + rw)
6 years ago
self.passPath = self.setupPath + '/nginx/pass'
# if not os.path.exists(pp):
# public.execShell("mkdir -p " + rw + " && chmod -R 755 " + rw)
6 years ago
6 years ago
self.logsPath = public.getRootDir() + '/wwwlogs'
6 years ago
# ssl conf
6 years ago
if public.isAppleSystem():
6 years ago
self.sslDir = self.setupPath + '/letsencrypt/'
6 years ago
else:
self.sslDir = '/etc/letsencrypt/live/'
6 years ago
6 years ago
##### ----- start ----- ###
def listApi(self):
6 years ago
_list = public.M('sites').where('', ()).field(
'id,name,path,status,ps,addtime,edate').limit('0,5').order('id desc').select()
_ret = {}
_ret['data'] = _list
count = public.M('sites').where('', ()).count()
_page = {}
_page['count'] = count
_page['tojs'] = 'getWeb'
_ret['page'] = public.getPage(_page)
return public.getJson(_ret)
6 years ago
def getPhpVersionApi(self):
return self.getPhpVersion()
6 years ago
def setPhpVersionApi(self):
siteName = request.form.get('siteName', '').encode('utf-8')
version = request.form.get('version', '').encode('utf-8')
# nginx
6 years ago
file = self.getHostConf(siteName)
6 years ago
conf = public.readFile(file)
if conf:
rep = "enable-php-([0-9]{2,3})\.conf"
tmp = re.search(rep, conf).group()
conf = conf.replace(tmp, 'enable-php-' + version + '.conf')
public.writeFile(file, conf)
public.restartWeb()
msg = public.getInfo('成功切换网站[{1}]的PHP版本为PHP-{2}', (siteName, version))
6 years ago
public.writeLog("网站管理", msg)
6 years ago
return public.returnJson(True, msg)
6 years ago
def getDomainApi(self):
pid = request.form.get('pid', '').encode('utf-8')
return self.getDomain(pid)
6 years ago
# 获取站点所有域名
def getSiteDomainsApi(self):
pid = request.form.get('id', '').encode('utf-8')
data = {}
domains = public.M('domain').where(
'pid=?', (pid,)).field('name,id').select()
binding = public.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'] = public.M('users').getField('email')
if data['email'] == '287962566@qq.com':
data['email'] = ''
return public.returnJson(True, 'OK', data)
6 years ago
def getDirBindingApi(self):
mid = request.form.get('id', '').encode('utf-8')
path = public.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 public.returnJson(True, 'OK', data)
os.system('mkdir -p ' + path)
os.system('chmod 755 ' + path)
os.system('chown www:www ' + path)
siteName = public.M('sites').where(
'id=?', (get.id,)).getField('name')
public.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'] = public.M('binding').where('pid=?', (mid,)).field(
'id,pid,domain,path,port,addtime').select()
return public.returnJson(True, 'OK', data)
def getDirUserIniApi(self):
mid = request.form.get('id', '').encode('utf-8')
path = public.M('sites').where('id=?', (mid,)).getField('path')
name = public.M('sites').where("id=?", (mid,)).getField('name')
data = {}
data['logs'] = self.getLogsStatus(name)
data['userini'] = False
if os.path.exists(path + '/.user.ini'):
data['userini'] = True
data['runPath'] = self.getSiteRunPath(mid)
data['pass'] = self.getHasPwd(name)
6 years ago
data['path'] = path
6 years ago
return public.returnJson(True, 'OK', data)
6 years ago
def setDirUserIniApi(self):
path = request.form.get('path', '').encode('utf-8')
filename = path + '/.user.ini'
self.delUserInI(path)
if os.path.exists(filename):
public.execShell("which chattr && chattr -i " + filename)
os.remove(filename)
return public.returnJson(True, '已清除防跨站设置!')
public.writeFile(filename, 'open_basedir=' + path + '/:/tmp/:/proc/')
public.execShell("which chattr && chattr +i " + filename)
return public.returnJson(True, '已打开防跨站设置!')
6 years ago
def logsOpenApi(self):
mid = request.form.get('id', '').encode('utf-8')
name = public.M('sites').where("id=?", (mid,)).getField('name')
# NGINX
filename = self.getHostConf(name)
if os.path.exists(filename):
conf = public.readFile(filename)
rep = self.logsPath + "/" + name + ".log"
if conf.find(rep) != -1:
conf = conf.replace(rep, "off")
else:
conf = conf.replace('access_log off', 'access_log ' + rep)
public.writeFile(filename, conf)
public.restartWeb()
return public.returnJson(True, '操作成功!')
6 years ago
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):
mpath = vpath + '/' + d + '/info.json'
if not os.path.exists(mpath):
continue
tmp = public.readFile(mpath)
if not tmp:
continue
tmp1 = json.loads(tmp)
data.append(tmp1)
return public.returnJson(True, 'OK', data)
except:
return public.returnJson(True, 'OK', [])
6 years ago
def getSslApi(self):
siteName = request.form.get('siteName', '').encode('utf-8')
6 years ago
path = self.sslDir + siteName
6 years ago
csrpath = path + "/fullchain.pem" # 生成证书路径
keypath = path + "/privkey.pem" # 密钥文件路径
key = public.readFile(keypath)
csr = public.readFile(csrpath)
file = self.getHostConf(siteName)
conf = public.readFile(file)
keyText = 'ssl_certificate'
status = True
6 years ago
stype = 0
6 years ago
if(conf.find(keyText) == -1):
status = False
6 years ago
stype = -1
6 years ago
toHttps = self.isToHttps(siteName)
id = public.M('sites').where("name=?", (siteName,)).getField('id')
domains = public.M('domain').where(
"pid=?", (id,)).field('name').select()
data = {'status': status, 'domain': domains, 'key': key,
6 years ago
'csr': csr, 'type': stype, 'httpTohttps': toHttps}
6 years ago
return public.returnJson(True, 'OK', data)
6 years ago
def setSslApi(self):
siteName = request.form.get('siteName', '').encode('utf-8')
key = request.form.get('key', '').encode('utf-8')
csr = request.form.get('csr', '').encode('utf-8')
6 years ago
path = self.sslDir + siteName
6 years ago
if not os.path.exists(path):
public.execShell('mkdir -p ' + path)
csrpath = path + "/fullchain.pem" # 生成证书路径
keypath = path + "/privkey.pem" # 密钥文件路径
if(key.find('KEY') == -1):
return public.returnJson(False, '秘钥错误,请检查!')
if(csr.find('CERTIFICATE') == -1):
return public.returnJson(False, '证书错误,请检查!')
public.writeFile('/tmp/cert.pl', csr)
if not public.checkCert('/tmp/cert.pl'):
return public.returnJson(False, '证书错误,请粘贴正确的PEM格式证书!')
public.execShell('\\cp -a ' + keypath + ' /tmp/backup1.conf')
public.execShell('\\cp -a ' + csrpath + ' /tmp/backup2.conf')
# 清理旧的证书链
if os.path.exists(path + '/README'):
public.execShell('rm -rf ' + path)
public.execShell('rm -rf ' + path + '-00*')
public.execShell('rm -rf /etc/letsencrypt/archive/' + siteName)
public.execShell(
'rm -rf /etc/letsencrypt/archive/' + siteName + '-00*')
public.execShell(
'rm -f /etc/letsencrypt/renewal/' + siteName + '.conf')
public.execShell('rm -f /etc/letsencrypt/renewal/' +
siteName + '-00*.conf')
public.execShell('rm -f ' + path + '/README')
public.execShell('mkdir -p ' + path)
public.writeFile(keypath, key)
public.writeFile(csrpath, csr)
# 写入配置文件
result = self.setSslConf(siteName)
6 years ago
# print result['msg']
6 years ago
if not result['status']:
return public.getJson(result)
6 years ago
isError = public.checkWebConfig()
6 years ago
if(type(isError) == str):
public.execShell('\\cp -a /tmp/backup1.conf ' + keypath)
public.execShell('\\cp -a /tmp/backup2.conf ' + csrpath)
return public.returnJson(False, 'ERROR: <br><a style="color:red;">' + isError.replace("\n", '<br>') + '</a>')
public.restartWeb()
public.writeLog('TYPE_SITE', '证书已保存!')
return public.returnJson(True, '证书已保存!')
6 years ago
def closeSslConfApi(self):
siteName = request.form.get('siteName', '').encode('utf-8')
file = self.getHostConf(siteName)
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+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)
public.writeFile(file, conf)
msg = public.getInfo('网站[{1}]关闭SSL成功!', (siteName,))
public.writeLog('TYPE_SITE', msg)
public.restartWeb()
return public.returnJson(True, 'SSL已关闭!')
6 years ago
def createLetApi(self):
siteName = request.form.get('siteName', '').encode('utf-8')
updateOf = request.form.get('updateOf', '')
domains = request.form.get('domains', '').encode('utf-8')
force = request.form.get('force', '').encode('utf-8')
renew = request.form.get('renew', '').encode('utf-8')
email_args = request.form.get('email', '').encode('utf-8')
domains = json.loads(domains)
email = public.M('users').getField('email')
if email_args.strip() != '':
public.M('users').setField('email', email_args)
email = email_args
if not len(domains):
return public.returnJson(False, '请选择域名')
file = self.getHostConf(siteName)
if os.path.exists(file):
siteConf = public.readFile(file)
if siteConf.find('301-START') != -1:
return public.returnJson(False, '检测到您的站点做了301重定向设置,请先关闭重定向!')
6 years ago
letpath = public.getServerDir() + '/letsencrypt/live/' + siteName
csrpath = letpath + "/fullchain.pem" # 生成证书路径
keypath = letpath + "/privkey.pem" # 密钥文件路径
6 years ago
actionstr = updateOf
siteInfo = public.M('sites').where(
'name=?', (siteName,)).field('id,name,path').find()
path = self.getSitePath(siteName)
6 years ago
srcPath = siteInfo['path']
# 检测acem是否安装
if public.isAppleSystem():
user = public.execShell(
"who | sed -n '2, 1p' |awk '{print $1}'")[0].strip()
acem = '/Users/' + user + '/.acme.sh/acme.sh'
else:
acem = '/root/.acme.sh/acme.sh'
if not os.path.exists(acem):
acem = '/.acme.sh/acme.sh'
if not os.path.exists(acem):
try:
public.execShell("curl -sS curl https://get.acme.sh | sh")
except:
return public.returnJson(False, '尝试自动安装ACME失败,请通过以下命令尝试手动安装<p>安装命令: curl https://get.acme.sh | sh</p>' + acem)
if not os.path.exists(acem):
return public.returnJson(False, '尝试自动安装ACME失败,请通过以下命令尝试手动安装<p>安装命令: curl https://get.acme.sh | sh</p>' + acem)
force_bool = False
if force == 'true':
force_bool = True
if renew == 'true':
execStr = acem + " --renew --yes-I-know-dns-manual-mode-enough-go-ahead-please"
else:
execStr = acem + " --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 public.checkIp(domain):
continue
if domain.find('*.') != -1:
return public.returnJson(False, '泛域名不能使用【文件验证】的方式申请证书!')
execStr += ' -w ' + path
execStr += ' -d ' + domain
domainCount += 1
if domainCount == 0:
return public.returnJson(False, '请选择域名(不包括IP地址与泛域名)!')
home_path = public.getServerDir() + '/openresty/nginx/conf/cert/' + \
domains[0]
home_cert = home_path + '/fullchain.cer'
home_key = home_path + '/' + domains[0] + '.key'
if not os.path.exists(home_cert):
home_path = '/.acme.sh/' + domains[0]
home_cert = home_path + '/fullchain.cer'
home_key = home_path + '/' + domains[0] + '.key'
if not os.path.exists(home_cert):
home_path = '/root/.acme.sh/' + domains[0]
home_cert = home_path + '/fullchain.cer'
home_key = home_path + '/' + domains[0] + '.key'
if public.isAppleSystem():
user = public.execShell(
"who | sed -n '2, 1p' |awk '{print $1}'")[0].strip()
acem = '/Users/' + user + '/.acme.sh/'
if not os.path.exists(home_cert):
home_path = acem + domains[0]
home_cert = home_path + '/fullchain.cer'
home_key = home_path + '/' + domains[0] + '.key'
6 years ago
6 years ago
# print home_cert
6 years ago
cmd = 'export ACCOUNT_EMAIL=' + email + ' && ' + execStr
result = public.execShell(cmd)
if not os.path.exists(home_cert.replace("\*", "*")):
data = {}
data['err'] = result
data['out'] = result[0]
data['msg'] = '签发失败,我们无法验证您的域名:<p>1、检查域名是否绑定到对应站点</p>\
<p>2检查域名是否正确解析到本服务器,或解析还未完全生效</p>\
<p>3如果您的站点设置了反向代理,或使用了CDN,请先将其关闭</p>\
<p>4如果您的站点设置了301重定向,请先将其关闭</p>\
<p>5如果以上检查都确认没有问题请尝试更换DNS服务商</p>'
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'] = '签发失败,您尝试申请证书的失败次数已达上限!<p>1、检查域名是否绑定到对应站点</p>\
<p>2检查域名是否正确解析到本服务器,或解析还未完全生效</p>\
<p>3如果您的站点设置了反向代理,或使用了CDN,请先将其关闭</p>\
<p>4如果您的站点设置了301重定向,请先将其关闭</p>\
<p>5如果以上检查都确认没有问题请尝试更换DNS服务商</p>'
data['status'] = False
return public.getJson(data)
if not os.path.exists(letpath):
public.execShell("mkdir -p " + letpath)
public.execShell("ln -sf \"" + home_cert + "\" \"" + csrpath + '"')
public.execShell("ln -sf \"" + home_key + "\" \"" + keypath + '"')
public.execShell('echo "let" > "' + letpath + '/README"')
if(actionstr == '2'):
return public.returnJson(True, '证书已更新!')
# 写入配置文件
6 years ago
result = self.setSslConf(siteName)
6 years ago
# print result['msg']
6 years ago
if not result['status']:
return public.getJson(result)
result['csr'] = public.readFile(csrpath)
result['key'] = public.readFile(keypath)
public.restartWeb()
return public.returnJson(True, 'OK', result)
6 years ago
6 years ago
def getIndexApi(self):
sid = request.form.get('id', '').encode('utf-8')
data = {}
index = self.getIndex(sid)
data['index'] = index
return public.getJson(data)
def setIndexApi(self):
sid = request.form.get('id', '').encode('utf-8')
index = request.form.get('index', '').encode('utf-8')
return self.setIndex(sid, index)
def getLimitNetApi(self):
sid = request.form.get('id', '').encode('utf-8')
return self.getLimitNet(sid)
def saveLimitNetApi(self):
sid = request.form.get('id', '').encode('utf-8')
perserver = request.form.get('perserver', '').encode('utf-8')
perip = request.form.get('perip', '').encode('utf-8')
limit_rate = request.form.get('limit_rate', '').encode('utf-8')
return self.saveLimitNet(sid, perserver, perip, limit_rate)
def closeLimitNetApi(self):
sid = request.form.get('id', '').encode('utf-8')
return self.closeLimitNet(sid)
def getSecurityApi(self):
sid = request.form.get('id', '').encode('utf-8')
name = request.form.get('name', '').encode('utf-8')
return self.getSecurity(sid, name)
def setSecurityApi(self):
fix = request.form.get('fix', '').encode('utf-8')
domains = request.form.get('domains', '').encode('utf-8')
status = request.form.get('status', '').encode('utf-8')
name = request.form.get('name', '').encode('utf-8')
sid = request.form.get('id', '').encode('utf-8')
return self.setSecurity(sid, name, fix, domains, status)
def getLogsApi(self):
siteName = request.form.get('siteName', '').encode('utf-8')
return self.getLogs(siteName)
def getSitePhpVersionApi(self):
siteName = request.form.get('siteName', '').encode('utf-8')
return self.getSitePhpVersion(siteName)
def getHostConfApi(self):
siteName = request.form.get('siteName', '').encode('utf-8')
host = self.getHostConf(siteName)
return public.getJson({'host': host})
def getRewriteConfApi(self):
siteName = request.form.get('siteName', '').encode('utf-8')
rewrite = self.getRewriteConf(siteName)
return public.getJson({'rewrite': rewrite})
6 years ago
def getRewriteTplApi(self):
tplname = request.form.get('tplname', '').encode('utf-8')
file = public.getRunDir() + '/rewrite/nginx/' + tplname + '.conf'
if not os.path.exists(file):
return public.returnJson(False, '模版不存在!')
return public.returnJson(True, 'OK', file)
6 years ago
def getRewriteListApi(self):
rlist = self.getRewriteList()
return public.getJson(rlist)
def getRootDirApi(self):
data = {}
data['dir'] = public.getWwwDir()
return public.getJson(data)
def setEndDateApi(self):
sid = request.form.get('id', '').encode('utf-8')
edate = request.form.get('edate', '').encode('utf-8')
return self.setEndDate(sid, edate)
def addApi(self):
webname = request.form.get('webinfo', '').encode('utf-8')
ps = request.form.get('ps', '').encode('utf-8')
path = request.form.get('path', '').encode('utf-8')
version = request.form.get('version', '').encode('utf-8')
port = request.form.get('port', '').encode('utf-8')
return self.add(webname, port, ps, path, version)
def addDomainApi(self):
isError = public.checkWebConfig()
if isError != True:
return public.returnJson(False, 'ERROR: 检测到配置文件有错误,请先排除后再操作<br><br><a style="color:red;">' + isError.replace("\n", '<br>') + '</a>')
domain = request.form.get('domain', '').encode('utf-8')
webname = request.form.get('webname', '').encode('utf-8')
pid = request.form.get('id', '').encode('utf-8')
if len(domain) < 3:
return public.returnJson(False, '域名不能为空!')
domains = domain.split(',')
for domain in domains:
if domain == "":
continue
domain = domain.split(':')
# print domain
domain_name = self.toPunycode(domain[0])
domain_port = '80'
reg = "^([\w\-\*]{1,100}\.){1,4}([\w\-]{1,24}|[\w\-]{1,24}\.[\w\-]{1,24})$"
if not re.match(reg, domain_name):
return public.returnJson(False, '域名格式不正确!')
if len(domain) == 2:
domain_port = domain[1]
if domain_port == "":
domain_port = "80"
if not public.checkPort(domain_port):
return public.returnJson(False, '端口范围不合法!')
opid = public.M('domain').where(
"name=? AND (port=? OR pid=?)", (domain, domain_port, pid)).getField('pid')
if opid:
if public.M('sites').where('id=?', (opid,)).count():
return public.returnJson(False, '指定域名已绑定过!')
public.M('domain').where('pid=?', (opid,)).delete()
if public.M('binding').where('domain=?', (domain,)).count():
return public.returnJson(False, '您添加的域名已存在!')
self.nginxAddDomain(webname, domain_name, domain_port)
public.restartWeb()
msg = public.getInfo('网站[{1}]添加域名[{2}]成功!', (webname, domain_name))
public.writeLog('TYPE_SITE', msg)
public.M('domain').add('pid,name,port,addtime',
(pid, domain_name, domain_port, public.getDate()))
return public.returnJson(True, '域名添加成功!')
6 years ago
def addDirBindApi(self):
pid = request.form.get('id', '').encode('utf-8')
domain = request.form.get('domain', '').encode('utf-8')
dirName = request.form.get('dirName', '').encode('utf-8')
tmp = domain.split(':')
domain = tmp[0]
port = '80'
if len(tmp) > 1:
port = tmp[1]
if dirName == '':
public.returnJson(False, '目录不能为空!')
reg = "^([\w\-\*]{1,100}\.){1,4}(\w{1,10}|\w{1,10}\.\w{1,10})$"
if not re.match(reg, domain):
return public.returnJson(False, '主域名格式不正确!')
siteInfo = public.M('sites').where(
"id=?", (pid,)).field('id,path,name').find()
webdir = siteInfo['path'] + '/' + dirName
if public.M('binding').where("domain=?", (domain,)).count() > 0:
6 years ago
return public.returnJson(False, '您添加的域名已存在!')
if public.M('domain').where("name=?", (domain,)).count() > 0:
return public.returnJson(False, '您添加的域名已存在!')
filename = self.getHostConf(siteInfo['name'])
conf = public.readFile(filename)
6 years ago
if conf:
rep = "enable-php-([0-9]{2,3})\.conf"
tmp = re.search(rep, conf).groups()
version = tmp[0]
source_dirbind_tpl = public.getRunDir() + '/data/tpl/nginx_dirbind.conf'
content = public.readFile(source_dirbind_tpl)
content = content.replace('{$PORT}', port)
content = content.replace('{$PHPVER}', version)
content = content.replace('{$DIRBIND}', domain)
content = content.replace('{$ROOT_DIR}', webdir)
content = content.replace('{$SERVER_MAIN}', siteInfo['name'])
content = content.replace('{$OR_REWRITE}', self.rewritePath)
content = content.replace('{$LOGPATH}', public.getLogsDir())
conf += "\r\n" + content
6 years ago
shutil.copyfile(filename, '/tmp/backup.conf')
public.writeFile(filename, conf)
conf = public.readFile(filename)
# 检查配置是否有误
isError = public.checkWebConfig()
if isError != True:
shutil.copyfile('/tmp/backup.conf', filename)
return public.returnJson(False, 'ERROR: <br><a style="color:red;">' + isError.replace("\n", '<br>') + '</a>')
public.M('binding').add('pid,domain,port,path,addtime',
(pid, domain, port, dirName, public.getDate()))
6 years ago
public.restartWeb()
msg = public.getInfo('网站[{1}]子目录[{2}]绑定到[{3}]',
(siteInfo['name'], dirName, domain))
public.writeLog('网站管理', msg)
return public.returnJson(True, '添加成功!')
def delDirBindApi(self):
mid = request.form.get('id', '').encode('utf-8')
binding = public.M('binding').where(
"id=?", (mid,)).field('id,pid,domain,path').find()
siteName = public.M('sites').where(
"id=?", (binding['pid'],)).getField('name')
6 years ago
filename = self.getHostConf(siteName)
conf = public.readFile(filename)
if conf:
rep = "\s*.+BINDING-" + \
binding['domain'] + \
"-START(.|\n)+BINDING-" + binding['domain'] + "-END"
conf = re.sub(rep, '', conf)
public.writeFile(filename, conf)
6 years ago
public.M('binding').where("id=?", (mid,)).delete()
6 years ago
filename = self.getDirBindRewrite(siteName, binding['path'])
if os.path.exists(filename):
os.remove(filename)
public.restartWeb()
msg = public.getInfo('删除网站[{1}]子目录[{2}]绑定',
(siteName, binding['path']))
public.writeLog('网站管理', msg)
return public.returnJson(True, '删除成功!')
6 years ago
# 取子目录Rewrite
def getDirBindRewriteApi(self):
mid = request.form.get('id', '').encode('utf-8')
add = request.form.get('add', '0').encode('utf-8')
find = public.M('binding').where(
"id=?", (mid,)).field('id,pid,domain,path').find()
site = public.M('sites').where(
"id=?", (find['pid'],)).field('id,name,path').find()
filename = self.getDirBindRewrite(site['name'], find['path'])
if add == '1':
public.writeFile(filename, '')
file = self.getHostConf(site['name'])
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['rewrite_dir'] = self.rewritePath
data['status'] = False
if os.path.exists(filename):
data['status'] = True
data['data'] = public.readFile(filename)
data['rlist'] = []
for ds in os.listdir(self.rewritePath):
if ds == 'list.txt':
continue
data['rlist'].append(ds[0:len(ds) - 5])
data['filename'] = filename
return public.getJson(data)
6 years ago
6 years ago
# 修改物理路径
def setPathApi(self):
mid = request.form.get('id', '').encode('utf-8')
path = request.form.get('path', '').encode('utf-8')
path = self.getPath(path)
print path
if path == "" or mid == '0':
return public.returnJson(False, "目录不能为空!")
import files_api
if not files_api.files_api().checkDir(path):
return public.returnJson(False, "不能以系统关键目录作为站点目录")
siteFind = public.M("sites").where(
"id=?", (mid,)).field('path,name').find()
if siteFind["path"] == path:
return public.returnJson(False, "与原路径一致,无需修改!")
file = self.getHostConf(siteFind['name'])
conf = public.readFile(file)
if conf:
conf = conf.replace(siteFind['path'], path)
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/:/proc/')
public.execShell('chmod 644 ' + userIni)
public.execShell('chown root:root ' + userIni)
public.execShell('chattr +i ' + userIni)
public.restartWeb()
public.M("sites").where("id=?", (mid,)).setField('path', path)
msg = public.getInfo('修改网站[{1}]物理路径成功!', (siteFind['name'],))
public.writeLog('网站管理', msg)
return public.returnJson(True, "设置成功!")
# 设置当前站点运行目录
def setSiteRunPathApi(self):
mid = request.form.get('id', '').encode('utf-8')
runPath = request.form.get('runPath', '').encode('utf-8')
siteName = public.M('sites').where('id=?', (mid,)).getField('name')
sitePath = public.M('sites').where('id=?', (mid,)).getField('path')
newPath = sitePath + runPath
# 处理Nginx
filename = self.getHostConf(siteName)
if os.path.exists(filename):
conf = public.readFile(filename)
rep = '\s*root\s*(.+);'
path = re.search(rep, conf).groups()[0]
conf = conf.replace(path, newPath)
public.writeFile(filename, conf)
self.delUserInI(sitePath)
self.setDirUserINI(newPath)
public.restartWeb()
return public.returnJson(True, '设置成功!')
6 years ago
# 设置目录加密
def setHasPwdApi(self):
username = request.form.get('username', '').encode('utf-8')
password = request.form.get('password', '').encode('utf-8')
siteName = request.form.get('siteName', '').encode('utf-8')
mid = request.form.get('id', '')
6 years ago
6 years ago
if len(username.strip()) == 0 or len(password.strip()) == 0:
return public.returnJson(False, '用户名或密码不能为空!')
if siteName == '':
siteName = public.M('sites').where('id=?', (mid,)).getField('name')
# self.closeHasPwd(get)
6 years ago
filename = self.passPath + '/' + siteName + '.pass'
print filename
6 years ago
passconf = username + ':' + public.hasPwd(password)
6 years ago
if siteName == 'phpmyadmin':
6 years ago
configFile = self.setupPath + '/openresty/nginx/conf/nginx.conf'
else:
configFile = self.setupPath + '/openresty/nginx/vhost/' + siteName + '.conf'
# 处理Nginx配置
conf = public.readFile(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(configFile, conf)
# 写密码配置
passDir = self.passPath
if not os.path.exists(passDir):
6 years ago
public.execShell('mkdir -p ' + passDir)
6 years ago
public.writeFile(filename, passconf)
public.restartWeb()
msg = public.getInfo('设置网站[{1}]为需要密码认证!', (siteName,))
public.writeLog("网站管理", msg)
return public.returnJson(True, '设置成功!')
# 取消目录加密
# 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)
6 years ago
# public.restartWeb()
# public.WriteLog("网站管理", "SITE_AUTH_CLOSE_SUCCESS",
6 years ago
# (get.siteName,))
# return public.returnMsg(True, 'SET_SUCCESS')
6 years ago
def delDomainApi(self):
domain = request.form.get('domain', '').encode('utf-8')
webname = request.form.get('webname', '').encode('utf-8')
port = request.form.get('port', '').encode('utf-8')
pid = request.form.get('id', '')
find = public.M('domain').where("pid=? AND name=?",
(pid, domain)).field('id,name').find()
domain_count = public.M('domain').where("pid=?", (pid,)).count()
if domain_count == 1:
return public.returnJson(False, '最后一个域名不能删除!')
6 years ago
file = self.getHostConf(webname)
6 years ago
conf = public.readFile(file)
if conf:
# 删除域名
rep = "server_name\s+(.+);"
tmp = re.search(rep, conf).group()
newServerName = tmp.replace(' ' + domain + ';', ';')
newServerName = newServerName.replace(' ' + domain + ' ', ' ')
conf = conf.replace(tmp, newServerName)
# 删除端口
rep = "listen\s+([0-9]+);"
tmp = re.findall(rep, conf)
port_count = public.M('domain').where(
'pid=? AND port=?', (pid, port)).count()
if public.inArray(tmp, port) == True and port_count < 2:
rep = "\n*\s+listen\s+" + port + ";"
conf = re.sub(rep, '', conf)
# 保存配置
public.writeFile(file, conf)
public.M('domain').where("id=?", (find['id'],)).delete()
msg = public.getInfo('网站[{1}]删除域名[{2}]成功!', (webname, domain))
public.writeLog('TYPE_SITE', msg)
public.restartWeb()
return public.returnJson(True, '站点删除成功!')
6 years ago
def deleteApi(self):
sid = request.form.get('id', '').encode('utf-8')
webname = request.form.get('webname', '').encode('utf-8')
6 years ago
path = request.form.get('path', '0').encode('utf-8')
return self.delete(sid, webname, path)
6 years ago
##### ----- end ----- ###
# 域名编码转换
6 years ago
def toPunycode(self, domain):
import re
if sys.version_info[0] == 2:
domain = domain.encode('utf8')
tmp = domain.split('.')
newdomain = ''
for dkey in tmp:
# 匹配非ascii字符
match = re.search(u"[\x80-\xff]+", dkey)
if not match:
newdomain += dkey + '.'
else:
newdomain += 'xn--' + \
dkey.decode('utf-8').encode('punycode') + '.'
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:
return path
npath = ''
for ph in path.split('/'):
npath += '/' + self.toPunycode(ph)
return npath.replace('//', '/')
# 路径处理
def getPath(self, path):
if path[-1] == '/':
return path[0:-1]
return path
def getSitePath(self, siteName):
file = self.getHostConf(siteName)
if os.path.exists(file):
conf = public.readFile(file)
rep = '\s*root\s*(.+);'
path = re.search(rep, conf).groups()[0]
return path
return ''
6 years ago
# 取当站点前运行目录
def getSiteRunPath(self, mid):
siteName = public.M('sites').where('id=?', (mid,)).getField('name')
sitePath = public.M('sites').where('id=?', (mid,)).getField('path')
path = sitePath
filename = self.getHostConf(siteName)
if os.path.exists(filename):
conf = public.readFile(filename)
rep = '\s*root\s*(.+);'
path = re.search(rep, conf).groups()[0]
data = {}
if sitePath == path:
data['runPath'] = '/'
else:
data['runPath'] = path.replace(sitePath, '')
dirnames = []
dirnames.append('/')
for filename in os.listdir(sitePath):
try:
filePath = sitePath + '/' + filename
if os.path.islink(filePath):
continue
if os.path.isdir(filePath):
dirnames.append('/' + filename)
except:
pass
data['dirs'] = dirnames
return data
def getHostConf(self, siteName):
6 years ago
return self.vhostPath + '/' + siteName + '.conf'
6 years ago
def getRewriteConf(self, siteName):
6 years ago
return self.rewritePath + '/' + siteName + '.conf'
6 years ago
def getDirBindRewrite(self, siteName, dirname):
return self.rewritePath + '/' + siteName + '_' + dirname + '.conf'
def getIndexConf(self):
return public.getServerDir() + '/openresty/nginx/conf/nginx.conf'
6 years ago
def getDomain(self, pid):
_list = public.M('domain').where("pid=?", (pid,)).field(
'id,pid,name,port,addtime').select()
return public.getJson(_list)
def getLogs(self, siteName):
logPath = public.getLogsDir() + '/' + siteName + '.log'
if not os.path.exists(logPath):
return public.returnJson(False, '日志为空')
6 years ago
return public.returnJson(True, public.getNumLines(logPath, 100))
6 years ago
6 years ago
# 取日志状态
def getLogsStatus(self, siteName):
filename = self.getHostConf(siteName)
conf = public.readFile(filename)
if conf.find('#ErrorLog') != -1:
return False
if conf.find("access_log /dev/null") != -1:
return False
return True
# 取目录加密状态
def getHasPwd(self, siteName):
filename = self.getHostConf(siteName)
conf = public.readFile(filename)
if conf.find('#AUTH_START') != -1:
return True
return False
6 years ago
def getSitePhpVersion(self, siteName):
6 years ago
conf = public.readFile(self.getHostConf(siteName))
6 years ago
rep = "enable-php-([0-9]{2,3})\.conf"
tmp = re.search(rep, conf).groups()
data = {}
data['phpversion'] = tmp[0]
return public.getJson(data)
6 years ago
def getIndex(self, sid):
siteName = public.M('sites').where("id=?", (sid,)).getField('name')
file = self.getHostConf(siteName)
conf = public.readFile(file)
rep = "\s+index\s+(.+);"
tmp = re.search(rep, conf).groups()
return tmp[0].replace(' ', ',')
def setIndex(self, sid, index):
if index.find('.') == -1:
return public.returnJson(False, '默认文档格式不正确,例:index.html')
index = index.replace(' ', '')
index = index.replace(',,', ',')
if len(index) < 3:
return public.returnJson(False, '默认文档不能为空!')
siteName = public.M('sites').where("id=?", (sid,)).getField('name')
index_l = index.replace(",", " ")
file = self.getHostConf(siteName)
conf = public.readFile(file)
if conf:
rep = "\s+index\s+.+;"
conf = re.sub(rep, "\n\tindex " + index_l + ";", conf)
public.writeFile(file, conf)
public.writeLog('TYPE_SITE', 'SITE_INDEX_SUCCESS', (siteName, index_l))
return public.returnJson(True, '设置成功!')
def getLimitNet(self, sid):
siteName = public.M('sites').where("id=?", (sid,)).getField('name')
filename = self.getHostConf(siteName)
# 站点总并发
data = {}
conf = public.readFile(filename)
try:
rep = "\s+limit_conn\s+perserver\s+([0-9]+);"
tmp = re.search(rep, conf).groups()
data['perserver'] = int(tmp[0])
# IP并发限制
rep = "\s+limit_conn\s+perip\s+([0-9]+);"
tmp = re.search(rep, conf).groups()
data['perip'] = int(tmp[0])
# 请求并发限制
rep = "\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 public.getJson(data)
def checkIndexConf(self):
limit = self.getIndexConf()
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)
def saveLimitNet(self, sid, perserver, perip, limit_rate):
str_perserver = 'limit_conn perserver ' + perserver + ';'
str_perip = 'limit_conn perip ' + perip + ';'
str_limit_rate = 'limit_rate ' + limit_rate + 'k;'
siteName = public.M('sites').where("id=?", (sid,)).getField('name')
filename = self.getHostConf(siteName)
conf = public.readFile(filename)
if(conf.find('limit_conn perserver') != -1):
# 替换总并发
rep = "limit_conn\s+perserver\s+([0-9]+);"
conf = re.sub(rep, str_perserver, conf)
# 替换IP并发限制
rep = "limit_conn\s+perip\s+([0-9]+);"
conf = re.sub(rep, str_perip, conf)
# 替换请求流量限制
rep = "limit_rate\s+([0-9]+)\w+;"
conf = re.sub(rep, str_limit_rate, conf)
else:
conf = conf.replace('#error_page 404/404.html;', "#error_page 404/404.html;\n " +
str_perserver + "\n " + str_perip + "\n " + str_limit_rate)
public.writeFile(filename, conf)
public.restartWeb()
public.writeLog('TYPE_SITE', 'SITE_NETLIMIT_OPEN_SUCCESS', (siteName,))
return public.returnJson(True, '设置成功!')
def closeLimitNet(self, sid):
siteName = public.M('sites').where("id=?", (sid,)).getField('name')
filename = self.getHostConf(siteName)
conf = public.readFile(filename)
# 清理总并发
rep = "\s+limit_conn\s+perserver\s+([0-9]+);"
conf = re.sub(rep, '', conf)
# 清理IP并发限制
rep = "\s+limit_conn\s+perip\s+([0-9]+);"
conf = re.sub(rep, '', conf)
# 清理请求流量限制
rep = "\s+limit_rate\s+([0-9]+)\w+;"
conf = re.sub(rep, '', conf)
public.writeFile(filename, conf)
public.restartWeb()
public.writeLog(
'TYPE_SITE', 'SITE_NETLIMIT_CLOSE_SUCCESS', (siteName,))
return public.returnJson(True, '已关闭流量限制!')
6 years ago
6 years ago
def getSecurity(self, sid, name):
filename = self.getHostConf(name)
conf = public.readFile(filename)
data = {}
if conf.find('SECURITY-START') != -1:
rep = "#SECURITY-START(\n|.){1,500}#SECURITY-END"
tmp = re.search(rep, conf).group()
data['fix'] = re.search(
"\(.+\)\$", tmp).group().replace('(', '').replace(')$', '').replace('|', ',')
data['domains'] = ','.join(re.search(
"valid_referers\s+none\s+blocked\s+(.+);\n", tmp).groups()[0].split())
data['status'] = True
else:
data['fix'] = 'jpg,jpeg,gif,png,js,css'
domains = public.M('domain').where(
'pid=?', (sid,)).field('name').select()
tmp = []
for domain in domains:
tmp.append(domain['name'])
data['domains'] = ','.join(tmp)
data['status'] = False
return public.getJson(data)
def setSecurity(self, sid, name, fix, domains, status):
if len(fix) < 2:
return public.returnJson(False, 'URL后缀不能为空!')
file = self.getHostConf(name)
if os.path.exists(file):
conf = public.readFile(file)
if conf.find('SECURITY-START') != -1:
rep = "\s{0,4}#SECURITY-START(\n|.){1,500}#SECURITY-END\n?"
conf = re.sub(rep, '', conf)
public.writeLog('网站管理', '站点[' + name + ']已关闭防盗链设置!')
else:
rconf = '''#SECURITY-START 防盗链配置
6 years ago
location ~ .*\.(%s)$
{
expires 30d;
access_log /dev/null;
valid_referers none blocked %s;
if ($invalid_referer){
return 404;
6 years ago
}
6 years ago
}
# SECURITY-END
include enable-php-''' % (fix.strip().replace(',', '|'), domains.strip().replace(',', ' '))
6 years ago
conf = re.sub("include\s+enable-php-", rconf, conf)
public.writeLog('网站管理', '站点[' + name + ']已开启防盗链!')
public.writeFile(file, conf)
public.restartWeb()
return public.returnJson(True, '设置成功!')
6 years ago
def getPhpVersion(self):
phpVersions = ('00', '52', '53', '54', '55',
'56', '70', '71', '72', '73', '74')
data = []
for val in phpVersions:
tmp = {}
if val == '00':
6 years ago
tmp['version'] = '00'
6 years ago
tmp['name'] = '纯静态'
data.append(tmp)
checkPath = public.getServerDir() + '/php/' + val + '/bin/php'
if os.path.exists(checkPath):
tmp['version'] = val
tmp['name'] = 'PHP-' + val
data.append(tmp)
return public.getJson(data)
6 years ago
# 是否跳转到https
def isToHttps(self, siteName):
file = self.getHostConf(siteName)
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
6 years ago
def getRewriteList(self):
rewriteList = {}
rewriteList['rewrite'] = []
rewriteList['rewrite'].append('0.当前')
for ds in os.listdir('rewrite/nginx'):
rewriteList['rewrite'].append(ds[0:len(ds) - 5])
rewriteList['rewrite'] = sorted(rewriteList['rewrite'])
return rewriteList
def createRootDir(self, path):
if not os.path.exists(path):
os.makedirs(path)
6 years ago
if not public.isAppleSystem():
public.execShell('chown -R www:www ' + path)
public.execShell('chmod -R 755 ' + path)
6 years ago
6 years ago
def nginxAddDomain(self, webname, domain, port):
file = self.getHostConf(webname)
6 years ago
conf = public.readFile(file)
if not conf:
return
# 添加域名
rep = "server_name\s*(.*);"
tmp = re.search(rep, conf).group()
domains = tmp.split(' ')
if not public.inArray(domains, domain):
newServerName = tmp.replace(';', ' ' + domain + ';')
conf = conf.replace(tmp, newServerName)
# 添加端口
rep = "listen\s+([0-9]+)\s*[default_server]*\s*;"
tmp = re.findall(rep, conf)
if not public.inArray(tmp, port):
listen = re.search(rep, conf).group()
conf = conf.replace(
listen, listen + "\n\tlisten " + port + ';')
# 保存配置文件
public.writeFile(file, conf)
return True
6 years ago
6 years ago
def nginxAddConf(self):
6 years ago
source_tpl = public.getRunDir() + '/data/tpl/nginx.conf'
6 years ago
vhost_file = self.vhostPath + '/' + self.siteName + '.conf'
6 years ago
content = public.readFile(source_tpl)
content = content.replace('{$PORT}', self.sitePort)
content = content.replace('{$SERVER_NAME}', self.siteName)
content = content.replace('{$ROOT_DIR}', self.sitePath)
content = content.replace('{$PHPVER}', self.phpVersion)
6 years ago
content = content.replace('{$OR_REWRITE}', self.rewritePath)
6 years ago
logsPath = public.getLogsDir()
content = content.replace('{$LOGPATH}', logsPath)
public.writeFile(vhost_file, content)
6 years ago
rewrite_content = '''
location /{
if (!-e $request_filename) {
rewrite ^(.*)$ /index.php/$1 last;
break;
}
}
'''
6 years ago
rewrite_file = self.rewritePath + '/' + self.siteName + '.conf'
6 years ago
public.writeFile(rewrite_file, rewrite_content)
6 years ago
def add(self, webname, port, ps, path, version):
6 years ago
6 years ago
siteMenu = json.loads(webname)
6 years ago
self.siteName = self.toPunycode(
siteMenu['domain'].strip().split(':')[0]).strip()
self.sitePath = self.toPunycodePath(
self.getPath(path.replace(' ', '')))
self.sitePort = port.strip().replace(' ', '')
6 years ago
self.phpVersion = version
siteM = public.M('sites')
if siteM.where("name=?", (self.siteName,)).count():
return public.returnJson(False, '您添加的站点已存在!')
6 years ago
# 写入数据库
6 years ago
pid = siteM.add('name,path,status,ps,edate,addtime',
(self.siteName, self.sitePath, '1', ps, '0000-00-00', public.getDate()))
6 years ago
opid = public.M('domain').where(
"name=?", (self.siteName,)).getField('pid')
if opid:
if public.M('sites').where('id=?', (opid,)).count():
return public.returnJson(False, '您添加的域名已存在!')
public.M('domain').where('pid=?', (opid,)).delete()
# 添加更多域名
for domain in siteMenu['domainlist']:
sdomain = domain
swebname = self.siteName
spid = str(get.pid)
# self.addDomain(domain, webname, pid)
public.M('domain').add('pid,name,port,addtime',
(pid, self.siteName, self.sitePort, public.getDate()))
6 years ago
6 years ago
self.createRootDir(self.sitePath)
self.nginxAddConf()
6 years ago
data = {}
data['siteStatus'] = False
6 years ago
public.restartWeb()
6 years ago
return public.returnJson(True, '添加成功')
6 years ago
6 years ago
def deleteWSLogs(self, webname):
assLogPath = public.getLogsDir() + '/' + webname + '.log'
errLogPath = public.getLogsDir() + '/' + webname + '.error.log'
confFile = self.setupPath + '/openresty/nginx/conf/vhost/' + webname + '.conf'
rewriteFile = self.setupPath + '/openresty/nginx/conf/rewrite/' + webname + '.conf'
6 years ago
logs = [assLogPath, errLogPath, confFile, rewriteFile]
for i in logs:
public.deleteFile(i)
def delete(self, sid, webname, path):
self.deleteWSLogs(webname)
if path == '1':
rootPath = public.getWwwDir() + '/' + webname
public.execShell('rm -rf ' + rootPath)
6 years ago
public.M('sites').where("id=?", (sid,)).delete()
6 years ago
public.restartWeb()
6 years ago
return public.returnJson(True, '站点删除成功!')
def setEndDate(self, sid, edate):
result = public.M('sites').where(
'id=?', (sid,)).setField('edate', edate)
siteName = public.M('sites').where('id=?', (sid,)).getField('name')
public.writeLog('TYPE_SITE', '设置成功,站点到期后将自动停止!', (siteName, edate))
return public.returnJson(True, '设置成功,站点到期后将自动停止!')
6 years ago
# ssl相关方法 start
def setSslConf(self, siteName):
file = self.getHostConf(siteName)
conf = public.readFile(file)
6 years ago
keyPath = self.sslDir + siteName + '/privkey.pem'
certPath = self.sslDir + siteName + '/fullchain.pem'
6 years ago
if conf:
if conf.find('ssl_certificate') == -1:
sslStr = """#error_page 404/404.html;
6 years ago
ssl_certificate %s;
ssl_certificate_key %s;
6 years ago
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
error_page 497 https://$host$request_uri;
6 years ago
""" % (certPath, keyPath)
6 years ago
if(conf.find('ssl_certificate') != -1):
return public.returnData(True, 'SSL开启成功!')
conf = conf.replace('#error_page 404/404.html;', sslStr)
rep = "listen\s+([0-9]+)\s*[default_server]*;"
tmp = re.findall(rep, conf)
if not public.inArray(tmp, '443'):
listen = re.search(rep, conf).group()
conf = conf.replace(
listen, listen + "\n\tlisten 443 ssl http2;")
shutil.copyfile(file, '/tmp/backup.conf')
public.writeFile(file, conf)
isError = public.checkWebConfig()
if(isError != True):
shutil.copyfile('/tmp/backup.conf', file)
return public.returnData(False, '证书错误: <br><a style="color:red;">' + isError.replace("\n", '<br>') + '</a>')
public.restartWeb()
self.saveCert(keyPath, certPath)
6 years ago
6 years ago
msg = public.getInfo('网站[{1}]开启SSL成功!', siteName)
public.writeLog('TYPE_SITE', msg)
return public.returnData(True, 'SSL开启成功!')
def saveCert(self, keyPath, certPath):
try:
6 years ago
certInfo = self.getCertName(certPath)
6 years ago
if not certInfo:
6 years ago
return public.returnData(False, '证书解析失败!')
vpath = self.sslDir + certInfo['subject']
6 years ago
if not os.path.exists(vpath):
os.system('mkdir -p ' + vpath)
public.writeFile(vpath + '/privkey.pem',
6 years ago
public.readFile(keyPath))
6 years ago
public.writeFile(vpath + '/fullchain.pem',
6 years ago
public.readFile(certPath))
6 years ago
public.writeFile(vpath + '/info.json', json.dumps(certInfo))
6 years ago
return public.returnData(True, '证书保存成功!')
except Exception as e:
return public.returnData(False, '证书保存失败!')
6 years ago
# 获取证书名称
def getCertName(self, certPath):
try:
openssl = '/usr/local/openssl/bin/openssl'
if not os.path.exists(openssl):
openssl = 'openssl'
result = public.execShell(
openssl + " x509 -in " + certPath + " -noout -subject -enddate -startdate -issuer")
tmp = result[0].split("\n")
data = {}
data['subject'] = tmp[0].split('=')[-1]
data['notAfter'] = self.strfToTime(tmp[1].split('=')[1])
data['notBefore'] = self.strfToTime(tmp[2].split('=')[1])
data['issuer'] = tmp[3].split('O=')[-1].split(',')[0]
if data['issuer'].find('/') != -1:
data['issuer'] = data['issuer'].split('/')[0]
result = public.execShell(
openssl + " x509 -in " + certPath + " -noout -text|grep DNS")
data['dns'] = result[0].replace(
'DNS:', '').replace(' ', '').strip().split(',')
return data
except:
return None
6 years ago
# 清除多余user.ini
def delUserInI(self, path, up=0):
for p1 in os.listdir(path):
try:
npath = path + '/' + p1
if os.path.isdir(npath):
if up < 100:
self.delUserInI(npath, up + 1)
else:
continue
useriniPath = npath + '/.user.ini'
if not os.path.exists(useriniPath):
continue
public.execShell('which chattr && chattr -i ' + useriniPath)
public.execShell('rm -f ' + useriniPath)
except:
continue
return True
6 years ago
# 设置目录防御
def setDirUserINI(self, newPath):
filename = newPath + '/.user.ini'
if os.path.exists(filename):
public.execShell("chattr -i " + filename)
os.remove(filename)
return public.returnJson(True, '已清除防跨站设置!')
self.delUserInI(newPath)
public.writeFile(filename, 'open_basedir=' +
newPath + '/:/tmp/:/proc/')
public.execShell("chattr +i " + filename)
return public.returnJson(True, '已打开防跨站设置!')
6 years ago
# 转换时间
def strfToTime(self, sdate):
import time
return time.strftime('%Y-%m-%d', time.strptime(sdate, '%b %d %H:%M:%S %Y %Z'))
# ssl相关方法 end