@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,115 @@
1
+ 'use strict';
2
+
3
+ const { expect } = require('chai');
4
+ const { isVulnerable } = require('./is-vulnerable');
5
+
6
+ describe('assess dataflow utils isVulnerable', function() {
7
+ [
8
+ {
9
+ args: [
10
+ 'untrusted',
11
+ ['ant'],
12
+ {
13
+ untrusted: [5, 10, 100, 102],
14
+ ant: [4, 104],
15
+ },
16
+ ],
17
+ desc: 'encompasses all',
18
+ expected: false,
19
+ },
20
+ {
21
+ args: [
22
+ 'untrusted',
23
+ ['ant', 'cat'],
24
+ {
25
+ untrusted: [5, 10, 100, 102],
26
+ ant: [0, 0],
27
+ cat: [1, 1, 2, 2, 4, 8],
28
+ },
29
+ ],
30
+ desc: 'no overlaps',
31
+ expected: true,
32
+ },
33
+ {
34
+ args: [
35
+ 'untrusted',
36
+ ['ant', 'cat'],
37
+ {
38
+ untrusted: [5, 10, 100, 102],
39
+ ant: [0, 0],
40
+ cat: [1, 1, 2, 2, 3, 8],
41
+ },
42
+ ],
43
+ desc: 'no overlaps',
44
+ expected: true,
45
+ },
46
+ {
47
+ args: [
48
+ 'untrusted',
49
+ ['ant', 'cat'],
50
+ {
51
+ untrusted: [5, 10, 100, 102],
52
+ ant: [0, 0],
53
+ cat: [1, 5, 3, 8],
54
+ },
55
+ ],
56
+ desc: 'no overlaps',
57
+ expected: true,
58
+ },
59
+ {
60
+ args: [
61
+ 'untrusted',
62
+ ['ant'],
63
+ {
64
+ untrusted: [5, 10, 100, 102],
65
+ ant: [4, 5],
66
+ },
67
+ ],
68
+ desc: 'no overlaps',
69
+ expected: true,
70
+ },
71
+ {
72
+ args: [
73
+ 'untrusted',
74
+ ['ant', 'cat', 'dog'],
75
+ {
76
+ untrusted: [8, 14],
77
+ ant: [4, 5, 7, 10],
78
+ cat: [6, 9],
79
+ dog: [9, 18],
80
+ },
81
+ ],
82
+ desc: 'encompasses all',
83
+ expected: false,
84
+ },
85
+ {
86
+ args: [
87
+ 'untrusted',
88
+ ['ant', 'cat', 'dog'],
89
+ {
90
+ ant: [4, 5, 7, 10],
91
+ cat: [6, 9],
92
+ dog: [9, 18],
93
+ },
94
+ ],
95
+ desc: 'when no target tags found',
96
+ expected: false,
97
+ },
98
+ {
99
+ args: [
100
+ 'untrusted',
101
+ ['ant'],
102
+ {
103
+ untrusted: [4, 5, 7, 10],
104
+ ant: [4, 5, 7, 10],
105
+ },
106
+ ],
107
+ desc: 'when there are multiple ranges but they are all covered',
108
+ expected: false,
109
+ },
110
+ ].forEach(({ args, desc, expected }) => {
111
+ it(`${desc} returns ${expected}`, function() {
112
+ expect(isVulnerable(...args)).to.equal(expected);
113
+ });
114
+ });
115
+ });
@@ -0,0 +1,321 @@
1
+ 'use strict';
2
+
3
+ const { expect } = require('chai');
4
+ const sinon = require('sinon');
5
+ const { InputType } = require('@contrast/common');
6
+ const { initAssessFixture } = require('@contrast/test/fixtures');
7
+
8
+ const os = require('os');
9
+
10
+ const testMethod = os.platform() === 'win32' ? describe.skip : describe;
11
+
12
+ testMethod('assess event-factory', function () {
13
+ let core, createSourceEvent, createPropagationEvent, createSinkEvent;
14
+
15
+ beforeEach(function () {
16
+ ({ core } = initAssessFixture());
17
+ ({
18
+ createSourceEvent,
19
+ createPropagationEvent,
20
+ createSinkEvent
21
+ } = require('./event-factory')(core));
22
+ });
23
+
24
+ describe('createSourceEvent', function () {
25
+ [
26
+ {
27
+ data: {},
28
+ invalidProp: 'result',
29
+ },
30
+ {
31
+ data: { result: { tracked: true, value: 'foo' } },
32
+ invalidProp: 'name',
33
+ },
34
+ {
35
+ data: {
36
+ name: 'frogs',
37
+ result: { tracked: true, value: 'foo' },
38
+ inputType: 'bad-value',
39
+ },
40
+ invalidProp: 'inputType',
41
+ },
42
+ {
43
+ data: {
44
+ name: 'frogs',
45
+ result: { tracked: true, value: 'foo' },
46
+ inputType: InputType.QUERYSTRING,
47
+ },
48
+ invalidProp: 'tags',
49
+ message: 'event has no tags'
50
+ }
51
+ ].forEach(({
52
+ data,
53
+ invalidProp,
54
+ message = `invalid ${invalidProp}`,
55
+ }) => {
56
+ it(`will not create event when props are invalid: ${message}`, function () {
57
+ const event = createSourceEvent(data);
58
+ expect(event).to.equal(null);
59
+ expect(core.logger.debug).to.have.been.calledWith(
60
+ sinon.match.object,
61
+ 'Source event not created: %s',
62
+ message
63
+ );
64
+ });
65
+ });
66
+
67
+ [
68
+ {
69
+ data: {
70
+ name: 'COOKIE_VALUE.frogs',
71
+ result: { tracked: true, value: 'foo' },
72
+ inputType: InputType.COOKIE_VALUE,
73
+ tags: {
74
+ untrusted: [0, 4],
75
+ cookie: [0, 4],
76
+ },
77
+ stack: [],
78
+ },
79
+ }
80
+ ].forEach(({ data, expected }) => {
81
+ it('returns the event data when validated', function () {
82
+ const event = createSourceEvent(data);
83
+ expect(event).to.equal(data);
84
+ expect(core.logger.debug).not.to.have.been.called;
85
+ });
86
+ });
87
+ });
88
+
89
+ describe('createPropagationEvent', function () {
90
+ const validData = {
91
+ name: 'String.prototype.concat',
92
+ history: [{ mock: 'SourceEvent' }],
93
+ object: {
94
+ value: 'test',
95
+ tracked: true
96
+ },
97
+ args: [{ value: '-another-test', tracked: false }],
98
+ result: {
99
+ value: 'test-another-test',
100
+ tracked: true
101
+ },
102
+ source: 'O',
103
+ target: 'R',
104
+ tags: { untrusted: [0, 3] }
105
+ };
106
+ const validStore = {
107
+ assess: {
108
+ propagationEventsCount: 0
109
+ }
110
+ };
111
+ const validResult = {
112
+ name: 'String.prototype.concat',
113
+ history: [{ mock: 'SourceEvent' }],
114
+ object: {
115
+ value: 'test',
116
+ tracked: true
117
+ },
118
+ args: [{ value: '-another-test', tracked: false }],
119
+ result: {
120
+ value: 'test-another-test',
121
+ tracked: true
122
+ },
123
+ tags: { untrusted: [0, 3] },
124
+ addedTags: [],
125
+ removedTags: [],
126
+ source: 'O',
127
+ target: 'R'
128
+ };
129
+
130
+ it('logs a debug statement for missing source context and returns null when executed in the wrong context', function () {
131
+ core.scopes.sources.run({}, function () {
132
+ const result = createPropagationEvent(validData);
133
+
134
+ expect(core.logger.debug).to.have.been.calledOnceWith(
135
+ sinon.match.object,
136
+ 'No sourceContext found during Propagation event creation'
137
+ );
138
+ expect(result).to.be.null;
139
+ });
140
+ });
141
+
142
+ it('logs a debug statement for going above the maximum propagation events limit and returns null when we are above the said limit', function () {
143
+ core.scopes.sources.run({ assess: { propagationEventsCount: 500 } }, function () {
144
+ const result = createPropagationEvent(validData);
145
+
146
+ expect(core.logger.debug).to.have.been.calledOnceWith(
147
+ sinon.match.object,
148
+ 'Maximum number of Propagation events reached. Event not created'
149
+ );
150
+ expect(result).to.be.null;
151
+ });
152
+
153
+ });
154
+
155
+ [
156
+ {
157
+ data: { ...validData, name: '' },
158
+ message: 'invalid name',
159
+ },
160
+ {
161
+ data: { ...validData, source: undefined },
162
+ message: 'invalid source',
163
+ },
164
+ {
165
+ data: { ...validData, history: [] },
166
+ message: 'invalid history',
167
+ },
168
+ {
169
+ data: { ...validData, source: 'S' },
170
+ message: 'invalid source',
171
+ },
172
+ {
173
+ data: { ...validData, target: 'T' },
174
+ message: 'invalid target',
175
+ },
176
+ ].forEach(({ data, message }) => {
177
+ it(`logs a debug statement when insufficient data is passed and returns null: ${message}`, function () {
178
+ core.scopes.sources.run(validStore, function () {
179
+ const result = createPropagationEvent(data);
180
+
181
+ expect(core.logger.debug).to.have.been.calledOnceWith(
182
+ sinon.match.object,
183
+ 'Propagation event not created: %s',
184
+ message,
185
+ );
186
+ expect(result).to.be.null;
187
+ });
188
+ });
189
+ });
190
+
191
+ it('returns an event with stacktrace generator function when stacktraces option is set to "ALL"', function () {
192
+ core.config.assess.stacktraces = 'ALL';
193
+ core.scopes.sources.run(validStore, function () {
194
+ const result = createPropagationEvent(validData);
195
+
196
+ expect(result).to.be.like(validResult);
197
+ expect(result.time).not.to.be.undefined;
198
+ expect(result.stack).to.be.an('array');
199
+ });
200
+ });
201
+
202
+ it('returns an event without stacktrace generator function when stacktraces option is not set to "ALL"', function () {
203
+ core.config.assess.stacktraces = 'SOME';
204
+ core.scopes.sources.run(validStore, function () {
205
+ const result = createPropagationEvent(validData);
206
+
207
+ expect(result).to.be.like(validResult);
208
+ expect(result.time).not.to.be.undefined;
209
+ expect(result.stack).to.deep.equal([]);
210
+ });
211
+ });
212
+ });
213
+
214
+ describe('createSinkEvent', function () {
215
+ const validData = {
216
+ name: 'mysql/lib/Connection.query',
217
+ history: [{ mock: 'SourceEvent' }],
218
+ object: {
219
+ value: 'MySQL.Query#0001',
220
+ tracked: false
221
+ },
222
+ args: [{ value: 'malicious-value', tracked: true }],
223
+ result: {
224
+ value: null,
225
+ tracked: false
226
+ },
227
+ tags: { untrusted: [0, 14] },
228
+ source: 'P0'
229
+ };
230
+ const validStore = {
231
+ assess: {
232
+ propagationEventsCount: 0
233
+ }
234
+ };
235
+ const validResult = {
236
+ name: 'mysql/lib/Connection.query',
237
+ history: [{ mock: 'SourceEvent' }],
238
+ object: {
239
+ value: 'MySQL.Query#0001',
240
+ tracked: false
241
+ },
242
+ args: [{ value: 'malicious-value', tracked: true }],
243
+ result: {
244
+ value: null,
245
+ tracked: false
246
+ },
247
+ tags: { untrusted: [0, 14] },
248
+ source: 'P0',
249
+ };
250
+
251
+ it('logs a debug statement for missing source context and returns null when executed in the wrong context', function () {
252
+ core.scopes.sources.run({}, function () {
253
+ const result = createSinkEvent(validData);
254
+
255
+ expect(core.logger.debug).to.have.been.calledOnceWith(
256
+ sinon.match.object,
257
+ 'no sourceContext found during sink event creation'
258
+ );
259
+ expect(result).to.be.null;
260
+ });
261
+ });
262
+
263
+ [
264
+ {
265
+ data: {
266
+ ...validData,
267
+ name: '',
268
+ },
269
+ message: 'no sink event name'
270
+ },
271
+ {
272
+ data: {
273
+ ...validData,
274
+ history: []
275
+ },
276
+ message: 'empty history for sink event'
277
+ },
278
+ {
279
+ data: {
280
+ ...validData,
281
+ source: 'S'
282
+ },
283
+ message: 'malformed or missing sink event source field',
284
+ },
285
+ ].forEach(({ data, message }) => {
286
+ it(`logs a debug statement when insufficient data is passed and returns null: ${message}`, function () {
287
+ core.scopes.sources.run(validStore, function () {
288
+ const result = createSinkEvent(data);
289
+
290
+ expect(core.logger.debug).to.have.been.calledWith(
291
+ sinon.match.object,
292
+ message
293
+ );
294
+ expect(result).to.be.null;
295
+ });
296
+ });
297
+ });
298
+
299
+ it('returns an event with stacktrace generator function when stacktraces option is not set to "NONE"', function () {
300
+ core.config.assess.stacktraces = 'ALL';
301
+ core.scopes.sources.run(validStore, function () {
302
+ const result = createSinkEvent(validData);
303
+
304
+ expect(result).to.be.like(validResult);
305
+ expect(result.time).not.to.be.undefined;
306
+ expect(result.stack).to.be.instanceOf(Array);
307
+ });
308
+ });
309
+
310
+ it('returns an event without stacktrace generator function when stacktraces option is set to "NONE"', function () {
311
+ core.config.assess.stacktraces = 'NONE';
312
+ core.scopes.sources.run(validStore, function () {
313
+ const result = createSinkEvent(validData);
314
+
315
+ expect(result).to.be.like(validResult);
316
+ expect(result.time).not.to.be.undefined;
317
+ expect(result.stack).to.deep.equal([]);
318
+ });
319
+ });
320
+ });
321
+ });
@@ -0,0 +1,194 @@
1
+ 'use strict';
2
+
3
+ const { expect } = require('chai');
4
+ const { Event } = require('@contrast/common');
5
+ const { initAssessFixture } = require('@contrast/test/fixtures');
6
+
7
+ describe('assess getPolicy', function () {
8
+ let core, getPolicy;
9
+
10
+ beforeEach(function () {
11
+ ({ core } = initAssessFixture());
12
+ getPolicy = require('./get-policy')(core);
13
+ });
14
+
15
+ function assertPolicyOK(policy) {
16
+ expect(policy).to.have.property('enabledRules').and.be.a('Set').not.empty;
17
+ expect(policy).to.have.property('getInputPolicy').and.be.a('Function');
18
+ }
19
+
20
+ it('inits policy and will adjust according to TS settings updates', function() {
21
+ let policy = getPolicy();
22
+
23
+ expect(policy.enabledRules).to.have.length.greaterThan(1);
24
+ expect(policy.enabledRules).to.contain('reflected-xss');
25
+
26
+ core.messages.emit(Event.SERVER_SETTINGS_UPDATE, {
27
+ assess: {
28
+ ['sql-injection']: { enable: true },
29
+ ['reflected-xss']: { enable: false },
30
+ }
31
+ });
32
+
33
+ policy = getPolicy();
34
+
35
+ expect(policy.enabledRules).to.contain('sql-injection');
36
+ expect(policy.enabledRules).not.to.contain('reflected-xss');
37
+ });
38
+
39
+ it('url exclusions can disable all rules', function() {
40
+ const uriPath = '/exclude-all-rules';
41
+ let policy = getPolicy({ uriPath });
42
+
43
+ assertPolicyOK(policy);
44
+
45
+ core.messages.emit(Event.SERVER_SETTINGS_UPDATE, {
46
+ exclusions: {
47
+ url: [{
48
+ urls: ['/exclude-all-rules'],
49
+ matchStrategy: 'ONLY',
50
+ assessmentRules: [],
51
+ assess_rules: [],
52
+ protect_rules: [],
53
+ modes: ['assess', 'defend'],
54
+ name: 'UrlExclusionAllRules'
55
+ }]
56
+ }
57
+ });
58
+
59
+ policy = getPolicy({ uriPath });
60
+ expect(policy).to.be.null;
61
+ });
62
+
63
+ it('url exclusions can disable specific rules', function() {
64
+ const uriPath = '/exclude-some-rules';
65
+ let policy = getPolicy({ uriPath });
66
+
67
+ assertPolicyOK(policy);
68
+
69
+ core.messages.emit(Event.SERVER_SETTINGS_UPDATE, {
70
+ exclusions: {
71
+ url: [{
72
+ urls: ['/exclude-some-rules'],
73
+ matchStrategy: 'ONLY',
74
+ assessmentRules: [],
75
+ assess_rules: ['sql-injection'],
76
+ protect_rules: [],
77
+ modes: ['assess', 'defend'],
78
+ name: 'UrlExclusionAllRules'
79
+ }]
80
+ }
81
+ });
82
+
83
+ policy = getPolicy({ uriPath });
84
+ expect(policy.enabledRules).not.to.contain('sql-injection');
85
+ });
86
+
87
+ [
88
+ {
89
+ inputType: 'HEADER',
90
+ exclusionType: 'HEADER',
91
+ },
92
+ {
93
+ inputType: 'QUERYSTRING',
94
+ exclusionType: 'PARAMETER',
95
+ },
96
+ {
97
+ inputType: 'BODY',
98
+ exclusionType: 'PARAMETER',
99
+ },
100
+ {
101
+ inputType: 'URL_PARAMETER',
102
+ exclusionType: 'PARAMETER',
103
+ },
104
+ {
105
+ inputType: 'COOKIE_VALUE',
106
+ exclusionType: 'COOKIE',
107
+ },
108
+ ].forEach(({ inputType, exclusionType }) => {
109
+ it(`input exclusions can exclude specific rules (input: ${inputType}, exclusion:${exclusionType})`, function() {
110
+ core.messages.emit(Event.SERVER_SETTINGS_UPDATE, {
111
+ exclusions: {
112
+ input: [{
113
+ type: exclusionType,
114
+ urls: ['/exclude-some-inputs', '/exclude-some-inputs-.*'],
115
+ matchStrategy: 'ONLY',
116
+ assessmentRules: [],
117
+ assess_rules: ['sql-injection', 'nosql-injection'],
118
+ protect_rules: [],
119
+ modes: ['assess', 'defend'],
120
+ name: 'abc.*'
121
+ }]
122
+ }
123
+ });
124
+
125
+ const policy = getPolicy({ uriPath: '/exclude-some-inputs' });
126
+ let inputPolicy = policy.getInputPolicy(inputType, 'abcdef');
127
+ expect(inputPolicy).to.have.property('track', true);
128
+ expect(inputPolicy).to.have.property('excludedRules')
129
+ .to.be.a('Set')
130
+ .and.have.lengthOf(2)
131
+ .and.contain('nosql-injection')
132
+ .and.contain('sql-injection');
133
+
134
+ inputPolicy = policy.getInputPolicy(inputType, 'xyz');
135
+ expect(inputPolicy).to.have.property('track', true);
136
+ expect(inputPolicy).to.have.property('excludedRules')
137
+ .to.be.a('Set')
138
+ .and.have.lengthOf(0);
139
+ });
140
+ });
141
+
142
+ [
143
+ {
144
+ inputType: 'HEADER',
145
+ exclusionType: 'HEADER',
146
+ },
147
+ {
148
+ inputType: 'QUERYSTRING',
149
+ exclusionType: 'PARAMETER',
150
+ },
151
+ {
152
+ inputType: 'BODY',
153
+ exclusionType: 'PARAMETER',
154
+ },
155
+ {
156
+ inputType: 'URL_PARAMETER',
157
+ exclusionType: 'PARAMETER',
158
+ },
159
+ {
160
+ inputType: 'COOKIE_VALUE',
161
+ exclusionType: 'COOKIE',
162
+ },
163
+ ].forEach(({ inputType, exclusionType }) => {
164
+ it(`input exclusions can exclude specific rules (input: ${inputType}, exclusion:${exclusionType})`, function() {
165
+ core.messages.emit(Event.SERVER_SETTINGS_UPDATE, {
166
+ exclusions: {
167
+ input: [{
168
+ type: exclusionType,
169
+ urls: ['/exclude-some-inputs', '/exclude-some-inputs-.*'],
170
+ matchStrategy: 'ONLY',
171
+ assessmentRules: [],
172
+ assess_rules: [],
173
+ protect_rules: [],
174
+ modes: ['assess', 'defend'],
175
+ name: 'abc.*'
176
+ }]
177
+ }
178
+ });
179
+
180
+ const policy = getPolicy({ uriPath: '/exclude-some-inputs' });
181
+ let inputPolicy;
182
+
183
+ inputPolicy = policy.getInputPolicy(inputType, 'abcdef');
184
+ expect(inputPolicy).to.have.property('track', false);
185
+ expect(inputPolicy).not.to.have.property('excludedRules');
186
+
187
+ inputPolicy = policy.getInputPolicy(inputType, 'xyz');
188
+ expect(inputPolicy).to.have.property('track', true);
189
+ expect(inputPolicy).to.have.property('excludedRules')
190
+ .to.be.a('Set')
191
+ .and.have.lengthOf(0);
192
+ });
193
+ });
194
+ });