contrast-agent 6.1.2 → 6.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (70) hide show
  1. checksums.yaml +4 -4
  2. data/lib/contrast/agent/at_exit_hook.rb +2 -1
  3. data/lib/contrast/agent/inventory/dependency_usage_analysis.rb +9 -5
  4. data/lib/contrast/agent/protect/rule/xss.rb +4 -0
  5. data/lib/contrast/agent/reporting/reporter.rb +2 -11
  6. data/lib/contrast/agent/reporting/reporting_events/application_inventory.rb +3 -18
  7. data/lib/contrast/agent/reporting/reporting_events/discovered_route.rb +75 -15
  8. data/lib/contrast/agent/reporting/reporting_events/finding.rb +2 -2
  9. data/lib/contrast/agent/reporting/reporting_events/library_usage_observation.rb +5 -19
  10. data/lib/contrast/agent/reporting/reporting_events/observed_library_usage.rb +6 -22
  11. data/lib/contrast/agent/reporting/reporting_events/observed_route.rb +1 -1
  12. data/lib/contrast/agent/reporting/reporting_events/preflight_message.rb +2 -3
  13. data/lib/contrast/agent/reporting/reporting_events/reporting_event.rb +1 -3
  14. data/lib/contrast/agent/reporting/reporting_events/route_coverage.rb +9 -0
  15. data/lib/contrast/agent/reporting/reporting_utilities/audit.rb +1 -2
  16. data/lib/contrast/agent/reporting/reporting_utilities/dtm_message.rb +0 -10
  17. data/lib/contrast/agent/reporting/reporting_utilities/reporter_client.rb +0 -1
  18. data/lib/contrast/agent/reporting/reporting_utilities/response.rb +60 -2
  19. data/lib/contrast/agent/reporting/reporting_utilities/response_extractor.rb +32 -10
  20. data/lib/contrast/agent/reporting/reporting_utilities/response_handler.rb +1 -1
  21. data/lib/contrast/agent/reporting/reporting_utilities/response_handler_utils.rb +58 -26
  22. data/lib/contrast/agent/reporting/settings/application_settings.rb +8 -23
  23. data/lib/contrast/agent/reporting/settings/assess_server_feature.rb +27 -33
  24. data/lib/contrast/agent/reporting/settings/bot_blocker.rb +68 -0
  25. data/lib/contrast/agent/reporting/settings/code_exclusion.rb +27 -0
  26. data/lib/contrast/agent/reporting/settings/exclusion_base.rb +33 -0
  27. data/lib/contrast/agent/reporting/settings/exclusions.rb +39 -57
  28. data/lib/contrast/agent/reporting/settings/helpers.rb +56 -0
  29. data/lib/contrast/agent/reporting/settings/input_exclusion.rb +37 -0
  30. data/lib/contrast/agent/reporting/settings/ip_filter.rb +35 -0
  31. data/lib/contrast/agent/reporting/settings/keyword.rb +74 -0
  32. data/lib/contrast/agent/reporting/settings/log_enhancer.rb +65 -0
  33. data/lib/contrast/agent/reporting/settings/protect.rb +4 -2
  34. data/lib/contrast/agent/reporting/settings/protect_server_feature.rb +62 -115
  35. data/lib/contrast/agent/reporting/settings/reaction.rb +11 -2
  36. data/lib/contrast/agent/reporting/settings/rule_definition.rb +63 -0
  37. data/lib/contrast/agent/reporting/settings/sampling.rb +10 -0
  38. data/lib/contrast/agent/reporting/settings/sanitizer.rb +38 -0
  39. data/lib/contrast/agent/reporting/settings/sensitive_data_masking.rb +9 -1
  40. data/lib/contrast/agent/reporting/settings/sensitive_data_masking_rule.rb +7 -0
  41. data/lib/contrast/agent/reporting/settings/server_features.rb +8 -0
  42. data/lib/contrast/agent/reporting/settings/syslog.rb +176 -0
  43. data/lib/contrast/agent/reporting/settings/url_exclusion.rb +42 -0
  44. data/lib/contrast/agent/reporting/settings/validator.rb +17 -0
  45. data/lib/contrast/agent/request_context.rb +4 -0
  46. data/lib/contrast/agent/request_handler.rb +8 -4
  47. data/lib/contrast/agent/static_analysis.rb +4 -8
  48. data/lib/contrast/agent/telemetry/events/exceptions/telemetry_exceptions_report.rb +1 -1
  49. data/lib/contrast/agent/thread_watcher.rb +4 -5
  50. data/lib/contrast/agent/version.rb +1 -1
  51. data/lib/contrast/agent.rb +1 -3
  52. data/lib/contrast/api/decorators/application_update.rb +0 -8
  53. data/lib/contrast/api/decorators.rb +0 -1
  54. data/lib/contrast/framework/base_support.rb +5 -4
  55. data/lib/contrast/framework/grape/support.rb +6 -6
  56. data/lib/contrast/framework/manager.rb +2 -4
  57. data/lib/contrast/framework/manager_extend.rb +1 -0
  58. data/lib/contrast/framework/rails/patch/action_controller_live_buffer.rb +2 -1
  59. data/lib/contrast/framework/rails/support.rb +9 -2
  60. data/lib/contrast/framework/sinatra/support.rb +3 -2
  61. data/lib/contrast/logger/aliased_logging.rb +31 -26
  62. data/lib/contrast/utils/response_utils.rb +14 -1
  63. data/lib/contrast/utils/telemetry.rb +9 -0
  64. data/lib/contrast/utils/telemetry_hash.rb +36 -12
  65. data/lib/contrast/utils/telemetry_identifier.rb +8 -0
  66. data/lib/contrast/utils/thread_tracker.rb +26 -9
  67. data/lib/contrast/utils/timer.rb +6 -1
  68. data/lib/contrast.rb +1 -3
  69. metadata +26 -14
  70. data/lib/contrast/api/decorators/library_usage_update.rb +0 -31
