contrast-agent 3.14.0 → 3.15.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_marshal_module/cs__assess_marshal_module.c +18 -15
- data/ext/cs__assess_marshal_module/cs__assess_marshal_module.h +1 -0
- data/ext/cs__assess_string/cs__assess_string.c +24 -25
- data/ext/cs__assess_string/cs__assess_string.h +3 -1
- data/ext/cs__common/cs__common.c +4 -2
- data/ext/cs__common/cs__common.h +1 -1
- data/lib/contrast.rb +1 -1
- data/lib/contrast/agent/assess.rb +1 -0
- data/lib/contrast/agent/assess/contrast_event.rb +4 -12
- data/lib/contrast/agent/assess/finalizers/freeze.rb +3 -1
- data/lib/contrast/agent/assess/finalizers/hash.rb +45 -1
- data/lib/contrast/agent/assess/policy/patcher.rb +1 -1
- data/lib/contrast/agent/assess/policy/policy.rb +0 -2
- data/lib/contrast/agent/assess/policy/policy_scanner.rb +0 -1
- data/lib/contrast/agent/assess/policy/preshift.rb +7 -11
- data/lib/contrast/agent/assess/policy/propagation_method.rb +50 -33
- data/lib/contrast/agent/assess/policy/propagator/append.rb +8 -5
- data/lib/contrast/agent/assess/policy/propagator/base.rb +1 -1
- data/lib/contrast/agent/assess/policy/propagator/center.rb +9 -5
- data/lib/contrast/agent/assess/policy/propagator/database_write.rb +5 -3
- data/lib/contrast/agent/assess/policy/propagator/insert.rb +6 -3
- data/lib/contrast/agent/assess/policy/propagator/keep.rb +4 -1
- data/lib/contrast/agent/assess/policy/propagator/match_data.rb +6 -6
- data/lib/contrast/agent/assess/policy/propagator/next.rb +7 -5
- data/lib/contrast/agent/assess/policy/propagator/prepend.rb +8 -5
- data/lib/contrast/agent/assess/policy/propagator/remove.rb +8 -4
- data/lib/contrast/agent/assess/policy/propagator/replace.rb +5 -2
- data/lib/contrast/agent/assess/policy/propagator/reverse.rb +7 -5
- data/lib/contrast/agent/assess/policy/propagator/select.rb +15 -7
- data/lib/contrast/agent/assess/policy/propagator/splat.rb +14 -8
- data/lib/contrast/agent/assess/policy/propagator/split.rb +14 -8
- data/lib/contrast/agent/assess/policy/propagator/substitution.rb +30 -21
- data/lib/contrast/agent/assess/policy/propagator/trim.rb +11 -5
- data/lib/contrast/agent/assess/policy/source_method.rb +85 -58
- data/lib/contrast/agent/assess/policy/trigger/reflected_xss.rb +16 -11
- data/lib/contrast/agent/assess/policy/trigger/xpath.rb +1 -1
- data/lib/contrast/agent/assess/policy/trigger_method.rb +38 -15
- data/lib/contrast/agent/assess/policy/trigger_node.rb +14 -13
- data/lib/contrast/agent/assess/policy/trigger_validation/ssrf_validator.rb +2 -1
- data/lib/contrast/agent/assess/properties.rb +2 -0
- data/lib/contrast/agent/assess/property/updated.rb +136 -0
- data/lib/contrast/agent/assess/tracker.rb +66 -0
- data/lib/contrast/agent/class_reopener.rb +7 -5
- data/lib/contrast/agent/middleware.rb +0 -1
- data/lib/contrast/agent/patching/policy/patcher.rb +13 -22
- data/lib/contrast/agent/patching/policy/policy.rb +1 -4
- data/lib/contrast/agent/response.rb +17 -6
- data/lib/contrast/agent/rewriter.rb +1 -3
- data/lib/contrast/agent/version.rb +1 -1
- data/lib/contrast/api/communication/messaging_queue.rb +1 -4
- data/lib/contrast/api/decorators/application_update.rb +2 -4
- data/lib/contrast/api/decorators/trace_event.rb +5 -5
- data/lib/contrast/components/app_context.rb +11 -9
- data/lib/contrast/components/config.rb +3 -13
- data/lib/contrast/components/contrast_service.rb +2 -2
- data/lib/contrast/config/application_configuration.rb +5 -2
- data/lib/contrast/config/service_configuration.rb +8 -2
- data/lib/contrast/configuration.rb +88 -47
- data/lib/contrast/extension/assess.rb +0 -2
- data/lib/contrast/extension/assess/array.rb +8 -5
- data/lib/contrast/extension/assess/erb.rb +6 -3
- data/lib/contrast/extension/assess/fiber.rb +9 -9
- data/lib/contrast/extension/assess/hash.rb +2 -3
- data/lib/contrast/extension/assess/kernel.rb +12 -5
- data/lib/contrast/extension/assess/marshal.rb +3 -2
- data/lib/contrast/extension/assess/regexp.rb +5 -4
- data/lib/contrast/extension/assess/string.rb +8 -10
- data/lib/contrast/framework/rack/patch/session_cookie.rb +12 -18
- data/lib/contrast/framework/rails/patch/assess_configuration.rb +4 -10
- data/lib/contrast/framework/rails/support.rb +2 -0
- data/lib/contrast/logger/application.rb +11 -3
- data/lib/contrast/utils/assess/tracking_util.rb +48 -3
- data/lib/contrast/utils/duck_utils.rb +0 -10
- data/lib/contrast/utils/env_configuration_item.rb +2 -1
- data/lib/contrast/utils/invalid_configuration_util.rb +21 -19
- data/lib/contrast/utils/string_utils.rb +10 -5
- data/resources/assess/policy.json +0 -10
- data/ruby-agent.gemspec +16 -15
- data/service_executables/VERSION +1 -1
- data/service_executables/linux/contrast-service +0 -0
- data/service_executables/mac/contrast-service +0 -0
- metadata +42 -21
- data/lib/contrast/agent/assess/finalizers/finalize.rb +0 -21
- data/lib/contrast/extension/assess/assess_extension.rb +0 -145
- data/lib/contrast/utils/freeze_util.rb +0 -32
@@ -100,16 +100,17 @@ module Contrast
|
|
100
100
|
# if the source isn't tracked, there can't be a violation
|
101
101
|
# this condition may not hold true forever, but for now it's
|
102
102
|
# a nice optimization
|
103
|
-
return false unless
|
103
|
+
return false unless Contrast::Agent::Assess::Tracker.tracked?(source)
|
104
104
|
|
105
|
+
properties = Contrast::Agent::Assess::Tracker.properties(source)
|
105
106
|
# find the ranges that violate the rule (untrusted, etc)
|
106
|
-
vulnerable_ranges = find_ranges_by_all_tags(Contrast::Utils::StringUtils.ret_length(source),
|
107
|
+
vulnerable_ranges = find_ranges_by_all_tags(Contrast::Utils::StringUtils.ret_length(source), properties, required_tags)
|
107
108
|
# if there aren't any vulnerable ranges, nope out
|
108
109
|
return false if vulnerable_ranges.empty?
|
109
110
|
|
110
111
|
# find the ranges that are exempt from the rule
|
111
112
|
# (validated, sanitized, etc)
|
112
|
-
secure_ranges = find_ranges_by_any_tag(
|
113
|
+
secure_ranges = find_ranges_by_any_tag(properties, disallowed_tags)
|
113
114
|
# if there are vulnerable ranges and no secure, report
|
114
115
|
return true if secure_ranges.empty?
|
115
116
|
|
@@ -178,27 +179,27 @@ module Contrast
|
|
178
179
|
# @param length [Integer] the length of the object which may have the
|
179
180
|
# given tags -- used as the maximum index to search for all of the
|
180
181
|
# tags.
|
181
|
-
# @param
|
182
|
+
# @param properties [Contrast::Agent::Assess::Properties] the
|
182
183
|
# properties to check for the tags
|
183
184
|
# @param tags [Set<String>] the list of tags on which to match
|
184
185
|
# @return [Array<Contrast::Agent::Assess::Tag>] the ranges satisfied
|
185
186
|
# by the given conditions
|
186
|
-
def find_ranges_by_all_tags length,
|
187
|
+
def find_ranges_by_all_tags length, properties, tags
|
187
188
|
# if there aren't any all_tags or tags, break early
|
188
|
-
return Contrast::Utils::ObjectShare::EMPTY_ARRAY unless
|
189
|
+
return Contrast::Utils::ObjectShare::EMPTY_ARRAY unless properties.tracked?
|
189
190
|
return Contrast::Utils::ObjectShare::EMPTY_ARRAY unless tags&.any?
|
190
191
|
|
191
192
|
# :zap: faster to treat all as any if there's only one tag
|
192
|
-
return find_ranges_by_any_tag(
|
193
|
+
return find_ranges_by_any_tag(properties, tags) if tags.length == 1
|
193
194
|
|
194
195
|
ranges = []
|
195
196
|
# TODO: RUBY-946 clean this up, perhaps with
|
196
|
-
# tags.each { |tag| applicable <<
|
197
|
+
# tags.each { |tag| applicable << properties.fetch_tag(tag) }
|
197
198
|
# return Contrast::Utils::ObjectShare::EMPTY_ARRAY unless applicable.length == tags.length
|
198
199
|
# ...
|
199
200
|
# find all the indicies on the source that have all the given tags
|
200
201
|
(0..length).each do |idx|
|
201
|
-
tags_at =
|
202
|
+
tags_at = properties.tags_at(idx)
|
202
203
|
ranges << idx if tags.all? do |tag|
|
203
204
|
found = false
|
204
205
|
tags_at.each do |tag_at|
|
@@ -227,19 +228,19 @@ module Contrast
|
|
227
228
|
|
228
229
|
# Find the ranges that satisfy any of the given tags.
|
229
230
|
#
|
230
|
-
# @param
|
231
|
+
# @param properties [Contrast::Agent::Assess::Properties] the
|
231
232
|
# properties to check for the tags
|
232
233
|
# @param tags [Set<String>] the list of tags on which to match
|
233
234
|
# @return [Array<Contrast::Agent::Assess::Tag>] the ranges satisfied
|
234
235
|
# by the given conditions
|
235
|
-
def find_ranges_by_any_tag
|
236
|
+
def find_ranges_by_any_tag properties, tags
|
236
237
|
# if there aren't any all_tags or tags, break early
|
237
|
-
return Contrast::Utils::ObjectShare::EMPTY_ARRAY unless
|
238
|
+
return Contrast::Utils::ObjectShare::EMPTY_ARRAY unless properties.tracked?
|
238
239
|
return Contrast::Utils::ObjectShare::EMPTY_ARRAY unless tags&.any?
|
239
240
|
|
240
241
|
ranges = []
|
241
242
|
tags.each do |desired|
|
242
|
-
found =
|
243
|
+
found = properties.fetch_tag(desired)
|
243
244
|
next unless found
|
244
245
|
|
245
246
|
# we need to dup here so that we don't change the tags if target is
|
@@ -38,7 +38,8 @@ module Contrast
|
|
38
38
|
finish = match.begin(:path)
|
39
39
|
finish ||= url.length
|
40
40
|
|
41
|
-
args[0]
|
41
|
+
properties = Contrast::Agent::Assess::Tracker.properties(args[0])
|
42
|
+
properties.any_tags_between?(start, finish)
|
42
43
|
end
|
43
44
|
end
|
44
45
|
end
|
@@ -5,6 +5,7 @@ require 'base64'
|
|
5
5
|
require 'set'
|
6
6
|
require 'contrast/agent/assess/property/evented'
|
7
7
|
require 'contrast/agent/assess/property/tagged'
|
8
|
+
require 'contrast/agent/assess/property/updated'
|
8
9
|
require 'contrast/utils/prevent_serialization'
|
9
10
|
|
10
11
|
module Contrast
|
@@ -20,6 +21,7 @@ module Contrast
|
|
20
21
|
include Contrast::Utils::PreventSerialization
|
21
22
|
include Contrast::Agent::Assess::Property::Evented
|
22
23
|
include Contrast::Agent::Assess::Property::Tagged
|
24
|
+
include Contrast::Agent::Assess::Property::Updated
|
23
25
|
|
24
26
|
attr_accessor :dupped_from
|
25
27
|
|
@@ -0,0 +1,136 @@
|
|
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
|
+
require 'contrast/utils/duck_utils'
|
5
|
+
|
6
|
+
module Contrast
|
7
|
+
module Agent
|
8
|
+
module Assess
|
9
|
+
module Property
|
10
|
+
# This module serves to hold the functionality required for the
|
11
|
+
# update of properties as they go through dataflow.
|
12
|
+
module Updated
|
13
|
+
# copy tags and info from source's properties to self
|
14
|
+
# @param source [Object] the object from which existing properties
|
15
|
+
# should be copied.
|
16
|
+
# @param owner [Object] the object to which these properties apply.
|
17
|
+
# @param shift [Integer] (0) how far to shift the tags during copy,
|
18
|
+
# useful for insert and append operations.
|
19
|
+
# @param skip_tags [Set<String>] (nil) the tags to not copy over,
|
20
|
+
# useful for propagation events that have 'untags'.
|
21
|
+
def copy_from source, owner, shift = 0, skip_tags = nil
|
22
|
+
return if owner.equal?(source)
|
23
|
+
return unless Contrast::Agent::Assess::Tracker.tracked?(source)
|
24
|
+
|
25
|
+
original = Contrast::Agent::Assess::Tracker.properties(source)
|
26
|
+
return unless original
|
27
|
+
|
28
|
+
adjust_duplicate(original)
|
29
|
+
|
30
|
+
original.events.each do |event|
|
31
|
+
events << event
|
32
|
+
end
|
33
|
+
|
34
|
+
original.tag_keys.each do |key|
|
35
|
+
next if skip_tags&.include?(key)
|
36
|
+
|
37
|
+
existing = tags[key]
|
38
|
+
had_existing = existing.any?
|
39
|
+
value = original.fetch_tag(key)
|
40
|
+
value.each do |tag|
|
41
|
+
existing << tag.copy_modified(shift)
|
42
|
+
end
|
43
|
+
Contrast::Utils::TagUtil.size_aware_merge(owner, existing) if had_existing
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
# Some propagation occurred, but we're not sure what the
|
48
|
+
# exact transformation was. To be safe, we just explode
|
49
|
+
# all the tags from the source to the return.
|
50
|
+
#
|
51
|
+
# If the return already had that tag, the existing tag
|
52
|
+
# range is recycled to save us an object.
|
53
|
+
#
|
54
|
+
# @param source [Object] the object from which existing properties
|
55
|
+
# should be copied.
|
56
|
+
# @param owner [Object] the object to which these properties apply.
|
57
|
+
def splat_from source, owner
|
58
|
+
splat_length = Contrast::Utils::StringUtils.ret_length(owner)
|
59
|
+
return if splat_length.zero?
|
60
|
+
|
61
|
+
splat_from_ret(splat_length)
|
62
|
+
splat_from_source(source, splat_length)
|
63
|
+
cleanup_tags
|
64
|
+
end
|
65
|
+
|
66
|
+
private
|
67
|
+
|
68
|
+
# Because of how our tracking works now, sometimes the Source and
|
69
|
+
# Target are the same, but their IDs in our map will be different due
|
70
|
+
# to PreShift duplication. To account for this, we have to ensure that
|
71
|
+
# the Object we're copying from does not have the same Properties
|
72
|
+
# that the Object we're copying to does. If they are the same, wipe the
|
73
|
+
# Target so that the copy method can update events and ranges as
|
74
|
+
# necessary.
|
75
|
+
# DO NOT TAKE THIS OUT!
|
76
|
+
def adjust_duplicate original
|
77
|
+
reset_properties if original == self
|
78
|
+
reset_properties if original.__id__ == dupped_from
|
79
|
+
reset_properties if original.dupped_from == __id__
|
80
|
+
end
|
81
|
+
|
82
|
+
# Wipe out the instance variables on this Properties instance,
|
83
|
+
# allowing them to be rebuilt.
|
84
|
+
def reset_properties
|
85
|
+
@_tags = nil
|
86
|
+
@_events = nil
|
87
|
+
@_properties = nil
|
88
|
+
end
|
89
|
+
|
90
|
+
# Splat all the tags from the source to this set of Properties
|
91
|
+
#
|
92
|
+
# @param source [Object] the object from which tags will be copied
|
93
|
+
# and splatted.
|
94
|
+
# @param splat_length [Integer] the length to which to to set all
|
95
|
+
# tags.
|
96
|
+
def splat_from_source source, splat_length
|
97
|
+
properties = Contrast::Agent::Assess::Tracker.properties(source)
|
98
|
+
return unless properties
|
99
|
+
|
100
|
+
properties.tag_keys.each do |key|
|
101
|
+
existing = fetch_tag(key)
|
102
|
+
# if the tag already exists, drop all but the first range
|
103
|
+
# then change that range to cover the entire return
|
104
|
+
if existing
|
105
|
+
existing.drop(existing.length - 1)
|
106
|
+
range = existing[0]
|
107
|
+
range.repurpose(0, splat_length)
|
108
|
+
else
|
109
|
+
add_tag(key, 0...splat_length)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
# Splat all the tags existing on this set of Properties
|
115
|
+
#
|
116
|
+
# @param splat_length [Integer] the length to which to to set all
|
117
|
+
# tags.
|
118
|
+
def splat_from_ret splat_length
|
119
|
+
return unless tracked?
|
120
|
+
|
121
|
+
tag_keys.each do |key|
|
122
|
+
next unless key
|
123
|
+
|
124
|
+
existing = fetch_tag(key)
|
125
|
+
next unless existing
|
126
|
+
|
127
|
+
existing.each do |range|
|
128
|
+
range.repurpose(0, splat_length)
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
@@ -0,0 +1,66 @@
|
|
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
|
+
require 'contrast/agent/assess/finalizers/hash'
|
5
|
+
|
6
|
+
module Contrast
|
7
|
+
module Agent
|
8
|
+
module Assess
|
9
|
+
# How we track the Assess properties attached to objects
|
10
|
+
#
|
11
|
+
# Finalized objects should run through this class as the Finalizers
|
12
|
+
# have tightly coupled dependencies on each other.
|
13
|
+
class Tracker
|
14
|
+
PROPERTIES_HASH = Contrast::Agent::Assess::Finalizers::Hash.new
|
15
|
+
|
16
|
+
class << self
|
17
|
+
def properties source
|
18
|
+
return unless trackable?(source)
|
19
|
+
|
20
|
+
PROPERTIES_HASH[source] ||= Contrast::Agent::Assess::Properties.new
|
21
|
+
end
|
22
|
+
|
23
|
+
def trackable? source
|
24
|
+
PROPERTIES_HASH.trackable?(source)
|
25
|
+
end
|
26
|
+
|
27
|
+
def tracked? source
|
28
|
+
PROPERTIES_HASH.tracked?(source)
|
29
|
+
end
|
30
|
+
|
31
|
+
def pre_freeze source
|
32
|
+
PROPERTIES_HASH.pre_freeze(source)
|
33
|
+
end
|
34
|
+
|
35
|
+
# Copy the properties from one object to the next, assuming the
|
36
|
+
# target does not already have its own properties.
|
37
|
+
#
|
38
|
+
# @param source [Object] the instance from which to copy properties
|
39
|
+
# @param target [Object] the instance to which to copy properties
|
40
|
+
def copy source, target
|
41
|
+
PROPERTIES_HASH[target] ||= properties(source).dup
|
42
|
+
end
|
43
|
+
|
44
|
+
# Duplicate the given object, returning the duplicate after copying
|
45
|
+
# the properties of the original and storing them as the properties
|
46
|
+
# of the duplicate.
|
47
|
+
#
|
48
|
+
# @param source [Object] the thing to duplicate
|
49
|
+
# @return [Object] the duplicate of the original, or the original if
|
50
|
+
# it does not respond to duplication
|
51
|
+
def duplicate source
|
52
|
+
return source unless source
|
53
|
+
|
54
|
+
duplicate = source.dup
|
55
|
+
PROPERTIES_HASH[duplicate] ||= PROPERTIES_HASH[source].dup
|
56
|
+
duplicate
|
57
|
+
rescue StandardError
|
58
|
+
source
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
require 'contrast/agent/assess/finalizers/freeze'
|
@@ -37,7 +37,7 @@ module Contrast
|
|
37
37
|
# being phased out with support for those language versions.
|
38
38
|
class ClassReopener
|
39
39
|
include Contrast::Components::Interface
|
40
|
-
access_component :logging
|
40
|
+
access_component :logging, :scope
|
41
41
|
|
42
42
|
END_NEW_LINE = "end\n"
|
43
43
|
PROTECTED_WITH_NEW_LINE = "protected\n"
|
@@ -101,11 +101,13 @@ module Contrast
|
|
101
101
|
# Evaluate the patches that have been staged for this class, replacing
|
102
102
|
# the method definitions with those our rewrite.
|
103
103
|
def commit_patches
|
104
|
-
|
104
|
+
with_contrast_scope do
|
105
|
+
return unless staged_changes?
|
105
106
|
|
106
|
-
|
107
|
-
|
108
|
-
|
107
|
+
content = build_content
|
108
|
+
valid = Ripper.sexp(content)
|
109
|
+
unbound_eval(class_name, content) if !!valid && !class_name.empty?
|
110
|
+
end
|
109
111
|
end
|
110
112
|
|
111
113
|
# Find the sourcecode of the method at the given location and return it
|
@@ -77,19 +77,21 @@ module Contrast
|
|
77
77
|
# This method is called by TracePointHook to instrument a specific class during a require
|
78
78
|
# or eval of dynamic class definition
|
79
79
|
def patch_specific_module mod
|
80
|
-
|
81
|
-
|
82
|
-
|
80
|
+
with_contrast_scope do
|
81
|
+
mod_name = mod.cs__name
|
82
|
+
return unless Contrast::Utils::ClassUtil.truly_defined?(mod_name)
|
83
|
+
return if AGENT.skip_instrumentation?(mod_name)
|
83
84
|
|
84
|
-
|
85
|
+
load_patches_for_module(mod_name)
|
85
86
|
|
86
|
-
|
87
|
+
return unless all_module_names.any? { |name| name == mod_name }
|
87
88
|
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
89
|
+
module_data = Contrast::Agent::ModuleData.new(mod, mod_name)
|
90
|
+
patch_into_module(module_data)
|
91
|
+
all_module_names.delete(mod_name) if status_type.get_status(mod).patched?
|
92
|
+
rescue StandardError => e
|
93
|
+
logger.error('Unable to patch module', e, module: mod_name)
|
94
|
+
end
|
93
95
|
end
|
94
96
|
|
95
97
|
# We did it, team. We found a patcher(s) that applies to the given
|
@@ -186,7 +188,7 @@ module Contrast
|
|
186
188
|
clazz = module_data.mod
|
187
189
|
|
188
190
|
status.patching!
|
189
|
-
patched =
|
191
|
+
patched = false
|
190
192
|
|
191
193
|
counts = 0
|
192
194
|
# Monkey patch any methods in this class that have matching nodes in the policy
|
@@ -219,17 +221,6 @@ module Contrast
|
|
219
221
|
module_data.mod).patch_status)
|
220
222
|
end
|
221
223
|
|
222
|
-
# Includes the given module with the
|
223
|
-
# Contrast::Extension::Assess::AssessExtension
|
224
|
-
# @param module_data [Contrast::Agent::ModuleData] the module, and
|
225
|
-
# its name, that's being patched into
|
226
|
-
def include_module module_data
|
227
|
-
return false unless Contrast::Agent::Assess::Policy::Policy.instance.tracked_classes.include?(module_data.name)
|
228
|
-
|
229
|
-
module_data.mod.send(:include, Contrast::Extension::Assess::AssessExtension)
|
230
|
-
true
|
231
|
-
end
|
232
|
-
|
233
224
|
# Get all of the instance methods on the given module, excluding
|
234
225
|
# those from super classes. this list will always include the
|
235
226
|
# initialize method
|
@@ -37,13 +37,12 @@ module Contrast
|
|
37
37
|
|
38
38
|
access_component :analysis, :logging
|
39
39
|
|
40
|
-
attr_reader :sources, :propagators, :triggers, :providers
|
40
|
+
attr_reader :sources, :propagators, :triggers, :providers
|
41
41
|
|
42
42
|
SOURCES_KEY = 'sources'
|
43
43
|
PROPAGATION_KEY = 'propagators'
|
44
44
|
RULES_KEY = 'rules'
|
45
45
|
TRIGGERS_KEY = 'triggers'
|
46
|
-
TRACKED_CLASSES_KEY = 'tracked_classes'
|
47
46
|
|
48
47
|
def self.policy_json
|
49
48
|
File.join(policy_folder, 'policy.json').cs__freeze
|
@@ -54,7 +53,6 @@ module Contrast
|
|
54
53
|
@propagators = []
|
55
54
|
@triggers = []
|
56
55
|
@providers = {}
|
57
|
-
@tracked_classes = []
|
58
56
|
|
59
57
|
json = Contrast::Utils::ResourceLoader.load(cs__class.policy_json)
|
60
58
|
from_hash_string(json)
|
@@ -114,7 +112,6 @@ module Contrast
|
|
114
112
|
def module_names
|
115
113
|
@_module_names ||= begin
|
116
114
|
m = Set.new
|
117
|
-
tracked_classes.each { |tracked| m << tracked }
|
118
115
|
sources.each { |source| m << source.class_name }
|
119
116
|
propagators.each { |propagator| m << propagator.class_name }
|
120
117
|
triggers.each { |trigger| m << trigger.class_name }
|
@@ -44,14 +44,9 @@ module Contrast
|
|
44
44
|
context_response = Contrast::Api::Dtm::HttpResponse.new
|
45
45
|
context_response.response_code = response_code.to_i
|
46
46
|
headers&.each_pair do |key, value|
|
47
|
-
|
48
|
-
v = Contrast::Utils::StringUtils.force_utf8(value)
|
49
|
-
context_response.response_headers[k] = v
|
47
|
+
append_pair(context_response.normalized_response_headers, key, value)
|
50
48
|
end
|
51
|
-
context_response.parsed_response_headers = true
|
52
|
-
|
53
49
|
context_response.response_body_binary = Contrast::Utils::StringUtils.force_utf8(body)
|
54
|
-
context_response.parsed_response_body = false
|
55
50
|
|
56
51
|
doc_type = document_type
|
57
52
|
context_response.document_type = doc_type if doc_type
|
@@ -97,6 +92,22 @@ module Contrast
|
|
97
92
|
|
98
93
|
private
|
99
94
|
|
95
|
+
# From the dtm for normalized_response_headers:
|
96
|
+
# Key is UPPERCASE_UNDERSCORE
|
97
|
+
#
|
98
|
+
# Example: Content-Type: text/html; charset=utf-8
|
99
|
+
# "CONTENT_TYPE" => Content-Type,["text/html; charset=utf8"]
|
100
|
+
def append_pair map, key, value
|
101
|
+
return unless key && value
|
102
|
+
return if value.is_a?(Hash)
|
103
|
+
|
104
|
+
safe_key = Contrast::Utils::StringUtils.force_utf8(key)
|
105
|
+
hash_key = Contrast::Utils::StringUtils.normalized_key(safe_key)
|
106
|
+
map[hash_key] ||= Contrast::Api::Dtm::Pair.new
|
107
|
+
map[hash_key].key = safe_key
|
108
|
+
map[hash_key].values << Contrast::Utils::StringUtils.force_utf8(value)
|
109
|
+
end
|
110
|
+
|
100
111
|
HTTP_PREFIX = /^[Hh][Tt][Tt][Pp][_-]/i.cs__freeze
|
101
112
|
|
102
113
|
# Given some holder of the content of the response's body, extract that
|