pull/632/head
Mr Chen 6 months ago
parent 433ad507e7
commit e5ed04ce31
  1. 5
      web/admin/site/__init__.py
  2. 83
      web/admin/site/dir.py
  3. 58
      web/admin/site/redirect.py
  4. 17
      web/admin/site/site.py
  5. 33
      web/admin/site/ssl.py
  6. 3
      web/core/db.py
  7. 33
      web/static/app/site.js
  8. 16
      web/thisdb/binding.py
  9. 6
      web/thisdb/domain.py
  10. 265
      web/utils/site.py

@ -12,4 +12,7 @@ from .site import *
from .site_types import *
from .site_default import *
from .php import *
from .logs import *
from .logs import *
from .dir import *
from .redirect import *
from .ssl import *

@ -0,0 +1,83 @@
# coding:utf-8
# ---------------------------------------------------------------------------------
# MW-Linux面板
# ---------------------------------------------------------------------------------
# copyright (c) 2018-∞(https://github.com/midoks/mdserver-web) All rights reserved.
# ---------------------------------------------------------------------------------
# Author: midoks <midoks@163.com>
# ---------------------------------------------------------------------------------
import os
import json
from flask import Blueprint, render_template
from flask import request
from admin.user_login_check import panel_login_required
from utils.plugin import plugin as MwPlugin
from utils.site import sites as MwSites
import utils.site as site
import core.mw as mw
import thisdb
from .site import blueprint
# 获取网站目录
@blueprint.route('/get_dir_user_ini', endpoint='get_dir_user_ini',methods=['POST'])
@panel_login_required
def get_dir_user_ini():
site_id = request.form.get('id', '')
return MwSites.instance().getDirUserIni(site_id)
# 设置防跨站攻击
@blueprint.route('/set_dir_user_ini', endpoint='set_dir_user_ini',methods=['POST'])
@panel_login_required
def set_dir_user_ini():
path = request.form.get('path', '')
run_path = request.form.get('run_path', '')
return MwSites.instance().setDirUserIni(path,run_path)
# 获取子目录绑定
@blueprint.route('/get_dir_binding', endpoint='get_dir_binding',methods=['POST'])
@panel_login_required
def get_dir_binding():
site_id = request.form.get('id', '')
return MwSites.instance().getDirBinding(site_id)
# 添加子目录绑定
@blueprint.route('/add_dir_bind', endpoint='add_dir_bind',methods=['POST'])
@panel_login_required
def add_dir_bind():
site_id = request.form.get('id', '')
domain = request.form.get('domain', '')
dir_name = request.form.get('dir_name', '')
return MwSites.instance().addDirBind(site_id,domain,dir_name)
# 获取目录绑定rewrite
@blueprint.route('/get_dir_bind_rewrite', endpoint='get_dir_bind_rewrite',methods=['POST'])
@panel_login_required
def get_dir_bind_rewrite():
binding_id = request.form.get('id', '')
add = request.form.get('add', '')
return MwSites.instance().getDirBindingRewrite(binding_id,add)
# 获取目录绑定rewrite
@blueprint.route('/del_dir_bind', endpoint='del_dir_bind',methods=['POST'])
@panel_login_required
def del_dir_bind():
binding_id = request.form.get('id', '')
return MwSites.instance().delDirBinding(binding_id)

@ -0,0 +1,58 @@
# coding:utf-8
# ---------------------------------------------------------------------------------
# MW-Linux面板
# ---------------------------------------------------------------------------------
# copyright (c) 2018-∞(https://github.com/midoks/mdserver-web) All rights reserved.
# ---------------------------------------------------------------------------------
# Author: midoks <midoks@163.com>
# ---------------------------------------------------------------------------------
import os
import json
from flask import Blueprint, render_template
from flask import request
from admin.user_login_check import panel_login_required
from utils.plugin import plugin as MwPlugin
from utils.site import sites as MwSites
import utils.site as site
import core.mw as mw
import thisdb
from .site import blueprint
# 获取重定向列表
@blueprint.route('/get_redirect', endpoint='get_redirect', methods=['POST'])
@panel_login_required
def get_redirect():
site_name = request.form.get("siteName", '')
return MwSites.instance().getRedirect(site_name)
# 设置重定向列表
@blueprint.route('/set_redirect', endpoint='set_redirect', methods=['POST'])
@panel_login_required
def set_redirect():
site_name = request.form.get("siteName", '')
site_from = request.form.get("from", '')
to = request.form.get("to", '') # redirect to
type = request.form.get("type", '') # path / domain
r_type = request.form.get("r_type", '') # redirect type
keep_path = request.form.get("keep_path", '') # keep path
return MwSites.instance().setRedirect(site_name, site_from, to, type, r_type, keep_path)
# 设置重定向配置
@blueprint.route('/get_redirect_conf', endpoint='get_redirect_conf', methods=['POST'])
@panel_login_required
def get_redirect_conf():
site_name = request.form.get("siteName", '')
rid = request.form.get("id", '')
return MwSites.instance().getRedirectConf(site_name, rid)

