Skip to content

Commit

Permalink
Merge pull request #122 from gadventures/migrating_signature
Browse files Browse the repository at this point in the history
Migrating utility methods from django-gapi-hooked
  • Loading branch information
marz619 committed Dec 12, 2019
2 parents 807ba3a + b926a2d commit b0e2c9b
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 0 deletions.
40 changes: 40 additions & 0 deletions gapipy/utils.py
Expand Up @@ -2,6 +2,8 @@
# Python 2 and 3
from __future__ import unicode_literals

import hashlib
import hmac
import sys
from functools import partial, wraps
from importlib import import_module
Expand Down Expand Up @@ -169,3 +171,41 @@ def wrapper(*args, **kwargs):
return func(*args, **kwargs).encode('utf-8')

return wrapper


def encode_if_not_bytes(data):
# This works in Py2 and 3: `bytes` is just an alias for `str` for Python 2
# versions since 2.6 (https://docs.python.org/3/whatsnew/2.6.html#pep-3112-byte-literals)
if isinstance(data, bytes):
return data

data = data.encode('utf-8')
return data


def compute_request_signature(app_key, request_body):
"""
Given an application key and request body, compute the signature as
directed by:
https://developers.gadventures.com/docs/webhooks.html#verifying-a-webhook
To verify that incoming webhooks are coming from the G API, we check
that this value matches the data in the request's `X-Gapi-Signature`
header.
"""
return hmac.new(
encode_if_not_bytes(app_key),
encode_if_not_bytes(request_body),
hashlib.sha256).hexdigest()

def compute_webhook_validation_key(app_key):
"""
Given an application key, compute the SHA256 hex digest (aka "Webhooks
Validation Key") as directed by:
https://developers.gadventures.com/docs/webhooks.html#registering-a-webhook
To successfully respond to incoming webhooks we include this value in
our response's `X-Application-SHA256` header.
"""
return hashlib.sha256(
encode_if_not_bytes(app_key)).hexdigest()
38 changes: 38 additions & 0 deletions tests/test_utils.py
Expand Up @@ -14,6 +14,8 @@
humanize_time,
location_label,
enforce_string_type,
compute_request_signature,
compute_webhook_validation_key,
)


Expand Down Expand Up @@ -66,3 +68,39 @@ def test_location_label(self):
place_2 = Place(name='Montreal')
self.assertEqual(location_label(place_1, place_2), 'Toronto – Montreal')
self.assertEqual(location_label(place_1, place_1), 'Toronto')

def test_compute_request_signature_handles_unicode_and_str(self):
"""
Test that compute_request_signature doesn't explode when given both unicode
and str inputs.
NOTE: All this test does is validate that calling the method does not raise an
exception for the different scenarios.
"""
# Matching types for both args
compute_request_signature(str('str app key'), str('str request body'))
compute_request_signature(u'unicode app key', u'unicode request body')

# Mismatched types for the args
compute_request_signature(str('str app key'), u'unicode request body')
compute_request_signature(u'unicode app key', str('str request body'))

# Including special characters (really this should never come up for the
# app key... should only contain digits and a-f as it is a hex string)
compute_request_signature(str('str app key'), u'ʎpoq ʇsǝnbǝɹ ǝpoɔᴉun')
compute_request_signature(u'ʎǝʞ ddɐ ǝpoɔᴉun', str('str request body'))
compute_request_signature(u'ʎǝʞ ddɐ ǝpoɔᴉun', u'ʎpoq ʇsǝnbǝɹ ǝpoɔᴉun')

def test_compute_webhook_validation_key_handles_unicode_and_str(self):
"""
Test that compute_webhook_validation_key doesn't explode when given unicode
or str input.
NOTE: All this test does is validate that calling the method does not raise an
exception for the different scenarios.
"""
# Bytestring/Unicode with only ASCII chars
compute_webhook_validation_key(str('str app key'))
compute_webhook_validation_key(u'unicode app key')

# Non-ASCII chars! (really this should never come up because app keys
# should only contain digits and a-f as they are hex strings)
compute_webhook_validation_key(u'ʎǝʞ ddɐ ǝpoɔᴉun')

0 comments on commit b0e2c9b

Please sign in to comment.