From 9bcecab12fbd9f5df5d2d41d3548092a03a9747b Mon Sep 17 00:00:00 2001
From: pabois <pierreandre.boissinot@noesya.coop>
Date: Fri, 25 Feb 2022 09:35:04 +0100
Subject: [PATCH] sanitizer

---
 .../administration/qualiopi/criterion.rb      |  2 ++
 .../administration/qualiopi/indicator.rb      |  2 ++
 app/models/communication/website/category.rb  |  1 +
 .../communication/website/index_page.rb       |  1 +
 app/models/communication/website/menu.rb      |  1 +
 app/models/communication/website/menu/item.rb |  1 +
 app/models/communication/website/page.rb      |  1 +
 app/models/communication/website/post.rb      |  1 +
 app/models/concerns/sanitizable.rb            | 21 +++++++++++++
 app/models/education/program.rb               |  1 +
 app/models/research/journal/article.rb        |  1 +
 app/models/research/journal/volume.rb         |  1 +
 app/models/research/laboratory/axis.rb        |  1 +
 app/models/research/thesis.rb                 |  2 ++
 app/models/university/person.rb               |  1 +
 app/services/osuny/sanitizer.rb               | 31 +++++++++++++++++++
 config/application.rb                         |  4 +--
 17 files changed, 71 insertions(+), 2 deletions(-)
 create mode 100644 app/models/concerns/sanitizable.rb
 create mode 100644 app/services/osuny/sanitizer.rb

diff --git a/app/models/administration/qualiopi/criterion.rb b/app/models/administration/qualiopi/criterion.rb
index b4ffaec5e..28bca2dce 100644
--- a/app/models/administration/qualiopi/criterion.rb
+++ b/app/models/administration/qualiopi/criterion.rb
@@ -10,6 +10,8 @@
 #  updated_at  :datetime         not null
 #
 class Administration::Qualiopi::Criterion < ApplicationRecord
+  include Sanitizable
+
   has_many :indicators, dependent: :destroy
 
   validates :number, uniqueness: true
diff --git a/app/models/administration/qualiopi/indicator.rb b/app/models/administration/qualiopi/indicator.rb
index c43737ece..6e06a0273 100644
--- a/app/models/administration/qualiopi/indicator.rb
+++ b/app/models/administration/qualiopi/indicator.rb
@@ -23,6 +23,8 @@
 #  fk_rails_eed87f7acf  (criterion_id => administration_qualiopi_criterions.id)
 #
 class Administration::Qualiopi::Indicator < ApplicationRecord
+  include Sanitizable
+
   belongs_to :criterion
 
   validates :number, uniqueness: true
diff --git a/app/models/communication/website/category.rb b/app/models/communication/website/category.rb
index 5dd734d33..28be40150 100644
--- a/app/models/communication/website/category.rb
+++ b/app/models/communication/website/category.rb
@@ -33,6 +33,7 @@
 #  fk_rails_e58348b119  (program_id => education_programs.id)
 #
 class Communication::Website::Category < ApplicationRecord
+  include Sanitizable
   include WithGit
   include WithFeaturedImage
   include WithBlobs
diff --git a/app/models/communication/website/index_page.rb b/app/models/communication/website/index_page.rb
index 9366722a9..049d93274 100644
--- a/app/models/communication/website/index_page.rb
+++ b/app/models/communication/website/index_page.rb
@@ -27,6 +27,7 @@
 #  fk_rails_7eb45227ae  (university_id => universities.id)
 #
 class Communication::Website::IndexPage < ApplicationRecord
+  include Sanitizable
   include WithGit
   include WithFeaturedImage
   include WithBlobs
diff --git a/app/models/communication/website/menu.rb b/app/models/communication/website/menu.rb
index 2ec3ea11b..2e21098b7 100644
--- a/app/models/communication/website/menu.rb
+++ b/app/models/communication/website/menu.rb
@@ -22,6 +22,7 @@
 #  fk_rails_dcc7198fc5  (communication_website_id => communication_websites.id)
 #
 class Communication::Website::Menu < ApplicationRecord
