@contrast/agent 4.9.1 → 4.10.3

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 (38) 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/bootstrap.js +2 -2
  6. package/lib/assess/propagators/joi/any.js +48 -0
  7. package/lib/assess/propagators/joi/index.js +2 -0
  8. package/lib/assess/propagators/joi/object.js +61 -0
  9. package/lib/assess/propagators/joi/string-base.js +16 -0
  10. package/lib/assess/propagators/mongoose/helpers.js +36 -1
  11. package/lib/assess/propagators/mongoose/index.js +1 -0
  12. package/lib/assess/propagators/mongoose/map.js +19 -31
  13. package/lib/assess/propagators/mongoose/mixed.js +71 -0
  14. package/lib/assess/propagators/mongoose/string.js +8 -0
  15. package/lib/core/arch-components/mysql.js +25 -15
  16. package/lib/core/arch-components/postgres.js +36 -26
  17. package/lib/core/arch-components/util.js +49 -0
  18. package/lib/core/config/options.js +11 -9
  19. package/lib/core/express/index.js +8 -3
  20. package/lib/core/fastify/index.js +2 -1
  21. package/lib/core/hapi/index.js +2 -1
  22. package/lib/core/koa/index.js +9 -1
  23. package/lib/core/logger/debug-logger.js +4 -3
  24. package/lib/core/rewrite/binary-expression.js +1 -2
  25. package/lib/core/rewrite/callees.js +19 -2
  26. package/lib/core/rewrite/catch-clause.js +4 -2
  27. package/lib/core/rewrite/import-declaration.js +71 -0
  28. package/lib/core/rewrite/index.js +10 -7
  29. package/lib/core/rewrite/injections.js +6 -4
  30. package/lib/core/rewrite/rewrite-log.js +5 -8
  31. package/lib/protect/restify/sources.js +35 -0
  32. package/lib/protect/rules/nosqli/nosql-injection-rule.js +30 -16
  33. package/lib/protect/rules/nosqli/nosql-scanner/index.js +1 -1
  34. package/lib/protect/rules/nosqli/nosql-scanner/rethinkdbscanner.js +26 -0
  35. package/lib/protect/sinks/index.js +2 -0
  36. package/lib/protect/sinks/mongodb.js +1 -3
  37. package/lib/protect/sinks/rethinkdb.js +47 -0
  38. package/package.json +23 -15
package/bin/VERSION CHANGED
@@ -1 +1 @@
1
- 2.28.5
1
+ 2.28.12
Binary file
Binary file
Binary file
package/bootstrap.js CHANGED
@@ -1,4 +1,3 @@
1
- #!/usr/bin/env node
2
1
  /**
3
2
  Copyright: 2022 Contrast Security, Inc
4
3
  Contact: support@contrastsecurity.com
@@ -13,6 +12,7 @@ Copyright: 2022 Contrast Security, Inc
13
12
  engineered, modified, repackaged, sold, redistributed or otherwise used in a
14
13
  way not consistent with the End User License Agreement.
15
14
  */
15
+ 'use strict';
16
16
 
17
17
  const startTime = process.hrtime();
18
18
 
@@ -25,7 +25,7 @@ const orig = Module.runMain;
25
25
  * process before invoking the main
26
26
  * script from cli
27
27
  */
