# 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/utils/object_share' cs__scoped_require 'contrast/agent/patching/policy/patch_status' cs__scoped_require 'contrast/agent/module_data' cs__scoped_require 'contrast/agent/rewriter' cs__scoped_require 'contrast/components/interface' module Contrast module Agent module Assess module Policy # This is our interface from the Patcher to the Rewriter # functionality # # TODO: RUBY-714 remove w/ EOL of 2.5 # @deprecated Changes to this class are discouraged as this approach is # being phased out with support for those language versions. module RewriterPatch include Contrast::Components::Interface access_component :agent, :analysis, :logging class << self def rewrite_interpolations return unless ASSESS.enabled? return unless AGENT.rewrite_interpolation? logger.debug_with_time("\t\tRunning Assess interpolation rewrite") do ObjectSpace.each_object(Module) do |mod| rewrite_interpolation(mod) end end end # Rails is being a jerk, again. It passes in a class before it is # done being defined. There is a state where the files have been # loaded, but the class definition is not complete, so the # methods of the class are not defined despite the class existing # # To get around this, we have those methods tell us the class # isn't ready def mid_defining? mod mod.instance_variable_defined?(:@cs__defining_class) && mod.instance_variable_get(:@cs__defining_class) end def rewrite_interpolation mod, redo_rewrite = false return unless ASSESS.enabled? return unless AGENT.rewrite_interpolation? return unless AGENT.interpolation_enabled? return if AGENT.skip_instrumentation? mod.cs__name return if mod.cs__frozen? return if mod.singleton_class? return if mid_defining?(mod) status = Contrast::Agent::Patching::Policy::PatchStatus.get_status(mod) return if (status&.rewritten? || status&.rewriting?) && !redo_rewrite module_name = mod.cs__name return unless module_name if module_name.start_with?(Contrast::Utils::ObjectShare::CONTRAST_MODULE_START, Contrast::Utils::ObjectShare::ANONYMOUS_CLASS_MARKER) status.no_rewrite! return end module_data = Contrast::Agent::ModuleData.new(mod, module_name) logger.debug_with_time("\t\t\tRewriting #{ module_name }") do Contrast::Agent::Rewriter.rewrite_class(module_data, redo_rewrite) end rescue StandardError => e logger.error( e, "Unable to patch assess into the module #{ mod }") end end end end end end end