@@ -152,9 +152,9 @@ module Contrast
152
152
  #
153
153
  # @param response [Contrast::Agent::Reporting::Response]
154
154
  def update_reaction response
155
- return unless response.application_settings&.reactions&.any?
155
+ return unless response&.reactions&.any?
156
156
 
157
- response.application_settings.reactions.each do |reaction|
157
+ response.reactions.each do |reaction|
158
158
  # The enums are all uppercase, we need to downcase them before attempting to log.
159
159
  level = reaction.level.nil? ? :error : reaction.level.downcase
160
160
  logger.with_level(level, reaction.message) if reaction.message
@@ -198,50 +198,82 @@ module Contrast
198
198
  response_body = response&.body
199
199
  return unless response_body
200
200
 
201
- response_data = JSON.parse(response_body)
201
+ response_data = JSON.parse(response_body, symbolize_names: true)
202
202
  return unless response_data.cs__is_a?(Hash)
203
203
 
204
- response_data = response_data.deep_symbolize_keys
204
+ populate_response(response_data)
205
+ rescue StandardError => e
206
+ logger.error('Unable to convert response', e)
207
+ nil
208
+ end
209
+
210
+ # Extracts the data from the response and coverts it to
211
+ # Contrast::Agent::Reporting::Response.
212
+ #
213
+ # @param response_data[Hash]
214
+ # @return response [Contrast::Agent::Reporting::Response]
215
+ def populate_response response_data
216
+ return unless (success, messages = extract_success(response_data))
217
+
205
218
  # check if response contains application settings or Feature settings
206
219
  if response_data[:settings]
207
220
  # the response contains ApplicationSettings
208
- app_settings = build_application_settings(response_data)
221
+ response = Contrast::Agent::Reporting::Response.build_application_response
222
+ response.success = success
223
+ response.messages = messages
224
+ app_settings = build_application_settings(response_data, response)
209
225
  logger.trace('Agent: Received updated application settings', raw: response_data, processed: app_settings)
210
226
  app_settings
211
227
  else
212
228
  # the response contains FeatureSettings
213
- server_features = build_feature_settings(response_data)
229
+ response = Contrast::Agent::Reporting::Response.build_server_response
230
+ response.success = success
231
+ response.messages = messages
232
+ server_features = build_feature_settings(response_data, response)
214
233
  logger.trace('Agent: Received updated application settings', raw: response_data, processed: server_features)
