mailshield 0.1.0 → 0.1.1

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: b14ffd727fa0a54fbce427772f17317f28743bdcd87ec2f204bf89fc25530f3e
4
- data.tar.gz: 6e593d1bac55e212d43d875692a2ae9d6ae10a451409e779f188531849bdac78
3
+ metadata.gz: 75a143d6ea43f54fb93d97111b110549b11af8e4095d8633a0983d29bc24d48a
4
+ data.tar.gz: 7a7f03578febe47f990afc419a87af3b0c2eb3100adf9738c8f8188511bc779d
5
5
  SHA512:
6
- metadata.gz: 7bff616725f5ee9c1ea1d8cf49777ad6a0e83915bf1e48639e771785b84df7e0cd3db9f55aa7093477cee93fdaf93c241c3b475d3c159f1dd31cfb95afbf7ce4
7
- data.tar.gz: acd38d78a78e94edf2df0e8f17b5debe32aca7ce17d2657df69323ff9909fa4c72f2f9d3023c3a937f535a12242525fc9ebf54209159fcacf5790b9ccb5e3fc7
6
+ metadata.gz: dcbab4e23187ea34d25a7f6a8a63083ed006d5456a40ac089b1e1dad4cab5c2dbc3d31833da47b03a6a49357d95cf0a7655805528ea1b9b14fa84748014f991b
7
+ data.tar.gz: 27ce04f2c1422ee26667c891d037c55bffc55aa1865dd66d62449469dbcdd90577c60b8eb4aa8c48dfde299b1445fb3c1f86002de9c034a3074a721db196b853
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Mailshield
4
- VERSION = "0.1.0"
4
+ VERSION = "0.1.1"
5
5
  end
data/lib/mailshield.rb CHANGED
@@ -2,33 +2,121 @@
2
2
 
3
3
  require_relative "mailshield/version"
4
4
  require 'resolv'
5
+ require 'csv'
5
6
 
6
7
  module MailShield
7
- class DomainChecker
8
- TEMP_DOMAINS = %w[mailinator.com tempmail.com guerrillamail.com].freeze # If any one want to contribute, please add the known more domains here.
9
8
 
10
- def self.temporary_email?(email)
9
+ class ValidationResult
10
+ attr_reader :emails
11
+
12
+ def initialize(emails)
13
+ @emails = emails
14
+ end
15
+
16
+ def valid_emails
17
+ emails.select { |email| email[:valid] }.map { |email| email[:email] }
18
+ end
19
+
20
+ def invalid_emails
21
+ emails.reject { |email| email[:valid] }.map { |email| email[:email] }
22
+ end
23
+
24
+ def get_emails
25
+ emails.map { |email| { email: email[:email], valid: email[:valid] } }
26
+ end
27
+ end
28
+
29
+ class << self
30
+ TEMP_DOMAINS = %w[mailinator.com tempmail.com guerrillamail.com].freeze # Known temporary domains
31
+
32
+
33
+ # Main method to validate an email and return results in a hash
34
+ def validate_email(email)
35
+ result = {
36
+ email: email,
37
+ valid: true,
38
+ issues: []
39
+ }
40
+
41
+ unless valid_email_format?(email)
42
+ result[:valid] = false
43
+ result[:issues] << "The email address format is invalid."
44
+ return result
45
+ end
46
+
11
47
  domain = extract_domain(email)
12
- return true if known_temp_domain?(domain)
48
+
49
+ if known_temp_domain?(domain)
50
+ result[:valid] = false
51
+ result[:issues] << "The email domain is known to be temporary or disposable."
52
+ return result
53
+ end
13
54
 
14
55
  mx_records = fetch_mx_records(domain)
15
- return true if suspicious_mx_records?(mx_records)
56
+ if mx_records.empty?
57
+ result[:valid] = false
58
+ result[:issues] << "The email domain does not have valid mail exchange records."
59
+ return result
60
+ elsif suspicious_mx_records?(mx_records)
61
+ result[:valid] = false
62
+ result[:issues] << "The email domain's mail exchange records suggest it might be used for temporary or disposable email services."
63
+ return result
64
+ end
16
65
 
17
- return true unless spf_record?(domain)
18
- return true unless dmarc_record?(domain)
66
+ unless spf_record?(domain)
67
+ result[:valid] = false
68
+ result[:issues] << "The email domain is missing important records that help confirm its authenticity."
69
+ return result
70
+ end
71
+
72
+ unless dmarc_record?(domain)
73
+ result[:valid] = false
74
+ result[:issues] << "The email domain is missing records that help protect against email fraud."
75
+ return result
76
+ end
77
+
78
+ result
79
+ end
80
+
81
+ def validate_emails_from_csv(input_file_path)
82
+ email_results = []
83
+
84
+ CSV.foreach(input_file_path, headers: true) do |row|
85
+ email = row['email']
86
+ validation_result = validate_email_for_csv(email)
87
+ email_results << { email: email, valid: validation_result }
88
+ end
89
+
90
+ ValidationResult.new(email_results)
91
+ end
92
+
93
+ def validate_email_for_csv(email)
94
+ return false unless valid_email_format?(email)
95
+ domain = extract_domain(email)
19
96
 
20
- false
97
+ return false if known_temp_domain?(domain)
98
+ return false unless spf_record?(domain)
99
+ return false unless dmarc_record?(domain)
100
+
101
+ true
21
102
  end
22
103
 
23
- def self.extract_domain(email)
104
+ private
105
+
106
+ def extract_domain(email)
24
107
  email.split('@').last.downcase
25
108
  end
26
109
 
27
- def self.known_temp_domain?(domain)
110
+ def valid_email_format?(email)
111
+ email_regex = /\A[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}\z/
112
+ !!(email =~ email_regex)
113
+ end
114
+
115
+ def known_temp_domain?(domain)
28
116
  TEMP_DOMAINS.include?(domain)
29
117
  end
30
118
 
31
- def self.fetch_mx_records(domain)
119
+ def fetch_mx_records(domain)
32
120
  Resolv::DNS.open do |dns|
33
121
  mx_records = dns.getresources(domain, Resolv::DNS::Resource::IN::MX)
34
122
  mx_records.map(&:exchange).map(&:to_s)
@@ -37,22 +125,22 @@ module MailShield
37
125
  []
38
126
  end
39
127
 
40
- def self.suspicious_mx_records?(mx_records)
128
+ def suspicious_mx_records?(mx_records)
41
129
  suspicious_patterns = [/mailinator/, /tempmail/, /guerrillamail/]
42
130
  mx_records.any? { |mx| suspicious_patterns.any? { |pattern| mx.match?(pattern) } }
43
131
  end
44
132
 
45
- def self.spf_record?(domain)
133
+ def spf_record?(domain)
46
134
  spf_records = fetch_txt_records(domain)
47
135
  spf_records.any? { |record| record.include?('v=spf1') }
48
136
  end
49
137
 
50
- def self.dmarc_record?(domain)
138
+ def dmarc_record?(domain)
51
139
  dmarc_records = fetch_txt_records("_dmarc.#{domain}")
52
140
  dmarc_records.any? { |record| record.include?('v=DMARC1') }
53
141
  end
54
142
 
55
- def self.fetch_txt_records(domain)
143
+ def fetch_txt_records(domain)
56
144
  Resolv::DNS.open do |dns|
57
145
  records = dns.getresources(domain, Resolv::DNS::Resource::IN::TXT)
58
146
  records.map(&:data)
@@ -62,3 +150,18 @@ module MailShield
62
150
  end
63
151
  end
64
152
  end
153
+
154
+
155
+ # SPF Record Explanation:
156
+ #
157
+ # SPF (Sender Policy Framework): A mechanism that helps email servers verify that an email claiming to come from a specific domain is actually sent by an authorized mail server.
158
+ # This prevents spammers from sending messages with forged "From" addresses.
159
+ #
160
+ # DMARC Record Explanation:
161
+ #
162
+ # DMARC (Domain-based Message Authentication, Reporting, and Conformance): A protocol that builds on SPF and DKIM (DomainKeys Identified Mail) to help email domain owners protect their domain from being used in email spoofing.
163
+ # It provides a way for domain owners to publish policies about their email authentication practices and how receiving mail servers should enforce them.
164
+ #
165
+ # References:
166
+ # https://www.dkim.org/
167
+ # https://www.cloudflare.com/en-gb/learning/dns/dns-records/dns-spf-record/
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mailshield
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - jana