truemail 1.7.1 → 2.0.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,10 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'truemail/core'
3
+ require_relative 'truemail/core'
4
4
 
5
5
  module Truemail
6
6
  INCOMPLETE_CONFIG = 'verifier_email is required parameter'
7
7
  NOT_CONFIGURED = 'use Truemail.configure before or pass custom configuration'
8
+ INVALID_TYPE = 'email should be a String'
8
9
 
9
10
  class << self
10
11
  def configuration(&block)
@@ -25,10 +26,12 @@ module Truemail
25
26
  end
26
27
 
27
28
  def validate(email, custom_configuration: nil, **options)
29
+ check_argument_type(email)
28
30
  Truemail::Validator.new(email, configuration: determine_configuration(custom_configuration), **options).run
29
31
  end
30
32
 
31
33
  def valid?(email, **options)
34
+ check_argument_type(email)
32
35
  validate(email, **options).result.valid?
33
36
  end
34
37
 
@@ -38,8 +41,12 @@ module Truemail
38
41
 
39
42
  private
40
43
 
41
- def raise_unless(condition, message)
42
- raise Truemail::ConfigurationError, message unless condition
44
+ def raise_unless(condition, message, error_class = Truemail::ConfigurationError)
45
+ raise error_class, message unless condition
46
+ end
47
+
48
+ def check_argument_type(argument)
49
+ raise_unless(argument.is_a?(String), Truemail::INVALID_TYPE, Truemail::TypeError)
43
50
  end
44
51
 
45
52
  def determine_configuration(custom_configuration)
@@ -3,12 +3,20 @@
3
3
  module Truemail
4
4
  module Audit
5
5
  class Base < Truemail::Worker
6
+ require 'net/http'
7
+ require 'ipaddr'
8
+ require 'resolv'
9
+
6
10
  private
7
11
 
8
12
  def add_warning(message)
9
13
  result.warnings[self.class.name.split('::').last.downcase.to_sym] = message
10
14
  end
11
15
 
16
+ def current_host_ip
17
+ result.current_host_ip
18
+ end
19
+
12
20
  def configuration
13
21
  result.configuration
14
22
  end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Truemail
4
+ module Audit
5
+ class Dns < Truemail::Audit::Base
6
+ VERIFIER_DOMAIN_NOT_REFER = 'A-record of verifier domain not refers to current host ip address'
7
+
8
+ def run
9
+ return if verifier_domain_refer_to_current_host_ip?
10
+ add_warning(Truemail::Audit::Dns::VERIFIER_DOMAIN_NOT_REFER)
11
+ end
12
+
13
+ private
14
+
15
+ def a_record
16
+ Truemail::Wrapper.call(configuration: configuration) do
17
+ Resolv::DNS.new.getaddress(verifier_domain).to_s
18
+ end
19
+ end
20
+
21
+ def verifier_domain_refer_to_current_host_ip?
22
+ a_record.eql?(current_host_ip)
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Truemail
4
+ module Audit
5
+ class Ip < Truemail::Audit::Base
6
+ GET_MY_IP_URL = 'https://api.ipify.org'
7
+ IPIFY_ERROR = 'impossible to detect current host address via third party service'
8
+
9
+ def run
10
+ return add_warning(Truemail::Audit::Ip::IPIFY_ERROR) unless detect_current_host_ip
11
+ Truemail::Audit::Dns.check(result)
12
+ Truemail::Audit::Ptr.check(result)
13
+ end
14
+
15
+ private
16
+
17
+ def detect_ip_via_ipify
18
+ Net::HTTP.get(URI(Truemail::Audit::Ip::GET_MY_IP_URL))
19
+ end
20
+
21
+ def detect_current_host_ip
22
+ result.current_host_ip = Truemail::Wrapper.call(configuration: configuration) do
23
+ detect_ip_via_ipify
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -3,38 +3,19 @@
3
3
  module Truemail
4
4
  module Audit
5
5
  class Ptr < Truemail::Audit::Base
6
- require 'net/http'
7
- require 'ipaddr'
8
- require 'resolv'
9
-
10
- GET_MY_IP_URL = 'https://api.ipify.org'
11
- IPIFY_ERROR = 'impossible to detect current host address via third party service'
12
- PTR_NOT_FOUND = 'ptr record for current host address was not found'
13
- PTR_NOT_REFER = 'ptr record does not reference to current verifier domain'
14
- VERIFIER_DOMAIN_NOT_REFER = 'a record of verifier domain not refers to current host address'
6
+ PTR_NOT_FOUND = 'PTR-record for current host ip address was not found'
7
+ PTR_NOT_REFER = 'PTR-record does not reference to current verifier domain'
15
8
 
