coppertone 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (81) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +1 -0
  3. data/LICENSE +1 -1
  4. data/Rakefile +2 -2
  5. data/coppertone.gemspec +1 -0
  6. data/lib/coppertone/directive.rb +14 -7
  7. data/lib/coppertone/error.rb +24 -5
  8. data/lib/coppertone/ip_address_wrapper.rb +9 -6
  9. data/lib/coppertone/macro_context.rb +7 -13
  10. data/lib/coppertone/macro_string/macro_expand.rb +3 -2
  11. data/lib/coppertone/macro_string.rb +12 -5
  12. data/lib/coppertone/mechanism/a.rb +5 -1
  13. data/lib/coppertone/mechanism/all.rb +11 -4
  14. data/lib/coppertone/mechanism/cidr_parser.rb +1 -1
  15. data/lib/coppertone/mechanism/domain_spec_mechanism.rb +9 -0
  16. data/lib/coppertone/mechanism/domain_spec_optional.rb +1 -0
  17. data/lib/coppertone/mechanism/domain_spec_required.rb +1 -0
  18. data/lib/coppertone/mechanism/domain_spec_with_dual_cidr.rb +1 -0
  19. data/lib/coppertone/mechanism/exists.rb +5 -1
  20. data/lib/coppertone/mechanism/include.rb +17 -5
  21. data/lib/coppertone/mechanism/ip4.rb +5 -1
  22. data/lib/coppertone/mechanism/ip6.rb +5 -1
  23. data/lib/coppertone/mechanism/ip_mechanism.rb +9 -1
  24. data/lib/coppertone/mechanism/mx.rb +5 -1
  25. data/lib/coppertone/mechanism/ptr.rb +5 -1
  26. data/lib/coppertone/mechanism.rb +25 -2
  27. data/lib/coppertone/modifier/base.rb +1 -0
  28. data/lib/coppertone/modifier/exp.rb +6 -2
  29. data/lib/coppertone/modifier/redirect.rb +5 -1
  30. data/lib/coppertone/modifier/unknown.rb +6 -1
  31. data/lib/coppertone/modifier.rb +11 -2
  32. data/lib/coppertone/null_macro_context.rb +23 -0
  33. data/lib/coppertone/qualifier.rb +8 -0
  34. data/lib/coppertone/record.rb +33 -41
  35. data/lib/coppertone/record_finder.rb +3 -1
  36. data/lib/coppertone/record_term_parser.rb +30 -0
  37. data/lib/coppertone/request.rb +3 -1
  38. data/lib/coppertone/request_context.rb +1 -2
  39. data/lib/coppertone/result.rb +6 -2
  40. data/lib/coppertone/utils/validated_domain_finder.rb +6 -4
  41. data/lib/coppertone/version.rb +1 -1
  42. data/lib/coppertone.rb +3 -1
  43. data/spec/directive_spec.rb +13 -0
  44. data/spec/ip_address_wrapper_spec.rb +3 -0
  45. data/spec/macro_string_spec.rb +20 -0
  46. data/spec/mechanism/a_spec.rb +22 -7
  47. data/spec/mechanism/all_spec.rb +8 -0
  48. data/spec/mechanism/exists_spec.rb +14 -6
  49. data/spec/mechanism/include_spec.rb +13 -1
  50. data/spec/mechanism/ip4_spec.rb +15 -5
  51. data/spec/mechanism/ip6_spec.rb +18 -11
  52. data/spec/mechanism/mx_spec.rb +56 -0
  53. data/spec/mechanism/ptr_spec.rb +7 -0
  54. data/spec/modifier/exp_spec.rb +10 -0
  55. data/spec/modifier/redirect_spec.rb +10 -0
  56. data/spec/open_spf/ALL_mechanism_syntax_spec.rb +6 -6
  57. data/spec/open_spf/A_mechanism_syntax_spec.rb +30 -30
  58. data/spec/open_spf/EXISTS_mechanism_syntax_spec.rb +8 -8
  59. data/spec/open_spf/IP4_mechanism_syntax_spec.rb +10 -10
  60. data/spec/open_spf/IP6_mechanism_syntax_spec.rb +10 -10
  61. data/spec/open_spf/Include_mechanism_semantics_and_syntax_spec.rb +10 -10
  62. data/spec/open_spf/Initial_processing_spec.rb +21 -14
  63. data/spec/open_spf/MX_mechanism_syntax_spec.rb +22 -22
  64. data/spec/open_spf/Macro_expansion_rules_spec.rb +26 -30
  65. data/spec/open_spf/PTR_mechanism_syntax_spec.rb +7 -7
  66. data/spec/open_spf/Processing_limits_spec.rb +12 -12
  67. data/spec/open_spf/Record_evaluation_spec.rb +13 -13
  68. data/spec/open_spf/Record_lookup_spec.rb +8 -8
  69. data/spec/open_spf/Selecting_records_spec.rb +11 -11
  70. data/spec/open_spf/Semantics_of_exp_and_other_modifiers_spec.rb +27 -25
  71. data/spec/open_spf/Test_cases_from_implementation_bugs_spec.rb +2 -2
  72. data/spec/record_spec.rb +34 -13
  73. data/spec/request_context_spec.rb +1 -1
  74. data/spec/rfc7208-tests.yml +10 -0
  75. metadata +59 -48
  76. data/lib/coppertone/dns/error.rb +0 -9
  77. data/lib/coppertone/dns/mock_client.rb +0 -106
  78. data/lib/coppertone/dns/resolv_client.rb +0 -110
  79. data/lib/coppertone/dns.rb +0 -3
  80. data/lib/resolv/dns/resource/in/spf.rb +0 -15
  81. data/spec/dns/resolv_client_spec.rb +0 -307
