valid_email2 3.2.4 → 3.4.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6f0eea64eb523ab5e3993b7e8c8abff01c0de45535ec72e81c94177c70442d59
4
- data.tar.gz: 771e67404527aa129be31a94c2eef0738f54b3e653f394964fa215dabe786b21
3
+ metadata.gz: 71c14200d42afbdf47d3222f443c72f81dd23af157f32baebbcc607d2ef09959
4
+ data.tar.gz: 67e841c534a03d363b118bc50026dcc54ee1550478a98d92e885d53c40905ffe
5
5
  SHA512:
6
- metadata.gz: 4d491d4b61f26a9155cee37e78e5a78fd60579418f17bfbe76713b3d9ab7d6a0e371f919c36bddf2843c69392c2cb6e3ed4f32d2b392b7642d5008b02b0ae02a
7
- data.tar.gz: 5ad7f4f013df6a23662c12e70113bdc9f74e98f31b680fad0de7730f17b4bd15b8761b26d1fb2d21f3b58dc89abcf049f225bfc5a05c5edc5ca9b0f50a81bd70
6
+ metadata.gz: 27e0b370d3fc4fa2fb1530e931c9f06156c88045f9b55a4b9e038d521460b34ac4dc8b81f6194ea649477cb4169774cfe3b7a9ad15e06447f472b0742700433e
7
+ data.tar.gz: d160ab3de4196dc830e26aedab650c9839520b9aadccb9e6153305eb42ad796929cab5a209aef3ce869e1a801171b7de45fdc23d3e5ac6004436ad7e31a2a6ef
@@ -1,3 +1,18 @@
1
+ ## Version 3.4.0
2
+ * Disallow consecutive dots https://github.com/micke/valid_email2/pull/163
3
+ * Add andyes.net https://github.com/micke/valid_email2/pull/162
4
+
5
+ ## Version 3.3.1
6
+ * Fix some performance regressions (https://github.com/micke/valid_email2/pull/150)
7
+
8
+ ## Version 3.3.0
9
+ * Allow multiple addresses separated by comma (https://github.com/micke/valid_email2/pull/156)
10
+ * Make prohibited_domain_characters_regex changeable (https://github.com/micke/valid_email2/pull/157)
11
+
12
+ ## Version 3.2.5
13
+ * Remove false positives
14
+ * Pull new domains
15
+
1
16
  ## Version 3.2.4
2
17
  * Remove false positives
3
18
 
data/README.md CHANGED
@@ -83,6 +83,11 @@ To validate create your own custom message:
83
83
  validates :email, 'valid_email_2/email': { message: "is not a valid email" }
84
84
  ```
85
85
 
86
+ To allow multiple addresses separated by comma:
87
+ ```ruby
88
+ validates :email, 'valid_email_2/email': { multiple: true }
89
+ ```
90
+
86
91
  All together:
87
92
  ```ruby
88
93
  validates :email, 'valid_email_2/email': { mx: true, disposable: true, disallow_subaddressing: true}
@@ -3398,6 +3398,7 @@ androidsapps.co
3398
3398
  androidworld.tw
3399
3399
  andthen.us
3400
3400
  andy1mail.host
3401
+ andyes.net
3401
3402
  andynugraha.net
3402
3403
  andyyxc45.biz
3403
3404
  aneaproducciones.com
@@ -7866,6 +7867,7 @@ cungmuachungnhom.com
7866
7867
  cungsuyngam.com
7867
7868
  cungtam.com
7868
7869
  cuoiz.com
7870
+ cuoly.com
7869
7871
  cuongvumarketingseo.com
7870
7872
  cupf6mdhtujxytdcoxh.cf
7871
7873
  cupf6mdhtujxytdcoxh.ga
@@ -9772,7 +9774,6 @@ edu.auction
9772
9774
  edu.dmtc.dev
9773
9775
  edu.hstu.eu.org
9774
9776
  edu.my
9775
- edu.sg
9776
9777
  eduanswer.ru
9777
9778
  education.eu
9778
9779
  educationleaders-ksa.com
@@ -10352,6 +10353,7 @@ eo-z.com
10352
10353
  eoffice.top
10353
10354
  eomail.com
10354
10355
  eonmech.com
10356
+ eoopy.com
10355
10357
  eorbs.com
10356
10358
  eos2mail.com
10357
10359
  eotoplenie.ru
@@ -11401,6 +11403,8 @@ fitnessjockey.org
11401
11403
  fitnessmojo.org
11402
11404
  fitnessreviewsonline.com
11403
11405
  fitnesszbyszko.pl
11406
+ fitschool.be
11407
+ fitschool.space
11404
11408
  fittinggeeks.pl
11405
11409
  fitzgeraldforjudge.com
11406
11410
  five-club.com
@@ -28483,6 +28487,7 @@ tempemailaddress.com
28483
28487
  tempemails.io
28484
28488
  tempinbox.co.uk
28485
28489
  tempinbox.com
28490
+ tempinbox.xyz
28486
28491
  tempm.cf
28487
28492
  tempm.com
28488
28493
  tempm.ga
@@ -33695,4 +33700,4 @@ zzv2bfja5.pl
33695
33700
  zzz.co
33696
33701
  zzz.com
33697
33702
  zzzmail.pl
33698
- zzzzzzzzzzzzz.com
33703
+ zzzzzzzzzzzzz.com
@@ -7,23 +7,35 @@ module ValidEmail2
7
7
  WHITELIST_FILE = "config/whitelisted_email_domains.yml"
8
8
  DISPOSABLE_FILE = File.expand_path('../config/disposable_email_domains.txt', __dir__)
9
9
 
10
- def self.disposable_emails
11
- @disposable_emails ||= File.open(DISPOSABLE_FILE){ |f| f.read }.split("\n")
12
- end
10
+ class << self
11
+ def disposable_emails
12
+ @disposable_emails ||= load_file(DISPOSABLE_FILE)
13
+ end
13
14
 
14
- def self.blacklist
15
- @blacklist ||= if File.exist?(BLACKLIST_FILE)
16
- YAML.load_file(File.expand_path(BLACKLIST_FILE))
17
- else
18
- []
19
- end
20
- end
15
+ def blacklist
16
+ @blacklist ||= load_if_exists(BLACKLIST_FILE)
17
+ end
18
+
19
+ def whitelist
20
+ @whitelist ||= load_if_exists(WHITELIST_FILE)
21
+ end
22
+
23
+ private
24
+
25
+ def load_if_exists(path)
26
+ File.exist?(path) ? load_file(path) : Set.new
27
+ end
21
28
 
22
- def self.whitelist
23
- @whitelist ||= if File.exist?(WHITELIST_FILE)
24
- YAML.load_file(File.expand_path(WHITELIST_FILE))
25
- else
26
- []
27
- end
29
+ def load_file(path)
30
+ # This method MUST return a Set, otherwise the
31
+ # performance will suffer!
32
+ if path.end_with?(".yml")
33
+ Set.new(YAML.load_file(path))
34
+ else
35
+ File.open(path, "r").each_line.each_with_object(Set.new) do |domain, set|
36
+ set << domain.tap(&:chomp!)
37
+ end
38
+ end
39
+ end
28
40
  end
29
41
  end
@@ -10,6 +10,14 @@ module ValidEmail2
10
10
  DEFAULT_RECIPIENT_DELIMITER = '+'.freeze
11
11
  DOT_DELIMITER = '.'.freeze
12
12
 
13
+ def self.prohibited_domain_characters_regex
14
+ @prohibited_domain_characters_regex ||= PROHIBITED_DOMAIN_CHARACTERS_REGEX
15
+ end
16
+
17
+ def self.prohibited_domain_characters_regex=(val)
18
+ @prohibited_domain_characters_regex = val
19
+ end
20
+
13
21
  def initialize(address)
14
22
  @parse_error = false
15
23
  @raw_address = address
@@ -24,25 +32,21 @@ module ValidEmail2
24
32
  end
25
33
 
26
34
  def valid?
27
- @valid ||= begin
28
- return false if @parse_error
35
+ return @valid unless @valid.nil?
36
+ return false if @parse_error
29
37
 
38
+ @valid = begin
30
39
  if address.domain && address.address == @raw_address
31
40
  domain = address.domain
32
41
 
33
- domain !~ PROHIBITED_DOMAIN_CHARACTERS_REGEX &&
34
- # Domain needs to have at least one dot
35
- domain =~ /\./ &&
36
- # Domain may not have two consecutive dots
37
- domain !~ /\.{2,}/ &&
38
- # Domain may not start with a dot
39
- domain !~ /^\./ &&
40
- # Domain may not start with a dash
41
- domain !~ /^-/ &&
42
- # Domain name may not end with a dash
43
- domain !~ /-\./ &&
44
- # Address may not contain a dot directly before @
45
- address.address !~ /\.@/
42
+ domain !~ self.class.prohibited_domain_characters_regex &&
43
+ domain.include?('.') &&
44
+ !domain.include?('..') &&
45
+ !domain.start_with?('.') &&
46
+ !domain.start_with?('-') &&
47
+ !domain.include?('-.') &&
48
+ !address.local.include?('..') &&
49
+ !address.local.end_with?('.')
46
50
  else
47
51
  false
48
52
  end
@@ -62,7 +66,7 @@ module ValidEmail2
62
66
  end
63
67
 
64
68
  def disposable_domain?
65
- valid? && domain_is_in?(ValidEmail2.disposable_emails)
69
+ domain_is_in?(ValidEmail2.disposable_emails)
66
70
  end
67
71
 
68
72
  def disposable_mx_server?
@@ -5,43 +5,44 @@ require "active_model/validations"
5
5
  module ValidEmail2
6
6
  class EmailValidator < ActiveModel::EachValidator
7
7
  def default_options
8
- { regex: true, disposable: false, mx: false, disallow_subaddressing: false }
8
+ { regex: true, disposable: false, mx: false, disallow_subaddressing: false, multiple: false }
9
9
  end
10
10
 
11
11
  def validate_each(record, attribute, value)
12
12
  return unless value.present?
13
13
  options = default_options.merge(self.options)
14
14
 
15
- address = ValidEmail2::Address.new(value)
15
+ value_spitted = options[:multiple] ? value.split(',').map(&:strip) : [value]
16
+ addresses = value_spitted.map { |v| ValidEmail2::Address.new(v) }
16
17
 
17
- error(record, attribute) && return unless address.valid?
18
+ error(record, attribute) && return unless addresses.all?(&:valid?)
18
19
 
19
20
  if options[:disallow_dotted]
20
- error(record, attribute) && return if address.dotted?
21
+ error(record, attribute) && return if addresses.any?(&:dotted?)
21
22
  end
22
23
 
23
24
  if options[:disallow_subaddressing]
24
- error(record, attribute) && return if address.subaddressed?
25
+ error(record, attribute) && return if addresses.any?(&:subaddressed?)
25
26
  end
26
27
 
27
28
  if options[:disposable]
28
- error(record, attribute) && return if address.disposable?
29
+ error(record, attribute) && return if addresses.any?(&:disposable?)
29
30
  end
30
31
 
31
32
  if options[:disposable_domain]
32
- error(record, attribute) && return if address.disposable_domain?
33
+ error(record, attribute) && return if addresses.any?(&:disposable_domain?)
33
34
  end
34
35
 
35
36
  if options[:disposable_with_whitelist]
36
- error(record, attribute) && return if address.disposable? && !address.whitelisted?
37
+ error(record, attribute) && return if addresses.any? { |address| address.disposable? && !address.whitelisted? }
37
38
  end
38
39
 
39
40
  if options[:blacklist]
40
- error(record, attribute) && return if address.blacklisted?
41
+ error(record, attribute) && return if addresses.any?(&:blacklisted?)
41
42
  end
42
43
 
43
44
  if options[:mx]
44
- error(record, attribute) && return unless address.valid_mx?
45
+ error(record, attribute) && return unless addresses.all?(&:valid_mx?)
45
46
  end
46
47
  end
47
48
 
@@ -1,3 +1,3 @@
1
1
  module ValidEmail2
2
- VERSION = "3.2.4"
2
+ VERSION = "3.4.0"
3
3
  end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ describe "Performance testing" do
6
+ let(:disposable_domain) { ValidEmail2.disposable_emails.first }
7
+
8
+ it "has acceptable lookup performance" do
9
+ address = ValidEmail2::Address.new("test@example.com")
10
+
11
+ # preload list and check size
12
+ expect(ValidEmail2.disposable_emails).to be_a(Set)
13
+ expect(ValidEmail2.disposable_emails.count).to be > 30000
14
+
15
+ # check lookup timing
16
+ expect { address.disposable_domain? }.to perform_under(0.0001).sample(10).times
17
+ end
18
+ end
@@ -1,6 +1,15 @@
1
1
  $:.unshift File.expand_path("../lib",__FILE__)
2
2
  require "valid_email2"
3
3
 
4
+ # Include and configure benchmark
5
+ require 'rspec-benchmark'
6
+ RSpec.configure do |config|
7
+ config.include RSpec::Benchmark::Matchers
8
+ end
9
+ RSpec::Benchmark.configure do |config|
10
+ config.disable_gc = true
11
+ end
12
+
4
13
  class TestModel
5
14
  include ActiveModel::Validations
6
15
 
@@ -39,6 +39,10 @@ class TestUserMessage < TestModel
39
39
  validates :email, 'valid_email_2/email': { message: "custom message" }
40
40
  end
41
41
 
42
+ class TestUserMultiple < TestModel
43
+ validates :email, 'valid_email_2/email': { multiple: true }
44
+ end
45
+
42
46
  describe ValidEmail2 do
43
47
 
44
48
  let(:disposable_domain) { ValidEmail2.disposable_emails.first }
@@ -83,13 +87,13 @@ describe ValidEmail2 do
83
87
  expect(user.valid?).to be_falsey
84
88
  end
85
89
 
86
- it "is invalid if the domain contains emoticons" do
87
- user = TestUser.new(email: "foo🙈@gmail.com")
88
- expect(user.valid?).to be_falsy
90
+ it "is invalid if the address contains consecutive dots" do
91
+ user = TestUser.new(email: "foo..bar@gmail.com")
92
+ expect(user.valid?).to be_falsey
89
93
  end
90
94
 
91
- it "is invalid if the domain contains .@ consecutively" do
92
- user = TestUser.new(email: "foo.@gmail.com")
95
+ it "is invalid if the email contains emoticons" do
96
+ user = TestUser.new(email: "foo🙈@gmail.com")
93
97
  expect(user.valid?).to be_falsy
94
98
  end
95
99
 
@@ -244,6 +248,20 @@ describe ValidEmail2 do
244
248
  end
245
249
  end
246
250
 
251
+ describe "with multiple addresses" do
252
+ it "tests each address for it's own" do
253
+ user = TestUserMultiple.new(email: "foo@gmail.com, bar@gmail.com")
254
+ expect(user.valid?).to be_truthy
255
+ end
256
+
257
+ context 'when one address is invalid' do
258
+ it "fails for all" do
259
+ user = TestUserMultiple.new(email: "foo@gmail.com, bar@123")
260
+ expect(user.valid?).to be_falsey
261
+ end
262
+ end
263
+ end
264
+
247
265
  describe "#dotted?" do
248
266
  it "is true when address local part contains a dot delimiter ('.')" do
249
267
  email = ValidEmail2::Address.new("john.doe@gmail.com")
@@ -23,6 +23,7 @@ Gem::Specification.new do |spec|
23
23
  spec.add_development_dependency "bundler", "~> 2.0"
24
24
  spec.add_development_dependency "rake", "~> 12.3.3"
25
25
  spec.add_development_dependency "rspec", "~> 3.5.0"
26
+ spec.add_development_dependency "rspec-benchmark", "~> 0.6"
26
27
  spec.add_development_dependency "pry"
27
28
  spec.add_runtime_dependency "mail", "~> 2.5"
28
29
  spec.add_runtime_dependency "activemodel", ">= 3.2"
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: 3.2.4
4
+ version: 3.4.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: 2020-07-12 00:00:00.000000000 Z
11
+ date: 2020-09-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -52,6 +52,20 @@ dependencies:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
54
  version: 3.5.0
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec-benchmark
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '0.6'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '0.6'
55
69
  - !ruby/object:Gem::Dependency
56
70
  name: pry
57
71
  requirement: !ruby/object:Gem::Requirement
@@ -120,6 +134,7 @@ files:
120
134
  - lib/valid_email2/email_validator.rb
121
135
  - lib/valid_email2/version.rb
122
136
  - pull_mailchecker_emails.rb
137
+ - spec/benchmark_spec.rb
123
138
  - spec/spec_helper.rb
124
139
  - spec/valid_email2_spec.rb
125
140
  - valid_email2.gemspec
@@ -142,11 +157,12 @@ required_rubygems_version: !ruby/object:Gem::Requirement
142
157
  - !ruby/object:Gem::Version
143
158
  version: '0'
144
159
  requirements: []
145
- rubygems_version: 3.1.4
160
+ rubygems_version: 3.1.2
146
161
  signing_key:
147
162
  specification_version: 4
148
163
  summary: ActiveModel validation for email. Including MX lookup and disposable email
149
164
  blacklist
150
165
  test_files:
166
+ - spec/benchmark_spec.rb
151
167
  - spec/spec_helper.rb
152
168
  - spec/valid_email2_spec.rb