# Copyright (c) 2020 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details. # frozen_string_literal: true cs__scoped_require 'contrast/components/interface' if defined?(ActiveRecord) && defined?(ActiveRecord::Scoping) && defined?(ActiveRecord::Scoping::Named) && defined?(ActiveRecord::Scoping::Named::ClassMethods) && ActiveRecord::Scoping::Named::ClassMethods. instance_methods(false). include?(:scope) module ActiveRecord module Scoping module Named # Our patch into the ActiveRecord::Scoping::Named::ClassMethods Module, # allowing for the runtime rewrite of interpolation calls defined in # methods defined dynamically during application execution. # # TODO: RUBY-534 module ClassMethods include Contrast::Components::Interface access_component :logging, :agent def _cs__rewrite method_name, body return body unless AGENT.rewrite_interpolation? return body unless body.is_a?(Proc) location = body.source_location return body if location.nil? # Good news, once we patch the body once, the source location # becomes eval. We may need to fix this later though (so it may # be bad news) return body if location.empty? || location[0].empty? || location[0].include?('eval') opener = Contrast::Agent::ClassReopener.new(Contrast::Agent::ModuleData.new(self)) original_source_code = opener.source_code(location, method_name) return body unless original_source_code return body if Contrast::Agent::Rewriter.send(:unrepeatable?, original_source_code) return body unless Contrast::Agent::Rewriter.send(:interpolations?, original_source_code) # the code looks like 'source :some_method_name, ->lambda_literal' # we just need the lambda body_start = original_source_code.index(',') + 1 original_source_code = original_source_code[body_start..-1] new_method_source = Contrast::Agent::Rewriter.send(:rewrite_method, original_source_code) return body unless Contrast::Agent::Rewriter.send(:valid_code?, new_method_source) unbound_eval(cs__name, new_method_source) rescue SyntaxError, StandardError => e logger.debug(e, "Can't parse method source in scoped method #{ method_name }: #{ e.message }") body end end end end end cs__scoped_require 'cs__assess_active_record_named/cs__assess_active_record_named' end