215
234
  server_features
216
235
  end
217
- rescue StandardError => e
218
- logger.error('Unable to convert response', e)
219
- nil
236
+ response
220
237
  end
221
238
 
222
239
  # @param response_data [Hash]
223
240
  # @return res [Contrast::Agent::Reporting::Response]
224
- def build_application_settings response_data
225
- res = Contrast::Agent::Reporting::Response.application_response
226
- extract_assess(response_data, res)
227
- extract_protect(response_data, res)
228
- extract_exclusions(response_data, res)
229
- extract_reactions(response_data, res)
230
- extract_sensitive_data_policy(response_data, res)
231
- res
241
+ def build_application_settings response_data, response
242
+ extract_assess(response_data, response)
243
+ extract_protect(response_data, response)
244
+ extract_exclusions(response_data, response)
245
+ extract_reactions(response_data, response)
246
+ extract_sensitive_data_policy(response_data, response)
247
+ response
232
248
  end
233
249
 
234
250
  # @param response_data [Hash]
235
251
  # @return res [Contrast::Agent::Reporting::Response]
236
- def build_feature_settings response_data
237
- res = Contrast::Agent::Reporting::Response.server_response
238
- extract_assess_server_features(response_data, res)
239
- extract_protect_server_features(response_data, res)
240
- extract_protect_lists(response_data, res)
241
- res.server_features.log_level = response_data[:logLevel]
242
- res.server_features.log_file = response_data[:logFile]
243
- res.server_features.telemetry = response_data[:telemetry]
244
- res
252
+ def build_feature_settings response_data, response
253
+ extract_reactions(response_data, response)
254
+ extract_assess_server_features(response_data, response)
255
+ extract_protect_server_features(response_data, response)
256
+ extract_protect_lists(response_data, response)
257
+ extract_log_settings(response_data, response)
258
+ response.server_features.telemetry = response_data[:telemetry]
259
+ response
260
+ end
261
+
262
+ # This method with check the success and messages field of the response.
263
+ # If the success is false, then it will return nil and log the error.
264
+ #
265
+ # @param response_data [Hash]
266
+ # @return [Array, nil] Returns the success status or nil if request
267
+ # was not processed by TS.
268
+ def extract_success response_data
269
+ success = response_data[:success]
270
+ messages = response_data[:messages]
271
+ return [success, messages] if success
272
+
273
+ logger.error('Unable to connect to Contrast UI') if messages.nil?
274
+ logger.error('Failure on Contrast UI processing request', reasons: messages.join(', ')) if messages
275
+
276
+ nil
245
277
  end
246
278
  end
247
279
  end
@@ -37,13 +37,6 @@ module Contrast
37
37
  @_exclusions ||= Contrast::Agent::Reporting::Settings::Exclusions.new
38
38
  end
39
39
 
40
- # Reaction the agent should take based on a state in TS.
41
- #
42
- # @return [Array<Contrast::Agent::Reporting::Settings::Reaction>, nil]
43
- def reactions
44
- @_reactions
45
- end
46
-
47
40
  # This object will hold the masking rules send from TS.
48
41
  #
49
42
  # @return sensitive_data_masking [Contrast::Agent::Reporting::Settings::SensitiveDataMasking] this object
@@ -52,22 +45,14 @@ module Contrast
52
45
  @_sensitive_data_masking ||= Contrast::Agent::Reporting::Settings::SensitiveDataMasking.new
53
46
  end
54
47
 
55
- # Set the reaction
56
- #
57
- # @param reactions [Array<Reaction>] {
58
- # level [String] The level at which the agent should log this reaction.
59
- # [ERROR, WARN, INFO, DEBUG, TRACE]
60
- # message [String] A message to log when receiving this reaction.
61
- # operation [String] What to do in response to this reaction.[NOOP, DISABLE] }
62
- # @return [Array<Contrast::Agent::Reporting::Settings::Reaction>]
63
- def reactions= reactions
64
- return unless reactions.is_a?(Array)
65
-
66
- @_reactions = []
67
- reactions.each do |r|
68
- reaction = Contrast::Agent::Reporting::Settings::Reaction.new(r[:level], r[:operation], r[:message])
69
- @_reactions << reaction
70
- end
48
+ # Currently protect and assess are not covered with to_controlled_hash methods
49
+ def to_controlled_hash
50
+ {
51
+ defend: {},
52
+ exceptions: exclusions.to_controlled_hash,
53
+ assessment: {},
54
+ sensitive_data_masking_policy: sensitive_data_masking.to_controlled_hash
55
+ }
71
56
  end
