Enhancement: Option to return app id from webhook

This commit is contained in:
Kyle Hornberg
2018-02-07 08:40:21 -06:00
parent 44a7c1dc55
commit 6f05bc4204
3 changed files with 77 additions and 41 deletions
+47
View File
@@ -0,0 +1,47 @@
import hashlib
import hmac
import json
from uuid import UUID
from octokit import utils
def valid_signature(headers, payload, secret):
encoding = 'utf-8'
algo, sig = headers.get('X-Hub-Signature').split('=')
digest = hmac.new(secret.encode(encoding), json.dumps(payload).encode(encoding), getattr(hashlib, algo)).hexdigest()
return hmac.compare_digest(sig.encode(encoding), digest.encode(encoding))
def valid_guid(guid):
try:
return str(UUID(guid)) == guid
except ValueError:
return False
def valid_event(event, events):
return event in utils.get_json_data('events.json') and (event in events or '*' in events)
def valid_user_agent(ua):
return ua.startswith('GitHub-Hookshot/')
def valid_headers(headers, events, verify_user_agent):
if not valid_guid(headers.get('X-GitHub-Delivery')):
return False
if not valid_event(headers.get('X-GitHub-Event'), events):
return False
if verify_user_agent and not valid_user_agent(headers.get('User-Agent', '')):
return False
return True
def verify(headers, payload, secret, events=[], verify_user_agent=False, return_app_id=False):
if not valid_headers(headers, events, verify_user_agent):
return False
validity = valid_signature(headers, payload, secret)
if validity and return_app_id and headers.get('X-GitHub-Event') == 'ping':
return payload.get('hook').get('app_id')
return validity
-41
View File
@@ -1,41 +0,0 @@
import hashlib
import hmac
import json
from uuid import UUID
from octokit import utils
def _compare(headers, payload, secret):
encoding = 'utf-8'
algo, sig = headers.get('X-Hub-Signature').split('=')
digest = hmac.new(secret.encode(encoding), json.dumps(payload).encode(encoding), getattr(hashlib, algo)).hexdigest()
return hmac.compare_digest(sig.encode(encoding), digest.encode(encoding))
def invalid_guid(guid):
try:
return str(UUID(guid)) != guid
except ValueError:
return True
def invalid_event(event, events):
if event not in utils.get_json_data('events.json'):
return True
if event not in events and '*' not in events:
return True
def valid_user_agent(ua):
return ua.startswith('GitHub-Hookshot/')
def verify(headers, payload, secret, events=[], verify_user_agent=False):
if invalid_guid(headers.get('X-GitHub-Delivery')):
return False
if invalid_event(headers.get('X-GitHub-Event'), events):
return False
if verify_user_agent and not valid_user_agent(headers.get('User-Agent', '')):
return False
return _compare(headers, payload, secret)
+30
View File
@@ -89,3 +89,33 @@ class TestWebhook(object):
secret = 'secret'
events = ['push']
assert webhook.verify(headers, payload, secret, events=events, verify_user_agent=True) is False
def test_verify_ping_event(self):
headers = {
'X-Hub-Signature': 'sha1=02ad50e35622a4cf597de5fb86f4d59520f5adda',
'X-GitHub-Event': 'ping',
'X-GitHub-Delivery': '72d3162f-cc78-11e3-81ab-4c9367dc0958',
'User-Agent': 'GitHub-Hookshot/',
}
payload = {
'hook': {
'type': 'App',
'id': 11,
'active': True,
'events': ['pull_request'],
'app_id': 42,
}
}
secret = 'secret'
assert webhook.verify(headers, payload, secret, events=['*'], return_app_id=True) == 42
def test_can_request_app_id_be_returned_on_non_ping_events(self):
headers = {
'X-Hub-Signature': 'sha1=5d61605c3feea9799210ddcb71307d4ba264225f',
'X-GitHub-Event': 'push',
'X-GitHub-Delivery': '72d3162f-cc78-11e3-81ab-4c9367dc0958',
'User-Agent': 'GitHub-Hookshot/',
}
payload = {}
secret = 'secret'
assert webhook.verify(headers, payload, secret, events=['*'], return_app_id=True)