diff --git a/app/models/concerns/dossier_filtering_concern.rb b/app/models/concerns/dossier_filtering_concern.rb index a1470bbda..ac040f3f5 100644 --- a/app/models/concerns/dossier_filtering_concern.rb +++ b/app/models/concerns/dossier_filtering_concern.rb @@ -39,5 +39,11 @@ module DossierFilteringConcern q = Array.new(values.count, "(#{table_column} = ?)").join(' OR ') where(q, *(values)) } + + scope :filter_array_enum, lambda { |table, column, values| + table_column = DossierFilterService.sanitized_column(table, column) + q = Array.new(values.count, "(#{table_column} = ?)").join(' OR ') + where(q, *(values. map { |value| "[\"#{value}\"]" })) + } end end diff --git a/app/models/type_de_champ.rb b/app/models/type_de_champ.rb index 902b3bb66..39b221fa7 100644 --- a/app/models/type_de_champ.rb +++ b/app/models/type_de_champ.rb @@ -532,7 +532,9 @@ class TypeDeChamp < ApplicationRecord end def self.filter_hash_type(type_champ) - if is_choice_type_from(type_champ) + if type_champ == 'multiple_drop_down_list' + :enums + elsif is_choice_type_from(type_champ) :enum else :text diff --git a/app/services/dossier_filter_service.rb b/app/services/dossier_filter_service.rb index 586213451..b046dbe5c 100644 --- a/app/services/dossier_filter_service.rb +++ b/app/services/dossier_filter_service.rb @@ -92,6 +92,9 @@ class DossierFilterService if filtered_column.type == :enum dossiers.with_type_de_champ(column) .filter_enum(:champs, value_column, values) + elsif filtered_column.type == :enums + dossiers.with_type_de_champ(column) + .filter_array_enum(:champs, value_column, values) else dossiers.with_type_de_champ(column) .filter_ilike(:champs, value_column, values) diff --git a/config/brakeman.ignore b/config/brakeman.ignore index 69ad55629..753bf47e5 100644 --- a/config/brakeman.ignore +++ b/config/brakeman.ignore @@ -44,6 +44,29 @@ ], "note": "" }, + { + "warning_type": "SQL Injection", + "warning_code": 0, + "fingerprint": "5092b33433aef8fe42b688a780325f3791a77b39e55131256c78cebc3c14c0a3", + "check_name": "SQL", + "message": "Possible SQL injection", + "file": "app/models/concerns/dossier_filtering_concern.rb", + "line": 46, + "link": "https://brakemanscanner.org/docs/warning_types/sql_injection/", + "code": "where(\"#{values.count} OR #{\"(#{DossierFilterService.sanitized_column(table, column)} = ?)\"}\", *values.map do\n \"[\\\"#{value}\\\"]\"\n end)", + "render_path": null, + "location": { + "type": "method", + "class": "DossierFilteringConcern", + "method": null + }, + "user_input": "values.count", + "confidence": "Medium", + "cwe_id": [ + 89 + ], + "note": "filtered by rails query params where(something: ?, values)" + }, { "warning_type": "SQL Injection", "warning_code": 0, @@ -272,6 +295,6 @@ "note": "Current is not a model" } ], - "updated": "2024-10-15 15:57:27 +0200", + "updated": "2024-10-16 18:07:17 +0200", "brakeman_version": "6.1.2" } diff --git a/spec/services/dossier_filter_service_spec.rb b/spec/services/dossier_filter_service_spec.rb index 95737dd25..5997d46b1 100644 --- a/spec/services/dossier_filter_service_spec.rb +++ b/spec/services/dossier_filter_service_spec.rb @@ -486,6 +486,23 @@ describe DossierFilterService do it { is_expected.to contain_exactly(kept_dossier.id) } end + + context 'with enums type_de_champ' do + let(:filter) { [type_de_champ.libelle, 'Favorable'] } + let(:types_de_champ_public) { [{ type: :multiple_drop_down_list, options: ['Favorable', 'Defavorable'] }] } + + before do + kept_champ = kept_dossier.champs.find_by(stable_id: type_de_champ.stable_id) + kept_champ.value = ['Favorable'] + kept_champ.save! + + discarded_champ = discarded_dossier.champs.find_by(stable_id: type_de_champ.stable_id) + discarded_champ.value = ['Defavorable'] + discarded_champ.save! + end + + it { is_expected.to contain_exactly(kept_dossier.id) } + end end context 'for type_de_champ_private table' do