def get_license(self, challenge, sid):
        """
        Requests and returns a license for the given challenge and sid
        :param challenge: The base64 encoded challenge
        :param sid: The sid paired to the challengew
        :return: Base64 representation of the licensekey or False unsuccessfull
        """
        common.debug('Requesting license')
        id = int(time.time() * 10000)

        license_request_data = {
            'version': 2,
            'url': self.last_license_url,
            'id': id,
            'esn': g.get_esn(),
            'languages': [g.PERSISTENT_STORAGE['locale_id']],
            'uiVersion': 'shakti-v5bca5cd3',
            'clientVersion': '6.0013.315.051',
            'params': [{
                'sessionId': sid,
                'clientTime': int(id / 10000),
                'challengeBase64': challenge,
                'xid': str(id + 1610)
            }],
            'echo': 'sessionId'
        }

        response = self._chunked_request(ENDPOINTS['license'],
                                         license_request_data, g.get_esn())
        return response[0]['licenseResponseBase64']
Exemple #2
0
 def _login(self, modal_error_message=False):
     """Perform account login"""
     # If exists get the current esn value before extract a new session data
     current_esn = g.get_esn()
     try:
         # First we get the authentication url without logging in, required for login API call
         react_context = website.extract_json(self._get('profiles'),
                                              'reactContext')
         auth_url = website.extract_api_data(react_context)['auth_url']
         common.debug('Logging in...')
         login_response = self._post('login',
                                     data=_login_payload(
                                         common.get_credentials(),
                                         auth_url))
         validate_msg = website.validate_login(login_response)
         if validate_msg:
             self.session.cookies.clear()
             common.purge_credentials()
             if modal_error_message:
                 ui.show_ok_dialog(common.get_local_string(30008),
                                   validate_msg)
             else:
                 ui.show_notification(common.get_local_string(30009))
             return False
         website.extract_session_data(login_response)
     except Exception as exc:
         common.error(traceback.format_exc())
         self.session.cookies.clear()
         raise exc
     common.info('Login successful')
     ui.show_notification(common.get_local_string(30109))
     self.update_session_data(current_esn)
     return True
Exemple #3
0
def generate_logblobs_params():
    """Generate the initial log blog"""
    # It seems that this log is sent when logging in to a profile the first time
    # i think it is the easiest to reproduce, the others contain too much data
    screen_size = str(xbmcgui.getScreenWidth()) + 'x' + str(xbmcgui.getScreenHeight())
    timestamp_utc = time.time()
    timestamp = int(timestamp_utc * 1000)
    client_ver = g.LOCAL_DB.get_value('asset_core', '', table=TABLE_SESSION)
    app_id = int(time.time()) * 10000 + random.randint(1, 10001)  # Should be used with all log requests
    if client_ver:
        result = re.search(r'-([0-9\.]+)\.js$', client_ver)
        client_ver = result.groups()[0]

    # Here you have to enter only the real data, falsifying the data would cause repercussions in netflix server logs
    # therefore since it is possible to exclude data, we avoid entering data that we do not have
    blob = {
        'browserua': common.get_user_agent().replace(' ', '#'),
        'browserhref': 'https://www.netflix.com/browse',
        # 'initstart': 988,
        # 'initdelay': 268,
        'screensize': screen_size,  # '1920x1080',
        'screenavailsize': screen_size,  # '1920x1040',
        'clientsize': screen_size,  # '1920x944',
        # 'pt_navigationStart': -1880,
        # 'pt_fetchStart': -1874,
        # 'pt_secureConnectionStart': -1880,
        # 'pt_requestStart': -1853,
        # 'pt_domLoading': -638,
        # 'm_asl_start': 990,
        # 'm_stf_creat': 993,
        # 'm_idb_open': 993,
        # 'm_idb_succ': 1021,
        # 'm_msl_load_no_data': 1059,
        # 'm_asl_comp': 1256,
        'type': 'startup',
        'sev': 'info',
        'devmod': 'chrome-cadmium',
        'clver': client_ver,  # e.g. '6.0021.220.051'
        'osplatform': g.LOCAL_DB.get_value('browser_info_os_name', '', table=TABLE_SESSION),
        'osver': g.LOCAL_DB.get_value('browser_info_os_version', '', table=TABLE_SESSION),
        'browsername': 'Chrome',
        'browserver': g.LOCAL_DB.get_value('browser_info_version', '', table=TABLE_SESSION),
        'appLogSeqNum': 0,
        'uniqueLogId': common.get_random_uuid(),
        'appId': app_id,
        'esn': g.get_esn(),
        'lver': '',
        # 'jssid': '15822792997793',  # Same value of appId
        # 'jsoffms': 1261,
        'clienttime': timestamp,
        'client_utc': int(timestamp_utc),
        'uiver': g.LOCAL_DB.get_value('ui_version', '', table=TABLE_SESSION)
    }

    blobs_container = {
        'entries': [blob]
    }
    blobs_dump = json.dumps(blobs_container)
    blobs_dump = blobs_dump.replace('"', '\"').replace(' ', '').replace('#', ' ')
    return {'logblobs': blobs_dump}
