Files
django-anymail/tests/utils_postal.py
Tilmann Becker e90c10b546 Add Postal support
Thanks to @tiltec for researching, implementing, testing and documenting it.
2021-06-07 17:11:35 -07:00

59 lines
1.8 KiB
Python

from base64 import b64encode
from django.test import override_settings
from tests.utils import ClientWithCsrfChecks
HAS_CRYPTOGRAPHY = True
try:
from cryptography.hazmat.primitives.asymmetric import rsa
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import padding
except ImportError:
HAS_CRYPTOGRAPHY = False
def make_key():
"""Generate RSA public key with short key size, for testing only"""
private_key = rsa.generate_private_key(
public_exponent=65537,
key_size=512,
)
return private_key
def derive_public_webhook_key(private_key):
"""Derive public """
public_key = private_key.public_key()
public_bytes = public_key.public_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PublicFormat.SubjectPublicKeyInfo
)
public_bytes = b'\n'.join(public_bytes.splitlines()[1:-1])
return public_bytes.decode('utf-8')
def sign(private_key, message):
"""Sign message with private key"""
signature = private_key.sign(message, padding.PKCS1v15(), hashes.SHA1())
return signature
class _ClientWithPostalSignature(ClientWithCsrfChecks):
private_key = None
def set_private_key(self, private_key):
self.private_key = private_key
def post(self, *args, **kwargs):
signature = b64encode(sign(self.private_key, kwargs['data'].encode('utf-8')))
kwargs.setdefault('HTTP_X_POSTAL_SIGNATURE', signature)
webhook_key = derive_public_webhook_key(self.private_key)
with override_settings(ANYMAIL={'POSTAL_WEBHOOK_KEY': webhook_key}):
return super().post(*args, **kwargs)
ClientWithPostalSignature = _ClientWithPostalSignature if HAS_CRYPTOGRAPHY else None