spf 0.0.46 → 0.0.47

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 CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- OTU2NzZlNmViOGYxMWE1Nzg2YzRiMGFiOGM4YjJiYzE5MGRhNDM5Mw==
4
+ NDRiZjE1NWYxNGNhYTc1N2NjODU5YTA4NmMyZjUxNjliMDIxYjlhZg==
5
5
  data.tar.gz: !binary |-
6
- ZDA4MDY2YzNhNDNlMjFkMTY4ZTRmOTJmY2E5ZjUyMGNiZTE0ZDU0ZA==
6
+ MmQ4NGVkMTE2MjdkZDA4NzE1ZGJjY2MzZTljMWE1MGRjYWU5N2FhMQ==
7
7
  SHA512:
8
8
  metadata.gz: !binary |-
9
- YzYxNTFhNGU1MGU3NTAxYjAzMzhiMTgwNDExOWVjYzgyNjgyYjc0Y2JmOWYw
10
- NDU2NDUxYTYyYTJjMmE5MDQxYmMwZWE5NDE4Mjc5MDc1M2Q5NmYwNTY5YTg1
11
- M2M5ZjNlYzA5NmRiMjkyNjEyMjEzZmEzNmM4NzIzYWM2NDVlYTc=
9
+ NjY4NWJjNWQ0MjAwN2VlMmNjYTc5ZjVkNmNlYjQxZmNkNzlhNGRjMGYxNDEx
10
+ M2M1ZGFmZDkyOTQ5NWJlY2QxYmY1NDdlZDIyZmY1Y2UyOWZlYmNmNDBkOWQ2
11
+ OTE1OTY5OTlhOTQ5MjhiZDVkMjliZWQ1MzY4NzYwMjgzZjVjM2I=
12
12
  data.tar.gz: !binary |-
13
- OTI4ODQ3NDEyNWMzOWQ5ZmM2MDdmYWJjN2Y4YTg2NTkwODZiMzBlNjk1ODdl
14
- MDdiYzJjNDdhZDk1OTE2MTExYTNjNzYwYTRkNmUyMzU1OWUzMTA2MWUxMDhm
15
- YTNmMTQzOWI0MWVjNDg5ZGM4YjA4YTczMWQ5YmFiYzY3ZTQ5ODE=
13
+ MmE5ZDY4OGYzY2IzZWRiMjI5NDQ3YThlOWM5MGViZGNiZmViM2U5YjBiMTVj
14
+ YjkyZGVhZTI0MGMzMDMzY2NhZTBmZjNhYWNjOWE4MTJlMzU5YTk0N2MwMjBh
15
+ YmMzYzM2N2I2MWIxNTY2MGFhMmM1NDg0ODE3NThjNDkzZjQyZmU=
data/Gemfile CHANGED
@@ -12,4 +12,5 @@ group :development do
12
12
  gem "rdoc", "~> 3"
13
13
  gem "bundler", "~> 1.2"
14
14
  gem "jeweler", "~> 1.8"
15
+ gem "simplecov", :require => false, :group => :test
15
16
  end
data/Gemfile.lock CHANGED
@@ -4,6 +4,7 @@ GEM
4
4
  addressable (2.3.7)
5
5
  builder (3.2.2)
6
6
  diff-lcs (1.2.5)
7
+ docile (1.1.5)
7
8
  faraday (0.8.9)
8
9
  multipart-post (~> 1.2.0)
9
10
  git (1.2.9.1)
@@ -50,6 +51,11 @@ GEM
50
51
  diff-lcs (>= 1.1.3, < 2.0)
51
52
  rspec-mocks (2.99.3)
52
53
  ruby-ip (0.9.3)
54
+ simplecov (0.9.2)
55
+ docile (~> 1.1.0)
56
+ multi_json (~> 1.0)
57
+ simplecov-html (~> 0.9.0)
58
+ simplecov-html (0.9.0)
53
59
 
54
60
  PLATFORMS
55
61
  ruby
@@ -60,3 +66,4 @@ DEPENDENCIES
60
66
  rdoc (~> 3)
61
67
  rspec (~> 2.9)
62
68
  ruby-ip (~> 0.9.1)
