email_address 0.1.2 → 0.2.0

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.
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  ################################################################################
2
4
  # ActiveRecord v5.0 Custom Type
3
5
  #
@@ -27,20 +29,22 @@
27
29
  # user.canonical_email #=> "patsmith@gmail.com"
28
30
  ################################################################################
29
31
 
30
- class EmailAddress::EmailAddressType < ActiveRecord::Type::Value
32
+ module EmailAddress
33
+ class EmailAddressType < ActiveRecord::Type::Value
31
34
 
32
- # From user input, setter
33
- def cast(value)
34
- super(EmailAddress.normal(value))
35
- end
35
+ # From user input, setter
36
+ def cast(value)
37
+ super(Address.new(value).normal)
38
+ end
36
39
 
37
- # From a database value
38
- def deserialize(value)
39
- value && EmailAddress.normal(value)
40
- end
41
- #
42
- # To a database value (string)
43
- def serialize(value)
44
- value && EmailAddress.normal(value)
40
+ # From a database value
41
+ def deserialize(value)
42
+ value && Address.new(value).normal
43
+ end
44
+
45
+ # To a database value (string)
46
+ def serialize(value)
47
+ value && Address.new(value).normal
48
+ end
45
49
  end
46
50
  end
@@ -1,41 +1,44 @@
1
- require 'resolv'
2
- require 'netaddr'
3
- require 'socket'
1
+ # frozen_string_literal: true
2
+
3
+ require "resolv"
4
+ require "socket"
4
5
 
5
6
  module EmailAddress
6
7
  class Exchanger
7
8
  include Enumerable
8
9
 
9
- def self.cached(host)
10
+ def self.cached(host, config = {})
10
11
  @host_cache ||= {}
11
- @cache_size ||= ENV['EMAIL_ADDRESS_CACHE_SIZE'].to_i || 100
12
+ @cache_size ||= ENV["EMAIL_ADDRESS_CACHE_SIZE"].to_i || 100
12
13
  if @host_cache.has_key?(host)
13
14
  o = @host_cache.delete(host)
14
15
  @host_cache[host] = o # LRU cache, move to end
15
16
  elsif @host_cache.size >= @cache_size
16
17
  @host_cache.delete(@host_cache.keys.first)
17
- @host_cache[host] = new(host)
18
+ @host_cache[host] = new(host, config)
18
19
  else
19
- @host_cache[host] = new(host)
20
+ @host_cache[host] = new(host, config)
20
21
  end
21
22
  end
22
23
 
23
- def initialize(host, config={})
24
+ def initialize(host, config = {})
24
25
  @host = host
25
- @config = config
26
+ @config = config.is_a?(Hash) ? Config.new(config) : config
27
+ @dns_disabled = @config[:host_validation] == :syntax || @config[:dns_lookup] == :off
26
28
  end
27
29
 
28
30
  def each(&block)
31
+ return if @dns_disabled
29
32
  mxers.each do |m|
30
- yield({host:m[0], ip:m[1], priority:m[2]})
33
+ yield({host: m[0], ip: m[1], priority: m[2]})
31
34
  end
32
35
  end
33
36
 
34
37
  # Returns the provider name based on the MX-er host names, or nil if not matched
35
38
  def provider
36
39
  return @provider if defined? @provider
37
- EmailAddress::Config.providers.each do |provider, config|
38
- if config[:exchanger_match] && self.matches?(config[:exchanger_match])
40
+ Config.providers.each do |provider, config|
41
+ if config[:exchanger_match] && matches?(config[:exchanger_match])
39
42
  return @provider = provider
40
43
  end
41
44
  end
@@ -44,28 +47,41 @@ module EmailAddress
44
47
 
45
48
  # Returns: [["mta7.am0.yahoodns.net", "66.94.237.139", 1], ["mta5.am0.yahoodns.net", "67.195.168.230", 1], ["mta6.am0.yahoodns.net", "98.139.54.60", 1]]
46
49
  # If not found, returns []
50
+ # Returns a dummy record when dns_lookup is turned off since it may exists, though
51
+ # may not find provider by MX name or IP. I'm not sure about the "0.0.0.0" ip, it should
52
+ # be good in this context, but in "listen" context it means "all bound IP's"
47
53
  def mxers
48
- @mxers ||= Resolv::DNS.open do |dns|
49
- ress = dns.getresources(@host, Resolv::DNS::Resource::IN::MX)
50
- records = ress.map do |r|
51
- begin
52
- [r.exchange.to_s, IPSocket::getaddress(r.exchange.to_s), r.preference]
53
- rescue SocketError # not found, but could also mean network not work or it could mean one record doesn't resolve an address
54
- nil
55
- end
54
+ return [["example.com", "0.0.0.0", 1]] if @dns_disabled
55
+ @mxers ||= Resolv::DNS.open { |dns|
56
+ dns.timeouts = @config[:dns_timeout] if @config[:dns_timeout]
57
+
58
+ ress = begin
59
+ dns.getresources(@host, Resolv::DNS::Resource::IN::MX)
60
+ rescue Resolv::ResolvTimeout
61
+ []
56
62
  end
63
+
64
+ records = ress.map { |r|
65
+ if r.exchange.to_s > " "
66
+ [r.exchange.to_s, IPSocket.getaddress(r.exchange.to_s), r.preference]
67
+ end
68
+ }
57
69
  records.compact
58
- end
70
+ }
71
+ # not found, but could also mean network not work or it could mean one record doesn't resolve an address
72
+ rescue SocketError
73
+ [["example.com", "0.0.0.0", 1]]
59
74
  end
60
75
 
61
76
  # Returns Array of domain names for the MX'ers, used to determine the Provider
62
77
  def domains
63
- @_domains ||= mxers.map {|m| EmailAddress::Host.new(m.first).domain_name }.sort.uniq
78
+ @_domains ||= mxers.map { |m| Host.new(m.first).domain_name }.sort.uniq
64
79
  end
65
80
 
66
81
  # Returns an array of MX IP address (String) for the given email domain
67
82
  def mx_ips
68
- mxers.map {|m| m[1] }
83
+ return ["0.0.0.0"] if @dns_disabled
84
+ mxers.map { |m| m[1] }
69
85
  end
70
86
 
71
87
  # Simple matcher, takes an array of CIDR addresses (ip/bits) and strings.
@@ -78,9 +94,9 @@ module EmailAddress
78
94
  rules = Array(rules)
79
95
  rules.each do |rule|
80
96
  if rule.include?("/")
81
- return rule if self.in_cidr?(rule)
97
+ return rule if in_cidr?(rule)
82
98
  else
83
- self.each {|mx| return rule if mx[:host].end_with?(rule) }
99
+ each { |mx| return rule if mx[:host].end_with?(rule) }
84
100
  end
85
101
  end
86
102
  false
@@ -88,14 +104,9 @@ module EmailAddress
88
104
 
89
105
  # Given a cidr (ip/bits) and ip address, returns true on match. Caches cidr object.
90
106
  def in_cidr?(cidr)
91
- c = NetAddr::CIDR.create(cidr)
92
- if cidr.include?(":")
93
- mx_ips.find { |ip| ip.include?(":") && c.matches?(ip) } ? true : false
94
- elsif cidr.include?(".")
95
- mx_ips.find { |ip| !ip.include?(":") && c.matches?(ip) } ? true : false
96
- else
97
- false
98
- end
107
+ net = IPAddr.new(cidr)
108
+ found = mx_ips.detect { |ip| net.include?(IPAddr.new(ip)) }
109
+ !!found
99
110
  end
100
111
  end
101
112
  end