valid_email2 2.3.1 → 3.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,5 +1,5 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
- gem 'activemodel', '~> 3.2.22'
3
+ gem 'activemodel', '~> 3.2.22.5'
4
4
 
5
5
  gemspec path: '../'
@@ -1,5 +1,5 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
- gem 'activemodel', '~> 4.2.9'
3
+ gem 'activemodel', '~> 4.2.10'
4
4
 
5
5
  gemspec path: '../'
@@ -1,5 +1,5 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
- gem 'activemodel', '~> 5.1.2'
3
+ gem 'activemodel', '~> 5.2.1'
4
4
 
5
5
  gemspec path: '../'
data/lib/valid_email2.rb CHANGED
@@ -1,17 +1,30 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "valid_email2/email_validator"
2
4
 
3
5
  module ValidEmail2
6
+ BLACKLIST_FILE = "config/blacklisted_email_domains.yml"
7
+ WHITELIST_FILE = "config/whitelisted_email_domains.yml"
8
+
4
9
  def self.disposable_emails
5
- @@disposable_emails ||= YAML.load_file(File.expand_path("../../vendor/disposable_emails.yml",__FILE__))
10
+ @disposable_emails ||= YAML.load_file(
11
+ File.expand_path('../config/disposable_email_domains.yml', __dir__)
12
+ )
6
13
  end
7
14
 
8
15
  def self.blacklist
9
- blacklist_file = "vendor/blacklist.yml"
10
- @@blacklist ||= File.exists?(blacklist_file) ? YAML.load_file(File.expand_path(blacklist_file)) : []
16
+ @blacklist ||= if File.exist?(BLACKLIST_FILE)
17
+ YAML.load_file(File.expand_path(BLACKLIST_FILE))
18
+ else
19
+ []
20
+ end
11
21
  end
12
22
 
13
23
  def self.whitelist
14
- whitelist_file = "vendor/whitelist.yml"
15
- @@whitelist ||= File.exists?(whitelist_file) ? YAML.load_file(File.expand_path(whitelist_file)) : []
24
+ @whitelist ||= if File.exist?(WHITELIST_FILE)
25
+ YAML.load_file(File.expand_path(WHITELIST_FILE))
26
+ else
27
+ []
28
+ end
16
29
  end
17
30
  end
@@ -45,7 +45,11 @@ module ValidEmail2
45
45
  end
46
46
 
47
47
  def disposable?
48
- valid? && domain_is_in?(ValidEmail2.disposable_emails)
48
+ valid? &&
49
+ (
50
+ domain_is_in?(ValidEmail2.disposable_emails) ||
51
+ mx_server_is_in?(ValidEmail2.disposable_emails)
52
+ )
49
53
  end
50
54
 
51
55
  def whitelisted?
@@ -59,10 +63,7 @@ module ValidEmail2
59
63
  def valid_mx?
60
64
  return false unless valid?
61
65
 
62
- Resolv::DNS.open do |dns|
63
- return dns.getresources(address.domain, Resolv::DNS::Resource::IN::MX).size > 0 ||
64
- dns.getresources(address.domain, Resolv::DNS::Resource::IN::A).size > 0
65
- end
66
+ mx_servers.any?
66
67
  end
67
68
 
68
69
  private
@@ -74,10 +75,29 @@ module ValidEmail2
74
75
  }
75
76
  end
76
77
 
77
- def address_contain_emoticons? email_str
78
- return false if email_str.nil?
78
+ def mx_server_is_in?(domain_list)
79
+ mx_servers.any? { |mx_server|
80
+ return false unless mx_server.respond_to?(:exchange)
81
+ mx_server = mx_server.exchange.to_s
82
+
83
+ domain_list.any? { |domain|
84
+ mx_server.end_with?(domain) && mx_server =~ /\A(?:.+\.)*?#{domain}\z/
85
+ }
86
+ }
87
+ end
88
+
89
+ def address_contain_emoticons?(email)
90
+ return false if email.nil?
91
+
92
+ email.each_char.any? { |char| char.bytesize > 1 }
93
+ end
79
94
 
80
- email_str.each_char.any? { |char| char.bytesize > 1 }
95
+ def mx_servers
96
+ @mx_servers ||= Resolv::DNS.open do |dns|
97
+ mx_servers = dns.getresources(address.domain, Resolv::DNS::Resource::IN::MX)
98
+ (mx_servers.any? && mx_servers) ||
99
+ dns.getresources(address.domain, Resolv::DNS::Resource::IN::A)
100
+ end
81
101
  end
82
102
  end
83
103
  end
@@ -1,3 +1,3 @@
1
1
  module ValidEmail2
