@contrast/agent 4.7.0 → 4.7.1

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 (76) hide show
  1. package/bin/VERSION +1 -1
  2. package/bin/linux/contrast-service +0 -0
  3. package/bin/mac/contrast-service +0 -0
  4. package/bin/windows/contrast-service.exe +0 -0
  5. package/lib/assess/membrane/deserialization-membrane.js +4 -5
  6. package/lib/assess/membrane/source-membrane.js +15 -19
  7. package/lib/assess/models/call-context.js +1 -1
  8. package/lib/assess/policy/propagators.json +8 -0
  9. package/lib/assess/policy/rules.json +2 -2
  10. package/lib/assess/policy/signatures.json +27 -0
  11. package/lib/assess/policy/util.js +2 -1
  12. package/lib/assess/propagators/JSON/parse.js +1 -1
  13. package/lib/assess/propagators/JSON/stringify.js +3 -3
  14. package/lib/assess/propagators/array-prototype-join.js +7 -8
  15. package/lib/assess/propagators/common.js +7 -5
  16. package/lib/assess/propagators/handlebars-escape-expresssion.js +1 -1
  17. package/lib/assess/propagators/joi/boolean.js +1 -1
  18. package/lib/assess/propagators/joi/expression.js +1 -1
  19. package/lib/assess/propagators/joi/number.js +1 -1
  20. package/lib/assess/propagators/joi/string-base.js +1 -1
  21. package/lib/assess/propagators/joi/string-schema.js +12 -13
  22. package/lib/assess/propagators/joi/values.js +11 -11
  23. package/lib/assess/propagators/manager.js +12 -10
  24. package/lib/assess/propagators/mongoose/helpers.js +20 -0
  25. package/lib/assess/propagators/mongoose/index.js +18 -0
  26. package/lib/assess/propagators/mongoose/map.js +74 -0
  27. package/lib/assess/propagators/mongoose/string.js +104 -0
  28. package/lib/assess/propagators/number.js +54 -0
  29. package/lib/assess/propagators/object.js +6 -7
  30. package/lib/assess/propagators/path/basename.js +14 -13
  31. package/lib/assess/propagators/path/common.js +1 -1
  32. package/lib/assess/propagators/path/dirname.js +14 -13
  33. package/lib/assess/propagators/path/extname.js +14 -13
  34. package/lib/assess/propagators/path/parse.js +1 -1
  35. package/lib/assess/propagators/path/relative.js +7 -5
  36. package/lib/assess/propagators/querystring/escape.js +20 -18
  37. package/lib/assess/propagators/querystring/parse.js +7 -5
  38. package/lib/assess/propagators/querystring/stringify.js +25 -24
  39. package/lib/assess/propagators/querystring/unescape.js +20 -18
  40. package/lib/assess/propagators/sequelize/sql-string-escape.js +1 -1
  41. package/lib/assess/propagators/sequelize/sql-string-format-named-parameters.js +1 -1
  42. package/lib/assess/propagators/sequelize/sql-string-format.js +3 -3
  43. package/lib/assess/propagators/sequelize/utils.js +2 -2
  44. package/lib/assess/propagators/string-prototype-replace.js +30 -28
  45. package/lib/assess/propagators/string-prototype-split.js +36 -36
  46. package/lib/assess/propagators/string-prototype-trim.js +15 -17
  47. package/lib/assess/propagators/string.js +12 -16
  48. package/lib/assess/propagators/template-escape.js +21 -18
  49. package/lib/assess/propagators/templates.js +8 -8
  50. package/lib/assess/propagators/url/url-prototype-parse.js +5 -6
  51. package/lib/assess/propagators/url/url-url.js +51 -43
  52. package/lib/assess/propagators/util/format.js +1 -1
  53. package/lib/assess/propagators/v8/init-hooks.js +3 -3
  54. package/lib/assess/propagators/validator/init-hooks.js +22 -22
  55. package/lib/assess/sinks/common.js +10 -5
  56. package/lib/assess/sinks/libxmljs-xxe.js +1 -1
  57. package/lib/assess/sinks/mongodb.js +2 -1
  58. package/lib/assess/sinks/ssrf-url.js +1 -1
  59. package/lib/constants.js +4 -1
  60. package/lib/core/config/options.js +1 -1
  61. package/lib/core/rewrite/injections.js +8 -0
  62. package/lib/feature-set.js +1 -1
  63. package/lib/hooks/object-to-primitive.js +6 -7
  64. package/lib/hooks/patcher.js +1 -1
  65. package/lib/protect/rules/nosqli/nosql-injection-rule.js +228 -0
  66. package/lib/protect/rules/rule-factory.js +2 -2
  67. package/lib/protect/service.js +23 -11
  68. package/lib/protect/sinks/mongodb.js +56 -55
  69. package/lib/reporter/translations/to-protobuf/dtm/index.js +1 -1
  70. package/lib/reporter/translations/to-protobuf/dtm/ip-denylist-details.js +1 -1
  71. package/lib/reporter/translations/to-protobuf/dtm/rasp-rule-sample.js +1 -1
  72. package/lib/reporter/translations/to-protobuf/settings/defend-features.js +8 -6
  73. package/lib/reporter/translations/to-protobuf/settings/exclusions.js +5 -4
  74. package/lib/tracker.js +13 -65
  75. package/package.json +2 -1
  76. package/lib/protect/rules/nosqli/no-sql-injection-rule.js +0 -109