@@ -128,6 +128,14 @@ tests:
128
128
  host: 192.0.2.3
129
129
  mailfrom: "foobar@ctrl.example.com"
130
130
  result: permerror
131
+ two-spaces:
132
+ description: >-
133
+ ABNF for term separation is one or more spaces, not just one.
134
+ spec: 4.6.1
135
+ helo: hosed
136
+ host: 1.2.3.4
137
+ mailfrom: "actually@fine.example.com"
138
+ result: fail
131
139
  zonedata:
132
140
  example.com:
133
141
  - TIMEOUT
@@ -151,6 +159,8 @@ zonedata:
151
159
  ctrl.example.com:
152
160
  - TXT: "v=spf1 a:ctrl.example.com\x0dptr -all"
153
161
  - A: 192.0.2.3
162
+ fine.example.com:
163
+ - TXT: "v=spf1 a -all"
154
164
  ---
155
165
  description: Record lookup
156
166
  tests:
metadata CHANGED
@@ -1,124 +1,136 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: coppertone
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Peter M. Goldstein
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-09-19 00:00:00.000000000 Z
11
+ date: 2014-09-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: i18n
15
14
  requirement: !ruby/object:Gem::Requirement
16
15
  requirements:
17
- - - ">="
16
+ - - '>='
18
17
  - !ruby/object:Gem::Version
19
18
  version: '0'
20
- type: :runtime
19
+ name: dns_adapter
21
20
  prerelease: false
21
+ type: :runtime
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - ">="
24
+ - - '>='
25
25
  - !ruby/object:Gem::Version
26
26
  version: '0'
27
27
  - !ruby/object:Gem::Dependency
28
- name: addressable
29
28
  requirement: !ruby/object:Gem::Requirement
30
29
  requirements:
31
- - - ">="
30
+ - - '>='
32
31
  - !ruby/object:Gem::Version
33
32
  version: '0'
33
+ name: i18n
34
+ prerelease: false
34
35
  type: :runtime
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ requirement: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - '>='
45
+ - !ruby/object:Gem::Version
46
+ version: '0'
47
+ name: addressable
35
48
  prerelease: false
49
+ type: :runtime
36
50
  version_requirements: !ruby/object:Gem::Requirement
37
51
  requirements:
