File: utils_postal.py

package info (click to toggle)
django-anymail 13.0-1
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 2,480 kB
  • sloc: python: 27,832; makefile: 132; javascript: 33; sh: 9
file content (56 lines) | stat: -rw-r--r-- 1,733 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
from base64 import b64encode

from django.test import override_settings

from tests.utils import ClientWithCsrfChecks

HAS_CRYPTOGRAPHY = True
try:
    from cryptography.hazmat.primitives import hashes, serialization
    from cryptography.hazmat.primitives.asymmetric import padding, rsa
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=1024,
    )
    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