#coding: utf-8
#-------------------------------------------------------------------
# 宝塔Linux面板
#-------------------------------------------------------------------
# Copyright (c) 2015-2017 宝塔软件(http:#bt.cn) All rights reserved.
#-------------------------------------------------------------------
# Author: zhwen<zhw@bt.cn>
#-------------------------------------------------------------------

#------------------------------
# 站点目录密码保护
#------------------------------
import public,re,os,json,shutil

class SiteDirAuth:
    # 取目录加密状态
    def __init__(self):
        self.webserver = public.get_webserver()
        self.setup_path = public.GetConfigValue('setup_path')
        self.conf_file = self.setup_path + "/panel/data/site_dir_auth.json"

    def get_conf_path(self,siteName):
        """
        获取网站配置文件路径
        @siteName 网站名称
        """
        path = self.setup_path
        if self.webserver == 'apache':
            path  = path + '/apache/conf/vhost/' + siteName + '.conf'
            return path
        elif self.webserver == 'nginx':
            path  = path + '/nginx/conf/vhost/' + siteName + '.conf'
            return path
        return None

    def get_auth_path(self,siteName):
        """
        授权目录
        @siteName 网站名称
        """
        path = self.setup_path
        if self.webserver == 'apache':
            path  = path + '/apache/conf/dir_auth/' + siteName
            if not os.path.exists(path): os.makedirs(path)
            return path
        elif self.webserver == 'nginx':
            path  = path + '/nginx/conf/dir_auth/' + siteName
            if not os.path.exists(path): os.makedirs(path)
            return path
        return None

    # 读取配置
    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):

        conf_file = self.get_conf_path(site_name)
        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:
        '''
        name = get.name
        site_dir = get.site_dir
        if public.get_webserver() == "openlitespeed":
            return public.returnMsg(False,"OpenLiteSpeed is currently not supported")

        password = get.password.strip()
        username = get.username.strip()
        if len(password) <= 0 or len(username) <= 0:
            return public.returnMsg(False, '请输入账号或密码')
        if not get.site_dir:
            return public.returnMsg(False, '请输入需要保护的目录')
        if not get.name:
            return public.returnMsg(False, '请输入名称')

        site_info = self.get_site_info(get.id)
        site_name = site_info["site_name"]
        if self._check_site_authorization(site_name):
            return public.returnMsg(False, '已经设置站点密码保护，请取消后再设置 站点配置 --> 站点目录 --> 密码访问')
        if self._check_dir_auth(site_name, name,site_dir):
            return public.returnMsg(False, '目录已经保护')
        
        if site_dir[0] == "/":
            site_dir = site_dir[1:]
            if site_dir and site_dir[-1] == "/":
                site_dir = site_dir[:-1]

        auth_path = self.get_auth_path(site_info["site_name"])
        public.writeFile(auth_path + '/' + name + '.pass'  ,username + ":" + password)

        auth_file = auth_path + '/' + name + '.conf' 
             
        conf_path =  self.get_conf_path(site_info["site_name"])
        conf = public.readFile(conf_path)
        if self.webserver == 'nginx':     
            #配置主配置文件
            if not re.search('include\s+dir_auth.+;',conf):
                conf = re.sub('#REWRITE-END\s+','#REWRITE-END\n\n\t#目录保护\n\tinclude dir_auth/' + site_info["site_name"] + '/*.conf;\n\n\t',conf)
                public.writeFile(conf_path,conf)
            
            #认证配置文件
            sub_conf = '''	location ~* ^/%s* {
		auth_basic "Authorization";
		auth_basic_user_file dir_auth/%s/%s.pass;
	}''' % (site_dir,site_info["site_name"],name)

            public.writeFile(auth_path + '/' + name + '.conf',sub_conf)

        else:            
            #配置主配置文件
            if not re.search('IncludeOptional\s+conf/dir_auth.+',conf):
                conf = re.sub('combined\s+','combined\n\n\t\t#目录保护\n\t\tIncludeOptional conf/dir_auth/' + site_info["site_name"] + '/*.conf\n\n\t\t',conf)
                public.writeFile(conf_path,conf)

            #认证配置文件
            sub_conf = '''<Directory "%s/%s/">
    AuthType basic
    AuthName "Authorization"
    AuthUserFile conf/dir_auth/%s/%s.pass
    Require user %s
    SetOutputFilter DEFLATE
    Options FollowSymLinks
    AllowOverride All
    DirectoryIndex index.php index.html index.htm default.php default.html default.htm
