# 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' 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 :agent, :logging 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 unless _cs__location_available?(location) 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('Can\'t parse method source in scoped method', e, method: method_name) body end # 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) def _cs__location_available? location return false if location.nil? return false if location.empty? || location[0].empty? || location[0].include?('eval') true end end end end end cs__scoped_require 'cs__assess_active_record_named/cs__assess_active_record_named'