contrast-agent 3.8.5 → 3.9.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/cs__assess_array/cs__assess_array.c +1 -1
- data/ext/cs__assess_module/cs__assess_module.c +0 -1
- data/ext/cs__assess_yield_track/cs__assess_yield_track.c +34 -0
- data/ext/cs__assess_yield_track/cs__assess_yield_track.h +12 -0
- data/ext/{cs__scope → cs__assess_yield_track}/extconf.rb +0 -0
- data/ext/cs__common/cs__common.c +6 -6
- data/ext/cs__common/cs__common.h +3 -1
- data/ext/cs__contrast_patch/cs__contrast_patch.c +142 -119
- data/ext/cs__contrast_patch/cs__contrast_patch.h +3 -0
- data/funchook/autom4te.cache/requests +48 -48
- data/funchook/config.log +2 -2
- data/lib/contrast/agent.rb +15 -5
- data/lib/contrast/agent/assess.rb +0 -1
- data/lib/contrast/agent/assess/contrast_event.rb +9 -8
- data/lib/contrast/agent/assess/policy/dynamic_source_factory.rb +68 -18
- data/lib/contrast/agent/assess/policy/policy.rb +0 -14
- data/lib/contrast/agent/assess/policy/policy_scanner.rb +1 -1
- data/lib/contrast/agent/assess/policy/preshift.rb +1 -1
- data/lib/contrast/agent/assess/policy/propagation_method.rb +4 -2
- data/lib/contrast/agent/assess/policy/propagator/custom.rb +1 -1
- data/lib/contrast/agent/assess/policy/propagator/database_write.rb +1 -1
- data/lib/contrast/agent/assess/policy/propagator/splat.rb +2 -2
- data/lib/contrast/agent/assess/policy/propagator/split.rb +166 -1
- data/lib/contrast/agent/assess/policy/rewriter_patch.rb +1 -0
- data/lib/contrast/agent/assess/policy/source_method.rb +199 -140
- data/lib/contrast/agent/assess/policy/source_validation/cross_site_validator.rb +30 -0
- data/lib/contrast/agent/assess/policy/source_validation/source_validation.rb +36 -0
- data/lib/contrast/agent/assess/policy/trigger_method.rb +238 -153
- data/lib/contrast/agent/assess/policy/trigger_node.rb +54 -9
- data/lib/contrast/agent/assess/policy/trigger_validation/trigger_validation.rb +13 -0
- data/lib/contrast/agent/assess/properties.rb +29 -0
- data/lib/contrast/agent/assess/rule/csrf/csrf_applicator.rb +35 -31
- data/lib/contrast/agent/assess/rule/provider/hardcoded_value_rule.rb +1 -1
- data/lib/contrast/agent/class_reopener.rb +98 -55
- data/lib/contrast/agent/feature_state.rb +1 -1
- data/lib/contrast/agent/inventory/policy/policy.rb +1 -1
- data/lib/contrast/agent/logger_manager.rb +2 -2
- data/lib/contrast/agent/middleware.rb +1 -3
- data/lib/contrast/agent/patching/policy/after_load_patch.rb +40 -4
- data/lib/contrast/agent/patching/policy/after_load_patcher.rb +33 -8
- data/lib/contrast/agent/patching/policy/method_policy.rb +20 -7
- data/lib/contrast/agent/patching/policy/patch.rb +54 -23
- data/lib/contrast/agent/patching/policy/patch_status.rb +0 -2
- data/lib/contrast/agent/patching/policy/patcher.rb +10 -11
- data/lib/contrast/agent/patching/policy/policy.rb +4 -0
- data/lib/contrast/agent/patching/policy/policy_node.rb +14 -1
- data/lib/contrast/agent/patching/policy/trigger_node.rb +2 -1
- data/lib/contrast/agent/protect/policy/policy.rb +6 -6
- data/lib/contrast/agent/protect/rule/base.rb +1 -1
- data/lib/contrast/agent/protect/rule/deserialization.rb +3 -25
- data/lib/contrast/agent/protect/rule/sqli.rb +1 -1
- data/lib/contrast/agent/railtie.rb +11 -5
- data/lib/contrast/agent/request.rb +1 -19
- data/lib/contrast/agent/request_context.rb +1 -1
- data/lib/contrast/agent/rewriter.rb +4 -3
- data/lib/contrast/agent/scope.rb +116 -19
- data/lib/contrast/agent/service_heartbeat.rb +5 -2
- data/lib/contrast/agent/settings_state.rb +12 -8
- data/lib/contrast/agent/version.rb +1 -1
- data/lib/contrast/api.rb +1 -0
- data/lib/contrast/api/speedracer.rb +2 -2
- data/lib/contrast/components/agent.rb +26 -7
- data/lib/contrast/components/app_context.rb +8 -45
- data/lib/contrast/components/contrast_service.rb +3 -4
- data/lib/contrast/components/interface.rb +1 -1
- data/lib/contrast/components/scope.rb +56 -26
- data/lib/contrast/config/ruby_configuration.rb +8 -3
- data/lib/contrast/delegators.rb +9 -0
- data/lib/contrast/delegators/application_update.rb +32 -0
- data/lib/contrast/extensions/framework/rack/cookie.rb +24 -0
- data/lib/contrast/extensions/framework/rack/request.rb +24 -0
- data/lib/contrast/extensions/framework/rack/response.rb +23 -0
- data/lib/contrast/extensions/framework/rails/action_controller_railties_helper_inherited.rb +20 -0
- data/lib/contrast/extensions/framework/rails/active_record.rb +26 -0
- data/lib/contrast/extensions/framework/rails/active_record_named.rb +53 -0
- data/lib/contrast/extensions/framework/rails/active_record_time_zone_inherited.rb +21 -0
- data/lib/contrast/extensions/framework/rails/buffer.rb +28 -0
- data/lib/contrast/extensions/framework/rails/configuration.rb +27 -0
- data/lib/contrast/extensions/framework/sinatra/base.rb +59 -0
- data/lib/contrast/{core_extensions → extensions/ruby_core}/assess.rb +12 -11
- data/lib/contrast/{core_extensions → extensions/ruby_core}/assess/array.rb +4 -3
- data/lib/contrast/{core_extensions → extensions/ruby_core}/assess/assess_extension.rb +0 -2
- data/lib/contrast/{core_extensions → extensions/ruby_core}/assess/basic_object.rb +1 -1
- data/lib/contrast/{core_extensions → extensions/ruby_core}/assess/erb.rb +0 -0
- data/lib/contrast/{core_extensions → extensions/ruby_core}/assess/exec_trigger.rb +0 -0
- data/lib/contrast/{core_extensions → extensions/ruby_core}/assess/fiber.rb +3 -4
- data/lib/contrast/{core_extensions → extensions/ruby_core}/assess/hash.rb +0 -0
- data/lib/contrast/{core_extensions → extensions/ruby_core}/assess/kernel.rb +1 -1
- data/lib/contrast/{core_extensions → extensions/ruby_core}/assess/module.rb +1 -1
- data/lib/contrast/{core_extensions → extensions/ruby_core}/assess/regexp.rb +0 -0
- data/lib/contrast/{core_extensions → extensions/ruby_core}/assess/string.rb +0 -0
- data/lib/contrast/{core_extensions → extensions/ruby_core}/assess/tilt_template_trigger.rb +0 -0
- data/lib/contrast/extensions/ruby_core/assess/xpath_library_trigger.rb +40 -0
- data/lib/contrast/{core_extensions → extensions/ruby_core}/delegator.rb +0 -0
- data/lib/contrast/{core_extensions → extensions/ruby_core}/eval_trigger.rb +1 -1
- data/lib/contrast/{core_extensions → extensions/ruby_core}/inventory.rb +0 -0
- data/lib/contrast/{core_extensions → extensions/ruby_core}/inventory/datastores.rb +1 -1
- data/lib/contrast/extensions/ruby_core/module.rb +17 -0
- data/lib/contrast/{core_extensions → extensions/ruby_core}/protect.rb +0 -0
- data/lib/contrast/{core_extensions → extensions/ruby_core}/protect/applies_command_injection_rule.rb +8 -6
- data/lib/contrast/{core_extensions → extensions/ruby_core}/protect/applies_deserialization_rule.rb +7 -5
- data/lib/contrast/{core_extensions → extensions/ruby_core}/protect/applies_no_sqli_rule.rb +5 -3
- data/lib/contrast/{core_extensions → extensions/ruby_core}/protect/applies_path_traversal_rule.rb +31 -27
- data/lib/contrast/{core_extensions → extensions/ruby_core}/protect/applies_sqli_rule.rb +5 -3
- data/lib/contrast/{core_extensions → extensions/ruby_core}/protect/applies_xxe_rule.rb +9 -7
- data/lib/contrast/{core_extensions → extensions/ruby_core}/protect/kernel.rb +0 -0
- data/lib/contrast/{core_extensions → extensions/ruby_core}/protect/psych.rb +1 -1
- data/lib/contrast/{core_extensions → extensions/ruby_core}/thread.rb +0 -0
- data/lib/contrast/framework/base_support.rb +63 -0
- data/lib/contrast/framework/manager.rb +109 -0
- data/lib/contrast/framework/platform_version.rb +21 -0
- data/lib/contrast/framework/rails_support.rb +88 -0
- data/lib/contrast/framework/sinatra_application_helper.rb +49 -0
- data/lib/contrast/framework/sinatra_support.rb +94 -0
- data/lib/contrast/framework/view_technologies_descriptor.rb +20 -0
- data/lib/contrast/utils/assess/tracking_util.rb +2 -4
- data/lib/contrast/utils/class_util.rb +92 -37
- data/lib/contrast/utils/duck_utils.rb +59 -39
- data/lib/contrast/utils/environment_util.rb +5 -75
- data/lib/contrast/utils/freeze_util.rb +3 -7
- data/lib/contrast/utils/invalid_configuration_util.rb +5 -5
- data/lib/contrast/utils/job_servers_running.rb +39 -0
- data/lib/contrast/utils/ruby_ast_rewriter.rb +2 -2
- data/lib/contrast/utils/service_response_util.rb +0 -6
- data/lib/contrast/utils/sinatra_helper.rb +6 -0
- data/lib/contrast/utils/stack_trace_utils.rb +1 -1
- data/resources/assess/policy.json +74 -23
- data/resources/inventory/policy.json +1 -1
- data/resources/protect/policy.json +11 -9
- data/resources/rubocops/object/frozen_cop.rb +1 -1
- data/ruby-agent.gemspec +2 -0
- data/service_executables/VERSION +1 -1
- data/service_executables/linux/contrast-service +0 -0
- data/service_executables/mac/contrast-service +0 -0
- metadata +94 -57
- data/ext/cs__scope/cs__scope.c +0 -96
- data/ext/cs__scope/cs__scope.h +0 -33
- data/lib/contrast/agent/assess/class_reverter.rb +0 -82
- data/lib/contrast/agent/patching/policy/policy_unpatcher.rb +0 -28
- data/lib/contrast/core_extensions/module.rb +0 -42
- data/lib/contrast/core_extensions/object.rb +0 -27
- data/lib/contrast/rails_extensions/assess/action_controller_inheritance.rb +0 -48
- data/lib/contrast/rails_extensions/assess/active_record.rb +0 -32
- data/lib/contrast/rails_extensions/assess/active_record_named.rb +0 -61
- data/lib/contrast/rails_extensions/assess/configuration.rb +0 -26
- data/lib/contrast/rails_extensions/buffer.rb +0 -30
- data/lib/contrast/rails_extensions/rack.rb +0 -45
- data/lib/contrast/sinatra_extensions/assess/cookie.rb +0 -26
- data/lib/contrast/sinatra_extensions/inventory/sinatra_base.rb +0 -59
- data/lib/contrast/utils/operating_environment.rb +0 -38
- data/lib/contrast/utils/path_util.rb +0 -151
- data/lib/contrast/utils/scope_util.rb +0 -99
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
# Copyright (c) 2020 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
|
|
2
|
-
# frozen_string_literal: true
|
|
3
|
-
|
|
4
|
-
cs__scoped_require 'contrast/components/interface'
|
|
5
|
-
|
|
6
|
-
if defined?(Rack) && defined?(Rack::Session) && defined?(Rack::Session::Cookie)
|
|
7
|
-
module Rack
|
|
8
|
-
module Session
|
|
9
|
-
# Our patch into the Rack::Session::Cookie Class, allowing for the
|
|
10
|
-
# runtime detection of insecure configurations on individual cookies
|
|
11
|
-
# within the application
|
|
12
|
-
class Cookie
|
|
13
|
-
include Contrast::Utils::InvalidConfigurationUtil
|
|
14
|
-
include Contrast::Components::Interface
|
|
15
|
-
|
|
16
|
-
access_component :scope
|
|
17
|
-
|
|
18
|
-
alias_method :cs__patched_initialize, :initialize
|
|
19
|
-
def initialize app, options = {}
|
|
20
|
-
Contrast::Utils::RackAssessSessionCookie.analyze_cookie_initialization(options)
|
|
21
|
-
cs__patched_initialize(app, options)
|
|
22
|
-
end
|
|
23
|
-
end
|
|
24
|
-
end
|
|
25
|
-
end
|
|
26
|
-
end
|
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
# Copyright (c) 2020 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
|
|
2
|
-
# frozen_string_literal: true
|
|
3
|
-
|
|
4
|
-
if defined?(Sinatra) && defined?(Sinatra::Base)
|
|
5
|
-
module Sinatra
|
|
6
|
-
# Our patch into the Sinatra::Base Class, allowing for the inventory of the
|
|
7
|
-
# routes called by the application
|
|
8
|
-
class Base
|
|
9
|
-
alias_method :cs__patched_call!, :call!
|
|
10
|
-
|
|
11
|
-
# publicly available method for Sinatra::Base things -- unfortunately,
|
|
12
|
-
# getting the routes appear to require a lookup every time
|
|
13
|
-
def call! *args
|
|
14
|
-
cs__patched_map_route(*args)
|
|
15
|
-
cs__patched_call!(*args)
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
private
|
|
19
|
-
|
|
20
|
-
# Use logic copied from Sinatra::Base#process_route to determine which
|
|
21
|
-
# pattern matches the request being invoked by Sinatra::Base#call!
|
|
22
|
-
#
|
|
23
|
-
# @param args [Array<Object>] we rely on the @settings object in
|
|
24
|
-
# Sinatra::Base and the env variable passed in as args[0]
|
|
25
|
-
def cs__patched_map_route *args
|
|
26
|
-
context = Contrast::Agent::REQUEST_TRACKER.current
|
|
27
|
-
return unless context
|
|
28
|
-
|
|
29
|
-
env = args[0]
|
|
30
|
-
return unless env
|
|
31
|
-
|
|
32
|
-
# There isn't a Request object in the Sinatra::Base yet - it's made
|
|
33
|
-
# during the #call! method, which we're patching - so we need to
|
|
34
|
-
# access the env
|
|
35
|
-
method = env[Rack::REQUEST_METHOD]
|
|
36
|
-
route = env[Rack::PATH_INFO]
|
|
37
|
-
route = route.to_s
|
|
38
|
-
|
|
39
|
-
# get all potential routes for this request type
|
|
40
|
-
routes = settings.routes[method]
|
|
41
|
-
return unless routes
|
|
42
|
-
|
|
43
|
-
# Do some cleanup that matches Sinatra::Base#process_route
|
|
44
|
-
route = '/' if route.empty? && !settings.empty_path_info?
|
|
45
|
-
route = route[0..-2] if !settings.strict_paths? && route != '/' && route.end_with?('/')
|
|
46
|
-
|
|
47
|
-
# Find the route that matches this request. Since we're using
|
|
48
|
-
# settings, we should resolve in the same precedence as Sinatra
|
|
49
|
-
routes.each do |pattern, _, _| # Mustermann::Sinatra
|
|
50
|
-
next unless pattern.params(route)
|
|
51
|
-
|
|
52
|
-
dtm = Contrast::Utils::PathUtil.get_sinatra_route(cs__class, method, pattern)
|
|
53
|
-
context.append_route_coverage(dtm)
|
|
54
|
-
break
|
|
55
|
-
end
|
|
56
|
-
end
|
|
57
|
-
end
|
|
58
|
-
end
|
|
59
|
-
end
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
# Copyright (c) 2020 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
|
|
2
|
-
# frozen_string_literal: true
|
|
3
|
-
|
|
4
|
-
cs__scoped_require 'contrast/components/interface'
|
|
5
|
-
|
|
6
|
-
module Contrast
|
|
7
|
-
module Utils
|
|
8
|
-
# A utility class to detect the environment the agent is operating within
|
|
9
|
-
class OperatingEnvironment
|
|
10
|
-
include Contrast::Components::Interface
|
|
11
|
-
access_component :logging
|
|
12
|
-
|
|
13
|
-
def self.unsupported?
|
|
14
|
-
sidekiq? || rake?
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
def self.sidekiq?
|
|
18
|
-
return unless defined?(Sidekiq) && Sidekiq.cs__respond_to?(:server?) && Sidekiq.server?
|
|
19
|
-
|
|
20
|
-
logger.debug(nil, "Detected the spawn of a Sidekiq process. Disabling Contrast for process #{ Process.pid }")
|
|
21
|
-
true
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
def self.rake?
|
|
25
|
-
return unless defined?(Rake) &&
|
|
26
|
-
Rake.cs__respond_to?(:application) &&
|
|
27
|
-
Rake.application.cs__respond_to?(:top_level_tasks)
|
|
28
|
-
|
|
29
|
-
disabled_rake_tasks = Contrast::Agent::FeatureState.instance.disabled_agent_rake_tasks
|
|
30
|
-
disabled_task = Rake.application.top_level_tasks.any? { |task| disabled_rake_tasks.include?(task) }
|
|
31
|
-
return false unless disabled_task
|
|
32
|
-
|
|
33
|
-
logger.debug(nil, "Detected startup within the rake task #{ disabled_task }. Disabling Contrast for process #{ Process.pid }")
|
|
34
|
-
true
|
|
35
|
-
end
|
|
36
|
-
end
|
|
37
|
-
end
|
|
38
|
-
end
|
|
@@ -1,151 +0,0 @@
|
|
|
1
|
-
# Copyright (c) 2020 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
|
|
2
|
-
# frozen_string_literal: true
|
|
3
|
-
|
|
4
|
-
cs__scoped_require 'contrast/utils/object_share'
|
|
5
|
-
cs__scoped_require 'contrast/utils/class_util'
|
|
6
|
-
cs__scoped_require 'contrast/components/interface'
|
|
7
|
-
|
|
8
|
-
module Contrast
|
|
9
|
-
module Utils
|
|
10
|
-
# Utility methods for finding routes within frameworks
|
|
11
|
-
class PathUtil
|
|
12
|
-
include Contrast::Components::Interface
|
|
13
|
-
access_component :logging
|
|
14
|
-
|
|
15
|
-
COVERAGE_LIMIT = 500 # CONTRAST-25730: Arbitrary coverage limit imposed by TeamServer
|
|
16
|
-
|
|
17
|
-
class << self
|
|
18
|
-
# find the routes in the application. since each framework maintains the
|
|
19
|
-
# routes slightly differently, we'll only support those that we've explicitly
|
|
20
|
-
# implemented (Rails & Sinatra currently)
|
|
21
|
-
#
|
|
22
|
-
# this method always returns an array, even if it's empty
|
|
23
|
-
def find_routes
|
|
24
|
-
if defined?(Rails)
|
|
25
|
-
find_rails_routes
|
|
26
|
-
elsif defined?(Sinatra)
|
|
27
|
-
find_sinatra_routes
|
|
28
|
-
else
|
|
29
|
-
Contrast::Utils::ObjectShare::EMPTY_ARRAY
|
|
30
|
-
end
|
|
31
|
-
rescue StandardError
|
|
32
|
-
Contrast::Utils::ObjectShare::EMPTY_ARRAY
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
# Given the Contrast Request object, determine the current Coverage route,
|
|
36
|
-
# returning a RouteCoverage object
|
|
37
|
-
def get_route request
|
|
38
|
-
get_rails_route(request) if defined?(Rails)
|
|
39
|
-
rescue StandardError => e
|
|
40
|
-
logger.error(e, 'Unable to generate route from request')
|
|
41
|
-
nil
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
def find_rails_routes
|
|
45
|
-
routes = []
|
|
46
|
-
count = 0
|
|
47
|
-
Rails.application.routes.routes.each do |route|
|
|
48
|
-
routes << rails_route_to_coverage(route)
|
|
49
|
-
count += 1
|
|
50
|
-
return routes if count > COVERAGE_LIMIT
|
|
51
|
-
end
|
|
52
|
-
routes
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
def get_rails_route request
|
|
56
|
-
return unless Rails.cs__respond_to?(:application)
|
|
57
|
-
|
|
58
|
-
# returns array of arrays [[match_data, path_parameters, route]], sorted by
|
|
59
|
-
# precedence
|
|
60
|
-
# match_data: ActionDispatch::Journey::Path::Pattern::MatchData
|
|
61
|
-
# path_parameters: hash of various things
|
|
62
|
-
# route: ActionDispatch::Journey::Route
|
|
63
|
-
full_routes = Rails.application.routes.router.send(:find_routes, request.rack_request)
|
|
64
|
-
return if full_routes.empty?
|
|
65
|
-
|
|
66
|
-
full_route = full_routes[0] # [match_data, path_parameters, route]
|
|
67
|
-
return unless full_route
|
|
68
|
-
|
|
69
|
-
route = full_route[2] # route w/ highest precedence
|
|
70
|
-
return unless route
|
|
71
|
-
|
|
72
|
-
rails_route_to_coverage(route)
|
|
73
|
-
end
|
|
74
|
-
|
|
75
|
-
# Convert ActionDispatch::Journey::Route to Contrast::Api::Dtm::RouteCoverage
|
|
76
|
-
def rails_route_to_coverage route
|
|
77
|
-
route_coverage = Contrast::Api::Dtm::RouteCoverage.new
|
|
78
|
-
route_coverage.route = "#{ route.defaults[:controller] }##{ route.defaults[:action] }"
|
|
79
|
-
|
|
80
|
-
verb = source_or_string(route.verb)
|
|
81
|
-
route_coverage.verb = Contrast::Utils::StringUtils.force_utf8(verb)
|
|
82
|
-
|
|
83
|
-
url = source_or_string(route.path.spec)
|
|
84
|
-
route_coverage.url = Contrast::Utils::StringUtils.force_utf8(url)
|
|
85
|
-
route_coverage
|
|
86
|
-
end
|
|
87
|
-
|
|
88
|
-
def source_or_string obj
|
|
89
|
-
if obj.cs__is_a?(Regexp)
|
|
90
|
-
obj.source
|
|
91
|
-
elsif obj.cs__respond_to?(:safe_string)
|
|
92
|
-
obj.safe_string
|
|
93
|
-
else
|
|
94
|
-
obj.to_s
|
|
95
|
-
end
|
|
96
|
-
end
|
|
97
|
-
|
|
98
|
-
# Iterate over every class that extends Sinatra::Base, pull out its routes
|
|
99
|
-
# (array of arrays with Mustermann::Sinatra as [][0]) and convert them into
|
|
100
|
-
# Contrast::Api::Dtm::RouteCoverage
|
|
101
|
-
def find_sinatra_routes
|
|
102
|
-
routes = []
|
|
103
|
-
controllers = sinatra_controllers
|
|
104
|
-
controllers.each do |clazz|
|
|
105
|
-
class_routes = sinatra_class_routes(clazz)
|
|
106
|
-
next unless class_routes
|
|
107
|
-
|
|
108
|
-
class_routes.each_pair do |method, list|
|
|
109
|
-
# item: [ Mustermann::Sinatra, [], Proc]
|
|
110
|
-
list.each do |item|
|
|
111
|
-
routes << sinatra_route_to_coverage(clazz, method, item[0])
|
|
112
|
-
return routes if routes.length > COVERAGE_LIMIT
|
|
113
|
-
end
|
|
114
|
-
end
|
|
115
|
-
end
|
|
116
|
-
routes
|
|
117
|
-
end
|
|
118
|
-
|
|
119
|
-
def sinatra_controllers
|
|
120
|
-
return [] unless defined?(Sinatra) && defined?(Sinatra::Base)
|
|
121
|
-
|
|
122
|
-
Contrast::Utils::ClassUtil.ancestors_of(Sinatra::Base)
|
|
123
|
-
end
|
|
124
|
-
|
|
125
|
-
def sinatra_class_routes controller
|
|
126
|
-
controller.instance_variable_get(:@routes)
|
|
127
|
-
rescue StandardError
|
|
128
|
-
logger.debug(nil, "#{ clazz } has no routes instance")
|
|
129
|
-
nil
|
|
130
|
-
end
|
|
131
|
-
|
|
132
|
-
# Invoked directly on Sinatra::Base#call!
|
|
133
|
-
def get_sinatra_route clazz, method, pattern
|
|
134
|
-
sinatra_route_to_coverage(clazz, method, pattern)
|
|
135
|
-
end
|
|
136
|
-
|
|
137
|
-
# given clazz, method, and Mustermann::Sinatra, build a
|
|
138
|
-
# Contrast::Api::Dtm::RouteCoverage
|
|
139
|
-
def sinatra_route_to_coverage clazz, method, pattern
|
|
140
|
-
safe_pattern = source_or_string(pattern)
|
|
141
|
-
|
|
142
|
-
route_coverage = Contrast::Api::Dtm::RouteCoverage.new
|
|
143
|
-
route_coverage.route = "#{ clazz }##{ method } #{ safe_pattern }"
|
|
144
|
-
route_coverage.verb = Contrast::Utils::StringUtils.force_utf8(method)
|
|
145
|
-
route_coverage.url = Contrast::Utils::StringUtils.force_utf8(safe_pattern)
|
|
146
|
-
route_coverage
|
|
147
|
-
end
|
|
148
|
-
end
|
|
149
|
-
end
|
|
150
|
-
end
|
|
151
|
-
end
|
|
@@ -1,99 +0,0 @@
|
|
|
1
|
-
# Copyright (c) 2020 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
|
|
2
|
-
# frozen_string_literal: true
|
|
3
|
-
|
|
4
|
-
cs__scoped_require 'contrast/components/interface'
|
|
5
|
-
|
|
6
|
-
module Kernel # :nodoc:
|
|
7
|
-
include Contrast::Components::Interface
|
|
8
|
-
|
|
9
|
-
access_component :scope
|
|
10
|
-
|
|
11
|
-
alias_method :cs__catch, :catch
|
|
12
|
-
|
|
13
|
-
# In the event of a `throw`, we need to override `catch`
|
|
14
|
-
# to save & restore scope state:
|
|
15
|
-
#
|
|
16
|
-
# scope_level == 0
|
|
17
|
-
#
|
|
18
|
-
# catch(:abc) do
|
|
19
|
-
# with_contrast_scope do
|
|
20
|
-
# throw :abc # will leak
|
|
21
|
-
# end
|
|
22
|
-
# end
|
|
23
|
-
#
|
|
24
|
-
# scope_level == 1
|
|
25
|
-
#
|
|
26
|
-
# While this will fix /all/ scope leaks, not just ones caused by `throw`,
|
|
27
|
-
# it shouldn't be relied upon as a catch-all (lmao) solution.
|
|
28
|
-
|
|
29
|
-
private
|
|
30
|
-
|
|
31
|
-
def catch *args, &block
|
|
32
|
-
# Save current scope level
|
|
33
|
-
scope_level = SCOPE.scope_for_current_ec.instance_variable_get(:@contrast_scope)
|
|
34
|
-
|
|
35
|
-
# Run original catch with block.
|
|
36
|
-
retval = cs__catch(*args, &block)
|
|
37
|
-
|
|
38
|
-
# Restore scope.
|
|
39
|
-
SCOPE.scope_for_current_ec.instance_variable_set(:@contrast_scope, scope_level)
|
|
40
|
-
|
|
41
|
-
retval
|
|
42
|
-
end
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
# ScopeUtil should probably be merged into Scope component.
|
|
46
|
-
module Contrast
|
|
47
|
-
module Utils
|
|
48
|
-
module ScopeUtil # :nodoc:
|
|
49
|
-
include Contrast::Components::Interface
|
|
50
|
-
|
|
51
|
-
access_component :analysis, :scope
|
|
52
|
-
|
|
53
|
-
# @return [Boolean]
|
|
54
|
-
def skip_contrast_analysis?
|
|
55
|
-
return true if in_contrast_scope?
|
|
56
|
-
return true unless Contrast::Agent::REQUEST_TRACKER.current&.analyze_request?
|
|
57
|
-
|
|
58
|
-
false
|
|
59
|
-
end
|
|
60
|
-
|
|
61
|
-
# Skip if we should skip_contrast_analysis?, sampling says to ignore this
|
|
62
|
-
# request, or assess has been disabled.
|
|
63
|
-
#
|
|
64
|
-
# @return [Boolean]
|
|
65
|
-
def skip_assess_analysis?
|
|
66
|
-
return true if skip_contrast_analysis?
|
|
67
|
-
|
|
68
|
-
current_context = Contrast::Agent::REQUEST_TRACKER.current
|
|
69
|
-
return true unless current_context.analyze_request?
|
|
70
|
-
|
|
71
|
-
!ASSESS.enabled?
|
|
72
|
-
end
|
|
73
|
-
|
|
74
|
-
def cs__enter_scope
|
|
75
|
-
enter_contrast_scope!
|
|
76
|
-
end
|
|
77
|
-
|
|
78
|
-
def cs__leave_scope
|
|
79
|
-
exit_contrast_scope!
|
|
80
|
-
end
|
|
81
|
-
|
|
82
|
-
def cs__enter_assess_scope
|
|
83
|
-
# If we shouldn't be doing assess things, don't propagate or whatever
|
|
84
|
-
disable_contrast = skip_assess_analysis?
|
|
85
|
-
return nil if disable_contrast
|
|
86
|
-
|
|
87
|
-
enter_contrast_scope!
|
|
88
|
-
end
|
|
89
|
-
|
|
90
|
-
def cs__enter_scope_contrast_patch
|
|
91
|
-
# If we're already in Contrast scope, don't propagate or whatever
|
|
92
|
-
disable_contrast = skip_contrast_analysis?
|
|
93
|
-
return nil if disable_contrast
|
|
94
|
-
|
|
95
|
-
enter_contrast_scope!
|
|
96
|
-
end
|
|
97
|
-
end
|
|
98
|
-
end
|
|
99
|
-
end
|