From 99b3fa664c6611be9716c2671dce25ef847a9708 Mon Sep 17 00:00:00 2001 From: Lee Penkman Date: Sat, 7 Jun 2025 14:43:43 +1200 Subject: [PATCH 1/2] CI: drop Python 3.11 --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d6d30a3..43ef1cd 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -10,7 +10,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: ['3.11', '3.12'] + python-version: ['3.12'] steps: - uses: actions/checkout@v4 - uses: actions/setup-python@v5 From adb45916240c6b5b0bb9f62fb687586912700ee2 Mon Sep 17 00:00:00 2001 From: Lee Penkman Date: Sat, 7 Jun 2025 14:52:43 +1200 Subject: [PATCH 2/2] Add Facebook auth tests and pin test deps --- README.md | 1 + gameon/facebook.py | 20 +++++++++---------- requirements-test.txt | 3 ++- tests/unit/test_facebook.py | 39 +++++++++++++++++++++++++++++++++++++ 4 files changed, 51 insertions(+), 12 deletions(-) create mode 100644 tests/unit/test_facebook.py diff --git a/README.md b/README.md index 1c856ea..5f7edde 100755 --- a/README.md +++ b/README.md @@ -75,6 +75,7 @@ sudo apt install -y python3.9-distutils pip install -r requirements.txt pip install -r questions/inference_server/model-requirements.txt pip install -r dev-requirements.txt +pip install -r requirements-test.txt ``` Using cuda is important to speed up inference. diff --git a/gameon/facebook.py b/gameon/facebook.py index 2ba249d..ee061e2 100755 --- a/gameon/facebook.py +++ b/gameon/facebook.py @@ -33,8 +33,6 @@ """ -import cgi -import time import urllib import urllib2 import httplib @@ -218,7 +216,7 @@ def put_photo(self, image, message=None, album_id=None, **kwargs): data = urllib2.urlopen(req).read() #For Python 3 use this: #except urllib2.HTTPError as e: - except urllib2.HTTPError, e: + except urllib2.HTTPError as e: data = e.read() # Facebook sends OAuth errors as 400, and urllib2 # throws an exception, we want a GraphAPIError try: @@ -263,7 +261,7 @@ def _encode_multipart_form(self, fields): else: L.append('Content-Disposition: form-data; name="%s"' % key) L.append('') - if isinstance(value, unicode): + if isinstance(value, str): logging.debug("Convert to ascii") value = value.encode('ascii') L.append(value) @@ -293,7 +291,7 @@ def request(self, path, args=None, post_args=None): file = urllib2.urlopen("https://graph.facebook.com/" + path + "?" + urllib.urlencode(args), post_data, timeout=self.timeout) - except urllib2.HTTPError, e: + except urllib2.HTTPError as e: response = _parse_json(e.read()) raise GraphAPIError(response) except TypeError: @@ -340,7 +338,7 @@ def fql(self, query, args=None, post_args=None): use the multiquery method else use single query """ - if not isinstance(query, basestring): + if not isinstance(query, str): args["queries"] = query fql_method = 'fql.multiquery' else: @@ -367,7 +365,7 @@ def fql(self, query, args=None, post_args=None): #Return a list if success, return a dictionary if failed if type(response) is dict and "error_code" in response: raise GraphAPIError(response) - except Exception, e: + except Exception as e: raise e finally: file.close() @@ -408,21 +406,21 @@ def __init__(self, result): self.result = result try: self.type = result["error_code"] - except: + except Exception: self.type = "" # OAuth 2.0 Draft 10 try: self.message = result["error_description"] - except: + except Exception: # OAuth 2.0 Draft 00 try: self.message = result["error"]["message"] - except: + except Exception: # REST server style try: self.message = result["error_msg"] - except: + except Exception: self.message = result Exception.__init__(self, self.message) diff --git a/requirements-test.txt b/requirements-test.txt index 8a1e38e..ee8652b 100644 --- a/requirements-test.txt +++ b/requirements-test.txt @@ -1,5 +1,6 @@ pytest==7.3.1 pytest-cov==4.1.0 -ruff +numpy +ruff==0.11.10 httpx colorama diff --git a/tests/unit/test_facebook.py b/tests/unit/test_facebook.py new file mode 100644 index 0000000..84bc60a --- /dev/null +++ b/tests/unit/test_facebook.py @@ -0,0 +1,39 @@ +import base64 +import hashlib +import hmac +import json + +import sys +import urllib.request as urllib_request +import http.client as http_client +import urllib.parse as urllib_parse +import cgi + +sys.modules.setdefault("urllib2", urllib_request) +sys.modules.setdefault("httplib", http_client) +sys.modules.setdefault("urlparse", urllib_parse) +cgi.parse_qs = urllib_parse.parse_qs + +from gameon.facebook import parse_signed_request # noqa: E402 + + +def make_signed_request(data: dict, secret: str) -> str: + payload = base64.urlsafe_b64encode(json.dumps(data).encode()).rstrip(b"=").decode() + sig = hmac.new(secret.encode('ascii'), msg=payload.encode('ascii'), digestmod=hashlib.sha256).digest() + encoded_sig = base64.urlsafe_b64encode(sig).rstrip(b"=").decode() + return f"{encoded_sig}.{payload}" + + +def test_parse_signed_request_valid(): + secret = "secret" + data = {"algorithm": "HMAC-SHA256", "user_id": "123"} + sr = make_signed_request(data, secret) + result = parse_signed_request(sr, secret) + assert result == data + + +def test_parse_signed_request_invalid_signature(): + secret = "secret" + data = {"algorithm": "HMAC-SHA256", "user_id": "123"} + sr = make_signed_request(data, secret) + assert parse_signed_request(sr, "wrong") is False