mirror of
https://github.com/khornberg/octokit.py
synced 2026-05-15 05:02:32 +03:00
Feature: verify webhooks
This commit is contained in:
@@ -85,6 +85,11 @@ Default values::
|
||||
|
||||
TODO Show them
|
||||
|
||||
Webhooks::
|
||||
|
||||
from octokit import webhook
|
||||
webhook.verify(headers, payload, secret, events=['push'])
|
||||
|
||||
Authentication
|
||||
--------------
|
||||
|
||||
|
||||
@@ -0,0 +1,121 @@
|
||||
[
|
||||
"*",
|
||||
"error",
|
||||
"commit_comment",
|
||||
"commit_comment.created",
|
||||
"create",
|
||||
"delete",
|
||||
"deployment",
|
||||
"deployment_status",
|
||||
"fork",
|
||||
"gollum",
|
||||
"installation",
|
||||
"installation_repositories",
|
||||
"installation_repositories.added",
|
||||
"installation_repositories.removed",
|
||||
"installation.created",
|
||||
"installation.deleted",
|
||||
"issue_comment",
|
||||
"issue_comment.created",
|
||||
"issue_comment.deleted",
|
||||
"issue_comment.edited",
|
||||
"issues",
|
||||
"issues.assigned",
|
||||
"issues.closed",
|
||||
"issues.demilestoned",
|
||||
"issues.edited",
|
||||
"issues.labeled",
|
||||
"issues.milestoned",
|
||||
"issues.opened",
|
||||
"issues.reopened",
|
||||
"issues.unassigned",
|
||||
"issues.unlabeled",
|
||||
"label",
|
||||
"label.created",
|
||||
"label.deleted",
|
||||
"label.edited",
|
||||
"marketplace_purchase",
|
||||
"marketplace_purchase.cancelled",
|
||||
"marketplace_purchase.changed",
|
||||
"marketplace_purchase.purchased",
|
||||
"member",
|
||||
"member.added",
|
||||
"member.deleted",
|
||||
"member.edited",
|
||||
"membership",
|
||||
"membership.added",
|
||||
"membership.removed",
|
||||
"milestone",
|
||||
"milestone.closed",
|
||||
"milestone.created",
|
||||
"milestone.deleted",
|
||||
"milestone.edited",
|
||||
"milestone.opened",
|
||||
"org_block",
|
||||
"org_block.blocked",
|
||||
"org_block.unblocked",
|
||||
"organization",
|
||||
"organization.member_added",
|
||||
"organization.member_invited",
|
||||
"organization.member_removed",
|
||||
"page_build",
|
||||
"ping",
|
||||
"project",
|
||||
"project_card",
|
||||
"project_card.closed",
|
||||
"project_card.created",
|
||||
"project_card.deleted",
|
||||
"project_card.edited",
|
||||
"project_card.reopened",
|
||||
"project_column",
|
||||
"project_column.created",
|
||||
"project_column.deleted",
|
||||
"project_column.edited",
|
||||
"project_column.moved",
|
||||
"project.converted",
|
||||
"project.created",
|
||||
"project.deleted",
|
||||
"project.edited",
|
||||
"project.moved",
|
||||
"public",
|
||||
"pull_request",
|
||||
"pull_request_review",
|
||||
"pull_request_review_comment",
|
||||
"pull_request_review_comment.created",
|
||||
"pull_request_review_comment.deleted",
|
||||
"pull_request_review_comment.edited",
|
||||
"pull_request_review.dismissed",
|
||||
"pull_request_review.edited",
|
||||
"pull_request_review.submitted",
|
||||
"pull_request.assigned",
|
||||
"pull_request.closed",
|
||||
"pull_request.edited",
|
||||
"pull_request.labeled",
|
||||
"pull_request.opened",
|
||||
"pull_request.reopened",
|
||||
"pull_request.review_request_removed",
|
||||
"pull_request.review_requested",
|
||||
"pull_request.synchronize",
|
||||
"pull_request.unassigned",
|
||||
"pull_request.unlabeled",
|
||||
"push",
|
||||
"release",
|
||||
"release.published",
|
||||
"repository",
|
||||
"repository.archived",
|
||||
"repository.created",
|
||||
"repository.deleted",
|
||||
"repository.privatized",
|
||||
"repository.publicized",
|
||||
"repository.unarchived",
|
||||
"status",
|
||||
"team",
|
||||
"team_add",
|
||||
"team.added_to_repository",
|
||||
"team.created",
|
||||
"team.deleted",
|
||||
"team.edited",
|
||||
"team.removed_from_repository",
|
||||
"watch",
|
||||
"watch.started"
|
||||
]
|
||||
@@ -1,3 +1,5 @@
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
|
||||
|
||||
@@ -6,3 +8,8 @@ def snake_case(string):
|
||||
From https://gist.github.com/jaytaylor/3660565#gistcomment-2271689
|
||||
"""
|
||||
return re.compile(r'(?!^)(?<!_)([A-Z])').sub(r'_\1', string).lower()
|
||||
|
||||
|
||||
def get_json_data(filename):
|
||||
with open(os.path.join(os.path.dirname(__file__), 'data', 'rest.json'), 'r') as f:
|
||||
return json.load(f)
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
import hashlib
|
||||
import hmac
|
||||
import json
|
||||
|
||||
from octokit import utils
|
||||
|
||||
|
||||
def verify(headers, payload, secret, events=[]):
|
||||
event = headers.get('X-GitHub-Event')
|
||||
if event not in utils.get_json_data('events.json'):
|
||||
return False
|
||||
if event not in events and '*' not in events:
|
||||
return False
|
||||
return _compare(headers, payload, secret)
|
||||
|
||||
|
||||
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))
|
||||
@@ -0,0 +1,38 @@
|
||||
from octokit import webhook
|
||||
|
||||
|
||||
class TestWebhook(object):
|
||||
|
||||
def test_can_verify_webhook(self):
|
||||
headers = {'X-Hub-Signature': 'sha1=5d61605c3feea9799210ddcb71307d4ba264225f', 'X-GitHub-Event': 'push'}
|
||||
payload = {}
|
||||
secret = 'secret'
|
||||
events = ['push']
|
||||
assert webhook.verify(headers, payload, secret, events=events)
|
||||
|
||||
def test_can_filter_webhook_events(self):
|
||||
headers = {'X-Hub-Signature': 'sha1=5d61605c3feea9799210ddcb71307d4ba264225f'}
|
||||
payload = {}
|
||||
secret = 'secret'
|
||||
events = ['push']
|
||||
assert webhook.verify(headers, payload, secret, events=events) is False
|
||||
|
||||
def test_must_specify_events_to_allow(self):
|
||||
headers = {'X-Hub-Signature': 'sha1=5d61605c3feea9799210ddcb71307d4ba264225f'}
|
||||
payload = {}
|
||||
secret = 'secret'
|
||||
assert webhook.verify(headers, payload, secret) is False
|
||||
|
||||
def test_can_specify_all_events(self):
|
||||
headers = {'X-Hub-Signature': 'sha1=5d61605c3feea9799210ddcb71307d4ba264225f', 'X-GitHub-Event': 'push'}
|
||||
payload = {}
|
||||
secret = 'secret'
|
||||
events = ['*']
|
||||
assert webhook.verify(headers, payload, secret, events=events)
|
||||
|
||||
def test_only_known_events_are_valid(self):
|
||||
headers = {'X-Hub-Signature': 'sha1=5d61605c3feea9799210ddcb71307d4ba264225f', 'X-GitHub-Event': 'pushy'}
|
||||
payload = {}
|
||||
secret = 'secret'
|
||||
events = ['pushy']
|
||||
assert webhook.verify(headers, payload, secret, events=events) is False
|
||||
Reference in New Issue
Block a user