@contrast/assess 1.31.0 → 1.32.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 (154) hide show
  1. package/lib/crypto-analysis/install/crypto.test.js +146 -0
  2. package/lib/crypto-analysis/install/math.test.js +65 -0
  3. package/lib/dataflow/index.test.js +36 -0
  4. package/lib/dataflow/propagation/index.test.js +103 -0
  5. package/lib/dataflow/propagation/install/JSON/index.test.js +50 -0
  6. package/lib/dataflow/propagation/install/JSON/parse-fn.test.js +232 -0
  7. package/lib/dataflow/propagation/install/JSON/parse.test.js +968 -0
  8. package/lib/dataflow/propagation/install/JSON/stringify.test.js +265 -0
  9. package/lib/dataflow/propagation/install/array-prototype-join.test.js +106 -0
  10. package/lib/dataflow/propagation/install/buffer.test.js +109 -0
  11. package/lib/dataflow/propagation/install/contrast-methods/add.test.js +94 -0
  12. package/lib/dataflow/propagation/install/contrast-methods/index.test.js +49 -0
  13. package/lib/dataflow/propagation/install/contrast-methods/number.test.js +50 -0
  14. package/lib/dataflow/propagation/install/contrast-methods/string.test.js +148 -0
  15. package/lib/dataflow/propagation/install/contrast-methods/tag.test.js +145 -0
  16. package/lib/dataflow/propagation/install/decode-uri-component.test.js +78 -0
  17. package/lib/dataflow/propagation/install/ejs/escape-xml.test.js +69 -0
  18. package/lib/dataflow/propagation/install/ejs/template.test.js +62 -0
  19. package/lib/dataflow/propagation/install/encode-uri.test.js +83 -0
  20. package/lib/dataflow/propagation/install/escape-html.test.js +71 -0
  21. package/lib/dataflow/propagation/install/escape.test.js +73 -0
  22. package/lib/dataflow/propagation/install/handlebars-utils-escape-expression.test.js +71 -0
  23. package/lib/dataflow/propagation/install/isnumeric-0.test.js +58 -0
  24. package/lib/dataflow/propagation/install/joi/any.test.js +270 -0
  25. package/lib/dataflow/propagation/install/joi/array.test.js +912 -0
  26. package/lib/dataflow/propagation/install/joi/boolean.test.js +103 -0
  27. package/lib/dataflow/propagation/install/joi/expression.test.js +76 -0
  28. package/lib/dataflow/propagation/install/joi/index.test.js +39 -0
  29. package/lib/dataflow/propagation/install/joi/number.test.js +103 -0
  30. package/lib/dataflow/propagation/install/joi/object.test.js +119 -0
  31. package/lib/dataflow/propagation/install/joi/ref.test.js +607 -0
  32. package/lib/dataflow/propagation/install/joi/string-schema.test.js +513 -0
  33. package/lib/dataflow/propagation/install/mongoose/index.test.js +42 -0
  34. package/lib/dataflow/propagation/install/mongoose/schema-map.test.js +348 -0
  35. package/lib/dataflow/propagation/install/mongoose/schema-mixed.test.js +512 -0
  36. package/lib/dataflow/propagation/install/mongoose/schema-string.test.js +160 -0
  37. package/lib/dataflow/propagation/install/mustache-escape.test.js +62 -0
  38. package/lib/dataflow/propagation/install/mysql-connection-escape.test.js +74 -0
  39. package/lib/dataflow/propagation/install/parse-int.test.js +48 -0
  40. package/lib/dataflow/propagation/install/path/basename.test.js +143 -0
  41. package/lib/dataflow/propagation/install/path/dirname.test.js +167 -0
  42. package/lib/dataflow/propagation/install/path/extname.test.js +141 -0
  43. package/lib/dataflow/propagation/install/path/format.test.js +250 -0
  44. package/lib/dataflow/propagation/install/path/index.test.js +45 -0
  45. package/lib/dataflow/propagation/install/path/join-and-resolve.test.js +485 -0
  46. package/lib/dataflow/propagation/install/path/normalize.test.js +176 -0
  47. package/lib/dataflow/propagation/install/path/parse.test.js +238 -0
  48. package/lib/dataflow/propagation/install/path/relative.test.js +239 -0
  49. package/lib/dataflow/propagation/install/path/toNamespacedPath.test.js +158 -0
  50. package/lib/dataflow/propagation/install/pug/index.test.js +55 -0
  51. package/lib/dataflow/propagation/install/pug-runtime-escape.test.js +69 -0
  52. package/lib/dataflow/propagation/install/querystring/escape.test.js +63 -0
  53. package/lib/dataflow/propagation/install/querystring/index.test.js +40 -0
  54. package/lib/dataflow/propagation/install/querystring/parse.test.js +272 -0
  55. package/lib/dataflow/propagation/install/querystring/stringify.test.js +301 -0
  56. package/lib/dataflow/propagation/install/reg-exp-prototype-exec.test.js +281 -0
  57. package/lib/dataflow/propagation/install/send.test.js +63 -0
  58. package/lib/dataflow/propagation/install/sequelize/query-generator.test.js +73 -0
  59. package/lib/dataflow/propagation/install/sequelize/sql-string.test.js +130 -0
  60. package/lib/dataflow/propagation/install/sql-template-strings.test.js +100 -0
  61. package/lib/dataflow/propagation/install/string/concat.test.js +132 -0
  62. package/lib/dataflow/propagation/install/string/format-methods.test.js +61 -0
  63. package/lib/dataflow/propagation/install/string/html-methods.test.js +164 -0
  64. package/lib/dataflow/propagation/install/string/index.test.js +103 -0
  65. package/lib/dataflow/propagation/install/string/match-all.test.js +399 -0
  66. package/lib/dataflow/propagation/install/string/match.test.js +361 -0
  67. package/lib/dataflow/propagation/install/string/replace.test.js +588 -0
  68. package/lib/dataflow/propagation/install/string/slice.test.js +265 -0
  69. package/lib/dataflow/propagation/install/string/split.test.js +500 -0
  70. package/lib/dataflow/propagation/install/string/substring.test.js +238 -0
  71. package/lib/dataflow/propagation/install/string/trim.test.js +122 -0
  72. package/lib/dataflow/propagation/install/unescape.test.js +78 -0
  73. package/lib/dataflow/propagation/install/url/domain-parsers.test.js +63 -0
  74. package/lib/dataflow/propagation/install/url/parse.test.js +391 -0
  75. package/lib/dataflow/propagation/install/url/searchParams.test.js +538 -0
  76. package/lib/dataflow/propagation/install/url/url.test.js +466 -0
  77. package/lib/dataflow/propagation/install/util-format.test.js +336 -0
  78. package/lib/dataflow/propagation/install/validator/hooks.test.js +211 -0
  79. package/lib/dataflow/sinks/index.test.js +78 -0
  80. package/lib/dataflow/sinks/install/child-process.test.js +338 -0
  81. package/lib/dataflow/sinks/install/eval.test.js +95 -0
  82. package/lib/dataflow/sinks/install/express/index.test.js +33 -0
  83. package/lib/dataflow/sinks/install/express/reflected-xss.js +55 -57
  84. package/lib/dataflow/sinks/install/express/reflected-xss.test.js +109 -0
  85. package/lib/dataflow/sinks/install/express/unvalidated-redirect.test.js +144 -0
  86. package/lib/dataflow/sinks/install/fastify/index.test.js +32 -0
  87. package/lib/dataflow/sinks/install/fastify/unvalidated-redirect.test.js +130 -0
  88. package/lib/dataflow/sinks/install/fs.test.js +138 -0
  89. package/lib/dataflow/sinks/install/function.test.js +103 -0
  90. package/lib/dataflow/sinks/install/hapi/index.test.js +32 -0
  91. package/lib/dataflow/sinks/install/hapi/unvalidated-redirect.test.js +130 -0
  92. package/lib/dataflow/sinks/install/http/index.test.js +33 -0
  93. package/lib/dataflow/sinks/install/http/request.test.js +184 -0
  94. package/lib/dataflow/sinks/install/http/server-response.test.js +162 -0
  95. package/lib/dataflow/sinks/install/koa/index.test.js +32 -0
  96. package/lib/dataflow/sinks/install/koa/unvalidated-redirect.test.js +200 -0
  97. package/lib/dataflow/sinks/install/libxmljs.test.js +158 -0
  98. package/lib/dataflow/sinks/install/marsdb.test.js +166 -0
  99. package/lib/dataflow/sinks/install/mongodb.test.js +621 -0
  100. package/lib/dataflow/sinks/install/mssql.test.js +136 -0
  101. package/lib/dataflow/sinks/install/mysql.test.js +233 -0
  102. package/lib/dataflow/sinks/install/node-serialize.test.js +85 -0
  103. package/lib/dataflow/sinks/install/postgres.test.js +158 -0
  104. package/lib/dataflow/sinks/install/restify.test.js +142 -0
  105. package/lib/dataflow/sinks/install/sequelize.test.js +100 -0
  106. package/lib/dataflow/sinks/install/sqlite3.test.js +118 -0
  107. package/lib/dataflow/sinks/install/vm.test.js +326 -0
  108. package/lib/dataflow/sources/handler.test.js +463 -0
  109. package/lib/dataflow/sources/index.test.js +58 -0
  110. package/lib/dataflow/sources/install/body-parser1.test.js +248 -0
  111. package/lib/dataflow/sources/install/busboy.test.js +152 -0
  112. package/lib/dataflow/sources/install/cookie-parser1.test.js +143 -0
  113. package/lib/dataflow/sources/install/express/params.test.js +105 -0
  114. package/lib/dataflow/sources/install/express/parsedUrl.test.js +65 -0
  115. package/lib/dataflow/sources/install/fastify/fastify.test.js +210 -0
  116. package/lib/dataflow/sources/install/fastify/index.test.js +33 -0
  117. package/lib/dataflow/sources/install/formidable1.test.js +119 -0
  118. package/lib/dataflow/sources/install/hapi/hapi.test.js +172 -0
  119. package/lib/dataflow/sources/install/hapi/index.test.js +33 -0
  120. package/lib/dataflow/sources/install/http.test.js +155 -0
  121. package/lib/dataflow/sources/install/koa/index.test.js +40 -0
  122. package/lib/dataflow/sources/install/koa/koa-bodyparsers.test.js +161 -0
  123. package/lib/dataflow/sources/install/koa/koa-multer.test.js +197 -0
  124. package/lib/dataflow/sources/install/koa/koa-routers.test.js +146 -0
  125. package/lib/dataflow/sources/install/koa/koa2.test.js +145 -0
  126. package/lib/dataflow/sources/install/multer1.test.js +145 -0
  127. package/lib/dataflow/sources/install/qs6.test.js +131 -0
  128. package/lib/dataflow/sources/install/querystring.test.js +82 -0
  129. package/lib/dataflow/sources/install/restify/fieldedTextBodyParser.test.js +88 -0
  130. package/lib/dataflow/sources/install/restify/index.test.js +38 -0
  131. package/lib/dataflow/sources/install/restify/jsonBodyParser.test.js +144 -0
  132. package/lib/dataflow/sources/install/restify/router.test.js +83 -0
  133. package/lib/dataflow/tag-utils-complete.test.js +27 -0
  134. package/lib/dataflow/tag-utils.test.js +192 -0
  135. package/lib/dataflow/tracker.test.js +216 -0
  136. package/lib/dataflow/utils/is-safe-content-type.test.js +16 -0
  137. package/lib/dataflow/utils/is-vulnerable.test.js +115 -0
  138. package/lib/event-factory.test.js +321 -0
  139. package/lib/get-policy.test.js +194 -0
  140. package/lib/get-source-context.test.js +108 -0
  141. package/lib/index.test.js +41 -0
  142. package/lib/make-source-context.test.js +50 -0
  143. package/lib/response-scanning/handlers/index.test.js +425 -0
  144. package/lib/response-scanning/handlers/utils.test.js +391 -0
  145. package/lib/response-scanning/index.test.js +41 -0
  146. package/lib/response-scanning/install/http.test.js +175 -0
  147. package/lib/rule-scopes.test.js +27 -0
  148. package/lib/session-configuration/handlers.test.js +84 -0
  149. package/lib/session-configuration/index.test.js +36 -0
  150. package/lib/session-configuration/install/express-session.test.js +220 -0
  151. package/lib/session-configuration/install/fastify-cookie.test.js +65 -0
  152. package/lib/session-configuration/install/hapi.test.js +269 -0
  153. package/lib/session-configuration/install/koa.test.js +92 -0
  154. package/package.json +2 -2
