# Copyright (c) 2023 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details. # frozen_string_literal: true module Contrast module Agent module Assess module Policy module Propagator # Propagation that results in all the tags of the source being # applied to the target at the point of insertion. The target's # preexisting tags are shifted to account for this insertion. class Insert < Contrast::Agent::Assess::Policy::Propagator::Base class << self # For the source, append its tags to the target. # Once the tag is applied, shift it to the location of the insert # Unlike additive propagation, this currently only supports one source # We assume that insert changes the preshift target # # @param propagation_node [Contrast::Agent::Assess::Policy::PropagationNode] the node responsible for the # propagation action required by this method. # @param preshift [Object] pre call state of the things. # @param target [Object] the object to which the source is being appended # @return [Object] the target with the tags applied def propagate propagation_node, preshift, target return unless (properties = Contrast::Agent::Assess::Tracker.properties!(target)) source = find_source(propagation_node.sources[1], preshift) patcher_target = propagation_node.targets[0] preshift_target = case patcher_target when Contrast::Utils::ObjectShare::OBJECT_KEY preshift.object else # this is hardly reached b/c insert supports only one source # changed to second argument: string.insert[idx, string_to_insert] # previously was args[int] => produces exception preshift.args[1] end # Find the first difference between the source to which # we inserted and the result. That is the insertion # point on which all tags need to be adjusted # If the insertion point is the end of the string, preshift length is returned # https://stackoverflow.com/questions/31714522/find-the-first-differing-character-between-two-strings-in-ruby insert_point = (0...preshift_target.length).find do |i| preshift_target[i] != target[i] end || preshift_target.length # Depending what's inserted, we might be wrong. For instance, inserting 'foo' # into 'asdfasdf' could result in 'asdfoofasdf'. we'd be off by one b/c of the 'f' insert_point = target.rindex(source, insert_point) overflow = insert_point...(insert_point + source.length) # handle shifting the inserted range properties.shift_tags([overflow]) properties.copy_from(source, target, insert_point, propagation_node.untags) properties.cleanup_tags end end end end end end end end