import os, sys, re, json, shutil, psutil, time
import uuid
from datetime import datetime
from hashlib import md5

from sslModel.base import sslBase
import public
from panelAes import AesCryptPy3
from ssl_manage import SSLManger


class main(sslBase):
    def __init__(self):
        self.__init_data()

    def __init_data(self):
        self.__create_table()
        self.check_and_add_ps_column()

    def __create_table(self):
        """
        @name 检查表是否存在
        """
        public.check_table('ssl_info',
                           "CREATE TABLE IF NOT EXISTS 'ssl_info' ("
                           "'id' INTEGER PRIMARY KEY AUTOINCREMENT, "
                           "'group_id' INTEGER NOT NULL DEFAULT 0, "
                           "'hash' TEXT NOT NULL UNIQUE, "
                           "'path' TEXT NOT NULL, "
                           "'dns' TEXT NOT NULL, "
                           "'subject' TEXT NOT NULL, "
                           "'info' TEXT NOT NULL DEFAULT '', "
                           "'cloud_id' INTEGER NOT NULL DEFAULT -1, "
                           "'not_after' TEXT NOT NULL, "
                           "'use_for_panel' INTEGER NOT NULL DEFAULT 0, "
                           "'use_for_site' TEXT NOT NULL DEFAULT '[]', "
                           "'auth_info' TEXT NOT NULL DEFAULT '{}', "
                           "'ps' TEXT DEFAULT '', "  # 新增字段ps，用于存储备份说明
                           "'create_time' INTEGER NOT NULL DEFAULT (strftime('%s'))"
                           ");"
                           )

    def check_and_add_ps_column(self):
        try:
            public.M('ssl_info').field('group_id').select()
        except Exception as e:
            if "no such column: group_id" in str(e):
                try:
                    public.M('ssl_info').execute("ALTER TABLE 'ssl_info' ADD 'group_id' INTEGER NOT NULL DEFAULT 0", ())
                except Exception as e:
                    pass

        try:
            public.M('ssl_info').field('ps').select()
        except Exception as e:
            if "no such column: group_id" in str(e):
                try:
                    public.M('ssl_info').execute("ALTER TABLE 'ssl_info' ADD 'ps' INTEGER NOT NULL DEFAULT ''", ())
                except Exception as e:
                    pass

    def get_cert_group(self, get):
        """
        @name 获取证书分组
        """
        data = []
        try:
            sfile = '{}/data/cert_group.json'.format(public.get_panel_path())
            if not os.path.isfile(sfile):
                data = [{'name': '默认分组', 'group_id': '0', 'ssl': {"1": [], "2": [], "3": []}}]
                public.writeFile(sfile, json.dumps(data))
                return data
            data = json.loads(public.readFile(sfile))
            for i in data:
                if not i.get('ssl'):
                    i['ssl'] = {"1": [], "2": [], "3": []}
            public.writeFile(sfile, json.dumps(data))
        except:
            pass

        return data

    def add_cert_group(self, get):
        """
        @name 添加证书分组
        """
        sfile = '{}/data/cert_group.json'.format(public.get_panel_path())
        try:
            data = json.loads(public.readFile(sfile))
        except:
            data = []

        for i in data:
            if get.name == i["name"]:
                return public.returnMsg(False, '此分组已存在')
        data.append({'name': get.name, 'group_id': uuid.uuid4().hex, 'ssl': {"1": [], "2": [], "3": []}})
        public.writeFile(sfile, json.dumps(data))
        return public.returnMsg(True, '添加成功')

    def del_cert_group(self, get):

        sfile = '{}/data/cert_group.json'.format(public.get_panel_path())
        try:
            data = json.loads(public.readFile(sfile))
            i = 0
            while i < len(data):
                if data[i]["group_id"] == str(get.group_id):
                    del data[i]
                    break
                i += 1
            public.writeFile(sfile, json.dumps(data))
            return public.returnMsg(True, '删除成功')
        except:
            return public.returnMsg(False, '删除失败')

    def set_cert_group(self, get):
        sfile = '{}/data/cert_group.json'.format(public.get_panel_path())
        try:
            ids = json.loads(get.ids)
        except:
            return public.returnMsg(False, "请选择证书")
        data = self.get_cert_group(get)
        for i in data:
            for j in ids:
                while str(j['id']) in i['ssl'][j['type']]:
                    i['ssl'][j['type']].remove(str(j['id']))
                if get.group_id == i['group_id']:
                    i['ssl'][j['type']].append(str(j['id']))

        public.writeFile(sfile, json.dumps(data))
        return public.returnMsg(True, '设置成功')

    def get_group_data(self, get):
        data = self.get_cert_group(get)
        type1 = {}
        type2 = {}
        type3 = {}
        for i in data:
            if not i.get('ssl'):
                continue
            type1.update({j: i['name'] for j in i['ssl']["1"] if i['ssl'].get("1")})
            type2.update({j: i['name'] for j in i['ssl']["2"] if i['ssl'].get("2")})
            type3.update({j: i['name'] for j in i['ssl']["3"] if i['ssl'].get("3")})
        return {"1": type1, "2": type2, "3": type3}

    def get_cert_to_site(self, pure=False):
        """
        获取证书部署网站
        """
        import acme_v2
        from datalistModel import sitesModel
        acme = acme_v2.acme_v2()
        sites_model = sitesModel.main()
        hash_data = acme.get_exclude_hash(public.to_dict_obj({}))
        hash_dic = {}
        hash_dic.update(hash_data.get("exclude_hash") or {})
        hash_dic.update(hash_data.get("exclude_hash_let") or {})

        # 获取所有网站
        site_data = public.M('sites').field('name,project_type').select()
        path = "/www/server/panel/vhost/cert/"
        data = {'cancel': []} if not pure else {}
        for cert in site_data:
            if cert['project_type'] in ['PHP', 'proxy', 'WP', 'WP2']:
                if sites_model.get_site_ssl_info(cert['name']) == -1:
                    continue
            else:
                if not SSLManger._get_site_ssl_info(cert['name'], cert['project_type'].lower()):
                    continue
                # if not RealSSLManger('{}_'.format(cert['project_type'].lower())).get_site_ssl_info(cert['name']):
                #     continue
            cert_name = cert["name"]
            cert_path = path + cert_name
            cert_index = ''
            if os.path.exists(cert_path + '/fullchain.pem'):
                try:
                    cert_index = self._hash(cert_filename=cert_path + '/fullchain.pem')
                except:
                    continue
                if not pure:
                    for k, v in hash_dic.items():
                        if v == cert_index:
                            # cert_index = k
                            if k not in data.keys():
                                data.update({k: [cert_name]})
                            else:
                                data[k].append(cert_name)
                            break
            if cert_index:
                if cert_index not in data.keys():
                    data.update({cert_index: [cert_name]})
                else:
                    data[cert_index].append(cert_name)
        return data

    def get_cert_brand(self):
        path = '{}/data/cert_brand.json'.format(public.get_panel_path())
        if not os.path.exists(path):
            data = {
                "comodo-positivessl-wildcard": "Sectigo RSA Domain Validation Secure Server CA",
                "comodo-positivessl": "Sectigo RSA Domain Validation Secure Server CA",
            }
            public.writeFile(path, json.dumps(data))
            return data
        return json.loads(public.readFile(path))

    def set_cert_brand(self, brand):
        path = '{}/data/cert_brand.json'.format(public.get_panel_path())
        data = self.get_cert_brand()
        data.update(brand)
        public.writeFile(path, json.dumps(data))


    def get_cert_list(self, get):
        """
        获取证书列表
        """
        import panelSSL

        search = get.get('search', '')
        group_id = get.get('group_id', '')
        status_id = get.get('status_id', '')
        search_domain = get.get('search_domain', '')
        cert_type = get.get('cert_type', '0')
        if status_id:
            status_id = int(status_id)
        if search:
            public.set_search_history('ssl', 'get_cert_list', search)

        group_data = self.get_cert_group(get)
        group_name_dic = self.get_group_data(get)
        group_name = None
        ssl_ids = None
        exclude_ids = {'1': [], '2': [], '3': []}

        for i in group_data:
            if str(i['group_id']) == str(group_id):
                group_name = i["name"]
                ssl_ids = i["ssl"]
            else:
                exclude_ids['1'].extend(i["ssl"]['1'])
                exclude_ids['2'].extend(i["ssl"]['2'])
                exclude_ids['3'].extend(i["ssl"]['3'])


        # 找不到分组直接置空
        if not ssl_ids and group_id:
            return {}

        p = 1
        if 'p' in get:
            p = int(get.p)
        collback = ''
        if 'collback' in get:
            collback = get.collback
        limit = 999999999
        if 'limit' in get:
            limit = int(get.limit)

        # 部署网站
        use_site_dic = self.get_cert_to_site()
        # 证书夹排除数据
        exclude_hash = panelSSL.panelSSL().get_exclude_hash(get)
        # 告警数据
        report_data_dic = self.get_report_task()

        format_time_strs = ("%Y-%m-%d", "%Y-%m-%d %H:%M:%S")
        from datetime import datetime
        today_time = datetime.today().timestamp()

        cancel_list = []
        if exclude_hash.get('exclude_hash'):
            cancel_list.extend(exclude_hash['exclude_hash'].values())
        if exclude_hash.get('exclude_hash_let'):
            cancel_list.extend(exclude_hash['exclude_hash_let'].values())

        will_num = 0
        end_num = 0
        data = []

        if cert_type in ("4", "0"):
            # 证书夹数据
            cert_data = []
            if status_id != 0:
                cert_data = public.M('ssl_info').field(
                    'id,hash,dns,cloud_id,not_after,auth_info,info,ps,group_id'
                ).select()

            for cert in cert_data:
                if not isinstance(cert,dict):
                    continue
                if cert['hash'] in cancel_list:
                    continue
                end_time = 90
                for f_str in format_time_strs:
                    try:
                        end_time = int(
                            (datetime.strptime(cert["not_after"], f_str).timestamp() - today_time) / (60 * 60 * 24)
                        )
                    except Exception as e:
                        continue
                cert["sort"] = cert['endDay'] = end_time
                if 0 < cert['endDay'] <= 30:
                    will_num += 1
                elif cert['endDay'] <= 0:
                    end_num += 1
                if status_id == 1 and cert['endDay'] <= 0:
                    continue
                elif status_id == 2 and (cert['endDay'] > 30 or cert['endDay'] <= 0):
                    continue
                elif status_id == 3 and (cert['endDay'] > 0):
                    continue

                if ssl_ids and str(cert['id']) not in ssl_ids['3']:
                    if str(group_id) == '0':
                        if str(cert['id']) in exclude_ids['3']:
                            continue
                    else:
                        continue
                cert['group_name'] = group_name if group_name else group_name_dic["3"].get(str(cert['id']), "默认分组")
                info = json.loads(cert["info"])
                cert['title'] = info['issuer']

                cert["domainName"] = json.loads(cert["dns"])
                domainName = ",".join(cert['domainName'] or [])
                if search.lower() not in domainName.lower() and search.lower() not in cert['title'].lower():
                    continue
                if search_domain and search_domain not in cert["domainName"]:
                    continue
                cert["auth_info"] = json.loads(cert["auth_info"])

                cert['type'] = "3"
                cert["use_site"] = use_site_dic.get(cert["hash"], [])
                cert["ssl_id"] = cert["hash"]
                cert["report_id"] = report_data_dic.get(cert['ssl_id'], "") or ""
                data.append(cert)

        if cert_type in ("1", "0"):
            brand_data = self.get_cert_brand()

            # 商用证书订单数据
            import ssl_info
            try:
                _cert_data = panelSSL.panelSSL().get_order_list(get)
            except:
                _cert_data = []
            if not isinstance(_cert_data, list):
                _cert_data = []
            for cert in _cert_data:
                if cert['endDate']:
                    cert['endDay'] = int(
                        (cert['endDate'] - today_time) / (60 * 60 * 24)
                    )
                if 0 < cert['endDay'] <= 30:
                    will_num += 1
                elif cert['endDay'] <= 0 and cert['orderStatus'] in ('COMPLETE', "EXPIRED"):
                    end_num += 1
                if status_id == 0 and cert['orderStatus'] not in ("PENDING", ""):
                    continue
                elif status_id == 1 and (cert['endDay'] <= 0 or cert['orderStatus'] != 'COMPLETE'):
                    continue
                elif status_id == 2 and ((cert['endDay'] > 30 or cert['endDay'] <= 0) or cert['orderStatus'] != 'COMPLETE'):
                    continue
                elif status_id == 3 and (cert['endDay'] > 0 or cert['orderStatus'] not in ('COMPLETE', "EXPIRED")):
                    continue

                cert['id'] = cert['oid']
                if ssl_ids and str(cert['id']) not in ssl_ids['1']:
                    if str(group_id) == '0':
                        if str(cert['id']) in exclude_ids['1']:
                            continue
                    else:
                        continue
                if cert['orderStatus'] in ('COMPLETE', "EXPIRED"):
                    title = brand_data.get(cert['code'], "")
                    if title:
                        cert["title"] = title
                    else:
                        # 证书信息
                        get.oid = cert['oid']
                        certInfo = panelSSL.panelSSL().get_order_find(get)
                        if certInfo['certificate'] and certInfo['caCertificate']:
                            _info = ssl_info.ssl_info().load_ssl_info_by_data(certInfo['certificate']+"\n"+certInfo['caCertificate'])
                            cert["title"] = _info['issuer']
                            self.set_cert_brand({cert['code']: title})

                cert['group_name'] = group_name if group_name else group_name_dic["1"].get(str(cert['id']), "默认分组")
                domainName = ",".join(cert['domainName'] or [])
                if search.lower() not in domainName.lower() and search.lower() not in cert["title"].lower():
                    continue
                cert['type'] = "1"
                cert["use_site"] = use_site_dic.get(str(cert["oid"]), [])
                cert["ssl_id"] = str(cert["oid"])
                cert["report_id"] = report_data_dic.get(cert['ssl_id'], "") or ""
                if cert["orderStatus"] == "":
                    cert["sort"] = 99998
                elif cert["orderStatus"] == "PENDING":
                    cert["sort"] = 99999
                cert['download_status'] = True if cert['orderStatus'] == 'COMPLETE' and cert['status'] == 1 else False
                data.append(cert)

        if cert_type in ("2", "0"):
        # 测试证书订单数据
            try:
                test_cert_data = panelSSL.panelSSL().GetOrderList(get)
            except:
                test_cert_data = {}
            for cert in test_cert_data.get('data', []):

                try:
                    end_time = int(
                        (cert["endtime"]/1000 - today_time) / (60 * 60 * 24)
                    )
                except Exception as e:
                    end_time = 90
                cert['endDay'] = end_time

                if 0 < cert['endDay'] <= 30 and cert['stateCode'] == "COMPLETED":
                    will_num += 1
                elif cert['endDay'] <= 0 and cert['stateCode'] == "COMPLETED":
                    end_num += 1
                if status_id == 0 and cert['stateCode'] != "WF_DOMAIN_APPROVAL":
                    continue
                elif status_id == 1 and (cert['endDay'] <= 0 or cert['stateCode'] != "COMPLETED"):
                    continue
                elif status_id == 2 and ((cert['endDay'] > 30 or cert['endDay'] <= 0) or cert['stateCode'] != "COMPLETED"):
                    continue
                elif status_id == 3 and (cert['endDay'] > 0 or cert['stateCode'] != "COMPLETED"):
                    continue

                cert['ssl_id'] = str(cert['ssl_id'])
                cert['id'] = cert['ssl_id']
                if ssl_ids and str(cert['id']) not in ssl_ids['2']:
                    if str(group_id) == '0':
                        if str(cert['id']) in exclude_ids['2']:
                            continue
                    else:
                        continue
                cert['group_name'] = group_name if group_name else group_name_dic["2"].get(str(cert['id']), "默认分组")
                cert['title'] = "TrustAsia RSA DV TLS CA G2"
                if search.lower() not in cert["authDomain"].lower() and search.lower() not in cert['title'].lower():
                    continue

                cert['domainName'] = [cert['authDomain']]
                cert['type'] = "2"
                cert["use_site"] = use_site_dic.get(cert["partnerOrderId"], [])
                cert["report_id"] = report_data_dic.get(cert['ssl_id'], "") or ""
                cert["sort"] = -99999999
                if cert['stateCode'] != 'COMPLETED':
                    del cert['endDay']
                data.append(cert)

        if cert_type in ("3", "0"):
            # 计划任务
            crontab_data = self.get_crontab()
            # let's encrypt证书订单数据
            import acme_v2
            let_cert_data = acme_v2.acme_v2().get_order_list(get)
            for cert in let_cert_data:
                if 0 < cert['endDay'] <= 30:
                    will_num += 1
                elif cert['endDay'] <= 0:
                    end_num += 1
                # 状态
                if status_id == 0 and (cert['status'] != "pending" or cert['endDay'] <= 0):
                    continue
                elif status_id == 1 and (cert['endDay'] <= 0 or cert['status'] == "pending"):
                    continue
                elif status_id == 2 and (cert['endDay'] > 30 or cert['endDay'] <= 0):
                    continue
                elif status_id == 3 and (cert['endDay'] > 0):
                    continue
                # 搜索
                cert['title'] = "let's Encrypt"
                cert['domainName'] = cert['domains']
                domainName = ",".join(cert['domainName'] or [])
                if search.lower() not in domainName.lower() and search.lower() not in cert["title"].lower():
                    continue
                if ssl_ids and str(cert['index']) not in ssl_ids['3']:
                    if str(group_id) == '0':
                        if str(cert['index']) in exclude_ids['3']:
                            continue
                    else:
                        continue
                cert['type'] = "3"
                cert['order_status'] = cert['status']
                cert['order_status_nm'] = cert['status']
                if cert['status'] == 'pending':
                    cert['order_status_nm'] = '待验证'
                    if cert.get('auth_tag'):
                        cert['status'] = 'invalid'
                        cert['order_status'] = 'invalid'
                        cert['order_status_nm'] = '验证失败'
                elif cert['status'] == 'valid':
                    cert['order_status_nm'] = '已完成'

                cert['group_name'] = group_name if group_name else group_name_dic["3"].get(str(cert['index']), "默认分组")
                cert["ssl_id"] = cert["index"]
                cert["id"] = cert["index"]
                cert["report_id"] = report_data_dic.get(cert['ssl_id'], "") or ""
                cert["use_site"] = use_site_dic.get(str(cert["index"]), [])
                cert["cloud_id"] = 1
                cert['crontab_id'] = -1
                for crontab in crontab_data:
                    if not crontab['sBody']:
                        continue
                    if cert['index'] in crontab['sBody']:
                        cert['crontab_id'] = crontab['id']
                        try:
                            renew_data = json.loads(public.readFile("{}/config/letsencrypt_auto_renew.json".format(public.get_panel_path())))
                        except:
                            renew_data = {}
                        cert['crontab_data'] = renew_data.get(str(cert['index']), {"status": 1, "error_msg": ""})
                        break
                cert["sort"] = cert['endDay']
                if cert['status'] == 'pending' and cert['endDay'] > 0:
                    cert["sort"] = 99999
                data.append(cert)

        reverse = True
        sort = 'sort'
        if status_id == 2:
            sort = 'endDay'
            reverse = False
        data = sorted(data, key=lambda k: k.get(sort, 0) or 0, reverse=reverse)

        count = len(data)
        start = (p - 1) * limit
        end = start + limit
        if end > count:
            end = count

        search_history = public.get_search_history('ssl', 'get_cert_list')
        page_data = public.get_page(count, p, limit, collback)
        page_data.update({"data": data[start: end], 'search_history': search_history, 'will_num': will_num, 'end_num': end_num})
        return page_data

    def get_cert_list_to_push(self, get):
        items = [
            {
                "title": "{} | {}".format(i["title"], ",".join(i.get("domainName", []) or "无")),
                "value": i["ssl_id"]
            }
            for i in self.get_cert_list(public.to_dict_obj({"status_id": 1}))['data'] if i.get("endDay")
        ]
        items.insert(0, {
              "title": "所有证书",
              "value": "all"
            })
        return items

    def remove_cloud_cert(self, get):
        ssl_id = None
        ssl_hash = None
        index = None
        local = False
        cloud = False
        force = False
        try:
            if "ssl_id" in get:
                ssl_id = int(get.ssl_id)
            if "ssl_hash" in get:
                ssl_hash = get.ssl_hash.strip()
            if "index" in get:
                index = get.index.strip()

            if "local" in get and get.local.strip() in ("1", 1, True, "true"):
                local = True
            if "cloud" in get and get.cloud.strip() in ("1", 1, True, "true"):
                cloud = True

        except (ValueError, AttributeError, KeyError):
            return public.ReturnMsg(False, "参数错误")
        try:
            finish_list = []
            if get.get("oid"):
                import panelSSL
                finish_list = panelSSL.panelSSL().batch_soft_release(public.to_dict_obj({"oid": get.oid}))['finish_list']
            import acme_v2
            _return = acme_v2.acme_v2()._delete_order(public.to_dict_obj({"index": index, "ssl_hash": ssl_hash, "local": local, "cloud": cloud, "force": force}))
            _return['finish_list'].extend(finish_list)
            return _return
        except ValueError as e:
            return public.ReturnMsg(status=False, msg=str(e))
        except Exception as e:
            return public.ReturnMsg(status=False, msg="操作错误：" + str(e))

    def del_site_cert(self, ssl_hash, no_site_list):
        import panelSite
        if not ssl_hash:
            return
        path = "/www/server/panel/vhost/cert"
        for cert_path in os.listdir(path):
            try:
                cert_hash = self._hash('{}/{}/fullchain.pem'.format(path, cert_path))
            except:
                continue
            if cert_hash == ssl_hash:
                if cert_path in no_site_list:
                    panelSite.panelSite().CloseSSLConf(public.to_dict_obj({"siteName": cert_path}))
                shutil.rmtree('{}/{}'.format(path, cert_path))

    def remove_cert(self, ssl_id=None, ssl_hash=None, local: bool = False, cloud: bool = False, force=False):
        _, _, user_info = self._get_cbc_key_and_iv(with_uer_info=True)
        if user_info is None:
            raise ValueError(
                public.lang("The panel is not logged in, so cloud upload is not possible!")
            )

        target = self.find_ssl_info(ssl_id=ssl_id, ssl_hash=ssl_hash)
        if not target:
            raise ValueError(public.lang('There is no specified certificate.'))

        if local:
            hash_dic = self.get_cert_to_site()
            no_site_list = hash_dic.get(target["hash"], [])
            if no_site_list and not force:
                raise ValueError(public.lang(
                    "The certificate is currently in use by website【{}】"
                    "Please turn off the SSL of these websites or configure these websites "
                    "with other certificates before deletion.".format(",".join(no_site_list))
                ))
            if os.path.exists(target["path"]):
                shutil.rmtree(target["path"])
            self._remove_ssl_from_local(target["hash"])  # 把ssl下的也删除
            # 删除cert
            self.del_site_cert(target["hash"], no_site_list)
            public.M('ssl_info').delete(id=target["id"])

        if target["cloud_id"] != -1 and cloud and not public.is_self_hosted():
            url = "https://wafapi2.yakpanel.com/api/Cert_cloud_deploy/del_cert"
            try:
                res_text = public.httpPost(url, {
                    "cert_id": target["cloud_id"],
                    "hashVal": target["hash"],
                    "uid": user_info["uid"],
                    "access_key": 'B' * 32,
                    "serverid": user_info["server_id"],
                })
                res_data = json.loads(res_text)
                if res_data["status"] is False:
                    return res_data
            except:
                if local:
                    raise ValueError(public.lang("Local deletion was successful, "
                                                 "but the connection to the cloud failed, "
                                                 "and cloud data could not be deleted.")
                                     )
                raise ValueError(public.lang("Failed to connect to the cloud. Unable to delete cloud data."))

            public.M('ssl_info').where("id = ?", (target["id"],)).update({"cloud_id": -1})
        elif target["cloud_id"] != -1 and cloud and public.is_self_hosted() and not local:
            public.M('ssl_info').where("id = ?", (target["id"],)).update({"cloud_id": -1})

        return public.returnMsg(True, public.lang("del successfully"))

    def batch_remove_cert(self, get):
        return self.remove_cloud_cert(get)

    def upload_cert_to_cloud(self, get):
        ssl_id = None
        ssl_hash = None
        try:
            if "ssl_id" in get:
                ssl_id = int(get.ssl_id)
            if "ssl_hash" in get:
                ssl_hash = get.ssl_hash.strip()
        except (ValueError, AttributeError, KeyError):
            return public.ReturnMsg(False, public.lang("wrong params"))
        try:
            data = self.upload_cert(ssl_id, ssl_hash)
            return data
        except ValueError as e:
            return public.ReturnMsg(False, str(e))
        except Exception as e:
            return public.ReturnMsg(False, public.lang("Operation error:" + str(e)))

    def upload_cert(self, ssl_id=None, ssl_hash=None):
        key, iv, user_info = self._get_cbc_key_and_iv()
        if key is None or iv is None:
            raise ValueError(False, public.lang('The panel is not logged in, and upload to the cloud is not possible!'))

        target = self.find_ssl_info(ssl_id=ssl_id, ssl_hash=ssl_hash)
        if not target:
            raise ValueError(public.lang('There is no specified certificate information.'))

        data = {
            'privateKey': public.readFile(target["path"] + '/privkey.pem'),
            'certificate': public.readFile(target["path"] + '/fullchain.pem'),
            "encryptWay": "AES-128-CBC",
            "hashVal": target['hash'],
            "uid": user_info["uid"],
            "access_key": 'B' * 32,
            "serverid": user_info["server_id"],
        }

        if data["privateKey"] is False or data["certificate"] is False:
            raise ValueError(public.lang('Certificate file reading error'))

        AES = AesCryptPy3(key, "CBC", iv, char_set="utf8")
        data["privateKey"] = AES.aes_encrypt(data["privateKey"])
        data["certificate"] = AES.aes_encrypt(data["certificate"])
        # 对接云端
        url = "https://wafapi2.yakpanel.com/api/Cert_cloud_deploy/cloud_deploy"

        try:
            res_text = public.httpPost(url, data)
            res_data = json.loads(res_text)
            if res_data["status"] is True:
                cloud_id = int(res_data["data"].get("id"))
                public.M('ssl_info').where("id = ?", (target["id"],)).update({"cloud_id": cloud_id})

                return res_data
            else:
                return res_data
        except:
            raise ValueError(public.lang('Failed to connect to the cloud'))

    def _remove_ssl_from_local(self, ssl_hash):
        local_path = '/www/server/panel/vhost/ssl'
        if not os.path.exists(local_path):
            return

        for p_name in os.listdir(local_path):
            pem_file = "{}/{}/fullchain.pem".format(local_path, p_name)

            if os.path.isfile(pem_file):
                hash_data = self._hash(cert_filename=pem_file)
                if hash_data == ssl_hash:
                    shutil.rmtree("{}/{}".format(local_path, p_name))

    def _hash(self, cert_filename: str = None, certificate: str = None, ignore_errors: bool = False):
        if cert_filename is not None and os.path.isfile(cert_filename):
            certificate = public.readFile(cert_filename)

        if not isinstance(certificate, str) or not certificate.startswith("-----BEGIN"):
            if ignore_errors:
                return None
            raise ValueError(public.lang("Certificate format error"))

        md5_obj = md5()
        md5_obj.update(certificate.encode("utf-8"))
        return md5_obj.hexdigest()

    @staticmethod
    def _get_cbc_key_and_iv(with_uer_info=True):
        uer_info_file = "{}/data/userInfo.json".format(public.get_panel_path())
        try:
            user_info = json.loads(public.readFile(uer_info_file))
            uid = user_info["uid"]
        except (json.JSONDecodeError, KeyError):
            return None, None, None

        md5_obj = md5()
        md5_obj.update(str(uid).encode('utf8'))
        bytes_data = md5_obj.hexdigest()

        key = ''
        iv = ''
        for i in range(len(bytes_data)):
            if i % 2 == 0:
                iv += bytes_data[i]
            else:
                key += bytes_data[i]

        if with_uer_info:
            return key, iv, user_info

        return key, iv, None

    @staticmethod
    def find_ssl_info(ssl_id=None, ssl_hash=None):
        tmp_conn = public.M('ssl_info')
        if ssl_id is None and ssl_hash is None:
            raise ValueError(public.lang("no params"))
        if ssl_id is not None:
            tmp_conn.where("id = ?", (ssl_id,))
        else:
            tmp_conn.where("hash = ?", (ssl_hash,))

        target = tmp_conn.find()
        if isinstance(target, str) and target.startswith("error"):
            raise ValueError(public.lang("db query error:" + target))

        if not bool(target):
            return None

        target["auth_info"] = json.loads(target["auth_info"])
        target["use_for_site"] = json.loads(target["use_for_site"])
        target["dns"] = json.loads(target["dns"])
        target["info"] = json.loads(target["info"])
        target['endtime'] = int((datetime.strptime(target['not_after'], "%Y-%m-%d").timestamp()
                                 - datetime.today().timestamp()) / (60 * 60 * 24))
        return target

    def GetCert(self, get):
        from ssl_manage import SSLManger
        if "ssl_hash" in get:
            return SSLManger.get_cert_for_deploy(get.ssl_hash.strip())
        else:
            if "index" in get:
                import acme_v2
                acme = acme_v2.acme_v2()
                exclude_data = acme.get_exclude_hash(get)
                ssl_hash = exclude_data['exclude_hash_let'].get(get.index)
                return SSLManger.get_cert_for_deploy(ssl_hash.strip())

        vpath = os.path.join('/www/server/panel/vhost/ssl', get.certName.replace("*.", ''))
        if not os.path.exists(vpath): return public.returnMsg(False, public.lang('The certificate does not exist!'))
        data = {}
        data['privkey'] = public.readFile(vpath + '/privkey.pem')
        data['fullchain'] = public.readFile(vpath + '/fullchain.pem')
        return data

    # 部署
    def SetCertToSite(self, get):

        try:
            if 'ssl_hash' in get or "index" in get:
                result = self.GetCert(get)
            else:
                result = {"privkey": get.privkey, "fullchain": get.fullchain}
            if not 'privkey' in result: return result
            siteName = get.siteName
            path = '/www/server/panel/vhost/cert/' + siteName
            if not os.path.exists(path):
                public.ExecShell('mkdir -p ' + path)
            csrpath = path + "/fullchain.pem"
            keypath = path + "/privkey.pem"

            # 清理旧的证书链
            public.ExecShell('rm -f ' + keypath)
            public.ExecShell('rm -f ' + csrpath)
            public.ExecShell('rm -rf ' + path + '-00*')
            public.ExecShell('rm -rf /etc/letsencrypt/archive/' + get.siteName)
            public.ExecShell('rm -rf /etc/letsencrypt/archive/' + get.siteName + '-00*')
            public.ExecShell('rm -f /etc/letsencrypt/renewal/' + get.siteName + '.conf')
            public.ExecShell('rm -f /etc/letsencrypt/renewal/' + get.siteName + '-00*.conf')
            public.ExecShell('rm -f ' + path + '/README')
            if os.path.exists(path + '/certOrderId'): os.remove(path + '/certOrderId')

            public.writeFile(keypath, result['privkey'])
            public.writeFile(csrpath, result['fullchain'])
            import panelSite
            return panelSite.panelSite().SetSSLConf(get)
        except Exception as ex:
            if 'isBatch' in get: return False
            return public.returnMsg(False, 'SET_ERROR,' + public.get_error_info())

    def SetBatchCertToSite(self, get):
        """
        @name 批量部署证书
        @auther hezhihong
        """

        if not hasattr(get, 'BatchInfo') or not get.BatchInfo:
            return public.returnMsg(False, public.lang('wrong params'))
        else:
            ssl_list = json.loads(get.BatchInfo)
        if isinstance(ssl_list, list):
            total_num = len(ssl_list)
            resultinfo = {"total": total_num, "success": 0, "faild": 0, "successList": [], "faildList": []}
            successList = []
            faildList = []
            successnum = 0
            failnum = 0
            for Info in ssl_list:
                set_result = {'status': True}
                get.certName = set_result['certName'] = Info.get('certName')
                get.siteName = set_result['siteName'] = str(Info['siteName'])  # 站点名称必定为字符串
                get.isBatch = True
                if "ssl_hash" in Info:
                    get.ssl_hash = Info.get('ssl_hash')
                result = self.SetCertToSite(get)
                if not result:
                    set_result['status'] = False
                    failnum += 1
                    faildList.append(set_result)
                else:
                    successnum += 1
                    successList.append(set_result)
                public.writeSpeed('setssl', successnum + failnum, total_num)
            import firewalls
            get.port = '443'
            get.ps = 'HTTPS'
            firewalls.firewalls().AddAcceptPort(get)
            public.serviceReload()
            resultinfo['success'] = successnum
            resultinfo['faild'] = failnum
            resultinfo['successList'] = successList
            resultinfo['faildList'] = faildList

            if hasattr(get, "set_https_mode") and get.set_https_mode.strip() in (True, 1, "1", "true"):
                import panelSite
                sites_obj = panelSite.panelSite()
                if not sites_obj.get_https_mode():
                    sites_obj.set_https_mode()

        else:
            return public.returnMsg(False, public.lang('wrong params type'))
        return resultinfo

    # 证书转为pkcs12
    def dump_pkcs12(self, key_pem=None, cert_pem=None, ca_pem=None, friendly_name=None):
        """
        @证书转为pkcs12
        @key_pem string 私钥数据
        @cert_pem string 证书数据
        @ca_pem string 可选的CA证书数据
        @friendly_name string 可选的证书名称
        """
        try:
            from acme_v2 import acme_v2
            result = acme_v2().dump_pkcs12(key_pem, cert_pem, ca_pem, friendly_name)
        except:
            import ssl_info
            result = ssl_info.ssl_info().dump_pkcs12_new(key_pem, cert_pem, ca_pem, friendly_name)
        return result

    def download_cert(self, get):
        # 兼容订单下载
        if 'index' in get:
            import acme_v2
            return acme_v2.acme_v2().download_cert_to_local(get)
        if 'ssl_id' in get:
            target = self.find_ssl_info(ssl_id=get.ssl_id)
        elif 'ssl_hash' in get:
            target = self.find_ssl_info(ssl_hash=get.ssl_hash)
        else:
            return public.returnMsg(False, public.lang('wrong params'))
        if not target:
            return public.returnMsg(False, public.lang('There is no certificate information.'))
        csrpath = os.path.join(target['path'], "fullchain.pem")
        keypath = os.path.join(target['path'], "privkey.pem")
        data_hash = self._hash(csrpath)
        if not os.path.isfile(csrpath) or get.ssl_hash != data_hash:
            return public.returnMsg(False, public.lang('There is no certificate information.'))
        key = public.readFile(keypath)
        csr = public.readFile(csrpath)

        rpath = '{}/temp/ssl'.format(public.get_panel_path())
        if os.path.exists(rpath): shutil.rmtree(rpath)
        path = '{}/{}'.format(rpath, data_hash)
        domain_cert = csr.split('-----END CERTIFICATE-----')[0] + "-----END CERTIFICATE-----\n"
        ca_cert = csr.replace(domain_cert, '')

        p12 = self.dump_pkcs12(key, '{}\n{}'.format(domain_cert.strip(), ca_cert), ca_cert)

        for x in ['IIS', 'Apache', 'Nginx', '其他证书']:
            d_file = '{}/{}'.format(path, x)
            if not os.path.exists(d_file): os.makedirs(d_file)

            if x == 'IIS' and p12 is not None:
                public.writeFile2(d_file + '/fullchain.pfx', p12, 'wb+')
                public.writeFile(d_file + '/password.txt', get['pwd'])
            elif x == 'Apache':
                public.writeFile(d_file + '/privkey.key', key)
                public.writeFile(d_file + '/root_bundle.crt', ca_cert)
                public.writeFile(d_file + '/domain.crt', domain_cert)
            else:
                public.writeFile(d_file + '/privkey.key', key)
                public.writeFile(d_file + '/fullchain.pem', '{}\n{}'.format(domain_cert.strip(), ca_cert))

        flist = []
        public.get_file_list(path, flist)

        zfile = '{}/{}.zip'.format(rpath, target["dns"][0]+"_"+data_hash)
        import zipfile
        f = zipfile.ZipFile(zfile, 'w', zipfile.ZIP_DEFLATED)
        for item in flist:
            s_path = item.replace(path, '')
            if s_path: f.write(item, s_path)
        f.close()

        port = str(public.get_panel_port())
        # host = public.GetLocalIp()  # 获取服务器地址
        from flask import request
        host = request.host.split(":")[0]
        ssl = "https" if public.is_ssl() else "http"

        zfile = '{}://{}:{}/download?filename={}'.format(ssl, host, port, zfile)

        return public.returnMsg(True, zfile)

    def get_order_download_data(self, index):
        import acme_v2
        acme = acme_v2.acme_v2()
        exclude_data = acme.get_exclude_hash(None)
        ssl_hash = exclude_data.get("exclude_hash_let", {}).get(index, "")
        data = self.find_ssl_info(ssl_hash=ssl_hash)
        if not data:
            raise ValueError(public.lang('There is no certificate information.'))
        data['info'] = json.dumps({"issuer": "let's Encrypt"})
        return data

    def batch_download_cert(self, get):
        if not 'ssl_hash' in get and not 'index' in get and not 'oid' in get:
            return public.returnMsg(False, public.lang('wrong params'))
        finish_list = []
        cert_data = []
        if 'ssl_hash' in get and get.ssl_hash.strip():
            hash_list = get.ssl_hash.split(',')
            ssl_hash = "','".join(hash_list) if len(hash_list) > 1 else hash_list[0]
            cert_data = public.M('ssl_info').where("hash in ('{}')".format(ssl_hash), ()).select()

        if 'index'in get and get.index.strip():
            index_list = get.index.split(',')
            for index in index_list:
                try:
                    cert_data.append(self.get_order_download_data(index))
                except:
                    finish_list.append({"status": False, "cert": {"info": json.dumps({"issuer": "let's Encrypt"})}})

        rpath = '{}/temp/_ssl'.format(public.get_panel_path())
        if os.path.exists(rpath): shutil.rmtree(rpath)

        if 'oid' in get and get.oid.strip():
            import panelSSL
            import base64

            os.makedirs(rpath)
            oid_list = get.oid.split(',')
            for oid in oid_list:

                try:
                    result = panelSSL.panelSSL().download_cert(public.to_dict_obj({'oid': oid}))
                    if not result or not result.get('data') or not result.get('filename'):
                        finish_list.append({"status": False, "cert": {"info": json.dumps({"issuer": oid})}})
                        continue
                    with open(rpath + '/{}_{}'.format(oid, result['filename']), 'wb') as f:
                        f.write(base64.b64decode(result['data']))
                    finish_list.append({"status": True, "cert": {"info": json.dumps({"issuer": oid})}})
                except:
                    finish_list.append({"status": False, "cert": {"info": json.dumps({"issuer": oid})}})

        for cert in cert_data:
            csrpath = os.path.join(cert['path'], "fullchain.pem")
            keypath = os.path.join(cert['path'], "privkey.pem")
            data_hash = self._hash(csrpath)

            if not os.path.exists(csrpath) or not os.path.exists(keypath):
                finish_list.append({"status": False, "cert": cert})

            key = public.readFile(keypath)
            csr = public.readFile(csrpath)
            try:
                dns = json.loads(cert['dns'])
            except:
                dns = cert.get('dns')

            path = '{}/{}'.format(rpath, dns[0]+"_"+data_hash)
            domain_cert = csr.split('-----END CERTIFICATE-----')[0] + "-----END CERTIFICATE-----\n"
            ca_cert = csr.replace(domain_cert, '')

            p12 = self.dump_pkcs12(key, '{}\n{}'.format(domain_cert.strip(), ca_cert), ca_cert)

            for x in ['IIS', 'Apache', 'Nginx', '其他证书']:
                d_file = '{}/{}'.format(path, x)
                if not os.path.exists(d_file): os.makedirs(d_file)

                if x == 'IIS' and p12 is not None:
                    public.writeFile2(d_file + '/fullchain.pfx', p12, 'wb+')
                    public.writeFile(d_file + '/password.txt', get['pwd'])
                elif x == 'Apache':
                    public.writeFile(d_file + '/privkey.key', key)
                    public.writeFile(d_file + '/root_bundle.crt', ca_cert)
                    public.writeFile(d_file + '/domain.crt', domain_cert)
                else:
                    public.writeFile(d_file + '/privkey.key', key)
                    public.writeFile(d_file + '/fullchain.pem', '{}\n{}'.format(domain_cert.strip(), ca_cert))
            finish_list.append({"status": True, "cert": cert})

        if os.path.exists(rpath) and os.listdir(rpath):
            flist = []
            public.get_file_list(rpath, flist)
            zfile = '{}.zip'.format(rpath)
            import zipfile
            f = zipfile.ZipFile(zfile, 'w', zipfile.ZIP_DEFLATED)
            for item in flist:
                s_path = item.replace(rpath, '')
                if s_path: f.write(item, s_path)
            f.close()
            port = str(public.get_panel_port())
            # host = public.GetLocalIp()  # 获取服务器地址
            from flask import request
            host = request.host.split(":")[0]
            ssl = "https" if public.is_ssl() else "http"
            zfile = '{}://{}:{}/download?filename={}'.format(ssl, host, port, zfile)
        else:
            zfile = ''
        return {'finish_list': finish_list, 'url': zfile}

    def parse_certificate(self, get):
        """
        获取证书信息
        """
        try:
            from cryptography import x509
            from cryptography.hazmat.backends import default_backend

            cert = x509.load_pem_x509_certificate(get.csr, default_backend())
            try:
                # 提取品牌（证书颁发对象）
                brand = cert.issuer.get_attributes_for_oid(x509.NameOID.COMMON_NAME)[0].value
                # 提取 CA 名称
                ca_name = cert.issuer.get_attributes_for_oid(x509.NameOID.ORGANIZATION_NAME)[0].value
            except:
                brand = "unknown"
                ca_name = "unknown"

            # 提取认证域名
            try:
                cn = cert.subject.get_attributes_for_oid(x509.NameOID.COMMON_NAME)[0].value
            except IndexError:
                cn = None

            # 提取 SAN（Subject Alternative Name）
            try:
                san_extension = cert.extensions.get_extension_for_oid(x509.ExtensionOID.SUBJECT_ALTERNATIVE_NAME).value
                san_domains = san_extension.get_values_for_type(x509.DNSName)
            except x509.ExtensionNotFound:
                san_domains = []
                # 合并 CN 和 SAN，并去重
            all_domains = set(san_domains)
            if cn:
                all_domains.add(cn)

            # 提取到期时间
            try:
                expiration_date = cert.not_valid_after_utc.timestamp()
            except:
                expiration_date = "unknown"

        except Exception as e:
            public.print_log(str(e))
            brand = "unknown"
            all_domains = []
            expiration_date = "unknown"
            ca_name = "unknown"

        return {
            "brand": brand,
            "domains": list(all_domains),
            "expiration_date": expiration_date,
            "ca_name": ca_name
        }

    def save_cert(self, get):
        from panelSite import panelSite
        import ssl_info
        ssl_info = ssl_info.ssl_info()
        create_order = False

        key = get.key.strip()
        csr = get.csr.strip()

        issuer = panelSite().analyze_ssl(csr)
        if issuer.get("organizationName") == "Let's Encrypt":
            create_order = True
            csr += "\n"

        # 验证证书和密钥是否匹配格式是否为pem
        check_flag, check_msg = ssl_info.verify_certificate_and_key_match(get.key, get.csr)
        if not check_flag: return public.returnMsg(False, check_msg)
        # 验证证书链是否完整
        check_chain_flag, check_chain_msg = ssl_info.verify_certificate_chain(get.csr)
        if not check_chain_flag: return public.returnMsg(False, check_chain_msg)

        hash_data = self._hash(certificate=csr)
        path = "/www/server/panel/vhost/ssl_saved/" + hash_data
        csrpath = path + "/fullchain.pem"
        keypath = path + "/privkey.pem"

        # 判断是否存在
        if os.path.exists(path):
            return {"status": True, "msg": public.lang("The certificate already exists."), "creat_order": create_order, "ssl_hash": hash_data}

        # 保存文件
        public.ExecShell('mkdir -p ' + path)
        public.writeFile(keypath, key)
        public.writeFile(csrpath, csr)
        # 解析数据
        cert_data = {}
        if csr:
            get.certPath = csrpath
            import panelSSL
            cert_data = panelSSL.panelSSL().GetCertName(get)

        # 写入数据库
        target = self.find_ssl_info(ssl_hash=hash_data)
        if target:
            public.M('ssl_info').where(
                "id = ?", (target["id"],)
            ).update(
                ({
                    "path": path,
                    "dns": json.dumps(cert_data["dns"]),
                    "subject": cert_data["subject"],
                    "info": json.dumps(cert_data),
                    "not_after": cert_data["notAfter"]
                })
            )
        else:
            public.M('ssl_info').add(
                'hash,path,dns,subject,info,not_after'
                , (hash_data, path, json.dumps(cert_data["dns"]), cert_data["subject"], json.dumps(cert_data), cert_data["notAfter"])
            )
        return {"status": True, "msg": public.lang("Save successfully"), "creat_order": create_order, "ssl_hash": hash_data}

    def create_order(self, get):
        try:
            target = self.find_ssl_info(ssl_hash=get.ssl_hash)
            ssl_info = target.get('info')

            if not ssl_info:
                return public.returnMsg(False, public.lang("Certificate information not found"))
            if ssl_info.get("issuer_O") != "Let's Encrypt":
                return public.returnMsg(False, public.lang("The certificate is not issued by Let's Encrypt."))
            index = public.md5(str(uuid.uuid4()))
            order_data = {
                "status": "valid",
                "auth_type": "dns",
                "domains": ssl_info.get("dns"),
                "auth_to": "dns",
                "certificate_url": "",
                "save_path": "vhost/ssl_saved/{}".format(get.ssl_hash),
                "index": index,
                "cert_timeout": datetime.strptime(ssl_info.get("notAfter"), "%Y-%m-%d").timestamp(),
                "renew_time": 0,
                "retry_count": 0,
                "next_retry_time": 0
            }
            # 写入config
            config_path = "/www/server/panel/config/letsencrypt_v2.json"
            try:
                config_data = json.loads(public.readFile(config_path))
            except:
                config_data = {}
            config_data["orders"][index] = order_data
            public.writeFile(config_path, json.dumps(config_data))

            import acme_v2
            acm_obj = acme_v2.acme_v2()
            pem = public.readFile("vhost/ssl_saved/{}/fullchain.pem".format(get.ssl_hash))
            acm_obj.set_exclude_hash(index, pem)
            return {"status": True, "msg": public.lang("Create successful!"), "index": index}
        except:
            public.print_log(public.get_error_info())
            return public.returnMsg(False, public.lang("Create fail!"))

    def apply_for_cert(self, get):
        """
        申请证书
        """
        from acme_v2 import acme_v2
        acm_obj = acme_v2()
        index = None
        if "index" in get:
            index = get.index
        if index:
            return acm_obj.apply_cert([], "dns", "dns", index=index)

        if 'auto_wildcard' in get and get.auto_wildcard == '1':
            acm_obj._auto_wildcard = True

        domains = json.loads(get.domains)
        auth_type = get.auth_type
        auth_to = get.auth_to

        return acm_obj.apply_cert(domains, auth_type, auth_to)

    def update_cert_from_cloud(self, get):
        """
        从云端同步到本地
        """
        if public.is_self_hosted():
            return public.returnMsg(False, public.lang('Certificate cloud sync is not available in self-hosted mode.'))
        key, iv, user_info = self._get_cbc_key_and_iv(with_uer_info=True)
        if key is None or iv is None:
            return public.returnMsg(False, public.lang("The panel is not logged in, "
                                                       "so it's impossible to connect to the cloud!"))
        # 获取本地证书
        local_cert = public.M('ssl_info').field(
            'hash'
        ).select()
        hash_list = [i['hash'] for i in local_cert]

        AES = AesCryptPy3(key, "CBC", iv, char_set="utf8")

        # 对接云端
        url = "https://wafapi2.yakpanel.com/api/Cert_cloud_deploy/get_cert_list"
        try:
            res_text = public.httpPost(url, {
                "uid": user_info["uid"],
                "access_key": 'B' * 32,
                "serverid": user_info["server_id"],
            })
            res_data = json.loads(res_text)
            if res_data["status"] is False:
                return public.returnMsg(False, public.lang('Failed to obtain cloud data'))

            res_list = res_data['data']
        except:
            return public.returnMsg(False, public.lang('Failed to obtain cloud data'))
        x = 0
        for data in res_list:
            try:
                get.key = AES.aes_decrypt(data["privateKey"])
                get.csr = AES.aes_decrypt(data["certificate"])
                cloud_id = data["id"]
                hash_data = self._hash(certificate=get.csr)

                if hash_data in hash_list:
                    # 删除本地证书
                    public.ExecShell('rm -rf /www/server/panel/vhost/ssl_saved/' + hash_data)
                self.save_cert(get)
                public.M('ssl_info').where("hash = ?", (hash_data,)).update({"cloud_id": cloud_id})
                x += 1
            except Exception as e:
                pass
        return public.returnMsg(True, "{} certificates have been synchronized.".format(str(x)))

    def get_report_task(self):

        from mod.project.push import taskMod
        report_data = taskMod.main().get_task_list().get('data')
        report_data_dic = {}
        if report_data:
            report_data_dic = {i["keyword"]: i["id"] for i in report_data if
                               i["source"] == "cert_endtime" and i["status"]}
        return report_data_dic

    def create_report_task(self, get):
        from mod.base.push_mod import manager

        data = self.get_cert_list(public.to_dict_obj({"status_id": 1}))["data"]
        if not get.ssl_id in [i['ssl_id'] for i in data]:
            return public.returnMsg(False, public.lang("Certificate information was not found"))
        sender_lsit = get.sender.split(",")
        task_data = {"task_data":{"tid":"71","type":"cert_endtime","title":"The certificate has expired.","status":True,"count":0,"interval":600,"project":get.ssl_id,"cycle":int(get.cycle)},"sender":sender_lsit,"number_rule":{"day_num":0,"total":int(get.total)},"time_rule":{"send_interval":0,"time_range":[0,86399]}}
        get.template_id = "71"
        get.task_data = json.dumps(task_data)

        return manager.PushManager().set_task_conf(get)

    def remove_report_task(self, get):
        from mod.base.push_mod import manager
        return manager.PushManager().remove_task_conf(get)

    def renewal_cert(self, get):
        import acme_v2
        if 'index' not in get:
            return public.returnMsg(False, public.lang('Required parameters are missing.'))
        return acme_v2.acme_v2().renew_cert(get.index)

    def get_crontab(self):
        data = public.M('crontab').select()
        return data

    def add_renewal_task(self, get):
        import crontab
        import random
        cron = crontab.crontab()
        get.name = "Renew the Let's Encrypt certificate[{}]".format(get.name).replace("'", "")
        get.sBody = "/www/server/panel/pyenv/bin/python3 -u /www/server/panel/class/acme_v2.py --renew=1 --index={} --cycle={}".format(get.index, get.cycle)
        get.type = "day"
        get.week = 1
        get.hour = random.randint(0, 23)
        get.minute = random.randint(0, 59)
        get.second = ""
        get.sName = ""
        get.backupTo = ""
        get.save = ""
        get.urladdress = ""
        get.notice_channel = ""
        get.datab_name = ""
        get.tables_name = ""
        get.keyword = ""
        get.where1 = 1
        get.timeSet = 1
        get.timeType = 'sday'
        get.sType = 'toShell'
        get.save_local = 0
        get.notice = 0
        get.flock = 1

        return cron.AddCrontab(get)

    def del_renewal_task(self, get):
        import crontab
        cron = crontab.crontab()
        get.id = get.crontab_id
        return cron.DelCrontab(get)

    def get_cert_content(self, get):
        """
        获取证书内容
        """
        if 'ssl_hash' in get and get.ssl_hash:
            ssl_hash = get.ssl_hash
        else:
            if 'index' in get and get.index:
                import acme_v2
                acme = acme_v2.acme_v2()
                exclude_data = acme.get_exclude_hash(None)
                ssl_hash = exclude_data.get("exclude_hash_let", {}).get(get.index, "")
            else:
                return public.returnMsg(False, public.lang('Required parameters are missing.'))
        if not ssl_hash:
            return public.returnMsg(False, public.lang('No certificate information was found.'))
        ssl_info = self.find_ssl_info(ssl_hash=ssl_hash)
        ssl_info["key"] = public.readFile("/www/server/panel/vhost/ssl_saved/{}/privkey.pem".format(ssl_hash))
        ssl_info["cert"] = public.readFile("/www/server/panel/vhost/ssl_saved/{}/fullchain.pem".format(ssl_hash))
        return {"status": True, "msg": public.lang("success"), "content": ssl_info}



