buildbot-transifex/buildbot_transifex/webhook.py

165 lines
5.8 KiB
Python

"""Transifex webhook handler """
import base64
import hashlib
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
from dateutil.parser import parse as dateparse
from twisted.internet import defer
from twisted.python import log
_HEADER_USER_AGENT = 'User-Agent'
_HEADER_SIGNATURE = 'X-TX-Signature'
_HEADER_URL_PATH = 'X-TX-Url'
_HTTP_DATE = 'date'
_EVENT_KEY = 'event'
class TransifexHandler(BaseHookHandler):
def __init__(self, master, secret, options, transifex_to_github_map):
if not options:
options = {}
self.secret = secret
self.master = master
self.options = options
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})
return [output, [('Content-type', 'application/json')]]
def _verifyTransifexSignature(
self, request, content, signature, header_signature
):
http_verb = 'POST'
http_url_path = request.getHeader(_HEADER_URL_PATH)
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(
key=self.rendered_secret,
msg=msg,
digestmod=hashlib.sha256
).digest()
)
if tx_signature != header_signature:
return False
if signature != request.getHeader(_HEADER_SIGNATURE):
return False
return True
def process_translation_completed(self, payload, transifex_to_github_map, event_type, codebase):
changes = []
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']
change = {
'author': "buildbot-transifex",
'resource': transifex_to_github_map["resource"],
'branch': transifex_to_github_map["branch"],
'project': transifex_to_github_map["project"],
'event': event_type,
'revision': revision,
'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")
}
}
if codebase is not None:
change['codebase'] = codebase
changes.insert(0, change)
return changes
def _transform_variables(self, payload, transifex_to_github_map):
project = payload.get('project', 'None')
transform_values = {
'resource': transifex_to_github_map["resource"],
'branch': transifex_to_github_map["branch"],
'project': transifex_to_github_map["project"],
}
return transform_values
@defer.inlineCallbacks
def getChanges(self, request):
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
option = self.options
self.rendered_secret = yield p.render(self.secret)
signature = hmac.new(
unicode2bytes(self.rendered_secret),
unicode2bytes(content_text.strip()),
digestmod=hashlib.sha256)
header_signature = bytes2unicode(
request.getHeader(_HEADER_SIGNATURE))
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")
event_type = payload.get("event", "None")
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")
}
change["changes"] = {
"author": "buildbot-transifex",
"repository": transifex_to_github_map['repository'],
}
log.msg("Received event '{}' from transifex".format(event_type))
codebase = ""
changes = []
handler_function = getattr(self, 'process_{}'.format(event_type), None)
if not handler_function:
log.msg("Ignoring transifex event '{}'".format(event_type))
else:
changes = handler_function(payload, event_type, codebase)
return (changes, 'transifex')
transifex = TransifexHandler(transifex_to_github_map)