buildbot-transifex/buildbot_transifex/webhook.py

165 lines
5.8 KiB
Python
Raw Normal View History

2023-01-06 15:08:43 +00:00
"""Transifex webhook handler """
2022-12-28 08:04:44 +00:00
import base64
import hashlib
2023-01-09 16:26:28 +00:00
import hmac
import json
import os
import requests
import time
import logging
from subprocess import call
from base64 import b64encode
from buildbot.process.properties import Properties
from buildbot.util import bytes2unicode, unicode2bytes
from buildbot.www.hooks.base import BaseHookHandler
2023-01-09 16:26:28 +00:00
from dateutil.parser import parse as dateparse
from twisted.internet import defer
from twisted.python import log
2022-12-28 08:04:44 +00:00
_HEADER_USER_AGENT = 'User-Agent'
_HEADER_SIGNATURE = 'X-TX-Signature'
2023-01-06 15:08:43 +00:00
_HEADER_URL_PATH = 'X-TX-Url'
2023-01-09 16:26:28 +00:00
_HTTP_DATE = 'date'
2022-12-28 08:04:44 +00:00
_EVENT_KEY = 'event'
2023-01-09 16:26:28 +00:00
2022-12-28 08:04:44 +00:00
class TransifexHandler(BaseHookHandler):
2023-01-09 16:26:28 +00:00
def __init__(self, master, secret, options, transifex_to_github_map):
2023-01-06 15:08:43 +00:00
if not options:
options = {}
self.secret = secret
self.master = master
2023-01-06 15:08:43 +00:00
self.options = options
2023-01-09 16:26:28 +00:00
self.transifex_to_github_map = transifex_to_github_map
def returnMessage(self, status = False, message = "Unimplemented"):
output = json.dumps({"status": "OK" if status else "FAIL", "message": message})
2023-01-06 15:08:43 +00:00
return [output, [('Content-type', 'application/json')]]
2023-01-09 16:26:28 +00:00
def _verifyTransifexSignature(
2023-01-06 15:08:43 +00:00
self, request, content, signature, header_signature
):
http_verb = 'POST'
2023-01-06 15:08:43 +00:00
http_url_path = request.getHeader(_HEADER_URL_PATH)
2023-01-09 16:26:28 +00:00
http_gmt_date = request.getHeader(_HTTP_DATE)
content_md5 = hashlib.md5(content).hexdigest()
msg = b'\n'.join([
http_verb, http_url_path, http_gmt_date, content_md5
])
tx_signature = base64.b64encode(
hmac.new(
2023-01-06 15:08:43 +00:00
key=self.rendered_secret,
msg=msg,
digestmod=hashlib.sha256
).digest()
)
2023-01-06 15:08:43 +00:00
if tx_signature != header_signature:
return False
2023-01-06 15:08:43 +00:00
if signature != request.getHeader(_HEADER_SIGNATURE):
return False
2023-01-09 16:26:28 +00:00
return True
2023-01-09 16:26:28 +00:00
def process_translation_completed(self, payload, transifex_to_github_map, event_type, codebase):
changes = []
2023-01-09 16:26:28 +00:00
transifex_response = self._transform_variables(payload, transifex_to_github_map)
# if 'pybitmessage-test' in transifex_response['project'] and 'messagespot' in transifex_response['resource']:
# if 'translation_completed' in transifex_response['event']:
language = transifex_response.get['language']
2023-01-06 15:08:43 +00:00
change = {
2023-01-09 16:26:28 +00:00
'author': "buildbot-transifex",
'resource': transifex_to_github_map["resource"],
'branch': transifex_to_github_map["branch"],
'project': transifex_to_github_map["project"],
2023-01-06 15:08:43 +00:00
'event': event_type,
2023-01-09 16:26:28 +00:00
'revision': revision,
2023-01-06 15:08:43 +00:00
'properties': {
2023-01-09 16:26:28 +00:00
"transifex_language": payload.get("language", "None"),
"transifex_event": payload.get("event", "None"),
"transifex_project": payload.get("project", "None"),
"transifex_resource": payload.get("resource", "None")
2023-01-06 15:08:43 +00:00
}
}
if codebase is not None:
change['codebase'] = codebase
changes.insert(0, change)
return changes
2023-01-09 16:26:28 +00:00
def _transform_variables(self, payload, transifex_to_github_map):
2023-01-06 15:08:43 +00:00
project = payload.get('project', 'None')
transform_values = {
2023-01-09 16:26:28 +00:00
'resource': transifex_to_github_map["resource"],
'branch': transifex_to_github_map["branch"],
'project': transifex_to_github_map["project"],
2022-12-28 08:04:44 +00:00
}
2023-01-06 15:08:43 +00:00
return transform_values
2022-12-28 08:04:44 +00:00
@defer.inlineCallbacks
def getChanges(self, request):
2023-01-09 16:26:28 +00:00
change = {}
self.secret = None
if isinstance(self.options, dict):
self.secret = self.options.get('secret')
try:
content = request.content.read()
content_text = bytes2unicode(content)
payload = json.loads(content_text)
except Exception as exception:
raise ValueError('Error loading JSON: ' + str(exception))
if self.secret is not None:
p = Properties()
p.master = self.master
2023-01-06 15:08:43 +00:00
option = self.options
self.rendered_secret = yield p.render(self.secret)
signature = hmac.new(
2023-01-06 15:08:43 +00:00
unicode2bytes(self.rendered_secret),
unicode2bytes(content_text.strip()),
digestmod=hashlib.sha256)
header_signature = bytes2unicode(
request.getHeader(_HEADER_SIGNATURE))
2023-01-09 16:26:28 +00:00
if not self._verifyTransifexSignature(request, content, self.rendered_secret, signature, header_signature):
logging.warning("Verify Transifex Signature fail.")
else:
logging.warning("Verify Transifex Signature ok")
2023-01-06 15:08:43 +00:00
event_type = payload.get("event", "None")
2023-01-09 16:26:28 +00:00
change["properties"] = {
"transifex_language": payload.get("language", "None"),
"transifex_event": payload.get("event", "None"),
"transifex_project": payload.get("project", "None"),
"transifex_resource": payload.get("resource", "None")
2023-01-06 15:08:43 +00:00
}
2023-01-09 16:26:28 +00:00
change["changes"] = {
2023-01-06 15:08:43 +00:00
"author": "buildbot-transifex",
2023-01-09 16:26:28 +00:00
"repository": transifex_to_github_map['repository'],
2023-01-06 15:08:43 +00:00
}
2022-12-28 08:04:44 +00:00
log.msg("Received event '{}' from transifex".format(event_type))
2022-12-28 08:04:44 +00:00
codebase = ""
2018-09-04 13:04:29 +00:00
changes = []
handler_function = getattr(self, 'process_{}'.format(event_type), None)
if not handler_function:
2022-12-28 08:04:44 +00:00
log.msg("Ignoring transifex event '{}'".format(event_type))
else:
changes = handler_function(payload, event_type, codebase)
2018-09-04 13:04:29 +00:00
2022-12-28 08:04:44 +00:00
return (changes, 'transifex')
2023-01-09 16:26:28 +00:00
transifex = TransifexHandler(transifex_to_github_map)