contrast-agent 7.0.0 → 7.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (90) hide show
  1. checksums.yaml +4 -4
  2. data/ext/extconf_common.rb +88 -14
  3. data/lib/contrast/agent/assess/policy/policy.rb +1 -1
  4. data/lib/contrast/agent/assess/policy/source_method.rb +13 -4
  5. data/lib/contrast/agent/assess/policy/trigger_method.rb +12 -18
  6. data/lib/contrast/agent/deadzone/policy/policy.rb +1 -1
  7. data/lib/contrast/agent/excluder/excluder.rb +64 -31
  8. data/lib/contrast/agent/patching/policy/policy.rb +2 -2
  9. data/lib/contrast/agent/protect/input_analyzer/worth_watching_analyzer.rb +3 -0
  10. data/lib/contrast/agent/protect/rule/base.rb +4 -6
  11. data/lib/contrast/agent/protect/rule/bot_blocker/bot_blocker.rb +1 -1
  12. data/lib/contrast/agent/protect/rule/bot_blocker/bot_blocker_input_classification.rb +2 -2
  13. data/lib/contrast/agent/protect/rule/cmdi/cmdi_backdoors.rb +1 -1
  14. data/lib/contrast/agent/protect/rule/cmdi/cmdi_base_rule.rb +1 -1
  15. data/lib/contrast/agent/protect/rule/deserialization/deserialization.rb +2 -2
  16. data/lib/contrast/agent/protect/rule/no_sqli/no_sqli.rb +1 -1
  17. data/lib/contrast/agent/protect/rule/path_traversal/path_traversal_semantic_security_bypass.rb +1 -1
  18. data/lib/contrast/agent/protect/rule/sqli/sqli_semantic/sqli_dangerous_functions.rb +1 -1
  19. data/lib/contrast/agent/protect/rule/utils/filters.rb +6 -6
  20. data/lib/contrast/agent/protect/rule/xxe/xxe.rb +1 -1
  21. data/lib/contrast/agent/reporting/client/interface.rb +132 -0
  22. data/lib/contrast/agent/reporting/client/interface_base.rb +27 -0
  23. data/lib/contrast/agent/reporting/connection_status.rb +0 -1
  24. data/lib/contrast/agent/reporting/input_analysis/input_analysis_result.rb +6 -4
  25. data/lib/contrast/agent/reporting/reporter.rb +23 -23
  26. data/lib/contrast/agent/reporting/reporting_events/agent_effective_config.rb +32 -0
  27. data/lib/contrast/agent/reporting/reporting_events/discovered_route.rb +1 -1
  28. data/lib/contrast/agent/reporting/reporting_utilities/audit.rb +10 -3
  29. data/lib/contrast/agent/reporting/reporting_utilities/endpoints.rb +7 -0
  30. data/lib/contrast/agent/reporting/reporting_utilities/headers.rb +3 -1
  31. data/lib/contrast/agent/reporting/reporting_utilities/reporter_client.rb +57 -12
  32. data/lib/contrast/agent/reporting/reporting_utilities/reporter_client_utils.rb +55 -38
  33. data/lib/contrast/agent/reporting/reporting_utilities/resend.rb +144 -0
  34. data/lib/contrast/agent/reporting/reporting_utilities/response_handler.rb +35 -13
  35. data/lib/contrast/agent/reporting/reporting_utilities/response_handler_mode.rb +14 -1
  36. data/lib/contrast/agent/reporting/reporting_utilities/response_handler_utils.rb +13 -12
  37. data/lib/contrast/agent/reporting/reporting_workers/application_server_worker.rb +3 -0
  38. data/lib/contrast/agent/reporting/reporting_workers/reporter_heartbeat.rb +3 -0
  39. data/lib/contrast/agent/reporting/reporting_workers/server_settings_worker.rb +3 -0
  40. data/lib/contrast/agent/request/request.rb +27 -12
  41. data/lib/contrast/agent/telemetry/base.rb +55 -31
  42. data/lib/contrast/agent/telemetry/client.rb +1 -3
  43. data/lib/contrast/agent/telemetry/exception/obfuscate.rb +97 -0
  44. data/lib/contrast/agent/telemetry/exception.rb +1 -0
  45. data/lib/contrast/agent/telemetry/telemetry.rb +0 -7
  46. data/lib/contrast/agent/thread/thread_watcher.rb +2 -2
  47. data/lib/contrast/agent/version.rb +1 -1
  48. data/lib/contrast/components/agent.rb +1 -1
  49. data/lib/contrast/components/api.rb +2 -2
  50. data/lib/contrast/components/app_context.rb +1 -1
  51. data/lib/contrast/components/assess.rb +1 -1
  52. data/lib/contrast/components/assess_rules.rb +1 -1
  53. data/lib/contrast/components/base.rb +3 -3
  54. data/lib/contrast/components/config/sources.rb +13 -9
  55. data/lib/contrast/components/config.rb +2 -2
  56. data/lib/contrast/components/protect.rb +2 -2
  57. data/lib/contrast/components/sampling.rb +6 -4
  58. data/lib/contrast/components/settings.rb +10 -1
  59. data/lib/contrast/config/certification_configuration.rb +1 -1
  60. data/lib/contrast/config/configuration_files.rb +47 -0
  61. data/lib/contrast/config/diagnostics/command_line.rb +24 -0
  62. data/lib/contrast/config/{config.rb → diagnostics/config.rb} +21 -6
  63. data/lib/contrast/config/diagnostics/contrast_ui.rb +24 -0
  64. data/lib/contrast/config/diagnostics/effective_config.rb +28 -0
  65. data/lib/contrast/config/diagnostics/effective_config_value.rb +14 -0
  66. data/lib/contrast/config/diagnostics/environment_variables.rb +51 -0
  67. data/lib/contrast/config/{diagnostics.rb → diagnostics/monitor.rb} +10 -10
  68. data/lib/contrast/config/diagnostics/source_config_value.rb +55 -0
  69. data/lib/contrast/config/diagnostics/tools.rb +188 -0
  70. data/lib/contrast/config/diagnostics/user_configuration_file.rb +44 -0
  71. data/lib/contrast/config/request_audit_configuration.rb +1 -1
  72. data/lib/contrast/config/server_configuration.rb +1 -1
  73. data/lib/contrast/config/validate.rb +2 -2
  74. data/lib/contrast/configuration.rb +82 -57
  75. data/lib/contrast/framework/grape/support.rb +1 -2
  76. data/lib/contrast/framework/manager.rb +17 -8
  77. data/lib/contrast/framework/rack/support.rb +99 -1
  78. data/lib/contrast/framework/rails/support.rb +1 -2
  79. data/lib/contrast/framework/sinatra/support.rb +1 -2
  80. data/lib/contrast/logger/aliased_logging.rb +18 -9
  81. data/lib/contrast/utils/hash_utils.rb +62 -0
  82. data/lib/contrast/utils/json.rb +46 -0
  83. data/lib/contrast/utils/net_http_base.rb +75 -26
  84. data/lib/contrast/utils/request_utils.rb +14 -0
  85. data/resources/assess/policy.json +11 -0
  86. metadata +20 -8
  87. data/lib/contrast/agent/reporting/input_analysis/details/bot_blocker_details.rb +0 -27
  88. data/lib/contrast/config/diagnostics_tools.rb +0 -99
  89. data/lib/contrast/config/effective_config.rb +0 -131
  90. data/lib/contrast/config/effective_config_value.rb +0 -32
