alydns.py 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. # coding:utf-8
  2. import base64
  3. import urllib
  4. import hmac
  5. import pytz
  6. import datetime
  7. import random
  8. import string
  9. import json
  10. import sys
  11. pv = "python2"
  12. #python2
  13. if sys.version_info[0] < 3:
  14. from urllib import quote
  15. from urllib import urlencode
  16. import hashlib
  17. else:
  18. from urllib.parse import quote
  19. from urllib.parse import urlencode
  20. from urllib import request
  21. pv = "python3"
  22. class AliDns:
  23. def __init__(self, access_key_id, access_key_secret, domain_name):
  24. self.access_key_id = access_key_id
  25. self.access_key_secret = access_key_secret
  26. self.domain_name = domain_name
  27. @staticmethod
  28. def getDomain(domain):
  29. domain_parts = domain.split('.')
  30. if len(domain_parts) > 2:
  31. rootdomain='.'.join(domain_parts[-(2 if domain_parts[-1] in {"co.jp","com.tw","net","com","com.cn","org","cn","gov","net.cn","io","top","me","int","edu","link"} else 3):])
  32. selfdomain=domain.split(rootdomain)[0]
  33. return (selfdomain[0:len(selfdomain)-1],rootdomain)
  34. return ("",domain)
  35. @staticmethod
  36. def generate_random_str(length=14):
  37. """
  38. 生成一个指定长度(默认14位)的随机数值,其中
  39. string.digits = "0123456789'
  40. """
  41. str_list = [random.choice(string.digits) for i in range(length)]
  42. random_str = ''.join(str_list)
  43. return random_str
  44. @staticmethod
  45. def percent_encode(str):
  46. res = quote(str.encode('utf-8'), '')
  47. res = res.replace('+', '%20')
  48. res = res.replace('*', '%2A')
  49. res = res.replace('%7E', '~')
  50. return res
  51. @staticmethod
  52. def utc_time():
  53. """
  54. 请求的时间戳。日期格式按照ISO8601标准表示,
  55. 并需要使用UTC时间。格式为YYYY-MM-DDThh:mm:ssZ
  56. 例如,2015-01-09T12:00:00Z(为UTC时间2015年1月9日12点0分0秒)
  57. :return:
  58. """
  59. utc_tz = pytz.timezone('UTC')
  60. time = datetime.datetime.now(tz=utc_tz).strftime('%Y-%m-%dT%H:%M:%SZ')
  61. return time
  62. @staticmethod
  63. def sign_string(url_param):
  64. percent_encode = AliDns.percent_encode
  65. sorted_url_param = sorted(url_param.items(), key=lambda x: x[0])
  66. can_string = ''
  67. for k, v in sorted_url_param:
  68. can_string += '&' + percent_encode(k) + '=' + percent_encode(v)
  69. string_to_sign = 'GET' + '&' + '%2F' + '&' + percent_encode(can_string[1:])
  70. return string_to_sign
  71. @staticmethod
  72. def access_url(url):
  73. if pv == "python2" :
  74. f = urllib.urlopen(url)
  75. result = f.read().decode('utf-8')
  76. #print(result)
  77. return json.loads(result)
  78. else :
  79. req = request.Request(url)
  80. with request.urlopen(req) as f:
  81. result = f.read().decode('utf-8')
  82. #print(result)
  83. return json.loads(result)
  84. def visit_url(self, action_param):
  85. common_param = {
  86. 'Format': 'json',
  87. 'Version': '2015-01-09',
  88. 'AccessKeyId': self.access_key_id,
  89. 'SignatureMethod': 'HMAC-SHA1',
  90. 'Timestamp': AliDns.utc_time(),
  91. 'SignatureVersion': '1.0',
  92. 'SignatureNonce': AliDns.generate_random_str(),
  93. 'DomainName': self.domain_name,
  94. }
  95. url_param = dict(common_param, **action_param)
  96. string_to_sign = AliDns.sign_string(url_param)
  97. hash_bytes = self.access_key_secret + "&"
  98. if pv == "python2":
  99. h = hmac.new(hash_bytes, string_to_sign, digestmod=hashlib.sha1)
  100. else :
  101. h = hmac.new(hash_bytes.encode('utf-8'), string_to_sign.encode('utf-8'), digestmod='SHA1')
  102. signature = base64.encodestring(h.digest()).strip()
  103. url_param.setdefault('Signature', signature)
  104. url = 'https://alidns.aliyuncs.com/?' + urlencode(url_param)
  105. #print(url)
  106. return AliDns.access_url(url)
  107. # 显示所有
  108. def describe_domain_records(self):
  109. """
  110. 最多只能查询此域名的 500条解析记录
  111. PageNumber 当前页数,起始值为1,默认为1
  112. PageSize 分页查询时设置的每页行数,最大值500,默认为20
  113. :return:
  114. """
  115. action_param = dict(
  116. Action='DescribeDomainRecords',
  117. PageNumber='1',
  118. PageSize='500',
  119. )
  120. result = self.visit_url(action_param)
  121. return result
  122. # 增加解析
  123. def add_domain_record(self, type, rr, value):
  124. action_param = dict(
  125. Action='AddDomainRecord',
  126. RR=rr,
  127. Type=type,
  128. Value=value,
  129. )
  130. result = self.visit_url(action_param)
  131. return result
  132. # 修改解析
  133. def update_domain_record(self, id, type, rr, value):
  134. action_param = dict(
  135. Action="UpdateDomainRecord",
  136. RecordId=id,
  137. RR=rr,
  138. Type=type,
  139. Value=value,
  140. )
  141. result = self.visit_url(action_param)
  142. return result
  143. # 删除解析
  144. def delete_domain_record(self, id):
  145. action_param = dict(
  146. Action="DeleteDomainRecord",
  147. RecordId=id,
  148. )
  149. result = self.visit_url(action_param)
  150. return result
  151. if __name__ == '__main__':
  152. #filename,ACCESS_KEY_ID, ACCESS_KEY_SECRET = sys.argv
  153. #domain = AliDns(ACCESS_KEY_ID, ACCESS_KEY_SECRET, 'simplehttps.com')
  154. #domain.describe_domain_records()
  155. #增加记录
  156. #print(domain.add_domain_record("TXT", "test", "test"))
  157. # 修改解析
  158. #domain.update_domain_record('4011918010876928', 'TXT', 'test2', 'text2')
  159. # 删除解析记录
  160. # data = domain.describe_domain_records()
  161. # record_list = data["DomainRecords"]["Record"]
  162. # for item in record_list:
  163. # if 'test' in item['RR']:
  164. # domain.delete_domain_record(item['RecordId'])
  165. # 第一个参数是 action,代表 (add/clean)
  166. # 第二个参数是域名
  167. # 第三个参数是主机名(第三个参数+第二个参数组合起来就是要添加的 TXT 记录)
  168. # 第四个参数是 TXT 记录值
  169. # 第五个参数是 APPKEY
  170. # 第六个参数是 APPTOKEN
  171. #sys.exit(0)
  172. print ("域名 API 调用开始")
  173. print ("-".join(sys.argv))
  174. file_name, cmd ,certbot_domain, acme_challenge, certbot_validation,ACCESS_KEY_ID, ACCESS_KEY_SECRET = sys.argv
  175. certbot_domain=AliDns.getDomain(certbot_domain)
  176. # print (certbot_domain)
  177. if certbot_domain[0]=="":
  178. selfdomain = acme_challenge
  179. else:
  180. selfdomain = acme_challenge + "." + certbot_domain[0]
  181. domain = AliDns(ACCESS_KEY_ID, ACCESS_KEY_SECRET, certbot_domain[1])
  182. if cmd == "add":
  183. result = (domain.add_domain_record("TXT",selfdomain, certbot_validation))
  184. if "Code" in result:
  185. print ("aly dns 域名增加失败-"+str(result["Code"]) + ":" + str(result["Message"]))
  186. elif cmd == "clean":
  187. data = domain.describe_domain_records()
  188. if "Code" in data:
  189. print ("aly dns 域名删除失败-"+str(data["Code"]) + ":" + str(data["Message"]))
  190. sys.exit(0)
  191. record_list = data["DomainRecords"]["Record"]
  192. if record_list:
  193. for item in record_list:
  194. if (item['RR'] == selfdomain):
  195. domain.delete_domain_record(item['RecordId'])
  196. print ("域名 API 调用结束")