# Copyright (c) 2023 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details. # frozen_string_literal: true require 'contrast/utils/timer' require 'contrast/agent/reporting/reporting_events/application_defend_attack_sample' require 'contrast/agent/reporting/reporting_events/reportable_hash' module Contrast module Agent module Reporting # This is the new AttackerSampleActivity class which will include Sample of the given attacks in the activity # period. class ApplicationDefendAttackSampleActivity < Contrast::Agent::Reporting::ReportableHash # @return [Array<Contrast::Agent::Reporting::ApplicationDefendAttackSample>] attr_reader :samples # @return [Hash<Integer,Integer>] map of time from start in seconds to number of attacks in that second attr_reader :time_map def initialize @samples = [] @start_time = Contrast::Agent::REQUEST_TRACKER.current&.timer&.start_ms || 0 # in ms @event_type = :application_defend_attack_sample_activity @time_map = Hash.new { |h, k| h[k] = 0 } super() end def to_controlled_hash validate { attackTimeMap: time_map, samples: samples.map(&:to_controlled_hash), startTime: @start_time, # Start time in ms. total: 1 # there will only ever be 1 attack sample, until batching is done } end def validate raise(ArgumentError, 'Start Time is not presented') unless @start_time end # @param attack_result [Contrast::Agent::Reporting::AttackResult] def attach_data attack_result attack_result.samples.each do |attack_sample| base_time = Contrast::Agent::REQUEST_TRACKER.current&.timer&.start_ms || 0 sample_time = attack_sample.time_stamp.to_i samples << Contrast::Agent::Reporting::ApplicationDefendAttackSample.convert(attack_result, attack_sample) @start_time = if sample_time.zero? @start_time else sample_time end attack_second = (@start_time - base_time) / 1000 # in seconds time_map[attack_second] += 1 end end # This method will merge time_maps of attack samples with same # type. # # @param map [Hash<Integer,Integer>] TimeMap to append to previously_violated rule # samples. # @return time_map [Hash<Integer,Integer>] merged time map with updated occurrences. def merge_time_maps map # If the second is the same (key) if we just merge there won't be a new entry, # so just increase the attack count. map.each_key do |key| @time_map[key] = @time_map.fetch(key, 0) + map[key] end @time_map end end end end end