diff --git a/README.md b/README.md index 1a8920c..7e9b6a8 100644 --- a/README.md +++ b/README.md @@ -53,6 +53,11 @@ To validate that the domain is not a disposable email: validates :email, 'valid_email_2/email': { disposable: true } ``` +To validate that the domain is not a disposable email or a disposable email but whitelisted (under vendor/whitelist.yml): +```ruby +validates :email, 'valid_email_2/email': { disposable_with_whitelist: true } +``` + To validate that the domain is not blacklisted (under vendor/blacklist.yml): ```ruby validates :email, 'valid_email_2/email': { blacklist: true } diff --git a/lib/valid_email2.rb b/lib/valid_email2.rb index ebfcfc1..dbc1063 100644 --- a/lib/valid_email2.rb +++ b/lib/valid_email2.rb @@ -9,4 +9,9 @@ def self.blacklist blacklist_file = "vendor/blacklist.yml" @@blacklist ||= File.exists?(blacklist_file) ? YAML.load_file(File.expand_path(blacklist_file)) : [] end + + def self.whitelist + whitelist_file = "vendor/whitelist.yml" + @@whitelist ||= File.exists?(whitelist_file) ? YAML.load_file(File.expand_path(whitelist_file)) : [] + end end diff --git a/lib/valid_email2/address.rb b/lib/valid_email2/address.rb index a02e500..425adb9 100644 --- a/lib/valid_email2/address.rb +++ b/lib/valid_email2/address.rb @@ -48,6 +48,10 @@ def disposable? valid? && domain_is_in?(ValidEmail2.disposable_emails) end + def whitelisted? + domain_is_in?(ValidEmail2.whitelist) + end + def blacklisted? valid? && domain_is_in?(ValidEmail2.blacklist) end diff --git a/lib/valid_email2/email_validator.rb b/lib/valid_email2/email_validator.rb index ebba1c5..3eea2d6 100644 --- a/lib/valid_email2/email_validator.rb +++ b/lib/valid_email2/email_validator.rb @@ -24,6 +24,10 @@ def validate_each(record, attribute, value) error(record, attribute) && return if address.disposable? end + if options[:disposable_with_whitelist] + error(record, attribute) && return if address.disposable? && !address.whitelisted? + end + if options[:blacklist] error(record, attribute) && return if address.blacklisted? end diff --git a/spec/valid_email2_spec.rb b/spec/valid_email2_spec.rb index 98cd9c8..e411f0b 100644 --- a/spec/valid_email2_spec.rb +++ b/spec/valid_email2_spec.rb @@ -16,6 +16,10 @@ class TestUserDisallowDisposable < TestModel validates :email, 'valid_email_2/email': { disposable: true } end +class TestUserDisallowDisposableWithWhitelist < TestModel + validates :email, 'valid_email_2/email': { disposable_with_whitelist: true } +end + class TestUserDisallowBlacklisted < TestModel validates :email, 'valid_email_2/email': { blacklist: true } end @@ -82,6 +86,22 @@ class TestUserDisallowBlacklisted < TestModel user = TestUserDisallowDisposable.new(email: "foo@example.com") expect(user.valid?).to be_truthy end + + describe "with whitelisted emails" do + it "should be invalid when the domain is in the list of disposable and there is no whitelist" do + user = TestUserDisallowDisposableWithWhitelist.new(email: "foo@#{ValidEmail2.disposable_emails.first}") + expect(user.valid?).to be_falsey + end + + it "should be valid when the domain is in the list of disposable but it is in the whitelist" do + whitelist_domain = ValidEmail2.disposable_emails.first + whitelist_file_path = "vendor/whitelist.yml" + File.open(whitelist_file_path, "w") {|f| f.write whitelist_domain.to_yaml } + user = TestUserDisallowDisposableWithWhitelist.new(email: "foo@#{whitelist_domain}") + expect(user.valid?).to be_falsey + File.delete(whitelist_file_path) + end + end end describe "blacklisted emails" do