From ad747c1e13f79d04b14a1cbde33fb48d045feb26 Mon Sep 17 00:00:00 2001
From: Ahmad Farhat <ahmad.af.farhat@gmail.com>
Date: Wed, 1 Nov 2023 09:48:25 -0400
Subject: [PATCH] Fix case sensitive emails  (#5485)

* case sensitive emails

* Update schema.rb
---
 .../api/v1/admin/invitations_controller.rb       |  2 +-
 .../api/v1/migrations/external_controller.rb     |  2 +-
 .../api/v1/reset_password_controller.rb          |  2 +-
 app/controllers/api/v1/sessions_controller.rb    |  3 ++-
 app/controllers/api/v1/users_controller.rb       |  3 ++-
 app/controllers/external_controller.rb           |  2 +-
 app/services/recordings_sync.rb                  |  6 +++---
 db/data/20231030185844_lowercase_emails.rb       | 16 ++++++++++++++++
 db/data_schema.rb                                |  2 +-
 db/schema.rb                                     |  2 +-
 10 files changed, 29 insertions(+), 11 deletions(-)
 create mode 100644 db/data/20231030185844_lowercase_emails.rb

diff --git a/app/controllers/api/v1/admin/invitations_controller.rb b/app/controllers/api/v1/admin/invitations_controller.rb
index 5d022e83..6aab9529 100644
--- a/app/controllers/api/v1/admin/invitations_controller.rb
+++ b/app/controllers/api/v1/admin/invitations_controller.rb
@@ -39,7 +39,7 @@ module Api
         # Creates an invitation for the specified emails (comma separated) and sends them an email
         def create
           params[:invitations][:emails].split(',').each do |email|
-            invitation = Invitation.find_or_initialize_by(email:, provider: current_provider).tap do |i|
+            invitation = Invitation.find_or_initialize_by(email: email.downcase, provider: current_provider).tap do |i|
               i.updated_at = Time.zone.now
               i.save!
             end
diff --git a/app/controllers/api/v1/migrations/external_controller.rb b/app/controllers/api/v1/migrations/external_controller.rb
index f9d39c15..9a68ab20 100644
--- a/app/controllers/api/v1/migrations/external_controller.rb
+++ b/app/controllers/api/v1/migrations/external_controller.rb
@@ -91,7 +91,7 @@ module Api
             return render_error(status: :bad_request, errors: 'Provider does not exist')
           end
 
-          return render_data status: :created if User.exists?(email: user_hash[:email], provider: user_hash[:provider])
+          return render_data status: :created if User.exists?(email: user_hash[:email].downcase, provider: user_hash[:provider])
 
           user_hash[:language] = I18n.default_locale if user_hash[:language].blank? || user_hash[:language] == 'default'
 
diff --git a/app/controllers/api/v1/reset_password_controller.rb b/app/controllers/api/v1/reset_password_controller.rb
index 99c7a8d3..feea5ec0 100644
--- a/app/controllers/api/v1/reset_password_controller.rb
+++ b/app/controllers/api/v1/reset_password_controller.rb
@@ -30,7 +30,7 @@ module Api
         # TODO: Log events.
         return render_error unless params[:user]
 
-        user = User.find_by email: params[:user][:email]
+        user = User.find_by email: params[:user][:email].downcase
 
         # Silently fail for unfound or external users.
         return render_data status: :ok unless user && !user.external_id?
diff --git a/app/controllers/api/v1/sessions_controller.rb b/app/controllers/api/v1/sessions_controller.rb
index d764ad97..65a07e91 100644
--- a/app/controllers/api/v1/sessions_controller.rb
+++ b/app/controllers/api/v1/sessions_controller.rb
@@ -36,7 +36,8 @@ module Api
         return render_error if hcaptcha_enabled? && !verify_hcaptcha(response: params[:token])
 
         # Search for a user within the current provider and, if not found, search for a super admin within bn provider
-        user = User.find_by(email: session_params[:email], provider: current_provider) || User.find_by(email: session_params[:email], provider: 'bn')
+        user = User.find_by(email: session_params[:email].downcase, provider: current_provider) ||
+               User.find_by(email: session_params[:email].downcase, provider: 'bn')
 
         # Return an error if the user is not found
         return render_error if user.blank?
diff --git a/app/controllers/api/v1/users_controller.rb b/app/controllers/api/v1/users_controller.rb
index 95b7a69e..f00dd0e3 100644
--- a/app/controllers/api/v1/users_controller.rb
+++ b/app/controllers/api/v1/users_controller.rb
@@ -169,7 +169,8 @@ module Api
         return false if create_user_params[:invite_token].blank?
 
         # Try to delete the invitation and return true if it succeeds
-        Invitation.destroy_by(email: create_user_params[:email], provider: current_provider, token: create_user_params[:invite_token]).present?
+        Invitation.destroy_by(email: create_user_params[:email].downcase, provider: current_provider,
+                              token: create_user_params[:invite_token]).present?
       end
     end
   end
diff --git a/app/controllers/external_controller.rb b/app/controllers/external_controller.rb
index b7f7a4d1..7e916805 100644
--- a/app/controllers/external_controller.rb
+++ b/app/controllers/external_controller.rb
@@ -129,7 +129,7 @@ class ExternalController < ApplicationController
     return false if token.blank?
 
     # Try to delete the invitation and return true if it succeeds
-    Invitation.destroy_by(email:, provider: current_provider, token:).present?
+    Invitation.destroy_by(email: email.downcase, provider: current_provider, token:).present?
   end
 
   def build_user_info(credentials)
diff --git a/app/services/recordings_sync.rb b/app/services/recordings_sync.rb
index af50e10b..bacdfd19 100644
--- a/app/services/recordings_sync.rb
+++ b/app/services/recordings_sync.rb
@@ -23,9 +23,9 @@ class RecordingsSync
   end
 
   def call
-    recordings = @room.recordings
-    Format.where(recordings:).delete_all
-    recordings.delete_all
+    room_recordings = @room.recordings
+    Format.where(recording: room_recordings).delete_all
+    room_recordings.delete_all
 
     recordings = BigBlueButtonApi.new(provider: @provider).get_recordings(meeting_ids: @room.meeting_id)
     recordings[:recordings].each do |recording|
diff --git a/db/data/20231030185844_lowercase_emails.rb b/db/data/20231030185844_lowercase_emails.rb
new file mode 100644
index 00000000..fbe41a00
--- /dev/null
+++ b/db/data/20231030185844_lowercase_emails.rb
@@ -0,0 +1,16 @@
+# frozen_string_literal: true
+
+class LowercaseEmails < ActiveRecord::Migration[7.1]
+  def up
+    User.all.find_each(batch_size: 250) do |user|
+      downcase = user.email.downcase
+      next if user.email == downcase
+
+      user.update(email: downcase)
+    end
+  end
+
+  def down
+    raise ActiveRecord::IrreversibleMigration
+  end
+end
diff --git a/db/data_schema.rb b/db/data_schema.rb
index 40131930..5e92e7bf 100644
--- a/db/data_schema.rb
+++ b/db/data_schema.rb
@@ -1 +1 @@
-DataMigrate::Data.define(version: 20230228193705)
+DataMigrate::Data.define(version: 20231030185844)
diff --git a/db/schema.rb b/db/schema.rb
index f0760fed..9cd0b8c6 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -10,7 +10,7 @@
 #
 # It's strongly recommended that you check this file into your version control system.
 
-ActiveRecord::Schema[7.0].define(version: 2023_07_05_183747) do
+ActiveRecord::Schema[7.1].define(version: 2023_07_05_183747) do
   # These are extensions that must be enabled in order to support this database
   enable_extension "pgcrypto"
   enable_extension "plpgsql"
-- 
GitLab