@contrast/agent 4.5.0 → 4.7.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.
- package/bin/VERSION +1 -1
- package/bin/linux/contrast-service +0 -0
- package/bin/mac/contrast-service +0 -0
- package/bin/windows/contrast-service.exe +0 -0
- package/lib/assess/membrane/source-membrane.js +4 -18
- package/lib/assess/policy/propagators.json +11 -21
- package/lib/assess/policy/rules.json +5 -0
- package/lib/assess/policy/signatures.json +15 -0
- package/lib/assess/propagators/dustjs/escape-html.js +22 -0
- package/lib/assess/propagators/dustjs/escape-js.js +22 -0
- package/lib/assess/propagators/encode-uri/encode-uri-component.js +22 -0
- package/lib/assess/propagators/encode-uri/encode-uri.js +22 -0
- package/lib/assess/propagators/index.js +0 -2
- package/lib/assess/propagators/joi/values.js +26 -11
- package/lib/assess/propagators/mustache/escape.js +22 -0
- package/lib/assess/propagators/path/common.js +155 -46
- package/lib/assess/propagators/path/join.js +5 -1
- package/lib/assess/propagators/path/normalize.js +1 -2
- package/lib/assess/propagators/path/resolve.js +11 -2
- package/lib/assess/propagators/template-escape.js +84 -0
- package/lib/assess/propagators/templates.js +2 -3
- package/lib/assess/sinks/dustjs-linkedin-xss.js +131 -0
- package/lib/core/arch-components/dynamodb.js +1 -2
- package/lib/core/arch-components/dynamodbv3.js +44 -0
- package/lib/core/arch-components/index.js +1 -0
- package/lib/core/arch-components/rethinkdb.js +53 -0
- package/lib/core/async-storage/hooks/bluebird.js +20 -0
- package/lib/core/config/options.js +2 -1
- package/lib/core/stacktrace.js +3 -4
- package/lib/feature-set.js +2 -1
- package/lib/hooks/frameworks/base.js +8 -2
- package/lib/hooks/frameworks/http.js +23 -16
- package/lib/hooks/frameworks/http2.js +73 -0
- package/lib/hooks/frameworks/index.js +8 -3
- package/lib/hooks/http.js +112 -128
- package/lib/hooks/patcher.js +69 -48
- package/lib/hooks/require.js +16 -22
- package/lib/instrumentation.js +0 -3
- package/lib/protect/rules/cmd-injection-command-backdoors/backdoor-detector.js +3 -3
- package/lib/protect/rules/signatures/reflected-xss/helpers/function-call.js +1 -1
- package/lib/protect/rules/xss/helpers/function-call.js +1 -1
- package/lib/util/clean-stack.js +1 -1
- package/lib/util/clean-string/brackets.js +3 -3
- package/lib/util/ip-analyzer.js +1 -1
- package/lib/util/some.js +27 -0
- package/lib/util/source-map.js +1 -1
- package/lib/util/xml-analyzer/external-entity-finder.js +1 -1
- package/package.json +14 -16
- package/lib/hooks/frameworks/https.js +0 -42
- package/node_modules/bindings/LICENSE.md +0 -22
- package/node_modules/bindings/README.md +0 -98
- package/node_modules/bindings/bindings.js +0 -221
- package/node_modules/bindings/package.json +0 -32
- package/node_modules/file-uri-to-path/.npmignore +0 -1
- package/node_modules/file-uri-to-path/.travis.yml +0 -30
- package/node_modules/file-uri-to-path/History.md +0 -21
- package/node_modules/file-uri-to-path/LICENSE +0 -20
- package/node_modules/file-uri-to-path/README.md +0 -74
- package/node_modules/file-uri-to-path/index.d.ts +0 -2
- package/node_modules/file-uri-to-path/index.js +0 -66
- package/node_modules/file-uri-to-path/package.json +0 -36
- package/node_modules/file-uri-to-path/test/test.js +0 -24
- package/node_modules/file-uri-to-path/test/tests.json +0 -13
- package/node_modules/glossy/LICENSE +0 -19
- package/node_modules/glossy/README.md +0 -129
- package/node_modules/glossy/index.js +0 -12
- package/node_modules/glossy/lib/glossy/parse.js +0 -520
- package/node_modules/glossy/lib/glossy/produce.js +0 -459
- package/node_modules/glossy/package.json +0 -47
- package/node_modules/glossy/test/decide.js +0 -7
- package/node_modules/glossy/test/decode_pri.js +0 -24
- package/node_modules/glossy/test/parse_3164.js +0 -104
- package/node_modules/glossy/test/parse_5424.js +0 -106
- package/node_modules/glossy/test/parse_5848.js +0 -40
- package/node_modules/glossy/test/parse_8601.js +0 -14
- package/node_modules/glossy/test/parse_rfc3339.js +0 -9
- package/node_modules/glossy/test/produce.js +0 -162
- package/node_modules/glossy/test/runner.js +0 -40
- package/node_modules/glossy/test/structure_data.js +0 -24
- package/node_modules/nan/CHANGELOG.md +0 -537
- package/node_modules/nan/LICENSE.md +0 -13
- package/node_modules/nan/README.md +0 -455
- package/node_modules/nan/doc/asyncworker.md +0 -146
- package/node_modules/nan/doc/buffers.md +0 -54
- package/node_modules/nan/doc/callback.md +0 -76
- package/node_modules/nan/doc/converters.md +0 -41
- package/node_modules/nan/doc/errors.md +0 -226
- package/node_modules/nan/doc/json.md +0 -62
- package/node_modules/nan/doc/maybe_types.md +0 -583
- package/node_modules/nan/doc/methods.md +0 -664
- package/node_modules/nan/doc/new.md +0 -147
- package/node_modules/nan/doc/node_misc.md +0 -123
- package/node_modules/nan/doc/object_wrappers.md +0 -263
- package/node_modules/nan/doc/persistent.md +0 -296
- package/node_modules/nan/doc/scopes.md +0 -73
- package/node_modules/nan/doc/script.md +0 -38
- package/node_modules/nan/doc/string_bytes.md +0 -62
- package/node_modules/nan/doc/v8_internals.md +0 -199
- package/node_modules/nan/doc/v8_misc.md +0 -85
- package/node_modules/nan/include_dirs.js +0 -1
- package/node_modules/nan/nan.h +0 -2898
- package/node_modules/nan/nan_callbacks.h +0 -88
- package/node_modules/nan/nan_callbacks_12_inl.h +0 -514
- package/node_modules/nan/nan_callbacks_pre_12_inl.h +0 -520
- package/node_modules/nan/nan_converters.h +0 -72
- package/node_modules/nan/nan_converters_43_inl.h +0 -68
- package/node_modules/nan/nan_converters_pre_43_inl.h +0 -42
- package/node_modules/nan/nan_define_own_property_helper.h +0 -29
- package/node_modules/nan/nan_implementation_12_inl.h +0 -430
- package/node_modules/nan/nan_implementation_pre_12_inl.h +0 -263
- package/node_modules/nan/nan_json.h +0 -166
- package/node_modules/nan/nan_maybe_43_inl.h +0 -356
- package/node_modules/nan/nan_maybe_pre_43_inl.h +0 -268
- package/node_modules/nan/nan_new.h +0 -340
- package/node_modules/nan/nan_object_wrap.h +0 -156
- package/node_modules/nan/nan_persistent_12_inl.h +0 -132
- package/node_modules/nan/nan_persistent_pre_12_inl.h +0 -242
- package/node_modules/nan/nan_private.h +0 -73
- package/node_modules/nan/nan_string_bytes.h +0 -305
- package/node_modules/nan/nan_typedarray_contents.h +0 -96
- package/node_modules/nan/nan_weak.h +0 -437
- package/node_modules/nan/package.json +0 -41
- package/node_modules/nan/tools/1to2.js +0 -412
- package/node_modules/nan/tools/README.md +0 -14
- package/node_modules/nan/tools/package.json +0 -19
- package/node_modules/unix-dgram/LICENSE +0 -13
- package/node_modules/unix-dgram/README.md +0 -107
- package/node_modules/unix-dgram/binding.gyp +0 -20
- package/node_modules/unix-dgram/build/Makefile +0 -324
- package/node_modules/unix-dgram/build/Release/.deps/Release/obj.target/unix_dgram/src/unix_dgram.o.d +0 -58
- package/node_modules/unix-dgram/build/Release/.deps/Release/obj.target/unix_dgram.node.d +0 -1
- package/node_modules/unix-dgram/build/Release/.deps/Release/unix_dgram.node.d +0 -1
- package/node_modules/unix-dgram/build/Release/obj.target/unix_dgram/src/unix_dgram.o +0 -0
- package/node_modules/unix-dgram/build/Release/obj.target/unix_dgram.node +0 -0
- package/node_modules/unix-dgram/build/Release/unix_dgram.node +0 -0
- package/node_modules/unix-dgram/build/binding.Makefile +0 -6
- package/node_modules/unix-dgram/build/config.gypi +0 -213
- package/node_modules/unix-dgram/build/unix_dgram.target.mk +0 -159
- package/node_modules/unix-dgram/lib/unix_dgram.js +0 -168
- package/node_modules/unix-dgram/package.json +0 -36
- package/node_modules/unix-dgram/src/unix_dgram.cc +0 -404
- package/node_modules/unix-dgram/src/win_dummy.cc +0 -7
- package/node_modules/unix-dgram/test/test-connect-callback.js +0 -68
- package/node_modules/unix-dgram/test/test-connect.js +0 -53
- package/node_modules/unix-dgram/test/test-dgram-unix.js +0 -58
- package/node_modules/unix-dgram/test/test-send-error.js +0 -26
- package/node_modules/winston-syslog/.eslintrc +0 -7
- package/node_modules/winston-syslog/.travis.yml +0 -14
- package/node_modules/winston-syslog/CHANGELOG.md +0 -9
- package/node_modules/winston-syslog/LICENSE +0 -20
- package/node_modules/winston-syslog/README.md +0 -135
- package/node_modules/winston-syslog/lib/utils.js +0 -26
- package/node_modules/winston-syslog/lib/winston-syslog.js +0 -385
- package/node_modules/winston-syslog/package.json +0 -56
- package/node_modules/winston-syslog/test/format-test.js +0 -122
- package/node_modules/winston-syslog/test/syslog-test.js +0 -95
- package/node_modules/winston-syslog/test/unix-connect-test.js +0 -133
|
@@ -34,7 +34,12 @@ module.exports.handle = function handle() {
|
|
|
34
34
|
if (!data.args[0]) return;
|
|
35
35
|
const resultMeta = getResultMeta(data, 'resolve');
|
|
36
36
|
const isAbsolute = absolutePath(data.args[0]);
|
|
37
|
-
|
|
37
|
+
|
|
38
|
+
/*
|
|
39
|
+
plus one in case isAbsolute is false since our working deretory ends without slash
|
|
40
|
+
example: /Users/John/Documents/Projects/node-agent
|
|
41
|
+
*/
|
|
42
|
+
resultMeta.offset = isAbsolute ? 0 : process.cwd().length + 1;
|
|
38
43
|
|
|
39
44
|
// a work-around for paths like C:\Windows
|
|
40
45
|
if (
|
|
@@ -45,7 +50,11 @@ module.exports.handle = function handle() {
|
|
|
45
50
|
resultMeta.evaluator = (segmentOffset) => segmentOffset > -1;
|
|
46
51
|
}
|
|
47
52
|
|
|
48
|
-
propagate({
|
|
53
|
+
propagate({
|
|
54
|
+
data,
|
|
55
|
+
resultMeta,
|
|
56
|
+
win32: os === 'win32'
|
|
57
|
+
});
|
|
49
58
|
}
|
|
50
59
|
});
|
|
51
60
|
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
Copyright: 2021 Contrast Security, Inc
|
|
3
|
+
Contact: support@contrastsecurity.com
|
|
4
|
+
License: Commercial
|
|
5
|
+
|
|
6
|
+
NOTICE: This Software and the patented inventions embodied within may only be
|
|
7
|
+
used as part of Contrast Security’s commercial offerings. Even though it is
|
|
8
|
+
made available through public repositories, use of this Software is subject to
|
|
9
|
+
the applicable End User Licensing Agreement found at
|
|
10
|
+
https://www.contrastsecurity.com/enduser-terms-0317a or as otherwise agreed
|
|
11
|
+
between Contrast Security and the End User. The Software may not be reverse
|
|
12
|
+
engineered, modified, repackaged, sold, redistributed or otherwise used in a
|
|
13
|
+
way not consistent with the End User License Agreement.
|
|
14
|
+
*/
|
|
15
|
+
'use strict';
|
|
16
|
+
|
|
17
|
+
const tracker = require('../../tracker');
|
|
18
|
+
const TagRange = require('../models/tag-range');
|
|
19
|
+
const { CallContext, PropagationEvent, Signature } = require('../models');
|
|
20
|
+
|
|
21
|
+
function getEscapedTagRanges(input, result, start, stop, tag) {
|
|
22
|
+
const textArr = input.split('').slice(start, stop + 1);
|
|
23
|
+
const escapedArr = result.split('');
|
|
24
|
+
const overlap = textArr.filter((x) => {
|
|
25
|
+
if (escapedArr.includes(x)) {
|
|
26
|
+
return x;
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
if (overlap.length === 0) {
|
|
30
|
+
return [];
|
|
31
|
+
}
|
|
32
|
+
const newTagRanges = [];
|
|
33
|
+
let firstIndex = escapedArr.indexOf(overlap[0]);
|
|
34
|
+
let currIndex = firstIndex;
|
|
35
|
+
let nextIndex;
|
|
36
|
+
for (let i = 1; i < overlap.length; i++) {
|
|
37
|
+
nextIndex = escapedArr.indexOf(overlap[i], currIndex + 1);
|
|
38
|
+
if (nextIndex !== currIndex + 1) {
|
|
39
|
+
newTagRanges.push(new TagRange(firstIndex, currIndex, tag));
|
|
40
|
+
firstIndex = nextIndex;
|
|
41
|
+
}
|
|
42
|
+
if (i === overlap.length - 1) {
|
|
43
|
+
newTagRanges.push(new TagRange(firstIndex, nextIndex, tag));
|
|
44
|
+
}
|
|
45
|
+
currIndex = nextIndex;
|
|
46
|
+
}
|
|
47
|
+
return newTagRanges;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function propagator(data, tagName, signatureName) {
|
|
51
|
+
const input = data.args[0];
|
|
52
|
+
|
|
53
|
+
if (!input || !tracker.getData(input).tracked) {
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// adjust tag ranges
|
|
58
|
+
const tagRanges = [];
|
|
59
|
+
tracker.getData(input).tagRanges.forEach((range) => {
|
|
60
|
+
const { start, stop, tag } = range;
|
|
61
|
+
tagRanges.push(
|
|
62
|
+
...getEscapedTagRanges(input, data.result, start, stop, tag)
|
|
63
|
+
);
|
|
64
|
+
});
|
|
65
|
+
tagRanges.push(new TagRange(0, data.result.length - 1, tagName));
|
|
66
|
+
const result = tracker.track(data.result);
|
|
67
|
+
const trackData = tracker.getData(result);
|
|
68
|
+
trackData.tagRanges = tagRanges;
|
|
69
|
+
trackData.event = new PropagationEvent({
|
|
70
|
+
context: new CallContext({
|
|
71
|
+
...data,
|
|
72
|
+
obj: null
|
|
73
|
+
}),
|
|
74
|
+
parents: [trackData.event],
|
|
75
|
+
signature: new Signature(signatureName),
|
|
76
|
+
source: 'P',
|
|
77
|
+
target: 'R',
|
|
78
|
+
tagRanges,
|
|
79
|
+
tags: tagName
|
|
80
|
+
});
|
|
81
|
+
data.result = result;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
module.exports.propagate = propagator;
|
|
@@ -21,10 +21,9 @@ const tracker = require('../../tracker.js');
|
|
|
21
21
|
|
|
22
22
|
const { PropagationEvent, Signature, CallContext } = require('../models');
|
|
23
23
|
const { isString } = require('../../util/is-string');
|
|
24
|
+
const injections = require('../../core/rewrite/injections');
|
|
24
25
|
|
|
25
|
-
const ContrastMethods =
|
|
26
|
-
'ContrastMethods'
|
|
27
|
-
);
|
|
26
|
+
const ContrastMethods = injections.get('ContrastMethods');
|
|
28
27
|
|
|
29
28
|
/**
|
|
30
29
|
* In order to propagate through template literals, we leverage rewriting to
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
/**
|
|
2
|
+
Copyright: 2021 Contrast Security, Inc
|
|
3
|
+
Contact: support@contrastsecurity.com
|
|
4
|
+
License: Commercial
|
|
5
|
+
|
|
6
|
+
NOTICE: This Software and the patented inventions embodied within may only be
|
|
7
|
+
used as part of Contrast Security’s commercial offerings. Even though it is
|
|
8
|
+
made available through public repositories, use of this Software is subject to
|
|
9
|
+
the applicable End User Licensing Agreement found at
|
|
10
|
+
https://www.contrastsecurity.com/enduser-terms-0317a or as otherwise agreed
|
|
11
|
+
between Contrast Security and the End User. The Software may not be reverse
|
|
12
|
+
engineered, modified, repackaged, sold, redistributed or otherwise used in a
|
|
13
|
+
way not consistent with the End User License Agreement.
|
|
14
|
+
*/
|
|
15
|
+
'use strict';
|
|
16
|
+
|
|
17
|
+
const patcher = require('../../hooks/patcher');
|
|
18
|
+
const { PATCH_TYPES } = require('../../constants');
|
|
19
|
+
const moduleHook = require('../../hooks/require');
|
|
20
|
+
const { CallContext, Signature } = require('../models');
|
|
21
|
+
const {
|
|
22
|
+
RULES: { REFLECTED_XSS }
|
|
23
|
+
} = require('../../constants');
|
|
24
|
+
|
|
25
|
+
const signature = new Signature({
|
|
26
|
+
moduleName: 'http.ClientResponse',
|
|
27
|
+
methodName: 'write',
|
|
28
|
+
isModule: true
|
|
29
|
+
});
|
|
30
|
+
const moduleName = 'dustjs-linkedin';
|
|
31
|
+
|
|
32
|
+
class Handler {
|
|
33
|
+
constructor({ report, isVulnerable, requiredTags, xss: { disallowedTags } }) {
|
|
34
|
+
this._isVulnerable = isVulnerable;
|
|
35
|
+
this.report = report;
|
|
36
|
+
this.requiredTags = requiredTags;
|
|
37
|
+
this.disallowedTags = disallowedTags;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
isVulnerable(input) {
|
|
41
|
+
const { requiredTags, disallowedTags } = this;
|
|
42
|
+
const ret = this._isVulnerable({
|
|
43
|
+
input,
|
|
44
|
+
ruleId: REFLECTED_XSS,
|
|
45
|
+
disallowedTags,
|
|
46
|
+
requiredTags
|
|
47
|
+
});
|
|
48
|
+
return ret;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
handle() {
|
|
52
|
+
moduleHook.resolve({ name: moduleName }, (dust) =>
|
|
53
|
+
this.handleRequire(dust)
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
getType(obj) {
|
|
58
|
+
return obj && obj.constructor && obj.constructor.name;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
isResponseType(typeName) {
|
|
62
|
+
return typeName === 'ServerResponse';
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
patchDust(dust) {
|
|
66
|
+
const self = this;
|
|
67
|
+
patcher.patch(dust, 'stream', {
|
|
68
|
+
name: moduleName,
|
|
69
|
+
patchType: PATCH_TYPES.ASSESS_SINK,
|
|
70
|
+
alwaysRun: true,
|
|
71
|
+
post(data) {
|
|
72
|
+
self.patchStream(data.result);
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Patch the pipe method and check wether the stream is targeting a
|
|
79
|
+
* response instance. If so, add the instance to the set of streams
|
|
80
|
+
* we should follow.
|
|
81
|
+
*/
|
|
82
|
+
patchStream(streamInstance) {
|
|
83
|
+
const self = this;
|
|
84
|
+
patcher.patch(streamInstance, 'pipe', {
|
|
85
|
+
name: 'dust.Stream.prototype',
|
|
86
|
+
patchType: PATCH_TYPES.ASSESS_SINK,
|
|
87
|
+
alwaysRun: true,
|
|
88
|
+
pre({ args: [maybeRes] }) {
|
|
89
|
+
self.patchStreamTarget(maybeRes);
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
patchStreamTarget(target) {
|
|
95
|
+
const self = this;
|
|
96
|
+
const typeName = self.getType(target);
|
|
97
|
+
|
|
98
|
+
if (self.isResponseType(typeName)) {
|
|
99
|
+
patcher.patch(target, 'write', {
|
|
100
|
+
name: 'dust.pipeTarget',
|
|
101
|
+
patchType: PATCH_TYPES.ASSESS_SINK,
|
|
102
|
+
alwaysRun: true,
|
|
103
|
+
post({ args: [str], hooked }) {
|
|
104
|
+
if (self.isVulnerable(str)) {
|
|
105
|
+
self.report({
|
|
106
|
+
ruleId: REFLECTED_XSS,
|
|
107
|
+
signature,
|
|
108
|
+
input: str,
|
|
109
|
+
ctxt: new CallContext({
|
|
110
|
+
obj: typeName,
|
|
111
|
+
args: [str],
|
|
112
|
+
result: str,
|
|
113
|
+
stackOpts: {
|
|
114
|
+
constructorOpt: hooked
|
|
115
|
+
}
|
|
116
|
+
})
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
handleRequire(dust) {
|
|
125
|
+
this.patchDust(dust);
|
|
126
|
+
return dust;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
module.exports = ({ common }) => new Handler(common);
|
|
131
|
+
module.exports.Handler = Handler;
|
|
@@ -18,7 +18,6 @@ const agentEmitter = require('../../agent-emitter');
|
|
|
18
18
|
const { PATCH_TYPES } = require('../../constants');
|
|
19
19
|
const ModuleHook = require('../../hooks/require');
|
|
20
20
|
const patcher = require('../../hooks/patcher');
|
|
21
|
-
const _ = require('lodash');
|
|
22
21
|
|
|
23
22
|
ModuleHook.resolve({ name: 'aws-sdk' }, (AWS) => {
|
|
24
23
|
patcher.patch(AWS.DynamoDB.prototype, 'makeRequest', {
|
|
@@ -27,7 +26,7 @@ ModuleHook.resolve({ name: 'aws-sdk' }, (AWS) => {
|
|
|
27
26
|
alwaysRun: true,
|
|
28
27
|
post(ctx) {
|
|
29
28
|
try {
|
|
30
|
-
const endpoint =
|
|
29
|
+
const { endpoint } = this;
|
|
31
30
|
agentEmitter.emit('architectureComponent', {
|
|
32
31
|
vendor: 'DynamoDB',
|
|
33
32
|
url: new URL(`${endpoint.protocol}//${endpoint.hostname}`).toString(),
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
Copyright: 2021 Contrast Security, Inc
|
|
3
|
+
Contact: support@contrastsecurity.com
|
|
4
|
+
License: Commercial
|
|
5
|
+
|
|
6
|
+
NOTICE: This Software and the patented inventions embodied within may only be
|
|
7
|
+
used as part of Contrast Security’s commercial offerings. Even though it is
|
|
8
|
+
made available through public repositories, use of this Software is subject to
|
|
9
|
+
the applicable End User Licensing Agreement found at
|
|
10
|
+
https://www.contrastsecurity.com/enduser-terms-0317a or as otherwise agreed
|
|
11
|
+
between Contrast Security and the End User. The Software may not be reverse
|
|
12
|
+
engineered, modified, repackaged, sold, redistributed or otherwise used in a
|
|
13
|
+
way not consistent with the End User License Agreement.
|
|
14
|
+
*/
|
|
15
|
+
'use strict';
|
|
16
|
+
const logger = require('../logger')('contrast:arch-component');
|
|
17
|
+
const agentEmitter = require('../../agent-emitter');
|
|
18
|
+
const { PATCH_TYPES } = require('../../constants');
|
|
19
|
+
const ModuleHook = require('../../hooks/require');
|
|
20
|
+
const patcher = require('../../hooks/patcher');
|
|
21
|
+
|
|
22
|
+
function emitArchitectureComponent(endpoint) {
|
|
23
|
+
agentEmitter.emit('architectureComponent', {
|
|
24
|
+
vendor: 'DynamoDB',
|
|
25
|
+
url: new URL(`${endpoint.protocol}//${endpoint.hostname}`).toString(),
|
|
26
|
+
remoteHost: '',
|
|
27
|
+
remotePort: endpoint.port
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
ModuleHook.resolve({ name: '@aws-sdk/client-dynamodb' }, (AWS) => {
|
|
32
|
+
patcher.patch(AWS.DynamoDBClient.prototype, 'send', {
|
|
33
|
+
name: 'DynamoDBv3.arch_component',
|
|
34
|
+
patchType: PATCH_TYPES.ARCH_COMPONENT,
|
|
35
|
+
alwaysRun: true,
|
|
36
|
+
post(ctx) {
|
|
37
|
+
try {
|
|
38
|
+
this.config.endpoint().then(emitArchitectureComponent);
|
|
39
|
+
} catch (err) {
|
|
40
|
+
logger.warn('unable to report DynamoDB architecture component\n', err);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
});
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
Copyright: 2021 Contrast Security, Inc
|
|
3
|
+
Contact: support@contrastsecurity.com
|
|
4
|
+
License: Commercial
|
|
5
|
+
|
|
6
|
+
NOTICE: This Software and the patented inventions embodied within may only be
|
|
7
|
+
used as part of Contrast Security’s commercial offerings. Even though it is
|
|
8
|
+
made available through public repositories, use of this Software is subject to
|
|
9
|
+
the applicable End User Licensing Agreement found at
|
|
10
|
+
https://www.contrastsecurity.com/enduser-terms-0317a or as otherwise agreed
|
|
11
|
+
between Contrast Security and the End User. The Software may not be reverse
|
|
12
|
+
engineered, modified, repackaged, sold, redistributed or otherwise used in a
|
|
13
|
+
way not consistent with the End User License Agreement.
|
|
14
|
+
*/
|
|
15
|
+
'use strict';
|
|
16
|
+
|
|
17
|
+
const agentEmitter = require('../../agent-emitter');
|
|
18
|
+
const { PATCH_TYPES } = require('../../constants');
|
|
19
|
+
const ModuleHook = require('../../hooks/require');
|
|
20
|
+
const patcher = require('../../hooks/patcher');
|
|
21
|
+
const logger = require('../logger')('contrast:arch-component');
|
|
22
|
+
|
|
23
|
+
ModuleHook.resolve({ name: 'rethinkdb' }, (rethinkdb) => {
|
|
24
|
+
patcher.patch(rethinkdb, 'connect', {
|
|
25
|
+
name: 'rethinkdb.arch_component',
|
|
26
|
+
patchType: PATCH_TYPES.ARCH_COMPONENT,
|
|
27
|
+
alwaysRun: true,
|
|
28
|
+
post(ctx) {
|
|
29
|
+
ctx.result
|
|
30
|
+
.then((res) => {
|
|
31
|
+
if (res.open) {
|
|
32
|
+
const url =
|
|
33
|
+
res.host == 'localhost'
|
|
34
|
+
? 'http://localhost'
|
|
35
|
+
: new URL(res.host).toString();
|
|
36
|
+
agentEmitter.emit('architectureComponent', {
|
|
37
|
+
vendor: 'RethinkDB',
|
|
38
|
+
url,
|
|
39
|
+
remotePort: res.port
|
|
40
|
+
});
|
|
41
|
+
} else {
|
|
42
|
+
logger.warn('unable to open RethinkDB connection');
|
|
43
|
+
}
|
|
44
|
+
})
|
|
45
|
+
.catch((err) => {
|
|
46
|
+
logger.warn(
|
|
47
|
+
'unable to report RethinkDB architecture component\n%o',
|
|
48
|
+
err
|
|
49
|
+
);
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
});
|
|
@@ -23,6 +23,26 @@ module.exports = function() {
|
|
|
23
23
|
moduleHook.resolve({ name: 'bluebird' }, (bluebird) => {
|
|
24
24
|
module.exports.patchConfig(bluebird);
|
|
25
25
|
module.exports.patchAddCallbacks(bluebird);
|
|
26
|
+
module.exports.patchGetNewLibraryCopy(bluebird);
|
|
27
|
+
});
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Ensures that new library copies are also instrumented.
|
|
32
|
+
* @param {function} bluebird the library export
|
|
33
|
+
*/
|
|
34
|
+
module.exports.patchGetNewLibraryCopy = function(bluebird) {
|
|
35
|
+
if (typeof bluebird.getNewLibraryCopy !== 'function') {
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
patcher.patch(bluebird, 'getNewLibraryCopy', {
|
|
40
|
+
alwaysRun: true,
|
|
41
|
+
name: 'bluebird.getNewLibraryCopy',
|
|
42
|
+
patchType: PATCH_TYPES.ASYNC_CONTEXT,
|
|
43
|
+
post(data) {
|
|
44
|
+
module.exports.patchAddCallbacks(data.result);
|
|
45
|
+
}
|
|
26
46
|
});
|
|
27
47
|
};
|
|
28
48
|
|
|
@@ -483,7 +483,8 @@ const agent = [
|
|
|
483
483
|
arg: '<limit>',
|
|
484
484
|
default: 10,
|
|
485
485
|
fn: parseNum,
|
|
486
|
-
desc:
|
|
486
|
+
desc:
|
|
487
|
+
'set limit for stack trace size (larger limits will improve accuracy but increase memory usage)'
|
|
487
488
|
},
|
|
488
489
|
{
|
|
489
490
|
name: 'agent.polling.app_activity_ms',
|
package/lib/core/stacktrace.js
CHANGED
|
@@ -15,13 +15,13 @@ Copyright: 2021 Contrast Security, Inc
|
|
|
15
15
|
'use strict';
|
|
16
16
|
|
|
17
17
|
const semver = require('semver');
|
|
18
|
+
const agent = require('../agent');
|
|
18
19
|
const process = require('process');
|
|
19
20
|
const sourceMap = require('../util/source-map');
|
|
20
21
|
const _isAgentPath = require('../util/is-agent-path');
|
|
21
22
|
|
|
22
|
-
const STACK_TRACE_LIMIT =
|
|
23
|
+
const STACK_TRACE_LIMIT = agent.config.agent.stack_trace_limit;
|
|
23
24
|
const EVAL_ORIGIN_REGEX = /\((.*?):(\d+):\d+\)/;
|
|
24
|
-
const EJS_EVAL_ORIGIN_REGEX = /(.*\.ejs$)/;
|
|
25
25
|
const EVENTS_FILE = semver.gte(process.version, '16.0.0')
|
|
26
26
|
? 'node:events'
|
|
27
27
|
: 'events.js';
|
|
@@ -146,8 +146,7 @@ class Factory {
|
|
|
146
146
|
if (callsite.isEval()) {
|
|
147
147
|
evalOrigin = Factory.formatFileName(callsite.getEvalOrigin());
|
|
148
148
|
[, file, lineNumber, columnNumber] =
|
|
149
|
-
evalOrigin.match(EVAL_ORIGIN_REGEX) ||
|
|
150
|
-
evalOrigin.match(EJS_EVAL_ORIGIN_REGEX);
|
|
149
|
+
evalOrigin.match(EVAL_ORIGIN_REGEX) || evalOrigin.endsWith('.ejs');
|
|
151
150
|
}
|
|
152
151
|
|
|
153
152
|
file = file || callsite.getFileName();
|
package/lib/feature-set.js
CHANGED
|
@@ -22,8 +22,14 @@ const RequestFactory = require('../../reporter/models/utils/request-factory');
|
|
|
22
22
|
const CleanStack = require('../../util/clean-stack');
|
|
23
23
|
const agentEmitter = require('../../agent-emitter');
|
|
24
24
|
|
|
25
|
+
/** @typedef {import('../../agent').ContrastAgent} Agent */
|
|
26
|
+
|
|
25
27
|
class BaseFramework {
|
|
26
|
-
|
|
28
|
+
/**
|
|
29
|
+
* @param {Object} opts
|
|
30
|
+
* @param {string} opts.id
|
|
31
|
+
* @param {Agent} opts.agent
|
|
32
|
+
*/
|
|
27
33
|
constructor({ id, agent } = {}) {
|
|
28
34
|
this.id = id;
|
|
29
35
|
this.agent = agent;
|
|
@@ -46,7 +52,7 @@ class BaseFramework {
|
|
|
46
52
|
* -- Note --
|
|
47
53
|
* The current imlementation uses a CleanStack instance in order to generate
|
|
48
54
|
* a stackframe from which to obtain the information. This can be expensive.
|
|
49
|
-
* @returns {
|
|
55
|
+
* @returns {string}
|
|
50
56
|
*/
|
|
51
57
|
getAppCodeLocation() {
|
|
52
58
|
const limit = Error.stackTraceLimit;
|
|
@@ -19,39 +19,41 @@ const moduleHook = require('../require');
|
|
|
19
19
|
const patcher = require('../patcher');
|
|
20
20
|
const { HTTP_EVENTS, PATCH_TYPES } = require('../../constants');
|
|
21
21
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
super({ id, agent });
|
|
25
|
-
|
|
26
|
-
this.init();
|
|
27
|
-
}
|
|
22
|
+
/** @typedef {import('../../agent').ContrastAgent} Agent */
|
|
23
|
+
/** @typedef {import('net').Server} Server */
|
|
28
24
|
|
|
25
|
+
class HttpFramework extends BaseFramework {
|
|
29
26
|
/**
|
|
30
|
-
*
|
|
27
|
+
* @param {Agent} agent
|
|
28
|
+
* @param {string} id
|
|
31
29
|
*/
|
|
32
|
-
|
|
30
|
+
constructor(agent, id = 'http') {
|
|
31
|
+
super({ agent, id });
|
|
33
32
|
moduleHook.resolve({ name: this.id }, this.onRequire.bind(this));
|
|
34
33
|
}
|
|
35
34
|
|
|
35
|
+
/**
|
|
36
|
+
* @template {import('http') | import('https')} T
|
|
37
|
+
* @param {T} xport
|
|
38
|
+
* @returns {T}
|
|
39
|
+
*/
|
|
36
40
|
onRequire(xport) {
|
|
37
|
-
const { id } = this;
|
|
38
|
-
|
|
39
41
|
patcher.patch(xport, 'Server', {
|
|
40
|
-
name: `${id}.Server`,
|
|
42
|
+
name: `${this.id}.Server`,
|
|
41
43
|
patchType: PATCH_TYPES.FRAMEWORK,
|
|
42
44
|
alwaysRun: true,
|
|
43
45
|
post: (fnData) => this.handleServerCreate(fnData.args, fnData.result)
|
|
44
46
|
});
|
|
45
47
|
|
|
46
48
|
patcher.patch(xport, 'createServer', {
|
|
47
|
-
name: `${id}.createServer`,
|
|
49
|
+
name: `${this.id}.createServer`,
|
|
48
50
|
patchType: PATCH_TYPES.FRAMEWORK,
|
|
49
51
|
alwaysRun: true,
|
|
50
52
|
post: (fnData) => this.handleServerCreate(fnData.args, fnData.result)
|
|
51
53
|
});
|
|
52
54
|
|
|
53
55
|
patcher.patch(xport.Server.prototype, 'listen', {
|
|
54
|
-
name: `${id}.Server.prototype`,
|
|
56
|
+
name: `${this.id}.Server.prototype`,
|
|
55
57
|
patchType: PATCH_TYPES.FRAMEWORK,
|
|
56
58
|
alwaysRun: true,
|
|
57
59
|
pre: (fnData) => this.handleServerListen(fnData.args, fnData.obj)
|
|
@@ -62,6 +64,7 @@ class HttpFramework extends BaseFramework {
|
|
|
62
64
|
|
|
63
65
|
/**
|
|
64
66
|
* Emits a listen event if one has not been pubished for the server instance.
|
|
67
|
+
* @param {any[]}
|
|
65
68
|
* @param {Server} server Server on which `listen` was called
|
|
66
69
|
*/
|
|
67
70
|
handleServerListen(args, server) {
|
|
@@ -70,12 +73,16 @@ class HttpFramework extends BaseFramework {
|
|
|
70
73
|
|
|
71
74
|
/**
|
|
72
75
|
* Emits a create event for the new Server instance.
|
|
73
|
-
* @param {
|
|
76
|
+
* @param {any[]} args The arguments passed to the Server constructor
|
|
74
77
|
* @param {Server} server The http Server instance
|
|
75
78
|
*/
|
|
76
79
|
handleServerCreate(args, server) {
|
|
77
|
-
const [
|
|
78
|
-
|
|
80
|
+
const [options] = args;
|
|
81
|
+
let [, handler] = args;
|
|
82
|
+
if (typeof options === 'function') {
|
|
83
|
+
handler = options;
|
|
84
|
+
}
|
|
85
|
+
this.emitter.emit(HTTP_EVENTS.SERVER_CREATE, handler, server);
|
|
79
86
|
}
|
|
80
87
|
}
|
|
81
88
|
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
Copyright: 2021 Contrast Security, Inc
|
|
3
|
+
Contact: support@contrastsecurity.com
|
|
4
|
+
License: Commercial
|
|
5
|
+
|
|
6
|
+
NOTICE: This Software and the patented inventions embodied within may only be
|
|
7
|
+
used as part of Contrast Security’s commercial offerings. Even though it is
|
|
8
|
+
made available through public repositories, use of this Software is subject to
|
|
9
|
+
the applicable End User Licensing Agreement found at
|
|
10
|
+
https://www.contrastsecurity.com/enduser-terms-0317a or as otherwise agreed
|
|
11
|
+
between Contrast Security and the End User. The Software may not be reverse
|
|
12
|
+
engineered, modified, repackaged, sold, redistributed or otherwise used in a
|
|
13
|
+
way not consistent with the End User License Agreement.
|
|
14
|
+
*/
|
|
15
|
+
'use strict';
|
|
16
|
+
|
|
17
|
+
const { PATCH_TYPES } = require('../../constants');
|
|
18
|
+
const patcher = require('../patcher');
|
|
19
|
+
const HttpFramework = require('./http');
|
|
20
|
+
|
|
21
|
+
/** @typedef {import('../../agent').ContrastAgent} Agent */
|
|
22
|
+
|
|
23
|
+
class Http2Framework extends HttpFramework {
|
|
24
|
+
/**
|
|
25
|
+
* @param {Agent} agent
|
|
26
|
+
*/
|
|
27
|
+
constructor(agent) {
|
|
28
|
+
super(agent, 'http2');
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* @param {import('http2')} http2
|
|
33
|
+
* @returns {import('http2')}
|
|
34
|
+
*/
|
|
35
|
+
onRequire(http2) {
|
|
36
|
+
patcher.patch(http2, 'createServer', {
|
|
37
|
+
name: `${this.id}.createServer`,
|
|
38
|
+
patchType: PATCH_TYPES.FRAMEWORK,
|
|
39
|
+
alwaysRun: true,
|
|
40
|
+
post: ({ args, result }) => this.handleServerCreate(args, result)
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
patcher.patch(http2, 'createSecureServer', {
|
|
44
|
+
name: `${this.id}.createSecureServer`,
|
|
45
|
+
patchType: PATCH_TYPES.FRAMEWORK,
|
|
46
|
+
alwaysRun: true,
|
|
47
|
+
post: ({ args, result }) => this.handleServerCreate(args, result)
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
return http2;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Emits a create event for the new Server instance.
|
|
55
|
+
* @param {any[]} args The arguments passed to the Server constructor
|
|
56
|
+
* @param {import('net').Server} server The http Server instance
|
|
57
|
+
*/
|
|
58
|
+
handleServerCreate(args, server) {
|
|
59
|
+
super.handleServerCreate(args, server);
|
|
60
|
+
|
|
61
|
+
// Since the `Http2Server` class is not exported, we can patch it here after
|
|
62
|
+
// creation.
|
|
63
|
+
// NOTE: could we just patch `net.Server` here and in `http`?
|
|
64
|
+
patcher.patch(server, 'listen', {
|
|
65
|
+
name: `${this.id}.Http2Server.listen`,
|
|
66
|
+
patchType: PATCH_TYPES.FRAMEWORK,
|
|
67
|
+
alwaysRun: true,
|
|
68
|
+
pre: ({ args, obj }) => this.handleServerListen(args, obj)
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
module.exports = Http2Framework;
|
|
@@ -14,9 +14,14 @@ Copyright: 2021 Contrast Security, Inc
|
|
|
14
14
|
*/
|
|
15
15
|
'use strict';
|
|
16
16
|
|
|
17
|
+
const Http = require('./http');
|
|
18
|
+
const Http2 = require('./http2');
|
|
19
|
+
const Hapi16 = require('./hapi16');
|
|
20
|
+
|
|
17
21
|
module.exports = function(agent) {
|
|
18
22
|
// load all the hooks
|
|
19
|
-
new (
|
|
20
|
-
new (
|
|
21
|
-
new (
|
|
23
|
+
new Http(agent);
|
|
24
|
+
new Http(agent, 'https');
|
|
25
|
+
new Http2(agent);
|
|
26
|
+
new Hapi16(agent);
|
|
22
27
|
};
|