@@ -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
- STARTUP_EVENTS.each do |event|
43
- startup_event = event.new
44
- send_event(startup_event, connection)
45
- rescue StandardError => e
46
- handle_error(startup_event, e)
47
- end
48
- logger.debug('Startup messages sent')
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
@@ -53,45 +75,30 @@ module Contrast
53
75
  # @param request [Net::HTTPRequest]
54
76
  # @return [Net::HTTPRequest]
55
77
  def build_headers request
56
- app_version = @headers.app_version
57
- request['API-Key'] = @headers.api_key
58
- request['Application-Language'] = @headers.app_language
59
- request['Application-Name'] = @headers.app_name
60
- request['Application-Path'] = @headers.app_path
61
- request['Application-Version'] = app_version if app_version
78
+ build_application_headers(request)
79
+ build_encode_and_compress_headers(request)
62
80
  request['Authorization'] = @headers.authorization
63
81
  request['Server-Name'] = @headers.server_name
64
82
  request['Server-Path'] = @headers.server_path
65
83
  request['Server-Type'] = @headers.server_type
66
84
  request['X-Contrast-Agent'] = @headers.agent_version
67
85
  request['X-Contrast-Header-Encoding'] = @headers.encoding
68
- build_encode_and_compress_headers(request)
86
+ request['Session-ID'] = @headers.session_id
69
87
  request
