coppertone 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 70afc7cde39b4b1374dd4b0a580b9908a15b8745
4
- data.tar.gz: ef5687a65195e0c2291f68bad0671b5448b35af6
3
+ metadata.gz: d50206e3df522c6100a46e2a6f64989d10da5774
4
+ data.tar.gz: 773a9709e679f5d45e5a7a6f779112ffea0e9aff
5
5
  SHA512:
6
- metadata.gz: f441c6616fe2346f55fa5251c74a15c5f77701684d612441a918572da57675a89b1cb956a4c7aee006e59f496dfd33b4378a133005eb703a66dbee9f7dde0ce4
7
- data.tar.gz: c9b568748213933e23c29ca8028cf96b8b179357cd02c0c7915dd05bba7adf033a5005be97f2677de9f70e6fb8afa17192765b59bb4251de1fd9410662c0b4d1
6
+ metadata.gz: 2752ba8667d8f7d8458cfa0429a4140f59a42af7a7ad52881b5a75f1e4881d2b4038a5fb1a8ca22dff54ca7301941da42400b94f87ddf5b6972ffb9de3900c06
7
+ data.tar.gz: 90cb6889a3ed66eb50663e0681ffc011641d20329c0ffb86b7d6af780d40189beb36fac80c78f4e1107295134d643a104bd7933c10ca99d265e693ff0590b90a
data/.travis.yml CHANGED
@@ -5,4 +5,5 @@ rvm:
5
5
  - 2.0.0
6
6
  - 2.1.2
7
7
  - jruby-19mode
8
+ - rbx
8
9
 
