require 'active_support/core_ext/object/blank' require 'active_support/core_ext/hash/keys' module ActionDispatch module Http # Allows you to specify sensitive parameters which will be replaced from # the request log by looking in all subhashes of the param hash for keys # to filter. If a block is given, each key and value of the parameter # hash and all subhashes is passed to it, the value or key can be replaced # using String#replace or similar method. # # Examples: # # env["action_dispatch.parameter_filter"] = [:password] # => replaces the value to all keys matching /password/i with "[FILTERED]" # # env["action_dispatch.parameter_filter"] = [:foo, "bar"] # => replaces the value to all keys matching /foo|bar/i with "[FILTERED]" # # env["action_dispatch.parameter_filter"] = lambda do |k,v| # v.reverse! if k =~ /secret/i # end # => reverses the value to all keys matching /secret/i # module FilterParameters extend ActiveSupport::Concern # Return a hash of parameters with all sensitive data replaced. def filtered_parameters @filtered_parameters ||= process_parameter_filter(parameters) end alias :fitered_params :filtered_parameters # Return a hash of request.env with all sensitive data replaced. def filtered_env filtered_env = @env.dup filtered_env.each do |key, value| if (key =~ /RAW_POST_DATA/i) filtered_env[key] = '[FILTERED]' elsif value.is_a?(Hash) filtered_env[key] = process_parameter_filter(value) end end filtered_env end protected def compile_parameter_filter #:nodoc: strings, regexps, blocks = [], [], [] Array(@env["action_dispatch.parameter_filter"]).each do |item| case item when NilClass when Proc blocks << item when Regexp regexps << item else strings << item.to_s end end regexps << Regexp.new(strings.join('|'), true) unless strings.empty? [regexps, blocks] end def filtering_parameters? #:nodoc: @env["action_dispatch.parameter_filter"].present? end def process_parameter_filter(original_params) #:nodoc: return original_params.dup unless filtering_parameters? filtered_params = {} regexps, blocks = compile_parameter_filter original_params.each do |key, value| if regexps.find { |r| key =~ r } value = '[FILTERED]' elsif value.is_a?(Hash) value = process_parameter_filter(value) elsif value.is_a?(Array) value = value.map { |i| process_parameter_filter(i) } elsif blocks.present? key = key.dup value = value.dup if value.duplicable? blocks.each { |b| b.call(key, value) } end filtered_params[key] = value end filtered_params end end end end