import pprint
import random
from StringIO import StringIO
+
+from datetime import datetime
import requests
import zlib
last_drm_context = ''
last_playback_context = ''
#esn = "NFCDCH-LX-CQE0NU6PA5714R25VPLXVU2A193T36"
- esn = "WWW-BROWSE-D7GW1G4NPXGR1F0X1H3EQGY3V1F5WE"
+ #esn = "WWW-BROWSE-D7GW1G4NPXGR1F0X1H3EQGY3V1F5WE"
#esn = "NFCDIE-02-DCH84Q2EK3N6VFVQJ0NLRQ27498N0F"
current_message_id = 0
session = requests.session()
elif self.file_exists(self.kodi_helper.msl_data_path, 'rsa_key.bin'):
self.kodi_helper.log(msg='RSA Keys do already exist load old ones')
self.__load_rsa_keys()
- self.__perform_key_handshake()
+ if self.kodi_helper.get_esn():
+ self.__perform_key_handshake()
else:
self.kodi_helper.log(msg='Create new RSA Keys')
# Create new Key Pair and save
self.rsa_key = RSA.generate(2048)
self.__save_rsa_keys()
- self.__perform_key_handshake()
+ if self.kodi_helper.get_esn():
+ self.__perform_key_handshake()
+
+ def perform_key_handshake(self):
+ self.__perform_key_handshake()
def load_manifest(self, viewable_id):
"""
'heaac-2-dash',
#subtiltes
- 'dfxp-ls-sdh',
- #'simplesdh',
+ #'dfxp-ls-sdh',
+ 'simplesdh',
#'nflx-cmisc',
#unkown
segment_base = ET.SubElement(rep, 'SegmentBase', indexRange="0-"+str(init_length), indexRangeExact="true")
ET.SubElement(segment_base, 'Initialization', range='0-'+str(init_length))
- # Multiple Adaption Set for subtiles
+ # Multiple Adaption Sets for subtiles
for text_track in manifest['textTracks']:
- print text_track
if 'downloadables' not in text_track or text_track['downloadables'] is None:
continue
subtiles_adaption_set = ET.SubElement(period, 'AdaptationSet',
lang=text_track['bcp47'],
+ codecs='stpp',
contentType='text',
- mimeType='text/vtt')
+ mimeType='application/ttml+xml')
for downloadable in text_track['downloadables']:
rep = ET.SubElement(subtiles_adaption_set, 'Representation',
- bandwidth='0',
nflxProfile=downloadable['contentProfile']
)
- print downloadable['urls']
ET.SubElement(rep, 'BaseURL').text = self.__get_base_url(downloadable['urls'])
-
-
-
xml = ET.tostring(root, encoding='utf-8', method='xml')
xml = xml.replace('\n', '').replace('\r', '')
return xml
}
def __generate_msl_request_data(self, data):
+ self.__load_msl_data()
header_encryption_envelope = self.__encrypt(self.__generate_msl_header())
header = {
'headerdata': base64.standard_b64encode(header_encryption_envelope),
:return: The base64 encoded JSON String of the header
"""
self.current_message_id = self.rndm.randint(0, pow(2, 52))
+ esn = self.kodi_helper.get_esn()
header_data = {
- 'sender': self.esn,
+ 'sender': esn,
'handshake': is_handshake,
'nonreplayable': False,
'capabilities': {
:param plaintext:
:return: Serialized JSON String of the encryption Envelope
"""
+ esn = self.kodi_helper.get_esn()
+
iv = get_random_bytes(16)
encryption_envelope = {
'ciphertext': '',
- 'keyid': self.esn + '_' + str(self.sequence_number),
+ 'keyid': esn + '_' + str(self.sequence_number),
'sha256': 'AA==',
'iv': base64.standard_b64encode(iv)
}
def __perform_key_handshake(self):
header = self.__generate_msl_header(is_key_request=True, is_handshake=True, compressionalgo="", encrypt=False)
+ esn = self.kodi_helper.get_esn()
+
request = {
'entityauthdata': {
'scheme': 'NONE',
'authdata': {
- 'identity': self.esn
+ 'identity': esn
}
},
'headerdata': base64.standard_b64encode(header),
def __load_msl_data(self):
msl_data = json.JSONDecoder().decode(self.load_file(self.kodi_helper.msl_data_path, 'msl_data.json'))
+ #Check expire date of the token
+ master_token = json.JSONDecoder().decode(base64.standard_b64decode(msl_data['tokens']['mastertoken']['tokendata']))
+ valid_until = datetime.utcfromtimestamp(int(master_token['expiration']))
+ present = datetime.now()
+ difference = valid_until - present
+ difference = difference.total_seconds() / 60 / 60
+ # If token expires in less then 10 hours or is expires renew it
+ if difference < 10:
+ self.__load_rsa_keys()
+ self.__perform_key_handshake()
+ return
+
self.__set_master_token(msl_data['tokens']['mastertoken'])
self.encryption_key = base64.standard_b64decode(msl_data['encryption_key'])
self.sign_key = base64.standard_b64decode(msl_data['sign_key'])
+
+ def save_msl_data(self):
+ self.__save_msl_data()
+
def __save_msl_data(self):
"""
Saves the keys and tokens in json file