70
88
  end
71
89
 
72
- # Handles standard error case, logs and set status for failure
73
- #
74
- # @param event [Contrast::Agent::Reporting::ReportingEvent]
75
- # One of the DTMs valid for the event field of Contrast::Api::Dtm::Message
76
- # @param error_msg [StandardError]
77
- # @return nil [NilClass] to be passed as response
78
- def handle_error event, error_msg
79
- status.failure!
80
- logger.error('Unable to send message.',
81
- error_msg,
82
- client: Contrast::Agent::Reporting::ReporterClient::SERVICE_NAME,
83
- event_id: event&.__id__,
84
- event_type: event&.cs__class&.cs__name)
85
- nil
86
- end
87
-
88
90
  # Handles response processing and sets status
89
91
  #
90
92
  # @param event [Contrast::Agent::Reporting::ReportingEvent] The event sent to TeamServer.
91
93
  # @param response [Net::HTTP::Response]
92
94
  def process_settings_response response, event
93
95
  res = response_handler.process(response, event)
94
- status.success! if res
96
+ if res
97
+ status.success!
98
+ mode.resend.reset_rescue_attempts
99
+ else
100
+ status.failure!
101
+ end
95
102
  res
96
103
  end
97
104
 
@@ -108,6 +115,7 @@ module Contrast
108
115
  return unless response&.body && connection
109
116
 
110
117
  findings_to_return = response.body.split(',').delete_if { |el| el.include?('*') }
118
+ mode.resend.reset_rescue_attempts
111
119
  findings_to_return.each do |index|
112
120
  preflight_message = event.messages[index.to_i]
113
121
  corresponding_finding = Contrast::Agent::Reporting::ReportingStorage.delete(preflight_message.data)
@@ -116,7 +124,7 @@ module Contrast
116
124
  send_event(corresponding_finding, connection)
117
125
  end
118
126
  rescue StandardError => e
119
- logger.error('Unable to handle response', e)
127
+ logger.error('[Reporter] Unable to handle preflight response', e)
120
128
  end
121
129
 
122
130
  # Convert the given event into an appropriate Net::HTTPRequest object, setting the request headers and
@@ -137,10 +145,7 @@ module Contrast
137
145
  end
138
146
  build_headers(request)
139
147
  event.attach_headers(request)
140
- # compress:
141
- gzip = Zlib::GzipWriter.new(StringIO.new)
142
- gzip << event.event_json
143
- request.body = gzip.close.string
148
+ request.body = compress_event(event)
144
149
  request
145
150
  end
146
151
  end
@@ -155,6 +160,18 @@ module Contrast
155
160
  request['X-Contrast-Encoding'] = @headers.compression
156
161
  request['Content-Encoding'] = @headers.compression
157
162
  end
