@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,500 @@
1
+ 'use strict';
2
+
3
+ const { expect } = require('chai');
4
+ const sinon = require('sinon');
5
+ const { initAssessFixture } = require('@contrast/test/fixtures');
6
+
7
+ describe('assess dataflow propagation string split', function () {
8
+ let core, simulateRequestScope, trackString, tracker;
9
+
10
+ beforeEach(function () {
11
+ ({
12
+ core,
13
+ trackString,
14
+ simulateRequestScope
15
+ } = initAssessFixture());
16
+
17
+ tracker = core.assess.dataflow.tracker;
18
+ sinon.spy(tracker, 'track');
19
+
20
+ core.assess.dataflow.propagation.stringInstrumentation.substring.install();
21
+ core.assess.dataflow.propagation.stringInstrumentation.split.install();
22
+ });
23
+
24
+ afterEach(function () {
25
+ tracker.track.restore();
26
+ core.assess.dataflow.propagation.stringInstrumentation.substring.uninstall();
27
+ core.assess.dataflow.propagation.stringInstrumentation.split.uninstall();
28
+ });
29
+
30
+ describe('base cases', function () {
31
+ it('normal split on non-tracked string', function () {
32
+ simulateRequestScope(() => {
33
+ const ret = 'foo?foo'.split('?');
34
+ expect(ret).to.deep.equal(['foo', 'foo']);
35
+ ret.forEach((str) => {
36
+ expect(tracker.getData(str)).to.be.null;
37
+ });
38
+ });
39
+ });
40
+
41
+ it('regex split on non-tracked string', function () {
42
+ simulateRequestScope(() => {
43
+ const ret = 'foo?foo'.split(/\?/);
44
+ expect(ret).to.deep.equal(['foo', 'foo']);
45
+ ret.forEach((str) => {
46
+ expect(tracker.getData(str)).to.be.null;
47
+ });
48
+ });
49
+ });
50
+
51
+ it('array split on non-tracked string', function () {
52
+ simulateRequestScope(() => {
53
+ const ret = 'foo?,?foo'.split(['?', '?']);
54
+ expect(ret).to.deep.equal(['foo', 'foo']);
55
+ ret.forEach((str) => {
56
+ expect(tracker.getData(str)).to.be.null;
57
+ });
58
+ });
59
+ });
60
+
61
+ it('apply split on non-tracked string', function () {
62
+ simulateRequestScope(() => {
63
+ const ret = String.prototype.split.apply('foo?foo', ['?']);
64
+ expect(ret).to.deep.equal(['foo', 'foo']);
65
+ ret.forEach((str) => {
66
+ expect(tracker.getData(str)).to.be.null;
67
+ });
68
+ });
69
+ });
70
+
71
+ it('limited split on non-tracked string', function () {
72
+ simulateRequestScope(() => {
73
+ const ret = 'foo?foo?foo'.split('?', 2);
74
+ expect(ret).to.deep.equal(['foo', 'foo']);
75
+ ret.forEach((str) => {
76
+ expect(tracker.getData(str)).to.be.null;
77
+ });
78
+ });
79
+ });
80
+
81
+ it('split on empty string', function () {
82
+ simulateRequestScope(() => {
83
+ const ret = ''.split('?');
84
+ expect(ret).to.deep.equal(['']);
85
+ expect(tracker.getData(ret[0])).to.be.null;
86
+ });
87
+ });
88
+
89
+ it('split on object', function () {
90
+ simulateRequestScope(() => {
91
+ const ret = String.prototype.split.apply({ foo: 'foo' }, ['foo']);
92
+ expect(ret).to.deep.equal(['[object Object]']);
93
+ expect(tracker.getData(ret[0])).to.be.null;
94
+ });
95
+ });
96
+ });
97
+
98
+ describe('undefined/empty separators', function () {
99
+ [
100
+ [],
101
+ [undefined],
102
+ [null]
103
+ ].forEach((rest) => {
104
+ it(`handles ${rest[0]} separator`, function () {
105
+ simulateRequestScope(() => {
106
+ const extern = trackString('foo');
107
+ const ret = extern.split(rest[0]);
108
+ expect(ret).to.deep.equal(['foo']);
109
+ expect(tracker.getData(ret[0]).tags).to.deep.equal({
110
+ UNTRUSTED: [0, 2]
111
+ });
112
+ });
113
+ });
114
+ });
115
+
116
+ it('handles empty separator for a fully tracked string', function () {
117
+ simulateRequestScope(() => {
118
+ const extern = trackString('foo');
119
+ const ret = extern.split('');
120
+ expect(ret).to.deep.equal(['f', 'o', 'o']);
121
+ ret.forEach((str) => {
122
+ expect(tracker.getData(str).tags).to.deep.equal({
123
+ UNTRUSTED: [0, 0]
124
+ });
125
+ });
126
+ });
127
+ });
128
+
129
+ it('handles empty separator for a partially tracked string', function () {
130
+ simulateRequestScope(() => {
131
+ const extern = trackString('foo', {
132
+ tags: {
133
+ UNTRUSTED: [1, 1]
134
+ }
135
+ });
136
+ const ret = extern.split('');
137
+ expect(ret).to.deep.equal(['f', 'o', 'o']);
138
+ expect(tracker.getData(ret[0])).to.be.null;
139
+ expect(tracker.getData(ret[1]).tags).to.deep.equal({
140
+ UNTRUSTED: [0, 0]
141
+ });
142
+ expect(tracker.getData(ret[2])).to.be.null;
143
+ });
144
+ });
145
+
146
+ it('handles empty separator for a tracked string with different named ranges', function () {
147
+ simulateRequestScope(() => {
148
+ const extern = trackString('foo', {
149
+ tags: {
150
+ foo: [0, 0],
151
+ bar: [1, 2]
152
+ }
153
+ });
154
+ const ret = extern.split('');
155
+ expect(ret).to.deep.equal(['f', 'o', 'o']);
156
+ expect(tracker.getData(ret[0]).tags).to.deep.equal({
157
+ foo: [0, 0]
158
+ });
159
+ expect(tracker.getData(ret[1]).tags).to.deep.equal({
160
+ bar: [0, 0]
161
+ });
162
+ expect(tracker.getData(ret[2]).tags).to.deep.equal({
163
+ bar: [0, 0]
164
+ });
165
+ });
166
+ });
167
+ });
168
+
169
+ describe('string separators', function () {
170
+
171
+ it('keeps track of an unsplit string', function () {
172
+ simulateRequestScope(() => {
173
+ const extern = trackString('foo', {
174
+ tags: {
175
+ untrusted: [0, 2]
176
+ }
177
+ });
178
+ const ret = extern.split('?');
179
+ expect(ret).to.deep.equal(['foo']);
180
+ expect(tracker.getData(ret[0]).tags).to.deep.equal({
181
+ untrusted: [0, 2]
182
+ });
183
+ });
184
+ });
185
+
186
+ it('handles split limit of 0', function () {
187
+ simulateRequestScope(() => {
188
+ const extern = trackString('foo?foo?foo', {
189
+ tags: {
190
+ untrusted: [0, 10]
191
+ }
192
+ });
193
+ const ret = extern.split('?', 0);
194
+ expect(ret).to.deep.equal([]);
195
+ });
196
+ });
197
+
198
+ it('handles non-zero split limit', function () {
199
+ simulateRequestScope(() => {
200
+ const extern = trackString('foo?foo?foo');
201
+ const ret = extern.split('?', 2);
202
+ expect(ret).to.deep.equal(['foo', 'foo']);
203
+ ret.forEach((str) => {
204
+ expect(tracker.getData(str).tags).to.deep.equal({
205
+ UNTRUSTED: [0, 2]
206
+ });
207
+ });
208
+ });
209
+ });
210
+
211
+ it('keeps track of a tracked split string', function () {
212
+ simulateRequestScope(() => {
213
+ const extern = trackString('foo?foo?foo');
214
+ const ret = extern.split('?');
215
+ expect(ret).to.deep.equal(['foo', 'foo', 'foo']);
216
+
217
+ ret.forEach((str) => {
218
+ expect(tracker.getData(str).tags).to.deep.equal({
219
+ UNTRUSTED: [0, 2]
220
+ });
221
+ });
222
+ });
223
+ });
224
+
225
+ it('does not call tracker.track if the split result is the original string', function () {
226
+ simulateRequestScope(() => {
227
+ const extern = trackString('foo?foo?foo');
228
+ tracker.track.resetHistory();
229
+
230
+ const ret = extern.split('!');
231
+ expect(ret).to.deep.equal(['foo?foo?foo']);
232
+ expect(tracker.getData(ret[0]).tags).to.deep.equal({
233
+ UNTRUSTED: [0, 10]
234
+ });
235
+ expect(tracker.track).to.not.have.been.called;
236
+ });
237
+ });
238
+
239
+ it('keeps track of a tracked split string (long separator)', function () {
240
+ simulateRequestScope(() => {
241
+ const extern = trackString('foo?foo?foo');
242
+ const ret = extern.split('?foo?');
243
+ expect(ret).to.deep.equal(['foo', 'foo']);
244
+ ret.forEach((str) => {
245
+ expect(tracker.getData(str).tags).to.deep.equal({
246
+ UNTRUSTED: [0, 2]
247
+ });
248
+ });
249
+ });
250
+ });
251
+
252
+ it('keeps track of a partially tracked split string', function () {
253
+ simulateRequestScope(() => {
254
+ const extern = trackString('foo?foo?foo', {
255
+ tags: {
256
+ untrusted: [0, 2, 8, 10]
257
+ }
258
+ });
259
+ const ret = extern.split('?');
260
+ expect(ret).to.deep.equal(['foo', 'foo', 'foo']);
261
+ expect(tracker.getData(ret[0]).tags).to.deep.equal({
262
+ untrusted: [0, 2]
263
+ });
264
+ expect(tracker.getData(ret[1])).to.be.null;
265
+ expect(tracker.getData(ret[2]).tags).to.deep.equal({
266
+ untrusted: [0, 2]
267
+ });
268
+ });
269
+ });
270
+
271
+ it('keeps track of a tracked split string with different tag range names', function () {
272
+ simulateRequestScope(() => {
273
+ const extern = trackString('foo?foo?foo', {
274
+ tags: {
275
+ untrusted: [0, 2, 8, 10],
276
+ foo: [0, 2],
277
+ bar: [4, 10]
278
+ }
279
+ });
280
+ const ret = extern.split('?');
281
+ expect(ret).to.deep.equal(['foo', 'foo', 'foo']);
282
+ expect(tracker.getData(ret[0]).tags).to.deep.equal({
283
+ untrusted: [0, 2],
284
+ foo: [0, 2]
285
+ });
286
+ expect(tracker.getData(ret[1]).tags).to.deep.equal({
287
+ bar: [0, 2]
288
+ });
289
+ expect(tracker.getData(ret[2]).tags).to.deep.equal({
290
+ untrusted: [0, 2],
291
+ bar: [0, 2]
292
+ });
293
+ });
294
+ });
295
+
296
+ it('keeps track of tracked separators', function () {
297
+ simulateRequestScope(() => {
298
+
299
+ const extern = trackString('foo?foo', {
300
+ tags: {
301
+ untrusted: [0, 10]
302
+ }
303
+ });
304
+
305
+ const trackedSep = trackString('?', {
306
+ tags: {
307
+ untrusted: [0, 0]
308
+ }
309
+ });
310
+ const ret = extern.split(trackedSep);
311
+ expect(ret).to.deep.equal(['foo', 'foo']);
312
+ ret.forEach((str) => {
313
+ expect(tracker.getData(str).args).to.deep.equal([{
314
+ value: '?', tracked: true
315
+ }]);
316
+ });
317
+ });
318
+ });
319
+
320
+ it('reports result as a comma delimited list', function () {
321
+ simulateRequestScope(() => {
322
+ const extern = trackString('foo?foo?foo', {
323
+ tags: {
324
+ untrusted: [0, 10]
325
+ }
326
+ });
327
+ const ret = extern.split('?');
328
+ expect(ret).to.deep.equal(['foo', 'foo', 'foo']);
329
+ ret.forEach((str) => {
330
+ expect(tracker.getData(str).result).to.deep.equal({
331
+ value: 'foo',
332
+ tracked: true
333
+ });
334
+ });
335
+ });
336
+ });
337
+ });
338
+
339
+ describe('regEx separators', function () {
340
+ it('keeps track of a tracked split string separated by a RegEx', function () {
341
+ simulateRequestScope(() => {
342
+ const extern = trackString('foo?foo?foo', {
343
+ tags: {
344
+ untrusted: [0, 10]
345
+ }
346
+ });
347
+ const ret = extern.split(/\?/g);
348
+ expect(ret).to.deep.equal(['foo', 'foo', 'foo']);
349
+ ret.forEach((str) => {
350
+ expect(tracker.getData(str).tags).to.deep.equal({
351
+ untrusted: [0, 2]
352
+ });
353
+ });
354
+ });
355
+ });
356
+
357
+ it('keeps track of a tracked split string separated by a more complex RegEx', function () {
358
+ simulateRequestScope(() => {
359
+ const extern = trackString('foo1foo2foo', {
360
+ tags: {
361
+ untrusted: [0, 10]
362
+ }
363
+ });
364
+ const ret = extern.split(/\d/g);
365
+ expect(ret).to.deep.equal(['foo', 'foo', 'foo']);
366
+ ret.forEach((str) => {
367
+ expect(tracker.getData(str).tags).to.deep.equal({
368
+ untrusted: [0, 2]
369
+ });
370
+ });
371
+ });
372
+ });
373
+
374
+ it('keeps track of a tracked split string separated by a RegEx containing capturing parentheses', function () {
375
+ simulateRequestScope(() => {
376
+ const extern = trackString('foo?foo?foo', {
377
+ tags: {
378
+ untrusted: [0, 10]
379
+ }
380
+ });
381
+ const ret = extern.split(/(\?)/g);
382
+ expect(ret).to.deep.equal(['foo', '?', 'foo', '?', 'foo']);
383
+ ret.forEach((str) => {
384
+ expect(tracker.getData(str).tags).to.deep.equal({
385
+ untrusted: [0, str.length - 1]
386
+ });
387
+ });
388
+ });
389
+ });
390
+ });
391
+
392
+ describe('complex/edge cases', function () {
393
+
394
+ it('handles non-english characters', function () {
395
+ simulateRequestScope(() => {
396
+ const extern = trackString('fꙨꙨꙮፈar', {
397
+ tags: {
398
+ untrusted: [0, 10]
399
+ }
400
+ });
401
+ const ret = extern.split('ꙮ');
402
+ expect(ret).to.deep.equal(['fꙨꙨ', 'ፈar']);
403
+ ret.forEach((str) => {
404
+ expect(tracker.getData(str).tags).to.deep.equal({
405
+ untrusted: [0, 2]
406
+ });
407
+ });
408
+ });
409
+ });
410
+
411
+ it('handles multiple calls to split and keeps track of tracked strings with different named ranges', function () {
412
+ simulateRequestScope(() => {
413
+ const extern = trackString('foo?foo?foo', {
414
+ tags: {
415
+ untrusted: [0, 8],
416
+ foo: [0, 2],
417
+ bar: [0, 6],
418
+ foobar: [9, 10]
419
+ }
420
+ });
421
+ let [foo1, foo2, foo3] = [...extern.split('?')];
422
+ foo1 = foo1.split();
423
+ foo2 = foo2.split('');
424
+ foo3 = foo3.split(/(o)/g);
425
+
426
+ expect(foo1).to.deep.equal(['foo']);
427
+ expect(foo2).to.deep.equal(['f', 'o', 'o']);
428
+ expect(foo3).to.deep.equal(['f', 'o', '', 'o', '']);
429
+
430
+ expect(tracker.getData(foo1[0]).tags).to.deep.equal({
431
+ untrusted: [0, 2],
432
+ foo: [0, 2],
433
+ bar: [0, 2]
434
+ });
435
+ foo2.forEach((char) => {
436
+ expect(tracker.getData(char).tags).to.deep.equal({
437
+ untrusted: [0, 0],
438
+ bar: [0, 0]
439
+ });
440
+ });
441
+ expect(tracker.getData(foo3[0]).tags).to.deep.equal({
442
+ untrusted: [0, 0]
443
+ });
444
+ expect(tracker.getData(foo3[1]).tags).to.deep.equal({
445
+ foobar: [0, 0]
446
+ });
447
+ expect(tracker.getData(foo3[3]).tags).to.deep.equal({
448
+ foobar: [0, 0]
449
+ });
450
+ });
451
+ });
452
+
453
+ it('custom splitter returns tracked strings', function () {
454
+ simulateRequestScope(() => {
455
+ const customSplit = {
456
+ [Symbol.split](str) {
457
+ return [str, str];
458
+ }
459
+ };
460
+ const extern = trackString('foo', {
461
+ tags: {
462
+ untrusted: [0, 2]
463
+ }
464
+ });
465
+ const ret = extern.split(customSplit);
466
+ expect(ret).to.deep.equal(['foo', 'foo']);
467
+ ret.forEach((str) => {
468
+ expect(tracker.getData(str).tags).to.deep.equal({
469
+ untrusted: [0, 2]
470
+ });
471
+ });
472
+ });
473
+ });
474
+
475
+ it('custom splitter calls split', function () {
476
+ simulateRequestScope(() => {
477
+ const onlySplitFoo = {
478
+ [Symbol.split](str) {
479
+ if (str.includes('foo')) {
480
+ return str.split('?');
481
+ } else {
482
+ return [];
483
+ }
484
+ }
485
+ };
486
+ const extern = trackString('foo?bar', {
487
+ tags: {
488
+ untrusted: [0, 2]
489
+ }
490
+ });
491
+ const ret = extern.split(onlySplitFoo);
492
+ expect(ret).to.deep.equal(['foo', 'bar']);
493
+ expect(tracker.getData(ret[0]).tags).to.deep.equal({
494
+ untrusted: [0, 2]
495
+ });
496
+ expect(tracker.getData(ret[1])).to.be.null;
497
+ });
498
+ });
499
+ });
500
+ });