diff --git a/robin_stocks/robinhood/authentication.py b/robin_stocks/robinhood/authentication.py index 9bd3430..b745d2d 100644 --- a/robin_stocks/robinhood/authentication.py +++ b/robin_stocks/robinhood/authentication.py @@ -108,7 +108,11 @@ def login(username=None, password=None, expiresIn=86400, scope='internal', by_sm 'scope': scope, 'username': username, 'challenge_type': challenge_type, - 'device_token': device_token + 'device_token': device_token, + 'try_passkeys': False, + 'token_request_path':'/login', + 'create_read_only_secondary_token':True, + 'request_id': '848bd19e-02bc-45d9-99b5-01bce5a79ea7' } if mfa_code: @@ -181,6 +185,10 @@ def login(username=None, password=None, expiresIn=86400, scope='internal', by_sm update_session( 'X-ROBINHOOD-CHALLENGE-RESPONSE-ID', challenge_id) data = request_post(url, payload) + elif 'verification_workflow' in data: + workflow_id = data['verification_workflow']['id'] + _validate_sherrif_id(device_token=device_token, workflow_id=workflow_id, mfa_code=mfa_code) + data = request_post(url, payload) # Update Session data with authorization or raise exception with the information present in data. if 'access_token' in data: token = '{0} {1}'.format(data['token_type'], data['access_token']) @@ -193,12 +201,49 @@ def login(username=None, password=None, expiresIn=86400, scope='internal', by_sm 'access_token': data['access_token'], 'refresh_token': data['refresh_token'], 'device_token': payload['device_token']}, f) + else: - raise Exception(data['detail']) + if 'detail' in data: + raise Exception(data['detail']) + raise Exception(f"Received an error response {data}") else: raise Exception('Error: Trouble connecting to robinhood API. Check internet connection.') return(data) +def _validate_sherrif_id(device_token:str, workflow_id:str,mfa_code:str): + url = "https://api.robinhood.com/pathfinder/user_machine/" + payload = { + 'device_id': device_token, + 'flow': 'suv', + 'input':{'workflow_id': workflow_id} + } + data = request_post(url=url, payload=payload,json=True) + if "id" in data: + inquiries_url = f"https://api.robinhood.com/pathfinder/inquiries/{data['id']}/user_view/" + res = request_get(inquiries_url) + challenge_id=res['type_context']["context"]["sheriff_challenge"]["id"] + challenge_url = f"https://api.robinhood.com/challenge/{challenge_id}/respond/" + challenge_payload = { + 'response': mfa_code + } + challenge_response = request_post(url=challenge_url, payload=challenge_payload,json=True ) + if challenge_response["status"] == "validated": + inquiries_payload = {"sequence":0,"user_input":{"status":"continue"}} + inquiries_response = request_post(url=inquiries_url, payload=inquiries_payload,json=True ) + if inquiries_response["type_context"]["result"] == "workflow_status_approved": + return + else: + raise Exception("workflow status not approved") + else: + raise Exception("Challenge not validated") + raise Exception("Id not returned in user-machine call") + +def _get_sherrif_challenge(token_id:str): + + if "id" in data: + return data["id"] + raise Exception("Id not returned in user-machine call") + @login_required def logout():