#coding: utf-8
# +-------------------------------------------------------------------
# | 宝塔Windows面板
# +-------------------------------------------------------------------
# | Copyright (c) 2015-2016 宝塔软件(http://www.bt.cn) All rights reserved.
# +-------------------------------------------------------------------
# | Author: 沐落 <cjx@bt.cn>
# +-------------------------------------------------------------------

#------------------------------
# SSL接口
#------------------------------

import public,os,sys,binascii,urllib,json,time,datetime,re
try:
    from BTPanel import cache,session
except:
    pass
from panelAuth import panelAuth
class panelSSL:
    #__APIURL = 'http://www.bt.cn/api/AuthCloud';
    __APIURL = 'https://www.bt.cn/api/Auth';
    __APIURL2 = 'https://www.bt.cn/api/Cert'
    __UPATH = 'data/userInfo.json';
    __userInfo = None;
    __PDATA = None;
    setupPath = None #安装路径

    #构造方法
    def __init__(self):
        self.setupPath = public.GetConfigValue('setup_path')
        pdata = {}
        data = {}
        if os.path.exists(self.__UPATH):
            try:
                self.__userInfo = json.loads(public.readFile(self.__UPATH));
                if self.__userInfo:
                    pdata['access_key'] = self.__userInfo['access_key'];
                    data['secret_key'] = self.__userInfo['secret_key'];
            except :
                self.__userInfo = None
        else:
            pdata['access_key'] = 'test';
            data['secret_key'] = '123456';
        pdata['data'] = data;
        self.__PDATA = pdata;

    def GetToken(self,get):
        """
        登录官网获取Token
        @get.username 官网手机号
        @get.password 官网账号密码
        """
        rtmp = ""
        data = {}
        data['username'] = public.rsa_decrypt(get.username)
        data['password'] = public.md5(public.rsa_decrypt(get.password))

        data['serverid'] = panelAuth().get_serverid()
        pdata = {}
        pdata['data'] = self.De_Code(data);
        try:
            rtmp = public.httpPost(self.__APIURL+'/GetToken',pdata)

            result = json.loads(rtmp);
            result['data'] = self.En_Code(result['data']);
            if result['data']:
                result['data']['serverid'] = data['serverid']
                public.writeFile(self.__UPATH,json.dumps(result['data']));
                if os.path.exists('data/bind_path.pl'): os.remove('data/bind_path.pl')
                public.flush_plugin_list()
            del(result['data']);
            session['focre_cloud'] = True
            return result;
        except Exception as ex:
            return public.returnMsg(False,'连接服务器失败!<br>' + rtmp)

    def GetAuthToken(self,get):
        """
        登录官网获取Token
        @get.username 官网手机号
        @get.password 官网账号密码
        """
        rtmp = ""
        data = {}
        data['username'] = public.rsa_decrypt(get.username)
        data['password'] = public.md5(public.rsa_decrypt(get.password))

        data['serverid'] = panelAuth().get_serverid()

        if 'code' in get: data['code'] = get.code;
        if 'token' in get: data['token'] = get.token;
        
        o_code = public.readFile('data/o.pl')
        if not o_code: o_code = ''
        data['o'] = o_code
        
        pdata = {}
        pdata['data'] = self.De_Code(data);
        try:

            rtmp = public.httpPost('https://api.bt.cn/Auth/GetAuthToken',pdata)

            result = json.loads(rtmp);
            result['data'] = self.En_Code(result['data']);
            if not result['status']: return result
            if result['data']:
                if result['data']['serverid'] != data['serverid']:
                    public.writeFile('data/sid.pl',result['data']['serverid'])
                public.writeFile(self.__UPATH,json.dumps(result['data']));

                if os.path.exists('data/bind_path.pl'): os.remove('data/bind_path.pl')
                public.flush_plugin_list()
            del(result['data']);
            session['focre_cloud'] = True
            return result;
        except Exception as ex:
            print(rtmp)
            return public.returnMsg(False,'连接服务器失败!<br>' + rtmp)

    def GetBindCode(self,get):
        """
        获取验证码
        """
        rtmp = ""
        data = {}
        data['username'] = get.username
        data['token'] = get.token;
        pdata = {}
        pdata['data'] = self.De_Code(data);
        try:
            rtmp = public.httpPost('https://api.bt.cn/Auth/GetBindCode',pdata)
            result = json.loads(rtmp);
            return result;
        except Exception as ex:
            return public.returnMsg(False,'连接服务器失败!<br>' + rtmp)

    def DelToken(self,get):
        """
        删除授权token
        """
        if os.path.exists(self.__UPATH): os.remove(self.__UPATH)
        session['focre_cloud'] = True
        return public.returnMsg(True,"SSL_BTUSER_UN");

    def GetUserInfo(self,get):
        """
        获取用户信息
        """
        result = {}
        if self.__userInfo:
            userTmp = {}
            userTmp['username'] = self.__userInfo['username'][0:3]+'****'+self.__userInfo['username'][-4:];
            result['status'] = True;
            result['msg'] = public.getMsg('SSL_GET_SUCCESS');
            result['data'] = userTmp;
        else:
            userTmp = {}
            userTmp['username'] = public.getMsg('SSL_NOT_BTUSER');
            result['status'] = False;
            result['msg'] = public.getMsg('SSL_NOT_BTUSER');
            result['data'] = userTmp;
        return result;

    def GetOrderList(self,get):
        """
        获取SSL订单列表
        @get.focre 开启本地缓存
        @get.siteName 网站名称

        """
        get.focre = 1

        focre  = 0
        if hasattr(get,'force'): focre = int(get.force)
        lcoalTmp = 'data/ssl_order_list.json'

        result = None
        #if os.path.exists(lcoalTmp): result = json.loads(public.readFile(lcoalTmp))

        if not result or  focre > 0:
            lcoalTmp = 'data/ssl_order_list.json'
            if hasattr(get,'siteName'):
                path =  self.setupPath + '/panel/vhost/cert/'+ get.siteName + '/partnerOrderId';
                if os.path.exists(path):
                    self.__PDATA['data']['partnerOrderId'] = public.readFile(path);

            self.__PDATA['data'] = self.De_Code(self.__PDATA['data']);
            data = ""
            try:
                data = public.httpPost(self.__APIURL + '/GetSSLList',self.__PDATA)
                result = json.loads(data)
            except Exception as ex:
                return public.returnMsg(False,'连接服务器失败!<br>' + str(data))

            result['data'] = self.En_Code(result['data']);
            for i in range(len(result['data'])):
                result['data'][i]['endtime'] =   self.add_months(result['data'][i]['createTime'],result['data'][i]['validityPeriod'])

            if result: public.writeFile(lcoalTmp,json.dumps(result))

        return result;


    def add_months(self,dt,months):
        """
        计算日期增加(月)
        """
        import calendar
        dt = datetime.datetime.fromtimestamp(dt/1000);
        month = dt.month - 1 + months
        year = dt.year + month // 12
        month = month % 12 + 1

        day = min(dt.day,calendar.monthrange(year,month)[1])
        return (time.mktime(dt.replace(year=year, month=month, day=day).timetuple()) + 86400) * 1000

    def CheckDvDomain(self,get):
        """
        检测是否本机申请证书
        """
        pid = public.M('domain').where('name=?',(get.domain,)).getField('pid');
        return pid

    def ApplyDVSSL(self,get):
        """
        申请证书
        """
        if not 'orgName' in get: return public.returnMsg(False,'缺少必要参数 orgName')
        if not 'orgPhone' in get: return public.returnMsg(False,'缺少必要参数 orgPhone')
        if not 'orgPostalCode' in get: return public.returnMsg(False,'缺少必要参数 orgPostalCode')
        if not 'orgRegion' in get: return public.returnMsg(False,'缺少必要参数 orgRegion')
        if not 'orgCity' in get: return public.returnMsg(False,'缺少必要参数 orgCity')
        if not 'orgAddress' in get: return public.returnMsg(False,'缺少必要参数 orgAddress')
        if not 'orgDivision' in get: return public.returnMsg(False,'缺少必要参数 orgDivision')

        get.id = public.M('domain').where('name=?',(get.domain,)).getField('pid');
        if hasattr(get,'siteName'):
            get.path = public.M('sites').where('id=?',(get.id,)).getField('path');
        else:
            get.siteName = public.M('sites').where('id=?',(get.id,)).getField('name');

        #当申请二级域名为www时，检测主域名是否绑定到同一网站
        if get.domain[:4] == 'www.':
            if not public.M('domain').where('name=? AND pid=?',(get.domain[4:],get.id)).count():
                msg = '''申请 [{}] 证书需要验证根域名 [{}] <br> 请完成以下操作<br>
                  1、请先添加根域名解析记录，[主机记录：@ 记录类型：A] <a class="btlink" href="https://www.bt.cn/bbs/thread-33099-1-1.html" target="_blank">>>教程</a><br>
                  2、网站设置->域名管理->添加域名[{}]<br>'''.format(get.domain,get.domain[4:],get.domain[4:])
                return public.returnMsg(False,msg)
        #判断是否是Java项目
        if public.M('sites').where('id=?',(get.id,)).getField('project_type') == 'Java':
            get.path='{}/java_node_ssl/'.format(public.M("config").getField("sites_path"))
            runPath=""
        elif public.M('sites').where('id=?',(get.id,)).getField('project_type') == 'Node':
            get.path=public.M('sites').where('id=?',(get.id,)).getField('path')
            runPath=''
        else:
            runPath = self.GetRunPath(get)
        if runPath != False and runPath != '/': get.path +=  runPath;
        authfile = get.path + '/.well-known/pki-validation/fileauth.txt';
        if not self.CheckDomain(get):
            if not os.path.exists(authfile):
                return public.returnMsg(False,'无法写入验证文件: {}'.format(authfile))
            else:
                msg = '''无法正确访问验证文件<br><a class="btlink" href="{c_url}" target="_blank">{c_url}</a> <br><br>
                <p></b>可能的原因：</b></p>
                1、未正确解析，或解析未生效 [请正确解析域名，或等待解析生效后重试]<br>
                2、检查是否有设置301/302重定向 [请暂时关闭重定向相关配置]<br>
                3、检查该网站是否已部署HTTPS并设置强制HTTPS [请暂时关闭强制HTTPS功能]<br>'''.format(c_url = self._check_url)
                return public.returnMsg(False,msg)

        action = 'ApplyDVSSL';
        if hasattr(get,'partnerOrderId'):
            self.__PDATA['data']['partnerOrderId'] = get.partnerOrderId;
            action = 'ReDVSSL';

        self.__PDATA['data']['domain'] = get.domain;
        self.__PDATA['data']['orgPhone'] = get.orgPhone
        self.__PDATA['data']['orgPostalCode'] = get.orgPostalCode
        self.__PDATA['data']['orgRegion'] = get.orgRegion
        self.__PDATA['data']['orgCity'] = get.orgCity
        self.__PDATA['data']['orgAddress'] = get.orgAddress
        self.__PDATA['data']['orgDivision'] = get.orgDivision
        self.__PDATA['data']['orgName'] = get.orgName
        self.__PDATA['data'] = self.De_Code(self.__PDATA['data']);
        result = public.httpPost(self.__APIURL + '/' + action,self.__PDATA)
        try:
            result = json.loads(result);
        except: return result;
        result['data'] = self.En_Code(result['data']);
        if not 'authPath' in result['data']: result['data']['authPath'] = '/.well-known/pki-validation/'
        authfile = get.path + result['data']['authPath'] + result['data']['authKey']

        if 'authValue' in result['data']:
            public.writeFile(authfile,result['data']['authValue']);
        return result;


    def GetDVSSL(self,get):

        """
        申请证书
        """
        get.id = public.M('domain').where('name=?',(get.domain,)).getField('pid');
        if hasattr(get,'siteName'):
            get.path = public.M('sites').where('id=?',(get.id,)).getField('path');
        else:
            get.siteName = public.M('sites').where('id=?',(get.id,)).getField('name');

        #当申请二级域名为www时，检测主域名是否绑定到同一网站
        if get.domain[:4] == 'www.':
            if not public.M('domain').where('name=? AND pid=?',(get.domain[4:],get.id)).count():
                return public.returnMsg(False,"申请[%s]证书需要验证[%s]请将[%s]绑定并解析到站点!" % (get.domain,get.domain[4:],get.domain[4:]))

        #result = self.check_ssl_caa([get.domain],[])
        #if result:  return result

        runPath = self.GetRunPath(get);

        if runPath != False and runPath != '/': get.path +=  runPath;
        authfile = get.path + '/.well-known/pki-validation/fileauth.txt';
        if not self.CheckDomain(get):
            if not os.path.exists(authfile):
                return public.returnMsg(False,'无法写入验证文件: {}'.format(authfile))
            else:
                msg = '''无法正确访问验证文件<br><a class="btlink" href="{c_url}" target="_blank">{c_url}</a> <br><br>
                <p></b>可能的原因：</b></p>
                1、未正确解析，或解析未生效 [请正确解析域名，或等待解析生效后重试]<br>
                2、检查是否有设置301/302重定向 [请暂时关闭重定向相关配置]<br>
                3、检查该网站是否已部署HTTPS并设置强制HTTPS [请暂时关闭强制HTTPS功能]<br>'''.format(c_url = self._check_url)
                return public.returnMsg(False,msg)

        action = 'GetDVSSL';
        if hasattr(get,'partnerOrderId'):
            self.__PDATA['data']['partnerOrderId'] = get.partnerOrderId;
            action = 'ReDVSSL';

        self.__PDATA['data']['domain'] = get.domain;
        self.__PDATA['data'] = self.De_Code(self.__PDATA['data']);
        result = public.httpPost(self.__APIURL + '/' + action,self.__PDATA)
        try:
            result = json.loads(result);
        except: return result;
        result['data'] = self.En_Code(result['data']);

        if 'authValue' in result['data']:
            public.writeFile(authfile,result['data']['authValue']);
        return result;

    #获取运行目录
    def GetRunPath(self,get):
        if hasattr(get,'siteName'):
            get.id = public.M('sites').where('name=?',(get.siteName,)).getField('id');
        else:
            get.id = public.M('sites').where('path=?',(get.path,)).getField('id');
        if not get.id: return False;
        import panelSite
        result = panelSite.panelSite().GetSiteRunPath(get);
        if 'runPath' in result:
            return result['runPath'];
        return '/'

    #检查域名是否解析
    def CheckDomain(self,get):
        try:
            #创建目录
            spath = get.path + '/.well-known/pki-validation'
            if not os.path.exists(spath): os.makedirs(spath)

            #生成并写入检测内容
            epass = public.GetRandomString(32)
            public.writeFile(spath + '/fileauth.txt',epass)

            #检测目标域名访问结果
            if get.domain[:4] == 'www.':   #申请二级域名为www时检测主域名
                get.domain = get.domain[4:]

            import http_requests
            self._check_url = 'http://' + get.domain + '/.well-known/pki-validation/fileauth.txt'
            result = http_requests.get(self._check_url,s_type='curl').text
            self.__test = result
            if result == epass: return True
            return False
        except:
            print(public.get_error_info())
            return False

    #确认域名
    def Completed(self,get):
        self.__PDATA['data']['partnerOrderId'] = get.partnerOrderId
        self.__PDATA['data'] = self.De_Code(self.__PDATA['data'])
        if hasattr(get,'siteName'):
            get.path = public.M('sites').where('name=?',(get.siteName,)).getField('path')
            if public.M('sites').where('name=?',(get.siteName)).getField('project_type') == 'Java':
                runPath = '{}/java_node_ssl'.format(public.M("config").getField("sites_path"))
            else:
                runPath = self.GetRunPath(get)
            if runPath != False and runPath != '/': get.path +=  runPath;
            sslInfo = json.loads(public.httpPost(self.__APIURL + '/SyncOrder',self.__PDATA))

            sslInfo['data'] = self.En_Code(sslInfo['data'])
            try:
                public.writeFile(get.path + '/.well-known/pki-validation/' + sslInfo['data']['authKey'],sslInfo['data']['authValue']);
            except:
                return public.returnMsg(False,'SSL_CHECK_WRITE_ERR')
        public.httpPost(self.__APIURL + '/Completed',self.__PDATA)

        n = 0
        while True:
            if n > 5: break
            try:
                time.sleep(5)
                rRet = json.loads(public.httpPost(self.__APIURL + '/SyncOrder',self.__PDATA));

                rRet['data'] = self.En_Code(rRet['data']);
                if rRet['data']['stateCode'] == 'COMPLETED': break
                n += 1
            except : pass

        return rRet;

    #同步指定订单
    def SyncOrder(self,get):
        self.__PDATA['data']['partnerOrderId'] = get.partnerOrderId;
        self.__PDATA['data'] = self.De_Code(self.__PDATA['data']);
        result = json.loads(public.httpPost(self.__APIURL + '/SyncOrder',self.__PDATA));
        result['data'] = self.En_Code(result['data']);
        return result;

    #获取证书
    def GetSSLInfo(self,get):
        self.__PDATA['data']['partnerOrderId'] = get.partnerOrderId;
        self.__PDATA['data'] = self.De_Code(self.__PDATA['data']);

        serverType = public.get_webserver();
        if serverType == 'iis':
            result = public.httpPost(self.__APIURL + '/GetPKCS12',self.__PDATA)
        else:
            result = public.httpPost(self.__APIURL + '/GetSSLInfo',self.__PDATA)
        result = json.loads(result)
        result['data'] = self.En_Code(result['data']);

        #写配置到站点
        if hasattr(get,'siteName'):
            try:
                if result['status']:
                    siteName = get.siteName;
                    path = self.setupPath + '/panel/vhost/cert/'+ siteName;
                    if not os.path.exists(path): os.makedirs(path)
                    pidpath = path + "/partnerOrderId";
                    if serverType == 'iis':
                        pwdpath = path + "/password"
                        pfxpath = path + "/fullchain.pfx"
                        import base64
                        public.writeFile(pwdpath,result['data']['password'])
                        #写入pfx证书
                        public.writeFile2(pfxpath,base64.b64decode(result['data']['fileData']),'wb+')

                        #处理一个网站多个域名证书
                        get.certPath = pfxpath
                        get.password = result['data']['password']
                        cert_data = self.GetCertName(get)
                        if cert_data:
                            domain = cert_data['dns'][0]
                            if domain.find("*") < 0:
                                if len(cert_data['dns']) > 1 : domain = cert_data['dns'][len(cert_data['dns']) - 1]

                                pwdpath = path + "/" + domain
                                pfxpath = path + "/" + domain + ".pfx"

                                public.writeFile(pwdpath,result['data']['password'])
                                public.writeFile2(pfxpath,base64.b64decode(result['data']['fileData']),'wb+')

                    elif serverType == 'apache':
                        path = os.getenv("BT_SETUP") + '/apache/conf/ssl/' + siteName
                        if not os.path.exists(path): os.makedirs(path)

                        csrpath = path + "/fullchain.pem";
                        keypath = path + "/privkey.pem";

                        public.writeFile(keypath,result['data']['privateKey']);
                        public.writeFile(csrpath,result['data']['cert'] + result['data']['certCa']);

                    else:
                        path = os.getenv("BT_SETUP") + '/nginx/conf/ssl/' + siteName
                        if not os.path.exists(path): os.makedirs(path)

                        csrpath = path + "/fullchain.pem";
                        keypath = path + "/privkey.pem";

                        public.writeFile(keypath,result['data']['privateKey'].strip());
                        public.writeFile(csrpath,result['data']['cert'] + result['data']['certCa'].strip());

                    public.writeFile(pidpath,get.partnerOrderId);
                    import panelSite
                    result = panelSite.panelSite().SetSSLConf(get);
                    return result;
                else:
                    return public.returnMsg(False,result['msg']);
            except Exception as ex:
                return public.returnMsg(False,'SET_ERROR,' + str(ex));
        return result

    #部署证书夹证书
    def SetCertToSite(self,get):
        try:
            import shutil
            siteName = get.siteName
            path = self.setupPath + '/panel/vhost/cert/'+ siteName
            if not os.path.exists(path): os.makedirs(path)

            d_path = self.setupPath + '/panel/vhost/ssl/' + get.certName
            d_path = d_path.replace("*.","")

            serverType = public.get_webserver()
            if serverType == 'iis':
                shutil.copyfile( d_path + "/fullchain.pfx",path + '/fullchain.pfx')

                if 'password' in get and get['password']:
                    public.writeFile(d_path + '/password',get.password)
                if os.path.exists(d_path + '/password'): shutil.copyfile(d_path + '/password',path + '/password')
            else:
                npath = os.getenv("BT_SETUP") + '/' + serverType + '/conf/ssl/' + siteName
                if not os.path.exists(npath): os.makedirs(npath)
                shutil.copyfile( d_path + "/fullchain.pem",npath + '/fullchain.pem')
                shutil.copyfile( d_path + "/privkey.pem",npath + '/privkey.pem')

            if os.path.exists(path + '/partnerOrderId'): os.remove(path + '/partnerOrderId')
            if os.path.exists(d_path + '/partnerOrderId'): shutil.copyfile(d_path + '/partnerOrderId',path + '/partnerOrderId')


            import panelSite
            ret = panelSite.panelSite().SetSSLConf(get)
            public.print_log(ret)
            if ret['status']:
                public.serviceReload()
                return public.returnMsg(True,'SET_SUCCESS')
            return ret
        except Exception as ex:
            return public.returnMsg(False,'SET_ERROR,' + str(ex))

    #获取证书列表
    def GetCertList(self,get):
        try:
            vpath = self.setupPath + '/panel/vhost/ssl'
            if not os.path.exists(vpath): os.makedirs(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 data
        except:
            return []

    #删除证书
    def RemoveCert(self,get):
        try:
            vpath = self.setupPath + '/panel/vhost/ssl/' + get.certName
            vpath = vpath.replace("*.","")
            if not os.path.exists(vpath): return public.returnMsg(False,'证书不存在!')
            import shutil
            shutil.rmtree(vpath)
            return public.returnMsg(True,'证书已删除!')
        except:
            return public.returnMsg(False,'删除失败!')

    #保存证书
    def SaveCert(self,get):
        try:
            certInfo = self.GetCertName(get)
            if not certInfo: return public.returnMsg(False,'证书解析失败!');
            vpath = self.setupPath + '/panel/vhost/ssl/' + certInfo['subject'];
            if not os.path.exists(vpath):  os.makedirs(vpath);

            vpath = vpath.replace("*.","")
            serverType = public.get_webserver();
            if serverType == 'iis':
                import shutil
                if get.password: public.writeFile(vpath + '/password',get.password)
                shutil.copyfile(get.certPath,vpath + '/fullchain.pfx')
                if hasattr(get,'local'):
                    local_path = self.setupPath + '/panel/vhost/cert/localhost'
                    if not os.path.exists(local_path):  os.makedirs(local_path);

                    shutil.copyfile(get.certPath,local_path + '/fullchain.pfx')
            else:
                public.writeFile(vpath + '/privkey.pem',public.readFile(get.keyPath));
                public.writeFile(vpath + '/fullchain.pem',public.readFile(get.certPath));
            public.writeFile(vpath + '/info.json',json.dumps(certInfo));

            if os.path.exists(vpath + '/partnerOrderId'): os.remove(vpath + '/partnerOrderId')
            if get.partnerOrderId: public.writeFile(vpath + '/partnerOrderId',get.partnerOrderId)

            return public.returnMsg(True,'证书保存成功!');
        except:
            return public.returnMsg(False,'证书保存失败!');

    #拆分根证书
    def split_ca_data(self,cert):
        datas = cert.split('-----END CERTIFICATE-----')
        return {"cert":datas[0] + "-----END CERTIFICATE-----\n","ca_data":datas[1] + '-----END CERTIFICATE-----\n' }

    #获取证书哈希
    def get_cert_data(self,cret_data):

        from OpenSSL import crypto

        x509 = crypto.load_certificate(crypto.FILETYPE_PEM, cret_data)

        buffs = x509.digest('sha1')
        hash =  bytes.decode(buffs).replace(':','')
        data = {}
        data['hash'] = hash
        data['timeout'] = self.strfToTime(bytes.decode(x509.get_notAfter())[:-1])
        data['unix_timeout'] = self.get_unixtime(data['timeout'],"%Y-%m-%d")

        return data

    def get_unixtime(self,data,format = "%Y-%m-%d %H:%M:%S"):

        import time
        timeArray = time.strptime(data,format )

        timeStamp = int(time.mktime(timeArray))
        return timeStamp

    #获取证书名称
    def GetCertName(self,get):
        try:
            try:
                from OpenSSL import crypto
                from urllib3.contrib import pyopenssl as reqs
            except :
                os.system(public.get_run_pip('[PIP] install crypto'))
                os.system(public.get_run_pip('[PIP] install pyopenssl'))

                from OpenSSL import crypto
                from urllib3.contrib import pyopenssl as reqs

            certPath = get.certPath
            if os.path.exists(certPath):
                data = {}

                f = open(certPath,'rb')
                pfx_buffer = f.read()
                cret_data = pfx_buffer
                if certPath[-4:] == '.pfx':
                    if hasattr(get, 'password'):
                        password = get.password
                        if password:
                            try:
                                p12 = crypto.load_pkcs12(pfx_buffer,get.password)
                            except :
                                p12 = crypto.load_pkcs12(pfx_buffer)
                        else:
                            p12 = crypto.load_pkcs12(pfx_buffer)
                    else:
                        p12 = crypto.load_pkcs12(pfx_buffer)
                    x509 = p12.get_certificate()
                    data['type'] = 'pfx'
                else:
                    #验证域名证书和跟证书顺序
                    try:
                        cert_data = self.split_ca_data(public.readFile(certPath))
                        cert_d1 = self.get_cert_data(cert_data['cert'])
                        cert_d2 = self.get_cert_data(cert_data['ca_data'])
                        if cert_d1['unix_timeout'] > cert_d2['unix_timeout']:
                            public.writeFile(certPath,cert_data['ca_data'] + cert_data['cert'])
                            f = open(certPath,'rb')
                            pfx_buffer = f.read()
                    except :pass

                    x509 = crypto.load_certificate(crypto.FILETYPE_PEM, pfx_buffer)
                    data['type'] = 'pem'
                buffs = x509.digest('sha1')
                data['hash'] =  bytes.decode(buffs).replace(':','')
                data['number'] = x509.get_serial_number()
                issuser = x509.get_issuer()

                is_key = 'O'
                if len(issuser.get_components()) == 1: is_key = 'CN'
                for item in issuser.get_components():
                    if bytes.decode(item[0]) == is_key:
                        data['issuer'] = bytes.decode(item[1])
                        break

                data['notAfter'] = self.strfToTime(bytes.decode( x509.get_notAfter())[:-1])
                data['notBefore'] = self.strfToTime(bytes.decode(x509.get_notBefore())[:-1])
                data['version'] = x509.get_version()
                data['timeout'] = x509.has_expired()

                data['endtime'] = self.get_ssl_endtime(data['notAfter'])
                x509name = x509.get_subject()
                data['subject'] = x509name.commonName.replace('*','_')
                data['dns'] = []
                alts = reqs.get_subj_alt_name(x509)
                for x in alts:
                    data['dns'].append(x[1])

            data['endtime'] = int(int(time.mktime(time.strptime(data['notAfter'], "%Y-%m-%d")) - time.time()) / 86400)
            return data;
        except:
            #print(public.get_error_info())
            return None

    def get_ssl_endtime(self,endtime):
        endtime = time.mktime(time.strptime(endtime, "%Y-%m-%d"))
        return int((endtime - time.time())/86400);


    #转换时间
    def strfToTime(self,sdate):
        import time
        return time.strftime('%Y-%m-%d',time.strptime(sdate,'%Y%m%d%H%M%S'))

    #获取产品列表
    def GetSSLProduct(self,get):
        self.__PDATA['data'] = self.De_Code(self.__PDATA['data']);
        result = json.loads(public.httpPost(self.__APIURL + '/GetSSLProduct',self.__PDATA));
        result['data'] = self.En_Code(result['data'])
        return result

    #加密数据
    def De_Code(self,data):
        if sys.version_info[0] == 2:
            import urllib
            pdata = urllib.urlencode(data)
            return binascii.hexlify(pdata)
        else:
            import urllib.parse
            pdata = urllib.parse.urlencode(data)
            if type(pdata) == str: pdata = pdata.encode('utf-8')
            res = binascii.hexlify(pdata).decode()

            return res

    #解密数据
    def En_Code(self,data):
        if sys.version_info[0] == 2:
            import urllib
            result = urllib.unquote(binascii.unhexlify(data))
        else:
            import urllib.parse
            if type(data) == str: data = data.encode('utf-8')
            tmp = binascii.unhexlify(data)
            if type(tmp) != str: tmp = tmp.decode('utf-8')
            result = urllib.parse.unquote(tmp)

        if type(result) != str: result = result.decode('utf-8')
        return json.loads(result)

    # 手动一键续签
    def renew_lets_ssl(self, get):
        if not os.path.exists('vhost/crontab.json'):
            return public.returnMsg(False,'当前没有可以续订的证书!')

        old_list = json.loads(public.ReadFile("vhost/crontab.json"))
        cron_list = old_list
        if hasattr(get, 'siteName'):
            if not get.siteName in old_list:
                return public.returnMsg(False,'当前网站没有可以续订的证书.')
            cron_list = {}
            cron_list[get.siteName] = old_list[get.siteName]

        import panelLets
        lets = panelLets.panelLets()

        result = {}
        result['status'] = True
        result['sucess_list']  = []
        result['err_list'] = []
        for siteName in cron_list:
            data = cron_list[siteName]

            ret = lets.renew_lest_cert(data)
            if ret['status']:
                result['sucess_list'].append(siteName)
            else:
                result['err_list'].append({"siteName":siteName,"msg":ret['msg']})
        return result

    #获取产品列表
    def get_product_list(self,get):
        p_type = 'dv'
        if 'p_type' in get: p_type = get.p_type
        result = self.request('get_product_list?p_type={}'.format(p_type))

        return result

    def get_product_list_v2(self,get):
        p_type = 'dv'
        if 'p_type' in get: p_type = get.p_type

        result = self.request('get_product_list_v2?p_type={}'.format(p_type))
        return result

    #获取商业证书订单列表
    def get_order_list(self,get):
        result = self.request('get_order_list')
        return result

    #获指定商业证书订单
    def get_order_find(self,get):
        self.__PDATA['data']['oid'] = get.oid
        result = self.request('get_order_find')
        return result

    #下载证书
    def download_cert(self,get):
        self.__PDATA['data']['oid'] = get.oid
        result = self.request('download_cert')
        return result


    def set_cert(self,get):
        """
        @name 部署指定商业证书
        @param siteName 网站名称
        """
        siteName = get.siteName
        certInfo = self.get_order_find(get)

        path = self.setupPath + '/panel/vhost/cert/' + siteName
        if not os.path.exists(path): os.makedirs(path)
        pidpath = path+"/certOrderId"

        serverType = public.get_webserver()
        if serverType == 'iis':
            pwdpath = path + "/password"
            pfxpath = path + "/fullchain.pfx"
            import base64
            password = certInfo['pkcsPass']
            public.writeFile(pwdpath,password)
            #写入pfx证书
            public.writeFile2(pfxpath,base64.b64decode(certInfo['pkcs12']),'wb+')

            #处理一个网站多个域名证书
            get.certPath = pfxpath
            get.password = password
            cert_data = self.GetCertName(get)
            if cert_data:
                domain = cert_data['dns'][0]
                if domain.find("*") < 0:
                    if len(cert_data['dns']) > 1 : domain = cert_data['dns'][len(cert_data['dns']) - 1]

                    pwdpath = path + "/" + domain
                    pfxpath = path + "/" + domain + ".pfx"

                    public.writeFile(pwdpath,password)
                    public.writeFile2(pfxpath,base64.b64decode(certInfo['pkcs12']),'wb+')
                    public.writeFile(pidpath,get.oid)

        elif serverType == 'apache':
            path = os.getenv("BT_SETUP") + '/apache/conf/ssl/' + siteName
            if not os.path.exists(path): os.makedirs(path)

            csrpath = path + "/fullchain.pem"
            keypath = path + "/privkey.pem"

            public.writeFile(keypath,certInfo['privateKey'])
            public.writeFile(csrpath,certInfo['certificate']+"\n"+certInfo['caCertificate'])
            public.writeFile(pidpath,get.oid)

        else:
            path = os.getenv("BT_SETUP") + '/nginx/conf/ssl/' + siteName
            if not os.path.exists(path): os.makedirs(path)

            csrpath = path + "/fullchain.pem"
            keypath = path + "/privkey.pem"

            public.writeFile(keypath,certInfo['privateKey'])
            public.writeFile(csrpath,certInfo['certificate'] + "\n" + certInfo['caCertificate'])
            public.writeFile(pidpath,get.oid)

        other_file = path + '/partnerOrderId'
        if os.path.exists(other_file): os.remove(other_file)
        other_file = path + '/README'
        if os.path.exists(other_file): os.remove(other_file)

        import panelSite
        ret = panelSite.panelSite().SetSSLConf(get)
        if not ret['status']: return ret

        public.serviceReload(siteName)
        return public.returnMsg(True,'SET_SUCCESS')

    def check_ssl_caa(self,domains,clist = ['sectigo.com','digicert.com','comodoca.com']):
        '''
            @name 检查CAA记录是否正确
            @param domains 域名列表
            @param clist 正确的记录值关键词
            @return bool
        '''
        try:
            data = {}
            for domain in domains:
                root,zone = public.get_root_domain(domain)
                for d in [domain,root,'_acme-challenge.{}'.format(root),'_acme-challenge.{}'.format(domain)]:
                    ret = public.query_dns(d,'CAA')
                    if not ret: continue

                    slist = []
                    for val in ret:
                        if val['value'] in clist:
                            return False

                        slist.append(val)

                    if len(slist) > 0:
                        data[d] = slist
            if data:
                result = {}
                result['status'] = False
                result['msg'] = 'error:域名的DNS解析中存在CAA记录，请删除后重新申请'
                result['data'] = json.dumps(data)
                result['caa_list'] = data
                return result
        except : pass
        return False

    #生成商业证书支付订单
    def apply_order_pay(self,args):

        pdata = json.loads(args.pdata)
        result = self.check_ssl_caa(pdata['domains'])
        if result:  return result

        self.__PDATA['data'] = pdata
        result = self.request('apply_cert_order')
        return result

    #检查商业证书支付状态
    def get_pay_status(self,args):
        self.__PDATA['data']['oid'] = args.oid
        result = self.request('get_pay_status')
        return result

    #提交商业证书订单到CA
    def apply_order(self,args):
        self.__PDATA['data']['oid'] = args.oid
        result = self.request('apply_cert')
        if result['status'] == True:
            self.__PDATA['data'] = {}
            result['verify_info'] = self.get_verify_info(args)
        return result


    #获取商业证书验证信息
    def get_verify_info(self,args):
        self.__PDATA['data']['oid'] = args.oid
        verify_info = self.request('get_verify_info')

        is_file_verify = 'fileName' in verify_info
        verify_info['paths'] = []
        verify_info['hosts'] = []

        for domain in verify_info['domains']:
            if is_file_verify:
                siteRunPath = self.get_domain_run_path(domain)
                if not siteRunPath:
                    if domain[:4] == 'www.': domain = domain[:4]
                    verify_info['paths'].append(verify_info['path'].replace('example.com',domain))
                    continue
                verify_path = siteRunPath + '/.well-known/pki-validation'
                if not os.path.exists(verify_path):
                    os.makedirs(verify_path)
                verify_file = verify_path + '/' + verify_info['fileName']
                if os.path.exists(verify_file): continue
                public.writeFile(verify_file,verify_info['content'])
            else:
                if domain[:4] == 'www.': domain = domain[:4]
                verify_info['hosts'].append(verify_info['host'] + '.' + domain)

                if 'auth_to' in args:
                    root,zone = public.get_root_domain(domain)
                    self.create_dns_record(args['auth_to'],verify_info['host'] + '.' + root,verify_info['value'])
        return verify_info

    #处理验证信息
    def set_verify_info(self,args):
        verify_info = self.get_verify_info(args)
        is_file_verify = 'fileName' in verify_info
        verify_info['paths'] = []
        verify_info['hosts'] = []
        for domain in verify_info['domains']:
            if domain[:2] == '*.': domain = domain[2:]
            if is_file_verify:
                siteRunPath = self.get_domain_run_path(domain)
                if not siteRunPath:
                    if domain[:4] == 'www.': domain = domain[4:]
                    verify_info['paths'].append(verify_info['path'].replace('example.com',domain))
                    continue
                verify_path = siteRunPath + '/.well-known/pki-validation'
                if not os.path.exists(verify_path):
                    os.makedirs(verify_path)
                verify_file = verify_path + '/' + verify_info['fileName']
                if os.path.exists(verify_file): continue
                public.writeFile(verify_file,verify_info['content'])
            else:
                if domain[:4] == 'www.': domain = domain[4:]
                verify_info['hosts'].append(verify_info['host'] + '.' + domain)

                if 'auth_to' in args:
                    root,zone = public.get_root_domain(domain)
                    self.create_dns_record(args['auth_to'],verify_info['host'] + '.' + root,verify_info['value'])
        return verify_info


    #获取指定域名的PATH
    def get_domain_run_path(self,domain):
        pid = public.M('domain').where('name=?',(domain,)).getField('pid')
        if not pid: return False
        return self.get_site_run_path(pid)


    def get_site_run_path(self,pid):
        '''
        @name 获取网站运行目录
        @author hwliang<2020-08-05>
        @param pid(int) 网站标识
        @return string
        '''
        siteInfo = public.M('sites').where('id=?',(pid,)).find()
        siteName = siteInfo['name']
        sitePath = siteInfo['path']
        webserver_type = public.get_webserver()
        setupPath = self.setupPath

        import panelSite
        info = panelSite.panelSite().get_site_info(siteName)
        if info:  return info['path']
        return False

    #验证URL是否匹配
    def check_url_txt(self,args,timeout = 6):
        url = args.url
        content = args.content

        import http_requests
        res = http_requests.get(url,s_type='curl',timeout=timeout)
        result = res.text
        if not result: return 0

        if result.find('11001') != -1 or result.find('curl: (6)') != -1: return -1
        if result.find('curl: (7)') != -1 or res.status_code in [403,401]: return -5
        if result.find('Not Found') != -1 or result.find('not found') != -1 or res.status_code in [404]:return -2
        if result.find('timed out') != -1:return -3
        if result.find('301') != -1 or result.find('302') != -1 or result.find('Redirecting...') != -1 or res.status_code in [301,302]:return -4
        if result == content:return 1
        return 0


    #获取商业证书验证结果
    def get_verify_result(self,args):
        self.__PDATA['data']['oid'] = args.oid
        verify_info = self.request('get_verify_result')
        if verify_info['status'] in ['COMPLETE',False]: return verify_info
        is_file_verify = 'CNAME_CSR_HASH' != verify_info['data']['dcvList'][0]['dcvMethod']
        verify_info['paths'] = []
        verify_info['hosts'] = []
        if verify_info['data']['application']['status'] == 'ongoing':
            return public.returnMsg(False,'订单出现问题，CA正在人工验证，若24小时内依然出现此提示，请联系宝塔')
        for dinfo in verify_info['data']['dcvList']:
            is_https = dinfo['dcvMethod'] == 'HTTPS_CSR_HASH'
            if is_https:
                is_https = 's'
            else:
                is_https = ''
            domain = dinfo['domainName']
            if domain[:2] == '*.': domain = domain[2:]
            dinfo['domainName'] = domain
            if is_file_verify:
                if public.M('sites').where('id=?',(public.M('domain').where('name=?',(dinfo['domainName'])).getField('pid'),)).getField('project_type') == 'Java':
                    siteRunPath='{}/java_node_ssl'.format(public.M("config").getField("sites_path"))
                else:
                    siteRunPath = self.get_domain_run_path(domain)

                #if domain[:4] == 'www.': domain = domain[4:]

                status = 0
                url = 'http'+ is_https +'://'+ domain +'/.well-known/pki-validation/' + verify_info['data']['DCVfileName']
                get = public.dict_obj()
                get.url = url
                get.content = verify_info['data']['DCVfileContent']
                status = self.check_url_txt(get)

                verify_info['paths'].append({'url':url,'status':status})
                if not siteRunPath: continue

                verify_path = siteRunPath + '/.well-known/pki-validation'
                if not os.path.exists(verify_path):
                    os.makedirs(verify_path)
                verify_file = verify_path + '/' + verify_info['data']['DCVfileName']
                if os.path.exists(verify_file): continue
                public.writeFile(verify_file,verify_info['data']['DCVfileContent'])
            else:
                #if domain[:4] == 'www.': domain = domain[4:]
                domain,subb = public.get_root_domain(domain)
                dinfo['domainName'] = domain
                verify_info['hosts'].append(verify_info['data']['DCVdnsHost'] + '.' + domain)

        return verify_info

    #更换验证方式
    def again_verify(self,args):
        self.__PDATA['data']['oid'] = args.oid
        self.__PDATA['data']['dcvMethod'] = args.dcvMethod
        result = self.request('again_verify')
        return result

    #取消订单
    def cancel_cert_order(self,args):
        self.__PDATA['data']['oid'] = args.oid
        result = self.request('cancel_cert_order')
        return result

    #发送请求
    def request(self,dname):
        self.__PDATA['data'] = json.dumps(self.__PDATA['data'])
        try:
            result = public.httpPost(self.__APIURL2 + '/' + dname,self.__PDATA)
            result = json.loads(result)
        except:
            pass
        return result

    #生成商业证书支付订单
    def apply_cert_order_pay(self,args):
        pdata = json.loads(args.pdata)
        self.__PDATA['data'] = pdata
        result = self.request('apply_cert_order_pay')
        return result

    def apply_cert_install_pay(self,args):
        pdata = json.loads(args.pdata)
        self.__PDATA['data'] = pdata
        result = self.request('apply_cert_install_pay')
        return result


    #获取证书管理员信息
    def get_cert_admin(self,get):
        result = self.request('get_cert_admin')
        return result

    #完善资料CA(先支付接口)
    def apply_order_ca(self,args):
        pdata = json.loads(args.pdata)
        result = self.check_ssl_caa(pdata['domains'])
        if result:  return result

        self.__PDATA['data'] = pdata
        result = self.request('apply_cert_ca')
        if result['status'] == True:
            self.__PDATA['data'] = {}
            args['oid'] = pdata['oid']
            if 'auth_to' in pdata:
                args['auth_to'] = pdata['auth_to']
            result['verify_info'] = self.get_verify_info(args)
        return result

    #续签订单
    def renew_cert_order(self,args):
        pdata = json.loads(args.pdata)
        self.__PDATA['data'] = pdata

        result = self.request('renew_cert_order')
        if result['status'] == True:
            self.__PDATA['data'] = {}
            args['oid'] = result['oid']
            result['verify_info'] = self.get_verify_info(args)
        return result

    #******************************宝塔SSL支付接口*******************
    #检测是否开启https
    def CheckForceHTTPS(self,siteName):
        import panelSite
        site_obj = panelSite.panelSite()
        if site_obj.IsToHttps(siteName):
            return False
        return True

    #获取支付二维码
    def get_dv_paycode(self,args):
        self.__PDATA['data'] = self.De_Code(self.__PDATA['data']);
        result = public.httpPost(self.__APIURL + '/get_dv_paycode',self.__PDATA)
        try:
            result = json.loads(result);
        except: return result;
        return result;

    #获取支付状态
    def get_dv_paystatus(self,args):
        self.__PDATA['data']['ssl_id'] = args['ssl_id']
        self.__PDATA['data'] = self.De_Code(self.__PDATA['data']);
        result = public.httpPost(self.__APIURL + '/get_dv_paystatus',self.__PDATA)
        try:
            result = json.loads(result);
        except: return result;

        return result;

    #提交证书
    def apply_order_byca(self,get):

        get.id = public.M('domain').where('name=?',(get.domain,)).getField('pid')

        if hasattr(get,'siteName'):
            get.path = public.M('sites').where('id=?',(get.id,)).getField('path')
        else:
            get.siteName = public.M('sites').where('id=?',(get.id,)).getField('name')

        #当申请二级域名为www时，检测主域名是否绑定到同一网站
        if get.domain[:4] == 'www.':
            if not public.M('domain').where('name=? AND pid=?',(get.domain[4:],get.id)).count():
                msg = '''申请 [{}] 证书需要验证根域名 [{}] ,请完成以下操作 <br>
                  1、请先添加根域名解析记录，[主机记录：@ 记录类型：A] <a class="btlink" href="https://www.bt.cn/bbs/thread-66447-1-1.html" target="_blank">>>教程</a><br>
                  2、网站设置->域名管理->添加域名[{}]<br>'''.format(get.domain,get.domain[4:],get.domain[4:])
                return public.returnMsg(False,msg)

        #检测是否开启强制HTTPS
        if not self.CheckForceHTTPS(get.siteName):
            return public.returnMsg(False,'当前网站已开启【强制HTTPS】,请先关闭此功能再申请SSL证书!')

        #获取真实网站运行目录
        runPath = self.GetRunPath(get)
        if runPath != False and runPath != '/': get.path +=  runPath

        #提前模拟测试验证文件值是否正确
        authfile = get.path + '/.well-known/pki-validation/fileauth.txt'
        if not self.CheckDomain(get):
            if not os.path.exists(authfile):
                return public.returnMsg(False,'无法写入验证文件: {}'.format(authfile))
            else:
                msg = '''无法正确访问验证文件<br><a class="btlink" href="{c_url}" target="_blank">{c_url}</a> <br><br>
                <p></b>可能的原因：</b></p>
                1、未正确解析，或解析未生效 [请正确解析域名，或等待解析生效后重试]<br>
                2、检查是否有设置301/302重定向 [请暂时关闭重定向相关配置]<br>
                3、检查该网站是否设置强制HTTPS [请暂时关闭强制HTTPS功能]<br>'''.format(c_url = self._check_url)
                return public.returnMsg(False,msg)

        action = 'apply_order_byca'

        self.__PDATA['data']['ssl_id'] = get.ssl_id
        self.__PDATA['data']['domain'] = get.domain

        self.__PDATA['data'] = self.De_Code(self.__PDATA['data'])

        result = public.httpPost(self.__APIURL + '/' + action,self.__PDATA)
        try:
            result = json.loads(result)
        except: return result
        result['data'] = self.En_Code(result['data'])

        try:
            if 'authValue' in result['data'].keys():
                public.writeFile(authfile,result['data']['authValue'])
        except:
            try:
                public.writeFile(authfile,result['data']['authValue'])
            except:
                return result

        return result

    # 解析DNSAPI信息
    def get_dnsapi(self, auth_to):
        tmp = auth_to.split('|')
        dns_name = tmp[0]
        key = "None"
        secret = "None"
        if len(tmp) < 3:
            dnsapi_config = json.loads(public.readFile('{}/config/dns_api.json'.format(public.get_panel_path())))
            for dc in dnsapi_config:
                if dc['name'] != dns_name:
                    continue
                if not dc['data']:
                    continue
                key = dc['data'][0]['value']
                secret = dc['data'][1]['value']
        else:
            key = tmp[1]
            secret = tmp[2]
        return dns_name, key, secret

    #获取dnsapi对象
    def get_dns_class(self,auth_to):
        try:
            import panelDnsapi
            dns_name, key, secret = self.get_dnsapi(auth_to)
            dns_class = getattr(panelDnsapi, dns_name)(key, secret)
            dns_class._type = 1
            return dns_class
        except :
            return None

    # 解析域名
    def create_dns_record(self, auth_to, domain, dns_value):
        # 如果为手动解析
        if auth_to == 'dns':
            return None
        dns_class = self.get_dns_class(auth_to)
        if not dns_class:
            return public.returnMsg(False,"操作失败，请检查密钥是否正确.")

        #申请钱删除caa记录
        root,zone = public.get_root_domain(domain)
        try:
            dns_class.remove_record(public.de_punycode(root),'@','CAA')
        except :pass
        try:
            dns_class.create_dns_record(public.de_punycode(domain), dns_value)
            return public.returnMsg(True,'添加成功')
        except :
            return public.returnMsg(False,public.get_error_info())


    def check_ssl_method(self,get):
        """
        @name 检测ssl验证方式
        @domain string 域名
        """

        domain = get.domain
        if public.M('sites').where('id=?',(public.M('domain').where('name=?',(domain)).getField('pid'),)).getField('project_type') == 'Java':
            siteRunPath='{}/java_node_ssl'.format(public.M("config").getField("sites_path"))
        else:
            siteRunPath = self.get_domain_run_path(domain)

        if not siteRunPath:
            return public.returnMsg(False,'获取网站路径失败，请检查网站是否存在.')

        verify_path = siteRunPath + '/.well-known/pki-validation'
        if not os.path.exists(verify_path):  os.makedirs(verify_path)

        #生成临时文件
        check_val =  public.GetRandomString(16)
        verify_file = '{}/{}.txt'.format(verify_path,check_val)
        public.writeFile(verify_file,check_val)
        if not os.path.exists(verify_file):
            return public.returnMsg(False,'创建验证文件失败，请检测是否写入被拦截.')

        res = {}
        msg = [     '域名【{}】无法正确访问验证文件'.format(domain),
                    '可能的原因',
                    '1、未正确解析，或解析未生效 [请正确解析域名，或等待解析生效后重试]',
                    '2、检查是否有设置301/302重定向 [请暂时关闭重定向相关配置]',
                    '3、检查该网站是否已经开启反向代理 [请暂时关闭反向代理配置]'
                ]

        res['HTTP_CSR_HASH'] = msg
        res['HTTPS_CSR_HASH'] = msg

        #检测HTTP/https访问
        args = public.dict_obj()
        for stype in ['http','https']:
            args.url = '{}://{}/.well-known/pki-validation/{}.txt'.format(stype,domain,check_val)
            args.content = check_val
            if self.check_url_txt(args,2) == 1:
                res['{}_CSR_HASH'.format(stype).upper()] = 1

        #检测caa记录
        result =  self.check_ssl_caa([domain])
        if not result:
            res['CNAME_CSR_HASH'] = 1
        else:
            res['CNAME_CSR_HASH'] = json.loads(result['data'])

        if os.path.exists(verify_file):
            os.remove(verify_file)
        return res