@contrast/agent 4.20.0 → 4.21.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 (29) hide show
  1. package/lib/assess/hapi/sources.js +1 -1
  2. package/lib/assess/policy/signatures.json +12 -0
  3. package/lib/assess/propagators/validator/init-hooks.js +44 -5
  4. package/lib/assess/propagators/validator/validator-methods.js +6 -0
  5. package/lib/core/async-storage/hooks/mongodb.js +1 -1
  6. package/lib/core/hapi/index.js +15 -2
  7. package/lib/libraries.js +1 -1
  8. package/lib/list-installed.js +14 -20
  9. package/node_modules/moment/CHANGELOG.md +13 -1
  10. package/node_modules/moment/dist/locale/sr-cyrl.js +3 -2
  11. package/node_modules/moment/dist/locale/sr.js +3 -2
  12. package/node_modules/moment/dist/moment.js +3 -3
  13. package/node_modules/moment/locale/sr-cyrl.js +3 -2
  14. package/node_modules/moment/locale/sr.js +3 -2
  15. package/node_modules/moment/min/locales.js +6 -4
  16. package/node_modules/moment/min/locales.min.js +1 -1
  17. package/node_modules/moment/min/locales.min.js.map +1 -1
  18. package/node_modules/moment/min/moment-with-locales.js +8 -6
  19. package/node_modules/moment/min/moment-with-locales.min.js +1 -1
  20. package/node_modules/moment/min/moment-with-locales.min.js.map +1 -1
  21. package/node_modules/moment/min/moment.min.js +1 -1
  22. package/node_modules/moment/min/moment.min.js.map +1 -1
  23. package/node_modules/moment/moment.js +3 -3
  24. package/node_modules/moment/package.json +4 -4
  25. package/node_modules/moment/src/lib/create/from-string.js +1 -1
  26. package/node_modules/moment/src/locale/sr-cyrl.js +3 -2
  27. package/node_modules/moment/src/locale/sr.js +3 -2
  28. package/node_modules/moment/src/moment.js +2 -2
  29. package/package.json +1 -1
