From b3bef96744a843b518d63e9f10592c8eb34d1c9b Mon Sep 17 00:00:00 2001
From: Sam <sam.saffron@gmail.com>
Date: Tue, 12 Sep 2023 11:06:35 +1000
Subject: [PATCH] FIX: send email to normalized email owner when hiding emails
 (#23524)

Previous to this change when both `normalize_emails` and `hide_email_address_taken`
is enabled the expected `account_exists` email was only sent on exact email
matches.

This expands it so it also sends an email to the canonical email owner.
---
 app/controllers/users_controller.rb    |  7 +++-
 spec/requests/users_controller_spec.rb | 50 +++++++++++++++++++++++++-
 spec/support/sidekiq_helpers.rb        |  2 +-
 3 files changed, 56 insertions(+), 3 deletions(-)

diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb
index ba705c123bf..d1c6b6ca010 100644
--- a/app/controllers/users_controller.rb
+++ b/app/controllers/users_controller.rb
@@ -767,7 +767,12 @@ class UsersController < ApplicationController
           user.errors[:primary_email]&.include?(I18n.t("errors.messages.taken"))
       session["user_created_message"] = activation.success_message
 
-      if existing_user = User.find_by_email(user.primary_email&.email)
+      existing_user = User.find_by_email(user.primary_email&.email)
+      if !existing_user && SiteSetting.normalize_emails
+        existing_user =
+          UserEmail.find_by_normalized_email(user.primary_email&.normalized_email)&.user
+      end
+      if existing_user
         Jobs.enqueue(:critical_user_email, type: "account_exists", user_id: existing_user.id)
       end
 
diff --git a/spec/requests/users_controller_spec.rb b/spec/requests/users_controller_spec.rb
index 410e9b1542f..4ddad06890c 100644
--- a/spec/requests/users_controller_spec.rb
+++ b/spec/requests/users_controller_spec.rb
@@ -834,6 +834,46 @@ RSpec.describe UsersController do
         end
       end
 
+      context "when normalize_emails is enabled" do
+        let (:email) {
+          "jane+100@gmail.com"
+        }
+        let (:dupe_email) {
+          "jane+191@gmail.com"
+        }
+        let! (:user) {
+          Fabricate(:user, email: email, password: "strongpassword")
+        }
+
+        before do
+          SiteSetting.hide_email_address_taken = true
+          SiteSetting.normalize_emails = true
+        end
+
+        it "sends an email to normalized email owner when hide_email_address_taken is enabled" do
+          expect do
+            expect_enqueued_with(
+              job: Jobs::CriticalUserEmail,
+              args: {
+                type: "account_exists",
+                user_id: user.id,
+              },
+            ) do
+              post "/u.json",
+                   params: {
+                     name: "Jane Doe",
+                     username: "janedoe9999",
+                     password: "strongpassword",
+                     email: dupe_email,
+                   }
+            end
+          end.to_not change { User.count }
+
+          expect(response.status).to eq(200)
+          expect(session["user_created_message"]).to be_present
+        end
+      end
+
       context "when users already exists with given email" do
         let!(:existing) { Fabricate(:user, email: post_user_params[:email]) }
 
@@ -850,7 +890,15 @@ RSpec.describe UsersController do
 
         it "returns success if hide_email_address_taken is enabled" do
           SiteSetting.hide_email_address_taken = true
-          expect { post_user }.to_not change { User.count }
+          expect {
+            expect_enqueued_with(
+              job: Jobs::CriticalUserEmail,
+              args: {
+                type: "account_exists",
+                user_id: existing.id,
+              },
+            ) { post_user }
+          }.to_not change { User.count }
 
           expect(response.status).to eq(200)
           expect(session["user_created_message"]).to be_present
diff --git a/spec/support/sidekiq_helpers.rb b/spec/support/sidekiq_helpers.rb
index 883fe0fde05..73cffb463f7 100644
--- a/spec/support/sidekiq_helpers.rb
+++ b/spec/support/sidekiq_helpers.rb
@@ -32,7 +32,7 @@ module SidekiqHelpers
       eq(expectation),
       (
         if expectation
-          "No enqueued job with #{expected} found"
+          "No enqueued job with #{expected}\nFound:\n #{jobs.inspect}"
         else
           "Enqueued job with #{expected} found"
         end