# Copyright (c) 2022 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details. # frozen_string_literal: true require 'contrast/agent/reporting/settings/assess_rule' require 'contrast/agent/reporting/settings/protect_rule' module Contrast module Agent module Reporting # This module will hold the methods for TS response conversion to settings objects. module ResponseExtractor private ########################################## # Server Settings Parsing # ########################################## # This method is universal and used for both ng endpoing of feature settings and the new # Server settings endpoint. Used in both build_feature_settings and build_server_settings. # Passing the ng_ flag determines the use of the endpoint and response used because some of # the response fields are with different names or do not exist: [enabled vs enable] # # @param response_data [Hash] # @param res [Contrast::Agent::Reporting::Response] def extract_assess_server_settings response_data, res assess = response_data[:assess] return unless assess res.server_features.assess.enabled = assess[:enable] res.server_features.assess.report_stacktraces = assess[:report_stacktraces] res.server_features.assess.sampling = assess[:sampling] res.server_features.assess.sanitizers = assess[:sanitizers] res.server_features.assess.validators = assess[:validators] end # @param response_data [Hash] # @param res [Contrast::Agent::Reporting::Response] def extract_protect_server_settings response_data, res protect = response_data[:protect] return unless protect res.server_features.protect.enabled = protect[:enable] res.server_features.protect.observability = protect[:observability] res.server_features.protect.log_enhancers = protect[:log_enhancers] update_protect_rules(protect, res) end # This method is used with ServerSettings as we expect to have data for # all the loggers - security_logger, logger, syslog. # # @param response_data [Hash] # @param res [Contrast::Agent::Reporting::Response] def extract_loggers response_data, res logger = response_data[:logger] security_logger = response_data[:security_logger] if logger res.server_features.log_level = logger[:level] res.server_features.log_file = logger[:path] end return unless security_logger log_level = security_logger[:level] log_file = security_logger[:path] res.server_features.security_logger.log_level = log_level res.server_features.security_logger.log_file = log_file res.server_features.security_logger.not_blank! res.server_features.security_logger.syslog.assign_array(response_data[:security_logger][:syslog], ng_: false) end # @param protect [Hash] response data # @param res [Contrast::Agent::Reporting::Response] def update_protect_rules protect, res return unless (rules = protect[:rules]) res.server_features.protect.ip_allowlist = rules[:ip_allowlist] res.server_features.protect.ip_denylist = rules[:ip_denylist] res.server_features.protect.bot_blocker.enable = rules[:bot_blocker][:enable] res.server_features.protect.bot_blocker.bots = rules[:bot_blocker][:bots] res.server_features.protect.rules_to_definition_list(rules) end ########################################## # Application Settings Parsing # ########################################## # @param response_data [Hash] # @param res [Contrast::Agent::Reporting::Response] def extract_assess_application_settings response_data, res assess = response_data[:assess] return unless assess assess.each_pair do |rule_id, value| rule_setting = Contrast::Agent::Reporting::Settings::AssessRule.new.tap { |setting| setting.enable = value[:enable] } res.application_settings.assess.rule_settings[rule_id.to_s] = rule_setting end # This endpoint can never give us session_id, so we dont need to set it here # res.application_settings.assess.session_id end # @param response_data [Hash] # @param res [Contrast::Agent::Reporting::Response] def extract_protect_application_settings response_data, res protect = response_data[:protect] return unless protect rules = protect[:rules] rules&.each_pair do |rule_id, value| rule_setting = Contrast::Agent::Reporting::Settings::ProtectRule.new.tap { |setting| setting.mode = value[:mode] } res.application_settings.protect.rule_settings[rule_id.to_s] = rule_setting end protect[:'virtual-patches']&.each do |patch_json| res.application_settings.protect.virtual_patches << Contrast::Agent::Reporting::Settings::VirtualPatch.new(patch_json) end end # @param response_data [Hash] # @param res [Contrast::Agent::Reporting::Response] def extract_exclusions response_data, res exclusions = response_data[:exclusions] return unless exclusions res.application_settings.exclusions.code_exclusions = exclusions[:code] res.application_settings.exclusions.url_exclusions = exclusions[:url] extract_input_exclusions(response_data[:exclusions], res) end # Input exclusions between NG and non-NG are different, so need to be cast separately. # # @param exclusions [Hash] # @param res [Contrast::Agent::Reporting::Response] def extract_input_exclusions exclusions, res res.application_settings.exclusions.input_exclusions = [] exclusions[:input].each do |exclusion_details| input_exclusion = Contrast::Agent::Reporting::Settings::InputExclusion.new input_exclusion.name = exclusion_details[:name] input_exclusion.modes = exclusion_details[:modes] input_exclusion.assess_rules = exclusion_details[:assess_rules] input_exclusion.protect_rules = exclusion_details[:protect_rules] input_exclusion.input_name = exclusion_details[:name] input_exclusion.input_type = exclusion_details[:type] input_exclusion.urls = exclusion_details[:urls] res.application_settings.exclusions.input_exclusions << exclusion end end # @param response_data [Hash] # @param res [Contrast::Agent::Reporting::Response] def extract_sensitive_data_policy response_data, res return unless (sensitive_data = response_data[:sensitive_data_masking_policy]) res.application_settings.sensitive_data_masking.mask_http_body = sensitive_data[:mask_http_body] res.application_settings.sensitive_data_masking.mask_attack_vector = sensitive_data[:mask_attack_vector] res.application_settings.sensitive_data_masking.build_rules_form_settings(sensitive_data[:rules]) end # @param response_data [Hash] # @param res [Contrast::Agent::Reporting::Response] def extract_reactions response_data, res res.reactions = response_data[:reactions] end end end end end