Exemple #4
0
 def _login(self, modal_error_message=False):
     """Perform account login"""
     # If exists get the current esn value before extract a new session data
     current_esn = g.get_esn()
     try:
         # First we get the authentication url without logging in, required for login API call
         react_context = website.extract_json(self._get('login'), 'reactContext')
         auth_url = website.extract_api_data(react_context)['auth_url']
         common.debug('Logging in...')
         login_response = self._post(
             'login',
             data=_login_payload(common.get_credentials(), auth_url))
         try:
             website.extract_session_data(login_response, validate=True, update_profiles=True)
             common.info('Login successful')
             ui.show_notification(common.get_local_string(30109))
             self.update_session_data(current_esn)
             return True
         except (LoginValidateError, LoginValidateErrorIncorrectPassword) as exc:
             self.session.cookies.clear()
             common.purge_credentials()
             if not modal_error_message:
                 raise
             ui.show_ok_dialog(common.get_local_string(30008), unicode(exc))
     except InvalidMembershipStatusError:
         ui.show_error_info(common.get_local_string(30008),
                            common.get_local_string(30180),
                            False, True)
     except Exception:  # pylint: disable=broad-except
         import traceback
         common.error(g.py2_decode(traceback.format_exc(), 'latin-1'))
         self.session.cookies.clear()
         raise
     return False
