You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

177 lines
4.7 KiB

  1. import hmac
  2. from hashlib import sha256
  3. import base64
  4. import struct
  5. from zlib import crc32
  6. import secrets
  7. import time
  8. from collections import OrderedDict
  9. kJoinChannel = 1
  10. kPublishAudioStream = 2
  11. kPublishVideoStream = 3
  12. kPublishDataStream = 4
  13. kPublishAudiocdn = 5
  14. kPublishVideoCdn = 6
  15. kRequestPublishAudioStream = 7
  16. kRequestPublishVideoStream = 8
  17. kRequestPublishDataStream = 9
  18. kInvitePublishAudioStream = 10
  19. kInvitePublishVideoStream = 11
  20. kInvitePublishDataStream = 12
  21. kAdministrateChannel = 101
  22. kRtmLogin = 1000
  23. VERSION_LENGTH = 3
  24. APP_ID_LENGTH = 32
  25. def getVersion():
  26. return '006'
  27. def packUint16(x):
  28. return struct.pack('<H', int(x))
  29. def packUint32(x):
  30. return struct.pack('<I', int(x))
  31. def packInt32(x):
  32. return struct.pack('<i', int(x))
  33. def packString(string):
  34. return packUint16(len(string)) + string
  35. def packMap(m):
  36. ret = packUint16(len(list(m.items())))
  37. for k, v in list(m.items()):
  38. ret += packUint16(k) + packString(v)
  39. return ret
  40. def packMapUint32(m):
  41. ret = packUint16(len(list(m.items())))
  42. for k, v in list(m.items()):
  43. ret += packUint16(k) + packUint32(v)
  44. return ret
  45. class ReadByteBuffer:
  46. def __init__(self, bytes):
  47. self.buffer = bytes
  48. self.position = 0
  49. def unPackUint16(self):
  50. len = struct.calcsize('H')
  51. buff = self.buffer[self.position: self.position + len]
  52. ret = struct.unpack('<H', buff)[0]
  53. self.position += len
  54. return ret
  55. def unPackUint32(self):
  56. len = struct.calcsize('I')
  57. buff = self.buffer[self.position: self.position + len]
  58. ret = struct.unpack('<I', buff)[0]
  59. self.position += len
  60. return ret
  61. def unPackString(self):
  62. strlen = self.unPackUint16()
  63. buff = self.buffer[self.position: self.position + strlen]
  64. ret = struct.unpack('<' + str(strlen) + 's', buff)[0]
  65. self.position += strlen
  66. return ret
  67. def unPackMapUint32(self):
  68. messages = {}
  69. maplen = self.unPackUint16()
  70. for index in range(maplen):
  71. key = self.unPackUint16()
  72. value = self.unPackUint32()
  73. messages[key] = value
  74. return messages
  75. def unPackContent(buff):
  76. readbuf = ReadByteBuffer(buff)
  77. signature = readbuf.unPackString()
  78. crc_channel_name = readbuf.unPackUint32()
  79. crc_uid = readbuf.unPackUint32()
  80. m = readbuf.unPackString()
  81. return signature, crc_channel_name, crc_uid, m
  82. def unPackMessages(buff):
  83. readbuf = ReadByteBuffer(buff)
  84. salt = readbuf.unPackUint32()
  85. ts = readbuf.unPackUint32()
  86. messages = readbuf.unPackMapUint32()
  87. return salt, ts, messages
  88. class AccessToken:
  89. def __init__(self, appID='', appCertificate='', channelName='', uid=''):
  90. self.appID = appID
  91. self.appCertificate = appCertificate
  92. self.channelName = channelName
  93. self.ts = int(time.time()) + 24 * 3600
  94. self.salt = secrets.SystemRandom().randint(1, 99999999)
  95. self.messages = {}
  96. if (uid == 0):
  97. self.uidStr = ""
  98. else:
  99. self.uidStr = str(uid)
  100. def addPrivilege(self, privilege, expireTimestamp):
  101. self.messages[privilege] = expireTimestamp
  102. def fromString(self, originToken):
  103. try:
  104. dk6version = getVersion()
  105. originVersion = originToken[:VERSION_LENGTH]
  106. if (originVersion != dk6version):
  107. return False
  108. originAppID = originToken[VERSION_LENGTH:(VERSION_LENGTH + APP_ID_LENGTH)]
  109. originContent = originToken[(VERSION_LENGTH + APP_ID_LENGTH):]
  110. originContentDecoded = base64.b64decode(originContent)
  111. signature, crc_channel_name, crc_uid, m = unPackContent(originContentDecoded)
  112. self.salt, self.ts, self.messages = unPackMessages(m)
  113. except Exception as e:
  114. print("error:", str(e))
  115. return False
  116. return True
  117. def build(self):
  118. self.messages = OrderedDict(sorted(iter(self.messages.items()), key=lambda x: int(x[0])))
  119. m = packUint32(self.salt) + packUint32(self.ts) \
  120. + packMapUint32(self.messages)
  121. val = self.appID.encode('utf-8') + self.channelName.encode('utf-8') + self.uidStr.encode('utf-8') + m
  122. signature = hmac.new(self.appCertificate.encode('utf-8'), val, sha256).digest()
  123. crc_channel_name = crc32(self.channelName.encode('utf-8')) & 0xffffffff
  124. crc_uid = crc32(self.uidStr.encode('utf-8')) & 0xffffffff
  125. content = packString(signature) \
  126. + packUint32(crc_channel_name) \
  127. + packUint32(crc_uid) \
  128. + packString(m)
  129. version = getVersion()
  130. ret = version + self.appID + base64.b64encode(content).decode('utf-8')
  131. return ret