Skip to content

Instantly share code, notes, and snippets.

@ndbroadbent
Created April 27, 2019 13:35
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ndbroadbent/0f9e01af5f03be81580e7792e85ffbb7 to your computer and use it in GitHub Desktop.
Save ndbroadbent/0f9e01af5f03be81580e7792e85ffbb7 to your computer and use it in GitHub Desktop.
Monkey Patch for ActionDispatch::Http::ParameterFilter::CompiledFilter to support more complex filtering rules
# lib/action_dispatch_parameter_filter.rb
require 'action_dispatch/http/parameter_filter'
if Rails.version != '5.2.2.1'
raise "You've updated the Rails version. " \
"Please check #{__FILE__} and ensure that everything still works."
end
module ActionDispatch
module Http
class ParameterFilter
class CustomFilter
def filter(_params)
raise 'Not implemented!'
end
end
class CompiledFilter # :nodoc:
def self.compile(filters)
return ->(params) { params.dup } if filters.empty?
strings = []
regexps = []
blocks = []
custom_filters = []
filters.each do |item|
case item
when Proc
blocks << item
when CustomFilter
custom_filters << item
when Regexp
regexps << item
else
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?
deep_regexps << Regexp.new(deep_strings.join('|'), true) unless deep_strings.empty?
new regexps, deep_regexps, blocks, custom_filters
end
# attr_reader :regexps, :deep_regexps, :blocks, :custom_filters
attr_reader :custom_filters
def initialize(regexps, deep_regexps, blocks, custom_filters)
@regexps = regexps
@deep_regexps = deep_regexps.any? ? deep_regexps : nil
@blocks = blocks
@custom_filters = custom_filters
end
def call(original_params, parents = [])
custom_filtered_params = original_params
if custom_filters.any?
custom_filters.each do |filter|
custom_filtered_params = filter.filter(custom_filtered_params)
end
end
filtered_params = original_params.class.new
custom_filtered_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, parents)
elsif value.is_a?(Array)
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
filtered_params
end
end
end
end
end
# lib/my_app/custom_parameter_filter.rb
module MyApp
class CustomParameterFilter < ActionDispatch::Http::ParameterFilter::CustomFilter
def filter(params)
case [params[:controller], params[:action]]
when ['api/v1/my_controller', 'create']
cloned_params = params.dup
cloned_params[:data] = ActionDispatch::Http::ParameterFilter::FILTERED
return cloned_params
end
params
end
end
end
# config/initializers/filter_parameter_logging.rb
# Be sure to restart your server when you modify this file.
# Configure sensitive parameters which will be filtered from the log file.
Rails.application.config.filter_parameters += %i[
password
password_confirmation
]
Rails.application.config.filter_parameters << MyApp::CustomParameterFilter.new
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment