coppertone 0.0.3 → 0.0.4
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 +4 -4
- data/.travis.yml +3 -1
- data/lib/coppertone/directive.rb +7 -2
- data/lib/coppertone/error.rb +4 -0
- data/lib/coppertone/macro_string.rb +5 -0
- data/lib/coppertone/mechanism/domain_spec_mechanism.rb +15 -0
- data/lib/coppertone/mechanism/domain_spec_optional.rb +0 -5
- data/lib/coppertone/mechanism/domain_spec_required.rb +0 -5
- data/lib/coppertone/mechanism/domain_spec_with_dual_cidr.rb +10 -16
- data/lib/coppertone/mechanism/include.rb +0 -9
- data/lib/coppertone/mechanism/ip_mechanism.rb +7 -7
- data/lib/coppertone/modifier/redirect.rb +3 -5
- data/lib/coppertone/modifier/unknown.rb +3 -10
- data/lib/coppertone/modifier.rb +10 -2
- data/lib/coppertone/record.rb +29 -22
- data/lib/coppertone/record_term_parser.rb +5 -11
- data/lib/coppertone/terms_parser.rb +23 -0
- data/lib/coppertone/utils/domain_utils.rb +5 -0
- data/lib/coppertone/version.rb +1 -1
- data/lib/coppertone.rb +1 -0
- data/spec/directive_spec.rb +33 -0
- data/spec/mechanism/a_spec.rb +5 -0
- data/spec/mechanism/all_spec.rb +1 -0
- data/spec/mechanism/exists_spec.rb +3 -0
- data/spec/mechanism/include_spec.rb +10 -0
- data/spec/mechanism/ip4_spec.rb +9 -6
- data/spec/mechanism/ip6_spec.rb +9 -6
- data/spec/mechanism/mx_spec.rb +9 -0
- data/spec/mechanism/ptr_spec.rb +2 -0
- data/spec/modifier/redirect_spec.rb +22 -0
- data/spec/modifier/unknown_spec.rb +10 -0
- data/spec/null_macro_context_spec.rb +22 -0
- data/spec/qualifier_spec.rb +10 -0
- data/spec/record_spec.rb +26 -0
- metadata +51 -44
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 98149a0b1ea7cda00c82becc04efa776fe05d04c
|
4
|
+
data.tar.gz: 4b5c342217d8ea99622fc3b7e0d75a2d49d008b5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3e739ea5580ee84d251ffae5f170d1116e40a5c789b94320878727de04c4a3dc8e6ea00641e14a0454c8aba087b9579c133362b1075ca20d1a25cdbc3188e2ff
|
7
|
+
data.tar.gz: 89ce502d95dd1e60dafe3398d39788548f70758f3b435e3949f9fe7d62bc9356d12765b4898dd96d24eb6db76a6824dabbb74f0c5e05705c7ba015702092d9a3
|
data/.travis.yml
CHANGED
data/lib/coppertone/directive.rb
CHANGED
@@ -1,11 +1,15 @@
|
|
1
1
|
require 'coppertone/mechanism'
|
2
2
|
require 'coppertone/qualifier'
|
3
|
+
require 'active_support/core_ext/module/delegation'
|
3
4
|
|
4
5
|
module Coppertone
|
5
6
|
# Instances of this class represent directive terms, as defined by the
|
6
7
|
# SPF specification (see section 4.6.1).
|
7
8
|
class Directive
|
8
9
|
attr_reader :qualifier, :mechanism
|
10
|
+
delegate :context_dependent?, :dns_lookup_term?,
|
11
|
+
:includes_ptr?, to: :mechanism
|
12
|
+
|
9
13
|
def initialize(qualifier, mechanism)
|
10
14
|
@qualifier = qualifier
|
11
15
|
@mechanism = mechanism
|
@@ -19,8 +23,9 @@ module Coppertone
|
|
19
23
|
end
|
20
24
|
end
|
21
25
|
|
22
|
-
def
|
23
|
-
|
26
|
+
def target_domain
|
27
|
+
fail NeedsContextError unless dns_lookup_term?
|
28
|
+
mechanism.target_domain
|
24
29
|
end
|
25
30
|
|
26
31
|
def all?
|
data/lib/coppertone/error.rb
CHANGED
@@ -45,4 +45,8 @@ module Coppertone
|
|
45
45
|
class TermLimitExceededError < PermerrorError; end
|
46
46
|
class VoidLimitExceededError < PermerrorError; end
|
47
47
|
class MXLimitExceededError < PermerrorError; end
|
48
|
+
|
49
|
+
# Raised when context is required to evaluate a value, but
|
50
|
+
# context is not available
|
51
|
+
class NeedsContextError < Coppertone::Error; end
|
48
52
|
end
|
@@ -27,6 +27,21 @@ module Coppertone
|
|
27
27
|
return false unless domain_spec
|
28
28
|
domain_spec.includes_ptr?
|
29
29
|
end
|
30
|
+
|
31
|
+
def target_domain
|
32
|
+
fail Coppertone::NeedsContextError if context_dependent?
|
33
|
+
domain_spec.to_s
|
34
|
+
end
|
35
|
+
|
36
|
+
def ==(other)
|
37
|
+
return false unless other.instance_of? self.class
|
38
|
+
domain_spec == other.domain_spec
|
39
|
+
end
|
40
|
+
alias_method :eql?, :==
|
41
|
+
|
42
|
+
def hash
|
43
|
+
domain_spec.hash
|
44
|
+
end
|
30
45
|
end
|
31
46
|
end
|
32
47
|
end
|
@@ -25,14 +25,6 @@ module Coppertone
|
|
25
25
|
@ip_v6_cidr_length ||= 128
|
26
26
|
end
|
27
27
|
|
28
|
-
def cidr_length(macro_context)
|
29
|
-
if macro_context.original_ip_v6?
|
30
|
-
ip_v6_cidr_length
|
31
|
-
else
|
32
|
-
ip_v4_cidr_length
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
28
|
def match?(macro_context, request_context)
|
37
29
|
request_context.register_dns_lookup_term
|
38
30
|
target_name = generate_target_name(macro_context, request_context)
|
@@ -47,6 +39,7 @@ module Coppertone
|
|
47
39
|
def parse_argument(attributes)
|
48
40
|
fail InvalidMechanismError if attributes.blank?
|
49
41
|
cidr_matches = CIDR_REGEXP.match(attributes)
|
42
|
+
fail InvalidMechanismError unless cidr_matches
|
50
43
|
macro_string, raw_ip_v4_cidr_length, raw_ip_v6_cidr_length =
|
51
44
|
clean_matches(attributes, cidr_matches)
|
52
45
|
process_matches(macro_string, raw_ip_v4_cidr_length,
|
@@ -65,14 +58,10 @@ module Coppertone
|
|
65
58
|
end
|
66
59
|
|
67
60
|
def clean_matches(attributes, cidr_matches)
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
domain_spec_end = term.blank? ? -1 : (-1 - term.length)
|
73
|
-
else
|
74
|
-
domain_spec_end = -1
|
75
|
-
end
|
61
|
+
raw_ip_v4_cidr_length = cidr_matches[2] unless cidr_matches[2].blank?
|
62
|
+
raw_ip_v6_cidr_length = cidr_matches[4] unless cidr_matches[4].blank?
|
63
|
+
term = cidr_matches[0]
|
64
|
+
domain_spec_end = term.blank? ? -1 : (-1 - term.length)
|
76
65
|
macro_string = parse_domain_spec(attributes, domain_spec_end)
|
77
66
|
[macro_string, raw_ip_v4_cidr_length, raw_ip_v6_cidr_length]
|
78
67
|
end
|
@@ -110,6 +99,11 @@ module Coppertone
|
|
110
99
|
ip_v4_cidr_length == other.ip_v4_cidr_length &&
|
111
100
|
ip_v6_cidr_length == other.ip_v6_cidr_length
|
112
101
|
end
|
102
|
+
alias_method :eql?, :==
|
103
|
+
|
104
|
+
def hash
|
105
|
+
domain_spec.hash ^ ip_v4_cidr_length.hash ^ ip_v6_cidr_length.hash
|
106
|
+
end
|
113
107
|
end
|
114
108
|
end
|
115
109
|
end
|
@@ -21,15 +21,6 @@ module Coppertone
|
|
21
21
|
RecordFinder.new(request_context.dns_client, target_name).record
|
22
22
|
end
|
23
23
|
|
24
|
-
def context_dependent_result?(request_context,
|
25
|
-
macro_context =
|
26
|
-
Coppertone::NullMacroContext.new)
|
27
|
-
target_name =
|
28
|
-
target_name_from_domain_spec(macro_context, request_context)
|
29
|
-
included_record(request_context, target_name)
|
30
|
-
.context_dependent_result?(request_context)
|
31
|
-
end
|
32
|
-
|
33
24
|
def self.label
|
34
25
|
'include'
|
35
26
|
end
|
@@ -2,7 +2,7 @@ module Coppertone
|
|
2
2
|
class Mechanism # rubocop:disable Style/Documentation
|
3
3
|
# Implements the ip4 mechanism.
|
4
4
|
class IPMechanism < Mechanism
|
5
|
-
attr_reader :
|
5
|
+
attr_reader :netblock
|
6
6
|
def self.create(attributes)
|
7
7
|
new(attributes)
|
8
8
|
end
|
@@ -11,9 +11,9 @@ module Coppertone
|
|
11
11
|
super(attributes)
|
12
12
|
unless attributes.blank?
|
13
13
|
attributes = attributes[1..-1] if attributes[0] == ':'
|
14
|
-
@
|
14
|
+
@netblock = parse_netblock(attributes)
|
15
15
|
end
|
16
|
-
fail Coppertone::InvalidMechanismError if @
|
16
|
+
fail Coppertone::InvalidMechanismError if @netblock.nil?
|
17
17
|
end
|
18
18
|
|
19
19
|
LEADING_ZEROES_IN_CIDR_REGEXP = /\/0\d/
|
@@ -29,7 +29,7 @@ module Coppertone
|
|
29
29
|
IP_PARSE_ERROR = IPAddr::Error
|
30
30
|
end
|
31
31
|
|
32
|
-
def
|
32
|
+
def parse_netblock(ip_as_s)
|
33
33
|
validate_no_leading_zeroes_in_cidr(ip_as_s)
|
34
34
|
addr, cidr_length, dual = ip_as_s.split('/')
|
35
35
|
return nil if dual
|
@@ -43,13 +43,13 @@ module Coppertone
|
|
43
43
|
def match?(macro_context, _request_context)
|
44
44
|
ip = ip_for_match(macro_context)
|
45
45
|
return false unless ip
|
46
|
-
return false unless ip.ipv4? == @
|
47
|
-
@
|
46
|
+
return false unless ip.ipv4? == @netblock.ipv4?
|
47
|
+
@netblock.include?(ip)
|
48
48
|
end
|
49
49
|
|
50
50
|
def ==(other)
|
51
51
|
return false unless other.instance_of? self.class
|
52
|
-
|
52
|
+
netblock == other.netblock
|
53
53
|
end
|
54
54
|
end
|
55
55
|
end
|
@@ -16,11 +16,9 @@ module Coppertone
|
|
16
16
|
RedirectRecordFinder.new(self, macro_context, request_context).record
|
17
17
|
end
|
18
18
|
|
19
|
-
def
|
20
|
-
|
21
|
-
|
22
|
-
included_record(macro_context, request_context)
|
23
|
-
.context_dependent_result?(request_context)
|
19
|
+
def target_domain
|
20
|
+
fail NeedsContextError if context_dependent?
|
21
|
+
arguments
|
24
22
|
end
|
25
23
|
|
26
24
|
def self.label
|
@@ -1,12 +1,10 @@
|
|
1
1
|
module Coppertone
|
2
2
|
class Modifier # rubocop:disable Style/Documentation
|
3
3
|
class Unknown < Modifier
|
4
|
-
|
5
|
-
|
6
|
-
end
|
7
|
-
|
8
|
-
def initialize(attributes)
|
4
|
+
attr_reader :label
|
5
|
+
def initialize(label, attributes)
|
9
6
|
super(attributes)
|
7
|
+
@label = label
|
10
8
|
@macro_string = Coppertone::MacroString.new(attributes)
|
11
9
|
rescue Coppertone::MacroStringParsingError
|
12
10
|
raise Coppertone::InvalidModifierError
|
@@ -19,11 +17,6 @@ module Coppertone
|
|
19
17
|
def includes_ptr?
|
20
18
|
false
|
21
19
|
end
|
22
|
-
|
23
|
-
def self.label
|
24
|
-
'unknown'
|
25
|
-
end
|
26
20
|
end
|
27
|
-
register(Coppertone::Modifier::Unknown)
|
28
21
|
end
|
29
22
|
end
|
data/lib/coppertone/modifier.rb
CHANGED
@@ -20,7 +20,11 @@ module Coppertone
|
|
20
20
|
return nil unless matches
|
21
21
|
type = matches[1]
|
22
22
|
attributes = matches[2]
|
23
|
-
build(type, attributes) ||
|
23
|
+
build(type, attributes) || build_unknown(type, attributes)
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.build_unknown(type, attributes)
|
27
|
+
Coppertone::Modifier::Unknown.new(type, attributes)
|
24
28
|
end
|
25
29
|
|
26
30
|
attr_reader :arguments
|
@@ -28,8 +32,12 @@ module Coppertone
|
|
28
32
|
@arguments = arguments
|
29
33
|
end
|
30
34
|
|
35
|
+
def label
|
36
|
+
self.class.label
|
37
|
+
end
|
38
|
+
|
31
39
|
def to_s
|
32
|
-
"#{
|
40
|
+
"#{label}=#{arguments}"
|
33
41
|
end
|
34
42
|
end
|
35
43
|
end
|
data/lib/coppertone/record.rb
CHANGED
@@ -29,13 +29,12 @@ module Coppertone
|
|
29
29
|
all_directive ? true : false
|
30
30
|
end
|
31
31
|
|
32
|
-
def
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
include_all?
|
32
|
+
def dns_lookup_term_count
|
33
|
+
@dns_lookup_term_count ||=
|
34
|
+
begin
|
35
|
+
base = redirect.nil? ? 0 : 1
|
36
|
+
base + directives.select(&:dns_lookup_term?).size
|
37
|
+
end
|
39
38
|
end
|
40
39
|
|
41
40
|
def includes
|
@@ -51,32 +50,36 @@ module Coppertone
|
|
51
50
|
@modifiers ||= @terms.select { |t| t.is_a?(Coppertone::Modifier) }
|
52
51
|
end
|
53
52
|
|
54
|
-
def find_redirect
|
55
|
-
find_modifier(Coppertone::Modifier::Redirect)
|
56
|
-
end
|
57
|
-
|
58
53
|
def redirect
|
59
54
|
@redirect ||= find_redirect
|
60
55
|
end
|
61
56
|
|
62
|
-
def
|
63
|
-
|
57
|
+
def redirect_with_directives?
|
58
|
+
redirect && directives.any?
|
64
59
|
end
|
65
60
|
|
66
|
-
def
|
61
|
+
def netblock_mechanisms
|
62
|
+
@netblock_mechanisms ||=
|
63
|
+
directives.select { |d| d.mechanism.is_a?(Coppertone::Mechanism::IPMechanism) }
|
64
|
+
end
|
65
|
+
|
66
|
+
def netblocks_only?
|
67
|
+
return false if redirect
|
68
|
+
directives.reject(&:all?).reject do |d|
|
69
|
+
d.mechanism.is_a?(Coppertone::Mechanism::IPMechanism)
|
70
|
+
end.empty?
|
71
|
+
end
|
72
|
+
|
73
|
+
def context_dependent_evaluation?
|
67
74
|
return true if directives.exist?(&:context_dependent)
|
68
|
-
|
69
|
-
return false if includes.blank?
|
70
|
-
includes.exists? { |i| i.context_dependent_result?(request_context) }
|
75
|
+
redirect && redirect.context_dependent?
|
71
76
|
end
|
72
77
|
|
73
|
-
def
|
74
|
-
|
75
|
-
redirect.context_dependent? ||
|
76
|
-
redirect.context_dependent_result?(request_context)
|
78
|
+
def exp
|
79
|
+
@exp ||= find_modifier(Coppertone::Modifier::Exp)
|
77
80
|
end
|
78
81
|
|
79
|
-
def
|
82
|
+
def context_dependent_explanation?
|
80
83
|
exp && exp.context_dependent?
|
81
84
|
end
|
82
85
|
|
@@ -93,6 +96,10 @@ module Coppertone
|
|
93
96
|
arr.first
|
94
97
|
end
|
95
98
|
|
99
|
+
def find_redirect
|
100
|
+
find_modifier(Coppertone::Modifier::Redirect)
|
101
|
+
end
|
102
|
+
|
96
103
|
def self.version_str
|
97
104
|
Coppertone::RecordTermParser::VERSION_STR
|
98
105
|
end
|
@@ -10,22 +10,16 @@ module Coppertone
|
|
10
10
|
RECORD_REGEXP.match(text.strip) ? true : false
|
11
11
|
end
|
12
12
|
|
13
|
-
attr_reader :terms
|
13
|
+
attr_reader :text, :terms
|
14
14
|
def initialize(text)
|
15
15
|
fail RecordParsingError unless self.class.record?(text)
|
16
16
|
fail RecordParsingError unless ALLOWED_CHARACTERS.match(text)
|
17
|
-
@
|
17
|
+
@text = text
|
18
|
+
@terms = Coppertone::TermsParser.new(terms_segment).terms
|
18
19
|
end
|
19
20
|
|
20
|
-
def
|
21
|
-
|
22
|
-
text_without_prefix.strip.split(/ /).select { |s| !s.blank? }
|
23
|
-
end
|
24
|
-
|
25
|
-
def parse_token(token)
|
26
|
-
term = Term.build_from_token(token)
|
27
|
-
fail RecordParsingError unless term
|
28
|
-
term
|
21
|
+
def terms_segment
|
22
|
+
text[VERSION_STR.length..-1].strip
|
29
23
|
end
|
30
24
|
end
|
31
25
|
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Coppertone
|
2
|
+
# Parses a un-prefixed string into terms
|
3
|
+
class TermsParser
|
4
|
+
attr_reader :text
|
5
|
+
def initialize(text)
|
6
|
+
@text = text
|
7
|
+
end
|
8
|
+
|
9
|
+
def terms
|
10
|
+
tokens.map { |token| parse_token(token) }
|
11
|
+
end
|
12
|
+
|
13
|
+
def tokens
|
14
|
+
text.split(/ /).select { |s| !s.blank? }
|
15
|
+
end
|
16
|
+
|
17
|
+
def parse_token(token)
|
18
|
+
term = Term.build_from_token(token)
|
19
|
+
fail RecordParsingError unless term
|
20
|
+
term
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -26,6 +26,11 @@ module Coppertone
|
|
26
26
|
NO_DASH_REGEXP.match(l) || DASH_REGEXP.match(l)
|
27
27
|
end
|
28
28
|
|
29
|
+
def self.valid_ldh_domain?(domain)
|
30
|
+
return false unless valid?(domain)
|
31
|
+
to_labels(domain).all? { |l| valid_hostname_label?(l) }
|
32
|
+
end
|
33
|
+
|
29
34
|
def self.valid_label?(l)
|
30
35
|
(l.length >= 0) && (l.length <= 63)
|
31
36
|
end
|
data/lib/coppertone/version.rb
CHANGED
data/lib/coppertone.rb
CHANGED
@@ -42,6 +42,7 @@ require 'coppertone/domain_spec'
|
|
42
42
|
require 'coppertone/directive'
|
43
43
|
require 'coppertone/modifier'
|
44
44
|
require 'coppertone/term'
|
45
|
+
require 'coppertone/terms_parser'
|
45
46
|
require 'coppertone/record_term_parser'
|
46
47
|
require 'coppertone/record'
|
47
48
|
require 'coppertone/record_evaluator'
|
data/spec/directive_spec.rb
CHANGED
@@ -51,4 +51,37 @@ describe Coppertone::Directive do
|
|
51
51
|
end
|
52
52
|
end
|
53
53
|
end
|
54
|
+
|
55
|
+
context '#target_domain' do
|
56
|
+
it 'yields the target domain when the mechanism is not context dependent' do
|
57
|
+
d = Coppertone::Term.build_from_token('include:_spf.example.org')
|
58
|
+
expect(d.target_domain).to eq('_spf.example.org')
|
59
|
+
end
|
60
|
+
|
61
|
+
it 'raises an error when the mechanism is context dependent' do
|
62
|
+
d = Coppertone::Term.build_from_token('include:_spf.%{h}.example.org')
|
63
|
+
expect do
|
64
|
+
d.target_domain
|
65
|
+
end.to raise_error Coppertone::NeedsContextError
|
66
|
+
end
|
67
|
+
|
68
|
+
it 'raises an error when the mechanism does not support a target domain' do
|
69
|
+
d = Coppertone::Term.build_from_token('ip4:1.2.3.4')
|
70
|
+
expect do
|
71
|
+
d.target_domain
|
72
|
+
end.to raise_error Coppertone::NeedsContextError
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
context '#to_s' do
|
77
|
+
it 'should hide a default qualifier' do
|
78
|
+
d = Coppertone::Term.build_from_token('~include:_spf.%{h}.example.org')
|
79
|
+
expect(d.to_s).to eq('~include:_spf.%{h}.example.org')
|
80
|
+
end
|
81
|
+
|
82
|
+
it 'should hide a default qualifier' do
|
83
|
+
d = Coppertone::Term.build_from_token('+include:_spf.%{h}.example.org')
|
84
|
+
expect(d.to_s).to eq('include:_spf.%{h}.example.org')
|
85
|
+
end
|
86
|
+
end
|
54
87
|
end
|
data/spec/mechanism/a_spec.rb
CHANGED
@@ -11,6 +11,7 @@ describe Coppertone::Mechanism::A do
|
|
11
11
|
expect(mech.to_s).to eq('a')
|
12
12
|
expect(mech).not_to be_includes_ptr
|
13
13
|
expect(mech).to be_context_dependent
|
14
|
+
expect(mech).to be_dns_lookup_term
|
14
15
|
end
|
15
16
|
|
16
17
|
it 'should not fail if called with a blank argument' do
|
@@ -22,6 +23,7 @@ describe Coppertone::Mechanism::A do
|
|
22
23
|
expect(mech.to_s).to eq('a')
|
23
24
|
expect(mech).not_to be_includes_ptr
|
24
25
|
expect(mech).to be_context_dependent
|
26
|
+
expect(mech).to be_dns_lookup_term
|
25
27
|
end
|
26
28
|
|
27
29
|
it 'should fail if called with an invalid macrostring' do
|
@@ -40,6 +42,7 @@ describe Coppertone::Mechanism::A do
|
|
40
42
|
expect(mech.to_s).to eq('a:_spf.example.com')
|
41
43
|
expect(mech).not_to be_includes_ptr
|
42
44
|
expect(mech).not_to be_context_dependent
|
45
|
+
expect(mech).to be_dns_lookup_term
|
43
46
|
end
|
44
47
|
|
45
48
|
it 'should parse a context dependent domain spec' do
|
@@ -52,6 +55,7 @@ describe Coppertone::Mechanism::A do
|
|
52
55
|
expect(mech.to_s).to eq('a:_spf.%{d}.example.com')
|
53
56
|
expect(mech).not_to be_includes_ptr
|
54
57
|
expect(mech).to be_context_dependent
|
58
|
+
expect(mech).to be_dns_lookup_term
|
55
59
|
end
|
56
60
|
|
57
61
|
it 'should parse a domain spec with a ptr' do
|
@@ -64,6 +68,7 @@ describe Coppertone::Mechanism::A do
|
|
64
68
|
expect(mech.to_s).to eq('a:_spf.%{p}.example.com')
|
65
69
|
expect(mech).to be_includes_ptr
|
66
70
|
expect(mech).to be_context_dependent
|
71
|
+
expect(mech).to be_dns_lookup_term
|
67
72
|
end
|
68
73
|
|
69
74
|
it 'should parse a valid IP v4 CIDR length with a domain spec' do
|
data/spec/mechanism/all_spec.rb
CHANGED
@@ -7,6 +7,7 @@ describe Coppertone::Mechanism::All do
|
|
7
7
|
expect(subject.to_s).to eq('all')
|
8
8
|
expect(subject).not_to be_includes_ptr
|
9
9
|
expect(subject).not_to be_context_dependent
|
10
|
+
expect(subject).not_to be_dns_lookup_term
|
10
11
|
end
|
11
12
|
|
12
13
|
it 'should not allow creation of new instances' do
|
@@ -28,6 +28,7 @@ describe Coppertone::Mechanism::Exists do
|
|
28
28
|
expect(mech.to_s).to eq('exists:_spf.example.com')
|
29
29
|
expect(mech).not_to be_includes_ptr
|
30
30
|
expect(mech).not_to be_context_dependent
|
31
|
+
expect(mech).to be_dns_lookup_term
|
31
32
|
end
|
32
33
|
|
33
34
|
it 'should parse a context dependent domain spec' do
|
@@ -38,6 +39,7 @@ describe Coppertone::Mechanism::Exists do
|
|
38
39
|
expect(mech.to_s).to eq('exists:_spf.%{d}.example.com')
|
39
40
|
expect(mech).not_to be_includes_ptr
|
40
41
|
expect(mech).to be_context_dependent
|
42
|
+
expect(mech).to be_dns_lookup_term
|
41
43
|
end
|
42
44
|
|
43
45
|
it 'should parse a domain spec with a ptr' do
|
@@ -48,6 +50,7 @@ describe Coppertone::Mechanism::Exists do
|
|
48
50
|
expect(mech.to_s).to eq('exists:_spf.%{p}.example.com')
|
49
51
|
expect(mech).to be_includes_ptr
|
50
52
|
expect(mech).to be_context_dependent
|
53
|
+
expect(mech).to be_dns_lookup_term
|
51
54
|
end
|
52
55
|
end
|
53
56
|
|
@@ -28,6 +28,8 @@ describe Coppertone::Mechanism::Include do
|
|
28
28
|
expect(mech.to_s).to eq('include:_spf.example.com')
|
29
29
|
expect(mech).not_to be_includes_ptr
|
30
30
|
expect(mech).not_to be_context_dependent
|
31
|
+
expect(mech).to be_dns_lookup_term
|
32
|
+
expect(mech.target_domain).to eq('_spf.example.com')
|
31
33
|
end
|
32
34
|
|
33
35
|
it 'should parse a context dependent domain spec' do
|
@@ -38,6 +40,10 @@ describe Coppertone::Mechanism::Include do
|
|
38
40
|
expect(mech.to_s).to eq('include:_spf.%{d}.example.com')
|
39
41
|
expect(mech).not_to be_includes_ptr
|
40
42
|
expect(mech).to be_context_dependent
|
43
|
+
expect(mech).to be_dns_lookup_term
|
44
|
+
expect do
|
45
|
+
mech.target_domain
|
46
|
+
end.to raise_error Coppertone::NeedsContextError
|
41
47
|
end
|
42
48
|
|
43
49
|
it 'should parse a domain spec with a ptr' do
|
@@ -48,6 +54,10 @@ describe Coppertone::Mechanism::Include do
|
|
48
54
|
expect(mech.to_s).to eq('include:_spf.%{p}.example.com')
|
49
55
|
expect(mech).to be_includes_ptr
|
50
56
|
expect(mech).to be_context_dependent
|
57
|
+
expect(mech).to be_dns_lookup_term
|
58
|
+
expect do
|
59
|
+
mech.target_domain
|
60
|
+
end.to raise_error Coppertone::NeedsContextError
|
51
61
|
end
|
52
62
|
end
|
53
63
|
|
data/spec/mechanism/ip4_spec.rb
CHANGED
@@ -22,26 +22,29 @@ describe Coppertone::Mechanism::IP4 do
|
|
22
22
|
|
23
23
|
it 'should not fail if called with an IP v6' do
|
24
24
|
mech = Coppertone::Mechanism::IP4.new(':fe80::202:b3ff:fe1e:8329')
|
25
|
-
expect(mech.
|
25
|
+
expect(mech.netblock).to eq(IPAddr.new('fe80::202:b3ff:fe1e:8329'))
|
26
26
|
expect(mech.to_s).to eq('ip4:fe80::202:b3ff:fe1e:8329')
|
27
27
|
expect(mech).not_to be_includes_ptr
|
28
28
|
expect(mech).not_to be_context_dependent
|
29
|
+
expect(mech).not_to be_dns_lookup_term
|
29
30
|
end
|
30
31
|
|
31
32
|
it 'should work if called with an IP4' do
|
32
33
|
mech = Coppertone::Mechanism::IP4.new(':1.2.3.4')
|
33
|
-
expect(mech.
|
34
|
+
expect(mech.netblock).to eq(IPAddr.new('1.2.3.4'))
|
34
35
|
expect(mech.to_s).to eq('ip4:1.2.3.4')
|
35
36
|
expect(mech).not_to be_includes_ptr
|
36
37
|
expect(mech).not_to be_context_dependent
|
38
|
+
expect(mech).not_to be_dns_lookup_term
|
37
39
|
end
|
38
40
|
|
39
41
|
it 'should work if called with an IP4 with a pfxlen' do
|
40
42
|
mech = Coppertone::Mechanism::IP4.new(':1.2.3.4/4')
|
41
|
-
expect(mech.
|
43
|
+
expect(mech.netblock).to eq(IPAddr.new('1.2.3.4/4'))
|
42
44
|
expect(mech.to_s).to eq('ip4:1.2.3.4/4')
|
43
45
|
expect(mech).not_to be_includes_ptr
|
44
46
|
expect(mech).not_to be_context_dependent
|
47
|
+
expect(mech).not_to be_dns_lookup_term
|
45
48
|
end
|
46
49
|
end
|
47
50
|
|
@@ -66,17 +69,17 @@ describe Coppertone::Mechanism::IP4 do
|
|
66
69
|
|
67
70
|
it 'should not fail if called with an IP v6' do
|
68
71
|
mech = Coppertone::Mechanism::IP4.create(':fe80::202:b3ff:fe1e:8329')
|
69
|
-
expect(mech.
|
72
|
+
expect(mech.netblock).to eq(IPAddr.new('fe80::202:b3ff:fe1e:8329'))
|
70
73
|
end
|
71
74
|
|
72
75
|
it 'should work if called with an IP4' do
|
73
76
|
mech = Coppertone::Mechanism::IP4.create(':1.2.3.4')
|
74
|
-
expect(mech.
|
77
|
+
expect(mech.netblock).to eq(IPAddr.new('1.2.3.4'))
|
75
78
|
end
|
76
79
|
|
77
80
|
it 'should work if called with an IP4 with a pfxlen' do
|
78
81
|
mech = Coppertone::Mechanism::IP4.create(':1.2.3.4/4')
|
79
|
-
expect(mech.
|
82
|
+
expect(mech.netblock).to eq(IPAddr.new('1.2.3.4/4'))
|
80
83
|
end
|
81
84
|
|
82
85
|
it 'should fail if called with an invalid pfxlen' do
|
data/spec/mechanism/ip6_spec.rb
CHANGED
@@ -22,19 +22,22 @@ describe Coppertone::Mechanism::IP6 do
|
|
22
22
|
|
23
23
|
it 'should not fail if called with an IP v4' do
|
24
24
|
mech = Coppertone::Mechanism::IP6.new(':1.2.3.4')
|
25
|
-
expect(mech.
|
25
|
+
expect(mech.netblock).to eq(IPAddr.new('1.2.3.4'))
|
26
|
+
expect(mech).not_to be_dns_lookup_term
|
26
27
|
end
|
27
28
|
|
28
29
|
it 'should work if called with an IP6' do
|
29
30
|
mech = Coppertone::Mechanism::IP6.new(':fe80::202:b3ff:fe1e:8329')
|
30
|
-
expect(mech.
|
31
|
+
expect(mech.netblock)
|
31
32
|
.to eq(IPAddr.new('fe80::202:b3ff:fe1e:8329'))
|
33
|
+
expect(mech).not_to be_dns_lookup_term
|
32
34
|
end
|
33
35
|
|
34
36
|
it 'should work if called with an IP6 with a pfxlen' do
|
35
37
|
mech = Coppertone::Mechanism::IP6.new(':fe80::202:b3ff:fe1e:8329/64')
|
36
|
-
expect(mech.
|
38
|
+
expect(mech.netblock)
|
37
39
|
.to eq(IPAddr.new('fe80::202:b3ff:fe1e:8329/64'))
|
40
|
+
expect(mech).not_to be_dns_lookup_term
|
38
41
|
end
|
39
42
|
|
40
43
|
it 'should fail if called with an invalid pfxlen' do
|
@@ -66,14 +69,14 @@ describe Coppertone::Mechanism::IP6 do
|
|
66
69
|
|
67
70
|
it 'should not fail if called with an IP v4' do
|
68
71
|
mech = Coppertone::Mechanism::IP6.create(':1.2.3.4')
|
69
|
-
expect(mech.
|
72
|
+
expect(mech.netblock).to eq(IPAddr.new('1.2.3.4'))
|
70
73
|
expect(mech).not_to be_includes_ptr
|
71
74
|
expect(mech).not_to be_context_dependent
|
72
75
|
end
|
73
76
|
|
74
77
|
it 'should work if called with an IP6' do
|
75
78
|
mech = Coppertone::Mechanism::IP6.create(':fe80::202:b3ff:fe1e:8329')
|
76
|
-
expect(mech.
|
79
|
+
expect(mech.netblock)
|
77
80
|
.to eq(IPAddr.new('fe80::202:b3ff:fe1e:8329'))
|
78
81
|
expect(mech).not_to be_includes_ptr
|
79
82
|
expect(mech).not_to be_context_dependent
|
@@ -81,7 +84,7 @@ describe Coppertone::Mechanism::IP6 do
|
|
81
84
|
|
82
85
|
it 'should work if called with an IP6 with a pfxlen' do
|
83
86
|
mech = Coppertone::Mechanism::IP6.create(':fe80::202:b3ff:fe1e:8329/64')
|
84
|
-
expect(mech.
|
87
|
+
expect(mech.netblock)
|
85
88
|
.to eq(IPAddr.new('fe80::202:b3ff:fe1e:8329/64'))
|
86
89
|
expect(mech).not_to be_includes_ptr
|
87
90
|
expect(mech).not_to be_context_dependent
|
data/spec/mechanism/mx_spec.rb
CHANGED
@@ -11,6 +11,7 @@ describe Coppertone::Mechanism::MX do
|
|
11
11
|
expect(mech.to_s).to eq('mx')
|
12
12
|
expect(mech).not_to be_includes_ptr
|
13
13
|
expect(mech).to be_context_dependent
|
14
|
+
expect(mech).to be_dns_lookup_term
|
14
15
|
end
|
15
16
|
|
16
17
|
it 'should not fail if called with a blank argument' do
|
@@ -22,6 +23,7 @@ describe Coppertone::Mechanism::MX do
|
|
22
23
|
expect(mech.to_s).to eq('mx')
|
23
24
|
expect(mech).not_to be_includes_ptr
|
24
25
|
expect(mech).to be_context_dependent
|
26
|
+
expect(mech).to be_dns_lookup_term
|
25
27
|
end
|
26
28
|
|
27
29
|
it 'should fail if called with an invalid macrostring' do
|
@@ -39,6 +41,7 @@ describe Coppertone::Mechanism::MX do
|
|
39
41
|
expect(mech.to_s).to eq('mx/24')
|
40
42
|
expect(mech).not_to be_includes_ptr
|
41
43
|
expect(mech).to be_context_dependent
|
44
|
+
expect(mech).to be_dns_lookup_term
|
42
45
|
end
|
43
46
|
|
44
47
|
it 'should process the domain spec if it includes a IP v6 CIDR' do
|
@@ -61,6 +64,7 @@ describe Coppertone::Mechanism::MX do
|
|
61
64
|
expect(mech.to_s).to eq('mx/28//96')
|
62
65
|
expect(mech).not_to be_includes_ptr
|
63
66
|
expect(mech).to be_context_dependent
|
67
|
+
expect(mech).to be_dns_lookup_term
|
64
68
|
end
|
65
69
|
|
66
70
|
it 'should not fail if called with a fixed domain spec without explicit CIDRs' do
|
@@ -83,6 +87,7 @@ describe Coppertone::Mechanism::MX do
|
|
83
87
|
expect(mech.ip_v4_cidr_length).to eq(28)
|
84
88
|
expect(mech.ip_v6_cidr_length).to eq(96)
|
85
89
|
expect(mech.to_s).to eq('mx:mx.example.com/28//96')
|
90
|
+
expect(mech).to be_dns_lookup_term
|
86
91
|
end
|
87
92
|
|
88
93
|
it 'should not fail if called with a context-dependent domain spec without explicit CIDRs' do
|
@@ -95,6 +100,7 @@ describe Coppertone::Mechanism::MX do
|
|
95
100
|
expect(mech.to_s).to eq('mx:%{d}.example.com')
|
96
101
|
expect(mech).not_to be_includes_ptr
|
97
102
|
expect(mech).to be_context_dependent
|
103
|
+
expect(mech).to be_dns_lookup_term
|
98
104
|
end
|
99
105
|
|
100
106
|
it 'should not fail if called with a fixed domain spec with explicit CIDRs' do
|
@@ -107,6 +113,7 @@ describe Coppertone::Mechanism::MX do
|
|
107
113
|
expect(mech.to_s).to eq('mx:%{d}.example.com/28//96')
|
108
114
|
expect(mech).not_to be_includes_ptr
|
109
115
|
expect(mech).to be_context_dependent
|
116
|
+
expect(mech).to be_dns_lookup_term
|
110
117
|
end
|
111
118
|
|
112
119
|
it 'should not fail if called with a context-dependent domain spec without explicit CIDRs with PTR' do
|
@@ -119,6 +126,7 @@ describe Coppertone::Mechanism::MX do
|
|
119
126
|
expect(mech.to_s).to eq('mx:%{p}.example.com')
|
120
127
|
expect(mech).to be_includes_ptr
|
121
128
|
expect(mech).to be_context_dependent
|
129
|
+
expect(mech).to be_dns_lookup_term
|
122
130
|
end
|
123
131
|
|
124
132
|
it 'should not fail if called with a fixed domain spec with explicit CIDRs with PTR' do
|
@@ -131,6 +139,7 @@ describe Coppertone::Mechanism::MX do
|
|
131
139
|
expect(mech.to_s).to eq('mx:%{p}.example.com/28//96')
|
132
140
|
expect(mech).to be_includes_ptr
|
133
141
|
expect(mech).to be_context_dependent
|
142
|
+
expect(mech).to be_dns_lookup_term
|
134
143
|
end
|
135
144
|
end
|
136
145
|
|
data/spec/mechanism/ptr_spec.rb
CHANGED
@@ -8,6 +8,7 @@ describe Coppertone::Mechanism::Ptr do
|
|
8
8
|
expect(mech.domain_spec).to be_nil
|
9
9
|
expect(mech).not_to be_includes_ptr
|
10
10
|
expect(mech).to be_context_dependent
|
11
|
+
expect(mech).to be_dns_lookup_term
|
11
12
|
end
|
12
13
|
|
13
14
|
it 'should not fail if called with a blank argument' do
|
@@ -16,6 +17,7 @@ describe Coppertone::Mechanism::Ptr do
|
|
16
17
|
expect(mech.domain_spec).to be_nil
|
17
18
|
expect(mech).not_to be_includes_ptr
|
18
19
|
expect(mech).to be_context_dependent
|
20
|
+
expect(mech).to be_dns_lookup_term
|
19
21
|
end
|
20
22
|
|
21
23
|
it 'should fail if called with an invalid macrostring' do
|
@@ -11,6 +11,7 @@ describe Coppertone::Modifier::Redirect do
|
|
11
11
|
.to eq('redirect=test.example.com')
|
12
12
|
expect(modifier).not_to be_includes_ptr
|
13
13
|
expect(modifier).not_to be_context_dependent
|
14
|
+
expect(modifier.target_domain).to eq('test.example.com')
|
14
15
|
end
|
15
16
|
|
16
17
|
it 'should work with a context independent domain spec' do
|
@@ -22,6 +23,9 @@ describe Coppertone::Modifier::Redirect do
|
|
22
23
|
.to eq('redirect=%{d}.example.com')
|
23
24
|
expect(modifier).not_to be_includes_ptr
|
24
25
|
expect(modifier).to be_context_dependent
|
26
|
+
expect do
|
27
|
+
modifier.target_domain
|
28
|
+
end.to raise_error Coppertone::NeedsContextError
|
25
29
|
end
|
26
30
|
|
27
31
|
it 'should work with a context independent domain spec with a PTR' do
|
@@ -33,6 +37,9 @@ describe Coppertone::Modifier::Redirect do
|
|
33
37
|
.to eq('redirect=%{p}.example.com')
|
34
38
|
expect(modifier).to be_includes_ptr
|
35
39
|
expect(modifier).to be_context_dependent
|
40
|
+
expect do
|
41
|
+
modifier.target_domain
|
42
|
+
end.to raise_error Coppertone::NeedsContextError
|
36
43
|
end
|
37
44
|
end
|
38
45
|
|
@@ -42,4 +49,19 @@ describe Coppertone::Modifier::Redirect do
|
|
42
49
|
.to eq('redirect=test.example.com')
|
43
50
|
end
|
44
51
|
end
|
52
|
+
|
53
|
+
context '#included_record' do
|
54
|
+
it 'should delegate to included_record' do
|
55
|
+
modifier = Coppertone::Modifier::Redirect.new('test.example.com')
|
56
|
+
record = double(:record)
|
57
|
+
finder = double(:finder)
|
58
|
+
expect(finder).to receive(:record).and_return(record)
|
59
|
+
macro_ctx = double(:macro_ctx)
|
60
|
+
request_ctx = double(:request_ctx)
|
61
|
+
expect(Coppertone::RedirectRecordFinder).to receive(:new)
|
62
|
+
.with(modifier, macro_ctx, request_ctx).and_return(finder)
|
63
|
+
expect(modifier.included_record(macro_ctx, request_ctx))
|
64
|
+
.to eq(record)
|
65
|
+
end
|
66
|
+
end
|
45
67
|
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Coppertone::Modifier::Unknown do
|
4
|
+
it 'should always be context independent and never require macro evaluation' do
|
5
|
+
unk = Coppertone::Modifier::Unknown.new('abcd', 'wxyz')
|
6
|
+
expect(unk).not_to be_context_dependent
|
7
|
+
expect(unk).not_to be_includes_ptr
|
8
|
+
expect(unk.to_s).to eq('abcd=wxyz')
|
9
|
+
end
|
10
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Coppertone::NullMacroContext do
|
4
|
+
%w(s l o d i p v h c r t).each do |i|
|
5
|
+
it "should raise an error for #{i}" do
|
6
|
+
expect do
|
7
|
+
Coppertone::NullMacroContext::NULL_CONTEXT.send(i)
|
8
|
+
end.to raise_error ArgumentError
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should raise an error for #{i.upcase}" do
|
12
|
+
expect do
|
13
|
+
Coppertone::NullMacroContext::NULL_CONTEXT.send(i.upcase)
|
14
|
+
end.to raise_error ArgumentError
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'should return self for with_domain' do
|
19
|
+
n = Coppertone::NullMacroContext::NULL_CONTEXT
|
20
|
+
expect(n.with_domain('abcd')).to eq(n)
|
21
|
+
end
|
22
|
+
end
|
data/spec/qualifier_spec.rb
CHANGED
@@ -11,6 +11,7 @@ describe Coppertone::Qualifier do
|
|
11
11
|
it "should map from #{k} to the correct value" do
|
12
12
|
expect(Coppertone::Qualifier.find_by_text(k)).to eq(v)
|
13
13
|
expect(v.text).to eq(k)
|
14
|
+
expect(v.to_s).to eq(k)
|
14
15
|
end
|
15
16
|
end
|
16
17
|
end
|
@@ -22,6 +23,15 @@ describe Coppertone::Qualifier do
|
|
22
23
|
end
|
23
24
|
end
|
24
25
|
|
26
|
+
context '#default?' do
|
27
|
+
it 'should produce the right values for default?' do
|
28
|
+
expect(Coppertone::Qualifier::PASS).to be_default
|
29
|
+
expect(Coppertone::Qualifier::FAIL).not_to be_default
|
30
|
+
expect(Coppertone::Qualifier::SOFTFAIL).not_to be_default
|
31
|
+
expect(Coppertone::Qualifier::NEUTRAL).not_to be_default
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
25
35
|
context '#qualifiers' do
|
26
36
|
it 'should have the correct contents' do
|
27
37
|
qualifiers = Coppertone::Qualifier.qualifiers
|
data/spec/record_spec.rb
CHANGED
@@ -40,6 +40,7 @@ describe Coppertone::Record do
|
|
40
40
|
expect(directive.qualifier).to eq(Coppertone::Qualifier::SOFTFAIL)
|
41
41
|
expect(directive.mechanism).to eq(Coppertone::Mechanism::All.instance)
|
42
42
|
expect(record.modifiers).to be_empty
|
43
|
+
expect(record.to_s).to eq('v=spf1 ~all')
|
43
44
|
end
|
44
45
|
|
45
46
|
it 'be case insensitive when parsing the version string' do
|
@@ -50,6 +51,7 @@ describe Coppertone::Record do
|
|
50
51
|
expect(directive.qualifier).to eq(Coppertone::Qualifier::SOFTFAIL)
|
51
52
|
expect(directive.mechanism).to eq(Coppertone::Mechanism::All.instance)
|
52
53
|
expect(record.modifiers).to be_empty
|
54
|
+
expect(record.to_s).to eq('v=spf1 ~all')
|
53
55
|
end
|
54
56
|
|
55
57
|
it 'should parse more complex records' do
|
@@ -71,6 +73,7 @@ describe Coppertone::Record do
|
|
71
73
|
expect(record.redirect).to be_nil
|
72
74
|
expect(record.exp)
|
73
75
|
.to eq(Coppertone::Modifier::Exp.new('explain._spf.%{d}'))
|
76
|
+
expect(record.to_s).to eq('v=spf1 mx -all exp=explain._spf.%{d}')
|
74
77
|
end
|
75
78
|
|
76
79
|
it 'should fail on more records with duplicate modifiers' do
|
@@ -118,4 +121,27 @@ describe Coppertone::Record do
|
|
118
121
|
expect(Coppertone::Record.new('v=spf1 mx -all redirect=explain._spf.%{d}').unknown_modifiers).to be_empty
|
119
122
|
end
|
120
123
|
end
|
124
|
+
|
125
|
+
context '#dns_lookup_term_count' do
|
126
|
+
it 'should calculate correctly' do
|
127
|
+
expect(Coppertone::Record.new('v=spf1 -all exp=explain._spf.%{d}').dns_lookup_term_count).to eq(0)
|
128
|
+
expect(Coppertone::Record.new('v=spf1 a:example.test.com -exists:some.domain.com ~all').dns_lookup_term_count).to eq(2)
|
129
|
+
expect(Coppertone::Record.new('v=spf1 ip4:1.2.3.4 -exists:some.domain.com ~all').dns_lookup_term_count).to eq(1)
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
context '#includes' do
|
134
|
+
it 'should yield an empty array when there are no include' do
|
135
|
+
expect(Coppertone::Record.new('v=spf1 mx -all exp=explain._spf.%{d}').includes).to be_empty
|
136
|
+
expect(Coppertone::Record.new('v=spf1 ip4:1.2.3.4 ~all').includes).to be_empty
|
137
|
+
end
|
138
|
+
|
139
|
+
it 'should yield a set of the includes, in order' do
|
140
|
+
r = Coppertone::Record
|
141
|
+
.new('v=spf1 include:_spf.domain1.com ip4:1.2.3.4 include:_spf.domain2.com ~all exp=explain._spf.%{d}')
|
142
|
+
includes = r.includes
|
143
|
+
expect(includes.map(&:mechanism).all? {|i| i.is_a?(Coppertone::Mechanism::Include)}).to be_truthy
|
144
|
+
expect(includes.map(&:target_domain)).to eq(%w(_spf.domain1.com _spf.domain2.com))
|
145
|
+
end
|
146
|
+
end
|
121
147
|
end
|
metadata
CHANGED
@@ -1,136 +1,138 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: coppertone
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.4
|
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-
|
11
|
+
date: 2014-11-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
|
+
name: dns_adapter
|
14
15
|
requirement: !ruby/object:Gem::Requirement
|
15
16
|
requirements:
|
16
|
-
- -
|
17
|
+
- - ">="
|
17
18
|
- !ruby/object:Gem::Version
|
18
19
|
version: '0'
|
19
|
-
name: dns_adapter
|
20
|
-
prerelease: false
|
21
20
|
type: :runtime
|
21
|
+
prerelease: false
|
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: i18n
|
28
29
|
requirement: !ruby/object:Gem::Requirement
|
29
30
|
requirements:
|
30
|
-
- -
|
31
|
+
- - ">="
|
31
32
|
- !ruby/object:Gem::Version
|
32
33
|
version: '0'
|
33
|
-
name: i18n
|
34
|
-
prerelease: false
|
35
34
|
type: :runtime
|
35
|
+
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- -
|
38
|
+
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '0'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
|
+
name: addressable
|
42
43
|
requirement: !ruby/object:Gem::Requirement
|
43
44
|
requirements:
|
44
|
-
- -
|
45
|
+
- - ">="
|
45
46
|
- !ruby/object:Gem::Version
|
46
47
|
version: '0'
|
47
|
-
name: addressable
|
48
|
-
prerelease: false
|
49
48
|
type: :runtime
|
49
|
+
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
|
-
- -
|
52
|
+
- - ">="
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '0'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
|
+
name: activesupport
|
56
57
|
requirement: !ruby/object:Gem::Requirement
|
57
58
|
requirements:
|
58
|
-
- -
|
59
|
+
- - ">="
|
59
60
|
- !ruby/object:Gem::Version
|
60
61
|
version: '3.0'
|
61
|
-
name: activesupport
|
62
|
-
prerelease: false
|
63
62
|
type: :runtime
|
63
|
+
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
|
-
- -
|
66
|
+
- - ">="
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '3.0'
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
|
+
name: bundler
|
70
71
|
requirement: !ruby/object:Gem::Requirement
|
71
72
|
requirements:
|
72
|
-
- -
|
73
|
+
- - ">="
|
73
74
|
- !ruby/object:Gem::Version
|
74
75
|
version: '0'
|
75
|
-
name: bundler
|
76
|
-
prerelease: false
|
77
76
|
type: :development
|
77
|
+
prerelease: false
|
78
78
|
version_requirements: !ruby/object:Gem::Requirement
|
79
79
|
requirements:
|
80
|
-
- -
|
80
|
+
- - ">="
|
81
81
|
- !ruby/object:Gem::Version
|
82
82
|
version: '0'
|
83
83
|
- !ruby/object:Gem::Dependency
|
84
|
+
name: rake
|
84
85
|
requirement: !ruby/object:Gem::Requirement
|
85
86
|
requirements:
|
86
|
-
- - ~>
|
87
|
+
- - "~>"
|
87
88
|
- !ruby/object:Gem::Version
|
88
89
|
version: '10.0'
|
89
|
-
name: rake
|
90
|
-
prerelease: false
|
91
90
|
type: :development
|
91
|
+
prerelease: false
|
92
92
|
version_requirements: !ruby/object:Gem::Requirement
|
93
93
|
requirements:
|
94
|
-
- - ~>
|
94
|
+
- - "~>"
|
95
95
|
- !ruby/object:Gem::Version
|
96
96
|
version: '10.0'
|
97
97
|
- !ruby/object:Gem::Dependency
|
98
|
+
name: rspec
|
98
99
|
requirement: !ruby/object:Gem::Requirement
|
99
100
|
requirements:
|
100
|
-
- -
|
101
|
+
- - ">="
|
101
102
|
- !ruby/object:Gem::Version
|
102
103
|
version: '3.0'
|
103
|
-
name: rspec
|
104
|
-
prerelease: false
|
105
104
|
type: :development
|
105
|
+
prerelease: false
|
106
106
|
version_requirements: !ruby/object:Gem::Requirement
|
107
107
|
requirements:
|
108
|
-
- -
|
108
|
+
- - ">="
|
109
109
|
- !ruby/object:Gem::Version
|
110
110
|
version: '3.0'
|
111
111
|
- !ruby/object:Gem::Dependency
|
112
|
+
name: rubocop
|
112
113
|
requirement: !ruby/object:Gem::Requirement
|
113
114
|
requirements:
|
114
|
-
- -
|
115
|
+
- - ">="
|
115
116
|
- !ruby/object:Gem::Version
|
116
117
|
version: '0'
|
117
|
-
name: rubocop
|
118
|
-
prerelease: false
|
119
118
|
type: :development
|
119
|
+
prerelease: false
|
120
120
|
version_requirements: !ruby/object:Gem::Requirement
|
121
121
|
requirements:
|
122
|
-
- -
|
122
|
+
- - ">="
|
123
123
|
- !ruby/object:Gem::Version
|
124
124
|
version: '0'
|
125
|
-
description: Coppertone includes tools for parsing SPF DNS records, evaluating the
|
125
|
+
description: Coppertone includes tools for parsing SPF DNS records, evaluating the
|
126
|
+
result of SPF checks for received emails, and creating appropriate email headers
|
127
|
+
from SPF results.
|
126
128
|
email:
|
127
129
|
- peter.m.goldstein@gmail.com
|
128
130
|
executables: []
|
129
131
|
extensions: []
|
130
132
|
extra_rdoc_files: []
|
131
133
|
files:
|
132
|
-
- .gitignore
|
133
|
-
- .travis.yml
|
134
|
+
- ".gitignore"
|
135
|
+
- ".travis.yml"
|
134
136
|
- Gemfile
|
135
137
|
- LICENSE
|
136
138
|
- README.md
|
@@ -183,6 +185,7 @@ files:
|
|
183
185
|
- lib/coppertone/sender_identity.rb
|
184
186
|
- lib/coppertone/spf_service.rb
|
185
187
|
- lib/coppertone/term.rb
|
188
|
+
- lib/coppertone/terms_parser.rb
|
186
189
|
- lib/coppertone/utils.rb
|
187
190
|
- lib/coppertone/utils/domain_utils.rb
|
188
191
|
- lib/coppertone/utils/host_utils.rb
|
@@ -208,7 +211,9 @@ files:
|
|
208
211
|
- spec/mechanism_spec.rb
|
209
212
|
- spec/modifier/exp_spec.rb
|
210
213
|
- spec/modifier/redirect_spec.rb
|
214
|
+
- spec/modifier/unknown_spec.rb
|
211
215
|
- spec/modifier_spec.rb
|
216
|
+
- spec/null_macro_context_spec.rb
|
212
217
|
- spec/open_spf/ALL_mechanism_syntax_spec.rb
|
213
218
|
- spec/open_spf/A_mechanism_syntax_spec.rb
|
214
219
|
- spec/open_spf/EXISTS_mechanism_syntax_spec.rb
|
@@ -245,24 +250,24 @@ homepage: https://github.com/petergoldstein/coppertone
|
|
245
250
|
licenses:
|
246
251
|
- Apache
|
247
252
|
metadata: {}
|
248
|
-
post_install_message:
|
253
|
+
post_install_message:
|
249
254
|
rdoc_options: []
|
250
255
|
require_paths:
|
251
256
|
- lib
|
252
257
|
required_ruby_version: !ruby/object:Gem::Requirement
|
253
258
|
requirements:
|
254
|
-
- -
|
259
|
+
- - ">="
|
255
260
|
- !ruby/object:Gem::Version
|
256
261
|
version: '0'
|
257
262
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
258
263
|
requirements:
|
259
|
-
- -
|
264
|
+
- - ">="
|
260
265
|
- !ruby/object:Gem::Version
|
261
266
|
version: '0'
|
262
267
|
requirements: []
|
263
|
-
rubyforge_project:
|
264
|
-
rubygems_version: 2.
|
265
|
-
signing_key:
|
268
|
+
rubyforge_project:
|
269
|
+
rubygems_version: 2.4.4
|
270
|
+
signing_key:
|
266
271
|
specification_version: 4
|
267
272
|
summary: A Sender Policy Framework (SPF) toolkit
|
268
273
|
test_files:
|
@@ -285,7 +290,9 @@ test_files:
|
|
285
290
|
- spec/mechanism_spec.rb
|
286
291
|
- spec/modifier/exp_spec.rb
|
287
292
|
- spec/modifier/redirect_spec.rb
|
293
|
+
- spec/modifier/unknown_spec.rb
|
288
294
|
- spec/modifier_spec.rb
|
295
|
+
- spec/null_macro_context_spec.rb
|
289
296
|
- spec/open_spf/ALL_mechanism_syntax_spec.rb
|
290
297
|
- spec/open_spf/A_mechanism_syntax_spec.rb
|
291
298
|
- spec/open_spf/EXISTS_mechanism_syntax_spec.rb
|