contrast-agent 7.1.0 → 7.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/ext/extconf_common.rb +88 -14
- data/lib/contrast/agent/assess/policy/source_method.rb +13 -4
- data/lib/contrast/agent/assess/policy/trigger_method.rb +12 -18
- data/lib/contrast/agent/excluder/excluder.rb +64 -31
- data/lib/contrast/agent/protect/rule/base.rb +4 -6
- data/lib/contrast/agent/protect/rule/bot_blocker/bot_blocker.rb +1 -1
- data/lib/contrast/agent/protect/rule/bot_blocker/bot_blocker_input_classification.rb +2 -2
- data/lib/contrast/agent/protect/rule/cmdi/cmdi_backdoors.rb +1 -1
- data/lib/contrast/agent/protect/rule/cmdi/cmdi_base_rule.rb +1 -1
- data/lib/contrast/agent/protect/rule/deserialization/deserialization.rb +2 -2
- data/lib/contrast/agent/protect/rule/path_traversal/path_traversal_semantic_security_bypass.rb +1 -1
- data/lib/contrast/agent/protect/rule/sqli/sqli_semantic/sqli_dangerous_functions.rb +1 -1
- data/lib/contrast/agent/protect/rule/utils/filters.rb +6 -6
- data/lib/contrast/agent/protect/rule/xxe/xxe.rb +1 -1
- data/lib/contrast/agent/reporting/client/interface.rb +132 -0
- data/lib/contrast/agent/reporting/client/interface_base.rb +27 -0
- data/lib/contrast/agent/reporting/connection_status.rb +0 -1
- data/lib/contrast/agent/reporting/input_analysis/input_analysis_result.rb +6 -4
- data/lib/contrast/agent/reporting/reporter.rb +11 -26
- data/lib/contrast/agent/reporting/reporting_events/discovered_route.rb +1 -1
- data/lib/contrast/agent/reporting/reporting_utilities/audit.rb +10 -3
- data/lib/contrast/agent/reporting/reporting_utilities/reporter_client.rb +47 -6
- data/lib/contrast/agent/reporting/reporting_utilities/reporter_client_utils.rb +40 -31
- data/lib/contrast/agent/reporting/reporting_utilities/resend.rb +144 -0
- data/lib/contrast/agent/reporting/reporting_utilities/response_handler.rb +35 -13
- data/lib/contrast/agent/reporting/reporting_utilities/response_handler_mode.rb +14 -1
- data/lib/contrast/agent/reporting/reporting_utilities/response_handler_utils.rb +11 -11
- data/lib/contrast/agent/request/request.rb +27 -12
- data/lib/contrast/agent/telemetry/base.rb +18 -19
- data/lib/contrast/agent/telemetry/exception/obfuscate.rb +97 -0
- data/lib/contrast/agent/telemetry/exception.rb +1 -0
- data/lib/contrast/agent/version.rb +1 -1
- data/lib/contrast/components/config/sources.rb +6 -5
- data/lib/contrast/components/settings.rb +9 -0
- data/lib/contrast/config/diagnostics/source_config_value.rb +5 -1
- data/lib/contrast/config/diagnostics/tools.rb +4 -4
- data/lib/contrast/config/validate.rb +2 -2
- data/lib/contrast/configuration.rb +11 -19
- data/lib/contrast/framework/grape/support.rb +1 -2
- data/lib/contrast/framework/manager.rb +17 -8
- data/lib/contrast/framework/rack/support.rb +99 -1
- data/lib/contrast/framework/rails/support.rb +1 -2
- data/lib/contrast/framework/sinatra/support.rb +1 -2
- data/lib/contrast/logger/aliased_logging.rb +18 -9
- data/lib/contrast/utils/hash_utils.rb +21 -2
- data/lib/contrast/utils/request_utils.rb +14 -0
- data/resources/assess/policy.json +11 -0
- metadata +6 -3
- data/lib/contrast/agent/reporting/input_analysis/details/bot_blocker_details.rb +0 -27
@@ -0,0 +1,132 @@
|
|
1
|
+
# Copyright (c) 2023 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require 'contrast/agent/reporting/client/interface_base'
|
5
|
+
|
6
|
+
module Contrast
|
7
|
+
module Agent
|
8
|
+
module Reporting
|
9
|
+
module Client
|
10
|
+
# Interface to safely manage connections across threads.
|
11
|
+
class Interface < Contrast::Agent::Reporting::Client::InterfaceBase
|
12
|
+
# Execute startup routine and
|
13
|
+
def startup
|
14
|
+
with_monitor { reporter_client.startup!(reporting_connection) }
|
15
|
+
end
|
16
|
+
|
17
|
+
# @param event [Contrast::Agent::Reporting::ReportingEvent]
|
18
|
+
# @return [Net::HTTPResponse]
|
19
|
+
def send_event event
|
20
|
+
with_monitor { reporter_client.send_event(event, reporting_connection) }
|
21
|
+
end
|
22
|
+
|
23
|
+
# return [Boolean]
|
24
|
+
def sleep?
|
25
|
+
with_monitor { reporter_client.sleep? }
|
26
|
+
end
|
27
|
+
|
28
|
+
# Retry once than discard the event. This is trigger on too many events of
|
29
|
+
# same kind error.
|
30
|
+
#
|
31
|
+
# @param event [Contrast::Agent::Reporting::ReportingEvent]
|
32
|
+
def handle_resend event
|
33
|
+
with_monitor do
|
34
|
+
reporter_client.handle_resend(event, reporting_connection)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# Check to see if client exists and there is connection
|
39
|
+
#
|
40
|
+
# @return [Boolean
|
41
|
+
def connected?
|
42
|
+
with_monitor do
|
43
|
+
return true if reporter_client && reporting_connection
|
44
|
+
|
45
|
+
false
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
# Check to see if statup connections are sent or not
|
50
|
+
def startup_messages_sent?
|
51
|
+
with_monitor { reporter_client.status.startup_messages_sent? }
|
52
|
+
end
|
53
|
+
|
54
|
+
# Check to see if event need to be resend
|
55
|
+
#
|
56
|
+
# @return [Boolean, nil]
|
57
|
+
def resending?
|
58
|
+
with_monitor { reporter_client.mode.status == reporter_client.mode.resending }
|
59
|
+
end
|
60
|
+
|
61
|
+
# Return timeout in ms
|
62
|
+
def timeout
|
63
|
+
with_monitor { reporter_client.timeout } || Contrast::Agent::Reporting::ResponseHandler::TIMEOUT
|
64
|
+
end
|
65
|
+
|
66
|
+
# @return headers [Contrast::Agent::Reporting::Headers]
|
67
|
+
def headers
|
68
|
+
with_monitor { reporter_client.headers }
|
69
|
+
end
|
70
|
+
|
71
|
+
# Response_handler
|
72
|
+
#
|
73
|
+
# @return [Contrast::Agent::Reporting::ResponseHandler]
|
74
|
+
def response_handler
|
75
|
+
with_monitor { reporter_client.response_handler }
|
76
|
+
end
|
77
|
+
|
78
|
+
def status
|
79
|
+
with_monitor { reporter_client.status }
|
80
|
+
end
|
81
|
+
|
82
|
+
private
|
83
|
+
|
84
|
+
# @return [Contrast::Agent::Reporting::ReporterClient]
|
85
|
+
def reporter_client
|
86
|
+
@_reporter_client ||= Contrast::Agent::Reporting::ReporterClient.new
|
87
|
+
end
|
88
|
+
|
89
|
+
# @return [Net::HTTP, nil] Return open connection or nil
|
90
|
+
def reporting_connection
|
91
|
+
@_reporting_connection ||= reporter_client.initialize_connection
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
module Telemetry
|
97
|
+
# Interface to safely manage connections across threads.
|
98
|
+
class Interface < Contrast::Agent::Reporting::Client::InterfaceBase
|
99
|
+
URL = 'https://telemetry.ruby.contrastsecurity.com/'
|
100
|
+
|
101
|
+
# Check to see if client exists and there is connection
|
102
|
+
#
|
103
|
+
# @return [Boolean
|
104
|
+
def connected?
|
105
|
+
with_monitor do
|
106
|
+
return true if telemetry_client && telemetry_connection
|
107
|
+
|
108
|
+
false
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
# Starts telemetry request.
|
113
|
+
def request_with_response event
|
114
|
+
with_monitor do
|
115
|
+
telemetry_client.handle_response(telemetry_client.send_request(event, telemetry_connection))
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
private
|
120
|
+
|
121
|
+
def telemetry_client
|
122
|
+
@_telemetry_client ||= Contrast::Agent::Telemetry::Client.new
|
123
|
+
end
|
124
|
+
|
125
|
+
def telemetry_connection
|
126
|
+
@_telemetry_connection ||= telemetry_client.initialize_connection(URL)
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# Copyright (c) 2023 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require 'monitor'
|
5
|
+
|
6
|
+
module Contrast
|
7
|
+
module Agent
|
8
|
+
module Reporting
|
9
|
+
module Client
|
10
|
+
# Common methods for Client interface.
|
11
|
+
class InterfaceBase
|
12
|
+
# Execute calls to connection with thread safety.
|
13
|
+
def with_monitor &block
|
14
|
+
monitor.synchronize(&block)
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
# @return [Monitor]
|
20
|
+
def monitor
|
21
|
+
@_monitor ||= Monitor.new
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -4,7 +4,7 @@
|
|
4
4
|
require 'contrast/utils/object_share'
|
5
5
|
require 'contrast/agent/reporting/input_analysis/input_type'
|
6
6
|
require 'contrast/agent/reporting/input_analysis/score_level'
|
7
|
-
require 'contrast/agent/reporting/
|
7
|
+
require 'contrast/agent/reporting/details/protect_rule_details'
|
8
8
|
|
9
9
|
module Contrast
|
10
10
|
module Agent
|
@@ -112,14 +112,16 @@ module Contrast
|
|
112
112
|
|
113
113
|
# Additional per rule details containing more specific info.
|
114
114
|
#
|
115
|
-
# @param protect_rule_details [Contrast::Agent::Reporting::ProtectRuleDetails]
|
115
|
+
# @param protect_rule_details [Contrast::Agent::Reporting::Details::ProtectRuleDetails]
|
116
116
|
def details= protect_rule_details
|
117
|
-
|
117
|
+
return unless protect_rule_details.is_a?(Contrast::Agent::Reporting::Details::ProtectRuleDetails)
|
118
|
+
|
119
|
+
@_details = protect_rule_details
|
118
120
|
end
|
119
121
|
|
120
122
|
# Additional per rule details containing more specific info.
|
121
123
|
#
|
122
|
-
# @return [Contrast::Agent::Reporting::ProtectRuleDetails, nil]
|
124
|
+
# @return [Contrast::Agent::Reporting::Details::ProtectRuleDetails, nil]
|
123
125
|
def details
|
124
126
|
@_details
|
125
127
|
end
|
@@ -6,6 +6,7 @@ require 'contrast/agent/reporting/report'
|
|
6
6
|
require 'contrast/components/logger'
|
7
7
|
require 'contrast/agent/reporting/reporting_events/agent_startup'
|
8
8
|
require 'contrast/agent/telemetry/exception'
|
9
|
+
require 'contrast/agent/reporting/client/interface'
|
9
10
|
|
10
11
|
module Contrast
|
11
12
|
module Agent
|
@@ -29,11 +30,7 @@ module Contrast
|
|
29
30
|
end
|
30
31
|
|
31
32
|
def client
|
32
|
-
@_client ||= Contrast::Agent::Reporting::
|
33
|
-
end
|
34
|
-
|
35
|
-
def connection
|
36
|
-
@_connection ||= client.initialize_connection
|
33
|
+
@_client ||= Contrast::Agent::Reporting::Client::Interface.new
|
37
34
|
end
|
38
35
|
|
39
36
|
def start_thread!
|
@@ -41,13 +38,12 @@ module Contrast
|
|
41
38
|
return if running?
|
42
39
|
|
43
40
|
@connection_attempts = 0
|
44
|
-
|
45
|
-
client.startup!(connection)
|
46
41
|
@_thread = Contrast::Agent::Thread.new do
|
47
42
|
logger.debug('[Reporter] Starting background Reporter thread.')
|
43
|
+
client.startup
|
48
44
|
loop do
|
49
|
-
next unless connected?
|
50
45
|
break unless attempt_to_start?
|
46
|
+
next unless connected?
|
51
47
|
|
52
48
|
process_event(queue.pop)
|
53
49
|
rescue StandardError => e
|
@@ -61,12 +57,7 @@ module Contrast
|
|
61
57
|
#
|
62
58
|
# @param event [Contrast::Agent::Reporting::ReportingEvent] Freshly pop-ed event.
|
63
59
|
def handle_resend event
|
64
|
-
|
65
|
-
# Retry once than discard the event. This is trigger on too many events of
|
66
|
-
# same kind error.
|
67
|
-
client.send_event(event, connection) if client.mode.status == client.mode.resending
|
68
|
-
client.mode.reset_mode
|
69
|
-
client.wake_up
|
60
|
+
client.handle_resend(event)
|
70
61
|
end
|
71
62
|
|
72
63
|
# @param event [Contrast::Agent::Reporting::ReportingEvent]
|
@@ -99,8 +90,9 @@ module Contrast
|
|
99
90
|
return
|
100
91
|
end
|
101
92
|
return unless event
|
93
|
+
return unless connected?
|
102
94
|
|
103
|
-
client.send_event(event
|
95
|
+
client.send_event(event)
|
104
96
|
rescue StandardError => e
|
105
97
|
logger.error('[Reporter] Could not send message to TeamServer from reporting queue.', e)
|
106
98
|
end
|
@@ -124,17 +116,9 @@ module Contrast
|
|
124
116
|
@_queue ||= Queue.new
|
125
117
|
end
|
126
118
|
|
127
|
-
# TODO: RUBY-99999
|
128
|
-
# The client and connection are being used in multiple threads/ concurrently, and that's not okay. We need
|
129
|
-
# to figure out why that is and lock it so that it isn't.
|
130
|
-
#
|
131
119
|
# @return [Boolean]
|
132
120
|
def connected?
|
133
|
-
if client
|
134
|
-
# Try to resend startup messages now with connection:
|
135
|
-
client.startup!(connection) unless client.status.startup_messages_sent?
|
136
|
-
return true
|
137
|
-
end
|
121
|
+
return true if client.connected?
|
138
122
|
|
139
123
|
logger.debug('[Reporter] No client/connection; sleeping...')
|
140
124
|
@connection_attempts += 1
|
@@ -148,8 +132,8 @@ module Contrast
|
|
148
132
|
|
149
133
|
# @param event [Contrast::Agent::Reporting::ReportingEvent]
|
150
134
|
def process_event event
|
151
|
-
client.send_event(event
|
152
|
-
handle_resend(event) if client.
|
135
|
+
client.send_event(event)
|
136
|
+
handle_resend(event) if client.resending?
|
153
137
|
rescue StandardError => e
|
154
138
|
logger.error('[Reporter] Could not send message to TeamServer from reporting queue.', e)
|
155
139
|
end
|
@@ -171,6 +155,7 @@ module Contrast
|
|
171
155
|
stack_trace[1].path.delete_prefix(Dir.pwd)
|
172
156
|
end
|
173
157
|
stack_frame_function = stack_trace.nil? || stack_trace[1].nil? ? 'none' : stack_trace[1].label
|
158
|
+
stack_frame_type = Contrast::Agent::Telemetry::Exception::Obfuscate.obfuscate_path(stack_frame_type)
|
174
159
|
Contrast::Agent::Telemetry::Exception::StackFrame.build(stack_frame_function, stack_frame_type, nil)
|
175
160
|
end
|
176
161
|
end
|
@@ -81,7 +81,7 @@ module Contrast
|
|
81
81
|
safe_url = source_or_string(url || pattern)
|
82
82
|
|
83
83
|
msg = new
|
84
|
-
msg.signature = "#{ controller }##{ method } #{ safe_pattern }"
|
84
|
+
msg.signature = "#{ controller }##{ method } #{ safe_pattern }" # rubocop:disable [Security/Object/Method]
|
85
85
|
msg.verb = Contrast::Utils::StringUtils.force_utf8(method)
|
86
86
|
msg.url = Contrast::Utils::StringUtils.force_utf8(safe_url)
|
87
87
|
msg
|
@@ -55,17 +55,24 @@ module Contrast
|
|
55
55
|
# @param event_name [String] the type portion of the file to which to write
|
56
56
|
# @param data [any] The data to be written to the file
|
57
57
|
def write_to_file type, event_name, data = nil
|
58
|
-
time =
|
58
|
+
time = Contrast::Utils::Timer.now_ms
|
59
59
|
destination = type == :request ? path_for_requests : path_for_responses
|
60
60
|
# If the feature is disabled or we have yet to create the directory structure, then we could have a nil
|
61
61
|
# destination. In that case, take no action
|
62
62
|
return unless destination
|
63
63
|
|
64
|
-
|
64
|
+
# Get process id and thread id to make sure we don't overwrite files
|
65
|
+
process_id = Process.pid
|
66
|
+
thread_id = Thread.current.object_id
|
67
|
+
event_title = event_name.gsub('::', '-')
|
68
|
+
filename = "#{ time }_#{ thread_id }_#{ process_id }_#{ event_title }_teamserver_#{ type }.json"
|
65
69
|
filepath = File.join(destination, filename)
|
66
70
|
logger.debug('Writing to file', eventname: event_name, filename: filename, filepath: filepath)
|
67
71
|
# Here is use append mode, because of a slightly possibility of overwriting an existing file
|
68
|
-
File.open(filepath, 'a')
|
72
|
+
File.open(filepath, 'a') do |f|
|
73
|
+
f.write(Contrast::Utils::StringUtils.force_utf8(data))
|
74
|
+
f.close
|
75
|
+
end
|
69
76
|
rescue StandardError => e
|
70
77
|
logger.warn('Saving audit failed', e: e)
|
71
78
|
end
|
@@ -14,6 +14,7 @@ require 'contrast/agent/reporting/reporting_utilities/response_handler'
|
|
14
14
|
require 'contrast/agent/reporting/reporting_events/application_settings'
|
15
15
|
require 'contrast/agent/reporting/reporting_events/agent_effective_config'
|
16
16
|
require 'contrast/agent/reporting/reporting_utilities/reporter_client_utils'
|
17
|
+
require 'contrast/agent/reporting/reporting_utilities/resend'
|
17
18
|
|
18
19
|
module Contrast
|
19
20
|
module Agent
|
@@ -72,17 +73,17 @@ module Contrast
|
|
72
73
|
def send_event event, connection
|
73
74
|
return unless connection
|
74
75
|
|
76
|
+
response = nil
|
75
77
|
logger.debug('[Reporter] Preparing to send reporting event', event_class: event.cs__class)
|
76
|
-
|
77
78
|
request = build_request(event)
|
78
79
|
response = connection.request(request)
|
79
|
-
audit
|
80
|
+
audit.audit_event(event, response) if ::Contrast::API.request_audit_enable
|
80
81
|
process_settings_response(response, event)
|
81
|
-
report_configuration(response, event)
|
82
82
|
process_preflight_response(event, response, connection)
|
83
|
+
report_configuration(response, event)
|
83
84
|
response
|
84
85
|
rescue StandardError => e
|
85
|
-
|
86
|
+
handle_response_error(event, connection, e)
|
86
87
|
end
|
87
88
|
|
88
89
|
# Write effective config to file:
|
@@ -103,6 +104,9 @@ module Contrast
|
|
103
104
|
diagnostics.write_to_file
|
104
105
|
config_event = Contrast::Agent::Reporting::AgentEffectiveConfig.new(diagnostics)
|
105
106
|
Contrast::Agent.reporter.send_event(config_event)
|
107
|
+
rescue StandardError => e
|
108
|
+
# Don't let this error bubble up and stop the agent reporting, with resending triggered.
|
109
|
+
logger.error('[Reporter] Error while reporting configuration', error: e, event_type: event&.cs__class)
|
106
110
|
end
|
107
111
|
|
108
112
|
def status
|
@@ -117,10 +121,47 @@ module Contrast
|
|
117
121
|
@_diagnostics ||= Contrast::Config::Diagnostics::Monitor.new(Contrast::LOGGER.path)
|
118
122
|
end
|
119
123
|
|
124
|
+
# Compress data with Zlib
|
125
|
+
#
|
126
|
+
# @param event [Contrast::Agent::Reporting::ReportingEvent]
|
127
|
+
# @param level [Integer] compression level
|
128
|
+
# @param strategy [Integer] compression strategy
|
129
|
+
# @return [String] compressed data
|
130
|
+
def compress_event event, level = Zlib::DEFAULT_COMPRESSION, strategy = Zlib::DEFAULT_STRATEGY
|
131
|
+
compressed_data = StringIO.new.set_encoding(STRING_ENCODING)
|
132
|
+
gzip = Zlib::GzipWriter.new(compressed_data, level, strategy)
|
133
|
+
gzip.write(event.event_json)
|
134
|
+
gzip.close
|
135
|
+
gzip = nil
|
136
|
+
compressed_event = compressed_data.string.dup
|
137
|
+
compressed_data.close
|
138
|
+
compressed_data = nil
|
139
|
+
compressed_event
|
140
|
+
ensure
|
141
|
+
gzip&.close
|
142
|
+
compressed_data&.close
|
143
|
+
compressed_event
|
144
|
+
end
|
145
|
+
|
146
|
+
# Reads compressed data
|
147
|
+
#
|
148
|
+
# @param compresed_data [String]
|
149
|
+
def decompress compresed_data
|
150
|
+
Zlib::GzipReader.wrap(StringIO.new(compresed_data), &:read)
|
151
|
+
end
|
152
|
+
|
153
|
+
##############
|
154
|
+
# Forwarders #
|
155
|
+
##############
|
156
|
+
|
120
157
|
def sleep?
|
121
158
|
response_handler.sleep?
|
122
159
|
end
|
123
160
|
|
161
|
+
def put_to_sleep
|
162
|
+
response_handler.put_to_sleep
|
163
|
+
end
|
164
|
+
|
124
165
|
def timeout
|
125
166
|
response_handler.timeout
|
126
167
|
end
|
@@ -129,8 +170,8 @@ module Contrast
|
|
129
170
|
response_handler.mode
|
130
171
|
end
|
131
172
|
|
132
|
-
def
|
133
|
-
response_handler.
|
173
|
+
def enter_run_mode
|
174
|
+
response_handler.enter_run_mode
|
134
175
|
end
|
135
176
|
|
136
177
|
def wake_up
|
@@ -8,16 +8,20 @@ require 'contrast/components/scope'
|
|
8
8
|
require 'contrast/agent/reporting/reporting_events/application_startup'
|
9
9
|
require 'contrast/agent/reporting/reporting_utilities/reporter_client'
|
10
10
|
require 'contrast/agent/reporting/reporting_utilities/endpoints'
|
11
|
+
require 'contrast/agent/reporting/reporting_utilities/resend'
|
11
12
|
|
12
13
|
module Contrast
|
13
14
|
module Agent
|
14
15
|
module Reporting
|
15
16
|
# This module holds utilities required by the reporting service client
|
16
17
|
module ReporterClientUtils
|
18
|
+
include Contrast::Agent::Reporting::Resend
|
17
19
|
include Contrast::Components::Logger::InstanceMethods
|
18
20
|
include Contrast::Components::Scope::InstanceMethods
|
19
21
|
include Contrast::Agent::Reporting::Endpoints
|
20
22
|
|
23
|
+
STRING_ENCODING = 'BINARY'
|
24
|
+
|
21
25
|
# List the events that need to be sent when agent starts up.
|
22
26
|
# The order here matters -- DO NOT CHANGE IT!!! >_< - HM
|
23
27
|
#
|
@@ -33,19 +37,37 @@ module Contrast
|
|
33
37
|
|
34
38
|
private
|
35
39
|
|
36
|
-
# Send Agent Startup event
|
40
|
+
# Send Agent Startup event. If error occurs, it will try to resend the message.
|
37
41
|
#
|
38
42
|
# @param connection [Net::HTTP] open connection
|
39
43
|
def send_agent_startup connection
|
40
|
-
logger.debug('Preparing to send startup messages')
|
44
|
+
logger.debug('[Reporter] Preparing to send startup messages')
|
45
|
+
STARTUP_EVENTS.each { |event| send_event(event.new, connection) }
|
46
|
+
logger.debug('[Reporter] Startup messages sent.') if status.startup_messages_sent?
|
47
|
+
end
|
41
48
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
+
# Disable reporting and log the error
|
50
|
+
#
|
51
|
+
# @param event [Contrast::Agent::Reporting::ReportingEvent]
|
52
|
+
# @param error [StandardError]
|
53
|
+
def disable_reporting event, error
|
54
|
+
status.failure!
|
55
|
+
mode.resend.reset_rescue_attempts
|
56
|
+
mode.status = mode.disabled
|
57
|
+
message = '[Reporter] Unable to send message.'
|
58
|
+
response_handler.stop_reporting(message,
|
59
|
+
application: Contrast::APP_CONTEXT.name, # rubocop:disable Security/Module/Name
|
60
|
+
connection_error: error,
|
61
|
+
client: Contrast::Agent::Reporting::ReporterClient::SERVICE_NAME,
|
62
|
+
event_id: event&.__id__,
|
63
|
+
event_type: event&.cs__class&.cs__name)
|
64
|
+
nil
|
65
|
+
end
|
66
|
+
|
67
|
+
def response_success!
|
68
|
+
status.success!
|
69
|
+
mode.enter_run_mode
|
70
|
+
mode.resend.reset_rescue_attempts
|
49
71
|
end
|
50
72
|
|
51
73
|
# This method will build headers of the request required for TS communication
|
@@ -65,29 +87,18 @@ module Contrast
|
|
65
87
|
request
|
66
88
|
end
|
67
89
|
|
68
|
-
# Handles standard error case, logs and set status for failure
|
69
|
-
#
|
70
|
-
# @param event [Contrast::Agent::Reporting::ReportingEvent]
|
71
|
-
# One of the DTMs valid for the event field of Contrast::Api::Dtm::Message
|
72
|
-
# @param error_msg [StandardError]
|
73
|
-
# @return nil [NilClass] to be passed as response
|
74
|
-
def handle_error event, error_msg
|
75
|
-
status.failure!
|
76
|
-
logger.error('Unable to send message.',
|
77
|
-
error_msg,
|
78
|
-
client: Contrast::Agent::Reporting::ReporterClient::SERVICE_NAME,
|
79
|
-
event_id: event&.__id__,
|
80
|
-
event_type: event&.cs__class&.cs__name)
|
81
|
-
nil
|
82
|
-
end
|
83
|
-
|
84
90
|
# Handles response processing and sets status
|
85
91
|
#
|
86
92
|
# @param event [Contrast::Agent::Reporting::ReportingEvent] The event sent to TeamServer.
|
87
93
|
# @param response [Net::HTTP::Response]
|
88
94
|
def process_settings_response response, event
|
89
95
|
res = response_handler.process(response, event)
|
90
|
-
|
96
|
+
if res
|
97
|
+
status.success!
|
98
|
+
mode.resend.reset_rescue_attempts
|
99
|
+
else
|
100
|
+
status.failure!
|
101
|
+
end
|
91
102
|
res
|
92
103
|
end
|
93
104
|
|
@@ -104,6 +115,7 @@ module Contrast
|
|
104
115
|
return unless response&.body && connection
|
105
116
|
|
106
117
|
findings_to_return = response.body.split(',').delete_if { |el| el.include?('*') }
|
118
|
+
mode.resend.reset_rescue_attempts
|
107
119
|
findings_to_return.each do |index|
|
108
120
|
preflight_message = event.messages[index.to_i]
|
109
121
|
corresponding_finding = Contrast::Agent::Reporting::ReportingStorage.delete(preflight_message.data)
|
@@ -112,7 +124,7 @@ module Contrast
|
|
112
124
|
send_event(corresponding_finding, connection)
|
113
125
|
end
|
114
126
|
rescue StandardError => e
|
115
|
-
logger.error('Unable to handle response', e)
|
127
|
+
logger.error('[Reporter] Unable to handle preflight response', e)
|
116
128
|
end
|
117
129
|
|
118
130
|
# Convert the given event into an appropriate Net::HTTPRequest object, setting the request headers and
|
@@ -133,10 +145,7 @@ module Contrast
|
|
133
145
|
end
|
134
146
|
build_headers(request)
|
135
147
|
event.attach_headers(request)
|
136
|
-
|
137
|
-
gzip = Zlib::GzipWriter.new(StringIO.new)
|
138
|
-
gzip << event.event_json
|
139
|
-
request.body = gzip.close.string
|
148
|
+
request.body = compress_event(event)
|
140
149
|
request
|
141
150
|
end
|
142
151
|
end
|