email_validator 2.2.2 → 2.2.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9f5010b8d56592e8febeda1e96b6fa35a27e2dae75dab6277fbade5f35b74b18
4
- data.tar.gz: 50bbb4a9c6abea2db5c2e887ba67a88739afccdb445c56be74c063b10993cef3
3
+ metadata.gz: c6952edf85fc0eafbe159b4a3b812731c81361ee0a15f22927e270a3eb885c9d
4
+ data.tar.gz: 8b5a56e059f652f1822c93cbcec0be9da23842433e9c7e5f97478496ba888ff9
5
5
  SHA512:
6
- metadata.gz: b520404b2777c72ac87eaccaaacb073b340ebca043d104d531d8d78c74fd413d2f0e1c5ef6b7d08529a23d2aad913c7e1d15ab16989ea5777b5f41d37539365b
7
- data.tar.gz: 100eb11eaff2bd530d7a6c554655d93649a45aa6a5e5718a31cfa0c994f8e5341b57964d01c7f256ce4e8e927c3ba8e5610694cd293dda2d3241a2f2c187e1b9
6
+ metadata.gz: 158307d4196989b8d73872fa91c302ee9eab174b25f0686f3d61fe395796fa0b8e6c1c08185a4accf6c9581e23ba66bbebb8e3e8dc46b7ded935ed80a2484b53
7
+ data.tar.gz: 7f9ccf405a9bcf08d809fa58819d9e6d8489871a52020115802f3c755eddc3962b3533928f8f7c40e8122b055ad185c6f72cf1878ad6c920ba1b86872c0362a8
data/CHANGELOG.md CHANGED
@@ -5,6 +5,41 @@ This file is used to list changes made in `email_validator`.
5
5
  All notable changes to this project will be documented in this file.