163
+
164
+ # Adds corresponding application headers to request.
165
+ #
166
+ # @param request [Net::HTTPRequest]
167
+ def build_application_headers request
168
+ app_version = @headers.app_version
169
+ request['API-Key'] = @headers.api_key
170
+ request['Application-Language'] = @headers.app_language
171
+ request['Application-Name'] = @headers.app_name
172
+ request['Application-Path'] = @headers.app_path
173
+ request['Application-Version'] = app_version if app_version
174
+ end
158
175
  end
159
176
  end
160
177
  end
@@ -0,0 +1,144 @@
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
+ module Contrast
5
+ module Agent
6
+ module Reporting
7
+ # Module to house the Resend logic, when there is no response from TS.
8
+ module Resend
9
+ # How manny times the client will try to rescue from above error before raising an
10
+ # error to reflect the events.
11
+ #
12
+ RESCUE_ATTEMPTS = 3
13
+ TIMEOUT = 5
14
+ RETRY_ERRORS = [
15
+ Net::OpenTimeout, Net::ReadTimeout, ArgumentError, EOFError, OpenSSL::SSL::SSLError, Resolv::ResolvError,
16
+ Errno::ECONNRESET, Errno::ECONNREFUSED, Errno::ETIMEDOUT, Errno::ESHUTDOWN, Errno::EHOSTDOWN, NameError,
17
+ Errno::EHOSTUNREACH, Errno::EISCONN, Errno::ECONNABORTED, Errno::ENETRESET, Errno::ENETUNREACH, SocketError,
18
+ NameError, NoMethodError, Timeout::Error, RuntimeError
19
+ ].cs__freeze
20
+ RESENDING_MESSAGE = '[Reporter] Resending message...'
21
+ END_RESENDING_MESSAGE = '[Reporter] Reporter tried to resend event and received error:'
22
+
23
+ # This method is mainly used in inside error handling and startup mesasges sending.
24
+ #
25
+ # @param event [Contrast::Agent::Reporting::ReportingEvent] event to resend
26
+ # @param connection [Net::HTTP] open connection
27
+ # @param error [StandardError] error that was raised
28
+ # @return [Net::HTTPResponse, nil] response from TS
29
+ def try_resend event, connection, error
30
+ # The timeout for agent to sleep is set here, we don't need to raise an error,
31
+ # but also 15 min is a long time to wait for example if event is startup message.
32
+ # Override timeout
33
+ if Contrast::Agent::Reporting::ReporterClientUtils::STARTUP_EVENTS.include?(event.cs__class)
34
+ response_handler.suspend_reporting(RESENDING_MESSAGE,
35
+ TIMEOUT,
36
+ error,
37
+ event: event,
38
+ log_error: false,
39
+ startup: true)
40
+ end
41
+ mode.enter_resend_mode
42
+ handle_resend(event, connection)
43
+ end
44
+
45
+ # This method will handle the error and will decide if we need to resend the event
46
+ #
47
+ # @param event [Contrast::Agent::Reporting::ReportingEvent]
48
+ # @param connection [Net::HTTP] open connection
49
+ # @return [Net::HTTPResponse, nil] response from TS
50
+ def handle_resend event, connection
51
+ if sleep?
52
+ logger.debug("[Reporter] sleeping for #{ TIMEOUT } seconds before resending...")
53
+ Thread.current.send(:sleep, timeout)
54
+ wake_up
55
+ end
56
+ response = mode.status == mode.resending ? send_event(event, connection) : nil
57
+ response_success! if response
58
+ response
59
+ end
60
+
61
+ # Handles errors that occurs before the ResponseHandler do not have a response, or response
62
+ # code to hande. This Errors requires different handling, because most of errors here
63
+ # occurs when the response cannot be read, there is open ssl error, or a certain Timeout
64
+ # is reached.
65
+ #
66
+ # @param event [Contrast::Agent::Reporting::ReportingEvent]
67
+ # One of the DTMs valid for the event field of Contrast::Api::Dtm::Message
68
+ # @param error [StandardError]
69
+ # @param connection [Net::HTTP] open connection
70
+ # @return nil [NilClass] to be passed as response
71
+ def handle_response_error event, connection, error
72
+ return end_of_rescue(event, error) if mode.resend.rescue_attempts >= RESCUE_ATTEMPTS
73
+
74
+ if RETRY_ERRORS.include?(error.cs__class)
75
+ mode.resend.increase_rescue_attempts
76
+ try_resend(event, connection, error)
77
+ else
78
+ end_of_rescue(event, error)
79
+ end
80
+ end
81
+
82
+ # End of rescue attempts.
83
+ #
84
+ # @param event [Contrast::Agent::Reporting::ReportingEvent]
85
+ # @param error [StandardError]
86
+ # @return [NilClass]
87
+ def end_of_rescue event, error
88
+ if Contrast::Agent::Reporting::ReporterClientUtils::STARTUP_EVENTS.include?(event.cs__class)
89
+ # Agent didn't send it's startup events, There will be reporting errors, disable reporting.
90
+ disable_reporting(event, error)
91
+ else
92
+ # There is an error in one of the reported messages, log that error and continue.
93
+ logger.error(END_RESENDING_MESSAGE,
94
+ resend_attempts: Contrast::Agent::Reporting::Resend::RESCUE_ATTEMPTS,
95
+ connection_error: error,
96
+ client: Contrast::Agent::Reporting::ReporterClient::SERVICE_NAME,
97
+ event_id: event&.__id__,
98
+ event_type: event&.cs__class&.cs__name)
99
+ end
100
+ end
101
+
102
+ # Disable reporting when there is an error that cannot be handled.
103
+ #
104
+ # @param event [Contrast::Agent::Reporting::ReportingEvent]
105
+ # @param error [StandardError]
106
+ # @return [NilClass]
107
+ def disable_reporting event, error
108
+ logger.error('[Agent] Disabling Reporting...', error: error.message, event_type: event.cs__class&.cs__name)
109
+ Contrast::AGENT.disable!
110
+ end
111
+
112
+ # Methods that will initialize the resending state.
113
+ class Status
114
+ # RESEND_STARTUP_EVENTS = 4
115
+
116
+ def initialize
117
+ @_rescue_attempts = 0
118
+ end
119
+
120
+ # return how many times the client has tried to rescue from error.
121
+ #
122
+ # @return [Integer]
123
+ def rescue_attempts
124
+ @_rescue_attempts ||= 0
125
+ end
126
+
127
+ # Reset Error rescues attempts.
128
+ #
129
+ # @return [Integer]
130
+ def reset_rescue_attempts
131
+ @_rescue_attempts = 0
132
+ end
133
+
134
+ # Increase the Error rescues attempts.
135
+ #
136
+ # @return [Integer]
137
+ def increase_rescue_attempts
138
+ @_rescue_attempts += 1
139
+ end
140
+ end
141
+ end
142
+ end
143
+ end
144
+ end
@@ -40,7 +40,7 @@ module Contrast
40
40
  assess_on: ::Contrast::ASSESS.enabled?)
