2015-01-27 21:47:17 +01:00
|
|
|
# coding: utf-8
|
|
|
|
from __future__ import unicode_literals
|
|
|
|
import os
|
2015-03-06 13:16:49 +01:00
|
|
|
import pytest
|
2015-01-27 21:47:17 +01:00
|
|
|
import emails
|
2015-03-06 19:41:28 +01:00
|
|
|
from emails import Message
|
2015-02-28 12:27:30 +01:00
|
|
|
from emails.compat import NativeStringIO, to_bytes, to_native
|
2015-03-06 13:16:49 +01:00
|
|
|
from emails.exc import DKIMException
|
2015-03-06 19:41:28 +01:00
|
|
|
import emails.packages.dkim
|
2015-03-06 13:16:49 +01:00
|
|
|
from .helpers import common_email_data
|
2015-01-27 21:47:17 +01:00
|
|
|
|
|
|
|
|
2015-03-06 19:41:28 +01:00
|
|
|
|
|
|
|
PRIV_KEY = b"""-----BEGIN RSA PRIVATE KEY-----
|
|
|
|
MIICXAIBAAKBgQDKHKzbg7LwpSJVfy9h8YQciVuIiexJ6OKJcCc6akJuLx+qPJGr
|
|
|
|
t0chdV92slT9Lm1DUAjQEd8r9kVKa8FrWrnThMWx5HoXkGOIW2NqC0vrTZUgvhWy
|
|
|
|
mlnwiysIylCirStZvA2uszYiFQK8slYD3H25UFTIOqLgB6AvV6URo26iJQIDAQAB
|
|
|
|
AoGAOHt5B0Ov3zaW+MO5byq6m+r7DJZW1XTi0jvoipelhvteYwnYP9/RXhVaH2bI
|
|
|
|
/5RY7qXQQK2t67BAPwMMI79QDL+jWsgwE0hly/qloOgEuX1+D/yGBShlYNQXvjAY
|
|
|
|
UgkNYtp5JBVr8byz7upzvIyDsWJGoUrBindYnEiAVgwzZuECQQDKsKRwQhTCOZjW
|
|
|
|
tkrockxDKMlXyKRLpOdqmwH0hwUdcWklxlmE+IJz4NVlz5qCVJz/oT+TgBNex8I5
|
|
|
|
spxWAmdNAkEA/0UdnlXYueGVDIe5SUQGlXb8U8fTYtA/NsduFwq8QEWMrVBXK+uH
|
|
|
|
4upq70kFlyfP5mpTOZwUgY2jH/qrXD8qOQJAdx1L5bTP4jxa94N1jhjtfGJRwMbm
|
|
|
|
1pV4cgvaIEvg06a8djiUjzJD57lvbz+Lu5/iC9BFPnd76q1WFPZELb+H2QJBAK8y
|
|
|
|
DWDlBEiW5QfjgqwhDu+36PfLNm4kBK6g8xLHYGowEZvFfv56uRloz5mIoVibj1lR
|
|
|
|
ceshDwXXYrSJAuDdzSkCQDkx2TeKLUqKSxJNUYSrakQIo/41AOFvFBTbJuH3RZoy
|
|
|
|
W/1DFMld7rC2gVHYW3m/LNd1qbi5QR9/buGxE7Y8ylI=
|
2015-01-27 21:47:17 +01:00
|
|
|
-----END RSA PRIVATE KEY-----"""
|
|
|
|
|
2015-03-06 19:41:28 +01:00
|
|
|
PUB_KEY = b"""MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDKHKzbg7LwpSJVfy9h8YQciVuI
|
|
|
|
iexJ6OKJcCc6akJuLx+qPJGrt0chdV92slT9Lm1DUAjQEd8r9kVKa8FrWrnThMWx
|
|
|
|
5HoXkGOIW2NqC0vrTZUgvhWymlnwiysIylCirStZvA2uszYiFQK8slYD3H25UFTI
|
|
|
|
OqLgB6AvV6URo26iJQIDAQAB"""
|
2015-01-27 21:47:17 +01:00
|
|
|
|
|
|
|
|
2015-03-06 19:41:28 +01:00
|
|
|
def _generate_key(length=1024):
|
|
|
|
# From: http://stackoverflow.com/questions/3504955/using-rsa-in-python
|
2015-01-27 21:47:17 +01:00
|
|
|
try:
|
|
|
|
from Crypto.PublicKey import RSA
|
2015-03-06 19:41:28 +01:00
|
|
|
key = RSA.generate(length)
|
|
|
|
return to_bytes(key.exportKey()), to_bytes(key.publickey().exportKey())
|
2015-01-27 21:47:17 +01:00
|
|
|
except ImportError:
|
2015-03-06 19:41:28 +01:00
|
|
|
return PRIV_KEY, PUB_KEY
|
|
|
|
|
2015-01-27 21:47:17 +01:00
|
|
|
|
2015-03-06 19:41:28 +01:00
|
|
|
def _check_dkim(message, pub_key=PUB_KEY):
|
|
|
|
def _plain_public_key(s):
|
|
|
|
return b"".join([l for l in s.split(b'\n') if not l.startswith(b'---')])
|
|
|
|
o = emails.packages.dkim.DKIM(message=message.as_string())
|
|
|
|
return o.verify(dnsfunc=lambda name: b"".join([b"v=DKIM1; p=", _plain_public_key(pub_key)]))
|
2015-01-27 21:47:17 +01:00
|
|
|
|
|
|
|
|
|
|
|
def test_dkim():
|
|
|
|
|
2015-03-06 19:41:28 +01:00
|
|
|
priv_key, pub_key = _generate_key(length=1024)
|
2015-01-27 21:47:17 +01:00
|
|
|
|
2015-03-25 15:04:11 +01:00
|
|
|
DKIM_PARAMS = [dict(key=NativeStringIO(to_native(priv_key)),
|
2015-02-28 12:27:30 +01:00
|
|
|
selector='_dkim',
|
2015-03-06 19:41:28 +01:00
|
|
|
domain='somewhere.net'),
|
2015-03-25 15:04:11 +01:00
|
|
|
|
|
|
|
dict(key=priv_key,
|
|
|
|
selector='_dkim',
|
|
|
|
domain='somewhere.net'),
|
|
|
|
|
|
|
|
# legacy key argument name
|
2015-03-06 19:41:28 +01:00
|
|
|
dict(privkey=priv_key,
|
|
|
|
selector='_dkim',
|
|
|
|
domain='somewhere.net'),
|
2015-02-28 12:27:30 +01:00
|
|
|
]
|
2015-01-27 21:47:17 +01:00
|
|
|
|
2015-02-28 12:27:30 +01:00
|
|
|
for dkimparams in DKIM_PARAMS:
|
2015-03-06 19:41:28 +01:00
|
|
|
message = Message(**common_email_data())
|
2015-02-28 12:27:30 +01:00
|
|
|
message.dkim(**dkimparams)
|
2015-03-06 19:41:28 +01:00
|
|
|
# check DKIM header exist
|
2015-02-28 12:27:30 +01:00
|
|
|
assert message.as_message()['DKIM-Signature']
|
2015-03-06 19:41:28 +01:00
|
|
|
#print(__name__, "type message.as_string()==", type(message.as_string()))
|
|
|
|
assert b'DKIM-Signature: ' in message.as_string()
|
|
|
|
assert _check_dkim(message, pub_key)
|
2015-03-06 13:16:49 +01:00
|
|
|
|
|
|
|
|
2015-03-06 17:32:08 +01:00
|
|
|
def test_dkim_error():
|
2015-03-06 13:16:49 +01:00
|
|
|
|
|
|
|
m = emails.html(**common_email_data())
|
2015-03-25 15:04:11 +01:00
|
|
|
|
|
|
|
# No key
|
|
|
|
with pytest.raises(TypeError):
|
|
|
|
m.dkim(selector='_dkim',
|
|
|
|
domain='somewhere.net',
|
|
|
|
ignore_sign_errors=False)
|
|
|
|
|
|
|
|
|
|
|
|
# Error in invalid key
|
2015-03-06 13:16:49 +01:00
|
|
|
invalid_key = 'X'
|
|
|
|
with pytest.raises(DKIMException):
|
2015-03-25 15:04:11 +01:00
|
|
|
m.dkim(key=invalid_key,
|
2015-03-06 13:16:49 +01:00
|
|
|
selector='_dkim',
|
|
|
|
domain='somewhere.net',
|
|
|
|
ignore_sign_errors=False)
|
2015-03-06 17:32:08 +01:00
|
|
|
|
|
|
|
# Error on invalid dkim parameters
|
|
|
|
|
2015-03-25 15:04:11 +01:00
|
|
|
m.dkim(key=PRIV_KEY,
|
2015-03-06 17:32:08 +01:00
|
|
|
selector='_dkim',
|
|
|
|
domain='somewhere.net',
|
|
|
|
include_headers=['To'])
|
|
|
|
|
|
|
|
with pytest.raises(DKIMException):
|
|
|
|
# include_heades must contain 'From'
|
|
|
|
m.as_string()
|
|
|
|
|
|
|
|
# Skip error on ignore_sign_errors=True
|
2015-03-25 15:04:11 +01:00
|
|
|
m.dkim(key=PRIV_KEY,
|
2015-03-06 17:32:08 +01:00
|
|
|
selector='_dkim',
|
|
|
|
domain='somewhere.net',
|
|
|
|
ignore_sign_errors=True,
|
|
|
|
include_headers=['To'])
|
|
|
|
|
|
|
|
m.as_string()
|
2015-03-06 19:41:28 +01:00
|
|
|
m.as_message()
|
2015-03-25 15:04:11 +01:00
|
|
|
|
|
|
|
|
|
|
|
def test_dkim_sign_twice():
|
|
|
|
|
|
|
|
# Test #44:
|
|
|
|
# " if you put the open there and send more than one messages it fails
|
|
|
|
# (the first works but the next will not if you dont seek(0) the dkim file first)"
|
|
|
|
# Actually not.
|
|
|
|
|
|
|
|
priv_key, pub_key = _generate_key(length=1024)
|
|
|
|
message = Message(**common_email_data())
|
|
|
|
message.dkim(key=NativeStringIO(to_native(priv_key)), selector='_dkim', domain='somewhere.net')
|
|
|
|
for n in range(2):
|
|
|
|
message.subject = 'Test %s' % n
|
|
|
|
assert _check_dkim(message, pub_key)
|