def handle_sk(self, sess): response_page = BeautifulSoup(sess.text, 'html.parser') challenge_url = sess.url.split("?")[0] challenges_txt = response_page.find('input', { 'name': "id-challenge" }).get('value') facet_url = urllib_parse.urlparse(challenge_url) facet = facet_url.scheme + "://" + facet_url.netloc keyHandleJSField = response_page.find('div', { 'jsname': 'C0oDBd' }).get('data-challenge-ui') startJSONPosition = keyHandleJSField.find('{') endJSONPosition = keyHandleJSField.rfind('}') keyHandleJsonPayload = json.loads( keyHandleJSField[startJSONPosition:endJSONPosition + 1]) keyHandles = self.find_key_handles( keyHandleJsonPayload, base64.urlsafe_b64encode(base64.b64decode(challenges_txt))) appId = self.find_app_id(str(keyHandleJsonPayload)) # txt sent for signing needs to be base64 url encode # we also have to remove any base64 padding because including including it will prevent google accepting the auth response challenges_txt_encode_pad_removed = base64.urlsafe_b64encode( base64.b64decode(challenges_txt)).strip('='.encode()) u2f_challenges = [{ 'version': 'U2F_V2', 'challenge': challenges_txt_encode_pad_removed.decode(), 'appId': appId, 'keyHandle': keyHandle.decode() } for keyHandle in keyHandles] # Prompt the user up to attempts_remaining times to insert their U2F device. attempts_remaining = 5 auth_response = None while True: try: auth_response_dict = u2f.u2f_auth(u2f_challenges, facet) auth_response = json.dumps(auth_response_dict) break except RuntimeWarning: logging.error("No U2F device found. %d attempts remaining", attempts_remaining) if attempts_remaining <= 0: break else: input( "Insert your U2F device and press enter to try again..." ) attempts_remaining -= 1 # If we exceed the number of attempts, raise an error and let the program exit. if auth_response is None: raise ExpectedGoogleException( "No U2F device found. Please check your setup.") payload = { 'challengeId': response_page.find('input', { 'name': 'challengeId' }).get('value'), 'challengeType': response_page.find('input', { 'name': 'challengeType' }).get('value'), 'continue': response_page.find('input', { 'name': 'continue' }).get('value'), 'scc': response_page.find('input', { 'name': 'scc' }).get('value'), 'sarp': response_page.find('input', { 'name': 'sarp' }).get('value'), 'checkedDomains': response_page.find('input', { 'name': 'checkedDomains' }).get('value'), 'pstMsg': '1', 'TL': response_page.find('input', { 'name': 'TL' }).get('value'), 'gxf': response_page.find('input', { 'name': 'gxf' }).get('value'), 'id-challenge': challenges_txt, 'id-assertion': auth_response, 'TrustDevice': 'on', } return self.post(challenge_url, data=payload)
def handle_sk(self, sess): response_page = BeautifulSoup(sess.text, 'html.parser') challenge_url = sess.url.split("?")[0] challenges_txt = response_page.find('input', { 'name': "id-challenge" }).get('value') challenges = json.loads(challenges_txt) facet_url = urllib_parse.urlparse(challenge_url) facet = facet_url.scheme + "://" + facet_url.netloc app_id = challenges["appId"] u2f_challenges = [] for c in challenges["challenges"]: c["appId"] = app_id u2f_challenges.append(c) # Prompt the user up to attempts_remaining times to insert their U2F device. attempts_remaining = 5 auth_response = None while True: try: auth_response = json.dumps(u2f.u2f_auth(u2f_challenges, facet)) break except RuntimeWarning: logging.error("No U2F device found. %d attempts remaining", attempts_remaining) if attempts_remaining <= 0: break else: input( "Insert your U2F device and press enter to try again..." ) attempts_remaining -= 1 # If we exceed the number of attempts, raise an error and let the program exit. if auth_response is None: raise ExpectedGoogleException( "No U2F device found. Please check your setup.") payload = { 'challengeId': response_page.find('input', { 'name': 'challengeId' }).get('value'), 'challengeType': response_page.find('input', { 'name': 'challengeType' }).get('value'), 'continue': response_page.find('input', { 'name': 'continue' }).get('value'), 'scc': response_page.find('input', { 'name': 'scc' }).get('value'), 'sarp': response_page.find('input', { 'name': 'sarp' }).get('value'), 'checkedDomains': response_page.find('input', { 'name': 'checkedDomains' }).get('value'), 'pstMsg': response_page.find('input', { 'name': 'pstMsg' }).get('value'), 'TL': response_page.find('input', { 'name': 'TL' }).get('value'), 'gxf': response_page.find('input', { 'name': 'gxf' }).get('value'), 'id-challenge': challenges_txt, 'id-assertion': auth_response, 'TrustDevice': 'on', } return self.post(challenge_url, data=payload)