2022-01-11 09:37:07 -08:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
2022-10-13 12:23:12 -07:00
|
|
|
require "tldv"
|
|
|
|
|
2022-01-11 09:37:07 -08:00
|
|
|
class TypoedEmailValidator < ActiveModel::EachValidator
|
|
|
|
# this array contains "forbidden" email address endings
|
|
|
|
INVALID_ENDINGS = [
|
|
|
|
# with @:
|
|
|
|
*%w[
|
2023-01-29 21:01:01 -08:00
|
|
|
aoo.com
|
2022-01-11 09:37:07 -08:00
|
|
|
fmail.com
|
2022-06-21 10:33:51 -07:00
|
|
|
gail.com
|
|
|
|
gamil.com
|
2022-01-11 09:37:07 -08:00
|
|
|
gemail.com
|
2022-08-25 11:28:29 -07:00
|
|
|
gmaik.com
|
2022-06-21 10:33:51 -07:00
|
|
|
gmail.cm
|
2022-01-11 09:37:07 -08:00
|
|
|
gmail.co
|
2022-10-11 11:43:01 -07:00
|
|
|
gmail.co.uk
|
2023-01-06 01:26:32 -08:00
|
|
|
gmail.om
|
2022-01-11 09:37:07 -08:00
|
|
|
gmaile.com
|
|
|
|
gmaill.com
|
2022-01-17 10:22:34 -08:00
|
|
|
gmali.com
|
2023-01-29 10:19:35 -08:00
|
|
|
gmaul.com
|
2022-08-14 11:49:51 -07:00
|
|
|
gnail.com
|
2022-06-21 10:33:51 -07:00
|
|
|
hotamil.com
|
2022-07-24 12:43:28 -07:00
|
|
|
hotmai.com
|
2022-03-03 21:13:38 -08:00
|
|
|
hotmaill.com
|
2022-06-21 10:33:51 -07:00
|
|
|
iclooud.com
|
2022-04-10 00:55:05 -07:00
|
|
|
iclould.com
|
2022-01-11 09:37:07 -08:00
|
|
|
icluod.com
|
2022-10-02 13:13:34 -07:00
|
|
|
protonail.com
|
2022-08-14 11:49:51 -07:00
|
|
|
xn--gmail-xk1c.com
|
2022-07-24 12:43:28 -07:00
|
|
|
yahooo.com
|
2022-08-14 11:49:51 -07:00
|
|
|
☺gmail.com
|
2022-01-11 09:37:07 -08:00
|
|
|
].map { "@#{_1}" }
|
|
|
|
].freeze
|
|
|
|
|
|
|
|
def validate_each(record, attribute, value)
|
|
|
|
return if valid?(value)
|
|
|
|
|
2022-03-03 21:13:38 -08:00
|
|
|
record.errors.add(attribute, :typo, message: "contains a typo")
|
2022-01-11 09:37:07 -08:00
|
|
|
end
|
|
|
|
|
|
|
|
private
|
|
|
|
|
|
|
|
def valid?(value)
|
|
|
|
# needs an @
|
2022-01-17 10:23:39 -08:00
|
|
|
return false unless value.include?("@")
|
2022-01-11 09:37:07 -08:00
|
|
|
|
|
|
|
# part after the @ needs to have at least one period
|
2022-10-13 12:23:12 -07:00
|
|
|
_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)
|
2022-01-11 09:37:07 -08:00
|
|
|
|
|
|
|
# finally, common typos
|
|
|
|
return false if INVALID_ENDINGS.any? { value.end_with?(_1) }
|
|
|
|
|
|
|
|
true
|
|
|
|
end
|
|
|
|
end
|