@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,270 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const sinon = require('sinon');
|
|
4
|
-
const { expect } = require('chai');
|
|
5
|
-
const EventEmitter = require('events');
|
|
6
|
-
const Protect = require('../..');
|
|
7
|
-
const { initProtectFixture } = require('@contrast/test/fixtures');
|
|
8
|
-
|
|
9
|
-
describe('protect input-analysis http', function () {
|
|
10
|
-
|
|
11
|
-
describe('initialization', function () {
|
|
12
|
-
let core, httpInstr, mockServer;
|
|
13
|
-
// this captures the sinon stub before it is wrapped by Perf so we can
|
|
14
|
-
// determine if it was called/not called as expected. if we don't do this
|
|
15
|
-
// the core.depHooks.install() will be replaced by the Perf wrapper and
|
|
16
|
-
// sinon will complain that it's not a spy/call-to-spy.
|
|
17
|
-
|
|
18
|
-
beforeEach(function () {
|
|
19
|
-
({ core } = initProtectFixture());
|
|
20
|
-
|
|
21
|
-
core.protect = Protect(core);
|
|
22
|
-
httpInstr = require('./http')(core);
|
|
23
|
-
httpInstr.around = sinon.stub();
|
|
24
|
-
|
|
25
|
-
sinon.stub(core.protect.errorHandlers, 'initDomain');
|
|
26
|
-
|
|
27
|
-
mockServer = {
|
|
28
|
-
Server: {
|
|
29
|
-
prototype: {
|
|
30
|
-
emit: () => { },
|
|
31
|
-
_events: {
|
|
32
|
-
request: 'REQUEST',
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
},
|
|
36
|
-
createServer() { },
|
|
37
|
-
createSecureServer() { }
|
|
38
|
-
};
|
|
39
|
-
|
|
40
|
-
core.depHooks.resolve.yields(mockServer);
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
it('should not be initialized after being required', function () {
|
|
44
|
-
expect(httpInstr.install).a('function');
|
|
45
|
-
// the next two lines are effectively: expect(core.depHooks.install).not.to.have.been.called;
|
|
46
|
-
const depHooksInstall = core.Perf.all.get('agentify').get('agentify:@contrast/dep-hooks:install');
|
|
47
|
-
expect(depHooksInstall).equal(undefined);
|
|
48
|
-
expect(core.depHooks.resolve).not.to.have.been.called;
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
it('should be initialized after being installed', function () {
|
|
52
|
-
httpInstr.install();
|
|
53
|
-
expect(core.depHooks.resolve).to.have.callCount(4);
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
describe('hook createServer', function () {
|
|
57
|
-
let postHook;
|
|
58
|
-
|
|
59
|
-
this.beforeEach(function () {
|
|
60
|
-
sinon.spy(core.patcher, 'patch');
|
|
61
|
-
httpInstr.install();
|
|
62
|
-
postHook = core.patcher.patch.getCall(3).lastArg.post;
|
|
63
|
-
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
it('should patch the Server prototype for http2', function () {
|
|
67
|
-
postHook({ result: Object.create(mockServer.Server.prototype) });
|
|
68
|
-
|
|
69
|
-
expect(core.patcher.patch).to.have.been.calledWith(mockServer.Server.prototype, 'emit', {
|
|
70
|
-
name: 'http2.Server.prototype.emit',
|
|
71
|
-
patchType: 'protect-input-analysis',
|
|
72
|
-
around: sinon.match.func,
|
|
73
|
-
funcKey: 'protect-input-analysis:http2.Server.prototype.emit'
|
|
74
|
-
});
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
it('should throw an error if we cannot patch the Server prototype for http2', function () {
|
|
78
|
-
postHook({ result: Object.create(null), funcKey: 'a' });
|
|
79
|
-
postHook({ result: null, funcKey: 'b' });
|
|
80
|
-
expect(core.logger.error).to.have.been.calledWith(
|
|
81
|
-
{ funcKey: 'a' },
|
|
82
|
-
'Unable to patch %s, continuing without instrumentation',
|
|
83
|
-
'http2.Server.prototype',
|
|
84
|
-
);
|
|
85
|
-
expect(core.logger.error).to.have.been.calledWith(
|
|
86
|
-
{ funcKey: 'b' },
|
|
87
|
-
'Unable to patch %s, continuing without instrumentation',
|
|
88
|
-
'http2.Server.prototype',
|
|
89
|
-
);
|
|
90
|
-
|
|
91
|
-
});
|
|
92
|
-
});
|
|
93
|
-
|
|
94
|
-
describe('around()', function () {
|
|
95
|
-
let core,
|
|
96
|
-
httpInstr,
|
|
97
|
-
server,
|
|
98
|
-
serverEmit,
|
|
99
|
-
req,
|
|
100
|
-
res,
|
|
101
|
-
reqEmitter,
|
|
102
|
-
context,
|
|
103
|
-
expectedReqData,
|
|
104
|
-
connectInputs;
|
|
105
|
-
|
|
106
|
-
beforeEach(function () {
|
|
107
|
-
({ core } = initProtectFixture());
|
|
108
|
-
|
|
109
|
-
Object.assign(core.config.protect.rules, {
|
|
110
|
-
'cmd-injection': { mode: 'monitor' },
|
|
111
|
-
'reflected-xss': { mode: 'block' }
|
|
112
|
-
});
|
|
113
|
-
core.protect = Protect(core);
|
|
114
|
-
|
|
115
|
-
sinon.spy(core.protect.inputAnalysis, 'handleConnect');
|
|
116
|
-
sinon.spy(core.protect.inputAnalysis, 'handleIpDenylist');
|
|
117
|
-
sinon.spy(core.protect.inputAnalysis, 'handleIpAllowlist');
|
|
118
|
-
|
|
119
|
-
httpInstr = require('./http')(core);
|
|
120
|
-
|
|
121
|
-
sinon.spy(core.protect, 'makeSourceContext');
|
|
122
|
-
|
|
123
|
-
server = {};
|
|
124
|
-
serverEmit = sinon.stub();
|
|
125
|
-
server.prototype = { emit: serverEmit };
|
|
126
|
-
reqEmitter = new EventEmitter();
|
|
127
|
-
req = {
|
|
128
|
-
url: '/',
|
|
129
|
-
method: 'GET',
|
|
130
|
-
rawHeaders: ['host', 'vogon.com', 'content-type', 'application/json'],
|
|
131
|
-
// this needs to look sort of like a real incoming message
|
|
132
|
-
emit: (...args) => reqEmitter.emit(...args),
|
|
133
|
-
_events: {},
|
|
134
|
-
socket: { _readableState: { autoDestroy: false } },
|
|
135
|
-
resume: sinon.stub(),
|
|
136
|
-
};
|
|
137
|
-
res = {
|
|
138
|
-
end: sinon.stub(),
|
|
139
|
-
writeHead: sinon.stub(),
|
|
140
|
-
headersSent: false,
|
|
141
|
-
on: sinon.stub(),
|
|
142
|
-
};
|
|
143
|
-
context = {
|
|
144
|
-
instance: server,
|
|
145
|
-
method: serverEmit,
|
|
146
|
-
args: ['request', req, res],
|
|
147
|
-
funcKey: 'funcKey',
|
|
148
|
-
};
|
|
149
|
-
|
|
150
|
-
// setup a few expected results. these can be modified as needed by
|
|
151
|
-
// different tests.
|
|
152
|
-
expectedReqData = {
|
|
153
|
-
method: req.method.toLowerCase(),
|
|
154
|
-
headers: req.rawHeaders.map((h, i) => i & 1 ? h : h.toLowerCase()),
|
|
155
|
-
uriPath: '/',
|
|
156
|
-
url: '/',
|
|
157
|
-
queries: '',
|
|
158
|
-
contentType: '',
|
|
159
|
-
};
|
|
160
|
-
connectInputs = {
|
|
161
|
-
headers: expectedReqData.headers,
|
|
162
|
-
uriPath: expectedReqData.uriPath,
|
|
163
|
-
method: expectedReqData.method
|
|
164
|
-
};
|
|
165
|
-
});
|
|
166
|
-
|
|
167
|
-
it('does not handle non-requests', function () {
|
|
168
|
-
context = {
|
|
169
|
-
instance: server,
|
|
170
|
-
method: serverEmit,
|
|
171
|
-
args: ['foo', req, res]
|
|
172
|
-
};
|
|
173
|
-
const next = sinon.stub();
|
|
174
|
-
core.scopes.sources.run({ protect: {} }, () => httpInstr.around(next, context));
|
|
175
|
-
expect(core.protect.inputAnalysis.handleConnect).not.have.been.called;
|
|
176
|
-
expect(next).to.have.been.called;
|
|
177
|
-
});
|
|
178
|
-
|
|
179
|
-
it('works as expected', function () {
|
|
180
|
-
res.on = (eventName, fn) => {
|
|
181
|
-
fn();
|
|
182
|
-
};
|
|
183
|
-
core.scopes.sources.run({ protect: {} }, () => httpInstr.around(() => { }, context));
|
|
184
|
-
const sourceContext = core.protect.makeSourceContext.returnValues[0];
|
|
185
|
-
expect(core.protect.inputAnalysis.handleConnect).to.have.been.calledOnceWith(sourceContext, connectInputs);
|
|
186
|
-
});
|
|
187
|
-
|
|
188
|
-
it('debug logs if no async context', function () {
|
|
189
|
-
sinon.stub(core.scopes.sources, 'getStore').returns(undefined);
|
|
190
|
-
core.logger.debug = sinon.stub();
|
|
191
|
-
core.scopes.sources.run({ protect: {} }, () => httpInstr.around(() => { }, context));
|
|
192
|
-
|
|
193
|
-
expect(core.logger.debug).to.have.been.calledOnceWith({ funcKey: 'funcKey' }, 'request store not available during http input-analysis');
|
|
194
|
-
});
|
|
195
|
-
|
|
196
|
-
it('error logs on exceptions', function () {
|
|
197
|
-
const err = new Error('sometimes things do not work out');
|
|
198
|
-
core.protect.inputAnalysis.handleConnect.restore();
|
|
199
|
-
sinon.stub(core.protect.inputAnalysis, 'handleConnect').throws(err);
|
|
200
|
-
core.scopes.sources.run({ protect: {} }, () => httpInstr.around(() => { }, context));
|
|
201
|
-
expect(core.logger.error).to.have.been.calledWith({ err, funcKey: 'funcKey' }, 'Error during http input analysis');
|
|
202
|
-
});
|
|
203
|
-
|
|
204
|
-
it('connectInputs will contain not a cookies header', function () {
|
|
205
|
-
const withoutCookies = req.rawHeaders.slice();
|
|
206
|
-
req.rawHeaders.push('COOKIES', 'this;that;the other;thing');
|
|
207
|
-
expectedReqData.headers.push('cookies', 'this;that;the other;thing');
|
|
208
|
-
core.scopes.sources.run({ protect: {} }, () => httpInstr.around(() => { }, context));
|
|
209
|
-
const sourceContext = core.protect.makeSourceContext.returnValues[0];
|
|
210
|
-
connectInputs.headers = withoutCookies;
|
|
211
|
-
expect(core.protect.inputAnalysis.handleConnect).to.have.been.calledOnceWith(sourceContext, connectInputs);
|
|
212
|
-
});
|
|
213
|
-
|
|
214
|
-
it('does no analysis and just executes the request if the sourceContext has the allowed property set to true', function () {
|
|
215
|
-
core.protect.makeSourceContext = () => ({
|
|
216
|
-
allowed: true
|
|
217
|
-
});
|
|
218
|
-
core.scopes.sources.run({ protect: {} }, () => httpInstr.around(() => { }, context));
|
|
219
|
-
|
|
220
|
-
expect(core.protect.inputAnalysis.handleConnect).not.to.have.been.called;
|
|
221
|
-
expect(core.logger.debug).not.to.have.been.called;
|
|
222
|
-
});
|
|
223
|
-
|
|
224
|
-
it('does not emit the original event when blocked', function () {
|
|
225
|
-
req.url = '/need/<script>%20this&that';
|
|
226
|
-
core.scopes.sources.run({ protect: {} }, () => httpInstr.around(() => { }, context));
|
|
227
|
-
|
|
228
|
-
const block = ['block', 'reflected-xss'];
|
|
229
|
-
|
|
230
|
-
expect(core.protect.inputAnalysis.handleConnect).to.have.been.calledOnce.returned(block);
|
|
231
|
-
expect(core.logger.debug).to.have.been.calledWith({ block, funcKey: 'funcKey' }, 'request blocked by not emitting request event');
|
|
232
|
-
});
|
|
233
|
-
|
|
234
|
-
it('does not handle a request body when it is not JSON', function () {
|
|
235
|
-
req.rawHeaders = ['Content-Type', 'multipart/form-data'];
|
|
236
|
-
expectedReqData.headers = ['content-type', 'multipart/form-data'];
|
|
237
|
-
expectedReqData.contentType = 'multipart/form-data';
|
|
238
|
-
core.scopes.sources.run({ protect: {} }, () => httpInstr.around(() => { }, context));
|
|
239
|
-
const sourceContext = core.protect.makeSourceContext.returnValues[0];
|
|
240
|
-
connectInputs.headers = expectedReqData.headers;
|
|
241
|
-
expect(core.protect.inputAnalysis.handleConnect).to.have.been.calledOnceWith(sourceContext, connectInputs);
|
|
242
|
-
});
|
|
243
|
-
|
|
244
|
-
it('stores the virtualPatchesEvaluators in the protect store from inputAnalysis if there are some', function () {
|
|
245
|
-
core.protect.inputAnalysis.virtualPatchesEvaluators = [new Map([['a', 'b']]), new Map([['a', 'b'], ['c', 'd']])];
|
|
246
|
-
core.scopes.sources.run({ protect: {} }, () => httpInstr.around(() => { }, context));
|
|
247
|
-
|
|
248
|
-
const { virtualPatchesEvaluators } = core.protect.makeSourceContext.returnValues[0];
|
|
249
|
-
|
|
250
|
-
expect(virtualPatchesEvaluators.length).to.equal(2);
|
|
251
|
-
expect(virtualPatchesEvaluators[0].size).to.equal(1);
|
|
252
|
-
expect(virtualPatchesEvaluators[1].size).to.equal(2);
|
|
253
|
-
});
|
|
254
|
-
|
|
255
|
-
it('calls handleIpDenylist() if there is a IP Denylist', function () {
|
|
256
|
-
core.protect.inputAnalysis.ipDenylist = ['test-entry'];
|
|
257
|
-
core.scopes.sources.run({ protect: {} }, () => httpInstr.around(() => { }, context));
|
|
258
|
-
|
|
259
|
-
expect(core.protect.inputAnalysis.handleIpDenylist).to.have.been.called;
|
|
260
|
-
});
|
|
261
|
-
|
|
262
|
-
it('calls handleIpAllowlist() if there is a IP Denylist', function () {
|
|
263
|
-
core.protect.inputAnalysis.ipAllowlist = ['test-entry'];
|
|
264
|
-
core.scopes.sources.run({ protect: {} }, () => httpInstr.around(() => { }, context));
|
|
265
|
-
|
|
266
|
-
expect(core.protect.inputAnalysis.handleIpAllowlist).to.have.been.called;
|
|
267
|
-
});
|
|
268
|
-
});
|
|
269
|
-
});
|
|
270
|
-
});
|
|
@@ -1,92 +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 koaBodyInstr = require('./koa-body5');
|
|
9
|
-
|
|
10
|
-
describe('protect input-analysis koa-body v5.x', function () {
|
|
11
|
-
let core, inputAnalysis, koaBodyMock, patchedKoaBody, body, nextStub;
|
|
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
|
-
body = { parameter: 'parsed' };
|
|
25
|
-
|
|
26
|
-
koaBodyMock = (body) => (ctx, next) => {
|
|
27
|
-
ctx.request.body = body;
|
|
28
|
-
next();
|
|
29
|
-
};
|
|
30
|
-
nextStub = sinon.stub();
|
|
31
|
-
sinon.spy(core.patcher, 'patch');
|
|
32
|
-
|
|
33
|
-
koaBodyInstr(core).install();
|
|
34
|
-
patchedKoaBody = core.depHooks.resolve.yield(koaBodyMock)[0];
|
|
35
|
-
core.patcher.patch.resetHistory();
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
it('calls patcher on the `cookie-parser` module export', function () {
|
|
39
|
-
core.depHooks.resolve.yield(koaBodyMock);
|
|
40
|
-
|
|
41
|
-
expect(core.patcher.patch).to.have.been.calledOnce;
|
|
42
|
-
expect(core.patcher.patch).to.have.been.calledWithMatch(koaBodyMock, {
|
|
43
|
-
name: 'koa-body',
|
|
44
|
-
patchType: 'protect-input-analysis',
|
|
45
|
-
post: sinon.match.func
|
|
46
|
-
});
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
it('calls `.handleParsedBody` when parsing body is successful and in right context', function () {
|
|
50
|
-
core.scopes.sources.run({ protect: {} }, () => {
|
|
51
|
-
const bParser = patchedKoaBody(body);
|
|
52
|
-
bParser({ request: {} }, nextStub);
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
expect(core.patcher.patch).to.have.been.calledOnce;
|
|
56
|
-
expect(core.patcher.patch).to.have.been.calledWithMatch(sinon.match.func, {
|
|
57
|
-
name: 'koa-body',
|
|
58
|
-
patchType: 'protect-input-analysis',
|
|
59
|
-
pre: sinon.match.func
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
expect(nextStub).to.have.been.calledOnce;
|
|
63
|
-
expect(inputAnalysis.handleParsedBody).to.have.been.calledOnce;
|
|
64
|
-
expect(inputAnalysis.handleParsedBody).to.have.been.calledWithMatch({ parsedBody: body }, body);
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
it('does not call `.handleParsedBody` when not in context', function () {
|
|
68
|
-
core.scopes.sources.run({}, () => {
|
|
69
|
-
const cParser = patchedKoaBody(body);
|
|
70
|
-
cParser({ request: {} }, nextStub);
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
expect(inputAnalysis.handleCookies).not.to.have.been.called;
|
|
74
|
-
expect(nextStub).to.have.been.calledOnce;
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
it('does not call `.handleParsedBody` when `koa-body` does not return a result', function () {
|
|
78
|
-
core.scopes.sources.run({ protect: {} }, () => {
|
|
79
|
-
const cParser = patchedKoaBody();
|
|
80
|
-
cParser({ request: {} }, nextStub);
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
core.scopes.sources.run({ protect: {} }, () => {
|
|
84
|
-
const cParser = patchedKoaBody({});
|
|
85
|
-
cParser({ request: {} }, nextStub);
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
expect(inputAnalysis.handleCookies).not.to.have.been.called;
|
|
89
|
-
expect(core.logger.debug).not.to.have.been.called;
|
|
90
|
-
expect(nextStub).to.have.been.calledTwice;
|
|
91
|
-
});
|
|
92
|
-
});
|
|
@@ -1,92 +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 koaBodyparserInstr = require('./koa-bodyparser4');
|
|
9
|
-
|
|
10
|
-
describe('protect input-analysis koa-bodyparser v4.x', function () {
|
|
11
|
-
let core, inputAnalysis, koaBodyparserMock, patchedKoaBodyparser, body, nextStub;
|
|
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
|
-
body = { parameter: 'parsed' };
|
|
25
|
-
|
|
26
|
-
koaBodyparserMock = (body) => (ctx, next) => {
|
|
27
|
-
ctx.request.body = body;
|
|
28
|
-
next();
|
|
29
|
-
};
|
|
30
|
-
nextStub = sinon.stub();
|
|
31
|
-
sinon.spy(core.patcher, 'patch');
|
|
32
|
-
|
|
33
|
-
koaBodyparserInstr(core).install();
|
|
34
|
-
patchedKoaBodyparser = core.depHooks.resolve.yield(koaBodyparserMock)[0];
|
|
35
|
-
core.patcher.patch.resetHistory();
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
it('calls patcher on the `cookie-parser` module export', function () {
|
|
39
|
-
core.depHooks.resolve.yield(koaBodyparserMock);
|
|
40
|
-
|
|
41
|
-
expect(core.patcher.patch).to.have.been.calledOnce;
|
|
42
|
-
expect(core.patcher.patch).to.have.been.calledWithMatch(koaBodyparserMock, {
|
|
43
|
-
name: 'koa-bodyparser',
|
|
44
|
-
patchType: 'protect-input-analysis',
|
|
45
|
-
post: sinon.match.func
|
|
46
|
-
});
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
it('calls `.handleParsedBody` when parsing body is successful and in right context', function () {
|
|
50
|
-
core.scopes.sources.run({ protect: {} }, () => {
|
|
51
|
-
const bParser = patchedKoaBodyparser(body);
|
|
52
|
-
bParser({ request: {} }, nextStub);
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
expect(core.patcher.patch).to.have.been.calledOnce;
|
|
56
|
-
expect(core.patcher.patch).to.have.been.calledWithMatch(sinon.match.func, {
|
|
57
|
-
name: 'koa-bodyparser',
|
|
58
|
-
patchType: 'protect-input-analysis',
|
|
59
|
-
pre: sinon.match.func
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
expect(nextStub).to.have.been.calledOnce;
|
|
63
|
-
expect(inputAnalysis.handleParsedBody).to.have.been.calledOnce;
|
|
64
|
-
expect(inputAnalysis.handleParsedBody).to.have.been.calledWithMatch({ parsedBody: body }, body);
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
it('does not call `.handleParsedBody` when not in context', function () {
|
|
68
|
-
core.scopes.sources.run({}, () => {
|
|
69
|
-
const cParser = patchedKoaBodyparser(body);
|
|
70
|
-
cParser({ request: {} }, nextStub);
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
expect(inputAnalysis.handleCookies).not.to.have.been.called;
|
|
74
|
-
expect(nextStub).to.have.been.calledOnce;
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
it('does not call `.handleParsedBody` when `koa-bodyparser` does not return a result', function () {
|
|
78
|
-
core.scopes.sources.run({ protect: {} }, () => {
|
|
79
|
-
const cParser = patchedKoaBodyparser();
|
|
80
|
-
cParser({ request: {} }, nextStub);
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
core.scopes.sources.run({ protect: {} }, () => {
|
|
84
|
-
const cParser = patchedKoaBodyparser({});
|
|
85
|
-
cParser({ request: {} }, nextStub);
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
expect(inputAnalysis.handleCookies).not.to.have.been.called;
|
|
89
|
-
expect(core.logger.debug).not.to.have.been.called;
|
|
90
|
-
expect(nextStub).to.have.been.calledTwice;
|
|
91
|
-
});
|
|
92
|
-
});
|