2
- VERSION = "2.3.1"
2
+ VERSION = "3.0.0"
3
3
  end
@@ -10,7 +10,7 @@ whitelisted_emails = %w(
10
10
  hush.ai hush.com hushmail.me naver.com qq.com example.com
11
11
  )
12
12
 
13
- existing_emails = YAML.load_file("vendor/disposable_emails.yml")
13
+ existing_emails = YAML.load_file("config/disposable_email_domains.yml")
14
14
 
15
15
  url = "https://raw.githubusercontent.com/FGRibreau/mailchecker/master/list.json"
16
16
  resp = Net::HTTP.get_response(URI.parse(url))
@@ -19,4 +19,4 @@ remote_emails = JSON.parse(resp.body).flatten - whitelisted_emails
19
19
 
20
20
  result_emails = (existing_emails + remote_emails).map(&:strip).uniq.sort
21
21
 
22
- File.open("vendor/disposable_emails.yml", "w") {|f| f.write result_emails.to_yaml }
22
+ File.open("config/disposable_email_domains.yml", "w") {|f| f.write result_emails.to_yaml }
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "spec_helper"
2
4
 
3
5
  class TestUser < TestModel
@@ -5,7 +7,7 @@ class TestUser < TestModel
5
7
  end
6
8
 
7
9
  class TestUserSubaddressing < TestModel
8
- validates :email, 'valid_email_2/email': {disallow_subaddressing: true}
10
+ validates :email, 'valid_email_2/email': { disallow_subaddressing: true }
9
11
  end
10
12
 
11
13
  class TestUserMX < TestModel
@@ -24,99 +26,127 @@ class TestUserDisallowBlacklisted < TestModel
24
26
  validates :email, 'valid_email_2/email': { blacklist: true }
25
27
  end
26
28
 
29
+ class TestUserMessage < TestModel
30
+ validates :email, 'valid_email_2/email': { message: "custom message" }
31
+ end
32
+
27
33
  describe ValidEmail2 do
28
34
  describe "basic validation" do
29
35
  subject(:user) { TestUser.new(email: "") }
30
36
 
31
- it "should not be valid email is valid" do
37
+ it "is valid" do
32
38
  user = TestUser.new(email: "foo@bar123.com")
33
39
  expect(user.valid?).to be_truthy
34
40
  end
35
41
 
36
- it "should be valid when email is empty" do
42
+ it "is invalid if email is empty" do
37
43
  expect(user.valid?).to be_truthy
38
44
  end
39
45
 
40
- it "should not be valid when domain is missing" do
46
+ it "is invalid if domain is missing" do
41
47
  user = TestUser.new(email: "foo@.com")
42
48
  expect(user.valid?).to be_falsey
43
49
  end
44
50
 
45
- it "should be invalid when domain includes invalid characters" do
46
- %w(+ _ !).each do |invalid_character|
51
+ it "is invalid if email contains invalid characters" do
52
+ %w[+ _ !].each do |invalid_character|
47
53
  user = TestUser.new(email: "foo@google#{invalid_character}yahoo.com")
48
54
  expect(user.valid?).to be_falsey
49
55
  end
50
56
  end
51
57
 
52
- it "should be invalid when email is malformed" do
58
+ it "is invalid if address is malformed" do
53
59
  user = TestUser.new(email: "foo@bar")
54
60
  expect(user.valid?).to be_falsey
55
61
  end
56
62
 
57
- it "should be invalid if Mail::AddressListsParser raises exception" do
63
+ it "is invalid if Mail::AddressListsParser raises exception" do
58
64
  user = TestUser.new(email: "foo@gmail.com")
59
65
  expect(Mail::Address).to receive(:new).and_raise(Mail::Field::ParseError.new(nil, nil, nil))
60
66
  expect(user.valid?).to be_falsey
61
67
  end
62
68
 
63
- it "shouldn't be valid if the domain constains consecutives dots" do
69
+ it "is invalid if the domain contains consecutive dots" do
64
70
  user = TestUser.new(email: "foo@bar..com")
65
71
  expect(user.valid?).to be_falsey
66
72
  end
73
+
74
+ it "is invalid if the domain contains emoticons" do
75
+ user = TestUser.new(email: "foo🙈@gmail.com")
76
+ expect(user.valid?).to be_falsy
77
+ end
67
78
  end
68
79
 
69
- describe "disposable emails" do
70
- it "should be valid when the domain is not in the list of disposable email providers" do
80
+ describe "with disposable validation" do
81
+ it "is valid if it's not a disposable email" do
71
82
  user = TestUserDisallowDisposable.new(email: "foo@gmail.com")
72
83
  expect(user.valid?).to be_truthy
73
84
  end
74
85
 