72
57
  end
73
58
  end
@@ -3,6 +3,9 @@
3
3
 
4
4
  require 'contrast/utils/object_share'
5
5
  require 'contrast/agent/reporting/settings/sampling'
6
+ require 'contrast/agent/reporting/settings/sanitizer'
7
+ require 'contrast/agent/reporting/settings/validator'
8
+ require 'contrast/agent/reporting/settings/helpers'
6
9
 
7
10
  module Contrast
8
11
  module Agent
@@ -52,54 +55,45 @@ module Contrast
52
55
 
53
56
  # The sanitizers defined by the user for use by the agent on this server for this organization.
54
57
  #
55
- # @return sanitizers [Array<AssessCustomRules>] AssessCustomRules
56
- # Api [String], Rules [Array[RulesID]]
57
- # tags [Array[String]]
58
- # uuid [String]
58
+ # @return sanitizers [Array<Contrast::Agent::Reporting::Settings::Sanitizer>]
59
59
  def sanitizers
60
60
  @_sanitizers ||= []
61
61
  end
62
62
 
63
63
  # set sanitizer
64
64
  #
65
- # @param sanitizers [Array<AssessCustomRules>] of AssessCustomRule: {
66
- # Api [String], Rules [Array[RulesID]]
67
- # tags [Array[String]]
68
- # uuid [String]
69
- # }
70
- # @return sanitizers [Array<AssessCustomRules>] AssessCustomRules
71
- # Api [String], Rules [Array[RulesID]]
72
- # tags [Array[String]]
73
- # uuid [String]
74
- def sanitizers= sanitizers
75
- @_sanitizers = sanitizers if sanitizers.is_a?(Array)
65
+ # @param sanitizers_array [Array<Contrast::Agent::Reporting::Settings::Sanitizer>]
66
+ # @return sanitizers [Array<Contrast::Agent::Reporting::Settings::Sanitizer>]
67
+ def sanitizers= sanitizers_array
68
+ Contrast::Agent::Reporting::Settings::Helpers.array_to_iv(Contrast::Agent::Reporting::Settings::Sanitizer,
69
+ sanitizers,
70
+ sanitizers_array)
76
71
  end
77
72
 
78
73
  # The validators defined by the user for use by the agent on this server for this organization.
79
74
  #
80
- # @return validators [Array<AssessCustomRules>] of AssessCustomRule: {
81
- # Api [String], Rules [Array[RulesID]]
82
- # tags [Array[String]]
83
- # uuid [String]
84
- # }
75
+ # @return sanitizers [Array<Contrast::Agent::Reporting::Settings::Validator>]
85
76
  def validators
86
77
  @_validators ||= []
87
78
  end
88
79
 
89
- # The validators defined by the user for use by the agent on this server for this organization.
80
+ # set validators
90
81
  #
91
- # @param validators [Array<AssessCustomRules>] of AssessCustomRule: {
92
- # Api [String], Rules [Array[RulesID]]
93
- # tags [Array[String]]
94
- # uuid [String]
95
- # }
96
- # @return validators [Array<AssessCustomRules>] of AssessCustomRule: {
97
- # Api [String], Rules [Array[RulesID]]
98
- # tags [Array[String]]
99
- # uuid [String]
100
- # }
101
- def validators= validators
102
- @_validators = validators if validators.is_a?(Array)
82
+ # @param validators_array [Array<Contrast::Agent::Reporting::Settings::Validator>]
83
+ # @return sanitizers [Array<Contrast::Agent::Reporting::Settings::Validator>]
84
+ def validators= validators_array
85
+ Contrast::Agent::Reporting::Settings::Helpers.array_to_iv(Contrast::Agent::Reporting::Settings::Validator,
86
+ validators,
87
+ validators_array)
88
+ end
89
+
90
+ def to_controlled_hash
91
+ {
92
+ enabled: enabled?,
93
+ sampling: sampling.to_controlled_hash,
94
+ sanitizers: sanitizers.map(&:to_controlled_hash),
95
+ validators: validators.map(&:to_controlled_hash)
96
+ }
103
97
  end
