diff --git a/CHANGELOG.md b/CHANGELOG.md index bd232c2..663257f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ ## 5.0.0 (unreleased) - Searches now use lazy loading (similar to Active Record) +- Added basic protection from unfiltered parameters to `where` option - Anchor regular expressions by default - Raise error when `search` called on relations - Raise `ArgumentError` (instead of warning) for invalid regular expression modifiers diff --git a/lib/searchkick/query.rb b/lib/searchkick/query.rb index 5272801..6945b1e 100644 --- a/lib/searchkick/query.rb +++ b/lib/searchkick/query.rb @@ -435,7 +435,7 @@ module Searchkick payload = {} # type when inheritance - where = (options[:where] || {}).dup + where = ensure_permitted(options[:where] || {}).dup if searchkick_options[:inheritance] && (options[:type] || (klass != searchkick_klass && searchkick_index)) where[:type] = [options[:type] || klass].flatten.map { |v| searchkick_index.klass_document_type(v, true) } end @@ -832,8 +832,9 @@ module Searchkick end where = {} - where = (options[:where] || {}).reject { |k| k == field } unless options[:smart_aggs] == false - agg_filters = where_filters(where.merge(agg_options[:where] || {})) + where = ensure_permitted(options[:where] || {}).reject { |k| k == field } unless options[:smart_aggs] == false + agg_where = ensure_permitted(agg_options[:where] || {}) + agg_filters = where_filters(where.merge(agg_where)) # only do one level comparison for simplicity filters.select! do |filter| @@ -872,12 +873,13 @@ module Searchkick payload[:sort] = options[:order].is_a?(Enumerable) ? options[:order] : {options[:order] => :asc} end - def where_filters(where) - # if where.respond_to?(:permitted?) && !where.permitted? - # # TODO check in more places - # Searchkick.warn("Passing unpermitted parameters will raise an exception in Searchkick 5") - # end + # provides *very* basic protection from unfiltered parameters + # this is not meant to be comprehensive and may be expanded in the future + def ensure_permitted(obj) + obj.to_h + end + def where_filters(where) filters = [] (where || {}).each do |field, value| field = :_id if field.to_s == "id" diff --git a/test/parameters_test.rb b/test/parameters_test.rb index 297a98f..62d0589 100644 --- a/test/parameters_test.rb +++ b/test/parameters_test.rb @@ -6,17 +6,30 @@ class ParametersTest < Minitest::Test super end - def test_where_unpermitted - # TODO raise error in Searchkick 6 - store [{name: "Product A", store_id: 1}, {name: "Product B", store_id: 2}] + def test_options params = ActionController::Parameters.new({store_id: 1}) - assert_search "product", ["Product A"], where: params + assert_raises(ActionController::UnfilteredParameters) do + Product.search("*", **params) + end + end + + def test_where + params = ActionController::Parameters.new({store_id: 1}) + assert_raises(ActionController::UnfilteredParameters) do + Product.search("*", where: params) + end end def test_where_permitted store [{name: "Product A", store_id: 1}, {name: "Product B", store_id: 2}] params = ActionController::Parameters.new({store_id: 1}) - assert_search "product", ["Product A"], where: params.permit! + assert_search "product", ["Product A"], where: params.permit(:store_id) + end + + def test_where_value + store [{name: "Product A", store_id: 1}, {name: "Product B", store_id: 2}] + params = ActionController::Parameters.new({store_id: 1}) + assert_search "product", ["Product A"], where: {store_id: params[:store_id]} end def test_where_hash @@ -26,4 +39,18 @@ class ParametersTest < Minitest::Test end assert_equal error.message, "can't cast ActionController::Parameters" end + + def test_aggs_where + params = ActionController::Parameters.new({store_id: 1}) + assert_raises(ActionController::UnfilteredParameters) do + Product.search("*", aggs: {size: {where: params}}) + end + end + + def test_aggs_where_smart_aggs_false + params = ActionController::Parameters.new({store_id: 1}) + assert_raises(ActionController::UnfilteredParameters) do + Product.search("*", aggs: {size: {where: params}}, smart_aggs: false) + end + end end -- libgit2 0.21.0