Exemple #5
0
    def release_license(self, data=None):  # pylint: disable=unused-argument
        """Release the server license"""
        try:
            # When UpNext is used a new video is loaded while another one is running and not yet released,
            # so you need to take the right data of first added license
            url = self.licenses_release_url.pop()
            sid = self.licenses_session_id.pop()
            xid = self.licenses_xid.pop()

            common.debug('Requesting releasing license')
            params = [{
                'url': url,
                'params': {
                    'drmSessionId': sid,
                    'xid': xid
                },
                'echo': 'drmSessionId'
            }]

            response = self.msl_requests.chunked_request(
                ENDPOINTS['license'],
                self.msl_requests.build_request_data('/bundle', params),
                g.get_esn())
            common.debug('License release response: {}', response)
        except IndexError:
            # Example the supplemental media type have no license
            common.debug('No license to release')
 def update_session_data(self, old_esn=g.get_esn()):
     self.session.headers.update({
         'x-netflix.request.client.user.guid':
         g.LOCAL_DB.get_active_profile_guid()
     })
     cookies.save(self.account_hash, self.session.cookies)
     _update_esn(old_esn)
    def load_manifest(self, viewable_id):
        """
        Loads the manifests for the given viewable_id and returns a mpd-XML-Manifest

        :param viewable_id: The id of of the viewable
        :return: MPD XML Manifest or False if no success
        """
        try:
            manifest = self._load_manifest(viewable_id, g.get_esn())
        except MSLError as exc:
            if 'Email or password is incorrect' in g.py2_decode(str(exc)):
                # Known cases when MSL error "Email or password is incorrect." can happen:
                # - If user change the password when the nf session was still active
                # - Netflix has reset the password for suspicious activity when the nf session was still active
                # Then clear the credentials and also user tokens.
                common.purge_credentials()
                self.msl_requests.crypto.clear_user_id_tokens()
            raise
        # Disable 1080p Unlock for now, as it is broken due to Netflix changes
        # if (g.ADDON.getSettingBool('enable_1080p_unlock') and
        #         not g.ADDON.getSettingBool('enable_vp9_profiles') and
        #         not has_1080p(manifest)):
        #     common.debug('Manifest has no 1080p viewables, trying unlock')
        #     manifest = self.get_edge_manifest(viewable_id, manifest)
        return self.__tranform_to_dash(manifest)
    def get_license(self, challenge, sid):
        """
        Requests and returns a license for the given challenge and sid
        :param challenge: The base64 encoded challenge
        :param sid: The sid paired to the challengew
        :return: Base64 representation of the licensekey or False unsuccessfull
        """
        common.debug('Requesting license')
        timestamp = int(time.time() * 10000)

        license_request_data = {
            'version': 2,
            'url': self.last_license_url,
            'id': timestamp,
            'languages': [g.LOCAL_DB.get_value('locale_id')],
            'params': [{
                'sessionId': sid,
                'clientTime': int(timestamp / 10000),
                'challengeBase64': challenge,
                'xid': str(timestamp + 1610)
            }],
            'echo': 'sessionId'
        }

        response = self._chunked_request(ENDPOINTS['license'], license_request_data, g.get_esn())
        return response[0]['licenseResponseBase64']
 def _show_only_forced_subtitle(self):
     # Forced stream not found, then fix Kodi bug if user chose to apply the workaround
     # Kodi bug???:
     # If the kodi player is set with "forced only" subtitle setting, Kodi use this behavior:
     # 1) try to select forced subtitle that matches audio language
     # 2) if missing the forced subtitle in language, then
     #    Kodi try to select: The first "forced" subtitle or the first "regular" subtitle
     #    that can respect the chosen language or not, depends on the available streams
     # So can cause a wrong subtitle language or in a permanent display of subtitles!
     # This does not reflect the setting chosen in the Kodi player and is very annoying!
     # There is no other solution than to disable the subtitles manually.
     audio_language = common.get_kodi_audio_language()
     if self.legacy_kodi_version:
         # --- ONLY FOR KODI VERSION 18 ---
         # NOTE: With Kodi 18 it is not possible to read the properties of the streams
         # so the only possible way is to read the data from the manifest file
         cache_identifier = g.get_esn() + '_' + self.videoid.value
         manifest_data = g.CACHE.get(CACHE_MANIFESTS, cache_identifier)
         common.fix_locale_languages(manifest_data['timedtexttracks'])
         if not any(
                 text_track.get('isForcedNarrative', False) is True
                 and text_track['language'] == audio_language
                 for text_track in manifest_data['timedtexttracks']):
             self.sc_settings.update({'subtitleenabled': False})
     else:
         # --- ONLY FOR KODI VERSION 19 ---
         # Check the current stream
         player_stream = self.player_state.get(
             STREAMS['subtitle']['current'])
         if not player_stream[
                 'isforced'] or player_stream['language'] != audio_language:
             self.sc_settings.update({'subtitleenabled': False})
Exemple #10
0
 def _process_event_request(self, event):
     """Do the event post request"""
     event.status = Event.STATUS_REQUESTED
     # Request attempts can be made up to a maximum of 3 times per event
     while event.is_attempts_granted():
         common.info('EVENT [{}] - Executing request (attempt {})', event, event.req_attempt)
         params = {'reqAttempt': event.req_attempt,
                   'reqPriority': 20 if event.event_type == EVENT_START else 0,
                   'reqName': 'events/{}'.format(event)}
         url = ENDPOINTS['events'] + '?' + urlencode(params).replace('%2F', '/')
         try:
             response = self.chunked_request(url, event.request_data, g.get_esn(), disable_msl_switch=False)
             event.set_response(response)
             break
         except Exception as exc:  # pylint: disable=broad-except
             common.error('EVENT [{}] - The request has failed: {}', event, exc)
     if event.event_type == EVENT_STOP:
         self.clear_queue()
         if event.event_data['is_in_mylist']:
             # If video is in my list, invalidate the continueWatching list (update lolomo context data)
             api.update_lolomo_context('continueWatching')
         else:
             # Else invalidate the 'queue' list (update lolomo context data)
             # Todo: get 'queue' lolomo id/index
             # api.update_lolomo_context('queue')
             pass
         api.update_videoid_bookmark(event.get_video_id())
     # Below commented lines: let future requests continue to be sent, unstable connections like wi-fi cause problems
     # if not event.is_response_success():
         # The event request is unsuccessful then there is some problem,
         # no longer make any future requests from this event id
     #     return False
     return True