+  include Sanitizable
   include WithGit
 
   belongs_to :university
diff --git a/app/models/communication/website/menu/item.rb b/app/models/communication/website/menu/item.rb
index d95a6563b..f4980a465 100644
--- a/app/models/communication/website/menu/item.rb
+++ b/app/models/communication/website/menu/item.rb
@@ -32,6 +32,7 @@
 #  fk_rails_fa4f4585e4  (website_id => communication_websites.id)
 #
 class Communication::Website::Menu::Item < ApplicationRecord
+  include Sanitizable
   include WithTree
   include WithPosition
   include WithTargets
diff --git a/app/models/communication/website/page.rb b/app/models/communication/website/page.rb
index 7aa7eee02..7ee31a9de 100644
--- a/app/models/communication/website/page.rb
+++ b/app/models/communication/website/page.rb
@@ -39,6 +39,7 @@
 #
 
 class Communication::Website::Page < ApplicationRecord
+  include Sanitizable
   include WithGit
   include WithFeaturedImage
   include WithBlobs
diff --git a/app/models/communication/website/post.rb b/app/models/communication/website/post.rb
index 0cd59f91a..80c4c0218 100644
--- a/app/models/communication/website/post.rb
+++ b/app/models/communication/website/post.rb
@@ -32,6 +32,7 @@
 #  fk_rails_e0eec447b0  (author_id => university_people.id)
 #
 class Communication::Website::Post < ApplicationRecord
+  include Sanitizable
   include WithGit
   include WithFeaturedImage
   include WithBlobs
diff --git a/app/models/concerns/sanitizable.rb b/app/models/concerns/sanitizable.rb
new file mode 100644
index 000000000..1d9b39065
--- /dev/null
+++ b/app/models/concerns/sanitizable.rb
@@ -0,0 +1,21 @@
+module Sanitizable
+  extend ActiveSupport::Concern
+
+  included do
+
+    before_validation :sanitize_fields
+
+    def sanitize_fields
+      attributes_to_sanitize = self.class.columns_hash.map { |name,value| [name, value.type] }
+                                                      .to_h
+                                                      .select { |attr_name, attr_type|
+                                                        [:string, :text].include?(attr_type) && public_send(attr_name).present?
+                                                      }
+
+      attributes_to_sanitize.each do |attr_name, attr_type|
+        public_send "#{attr_name}=", Osuny::Sanitizer.sanitize(public_send(attr_name), attr_type)
+      end
+    end
+
+  end
+end
diff --git a/app/models/education/program.rb b/app/models/education/program.rb
index 5d9827e76..69cc14e8e 100644
--- a/app/models/education/program.rb
+++ b/app/models/education/program.rb
@@ -43,6 +43,7 @@
 #  fk_rails_ec1f16f607  (parent_id => education_programs.id)
 #
 class Education::Program < ApplicationRecord
+  include Sanitizable
   include WithGit
   include WithFeaturedImage
   include WithBlobs
diff --git a/app/models/research/journal/article.rb b/app/models/research/journal/article.rb
index 10366cfd8..632708ee1 100644
--- a/app/models/research/journal/article.rb
+++ b/app/models/research/journal/article.rb
@@ -34,6 +34,7 @@
 #  fk_rails_935541e014  (university_id => universities.id)
 #
 class Research::Journal::Article < ApplicationRecord
+  include Sanitizable
   include WithGit
   include WithBlobs
   include WithPosition
diff --git a/app/models/research/journal/volume.rb b/app/models/research/journal/volume.rb
index 30c6db4a0..719f76d55 100644
--- a/app/models/research/journal/volume.rb
+++ b/app/models/research/journal/volume.rb
@@ -27,6 +27,7 @@
 #  fk_rails_c83d5e9068  (university_id => universities.id)
 #
 class Research::Journal::Volume < ApplicationRecord
+  include Sanitizable
   include WithGit
   include WithBlobs
   include WithFeaturedImage
