dkimverify 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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