@contrast/protect 1.53.1 → 1.54.1
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 +15 -12
- 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 -1236
- 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,45 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const sinon = require('sinon');
|
|
4
|
-
const { expect } = require('chai');
|
|
5
|
-
const proxyquire = require('proxyquire');
|
|
6
|
-
const mocks = require('@contrast/test/mocks');
|
|
7
|
-
|
|
8
|
-
describe('protect input-analysis', function () {
|
|
9
|
-
let modulesMock, installStub, core, inputAnalysis;
|
|
10
|
-
beforeEach(function () {
|
|
11
|
-
installStub = sinon.stub();
|
|
12
|
-
modulesMock = (propertyName) => function (core) {
|
|
13
|
-
if (propertyName) {
|
|
14
|
-
core.protect.inputAnalysis[propertyName] = { install: installStub };
|
|
15
|
-
}
|
|
16
|
-
};
|
|
17
|
-
core = mocks.core();
|
|
18
|
-
core.depHooks = mocks.depHooks();
|
|
19
|
-
core.protect = mocks.protect();
|
|
20
|
-
|
|
21
|
-
inputAnalysis = proxyquire('.', {
|
|
22
|
-
'./handlers': modulesMock,
|
|
23
|
-
'./install/http': modulesMock('httpInstrumentation'),
|
|
24
|
-
'./install/fastify': modulesMock('fastify3Instrumentation'),
|
|
25
|
-
'./install/koa2': modulesMock('koa2Instrumentation'),
|
|
26
|
-
'./install/koa-body5': modulesMock('koaBody5Instrumentation'),
|
|
27
|
-
'./install/koa-bodyparser4': modulesMock('koaBodyparser4Instrumentation'),
|
|
28
|
-
'./install/express': modulesMock('expressInstrumentation'),
|
|
29
|
-
'./install/body-parser1': modulesMock('bodyParser1Instrumentation'),
|
|
30
|
-
'./install/cookie-parser1': modulesMock('cookieParser1Instrumentation'),
|
|
31
|
-
'./install/formidable1': modulesMock('formidable1Instrumentation'),
|
|
32
|
-
'./install/multer1': modulesMock('multer1Instrumentation'),
|
|
33
|
-
'./install/qs6': modulesMock('qs6Instrumentation'),
|
|
34
|
-
'./install/restify': modulesMock('restifyInstrumentation'),
|
|
35
|
-
'./install/universal-cookie4': modulesMock('universalCookie4Instrumentation'),
|
|
36
|
-
'./install/hapi': modulesMock('hapiInstrumentation'),
|
|
37
|
-
// Total of 15 modules required - 1 handlers and 14 modules to be installed
|
|
38
|
-
});
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
it('calls the install method on all hooks', function () {
|
|
42
|
-
inputAnalysis(core).install();
|
|
43
|
-
expect(installStub).to.have.callCount(14);
|
|
44
|
-
});
|
|
45
|
-
});
|
|
@@ -1,134 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const sinon = require('sinon');
|
|
4
|
-
const { expect } = require('chai');
|
|
5
|
-
const scopes = require('@contrast/scopes');
|
|
6
|
-
const mocks = require('@contrast/test/mocks');
|
|
7
|
-
const SecurityException = require('../../security-exception');
|
|
8
|
-
const secEx = SecurityException.create();
|
|
9
|
-
const bodyParserInstr = require('./body-parser1');
|
|
10
|
-
|
|
11
|
-
describe('protect input-analysis body-parser v1.x', function () {
|
|
12
|
-
let core, inputAnalysis, bodyParserMock, patchedBodyParser, body, nextStub;
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
beforeEach(function () {
|
|
16
|
-
core = mocks.core();
|
|
17
|
-
core.logger = mocks.logger();
|
|
18
|
-
core.scopes = scopes(core);
|
|
19
|
-
core.protect = mocks.protect();
|
|
20
|
-
require('../../get-source-context')(core);
|
|
21
|
-
core.depHooks = mocks.depHooks();
|
|
22
|
-
|
|
23
|
-
inputAnalysis = core.protect.inputAnalysis;
|
|
24
|
-
body = { parameter: 'parsed' };
|
|
25
|
-
const bodyParserFn = (payload) => (req, res, next) => {
|
|
26
|
-
if (payload) {
|
|
27
|
-
req.body = payload;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
next();
|
|
31
|
-
};
|
|
32
|
-
bodyParserMock = (payload) => bodyParserFn(payload);
|
|
33
|
-
nextStub = sinon.stub();
|
|
34
|
-
|
|
35
|
-
['json', 'raw', 'text', 'urlencoded'].forEach((property) => {
|
|
36
|
-
bodyParserMock[property] = (payload) => (req, res, next) => {
|
|
37
|
-
if (payload) {
|
|
38
|
-
req.body = payload;
|
|
39
|
-
}
|
|
40
|
-
next();
|
|
41
|
-
};
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
bodyParserInstr(core).install();
|
|
45
|
-
core.depHooks.resolve.yield(bodyParserMock);
|
|
46
|
-
patchedBodyParser = core.depHooks.resolve.yield(bodyParserMock)[0];
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
it('calls `.handleParsedBody` when parsing is successful and in right context', function () {
|
|
50
|
-
core.scopes.sources.run({ protect: {} }, () => {
|
|
51
|
-
patchedBodyParser(body)({}, {}, nextStub);
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
core.scopes.sources.run({ protect: {} }, () => {
|
|
55
|
-
patchedBodyParser.json()({ body }, {}, nextStub);
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
expect(inputAnalysis.handleParsedBody).to.have.been.calledTwice;
|
|
59
|
-
expect(inputAnalysis.handleParsedBody).to.have.been.calledWithMatch({ parsedBody: body }, body);
|
|
60
|
-
expect(nextStub).to.have.been.calledTwice;
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
it('calls `.handleParsedBody` when parsing is successful, in right context with the body parsed by JSON.parse when bodyParser.text method is used', function () {
|
|
64
|
-
|
|
65
|
-
core.scopes.sources.run({ protect: {} }, () => {
|
|
66
|
-
patchedBodyParser.text()({ body: JSON.stringify(body) }, {}, nextStub);
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
expect(inputAnalysis.handleParsedBody).to.have.been.calledOnceWith({ parsedBody: body }, body);
|
|
70
|
-
expect(nextStub).to.have.been.calledOnce;
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
it('logs an error if parsing the body in case of bodyParser.text throws an error', function () {
|
|
74
|
-
|
|
75
|
-
core.scopes.sources.run({ protect: {} }, () => {
|
|
76
|
-
patchedBodyParser.text()({ body: 'not-a-valid-JSON' }, {}, nextStub);
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
expect(core.logger.error).to.have.been.calledOnceWithExactly(sinon.match.any, 'Error parsing with bodyParser.text()');
|
|
80
|
-
expect(nextStub).to.have.been.calledOnce;
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
it('does not call `.handleParsedBody` when not in context', function () {
|
|
84
|
-
core.scopes.sources.run({}, () => {
|
|
85
|
-
patchedBodyParser(body)({}, {}, nextStub);
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
core.scopes.sources.run({}, () => {
|
|
89
|
-
patchedBodyParser.json()({ body }, {}, nextStub);
|
|
90
|
-
});
|
|
91
|
-
|
|
92
|
-
expect(inputAnalysis.handleParsedBody).not.to.have.been.called;
|
|
93
|
-
expect(nextStub).to.have.been.calledTwice;
|
|
94
|
-
});
|
|
95
|
-
|
|
96
|
-
it('does not call `.handleParsedBody` when `body-parser` does not return a result', function () {
|
|
97
|
-
core.scopes.sources.run({ protect: {} }, () => {
|
|
98
|
-
patchedBodyParser(null);
|
|
99
|
-
});
|
|
100
|
-
|
|
101
|
-
core.scopes.sources.run({ protect: {} }, () => {
|
|
102
|
-
patchedBodyParser.json()({}, {}, nextStub);
|
|
103
|
-
});
|
|
104
|
-
|
|
105
|
-
core.scopes.sources.run({ protect: {} }, () => {
|
|
106
|
-
patchedBodyParser.json()({ body: {} }, {}, nextStub);
|
|
107
|
-
});
|
|
108
|
-
|
|
109
|
-
expect(inputAnalysis.handleParsedBody).not.to.have.been.called;
|
|
110
|
-
expect(nextStub).to.have.been.calledTwice;
|
|
111
|
-
});
|
|
112
|
-
|
|
113
|
-
it('handles a case with SecurityException from `.handleParsedBody`', function () {
|
|
114
|
-
inputAnalysis.handleParsedBody.throws(secEx);
|
|
115
|
-
core.scopes.sources.run({ protect: {} }, () => {
|
|
116
|
-
patchedBodyParser(body)({}, {}, nextStub);
|
|
117
|
-
});
|
|
118
|
-
|
|
119
|
-
expect(nextStub).to.have.been.calledWith(secEx);
|
|
120
|
-
});
|
|
121
|
-
|
|
122
|
-
it('handles a case with an error in the input analysis from `.handleParsedBody`', function () {
|
|
123
|
-
const err = new Error('Input Analysis Error');
|
|
124
|
-
|
|
125
|
-
inputAnalysis.handleParsedBody.throws(err);
|
|
126
|
-
core.scopes.sources.run({ protect: {} }, () => {
|
|
127
|
-
patchedBodyParser(body)({}, {}, nextStub);
|
|
128
|
-
});
|
|
129
|
-
|
|
130
|
-
expect(core.logger.error).to.have.been.calledWith({ err }, 'Unexpected error during input analysis');
|
|
131
|
-
expect(nextStub).to.have.been.calledOnce;
|
|
132
|
-
expect(nextStub).not.to.have.been.calledWith(err);
|
|
133
|
-
});
|
|
134
|
-
});
|
|
@@ -1,81 +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 busboyInstr = require('./busboy1');
|
|
9
|
-
|
|
10
|
-
describe('protect input-analysis busboy v1.x', function () {
|
|
11
|
-
let core, inputAnalysis, mockBusboy;
|
|
12
|
-
|
|
13
|
-
beforeEach(function () {
|
|
14
|
-
core = mocks.core();
|
|
15
|
-
core.logger = mocks.logger();
|
|
16
|
-
core.scopes = scopes(core);
|
|
17
|
-
core.protect = mocks.protect();
|
|
18
|
-
require('../../get-source-context')(core);
|
|
19
|
-
core.depHooks = mocks.depHooks();
|
|
20
|
-
core.patcher = patcher(core);
|
|
21
|
-
|
|
22
|
-
inputAnalysis = core.protect.inputAnalysis;
|
|
23
|
-
|
|
24
|
-
mockBusboy = function () { };
|
|
25
|
-
mockBusboy.prototype.emit = function () { };
|
|
26
|
-
sinon.spy(mockBusboy.prototype, 'emit');
|
|
27
|
-
sinon.spy(core.patcher, 'patch');
|
|
28
|
-
|
|
29
|
-
busboyInstr(core).install();
|
|
30
|
-
core.depHooks.resolve.yield(mockBusboy);
|
|
31
|
-
core.patcher.patch.resetHistory();
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
it('calls patcher on the `.emit` method', function () {
|
|
35
|
-
core.depHooks.resolve.yield(mockBusboy);
|
|
36
|
-
|
|
37
|
-
expect(core.patcher.patch).to.have.been.calledOnce;
|
|
38
|
-
expect(core.patcher.patch).to.have.been.calledWithMatch(mockBusboy.prototype, 'emit', {
|
|
39
|
-
name: 'busboy.prototype.emit',
|
|
40
|
-
patchType: 'protect-input-analysis',
|
|
41
|
-
pre: sinon.match.func
|
|
42
|
-
});
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
it('calls `.handleFileUploadName` when there is a multipart file and it is in right context', function () {
|
|
46
|
-
core.scopes.sources.run({ protect: {} }, () => {
|
|
47
|
-
mockBusboy.prototype.emit('file', null, null, 'filename');
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
expect(inputAnalysis.handleFileUploadName).to.have.been.calledOnce;
|
|
51
|
-
expect(inputAnalysis.handleFileUploadName).to.have.been.calledWithMatch({}, ['filename']);
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
it('does not call `.handleFileUploadName` when not in context', function () {
|
|
56
|
-
core.scopes.sources.run({}, () => {
|
|
57
|
-
mockBusboy.prototype.emit('file', null, null, 'filename');
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
expect(inputAnalysis.handleFileUploadName).not.to.have.been.called;
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
it('does not call `.handleFileUploadName` when `.emit` is not called with `file` event', function () {
|
|
64
|
-
core.scopes.sources.run({ protect: {} }, () => {
|
|
65
|
-
mockBusboy.prototype.emit('not-file', null, null, 'filename');
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
expect(inputAnalysis.handleParsedBody).not.to.have.been.called;
|
|
69
|
-
expect(core.logger.debug).not.to.have.been.called;
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
it('does not call `.handleFileUploadName` when `.emit` call does not contain a filename', function () {
|
|
73
|
-
core.scopes.sources.run({ protect: {} }, () => {
|
|
74
|
-
mockBusboy.prototype.emit('not-file');
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
expect(inputAnalysis.handleParsedBody).not.to.have.been.called;
|
|
78
|
-
expect(core.logger.debug).not.to.have.been.called;
|
|
79
|
-
});
|
|
80
|
-
});
|
|
81
|
-
|
|
@@ -1,144 +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 cookieParserInstr = require('./cookie-parser1');
|
|
11
|
-
|
|
12
|
-
describe('protect input-analysis cookie-parser v1.x', function () {
|
|
13
|
-
let core, inputAnalysis, cookieParserMock, patchedCookieParser, cookie, signedCookie, nextStub;
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
beforeEach(function () {
|
|
17
|
-
core = mocks.core();
|
|
18
|
-
core.logger = mocks.logger();
|
|
19
|
-
core.scopes = scopes(core);
|
|
20
|
-
core.protect = mocks.protect();
|
|
21
|
-
require('../../get-source-context')(core);
|
|
22
|
-
core.depHooks = mocks.depHooks();
|
|
23
|
-
core.patcher = patcher(core);
|
|
24
|
-
|
|
25
|
-
inputAnalysis = core.protect.inputAnalysis;
|
|
26
|
-
cookie = {
|
|
27
|
-
cookie: { parameter: 'parsed' },
|
|
28
|
-
};
|
|
29
|
-
signedCookie = {
|
|
30
|
-
signedCookie: { secret: 'parsed' }
|
|
31
|
-
};
|
|
32
|
-
cookieParserMock = (cookies) => (req, res, next) => {
|
|
33
|
-
req.cookies = cookies?.cookie;
|
|
34
|
-
req.signedCookies = cookies?.signedCookie;
|
|
35
|
-
next();
|
|
36
|
-
};
|
|
37
|
-
nextStub = sinon.stub();
|
|
38
|
-
sinon.spy(core.patcher, 'patch');
|
|
39
|
-
|
|
40
|
-
cookieParserInstr(core).install();
|
|
41
|
-
patchedCookieParser = core.depHooks.resolve.yield(cookieParserMock)[0];
|
|
42
|
-
core.patcher.patch.resetHistory();
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
it('calls patcher on the `cookie-parser` module export', function () {
|
|
46
|
-
core.depHooks.resolve.yield(cookieParserMock);
|
|
47
|
-
|
|
48
|
-
expect(core.patcher.patch).to.have.been.calledOnce;
|
|
49
|
-
expect(core.patcher.patch).to.have.been.calledWithMatch(cookieParserMock, {
|
|
50
|
-
name: 'cookie-parser',
|
|
51
|
-
patchType: 'protect-input-analysis',
|
|
52
|
-
post: sinon.match.func
|
|
53
|
-
});
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
it('calls `.handleCookies` when parsing normal cookies is successful and in right context', function () {
|
|
57
|
-
core.scopes.sources.run({ protect: {} }, () => {
|
|
58
|
-
const cParser = patchedCookieParser(cookie);
|
|
59
|
-
cParser({}, {}, nextStub);
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
expect(core.patcher.patch).to.have.been.calledOnce;
|
|
63
|
-
expect(core.patcher.patch).to.have.been.calledWithMatch(sinon.match.func, {
|
|
64
|
-
name: 'cookie-parser',
|
|
65
|
-
patchType: 'protect-input-analysis',
|
|
66
|
-
pre: sinon.match.func
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
expect(nextStub).to.have.been.calledOnce;
|
|
70
|
-
expect(inputAnalysis.handleCookies).to.have.been.calledOnce;
|
|
71
|
-
expect(inputAnalysis.handleCookies).to.have.been.calledWithMatch({ parsedCookies: { ...cookie.cookie } }, { ...cookie.cookie });
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
it('calls `.handleCookies` when parsing signed cookies is successful and in right context', function () {
|
|
75
|
-
core.scopes.sources.run({ protect: {} }, () => {
|
|
76
|
-
const cParser = patchedCookieParser(signedCookie);
|
|
77
|
-
cParser({}, {}, nextStub);
|
|
78
|
-
});
|
|
79
|
-
|
|
80
|
-
expect(core.patcher.patch).to.have.been.calledOnce;
|
|
81
|
-
expect(core.patcher.patch).to.have.been.calledWithMatch(sinon.match.func, {
|
|
82
|
-
name: 'cookie-parser',
|
|
83
|
-
patchType: 'protect-input-analysis',
|
|
84
|
-
pre: sinon.match.func
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
expect(nextStub).to.have.been.calledOnce;
|
|
88
|
-
expect(inputAnalysis.handleCookies).to.have.been.calledOnce;
|
|
89
|
-
expect(inputAnalysis.handleCookies).to.have.been.calledWithMatch({ parsedCookies: { ...signedCookie.signedCookie } }, { ...signedCookie.signedCookie });
|
|
90
|
-
});
|
|
91
|
-
|
|
92
|
-
it('does not call `.handleCookies` when not in context', function () {
|
|
93
|
-
core.scopes.sources.run({}, () => {
|
|
94
|
-
const cParser = patchedCookieParser(cookie);
|
|
95
|
-
cParser({}, {}, nextStub);
|
|
96
|
-
});
|
|
97
|
-
|
|
98
|
-
expect(inputAnalysis.handleCookies).not.to.have.been.called;
|
|
99
|
-
expect(nextStub).to.have.been.calledOnce;
|
|
100
|
-
});
|
|
101
|
-
|
|
102
|
-
it('does not call `.handleCookies` when `cookie-parser` does not return a result', function () {
|
|
103
|
-
core.scopes.sources.run({ protect: {} }, () => {
|
|
104
|
-
const cParser = patchedCookieParser();
|
|
105
|
-
cParser({}, {}, nextStub);
|
|
106
|
-
});
|
|
107
|
-
|
|
108
|
-
core.scopes.sources.run({ protect: {} }, () => {
|
|
109
|
-
const cParser = patchedCookieParser({});
|
|
110
|
-
cParser({}, {}, nextStub);
|
|
111
|
-
});
|
|
112
|
-
|
|
113
|
-
expect(inputAnalysis.handleCookies).not.to.have.been.called;
|
|
114
|
-
expect(core.logger.debug).not.to.have.been.called;
|
|
115
|
-
expect(nextStub).to.have.been.calledTwice;
|
|
116
|
-
});
|
|
117
|
-
|
|
118
|
-
it('handles a case with SecurityException from `.handleCookies`', function () {
|
|
119
|
-
inputAnalysis.handleCookies.throws(secEx);
|
|
120
|
-
core.scopes.sources.run({ protect: {} }, () => {
|
|
121
|
-
const cParser = patchedCookieParser(cookie);
|
|
122
|
-
cParser({}, {}, nextStub);
|
|
123
|
-
});
|
|
124
|
-
|
|
125
|
-
expect(nextStub).to.have.been.calledOnceWith(secEx);
|
|
126
|
-
});
|
|
127
|
-
|
|
128
|
-
it('handles a case with an error in the input analysis from `.handleCookies`', function () {
|
|
129
|
-
const err = new Error('Input Analysis Error');
|
|
130
|
-
|
|
131
|
-
inputAnalysis.handleCookies.throws(err);
|
|
132
|
-
core.scopes.sources.run({ protect: {} }, () => {
|
|
133
|
-
const cParser = patchedCookieParser(cookie);
|
|
134
|
-
cParser({}, {}, nextStub);
|
|
135
|
-
});
|
|
136
|
-
|
|
137
|
-
expect(core.logger.error).to.have.been.calledWith(
|
|
138
|
-
{ err, funcKey: 'protect-input-analysis:cookie-parser' },
|
|
139
|
-
'Unexpected error during input analysis'
|
|
140
|
-
);
|
|
141
|
-
expect(nextStub).to.have.been.calledOnce;
|
|
142
|
-
expect(nextStub).not.to.have.been.calledWith(err);
|
|
143
|
-
});
|
|
144
|
-
});
|
|
@@ -1,241 +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 expressInstr = require('./express');
|
|
11
|
-
|
|
12
|
-
describe('protect input-analysis express', function () {
|
|
13
|
-
let core,
|
|
14
|
-
inputAnalysis,
|
|
15
|
-
expressQueryMock,
|
|
16
|
-
requestMock,
|
|
17
|
-
nextStub,
|
|
18
|
-
query,
|
|
19
|
-
Layer;
|
|
20
|
-
|
|
21
|
-
beforeEach(function () {
|
|
22
|
-
core = mocks.core();
|
|
23
|
-
core.logger = mocks.logger();
|
|
24
|
-
core.scopes = scopes(core);
|
|
25
|
-
core.protect = mocks.protect();
|
|
26
|
-
require('../../get-source-context')(core);
|
|
27
|
-
core.depHooks = mocks.depHooks();
|
|
28
|
-
core.patcher = patcher(core);
|
|
29
|
-
sinon.spy(core.patcher, 'patch');
|
|
30
|
-
|
|
31
|
-
query = { parameter: 'parsed-query' };
|
|
32
|
-
expressQueryMock = (payload) => (req, res, next) => {
|
|
33
|
-
req.query = payload;
|
|
34
|
-
next();
|
|
35
|
-
};
|
|
36
|
-
|
|
37
|
-
requestMock = {
|
|
38
|
-
get query() {
|
|
39
|
-
return { parameter: 'parsed-query' };
|
|
40
|
-
}
|
|
41
|
-
};
|
|
42
|
-
|
|
43
|
-
Layer = sinon.stub();
|
|
44
|
-
Layer.prototype.match = sinon.stub().returns(true);
|
|
45
|
-
|
|
46
|
-
core.depHooks.resolve.withArgs({ name: 'express', version: '4', file: 'lib/middleware/query.js' }).yields(expressQueryMock);
|
|
47
|
-
core.depHooks.resolve.withArgs({ name: 'express', version: '5', file: 'lib/request.js' }).yields(requestMock);
|
|
48
|
-
|
|
49
|
-
nextStub = sinon.stub();
|
|
50
|
-
|
|
51
|
-
inputAnalysis = core.protect.inputAnalysis;
|
|
52
|
-
expressInstr(core).install();
|
|
53
|
-
expressQueryMock = core.patcher.patch.getCall(0).returnValue;
|
|
54
|
-
core.patcher.patch.resetHistory();
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
describe('express4 query patch', function () {
|
|
58
|
-
it('calls `.handleQueryParams` when parsing is successful and in right context', function () {
|
|
59
|
-
core.scopes.sources.run({ protect: {} }, () => {
|
|
60
|
-
const queryParser = expressQueryMock(query);
|
|
61
|
-
queryParser({}, {}, nextStub);
|
|
62
|
-
});
|
|
63
|
-
|
|
64
|
-
expect(core.patcher.patch).to.have.been.calledOnce;
|
|
65
|
-
expect(core.patcher.patch).to.have.been.calledWithMatch(sinon.match.func, {
|
|
66
|
-
name: 'express.query',
|
|
67
|
-
patchType: 'protect-input-analysis',
|
|
68
|
-
pre: sinon.match.func
|
|
69
|
-
});
|
|
70
|
-
|
|
71
|
-
expect(nextStub).to.have.been.calledOnce;
|
|
72
|
-
expect(inputAnalysis.handleQueryParams).to.have.been.calledOnce;
|
|
73
|
-
expect(inputAnalysis.handleQueryParams).to.have.been.calledWithMatch({ parsedQuery: query }, query);
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
it('does not call `.handleQueryParams` when not in context', function () {
|
|
77
|
-
core.scopes.sources.run({}, () => {
|
|
78
|
-
const queryParser = expressQueryMock(query);
|
|
79
|
-
queryParser({}, {}, nextStub);
|
|
80
|
-
});
|
|
81
|
-
|
|
82
|
-
expect(inputAnalysis.handleQueryParams).not.to.have.been.called;
|
|
83
|
-
expect(nextStub).to.have.been.calledOnce;
|
|
84
|
-
});
|
|
85
|
-
|
|
86
|
-
it('does not call `.handleQueryParams` when no query is passed to`express.query`', function () {
|
|
87
|
-
core.scopes.sources.run({ protect: {} }, () => {
|
|
88
|
-
const queryParser = expressQueryMock();
|
|
89
|
-
queryParser({}, {}, nextStub);
|
|
90
|
-
});
|
|
91
|
-
|
|
92
|
-
expect(inputAnalysis.handleQueryParams).not.to.have.been.called;
|
|
93
|
-
expect(nextStub).to.have.been.calledOnce;
|
|
94
|
-
});
|
|
95
|
-
|
|
96
|
-
it('does not call `.handleQueryParams` when query was already parsed', function () {
|
|
97
|
-
core.scopes.sources.run({ protect: { parsedQuery: query } }, () => {
|
|
98
|
-
const queryParser = expressQueryMock();
|
|
99
|
-
queryParser({}, {}, nextStub);
|
|
100
|
-
});
|
|
101
|
-
|
|
102
|
-
expect(inputAnalysis.handleQueryParams).not.to.have.been.called;
|
|
103
|
-
expect(nextStub).to.have.been.calledOnce;
|
|
104
|
-
});
|
|
105
|
-
|
|
106
|
-
it('handles a case with SecurityException from `.handleQueryParams`', function () {
|
|
107
|
-
inputAnalysis.handleQueryParams.throws(secEx);
|
|
108
|
-
core.scopes.sources.run({ protect: {} }, () => {
|
|
109
|
-
const queryParser = expressQueryMock(query);
|
|
110
|
-
queryParser({}, {}, nextStub);
|
|
111
|
-
});
|
|
112
|
-
|
|
113
|
-
expect(nextStub).to.have.been.calledOnceWith(secEx);
|
|
114
|
-
});
|
|
115
|
-
|
|
116
|
-
it('handles a case with an error in the input analysis from `.handleQueryParams`', function () {
|
|
117
|
-
const err = new Error('Input Analysis Error');
|
|
118
|
-
|
|
119
|
-
inputAnalysis.handleQueryParams.throws(err);
|
|
120
|
-
core.scopes.sources.run({ protect: {} }, () => {
|
|
121
|
-
const queryParser = expressQueryMock(query);
|
|
122
|
-
queryParser({}, {}, nextStub);
|
|
123
|
-
});
|
|
124
|
-
|
|
125
|
-
expect(core.logger.error).to.have.been.calledWith(
|
|
126
|
-
{ err, funcKey: 'protect-input-analysis:express.query' },
|
|
127
|
-
'Unexpected error during input analysis'
|
|
128
|
-
);
|
|
129
|
-
expect(nextStub).to.have.been.calledOnce;
|
|
130
|
-
expect(nextStub).not.to.have.been.calledWith(err);
|
|
131
|
-
});
|
|
132
|
-
});
|
|
133
|
-
|
|
134
|
-
describe('express5 query get patch', function() {
|
|
135
|
-
it('does not call `.handleQueryParams` when not in context', function () {
|
|
136
|
-
core.scopes.sources.run({}, () => {
|
|
137
|
-
requestMock.query;
|
|
138
|
-
});
|
|
139
|
-
|
|
140
|
-
expect(inputAnalysis.handleQueryParams).not.to.have.been.called;
|
|
141
|
-
});
|
|
142
|
-
|
|
143
|
-
it('does not call `.handleQueryParams` when no query exists', function () {
|
|
144
|
-
requestMock = {
|
|
145
|
-
get query() {
|
|
146
|
-
return {};
|
|
147
|
-
}
|
|
148
|
-
};
|
|
149
|
-
core.scopes.sources.run({ protect: {} }, () => {
|
|
150
|
-
requestMock.query;
|
|
151
|
-
});
|
|
152
|
-
|
|
153
|
-
expect(inputAnalysis.handleQueryParams).not.to.have.been.called;
|
|
154
|
-
});
|
|
155
|
-
|
|
156
|
-
it('does not call `.handleQueryParams` when query was already parsed', function () {
|
|
157
|
-
core.scopes.sources.run({ protect: { parsedQuery: query } }, () => {
|
|
158
|
-
requestMock.query;
|
|
159
|
-
});
|
|
160
|
-
|
|
161
|
-
expect(inputAnalysis.handleQueryParams).not.to.have.been.called;
|
|
162
|
-
});
|
|
163
|
-
|
|
164
|
-
it('calls `.handleQueryParams` when parsing is successful and in right context', function () {
|
|
165
|
-
core.scopes.sources.run({ protect: {} }, () => {
|
|
166
|
-
requestMock.query;
|
|
167
|
-
});
|
|
168
|
-
|
|
169
|
-
expect(inputAnalysis.handleQueryParams).to.have.been.calledOnce;
|
|
170
|
-
expect(inputAnalysis.handleQueryParams).to.have.been.calledWithMatch({ parsedQuery: query }, query);
|
|
171
|
-
});
|
|
172
|
-
});
|
|
173
|
-
|
|
174
|
-
['4', '5'].forEach((v) => {
|
|
175
|
-
describe(`express${v} Layer.prototype.match`, function() {
|
|
176
|
-
let layer;
|
|
177
|
-
beforeEach(function() {
|
|
178
|
-
const args = v === '4'
|
|
179
|
-
? { name: 'express', version: '4', file: 'lib/router/layer.js' }
|
|
180
|
-
: { name: 'router', version: '2', file: 'lib/layer.js' };
|
|
181
|
-
core.depHooks.resolve.withArgs(args).yields(Layer);
|
|
182
|
-
expressInstr(core).install();
|
|
183
|
-
layer = { keys: ['foo'], params: { foo: 'bar' }, route: { path: '/test' } };
|
|
184
|
-
});
|
|
185
|
-
|
|
186
|
-
it('calls `.handleUrlParams` when parsing is successful and in right context', function () {
|
|
187
|
-
core.scopes.sources.run({ protect: {} }, () => {
|
|
188
|
-
Reflect.apply(Layer.prototype.match, layer, ['/bar']);
|
|
189
|
-
});
|
|
190
|
-
|
|
191
|
-
expect(inputAnalysis.handleUrlParams).to.have.been.calledOnce;
|
|
192
|
-
expect(inputAnalysis.handleUrlParams).to.have.been.calledWithMatch({ parsedParams: layer.params }, layer.params);
|
|
193
|
-
});
|
|
194
|
-
|
|
195
|
-
it('does not call `.handleUrlParams` when match returns false', function () {
|
|
196
|
-
Layer.prototype.match.returns(false);
|
|
197
|
-
|
|
198
|
-
core.scopes.sources.run({}, () => {
|
|
199
|
-
Reflect.apply(Layer.prototype.match, layer, ['/bar']);
|
|
200
|
-
});
|
|
201
|
-
|
|
202
|
-
expect(inputAnalysis.handleUrlParams).not.to.have.been.called;
|
|
203
|
-
});
|
|
204
|
-
|
|
205
|
-
it('does not call `.handleUrlParams` when the route path is undefined', function () {
|
|
206
|
-
core.scopes.sources.run({}, () => {
|
|
207
|
-
Reflect.apply(Layer.prototype.match, { ...layer, route: undefined }, ['/bar']);
|
|
208
|
-
});
|
|
209
|
-
|
|
210
|
-
expect(inputAnalysis.handleUrlParams).not.to.have.been.called;
|
|
211
|
-
});
|
|
212
|
-
|
|
213
|
-
it('does not call `.handleUrlParams` when the route path is `*`', function () {
|
|
214
|
-
core.scopes.sources.run({}, () => {
|
|
215
|
-
Reflect.apply(Layer.prototype.match, { ...layer, route: { path: '*' } }, ['/bar']);
|
|
216
|
-
});
|
|
217
|
-
|
|
218
|
-
expect(inputAnalysis.handleUrlParams).not.to.have.been.called;
|
|
219
|
-
});
|
|
220
|
-
|
|
221
|
-
it('does not call `.handleUrlParams` when not in context', function () {
|
|
222
|
-
core.scopes.sources.run({}, () => {
|
|
223
|
-
Reflect.apply(Layer.prototype.match, layer, ['/bar']);
|
|
224
|
-
});
|
|
225
|
-
|
|
226
|
-
expect(inputAnalysis.handleUrlParams).not.to.have.been.called;
|
|
227
|
-
});
|
|
228
|
-
|
|
229
|
-
it('does not call `.handleUrlParams` when no params are present on the current layer', function () {
|
|
230
|
-
layer = { keys: [], params: {} };
|
|
231
|
-
|
|
232
|
-
core.scopes.sources.run({ protect: {} }, () => {
|
|
233
|
-
Reflect.apply(Layer.prototype.match, layer, ['/bar']);
|
|
234
|
-
});
|
|
235
|
-
|
|
236
|
-
expect(inputAnalysis.handleUrlParams).not.to.have.been.called;
|
|
237
|
-
});
|
|
238
|
-
|
|
239
|
-
});
|
|
240
|
-
});
|
|
241
|
-
});
|