dkim 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.travis.yml +9 -0
- data/CHANGELOG.md +9 -0
- data/Gemfile +10 -0
- data/Guardfile +5 -0
- data/README.md +50 -60
- data/bin/dkimsign.rb +0 -0
- data/lib/dkim.rb +3 -8
- data/lib/dkim/interceptor.rb +13 -1
- data/lib/dkim/options.rb +72 -0
- data/lib/dkim/signed_mail.rb +18 -43
- data/lib/dkim/version.rb +1 -1
- data/test/dkim/canonicalization_test.rb +80 -0
- data/test/dkim/dkim_header_test.rb +42 -0
- data/test/dkim/interceptor_test.rb +108 -0
- data/test/dkim/options_test.rb +37 -0
- data/test/dkim/signed_mail_test.rb +66 -0
- data/test/test_helper.rb +34 -4
- metadata +22 -5
- data/test/canonicalization_test.rb +0 -78
data/.travis.yml
ADDED
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,14 @@
|
|
1
1
|
# dkim Changelog
|
2
2
|
|
3
|
+
## 2012.04.15, Version 0.2.0
|
4
|
+
* Warn and strip existing signatures in Dkim::Interceptor
|
5
|
+
* Dkim options can be accessed and modified using new Dkim.options or signed_mail.options hash
|
6
|
+
* Refactoring and better testing
|
7
|
+
* Improved documentation
|
8
|
+
|
9
|
+
## 2011.12.10, Version 0.1.0
|
10
|
+
* Ensure header lines are not folded using Dkim::Interceptor
|
11
|
+
|
3
12
|
## 2011.07.25, Version 0.0.3
|
4
13
|
* add Dkim::Interceptor class for integration with rails and [mail](https://github.com/mikel/mail)
|
5
14
|
|
data/Gemfile
CHANGED
data/Guardfile
ADDED
data/README.md
CHANGED
@@ -1,30 +1,62 @@
|
|
1
1
|
dkim
|
2
2
|
====
|
3
|
-
|
4
3
|
A DKIM signing library in ruby.
|
5
4
|
|
5
|
+
[](http://travis-ci.org/jhawthorn/dkim)
|
6
|
+
|
7
|
+
[Documentation](http://rubydoc.info/github/jhawthorn/dkim)
|
8
|
+
|
6
9
|
Installation
|
7
10
|
============
|
8
11
|
|
9
12
|
sudo gem install dkim
|
10
13
|
|
11
|
-
|
12
|
-
|
14
|
+
Necessary configuration
|
15
|
+
=======================
|
16
|
+
A private key, a domain, and a selector need to be specified in order to sign messages.
|
17
|
+
|
18
|
+
These can be specified globally
|
19
|
+
|
20
|
+
Dkim::domain = 'example.com'
|
21
|
+
Dkim::selector = 'mail'
|
22
|
+
Dkim::private_key = open('private.pem').read
|
23
|
+
|
24
|
+
Options can be overridden per message.
|
25
|
+
|
26
|
+
Dkim.sign(mail, :selector => 'mail2', :private_key => open('private2.pem').read)
|
27
|
+
|
28
|
+
For more details see {Dkim::Options}
|
29
|
+
|
30
|
+
Usage With Rails
|
31
|
+
================
|
32
|
+
|
33
|
+
Dkim contains `Dkim::Interceptor` which can be used to sign all mail delivered by rails 3 or [mail](https://github.com/mikel/mail).
|
34
|
+
For rails, create an initializer (for example `config/initializers/dkim.rb`) with the following template.
|
35
|
+
|
36
|
+
# Configure dkim globally (see above)
|
37
|
+
Dkim::domain = 'example.com'
|
38
|
+
Dkim::selector = 'mail'
|
39
|
+
Dkim::private_key = open('private.pem').read
|
40
|
+
|
41
|
+
# This will sign all ActionMailer deliveries
|
42
|
+
ActionMailer::Base.register_interceptor(Dkim::Interceptor)
|
43
|
+
|
44
|
+
Standalone Usage
|
45
|
+
================
|
13
46
|
|
14
47
|
Calling `Dkim.sign` on a string representing an email message returns the message with a DKIM signature inserted.
|
15
48
|
|
16
49
|
For example
|
17
50
|
|
18
|
-
mail = <<
|
51
|
+
mail = Dkim.sign(<<EOS)
|
19
52
|
To: someone@example.com
|
20
53
|
From: john@example.com
|
21
54
|
Subject: hi
|
22
|
-
|
55
|
+
|
23
56
|
Howdy
|
24
|
-
|
57
|
+
EOS
|
25
58
|
|
26
59
|
Dkim.sign(mail)
|
27
|
-
|
28
60
|
# =>
|
29
61
|
# To: someone@example.com
|
30
62
|
# From: john@example.com
|
@@ -34,67 +66,25 @@ For example
|
|
34
66
|
# b=0mKnNOkxFGiww63Zu4t46J7eZc3Uak3I9km3IH2Le3XcnSNtWJgxiwBX26IZ5yzcT
|
35
67
|
# VwJzcCnPKCScIJMQ7yfbfXmNsKVIOV6eSUqu1YvJ1fgzlSAXuDEMNFTjoto5rrdA+
|
36
68
|
# BgX849hEY/bWHDl1JJgNpiwtpl4t0Q7M4BVJUd7Lo=
|
37
|
-
#
|
69
|
+
#
|
38
70
|
# Howdy
|
39
71
|
|
40
|
-
|
41
|
-
-----------------------
|
42
|
-
A private key, a domain, and a selector need to be specified in order to sign messages.
|
43
|
-
|
44
|
-
These can be specified globally
|
45
|
-
|
46
|
-
Dkim::domain = 'example.com'
|
47
|
-
Dkim::selector = 'mail'
|
48
|
-
Dkim::private_key = open('private.pem').read
|
72
|
+
More flexibility can be found using {Dkim::SignedMail} directly.
|
49
73
|
|
50
|
-
|
51
|
-
|
52
|
-
Dkim.sign(mail, :selector => 'mail2', :private_key => open('private2.pem').read)
|
53
|
-
|
54
|
-
Additional configuration
|
55
|
-
------------------------
|
74
|
+
Specific configuration
|
75
|
+
========================
|
56
76
|
|
57
|
-
|
58
|
-
|
59
|
-
Dkim::signable_headers = Dkim::DefaultHeaders # Sign only the specified headers
|
60
|
-
Dkim::signing_algorithm = 'rsa-sha256' # can be rsa-sha1 or rsa-sha256 (default)
|
61
|
-
Dkim::header_canonicalization = 'relaxed' # Can be simple or relaxed (default)
|
62
|
-
Dkim::body_canonicalization = 'relaxed' # Can be simple or relaxed (default)
|
63
|
-
|
64
|
-
The defaults should fit most users needs; however, certain use cases will need them to be customized.
|
65
|
-
|
66
|
-
For example, for sending mesages through amazon SES, certain headers should not be signed
|
77
|
+
For sending mesages through Amazon SES, certain headers should not be signed
|
67
78
|
|
68
79
|
Dkim::signable_headers = Dkim::DefaultHeaders - %w{Message-ID Resent-Message-ID Date Return-Path Bounces-To}
|
69
80
|
|
70
|
-
|
81
|
+
Some OpenSSL's don't have sha256 support.
|
82
|
+
RFC 6376 states that signers SHOULD sign using rsa-sha256.
|
83
|
+
For this reason, dkim will *not* use rsa-sha1 as a fallback.
|
71
84
|
If you wish to override this behaviour and use whichever algorithm is available you can use this snippet (**not recommended**).
|
72
85
|
|
73
86
|
Dkim::signing_algorithm = defined?(OpenSSL::Digest::SHA256) ? 'rsa-sha256' : 'rsa-sha1'
|
74
87
|
|
75
|
-
Usage With Rails
|
76
|
-
================
|
77
|
-
|
78
|
-
Dkim contains `Dkim::Interceptor` which can be used to sign all mail delivered by the [mail gem](https://github.com/mikel/mail) or rails 3, which uses mail.
|
79
|
-
For rails, create an initializer (for example `config/initializers/dkim.rb`) with the following template.
|
80
|
-
|
81
|
-
# Configure dkim globally (see above)
|
82
|
-
Dkim::domain = 'example.com'
|
83
|
-
Dkim::selector = 'mail'
|
84
|
-
Dkim::private_key = open('private.pem').read
|
85
|
-
|
86
|
-
# This will sign all ActionMailer deliveries
|
87
|
-
ActionMailer::Base.register_interceptor('Dkim::Interceptor')
|
88
|
-
|
89
|
-
Example executable
|
90
|
-
==================
|
91
|
-
|
92
|
-
The library includes a `dkimsign.rb` executable suitable for testing the library or performing simple signatures.
|
93
|
-
|
94
|
-
`dkimsign.rb DOMAIN SELECTOR KEYFILE [MAILFILE]`
|
95
|
-
|
96
|
-
If MAILFILE is not specified `dkimsign.rb` will read the mail message from standard in.
|
97
|
-
|
98
88
|
Limitations
|
99
89
|
===========
|
100
90
|
|
@@ -108,11 +98,11 @@ Limitations
|
|
108
98
|
Resources
|
109
99
|
=========
|
110
100
|
|
111
|
-
* [RFC
|
101
|
+
* [RFC 6376](http://tools.ietf.org/html/rfc6376)
|
112
102
|
* Inspired by perl's [Mail-DKIM](http://dkimproxy.sourceforge.net/)
|
113
103
|
|
114
|
-
|
115
|
-
|
104
|
+
License
|
105
|
+
=======
|
116
106
|
|
117
107
|
(The MIT License)
|
118
108
|
|
data/bin/dkimsign.rb
CHANGED
File without changes
|
data/lib/dkim.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
|
2
2
|
require 'dkim/signed_mail'
|
3
|
+
require 'dkim/options'
|
3
4
|
require 'dkim/interceptor'
|
4
5
|
|
5
6
|
module Dkim
|
@@ -14,13 +15,7 @@ module Dkim
|
|
14
15
|
List-Post List-Owner List-Archive}
|
15
16
|
|
16
17
|
class << self
|
17
|
-
|
18
|
-
|
19
|
-
attr_reader :private_key
|
20
|
-
def private_key= key
|
21
|
-
key = OpenSSL::PKey::RSA.new(key) if key.is_a?(String)
|
22
|
-
@private_key = key
|
23
|
-
end
|
18
|
+
include Dkim::Options
|
24
19
|
|
25
20
|
def sign message, options={}
|
26
21
|
SignedMail.new(message, options).to_s
|
@@ -28,7 +23,7 @@ module Dkim
|
|
28
23
|
end
|
29
24
|
end
|
30
25
|
|
31
|
-
Dkim::signable_headers = Dkim::DefaultHeaders
|
26
|
+
Dkim::signable_headers = Dkim::DefaultHeaders.dup
|
32
27
|
Dkim::domain = nil
|
33
28
|
Dkim::selector = nil
|
34
29
|
Dkim::signing_algorithm = 'rsa-sha256'
|
data/lib/dkim/interceptor.rb
CHANGED
@@ -3,7 +3,19 @@ module Dkim
|
|
3
3
|
class Interceptor
|
4
4
|
def self.delivering_email(message)
|
5
5
|
require 'mail/dkim_field'
|
6
|
-
|
6
|
+
|
7
|
+
# strip any existing signatures
|
8
|
+
if message['DKIM-Signature']
|
9
|
+
warn "WARNING: Dkim::Interceptor given a message with an existing signature, which it has replaced."
|
10
|
+
warn "If you really want to add a second signature to the message, you should be using the dkim gem directly."
|
11
|
+
message['DKIM-Signature'] = nil
|
12
|
+
end
|
13
|
+
|
14
|
+
# generate new signature
|
15
|
+
dkim_signature = SignedMail.new(message.encoded).dkim_header.value
|
16
|
+
|
17
|
+
# append signature to message
|
18
|
+
message.header.fields << Mail::DkimField.new(dkim_signature)
|
7
19
|
message
|
8
20
|
end
|
9
21
|
end
|
data/lib/dkim/options.rb
ADDED
@@ -0,0 +1,72 @@
|
|
1
|
+
module Dkim
|
2
|
+
module Options
|
3
|
+
private
|
4
|
+
def self.define_option_method attribute_name
|
5
|
+
define_method(attribute_name){options[attribute_name]}
|
6
|
+
define_method("#{attribute_name}="){|value| options[attribute_name] = value}
|
7
|
+
end
|
8
|
+
public
|
9
|
+
|
10
|
+
# @attribute [rw]
|
11
|
+
# Hash of all options
|
12
|
+
# @return [Hash]
|
13
|
+
def options
|
14
|
+
@options ||= {}
|
15
|
+
end
|
16
|
+
attr_writer :options
|
17
|
+
|
18
|
+
# @attribute [rw]
|
19
|
+
# This corresponds to the t= tag in the dkim header.
|
20
|
+
# The default (nil) is to use the current time at signing.
|
21
|
+
# @return [Time,#to_i] A Time object or seconds since the epoch
|
22
|
+
define_option_method :time
|
23
|
+
|
24
|
+
# @attribute [rw]
|
25
|
+
# The signing algorithm for dkim. Valid values are 'rsa-sha1' and 'rsa-sha256' (default).
|
26
|
+
# This corresponds to the a= tag in the dkim header.
|
27
|
+
# @return [String] signing algorithm
|
28
|
+
define_option_method :signing_algorithm
|
29
|
+
|
30
|
+
# @attribute [rw]
|
31
|
+
# Configures which headers should be signed.
|
32
|
+
# Defaults to {Dkim::DefaultHeaders Dkim::DefaultHeaders}
|
33
|
+
# @return [Array<String>] signable headers
|
34
|
+
define_option_method :signable_headers
|
35
|
+
|
36
|
+
# @attribute [rw]
|
37
|
+
# The domain used for signing.
|
38
|
+
# This corresponds to the d= tag in the dkim header.
|
39
|
+
# @return [String] domain
|
40
|
+
define_option_method :domain
|
41
|
+
|
42
|
+
# @attribute [rw]
|
43
|
+
# Selector used for signing.
|
44
|
+
# This corresponds to the s= tag in the dkim header.
|
45
|
+
# @return [String] selector
|
46
|
+
define_option_method :selector
|
47
|
+
|
48
|
+
# @attribute [rw]
|
49
|
+
# Header canonicalization algorithm.
|
50
|
+
# Valid values are 'simple' and 'relaxed' (default)
|
51
|
+
# This corresponds to the first half of the c= tag in the dkim header.
|
52
|
+
# @return [String] header canonicalization algorithm
|
53
|
+
define_option_method :header_canonicalization
|
54
|
+
|
55
|
+
# @attribute [rw]
|
56
|
+
# Body canonicalization algorithm.
|
57
|
+
# Valid values are 'simple' and 'relaxed' (default)
|
58
|
+
# This corresponds to the second half of the c= tag in the dkim header.
|
59
|
+
# @return [String] body canonicalization algorithm
|
60
|
+
define_option_method :body_canonicalization
|
61
|
+
|
62
|
+
# @attribute [rw]
|
63
|
+
# RSA private key for signing.
|
64
|
+
# Can be assigned either an {OpenSSL::PKey::RSA} private key or a valid PEM format string.
|
65
|
+
# @return [OpenSSL::PKey::RSA] private key
|
66
|
+
define_option_method :private_key
|
67
|
+
def private_key= key
|
68
|
+
key = OpenSSL::PKey::RSA.new(key) if key.is_a?(String)
|
69
|
+
options[:private_key] = key
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
data/lib/dkim/signed_mail.rb
CHANGED
@@ -4,69 +4,44 @@ require 'dkim/body'
|
|
4
4
|
require 'dkim/dkim_header'
|
5
5
|
require 'dkim/header'
|
6
6
|
require 'dkim/header_list'
|
7
|
+
require 'dkim/options'
|
7
8
|
|
8
9
|
module Dkim
|
9
10
|
class SignedMail
|
11
|
+
include Options
|
12
|
+
|
13
|
+
# A new instance of SignedMail
|
14
|
+
#
|
15
|
+
# @param [String,#to_s] message mail message to be signed
|
16
|
+
# @param [Hash] options hash of options for signing. Defaults are taken from {Dkim}. See {Options} for details.
|
10
17
|
def initialize message, options={}
|
11
18
|
message = message.to_s.gsub(/\r?\n/, "\r\n")
|
12
19
|
headers, body = message.split(/\r?\n\r?\n/, 2)
|
13
20
|
@headers = HeaderList.new headers
|
14
21
|
@body = Body.new body
|
15
22
|
|
16
|
-
|
17
|
-
@
|
18
|
-
@selector = options[:selector]
|
19
|
-
@time = options[:time]
|
20
|
-
@signing_algorithm = options[:signing_algorithm]
|
21
|
-
@private_key = options[:private_key]
|
22
|
-
@header_canonicalization = options[:header_canonicalization]
|
23
|
-
@body_canonicalization = options[:body_canonicalization]
|
24
|
-
end
|
25
|
-
|
26
|
-
# options for signatures
|
27
|
-
attr_writer :signing_algorithm, :signable_headers, :domain, :selector, :time, :header_canonicalization, :body_canonicalization
|
28
|
-
|
29
|
-
def private_key= key
|
30
|
-
key = OpenSSL::PKey::RSA.new(key) if key.is_a?(String)
|
31
|
-
@private_key = key
|
32
|
-
end
|
33
|
-
def private_key
|
34
|
-
@private_key || Dkim::private_key
|
35
|
-
end
|
36
|
-
def signing_algorithm
|
37
|
-
@signing_algorithm || Dkim::signing_algorithm
|
38
|
-
end
|
39
|
-
def signable_headers
|
40
|
-
@signable_headers || Dkim::signable_headers
|
41
|
-
end
|
42
|
-
def domain
|
43
|
-
@domain || Dkim::domain
|
44
|
-
end
|
45
|
-
def selector
|
46
|
-
@selector || Dkim::selector
|
47
|
-
end
|
48
|
-
def time
|
49
|
-
@time
|
50
|
-
end
|
51
|
-
def header_canonicalization
|
52
|
-
@header_canonicalization || Dkim::header_canonicalization
|
53
|
-
end
|
54
|
-
def body_canonicalization
|
55
|
-
@body_canonicalization || Dkim::body_canonicalization
|
23
|
+
# default options from Dkim.options
|
24
|
+
@options = Dkim.options.merge(options)
|
56
25
|
end
|
57
26
|
|
27
|
+
# @return [Array<String>] Signed headers of message in their canonical forms
|
58
28
|
def signed_headers
|
59
29
|
(@headers.map(&:relaxed_key) & signable_headers.map(&:downcase)).sort
|
60
30
|
end
|
31
|
+
|
32
|
+
# @return [String] Signed headers of message in their canonical forms
|
61
33
|
def canonical_header
|
62
34
|
headers = signed_headers.map do |key|
|
63
35
|
@headers[key].to_s(header_canonicalization) + "\r\n"
|
64
36
|
end.join
|
65
37
|
end
|
38
|
+
|
39
|
+
# @return [String] Body of message in its canonical form
|
66
40
|
def canonical_body
|
67
41
|
@body.to_s(body_canonicalization)
|
68
42
|
end
|
69
43
|
|
44
|
+
# @return [DkimHeader] Constructed signature for the mail message
|
70
45
|
def dkim_header
|
71
46
|
dkim_header = DkimHeader.new
|
72
47
|
|
@@ -97,8 +72,8 @@ module Dkim
|
|
97
72
|
dkim_header
|
98
73
|
end
|
99
74
|
|
75
|
+
# @return [String] Message combined with calculated dkim header signature
|
100
76
|
def to_s
|
101
|
-
# Return the original message with the calculated header
|
102
77
|
headers = @headers.to_a + [dkim_header]
|
103
78
|
headers.map(&:to_s).join("\r\n") +
|
104
79
|
"\r\n\r\n" +
|
@@ -107,13 +82,13 @@ module Dkim
|
|
107
82
|
|
108
83
|
private
|
109
84
|
def base64_encode data
|
110
|
-
[data].pack('m0
|
85
|
+
[data].pack('m0').gsub("\n",'')
|
111
86
|
end
|
112
87
|
def digest_alg
|
113
88
|
case signing_algorithm
|
114
89
|
when 'rsa-sha1'
|
115
90
|
OpenSSL::Digest::SHA1.new
|
116
|
-
when 'rsa-sha256'
|
91
|
+
when 'rsa-sha256'
|
117
92
|
OpenSSL::Digest::SHA256.new
|
118
93
|
else
|
119
94
|
raise "Unknown digest algorithm: '#{signing_algorithm}'"
|
data/lib/dkim/version.rb
CHANGED
@@ -0,0 +1,80 @@
|
|
1
|
+
|
2
|
+
require 'test_helper'
|
3
|
+
|
4
|
+
module Dkim
|
5
|
+
class CanonicalizationTest < MiniTest::Unit::TestCase
|
6
|
+
# from section 3.4.6 of RFC 6376
|
7
|
+
def setup
|
8
|
+
@input = <<-eos.rfc_format
|
9
|
+
A: <SP> X <CRLF>
|
10
|
+
B <SP> : <SP> Y <HTAB><CRLF>
|
11
|
+
<HTAB> Z <SP><SP><CRLF>
|
12
|
+
<CRLF>
|
13
|
+
<SP> C <SP><CRLF>
|
14
|
+
D <SP><HTAB><SP> E <CRLF>
|
15
|
+
<CRLF>
|
16
|
+
<CRLF>
|
17
|
+
eos
|
18
|
+
@mail = SignedMail.new(@input)
|
19
|
+
@mail.signable_headers = ['A', 'B']
|
20
|
+
end
|
21
|
+
def test_relaxed_header
|
22
|
+
@mail.header_canonicalization = 'relaxed'
|
23
|
+
expected_header = <<-eos.rfc_format
|
24
|
+
a:X <CRLF>
|
25
|
+
b:Y <SP> Z <CRLF>
|
26
|
+
eos
|
27
|
+
assert_equal expected_header, @mail.canonical_header
|
28
|
+
end
|
29
|
+
def test_relaxed_body
|
30
|
+
@mail.body_canonicalization = 'relaxed'
|
31
|
+
expected_body = <<-eos.rfc_format
|
32
|
+
<SP> C <CRLF>
|
33
|
+
D <SP> E <CRLF>
|
34
|
+
eos
|
35
|
+
assert_equal expected_body, @mail.canonical_body
|
36
|
+
end
|
37
|
+
|
38
|
+
def test_simple_header
|
39
|
+
@mail.header_canonicalization = 'simple'
|
40
|
+
expected_header = <<-eos.rfc_format
|
41
|
+
A: <SP> X <CRLF>
|
42
|
+
B <SP> : <SP> Y <HTAB><CRLF>
|
43
|
+
<HTAB> Z <SP><SP><CRLF>
|
44
|
+
eos
|
45
|
+
assert_equal expected_header, @mail.canonical_header
|
46
|
+
end
|
47
|
+
def test_simple_body
|
48
|
+
@mail.body_canonicalization = 'simple'
|
49
|
+
expected_body = <<-eos.rfc_format
|
50
|
+
<SP> C <SP><CRLF>
|
51
|
+
D <SP><HTAB><SP> E <CRLF>
|
52
|
+
eos
|
53
|
+
assert_equal expected_body, @mail.canonical_body
|
54
|
+
end
|
55
|
+
|
56
|
+
# from errata: empty bodies
|
57
|
+
def test_simple_empty_body
|
58
|
+
@mail = SignedMail.new("test: test\r\n\r\n")
|
59
|
+
@mail.body_canonicalization = 'simple'
|
60
|
+
|
61
|
+
assert_equal "\r\n", @mail.canonical_body
|
62
|
+
end
|
63
|
+
|
64
|
+
def test_relaxed_empty_body
|
65
|
+
@mail = SignedMail.new("test: test\r\n\r\n")
|
66
|
+
@mail.body_canonicalization = 'relaxed'
|
67
|
+
|
68
|
+
assert_equal "", @mail.canonical_body
|
69
|
+
end
|
70
|
+
|
71
|
+
def test_relaxed_errata_1384
|
72
|
+
body = "testing<crlf><sp><sp><cr><lf><cr><lf>".rfc_format
|
73
|
+
@mail = SignedMail.new("test: test\r\n\r\n#{body}")
|
74
|
+
@mail.body_canonicalization = 'relaxed'
|
75
|
+
|
76
|
+
assert_equal "testing\r\n", @mail.canonical_body
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
@@ -0,0 +1,42 @@
|
|
1
|
+
|
2
|
+
require 'test_helper'
|
3
|
+
|
4
|
+
module Dkim
|
5
|
+
class DkimHeaderTest < MiniTest::Unit::TestCase
|
6
|
+
def setup
|
7
|
+
@header = DkimHeader.new
|
8
|
+
|
9
|
+
# from Appendix A of RFC 6376
|
10
|
+
@header['v'] = '1'
|
11
|
+
@header['a'] = 'rsa-sha256'
|
12
|
+
@header['s'] = 'brisbane'
|
13
|
+
@header['d'] = 'example.com'
|
14
|
+
@header['c'] = 'simple/simple'
|
15
|
+
@header['q'] = 'dns/txt'
|
16
|
+
@header['i'] = 'joe@football.example.com'
|
17
|
+
@header['h'] = 'Received : From : To : Subject : Date : Message-ID'
|
18
|
+
@header['bh']= '2jUSOH9NhtVGCQWNr9BrIAPreKQjO6Sn7XIkfJVOzv8='
|
19
|
+
@header['b'] = 'AuUoFEfDxTDkHlLXSZEpZj79LICEps6eda7W3deTVFOk4yAUoqOB4nujc7YopdG5dWLSdNg6xNAZpOPr+kHxt1IrE+NahM6L/LbvaHutKVdkLLkpVaVVQPzeRDI009SO2Il5Lu7rDNH6mZckBdrIx0orEtZV4bmp/YzhwvcubU4='
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_correct_format
|
23
|
+
header = @header.to_s
|
24
|
+
|
25
|
+
# result from RFC 6376 minus trailing ';'
|
26
|
+
expected = %{
|
27
|
+
DKIM-Signature: v=1; a=rsa-sha256; s=brisbane; d=example.com;
|
28
|
+
c=simple/simple; q=dns/txt; i=joe@football.example.com;
|
29
|
+
h=Received : From : To : Subject : Date : Message-ID;
|
30
|
+
bh=2jUSOH9NhtVGCQWNr9BrIAPreKQjO6Sn7XIkfJVOzv8=;
|
31
|
+
b=AuUoFEfDxTDkHlLXSZEpZj79LICEps6eda7W3deTVFOk4yAUoqOB
|
32
|
+
4nujc7YopdG5dWLSdNg6xNAZpOPr+kHxt1IrE+NahM6L/LbvaHut
|
33
|
+
KVdkLLkpVaVVQPzeRDI009SO2Il5Lu7rDNH6mZckBdrIx0orEtZV
|
34
|
+
4bmp/YzhwvcubU4=
|
35
|
+
}
|
36
|
+
|
37
|
+
# compare removing whitespace
|
38
|
+
assert_equal expected.gsub(/\s/,''), header.gsub(/\s/,'')
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
@@ -0,0 +1,108 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
require 'mail'
|
4
|
+
|
5
|
+
module Dkim
|
6
|
+
SIGNEDMAIL = <<-eos
|
7
|
+
DKIM-Signature: v=1; a=rsa-sha256; s=brisbane; d=example.com;
|
8
|
+
c=simple/simple; q=dns/txt; i=joe@football.example.com;
|
9
|
+
h=Received : From : To : Subject : Date : Message-ID;
|
10
|
+
bh=2jUSOH9NhtVGCQWNr9BrIAPreKQjO6Sn7XIkfJVOzv8=;
|
11
|
+
b=AuUoFEfDxTDkHlLXSZEpZj79LICEps6eda7W3deTVFOk4yAUoqOB
|
12
|
+
4nujc7YopdG5dWLSdNg6xNAZpOPr+kHxt1IrE+NahM6L/LbvaHut
|
13
|
+
KVdkLLkpVaVVQPzeRDI009SO2Il5Lu7rDNH6mZckBdrIx0orEtZV
|
14
|
+
4bmp/YzhwvcubU4=;
|
15
|
+
Received: from client1.football.example.com [192.0.2.1]
|
16
|
+
by submitserver.example.com with SUBMISSION;
|
17
|
+
Fri, 11 Jul 2003 21:01:54 -0700 (PDT)
|
18
|
+
From: Joe SixPack <joe@football.example.com>
|
19
|
+
To: Suzie Q <suzie@shopping.example.net>
|
20
|
+
Subject: Is dinner ready?
|
21
|
+
Date: Fri, 11 Jul 2003 21:00:37 -0700 (PDT)
|
22
|
+
Message-ID: <20030712040037.46341.5F8J@football.example.com>
|
23
|
+
DKIM-Signature: v=1; a=rsa-sha256; s=brisbane; d=example.com;
|
24
|
+
c=simple/simple; q=dns/txt; i=joe@football.example.com;
|
25
|
+
h=Received : From : To : Subject : Date : Message-ID;
|
26
|
+
bh=2jUSOH9NhtVGCQWNr9BrIAPreKQjO6Sn7XIkfJVOzv8=;
|
27
|
+
b=AuUoFEfDxTDkHlLXSZEpZj79LICEps6eda7W3deTVFOk4yAUoqOB
|
28
|
+
4nujc7YopdG5dWLSdNg6xNAZpOPr+kHxt1IrE+NahM6L/LbvaHut
|
29
|
+
KVdkLLkpVaVVQPzeRDI009SO2Il5Lu7rDNH6mZckBdrIx0orEtZV
|
30
|
+
4bmp/YzhwvcubU4=;
|
31
|
+
|
32
|
+
Hi.
|
33
|
+
|
34
|
+
We lost the game. Are you hungry yet?
|
35
|
+
|
36
|
+
Joe.
|
37
|
+
eos
|
38
|
+
|
39
|
+
class InterceptorTest < MiniTest::Unit::TestCase
|
40
|
+
def setup
|
41
|
+
@original_options = Dkim.options.dup
|
42
|
+
|
43
|
+
mail = EXAMPLEEMAIL.dup
|
44
|
+
|
45
|
+
@mail = Mail.new(mail)
|
46
|
+
end
|
47
|
+
|
48
|
+
def teardown
|
49
|
+
Dkim.options = @original_options
|
50
|
+
end
|
51
|
+
|
52
|
+
def test_header_with_relaxed
|
53
|
+
Dkim.header_canonicalization = 'relaxed'
|
54
|
+
Dkim.body_canonicalization = 'relaxed'
|
55
|
+
Dkim.signing_algorithm = 'rsa-sha256'
|
56
|
+
Interceptor.delivering_email(@mail)
|
57
|
+
dkim_header = @mail['DKIM-Signature']
|
58
|
+
|
59
|
+
assert dkim_header
|
60
|
+
assert_includes dkim_header.to_s, 'rsa-sha256'
|
61
|
+
assert_includes dkim_header.to_s, 's=brisbane'
|
62
|
+
assert_includes dkim_header.to_s, 'd=example.com'
|
63
|
+
assert_includes dkim_header.to_s, 'c=relaxed/relaxed'
|
64
|
+
assert_includes dkim_header.to_s, 'q=dns/txt'
|
65
|
+
assert_includes dkim_header.to_s, 'bh=2jUSOH9NhtVGCQWNr9BrIAPreKQjO6Sn7XIkfJVOzv8='
|
66
|
+
|
67
|
+
# TODO: double check signing of 'b' header
|
68
|
+
end
|
69
|
+
|
70
|
+
def test_header_with_simple
|
71
|
+
Dkim.header_canonicalization = 'simple'
|
72
|
+
Dkim.body_canonicalization = 'simple'
|
73
|
+
Dkim.signing_algorithm = 'rsa-sha256'
|
74
|
+
Interceptor.delivering_email(@mail)
|
75
|
+
dkim_header = @mail['DKIM-Signature']
|
76
|
+
assert dkim_header
|
77
|
+
assert_includes dkim_header.to_s, 'rsa-sha256'
|
78
|
+
assert_includes dkim_header.to_s, 's=brisbane'
|
79
|
+
assert_includes dkim_header.to_s, 'd=example.com'
|
80
|
+
assert_includes dkim_header.to_s, 'c=simple/simple'
|
81
|
+
assert_includes dkim_header.to_s, 'q=dns/txt'
|
82
|
+
assert_includes dkim_header.to_s, 'bh=2jUSOH9NhtVGCQWNr9BrIAPreKQjO6Sn7XIkfJVOzv8='
|
83
|
+
|
84
|
+
# TODO: double check signing of 'b' header
|
85
|
+
end
|
86
|
+
|
87
|
+
def test_strips_exsting_headers
|
88
|
+
warnings = ""
|
89
|
+
klass = Class.new(Interceptor)
|
90
|
+
klass.class.send(:define_method, :warn) do |message|
|
91
|
+
warnings << message << "\n"
|
92
|
+
end
|
93
|
+
@mail = Mail.new(SIGNEDMAIL)
|
94
|
+
|
95
|
+
assert_equal 2, @mail.header.fields.count { |field| field.name =~ /^DKIM-Signature$/i }
|
96
|
+
assert_equal 2, @mail.encoded.scan('DKIM-Signature').count
|
97
|
+
|
98
|
+
klass.delivering_email(@mail)
|
99
|
+
|
100
|
+
# should give a warning
|
101
|
+
assert_includes warnings, 'Interceptor'
|
102
|
+
|
103
|
+
assert_equal 1, @mail.header.fields.count { |field| field.name =~ /^DKIM-Signature$/i }
|
104
|
+
assert_equal 1, @mail.encoded.scan('DKIM-Signature').count
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Dkim
|
2
|
+
class OptionsTest < MiniTest::Unit::TestCase
|
3
|
+
def setup
|
4
|
+
klass = Class.new
|
5
|
+
klass.send :include, Options
|
6
|
+
@options = klass.new
|
7
|
+
end
|
8
|
+
def test_defaults_empty
|
9
|
+
assert_equal({}, @options.options)
|
10
|
+
end
|
11
|
+
|
12
|
+
def test_all_options
|
13
|
+
@options.signing_algorithm = 'abc123'
|
14
|
+
assert_equal({:signing_algorithm => 'abc123'}, @options.options)
|
15
|
+
|
16
|
+
desired_options = {
|
17
|
+
:signing_algorithm => 'abc123',
|
18
|
+
:signable_headers => [],
|
19
|
+
:domain => 'example.net',
|
20
|
+
:selector => 'selector',
|
21
|
+
:time => 'time',
|
22
|
+
:header_canonicalization => 'simple',
|
23
|
+
:body_canonicalization => 'simple'
|
24
|
+
}
|
25
|
+
|
26
|
+
desired_options.each do |key, value|
|
27
|
+
@options.send("#{key}=", value)
|
28
|
+
end
|
29
|
+
|
30
|
+
assert_equal(desired_options, @options.options)
|
31
|
+
|
32
|
+
desired_options.each do |key, value|
|
33
|
+
assert_equal value, @options.send("#{key}")
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
|
2
|
+
require 'test_helper'
|
3
|
+
|
4
|
+
module Dkim
|
5
|
+
class SignedMailTest < MiniTest::Unit::TestCase
|
6
|
+
def setup
|
7
|
+
@mail = EXAMPLEEMAIL.dup
|
8
|
+
end
|
9
|
+
|
10
|
+
def test_defaults
|
11
|
+
signed_mail = SignedMail.new(@mail, :time => Time.at(1234567890))
|
12
|
+
dkim_header = signed_mail.dkim_header
|
13
|
+
|
14
|
+
assert_equal 'rsa-sha256', dkim_header['a']
|
15
|
+
assert_equal 'brisbane', dkim_header['s']
|
16
|
+
assert_equal 'example.com', dkim_header['d']
|
17
|
+
assert_equal 'relaxed/relaxed', dkim_header['c']
|
18
|
+
assert_equal 'dns/txt', dkim_header['q']
|
19
|
+
|
20
|
+
# bh value from RFC 6376
|
21
|
+
assert_equal '2jUSOH9NhtVGCQWNr9BrIAPreKQjO6Sn7XIkfJVOzv8=', dkim_header['bh']
|
22
|
+
assert_equal 'mamSUb17FQSZY2lfkeAsH/DvmpHsXdaFAu6BfbVblGBQ5+2yIPCx+clF5wClVBj97utSZb1WwOM0iup1JL37FI/UG+bxHo+MdGLqbLR63THGEdVF8FVeST4o4EQTWe0H3P/sU2rRZ61+M2SrTS94QkKAgj89QNOG48xSAO9xdfs=', dkim_header['b']
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_overrides
|
26
|
+
options = {
|
27
|
+
:domain => 'example.org',
|
28
|
+
:selector => 'sidney',
|
29
|
+
:time => Time.now,
|
30
|
+
:signing_algorithm => 'rsa-sha1',
|
31
|
+
:header_canonicalization => 'simple',
|
32
|
+
:body_canonicalization => 'simple',
|
33
|
+
:time => Time.at(1234567890)
|
34
|
+
}
|
35
|
+
signed_mail = SignedMail.new(@mail, options)
|
36
|
+
dkim_header = signed_mail.dkim_header
|
37
|
+
|
38
|
+
assert_equal 'rsa-sha1', dkim_header['a']
|
39
|
+
assert_equal 'sidney', dkim_header['s']
|
40
|
+
assert_equal 'example.org', dkim_header['d']
|
41
|
+
assert_equal 'simple/simple', dkim_header['c']
|
42
|
+
assert_equal 'dns/txt', dkim_header['q']
|
43
|
+
assert_equal 'yk6W9pJJilr5MMgeEdSd7J3IaJI=', dkim_header['bh']
|
44
|
+
assert_equal 'sqYGmen+fouyIj83HuJ1v+1x40xp481bLxxcgAWMFsWYEwG05KYl+o0ZWn8jqgd1coKlX29o9iFjcMtZHudT8KpOdcLVYpY3gxzNfEgH79eRz32/ieGgroSK2GoMA/aV1QkxfUZexLUdj9oOX8uaMYXDkj8RGmlEGi+NDz/e4sE=', dkim_header['b']
|
45
|
+
end
|
46
|
+
|
47
|
+
def test_empty_body_hashes
|
48
|
+
@mail = @mail.split("\n\n").first + "\n\n"
|
49
|
+
|
50
|
+
# the following are from RFC 6376 section 3.4.3 and 3.4.4
|
51
|
+
[
|
52
|
+
# [bh, options]
|
53
|
+
['uoq1oCgLlTqpdDX/iUbLy7J1Wic=', {:body_canonicalization => 'simple', :signing_algorithm => 'rsa-sha1' }],
|
54
|
+
['frcCV1k9oG9oKj3dpUqdJg1PxRT2RSN/XKdLCPjaYaY=', {:body_canonicalization => 'simple', :signing_algorithm => 'rsa-sha256'}],
|
55
|
+
['2jmj7l5rSw0yVb/vlWAYkK/YBwk=', {:body_canonicalization => 'relaxed', :signing_algorithm => 'rsa-sha1' }],
|
56
|
+
['47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=', {:body_canonicalization => 'relaxed', :signing_algorithm => 'rsa-sha256'}],
|
57
|
+
].each do |body_hash, options|
|
58
|
+
signed_mail = SignedMail.new(@mail, options)
|
59
|
+
dkim_header = signed_mail.dkim_header
|
60
|
+
|
61
|
+
assert_equal body_hash, dkim_header['bh']
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
data/test/test_helper.rb
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
|
2
|
-
require '
|
2
|
+
require 'minitest/autorun'
|
3
3
|
require 'dkim'
|
4
4
|
|
5
5
|
class String
|
6
|
-
# Parse the format used in
|
6
|
+
# Parse the format used in RFC 6376
|
7
7
|
#
|
8
8
|
# In the following examples, actual whitespace is used only for
|
9
9
|
# clarity. The actual input and output text is designated using
|
@@ -23,7 +23,37 @@ class String
|
|
23
23
|
end
|
24
24
|
end
|
25
25
|
|
26
|
-
# examples used in
|
27
|
-
|
26
|
+
# examples used in RFC 6376
|
27
|
+
EXAMPLEEMAIL = %{
|
28
|
+
From: Joe SixPack <IIVyTowbcT@www.brandonchecketts.com>
|
29
|
+
To: Suzie Q <suzie@shopping.example.net>
|
30
|
+
Subject: Is dinner ready?
|
31
|
+
Date: Fri, 11 Jul 2003 21:00:37 -0700 (PDT)
|
32
|
+
Message-ID: <20030712040037.46341.5F8J@football.example.com>
|
33
|
+
|
34
|
+
Hi.
|
35
|
+
|
36
|
+
We lost the game. Are you hungry yet?
|
28
37
|
|
38
|
+
Joe.}.gsub(/\A\n/,'')
|
39
|
+
|
40
|
+
Dkim::domain = 'example.com'
|
41
|
+
Dkim::selector = 'brisbane'
|
42
|
+
Dkim::private_key = %{
|
43
|
+
-----BEGIN RSA PRIVATE KEY-----
|
44
|
+
MIICXwIBAAKBgQDwIRP/UC3SBsEmGqZ9ZJW3/DkMoGeLnQg1fWn7/zYtIxN2SnFC
|
45
|
+
jxOCKG9v3b4jYfcTNh5ijSsq631uBItLa7od+v/RtdC2UzJ1lWT947qR+Rcac2gb
|
46
|
+
to/NMqJ0fzfVjH4OuKhitdY9tf6mcwGjaNBcWToIMmPSPDdQPNUYckcQ2QIDAQAB
|
47
|
+
AoGBALmn+XwWk7akvkUlqb+dOxyLB9i5VBVfje89Teolwc9YJT36BGN/l4e0l6QX
|
48
|
+
/1//6DWUTB3KI6wFcm7TWJcxbS0tcKZX7FsJvUz1SbQnkS54DJck1EZO/BLa5ckJ
|
49
|
+
gAYIaqlA9C0ZwM6i58lLlPadX/rtHb7pWzeNcZHjKrjM461ZAkEA+itss2nRlmyO
|
50
|
+
n1/5yDyCluST4dQfO8kAB3toSEVc7DeFeDhnC1mZdjASZNvdHS4gbLIA1hUGEF9m
|
51
|
+
3hKsGUMMPwJBAPW5v/U+AWTADFCS22t72NUurgzeAbzb1HWMqO4y4+9Hpjk5wvL/
|
52
|
+
eVYizyuce3/fGke7aRYw/ADKygMJdW8H/OcCQQDz5OQb4j2QDpPZc0Nc4QlbvMsj
|
53
|
+
7p7otWRO5xRa6SzXqqV3+F0VpqvDmshEBkoCydaYwc2o6WQ5EBmExeV8124XAkEA
|
54
|
+
qZzGsIxVP+sEVRWZmW6KNFSdVUpk3qzK0Tz/WjQMe5z0UunY9Ax9/4PVhp/j61bf
|
55
|
+
eAYXunajbBSOLlx4D+TunwJBANkPI5S9iylsbLs6NkaMHV6k5ioHBBmgCak95JGX
|
56
|
+
GMot/L2x0IYyMLAz6oLWh2hm7zwtb0CgOrPo1ke44hFYnfc=
|
57
|
+
-----END RSA PRIVATE KEY-----
|
58
|
+
}
|
29
59
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dkim
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2012-04-16 00:00:00.000000000 Z
|
13
13
|
dependencies: []
|
14
14
|
description: gem for adding DKIM signatures to email messages
|
15
15
|
email:
|
@@ -20,8 +20,10 @@ extensions: []
|
|
20
20
|
extra_rdoc_files: []
|
21
21
|
files:
|
22
22
|
- .gitignore
|
23
|
+
- .travis.yml
|
23
24
|
- CHANGELOG.md
|
24
25
|
- Gemfile
|
26
|
+
- Guardfile
|
25
27
|
- README.md
|
26
28
|
- Rakefile
|
27
29
|
- bin/dkimsign.rb
|
@@ -33,10 +35,15 @@ files:
|
|
33
35
|
- lib/dkim/header.rb
|
34
36
|
- lib/dkim/header_list.rb
|
35
37
|
- lib/dkim/interceptor.rb
|
38
|
+
- lib/dkim/options.rb
|
36
39
|
- lib/dkim/signed_mail.rb
|
37
40
|
- lib/dkim/version.rb
|
38
41
|
- lib/mail/dkim_field.rb
|
39
|
-
- test/canonicalization_test.rb
|
42
|
+
- test/dkim/canonicalization_test.rb
|
43
|
+
- test/dkim/dkim_header_test.rb
|
44
|
+
- test/dkim/interceptor_test.rb
|
45
|
+
- test/dkim/options_test.rb
|
46
|
+
- test/dkim/signed_mail_test.rb
|
40
47
|
- test/test_helper.rb
|
41
48
|
homepage: https://github.com/jhawthorn/dkim
|
42
49
|
licenses: []
|
@@ -50,18 +57,28 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
50
57
|
- - ! '>='
|
51
58
|
- !ruby/object:Gem::Version
|
52
59
|
version: '0'
|
60
|
+
segments:
|
61
|
+
- 0
|
62
|
+
hash: -2701069676603955611
|
53
63
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
54
64
|
none: false
|
55
65
|
requirements:
|
56
66
|
- - ! '>='
|
57
67
|
- !ruby/object:Gem::Version
|
58
68
|
version: '0'
|
69
|
+
segments:
|
70
|
+
- 0
|
71
|
+
hash: -2701069676603955611
|
59
72
|
requirements: []
|
60
73
|
rubyforge_project: dkim
|
61
|
-
rubygems_version: 1.8.
|
74
|
+
rubygems_version: 1.8.17
|
62
75
|
signing_key:
|
63
76
|
specification_version: 3
|
64
77
|
summary: DKIM library in ruby
|
65
78
|
test_files:
|
66
|
-
- test/canonicalization_test.rb
|
79
|
+
- test/dkim/canonicalization_test.rb
|
80
|
+
- test/dkim/dkim_header_test.rb
|
81
|
+
- test/dkim/interceptor_test.rb
|
82
|
+
- test/dkim/options_test.rb
|
83
|
+
- test/dkim/signed_mail_test.rb
|
67
84
|
- test/test_helper.rb
|
@@ -1,78 +0,0 @@
|
|
1
|
-
|
2
|
-
require 'test_helper'
|
3
|
-
|
4
|
-
class CanonicalizationTest < Test::Unit::TestCase
|
5
|
-
# from section 3.4.6 of rfc4871
|
6
|
-
def setup
|
7
|
-
@input = <<-eos.rfc_format
|
8
|
-
A: <SP> X <CRLF>
|
9
|
-
B <SP> : <SP> Y <HTAB><CRLF>
|
10
|
-
<HTAB> Z <SP><SP><CRLF>
|
11
|
-
<CRLF>
|
12
|
-
<SP> C <SP><CRLF>
|
13
|
-
D <SP><HTAB><SP> E <CRLF>
|
14
|
-
<CRLF>
|
15
|
-
<CRLF>
|
16
|
-
eos
|
17
|
-
@mail = Dkim::SignedMail.new(@input)
|
18
|
-
@mail.signable_headers = ['A', 'B']
|
19
|
-
end
|
20
|
-
def test_relaxed_header
|
21
|
-
@mail.header_canonicalization = 'relaxed'
|
22
|
-
expected_header = <<-eos.rfc_format
|
23
|
-
a:X <CRLF>
|
24
|
-
b:Y <SP> Z <CRLF>
|
25
|
-
eos
|
26
|
-
assert_equal expected_header, @mail.canonical_header
|
27
|
-
end
|
28
|
-
def test_relaxed_body
|
29
|
-
@mail.body_canonicalization = 'relaxed'
|
30
|
-
expected_body = <<-eos.rfc_format
|
31
|
-
<SP> C <CRLF>
|
32
|
-
D <SP> E <CRLF>
|
33
|
-
eos
|
34
|
-
assert_equal expected_body, @mail.canonical_body
|
35
|
-
end
|
36
|
-
|
37
|
-
def test_simple_header
|
38
|
-
@mail.header_canonicalization = 'simple'
|
39
|
-
expected_header = <<-eos.rfc_format
|
40
|
-
A: <SP> X <CRLF>
|
41
|
-
B <SP> : <SP> Y <HTAB><CRLF>
|
42
|
-
<HTAB> Z <SP><SP><CRLF>
|
43
|
-
eos
|
44
|
-
assert_equal expected_header, @mail.canonical_header
|
45
|
-
end
|
46
|
-
def test_simple_body
|
47
|
-
@mail.body_canonicalization = 'simple'
|
48
|
-
expected_body = <<-eos.rfc_format
|
49
|
-
<SP> C <SP><CRLF>
|
50
|
-
D <SP><HTAB><SP> E <CRLF>
|
51
|
-
eos
|
52
|
-
assert_equal expected_body, @mail.canonical_body
|
53
|
-
end
|
54
|
-
|
55
|
-
# from errata: empty bodies
|
56
|
-
def test_simple_empty_body
|
57
|
-
@mail = Dkim::SignedMail.new("test: test\r\n\r\n")
|
58
|
-
@mail.body_canonicalization = 'simple'
|
59
|
-
|
60
|
-
assert_equal "\r\n", @mail.canonical_body
|
61
|
-
end
|
62
|
-
|
63
|
-
def test_relaxed_empty_body
|
64
|
-
@mail = Dkim::SignedMail.new("test: test\r\n\r\n")
|
65
|
-
@mail.body_canonicalization = 'relaxed'
|
66
|
-
|
67
|
-
assert_equal "", @mail.canonical_body
|
68
|
-
end
|
69
|
-
|
70
|
-
def test_relaxed_errata_1384
|
71
|
-
body = "testing<crlf><sp><sp><cr><lf><cr><lf>".rfc_format
|
72
|
-
@mail = Dkim::SignedMail.new("test: test\r\n\r\n#{body}")
|
73
|
-
@mail.body_canonicalization = 'relaxed'
|
74
|
-
|
75
|
-
assert_equal "testing\r\n", @mail.canonical_body
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|