@@ -0,0 +1,607 @@
1
+ 'use strict';
2
+
3
+ const { expect } = require('chai');
4
+ const { initAssessFixture } = require('@contrast/test/fixtures');
5
+ const { DataflowTag } = require('@contrast/common');
6
+
7
+ describe('assess dataflow propagation joi string and ref', function() {
8
+ let core, joi, tracker, trackString, simulateRequestScope;
9
+
10
+ beforeEach(function() {
11
+ ({ core, simulateRequestScope, trackString } = initAssessFixture());
12
+ tracker = core.assess.dataflow.tracker;
13
+
14
+ core.depHooks.resolve.withArgs({ name: 'joi', file: 'lib/types/string.js', version: '>=17.0.0' }).yields(require('joi-17/lib/types/string'));
15
+ core.depHooks.resolve.withArgs({ name: 'joi', file: 'lib/types/keys.js', version: '>=17.0.0' }).yields(require('joi-17/lib/types/keys'));
16
+ core.depHooks.resolve.withArgs({ name: 'joi', file: 'lib/validator', version: '>=17.0.0' }).yields(require('joi-17/lib/validator'));
17
+ core.depHooks.resolve.withArgs({ name: 'joi', file: 'lib/values.js', version: '>=17.0.0' }).yields(require('joi-17/lib/values'));
18
+
19
+ require('./index')(core).install();
20
+ joi = require('joi-17');
21
+ });
22
+
23
+ afterEach(function() {
24
+ Object.keys(require.cache).forEach((key) => {
25
+ if (key.includes('joi')) {
26
+ delete require.cache[key];
27
+ }
28
+ });
29
+ });
30
+
31
+ describe('Validator tests for joi/lib/ref.js', function() {
32
+ const schemaMethods = ['object', 'object.keys'];
33
+
34
+ /**
35
+ * Builds a schema to be used in tests. Returns joi.object(data) or
36
+ * object().keys(data) based on `methods` arg.
37
+ * @param {string} methods dot-delimited path e.g. object or object.keys
38
+ * @param {object} schemaData data used to make schema
39
+ * @returns {object} the schema instance
40
+ */
41
+ function getSchema(methods, schemaData) {
42
+ return methods
43
+ .split('.')
44
+ .reduce(
45
+ (acc, method, i, arr) =>
46
+ acc[method](i === arr.length - 1 ? schemaData : undefined),
47
+ joi
48
+ );
49
+ }
50
+
51
+ schemaMethods.forEach((methods) => {
52
+ it(`untracked refs of tracked values will not be tracked (${methods})`, function() {
53
+ simulateRequestScope(() => {
54
+ const schema = getSchema(methods, {
55
+ a: joi.string().guid(),
56
+ b: joi.ref('a'),
57
+ });
58
+ const data = {
59
+ a: trackString('fa2cdd9e-7eb0-4bb0-a37d-ddd4d9b23265'),
60
+ b: 'fa2cdd9e-7eb0-4bb0-a37d-ddd4d9b23265',
61
+ };
62
+
63
+ const result = schema.validate(data, { convert: false });
64
+ // result
65
+ makeAssertions(tracker.getData(result.value.a));
66
+ expect(tracker.getData(result.value.b)).to.be.null;
67
+ // orig (target: A)
68
+ makeAssertions(tracker.getData(data.a));
69
+ // validation outcome
70
+ expect(result.errors).to.be.undefined;
71
+ });
72
+ });
73
+
74
+ it(`untracked refs of tracked values will not be tracked (nested) (${methods})`, function() {
75
+ simulateRequestScope(() => {
76
+ const schema = getSchema(methods, {
77
+ a: { aa: joi.string().guid() },
78
+ b: joi.ref('a.aa'),
79
+ c: { cc: { ccc: joi.ref('....a.aa') } },
80
+ });
81
+ const data = {
82
+ a: { aa: trackString('fa2cdd9e-7eb0-4bb0-a37d-ddd4d9b23265') },
83
+ b: 'fa2cdd9e-7eb0-4bb0-a37d-ddd4d9b23265',
84
+ c: { cc: { ccc: 'fa2cdd9e-7eb0-4bb0-a37d-ddd4d9b23265' } },
85
+ };
86
+
87
+ const result = schema.validate(data, { convert: false });
88
+
89
+ // validation outcome
90
+ expect(result.errors).to.be.undefined;
91
+ // result
92
+ expect(tracker.getData(result.value.b)).to.be.null;
93
+ expect(tracker.getData(result.value.c.cc.ccc)).to.be.null;
94
+ makeAssertions(tracker.getData(result.value.a.aa));
95
+ // orig (target: A)
96
+ makeAssertions(tracker.getData(data.a.aa));
97
+ });
98
+ });
99
+
100
+ it(`tracked refs of tracked values should not be tracked when convert: true and mapped value is untracked (${methods})`, function() {
101
+ simulateRequestScope(() => {
102
+ const schema = getSchema(methods, {
103
+ a: joi.string().guid(),
104
+ b: joi.ref('a', {
105
+ map: [['fa2cdd9e-7eb0-4bb0-a37d-ddd4d9b23265', 'foo']],
106
+ }),
107
+ });
108
+ const data = {
109
+ a: trackString('fa2cdd9e-7eb0-4bb0-a37d-ddd4d9b23265'),
110
+ b: trackString('foo'),
111
+ };
112
+
113
+ const result = schema.validate(data, { convert: true });
114
+
115
+ // validation outcome
116
+ expect(result.errors).to.be.undefined;
117
+ // result
118
+ makeAssertions(tracker.getData(result.value.a));
119
+ expect(tracker.getData(result.value.b)).to.be.null;
120
+ // orig (target: A)
121
+ makeAssertions(tracker.getData(data.a));
122
+ // orig 'b' value's untracked as it's equal to an untracked value
123
+ expect(tracker.getData(data.b)).to.be.null;
124
+ });
125
+ });
126
+
127
+ it(`tracked refs of tracked values should not be tracked when convert: false and mapped value is untracked (${methods})`, function() {
128
+ simulateRequestScope(() => {
129
+ const schema = getSchema(methods, {
130
+ a: joi.string().guid(),
131
+ b: joi.ref('a', {
132
+ map: [['fa2cdd9e-7eb0-4bb0-a37d-ddd4d9b23265', 'foo']],
133
+ }),
134
+ });
135
+ const data = {
136
+ a: 'fa2cdd9e-7eb0-4bb0-a37d-ddd4d9b23265',
137
+ b: trackString('foo'),
138
+ };
139
+
140
+ const result = schema.validate(data, { convert: false });
141
+
142
+ // result
143
+ expect(tracker.getData(result.value.a)).to.be.null;
144
+ expect(tracker.getData(result.value.b)).to.be.null;
145
+ // orig
146
+ expect(tracker.getData(data.b)).to.be.null;
147
+ // validation outcome
148
+ expect(result.errors).to.be.undefined;
149
+ });
150
+ });
151
+
152
+ it(`tracked refs of tracked values should also be validated (${methods})`, function(done) {
153
+ simulateRequestScope(() => {
154
+ const schema = getSchema(methods, {
155
+ a: joi.string().guid(),
156
+ b: joi.ref('a'),
157
+ });
158
+ const data = {
159
+ a: trackString(
160
+ 'fa2cdd9e-7eb0-4bb0-a37d-ddd4d9b23265'
161
+ ),
162
+ b: trackString(
163
+ 'fa2cdd9e-7eb0-4bb0-a37d-ddd4d9b23265',
164
+ {
165
+ tags: {
166
+ [DataflowTag.UNTRUSTED]: [0, 35],
167
+ [DataflowTag.CUSTOM]: [0, 35]
168
+ }
169
+ }
170
+ ),
171
+ };
172
+
173
+ // Check with validateAsync to make sure it works too
174
+ schema.validateAsync(data, {
175
+ convert: true,
176
+ abortEarly: false,
177
+ })
178
+ .then((result) => {
179
+ // result
180
+ makeAssertions(tracker.getData(result.a));
181
+ makeAssertions(tracker.getData(result.b));
182
+ // orig (target: A)
183
+ makeAssertions(tracker.getData(data.a));
184
+ makeAssertions(tracker.getData(data.b), {
185
+ tags: {
186
+ [DataflowTag.UNTRUSTED]: [0, 35],
187
+ [DataflowTag.CUSTOM]: [0, 35],
188
+ [DataflowTag.ALPHANUM_SPACE_HYPHEN]: [0, 35],
189
+ [DataflowTag.STRING_TYPE_CHECKED]: [0, 35]
190
+ },
191
+ });
192
+ done();
193
+ })
194
+ .catch(err => done(err));
195
+ });
196
+ });
197
+
198
+ it(`tracked refs of tracked values should also be partially validated even if overall validation fails, { convert: true } (${methods})`, function() {
199
+ simulateRequestScope(() => {
200
+ const schema = getSchema(methods, {
201
+ a: joi.string().guid(),
202
+ b: joi.ref('a'),
203
+ });
204
+ // The last character of these guids are invalid, BUT the string() schema
205
+ // validation should still apply the string-type-checked tag
206
+ const data = {
207
+ a: trackString(
208
+ 'fa2cdd9e-7eb0-4bb0-a37d-ddd4d9b2326-'
209
+ ),
210
+ b: trackString(
211
+ 'fa2cdd9e-7eb0-4bb0-a37d-ddd4d9b2326-',
212
+ {
213
+ tags: {
214
+ [DataflowTag.UNTRUSTED]: [0, 35],
215
+ [DataflowTag.CUSTOM]: [0, 35]
216
+ }
217
+ }
218
+ ),
219
+ };
220
+
221
+ // We need abortEarly in order to have joi continue to validate ref,
222
+ // although the full validation of the target key fails
223
+ const result = schema.validate(data, {
224
+ convert: true,
225
+ abortEarly: false,
226
+ });
227
+
228
+ const overrides = {
229
+ name: 'Joi.string.validate',
230
+ tags: {
231
+ [DataflowTag.UNTRUSTED]: [0, 35],
232
+ [DataflowTag.STRING_TYPE_CHECKED]: [0, 35]
233
+ },
234
+ methodName: 'string.validate'
235
+ };
236
+
237
+ // validation outcome
238
+ expect(result.error.details[0].message).to.equal(
239
+ '"a" must be a valid GUID'
240
+ );
241
+ // result
242
+ makeAssertions(tracker.getData(result.value.a), overrides);
243
+ makeAssertions(tracker.getData(result.value.b), overrides);
244
+ // orig (target: A)
245
+ makeAssertions(tracker.getData(data.a), overrides);
246
+ makeAssertions(tracker.getData(data.b), {
247
+ ...overrides,
248
+ tags: {
249
+ [DataflowTag.UNTRUSTED]: [0, 35],
250
+ [DataflowTag.CUSTOM]: [0, 35],
251
+ [DataflowTag.STRING_TYPE_CHECKED]: [0, 35]
252
+ },
253
+ });
254
+ });
255
+ });
256
+
257
+ it(`tracked refs of tracked values should also be partially validated even if overall validation fails, { convert: false } (${methods})`, function() {
258
+ simulateRequestScope(() => {
259
+ const schema = getSchema(methods, {
260
+ a: joi.string().guid(),
261
+ b: joi.ref('a'),
262
+ });
263
+ // The last character of these guids are invalid, BUT the string() schema
264
+ // validation should still apply the string-type-checked tag
265
+ const data = {
266
+ a: trackString(
267
+ 'fa2cdd9e-7eb0-4bb0-a37d-ddd4d9b2326-'
268
+ ),
269
+ b: trackString(
270
+ 'fa2cdd9e-7eb0-4bb0-a37d-ddd4d9b2326-',
271
+ {
272
+ tags: {
273
+ [DataflowTag.UNTRUSTED]: [0, 35],
274
+ [DataflowTag.CUSTOM]: [0, 35]
275
+ }
276
+ }
277
+ ),
278
+ };
279
+
280
+ // We need abortEarly in order to have joi continue to validate ref,
281
+ // although the full validation of the target key fails
282
+ const result = schema.validate(data, {
283
+ convert: false,
284
+ abortEarly: false,
285
+ });
286
+
287
+ const overrides = {
288
+ name: 'Joi.string.validate',
289
+ tags: {
290
+ [DataflowTag.UNTRUSTED]: [0, 35],
291
+ [DataflowTag.STRING_TYPE_CHECKED]: [0, 35]
292
+ },
293
+ methodName: 'string.validate'
294
+ };
295
+
296
+ // validation outcome
297
+ expect(result.error.details[0].message).to.equal(
298
+ '"a" must be a valid GUID'
299
+ );
300
+ // result
301
+ makeAssertions(tracker.getData(result.value.a), overrides);
302
+ makeAssertions(tracker.getData(result.value.b), {
303
+ ...overrides,
304
+ tags: {
305
+ [DataflowTag.UNTRUSTED]: [0, 35],
306
+ [DataflowTag.CUSTOM]: [0, 35],
307
+ [DataflowTag.STRING_TYPE_CHECKED]: [0, 35]
308
+ },
309
+ });
310
+ // orig (target: A)
311
+ makeAssertions(tracker.getData(data.a), overrides);
312
+ makeAssertions(tracker.getData(data.b), {
313
+ ...overrides,
314
+ tags: {
315
+ [DataflowTag.UNTRUSTED]: [0, 35],
316
+ [DataflowTag.CUSTOM]: [0, 35],
317
+ [DataflowTag.STRING_TYPE_CHECKED]: [0, 35]
318
+ },
319
+ });
320
+ });
321
+ });
322
+
323
+ it(`object refs where both target and ref are tracked - ref gets same validation tags (${methods})`, function() {
324
+ simulateRequestScope(() => {
325
+ const schema = getSchema(methods, {
326
+ a: joi.object({
327
+ aa: joi.object({
328
+ aaa: joi.string().guid(),
329
+ }),
330
+ foo: joi.string().guid(),
331
+ }),
332
+ b: joi.ref('a'),
333
+ });
334
+ const data = {
335
+ a: {
336
+ aa: {
337
+ aaa: trackString('fa2cdd9e-7eb0-4bb0-a37d-ddd4d9b23265'),
338
+ },
339
+ foo: trackString('fa2cdd9e-7eb0-4bb0-a37d-ddd4d9b23265'),
340
+ },
341
+ b: {
342
+ aa: {
343
+ aaa: trackString('fa2cdd9e-7eb0-4bb0-a37d-ddd4d9b23265'),
344
+ },
345
+ foo: trackString('fa2cdd9e-7eb0-4bb0-a37d-ddd4d9b23265'),
346
+ },
347
+ };
348
+
349
+ const result = schema.validate(data, { convert: false });
350
+
351
+ // validation outcome
352
+ expect(result.error).to.be.undefined;
353
+ //result
354
+ makeAssertions(tracker.getData(result.value.a.foo));
355
+ makeAssertions(tracker.getData(result.value.b.foo));
356
+
357
+ makeAssertions(tracker.getData(result.value.a.aa.aaa));
358
+ makeAssertions(tracker.getData(result.value.b.aa.aaa));
359
+ // orig (target: A)
360
+ makeAssertions(tracker.getData(data.a.foo));
361
+ makeAssertions(tracker.getData(data.b.foo));
362
+
363
+ makeAssertions(tracker.getData(data.a.aa.aaa));
364
+ makeAssertions(tracker.getData(data.b.aa.aaa));
365
+ });
366
+ });
367
+
368
+ it(`should tag the refs even when the target is not - (${methods})`, function() {
369
+ simulateRequestScope(() => {
370
+ const schema = getSchema(methods, {
371
+ a: { aa: joi.string().guid() },
372
+ b: joi.ref('a.aa'),
373
+ c: { cc: { ccc: joi.ref('....a.aa') } },
374
+ d: { dd: { ddd: joi.ref('....a.aa') } },
375
+ });
376
+
377
+ const data = {
378
+ a: { aa: 'fa2cdd9e-7eb0-4bb0-a37d-ddd4d9b23265' },
379
+ b: trackString('fa2cdd9e-7eb0-4bb0-a37d-ddd4d9b23265'),
380
+ c: { cc: { ccc: trackString('fa2cdd9e-7eb0-4bb0-a37d-ddd4d9b23265') } },
381
+ d: { dd: { ddd: 'fa2cdd9e-7eb0-4bb0-a37d-ddd4d9b23265' } },
382
+ };
383
+
384
+ const result = schema.validate(data, { convert: false });
385
+
386
+ // validation outcome
387
+ expect(result.error).to.be.undefined;
388
+ expect(tracker.getData(result.value.a)).to.be.null;
389
+ expect(tracker.getData(result.value.d.dd.ddd)).to.be.null;
390
+
391
+ makeAssertions(tracker.getData(result.value.b));
392
+ makeAssertions(tracker.getData(result.value.c.cc.ccc));
393
+ });
394
+ });
395
+
396
+ Object.entries({
397
+ base64: {
398
+ tag: DataflowTag.ALPHANUM_SPACE_HYPHEN,
399
+ value: 'aGVsbG8=',
400
+ },
401
+ guid: {
402
+ tag: DataflowTag.ALPHANUM_SPACE_HYPHEN,
403
+ value: 'fa2cdd9e-7eb0-4bb0-a37d-ddd4d9b23265',
404
+ },
405
+ alphanum: {
406
+ tag: DataflowTag.ALPHANUM_SPACE_HYPHEN,
407
+ value: 'rtgtr2342',
408
+ },
409
+ hex: {
410
+ tag: DataflowTag.ALPHANUM_SPACE_HYPHEN,
411
+ value: '54455354',
412
+ },
413
+ isoDate: {
414
+ tag: DataflowTag.ALPHANUM_SPACE_HYPHEN,
415
+ value: '2018-11-28T18:25:32.000Z',
416
+ },
417
+ isoDuration: {
418
+ tag: DataflowTag.ALPHANUM_SPACE_HYPHEN,
419
+ value: 'P3Y6M4DT12H30M5S',
420
+ },
421
+ token: {
422
+ tag: DataflowTag.ALPHANUM_SPACE_HYPHEN,
423
+ value: '_azAZ09',
424
+ },
425
+ creditCard: {
426
+ tag: DataflowTag.LIMITED_CHARS,
427
+ value: '4111111111111111',
428
+ },
429
+ ip: {
430
+ tag: DataflowTag.LIMITED_CHARS,
431
+ value: '0.0.0.0',
432
+ },
433
+ hostname: {
434
+ tag: DataflowTag.ALPHANUM_SPACE_HYPHEN,
435
+ value: 'www.contrastsecurity.com',
436
+ },
437
+ domain: {
438
+ tag: DataflowTag.ALPHANUM_SPACE_HYPHEN,
439
+ value: 'www.contrastsecurity.com',
440
+ },
441
+ }).forEach(([key, { value, tag }]) => {
442
+ it(`should tag the refs even when the target is not - string schemas(${key}) (${methods})`, function() {
443
+ simulateRequestScope(() => {
444
+ const schema = getSchema(methods, {
445
+ a: { [key]: joi.string()[key]() },
446
+ [key]: joi.ref(`a.${key}`),
447
+ });
448
+
449
+ const data = {
450
+ a: { [key]: value },
451
+ [key]: trackString(value),
452
+ };
453
+
454
+ const result = schema.validate(data, { convert: false });
455
+
456
+ // validation outcome
457
+ expect(result.error).to.be.undefined;
458
+
459
+ expect(tracker.getData(result.value.a[key])).to.be.null;
460
+ const { tags } = tracker.getData(result.value[key]);
461
+ expect(tags).to.deep.equal({
462
+ [DataflowTag.UNTRUSTED]: [0, value.length - 1],
463
+ [DataflowTag.STRING_TYPE_CHECKED]: [0, value.length - 1],
464
+ [tag]: [0, value.length - 1]
465
+ }
466
+ );
467
+ });
468
+ });
469
+ });
470
+
471
+ it(`ref used with adjust() option does merge the tags with the adjusted value (if any), { convert: true } (${methods})`, function() {
472
+ simulateRequestScope(() => {
473
+ const schema = getSchema('object', {
474
+ a: joi.string().guid(),
475
+ b: joi.ref('a', {
476
+ adjust: (v) => v
477
+ }),
478
+ });
479
+ const data = {
480
+ a: trackString('fa2cdd9e-7eb0-4bb0-a37d-ddd4d9b23265'),
481
+ b: trackString('fa2cdd9e-7eb0-4bb0-a37d-ddd4d9b23265', {
482
+ tags: {
483
+ [DataflowTag.UNTRUSTED]: [0, 35],
484
+ [DataflowTag.CUSTOM]: [0, 35]
485
+ }
486
+ }),
487
+ };
488
+
489
+ const result = schema.validate(data);
490
+
491
+ // validation result
492
+ expect(result.error).to.be.undefined;
493
+
494
+ const override = {
495
+ name: 'Joi.values.get',
496
+ methodName: 'values.get',
497
+ tags: {
498
+ [DataflowTag.ALPHANUM_SPACE_HYPHEN]: [0, 35],
499
+ [DataflowTag.STRING_TYPE_CHECKED]: [0, 35],
500
+ [DataflowTag.UNTRUSTED]: [0, 35],
501
+ [DataflowTag.CUSTOM]: [0, 35]
502
+ }
503
+ };
504
+ // result
505
+ makeAssertions(tracker.getData(result.value.a), override);
506
+ makeAssertions(tracker.getData(result.value.b), override);
507
+ // orig
508
+ makeAssertions(tracker.getData(data.a), override);
509
+ makeAssertions(tracker.getData(data.b), override);
510
+ });
511
+ });
512
+
513
+ it(`tracked ref of tracked value gets validation tags using { in: true } (${methods})`, function() {
514
+ simulateRequestScope(() => {
515
+ const schema = getSchema(methods, {
516
+ a: joi.array().items(joi.string().guid()),
517
+ b: joi.ref('a', { in: true }),
518
+ c: joi.string().guid(),
519
+ d: joi.ref('c', { in: true }),
520
+ });
521
+
522
+ const data = {
523
+ a: ['fa2cdd9e-7eb0-4bb0-a37d-ddd4d9b23267', trackString('fa2cdd9e-7eb0-4bb0-a37d-ddd4d9b23265'), 'fa2cdd9e-7eb0-4bb0-a37d-ddd4d9b23263'],
524
+ b: trackString('fa2cdd9e-7eb0-4bb0-a37d-ddd4d9b23265'),
525
+ c: trackString('fa2cdd9e-7eb0-4bb0-a37d-ddd4d9b23267'),
526
+ d: trackString('fa2cdd9e-7eb0-4bb0-a37d-ddd4d9b23267'),
527
+ };
528
+
529
+ const result = schema.validate(data);
530
+
531
+ // validation result
532
+ expect(result.error).to.be.undefined;
533
+ // result
534
+ makeAssertions(tracker.getData(result.value.a[1]));
535
+ makeAssertions(tracker.getData(result.value.b));
536
+ makeAssertions(tracker.getData(result.value.c));
537
+ makeAssertions(tracker.getData(result.value.d));
538
+ // orig
539
+ makeAssertions(tracker.getData(data.a[1]));
540
+ makeAssertions(tracker.getData(data.b));
541
+ makeAssertions(tracker.getData(data.c));
542
+ makeAssertions(tracker.getData(data.d));
543
+ });
544
+ });
545
+
546
+ it(`tracked ref of tracked value gets validation tags using { iterables: true } (${methods})`, function() {
547
+ simulateRequestScope(() => {
548
+ const schema = getSchema(methods, {
549
+ a: joi
550
+ .object({
551
+ aa: joi.string().guid(),
552
+ bb: joi.string()
553
+ })
554
+ .cast('map'),
555
+ b: joi.ref('a.bb', { iterables: true }),
556
+ });
557
+ const data = {
558
+ a: {
559
+ aa: trackString('fa2cdd9e-7eb0-4bb0-a37d-ddd4d9b23265'),
560
+ bb: trackString('fa2cdd9e-7eb0-4bb0-a37d-ddd4d9b23267'),
561
+ },
562
+ b: trackString('fa2cdd9e-7eb0-4bb0-a37d-ddd4d9b23267'),
563
+ };
564
+
565
+ const result = schema.validate(data);
566
+
567
+ const overrides = {
568
+ name: 'Joi.string.validate',
569
+ methodName: 'string.validate',
570
+ tags: {
571
+ [DataflowTag.UNTRUSTED]: [0, 35],
572
+ [DataflowTag.STRING_TYPE_CHECKED]: [0, 35],
573
+ }
574
+ };
575
+ // validation outcome
576
+ expect(result.error).to.be.undefined;
577
+ // result
578
+ makeAssertions(tracker.getData(result.value.a.get('aa')));
579
+ makeAssertions(tracker.getData(result.value.b), overrides);
580
+ // orig (target: A)
581
+ makeAssertions(tracker.getData(data.a.aa));
582
+ makeAssertions(tracker.getData(data.b), overrides);
583
+ });
584
+ });
585
+ });
586
+ });
587
+
588
+ function makeAssertions(trackData, overrides = {}) {
589
+ const assertionValues = {
590
+ name: 'Joi.string.guid',
591
+ tags: {
592
+ [DataflowTag.UNTRUSTED]: [0, 35],
593
+ [DataflowTag.ALPHANUM_SPACE_HYPHEN]: [0, 35],
594
+ [DataflowTag.STRING_TYPE_CHECKED]: [0, 35]
595
+ },
596
+ moduleName: 'joi',
597
+ methodName: 'string.guid',
598
+ ...overrides
599
+ };
600
+ expect(trackData.name).to.equal(assertionValues.name);
601
+ expect(trackData.tags).to.deep.equal(assertionValues.tags);
602
+ expect(trackData.moduleName).to.equal(assertionValues.moduleName);
603
+ expect(trackData.methodName).to.equal(assertionValues.methodName);
604
+ }
605
+ });
606
+
607
+