38
- - - ">="
52
+ - - '>='
39
53
  - !ruby/object:Gem::Version
40
54
  version: '0'
41
55
  - !ruby/object:Gem::Dependency
42
- name: activesupport
43
56
  requirement: !ruby/object:Gem::Requirement
44
57
  requirements:
45
- - - ">="
58
+ - - '>='
46
59
  - !ruby/object:Gem::Version
47
60
  version: '3.0'
48
- type: :runtime
61
+ name: activesupport
49
62
  prerelease: false
63
+ type: :runtime
50
64
  version_requirements: !ruby/object:Gem::Requirement
51
65
  requirements:
52
- - - ">="
66
+ - - '>='
53
67
  - !ruby/object:Gem::Version
54
68
  version: '3.0'
55
69
  - !ruby/object:Gem::Dependency
56
- name: bundler
57
70
  requirement: !ruby/object:Gem::Requirement
58
71
  requirements:
59
- - - ">="
72
+ - - '>='
60
73
  - !ruby/object:Gem::Version
61
74
  version: '0'
62
- type: :development
75
+ name: bundler
63
76
  prerelease: false
77
+ type: :development
64
78
  version_requirements: !ruby/object:Gem::Requirement
65
79
  requirements:
66
- - - ">="
80
+ - - '>='
67
81
  - !ruby/object:Gem::Version
68
82
  version: '0'
69
83
  - !ruby/object:Gem::Dependency
70
- name: rake
71
84
  requirement: !ruby/object:Gem::Requirement
72
85
  requirements:
73
- - - "~>"
86
+ - - ~>
74
87
  - !ruby/object:Gem::Version
75
88
  version: '10.0'
76
- type: :development
89
+ name: rake
77
90
  prerelease: false
91
+ type: :development
78
92
  version_requirements: !ruby/object:Gem::Requirement
79
93
  requirements:
80
- - - "~>"
94
+ - - ~>
81
95
  - !ruby/object:Gem::Version
82
96
  version: '10.0'
83
97
  - !ruby/object:Gem::Dependency
84
- name: rspec
85
98
  requirement: !ruby/object:Gem::Requirement
86
99
  requirements:
87
- - - ">="
100
+ - - '>='
88
101
  - !ruby/object:Gem::Version
89
102
  version: '3.0'
90
- type: :development
103
+ name: rspec
91
104
  prerelease: false
105
+ type: :development
92
106
  version_requirements: !ruby/object:Gem::Requirement
93
107
  requirements:
94
- - - ">="
108
+ - - '>='
95
109
  - !ruby/object:Gem::Version
96
110
  version: '3.0'
97
111
  - !ruby/object:Gem::Dependency
98
- name: rubocop
99
112
  requirement: !ruby/object:Gem::Requirement
100
113
  requirements:
101
- - - ">="
114
+ - - '>='
102
115
  - !ruby/object:Gem::Version
103
116
  version: '0'
104
- type: :development
117
+ name: rubocop
105
118
  prerelease: false
119
+ type: :development
106
120
  version_requirements: !ruby/object:Gem::Requirement
107
121
  requirements:
108
- - - ">="
122
+ - - '>='
109
123
  - !ruby/object:Gem::Version
110
124
  version: '0'
111
- description: Coppertone includes tools for parsing SPF DNS records, evaluating the
112
- result of SPF checks for received emails, and creating appropriate email headers
113
- from SPF results.
125
+ description: Coppertone includes tools for parsing SPF DNS records, evaluating the result of SPF checks for received emails, and creating appropriate email headers from SPF results.
114
126
  email:
115
127
  - peter.m.goldstein@gmail.com
116
128
  executables: []
117
129
  extensions: []
118
130
  extra_rdoc_files: []
119
131
  files:
120
- - ".gitignore"
121
- - ".travis.yml"
132
+ - .gitignore
133
+ - .travis.yml
122
134
  - Gemfile
123
135
  - LICENSE
124
136
  - README.md
@@ -127,10 +139,6 @@ files:
127
139
  - lib/coppertone.rb
