mailshield 1.6 → 1.7

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 951a883218a7b24ca485ad6e34755a420a754931ebb5590438e5ae3715ba385a
4
- data.tar.gz: 74522e2cc5992814083ebb6235a849ff0429f9482bcdec848911526511a386cf
3
+ metadata.gz: 18604539d1e37e6bb2be57844fc3f4655db6aad98fd6f8d8509264b55ab9cf8a
4
+ data.tar.gz: 55fc76651d319aa7f5c7289270dcfb13d7fbacfa0c1ca9ca5d8fdf19c268f14d
5
5
  SHA512:
6
- metadata.gz: fbc024e630f232ff8bb84fff735076c0f8b9c698a12874dc622b4fda4885b4daf7574a830a8acd109d2b3e57fc9265b877516556de71b936b9e3c22f32d01a7e
7
- data.tar.gz: 87b6a352c1e0307983ffae13f9675e97712d7c786ce39a84a4e09c0a9c6d3764a1c756fdd18ca4aabdb8fd08c11667d5dcdf8e8beaf0fd08322dc657bd13ff77
6
+ metadata.gz: 3b2ab77713d4d23a5836419b01df0c804bcc66291f5efb259dc437e9584fc7ee6ef933401701332e4105877e56da3beea02b51c7b1f06ccc49f958cac6ba9cc2
7
+ data.tar.gz: 53771549f5c3c334906acbeea35df4277581431a8fbe83636ace180ab25e7ae4bb0e80ebcbab87a28cd45c813665a29b731017966ad160ab4ec89ee18c83b287
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Mailshield
4
- VERSION = '1.6'
4
+ VERSION = '1.7'
5
5
  end
data/lib/mailshield.rb CHANGED
@@ -8,8 +8,10 @@ require 'csv'
8
8
  require 'net/smtp'
9
9
 
10
10
  module MailShield
11
+ # Regex pattern for validating email formats
11
12
  EMAIL_REGEX = /\A[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}\z/.freeze
12
13
 
14
+ # Custom error classes for various validation failures
13
15
  class ValidationError < StandardError; end
14
16
  class InvalidFormatError < ValidationError; end
15
17
  class DomainNotFoundError < ValidationError; end
@@ -17,57 +19,94 @@ module MailShield
17
19
  class DMARCError < ValidationError; end
18
20
  class SMTPError < ValidationError; end
19
21
  class TemporaryDomainError < ValidationError; end
22
+
20
23
  class << self
21
24
  attr_accessor :dns_cache, :smtp_cache, :whitelist, :blacklist
22
25
 
26
+ # Configuration method for initializing and yielding settings
23
27
  def configure
24
- @whitelist ||= []
25
- @blacklist ||= []
26
- yield self
28
+ initialize_lists
29
+ yield self if block_given?
27
30
  end
28
31
 
32
+ # Validate the structure and existence of the provided email
29
33
  def validate_email(email)
30
34
  reset_caches
31
-
32
35
  domain = extract_domain(email)
33
36
 
34
- return { valid: false, reason: 'Email domain is blacklisted.' } if blacklist.include?(domain)
37
+ return { valid: false, reason: 'Email domain is blacklisted.' } if blacklist && blacklist.include?(domain)
35
38
 
36
- if !whitelist.empty? && !whitelist.include?(domain)
39
+ if whitelist && !whitelist.empty? && !whitelist.include?(domain)
37
40
  return { valid: false, reason: 'Email domain is not whitelisted.' }
38
41
  end
39
42
 
40
- begin
41
- validate_known_disposal_domain?(domain)
42
- validate_format!(email)
43
- validate_domain!(domain)
44
- validate_spf!(domain)
45
- validate_dmarc!(domain)
46
- validate_smtp!(email)
47
- rescue ValidationError => e
48
- return { valid: false, reason: e.message }
49
- end
50
-
51
- { valid: true }
43
+ # Perform comprehensive validation checks
44
+ perform_validations(email, domain)
52
45
  end
53
46
 
54
- # Added Support for verifying email existance in real world
55
47
  def email_exists?(email)
56
48
  smtp_verify_email(email)
57
49
  end
58
50
 
59
- # Added Support for Email Format Validation
60
51
  def valid_format?(email)
61
52
  valid_email_format?(email)
62
53
  end
63
54
 
64
55
  private
65
56
 
57
+ # Initialize lists for whitelisting and blacklisting
58
+ def initialize_lists
59
+ @whitelist ||= []
60
+ @blacklist ||= []
61
+ end
62
+
66
63
  def reset_caches
67
64
  @dns_cache = {}
