class RuboCop::Cop::Betterment::AuthorizationInController
Constants
- MSG_UNSAFE_CREATE
MSG_UNSAFE_CREATE
= 'Model created/updated using unsafe parameters'.freeze
Attributes
unsafe_parameters[RW]
unsafe_regex[RW]
Public Class Methods
new(config = nil, options = nil)
click to toggle source
Calls superclass method
# File lib/rubocop/cop/betterment/authorization_in_controller.rb, line 34 def initialize(config = nil, options = nil) super(config, options) config = @config.for_cop(self) @unsafe_parameters = config.fetch("unsafe_parameters", []).map(&:to_sym) @unsafe_regex = Regexp.new config.fetch("unsafe_regex", ".*_id$") @wrapper_methods = {} @wrapper_names = [] end
Public Instance Methods
on_class(node)
click to toggle source
# File lib/rubocop/cop/betterment/authorization_in_controller.rb, line 43 def on_class(node) track_methods(node) track_assignments(node) end
on_send(node)
click to toggle source
# File lib/rubocop/cop/betterment/authorization_in_controller.rb, line 48 def on_send(node) # rubocop:disable Metrics/AbcSize,Metrics/PerceivedComplexity _receiver_node, _method_name, *arg_nodes = *node return if !model_new?(node) && !model_update?(node) arg_nodes.each do |argument| if argument.send_type? tag_unsafe_param_hash(argument) tag_unsafe_param_permit_wrapper(argument) elsif argument.variable? tag_unsafe_param_permit_wrapper(argument) elsif argument.hash_type? argument.children.each do |pair| next if pair.type != :pair _key, value = *pair.children tag_unsafe_param_hash(value) tag_unsafe_param_permit_wrapper(value) end end end end
Private Instance Methods
array_or_hash?(arg)
click to toggle source
# File lib/rubocop/cop/betterment/authorization_in_controller.rb, line 185 def array_or_hash?(arg) %i(array hash).include?(arg.type) end
contains_id_param?(arg_nodes)
click to toggle source
# File lib/rubocop/cop/betterment/authorization_in_controller.rb, line 189 def contains_id_param?(arg_nodes) arg_nodes.any? do |arg| sym_or_str?(arg) && suspicious_id?(arg.value) || array_or_hash?(arg) && contains_id_param?(arg.values) end end
extract_parameter(argument)
click to toggle source
# File lib/rubocop/cop/betterment/authorization_in_controller.rb, line 201 def extract_parameter(argument) _receiver_node, method_name, *arg_nodes = *argument return unless argument.send_type? && method_name == :[] argument_name = Utils::Parser.get_root_token(argument) if param_symbol?(argument_name) || @wrapper_names.include?(argument_name) arg_nodes.find do |arg| sym_or_str?(arg) && suspicious_id?(arg.value) end end end
get_all_assignments(node)
click to toggle source
# File lib/rubocop/cop/betterment/authorization_in_controller.rb, line 132 def get_all_assignments(node) return [] unless node.children && node.class_type? node.descendants.select do |descendant| _lhs, rhs = *descendant descendant.equals_asgn? && (descendant.type != :casgn) && rhs&.send_type? end end
get_all_methods(node)
click to toggle source
# File lib/rubocop/cop/betterment/authorization_in_controller.rb, line 145 def get_all_methods(node) return [] unless node.children && node.class_type? node.descendants.select do |descendant| descendant.def_type? end end
get_param_wrappers(methods)
click to toggle source
this finds all calls to any method on a params like object then walks up to find calls to permit if the arguments to permit are “suspicious”, then we add the whole method to a list of methods that wrap params.permit
# File lib/rubocop/cop/betterment/authorization_in_controller.rb, line 157 def get_param_wrappers(methods) # rubocop:disable Metrics/AbcSize,Metrics/PerceivedComplexity wrappers = [] methods.each do |method| return [] unless method.def_type? || method.send_type? method.descendants.each do |child| next unless child.send_type? next unless param_symbol?(child.method_name) child.ancestors.each do |ancestor| _receiver_node, method_name, *arg_nodes = *ancestor next unless ancestor.send_type? next unless method_name == :permit # we're only interested in calls to params.....permit(...) wrappers << method if contains_id_param?(arg_nodes) end end end wrappers end
param_symbol?(name)
click to toggle source
# File lib/rubocop/cop/betterment/authorization_in_controller.rb, line 141 def param_symbol?(name) name == :params end
suspicious_id?(symbol_name)
click to toggle source
check a symbol name against the cop's config parameters
# File lib/rubocop/cop/betterment/authorization_in_controller.rb, line 197 def suspicious_id?(symbol_name) @unsafe_parameters.include?(symbol_name.to_sym) || @unsafe_regex.match(symbol_name) # symbol_name.to_s.end_with?("_id") end
sym_or_str?(arg)
click to toggle source
# File lib/rubocop/cop/betterment/authorization_in_controller.rb, line 181 def sym_or_str?(arg) %i(sym str).include?(arg.type) end
tag_unsafe_param_hash(node)
click to toggle source
# File lib/rubocop/cop/betterment/authorization_in_controller.rb, line 73 def tag_unsafe_param_hash(node) unsafe_param = extract_parameter(node) add_offense(unsafe_param, message: MSG_UNSAFE_CREATE) if unsafe_param end
tag_unsafe_param_permit_wrapper(node)
click to toggle source
# File lib/rubocop/cop/betterment/authorization_in_controller.rb, line 78 def tag_unsafe_param_permit_wrapper(node) return if !node.send_type? && !node.variable? return if node.send_type? && (node.method_name == :[]) name = Utils::Parser.get_root_token(node) add_offense(node, message: MSG_UNSAFE_CREATE) if @wrapper_names.include?(name) end
track_assignments(node)
click to toggle source
keep track of all assignments that hold parameters
# File lib/rubocop/cop/betterment/authorization_in_controller.rb, line 103 def track_assignments(node) get_all_assignments(node).each do |assignment| variable_name, value = *assignment # if rhs calls params.permit, eg # - @var = params.permit(...) rhs_wrapper = get_param_wrappers([value]) unless rhs_wrapper.empty? @wrapper_methods[variable_name] = rhs_wrapper[0] @wrapper_names << variable_name end # if rhs is a call to a parameter wrapper, eg # @var = parameter_wrapper root_token = Utils::Parser.get_root_token(value) if root_token && @wrapper_names.include?(root_token) @wrapper_methods[variable_name] = assignment @wrapper_names << variable_name end # if rhs extracts a parameter, eg # @var = params[:user_id] if extract_parameter(value) @wrapper_methods[variable_name] = assignment @wrapper_names << variable_name end end end
track_methods(node)
click to toggle source
if a method returns params or params.permit(…) then it will be tracked; if the method does not explicitly return a params sourced argument, then it will not be tracked
# File lib/rubocop/cop/betterment/authorization_in_controller.rb, line 89 def track_methods(node) methods = get_all_methods(node) methods.map do |method| method_returns = Utils::Parser.get_return_values(method) unless get_param_wrappers(method_returns).empty? @wrapper_methods[method.method_name] = method @wrapper_names << method.method_name end end end