69
+ simplecov
@@ -0,0 +1,161 @@
1
+ require 'resolv'
2
+
3
+ require 'rubygems' # Gem.ruby_version / Gem::Version
4
+
5
+
6
+ # TCP fallback support, redux.
7
+ # A broken version of this made it into Ruby 1.9.2 in October 2010.
8
+ # <http://bugs.ruby-lang.org/issues/3835> That version would fail when trying
9
+ # a second TCP nameserver. This improved version fixes that.
10
+ # Filed upstream as <http://bugs.ruby-lang.org/issues/8285>.
11
+ ###############################################################################
12
+
13
+ class Resolv
14
+ class DNS
15
+ def each_resource(name, typeclass, &proc)
16
+ lazy_initialize
17
+ protocols = {} # PATCH
18
+ requesters = {} # PATCH
19
+ senders = {}
20
+ #begin # PATCH
21
+ @config.resolv(name) {|candidate, tout, nameserver, port|
22
+ msg = Message.new
23
+ msg.rd = 1
24
+ msg.add_question(candidate, typeclass)
25
+ protocol = protocols[candidate] ||= :udp # PATCH
26
+ requester = requesters[[protocol, nameserver]] ||= case protocol # PATCH
27
+ when :udp then make_udp_requester # PATCH
28
+ when :tcp then make_tcp_requester(nameserver, port) # PATCH
29
+ end # PATCH
30
+ sender = senders[[candidate, requester, nameserver, port]] ||= # PATCH
31
+ requester.sender(msg, candidate, nameserver, port) # PATCH
32
+ reply, reply_name = requester.request(sender, tout)
33
+ case reply.rcode
34
+ when RCode::NoError
35
+ if protocol == :udp and reply.tc == 1 # PATCH
36
+ # Retry via TCP: # PATCH
37
+ protocols[candidate] = :tcp # PATCH
38
+ redo # PATCH
39
+ else # PATCH
40
+ extract_resources(reply, reply_name, typeclass, &proc)
41
+ end # PATCH
42
+ return
43
+ when RCode::NXDomain
44
+ raise Config::NXDomain.new(reply_name.to_s)
45
+ else
46
+ raise Config::OtherResolvError.new(reply_name.to_s)
47
+ end
48
+ }
49
+ ensure
50
+ requesters.each_value { |requester| requester.close } # PATCH
51
+ #end # PATCH
52
+ end
53
+
54
+ #alias_method :make_udp_requester, :make_requester
55
+
56
+ def make_tcp_requester(host, port)
57
+ return Requester::TCP.new(host, port)
58
+ rescue Errno::ECONNREFUSED
59
+ # Treat a refused TCP connection attempt to a nameserver like a timeout,
60
+ # as Resolv::DNS::Config#resolv considers ResolvTimeout exceptions as a
61
+ # hint to try the next nameserver:
62
+ raise ResolvTimeout
63
+ end
64
+ end
65
+ end
66
+
67
+
68
+ # Fix for (unreported) "nil can't be coerced into Fixnum" TypeError exception
69
+ # caused by truncated (or otherwise malformed) answer packets.
70
+ ###############################################################################
71
+
72
+ class Resolv
73
+ class DNS
74
+ class Message
75
+ class MessageDecoder
76
+
77
+ def get_labels(limit=nil)
78
+ limit = @index if !limit || @index < limit
79
+ d = []
80
+ while true
81
+ case @data[@index] && @data[@index].ord # PATCH
82
+ when nil # PATCH
83
+ raise DecodeError.new("truncated or malformed packet") # PATCH
84
+ when 0
85
+ @index += 1
86
+ return d
87
+ when 192..255
88
+ idx = self.get_unpack('n')[0] & 0x3fff
89
+ if limit <= idx
90
+ raise DecodeError.new("non-backward name pointer")
91
+ end
92
+ save_index = @index
93
+ @index = idx
94
+ d += self.get_labels(limit)
95
+ @index = save_index
96
+ return d
97
+ else
98
+ d << self.get_label
99
+ end
100
+ end
101
+ return d
102
+ end
103
+
104
+ end
105
+ end
106
+ end
107
+ end
108
+
109
+
110
+ # Patch to expose timeout and NXDOMAIN errors to the ultimate caller of
111
+ # Resolv::DNS rather than swallowing them silently and returning an empty
112
+ # result set.
113
+ ###############################################################################
114
+
115
+ class Resolv
116
+ class TimeoutError < ResolvError; end
117
+ class NXDomainError < ResolvError; end
118
+
119
+ class DNS
120
+ class Config
121
+ attr_accessor :raise_errors # PATCH
122
+ def resolv(name)
123
+ candidates = generate_candidates(name)
124
+ timeouts = generate_timeouts
125
+ # Collect errors while making the various lookup attempts: # PATCH
126
+ errors = [] # PATCH
127
+ begin
128
+ candidates.each {|candidate|
129
+ begin
130
+ timeouts.each {|tout|
131
+ @nameserver_port.each {|nameserver, port|
132
+ begin
133
+ yield candidate, tout, nameserver, port
134
+ rescue ResolvTimeout
135
+ end
136
+ }
137
+ }
138
+ # Collect a timeout: # PATCH
139
+ errors << TimeoutError.new("DNS resolv timeout: #{name}") # PATCH
140
+ rescue NXDomain
141
+ # Collect an NXDOMAIN error: # PATCH
142
+ errors << NXDomainError.new("DNS name does not exist: #{name}") # PATCH
143
+ end
144
+ }
145
+ rescue ResolvError
146
+ # Allow subclasses to set this to override this behavior without # PATCH
147
+ # wholesale monkeypatching. # PATCH
148
+ raise if raise_errors # PATCH
149
+ # Ignore other errors like vanilla Resolv::DNS does. # PATCH
150
+ # Perhaps this is not a good idea, though, as it silently swallows # PATCH
151
+ # SERVFAILs, etc. # PATCH
152
+ end
153
+ # If one lookup succeeds, we will have returned within "yield" already. # PATCH
154
+ # Otherwise we now raise the first error that occurred: # PATCH
155
+ raise errors.first if not errors.empty? # PATCH
156
+ end
157
+ end
158
+ end
159
+ end
160
+
161
+ # vim:sw=2 sts=2
data/lib/spf/model.rb CHANGED
@@ -571,7 +571,7 @@ class SPF::Mech < SPF::Term
571
571
  return nil unless server and request
