From b8c02f14c5b0386a87adfd1ccb815472442ce037 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?S=C3=A9bastien=20Gaya?= <sebastien.gaya@gmail.com>
Date: Thu, 7 Dec 2023 17:41:29 +0100
Subject: [PATCH] whitelist where we use constantize on user input

---
 app/assets/javascripts/admin/commons/association.js    |  4 ++--
 app/controllers/admin/application_controller.rb        |  4 ++++
 .../admin/communication/blocks/headings_controller.rb  |  2 +-
 .../admin/communication/blocks_controller.rb           |  6 +++---
 .../admin/communication/contents_controller.rb         |  2 +-
 .../communication/extranets/contacts_controller.rb     |  4 +---
 .../admin/communication/websites/pages_controller.rb   |  4 +---
 .../communication/websites/permalinks_controller.rb    |  3 ++-
 app/controllers/admin/users_controller.rb              |  5 ++---
 app/models/communication/extranet/connection.rb        |  4 ++++
 app/models/communication/website/page.rb               |  4 ++++
 app/models/communication/website/page/organization.rb  |  4 ++++
 app/models/communication/website/page/person.rb        |  4 ++++
 app/services/polymorphic_object_finder.rb              | 10 ++++++----
 .../communication/extranets/contacts/_toggle.html.erb  |  4 ++--
 .../pages/show/special_pages/_organization.html.erb    |  2 +-
 .../websites/pages/show/special_pages/_person.html.erb |  2 +-
 17 files changed, 43 insertions(+), 25 deletions(-)