Exemple #11
0
    def get_license(self, challenge, sid):
        """
        Requests and returns a license for the given challenge and sid

        :param challenge: The base64 encoded challenge
        :param sid: The sid paired to the challenge
        :return: Base64 representation of the license key or False unsuccessful
        """
        common.debug('Requesting license')

        timestamp = int(time.time() * 10000)
        xid = str(timestamp + 1610)
        params = [{
            'drmSessionId': sid,
            'clientTime': int(timestamp / 10000),
            'challengeBase64': challenge,
            'xid': xid
        }]
        response = self.msl_requests.chunked_request(
            ENDPOINTS['license'],
            self.msl_requests.build_request_data(self.last_license_url, params,
                                                 'drmSessionId'), g.get_esn())
        # This xid must be used also for each future Event request, until playback stops
        g.LOCAL_DB.set_value('xid', xid, TABLE_SESSION)

        self.licenses_xid.insert(0, xid)
        self.licenses_session_id.insert(0, sid)
        self.licenses_release_url.insert(
            0, response[0]['links']['releaseLicense']['href'])

        if self.msl_requests.msl_switch_requested:
            self.msl_requests.msl_switch_requested = False
            self.bind_events()
        return response[0]['licenseResponseBase64']
 def get_license(self, challenge, sid):
     """
     Requests and returns a license for the given challenge and sid
     :param challenge: The base64 encoded challenge
     :param sid: The sid paired to the challengew
     :return: Base64 representation of the licensekey or False unsuccessfull
     """
     common.debug('Requesting license')
     license_request_data = {
         'method': 'license',
         'licenseType': 'STANDARD',
         'clientVersion': '4.0004.899.011',
         'uiVersion': 'akira',
         'languages': ['de-DE'],
         'playbackContextId': self.last_playback_context,
         'drmContextIds': [self.last_drm_context],
         'challenges': [{
             'dataBase64': challenge,
             'sessionId': sid
         }],
         'clientTime': int(time.time()),
         'xid': int((int(time.time()) + 0.1612) * 1000)
     }
     response = self._chunked_request(ENDPOINTS['license'],
                                      license_request_data, g.get_esn())
     return response['result']['licenses'][0]['data']
Exemple #13
0
def _set_esn(esn):
    """
    Set the ESN in settings if it hasn't been set yet.
    Return True if the new ESN has been set, False otherwise
    """
    if not g.get_esn() and esn:
        g.LOCAL_DB.set_value('esn', esn, table=TABLE_SESSION)
        return True
    return False
Exemple #14
0
 def bind_events(self):
     """Bind events"""
     # I don't know the real purpose of its use, it seems to be requested after the license and before starting
     # playback, and only the first time after a switch,
     # in the response you can also understand if the msl switch has worked
     common.debug('Requesting bind events')
     response = self.msl_requests.chunked_request(ENDPOINTS['events'],
                                                  self.msl_requests.build_request_data('/bind', {}),
                                                  g.get_esn(),
                                                  disable_msl_switch=False)
     common.debug('Bind events response: {}', response)
Exemple #15
0
def _esn_checks():
    # Check if the custom esn is changed
    custom_esn = g.ADDON.getSetting('esn')
    custom_esn_old = g.LOCAL_DB.get_value('custom_esn', '',
                                          TABLE_SETTINGS_MONITOR)
    if custom_esn != custom_esn_old:
        g.LOCAL_DB.set_value('custom_esn', custom_esn, TABLE_SETTINGS_MONITOR)
        common.send_signal(signal=common.Signals.ESN_CHANGED, data=g.get_esn())

    if not custom_esn:
        # Check if "Force identification as L3 Widevine device" is changed (ANDROID ONLY)
        is_l3_forced = bool(g.ADDON.getSettingBool('force_widevine_l3'))
        is_l3_forced_old = g.LOCAL_DB.get_value('force_widevine_l3', False,
                                                TABLE_SETTINGS_MONITOR)
        if is_l3_forced != is_l3_forced_old:
            g.LOCAL_DB.set_value('force_widevine_l3', is_l3_forced,
                                 TABLE_SETTINGS_MONITOR)
            # If user has changed setting is needed clear previous ESN and perform a new handshake with the new one
            g.LOCAL_DB.set_value('esn',
                                 common.generate_android_esn() or '',
                                 TABLE_SESSION)
            common.send_signal(signal=common.Signals.ESN_CHANGED,
                               data=g.get_esn())
Exemple #16
0
    def _load_msl_data(self, msl_data):
        try:
            self.crypto.load_msl_data(msl_data)
            self.crypto.load_crypto_session(msl_data)

            # Add-on just installed, the service starts but there is no esn
            if g.get_esn():
                # This is also done here only try to speed up the loading of manifest
                self._check_mastertoken_validity()
        except MSLError:
            raise
        except Exception:  # pylint: disable=broad-except
            import traceback
            common.error(traceback.format_exc())