package/bin/VERSION CHANGED
@@ -1 +1 @@
1
- 2.28.0
1
+ 2.28.5
Binary file
Binary file
Binary file
@@ -58,19 +58,18 @@ class DeserializationMembrane extends Membrane {
58
58
  });
59
59
 
60
60
  const tracked = tracker.track(str);
61
- const strData = tracker.getData(tracked);
62
61
 
63
- if (!strData.tracked) {
62
+ if (!tracked) {
64
63
  return str;
65
64
  }
66
65
 
67
- strData.event = event;
66
+ tracked.props.event = event;
68
67
  event.parents.push(this.event);
69
- strData.tagRanges = this.tagRanges.map(
68
+ tracked.props.tagRanges = this.tagRanges.map(
70
69
  (t) => new TagRange(0, str.length - 1, t.tag)
71
70
  );
72
71
 
73
- return tracked;
72
+ return tracked.str;
74
73
  }
75
74
  }
76
75
 
@@ -13,7 +13,6 @@ Copyright: 2021 Contrast Security, Inc
13
13
  way not consistent with the End User License Agreement.
14
14
  */
15
15
  'use strict';
16
- const _ = require('lodash');
17
16
 
18
17
  const logger = require('../../core/logger')('contrast:source-membrane');
19
18
  const Membrane = require('./index');
