aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRalf Jung <post@ralfj.de>2015-02-22 22:58:37 +0100
committerRalf Jung <post@ralfj.de>2015-02-22 22:58:37 +0100
commit1a695451f3a3261b0d73884b372f579a594b8313 (patch)
treeaf3b5cbc369ecbe503802efcf4aa35c207c8a5bd
parent5e4cc8e8aed90a3f5464cbdd1656e47bf3fc810e (diff)
verify the HMAC that GitHub sends
-rw-r--r--git_mirror.py18
-rwxr-xr-xwebhook-core.py17
-rwxr-xr-xwebhook.py11
3 files changed, 23 insertions, 23 deletions
diff --git a/git_mirror.py b/git_mirror.py
index 0bd4e81..3a65d85 100644
--- a/git_mirror.py
+++ b/git_mirror.py
@@ -22,7 +22,8 @@
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#==============================================================================
import sys, os, os.path, subprocess
-import configparser, itertools, json, re
+import configparser, itertools, re
+import hmac, hashlib
import email.mime.text, email.utils, smtplib
mail_sender = "null@localhost"
@@ -76,21 +77,13 @@ def send_mail(subject, text, recipients, sender, replyTo = None):
s.sendmail(sender, recipients, msg.as_string())
s.quit()
-def get_github_payload():
- '''Reeturn the github-style JSON encoded payload (as if we were called as a github webhook)'''
- try:
- data = sys.stdin.buffer.read()
- data = json.loads(data.decode('utf-8'))
- return data
- except:
- return {} # nothing read
-
class Repo:
def __init__(self, name, conf):
'''Creates a repository from a section of the git-mirror configuration file'''
self.name = name
self.local = conf['local']
self.owner = conf['owner'] # email address to notify in case of problems
+ self.hmac_secret = conf['hmac-secret'].encode('utf-8')
self.deploy_key = conf['deploy-key'] # the SSH ky used for authenticating against remote hosts
self.mirrors = {} # maps mirrors to their URLs
mirror_prefix = 'mirror-'
@@ -102,6 +95,11 @@ class Repo:
global mail_sender
send_mail("git-mirror {0}".format(self.name), msg, recipients = [self.owner], sender = mail_sender)
+ def compute_hmac(self, data):
+ h = hmac.new(self.hmac_secret, digestmod = hashlib.sha1)
+ h.update(data)
+ return h.hexdigest()
+
def find_mirror_by_url(self, match_urls):
for mirror, url in self.mirrors.items():
if url in match_urls:
diff --git a/webhook-core.py b/webhook-core.py
index d4c1ab7..934d41f 100755
--- a/webhook-core.py
+++ b/webhook-core.py
@@ -24,9 +24,22 @@
#==============================================================================
# This is the hook called by GitHub as webhook. It updats the local repository, and then all the other mirrors.
-import sys, traceback
+import sys, traceback, json
from git_mirror import *
+def get_github_payload(repo, signature):
+ '''Return the github-style JSON encoded payload (as if we were called as a github webhook)'''
+ data = sys.stdin.buffer.read()
+ verify_signature = repo.compute_hmac(data)
+ if signature != "sha1="+verify_signature:
+ raise Exception("You are not GitHub!")
+ try:
+ data = json.loads(data.decode('utf-8'))
+ return data
+ except ValueError:
+ return {} # nothing read
+
+
if __name__ == "__main__":
# call this with: <reponame> <event name> <signature>
repo = None # we will try to use this during exception handling
@@ -42,7 +55,7 @@ if __name__ == "__main__":
repo = repos[reponame]
# now sync this repository
- data = get_github_payload()
+ data = get_github_payload(repo, githubSignature)
if githubEvent == 'ping':
# github sends this initially
print("Content-Type: text/plain")
diff --git a/webhook.py b/webhook.py
index 33cae39..d91a4aa 100755
--- a/webhook.py
+++ b/webhook.py
@@ -29,17 +29,6 @@ webhook_core = "/home/git/git-mirror/webhook-core.py"
#
import urllib.request, urllib.parse, json, os, sys
-def is_github(remote_addr):
- '''Returns whether the address is a github hook address. This function requires Python 3.3.'''
- from ipaddress import ip_address, ip_network
- remote_addr = ip_address(ip_network)
- github = urllib.request.urlopen('https://api.github.com/meta').read()
- github = json.loads(github.decode('utf-8'))
- for net in github['hooks']:
- if remote_addr in ip_network(net):
- return True
- return False
-
# get repository from query string
query = os.getenv("QUERY_STRING")
query = urllib.parse.parse_qs(query)