@ -212,21 +212,6 @@ def get_php_version():
tplname = request.form.get('tplname', '')
return MwSites.instance().getRewriteTpl(tplname)
# 获取网站目录
@blueprint.route('/get_dir_user_ini', endpoint='get_dir_user_ini',methods=['POST'])
@panel_login_required
def get_dir_user_ini():
site_id = request.form.get('id', '')
return MwSites.instance().getDirUserIni(site_id)
# 设置防跨站攻击
@blueprint.route('/set_dir_user_ini', endpoint='set_dir_user_ini',methods=['POST'])
@panel_login_required
def set_dir_user_ini():
path = request.form.get('path', '')
run_path = request.form.get('run_path', '')
return MwSites.instance().setDirUserIni(path,run_path)
# 网站日志开关
@blueprint.route('/logs_open', endpoint='logs_open',methods=['POST'])
@panel_login_required
@ -252,8 +237,6 @@ def set_site_run_path():
return MwSites.instance().setSiteRunPath(site_id, run_path)
# 设置网站 - 开启密码访问
@blueprint.route('/set_has_pwd', endpoint='set_has_pwd',methods=['POST'])
@panel_login_required

@ -0,0 +1,33 @@
# coding:utf-8
# ---------------------------------------------------------------------------------
# MW-Linux面板
# ---------------------------------------------------------------------------------
# copyright (c) 2018-∞(https://github.com/midoks/mdserver-web) All rights reserved.
# ---------------------------------------------------------------------------------
# Author: midoks <midoks@163.com>
# ---------------------------------------------------------------------------------
import os
import json
from flask import Blueprint, render_template
from flask import request
from admin.user_login_check import panel_login_required
from utils.plugin import plugin as MwPlugin
from utils.site import sites as MwSites
import utils.site as site
import core.mw as mw
import thisdb
from .site import blueprint

@ -191,7 +191,8 @@ class Sql():
self.__close()
return data
except Exception as ex:
return "error: " + str(ex)
# return "error: " + str(ex)
return []
def inquiry(self, input_field=''):
# 查询数据集