diff --git a/app/models/research/laboratory/axis.rb b/app/models/research/laboratory/axis.rb
index 11e2f3d15..40cae3951 100644
--- a/app/models/research/laboratory/axis.rb
+++ b/app/models/research/laboratory/axis.rb
@@ -24,6 +24,7 @@
 #  fk_rails_d334f832b4  (university_id => universities.id)
 #
 class Research::Laboratory::Axis < ApplicationRecord
+  include Sanitizable
   include WithPosition
 
   has_summernote :text
diff --git a/app/models/research/thesis.rb b/app/models/research/thesis.rb
index 0d824cbfb..48f1f4aed 100644
--- a/app/models/research/thesis.rb
+++ b/app/models/research/thesis.rb
@@ -30,6 +30,8 @@
 #  fk_rails_b3380066dc  (research_laboratory_id => research_laboratories.id)
 #
 class Research::Thesis < ApplicationRecord
+  include Sanitizable
+
   belongs_to :university
   belongs_to :laboratory, foreign_key: :research_laboratory_id
   belongs_to :author, class_name: 'University::Person'
diff --git a/app/models/university/person.rb b/app/models/university/person.rb
index 49718973f..05eaa9662 100644
--- a/app/models/university/person.rb
+++ b/app/models/university/person.rb
@@ -31,6 +31,7 @@
 #  fk_rails_da35e70d61  (university_id => universities.id)
 #
 class University::Person < ApplicationRecord
+  include Sanitizable
   include WithGit
   include WithBlobs
   include WithSlug
diff --git a/app/services/osuny/sanitizer.rb b/app/services/osuny/sanitizer.rb
new file mode 100644
index 000000000..a155edb89
--- /dev/null
+++ b/app/services/osuny/sanitizer.rb
@@ -0,0 +1,31 @@
+class Osuny::Sanitizer
+  include ActionView::Helpers::SanitizeHelper
+
+  def self.sanitize(input, type = 'text')
+    return '' if input.blank?
+    raise ArgumentError.new('First argument must be a String') unless [String, ActionText::Content].include? input.class
+
+    case type.to_s
+    when 'string'
+      string_sanitize(input)
+    when 'text'
+      if input.is_a? String
+        safe_list_sanitizer.sanitize input
+      else
+        ActionText::Content.new(safe_list_sanitizer.sanitize input.to_html)
+      end
+    else
+      input
+    end
+  end
+
+  private
+
+  def self.string_sanitize(raw_string)
+    output = Loofah.fragment(raw_string).text(encode_special_chars: false)
+    while output != Loofah.fragment(output).text(encode_special_chars: false)
+      output = Loofah.fragment(output).text(encode_special_chars: false)
+    end
+    output
+  end
+end
diff --git a/config/application.rb b/config/application.rb
index 6dbe81158..010539967 100644
--- a/config/application.rb
+++ b/config/application.rb
@@ -53,14 +53,14 @@ module Osuny
       "cite", "code", "dd", "del", "dfn", "div", "dl", "dt", "em",
       "h1", "h2", "h3", "h4", "h5", "h6", "hr", "i", "img", "ins", "kbd", "li", "ol",
       "p", "picture", "pre", "samp", "small", "source", "span", "strong",
-      "sub", "sup", "tt", "u", "ul", "var", "video", "iframe"
+      "sub", "sup", "tt", "u", "ul", "var", "video", "iframe", "action-text-attachment"
     ]
     config.action_view.sanitized_allowed_attributes = [
       "abbr", "allowfullscreen", "alt", "cite", "controls", "datetime",
       "decoding", "frameborder", "height", "href", "loading", "mozallowfullscreen",
       "name", "sizes", "src", "srcset", "target", "title", "type",
       "webkitallowfullscreen", "width", "xml:lang",
-
+      "sgid", "content-type", "url", "filename", "filesize", "previewable"
     ]
 
     config.allowed_special_chars = '#?!,@$%^&*+:;£µ-'
-- 
GitLab