@contrast/protect 1.54.0 → 1.54.2
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.
- package/package.json +14 -11
- package/lib/error-handlers/common-handler.test.js +0 -52
- package/lib/error-handlers/index.test.js +0 -32
- package/lib/error-handlers/init-domain.test.js +0 -22
- package/lib/error-handlers/install/express.test.js +0 -290
- package/lib/error-handlers/install/fastify.test.js +0 -130
- package/lib/error-handlers/install/hapi.test.js +0 -102
- package/lib/error-handlers/install/koa2.test.js +0 -83
- package/lib/error-handlers/install/restify.test.js +0 -57
- package/lib/get-source-context.test.js +0 -35
- package/lib/hardening/handlers.test.js +0 -89
- package/lib/hardening/index.test.js +0 -31
- package/lib/hardening/install/node-serialize0.test.js +0 -58
- package/lib/index.test.js +0 -53
- package/lib/input-analysis/handlers.test.js +0 -1604
- package/lib/input-analysis/index.test.js +0 -45
- package/lib/input-analysis/install/body-parser1.test.js +0 -134
- package/lib/input-analysis/install/busboy1.test.js +0 -81
- package/lib/input-analysis/install/cookie-parser1.test.js +0 -144
- package/lib/input-analysis/install/express.test.js +0 -241
- package/lib/input-analysis/install/fastify.test.js +0 -96
- package/lib/input-analysis/install/formidable1.test.js +0 -114
- package/lib/input-analysis/install/hapi.test.js +0 -292
- package/lib/input-analysis/install/http.test.js +0 -270
- package/lib/input-analysis/install/koa-body5.test.js +0 -92
- package/lib/input-analysis/install/koa-bodyparser4.test.js +0 -92
- package/lib/input-analysis/install/koa2.test.js +0 -259
- package/lib/input-analysis/install/multer1.test.js +0 -209
- package/lib/input-analysis/install/qs6.test.js +0 -79
- package/lib/input-analysis/install/restify.test.js +0 -98
- package/lib/input-analysis/install/universal-cookie4.test.js +0 -70
- package/lib/input-analysis/ip-analysis.test.js +0 -71
- package/lib/input-analysis/virtual-patches.test.js +0 -106
- package/lib/input-tracing/handlers/index.test.js +0 -1237
- package/lib/input-tracing/index.test.js +0 -62
- package/lib/input-tracing/install/child-process.test.js +0 -133
- package/lib/input-tracing/install/eval.test.js +0 -78
- package/lib/input-tracing/install/fs.test.js +0 -108
- package/lib/input-tracing/install/function.test.js +0 -81
- package/lib/input-tracing/install/http.test.js +0 -85
- package/lib/input-tracing/install/http2.test.js +0 -83
- package/lib/input-tracing/install/marsdb.test.js +0 -126
- package/lib/input-tracing/install/mongodb.test.js +0 -280
- package/lib/input-tracing/install/mssql.test.js +0 -81
- package/lib/input-tracing/install/mysql.test.js +0 -108
- package/lib/input-tracing/install/postgres.test.js +0 -117
- package/lib/input-tracing/install/sequelize.test.js +0 -78
- package/lib/input-tracing/install/spdy.test.js +0 -76
- package/lib/input-tracing/install/sqlite3.test.js +0 -88
- package/lib/input-tracing/install/vm.test.js +0 -176
- package/lib/make-response-blocker.test.js +0 -99
- package/lib/make-source-context.test.js +0 -219
- package/lib/policy.test.js +0 -446
- package/lib/semantic-analysis/handlers.test.js +0 -379
- package/lib/semantic-analysis/index.test.js +0 -38
- package/lib/semantic-analysis/install/libxmljs.test.js +0 -156
- package/lib/semantic-analysis/utils/xml-analysis.test.js +0 -156
- package/lib/throw-security-exception.test.js +0 -37
|
@@ -1,259 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const sinon = require('sinon');
|
|
4
|
-
const { expect } = require('chai');
|
|
5
|
-
const scopes = require('@contrast/scopes');
|
|
6
|
-
const patcher = require('@contrast/patcher');
|
|
7
|
-
const mocks = require('@contrast/test/mocks');
|
|
8
|
-
const koaInstr = require('./koa2');
|
|
9
|
-
|
|
10
|
-
describe('protect input-analysis koa v2.x', function () {
|
|
11
|
-
let core,
|
|
12
|
-
inputAnalysis,
|
|
13
|
-
koaMock,
|
|
14
|
-
routerMock,
|
|
15
|
-
legacyRouterMock,
|
|
16
|
-
cookieMock,
|
|
17
|
-
nextStub,
|
|
18
|
-
query,
|
|
19
|
-
params,
|
|
20
|
-
cookies;
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
beforeEach(function () {
|
|
24
|
-
core = mocks.core();
|
|
25
|
-
core.logger = mocks.logger();
|
|
26
|
-
core.scopes = scopes(core);
|
|
27
|
-
core.protect = mocks.protect();
|
|
28
|
-
require('../../get-source-context')(core);
|
|
29
|
-
core.depHooks = mocks.depHooks();
|
|
30
|
-
core.patcher = patcher(core);
|
|
31
|
-
sinon.spy(core.patcher, 'patch');
|
|
32
|
-
|
|
33
|
-
query = { parameter: 'parsed-query' };
|
|
34
|
-
params = { parameter: 'parsed-param' };
|
|
35
|
-
cookies = { parameter: 'parsed-cookie' };
|
|
36
|
-
koaMock = {
|
|
37
|
-
prototype: {
|
|
38
|
-
middleware: [],
|
|
39
|
-
use: (newMiddleware) => {
|
|
40
|
-
newMiddleware && koaMock.prototype.middleware && koaMock.prototype.middleware.push(newMiddleware);
|
|
41
|
-
},
|
|
42
|
-
}
|
|
43
|
-
};
|
|
44
|
-
|
|
45
|
-
routerMock = {
|
|
46
|
-
prototype: {
|
|
47
|
-
params: (parameters) => parameters || {}
|
|
48
|
-
}
|
|
49
|
-
};
|
|
50
|
-
|
|
51
|
-
legacyRouterMock = {
|
|
52
|
-
prototype: {
|
|
53
|
-
params: (parameters) => parameters || {}
|
|
54
|
-
}
|
|
55
|
-
};
|
|
56
|
-
|
|
57
|
-
cookieMock = {
|
|
58
|
-
default: (cookie) => (ctx, next) => {
|
|
59
|
-
ctx.cookie = cookie;
|
|
60
|
-
next();
|
|
61
|
-
}
|
|
62
|
-
};
|
|
63
|
-
|
|
64
|
-
const mockDict = {
|
|
65
|
-
['koa']: koaMock,
|
|
66
|
-
['koa-router']: legacyRouterMock,
|
|
67
|
-
['@koa/router']: routerMock,
|
|
68
|
-
['koa-cookie']: cookieMock
|
|
69
|
-
};
|
|
70
|
-
|
|
71
|
-
core.depHooks.resolve.callsFake(function (desc, cb) {
|
|
72
|
-
const cbArg = mockDict[desc.name];
|
|
73
|
-
if (cbArg) {
|
|
74
|
-
cb(cbArg);
|
|
75
|
-
}
|
|
76
|
-
});
|
|
77
|
-
nextStub = sinon.stub();
|
|
78
|
-
|
|
79
|
-
inputAnalysis = core.protect.inputAnalysis;
|
|
80
|
-
koaInstr(core).install();
|
|
81
|
-
core.patcher.patch.resetHistory();
|
|
82
|
-
});
|
|
83
|
-
|
|
84
|
-
it('calls patcher for every necessary instrumentation', function () {
|
|
85
|
-
koaInstr(core).install();
|
|
86
|
-
expect(core.patcher.patch).to.have.callCount(4);
|
|
87
|
-
expect(core.patcher.patch).to.have.been.calledWithMatch(koaMock.prototype, 'use', {
|
|
88
|
-
name: 'Koa.Application',
|
|
89
|
-
patchType: 'protect-input-analysis',
|
|
90
|
-
pre: sinon.match.func
|
|
91
|
-
});
|
|
92
|
-
expect(core.patcher.patch).to.have.been.calledWithMatch(legacyRouterMock.prototype, 'params', {
|
|
93
|
-
name: '[koa-router].layer.prototype',
|
|
94
|
-
patchType: 'protect-input-analysis',
|
|
95
|
-
post: sinon.match.func
|
|
96
|
-
});
|
|
97
|
-
expect(core.patcher.patch).to.have.been.calledWithMatch(routerMock.prototype, 'params', {
|
|
98
|
-
name: '[@koa/router].layer.prototype',
|
|
99
|
-
patchType: 'protect-input-analysis',
|
|
100
|
-
post: sinon.match.func
|
|
101
|
-
});
|
|
102
|
-
expect(core.patcher.patch).to.have.been.calledWithMatch(sinon.match.func, {
|
|
103
|
-
name: 'koa-cookie',
|
|
104
|
-
patchType: 'protect-input-analysis',
|
|
105
|
-
post: sinon.match.func
|
|
106
|
-
});
|
|
107
|
-
});
|
|
108
|
-
|
|
109
|
-
describe('contrastStartMiddleware', function () {
|
|
110
|
-
it('successfully injects contrastMiddleware', function () {
|
|
111
|
-
koaMock.prototype.use('test');
|
|
112
|
-
|
|
113
|
-
expect(koaMock.prototype.middleware.length).to.equal(2);
|
|
114
|
-
expect(koaMock.prototype.middleware[0]._isContrastStartMiddleware).to.be.true;
|
|
115
|
-
});
|
|
116
|
-
|
|
117
|
-
it('does not inject contrastMiddleware if there is one already injected', function () {
|
|
118
|
-
koaMock.prototype.middleware.push({ _isContrastStartMiddleware: true });
|
|
119
|
-
koaMock.prototype.use();
|
|
120
|
-
|
|
121
|
-
expect(koaMock.prototype.middleware.length).to.equal(1);
|
|
122
|
-
});
|
|
123
|
-
|
|
124
|
-
it('does not call `.handleQueryParams` if there is no query on the ctx for `contrastStartMiddleware`', function () {
|
|
125
|
-
koaMock.prototype.use();
|
|
126
|
-
|
|
127
|
-
const contrastStartMiddleware = koaMock.prototype.middleware[0];
|
|
128
|
-
|
|
129
|
-
core.scopes.sources.run({ protect: {} }, () => {
|
|
130
|
-
contrastStartMiddleware({}, nextStub);
|
|
131
|
-
});
|
|
132
|
-
expect(nextStub).to.have.been.calledOnce;
|
|
133
|
-
expect(inputAnalysis.handleQueryParams).not.to.have.been.called;
|
|
134
|
-
});
|
|
135
|
-
|
|
136
|
-
it('calls `.handleQueryParams` if there is query on the ctx for `contrastStartMiddleware`', function () {
|
|
137
|
-
koaMock.prototype.use();
|
|
138
|
-
|
|
139
|
-
const contrastStartMiddleware = koaMock.prototype.middleware[0];
|
|
140
|
-
|
|
141
|
-
core.scopes.sources.run({ protect: {} }, () => {
|
|
142
|
-
contrastStartMiddleware({ query }, nextStub);
|
|
143
|
-
});
|
|
144
|
-
|
|
145
|
-
expect(nextStub).to.have.been.calledOnce;
|
|
146
|
-
expect(inputAnalysis.handleQueryParams).to.have.been.calledOnce;
|
|
147
|
-
expect(inputAnalysis.handleQueryParams).to.have.been.calledWithMatch({ parsedQuery: query }, query);
|
|
148
|
-
});
|
|
149
|
-
|
|
150
|
-
it('does not call `.handleQueryParams` if there is query on the ctx for `contrastStartMiddleware`, but we have already analyzed it', function () {
|
|
151
|
-
koaMock.prototype.use();
|
|
152
|
-
|
|
153
|
-
const contrastStartMiddleware = koaMock.prototype.middleware[0];
|
|
154
|
-
|
|
155
|
-
core.scopes.sources.run({ protect: { parsedQuery: 'analyzed-query' } }, () => {
|
|
156
|
-
contrastStartMiddleware({ query }, nextStub);
|
|
157
|
-
});
|
|
158
|
-
|
|
159
|
-
expect(nextStub).to.have.been.calledOnce;
|
|
160
|
-
expect(inputAnalysis.handleQueryParams).not.to.have.been.called;
|
|
161
|
-
});
|
|
162
|
-
|
|
163
|
-
it('does not call `.handleQueryParams` if there is no context', function () {
|
|
164
|
-
koaMock.prototype.use();
|
|
165
|
-
|
|
166
|
-
const contrastStartMiddleware = koaMock.prototype.middleware[0];
|
|
167
|
-
|
|
168
|
-
core.scopes.sources.run({}, () => {
|
|
169
|
-
contrastStartMiddleware({ query }, nextStub);
|
|
170
|
-
});
|
|
171
|
-
|
|
172
|
-
expect(nextStub).to.have.been.calledOnce;
|
|
173
|
-
expect(inputAnalysis.handleQueryParams).not.to.have.been.called;
|
|
174
|
-
});
|
|
175
|
-
|
|
176
|
-
});
|
|
177
|
-
|
|
178
|
-
describe('koa routers post hook', function () {
|
|
179
|
-
let getParamsFn;
|
|
180
|
-
this.beforeEach(function () {
|
|
181
|
-
getParamsFn = function (routerName) {
|
|
182
|
-
return routerName == 'koa-router' ? legacyRouterMock.prototype.params : routerMock.prototype.params;
|
|
183
|
-
};
|
|
184
|
-
});
|
|
185
|
-
['koa-router', '@koa/router'].forEach((router) => {
|
|
186
|
-
it(`[${router}] calls \`.handleUrlParams\` when parsing is successful and in the right context`, function () {
|
|
187
|
-
const paramsFn = getParamsFn(router);
|
|
188
|
-
core.scopes.sources.run({ protect: {} }, () => {
|
|
189
|
-
paramsFn(params);
|
|
190
|
-
});
|
|
191
|
-
|
|
192
|
-
expect(inputAnalysis.handleUrlParams).to.have.been.calledOnce;
|
|
193
|
-
expect(inputAnalysis.handleUrlParams).to.have.been.calledWithMatch({ parsedParams: params }, params);
|
|
194
|
-
});
|
|
195
|
-
|
|
196
|
-
it(`[${router}] does not call \`.handleUrlParams\` when there is no result from the parsing`, function () {
|
|
197
|
-
const paramsFn = getParamsFn(router);
|
|
198
|
-
|
|
199
|
-
core.scopes.sources.run({ protect: {} }, () => {
|
|
200
|
-
paramsFn(null);
|
|
201
|
-
});
|
|
202
|
-
|
|
203
|
-
expect(inputAnalysis.handleUrlParams).not.to.have.been.called;
|
|
204
|
-
});
|
|
205
|
-
|
|
206
|
-
it(`[${router}] does not call \`.handleUrlParams\` when there is no context`, function () {
|
|
207
|
-
const paramsFn = getParamsFn(router);
|
|
208
|
-
|
|
209
|
-
core.scopes.sources.run({}, () => {
|
|
210
|
-
paramsFn(params);
|
|
211
|
-
});
|
|
212
|
-
|
|
213
|
-
expect(inputAnalysis.handleUrlParams).not.to.have.been.called;
|
|
214
|
-
});
|
|
215
|
-
});
|
|
216
|
-
});
|
|
217
|
-
|
|
218
|
-
describe('koa-cookie patcher hooks', function () {
|
|
219
|
-
it('calls `.handleCookies` when parsing is successful and in right context', function () {
|
|
220
|
-
core.scopes.sources.run({ protect: {} }, () => {
|
|
221
|
-
const cParser = cookieMock.default(cookies);
|
|
222
|
-
cParser({}, nextStub);
|
|
223
|
-
});
|
|
224
|
-
|
|
225
|
-
expect(core.patcher.patch).to.have.been.calledOnce;
|
|
226
|
-
expect(core.patcher.patch).to.have.been.calledWithMatch(sinon.match.func, {
|
|
227
|
-
name: 'koa-cookie',
|
|
228
|
-
patchType: 'protect-input-analysis',
|
|
229
|
-
pre: sinon.match.func
|
|
230
|
-
});
|
|
231
|
-
|
|
232
|
-
expect(nextStub).to.have.been.calledOnce;
|
|
233
|
-
expect(inputAnalysis.handleCookies).to.have.been.calledOnce;
|
|
234
|
-
expect(inputAnalysis.handleCookies).to.have.been.calledWithMatch({ parsedCookies: cookies }, cookies);
|
|
235
|
-
});
|
|
236
|
-
|
|
237
|
-
it('does not call `.handleCookies` when not in context', function () {
|
|
238
|
-
core.scopes.sources.run({}, () => {
|
|
239
|
-
const cParser = cookieMock.default(cookies);
|
|
240
|
-
cParser({}, nextStub);
|
|
241
|
-
});
|
|
242
|
-
|
|
243
|
-
expect(inputAnalysis.handleCookies).not.to.have.been.called;
|
|
244
|
-
expect(nextStub).to.have.been.calledOnce;
|
|
245
|
-
});
|
|
246
|
-
|
|
247
|
-
it('does not call `.handleCookies` when `cookie-parser` does not return a result', function () {
|
|
248
|
-
core.scopes.sources.run({ protect: {} }, () => {
|
|
249
|
-
const cParser = cookieMock.default();
|
|
250
|
-
cParser({}, nextStub);
|
|
251
|
-
});
|
|
252
|
-
|
|
253
|
-
expect(inputAnalysis.handleCookies).not.to.have.been.called;
|
|
254
|
-
expect(core.logger.debug).not.to.have.been.called;
|
|
255
|
-
expect(nextStub).to.have.been.calledOnce;
|
|
256
|
-
});
|
|
257
|
-
});
|
|
258
|
-
|
|
259
|
-
});
|
|
@@ -1,209 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const sinon = require('sinon');
|
|
4
|
-
const { expect } = require('chai');
|
|
5
|
-
const scopes = require('@contrast/scopes');
|
|
6
|
-
const patcher = require('@contrast/patcher');
|
|
7
|
-
const mocks = require('@contrast/test/mocks');
|
|
8
|
-
const SecurityException = require('../../security-exception');
|
|
9
|
-
const secEx = SecurityException.create();
|
|
10
|
-
const multerInstr = require('./multer1');
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
describe('protect input-analysis multer v1.x', function () {
|
|
14
|
-
let core, inputAnalysis, multerMock, patchedMulter, payload, nextStub;
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
beforeEach(function () {
|
|
18
|
-
core = mocks.core();
|
|
19
|
-
core.logger = mocks.logger();
|
|
20
|
-
core.scopes = scopes(core);
|
|
21
|
-
core.protect = mocks.protect();
|
|
22
|
-
require('../../get-source-context')(core);
|
|
23
|
-
core.depHooks = mocks.depHooks();
|
|
24
|
-
core.patcher = patcher(core);
|
|
25
|
-
|
|
26
|
-
inputAnalysis = core.protect.inputAnalysis;
|
|
27
|
-
payload = { body: { parameter: 'parsed' }, file: { originalname: 'some-file' } };
|
|
28
|
-
multerMock = (payload) => (req, res, next) => {
|
|
29
|
-
if (payload) {
|
|
30
|
-
req.body = payload.body;
|
|
31
|
-
req.file = payload.file;
|
|
32
|
-
req.files = payload.files;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
next();
|
|
36
|
-
};
|
|
37
|
-
nextStub = sinon.stub();
|
|
38
|
-
sinon.spy(core.patcher, 'patch');
|
|
39
|
-
|
|
40
|
-
multerInstr(core).install();
|
|
41
|
-
patchedMulter = core.depHooks.resolve.yield(multerMock)[0];
|
|
42
|
-
|
|
43
|
-
core.patcher.patch.resetHistory();
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
it('calls patcher on the `multer` module export', function () {
|
|
47
|
-
core.depHooks.resolve.yield(multerMock);
|
|
48
|
-
|
|
49
|
-
expect(core.patcher.patch).to.have.been.calledOnce;
|
|
50
|
-
expect(core.patcher.patch).to.have.been.calledWithMatch(multerMock, {
|
|
51
|
-
name: 'multer.make-middleware',
|
|
52
|
-
patchType: 'protect-input-analysis',
|
|
53
|
-
post: sinon.match.func
|
|
54
|
-
});
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
it('calls `.handleParsedBody` and `handleFileUploadName` when parsing is successful and in right context', function () {
|
|
58
|
-
core.scopes.sources.run({ protect: {} }, () => {
|
|
59
|
-
const cParser = patchedMulter(payload);
|
|
60
|
-
cParser({}, {}, nextStub);
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
expect(core.patcher.patch).to.have.been.calledOnce;
|
|
64
|
-
expect(core.patcher.patch).to.have.been.calledWithMatch(sinon.match.func, {
|
|
65
|
-
name: 'multerMiddleware',
|
|
66
|
-
patchType: 'protect-input-analysis',
|
|
67
|
-
pre: sinon.match.func
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
expect(nextStub).to.have.been.calledOnce;
|
|
71
|
-
expect(inputAnalysis.handleParsedBody).to.have.been.calledOnce;
|
|
72
|
-
expect(inputAnalysis.handleParsedBody).to.have.been.calledWithMatch({ parsedBody: payload.body }, payload.body);
|
|
73
|
-
expect(inputAnalysis.handleFileUploadName).to.have.been.calledOnce;
|
|
74
|
-
expect(inputAnalysis.handleFileUploadName).to.have.been.calledWithMatch({ parsedBody: payload.body }, ['some-file']);
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
it('calls `.handleParsedBody` when parsing is successful and in right context, but payload has no files', function () {
|
|
78
|
-
payload.file = null;
|
|
79
|
-
core.scopes.sources.run({ protect: {} }, () => {
|
|
80
|
-
const cParser = patchedMulter(payload);
|
|
81
|
-
cParser({}, {}, nextStub);
|
|
82
|
-
});
|
|
83
|
-
|
|
84
|
-
expect(core.patcher.patch).to.have.been.calledOnce;
|
|
85
|
-
expect(core.patcher.patch).to.have.been.calledWithMatch(sinon.match.func, {
|
|
86
|
-
name: 'multerMiddleware',
|
|
87
|
-
patchType: 'protect-input-analysis',
|
|
88
|
-
pre: sinon.match.func
|
|
89
|
-
});
|
|
90
|
-
|
|
91
|
-
expect(nextStub).to.have.been.calledOnce;
|
|
92
|
-
expect(inputAnalysis.handleParsedBody).to.have.been.calledOnce;
|
|
93
|
-
expect(inputAnalysis.handleParsedBody).to.have.been.calledWithMatch({ parsedBody: payload.body }, payload.body);
|
|
94
|
-
expect(core.logger.debug).not.to.have.been.called;
|
|
95
|
-
});
|
|
96
|
-
|
|
97
|
-
it('does not call `.handleParsedBody` when not in context', function () {
|
|
98
|
-
core.scopes.sources.run({}, () => {
|
|
99
|
-
const cParser = patchedMulter(payload);
|
|
100
|
-
cParser({}, {}, nextStub);
|
|
101
|
-
});
|
|
102
|
-
|
|
103
|
-
expect(inputAnalysis.handleParsedBody).not.to.have.been.called;
|
|
104
|
-
expect(nextStub).to.have.been.calledOnce;
|
|
105
|
-
});
|
|
106
|
-
|
|
107
|
-
it('does not call `.handleParsedBody` when `multer` there is a result, but only files are uploaded', function () {
|
|
108
|
-
payload.body = null;
|
|
109
|
-
core.scopes.sources.run({ protect: {} }, () => {
|
|
110
|
-
const cParser = patchedMulter(payload);
|
|
111
|
-
cParser({}, {}, nextStub);
|
|
112
|
-
});
|
|
113
|
-
|
|
114
|
-
expect(inputAnalysis.handleParsedBody).not.to.have.been.called;
|
|
115
|
-
expect(inputAnalysis.handleFileUploadName).to.have.been.calledOnce;
|
|
116
|
-
expect(inputAnalysis.handleFileUploadName).to.have.been.calledWithMatch({}, ['some-file']);
|
|
117
|
-
expect(nextStub).to.have.been.calledOnce;
|
|
118
|
-
});
|
|
119
|
-
|
|
120
|
-
it('handles case with multiple files uploaded in an array', function () {
|
|
121
|
-
core.scopes.sources.run({ protect: {} }, () => {
|
|
122
|
-
const cParser = patchedMulter({ files: [{ originalname: 'some-file-1' }, { originalname: 'some-file-2' }] });
|
|
123
|
-
cParser({}, {}, nextStub);
|
|
124
|
-
});
|
|
125
|
-
|
|
126
|
-
expect(inputAnalysis.handleParsedBody).not.to.have.been.called;
|
|
127
|
-
expect(inputAnalysis.handleFileUploadName).to.have.been.calledOnce;
|
|
128
|
-
expect(inputAnalysis.handleFileUploadName).to.have.been.calledWithMatch({}, ['some-file-1', 'some-file-2']);
|
|
129
|
-
expect(nextStub).to.have.been.calledOnce;
|
|
130
|
-
});
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
it('handles case with multiple files uploaded in an object', function () {
|
|
134
|
-
core.scopes.sources.run({ protect: {} }, () => {
|
|
135
|
-
const cParser = patchedMulter({ files: { file1: { originalname: 'some-file-1' }, file2: { originalname: 'some-file-2' } } });
|
|
136
|
-
cParser({}, {}, nextStub);
|
|
137
|
-
});
|
|
138
|
-
|
|
139
|
-
expect(inputAnalysis.handleParsedBody).not.to.have.been.called;
|
|
140
|
-
expect(inputAnalysis.handleFileUploadName).to.have.been.calledOnce;
|
|
141
|
-
expect(inputAnalysis.handleFileUploadName).to.have.been.calledWithMatch({}, ['some-file-1', 'some-file-2']);
|
|
142
|
-
expect(nextStub).to.have.been.calledOnce;
|
|
143
|
-
});
|
|
144
|
-
|
|
145
|
-
it('does not call `.handleParsedBody` when `multer` does not have a body or files', function () {
|
|
146
|
-
core.scopes.sources.run({ protect: {} }, () => {
|
|
147
|
-
const cParser = patchedMulter();
|
|
148
|
-
cParser({}, {}, nextStub);
|
|
149
|
-
});
|
|
150
|
-
|
|
151
|
-
expect(inputAnalysis.handleParsedBody).not.to.have.been.called;
|
|
152
|
-
expect(core.logger.debug).not.to.have.been.called;
|
|
153
|
-
expect(nextStub).to.have.been.calledOnce;
|
|
154
|
-
});
|
|
155
|
-
|
|
156
|
-
it('handles a case with SecurityException from `.handleParsedBody`', function () {
|
|
157
|
-
inputAnalysis.handleParsedBody.throws(secEx);
|
|
158
|
-
core.scopes.sources.run({ protect: {} }, () => {
|
|
159
|
-
const cParser = patchedMulter(payload);
|
|
160
|
-
cParser({}, {}, nextStub);
|
|
161
|
-
});
|
|
162
|
-
|
|
163
|
-
expect(nextStub).to.have.been.calledOnceWith(secEx);
|
|
164
|
-
});
|
|
165
|
-
|
|
166
|
-
it('handles a case with SecurityException from `.handleFileUploadName`', function () {
|
|
167
|
-
inputAnalysis.handleFileUploadName.throws(secEx);
|
|
168
|
-
core.scopes.sources.run({ protect: {} }, () => {
|
|
169
|
-
const cParser = patchedMulter(payload);
|
|
170
|
-
cParser({}, {}, nextStub);
|
|
171
|
-
});
|
|
172
|
-
|
|
173
|
-
expect(nextStub).to.have.been.calledOnceWith(secEx);
|
|
174
|
-
});
|
|
175
|
-
|
|
176
|
-
it('handles a case with an error in the input analysis from `.handleParsedBody`', function () {
|
|
177
|
-
const err = new Error('Input Analysis Error');
|
|
178
|
-
|
|
179
|
-
inputAnalysis.handleParsedBody.throws(err);
|
|
180
|
-
core.scopes.sources.run({ protect: {} }, () => {
|
|
181
|
-
const cParser = patchedMulter(payload);
|
|
182
|
-
cParser({}, {}, nextStub);
|
|
183
|
-
});
|
|
184
|
-
|
|
185
|
-
expect(core.logger.error).to.have.been.calledWith(
|
|
186
|
-
{ err, funcKey: 'protect-input-analysis:multerMiddleware' },
|
|
187
|
-
'Unexpected error during input analysis'
|
|
188
|
-
);
|
|
189
|
-
expect(nextStub).to.have.been.calledOnce;
|
|
190
|
-
expect(nextStub).not.to.have.been.calledWith(err);
|
|
191
|
-
});
|
|
192
|
-
|
|
193
|
-
it('handles a case with an error in the input analysis from `.handleFileUploadName`', function () {
|
|
194
|
-
const err = new Error('Input Analysis Error');
|
|
195
|
-
|
|
196
|
-
inputAnalysis.handleFileUploadName.throws(err);
|
|
197
|
-
core.scopes.sources.run({ protect: {} }, () => {
|
|
198
|
-
const cParser = patchedMulter(payload);
|
|
199
|
-
cParser({}, {}, nextStub);
|
|
200
|
-
});
|
|
201
|
-
|
|
202
|
-
expect(core.logger.error).to.have.been.calledWith(
|
|
203
|
-
{ err, funcKey: 'protect-input-analysis:multerMiddleware' },
|
|
204
|
-
'Unexpected error during input analysis'
|
|
205
|
-
);
|
|
206
|
-
expect(nextStub).to.have.been.calledOnce;
|
|
207
|
-
expect(nextStub).not.to.have.been.calledWith(err);
|
|
208
|
-
});
|
|
209
|
-
});
|
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const sinon = require('sinon');
|
|
4
|
-
const { expect } = require('chai');
|
|
5
|
-
const scopes = require('@contrast/scopes');
|
|
6
|
-
const patcher = require('@contrast/patcher');
|
|
7
|
-
const mocks = require('@contrast/test/mocks');
|
|
8
|
-
const qsInstr = require('./qs6');
|
|
9
|
-
|
|
10
|
-
describe('protect input-analysis qs v6.x', function () {
|
|
11
|
-
let core, inputAnalysis, qsMock, patchedQs, query;
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
beforeEach(function () {
|
|
15
|
-
core = mocks.core();
|
|
16
|
-
core.logger = mocks.logger();
|
|
17
|
-
core.scopes = scopes(core);
|
|
18
|
-
core.protect = mocks.protect();
|
|
19
|
-
require('../../get-source-context')(core);
|
|
20
|
-
core.depHooks = mocks.depHooks();
|
|
21
|
-
core.patcher = patcher(core);
|
|
22
|
-
|
|
23
|
-
inputAnalysis = core.protect.inputAnalysis;
|
|
24
|
-
query = 'non-parsed';
|
|
25
|
-
qsMock = {
|
|
26
|
-
parse: (query) => ({ query } || {})
|
|
27
|
-
};
|
|
28
|
-
sinon.spy(core.patcher, 'patch');
|
|
29
|
-
|
|
30
|
-
qsInstr(core).install();
|
|
31
|
-
patchedQs = core.depHooks.resolve.yield(qsMock)[0];
|
|
32
|
-
core.patcher.patch.resetHistory();
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
it('calls patcher on the `.parse` method', function () {
|
|
36
|
-
core.depHooks.resolve.yield(qsMock);
|
|
37
|
-
|
|
38
|
-
expect(core.patcher.patch).to.have.been.calledOnce;
|
|
39
|
-
expect(core.patcher.patch).to.have.been.calledWithMatch(qsMock, 'parse', {
|
|
40
|
-
name: 'qs',
|
|
41
|
-
patchType: 'protect-input-analysis',
|
|
42
|
-
post: sinon.match.func
|
|
43
|
-
});
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
it('calls `.handleQueryParams` when parsing is successful, in right context and with reqData.queries present', function () {
|
|
47
|
-
core.scopes.sources.run({ protect: { reqData: { queries: 'non-parsed' } } }, () => {
|
|
48
|
-
patchedQs.parse(query);
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
expect(inputAnalysis.handleQueryParams).to.have.been.calledOnce;
|
|
52
|
-
expect(inputAnalysis.handleQueryParams).to.have.been.calledWithMatch({ parsedQuery: { query } }, { query });
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
it('does not call `.handleQueryParams` when parsing is successful, in right context but with reqData.queries not present', function () {
|
|
56
|
-
core.scopes.sources.run({ protect: { reqData: { queries: '' } } }, () => {
|
|
57
|
-
patchedQs.parse(query);
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
expect(inputAnalysis.handleQueryParams).not.to.have.been.called;
|
|
61
|
-
expect(core.logger.debug).not.to.have.been.called;
|
|
62
|
-
});
|
|
63
|
-
|
|
64
|
-
it('does not call `.handleQueryParams` when not in context', function () {
|
|
65
|
-
core.scopes.sources.run({}, () => {
|
|
66
|
-
patchedQs.parse(query);
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
expect(inputAnalysis.handleQueryParams).not.to.have.been.called;
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
it('does not call `.handleQueryParams` when `qs` does not return a result', function () {
|
|
73
|
-
core.scopes.sources.run({ protect: {} }, () => {
|
|
74
|
-
patchedQs.parse(null);
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
expect(inputAnalysis.handleQueryParams).not.to.have.been.called;
|
|
78
|
-
});
|
|
79
|
-
});
|
|
@@ -1,98 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const { expect } = require('chai');
|
|
4
|
-
const sinon = require('sinon');
|
|
5
|
-
const { initProtectFixture } = require('@contrast/test/fixtures');
|
|
6
|
-
const SecurityException = require('../../security-exception');
|
|
7
|
-
|
|
8
|
-
describe('protect input-analysis restify v8+', function () {
|
|
9
|
-
let core, simulateRequestScope, inputAnalysis, Server, req;
|
|
10
|
-
|
|
11
|
-
beforeEach(function () {
|
|
12
|
-
({ core, simulateRequestScope } = initProtectFixture());
|
|
13
|
-
inputAnalysis = core.protect.inputAnalysis;
|
|
14
|
-
sinon.stub(inputAnalysis, 'handleParsedBody');
|
|
15
|
-
sinon.stub(inputAnalysis, 'handleUrlParams');
|
|
16
|
-
sinon.stub(inputAnalysis, 'handleQueryParams');
|
|
17
|
-
|
|
18
|
-
// we stub the _afterUse method to return the error argument so we can check
|
|
19
|
-
// that it is called with our own SecurityException. We cannot check the
|
|
20
|
-
// stub's calls since depHooks and patcher mangle the `Server` variable.
|
|
21
|
-
Server = { prototype: { _afterUse: sinon.stub().returnsArg(0) } };
|
|
22
|
-
req = {};
|
|
23
|
-
|
|
24
|
-
core.depHooks.resolve
|
|
25
|
-
.withArgs({ name: 'restify', file: 'lib/server.js', version: '>=8 <12' })
|
|
26
|
-
.yields(Server);
|
|
27
|
-
|
|
28
|
-
inputAnalysis.restifyInstrumentation.install();
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
it('does not handle request when not in context', function () {
|
|
32
|
-
simulateRequestScope(() => {
|
|
33
|
-
const result = Server.prototype._afterUse(undefined, req);
|
|
34
|
-
|
|
35
|
-
expect(inputAnalysis.handleParsedBody).not.to.have.been.called;
|
|
36
|
-
expect(inputAnalysis.handleUrlParams).not.to.have.been.called;
|
|
37
|
-
expect(inputAnalysis.handleQueryParams).not.to.have.been.called;
|
|
38
|
-
expect(result).to.be.undefined;
|
|
39
|
-
}, {});
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
[
|
|
43
|
-
['body', 'handleParsedBody', 'parsedBody'],
|
|
44
|
-
['params', 'handleUrlParams', 'parsedParams'],
|
|
45
|
-
['query', 'handleQueryParams', 'parsedQuery'],
|
|
46
|
-
].forEach(([prop, method, ctxProp]) => {
|
|
47
|
-
describe(prop, function () {
|
|
48
|
-
it(`handles the request ${prop}`, function () {
|
|
49
|
-
simulateRequestScope(() => {
|
|
50
|
-
req[prop] = { foo: 'bar' };
|
|
51
|
-
Server.prototype._afterUse(undefined, req);
|
|
52
|
-
|
|
53
|
-
expect(inputAnalysis[method]).to.have.been.calledWith(sinon.match.object, req[prop]);
|
|
54
|
-
});
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
it(`handles the request ${prop} when already parsed`, function () {
|
|
58
|
-
const store = { protect: { [ctxProp]: { something: 'else ' } } };
|
|
59
|
-
|
|
60
|
-
simulateRequestScope(() => {
|
|
61
|
-
req[prop] = { foo: 'bar' };
|
|
62
|
-
Server.prototype._afterUse(undefined, req);
|
|
63
|
-
|
|
64
|
-
expect(inputAnalysis[method]).not.to.have.been.called;
|
|
65
|
-
}, store);
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
it('calls through to _afterUse with a new error when one is thrown', function () {
|
|
69
|
-
simulateRequestScope(() => {
|
|
70
|
-
req[prop] = { foo: 'bar' };
|
|
71
|
-
const err = SecurityException.create();
|
|
72
|
-
inputAnalysis[method].throws(err);
|
|
73
|
-
const result = Server.prototype._afterUse(undefined, req);
|
|
74
|
-
|
|
75
|
-
expect(inputAnalysis[method]).to.have.been.calledWith(sinon.match.object, req[prop]);
|
|
76
|
-
expect(core.logger.error).not.to.have.been.called;
|
|
77
|
-
expect(result).to.equal(err);
|
|
78
|
-
});
|
|
79
|
-
});
|
|
80
|
-
|
|
81
|
-
it('logs an error when an unknown one is thrown', function () {
|
|
82
|
-
simulateRequestScope(() => {
|
|
83
|
-
req[prop] = { foo: 'bar' };
|
|
84
|
-
const err = new Error('eek');
|
|
85
|
-
inputAnalysis[method].throws(err);
|
|
86
|
-
const result = Server.prototype._afterUse(undefined, req);
|
|
87
|
-
|
|
88
|
-
expect(inputAnalysis[method]).to.have.been.calledWith(sinon.match.object, req[prop]);
|
|
89
|
-
expect(core.logger.error).to.have.been.calledWith(
|
|
90
|
-
sinon.match({ err }),
|
|
91
|
-
'Unexpected error during input analysis',
|
|
92
|
-
);
|
|
93
|
-
expect(result).to.be.undefined;
|
|
94
|
-
});
|
|
95
|
-
});
|
|
96
|
-
});
|
|
97
|
-
});
|
|
98
|
-
});
|