104
98
  end
105
99
  end
@@ -0,0 +1,68 @@
1
+ # Copyright (c) 2022 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/settings/helpers'
5
+
6
+ module Contrast
7
+ module Agent
8
+ module Reporting
9
+ module Settings
10
+ # Indicate if the bot protection feature set is enabled for this server or not.
11
+ class BotBlocker
12
+ # @return [Boolean]
13
+ attr_accessor :enable
14
+
15
+ def initialize
16
+ @enable = true
17
+ end
18
+
19
+ # @return bots [Hash<Contrast::Agent::Reporting::Settings::Bot>, []]
20
+ def bots
21
+ @_bots ||= []
22
+ end
23
+
24
+ def bots= bots_array
25
+ Contrast::Agent::Reporting::Settings::Helpers.array_to_iv(Contrast::Agent::Reporting::Settings::Bot,
26
+ bots,
27
+ bots_array)
28
+ end
29
+
30
+ # We should be receiving:
31
+ # bot_blockers { enable, bots[{bot, case_sensitive, start_anchor}]}
32
+ # Instead in the response there is bot_blockers[], and the enable
33
+ # which can be retrieved from bot-blocker.
34
+ def to_controlled_hash
35
+ @enable
36
+ end
37
+ end
38
+
39
+ # This class is used to represent a Bot entity inside the bots array.
40
+ class Bot
41
+ ATTRIBUTES = %i[bot case_sensitive start_anchor].cs__freeze
42
+
43
+ # @return bot [String]
44
+ attr_accessor :bot
45
+ # @return case_sensitive [Boolean] Whether the name is case-sensitive
46
+ # or not.
47
+ attr_accessor :case_sensitive
48
+ # @return start_anchor [Boolean]
49
+ attr_accessor :start_anchor
50
+
51
+ def initialize
52
+ # default values of properties:
53
+ @start_anchor = false
54
+ @case_sensitive = false
55
+ end
56
+
57
+ def to_controlled_hash
58
+ {
59
+ bot: bot,
60
+ caseSensitive: case_sensitive,
61
+ startAnchor: start_anchor
62
+ }
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,27 @@
1
+ # Copyright (c) 2022 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/settings/exclusion_base'
5
+
6
+ module Contrast
7
+ module Agent
8
+ module Reporting
9
+ module Settings
10
+ # CodeExclusions class
11
+ class CodeExclusion < ExclusionBase
12
+ ATTRIBUTES = BASE_ATTRIBUTES.dup << :denylist
13
+ ATTRIBUTES.cs__freeze
14
+
15
+ # @return denylist [Array<String>] #rubocop:disable [Naming/InclusiveLanguage]
16
+ attr_accessor :denylist
17
+
18
+ def to_controlled_hash
19
+ hash = super
20
+ hash[:denylist] = denylist
21
+ hash
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,33 @@
1
+ # Copyright (c) 2022 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 Settings
8
+ # Base class to represent common exclusions fields.
9
+ class ExclusionBase
10
+ BASE_ATTRIBUTES = %i[name modes assess_rules protect_rules].cs__freeze
11
+
12
+ # @return name [String]
13
+ attr_accessor :name
14
+ # @return modes [Array<String>]
15
+ attr_accessor :modes
16
+ # @return assess_rules [Array<String>]
17
+ attr_accessor :assess_rules
18
+ # @return protect_rules [Array<String>]
19
+ attr_accessor :protect_rules
20
+
21
+ def to_controlled_hash
22
+ {
23
+ name: name, # rubocop:disable Security/Module/Name
24
+ modes: modes,
25
+ assessRules: assess_rules,
26
+ protectRules: protect_rules
27
+ }
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -1,6 +1,11 @@
1
1
  # Copyright (c) 2022 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/settings/code_exclusion'
