Browse Source

Create more robust cli_login() and authentication type handling

pull/459/head
FailSpy 1 year ago
parent
commit
fbe3e1bb3e
  1. 105
      steam/webauth.py

105
steam/webauth.py

@ -55,7 +55,7 @@ Example usage:
""" """
import json import json
from time import time from time import time, sleep
from base64 import b64encode from base64 import b64encode
from getpass import getpass from getpass import getpass
import six import six
@ -85,6 +85,8 @@ API_HEADERS = {
API_URL = 'https://api.steampowered.com/{}Service/{}/v{}' API_URL = 'https://api.steampowered.com/{}Service/{}/v{}'
SUPPORTED_AUTH_TYPES = [EAuthSessionGuardType.EmailCode, EAuthSessionGuardType.DeviceCode, EAuthSessionGuardType.DeviceConfirmation]
class WebAuth(object): class WebAuth(object):
"""New WEB Auth class. """New WEB Auth class.
@ -219,6 +221,7 @@ class WebAuth(object):
self.client_id = resp['response']['client_id'] self.client_id = resp['response']['client_id']
self.request_id = resp['response']['request_id'] self.request_id = resp['response']['request_id']
self.steam_id = SteamID(resp['response']['steamid']) self.steam_id = SteamID(resp['response']['steamid'])
self.allowed_confirmations = [EAuthSessionGuardType(confirm_type['confirmation_type']) for confirm_type in resp['response']['allowed_confirmations']]
def _startLoginSession(self): def _startLoginSession(self):
"""Starts login session via credentials.""" """Starts login session via credentials."""
@ -243,7 +246,7 @@ class WebAuth(object):
self.refresh_token = resp['response']['refresh_token'] self.refresh_token = resp['response']['refresh_token']
self.access_token = resp['response']['access_token'] self.access_token = resp['response']['access_token']
except KeyError: except KeyError:
raise WebAuthException('Authentication requires 2fa token, which is not provided or invalid') raise TwoFactorAuthNotProvided('Authentication requires 2fa token, which is not provided or invalid')
def _finalizeLogin(self): def _finalizeLogin(self):
self.sessionID = generate_session_id() self.sessionID = generate_session_id()
@ -299,9 +302,11 @@ class WebAuth(object):
if self.logged_on: if self.logged_on:
return self.session return self.session
username = username or self.username
password = password or self.password
if username == '' or password == '': if username == '' or password == '':
if self.username == '' and self.password == '': raise LoginIncorrect("Username or password is provided empty!")
raise ValueError("Username or password is provided empty!")
else: else:
self.username = username self.username = username
self.password = password self.password = password
@ -370,22 +375,78 @@ class WebAuth(object):
If you use email confirm, provide email_required = True, If you use email confirm, provide email_required = True,
else just provide code. else just provide code.
""" """
res = self.login( while True:
username, try:
password, res = self.login(
code, username,
email_required password,
) code,
if hasattr(res, '__call__'): email_required
while True: )
try: except LoginIncorrect:
twofactor_code = input('Enter your 2fa/email code: ') prompt = ("Enter password for %s: " if not password else "Invalid password for %s. Enter password:")
resp = res(twofactor_code) password = getpass(prompt % repr(self.username))
return resp continue
except WebAuthException: except TwoFactorAuthNotProvided:
pass # 2FA handling
else: allowed = set(self.allowed_confirmations)
return self.session if allowed.isdisjoint(SUPPORTED_AUTH_TYPES):
raise AuthTypeNotSupported("Couldn't find a supported auth type for this account.")
can_confirm_with_app = EAuthSessionGuardType.DeviceConfirmation in allowed
twofactor_code = ''
while twofactor_code.strip() == '':
prompt = ''
if EAuthSessionGuardType.DeviceCode in allowed:
prompt = 'Enter your Steam Guard code'
elif EAuthSessionGuardType.EmailCode in allowed:
prompt = 'Enter the Steam 2FA code emailed to you'
if can_confirm_with_app:
if prompt == '':
# don't think this is possible, but let's handle it anyways
input("Please confirm Steam Guard on your device and press ENTER to continue")
sleep(10)
else:
prompt += ' (or simply press Enter if approved via app)'
if prompt != '':
prompt += ': '
twofactor_code = input(prompt)
if can_confirm_with_app:
try:
self._pollLoginStatus() # test to see if they've authenticated via app
break
except TwoFactorAuthNotProvided:
# they've not authenticated via the app, let's see if we can use their provided code
pass
if twofactor_code.strip():
using_email_code = EAuthSessionGuardType.EmailCode in allowed
self._update_login_token(twofactor_code, EAuthSessionGuardType.EmailCode if using_email_code else EAuthSessionGuardType.DeviceCode)
try:
self._pollLoginStatus()
break
except TwoFactorAuthNotProvided:
print("Invalid auth code. Please try again")
twofactor_code = ''
continue
else:
print("Unauthenticated. Please try again")
self._finalizeLogin()
return self.session
if hasattr(res, '__call__'):
# this should not ever happen at this point as we don't use `email_required` on login()
while True:
try:
twofactor_code = input('Enter your 2fa/email code: ')
resp = res(twofactor_code)
return resp
except WebAuthException:
pass
else:
return self.session
#TODO: DEPRECATED, must be rewritten, like WebAuth #TODO: DEPRECATED, must be rewritten, like WebAuth
@ -506,6 +567,10 @@ class WebAuthException(Exception):
pass pass
class AuthTypeNotSupported(WebAuthException):
pass
class TwoFactorAuthNotProvided(WebAuthException): class TwoFactorAuthNotProvided(WebAuthException):
pass pass

Loading…
Cancel
Save