41
41
  response
42
42
  rescue StandardError => e
43
- logger.error('Unable to process response from TeamServer', e)
43
+ logger.error('[Reporter] Unable to process response from TeamServer', e)
44
44
  nil
45
45
  end
46
46
 
@@ -63,11 +63,45 @@ module Contrast
63
63
  @_mode ||= Contrast::Agent::Reporting::ResponseHandlerMode.new
64
64
  end
65
65
 
66
+ # Puts the reporting service to sleep
67
+ def put_to_sleep
68
+ @_sleep = true
69
+ end
70
+
66
71
  # Wakes the reporting service
67
72
  def wake_up
68
73
  @_sleep = false
69
74
  end
70
75
 
76
+ # Suspend the reporter and try again in time. If not set
77
+ # the timeout is set to 15 min As default:
78
+ #
79
+ # @param message [String] Message to log.
80
+ # @param timeout [Integer,nil] The timeout to wait and retry after.
81
+ # @param error_message [String, nil] Error message if any received.
82
+ # @param event [Contrast::Agent::Reporting::ReportingEvent, nil] The event sent to TeamServer if set
83
+ # @param log_error [Boolean] Whether to log the error or not.
84
+ # @param startup [Boolean] Whether this is a startup error or not.
85
+ def suspend_reporting message, timeout, error_message, event: nil, log_error: true, startup: false
86
+ @_timeout = timeout || Contrast::Agent::Reporting::ResponseHandler::TIMEOUT
87
+ if log_error
88
+ log_error_msg(message,
89
+ timeout: @_timeout,
90
+ error_message: error_message || 'none',
91
+ event_id: event.nil? ? 'none' : event&.__id__,
92
+ event_type: event.nil? ? 'none' : event&.cs__class&.cs__name)
93
+ end
94
+ if startup
95
+ logger.info(message,
96
+ connection_error: error_message,
97
+ client: Contrast::Agent::Reporting::ReporterClient::SERVICE_NAME,
98
+ event_id: event&.__id__,
99
+ timeout: timeout,
100
+ event_type: event&.cs__class&.cs__name)
101
+ end
102
+ put_to_sleep
103
+ end
104
+
71
105
  private
