Initial YakPanel commit

This commit is contained in:
Niranjan
2026-04-07 02:04:22 +05:30
commit 2826d3e7f3
5359 changed files with 1390724 additions and 0 deletions

Binary file not shown.

View 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
View 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

File diff suppressed because it is too large Load Diff

View 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
View 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 paramsundefined 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'))

View 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, "修改成功")

View 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))

View 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))

View 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

View 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
View 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))