def get_secure_token(secure_url, video_id): """send our embed token back with a few other url encoded parameters""" res = sess.get(secure_url) try: parsed_json = json.loads(res.text) except ValueError: utils.log('Failed to load JSON. Data is: {0}'.format(res.text)) if '<html' in res.text: # smart DNS redirects raise AussieAddonsException( 'Failed to get authorization token. Please ensure any smart ' 'DNS service is disabled.') else: raise Exception('Failed to get authorization token.') if parsed_json.get('authorized') is False: raise AussieAddonsException('Failed to get authorization token: {0}' ''.format(parsed_json.get('message'))) auth_data = parsed_json.get('authorization_data') utils.log('auth_data: %s' % auth_data) video = auth_data.get(video_id) if video.get('authorized') is False: raise AussieAddonsException('Failed to obtain secure token: {0}.\n' 'Check your subscription is valid.'.format( video.get('message'))) try: streams = video.get('streams') ios_token = streams[0]['url']['data'] return base64.b64decode(ios_token) except Exception as e: raise AussieAddonsException('Failed to get stream URL: {0}'.format(e))
def get_embed_token(pai, bearer, video_id): """ send our user token to get our embed token, including api key """ url = config.TELSTRA_AUTH_URL.format(code=video_id, pai=pai) sess.headers = {} sess.headers.update({'Authorization': 'Bearer {0}'.format(bearer)}) try: req = sess.get(url) data = req.text json_data = json.loads(data) if json_data.get('ErrorCode') is not None: raise AussieAddonsException() embed_token = json_data.get('token') except requests.exceptions.HTTPError as e: utils.log('Error getting embed token. ' 'Response: {0}'.format(e.response.text)) cache.delete('SOCCERTICKET') if e.response.status_code == 401: raise AussieAddonsException('Login token has expired, ' 'please try again.') else: raise e return urllib.quote_plus(embed_token)
def get_embed_token(user_token, video_id): """ send our user token to get our embed token, including api key """ url = config.EMBED_TOKEN_URL.format(video_id) sess.headers.update({ 'X-YinzCam-Ticket': user_token, 'Accept': 'application/json' }) try: req = sess.get(url) data = req.text json_data = json.loads(data) if json_data.get('ErrorCode') is not None: raise AussieAddonsException() video_token = json_data.get('VideoToken') except requests.exceptions.HTTPError as e: utils.log('Error getting embed token. ' 'Response: {0}'.format(e.response.text)) cache.delete('NETBALLTICKET') if e.response.status_code == 401: raise AussieAddonsException('Login token has expired, ' 'please try again.') else: raise e return urllib.quote(video_token)
def get_media_auth_token(pai, video_id): """ send our user token to get our embed token, including api key """ url = config.MEDIA_AUTH_URL.format(code=video_id, pai=pai) try: data = comm.fetch_url(url, request_token=True) json_data = json.loads(data) if json_data.get('Fault'): raise AussieAddonsException( json_data.get('fault').get('faultstring')) media_auth_token = json_data.get('urlSigningToken') except requests.exceptions.HTTPError as e: utils.log('Error getting embed token. ' 'Response: {0}'.format(e.response.text)) cache.delete('AFLTOKEN') if e.response.status_code in [400, 401]: raise AussieAddonsException('Login token has expired, ' 'please try again.') elif e.response.status_code == 404: raise AussieAddonsException( 'Unknown error, please wait a few moments and try again.') else: raise e return media_auth_token
def get_media_auth_token(ticket, video_id): """ send our user token to get our embed token, including api key """ url = config.MEDIA_AUTH_URL.format(video_id=video_id) sess.headers = {} sess.headers.update({ 'X-YinzCam-Ticket': ticket, 'Accept': 'application/json' }) try: req = sess.get(url) data = req.text json_data = json.loads(data) if json_data.get('Fault'): raise AussieAddonsException( json_data.get('fault').get('faultstring')) media_auth_token = json_data.get('VideoToken') except requests.exceptions.HTTPError as e: utils.log('Error getting embed token. ' 'Response: {0}'.format(e.response.text)) cache.delete('NETBALLTICKET') if e.response.status_code == 401: raise AussieAddonsException('Login token has expired, ' 'please try again.') else: raise e return media_auth_token
def request(self, method, url, *args, **kwargs): """Send the request after generating the complete URL.""" utils.log("Performing {0} for {1}".format(method, url)) try: req = super(Session, self).request(method, url, *args, **kwargs) req.raise_for_status() except SSLError as e: msg = ('SSL Error: {0}. This is usually due to an old version of ' 'Kodi. Please upgrade to Kodi v17 or later.'.format(e)) raise AussieAddonsException(msg) except requests.exceptions.HTTPError as e: raise e except Exception as e: raise AussieAddonsException('Error: {0}'.format(e)) return req
def get_embed_token(login_ticket, videoId): """ send our user token to get our embed token, including api key """ data = create_nrl_userid_xml(userToken) url = config.EMBED_TOKEN_URL.format(videoId) try: req = sess.post(url, data=data, headers=config.YINZCAM_AUTH_HEADERS, verify=False) xml = req.text[1:] try: tree = ET.fromstring(xml) except ET.ParseError as e: utils.log('Embed token response is: {0}'.format(xml)) cache.delete('NRLTOKEN') raise e if tree.find('ErrorCode') is not None: utils.log('Errorcode found: {0}'.format(xml)) raise AussieAddonsException() token = tree.find('Token').text except AussieAddonsException: cache.delete('NRLTOKEN') raise Exception('Login token has expired, please try again') return token
def get_secure_token(secure_url, videoId): """send our embed token back with a few other url encoded parameters""" res = session.get(secure_url) data = res.text try: parsed_json = json.loads(data) for stream in parsed_json['authorization_data'][videoId]['streams']: if stream.get('delivery_type') == 'dash': dash_url = stream['url'].get('data') wv_lic = stream.get('widevine_server_path') except KeyError: utils.log('Parsed json data: {0}'.format(parsed_json)) try: auth_msg = parsed_json['authorization_data'][videoId]['message'] if auth_msg == 'unauthorizedlocation': country = parsed_json['user_info']['country'] raise AussieAddonsException('Unauthorised location for ' 'streaming. ' 'Detected location is: {0}. ' 'Please check VPN/smart DNS ' 'settings and try again' ''.format(country)) except Exception as e: raise e return {'dash_url': base64.b64decode(dash_url), 'wv_lic': wv_lic}
def get_secure_token(secure_url, videoId): """ send our embed token back with a few other url encoded parameters """ res = sess.get(secure_url) data = res.text try: parsed_json = json.loads(data) token = (parsed_json['authorization_data'][videoId]['streams'][0] ['url']['data']) except KeyError: utils.log('Parsed json data: {0}'.format(parsed_json)) try: auth_msg = parsed_json['authorization_data'][videoId]['message'] if auth_msg == 'unauthorized location': country = parsed_json['user_info']['country'] raise AussieAddonsException('Unauthorised location for ' 'streaming. ' 'Detected location is: {0}. ' 'Please check VPN/smart DNS ' 'settings ' ' and try again'.format(country)) except Exception as e: raise e return base64.b64decode(token)
def get_embed_token(login_ticket, videoId): """ send our user token to get our embed token, including api key """ url = config.EMBED_TOKEN_URL.format(videoId) try: headers = {} headers.update({ 'X-YinzCam-AppID': 'NRL_LIVE', 'X-YinzCam-Ticket': login_ticket, 'Content-Type': 'application/xml', 'Accept': 'application/xml', 'Accept-Encoding': 'gzip', 'User-Agent': config.USER_AGENT, 'Connection': 'close' }) sess.headers = headers try: req = sess.get(url, verify=False) xml = req.text except requests.exceptions.HTTPError as e: if e.response.status_code == 401: cache.delete('NRLTICKET') raise AussieAddonsException('Login token has expired, ' 'please try again.') elif e.response.status_code == 403: cache.delete('NRLTICKET') tree = ET.fromstring(e.response.text) msg = str(tree.find('UserMessage').find('Content').text) raise AussieAddonsException(msg) else: raise e try: tree = ET.fromstring(xml) except ET.ParseError as e: utils.log('Embed token response is: {0}'.format(xml)) cache.delete('NRLTICKET') raise e if tree.find('ErrorCode') is not None: utils.log('Errorcode found: {0}'.format(xml)) raise AussieAddonsException('Login token has expired, ' 'please try again.') token = tree.find('VideoToken').text except AussieAddonsException as e: cache.delete('NRLTICKET') raise e return token
def get_paid_token(username, password): """ Obtain a valid token from Telstra/Yinzcam, will be used to make requests for Ooyala embed tokens """ session = custom_session.Session(force_tlsv1=False) auth_resp = session.get(config.NRL_AUTH, allow_redirects=False) xsrf = auth_resp.cookies['XSRF-TOKEN'] session.headers.update({'x-xsrf-token': xsrf}) data = {'emailAddress': '{0}'.format(username), 'password': '******'.format(password)} login_resp = session.post(config.NRL_LOGIN, json=data) login_resp_json = json.loads(login_resp.text) if not login_resp_json.get('success') == True: # noqa: E712 raise AussieAddonsException( 'Login failed for nrl.com: {0}'.format( login_resp_json.get('error'))) auth2_resp = session.get(config.NRL_AUTH, allow_redirects=False) redirect_url = auth2_resp.headers.get('Location') redirect_pieces = urlparse.urlsplit(redirect_url) redirect_query = dict(urlparse.parse_qsl(redirect_pieces.query)) code = redirect_query.get('code') token_form = {'code': code} token_form.update(config.TOKEN_DATA) session.headers = {} session.cookies.clear() token_resp = session.post(config.NRL_TOKEN, data=token_form) refresh_token = json.loads(token_resp.text).get('refresh_token') session.headers.update({'Content-Type': 'application/xml', 'Accept': 'application/json, text/plain, */*'}) ticket_signon = session.post( config.YINZCAM_AUTH_URL, data=config.NEW_LOGIN_DATA2.format(refresh_token)) ticket = json.loads(ticket_signon.text).get('Ticket') # check validity of subscription session.headers.update({'X-YinzCam-Ticket': ticket}) sub_status = session.get(config.STATUS_URL) status_json = json.loads(sub_status.text) if status_json.get('Valid') != 'true': raise AussieAddonsException('NRL.com login failed: {0}'.format( status_json.get('Reason'))) return ticket
def get_embed_token(user_token, video_id): """send our user token to get our embed token, including api key""" try: comm.update_token(sess) embed_token_url = config.EMBED_TOKEN_URL.format(user_token, video_id) utils.log("Fetching embed token: {0}".format(embed_token_url)) try: res = sess.get(embed_token_url) except requests.exceptions.SSLError: cache.delete('AFLTOKEN') raise AussieAddonsException( 'Your version of Kodi is too old to support live streaming. ' 'Please upgrade to the latest version.') except requests.exceptions.HTTPError as e: subscription_type = get_sub_type() if subscription_type == 0: # paid afl.com.au/linked cache.delete('AFLTOKEN') raise AussieAddonsException( 'Paid or linked subscription not found for supplied username ' 'and password. Please check the subscription type in settings ' 'is correct or your subscription has been linked to your ' 'Telstra ID in the Android/iOS app') elif subscription_type in [1, 3]: # free/mobile sub cache.delete('AFLTOKEN') utils.log(e.response.text) if e.response.status_code == 400: raise AussieAddonsException( 'Stored login token has expired, please try to play this ' 'item again. If this error persists please submit an ' 'issue on our github (github.com/aussieaddons/plugin.' 'video.afl-video') else: raise e else: # in-app purchase/manual raise AussieAddonsException( 'mis-uuid token is invalid, please check the token in ' 'the settings is correct and try again') data = json.loads(res.text) return quote(data.get('token'))
def make_list(params): utils.log('Making video list...') cache = True try: if 'team' in params: videos = comm.get_team_videos(params.get('team')) elif 'round_id' in params: videos = comm.get_round_videos(params.get('round_id')) elif params.get('category') == 'Live Matches': videos = comm.get_live_videos() cache = False elif params.get('category') == 'AFLW': videos = comm.get_aflw_videos() else: try: category = config.CATEGORY_LOOKUP[params.get('category')] except KeyError as e: xbmcgui.Dialog().ok( 'Outdated Favourites Link', 'The Kodi Favourite item being accessed was created with ' 'an earlier version of the AFL Video add-on and is no ' 'longer compatible. Please remove this link and update ' 'with a new one.') raise AussieAddonsException(e) videos = comm.get_category_videos(category) ok = True for v in videos: listitem = xbmcgui.ListItem(label=v.get_title()) thumb = v.get_thumbnail() listitem.setArt({'icon': thumb, 'thumb': thumb}) listitem.setInfo('video', v.get_kodi_list_item()) listitem.addStreamInfo('video', v.get_kodi_stream_info()) if not v.isdummy: listitem.setProperty('IsPlayable', 'true') # Build the URL for the program, including the list_info url = "%s?%s" % (sys.argv[0], v.make_kodi_url()) # Add the program item to the list ok = xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]), url=url, listitem=listitem, isFolder=False) xbmcplugin.endOfDirectory(handle=int(sys.argv[1]), succeeded=ok, cacheToDisc=cache) xbmcplugin.setContent(handle=int(sys.argv[1]), content='episodes') except Exception: utils.handle_error('Unable to fetch video list')
def fetch_bc_url(url, headers={}): """ Use fetch_url and catch Brightcove API errors """ try: data = cache.getData(url=url, headers=headers, noCache=True) return data except requests.exceptions.HTTPError as e: utils.log(e.response.text) if e.response.status_code == 403: try: error_data = json.loads(e.response.text) if error_data[0].get('error_subcode') == 'CLIENT_GEO': raise AussieAddonsException( 'Content is geoblocked, your detected country is: {0}' ''.format(error_data[0].get('client_geo'))) else: raise e except IndexError: raise e except ValueError: raise else: raise e
def get_user_token(): """Send user login info and retrieve token for session""" # in-app purchase/manual if subscription_type == 2: iap_token = addon.getSetting('IAP_TOKEN').lower() try: int(iap_token, 16) except ValueError: raise AussieAddonsException( 'mis-uuid token must be 32 characters in length, and only ' 'contain numbers 0-9 and letters a-f') if len(iap_token) != 32: raise AussieAddonsException( 'mis-uuid token must be 32 characters in length, and only ' 'contain numbers 0-9 and letters a-f') token = 'mis-uuid-{0}'.format(iap_token) utils.log('Using manual token: {0}******'.format(token[:-6])) return token stored_token = cache.get('AFLTOKEN') if stored_token: utils.log('Using token: {0}******'.format(stored_token[:-6])) return stored_token if addon.getSetting('LIVE_SUBSCRIPTION') == 'true': username = addon.getSetting('LIVE_USERNAME') password = addon.getSetting('LIVE_PASSWORD') if subscription_type == 1: # free subscription token = telstra_auth.get_token(username, password) else: # paid afl.com.au login_data = { 'userIdentifier': addon.getSetting('LIVE_USERNAME'), 'authToken': addon.getSetting('LIVE_PASSWORD'), 'userIdentifierType': 'EMAIL' } login_json = fetch_session_id(config.LOGIN_URL, login_data) data = json.loads(login_json) if data.get('responseCode') != 0: raise AussieAddonsException('Invalid Telstra ID login/' 'password for paid afl.com.au ' 'subscription.') session_id = data['data'].get('artifactValue') try: sess.headers.update({'Authorization': None}) encoded_session_id = urllib.quote(session_id) session_url = config.SESSION_URL.format(encoded_session_id) res = sess.get(session_url) data = json.loads(res.text) token = data.get('uuid') except requests.exceptions.HTTPError as e: utils.log(e.response.text) raise e cache.set('AFLTOKEN', token) utils.log('Using token: {0}******'.format(token[:-6])) return token else: raise AussieAddonsException('AFL Live Pass subscription is required ' 'for this content. Please open the ' 'add-on settings to enable and configure.')
def get_free_token(username, password): """ Obtain a valid token from Telstra/Yinzcam, will be used to make requests for Ooyala embed tokens """ session = custom_session.Session(force_tlsv1=False) prog_dialog = xbmcgui.DialogProgress() prog_dialog.create('Logging in with Telstra ID') # Send our first login request to Yinzcam, recieve (unactivated) ticket prog_dialog.update(1, 'Obtaining oauth token') userid = uuid.uuid4() config.OAUTH_DATA.update({'x-user-id': userid}) oauth_resp = session.post(config.OAUTH_URL, data=config.OAUTH_DATA) oauth_json = json.loads(oauth_resp.text) access_token = oauth_json.get('access_token') session.headers = {} session.headers.update( {'Authorization': 'Bearer {0}'.format(access_token)}) # Check entitlements (not sure if needed) session.get(config.ENTITLEMENTS_URL) prog_dialog.update(16, 'Getting SSO Client ID') # GET to our spc url and receive SSO client ID session.headers = config.SPC_HEADERS # check if needed spc_url = config.SPC_URL.format(userid) spc_resp = session.get(spc_url) sso_token_match = re.search('ssoClientId = "(\w+)"', spc_resp.text) try: sso_token = sso_token_match.group(1) except AttributeError as e: utils.log('SPC login response: {0}'.format(spc_resp.text)) raise e # Sign in to telstra.com with our SSO client id to get the url # for retrieving the bearer token for media orders prog_dialog.update(33, 'Signing on to telstra.com') sso_params = config.SSO_PARAMS sso_params.update({ 'client_id': sso_token, 'state': binascii.b2a_hex(os.urandom(16)), 'nonce': binascii.b2a_hex(os.urandom(16)) }) sso_auth_resp = session.get(config.SSO_URL, params=sso_params) sso_url = dict(urlparse.parse_qsl(urlparse.urlsplit( sso_auth_resp.url)[3])).get('goto') # login to telstra.com.au and get our BPSESSION cookie session.headers.update(config.SIGNON_HEADERS) signon_data = config.SIGNON_DATA signon_data = {'username': username, 'password': password, 'goto': sso_url} signon = session.post(config.SIGNON_URL, data=signon_data, allow_redirects=False) bp_session = session.cookies.get_dict().get('BPSESSION') # check signon is valid (correct username/password) signon_pieces = urlparse.urlsplit(signon.headers.get('Location')) signon_query = dict(urlparse.parse_qsl(signon_pieces.query)) utils.log('Sign-on result: %s' % signon_query) if 'errorcode' in signon_query: if signon_query['errorcode'] == '0': raise TelstraAuthException('Please enter your username ' 'in the settings') if signon_query['errorcode'] == '1': raise TelstraAuthException('Please enter your password ' 'in the settings') if signon_query['errorcode'] == '2': raise TelstraAuthException('Please enter your username and ' 'password in the settings') if signon_query['errorcode'] == '3': raise TelstraAuthException('Invalid Telstra ID username/password. ' 'Please check your username and ' 'password in the settings') # Use BPSESSION cookie to ask for bearer token sso_headers = config.SSO_HEADERS sso_headers.update({'Cookie': 'BPSESSION={0}'.format(bp_session)}) session.headers = sso_headers sso_token_resp = session.get(sso_url) bearer_token = dict( urlparse.parse_qsl(urlparse.urlsplit( sso_token_resp.url)[4]))['access_token'] # First check if there are any eligible services attached to the account prog_dialog.update(50, 'Determining eligible services') offer_id = dict(urlparse.parse_qsl( urlparse.urlsplit(spc_url)[3]))['offerId'] media_order_headers = config.MEDIA_ORDER_HEADERS media_order_headers.update( {'Authorization': 'Bearer {0}'.format(bearer_token)}) session.headers = media_order_headers try: offers = session.get(config.OFFERS_URL) except requests.exceptions.HTTPError as e: if e.response.status_code == 404: message = json.loads(e.response.text).get('userMessage') message += (' Please visit {0} '.format(config.HUB_URL) + 'for further instructions to link your mobile ' 'service to the supplied Telstra ID') raise TelstraAuthException(message) else: raise TelstraAuthException(e) try: offer_data = json.loads(offers.text) offers_list = offer_data['data']['offers'] ph_no = None for offer in offers_list: if offer.get('name') != 'My Football Live Pass': continue data = offer.get('productOfferingAttributes') ph_no = [x['value'] for x in data if x['name'] == 'ServiceId'][0] if not ph_no: raise TelstraAuthException( 'Unable to determine if you have any eligible services. ' 'Please ensure there is an eligible service linked to ' 'your Telstra ID to redeem the free offer. Please visit ' '{0} for further instructions'.format(config.HUB_URL)) except Exception as e: raise e # 'Order' the subscription package to activate the service prog_dialog.update(66, 'Activating live pass on service') order_data = config.MEDIA_ORDER_JSON.format(ph_no, offer_id, userid) order = session.post(config.MEDIA_ORDER_URL, data=order_data) # check to make sure order has been placed correctly if order.status_code == 201: try: order_json = json.loads(order.text) status = order_json['data'].get('status') == 'COMPLETE' if status: utils.log('Order status complete') except: utils.log('Unable to check status of order, continuing anyway') # Confirm activation prog_dialog.update(83, 'Confirming activation') session.headers = {} session.headers.update( {'Authorization': 'Bearer {0}'.format(access_token)}) confirm = json.loads(session.get(config.ENTITLEMENTS_URL).text) if len(confirm.get('entitlements')) < 1: raise AussieAddonsException('Telstra ID activation failed') session.close() prog_dialog.update(100, 'Finished!') prog_dialog.close() return json.dumps({'pai': str(userid), 'bearer': access_token})
def play(url): try: # Remove cookies.dat for Kodi < 17.0 - causes issues with playback addon = xbmcaddon.Addon() cookies_dat = xbmc.translatePath('special://home/cache/cookies.dat') if os.path.isfile(cookies_dat): os.remove(cookies_dat) p = classes.Program() p.parse_kodi_url(url) stream_data = comm.get_stream_url(p.get_house_number(), p.get_url()) stream_url = stream_data.get('stream_url') if not stream_url: utils.log('Not Playable: {0}'.format(repr(stream_data))) raise AussieAddonsException( 'Not available: {0}\n{1}'.format(stream_data.get('msg'), stream_data.get( 'availability'))) use_ia = addon.getSetting('USE_IA') == 'true' if use_ia: if addon.getSetting('IGNORE_DRM') == 'false': try: import drmhelper if not drmhelper.check_inputstream(drm=False): return except ImportError: utils.log("Failed to import drmhelper") utils.dialog_message( 'DRM Helper is needed for inputstream.adaptive ' 'playback. Disable "Use inputstream.adaptive for ' 'playback" in settings or install drmhelper. For ' 'more information, please visit: ' 'http://aussieaddons.com/drm') return hdrs = stream_url[stream_url.find('|') + 1:] listitem = xbmcgui.ListItem(label=p.get_list_title(), path=stream_url) thumb = p.get_thumb() listitem.setArt({'icon': thumb, 'thumb': thumb}) if use_ia: listitem.setProperty('inputstreamaddon', 'inputstream.adaptive') listitem.setProperty('inputstream.adaptive.manifest_type', 'hls') listitem.setProperty('inputstream.adaptive.stream_headers', hdrs) listitem.setProperty('inputstream.adaptive.license_key', stream_url) listitem.setInfo('video', p.get_kodi_list_item()) # Add subtitles if available if p.is_captions(): captions_url = stream_data.get('captions_url') profile = xbmcaddon.Addon().getAddonInfo('profile') path = xbmc.translatePath(profile) if not os.path.isdir(path): os.makedirs(path) caption_file = os.path.join(path, 'subtitles.eng.srt') if os.path.isfile(caption_file): os.remove(caption_file) try: sess = session.Session() webvtt_data = sess.get(captions_url).text if webvtt_data: with io.BytesIO() as buf: webvtt_captions = WebVTTReader().read(webvtt_data) srt_captions = SRTWriter().write(webvtt_captions) srt_unicode = srt_captions.encode('utf-8') buf.write(srt_unicode) with io.open(caption_file, "wb") as f: f.write(buf.getvalue()) if hasattr(listitem, 'setSubtitles'): listitem.setSubtitles([caption_file]) except Exception as e: utils.log( 'Subtitles not available for this program: {0}'.format(e)) if hasattr(listitem, 'addStreamInfo'): listitem.addStreamInfo('audio', p.get_kodi_audio_stream_info()) listitem.addStreamInfo('video', p.get_kodi_video_stream_info()) xbmcplugin.setResolvedUrl(int(sys.argv[1]), True, listitem=listitem) except Exception: utils.handle_error('Unable to play video')
def get_mobile_token(): session = custom_session.Session(force_tlsv1=False) prog_dialog = xbmcgui.DialogProgress() prog_dialog.create('Logging in with mobile service') prog_dialog.update(1, 'Obtaining oauth token') userid = str(uuid.uuid4()) config.OAUTH_DATA.update({'x-user-id': userid}) oauth_resp = session.post(config.OAUTH_URL, data=config.OAUTH_DATA) oauth_json = json.loads(oauth_resp.text) access_token = oauth_json.get('access_token') prog_dialog.update(20, 'Obtaining mobile token') mobile_userid_cookies = session.get( config.MOBILE_ID_URL).cookies.get_dict() mobile_userid = mobile_userid_cookies.get('GUID_S') if not mobile_userid or mobile_userid_cookies.get('nouid'): raise TelstraAuthException('Not connected to Telstra Mobile network. ' 'Please disable WiFi and enable mobile ' 'data if on a Telstra mobile device, or ' "connect this device's WiFi to a device " 'that is on the Telstra Mobile network ' 'and try again.') data = config.OAUTH_DATA data.update({'x-user-id': mobile_userid, 'x-user-idp': 'NGP'}) mobile_token_resp = session.post(config.OAUTH_URL, data=data) bearer_token = json.loads(mobile_token_resp.text).get('access_token') # First check if there are any eligible services attached to the account prog_dialog.update(40, 'Determining eligible services') media_order_headers = {} media_order_headers.update( {'Authorization': 'Bearer {0}'.format(bearer_token)}) session.headers = media_order_headers try: offers = session.get(config.OFFERS_URL) except requests.exceptions.HTTPError as e: if e.response.status_code == 404: message = json.loads(e.response.text).get('userMessage') message += (' Please visit {0} '.format(config.HUB_URL) + 'for further instructions to link your mobile ' 'service to the supplied Telstra ID') raise TelstraAuthException(message) else: raise TelstraAuthException(e) try: offer_data = json.loads(offers.text) offers_list = offer_data['data']['offers'] ph_no = None for offer in offers_list: if offer.get('name') != 'My Football Live Pass': continue data = offer.get('productOfferingAttributes') ph_no = [x['value'] for x in data if x['name'] == 'ServiceId'][0] if not ph_no: raise TelstraAuthException( 'Unable to determine if you have any eligible services. ' 'Please ensure there is an eligible service linked to ' 'your Telstra ID to redeem the free offer. Please visit ' '{0} for further instructions'.format(config.HUB_URL)) except Exception as e: raise e # 'Order' the subscription package to activate the service prog_dialog.update(60, 'Activating live pass on service') order_data = config.MOBILE_ORDER_JSON order_data.update({'serviceId': ph_no, 'pai': userid}) try: order = session.post(config.MEDIA_ORDER_URL, json=order_data) except requests.exceptions.HTTPError as e: raise e # check to make sure order has been placed correctly if order.status_code == 201: try: order_json = json.loads(order.text) status = order_json['data'].get('status') == 'COMPLETE' if status: utils.log('Order status complete') except: utils.log('Unable to check status of order, continuing anyway') # Confirm activation prog_dialog.update(80, 'Confirming activation') session.headers = {} session.headers.update( {'Authorization': 'Bearer {0}'.format(access_token)}) confirm = json.loads(session.get(config.ENTITLEMENTS_URL).text) if len(confirm.get('entitlements')) < 1: raise AussieAddonsException('Telstra ID activation failed') session.close() prog_dialog.update(100, 'Finished!') prog_dialog.close() return json.dumps({'pai': userid, 'bearer': access_token})
def get_free_token(username, password): """ Obtain a valid token from Telstra/Yinzcam, will be used to make requests for Ooyala embed tokens """ session = custom_session.Session(force_tlsv1=False) prog_dialog = xbmcgui.DialogProgress() prog_dialog.create('Logging in with Telstra ID') # Send our first login request to Yinzcam, recieve (unactivated) ticket prog_dialog.update(1, 'Obtaining user ticket') adid = uuid.uuid4() deviceid = uuid.uuid4() session.headers = config.YINZCAM_AUTH_HEADERS ticket_resp = session.post(config.YINZCAM_AUTH_URL, data=config.NEW_LOGIN_DATA1.format( adid=adid, deviceid=deviceid)) ticket_xml = ET.fromstring(ticket_resp.text) ticket = ticket_xml.find('Ticket').text session.headers = {'Accept': 'application/json, text/plain, */*'} session.headers.update({'X-YinzCam-Ticket': ticket}) # Send ticket back and get 'sports pass confirmation' URL and 'TpUid' yinz_resp = session.get(config.YINZCAM_AUTH_URL2) jsondata = json.loads(yinz_resp.text) token = jsondata.get('TpUid') spc_url = jsondata.get('Url') if not token or not spc_url: raise TelstraAuthException('Unable to get token/spc url from NRL API') prog_dialog.update(16, 'Getting SSO Client ID') # GET to our spc url and receive SSO client ID session.headers = config.SPC_HEADERS spc_resp = session.get(spc_url) sso_token_match = re.search('ssoClientId = "(\w+)"', spc_resp.text) try: sso_token = sso_token_match.group(1) except AttributeError as e: utils.log('SPC login response: {0}'.format(spc_resp.text)) raise e # Sign in to telstra.com with our SSO client id to get the url # for retrieving the bearer token for media orders prog_dialog.update(33, 'Signing on to telstra.com') sso_params = config.SSO_PARAMS sso_params.update({'client_id': sso_token, 'state': binascii.b2a_hex(os.urandom(16)), 'nonce': binascii.b2a_hex(os.urandom(16))}) sso_auth_resp = session.get(config.SSO_URL, params=sso_params) sso_url = dict(urlparse.parse_qsl( urlparse.urlsplit(sso_auth_resp.url)[3])).get('goto') # login to telstra.com.au and get our BPSESSION cookie session.headers.update(config.SIGNON_HEADERS) signon_data = config.SIGNON_DATA signon_data = {'username': username, 'password': password, 'goto': sso_url} signon = session.post(config.SIGNON_URL, data=signon_data, allow_redirects=False) bp_session = session.cookies.get_dict().get('BPSESSION') # check signon is valid (correct username/password) signon_pieces = urlparse.urlsplit(signon.headers.get('Location')) signon_query = dict(urlparse.parse_qsl(signon_pieces.query)) utils.log('Sign-on result: %s' % signon_query) if 'errorcode' in signon_query: if signon_query['errorcode'] == '0': raise TelstraAuthException('Please enter your username ' 'in the settings') if signon_query['errorcode'] == '1': raise TelstraAuthException('Please enter your password ' 'in the settings') if signon_query['errorcode'] == '2': raise TelstraAuthException('Please enter your username and ' 'password in the settings') if signon_query['errorcode'] == '3': raise TelstraAuthException('Invalid Telstra ID username/password. ' 'Please check your username and ' 'password in the settings') # Use BPSESSION cookie to ask for bearer token sso_headers = config.SSO_HEADERS sso_headers.update({'Cookie': 'BPSESSION={0}'.format(bp_session)}) session.headers = sso_headers sso_token_resp = session.get(sso_url) bearer_token = dict(urlparse.parse_qsl( urlparse.urlsplit(sso_token_resp.url)[4]))['access_token'] # First check if there are any eligible services attached to the account prog_dialog.update(50, 'Determining eligible services') offer_id = dict(urlparse.parse_qsl( urlparse.urlsplit(spc_url)[3]))['offerId'] media_order_headers = config.MEDIA_ORDER_HEADERS media_order_headers.update( {'Authorization': 'Bearer {0}'.format(bearer_token)}) session.headers = media_order_headers try: offers = session.get(config.OFFERS_URL) except requests.exceptions.HTTPError as e: if e.response.status_code == 404: message = json.loads(e.response.text).get('userMessage') message += (' Please visit {0} '.format(config.HUB_URL) + 'for further instructions to link your mobile ' 'service to the supplied Telstra ID') raise TelstraAuthException(message) else: raise TelstraAuthException(e.response.status_code) try: offer_data = json.loads(offers.text) offers_list = offer_data['data']['offers'] ph_no = None for offer in offers_list: if offer.get('name') != 'NRL Live Pass': continue data = offer.get('productOfferingAttributes') ph_no = [x['value'] for x in data if x['name'] == 'ServiceId'][0] if not ph_no: raise TelstraAuthException( 'Unable to determine if you have any eligible services. ' 'Please ensure there is an eligible service linked to ' 'your Telstra ID to redeem the free offer. Please visit ' '{0} for further instructions'.format(config.HUB_URL)) except Exception as e: raise e # 'Order' the subscription package to activate the service prog_dialog.update(66, 'Activating live pass on service') order_data = config.MEDIA_ORDER_JSON.format(ph_no, offer_id, token) order = session.post(config.MEDIA_ORDER_URL, data=order_data) # check to make sure order has been placed correctly if order.status_code == 201: try: order_json = json.loads(order.text) status = order_json['data'].get('status') == 'COMPLETE' if status: utils.log('Order status complete') except: utils.log('Unable to check status of order, continuing anyway') # Register the ticket prog_dialog.update(83, 'Registering live pass with ticket') session.headers = {'Accept': 'application/json', 'Accept-Encoding': 'gzip', 'Connection': 'Keep-Alive', 'User-Agent': 'okhttp/3.4.1', 'X-YinzCam-AppID': 'NRL_LIVE', 'X-YinzCam-Ticket': ticket} session.get(config.YINZ_CALLBACK_URL.format(token), allow_redirects=False) # Confirm everything has gone well prog_dialog.update(100, 'Checking status of Live Pass') sub_status = session.get(config.STATUS_URL) status_json = json.loads(sub_status.text) if status_json.get('Valid') != 'true': raise AussieAddonsException('Telstra ID activation failed: {0}'.format( status_json.get('Reason'))) session.close() prog_dialog.update(100, 'Finished!') prog_dialog.close() return ticket
def get_mobile_token(): session = custom_session.Session(force_tlsv1=False) prog_dialog = xbmcgui.DialogProgress() prog_dialog.create('Logging in with Telstra ID') # Send our first login request to Yinzcam, recieve (unactivated) ticket prog_dialog.update(1, 'Obtaining user ticket') adid = uuid.uuid4() deviceid = uuid.uuid4() session.headers = config.YINZCAM_AUTH_HEADERS ticket_resp = session.post(config.YINZCAM_AUTH_URL, data=config.NEW_LOGIN_DATA1.format( adid=adid, deviceid=deviceid)) ticket_xml = ET.fromstring(ticket_resp.text) ticket = ticket_xml.find('Ticket').text session.headers = {'Accept': 'application/json, text/plain, */*', 'X-YinzCam-Ticket': ticket} # Send ticket back and get 'sports pass confirmation' URL and 'TpUid' yinz_resp = session.get(config.YINZCAM_AUTH_URL2) jsondata = json.loads(yinz_resp.text) token = jsondata.get('TpUid') spc_url = jsondata.get('Url') if not token or not spc_url: raise TelstraAuthException('Unable to get token/spc url from NRL API') prog_dialog.update(20, 'Obtaining mobile token') mobile_userid_cookies = session.get( config.MOBILE_ID_URL).cookies.get_dict() mobile_userid = mobile_userid_cookies.get('GUID_S') if not mobile_userid or mobile_userid_cookies.get('nouid'): raise TelstraAuthException('Not connected to Telstra Mobile network. ' 'Please disable WiFi and enable mobile ' 'data if on a Telstra mobile device, or ' "connect this device's WiFi to a device " 'that is on the Telstra Mobile network ' 'and try again.') data = config.MOBILE_TOKEN_PARAMS data.update({'x-user-id': mobile_userid}) mobile_token_resp = session.post(config.OAUTH_URL, data=data) bearer_token = json.loads(mobile_token_resp.text).get('access_token') # First check if there are any eligible services attached to the account prog_dialog.update(40, 'Determining eligible services') session.headers = config.OAUTH_HEADERS session.headers.update( {'Authorization': 'Bearer {0}'.format(bearer_token)}) try: offers = session.get(config.OLD_OFFERS_URL) except requests.exceptions.HTTPError as e: if e.response.status_code == 404: message = json.loads(e.response.text).get('userMessage') message += (' Please visit {0} '.format(config.HUB_URL) + 'for further instructions to link your mobile ' 'service to the supplied Telstra ID') raise TelstraAuthException(message) else: raise TelstraAuthException(e) try: offer_data = json.loads(offers.text) offers_list = offer_data['data']['offers'] ph_no = None for offer in offers_list: if offer.get('name') != 'NRL Live Pass': continue data = offer.get('productOfferingAttributes') ph_no = [x['value'] for x in data if x['name'] == 'ServiceId'][0] if not ph_no: raise TelstraAuthException( 'Unable to determine if you have any eligible services. ' 'Please ensure there is an eligible service linked to ' 'your Telstra ID to redeem the free offer. Please visit ' '{0} for further instructions'.format(config.HUB_URL)) except Exception as e: raise e # 'Order' the subscription package to activate the service prog_dialog.update(60, 'Activating live pass on service') order_data = config.MOBILE_ORDER_JSON order_data.update({'serviceId': ph_no, 'pai': token}) order = session.post(config.OLD_MEDIA_ORDER_URL, json=order_data) # check to make sure order has been placed correctly prog_dialog.update(80, 'Confirming activation') if order.status_code == 201: try: order_json = json.loads(order.text) status = order_json['data'].get('status') == 'COMPLETE' if status: utils.log('Order status complete') except: utils.log('Unable to check status of order, continuing anyway') # Register the ticket prog_dialog.update(83, 'Registering live pass with ticket') session.headers = {'Accept': 'application/json', 'Accept-Encoding': 'gzip', 'Connection': 'Keep-Alive', 'User-Agent': 'okhttp/3.4.1', 'X-YinzCam-AppID': 'NRL_LIVE', 'X-YinzCam-Ticket': ticket} session.get(config.YINZ_CALLBACK_URL.format(token), allow_redirects=False) # Confirm everything has gone well prog_dialog.update(100, 'Checking status of Live Pass') sub_status = session.get(config.STATUS_URL) status_json = json.loads(sub_status.text) if status_json.get('Valid') != 'true': raise AussieAddonsException('Telstra ID activation failed: {0}'.format( status_json.get('Reason'))) session.close() prog_dialog.update(100, 'Finished!') prog_dialog.close() return ticket