diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 0000000..867cd4d --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,32 @@ +name: Run unit tests + +on: + pull_request: + +jobs: + tests: + runs-on: ubuntu-latest + + strategy: + matrix: + python-version: + - "3.8" + - "3.9" + - "3.10" + - "3.11" + - "3.12" + - "3.13" + - "3.14" + + steps: + - name: Check out repository + uses: actions/checkout@v6 + + - name: Set up Python + uses: actions/setup-python@v6 + with: + python-version: ${{ matrix.python-version }} + + - name: Run unit tests + run: | + python -m unittest discover -s test -v diff --git a/pysteamsignin/steamsignin.py b/pysteamsignin/steamsignin.py index a8bbb7b..e6e02b4 100644 --- a/pysteamsignin/steamsignin.py +++ b/pysteamsignin/steamsignin.py @@ -131,9 +131,13 @@ def ValidateResults(self, results): parsedArgs = urlencode(validationArgs).encode("utf-8") logger.info('Encoded the validation arguments, prepped to send.') - with urllib.request.urlopen(self._provider, parsedArgs, timeout = OPENID_TIMEOUT) as requestData: - responseData = requestData.read().decode('utf-8') - logger.info(f"Sent request to {self._provider}, got back a response.") + try: + with urllib.request.urlopen(self._provider, parsedArgs, timeout = OPENID_TIMEOUT) as requestData: + responseData = requestData.read().decode("utf-8") + logger.info(f"Sent request to {self._provider}, got back a response.") + except Exception as e: + logger.warning(f"Steam OpenID verification failed: {e}") + return False fields = {} diff --git a/setup.py b/setup.py index b86008a..1da7f6f 100644 --- a/setup.py +++ b/setup.py @@ -5,7 +5,7 @@ setuptools.setup( name="steamsignin", - version="1.1.2", + version="1.1.3", author="TeddiO", author_email="", description="OpenID 2.0 sign in for Steam", @@ -20,6 +20,6 @@ "License :: OSI Approved :: GNU General Public License v2 (GPLv2)", "Operating System :: OS Independent", ], - packages=setuptools.find_packages(exclude=('samples')), + packages=setuptools.find_packages(exclude=('samples', '.github')), python_requires=">=3.6" ) \ No newline at end of file diff --git a/test/tests.py b/test/tests.py new file mode 100644 index 0000000..a2b6f1a --- /dev/null +++ b/test/tests.py @@ -0,0 +1,93 @@ +import unittest +import sys +import os +import logging +from unittest.mock import patch +import urllib.error +import socket + +sys.path.append(os.path.join(os.path.dirname(os.path.dirname(__file__)))) +from pysteamsignin.steamsignin import SteamSignIn + + +def valid_results(): + steam_id = "12345678901234567" + claimed = f"https://steamcommunity.com/openid/id/{steam_id}" + + return { + "openid.assoc_handle": "assoc", + "openid.signed": "claimed_id,identity", + "openid.sig": "sig", + "openid.ns": "http://specs.openid.net/auth/2.0", + "openid.claimed_id": claimed, + "openid.identity": claimed, + } + + +class FakeSteamResponse: + def __init__(self, body): + self._body = body.encode("utf-8") + + def read(self): + return self._body + + def __enter__(self): + return self + + def __exit__(self, exc_type, exc, tb): + pass + + +class TestSteamSignIn(unittest.TestCase): + + @patch("urllib.request.urlopen") + def test_valid_openid_response_returns_steamid_string(self, mock_urlopen): + mock_urlopen.return_value = FakeSteamResponse("is_valid:true\n") + + signin = SteamSignIn() + result = signin.ValidateResults(valid_results()) + + self.assertEqual(result, "12345678901234567") + + @patch("urllib.request.urlopen") + def test_steam_is_valid_false_denies_login(self, mock_urlopen): + mock_urlopen.return_value = FakeSteamResponse("is_valid:false\n") + + signin = SteamSignIn() + result = signin.ValidateResults(valid_results()) + + self.assertFalse(result) + + @patch("urllib.request.urlopen", side_effect = socket.timeout("timed out")) + def test_openid_timeout_fails_closed_and_logs_warning(self, mock_urlopen): + with self.assertLogs("pysteamsignin.steamsignin", level = logging.WARNING) as logs: + signin = SteamSignIn() + result = signin.ValidateResults(valid_results()) + + self.assertFalse(result) + self.assertIn("Steam OpenID verification failed", logs.output[0]) + + @patch("urllib.request.urlopen", side_effect = urllib.error.URLError("connection failed")) + def test_network_error_fails_closed_and_logs_warning(self, mock_urlopen): + with self.assertLogs("pysteamsignin.steamsignin", level = logging.WARNING) as logs: + signin = SteamSignIn() + result = signin.ValidateResults(valid_results()) + + self.assertFalse(result) + self.assertIn("Steam OpenID verification failed", logs.output[0]) + + @patch("urllib.request.urlopen") + def test_claimed_id_identity_mismatch_fails_validation(self, mock_urlopen): + mock_urlopen.return_value = FakeSteamResponse("is_valid:true\n") + + results = valid_results() + results["openid.identity"] = "https://steamcommunity.com/openid/id/DIFFERENT" + + signin = SteamSignIn() + result = signin.ValidateResults(results) + + self.assertFalse(result) + + +if __name__ == "__main__": + unittest.main()