email_validator 2.2.2 → 2.2.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +10 -0
- data/README.md +7 -3
- data/lib/email_validator.rb +35 -16
- data/spec/email_validator_spec.rb +53 -17
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 46bd723714c6aa3a844e584e986e5989920b6d3f212a44d800183d118c561cb7
|
4
|
+
data.tar.gz: bb58e5bf862c4be796e3ce59727dcf3fd2e28267e7c6077014f01d25dc841580
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2ece91a44bd82bd79c5484a17729996731787148b6813af0c4e41804715242a9cbfb4c0d661b08e0c904753dd59f23560d11aed7bf9044986802445e36f69438
|
7
|
+
data.tar.gz: 1b91bf21ce112f86f9b97138573d20fe14b67f075935136c3b19a620f155d50c5d5cf5ff9566e4c101429b8d7ce80ccb80709a2a15eeb07f4caeaac34f2b86b0
|
data/CHANGELOG.md
CHANGED
@@ -5,6 +5,16 @@ 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.3 (2021-04-05)
|
9
|
+
|
10
|
+
* [karlwilbur] - Fix regexp for numeric domains (fixes [#72](https://github.com/K-and-R/email_validator/issues/72))
|
11
|
+
- [delphaber] - Add checks for numeric-only domains in tests (should be considered valid)
|
12
|
+
- [karlwilbur] - Fix specs for numeric-only domains labels (should be considered valid)
|
13
|
+
- [karlwilbur] - Add checks for numeric-only TLDs in tests (should be considered invalid)
|
14
|
+
- [karlwilbur] - Add tests to ensure that `regexp` returns expected value
|
15
|
+
- [karlwilbur] - Add checks for double dash in domain (should be considered invalid)
|
16
|
+
- [karlwilbur] - Add `EmailValidator::Error` class, raise `EmailValidator::Error` when invalid `mode`
|
17
|
+
|
8
18
|
## 2.2.2 (2020-12-10)
|
9
19
|
|
10
20
|
* [karlwilbur] - Fix includes for `:rfc` and `:strict` modes from `Gemfile`
|
data/README.md
CHANGED
@@ -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:
|
58
|
-
|
59
|
-
|
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'}
|
@@ -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
|
data/lib/email_validator.rb
CHANGED
@@ -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
|
@@ -35,8 +44,11 @@ class EmailValidator < ActiveModel::EachValidator
|
|
35
44
|
loose_regexp(options)
|
36
45
|
when :rfc
|
37
46
|
rfc_regexp(options)
|
38
|
-
|
47
|
+
when :strict
|
48
|
+
options[:require_fqdn] = true
|
39
49
|
strict_regexp(options)
|
50
|
+
else
|
51
|
+
fail EmailValidator::Error, "Validation mode '#{options[:mode]}' is not supported by EmailValidator"
|
40
52
|
end
|
41
53
|
end
|
42
54
|
|
@@ -81,31 +93,38 @@ class EmailValidator < ActiveModel::EachValidator
|
|
81
93
|
end
|
82
94
|
|
83
95
|
def host_label_pattern
|
96
|
+
"#{label_is_correct_length}" \
|
97
|
+
"#{label_contains_no_more_than_one_consecutive_hyphen}" \
|
84
98
|
"#{alnum}(?:#{alnumhy}{,61}#{alnum})?"
|
85
99
|
end
|
86
100
|
|
87
101
|
# splitting this up into separate regex pattern for performance; let's not
|
88
102
|
# try the "contains" pattern unless we have to
|
89
103
|
def domain_label_pattern
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
104
|
+
"#{host_label_pattern}\\.#{tld_label_pattern}"
|
105
|
+
end
|
106
|
+
|
107
|
+
# While, techincally, TLDs can be numeric-only, this is not allowed by ICANN
|
108
|
+
# Ref: ICANN Application Guidebook for new TLDs (June 2012)
|
109
|
+
# says the following starting at page 64:
|
110
|
+
#
|
111
|
+
# > The ASCII label must consist entirely of letters (alphabetic characters a-z)
|
112
|
+
#
|
113
|
+
# -- https://newgtlds.icann.org/en/applicants/agb/guidebook-full-04jun12-en.pdf
|
114
|
+
def tld_label_pattern
|
115
|
+
"#{alpha}{1,64}"
|
97
116
|
end
|
98
117
|
|
99
|
-
def
|
100
|
-
|
118
|
+
def label_is_correct_length
|
119
|
+
'(?=[^.]{1,63}(?:\.|$))'
|
101
120
|
end
|
102
121
|
|
103
|
-
def
|
104
|
-
|
122
|
+
def domain_part_is_correct_length
|
123
|
+
'(?=.{1,255}$)'
|
105
124
|
end
|
106
125
|
|
107
|
-
def
|
108
|
-
|
126
|
+
def label_contains_no_more_than_one_consecutive_hyphen
|
127
|
+
'(?!.*?--.*$)'
|
109
128
|
end
|
110
129
|
|
111
130
|
def atom_char
|
@@ -122,11 +141,11 @@ class EmailValidator < ActiveModel::EachValidator
|
|
122
141
|
def domain_part_pattern(options)
|
123
142
|
return options[:domain].sub(/\./, '\.') if options[:domain].present?
|
124
143
|
return fqdn_pattern if options[:require_fqdn]
|
125
|
-
"
|
144
|
+
"#{domain_part_is_correct_length}(?:#{address_literal}|(?:#{host_label_pattern}\\.)*#{tld_label_pattern})"
|
126
145
|
end
|
127
146
|
|
128
147
|
def fqdn_pattern
|
129
|
-
"(?=.{1,255}$)(?:#{host_label_pattern}\\.)*#{domain_label_pattern}
|
148
|
+
"(?=.{1,255}$)(?:#{host_label_pattern}\\.)*#{domain_label_pattern}"
|
130
149
|
end
|
131
150
|
|
132
151
|
private
|
@@ -146,7 +146,8 @@ RSpec.describe EmailValidator do
|
|
146
146
|
'john.doe@a2.com',
|
147
147
|
'john.doe@2020.a-z.com',
|
148
148
|
'john.doe@2020.a2z.com',
|
149
|
-
'john.doe@2020.12345a6789.com'
|
149
|
+
'john.doe@2020.12345a6789.com',
|
150
|
+
'jonh.doe@163.com'
|
150
151
|
]).flatten.each do |email|
|
151
152
|
context 'when using defaults' do
|
152
153
|
it "'#{email}' should be valid" do
|
@@ -289,20 +290,20 @@ RSpec.describe EmailValidator do
|
|
289
290
|
end
|
290
291
|
|
291
292
|
context 'when in `:strict` mode' do
|
292
|
-
it "'#{email}' should
|
293
|
-
expect(StrictUser.new(:email => email)).
|
293
|
+
it "'#{email}' should be valid" do
|
294
|
+
expect(StrictUser.new(:email => email)).to be_valid
|
294
295
|
end
|
295
296
|
|
296
|
-
it "'#{email}' should
|
297
|
-
expect(described_class).
|
297
|
+
it "'#{email}' should be valid using EmailValidator.valid?" do
|
298
|
+
expect(described_class).to be_valid(email, :mode => :strict)
|
298
299
|
end
|
299
300
|
|
300
|
-
it "'#{email}' should be invalid using EmailValidator.invalid?" do
|
301
|
-
expect(described_class).
|
301
|
+
it "'#{email}' should be not invalid using EmailValidator.invalid?" do
|
302
|
+
expect(described_class).not_to be_invalid(email, :mode => :strict)
|
302
303
|
end
|
303
304
|
|
304
|
-
it "'#{email}' should
|
305
|
-
expect(!!(email.strip =~ described_class.regexp(:mode => :strict))).to be(
|
305
|
+
it "'#{email}' should match the regexp" do
|
306
|
+
expect(!!(email.strip =~ described_class.regexp(:mode => :strict))).to be(true)
|
306
307
|
end
|
307
308
|
end
|
308
309
|
|
@@ -476,6 +477,7 @@ RSpec.describe EmailValidator do
|
|
476
477
|
'host-beginning-with-dot@.example.com',
|
477
478
|
'domain-beginning-with-dash@-example.com',
|
478
479
|
'domain-ending-with-dash@example-.com',
|
480
|
+
'domain-contains-double-dash@foo--example.com',
|
479
481
|
'the-local-part-is-invalid-if-it-is-longer-than-sixty-four-characters@sld.dev',
|
480
482
|
"domain-too-long@t#{".#{'o' * 63}" * 5}.long",
|
481
483
|
"user@example.com<script>alert('hello')</script>"
|
@@ -703,7 +705,8 @@ RSpec.describe EmailValidator do
|
|
703
705
|
]}).concat([
|
704
706
|
'user..-with-double-dots@example.com',
|
705
707
|
'.user-beginning-with-dot@example.com',
|
706
|
-
'user-ending-with-dot.@example.com'
|
708
|
+
'user-ending-with-dot.@example.com',
|
709
|
+
'fully-numeric-tld@example.123'
|
707
710
|
]).flatten.each do |email|
|
708
711
|
context 'when using defaults' do
|
709
712
|
it "#{email.strip} in a model should be valid" do
|
@@ -781,23 +784,24 @@ RSpec.describe EmailValidator do
|
|
781
784
|
end
|
782
785
|
end
|
783
786
|
|
787
|
+
# Strict mode enables `require_fqdn` anyway
|
784
788
|
context 'when in `:strict` mode' do
|
785
789
|
let(:opts) { { :require_fqdn => false, :mode => :strict } }
|
786
790
|
|
787
|
-
it 'is valid' do
|
788
|
-
expect(NonFqdnStrictUser.new(:email => email)).
|
791
|
+
it 'is not valid' do
|
792
|
+
expect(NonFqdnStrictUser.new(:email => email)).not_to be_valid
|
789
793
|
end
|
790
794
|
|
791
|
-
it 'is valid using EmailValidator.valid?' do
|
792
|
-
expect(described_class).
|
795
|
+
it 'is not valid using EmailValidator.valid?' do
|
796
|
+
expect(described_class).not_to be_valid(email, opts)
|
793
797
|
end
|
794
798
|
|
795
|
-
it 'is
|
796
|
-
expect(described_class).
|
799
|
+
it 'is invalid using EmailValidator.invalid?' do
|
800
|
+
expect(described_class).to be_invalid(email, opts)
|
797
801
|
end
|
798
802
|
|
799
803
|
it 'matches the regexp' do
|
800
|
-
expect(!!(email =~ described_class.regexp(opts))).to be(
|
804
|
+
expect(!!(email =~ described_class.regexp(opts))).to be(false)
|
801
805
|
end
|
802
806
|
end
|
803
807
|
|
@@ -1012,4 +1016,36 @@ RSpec.describe EmailValidator do
|
|
1012
1016
|
end
|
1013
1017
|
end
|
1014
1018
|
end
|
1019
|
+
|
1020
|
+
context 'with regexp' do
|
1021
|
+
it 'returns a regexp when asked' do
|
1022
|
+
expect(described_class.regexp).to be_a(Regexp)
|
1023
|
+
end
|
1024
|
+
|
1025
|
+
it 'returns a strict regexp when asked' do
|
1026
|
+
expect(described_class.regexp(:mode => :strict)).to be_a(Regexp)
|
1027
|
+
end
|
1028
|
+
|
1029
|
+
it 'returns a RFC regexp when asked' do
|
1030
|
+
expect(described_class.regexp(:mode => :rfc)).to be_a(Regexp)
|
1031
|
+
end
|
1032
|
+
|
1033
|
+
it 'has different regexp for strict and loose' do
|
1034
|
+
expect(described_class.regexp(:mode => :strict)).not_to eq(described_class.regexp(:mode => :loose))
|
1035
|
+
end
|
1036
|
+
|
1037
|
+
it 'has different regexp for RFC and loose' do
|
1038
|
+
expect(described_class.regexp(:mode => :rfc)).not_to eq(described_class.regexp(:mode => :loose))
|
1039
|
+
end
|
1040
|
+
|
1041
|
+
it 'has different regexp for RFC and strict' do
|
1042
|
+
expect(described_class.regexp(:mode => :rfc)).not_to eq(described_class.regexp(:mode => :strict))
|
1043
|
+
end
|
1044
|
+
end
|
1045
|
+
|
1046
|
+
context 'with invalid `:mode`' do
|
1047
|
+
it 'raises an error' do
|
1048
|
+
expect { described_class.regexp(:mode => :invalid) }.to raise_error(EmailValidator::Error)
|
1049
|
+
end
|
1050
|
+
end
|
1015
1051
|
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.
|
4
|
+
version: 2.2.3
|
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:
|
12
|
+
date: 2021-04-05 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activemodel
|