Skip to content

Commit

Permalink
v 0.6.0: added ability to authenticate via backup codes
Browse files Browse the repository at this point in the history
fixes #7
  • Loading branch information
Mixaill committed Jul 8, 2019
1 parent 414a992 commit 9f5d005
Show file tree
Hide file tree
Showing 7 changed files with 50 additions and 19 deletions.
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@ GOG Galaxy 2.0 Wargaming Game Center integration

## Changelog

* v. 0.6.0
* Implemented ability to install games. Ability to install games is implemented. Now this integration implements a minimal set of functions for everyday use!
* Implemented login via OTP backup codes
* Fixed exception in `get_owned_games()` function
* Updated Sentry SDK to 0.10.0

* v. 0.5.0
* Fetch owned games from Wargaming.net account

Expand Down
2 changes: 1 addition & 1 deletion manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "Galaxy Wargaming plugin",
"platform": "wargaming",
"guid": "91728e8a-33c3-4b6d-8382-4dd31043dec1",
"version": "0.5.0",
"version": "0.6.0",
"description": "Galaxy Wargaming plugin",
"author": "Mikhail Paulyshka",
"email": "[email protected]",
Expand Down
2 changes: 1 addition & 1 deletion version.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = "0.5.0"
__version__ = "0.6.0"
17 changes: 12 additions & 5 deletions wgc/html/2fa.html
Original file line number Diff line number Diff line change
Expand Up @@ -51,12 +51,19 @@ <h3 class="card-header"><i class="fa fa-user-circle"></i> Two Factor Authenticat
</div>
</div>

<div class="row">
<div class="form-check row">
<div class="col-sm-8 offset-1">
<input type="checkbox" class="form-check-input" name="use_backup" id="use_backup">
<label class="form-check-label" for="use_backup">Use backup code instead of one-time password</label>
</div>
</div>
</div>

<div class="card-block">
<div class="form-group row">
<div class="col col-8 offset-8">
<div class="row">
<div class="col-sm-6">
<button type="submit" class="btn btn-block btn-success">Verify</button>
</div>
<div class="col-sm-6">
<button type="submit" class="btn btn-block btn-success">Verify</button>
</div>
</div>
</div>
Expand Down
17 changes: 12 additions & 5 deletions wgc/html/2fa_failed.html
Original file line number Diff line number Diff line change
Expand Up @@ -56,12 +56,19 @@ <h3 class="card-header"><i class="fa fa-user-circle"></i> Two Factor Authenticat
</div>
</div>

<div class="row">
<div class="form-check row">
<div class="col-sm-8 offset-1">
<input type="checkbox" class="form-check-input" name="use_backup" id="use_backup">
<label class="form-check-label" for="use_backup">Use backup code instead of one-time password</label>
</div>
</div>
</div>

<div class="card-block">
<div class="form-group row">
<div class="col col-8 offset-8">
<div class="row">
<div class="col-sm-6">
<button type="submit" class="btn btn-block btn-success">Verify</button>
</div>
<div class="col-sm-6">
<button type="submit" class="btn btn-block btn-success">Verify</button>
</div>
</div>
</div>
Expand Down
24 changes: 17 additions & 7 deletions wgc/wgc_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,9 +82,13 @@ def do_POST_2fa(self, data):
data_valid = False
auth_result = False

use_backup_code = False
if b'use_backup' in data:
use_backup_code = True

if data_valid:
try:
auth_result = self.backend.do_auth_2fa(data[b'authcode'][0].decode("utf-8"))
auth_result = self.backend.do_auth_2fa(data[b'authcode'][0].decode("utf-8"), use_backup_code)
except Exception:
logging.exception("error on doing auth:")

Expand All @@ -95,7 +99,7 @@ def do_POST_2fa(self, data):
self.send_header('Location','/finished')
elif auth_result == WGCAuthorizationResult.REQUIRES_2FA:
self.send_header('Location','/2fa')
elif auth_result == WGCAuthorizationResult.INCORRECT_2FA:
elif auth_result == WGCAuthorizationResult.INCORRECT_2FA or auth_result == WGCAuthorizationResult.INCORRECT_2FA_BACKUP:
self.send_header('Location','/2fa_failed')
else:
self.send_header('Location','/login_failed')
Expand Down Expand Up @@ -341,7 +345,7 @@ def do_auth_emailpass(self, realm, email, password) -> WGCAuthorizationResult:
return self.do_auth_token(realm, email, token_data_bypassword)


def do_auth_2fa(self, otp_code) -> WGCAuthorizationResult:
def do_auth_2fa(self, otp_code: str, use_backup_code: bool) -> WGCAuthorizationResult:
'''
Submits 2FA answer and continue authorization
'''
Expand Down Expand Up @@ -372,14 +376,17 @@ def do_auth_2fa(self, otp_code) -> WGCAuthorizationResult:
self._login_info_temp['password'],
self._login_info_temp['pow_number'],
self._login_info_temp['twofactor_token'],
otp_code)
otp_code,
use_backup_code)

# process error
if token_data_byotp['status_code'] != 200:
if 'error_description' in token_data_byotp:
error_desc = token_data_byotp['error_description']
if error_desc == 'twofactor_invalid' or error_desc == 'Invalid otp_code parameter value.':
return WGCAuthorizationResult.INCORRECT_2FA
if error_desc == 'Invalid backup_code parameter value.':
return WGCAuthorizationResult.INCORRECT_2FA_BACKUP

logging.error('wgc_auth/do_auth_2fa: failed to request token by email, password and OTP: %s' % token_data_byotp)
return WGCAuthorizationResult.FAILED
Expand Down Expand Up @@ -492,7 +499,7 @@ def __oauth_challenge_calculate(self, challenge_data):

pow_number = pow_number + 1

def __oauth_token_get_bypassword(self, realm, email, password, pow_number, twofactor_token = None, otp_code = None):
def __oauth_token_get_bypassword(self, realm, email, password, pow_number, twofactor_token : str = None, otp_code : str = None, use_backup_code : bool = False):
body = dict()
body['username'] = email
body['password'] = password
Expand All @@ -503,7 +510,10 @@ def __oauth_token_get_bypassword(self, realm, email, password, pow_number, twofa
if twofactor_token is not None:
body['twofactor_token'] = twofactor_token
if otp_code is not None:
body['otp_code'] = otp_code
if use_backup_code:
body['backup_code'] = otp_code
else:
body['otp_code'] = otp_code

response = self._session.post(self.__get_url('wgnet', realm, self.OAUTH_URL_TOKEN), data = body)
while response.status_code == 202:
Expand All @@ -513,7 +523,7 @@ def __oauth_token_get_bypassword(self, realm, email, password, pow_number, twofa
try:
text = json.loads(response.text)
except Exception:
logging.exception('wgc_auth/oauth_token_get_bypassword: failed to parse response')
logging.exception('wgc_api/__oauth_token_get_bypassword: failed to parse response')
return None

text['status_code'] = response.status_code
Expand Down
1 change: 1 addition & 0 deletions wgc/wgc_constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ class WGCAuthorizationResult(Enum):
INCORRECT_2FA = 4
INVALID_LOGINPASS = 5
ACCOUNT_NOT_FOUND = 6
INCORRECT_2FA_BACKUP = 7


WGCRealms = {
Expand Down

0 comments on commit 9f5d005

Please sign in to comment.