1418 lines
58 KiB
Python
1418 lines
58 KiB
Python
|
|
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}
|
|||
|
|
|
|||
|
|
|
|||
|
|
|