diff --git a/Gemfile b/Gemfile index 880832ce..b63d1937 100644 --- a/Gemfile +++ b/Gemfile @@ -65,6 +65,9 @@ gem "redis" gem "fake_email_validator" +# TLD validation +gem "tldv", "~> 0.1.0" + gem "jwt", "~> 2.5" group :development do diff --git a/Gemfile.lock b/Gemfile.lock index d18ddfac..43bd3c94 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -518,6 +518,9 @@ GEM thread_safe (0.3.6) tilt (2.0.11) timeout (0.3.0) + tldv (0.1.0) + tldv-data (~> 1.0) + tldv-data (1.0.2022101300) turbo-rails (1.1.1) actionpack (>= 6.0.0) activejob (>= 6.0.0) @@ -641,6 +644,7 @@ DEPENDENCIES simplecov-cobertura simplecov-json spring (~> 4.1) + tldv (~> 0.1.0) turbo-rails twitter twitter-text diff --git a/app/validators/typoed_email_validator.rb b/app/validators/typoed_email_validator.rb index 279c4950..8131bb48 100644 --- a/app/validators/typoed_email_validator.rb +++ b/app/validators/typoed_email_validator.rb @@ -1,15 +1,10 @@ # frozen_string_literal: true +require "tldv" + class TypoedEmailValidator < ActiveModel::EachValidator # this array contains "forbidden" email address endings INVALID_ENDINGS = [ - # without @: - ".carrd", - ".con", - ".coom", - ".cmo", - ".mail", - # with @: *%w[ fmail.com @@ -50,7 +45,13 @@ class TypoedEmailValidator < ActiveModel::EachValidator return false unless value.include?("@") # part after the @ needs to have at least one period - return false if value.split("@", 2).last.count(".").zero? + _prefix, domain = value.split("@", 2) + domain_parts = domain.split(".") + return false if domain_parts.length == 1 + + # check if the TLD is valid + tld = domain_parts.last + return false unless TLDv.valid?(tld) # finally, common typos return false if INVALID_ENDINGS.any? { value.end_with?(_1) } diff --git a/spec/controllers/user/registration_controller_spec.rb b/spec/controllers/user/registration_controller_spec.rb index 025e3edd..c31f5670 100644 --- a/spec/controllers/user/registration_controller_spec.rb +++ b/spec/controllers/user/registration_controller_spec.rb @@ -30,7 +30,7 @@ describe User::RegistrationsController, type: :controller do { user: { screen_name: "dio", - email: "the-world-21@somewhere.everywhere", + email: "the-world-21@somewhere.everywhere.now", password: "AReallySecurePassword456!", password_confirmation: "AReallySecurePassword456!" } @@ -85,7 +85,7 @@ describe User::RegistrationsController, type: :controller do { user: { screen_name: "Dio Brando", - email: "the-world-21@somewhere.everywhere", + email: "the-world-21@somewhere.everywhere.now", password: "AReallySecurePassword456!", password_confirmation: "AReallySecurePassword456!" } @@ -102,7 +102,7 @@ describe User::RegistrationsController, type: :controller do { user: { screen_name: "moderator", - email: "the-world-21@somewhere.everywhere", + email: "the-world-21@somewhere.everywhere.now", password: "AReallySecurePassword456!", password_confirmation: "AReallySecurePassword456!" } diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 5d12058f..d2714b22 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -64,6 +64,7 @@ RSpec.describe User, type: :model do include_examples "valid email", "fritz.fantom@protonmail.com" include_examples "valid email", "fritz.fantom@example.email" include_examples "valid email", "fritz.fantom@enterprise.k8s.420stripes.k8s.needs.more.k8s.jira.atlassian.k8s.eu-central-1.s3.amazonaws.com" + include_examples "valid email", "fritz.fantom@emacs.horse" include_examples "invalid email", "@jack" # examples from the real world: