420 lines
18 KiB
Python
420 lines
18 KiB
Python
|
|
#coding: utf-8
|
|||
|
|
#-------------------------------------------------------------------
|
|||
|
|
# YakPanel
|
|||
|
|
#-------------------------------------------------------------------
|
|||
|
|
# Copyright (c) 2015-2017 YakPanel(www.yakpanel.com) All rights reserved.
|
|||
|
|
#-------------------------------------------------------------------
|
|||
|
|
# Author: zhwen <zhw@yakpanel.com>
|
|||
|
|
#-------------------------------------------------------------------
|
|||
|
|
|
|||
|
|
#------------------------------
|
|||
|
|
# 站点目录密码保护
|
|||
|
|
#------------------------------
|
|||
|
|
import public,re,os,json,shutil
|
|||
|
|
from public.validate import Param
|
|||
|
|
|
|||
|
|
class SiteDirAuth:
|
|||
|
|
# 取目录加密状态
|
|||
|
|
def __init__(self):
|
|||
|
|
self.setup_path = public.GetConfigValue('setup_path')
|
|||
|
|
self.conf_file = self.setup_path + "/panel/data/site_dir_auth.json"
|
|||
|
|
# 读取配置
|
|||
|
|
def _read_conf(self):
|
|||
|
|
conf = public.readFile(self.conf_file)
|
|||
|
|
if not conf:
|
|||
|
|
conf = {}
|
|||
|
|
public.writeFile(self.conf_file,json.dumps(conf))
|
|||
|
|
return conf
|
|||
|
|
try:
|
|||
|
|
conf = json.loads(conf)
|
|||
|
|
if not isinstance(conf,dict):
|
|||
|
|
conf = {}
|
|||
|
|
public.writeFile(self.conf_file, json.dumps(conf))
|
|||
|
|
except:
|
|||
|
|
conf = {}
|
|||
|
|
public.writeFile(self.conf_file, json.dumps(conf))
|
|||
|
|
return conf
|
|||
|
|
|
|||
|
|
def _write_conf(self,conf,site_name):
|
|||
|
|
c = self._read_conf()
|
|||
|
|
if not c or site_name not in c:
|
|||
|
|
c[site_name] = [conf]
|
|||
|
|
else:
|
|||
|
|
if site_name in c:
|
|||
|
|
c[site_name].append(conf)
|
|||
|
|
public.writeFile(self.conf_file,json.dumps(c))
|
|||
|
|
|
|||
|
|
def _check_site_authorization(self,site_name):
|
|||
|
|
webserver=public.get_webserver()
|
|||
|
|
conf_file = "{setup_path}/panel/vhost/{webserver}/{site_name}.conf".format(
|
|||
|
|
setup_path=self.setup_path, site_name=site_name,webserver=webserver)
|
|||
|
|
if "Authorization" in public.readFile(conf_file):
|
|||
|
|
return True
|
|||
|
|
|
|||
|
|
|
|||
|
|
# 设置目录加密
|
|||
|
|
def set_dir_auth(self,get):
|
|||
|
|
'''
|
|||
|
|
get.name auth_name
|
|||
|
|
get.site_dir auth_dir
|
|||
|
|
get.username username
|
|||
|
|
get.password password
|
|||
|
|
get.id site id
|
|||
|
|
:param get:
|
|||
|
|
:return:
|
|||
|
|
'''
|
|||
|
|
# 校验参数
|
|||
|
|
try:
|
|||
|
|
get.validate([
|
|||
|
|
Param('site_dir').String(),
|
|||
|
|
Param('name').String(),
|
|||
|
|
Param('username').String(),
|
|||
|
|
Param('password').String(),
|
|||
|
|
Param('id').Integer(),
|
|||
|
|
], [
|
|||
|
|
public.validate.trim_filter(),
|
|||
|
|
])
|
|||
|
|
except Exception as ex:
|
|||
|
|
public.print_log("error info: {}".format(ex))
|
|||
|
|
return public.return_message(-1, 0, str(ex))
|
|||
|
|
# if len(get.username) < 3 or len(get.password) < 3:
|
|||
|
|
# return public.return_msg_gettext(False, public.lang("Username or password cannot be less than 3 characters"))
|
|||
|
|
# name = get.name
|
|||
|
|
param = self.__check_param(get)
|
|||
|
|
if param['status']==-1:
|
|||
|
|
return param
|
|||
|
|
param = param['message']
|
|||
|
|
password = param['password']
|
|||
|
|
username = param['username']
|
|||
|
|
name = param['name']
|
|||
|
|
site_dir = get.site_dir
|
|||
|
|
if public.get_webserver() == "openlitespeed":
|
|||
|
|
return public.return_message(-1, 0, public.lang("OpenLiteSpeed is currently not supported"))
|
|||
|
|
# if not hasattr(get,"password") or not get.password or not hasattr(get,"username") or not get.username:
|
|||
|
|
# return public.return_msg_gettext(False, public.lang("Please enter an account or password"))
|
|||
|
|
if not get.site_dir:
|
|||
|
|
return public.return_message(-1, 0, public.lang("Please enter the directory to be protected"))
|
|||
|
|
if not get.name:
|
|||
|
|
return public.return_message(-1, 0, public.lang("Please enter the Name"))
|
|||
|
|
passwd = public.hasPwd(password)
|
|||
|
|
site_info = self.get_site_info(get.id)
|
|||
|
|
site_name = site_info["site_name"]
|
|||
|
|
if self._check_site_authorization(site_name):
|
|||
|
|
return public.return_message(-1, 0, public.lang("Site password protection has been set, please cancel and then set. Site directory --> Password access"))
|
|||
|
|
if self._check_dir_auth(site_name, name,site_dir):
|
|||
|
|
return public.return_message(-1, 0, public.lang("Directory has been protected"))
|
|||
|
|
auth = "{user}:{passwd}".format(user=username,passwd=passwd)
|
|||
|
|
auth_file = '{setup_path}/pass/{site_name}'.format(setup_path=self.setup_path,site_name=site_name)
|
|||
|
|
if not os.path.exists(auth_file):
|
|||
|
|
os.makedirs(auth_file)
|
|||
|
|
auth_file = auth_file+"/{}.pass".format(name)
|
|||
|
|
public.writeFile(auth_file,auth)
|
|||
|
|
# 配置独立认证文件
|
|||
|
|
self.set_dir_auth_file(site_info["site_path"],site_name,name,username,site_dir,auth_file)
|
|||
|
|
# 配置站点主文件
|
|||
|
|
result = self.set_conf(site_name,"create")
|
|||
|
|
if result:
|
|||
|
|
return public.return_message(0,0,result)
|
|||
|
|
# 检查配置
|
|||
|
|
webserver = public.get_webserver()
|
|||
|
|
result=self.check_site_conf(webserver,site_name,name)
|
|||
|
|
if result:
|
|||
|
|
return public.return_message(0,0,result)
|
|||
|
|
# 写配置
|
|||
|
|
conf = {"name":name,"site_dir":get.site_dir,"auth_file":auth_file}
|
|||
|
|
self._write_conf(conf,site_name)
|
|||
|
|
public.serviceReload()
|
|||
|
|
return public.return_message(0, 0, public.lang("Successfully created"))
|
|||
|
|
|
|||
|
|
# 检查配置是否存在
|
|||
|
|
def _check_dir_auth(self, site_name, name,site_dir):
|
|||
|
|
conf = self._read_conf()
|
|||
|
|
if not conf:
|
|||
|
|
return False
|
|||
|
|
if site_name in conf:
|
|||
|
|
for i in conf[site_name]:
|
|||
|
|
if name in i.values() or site_dir == i["site_dir"]:
|
|||
|
|
return True
|
|||
|
|
|
|||
|
|
# 获取当前站点php版本
|
|||
|
|
def get_site_php_version(self,siteName):
|
|||
|
|
try:
|
|||
|
|
conf = public.readFile(self.setup_path + '/panel/vhost/'+public.get_webserver()+'/'+siteName+'.conf');
|
|||
|
|
if public.get_webserver() == 'nginx':
|
|||
|
|
rep = r"enable-php-(\w{2,5})\.conf"
|
|||
|
|
tmp = re.search(rep,conf)
|
|||
|
|
if not tmp:
|
|||
|
|
rep = r"enable-php-(\d+-wpfastcgi).conf"
|
|||
|
|
re.search(rep, conf)
|
|||
|
|
else:
|
|||
|
|
rep = r"php-cgi-(\w{2,5})\.sock"
|
|||
|
|
tmp = re.search(rep,conf).groups()
|
|||
|
|
if tmp:
|
|||
|
|
return tmp[0]
|
|||
|
|
else:
|
|||
|
|
return ""
|
|||
|
|
except:
|
|||
|
|
return public.return_msg_gettext(False, public.lang("Apache2.2 does NOT support MultiPHP!"))
|
|||
|
|
|
|||
|
|
# 获取站点名
|
|||
|
|
def get_site_info(self,id):
|
|||
|
|
site_info = public.M('sites').where('id=?', (id,)).field('name,path').find()
|
|||
|
|
return {"site_name":site_info["name"],"site_path":site_info["path"]}
|
|||
|
|
|
|||
|
|
def change_dir_auth_file_nginx_phpver(self,site_name,phpv,auth_name):
|
|||
|
|
file_path = "{setup_path}/panel/vhost/nginx/dir_auth/{site_name}/{auth_name}.conf".format(
|
|||
|
|
setup_path=self.setup_path,site_name=site_name,auth_name=auth_name)
|
|||
|
|
conf = public.readFile(file_path)
|
|||
|
|
if not conf:
|
|||
|
|
return False
|
|||
|
|
|
|||
|
|
if phpv == 'other':
|
|||
|
|
php_conf = "include /www/server/panel/vhost/other_php/{}/enable-php-other.conf;".format(site_name)
|
|||
|
|
else:
|
|||
|
|
php_conf = 'include enable-php-{}.conf;'.format(phpv)
|
|||
|
|
|
|||
|
|
rep = r"include\s+(enable-php-\w+|/www/server/panel/vhost/other_php/{}/enable-php-other)\.conf;".format(site_name)
|
|||
|
|
conf = re.sub(rep,php_conf,conf)
|
|||
|
|
|
|||
|
|
public.writeFile(file_path,conf)
|
|||
|
|
|
|||
|
|
# 设置独立认证文件
|
|||
|
|
def set_dir_auth_file(self,site_path,site_name,name,username,site_dir,auth_file):
|
|||
|
|
php_ver = self.get_site_php_version(site_name)
|
|||
|
|
php_conf = ""
|
|||
|
|
if php_ver:
|
|||
|
|
if php_ver == 'other':
|
|||
|
|
php_conf = "include /www/server/panel/vhost/other_php/{}/enable-php-{}.conf;".format(site_name,php_ver)
|
|||
|
|
else:
|
|||
|
|
php_conf = "include enable-php-{}.conf;".format(php_ver)
|
|||
|
|
|
|||
|
|
for i in ["nginx","apache"]:
|
|||
|
|
file_path = "{setup_path}/panel/vhost/{webserver}/dir_auth/{site_name}"
|
|||
|
|
if i == "nginx":
|
|||
|
|
# 设置nginx
|
|||
|
|
conf = '''location ~* ^%s* {
|
|||
|
|
#AUTH_START
|
|||
|
|
auth_basic "Authorization";
|
|||
|
|
auth_basic_user_file %s;
|
|||
|
|
%s
|
|||
|
|
#AUTH_END
|
|||
|
|
}''' % (site_dir,auth_file,php_conf)
|
|||
|
|
else:
|
|||
|
|
# 设置apache
|
|||
|
|
conf = '''<Directory "{site_path}{site_dir}">
|
|||
|
|
#AUTH_START
|
|||
|
|
AuthType basic
|
|||
|
|
AuthName "Authorization "
|
|||
|
|
AuthUserFile {auth_file}
|
|||
|
|
Require user {username}
|
|||
|
|
#AUTH_END
|
|||
|
|
SetOutputFilter DEFLATE
|
|||
|
|
Options FollowSymLinks
|
|||
|
|
AllowOverride All
|
|||
|
|
#Require all granted
|
|||
|
|
DirectoryIndex index.php index.html index.htm default.php default.html default.htm
|
|||
|
|
</Directory>'''.format(site_path=site_path,site_dir=site_dir,auth_file=auth_file,username=username,site_name=site_name)
|
|||
|
|
conf_file = file_path.format(setup_path=self.setup_path,site_name=site_name,webserver=i)
|
|||
|
|
if not os.path.exists(conf_file):
|
|||
|
|
os.makedirs(conf_file)
|
|||
|
|
conf_file = conf_file + '/{}.conf'.format(name)
|
|||
|
|
public.writeFile(conf_file,conf)
|
|||
|
|
|
|||
|
|
# 设置apache配置
|
|||
|
|
def set_conf(self,site_name,act):
|
|||
|
|
for i in ["nginx", "apache"]:
|
|||
|
|
dir_auth_file = "%s/panel/vhost/%s/dir_auth/%s/*.conf" % (self.setup_path,i,site_name,)
|
|||
|
|
file = self.setup_path + "/panel/vhost/{}/".format(i) + site_name + ".conf"
|
|||
|
|
shutil.copyfile(file, '/tmp/{}_file_bk.conf'.format(i))
|
|||
|
|
|
|||
|
|
if os.path.exists(file):
|
|||
|
|
conf = public.readFile(file)
|
|||
|
|
if i == "apache":
|
|||
|
|
if act == "create":
|
|||
|
|
rep = "IncludeOptional.*\\/dir_auth\\/.*conf(\n|.)+<\\/VirtualHost>"
|
|||
|
|
rep1 = "</VirtualHost>"
|
|||
|
|
if not re.search(rep, conf):
|
|||
|
|
conf = conf.replace(rep1,
|
|||
|
|
"\n\t#Directory protection rules, do not manually delete\n\tIncludeOptional {}\n</VirtualHost>".format(
|
|||
|
|
dir_auth_file))
|
|||
|
|
else:
|
|||
|
|
rep = "\n*#Directory protection rules, do not manually delete\n+\\s+IncludeOptional[\\s\\w\\/\\.\\*]+"
|
|||
|
|
conf = re.sub(rep, '', conf)
|
|||
|
|
public.writeFile(file, conf)
|
|||
|
|
else:
|
|||
|
|
if act == "create":
|
|||
|
|
rep = "#SSL-END(\n|.)+include.*\\/dir_auth\\/.*conf;"
|
|||
|
|
rep1 = "#SSL-END"
|
|||
|
|
if not re.search(rep,conf):
|
|||
|
|
conf = conf.replace(rep1, rep1 + "\n\t#Directory protection rules, do not manually delete\n\tinclude {};".format(dir_auth_file))
|
|||
|
|
else:
|
|||
|
|
rep = "\n*#Directory protection rules, do not manually delete\n+\\s+include[\\s\\w\\/\\.\\*]+;"
|
|||
|
|
conf = re.sub(rep, '', conf)
|
|||
|
|
public.writeFile(file, conf)
|
|||
|
|
|
|||
|
|
# 验证站点配置
|
|||
|
|
def check_site_conf(self,webserver,site_name,name):
|
|||
|
|
isError = public.checkWebConfig()
|
|||
|
|
auth_file = "{setup_path}/panel/vhost/{webserver}/dir_auth/{site_name}/{name}.conf".format(setup_path=self.setup_path,webserver=webserver,site_name=site_name,name=name)
|
|||
|
|
if (isError != True):
|
|||
|
|
os.remove(auth_file)
|
|||
|
|
# a_conf = self._read_conf()
|
|||
|
|
# for i in range(len(a_conf)-1,-1,-1):
|
|||
|
|
# if site_name == a_conf[i]["sitename"] and a_conf[i]["proxyname"]:
|
|||
|
|
# del a_conf[i]
|
|||
|
|
return public.return_msg_gettext(False, public.lang('ERROR: %s<br><a style="color:red;">' % public.lang("Configuration ERROR") + isError.replace("\n", '<br>') + '</a>'))
|
|||
|
|
|
|||
|
|
# 删除密码保护
|
|||
|
|
def delete_dir_auth(self,get):
|
|||
|
|
'''
|
|||
|
|
get.id
|
|||
|
|
get.name
|
|||
|
|
:param get:
|
|||
|
|
:return:
|
|||
|
|
'''
|
|||
|
|
try:
|
|||
|
|
get.validate([
|
|||
|
|
Param('name').String(),
|
|||
|
|
Param('id').Integer(),
|
|||
|
|
], [
|
|||
|
|
public.validate.trim_filter(),
|
|||
|
|
])
|
|||
|
|
except Exception as ex:
|
|||
|
|
public.print_log("error info: {}".format(ex))
|
|||
|
|
return public.return_message(-1, 0, str(ex))
|
|||
|
|
|
|||
|
|
name = get.name
|
|||
|
|
site_info = self.get_site_info(get.id)
|
|||
|
|
site_name = site_info["site_name"]
|
|||
|
|
conf = self._read_conf()
|
|||
|
|
if site_name not in conf:
|
|||
|
|
return public.return_message(-1,0,"The website does not exist in the configuration:{}",(site_name,))
|
|||
|
|
for i in range(len(conf[site_name])):
|
|||
|
|
if name in conf[site_name][i].values():
|
|||
|
|
print(conf[site_name][i])
|
|||
|
|
del(conf[site_name][i])
|
|||
|
|
if not conf[site_name]:
|
|||
|
|
del(conf[site_name])
|
|||
|
|
break
|
|||
|
|
public.writeFile(self.conf_file,json.dumps(conf))
|
|||
|
|
for i in ["nginx", "apache"]:
|
|||
|
|
file_path = "{setup_path}/panel/vhost/{webserver}/dir_auth/{site_name}/{name}.conf".format(webserver=i,
|
|||
|
|
setup_path=self.setup_path,
|
|||
|
|
site_name=site_name,
|
|||
|
|
name=name)
|
|||
|
|
os.remove(file_path)
|
|||
|
|
if not conf:
|
|||
|
|
self.set_conf(site_name,"delete")
|
|||
|
|
if not hasattr(get,'multiple'):
|
|||
|
|
public.serviceReload()
|
|||
|
|
return public.return_message(0, 0, public.lang("Successfully deleted!"))
|
|||
|
|
|
|||
|
|
# 修改目录保护密码
|
|||
|
|
def modify_dir_auth_pass(self,get):
|
|||
|
|
'''
|
|||
|
|
get.id
|
|||
|
|
get.name
|
|||
|
|
get.username
|
|||
|
|
get.password
|
|||
|
|
:param get:
|
|||
|
|
:return:
|
|||
|
|
'''
|
|||
|
|
# 校验参数
|
|||
|
|
try:
|
|||
|
|
get.validate([
|
|||
|
|
Param('name').String(),
|
|||
|
|
Param('username').String(),
|
|||
|
|
Param('password').String(),
|
|||
|
|
Param('id').Integer(),
|
|||
|
|
|
|||
|
|
], [
|
|||
|
|
public.validate.trim_filter(),
|
|||
|
|
])
|
|||
|
|
except Exception as ex:
|
|||
|
|
public.print_log("error info: {}".format(ex))
|
|||
|
|
return public.return_message(-1, 0, str(ex))
|
|||
|
|
|
|||
|
|
# if not hasattr(get,"password") or not get.password or not hasattr(get,"username") or not get.username:
|
|||
|
|
# return public.return_msg_gettext(False, public.lang("Username or password cannot be less than 3 characters"))
|
|||
|
|
param = self.__check_param(get)
|
|||
|
|
if param['status']==-1:
|
|||
|
|
return param
|
|||
|
|
param = param['message']
|
|||
|
|
password = param['password']
|
|||
|
|
username = param['username']
|
|||
|
|
name = get.name
|
|||
|
|
site_info = self.get_site_info(get.id)
|
|||
|
|
site_name = site_info["site_name"]
|
|||
|
|
passwd = public.hasPwd(get.password)
|
|||
|
|
auth = "{user}:{passwd}".format(user=get.username,passwd=passwd)
|
|||
|
|
auth_file = '{setup_path}/pass/{site_name}/{name}.pass'.format(setup_path=self.setup_path,site_name=site_name,name=name)
|
|||
|
|
public.writeFile(auth_file,auth)
|
|||
|
|
public.serviceReload()
|
|||
|
|
return public.return_message(0, 0, public.lang("Setup successfully!"))
|
|||
|
|
|
|||
|
|
# 获取目录保护列表
|
|||
|
|
def get_dir_auth(self,get):
|
|||
|
|
'''
|
|||
|
|
get.id
|
|||
|
|
get.sitename
|
|||
|
|
:param get:
|
|||
|
|
:return:
|
|||
|
|
'''
|
|||
|
|
# 校验参数
|
|||
|
|
try:
|
|||
|
|
get.validate([
|
|||
|
|
Param('id').Integer(),
|
|||
|
|
|
|||
|
|
], [
|
|||
|
|
public.validate.trim_filter(),
|
|||
|
|
])
|
|||
|
|
except Exception as ex:
|
|||
|
|
public.print_log("error info: {}".format(ex))
|
|||
|
|
return public.return_message(-1, 0, str(ex))
|
|||
|
|
|
|||
|
|
if not hasattr(get, 'siteName'):
|
|||
|
|
site_info = self.get_site_info(get.id)
|
|||
|
|
site_name = site_info["site_name"]
|
|||
|
|
else:
|
|||
|
|
site_name = get.siteName
|
|||
|
|
conf = self._read_conf()
|
|||
|
|
if site_name in conf:
|
|||
|
|
return public.return_message(0,0,{site_name:conf[site_name]})
|
|||
|
|
return public.return_message(0,0,{})
|
|||
|
|
|
|||
|
|
def __check_param(self, get):
|
|||
|
|
values = {}
|
|||
|
|
if hasattr(get, "password"):
|
|||
|
|
if not get.password:
|
|||
|
|
return public.return_message(-1, 0, public.lang("Please enter password!"))
|
|||
|
|
password = get.password.strip()
|
|||
|
|
if len(password) < 3:
|
|||
|
|
return public.return_message(-1, 0, public.lang("Password cannot be less than 3 characters"))
|
|||
|
|
if re.search(r'\s', password):
|
|||
|
|
return public.return_message(-1, 0, public.lang("Password cannot contain spaces"))
|
|||
|
|
values['password'] = password
|
|||
|
|
|
|||
|
|
if hasattr(get, "username"):
|
|||
|
|
if not get.username:
|
|||
|
|
return public.return_message(-1, 0, public.lang("Please enter username!"))
|
|||
|
|
username = get.username.strip()
|
|||
|
|
if len(username) < 3:
|
|||
|
|
return public.return_message(-1, 0, public.lang("Username cannot be less than 3 characters"))
|
|||
|
|
if re.search(r'\s', username):
|
|||
|
|
return public.return_message(-1, 0, public.lang("Username cannot contain spaces"))
|
|||
|
|
values['username'] = username
|
|||
|
|
|
|||
|
|
if hasattr(get, "name"):
|
|||
|
|
if not get.name:
|
|||
|
|
return public.return_message(-1, 0, public.lang("Please enter a name!"))
|
|||
|
|
name = get.name.strip()
|
|||
|
|
if len(name) < 3:
|
|||
|
|
return public.return_message(-1, 0, public.lang("Name cannot be less than 3 characters"))
|
|||
|
|
if re.search(r'\s', name):
|
|||
|
|
return public.return_message(-1, 0, public.lang("Name cannot contain spaces"))
|
|||
|
|
if re.search('[\\/\"\'\\!@#$%^&*()+={}\\[\\]\\:\\;\\?><,./\\\\]+', name):
|
|||
|
|
return public.return_message(-1, 0, public.lang("Name format must be [ aaa_bbb ]"))
|
|||
|
|
values['name'] = name
|
|||
|
|
|
|||
|
|
return public.return_message(0,0, values)
|