buildbot-transifex/buildbot_transifex/webhook.py

174 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
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'
HTTP_DATE = 'date'
2022-12-28 08:04:44 +00:00
_EVENT_KEY = 'event'
2023-01-06 15:08:43 +00:00
transifex_request_data = {}
2022-12-28 08:04:44 +00:00
class TransifexHandler(BaseHookHandler):
2023-01-06 15:08:43 +00:00
def __init__(self, master, secret, options, transifex_dict):
if not options:
options = {}
self.secret = secret
self.master = master
2023-01-06 15:08:43 +00:00
self.options = options
self.transifex_dict = transifex_dict
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)
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
def process_translation_completed(self, payload, transifex_dict, event_type, codebase):
changes = []
transifex_response = self._transform_variables(payload, transifex_dict)
2023-01-09 16:26:28 +00:00
# if 'pybitmessage-test' in transifex_response['project'] and 'messagespot' in transifex_response['resource']:
# if 'translation_completed' in transifex_response['event']:
try:
lang = transifex_response['language']
except Exception as exception:
raise KeyError('No such key found: ' + str(exception))
2023-01-06 15:08:43 +00:00
change = {
2023-01-09 16:26:28 +00:00
'author': 'buildbot-transifex',
'resource': transifex_dict['resource'],
2023-01-06 15:08:43 +00:00
'branch': transifex_dict['branch'],
2023-01-09 16:26:28 +00:00
'project': transifex_dict['project'],
2023-01-06 15:08:43 +00:00
'event': event_type,
'properties': {
'branch': branch,
'revision': revision,
'language': lang,
'resource': resource,
'project': project
}
}
if codebase is not None:
change['codebase'] = codebase
changes.insert(0, change)
return changes
def _transform_variables(self, payload, transifex_dict):
2023-01-06 15:08:43 +00:00
project = payload.get('project', 'None')
transform_values = {
project: {
"repository": "https://github.com/Bitmessage/PyBitmessage",
"branch": "v0.6"
}
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):
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
self._verifyTransifexSignature(
2023-01-06 15:08:43 +00:00
request, content, self.rendered_secret,
signature, header_signature
2022-12-28 08:04:44 +00:00
)
2023-01-06 15:08:43 +00:00
event_type = payload.get("event", "None")
language = payload.get("language", 'None')
project = payload.get("project", 'None')
resource = payload.get("resource", 'None')
2023-01-09 16:26:28 +00:00
transifex_request_data['branch'] = transifex_dict['branch']
2023-01-06 15:08:43 +00:00
transifex_request_data['revision'] = ""
2023-01-09 16:26:28 +00:00
transifex_request_data["properties"] = {
"transifex_language": language,
"transifex_resource": resource,
"transifex_project": project
}
2023-01-06 15:08:43 +00:00
transifex_request_data["properties"] = {
"branch": branch,
"revision": revision
}
transifex_request_data["changes"] = {
"author": "buildbot-transifex",
"repository": project,
}
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-02 15:00:09 +00:00
transifex = TransifexHandler(transifex_dict)