@contrast/assess 1.40.0 → 1.42.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 (167) hide show
  1. package/lib/crypto-analysis/install/crypto.js +4 -5
  2. package/lib/crypto-analysis/install/crypto.test.js +1 -1
  3. package/lib/crypto-analysis/install/math.js +2 -4
  4. package/lib/dataflow/propagation/install/JSON/parse.js +2 -3
  5. package/lib/dataflow/propagation/install/JSON/stringify.js +3 -4
  6. package/lib/dataflow/propagation/install/array-prototype-join.js +2 -3
  7. package/lib/dataflow/propagation/install/buffer.js +3 -4
  8. package/lib/dataflow/propagation/install/contrast-methods/add.js +2 -3
  9. package/lib/dataflow/propagation/install/contrast-methods/number.js +2 -3
  10. package/lib/dataflow/propagation/install/contrast-methods/string.js +2 -3
  11. package/lib/dataflow/propagation/install/contrast-methods/tag.js +2 -3
  12. package/lib/dataflow/propagation/install/decode-uri-component.js +2 -3
  13. package/lib/dataflow/propagation/install/ejs/escape-xml.js +3 -4
  14. package/lib/dataflow/propagation/install/ejs/template.js +3 -4
  15. package/lib/dataflow/propagation/install/ejs/template.test.js +1 -1
  16. package/lib/dataflow/propagation/install/encode-uri.js +2 -3
  17. package/lib/dataflow/propagation/install/escape-html.js +3 -4
  18. package/lib/dataflow/propagation/install/escape.js +2 -3
  19. package/lib/dataflow/propagation/install/fastify-send.js +3 -3
  20. package/lib/dataflow/propagation/install/fastify-send.test.js +1 -3
  21. package/lib/dataflow/propagation/install/handlebars-utils-escape-expression.js +3 -4
  22. package/lib/dataflow/propagation/install/isnumeric-0.js +1 -1
  23. package/lib/dataflow/propagation/install/joi/any.js +1 -1
  24. package/lib/dataflow/propagation/install/joi/any.test.js +1 -1
  25. package/lib/dataflow/propagation/install/joi/array.test.js +5 -5
  26. package/lib/dataflow/propagation/install/joi/boolean.js +3 -3
  27. package/lib/dataflow/propagation/install/joi/boolean.test.js +1 -1
  28. package/lib/dataflow/propagation/install/joi/expression.js +3 -3
  29. package/lib/dataflow/propagation/install/joi/expression.test.js +1 -1
  30. package/lib/dataflow/propagation/install/joi/index.js +3 -3
  31. package/lib/dataflow/propagation/install/joi/keys.js +3 -3
  32. package/lib/dataflow/propagation/install/joi/number.js +3 -3
  33. package/lib/dataflow/propagation/install/joi/number.test.js +1 -1
  34. package/lib/dataflow/propagation/install/joi/object.js +1 -1
  35. package/lib/dataflow/propagation/install/joi/object.test.js +1 -1
  36. package/lib/dataflow/propagation/install/joi/ref.test.js +4 -4
  37. package/lib/dataflow/propagation/install/joi/string-schema.js +4 -4
  38. package/lib/dataflow/propagation/install/joi/string-schema.test.js +4 -4
  39. package/lib/dataflow/propagation/install/joi/values.js +3 -3
  40. package/lib/dataflow/propagation/install/mongoose/schema-map.js +4 -4
  41. package/lib/dataflow/propagation/install/mongoose/schema-mixed.js +4 -4
  42. package/lib/dataflow/propagation/install/mongoose/schema-string.js +4 -4
  43. package/lib/dataflow/propagation/install/mustache-escape.js +3 -4
  44. package/lib/dataflow/propagation/install/mustache-escape.test.js +1 -1
  45. package/lib/dataflow/propagation/install/mysql-connection-escape.js +22 -14
  46. package/lib/dataflow/propagation/install/mysql-connection-escape.test.js +1 -1
  47. package/lib/dataflow/propagation/install/parse-int.js +2 -3
  48. package/lib/dataflow/propagation/install/path/basename.js +3 -4
  49. package/lib/dataflow/propagation/install/path/dirname.js +3 -4
  50. package/lib/dataflow/propagation/install/path/extname.js +3 -4
  51. package/lib/dataflow/propagation/install/path/format.js +3 -4
  52. package/lib/dataflow/propagation/install/path/index.test.js +1 -1
  53. package/lib/dataflow/propagation/install/path/join-and-resolve.js +3 -4
  54. package/lib/dataflow/propagation/install/path/normalize.js +4 -5
  55. package/lib/dataflow/propagation/install/path/parse.js +3 -4
  56. package/lib/dataflow/propagation/install/path/relative.js +4 -5
  57. package/lib/dataflow/propagation/install/path/toNamespacedPath.js +3 -4
  58. package/lib/dataflow/propagation/install/pug/index.js +3 -4
  59. package/lib/dataflow/propagation/install/pug-runtime-escape.js +3 -4
  60. package/lib/dataflow/propagation/install/querystring/escape.js +3 -4
  61. package/lib/dataflow/propagation/install/querystring/escape.test.js +1 -1
  62. package/lib/dataflow/propagation/install/querystring/parse.js +3 -4
  63. package/lib/dataflow/propagation/install/querystring/parse.test.js +1 -1
  64. package/lib/dataflow/propagation/install/querystring/stringify.js +3 -4
  65. package/lib/dataflow/propagation/install/querystring/stringify.test.js +1 -1
  66. package/lib/dataflow/propagation/install/reg-exp-prototype-exec.js +2 -3
  67. package/lib/dataflow/propagation/install/send.js +3 -3
  68. package/lib/dataflow/propagation/install/sequelize/query-generator.js +3 -3
  69. package/lib/dataflow/propagation/install/sequelize/query-generator.test.js +2 -1
  70. package/lib/dataflow/propagation/install/sequelize/sql-string.js +5 -5
  71. package/lib/dataflow/propagation/install/sql-template-strings.js +3 -3
  72. package/lib/dataflow/propagation/install/string/concat.js +2 -3
  73. package/lib/dataflow/propagation/install/string/format-methods.js +2 -3
  74. package/lib/dataflow/propagation/install/string/html-methods.js +3 -4
  75. package/lib/dataflow/propagation/install/string/match-all.js +2 -3
  76. package/lib/dataflow/propagation/install/string/match.js +2 -3
  77. package/lib/dataflow/propagation/install/string/replace.js +2 -3
  78. package/lib/dataflow/propagation/install/string/slice.js +2 -3
  79. package/lib/dataflow/propagation/install/string/split.js +2 -3
  80. package/lib/dataflow/propagation/install/string/substring.js +2 -3
  81. package/lib/dataflow/propagation/install/string/trim.js +2 -3
  82. package/lib/dataflow/propagation/install/unescape.js +2 -3
  83. package/lib/dataflow/propagation/install/url/domain-parsers.js +3 -4
  84. package/lib/dataflow/propagation/install/url/parse.js +3 -4
  85. package/lib/dataflow/propagation/install/url/parse.test.js +2 -2
  86. package/lib/dataflow/propagation/install/url/searchParams.js +3 -4
  87. package/lib/dataflow/propagation/install/url/url.js +3 -4
  88. package/lib/dataflow/propagation/install/util-format.js +3 -4
  89. package/lib/dataflow/propagation/install/validator/hooks.js +9 -9
  90. package/lib/dataflow/sinks/install/child-process.js +5 -6
  91. package/lib/dataflow/sinks/install/eval.js +2 -3
  92. package/lib/dataflow/sinks/install/express/reflected-xss.js +3 -4
  93. package/lib/dataflow/sinks/install/express/unvalidated-redirect.js +3 -4
  94. package/lib/dataflow/sinks/install/fastify/unvalidated-redirect.js +3 -4
  95. package/lib/dataflow/sinks/install/fs.js +4 -5
  96. package/lib/dataflow/sinks/install/fs.test.js +2 -2
  97. package/lib/dataflow/sinks/install/function.js +2 -3
  98. package/lib/dataflow/sinks/install/hapi/unvalidated-redirect.js +3 -4
  99. package/lib/dataflow/sinks/install/http/request.js +3 -4
  100. package/lib/dataflow/sinks/install/http/request.test.js +2 -2
  101. package/lib/dataflow/sinks/install/http/server-response.js +5 -6
  102. package/lib/dataflow/sinks/install/http/server-response.test.js +3 -3
  103. package/lib/dataflow/sinks/install/koa/unvalidated-redirect.js +3 -4
  104. package/lib/dataflow/sinks/install/libxmljs.js +4 -5
  105. package/lib/dataflow/sinks/install/libxmljs.test.js +2 -2
  106. package/lib/dataflow/sinks/install/marsdb.js +3 -4
  107. package/lib/dataflow/sinks/install/marsdb.test.js +3 -3
  108. package/lib/dataflow/sinks/install/mongodb.js +3 -4
  109. package/lib/dataflow/sinks/install/mongodb.test.js +2 -6
  110. package/lib/dataflow/sinks/install/mssql.js +4 -5
  111. package/lib/dataflow/sinks/install/mssql.test.js +2 -2
  112. package/lib/dataflow/sinks/install/mysql.js +4 -5
  113. package/lib/dataflow/sinks/install/mysql.test.js +2 -11
  114. package/lib/dataflow/sinks/install/node-serialize.js +3 -4
  115. package/lib/dataflow/sinks/install/node-serialize.test.js +1 -3
  116. package/lib/dataflow/sinks/install/postgres.js +5 -6
  117. package/lib/dataflow/sinks/install/postgres.test.js +3 -9
  118. package/lib/dataflow/sinks/install/restify.js +3 -4
  119. package/lib/dataflow/sinks/install/restify.test.js +3 -5
  120. package/lib/dataflow/sinks/install/sequelize.js +3 -4
  121. package/lib/dataflow/sinks/install/sqlite3.js +3 -4
  122. package/lib/dataflow/sinks/install/vm.js +3 -4
  123. package/lib/dataflow/sources/install/body-parser1.js +2 -4
  124. package/lib/dataflow/sources/install/body-parser1.test.js +4 -8
  125. package/lib/dataflow/sources/install/busboy.js +3 -4
  126. package/lib/dataflow/sources/install/busboy.test.js +2 -2
  127. package/lib/dataflow/sources/install/cookie-parser1.js +2 -4
  128. package/lib/dataflow/sources/install/cookie-parser1.test.js +2 -4
  129. package/lib/dataflow/sources/install/express/params.js +56 -38
  130. package/lib/dataflow/sources/install/express/params.test.js +80 -73
  131. package/lib/dataflow/sources/install/express/parsedUrl.js +45 -29
  132. package/lib/dataflow/sources/install/express/parsedUrl.test.js +71 -29
  133. package/lib/dataflow/sources/install/fastify/fastify.js +2 -3
  134. package/lib/dataflow/sources/install/fastify/fastify.test.js +3 -6
  135. package/lib/dataflow/sources/install/formidable1.js +2 -3
  136. package/lib/dataflow/sources/install/hapi/hapi.js +1 -2
  137. package/lib/dataflow/sources/install/http.js +2 -3
  138. package/lib/dataflow/sources/install/http.test.js +2 -2
  139. package/lib/dataflow/sources/install/koa/koa-bodyparsers.js +3 -5
  140. package/lib/dataflow/sources/install/koa/koa-multer.js +3 -4
  141. package/lib/dataflow/sources/install/koa/koa-multer.test.js +1 -1
  142. package/lib/dataflow/sources/install/koa/koa-routers.js +3 -4
  143. package/lib/dataflow/sources/install/koa/koa2.js +2 -4
  144. package/lib/dataflow/sources/install/multer1.js +2 -3
  145. package/lib/dataflow/sources/install/multer1.test.js +1 -3
  146. package/lib/dataflow/sources/install/qs6.js +2 -4
  147. package/lib/dataflow/sources/install/querystring.js +2 -3
  148. package/lib/dataflow/sources/install/restify/fieldedTextBodyParser.js +2 -3
  149. package/lib/dataflow/sources/install/restify/fieldedTextBodyParser.test.js +1 -1
  150. package/lib/dataflow/sources/install/restify/jsonBodyParser.js +2 -3
  151. package/lib/dataflow/sources/install/restify/jsonBodyParser.test.js +1 -1
  152. package/lib/dataflow/sources/install/restify/router.js +2 -4
  153. package/lib/dataflow/sources/install/restify/router.test.js +4 -6
  154. package/lib/get-source-context.js +77 -37
  155. package/lib/get-source-context.test.js +106 -53
  156. package/lib/index.d.ts +3 -9
  157. package/lib/response-scanning/install/http.js +3 -3
  158. package/lib/response-scanning/install/http.test.js +2 -2
  159. package/lib/session-configuration/install/express-session.js +1 -1
  160. package/lib/session-configuration/install/express-session.test.js +1 -3
  161. package/lib/session-configuration/install/fastify-cookie.js +1 -1
  162. package/lib/session-configuration/install/fastify-cookie.test.js +1 -3
  163. package/lib/session-configuration/install/koa.js +1 -1
  164. package/lib/session-configuration/install/koa.test.js +1 -1
  165. package/package.json +11 -11
  166. package/lib/constants.js +0 -26
  167. package/lib/dataflow/sinks/install/fs-original.js +0 -170