Exemple #17
0
    def load_manifest(self, viewable_id):
        """
        Loads the manifests for the given viewable_id and returns a mpd-XML-Manifest

        :param viewable_id: The id of of the viewable
        :return: MPD XML Manifest or False if no success
        """
        manifest = self._load_manifest(viewable_id, g.get_esn())
        # Disable 1080p Unlock for now, as it is broken due to Netflix changes
        # if (g.ADDON.getSettingBool('enable_1080p_unlock') and
        #         not g.ADDON.getSettingBool('enable_vp9_profiles') and
        #         not has_1080p(manifest)):
        #     common.debug('Manifest has no 1080p viewables, trying unlock')
        #     manifest = self.get_edge_manifest(viewable_id, manifest)
        return self.__tranform_to_dash(manifest)
Exemple #18
0
    def perform_key_handshake(self, data=None):  # pylint: disable=unused-argument
        """Perform a key handshake and initialize crypto keys"""
        esn = g.get_esn()
        if not esn:
            common.warn('Cannot perform key handshake, missing ESN')
            return False

        common.info('Performing key handshake with ESN: {}',
                    common.censure(esn) if g.ADDON.getSetting('esn') else esn)
        response = _process_json_response(self._post(ENDPOINTS['manifest'], self.handshake_request(esn)))
        header_data = self.decrypt_header_data(response['headerdata'], False)
        self.crypto.parse_key_response(header_data, esn, True)

        # Delete all the user id tokens (are correlated to the previous mastertoken)
        self.crypto.clear_user_id_tokens()
        common.debug('Key handshake successful')
        return True
Exemple #19
0
    def release_license(self, data=None):  # pylint: disable=unused-argument
        """Release the server license"""
        common.debug('Requesting releasing license')

        params = [{
            'url': self.last_license_release_url,
            'params': {
                'sessionId': self.last_license_session_id,
                'xid': g.LOCAL_DB.get_value('xid', table=TABLE_SESSION)
            },
            'echo': 'sessionId'
        }]

        response = self.msl_requests.chunked_request(
            ENDPOINTS['license'],
            self.msl_requests.build_request_data('/bundle', params),
            g.get_esn())
        common.debug('License release response: {}', response)
Exemple #20
0
 def _get_owner_user_id_token(self):
     """A way to get the user token id of owner profile"""
     # In order to get a user id token of another (non-owner) profile you must make a request with SWITCH_PROFILE
     # authentication scheme (a custom authentication for netflix), and this request can be directly included
     # in the MSL manifest request.
     # But in order to execute this switch profile, you need to have the user id token of the main (owner) profile.
     # The only way (found to now) to get it immediately, is send a logblob event request, and save the
     # user id token obtained in the response.
     common.debug('Requesting logblog')
     params = {'reqAttempt': 1,
               'reqPriority': 0,
               'reqName': EVENT_BIND}
     url = ENDPOINTS['logblobs'] + '?' + urlencode(params).replace('%2F', '/')
     response = self.chunked_request(url,
                                     self.build_request_data('/logblob', generate_logblobs_params()),
                                     g.get_esn(),
                                     force_auth_credential=True)
     common.debug('Response of logblob request: {}', response)
Exemple #21
0
 def __init__(self):
     # pylint: disable=broad-except
     self.request_builder = None
     try:
         msl_data = json.loads(common.load_file('msl_data.json'))
         common.info('Loaded MSL data from disk')
     except Exception:
         msl_data = None
     try:
         self.request_builder = MSLRequestBuilder(msl_data)
         # Addon just installed, the service starts but there is no esn
         if g.get_esn():
             self.check_mastertoken_validity()
     except Exception:
         import traceback
         common.error(traceback.format_exc())
     common.register_slot(signal=common.Signals.ESN_CHANGED,
                          callback=self.perform_key_handshake)
    def perform_key_handshake(self, data=None):
        """Perform a key handshake and initialize crypto keys"""
        # pylint: disable=unused-argument
        esn = data or g.get_esn()
        if not esn:
            common.info('Cannot perform key handshake, missing ESN')
            return

        common.debug('Performing key handshake. ESN: {}'.format(esn))

        response = _process_json_response(
            self._post(ENDPOINTS['manifest'],
                       self.request_builder.handshake_request(esn)))
        headerdata = json.loads(
            base64.standard_b64decode(response['headerdata']))
        self.request_builder.crypto.parse_key_response(
            headerdata, not common.is_edge_esn(esn))
        common.debug('Key handshake successful')
