Initial YakPanel commit
This commit is contained in:
BIN
class/sslModel/__pycache__/certModel.cpython-314.pyc
Normal file
BIN
class/sslModel/__pycache__/certModel.cpython-314.pyc
Normal file
Binary file not shown.
199
class/sslModel/aliyunModel.py
Normal file
199
class/sslModel/aliyunModel.py
Normal file
@@ -0,0 +1,199 @@
|
||||
import time
|
||||
|
||||
from sslModel.base import sslBase
|
||||
|
||||
import public
|
||||
import os
|
||||
|
||||
from urllib.parse import urlencode, quote_plus
|
||||
import hashlib
|
||||
import hmac
|
||||
import uuid
|
||||
import pytz
|
||||
import requests
|
||||
from datetime import datetime
|
||||
|
||||
|
||||
|
||||
class main(sslBase):
|
||||
dns_provider_name = "aliyun"
|
||||
_type = 0
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
def __init_data(self, data):
|
||||
self.access_key_id = data["AccessKey"]
|
||||
self.access_key_secret = data["SecretKey"]
|
||||
self.endpoint = "alidns.cn-hangzhou.aliyuncs.com"
|
||||
self.ALGORITHM = "ACS3-HMAC-SHA256"
|
||||
self.x_acs_version = "2015-01-09"
|
||||
|
||||
def sign_to_response(self, dns_id, action, query_param):
|
||||
self.__init_data(self.get_dns_data(None)[dns_id])
|
||||
|
||||
def hmac256(key, msg):
|
||||
return hmac.new(key, msg.encode('utf-8'), hashlib.sha256).digest()
|
||||
|
||||
def sha256_hex(s):
|
||||
return hashlib.sha256(s.encode('utf-8')).hexdigest()
|
||||
|
||||
def percent_code(encoded_str):
|
||||
return encoded_str.replace('+', '%20').replace('*', '%2A').replace('%7E', '~')
|
||||
|
||||
headers = {
|
||||
"host": self.endpoint,
|
||||
"x-acs-action": action,
|
||||
"x-acs-version": self.x_acs_version,
|
||||
"x-acs-date": datetime.now(pytz.timezone('Etc/GMT')).strftime('%Y-%m-%dT%H:%M:%SZ'),
|
||||
"x-acs-signature-nonce": str(uuid.uuid4()),
|
||||
}
|
||||
|
||||
sorted_query_params = sorted(query_param.items(), key=lambda item: item[0])
|
||||
query_param = {k: v for k, v in sorted_query_params}
|
||||
|
||||
# Step 1: Construct Canonical Query String and Payload Hash
|
||||
canonical_query_string = '&'.join(
|
||||
f'{percent_code(quote_plus(k))}={percent_code(quote_plus(str(v)))}' for k, v in
|
||||
query_param.items())
|
||||
hashed_request_payload = sha256_hex('')
|
||||
headers['x-acs-content-sha256'] = hashed_request_payload
|
||||
sorted_headers = sorted(headers.items(), key=lambda item: item[0])
|
||||
headers = {k: v for k, v in sorted_headers}
|
||||
|
||||
# Construct Canonical Headers and Signed Headers
|
||||
canonical_headers = '\n'.join(f'{k.lower()}:{v}' for k, v in headers.items() if
|
||||
k.lower().startswith('x-acs-') or k.lower() in ['host', 'content-type'])
|
||||
signed_headers = ';'.join(sorted(headers.keys(), key=lambda x: x.lower()))
|
||||
|
||||
canonical_request = f'GET\n/\n{canonical_query_string}\n{canonical_headers}\n\n{signed_headers}\n{hashed_request_payload}'
|
||||
|
||||
# Step 2: Construct String to Sign
|
||||
hashed_canonical_request = sha256_hex(canonical_request)
|
||||
string_to_sign = f'{self.ALGORITHM}\n{hashed_canonical_request}'
|
||||
|
||||
# Step 3: Compute Signature
|
||||
signature = hmac256(self.access_key_secret.encode('utf-8'), string_to_sign).hex().lower()
|
||||
|
||||
# Step 4: Construct Authorization Header
|
||||
authorization = f'{self.ALGORITHM} Credential={self.access_key_id},SignedHeaders={signed_headers},Signature={signature}'
|
||||
headers['Authorization'] = authorization
|
||||
|
||||
url = f'https://{self.endpoint}/'
|
||||
if query_param:
|
||||
url += '?' + urlencode(query_param, doseq=True, safe='*')
|
||||
headers = {k: v for k, v in headers.items()}
|
||||
|
||||
response = requests.request(method="GET", url=url, headers=headers)
|
||||
return response
|
||||
|
||||
|
||||
def create_dns_record(self, get):
|
||||
domain_name = get.domain_name
|
||||
domain_dns_value = get.domain_dns_value
|
||||
record_type = 'TXT'
|
||||
if 'record_type' in get:
|
||||
record_type = get.record_type
|
||||
|
||||
domain_name, sub_domain, _ = self.extract_zone(domain_name)
|
||||
|
||||
if not sub_domain:
|
||||
sub_domain = '@'
|
||||
|
||||
query_param = {
|
||||
"DomainName": domain_name,
|
||||
"RR": sub_domain,
|
||||
"Type": record_type,
|
||||
"Value": domain_dns_value
|
||||
}
|
||||
|
||||
try:
|
||||
response = self.sign_to_response(get.dns_id, "AddDomainRecord", query_param)
|
||||
if response.status_code != 200:
|
||||
return public.returnMsg(False, self.get_error(response.text))
|
||||
return public.returnMsg(True, '添加成功')
|
||||
except Exception as e:
|
||||
return public.returnMsg(False, self.get_error(str(e)))
|
||||
|
||||
def delete_dns_record(self, get):
|
||||
RecordId = get.RecordId
|
||||
|
||||
try:
|
||||
response = self.sign_to_response(get.dns_id, "DeleteDomainRecord", {"RecordId":RecordId})
|
||||
if response.status_code != 200:
|
||||
return public.returnMsg(False, self.get_error(response.text))
|
||||
return public.returnMsg(True, '删除成功')
|
||||
except Exception as e:
|
||||
return public.returnMsg(False, self.get_error(str(e)))
|
||||
|
||||
def get_dns_record(self, get):
|
||||
domain_name, _, sub_domain = self.extract_zone(get.domain_name)
|
||||
data = {}
|
||||
try:
|
||||
response = self.sign_to_response(get.dns_id, "DescribeDomainRecords", {"DomainName": domain_name})
|
||||
res = response.json()
|
||||
if response.status_code != 200:
|
||||
return {}
|
||||
data["list"] = [
|
||||
{
|
||||
"RecordId": i["RecordId"],
|
||||
"name": i["RR"] + "." + domain_name if i["RR"] != '@' else domain_name,
|
||||
"value": i["Value"],
|
||||
"line": i["Line"],
|
||||
"ttl": i["TTL"],
|
||||
"type": i["Type"],
|
||||
"status": "启用" if i["Status"] == "ENABLE" else "暂停" if i["Status"] == "DISABLE" else i["Status"],
|
||||
"mx": i.get("Priority") or 0,
|
||||
"updated_on": time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(i["UpdateTimestamp"] / 1000)),
|
||||
"remark": i.get("Remark") or "",
|
||||
}
|
||||
for i in res["DomainRecords"]["Record"]
|
||||
]
|
||||
data["info"] = {
|
||||
"record_total": res["TotalCount"]
|
||||
}
|
||||
|
||||
except Exception as e:
|
||||
pass
|
||||
self.set_record_data({domain_name: data})
|
||||
return data
|
||||
|
||||
def update_dns_record(self, get):
|
||||
RecordId = get.RecordId
|
||||
domain_name = get.domain_name
|
||||
domain_dns_value = get.domain_dns_value
|
||||
record_type = get.record_type
|
||||
|
||||
domain_name, sub_domain, _ = self.extract_zone(domain_name)
|
||||
|
||||
try:
|
||||
params = {
|
||||
"RecordId": RecordId,
|
||||
"Type": record_type,
|
||||
"Value": domain_dns_value,
|
||||
"RR": sub_domain,
|
||||
}
|
||||
response = self.sign_to_response(get.dns_id, "UpdateDomainRecord", params)
|
||||
if response.status_code != 200:
|
||||
return public.returnMsg(False, self.get_error(response.text))
|
||||
return public.returnMsg(True, "修改成功")
|
||||
except Exception as e:
|
||||
return public.returnMsg(False, self.get_error(str(e)))
|
||||
|
||||
def get_error(self, error):
|
||||
if "DomainRecordConflict" in error:
|
||||
return "与其他记录冲突,不能添加"
|
||||
elif "SubDomainInvalid.Value" in error:
|
||||
return "DNS记录值无效或者格式错误"
|
||||
elif "DomainRecordDuplicate" in error:
|
||||
return "解析记录已存在"
|
||||
elif "The parameter value RR is invalid" in error:
|
||||
return "主机记录错误,请检查后重试"
|
||||
elif "InvalidDomainName.NoExist" in error:
|
||||
return "这个阿里云账户下面不存在这个域名,请检查dns接口配置后重试"
|
||||
elif "IncorrectDomainUser" in error:
|
||||
return "这个阿里云账户下面不存在这个域名,请检查dns接口配置后重试"
|
||||
elif "InvalidAccessKeyId.NotFound" in error:
|
||||
return "无效的Access Key"
|
||||
else:
|
||||
return error
|
||||
167
class/sslModel/base.py
Normal file
167
class/sslModel/base.py
Normal file
@@ -0,0 +1,167 @@
|
||||
# coding: utf-8
|
||||
# -------------------------------------------------------------------
|
||||
# YakPanel
|
||||
# -------------------------------------------------------------------
|
||||
# Copyright (c) 2015-2099 YakPanel(https://www.yakpanel.com) All rights reserved.
|
||||
# -------------------------------------------------------------------
|
||||
# Author: cjxin <cjxin@yakpanel.com>
|
||||
# -------------------------------------------------------------------
|
||||
# 面板获取列表公共库
|
||||
# ------------------------------
|
||||
|
||||
import os,sys,time,json,db,re
|
||||
import uuid
|
||||
|
||||
os.chdir("/www/server/panel")
|
||||
if 'class/' not in sys.path:
|
||||
sys.path.insert(0, 'class/')
|
||||
import public
|
||||
|
||||
|
||||
|
||||
caa_value = '0 issue "letsencrypt.org"'
|
||||
# godaddy接口访问不了,先注释
|
||||
# 'GoDaddyDns':'godaddy'
|
||||
dns_type = {'DNSPodDns': 'dnspod', 'AliyunDns': 'aliyun', 'HuaweiCloudDns': 'huaweicloud', 'TencentCloudDns': 'tencentcloud', 'CloudFlareDns': 'cloudflare', 'WestDns': 'west'}
|
||||
# dns_name = {'DNSPodDns':'DNSPod','AliyunDns':'阿里云DNS','HuaweiCloudDns':'华为云DNS','TencentCloudDns':'腾讯云DNS','CloudflareDns':'CloudFlare',}
|
||||
class sslBase(object):
|
||||
def __init__(self):
|
||||
self.dns_provider_name = self.__class__.__name__
|
||||
|
||||
self.top_domain_list = [
|
||||
'.ac.cn', '.ah.cn', '.bj.cn', '.com.cn', '.cq.cn', '.fj.cn', '.gd.cn',
|
||||
'.gov.cn', '.gs.cn', '.gx.cn', '.gz.cn', '.ha.cn', '.hb.cn', '.he.cn',
|
||||
'.hi.cn', '.hk.cn', '.hl.cn', '.hn.cn', '.jl.cn', '.js.cn', '.jx.cn',
|
||||
'.ln.cn', '.mo.cn', '.net.cn', '.nm.cn', '.nx.cn', '.org.cn', '.us.kg']
|
||||
top_domain_list_data = public.readFile('{}/config/domain_root.txt'.format(public.get_panel_path()))
|
||||
if top_domain_list_data:
|
||||
self.top_domain_list = set(self.top_domain_list + top_domain_list_data.strip().split('\n'))
|
||||
|
||||
def log_response(self, response):
|
||||
try:
|
||||
log_body = response.json()
|
||||
except ValueError:
|
||||
log_body = response.content
|
||||
return log_body
|
||||
|
||||
def create_dns_record(self, domain_name, domain_dns_value):
|
||||
raise NotImplementedError("create_dns_record method must be implemented.")
|
||||
|
||||
def delete_dns_record(self, domain_name, domain_dns_value):
|
||||
raise NotImplementedError("delete_dns_record method must be implemented.")
|
||||
|
||||
@classmethod
|
||||
def new(cls, conf_data):
|
||||
raise NotImplementedError("new method must be implemented.")
|
||||
|
||||
def remove_record(self, domain, host, s_type):
|
||||
raise NotImplementedError("remove_record method must be implemented.")
|
||||
|
||||
def add_record_for_creat_site(self, domain, server_ip):
|
||||
raise NotImplementedError("remove_record method must be implemented.")
|
||||
|
||||
|
||||
def extract_zone(self,domain_name, is_let_txt=False):
|
||||
if is_let_txt:
|
||||
domain_name = domain_name.lstrip("*.")
|
||||
top_domain = "." + ".".join(domain_name.rsplit('.')[-2:])
|
||||
is_tow_top = False
|
||||
if top_domain in self.top_domain_list:
|
||||
is_tow_top = True
|
||||
if domain_name.count(".") <= 1:
|
||||
zone = ""
|
||||
root = domain_name
|
||||
acme_txt = "_acme-challenge"
|
||||
else:
|
||||
zone, middle, last = domain_name.rsplit(".", 2)
|
||||
acme_txt = "_acme-challenge.%s" % zone
|
||||
if is_tow_top:
|
||||
last = top_domain[1:]
|
||||
middle = zone.split(".")[-1]
|
||||
root = ".".join([middle, last])
|
||||
return root, zone, acme_txt
|
||||
|
||||
def get_dns_data(self, get):
|
||||
"""
|
||||
@name 获取dns的api数据
|
||||
"""
|
||||
res = {}
|
||||
sfile = "{}/config/dns_mager.conf".format(public.get_panel_path())
|
||||
|
||||
try:
|
||||
if not os.path.exists(sfile):
|
||||
return res
|
||||
data = json.loads(public.readFile(sfile))
|
||||
|
||||
for key in data.keys():
|
||||
for val in data[key]:
|
||||
if val['id'] in res:
|
||||
continue
|
||||
if not dns_type.get(key,''):
|
||||
continue
|
||||
# val['dns_name'] = dns_name.get(key)
|
||||
val['dns_name'] = key
|
||||
val['dns_type'] = dns_type.get(key,'')
|
||||
res[val['id']] = val
|
||||
except:pass
|
||||
return res
|
||||
|
||||
def get_record_data(self):
|
||||
path = '{}/data/record_data.json'.format(public.get_panel_path())
|
||||
try:
|
||||
data = json.loads(public.readFile(path))
|
||||
except:
|
||||
data = {}
|
||||
return data
|
||||
|
||||
def set_record_data(self, data):
|
||||
path = '{}/data/record_data.json'.format(public.get_panel_path())
|
||||
record_data = self.get_record_data()
|
||||
record_data.update(data)
|
||||
try:
|
||||
public.writeFile(path, json.dumps(record_data))
|
||||
except:
|
||||
pass
|
||||
|
||||
def _dns_data():
|
||||
"""
|
||||
将旧的dnsapi同步到dns_mager.conf
|
||||
"""
|
||||
try:
|
||||
old_file = "{}/config/dns_api.json".format(public.get_panel_path())
|
||||
if not os.path.exists(old_file):
|
||||
return
|
||||
new_file = "{}/config/dns_mager.conf".format(public.get_panel_path())
|
||||
try:
|
||||
old_data = json.loads(public.readFile(old_file))
|
||||
except:
|
||||
return
|
||||
if not os.path.exists(new_file):
|
||||
new_data = {}
|
||||
else:
|
||||
new_data = json.loads(public.readFile(new_file))
|
||||
for i in old_data:
|
||||
if not i['data']:
|
||||
continue
|
||||
if i['name'] == "TencentCloudDns":
|
||||
for d in i['data']:
|
||||
d['name'] = "secret_id" if d['name'] == "AccessKey" else "secret_key" if d['name'] == "SecretKey" else d['name']
|
||||
if new_data.get(i['name']) or i['name'] not in dns_type.keys():
|
||||
continue
|
||||
pl = True
|
||||
value = {'ps': "旧版本{}接口".format(i['name']), 'id': uuid.uuid4().hex}
|
||||
for val in i['data']:
|
||||
if not val['value']:
|
||||
pl = False
|
||||
break
|
||||
value.update({val['name']: val['value']})
|
||||
if not pl:
|
||||
continue
|
||||
new_data[i['name']] = [value]
|
||||
# print(new_data)
|
||||
public.writeFile(new_file, json.dumps(new_data))
|
||||
except:
|
||||
pass
|
||||
|
||||
_dns_data()
|
||||
del _dns_data
|
||||
1417
class/sslModel/certModel.py
Normal file
1417
class/sslModel/certModel.py
Normal file
File diff suppressed because it is too large
Load Diff
194
class/sslModel/cloudflareModel.py
Normal file
194
class/sslModel/cloudflareModel.py
Normal file
@@ -0,0 +1,194 @@
|
||||
from sslModel.base import sslBase
|
||||
import requests
|
||||
from urllib.parse import urlparse
|
||||
from urllib.parse import urljoin
|
||||
import public
|
||||
|
||||
|
||||
class main(sslBase):
|
||||
dns_provider_name = "cloudflare"
|
||||
_type = 0 # 0:lest 1:锐成
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
def __init_data(self, data):
|
||||
self.CLOUDFLARE_EMAIL = data['E-Mail']
|
||||
self.CLOUDFLARE_API_KEY = data['API Key']
|
||||
self.CLOUDFLARE_API_BASE_URL = 'https://api.cloudflare.com/client/v4/'
|
||||
self.HTTP_TIMEOUT = 65 # seconds
|
||||
|
||||
self.headers = {
|
||||
"X-Auth-Email": self.CLOUDFLARE_EMAIL,
|
||||
"X-Auth-Key": self.CLOUDFLARE_API_KEY
|
||||
}
|
||||
|
||||
def get_dns_record(self, get):
|
||||
domain_name = get.domain_name
|
||||
dns_id = get.dns_id
|
||||
self.__init_data(self.get_dns_data(None)[dns_id])
|
||||
|
||||
root_domain, _, sub_domain = self.extract_zone(domain_name)
|
||||
data = {}
|
||||
try:
|
||||
zone_dic = self.get_zoneid_dic(get)
|
||||
zone_id = zone_dic[root_domain]
|
||||
url = urljoin(self.CLOUDFLARE_API_BASE_URL, "zones/{}/dns_records".format(zone_id))
|
||||
response = requests.get(url, headers=self.headers, timeout=self.HTTP_TIMEOUT).json()
|
||||
data = {
|
||||
"info": {
|
||||
'record_total': response['result_info']['total_count']
|
||||
},
|
||||
"list": [
|
||||
{
|
||||
"RecordId": i["id"],
|
||||
"name": i["name"],
|
||||
"domain_name": i["name"],
|
||||
"value": i["content"],
|
||||
"line": "默认",
|
||||
"ttl": i["ttl"],
|
||||
"type": i["type"],
|
||||
"status": "启用",
|
||||
"mx": i.get("priority") or 0,
|
||||
"updated_on": i["modified_on"],
|
||||
"remark": i.get("comment") or "",
|
||||
}
|
||||
for i in response["result"]
|
||||
]
|
||||
}
|
||||
|
||||
except Exception as e:
|
||||
pass
|
||||
self.set_record_data({domain_name: data})
|
||||
return data
|
||||
|
||||
def create_dns_record(self, get):
|
||||
domain_name = get.domain_name
|
||||
dns_id = get.dns_id
|
||||
record_type = get.record_type
|
||||
domain_dns_value = get.domain_dns_value
|
||||
|
||||
self.__init_data(self.get_dns_data(None)[dns_id])
|
||||
|
||||
root_domain, sub_domain, _ = self.extract_zone(domain_name)
|
||||
body = {
|
||||
"content": get.domain_dns_value,
|
||||
"name": sub_domain or '@',
|
||||
"type": get.record_type if 'record_type' in get else 'TXT'
|
||||
}
|
||||
# CAA记录特殊处理
|
||||
if record_type == 'CAA':
|
||||
values = domain_dns_value.split(' ')
|
||||
if len(values) != 3 or values[1] not in ("issue", "issuewild", "iodef"):
|
||||
return public.returnMsg(False, '解析记录格式错误,请检查后重试')
|
||||
body["data"] = {
|
||||
"flags": values[0],
|
||||
"tag": values[1],
|
||||
"value": values[2].replace('"', ''),
|
||||
}
|
||||
|
||||
try:
|
||||
zone_dic = self.get_zoneid_dic(get)
|
||||
zone_id = zone_dic.get(root_domain)
|
||||
if not zone_id:
|
||||
return public.returnMsg(False, '此域名配置的dns账号不正确')
|
||||
url = urljoin(self.CLOUDFLARE_API_BASE_URL, "zones/{}/dns_records".format(zone_id))
|
||||
response = requests.post(url, headers=self.headers, json=body, timeout=self.HTTP_TIMEOUT)
|
||||
if response.status_code == 200:
|
||||
return public.returnMsg(True, '添加成功')
|
||||
else:
|
||||
return public.returnMsg(False, '添加失败,{}'.format(self.get_error(response.text)))
|
||||
except Exception as e:
|
||||
return public.returnMsg(False, '添加失败,msg:{}'.format(e))
|
||||
|
||||
def delete_dns_record(self, get):
|
||||
domain_name = get.domain_name
|
||||
dns_id = get.dns_id
|
||||
RecordId = get.RecordId
|
||||
|
||||
self.__init_data(self.get_dns_data(None)[dns_id])
|
||||
|
||||
root_domain, sub_domain, _ = self.extract_zone(domain_name)
|
||||
|
||||
try:
|
||||
zone_dic = self.get_zoneid_dic(get)
|
||||
zone_id = zone_dic.get(root_domain)
|
||||
if not zone_id:
|
||||
return public.returnMsg(False, '此域名配置的dns账号不正确')
|
||||
url = urljoin(self.CLOUDFLARE_API_BASE_URL, "zones/{}/dns_records/{}".format(zone_id, RecordId))
|
||||
response = requests.delete(url, headers=self.headers, timeout=self.HTTP_TIMEOUT)
|
||||
if response.status_code == 200:
|
||||
return public.returnMsg(True, '删除成功')
|
||||
else:
|
||||
return public.returnMsg(False, self.get_error(response.text))
|
||||
except Exception as e:
|
||||
return public.returnMsg(False, '删除失败,msg:{}'.format(e))
|
||||
|
||||
def get_zoneid_dic(self, get):
|
||||
dns_id = get.dns_id
|
||||
self.__init_data(self.get_dns_data(None)[dns_id])
|
||||
|
||||
url = urljoin(self.CLOUDFLARE_API_BASE_URL, "zones?status=active&per_page=1000")
|
||||
try:
|
||||
response = requests.get(url, headers=self.headers, timeout=self.HTTP_TIMEOUT)
|
||||
data = response.json()
|
||||
return {i["name"]: i["id"] for i in data["result"]}
|
||||
except:
|
||||
return {}
|
||||
|
||||
def update_dns_record(self, get):
|
||||
domain_name = get.domain_name
|
||||
RecordId = get.RecordId
|
||||
domain_dns_value = get.domain_dns_value
|
||||
record_type = get.record_type
|
||||
dns_id = get.dns_id
|
||||
|
||||
self.__init_data(self.get_dns_data(None)[dns_id])
|
||||
|
||||
root_domain, sub_domain, _ = self.extract_zone(domain_name)
|
||||
|
||||
body = {
|
||||
"content": get.domain_dns_value,
|
||||
"name": sub_domain or '@',
|
||||
"type": get.record_type,
|
||||
}
|
||||
|
||||
# CAA记录特殊处理
|
||||
if record_type == 'CAA':
|
||||
values = domain_dns_value.split(' ')
|
||||
if len(values) != 3:
|
||||
return public.returnMsg(False, '解析记录格式错误,请检查后重试')
|
||||
body["data"] = {
|
||||
"flags": values[0],
|
||||
"tag": values[1],
|
||||
"value": values[2].replace('"', ''),
|
||||
}
|
||||
try:
|
||||
zone_dic = self.get_zoneid_dic(get)
|
||||
zone_id = zone_dic.get(root_domain)
|
||||
if not zone_id:
|
||||
return public.returnMsg(False, '此域名配置的dns账号不正确')
|
||||
url = urljoin(self.CLOUDFLARE_API_BASE_URL, "zones/{}/dns_records/{}".format(zone_id, RecordId))
|
||||
response = requests.patch(url, headers=self.headers, json=body, timeout=self.HTTP_TIMEOUT)
|
||||
if response.status_code == 200:
|
||||
return public.returnMsg(True, '修改成功')
|
||||
else:
|
||||
return public.returnMsg(False, '修改失败,{}'.format(self.get_error(response.text)))
|
||||
except Exception as e:
|
||||
return public.returnMsg(False, '修改失败,msg:{}'.format(e))
|
||||
|
||||
def get_error(self, error):
|
||||
if "Record does not exist" in error:
|
||||
return "解析记录不存在"
|
||||
elif "Content for A record must be a valid IPv4 address" in error:
|
||||
return "【A】记录的解析值必须为IPv4地址"
|
||||
elif "Content for CNAME record is invalid" in error:
|
||||
return "请正确填写【CNAME】类型的解析值"
|
||||
elif "DNS record type is invalid" in error:
|
||||
return "解析记录类型无效"
|
||||
elif "A record with the same settings already exists" in error:
|
||||
return "已存在相同的解析记录"
|
||||
elif "Error unable to get DNS zone for domain_name" in error:
|
||||
return "这个cloudflare账户下面不存在这个域名,请检查dns接口配置后重试"
|
||||
else:
|
||||
return error
|
||||
523
class/sslModel/dataModel.py
Normal file
523
class/sslModel/dataModel.py
Normal file
@@ -0,0 +1,523 @@
|
||||
# coding: utf-8
|
||||
# -------------------------------------------------------------------
|
||||
# YakPanel
|
||||
# -------------------------------------------------------------------
|
||||
# Copyright (c) 2015-2099 YakPanel(https://www.yakpanel.com) All rights reserved.
|
||||
# -------------------------------------------------------------------
|
||||
# Author: cjxin <cjxin@yakpanel.com>
|
||||
# -------------------------------------------------------------------
|
||||
|
||||
# 备份
|
||||
# ------------------------------
|
||||
import os, sys, re, json, shutil, psutil, time
|
||||
import uuid
|
||||
from mod.project.push import taskMod
|
||||
|
||||
from sslModel.base import sslBase
|
||||
import public
|
||||
|
||||
|
||||
class main(sslBase):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
# self.__init_data()
|
||||
|
||||
|
||||
|
||||
def run_fun(self,get):
|
||||
"""
|
||||
@name 执行指定函数
|
||||
@param get.def_name 函数名
|
||||
@param get.dns_type dns类型
|
||||
"""
|
||||
|
||||
if 'fun_name' not in get:
|
||||
return public.returnMsg(False, public.lang('undefined fun_name'))
|
||||
|
||||
if not get.fun_name in ['delete_dns_record','create_dns_record','get_dns_record','update_dns_record','set_dns_record_status', 'get_domain_list']:
|
||||
return public.returnMsg(False,public.lang('wrong params,undefined func name'))
|
||||
|
||||
dns_type = False
|
||||
try:
|
||||
dns_data = self.get_dns_data(get)
|
||||
dns_type = dns_data[get.dns_id]['dns_type']
|
||||
except: pass
|
||||
if not dns_type:
|
||||
return public.returnMsg(False,public.lang('dns_id unknown'))
|
||||
get.dns_type = dns_type
|
||||
try:
|
||||
res = self.func_models(get, get.fun_name)
|
||||
return res
|
||||
except Exception as e:
|
||||
return public.returnMsg(False,public.lang('Execution failed:{}'.format(str(e))))
|
||||
|
||||
|
||||
def get_domain_list(self,get):
|
||||
"""
|
||||
@name 获取域名列表
|
||||
"""
|
||||
self.__init_data()
|
||||
|
||||
filter_sql = ''
|
||||
if get.get('search'):
|
||||
filter_sql += ' and domain like {}'.format("'%"+get.search+"%'")
|
||||
public.set_search_history('ssl', 'get_domain_list', get.search)
|
||||
if get.get('type_id'):
|
||||
filter_sql += " and type_id = '{}'".format(get.type_id)
|
||||
|
||||
p = 1
|
||||
if 'p' in get:
|
||||
p = int(get.p)
|
||||
collback = ''
|
||||
if 'collback' in get:
|
||||
collback = get.collback
|
||||
limit = 20
|
||||
if 'limit' in get:
|
||||
limit = int(get.limit)
|
||||
|
||||
count = public.M('ssl_domains').where('1=1 {}'.format(filter_sql), ()).count()
|
||||
page_data = public.get_page(count, p, limit, collback)
|
||||
|
||||
dns_data = self.get_dns_data(get)
|
||||
data = public.M('ssl_domains').field('id,domain,type_id,dns_id,endtime,ps').where('1=1 {}'.format(filter_sql), ()).limit(page_data['shift'] + ',' + page_data['row']).select()
|
||||
|
||||
record_data = self.get_record_data()
|
||||
|
||||
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"] == "domain_endtime" and i["status"]}
|
||||
|
||||
domain_list = []
|
||||
_data = []
|
||||
remove_ids = []
|
||||
for val in data:
|
||||
if val['domain'] in domain_list:
|
||||
remove_ids.append(str(val['id']))
|
||||
continue
|
||||
domain_list.append(val['domain'])
|
||||
val["report_id"] = report_data_dic.get(val['domain'], "") or ""
|
||||
|
||||
if val['dns_id'] == '0': val['dns_id'] = ''
|
||||
|
||||
val['dns'] = dns_data.get(val['dns_id'],{})
|
||||
# 获取子域名数量
|
||||
val['sbd_count'] = record_data.get(val["domain"], {}).get('info', {}).get('record_total', '-')
|
||||
_data.append(val)
|
||||
try:
|
||||
public.M('ssl_domains').where("id in ({})".format(",".join(remove_ids)), ()).delete()
|
||||
except Exception as e:
|
||||
print(e)
|
||||
|
||||
search_history = public.get_search_history('ssl', 'get_domain_list')
|
||||
page_data.update({'data': _data, 'search_history': search_history})
|
||||
public.set_module_logs('ssl', 'get_domain_list', 1)
|
||||
return page_data
|
||||
|
||||
|
||||
def set_domain_ps(self,get):
|
||||
"""
|
||||
@name 设置域名备注
|
||||
@param get.id 域名id
|
||||
@param get.ps 备注
|
||||
"""
|
||||
id = get.id
|
||||
ps = get.ps
|
||||
res = public.M('ssl_domains').where('id=?',(id,)).setField('ps',ps)
|
||||
if not res:
|
||||
return public.returnMsg(False,public.lang('Setting fail!'))
|
||||
return public.returnMsg(True,public.lang('setting succeed!'))
|
||||
|
||||
def set_domain_dns(self,get):
|
||||
"""
|
||||
@name 给域名设置dns
|
||||
@param get.ids 域名id [1,2,3]
|
||||
@param get.dns_id dns_id
|
||||
"""
|
||||
try:
|
||||
ids = json.loads(get.ids)
|
||||
except: pass
|
||||
|
||||
if not ids:
|
||||
return public.returnMsg(False,public.lang('Please select the domain name you want to set!'))
|
||||
|
||||
dns_id = get.dns_id
|
||||
dns_data = self.get_dns_data(get)
|
||||
if dns_id not in dns_data:
|
||||
return public.returnMsg(False,public.lang('The specified DNS does not exist!'))
|
||||
|
||||
params = []
|
||||
for id in ids:
|
||||
params.append((dns_id,id))
|
||||
|
||||
res = public.M('ssl_domains').executemany('update ssl_domains set dns_id=? where id=?',params)
|
||||
if type(res) != int:
|
||||
return public.returnMsg(False,public.lang('setting fail!'))
|
||||
|
||||
return public.returnMsg(True,public.lang('The setting was successful, and {} records have been updated!'.format(res)))
|
||||
|
||||
def set_domain_endtime(self,get):
|
||||
"""
|
||||
@name 设置域名到期时间
|
||||
@param get.ids 域名id [1,2,3]
|
||||
@param get.endtime 到期时间
|
||||
"""
|
||||
try:
|
||||
ids = json.loads(get.ids)
|
||||
except: pass
|
||||
|
||||
if not ids:
|
||||
return public.returnMsg(False,public.lang('Please select the domain name you want to set!'))
|
||||
|
||||
endtime = get.endtime
|
||||
params = []
|
||||
for id in ids:
|
||||
params.append((endtime,id))
|
||||
|
||||
res = public.M('ssl_domains').executemany('update ssl_domains set endtime=? where id=?',params)
|
||||
if type(res) != int:
|
||||
return public.returnMsg(False,public.lang('setting fail!'))
|
||||
|
||||
return public.returnMsg(True,public.lang('The setting was successful, and {} records have been updated!'.format(res)))
|
||||
|
||||
def set_domain_type(self,get):
|
||||
"""
|
||||
@设置域名到期时间
|
||||
@param get.ids 域名id [1,2,3]
|
||||
@param get.type_id 类型id
|
||||
"""
|
||||
try:
|
||||
ids = json.loads(get.ids)
|
||||
except: pass
|
||||
|
||||
if not ids:
|
||||
return public.returnMsg(False,public.lang('Please select the domain name you want to set!'))
|
||||
|
||||
type_id = get.type_id
|
||||
params = []
|
||||
for id in ids:
|
||||
params.append((type_id,id))
|
||||
|
||||
res = public.M('ssl_domains').executemany('update ssl_domains set type_id=? where id=?',params)
|
||||
if type(res) != int:
|
||||
return public.returnMsg(False,'setting fail!')
|
||||
|
||||
return public.returnMsg(True,public.lang('The setting was successful, and {} records have been updated!'.format(res)))
|
||||
|
||||
|
||||
def get_domain_type(self,get):
|
||||
"""
|
||||
@name 获取域名类型
|
||||
"""
|
||||
data = [{'type_id': 0, 'name': 'default'}]
|
||||
try:
|
||||
sfile = '{}/data/domains_type.json'.format(public.get_panel_path())
|
||||
data.extend(json.loads(public.readFile(sfile)))
|
||||
except:pass
|
||||
|
||||
return data
|
||||
|
||||
def add_domain_type(self,get):
|
||||
"""
|
||||
@name 添加域名分类
|
||||
@param get.name 分类名称
|
||||
@param get.type_id 分类类型
|
||||
|
||||
"""
|
||||
sfile = '{}/data/domains_type.json'.format(public.get_panel_path())
|
||||
try:
|
||||
data = json.loads(public.readFile(sfile))
|
||||
except:
|
||||
data = []
|
||||
type_id = str(uuid.uuid4().hex)
|
||||
if 'type_id' in get:
|
||||
type_id = get.type_id
|
||||
for i in data:
|
||||
if get.name == i["name"] or get.name == 'default':
|
||||
return public.returnMsg(False, public.lang('This type already exists.'))
|
||||
|
||||
data.append({'name':get.name,'type_id':type_id})
|
||||
public.writeFile(sfile,json.dumps(data))
|
||||
return public.returnMsg(True,public.lang('add successfully!'))
|
||||
|
||||
def del_domain_type(self, get):
|
||||
sfile = '{}/data/domains_type.json'.format(public.get_panel_path())
|
||||
try:
|
||||
data = json.loads(public.readFile(sfile))
|
||||
i = 0
|
||||
while i < len(data):
|
||||
if data[i]["type_id"] == get.type_id:
|
||||
del data[i]
|
||||
break
|
||||
i += 1
|
||||
public.writeFile(sfile, json.dumps(data))
|
||||
return public.returnMsg(True, public.lang('del successful'))
|
||||
except:
|
||||
return public.returnMsg(True, public.lang('del fail'))
|
||||
|
||||
|
||||
def __init_data(self):
|
||||
"""
|
||||
@name 同步数据
|
||||
"""
|
||||
# 检查表是否存在
|
||||
self.__create_table()
|
||||
|
||||
# 根据文件修改时间判断是否要同步
|
||||
check_path = "/www/server/panel/data/sync_domains.pl"
|
||||
m_time = str(os.stat("/www/server/panel/data/db/site.db").st_mtime)
|
||||
check_path_docker = "/www/server/panel/data/sync_domains_docker.pl"
|
||||
m_time_docker = str(os.stat("/www/server/panel/data/db/docker.db").st_mtime)
|
||||
if os.path.exists(check_path) and os.path.exists(check_path_docker):
|
||||
if m_time == public.readFile(check_path) and m_time_docker == public.readFile(check_path_docker):
|
||||
return
|
||||
public.writeFile(check_path, m_time)
|
||||
public.writeFile(check_path_docker, m_time)
|
||||
|
||||
# 获取手动删除的域名
|
||||
del_path = '{}/config/del_domains.pl'.format(public.get_panel_path())
|
||||
try:
|
||||
skip_domains = json.loads(public.readFile(del_path))
|
||||
except:
|
||||
skip_domains = []
|
||||
|
||||
root_domains = {i['domain'] for i in public.M('ssl_domains').field('domain').select()}
|
||||
site_domains = {self.extract_zone(i['name'])[0] for i in public.M('domain').field('name').select()}
|
||||
docker_site_domains = {self.extract_zone(i['name'])[0] for i in public.M('docker_domain').field('name').select()}
|
||||
add_domains = (site_domains | docker_site_domains) - root_domains - set(skip_domains)
|
||||
# del_domains = root_domains - (docker_site_domains | site_domains)
|
||||
|
||||
# 添加域名
|
||||
for domain in add_domains:
|
||||
public.M('ssl_domains').add('domain,dns_id,type_id,endtime,ps', (domain, 0, 0, 0, ''))
|
||||
|
||||
# 删除域名
|
||||
# for domain in del_domains:
|
||||
# public.M('ssl_domains').where("domain=?", (domain,)).delete()
|
||||
|
||||
def del_domains(self, get):
|
||||
"""
|
||||
@name 删除域名
|
||||
@param get.domains 域名列表,以逗号分隔
|
||||
"""
|
||||
domains = get.domains.split(',')
|
||||
try:
|
||||
public.M('ssl_domains').where("domain in ('{}')".format("','".join(domains)), ()).delete()
|
||||
path = '{}/config/del_domains.pl'.format(public.get_panel_path())
|
||||
try:
|
||||
del_domains = json.loads(public.readFile(path))
|
||||
del_domains.extend(domains)
|
||||
public.writeFile(path, json.dumps(del_domains))
|
||||
except:
|
||||
public.writeFile(path, json.dumps(domains))
|
||||
return public.returnMsg(True, public.lang('del successfully'))
|
||||
except:
|
||||
return public.returnMsg(False, public.lang('del fail'))
|
||||
|
||||
# 手动同步域名
|
||||
def sync_domains(self, get):
|
||||
"""
|
||||
@name 手动同步域名
|
||||
"""
|
||||
root_domains = {i['domain'] for i in public.M('ssl_domains').field('domain').select()}
|
||||
site_domains = {self.extract_zone(i['name'])[0] for i in public.M('domain').field('name').select()}
|
||||
docker_site_domains = {self.extract_zone(i['name'])[0] for i in public.M('docker_domain').field('name').select()}
|
||||
add_domains = (site_domains | docker_site_domains) - root_domains
|
||||
del_domains = root_domains - (docker_site_domains | site_domains)
|
||||
|
||||
# 添加域名
|
||||
for domain in add_domains:
|
||||
public.M('ssl_domains').add('domain,dns_id,type_id,endtime,ps', (domain, 0, 0, 0, ''))
|
||||
# 删除域名
|
||||
for domain in del_domains:
|
||||
public.M('ssl_domains').where("domain=?", (domain,)).delete()
|
||||
# 删除文件
|
||||
try:
|
||||
os.remove('{}/config/del_domains.pl'.format(public.get_panel_path()))
|
||||
except: pass
|
||||
return public.returnMsg(True, public.lang('Sync successful.'))
|
||||
|
||||
|
||||
def __create_table(self):
|
||||
"""
|
||||
@name 检查表是否存在
|
||||
"""
|
||||
public.check_table('ssl_domains',"""CREATE TABLE IF NOT EXISTS `ssl_domains` (
|
||||
`id` INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
`domain` TEXT,
|
||||
`dns_id` TEXT,
|
||||
`type_id` INTEGER,
|
||||
`endtime` INTEGER,
|
||||
`ps` TEXT
|
||||
)
|
||||
""")
|
||||
|
||||
def get_objectModel(self):
|
||||
'''
|
||||
获取模型对象
|
||||
'''
|
||||
from panelController import Controller
|
||||
project_obj = Controller()
|
||||
|
||||
return project_obj
|
||||
|
||||
|
||||
def func_models(self,get,def_name):
|
||||
'''
|
||||
获取模型对象
|
||||
'''
|
||||
|
||||
if 'dns_type' not in get:
|
||||
raise Exception(public.lang('undefined dns_type'))
|
||||
|
||||
sfile = '{}/class/sslModel/{}Model.py'.format(public.get_panel_path(),get.dns_type)
|
||||
if not os.path.exists(sfile):
|
||||
raise Exception(public.lang('The module file {} does not exist.'.format(sfile)))
|
||||
obj_main = self.get_objectModel()
|
||||
|
||||
args = public.dict_obj()
|
||||
args['data'] = get
|
||||
args['mod_name'] = get.dns_type
|
||||
args['def_name'] = def_name
|
||||
|
||||
return obj_main.model(args)
|
||||
|
||||
def get_domain_dns_config(self, get):
|
||||
self.__init_data()
|
||||
|
||||
dns_data = self.get_dns_data(get)
|
||||
root_data = public.M('ssl_domains').field('id,domain,dns_id').select()
|
||||
where_sql = '1=1'
|
||||
param = []
|
||||
if 'site_id' in get:
|
||||
where_sql += " AND pid in ({})".format(get.site_id)
|
||||
# param.append("({})".format(get.site_id))
|
||||
if 'domain_name' in get:
|
||||
where_sql += " AND name like ?"
|
||||
param.append('%{}%'.format(get.domain_name))
|
||||
data = public.M('domain').where(where_sql, param).field('name,pid as site_id').select() + public.M('docker_domain').where(where_sql, param).field('name,pid as site_id').select()
|
||||
for i in data:
|
||||
root, sub_domain, _ = self.extract_zone(i['name'])
|
||||
i["status"] = 0
|
||||
i["domain_id"] = -1
|
||||
for j in root_data:
|
||||
if j['domain'] == root:
|
||||
i["domain_id"] = j["id"]
|
||||
i["status"] = 1 if j["dns_id"] in dns_data.keys() else 0
|
||||
break
|
||||
if 'auto_wildcard' in get and get.auto_wildcard == '1':
|
||||
new_data = []
|
||||
for i in data:
|
||||
root, _, _ = self.extract_zone(i['name'])
|
||||
# 创建新对象以避免修改原数据
|
||||
new_item = i.copy()
|
||||
new_item['name'] = root
|
||||
if new_item not in new_data:
|
||||
new_data.append(new_item)
|
||||
|
||||
# 处理通配符域名
|
||||
wildcard_item = new_item.copy()
|
||||
wildcard_item['name'] = "*." + root
|
||||
if wildcard_item not in new_data:
|
||||
new_data.append(wildcard_item)
|
||||
data = new_data
|
||||
return data
|
||||
|
||||
def get_site_list(self, get):
|
||||
return public.M('sites').field('name,id').select() + public.M('docker_sites').field('name,id').select()
|
||||
|
||||
def create_report_task(self, get):
|
||||
from mod.base.push_mod import manager
|
||||
|
||||
sender_lsit = get.sender.split(",")
|
||||
task_data = {"task_data":{"tid":"70","type":"domain_endtime","title":"Domain name expiration","status":True,"count":0,"interval":600,"project":get.domain,"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 = "70"
|
||||
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 add_dns_value_by_domain(self, domain, dns_value, record_type="TXT", is_let_txt=False):
|
||||
root, _, subd = self.extract_zone(domain, is_let_txt)
|
||||
domain_name = subd+'.'+root if is_let_txt else domain
|
||||
try:
|
||||
data = public.M('ssl_domains').field('dns_id').where("domain=?", (root,)).select()
|
||||
dns_id = data[0]['dns_id']
|
||||
except:
|
||||
dns_id = ''
|
||||
for dns_config in self.get_dns_data(public.dict_obj()).values():
|
||||
if root in dns_config.get("domains", []) or str(dns_id) == dns_config["id"]:
|
||||
args = {
|
||||
"fun_name": "create_dns_record",
|
||||
"dns_id": dns_id,
|
||||
"domain_dns_value": dns_value,
|
||||
"record_type": record_type,
|
||||
"domain_name": domain_name,
|
||||
}
|
||||
_return = self.run_fun(public.to_dict_obj(args))
|
||||
if not _return["status"] and '记录已存在' not in _return["msg"]:
|
||||
raise Exception(public.lang("Failed to set the DNS record:{}".format(_return["msg"])))
|
||||
else:
|
||||
return _return
|
||||
raise Exception(public.lang("No valid DNS API key information was found for the domain name {}.".format(domain)))
|
||||
|
||||
def get_dns_value_by_domain(self, domain, record_type="TXT", is_let_txt=False):
|
||||
root, _, subd = self.extract_zone(domain, is_let_txt)
|
||||
domain_name = subd + '.' + root if is_let_txt else domain
|
||||
try:
|
||||
data = public.M('ssl_domains').field('dns_id').where("domain=?", (root,)).select()
|
||||
dns_id = data[0]['dns_id']
|
||||
except:
|
||||
dns_id = ''
|
||||
for dns_config in self.get_dns_data(public.dict_obj()).values():
|
||||
if root in dns_config.get("domains", []) or str(dns_id) == dns_config["id"]:
|
||||
args = {
|
||||
"fun_name": "get_dns_record",
|
||||
"dns_id": dns_id,
|
||||
"domain_name": domain,
|
||||
}
|
||||
record_data = self.run_fun(public.to_dict_obj(args))
|
||||
_return = []
|
||||
for record in record_data.get("list", []):
|
||||
if record["type"] == record_type and record["name"] == domain_name:
|
||||
_return.append(record["RecordId"])
|
||||
return _return, dns_id
|
||||
return [], ""
|
||||
|
||||
def del_dns_value_by_domain(self, domain, record_type="TXT", is_let_txt=False):
|
||||
ids, dns_id = self.get_dns_value_by_domain(domain, record_type, is_let_txt)
|
||||
for record_id in ids:
|
||||
args = {
|
||||
"fun_name": "delete_dns_record",
|
||||
"dns_id": dns_id,
|
||||
"RecordId": record_id,
|
||||
"domain_name": domain,
|
||||
}
|
||||
_return = self.run_fun(public.to_dict_obj(args))
|
||||
if not _return["status"]:
|
||||
raise Exception(public.lang("Failed to delete the DNS record:{}".format(_return["msg"])))
|
||||
|
||||
def get_sub_domains(self, get):
|
||||
import socket
|
||||
root_domain = get.root_domain
|
||||
domains = public.M('domain').where("name like ?", ('%'+root_domain,)).field('name,pid').select()
|
||||
for domain in domains:
|
||||
site_data = public.M('sites').where("id = ?", (domain['pid'],)).find()
|
||||
domain.update({"site_name": site_data['name']})
|
||||
domain.update({"record_a": socket.gethostbyname(domain['name'])})
|
||||
return domains
|
||||
|
||||
def add_domain(self, get):
|
||||
domain_name = get.domain_name
|
||||
dns_id = get.dns_id
|
||||
data = public.M('ssl_domains').field('id').where("domain=?", (domain_name,)).select()
|
||||
if data:
|
||||
return public.returnMsg(False, public.lang('The domain name already exists.'))
|
||||
public.M('ssl_domains').add('domain,dns_id,type_id,endtime,ps', (domain_name, dns_id, 0, 0, ''))
|
||||
return public.returnMsg(True, public.lang('add success'))
|
||||
|
||||
|
||||
176
class/sslModel/dnsapiModel.py
Normal file
176
class/sslModel/dnsapiModel.py
Normal file
@@ -0,0 +1,176 @@
|
||||
import json
|
||||
import os
|
||||
import uuid
|
||||
|
||||
import public
|
||||
from sslModel.base import sslBase
|
||||
|
||||
|
||||
class main(sslBase):
|
||||
def dns_support_info(self):
|
||||
# aa dns 支持的品牌, 及其默认值
|
||||
data = [
|
||||
{
|
||||
"name": "dns",
|
||||
"title": "Manual resolution",
|
||||
"ps": "Returns the host and txt values, which are manually parsed by the user",
|
||||
"data": False
|
||||
},
|
||||
{
|
||||
"name": "CloudFlareDns",
|
||||
"title": "CloudFlare",
|
||||
"data": [
|
||||
{
|
||||
"key": "SAVED_CF_MAIL",
|
||||
"name": "E-Mail",
|
||||
"value": "",
|
||||
},
|
||||
{
|
||||
"key": "SAVED_CF_KEY",
|
||||
"name": "API Key",
|
||||
"value": "",
|
||||
}
|
||||
],
|
||||
"help": "How to get API Token",
|
||||
"ps": "Use CloudFlare's API interface to automatically parse and apply for SSL",
|
||||
},
|
||||
{
|
||||
"name": "CloudxnsDns",
|
||||
"title": "CloudXns",
|
||||
"data": [
|
||||
{
|
||||
"key": "SAVED_CX_Key",
|
||||
"name": "AccessKey",
|
||||
"value": ""
|
||||
},
|
||||
{
|
||||
"key": "SAVED_CX_Secret",
|
||||
"name": "SecretKey",
|
||||
"value": ""
|
||||
}
|
||||
],
|
||||
"ps": "Automatically resolve application SSL using cloudxns API interface",
|
||||
"help": "CloudxnsBackground > User Center > API Management, follow the instructions to get AccessKey/SecretKey",
|
||||
},
|
||||
{
|
||||
"name": "NameCheapDns",
|
||||
"title": "NameCheap",
|
||||
"data": [
|
||||
{
|
||||
"key": "SAVED_NC_ACCOUNT",
|
||||
"name": "Account",
|
||||
"value": ""
|
||||
},
|
||||
{
|
||||
"key": "SAVED_CX_APIKEY",
|
||||
"name": "ApiKey",
|
||||
"value": ""
|
||||
}
|
||||
],
|
||||
"ps": "Use NameCheap's API interface to automatically parse and apply for SSL",
|
||||
"help": "Namecheap API needs added in Whitelisted IPs (only IPv4): "
|
||||
"Profile > Tools menu > Namecheap API Access > Whitelisted IPs, "
|
||||
"please check: https://www.namecheap.com/support/api/intro/",
|
||||
},
|
||||
# godaddy pro 环境需要账号里50个域名以上方可调用
|
||||
]
|
||||
return data
|
||||
|
||||
def get_dnsapi_add_data(self):
|
||||
data = [
|
||||
{
|
||||
'name': 'DNSPod',
|
||||
'id': 'DNSPodDns',
|
||||
'params': ['ID', 'Token']
|
||||
},
|
||||
{
|
||||
'name': '阿里云DNS',
|
||||
'id': 'AliyunDns',
|
||||
'params': ['AccessKey', 'SecretKey']
|
||||
},
|
||||
{
|
||||
'name': '腾讯云DNS',
|
||||
'id': 'TencentCloudDns',
|
||||
'params': ['secret_id', 'secret_key']
|
||||
},
|
||||
{
|
||||
'name': '华为云DNS',
|
||||
'id': 'HuaweiCloudDns',
|
||||
'params': ['AccessKey', 'SecretKey', 'project_id']
|
||||
},
|
||||
{
|
||||
'name': 'CloudFlare',
|
||||
'id': 'CloudFlareDns',
|
||||
'params': ['E-Mail', 'API Key']
|
||||
},
|
||||
{
|
||||
'name': '西部数码',
|
||||
'id': 'WestDns',
|
||||
'params': ['user_name', 'api_password']
|
||||
},
|
||||
# godaddy接口访问不了,先注释
|
||||
# {
|
||||
# 'name': 'GoDaddy',
|
||||
# 'id': 'GoDaddyDns',
|
||||
# 'params': ['Key', 'Secret']
|
||||
# },
|
||||
]
|
||||
return data
|
||||
|
||||
def get_dns_data(self, get):
|
||||
api_data = super().get_dns_data(get)
|
||||
add_data = self.get_dnsapi_add_data()
|
||||
return {"data": [i for i in api_data.values()], "add_data": add_data}
|
||||
|
||||
def add_dns_data(self, get):
|
||||
dns_name = get.dns_name
|
||||
ps = get.ps
|
||||
pdata = json.loads(get.pdata)
|
||||
|
||||
if dns_name not in [i['id'] for i in self.get_dnsapi_add_data()]:
|
||||
return public.returnMsg(False, "暂不支持此类型")
|
||||
|
||||
pdata.update({'id': uuid.uuid4().hex, 'ps': ps})
|
||||
|
||||
data = {}
|
||||
sfile = "{}/config/dns_mager.conf".format(public.get_panel_path())
|
||||
if os.path.exists(sfile):
|
||||
data = json.loads(public.readFile(sfile))
|
||||
type_data = data.get(dns_name)
|
||||
if type_data:
|
||||
type_data.append(pdata)
|
||||
else:
|
||||
type_data = [pdata]
|
||||
data[dns_name] = type_data
|
||||
public.writeFile(sfile, json.dumps(data))
|
||||
return public.returnMsg(True, "添加成功")
|
||||
|
||||
def del_dns_data(self, get):
|
||||
dns_id = get.dns_id
|
||||
|
||||
sfile = "{}/config/dns_mager.conf".format(public.get_panel_path())
|
||||
data = json.loads(public.readFile(sfile))
|
||||
|
||||
for key in data.keys():
|
||||
for val in data[key]:
|
||||
if val['id'] == dns_id:
|
||||
data[key].remove(val)
|
||||
public.writeFile(sfile, json.dumps(data))
|
||||
return public.returnMsg(True, "删除成功")
|
||||
|
||||
def upd_dns_data(self, get):
|
||||
dns_id = get.dns_id
|
||||
ps = get.ps
|
||||
pdata = {}
|
||||
if 'pdata' in get:
|
||||
pdata = json.loads(get.pdata)
|
||||
pdata.update({'ps': ps})
|
||||
sfile = "{}/config/dns_mager.conf".format(public.get_panel_path())
|
||||
data = json.loads(public.readFile(sfile))
|
||||
|
||||
for key in data.keys():
|
||||
for val in data[key]:
|
||||
if val['id'] == dns_id:
|
||||
val.update(pdata)
|
||||
public.writeFile(sfile, json.dumps(data))
|
||||
return public.returnMsg(True, "修改成功")
|
||||
181
class/sslModel/dnspodModel.py
Normal file
181
class/sslModel/dnspodModel.py
Normal file
@@ -0,0 +1,181 @@
|
||||
from sslModel.base import sslBase
|
||||
import requests
|
||||
from urllib.parse import urlparse
|
||||
from urllib.parse import urljoin
|
||||
import public
|
||||
|
||||
class main(sslBase):
|
||||
dns_provider_name = "dnspod"
|
||||
_type = 0 # 0:lest 1:锐成
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
def __init_data(self,data):
|
||||
|
||||
self.DNSPOD_ID = data['ID']
|
||||
self.DNSPOD_API_KEY = data['Token']
|
||||
self.DNSPOD_API_BASE_URL = 'https://dnsapi.cn/'
|
||||
self.HTTP_TIMEOUT = 65 # seconds
|
||||
self.DNSPOD_LOGIN = "{0},{1}".format(self.DNSPOD_ID, self.DNSPOD_API_KEY)
|
||||
|
||||
def create_dns_record(self,get):
|
||||
"""
|
||||
@name 创建dns记录
|
||||
@param get.dns_id dns_id
|
||||
@param get.domain_name 域名
|
||||
@param get.domain_dns_value 域名解析值
|
||||
"""
|
||||
dns_id = get.dns_id
|
||||
domain_name = get.domain_name
|
||||
domain_dns_value = get.domain_dns_value
|
||||
record_type = 'TXT'
|
||||
if 'record_type' in get:
|
||||
record_type = get.record_type
|
||||
|
||||
self.__init_data(self.get_dns_data(None)[dns_id])
|
||||
domain_name, subd, _ = self.extract_zone(domain_name)
|
||||
|
||||
return self.add_record(domain_name, subd, domain_dns_value, record_type)
|
||||
|
||||
def delete_dns_record(self,get):
|
||||
"""
|
||||
@name 删除dns记录
|
||||
@param get.dns_id dns_id
|
||||
@param get.domain_name 域名
|
||||
"""
|
||||
dns_id = get.dns_id
|
||||
domain_name = get.domain_name
|
||||
RecordId = get.RecordId
|
||||
|
||||
self.__init_data(self.get_dns_data(None)[dns_id])
|
||||
|
||||
try:
|
||||
domain_name, subd, _ = self.extract_zone(domain_name)
|
||||
res = self.remove_record(domain_name, RecordId)
|
||||
if res["status"]["code"] != '1':
|
||||
return public.returnMsg(False, res["status"]["message"])
|
||||
except Exception as e:
|
||||
return public.returnMsg(False, e)
|
||||
|
||||
return public.returnMsg(True, '删除成功')
|
||||
|
||||
def get_dns_record(self,get):
|
||||
"""
|
||||
@name 获取dns记录
|
||||
@param get.dns_id dns_id
|
||||
@param get.domain_name 域名
|
||||
@return json
|
||||
"""
|
||||
dns_id = get.dns_id
|
||||
domain_name = get.domain_name
|
||||
|
||||
self.__init_data(self.get_dns_data(None)[dns_id])
|
||||
|
||||
domain_name, _, subd = self.extract_zone(domain_name)
|
||||
|
||||
url = urljoin(self.DNSPOD_API_BASE_URL, "Record.List")
|
||||
rootdomain = domain_name
|
||||
body = {
|
||||
"login_token": self.DNSPOD_LOGIN,
|
||||
"format": "json",
|
||||
"domain": rootdomain,
|
||||
}
|
||||
|
||||
try:
|
||||
list_dns_response = requests.post(url, data=body, timeout=self.HTTP_TIMEOUT).json()
|
||||
except:
|
||||
list_dns_response = {}
|
||||
data = {}
|
||||
if list_dns_response.get("status", {}).get("code") == "10":
|
||||
data = {"info": {'record_total': 0}, "list": []}
|
||||
if 'records' in list_dns_response:
|
||||
for i in list_dns_response['records']:
|
||||
i['name'] = i['name'] + "." + domain_name if i['name'] != '@' else domain_name
|
||||
i['RecordId'] = i['id']
|
||||
i["status"] = "启用" if i["status"] == "enable" else "暂停" if i["status"] == "disable" else i["status"]
|
||||
data['list'] = list_dns_response['records']
|
||||
if 'info' in list_dns_response:
|
||||
data['info'] = list_dns_response['info']
|
||||
if not data:
|
||||
data = list_dns_response
|
||||
self.set_record_data({domain_name: data})
|
||||
return data
|
||||
|
||||
def add_record(self, domain_name, subd, domain_dns_value, s_type):
|
||||
"""
|
||||
@name 添加记录
|
||||
@param domain_name 域名
|
||||
@param subd 子域名
|
||||
@param domain_dns_value 解析值
|
||||
@param s_type 记录类型
|
||||
"""
|
||||
url = urljoin(self.DNSPOD_API_BASE_URL, "Record.Create")
|
||||
body = {
|
||||
"record_type": s_type,
|
||||
"domain": domain_name,
|
||||
"sub_domain": subd,
|
||||
"value": domain_dns_value,
|
||||
"record_line_id": "0",
|
||||
"format": "json",
|
||||
"login_token": self.DNSPOD_LOGIN,
|
||||
}
|
||||
create_dnspod_dns_record_response = requests.post(
|
||||
url, data=body, timeout=self.HTTP_TIMEOUT
|
||||
).json()
|
||||
if create_dnspod_dns_record_response["status"]["code"] != "1":
|
||||
raise ValueError(
|
||||
"Error creating dnspod dns record: status_code={status_code} response={response}".format(
|
||||
status_code=create_dnspod_dns_record_response["status"]["code"],
|
||||
response=create_dnspod_dns_record_response["status"]["message"],
|
||||
)
|
||||
)
|
||||
return public.returnMsg(True, '添加成功')
|
||||
|
||||
def remove_record(self, domain_name, RecordId):
|
||||
rootdomain = domain_name
|
||||
|
||||
urlr = urljoin(self.DNSPOD_API_BASE_URL, "Record.Remove")
|
||||
bodyr = {
|
||||
"login_token": self.DNSPOD_LOGIN,
|
||||
"format": "json",
|
||||
"domain": rootdomain,
|
||||
"record_id": RecordId,
|
||||
}
|
||||
return requests.post(
|
||||
urlr, data=bodyr, timeout=self.HTTP_TIMEOUT
|
||||
).json()
|
||||
|
||||
def add_record_for_creat_site(self, domain, server_ip):
|
||||
domain_name, zone, _ = self.extract_zone(domain)
|
||||
self.add_record(domain_name, zone, server_ip, "A")
|
||||
|
||||
def update_dns_record(self, get):
|
||||
domain_name = get.domain_name
|
||||
|
||||
domain_name, subd, _ = self.extract_zone(domain_name)
|
||||
|
||||
self.__init_data(self.get_dns_data(None)[get.dns_id])
|
||||
|
||||
url = urljoin(self.DNSPOD_API_BASE_URL, "Record.Modify")
|
||||
|
||||
body = {
|
||||
"login_token": self.DNSPOD_LOGIN,
|
||||
"domain": domain_name,
|
||||
"record_id": get.RecordId,
|
||||
"sub_domain": subd,
|
||||
"record_type": get.record_type,
|
||||
"record_line": get.RecordLine,
|
||||
"value": get.domain_dns_value,
|
||||
"mx ": get.mx,
|
||||
}
|
||||
try:
|
||||
res = requests.post(
|
||||
url, data=body, timeout=self.HTTP_TIMEOUT
|
||||
).json()
|
||||
if res["status"]["code"] != '1':
|
||||
return public.returnMsg(False, res["status"]["message"])
|
||||
|
||||
return public.returnMsg(True, "修改成功")
|
||||
except Exception as e:
|
||||
return public.returnMsg(False, "操作失败:{}".format(e))
|
||||
108
class/sslModel/godaddyModel.py
Normal file
108
class/sslModel/godaddyModel.py
Normal file
@@ -0,0 +1,108 @@
|
||||
from sslModel.base import sslBase
|
||||
import requests
|
||||
from urllib.parse import urlparse
|
||||
from urllib.parse import urljoin
|
||||
import public
|
||||
|
||||
|
||||
class main(sslBase):
|
||||
dns_provider_name = "godaddy"
|
||||
_type = 0 # 0:lest 1:锐成
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
def __init_data(self, data):
|
||||
self.key = data['Key']
|
||||
self.secret = data['Secret']
|
||||
self.base_url = 'https://api.godaddy.com'
|
||||
self.timeout = 65
|
||||
|
||||
self.headers = {
|
||||
"Authorization": "sso-key {}:{}".format(self.key, self.secret)
|
||||
}
|
||||
|
||||
def create_dns_record(self, get):
|
||||
dns_id = get.dns_id
|
||||
domain_name = get.domain_name
|
||||
domain_dns_value = get.domain_dns_value
|
||||
|
||||
self.__init_data(self.get_dns_data(None)[dns_id])
|
||||
|
||||
root_domain, sub_domain, _ = self.extract_zone(domain_name)
|
||||
|
||||
body = [
|
||||
{
|
||||
"data": domain_dns_value,
|
||||
"name": sub_domain or '@',
|
||||
"type": "TXT" if 'record_type' not in get else get.record_type,
|
||||
}
|
||||
]
|
||||
url = urljoin(self.base_url, "/v1/domains/{}/records".format(root_domain))
|
||||
try:
|
||||
response = requests.patch(
|
||||
url, headers=self.headers, json=body, timeout=self.timeout,
|
||||
)
|
||||
if response.status_code == 200:
|
||||
return public.returnMsg(False, '添加成功')
|
||||
else:
|
||||
return public.returnMsg(False, '添加失败,{}'.format(response.json()))
|
||||
except Exception as e:
|
||||
return public.returnMsg(False, '添加失败,msg:{}'.format(e))
|
||||
|
||||
def get_dns_record(self, get):
|
||||
dns_id = get.dns_id
|
||||
domain_name = get.domain_name
|
||||
|
||||
root_domain, _, sub_domain = self.extract_zone(domain_name)
|
||||
|
||||
self.__init_data(self.get_dns_data(None)[dns_id])
|
||||
url = urljoin(self.base_url, "/v1/domains/{}/records".format(root_domain))
|
||||
data = {}
|
||||
try:
|
||||
response = requests.get(
|
||||
url, headers=self.headers, timeout=self.timeout,
|
||||
)
|
||||
json_data = response.json()
|
||||
data["list"] = [
|
||||
{
|
||||
"name": i["name"] + "." + root_domain if i["name"] != '@' else root_domain,
|
||||
"ttl": i["ttl"],
|
||||
"type": i["type"],
|
||||
"value": i["data"],
|
||||
"line": "",
|
||||
"status": "",
|
||||
"mx": i.get("priority") or 0,
|
||||
"updated_on": "",
|
||||
"remark": "",
|
||||
}
|
||||
for i in json_data
|
||||
]
|
||||
data["info"] = {
|
||||
"record_total": len(data["list"])
|
||||
}
|
||||
return data
|
||||
|
||||
except Exception as e:
|
||||
return data
|
||||
|
||||
def delete_dns_record(self, get):
|
||||
domain_name = get.domain_name
|
||||
dns_id = get.dns_id
|
||||
|
||||
root_domain, sub_domain, _ = self.extract_zone(domain_name)
|
||||
|
||||
self.__init_data(self.get_dns_data(None)[dns_id])
|
||||
|
||||
url = urljoin(self.base_url, "/v1/domains/{}/records/{}/{}".format(root_domain, 'TXT' if 'record_type' not in get else get.record_type, sub_domain))
|
||||
|
||||
try:
|
||||
response = requests.delete(
|
||||
url, headers=self.headers, timeout=self.timeout,
|
||||
)
|
||||
if response.status_code == 204:
|
||||
return public.returnMsg(True, '删除成功')
|
||||
else:
|
||||
return public.returnMsg(True, '删除失败,{}'.format(response.text))
|
||||
except Exception as e:
|
||||
return public.returnMsg(False, '删除失败,msg:{}'.format(e))
|
||||
338
class/sslModel/huaweicloudModel.py
Normal file
338
class/sslModel/huaweicloudModel.py
Normal file
@@ -0,0 +1,338 @@
|
||||
import json
|
||||
|
||||
from sslModel.base import sslBase
|
||||
|
||||
import public
|
||||
|
||||
import copy
|
||||
import sys
|
||||
import hashlib
|
||||
import hmac
|
||||
import binascii
|
||||
from datetime import datetime
|
||||
import requests
|
||||
|
||||
|
||||
class main(sslBase):
|
||||
dns_provider_name = "huaweicloud"
|
||||
_type = 0
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.region = "cn-south-1"
|
||||
self.BasicDateFormat = "%Y%m%dT%H%M%SZ"
|
||||
self.Algorithm = "SDK-HMAC-SHA256"
|
||||
self.HeaderXDate = "X-Sdk-Date"
|
||||
self.HeaderHost = "host"
|
||||
self.HeaderAuthorization = "Authorization"
|
||||
self.HeaderContentSha256 = "x-sdk-content-sha256"
|
||||
self.url = "https://dns.cn-north-1.myhuaweicloud.com"
|
||||
|
||||
def __init_data(self, data):
|
||||
self.ak = data["AccessKey"]
|
||||
self.sk = data["SecretKey"]
|
||||
self.project_id = data["project_id"]
|
||||
|
||||
def sign_to_response(self, dns_id, method="", url="", headers=None, body=""):
|
||||
url = self.url + url
|
||||
self.__init_data(self.get_dns_data(None)[dns_id])
|
||||
if sys.version_info.major < 3:
|
||||
body = body
|
||||
from urllib import quote, unquote
|
||||
|
||||
def hmacsha256(keyByte, message):
|
||||
return hmac.new(keyByte, message, digestmod=hashlib.sha256).digest()
|
||||
|
||||
# Create a "String to Sign".
|
||||
def StringToSign(canonicalRequest, t):
|
||||
bytes = HexEncodeSHA256Hash(canonicalRequest)
|
||||
return "%s\n%s\n%s" % (self.Algorithm, datetime.strftime(t, self.BasicDateFormat), bytes)
|
||||
|
||||
else:
|
||||
body = body.encode("utf-8")
|
||||
from urllib.parse import quote, unquote
|
||||
|
||||
def hmacsha256(keyByte, message):
|
||||
return hmac.new(keyByte.encode('utf-8'), message.encode('utf-8'), digestmod=hashlib.sha256).digest()
|
||||
|
||||
# Create a "String to Sign".
|
||||
def StringToSign(canonicalRequest, t):
|
||||
bytes = HexEncodeSHA256Hash(canonicalRequest.encode('utf-8'))
|
||||
return "%s\n%s\n%s" % (self.Algorithm, datetime.strftime(t, self.BasicDateFormat), bytes)
|
||||
|
||||
def HexEncodeSHA256Hash(data):
|
||||
sha256 = hashlib.sha256()
|
||||
sha256.update(data)
|
||||
return sha256.hexdigest()
|
||||
|
||||
def findHeader(headers, header):
|
||||
for k in headers:
|
||||
if k.lower() == header.lower():
|
||||
return headers[k]
|
||||
return None
|
||||
|
||||
def CanonicalQueryString(query):
|
||||
keys = []
|
||||
for key in query:
|
||||
keys.append(key)
|
||||
keys.sort()
|
||||
a = []
|
||||
for key in keys:
|
||||
k = quote(key, safe='~')
|
||||
value = query[key]
|
||||
if type(value) is list:
|
||||
value.sort()
|
||||
for v in value:
|
||||
kv = k + "=" + quote(str(v), safe='~')
|
||||
a.append(kv)
|
||||
else:
|
||||
kv = k + "=" + quote(str(value), safe='~')
|
||||
a.append(kv)
|
||||
return '&'.join(a)
|
||||
|
||||
def SignStringToSign(stringToSign, signingKey):
|
||||
hm = hmacsha256(signingKey, stringToSign)
|
||||
return binascii.hexlify(hm).decode()
|
||||
|
||||
def AuthHeaderValue(signature, AppKey, signedHeaders):
|
||||
return "%s Access=%s, SignedHeaders=%s, Signature=%s" % (
|
||||
self.Algorithm, AppKey, ";".join(signedHeaders), signature)
|
||||
|
||||
spl = url.split("://", 1)
|
||||
scheme = 'http'
|
||||
if len(spl) > 1:
|
||||
scheme = spl[0]
|
||||
url = spl[1]
|
||||
query = {}
|
||||
spl = url.split('?', 1)
|
||||
url = spl[0]
|
||||
if len(spl) > 1:
|
||||
for kv in spl[1].split("&"):
|
||||
spl = kv.split("=", 1)
|
||||
key = spl[0]
|
||||
value = ""
|
||||
if len(spl) > 1:
|
||||
value = spl[1]
|
||||
if key != '':
|
||||
key = unquote(key)
|
||||
value = unquote(value)
|
||||
if key in query:
|
||||
query[key].append(value)
|
||||
else:
|
||||
query[key] = [value]
|
||||
spl = url.split('/', 1)
|
||||
host = spl[0]
|
||||
if len(spl) > 1:
|
||||
url = '/' + spl[1]
|
||||
else:
|
||||
url = '/'
|
||||
if headers is None:
|
||||
headers = {"content-type": "application/json"}
|
||||
else:
|
||||
headers = copy.deepcopy(headers)
|
||||
|
||||
headerTime = findHeader(headers, self.HeaderXDate)
|
||||
|
||||
if headerTime is None:
|
||||
t = datetime.utcnow()
|
||||
headers[self.HeaderXDate] = datetime.strftime(t, self.BasicDateFormat)
|
||||
else:
|
||||
t = datetime.strptime(headerTime, self.BasicDateFormat)
|
||||
|
||||
haveHost = False
|
||||
for key in headers:
|
||||
if key.lower() == 'host':
|
||||
haveHost = True
|
||||
break
|
||||
if not haveHost:
|
||||
headers["host"] = host
|
||||
signedHeaders = []
|
||||
for key in headers:
|
||||
signedHeaders.append(key.lower())
|
||||
signedHeaders.sort()
|
||||
a = []
|
||||
__headers = {}
|
||||
for key in headers:
|
||||
keyEncoded = key.lower()
|
||||
value = headers[key]
|
||||
valueEncoded = value.strip()
|
||||
__headers[keyEncoded] = valueEncoded
|
||||
if sys.version_info.major == 3:
|
||||
headers[key] = valueEncoded.encode("utf-8").decode('iso-8859-1')
|
||||
for key in signedHeaders:
|
||||
a.append(key + ":" + __headers[key])
|
||||
canonicalHeaders = '\n'.join(a) + "\n"
|
||||
|
||||
hexencode = findHeader(headers, self.HeaderContentSha256)
|
||||
if hexencode is None:
|
||||
hexencode = HexEncodeSHA256Hash(body)
|
||||
pattens = unquote(url).split('/')
|
||||
CanonicalURI = []
|
||||
for v in pattens:
|
||||
CanonicalURI.append(quote(v, safe="~"))
|
||||
CanonicalURL = "/".join(CanonicalURI)
|
||||
if CanonicalURL[-1] != '/':
|
||||
CanonicalURL = CanonicalURL + "/" # always end with /
|
||||
|
||||
canonicalRequest = "%s\n%s\n%s\n%s\n%s\n%s" % (method.upper(), CanonicalURL, CanonicalQueryString(query),
|
||||
canonicalHeaders, ";".join(signedHeaders), hexencode)
|
||||
|
||||
stringToSign = StringToSign(canonicalRequest, t)
|
||||
signature = SignStringToSign(stringToSign, self.sk)
|
||||
authValue = AuthHeaderValue(signature, self.ak, signedHeaders)
|
||||
headers[self.HeaderAuthorization] = authValue
|
||||
headers["content-length"] = str(len(body))
|
||||
queryString = CanonicalQueryString(query)
|
||||
if queryString != "":
|
||||
url = url + "?" + queryString
|
||||
|
||||
res = requests.request(method, scheme + "://" + host + url, headers=headers, data=body)
|
||||
return res
|
||||
|
||||
def create_dns_record(self, get):
|
||||
domain_name = get.domain_name
|
||||
domain_dns_value = get.domain_dns_value
|
||||
record_type = 'TXT'
|
||||
if 'record_type' in get:
|
||||
record_type = get.record_type
|
||||
if record_type == 'TXT':
|
||||
domain_dns_value = "\"{}\"".format(domain_dns_value)
|
||||
|
||||
root_domain, sub_domain, _ = self.extract_zone(domain_name)
|
||||
if sub_domain == "@":
|
||||
domain_name = root_domain
|
||||
|
||||
try:
|
||||
zone_dic = self.get_zoneid_dict(get.dns_id)
|
||||
zone_id = zone_dic.get(root_domain)
|
||||
body = json.dumps({
|
||||
"name": domain_name,
|
||||
"type": record_type,
|
||||
"records": [domain_dns_value],
|
||||
})
|
||||
|
||||
res = self.sign_to_response(get.dns_id, "POST", "/v2/zones/{}/recordsets".format(zone_id), body=body)
|
||||
if res.status_code != 202:
|
||||
return public.returnMsg(False, self.get_error(res.text))
|
||||
|
||||
return public.returnMsg(True, '添加成功')
|
||||
except Exception as e:
|
||||
return public.returnMsg(False, self.get_error(str(e)))
|
||||
|
||||
def delete_dns_record(self, get):
|
||||
domain_name = get.domain_name
|
||||
RecordId = get.RecordId
|
||||
root_domain, _, sub_domain = self.extract_zone(domain_name)
|
||||
|
||||
zone_dic = self.get_zoneid_dict(get.dns_id)
|
||||
zone_id = zone_dic[root_domain]
|
||||
try:
|
||||
res = self.sign_to_response(get.dns_id, "DELETE", "/v2/zones/{}/recordsets/{}".format(zone_id, RecordId))
|
||||
if res.status_code != 202:
|
||||
return public.returnMsg(False, self.get_error(res.text))
|
||||
return public.returnMsg(True, '删除成功')
|
||||
except Exception as e:
|
||||
return public.returnMsg(False, self.get_error(str(e)))
|
||||
|
||||
def get_zoneid_dict(self, dns_id):
|
||||
"""
|
||||
获取所有域名对应id
|
||||
"""
|
||||
res = self.sign_to_response(dns_id, "GET", "/v2/zones")
|
||||
if res.status_code != 200:
|
||||
return {}
|
||||
response = res.json()
|
||||
data = {i["name"][:-1]: i["id"] for i in response["zones"]}
|
||||
|
||||
return data
|
||||
|
||||
def get_dns_record(self, get):
|
||||
domain_name = get.domain_name
|
||||
root_domain, _, sub_domain = self.extract_zone(domain_name)
|
||||
data = {}
|
||||
try:
|
||||
zone_dic = self.get_zoneid_dict(get.dns_id)
|
||||
limit = 100
|
||||
offset = 0
|
||||
zone_id = zone_dic[root_domain]
|
||||
res = self.sign_to_response(get.dns_id, "GET",
|
||||
"/v2/zones/{}/recordsets?limit={}&offset={}".format(zone_id, limit, offset))
|
||||
if res.status_code != 200:
|
||||
return {}
|
||||
response = res.json()
|
||||
|
||||
data["list"] = [
|
||||
{
|
||||
"RecordId": i["id"],
|
||||
"name": i["name"][:-1],
|
||||
"value": '\r\n'.join(i["records"]) if i["type"] != "TXT" else '\r\n'.join([j.replace('"', '') for j in i["records"]]),
|
||||
"line": "默认",
|
||||
"ttl": i["ttl"],
|
||||
"type": i["type"],
|
||||
"status": "启用"if i["status"] == "ACTIVE" else "暂停" if i["status"] == "DISABLE" else i["status"],
|
||||
"mx": "",
|
||||
"updated_on": i["update_at"],
|
||||
"remark": i.get("description") or "",
|
||||
}
|
||||
for i in response["recordsets"]
|
||||
]
|
||||
data["info"] = {
|
||||
'record_total': response['metadata']['total_count']
|
||||
}
|
||||
except Exception as e:
|
||||
pass
|
||||
self.set_record_data({root_domain: data})
|
||||
return data
|
||||
|
||||
def update_dns_record(self, get):
|
||||
domain_name = get.domain_name
|
||||
RecordId = get.RecordId
|
||||
record_type = get.record_type
|
||||
domain_dns_value = get.domain_dns_value
|
||||
root_domain, _, sub_domain = self.extract_zone(domain_name)
|
||||
|
||||
if sub_domain == "@":
|
||||
domain_name = root_domain
|
||||
if record_type == 'TXT':
|
||||
domain_dns_value = "\"{}\"".format(domain_dns_value)
|
||||
|
||||
zone_dic = self.get_zoneid_dict(get.dns_id)
|
||||
zone_id = zone_dic[root_domain]
|
||||
try:
|
||||
body = json.dumps({
|
||||
"name": domain_name,
|
||||
"type": record_type,
|
||||
"records": [domain_dns_value],
|
||||
})
|
||||
|
||||
res = self.sign_to_response(get.dns_id, "PUT", "/v2/zones/{}/recordsets/{}".format(zone_id, RecordId), body=body)
|
||||
if res.status_code != 202:
|
||||
return public.returnMsg(False, self.get_error(res.text))
|
||||
|
||||
return public.returnMsg(True, '修改成功')
|
||||
except Exception as e:
|
||||
return public.returnMsg(False, self.get_error(str(e)))
|
||||
|
||||
def get_error(self, error):
|
||||
if "DNS.0317" in error:
|
||||
return "此记录为系统默认域名记录值,不能删除。"
|
||||
elif "DNS.0318" in error:
|
||||
return "此记录为系统默认域名记录值,不能更新。"
|
||||
elif "DNS.0321" in error:
|
||||
return "子域名级别超过限制。"
|
||||
elif "DNS.0324" in error:
|
||||
return "系统默认解析记录不能操作。"
|
||||
elif "DNS.0308" in error:
|
||||
return "记录集类型非法。"
|
||||
elif "DNS.0307" in error:
|
||||
return "记录集的值非法。"
|
||||
elif "DNS.0302" in error:
|
||||
return "这个华为云账户下面不存在这个域名,请检查dns接口配置后重试"
|
||||
elif "APIGW.0301" in error:
|
||||
return "dns账号信息有误"
|
||||
elif "DNS.0312" in error:
|
||||
return "存在同名的主机记录"
|
||||
elif "DNS.0313" in error:
|
||||
return "不存在这条记录"
|
||||
else:
|
||||
return error
|
||||
194
class/sslModel/tencentcloudModel.py
Normal file
194
class/sslModel/tencentcloudModel.py
Normal file
@@ -0,0 +1,194 @@
|
||||
import hashlib
|
||||
import hmac
|
||||
import json
|
||||
import time
|
||||
from datetime import datetime
|
||||
|
||||
import public
|
||||
import requests
|
||||
from sslModel.base import sslBase
|
||||
|
||||
|
||||
class main(sslBase):
|
||||
dns_provider_name = "tencentcloud"
|
||||
_type = 0
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.endpoint = "dnspod.tencentcloudapi.com"
|
||||
self.host = "https://dnspod.tencentcloudapi.com"
|
||||
self.version = "2021-03-23"
|
||||
self.algorithm = "TC3-HMAC-SHA256"
|
||||
|
||||
def __init_data(self, data):
|
||||
self.secret_id = data["secret_id"]
|
||||
self.secret_key = data["secret_key"]
|
||||
|
||||
def get_headers(self, dns_id, action, payload, region="", token=""):
|
||||
self.__init_data(self.get_dns_data(None)[dns_id])
|
||||
timestamp = int(time.time())
|
||||
# timestamp = 1551113065
|
||||
date = datetime.utcfromtimestamp(timestamp).strftime("%Y-%m-%d")
|
||||
# ************* 步骤 1:拼接规范请求串 *************
|
||||
http_request_method = "POST"
|
||||
canonical_uri = "/"
|
||||
canonical_querystring = ""
|
||||
ct = "application/json; charset=utf-8"
|
||||
canonical_headers = "content-type:%s\nhost:%s\nx-tc-action:%s\n" % (ct, self.endpoint, action.lower())
|
||||
signed_headers = "content-type;host;x-tc-action"
|
||||
hashed_request_payload = hashlib.sha256(payload.encode("utf-8")).hexdigest()
|
||||
canonical_request = (http_request_method + "\n" +
|
||||
canonical_uri + "\n" +
|
||||
canonical_querystring + "\n" +
|
||||
canonical_headers + "\n" +
|
||||
signed_headers + "\n" +
|
||||
hashed_request_payload)
|
||||
# ************* 步骤 2:拼接待签名字符串 *************
|
||||
credential_scope = date + "/" + "dnspod" + "/" + "tc3_request"
|
||||
hashed_canonical_request = hashlib.sha256(canonical_request.encode("utf-8")).hexdigest()
|
||||
string_to_sign = (self.algorithm + "\n" +
|
||||
str(timestamp) + "\n" +
|
||||
credential_scope + "\n" +
|
||||
hashed_canonical_request)
|
||||
# ************* 步骤 3:计算签名 *************
|
||||
# 计算签名摘要函数
|
||||
def sign(key, msg):
|
||||
return hmac.new(key, msg.encode("utf-8"), hashlib.sha256).digest()
|
||||
secret_date = sign(("TC3" + self.secret_key).encode("utf-8"), date)
|
||||
secret_service = sign(secret_date, "dnspod")
|
||||
secret_signing = sign(secret_service, "tc3_request")
|
||||
signature = hmac.new(secret_signing, string_to_sign.encode("utf-8"), hashlib.sha256).hexdigest()
|
||||
# ************* 步骤 4:拼接 Authorization *************
|
||||
authorization = (self.algorithm + " " +
|
||||
"Credential=" + self.secret_id + "/" + credential_scope + ", " +
|
||||
"SignedHeaders=" + signed_headers + ", " +
|
||||
"Signature=" + signature)
|
||||
headers = {
|
||||
"Authorization": authorization,
|
||||
"Content-Type": "application/json; charset=utf-8",
|
||||
"Host": self.endpoint,
|
||||
"X-TC-Action": action,
|
||||
"X-TC-Timestamp": str(timestamp),
|
||||
"X-TC-Version": self.version
|
||||
}
|
||||
if region:
|
||||
headers["X-TC-Region"] = region
|
||||
if token:
|
||||
headers["X-TC-Token"] = token
|
||||
return headers
|
||||
|
||||
def create_dns_record(self, get):
|
||||
domain_name = get.domain_name
|
||||
domain_dns_value = get.domain_dns_value
|
||||
record_type = 'TXT'
|
||||
if 'record_type' in get:
|
||||
record_type = get.record_type
|
||||
record_line = '默认'
|
||||
if 'record_line' in get:
|
||||
record_line = get.record_line
|
||||
|
||||
domain_name, sub_domain, _ = self.extract_zone(domain_name)
|
||||
|
||||
try:
|
||||
params = json.dumps({
|
||||
"Domain": domain_name,
|
||||
"SubDomain": sub_domain,
|
||||
"RecordType": record_type,
|
||||
"RecordLine": record_line,
|
||||
"Value": domain_dns_value,
|
||||
})
|
||||
headers = self.get_headers(get.dns_id, "CreateRecord", params)
|
||||
res = requests.post(self.host, headers=headers, data=params).json()
|
||||
if "Error" in res['Response']:
|
||||
return public.returnMsg(False, res['Response']["Error"]["Message"])
|
||||
return public.returnMsg(True, '添加成功')
|
||||
except Exception as e:
|
||||
return public.returnMsg(False, '添加失败,msg:{}'.format(e))
|
||||
|
||||
def delete_dns_record(self, get):
|
||||
try:
|
||||
domain_name = get.domain_name
|
||||
RecordId = get.RecordId
|
||||
root_domain, _, sub_domain = self.extract_zone(domain_name)
|
||||
|
||||
params = json.dumps({
|
||||
"Domain": root_domain,
|
||||
"RecordId": int(RecordId)
|
||||
})
|
||||
headers = self.get_headers(get.dns_id, "DeleteRecord", params)
|
||||
res = requests.post(self.host, headers=headers, data=params).json()
|
||||
if "Error" in res['Response']:
|
||||
return public.returnMsg(False, res['Response']["Error"]["Message"])
|
||||
return public.returnMsg(True, '删除成功!')
|
||||
except Exception as e:
|
||||
return public.returnMsg(False, e)
|
||||
|
||||
def get_dns_record(self, get):
|
||||
|
||||
domain_name, _, sub_domain = self.extract_zone(get.domain_name)
|
||||
params = json.dumps({
|
||||
"Domain": domain_name,
|
||||
})
|
||||
|
||||
data = {}
|
||||
try:
|
||||
headers = self.get_headers(get.dns_id, "DescribeRecordList", params)
|
||||
json_data = requests.post(self.host, headers=headers, data=params).json()
|
||||
json_data = json_data['Response']
|
||||
if "Error" in json_data:
|
||||
if json_data["Error"]["Code"] == "ResourceNotFound.NoDataOfRecord":
|
||||
data = {"info": {'record_total': 0}, "list": []}
|
||||
else:
|
||||
data = json_data
|
||||
# if 'RecordList' in json_data:
|
||||
# data['list'] = json_data['RecordList']
|
||||
if 'RecordCountInfo' in json_data:
|
||||
data['info'] = {
|
||||
"record_total": json_data['RecordCountInfo']['SubdomainCount']
|
||||
}
|
||||
data["list"] = [
|
||||
{
|
||||
"RecordId": i["RecordId"],
|
||||
"name": i["Name"] + "." + domain_name if i["Name"] != '@' else domain_name,
|
||||
"value": i["Value"],
|
||||
"line": i["Line"],
|
||||
"ttl": i["TTL"],
|
||||
"type": i["Type"],
|
||||
"status": "启用" if i["Status"] == "ENABLE" else "暂停" if i["Status"] == "DISABLE" else i["Status"],
|
||||
"mx": i.get("MX"),
|
||||
"updated_on": i["UpdatedOn"],
|
||||
"remark": i.get("Remark") or "",
|
||||
}
|
||||
for i in json_data["RecordList"]
|
||||
]
|
||||
|
||||
except Exception as e:
|
||||
pass
|
||||
self.set_record_data({domain_name: data})
|
||||
return data
|
||||
|
||||
def update_dns_record(self, get):
|
||||
RecordId = get.RecordId
|
||||
RecordLine = get.RecordLine
|
||||
domain_name = get.domain_name
|
||||
domain_dns_value = get.domain_dns_value
|
||||
record_type = get.record_type
|
||||
|
||||
domain_name, sub_domain, _ = self.extract_zone(domain_name)
|
||||
|
||||
try:
|
||||
params = json.dumps({
|
||||
"Domain": domain_name,
|
||||
"SubDomain": sub_domain,
|
||||
"RecordType": record_type,
|
||||
"RecordLine": RecordLine,
|
||||
"Value": domain_dns_value,
|
||||
"RecordId": int(RecordId)
|
||||
})
|
||||
headers = self.get_headers(get.dns_id, "ModifyRecord", params)
|
||||
res = requests.post(self.host, headers=headers, data=params).json()
|
||||
if "Error" in res['Response']:
|
||||
return public.returnMsg(False, res['Response']["Error"]["Message"])
|
||||
return public.returnMsg(True, '修改成功!')
|
||||
except Exception as e:
|
||||
return public.returnMsg(False, e)
|
||||
146
class/sslModel/westModel.py
Normal file
146
class/sslModel/westModel.py
Normal file
@@ -0,0 +1,146 @@
|
||||
import hashlib
|
||||
import time
|
||||
|
||||
import requests
|
||||
|
||||
from sslModel.base import sslBase
|
||||
import public
|
||||
|
||||
|
||||
class main(sslBase):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
def __init_data(self, data):
|
||||
self.api_url = 'https://api.west.cn/api/v2/domain/'
|
||||
# 账号
|
||||
self.user_name = data["user_name"]
|
||||
# api 密码
|
||||
self.api_password = data["api_password"]
|
||||
self.headers = {'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8'}
|
||||
|
||||
def get_params(self):
|
||||
timestamp = str(time.time() * 1000)
|
||||
token = hashlib.md5((self.user_name + self.api_password + timestamp).encode("utf-8")).hexdigest()
|
||||
return {"username": self.user_name, "token": token, "time": timestamp}
|
||||
|
||||
def _request(self, dns_id, body):
|
||||
self.__init_data(self.get_dns_data(None)[dns_id])
|
||||
params = self.get_params()
|
||||
try:
|
||||
res = requests.post(self.api_url, headers=self.headers, params=params, data=body)
|
||||
|
||||
if res.status_code != 200:
|
||||
return False, res.text
|
||||
json_data = res.json()
|
||||
if json_data['result'] != 200:
|
||||
return False, json_data['msg']
|
||||
return True, json_data
|
||||
except Exception as e:
|
||||
return False, e
|
||||
|
||||
def get_dns_record(self, get):
|
||||
domain_name, _, sub_domain = self.extract_zone(get.domain_name)
|
||||
limit = "500"
|
||||
p = "1"
|
||||
if "limit" in get:
|
||||
limit = str(get["limit"])
|
||||
if "p" in get:
|
||||
p = str(get["p"])
|
||||
body = {
|
||||
"domain": domain_name,
|
||||
"act": "getdnsrecord",
|
||||
"limit": limit,
|
||||
"pageno": p,
|
||||
}
|
||||
try:
|
||||
flag, res = self._request(get.dns_id, body)
|
||||
|
||||
data = {"list": [], "info": {"record_total": res['data']['total']}}
|
||||
if not flag:
|
||||
data = {}
|
||||
for record in res['data']["items"]:
|
||||
data["list"].append(
|
||||
{
|
||||
"RecordId": record["id"],
|
||||
"name": record["item"] + "." + domain_name if record["item"] != "@" else domain_name,
|
||||
"value": record["value"],
|
||||
"line": record["line"] if record["line"] else "默认",
|
||||
"ttl": record["ttl"],
|
||||
"type": record["type"],
|
||||
"status": "启用" if record["pause"] == 0 else "暂停",
|
||||
"mx": "",
|
||||
"updated_on": "",
|
||||
"remark": "",
|
||||
}
|
||||
)
|
||||
except Exception as e:
|
||||
data = {}
|
||||
self.set_record_data({domain_name: data})
|
||||
return data
|
||||
|
||||
def create_dns_record(self, get):
|
||||
domain_name, sub_domain, _ = self.extract_zone(get.domain_name)
|
||||
record_type = 'TXT'
|
||||
if 'record_type' in get:
|
||||
record_type = get.record_type
|
||||
body = {
|
||||
"act": "adddnsrecord",
|
||||
"domain": domain_name,
|
||||
"host": sub_domain,
|
||||
"type": record_type,
|
||||
"value": get.domain_dns_value,
|
||||
"ttl": "600",
|
||||
"level": "10",
|
||||
"line": "",
|
||||
}
|
||||
try:
|
||||
flag, res = self._request(get.dns_id, body)
|
||||
if not flag:
|
||||
return public.returnMsg(False, '添加失败:{}'.format(res))
|
||||
return public.returnMsg(True, "添加成功")
|
||||
except Exception as e:
|
||||
return public.returnMsg(False, '添加失败:{}'.format(e))
|
||||
|
||||
def delete_dns_record(self, get):
|
||||
domain_name, _, sub_domain = self.extract_zone(get.domain_name)
|
||||
|
||||
body = {
|
||||
"act": "deldnsrecord",
|
||||
"domain": domain_name,
|
||||
"id": get.RecordId,
|
||||
}
|
||||
try:
|
||||
flag, res = self._request(get.dns_id, body)
|
||||
if not flag:
|
||||
return public.returnMsg(False, '删除失败:{}'.format(res))
|
||||
return public.returnMsg(True, "删除成功")
|
||||
except Exception as e:
|
||||
return public.returnMsg(False, '删除失败:{}'.format(e))
|
||||
|
||||
def update_dns_record(self, get):
|
||||
# 不能修改主机记录和类型
|
||||
domain_name, sub_domain, _ = self.extract_zone(get.domain_name)
|
||||
body = {
|
||||
"act": "moddnsrecord",
|
||||
"id": get.RecordId,
|
||||
"domain": domain_name,
|
||||
"host": sub_domain,
|
||||
"type": get.record_type,
|
||||
"value": get.domain_dns_value,
|
||||
"level": "10",
|
||||
"ttl": "600",
|
||||
}
|
||||
try:
|
||||
flag, res = self._request(get.dns_id, body)
|
||||
if not flag:
|
||||
return public.returnMsg(False, '修改失败:{}'.format(res))
|
||||
return public.returnMsg(True, "修改成功")
|
||||
except Exception as e:
|
||||
return public.returnMsg(False, '修改失败:{}'.format(e))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user