@@ -28,15 +28,9 @@ describe('assess dataflow sinks postgres', function () {
28
28
  reportFindings = sinon.stub(core.assess.dataflow.sinks, 'reportFindings');
29
29
  reportSafePositive = sinon.stub(core.assess.dataflow.sinks, 'reportSafePositive');
30
30
 
31
- core.depHooks.resolve
32
- .withArgs({ name: 'pg', file: 'lib/client.js' })
33
- .yields(Client);
34
-
35
- core.depHooks.resolve
36
- .withArgs({ name: 'pg', file: 'lib/native/client.js' })
37
- .yields(NativeClient);
38
-
39
- core.depHooks.resolve.withArgs({ name: 'pg-pool' }).yields(Pool);
31
+ core.depHooks.resolve.withArgs(sinon.match({ name: 'pg', file: 'lib/client.js' })).yields(Client);
32
+ core.depHooks.resolve.withArgs(sinon.match({ name: 'pg', file: 'lib/native/client.js' })).yields(NativeClient);
33
+ core.depHooks.resolve.withArgs(sinon.match({ name: 'pg-pool' })).yields(Pool);
40
34
 
41
35
  require('./postgres')(core).install();
42
36
  });
@@ -28,7 +28,6 @@ const {
28
28
  isString,
29
29
  primordials: { ArrayPrototypeJoin },
30
30
  } = require('@contrast/common');
