dkim 0.2.0 → 1.0.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/CHANGELOG.md +11 -5
- data/lib/dkim/canonicalized_headers.rb +26 -0
- data/lib/dkim/dkim_header.rb +21 -12
- data/lib/dkim/encodings.rb +3 -0
- data/lib/dkim/encodings/base64.rb +12 -0
- data/lib/dkim/encodings/dkim_quoted_printable.rb +19 -0
- data/lib/dkim/encodings/plain_text.rb +8 -0
- data/lib/dkim/header.rb +7 -0
- data/lib/dkim/interceptor.rb +2 -2
- data/lib/dkim/signed_mail.rb +15 -17
- data/lib/dkim/tag_value_list.rb +28 -0
- data/lib/dkim/version.rb +1 -1
- data/lib/mail/dkim_field.rb +2 -2
- data/test/dkim/canonicalized_headers_test.rb +51 -0
- data/test/dkim/dkim_header_test.rb +3 -2
- data/test/dkim/encodings_test.rb +24 -0
- data/test/dkim/interceptor_test.rb +17 -0
- data/test/dkim/options_test.rb +2 -0
- data/test/dkim/signed_mail_test.rb +30 -12
- data/test/dkim/tag_value_list_test.rb +28 -0
- data/test/test_helper.rb +2 -0
- metadata +15 -10
- data/lib/dkim/header_list.rb +0 -19
data/CHANGELOG.md
CHANGED
@@ -1,18 +1,24 @@
|
|
1
1
|
# dkim Changelog
|
2
2
|
|
3
|
-
##
|
3
|
+
## 1.0.0 (2012-01-15)
|
4
|
+
* DKIM-Signature header is now prepended rather than appended
|
5
|
+
* Headers are signed in the order they appear
|
6
|
+
* Correct signing of repeated headers
|
7
|
+
* Correct signing of missing headers
|
8
|
+
|
9
|
+
## 0.2.0 (2012-04-15)
|
4
10
|
* Warn and strip existing signatures in Dkim::Interceptor
|
5
11
|
* Dkim options can be accessed and modified using new Dkim.options or signed_mail.options hash
|
6
12
|
* Refactoring and better testing
|
7
13
|
* Improved documentation
|
8
14
|
|
9
|
-
##
|
15
|
+
## 0.1.0 (2011-12-10)
|
10
16
|
* Ensure header lines are not folded using Dkim::Interceptor
|
11
17
|
|
12
|
-
##
|
18
|
+
## 0.0.3 (2011-07-25)
|
13
19
|
* add Dkim::Interceptor class for integration with rails and [mail](https://github.com/mikel/mail)
|
14
20
|
|
15
|
-
##
|
21
|
+
## 0.0.2 (2011-06-01)
|
16
22
|
|
17
23
|
* add convenience method Dkim.sign
|
18
24
|
* support for the simple canonicalization algorithm
|
@@ -20,7 +26,7 @@
|
|
20
26
|
* correct handling of an empty message body
|
21
27
|
|
22
28
|
|
23
|
-
##
|
29
|
+
## 0.0.1 (2011-05-10)
|
24
30
|
|
25
31
|
* Initial release
|
26
32
|
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Dkim
|
2
|
+
class CanonicalizedHeaders
|
3
|
+
include Enumerable
|
4
|
+
def initialize header_list, signed_headers
|
5
|
+
@header_list = header_list
|
6
|
+
@signed_headers = signed_headers.map(&:downcase)
|
7
|
+
end
|
8
|
+
def each(&block)
|
9
|
+
header_hash = Hash.new {|h,k| h[k] = []}
|
10
|
+
@header_list.each do |header|
|
11
|
+
header_hash[header.relaxed_key] << header
|
12
|
+
end
|
13
|
+
|
14
|
+
@signed_headers.each do |key|
|
15
|
+
if header = header_hash[key].pop
|
16
|
+
yield header
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
def to_s(canonicalization)
|
21
|
+
map do |header|
|
22
|
+
header.to_s(canonicalization) + "\r\n"
|
23
|
+
end.join
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
data/lib/dkim/dkim_header.rb
CHANGED
@@ -1,28 +1,37 @@
|
|
1
1
|
|
2
2
|
require 'dkim/header'
|
3
|
+
require 'dkim/tag_value_list'
|
4
|
+
require 'dkim/encodings'
|
3
5
|
|
4
6
|
module Dkim
|
5
7
|
class DkimHeader < Header
|
8
|
+
attr_reader :list
|
6
9
|
def initialize values={}
|
7
10
|
self.key = 'DKIM-Signature'
|
8
|
-
@
|
11
|
+
@list = TagValueList.new values
|
9
12
|
end
|
10
13
|
def value
|
11
|
-
@
|
12
|
-
" #{k}=#{v}"
|
13
|
-
end.join(';')
|
14
|
+
" #{@list}"
|
14
15
|
end
|
15
16
|
def [] k
|
16
|
-
|
17
|
-
value && value[1]
|
17
|
+
encoder_for(k).decode(@list[k])
|
18
18
|
end
|
19
19
|
def []= k, v
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
20
|
+
@list[k] = encoder_for(k).encode(v)
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
def encoder_for key
|
25
|
+
case key
|
26
|
+
when *%w{v a c d h l q s t x}
|
27
|
+
Encodings::PlainText
|
28
|
+
when *%w{i z}
|
29
|
+
Encodings::DkimQuotedPrintable
|
30
|
+
when *%w{b bh}
|
31
|
+
Encodings::Base64
|
32
|
+
else
|
33
|
+
raise "unknown key: #{key}"
|
34
|
+
end.new
|
26
35
|
end
|
27
36
|
end
|
28
37
|
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
|
2
|
+
module Dkim
|
3
|
+
module Encodings
|
4
|
+
# Implements DKIM-Quoted-Printable as described in rfc6376 section 2.11
|
5
|
+
class DkimQuotedPrintable
|
6
|
+
DkimUnafeChar = /[^\x21-\x3A\x3C\x3E-\x7E]/
|
7
|
+
def encode string
|
8
|
+
string.gsub(DkimUnafeChar) do |char|
|
9
|
+
"=%.2x" % char.unpack('C')
|
10
|
+
end
|
11
|
+
end
|
12
|
+
def decode string
|
13
|
+
string.gsub(/=([0-9A-F]{2})/) do
|
14
|
+
$1.hex.chr
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
data/lib/dkim/header.rb
CHANGED
data/lib/dkim/interceptor.rb
CHANGED
@@ -14,8 +14,8 @@ module Dkim
|
|
14
14
|
# generate new signature
|
15
15
|
dkim_signature = SignedMail.new(message.encoded).dkim_header.value
|
16
16
|
|
17
|
-
#
|
18
|
-
message.header.fields
|
17
|
+
# prepend signature to message
|
18
|
+
message.header.fields.unshift Mail::DkimField.new(dkim_signature)
|
19
19
|
message
|
20
20
|
end
|
21
21
|
end
|
data/lib/dkim/signed_mail.rb
CHANGED
@@ -3,8 +3,8 @@ require 'openssl'
|
|
3
3
|
require 'dkim/body'
|
4
4
|
require 'dkim/dkim_header'
|
5
5
|
require 'dkim/header'
|
6
|
-
require 'dkim/header_list'
|
7
6
|
require 'dkim/options'
|
7
|
+
require 'dkim/canonicalized_headers'
|
8
8
|
|
9
9
|
module Dkim
|
10
10
|
class SignedMail
|
@@ -17,23 +17,28 @@ module Dkim
|
|
17
17
|
def initialize message, options={}
|
18
18
|
message = message.to_s.gsub(/\r?\n/, "\r\n")
|
19
19
|
headers, body = message.split(/\r?\n\r?\n/, 2)
|
20
|
-
@
|
20
|
+
@original_message = message
|
21
|
+
@headers = Header.parse headers
|
21
22
|
@body = Body.new body
|
22
23
|
|
23
24
|
# default options from Dkim.options
|
24
25
|
@options = Dkim.options.merge(options)
|
25
26
|
end
|
26
27
|
|
27
|
-
|
28
|
+
def canonicalized_headers
|
29
|
+
CanonicalizedHeaders.new(@headers, signed_headers)
|
30
|
+
end
|
31
|
+
|
32
|
+
# @return [Array<String>] lowercased names of headers in the order they are signed
|
28
33
|
def signed_headers
|
29
|
-
|
34
|
+
@headers.map(&:relaxed_key).select do |key|
|
35
|
+
signable_headers.map(&:downcase).include?(key)
|
36
|
+
end
|
30
37
|
end
|
31
38
|
|
32
39
|
# @return [String] Signed headers of message in their canonical forms
|
33
40
|
def canonical_header
|
34
|
-
|
35
|
-
@headers[key].to_s(header_canonicalization) + "\r\n"
|
36
|
-
end.join
|
41
|
+
canonicalized_headers.to_s(header_canonicalization)
|
37
42
|
end
|
38
43
|
|
39
44
|
# @return [String] Body of message in its canonical form
|
@@ -59,31 +64,24 @@ module Dkim
|
|
59
64
|
dkim_header['t'] = (time || Time.now).to_i
|
60
65
|
|
61
66
|
# Add body hash and blank signature
|
62
|
-
dkim_header['bh']=
|
67
|
+
dkim_header['bh']= digest_alg.digest(canonical_body)
|
63
68
|
dkim_header['h'] = signed_headers.join(':')
|
64
69
|
dkim_header['b'] = ''
|
65
70
|
|
66
71
|
# Calculate signature based on intermediate signature header
|
67
72
|
headers = canonical_header
|
68
73
|
headers << dkim_header.to_s(header_canonicalization)
|
69
|
-
|
70
|
-
dkim_header['b'] = signature
|
74
|
+
dkim_header['b'] = private_key.sign(digest_alg, headers)
|
71
75
|
|
72
76
|
dkim_header
|
73
77
|
end
|
74
78
|
|
75
79
|
# @return [String] Message combined with calculated dkim header signature
|
76
80
|
def to_s
|
77
|
-
|
78
|
-
headers.map(&:to_s).join("\r\n") +
|
79
|
-
"\r\n\r\n" +
|
80
|
-
@body.to_s
|
81
|
+
dkim_header.to_s + "\r\n" + @original_message
|
81
82
|
end
|
82
83
|
|
83
84
|
private
|
84
|
-
def base64_encode data
|
85
|
-
[data].pack('m0').gsub("\n",'')
|
86
|
-
end
|
87
85
|
def digest_alg
|
88
86
|
case signing_algorithm
|
89
87
|
when 'rsa-sha1'
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Dkim
|
2
|
+
class TagValueList
|
3
|
+
def initialize values={}
|
4
|
+
@keys = values.keys
|
5
|
+
@values = values.dup
|
6
|
+
end
|
7
|
+
def to_s
|
8
|
+
@keys.map do |k|
|
9
|
+
"#{k}=#{@values[k]}"
|
10
|
+
end.join('; ')
|
11
|
+
end
|
12
|
+
def [] k
|
13
|
+
@values[k]
|
14
|
+
end
|
15
|
+
def []= k, v
|
16
|
+
@keys << k unless self[k]
|
17
|
+
@values[k] = v
|
18
|
+
end
|
19
|
+
def self.parse string
|
20
|
+
list = new
|
21
|
+
string.split(';').each do |keyval|
|
22
|
+
key, value = keyval.split('=', 2)
|
23
|
+
list[key.strip] = value.strip
|
24
|
+
end
|
25
|
+
list
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
data/lib/dkim/version.rb
CHANGED
data/lib/mail/dkim_field.rb
CHANGED
@@ -0,0 +1,51 @@
|
|
1
|
+
|
2
|
+
require 'test_helper'
|
3
|
+
|
4
|
+
module Dkim
|
5
|
+
class CanonicalizedHeadersTest < MiniTest::Unit::TestCase
|
6
|
+
def test_maintains_order
|
7
|
+
headers = "ABCD".chars.map {|c| Header.new(c, c) }
|
8
|
+
header_keys = headers.map &:relaxed_key
|
9
|
+
header_keys.permutation.each do |signed_headers|
|
10
|
+
ch = CanonicalizedHeaders.new(headers, signed_headers)
|
11
|
+
assert_equal signed_headers, ch.map(&:relaxed_key)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def test_repeated_headers
|
16
|
+
headers = [
|
17
|
+
Header.new('A', '1'),
|
18
|
+
Header.new('B', '2'),
|
19
|
+
Header.new('C', '3'),
|
20
|
+
Header.new('A', '4'),
|
21
|
+
Header.new('D', '5')
|
22
|
+
]
|
23
|
+
ch = CanonicalizedHeaders.new(headers, %w{A A B C D})
|
24
|
+
assert_equal %w{4 1 2 3 5}, ch.map(&:value)
|
25
|
+
assert_equal <<-eos.rfc_format, ch.to_s('simple')
|
26
|
+
A:4<CRLF>
|
27
|
+
A:1<CRLF>
|
28
|
+
B:2<CRLF>
|
29
|
+
C:3<CRLF>
|
30
|
+
D:5<CRLF>
|
31
|
+
eos
|
32
|
+
end
|
33
|
+
|
34
|
+
# missing headers should be ignored
|
35
|
+
def test_missing_headers
|
36
|
+
headers = [
|
37
|
+
Header.new('A', '1'),
|
38
|
+
Header.new('B', '2'),
|
39
|
+
Header.new('C', '3'),
|
40
|
+
]
|
41
|
+
ch = CanonicalizedHeaders.new(headers, %w{A A B C})
|
42
|
+
assert_equal %w{a b c}, ch.map(&:relaxed_key)
|
43
|
+
assert_equal <<-eos.rfc_format, ch.to_s('simple')
|
44
|
+
A:1<CRLF>
|
45
|
+
B:2<CRLF>
|
46
|
+
C:3<CRLF>
|
47
|
+
eos
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
@@ -1,5 +1,6 @@
|
|
1
1
|
|
2
2
|
require 'test_helper'
|
3
|
+
require 'base64'
|
3
4
|
|
4
5
|
module Dkim
|
5
6
|
class DkimHeaderTest < MiniTest::Unit::TestCase
|
@@ -15,8 +16,8 @@ module Dkim
|
|
15
16
|
@header['q'] = 'dns/txt'
|
16
17
|
@header['i'] = '[email protected]'
|
17
18
|
@header['h'] = 'Received : From : To : Subject : Date : Message-ID'
|
18
|
-
@header['bh']= '2jUSOH9NhtVGCQWNr9BrIAPreKQjO6Sn7XIkfJVOzv8='
|
19
|
-
@header['b'] = 'AuUoFEfDxTDkHlLXSZEpZj79LICEps6eda7W3deTVFOk4yAUoqOB4nujc7YopdG5dWLSdNg6xNAZpOPr+kHxt1IrE+NahM6L/LbvaHutKVdkLLkpVaVVQPzeRDI009SO2Il5Lu7rDNH6mZckBdrIx0orEtZV4bmp/YzhwvcubU4='
|
19
|
+
@header['bh']= Base64.decode64 '2jUSOH9NhtVGCQWNr9BrIAPreKQjO6Sn7XIkfJVOzv8='
|
20
|
+
@header['b'] = Base64.decode64 'AuUoFEfDxTDkHlLXSZEpZj79LICEps6eda7W3deTVFOk4yAUoqOB4nujc7YopdG5dWLSdNg6xNAZpOPr+kHxt1IrE+NahM6L/LbvaHutKVdkLLkpVaVVQPzeRDI009SO2Il5Lu7rDNH6mZckBdrIx0orEtZV4bmp/YzhwvcubU4='
|
20
21
|
end
|
21
22
|
|
22
23
|
def test_correct_format
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Dkim
|
2
|
+
class EncodingsTest < MiniTest::Unit::TestCase
|
3
|
+
def test_plain_text
|
4
|
+
@encoder = Encodings::PlainText.new
|
5
|
+
assert_equal 'testing123', @encoder.encode('testing123')
|
6
|
+
assert_equal 'testing123', @encoder.decode('testing123')
|
7
|
+
end
|
8
|
+
def test_base64
|
9
|
+
@encoder = Encodings::Base64.new
|
10
|
+
assert_equal 'dGVzdGluZzEyMw==', @encoder.encode('testing123')
|
11
|
+
assert_equal 'testing123', @encoder.decode('dGVzdGluZzEyMw==')
|
12
|
+
end
|
13
|
+
def test_quoted_printable
|
14
|
+
@encoder = Encodings::DkimQuotedPrintable.new
|
15
|
+
assert_equal 'testing123', @encoder.encode('testing123')
|
16
|
+
assert_equal 'testing123', @encoder.decode('testing123')
|
17
|
+
|
18
|
+
encoded = 'From:[email protected]|To:[email protected]|Subject:demo=20run|Date:July=205,=202005=203:44:08=20PM=20-0700'
|
19
|
+
decoded = 'From:[email protected]|To:[email protected]|Subject:demo run|Date:July 5, 2005 3:44:08 PM -0700'
|
20
|
+
assert_equal encoded, @encoder.encode(decoded)
|
21
|
+
assert_equal decoded, @encoder.decode(encoded)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -40,6 +40,9 @@ Joe.
|
|
40
40
|
def setup
|
41
41
|
@original_options = Dkim.options.dup
|
42
42
|
|
43
|
+
# ensure time does not change
|
44
|
+
Dkim.time = Time.now
|
45
|
+
|
43
46
|
mail = EXAMPLEEMAIL.dup
|
44
47
|
|
45
48
|
@mail = Mail.new(mail)
|
@@ -103,6 +106,20 @@ Joe.
|
|
103
106
|
assert_equal 1, @mail.header.fields.count { |field| field.name =~ /^DKIM-Signature$/i }
|
104
107
|
assert_equal 1, @mail.encoded.scan('DKIM-Signature').count
|
105
108
|
end
|
109
|
+
|
110
|
+
def test_same_output_as_direct_usage
|
111
|
+
dkim_header = @mail['DKIM-Signature']
|
112
|
+
|
113
|
+
# Most necessary under simple
|
114
|
+
Dkim.header_canonicalization = 'simple'
|
115
|
+
Dkim.body_canonicalization = 'simple'
|
116
|
+
|
117
|
+
expected = Dkim.sign @mail.to_s
|
118
|
+
|
119
|
+
Interceptor.delivering_email(@mail)
|
120
|
+
|
121
|
+
assert_equal expected, @mail.to_s
|
122
|
+
end
|
106
123
|
end
|
107
124
|
end
|
108
125
|
|
data/test/dkim/options_test.rb
CHANGED
@@ -9,17 +9,18 @@ module Dkim
|
|
9
9
|
|
10
10
|
def test_defaults
|
11
11
|
signed_mail = SignedMail.new(@mail, :time => Time.at(1234567890))
|
12
|
-
dkim_header = signed_mail.dkim_header
|
12
|
+
dkim_header = signed_mail.dkim_header.list
|
13
13
|
|
14
14
|
assert_equal 'rsa-sha256', dkim_header['a']
|
15
15
|
assert_equal 'brisbane', dkim_header['s']
|
16
16
|
assert_equal 'example.com', dkim_header['d']
|
17
17
|
assert_equal 'relaxed/relaxed', dkim_header['c']
|
18
18
|
assert_equal 'dns/txt', dkim_header['q']
|
19
|
+
assert_equal 'from:to:subject:date:message-id', dkim_header['h']
|
19
20
|
|
20
21
|
# bh value from RFC 6376
|
21
22
|
assert_equal '2jUSOH9NhtVGCQWNr9BrIAPreKQjO6Sn7XIkfJVOzv8=', dkim_header['bh']
|
22
|
-
assert_equal '
|
23
|
+
assert_equal 'dQOeSpGJTfSbX4hPGGsy4ipcNAzC/33K7XaEXkjBneJJhv6MczHkJNsfmXeYESNIh5WVTuvE5IbnDPBVFrL+b3GKiLiyp/vlKO2NJViX4dLnKT/GdxjJh06ljZcYjUA+PorHvMwdu+cDsCffN8A7IhfVdsFruQr3vFPD0JyJ9XU=', dkim_header['b']
|
23
24
|
end
|
24
25
|
|
25
26
|
def test_overrides
|
@@ -33,15 +34,16 @@ module Dkim
|
|
33
34
|
:time => Time.at(1234567890)
|
34
35
|
}
|
35
36
|
signed_mail = SignedMail.new(@mail, options)
|
36
|
-
dkim_header = signed_mail.dkim_header
|
37
|
-
|
38
|
-
assert_equal 'rsa-sha1',
|
39
|
-
assert_equal 'sidney',
|
40
|
-
assert_equal 'example.org',
|
41
|
-
assert_equal 'simple/simple',
|
42
|
-
assert_equal 'dns/txt',
|
43
|
-
assert_equal
|
44
|
-
assert_equal '
|
37
|
+
dkim_header = signed_mail.dkim_header.list
|
38
|
+
|
39
|
+
assert_equal 'rsa-sha1', dkim_header['a']
|
40
|
+
assert_equal 'sidney', dkim_header['s']
|
41
|
+
assert_equal 'example.org', dkim_header['d']
|
42
|
+
assert_equal 'simple/simple', dkim_header['c']
|
43
|
+
assert_equal 'dns/txt', dkim_header['q']
|
44
|
+
assert_equal "from:to:subject:date:message-id", dkim_header['h']
|
45
|
+
assert_equal 'yk6W9pJJilr5MMgeEdSd7J3IaJI=', dkim_header['bh']
|
46
|
+
assert_equal 't+dk4yxTI2ByZxxRzkwhZhM4WzTZjGWHiWnS2t4pg7oT7fAIlMrfihJ/CIvGmYqYv4lbq4LStHqHx9TmEgxrkjLevHtuqhxkN55xJ2vA2QzTzFi2fMDZ4fFqWy4QtvlLjBAhevG+LXpmjPYec1cyeMlHlPAthq5+RNi6NHErJiM=', dkim_header['b']
|
45
47
|
end
|
46
48
|
|
47
49
|
def test_empty_body_hashes
|
@@ -56,11 +58,27 @@ module Dkim
|
|
56
58
|
['47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=', {:body_canonicalization => 'relaxed', :signing_algorithm => 'rsa-sha256'}],
|
57
59
|
].each do |body_hash, options|
|
58
60
|
signed_mail = SignedMail.new(@mail, options)
|
59
|
-
dkim_header = signed_mail.dkim_header
|
61
|
+
dkim_header = signed_mail.dkim_header.list
|
60
62
|
|
61
63
|
assert_equal body_hash, dkim_header['bh']
|
62
64
|
end
|
63
65
|
end
|
66
|
+
|
67
|
+
def test_multiple_instances_of_header
|
68
|
+
@mail = <<-eos
|
69
|
+
Received: <A>
|
70
|
+
Received: <B>
|
71
|
+
Received: <C>
|
72
|
+
|
73
|
+
eos
|
74
|
+
|
75
|
+
signed_mail = SignedMail.new(@mail, :header_canonicalization => 'simple', :signable_headers => Dkim::DefaultHeaders + ['Received'])
|
76
|
+
|
77
|
+
assert_equal "received:received:received", signed_mail.dkim_header['h']
|
78
|
+
|
79
|
+
headers = signed_mail.canonical_header
|
80
|
+
assert_equal "Received: <C>\r\nReceived: <B>\r\nReceived: <A>\r\n", headers.to_s
|
81
|
+
end
|
64
82
|
end
|
65
83
|
end
|
66
84
|
|
@@ -0,0 +1,28 @@
|
|
1
|
+
|
2
|
+
require 'test_helper'
|
3
|
+
|
4
|
+
module Dkim
|
5
|
+
class TagValueListTest < MiniTest::Unit::TestCase
|
6
|
+
def test_replacement
|
7
|
+
@list = TagValueList.new
|
8
|
+
|
9
|
+
@list['a'] = '1'
|
10
|
+
@list['b'] = '2'
|
11
|
+
@list['c'] = '3'
|
12
|
+
assert_equal 'a=1; b=2; c=3', @list.to_s
|
13
|
+
|
14
|
+
@list['b'] = '4'
|
15
|
+
assert_equal 'a=1; b=4; c=3', @list.to_s
|
16
|
+
end
|
17
|
+
def test_correct_format
|
18
|
+
@list = TagValueList.new
|
19
|
+
|
20
|
+
@list['b'] = '2'
|
21
|
+
@list['a'] = '1'
|
22
|
+
@list['c'] = '!@#$%^'
|
23
|
+
|
24
|
+
assert_equal 'b=2; a=1; c=!@#$%^', @list.to_s
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
data/test/test_helper.rb
CHANGED
metadata
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dkim
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.0
|
5
4
|
prerelease:
|
5
|
+
version: 1.0.0
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- John Hawthorn
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2013-01-15 00:00:00.000000000 Z
|
13
13
|
dependencies: []
|
14
14
|
description: gem for adding DKIM signatures to email messages
|
15
15
|
email:
|
@@ -31,19 +31,27 @@ files:
|
|
31
31
|
- lib/dkim.rb
|
32
32
|
- lib/dkim/body.rb
|
33
33
|
- lib/dkim/canonicalizable.rb
|
34
|
+
- lib/dkim/canonicalized_headers.rb
|
34
35
|
- lib/dkim/dkim_header.rb
|
36
|
+
- lib/dkim/encodings.rb
|
37
|
+
- lib/dkim/encodings/base64.rb
|
38
|
+
- lib/dkim/encodings/dkim_quoted_printable.rb
|
39
|
+
- lib/dkim/encodings/plain_text.rb
|
35
40
|
- lib/dkim/header.rb
|
36
|
-
- lib/dkim/header_list.rb
|
37
41
|
- lib/dkim/interceptor.rb
|
38
42
|
- lib/dkim/options.rb
|
39
43
|
- lib/dkim/signed_mail.rb
|
44
|
+
- lib/dkim/tag_value_list.rb
|
40
45
|
- lib/dkim/version.rb
|
41
46
|
- lib/mail/dkim_field.rb
|
42
47
|
- test/dkim/canonicalization_test.rb
|
48
|
+
- test/dkim/canonicalized_headers_test.rb
|
43
49
|
- test/dkim/dkim_header_test.rb
|
50
|
+
- test/dkim/encodings_test.rb
|
44
51
|
- test/dkim/interceptor_test.rb
|
45
52
|
- test/dkim/options_test.rb
|
46
53
|
- test/dkim/signed_mail_test.rb
|
54
|
+
- test/dkim/tag_value_list_test.rb
|
47
55
|
- test/test_helper.rb
|
48
56
|
homepage: https://github.com/jhawthorn/dkim
|
49
57
|
licenses: []
|
@@ -57,28 +65,25 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
57
65
|
- - ! '>='
|
58
66
|
- !ruby/object:Gem::Version
|
59
67
|
version: '0'
|
60
|
-
segments:
|
61
|
-
- 0
|
62
|
-
hash: -2701069676603955611
|
63
68
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
64
69
|
none: false
|
65
70
|
requirements:
|
66
71
|
- - ! '>='
|
67
72
|
- !ruby/object:Gem::Version
|
68
73
|
version: '0'
|
69
|
-
segments:
|
70
|
-
- 0
|
71
|
-
hash: -2701069676603955611
|
72
74
|
requirements: []
|
73
75
|
rubyforge_project: dkim
|
74
|
-
rubygems_version: 1.8.
|
76
|
+
rubygems_version: 1.8.24
|
75
77
|
signing_key:
|
76
78
|
specification_version: 3
|
77
79
|
summary: DKIM library in ruby
|
78
80
|
test_files:
|
79
81
|
- test/dkim/canonicalization_test.rb
|
82
|
+
- test/dkim/canonicalized_headers_test.rb
|
80
83
|
- test/dkim/dkim_header_test.rb
|
84
|
+
- test/dkim/encodings_test.rb
|
81
85
|
- test/dkim/interceptor_test.rb
|
82
86
|
- test/dkim/options_test.rb
|
83
87
|
- test/dkim/signed_mail_test.rb
|
88
|
+
- test/dkim/tag_value_list_test.rb
|
84
89
|
- test/test_helper.rb
|
data/lib/dkim/header_list.rb
DELETED
@@ -1,19 +0,0 @@
|
|
1
|
-
module Dkim
|
2
|
-
class HeaderList
|
3
|
-
include Enumerable
|
4
|
-
def initialize headers
|
5
|
-
@headers = headers.split(/\r?\n(?!([ \t]))/).map do |header|
|
6
|
-
key, value = header.split(':', 2)
|
7
|
-
Header.new(key, value)
|
8
|
-
end
|
9
|
-
end
|
10
|
-
def [](key)
|
11
|
-
@headers.detect do |header|
|
12
|
-
header.relaxed_key == key
|
13
|
-
end
|
14
|
-
end
|
15
|
-
def each(&block)
|
16
|
-
@headers.each(&block)
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|