Exemple #23
0
    def perform_key_handshake(self, data=None):
        """Perform a key handshake and initialize crypto keys"""
        # pylint: disable=unused-argument
        esn = data or g.get_esn()
        if not esn:
            common.info('Cannot perform key handshake, missing ESN')
            return False

        common.debug('Performing key handshake. ESN: {}', esn)

        response = _process_json_response(
            self._post(ENDPOINTS['manifest'],
                       self.request_builder.handshake_request(esn)))
        header_data = self.request_builder.decrypt_header_data(
            response['headerdata'], False)
        self.request_builder.crypto.parse_key_response(
            header_data, not common.is_edge_esn(esn))
        # Reset the user id token
        self.request_builder.user_id_token = None
        common.debug('Key handshake successful')
        return True
Exemple #24
0
 def _mastertoken_checks(self):
     """Perform checks to the MasterToken and executes a new key handshake when necessary"""
     is_handshake_required = False
     if self.crypto.mastertoken:
         if self.crypto.is_current_mastertoken_expired():
             common.debug('Stored MSL MasterToken is expired, a new key handshake will be performed')
             is_handshake_required = True
         else:
             # Check if the current ESN is same of ESN bound to MasterToken
             if g.get_esn() != self.crypto.bound_esn:
                 common.debug('Stored MSL MasterToken is bound to a different ESN, '
                              'a new key handshake will be performed')
                 is_handshake_required = True
     else:
         common.debug('MSL MasterToken is not available, a new key handshake will be performed')
         is_handshake_required = True
     if is_handshake_required:
         if self.perform_key_handshake():
             msl_data = json.loads(common.load_file(MSL_DATA_FILENAME))
             self.crypto.load_msl_data(msl_data)
             self.crypto.load_crypto_session(msl_data)
 def _process_event_request(self, event):
     """Do the event post request"""
     event.status = Event.STATUS_REQUESTED
     # Request attempts can be made up to a maximum of 3 times per event
     while event.is_attempts_granted():
         common.info('EVENT [{}] - Executing request (attempt {})', event, event.req_attempt)
         params = {'reqAttempt': event.req_attempt,
                   'reqPriority': 20 if event.event_type == EVENT_START else 0,
                   'reqName': 'events/{}'.format(event)}
         url = ENDPOINTS['events'] + '?' + urlencode(params).replace('%2F', '/')
         try:
             response = self.chunked_request(url, event.request_data, g.get_esn(), disable_msl_switch=False)
             event.set_response(response)
             break
         except Exception as exc:  # pylint: disable=broad-except
             common.error('EVENT [{}] - The request has failed: {}', event, exc)
     if event.event_type == EVENT_STOP:
         self.clear_queue()
         # api.update_lolomo_context('continueWatching', video_id=event.get_video_id())
     if not event.is_response_success():
         # The event request is unsuccessful then there is some problem,
         # no longer make any future requests from this event id
         return False
     return True
Exemple #26
0
def _update_esn(old_esn):
    """Perform key handshake if the esn has changed on Session initialization"""
    current_esn = g.get_esn()
    if old_esn != current_esn:
        common.send_signal(signal=common.Signals.ESN_CHANGED, data=current_esn)
Exemple #27
0
 def _verify_esn_existence(self):
     # if for any reason esn is no longer exist get one
     if not g.get_esn():
         return self._refresh_session_data()
     return True
Exemple #28
0
 def update_session_data(self, old_esn=None):
     old_esn = old_esn or g.get_esn()
     self.set_session_header_data()
     cookies.save(self.account_hash, self.session.cookies)
     _update_esn(old_esn)
Exemple #29
0
 def load_msl_data(self, msl_data=None):
     self._msl_data = msl_data if msl_data else {}
     if msl_data:
         self.set_mastertoken(msl_data['tokens']['mastertoken'])
         self.bound_esn = msl_data.get('bound_esn', g.get_esn())
Exemple #30
0
 def view_esn(self, pathitems=None):  # pylint: disable=unused-argument
     """Show the ESN in use"""
     ui.show_ok_dialog(common.get_local_string(30016), g.get_esn())