CommonService.py 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251
  1. import datetime
  2. import time
  3. from random import Random
  4. import base64
  5. import pytz
  6. import requests
  7. import OpenSSL.crypto as ct
  8. from base64 import encodebytes
  9. from azoauth.config import ALEXA_EVENT_API, CLIENT_CONFIG, LOGGER
  10. from model.models import iotdeviceInfoModel, UidRtspModel, AlexaAuthModel
  11. # 复用性且公用较高封装代码在这
  12. class CommonService:
  13. # 生成随机数
  14. @staticmethod
  15. def encrypt_data(randomlength=8, number=False):
  16. str = ''
  17. if number == False:
  18. characterSet = 'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsT' \
  19. 'tUuVvWwXxYyZz0123456789'
  20. else:
  21. characterSet = '0123456789'
  22. length = len(characterSet) - 1
  23. random = Random()
  24. for index in range(randomlength):
  25. str += characterSet[random.randint(0, length)]
  26. return str
  27. # 加密
  28. # @staticmethod
  29. def encrypt_pwd(self, userPwd):
  30. for i in range(1, 4):
  31. if i == 1:
  32. userPwd = self.RandomStr(3, False)+userPwd+self.RandomStr(3, False)
  33. userPwd = base64.b64encode(str(userPwd).encode("utf-8")).decode('utf8')
  34. if i == 2:
  35. userPwd = self.RandomStr(2, False)+str(userPwd)+self.RandomStr(2, False)
  36. userPwd = base64.b64encode(str(userPwd).encode("utf-8")).decode('utf8')
  37. if i == 3:
  38. userPwd = self.RandomStr(1, False)+str(userPwd)+self.RandomStr(1, False)
  39. userPwd = base64.b64encode(str(userPwd).encode("utf-8")).decode('utf8')
  40. return userPwd
  41. # 解密
  42. @staticmethod
  43. def decode_pwd(password):
  44. for i in range(1, 4):
  45. if i == 1:
  46. # 第一次先解密
  47. password = base64.b64decode(password)
  48. password = password.decode('utf-8')
  49. # 截去第一位,最后一位
  50. password = password[1:-1]
  51. if i == 2:
  52. # 第2次先解密
  53. password = base64.b64decode(password)
  54. password = password.decode('utf-8')
  55. # 去前2位,后2位
  56. password = password[2:-2]
  57. if i == 3:
  58. # 第3次先解密
  59. password = base64.b64decode(password)
  60. password = password.decode('utf-8')
  61. # 去前3位,后3位
  62. password = password[3:-3]
  63. return password
  64. # 生成随机字符串
  65. @staticmethod
  66. def RandomStr(randomlength=8, number=False):
  67. str = ''
  68. if number == False:
  69. characterSet = 'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsT' \
  70. 'tUuVvWwXxYyZz0123456789'
  71. else:
  72. characterSet = '0123456789'
  73. length = len(characterSet) - 1
  74. random = Random()
  75. for index in range(randomlength):
  76. str += characterSet[random.randint(0, length)]
  77. return str
  78. @staticmethod
  79. def query_serial_with_uid(uid):
  80. # 根据uid查询序列号,存在则返回序列号,否则返uid
  81. uid_qs = UidRtspModel.objects.filter(uid=uid).values('serial_number')
  82. if uid_qs.exists():
  83. serial_number = uid_qs[0]['serial_number']
  84. if serial_number:
  85. return serial_number
  86. return uid
  87. @staticmethod
  88. def req_publish_mqtt_msg(identification_code, topic_name, msg, qos=1):
  89. """
  90. 通用发布MQTT消息函数
  91. @param identification_code: 标识码
  92. @param topic_name: 主题名
  93. @param msg: 消息内容
  94. @param qos: mqtt qos等级
  95. @return: boolean
  96. """
  97. if not all([identification_code, topic_name]):
  98. return False
  99. if identification_code.endswith('11L'):
  100. thing_name = 'LC_' + identification_code
  101. else:
  102. thing_name = 'Ansjer_Device_' + identification_code
  103. try:
  104. # 获取数据组织将要请求的url
  105. iot = iotdeviceInfoModel.objects.filter(
  106. thing_name=thing_name).values(
  107. 'endpoint', 'token_iot_number')
  108. if not iot.exists():
  109. return False
  110. endpoint = iot[0]['endpoint']
  111. Token = iot[0]['token_iot_number']
  112. # api doc: https://docs.aws.amazon.com/zh_cn/iot/latest/developerguide/http.html
  113. # url: https://IoT_data_endpoint/topics/url_encoded_topic_name?qos=1
  114. # post请求url发布MQTT消息
  115. url = 'https://{}/topics/{}?qos={}'.format(endpoint, topic_name, qos)
  116. authorizer_name = 'Ansjer_Iot_Auth'
  117. signature = CommonService.rsa_sign(Token) # Token签名
  118. headers = {
  119. 'x-amz-customauthorizer-name': authorizer_name,
  120. 'Token': Token,
  121. 'x-amz-customauthorizer-signature': signature}
  122. r = requests.post(url=url, headers=headers, json=msg, timeout=2)
  123. if r.status_code == 200:
  124. res = r.json()
  125. if res['message'] == 'OK':
  126. return True
  127. return False
  128. else:
  129. return False
  130. except Exception as e:
  131. return False
  132. @staticmethod
  133. def rsa_sign(Token):
  134. # 私钥签名Token
  135. if not Token:
  136. return ''
  137. private_key_file = '''-----BEGIN RSA PRIVATE KEY-----
  138. MIIEpQIBAAKCAQEA5iJzEDPqtGmFMggekVro6C0lrjuC2BjunGkrFNJWpDYzxCzE
  139. X5jf4/Fq7hcIaQd5sqHugDxPVollSLPe9zNilbrd0sZfU+Ed8gRVuKW9KwfE9XFr
  140. L0pt6bKRQ0IIRfiZ9TuR0tsQysvcO1GZSXcYfPue3tGM1zOnWFThWDqZ06+sOxzt
  141. RMRl4yNfbpCG4MfxG3itNXOfrjZv2OMLSXrxmzubSvRpUYSvQPs4fm9302SAnySY
  142. 0MKzx6H6528ZQm/IDDSZy6EmNBIyTRDfxC56vnYcXvqedAQh7jJnjdvt6Q4MhASH
  143. eIYi1FBSdu2NT6wgpnrqXzx5pq9kR/lnsLID0wIDAQABAoIBAQCiF4GT1/1oNSpr
  144. ouxk1PNXFPWFUsVGD8mAwVJmx//eiY7MjfuCmdqYYmI+cFqsH2fIOeYSzGfVO9Dq
  145. 9EYHN1oovAWhf7eFDPpajFMUSyiCNmazub8VAAeKowtNpCTPo9pMsDh1m3aoYA4u
  146. ebrN0+Sbo16y8kWRDgDAZoiR7DSMs8lczk16hwfv5mw8XpNDbaL3Coi4Koe2S1Yh
  147. 2SX3vWFlpd7qF1ZYXuZIp+b8JPrV7n9eUKoFgzj0gqgwQK80CoexIjiOrNMPvkQa
  148. q+8kCvFjAzKxOK7e8gjM8lMRiGodb61kmYZkkJzFwWO4EaGbl34lfVECd1Ixp3tF
  149. be0OWAGBAoGBAPSteXDzzToD8ovM7LL11x0jWwI6HOiHu89kZtW566rIezjWBuA2
  150. TxrcYKM3h9jQRXS3CsMdoIv6XGk5lqM8ADtjn23FBWe/THYLh8bm8JOgh5RRWQDg
  151. SvkLfi9Ih2mM4NJfmuuDOh3Nze2efLM7+kOZWUQwF2Zx9mL5jvRBk351AoGBAPDI
  152. sYmT2Li+i5+0vykA2m5uPF8ZOW8BGtAfCZv0suW7BNzSgin78g9WapRd/4p0NNiL
  153. /nVMqPPCpd1akCUpV+GDWQt0hV+HZjxANE0KWhciQRyo2qvo51j8SWILJSgh0tXC
  154. aTF8qt6oGw3VN3m57vKhbrlDaz0J/NDJFci6msAnAoGBAOuG6bXPGijUj+//DYKf
  155. n7jOxdZ49kboEePrtAncdHzri6IEdI3z+WXT6bpzw/LzWUimwldb96WHFNm9s8Hi
  156. Ch8hIODbnP5naUTgiIzw1XhmONyPCewL/F+LrqX5XVA/alNX8JrwsUrrR2WLAGLQ
  157. Q3I69XDsEjptTU2tCO0bCs3ZAoGBAJ2lCHfm0JHET230zONvp5N9oREyVqQSuRdh
  158. +syc3TQDyh85w/bw+X6JOaaCFHj1tFPC9Iqf8k4GNspCLPXnp54CfR4+38O3xnvU
  159. HWoDSRC0YKT++IxtJGriYrlKSr2Hx54kdvLriIPW1D+uRW/xCDza7L9nIKMKEvgv
  160. b4/IfOEpAoGAeKM9Te7T1VzlAkS0CJOwanzwYV/zrex84WuXxlsGgPQ871lTs5AP
  161. H1QLfLfFXH+UVrCEC2yv4eml/cqFkpB3gE5i4MQ8GPVIOSs5tsIyl8YUA03vdNdB
  162. GCqvlyw5dfxNA+EtxNE2wCW/LW7ENJlACgcfgPlBZtpLheWoZB/maw4=
  163. -----END RSA PRIVATE KEY-----'''
  164. # 使用密钥文件方式
  165. # private_key_file_path = os.path.join(BASE_DIR, 'static/iotCore/private.pem')#.replace('\\', '/')
  166. # private_key_file = open(private_key_file_path, 'r')
  167. private_key = ct.load_privatekey(ct.FILETYPE_PEM, private_key_file)
  168. signature = ct.sign(private_key, Token.encode('utf8'), 'sha256')
  169. signature = encodebytes(signature).decode('utf8').replace('\n', '')
  170. # print('signature:', signature)
  171. return signature
  172. @staticmethod
  173. def timestamp_to_iso8601(timestamp):
  174. # 将十位时间戳(秒)转换为UTC时区的datetime对象
  175. utc_dt = datetime.datetime.fromtimestamp(timestamp, pytz.UTC)
  176. # 格式化为YYYY-MM-DDThh:mm:ssZ格式
  177. return utc_dt.strftime("%Y-%m-%dT%H:%M:%SZ")
  178. @classmethod
  179. def get_access_token(cls, user_id):
  180. auth_qs = AlexaAuthModel.objects.filter(userID=user_id).values(
  181. 'expiresTime', 'refresh_token', 'access_token', 'alexa_region', 'skill_name')
  182. if not auth_qs.exists():
  183. return False
  184. expires_time = auth_qs[0]['expiresTime']
  185. alexa_region = auth_qs[0]['alexa_region']
  186. now_time = int(time.time())
  187. if now_time < expires_time:
  188. access_token = auth_qs[0]['access_token']
  189. else:
  190. if alexa_region not in ALEXA_EVENT_API.keys():
  191. return False
  192. skill_name = auth_qs[0]['skill_name']
  193. refresh_token = auth_qs[0]['refresh_token']
  194. res = cls.get_refresh_token(refresh_token, skill_name)
  195. if 'error' not in res:
  196. auth_qs.update(
  197. access_token=res['access_token'],
  198. refresh_token=res['refresh_token'],
  199. expiresTime=now_time + 3000,
  200. updTime=now_time,
  201. )
  202. access_token = res['access_token']
  203. else:
  204. return False
  205. return access_token
  206. @staticmethod
  207. def get_refresh_token(refresh_token, skill_name):
  208. # 请求更新token
  209. if skill_name not in CLIENT_CONFIG.keys():
  210. return {'error': 'error skill_name'}
  211. payload = {
  212. 'grant_type': 'refresh_token',
  213. 'refresh_token': refresh_token,
  214. 'client_id': CLIENT_CONFIG[skill_name]['client_id'],
  215. 'client_secret': CLIENT_CONFIG[skill_name]['client_secret'],
  216. }
  217. auth_request_url = 'https://api.amazon.com/auth/o2/token'
  218. headers = {
  219. 'content-type': "application/x-www-form-urlencoded",
  220. 'cache-control': "no-cache"
  221. }
  222. try:
  223. res = requests.post(auth_request_url, data=payload, headers=headers, timeout=5)
  224. res.raise_for_status()
  225. request_json = res.json()
  226. return request_json
  227. except requests.exceptions.RequestException as e:
  228. return {'error': str(e)}