# Copyright (c) 2022 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details. # frozen_string_literal: true module Contrast module Utils module Patching # This module will include patch methods from Patcher module # in case of need to add new logic to the Patcher # please do it here module PatcherUtils # This method is called by TracePointHook to instrument a specific class during a require # or eval of dynamic class definition def patch_specific_module mod with_contrast_scope do mod_name = mod.cs__name return unless Contrast::Utils::ClassUtil.truly_defined?(mod_name) return if ::Contrast::AGENT.skip_instrumentation?(mod_name) load_patches_for_module(mod_name) return if all_module_names.none?(mod_name) module_data = Contrast::Agent::ModuleData.new(mod, mod_name) patch_into_module(module_data) all_module_names.delete(mod_name) if status_type.get_status(mod).patched? rescue StandardError => e logger.error('Unable to patch module', e, module: mod_name) end end # We did it, team. We found a patcher(s) that applies to the given # class (or module) and the given method. Time to do some tracking. # # @param mod [Module] the module in which the patch should be # placed. # @param methods [Array(Symbol)] all the instance or singleton # methods in this mod. # @param method_policy [Contrast::Agent::Patching::Policy::MethodPolicy] # the policy that applies to the given method_name. # @return [Boolean] if patched, either by this invocation or a # previous, or not def patch_method mod, methods, method_policy return false unless methods&.any? # don't even build the name if there are no methods if Contrast::Utils::ClassUtil.prepended_method?(mod, method_policy) Contrast::Agent::Patching::Policy::Patch.instrument_with_prepend(mod, method_policy) else Contrast::Agent::Patching::Policy::Patch.instrument_with_alias(mod, methods, method_policy) end end end end end end