16
9
  def run
17
- return if !current_host_address && add_warning(Truemail::Audit::Ptr::IPIFY_ERROR)
18
- return if ptr_records.empty? && add_warning(Truemail::Audit::Ptr::PTR_NOT_FOUND)
19
- return if ptr_not_refer_to_verifier_domain? && add_warning(Truemail::Audit::Ptr::PTR_NOT_REFER)
20
- return if verifier_domain_refer_to_current_host_address?
21
- add_warning(Truemail::Audit::Ptr::VERIFIER_DOMAIN_NOT_REFER)
10
+ return add_warning(Truemail::Audit::Ptr::PTR_NOT_FOUND) if ptr_records.empty?
11
+ return if ptr_refer_to_verifier_domain?
12
+ add_warning(Truemail::Audit::Ptr::PTR_NOT_REFER)
22
13
  end
23
14
 
24
15
  private
25
16
 
26
- def detect_ip_via_ipify
27
- Net::HTTP.get(URI(Truemail::Audit::Ptr::GET_MY_IP_URL))
28
- end
29
-
30
- def current_host_address
31
- @current_host_address ||= Truemail::Wrapper.call(configuration: configuration) do
32
- IPAddr.new(detect_ip_via_ipify)
33
- end
34
- end
35
-
36
17
  def current_host_reverse_lookup
37
- current_host_address.reverse
18
+ IPAddr.new(current_host_ip).reverse
38
19
  end
39
20
 
40
21
  def ptr_records
@@ -45,18 +26,8 @@ module Truemail
45
26
  end || []
46
27
  end
47
28
 
48
- def ptr_not_refer_to_verifier_domain?
49
- !ptr_records.include?(verifier_domain)
50
- end
51
-
52
- def a_record
53
- Truemail::Wrapper.call(configuration: configuration) do
54
- Resolv::DNS.new.getaddress(verifier_domain).to_s
55
- end
56
- end
57
-
58
- def verifier_domain_refer_to_current_host_address?
59
- a_record.eql?(current_host_address.to_s)
29
+ def ptr_refer_to_verifier_domain?
30
+ ptr_records.include?(verifier_domain)
60
31
  end
61
32
  end
62
33
  end
@@ -1,22 +1,24 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Truemail
4
- class Auditor
5
- Result = Struct.new(:warnings, :configuration, keyword_init: true) do
4
+ class Auditor < Truemail::Executor
5
+ Result = Struct.new(:current_host_ip, :warnings, :configuration, keyword_init: true) do
6
6
  def initialize(warnings: {}, **args)
7
7
  super
8
8
  end
9
9
  end
10
10
 
11
- attr_reader :result
12
-
13
11
  def initialize(configuration:)
14
12
  @result = Truemail::Auditor::Result.new(configuration: configuration)
15
13
  end
16
14
 
17
15
  def run
18
- Truemail::Audit::Ptr.check(result)
16
+ Truemail::Audit::Ip.check(result)
19
17
  self
20
18
  end
19
+
20
+ def as_json
21
+ Truemail::Log::Serializer::AuditorJson.call(self)
22
+ end
21
23
  end
22
24
  end
@@ -6,6 +6,7 @@ module Truemail
6
6
  DEFAULT_RESPONSE_TIMEOUT = 2
7
7
  DEFAULT_CONNECTION_ATTEMPTS = 2
8
8
  DEFAULT_VALIDATION_TYPE = :smtp
9
+ DEFAULT_LOGGER_OPTIONS = { tracking_event: :error, stdout: false, log_absolute_path: nil }.freeze
9
10
 
10
11
  attr_reader :email_pattern,
11
12
  :smtp_error_body_pattern,
@@ -71,7 +72,8 @@ module Truemail
71
72
  end
72
73
  end
73
74
 
74
- def logger=(tracking_event: :error, stdout: false, log_absolute_path: nil)
75
+ def logger=(options)
76
+ tracking_event, stdout, log_absolute_path = logger_options(options)
75
77
  valid_event = Truemail::Log::Event::TRACKING_EVENTS.key?(tracking_event)
76
78
  stdout_only = stdout && log_absolute_path.nil?
77
79
  file_only = log_absolute_path.is_a?(String)
@@ -109,7 +111,7 @@ module Truemail
109
111
  end
110
112
 
111
113
  def validate_arguments(argument, method)
