Skip to content

Commit

Permalink
No 2 fa bugfix (#29)
Browse files Browse the repository at this point in the history
enums: Corrected type hint in `to_TwoFactorMethod`
steam_auth_polling_data: Corrected 'any' check in 'has_valid_confirmation_method'. No 2FA's enum value is 0, which was being coerced to False.
backend_steam_network: The value from no two-factor is now returned instead of set to result and unused. The _handle_steam_guard_none function now properly calls the finish auth process so we're actually logged in. previously it'd just short-circuit that process and then error later. Properly does this, expected wrong UserActionRequired value and also wasn't awaited. in other words, several small, dumb mistakes.

bumped manifest and current version to 1.0.7 as a result of these changes.

Hardened the User Info Cache code so it would not error if the data somehow was cleared to Null and written to the credentials storage. It will also write an empty dict to the credentials instead of a dict of nulls.

Stripped the leading and trailing whitespace characters during 2FA code inputs so the whitespace wouldn't make your 2FA fail.

Properly type-hint 2FA code so it would resolve nicely in any IDE or MyPy

Fixed broken urls in current_version,json
Updated version.py to have 1.0.7 with relevant changelog information

Hardened the User Info Cache code so it would not error if the data somehow was cleared to Null and written to the credentials storage. It will also write an empty dict to the credentials instead of a dict of nulls.

Stripped the leading and trailing whitespace characters during 2FA code inputs so the whitespace wouldn't make your 2FA fail.

Properly type-hint 2FA code so it would resolve nicely in any IDE or MyPy

Fixed broken urls in current_version,json

update gitignore to avoid .gz files. The mac with installer is uses that compression. partially updated the batch file to deal with issues, still needs some tweaking
  • Loading branch information
ABaumher committed Jun 23, 2023
1 parent be8f2b0 commit c524900
Show file tree
Hide file tree
Showing 9 changed files with 50 additions and 36 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,4 @@ output/

/protoc
*.zip
*.gz
2 changes: 1 addition & 1 deletion auto-copy-windows.bat
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,4 @@ set "PLUGIN_PATH=%localappdata%\GOG.com\Galaxy\plugins\installed\steam_ca27391f-

rmdir /S /Q -rf "%PLUGIN_PATH%"
mkdir "%PLUGIN_PATH%"
powershell Expand-Archive ".\windows.zip" -DestinationPath %PLUGIN_PATH%
powershell "[Environment]::CurrentDirectory = Get-Location; Expand-Archive '.\windows.zip' -DestinationPath '%PLUGIN_PATH%'"
6 changes: 3 additions & 3 deletions current_version.json
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
{
"tag_name": "v1.0.6",
"tag_name": "v1.0.7",
"assets": [
{
"browser_download_url": "https://github.com/ABaumher/galaxy-integration-steam/releases/download/v1.0.6-beta/windows.zip",
"browser_download_url": "https://github.com/ABaumher/galaxy-integration-steam/releases/download/v1.0.7/windows.zip",
"name": "windows.zip"
},
{
"browser_download_url": "https://github.com/ABaumher/galaxy-integration-steam/releases/download/v1.0.6-beta/mac.zip",
"browser_download_url": "https://github.com/ABaumher/galaxy-integration-steam/releases/download/v1.0.7/mac.zip",
"name": "mac.zip"
}
]
Expand Down
22 changes: 12 additions & 10 deletions src/backend_steam_network.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import logging
import ssl
from contextlib import suppress
from typing import Callable, List, Any, Dict, Union, Coroutine
from typing import Callable, List, Any, Dict, Union, Coroutine, cast
from urllib import parse
from pprint import pformat

Expand Down Expand Up @@ -192,7 +192,7 @@ def _get_mobile_confirm_kwargs(self, allowed_methods: Dict[TwoFactorMethod, str]

return fallbackData

async def pass_login_credentials(self, step, credentials, cookies):
async def pass_login_credentials(self, step, credentials: Dict[str, str], cookies):
end_uri = credentials["end_uri"]

if (DisplayUriHelper.LOGIN.EndUri() in end_uri):
Expand All @@ -219,7 +219,7 @@ def sanitize_string(data : str) -> str:
"""
return (''.join([i if ord(i) < 128 else '' for i in data]))[:64]

async def _handle_login_finished(self, credentials) -> Union[NextStep, Authentication]:
async def _handle_login_finished(self, credentials: Dict[str, str]) -> Union[NextStep, Authentication]:
parsed_url = parse.urlsplit(credentials["end_uri"])
params = parse.parse_qs(parsed_url.query)
if ("password" not in params or "username" not in params):
Expand All @@ -236,7 +236,7 @@ async def _handle_login_finished(self, credentials) -> Union[NextStep, Authentic
allowed_methods = self._authentication_cache.two_factor_allowed_methods
method, msg = allowed_methods[0]
if (method == TwoFactorMethod.Nothing):
result = await self._handle_steam_guard_none()
return await self._handle_steam_guard_none()
elif (method == TwoFactorMethod.PhoneCode):
return next_step_response_simple(DisplayUriHelper.TWO_FACTOR_MOBILE)
elif (method == TwoFactorMethod.EmailCode):
Expand All @@ -250,12 +250,12 @@ async def _handle_login_finished(self, credentials) -> Union[NextStep, Authentic
return next_step_response_simple(DisplayUriHelper.LOGIN, True)
#result here should be password, or unathorized.

async def _handle_steam_guard(self, credentials, method: TwoFactorMethod, fallback: DisplayUriHelper) -> Union[NextStep, Authentication]:
parsed_url = parse.urlsplit(credentials["end_uri"])
async def _handle_steam_guard(self, credentials: Dict[str, str], method: TwoFactorMethod, fallback: DisplayUriHelper) -> Union[NextStep, Authentication]:
parsed_url: parse.SplitResult = parse.urlsplit(credentials["end_uri"])
params = parse.parse_qs(parsed_url.query)
if ("code" not in params):
return next_step_response_simple(fallback, True)
code = params["code"][0]
code = params["code"][0].strip()
await self._websocket_client.communication_queues["websocket"].put({'mode': AuthCall.UPDATE_TWO_FACTOR, 'two-factor-code' : code, 'two-factor-method' : method })
result = await self._get_websocket_auth_step()
if (result == UserActionRequired.NoActionConfirmLogin):
Expand All @@ -269,10 +269,12 @@ async def _handle_steam_guard(self, credentials, method: TwoFactorMethod, fallba

async def _handle_steam_guard_none(self) -> Authentication:
result = await self._handle_2FA_PollOnce()
if (result != UserActionRequired.NoActionRequired):
raise UnknownBackendResponse()
else:
if (result == UserActionRequired.NoActionRequired):
return Authentication(self._user_info_cache.steam_id, self._user_info_cache.persona_name)
elif result == UserActionRequired.NoActionConfirmToken:
return await self._finish_auth_process()
else:
raise UnknownBackendResponse()

async def _handle_steam_guard_check(self, fallback: DisplayUriHelper, is_confirm: bool, **kwargs:str) -> Union[NextStep, Authentication]:
result = await self._handle_2FA_PollOnce(is_confirm)
Expand Down
2 changes: 1 addition & 1 deletion src/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "Galaxy Steam plugin Version 2",
"platform": "steam",
"guid": "ca27391f-2675-49b1-92c0-896d43afa4f8",
"version": "1.0.6",
"version": "1.0.7",
"description": "Galaxy plugin for Steam. Updated with new authentication logic",
"author": "ABaumher, don-de-marco, et al.",
"email": "[email protected]",
Expand Down
2 changes: 1 addition & 1 deletion src/steam_network/enums.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ class TwoFactorMethod(enum.IntEnum):
#EmailConfirm = 5 #Does not exist? Likely something Steam thought about implementing and decided not to. if that changes, we can support it.


def to_TwoFactorMethod(auth_enum : EnumTypeWrapper) -> TwoFactorMethod:
def to_TwoFactorMethod(auth_enum : Union[CAuthentication_AllowedConfirmation, EnumTypeWrapper]) -> TwoFactorMethod:
if (isinstance(auth_enum, CAuthentication_AllowedConfirmation)):
auth_enum = auth_enum.confirmation_type
ret_val, _ = _to_TwoFactorMethod(auth_enum, None)
Expand Down
2 changes: 1 addition & 1 deletion src/steam_network/steam_auth_polling_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,4 +48,4 @@ def extended_error_message(self):

def has_valid_confirmation_method(self):
#if any value in allowed confirmations does not equal unknown, return true. else return false.
return any(c for c in self._allowed_confirmations if c != TwoFactorMethod.Unknown)
return any(c != TwoFactorMethod.Unknown for c in self._allowed_confirmations)
43 changes: 25 additions & 18 deletions src/steam_network/user_info_cache.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import asyncio
import base64
import logging
from typing import Optional
from typing import Optional, Dict

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -31,30 +31,37 @@ def is_initialized(self) -> bool:


def to_dict(self):
creds = {
'steam_id': base64.b64encode(str(self._steam_id).encode('utf-8')).decode('utf-8'),
'refresh_token': base64.b64encode(str(self._refresh_token).encode('utf-8')).decode('utf-8'),
'account_username': base64.b64encode(str(self._account_username).encode('utf-8')).decode('utf-8'),
'persona_name': base64.b64encode(str(self._persona_name).encode('utf-8')).decode('utf-8'),
}
creds = {}
if self.is_initialized():
creds = {
'steam_id': base64.b64encode(str(self._steam_id).encode('utf-8')).decode('utf-8'),
'refresh_token': base64.b64encode(self._refresh_token.encode('utf-8')).decode('utf-8'),
'account_username': base64.b64encode(self._account_username.encode('utf-8')).decode('utf-8'),
'persona_name': base64.b64encode(self._persona_name.encode('utf-8')).decode('utf-8'),
}
return creds

def from_dict(self, lookup):
for key in lookup.keys():
if lookup[key]:
def from_dict(self, lookup: Dict[str, str]):
for key, val in lookup.items():
if val:
logger.info(f"Loaded {key} from stored credentials")

if 'steam_id' in lookup:
self._steam_id = int(base64.b64decode(lookup['steam_id']).decode('utf-8'))
item = lookup.get('steam_id')
if item is not None:
self._steam_id = int(base64.b64decode(item).decode('utf-8'))

item = lookup.get('account_username')
if item is not None:
self._account_username = base64.b64decode(item).decode('utf-8')

if 'account_username' in lookup:
self._account_username = base64.b64decode(lookup['account_username']).decode('utf-8')

if 'persona_name' in lookup:
self._persona_name = base64.b64decode(lookup['persona_name']).decode('utf-8')
item = lookup.get('persona_name')
if item is not None:
self._persona_name = base64.b64decode(item).decode('utf-8')

if 'refresh_token' in lookup:
self._refresh_token = base64.b64decode(lookup['refresh_token']).decode('utf-8')
item = lookup.get('refresh_token')
if item is not None:
self._refresh_token = base64.b64decode(item).decode('utf-8')

@property
def changed(self):
Expand Down
6 changes: 5 additions & 1 deletion src/version.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
__version__ = "1.0.6"
__version__ = "1.0.7"
__changelog__ = {
"unreleased": '''
''',
"1.0.7": """
- Fixes issues when SteamGuard is disabled. Made it so 2FA codes would ignore leading or trailing whitespace.
- Code cleanup
""",
"1.0.6": """
- reintroduces password santization so users with long passwords or illegal characters can log in as intended
- Code cleanup
Expand Down

0 comments on commit c524900

Please sign in to comment.