# Copyright (c) 2022 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details. # frozen_string_literal: true require 'contrast/agent/worker_thread' require 'contrast/agent/reporting/report' require 'contrast/components/logger' module Contrast module Agent # This module will hold everything essential to reporting to TeamServer class Reporter < WorkerThread include Contrast::Components::Logger::InstanceMethods include Contrast::Utils::ObjectShare # 15 min TIMEOUT = 900.cs__freeze class << self # check if we can report to TS # # @return[Boolean] true if bypass is enabled, or false if bypass disabled def enabled? @_enabled = Contrast::CONTRAST_SERVICE.use_agent_communication? if @_enabled.nil? @_enabled end end def client @_client ||= Contrast::Agent::Reporting::ReporterClient.new end def connection @_connection ||= client.initialize_connection end def audit @_audit ||= Contrast::Agent::Reporting::Audit.new end def attempt_to_start? unless cs__class.enabled? logger.warn('Reporter service is disabled!') return false end logger.debug('Attempting to start Reporter thread') unless running? true end def start_thread! return if running? client.startup!(connection) @_thread = Contrast::Agent::Thread.new do logger.debug('Starting background Reporter thread.') loop do event = queue.pop begin response = client.send_event(event, connection) audit&.audit_event(event, response) if ::Contrast::API.request_audit_enable? rescue StandardError => e logger.error('Could not send message to service from Reporter queue.', e) end sleep(TIMEOUT) if client.sleep? client.wake_up end end end def send_event event if ::Contrast::AGENT.disabled? logger.warn('Attempted to queue event with Agent disabled', caller: caller, event: event) return end return unless event return unless cs__class.enabled? logger.debug('Enqueued event for sending', event_type: event.cs__class) audit&.audit_event(event) if ::Contrast::API.request_audit_enable? queue << event end # Use this to bypass the messaging queue and leave response processing to the caller def send_event_immediately event if ::Contrast::AGENT.disabled? logger.warn('Reporter attempted to send event immediately with Agent disabled', caller: caller, event: event) return end response = client.send_event(event, connection, true) client.send(:handle_response, event, response, connection) if response&.code == 200 audit&.audit_event(event, response) if ::Contrast::API.request_audit_enable? rescue StandardError => e logger.error('Could not send message to service from Reporter queue.', e) end def delete_queue! @_queue&.clear @_queue&.close @_queue = nil end def stop! return unless running? super delete_queue! end private def queue @_queue ||= Queue.new end end end end