112
- constant = Truemail::RegexConstant.const_get("regex_#{method[/\A.+_(.+)\=\z/, 1]}_pattern".upcase)
114
+ constant = Truemail::RegexConstant.const_get("regex_#{method[/\A.+_(.+)=\z/, 1]}_pattern".upcase)
113
115
  raise_unless(argument, method, constant.match?(argument.to_s))
114
116
  end
115
117
 
@@ -140,5 +142,9 @@ module Truemail
140
142
  check_validation_type(validation_type)
141
143
  end
142
144
  end
145
+
146
+ def logger_options(current_options)
147
+ Truemail::Configuration::DEFAULT_LOGGER_OPTIONS.merge(current_options).values
148
+ end
143
149
  end
144
150
  end
@@ -1,15 +1,17 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Truemail
4
- require 'truemail/version'
5
- require 'truemail/configuration'
6
- require 'truemail/worker'
7
- require 'truemail/wrapper'
8
- require 'truemail/auditor'
9
- require 'truemail/validator'
10
- require 'truemail/logger'
4
+ require_relative '../truemail/version'
5
+ require_relative '../truemail/configuration'
6
+ require_relative '../truemail/worker'
7
+ require_relative '../truemail/executor'
8
+ require_relative '../truemail/wrapper'
9
+ require_relative '../truemail/auditor'
10
+ require_relative '../truemail/validator'
11
+ require_relative '../truemail/logger'
11
12
 
12
13
  ConfigurationError = Class.new(StandardError)
14
+ TypeError = Class.new(StandardError)
13
15
 
14
16
  ArgumentError = Class.new(StandardError) do
15
17
  def initialize(arg_value, arg_name)
@@ -29,32 +31,36 @@ module Truemail
29
31
  end
30
32
 
31
33
  module RegexConstant
