aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGuillaume Malette <gmalette@gmail.com>2014-01-31 03:50:09 +0000
committerGuillaume Malette <guillaume@shopify.com>2015-06-22 10:04:11 -0400
commit33b93174f0db9783b3c6c906666923103569c6a3 (patch)
tree2cdbdefab1159e4c8d1f17ceb4bb58b27ddb02f1
parentebc4c607a7859c9c35246d7fe74a17208ef3a66e (diff)
downloadrails-33b93174f0db9783b3c6c906666923103569c6a3.tar.gz
rails-33b93174f0db9783b3c6c906666923103569c6a3.tar.bz2
rails-33b93174f0db9783b3c6c906666923103569c6a3.zip
Allow filtering params based on parent keys
Add the possibility to only filter parameters based on their full path instead of relying on the immediate key. config.filter_parameters += ['credit_card.code'] { 'credit_card' => { 'code' => '[FILTERED]' }, 'source' => { 'code' => '<%= puts 5 %>' } }
-rw-r--r--actionpack/CHANGELOG.md10
-rw-r--r--actionpack/lib/action_dispatch/http/parameter_filter.rb24
-rw-r--r--actionpack/test/dispatch/request_test.rb1
3 files changed, 28 insertions, 7 deletions
diff --git a/actionpack/CHANGELOG.md b/actionpack/CHANGELOG.md
index cb5e7516fb..46856ffc5d 100644
--- a/actionpack/CHANGELOG.md
+++ b/actionpack/CHANGELOG.md
@@ -1,3 +1,13 @@
+* Add ability to filter parameters based on parent keys.
+
+ # matches {credit_card: {code: "xxxx"}}
+ # doesn't match {file: { code: "xxxx"}}
+ config.filter_parameters += [ "credit_card.code" ]
+
+ See #13897.
+
+ *Guillaume Malette*
+
* Deprecate passing first parameter as `Hash` and default status code for `head` method.
*Mehmet Emin İNAÇ*
diff --git a/actionpack/lib/action_dispatch/http/parameter_filter.rb b/actionpack/lib/action_dispatch/http/parameter_filter.rb
index df4b073a17..6e058b829e 100644
--- a/actionpack/lib/action_dispatch/http/parameter_filter.rb
+++ b/actionpack/lib/action_dispatch/http/parameter_filter.rb
@@ -30,36 +30,46 @@ module ActionDispatch
when Regexp
regexps << item
else
- strings << item.to_s
+ strings << Regexp.escape(item.to_s)
end
end
+ deep_regexps, regexps = regexps.partition { |r| r.to_s.include?("\\.") }
+ deep_strings, strings = strings.partition { |s| s.include?("\\.") }
+
regexps << Regexp.new(strings.join('|'), true) unless strings.empty?
- new regexps, blocks
+ deep_regexps << Regexp.new(deep_strings.join('|'), true) unless deep_strings.empty?
+
+ new regexps, deep_regexps, blocks
end
- attr_reader :regexps, :blocks
+ attr_reader :regexps, :deep_regexps, :blocks
- def initialize(regexps, blocks)
+ def initialize(regexps, deep_regexps, blocks)
@regexps = regexps
+ @deep_regexps = deep_regexps.any? ? deep_regexps : nil
@blocks = blocks
end
- def call(original_params)
+ def call(original_params, parents = [])
filtered_params = {}
original_params.each do |key, value|
+ parents.push(key) if deep_regexps
if regexps.any? { |r| key =~ r }
value = FILTERED
+ elsif deep_regexps && (joined = parents.join('.')) && deep_regexps.any? { |r| joined =~ r }
+ value = FILTERED
elsif value.is_a?(Hash)
- value = call(value)
+ value = call(value, parents)
elsif value.is_a?(Array)
- value = value.map { |v| v.is_a?(Hash) ? call(v) : v }
+ value = value.map { |v| v.is_a?(Hash) ? call(v, parents) : v }
elsif blocks.any?
key = key.dup if key.duplicable?
value = value.dup if value.duplicable?
blocks.each { |b| b.call(key, value) }
end
+ parents.pop if deep_regexps
filtered_params[key] = value
end
diff --git a/actionpack/test/dispatch/request_test.rb b/actionpack/test/dispatch/request_test.rb
index 27ee8603e4..ff63c10e8d 100644
--- a/actionpack/test/dispatch/request_test.rb
+++ b/actionpack/test/dispatch/request_test.rb
@@ -989,6 +989,7 @@ class RequestParameterFilter < BaseRequestTest
[{'foo'=>'bar', 'baz'=>'foo'},{'foo'=>'[FILTERED]', 'baz'=>'[FILTERED]'},%w'foo baz'],
[{'bar'=>{'foo'=>'bar','bar'=>'foo'}},{'bar'=>{'foo'=>'[FILTERED]','bar'=>'foo'}},%w'fo'],
[{'foo'=>{'foo'=>'bar','bar'=>'foo'}},{'foo'=>'[FILTERED]'},%w'f banana'],
+ [{'deep'=>{'cc'=>{'code'=>'bar','bar'=>'foo'},'ss'=>{'code'=>'bar'}}},{'deep'=>{'cc'=>{'code'=>'[FILTERED]','bar'=>'foo'},'ss'=>{'code'=>'bar'}}},%w'deep.cc.code'],
[{'baz'=>[{'foo'=>'baz'}, "1"]}, {'baz'=>[{'foo'=>'[FILTERED]'}, "1"]}, [/foo/]]]
test_hashes.each do |before_filter, after_filter, filter_words|