aboutsummaryrefslogtreecommitdiffstats
path: root/local
diff options
context:
space:
mode:
authorkongr45gpen <electrovesta@gmail.com>2016-03-15 16:41:58 +0200
committerkongr45gpen <electrovesta@gmail.com>2016-03-15 16:41:58 +0200
commit23d851aff066a39e3ceb01f85c30539e467a70ea (patch)
tree2feeadac920c62161163b3b4d7ee0ae8361787b9 /local
parente56a487b2a6672284a8f18a816782b5fdebf3b08 (diff)
downloadsupybot_github-23d851aff066a39e3ceb01f85c30539e467a70ea.tar.gz
supybot_github-23d851aff066a39e3ceb01f85c30539e467a70ea.tar.bz2
supybot_github-23d851aff066a39e3ceb01f85c30539e467a70ea.zip
Add support for github secrets
Diffstat (limited to 'local')
-rw-r--r--local/globals.py2
-rw-r--r--local/handler/GithubHandler.py37
-rw-r--r--local/utility.py22
3 files changed, 52 insertions, 9 deletions
diff --git a/local/globals.py b/local/globals.py
index 6cc8c7b..b389cab 100644
--- a/local/globals.py
+++ b/local/globals.py
@@ -2,7 +2,9 @@ def init():
global messageList
global configOverrides
global travisStatuses
+ global secretDB
messageList = []
configOverrides = {}
travisStatuses = {}
+ secretDB = None
diff --git a/local/handler/GithubHandler.py b/local/handler/GithubHandler.py
index 4d420e3..53ea740 100644
--- a/local/handler/GithubHandler.py
+++ b/local/handler/GithubHandler.py
@@ -1,10 +1,12 @@
import os
import re
+import hmac
import json
import time
import random
import urllib
import urllib2
+import hashlib
import urlparse
import threading
import BaseHTTPServer
@@ -37,17 +39,12 @@ class GithubHandler(BaseHTTPServer.BaseHTTPRequestHandler):
def do_POST(s):
"""Respond to a POST request."""
length = int(s.headers['Content-Length'])
+ payload = s.rfile.read(length).decode('utf-8')
if 'content-type' not in s.headers or s.headers['content-type'] == 'application/x-www-form-urlencoded':
- post_data = urlparse.parse_qs(s.rfile.read(length).decode('utf-8'))
+ post_data = urlparse.parse_qs(payload)
data = json.loads(post_data['payload'][0])
else:
- data = json.loads(s.rfile.read(length).decode('utf-8'))
-
- s.send_response(200)
- s.send_header('Content-type', 'text/html')
- s.end_headers()
- s.wfile.write("Thanks, you're awesome.\n")
- s.wfile.write(s.path.split('/'))
+ data = json.loads(payload)
if 'X-GitHub-Event' in s.headers:
eventType = s.headers['X-GitHub-Event']
@@ -58,7 +55,7 @@ class GithubHandler(BaseHTTPServer.BaseHTTPRequestHandler):
if not os.path.exists('requests/'):
os.makedirs('requests')
- f = open('requests/' + eventType + strftime("%Y-%m-%d %H:%M:%S") + '.json', 'w')
+ f = open('requests/' + eventType.replace('/','_') + strftime("%Y-%m-%d %H:%M:%S") + '.json', 'w')
f.write(json.dumps(data, sort_keys=True, indent=4, separators=(',', ': ')))
f.close()
@@ -92,11 +89,33 @@ class GithubHandler(BaseHTTPServer.BaseHTTPRequestHandler):
i+=1
+ s.send_response(200)
+ s.send_header('Content-type', 'text/html')
+ s.end_headers()
+ s.wfile.write("Thanks, you're awesome.\n")
+ s.wfile.write(s.path.split('/'))
+
if requireCode and receivedcode != configValue('passcode'):
# The password is wrong
s.wfile.write("The password is wrong")
return
+ secret = getChannelSecret(channel)
+ if secret is not None:
+ if not 'X-Hub-Signature' in s.headers:
+ s.wfile.write("This channel requires a secret")
+ return
+
+ digest = "sha1=%s" % (hmac.new(secret, payload, hashlib.sha1).hexdigest(),)
+ log.debug("expected digest: %s", digest)
+
+ provided = s.headers['X-Hub-Signature']
+ log.debug("provided digest: %s", provided)
+
+ if not secureCompare(digest, provided):
+ s.wfile.write("Invalid secret key")
+ return
+
brackets = parseBrackets(configValue('brackets'))
themeName = configValue('theme')
diff --git a/local/utility.py b/local/utility.py
index de540a6..2594b61 100644
--- a/local/utility.py
+++ b/local/utility.py
@@ -1,5 +1,7 @@
import re
import math
+import random
+import string
import urllib2
import supybot.conf as conf
@@ -134,6 +136,26 @@ def isStatusVisible(repo, status):
globals.travisStatuses[repo] = status
return changed
+def randomString(length):
+ """Returns a securely generated random string of a specific length"""
+ return ''.join(random.SystemRandom().choice(
+ string.ascii_uppercase + string.ascii_lowercase + string.digits
+ ) for _ in range(length))
+
+def secureCompare(s1, s2):
+ """Securely compare two strings"""
+ return sum(i != j for i, j in zip(s1, s2)) is 0
+
+def getChannelSecret(channel):
+ """Returns a secret for a channel, or None if that channel has no secret"""
+ if globals.secretDB is None:
+ return None
+ try:
+ record = globals.secretDB.get(channel, 1)
+ return record.secret
+ except KeyError:
+ return None
+
def hexToMirc(hash):
colors = {
'white': (255, 255, 255),

© 2014-2024 Faster IT GmbH | imprint | privacy policy