dkimverify 0.0.1

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.
@@ -0,0 +1,300 @@
1
+ require 'spec_helper'
2
+ require 'dkim/query/parser'
3
+
4
+ describe Parser do
5
+ describe ".parse" do
6
+ subject { described_class }
7
+
8
+ let(:dkim) do
9
+ %{k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDrEee0Ri4Juz+QfiWYui/E9UGSXau/2P8LjnTD8V4Unn+2FAZVGE3kL23bzeoULYv4PeleB3gfmJiDJOKU3Ns5L4KJAUUHjFwDebt0NP+sBK0VKeTATL2Yr/S3bT/xhy+1xtj4RkdV7fVxTn56Lb4udUnwuxK4V5b5PdOKj/+XcwIDAQAB; n=A 1024 bit key;}
10
+ end
11
+
12
+ it "should parse a DKIM record into a Hash" do
13
+ expect(subject.parse(dkim)).to be == {
14
+ k: :rsa,
15
+ p: %{MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDrEee0Ri4Juz+QfiWYui/E9UGSXau/2P8LjnTD8V4Unn+2FAZVGE3kL23bzeoULYv4PeleB3gfmJiDJOKU3Ns5L4KJAUUHjFwDebt0NP+sBK0VKeTATL2Yr/S3bT/xhy+1xtj4RkdV7fVxTn56Lb4udUnwuxK4V5b5PdOKj/+XcwIDAQAB},
16
+ n: "A 1024 bit key;"
17
+ }
18
+ end
19
+ end
20
+
21
+ describe "tags" do
22
+ describe "v" do
23
+ subject { super().key_v_tag }
24
+
25
+ it "should parse v=DKIM1" do
26
+ expect(subject.parse('v=DKIM1')).to be == {
27
+ name: 'v',
28
+ value: {symbol: 'DKIM1'}
29
+ }
30
+ end
31
+ end
32
+
33
+ describe "g" do
34
+ subject { super().key_g_tag }
35
+ end
36
+
37
+ describe "h" do
38
+ subject { super().key_h_tag }
39
+
40
+ it "should parse h=sha1" do
41
+ expect(subject.parse('h=sha1')).to be == {
42
+ name: 'h',
43
+ value: {symbol: 'sha1'}
44
+ }
45
+ end
46
+
47
+ it "should parse h=sha256" do
48
+ expect(subject.parse('h=sha256')).to be == {
49
+ name: 'h',
50
+ value: {symbol: 'sha256'}
51
+ }
52
+ end
53
+
54
+ it "should parse h=sha1:sha256" do
55
+ expect(subject.parse('h=sha1:sha256')).to be == {
56
+ name: 'h',
57
+ value: [
58
+ {symbol: 'sha1'},
59
+ {symbol: 'sha256'}
60
+ ]
61
+ }
62
+ end
63
+
64
+ it "should parse h=abc-123-xyz" do
65
+ expect(subject.parse('h=abc-123-xyz')).to be == {
66
+ name: 'h',
67
+ value: {string: 'abc-123-xyz'}
68
+ }
69
+ end
70
+ end
71
+
72
+ describe "k" do
73
+ subject { super().key_k_tag }
74
+
75
+ it "should parse k=rsa" do
76
+ expect(subject.parse('k=rsa')).to be == {
77
+ name: 'k',
78
+ value: {symbol: 'rsa'}
79
+ }
80
+ end
81
+
82
+ it "should parse k=abc-123-xyz" do
83
+ expect(subject.parse('k=abc-123-xyz')).to be == {
84
+ name: 'k',
85
+ value: {string: 'abc-123-xyz'}
86
+ }
87
+ end
88
+ end
89
+
90
+ describe "n" do
91
+ subject { super().key_n_tag }
92
+
93
+ let(:notes) { %{A 1024 bit key} }
94
+
95
+ it "should parse n=..." do
96
+ expect(subject.parse("n=#{notes}")).to be == {
97
+ name: 'n',
98
+ value: {string: notes}
99
+ }
100
+ end
101
+ end
102
+
103
+ describe "p" do
104
+ subject { super().key_p_tag }
105
+
106
+ let(:base64) { %{MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDrEee0Ri4Juz+QfiWYui/E9UGSXau/2P8LjnTD8V4Unn+2FAZVGE3kL23bzeoULYv4PeleB3gfmJiDJOKU3Ns5L4KJAUUHjFwDebt0NP+sBK0VKeTATL2Yr/S3bT/xhy+1xtj4RkdV7fVxTn56Lb4udUnwuxK4V5b5PdOKj/+XcwIDAQAB} }
107
+
108
+ it "should parse p=..." do
109
+ expect(subject.parse("p=#{base64}")).to be == {
110
+ name: 'p',
111
+ value: {asn1: base64}
112
+ }
113
+ end
114
+ end
115
+
116
+ describe "s" do
117
+ subject { super().key_s_tag }
118
+
119
+ it "should parse s=email" do
120
+ expect(subject.parse('s=email')).to be == {
121
+ name: 's',
122
+ value: {symbol: 'email'}
123
+ }
124
+ end
125
+
126
+ it "should parse s=*" do
127
+ expect(subject.parse('s=*')).to be == {
128
+ name: 's',
129
+ value: {symbol: '*'}
130
+ }
131
+ end
132
+
133
+ it "should parse s=email:*" do
134
+ expect(subject.parse('s=email:*')).to be == {
135
+ name: 's',
136
+ value: [{symbol: 'email'}, {symbol: '*'}]
137
+ }
138
+ end
139
+
140
+ it "should parse s=abc-123-xyz" do
141
+ expect(subject.parse('s=abc-123-xyz')).to be == {
142
+ name: 's',
143
+ value: {string: 'abc-123-xyz'}
144
+ }
145
+ end
146
+ end
147
+
148
+ describe "t" do
149
+ subject { super().key_t_tag }
150
+
151
+ it "should parse t=y" do
152
+ expect(subject.parse('t=y')).to be == {
153
+ name: 't',
154
+ value: {symbol: 'y'}
155
+ }
156
+ end
157
+
158
+ it "should parse t=s" do
159
+ expect(subject.parse('t=s')).to be == {
160
+ name: 't',
161
+ value: {symbol: 's'}
162
+ }
163
+ end
164
+
165
+ it "should parse t=abc-123-xyz" do
166
+ expect(subject.parse('t=abc-123-xyz')).to be == {
167
+ name: 't',
168
+ value: {string: 'abc-123-xyz'}
169
+ }
170
+ end
171
+ end
172
+ end
173
+
174
+ describe "rules" do
175
+ describe "dkim_quoted_printable" do
176
+ end
177
+
178
+ describe "dkim_safe_char" do
179
+ end
180
+
181
+ describe "hyphenated_word" do
182
+ subject { super().hyphenated_word }
183
+
184
+ it "should parse abc" do
185
+ expect(subject.parse('abc')).to be == 'abc'
186
+ end
187
+
188
+ it "should parse abc123" do
189
+ expect(subject.parse('abc123')).to be == 'abc123'
190
+ end
191
+
192
+ it "should parse a-b-c" do
193
+ expect(subject.parse('a-b-c')).to be == 'a-b-c'
194
+ end
195
+
196
+ it "should parse a---b---c" do
197
+ expect(subject.parse('a---b---c')).to be == 'a---b---c'
198
+ end
199
+
200
+ it "should not parse -a" do
201
+ expect { subject.parse('-a') }.to raise_error(Parslet::ParseFailed)
202
+ end
203
+
204
+ it "should not parse a-" do
205
+ expect { subject.parse('a-') }.to raise_error(Parslet::ParseFailed)
206
+ end
207
+
208
+ it "should not parse -" do
209
+ expect { subject.parse('-') }.to raise_error(Parslet::ParseFailed)
210
+ end
211
+ end
212
+
213
+ describe "base64string" do
214
+ end
215
+
216
+ describe "qp_section" do
217
+ subject { super().qp_section }
218
+
219
+ it "should parse \"A\"" do
220
+ expect(subject.parse('A')).to be == 'A'
221
+ end
222
+
223
+ it "should parse \"AAA\"" do
224
+ expect(subject.parse('AAA')).to be == 'AAA'
225
+ end
226
+
227
+ it "should parse \" A\"" do
228
+ expect(subject.parse(' A')).to be == ' A'
229
+ end
230
+
231
+ it "should parse \"A B\"" do
232
+ expect(subject.parse('A B')).to be == 'A B'
233
+ end
234
+
235
+ it "should not parse \" \"" do
236
+ expect {
237
+ subject.parse(' ')
238
+ }.to raise_error(Parslet::ParseFailed)
239
+ end
240
+
241
+ it "should not parse \"A \"" do
242
+ expect {
243
+ subject.parse('A ')
244
+ }.to raise_error(Parslet::ParseFailed)
245
+ end
246
+ end
247
+
248
+ describe "hex_octet" do
249
+ end
250
+ end
251
+
252
+ describe Parser::Transform do
253
+ context "when given {symbol: ...}" do
254
+ let(:string) { 'foo' }
255
+
256
+ it "should convert the string into a Symbol" do
257
+ expect(subject.apply(symbol: string)).to be == string.to_sym
258
+ end
259
+ end
260
+
261
+ context "when given {tag: {name: ..., value: ...}}" do
262
+ let(:name) { 'foo' }
263
+ let(:value) { 'bar' }
264
+
265
+ it "should convert the string into Hash" do
266
+ expect(subject.apply(
267
+ {tag: {name: name, value: value}}
268
+ )).to be == {name.to_sym => value}
269
+ end
270
+ end
271
+
272
+ context "when given {tag: {name: ..., value: [...]}}" do
273
+ let(:name) { 'foo' }
274
+ let(:value) { ['a', 'b'] }
275
+
276
+ it "should convert the string into Hash" do
277
+ expect(subject.apply(
278
+ {tag: {name: name, value: value}}
279
+ )).to be == {name.to_sym => value}
280
+ end
281
+ end
282
+
283
+ context "when {tag_list: {...}}" do
284
+ let(:hash) { {foo: 'bar'} }
285
+
286
+ it "should return the single Hash" do
287
+ expect(subject.apply({tag_list: hash})).to be == hash
288
+ end
289
+ end
290
+
291
+ context "when {tag_list: [{...}, ...]}" do
292
+ let(:hashes) { [{foo: 'bar'}, {baz: 'quix'}] }
293
+ let(:hash) { {foo: 'bar', baz: 'quix'} }
294
+
295
+ it "should merge the Hashes together" do
296
+ expect(subject.apply({tag_list: hashes})).to be == hash
297
+ end
298
+ end
299
+ end
300
+ end
@@ -0,0 +1,68 @@
1
+ require 'spec_helper'
2
+ require 'dkim/query/query'
3
+
4
+ describe DKIM::Query do
5
+ subject { described_class }
6
+
7
+ let(:domain) { 'yahoo.com' }
8
+
9
+ describe ".host_without_tld" do
10
+ let(:tld) { ".com" }
11
+
12
+ it "should strip the last component of the domain" do
13
+ expect(subject.host_without_tld(domain)).to be == domain.chomp(tld)
14
+ end
15
+
16
+ context "when given a host with no tld" do
17
+ let(:domain) { 'test' }
18
+
19
+ it "should return the full host" do
20
+ expect(subject.host_without_tld(domain)).to be == domain
21
+ end
22
+ end
23
+ end
24
+
25
+ describe ".selectors_for" do
26
+ subject { described_class.selectors_for(domain) }
27
+
28
+ described_class::SELECTORS.each do |selector|
29
+ it "should include '#{selector}'" do
30
+ expect(subject).to include(selector)
31
+ end
32
+ end
33
+
34
+ it "should include the domain without the TLD" do
35
+ expect(subject).to include('yahoo')
36
+ end
37
+ end
38
+
39
+ describe ".query" do
40
+ it "should return all found DKIM keys" do
41
+ expect(subject.query(domain)).to be == {
42
+ 's1024' => 'k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDrEee0Ri4Juz+QfiWYui/E9UGSXau/2P8LjnTD8V4Unn+2FAZVGE3kL23bzeoULYv4PeleB3gfmJiDJOKU3Ns5L4KJAUUHjFwDebt0NP+sBK0VKeTATL2Yr/S3bT/xhy+1xtj4RkdV7fVxTn56Lb4udUnwuxK4V5b5PdOKj/+XcwIDAQAB; n=A 1024 bit key;'
43
+ }
44
+ end
45
+
46
+ context "with custom selectors" do
47
+ let(:selectors) { ['google', 's1024'] }
48
+
49
+ it "should query those selectors only" do
50
+ expect(subject.query(domain, selectors: selectors)).to have_key('s1024')
51
+ end
52
+ end
53
+
54
+ context "with no selectors" do
55
+ it "should not find any keys" do
56
+ expect(subject.query(domain, selectors: [])).to be_empty
57
+ end
58
+ end
59
+
60
+ context "when given an invalid domain" do
61
+ let(:domain) { 'foo.bar.com' }
62
+
63
+ it "should return {}" do
64
+ expect(subject.query(domain)).to be == {}
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,13 @@
1
+ if ENV['CODECLIMATE_REPO_TOKEN']
2
+ require "codeclimate-test-reporter"
3
+ CodeClimate::TestReporter.start
4
+ end
5
+
6
+ require 'rspec'
7
+ require 'dkim/query'
8
+
9
+ include DKIM::Query
10
+
11
+ RSpec.configure do |specs|
12
+ specs
13
+ end
@@ -0,0 +1,43 @@
1
+ ##
2
+ # Adapted from gist: https://gist.github.com/zerothabhishek/3015666
3
+ # Orginal author: zerothabhishek
4
+ ##
5
+
6
+ require 'nokogiri'
7
+ require 'open-uri'
8
+ require 'resolv'
9
+ require 'csv'
10
+
11
+ namespace :alexa do
12
+ desc 'Scrapes the Alexa Top 500 and updates spec/data/alexa.csv'
13
+ task :scrape do
14
+ resolver = Resolv::DNS.new
15
+
16
+ CSV.open("spec/data/alexa.csv","w") do |csv|
17
+ (0..19).each do |i|
18
+ url = "http://www.alexa.com/topsites/global;#{i} "
19
+ doc = Nokogiri::HTML(open(url))
20
+
21
+ doc.css(".site-listing").each do |li|
22
+ begin
23
+ site_name = li.css(".desc-container .desc-paragraph a")[0].content
24
+ site_rank = li.css(".count")[0].content
25
+
26
+ puts "Resolving #{site_name} ..."
27
+ dmarc = begin
28
+ resolver.getresource(
29
+ "_dmarc.#{site_name.downcase}",
30
+ Resolv::DNS::Resource::IN::TXT
31
+ ).strings.join
32
+ rescue Resolv::ResolvError
33
+ end
34
+
35
+ csv << [site_rank, site_name, dmarc]
36
+ rescue => exception
37
+ warn exception.message
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,16 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |gem|
4
+ gem.name = "dkimverify"
5
+ gem.version = '0.0.1'
6
+ gem.authors = ["Jeremy B. Merrill"]
7
+ gem.license = "MIT"
8
+ gem.email = ["jeremybmerrill@gmail.com"]
9
+ gem.description = %q{ A pure-Ruby library for validating/verifying DKIM signatures. }
10
+ gem.summary = %q{ A pure-Ruby library for validating/verifying DKIM signatures. }
11
+ gem.homepage = "https://github.com/jeremybmerrill/dkimverify"
12
+ gem.files = `git ls-files`.split($/)
13
+ gem.require_paths = ["dkim-query"]
14
+ gem.add_dependency "mail", "2.6.4"
15
+ gem.add_dependency "parslet", "~> 1.6"
16
+ end