Skip to content

Commit bc50b0b

Browse files
committed
abstracted user email validations into EmailValidations concern
1 parent b0996a7 commit bc50b0b

3 files changed

Lines changed: 59 additions & 52 deletions

File tree

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
module EmailValidations
2+
extend ActiveSupport::Concern
3+
4+
included do
5+
validate :email_domain_not_blocklisted
6+
validate :email_not_blocklisted
7+
validate :email_not_bad_pattern
8+
end
9+
10+
def email_domain_not_blocklisted
11+
return unless File.exist?(Rails.root.join('../.qpixel-domain-blocklist.txt'))
12+
return unless saved_changes.include? 'email'
13+
14+
blocklist = File.read(Rails.root.join('../.qpixel-domain-blocklist.txt')).split("\n")
15+
email_domain = email.split('@')[-1]
16+
matched = blocklist.select { |x| email_domain == x }
17+
if matched.any?
18+
errors.add(:base, ApplicationRecord.useful_err_msg.sample)
19+
matched_domains = matched.map { |d| "equals: #{d}" }
20+
AuditLog.block_log(event_type: 'user_email_domain_blocked',
21+
comment: "email: #{email}\n#{matched_domains.join("\n")}\nsource: file")
22+
end
23+
end
24+
25+
def email_not_blocklisted
26+
return true unless saved_changes.include? 'email'
27+
28+
email_domain = email.split('@')[-1]
29+
is_mail_blocked = BlockedItem.emails.where(value: email)
30+
is_mail_host_blocked = BlockedItem.email_hosts.where(value: email_domain)
31+
if is_mail_blocked.any? || is_mail_host_blocked.any?
32+
errors.add(:base, ApplicationRecord.useful_err_msg.sample)
33+
if is_mail_blocked.any?
34+
AuditLog.block_log(event_type: 'user_email_blocked', related: is_mail_blocked.first,
35+
comment: "email: #{email}\nfull match to: #{is_mail_blocked.first.value}")
36+
end
37+
if is_mail_host_blocked.any?
38+
AuditLog.block_log(event_type: 'user_email_domain_blocked', related: is_mail_host_blocked.first,
39+
comment: "email: #{email}\ndomain match to: #{is_mail_host_blocked.first.value}")
40+
end
41+
end
42+
end
43+
44+
def email_not_bad_pattern
45+
return unless File.exist?(Rails.root.join('../.qpixel-email-patterns.txt'))
46+
return unless changes.include? 'email'
47+
48+
patterns = File.read(Rails.root.join('../.qpixel-email-patterns.txt')).split("\n")
49+
matched = patterns.select { |p| email.match? Regexp.new(p) }
50+
if matched.any?
51+
errors.add(:base, ApplicationRecord.useful_err_msg.sample)
52+
matched_patterns = matched.map { |p| "matched: #{p}" }
53+
AuditLog.block_log(event_type: 'user_email_pattern_match',
54+
comment: "email: #{email}\n#{matched_patterns.join("\n")}")
55+
end
56+
end
57+
end

app/models/user.rb

Lines changed: 1 addition & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
class User < ApplicationRecord
2+
include ::EmailValidations
23
include ::UsernameValidations
34
include ::UserRateLimits
45
include ::UserMerge
@@ -36,9 +37,6 @@ class User < ApplicationRecord
3637
accepts_nested_attributes_for :user_websites
3738

3839
validates :login_token, uniqueness: { allow_blank: true, case_sensitive: false }
39-
validate :email_domain_not_blocklisted
40-
validate :not_blocklisted?
41-
validate :email_not_bad_pattern
4240

4341
delegate :reputation, :reputation=, :privilege?, :privilege, to: :community_user
4442

@@ -375,54 +373,6 @@ def rtl_safe_username
375373
"#{username}\u202D"
376374
end
377375

378-
def email_domain_not_blocklisted
379-
return unless File.exist?(Rails.root.join('../.qpixel-domain-blocklist.txt'))
380-
return unless saved_changes.include? 'email'
381-
382-
blocklist = File.read(Rails.root.join('../.qpixel-domain-blocklist.txt')).split("\n")
383-
email_domain = email.split('@')[-1]
384-
matched = blocklist.select { |x| email_domain == x }
385-
if matched.any?
386-
errors.add(:base, ApplicationRecord.useful_err_msg.sample)
387-
matched_domains = matched.map { |d| "equals: #{d}" }
388-
AuditLog.block_log(event_type: 'user_email_domain_blocked',
389-
comment: "email: #{email}\n#{matched_domains.join("\n")}\nsource: file")
390-
end
391-
end
392-
393-
def not_blocklisted?
394-
return true unless saved_changes.include? 'email'
395-
396-
email_domain = email.split('@')[-1]
397-
is_mail_blocked = BlockedItem.emails.where(value: email)
398-
is_mail_host_blocked = BlockedItem.email_hosts.where(value: email_domain)
399-
if is_mail_blocked.any? || is_mail_host_blocked.any?
400-
errors.add(:base, ApplicationRecord.useful_err_msg.sample)
401-
if is_mail_blocked.any?
402-
AuditLog.block_log(event_type: 'user_email_blocked', related: is_mail_blocked.first,
403-
comment: "email: #{email}\nfull match to: #{is_mail_blocked.first.value}")
404-
end
405-
if is_mail_host_blocked.any?
406-
AuditLog.block_log(event_type: 'user_email_domain_blocked', related: is_mail_host_blocked.first,
407-
comment: "email: #{email}\ndomain match to: #{is_mail_host_blocked.first.value}")
408-
end
409-
end
410-
end
411-
412-
def email_not_bad_pattern
413-
return unless File.exist?(Rails.root.join('../.qpixel-email-patterns.txt'))
414-
return unless changes.include? 'email'
415-
416-
patterns = File.read(Rails.root.join('../.qpixel-email-patterns.txt')).split("\n")
417-
matched = patterns.select { |p| email.match? Regexp.new(p) }
418-
if matched.any?
419-
errors.add(:base, ApplicationRecord.useful_err_msg.sample)
420-
matched_patterns = matched.map { |p| "matched: #{p}" }
421-
AuditLog.block_log(event_type: 'user_email_pattern_match',
422-
comment: "email: #{email}\n#{matched_patterns.join("\n")}")
423-
end
424-
end
425-
426376
def ensure_community_user!
427377
community_user || create_community_user(reputation: SiteSetting['NewUserInitialRep'])
428378
end

test/models/user_test.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -309,7 +309,7 @@ class UserTest < ActiveSupport::TestCase
309309
assert_equal 1, local_result.size
310310
end
311311

312-
test 'not_blocklisted? should correctly determine if the user is blocklisted' do
312+
test 'email_not_blocklisted should correctly determine if the user is blocklisted' do
313313
std = users(:standard_user)
314314

315315
std.skip_reconfirmation!

0 commit comments

Comments
 (0)