coppertone 0.0.1

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.
Files changed (114) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +34 -0
  3. data/.travis.yml +7 -0
  4. data/Gemfile +7 -0
  5. data/LICENSE +201 -0
  6. data/README.md +58 -0
  7. data/Rakefile +140 -0
  8. data/coppertone.gemspec +27 -0
  9. data/lib/coppertone/class_builder.rb +20 -0
  10. data/lib/coppertone/directive.rb +38 -0
  11. data/lib/coppertone/dns/error.rb +9 -0
  12. data/lib/coppertone/dns/mock_client.rb +106 -0
  13. data/lib/coppertone/dns/resolv_client.rb +110 -0
  14. data/lib/coppertone/dns.rb +3 -0
  15. data/lib/coppertone/domain_spec.rb +45 -0
  16. data/lib/coppertone/error.rb +29 -0
  17. data/lib/coppertone/ip_address_wrapper.rb +75 -0
  18. data/lib/coppertone/macro_context.rb +67 -0
  19. data/lib/coppertone/macro_string/macro_expand.rb +84 -0
  20. data/lib/coppertone/macro_string/macro_literal.rb +24 -0
  21. data/lib/coppertone/macro_string/macro_parser.rb +62 -0
  22. data/lib/coppertone/macro_string/macro_static_expand.rb +52 -0
  23. data/lib/coppertone/macro_string.rb +31 -0
  24. data/lib/coppertone/mechanism/a.rb +16 -0
  25. data/lib/coppertone/mechanism/all.rb +24 -0
  26. data/lib/coppertone/mechanism/cidr_parser.rb +14 -0
  27. data/lib/coppertone/mechanism/domain_spec_mechanism.rb +18 -0
  28. data/lib/coppertone/mechanism/domain_spec_optional.rb +46 -0
  29. data/lib/coppertone/mechanism/domain_spec_required.rb +37 -0
  30. data/lib/coppertone/mechanism/domain_spec_with_dual_cidr.rb +114 -0
  31. data/lib/coppertone/mechanism/exists.rb +14 -0
  32. data/lib/coppertone/mechanism/include.rb +18 -0
  33. data/lib/coppertone/mechanism/include_matcher.rb +34 -0
  34. data/lib/coppertone/mechanism/ip4.rb +13 -0
  35. data/lib/coppertone/mechanism/ip6.rb +13 -0
  36. data/lib/coppertone/mechanism/ip_mechanism.rb +48 -0
  37. data/lib/coppertone/mechanism/mx.rb +40 -0
  38. data/lib/coppertone/mechanism/ptr.rb +17 -0
  39. data/lib/coppertone/mechanism.rb +32 -0
  40. data/lib/coppertone/modifier/base.rb +24 -0
  41. data/lib/coppertone/modifier/exp.rb +34 -0
  42. data/lib/coppertone/modifier/redirect.rb +17 -0
  43. data/lib/coppertone/modifier/unknown.rb +16 -0
  44. data/lib/coppertone/modifier.rb +30 -0
  45. data/lib/coppertone/qualifier.rb +45 -0
  46. data/lib/coppertone/record.rb +86 -0
  47. data/lib/coppertone/record_evaluator.rb +63 -0
  48. data/lib/coppertone/record_finder.rb +34 -0
  49. data/lib/coppertone/request.rb +68 -0
  50. data/lib/coppertone/request_context.rb +67 -0
  51. data/lib/coppertone/request_count_limiter.rb +36 -0
  52. data/lib/coppertone/result.rb +50 -0
  53. data/lib/coppertone/sender_identity.rb +39 -0
  54. data/lib/coppertone/spf_service.rb +9 -0
  55. data/lib/coppertone/term.rb +13 -0
  56. data/lib/coppertone/utils/domain_utils.rb +59 -0
  57. data/lib/coppertone/utils/host_utils.rb +22 -0
  58. data/lib/coppertone/utils/ip_in_domain_checker.rb +53 -0
  59. data/lib/coppertone/utils/validated_domain_finder.rb +40 -0
  60. data/lib/coppertone/utils.rb +4 -0
  61. data/lib/coppertone/version.rb +3 -0
  62. data/lib/coppertone.rb +48 -0
  63. data/lib/resolv/dns/resource/in/spf.rb +15 -0
  64. data/spec/directive_spec.rb +41 -0
  65. data/spec/dns/resolv_client_spec.rb +307 -0
  66. data/spec/domain_spec_spec.rb +35 -0
  67. data/spec/ip_address_wrapper_spec.rb +67 -0
  68. data/spec/macro_context_spec.rb +69 -0
  69. data/spec/macro_string/macro_expand_spec.rb +79 -0
  70. data/spec/macro_string/macro_literal_spec.rb +27 -0
  71. data/spec/macro_string/macro_static_expand_spec.rb +67 -0
  72. data/spec/macro_string_spec.rb +20 -0
  73. data/spec/mechanism/a_spec.rb +198 -0
  74. data/spec/mechanism/all_spec.rb +22 -0
  75. data/spec/mechanism/exists_spec.rb +91 -0
  76. data/spec/mechanism/include_spec.rb +43 -0
  77. data/spec/mechanism/ip4_spec.rb +110 -0
  78. data/spec/mechanism/ip6_spec.rb +104 -0
  79. data/spec/mechanism/mx_spec.rb +51 -0
  80. data/spec/mechanism/ptr_spec.rb +43 -0
  81. data/spec/mechanism_spec.rb +4 -0
  82. data/spec/modifier_spec.rb +4 -0
  83. data/spec/open_spf/ALL_mechanism_syntax_spec.rb +38 -0
  84. data/spec/open_spf/A_mechanism_syntax_spec.rb +159 -0
  85. data/spec/open_spf/EXISTS_mechanism_syntax_spec.rb +46 -0
  86. data/spec/open_spf/IP4_mechanism_syntax_spec.rb +59 -0
  87. data/spec/open_spf/IP6_mechanism_syntax_spec.rb +60 -0
  88. data/spec/open_spf/Include_mechanism_semantics_and_syntax_spec.rb +56 -0
  89. data/spec/open_spf/Initial_processing_spec.rb +77 -0
  90. data/spec/open_spf/MX_mechanism_syntax_spec.rb +119 -0
  91. data/spec/open_spf/Macro_expansion_rules_spec.rb +154 -0
  92. data/spec/open_spf/PTR_mechanism_syntax_spec.rb +42 -0
  93. data/spec/open_spf/Processing_limits_spec.rb +72 -0
  94. data/spec/open_spf/Record_evaluation_spec.rb +75 -0
  95. data/spec/open_spf/Record_lookup_spec.rb +48 -0
  96. data/spec/open_spf/Selecting_records_spec.rb +61 -0
  97. data/spec/open_spf/Semantics_of_exp_and_other_modifiers_spec.rb +167 -0
  98. data/spec/open_spf/Test_cases_from_implementation_bugs_spec.rb +17 -0
  99. data/spec/qualifier_spec.rb +54 -0
  100. data/spec/record_evaluator_spec.rb +4 -0
  101. data/spec/record_finder_spec.rb +4 -0
  102. data/spec/record_spec.rb +100 -0
  103. data/spec/request_context_spec.rb +43 -0
  104. data/spec/request_count_limiter_spec.rb +28 -0
  105. data/spec/result_spec.rb +4 -0
  106. data/spec/rfc7208-tests.yml +2548 -0
  107. data/spec/sender_identity_spec.rb +69 -0
  108. data/spec/spec_helper.rb +8 -0
  109. data/spec/term_spec.rb +38 -0
  110. data/spec/utils/domain_utils_spec.rb +60 -0
  111. data/spec/utils/host_utils_spec.rb +32 -0
  112. data/spec/utils/ip_in_domain_checker_spec.rb +4 -0
  113. data/spec/utils/validated_domain_finder_spec.rb +4 -0
  114. metadata +306 -0
