2024-02-09 09:56:03 +01:00
|
|
|
class StrictEmailValidator < ActiveModel::EachValidator
|
|
|
|
# default devise email is : /\A[^@\s]+@[^@\s]+\z/
|
|
|
|
# saying that it's quite permissive
|
|
|
|
# but we want more, we want to ensure it's a domain with extension
|
|
|
|
# so we append \.[A-Za-z]{2,}
|
2024-03-12 11:12:30 +01:00
|
|
|
TRUEMAIL_REGEX_DOMAIN = /[\p{L}0-9]+([-.]{1}[\p{L}\p{N}\p{Pd}]*[\p{L}\p{N}]+)*\.\p{L}{2,63}/i.freeze
|
|
|
|
TRUEMAIL_REGEX_EMAIL_PATTERN = %r{(?=\A.{6,255}\z)(\A([\p{L}0-9]+[\w\p{L}.+!~,'&%#*^`{}|\-/?=$]*)@(#{TRUEMAIL_REGEX_DOMAIN})\z)}.freeze
|
|
|
|
|
|
|
|
REGEXP = TRUEMAIL_REGEX_EMAIL_PATTERN
|
|
|
|
|
2024-02-15 09:45:20 +01:00
|
|
|
DATE_SINCE_STRICT_EMAIL_VALIDATION = Date.parse(ENV.fetch('STRICT_EMAIL_VALIDATION_STARTS_ON')) rescue 0
|
2024-02-09 09:56:03 +01:00
|
|
|
|
|
|
|
def validate_each(record, attribute, value)
|
2024-02-12 12:39:43 +01:00
|
|
|
if value.present? && !regexp_for(record).match?(value)
|
|
|
|
record.errors.add(attribute, :invalid_email_format)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def regexp_for(record)
|
2024-02-15 09:45:20 +01:00
|
|
|
if StrictEmailValidator.eligible_to_new_validation?(record)
|
2024-02-12 12:39:43 +01:00
|
|
|
REGEXP
|
|
|
|
else
|
|
|
|
Devise.email_regexp
|
2024-02-09 09:56:03 +01:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2024-02-15 09:45:20 +01:00
|
|
|
def self.eligible_to_new_validation?(record)
|
2024-02-09 09:56:03 +01:00
|
|
|
return false if !strict_validation_enabled?
|
2024-02-15 09:45:20 +01:00
|
|
|
return false if (record.created_at || Time.zone.now) < DATE_SINCE_STRICT_EMAIL_VALIDATION
|
2024-02-09 09:56:03 +01:00
|
|
|
true
|
|
|
|
end
|
|
|
|
|
|
|
|
def self.strict_validation_enabled?
|
2024-02-15 09:45:20 +01:00
|
|
|
ENV.key?('STRICT_EMAIL_VALIDATION_STARTS_ON')
|
2024-02-09 09:56:03 +01:00
|
|
|
end
|
|
|
|
end
|