X-Git-Url: http://git.code-monkey.de/?a=blobdiff_plain;f=resources%2Flib%2FMSL.py;h=d0387972ceeab83ea253a55bf22fb89bc2c748eb;hb=19251d2cfa324ef7eff3223687e56b070b537635;hp=0b623f86d57584b1de13befd1df90f40649a4356;hpb=27a18564ddbf17c7897981d732f5570d5eefa19e;p=plugin.video.netflix.git diff --git a/resources/lib/MSL.py b/resources/lib/MSL.py index 0b623f8..d038797 100644 --- a/resources/lib/MSL.py +++ b/resources/lib/MSL.py @@ -10,6 +10,8 @@ import os import pprint import random from StringIO import StringIO + +from datetime import datetime import requests import zlib @@ -40,7 +42,7 @@ class MSL: 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() @@ -69,13 +71,18 @@ class MSL: 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): """ @@ -154,8 +161,8 @@ class MSL: 'heaac-2-dash', #subtiltes - 'dfxp-ls-sdh', - #'simplesdh', + #'dfxp-ls-sdh', + 'simplesdh', #'nflx-cmisc', #unkown @@ -353,27 +360,22 @@ class MSL: 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/ttml') + 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 @@ -409,6 +411,7 @@ class MSL: } 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), @@ -456,9 +459,10 @@ class MSL: :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': { @@ -510,10 +514,12 @@ class MSL: :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) } @@ -538,11 +544,13 @@ class MSL: 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), @@ -583,10 +591,26 @@ class MSL: 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