@contrast/assess 1.28.0 → 1.29.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 (81) hide show
  1. package/lib/crypto-analysis/install/crypto.js +3 -3
  2. package/lib/dataflow/propagation/install/JSON/parse-fn.js +5 -5
  3. package/lib/dataflow/propagation/install/JSON/parse.js +3 -3
  4. package/lib/dataflow/propagation/install/JSON/stringify.js +24 -17
  5. package/lib/dataflow/propagation/install/array-prototype-join.js +3 -3
  6. package/lib/dataflow/propagation/install/buffer.js +60 -2
  7. package/lib/dataflow/propagation/install/contrast-methods/add.js +1 -3
  8. package/lib/dataflow/propagation/install/ejs/template.js +3 -3
  9. package/lib/dataflow/propagation/install/joi/boolean.js +1 -1
  10. package/lib/dataflow/propagation/install/joi/expression.js +1 -1
  11. package/lib/dataflow/propagation/install/joi/index.js +1 -1
  12. package/lib/dataflow/propagation/install/joi/keys.js +5 -4
  13. package/lib/dataflow/propagation/install/joi/number.js +1 -1
  14. package/lib/dataflow/propagation/install/joi/string-schema.js +3 -2
  15. package/lib/dataflow/propagation/install/joi/utils.js +9 -5
  16. package/lib/dataflow/propagation/install/joi/values.js +4 -3
  17. package/lib/dataflow/propagation/install/mongoose/schema-map.js +2 -2
  18. package/lib/dataflow/propagation/install/mongoose/schema-mixed.js +2 -2
  19. package/lib/dataflow/propagation/install/mongoose/schema-string.js +2 -2
  20. package/lib/dataflow/propagation/install/path/basename.js +2 -2
  21. package/lib/dataflow/propagation/install/path/common.js +5 -5
  22. package/lib/dataflow/propagation/install/path/format.js +7 -4
  23. package/lib/dataflow/propagation/install/path/join-and-resolve.js +2 -2
  24. package/lib/dataflow/propagation/install/path/parse.js +4 -5
  25. package/lib/dataflow/propagation/install/querystring/escape.js +1 -1
  26. package/lib/dataflow/propagation/install/querystring/parse.js +8 -8
  27. package/lib/dataflow/propagation/install/querystring/stringify.js +1 -1
  28. package/lib/dataflow/propagation/install/reg-exp-prototype-exec.js +2 -3
  29. package/lib/dataflow/propagation/install/send.js +2 -2
  30. package/lib/dataflow/propagation/install/string/concat.js +19 -19
  31. package/lib/dataflow/propagation/install/string/html-methods.js +1 -1
  32. package/lib/dataflow/propagation/install/string/index.js +4 -3
  33. package/lib/dataflow/propagation/install/string/match-all.js +3 -9
  34. package/lib/dataflow/propagation/install/string/match.js +6 -5
  35. package/lib/dataflow/propagation/install/string/replace.js +23 -17
  36. package/lib/dataflow/propagation/install/string/slice.js +5 -5
  37. package/lib/dataflow/propagation/install/string/split.js +13 -11
  38. package/lib/dataflow/propagation/install/string/substring.js +6 -5
  39. package/lib/dataflow/propagation/install/url/parse.js +1 -1
  40. package/lib/dataflow/propagation/install/url/searchParams.js +2 -1
  41. package/lib/dataflow/propagation/install/url/url.js +1 -1
  42. package/lib/dataflow/sinks/index.js +1 -0
  43. package/lib/dataflow/sinks/install/child-process.js +4 -4
  44. package/lib/dataflow/sinks/install/express/reflected-xss.js +7 -5
  45. package/lib/dataflow/sinks/install/express/unvalidated-redirect.js +1 -2
  46. package/lib/dataflow/sinks/install/fastify/unvalidated-redirect.js +1 -3
  47. package/lib/dataflow/sinks/install/fs.js +3 -3
  48. package/lib/dataflow/sinks/install/function.js +3 -3
  49. package/lib/dataflow/sinks/install/hapi/unvalidated-redirect.js +1 -2
  50. package/lib/dataflow/sinks/install/http/request.js +6 -5
  51. package/lib/dataflow/sinks/install/koa/unvalidated-redirect.js +2 -2
  52. package/lib/dataflow/sinks/install/libxmljs.js +1 -1
  53. package/lib/dataflow/sinks/install/marsdb.js +1 -2
  54. package/lib/dataflow/sinks/install/mongodb.js +1 -1
  55. package/lib/dataflow/sinks/install/mysql.js +1 -1
  56. package/lib/dataflow/sinks/install/postgres.js +1 -3
  57. package/lib/dataflow/sinks/install/restify.js +208 -0
  58. package/lib/dataflow/sinks/install/sequelize.js +1 -2
  59. package/lib/dataflow/sinks/install/vm.js +5 -5
  60. package/lib/dataflow/sources/handler.js +2 -2
  61. package/lib/dataflow/sources/index.js +1 -0
  62. package/lib/dataflow/sources/install/http.js +4 -4
  63. package/lib/dataflow/sources/install/restify/fieldedTextBodyParser.js +85 -0
  64. package/lib/dataflow/sources/install/restify/index.js +32 -0
  65. package/lib/dataflow/sources/install/restify/jsonBodyParser.js +109 -0
  66. package/lib/dataflow/sources/install/restify/router.js +77 -0
  67. package/lib/dataflow/tag-utils.js +20 -4
  68. package/lib/dataflow/tracker.js +1 -0
  69. package/lib/event-factory.js +3 -3
  70. package/lib/get-policy.js +2 -2
  71. package/lib/index.d.ts +18 -0
  72. package/lib/index.js +13 -0
  73. package/lib/make-source-context.js +2 -2
  74. package/lib/response-scanning/handlers/index.js +10 -10
  75. package/lib/response-scanning/handlers/utils.js +19 -12
  76. package/lib/response-scanning/install/http.js +9 -59
  77. package/lib/session-configuration/install/express-session.js +3 -5
  78. package/lib/session-configuration/install/fastify-cookie.js +3 -3
  79. package/lib/session-configuration/install/hapi.js +1 -3
  80. package/lib/session-configuration/install/koa.js +1 -1
  81. package/package.json +4 -4
