spf 0.0.47 → 0.0.52
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 +5 -13
- data/Gemfile +2 -2
- data/Gemfile.lock +45 -32
- data/README.rdoc +1 -1
- data/lib/spf/error.rb +4 -4
- data/lib/spf/eval.rb +7 -1
- data/lib/spf/macro_string.rb +123 -6
- data/lib/spf/model.rb +33 -21
- data/lib/spf/version.rb +1 -1
- data/spf.gemspec +2 -2
- metadata +23 -23
checksums.yaml
CHANGED
@@ -1,15 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
|
5
|
-
data.tar.gz: !binary |-
|
6
|
-
MmQ4NGVkMTE2MjdkZDA4NzE1ZGJjY2MzZTljMWE1MGRjYWU5N2FhMQ==
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: b17ea1cbb732cbec18d856f16a3e107ccb7fb994
|
4
|
+
data.tar.gz: e160f6ad54fb977fca0fa9d2a9040c573c680ce3
|
7
5
|
SHA512:
|
8
|
-
metadata.gz:
|
9
|
-
|
10
|
-
M2M1ZGFmZDkyOTQ5NWJlY2QxYmY1NDdlZDIyZmY1Y2UyOWZlYmNmNDBkOWQ2
|
11
|
-
OTE1OTY5OTlhOTQ5MjhiZDVkMjliZWQ1MzY4NzYwMjgzZjVjM2I=
|
12
|
-
data.tar.gz: !binary |-
|
13
|
-
MmE5ZDY4OGYzY2IzZWRiMjI5NDQ3YThlOWM5MGViZGNiZmViM2U5YjBiMTVj
|
14
|
-
YjkyZGVhZTI0MGMzMDMzY2NhZTBmZjNhYWNjOWE4MTJlMzU5YTk0N2MwMjBh
|
15
|
-
YmMzYzM2N2I2MWIxNTY2MGFhMmM1NDg0ODE3NThjNDkzZjQyZmU=
|
6
|
+
metadata.gz: dc7615918b321907dd7a434a53e36b313e44a07868fb2f64c9a66f0ac2a11b3b6c7d630edf508dfbfb5bf7b93afaac2bb966e2a665ff8f1a8b2fb339feb090f8
|
7
|
+
data.tar.gz: bacbe5b5077843edd490606fa853fcaca6a66eee2a03d251b2f3bbc126e94d8c1ce799fe340a600eb27347765ecc0fb145273e266494581dd6dc17c8476a1698
|
data/Gemfile
CHANGED
@@ -9,8 +9,8 @@ gem "ruby-ip", "~> 0.9.1"
|
|
9
9
|
# Include everything needed to run rake, tests, features, etc.
|
10
10
|
group :development do
|
11
11
|
gem "rspec", "~> 2.9"
|
12
|
-
gem "rdoc", "~> 3"
|
12
|
+
gem "rdoc", "~> 4.3"
|
13
13
|
gem "bundler", "~> 1.2"
|
14
|
-
gem "jeweler", "~>
|
14
|
+
gem "jeweler", "~> 2.0"
|
15
15
|
gem "simplecov", :require => false, :group => :test
|
16
16
|
end
|
data/Gemfile.lock
CHANGED
@@ -1,47 +1,55 @@
|
|
1
1
|
GEM
|
2
2
|
remote: http://rubygems.org/
|
3
3
|
specs:
|
4
|
-
addressable (2.
|
5
|
-
builder (3.2.
|
4
|
+
addressable (2.4.0)
|
5
|
+
builder (3.2.4)
|
6
|
+
descendants_tracker (0.0.4)
|
7
|
+
thread_safe (~> 0.3, >= 0.3.1)
|
6
8
|
diff-lcs (1.2.5)
|
7
9
|
docile (1.1.5)
|
8
|
-
faraday (0.
|
9
|
-
multipart-post (
|
10
|
-
git (1.
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
10
|
+
faraday (0.9.2)
|
11
|
+
multipart-post (>= 1.2, < 3)
|
12
|
+
git (1.7.0)
|
13
|
+
rchardet (~> 1.8)
|
14
|
+
github_api (0.16.0)
|
15
|
+
addressable (~> 2.4.0)
|
16
|
+
descendants_tracker (~> 0.0.4)
|
17
|
+
faraday (~> 0.8, < 0.10)
|
18
|
+
hashie (>= 3.4)
|
19
|
+
mime-types (>= 1.16, < 3.0)
|
20
|
+
oauth2 (~> 1.0)
|
21
|
+
hashie (4.1.0)
|
22
|
+
highline (2.0.3)
|
23
|
+
jeweler (2.3.9)
|
21
24
|
builder
|
22
|
-
bundler
|
25
|
+
bundler
|
23
26
|
git (>= 1.2.5)
|
24
|
-
github_api (
|
27
|
+
github_api (~> 0.16.0)
|
25
28
|
highline (>= 1.6.15)
|
26
|
-
nokogiri (
|
29
|
+
nokogiri (>= 1.5.10)
|
30
|
+
psych
|
27
31
|
rake
|
28
32
|
rdoc
|
29
|
-
|
30
|
-
jwt (
|
33
|
+
semver2
|
34
|
+
jwt (2.2.1)
|
35
|
+
mime-types (2.99.3)
|
36
|
+
mini_portile2 (2.4.0)
|
31
37
|
multi_json (1.10.1)
|
32
|
-
multi_xml (0.
|
33
|
-
multipart-post (1.
|
34
|
-
nokogiri (1.
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
+
multi_xml (0.6.0)
|
39
|
+
multipart-post (2.1.1)
|
40
|
+
nokogiri (1.10.10)
|
41
|
+
mini_portile2 (~> 2.4.0)
|
42
|
+
oauth2 (1.4.4)
|
43
|
+
faraday (>= 0.8, < 2.0)
|
44
|
+
jwt (>= 1.0, < 3.0)
|
38
45
|
multi_json (~> 1.3)
|
39
46
|
multi_xml (~> 0.5)
|
40
|
-
rack (
|
41
|
-
|
47
|
+
rack (>= 1.2, < 3)
|
48
|
+
psych (3.1.0)
|
49
|
+
rack (2.2.3)
|
42
50
|
rake (10.4.2)
|
43
|
-
|
44
|
-
|
51
|
+
rchardet (1.8.0)
|
52
|
+
rdoc (4.3.0)
|
45
53
|
rspec (2.99.0)
|
46
54
|
rspec-core (~> 2.99.0)
|
47
55
|
rspec-expectations (~> 2.99.0)
|
@@ -51,19 +59,24 @@ GEM
|
|
51
59
|
diff-lcs (>= 1.1.3, < 2.0)
|
52
60
|
rspec-mocks (2.99.3)
|
53
61
|
ruby-ip (0.9.3)
|
62
|
+
semver2 (3.4.2)
|
54
63
|
simplecov (0.9.2)
|
55
64
|
docile (~> 1.1.0)
|
56
65
|
multi_json (~> 1.0)
|
57
66
|
simplecov-html (~> 0.9.0)
|
58
67
|
simplecov-html (0.9.0)
|
68
|
+
thread_safe (0.3.6)
|
59
69
|
|
60
70
|
PLATFORMS
|
61
71
|
ruby
|
62
72
|
|
63
73
|
DEPENDENCIES
|
64
74
|
bundler (~> 1.2)
|
65
|
-
jeweler (~>
|
66
|
-
rdoc (~> 3)
|
75
|
+
jeweler (~> 2.0)
|
76
|
+
rdoc (~> 4.3)
|
67
77
|
rspec (~> 2.9)
|
68
78
|
ruby-ip (~> 0.9.1)
|
69
79
|
simplecov
|
80
|
+
|
81
|
+
BUNDLED WITH
|
82
|
+
1.16.1
|
data/README.rdoc
CHANGED
@@ -29,7 +29,7 @@ Note: This gem is currently very early in its lifecycle. The API is *not* guara
|
|
29
29
|
|
30
30
|
== Copyright
|
31
31
|
|
32
|
-
Copyright
|
32
|
+
Copyright 2016 Agari Data, Inc.
|
33
33
|
|
34
34
|
Licensed under the Apache License, Version 2.0 (the "License");
|
35
35
|
you may not use this software except in compliance with the License.
|
data/lib/spf/error.rb
CHANGED
@@ -50,15 +50,15 @@ module SPF
|
|
50
50
|
class InvalidModError < SyntaxError; end # Invalid modifier
|
51
51
|
class InvalidTermError < SyntaxError; end # Invalid term
|
52
52
|
class JunkInTermError < SyntaxError; end # Junk encountered in term
|
53
|
-
class
|
53
|
+
class DuplicateGlobalModError < InvalidModError; end # Duplicate global modifier
|
54
54
|
class InvalidMechError < InvalidTermError; end # Invalid mechanism
|
55
55
|
class InvalidMechQualifierError < InvalidMechError; end # Invalid mechanism qualifier
|
56
56
|
class InvalidMechCIDRError < InvalidMechError; end # Invalid CIDR netblock in mech
|
57
57
|
class TermDomainSpecExpectedError < SyntaxError; end # Missing required <domain-spec> in term
|
58
58
|
class TermIPv4AddressExpectedError < SyntaxError; end # Missing required <ip4-network> in term
|
59
|
-
class
|
60
|
-
class
|
61
|
-
class
|
59
|
+
class TermIPv4PrefixLengthExpectedError < SyntaxError; end # Missing required <ip4-cidr-length> in term
|
60
|
+
class TermIPv6AddressExpectedError < SyntaxError; end # Missing required <ip6-network> in term
|
61
|
+
class TermIPv6PrefixLengthExpectedError < SyntaxError; end # Missing required <ip6-cidr-length> in term
|
62
62
|
class InvalidMacroStringError < SyntaxError; end # Invalid macro string
|
63
63
|
class InvalidMacroError < InvalidMacroStringError
|
64
64
|
end # Invalid macro
|
data/lib/spf/eval.rb
CHANGED
@@ -275,7 +275,13 @@ class SPF::Server
|
|
275
275
|
versions.each do |version|
|
276
276
|
klass = RECORD_CLASSES_BY_VERSION[version]
|
277
277
|
begin
|
278
|
-
|
278
|
+
options = {:raise_exceptions => @raise_exceptions}
|
279
|
+
# A MacroString object for domain indicates this is a nested record.
|
280
|
+
# Storing the domain.text maintains an association to the include domain.
|
281
|
+
if domain.class == SPF::MacroString
|
282
|
+
options[:record_domain] = domain.text
|
283
|
+
end
|
284
|
+
record = klass.new_from_string(text, options)
|
279
285
|
rescue SPF::InvalidRecordVersionError => error
|
280
286
|
if text =~ /#{LOOSE_SPF_MATCH_PATTERN}/
|
281
287
|
possible_matches << text
|
data/lib/spf/macro_string.rb
CHANGED
@@ -1,5 +1,8 @@
|
|
1
1
|
# encoding: ASCII-8BIT
|
2
2
|
require 'spf/util'
|
3
|
+
require 'spf/error'
|
4
|
+
require 'uri'
|
5
|
+
|
3
6
|
|
4
7
|
module SPF
|
5
8
|
class MacroString
|
@@ -22,8 +25,8 @@ module SPF
|
|
22
25
|
or raise ArgumentError, "Missing required 'text' option"
|
23
26
|
@server = options[:server]
|
24
27
|
@request = options[:request]
|
28
|
+
@is_explanation = options[:is_explanation]
|
25
29
|
@expanded = nil
|
26
|
-
self.expand
|
27
30
|
end
|
28
31
|
|
29
32
|
attr_reader :text, :server, :request
|
@@ -43,9 +46,124 @@ module SPF
|
|
43
46
|
return (@expanded = @text) unless @text =~ /%/
|
44
47
|
# Short-circuit expansion if text has no '%' characters.
|
45
48
|
|
49
|
+
server, request = context ? context : [@server, @request]
|
50
|
+
|
51
|
+
valid_context(true, server, request)
|
52
|
+
|
46
53
|
expanded = ''
|
47
|
-
|
48
|
-
|
54
|
+
|
55
|
+
text = @text
|
56
|
+
|
57
|
+
while m = text.match(/ (.*?) %(.) /x) do
|
58
|
+
expanded += m[1]
|
59
|
+
key = m[2]
|
60
|
+
|
61
|
+
if (key == '{')
|
62
|
+
if m2 = m.post_match.match(/ (\w|_\p{Alpha}+) ([0-9]+)? (r)? ([.\-+,\/_=])? } /x)
|
63
|
+
char, rh_parts, reverse, delimiter = m2.captures
|
64
|
+
|
65
|
+
# Upper-case macro chars trigger URL-escaping AKA percent-encoding
|
66
|
+
# (RFC 4408, 8.1/26):
|
67
|
+
do_percent_encode = char =~ /\p{Upper}/
|
68
|
+
char.downcase!
|
69
|
+
|
70
|
+
if char == 's' # RFC 4408, 8.1/19
|
71
|
+
value = request.identity
|
72
|
+
elsif char == 'l' # RFC 4408, 8.1/19
|
73
|
+
value = request.localpart
|
74
|
+
elsif char == 'o' # RFC 4408, 8.1/19
|
75
|
+
value = request.domain
|
76
|
+
elsif char == 'd' # RFC 4408, 8.1/6/4
|
77
|
+
value = request.authority_domain
|
78
|
+
elsif char == 'i' # RFC 4408, 8.1/20, 8.1/21
|
79
|
+
ip_address = request.ip_address
|
80
|
+
ip_address = SPF::Util.ipv6_address_to_ipv4(ip_address) if SPF::Util.ipv6_address_is_ipv4_mapped(ip_address)
|
81
|
+
if IP::V4 === ip_address
|
82
|
+
value = ip_address.to_addr
|
83
|
+
elsif IP::V6 === ip_address
|
84
|
+
value = ip_address.to_hex.upcase.split('').join('.')
|
85
|
+
else
|
86
|
+
server.throw_result(:permerror, request, "Unexpected IP address version in request")
|
87
|
+
end
|
88
|
+
elsif char == 'p' # RFC 4408, 8.1/22
|
89
|
+
# According to RFC 7208 the "p" macro letter should not be used (or even published).
|
90
|
+
# Here it is left unexpanded and transformers and delimiters are not applied.
|
91
|
+
value = '%{' + m2.to_s
|
92
|
+
rh_parts = nil
|
93
|
+
reverse = nil
|
94
|
+
elsif char == 'v' # RFC 4408, 8.1/6/7
|
95
|
+
if IP::V4 === request.ip_address
|
96
|
+
value = 'in-addr'
|
97
|
+
elsif IP::V6 === request.ip_address
|
98
|
+
value = 'ip6'
|
99
|
+
else
|
100
|
+
# Unexpected IP address version.
|
101
|
+
server.throw_result(:permerror, request, "Unexpected IP address version in request")
|
102
|
+
end
|
103
|
+
elsif char == 'h' # RFC 4408, 8.1/6/8
|
104
|
+
value = request.helo_identity || 'unknown'
|
105
|
+
elsif char == 'c' # RFC 4408, 8.1/20, 8.1/21
|
106
|
+
raise SPF::InvalidMacroStringError.new("Illegal 'c' macro in non-explanation macro string '#{@text}'") unless @is_explanation
|
107
|
+
ip_address = request.ip_address
|
108
|
+
value = SPF::Util::ip_address_to_string(ip_address)
|
109
|
+
elsif char == 'r' # RFC 4408, 8.1/23
|
110
|
+
value = server.hostname || 'unknown'
|
111
|
+
elsif char == 't'
|
112
|
+
raise SPF::InvalidMacroStringError.new("Illegal 't' macro in non-explanation macro string '#{@text}'") unless @is_explanation
|
113
|
+
value = Time.now.to_i.to_s
|
114
|
+
elsif char == '_scope'
|
115
|
+
# Scope pseudo macro for internal use only!
|
116
|
+
value = request.scope.to_s
|
117
|
+
else
|
118
|
+
# Unknown macro character.
|
119
|
+
raise SPF::InvalidMacroStringError.new("Invalid macro character #{char} in macro string '#{@text}'")
|
120
|
+
end
|
121
|
+
|
122
|
+
if rh_parts || reverse
|
123
|
+
delimiter ||= self.class.default_split_delimiters
|
124
|
+
list = value.split(delimiter)
|
125
|
+
list.reverse! if reverse
|
126
|
+
# Extract desired parts:
|
127
|
+
if rh_parts && rh_parts.to_i > 0
|
128
|
+
list = list.last(rh_parts.to_i)
|
129
|
+
end
|
130
|
+
if rh_parts && rh_parts.to_i == 0
|
131
|
+
raise SPF::InvalidMacroStringError.new("Illegal selection of 0 (zero) right-hand parts in macro string '#{@text}'")
|
132
|
+
end
|
133
|
+
value = list.join(self.class.default_join_delimiter)
|
134
|
+
end
|
135
|
+
|
136
|
+
if do_percent_encode
|
137
|
+
unsafe = Regexp.new('^' + self.class.uri_unreserved_chars)
|
138
|
+
value = URI.escape(value, unsafe)
|
139
|
+
end
|
140
|
+
|
141
|
+
expanded += value
|
142
|
+
|
143
|
+
text = m2.post_match
|
144
|
+
else
|
145
|
+
# Invalid macro expression.
|
146
|
+
raise SPF::InvalidMacroStringError.new("Invalid macro expression in macro string '#{@text}'")
|
147
|
+
end
|
148
|
+
elsif key == '-'
|
149
|
+
expanded += '-'
|
150
|
+
text = m.post_match
|
151
|
+
elsif key == '_'
|
152
|
+
expanded += ' '
|
153
|
+
text = m.post_match
|
154
|
+
elsif key == '%'
|
155
|
+
expanded += '%'
|
156
|
+
text = m.post_match
|
157
|
+
else
|
158
|
+
# Invalid macro expression.
|
159
|
+
pos = m.offset(2).first
|
160
|
+
raise SPF::InvalidMacroStringError.new("Invalid macro expression at pos #{pos} in macro string '#{@text}'")
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
expanded += text # Append remaining unmatched characters.
|
165
|
+
|
166
|
+
context ? expanded : @expanded = expanded
|
49
167
|
end
|
50
168
|
|
51
169
|
def to_s
|
@@ -58,16 +176,15 @@ module SPF
|
|
58
176
|
|
59
177
|
def valid_context(required, server = self.server, request = self.request)
|
60
178
|
if not SPF::Server === server
|
61
|
-
raise
|
179
|
+
raise SPF::MacroExpansionCtxRequiredError.new('SPF server object required') if required
|
62
180
|
return false
|
63
181
|
end
|
64
182
|
if not SPF::Request === request
|
65
|
-
raise
|
183
|
+
raise SPF::MacroExpansionCtxRequiredError.new('SPF request object required') if required
|
66
184
|
return false
|
67
185
|
end
|
68
186
|
return true
|
69
187
|
end
|
70
|
-
|
71
188
|
end
|
72
189
|
end
|
73
190
|
|
data/lib/spf/model.rb
CHANGED
@@ -86,7 +86,7 @@ class SPF::Term
|
|
86
86
|
::
|
87
87
|
"
|
88
88
|
|
89
|
-
attr_reader :errors, :ip_netblocks, :ip_address, :ip_network, :ipv4_prefix_length, :ipv6_prefix_length, :domain_spec, :raw_params
|
89
|
+
attr_reader :errors, :ip_netblocks, :ip_address, :ip_network, :ipv4_prefix_length, :ipv6_prefix_length, :domain_spec, :raw_params, :record_domain
|
90
90
|
|
91
91
|
def initialize(options = {})
|
92
92
|
@ip_address = nil
|
@@ -97,6 +97,7 @@ class SPF::Term
|
|
97
97
|
@errors = []
|
98
98
|
@ip_netblocks = []
|
99
99
|
@text = options[:text]
|
100
|
+
@record_domain = options[:record_domain]
|
100
101
|
@raise_exceptions = options.has_key?(:raise_exceptions) ? options[:raise_exceptions] : true
|
101
102
|
end
|
102
103
|
|
@@ -117,6 +118,8 @@ class SPF::Term
|
|
117
118
|
domain_spec = $1
|
118
119
|
domain_spec.sub!(/^(.*?)\.?$/, $1)
|
119
120
|
@domain_spec = SPF::MacroString.new({:text => domain_spec})
|
121
|
+
elsif record_domain
|
122
|
+
@domain_spec = SPF::MacroString.new({:text => record_domain})
|
120
123
|
elsif required
|
121
124
|
error(SPF::TermDomainSpecExpectedError.new(
|
122
125
|
"Missing required domain-spec in '#{@text}'"))
|
@@ -139,13 +142,13 @@ class SPF::Term
|
|
139
142
|
if @parse_text.sub!(/^\/(\d+)/, '')
|
140
143
|
bits = $1.to_i
|
141
144
|
unless bits and bits >= 0 and bits <= 32 and $1 !~ /^0./
|
142
|
-
error(SPF::
|
145
|
+
error(SPF::TermIPv4PrefixLengthExpectedError.new(
|
143
146
|
"Invalid IPv4 prefix length encountered in '#{@text}'"))
|
144
147
|
return
|
145
148
|
end
|
146
149
|
@ipv4_prefix_length = bits
|
147
150
|
elsif required
|
148
|
-
error(SPF::
|
151
|
+
error(SPF::TermIPv4PrefixLengthExpectedError.new(
|
149
152
|
"Missing required IPv4 prefix length in '#{@text}"))
|
150
153
|
return
|
151
154
|
else
|
@@ -168,7 +171,7 @@ class SPF::Term
|
|
168
171
|
if @parse_text.sub!(/(#{IPV6_ADDRESS_PATTERN})(?=\/|$)/x, '')
|
169
172
|
@ip_address = $1
|
170
173
|
elsif required
|
171
|
-
error(SPF::
|
174
|
+
error(SPF::TermIPv6AddressExpectedError.new(
|
172
175
|
"Missing or invalid required IPv6 address in '#{@text}'"))
|
173
176
|
end
|
174
177
|
@ip_address = @parse_text.dup unless @ip_address
|
@@ -184,7 +187,7 @@ class SPF::Term
|
|
184
187
|
end
|
185
188
|
@ipv6_prefix_length = bits
|
186
189
|
elsif required
|
187
|
-
error(SPF::
|
190
|
+
error(SPF::TermIPv6PrefixLengthExpectedError.new(
|
188
191
|
"Missing required IPv6 prefix length in '#{@text}'"))
|
189
192
|
return
|
190
193
|
else
|
@@ -214,7 +217,7 @@ class SPF::Term
|
|
214
217
|
|
215
218
|
def domain(server, request)
|
216
219
|
if self.instance_variable_defined?(:@domain_spec) and @domain_spec
|
217
|
-
return @domain_spec
|
220
|
+
return SPF::MacroString.new({:server => server, :request => request, :text => @domain_spec.text})
|
218
221
|
end
|
219
222
|
return request.authority_domain
|
220
223
|
end
|
@@ -446,13 +449,13 @@ class SPF::Mech < SPF::Term
|
|
446
449
|
server.count_dns_interactive_term(request)
|
447
450
|
|
448
451
|
domain = self.domain(server, request)
|
449
|
-
|
450
|
-
|
451
|
-
|
452
|
-
|
452
|
+
begin
|
453
|
+
rrs = server.dns_lookup(domain, 'A')
|
454
|
+
return true if rrs.any?
|
455
|
+
rescue SPF::DNSNXDomainError => e
|
456
|
+
server.count_void_dns_lookup(request)
|
457
|
+
return false
|
453
458
|
end
|
454
|
-
|
455
|
-
return false
|
456
459
|
end
|
457
460
|
|
458
461
|
end
|
@@ -465,9 +468,11 @@ class SPF::Mech < SPF::Term
|
|
465
468
|
self.parse_ipv4_network(required)
|
466
469
|
if IP === @ip_network
|
467
470
|
@ip_netblocks << @ip_network
|
468
|
-
@
|
469
|
-
|
470
|
-
|
471
|
+
if @ip_network.respond_to?(:offset) && @ip_network.offset != 0
|
472
|
+
@errors << SPF::InvalidMechCIDRError.new(
|
473
|
+
"Invalid CIDR netblock - bits in host portion of address of #{@ip_network}"
|
474
|
+
)
|
475
|
+
end
|
471
476
|
end
|
472
477
|
end
|
473
478
|
|
@@ -498,9 +503,11 @@ class SPF::Mech < SPF::Term
|
|
498
503
|
def parse_params(required = true)
|
499
504
|
self.parse_ipv6_network(required)
|
500
505
|
@ip_netblocks << @ip_network if IP === @ip_network
|
501
|
-
@
|
502
|
-
|
503
|
-
|
506
|
+
if @ip_network.respond_to?(:offset) && @ip_network.offset != 0
|
507
|
+
@errors << SPF::InvalidMechCIDRError.new(
|
508
|
+
"Invalid CIDR netblock - bits in host portion of address of #{@ip_network}"
|
509
|
+
)
|
510
|
+
end
|
504
511
|
end
|
505
512
|
|
506
513
|
def params
|
@@ -571,7 +578,7 @@ class SPF::Mech < SPF::Term
|
|
571
578
|
return nil unless server and request
|
572
579
|
authority_domain = self.domain(server, request)
|
573
580
|
sub_request = request.new_sub_request({:authority_domain => authority_domain})
|
574
|
-
return @nested_record = server.
|
581
|
+
return @nested_record = server.select_record(sub_request, loose_match)
|
575
582
|
end
|
576
583
|
|
577
584
|
end
|
@@ -840,6 +847,7 @@ class SPF::Record
|
|
840
847
|
@global_mods ||= {}
|
841
848
|
@errors = []
|
842
849
|
@ip_netblocks = []
|
850
|
+
@record_domain = options[:record_domain]
|
843
851
|
@raise_exceptions = options.has_key?(:raise_exceptions) ? options[:raise_exceptions] : true
|
844
852
|
end
|
845
853
|
|
@@ -910,7 +918,11 @@ class SPF::Record
|
|
910
918
|
error(exception)
|
911
919
|
mech_class = SPF::Mech
|
912
920
|
end
|
913
|
-
|
921
|
+
options = {:raise_exceptions => @raise_exceptions}
|
922
|
+
if instance_variable_defined?("@record_domain")
|
923
|
+
options[:record_domain] = @record_domain
|
924
|
+
end
|
925
|
+
term = mech = mech_class.new_from_string(mech_text, options)
|
914
926
|
term.errors << exception if exception
|
915
927
|
@ip_netblocks << mech.ip_netblocks if mech.ip_netblocks
|
916
928
|
@terms << mech
|
@@ -937,7 +949,7 @@ class SPF::Record
|
|
937
949
|
if SPF::GlobalMod === mod
|
938
950
|
# Global modifier.
|
939
951
|
if @global_mods[mod_name]
|
940
|
-
raise SPF::
|
952
|
+
raise SPF::DuplicateGlobalModError.new("Duplicate global modifier '#{mod_name}' encountered")
|
941
953
|
end
|
942
954
|
@global_mods[mod_name] = mod
|
943
955
|
elsif SPF::PositionalMod === mod
|
data/lib/spf/version.rb
CHANGED
data/spf.gemspec
CHANGED
@@ -2,11 +2,11 @@
|
|
2
2
|
# DO NOT EDIT THIS FILE DIRECTLY
|
3
3
|
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
4
|
# -*- encoding: utf-8 -*-
|
5
|
-
# stub: spf 0.0.
|
5
|
+
# stub: spf 0.0.48 ruby lib
|
6
6
|
|
7
7
|
Gem::Specification.new do |s|
|
8
8
|
s.name = "spf"
|
9
|
-
s.version = "0.0.
|
9
|
+
s.version = "0.0.52"
|
10
10
|
|
11
11
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
12
12
|
s.require_paths = ["lib"]
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: spf
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.52
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andrew Flury
|
8
8
|
- Julian Mehnle
|
9
9
|
- Jacob Rideout
|
10
|
-
autorequire:
|
10
|
+
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
13
|
date: 2015-04-29 00:00:00.000000000 Z
|
@@ -16,74 +16,75 @@ dependencies:
|
|
16
16
|
name: ruby-ip
|
17
17
|
requirement: !ruby/object:Gem::Requirement
|
18
18
|
requirements:
|
19
|
-
- - ~>
|
19
|
+
- - "~>"
|
20
20
|
- !ruby/object:Gem::Version
|
21
21
|
version: 0.9.1
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
24
|
version_requirements: !ruby/object:Gem::Requirement
|
25
25
|
requirements:
|
26
|
-
- - ~>
|
26
|
+
- - "~>"
|
27
27
|
- !ruby/object:Gem::Version
|
28
28
|
version: 0.9.1
|
29
29
|
- !ruby/object:Gem::Dependency
|
30
30
|
name: rspec
|
31
31
|
requirement: !ruby/object:Gem::Requirement
|
32
32
|
requirements:
|
33
|
-
- - ~>
|
33
|
+
- - "~>"
|
34
34
|
- !ruby/object:Gem::Version
|
35
35
|
version: '2.9'
|
36
36
|
type: :development
|
37
37
|
prerelease: false
|
38
38
|
version_requirements: !ruby/object:Gem::Requirement
|
39
39
|
requirements:
|
40
|
-
- - ~>
|
40
|
+
- - "~>"
|
41
41
|
- !ruby/object:Gem::Version
|
42
42
|
version: '2.9'
|
43
43
|
- !ruby/object:Gem::Dependency
|
44
44
|
name: rdoc
|
45
45
|
requirement: !ruby/object:Gem::Requirement
|
46
46
|
requirements:
|
47
|
-
- - ~>
|
47
|
+
- - "~>"
|
48
48
|
- !ruby/object:Gem::Version
|
49
49
|
version: '3'
|
50
50
|
type: :development
|
51
51
|
prerelease: false
|
52
52
|
version_requirements: !ruby/object:Gem::Requirement
|
53
53
|
requirements:
|
54
|
-
- - ~>
|
54
|
+
- - "~>"
|
55
55
|
- !ruby/object:Gem::Version
|
56
56
|
version: '3'
|
57
57
|
- !ruby/object:Gem::Dependency
|
58
58
|
name: bundler
|
59
59
|
requirement: !ruby/object:Gem::Requirement
|
60
60
|
requirements:
|
61
|
-
- - ~>
|
61
|
+
- - "~>"
|
62
62
|
- !ruby/object:Gem::Version
|
63
63
|
version: '1.2'
|
64
64
|
type: :development
|
65
65
|
prerelease: false
|
66
66
|
version_requirements: !ruby/object:Gem::Requirement
|
67
67
|
requirements:
|
68
|
-
- - ~>
|
68
|
+
- - "~>"
|
69
69
|
- !ruby/object:Gem::Version
|
70
70
|
version: '1.2'
|
71
71
|
- !ruby/object:Gem::Dependency
|
72
72
|
name: jeweler
|
73
73
|
requirement: !ruby/object:Gem::Requirement
|
74
74
|
requirements:
|
75
|
-
- - ~>
|
75
|
+
- - "~>"
|
76
76
|
- !ruby/object:Gem::Version
|
77
77
|
version: '1.8'
|
78
78
|
type: :development
|
79
79
|
prerelease: false
|
80
80
|
version_requirements: !ruby/object:Gem::Requirement
|
81
81
|
requirements:
|
82
|
-
- - ~>
|
82
|
+
- - "~>"
|
83
83
|
- !ruby/object:Gem::Version
|
84
84
|
version: '1.8'
|
85
|
-
description:
|
86
|
-
|
85
|
+
description: |2
|
86
|
+
An object-oriented Ruby implementation of the Sender Policy Framework (SPF)
|
87
|
+
e-mail sender authentication system, fully compliant with RFC 4408.
|
87
88
|
email:
|
88
89
|
- code@agari.com
|
89
90
|
- aflury@agari.com
|
@@ -94,8 +95,8 @@ extensions: []
|
|
94
95
|
extra_rdoc_files:
|
95
96
|
- README.rdoc
|
96
97
|
files:
|
97
|
-
- .document
|
98
|
-
- .rspec
|
98
|
+
- ".document"
|
99
|
+
- ".rspec"
|
99
100
|
- Gemfile
|
100
101
|
- Gemfile.lock
|
101
102
|
- README.rdoc
|
@@ -117,25 +118,24 @@ homepage: https://github.com/agaridata/spf-ruby
|
|
117
118
|
licenses:
|
118
119
|
- none (all rights reserved)
|
119
120
|
metadata: {}
|
120
|
-
post_install_message:
|
121
|
+
post_install_message:
|
121
122
|
rdoc_options: []
|
122
123
|
require_paths:
|
123
124
|
- lib
|
124
125
|
required_ruby_version: !ruby/object:Gem::Requirement
|
125
126
|
requirements:
|
126
|
-
- -
|
127
|
+
- - ">="
|
127
128
|
- !ruby/object:Gem::Version
|
128
129
|
version: '0'
|
129
130
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
130
131
|
requirements:
|
131
|
-
- -
|
132
|
+
- - ">="
|
132
133
|
- !ruby/object:Gem::Version
|
133
134
|
version: '0'
|
134
135
|
requirements: []
|
135
|
-
rubyforge_project:
|
136
|
-
rubygems_version: 2.
|
137
|
-
signing_key:
|
136
|
+
rubyforge_project:
|
137
|
+
rubygems_version: 2.5.1
|
138
|
+
signing_key:
|
138
139
|
specification_version: 4
|
139
140
|
summary: Implementation of the Sender Policy Framework
|
140
141
|
test_files: []
|
141
|
-
has_rdoc:
|