5
+ require 'contrast/agent/reporting/settings/input_exclusion'
6
+ require 'contrast/agent/reporting/settings/url_exclusion'
7
+ require 'contrast/agent/reporting/settings/helpers'
8
+
4
9
  module Contrast
5
10
  module Agent
6
11
  module Reporting
@@ -11,52 +16,38 @@ module Contrast
11
16
  class Exclusions
12
17
  # Cases where rules should be excluded if violated in a method call
13
18
  #
14
- # @return code_exclusions [Array<CodeExclusion>] Array of CodeExclusion: {
15
- # name [String] The name of the exclusion as defined by the user in TS.
16
- # modes [String] If this exclusion applies to assess or protect. [assess, defend]
17
- # assess_rules [Array] Array of assess rules to which this exclusion applies. AssessRuleID [String]
18
- # denylist [String] The call, if in the stack, should result in the agent not taking action.
19
- # }
19
+ # @return code_exclusions [Array<Contrast::Agent::Reporting::Settings::CodeExclusion>] Array of CodeExclusion
20
20
  def code_exclusions
21
21
  @_code_exclusions ||= []
22
22
  end
23
23
 
24
24
  # set the CodeExclusions array
25
25
  #
26
- # @param code_exclusions [Array<CodeExclusion>] Array of CodeExclusion: {
26
+ # @param new_code_exclusions [Array<CodeExclusion>] Array of CodeExclusion: {
27
27
  # name [String] The name of the exclusion as defined by the user in TS.
28
28
  # modes [String] If this exclusion applies to assess or protect. [assess, defend]
29
29
  # assess_rules [Array] Array of assess rules to which this exclusion applies. AssessRuleID [String]
30
30
  # denylist [String] The call, if in the stack, should result in the agent not taking action.
31
31
  # }
32
- # @return code_exclusions [Array<CodeExclusion>] Array of CodeExclusion: {
33
- # name [String] The name of the exclusion as defined by the user in TS.
34
- # modes [String] If this exclusion applies to assess or protect. [assess, defend]
35
- # assess_rules [Array] Array of assess rules to which this exclusion applies. AssessRuleID [String]
36
- # denylist [String] The call, if in the stack, should result in the agent not taking action.
37
- # }
38
- def code_exclusions= code_exclusions
39
- @_code_exclusions = code_exclusions if code_exclusions.is_a?(Array)
32
+ # @return code_exclusions [Array<Contrast::Agent::Reporting::Settings::CodeExclusion>] Array of CodeExclusion
33
+ def code_exclusions= new_code_exclusions
34
+ @_code_exclusions = Contrast::Agent::Reporting::Settings::Helpers.array_to_iv(
35
+ Contrast::Agent::Reporting::Settings::CodeExclusion,
36
+ code_exclusions,
37
+ new_code_exclusions)
40
38
  end
41
39
 
42
40
  # Cases where rules should be excluded if violated from a given input.
43
41
  #
44
- # @return input_exclusions [Array<InputExclusions>] Array of InputExclusions: {
45
- # name [String] The name of the input.
46
- # modes [String] If this exclusion applies to assess or protect. [assess, defend]
47
- # assess_rules [Array] Array of assess rules to which this exclusion applies. AssessRuleID [String]
48
- # protect_rules [Array] Array of ProtectRuleID [String] The protect rules to which this exclusion applies.
49
- # urls [Array] Array of URLs to which the exclusions apply. URL [String]
50
- # match_strategy [String] If this exclusion applies to all URLs or only those specified. [ALL, ONLY]
51
- # type [String] The type of the input [COOKIE, PARAMETER, HEADER, BODY, QUERYSTRING]
52
- # }
42
+ # @return input_exclusions [Array<Contrast::Agent::Reporting::Settings::InputExclusions>]
43
+ # Array of InputExclusions
53
44
  def input_exclusions
54
45
  @_input_exclusions ||= []
55
46
  end
56
47
 
57
48
  # set the InputExclusions array
58
49
  #
59
- # @param input_exclusions [Array<InputExclusions>] Array of InputExclusions: {
50
+ # @param new_input_exclusions [Array<InputExclusions>] Array of InputExclusions: {
60
51
  # name [String] The name of the input.