68
65
  @smtp_cache = {}
69
66
  end
70
67
 
68
+ def blacklisted?(domain)
69
+ blacklist.include?(domain)
70
+ end
71
+
72
+ def handle_blacklist(domain)
73
+ {
74
+ valid: false,
75
+ reason: 'Email domain is blacklisted.'
76
+ }
77
+ end
78
+
79
+ def whitelisted?(domain)
80
+ !whitelist.empty? && whitelist.include?(domain)
81
+ end
82
+
83
+ def handle_whitelist(domain)
84
+ {
85
+ valid: false,
86
+ reason: 'Email domain is not whitelisted.'
87
+ }
88
+ end
89
+
90
+ # Perform all necessary validations for the given email
91
+ def perform_validations(email, domain)
92
+ begin
93
+ validate_known_disposal_domain?(domain) # Custom method to check for disposable domains
94
+ validate_format!(email)
95
+ validate_domain!(domain)
96
+ validate_spf!(domain)
97
+ validate_dmarc!(domain)
98
+ validate_smtp!(email)
99
+ rescue ValidationError => e
100
+ return handle_validation_error(e)
101
+ end
102
+
103
+ { valid: true }
104
+ end
105
+
106
+ def handle_validation_error(error)
107
+ { valid: false, reason: error.message }
108
+ end
109
+
71
110
  def validate_format!(email)
72
111
  raise InvalidFormatError, 'The email address format is invalid.' unless valid_email_format?(email)
73
112
  end
@@ -96,6 +135,7 @@ module MailShield
96
135
  EMAIL_REGEX.match?(email)
97
136
  end
98
137
 
138
+ # Fetch MX records for the given domain
99
139
  def fetch_mx_records(domain)
100
140
  Resolv::DNS.open do |dns|
101
141
  dns.getresources(domain, Resolv::DNS::Resource::IN::MX).map(&:exchange).map(&:to_s)
@@ -104,16 +144,19 @@ module MailShield
104
144
  []
105
145
  end
106
146
 
147
+ # Check if SPF records are available for the domain
107
148
  def spf_record?(domain)
108
149
  spf_records = fetch_txt_records(domain)
109
150
  spf_records.any? { |record| record.include?('v=spf1') }
110
151
  end
111
152
 
153
+ # Check if DMARC records are available for the domain
112
154
  def dmarc_record?(domain)
113
155
  dmarc_records = fetch_txt_records("_dmarc.#{domain}")
114
156
  dmarc_records.any? { |record| record.include?('v=DMARC1') }
115
157
  end
116
158
 
159
+ # Fetch TXT records for the domain
117
160
  def fetch_txt_records(domain)
118
161
  Resolv::DNS.open do |dns|
119
162
  records = dns.getresources(domain, Resolv::DNS::Resource::IN::TXT)
@@ -123,6 +166,7 @@ module MailShield
123
166
  []
124
167
  end
125
168
 
169
+ # Verify the email address using SMTP
126
170
  def smtp_verify_email(email)
127
171
  domain = extract_domain(email)
128
172
  smtp_server = get_smtp_server(domain)
@@ -134,13 +178,18 @@ module MailShield
134
178
  smtp.helo('localhost')
135
179
  smtp.mailfrom('test@example.com')
136
180
  response = smtp.rcptto(email)
137
- response.status == '250' || response.status == '250 OK'
181
+ smtp_response_status(response)
138
182
  end
139
183
  rescue Net::SMTPFatalError, Net::SMTPServerBusy, Net::SMTPSyntaxError, Errno::ECONNREFUSED
140
184
  false
141
185
  end
142
186
  end
143
187
 
188
+ def smtp_response_status(response)
189
+ response.status == '250' || response.status == '250 OK'
190
+ end
191
+
192
+ # Retrieve the SMTP server for the specified domain
144
193
  def get_smtp_server(domain)
145
194
  mx_records = fetch_mx_records(domain)
146
195
  mx_records.first
@@ -150,6 +199,7 @@ end
150
199
 
151
200
  module ActiveModel
152
201
  module Validations
202
+ # Validator for secure email verification
153
203
  class SecureEmailValidator < ::MailShield::SecureEmailValidator
154
204
  def initialize(options = {})
155
205
  super
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mailshield
3
3
  version: !ruby/object:Gem::Version
4
- version: '1.6'
4
+ version: '1.7'
5
5
  platform: ruby
6
6
  authors:
7
7
  - jana
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-09-16 00:00:00.000000000 Z
11
+ date: 2024-10-05 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activemodel
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: net-smtp
15
29
  requirement: !ruby/object:Gem::Requirement