@ -1347,13 +1347,13 @@ function showRewrite(rdata){
//添加子目录绑定
function addDirBinding(id){
var domain = $("input[name='domain']").val();
var dirName = $("select[name='dirName']").val();
if(domain == '' || dirName == '' || dirName == null){
var dir_name = $("select[name='dirName']").val();
if(domain == '' || dir_name == '' || dir_name == null){
layer.msg(lan.site.d_s_empty,{icon:2});
return;
}
var data = 'id='+id+'&domain='+domain+'&dirName='+dirName;
var data = 'id='+id+'&domain='+domain+'&dir_name='+dir_name;
$.post('/site/add_dir_bind',data,function(rdata){
dirBinding(id);
layer.msg(rdata.msg,{icon:rdata.status?1:2});
@ -1421,6 +1421,7 @@ function to301(siteName, type, obj){
$('.btn-colse-prosy').click(function() {
layer.close(redirect_form);
});
$('.btn-submit-redirect').click(function() {
var keep_path = $('[name="keep_path"]').prop('checked') ? 1 : 0;
var r_type = $('[name="r_type"]').val();
@ -1428,24 +1429,14 @@ function to301(siteName, type, obj){
var from = $('[name="from"]').val();
var to = $('[name="to"]').val();
$.post('/site/set_redirect', {
siteName: siteName,
type: type,
r_type: r_type,
from: from,
to: to,
keep_path: keep_path
}, function(res) {
res = JSON.parse(res);
if (res.status) {
$.post('/site/set_redirect', {siteName: siteName,type: type,r_type: r_type,from: from,to: to,keep_path: keep_path}, function(data) {
if (data.status) {
layer.close(redirect_form);
to301(siteName)
to301(siteName);
} else {
layer.msg(res.msg, {
icon: 2
});
layer.msg(data.msg, {icon: 2});
}
});
},'json');
});
}, 100);
}
@ -1455,14 +1446,13 @@ function to301(siteName, type, obj){
siteName: siteName,
id: obj,
}, function(res) {
res = JSON.parse(res);
if (res.status == true) {
layer.msg('删除成功', {time: 1000,icon: 1});
to301(siteName);
} else {
layer.msg(res.msg, {time: 1000,icon: 2});
}
});
},'json');
return
}
@ -1471,7 +1461,6 @@ function to301(siteName, type, obj){
var data = {siteName: siteName,id: obj};
$.post('/site/get_redirect_conf', data, function(res) {
layer.close(laoding);
res = JSON.parse(res);
if (res.status == true) {
var mBody = "<div class='webEdit-box' style='padding: 20px'>\
<textarea style='height: 320px; width: 445px; margin-left: 20px; line-height:18px' id='configRedirectBody'>"+res.data.result+"</textarea>\
@ -2326,7 +2315,7 @@ function opSSL(type, id, siteName, callback){
var key = '';
var csr = '';
var loadT = layer.msg('正在提交任务...',{icon:16,time:0,shade: [0.3, '#000']});
$.post('site/get_ssl','site_name='+siteName,function(data){
$.post('/site/get_ssl','site_name='+siteName,function(data){
layer.close(loadT);
var rdata = data['data'];

@ -14,6 +14,10 @@ import core.mw as mw
__FIELD = 'id,pid,domain,port,path,add_time'
def getBindingCountByDomain(name):
# .debug(True)
return mw.M('binding').where("domain=?", (name,)).count()
def addBinding(pid, domain, port, path):
now_time = mw.getDateFromNow()
insert_data = {
@ -25,15 +29,17 @@ def addBinding(pid, domain, port, path):
}
return mw.M('binding').insert(insert_data)
def getBindingListBySiteId(site_id):
task_list = mw.M('binding').where('pid=?', (site_id,)).field(__FIELD).select()
return task_list
# .debug(True)
binding_list = mw.M('binding').field(__FIELD).where('pid=?', (site_id,)).select()
return binding_list
def getBindingById(site_id):
return mw.M('binding').where("id=?", (site_id,)).field(__FIELD).find()
def deleteBindingId(domain_id):
return mw.M('binding').where("id=?", (domain_id,)).delete()
def deleteBindingById(binding_id):
return mw.M('binding').where("id=?", (binding_id,)).delete()
def deleteBindingBySiteId(site_id):
return mw.M('binding').where("pid=?", (site_id,)).delete()

@ -12,6 +12,10 @@ import core.mw as mw
__FIELD = 'id,pid,name,port,add_time'
def getDomainCountByName(name):
# .debug(True)
return mw.M('domain').where("name=?", (name,)).count()
def addDomain(pid, name, port):
now_time = mw.getDateFromNow()
insert_data = {
@ -25,7 +29,7 @@ def addDomain(pid, name, port):
def getDomainByPid(pid):
# .debug(True)
return mw.M('domain').field(__FIELD).where("pid=?", (pid,)).select()
def deleteDomainId(domain_id):
return mw.M('domain').where("id=?", (domain_id,)).delete()

@ -124,8 +124,8 @@ class sites(object):
def getProxyPath(self, siteName):
return "{}/{}".format(self.proxyPath, siteName)
def getDirBindRewrite(self, siteName, dirname):
return self.rewritePath + '/' + siteName + '_' + dirname + '.conf'
def getDirBindRewrite(self, site_name, dir_name):
return self.rewritePath + '/' + site_name + '_' + dir_name + '.conf'
def getIndexConf(self):
return mw.getServerDir() + '/openresty/nginx/conf/nginx.conf'
@ -256,8 +256,7 @@ class sites(object):
def nginxAddConf(self):
source_tpl = mw.getPanelDir() + '/data/tpl/nginx.conf'
print(source_tpl)
vhost_file = self.vhostPath + '/' + self.siteName + '.conf'
vhost_file = self.getHostConf(self.siteName)
content = mw.readFile(source_tpl)
content = content.replace('{$PORT}', self.sitePort)
@ -463,6 +462,154 @@ class sites(object):
self.addDirUserIni(site_path, run_path)
return mw.returnData(True, '已打开防跨站设置!')
def getDirBinding(self, site_id):
info = thisdb.getSitesById(site_id)
path = info['path']
if not os.path.exists(path):
checks = ['/', '/usr', '/etc']
if path in checks:
data = {}
data['dirs'] = []
data['binding'] = []
return mw.returnData(True, 'OK', data)
os.system('mkdir -p ' + path)
os.system('chmod 755 ' + path)
os.system('chown www:www ' + path)
siteName = info['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'] = thisdb.getBindingListBySiteId(site_id)
return mw.returnJson(True, 'OK', data)
def addDirBind(self, site_id, domain, dir_name):
domain_split = domain.split(':')
domain = domain_split[0]
port = '80'
if len(domain_split) > 1:
port = domain_split[1]
if dir_name == '':
mw.returnData(False, '目录不能为空!')
reg = r"^([\w\-\*]{1,100}\.){1,4}(\w{1,10}|\w{1,10}\.\w{1,10})$"
if not re.match(reg, domain):
return mw.returnData(False, '主域名格式不正确!')
info = thisdb.getSitesById(site_id)
webdir = info['path'] + '/' + dir_name
if thisdb.getBindingCountByDomain(domain):
return mw.returnData(False, '您添加的域名在子目录已存在!')
if thisdb.getDomainCountByName(domain) > 0:
return mw.returnData(False, '您添加的域名已存在!')
filename = self.getHostConf(info['name'])
conf = mw.readFile(filename)
if conf:
rep = r"enable-php-([0-9]{2,3})\.conf"
domain_split = re.search(rep, conf).groups()
version = domain_split[0]
source_dirbind_tpl = mw.getPanelDir() + '/data/tpl/nginx_dirbind.conf'
content = mw.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}', info['name'])
content = content.replace('{$OR_REWRITE}', self.rewritePath)
content = content.replace('{$PHP_DIR}', self.setupPath + '/php')
content = content.replace('{$LOGPATH}', mw.getLogsDir())
conf += "\r\n" + content
mw.backFile(filename)
mw.writeFile(filename, conf)
conf = mw.readFile(filename)
# 检查配置是否有误
isError = mw.checkWebConfig()
if isError != True:
mw.restoreFile(filename)
msg = 'ERROR: <br><a style="color:red;">' + isError.replace("\n", '<br>') + '</a>'
return mw.returnData(False, msg)
thisdb.addBinding(site_id,domain,port,dir_name)
msg = mw.getInfo('网站[{1}]子目录[{2}]绑定到[{3}]',(info['name'], dir_name, domain))
mw.writeLog('网站管理', msg)
mw.restartWeb()
mw.removeBackFile(filename)
return mw.returnData(True, '添加成功!')
# 取子目录Rewrite
def getDirBindingRewrite(self, binding_id, add):
binding_info = thisdb.getBindingById(binding_id)
info = thisdb.getSitesById(binding_info['pid'])
filename = self.getDirBindRewrite(info['name'], binding_info['path'])
if add == '1':
mw.writeFile(filename, '')
file = self.getHostConf(info['name'])
conf = mw.readFile(file)
domain = binding_info['domain']
rep = "\n#BINDING-" + domain + "-START(.|\n)+BINDING-" + domain + "-END"
tmp = re.search(rep, conf).group()
dirConf = tmp.replace('rewrite/' + info['name'] + '.conf;', 'rewrite/' + info['name'] + '_' + binding_info['path'] + '.conf;')
conf = conf.replace(tmp, dirConf)
mw.writeFile(file, conf)
data = {}
data['rewrite_dir'] = self.rewritePath
data['status'] = False
if os.path.exists(filename):
data['status'] = True
data['data'] = mw.readFile(filename)
data['rlist'] = []
for ds in os.listdir(self.rewritePath):
if ds[0:1] == '.':
continue
if ds == 'list.txt':
continue
data['rlist'].append(ds[0:len(ds) - 5])
data['filename'] = filename
return data
def delDirBinding(self, binding_id):
binding_info = thisdb.getBindingById(binding_id)
info = thisdb.getSitesById(binding_info['pid'])
filename = self.getHostConf(info['name'])
conf = mw.readFile(filename)
if conf:
rep = r"\s*.+BINDING-" + binding_info['domain'] + "-START(.|\n)+BINDING-" + binding_info['domain'] + "-END"
conf = re.sub(rep, '', conf)
mw.writeFile(filename, conf)
filename = self.getDirBindRewrite(info['name'], binding_info['path'])
if os.path.exists(filename):
os.remove(filename)
msg = mw.getInfo('删除网站[{1}]子目录[{2}]绑定',(info['name'], binding_info['path']))
mw.writeLog('网站管理', msg)
mw.restartWeb()
thisdb.deleteBindingById(binding_id)
return mw.returnJson(True, '删除成功!')
def logsOpen(self, site_id):
info = thisdb.getSitesById(site_id)
name = info['name']
@ -782,6 +929,116 @@ class sites(object):
mw.writeLog('网站管理', '网站[{1}]流量限制已关闭!', (siteName,))
return mw.returnData(True, '已关闭流量限制!')
# 获取重定向配置
def getRedirect(self, siteName):
redirect_file = self.getRedirectDataPath(siteName)
if not os.path.exists(redirect_file):
mw.execShell("mkdir {}/{}".format(self.redirectPath, siteName))
return mw.returnData(True, "no exists!", {"result": [], "count": 0})
content = mw.readFile(redirect_file)
data = json.loads(content)
# 处理301信息
return mw.returnData(True, "ok", {"result": data, "count": len(data)})
# 操作 重定向配置
def operateRedirectConf(self, siteName, method='start'):
vhost_file = self.getHostConf(siteName)
content = mw.readFile(vhost_file)
cnf_301 = '''#301-START
include %s/*.conf;
#301-END''' % (self.getRedirectPath( siteName))
cnf_301_source = '#301-START'
# print('operateRedirectConf', content.find('#301-END'))
if content.find('#301-END') != -1:
if method == 'stop':
rep = '#301-START(\n|.){1,500}#301-END'
content = re.sub(rep, '#301-START', content)
else:
if method == 'start':
content = re.sub(cnf_301_source, cnf_301, content)
mw.writeFile(vhost_file, content)
# get redirect status
def setRedirect(self, siteName, site_from, to, type, r_type, keep_path):
if siteName == '' or site_from == '' or to == '' or type == '' or r_type == '':
return mw.returnData(False, "必填项不能为空!")
redirect_file = self.getRedirectDataPath(siteName)
content = mw.readFile(redirect_file) if os.path.exists(redirect_file) else ""
data = json.loads(content) if content != "" else []
_r_type = 0 if r_type == "301" else 1
_type_code = 0 if type == "path" else 1
_keep_path = 1 if keep_path == "1" else 0
# check if domain exists in site
if _type_code == 1:
pid = mw.M('domain').where("name=?", (_siteName,)).field('id,pid,name,port,addtime').select()
site_domain_lists = mw.M('domain').where("pid=?", (pid[0]['pid'],)).field('name').select()
found = False
for item in site_domain_lists:
if item['name'] == _from:
found = True
break
if found == False:
return mw.returnData(False, "域名不存在!")
file_content = ""
# path
if _type_code == 0:
redirect_type = "permanent" if _r_type == 0 else "redirect"
if not site_from.startswith("/"):
site_from = "/{}".format(site_from)
if _keep_path == 1:
to = "{}$1".format(to)
site_from = "{}(.*)".format(site_from)
file_content = "rewrite ^{} {} {};".format(site_from, to, redirect_type)
# domain
else:
if _keep_path == 1:
_to = "{}$request_uri".format(_to)
redirect_type = "301" if _type_code == 0 else "302"
_if = "if ($host ~ '^{}')".format(site_from)
_return = "return {} {}; ".format(redirect_type, to)
file_content = _if + "{\r\n " + _return + "\r\n}"
_id = mw.md5("{}+{}".format(file_content, siteName))
# 防止规则重复
for item in data:
if item["r_from"] == site_from:
return mw.returnData(False, "重复的规则!")
rep = r"http(s)?\:\/\/([a-zA-Z0-9][-a-zA-Z0-9]{0,62}\.)+([a-zA-Z0-9][a-zA-Z0-9]{0,62})+.?"
if not re.match(rep, to):
return mw.returnData(False, "错误的目标地址")
# write data json file
data.append({"r_from": site_from, "type": _type_code, "r_type": _type_code,"r_to": to, 'keep_path': _keep_path, 'id': _id})
mw.writeFile(redirect_file, json.dumps(data))
mw.writeFile("{}/{}.conf".format(self.getRedirectPath(siteName), _id), file_content)
self.operateRedirectConf(siteName, 'start')
mw.restartWeb()
return mw.returnData(True, "设置成功")
def getRedirectConf(self,siteName, rid):
if rid == '' or siteName == '':
return mw.returnData(False, "必填项不能为空!")
path = self.getRedirectPath(siteName)
conf = "{}/{}.conf".format(path, rid)
data = mw.readFile(conf)
if data == False:
return mw.returnData(False, "获取失败!")
return mw.returnData(True, "ok", {"result": data})
def setPhpVersion(self, siteName, version):
# nginx
file = self.getHostConf(siteName)

Loading…
Cancel
Save