572
572
  authority_domain = self.domain(server, request)
573
573
  sub_request = request.new_sub_request({:authority_domain => authority_domain})
574
- return @nested_record = server.select_record(sub_request, loose_match)
574
+ return @nested_record = server.selectrecord(sub_request, loose_match)
575
575
  end
576
576
 
577
577
  end
@@ -786,14 +786,14 @@ class SPF::Mod < SPF::Term
786
786
  end
787
787
 
788
788
  def process(server, request, result)
789
+
789
790
  server.count_dns_interactive_term(request)
790
791
 
791
792
  # Only perform redirection if no mechanism matched (RFC 4408, 6.1/1):
792
793
  return unless SPF::Result::NeutralByDefault === result
793
794
 
794
795
  # Create sub-request with mutated authorithy domain:
795
- authority_domain = @domain_spec.new({:server => server, :request => request})
796
- sub_request = request.new_sub_request({:authority_domain => authority_domain})
796
+ sub_request = request.new_sub_request({:authority_domain => @domain_spec})
797
797
 
798
798
  # Process sub-request:
799
799
  result = server.process(sub_request)
@@ -807,7 +807,7 @@ class SPF::Mod < SPF::Term
807
807
  end
808
808
 
809
809
  # Propagate any other results as-is:
810
- result.throw
810
+ raise result
811
811
  end
812
812
 
813
813
  def nested_record(server=nil, request=nil)
@@ -998,6 +998,8 @@ class SPF::Record
998
998
  error(SPF::UnexpectedTermObjectError.new("Unexpected term object '#{term}' encountered."))
999
999
  end
1000
1000
  end
1001
+ server.throw_result(:neutral_by_default, request,
1002
+ 'Default neutral result due to no mechanism matches')
1001
1003
  rescue SPF::Result => result
1002
1004
  # Process global modifiers in ascending order of precedence:
1003
1005
  global_mods.each do |global_mod|
data/lib/spf/request.rb CHANGED
@@ -22,19 +22,19 @@ class SPF::Request
22
22
  DEFAULT_LOCALPART = 'postmaster'
23
23
 
24
24
  def initialize(options = {})
