dkim-query 0.2.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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 6a9a19d4d8e858912741c97e5aa6327db4384823
4
+ data.tar.gz: 9d89cefe4db5f22c1de6b6b75b006634b4f4b708
5
+ SHA512:
6
+ metadata.gz: 8a48826f63465c69a2f098d4ad644ad7a750cc7f9fc33af0fa28cdd1da8aaec03132d1fae5d8d237625c9267669dc3f2e1648dbfc385dd87370d8420b336ad50
7
+ data.tar.gz: 9cebe26aeb4cedcb2bcd5991636b103271da72fcd92bcda9dea3e4cdded337d082dda9d041125a2f21ee89866a3a07e136f0ec0f93b8b26d8be6dfd869b20bbc
data/.gitignore ADDED
@@ -0,0 +1,51 @@
1
+ <<<<<<< HEAD
2
+ /.bundle/
3
+ /.yardoc
4
+ /Gemfile.lock
5
+ /_yardoc/
6
+ /coverage/
7
+ /doc/
8
+ /pkg/
9
+ /spec/reports/
10
+ /tmp/
11
+ *.bundle
12
+ *.so
13
+ *.o
14
+ *.a
15
+ mkmf.log
16
+ =======
17
+ *.gem
18
+ *.rbc
19
+ /.config
20
+ /coverage/
21
+ /InstalledFiles
22
+ /pkg/
23
+ /spec/reports/
24
+ /test/tmp/
25
+ /test/version_tmp/
26
+ /tmp/
27
+
28
+ ## Specific to RubyMotion:
29
+ .dat*
30
+ .repl_history
31
+ build/
32
+
33
+ ## Documentation cache and generated files:
34
+ /.yardoc/
35
+ /_yardoc/
36
+ /doc/
37
+ /rdoc/
38
+
39
+ ## Environment normalisation:
40
+ /.bundle/
41
+ /lib/bundler/man/
42
+
43
+ # for a library or gem, you might want to ignore these files since the code is
44
+ # intended to run in multiple environments; otherwise, check them in:
45
+ # Gemfile.lock
46
+ # .ruby-version
47
+ # .ruby-gemset
48
+
49
+ # unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
50
+ .rvmrc
51
+ >>>>>>> 62c17ee30b1a7d25ef12fab39fd6c2de0bcbadbc
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --colour --format documentation
data/.travis.yml ADDED
@@ -0,0 +1,17 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.9.3
4
+ - 2.0
5
+ - 2.1
6
+ - 2.2
7
+ - jruby
8
+ - rbx-2
9
+ matrix:
10
+ allow_failures:
11
+ - rvm: rbx-2
12
+ addons:
13
+ code_climate:
14
+ repo_token: 151a667c2c51ff76ac825c07c33e8e63c1ae9956a73f4d0ec7a043d877d05c95
15
+ notifications:
16
+ slack:
17
+ secure: Ykcz/gLRZcXhyOGedVgj1u3CDUbZS4y/nL1dREBE0Ar73Vrz+ulcMhri3VzfVBQGkWw06EjqHcIwsIomEInLJKxk3RTfpcYQAdYN+5iEDNOri9a5NK618WdrCuaCS3sKqYbJ/KB0slJDcJ1W+EXkr4GRqZTr5rPdmllUnoaqDCQ=
data/.yardopts ADDED
@@ -0,0 +1 @@
1
+ --markup markdown --title "DKIM::Query Documentation" --protected
data/ChangeLog.md ADDED
@@ -0,0 +1,3 @@
1
+ ### 0.2.1 / 2015-07-01
2
+
3
+ * Initial release.
data/Gemfile ADDED
@@ -0,0 +1,17 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in dkim-query.gemspec
4
+ gemspec
5
+
6
+ group :development do
7
+ gem 'rake'
8
+ gem 'rspec', '~> 3.0'
9
+
10
+ gem 'kramdown'
11
+ gem 'yard', '~> 0.8'
12
+ end
13
+
14
+ group :test do
15
+ gem 'json'
16
+ gem 'codeclimate-test-reporter', require: nil
17
+ end
data/LICENSE.txt ADDED
@@ -0,0 +1,20 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2014 Trail of Bits
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
6
+ this software and associated documentation files (the "Software"), to deal in
7
+ the Software without restriction, including without limitation the rights to
8
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9
+ the Software, and to permit persons to whom the Software is furnished to do so,
10
+ subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17
+ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
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.
data/README.md ADDED
@@ -0,0 +1,98 @@
1
+ # dkim-query
2
+
3
+ [![Code Climate](https://codeclimate.com/github/trailofbits/dkim-query/badges/gpa.svg)](https://codeclimate.com/github/trailofbits/dkim-query)
4
+ [![Test Coverage](https://codeclimate.com/github/trailofbits/dkim-query/badges/coverage.svg)](https://codeclimate.com/github/trailofbits/dkim-query)
5
+ [![Build Status](https://travis-ci.org/trailofbits/dkim-query.svg)](https://travis-ci.org/trailofbits/dkim-query)
6
+
7
+ The `dkim-query` library searches the [DKIM] records for a host. We assume the
8
+ host uses standard dkim 'selectors', and also check if they use their own
9
+ 'selector'.
10
+
11
+ ## Examples
12
+
13
+ Parse a DKIM record:
14
+
15
+ require 'dkim/query'
16
+
17
+ key = DKIM::Query::Key.parse("k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDrEee0Ri4Juz+QfiWYui/E9UGSXau/2P8LjnTD8V4Unn+2FAZVGE3kL23bzeoULYv4PeleB3gfmJiDJOKU3Ns5L4KJAUUHjFwDebt0NP+sBK0VKeTATL2Yr/S3bT/xhy+1xtj4RkdV7fVxTn56Lb4udUnwuxK4V5b5PdOKj/+XcwIDAQAB; n=A 1024 bit key")
18
+
19
+ key.v
20
+ # => nil
21
+
22
+ key.g
23
+ # => nil
24
+
25
+ key.h
26
+ # => nil
27
+
28
+ key.k
29
+ # => :rsa
30
+
31
+ key.n
32
+ # => "A 1024 bit key"@230
33
+
34
+ key.p
35
+ # => "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDrEee0Ri4Juz+QfiWYui/E9UGSXau/2P8LjnTD8V4Unn+2FAZVGE3kL23bzeoULYv4PeleB3gfmJiDJOKU3Ns5L4KJAUUHjFwDebt0NP+sBK0VKeTATL2Yr/S3bT/xhy+1xtj4RkdV7fVxTn56Lb4udUnwuxK4V5b5PdOKj/+XcwIDAQAB"@10
36
+
37
+ key.s
38
+ # => nil
39
+
40
+ key.t
41
+ # => nil
42
+
43
+ Query all keys for a domain:
44
+
45
+ DKIM::Query::Domain.query('yahoo.com')
46
+ # => #<DKIM::Query::Domain:0x0000000315c950 @name="yahoo.com", @keys={"s1024"=>#<DKIM::Query::Key:0x0000000315c9f0 @v=nil, @g=nil, @h=nil, @k=:rsa, @n="A 1024 bit key;"@230, @p="MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDrEee0Ri4Juz+QfiWYui/E9UGSXau/2P8LjnTD8V4Unn+2FAZVGE3kL23bzeoULYv4PeleB3gfmJiDJOKU3Ns5L4KJAUUHjFwDebt0NP+sBK0VKeTATL2Yr/S3bT/xhy+1xtj4RkdV7fVxTn56Lb4udUnwuxK4V5b5PdOKj/+XcwIDAQAB"@10, @s=nil, @t=nil>}>
47
+
48
+ ## Synopsis
49
+
50
+ Query a domain:
51
+
52
+ dkim-query google.com
53
+ ____________________________
54
+ DKIM record search for google.com
55
+ - using selectors: ["default", "dkim", "google"]
56
+ - no DKIM record found for google.com
57
+ ____________________________
58
+
59
+
60
+ Query multiple domains:
61
+
62
+ dkim-query trailofbits.com facebook.com yahoo.com
63
+ ____________________________
64
+ DKIM record search for trailofbits.com
65
+ - using selectors: ["default", "dkim", "google", "trailofbits"]
66
+ - found DKIM record for trailofbits.com at trailofbits._domainkey.trailofbits.com:
67
+ v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCwe04g1hSR55ACcRiLAg0MoEiY5BBviJHJHq/d9r6o+F50fa1TrNNulwKXaST+WCEcW6D2KZ+dt9JvgB9ApIEAFCzHRXhawga0GsfDkOllvpXgT95IPcnYrSkM+rJSbaqHh+YI5sV9sKnvzZDVmB7l5gU3yD74aDmjs9wSg8RC5wIDAQAB
68
+ ____________________________
69
+
70
+ ____________________________
71
+ DKIM record search for facebook.com
72
+ - using selectors: ["default", "dkim", "google", "facebook"]
73
+ - found DKIM record for facebook.com at default._domainkey.facebook.com:
74
+ t=y; k=rsa; p=MHwwDQYJKoZIhvcNAQEBBQADawAwaAJhALkZ4wTn2SQ3EW0vVBExi8izmZZnjZH8JIY5Y964jzDORZku43o6ooFq6HLMjBxmcDYOrJFRdcsKDWtI0Be/uLfc/rClXuyEbcENXfadg77HHv35BI85RNy4TKeai3hxoQIDAQAB;
75
+ ____________________________
76
+
77
+ ____________________________
78
+ DKIM record search for yahoo.com
79
+ - using selectors: ["default", "dkim", "google", "yahoo"]
80
+ - no DKIM record found for yahoo.com
81
+ ____________________________
82
+
83
+ ## Requirements
84
+
85
+ * [ruby] >= 1.9.1
86
+ * [parslet] ~> 1.6
87
+
88
+ ## Install
89
+
90
+ rake install
91
+
92
+ ## License
93
+
94
+ See the {file:LICENSE.txt} file.
95
+
96
+ [DKIM]: https://tools.ietf.org/html/rfc6376
97
+ [ruby]: https://www.ruby-lang.org/
98
+ [parslet]: http://kschiess.github.io/parslet/
data/Rakefile ADDED
@@ -0,0 +1,23 @@
1
+ # encoding: utf-8
2
+ require 'rubygems'
3
+
4
+ begin
5
+ require 'bundler/setup'
6
+ rescue LoadError => e
7
+ warn e.message
8
+ warn "Run `gem install bundler` to install Bundler."
9
+ exit -1
10
+ end
11
+
12
+ require 'rake'
13
+ require 'bundler/gem_tasks'
14
+
15
+ require 'rspec/core/rake_task'
16
+ RSpec::Core::RakeTask.new
17
+
18
+ task :test => :spec
19
+ task :default => :spec
20
+
21
+ require 'yard'
22
+ YARD::Rake::YardocTask.new
23
+ task :doc => :yard
data/bin/dkim-query ADDED
@@ -0,0 +1,34 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ lib_dir = File.expand_path('../../lib',__FILE__)
4
+ $LOAD_PATH.unshift(lib_dir) unless $LOAD_PATH.include?(lib_dir)
5
+
6
+ require 'dkim-query'
7
+
8
+ unless ARGV[0]
9
+ warn "Please supply at least one host name"
10
+ exit
11
+ end
12
+
13
+ ARGV.each do |arg|
14
+ puts "____________________________\n"
15
+ puts "DKIM record search for #{arg}"
16
+
17
+ domain = DKIM::Query::Domain.query(arg)
18
+
19
+ unless domain.keys.empty?
20
+ puts "- found DKIM record for #{arg}"
21
+
22
+ domain.keys.each do |selector,key|
23
+ puts " #{selector}:"
24
+
25
+ [:v, :g, :h, :k, :n, :p, :s, :t].each do |field|
26
+ value = key.send(field)
27
+ puts " #{field}: #{value}" if value
28
+ end
29
+ end
30
+ else
31
+ puts "- no DKIM record found for #{arg}"
32
+ end
33
+ puts "____________________________\n\n"
34
+ end
@@ -0,0 +1,26 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'dkim/query/version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = "dkim-query"
8
+ gem.version = DKIM::Query::VERSION
9
+ gem.authors = ["nicktitle"]
10
+ gem.email = ["nick.esposito@trailofbits.com"]
11
+ gem.summary = %q{DKIM Retriever and Parser}
12
+ gem.description = %q{Search and retrieve DKIM records for any number of hosts}
13
+ gem.homepage = "https://github.com/trailofbits/dkim-query#readme"
14
+ gem.license = "MIT"
15
+
16
+ gem.files = `git ls-files -z`.split("\x0")
17
+ gem.executables = ['dkim-query']
18
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
19
+ gem.require_paths = ["lib"]
20
+ gem.required_ruby_version = '>= 1.9.1'
21
+
22
+ gem.add_dependency "parslet", "~> 1.6"
23
+
24
+ gem.add_development_dependency "bundler", "~> 1.6"
25
+ gem.add_development_dependency "rake", "~> 10.0"
26
+ end
@@ -0,0 +1,138 @@
1
+ require 'dkim/query/query'
2
+ require 'dkim/query/key'
3
+
4
+ require 'resolv'
5
+
6
+ module DKIM
7
+ module Query
8
+ class Domain
9
+
10
+ include Enumerable
11
+
12
+ # Name of the domain
13
+ #
14
+ # @return [String]
15
+ attr_reader :name
16
+
17
+ # DKIM Keys of the domain
18
+ #
19
+ # @return [Hash{String => Key}]
20
+ attr_reader :keys
21
+
22
+ #
23
+ # Initializes the domain.
24
+ #
25
+ # @param [String] name
26
+ # The domain name.
27
+ #
28
+ # @param [Hash{String => Key}] keys
29
+ # The DKIM Keys of the domain.
30
+ #
31
+ # @api public
32
+ #
33
+ def initialize(name,keys={})
34
+ @name = name
35
+ @keys = keys
36
+ end
37
+
38
+ #
39
+ # Parses the DKIM Keys.
40
+ #
41
+ # @param [String] domain
42
+ # The domain the keys belong to.
43
+ #
44
+ # @param [Hash{String => String}] keys
45
+ # The DKIM selectors and keys.
46
+ #
47
+ # @return [Domain]
48
+ # The domain and it's parsed DKIM keys.
49
+ #
50
+ # @api semipublic
51
+ #
52
+ def self.parse(domain,keys={})
53
+ keys = Hash[keys.map { |selector,record|
54
+ [selector, Key.parse(record)]
55
+ }]
56
+
57
+ return new(domain,keys)
58
+ end
59
+
60
+ #
61
+ # Parses the DKIM Keys.
62
+ #
63
+ # @param [String] domain
64
+ # The domain the keys belong to.
65
+ #
66
+ # @param [Hash{String => String}] keys
67
+ # The DKIM selectors and keys.
68
+ #
69
+ # @return [Domain]
70
+ # The domain and it's parsed DKIM keys.
71
+ #
72
+ # @raise [Parslet::ParseFailed]
73
+ # One of the keys was invalid.
74
+ #
75
+ # @api semipublic
76
+ #
77
+ def self.parse!(domain,keys={})
78
+ keys = Hash[keys.map { |selector,record|
79
+ [selector, Key.parse!(record)]
80
+ }]
81
+
82
+ return new(domain,keys)
83
+ end
84
+
85
+ #
86
+ # Queries the domain for all DKIM selectors.
87
+ #
88
+ # @param [String] domain
89
+ # The domain to query.
90
+ #
91
+ # @option options [Array<String>] :selectors
92
+ # sub-domain selectors.
93
+ #
94
+ # @option options [Resolv::DNS] :resolver
95
+ #
96
+ # @return [Domain]
97
+ # The domain and it's DKIM Keys.
98
+ #
99
+ # @api public
100
+ #
101
+ def self.query(domain,options={})
102
+ parse(domain,Query.query(domain,options))
103
+ end
104
+
105
+ #
106
+ # Enumerates over each individual key.
107
+ #
108
+ # @yield [key]
109
+ # The given block will be passed each key.
110
+ #
111
+ # @yieldparam [DKIM::Query::Key] key
112
+ # A key belonging to the domain.
113
+ #
114
+ # @return [Enumerator]
115
+ # If no block was given, an Enumerator will be returned.
116
+ #
117
+ # @api public
118
+ #
119
+ def each(&block)
120
+ @keys.each_value(&block)
121
+ end
122
+
123
+ #
124
+ # Selects a key from the domain.
125
+ #
126
+ # @param [String] selector
127
+ # The selector.
128
+ #
129
+ # @return [Key, nil]
130
+ # The key within that selector.
131
+ #
132
+ def [](selector)
133
+ @keys[selector]
134
+ end
135
+
136
+ end
137
+ end
138
+ end
@@ -0,0 +1,8 @@
1
+ require 'parslet'
2
+
3
+ module DKIM
4
+ module Query
5
+ class InvalidKey < Parslet::ParseFailed
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,135 @@
1
+ require 'dkim/query/exceptions'
2
+ require 'dkim/query/parser'
3
+ require 'dkim/query/malformed_key'
4
+
5
+ module DKIM
6
+ module Query
7
+ class Key
8
+
9
+ attr_reader :v
10
+ alias version v
11
+
12
+ attr_reader :g
13
+ alias granularity g
14
+
15
+ attr_reader :h
16
+ alias hash h
17
+
18
+ attr_reader :k
19
+ alias key k
20
+
21
+ attr_reader :n
22
+ alias notes n
23
+
24
+ attr_reader :p
25
+ alias public_key p
26
+
27
+ attr_reader :s
28
+ alias service_type s
29
+
30
+ attr_reader :t
31
+ alias flags t
32
+
33
+ #
34
+ # Initialize the key.
35
+ #
36
+ # @param [Hash{Symbol => Symbol,String}] tags
37
+ # Tags for the key.
38
+ #
39
+ # @option tags [Symbol] :v
40
+ #
41
+ # @option tags [Symbol] :g
42
+ #
43
+ # @option tags [Symbol] :h
44
+ #
45
+ # @option tags [Symbol] :k
46
+ #
47
+ # @option tags [Symbol] :n
48
+ #
49
+ # @option tags [Symbol] :p
50
+ #
51
+ # @option tags [Symbol] :s
52
+ #
53
+ # @option tags [Symbol] :t
54
+ #
55
+ def initialize(tags={})
56
+ @v, @g, @h, @k, @n, @p, @s, @t = tags.values_at(:v,:g,:h,:k,:n,:p,:s,:t)
57
+ end
58
+
59
+ #
60
+ # Parses a DKIM Key record.
61
+ #
62
+ # @param [String] record
63
+ # The DKIM key record.
64
+ #
65
+ # @return [Key]
66
+ # The new key.
67
+ #
68
+ # @raise [InvalidKey]
69
+ # Could not parse the DKIM Key record.
70
+ #
71
+ def self.parse!(record)
72
+ new(Parser.parse(record))
73
+ rescue Parslet::ParseFailed => error
74
+ raise(InvalidKey.new(error.message,error.cause))
75
+ end
76
+
77
+ #
78
+ # Parses a DKIM Key record.
79
+ #
80
+ # @param [String] record
81
+ # The DKIM key record.
82
+ #
83
+ # @return [Key, MalformedKey]
84
+ # The parsed key. If the key could not be parsed, a {MalformedKey}
85
+ # will be returned.
86
+ #
87
+ def self.parse(record)
88
+ begin
89
+ parse!(record)
90
+ rescue Parslet::ParseFailed => error
91
+ MalformedKey.new(record,error.cause)
92
+ end
93
+ end
94
+
95
+ #
96
+ # Converts the key to a Hash.
97
+ #
98
+ # @return [Hash{:v,:g,:h,:k,:n,:p,:s,:t => Object}]
99
+ #
100
+ def to_hash
101
+ {
102
+ v: @v,
103
+ g: @g,
104
+ h: @h,
105
+ k: @k,
106
+ n: @n,
107
+ p: @p,
108
+ s: @s,
109
+ t: @t
110
+ }
111
+ end
112
+
113
+ #
114
+ # Converts the key back into a DKIM String.
115
+ #
116
+ # @return [String]
117
+ #
118
+ def to_s
119
+ tags = []
120
+
121
+ tags << "v=#{@v}" if @v
122
+ tags << "g=#{@g}" if @g
123
+ tags << "h=#{@h}" if @h
124
+ tags << "k=#{@k}" if @k
125
+ tags << "p=#{@p}" if @p
126
+ tags << "s=#{@s}" if @s
127
+ tags << "t=#{@t}" if @t
128
+ tags << "n=#{@n}" if @n
129
+
130
+ return tags.join('; ')
131
+ end
132
+
133
+ end
134
+ end
135
+ end
@@ -0,0 +1,33 @@
1
+ module DKIM
2
+ module Query
3
+ class MalformedKey
4
+
5
+ # Raw value of the DKIM key.
6
+ #
7
+ # @return [String]
8
+ attr_reader :value
9
+
10
+ # Cause of the parser failure.
11
+ #
12
+ # @return [Parslet::Cause]
13
+ attr_reader :cause
14
+
15
+ #
16
+ # Initializes the malformed key.
17
+ #
18
+ # @param [String] value
19
+ # The raw DKIM key.
20
+ #
21
+ # @param [Parslet::Cause] cause
22
+ # The cause of the parser failure.
23
+ #
24
+ def initialize(value,cause)
25
+ @value = value
26
+ @cause = cause
27
+ end
28
+
29
+ alias value to_s
30
+
31
+ end
32
+ end
33
+ end