# Copyright (c) 2021 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 exactly as is. The target's preexisting tags # are unaffected beyond any merging of overlapping tags. class MatchData < Contrast::Agent::Assess::Policy::Propagator::Base class << self def square_bracket_tagger propagation_node, preshift, ret, _block case ret when Array idx = 0 while idx < ret.length return_value = ret[idx] index = idx idx += 1 next unless return_value square_bracket_single(target_matchdata_index(preshift, index), preshift, return_value, propagation_node) end when String target_matchdata_index = preshift.args[0] square_bracket_single(target_matchdata_index, preshift, ret, propagation_node) end ret end def captures_tagger propagation_node, preshift, ret, _block idx = 0 while idx < ret.length return_value = ret[idx] index = idx idx += 1 next unless return_value targetted_index = index + 1 square_bracket_single(targetted_index, preshift, return_value, propagation_node) end ret end def to_a_tagger propagation_node, preshift, ret, _block idx = 0 while idx < ret.length return_value = ret[idx] index = idx idx += 1 next unless return_value square_bracket_single(index, preshift, return_value, propagation_node) end ret end def values_at_tagger propagation_node, preshift, ret, _block idx = 0 while idx < ret.length return_value = ret[idx] return_index = idx idx += 1 next unless return_value original_group_arg_index = preshift.args[return_index] square_bracket_single(original_group_arg_index, preshift, return_value, propagation_node) end ret end private def target_matchdata_index preshift, index if preshift.args[0].is_a?(Range) arg_range = preshift.args[0] arg_range.to_a.empty? ? index + 1 : arg_range.to_a[index] else preshift.args[index] end end def square_bracket_single argument_index, preshift, return_value, propagation_node original_start_index = preshift.object.begin(argument_index) original_end_index = preshift.object.end(argument_index) return unless (original_properties = Contrast::Agent::Assess::Tracker.properties(preshift.object)) applicable_tags = original_properties.tags_at_range(original_start_index...original_end_index) return if applicable_tags.empty? return unless (return_properties = Contrast::Agent::Assess::Tracker.properties!(return_value)) applicable_tags.each do |tag_name, tag_ranges| return_properties.set_tags(tag_name, tag_ranges) end return_properties.build_event(propagation_node, return_value, preshift.object, return_value, preshift.args) end end end end end end end end