Skip to content

Commit a4da1ce

Browse files
phoetcm-dyoshikawa
andauthored
Nested domains (#278)
* fix domain checking logic in address.rb * feat: Add support for domain hierarchy depth in disposable domain checking * fix: Adjust domain hierarchy depth check to start from 3 * fix: Update domain hierarchy max depth to 3 and adjust related tests * fix: Correct domain hierarchy token handling in address.rb * formatting through rubocop * feat: detect subdomains 6 levels deep --------- Co-authored-by: cm-dyoshikawa <[email protected]>
1 parent ed4a5c7 commit a4da1ce

File tree

5 files changed

+339
-8
lines changed

5 files changed

+339
-8
lines changed

.rubocop.yml

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
inherit_from: .rubocop_todo.yml
2+
3+
# The behavior of RuboCop can be controlled via the .rubocop.yml
4+
# configuration file. It makes it possible to enable/disable
5+
# certain cops (checks) and to alter their behavior if they accept
6+
# any parameters. The file can be placed either in your home
7+
# directory or in some project directory.
8+
#
9+
# RuboCop will start looking for the configuration file in the directory
10+
# where the inspected file is and continue its way up to the root directory.
11+
#
12+
# See https://docs.rubocop.org/rubocop/configuration
13+
14+
Style/StringLiterals:
15+
EnforcedStyle: double_quotes
16+
Gemspec/OrderedDependencies:
17+
Enabled: no

.rubocop_todo.yml

+263
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,263 @@
1+
# This configuration was generated by
2+
# `rubocop --auto-gen-config`
3+
# on 2025-02-14 12:05:00 UTC using RuboCop version 1.71.2.
4+
# The point is for the user to remove these configuration records
5+
# one by one as the offenses are removed from the code base.
6+
# Note that changes in the inspected code, or installation of new
7+
# versions of RuboCop, may require this file to be generated again.
8+
9+
# Offense count: 1
10+
# This cop supports safe autocorrection (--autocorrect).
11+
Layout/EmptyLineAfterGuardClause:
12+
Exclude:
13+
- 'lib/valid_email2/email_validator.rb'
14+
15+
# Offense count: 2
16+
# This cop supports safe autocorrection (--autocorrect).
17+
# Configuration parameters: AllowForAlignment, AllowBeforeTrailingComments, ForceEqualSignAlignment.
18+
Layout/ExtraSpacing:
19+
Exclude:
20+
- 'lib/valid_email2.rb'
21+
22+
# Offense count: 1
23+
# This cop supports safe autocorrection (--autocorrect).
24+
Layout/SpaceAfterComma:
25+
Exclude:
26+
- 'spec/spec_helper.rb'
27+
28+
# Offense count: 2
29+
# This cop supports safe autocorrection (--autocorrect).
30+
# Configuration parameters: AllowForAlignment, EnforcedStyleForExponentOperator, EnforcedStyleForRationalLiterals.
31+
# SupportedStylesForExponentOperator: space, no_space
32+
# SupportedStylesForRationalLiterals: space, no_space
33+
Layout/SpaceAroundOperators:
34+
Exclude:
35+
- 'lib/valid_email2.rb'
36+
37+
# Offense count: 1
38+
# This cop supports safe autocorrection (--autocorrect).
39+
Lint/ScriptPermission:
40+
Exclude:
41+
- 'pull_mailchecker_emails.rb'
42+
43+
# Offense count: 1
44+
# This cop supports safe autocorrection (--autocorrect).
45+
# Configuration parameters: AutoCorrect, IgnoreEmptyBlocks, AllowUnusedKeywordArguments.
46+
Lint/UnusedBlockArgument:
47+
Exclude:
48+
- 'lib/valid_email2/dns.rb'
49+
50+
# Offense count: 2
51+
# Configuration parameters: AllowedMethods, AllowedPatterns, CountRepeatedAttributes.
52+
Metrics/AbcSize:
53+
Max: 63
54+
55+
# Offense count: 11
56+
# Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns.
57+
# AllowedMethods: refine
58+
Metrics/BlockLength:
59+
Max: 348
60+
61+
# Offense count: 1
62+
# Configuration parameters: CountComments, CountAsOne.
63+
Metrics/ClassLength:
64+
Max: 105
65+
66+
# Offense count: 1
67+
# Configuration parameters: AllowedMethods, AllowedPatterns.
68+
Metrics/CyclomaticComplexity:
69+
Max: 44
70+
71+
# Offense count: 2
72+
# Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns.
73+
Metrics/MethodLength:
74+
Max: 32
75+
76+
# Offense count: 1
77+
# Configuration parameters: AllowedMethods, AllowedPatterns.
78+
Metrics/PerceivedComplexity:
79+
Max: 44
80+
81+
# Offense count: 2
82+
# This cop supports safe autocorrection (--autocorrect).
83+
# Configuration parameters: EnforcedStyle, ProceduralMethods, FunctionalMethods, AllowedMethods, AllowedPatterns, AllowBracesOnProceduralOneLiners, BracesRequiredMethods.
84+
# SupportedStyles: line_count_based, semantic, braces_for_chaining, always_braces
85+
# ProceduralMethods: benchmark, bm, bmbm, create, each_with_object, measure, new, realtime, tap, with_object
86+
# FunctionalMethods: let, let!, subject, watch
87+
# AllowedMethods: lambda, proc, it
88+
Style/BlockDelimiters:
89+
Exclude:
90+
- 'lib/valid_email2/address.rb'
91+
92+
# Offense count: 1
93+
# This cop supports safe autocorrection (--autocorrect).
94+
# Configuration parameters: EnforcedStyle, SingleLineConditionsOnly, IncludeTernaryExpressions.
95+
# SupportedStyles: assign_to_condition, assign_inside_condition
96+
Style/ConditionalAssignment:
97+
Exclude:
98+
- 'lib/valid_email2/email_validator.rb'
99+
100+
# Offense count: 4
101+
# Configuration parameters: AllowedConstants.
102+
Style/Documentation:
103+
Exclude:
104+
- 'spec/**/*'
105+
- 'test/**/*'
106+
- 'lib/valid_email2.rb'
107+
- 'lib/valid_email2/address.rb'
108+
- 'lib/valid_email2/dns.rb'
109+
- 'lib/valid_email2/email_validator.rb'
110+
111+
# Offense count: 1
112+
# This cop supports safe autocorrection (--autocorrect).
113+
Style/ExpandPathArguments:
114+
Exclude:
115+
- 'spec/spec_helper.rb'
116+
117+
# Offense count: 10
118+
# This cop supports unsafe autocorrection (--autocorrect-all).
119+
# Configuration parameters: EnforcedStyle.
120+
# SupportedStyles: always, always_true, never
121+
Style/FrozenStringLiteralComment:
122+
Exclude:
123+
- '**/*.arb'
124+
- 'Gemfile'
125+
- 'Rakefile'
126+
- 'gemfiles/activemodel6.gemfile'
127+
- 'gemfiles/activemodel7.gemfile'
128+
- 'gemfiles/activemodel8.gemfile'
129+
- 'lib/valid_email2/dns.rb'
130+
- 'lib/valid_email2/email_validator.rb'
131+
- 'pull_mailchecker_emails.rb'
132+
- 'spec/spec_helper.rb'
133+
- 'valid_email2.gemspec'
134+
135+
# Offense count: 2
136+
# This cop supports safe autocorrection (--autocorrect).
137+
# Configuration parameters: MinBodyLength, AllowConsecutiveConditionals.
138+
Style/GuardClause:
139+
Exclude:
140+
- 'lib/valid_email2/dns.rb'
141+
- 'lib/valid_email2/email_validator.rb'
142+
143+
# Offense count: 1
144+
# This cop supports unsafe autocorrection (--autocorrect-all).
145+
# Configuration parameters: AllowedReceivers.
146+
# AllowedReceivers: Thread.current
147+
Style/HashEachMethods:
148+
Exclude:
149+
- 'lib/valid_email2/dns.rb'
150+
151+
# Offense count: 2
152+
# This cop supports safe autocorrection (--autocorrect).
153+
# Configuration parameters: EnforcedStyle, EnforcedShorthandSyntax, UseHashRocketsWithSymbolValues, PreferHashRocketsForNonAlnumEndingSymbols.
154+
# SupportedStyles: ruby19, hash_rockets, no_mixed_keys, ruby19_no_mixed_keys
155+
# SupportedShorthandSyntax: always, never, either, consistent, either_consistent
156+
Style/HashSyntax:
157+
Exclude:
158+
- 'Rakefile'
159+
160+
# Offense count: 1
161+
# This cop supports unsafe autocorrection (--autocorrect-all).
162+
# Configuration parameters: EnforcedStyle.
163+
# SupportedStyles: literals, strict
164+
Style/MutableConstant:
165+
Exclude:
166+
- 'lib/valid_email2/dns.rb'
167+
168+
# Offense count: 1
169+
# This cop supports safe autocorrection (--autocorrect).
170+
# Configuration parameters: Strict, AllowedNumbers, AllowedPatterns.
171+
Style/NumericLiterals:
172+
MinDigits: 6
173+
174+
# Offense count: 2
175+
# This cop supports unsafe autocorrection (--autocorrect-all).
176+
# Configuration parameters: EnforcedStyle, AllowedMethods, AllowedPatterns.
177+
# SupportedStyles: predicate, comparison
178+
Style/NumericPredicate:
179+
Exclude:
180+
- 'spec/**/*'
181+
- 'lib/valid_email2/address.rb'
182+
183+
# Offense count: 1
184+
# This cop supports safe autocorrection (--autocorrect).
185+
Style/Proc:
186+
Exclude:
187+
- 'spec/valid_email2_spec.rb'
188+
189+
# Offense count: 1
190+
# This cop supports safe autocorrection (--autocorrect).
191+
# Configuration parameters: EnforcedStyle, AllowInnerSlashes.
192+
# SupportedStyles: slashes, percent_r, mixed
193+
Style/RegexpLiteral:
194+
Exclude:
195+
- 'lib/valid_email2/address.rb'
196+
197+
# Offense count: 1
198+
# This cop supports unsafe autocorrection (--autocorrect-all).
199+
Style/SlicingWithRange:
200+
Exclude:
201+
- 'lib/valid_email2/address.rb'
202+
203+
# Offense count: 9
204+
# This cop supports safe autocorrection (--autocorrect).
205+
# Configuration parameters: AllowModifier.
206+
Style/SoleNestedConditional:
207+
Exclude:
208+
- 'lib/valid_email2/email_validator.rb'
209+
210+
# Offense count: 2
211+
# This cop supports unsafe autocorrection (--autocorrect-all).
212+
# Configuration parameters: RequireEnglish, EnforcedStyle.
213+
# SupportedStyles: use_perl_names, use_english_names, use_builtin_english_names
214+
Style/SpecialGlobalVars:
215+
Exclude:
216+
- 'spec/spec_helper.rb'
217+
- 'valid_email2.gemspec'
218+
219+
# Offense count: 35
220+
# This cop supports safe autocorrection (--autocorrect).
221+
# Configuration parameters: EnforcedStyle, ConsistentQuotesInMultiline.
222+
# SupportedStyles: single_quotes, double_quotes
223+
Style/StringLiterals:
224+
Exclude:
225+
- 'Gemfile'
226+
- 'gemfiles/activemodel6.gemfile'
227+
- 'gemfiles/activemodel7.gemfile'
228+
- 'gemfiles/activemodel8.gemfile'
229+
- 'lib/valid_email2.rb'
230+
- 'lib/valid_email2/address.rb'
231+
- 'lib/valid_email2/email_validator.rb'
232+
- 'spec/spec_helper.rb'
233+
- 'spec/valid_email2_spec.rb'
234+
- 'valid_email2.gemspec'
235+
236+
# Offense count: 3
237+
# This cop supports safe autocorrection (--autocorrect).
238+
# Configuration parameters: ExactNameMatch, AllowPredicates, AllowDSLWriters, IgnoreClassMethods, AllowedMethods.
239+
# AllowedMethods: to_ary, to_a, to_c, to_enum, to_h, to_hash, to_i, to_int, to_io, to_open, to_path, to_proc, to_r, to_regexp, to_str, to_s, to_sym
240+
Style/TrivialAccessors:
241+
Exclude:
242+
- 'lib/valid_email2/address.rb'
243+
244+
# Offense count: 1
245+
# This cop supports safe autocorrection (--autocorrect).
246+
# Configuration parameters: EnforcedStyle, MinSize, WordRegex.
247+
# SupportedStyles: percent, brackets
248+
Style/WordArray:
249+
Exclude:
250+
- 'spec/valid_email2_spec.rb'
251+
252+
# Offense count: 1
253+
# This cop supports unsafe autocorrection (--autocorrect-all).
254+
Style/ZeroLengthPredicate:
255+
Exclude:
256+
- 'lib/valid_email2/address.rb'
257+
258+
# Offense count: 17
259+
# This cop supports safe autocorrection (--autocorrect).
260+
# Configuration parameters: AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, AllowedPatterns, SplitStrings.
261+
# URISchemes: http, https
262+
Layout/LineLength:
263+
Max: 186

lib/valid_email2/address.rb

+9-3
Original file line numberDiff line numberDiff line change
@@ -117,10 +117,16 @@ def domain_is_in?(domain_list)
117117
address_domain = address.domain.downcase
118118
return true if domain_list.include?(address_domain)
119119

120-
i = address_domain.index('.')
121-
return false unless i
120+
tokens = address_domain.split('.')
121+
return false if tokens.length < 3
122122

123-
domain_list.include?(address_domain[(i + 1)..-1])
123+
# check only 6 elements deep
124+
2.upto(6).each do |depth|
125+
limited_sub_domain_part = tokens.reverse.first(depth).reverse.join('.')
126+
return true if domain_list.include?(limited_sub_domain_part)
127+
end
128+
129+
false
124130
end
125131

126132
def mx_server_is_in?(domain_list)

spec/address_spec.rb

+46-1
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,52 @@
5555

5656
it "is valid if it contains special scandinavian characters" do
5757
address = described_class.new("jø[email protected]")
58-
expect(address.valid?).to eq true
58+
expect(address.valid?).to be_truthy
59+
end
60+
end
61+
end
62+
63+
describe "#disposable_domain?" do
64+
context "when the disposable domain does not have subdomains" do
65+
let(:disposable_domain) { ValidEmail2.disposable_emails.select { |domain| domain.count(".") == 1 }.sample }
66+
67+
it "is true if the domain is in the disposable_emails list" do
68+
address = described_class.new("foo@#{disposable_domain}")
69+
expect(address.disposable_domain?).to be_truthy
70+
end
71+
72+
it "is true if the domain is a subdomain of a disposable domain" do
73+
address = described_class.new("foo@sub.#{disposable_domain}")
74+
expect(address.disposable_domain?).to be_truthy
75+
end
76+
77+
it "is true if the domain is a deeply nested subdomain of a disposable domain" do
78+
address = described_class.new("[email protected].#{disposable_domain}")
79+
expect(address.disposable_domain?).to be_truthy
80+
end
81+
82+
it "is false if the domain is not in the disposable_emails list" do
83+
address = described_class.new("[email protected]")
84+
expect(address.disposable_domain?).to eq false
85+
end
86+
end
87+
88+
context "when the disposable domain has subdomains" do
89+
let(:disposable_domain) { ValidEmail2.disposable_emails.select { |domain| domain.count(".") > 1 }.sample }
90+
91+
it "is true if the domain is in the disposable_emails list" do
92+
address = described_class.new("foo@#{disposable_domain}")
93+
expect(address.disposable_domain?).to be_truthy
94+
end
95+
96+
it "is true if the domain is a subdomain of a disposable domain" do
97+
address = described_class.new("foo@sub.#{disposable_domain}")
98+
expect(address.disposable_domain?).to be_truthy
99+
end
100+
101+
it "is true if the domain is a deeply nested subdomain of a disposable domain" do
102+
address = described_class.new("[email protected].#{disposable_domain}")
103+
expect(address.disposable_domain?).to be_truthy
59104
end
60105
end
61106
end

valid_email2.gemspec

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
# coding: utf-8
2-
lib = File.expand_path('../lib', __FILE__)
1+
lib = File.expand_path('lib', __dir__)
32
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
43
require "valid_email2/version"
54

@@ -8,8 +7,8 @@ Gem::Specification.new do |spec|
87
spec.version = ValidEmail2::VERSION
98
spec.authors = ["Micke Lisinge"]
109
spec.email = ["[email protected]"]
11-
spec.description = %q{ActiveModel validation for email. Including MX lookup and disposable email deny list}
12-
spec.summary = %q{ActiveModel validation for email. Including MX lookup and disposable email deny list}
10+
spec.description = 'ActiveModel validation for email. Including MX lookup and disposable email deny list'
11+
spec.summary = 'ActiveModel validation for email. Including MX lookup and disposable email deny list'
1312
spec.homepage = "https://github.com/micke/valid_email2"
1413
spec.license = "MIT"
1514

@@ -27,6 +26,7 @@ Gem::Specification.new do |spec|
2726
spec.add_development_dependency "rspec-benchmark", "~> 0.6"
2827
spec.add_development_dependency "net-smtp"
2928
spec.add_development_dependency "debug"
29+
spec.add_development_dependency "rubocop"
3030
spec.add_runtime_dependency "mail", "~> 2.5"
3131
spec.add_runtime_dependency "activemodel", ">= 6.0"
3232
end

0 commit comments

Comments
 (0)