diff --git a/app/assets/javascripts/admin/commons/association.js b/app/assets/javascripts/admin/commons/association.js
index b4a0fcd5e..e93455cbb 100644
--- a/app/assets/javascripts/admin/commons/association.js
+++ b/app/assets/javascripts/admin/commons/association.js
@@ -10,8 +10,8 @@ $(function () {
                 type: 'POST',
                 url: target,
                 data: {
-                    objectId: id,
-                    objectType: type
+                    'object_id': id,
+                    'object_type': type
                 }
             }).done(function () {
                 location.reload();
diff --git a/app/controllers/admin/application_controller.rb b/app/controllers/admin/application_controller.rb
index 5a98ff54f..3861751d2 100644
--- a/app/controllers/admin/application_controller.rb
+++ b/app/controllers/admin/application_controller.rb
@@ -38,6 +38,10 @@ class Admin::ApplicationController < ApplicationController
     # If the block doesn't exist anymore
   end
 
+  def model_names_with_blocks
+    @model_names_with_blocks ||= ApplicationRecord.descendants.select { |model| model.included_modules.include?(WithBlocks) }.map(&:name)
+  end
+
   private
 
   def redirect_if_context_is_not_an_university!
diff --git a/app/controllers/admin/communication/blocks/headings_controller.rb b/app/controllers/admin/communication/blocks/headings_controller.rb
index 53e597801..11114a04c 100644
--- a/app/controllers/admin/communication/blocks/headings_controller.rb
+++ b/app/controllers/admin/communication/blocks/headings_controller.rb
@@ -20,7 +20,7 @@ class Admin::Communication::Blocks::HeadingsController < Admin::Communication::B
   end
 
   def new
-    @heading.about = PolymorphicObjectFinder.find params, :about
+    @heading.about = PolymorphicObjectFinder.find(params, :about, current_university, whitelist: model_names_with_blocks)
     breadcrumb
   end
 
diff --git a/app/controllers/admin/communication/blocks_controller.rb b/app/controllers/admin/communication/blocks_controller.rb
index 4baa5141c..e2b24df08 100644
--- a/app/controllers/admin/communication/blocks_controller.rb
+++ b/app/controllers/admin/communication/blocks_controller.rb
@@ -18,7 +18,7 @@ class Admin::Communication::BlocksController < Admin::Communication::Application
   end
 
   def new
-    @block.about = PolymorphicObjectFinder.find params, :about
+    @block.about = PolymorphicObjectFinder.find(params, :about, current_university, whitelist: model_names_with_blocks)
     breadcrumb
   end
 
@@ -61,12 +61,12 @@ class Admin::Communication::BlocksController < Admin::Communication::Application
     return unless request.xhr?
     cookies.signed[Communication::Block::BLOCK_COPY_COOKIE] = {
       value: params[:id],
-      path: '/admin' 
+      path: '/admin'
     }
   end
 
   def paste
-    about = PolymorphicObjectFinder.find(params, :about)
+    about = PolymorphicObjectFinder.find(params, :about, current_university, whitelist: model_names_with_blocks)
     # On réattribue à @block pour bénéficier du calcul dans about_path
     @block = @block.paste(about)
     cookies.delete(Communication::Block::BLOCK_COPY_COOKIE, path: '/admin')
diff --git a/app/controllers/admin/communication/contents_controller.rb b/app/controllers/admin/communication/contents_controller.rb
index ff344cda5..bdd741ef2 100644
--- a/app/controllers/admin/communication/contents_controller.rb
+++ b/app/controllers/admin/communication/contents_controller.rb
@@ -13,7 +13,7 @@ class Admin::Communication::ContentsController < Admin::Communication::Applicati
   protected
 
   def load_about
-    @about = PolymorphicObjectFinder.find(params, :about)
+    @about = PolymorphicObjectFinder.find(params, :about, current_university, whitelist: model_names_with_blocks)
     raise_403_unless @about.university == current_university
     raise_403_unless can?(:edit, @about)
   end
diff --git a/app/controllers/admin/communication/extranets/contacts_controller.rb b/app/controllers/admin/communication/extranets/contacts_controller.rb
index 6283e05b3..417447132 100644
--- a/app/controllers/admin/communication/extranets/contacts_controller.rb
+++ b/app/controllers/admin/communication/extranets/contacts_controller.rb
@@ -53,8 +53,6 @@ class Admin::Communication::Extranets::ContactsController < Admin::Communication
   protected
 
   def load_object
-    object_type = params[:objectType]
-    object_id = params[:objectId]
-    @object = object_type.constantize.find object_id
+    @object = PolymorphicObjectFinder.find(params, :object, current_university, whitelist: Communication::Extranet::Connection.connectable_model_names)
   end
 end
diff --git a/app/controllers/admin/communication/websites/pages_controller.rb b/app/controllers/admin/communication/websites/pages_controller.rb
index f788465d0..aae55ee3a 100644
--- a/app/controllers/admin/communication/websites/pages_controller.rb
+++ b/app/controllers/admin/communication/websites/pages_controller.rb
@@ -134,9 +134,7 @@ class Admin::Communication::Websites::PagesController < Admin::Communication::We
   protected
 
   def load_object
-    object_type = params[:objectType]
-    object_id = params[:objectId]
-    @object = object_type.constantize.find object_id
+    @object = PolymorphicObjectFinder.find(params, :object, current_university, whitelist: @page.connectable_model_names)
   end
 
   def breadcrumb
diff --git a/app/controllers/admin/communication/websites/permalinks_controller.rb b/app/controllers/admin/communication/websites/permalinks_controller.rb
index 49a39f0c4..28aec9d20 100644
--- a/app/controllers/admin/communication/websites/permalinks_controller.rb
+++ b/app/controllers/admin/communication/websites/permalinks_controller.rb
@@ -2,7 +2,8 @@ class Admin::Communication::Websites::PermalinksController < Admin::Communicatio
 
   def create
     @path = params['communication_website_permalink']['path']
-    @about = PolymorphicObjectFinder.find(params, :about)
+    model_names_with_permalinks = ApplicationRecord.descendants.select { |model| model.included_modules.include?(WithPermalink) }.map(&:name)
+    @about = PolymorphicObjectFinder.find(params, :about, current_university, whitelist: model_names_with_permalinks)
     @permalink = @about.add_redirection(@path)
   end
 end
\ No newline at end of file
diff --git a/app/controllers/admin/users_controller.rb b/app/controllers/admin/users_controller.rb
index 122be9729..3968a1e2a 100644
--- a/app/controllers/admin/users_controller.rb
+++ b/app/controllers/admin/users_controller.rb
@@ -21,9 +21,8 @@ class Admin::UsersController < Admin::ApplicationController
 
   def favorite
     operation = params[:operation]
-    id = params[:about_id]
-    type = params[:about_type]
-    about = type.constantize.find id
+    favoritable_model_names = ApplicationRecord.descendants.select { |model| model.included_modules.include?(Favoritable) }.map(&:name)
+    about = PolymorphicObjectFinder.find(params, :about, current_university, whitelist: favoritable_model_names)
     if operation == 'add'
       current_user.add_favorite(about)
     else
diff --git a/app/models/communication/extranet/connection.rb b/app/models/communication/extranet/connection.rb
index 30cc10e73..9d06bb3c9 100644
--- a/app/models/communication/extranet/connection.rb
+++ b/app/models/communication/extranet/connection.rb
@@ -25,4 +25,8 @@ class Communication::Extranet::Connection < ApplicationRecord
   belongs_to :university
   belongs_to :extranet, class_name: 'Communication::Extranet'
   belongs_to :object, polymorphic: true
+
+  def self.connectable_model_names
+    ["University::Organization", "University::Person"]
+  end
 end
diff --git a/app/models/communication/website/page.rb b/app/models/communication/website/page.rb
index 6ddca2a2d..82c736ab2 100644
--- a/app/models/communication/website/page.rb
+++ b/app/models/communication/website/page.rb
@@ -142,6 +142,10 @@ class Communication::Website::Page < ApplicationRecord
               .where.not(id: id)
   end
 
+  def connectable_model_names
+    []
+  end
+
   protected
 
   def check_accessibility
diff --git a/app/models/communication/website/page/organization.rb b/app/models/communication/website/page/organization.rb
index b17a2c96d..3b9249339 100644
--- a/app/models/communication/website/page/organization.rb
+++ b/app/models/communication/website/page/organization.rb
@@ -57,6 +57,10 @@ class Communication::Website::Page::Organization < Communication::Website::Page
     University::Organization.where(id: ids)
   end
 
+  def connectable_model_names
+    ["University::Organization"]
+  end
+
   protected
 
   def current_git_path
diff --git a/app/models/communication/website/page/person.rb b/app/models/communication/website/page/person.rb
index 4c11cd187..431a660a3 100644
--- a/app/models/communication/website/page/person.rb
+++ b/app/models/communication/website/page/person.rb
@@ -56,6 +56,10 @@ class Communication::Website::Page::Person < Communication::Website::Page
     University::Person.where(id: ids)
   end
 
+  def connectable_model_names
+    ["University::Person"]
+  end
+
   protected
 
   def current_git_path
diff --git a/app/services/polymorphic_object_finder.rb b/app/services/polymorphic_object_finder.rb
index 47bf78dcc..763cba5a1 100644
--- a/app/services/polymorphic_object_finder.rb
+++ b/app/services/polymorphic_object_finder.rb
@@ -1,12 +1,14 @@
 class PolymorphicObjectFinder
-  # @block.about = Polymorphic.find params, :about
+  # @block.about = Polymorphic.find params, :about, current_university, whitelist: ["Communication::Website::Page"]
   # Rails uses ActiveRecord::Inheritance#polymorphic_name to hydrate the about_type.
   # Example: A Block for a Communication::Website::Page::Home will have about_type = "Communication::Website::Page"
-  def self.find(params, key)
+  def self.find(params, key, university, whitelist: [])
     key_id = "#{key}_id".to_sym
     key_type = "#{key}_type".to_sym
-    klass = params[key_type].constantize
+    model_name = whitelist.detect { |item| item == params[key_type] }
+    return unless model_name.nil?
+    model = model.constantize
     id = params[key_id]
-    klass.find id
+    model.where(university: university).find(id)
   end
 end
\ No newline at end of file
diff --git a/app/views/admin/communication/extranets/contacts/_toggle.html.erb b/app/views/admin/communication/extranets/contacts/_toggle.html.erb
index 0d8b6960e..23b704726 100644
--- a/app/views/admin/communication/extranets/contacts/_toggle.html.erb
+++ b/app/views/admin/communication/extranets/contacts/_toggle.html.erb
@@ -2,8 +2,8 @@
 connected = @extranet.connected?(about)
 path = toggle_admin_communication_extranet_contacts_path(
   extranet_id: @extranet.id,
-  objectId: about.id,
-  objectType: about.class,
+  object_id: about.id,
+  object_type: about.class,
 )
 %>
   <input  class="form-check-input"
diff --git a/app/views/admin/communication/websites/pages/show/special_pages/_organization.html.erb b/app/views/admin/communication/websites/pages/show/special_pages/_organization.html.erb
index 9292423bb..232e8ca99 100644
--- a/app/views/admin/communication/websites/pages/show/special_pages/_organization.html.erb
+++ b/app/views/admin/communication/websites/pages/show/special_pages/_organization.html.erb
@@ -22,7 +22,7 @@
         <tr>
           <td><%= link_to organization, [:admin, organization] %></td>
           <td><%= link_to 'Déconnecter',
-                          disconnect_admin_communication_website_page_path(@page, objectId: organization.id, objectType: organization.class),
+                          disconnect_admin_communication_website_page_path(@page, object_id: organization.id, object_type: organization.class),
                           class: button_classes_danger,
                           method: :post %></td>
         </tr>
diff --git a/app/views/admin/communication/websites/pages/show/special_pages/_person.html.erb b/app/views/admin/communication/websites/pages/show/special_pages/_person.html.erb
index 0c263addf..babffb39e 100644
--- a/app/views/admin/communication/websites/pages/show/special_pages/_person.html.erb
+++ b/app/views/admin/communication/websites/pages/show/special_pages/_person.html.erb
@@ -22,7 +22,7 @@
         <tr>
           <td><%= link_to person, [:admin, person] %></td>
           <td><%= link_to 'Déconnecter',
-                          disconnect_admin_communication_website_page_path(@page, objectId: person.id, objectType: person.class),
+                          disconnect_admin_communication_website_page_path(@page, object_id: person.id, object_type: person.class),
                           class: button_classes_danger,
                           method: :post %></td>
         </tr>
-- 
GitLab