spf 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
data/lib/spf/eval.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  require 'ip'
2
2
  require 'resolv'
3
3
 
4
+ require 'spf/error'
4
5
  require 'spf/model'
5
6
  require 'spf/result'
6
7
 
@@ -46,7 +47,7 @@ class SPF::Server
46
47
  def initialize(options = {})
47
48
  @default_authority_explanation = options[:default_authority_explanation] ||
48
49
  DEFAULT_DEFAULT_AUTHORITY_EXPLANATION
49
- unless @default_authority_explanation.is_a?(SPF::MacroString)
50
+ unless SPF::MacroString === @default_authority_explanation
50
51
  @default_authority_explanation = SPF::MacroString.new({
51
52
  :text => @default_authority_explanation,
52
53
  :server => self,
@@ -122,7 +123,7 @@ class SPF::Server
122
123
  end
123
124
 
124
125
  def dns_lookup(domain, rr_type)
125
- if domain.is_a?(SPF::MacroString)
126
+ if SPF::MacroString === domain
126
127
  domain = domain.expand
127
128
  # Truncate overlong labels at 63 bytes (RFC 4408, 8.1/27)
128
129
  domain.gsub!(/([^.]{63})[^.]+/, "#{$1}")
@@ -132,7 +133,7 @@ class SPF::Server
132
133
 
133
134
  rr_type = self.resource_typeclass_for_rr_type(rr_type)
134
135
 
135
- domain.sub(/^(.*?)\.?$/, $1 ? "#{$1}".downcase : '')
136
+ domain = domain.sub(/\.$/, '').downcase
136
137
 
137
138
  packet = @dns_resolver.getresources(domain, rr_type)
138
139
 
@@ -214,13 +215,13 @@ class SPF::Server
214
215
 
215
216
  if records.empty?
216
217
  # RFC 4408, 4.5/7
217
- raise SPF::NoAcceptableRecordError('No applicable sender policy available')
218
+ raise SPF::NoAcceptableRecordError.new('No applicable sender policy available')
218
219
  end
219
220
 
220
221
  # Discard all records but the highest acceptable version:
221
222
  preferred_record_class = records[0].class
222
223
 
223
- records = records.select { |record| record.is_a?(preferred_record_class) }
224
+ records = records.select { |record| preferred_record_class === record }
224
225
 
225
226
  if records.length != 1
226
227
  # RFC 4408, 4.5/6
@@ -242,7 +243,7 @@ class SPF::Server
242
243
  rr_type = resource_typeclass_for_rr_type(rr_type)
243
244
  records = []
244
245
  packet.each do |rr|
245
- next unless rr.is_a?(rr_type)
246
+ next unless rr_type === rr
246
247
  text = rr.strings.join('')
247
248
  record = false
248
249
  versions.each do |version|
data/lib/spf/model.rb CHANGED
@@ -85,6 +85,15 @@ class SPF::Term
85
85
  ::
86
86
  "
87
87
 
88
+ attr_reader :ip_address, :ip_network, :ipv4_prefix_length, :ipv6_prefix_length
89
+
90
+ def initialize
91
+ @ip_address = nil
92
+ @ip_network = nil
93
+ @ipv4_prefix_length = nil
94
+ @ipv6_prefix_length = nil
95
+ end
96
+
88
97
  def self.new_from_string(text, options = {})
89
98
  #term = SPF::Term.new(options, {:text => text})
90
99
  options[:text] = text
@@ -210,7 +219,7 @@ class SPF::Mech < SPF::Term
210
219
  @parse_text = @text.dup
211
220
  end
212
221
  if self.instance_variable_defined?(:@domain_spec) and
213
- not @domain_spec.is_a?(SPF::MacroString)
222
+ not SPF::MacroString === @domain_spec
214
223
  @domain_spec = SPF::MacroString.new({:text => @domain_spec})
215
224
  end
216
225
  end
@@ -351,7 +360,7 @@ class SPF::Mech < SPF::Term
351
360
  return params
352
361
  end
353
362
 
354
- def match(server, request)
363
+ def match(server, request, want_result = true)
355
364
  server.count_dns_interactive_term(request)
356
365
  return self.match_in_domain(server, request)
357
366
  end
@@ -366,7 +375,7 @@ class SPF::Mech < SPF::Term
366
375
  # No parameters.
367
376
  end
368
377
 
369
- def match(server, request)
378
+ def match(server, request, want_result = true)
370
379
  return true
371
380
  end
372
381
 
@@ -384,7 +393,7 @@ class SPF::Mech < SPF::Term
384
393
  return @domain_spec ? ':' + @domain_spec : nill
385
394
  end
386
395
 
387
- def match(server, request)
396
+ def match(server, request, want_result = true)
388
397
  server.count_dns_interactive_term(request)
389
398
 
390
399
  domain = self.domain(server, request)
@@ -414,8 +423,8 @@ class SPF::Mech < SPF::Term
414
423
  return result
415
424
  end
416
425
 
417
- def match(server, request)
418
- ip_network_v6 = @ip_network.is_a?(IP::V4) ?
426
+ def match(server, request, want_result = true)
427
+ ip_network_v6 = IP::V4 === @ip_network ?
419
428
  SPF::Util.ipv4_address_to_ipv6(@ip_network) :
420
429
  @ip_network
421
430
  return ip_network_v6.contains?(request.ip_address_v6)
@@ -438,7 +447,7 @@ class SPF::Mech < SPF::Term
438
447
  return params
439
448
  end
440
449
 
441
- def match(server, request)
450
+ def match(server, request, want_result = true)
442
451
  return @ip_network.contains?(request.ip_address_v6)
443
452
  end
444
453
 
@@ -456,7 +465,8 @@ class SPF::Mech < SPF::Term
456
465
  return @domain_spec ? ':' + @domain_spec : nil
457
466
  end
458
467
 
459
- def match(server, request)
468
+ def match(server, request, want_result = true)
469
+
460
470
  server.count_dns_interactive_term(request)
461
471
 
462
472
  # Create sub-request with mutated authority domain:
@@ -468,17 +478,18 @@ class SPF::Mech < SPF::Term
468
478
 
469
479
  # Translate result of sub-request (RFC 4408, 5.9):
470
480
 
471
- return true if
472
- result.is_a?(SPF::Result::Pass)
481
+ return false unless want_result
482
+
483
+ return true if SPF::Result::Pass === result
473
484
 
474
485
  return false if
475
- result.is_a?(SPF::Result::Fail) or
476
- result.is_a?(SPF::Result::SoftFail) or
477
- result.is_a?(SPF::Result::Neutral)
486
+ SPF::Result::Fail === result or
487
+ SPF::Result::SoftFail === result or
488
+ SPF::Result::Neutral === result or
478
489
 
479
490
  server.throw_result('permerror', request,
480
491
  "Include domain '#{authority_domain}' has no applicable sender policy") if
481
- result.is_a?(SPF::Result::None)
492
+ SPF::Result::None === result
482
493
 
483
494
  # Propagate any other results (including {Perm,Temp}Error) as-is:
484
495
  raise result
@@ -508,7 +519,7 @@ class SPF::Mech < SPF::Term
508
519
  return params
509
520
  end
510
521
 
511
- def match(server, request)
522
+ def match(server, request, want_result = true)
512
523
 
513
524
  server.count_dns_interactive_term(request)
514
525
 
@@ -549,7 +560,7 @@ class SPF::Mech < SPF::Term
549
560
  return @domain_spec ? ':' + @domain_spec : nil
550
561
  end
551
562
 
552
- def match(server, request)
563
+ def match(server, request, want_result = true)
553
564
  return SPF::Util.valid_domain_for_ip_address(
554
565
  server, request, request.ip_address, self.domain(server, request)) ?
555
566
  true : false
@@ -566,7 +577,7 @@ class SPF::Mod < SPF::Term
566
577
 
567
578
  @parse_text = @text.dup unless @parse_text
568
579
 
569
- if @domain_spec and not @domain_spec.is_a?(SPF::MacroString)
580
+ if @domain_spec and not SPF::MacroString === @domain_spec
570
581
  @domain_spec = SPF::MacroString.new({:text => @domain_spec})
571
582
  end
572
583
  end
@@ -684,7 +695,7 @@ class SPF::Mod < SPF::Term
684
695
  server.count_dns_interactive_term(request)
685
696
 
686
697
  # Only perform redirection if no mechanism matched (RFC 4408, 6.1/1):
687
- return unless result.is_a?(SPF::Result::NeutralByDefault)
698
+ return unless SPF::Result::NeutralByDefault === result
688
699
 
689
700
  # Create sub-request with mutated authorithy domain:
690
701
  authority_domain = @domain_spec.new({:server => server, :request => request})
@@ -694,7 +705,7 @@ class SPF::Mod < SPF::Term
694
705
  result = server.process(sub_request)
695
706
 
696
707
  # Translate result of sub-request (RFC 4408, 6.1/4):
697
- if result.is_a?(SPF::Result::None)
708
+ if SPF::Result::None === result
698
709
  server.throw_result(:permerror, request,
699
710
  "Redirect domain '#{authority_domain}' has no applicable sender policy")
700
711
  end
@@ -789,13 +800,13 @@ class SPF::Record
789
800
  if mod_class
790
801
  # Known modifier.
791
802
  mod = mod_class.new_from_string(mod_text)
792
- if mod.is_a?(SPF::GlobalMod)
803
+ if SPF::GlobalMod === mod
793
804
  # Global modifier.
794
805
  unless @global_mods[mod_name]
795
806
  raise SPF::DuplicateGlobalMod.new("Duplicate global modifier '#{mod_name}' encountered")
796
807
  end
797
808
  @global_mods[mod_name] = mod
798
- elsif mod.is_a?(SPF::PositionalMod)
809
+ elsif SPF::PositionalMod === mod
799
810
  # Positional modifier, queue normally:
800
811
  @terms << mod
801
812
  end
@@ -822,26 +833,26 @@ class SPF::Record
822
833
  raise SPF::OptionRequiredError.new('Request object required for record evaluation') unless request
823
834
  begin
824
835
  @terms.each do |term|
825
- if term.is_a?(SPF::Mech)
836
+ if SPF::Mech === term
837
+ #if term.is_a?(SPF::Mech)
826
838
  # Term is a mechanism.
827
839
  mech = term
828
- if mech.match(server, request)
840
+ if mech.match(server, request, request.ip_address != nil)
829
841
  result_name = RESULTS_BY_QUALIFIER[mech.qualifier]
830
842
  result_class = server.result_class(result_name)
831
843
  result = result_class.new([server, request, "Mechanism '#{term}' matched"])
832
844
  mech.explain(server, request, result)
833
845
  raise result
834
846
  end
835
- elsif term.is_a?(SPF::PositionalMod)
847
+ elsif SPF::PositionalMod === term
836
848
  # Term is a positional modifier.
837
849
  mod = term
838
850
  mod.process(server, request)
839
- elsif term.is_a?(SPF::UnknownMod)
851
+ elsif SPF::UnknownMod === term
840
852
  # Term is an unknown modifier. Ignore it (RFC 4408, 6/3).
841
853
  else
842
854
  # Invalid term object encountered:
843
- raise SPF::UnexpectedTermObjectError.new(
844
- "Unexpected term object '#{term}' encountered.")
855
+ raise SPF::UnexpectedTermObjectError.new("Unexpected term object '#{term}' encountered.")
845
856
  end
846
857
  end
847
858
  rescue SPF::Result => result
@@ -880,6 +891,10 @@ class SPF::Record
880
891
  'v=spf1'
881
892
  end
882
893
 
894
+ def self.version_tag
895
+ 'v=spf1'
896
+ end
897
+
883
898
  def version_tag_pattern
884
899
  " v=spf(1) (?= \\x20+ | $ ) "
885
900
  end
data/lib/spf/request.rb CHANGED
@@ -25,7 +25,7 @@ class SPF::Request
25
25
  @state = {}
26
26
  @versions = options[:versions]
27
27
  @scope = options[:scope] || :mfrom
28
- @scope = @scope.to_sym if @scope.is_a?(String)
28
+ @scope = @scope.to_sym if String === @scope
29
29
  @_authority_domain = options[:authority_domain]
30
30
  @identity = options[:identity]
31
31
  @ip_address = options[:ip_address]
@@ -40,14 +40,13 @@ class SPF::Request
40
40
  raise SPF::InvalidScopeError.new("Invalid scope '#{@scope}'")
41
41
 
42
42
  # Versions:
43
- if self.instance_variable_defined?(:@versions)
44
- if @versions.is_a?(Symbol)
43
+ if @versions
44
+ if Symbol === @versions
45
45
  # Single version specified as a symbol:
46
46
  @versions = [@versions]
47
- elsif not @versions.is_a?(Array)
47
+ elsif not Array === @versions
48
48
  # Something other than symbol or array specified:
49
- raise SPF::InvalidOptionValueError.new(
50
- "'versions' option must be symbol or array")
49
+ raise SPF::InvalidOptionValueError.new("'versions' option must be symbol or array")
51
50
  end
52
51
 
53
52
  # All requested record versions must be supported:
@@ -91,24 +90,21 @@ class SPF::Request
91
90
  @helo_identity ||= @identity
92
91
  end
93
92
 
94
- # IP address:
95
- if [:helo, :mfrom, :pra].find(@scope) and not self.instance_variable_defined?(:@ip_address)
96
- raise SPF::OptionRequiredError.new("Missing required 'ip_address' option")
97
- end
93
+ return unless @ip_address
98
94
 
99
95
  # Ensure ip_address is an IP object:
100
- unless @ip_address.is_a?(IP)
96
+ unless IP === @ip_address
101
97
  @ip_address = IP.new(@ip_address)
102
98
  end
103
99
 
104
100
  # Convert IPv4 address to IPv4-mapped IPv6 address:
105
101
 
106
- if SPF::Util.ipv6_address_is_ipv4_mapped(self.ip_address)
102
+ if SPF::Util.ipv6_address_is_ipv4_mapped(@ip_address)
107
103
  @ip_address_v6 = @ip_address # Accept as IPv6 address as-is
108
104
  @ip_address = SPF::Util.ipv6_address_to_ipv4(@ip_address)
109
- elsif @ip_address.is_a?(IP::V4)
105
+ elsif IP::V4 === @ip_address
110
106
  @ip_address_v6 = SPF::Util.ipv4_address_to_ipv6(@ip_address)
111
- elsif @ip_address.is_a?(IP::V6)
107
+ elsif IP::V6 === @ip_address
112
108
  @ip_address_v6 = @ip_address
113
109
  else
114
110
  raise SPF::InvalidOptionValueError.new("Unexpected IP address version");
@@ -131,7 +127,7 @@ class SPF::Request
131
127
  unless field
132
128
  raise SPF::OptionRequiredError.new('Field name required')
133
129
  end
134
- if value and value === Fixnum
130
+ if value and Fixnum === value
135
131
  @state[field] = 0 unless @state[field]
136
132
  @state[field] += value
137
133
  else
data/lib/spf/result.rb CHANGED
@@ -140,7 +140,7 @@ class SPF::Result < Exception
140
140
 
141
141
  def klass(name=nil)
142
142
  if name
143
- name = name.to_sym if name.is_a?(String)
143
+ name = name.to_sym if String === name
144
144
  return self.RESULT_CLASSES[name]
145
145
  else
146
146
  return name
@@ -150,7 +150,7 @@ class SPF::Result < Exception
150
150
  def isa_by_name(name)
151
151
  suspect_class = self.klass(name)
152
152
  return false unless suspect_class
153
- return self.is_a?(suspect_class)
153
+ return suspect_class === self
154
154
  end
155
155
 
156
156
  def is_code(code)
data/lib/spf/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  module SPF
2
- VERSION = '0.0.1'
2
+ VERSION = '0.0.2'
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.1"
8
+ s.version = "0.0.2"
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.1
4
+ version: 0.0.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors: