This repository has been archived on 2023-11-19. You can view files and clone it, but cannot push or open issues or pull requests.
webhooks/webhooks.py

380 lines
12 KiB
Python
Raw Permalink Normal View History

2022-06-25 00:16:00 +00:00
import logging
import base64
import hmac
import hashlib
2022-06-25 00:16:00 +00:00
import requests
import yaml
import os
2022-11-25 22:58:09 +00:00
import redis
2022-06-25 00:16:00 +00:00
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PublicKey
from flask import Flask, jsonify, request, abort
app = Flask(__name__)
# setup the environment
SNAP_USER_DATA = os.environ.get('SNAP_USER_DATA')
2022-09-27 18:19:00 +00:00
CONFIG_FILE = os.environ.get('CONFIG_FILE')
LOG_FILE = os.environ.get('LOG_FILE')
2022-11-25 22:58:09 +00:00
REDIS_HOST = os.environ.get('REDIS_HOST', 'localhost')
REDIS_PORT = os.environ.get('REDIS_PORT', 6379)
2022-06-25 00:16:00 +00:00
if SNAP_USER_DATA is None:
2022-09-27 18:19:00 +00:00
if CONFIG_FILE is None:
filename = 'config.yaml'
else:
filename = CONFIG_FILE
if LOG_FILE is None:
log_file = 'webhook.log'
else:
log_file = LOG_FILE
2022-06-25 00:16:00 +00:00
else:
filename = SNAP_USER_DATA + '/config.yaml'
log_file = SNAP_USER_DATA + '/webhook.log'
logging.basicConfig(level=logging.DEBUG, filename=log_file)
with open(filename, "rb") as config_file:
config = yaml.load(config_file, Loader=yaml.SafeLoader)
2022-11-25 22:58:09 +00:00
rs = redis.Redis(host=REDIS_HOST, port=REDIS_PORT)
2022-06-25 00:16:00 +00:00
srht_public_key = Ed25519PublicKey.from_public_bytes(
base64.b64decode(config['srht_payload_sig']))
# GitHub webhooks
# https://docs.github.com/en/developers/webhooks-and-events/webhooks/webhook-events-and-payloads
2022-06-25 00:16:00 +00:00
# Gittea webhooks
# https://docs.gitea.io/en-us/webhooks/
2022-06-25 00:16:00 +00:00
@app.route('/gitea/<gateway>', methods=['POST'])
def gitea_event(gateway=None):
secret = bytes(config["gitea_secret"], "utf-8")
signature = request.headers["X-Gitea-Signature"]
event = request.headers["X-Gitea-Event-Type"]
sigcheck = hmac.new(secret, msg=request.data, digestmod=hashlib.sha256).hexdigest()
if gateway is None:
logging.info("MISSING GATEWAY")
abort(400)
if sigcheck != signature:
logging.info("INVALID GITEA SIGNATURE")
abort(401)
if event == "push":
logging.debug(f"Gitea - {event} >> {gateway} ")
gt_push_event(gateway, request.json)
elif event == "issues":
logging.debug(f"Gitea - {event} >> {gateway} ")
gt_issue_event(gateway, request.json)
elif event == "issue_comment":
logging.debug(f"Gitea - {event} >> {gateway} ")
gt_comment_event(gateway, request.json)
else:
logging.info("UNKNOWN GITEA EVENT")
logging.debug(f"Gitea - {event} >> {gateway} ")
logging.debug(request.json)
return "", 200
def gt_push_event(gateway, data):
logging.debug(f">> {gateway}")
# logging.debug(data)
project = data["repository"]["full_name"]
username = data["pusher"]["username"]
branch = data['ref'][len('refs/heads/'):]
count = len(data["commits"])
s = "s" if count > 1 else ""
body = f"[{project}] {username} pushed {count} commit{s} to {branch}:\n"
for commit in data["commits"]:
cid = commit["id"][:8]
title = commit["message"]
url = commit["url"]
body += f"- [{cid}]({url}) {title}\n"
logging.debug(body)
mb_url = config["codeberg_gateway"]
payload = { 'gateway': gateway, 'username': "codeberg", 'text': body.rstrip() }
r = requests.post(mb_url, json=payload)
def gt_issue_event(gateway, data):
logging.debug(f">> {gateway}")
# logging.debug(data)
project = data["repository"]["full_name"]
issue = data["issue"]
username = issue["user"]["username"]
number = issue["number"]
title = issue["title"]
description = issue["body"]
action = data["action"]
body = f"[{project}] {username} {action} issue #{number}: {title}\n"
if action in ["opened", "reopened"]:
body += f"{description}"
logging.debug(body)
mb_url = config["codeberg_gateway"]
payload = { 'gateway': gateway, 'username': "codeberg", 'text': body.rstrip() }
r = requests.post(mb_url, json=payload)
def gt_comment_event(gateway, data):
logging.debug(f">> {gateway}")
# logging.debug(data)
project = data["repository"]["full_name"]
issue = data["issue"]
comment = data["comment"]
username = comment["user"]["username"]
number = issue["number"]
title = issue["title"]
action = data["action"]
note = data["comment"]["body"]
body = f"[{project}] {username} commented on issue #{number}: {title}\n"
body += f"> {note}"
logging.debug(body)
mb_url = config["codeberg_gateway"]
payload = { 'gateway': gateway, 'username': "codeberg", 'text': body.rstrip() }
r = requests.post(mb_url, json=payload)
# GitLab webhooks
# https://docs.gitlab.com/ee/user/project/integrations/webhook_events.html
2022-06-25 00:16:00 +00:00
@app.route('/gitlab/<gateway>', methods=['POST'])
def gitlab_event(gateway=None):
token = request.headers['X-Gitlab-Token']
event = request.headers['X-Gitlab-Event']
if gateway is None:
logging.info("MISSING GATEWAY")
abort(400)
if token != config['gitlab_token']:
logging.info("INVALID GITLAB TOKEN")
abort(401)
if event == "Push Hook":
logging.debug(f"GitLab - {event} >> {gateway} ")
gl_push_event(gateway, request.json)
elif event == "Issue Hook":
logging.debug(f"GitLab - {event} >> {gateway} ")
gl_issue_event(gateway, request.json)
elif event == "Note Hook":
logging.debug(f"GitLab - {event} >> {gateway} ")
gl_comment_event(gateway, request.json)
elif event == "Merge Request Hook":
logging.debug(f"GitLab - {event} >> {gateway} ")
gl_mr_event(gateway, request.json)
elif event == "Release Hook":
logging.debug(f"GitLab - {event} >> {gateway} ")
gl_release_event(gateway, request.json)
else:
logging.info("UNKNOWN GITLAB EVENT")
logging.debug(f"GitLab - {event} >> {gateway} ")
logging.debug(request.json)
return "", 200
def gl_push_event(gateway, data):
logging.debug(f">> {gateway}")
# logging.debug(data)
project = data["project"]["path_with_namespace"]
username = data["user_username"]
2022-11-25 22:58:09 +00:00
branch = data['ref'][len('refs/heads/'):]
2022-06-25 00:16:00 +00:00
count = data["total_commits_count"]
homepage = data["repository"]["homepage"]
s = "s" if count > 1 else ""
body = f"[{project}] {username} pushed {count} commit{s} to {branch}:\n"
for commit in data["commits"]:
cid = commit["id"][:8]
title = commit["title"]
url = commit["url"]
body += f"- [{cid}]({url}) {title}\n"
logging.debug(body)
mb_url = config["gitlab_gateway"]
payload = { 'gateway': gateway, 'username': "gitlab", 'text': body.rstrip() }
r = requests.post(mb_url, json=payload)
def gl_issue_event(gateway, data):
logging.debug(f">> {gateway}")
# logging.debug(data)
project = data["project"]["path_with_namespace"]
username = data["user"]["username"]
oid = data["object_attributes"]["iid"]
title = data["object_attributes"]["title"]
description = data['object_attributes']['description']
if "action" in data["object_attributes"]:
action = data["object_attributes"]["action"]
else:
action = "?"
body = f"[{project}] {username} {action} issue #{oid}: {title}\n"
if action in ["open", "reopen"]:
body += f"{description}"
2022-08-20 14:23:16 +00:00
elif action == "update":
return
2022-06-25 00:16:00 +00:00
logging.debug(body)
mb_url = config["gitlab_gateway"]
payload = { 'gateway': gateway, 'username': "gitlab", 'text': body }
r = requests.post(mb_url, json=payload)
def gl_mr_event(gateway, data):
logging.debug(f">> {gateway}")
# logging.debug(data)
project = data["project"]["path_with_namespace"]
username = data["user"]["username"]
oid = data["object_attributes"]["iid"]
title = data["object_attributes"]["title"]
description = data['object_attributes']['description']
if "action" in data["object_attributes"]:
action = data["object_attributes"]["action"]
else:
action = "?"
body = f"[{project}] {username} {action} merge request !{oid}: {title}\n"
2022-08-21 16:15:33 +00:00
if action in ["open", "reopen"]:
body += f"{description}"
elif action == "update":
return
2022-06-25 00:16:00 +00:00
logging.debug(body)
mb_url = config["gitlab_gateway"]
payload = { 'gateway': gateway, 'username': "gitlab", 'text': body }
r = requests.post(mb_url, json=payload)
def gl_release_event(gateway, data):
logging.debug(f">> {gateway}")
# logging.debug(data)
project = data["project"]["path_with_namespace"]
name = data["name"]
url = data["url"]
if data["action"] != "create":
return
body = f"[{project}] release {name}\n"
body += f"{url}"
logging.debug(body)
mb_url = config["gitlab_gateway"]
payload = { 'gateway': gateway, 'username': "gitlab", 'text': body }
r = requests.post(mb_url, json=payload)
def gl_comment_event(gateway, data):
logging.debug(f">> {gateway}")
logging.debug(data)
project = data["project"]["path_with_namespace"]
username = data["user"]["username"]
oid = data["object_attributes"]["id"]
note = data["object_attributes"]["note"]
ntype = data["object_attributes"]["noteable_type"]
if ntype == "Issue":
iid = data["issue"]["iid"]
title = data["issue"]["title"]
item = f"issue #{iid}: {title}"
elif ntype == "MergeRequest":
mid = data["merge_request"]["id"]
title = data["merge_request"]["title"]
item = f"merge request !{mid}: {title}"
elif ntype == "Commit":
cid = data["commit"]["id"][:8]
item = f"commit {cid}"
elif ntype == "Snippet":
sid = data["snippet"]["sid"]
title = data["snippet"]["title"]
item = f"snippet {sid}: {title}"
else:
item = "?"
body = f"[{project}] {username} commented on {item}\n"
body += f"> {note}"
logging.debug(body)
mb_url = config["gitlab_gateway"]
payload = { 'gateway': gateway, 'username': "gitlab", 'text': body }
r = requests.post(mb_url, json=payload)
@app.route('/srht/<user>/<repo>/<gateway>', methods=['POST'])
def srht_event(user, repo, gateway):
logging.debug(request.url)
logging.debug(request.headers)
payload = request.data
signature = request.headers["X-Payload-Signature"]
signature = base64.b64decode(signature)
nonce = request.headers["X-Payload-Nonce"].encode()
try:
srht_public_key.verify(signature, payload + nonce)
event = request.headers["X-Webhook-Event"]
if event == "repo:post-update":
logging.debug(f"SRHT - {event} >> {gateway}")
# __post_update(user, repo, gateway, request.json)
elif event == "ticket:create":
logging.debug(f"SRHT - {event} >> {gateway}")
# __ticket_create(user, repo, gateway, request.json)
elif event == "event:create":
logging.debug(f"SRHT - {event} >> {gateway}")
# __event_create(user, repo, gateway, request.json)
except Exception:
logging.exception('SRHT')
return '', 200
2022-11-25 22:58:09 +00:00
@app.route('/tars/', methods=['POST'])
def feedbot_cmd():
token = request.headers['Authorization']
user_id = request.form['user_id']
reply = {"username": "tars"}
cmd_text = request.form['text']
cmd_help = '''
The following commands are available:
xpost-on: turn on cross posts from mastodon to pnut
xpost-off: turn off cross posts from mastodon to pnut
'''
if token != "Token " + config['mm_tars_token']:
logging.debug("INVALID TOKEN")
abort(401)
if user_id != config['mm_user_id']:
logging.debug("UNAUTHORIZED USER")
abort(403)
if cmd_text == "xpost-on":
logging.debug("enable crossposts")
rs.rpush('TARS', "feedbot_enable")
reply['text'] = "crossposts will be enabled"
elif cmd_text == "xpost-off":
logging.debug("disable crossposts")
rs.rpush('TARS', "feedbot_disable")
reply['text'] = "crossposts will be disabled"
else:
logging.debug("SHOW HELP?")
reply['text'] = cmd_help
return reply, 200