spf-query 0.1.4 → 0.1.5
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 -4
- data/ChangeLog.md +9 -0
- data/LICENSE.txt +2 -2
- data/lib/resolv/dns/resource/in/spf.rb +3 -0
- data/lib/spf/query/exceptions.rb +8 -0
- data/lib/spf/query/ip.rb +23 -0
- data/lib/spf/query/macro.rb +40 -0
- data/lib/spf/query/macro_string.rb +39 -3
- data/lib/spf/query/mechanism.rb +56 -1
- data/lib/spf/query/modifier.rb +26 -0
- data/lib/spf/query/query.rb +1 -1
- data/lib/spf/query/record.rb +3 -0
- data/lib/spf/query/version.rb +2 -1
- data/spec/query_spec.rb +16 -0
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b9a9fddefde5c33a2ad1385bab0d15ca8477ad0a
|
4
|
+
data.tar.gz: ed9f792eb99ef6308b07627645efb7aae4eeb695
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 62515f4dd785031a84487205a3f7d85608464798e53b8667f09c69cf230590d398ccebd5aaf09e95951b1630c3a048268db28b59bde3e601afe40db385730817
|
7
|
+
data.tar.gz: 4647bd4bc4351b6cb2032a7dac1d6b05d51e93e6cafd308423abb07d9118d5c2655057da7d2068074331e81577ee39d44489f90621fadf9cf26ab21c49ccb6ca
|
data/.travis.yml
CHANGED
data/ChangeLog.md
CHANGED
@@ -1,3 +1,12 @@
|
|
1
|
+
### 0.1.5 / 2016-07-10
|
2
|
+
|
3
|
+
* Fixed a bug in {SPF::Query.query} for when the TXT record is split into
|
4
|
+
multiple strings. According to [RFC 7208, Section 3.3], multiple strings
|
5
|
+
should be joined together _without_ spaces.
|
6
|
+
* Fixed a bug in {SPF::Query::Mechanism#to_s}.
|
7
|
+
|
8
|
+
[RFC 7208, Section 3.3]: https://tools.ietf.org/html/rfc7208#section-3.3
|
9
|
+
|
1
10
|
### 0.1.4 / 2015-12-10
|
2
11
|
|
3
12
|
* Prioritize TXT records on `_spf.example.com` and `example.com` over a SPF
|
data/LICENSE.txt
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
The MIT License (MIT)
|
2
2
|
|
3
|
-
Copyright (c) 2014 Trail of Bits
|
3
|
+
Copyright (c) 2014-2016 Trail of Bits
|
4
4
|
|
5
5
|
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
6
6
|
this software and associated documentation files (the "Software"), to deal in
|
@@ -17,4 +17,4 @@ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
|
17
17
|
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
18
18
|
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
19
19
|
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
20
|
-
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
20
|
+
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/lib/spf/query/exceptions.rb
CHANGED
@@ -2,9 +2,17 @@ require 'parslet'
|
|
2
2
|
|
3
3
|
module SPF
|
4
4
|
module Query
|
5
|
+
#
|
6
|
+
# Exception for when the SPF record cannot be parsed.
|
7
|
+
#
|
5
8
|
class InvalidRecord < Parslet::ParseFailed
|
6
9
|
end
|
7
10
|
|
11
|
+
#
|
12
|
+
# Exception for when [SenderID] is found in-place of SPF.
|
13
|
+
#
|
14
|
+
# [SenderID]: http://www.openspf.org/SPF_vs_Sender_ID
|
15
|
+
#
|
8
16
|
class SenderIDFound < InvalidRecord
|
9
17
|
end
|
10
18
|
end
|
data/lib/spf/query/ip.rb
CHANGED
@@ -1,16 +1,39 @@
|
|
1
1
|
module SPF
|
2
2
|
module Query
|
3
|
+
#
|
4
|
+
# Represents an IP address in an SPF record.
|
5
|
+
#
|
3
6
|
class IP
|
4
7
|
|
8
|
+
# The address.
|
9
|
+
#
|
10
|
+
# @return [String]
|
5
11
|
attr_reader :address
|
6
12
|
|
13
|
+
# CIDR length.
|
14
|
+
#
|
15
|
+
# @return [Integer, nil]
|
7
16
|
attr_reader :cidr_length
|
8
17
|
|
18
|
+
#
|
19
|
+
# Initializes the IP.
|
20
|
+
#
|
21
|
+
# @param [String] address
|
22
|
+
# The IP address.
|
23
|
+
#
|
24
|
+
# @param [Integer, nil] cidr_length
|
25
|
+
# Optional CIDR length.
|
26
|
+
#
|
9
27
|
def initialize(address,cidr_length=nil)
|
10
28
|
@address = address
|
11
29
|
@cidr_length = cidr_length
|
12
30
|
end
|
13
31
|
|
32
|
+
#
|
33
|
+
# Converts the IP address to a String.
|
34
|
+
#
|
35
|
+
# @return [String]
|
36
|
+
#
|
14
37
|
def to_s
|
15
38
|
if @cidr_length then "#{@address}/#{@cidr_length}"
|
16
39
|
else "#{@address}"
|
data/lib/spf/query/macro.rb
CHANGED
@@ -1,13 +1,43 @@
|
|
1
1
|
module SPF
|
2
2
|
module Query
|
3
|
+
#
|
4
|
+
# Represents an SPF string macro.
|
5
|
+
#
|
3
6
|
class Macro
|
4
7
|
|
8
|
+
# The macro letter.
|
9
|
+
#
|
10
|
+
# @return [Symbol]
|
5
11
|
attr_reader :letter
|
6
12
|
|
13
|
+
# Number of times the macro must be repeated.
|
14
|
+
#
|
15
|
+
# @return [Integer, nil]
|
7
16
|
attr_reader :digits
|
8
17
|
|
18
|
+
# Macro delimiter character.
|
19
|
+
#
|
20
|
+
# @return [Array<String>]
|
9
21
|
attr_reader :delimiters
|
10
22
|
|
23
|
+
#
|
24
|
+
# Initializes the macro.
|
25
|
+
#
|
26
|
+
# @param [Symbol] letter
|
27
|
+
# The macro letter.
|
28
|
+
#
|
29
|
+
# @param [Hash] options
|
30
|
+
# Additional options.
|
31
|
+
#
|
32
|
+
# @option options [Integer] :digits
|
33
|
+
# Number of times to repeat the macro.
|
34
|
+
#
|
35
|
+
# @option options [Boolean] :reverse
|
36
|
+
# Whether to reverse the value.
|
37
|
+
#
|
38
|
+
# @option options [Array<String>, String] :delimiters
|
39
|
+
# Delimiter characters.
|
40
|
+
#
|
11
41
|
def initialize(letter,options={})
|
12
42
|
@letter = letter
|
13
43
|
@digits = options[:digits]
|
@@ -15,10 +45,20 @@ module SPF
|
|
15
45
|
@delimiters = Array(options[:delimiters])
|
16
46
|
end
|
17
47
|
|
48
|
+
#
|
49
|
+
# Specifies if the macro should be reversed.
|
50
|
+
#
|
51
|
+
# @return [Boolean]
|
52
|
+
#
|
18
53
|
def reverse?
|
19
54
|
@reverse
|
20
55
|
end
|
21
56
|
|
57
|
+
#
|
58
|
+
# Converts the macro a String.
|
59
|
+
#
|
60
|
+
# @return [String]
|
61
|
+
#
|
22
62
|
def to_s
|
23
63
|
"%{#{@letter}#{@digits}#{@delimiters.join}}"
|
24
64
|
end
|
@@ -1,29 +1,65 @@
|
|
1
1
|
module SPF
|
2
2
|
module Query
|
3
|
+
#
|
4
|
+
# Represents a string containing SPF macros.
|
5
|
+
#
|
3
6
|
class MacroString
|
4
7
|
|
5
8
|
include Enumerable
|
6
9
|
|
10
|
+
#
|
11
|
+
# Initializes the macro string.
|
12
|
+
#
|
13
|
+
# @param [Array<String, Macro>] elements
|
14
|
+
# String literals and String macros.
|
15
|
+
#
|
7
16
|
def initialize(elements)
|
8
17
|
@elements = elements
|
9
18
|
end
|
10
19
|
|
20
|
+
#
|
21
|
+
# Enumerates over the macro string literals and macros.
|
22
|
+
#
|
23
|
+
# @yield [element]
|
24
|
+
#
|
25
|
+
# @yieldparam [String, Macro] element
|
26
|
+
#
|
27
|
+
# @return [Enumerator]
|
28
|
+
# If no block is given, an Enumerator will be returned.
|
29
|
+
#
|
11
30
|
def each(&block)
|
12
31
|
@elements.each(&block)
|
13
32
|
end
|
14
33
|
|
34
|
+
#
|
35
|
+
# Accesses the String literal or macro at the given index or range.
|
36
|
+
#
|
37
|
+
# @param [Integer, (Integer, Integer), Range] arguments
|
38
|
+
# The index or range to access.
|
39
|
+
#
|
40
|
+
# @return [Array<String, Macro>, String, Macro]
|
41
|
+
# The String literal(s) or macro(s) at the given index or range.
|
42
|
+
#
|
15
43
|
def [](*arguments)
|
16
44
|
@elements[*arguments]
|
17
45
|
end
|
18
46
|
|
47
|
+
#
|
48
|
+
# Converts the macro string to an Array.
|
49
|
+
#
|
50
|
+
# @return [Array<String, Macro>]
|
51
|
+
#
|
19
52
|
def to_a
|
20
53
|
@elements
|
21
54
|
end
|
22
55
|
|
23
|
-
|
24
|
-
@elements
|
25
|
-
end
|
56
|
+
alias to_ary to_a
|
26
57
|
|
58
|
+
#
|
59
|
+
# Converts the macro string to a String.
|
60
|
+
#
|
61
|
+
# @return [String]
|
62
|
+
#
|
27
63
|
def to_s
|
28
64
|
@elements.join
|
29
65
|
end
|
data/lib/spf/query/mechanism.rb
CHANGED
@@ -1,18 +1,42 @@
|
|
1
1
|
module SPF
|
2
2
|
module Query
|
3
|
+
#
|
4
|
+
# Represents an SPF mechanism.
|
5
|
+
#
|
3
6
|
class Mechanism
|
4
7
|
|
8
|
+
# Maps qualifier symbols to Symbols
|
5
9
|
QUALIFIERS = {
|
6
10
|
'+' => :pass,
|
7
11
|
'-' => :fail,
|
8
12
|
'~' => :soft_fail,
|
9
|
-
'?' => :
|
13
|
+
'?' => :neutral
|
10
14
|
}
|
11
15
|
|
16
|
+
# The mechanism name.
|
17
|
+
#
|
18
|
+
# @return [Symbol]
|
12
19
|
attr_reader :name
|
13
20
|
|
21
|
+
# The mechanism value.
|
22
|
+
#
|
23
|
+
# @return [String, MacroString, IP, nil]
|
14
24
|
attr_reader :value
|
15
25
|
|
26
|
+
#
|
27
|
+
# Initializes the mechanism.
|
28
|
+
#
|
29
|
+
# @param [Symbol] name
|
30
|
+
#
|
31
|
+
# @param [Hash] options
|
32
|
+
# Additional options.
|
33
|
+
#
|
34
|
+
# @option options [String, MacroString, IP] :value
|
35
|
+
# Optional value.
|
36
|
+
#
|
37
|
+
# @option options [Symbol] :qualifier
|
38
|
+
# Mechanism qualifier.
|
39
|
+
#
|
16
40
|
def initialize(name,options={})
|
17
41
|
@name = name
|
18
42
|
|
@@ -20,26 +44,57 @@ module SPF
|
|
20
44
|
@qualifier = options[:qualifier]
|
21
45
|
end
|
22
46
|
|
47
|
+
#
|
48
|
+
# The mechanism qualifier.
|
49
|
+
#
|
50
|
+
# @return [:pass, :fail, :soft_fail, :neutral]
|
51
|
+
# The qualifier. Defaults to `:pass`.
|
52
|
+
#
|
23
53
|
def qualifier
|
24
54
|
@qualifier || :pass
|
25
55
|
end
|
26
56
|
|
57
|
+
#
|
58
|
+
# Determines whether the qualifier is a "pass".
|
59
|
+
#
|
60
|
+
# @return [Boolean]
|
61
|
+
#
|
27
62
|
def pass?
|
28
63
|
@qualifier == :pass || @qualifier.nil?
|
29
64
|
end
|
30
65
|
|
66
|
+
#
|
67
|
+
# Determines if the qualifier is a "fail".
|
68
|
+
#
|
69
|
+
# @return [Boolean]
|
70
|
+
#
|
31
71
|
def fail?
|
32
72
|
@qualifier == :fail
|
33
73
|
end
|
34
74
|
|
75
|
+
#
|
76
|
+
# Determines whether the qualifier is a "soft_fail".
|
77
|
+
#
|
78
|
+
# @return [Boolean]
|
79
|
+
#
|
35
80
|
def soft_fail?
|
36
81
|
@qualifier == :soft_fail
|
37
82
|
end
|
38
83
|
|
84
|
+
#
|
85
|
+
# Determines whether the qualifier is a "neutral".
|
86
|
+
#
|
87
|
+
# @return [Boolean]
|
88
|
+
#
|
39
89
|
def neutral?
|
40
90
|
@qualifier == :neutral
|
41
91
|
end
|
42
92
|
|
93
|
+
#
|
94
|
+
# Converts the mechanism to a String.
|
95
|
+
#
|
96
|
+
# @return [String]
|
97
|
+
#
|
43
98
|
def to_s
|
44
99
|
str = "#{QUALIFIERS.invert[@qualifier]}#{@name}"
|
45
100
|
str << ":#{@value}" if value
|
data/lib/spf/query/modifier.rb
CHANGED
@@ -1,15 +1,38 @@
|
|
1
1
|
module SPF
|
2
2
|
module Query
|
3
|
+
#
|
4
|
+
# Represents SPF record modifiers.
|
5
|
+
#
|
3
6
|
class Modifier
|
4
7
|
|
8
|
+
# Modifier name.
|
9
|
+
#
|
10
|
+
# @return [Symbol]
|
5
11
|
attr_reader :name
|
6
12
|
|
13
|
+
# Modifier value.
|
14
|
+
#
|
15
|
+
# @return [String, MacroString, IP, nil]
|
7
16
|
attr_reader :value
|
8
17
|
|
18
|
+
#
|
19
|
+
# Initializes the modifier.
|
20
|
+
#
|
21
|
+
# @param [Symbol] name
|
22
|
+
# Modifier name.
|
23
|
+
#
|
24
|
+
# @param [String, nil] value
|
25
|
+
# Modifier value.
|
26
|
+
#
|
9
27
|
def initialize(name,value=nil)
|
10
28
|
@name, @value = name, value
|
11
29
|
end
|
12
30
|
|
31
|
+
#
|
32
|
+
# Converts the modifier to a String.
|
33
|
+
#
|
34
|
+
# @return [String]
|
35
|
+
#
|
13
36
|
def to_s
|
14
37
|
if @value then "#{@name}=#{@value}"
|
15
38
|
else "#{@name}"
|
@@ -18,6 +41,9 @@ module SPF
|
|
18
41
|
|
19
42
|
end
|
20
43
|
|
44
|
+
#
|
45
|
+
# Represents non-standard modifier names.
|
46
|
+
#
|
21
47
|
class UnknownModifier < Modifier
|
22
48
|
end
|
23
49
|
end
|
data/lib/spf/query/query.rb
CHANGED
data/lib/spf/query/record.rb
CHANGED
data/lib/spf/query/version.rb
CHANGED
data/spec/query_spec.rb
CHANGED
@@ -19,6 +19,22 @@ describe SPF::Query do
|
|
19
19
|
end
|
20
20
|
end
|
21
21
|
|
22
|
+
context "when the domain.com has a TXT record" do
|
23
|
+
let(:domain) { 'yahoo.com' }
|
24
|
+
|
25
|
+
it "should return the TXT record containing the SPF record" do
|
26
|
+
expect(subject.query(domain)).to be == %{v=spf1 redirect=_spf.mail.yahoo.com}
|
27
|
+
end
|
28
|
+
|
29
|
+
context "and when the record is split into multiple strings" do
|
30
|
+
let(:domain) { 'fb.com' }
|
31
|
+
|
32
|
+
it "should join the strings, without spaces" do
|
33
|
+
expect(subject.query(domain)).to be == %{v=spf1 ip4:69.171.232.0/24 ip4:199.201.64.23 ip4:192.201.64.23 ip4:69.63.179.25 ip4:69.63.178.128/25 ip4:69.63.184.0/25 ip4:66.220.144.128/25 ip4:66.220.155.128/25 include:spf-00082601.pphosted.com mx -all}
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
22
38
|
context "when the domain has a SPF type record" do
|
23
39
|
let(:domain) { 'getlua.com' }
|
24
40
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: spf-query
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- nicktitle
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2016-06-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: parslet
|