@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.
Files changed (157) hide show
  1. package/bin/VERSION +1 -1
  2. package/bin/linux/contrast-service +0 -0
  3. package/bin/mac/contrast-service +0 -0
  4. package/bin/windows/contrast-service.exe +0 -0
  5. package/lib/assess/membrane/source-membrane.js +4 -18
  6. package/lib/assess/policy/propagators.json +11 -21
  7. package/lib/assess/policy/rules.json +5 -0
  8. package/lib/assess/policy/signatures.json +15 -0
  9. package/lib/assess/propagators/dustjs/escape-html.js +22 -0
  10. package/lib/assess/propagators/dustjs/escape-js.js +22 -0
  11. package/lib/assess/propagators/encode-uri/encode-uri-component.js +22 -0
  12. package/lib/assess/propagators/encode-uri/encode-uri.js +22 -0
  13. package/lib/assess/propagators/index.js +0 -2
  14. package/lib/assess/propagators/joi/values.js +26 -11
  15. package/lib/assess/propagators/mustache/escape.js +22 -0
  16. package/lib/assess/propagators/path/common.js +155 -46
  17. package/lib/assess/propagators/path/join.js +5 -1
  18. package/lib/assess/propagators/path/normalize.js +1 -2
  19. package/lib/assess/propagators/path/resolve.js +11 -2
  20. package/lib/assess/propagators/template-escape.js +84 -0
  21. package/lib/assess/propagators/templates.js +2 -3
  22. package/lib/assess/sinks/dustjs-linkedin-xss.js +131 -0
  23. package/lib/core/arch-components/dynamodb.js +1 -2
  24. package/lib/core/arch-components/dynamodbv3.js +44 -0
  25. package/lib/core/arch-components/index.js +1 -0
  26. package/lib/core/arch-components/rethinkdb.js +53 -0
  27. package/lib/core/async-storage/hooks/bluebird.js +20 -0
  28. package/lib/core/config/options.js +2 -1
  29. package/lib/core/stacktrace.js +3 -4
  30. package/lib/feature-set.js +2 -1
  31. package/lib/hooks/frameworks/base.js +8 -2
  32. package/lib/hooks/frameworks/http.js +23 -16
  33. package/lib/hooks/frameworks/http2.js +73 -0
  34. package/lib/hooks/frameworks/index.js +8 -3
  35. package/lib/hooks/http.js +112 -128
  36. package/lib/hooks/patcher.js +69 -48
  37. package/lib/hooks/require.js +16 -22
  38. package/lib/instrumentation.js +0 -3
  39. package/lib/protect/rules/cmd-injection-command-backdoors/backdoor-detector.js +3 -3
  40. package/lib/protect/rules/signatures/reflected-xss/helpers/function-call.js +1 -1
  41. package/lib/protect/rules/xss/helpers/function-call.js +1 -1
  42. package/lib/util/clean-stack.js +1 -1
  43. package/lib/util/clean-string/brackets.js +3 -3
  44. package/lib/util/ip-analyzer.js +1 -1
  45. package/lib/util/some.js +27 -0
  46. package/lib/util/source-map.js +1 -1
  47. package/lib/util/xml-analyzer/external-entity-finder.js +1 -1
  48. package/package.json +14 -16
  49. package/lib/hooks/frameworks/https.js +0 -42
  50. package/node_modules/bindings/LICENSE.md +0 -22
  51. package/node_modules/bindings/README.md +0 -98
  52. package/node_modules/bindings/bindings.js +0 -221
  53. package/node_modules/bindings/package.json +0 -32
  54. package/node_modules/file-uri-to-path/.npmignore +0 -1
  55. package/node_modules/file-uri-to-path/.travis.yml +0 -30
  56. package/node_modules/file-uri-to-path/History.md +0 -21
  57. package/node_modules/file-uri-to-path/LICENSE +0 -20
  58. package/node_modules/file-uri-to-path/README.md +0 -74
  59. package/node_modules/file-uri-to-path/index.d.ts +0 -2
  60. package/node_modules/file-uri-to-path/index.js +0 -66
  61. package/node_modules/file-uri-to-path/package.json +0 -36
  62. package/node_modules/file-uri-to-path/test/test.js +0 -24
  63. package/node_modules/file-uri-to-path/test/tests.json +0 -13
  64. package/node_modules/glossy/LICENSE +0 -19
  65. package/node_modules/glossy/README.md +0 -129
  66. package/node_modules/glossy/index.js +0 -12
  67. package/node_modules/glossy/lib/glossy/parse.js +0 -520
  68. package/node_modules/glossy/lib/glossy/produce.js +0 -459
  69. package/node_modules/glossy/package.json +0 -47
  70. package/node_modules/glossy/test/decide.js +0 -7
  71. package/node_modules/glossy/test/decode_pri.js +0 -24
  72. package/node_modules/glossy/test/parse_3164.js +0 -104
  73. package/node_modules/glossy/test/parse_5424.js +0 -106
  74. package/node_modules/glossy/test/parse_5848.js +0 -40
  75. package/node_modules/glossy/test/parse_8601.js +0 -14
  76. package/node_modules/glossy/test/parse_rfc3339.js +0 -9
  77. package/node_modules/glossy/test/produce.js +0 -162
  78. package/node_modules/glossy/test/runner.js +0 -40
  79. package/node_modules/glossy/test/structure_data.js +0 -24
  80. package/node_modules/nan/CHANGELOG.md +0 -537
  81. package/node_modules/nan/LICENSE.md +0 -13
  82. package/node_modules/nan/README.md +0 -455
  83. package/node_modules/nan/doc/asyncworker.md +0 -146
  84. package/node_modules/nan/doc/buffers.md +0 -54
  85. package/node_modules/nan/doc/callback.md +0 -76
  86. package/node_modules/nan/doc/converters.md +0 -41
  87. package/node_modules/nan/doc/errors.md +0 -226
  88. package/node_modules/nan/doc/json.md +0 -62
  89. package/node_modules/nan/doc/maybe_types.md +0 -583
  90. package/node_modules/nan/doc/methods.md +0 -664
  91. package/node_modules/nan/doc/new.md +0 -147
  92. package/node_modules/nan/doc/node_misc.md +0 -123
  93. package/node_modules/nan/doc/object_wrappers.md +0 -263
  94. package/node_modules/nan/doc/persistent.md +0 -296
  95. package/node_modules/nan/doc/scopes.md +0 -73
  96. package/node_modules/nan/doc/script.md +0 -38
  97. package/node_modules/nan/doc/string_bytes.md +0 -62
  98. package/node_modules/nan/doc/v8_internals.md +0 -199
  99. package/node_modules/nan/doc/v8_misc.md +0 -85
  100. package/node_modules/nan/include_dirs.js +0 -1
  101. package/node_modules/nan/nan.h +0 -2898
  102. package/node_modules/nan/nan_callbacks.h +0 -88
  103. package/node_modules/nan/nan_callbacks_12_inl.h +0 -514
  104. package/node_modules/nan/nan_callbacks_pre_12_inl.h +0 -520
  105. package/node_modules/nan/nan_converters.h +0 -72
  106. package/node_modules/nan/nan_converters_43_inl.h +0 -68
  107. package/node_modules/nan/nan_converters_pre_43_inl.h +0 -42
  108. package/node_modules/nan/nan_define_own_property_helper.h +0 -29
  109. package/node_modules/nan/nan_implementation_12_inl.h +0 -430
  110. package/node_modules/nan/nan_implementation_pre_12_inl.h +0 -263
  111. package/node_modules/nan/nan_json.h +0 -166
  112. package/node_modules/nan/nan_maybe_43_inl.h +0 -356
  113. package/node_modules/nan/nan_maybe_pre_43_inl.h +0 -268
  114. package/node_modules/nan/nan_new.h +0 -340
  115. package/node_modules/nan/nan_object_wrap.h +0 -156
  116. package/node_modules/nan/nan_persistent_12_inl.h +0 -132
  117. package/node_modules/nan/nan_persistent_pre_12_inl.h +0 -242
  118. package/node_modules/nan/nan_private.h +0 -73
  119. package/node_modules/nan/nan_string_bytes.h +0 -305
  120. package/node_modules/nan/nan_typedarray_contents.h +0 -96
  121. package/node_modules/nan/nan_weak.h +0 -437
  122. package/node_modules/nan/package.json +0 -41
  123. package/node_modules/nan/tools/1to2.js +0 -412
  124. package/node_modules/nan/tools/README.md +0 -14
  125. package/node_modules/nan/tools/package.json +0 -19
  126. package/node_modules/unix-dgram/LICENSE +0 -13
  127. package/node_modules/unix-dgram/README.md +0 -107
  128. package/node_modules/unix-dgram/binding.gyp +0 -20
  129. package/node_modules/unix-dgram/build/Makefile +0 -324
  130. package/node_modules/unix-dgram/build/Release/.deps/Release/obj.target/unix_dgram/src/unix_dgram.o.d +0 -58
  131. package/node_modules/unix-dgram/build/Release/.deps/Release/obj.target/unix_dgram.node.d +0 -1
  132. package/node_modules/unix-dgram/build/Release/.deps/Release/unix_dgram.node.d +0 -1
  133. package/node_modules/unix-dgram/build/Release/obj.target/unix_dgram/src/unix_dgram.o +0 -0
  134. package/node_modules/unix-dgram/build/Release/obj.target/unix_dgram.node +0 -0
  135. package/node_modules/unix-dgram/build/Release/unix_dgram.node +0 -0
  136. package/node_modules/unix-dgram/build/binding.Makefile +0 -6
  137. package/node_modules/unix-dgram/build/config.gypi +0 -213
  138. package/node_modules/unix-dgram/build/unix_dgram.target.mk +0 -159
  139. package/node_modules/unix-dgram/lib/unix_dgram.js +0 -168
  140. package/node_modules/unix-dgram/package.json +0 -36
  141. package/node_modules/unix-dgram/src/unix_dgram.cc +0 -404
  142. package/node_modules/unix-dgram/src/win_dummy.cc +0 -7
  143. package/node_modules/unix-dgram/test/test-connect-callback.js +0 -68
  144. package/node_modules/unix-dgram/test/test-connect.js +0 -53
  145. package/node_modules/unix-dgram/test/test-dgram-unix.js +0 -58
  146. package/node_modules/unix-dgram/test/test-send-error.js +0 -26
  147. package/node_modules/winston-syslog/.eslintrc +0 -7
  148. package/node_modules/winston-syslog/.travis.yml +0 -14
  149. package/node_modules/winston-syslog/CHANGELOG.md +0 -9
  150. package/node_modules/winston-syslog/LICENSE +0 -20
  151. package/node_modules/winston-syslog/README.md +0 -135
  152. package/node_modules/winston-syslog/lib/utils.js +0 -26
  153. package/node_modules/winston-syslog/lib/winston-syslog.js +0 -385
  154. package/node_modules/winston-syslog/package.json +0 -56
  155. package/node_modules/winston-syslog/test/format-test.js +0 -122
  156. package/node_modules/winston-syslog/test/syslog-test.js +0 -95
  157. 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
