diff --git a/resources/lib/services/msl/msl_request_builder.py b/resources/lib/services/msl/msl_request_builder.py index dfc10ed4a..f989f1e33 100644 --- a/resources/lib/services/msl/msl_request_builder.py +++ b/resources/lib/services/msl/msl_request_builder.py @@ -14,8 +14,10 @@ import random import time -from resources.lib.globals import G import resources.lib.common as common +from resources.lib.common.exceptions import MSLError +from resources.lib.globals import G +from resources.lib.services.msl.msl_utils import MSL_AUTH_USER_ID_TOKEN, MSL_AUTH_EMAIL_PASSWORD, MSL_AUTH_NETFLIXID from resources.lib.utils.logging import measure_exec_time_decorator @@ -126,14 +128,16 @@ def decrypt_header_data(self, data, enveloped=True): def _add_auth_info(self, header_data, auth_data): """User authentication identifies the application user associated with a message""" - # Warning: the user id token contains also contains the identity of the netflix profile - # therefore it is necessary to use the right user id token for the request - if auth_data.get('user_id_token'): + if auth_data['auth_scheme'] == MSL_AUTH_USER_ID_TOKEN: + # Authentication scheme with: User ID token + # Make requests by using by default main netflix profile, since the user id token contains also the identity + # of the netflix profile, to send data to the right profile (e.g. for continue watching) must be used + # SWITCH_PROFILE scheme to switching MSL profile. + # 25/09/2022: SWITCH_PROFILE auth scheme has been disabled on netflix website backend and not works anymore. if auth_data['use_switch_profile']: - # The SWITCH_PROFILE is a custom Netflix MSL user authentication scheme - # that is needed for switching profile on MSL side - # works only combined with user id token and can not be used with all endpoints - # after use it you will get user id token of the profile specified in the response + # The SWITCH_PROFILE is a custom Netflix MSL user authentication scheme, that is needed for switching + # profile on MSL side, works only combined with user id token and can not be used with all endpoints + # after use it you will get the user id token of the requested profile in the response. header_data['userauthdata'] = { 'scheme': 'SWITCH_PROFILE', 'authdata': { @@ -142,10 +146,10 @@ def _add_auth_info(self, header_data, auth_data): } } else: - # Authentication with user ID token containing the user identity (netflix profile) header_data['useridtoken'] = auth_data['user_id_token'] - else: - # Authentication with the user credentials + elif auth_data['auth_scheme'] == MSL_AUTH_EMAIL_PASSWORD: + # Authentication scheme with: Email password + # Make requests by using main netflix profile only (you cannot update continue watching to other profiles) credentials = common.get_credentials() header_data['userauthdata'] = { 'scheme': 'EMAIL_PASSWORD', @@ -154,13 +158,18 @@ def _add_auth_info(self, header_data, auth_data): 'password': credentials['password'] } } - # Authentication with user Netflix ID cookies - # This not works on android, - # will raise: User authentication data does not match entity identity - # header_data['userauthdata'] = { - # 'scheme': 'NETFLIXID', - # 'authdata': { - # 'netflixid': cookies['NetflixId'], - # 'securenetflixid': cookies['SecureNetflixId'] - # } - # } + elif auth_data['auth_scheme'] == MSL_AUTH_NETFLIXID: + # Authentication scheme with: Netflix ID cookies + # Make requests by using the same netflix profile used/set on nfsession (website) + + # Workaround to get updated auth data from nfsession + data = common.make_http_call('get_auth_data', {'placeholder_data': ''}) + header_data['userauthdata'] = { + 'scheme': 'NETFLIXID', + 'authdata': { + 'netflixid': data['NetflixId'], + 'securenetflixid': data['SecureNetflixId'] + } + } + else: + raise MSLError('Authentication scheme not supported.') diff --git a/resources/lib/services/msl/msl_requests.py b/resources/lib/services/msl/msl_requests.py index fdfcda3d9..884a359b5 100644 --- a/resources/lib/services/msl/msl_requests.py +++ b/resources/lib/services/msl/msl_requests.py @@ -23,7 +23,8 @@ from resources.lib.globals import G from resources.lib.services.msl.msl_request_builder import MSLRequestBuilder from resources.lib.services.msl.msl_utils import (display_error_info, generate_logblobs_params, ENDPOINTS, - MSL_DATA_FILENAME, create_req_params) + MSL_DATA_FILENAME, create_req_params, MSL_AUTH_NETFLIXID, + MSL_AUTH_USER_ID_TOKEN) from resources.lib.services.tcp_keep_alive import enable_tcp_keep_alive from resources.lib.utils.esn import get_esn from resources.lib.utils.logging import LOG, measure_exec_time_decorator, perf_clock @@ -32,6 +33,8 @@ class MSLRequests(MSLRequestBuilder): """Provides methods to make MSL requests""" + MSL_AUTH_SCHEME = MSL_AUTH_NETFLIXID + def __init__(self, msl_data=None): super(MSLRequests, self).__init__() from requests import session @@ -162,12 +165,17 @@ def _check_user_id_token(self, disable_msl_switch, force_auth_credential=False): def chunked_request(self, endpoint, request_data, esn, disable_msl_switch=True, force_auth_credential=False): """Do a POST request and process the chunked response""" self._mastertoken_checks() - auth_data = self._check_user_id_token(disable_msl_switch, force_auth_credential) + + auth_data = {'auth_scheme': self.MSL_AUTH_SCHEME} + + if self.MSL_AUTH_SCHEME == MSL_AUTH_USER_ID_TOKEN: + auth_data = self._check_user_id_token(disable_msl_switch, force_auth_credential) + LOG.debug('Chunked request will be executed with auth data: {}', auth_data) chunked_response = self._process_chunked_response( self._post(endpoint, self.msl_request(request_data, esn, auth_data)), - save_uid_token_to_owner=auth_data['user_id_token'] is None) + save_uid_token_to_owner=auth_data.get('user_id_token') is None) return chunked_response['result'] def _post(self, endpoint, request_data): diff --git a/resources/lib/services/msl/msl_utils.py b/resources/lib/services/msl/msl_utils.py index 3385f5b44..2af75bed5 100644 --- a/resources/lib/services/msl/msl_utils.py +++ b/resources/lib/services/msl/msl_utils.py @@ -45,6 +45,10 @@ 'logblobs': CHROME_PLAYAPI_URL + 'logblob/1' } +MSL_AUTH_NETFLIXID = 'NETFLIXID' # Netflix ID cookies user authentication +MSL_AUTH_EMAIL_PASSWORD = 'EMAIL_PASSWORD' # Email password user authentication +MSL_AUTH_USER_ID_TOKEN = 'USER_ID_TOKEN' # User ID token user authentication + MSL_DATA_FILENAME = 'msl_data.json' EVENT_START = 'start' # events/start : Video starts diff --git a/resources/lib/services/nfsession/nfsession_ops.py b/resources/lib/services/nfsession/nfsession_ops.py index 273dafa7c..f6bcc88ca 100644 --- a/resources/lib/services/nfsession/nfsession_ops.py +++ b/resources/lib/services/nfsession/nfsession_ops.py @@ -49,7 +49,8 @@ def __init__(self): self.get_metadata, self.update_loco_context, self.update_videoid_bookmark, - self.get_loco_data + self.get_loco_data, + self.get_auth_data ] # Share the activate profile function to SessionBase class self.external_func_activate_profile = self.activate_profile @@ -91,6 +92,14 @@ def fetch_initial_page(self): self.session.cookies.clear() self.login() + def get_auth_data(self, placeholder_data): # pylint: disable=unused-argument + """Workaround to get auth data""" + data = { + 'NetflixId': self.session.cookies['NetflixId'], + 'SecureNetflixId': self.session.cookies['SecureNetflixId'] + } + return data + @measure_exec_time_decorator(is_immediate=True) def activate_profile(self, guid): """Set the profile identified by guid as active"""