128
140
  - lib/coppertone/class_builder.rb
129
141
  - lib/coppertone/directive.rb
130
- - lib/coppertone/dns.rb
131
- - lib/coppertone/dns/error.rb
132
- - lib/coppertone/dns/mock_client.rb
133
- - lib/coppertone/dns/resolv_client.rb
134
142
  - lib/coppertone/domain_spec.rb
135
143
  - lib/coppertone/error.rb
136
144
  - lib/coppertone/ip_address_wrapper.rb
@@ -161,10 +169,12 @@ files:
161
169
  - lib/coppertone/modifier/exp.rb
162
170
  - lib/coppertone/modifier/redirect.rb
163
171
  - lib/coppertone/modifier/unknown.rb
172
+ - lib/coppertone/null_macro_context.rb
164
173
  - lib/coppertone/qualifier.rb
165
174
  - lib/coppertone/record.rb
166
175
  - lib/coppertone/record_evaluator.rb
167
176
  - lib/coppertone/record_finder.rb
177
+ - lib/coppertone/record_term_parser.rb
168
178
  - lib/coppertone/request.rb
169
179
  - lib/coppertone/request_context.rb
170
180
  - lib/coppertone/request_count_limiter.rb
@@ -178,9 +188,7 @@ files:
178
188
  - lib/coppertone/utils/ip_in_domain_checker.rb
179
189
  - lib/coppertone/utils/validated_domain_finder.rb
180
190
  - lib/coppertone/version.rb
181
- - lib/resolv/dns/resource/in/spf.rb
182
191
  - spec/directive_spec.rb
183
- - spec/dns/resolv_client_spec.rb
184
192
  - spec/domain_spec_spec.rb
185
193
  - spec/ip_address_wrapper_spec.rb
186
194
  - spec/macro_context_spec.rb
@@ -197,6 +205,8 @@ files:
197
205
  - spec/mechanism/mx_spec.rb
198
206
  - spec/mechanism/ptr_spec.rb
199
207
  - spec/mechanism_spec.rb
208
+ - spec/modifier/exp_spec.rb
209
+ - spec/modifier/redirect_spec.rb
200
210
  - spec/modifier_spec.rb
201
211
  - spec/open_spf/ALL_mechanism_syntax_spec.rb
202
212
  - spec/open_spf/A_mechanism_syntax_spec.rb
@@ -233,29 +243,28 @@ homepage: https://github.com/petergoldstein/coppertone
233
243
  licenses:
234
244
  - Apache
235
245
  metadata: {}
236
- post_install_message:
246
+ post_install_message:
237
247
  rdoc_options: []
238
248
  require_paths:
239
249
  - lib
240
250
  required_ruby_version: !ruby/object:Gem::Requirement
241
251
  requirements:
242
- - - ">="
252
+ - - '>='
243
253
  - !ruby/object:Gem::Version
244
254
  version: '0'
245
255
  required_rubygems_version: !ruby/object:Gem::Requirement
246
256
  requirements:
247
- - - ">="
257
+ - - '>='
248
258
  - !ruby/object:Gem::Version
249
259
  version: '0'
250
260
  requirements: []
251
- rubyforge_project:
252
- rubygems_version: 2.4.1
253
- signing_key:
261
+ rubyforge_project:
262
+ rubygems_version: 2.1.9
263
+ signing_key:
254
264
  specification_version: 4
255
265
  summary: A Sender Policy Framework (SPF) toolkit
256
266
  test_files:
257
267
  - spec/directive_spec.rb
258
- - spec/dns/resolv_client_spec.rb
259
268
  - spec/domain_spec_spec.rb
260
269
  - spec/ip_address_wrapper_spec.rb
261
270
  - spec/macro_context_spec.rb
@@ -272,6 +281,8 @@ test_files:
272
281
  - spec/mechanism/mx_spec.rb
273
282
  - spec/mechanism/ptr_spec.rb
274
283
  - spec/mechanism_spec.rb