6
6
  This project adheres to [Semantic Versioning](http://semver.org/).
7
7
 
8
+ ## 2.2.4 (2022-11-09)
9
+
10
+ * [karlwilbur] - Remove Ruby 2.4 from tested versions; add Ruby 3.0 and 3.1 to tested versions
11
+ * [karlwilbur] - Fix issue where `domain: ''` wasn't requiring empty domain
12
+ * [karlwilbur] - Remove checks for double hyphens (fixes [#87](https://github.com/K-and-R/email_validator/issues/87))
13
+ * [dependabot] - Security updates
14
+ - [#89](https://github.com/K-and-R/email_validator/pull/89)
15
+ + Bump `minimist` from `1.2.5` to `1.2.7`
16
+ - [#86](https://github.com/K-and-R/email_validator/pull/86)
17
+ + Bump `node-fetch` from `2.6.1` to `2.6.7`
18
+ + Add `whatwg-url` at `5.0.0`
19
+ + Add `tr46` at `0.0.3`
20
+ + Add `webidl-conversions` at `3.0.0`
21
+ - [#80](https://github.com/K-and-R/email_validator/pull/80)
22
+ + Bump `tar` from `6.0.5` to `6.1.11`
23
+ + Bump `minipass` from `3.1.3` to `3.1.5`
24
+ - [#79](https://github.com/K-and-R/email_validator/pull/79)
25
+ + Bump `path-parse` from `1.0.6` to `1.0.7`
26
+ - [#76](https://github.com/K-and-R/email_validator/pull/76)
27
+ + Bump `lodash` from `4.17.20` to `4.17.21`
28
+ - [#75](https://github.com/K-and-R/email_validator/pull/75)
29
+ + Bump `hosted-git-info` from `2.8.8` to `2.8.9`
30
+ * [msands] - Fix URL in `README.md` [#81](https://github.com/K-and-R/email_validator/pull/81)
31
+ * [kerolloz] - Fix typo in `README.md` [#73](https://github.com/K-and-R/email_validator/pull/73)
32
+
33
+ ## 2.2.3 (2021-04-05)
34
+
35
+ * [karlwilbur] - Fix regexp for numeric domains (fixes [#72](https://github.com/K-and-R/email_validator/issues/72))
36
+ - [delphaber] - Add checks for numeric-only domains in tests (should be considered valid)
37
+ - [karlwilbur] - Fix specs for numeric-only domains labels (should be considered valid)
38
+ - [karlwilbur] - Add checks for numeric-only TLDs in tests (should be considered invalid)
39
+ - [karlwilbur] - Add tests to ensure that `regexp` returns expected value
40
+ * [karlwilbur] - Add checks for double dash in domain (should be considered invalid)
41
+ * [karlwilbur] - Add `EmailValidator::Error` class, raise `EmailValidator::Error` when invalid `mode`
42
+
8
43
  ## 2.2.2 (2020-12-10)
9
44
 
10
45
  * [karlwilbur] - Fix includes for `:rfc` and `:strict` modes from `Gemfile`
data/README.md CHANGED
@@ -14,7 +14,7 @@ Formerly found at: <https://github.com/balexand/email_validator>
14
14
 
15
15
  The default validation provided by this gem (the `:loose` configuration option)
16
16
  is extremely loose. It just checks that there's an `@` with something before and
17
- after it without any whitespace. See [this article by David Gilbertson](https://hackernoon.com/the-100-correct-way-to-validate-email-addresses-7c4818f24643)
17
+ after it without any whitespace. See [this article by David Gilbertson](https://medium.com/hackernoon/the-100-correct-way-to-validate-email-addresses-7c4818f24643)
18
18
  for an explanation of why.
19
19
 
20
20
  We understand that many use cases require an increased level of validation. This
@@ -54,9 +54,9 @@ by setting `require_fqdn: true` or by enabling `:strict` checking:
54
54
  validates :my_email_attribute, email: {mode: :strict, require_fqdn: true}
55
55
  ```
56
56
 
57
- You can also limit to a single domain (e.g: this might help if, for example, you
58
- have separate `User` and `AdminUser` models and want to ensure that `AdminUser`
59
- emails are on a specific domain):
57
+ You can also limit to a single domain (e.g: you have separate `User` and
58
+ `AdminUser` models and want to ensure that `AdminUser` emails are on a specific
59
+ domain):
60
60
 
61
61
  ```ruby
62
62
  validates :my_email_attribute, email: {domain: 'example.com'}
@@ -68,7 +68,7 @@ Default configuration can be overridden by setting options in `config/initialize
68
68
 
69
69
  ```ruby
70
70
  if defined?(EmailValidator)
71
- # To completly override the defaults
71
+ # To completely override the defaults
72
72
  EmailValidator.default_options = {
73
73
  allow_nil: false,
74
74
  domain: nil,
@@ -166,6 +166,10 @@ EmailValidator.valid?('narf@somehost') # boolean false
166
166
  EmailValidator.invalid?('narf@somehost', require_fqdn: false) # boolean true
167
167
  ```
168
168
 
169
+ _NB: Enabling strict mode (`mode: :strict`) enables `require_fqdn`
170
+ (`require_fqdn: true`), overridding any `require_fqdn: false` while
171
+ `mode: :strict` is set._
172
+
169
173
  ### Requiring a specific domain
170
174
 
171
175
  ```ruby
@@ -1,4 +1,6 @@
1
1
  # Based on work from http://thelucid.com/2010/01/08/sexy-validation-in-edge-rails-rails-3/
2
+
3
+ # EmailValidator class
2
4
  class EmailValidator < ActiveModel::EachValidator
3
5
  # rubocop:disable Style/ClassVars
4
6
  @@default_options = {
@@ -9,6 +11,13 @@ class EmailValidator < ActiveModel::EachValidator
9
11
  }
10
12
  # rubocop:enable Style/ClassVars
11
13
 
14
+ # EmailValidator::Error class
15
+ class Error < StandardError
16
+ def initialize(msg = 'EmailValidator error')
17
+ super
18
+ end
19
+ end
20
+
12
21
  class << self
13
22
  def default_options
14
23
  @@default_options
@@ -18,6 +27,8 @@ class EmailValidator < ActiveModel::EachValidator
18
27
  options = parse_options(options)
19
28
  return true if value.nil? && options[:allow_nil] == true
20
29
  return false if value.nil?
30
+ # quickly fail if domain is required but doesn't match
31
+ return false unless options[:domain].nil? || value[/^.*@#{regexp_safe_domain(options)}$/]
21
32
  !!(value =~ regexp(options))
22
33
  end
23
34
 
@@ -35,8 +46,11 @@ class EmailValidator < ActiveModel::EachValidator
35
46
  loose_regexp(options)
36
47
  when :rfc
37
48
  rfc_regexp(options)
38
- else
49
+ when :strict
50
+ options[:require_fqdn] = true
39
51
  strict_regexp(options)
52
+ else
53
+ fail EmailValidator::Error, "Validation mode '#{options[:mode]}' is not supported by EmailValidator"
40
54
  end
41
55
  end
42
56
 
@@ -81,31 +95,33 @@ class EmailValidator < ActiveModel::EachValidator
81
95
  end
82
96
 
83
97
  def host_label_pattern
98
+ "#{label_is_correct_length}" \
84
99
  "#{alnum}(?:#{alnumhy}{,61}#{alnum})?"
85
100
  end
86
101
 
87
102
  # splitting this up into separate regex pattern for performance; let's not
88
103
  # try the "contains" pattern unless we have to
89
104
  def domain_label_pattern
90
- '(?=[^.]{1,63}(?:\.|$))' \
91
- '(?:' \
92
- "#{alpha}" \
93
- "|#{domain_label_starts_with_a_letter_pattern}" \
94
- "|#{domain_label_ends_with_a_letter_pattern}" \
95
- "|#{domain_label_contains_a_letter_pattern}" \
96
- ')'
105
+ "#{host_label_pattern}\\.#{tld_label_pattern}"
97
106
  end
98
107
 
99
- def domain_label_starts_with_a_letter_pattern
100
- "#{alpha}#{alnumhy}{,61}#{alnum}"
108
+ # While, techincally, TLDs can be numeric-only, this is not allowed by ICANN
109
+ # Ref: ICANN Application Guidebook for new TLDs (June 2012)
110
+ # says the following starting at page 64:
111
+ #
112
+ # > The ASCII label must consist entirely of letters (alphabetic characters a-z)
113
+ #
114
+ # -- https://newgtlds.icann.org/en/applicants/agb/guidebook-full-04jun12-en.pdf
115
+ def tld_label_pattern
116
+ "#{alpha}{1,64}"
101
117
  end
102
118
 
103
- def domain_label_ends_with_a_letter_pattern
104
- "#{alnum}#{alnumhy}{,61}#{alpha}"
119
+ def label_is_correct_length
120
+ '(?=[^.]{1,63}(?:\.|$))'
105
121
  end
106
122
 
107
- def domain_label_contains_a_letter_pattern
108
- "(?:[[:digit:]])(?:[[:digit:]]|-)*#{alpha}#{alnumhy}*#{alnum}"
123
+ def domain_part_is_correct_length
124
+ '(?=.{1,255}$)'
109
125
  end
110
126
 
111
127
  def atom_char
@@ -120,13 +136,13 @@ class EmailValidator < ActiveModel::EachValidator
120
136
  end
121
137
 
122
138
  def domain_part_pattern(options)
123
- return options[:domain].sub(/\./, '\.') if options[:domain].present?
139
+ return regexp_safe_domain(options) unless options[:domain].nil?
124
140
  return fqdn_pattern if options[:require_fqdn]
125
- "(?=.{1,255}$)(?:#{address_literal}|(?:#{host_label_pattern}\\.)*#{domain_label_pattern})"
141
+ "#{domain_part_is_correct_length}(?:#{address_literal}|(?:#{host_label_pattern}\\.)*#{tld_label_pattern})"
126
142
  end
127
143
 
128
144
  def fqdn_pattern
129
- "(?=.{1,255}$)(?:#{host_label_pattern}\\.)*#{domain_label_pattern}\\.#{domain_label_pattern}"
145
+ "(?=.{1,255}$)(?:#{host_label_pattern}\\.)*#{domain_label_pattern}"
130
146
  end
131
147
 
132
148
  private
@@ -136,6 +152,10 @@ class EmailValidator < ActiveModel::EachValidator
136
152
  options[:require_fqdn] = true if options[:require_fqdn].nil? && options[:mode] == :strict
137
153
  default_options.merge(options)
138
154
  end
155
+
156
+ def regexp_safe_domain(options)
157
+ options[:domain].sub(/\./, '\.')
158
+ end
139
159
  end
140
160
 
141
161
  def validate_each(record, attribute, value)
@@ -52,6 +52,18 @@ class NonFqdnRfcUser < TestModel
52
52
  validates :email, :email => { :require_fqdn => false, :mode => :rfc }
53
53
  end
54
54
 
55
+ class RequireFqdnWithEmptyDomainUser < TestModel
56
+ validates :email_address, :email => { :require_fqdn => true, :domain => '' }
57
+ end
58
+
59
+ class RequireEmptyDomainStrictUser < TestModel
60
+ validates :email_address, :email => { :require_fqdn => true, :domain => '', :mode => :strict }
61
+ end
62
+
63
+ class RequireEmptyDomainRfcUser < TestModel
64
+ validates :email_address, :email => { :require_fqdn => true, :domain => '', :mode => :rfc }
65
+ end
66
+
55
67
  class DefaultUserWithMessage < TestModel
56
68
  validates :email_address, :email => { :message => 'is not looking very good!' }
57
69
  end
@@ -146,7 +158,10 @@ RSpec.describe EmailValidator do
146
158
  'john.doe@a2.com',
147
159
  'john.doe@2020.a-z.com',
148
160
  'john.doe@2020.a2z.com',
149
- 'john.doe@2020.12345a6789.com'
161
+ 'john.doe@2020.12345a6789.com',
162
+ 'jonh.doe@163.com',
163
+ 'test@umläut.com', # non-ASCII
164
+ 'test@xn--umlut-ira.com' # ASCII-compatibale encoding of non-ASCII
150
165
  ]).flatten.each do |email|
151
166
  context 'when using defaults' do
152
167
  it "'#{email}' should be valid" do
@@ -289,20 +304,20 @@ RSpec.describe EmailValidator do
289
304
  end
290
305
 
291
306
  context 'when in `:strict` mode' do
292
- it "'#{email}' should not be valid" do
293
- expect(StrictUser.new(:email => email)).not_to be_valid
307
+ it "'#{email}' should be valid" do
308
+ expect(StrictUser.new(:email => email)).to be_valid
294
309
  end
295
310
 
296
- it "'#{email}' should not be valid using EmailValidator.valid?" do
297
- expect(described_class).not_to be_valid(email, :mode => :strict)
311
+ it "'#{email}' should be valid using EmailValidator.valid?" do
312
+ expect(described_class).to be_valid(email, :mode => :strict)
298
313
  end
299
314
 
300
- it "'#{email}' should be invalid using EmailValidator.invalid?" do
301
- expect(described_class).to be_invalid(email, :mode => :strict)
315
+ it "'#{email}' should be not invalid using EmailValidator.invalid?" do
316
+ expect(described_class).not_to be_invalid(email, :mode => :strict)
302
317
  end
303
318
 
304
- it "'#{email}' should not match the regexp" do
305
- expect(!!(email.strip =~ described_class.regexp(:mode => :strict))).to be(false)
319
+ it "'#{email}' should match the regexp" do
320
+ expect(!!(email.strip =~ described_class.regexp(:mode => :strict))).to be(true)
306
321
  end
307
322
  end
308
323
 
@@ -703,7 +718,8 @@ RSpec.describe EmailValidator do
703
718
  ]}).concat([
704
719
  'user..-with-double-dots@example.com',
705
720
  '.user-beginning-with-dot@example.com',
706
- 'user-ending-with-dot.@example.com'
721
+ 'user-ending-with-dot.@example.com',
722
+ 'fully-numeric-tld@example.123'
707
723
  ]).flatten.each do |email|
708
724
  context 'when using defaults' do
709
725
  it "#{email.strip} in a model should be valid" do
@@ -724,7 +740,7 @@ RSpec.describe EmailValidator do
724
740
  end
725
741
 
726
742
  context 'when in `:strict` mode' do
727
- it "#{email.strip} in a model should be valid" do
743
+ it "#{email.strip} in a model should not be valid" do
728
744
  expect(StrictUser.new(:email => email)).not_to be_valid
729
745
  end
730
746
 
@@ -761,6 +777,68 @@ RSpec.describe EmailValidator do
761
777
  end
762
778
  end
763
779
 
780
+ context 'when `require_fqdn` is explicitly enabled with a blank domain' do
781
+ let(:opts) { { :require_fqdn => true, :domain => '' } }
782
+
783
+ context 'when given a email containing any domain' do
784
+ let(:email) { 'someuser@somehost' }
785
+
786
+ context 'when using defaults' do
787
+ it 'is not valid in a model' do
788
+ expect(RequireFqdnWithEmptyDomainUser.new(:email => email)).not_to be_valid
789
+ end
790
+
791
+ it 'is not using EmailValidator.valid?' do
792
+ expect(described_class).not_to be_valid(email, opts)
793
+ end
794
+
795
+ it 'is invalid using EmailValidator.invalid?' do
796
+ expect(described_class).to be_invalid(email, opts)
797
+ end
798
+
799
+ it 'does not match the regexp' do
800
+ expect(!!(email =~ described_class.regexp(opts))).to be(false)
801
+ end
802
+ end
803
+
804
+ context 'when in `:strict` mode' do
805
+ it 'is not valid in a model' do
806
+ expect(RequireEmptyDomainStrictUser.new(:email => email)).not_to be_valid
807
+ end
808
+
809
+ it 'is not using EmailValidator.valid?' do
810
+ expect(described_class).not_to be_valid(email, opts.merge({ :mode => :strict }))
811
+ end
812
+
813
+ it 'is invalid using EmailValidator.invalid?' do
814
+ expect(described_class).to be_invalid(email, opts.merge({ :mode => :strict }))
815
+ end
816
+
817
+ it 'does not match the regexp' do
818
+ expect(!!(email =~ described_class.regexp(opts.merge({ :mode => :strict })))).to be(false)
819
+ end
820
+ end
821
+
822
+ context 'when in `:rfc` mode' do
823
+ it 'is not valid in a model' do
824
+ expect(RequireEmptyDomainRfcUser.new(:email => email)).not_to be_valid
825
+ end
826
+
827
+ it 'is not using EmailValidator.valid?' do
828
+ expect(described_class).not_to be_valid(email, opts.merge({ :mode => :rfc }))
829
+ end
830
+
831
+ it 'is invalid using EmailValidator.invalid?' do
832
+ expect(described_class).to be_invalid(email, opts.merge({ :mode => :rfc }))
833
+ end
834
+
835
+ it 'does not match the regexp' do
836
+ expect(!!(email =~ described_class.regexp(opts.merge({ :mode => :rfc })))).to be(false)
837
+ end
838
+ end
839
+ end
840
+ end
841
+
764
842
  context 'when `require_fqdn` is explicitly disabled' do
765
843
  let(:opts) { { :require_fqdn => false } }
766
844
 
@@ -781,23 +859,24 @@ RSpec.describe EmailValidator do
781
859
  end
782
860
  end
783
861
 
862
+ # Strict mode enables `require_fqdn` anyway
784
863
  context 'when in `:strict` mode' do
785
864
  let(:opts) { { :require_fqdn => false, :mode => :strict } }
786
865
 
787
- it 'is valid' do
788
- expect(NonFqdnStrictUser.new(:email => email)).to be_valid
866
+ it 'is not valid' do
867
+ expect(NonFqdnStrictUser.new(:email => email)).not_to be_valid
789
868
  end
790
869
 
791
- it 'is valid using EmailValidator.valid?' do
792
- expect(described_class).to be_valid(email, opts)
870
+ it 'is not valid using EmailValidator.valid?' do
871
+ expect(described_class).not_to be_valid(email, opts)
793
872
  end
794
873
 
795
- it 'is not invalid using EmailValidator.invalid?' do
796
- expect(described_class).not_to be_invalid(email, opts)
874
+ it 'is invalid using EmailValidator.invalid?' do
875
+ expect(described_class).to be_invalid(email, opts)
797
876
  end
798
877
 
799
878
  it 'matches the regexp' do
800
- expect(!!(email =~ described_class.regexp(opts))).to be(true)
879
+ expect(!!(email =~ described_class.regexp(opts))).to be(false)
801
880
  end
802
881
  end
803
882
 
@@ -1012,4 +1091,36 @@ RSpec.describe EmailValidator do
1012
1091
  end
1013
1092
  end
1014
1093
  end
1094
+
1095
+ context 'with regexp' do
1096
+ it 'returns a regexp when asked' do
1097
+ expect(described_class.regexp).to be_a(Regexp)
1098
+ end
1099
+
1100
+ it 'returns a strict regexp when asked' do
1101
+ expect(described_class.regexp(:mode => :strict)).to be_a(Regexp)
1102
+ end
1103
+
1104
+ it 'returns a RFC regexp when asked' do
1105
+ expect(described_class.regexp(:mode => :rfc)).to be_a(Regexp)
1106
+ end
1107
+
1108
+ it 'has different regexp for strict and loose' do
1109
+ expect(described_class.regexp(:mode => :strict)).not_to eq(described_class.regexp(:mode => :loose))
1110
+ end
1111
+
1112
+ it 'has different regexp for RFC and loose' do
1113
+ expect(described_class.regexp(:mode => :rfc)).not_to eq(described_class.regexp(:mode => :loose))
1114
+ end
1115
+
1116
+ it 'has different regexp for RFC and strict' do
1117
+ expect(described_class.regexp(:mode => :rfc)).not_to eq(described_class.regexp(:mode => :strict))
1118
+ end
1119
+ end
1120
+
1121
+ context 'with invalid `:mode`' do
1122
+ it 'raises an error' do
1123
+ expect { described_class.regexp(:mode => :invalid) }.to raise_error(EmailValidator::Error)
1124
+ end
1125
+ end
1015
1126
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: email_validator
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.2.2
4
+ version: 2.2.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brian Alexander
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2020-12-11 00:00:00.000000000 Z
12
+ date: 2022-11-09 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activemodel
@@ -61,7 +61,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
61
61
  - !ruby/object:Gem::Version
62
62
  version: '0'
63
63
  requirements: []
64
- rubygems_version: 3.1.4
64
+ rubygems_version: 3.2.15
65
65
  signing_key:
66
66
  specification_version: 4
67
67
  summary: An email validator for Rails 3+.