Don't handle json payload key errors inside webhooks.

Fixes first part of #6213.
This commit is contained in:
Robert Hönig
2017-08-24 17:31:04 +02:00
committed by Tim Abbott
parent ecb428100f
commit 18a080cd6c
23 changed files with 273 additions and 363 deletions

View File

@@ -82,12 +82,8 @@ def api_helloworld_webhook(request, user_profile,
body = 'Hello! I am happy to be here! :smile:' body = 'Hello! I am happy to be here! :smile:'
# try to add the Wikipedia article of the day # try to add the Wikipedia article of the day
# return appropriate error if not successful
try:
body_template = '\nThe Wikipedia featured article for today is **[{featured_title}]({featured_url})**' body_template = '\nThe Wikipedia featured article for today is **[{featured_title}]({featured_url})**'
body += body_template.format(**payload) body += body_template.format(**payload)
except KeyError as e:
return json_error(_("Missing key {} in JSON").format(str(e)))
# send the message # send the message
check_send_message(user_profile, request.client, 'stream', check_send_message(user_profile, request.client, 'stream',
@@ -95,7 +91,6 @@ def api_helloworld_webhook(request, user_profile,
# return json result # return json result
return json_success() return json_success()
``` ```
The above code imports the required functions and defines the main webhook The above code imports the required functions and defines the main webhook
@@ -137,10 +132,11 @@ functions.
In the body of the function we define the body of the message as `Hello! I am In the body of the function we define the body of the message as `Hello! I am
happy to be here! :smile:`. The `:smile:` indicates an emoji. Then we append a happy to be here! :smile:`. The `:smile:` indicates an emoji. Then we append a
link to the Wikipedia article of the day as provided by the json payload. If link to the Wikipedia article of the day as provided by the json payload.
the json payload does not include data for `featured_title` and `featured_url`
we catch a `KeyError` and use `json_error` to return the appropriate * Sometimes, it might occur that a json payload does not contain all required keys your
information: a 400 http status code with relevant details. integration checks for. In such a case, any `KeyError` thrown is handled by the server
backend and will create an appropriate response.
Then we send a public (stream) message with `check_send_message` which will Then we send a public (stream) message with `check_send_message` which will
validate the message and then send it. validate the message and then send it.

View File

@@ -17,12 +17,8 @@ def api_airbrake_webhook(request, user_profile,
payload=REQ(argument_type='body'), payload=REQ(argument_type='body'),
stream=REQ(default='airbrake')): stream=REQ(default='airbrake')):
# type: (HttpRequest, UserProfile, Dict[str, Any], Text) -> HttpResponse # type: (HttpRequest, UserProfile, Dict[str, Any], Text) -> HttpResponse
try:
subject = get_subject(payload) subject = get_subject(payload)
body = get_body(payload) body = get_body(payload)
except KeyError as e:
return json_error(_("Missing key {} in JSON").format(str(e)))
check_send_message(user_profile, request.client, 'stream', [stream], subject, body) check_send_message(user_profile, request.client, 'stream', [stream], subject, body)
return json_success() return json_success()

View File

@@ -17,10 +17,7 @@ from typing import Dict, Any, Text
def api_appfollow_webhook(request, user_profile, stream=REQ(default="appfollow"), def api_appfollow_webhook(request, user_profile, stream=REQ(default="appfollow"),
payload=REQ(argument_type="body")): payload=REQ(argument_type="body")):
# type: (HttpRequest, UserProfile, Text, Dict[str, Any]) -> HttpResponse # type: (HttpRequest, UserProfile, Text, Dict[str, Any]) -> HttpResponse
try:
message = payload["text"] message = payload["text"]
except KeyError:
return json_error(_("Missing 'text' argument in JSON"))
app_name = re.search('\A(.+)', message).group(0) app_name = re.search('\A(.+)', message).group(0)
check_send_message(user_profile, request.client, "stream", [stream], app_name, convert_markdown(message)) check_send_message(user_profile, request.client, "stream", [stream], app_name, convert_markdown(message))

View File

@@ -44,7 +44,6 @@ class UnknownTriggerType(Exception):
def api_bitbucket2_webhook(request, user_profile, payload=REQ(argument_type='body'), def api_bitbucket2_webhook(request, user_profile, payload=REQ(argument_type='body'),
stream=REQ(default='bitbucket'), branches=REQ(default=None)): stream=REQ(default='bitbucket'), branches=REQ(default=None)):
# type: (HttpRequest, UserProfile, Dict[str, Any], str, Optional[Text]) -> HttpResponse # type: (HttpRequest, UserProfile, Dict[str, Any], str, Optional[Text]) -> HttpResponse
try:
type = get_type(request, payload) type = get_type(request, payload)
if type != 'push': if type != 'push':
subject = get_subject_based_on_type(payload, type) subject = get_subject_based_on_type(payload, type)
@@ -59,10 +58,6 @@ def api_bitbucket2_webhook(request, user_profile, payload=REQ(argument_type='bod
bodies_list = get_push_bodies(payload) bodies_list = get_push_bodies(payload)
for body, subject in zip(bodies_list, subjects): for body, subject in zip(bodies_list, subjects):
check_send_message(user_profile, request.client, 'stream', [stream], subject, body) check_send_message(user_profile, request.client, 'stream', [stream], subject, body)
except KeyError as e:
return json_error(_("Missing key {} in JSON").format(str(e)))
return json_success() return json_success()
def get_subject_for_branch_specified_events(payload, branch_name=None): def get_subject_for_branch_specified_events(payload, branch_name=None):

View File

@@ -29,12 +29,9 @@ CODESHIP_STATUS_MAPPER = {
def api_codeship_webhook(request, user_profile, payload=REQ(argument_type='body'), def api_codeship_webhook(request, user_profile, payload=REQ(argument_type='body'),
stream=REQ(default='codeship')): stream=REQ(default='codeship')):
# type: (HttpRequest, UserProfile, Dict[str, Any], str) -> HttpResponse # type: (HttpRequest, UserProfile, Dict[str, Any], str) -> HttpResponse
try:
payload = payload['build'] payload = payload['build']
subject = get_subject_for_http_request(payload) subject = get_subject_for_http_request(payload)
body = get_body_for_http_request(payload) body = get_body_for_http_request(payload)
except KeyError as e:
return json_error(_("Missing key {} in JSON").format(str(e)))
check_send_message(user_profile, request.client, 'stream', [stream], subject, body) check_send_message(user_profile, request.client, 'stream', [stream], subject, body)
return json_success() return json_success()

View File

@@ -22,7 +22,6 @@ VERIFICATION_EVENT = 'verification'
def api_crashlytics_webhook(request, user_profile, payload=REQ(argument_type='body'), def api_crashlytics_webhook(request, user_profile, payload=REQ(argument_type='body'),
stream=REQ(default='crashlytics')): stream=REQ(default='crashlytics')):
# type: (HttpRequest, UserProfile, Dict[str, Any], Text) -> HttpResponse # type: (HttpRequest, UserProfile, Dict[str, Any], Text) -> HttpResponse
try:
event = payload['event'] event = payload['event']
if event == VERIFICATION_EVENT: if event == VERIFICATION_EVENT:
subject = CRASHLYTICS_SETUP_SUBJECT_TEMPLATE subject = CRASHLYTICS_SETUP_SUBJECT_TEMPLATE
@@ -37,8 +36,6 @@ def api_crashlytics_webhook(request, user_profile, payload=REQ(argument_type='bo
impacted_devices_count=issue_body['impacted_devices_count'], impacted_devices_count=issue_body['impacted_devices_count'],
url=issue_body['url'] url=issue_body['url']
) )
except KeyError as e:
return json_error(_("Missing key {} in JSON".format(str(e))))
check_send_message(user_profile, request.client, 'stream', [stream], check_send_message(user_profile, request.client, 'stream', [stream],
subject, body) subject, body)

View File

@@ -24,13 +24,10 @@ def api_delighted_webhook(request, user_profile,
stream=REQ(default='delighted'), stream=REQ(default='delighted'),
topic=REQ(default='Survey Response')): topic=REQ(default='Survey Response')):
# type: (HttpRequest, UserProfile, Dict[str, Dict[str, Any]], text_type, text_type) -> HttpResponse # type: (HttpRequest, UserProfile, Dict[str, Dict[str, Any]], text_type, text_type) -> HttpResponse
try:
person = payload['event_data']['person'] person = payload['event_data']['person']
selected_payload = {'email': person['email']} selected_payload = {'email': person['email']}
selected_payload['score'] = payload['event_data']['score'] selected_payload['score'] = payload['event_data']['score']
selected_payload['comment'] = payload['event_data']['comment'] selected_payload['comment'] = payload['event_data']['comment']
except KeyError as e:
return json_error(_("Missing key {} in JSON").format(str(e)))
BODY_TEMPLATE = body_template(selected_payload['score']) BODY_TEMPLATE = body_template(selected_payload['score'])
body = BODY_TEMPLATE.format(**selected_payload) body = BODY_TEMPLATE.format(**selected_payload)

View File

@@ -133,11 +133,7 @@ def api_freshdesk_webhook(request, user_profile, payload=REQ(argument_type='body
ticket = TicketDict(ticket_data) ticket = TicketDict(ticket_data)
subject = "#%s: %s" % (ticket.id, ticket.subject) subject = "#%s: %s" % (ticket.id, ticket.subject)
try:
event_info = parse_freshdesk_event(ticket.triggered_event) event_info = parse_freshdesk_event(ticket.triggered_event)
except ValueError:
return json_error(_("Malformed event %s") % (ticket.triggered_event,))
if event_info[1] == "created": if event_info[1] == "created":
content = format_freshdesk_ticket_creation_message(ticket) content = format_freshdesk_ticket_creation_message(ticket)

View File

@@ -71,8 +71,6 @@ def api_gogs_webhook(request, user_profile,
repo = payload['repository']['name'] repo = payload['repository']['name']
event = request.META['HTTP_X_GOGS_EVENT'] event = request.META['HTTP_X_GOGS_EVENT']
try:
if event == 'push': if event == 'push':
branch = payload['ref'].replace('refs/heads/', '') branch = payload['ref'].replace('refs/heads/', '')
if branches is not None and branches.find(branch) == -1: if branches is not None and branches.find(branch) == -1:
@@ -98,8 +96,6 @@ def api_gogs_webhook(request, user_profile,
) )
else: else:
return json_error(_('Invalid event "{}" in request headers').format(event)) return json_error(_('Invalid event "{}" in request headers').format(event))
except KeyError as e:
return json_error(_('Missing key {} in JSON').format(str(e)))
check_send_message(user_profile, request.client, 'stream', [stream], topic, body) check_send_message(user_profile, request.client, 'stream', [stream], topic, body)
return json_success() return json_success()

View File

@@ -18,14 +18,10 @@ def api_gosquared_webhook(request, user_profile,
stream=REQ(default='gosquared'), stream=REQ(default='gosquared'),
topic=REQ(default=None)): topic=REQ(default=None)):
# type: (HttpRequest, UserProfile, Dict[str, Dict[str, Any]], Text, Text) -> HttpResponse # type: (HttpRequest, UserProfile, Dict[str, Dict[str, Any]], Text, Text) -> HttpResponse
try:
domain_name = payload['siteDetails']['domain'] domain_name = payload['siteDetails']['domain']
user_num = payload['concurrents'] user_num = payload['concurrents']
user_acc = payload['siteDetails']['acct'] user_acc = payload['siteDetails']['acct']
acc_url = 'https://www.gosquared.com/now/' + user_acc acc_url = 'https://www.gosquared.com/now/' + user_acc
except KeyError as e:
return json_error(_("Missing key {} in JSON").format(str(e)))
body = BODY_TEMPLATE.format(website_name=domain_name, website_url=acc_url, user_num=user_num) body = BODY_TEMPLATE.format(website_name=domain_name, website_url=acc_url, user_num=user_num)
# allows for customisable topics # allows for customisable topics
if topic is None: if topic is None:

View File

@@ -40,7 +40,6 @@ def api_greenhouse_webhook(request, user_profile,
payload=REQ(argument_type='body'), payload=REQ(argument_type='body'),
stream=REQ(default='greenhouse'), topic=REQ(default=None)): stream=REQ(default='greenhouse'), topic=REQ(default=None)):
# type: (HttpRequest, UserProfile, Dict[str, Any], str, str) -> HttpResponse # type: (HttpRequest, UserProfile, Dict[str, Any], str, str) -> HttpResponse
try:
if payload['action'] == 'update_candidate': if payload['action'] == 'update_candidate':
candidate = payload['payload']['candidate'] candidate = payload['payload']['candidate']
else: else:
@@ -57,8 +56,5 @@ def api_greenhouse_webhook(request, user_profile,
if topic is None: if topic is None:
topic = "{} - {}".format(action, str(candidate['id'])) topic = "{} - {}".format(action, str(candidate['id']))
except KeyError as e:
return json_error(_("Missing key {} in JSON").format(str(e)))
check_send_message(user_profile, request.client, 'stream', [stream], topic, body) check_send_message(user_profile, request.client, 'stream', [stream], topic, body)
return json_success() return json_success()

View File

@@ -48,12 +48,7 @@ def api_hellosign_webhook(request, user_profile,
stream=REQ(default='hellosign'), stream=REQ(default='hellosign'),
topic=REQ(default=None)): topic=REQ(default=None)):
# type: (HttpRequest, UserProfile, Dict[str, Dict[str, Any]], text_type, text_type) -> HttpResponse # type: (HttpRequest, UserProfile, Dict[str, Dict[str, Any]], text_type, text_type) -> HttpResponse
try: model_payload = ready_payload(payload['signature_request']['signatures'], payload)
model_payload = ready_payload(payload['signature_request']['signatures'],
payload)
except KeyError as e:
return json_error(_("Missing key {} in JSON").format(str(e)))
body = format_body(payload['signature_request']['signatures'], model_payload) body = format_body(payload['signature_request']['signatures'], model_payload)
topic = topic or model_payload['contract_title'] topic = topic or model_payload['contract_title']
check_send_message(user_profile, request.client, 'stream', [stream], check_send_message(user_profile, request.client, 'stream', [stream],

View File

@@ -21,12 +21,8 @@ def api_helloworld_webhook(request, user_profile,
body = 'Hello! I am happy to be here! :smile:' body = 'Hello! I am happy to be here! :smile:'
# try to add the Wikipedia article of the day # try to add the Wikipedia article of the day
# return appropriate error if not successful
try:
body_template = '\nThe Wikipedia featured article for today is **[{featured_title}]({featured_url})**' body_template = '\nThe Wikipedia featured article for today is **[{featured_title}]({featured_url})**'
body += body_template.format(**payload) body += body_template.format(**payload)
except KeyError as e:
return json_error(_("Missing key {} in JSON").format(str(e)))
# send the message # send the message
check_send_message(user_profile, request.client, 'stream', [stream], topic, body) check_send_message(user_profile, request.client, 'stream', [stream], topic, body)

View File

@@ -18,10 +18,7 @@ def api_homeassistant_webhook(request, user_profile,
# type: (HttpRequest, UserProfile, Dict[str, str], Text) -> HttpResponse # type: (HttpRequest, UserProfile, Dict[str, str], Text) -> HttpResponse
# construct the body of the message # construct the body of the message
try:
body = payload["message"] body = payload["message"]
except KeyError as e:
return json_error(_("Missing key {} in JSON").format(str(e)))
# set the topic to the topic parameter, if given # set the topic to the topic parameter, if given
if "topic" in payload: if "topic" in payload:

View File

@@ -17,14 +17,9 @@ def api_mention_webhook(request, user_profile,
stream=REQ(default='mention'), stream=REQ(default='mention'),
topic=REQ(default='news')): topic=REQ(default='news')):
# type: (HttpRequest, UserProfile, Dict[str, Iterable[Dict[str, Any]]], Text, Optional[Text]) -> HttpResponse # type: (HttpRequest, UserProfile, Dict[str, Iterable[Dict[str, Any]]], Text, Optional[Text]) -> HttpResponse
try:
title = payload["title"] title = payload["title"]
source_url = payload["url"] source_url = payload["url"]
description = payload["description"] description = payload["description"]
except KeyError as e:
return json_error(_("Missing key {} in JSON").format(str(e)))
# construct the body of the message # construct the body of the message
body = '**[%s](%s)**:\n%s' % (title, source_url, description) body = '**[%s](%s)**:\n%s' % (title, source_url, description)

View File

@@ -41,14 +41,11 @@ def api_opsgenie_webhook(request, user_profile,
if 'message' in payload['alert']: if 'message' in payload['alert']:
info['additional_info'] += "Message: *{}*\n".format(payload['alert']['message']) info['additional_info'] += "Message: *{}*\n".format(payload['alert']['message'])
body = '' body = ''
try:
body_template = "**OpsGenie: [Alert for {integration_name}.](https://app.opsgenie.com/alert/V2#/show/{alert_id})**\n" \ body_template = "**OpsGenie: [Alert for {integration_name}.](https://app.opsgenie.com/alert/V2#/show/{alert_id})**\n" \
"Type: *{alert_type}*\n" \ "Type: *{alert_type}*\n" \
"{additional_info}" \ "{additional_info}" \
"{tags}" "{tags}"
body += body_template.format(**info) body += body_template.format(**info)
except KeyError as e:
return json_error(_("Missing key {} in JSON").format(str(e)))
# send the message # send the message
check_send_message(user_profile, request.client, 'stream', [stream], topic, body) check_send_message(user_profile, request.client, 'stream', [stream], topic, body)

View File

@@ -19,7 +19,6 @@ def api_papertrail_webhook(request, user_profile,
# type: (HttpRequest, UserProfile, Dict[str, Any], Text, Text) -> HttpResponse # type: (HttpRequest, UserProfile, Dict[str, Any], Text, Text) -> HttpResponse
# construct the message of the message # construct the message of the message
try:
message_template = '**"{}"** search found **{}** matches - {}\n```' message_template = '**"{}"** search found **{}** matches - {}\n```'
message = [message_template.format(payload["saved_search"]["name"], message = [message_template.format(payload["saved_search"]["name"],
str(len(payload["events"])), str(len(payload["events"])),
@@ -36,8 +35,6 @@ def api_papertrail_webhook(request, user_profile,
else: else:
message.append('```') message.append('```')
post = '\n'.join(message) post = '\n'.join(message)
except KeyError as e:
return json_error(_("Missing key {} in JSON").format(str(e)))
# send the message # send the message
check_send_message(user_profile, request.client, 'stream', [stream], topic, post) check_send_message(user_profile, request.client, 'stream', [stream], topic, post)

View File

@@ -167,14 +167,9 @@ def api_pivotal_webhook(request, user_profile, stream=REQ()):
subject = content = None subject = content = None
try: try:
subject, content = api_pivotal_webhook_v3(request, user_profile, stream) subject, content = api_pivotal_webhook_v3(request, user_profile, stream)
except AttributeError:
return json_error(_("Failed to extract data from Pivotal XML response"))
except Exception: except Exception:
# Attempt to parse v5 JSON payload # Attempt to parse v5 JSON payload
try:
subject, content = api_pivotal_webhook_v5(request, user_profile, stream) subject, content = api_pivotal_webhook_v5(request, user_profile, stream)
except AttributeError:
return json_error(_("Failed to extract data from Pivotal V5 JSON response"))
if subject is None or content is None: if subject is None or content is None:
return json_error(_("Unable to handle Pivotal payload")) return json_error(_("Unable to handle Pivotal payload"))

View File

@@ -23,7 +23,6 @@ def api_semaphore_webhook(request, user_profile,
# semaphore only gives the last commit, even if there were multiple commits # semaphore only gives the last commit, even if there were multiple commits
# since the last build # since the last build
try:
branch_name = payload["branch_name"] branch_name = payload["branch_name"]
project_name = payload["project_name"] project_name = payload["project_name"]
result = payload["result"] result = payload["result"]
@@ -32,26 +31,18 @@ def api_semaphore_webhook(request, user_profile,
commit_url = payload["commit"]["url"] commit_url = payload["commit"]["url"]
author_email = payload["commit"]["author_email"] author_email = payload["commit"]["author_email"]
message = payload["commit"]["message"] message = payload["commit"]["message"]
except KeyError as e:
return json_error(_("Missing key %s in JSON") % (str(e),))
if event == "build": if event == "build":
try:
build_url = payload["build_url"] build_url = payload["build_url"]
build_number = payload["build_number"] build_number = payload["build_number"]
except KeyError as e:
return json_error(_("Missing key %s in JSON") % (str(e),))
content = u"[build %s](%s): %s\n" % (build_number, build_url, result) content = u"[build %s](%s): %s\n" % (build_number, build_url, result)
elif event == "deploy": elif event == "deploy":
try:
build_url = payload["build_html_url"] build_url = payload["build_html_url"]
build_number = payload["build_number"] build_number = payload["build_number"]
deploy_url = payload["html_url"] deploy_url = payload["html_url"]
deploy_number = payload["number"] deploy_number = payload["number"]
server_name = payload["server_name"] server_name = payload["server_name"]
except KeyError as e:
return json_error(_("Missing key %s in JSON") % (str(e),))
content = u"[deploy %s](%s) of [build %s](%s) on server %s: %s\n" % \ content = u"[deploy %s](%s) of [build %s](%s) on server %s: %s\n" % \
(deploy_number, deploy_url, build_number, build_url, server_name, result) (deploy_number, deploy_url, build_number, build_url, server_name, result)

View File

@@ -22,7 +22,6 @@ def api_solano_webhook(request, user_profile,
event = payload.get('event') event = payload.get('event')
if event == 'test': if event == 'test':
return handle_test_event(user_profile, request.client, stream, topic) return handle_test_event(user_profile, request.client, stream, topic)
try:
try: try:
author = payload['committers'][0] author = payload['committers'][0]
except KeyError: except KeyError:
@@ -31,8 +30,6 @@ def api_solano_webhook(request, user_profile,
build_log = payload['url'] build_log = payload['url']
repository = payload['repository']['url'] repository = payload['repository']['url']
commit_id = payload['commit_id'] commit_id = payload['commit_id']
except KeyError as e:
return json_error(_('Missing key {} in JSON').format(str(e)))
good_status = ['passed'] good_status = ['passed']
bad_status = ['failed', 'error'] bad_status = ['failed', 'error']

View File

@@ -20,7 +20,6 @@ def api_stripe_webhook(request, user_profile,
# type: (HttpRequest, UserProfile, Dict[str, Any], Text, Optional[Text]) -> HttpResponse # type: (HttpRequest, UserProfile, Dict[str, Any], Text, Optional[Text]) -> HttpResponse
body = None body = None
event_type = payload["type"] event_type = payload["type"]
try:
data_object = payload["data"]["object"] data_object = payload["data"]["object"]
if event_type.startswith('charge'): if event_type.startswith('charge'):
@@ -157,8 +156,6 @@ def api_stripe_webhook(request, user_profile,
if topic is None: if topic is None:
topic = "Transfer {}".format(object_id) topic = "Transfer {}".format(object_id)
except KeyError as e:
return json_error(_("Missing key {} in JSON".format(str(e))))
if body is None: if body is None:
return json_error(_("We don't support {} event".format(event_type))) return json_error(_("We don't support {} event".format(event_type)))

View File

@@ -252,10 +252,7 @@ def parse_message(message):
def generate_content(data): def generate_content(data):
# type: (Mapping[str, Any]) -> str # type: (Mapping[str, Any]) -> str
""" Gets the template string and formats it with parsed data. """ """ Gets the template string and formats it with parsed data. """
try:
return templates[data['type']][data['event']] % data['values'] return templates[data['type']][data['event']] % data['values']
except KeyError:
return json_error(_("Unknown message"))
def get_owner_name(message): def get_owner_name(message):
# type: (Mapping[str, Any]) -> str # type: (Mapping[str, Any]) -> str

View File

@@ -16,12 +16,9 @@ SUBJECT_TEMPLATE = "{service_url}"
def send_message_for_event(event, user_profile, client, stream): def send_message_for_event(event, user_profile, client, stream):
# type: (Dict[str, Any], UserProfile, Client, str) -> None # type: (Dict[str, Any], UserProfile, Client, str) -> None
try:
event_type = get_event_type(event) event_type = get_event_type(event)
subject = SUBJECT_TEMPLATE.format(service_url=event['check']['url']) subject = SUBJECT_TEMPLATE.format(service_url=event['check']['url'])
body = EVENT_TYPE_BODY_MAPPER[event_type](event) body = EVENT_TYPE_BODY_MAPPER[event_type](event)
except KeyError as e:
return json_error(_("Missing key {} in JSON").format(str(e)))
check_send_message(user_profile, client, 'stream', [stream], subject, body) check_send_message(user_profile, client, 'stream', [stream], subject, body)
def get_body_for_up_event(event): def get_body_for_up_event(event):