284
+ - spec/modifier/exp_spec.rb
285
+ - spec/modifier/redirect_spec.rb
275
286
  - spec/modifier_spec.rb
276
287
  - spec/open_spf/ALL_mechanism_syntax_spec.rb
277
288
  - spec/open_spf/A_mechanism_syntax_spec.rb
@@ -1,9 +0,0 @@
1
- require 'coppertone/error'
2
-
3
- module Coppertone
4
- module DNS
5
- class Error < ::Coppertone::TemperrorError; end
6
- class TimeoutError < Error; end
7
- class NXDomainError < Error; end
8
- end
9
- end
@@ -1,106 +0,0 @@
1
- require 'coppertone/error'
2
-
3
- module Coppertone
4
- module DNS
5
- # A mock client for use in tests.
6
- class MockClient
7
- def initialize(zone_data)
8
- @zone_data = {}
9
- zone_data.each do |k, v|
10
- @zone_data[k.downcase] = v.dup
11
- end
12
- end
13
-
14
- def fetch_a_records(domain)
15
- fetch_records(domain, 'A')
16
- end
17
-
18
- def fetch_aaaa_records(domain)
19
- fetch_records(domain, 'AAAA')
20
- end
21
-
22
- def fetch_mx_records(domain)
23
- fetch_records(domain, 'MX')
24
- end
25
-
26
- def fetch_ptr_records(arpa_address)
27
- fetch_records(arpa_address, 'PTR')
28
- end
29
-
30
- def fetch_txt_records(domain)
31
- fetch_records(domain, 'TXT')
32
- end
33
-
34
- def fetch_spf_records(domain)
35
- fetch_records(domain, 'SPF')
36
- end
37
-
38
- def fetch_records(domain, type)
39
- record_set = find_records_for_domain(domain)
40
- return [] if record_set.empty?
41
- records = records_for_type(record_set, type)
42
- if records.empty?
43
- check_for_timeout(record_set)
44
- else
45
- formatted_records(records, type)
46
- end
47
- end
48
-
49
- private
50
-
51
- def normalize_domain(domain)
52
- return if domain.blank?
53
- domain = domain[0...-1] if domain[domain.length - 1] == '.'
54
- domain.downcase
55
- end
56
-
57
- def find_records_for_domain(domain)
58
- return [] if domain.blank?
59
- @zone_data[normalize_domain(domain)] || []
60
- end
61
-
62
- def records_for_type(record_set, type)
63
- record_set.select do |r|
64
- r.is_a?(Hash) && r[type] && r[type] != 'NONE'
65
- end
66
- end
67
-
68
- TIMEOUT = 'TIMEOUT'
69
- def check_for_timeout(record_set)
70
- return [] if record_set.select { |r| r == TIMEOUT }.empty?
71
- fail Coppertone::DNS::TimeoutError
72
- end
73
-
74
- RECORD_TYPE_TO_ATTR_NAME_MAP = {
75
- 'A' => :address,
76
- 'AAAA' => :address,
77
- 'MX' => :exchange,
78
- 'PTR' => :name,
79
- 'SPF' => :text,
80
- 'TXT' => :text
81
- }
82
-
83
- def formatted_records(records, type)
84
- records.map do |r|
85
- val = r[type]
86
- fail Coppertone::DNS::TimeoutError if val == TIMEOUT
87
- val = normalize_value(val, type)
88
- {
89
- type: type,
90
- RECORD_TYPE_TO_ATTR_NAME_MAP[type] => val
91
- }
92
- end
93
- end
94
-
95
- def normalize_value(value, type)
96
- if type == 'MX' && value.is_a?(Array)
97
- value.last
98
- elsif (type == 'TXT' || type == 'SPF') && value.is_a?(Array)
99
- value.join('')
100
- else
101
- value
102
- end
103
- end
104
- end
105
- end
106
- end
@@ -1,110 +0,0 @@
1
- require 'resolv'
2
- require 'resolv/dns/resource/in/spf'
3
-
4
- module Coppertone
5
- module DNS
6
- # An adapter client for the internal Resolv DNS client.
7
- class ResolvClient
8
- def fetch_a_records(domain)
9
- fetch_a_type_records(domain, 'A')
10
- end
11
-
12
- def fetch_aaaa_records(domain)
13
- fetch_a_type_records(domain, 'AAAA')
14
- end
15
-
16
- def fetch_mx_records(domain)
17
- fetch_records(domain, 'MX') do |record|
18
- {
19
- type: 'MX',
20
- exchange: record.exchange.to_s
21
- }
22
- end
23
- end
24
-
25
- def fetch_ptr_records(arpa_address)
26
- fetch_records(arpa_address, 'PTR') do |record|
27
- {
28
- type: 'PTR',
29
- name: record.name.to_s
30
- }
31
- end
32
- end
33
-
34
- def fetch_txt_records(domain)
35
- fetch_txt_type_records(domain, 'TXT')
36
- end
37
-
38
- def fetch_spf_records(domain)
39
- fetch_txt_type_records(domain, 'SPF')
40
- end
41
-
42
- private
43
-
44
- def fetch_a_type_records(domain, type)
45
- fetch_records(domain, type) do |record|
46
- {
47
- type: type,
48
- address: record.address.to_s
49
- }
50
- end
51
- end
52
-
53
- def fetch_txt_type_records(domain, type)
54
- fetch_records(domain, type) do |record|
55
- {
56
- type: type,
57
- # Use strings.join('') to avoid JRuby issue where
58
- # data only returns the first string
59
- text: record.strings.join('')
60
- }
61
- end
62
- end
63
-
64
- def fetch_records(domain, type, &block)
65
- records = dns_lookup(domain, type)
66
- records.map(&block)
67
- end
68
-
69
- TRAILING_DOT_REGEXP = /\.\z/
70
- def normalize_domain(domain)
71
- (domain.sub(TRAILING_DOT_REGEXP, '') || domain).downcase
72
- end
73
-
74
- def dns_lookup(domain, rr_type)
75
- domain = normalize_domain(domain)
76
- resources = getresources(domain, rr_type)
77
-
78
- unless resources
79
- fail Coppertone::DNS::Error,
80
- "Unknown error on DNS '#{rr_type}' lookup of '#{domain}'"
81
- end
82
-
83
- resources
84
- end
85
-
86
- def getresources(domain, rr_type)
87
- rr_class = self.class.type_class(rr_type)
88
- dns_resolver.getresources(domain, rr_class)
89
- rescue Resolv::ResolvTimeout
90
- raise Coppertone::DNS::TimeoutError,
91
- "Time-out on DNS '#{rr_type}' lookup of '#{domain}'"
92
- rescue Resolv::ResolvError
93
- raise Coppertone::DNS::Error, "Error on DNS lookup of '#{domain}'"
94
- end
95
-
96
- SUPPORTED_RR_TYPES = %w(A AAAA MX PTR TXT SPF)
97
- def self.type_class(rr_type)
98
- if SUPPORTED_RR_TYPES.include?(rr_type)
99
- Resolv::DNS::Resource::IN.const_get(rr_type)
100
- else
101
- fail ArgumentError, "Unknown RR type: #{rr_type}"
102
- end
103
- end
104
-
105
- def dns_resolver
106
- @dns_resolver ||= Resolv::DNS.new
107
- end
108
- end
109
- end
110
- end
@@ -1,3 +0,0 @@
1
- require 'coppertone/dns/error'
2
- require 'coppertone/dns/resolv_client'
3
- require 'coppertone/dns/mock_client'
@@ -1,15 +0,0 @@
1
- require 'resolv'
2
-
3
- class Resolv
4
- class DNS
5
- class Resource
6
- module IN
7
- # DNS record type for SPF records
8
- class SPF < Resolv::DNS::Resource::IN::TXT
9
- # resolv.rb doesn't define an SPF resource type.
10
- TypeValue = 99 # rubocop:disable Style/ConstantName
11
- end
12
- end
13
- end
14
- end
15
- end