email_assessor 0.7.1 → 0.8.1
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/email_assessor/address.rb +14 -2
- data/lib/email_assessor/email_validator.rb +52 -9
- data/lib/email_assessor/version.rb +1 -1
- data/lib/email_assessor.rb +2 -0
- data/spec/email_assessor_spec.rb +33 -0
- data/vendor/disposable_domains.txt +21970 -0
- data/vendor/educational_domains.txt +5298 -0
- data/vendor/fastpass_domains.txt +35 -0
- metadata +5 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8b030fd55305340114adc5f313d216c398b15097ed82d97c1ae19ab29a8bb371
|
4
|
+
data.tar.gz: f28a6570204c3af6fa87ddf9ed4954b6ae2f03e53f30d74ccbdaeb1316424c63
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a6e6cdf6bc76dcd825ab27f721b489b54143d08fb1dc692c9727afa11bbef658fa678135be3bd0803e0e986789aee8a9a74a240ba7b1154c094d876ca154aa07
|
7
|
+
data.tar.gz: 0b8c0b930ba5c0e9a26afb30a6f142336782db311a0ea6ca36476c288f717143c443045a54c3357a711c875ede73995be16c8966d948f4d2fd646278691b4e99
|
@@ -111,11 +111,23 @@ module EmailAssessor
|
|
111
111
|
end
|
112
112
|
|
113
113
|
def disposable?
|
114
|
-
|
114
|
+
domain_in_file?(EmailAssessor::DISPOSABLE_DOMAINS_FILE_NAME)
|
115
115
|
end
|
116
116
|
|
117
117
|
def blacklisted?
|
118
|
-
|
118
|
+
domain_in_file?(EmailAssessor::BLACKLISTED_DOMAINS_FILE_NAME)
|
119
|
+
end
|
120
|
+
|
121
|
+
def educational?
|
122
|
+
domain_in_file?(EmailAssessor::EDUCATIONAL_DOMAINS_FILE_NAME)
|
123
|
+
end
|
124
|
+
|
125
|
+
def fastpass?
|
126
|
+
domain_in_file?(EmailAssessor::FASTPASS_DOMAINS_FILE_NAME)
|
127
|
+
end
|
128
|
+
|
129
|
+
def domain_in_file?(filename)
|
130
|
+
valid? && EmailAssessor.domain_in_file?(address.domain, filename)
|
119
131
|
end
|
120
132
|
|
121
133
|
def valid_mx?
|
@@ -5,31 +5,74 @@ require "active_model/validations"
|
|
5
5
|
|
6
6
|
class EmailValidator < ActiveModel::EachValidator
|
7
7
|
def default_options
|
8
|
-
{ regex: true, disposable: false, mx: false }
|
8
|
+
{ regex: true, disposable: false, mx: false, fastpass: true }
|
9
9
|
end
|
10
10
|
|
11
11
|
def validate_each(record, attribute, value)
|
12
12
|
return unless value.present?
|
13
|
-
|
13
|
+
|
14
|
+
options = default_options.merge!(self.options)
|
14
15
|
|
15
16
|
address = EmailAssessor::Address.new(value)
|
16
17
|
|
17
18
|
error(record, attribute) && return unless address.valid?
|
18
19
|
|
20
|
+
# Skip all domain blocklist checks for fastpass domains.
|
21
|
+
# The goal is to skip needless validation for common "good" domains such as Gmail, Yahoo, and Outlook.
|
22
|
+
# The fastpass domain list is configurable via vendor/fastpass_domains.txt
|
23
|
+
validate_domain(record, attribute, address, options) unless options[:fastpass] && address.fastpass?
|
24
|
+
|
25
|
+
# Exit early if validate_domain found a validation error
|
26
|
+
return if record.errors.key?(attribute)
|
27
|
+
|
28
|
+
if options[:mx]
|
29
|
+
error(record, attribute, error_type(:mx, options)) && return unless address.valid_mx?
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def error(record, attribute, type = options[:message] || :invalid)
|
36
|
+
record.errors.add(attribute, type)
|
37
|
+
end
|
38
|
+
|
39
|
+
def error_type(validator, options)
|
40
|
+
option_value = options[validator]
|
41
|
+
|
42
|
+
if option_value.is_a?(String) || option_value.is_a?(Symbol)
|
43
|
+
return option_value
|
44
|
+
end
|
45
|
+
|
46
|
+
options[:message] || :invalid
|
47
|
+
end
|
48
|
+
|
49
|
+
def validate_domain(record, attribute, address, options)
|
19
50
|
if options[:disposable]
|
20
|
-
error(record, attribute) && return if address.disposable?
|
51
|
+
error(record, attribute, error_type(:disposable, options)) && return if address.disposable?
|
21
52
|
end
|
22
53
|
|
23
54
|
if options[:blacklist]
|
24
|
-
error(record, attribute) && return if address.blacklisted?
|
55
|
+
error(record, attribute, error_type(:blacklist, options)) && return if address.blacklisted?
|
25
56
|
end
|
26
57
|
|
27
|
-
if options[:
|
28
|
-
error(record, attribute) && return
|
58
|
+
if options[:educational]
|
59
|
+
error(record, attribute, error_type(:educational, options)) && return if address.educational?
|
29
60
|
end
|
30
|
-
end
|
31
61
|
|
32
|
-
|
33
|
-
|
62
|
+
# if options[:domain_not_in]
|
63
|
+
# matched_blocklist = options[:domain_not_in].select do |entry|
|
64
|
+
# unless entry.key?(:blocklist)
|
65
|
+
# fail "domain_not_in entries must be in format { blocklist: \"filename\"[, message: symbol|string] }"
|
66
|
+
# end
|
67
|
+
|
68
|
+
# next unless address.domain_in_blocklist?(entry[:blocklist])
|
69
|
+
|
70
|
+
# error(record, attribute, entry[:message])
|
71
|
+
|
72
|
+
# true
|
73
|
+
# end
|
74
|
+
|
75
|
+
# return if matched_blocklist
|
76
|
+
# end
|
34
77
|
end
|
35
78
|
end
|
data/lib/email_assessor.rb
CHANGED
@@ -3,6 +3,8 @@ require "email_assessor/email_validator"
|
|
3
3
|
|
4
4
|
module EmailAssessor
|
5
5
|
DISPOSABLE_DOMAINS_FILE_NAME = File.expand_path("../../vendor/disposable_domains.txt", __FILE__)
|
6
|
+
FASTPASS_DOMAINS_FILE_NAME = File.expand_path("../../vendor/fastpass_domains.txt", __FILE__)
|
7
|
+
EDUCATIONAL_DOMAINS_FILE_NAME = File.expand_path("../../vendor/educational_domains.txt", __FILE__)
|
6
8
|
BLACKLISTED_DOMAINS_FILE_NAME = File.expand_path("vendor/blacklisted_domains.txt")
|
7
9
|
|
8
10
|
def self.domain_is_disposable?(domain)
|
data/spec/email_assessor_spec.rb
CHANGED
@@ -17,10 +17,15 @@ class TestUserDisallowBlacklisted < TestModel
|
|
17
17
|
validates :email, email: { blacklist: true }
|
18
18
|
end
|
19
19
|
|
20
|
+
class TestUserDisallowEducational < TestModel
|
21
|
+
validates :email, email: { educational: :no_educational }
|
22
|
+
end
|
23
|
+
|
20
24
|
describe EmailAssessor do
|
21
25
|
let(:plain_user) { TestUser.new(email: "") }
|
22
26
|
let(:disposable_user) { TestUserDisallowDisposable.new(email: "foo@gmail.com") }
|
23
27
|
let(:blacklist_user) { TestUserDisallowBlacklisted.new(email: "foo@gmail.com") }
|
28
|
+
let(:educational_user) { TestUserDisallowEducational.new(email: "foo@gmail.com") }
|
24
29
|
let(:mx_user) { TestUserMX.new(email: "foo@gmail.com") }
|
25
30
|
|
26
31
|
let(:blacklisted_domains_file_name) { described_class::BLACKLISTED_DOMAINS_FILE_NAME }
|
@@ -29,6 +34,9 @@ describe EmailAssessor do
|
|
29
34
|
let(:disposable_domains_file_name) { described_class::DISPOSABLE_DOMAINS_FILE_NAME }
|
30
35
|
let(:disposable_domain) { File.open(disposable_domains_file_name, &:readline).chomp }
|
31
36
|
|
37
|
+
let(:educational_domains_file_name) { described_class::EDUCATIONAL_DOMAINS_FILE_NAME }
|
38
|
+
let(:educational_domain) { File.open(educational_domains_file_name, &:readline).chomp }
|
39
|
+
|
32
40
|
describe "basic validation" do
|
33
41
|
subject(:user) { plain_user }
|
34
42
|
|
@@ -161,6 +169,31 @@ describe EmailAssessor do
|
|
161
169
|
end
|
162
170
|
end
|
163
171
|
|
172
|
+
describe "educational domains" do
|
173
|
+
subject(:user) { educational_user }
|
174
|
+
|
175
|
+
it "is valid when email domain is not in the educational blocklist" do
|
176
|
+
is_expected.to be_valid
|
177
|
+
end
|
178
|
+
|
179
|
+
it "is invalid when email domain is in the educational blocklist" do
|
180
|
+
user.email = "foo@#{educational_domain}"
|
181
|
+
is_expected.to be_invalid
|
182
|
+
end
|
183
|
+
|
184
|
+
it "is invalid when email is in the educational blocklist regardless of case" do
|
185
|
+
user.email = "foo@#{educational_domain.upcase}"
|
186
|
+
is_expected.to be_invalid
|
187
|
+
end
|
188
|
+
|
189
|
+
it "is invalid when email domain is in the educational blocklist regardless of subdomain" do
|
190
|
+
user.email = "foo@abc123.#{educational_domain}"
|
191
|
+
is_expected.to be_invalid
|
192
|
+
expect(user.errors.added?(:email, :no_educational)).to be_truthy
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
|
164
197
|
describe "mx lookup" do
|
165
198
|
subject(:user) { mx_user }
|
166
199
|
|