25
- @opt = options
26
- @state = {}
27
- @versions = options[:versions]
28
- @scope = options[:scope] || :mfrom
29
- @scope = @scope.to_sym if String === @scope
30
- @authority_domain = options[:authority_domain]
31
- @identity = options[:identity]
32
- @ip_address = options[:ip_address]
33
- @helo_identity = options[:helo_identity]
34
- @root_request = self
35
- @super_request = self
36
- @record = nil
37
- @sub_requests = []
25
+ @opt = options
26
+ @state = {}
27
+ @versions = options[:versions]
28
+ @scope = options[:scope] || :mfrom
29
+ @scope = @scope.to_sym if String === @scope
30
+ @authority_domain = options[:authority_domain]
31
+ @identity = options[:identity]
32
+ @ip_address = options[:ip_address]
33
+ @helo_identity = options[:helo_identity]
34
+ @root_request = self
35
+ @super_request = self
36
+ @record = nil
37
+ @sub_requests = []
38
38
 
39
39
  # Scope:
40
40
  versions_for_scope = VERSIONS_FOR_SCOPE[@scope] or
@@ -42,11 +42,11 @@ class SPF::Request
42
42
 
43
43
  # Versions:
44
44
  if @versions
45
- if Symbol === @versions
46
- # Single version specified as a symbol:
45
+ if Fixnum === @versions
46
+ # Single version specified as a Fixnum:
47
47
  @versions = [@versions]
48
48
  elsif not Array === @versions
49
- # Something other than symbol or array specified:
49
+ # Something other than Fixnum or array specified:
50
50
  raise SPF::InvalidOptionValueError.new("'versions' option must be symbol or array")
51
51
  end
52
52
 
@@ -64,6 +64,14 @@ class SPF::Request
64
64
  @versions = versions_for_scope
65
65
  end
66
66
 
67
+ versions = @versions.select {|x| versions_for_scope.include?(x)}
68
+ if versions.empty?
69
+ raise SPF::InvalidScopeError.new(
70
+ "Invalid scope '#{@scope}' for record version(s) #{@versions}"
71
+ )
72
+ end
73
+ @versions = versions
74
+
67
75
  # Identity:
68
76
  raise SPF::OptionRequiredError.new(
69
77
  "Missing required 'identity' option") unless @identity
@@ -128,11 +136,15 @@ class SPF::Request
128
136
  unless field
129
137
  raise SPF::OptionRequiredError.new('Field name required')
130
138
  end
131
- if value and Fixnum === value
132
- @state[field] = 0 unless @state[field]
133
- @state[field] += value
139
+ if value
140
+ if Fixnum === value
141
+ @state[field] = 0 unless @state[field]
142
+ return (@state[field] += value)
143
+ else
144
+ return (@state[field] = value)
145
+ end
134
146
  else
135
- @state[field] = value
147
+ return @state[field]
136
148
  end
137
149
  end
138
150
  end
data/lib/spf/result.rb CHANGED
@@ -4,7 +4,7 @@ require 'spf/util'
4
4
 
5
5
  class SPF::Result < Exception
6
6
 
7
- attr_reader :server, :request
7
+ attr_reader :server, :request, :result_text
8
8
 
9
9
  class SPF::Result::Pass < SPF::Result
10
10
  def code
@@ -63,9 +63,6 @@ class SPF::Result < Exception
63
63
  # This is a special-case of the Neutral result that is thrown as a default
64
64
  # when "falling off" the end of the record. See SPF::Record.eval().
65
65
  NAME = :neutral_by_default
66
- def code
67
- :neutral_by_default
68
- end
69
66
  end
70
67
 
71
68
  class SPF::Result::None < SPF::Result
@@ -133,6 +130,7 @@ class SPF::Result < Exception
133
130
  unless self.instance_variable_defined?(:@request)
134
131
  raise SPF::OptionRequiredError.new('Request object required')
135
132
  end
133
+ @result_text = args.shift if args.any?
136
134
  end
137
135
 
138
136
  def name
@@ -142,20 +140,20 @@ class SPF::Result < Exception
142
140
  def klass(name=nil)
143
141
  if name
144
142
  name = name.to_sym if String === name
145
- return self.RESULT_CLASSES[name]
143
+ return RESULT_CLASSES[name]
146
144
  else
147
145
  return name
148
146
  end
149
147
  end
150
148
 
151
149
  def isa_by_name(name)
152
- suspect_class = self.klass(name)
150
+ suspect_class = self.klass(name.downcase)
153
151
  return false unless suspect_class