@@ -15,7 +15,14 @@
15
15
 
16
16
  'use strict';
17
17
 
18
- const { join, substring, toLowerCase, split, trim, replace } = require('@contrast/common');
18
+ const {
19
+ ArrayPrototypeJoin,
20
+ StringPrototypeSubstring,
21
+ StringPrototypeToLowerCase,
22
+ StringPrototypeSplit,
23
+ StringPrototypeTrim,
24
+ StringPrototypeReplace
25
+ } = require('@contrast/common');
19
26
 
20
27
  //
21
28
  // General HTML utils
@@ -32,7 +39,7 @@ const reHasUnescapedHtml = RegExp(reUnescapedHtml.source);
32
39
 
33
40
  function escapeHtml(string) {
34
41
  return (string && reHasUnescapedHtml.test(string))
35
- ? replace(string, reUnescapedHtml, (chr) => htmlEscapes[chr])
42
+ ? StringPrototypeReplace.call(string, reUnescapedHtml, (chr) => htmlEscapes[chr])
36
43
  : (string || '');
37
44
  }
38
45
 
@@ -54,7 +61,7 @@ function getElements(htmlTag, content = '') {
54
61
  [htmlTagRangeStart, htmlTagRangeLength] = getHtmlTagRange(htmlTag, content, offset);
55
62
  if (htmlTagRangeStart >= 0) {
56
63
  offset = htmlTagRangeStart + htmlTagRangeLength;
57
- elements.push(substring(content, htmlTagRangeStart, offset));
64
+ elements.push(StringPrototypeSubstring.call(content, htmlTagRangeStart, offset));
58
65
  }
59
66
  } while (htmlTagRangeStart >= 0);
60
67
 
@@ -69,7 +76,7 @@ function isHtmlContent(responseHeaders) {
69
76
  }
70
77
 
71
78
  // we may want to do a case-insensitive search through object keys here
72
- const contentType = toLowerCase(responseHeaders['Content-Type'] || responseHeaders['content-type'] || '');
79
+ const contentType = StringPrototypeToLowerCase.call(responseHeaders['Content-Type'] || responseHeaders['content-type'] || '');
73
80
 