72
106
 
73
107
  # Handles the errors code received from TS and takes appropriate action.
@@ -93,18 +127,6 @@ module Contrast
93
127
  end
94
128
  end
95
129
 
96
- # Suspend the reporter and try again in time. If not set
97
- # the timeout is set to 15 min As default:
98
- #
99
- # @param message [String] Message to log.
100
- # @param timeout [Integer,nil] The timeout to wait and retry after.
101
- # @param error_message [String, nil] Error message if any received.
102
- def suspend_reporting message, timeout, error_message
103
- @_timeout = timeout || Contrast::Agent::Reporting::ResponseHandler::TIMEOUT
104
- log_error_msg(message, timeout: @_timeout, error_message: error_message || 'none')
105
- @_sleep = true
106
- end
107
-
108
130
  # Log what we've received.
109
131
  #
110
132
  # @param message [String] Message to log
@@ -1,6 +1,8 @@
1
1
  # Copyright (c) 2023 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
2
2
  # frozen_string_literal: true
3
3
 
4
+ require 'contrast/agent/reporting/reporting_utilities/resend'
5
+
4
6
  module Contrast
5
7
  module Agent
6
8
  module Reporting
@@ -44,6 +46,17 @@ module Contrast
44
46
  @_status ||= running
45
47
  end
46
48
 
49
+ # Resend Status tracker
50
+ #
51
+ # @return [Contrast::Agent::Reporting::Resend::Status]
52
+ def resend
53
+ @_resend ||= Contrast::Agent::Reporting::Resend::Status.new
54
+ end
55
+
56
+ def enter_resend_mode
57
+ @_status = resending
58
+ end
59
+
47
60
  # Set current mode.
48
61
  #
49
62
  # @return [Symbol] Reporter's client and Response Handler
@@ -54,7 +67,7 @@ module Contrast
54
67
 
55
68
  # Reset mode
56
69
  #
57
- def reset_mode
70
+ def enter_run_mode
58
71
  @_status = running
59
72
  end
60
73
  end
@@ -4,6 +4,7 @@
4
4
  require 'contrast/agent/reporting/reporting_utilities/ng_response_extractor'
5
5
  require 'contrast/agent/reporting/reporting_utilities/response_extractor'
6
6
  require 'contrast/agent/reactions/disable_reaction'
7
+ require 'contrast/utils/json'
7
8
 
8
9
  module Contrast
