From c899a8e254930a9f9af2f3c7cdeed10ff40e44f0 Mon Sep 17 00:00:00 2001 From: Stian Prestholdt Date: Tue, 21 Oct 2014 13:52:39 +0200 Subject: [PATCH] Add Python 3 support for FacebookAuthorization.parse_signed_data `json.loads` was expecting a string, but in python 3 `base64decode()` return bytes and that is why it bugged. We fix this by making sure the decoded payload data is in string and that `hmac.new()` is provided with arguments in bytes. `open_facebook.utils.smart_str` will do that job correctly in python 2 and 3. We also use `hmac.compare_digest()` which is the preferred way to compare those kinds of data to prevent timing analysis. If not `hmac.compare_digest` is available (python 2.7.7+) then we just compare logically. Fixes #491. --- open_facebook/api.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/open_facebook/api.py b/open_facebook/api.py index b023e018..9f16091a 100644 --- a/open_facebook/api.py +++ b/open_facebook/api.py @@ -464,7 +464,7 @@ def parse_signed_data(cls, signed_request, and http://sunilarora.org/parsing-signedrequest-parameter-in-python-bas ''' - from open_facebook.utils import base64_url_decode_php_style + from open_facebook.utils import base64_url_decode_php_style, smart_str l = signed_request.split('.', 2) encoded_sig = l[0] payload = l[1] @@ -472,7 +472,7 @@ def parse_signed_data(cls, signed_request, sig = base64_url_decode_php_style(encoded_sig) import hmac import hashlib - data = json.loads(base64_url_decode_php_style(payload)) + data = json.loads(base64_url_decode_php_style(payload).decode('utf-8')) algo = data.get('algorithm').upper() if algo != 'HMAC-SHA256': @@ -482,10 +482,12 @@ def parse_signed_data(cls, signed_request, logger.error('Unknown algorithm') return None else: - expected_sig = hmac.new(secret, msg=payload, + expected_sig = hmac.new(smart_str(secret), msg=smart_str(payload), digestmod=hashlib.sha256).digest() - if sig != expected_sig: + if (hasattr(hmac, 'compare_digest') and + not hmac.compare_digest(sig, expected_sig) or + sig != expected_sig): error_format = 'Signature %s didnt match the expected signature %s' error_message = error_format % (sig, expected_sig) send_warning(error_message)