spf-query 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.
- checksums.yaml +7 -0
- data/.gitignore +57 -0
- data/.rspec +1 -0
- data/.travis.yml +18 -0
- data/ChangeLog.md +6 -0
- data/Gemfile +15 -0
- data/LICENSE.txt +20 -0
- data/README.md +75 -0
- data/Rakefile +23 -0
- data/bin/spf-query +28 -0
- data/lib/resolv/dns/resource/in/spf.rb +9 -0
- data/lib/spf/query.rb +3 -0
- data/lib/spf/query/exceptions.rb +8 -0
- data/lib/spf/query/ip.rb +22 -0
- data/lib/spf/query/macro.rb +28 -0
- data/lib/spf/query/macro_string.rb +25 -0
- data/lib/spf/query/mechanism.rb +52 -0
- data/lib/spf/query/modifier.rb +24 -0
- data/lib/spf/query/parser.rb +281 -0
- data/lib/spf/query/query.rb +48 -0
- data/lib/spf/query/record.rb +204 -0
- data/lib/spf/query/version.rb +5 -0
- data/spec/mechanism_spec.rb +65 -0
- data/spec/parser_spec.rb +608 -0
- data/spec/query_spec.rb +38 -0
- data/spec/record_spec.rb +212 -0
- data/spec/spec_helper.rb +9 -0
- data/spf-query.gemspec +26 -0
- metadata +120 -0
data/spec/query_spec.rb
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'spf/query/query'
|
3
|
+
|
4
|
+
describe SPF::Query do
|
5
|
+
subject { described_class }
|
6
|
+
|
7
|
+
describe ".query" do
|
8
|
+
let(:domain) { 'gmail.com' }
|
9
|
+
|
10
|
+
it "should return the first SPF record" do
|
11
|
+
expect(subject.query(domain)).to be == %{v=spf1 redirect=_spf.google.com}
|
12
|
+
end
|
13
|
+
|
14
|
+
context "when _spf.domain.com exists" do
|
15
|
+
let(:domain) { 'google.com' }
|
16
|
+
|
17
|
+
it "should return the first SPF record" do
|
18
|
+
expect(subject.query(domain)).to be == %{v=spf1 include:_netblocks.google.com include:_netblocks2.google.com include:_netblocks3.google.com ~all}
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
context "when the domain has a SPF type record" do
|
23
|
+
let(:domain) { 'getlua.com' }
|
24
|
+
|
25
|
+
it "should prefer the SPF type record over other TXT records" do
|
26
|
+
expect(subject.query(domain)).to be == %{v=spf1 include:mail.zendesk.com include:servers.mcsv.net include:_spf.google.com include:sendgrid.net include:mktomail.com ~all}
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
context "when given an invalid domain" do
|
31
|
+
let(:domain) { 'foo.bar.com' }
|
32
|
+
|
33
|
+
it "should return nil" do
|
34
|
+
expect(subject.query(domain)).to be_nil
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
data/spec/record_spec.rb
ADDED
@@ -0,0 +1,212 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'spf/query/record'
|
3
|
+
|
4
|
+
describe SPF::Query::Record do
|
5
|
+
let(:spf) do
|
6
|
+
%{v=spf1 ip4:199.16.156.0/22 ip4:199.59.148.0/22 ip4:8.25.194.0/23 ip4:8.25.196.0/23 ip4:204.92.114.203 ip4:204.92.114.204/31 ip4:107.20.52.15 ip4:23.21.83.90 include:_spf.google.com include:_thirdparty.twitter.com all}
|
7
|
+
end
|
8
|
+
|
9
|
+
subject { described_class.parse(spf) }
|
10
|
+
|
11
|
+
describe "#initialize" do
|
12
|
+
let(:version) { :spf1 }
|
13
|
+
|
14
|
+
let(:ip4_rules) do
|
15
|
+
[
|
16
|
+
Mechanism.new(:ip4, value: IP.new('199.16.156.0', 22)),
|
17
|
+
Mechanism.new(:ip4, value: IP.new('199.59.148.0', 22)),
|
18
|
+
Mechanism.new(:ip4, value: IP.new('8.25.194.0', 23)),
|
19
|
+
Mechanism.new(:ip4, value: IP.new('8.25.196.0', 23)),
|
20
|
+
Mechanism.new(:ip4, value: IP.new('204.92.114.203')),
|
21
|
+
Mechanism.new(:ip4, value: IP.new('204.92.114.204', 31)),
|
22
|
+
Mechanism.new(:ip4, value: IP.new('107.20.52.15')),
|
23
|
+
Mechanism.new(:ip4, value: IP.new('23.21.83.90')),
|
24
|
+
]
|
25
|
+
end
|
26
|
+
|
27
|
+
let(:include_rules) do
|
28
|
+
[
|
29
|
+
Mechanism.new(:include, value: '_spf.google.com'),
|
30
|
+
Mechanism.new(:include, value: '_thirdparty.twitter.com'),
|
31
|
+
]
|
32
|
+
end
|
33
|
+
|
34
|
+
let(:all_rule) { Mechanism.new(:all) }
|
35
|
+
let(:rules) { ip4_rules + include_rules + [all_rule] }
|
36
|
+
|
37
|
+
subject { described_class.new(version,rules) }
|
38
|
+
|
39
|
+
it "should set version" do
|
40
|
+
expect(subject.version).to be version
|
41
|
+
end
|
42
|
+
|
43
|
+
it "should set rules" do
|
44
|
+
expect(subject.rules).to be rules
|
45
|
+
end
|
46
|
+
|
47
|
+
describe "#mechanisms" do
|
48
|
+
subject { super().mechanisms }
|
49
|
+
|
50
|
+
it "should contain every Mechanism object" do
|
51
|
+
expect(subject).to all(be_a(Mechanism))
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
describe "#modifiers" do
|
56
|
+
pending "need to add modifiers"
|
57
|
+
end
|
58
|
+
|
59
|
+
describe "#all" do
|
60
|
+
subject { super().all }
|
61
|
+
|
62
|
+
it "should find the last all mechanism" do
|
63
|
+
expect(subject).to be all_rule
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
describe "#include" do
|
68
|
+
subject { super().include }
|
69
|
+
|
70
|
+
it "should find all include: mechanisms" do
|
71
|
+
expect(subject).to be == include_rules
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
describe "#a" do
|
76
|
+
subject { super().a }
|
77
|
+
|
78
|
+
pending "need to add a: mechanisms" do
|
79
|
+
it "should find all a: mechanisms" do
|
80
|
+
expect(subject).to be == a
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
describe "#mx" do
|
86
|
+
subject { super().mx }
|
87
|
+
|
88
|
+
pending "need to add mx: mechanisms" do
|
89
|
+
it "should find all mx: mechanisms" do
|
90
|
+
expect(subject).to be == mx
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
describe "#ptr" do
|
96
|
+
subject { super().ptr }
|
97
|
+
|
98
|
+
pending "need to add ptr: mechanisms" do
|
99
|
+
it "should find all ptr: mechanisms" do
|
100
|
+
expect(subject).to be == ptr
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
describe "#ip4" do
|
106
|
+
subject { super().ip4 }
|
107
|
+
|
108
|
+
it "should find all ip4: mechanisms" do
|
109
|
+
expect(subject).to be == ip4_rules
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
describe "#ip6" do
|
114
|
+
subject { super().ptr }
|
115
|
+
|
116
|
+
pending "need to add ip6: mechanisms" do
|
117
|
+
it "should find all ip6: mechanisms" do
|
118
|
+
expect(subject).to be == ip6
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
describe "#exists" do
|
124
|
+
subject { super().exists }
|
125
|
+
|
126
|
+
pending "need to add exists: mechanisms" do
|
127
|
+
it "should find all exists: mechanisms" do
|
128
|
+
expect(subject).to be == exists
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
describe "#redirect" do
|
134
|
+
subject { super().exists }
|
135
|
+
|
136
|
+
pending "need to add a redirect: modifier" do
|
137
|
+
it "should find the first redirect: modifier" do
|
138
|
+
expect(subject).to be == redirect
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
describe "#exp" do
|
144
|
+
subject { super().exp }
|
145
|
+
|
146
|
+
pending "need to add a exp: modifier" do
|
147
|
+
it "should find the first exp: modifier" do
|
148
|
+
expect(subject).to be == exp
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
describe ".parse" do
|
155
|
+
context "when parsing a valid record" do
|
156
|
+
let(:spf) do
|
157
|
+
%{v=spf1 ip4:199.16.156.0/22 ip4:199.59.148.0/22 ip4:8.25.194.0/23 ip4:8.25.196.0/23 ip4:204.92.114.203 ip4:204.92.114.204/31 ip4:107.20.52.15 ip4:23.21.83.90 include:_spf.google.com include:_thirdparty.twitter.com all}
|
158
|
+
end
|
159
|
+
|
160
|
+
subject { described_class.parse(spf) }
|
161
|
+
|
162
|
+
it "should return a Record" do
|
163
|
+
expect(subject).to be_kind_of(Record)
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
context "when parsing an invalid record" do
|
168
|
+
let(:spf) { %{v=foo} }
|
169
|
+
|
170
|
+
it "should raise an InvalidRecord exception" do
|
171
|
+
expect {
|
172
|
+
described_class.parse(spf)
|
173
|
+
}.to raise_error(InvalidRecord)
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
describe ".query" do
|
179
|
+
let(:domain) { 'twitter.com' }
|
180
|
+
|
181
|
+
subject { described_class.query(domain) }
|
182
|
+
|
183
|
+
it "should return a Record" do
|
184
|
+
expect(subject).to be_kind_of(Record)
|
185
|
+
end
|
186
|
+
|
187
|
+
context "when given a domain without SPF" do
|
188
|
+
let(:domain) { 'geocities.com' }
|
189
|
+
|
190
|
+
it "should return nil" do
|
191
|
+
expect(subject).to be nil
|
192
|
+
end
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
describe "#each" do
|
197
|
+
it "should enumerate over ever record" do
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
describe "#to_s" do
|
202
|
+
it "should convert the record back into SPF" do
|
203
|
+
expect(subject.to_s).to be == spf
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
describe "#inspect" do
|
208
|
+
it "should display the raw SPF" do
|
209
|
+
expect(subject.inspect).to be == "#<#{described_class}: #{spf}>"
|
210
|
+
end
|
211
|
+
end
|
212
|
+
end
|
data/spec/spec_helper.rb
ADDED
data/spf-query.gemspec
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'spf/query/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |gem|
|
7
|
+
gem.name = "spf-query"
|
8
|
+
gem.version = SPF::Query::VERSION
|
9
|
+
gem.authors = ["nicktitle"]
|
10
|
+
gem.email = ["nick.esposito@trailofbits.com"]
|
11
|
+
gem.summary = %q{SPF Retriever and Parser}
|
12
|
+
gem.description = %q{Search and retrieve SPF records for any number of hosts}
|
13
|
+
gem.homepage = "https://github.com/trailofbits/spf-query#readme"
|
14
|
+
gem.license = "MIT"
|
15
|
+
|
16
|
+
gem.files = `git ls-files -z`.split("\x0")
|
17
|
+
gem.executables = ['spf-query']
|
18
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
19
|
+
gem.require_paths = ["lib"]
|
20
|
+
gem.required_ruby_version = '>= 1.9.1'
|
21
|
+
|
22
|
+
gem.add_dependency "parslet", "~> 1.0"
|
23
|
+
|
24
|
+
gem.add_development_dependency "bundler", "~> 1.6"
|
25
|
+
gem.add_development_dependency "rake", "~> 10.0"
|
26
|
+
end
|
metadata
ADDED
@@ -0,0 +1,120 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: spf-query
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- nicktitle
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-07-01 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: parslet
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: bundler
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.6'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.6'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rake
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '10.0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '10.0'
|
55
|
+
description: Search and retrieve SPF records for any number of hosts
|
56
|
+
email:
|
57
|
+
- nick.esposito@trailofbits.com
|
58
|
+
executables:
|
59
|
+
- spf-query
|
60
|
+
extensions: []
|
61
|
+
extra_rdoc_files: []
|
62
|
+
files:
|
63
|
+
- ".gitignore"
|
64
|
+
- ".rspec"
|
65
|
+
- ".travis.yml"
|
66
|
+
- ChangeLog.md
|
67
|
+
- Gemfile
|
68
|
+
- LICENSE.txt
|
69
|
+
- README.md
|
70
|
+
- Rakefile
|
71
|
+
- bin/spf-query
|
72
|
+
- lib/resolv/dns/resource/in/spf.rb
|
73
|
+
- lib/spf/query.rb
|
74
|
+
- lib/spf/query/exceptions.rb
|
75
|
+
- lib/spf/query/ip.rb
|
76
|
+
- lib/spf/query/macro.rb
|
77
|
+
- lib/spf/query/macro_string.rb
|
78
|
+
- lib/spf/query/mechanism.rb
|
79
|
+
- lib/spf/query/modifier.rb
|
80
|
+
- lib/spf/query/parser.rb
|
81
|
+
- lib/spf/query/query.rb
|
82
|
+
- lib/spf/query/record.rb
|
83
|
+
- lib/spf/query/version.rb
|
84
|
+
- spec/mechanism_spec.rb
|
85
|
+
- spec/parser_spec.rb
|
86
|
+
- spec/query_spec.rb
|
87
|
+
- spec/record_spec.rb
|
88
|
+
- spec/spec_helper.rb
|
89
|
+
- spf-query.gemspec
|
90
|
+
homepage: https://github.com/trailofbits/spf-query#readme
|
91
|
+
licenses:
|
92
|
+
- MIT
|
93
|
+
metadata: {}
|
94
|
+
post_install_message:
|
95
|
+
rdoc_options: []
|
96
|
+
require_paths:
|
97
|
+
- lib
|
98
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
99
|
+
requirements:
|
100
|
+
- - ">="
|
101
|
+
- !ruby/object:Gem::Version
|
102
|
+
version: 1.9.1
|
103
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
104
|
+
requirements:
|
105
|
+
- - ">="
|
106
|
+
- !ruby/object:Gem::Version
|
107
|
+
version: '0'
|
108
|
+
requirements: []
|
109
|
+
rubyforge_project:
|
110
|
+
rubygems_version: 2.4.7
|
111
|
+
signing_key:
|
112
|
+
specification_version: 4
|
113
|
+
summary: SPF Retriever and Parser
|
114
|
+
test_files:
|
115
|
+
- spec/mechanism_spec.rb
|
116
|
+
- spec/parser_spec.rb
|
117
|
+
- spec/query_spec.rb
|
118
|
+
- spec/record_spec.rb
|
119
|
+
- spec/spec_helper.rb
|
120
|
+
has_rdoc:
|