9
10
  module Agent
@@ -53,6 +54,16 @@ module Contrast
53
54
  @_last_application_modified
54
55
  end
55
56
 
57
+ # Cease reporting about this application
58
+ #
59
+ # @param message [String] Message to log
60
+ # @param info_hash [Hash] information about the context to log.
61
+ def stop_reporting message, info_hash
62
+ Contrast::Agent.reporter&.stop!
63
+ log_error_msg(message, info_hash)
64
+ ::Contrast::AGENT.disable!
65
+ end
66
+
56
67
  private
57
68
 
58
69
  # check if response code is valid before analyze it
@@ -126,7 +137,7 @@ module Contrast
126
137
  # log, suspend, disable:
127
138
  if mode == @_mode.running
128
139
  log_error_msg(message,
129
- response: response.__id__,
140
+ response_id: response.__id__,
130
141
  request: Contrast::Agent::REQUEST_TRACKER.current&.request&.type,
131
142
  error_message: error_message || 'none',
132
143
  auth_error: auth_error || 'none')
@@ -175,16 +186,6 @@ module Contrast
175
186
  end
176
187
  end
177
188
 
178
- # Cease reporting about this application
179
- #
180
- # @param message [String] Message to log
181
- # @param info_hash [Hash] information about the context to log.
182
- def stop_reporting message, info_hash
183
- Contrast::Agent.reporter&.stop!
184
- log_error_msg(message, info_hash)
185
- ::Contrast::AGENT.disable!
186
- end
187
-
188
189
  # Applies the settings from the TS response
189
190
  #
190
191
  # @param response [Contrast::Agent::Reporting::Response]
@@ -257,7 +258,7 @@ module Contrast
257
258
  response_body = response&.body
258
259
  return unless response_body
259
260
 
260
- response_data = JSON.parse(response_body, symbolize_names: true)
261
+ response_data = Contrast::Utils::Json.parse(response_body, deep_symbolize: true)
261
262
  return unless response_data.cs__is_a?(Hash)
262
263
 
263
264
  extract_response_last_modified(response, event)
@@ -13,11 +13,14 @@ module Contrast
13
13
  RESEND_INTERVAL_MS = 30_000.cs__freeze
14
14
 
15
15
  def start_thread!
16
+ return unless attempt_to_start?
16
17
  return if running?
17
18
 
18
19
  @_thread = Contrast::Agent::Thread.new do
19
20
  logger.info('[ApplicationSettingsWorker] Starting thread.', sending_interval: application_server_ms)
20
21
  loop do
22
+ break unless attempt_to_start?
23
+
21
24
  logger.info('[ApplicationSettingsWorker] Fetching Settings', sending_interval: application_server_ms)
22
25
  Contrast::Agent.reporter&.send_event(application_settings_message)
23
26
  sleep(application_server_ms / 1000)
@@ -19,11 +19,14 @@ module Contrast
19
19
  REFRESH_INTERVAL_SEC = 60
20
20
 
21
21
  def start_thread!
22
+ return unless attempt_to_start?
22
23
  return if running?
23
24
 
24
25
  @_thread = Contrast::Agent::Thread.new do
25
26
  logger.info('[Heartbeat] Starting thread.')
26
27
  loop do
28
+ break unless attempt_to_start?
29
+
27
30
  polling_events.each do |event|
28
31
  Contrast::Agent.reporter&.send_event(event)
29
32
  end
@@ -13,11 +13,14 @@ module Contrast
13
13
  RESEND_INTERVAL_MS = 60_000.cs__freeze
14
14
 
15
15
  def start_thread!
16
+ return unless attempt_to_start?
16
17
  return if running?
17
18
 
18
19
  @_thread = Contrast::Agent::Thread.new do
19
20
  logger.info('[ServerSettingsWorker] Starting thread.', sending_interval: server_settings_resend_ms)
20
21
  loop do
