spf 0.0.46 → 0.0.47

Sign up to get free protection for your applications and to get access to all the features.
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: