mailshield 0.1.1 → 1.2
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.
- checksums.yaml +4 -4
- data/lib/mailshield/disposable_domains.rb +94 -0
- data/lib/mailshield/docs/mailshield.png +0 -0
- data/lib/mailshield/secure_email_validator.rb +18 -0
- data/lib/mailshield/version.rb +1 -1
- data/lib/mailshield.rb +79 -114
- metadata +6 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 47694cab766631dd24097db7e130aeac98bbc12f2ad4aef7a5f065811796ea71
|
4
|
+
data.tar.gz: 52d6019eb905e12d7d4e5d6eee0cae2c36fba7e301a5e897c3350fa26aeb632f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 41ec5aa1ae5db31d9e0e437eac3dc85da10561cecc9c1b57fe793fccda7990f7a707695c4f794c0518ed2fb23c99767daa18a7cca8488e7792b939e5a71d432e
|
7
|
+
data.tar.gz: 887fe66ea4b30711689cea1346c9466d326cb13c927b6e957c6d6d035ef908f0a5739751f27e6af17c4dbdb3d6df9d5bca4bf89087064fbc3d2427f8ce4a717b
|
@@ -0,0 +1,94 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'set'
|
3
|
+
|
4
|
+
module MailShield
|
5
|
+
KNOWN_DISPOSABLE_DOMAINS = Set.new(
|
6
|
+
[
|
7
|
+
'10mail.org', '10minut.com.pl', '10minut.xyz', '10minutemail.nl', '11163.com',
|
8
|
+
'1secmail.com', '1secmail.net', '1secmail.org', '20minutemail.com', '2chmail.net',
|
9
|
+
'30wave.com', '4warding.net', '55hosting.net', '5july.org', '5ymail.com',
|
10
|
+
'672643.net', '6ip.us', '99.com', 'acentri.com', 'afrobacon.com',
|
11
|
+
'ahk.jp', 'aiafhg.com', 'airsi.de', 'akgq701.com', 'aleeas.com',
|
12
|
+
'alienware13.com', 'ama-trans.de', 'amiri.net', 'ano-mail.net', 'anonaddy.com',
|
13
|
+
'anonmails.de', 'apkmd.com', 'armyspy.com', 'asorent.com', 'augmentationtechnology.com',
|
14
|
+
'aver.com', 'averdov.com', 'axsup.net', 'b2cmail.de', 'banit.club',
|
15
|
+
'bearsarefuzzy.com', 'belamail.org', 'bitwhites.top', 'bladesmail.net', 'bobmail.info',
|
16
|
+
'boxformail.in', 'ccmail.uk', 'ceed.se', 'chammy.info', 'cheaphub.net',
|
17
|
+
'choco.la', 'choicemail1.com', 'chong-mail.net', 'cocoro.uk', 'cocovpn.com',
|
18
|
+
'crazymailing.com', 'cream.pink', 'cutradition.com', 'cuvox.de', 'd1yun.com',
|
19
|
+
'd3p.dk', 'dab.ro', 'dandikmail.com', 'datum2.com', 'dayrep.com',
|
20
|
+
'desoz.com', 'devnullmail.com', 'digdig.org', 'digitalsanctuary.com', 'dispo.in',
|
21
|
+
'dispostable.com', 'dndent.com', 'domozmail.com', 'drdrb.com', 'drevo.si',
|
22
|
+
'dropmail.me', 'dukedish.com', 'durandinterstellar.com', 'e4ward.com', 'eay.jp',
|
23
|
+
'ee1.pl', 'efxs.ca', 'einmalmail.de', 'einrot.com', 'eintagsmail.de',
|
24
|
+
'email.com', 'email.it', 'email60.com', 'emailinfive.com', 'emailresort.com',
|
25
|
+
'emailxfer.com', 'emeraldwebmail.com', 'emlhub.com', 'emlpro.com', 'emltmp.com',
|
26
|
+
'envy17.com', 'esemay.com', 'ether123.net', 'ethereum1.top', 'ethersports.org',
|
27
|
+
'evyush.com', 'exdonuts.com', 'express.net.ua', 'eyepaste.com', 'fanclub.pm',
|
28
|
+
'fangoh.com', 'fantasymail.de', 'fastmail.com', 'fatflap.com', 'fightallspam.com',
|
29
|
+
'fiifke.de', 'findu.pl', 'fleckens.hu', 'foobarbot.net', 'fr33mail.info',
|
30
|
+
'freeinbox.email', 'freeml.net', 'fukurou.ch', 'fuwamofu.com', 'fuwari.be',
|
31
|
+
'gafy.net', 'gambling.com', 'gehensiemirnichtaufdensack.de', 'gelitik.in', 'geronra.com',
|
32
|
+
'getmails.eu', 'getover.de', 'givememail.club', 'gmatch.org', 'go2vpn.net',
|
33
|
+
'golemico.com', 'greenhousemail.com', 'guerillamail.biz', 'guerrillamail.com', 'gustr.com',
|
34
|
+
'haltospam.com', 'hamham.uk', 'harakirimail.com', 'haydoo.com', 'headstrong.de',
|
35
|
+
'heisei.be', 'herp.in', 'herpderp.nl', 'hidemyass.com', 'hidzz.com',
|
36
|
+
'hola.org', 'honeys.be', 'honor-8.com', 'hornyalwary.top', 'hostcalls.com',
|
37
|
+
'hotmai.com', 'hotsoup.be', 'ichigo.me', 'icx.ro', 'ieatspam.eu',
|
38
|
+
'ige.es', 'imails.info', 'imstations.com', 'in-ulm.de', 'inboxalias.com',
|
39
|
+
'inkomail.com', 'instaddr.ch', 'interstats.org', 'ip6.li', 'janproz.com',
|
40
|
+
'jobposts.net', 'jourrapide.com', 'kagi.be', 'katztube.com', 'kbox.li',
|
41
|
+
'kkmail.be', 'kksm.be', 'klipschx12.com', 'kmail.li', 'koszmail.pl',
|
42
|
+
'kpay.be', 'kpost.be', 'kulturbetrieb.info', 'labworld.org', 'lee.mx',
|
43
|
+
'lenovog4.com', 'lgxscreen.com', 'lifetotech.com', 'ligsb.com', 'lillemap.net',
|
44
|
+
'locanto1.club', 'locantofuck.top', 'lukop.dk', 'macr2.com', 'macromaid.com',
|
45
|
+
'magim.be', 'mail.darmajaya.ac.id', 'mail.ru', 'mail.tm', 'mail21.cc',
|
46
|
+
'mailcker.com', 'maildrop.cc', 'maildx.com', 'mailfs.com', 'mailguard.me',
|
47
|
+
'mailinater.com', 'mailinator.com', 'mailinator.net', 'mailinator.us', 'mailsac.com',
|
48
|
+
'mailscrap.com', 'mailshell.com', 'mailtechx.com', 'mailtothis.com', 'mama3.org',
|
49
|
+
'manybrain.com', 'mbox.re', 'meantinc.com', 'mepost.pw', 'merry.pink',
|
50
|
+
'metalunits.com', 'midiharmonica.com', 'mirai.re', 'mobilevpn.top', 'mofu.be',
|
51
|
+
'moimoi.re', 'monumentmail.com', 'morsin.com', 'mt2009.com', 'mt2014.com',
|
52
|
+
'mt2015.com', 'mybitti.de', 'mymail-in.net', 'mymailoasis.com', 'mypacks.net',
|
53
|
+
'myspamless.com', 'mystvpn.com', 'mytrashmail.com', 'na-cat.com', 'nada.email',
|
54
|
+
'nagi.be', 'nanonym.ch', 'neko2.net', 'nekochan.fr', 'nervmich.net',
|
55
|
+
'nextstopvalhalla.com', 'nezdiro.org', 'nezumi.be', 'niseko.be', 'nospamfor.us',
|
56
|
+
'notmailinator.com', 'ntlhelp.net', 'nurfuerspam.de', 'nutpa.net', 'nypato.com',
|
57
|
+
'okinawa.li', 'onemail.host', 'onetm.jp', 'online.ms', 'oopi.org',
|
58
|
+
'ovomail.co', 'owleyes.ch', 'oxopoha.com', 'p33.org', 'pancakemail.com',
|
59
|
+
'pavilionx2.com', 'payperex2.com', 'pecinan.net', 'pingir.com', 'placebomail10.com',
|
60
|
+
'plw.me', 'porsh.net', 'pratikmail.com', 'pratikmail.org', 'prin.be',
|
61
|
+
'privy-mail.de', 'pro-tag.org', 'projectcl.com', 'psh.me', 'put2.net',
|
62
|
+
'putthisinyourspamdatabase.com', 'qtum-ico.com', 'quickemail.info', 'quicksend.ch', 'rabin.ca',
|
63
|
+
'rapt.be', 'reallymymail.com', 'recode.me', 'redfeathercrow.com', 'reftoken.net',
|
64
|
+
'rhyta.com', 'rootfest.net', 'royal.net', 'ruru.be', 'safetymail.info',
|
65
|
+
'schrott-email.de', 'sendnow.win', 'sendspamhere.com', 'senseless-entertainment.com', 'sexyalwasmi.top',
|
66
|
+
'shalar.net', 'sharklasers.com', 'shieldedmail.com', 'shieldemail.com', 'shipfromto.com',
|
67
|
+
'shrib.com', 'sika3.com', 'simaenaga.com', 'simplelogin.co', 'sinaite.net',
|
68
|
+
'slaskpost.se', 'sofia.re', 'sogetthis.com', 'spamdecoy.net', 'spamhereplease.com',
|
69
|
+
'spamhole.com', 'stayhome.li', 'storiqax.top', 'storj99.com', 'storj99.top',
|
70
|
+
'stromox.com', 'superrito.com', 'supersave.net', 'suremail.info', 'svk.jp',
|
71
|
+
'tapi.re', 'teleworm.us', 'temp-mail.org', 'tempail.com', 'tempemail.net',
|
72
|
+
'tempmail.dev', 'tempmail2.com', 'tempmailer.com', 'tempmailo.com', 'tensi.org',
|
73
|
+
'testudine.com', 'thankyou2010.com', 'thisisnotmyrealemail.com', 'throwam.com', 'tilien.com',
|
74
|
+
'tmail.ws', 'tokem.co', 'topless-new-world.com', 'topmail.com', 'torba.cc',
|
75
|
+
'trickmail.net', 'trickmail.org', 'trixtrux1.com', 'truckeremail.net', 'tryalert.com',
|
76
|
+
'turual.com', 'twddos.com', 'unmail.ru', 'uploadnolimit.com', 'uw5t6ds54.com',
|
77
|
+
'ventolin.org', 'vintomaper.com', 'vmailcloud.com', 'vubby.com', 'vuiy.pw',
|
78
|
+
'warpmail.net', 'watch-harry-potter.com', 'watchfulli.com', 'wep68.com', 'wh4f.org',
|
79
|
+
'willhackforfood.biz', 'winbroadband.co.uk', 'workshop-liberal.com', 'wronghead.com', 'wwwmail.win',
|
80
|
+
'x24.com', 'xn--9kq967o.com', 'xn--cg7bx4b4x1b.com', 'xsynergy.top', 'xxhamsterxx.com',
|
81
|
+
'yepmail.net', 'yesspam.com', 'yo-site.com', 'yogotemail.com', 'yopmail.fr',
|
82
|
+
'yopmail.gq', 'yopmail.net', 'yopmail.org', 'yourinbox.email', 'yuurok.com',
|
83
|
+
'zainmax.net', 'ze.gy', 'zipmail.com', 'zoemail.net', 'zombie-hive.com',
|
84
|
+
'zsero.com', 'zumrot.com'
|
85
|
+
]
|
86
|
+
)
|
87
|
+
|
88
|
+
|
89
|
+
class << self
|
90
|
+
def disposable_domain?(domain)
|
91
|
+
KNOWN_DISPOSABLE_DOMAINS.include?(domain)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
Binary file
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'active_model'
|
4
|
+
|
5
|
+
module MailShield
|
6
|
+
class SecureEmailValidator < ActiveModel::Validator
|
7
|
+
def validate(record)
|
8
|
+
email = record.email
|
9
|
+
return if email.blank?
|
10
|
+
|
11
|
+
result = MailShield.validate_email(email)
|
12
|
+
|
13
|
+
return if result[:valid]
|
14
|
+
|
15
|
+
record.errors.add(:email, result[:issue])
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
data/lib/mailshield/version.rb
CHANGED
data/lib/mailshield.rb
CHANGED
@@ -1,133 +1,89 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative
|
3
|
+
require_relative 'mailshield/version'
|
4
|
+
require_relative 'mailshield/disposable_domains'
|
4
5
|
require 'resolv'
|
5
6
|
require 'csv'
|
7
|
+
require 'net/smtp'
|
6
8
|
|
7
9
|
module MailShield
|
10
|
+
EMAIL_REGEX = /\A[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}\z/.freeze
|
8
11
|
|
9
|
-
class
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
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
|
12
|
+
class ValidationError < StandardError; end
|
13
|
+
class InvalidFormatError < ValidationError; end
|
14
|
+
class DomainNotFoundError < ValidationError; end
|
15
|
+
class SPFError < ValidationError; end
|
16
|
+
class DMARCError < ValidationError; end
|
17
|
+
class SMTPError < ValidationError; end
|
28
18
|
|
29
19
|
class << self
|
30
|
-
|
31
|
-
|
20
|
+
attr_accessor :dns_cache, :smtp_cache
|
32
21
|
|
33
|
-
|
34
|
-
|
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
|
22
|
+
def validate_email(email, verify_by_send: false)
|
23
|
+
reset_caches
|
46
24
|
|
47
25
|
domain = extract_domain(email)
|
48
26
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
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
|
65
|
-
|
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
|
27
|
+
begin
|
28
|
+
validate_format!(email)
|
29
|
+
validate_domain!(domain)
|
30
|
+
validate_spf!(domain)
|
31
|
+
validate_dmarc!(domain)
|
32
|
+
validate_smtp!(email) if verify_by_send
|
33
|
+
rescue ValidationError => e
|
34
|
+
return { valid: false, issues: [e.message] }
|
70
35
|
end
|
71
36
|
|
72
|
-
|
73
|
-
|
74
|
-
result[:issues] << "The email domain is missing records that help protect against email fraud."
|
75
|
-
return result
|
76
|
-
end
|
37
|
+
{ valid: true }
|
38
|
+
end
|
77
39
|
|
78
|
-
|
40
|
+
def verify_address(email)
|
41
|
+
smtp_verify_email(email)
|
79
42
|
end
|
80
43
|
|
81
|
-
|
82
|
-
email_results = []
|
44
|
+
private
|
83
45
|
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
end
|
46
|
+
def reset_caches
|
47
|
+
@dns_cache = {}
|
48
|
+
@smtp_cache = {}
|
49
|
+
end
|
89
50
|
|
90
|
-
|
51
|
+
def validate_format!(email)
|
52
|
+
raise InvalidFormatError, 'The email address format is invalid.' unless valid_email_format?(email)
|
91
53
|
end
|
92
54
|
|
93
|
-
def
|
94
|
-
|
95
|
-
|
55
|
+
def validate_domain!(domain)
|
56
|
+
raise DomainNotFoundError, 'Email Not Found.' if fetch_mx_records(domain).empty?
|
57
|
+
end
|
96
58
|
|
97
|
-
|
98
|
-
|
99
|
-
|
59
|
+
def validate_spf!(domain)
|
60
|
+
raise SPFError, 'Temporary / Disposable Email' unless spf_record?(domain)
|
61
|
+
end
|
100
62
|
|
101
|
-
|
63
|
+
def validate_dmarc!(domain)
|
64
|
+
raise DMARCError, 'Temporary / Disposable Email' unless dmarc_record?(domain)
|
102
65
|
end
|
103
66
|
|
104
|
-
|
67
|
+
def validate_smtp!(email)
|
68
|
+
raise SMTPError, 'Email Address Not Found' unless smtp_verify_email(email)
|
69
|
+
end
|
105
70
|
|
106
71
|
def extract_domain(email)
|
107
72
|
email.split('@').last.downcase
|
108
73
|
end
|
109
74
|
|
110
75
|
def valid_email_format?(email)
|
111
|
-
|
112
|
-
!!(email =~ email_regex)
|
113
|
-
end
|
114
|
-
|
115
|
-
def known_temp_domain?(domain)
|
116
|
-
TEMP_DOMAINS.include?(domain)
|
76
|
+
EMAIL_REGEX.match?(email)
|
117
77
|
end
|
118
78
|
|
119
79
|
def fetch_mx_records(domain)
|
120
|
-
|
121
|
-
|
122
|
-
|
80
|
+
dns_cache[domain] ||= begin
|
81
|
+
Resolv::DNS.open do |dns|
|
82
|
+
dns.getresources(domain, Resolv::DNS::Resource::IN::MX).map(&:exchange).map(&:to_s)
|
83
|
+
end
|
84
|
+
rescue Resolv::ResolvError
|
85
|
+
[]
|
123
86
|
end
|
124
|
-
rescue Resolv::ResolvError
|
125
|
-
[]
|
126
|
-
end
|
127
|
-
|
128
|
-
def suspicious_mx_records?(mx_records)
|
129
|
-
suspicious_patterns = [/mailinator/, /tempmail/, /guerrillamail/]
|
130
|
-
mx_records.any? { |mx| suspicious_patterns.any? { |pattern| mx.match?(pattern) } }
|
131
87
|
end
|
132
88
|
|
133
89
|
def spf_record?(domain)
|
@@ -141,27 +97,36 @@ module MailShield
|
|
141
97
|
end
|
142
98
|
|
143
99
|
def fetch_txt_records(domain)
|
144
|
-
|
145
|
-
|
146
|
-
|
100
|
+
dns_cache[domain] ||= begin
|
101
|
+
Resolv::DNS.open do |dns|
|
102
|
+
dns.getresources(domain, Resolv::DNS::Resource::IN::TXT).map(&:data)
|
103
|
+
end
|
104
|
+
rescue Resolv::ResolvError
|
105
|
+
[]
|
147
106
|
end
|
148
|
-
rescue Resolv::ResolvError
|
149
|
-
[]
|
150
107
|
end
|
151
|
-
end
|
152
|
-
end
|
153
108
|
|
109
|
+
def smtp_verify_email(email)
|
110
|
+
domain = extract_domain(email)
|
111
|
+
smtp_server = smtp_cache[domain] ||= get_smtp_server(domain)
|
112
|
+
|
113
|
+
return false unless smtp_server
|
114
|
+
|
115
|
+
begin
|
116
|
+
Net::SMTP.start(smtp_server, 25, 'localhost') do |smtp|
|
117
|
+
smtp.helo('localhost')
|
118
|
+
smtp.mailfrom('test@example.com')
|
119
|
+
response = smtp.rcptto(email)
|
120
|
+
response == '250 OK'
|
121
|
+
end
|
122
|
+
rescue Net::SMTPFatalError, Net::SMTPServerBusy, Net::SMTPSyntaxError, Errno::ECONNREFUSED
|
123
|
+
false
|
124
|
+
end
|
125
|
+
end
|
154
126
|
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
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/
|
127
|
+
def get_smtp_server(domain)
|
128
|
+
mx_records = fetch_mx_records(domain)
|
129
|
+
mx_records.first
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mailshield
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: '1.2'
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- jana
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-09-03 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: MailShield helps secure your application by identifying temporary or
|
14
14
|
disposable email domains.
|
@@ -19,6 +19,9 @@ extensions: []
|
|
19
19
|
extra_rdoc_files: []
|
20
20
|
files:
|
21
21
|
- lib/mailshield.rb
|
22
|
+
- lib/mailshield/disposable_domains.rb
|
23
|
+
- lib/mailshield/docs/mailshield.png
|
24
|
+
- lib/mailshield/secure_email_validator.rb
|
22
25
|
- lib/mailshield/version.rb
|
23
26
|
homepage: https://github.com/janarthanan-shanmugam/mailshield
|
24
27
|
licenses:
|
@@ -43,7 +46,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
43
46
|
- !ruby/object:Gem::Version
|
44
47
|
version: '0'
|
45
48
|
requirements: []
|
46
|
-
rubygems_version: 3.5.
|
49
|
+
rubygems_version: 3.5.18
|
47
50
|
signing_key:
|
48
51
|
specification_version: 4
|
49
52
|
summary: A gem to detect temporary or disposable email domains.
|