74
81
  return (
75
82
  !contentType ||
@@ -88,7 +95,7 @@ function isParseableResponse(responseHeaders) {
88
95
  // we may want to do a case-insensitive search through object keys here
89
96
  let contentType =
90
97
  responseHeaders['Content-Type'] || responseHeaders['content-type'];
91
- if (contentType) contentType = toLowerCase(contentType);
98
+ if (contentType) contentType = StringPrototypeToLowerCase.call(contentType);
92
99
 
93
100
  return (
94
101
  !contentType ||
@@ -123,7 +130,7 @@ function getAttribute(attribute, htmlTag = '') {
123
130
  }
124
131
  }
125
132
 
126
- return substring(htmlTag, attrStart, attrEnd);
133
+ return StringPrototypeSubstring.call(htmlTag, attrStart, attrEnd);
127
134
  }
128
135
 
129
136
  /**
@@ -213,16 +220,16 @@ function checkCacheControlValue(value = '') {
213
220
  let noStore = false;
214
221
 
215
222
  value.forEach((directive) => {
216
- if (toLowerCase(directive).includes('no-cache')) {
223
+ if (StringPrototypeToLowerCase.call(directive).includes('no-cache')) {
217
224
  noCache = true;
218
225
  }
219
- if (toLowerCase(directive).includes('no-store')) {
226
+ if (StringPrototypeToLowerCase.call(directive).includes('no-store')) {
220
227
  noStore = true;
221
228
  }
222
229
  });
223
230
  return [noCache, noStore];
224
231
  } else {
225
- value = toLowerCase(value);
232
+ value = StringPrototypeToLowerCase.call(value);
226
233
  return [value.includes('no-cache'), value.includes('no-store')];
227
234
  }
228
235
  }
@@ -317,7 +324,7 @@ function formatSource({
317
324
  }
318
325
 
319
326
  data[`${key}Secure`] = isSecure;
320
- data[`${key}Value`] = join(sources, ' ');
327
+ data[`${key}Value`] = ArrayPrototypeJoin.call(sources, ' ');
321
328
  }
322
329
 
323
330
  /**
@@ -325,8 +332,8 @@ function formatSource({
325
332
  */
326
333
  function policyParser(policy) {
327
334
  const result = {};
328
- for (const directive of split(policy, ';')) {
329
- const [directiveKey, ...directiveValue] = split(trim(directive), /\s+/g);
335
+ for (const directive of StringPrototypeSplit.call(policy, ';')) {
336
+ const [directiveKey, ...directiveValue] = StringPrototypeSplit.call(StringPrototypeTrim.call(directive), /\s+/g);
330
337
  if (
331
338
  directiveKey &&
332
339
  !Object.prototype.hasOwnProperty.call(result, directiveKey)
@@ -15,7 +15,7 @@
15
15
 
16
16
  'use strict';
17
17
 
18
- const { split, substring, toLowerCase, trim } = require('@contrast/common');
18
+ const { StringPrototypeSplit, StringPrototypeSubstring, StringPrototypeToLowerCase, StringPrototypeTrim } = require('@contrast/common');
19
19
 
20
20
  /**
21
21
  * @param {{
@@ -46,13 +46,13 @@ module.exports = function(core) {
46
46
 
47
47
  function parseHeaders(rawHeaders) {
48
48
  const headersToParse = rawHeaders || '';
49
- const headersArray = split(headersToParse, '\r\n').filter(Boolean);
49
+ const headersArray = StringPrototypeSplit.call(headersToParse, '\r\n').filter(Boolean);
50
50
  return headersArray.reduce((acc, header) => {
51
51
  const idx = header.indexOf(':');
52
52
 
53
53
  if (idx > -1) {
54
- const name = toLowerCase(substring(header, 0, idx));
55
- const value = trim(substring(header, idx + 1));
54
+ const name = StringPrototypeToLowerCase.call(StringPrototypeSubstring.call(header, 0, idx));
55
+ const value = StringPrototypeTrim.call(StringPrototypeSubstring.call(header, idx + 1));
56
56
  const currentValue = acc[name];
57
57
  acc[name] = currentValue
58
58
  ? Array.isArray(currentValue)
@@ -100,7 +100,7 @@ module.exports = function(core) {
100
100
  if (!sourceContext) return;
101
101
 
102
102
  const evaluationContext = {
103
- responseBody: toLowerCase(data.args[0] || ''),
103
+ responseBody: StringPrototypeToLowerCase.call(data.args[0] || ''),
104
104
  responseHeaders: parseHeaders(data.result._header),
105
105
  };
106
106
 
@@ -118,7 +118,7 @@ module.exports = function(core) {
118
118
  if (!sourceContext) return;
119
119
 
120
120
  const evaluationContext = {
121
- responseBody: toLowerCase(data.args[0] || ''),
121
+ responseBody: StringPrototypeToLowerCase.call(data.args[0] || ''),
122
122
  responseHeaders: parseHeaders(data.result._header),
123
123
  };
124
124
 
@@ -141,7 +141,7 @@ module.exports = function(core) {
141
141
 
142
142
  const headersSymbol = Object.getOwnPropertySymbols(data.obj).find(symbol => symbol.toString().includes('headers'));
143
143
  const evaluationContext = {
144
- responseBody: toLowerCase(data.args[0] || ''),
144
+ responseBody: StringPrototypeToLowerCase.call(data.args[0] || ''),
145
145
  responseHeaders: data.obj[headersSymbol],
146
146
  };
147
147
 
@@ -160,7 +160,7 @@ module.exports = function(core) {
160
160
 
161
161
  const headersSymbol = Object.getOwnPropertySymbols(data.result).find(symbol => symbol.toString().includes('headers'));
162
162
  const evaluationContext = {
163
- responseBody: toLowerCase(data.args[0] || ''),
163
+ responseBody: StringPrototypeToLowerCase.call(data.args[0] || ''),
164
164
  responseHeaders: data.result[headersSymbol],
165
165
  };
166
166
 
@@ -169,57 +169,7 @@ module.exports = function(core) {
169
169
  });
170
170
  }
171
171
 
172
- // patching the stream object
173
- ['createServer', 'createSecureServer'].forEach((server) => {
174
- patcher.patch(http2, server, {
175
- name: `http2.${server}`,
176
- patchType,
177
- post(data) {
178
- // The other option is once again to patch the `emit` method of the server
179
- // similar to how we patch it for creating sources, but take action only on
180
- // `stream` events. I chose the currentt approach because the hook will only
181
- // run on a `stream` event instead of checking and returning on each `request`
182
- // connect.
183
- data.result._events = patcher.patch(data.result._events, 'stream', {
184
- name: 'stream',
185
- patchType: 'stream-patch',
186
- pre(data) {
187
- patcher.patch(data.args[0], 'write', {
188
- name: 'Http2Stream.write',
189
- patchType,
190
- post(data) {
191
- const sourceContext = getSourceContext();
192
- if (!sourceContext) return;
193
-
194
- const evaluationContext = {
195
- responseBody: toLowerCase(data.args[0] || ''),
196
- responseHeaders: data.obj.sentHeaders,
197
- };
198
-
199
- writeHookChecks(sourceContext, evaluationContext);
200
- }
201
- });
202
-
203
- patcher.patch(data.args[0], 'end', {
204
- name: 'Http2Stream.end',
205
- patchType,
206
- post(data) {
207
- const sourceContext = getSourceContext();
208
- if (!sourceContext) return;
209
-
210
- const evaluationContext = {
211
- responseBody: toLowerCase(data.args[0] || ''),
212
- responseHeaders: data.obj.sentHeaders,
213
- };
214
-
215
- endHookChecks(sourceContext, evaluationContext);
216
- }
217
- });
218
- }
219
- });
220
- }
221
- });
222
- });
172
+ // todo: patching the stream object (NODE-3467)
223
173
  });
224
174
  };
225
175
 
@@ -14,8 +14,7 @@
14
14
  */
15
15
  'use strict';
16
16
 
17
- const util = require('util');
18
- const { toLowerCase } = require('@contrast/common');
17
+ const { StringPrototypeToLowerCase } = require('@contrast/common');
19
18
  const { patchType } = require('../common');
20
19
 
21
20
  /**
@@ -27,6 +26,7 @@ const { patchType } = require('../common');
27
26
  module.exports = function (core) {
28
27
  const {
29
28
  assess: {
29
+ inspect, // todo: remove
30
30
  getSourceContext,
31
31
  eventFactory: { createSessionEvent },
32
32
  sessionConfiguration: {
@@ -40,8 +40,6 @@ module.exports = function (core) {
40
40
 
41
41
  const expressSession = core.assess.sessionConfiguration.expressSession = {};
42
42
 
43
- const inspect = patcher.unwrap(util.inspect);
44
-
45
43
  expressSession.install = function () {
46
44
  return depHooks.resolve({ name: 'express-session' }, (session) => {
47
45
  // Return the hooked function as the export.
@@ -104,7 +102,7 @@ module.exports = function (core) {
104
102
  name: 'http.setHeader',
105
103
  patchType,
106
104
  pre({ args: [key, value] }) {
107
- if (toLowerCase(key) !== 'set-cookie') return;
105
+ if (StringPrototypeToLowerCase.call(key) !== 'set-cookie') return;
108
106
 
109
107
  if (checkForHTTPOnly) {
110
108
  handleHttpOnly(sourceContext, value, sessionEvent);
@@ -14,8 +14,7 @@
14
14
  */
15
15
  'use strict';
16
16
 
17
- const { inspect } = require('util');
18
- const { toLowerCase } = require('@contrast/common');
17
+ const { StringPrototypeToLowerCase } = require('@contrast/common');
19
18
  const { patchType } = require('../common');
20
19
 
21
20
  /**
@@ -27,6 +26,7 @@ const { patchType } = require('../common');
27
26
  module.exports = function (core) {
28
27
  const {
29
28
  assess: {
29
+ inspect, // todo: remove
30
30
  getSourceContext,
31
31
  eventFactory: { createSessionEvent },
32
32
  sessionConfiguration: {
@@ -82,7 +82,7 @@ module.exports = function (core) {
82
82
  name: 'fastify.Reply.header',
83
83
  pre(data) {
84
84
  const [key, value] = data.args;
85
- if (toLowerCase(key) !== 'set-cookie') return;
85
+ if (StringPrototypeToLowerCase.call(key) !== 'set-cookie') return;
86
86
 
87
87
  const sourceContext = getSourceContext();
88
88
  if (!sourceContext) return;
@@ -14,12 +14,12 @@
14
14
  */
15
15
  'use strict';
16
16
 
17
- const util = require('util');
18
17
  const { patchType } = require('../common');
19
18
 
20
19
  module.exports = function (core) {
21
20
  const {
22
21
  assess: {
22
+ inspect, // todo: remove
23
23
  eventFactory: { createSessionEvent },
24
24
  sessionConfiguration: {
25
25
  handleHttpOnly,
@@ -33,8 +33,6 @@ module.exports = function (core) {
33
33
 
34
34
  const hapiSession = core.assess.sessionConfiguration.hapiSession = {};
35
35
 
36
- const inspect = patcher.unwrap(util.inspect);
37
-
38
36
  hapiSession.install = function () {
39
37
  return depHooks.resolve({ name: '@hapi/hapi', version: '>=18 <22' }, (hapi) => {
40
38
  ['server', 'Server'].forEach((server) => {
@@ -14,7 +14,6 @@
14
14
  */
15
15
  'use strict';
16
16
 
17
- const { inspect } = require('util');
18
17
  const { patchType } = require('../common');
19
18
 
20
19
  /**
@@ -26,6 +25,7 @@ const { patchType } = require('../common');
26
25
  module.exports = function (core) {
27
26
  const {
28
27
  assess: {
28
+ inspect, // todo: remove
29
29
  getSourceContext,
30
30
  eventFactory: { createSessionEvent },
31
31
  sessionConfiguration: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@contrast/assess",
3
- "version": "1.28.0",
3
+ "version": "1.29.0",
4
4
  "description": "Contrast service providing framework-agnostic Assess support",
5
5
  "license": "SEE LICENSE IN LICENSE",
6
6
  "author": "Contrast Security <nodejs@contrastsecurity.com> (https://www.contrastsecurity.com)",
@@ -11,14 +11,14 @@
11
11
  "types": "lib/index.d.ts",
12
12
  "engines": {
13
13
  "npm": ">=6.13.7 <7 || >= 8.3.1",
14
- "node": ">= 14.18.0"
14
+ "node": ">= 16.9.1"
15
15
  },
16
16
  "scripts": {
17
17
  "test": "../scripts/test.sh"
18
18
  },
19
19
  "dependencies": {
20
- "@contrast/common": "1.21.0",
21
- "@contrast/distringuish": "^4.4.0",
20
+ "@contrast/common": "1.21.1",
21
+ "@contrast/distringuish": "^5.0.0",
22
22
  "@contrast/scopes": "1.4.1"
23
23
  }
24
24
  }