61
52
  # modes [String] If this exclusion applies to assess or protect. [assess, defend]
62
53
  # assess_rules [Array] Array of assess rules to which this exclusion applies. AssessRuleID [String]
@@ -65,37 +56,25 @@ module Contrast
65
56
  # match_strategy [String] If this exclusion applies to all URLs or only those specified. [ALL, ONLY]
66
57
  # type [String] The type of the input [COOKIE, PARAMETER, HEADER, BODY, QUERYSTRING]
67
58
  # }
68
- # @return input_exclusions [Array<InputExclusions>] Array of InputExclusions: {
69
- # name [String] The name of the input.
70
- # modes [String] If this exclusion applies to assess or protect. [assess, defend]
71
- # assess_rules [Array] Array of assess rules to which this exclusion applies. AssessRuleID [String]
72
- # protect_rules [Array] Array of ProtectRuleID [String] The protect rules to which this exclusion applies.
73
- # urls [Array] Array of URLs to which the exclusions apply. URL [String]
74
- # match_strategy [String] If this exclusion applies to all URLs or only those specified. [ALL, ONLY]
75
- # type [String] The type of the input [COOKIE, PARAMETER, HEADER, BODY, QUERYSTRING]
76
- # }
77
- def input_exclusions= input_exclusions
78
- @_input_exclusions = input_exclusions if input_exclusions.is_a?(Array)
59
+ # @return input_exclusions [Array<Contrast::Agent::Reporting::Settings::InputExclusions>]
60
+ # Array of InputExclusions
61
+ def input_exclusions= new_input_exclusions
62
+ @_input_exclusions = Contrast::Agent::Reporting::Settings::Helpers.array_to_iv(
63
+ Contrast::Agent::Reporting::Settings::InputExclusion,
64
+ input_exclusions,
65
+ new_input_exclusions)
79
66
  end
80
67
 
81
68
  # A case where rules should be excluded if violated during a call to a given URL.
82
69
  #
83
- # @return url_exclusions [Array<UrlExclusions>] Array of UrlExclusions: {
84
- # name [String] The name of the input.
85
- # modes [String] If this exclusion applies to assess or protect. [assess, defend]
86
- # assess_rules [Array] Array of assess rules to which this exclusion applies. AssessRuleID [String]
87
- # protect_rules [Array] Array of ProtectRuleID [String] The protect rules to which this exclusion applies.
88
- # urls [Array] Array of URLs to which the exclusions apply. URL [String]
89
- # match_strategy [String] If this exclusion applies to all URLs or only those specified. [ALL, ONLY]
90
- # type [String] The type of the input [COOKIE, PARAMETER, HEADER, BODY, QUERYSTRING]
91
- # }
70
+ # @return url_exclusions [Array<Contrast::Agent::Reporting::Settings::UrlExclusion>] Array of UrlExclusions
92
71
  def url_exclusions
93
72
  @_url_exclusions ||= []
94
73
  end
95
74
 
96
75
  # set the UrlExclusions array
97
76
  #
98
- # @param url_exclusions [Array] Array of UrlExclusions: {
77
+ # @param new_url_exclusions [Array] Array of UrlExclusions: {
99
78
  # name [String] The name of the input.
100
79
  # modes [String] If this exclusion applies to assess or protect. [assess, defend]
101
80
  # assess_rules [Array] Array of assess rules to which this exclusion applies. AssessRuleID [String]
@@ -104,17 +83,20 @@ module Contrast
104
83
  # match_strategy [String] If this exclusion applies to all URLs or only those specified. [ALL, ONLY]
105
84
  # type [String] The type of the input [COOKIE, PARAMETER, HEADER, BODY, QUERYSTRING]
106
85
  # }
