spf_lookup 0.1.2a

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
+ SHA256:
3
+ metadata.gz: 73fb8d746701c15855dfaed242f391e384ce96071157335c76b9bb73ce7e01f0
4
+ data.tar.gz: 17af222e4787d6c07f0778485912a86138b5671cc81597e697e56dd3a7b3cc3d
5
+ SHA512:
6
+ metadata.gz: c4fda7cf88816bb58a9ce8a474c705f98902f6885f588c2b3a576ce45ffec69ca20d05aea0bcacc59b63b6a689fdc41a4dfd22bc18ad3536420d1bb24aceda65
7
+ data.tar.gz: fbe13fccbda702dc559ca355b3fc7ecf0ef58323cc2ebbea180c51f29ba7d85f7d729b7f70c9fd5c49ea7c50b9ebbd202a26f14e20a0b864403f2f666b310139
data/.gitignore ADDED
@@ -0,0 +1,14 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+ /vendor/
10
+ Gemfile.lock
11
+ # rspec failure tracking
12
+ .rspec_status
13
+
14
+ *.swp
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
data/.travis.yml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ sudo: false
3
+ language: ruby
4
+ cache: bundler
5
+ rvm:
6
+ - 2.4.1
7
+ before_install: gem install bundler -v 2.0.1
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "https://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in spf_lookup.gemspec
4
+ gemspec
data/README.md ADDED
@@ -0,0 +1,89 @@
1
+ # SpfLookup
2
+
3
+ SpfLookup will count the number of SPF lookups for a given domain.
4
+
5
+ ## Overview
6
+
7
+ RFC specify a limit of 10 DNS lookups for SPF. https://datatracker.ietf.org/doc/html/rfc7208#section-4.6.4
8
+
9
+ Therefore, when configuring SPF, you need to check the number of SPF lookups for target domain and make sure that the number of lookups after configuration is within the upper limit set by the RFC.
10
+
11
+ SpfLookup will count the nubmer of SPF lookups by passing the domain,
12
+ so you can reduce the work of counting the number of SPF lookups.
13
+
14
+
15
+
16
+ ## Installation
17
+
18
+ Add this line to your application's Gemfile:
19
+
20
+ ```ruby
21
+ gem 'spf_lookup'
22
+ ```
23
+
24
+ And then execute:
25
+
26
+ $ bundle
27
+
28
+ Or install it yourself as:
29
+
30
+ $ gem install spf_lookup
31
+
32
+ ## Example
33
+
34
+ ```ruby
35
+ require "spf_lookup"
36
+
37
+ domain = "sample.example.com"
38
+
39
+ resolv_conf = {
40
+ nameserver: ['8.8.8.8']
41
+ }
42
+
43
+ # SpfLookup.dns_configure argumets is the same as the one passed to the initializer of Resolv::DNS
44
+ SpfLookup.dns_configure(resolv_conf)
45
+
46
+
47
+ # Retrive spf record set.
48
+ record_set = SpfLookup.retrieve_record_set(domain)
49
+ record_set_hash = record_set.to_hash
50
+
51
+ ## record set information
52
+ puts record_set_hash[:lookup_term_count]
53
+ puts record_set_hash[:domain]
54
+ puts record_set_hash[:record_value]
55
+ puts record_set_hash[:includes]
56
+
57
+ puts record_set_hash[:includes].first[:lookup_term_count]
58
+ puts record_set_hash[:includes].first[:domain]
59
+ puts record_set_hash[:includes].first[:record_value]
60
+ puts record_set_hash[:includes].first[:includes]
61
+
62
+ # Lookup count check.
63
+ ## If you want to use "retrieve_record_set" method, use this.
64
+ lookup_count = record_set.lookup_count
65
+ ## If you DON'T want to use "retrieve_record_set" method, use this.
66
+ lookup_count = SpfLookup.lookup_count(domain)
67
+
68
+ if lookup_count > SpfLookup::LOOKUP_LIMIT_SPECIFIED_BY_RFC7208
69
+ puts "Invalid SPF lookup count!"
70
+ end
71
+
72
+ ```
73
+
74
+ ## Development
75
+
76
+ After checking out the repo, run `bin/setup` to install dependencies. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
77
+
78
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
79
+
80
+ ## Contributing
81
+
82
+ Bug reports and pull requests are welcome on GitHub at https://github.com/shirot7335/spf_lookup. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
83
+
84
+ ## WIP
85
+ * test
86
+
87
+ ## License
88
+
89
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "spf_lookup"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,10 @@
1
+ module SpfLookup
2
+ class Error < StandardError
3
+ end
4
+
5
+ class SpfRecordNotFound < Error
6
+ end
7
+
8
+ class MultipleSpfRecordError < Error
9
+ end
10
+ end
@@ -0,0 +1,62 @@
1
+ require 'coppertone'
2
+ require_relative './txt_record_fetcher'
3
+ require_relative './spf_record'
4
+ require_relative './error'
5
+
6
+ module SpfLookup
7
+ class Lookup
8
+
9
+ class << self
10
+ def run(domain)
11
+ return dns_lookup(domain)
12
+ end
13
+
14
+ private
15
+
16
+ def dns_lookup(domain)
17
+ spf_record = find_spf_record(domain)
18
+
19
+ includes = lookup_target_domains(spf_record).map {|_domain|
20
+ dns_lookup(_domain)
21
+ }
22
+
23
+ return SpfRecord.new(
24
+ domain,
25
+ spf_record&.to_s,
26
+ includes,
27
+ spf_record&.dns_lookup_term_count
28
+ )
29
+ end
30
+
31
+ def lookup_target_domains(spf_record)
32
+ return [] if spf_record.blank?
33
+
34
+ domain_fetcher = -> (obj) { obj.domain_spec.macro_text }
35
+
36
+ domains = spf_record.includes.each_with_object([]) { |include_value, memo|
37
+ memo << domain_fetcher.(include_value.mechanism)
38
+ }
39
+ domains << domain_fetcher.(spf_record.redirect) unless spf_record.redirect.nil?
40
+
41
+ return domains.compact
42
+ end
43
+
44
+ def find_spf_record(domain)
45
+ spf_record = record_fetcher.txt_record_values(domain).each_with_object([]) {|txt_record_value, memo|
46
+ memo << Coppertone::Record.new(txt_record_value) if Coppertone::Record.record?(txt_record_value)
47
+ }
48
+
49
+ if spf_record.length > 1
50
+ raise SpfLookup::MultipleSpfRecordError.new("There must be only one SPF record in the same domain.")
51
+ end
52
+
53
+ return spf_record.first
54
+ end
55
+
56
+ def record_fetcher
57
+ @fetcher ||= TXTRecordFetcher.new(SpfLookup::DNS_CONFIG[:option])
58
+ end
59
+ end
60
+ end
61
+
62
+ end
@@ -0,0 +1,51 @@
1
+ require "json"
2
+
3
+ module SpfLookup
4
+ class SpfRecord
5
+ attr_accessor :domain, :record_value, :includes
6
+ attr_accessor :lookup_term_count
7
+
8
+ def initialize(domain, record_value, includes, lookup_term_count)
9
+ @domain = domain || ""
10
+ @record_value = record_value || ""
11
+ @includes = includes || []
12
+ @lookup_term_count = lookup_term_count || 0
13
+ end
14
+
15
+ def lookup_count
16
+ return count_dns_lookup_0
17
+ end
18
+
19
+ def to_hash
20
+ return {
21
+ domain: @domain,
22
+ record_value: @record_value,
23
+ includes: includes_to_hash,
24
+ lookup_term_count: @lookup_term_count
25
+ }
26
+ end
27
+
28
+ def to_json
29
+ return self.to_hash.to_json
30
+ end
31
+
32
+ private
33
+
34
+ def count_dns_lookup_0
35
+ return count_dns_lookup(self, 0)
36
+ end
37
+
38
+ def count_dns_lookup(result, count)
39
+ _count = result.includes.inject(count) {|memo, r|
40
+ memo = count_dns_lookup(r, memo)
41
+ }
42
+
43
+ return _count + result.lookup_term_count
44
+ end
45
+
46
+ def includes_to_hash
47
+ return includes.map {|result| result.to_hash }
48
+ end
49
+ end
50
+
51
+ end
@@ -0,0 +1,33 @@
1
+ require 'resolv'
2
+
3
+
4
+ module SpfLookup
5
+ class TXTRecordFetcher
6
+
7
+ SUPPORTED_TYPE_CLASS = %w[TXT].freeze
8
+
9
+ def initialize(dns_conf = nil)
10
+ @resolver = Resolv::DNS.new(dns_conf)
11
+ end
12
+
13
+ def txt_record_values(domain)
14
+ return txt_record_resources(domain).collect { |resource| resource.data }
15
+ end
16
+
17
+ def txt_record_resources(domain)
18
+ return record_resources(domain, 'TXT')
19
+ end
20
+
21
+ def record_resources(domain, record_type)
22
+ resources = @resolver.getresources(domain, type_class(record_type))
23
+ return resources
24
+ end
25
+
26
+ private
27
+ def type_class(record_type)
28
+ raise ArgumentError unless SUPPORTED_TYPE_CLASS.include?(record_type.upcase)
29
+ Resolv::DNS::Resource::IN.const_get(record_type.upcase)
30
+ end
31
+
32
+ end
33
+ end
@@ -0,0 +1,3 @@
1
+ module SpfLookup
2
+ VERSION = "0.1.2a"
3
+ end
data/lib/spf_lookup.rb ADDED
@@ -0,0 +1,28 @@
1
+ require "spf_lookup/version"
2
+
3
+ require_relative './spf_lookup/lookup'
4
+
5
+ module SpfLookup
6
+
7
+ # 'options' could set nil or Resolv::DNS.new argument.
8
+ # ex.
9
+ # {nameserver: '8.8.8.8'}
10
+ DNS_CONFIG = {option: nil}
11
+ LOOKUP_LIMIT_SPECIFIED_BY_RFC7208 = 10
12
+
13
+ class << self
14
+ def retrieve_record_set(domain)
15
+ return SpfLookup::Lookup.run(domain)
16
+ end
17
+
18
+ def lookup_count(domain)
19
+ return SpfLookup::Lookup.run(domain).lookup_count
20
+ end
21
+
22
+ def dns_configure(dns_config = nil)
23
+ DNS_CONFIG[:option] = dns_config
24
+ end
25
+ end
26
+
27
+ end
28
+
@@ -0,0 +1,46 @@
1
+
2
+ lib = File.expand_path("../lib", __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require "spf_lookup/version"
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "spf_lookup"
8
+ spec.version = SpfLookup::VERSION
9
+ spec.authors = ["Ryouichi Suganuma"]
10
+ spec.email = ["shirot.white4624@gmail.com"]
11
+
12
+ spec.summary = %q{lookup counter for SPF registration.}
13
+ spec.description = %q{SpfLookup will count the number of SPF lookups for a given domain.}
14
+ spec.homepage = "https://github.com/shirot7335/spf_lookup"
15
+ spec.license = "Confidential"
16
+
17
+ # Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
18
+ # to allow pushing to a single host or delete this section to allow pushing to any host.
19
+ #if spec.respond_to?(:metadata)
20
+ # spec.metadata["allowed_push_host"] = "TODO: Set to 'http://mygemserver.com'"
21
+
22
+ # spec.metadata["homepage_uri"] = spec.homepage
23
+ # spec.metadata["source_code_uri"] = "TODO: Put your gem's public repo URL here."
24
+ # spec.metadata["changelog_uri"] = "TODO: Put your gem's CHANGELOG.md URL here."
25
+ #else
26
+ # raise "RubyGems 2.0 or newer is required to protect against " \
27
+ # "public gem pushes."
28
+ #end
29
+
30
+ # Specify which files should be added to the gem when it is released.
31
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
32
+ spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
33
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
34
+ end
35
+ spec.bindir = "exe"
36
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
37
+ spec.require_paths = ["lib"]
38
+
39
+ spec.add_dependency "domain_name", "~> 0.5"
40
+ spec.add_dependency "coppertone", "~> 0.0.10"
41
+
42
+ spec.add_development_dependency "bundler", "~> 2.0"
43
+ spec.add_development_dependency "rake", "~> 10.0"
44
+ spec.add_development_dependency "rspec", "~> 3.0"
45
+ spec.add_development_dependency "pry", "~> 0.12.2"
46
+ end
metadata ADDED
@@ -0,0 +1,142 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: spf_lookup
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.2a
5
+ platform: ruby
6
+ authors:
7
+ - Ryouichi Suganuma
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2021-10-13 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: domain_name
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '0.5'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '0.5'
27
+ - !ruby/object:Gem::Dependency
28
+ name: coppertone
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: 0.0.10
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: 0.0.10
41
+ - !ruby/object:Gem::Dependency
42
+ name: bundler
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '2.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '2.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '10.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '10.0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rspec
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '3.0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '3.0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: pry
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: 0.12.2
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: 0.12.2
97
+ description: SpfLookup will count the number of SPF lookups for a given domain.
98
+ email:
99
+ - shirot.white4624@gmail.com
100
+ executables: []
101
+ extensions: []
102
+ extra_rdoc_files: []
103
+ files:
104
+ - ".gitignore"
105
+ - ".rspec"
106
+ - ".travis.yml"
107
+ - Gemfile
108
+ - README.md
109
+ - Rakefile
110
+ - bin/console
111
+ - bin/setup
112
+ - lib/spf_lookup.rb
113
+ - lib/spf_lookup/error.rb
114
+ - lib/spf_lookup/lookup.rb
115
+ - lib/spf_lookup/spf_record.rb
116
+ - lib/spf_lookup/txt_record_fetcher.rb
117
+ - lib/spf_lookup/version.rb
118
+ - spf_lookup.gemspec
119
+ homepage: https://github.com/shirot7335/spf_lookup
120
+ licenses:
121
+ - Confidential
122
+ metadata: {}
123
+ post_install_message:
124
+ rdoc_options: []
125
+ require_paths:
126
+ - lib
127
+ required_ruby_version: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ required_rubygems_version: !ruby/object:Gem::Requirement
133
+ requirements:
134
+ - - ">"
135
+ - !ruby/object:Gem::Version
136
+ version: 1.3.1
137
+ requirements: []
138
+ rubygems_version: 3.0.3
139
+ signing_key:
140
+ specification_version: 4
141
+ summary: lookup counter for SPF registration.
142
+ test_files: []