22
+ break unless attempt_to_start?
23
+
21
24
  logger.info('[ServerSettingsWorker] Fetching Settings', sending_interval: server_settings_resend_ms)
22
25
  Contrast::Agent.reporter&.send_event(settings_message)
23
26
  sleep(server_settings_resend_ms / 1000)
@@ -10,6 +10,7 @@ require 'contrast/utils/hash_digest'
10
10
  require 'contrast/components/logger'
11
11
  require 'contrast/components/scope'
12
12
  require 'contrast/utils/request_utils'
13
+ require 'contrast/utils/duck_utils'
13
14
 
14
15
  module Contrast
15
16
  module Agent
@@ -24,12 +25,7 @@ module Contrast
24
25
 
25
26
  extend Forwardable
26
27
 
27
- INNER_REST_TOKEN = %r{/\d+/}.cs__freeze
28
- LAST_REST_TOKEN = %r{/\d+$}.cs__freeze
29
- INNER_NUMBER_MARKER = '/{n}/'
30
- LAST_NUMBER_MARKER = '/{n}'
31
- STATIC_SUFFIXES = /\.(?:js|css|jpeg|jpg|gif|png|ico|woff|svg|pdf|eot|ttf|jar)$/i.cs__freeze
32
- MEDIA_TYPE_MARKERS = %w[image/ text/css text/javascript].cs__freeze
28
+ EMPTY_PATH = '/'
33
29
 
34
30
  # @return [Rack::Request] The passed to the Agent RackRequest to be wrapped.
35
31
  attr_reader :rack_request
@@ -75,12 +71,31 @@ module Contrast
75
71
  def normalized_uri
76
72
  @_normalized_uri ||= begin
77
73
  path = rack_request.path_info || rack_request.path.to_s
78
- path = '/' if path.empty?
79
-
80
- uri = path.split(Contrast::Utils::ObjectShare::SEMICOLON)[0] # remove ;jsessionid
81
- uri = uri.split(Contrast::Utils::ObjectShare::QUESTION_MARK)[0] # remove ?query_string=
82
- uri.gsub(INNER_REST_TOKEN, INNER_NUMBER_MARKER) # replace interior tokens
83
- uri.gsub(LAST_REST_TOKEN, LAST_NUMBER_MARKER) # replace last token
74
+ path = EMPTY_PATH if Contrast::Utils::DuckUtils.empty_duck?(path)
75
+
76
+ # /foo/bar;jsessionid=123 => /foo/bar
77
+ uri = path.split(Contrast::Utils::ObjectShare::SEMICOLON)[0]
78
+ # /foo/bar?query_string=123 => /foo/bar
79
+ uri = uri.split(Contrast::Utils::ObjectShare::QUESTION_MARK)[0]
80
+
81
+ # Replace with tokens:
82
+ # NUM_ => '/{n}/'
83
+ # ID_ => '{ID}'
84
+ #
85
+ # replace UUIDs: /123e4567-e89b-42d3-a456-556642440000/ => /{ID}/
86
+ uri.gsub!(UUID_PATTERN, ID_)
87
+ # replace hash patterns: /6f1ed002ab5595859014ebf0951522d9/ => /{ID}/
88
+ uri.gsub!(HASH_PATTERN, ID_)
89
+ # replace windows SID: /S-1-5-21-1843332746-572796286-2118856591-1000/ => /{ID}/
90
+ uri.gsub!(WIN_PATTERN, ID_)
91
+ # replace interior number tokens: /123/ => /{n}/
92
+ uri.gsub!(NUM_PATTERN, NUM_)
93
+ # replace last number tokens: /123 => /{n}
94
+ uri.gsub!(END_PATTERN, NUM_[0..-2])
95
+ uri
96
+ rescue StandardError => e
97
+ logger.error('error normalizing uri', error: e, backtrace: e.backtrace)
98
+ EMPTY_PATH
84
99
  end
85
100
  end
86
101