# Copyright (c) 2022 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details. # frozen_string_literal: true require 'contrast/components/logger' require 'contrast/agent/reporting/reporting_events/application_defend_attacker_activity' module Contrast module Agent module Reporting # This is the new ApplicationDefendActivity class which includes information about the defense of the application # which was discovered during exercise of the application during this activity period. class ApplicationDefendActivity # @return [Array] attr_reader :attackers def initialize @attackers = [] @event_type = :application_defend_activity end def to_controlled_hash { attackers: attackers.map(&:to_controlled_hash) } end # @param attack_result [Contrast::Agent::Reporting::AttackResult] def attach_data attack_result attacker_activity = Contrast::Agent::Reporting::ApplicationDefendAttackerActivity.new attacker_activity.attach_data(attack_result) existing_attacker_activity = attackers.find do |existing| existing.source_forwarded_for == attacker_activity.source_forwarded_for && existing.source_ip == attacker_activity.source_ip end rule = attack_result.rule_id if existing_attacker_activity attach_existing(existing_attacker_activity, attacker_activity, rule) else attackers << attacker_activity end end # @param existing_attacker_activity [Contrast::Agent::Reporting::ApplicationDefendAttackerActivity] # @param attacker_activity [Contrast::Agent::Reporting::ApplicationDefendAttackerActivity] # @param rule [String] def attach_existing existing_attacker_activity, attacker_activity, rule new_violation = attacker_activity.protection_rules[rule] sample_activity = Contrast::Agent::Reporting::ApplicationDefendAttackSampleActivity if (previously_violated = existing_attacker_activity.protection_rules[rule]) if (new_blocked = new_violation.blocked) previously_violated.blocked ||= sample_activity.new previously_violated.blocked.samples.concat(new_blocked.samples) if new_blocked.samples previously_violated.blocked.merge_time_maps(new_blocked.time_map) end if (new_exploited = new_violation.exploited) previously_violated.exploited ||= sample_activity.new previously_violated.exploited.samples.concat(new_exploited.samples) if new_exploited.samples previously_violated.exploited.merge_time_maps(new_exploited.time_map) end if (new_ineffective = new_violation.ineffective) previously_violated.ineffective ||= sample_activity.new previously_violated.ineffective.samples.concat(new_ineffective.samples) if new_ineffective.samples previously_violated.ineffective.merge_time_maps(new_ineffective.time_map) end if (new_suspicious = new_violation.suspicious) previously_violated.suspicious ||= sample_activity.new previously_violated.suspicious.samples.concat(new_suspicious.samples) if new_suspicious.samples previously_violated.suspicious.merge_time_maps(new_suspicious.time_map) end else existing_attacker_activity.protection_rules[rule] = new_violation end end end end end end