</Directory>''' % (site_info['site_path'],site_dir,site_info["site_name"],name,username)

            public.writeFile(auth_path + '/' + name + '.conf',sub_conf)

        # 检查配置
        webserver = public.get_webserver()
        result=self.check_site_conf(webserver,site_name,name)
        if result:
            return result
        # 写配置
        conf = {"name":name,"site_dir":get.site_dir,"auth_file":auth_file}
        self._write_conf(conf,site_name)
        public.serviceReload()
        return public.returnMsg(True,"创建成功")

    # 检查配置是否存在
    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:
            if self.webserver == 'apache':           
                filename = self.get_conf_path(siteName)
                if os.path.exists(filename):          
                    conf = public.readFile(filename)
                    tmp = re.search('/php/(.+).conf',conf)            
                    if tmp: return tmp.groups()[0]       
            else:
                filename = self.get_conf_path(siteName)               
                if os.path.exists(filename):          
                    conf = public.readFile(filename)
                    tmp = re.search('include php/(\d+).conf;',conf)                  
                    if tmp: return tmp.groups()[0]    
            return "";
        except:
            return public.returnMsg(False, 'SITE_PHPVERSION_ERR_A22')

    # 获取站点名
    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 check_site_conf(self,webserver,site_name,name):
        isError = public.checkWebConfig()
        auth_path = self.get_auth_path(site_name)
        auth_file = auth_path + '/' + name + '.conf' 
        if (isError != True):
            if os.path.exists(auth_file): 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.returnMsg(False, 'ERROR: %s<br><a style="color:red;">' % public.GetMsg("CONFIG_ERROR") + isError.replace("\n",
                                                                                                          '<br>') + '</a>')

    # 删除密码保护
    def delete_dir_auth(self,get):
        '''
        get.id
        get.name
        :param get:
        :return:
        '''
        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.returnMsg(False,"配置文件中不存在网站名：{}".format(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))
        
        auth_path = self.get_auth_path(site_name)

        if os.path.exists(auth_path + '/' + name + '.conf'): os.remove(auth_path + '/' + name + '.conf')
        if os.path.exists(auth_path + '/' + name + '.pass'): os.remove(auth_path + '/' + name + '.pass')
        public.serviceReload()
        return public.returnMsg(True,"删除成功")

    # 修改目录保护密码
    def modify_dir_auth_pass(self,get):
        """
        修改目录保护密码
        @get.name 保护名称
        @get.id 网站id
        """
        name = get.name
        site_info = self.get_site_info(get.id)
        site_name = site_info["site_name"]
  
        password = get.password.strip()
        username = get.username.strip()
        if len(password) <= 0 or len(username) <= 0:
            return public.returnMsg(False, '请输入账号或密码')
      
        auth_path = self.get_auth_path(site_name)
        public.writeFile(auth_path + '/' + name + '.pass'  ,username + ":" + password)
      
        public.serviceReload()
        return public.returnMsg(True,"修改成功")

    # 获取目录保护列表
    def get_dir_auth(self,get):
        '''
        get.id
        :param get:
        :return:
        '''
        site_info = self.get_site_info(get.id)
        site_name = site_info["site_name"]
        conf = self._read_conf()
        if site_name in conf:
            return {site_name:conf[site_name]}
        return {}