valid_email2 3.2.3 → 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: dc36490d5ad59e2c3b3cdd3c539a812f856edcc6f9ca58cb83abd76dd6c552e9
4
- data.tar.gz: 760dfc6b6d8b451ed0e872157018f6d71da9e47c6511bacbb553115ed66210b2
3
+ metadata.gz: 71c14200d42afbdf47d3222f443c72f81dd23af157f32baebbcc607d2ef09959
4
+ data.tar.gz: 67e841c534a03d363b118bc50026dcc54ee1550478a98d92e885d53c40905ffe
5
5
  SHA512:
6
- metadata.gz: b6669d5eccb655f44f2afa63b2b4d9709b70a01c54c5a8b3d1667618c75aae426aef4c082ea5844ea72510f3777a417e08acd8bdacb01e77e920aa4b096463d0
7
- data.tar.gz: '09819606d5610bbb084b8ac28b175b9c6eb7b23b03aaf7a90f54364480aa2d86b310bfcd2af179b364fca5650a2bcf5d207d44bdfb7cf725a1b14b939e68f6d9'
6
+ metadata.gz: 27e0b370d3fc4fa2fb1530e931c9f06156c88045f9b55a4b9e038d521460b34ac4dc8b81f6194ea649477cb4169774cfe3b7a9ad15e06447f472b0742700433e
7
+ data.tar.gz: d160ab3de4196dc830e26aedab650c9839520b9aadccb9e6153305eb42ad796929cab5a209aef3ce869e1a801171b7de45fdc23d3e5ac6004436ad7e31a2a6ef
@@ -1,3 +1,21 @@
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
+
16
+ ## Version 3.2.4
17
+ * Remove false positives
18
+
1
19
  ## Version 3.2.3
2
20
  * Disallow backtick (\`) in domain
3
21
  * https://github.com/micke/valid_email2/pull/152
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
@@ -4181,6 +4182,9 @@ awahal0vk1o7gbyzf0.ml
4181
4182
  awahal0vk1o7gbyzf0.tk
4182
4183
  awatum.de
4183
4184
  awca.eu
4185
+ awdrt.com
4186
+ awdrt.net
4187
+ awdrt.org
4184
4188
  aweather.ru
4185
4189
  aweightlossguide.com
4186
4190
  awemail.com
@@ -7863,6 +7867,7 @@ cungmuachungnhom.com
7863
7867
  cungsuyngam.com
7864
7868
  cungtam.com
7865
7869
  cuoiz.com
7870
+ cuoly.com
7866
7871
  cuongvumarketingseo.com
7867
7872
  cupf6mdhtujxytdcoxh.cf
7868
7873
  cupf6mdhtujxytdcoxh.ga
@@ -9769,7 +9774,6 @@ edu.auction
9769
9774
  edu.dmtc.dev
9770
9775
  edu.hstu.eu.org
9771
9776
  edu.my
9772
- edu.sg
9773
9777
  eduanswer.ru
9774
9778
  education.eu
9775
9779
  educationleaders-ksa.com
@@ -10119,6 +10123,7 @@ emailme.win
10119
10123
  emailmenow.info
10120
10124
  emailmiser.com
10121
10125
  emailmobile.net
10126
+ emailmonkey.club
10122
10127
  emailmynn.com
10123
10128
  emailmysr.com
10124
10129
  emailna.co
@@ -10348,6 +10353,7 @@ eo-z.com
10348
10353
  eoffice.top
10349
10354
  eomail.com
10350
10355
  eonmech.com
10356
+ eoopy.com
10351
10357
  eorbs.com
10352
10358
  eos2mail.com
10353
10359
  eotoplenie.ru
@@ -11397,6 +11403,8 @@ fitnessjockey.org
11397
11403
  fitnessmojo.org
11398
11404
  fitnessreviewsonline.com
11399
11405
  fitnesszbyszko.pl
11406
+ fitschool.be
11407
+ fitschool.space
11400
11408
  fittinggeeks.pl
11401
11409
  fitzgeraldforjudge.com
11402
11410
  five-club.com
@@ -18797,6 +18805,7 @@ mailbox92.biz
18797
18805
  mailboxheaven.info
18798
18806
  mailboxint.info
18799
18807
  mailboxlife.net
18808
+ mailboxok.club
18800
18809
  mailboxonline.org
18801
18810
  mailboxrental.org
18802
18811
  mailboxxx.net
@@ -28478,6 +28487,7 @@ tempemailaddress.com
28478
28487
  tempemails.io
28479
28488
  tempinbox.co.uk
28480
28489
  tempinbox.com
28490
+ tempinbox.xyz
28481
28491
  tempm.cf
28482
28492
  tempm.com
28483
28493
  tempm.ga
@@ -29594,6 +29604,9 @@ tsukushiakihito.gq
29594
29604
  tt2dx90.com
29595
29605
  ttbbc.com
29596
29606
  ttdfytdd.ml
29607
+ ttirv.com
29608
+ ttirv.net
29609
+ ttirv.org
29597
29610
  ttoubdzlowecm7i2ua8.cf
29598
29611
  ttoubdzlowecm7i2ua8.ga
29599
29612
  ttoubdzlowecm7i2ua8.gq
@@ -32784,7 +32797,6 @@ yammyshop.com
32784
32797
  yandere.cu.cc
32785
32798
  yandex.ca
32786
32799
  yandex.comx.cf
32787
- yandex.net
32788
32800
  yandexmail.cf
32789
32801
  yandexmail.ga
32790
32802
  yandexmail.gq
@@ -33688,4 +33700,4 @@ zzv2bfja5.pl
33688
33700
  zzz.co
33689
33701
  zzz.com
33690
33702
  zzzmail.pl
33691
- 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.3"
2
+ VERSION = "3.4.0"
3
3
  end
@@ -8,6 +8,7 @@ require "net/http"
8
8
  whitelisted_emails = %w(
9
9
  onet.pl poczta.onet.pl fastmail.fm hushmail.com
10
10
  hush.ai hush.com hushmail.me naver.com qq.com example.com
11
+ yandex.net gmx.com gmx.es
11
12
  )
12
13
 
13
14
  existing_emails = File.open("config/disposable_email_domains.txt") { |f| f.read.split("\n") }
@@ -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.3
4
+ version: 3.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Micke Lisinge
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-06-30 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
@@ -127,7 +142,7 @@ homepage: https://github.com/micke/valid_email2
127
142
  licenses:
128
143
  - MIT
129
144
  metadata: {}
130
- post_install_message:
145
+ post_install_message:
131
146
  rdoc_options: []
132
147
  require_paths:
133
148
  - lib
@@ -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.0.3
146
- signing_key:
160
+ rubygems_version: 3.1.2
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