Add Github webhook support

This commit is contained in:
rubenwardy 2020-01-24 21:39:35 +00:00
parent beb9c0e959
commit d4936e18ee
1 changed files with 61 additions and 4 deletions

View File

@ -18,19 +18,21 @@ from flask import Blueprint
bp = Blueprint("github", __name__) bp = Blueprint("github", __name__)
from flask import redirect, url_for, request, flash from flask import redirect, url_for, request, flash, abort
from flask_user import current_user from flask_user import current_user
from sqlalchemy import func from sqlalchemy import func
from flask_github import GitHub from flask_github import GitHub
from app import github from app import github, csrf
from app.models import db, User from app.models import db, User, APIToken, Package
from app.utils import loginUser from app.utils import loginUser
from app.blueprints.api.support import error, handleCreateRelease
import hmac
@bp.route("/github/start/") @bp.route("/github/start/")
def start(): def start():
return github.authorize("") return github.authorize("")
@bp.route("/user/github/callback/") @bp.route("/github/callback/")
@github.authorized_handler @github.authorized_handler
def callback(oauth_token): def callback(oauth_token):
next_url = request.args.get("next") next_url = request.args.get("next")
@ -72,3 +74,58 @@ def callback(oauth_token):
else: else:
flash("Authorization failed [err=gh-login-failed]", "danger") flash("Authorization failed [err=gh-login-failed]", "danger")
return redirect(url_for("user.login")) return redirect(url_for("user.login"))
@bp.route("/github/webhook/", methods=["POST"])
@csrf.exempt
def webhook():
json = request.json
# Get package
github_url = "github.com/" + json["repository"]["full_name"]
package = Package.query.filter(Package.repo.like("%{}%".format(github_url))).first()
if package is None:
return error(400, "Unknown package")
# Get all tokens for package
possible_tokens = APIToken.query.filter_by(package=package).all()
actual_token = None
#
# Check signature
#
header_signature = request.headers.get('X-Hub-Signature')
if header_signature is None:
return error(403, "Expected payload signature")
sha_name, signature = header_signature.split('=')
if sha_name != 'sha1':
return error(403, "Expected SHA1 payload signature")
for token in possible_tokens:
mac = hmac.new(token.access_token.encode("utf-8"), msg=request.data, digestmod='sha1')
if hmac.compare_digest(str(mac.hexdigest()), signature):
actual_token = token
break
if actual_token is None:
return error(403, "Invalid authentication")
#
# Check event
#
event = request.headers.get("X-GitHub-Event")
if event == "push":
title = json["head_commit"]["message"].partition("\n")[0]
ref = json["after"]
else:
return error(400, "Unknown event, expected 'push'")
#
# Perform release
#
return handleCreateRelease(actual_token, package, title, ref)