75
- it "should be invalid when domain is in the list of disposable email providers" do
86
+ it "is invalid if it's a disposable email" do
76
87
  user = TestUserDisallowDisposable.new(email: "foo@#{ValidEmail2.disposable_emails.first}")
77
88
  expect(user.valid?).to be_falsey
78
89
  end
79
90
 
80
- it "should be invalid when domain is a subdomain of a disposable domain" do
91
+ it "is invalid if the domain is a subdomain of a disposable domain" do
81
92
  user = TestUserDisallowDisposable.new(email: "foo@bar.#{ValidEmail2.disposable_emails.first}")
82
93
  expect(user.valid?).to be_falsey
83
94
  end
84
95
 
85
- it "should allow example.com that is common in lists of disposable email providers" do
96
+ it "allows example.com" do
86
97
  user = TestUserDisallowDisposable.new(email: "foo@example.com")
87
98
  expect(user.valid?).to be_truthy
88
99
  end
89
100
 
101
+ context "with domain that is not disposable but it's mx server is disposable" do
102
+ let(:domain) { "sogetthis.com" }
103
+
104
+ around do |example|
105
+ ValidEmail2.disposable_emails.delete(domain)
106
+ example.run
107
+ ValidEmail2.disposable_emails << domain
108
+ end
109
+
110
+ it "is invalid" do
111
+ user = TestUserDisallowDisposable.new(email: "foo@sogetthis.com")
112
+ expect(user.valid?).to be_falsey
113
+ end
114
+ end
115
+
90
116
  describe "with whitelisted emails" do
91
- it "should be invalid when the domain is in the list of disposable and there is no whitelist" do
92
- user = TestUserDisallowDisposableWithWhitelist.new(email: "foo@#{ValidEmail2.disposable_emails.first}")
117
+ let(:whitelist_domain) { ValidEmail2.disposable_emails.first }
118
+ let(:whitelist_file_path) { "config/whitelisted_email_domains.yml" }
119
+
120
+ after do
121
+ FileUtils.rm(whitelist_file_path, force: true)
122
+ end
123
+
124
+ it "is invalid if the domain is disposable and not in the whitelist" do
125
+ user = TestUserDisallowDisposableWithWhitelist.new(email: "foo@#{whitelist_domain}")
93
126
  expect(user.valid?).to be_falsey
94
127
  end
95
128
 
96
- it "should be valid when the domain is in the list of disposable but it is in the whitelist" do
97
- whitelist_domain = ValidEmail2.disposable_emails.first
98
- whitelist_file_path = "vendor/whitelist.yml"
99
- File.open(whitelist_file_path, "w") {|f| f.write whitelist_domain.to_yaml }
129
+ it "is valid if the domain is disposable but in the whitelist" do
130
+ File.open(whitelist_file_path, "w") { |f| f.write [whitelist_domain].to_yaml }
100
131
  user = TestUserDisallowDisposableWithWhitelist.new(email: "foo@#{whitelist_domain}")
101
132
  expect(user.valid?).to be_falsey
102
- File.delete(whitelist_file_path)
103
133
  end
104
134
  end
105
135
  end
106
136
 
107
- describe "blacklisted emails" do
108
- it "should be valid when email is not in the blacklist" do
137
+ describe "with blacklist validation" do
138
+ it "is valid if the domain is not blacklisted" do
109
139
  user = TestUserDisallowBlacklisted.new(email: "foo@gmail.com")
110
140
  expect(user.valid?).to be_truthy
111
141
  end
112
142
 
113
- it "should be invalid when email is in the blacklist" do
143
+ it "is invalid if the domain is blacklisted" do
114
144
  user = TestUserDisallowBlacklisted.new(email: "foo@#{ValidEmail2.blacklist.first}")
115
145
  expect(user.valid?).to be_falsey
116
146
  end
117
147
  end
118
148
 
119
- describe "mx lookup" do
149
+ describe "with mx validation" do
120
150
  it "should be valid if mx records are found" do
121
151
  user = TestUserMX.new(email: "foo@gmail.com")
122
152
  expect(user.valid?).to be_truthy
@@ -133,58 +163,35 @@ describe ValidEmail2 do
133
163
  end
134
164
  end
135
165
 
136
- describe "emoticons emails" do
137
- it "should be invalid if email contains emoticon" do
138
- email = ValidEmail2::Address.new("foo🙈@gmail.com")
139
- expect(email.valid?).to be_falsy
166
+ describe "with subaddress validation" do
167
+ it "is valid when address does not contain subaddress" do
168
+ user = TestUserSubaddressing.new(email: "foo@gmail.com")
169
+ expect(user.valid?).to be_truthy
140
170
  end
141
- end
142
171
 