32
- REGEX_DOMAIN = /[\p{L}0-9]+([\-\.]{1}[\p{L}0-9]+)*\.[\p{L}]{2,63}/i.freeze
33
- REGEX_EMAIL_PATTERN = /(?=\A.{6,255}\z)(\A([\p{L}0-9]+[\w|\-|\.|\+]*)@(#{REGEX_DOMAIN})\z)/.freeze
34
+ REGEX_DOMAIN = /[\p{L}0-9]+([\-.]{1}[\p{L}0-9]+)*\.\p{L}{2,63}/i.freeze
35
+ REGEX_EMAIL_PATTERN = /(?=\A.{6,255}\z)(\A([\p{L}0-9]+[\w|\-|.|+]*)@(#{REGEX_DOMAIN})\z)/.freeze
34
36
  REGEX_DOMAIN_PATTERN = /(?=\A.{4,255}\z)(\A#{REGEX_DOMAIN}\z)/.freeze
35
37
  REGEX_DOMAIN_FROM_EMAIL = /\A.+@(.+)\z/.freeze
36
38
  REGEX_SMTP_ERROR_BODY_PATTERN = /(?=.*550)(?=.*(user|account|customer|mailbox)).*/i.freeze
37
39
  end
38
40
 
39
41
  module Audit
40
- require 'truemail/audit/base'
41
- require 'truemail/audit/ptr'
42
+ require_relative '../truemail/audit/base'
43
+ require_relative '../truemail/audit/ip'
44
+ require_relative '../truemail/audit/dns'
45
+ require_relative '../truemail/audit/ptr'
42
46
  end
43
47
 
44
48
  module Validate
45
- require 'truemail/validate/base'
46
- require 'truemail/validate/domain_list_match'
47
- require 'truemail/validate/regex'
48
- require 'truemail/validate/mx'
49
- require 'truemail/validate/smtp'
50
- require 'truemail/validate/smtp/response'
51
- require 'truemail/validate/smtp/request'
49
+ require_relative '../truemail/validate/base'
50
+ require_relative '../truemail/validate/domain_list_match'
51
+ require_relative '../truemail/validate/regex'
52
+ require_relative '../truemail/validate/mx'
53
+ require_relative '../truemail/validate/smtp'
54
+ require_relative '../truemail/validate/smtp/response'
55
+ require_relative '../truemail/validate/smtp/request'
52
56
  end
53
57
 
54
58
  module Log
55
- require 'truemail/log/event'
56
- require 'truemail/log/serializer/base'
57
- require 'truemail/log/serializer/text'
58
- require 'truemail/log/serializer/json'
59
+ require_relative '../truemail/log/event'
60
+ require_relative '../truemail/log/serializer/base'
61
+ require_relative '../truemail/log/serializer/auditor_json'
62
+ require_relative '../truemail/log/serializer/validator_base'
63
+ require_relative '../truemail/log/serializer/validator_text'
64
+ require_relative '../truemail/log/serializer/validator_json'
59
65
  end
60
66
  end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Truemail
4
+ class Executor
5
+ attr_reader :result
6
+
7
+ def run; end
8
+
9
+ def as_json; end
10
+ end
11
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Truemail
4
+ module Log
5
+ module Serializer
6
+ class AuditorJson < Truemail::Log::Serializer::Base
7
+ def serialize
8
+ result.to_json
9
+ end
10
+
11
+ private
12
+
13
+ def result
14
+ @result ||=
15
+ {
16
+ date: Time.now,
17
+ current_host_ip: executor_result.current_host_ip,
18
+ warnings: warnings(executor_result.warnings),
19
+ configuration: configuration
20
+ }
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -4,47 +4,35 @@ module Truemail
4
4
  module Log
5
5
  module Serializer
6
6
  class Base
7
+ require 'json'
8
+
7
9
  DEFAULT_GEM_VALUE = 'default gem value'
8
10
 
9
- def self.call(validator_instance)
10
- new(validator_instance).serialize
11
+ def self.call(executor_instance)
12
+ new(executor_instance).serialize
11
13
  end
12
14
 
13
- def initialize(validator_instance)
14
- @validation_type = validator_instance.validation_type
15
- @validation_result = validator_instance.result
16
- @validation_configuration = validation_result.configuration
15
+ def initialize(executor_instance)
16
+ @executor_result = executor_instance.result
17
+ @executor_configuration = executor_result.configuration
17
18
  end
18
19
 
19
20
  def serialize; end
20
21
 
21
22
  private
22
23
 
23
- attr_reader :validation_type, :validation_result, :validation_configuration
24
+ attr_reader :executor_result, :executor_configuration
24
25
 
25
- def errors
26
- validation_errors = validation_result.errors
27
- return if validation_errors.empty?
28
- validation_errors
26
+ def errors(executor_result_target)
27
+ return if executor_result_target.empty?
28
+ executor_result_target
29
29
  end
30
30
 
31
- def smtp_debug
32
- validation_smtp_debug = validation_result.smtp_debug
33
- return unless validation_smtp_debug
34
- validation_smtp_debug.map do |smtp_request|
35
- smtp_response = smtp_request.response
36
- {
37
- mail_host: smtp_request.host,
38
- port_opened: smtp_response.port_opened,
39
- connection: smtp_response.connection,
40
- errors: smtp_response.errors
41
- }
42
- end
43
- end
31
+ alias warnings errors
44
32
 
45
33
  %i[validation_type_by_domain whitelisted_domains blacklisted_domains].each do |method|
46
34
  define_method(method) do
47
- value = validation_configuration.public_send(method)
35
+ value = executor_configuration.public_send(method)
48
36
  return if value.empty?
49
37
  value
50
38
  end
@@ -52,7 +40,7 @@ module Truemail
52
40
 
53
41
  %i[email_pattern smtp_error_body_pattern].each do |method|
54
42
  define_method(method) do
55
- value = validation_configuration.public_send(method)
43
+ value = executor_configuration.public_send(method)
56
44
  default_pattern = Truemail::RegexConstant.const_get(
57
45
  (method.eql?(:email_pattern) ? :regex_email_pattern : :regex_smtp_error_body_pattern).upcase
58
46
  )
@@ -64,28 +52,15 @@ module Truemail
64
52
  def configuration
65
53
  {
66
54
  validation_type_by_domain: validation_type_by_domain,
67
- whitelist_validation: validation_configuration.whitelist_validation,
55
+ whitelist_validation: executor_configuration.whitelist_validation,
68
56
  whitelisted_domains: whitelisted_domains,
69
57
  blacklisted_domains: blacklisted_domains,
70
- not_rfc_mx_lookup_flow: validation_configuration.not_rfc_mx_lookup_flow,
71
- smtp_safe_check: validation_configuration.smtp_safe_check,
58
+ not_rfc_mx_lookup_flow: executor_configuration.not_rfc_mx_lookup_flow,
59
+ smtp_safe_check: executor_configuration.smtp_safe_check,
72
60
  email_pattern: email_pattern,
73
61
  smtp_error_body_pattern: smtp_error_body_pattern
74
62
  }
75
63
  end
76
-
77
- def result
78
- @result ||=
79
- {
80
- date: Time.now,
81
- email: validation_result.email,
82
- validation_type: validation_type,
83
- success: validation_result.success,
84
- errors: errors,
85
- smtp_debug: smtp_debug,
86
- configuration: configuration
87
- }
88
- end
89
64
  end
90
65
  end
91
66
  end