Add basic end-to-end tests.
This commit is contained in:
@@ -0,0 +1 @@
|
|||||||
|
/.testrepository
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
[DEFAULT]
|
||||||
|
test_command=PYTHONPATH=. python -m subunit.run $LISTOPT $IDOPTION dkim.tests.test_dkim
|
||||||
|
test_id_option=--load-list $IDFILE
|
||||||
|
test_list_option=--list
|
||||||
@@ -21,6 +21,17 @@ To build and install pydkim:
|
|||||||
|
|
||||||
python setup.py install
|
python setup.py install
|
||||||
|
|
||||||
|
TESTING
|
||||||
|
|
||||||
|
To run pydkim's test suite:
|
||||||
|
|
||||||
|
PYTHONPATH=. python dkim/tests/test_dkim.py
|
||||||
|
|
||||||
|
Alternatively, if you have testrepository installed:
|
||||||
|
|
||||||
|
testr init
|
||||||
|
testr run
|
||||||
|
|
||||||
USAGE
|
USAGE
|
||||||
|
|
||||||
The pydkim library offers one module called dkim. The sign() function takes an
|
The pydkim library offers one module called dkim. The sign() function takes an
|
||||||
|
|||||||
@@ -396,7 +396,7 @@ def sign(message, selector, domain, privkey, identity=None, canonicalize=(Simple
|
|||||||
|
|
||||||
return sig + "\r\n"
|
return sig + "\r\n"
|
||||||
|
|
||||||
def verify(message, debuglog=None):
|
def verify(message, debuglog=None, dnsfunc=dnstxt):
|
||||||
"""Verify a DKIM signature on an RFC822 formatted message.
|
"""Verify a DKIM signature on an RFC822 formatted message.
|
||||||
|
|
||||||
@param message: an RFC822 formatted message (with either \\n or \\r\\n line endings)
|
@param message: an RFC822 formatted message (with either \\n or \\r\\n line endings)
|
||||||
@@ -548,7 +548,7 @@ def verify(message, debuglog=None):
|
|||||||
print >>debuglog, "body hash mismatch (got %s, expected %s)" % (base64.b64encode(bodyhash), sig['bh'])
|
print >>debuglog, "body hash mismatch (got %s, expected %s)" % (base64.b64encode(bodyhash), sig['bh'])
|
||||||
return False
|
return False
|
||||||
|
|
||||||
s = dnstxt(sig['s']+"._domainkey."+sig['d']+".")
|
s = dnsfunc(sig['s']+"._domainkey."+sig['d']+".")
|
||||||
if not s:
|
if not s:
|
||||||
return False
|
return False
|
||||||
a = re.split(r"\s*;\s*", s)
|
a = re.split(r"\s*;\s*", s)
|
||||||
@@ -629,11 +629,3 @@ def verify(message, debuglog=None):
|
|||||||
assert len(v) == len(sig2)
|
assert len(v) == len(sig2)
|
||||||
# Byte-by-byte compare of signatures
|
# Byte-by-byte compare of signatures
|
||||||
return not [1 for x in zip(v, sig2) if x[0] != x[1]]
|
return not [1 for x in zip(v, sig2) if x[0] != x[1]]
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
message = """From: greg@hewgill.com\r\nSubject: test\r\n message\r\n\r\nHi.\r\n\r\nWe lost the game. Are you hungry yet?\r\n\r\nJoe.\r\n"""
|
|
||||||
print rfc822_parse(message)
|
|
||||||
sig = sign(message, "greg", "hewgill.com", open("/home/greg/.domainkeys/rsa.private").read())
|
|
||||||
print sig
|
|
||||||
print verify(sig+message)
|
|
||||||
#print sign(open("/home/greg/tmp/message").read(), "greg", "hewgill.com", open("/home/greg/.domainkeys/rsa.private").read())
|
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
Received: from localhost
|
||||||
|
Message-ID: <example@example.com>
|
||||||
|
Date: Mon, 01 Jan 2011 01:02:03 +0400
|
||||||
|
From: Test User <test@example.com>
|
||||||
|
To: somebody@example.com
|
||||||
|
Subject: Testing
|
||||||
|
|
||||||
|
This is a test message.
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
-----BEGIN RSA PRIVATE KEY-----
|
||||||
|
MIICXQIBAAKBgQDkHlOQoBTzWRiGs5V6NpP3idY6Wk08a5qhdR6wy5bdOKb2jLQi
|
||||||
|
Y/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lxj+PL6lHvqM
|
||||||
|
KrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB
|
||||||
|
AoGAH0cxOhFZDgzXWhDhnAJDw5s4roOXN4OhjiXa8W7Y3rhX3FJqmJSPuC8N9vQm
|
||||||
|
6SVbaLAE4SG5mLMueHlh4KXffEpuLEiNp9Ss3O4YfLiQpbRqE7Tm5SxKjvvQoZZe
|
||||||
|
zHorimOaChRL2it47iuWxzxSiRMv4c+j70GiWdxXnxe4UoECQQDzJB/0U58W7RZy
|
||||||
|
6enGVj2kWF732CoWFZWzi1FicudrBFoy63QwcowpoCazKtvZGMNlPWnC7x/6o8Gc
|
||||||
|
uSe0ga2xAkEA8C7PipPm1/1fTRQvj1o/dDmZp243044ZNyxjg+/OPN0oWCbXIGxy
|
||||||
|
WvmZbXriOWoSALJTjExEgraHEgnXssuk7QJBALl5ICsYMu6hMxO73gnfNayNgPxd
|
||||||
|
WFV6Z7ULnKyV7HSVYF0hgYOHjeYe9gaMtiJYoo0zGN+L3AAtNP9huqkWlzECQE1a
|
||||||
|
licIeVlo1e+qJ6Mgqr0Q7Aa7falZ448ccbSFYEPD6oFxiOl9Y9se9iYHZKKfIcst
|
||||||
|
o7DUw1/hz2Ck4N5JrgUCQQCyKveNvjzkkd8HjYs0SwM0fPjK16//5qDZ2UiDGnOe
|
||||||
|
uEzxBDAr518Z8VFbR41in3W4Y3yCDgQlLlcETrS+zYcL
|
||||||
|
-----END RSA PRIVATE KEY-----
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
v=DKIM1; g=*; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkHlOQoBTzWRiGs5V6NpP3idY6Wk08a5qhdR6wy5bdOKb2jLQiY/J16JYi0Qvx/byYzCNb3W91y3FutACDfzwQ/BC/e/8uBsCR+yz1Lxj+PL6lHvqMKrM3rG4hstT5QjvHO9PzoxZyVYLzBfO2EeC3Ip3G+2kryOTIKT+l/K4w3QIDAQAB
|
||||||
@@ -0,0 +1,72 @@
|
|||||||
|
# This software is provided 'as-is', without any express or implied
|
||||||
|
# warranty. In no event will the author be held liable for any damages
|
||||||
|
# arising from the use of this software.
|
||||||
|
#
|
||||||
|
# Permission is granted to anyone to use this software for any purpose,
|
||||||
|
# including commercial applications, and to alter it and redistribute it
|
||||||
|
# freely, subject to the following restrictions:
|
||||||
|
#
|
||||||
|
# 1. The origin of this software must not be misrepresented; you must not
|
||||||
|
# claim that you wrote the original software. If you use this software
|
||||||
|
# in a product, an acknowledgment in the product documentation would be
|
||||||
|
# appreciated but is not required.
|
||||||
|
# 2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
# misrepresented as being the original software.
|
||||||
|
# 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
#
|
||||||
|
# Copyright (c) 2011 William Grant <me@williamgrant.id.au>
|
||||||
|
|
||||||
|
import os.path
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
import dkim
|
||||||
|
|
||||||
|
|
||||||
|
def read_test_data(filename):
|
||||||
|
"""Get the content of the given test data file.
|
||||||
|
|
||||||
|
The files live in dkim/tests/data.
|
||||||
|
"""
|
||||||
|
path = os.path.join(os.path.dirname(__file__), 'data', filename)
|
||||||
|
return open(path).read()
|
||||||
|
|
||||||
|
|
||||||
|
class TestFold(unittest.TestCase):
|
||||||
|
|
||||||
|
def test_short_line(self):
|
||||||
|
self.assertEqual(
|
||||||
|
"foo", dkim.fold("foo"))
|
||||||
|
|
||||||
|
def DISABLED_test_long_line(self):
|
||||||
|
# The function is terribly broken, not passing even this simple
|
||||||
|
# test.
|
||||||
|
self.assertEqual(
|
||||||
|
"foo"*24 + "\r\n foo", dkim.fold("foo" * 25))
|
||||||
|
|
||||||
|
|
||||||
|
class TestSignAndVerify(unittest.TestCase):
|
||||||
|
"""End-to-end signature and verification tests."""
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
self.message = read_test_data("test.message")
|
||||||
|
self.key = read_test_data("test.private")
|
||||||
|
|
||||||
|
def dnsfunc(self, domain):
|
||||||
|
self.assertEqual('test._domainkey.example.com.', domain)
|
||||||
|
return read_test_data("test.txt")
|
||||||
|
|
||||||
|
def test_verifies(self):
|
||||||
|
# A message verifies after being signed.
|
||||||
|
sig = dkim.sign(self.message, "test", "example.com", self.key)
|
||||||
|
res = dkim.verify(sig + self.message, dnsfunc=self.dnsfunc)
|
||||||
|
self.assertTrue(res)
|
||||||
|
|
||||||
|
def test_altered_body_fails(self):
|
||||||
|
# An altered body fails verification.
|
||||||
|
sig = dkim.sign(self.message, "test", "example.com", self.key)
|
||||||
|
res = dkim.verify(sig + self.message + "foo", dnsfunc=self.dnsfunc)
|
||||||
|
self.assertFalse(res)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
||||||
Reference in New Issue
Block a user