28
- Module.runMain = async function(...args) {
28
+ Module.runMain = async function (...args) {
29
29
  const { isMainThread } = require('worker_threads');
30
30
 
31
31
  try {
@@ -0,0 +1,48 @@
1
+ /**
2
+ Copyright: 2022 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
+ const requireHook = require('../../../hooks/require');
16
+ const patcher = require('../../../hooks/patcher');
17
+ const {
18
+ PATCH_TYPES: { ASSESS_PROPAGATOR }
19
+ } = require('../../../constants');
20
+ const tracker = require('../../../tracker');
21
+ const agent = require('../../../agent');
22
+
23
+ requireHook.resolve(
24
+ { name: 'joi', file: 'lib/types/any.js', version: '>=17.0.0' },
25
+ (object) => {
26
+ if (
27
+ !agent.config ||
28
+ (agent.config && !agent.config.agent.trust_custom_validators)
29
+ ) {
30
+ return;
31
+ }
32
+
33
+ patcher.patch(object._definition.rules.custom, 'validate', {
34
+ name: 'joi.any.custom.validate',
35
+ patchType: ASSESS_PROPAGATOR,
36
+ alwaysRun: true,
37
+ post(data) {
38
+ if (data.result && typeof data.result === 'string') {
39
+ tracker.untrack(data.result);
40
+ }
41
+
42
+ if (data.args[0] && typeof data.args[0] === 'string') {
43
+ tracker.untrack(data.args[0]);
44
+ }
45
+ }
46
+ });
47
+ }
48
+ );
@@ -21,4 +21,6 @@ module.exports.handle = function() {
21
21
  require('./string-schema');
22
22
  require('./string-base');
23
23
  require('./expression');
24
+ require('./object');
25
+ require('./any');
24
26
  };
@@ -0,0 +1,61 @@
1
+ /**
2
+ Copyright: 2022 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
+ const requireHook = require('../../../hooks/require');
16
+ const patcher = require('../../../hooks/patcher');
17
+ const {
18
+ PATCH_TYPES: { ASSESS_PROPAGATOR }
19
+ } = require('../../../constants');
20
+ const tracker = require('../../../tracker');
21
+ const agent = require('../../../agent');
22
+
23
+ const traverseObjectAndUntrack = (object, incomingInput, result) => {
24
+ if (object.type === 'object' && object.$_terms.keys) {
25
+ object.$_terms.keys.forEach(({ key, schema }) => {
26
+ traverseObjectAndUntrack(schema, incomingInput[key], result[key]);
27
+ });
28
+ }
29
+
30
+ if (
31
+ object.type === 'string' &&
32
+ Array.isArray(object.$_terms.externals) &&
33
+ object.$_terms.externals.length
34
+ ) {
35
+ tracker.untrack(incomingInput);
36
+ tracker.untrack(result);
37
+ }
38
+ };
39
+
40
+ requireHook.resolve(
41
+ { name: 'joi', file: 'lib/types/object.js', version: '>=17.0.0' },
42
+ (object) => {
43
+ if (
44
+ !agent.config ||
45
+ (agent.config && !agent.config.agent.trust_custom_validators)
46
+ ) {
47
+ return;
48
+ }
49
+
50
+ patcher.patch(object.__proto__, 'validateAsync', {
51
+ name: 'joi.object.validateAsync',
52
+ patchType: ASSESS_PROPAGATOR,
53
+ alwaysRun: true,
54
+ post(data) {
55
+ data.result.then((result) =>
56
+ traverseObjectAndUntrack(data.obj, data.args[0], result)
57
+ );
58
+ }
59
+ });
60
+ }
61
+ );
@@ -24,6 +24,7 @@ const tracker = require('../../../tracker');
24
24
  const { PropagationEvent, Signature, CallContext } = require('../../models');
25
25
  const TagRange = require('../../models/tag-range');
26
26
  const tagRangeUtil = require('../../models/tag-range/util');
27
+ const agent = require('../../../agent');
27
28
 
28
29
  /**
29
30
  * Patch joi.string.validate so that it tags input with string-type-checked if validated
@@ -54,6 +55,21 @@ function instrumentJoiString(string) {
54
55
  }
55
56
  }
56
57
  });
58
+
59
+ if (agent.config.agent.trust_custom_validators) {
60
+ patcher.patch(string.__proto__, 'validateAsync', {
61
+ name: 'joi.string.validateAsync',
62
+ patchType: ASSESS_PROPAGATOR,
63
+ alwaysRun: true,
64
+ post(data) {
65
+ if (!data.obj.$_terms.externals.length) return;
66
+ data.result.then((result) => {
67
+ tracker.untrack(data.args[0]);
68
+ tracker.untrack(result);
69
+ });
70
+ }
71
+ });
72
+ }
57
73
  }
58
74
 
59
75
  requireHook.resolve(
@@ -12,9 +12,44 @@ Copyright: 2022 Contrast Security, Inc
12
12
  engineered, modified, repackaged, sold, redistributed or otherwise used in a
13
13
  way not consistent with the End User License Agreement.
14
14
  */
15
+ const TagRange = require('../../models/tag-range');
16
+ const { CallContext, PropagationEvent, Signature } = require('../../models');
17
+
15
18
  const hasUserDefinedValidator = (data) =>
16
19
  data.obj.validators.some((validator) => validator.type === 'user defined');
17
20
 
21
+ const tagCustomValidatedValues = (values, data, tracker, tagRangeUtil) => {
22
+ for (const value of values) {
23
+ if (typeof value !== 'string') continue;
24
+
25
+ const trackingData = tracker.track(value);
26
+
27
+ if (!trackingData) return;
28
+
29
+ const { props } = trackingData;
30
+ const stringLength = value.length - 1;
31
+
32
+ props.tagRanges = tagRangeUtil.add(
33
+ props.tagRanges,
34
+ new TagRange(0, stringLength, 'custom-validated-nosql-injection')
35
+ );
36
+
37
+ props.tagRanges = tagRangeUtil.add(
38
+ props.tagRanges,
39
+ new TagRange(0, stringLength, 'string-type-checked')
40
+ );
41
+
42
+ props.event = new PropagationEvent({
43
+ context: new CallContext(data),
44
+ signature: new Signature('mongoose.mixed.doValidateSync'),
45
+ tagRanges: props.tagRanges,
46
+ source: 'P',
47
+ target: 'A',
48
+ parents: [props.event]
49
+ });
50
+ }
51
+ };
18
52
  module.exports = {
19
- hasUserDefinedValidator
53
+ hasUserDefinedValidator,
54
+ tagCustomValidatedValues
20
55
  };
@@ -15,4 +15,5 @@ Copyright: 2022 Contrast Security, Inc
15
15
  module.exports.handle = () => {
16
16
  require('./map');
17
17
  require('./string');
18
+ require('./mixed');
18
19
  };
@@ -21,9 +21,11 @@ const tagRangeUtil = require('../../models/tag-range/util');
21
21
  const {
22
22
  PATCH_TYPES: { ASSESS_PROPAGATOR }
23
23
  } = require('../../../constants');
24
- const TagRange = require('../../models/tag-range');
25
- const { CallContext, PropagationEvent, Signature } = require('../../models');
26
- const { hasUserDefinedValidator } = require('./helpers');
24
+ const {
25
+ hasUserDefinedValidator,
26
+ tagCustomValidatedValues
27
+ } = require('./helpers');
28
+ const agent = require('../../../agent');
27
29
 
28
30
  const doValidateSyncPatcher = (SchemaMap) => {
29
31
  patcher.patch(SchemaMap.prototype, 'doValidateSync', {
@@ -31,37 +33,16 @@ const doValidateSyncPatcher = (SchemaMap) => {
31
33
  name: 'mongoose.map.doValidateSync',
32
34
  patchType: ASSESS_PROPAGATOR,
33
35
  post(data) {
34
- if (data.result || data.obj.options.of.name !== 'String') return;
36
+ if (data.result) return;
35
37
 
36
38
  if (!hasUserDefinedValidator(data)) return;
37
39
 
38
- for (const value of data.args[0].values()) {
39
- const trackingData = tracker.track(value);
40
-
41
- if (!trackingData) return;
42
-
43
- const { props } = trackingData;
44
- const stringLength = value.length - 1;
45
-
46
- props.tagRanges = tagRangeUtil.add(
47
- props.tagRanges,
48
- new TagRange(0, stringLength, 'custom-validated-nosql-injection')
49
- );
50
-
51
- props.tagRanges = tagRangeUtil.add(
52
- props.tagRanges,
53
- new TagRange(0, stringLength, 'string-type-checked')
54
- );
55
-
56
- props.event = new PropagationEvent({
57
- context: new CallContext(data),
58
- signature: new Signature('mongoose.map.doValidateSync'),
59
- tagRanges: props.tagRanges,
60
- source: 'P',
61
- target: 'A',
62
- parents: [props.event]
63
- });
64
- }
40
+ tagCustomValidatedValues(
41
+ data.args[0].values(),
42
+ data,
43
+ tracker,
44
+ tagRangeUtil
45
+ );
65
46
  }
66
47
  });
67
48
  };
@@ -69,6 +50,13 @@ const doValidateSyncPatcher = (SchemaMap) => {
69
50
  requireHook.resolve(
70
51
  { name: 'mongoose', file: 'lib/schema/map.js', version: '>=5.0.0' },
71
52
  (SchemaMap) => {
53
+ if (
54
+ !agent.config ||
55
+ (agent.config && !agent.config.agent.trust_custom_validators)
56
+ ) {
57
+ return;
58
+ }
59
+
72
60
  doValidateSyncPatcher(SchemaMap);
73
61
  }
74
62
  );
@@ -0,0 +1,71 @@
1
+ /**
2
+ Copyright: 2022 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 patcher = require('../../../hooks/patcher');
19
+ const requireHook = require('../../../hooks/require');
20
+ const tagRangeUtil = require('../../models/tag-range/util');
21
+ const {
22
+ PATCH_TYPES: { ASSESS_PROPAGATOR }
23
+ } = require('../../../constants');
24
+ const {
25
+ hasUserDefinedValidator,
26
+ tagCustomValidatedValues
27
+ } = require('./helpers');
28
+ const agent = require('../../../agent');
29
+
30
+ const doValidateSyncPatcher = (SchemaMap) => {
31
+ patcher.patch(SchemaMap.prototype, 'doValidateSync', {
32
+ alwaysRun: true,
33
+ name: 'mongoose.mixed.doValidateSync',
34
+ patchType: ASSESS_PROPAGATOR,
35
+ post(data) {
36
+ if (data.result || !hasUserDefinedValidator(data)) return;
37
+
38
+ const input = data.args[0];
39
+ const inputType = typeof input;
40
+
41
+ if (inputType !== 'string' && inputType !== 'object') return;
42
+
43
+ let values;
44
+ if (inputType === 'string') {
45
+ values = [input];
46
+ } else if (Array.isArray(input)) {
47
+ values = input;
48
+ } else if (input instanceof Map) {
49
+ values = input.values();
50
+ } else {
51
+ values = Object.values(input);
52
+ }
53
+
54
+ tagCustomValidatedValues(values, data, tracker, tagRangeUtil);
55
+ }
56
+ });
57
+ };
58
+
59
+ requireHook.resolve(
60
+ { name: 'mongoose', file: 'lib/schema/mixed.js', version: '>=5.0.0' },
61
+ (SchemaMap) => {
62
+ if (
63
+ !agent.config ||
64
+ (agent.config && !agent.config.agent.trust_custom_validators)
65
+ ) {
66
+ return;
67
+ }
68
+
69
+ doValidateSyncPatcher(SchemaMap);
70
+ }
71
+ );
@@ -24,6 +24,7 @@ const {
24
24
  const TagRange = require('../../models/tag-range');
25
25
  const { CallContext, PropagationEvent, Signature } = require('../../models');
26
26
  const { hasUserDefinedValidator } = require('./helpers');
27
+ const agent = require('../../../agent');
27
28
 
28
29
  const enumPatcher = (SchemaString) => {
29
30
  patcher.patch(SchemaString.prototype, 'enum', {
@@ -98,6 +99,13 @@ const doValidateSyncPatcher = (SchemaString) => {
98
99
  requireHook.resolve(
99
100
  { name: 'mongoose', file: 'lib/schema/string.js', version: '>=5.0.0' },
100
101
  (SchemaString) => {
102
+ if (
103
+ !agent.config ||
104
+ (agent.config && !agent.config.agent.trust_custom_validators)
105
+ ) {
106
+ return;
107
+ }
108
+
101
109
  enumPatcher(SchemaString);
102
110
  doValidateSyncPatcher(SchemaString);
103
111
  }
@@ -19,6 +19,7 @@ const ModuleHook = require('../../hooks/require');
19
19
  const agentEmitter = require('../../agent-emitter');
20
20
  const { PATCH_TYPES } = require('../../constants');
21
21
  const logger = require('../logger')('contrast:arch-component');
22
+ const waitToConnect = require('./util');
22
23
 
23
24
  ModuleHook.resolve(
24
25
  { name: 'mysql', file: 'lib/Connection.js' },
@@ -28,22 +29,31 @@ ModuleHook.resolve(
28
29
  patchType: PATCH_TYPES.ARCH_COMPONENT,
29
30
  alwaysRun: true,
30
31
  post(wrapCtx) {
31
- try {
32
- let url = 'mysql://';
33
- if (this.config.socketPath) {
34
- url += this.config.socketPath;
35
- } else {
36
- url += `${this.config.host}`;
37
- }
38
- agentEmitter.emit('architectureComponent', {
39
- vendor: 'MySQL',
40
- url: new URL(url).toString(),
41
- remoteHost: '',
42
- remotePort: !this.config.socketPath ? this.config.port : -1
32
+ waitToConnect(wrapCtx)
33
+ .then(() => {
34
+ try {
35
+ let url = 'mysql://';
36
+ if (this.config.socketPath) {
37
+ url += this.config.socketPath;
38
+ } else {
39
+ url += `${this.config.host}`;
40
+ }
41
+ agentEmitter.emit('architectureComponent', {
42
+ vendor: 'MySQL',
43
+ url: new URL(url).toString(),
44
+ remoteHost: '',
45
+ remotePort: !this.config.socketPath ? this.config.port : -1
46
+ });
47
+ } catch (err) {
48
+ logger.warn(
49
+ 'unable to report MySQL architecture component\n',
50
+ err
51
+ );
52
+ }
53
+ })
54
+ .catch((err) => {
55
+ logger.warn('unable to report MySQL architecture component\n', err);
43
56
  });
44
- } catch (err) {
45
- logger.warn('unable to report MySQL architecture component\n', err);
46
- }
47
57
  }
48
58
  });
49
59
  }
@@ -18,6 +18,7 @@ const ModuleHook = require('../../hooks/require');
18
18
  const agentEmitter = require('../../agent-emitter');
19
19
  const { PATCH_TYPES } = require('../../constants');
20
20
  const logger = require('../logger')('contrast:arch-component');
21
+ const waitToConnect = require('./util');
21
22
 
22
23
  ModuleHook.resolve({ name: 'pg', file: 'lib/client.js' }, (pgClient) =>
23
24
  patcher.patch(pgClient, {
@@ -25,37 +26,46 @@ ModuleHook.resolve({ name: 'pg', file: 'lib/client.js' }, (pgClient) =>
25
26
  patchType: PATCH_TYPES.ARCH_COMPONENT,
26
27
  alwaysRun: true,
27
28
  post(wrapCtx) {
28
- try {
29
- const {
30
- host = process.env.PGHOST,
31
- port = process.env.PGPORT
32
- } = wrapCtx.result;
29
+ waitToConnect(wrapCtx)
30
+ .then(() => {
31
+ try {
32
+ const {
33
+ host = process.env.PGHOST,
34
+ port = process.env.PGPORT
35
+ } = wrapCtx.result;
33
36
 
34
- if (!host) {
35
- return;
36
- }
37
+ if (!host) {
38
+ return;
39
+ }
37
40
 
38
- let url = host;
41
+ let url = host;
39
42
 
40
- // build protocol and port into url prior to parsing
41
- if (url.indexOf('://') === -1) {
42
- url = `postgresql://${url}`;
43
- }
44
- if (port !== undefined) {
45
- url = `${url}:${port}`;
46
- }
43
+ // build protocol and port into url prior to parsing
44
+ if (url.indexOf('://') === -1) {
45
+ url = `postgresql://${url}`;
46
+ }
47
+ if (port !== undefined) {
48
+ url = `${url}:${port}`;
49
+ }
47
50
 
48
- agentEmitter.emit('architectureComponent', {
49
- vendor: 'PostgreSQL',
50
- remotePort: port || 0,
51
- url: new URL(url).toString()
51
+ agentEmitter.emit('architectureComponent', {
52
+ vendor: 'PostgreSQL',
53
+ remotePort: port || 0,
54
+ url: new URL(url).toString()
55
+ });
56
+ } catch (err) {
57
+ logger.warn(
58
+ 'unable to report PostgreSQL architecture component\n%o',
59
+ err
60
+ );
61
+ }
62
+ })
63
+ .catch((err) => {
64
+ logger.warn(
65
+ 'unable to report PostgreSQL architecture component\n%o',
66
+ err
67
+ );
52
68
  });
53
- } catch (err) {
54
- logger.warn(
55
- 'unable to report PostgreSQL architecture component\n%o',
56
- err
57
- );
58
- }
59
69
  }
60
70
  })
61
71
  );
@@ -0,0 +1,49 @@
1
+ /**
2
+ Copyright: 2022 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
+ const MYSQL = 'mysql.connect.arch_component';
16
+ const POSTGRES = 'pg.Client.arch_component';
17
+
18
+ module.exports = function waitToConnect(ctx, count = 0) {
19
+ return new Promise((resolve, reject) => {
20
+ const maxAttempts = 10 * 60; // i.e., 1 min.
21
+ const checkConnection = setInterval(
22
+ function(ctx, resolve, reject) {
23
+ if (count >= maxAttempts) {
24
+ clearInterval(checkConnection);
25
+ reject();
26
+ }
27
+ switch (ctx.name) {
28
+ case MYSQL:
29
+ if (ctx.obj.state === 'authenticated') {
30
+ clearInterval(checkConnection);
31
+ resolve();
32
+ }
33
+ break;
34
+ case POSTGRES:
35
+ if (ctx.result._connected) {
36
+ clearInterval(checkConnection);
37
+ resolve();
38
+ }
39
+ break;
40
+ }
41
+ count++;
42
+ },
43
+ 100,
44
+ ctx,
45
+ resolve,
46
+ reject
47
+ );
48
+ });
49
+ };
@@ -487,6 +487,12 @@ const agent = [
487
487
  desc:
488
488
  'set limit for stack trace size (larger limits will improve accuracy but increase memory usage)'
489
489
  },
490
+ {
491
+ name: 'agent.trust_custom_validators',
492
+ arg: '<trust-custom-validators>',
493
+ default: false,
494
+ desc: `trust incoming strings when they pass custom validators (Mongoose, Joi)`
495
+ },
490
496
  {
491
497
  name: 'agent.traverse_and_track',
492
498
  arg: '<traverse-and-track>',
@@ -977,11 +983,11 @@ if (process.env.CONTRAST_DEV) {
977
983
  const sails = [
978
984
  {
979
985
  name: 'pathToSails',
980
- arg: '<path>',
986
+ arg: '<path>'
981
987
  },
982
988
  {
983
989
  name: 'gdsrc',
984
- arg: '<path>',
990
+ arg: '<path>'
985
991
  }
986
992
  ];
987
993
 
@@ -1030,16 +1036,12 @@ options.forEach((option) => {
1030
1036
  // The agent doesn't need to do anything with these options. It just needs to not
1031
1037
  // throw an error when it encounters them but we also don't need them displayed on
1032
1038
  // the agent's config option list. The newest version of Commander lets us do exactly this.
1033
- // This is structured so that if anything like this is discovered again, they can be
1039
+ // This is structured so that if anything like this is discovered again, they can be
1034
1040
  // added in easily.
1035
- const hiddenOptions = [].concat(
1036
- sails
1037
- )
1041
+ const hiddenOptions = [].concat(sails);
1038
1042
 
1039
1043
  hiddenOptions.forEach((option) => {
1040
- program.addOption(
1041
- new Option(`--${option.name} ${option.arg}`).hideHelp()
1042
- )
1044
+ program.addOption(new Option(`--${option.name} ${option.arg}`).hideHelp());
1043
1045
  });
1044
1046
 
1045
1047
  function getDefault(optionName) {
@@ -397,6 +397,9 @@ class ExpressFramework {
397
397
  req[LAYER_STACK].pop();
398
398
  }
399
399
  });
400
+ if (req.query) {
401
+ decorateRequest({ query: req.query });
402
+ }
400
403
  const params = new Object(this.params);
401
404
  if (Object.keys(params).length) {
402
405
  agentEmitter.emit(
@@ -419,12 +422,14 @@ class ExpressFramework {
419
422
 
420
423
  Whatever the core issue is, it doesn't appear to have any effects
421
424
  elsewhere in any of our Express/Kraken framework support.
422
-
423
- BODY_PARSED event is emitted to support Sails framework
424
425
  */
425
426
  if (req.body) {
426
427
  decorateRequest({ body: req.body });
427
- agentEmitter.emit(EVENTS.BODY_PARSED, req, res, req.body);
428
+
429
+ // BODY_PARSED event is emitted to support Sails framework
430
+ if (req._sails) {
431
+ agentEmitter.emit(EVENTS.BODY_PARSED, req, res, req.body);
432
+ }
428
433
  }
429
434
  }
430
435
  });
@@ -154,7 +154,8 @@ class FastifyCore {
154
154
  agentEmitter.emit(constants.EVENTS.PRE_VALIDATION, ...data);
155
155
  decorateRequest({
156
156
  body: request.body,
157
- parameters: request.params
157
+ parameters: request.params,
158
+ query: request.query
158
159
  });
159
160
  done();
160
161
  }