31
- const { InstrumentationType: { RULE } } = require('../../../constants');
32
31
  const { createAppendTags } = require('../../tag-utils');
33
32
  const { patchType } = require('../common');
34
33
 
@@ -45,7 +44,7 @@ module.exports = function(core) {
45
44
  depHooks,
46
45
  patcher,
47
46
  assess: {
48
- getSourceContext,
47
+ getSinkContext,
49
48
  eventFactory: { createSinkEvent },
50
49
  dataflow: {
51
50
  tracker,
@@ -114,7 +113,7 @@ module.exports = function(core) {
114
113
  install() {
115
114
  // restify adds functionality to the built-in response via this patch function.
116
115
  // once it returns the request, it'll have been decorated with redirect() method.
117
- depHooks.resolve({ name: 'restify', file: 'lib/response.js' }, (responsePatch) => patcher.patch(responsePatch, {
116
+ depHooks.resolve({ name: 'restify', version: '<12', file: 'lib/response.js' }, (responsePatch) => patcher.patch(responsePatch, {
118
117
  name: 'restify.response.patch',
119
118
  patchType,
120
119
  post(data) {
@@ -122,7 +121,7 @@ module.exports = function(core) {
122
121
  patchType,
123
122
  name: 'restify.Response.redirect',
124
123
  pre(data) {
125
- if (!getSourceContext(RULE, ruleId)) return;
124
+ if (!getSinkContext(ruleId)) return;
126
125
 
127
126
  let vulnArgIdx;
128
127
  let vulnArgIsString = true;
@@ -33,11 +33,9 @@ describe('assess dataflow restify sinks', function () {
33
33
  return new Response();
34
34
  };
35
35
 
36
- core.depHooks.resolve
37
- .withArgs({ name: 'restify', file: 'lib/response.js' })
38
- .callsFake((desc, cb) => {
39
- patchMock = cb(patch);
40
- });
36
+ core.depHooks.resolve.callsFake((desc, cb) => {
37
+ patchMock = cb(patch);
38
+ });
41
39
 
42
40
  require('./restify')(core).install();
43
41
  });
@@ -25,7 +25,6 @@ const {
25
25
  CUSTOM_ENCODED,
26
26
  },
27
27
  } = require('@contrast/common');
28
- const { InstrumentationType: { RULE } } = require('../../../constants');
29
28
  const { patchType, filterSafeTags } = require('../common');
30
29
 
31
30
  /**
@@ -42,7 +41,7 @@ module.exports = function (core) {
42
41
  config,
43
42
  assess: {
44
43
  inspect, // TODO NODE-3455: remove
45
- getSourceContext,
44
+ getSinkContext,
46
45
  eventFactory: { createSinkEvent },
47
46
  dataflow: {
48
47
  tracker,
@@ -63,12 +62,12 @@ module.exports = function (core) {
63
62
  const sequelize = (core.assess.dataflow.sinks.sequelize = {});
64
63
 
65
64
  sequelize.install = function () {
66
- depHooks.resolve({ name: 'sequelize' }, (sequelize) => {
65
+ depHooks.resolve({ name: 'sequelize', version: '<7' }, (sequelize) => {
67
66
  patcher.patch(sequelize.prototype, 'query', {
68
67
  name: 'sequelize.prototype.query',
69
68
  patchType,
70
69
  around(next, data) {
71
- if (!getSourceContext(RULE, ruleId) || !data.args[0]) return next();
70
+ if (!getSinkContext(ruleId) || !data.args[0]) return next();
72
71
 
73
72
  const { args, hooked, orig } = data;
74
73
  const query = typeof args[0] === 'string' ? args[0] : args[0].query;
@@ -27,7 +27,6 @@ const {
27
27
  Rule: { SQL_INJECTION: ruleId },
28
28
  isString
29
29
  } = require('@contrast/common');
30
- const { InstrumentationType: { RULE } } = require('../../../constants');
31
30
 
32
31
  const safeTags = [
33
32
  `excluded:${ruleId}`,
@@ -49,7 +48,7 @@ module.exports = function(core) {
49
48
  depHooks,
50
49
  patcher,
51
50
  assess: {
52
- getSourceContext,
51
+ getSinkContext,
53
52
  eventFactory: { createSinkEvent },
54
53
  dataflow: {
55
54
  tracker,
@@ -60,7 +59,7 @@ module.exports = function(core) {
60
59
 
61
60
  const pre = (name, method) => (data) => {
62
61
  if (
63
- !getSourceContext(RULE, ruleId) ||
62
+ !getSinkContext(ruleId) ||
64
63
  !data.args[0] ||
65
64
  !isString(data.args[0]) ||
66
65
  isLocked(ruleId)
@@ -105,7 +104,7 @@ module.exports = function(core) {
105
104
 
106
105
  core.assess.dataflow.sinks.sqlite3 = {
107
106
  install() {
108
- depHooks.resolve({ name: 'sqlite3' }, sqlite3 => {
107
+ depHooks.resolve({ name: 'sqlite3', version: '<6' }, sqlite3 => {
109
108
  ['all', 'run', 'get', 'each', 'exec', 'prepare'].forEach((method) => {
110
109
  const name = `sqlite3.Database.prototype.${method}`;
111
110
  patcher.patch(sqlite3.Database.prototype, method, {
@@ -33,7 +33,6 @@ const {
33
33
  },
34
34
  traverseValues,
35
35
  } = require('@contrast/common');
36
- const { InstrumentationType: { RULE } } = require('../../../constants');
37
36
  const { createAdjustedQueryTags } = require('../../tag-utils');
38
37
 
39
38
  const safeTags = [
@@ -58,7 +57,7 @@ module.exports = function (core) {
58
57
  patcher,
59
58
  assess: {
60
59
  inspect, // TODO NODE-3455: remove
61
- getSourceContext,
60
+ getSinkContext,
62
61
  eventFactory: { createSinkEvent },
63
62
  dataflow: {
64
63
  tracker,
@@ -144,7 +143,7 @@ module.exports = function (core) {
144
143
  }
145
144
 
146
145
  function around(next, { args: origArgs, hooked, orig, name }) {
147
- if (!getSourceContext(RULE, ruleId) || isLocked(ruleId)) return next();
146
+ if (!getSinkContext(ruleId) || isLocked(ruleId)) return next();
148
147
 
149
148
  const methodPath = StringPrototypeSplit.call(name, '.');
150
149
  const method = methodPath[methodPath.length - 1];
@@ -250,7 +249,7 @@ module.exports = function (core) {
250
249
 
251
250
  core.assess.dataflow.sinks.vm = {
252
251
  install() {
253
- depHooks.resolve({ name: 'vm' }, (vm) => {
252
+ depHooks.resolve({ name: 'vm', version: '*' }, (vm) => {
254
253
  [
255
254
  'Script',
256
255
  'createScript',
@@ -16,7 +16,6 @@
16
16
  'use strict';
17
17
 
18
18
  const { InputType } = require('@contrast/common');
19
- const { InstrumentationType: { SOURCE } } = require('../../../constants');
20
19
  const { patchType } = require('../common');
21
20
 
22
21
  const METHODS = ['json', 'raw', 'text', 'urlencoded'];
@@ -39,10 +38,9 @@ module.exports = function init(core) {
39
38
  const preHook = (data) => {
40
39
  const [req, , next] = data.args;
41
40
  data.args[2] = scopes.wrap(function contrastNext(...args) {
42
- const sourceContext = getSourceContext(SOURCE);
41
+ const sourceContext = getSourceContext();
43
42
 
44
43
  if (!sourceContext) {
45
- logger.error({ funcKey: data.funcKey }, 'unable to handle source. Missing `sourceContext`');
46
44
  return next(...args);
47
45
  }
48
46
 
@@ -99,7 +97,7 @@ module.exports = function init(core) {
99
97
  core.assess.dataflow.sources.bodyParser1Instrumentation = {
100
98
  install() {
101
99
  depHooks.resolve(
102
- { name: 'body-parser', version: '>=1.0.0' },
100
+ { name: 'body-parser', version: '>=1 <2' },
103
101
  /** @param {import('body-parser').BodyParser} bodyParser */
104
102
  (bodyParser) => {
105
103
  bodyParser = patcher.patch(bodyParser, {
@@ -112,10 +112,8 @@ describe('assess dataflow sources body-parser v1', function () {
112
112
  middleware(req, res, next);
113
113
 
114
114
  expect(core.assess.dataflow.sources.handle).not.to.have.been.called;
115
- expect(core.logger.error).to.have.been.calledWith(
116
- { funcKey: 'assess-dataflow-source:body-parser.bodyParser' },
117
- 'unable to handle source. Missing `sourceContext`'
118
- );
115
+ expect(core.logger.trace.callCount).greaterThan(0);
116
+ expect(core.logger.trace.lastCall.args[0]).includes('Assess intentionally disabled');
119
117
  }, { assess: { policy: null } });
120
118
  });
121
119
 
@@ -210,10 +208,8 @@ describe('assess dataflow sources body-parser v1', function () {
210
208
  middleware(req, res, next);
211
209
 
212
210
  expect(core.assess.dataflow.sources.handle).not.to.have.been.called;
213
- expect(core.logger.error).to.have.been.calledWith(
214
- { funcKey: `assess-dataflow-source:body-parser.${method}.${method}Parser` },
215
- 'unable to handle source. Missing `sourceContext`',
216
- );
211
+ expect(core.logger.trace.callCount).greaterThan(0);
212
+ expect(core.logger.trace.lastCall.args[0]).includes('Assess intentionally disabled');
217
213
  }, { assess: { policy: null } });
218
214
  });
219
215
 
@@ -16,7 +16,6 @@
16
16
  'use strict';
17
17
 
18
18
  const { InputType } = require('@contrast/common');
19
- const { InstrumentationType: { SOURCE } } = require('../../../constants');
20
19
  const { patchType } = require('../common');
21
20
 
22
21
  const inputType = InputType.MULTIPART_VALUE;
@@ -38,7 +37,7 @@ module.exports = (core) => {
38
37
  function createPreHook(finalEventName) {
39
38
  return function (data) {
40
39
  const { orig, hooked, funcKey } = data;
41
- const sourceContext = getSourceContext(SOURCE);
40
+ const sourceContext = getSourceContext();
42
41
 
43
42
  if (!sourceContext) {
44
43
  return;
@@ -84,7 +83,7 @@ module.exports = (core) => {
84
83
 
85
84
  // Patch `busboy`
86
85
  function install() {
87
- depHooks.resolve({ name, version: '<1.0.0' }, (busboy) => {
86
+ depHooks.resolve({ name, version: '<1' }, (busboy) => {
88
87
  patcher.patch(busboy.prototype, 'emit', {
89
88
  name: 'busboy.prototype.emit',
90
89
  patchType,
@@ -93,7 +92,7 @@ module.exports = (core) => {
93
92
  });
94
93
 
95
94
 
96
- depHooks.resolve({ name, version: '>=1.0.0' }, (busboy) =>
95
+ depHooks.resolve({ name, version: '1' }, (busboy) =>
97
96
  patcher.patch(busboy, {
98
97
  name,
99
98
  patchType,
@@ -27,8 +27,8 @@ describe('assess dataflow sources busboy', function () {
27
27
  sinon.spy(sources, 'handle');
28
28
 
29
29
  busboyInstr(core).install();
30
- core.depHooks.resolve.withArgs({ name: 'busboy', version: '<1.0.0' }).yield(mockBusboy0);
31
- core.depHooks.resolve.withArgs({ name: 'busboy', version: '>=1.0.0' }).yield(mockBusboy1);
30
+ core.depHooks.resolve.withArgs({ name: 'busboy', version: '<1' }).yield(mockBusboy0);
31
+ core.depHooks.resolve.withArgs({ name: 'busboy', version: '1' }).yield(mockBusboy1);
32
32
  const patchedBusboy1 = core.patcher.patch.getCall(1).returnValue;
33
33
 
34
34
  emitMethodVersions = {
@@ -16,7 +16,6 @@
16
16
  'use strict';
17
17
 
18
18
  const { InputType } = require('@contrast/common');
19
- const { InstrumentationType: { SOURCE } } = require('../../../constants');
20
19
  const { patchType } = require('../common');
21
20
 
22
21
  module.exports = function init(core) {
@@ -25,7 +24,7 @@ module.exports = function init(core) {
25
24
  assess.dataflow.sources.cookieParser1Instrumentation = {
26
25
  install() {
27
26
  depHooks.resolve(
28
- { name: 'cookie-parser', version: '>=1.0.0' },
27
+ { name: 'cookie-parser', version: '>=1 <2' },
29
28
  /** @param {import('cookie-parser')} cookieParser */
30
29
  (cookieParser) =>
31
30
  patcher.patch(cookieParser, {
@@ -40,10 +39,9 @@ module.exports = function init(core) {
40
39
  const { funcKey } = data;
41
40
  const [req, , next] = data.args;
42
41
  data.args[2] = function contrastNext(...args) {
43
- const sourceContext = assess.getSourceContext(SOURCE);
42
+ const sourceContext = assess.getSourceContext();
44
43
 
45
44
  if (!sourceContext) {
46
- logger.error({ funcKey }, 'unable to handle source. Missing `sourceContext`');
47
45
  return next(...args);
48
46
  }
49
47
 
@@ -74,10 +74,8 @@ describe('assess dataflow sources cookie-parser v1', function () {
74
74
  middleware(req, res, next);
75
75
 
76
76
  expect(core.assess.dataflow.sources.handle).not.to.have.been.called;
77
- expect(core.logger.error).to.have.been.calledWith(
78
- { funcKey: 'assess-dataflow-source:cookie-parser.cookieParser' },
79
- 'unable to handle source. Missing `sourceContext`',
80
- );
77
+ expect(core.logger.trace.callCount).greaterThan(0);
78
+ expect(core.logger.trace.lastCall.args[0]).includes('Assess intentionally disabled');
81
79
  }, { assess: { policy: null } });
82
80
  });
83
81
 
@@ -16,7 +16,6 @@
16
16
  'use strict';
17
17
 
18
18
  const { InputType } = require('@contrast/common');
19
- const { InstrumentationType: { SOURCE } } = require('../../../../constants');
20
19
  const { patchType } = require('../../common');
21
20
 
22
21
  module.exports = function init(core) {
@@ -24,55 +23,74 @@ module.exports = function init(core) {
24
23
  logger,
25
24
  patcher,
26
25
  depHooks,
27
- assess: { getSourceContext },
26
+ assess: {
27
+ getSourceContext,
28
+ dataflow: { sources }
29
+ },
28
30
  } = core;
29
31
 
32
+ function postHook(name) {
33
+ return function({ obj: layer, result, orig, hooked, funcKey }) {
34
+ // we can exit early if
35
+ // the layer doesn't match the request or
36
+ // the layer doesn't recognize any parameters
37
+ if (
38
+ !result ||
39
+ !layer.keys ||
40
+ layer.keys.length === 0
41
+ ) return;
42
+
43
+ const sourceContext = getSourceContext();
44
+ if (!sourceContext) return;
45
+
46
+ if (sourceContext.parsedParams) {
47
+ logger.trace({ funcKey }, 'values already tracked');
48
+ return;
49
+ }
50
+
51
+ try {
52
+ sources.handle({
53
+ context: 'req.params',
54
+ name,
55
+ inputType: InputType.PARAMETER_VALUE,
56
+ stacktraceOpts: {
57
+ constructorOpt: hooked,
58
+ prependFrames: [orig]
59
+ },
60
+ data: layer.params,
61
+ sourceContext
62
+ });
63
+ sourceContext.parsedParams = true;
64
+ } catch (err) {
65
+ logger.error({ err, funcKey }, 'unable to handle source');
66
+ }
67
+ };
68
+ }
69
+
30
70
  core.assess.dataflow.sources.expressInstrumentation.params = {
31
71
  install() {
32
72
  const name = 'Layer.prototype.match';
33
73
  depHooks.resolve(
34
- { name: 'express', version: '>=4.0.0 <5.0.0', file: 'lib/router/layer.js' },
74
+ { name: 'express', version: '>=4 <5', file: 'lib/router/layer.js' },
35
75
  (Layer) => {
36
76
  patcher.patch(Layer.prototype, 'match', {
37
77
  name,
38
78
  patchType,
39
- post({ obj: layer, result, orig, hooked, funcKey }) {
40
- // we can exit early if
41
- // the layer doesn't match the request or
42
- // the layer doesn't recognize any parameters
43
- if (
44
- !result ||
45
- !layer.keys ||
46
- layer.keys.length === 0
47
- ) return;
48
-
49
- const sourceContext = getSourceContext(SOURCE);
50
- if (!sourceContext) return;
51
-
52
- if (sourceContext.parsedParams) {
53
- logger.trace({ funcKey }, 'values already tracked');
54
- return;
55
- }
56
-
57
- try {
58
- core.assess.dataflow.sources.handle({
59
- context: 'req.params',
60
- name,
61
- inputType: InputType.PARAMETER_VALUE,
62
- stacktraceOpts: {
63
- constructorOpt: hooked,
64
- prependFrames: [orig]
65
- },
66
- data: layer.params,
67
- sourceContext
68
- });
69
- sourceContext.parsedParams = true;
70
- } catch (err) {
71
- logger.error({ err, funcKey }, 'unable to handle source');
72
- }
73
- }
79
+ post: postHook(name)
74
80
  });
81
+ return Layer;
82
+ }
83
+ );
75
84
 
85
+ // Used by Express 5
86
+ depHooks.resolve(
87
+ { name: 'router', version: '>=2 <3', file: 'lib/layer.js' },
88
+ (Layer) => {
89
+ patcher.patch(Layer.prototype, 'match', {
90
+ name,
91
+ patchType,
92
+ post: postHook(name)
93
+ });
76
94
  return Layer;
77
95
  }
78
96
  );
@@ -8,96 +8,103 @@ const { InputType } = require('@contrast/common');
8
8
  describe('assess dataflow sources express params', function () {
9
9
  let core, simulateRequestScope, Layer, layer;
10
10
 
11
- beforeEach(function () {
12
- ({ core, simulateRequestScope } = initAssessFixture());
13
-
14
- sinon.stub(core.assess.dataflow.sources, 'handle');
15
-
16
- const LayerMock = sinon.stub();
17
- LayerMock.prototype.match = sinon.stub().returns(true);
18
-
19
- require('./params')(core).install();
20
- Layer = core.depHooks.resolve.yield(LayerMock)[0];
21
- layer = { keys: ['foo'], params: { foo: 'bar' } };
22
- });
11
+ [
12
+ { name: 'express', version: '>=4 <5', file: 'lib/router/layer.js' },
13
+ { name: 'router', version: '>=2 <3', file: 'lib/layer.js' }
14
+ ].forEach((args) => {
15
+ describe(`Express${args.name === 'express' ? '4' : '5'}`, function() {
16
+ beforeEach(function () {
17
+ ({ core, simulateRequestScope } = initAssessFixture());
18
+
19
+ sinon.stub(core.assess.dataflow.sources, 'handle');
20
+
21
+ const LayerMock = sinon.stub();
22
+ LayerMock.prototype.match = sinon.stub().returns(true);
23
+
24
+ require('./params')(core).install();
25
+ [Layer] = core.depHooks.resolve.withArgs(args).yield(LayerMock);
26
+ layer = { keys: ['foo'], params: { foo: 'bar' } };
27
+ });
23
28
 
24
- it('calls `.handle` when `match` adds params (and keys) to the Layer instance', function () {
25
- simulateRequestScope(() => {
26
- Reflect.apply(Layer.prototype.match, layer, ['/bar']);
27
-
28
- expect(core.assess.dataflow.sources.handle).to.have.been.calledWith({
29
- context: 'req.params',
30
- name: 'Layer.prototype.match',
31
- inputType: InputType.PARAMETER_VALUE,
32
- stacktraceOpts: {
33
- constructorOpt: sinon.match.func,
34
- prependFrames: sinon.match.array,
35
- },
36
- data: layer.params,
37
- sourceContext: core.scopes.sources.getStore().assess
29
+ it('calls `.handle` when `match` adds params (and keys) to the Layer instance', function () {
30
+ simulateRequestScope(() => {
31
+ Reflect.apply(Layer.prototype.match, layer, ['/bar']);
32
+
33
+ expect(core.assess.dataflow.sources.handle).to.have.been.calledWith({
34
+ context: 'req.params',
35
+ name: 'Layer.prototype.match',
36
+ inputType: InputType.PARAMETER_VALUE,
37
+ stacktraceOpts: {
38
+ constructorOpt: sinon.match.func,
39
+ prependFrames: sinon.match.array,
40
+ },
41
+ data: layer.params,
42
+ sourceContext: core.scopes.sources.getStore().assess
43
+ });
44
+ });
38
45
  });
39
- });
40
- });
41
46
 
42
- it('does not call `.handle` when `match` returns false', function () {
43
- Layer.prototype.match.returns(false);
47
+ it('does not call `.handle` when `match` returns false', function () {
48
+ Layer.prototype.match.returns(false);
44
49
 
45
- simulateRequestScope(() => {
46
- Reflect.apply(Layer.prototype.match, layer, ['/bar']);
50
+ simulateRequestScope(() => {
51
+ Reflect.apply(Layer.prototype.match, layer, ['/bar']);
47
52
 
48
- expect(core.assess.dataflow.sources.handle).not.to.have.been.called;
49
- });
50
- });
53
+ expect(core.assess.dataflow.sources.handle).not.to.have.been.called;
54
+ });
55
+ });
51
56
 
52
- it('does not call `.handle` when the layer is missing the expected properties', function () {
53
- simulateRequestScope(() => {
54
- Reflect.apply(Layer.prototype.match, {}, ['/bar']);
57
+ it('does not call `.handle` when the layer is missing the expected properties', function () {
58
+ simulateRequestScope(() => {
59
+ Reflect.apply(Layer.prototype.match, {}, ['/bar']);
55
60
 
56
- expect(core.assess.dataflow.sources.handle).not.to.have.been.called;
57
- });
58
- });
61
+ expect(core.assess.dataflow.sources.handle).not.to.have.been.called;
62
+ });
63
+ });
59
64
 
60
- it('does not call `.handle` when `match` adds no params or keys', function () {
61
- simulateRequestScope(() => {
62
- Reflect.apply(Layer.prototype.match, { keys: [], params: {} }, ['/bar']);
65
+ it('does not call `.handle` when `match` adds no params or keys', function () {
66
+ simulateRequestScope(() => {
67
+ Reflect.apply(Layer.prototype.match, { keys: [], params: {} }, ['/bar']);
63
68
 
64
- expect(core.assess.dataflow.sources.handle).not.to.have.been.called;
65
- });
66
- });
69
+ expect(core.assess.dataflow.sources.handle).not.to.have.been.called;
70
+ });
71
+ });
67
72
 
68
- it('does not handle when there is no assess policy in request context', function () {
69
- simulateRequestScope(() => {
70
- Reflect.apply(Layer.prototype.match, layer, ['/bar']);
73
+ it('does not handle when there is no assess policy in request context', function () {
74
+ simulateRequestScope(() => {
75
+ Reflect.apply(Layer.prototype.match, layer, ['/bar']);
71
76
 
72
- expect(core.assess.dataflow.sources.handle).not.to.have.been.called;
73
- }, { assess: { policy: null } });
74
- });
77
+ expect(core.assess.dataflow.sources.handle).not.to.have.been.called;
78
+ }, { assess: { policy: null } });
79
+ });
75
80
 
76
- it('does not call `.handle` when the values are already tracked', function () {
77
- simulateRequestScope(() => {
78
- core.scopes.sources.getStore().assess.parsedParams = true;
81
+ it('does not call `.handle` when the values are already tracked', function () {
82
+ simulateRequestScope(() => {
83
+ core.scopes.sources.getStore().assess.parsedParams = true;
79
84
 
80
- Reflect.apply(Layer.prototype.match, layer, ['/bar']);
85
+ Reflect.apply(Layer.prototype.match, layer, ['/bar']);
81
86
 
82
- expect(core.assess.dataflow.sources.handle).not.to.have.been.called;
83
- expect(core.logger.trace).to.have.been.calledWith(
84
- { funcKey: 'assess-dataflow-source:Layer.prototype.match' },
85
- 'values already tracked'
86
- );
87
- });
88
- });
87
+ expect(core.assess.dataflow.sources.handle).not.to.have.been.called;
88
+ expect(core.logger.trace).to.have.been.calledWith(
89
+ { funcKey: 'assess-dataflow-source:Layer.prototype.match' },
90
+ 'values already tracked'
91
+ );
92
+ });
93
+ });
89
94
 
90
- it('handles a case with an error in the `.handle` method', function () {
91
- const err = new Error('test');
92
- core.assess.dataflow.sources.handle.throws(err);
95
+ it('handles a case with an error in the `.handle` method', function () {
96
+ const err = new Error('test');
97
+ core.assess.dataflow.sources.handle.throws(err);
93
98
 
94
- simulateRequestScope(() => {
95
- Reflect.apply(Layer.prototype.match, layer, ['/bar']);
99
+ simulateRequestScope(() => {
100
+ Reflect.apply(Layer.prototype.match, layer, ['/bar']);
96
101
 
97
- expect(core.logger.error).to.have.been.calledWith(
98
- { err, funcKey: 'assess-dataflow-source:Layer.prototype.match' },
99
- 'unable to handle source'
100
- );
102
+ expect(core.logger.error).to.have.been.calledWith(
103
+ { err, funcKey: 'assess-dataflow-source:Layer.prototype.match' },
104
+ 'unable to handle source'
105
+ );
106
+ });
107
+ });
101
108
  });
102
109
  });
103
110
  });