107
- # @return url_exclusions [Array<UrlExclusions>] Array of UrlExclusions: {
108
- # name [String] The name of the input.
109
- # modes [String] If this exclusion applies to assess or protect. [assess, defend]
110
- # assess_rules [Array] Array of assess rules to which this exclusion applies. AssessRuleID [String]
111
- # protect_rules [Array] Array of ProtectRuleID [String] The protect rules to which this exclusion applies.
112
- # urls [Array] Array of URLs to which the exclusions apply. URL [String]
113
- # match_strategy [String] If this exclusion applies to all URLs or only those specified. [ALL, ONLY]
114
- # type [String] The type of the input [COOKIE, PARAMETER, HEADER, BODY, QUERYSTRING]
115
- # }
116
- def url_exclusions= url_exclusions
117
- @_url_exclusions = url_exclusions if url_exclusions.is_a?(Array)
86
+ # @return url_exclusions [Array<Contrast::Agent::Reporting::Settings::UrlExclusion>] Array of UrlExclusions
87
+ def url_exclusions= new_url_exclusions
88
+ @_url_exclusions = Contrast::Agent::Reporting::Settings::Helpers.array_to_iv(
89
+ Contrast::Agent::Reporting::Settings::UrlExclusion,
90
+ url_exclusions,
91
+ new_url_exclusions)
92
+ end
93
+
94
+ def to_controlled_hash
95
+ {
96
+ codeExceptions: code_exclusions.map(&:to_controlled_hash),
97
+ inputExceptions: input_exclusions.map(&:to_controlled_hash),
98
+ urlExceptions: url_exclusions.map(&:to_controlled_hash)
99
+ }
118
100
  end
119
101
  end
120
102
  end
@@ -0,0 +1,56 @@
1
+ # Copyright (c) 2022 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 Settings
8
+ # Helper methods used across the settings.
9
+ module Helpers
10
+ class << self
11
+ # Fills instance variable [Array] with new settings as new instance type
12
+ # for each entry.
13
+ #
14
+ # @param instance_type [Class] a class to create new instance from to
15
+ # @param instance_variable [Array] instance variable accessor method
16
+ # return an array to fill.
17
+ # @param array [Array] array to be used to fill the iv.
18
+ # fill the iv with the new type containing data from the provided array
19
+ # param.
20
+ # @return instance_variable [Class]
21
+ def array_to_iv instance_type, instance_variable, array
22
+ return unless array.is_a?(Array)
23
+
24
+ array.each_with_index do |entry, index|
25
+ new_instance = instance_type.new
26
+ instance_type::ATTRIBUTES.each do |attr|
27
+ new_instance.send("#{ attr }=".to_sym, entry[no_more_underscore(attr)])
28
+ end
29
+ instance_variable[index] = new_instance
30
+ end
31
+
32
+ instance_variable
33
+ end
34
+
35
+ # :attr_name => :attrName
36
+ # return original if no '_'
37
+ #
38
+ # @param attr_name [Symbol]
39
+ # @return normalized_name [Symbol]
40
+ def no_more_underscore attr_name
41
+ name = attr_name.to_s
42
+ idx = name.index('_')
43
+ return attr_name if idx.nil? || (idx.zero? && idx >= name.length)
44
+
45
+ result = name
46
+ result.slice!(idx)
47
+ result.insert(idx, name[idx]&.upcase)
48
+ result.slice!(idx + 1)
49
+ result.index('_') ? no_more_underscore(result).to_sym : result.to_sym
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,37 @@
1
+ # Copyright (c) 2022 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/settings/exclusion_base'
5
+ require 'contrast/utils/object_share'
6
+
7
+ module Contrast
8
+ module Agent
9
+ module Reporting
10
+ module Settings
11
+ # InputExclusions class
12
+ class InputExclusion < ExclusionBase
13
+ ATTRIBUTES = BASE_ATTRIBUTES.dup << :type
14
+ ATTRIBUTES.cs__freeze
15
+ VALID_INPUT_TYPES = %w[COOKIE PARAMETER HEADER BODY QUERYSTRING].cs__freeze
16
+
17
+ # @return type [String] The type of the input
18
+ def type
19
+ @_type ||= Contrast::Utils::ObjectShare::EMPTY_STRING
20
+ end
21
+
22
+ # @param new_type [String] Set new input type.
23
+ # @return type [String] The type of the input.
24
+ def type= new_type
25
+ @_type = new_type if VALID_INPUT_TYPES.include?(new_type)
26
+ end
27
+
28
+ def to_controlled_hash
29
+ hash = super
30
+ hash[:type] = type
31
+ hash
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end