@@ -0,0 +1,27 @@
1
+ require 'spec_helper'
2
+
3
+ describe Coppertone::MacroString::MacroLiteral do
4
+ let(:arg) { SecureRandom.hex(10) }
5
+ let(:macro) { Coppertone::MacroString::MacroLiteral.new(arg) }
6
+
7
+ it 'should expand to the argument' do
8
+ expect(macro.expand(double)).to eq(arg)
9
+ end
10
+
11
+ it 'should reduce to the argument in the macro form' do
12
+ expect(macro.to_s).to eq(arg)
13
+ end
14
+
15
+ context 'equality' do
16
+ it 'should treat different MacroLiterals with the same value as equal' do
17
+ expect(macro == Coppertone::MacroString::MacroLiteral.new(arg))
18
+ .to eql(true)
19
+ end
20
+
21
+ it 'otherwise should treat different MacroLiterals as unequal' do
22
+ other_arg = SecureRandom.hex(10)
23
+ expect(macro == Coppertone::MacroString::MacroLiteral.new(other_arg))
24
+ .to eql(false)
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,67 @@
1
+ require 'spec_helper'
2
+
3
+ describe Coppertone::MacroString::MacroStaticExpand do
4
+ context '#exists_for?' do
5
+ %w(%% %_ %-).each do |x|
6
+ it "should resolve a macro for the key #{x}" do
7
+ expect(Coppertone::MacroString::MacroStaticExpand.exists_for?(x))
8
+ .to eq(true)
9
+ end
10
+ end
11
+
12
+ it 'should return false for invalid keys' do
13
+ expect(Coppertone::MacroString::MacroStaticExpand.exists_for?('%a'))
14
+ .to eq(false)
15
+ end
16
+ end
17
+
18
+ context 'macro_for' do
19
+ %w(%% %_ %-).each do |x|
20
+ it "should resolve a macro for the key #{x}" do
21
+ expect(Coppertone::MacroString::MacroStaticExpand.macro_for(x))
22
+ .not_to be_nil
23
+ end
24
+ end
25
+
26
+ it 'should raise an error for invalid keys' do
27
+ expect do
28
+ Coppertone::MacroString::MacroStaticExpand.macro_for('%a')
29
+ end.to raise_error(Coppertone::MacroStringParsingError)
30
+ end
31
+ end
32
+
33
+ it 'should not allow creation of new macros' do
34
+ expect do
35
+ Coppertone::MacroString::MacroStaticExpand.new('a', 'b')
36
+ end.to raise_error(NoMethodError)
37
+ end
38
+
39
+ context 'percent macro' do
40
+ let(:macro) { Coppertone::MacroString::MacroStaticExpand::PERCENT_MACRO }
41
+
42
+ it 'should return the expected values' do
43
+ expect(macro.expand(nil)).to eq('%')
44
+ expect(macro.to_s).to eq('%%')
45
+ end
46
+ end
47
+
48
+ context 'space macro' do
49
+ let(:macro) { Coppertone::MacroString::MacroStaticExpand::SPACE_MACRO }
50
+
51
+ it 'should return the expected values' do
52
+ expect(macro.expand(nil)).to eq(' ')
53
+ expect(macro.to_s).to eq('%_')
54
+ end
55
+ end
56
+
57
+ context 'url encoded space macro' do
58
+ let(:macro) do
59
+ Coppertone::MacroString::MacroStaticExpand::URL_ENCODED_SPACE_MACRO
60
+ end
61
+
62
+ it 'should return the expected values' do
63
+ expect(macro.expand(nil)).to eq('%20')
64
+ expect(macro.to_s).to eq('%-')
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,20 @@
1
+ require 'spec_helper'
2
+
3
+ describe Coppertone::MacroString do
4
+ context 'equality' do
5
+ it 'should treat different MacroStrings with the same value as equal' do
6
+ arg = 'abc.%{dr-}.%%.test.com'
7
+ macro_string = Coppertone::MacroString.new(arg)
8
+ expect(macro_string == Coppertone::MacroString.new(arg))
9
+ .to eql(true)
10
+ end
11
+
12
+ it 'should otherwise treat different MacroStrings as unequal' do
13
+ arg = 'abc.%{dr-}.%%.test.com'
14
+ macro_string = Coppertone::MacroString.new(arg)
15
+ other_arg = 'eabc.%{dr-}.%%.test.com'
16
+ expect(macro_string == Coppertone::MacroString.new(other_arg))
17
+ .to eql(false)
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,198 @@
1
+ require 'spec_helper'
2
+
3
+ describe Coppertone::Mechanism::A do
4
+ context '#new' do
5
+ it 'should not fail if called with a nil argument' do
6
+ mech = Coppertone::Mechanism::A.new(nil)
7
+ expect(mech).not_to be_nil
8
+ expect(mech.domain_spec).to be_nil
9
+ expect(mech.ip_v4_cidr_length).to eq(32)
10
+ expect(mech.ip_v6_cidr_length).to eq(128)
11
+ end
12
+
13
+ it 'should not fail if called with a blank argument' do
14
+ mech = Coppertone::Mechanism::A.new('')
15
+ expect(mech).not_to be_nil
16
+ expect(mech.domain_spec).to be_nil
17
+ expect(mech.ip_v4_cidr_length).to eq(32)
18
+ expect(mech.ip_v6_cidr_length).to eq(128)
19
+ end
20
+
21
+ it 'should fail if called with an invalid macrostring' do
22
+ expect do
23
+ Coppertone::Mechanism::A.new(':abc%:def')
24
+ end.to raise_error(Coppertone::InvalidMechanismError)
25
+ end
26
+
27
+ it 'should parse a domain spec' do
28
+ mech = Coppertone::Mechanism::A.new(':_spf.%{d}.example.com')
29
+ expect(mech).not_to be_nil
30
+ expect(mech.domain_spec)
31
+ .to eq(Coppertone::DomainSpec.new('_spf.%{d}.example.com'))
32
+ expect(mech.ip_v4_cidr_length).to eq(32)
33
+ expect(mech.ip_v6_cidr_length).to eq(128)
34
+ end
35
+
36
+ it 'should parse a valid IP v4 CIDR length with a domain spec' do
37
+ mech = Coppertone::Mechanism::A.new(':_spf.%{d}.example.com/28')
38
+ expect(mech).not_to be_nil
39
+ expect(mech.domain_spec)
40
+ .to eq(Coppertone::DomainSpec.new('_spf.%{d}.example.com'))
41
+ expect(mech.ip_v4_cidr_length).to eq('28')
42
+ expect(mech.ip_v6_cidr_length).to eq(128)
43
+ end
44
+
45
+ it 'should fail if called with an invalid macrostring and IPv4 CIDR' do
46
+ expect do
47
+ Coppertone::Mechanism::A.new(':abc%:def/28')
48
+ end.to raise_error(Coppertone::InvalidMechanismError)
49
+ end
50
+
51
+ it 'should parse a valid IP v4 CIDR length' do
52
+ mech = Coppertone::Mechanism::A.new('/28')
53
+ expect(mech).not_to be_nil
54
+ expect(mech.domain_spec).to be_nil
55
+ expect(mech.ip_v4_cidr_length).to eq('28')
56
+ expect(mech.ip_v6_cidr_length).to eq(128)
57
+ end
58
+
59
+ it 'should not parse an invalid IP v4 CIDR length' do
60
+ expect do
61
+ Coppertone::Mechanism::A.new('/36')
62
+ end.to raise_error(Coppertone::InvalidMechanismError)
63
+
64
+ expect do
65
+ Coppertone::Mechanism::A.new('/a')
66
+ end.to raise_error(Coppertone::InvalidMechanismError)
67
+ end
68
+
69
+ it 'should parse a valid IP v6 CIDR length with a domain spec' do
70
+ mech = Coppertone::Mechanism::A.new(':_spf.%{d}.example.com//64')
71
+ expect(mech).not_to be_nil
72
+ expect(mech.domain_spec)
73
+ .to eq(Coppertone::DomainSpec.new('_spf.%{d}.example.com'))
74
+ expect(mech.ip_v4_cidr_length).to eq(32)
75
+ expect(mech.ip_v6_cidr_length).to eq('64')
76
+ end
77
+
78
+ it 'should fail if called with an invalid macrostring and IPv6 CIDR' do
79
+ expect do
80
+ Coppertone::Mechanism::A.new(':abc%:def//64')
81
+ end.to raise_error(Coppertone::InvalidMechanismError)
82
+ end
83
+
84
+ it 'should parse a valid IP v6 CIDR length' do
85
+ mech = Coppertone::Mechanism::A.new('//64')
86
+ expect(mech).not_to be_nil
87
+ expect(mech.domain_spec).to be_nil
88
+ expect(mech.ip_v4_cidr_length).to eq(32)
89
+ expect(mech.ip_v6_cidr_length).to eq('64')
90
+ end
91
+
92
+ it 'should not parse an invalid IP v6 CIDR length' do
93
+ expect do
94
+ Coppertone::Mechanism::A.new('//133')
95
+ end.to raise_error(Coppertone::InvalidMechanismError)
96
+
97
+ expect do
98
+ Coppertone::Mechanism::A.new('//a')
99
+ end.to raise_error(Coppertone::InvalidMechanismError)
100
+ end
101
+
102
+ it 'should parse a valid dual CIDR length with a domain spec' do
103
+ mech = Coppertone::Mechanism::A.new(':_spf.%{d}.example.com/28//64')
104
+ expect(mech).not_to be_nil
105
+ expect(mech.domain_spec)
106
+ .to eq(Coppertone::DomainSpec.new('_spf.%{d}.example.com'))
107
+ expect(mech.ip_v4_cidr_length).to eq('28')
108
+ expect(mech.ip_v6_cidr_length).to eq('64')
109
+ end
110
+
111
+ it 'should not parse a invalid dual CIDR length with a domain spec' do
112
+ expect do
113
+ Coppertone::Mechanism::A.new('_spf.%{d}.example.com/28//133')
114
+ end.to raise_error(Coppertone::InvalidMechanismError)
115
+ expect do
116
+ Coppertone::Mechanism::A.new('_spf.%{d}.example.com/44//64')
117
+ end.to raise_error(Coppertone::InvalidMechanismError)
118
+ end
119
+
120
+ it 'should fail if called with an invalid macrostring and dual CIDR' do
121
+ expect do
122
+ Coppertone::Mechanism::A.new('abc%:def/28//64')
123
+ end.to raise_error(Coppertone::InvalidMechanismError)
124
+ end
125
+ end
126
+
127
+ context '#create' do
128
+ it 'should fail if called with a nil argument' do
129
+ mech = Coppertone::Mechanism::A.create(nil)
130
+ expect(mech).not_to be_nil
131
+ expect(mech.domain_spec).to be_nil
132
+ expect(mech.ip_v4_cidr_length).to eq(32)
133
+ expect(mech.ip_v6_cidr_length).to eq(128)
134
+ end
135
+
136
+ it 'should fail if called with a blank argument' do
137
+ mech = Coppertone::Mechanism::A.create('')
138
+ expect(mech).not_to be_nil
139
+ expect(mech.domain_spec).to be_nil
140
+ expect(mech.ip_v4_cidr_length).to eq(32)
141
+ expect(mech.ip_v6_cidr_length).to eq(128)
142
+ end
143
+
144
+ it 'should fail if called with an argument invalid macrostring' do
145
+ expect do
146
+ Coppertone::Mechanism::A.create('abc%:def')
147
+ end.to raise_error(Coppertone::InvalidMechanismError)
148
+ end
149
+ end
150
+
151
+ context '#match?' do
152
+ context 'simple' do
153
+ let(:mech_domain) { 'gmail.com' }
154
+ let(:mech_arg) { ":#{mech_domain}" }
155
+ let(:gmail_dns_client) do
156
+ dc = double(:dns_client)
157
+ allow(dc).to receive(:fetch_a_records)
158
+ .with(mech_domain).and_return([
159
+ {
160
+ type: 'A',
161
+ address: '74.125.239.117'
162
+ },
163
+ {
164
+ type: 'A',
165
+ address: '74.125.239.118'
166
+ }
167
+ ])
168
+ dc
169
+ end
170
+
171
+ let(:domain) { 'yahoo.com' }
172
+ let(:matching_context) do
173
+ Coppertone::MacroContext.new(domain, '74.125.239.118', 'bob@gmail.com')
174
+ end
175
+
176
+ let(:not_matching_context) do
177
+ Coppertone::MacroContext.new(domain, '74.125.249.118', 'bob@gmail.com')
178
+ end
179
+
180
+ before do
181
+ allow(Coppertone::DNS::ResolvClient)
182
+ .to receive(:new).and_return(gmail_dns_client)
183
+ end
184
+
185
+ it 'should match when the IP matches the record' do
186
+ mech = Coppertone::Mechanism::A.create(mech_arg)
187
+ expect(mech.match?(matching_context, Coppertone::RequestContext.new))
188
+ .to eq(true)
189
+ end
190
+
191
+ it 'should not match when the IP does not match the record' do
192
+ mech = Coppertone::Mechanism::A.create(mech_arg)
193
+ expect(mech.match?(not_matching_context, Coppertone::RequestContext.new))
194
+ .to eq(false)
195
+ end
196
+ end
197
+ end
198
+ end
@@ -0,0 +1,22 @@
1
+ require 'spec_helper'
2
+
3
+ describe Coppertone::Mechanism::All do
4
+ subject { Coppertone::Mechanism::All.instance }
5
+ it 'should always return true regardless of argument' do
6
+ expect(subject.match?(double, double)).to eq(true)
7
+ end
8
+
9
+ it 'should not allow creation of new instances' do
10
+ expect do
11
+ Coppertone::Mechanism::All.new('')
12
+ end.to raise_error(NoMethodError)
13
+ end
14
+
15
+ context '#create' do
16
+ it 'should fail if any arguments are passed that are not blank' do
17
+ expect do
18
+ Coppertone::Mechanism::All.create('abcd')
19
+ end.to raise_error(Coppertone::RecordParsingError)
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,91 @@
1
+ require 'spec_helper'
2
+
3
+ describe Coppertone::Mechanism::Exists do
4
+ context '#new' do
5
+ it 'should fail if called with a nil argument' do
6
+ expect do
7
+ Coppertone::Mechanism::Exists.new(nil)
8
+ end.to raise_error(Coppertone::InvalidMechanismError)
9
+ end
10
+
11
+ it 'should fail if called with a blank argument' do
12
+ expect do
13
+ Coppertone::Mechanism::Exists.new('')
14
+ end.to raise_error(Coppertone::InvalidMechanismError)
15
+ end
16
+
17
+ it 'should fail if called with an invalid macrostring' do
18
+ expect do
19
+ Coppertone::Mechanism::Exists.new(':abc%:def')
20
+ end.to raise_error(Coppertone::InvalidMechanismError)
21
+ end
22
+ end
23
+
24
+ context '#create' do
25
+ it 'should fail if called with a nil argument' do
26
+ expect do
27
+ Coppertone::Mechanism::Exists.create(nil)
28
+ end.to raise_error(Coppertone::InvalidMechanismError)
29
+ end
30
+
31
+ it 'should fail if called with a blank argument' do
32
+ expect do
33
+ Coppertone::Mechanism::Exists.create('')
34
+ end.to raise_error(Coppertone::InvalidMechanismError)
35
+ end
36
+
37
+ it 'should fail if called with an invalid macrostring' do
38
+ expect do
39
+ Coppertone::Mechanism::Exists.create(':abc%:def')
40
+ end.to raise_error(Coppertone::InvalidMechanismError)
41
+ end
42
+ end
43
+
44
+ context '#match?' do
45
+ context 'simple' do
46
+ let(:mech_domain) { 'iexist.com' }
47
+ let(:mech_arg) { ":#{mech_domain}" }
48
+ let(:bad_domain) { 'idontexist.com' }
49
+ let(:bad_arg) { ":#{bad_domain}" }
50
+ let(:dns_client) do
51
+ dc = double(:dns_client)
52
+ allow(dc).to receive(:fetch_a_records)
53
+ .with(mech_domain).and_return([
54
+ {
55
+ type: 'A',
56
+ address: '74.125.234.117'
57
+ }
58
+ ])
59
+ allow(dc).to receive(:fetch_a_records)
60
+ .with(bad_domain).and_return([])
61
+ dc
62
+ end
63
+
64
+ let(:domain) { 'yahoo.com' }
65
+ let(:matching_context) do
66
+ Coppertone::MacroContext.new(domain, '74.125.239.118', 'bob@gmail.com')
67
+ end
68
+
69
+ let(:not_matching_context) do
70
+ Coppertone::MacroContext.new(domain, '74.125.249.118', 'bob@gmail.com')
71
+ end
72
+
73
+ before do
74
+ allow(Coppertone::DNS::ResolvClient)
75
+ .to receive(:new).and_return(dns_client)
76
+ end
77
+
78
+ it 'should match when the domain record for the target name exists' do
79
+ mech = Coppertone::Mechanism::Exists.create(mech_arg)
80
+ expect(mech.match?(matching_context, Coppertone::RequestContext.new))
81
+ .to eq(true)
82
+ end
83
+
84
+ it 'should match when the domain record for the target name exists' do
85
+ mech = Coppertone::Mechanism::Exists.create(bad_arg)
86
+ expect(mech.match?(matching_context, Coppertone::RequestContext.new))
87
+ .to eq(false)
88
+ end
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,43 @@
1
+ require 'spec_helper'
2
+
3
+ describe Coppertone::Mechanism::Include do
4
+ context '#new' do
5
+ it 'should fail if called with a nil argument' do
6
+ expect do
7
+ Coppertone::Mechanism::Include.new(nil)
8
+ end.to raise_error(Coppertone::InvalidMechanismError)
9
+ end
10
+
11
+ it 'should fail if called with a blank argument' do
12
+ expect do
13
+ Coppertone::Mechanism::Include.new('')
14
+ end.to raise_error(Coppertone::InvalidMechanismError)
15
+ end
16
+
17
+ it 'should fail if called with an invalid macrostring' do
18
+ expect do
19
+ Coppertone::Mechanism::Include.new('abc%:def')
20
+ end.to raise_error(Coppertone::InvalidMechanismError)
21
+ end
22
+ end
23
+
24
+ context '#create' do
25
+ it 'should fail if called with a nil argument' do
26
+ expect do
27
+ Coppertone::Mechanism::Include.create(nil)
28
+ end.to raise_error(Coppertone::InvalidMechanismError)
29
+ end
30
+
31
+ it 'should fail if called with a blank argument' do
32
+ expect do
33
+ Coppertone::Mechanism::Include.create('')
34
+ end.to raise_error(Coppertone::InvalidMechanismError)
35
+ end
36
+
37
+ it 'should fail if called with an argument invalid macrostring' do
38
+ expect do
39
+ Coppertone::Mechanism::Include.create('abc%:def')
40
+ end.to raise_error(Coppertone::InvalidMechanismError)
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,110 @@
1
+ require 'spec_helper'
2
+
3
+ describe Coppertone::Mechanism::IP4 do
4
+ context '#new' do
5
+ it 'should fail if called with a nil argument' do
6
+ expect do
7
+ Coppertone::Mechanism::IP4.new(nil)
8
+ end.to raise_error(Coppertone::InvalidMechanismError)
9
+ end
10
+
11
+ it 'should fail if called with a blank argument' do
12
+ expect do
13
+ Coppertone::Mechanism::IP4.new('')
14
+ end.to raise_error(Coppertone::InvalidMechanismError)
15
+ end
16
+
17
+ it 'should fail if called with an invalid IP' do
18
+ expect do
19
+ Coppertone::Mechanism::IP4.new(':not_an_ip')
20
+ end.to raise_error(Coppertone::InvalidMechanismError)
21
+ end
22
+
23
+ it 'should not fail if called with an IP v6' do
24
+ mech = Coppertone::Mechanism::IP4.new(':fe80::202:b3ff:fe1e:8329')
25
+ expect(mech.ip_network).to eq(IPAddr.new('fe80::202:b3ff:fe1e:8329'))
26
+ end
27
+
28
+ it 'should work if called with an IP4' do
29
+ mech = Coppertone::Mechanism::IP4.new(':1.2.3.4')
30
+ expect(mech.ip_network).to eq(IPAddr.new('1.2.3.4'))
31
+ end
32
+
33
+ it 'should work if called with an IP4 with a pfxlen' do
34
+ mech = Coppertone::Mechanism::IP4.new(':1.2.3.4/4')
35
+ expect(mech.ip_network).to eq(IPAddr.new('1.2.3.4/4'))
36
+ end
37
+ end
38
+
39
+ context '#create' do
40
+ it 'should fail if called with a nil argument' do
41
+ expect do
42
+ Coppertone::Mechanism::IP4.create(nil)
43
+ end.to raise_error(Coppertone::InvalidMechanismError)
44
+ end
45
+
46
+ it 'should fail if called with a blank argument' do
47
+ expect do
48
+ Coppertone::Mechanism::IP4.create('')
49
+ end.to raise_error(Coppertone::InvalidMechanismError)
50
+ end
51
+
52
+ it 'should fail if called with an invalid IP' do
53
+ expect do
54
+ Coppertone::Mechanism::IP4.create(':not_an_ip')
55
+ end.to raise_error(Coppertone::InvalidMechanismError)
56
+ end
57
+
58
+ it 'should not fail if called with an IP v6' do
59
+ mech = Coppertone::Mechanism::IP4.create(':fe80::202:b3ff:fe1e:8329')
60
+ expect(mech.ip_network).to eq(IPAddr.new('fe80::202:b3ff:fe1e:8329'))
61
+ end
62
+
63
+ it 'should work if called with an IP4' do
64
+ mech = Coppertone::Mechanism::IP4.create(':1.2.3.4')
65
+ expect(mech.ip_network).to eq(IPAddr.new('1.2.3.4'))
66
+ end
67
+
68
+ it 'should work if called with an IP4 with a pfxlen' do
69
+ mech = Coppertone::Mechanism::IP4.create('1.2.3.4/4')
70
+ expect(mech.ip_network).to eq(IPAddr.new('1.2.3.4/4'))
71
+ end
72
+
73
+ it 'should fail if called with an invalid pfxlen' do
74
+ expect do
75
+ Coppertone::Mechanism::IP4.new('1.2.3.4/127')
76
+ end.to raise_error(Coppertone::InvalidMechanismError)
77
+ end
78
+ end
79
+
80
+ context '.match' do
81
+ let(:client_ip) { IPAddr.new('4.5.6.7') }
82
+
83
+ let(:macro_context) do
84
+ mc = double(:macro_context)
85
+ allow(mc).to receive(:ip_v4).and_return(client_ip)
86
+ mc
87
+ end
88
+
89
+ let(:ip_v6_macro_context) do
90
+ mc = double(:macro_context)
91
+ allow(mc).to receive(:ip_v4).and_return(nil)
92
+ mc
93
+ end
94
+
95
+ it 'should return true if the client IP is in the network' do
96
+ mech = Coppertone::Mechanism::IP4.create('4.5.6.0/29')
97
+ expect(mech.match?(macro_context, double)).to eq(true)
98
+ end
99
+
100
+ it 'should return false if the client IP is not in the network' do
101
+ mech = Coppertone::Mechanism::IP4.create('4.5.6.0/30')
102
+ expect(mech.match?(macro_context, double)).to eq(false)
103
+ end
104
+
105
+ it 'should return false if the client IP is v6 only' do
106
+ mech = Coppertone::Mechanism::IP4.create('4.5.6.0/29')
107
+ expect(mech.match?(ip_v6_macro_context, double)).to eq(false)
108
+ end
109
+ end
110
+ end
@@ -0,0 +1,104 @@
1
+ require 'spec_helper'
2
+
3
+ describe Coppertone::Mechanism::IP6 do
4
+ context '#new' do
5
+ it 'should fail if called with a nil argument' do
6
+ expect do
7
+ Coppertone::Mechanism::IP6.new(nil)
8
+ end.to raise_error(Coppertone::InvalidMechanismError)
9
+ end
10
+
11
+ it 'should fail if called with a blank argument' do
12
+ expect do
13
+ Coppertone::Mechanism::IP6.new('')
14
+ end.to raise_error(Coppertone::InvalidMechanismError)
15
+ end
16
+
17
+ it 'should fail if called with an invalid IP' do
18
+ expect do
19
+ Coppertone::Mechanism::IP6.new('not_an_ip')
20
+ end.to raise_error(Coppertone::InvalidMechanismError)
21
+ end
22
+
23
+ it 'should not fail if called with an IP v4' do
24
+ mech = Coppertone::Mechanism::IP6.new('1.2.3.4')
25
+ expect(mech.ip_network).to eq(IPAddr.new('1.2.3.4'))
26
+ end
27
+
28
+ it 'should work if called with an IP6' do
29
+ mech = Coppertone::Mechanism::IP6.new('fe80::202:b3ff:fe1e:8329')
30
+ expect(mech.ip_network)
31
+ .to eq(IPAddr.new('fe80::202:b3ff:fe1e:8329'))
32
+ end
33
+
34
+ it 'should work if called with an IP6 with a pfxlen' do
35
+ mech = Coppertone::Mechanism::IP6.new('fe80::202:b3ff:fe1e:8329/64')
36
+ expect(mech.ip_network)
37
+ .to eq(IPAddr.new('fe80::202:b3ff:fe1e:8329/64'))
38
+ end
39
+
40
+ it 'should fail if called with an invalid pfxlen' do
41
+ expect do
42
+ Coppertone::Mechanism::IP6.new('fe80::202:b3ff:fe1e:8329/384')
43
+ end.to raise_error(Coppertone::InvalidMechanismError)
44
+ end
45
+
46
+ end
47
+
48
+ context '#create' do
49
+ it 'should fail if called with a nil argument' do
50
+ expect do
51
+ Coppertone::Mechanism::IP6.create(nil)
52
+ end.to raise_error(Coppertone::InvalidMechanismError)
53
+ end
54
+
55
+ it 'should fail if called with a blank argument' do
56
+ expect do
57
+ Coppertone::Mechanism::IP6.create('')
58
+ end.to raise_error(Coppertone::InvalidMechanismError)
59
+ end
60
+
61
+ it 'should fail if called with an invalid IP' do
62
+ expect do
63
+ Coppertone::Mechanism::IP6.create('not_an_ip')
64
+ end.to raise_error(Coppertone::InvalidMechanismError)
65
+ end
66
+
67
+ it 'should not fail if called with an IP v4' do
68
+ mech = Coppertone::Mechanism::IP6.create('1.2.3.4')
69
+ expect(mech.ip_network).to eq(IPAddr.new('1.2.3.4'))
70
+ end
71
+
72
+ it 'should work if called with an IP6' do
73
+ mech = Coppertone::Mechanism::IP6.create('fe80::202:b3ff:fe1e:8329')
74
+ expect(mech.ip_network)
75
+ .to eq(IPAddr.new('fe80::202:b3ff:fe1e:8329'))
76
+ end
77
+
78
+ it 'should work if called with an IP6 with a pfxlen' do
79
+ mech = Coppertone::Mechanism::IP6.create('fe80::202:b3ff:fe1e:8329/64')
80
+ expect(mech.ip_network)
81
+ .to eq(IPAddr.new('fe80::202:b3ff:fe1e:8329/64'))
82
+ end
83
+ end
84
+
85
+ context '.match' do
86
+ let(:client_ip) { IPAddr.new('fe80::202:b3ff:fe1e:8329') }
87
+
88
+ let(:macro_context) do
89
+ mc = double(:macro_context)
90
+ allow(mc).to receive(:ip_v6).and_return(client_ip)
91
+ mc
92
+ end
93
+
94
+ it 'should return true if the client IP is in the network' do
95
+ mech = Coppertone::Mechanism::IP6.create('fe80:0:0:0:202:b3ff:fe1e:8300/120')
96
+ expect(mech.match?(macro_context, double)).to eq(true)
97
+ end
98
+
99
+ it 'should return false if the client IP is not in the network' do
100
+ mech = Coppertone::Mechanism::IP6.create('fe80:0:0:0:202:b3ff:fe1e:8300/126')
101
+ expect(mech.match?(macro_context, double)).to eq(false)
102
+ end
103
+ end
104
+ end