import hashlib import hmac import json import os from ipaddress import ip_address, ip_network import requests from dotenv import load_dotenv from flask import Flask, abort, request def create_app(): app = Flask(__name__) load_dotenv() app.config["GITHUB_SECRET"] = os.getenv("GITHUB_SECRET") app.config["DISCORD_WEBHOOK"] = os.getenv("DISCORD_WEBHOOK") return app app = create_app() def verify_src_ip(src_ip): allowed_ips = requests.get("https://api.github.com/meta").json()["hooks"] return any(src_ip in ip_network(valid_ip) for valid_ip in allowed_ips) def verify_hmac_hash(data, signature): github_secret = bytes(app.config["GITHUB_SECRET"], "ascii") mac = hmac.new(github_secret, msg=data, digestmod=hashlib.sha1) return hmac.compare_digest("sha1=" + mac.hexdigest(), signature) @app.route("/github-payload", methods=["POST"]) def github_payload(): src_ip = ip_address(request.headers.get("X-Real-IP", request.access_route[0])) if not verify_src_ip(src_ip): app.logger.debug(f"invalid source ip: {src_ip}... aborting request") abort(403) signature = request.headers.get("X-Hub-Signature") data = request.data if not verify_hmac_hash(data, signature): app.logger.debug("failed to verify signature... aborting request") abort(403) payload = request.get_json() match event_type := request.headers.get("X-GitHub-Event"): case "ping": return json.dumps({"msg": "pong"}) case "issues": issues_handler(payload) case _: app.logger.debug(f"no handler defined for event {event_type}... continuing") return ("", 200, None) def issues_handler(payload): embed = { "author": { "name": payload["sender"]["login"], "icon_url": payload["sender"]["avatar_url"], }, "title": f"[{payload['repository']['full_name']}] Issue {payload['action'].capitalize()}: #{payload['issue']['number']} {payload['issue']['title']}", "url": payload["issue"]["html_url"], "description": payload["issue"].get("body"), } data = { "username": "Github-OpenGist", "embeds": [embed], } send_discord_webhook(app.config["DISCORD_WEBHOOK"], data) def send_discord_webhook(webhook_url, data): requests.post(webhook_url, json=data) if __name__ == "__main__": app.run(debug=True, port=5000)