# 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/agent/assess/policy/propagation_node' cs__scoped_require 'contrast/components/interface' cs__scoped_require 'contrast/extensions/ruby_core/assess/assess_extension' # This patch installs our extension as early as possible. The alternative is to # litter our code with Contrast::Utils::DuckUtils.trackable? checks. class String include Contrast::CoreExtensions::Assess::AssessExtension end module Contrast module CoreExtensions module Assess # This Class provides us with a way to invoke String propagation for those # methods which are too complex to fit into one of the standard # Contrast::Agent::Assess::Policy::Propagator molds without cluttering up the # String Class or exposing our methods there. class StringPropagator include Contrast::Components::Interface access_component :agent, :analysis, :logging, :scope NODE_HASH = { 'class_name' => 'String', 'instance_method' => true, 'method_name' => 'interpolate', 'method_visibility' => 'public', 'action' => 'CUSTOM', 'source' => 'O,P0', 'target' => 'R', 'patch_class' => 'NOOP', 'patch_method' => 'track_interpolation' }.cs__freeze INTERPOLATION_NODE = Contrast::Agent::Assess::Policy::PropagationNode.new(NODE_HASH) class << self def track_interpolation inputs, result return unless AGENT.interpolation_enabled? return if in_contrast_scope? return unless inputs.any?(&:cs__tracked?) with_contrast_scope do offset = 0 inputs.each do |input| result.cs__copy_from(input, offset) offset += input.length end result.cs__properties.build_event(INTERPOLATION_NODE, result, inputs, result, inputs) end end def instrument_string @_instrument_string ||= begin cs__scoped_require 'cs__assess_string/cs__assess_string' true end rescue StandardError => e logger.error('Error loading hash track patch', e) false end def instrument_string_interpolation if @_instrument_string_interpolation.nil? @_instrument_string_interpolation = begin if AGENT.patch_interpolation? cs__scoped_require 'cs__assess_string_interpolation26/cs__assess_string_interpolation26' end true rescue StandardError => e logger.error('Error loading interpolation patch', e) false end end @_instrument_string_interpolation end end end end end end