@@ -28,7 +28,7 @@ class HapiAssessSources {
28
28
  * Handles emitting of all assess source events
29
29
  */
30
30
  registerSourcesHandler() {
31
- agentEmitter.on(EVENTS.HAPI_PRE_HANDLER, ({ request }) => {
31
+ agentEmitter.on(EVENTS.HAPI_POST_AUTH, ({ request }) => {
32
32
  emitWatchableObjects(request);
33
33
  });
34
34
  }
@@ -1000,6 +1000,12 @@
1000
1000
  "methodName": "isCreditCard",
1001
1001
  "isModule": true
1002
1002
  },
1003
+ "validator.isDate": {
1004
+ "moduleName": "validator",
1005
+ "version": ">=13.0.0",
1006
+ "methodName": "isDecimal",
1007
+ "isModule": true
1008
+ },
1003
1009
  "validator.isDecimal": {
1004
1010
  "moduleName": "validator",
1005
1011
  "version": ">=13.0.0",
@@ -1018,6 +1024,12 @@
1018
1024
  "methodName": "isEAN",
1019
1025
  "isModule": true
1020
1026
  },
1027
+ "validator.isEmail": {
1028
+ "moduleName": "validator",
1029
+ "version": ">=13.0.0",
1030
+ "methodName": "isEmail",
1031
+ "isModule": true
1032
+ },
1021
1033
  "validator.isEthereumAddress": {
1022
1034
  "moduleName": "validator",
1023
1035
  "version": ">=13.0.0",
@@ -39,11 +39,11 @@ const agent = require('../../../agent');
39
39
  * https://docs.google.com/spreadsheets/d/17p5C6NOISNuWi8D-07d8gNg8byQytuwjtgBgzGpfU_w/edit#gid=0
40
40
  *
41
41
  */
42
- module.exports.handle = function() {
42
+ module.exports.handle = function () {
43
43
  const {
44
44
  validators,
45
45
  untrackers,
46
- sanitizers
46
+ sanitizers,
47
47
  } = require('./validator-methods.js');
48
48
 
49
49
  const patchType = PATCH_TYPES.ASSESS_PROPAGATOR;
@@ -62,7 +62,7 @@ module.exports.handle = function() {
62
62
  const patched = patcher.patch(obj, {
63
63
  name,
64
64
  patchType,
65
- post
65
+ post,
66
66
  });
67
67
  // babel adds a self-referential default property so if present in the unpatched
68
68
  // object update the patched object
@@ -89,7 +89,12 @@ module.exports.handle = function() {
89
89
  { name: 'validator', file: `lib/${validator}` },
90
90
  (index, meta) => {
91
91
  function post(data) {
92
- if (data.result && (validator !== 'matches' || (validator === 'matches' && agent.config.assess.trust_custom_validators))) {
92
+ if (
93
+ data.result &&
94
+ (validator !== 'matches' ||
95
+ (validator === 'matches' &&
96
+ agent.config.assess.trust_custom_validators))
97
+ ) {
93
98
  const trackingData = tracker.getData(data.args[0]);
94
99
  if (trackingData) {
95
100
  tagRangeUtil.addInPlace(
@@ -104,7 +109,7 @@ module.exports.handle = function() {
104
109
  signature,
105
110
  tagRanges: trackingData.tagRanges,
106
111
  source: 'O',
107
- target: 'R'
112
+ target: 'R',
108
113
  });
109
114
 
110
115
  event.parents.push(trackingData.event);
@@ -210,4 +215,38 @@ module.exports.handle = function() {
210
215
  }
211
216
  );
212
217
  }
218
+
219
+ moduleHook.resolve({ name: 'validator', file: 'lib/isEmail' }, (isEmail) => {
220
+ const signature = new Signature('validator.isEmail');
221
+
222
+ function post(data) {
223
+ const trackingData = tracker.getData(data.args[0]);
224
+ // The default options for the two fields of interest are:
225
+ // `{ allow_display_name: false, require_display_name: false }`
226
+ // so we can use an empty object as it will also yield
227
+ // falsy values for these two fields
228
+ const options = data.args[1] ? data.args[1] : {};
229
+ if (data.result && trackingData && !options.allow_display_name && !options.require_display_name) {
230
+ tagRangeUtil.addInPlace(
231
+ trackingData.tagRanges,
232
+ new TagRange(0, data.args[0].length - 1, 'limited-chars')
233
+ );
234
+ tagRangeUtil.removeInPlace(trackingData.tagRanges, ['untrusted']);
235
+
236
+ const context = new CallContext(data);
237
+ const event = new PropagationEvent({
238
+ context,
239
+ signature,
240
+ tagRanges: trackingData.tagRanges,
241
+ source: 'O',
242
+ target: 'R',
243
+ });
244
+
245
+ event.parents.push(trackingData.event);
246
+ trackingData.event = event;
247
+ }
248
+ }
249
+
250
+ return patch(isEmail, 'isEmail', post);
251
+ });
213
252
  };
@@ -32,6 +32,7 @@ module.exports = {
32
32
  isBoolean: 'limited-chars',
33
33
  isBtcAddress: 'alphanum-space-hyphen',
34
34
  isCreditCard: 'limited-chars',
35
+ isDate: 'limited-chars',
35
36
  isDecimal: 'limited-chars',
36
37
  // calls toFloat() which calls isFloat() so no need to hook.
37
38
  //isDivisibleBy: 'limited-chars',
@@ -88,5 +89,10 @@ module.exports = {
88
89
  escape: 'html-encoded'
89
90
  // toFloat uses isFloat which is hooked, so no need to do so again
90
91
  // toFloat: 'limited-chars'
92
+ },
93
+ customLogic: {
94
+ // this value is not used and it's added just for storing the information
95
+ // about what's patched in one place
96
+ isEmail: 'limited-chars'
91
97
  }
92
98
  };
@@ -96,7 +96,7 @@ function init() {
96
96
  {
97
97
  name: 'mongodb',
98
98
  file: 'lib/topologies/native_topology.js',
99
- version: '>=3.3.0 <4.0.0',
99
+ version: '>=3.3.0',
100
100
  },
101
101
  (tpl, { version }) => {
102
102
  if (semver.lt(version, '4.0.0')) {
@@ -42,6 +42,7 @@ const constants = {
42
42
  HAPI_ROUTES: 'hapi-routes', // used to instrument registered routes
43
43
  HAPI_ADD_ROUTE: 'hapi-add-route', // used to instrument adding a route
44
44
  HAPI_PRE_AUTH: 'hapi-pre-auth', // used to implement hapi onPreAuth hooks
45
+ HAPI_POST_AUTH: 'hapi-post-auth', // uses to implement hapi onPostAuth hooks
45
46
  HAPI_PRE_HANDLER: 'hapi-pre-handler', // used to implement hapi onPreHandler hooks
46
47
  HAPI_FINISHED: 'hapi-response-finished', // used to implement when hapi response is finished
47
48
  HAPI_PRE_RES: 'hapi-pre-response', // used to implement hapi onPreResponse hooks
@@ -162,12 +163,13 @@ class HapiCore {
162
163
  return h.continue;
163
164
  });
164
165
 
165
- server.ext('onPreHandler', function onPreHandler(request, h) {
166
- agentEmitter.emit(constants.EVENTS.HAPI_PRE_HANDLER, {
166
+ server.ext('onPostAuth', function onPostAuth(request, h) {
167
+ agentEmitter.emit(constants.EVENTS.HAPI_POST_AUTH, {
167
168
  request,
168
169
  h,
169
170
  server
170
171
  });
172
+
171
173
  // Update the domain's model of the request with body and params since it has been
172
174
  // fully parsed and validated
173
175
  decorateRequest({
@@ -176,6 +178,17 @@ class HapiCore {
176
178
  parameters: request.params,
177
179
  query: request.query
178
180
  });
181
+
182
+ return h.continue;
183
+ });
184
+
185
+ server.ext('onPreHandler', function onPreHandler(request, h) {
186
+ agentEmitter.emit(constants.EVENTS.HAPI_PRE_HANDLER, {
187
+ request,
188
+ h,
189
+ server
190
+ });
191
+
179
192
  return h.continue;
180
193
  });
181
194
 
package/lib/libraries.js CHANGED
@@ -164,7 +164,7 @@ const getLibInfo = async (agent, eluEnabled) =>
164
164
 
165
165
  return libs;
166
166
  } catch (err) {
167
- logger.error('unable to read installed dependencies. %o', err);
167
+ logger.error('unable to read installed dependencies: %o', err);
168
168
  return AppUpdate.libraries;
169
169
  }
170
170
  }, DEADZONE_NAME);
@@ -18,7 +18,7 @@ const semver = require('semver');
18
18
  const util = require('util');
19
19
 
20
20
  const {
21
- AGENT_INFO: { SUPPORTED_NPM_VERSIONS }
21
+ AGENT_INFO: { SUPPORTED_NPM_VERSIONS },
22
22
  } = require('./constants');
23
23
 
24
24
  const VERSION_REGEX = /^npm@(\S+)\s+(\S+)$/m;
@@ -39,19 +39,18 @@ const execFile = util.promisify(require('child_process').execFile);
39
39
  * @returns {Promise<Result>}
40
40
  */
41
41
  module.exports = async function listInstalled(cwd, logger) {
42
- const env = { ...process.env, NODE_OPTIONS: undefined };
43
- const args = ['ls', '--json', '--prod', '--long'];
42
+ const execFileOpts = {
43
+ cwd,
44
+ env: { ...process.env, NODE_OPTIONS: undefined },
45
+ maxBuffer: 1024 * 1024 * 128,
46
+ };
44
47
  let stdout;
45
48
 
46
49
  try {
47
- const result = await execFile('npm', ['help'], {
48
- cwd,
49
- env,
50
- shell: true,
51
- });
50
+ const result = await execFile('npm', ['help'], execFileOpts);
52
51
  stdout = result.stdout;
53
52
  } catch (err) {
54
- logger.debug('`npm` returned an error: %o', err);
53
+ logger.trace('`npm help` returned an error: %o', err);
55
54
  // If npm encounters any errors whatsoever it will return with a non-zero
56
55
  // exit code but still output the relevant information to stdout.
57
56
  // If an even worse error occurs, we may not be able to parse stdout.
@@ -61,12 +60,13 @@ module.exports = async function listInstalled(cwd, logger) {
61
60
  const [, version, location] = stdout.match(VERSION_REGEX) || [];
62
61
  if (!version)
63
62
  throw new Error(
64
- 'Unable to locate `npm`. Please enable debug level logs for more information.'
63
+ "Unable to locate `npm`. `npm` is required for your application's libraries to be reported to Contrast for analysis. Please enable debug level logs for more information."
65
64
  );
66
65
 
67
66
  logger.debug('using npm version %s at %s', version, location);
68
67
 
69
- if (semver.gte(version, '7.0.0')) args.push('--all');
68
+ const lsArgs = ['ls', '--json', '--long'];
69
+ if (semver.gte(version, '7.0.0')) lsArgs.push('--all');
70
70
  if (!semver.satisfies(version, SUPPORTED_NPM_VERSIONS))
71
71
  logger.warn(
72
72
  'The installed version of npm (%s at %s) can cause unexpected behavior. Please install a version that satisfies %s',
@@ -76,16 +76,10 @@ module.exports = async function listInstalled(cwd, logger) {
76
76
  );
77
77
 
78
78
  try {
79
- const result = await execFile('npm', args, {
80
- cwd,
81
- env,
82
- shell: true,
83
- maxBuffer: 1024 * 1024 * 128,
84
- });
85
-
79
+ const result = await execFile('npm', lsArgs, execFileOpts);
86
80
  stdout = result.stdout;
87
81
  } catch (err) {
88
- logger.debug('`npm ls` returned an error: %o', err);
82
+ logger.trace('`npm ls` returned an error: %o', err);
89
83
  stdout = err.stdout || '';
90
84
  }
91
85
 
@@ -94,7 +88,7 @@ module.exports = async function listInstalled(cwd, logger) {
94
88
  } catch (err) {
95
89
  logger.trace('parsing the output of `npm ls` failed: %o', err);
96
90
  throw new Error(
97
- '`npm ls` failed to provide a list of installed dependencies. Please enable debug level logs for more information.'
91
+ '`npm ls` failed to provide a list of installed dependencies. Please enable trace level logs for more information.'
98
92
  );
99
93
  }
100
94
  };
@@ -1,11 +1,23 @@
1
1
  Changelog
2
2
  =========
3
3
 
4
+ ### 2.29.4
5
+
6
+ * Release Jul 6, 2022
7
+ * [#6015](https://github.com/moment/moment/pull/6015) [bugfix] Fix ReDoS in preprocessRFC2822 regex
8
+
9
+ ### 2.29.3 [Full changelog](https://gist.github.com/ichernev/edebd440f49adcaec72e5e77b791d8be)
10
+
11
+ * Release Apr 17, 2022
12
+ * [#5995](https://github.com/moment/moment/pull/5995) [bugfix] Remove const usage
13
+ * [#5990](https://github.com/moment/moment/pull/5990) misc: fix advisory link
14
+
15
+
4
16
  ### 2.29.2 [See full changelog](https://gist.github.com/ichernev/1904b564f6679d9aac1ae08ce13bc45c)
5
17
 
6
18
  * Release Apr 3 2022
7
19
 
8
- Address https://github.com/advisories/GHSA-8hfj-j24r-96c4
20
+ Address https://github.com/moment/moment/security/advisories/GHSA-8hfj-j24r-96c4
9
21
 
10
22
  ### 2.29.1 [See full changelog](https://gist.github.com/marwahaha/cc478ba01a1292ab4bd4e861d164d99b)
11
23
 
@@ -31,7 +31,8 @@ var translator = {
31
31
  return wordKey[2];
32
32
  },
33
33
  translate: function (number, withoutSuffix, key, isFuture) {
34
- var wordKey = translator.words[key];
34
+ var wordKey = translator.words[key],
35
+ word;
35
36
 
36
37
  if (key.length === 1) {
37
38
  // Nominativ
@@ -39,7 +40,7 @@ var translator = {
39
40
  return isFuture || withoutSuffix ? wordKey[0] : wordKey[1];
40
41
  }
41
42
 
42
- const word = translator.correctGrammaticalCase(number, wordKey);
43
+ word = translator.correctGrammaticalCase(number, wordKey);
43
44
  // Nominativ
44
45
  if (key === 'yy' && withoutSuffix && word === 'годину') {
45
46
  return number + ' година';
@@ -31,7 +31,8 @@ var translator = {
31
31
  return wordKey[2];
32
32
  },
33
33
  translate: function (number, withoutSuffix, key, isFuture) {
34
- var wordKey = translator.words[key];
34
+ var wordKey = translator.words[key],
35
+ word;
35
36
 
36
37
  if (key.length === 1) {
37
38
  // Nominativ
@@ -39,7 +40,7 @@ var translator = {
39
40
  return isFuture || withoutSuffix ? wordKey[0] : wordKey[1];
40
41
  }
41
42
 
42
- const word = translator.correctGrammaticalCase(number, wordKey);
43
+ word = translator.correctGrammaticalCase(number, wordKey);
43
44
  // Nominativ
44
45
  if (key === 'yy' && withoutSuffix && word === 'godinu') {
45
46
  return number + ' godina';
@@ -1,5 +1,5 @@
1
1
  //! moment.js
2
- //! version : 2.29.2
2
+ //! version : 2.29.4
3
3
  //! authors : Tim Wood, Iskren Chernev, Moment.js contributors
4
4
  //! license : MIT
5
5
  //! momentjs.com
@@ -2448,7 +2448,7 @@ function untruncateYear(yearStr) {
2448
2448
  function preprocessRFC2822(s) {
2449
2449
  // Remove comments and folding whitespace and replace multiple-spaces with a single space
2450
2450
  return s
2451
- .replace(/\([^)]*\)|[\n\t]/g, ' ')
2451
+ .replace(/\([^()]*\)|[\n\t]/g, ' ')
2452
2452
  .replace(/(\s\s+)/g, ' ')
2453
2453
  .replace(/^\s\s*/, '')
2454
2454
  .replace(/\s\s*$/, '');
@@ -5629,7 +5629,7 @@ addParseToken('x', function (input, array, config) {
5629
5629
 
5630
5630
  //! moment.js
5631
5631
 
5632
- hooks.version = '2.29.2';
5632
+ hooks.version = '2.29.4';
5633
5633
 
5634
5634
  setHookCallback(createLocal);
5635
5635
 
@@ -38,7 +38,8 @@
38
38
  return wordKey[2];
39
39
  },
40
40
  translate: function (number, withoutSuffix, key, isFuture) {
41
- var wordKey = translator.words[key];
41
+ var wordKey = translator.words[key],
42
+ word;
42
43
 
43
44
  if (key.length === 1) {
44
45
  // Nominativ
@@ -46,7 +47,7 @@
46
47
  return isFuture || withoutSuffix ? wordKey[0] : wordKey[1];
47
48
  }
48
49
 
49
- const word = translator.correctGrammaticalCase(number, wordKey);
50
+ word = translator.correctGrammaticalCase(number, wordKey);
50
51
  // Nominativ
51
52
  if (key === 'yy' && withoutSuffix && word === 'годину') {
52
53
  return number + ' година';
@@ -38,7 +38,8 @@
38
38
  return wordKey[2];
39
39
  },
40
40
  translate: function (number, withoutSuffix, key, isFuture) {
41
- var wordKey = translator.words[key];
41
+ var wordKey = translator.words[key],
42
+ word;
42
43
 
43
44
  if (key.length === 1) {
44
45
  // Nominativ
@@ -46,7 +47,7 @@
46
47
  return isFuture || withoutSuffix ? wordKey[0] : wordKey[1];
47
48
  }
48
49
 
49
- const word = translator.correctGrammaticalCase(number, wordKey);
50
+ word = translator.correctGrammaticalCase(number, wordKey);
50
51
  // Nominativ
51
52
  if (key === 'yy' && withoutSuffix && word === 'godinu') {
52
53
  return number + ' godina';
@@ -10097,7 +10097,8 @@
10097
10097
  return wordKey[2];
10098
10098
  },
10099
10099
  translate: function (number, withoutSuffix, key, isFuture) {
10100
- var wordKey = translator$1.words[key];
10100
+ var wordKey = translator$1.words[key],
10101
+ word;
10101
10102
 
10102
10103
  if (key.length === 1) {
10103
10104
  // Nominativ
@@ -10105,7 +10106,7 @@
10105
10106
  return isFuture || withoutSuffix ? wordKey[0] : wordKey[1];
10106
10107
  }
10107
10108
 
10108
- const word = translator$1.correctGrammaticalCase(number, wordKey);
10109
+ word = translator$1.correctGrammaticalCase(number, wordKey);
10109
10110
  // Nominativ
10110
10111
  if (key === 'yy' && withoutSuffix && word === 'годину') {
10111
10112
  return number + ' година';
@@ -10219,7 +10220,8 @@
10219
10220
  return wordKey[2];
10220
10221
  },
10221
10222
  translate: function (number, withoutSuffix, key, isFuture) {
10222
- var wordKey = translator$2.words[key];
10223
+ var wordKey = translator$2.words[key],
10224
+ word;
10223
10225
 
10224
10226
  if (key.length === 1) {
10225
10227
  // Nominativ
@@ -10227,7 +10229,7 @@
10227
10229
  return isFuture || withoutSuffix ? wordKey[0] : wordKey[1];
10228
10230
  }
10229
10231
 
10230
- const word = translator$2.correctGrammaticalCase(number, wordKey);
10232
+ word = translator$2.correctGrammaticalCase(number, wordKey);
10231
10233
  // Nominativ
10232
10234
  if (key === 'yy' && withoutSuffix && word === 'godinu') {
10233
10235
  return number + ' godina';