data/README.md CHANGED
@@ -17,13 +17,15 @@ One of the challenges of writing a gem that is intended to implement a specifica
17
17
  3. Coppertone defaults to using the DNS term and lookup limits defined in [RFC 7208](http://tools.ietf.org/html/rfc7208#section-4.6.4), but makes these limits configurable.
18
18
  4. Coppertone does not do TLD validation on domains encountered in SPF processing. Domains are syntactically validated, but the TLD value is not checked against the public access list.
19
19
 
20
+ To ensure compliance with [RFC 7208](http://tools.ietf.org/html/rfc7208), Coppertone includes the latest published version of the [OpenSPF specs](http://www.openspf.org/Test_Suite) in its RSpec test suite.
21
+
20
22
  If you'd like to suggest amending these guidelines, please open an issue for discussion. Suggestions driven by real world behavior - divergences implemented by major mail server vendors or MTAs will be prioritized.
21
23
 
22
24
  ## Requirements
23
25
 
24
- Coppertone supports MRI 2.0 and up - earlier MRI rubies are not supported. JRuby and Rubinius support is planned, but these VMs are not currently supported.
26
+ Coppertone supports MRI 2.0 and up - earlier MRI rubies are not supported. JRuby 1.7.16+ and Rubinius 2.2+ are also supported.
25
27
 
26
- Coppertone does not require Rails.
28
+ Coppertone does not require Rails, although it does depend on ActiveSupport.
27
29
 
28
30
  ## Installation
29
31
 
@@ -43,7 +45,17 @@ Or install it yourself as:
43
45
 
44
46
  ## Usage
45
47
 
46
- TODO: Write usage instructions here
48
+ To use Coppertone as a simple SPF checker (as you might, for example, if you were bundling it in a receiving SMTP server), you may use the `Coppertone::SpfService#authenticate_email` method.
49
+
50
+ For example, were you authenticating an email sent by an SMTP server with IP address 1.2.3.4, advertising a HELO domain of 'mailserver123.example.org' and sent from 'somerandomperson@example.org', you'd invoke the method as follows:
51
+
52
+ result = Coppertone::SpfService#authenticate_email('1.2.3.4',
53
+ 'somerandomperson@example.org',
54
+ 'mailserver123.example.org')
55
+
56
+ which would yield an instance of Coppertone::Result with the appropriate result code, and any explanation message. If the email was validated, then this result will also include the validating mechanism and the validated identity ('helo' or 'mailfrom').
57
+
58
+ For more sophisticated use of Coppertone, please consult the code and corresponding documentation directly.
47
59
 
48
60
  ## Contributing
49
61
 
@@ -19,6 +19,10 @@ module Coppertone
19
19
  end
20
20
  end
21
21
 
22
+ def context_dependent?
23
+ mechanism.context_dependent?
24
+ end
25
+
22
26
  def all?
23
27
  mechanism.is_a?(Coppertone::Mechanism::All)
24
28
  end
@@ -30,6 +30,13 @@ module Coppertone
30
30
  macros.any? { |m| m.is_a?(Coppertone::MacroString::MacroExpand) }
31
31
  end
32
32
 
33
+ def includes_ptr?
34
+ expanded_macros = macros.select do |m|
35
+ m.is_a?(Coppertone::MacroString::MacroExpand)
36
+ end
37
+ expanded_macros.any?(&:ptr_macro?)
38
+ end
39
+
33
40
  def ==(other)
34
41
  return false unless other.instance_of? self.class
35
42
  macro_text == other.macro_text
@@ -22,6 +22,11 @@ module Coppertone
22
22
  return true unless domain_spec
23
23
  domain_spec.context_dependent?
24
24
  end
25
+
26
+ def includes_ptr?
27
+ return false unless domain_spec
28
+ domain_spec.includes_ptr?
29
+ end
25
30
  end
26
31
  end
27
32
  end
@@ -21,6 +21,15 @@ 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
+
24
33
  def self.label
25
34
  'include'
26
35
  end
@@ -42,6 +42,10 @@ module Coppertone
42
42
  def context_dependent?
43
43
  false
44
44
  end
45
+
46
+ def includes_ptr?
47
+ false
48
+ end
45
49
  end
46
50
  end
47
51
 
@@ -16,6 +16,14 @@ module Coppertone
16
16
  Coppertone::Utils::DomainUtils.macro_expanded_domain(domain)
17
17
  end
18
18
 
19
+ def context_dependent?
20
+ domain_spec.context_dependent?
21
+ end
22
+
23
+ def includes_ptr?
24
+ domain_spec.includes_ptr?
25
+ end
26
+
19
27
  def ==(other)
20
28
  return false unless other.instance_of? self.class
21
29
  domain_spec == other.domain_spec
@@ -12,6 +12,17 @@ module Coppertone
12
12
  target_name_from_domain_spec(macro_context, request_context)
13
13
  end
14
14
 
15
+ def included_record(macro_context, request_context)
16
+ RedirectRecordFinder.new(self, macro_context, request_context).record
17
+ end
18
+
19
+ def context_dependent_result?(request_context,
20
+ macro_context =
21
+ Coppertone::NullMacroContext.new)
22
+ included_record(macro_context, request_context)
23
+ .context_dependent_result?(request_context)
24
+ end
25
+
15
26
  def self.label
16
27
  'redirect'
17
28
  end
@@ -12,6 +12,14 @@ module Coppertone
12
12
  raise Coppertone::InvalidModifierError
13
13
  end
14
14
 
15
+ def context_dependent?
16
+ false
17
+ end
18
+
19
+ def includes_ptr?
20
+ false
21
+ end
22
+
15
23
  def self.label
16
24
  'unknown'
17
25
  end
@@ -1,8 +1,7 @@
1
1
  module Coppertone
2
- # A context used to evaluate records, directives, and modifiers that do not have
3
- # contextual dependence.
2
+ # A context used to evaluate records, directives, and modifiers that
3
+ # do not have contextual dependence.
4
4
  class NullMacroContext
5
-
6
5
  RESERVED_REGEXP = Regexp.new("[^#{URI::PATTERN::UNRESERVED}]")
7
6
  %w(s l o d i p v h c r t).each do |m|
8
7
  define_method(m.upcase) do
@@ -14,10 +13,10 @@ module Coppertone
14
13
  end
15
14
  end
16
15
 
17
- def with_domain(new_domain)
16
+ def with_domain(_new_domain)
18
17
  self
19
18
  end
20
19
 
21
20
  NULL_CONTEXT = new
22
21
  end
23
- end
22
+ end
@@ -38,6 +38,15 @@ module Coppertone
38
38
  include_all?
39
39
  end
40
40
 
41
+ def includes
42
+ @includes ||=
43
+ begin
44
+ directives.select do |d|
45
+ d.mechanism.is_a?(Coppertone::Mechanism::Include)
46
+ end
47
+ end
48
+ end
49
+
41
50
  def modifiers
42
51
  @modifiers ||= @terms.select { |t| t.is_a?(Coppertone::Modifier) }
43
52
  end
@@ -54,6 +63,23 @@ module Coppertone
54
63
  @exp ||= find_modifier(Coppertone::Modifier::Exp)
55
64
  end
56
65
 
66
+ def context_dependent_result?(request_context)
67
+ return true if directives.exist?(&:context_dependent)
68
+ return true if context_dependent_redirect_result?(request_context)
69
+ return false if includes.blank?
70
+ includes.exists? { |i| i.context_dependent_result?(request_context) }
71
+ end
72
+
73
+ def context_dependent_redirect_result?(request_context)
74
+ return false unless redirect
75
+ redirect.context_dependent? ||
76
+ redirect.context_dependent_result?(request_context)
77
+ end
78
+
79
+ def context_dependent_message?
80
+ exp && exp.context_dependent?
81
+ end
82
+
57
83
  KNOWN_MODS =
58
84
  [Coppertone::Modifier::Exp, Coppertone::Modifier::Redirect]
59
85
  def unknown_modifiers
@@ -50,14 +50,12 @@ module Coppertone
50
50
 
51
51
  def evaluate_none_result(result, macro_context, request_context)
52
52
  return result unless follow_redirect?
53
- redirect_target = record.redirect.evaluate(macro_context, request_context)
54
- if redirect_target
55
- redirect_record =
56
- RecordFinder.new(request_context.dns_client, redirect_target).record
57
- end
58
- fail InvalidRedirectError unless redirect_record
59
- rc = macro_context.with_domain(redirect_target)
60
- RecordEvaluator.new(redirect_record).evaluate(rc, request_context)
53
+ finder =
54
+ Coppertone::RedirectRecordFinder.new(record.redirect, macro_context,
55
+ request_context)
56
+ fail InvalidRedirectError unless finder.target && finder.record
57
+ rc = macro_context.with_domain(finder.target)
58
+ RecordEvaluator.new(finder.record).evaluate(rc, request_context)
61
59
  end
62
60
  end
63
61
  end
@@ -1,4 +1,5 @@
1
1
  module Coppertone
2
+ # Parses a record into terms
2
3
  class RecordTermParser
3
4
  VERSION_STR = 'v=spf1'
4
5
  RECORD_REGEXP = /\A#{VERSION_STR}(\s|\z)/i
@@ -0,0 +1,20 @@
1
+ module Coppertone
2
+ # A helper class for finding SPF records for a redirect modifier.
3
+ class RedirectRecordFinder
4
+ attr_reader :redirect, :macro_context, :request_context
5
+ def initialize(redirect, macro_context, request_context)
6
+ @redirect = redirect
7
+ @macro_context = macro_context
8
+ @request_context = request_context
9
+ end
10
+
11
+ def target
12
+ @redirect_target ||= redirect.evaluate(macro_context, request_context)
13
+ end
14
+
15
+ def record
16
+ return unless target
17
+ @record ||= RecordFinder.new(request_context.dns_client, target).record
18
+ end
19
+ end
20
+ end
@@ -1,3 +1,3 @@
1
1
  module Coppertone # rubocop:disable Style/Documentation
2
- VERSION = '0.0.2'.freeze
2
+ VERSION = '0.0.3'.freeze
3
3
  end
data/lib/coppertone.rb CHANGED
@@ -46,5 +46,6 @@ require 'coppertone/record_term_parser'
46
46
  require 'coppertone/record'
47
47
  require 'coppertone/record_evaluator'
48
48
  require 'coppertone/record_finder'
49
+ require 'coppertone/redirect_record_finder'
49
50
  require 'coppertone/request'
50
51
  require 'coppertone/spf_service'
@@ -9,6 +9,8 @@ describe Coppertone::Mechanism::A do
9
9
  expect(mech.ip_v4_cidr_length).to eq(32)
10
10
  expect(mech.ip_v6_cidr_length).to eq(128)
11
11
  expect(mech.to_s).to eq('a')
12
+ expect(mech).not_to be_includes_ptr
13
+ expect(mech).to be_context_dependent
12
14
  end
13
15
 
14
16
  it 'should not fail if called with a blank argument' do
@@ -18,6 +20,8 @@ describe Coppertone::Mechanism::A do
18
20
  expect(mech.ip_v4_cidr_length).to eq(32)
19
21
  expect(mech.ip_v6_cidr_length).to eq(128)
20
22
  expect(mech.to_s).to eq('a')
23
+ expect(mech).not_to be_includes_ptr
24
+ expect(mech).to be_context_dependent
21
25
  end
22
26
 
23
27
  it 'should fail if called with an invalid macrostring' do
@@ -26,7 +30,19 @@ describe Coppertone::Mechanism::A do
26
30
  end.to raise_error(Coppertone::InvalidMechanismError)
27
31
  end
28
32
 
29
- it 'should parse a domain spec' do
33
+ it 'should parse a context independent domain spec' do
34
+ mech = Coppertone::Mechanism::A.new(':_spf.example.com')
35
+ expect(mech).not_to be_nil
36
+ expect(mech.domain_spec)
37
+ .to eq(Coppertone::DomainSpec.new('_spf.example.com'))
38
+ expect(mech.ip_v4_cidr_length).to eq(32)
39
+ expect(mech.ip_v6_cidr_length).to eq(128)
40
+ expect(mech.to_s).to eq('a:_spf.example.com')
41
+ expect(mech).not_to be_includes_ptr
42
+ expect(mech).not_to be_context_dependent
43
+ end
44
+
45
+ it 'should parse a context dependent domain spec' do
30
46
  mech = Coppertone::Mechanism::A.new(':_spf.%{d}.example.com')
31
47
  expect(mech).not_to be_nil
32
48
  expect(mech.domain_spec)
@@ -34,6 +50,20 @@ describe Coppertone::Mechanism::A do
34
50
  expect(mech.ip_v4_cidr_length).to eq(32)
35
51
  expect(mech.ip_v6_cidr_length).to eq(128)
36
52
  expect(mech.to_s).to eq('a:_spf.%{d}.example.com')
53
+ expect(mech).not_to be_includes_ptr
54
+ expect(mech).to be_context_dependent
55
+ end
56
+
57
+ it 'should parse a domain spec with a ptr' do
58
+ mech = Coppertone::Mechanism::A.new(':_spf.%{p}.example.com')
59
+ expect(mech).not_to be_nil
60
+ expect(mech.domain_spec)
61
+ .to eq(Coppertone::DomainSpec.new('_spf.%{p}.example.com'))
62
+ expect(mech.ip_v4_cidr_length).to eq(32)
63
+ expect(mech.ip_v6_cidr_length).to eq(128)
64
+ expect(mech.to_s).to eq('a:_spf.%{p}.example.com')
65
+ expect(mech).to be_includes_ptr
66
+ expect(mech).to be_context_dependent
37
67
  end
38
68
 
39
69
  it 'should parse a valid IP v4 CIDR length with a domain spec' do
@@ -5,6 +5,8 @@ describe Coppertone::Mechanism::All do
5
5
  it 'should always return true regardless of argument' do
6
6
  expect(subject.match?(double, double)).to eq(true)
7
7
  expect(subject.to_s).to eq('all')
8
+ expect(subject).not_to be_includes_ptr
9
+ expect(subject).not_to be_context_dependent
8
10
  end
9
11
 
10
12
  it 'should not allow creation of new instances' do
@@ -20,9 +20,34 @@ describe Coppertone::Mechanism::Exists do
20
20
  end.to raise_error(Coppertone::InvalidMechanismError)
21
21
  end
22
22
 
23
- it 'should succeed if called with a valid macrostring' do
24
- mech = Coppertone::Mechanism::Exists.new(':%{d}.example.com')
25
- expect(mech.to_s).to eq('exists:%{d}.example.com')
23
+ it 'should parse a context independent domain spec' do
24
+ mech = Coppertone::Mechanism::Exists.new(':_spf.example.com')
25
+ expect(mech).not_to be_nil
26
+ expect(mech.domain_spec)
27
+ .to eq(Coppertone::DomainSpec.new('_spf.example.com'))
28
+ expect(mech.to_s).to eq('exists:_spf.example.com')
29
+ expect(mech).not_to be_includes_ptr
30
+ expect(mech).not_to be_context_dependent
31
+ end
32
+
33
+ it 'should parse a context dependent domain spec' do
34
+ mech = Coppertone::Mechanism::Exists.new(':_spf.%{d}.example.com')
35
+ expect(mech).not_to be_nil
36
+ expect(mech.domain_spec)
37
+ .to eq(Coppertone::DomainSpec.new('_spf.%{d}.example.com'))
38
+ expect(mech.to_s).to eq('exists:_spf.%{d}.example.com')
39
+ expect(mech).not_to be_includes_ptr
40
+ expect(mech).to be_context_dependent
41
+ end
42
+
43
+ it 'should parse a domain spec with a ptr' do
44
+ mech = Coppertone::Mechanism::Exists.new(':_spf.%{p}.example.com')
45
+ expect(mech).not_to be_nil
46
+ expect(mech.domain_spec)
47
+ .to eq(Coppertone::DomainSpec.new('_spf.%{p}.example.com'))
48
+ expect(mech.to_s).to eq('exists:_spf.%{p}.example.com')
49
+ expect(mech).to be_includes_ptr
50
+ expect(mech).to be_context_dependent
26
51
  end
27
52
  end
28
53
 
@@ -20,9 +20,34 @@ describe Coppertone::Mechanism::Include do
20
20
  end.to raise_error(Coppertone::InvalidMechanismError)
21
21
  end
22
22
 
23
- it 'creates a mechanism if called with a valid macrostring' do
23
+ it 'should parse a context independent domain spec' do
24
24
  mech = Coppertone::Mechanism::Include.new(':_spf.example.com')
25
+ expect(mech).not_to be_nil
26
+ expect(mech.domain_spec)
27
+ .to eq(Coppertone::DomainSpec.new('_spf.example.com'))
25
28
  expect(mech.to_s).to eq('include:_spf.example.com')
29
+ expect(mech).not_to be_includes_ptr
30
+ expect(mech).not_to be_context_dependent
31
+ end
32
+
33
+ it 'should parse a context dependent domain spec' do
34
+ mech = Coppertone::Mechanism::Include.new(':_spf.%{d}.example.com')
35
+ expect(mech).not_to be_nil
36
+ expect(mech.domain_spec)
37
+ .to eq(Coppertone::DomainSpec.new('_spf.%{d}.example.com'))
38
+ expect(mech.to_s).to eq('include:_spf.%{d}.example.com')
39
+ expect(mech).not_to be_includes_ptr
40
+ expect(mech).to be_context_dependent
41
+ end
42
+
43
+ it 'should parse a domain spec with a ptr' do
44
+ mech = Coppertone::Mechanism::Include.new(':_spf.%{p}.example.com')
45
+ expect(mech).not_to be_nil
46
+ expect(mech.domain_spec)
47
+ .to eq(Coppertone::DomainSpec.new('_spf.%{p}.example.com'))
48
+ expect(mech.to_s).to eq('include:_spf.%{p}.example.com')
49
+ expect(mech).to be_includes_ptr
50
+ expect(mech).to be_context_dependent
26
51
  end
27
52
  end
28
53
 
@@ -24,18 +24,24 @@ describe Coppertone::Mechanism::IP4 do
24
24
  mech = Coppertone::Mechanism::IP4.new(':fe80::202:b3ff:fe1e:8329')
25
25
  expect(mech.ip_network).to eq(IPAddr.new('fe80::202:b3ff:fe1e:8329'))
26
26
  expect(mech.to_s).to eq('ip4:fe80::202:b3ff:fe1e:8329')
27
+ expect(mech).not_to be_includes_ptr
28
+ expect(mech).not_to be_context_dependent
27
29
  end
28
30
 
29
31
  it 'should work if called with an IP4' do
30
32
  mech = Coppertone::Mechanism::IP4.new(':1.2.3.4')
31
33
  expect(mech.ip_network).to eq(IPAddr.new('1.2.3.4'))
32
34
  expect(mech.to_s).to eq('ip4:1.2.3.4')
35
+ expect(mech).not_to be_includes_ptr
36
+ expect(mech).not_to be_context_dependent
33
37
  end
34
38
 
35
39
  it 'should work if called with an IP4 with a pfxlen' do
36
40
  mech = Coppertone::Mechanism::IP4.new(':1.2.3.4/4')
37
41
  expect(mech.ip_network).to eq(IPAddr.new('1.2.3.4/4'))
38
42
  expect(mech.to_s).to eq('ip4:1.2.3.4/4')
43
+ expect(mech).not_to be_includes_ptr
44
+ expect(mech).not_to be_context_dependent
39
45
  end
40
46
  end
41
47
 
@@ -67,18 +67,24 @@ describe Coppertone::Mechanism::IP6 do
67
67
  it 'should not fail if called with an IP v4' do
68
68
  mech = Coppertone::Mechanism::IP6.create(':1.2.3.4')
69
69
  expect(mech.ip_network).to eq(IPAddr.new('1.2.3.4'))
70
+ expect(mech).not_to be_includes_ptr
71
+ expect(mech).not_to be_context_dependent
70
72
  end
71
73
 
72
74
  it 'should work if called with an IP6' do
73
75
  mech = Coppertone::Mechanism::IP6.create(':fe80::202:b3ff:fe1e:8329')
74
76
  expect(mech.ip_network)
75
77
  .to eq(IPAddr.new('fe80::202:b3ff:fe1e:8329'))
78
+ expect(mech).not_to be_includes_ptr
79
+ expect(mech).not_to be_context_dependent
76
80
  end
77
81
 
78
82
  it 'should work if called with an IP6 with a pfxlen' do
79
83
  mech = Coppertone::Mechanism::IP6.create(':fe80::202:b3ff:fe1e:8329/64')
80
84
  expect(mech.ip_network)
81
85
  .to eq(IPAddr.new('fe80::202:b3ff:fe1e:8329/64'))
86
+ expect(mech).not_to be_includes_ptr
87
+ expect(mech).not_to be_context_dependent
82
88
  end
83
89
  end
84
90
 
@@ -9,6 +9,8 @@ describe Coppertone::Mechanism::MX do
9
9
  expect(mech.ip_v4_cidr_length).to eq(32)
10
10
  expect(mech.ip_v6_cidr_length).to eq(128)
11
11
  expect(mech.to_s).to eq('mx')
12
+ expect(mech).not_to be_includes_ptr
13
+ expect(mech).to be_context_dependent
12
14
  end
13
15
 
14
16
  it 'should not fail if called with a blank argument' do
@@ -18,6 +20,8 @@ describe Coppertone::Mechanism::MX do
18
20
  expect(mech.ip_v4_cidr_length).to eq(32)
19
21
  expect(mech.ip_v6_cidr_length).to eq(128)
20
22
  expect(mech.to_s).to eq('mx')
23
+ expect(mech).not_to be_includes_ptr
24
+ expect(mech).to be_context_dependent
21
25
  end
22
26
 
23
27
  it 'should fail if called with an invalid macrostring' do
@@ -33,6 +37,8 @@ describe Coppertone::Mechanism::MX do
33
37
  expect(mech.ip_v4_cidr_length).to eq(24)
34
38
  expect(mech.ip_v6_cidr_length).to eq(128)
35
39
  expect(mech.to_s).to eq('mx/24')
40
+ expect(mech).not_to be_includes_ptr
41
+ expect(mech).to be_context_dependent
36
42
  end
37
43
 
38
44
  it 'should process the domain spec if it includes a IP v6 CIDR' do
@@ -42,6 +48,8 @@ describe Coppertone::Mechanism::MX do
42
48
  expect(mech.ip_v4_cidr_length).to eq(32)
43
49
  expect(mech.ip_v6_cidr_length).to eq(96)
44
50
  expect(mech.to_s).to eq('mx//96')
51
+ expect(mech).not_to be_includes_ptr
52
+ expect(mech).to be_context_dependent
45
53
  end
46
54
 
47
55
  it 'should process the domain spec if it includes an IP v4 CIDR and an IP v6 CIDR' do
@@ -51,9 +59,11 @@ describe Coppertone::Mechanism::MX do
51
59
  expect(mech.ip_v4_cidr_length).to eq(28)
52
60
  expect(mech.ip_v6_cidr_length).to eq(96)
53
61
  expect(mech.to_s).to eq('mx/28//96')
62
+ expect(mech).not_to be_includes_ptr
63
+ expect(mech).to be_context_dependent
54
64
  end
55
65
 
56
- it 'should not fail if called with a blank argument' do
66
+ it 'should not fail if called with a fixed domain spec without explicit CIDRs' do
57
67
  mech = Coppertone::Mechanism::MX.new(':mx.example.com')
58
68
  expect(mech).not_to be_nil
59
69
  expect(mech.domain_spec)
@@ -61,9 +71,11 @@ describe Coppertone::Mechanism::MX do
61
71
  expect(mech.ip_v4_cidr_length).to eq(32)
62
72
  expect(mech.ip_v6_cidr_length).to eq(128)
63
73
  expect(mech.to_s).to eq('mx:mx.example.com')
74
+ expect(mech).not_to be_includes_ptr
75
+ expect(mech).not_to be_context_dependent
64
76
  end
65
77
 
66
- it 'should not fail if called with a blank argument' do
78
+ it 'should not fail if called with a fixed domain spec with explicit CIDRs' do
67
79
  mech = Coppertone::Mechanism::MX.new(':mx.example.com/28//96')
68
80
  expect(mech).not_to be_nil
69
81
  expect(mech.domain_spec)
@@ -72,6 +84,54 @@ describe Coppertone::Mechanism::MX do
72
84
  expect(mech.ip_v6_cidr_length).to eq(96)
73
85
  expect(mech.to_s).to eq('mx:mx.example.com/28//96')
74
86
  end
87
+
88
+ it 'should not fail if called with a context-dependent domain spec without explicit CIDRs' do
89
+ mech = Coppertone::Mechanism::MX.new(':%{d}.example.com')
90
+ expect(mech).not_to be_nil
91
+ expect(mech.domain_spec)
92
+ .to eq(Coppertone::DomainSpec.new('%{d}.example.com'))
93
+ expect(mech.ip_v4_cidr_length).to eq(32)
94
+ expect(mech.ip_v6_cidr_length).to eq(128)
95
+ expect(mech.to_s).to eq('mx:%{d}.example.com')
96
+ expect(mech).not_to be_includes_ptr
97
+ expect(mech).to be_context_dependent
98
+ end
99
+
100
+ it 'should not fail if called with a fixed domain spec with explicit CIDRs' do
101
+ mech = Coppertone::Mechanism::MX.new(':%{d}.example.com/28//96')
102
+ expect(mech).not_to be_nil
103
+ expect(mech.domain_spec)
104
+ .to eq(Coppertone::DomainSpec.new('%{d}.example.com'))
105
+ expect(mech.ip_v4_cidr_length).to eq(28)
106
+ expect(mech.ip_v6_cidr_length).to eq(96)
107
+ expect(mech.to_s).to eq('mx:%{d}.example.com/28//96')
108
+ expect(mech).not_to be_includes_ptr
109
+ expect(mech).to be_context_dependent
110
+ end
111
+
112
+ it 'should not fail if called with a context-dependent domain spec without explicit CIDRs with PTR' do
113
+ mech = Coppertone::Mechanism::MX.new(':%{p}.example.com')
114
+ expect(mech).not_to be_nil
115
+ expect(mech.domain_spec)
116
+ .to eq(Coppertone::DomainSpec.new('%{p}.example.com'))
117
+ expect(mech.ip_v4_cidr_length).to eq(32)
118
+ expect(mech.ip_v6_cidr_length).to eq(128)
119
+ expect(mech.to_s).to eq('mx:%{p}.example.com')
120
+ expect(mech).to be_includes_ptr
121
+ expect(mech).to be_context_dependent
122
+ end
123
+
124
+ it 'should not fail if called with a fixed domain spec with explicit CIDRs with PTR' do
125
+ mech = Coppertone::Mechanism::MX.new(':%{p}.example.com/28//96')
126
+ expect(mech).not_to be_nil
127
+ expect(mech.domain_spec)
128
+ .to eq(Coppertone::DomainSpec.new('%{p}.example.com'))
129
+ expect(mech.ip_v4_cidr_length).to eq(28)
130
+ expect(mech.ip_v6_cidr_length).to eq(96)
131
+ expect(mech.to_s).to eq('mx:%{p}.example.com/28//96')
132
+ expect(mech).to be_includes_ptr
133
+ expect(mech).to be_context_dependent
134
+ end
75
135
  end
76
136
 
77
137
  context '#create' do
@@ -6,12 +6,16 @@ describe Coppertone::Mechanism::Ptr do
6
6
  mech = Coppertone::Mechanism::Ptr.new(nil)
7
7
  expect(mech).not_to be_nil
8
8
  expect(mech.domain_spec).to be_nil
9
+ expect(mech).not_to be_includes_ptr
10
+ expect(mech).to be_context_dependent
9
11
  end
10
12
 
11
13
  it 'should not fail if called with a blank argument' do
12
14
  mech = Coppertone::Mechanism::Ptr.new('')
13
15
  expect(mech).not_to be_nil
14
16
  expect(mech.domain_spec).to be_nil
17
+ expect(mech).not_to be_includes_ptr
18
+ expect(mech).to be_context_dependent
15
19
  end
16
20
 
17
21
  it 'should fail if called with an invalid macrostring' do
@@ -1,6 +1,41 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Coppertone::Modifier::Exp do
4
+ context '#new' do
5
+ it 'should work with a context independent domain spec' do
6
+ modifier = Coppertone::Modifier::Exp.new('test.example.com')
7
+ expect(modifier).not_to be_nil
8
+ expect(modifier.domain_spec)
9
+ .to eq(Coppertone::DomainSpec.new('test.example.com'))
10
+ expect(modifier.to_s)
11
+ .to eq('exp=test.example.com')
12
+ expect(modifier).not_to be_includes_ptr
13
+ expect(modifier).not_to be_context_dependent
14
+ end
15
+
16
+ it 'should work with a context independent domain spec' do
17
+ modifier = Coppertone::Modifier::Exp.new('%{d}.example.com')
18
+ expect(modifier).not_to be_nil
19
+ expect(modifier.domain_spec)
20
+ .to eq(Coppertone::DomainSpec.new('%{d}.example.com'))
21
+ expect(modifier.to_s)
22
+ .to eq('exp=%{d}.example.com')
23
+ expect(modifier).not_to be_includes_ptr
24
+ expect(modifier).to be_context_dependent
25
+ end
26
+
27
+ it 'should work with a context independent domain spec with a PTR' do
28
+ modifier = Coppertone::Modifier::Exp.new('%{p}.example.com')
29
+ expect(modifier).not_to be_nil
30
+ expect(modifier.domain_spec)
31
+ .to eq(Coppertone::DomainSpec.new('%{p}.example.com'))
32
+ expect(modifier.to_s)
33
+ .to eq('exp=%{p}.example.com')
34
+ expect(modifier).to be_includes_ptr
35
+ expect(modifier).to be_context_dependent
36
+ end
37
+ end
38
+
4
39
  context 'to_s' do
5
40
  it 'should result in the expected string' do
6
41
  expect(Coppertone::Modifier::Exp.new('test.example.com').to_s)
@@ -1,6 +1,41 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Coppertone::Modifier::Redirect do
4
+ context '#new' do
5
+ it 'should work with a context independent domain spec' do
6
+ modifier = Coppertone::Modifier::Redirect.new('test.example.com')
7
+ expect(modifier).not_to be_nil
8
+ expect(modifier.domain_spec)
9
+ .to eq(Coppertone::DomainSpec.new('test.example.com'))
10
+ expect(modifier.to_s)
11
+ .to eq('redirect=test.example.com')
12
+ expect(modifier).not_to be_includes_ptr
13
+ expect(modifier).not_to be_context_dependent
14
+ end
15
+
16
+ it 'should work with a context independent domain spec' do
17
+ modifier = Coppertone::Modifier::Redirect.new('%{d}.example.com')
18
+ expect(modifier).not_to be_nil
19
+ expect(modifier.domain_spec)
20
+ .to eq(Coppertone::DomainSpec.new('%{d}.example.com'))
21
+ expect(modifier.to_s)
22
+ .to eq('redirect=%{d}.example.com')
23
+ expect(modifier).not_to be_includes_ptr
24
+ expect(modifier).to be_context_dependent
25
+ end
26
+
27
+ it 'should work with a context independent domain spec with a PTR' do
28
+ modifier = Coppertone::Modifier::Redirect.new('%{p}.example.com')
29
+ expect(modifier).not_to be_nil
30
+ expect(modifier.domain_spec)
31
+ .to eq(Coppertone::DomainSpec.new('%{p}.example.com'))
32
+ expect(modifier.to_s)
33
+ .to eq('redirect=%{p}.example.com')
34
+ expect(modifier).to be_includes_ptr
35
+ expect(modifier).to be_context_dependent
36
+ end
37
+ end
38
+
4
39
  context 'to_s' do
5
40
  it 'should result in the expected string' do
6
41
  expect(Coppertone::Modifier::Redirect.new('test.example.com').to_s)
@@ -0,0 +1,4 @@
1
+ require 'spec_helper'
2
+
3
+ describe Coppertone::RedirectRecordFinder do
4
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: coppertone
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Peter M. Goldstein
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-09-27 00:00:00.000000000 Z
11
+ date: 2014-10-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  requirement: !ruby/object:Gem::Requirement
@@ -175,6 +175,7 @@ files:
175
175
  - lib/coppertone/record_evaluator.rb
176
176
  - lib/coppertone/record_finder.rb
177
177
  - lib/coppertone/record_term_parser.rb
178
+ - lib/coppertone/redirect_record_finder.rb
178
179
  - lib/coppertone/request.rb
179
180
  - lib/coppertone/request_context.rb
180
181
  - lib/coppertone/request_count_limiter.rb
@@ -228,6 +229,7 @@ files:
228
229
  - spec/record_evaluator_spec.rb
229
230
  - spec/record_finder_spec.rb
230
231
  - spec/record_spec.rb
232
+ - spec/redirect_record_finder_spec.rb
231
233
  - spec/request_context_spec.rb
232
234
  - spec/request_count_limiter_spec.rb
233
235
  - spec/result_spec.rb
@@ -304,6 +306,7 @@ test_files:
304
306
  - spec/record_evaluator_spec.rb
305
307
  - spec/record_finder_spec.rb
306
308
  - spec/record_spec.rb
309
+ - spec/redirect_record_finder_spec.rb
307
310
  - spec/request_context_spec.rb
308
311
  - spec/request_count_limiter_spec.rb
309
312
  - spec/result_spec.rb