1- import os
2- import email
31import pytest
42import emails
53from emails import Message
64from io import StringIO
75
86from emails .exc import DKIMException
9- from emails .utils import load_email_charsets
107import dkim
8+ from cryptography .hazmat .primitives import serialization
9+ from cryptography .hazmat .primitives .asymmetric import rsa
1110from .helpers import common_email_data
1211
1312
13+ @pytest .fixture (scope = "session" )
14+ def dkim_keys ():
15+ """Fresh 2048-bit RSA keypair for DKIM tests.
1416
15- PRIV_KEY = b"""-----BEGIN RSA PRIVATE KEY-----
16- MIICXAIBAAKBgQDKHKzbg7LwpSJVfy9h8YQciVuIiexJ6OKJcCc6akJuLx+qPJGr
17- t0chdV92slT9Lm1DUAjQEd8r9kVKa8FrWrnThMWx5HoXkGOIW2NqC0vrTZUgvhWy
18- mlnwiysIylCirStZvA2uszYiFQK8slYD3H25UFTIOqLgB6AvV6URo26iJQIDAQAB
19- AoGAOHt5B0Ov3zaW+MO5byq6m+r7DJZW1XTi0jvoipelhvteYwnYP9/RXhVaH2bI
20- /5RY7qXQQK2t67BAPwMMI79QDL+jWsgwE0hly/qloOgEuX1+D/yGBShlYNQXvjAY
21- UgkNYtp5JBVr8byz7upzvIyDsWJGoUrBindYnEiAVgwzZuECQQDKsKRwQhTCOZjW
22- tkrockxDKMlXyKRLpOdqmwH0hwUdcWklxlmE+IJz4NVlz5qCVJz/oT+TgBNex8I5
23- spxWAmdNAkEA/0UdnlXYueGVDIe5SUQGlXb8U8fTYtA/NsduFwq8QEWMrVBXK+uH
24- 4upq70kFlyfP5mpTOZwUgY2jH/qrXD8qOQJAdx1L5bTP4jxa94N1jhjtfGJRwMbm
25- 1pV4cgvaIEvg06a8djiUjzJD57lvbz+Lu5/iC9BFPnd76q1WFPZELb+H2QJBAK8y
26- DWDlBEiW5QfjgqwhDu+36PfLNm4kBK6g8xLHYGowEZvFfv56uRloz5mIoVibj1lR
27- ceshDwXXYrSJAuDdzSkCQDkx2TeKLUqKSxJNUYSrakQIo/41AOFvFBTbJuH3RZoy
28- W/1DFMld7rC2gVHYW3m/LNd1qbi5QR9/buGxE7Y8ylI=
29- -----END RSA PRIVATE KEY-----"""
30-
31- PUB_KEY = b"""MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDKHKzbg7LwpSJVfy9h8YQciVuI
32- iexJ6OKJcCc6akJuLx+qPJGrt0chdV92slT9Lm1DUAjQEd8r9kVKa8FrWrnThMWx
33- 5HoXkGOIW2NqC0vrTZUgvhWymlnwiysIylCirStZvA2uszYiFQK8slYD3H25UFTI
34- OqLgB6AvV6URo26iJQIDAQAB"""
35-
36-
37- def _generate_key (length = 1024 ):
38- # From: http://stackoverflow.com/questions/3504955/using-rsa-in-python
39- try :
40- from Crypto .PublicKey import RSA
41- key = RSA .generate (length )
42- return key .exportKey (), key .publickey ().exportKey ()
43- except ImportError :
44- return PRIV_KEY , PUB_KEY
45-
46-
47- def _check_dkim (message , pub_key = PUB_KEY ):
17+ Returns (private_key_pem, public_key_pem) as bytes.
18+ Generated once per test session — RSA keygen is slow (~100 ms).
19+ """
20+ key = rsa .generate_private_key (public_exponent = 65537 , key_size = 2048 )
21+ priv_pem = key .private_bytes (
22+ encoding = serialization .Encoding .PEM ,
23+ format = serialization .PrivateFormat .TraditionalOpenSSL ,
24+ encryption_algorithm = serialization .NoEncryption (),
25+ )
26+ pub_pem = key .public_key ().public_bytes (
27+ encoding = serialization .Encoding .PEM ,
28+ format = serialization .PublicFormat .SubjectPublicKeyInfo ,
29+ )
30+ return priv_pem , pub_pem
31+
32+
33+ def _check_dkim (message , pub_key ):
4834 def _plain_public_key (s ):
4935 return b"" .join ([l for l in s .split (b'\n ' ) if not l .startswith (b'---' )])
5036 message = message .as_string ()
5137 o = dkim .DKIM (message = message .encode ())
5238 return o .verify (dnsfunc = lambda name , ** kw : b"" .join ([b"v=DKIM1; p=" , _plain_public_key (pub_key )]))
5339
5440
55- def test_dkim ():
56-
57- priv_key , pub_key = _generate_key (length = 1024 )
41+ def test_dkim (dkim_keys ):
42+ priv_key , pub_key = dkim_keys
5843
5944 DKIM_PARAMS = [dict (key = StringIO (priv_key .decode ()),
6045 selector = '_dkim' ,
@@ -75,21 +60,13 @@ def test_dkim():
7560 message .dkim (** dkimparams )
7661 # check DKIM header exist
7762 assert message .as_message ()['DKIM-Signature' ]
78- #print(__name__, "type message.as_string()==", type(message.as_string()))
79- #print(message.as_string())
80- #print(type(message.as_string()))
81- #print(email.__file__)
82- #print(email.charset.CHARSETS)
83- #print('adding utf-8 charset...')
84- #email.charset.add_charset('utf-8', email.charset.BASE64, email.charset.BASE64)
85- #print(email.charset.CHARSETS)
8663 assert 'DKIM-Signature: ' in message .as_string ()
8764 assert _check_dkim (message , pub_key )
88- #assert 0
8965
9066
9167
92- def test_dkim_error ():
68+ def test_dkim_error (dkim_keys ):
69+ priv_key , _ = dkim_keys
9370
9471 m = emails .html (** common_email_data ())
9572
@@ -110,7 +87,7 @@ def test_dkim_error():
11087
11188 # Error on invalid dkim parameters
11289
113- m .dkim (key = PRIV_KEY ,
90+ m .dkim (key = priv_key ,
11491 selector = '_dkim' ,
11592 domain = 'somewhere.net' ,
11693 include_headers = ['To' ])
@@ -120,7 +97,7 @@ def test_dkim_error():
12097 m .as_string ()
12198
12299 # Skip error on ignore_sign_errors=True
123- m .dkim (key = PRIV_KEY ,
100+ m .dkim (key = priv_key ,
124101 selector = '_dkim' ,
125102 domain = 'somewhere.net' ,
126103 ignore_sign_errors = True ,
@@ -130,19 +107,18 @@ def test_dkim_error():
130107 m .as_message ()
131108
132109
133- def test_dkim_as_bytes ():
134-
135- priv_key , pub_key = _generate_key (length = 1024 )
110+ def test_dkim_as_bytes (dkim_keys ):
111+ priv_key , _ = dkim_keys
136112 message = Message (** common_email_data ())
137113 message .dkim (key = priv_key , selector = '_dkim' , domain = 'somewhere.net' )
138114 result = message .as_bytes ()
139115 assert isinstance (result , bytes )
140116 assert b'DKIM-Signature: ' in result
141117
142118
143- def test_dkim_sign_after_error ():
119+ def test_dkim_sign_after_error (dkim_keys ):
144120 """After a sign error with ignore_sign_errors, normal signing still works."""
145- priv_key , pub_key = _generate_key ( length = 1024 )
121+ priv_key , pub_key = dkim_keys
146122
147123 # First: sign with invalid include_headers (missing From), error ignored
148124 m1 = Message (** common_email_data ())
@@ -156,14 +132,14 @@ def test_dkim_sign_after_error():
156132 assert _check_dkim (m2 , pub_key )
157133
158134
159- def test_dkim_sign_twice ():
135+ def test_dkim_sign_twice (dkim_keys ):
160136
161137 # Test #44:
162138 # " if you put the open there and send more than one messages it fails
163139 # (the first works but the next will not if you dont seek(0) the dkim file first)"
164140 # Actually not.
141+ priv_key , pub_key = dkim_keys
165142
166- priv_key , pub_key = _generate_key (length = 1024 )
167143 message = Message (** common_email_data ())
168144 message .dkim (key = StringIO (priv_key .decode ()), selector = '_dkim' , domain = 'somewhere.net' )
169145 for n in range (2 ):
0 commit comments