dkim-query 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
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