mirror of
https://github.com/pacnpal/django-anymail.git
synced 2025-12-20 11:51:05 -05:00
84 lines
3.1 KiB
Python
84 lines
3.1 KiB
Python
from base64 import b64encode
|
|
import hashlib
|
|
import hmac
|
|
import json
|
|
from django.conf import settings
|
|
from django.core.exceptions import ImproperlyConfigured
|
|
from django.views.generic import View
|
|
from django.http import HttpResponse
|
|
from django.utils.decorators import method_decorator
|
|
from django.views.decorators.csrf import csrf_exempt
|
|
|
|
from djrill import signals
|
|
from djrill.compat import b
|
|
|
|
|
|
class DjrillWebhookSecretMixin(object):
|
|
|
|
@method_decorator(csrf_exempt)
|
|
def dispatch(self, request, *args, **kwargs):
|
|
secret = getattr(settings, 'DJRILL_WEBHOOK_SECRET', None)
|
|
secret_name = getattr(settings, 'DJRILL_WEBHOOK_SECRET_NAME', 'secret')
|
|
|
|
if secret is None:
|
|
raise ImproperlyConfigured(
|
|
"You have not set DJRILL_WEBHOOK_SECRET in the settings file.")
|
|
|
|
if request.GET.get(secret_name) != secret:
|
|
return HttpResponse(status=403)
|
|
|
|
return super(DjrillWebhookSecretMixin, self).dispatch(
|
|
request, *args, **kwargs)
|
|
|
|
|
|
class DjrillWebhookSignatureMixin(object):
|
|
|
|
@method_decorator(csrf_exempt)
|
|
def dispatch(self, request, *args, **kwargs):
|
|
|
|
signature_key = getattr(settings, 'DJRILL_WEBHOOK_SIGNATURE_KEY', None)
|
|
|
|
if signature_key and request.method == "POST":
|
|
|
|
# Make webhook url an explicit setting to make sure that this is the exact same string
|
|
# that the user entered in Mandrill
|
|
post_string = getattr(settings, "DJRILL_WEBHOOK_URL", None)
|
|
if post_string is None:
|
|
raise ImproperlyConfigured(
|
|
"You have set DJRILL_WEBHOOK_SIGNATURE_KEY, but haven't set DJRILL_WEBHOOK_URL in the settings file.")
|
|
|
|
signature = request.META.get("HTTP_X_MANDRILL_SIGNATURE", None)
|
|
if not signature:
|
|
return HttpResponse(status=403, content="X-Mandrill-Signature not set")
|
|
|
|
# The querydict is a bit special, see https://docs.djangoproject.com/en/dev/ref/request-response/#querydict-objects
|
|
# Mandrill needs it to be sorted and added to the hash
|
|
post_lists = sorted(request.POST.lists())
|
|
for value_list in post_lists:
|
|
for item in value_list[1]:
|
|
post_string += "%s%s" % (value_list[0], item)
|
|
|
|
hash_string = b64encode(hmac.new(key=b(signature_key), msg=b(post_string), digestmod=hashlib.sha1).digest())
|
|
if signature != hash_string:
|
|
return HttpResponse(status=403, content="Signature doesn't match")
|
|
|
|
return super(DjrillWebhookSignatureMixin, self).dispatch(
|
|
request, *args, **kwargs)
|
|
|
|
|
|
class DjrillWebhookView(DjrillWebhookSecretMixin, DjrillWebhookSignatureMixin, View):
|
|
def head(self, request, *args, **kwargs):
|
|
return HttpResponse()
|
|
|
|
def post(self, request, *args, **kwargs):
|
|
try:
|
|
data = json.loads(request.POST.get('mandrill_events'))
|
|
except TypeError:
|
|
return HttpResponse(status=400)
|
|
|
|
for event in data:
|
|
signals.webhook_event.send(
|
|
sender=None, event_type=event['event'], data=event)
|
|
|
|
return HttpResponse()
|