143
- describe "subaddressed emails" do
144
-
145
- describe "::Address::DEFAULT_RECIPIENT_DELIMITER" do
146
- it "should be recipient delimiter ('+')" do
147
- expect(ValidEmail2::Address::DEFAULT_RECIPIENT_DELIMITER).to eq('+')
148
- end
172
+ it "is invalid when address cotains subaddress" do
173
+ user = TestUserSubaddressing.new(email: "foo+1@gmail.com")
174
+ expect(user.valid?).to be_falsey
149
175
  end
176
+ end
150
177
 
151
- describe "::Address#subaddressed?" do
152
- it "should be true when address local part contains a recipient delimiter ('+')" do
153
- email = ValidEmail2::Address.new("foo+1@gmail.com")
154
- expect(email.subaddressed?).to be_truthy
155
- end
156
-
157
- it "should be false when address local part contains a recipient delimiter ('+')" do
158
- email = ValidEmail2::Address.new("foo@gmail.com")
159
- expect(email.subaddressed?).to be_falsey
160
- end
178
+ describe "with custom error message" do
179
+ it "supports settings a custom error message" do
180
+ user = TestUserMessage.new(email: "fakeemail")
181
+ user.valid?
182
+ expect(user.errors.full_messages).to include("Email custom message")
161
183
  end
184
+ end
162
185
 
163
- describe "user validation" do
164
- context "subaddressing is allowed (default)" do
165
- it "should be valid when address local part does not contain a recipient delimiter ('+')" do
166
- user = TestUser.new(email: "foo@gmail.com")
167
- expect(user.valid?).to be_truthy
168
- end
169
-
170
- it "should be valid when address local part contains a recipient delimiter ('+')" do
171
- user = TestUser.new(email: "foo+1@gmail.com")
172
- expect(user.valid?).to be_truthy
173
- end
174
- end
175
-
176
- context "subaddressing is forbidden" do
177
- it "should be valid when address local part does not contain a recipient delimiter ('+')" do
178
- user = TestUserSubaddressing.new(email: "foo@gmail.com")
179
- expect(user.valid?).to be_truthy
180
- end
181
-
182
- it "should be invalid when address local part contains a recipient delimiter ('+')" do
183
- user = TestUserSubaddressing.new(email: "foo+1@gmail.com")
184
- expect(user.valid?).to be_falsey
185
- end
186
- end
186
+ describe "#subaddressed?" do
187
+ it "should be true when address local part contains a recipient delimiter ('+')" do
188
+ email = ValidEmail2::Address.new("foo+1@gmail.com")
189
+ expect(email.subaddressed?).to be_truthy
187
190
  end
188
191
 
192
+ it "should be false when address local part contains a recipient delimiter ('+')" do
193
+ email = ValidEmail2::Address.new("foo@gmail.com")
194
+ expect(email.subaddressed?).to be_falsey
195
+ end
189
196
  end
190
197
  end
data/valid_email2.gemspec CHANGED
@@ -20,7 +20,7 @@ Gem::Specification.new do |spec|
20
20
 
21
21
  spec.required_ruby_version = ">= 1.9.3"
22
22
 
23
- spec.add_development_dependency "bundler", "~> 1.3"
23
+ spec.add_development_dependency "bundler", "~> 2.0"
24
24
  spec.add_development_dependency "rake", "~> 11.3.0"
25
25
  spec.add_development_dependency "rspec", "~> 3.5.0"
26
26
  spec.add_runtime_dependency "mail", "~> 2.5"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: valid_email2
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.3.1
4
+ version: 3.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Micke Lisinge
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-10-16 00:00:00.000000000 Z
11
+ date: 2019-02-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '1.3'
19
+ version: '2.0'
20
20
  type: :development
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '1.3'
26
+ version: '2.0'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: rake
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -95,6 +95,8 @@ files:
95
95
  - LICENSE.txt
96
96
  - README.md
97
97
  - Rakefile
98
+ - config/blacklisted_email_domains.yml
99
+ - config/disposable_email_domains.yml
98
100
  - gemfiles/activemodel3.gemfile
99
101
  - gemfiles/activemodel4.gemfile
100
102
  - gemfiles/activemodel5.gemfile
@@ -106,8 +108,6 @@ files:
106
108
  - spec/spec_helper.rb
107
109
  - spec/valid_email2_spec.rb
108
110
  - valid_email2.gemspec
109
- - vendor/blacklist.yml
110
- - vendor/disposable_emails.yml
111
111
  homepage: https://github.com/micke/valid_email2
112
112
  licenses:
113
113
  - MIT
data/vendor/blacklist.yml DELETED
@@ -1 +0,0 @@
1
- - blacklisted-test.com