- resultMeta.offset = isAbsolute ? 0 : process.cwd().length;
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({ data, resultMeta, win32: os === 'win32' });
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 = require('../../core/rewrite/injections').get(
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 = _.get(this, '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
+ });
@@ -17,3 +17,4 @@ require('./mysql');
17
17
  require('./sqlite3');
18
18
  require('./postgres');
19
19
  require('./dynamodb');
20
+ require('./dynamodbv3');
@@ -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: 'set limit for stack trace size'
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',
@@ -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 = 25;
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();
@@ -160,7 +160,8 @@ class FeatureSet {
160
160
  );
161
161
 
162
162
  return disabledConfig
163
- .split(/\s*,\s*/)
163
+ .split(',')
164
+ .map((c) => c.trim())
164
165
  .some((disabledId) => id === disabledId);
165
166
  }
166
167
 
@@ -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
- // sets options
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 {String}
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
- class HttpFramework extends BaseFramework {
23
- constructor(agent, id = 'http') {
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
- * Initialization logic.
27
+ * @param {Agent} agent
28
+ * @param {string} id
31
29
  */
32
- init() {
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 {*[]} args The arguments passed to the Server constructor
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 [callback] = args;
78
- this.emitter.emit(HTTP_EVENTS.SERVER_CREATE, callback, server);
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 (require('./http'))(agent);
20
- new (require('./https'))(agent);
21
- new (require('./hapi16'))(agent);
23
+ new Http(agent);
24
+ new Http(agent, 'https');
25
+ new Http2(agent);
26
+ new Hapi16(agent);
22
27
  };