@@ -64,9 +63,7 @@ module.exports = class SourceMembrane extends Membrane {
64
63
  if (cfg.array_request_sampling) {
65
64
  this.sample = cfg.array_request_sampling.enable;
66
65
  this.sampleThreshold = cfg.array_request_sampling.threshold;
67
- this.sampleInterval = this.sample
68
- ? cfg.array_request_sampling.interval
69
- : 1;
66
+ this.sampleInterval = cfg.array_request_sampling.interval || 1;
70
67
  }
71
68
  // used when a reqSourceEvent must be created because an entire object
72
69
  // is being stringified but individual properties are not being referenced
@@ -139,7 +136,7 @@ module.exports = class SourceMembrane extends Membrane {
139
136
  if (!this.ensureMetadata(metadata)) {
140
137
  return str;
141
138
  }
142
- const tracked = tracker.track2(str);
139
+ const tracked = tracker.track(str);
143
140
  if (!tracked) {
144
141
  return str;
145
142
  }
@@ -355,11 +352,6 @@ module.exports = class SourceMembrane extends Membrane {
355
352
  wrapArray(arr, metadata) {
356
353
  metadata.isArray = true;
357
354
 
358
- // if not sampling, treat it as any object. not sampling has 100%
359
- // accuracy.
360
- if (!this.sample) {
361
- return super.wrapArray(arr, metadata);
362
- }
363
355
  // don't sample more than once
364
356
  if (this.wrappedArrays.has(arr)) {
365
357
  return arr;
@@ -367,16 +359,20 @@ module.exports = class SourceMembrane extends Membrane {
367
359
 
368
360
  const limit = Math.min(this.sampleThreshold, arr.length);
369
361
 
370
- for (let i = 0; i < limit; i++) {
371
- if (i % this.sampleInterval === 0 && arr[i]) {
372
- const m = _.cloneDeep(metadata);
373
- if (m.path) {
374
- m.path += `[${i}]`;
375
- } else {
376
- m.path = `[${i}]`;
362
+ // if not sampling, treat it as any object. not sampling has 100% accuracy.
363
+ if (!this.sample || (limit === arr.length && this.sampleInterval === 1)) {
364
+ return super.wrapObject(arr, metadata);
365
+ } else if (!this.sampleThreshold) {
366
+ return arr;
367
+ } else {
368
+ const origPath = metadata.path;
369
+ for (let i = 0; i < limit; i += this.sampleInterval) {
370
+ if (arr[i]) {
371
+ const m = Object.assign({}, metadata);
372
+ m.path = origPath ? `${origPath}[${i}]` : `[${i}]`;
373
+ const wrapped = this.wrap(arr[i], m);
374
+ arr[i] = wrapped;
377
375
  }
378
-
379
- arr[i] = this.wrap(arr[i], m);
380
376
  }
381
377
  }
382
378
 
@@ -96,7 +96,7 @@ module.exports = class CallContext {
96
96
  }
97
97
 
98
98
  static isTracked(str) {
99
- if (tracker.getData2(str)) {
99
+ if (tracker.getData(str)) {
100
100
  return true;
101
101
  }
102
102
  return !!(str && typeof str === 'object' && str[PROXY_TARGET]);
@@ -40,10 +40,18 @@
40
40
  "enabled": true,
41
41
  "override": "./propagators/JSON/parse.js"
42
42
  },
43
+ "mongoose": {
44
+ "enabled": true,
45
+ "override": "./propagators/mongoose"
46
+ },
43
47
  "String": {
44
48
  "enabled": true,
45
49
  "override": "./propagators/string.js"
46
50
  },
51
+ "Number": {
52
+ "enabled": true,
53
+ "override": "./propagators/number.js"
54
+ },
47
55
  "Object": {
48
56
  "enabled": true,
49
57
  "override": "./propagators/object.js"
@@ -1157,7 +1157,7 @@
1157
1157
  "args": [
1158
1158
  {
1159
1159
  "index": 0,
1160
- "disallowedTags": ["limited-chars", "alphanum-space-hyphen"],
1160
+ "disallowedTags": ["limited-chars", "alphanum-space-hyphen", "custom-validated-nosql-injection"],
1161
1161
  "requiredTags": ["untrusted"]
1162
1162
  }
1163
1163
  ]
@@ -1172,7 +1172,7 @@
1172
1172
  "args": [
1173
1173
  {
1174
1174
  "index": 0,
1175
- "disallowedTags": [],
1175
+ "disallowedTags": ["custom-validated-nosql-injection"],
1176
1176
  "requiredTags": ["untrusted"]
1177
1177
  }
1178
1178
  ]
@@ -20,6 +20,11 @@
20
20
  "methodName": "domainToUnicode",
21
21
  "isModule": true
22
22
  },
23
+ "template strings": {
24
+ "moduleName": "global",
25
+ "methodName": "ContrastMethods.__contrastTag",
26
+ "isModule": false
27
+ },
23
28
  "axios": {
24
29
  "moduleName": "axios",
25
30
  "methodName": "",
@@ -642,6 +647,11 @@
642
647
  "methodName": "toNamespacedPath",
643
648
  "isModule": true
644
649
  },
650
+ "path.normalize": {
651
+ "moduleName": "path",
652
+ "methodName": "normalize",
653
+ "isModule": true
654
+ },
645
655
  "util.format": {
646
656
  "moduleName": "util",
647
657
  "methodName": "format",
@@ -1308,6 +1318,18 @@
1308
1318
  "methodName": "string.domain",
1309
1319
  "isModule": true
1310
1320
  },
1321
+ "mongoose.string.doValidateSync": {
1322
+ "moduleName": "mongoose",
1323
+ "version": ">=5.0.0",
1324
+ "methodName": "mongoose.string.doValidateSync",
1325
+ "isModule": true
1326
+ },
1327
+ "mongoose.map.doValidateSync": {
1328
+ "moduleName": "mongoose",
1329
+ "version": ">=5.0.0",
1330
+ "methodName": "mongoose.map.doValidateSync",
1331
+ "isModule": true
1332
+ },
1311
1333
  "v8.deserialize.serialize": {
1312
1334
  "moduleName": "v8",
1313
1335
  "methodName": "deserialize.serialize",
@@ -1322,6 +1344,11 @@
1322
1344
  "moduleName": "dustjs-linkedin",
1323
1345
  "methodName": "pipe",
1324
1346
  "isModule": true
1347
+ },
1348
+ "Number": {
1349
+ "moduleName": "Number",
1350
+ "methodName": "isNaN",
1351
+ "isModule": false
1325
1352
  }
1326
1353
  }
1327
1354
  }
@@ -89,6 +89,7 @@ utils.isRuleEnabled = function(ruleId) {
89
89
  * @param {boolean} enabled What to set the enabled property to
90
90
  */
91
91
  utils.setEnabled = function(node, enabled) {
92
+ /*eslint no-prototype-builtins: "warn"*/
92
93
  if (node.hasOwnProperty('enabled')) {
93
94
  node.enabled = enabled;
94
95
  return true;
@@ -236,7 +237,7 @@ utils.patchRecursive = function(obj, hookOptions, depth) {
236
237
  }
237
238
  }
238
239
  } catch (e) {
239
- logger.info(`unable to recurisvely patch ${e}`);
240
+ logger.info(`unable to recursively patch ${e}`);
240
241
  }
241
242
 
242
243
  return obj;
@@ -41,7 +41,7 @@ module.exports.handle = function() {
41
41
  name: ContrastJSON.name,
42
42
  patchType: PATCH_TYPES.ASSESS_PROPAGATOR,
43
43
  post(data) {
44
- const props = tracker.getData2(data.args[0]);
44
+ const props = tracker.getData(data.args[0]);
45
45
  const { result } = data;
46
46
  if (props && result) {
47
47
  const membrane = new DeserializationMembrane(data, props);
@@ -64,7 +64,7 @@ function getUntrustedSpaceProps(space) {
64
64
  }
65
65
  // otherwise if the space string is tracked then the entire json output inherits
66
66
  // the tracked string's tags.
67
- const props = tracker.getData2(space);
67
+ const props = tracker.getData(space);
68
68
  if (!props || props.tagRanges.length === 0) {
69
69
  return null;
70
70
  }
@@ -185,7 +185,7 @@ module.exports.handle = function() {
185
185
  */
186
186
  function contrastReplacer(key, val) {
187
187
  let isTracked = false;
188
- const valProperties = tracker.getData2(val);
188
+ const valProperties = tracker.getData(val);
189
189
  if (valProperties && valProperties.tagRanges.length) {
190
190
  data.metadata.propagate = true;
191
191
  isTracked = true;
@@ -256,7 +256,7 @@ module.exports.handle = function() {
256
256
  }
257
257
  }
258
258
 
259
- const tracked = tracker.track2(data.result);
259
+ const tracked = tracker.track(data.result);
260
260
  if (!tracked) {
261
261
  return data.result;
262
262
  }
@@ -27,7 +27,7 @@ module.exports.handle = function handle(data) {
27
27
  return;
28
28
  }
29
29
 
30
- // this handles join() andd join(undefined)
30
+ // this handles join() and join(undefined)
31
31
  const del = data.args[0] === undefined ? ',' : data.args[0];
32
32
 
33
33
  const parentEvents = [];
@@ -38,7 +38,7 @@ module.exports.handle = function handle(data) {
38
38
 
39
39
  let delimiterTracked = false;
40
40
 
41
- if (delimiterProperties.tracked) {
41
+ if (delimiterProperties) {
42
42
  delimiterTracked = true;
43
43
  parentEvents.push(delimiterProperties.event);
44
44
  delimiterTagRanges.push(...delimiterProperties.tagRanges);
@@ -56,21 +56,20 @@ module.exports.handle = function handle(data) {
56
56
 
57
57
  if (delimiterTracked || elementTracked) {
58
58
  const tracked = tracker.track(data.result);
59
- const metadata = tracker.getData(tracked);
60
- if (!metadata.tracked) {
59
+ if (!tracked) {
61
60
  return;
62
61
  }
63
62
 
64
- metadata.event = createEvent(
63
+ tracked.props.event = createEvent(
65
64
  data,
66
65
  resultTagRanges,
67
66
  parentEvents,
68
67
  delimiterTracked,
69
68
  elementTracked
70
69
  );
71
- metadata.tagRanges = resultTagRanges;
70
+ tracked.props.tagRanges = resultTagRanges;
72
71
 
73
- data.result = tracked;
72
+ data.result = tracked.str;
74
73
  }
75
74
  };
76
75
 
@@ -98,7 +97,7 @@ function propagateArrayData(
98
97
  const elem = array[i];
99
98
  const elemProperties = tracker.getData(elem);
100
99
 
101
- if (elem && elemProperties.tracked) {
100
+ if (elem && elemProperties) {
102
101
  parentEvents.push(elemProperties.event);
103
102
 
104
103
  targetData.elementTracked = true;
@@ -62,7 +62,7 @@ const escapeRegExp = (str) => {
62
62
  */
63
63
  const addTagRangesWithOffset = (metadata, arg) => {
64
64
  const argData = tracker.getData(arg);
65
- if (argData.tracked) {
65
+ if (argData) {
66
66
  tagRangeUtil.addAllWithOffsetInPlace(
67
67
  metadata.tagRanges,
68
68
  argData.tagRanges,
@@ -115,10 +115,12 @@ const createEvent = ({ tagRanges, method, parents }, data) => {
115
115
  */
116
116
  const trackResult = (metadata, data) => {
117
117
  if (metadata.tagRanges.length) {
118
- data.result = tracker.track(data.result);
119
- const trackedMeta = tracker.getData(data.result);
120
- trackedMeta.tagRanges = metadata.tagRanges;
121
- trackedMeta.event = createEvent(metadata, data);
118
+ const tracked = tracker.track(data.result);
119
+ if (tracked) {
120
+ tracked.props.tagRanges = metadata.tagRanges;
121
+ tracked.props.event = createEvent(metadata, data);
122
+ data.result = tracked.str;
123
+ }
122
124
  }
123
125
  };
124
126
 
@@ -48,7 +48,7 @@ function patchUtilsExport(utilsExport) {
48
48
  alwaysRun: true,
49
49
  post(data) {
50
50
  const trackData = tracker.getData(data.result);
51
- if (trackData.tracked) {
51
+ if (trackData) {
52
52
  trackData.tagRanges = tagRangeUtil.add(
53
53
  trackData.tagRanges,
54
54
  new TagRange(0, data.result.length - 1, 'html-encoded')
@@ -42,7 +42,7 @@ function instrumentJoiBoolean(boolean) {
42
42
  if (
43
43
  data.result &&
44
44
  typeof data.result.value === 'boolean' &&
45
- trackingData.tracked
45
+ trackingData
46
46
  ) {
47
47
  const { event } = trackingData;
48
48
  trackingData.tagRanges = tagRangeUtil.add(
@@ -32,7 +32,7 @@ function instrumentJoiExpression(expression) {
32
32
  patchType: ASSESS_PROPAGATOR,
33
33
  post(data) {
34
34
  const trackingData = tracker.getData(data.args[0]);
35
- if (trackingData.tracked && data.result._template) {
35
+ if (trackingData && data.result._template) {
36
36
  trackingData.tagRanges = tagRangeUtil.add(
37
37
  trackingData.tagRanges,
38
38
  new TagRange(0, data.args[0].length - 1, 'html-encoded')
@@ -41,7 +41,7 @@ function instrumentJoiNumber(number) {
41
41
  data.result &&
42
42
  data.result.value &&
43
43
  !data.result.errors &&
44
- trackingData.tracked
44
+ trackingData
45
45
  ) {
46
46
  const { event } = trackingData;
47
47
  trackingData.tagRanges = tagRangeUtil.add(
@@ -37,7 +37,7 @@ function instrumentJoiString(string) {
37
37
  patchType: ASSESS_PROPAGATOR,
38
38
  post(data) {
39
39
  const trackingData = tracker.getData(data.args[0]);
40
- if (data.result === undefined && trackingData.tracked) {
40
+ if (data.result === undefined && trackingData) {
41
41
  const { event } = trackingData;
42
42
  trackingData.tagRanges = tagRangeUtil.add(
43
43
  trackingData.tagRanges,
@@ -79,29 +79,28 @@ function reTrackCoercedValue(coerce, rule) {
79
79
  }
80
80
 
81
81
  const argContrastProperties = tracker.getData(args[0]);
82
- if (!argContrastProperties.tracked) {
82
+ if (!argContrastProperties) {
83
83
  return;
84
84
  }
85
85
 
86
- const str = tracker.track(result.value);
87
- const strContrastProperties = tracker.getData(str);
86
+ const tracked = tracker.track(result.value);
88
87
 
89
- if (strContrastProperties.tracked) {
90
- strContrastProperties.tagRanges = tagRangeUtil.add(
91
- strContrastProperties.tagRanges,
92
- new TagRange(0, str.length - 1, 'untrusted')
88
+ if (tracked) {
89
+ tracked.props.tagRanges = tagRangeUtil.add(
90
+ tracked.props.tagRanges,
91
+ new TagRange(0, tracked.str.length - 1, 'untrusted')
93
92
  );
94
93
 
95
- strContrastProperties.event = createPropagationEvent({
94
+ tracked.props.event = createPropagationEvent({
96
95
  data,
97
96
  trackedArgsData: argContrastProperties,
98
- tagRanges: strContrastProperties.tagRanges,
97
+ tagRanges: tracked.props.tagRanges,
99
98
  target: 'R',
100
99
  joiMethod: rule
101
100
  });
102
- }
103
101
 
104
- data.result = { value: str };
102
+ data.result = { value: tracked.str };
103
+ }
105
104
  }
106
105
  });
107
106
  }
@@ -120,13 +119,13 @@ function wrapRuleAsValidator(rules, rule, tagName) {
120
119
  }
121
120
 
122
121
  const argContrastProperties = tracker.getData(args[0]);
123
- if (!argContrastProperties.tracked) {
122
+ if (!argContrastProperties) {
124
123
  return;
125
124
  }
126
125
 
127
126
  const strContrastProperties = tracker.getData(result);
128
127
 
129
- if (strContrastProperties.tracked) {
128
+ if (strContrastProperties) {
130
129
  strContrastProperties.tagRanges = tagRangeUtil.add(
131
130
  strContrastProperties.tagRanges,
132
131
  new TagRange(0, result.length - 1, tagName)
@@ -41,7 +41,7 @@ function instrumentJoiValues(values) {
41
41
  name: 'joi.values',
42
42
  patchType: ASSESS_PROPAGATOR,
43
43
  post(data) {
44
- const {
44
+ let {
45
45
  args: [value],
46
46
  result
47
47
  } = data;
@@ -55,7 +55,7 @@ function instrumentJoiValues(values) {
55
55
  handler(result.value, value, data);
56
56
  } else if (_.isString(result.value)) {
57
57
  // use case is .valid() - safe
58
- tracker.untrack(result.value);
58
+ result.value = tracker.untrack(result.value) || result.value;
59
59
  }
60
60
  }
61
61
  });
@@ -94,14 +94,14 @@ const handler = (resultValue, argValue, data) => {
94
94
  */
95
95
  function getRefHandler(resolvedTrackData, refTrackData) {
96
96
  // 4 Cases
97
- if (!resolvedTrackData.tracked) {
98
- if (!refTrackData.tracked) {
97
+ if (!resolvedTrackData) {
98
+ if (!refTrackData) {
99
99
  return null;
100
100
  } else {
101
101
  return handleRefOnlyTracked;
102
102
  }
103
103
  } else {
104
- if (refTrackData.tracked) {
104
+ if (refTrackData) {
105
105
  return handleBothTracked;
106
106
  } else {
107
107
  return handleTargetOnlyTracked;
@@ -131,7 +131,7 @@ function handleTargetOnlyTracked(data, resolvedTrackData, refTrackData) {
131
131
  * @param {object} refTrackData tracking data for reference value
132
132
  */
133
133
  function handleBothTracked(data, resolvedTrackData, refTrackData) {
134
- const {
134
+ let {
135
135
  args: [value, , prefs],
136
136
  result
137
137
  } = data;
@@ -142,8 +142,8 @@ function handleBothTracked(data, resolvedTrackData, refTrackData) {
142
142
  }
143
143
 
144
144
  if (result.ref.map) {
145
- tracker.untrack(data.result.value);
146
- tracker.untrack(value);
145
+ data.result.value = tracker.untrack(data.result.value) || data.result.value;
146
+ value = tracker.untrack(value) || value;
147
147
  } else {
148
148
  copyValidationHistory(resolvedTrackData, refTrackData);
149
149
  if (prefs.convert) {
@@ -160,7 +160,7 @@ function handleBothTracked(data, resolvedTrackData, refTrackData) {
160
160
  * @param {object} refTrackData tracking data for reference value
161
161
  */
162
162
  function handleRefOnlyTracked(data, resolvedTrackData, refTrackData) {
163
- const {
163
+ let {
164
164
  args: [value, , prefs],
165
165
  result
166
166
  } = data;
@@ -179,8 +179,8 @@ function handleRefOnlyTracked(data, resolvedTrackData, refTrackData) {
179
179
  } else {
180
180
  // if map is used we can trust - like .valid()
181
181
  if (result.ref.map) {
182
- if (!tracker.getData(result.value).tracked) {
183
- tracker.untrack(value);
182
+ if (!tracker.getData(result.value)) {
183
+ value = tracker.untrack(value) || value;
184
184
  }
185
185
  } else {
186
186
  logger.debug(
@@ -112,13 +112,14 @@ module.exports = function Propagator(agent, propagationDescriptor) {
112
112
 
113
113
  // move the tags to the result of propagator
114
114
  if (event.tagRanges.length > 0 && validTarget === data.result) {
115
- data.result = tracker.track(data.result);
116
- const resultContrastProperties = tracker.getData(data.result);
117
- resultContrastProperties.tracked = true;
118
- resultContrastProperties.tagRanges = event.tagRanges;
115
+ const tracked = tracker.track(data.result);
116
+ if (tracked) {
117
+ tracked.props.tagRanges = event.tagRanges;
118
+ tracked.props.event = event;
119
+ data.result = tracked.str;
120
+ }
119
121
 
120
122
  event.parents.push(...sourceEvents);
121
- resultContrastProperties.event = event;
122
123
  }
123
124
  logger.trace('%s2%s %s --> %s', source, target, sources, [validTarget]);
124
125
  };
@@ -206,7 +207,7 @@ function createAppendTagRanges(data) {
206
207
  if (isString(data.obj)) {
207
208
  offset = data.obj.length;
208
209
  const sourceProps = tracker.getData(data.obj);
209
- if (sourceProps.tracked) {
210
+ if (sourceProps) {
210
211
  tagRangeUtil.addAllInPlace(newTags, sourceProps.tagRanges);
211
212
  }
212
213
  }
@@ -214,7 +215,7 @@ function createAppendTagRanges(data) {
214
215
  for (const arg of data.args) {
215
216
  if (arg) {
216
217
  const props = tracker.getData(arg);
217
- if (props.tracked) {
218
+ if (props) {
218
219
  tagRangeUtil.addAllWithOffsetInPlace(newTags, props.tagRanges, offset);
219
220
  }
220
221
 
@@ -339,7 +340,7 @@ function getSourcesMetadata(sources) {
339
340
  function isSourceTracked(sourceName, source) {
340
341
  if (source) {
341
342
  const contrastProperties = tracker.getData(source);
342
- return contrastProperties.tracked;
343
+ return !!contrastProperties;
343
344
  }
344
345
 
345
346
  return false;
@@ -384,7 +385,7 @@ function getTrackedSources(sources, skipNested) {
384
385
  function isTargetTracked(target, hasTags) {
385
386
  if (hasTags) {
386
387
  const contrastProperties = tracker.getData(target);
387
- return contrastProperties.tracked;
388
+ return !!contrastProperties;
388
389
  }
389
390
 
390
391
  return false;
@@ -457,7 +458,8 @@ function getValidSources(sources) {
457
458
  const sourceContrastProperties = tracker.getData(source);
458
459
  if (
459
460
  isString(source) &&
460
- !(sourceContrastProperties && sourceContrastProperties.tracked)
461
+ (!sourceContrastProperties ||
462
+ (sourceContrastProperties && !sourceContrastProperties.tracked))
461
463
  ) {
462
464
  return false;
463
465
  }
@@ -0,0 +1,20 @@
1
+ /**
2
+ Copyright: 2021 Contrast Security, Inc
3
+ Contact: support@contrastsecurity.com
4
+ License: Commercial
5
+
6
+ NOTICE: This Software and the patented inventions embodied within may only be
7
+ used as part of Contrast Security’s commercial offerings. Even though it is
8
+ made available through public repositories, use of this Software is subject to
9
+ the applicable End User Licensing Agreement found at
10
+ https://www.contrastsecurity.com/enduser-terms-0317a or as otherwise agreed
11
+ between Contrast Security and the End User. The Software may not be reverse
12
+ engineered, modified, repackaged, sold, redistributed or otherwise used in a
13
+ way not consistent with the End User License Agreement.
14
+ */
15
+ const hasUserDefinedValidator = (data) =>
16
+ data.obj.validators.some((validator) => validator.type === 'user defined');
17
+
18
+ module.exports = {
19
+ hasUserDefinedValidator
20
+ };
@@ -0,0 +1,18 @@
1
+ /**
2
+ Copyright: 2021 Contrast Security, Inc
3
+ Contact: support@contrastsecurity.com
4
+ License: Commercial
5
+
6
+ NOTICE: This Software and the patented inventions embodied within may only be
7
+ used as part of Contrast Security’s commercial offerings. Even though it is
8
+ made available through public repositories, use of this Software is subject to
9
+ the applicable End User Licensing Agreement found at
10
+ https://www.contrastsecurity.com/enduser-terms-0317a or as otherwise agreed
11
+ between Contrast Security and the End User. The Software may not be reverse
12
+ engineered, modified, repackaged, sold, redistributed or otherwise used in a
13
+ way not consistent with the End User License Agreement.
14
+ */
15
+ module.exports.handle = () => {
16
+ require('./map');
17
+ require('./string');
18
+ };