154
152
  return suspect_class === self
155
153
  end
156
154
 
157
155
  def is_code(code)
158
- return self.isa_by_name(code)
156
+ return self.isa_by_name(code.downcase)
159
157
  end
160
158
 
161
159
  def to_s
data/lib/spf/version.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  # encoding: ASCII-8BIT
2
2
  module SPF
3
- VERSION = '0.0.46'
3
+ VERSION = '0.0.47'
4
4
  end
5
5
 
6
6
  # vim:sw=2 sts=2
data/lib/spf.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  # encoding: ASCII-8BIT
2
+ require 'spf/ext/resolv'
2
3
  require 'spf/version'
3
4
  require 'spf/error'
4
5
  require 'spf/model'
data/spec/spec_helper.rb CHANGED
@@ -1,3 +1,6 @@
1
+ require 'simplecov'
2
+ SimpleCov.start
3
+
1
4
  $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
2
5
  $LOAD_PATH.unshift(File.dirname(__FILE__))
3
6
  require 'rspec'
@@ -8,5 +11,4 @@ require 'spf'
8
11
  Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
9
12
 
10
13
  RSpec.configure do |config|
11
-
12
14
  end
data/spec/spf_spec.rb CHANGED
@@ -1,7 +1,4 @@
1
1
  require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
2
 
3
- describe "SPF" do
4
- it "fails" do
5
- fail "hey buddy, you should probably rename this file and start specing for real"
6
- end
3
+ describe 'SPF' do
7
4
  end
data/spf.gemspec CHANGED
@@ -2,14 +2,16 @@
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.47 ruby lib
5
6
 
6
7
  Gem::Specification.new do |s|
7
8
  s.name = "spf"
8
- s.version = "0.0.46"
9
+ s.version = "0.0.47"
9
10
 
10
11
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
12
+ s.require_paths = ["lib"]
11
13
  s.authors = ["Andrew Flury", "Julian Mehnle", "Jacob Rideout"]
12
- s.date = "2015-03-04"
14
+ s.date = "2015-04-29"
13
15
  s.description = " An object-oriented Ruby implementation of the Sender Policy Framework (SPF)\n e-mail sender authentication system, fully compliant with RFC 4408.\n"
14
16
  s.email = ["code@agari.com", "aflury@agari.com", "jmehnle@agari.com", "jrideout@agari.com"]
15
17
  s.extra_rdoc_files = [
@@ -31,18 +33,18 @@ Gem::Specification.new do |s|
31
33
  "lib/spf/result.rb",
32
34
  "lib/spf/util.rb",
33
35
  "lib/spf/version.rb",
36
+ "lib/spf/ext/resolv.rb",
34
37
  "spec/spec_helper.rb",
35
38
  "spec/spf_spec.rb",
36
39
  "spf.gemspec"
37
40
  ]
38
41
  s.homepage = "https://github.com/agaridata/spf-ruby"
39
42
  s.licenses = ["none (all rights reserved)"]
40
- s.require_paths = ["lib"]
41
- s.rubygems_version = "1.8.23.2"
43
+ s.rubygems_version = "2.4.6"
42
44
  s.summary = "Implementation of the Sender Policy Framework"
43
45
 
44
46
  if s.respond_to? :specification_version then
45
- s.specification_version = 3
47
+ s.specification_version = 4
46
48
 
47
49
  if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
48
50
  s.add_runtime_dependency(%q<ruby-ip>, ["~> 0.9.1"])
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.46
4
+ version: 0.0.47
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrew Flury
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2015-03-04 00:00:00.000000000 Z
13
+ date: 2015-04-29 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: ruby-ip
@@ -103,6 +103,7 @@ files:
103
103
  - lib/spf.rb
104
104
  - lib/spf/error.rb
105
105
  - lib/spf/eval.rb
106
+ - lib/spf/ext/resolv.rb
106
107
  - lib/spf/macro_string.rb
107
108
  - lib/spf/model.rb
108
109
  - lib/spf/request.rb
@@ -134,7 +135,7 @@ requirements: []
134
135
  rubyforge_project:
135
136
  rubygems_version: 2.4.4
136
137
  signing_key:
137
- specification_version: 3
138
+ specification_version: 4
138
139
  summary: Implementation of the Sender Policy Framework
139
140
  test_files: []
140
141
  has_rdoc: