Skip to content

Commit

Permalink
Adds ability to validate by subdomain
Browse files Browse the repository at this point in the history
  • Loading branch information
ritec authored and hallelujah committed Dec 19, 2023
1 parent 753e3ce commit 4e667c4
Show file tree
Hide file tree
Showing 6 changed files with 69 additions and 0 deletions.
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,16 @@ validates :email,
}
```

You can detect partial match on disposable accounts, good for services that use subdomains.

```ruby
validates :email,
email: {
ban_partial_disposable_email: true,
message: I18n.t('validations.errors.models.user.invalid_email')
}
```

If you don't want the MX validator stuff, just require the right file

```ruby
Expand Down
1 change: 1 addition & 0 deletions lib/valid_email/all.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@
require 'valid_email/mx_validator'
require 'valid_email/mx_with_fallback_validator'
require 'valid_email/ban_disposable_email_validator'
require 'valid_email/ban_partial_disposable_email_validator'
require 'valid_email/domain_validator'
23 changes: 23 additions & 0 deletions lib/valid_email/ban_partial_disposable_email_validator.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
require 'active_model'
require 'active_model/validations'
require 'valid_email/validate_email'
class BanPartialDisposableEmailValidator < ActiveModel::EachValidator
# A list of disposable email domains
def self.config=(options)
@@config = options
end

# Required to use config outside
def self.config
@@config = [] unless defined? @@config

@@config
end

def validate_each(record, attribute, value)
r = ValidateEmail.ban_partial_disposable_email?(value)
record.errors.add attribute, (options[:message] || I18n.t(:invalid, :scope => "valid_email.validations.email")) unless r

r
end
end
5 changes: 5 additions & 0 deletions lib/valid_email/email_validator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@ def validate_each(record,attribute,value)
require 'valid_email/ban_disposable_email_validator'
r = BanDisposableEmailValidator.new(:attributes => attributes, message: options[:message]).validate(record)
end
# Check if part of domain is in disposable list
if r && options[:ban_partial_disposable_email]
require 'valid_email/ban_partial_disposable_email_validator'
r = BanPartialDisposableEmailValidator.new(:attributes => attributes, message: options[:message]).validate(record)
end
unless r
msg = (options[:message] || I18n.t(:invalid, :scope => "valid_email.validations.email"))
record.errors.add attribute, message: I18n.interpolate(msg, value: value)
Expand Down
10 changes: 10 additions & 0 deletions lib/valid_email/validate_email.rb
Original file line number Diff line number Diff line change
Expand Up @@ -128,5 +128,15 @@ def ban_disposable_email?(value)
rescue Mail::Field::ParseError
false
end

def ban_partial_disposable_email?(value)
m = Mail::Address.new(value)
m.domain && !BanDisposableEmailValidator.config.any? do |bde|
next if bde == nil
m.domain.end_with?(bde)
end
rescue Mail::Field::ParseError
false
end
end
end
20 changes: 20 additions & 0 deletions spec/email_validator_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ def self.model_name
validates :email, :email => {:ban_disposable_email => true}
end

person_class_partial_disposable_email = Class.new(email_class) do
validates :email, :email => {:ban_partial_disposable_email => true}
end

person_class_nil_allowed = Class.new(email_class) do
validates :email, :email => {:allow_nil => true}
end
Expand Down Expand Up @@ -248,6 +252,22 @@ def self.model_name
end
end

describe "validating email against partial disposable service match" do
subject { person_class_partial_disposable_email.new }

it "passes when email from trusted email services" do
subject.email = 'john@test.mail.ru'
expect(subject.valid?).to be_truthy
expect(subject.errors[:email]).to be_empty
end

it "fails when disposable email services partially matches email domain" do
subject.email = 'john@sub.grr.la'
expect(subject.valid?).to be_falsey
expect(subject.errors[:email]).to eq errors
end
end

describe "validating domain" do
subject { person_class_domain.new }

Expand Down

0 comments on commit 4e667c4

Please sign in to comment.