spf 0.0.26 → 0.0.27

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/lib/spf/error.rb CHANGED
@@ -14,15 +14,15 @@ module SPF
14
14
 
15
15
  class DNSError < Error; end # DNS error
16
16
  class DNSTimeoutError < DNSError; end # DNS timeout
17
- class RecordSelectionError < Error; end # Record selection error
18
- class NoAcceptableRecordError < RecordSelectionError; end # No acceptable record found
19
- class RedundantAcceptableRecordsError < RecordSelectionError # Redundant acceptable records found
20
- attr_accessor :records
21
- def initialize(message, records=[])
22
- @records = records
23
- super(message)
24
- end
17
+ class RecordSelectionError < Error # Record selection error
18
+ attr_accessor :records
19
+ def initialize(message, records=[])
20
+ @records = records
21
+ super(message)
25
22
  end
23
+ end
24
+ class NoAcceptableRecordError < RecordSelectionError; end # No acceptable record found
25
+ class RedundantAcceptableRecordsError < RecordSelectionError; end # Redundant acceptable records found
26
26
  class NoUnparsedTextError < Error; end # No unparsed text available
27
27
  class UnexpectedTermObjectError < Error; end # Unexpected term object encountered
28
28
  class ProcessingLimitExceededError < Error; end # Processing limit exceeded
@@ -33,7 +33,7 @@ module SPF
33
33
 
34
34
  class NothingToParseError < Error; end # Nothing to parse
35
35
  class SyntaxError < Error # Generic syntax error
36
- attr_accessor :text, :parse_text
36
+ attr_accessor :text, :parse_text, :domain
37
37
  def initialize(message, text=nil, parse_text=nil)
38
38
  @text = text
39
39
  @parse_text = parse_text
data/lib/spf/eval.rb CHANGED
@@ -44,6 +44,8 @@ class SPF::Server
44
44
  DEFAULT_MAX_NAME_LOOKUPS_PER_PTR_MECH = DEFAULT_MAX_NAME_LOOKUPS_PER_TERM
45
45
  DEFAULT_MAX_VOID_DNS_LOOKUPS = 2
46
46
 
47
+ LOOSE_SPF_MATCH_PATTERN = 'v=spf'
48
+
47
49
  def initialize(options = {})
48
50
  @default_authority_explanation = options[:default_authority_explanation] ||
49
51
  DEFAULT_DEFAULT_AUTHORITY_EXPLANATION
@@ -159,7 +161,7 @@ class SPF::Server
159
161
  return packet
160
162
  end
161
163
 
162
- def select_record(request)
164
+ def select_record(request, loose_match = false)
163
165
  domain = request.authority_domain
164
166
  versions = request.versions
165
167
  scope = request.scope
@@ -169,9 +171,10 @@ class SPF::Server
169
171
  # in future revisions of SPF):
170
172
  # Query for SPF type records first, then fall back to TXT type records.
171
173
 
172
- records = []
173
- query_count = 0
174
- dns_errors = []
174
+ records = []
175
+ loose_records = []
176
+ query_count = 0
177
+ dns_errors = []
175
178
 
176
179
  # Query for SPF-type RRs first:
177
180
  if (@query_rr_types == QUERY_RR_TYPE_ALL or
@@ -179,8 +182,10 @@ class SPF::Server
179
182
  begin
180
183
  query_count += 1
181
184
  packet = self.dns_lookup(domain, 'SPF')
182
- records << self.get_acceptable_records_from_packet(
183
- packet, 'SPF', versions, scope, domain)
185
+ matches = self.get_acceptable_records_from_packet(
186
+ packet, 'SPF', versions, scope, domain, loose_match)
187
+ records << matches[0]
188
+ loose_records << matches[1]
184
189
  rescue SPF::DNSError => e
185
190
  dns_errors << e
186
191
  #rescue SPF::DNSTimeout => e
@@ -205,8 +210,10 @@ class SPF::Server
205
210
  begin
206
211
  query_count += 1
207
212
  packet = self.dns_lookup(domain, 'TXT')
208
- records << self.get_acceptable_records_from_packet(
209
- packet, 'TXT', versions, scope, domain)
213
+ matches = self.get_acceptable_records_from_packet(
214
+ packet, 'TXT', versions, scope, domain, loose_match)
215
+ records << matches[0]
216
+ loose_records << matches[1]
210
217
  rescue SPF::DNSError => e
211
218
  dns_errors << e
212
219
  end
@@ -215,10 +222,12 @@ class SPF::Server
215
222
  raise dns_errors[0] unless dns_errors.length < query_count
216
223
 
217
224
  records.flatten!
225
+ loose_records.flatten!
218
226
 
219
227
  if records.empty?
220
228
  # RFC 4408, 4.5/7
221
- raise SPF::NoAcceptableRecordError.new('No applicable sender policy available')
229
+ raise SPF::NoAcceptableRecordError.new('No applicable sender policy available',
230
+ loose_records)
222
231
  end
223
232
 
224
233
  # Discard all records but the highest acceptable version:
@@ -238,7 +247,7 @@ class SPF::Server
238
247
  end
239
248
  end
240
249
 
241
- def get_acceptable_records_from_packet(packet, rr_type, versions, scope, domain)
250
+ def get_acceptable_records_from_packet(packet, rr_type, versions, scope, domain, loose_match)
242
251
 
243
252
  # Try higher record versions first.
244
253
  # (This may be too simplistic for future revisions of SPF.)
@@ -246,6 +255,7 @@ class SPF::Server
246
255
 
247
256
  rr_type = resource_typeclass_for_rr_type(rr_type)
248
257
  records = []
258
+ possible_matches = []
249
259
  packet.each do |rr|
250
260
  next unless rr_type === rr
251
261
  text = rr.strings.join('')
@@ -255,6 +265,9 @@ class SPF::Server
255
265
  begin
256
266
  record = klass.new_from_string(text, {:raise_exceptions => @raise_exceptions})
257
267
  rescue SPF::InvalidRecordVersionError => error
268
+ if text =~ /#{LOOSE_SPF_MATCH_PATTERN}/
269
+ possible_matches << text
270
+ end
258
271
  # Ignore non-SPF and unknown-version records.
259
272
  # Propagate other errors (including syntax errors), though.
260
273
  end
@@ -266,7 +279,7 @@ class SPF::Server
266
279
  end
267
280
  end
268
281
  end
269
- return records
282
+ return records, possible_matches
270
283
  end
271
284
 
272
285
  def count_dns_interactive_term(request)
data/lib/spf/model.rb CHANGED
@@ -551,12 +551,12 @@ class SPF::Mech < SPF::Term
551
551
  raise result
552
552
  end
553
553
 
554
- def nested_record(server=nil, request=nil)
554
+ def nested_record(server=nil, request=nil, loose_match = false)
555
555
  return @nested_record if @nested_record
556
556
  authority_domain = self.domain(server, request)
557
557
  return nil unless request
558
558
  sub_request = request.new_sub_request({:authority_domain => authority_domain})
559
- return @nested_record = server.select_record(sub_request)
559
+ return @nested_record = server.select_record(sub_request, loose_match)
560
560
  end
561
561
 
562
562
  end
data/lib/spf/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  module SPF
2
- VERSION = '0.0.26'
2
+ VERSION = '0.0.27'
3
3
  end
4
4
 
5
5
  # vim:sw=2 sts=2
data/spf.gemspec CHANGED
@@ -5,7 +5,7 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = "spf"
8
- s.version = "0.0.26"
8
+ s.version = "0.0.27"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Andrew Flury", "Julian Mehnle"]
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: spf
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.26
4
+ version: 0.0.27
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors: