@contrast/assess 1.35.0 → 1.36.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.
- package/lib/crypto-analysis/install/crypto.js +1 -1
- package/lib/dataflow/propagation/install/JSON/parse-fn.js +1 -1
- package/lib/dataflow/propagation/install/JSON/parse.js +3 -2
- package/lib/dataflow/propagation/install/JSON/parse.test.js +2 -2
- package/lib/dataflow/propagation/install/JSON/stringify.js +11 -10
- package/lib/dataflow/propagation/install/JSON/stringify.test.js +3 -3
- package/lib/dataflow/propagation/install/array-prototype-join.js +4 -3
- package/lib/dataflow/propagation/install/array-prototype-join.test.js +3 -3
- package/lib/dataflow/propagation/install/buffer.js +2 -3
- package/lib/dataflow/propagation/install/contrast-methods/tag.test.js +2 -2
- package/lib/dataflow/propagation/install/decode-uri-component.js +5 -8
- package/lib/dataflow/propagation/install/decode-uri-component.test.js +1 -1
- package/lib/dataflow/propagation/install/ejs/escape-xml.js +6 -9
- package/lib/dataflow/propagation/install/ejs/escape-xml.test.js +2 -2
- package/lib/dataflow/propagation/install/ejs/template.js +2 -2
- package/lib/dataflow/propagation/install/encode-uri.js +4 -6
- package/lib/dataflow/propagation/install/encode-uri.test.js +2 -2
- package/lib/dataflow/propagation/install/escape-html.js +5 -8
- package/lib/dataflow/propagation/install/escape-html.test.js +3 -3
- package/lib/dataflow/propagation/install/escape.js +5 -8
- package/lib/dataflow/propagation/install/escape.test.js +2 -2
- package/lib/dataflow/propagation/install/fastify-send.js +3 -5
- package/lib/dataflow/propagation/install/handlebars-utils-escape-expression.js +6 -9
- package/lib/dataflow/propagation/install/handlebars-utils-escape-expression.test.js +1 -1
- package/lib/dataflow/propagation/install/joi/boolean.js +50 -52
- package/lib/dataflow/propagation/install/joi/expression.js +3 -10
- package/lib/dataflow/propagation/install/joi/index.js +98 -101
- package/lib/dataflow/propagation/install/joi/keys.js +10 -5
- package/lib/dataflow/propagation/install/joi/number.js +50 -52
- package/lib/dataflow/propagation/install/joi/string-schema.js +9 -14
- package/lib/dataflow/propagation/install/joi/utils.js +7 -4
- package/lib/dataflow/propagation/install/joi/values.js +5 -7
- package/lib/dataflow/propagation/install/mongoose/schema-map.js +5 -4
- package/lib/dataflow/propagation/install/mongoose/schema-map.test.js +4 -4
- package/lib/dataflow/propagation/install/mongoose/schema-mixed.js +5 -4
- package/lib/dataflow/propagation/install/mongoose/schema-mixed.test.js +4 -5
- package/lib/dataflow/propagation/install/mongoose/schema-string.js +3 -4
- package/lib/dataflow/propagation/install/mustache-escape.js +5 -8
- package/lib/dataflow/propagation/install/mustache-escape.test.js +2 -2
- package/lib/dataflow/propagation/install/mysql-connection-escape.js +5 -8
- package/lib/dataflow/propagation/install/mysql-connection-escape.test.js +2 -2
- package/lib/dataflow/propagation/install/parse-int.js +3 -3
- package/lib/dataflow/propagation/install/path/basename.js +7 -12
- package/lib/dataflow/propagation/install/path/basename.test.js +2 -2
- package/lib/dataflow/propagation/install/path/common.js +2 -2
- package/lib/dataflow/propagation/install/path/dirname.js +5 -10
- package/lib/dataflow/propagation/install/path/dirname.test.js +2 -2
- package/lib/dataflow/propagation/install/path/extname.js +6 -11
- package/lib/dataflow/propagation/install/path/extname.test.js +2 -2
- package/lib/dataflow/propagation/install/path/format.js +7 -13
- package/lib/dataflow/propagation/install/path/format.test.js +2 -2
- package/lib/dataflow/propagation/install/path/join-and-resolve.js +7 -12
- package/lib/dataflow/propagation/install/path/join-and-resolve.test.js +2 -2
- package/lib/dataflow/propagation/install/path/normalize.js +4 -11
- package/lib/dataflow/propagation/install/path/normalize.test.js +2 -2
- package/lib/dataflow/propagation/install/path/parse.js +3 -8
- package/lib/dataflow/propagation/install/path/parse.test.js +2 -2
- package/lib/dataflow/propagation/install/path/relative.js +5 -11
- package/lib/dataflow/propagation/install/path/relative.test.js +2 -2
- package/lib/dataflow/propagation/install/path/toNamespacedPath.js +5 -11
- package/lib/dataflow/propagation/install/path/toNamespacedPath.test.js +2 -2
- package/lib/dataflow/propagation/install/pug/index.js +8 -3
- package/lib/dataflow/propagation/install/pug-runtime-escape.js +5 -8
- package/lib/dataflow/propagation/install/pug-runtime-escape.test.js +1 -1
- package/lib/dataflow/propagation/install/querystring/escape.js +3 -3
- package/lib/dataflow/propagation/install/querystring/parse.js +7 -11
- package/lib/dataflow/propagation/install/querystring/stringify.js +3 -3
- package/lib/dataflow/propagation/install/reg-exp-prototype-exec.js +4 -3
- package/lib/dataflow/propagation/install/reg-exp-prototype-exec.test.js +5 -3
- package/lib/dataflow/propagation/install/send.js +5 -10
- package/lib/dataflow/propagation/install/sequelize/query-generator.js +3 -4
- package/lib/dataflow/propagation/install/sequelize/sql-string.js +8 -12
- package/lib/dataflow/propagation/install/sequelize/sql-string.test.js +2 -13
- package/lib/dataflow/propagation/install/sql-template-strings.js +3 -5
- package/lib/dataflow/propagation/install/sql-template-strings.test.js +2 -2
- package/lib/dataflow/propagation/install/string/concat.js +2 -1
- package/lib/dataflow/propagation/install/string/concat.test.js +15 -2
- package/lib/dataflow/propagation/install/string/format-methods.js +4 -2
- package/lib/dataflow/propagation/install/string/format-methods.test.js +15 -2
- package/lib/dataflow/propagation/install/string/html-methods.js +1 -1
- package/lib/dataflow/propagation/install/string/html-methods.test.js +15 -2
- package/lib/dataflow/propagation/install/string/index.js +2 -2
- package/lib/dataflow/propagation/install/string/match-all.js +2 -1
- package/lib/dataflow/propagation/install/string/match-all.test.js +13 -0
- package/lib/dataflow/propagation/install/string/match.js +11 -10
- package/lib/dataflow/propagation/install/string/match.test.js +13 -0
- package/lib/dataflow/propagation/install/string/replace.js +15 -9
- package/lib/dataflow/propagation/install/string/replace.test.js +13 -0
- package/lib/dataflow/propagation/install/string/slice.js +2 -1
- package/lib/dataflow/propagation/install/string/slice.test.js +13 -0
- package/lib/dataflow/propagation/install/string/split.js +2 -1
- package/lib/dataflow/propagation/install/string/split.test.js +13 -0
- package/lib/dataflow/propagation/install/string/substring.js +2 -1
- package/lib/dataflow/propagation/install/string/substring.test.js +13 -0
- package/lib/dataflow/propagation/install/string/trim.js +4 -1
- package/lib/dataflow/propagation/install/string/trim.test.js +13 -0
- package/lib/dataflow/propagation/install/unescape.js +5 -8
- package/lib/dataflow/propagation/install/unescape.test.js +2 -2
- package/lib/dataflow/propagation/install/url/domain-parsers.js +4 -5
- package/lib/dataflow/propagation/install/url/domain-parsers.test.js +2 -2
- package/lib/dataflow/propagation/install/url/parse.js +3 -2
- package/lib/dataflow/propagation/install/url/parse.test.js +2 -2
- package/lib/dataflow/propagation/install/url/searchParams.js +5 -5
- package/lib/dataflow/propagation/install/url/searchParams.test.js +2 -2
- package/lib/dataflow/propagation/install/url/url.js +6 -3
- package/lib/dataflow/propagation/install/url/url.test.js +2 -2
- package/lib/dataflow/propagation/install/util-format.js +7 -6
- package/lib/dataflow/propagation/install/util-format.test.js +2 -2
- package/lib/dataflow/propagation/install/validator/hooks.js +7 -2
- package/lib/dataflow/sinks/install/child-process.js +1 -1
- package/lib/dataflow/sinks/install/child-process.test.js +1 -1
- package/lib/dataflow/sinks/install/fs.js +1 -1
- package/lib/dataflow/sinks/install/fs.test.js +1 -1
- package/lib/dataflow/sinks/install/function.js +1 -1
- package/lib/dataflow/sinks/install/http/request.js +2 -1
- package/lib/dataflow/sinks/install/http/request.test.js +1 -1
- package/lib/dataflow/sinks/install/http/server-response.test.js +3 -5
- package/lib/dataflow/sinks/install/restify.js +1 -1
- package/lib/dataflow/sinks/install/vm.js +4 -2
- package/lib/dataflow/sinks/install/vm.test.js +1 -1
- package/lib/dataflow/sources/handler.js +5 -2
- package/lib/dataflow/sources/install/body-parser1.test.js +4 -4
- package/lib/dataflow/sources/install/busboy.js +8 -3
- package/lib/dataflow/sources/install/busboy.test.js +2 -2
- package/lib/dataflow/sources/install/cookie-parser1.test.js +2 -2
- package/lib/dataflow/sources/install/express/params.js +14 -11
- package/lib/dataflow/sources/install/express/params.test.js +5 -7
- package/lib/dataflow/sources/install/express/parsedUrl.js +3 -2
- package/lib/dataflow/sources/install/fastify/fastify.js +7 -6
- package/lib/dataflow/sources/install/fastify/fastify.test.js +2 -2
- package/lib/dataflow/sources/install/formidable1.js +7 -6
- package/lib/dataflow/sources/install/formidable1.test.js +2 -2
- package/lib/dataflow/sources/install/hapi/hapi.js +8 -10
- package/lib/dataflow/sources/install/hapi/hapi.test.js +0 -1
- package/lib/dataflow/sources/install/http.js +20 -16
- package/lib/dataflow/sources/install/http.test.js +28 -34
- package/lib/dataflow/sources/install/koa/koa-bodyparsers.js +7 -7
- package/lib/dataflow/sources/install/koa/koa-bodyparsers.test.js +3 -4
- package/lib/dataflow/sources/install/koa/koa-multer.js +8 -4
- package/lib/dataflow/sources/install/koa/koa-routers.js +7 -6
- package/lib/dataflow/sources/install/koa/koa-routers.test.js +2 -2
- package/lib/dataflow/sources/install/koa/koa2.js +7 -3
- package/lib/dataflow/sources/install/koa/koa2.test.js +1 -1
- package/lib/dataflow/sources/install/multer1.js +6 -2
- package/lib/dataflow/sources/install/qs6.js +1 -1
- package/lib/dataflow/sources/install/querystring.js +1 -1
- package/lib/dataflow/sources/install/restify/fieldedTextBodyParser.js +1 -4
- package/lib/dataflow/sources/install/restify/fieldedTextBodyParser.test.js +6 -8
- package/lib/dataflow/sources/install/restify/jsonBodyParser.js +0 -1
- package/lib/dataflow/sources/install/restify/jsonBodyParser.test.js +4 -8
- package/lib/dataflow/sources/install/restify/router.test.js +2 -2
- package/lib/dataflow/tag-utils.js +1 -1
- package/lib/dataflow/tracker.js +1 -1
- package/lib/dataflow/utils/is-safe-content-type.js +3 -2
- package/lib/event-factory.js +4 -4
- package/lib/get-policy.js +2 -2
- package/lib/index.js +18 -7
- package/lib/index.test.js +4 -0
- package/lib/make-source-context.js +37 -28
- package/lib/make-source-context.test.js +7 -7
- package/lib/response-scanning/handlers/index.js +7 -5
- package/lib/response-scanning/handlers/utils.js +11 -8
- package/lib/response-scanning/install/http.js +1 -1
- package/lib/sampler.js +136 -0
- package/lib/sampler.test.js +296 -0
- package/lib/session-configuration/install/express-session.js +1 -1
- package/lib/session-configuration/install/fastify-cookie.js +1 -1
- package/package.json +10 -10
|
@@ -16,10 +16,16 @@
|
|
|
16
16
|
'use strict';
|
|
17
17
|
|
|
18
18
|
const { InputType } = require('@contrast/common');
|
|
19
|
+
const { InstrumentationType: { SOURCE } } = require('../../../../constants');
|
|
19
20
|
const { patchType } = require('../../common');
|
|
20
21
|
|
|
21
22
|
module.exports = function init(core) {
|
|
22
|
-
const {
|
|
23
|
+
const {
|
|
24
|
+
logger,
|
|
25
|
+
patcher,
|
|
26
|
+
depHooks,
|
|
27
|
+
assess: { getSourceContext },
|
|
28
|
+
} = core;
|
|
23
29
|
|
|
24
30
|
core.assess.dataflow.sources.expressInstrumentation.params = {
|
|
25
31
|
install() {
|
|
@@ -31,20 +37,17 @@ module.exports = function init(core) {
|
|
|
31
37
|
name,
|
|
32
38
|
patchType,
|
|
33
39
|
post({ obj: layer, result, orig, hooked, funcKey }) {
|
|
34
|
-
|
|
35
40
|
// we can exit early if
|
|
36
41
|
// the layer doesn't match the request or
|
|
37
42
|
// the layer doesn't recognize any parameters
|
|
38
|
-
if (
|
|
39
|
-
|
|
40
|
-
|
|
43
|
+
if (
|
|
44
|
+
!result ||
|
|
45
|
+
!layer.keys ||
|
|
46
|
+
layer.keys.length === 0
|
|
47
|
+
) return;
|
|
41
48
|
|
|
42
|
-
const sourceContext =
|
|
43
|
-
|
|
44
|
-
if (!sourceContext) {
|
|
45
|
-
logger.error({ funcKey }, 'unable to handle source. Missing `sourceContext`');
|
|
46
|
-
return;
|
|
47
|
-
}
|
|
49
|
+
const sourceContext = getSourceContext(SOURCE)
|
|
50
|
+
if (!sourceContext) return;
|
|
48
51
|
|
|
49
52
|
if (sourceContext.parsedParams) {
|
|
50
53
|
logger.trace({ funcKey }, 'values already tracked');
|
|
@@ -65,20 +65,18 @@ describe('assess dataflow sources express params', function () {
|
|
|
65
65
|
});
|
|
66
66
|
});
|
|
67
67
|
|
|
68
|
-
it('does not
|
|
68
|
+
it('does not handle when there is no assess policy in request context', function () {
|
|
69
69
|
simulateRequestScope(() => {
|
|
70
70
|
Reflect.apply(Layer.prototype.match, layer, ['/bar']);
|
|
71
71
|
|
|
72
72
|
expect(core.assess.dataflow.sources.handle).not.to.have.been.called;
|
|
73
|
-
|
|
74
|
-
{ funcKey: 'assess-dataflow-source:Layer.prototype.match' },
|
|
75
|
-
'unable to handle source. Missing `sourceContext`'
|
|
76
|
-
);
|
|
77
|
-
}, {});
|
|
73
|
+
}, { assess: { policy: null } });
|
|
78
74
|
});
|
|
79
75
|
|
|
80
76
|
it('does not call `.handle` when the values are already tracked', function () {
|
|
81
77
|
simulateRequestScope(() => {
|
|
78
|
+
core.scopes.sources.getStore().assess.parsedParams = true;
|
|
79
|
+
|
|
82
80
|
Reflect.apply(Layer.prototype.match, layer, ['/bar']);
|
|
83
81
|
|
|
84
82
|
expect(core.assess.dataflow.sources.handle).not.to.have.been.called;
|
|
@@ -86,7 +84,7 @@ describe('assess dataflow sources express params', function () {
|
|
|
86
84
|
{ funcKey: 'assess-dataflow-source:Layer.prototype.match' },
|
|
87
85
|
'values already tracked'
|
|
88
86
|
);
|
|
89
|
-
}
|
|
87
|
+
});
|
|
90
88
|
});
|
|
91
89
|
|
|
92
90
|
it('handles a case with an error in the `.handle` method', function () {
|
|
@@ -16,16 +16,17 @@
|
|
|
16
16
|
'use strict';
|
|
17
17
|
|
|
18
18
|
const { InputType } = require('@contrast/common');
|
|
19
|
+
const { InstrumentationType: { SOURCE } } = require('../../../../constants');
|
|
19
20
|
const { patchType } = require('../../common');
|
|
20
21
|
|
|
21
22
|
module.exports = function init(core) {
|
|
22
23
|
const {
|
|
23
24
|
assess: {
|
|
25
|
+
getSourceContext,
|
|
24
26
|
dataflow: { sources }
|
|
25
27
|
},
|
|
26
28
|
depHooks,
|
|
27
29
|
patcher,
|
|
28
|
-
scopes
|
|
29
30
|
} = core;
|
|
30
31
|
|
|
31
32
|
core.assess.dataflow.sources.expressInstrumentation.parsedUrl = {
|
|
@@ -48,7 +49,7 @@ module.exports = function init(core) {
|
|
|
48
49
|
name: 'express.middleware.init.expressInit.next',
|
|
49
50
|
patchType,
|
|
50
51
|
pre(data) {
|
|
51
|
-
const sourceContext =
|
|
52
|
+
const sourceContext = getSourceContext(SOURCE);
|
|
52
53
|
if (!sourceContext) return;
|
|
53
54
|
|
|
54
55
|
const sourceInfo = {
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
'use strict';
|
|
17
17
|
|
|
18
18
|
const { InputType } = require('@contrast/common');
|
|
19
|
+
const { InstrumentationType: { SOURCE } } = require('../../../../constants');
|
|
19
20
|
const { patchType } = require('../../common');
|
|
20
21
|
|
|
21
22
|
module.exports = function (core) {
|
|
@@ -23,7 +24,10 @@ module.exports = function (core) {
|
|
|
23
24
|
logger,
|
|
24
25
|
depHooks,
|
|
25
26
|
patcher,
|
|
26
|
-
assess: {
|
|
27
|
+
assess: {
|
|
28
|
+
getSourceContext,
|
|
29
|
+
dataflow: { sources }
|
|
30
|
+
},
|
|
27
31
|
} = core;
|
|
28
32
|
|
|
29
33
|
const source = sources.fastifyInstrumentation.fastify = {
|
|
@@ -38,12 +42,9 @@ module.exports = function (core) {
|
|
|
38
42
|
: typeof request.body == 'object'
|
|
39
43
|
? InputType.PARAMETER_VALUE
|
|
40
44
|
: InputType.BODY;
|
|
41
|
-
const sourceContext =
|
|
45
|
+
const sourceContext = getSourceContext(SOURCE);
|
|
42
46
|
|
|
43
|
-
if (!sourceContext)
|
|
44
|
-
logger.error({ funcKey }, 'unable to handle source. Missing `sourceContext`');
|
|
45
|
-
return;
|
|
46
|
-
}
|
|
47
|
+
if (!sourceContext) return;
|
|
47
48
|
|
|
48
49
|
[
|
|
49
50
|
{ key: 'query', inputType: InputType.QUERYSTRING, alreadyTrackedFlag: 'parsedQuery' },
|
|
@@ -146,10 +146,10 @@ describe('assess dataflow sources fastify', function () {
|
|
|
146
146
|
});
|
|
147
147
|
});
|
|
148
148
|
|
|
149
|
-
it('does not
|
|
149
|
+
it('does not handle source when there is no assess policy in request context', function () {
|
|
150
150
|
simulateRequestScope(() => {
|
|
151
151
|
fastifyServerMock();
|
|
152
|
-
}, {});
|
|
152
|
+
}, { assess: { policy: null } });
|
|
153
153
|
|
|
154
154
|
expect(sources.handle).not.to.have.been.called;
|
|
155
155
|
});
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
'use strict';
|
|
17
17
|
|
|
18
18
|
const { InputType } = require('@contrast/common');
|
|
19
|
+
const { InstrumentationType: { SOURCE } } = require('../../../constants');
|
|
19
20
|
const { patchType } = require('../common');
|
|
20
21
|
|
|
21
22
|
const inputType = InputType.MULTIPART_VALUE;
|
|
@@ -25,7 +26,10 @@ module.exports = (core) => {
|
|
|
25
26
|
depHooks,
|
|
26
27
|
patcher,
|
|
27
28
|
logger,
|
|
28
|
-
assess: {
|
|
29
|
+
assess: {
|
|
30
|
+
getSourceContext,
|
|
31
|
+
dataflow: { sources }
|
|
32
|
+
},
|
|
29
33
|
} = core;
|
|
30
34
|
|
|
31
35
|
const name = 'Formidable.IncomingForm.prototype.parse';
|
|
@@ -38,12 +42,9 @@ module.exports = (core) => {
|
|
|
38
42
|
patchType,
|
|
39
43
|
pre(data) {
|
|
40
44
|
const { funcKey } = data;
|
|
41
|
-
const sourceContext =
|
|
45
|
+
const sourceContext = getSourceContext(SOURCE);
|
|
42
46
|
|
|
43
|
-
if (!sourceContext)
|
|
44
|
-
logger.error({ inputType, funcKey }, 'unable to handle source. Missing `sourceContext`');
|
|
45
|
-
return;
|
|
46
|
-
}
|
|
47
|
+
if (!sourceContext) return;
|
|
47
48
|
|
|
48
49
|
if (sourceContext.parsedBody) {
|
|
49
50
|
logger.trace({ inputType, funcKey }, 'values already tracked');
|
|
@@ -82,10 +82,10 @@ describe('assess dataflow sources formidable v1.x', function () {
|
|
|
82
82
|
);
|
|
83
83
|
});
|
|
84
84
|
|
|
85
|
-
it('does not call `.handle` when
|
|
85
|
+
it('does not call `.handle` when there is no assess policy in request context', function () {
|
|
86
86
|
simulateRequestScope(() => {
|
|
87
87
|
patchedParse(req, cbStub);
|
|
88
|
-
}, {});
|
|
88
|
+
}, { assess: { policy: null } });
|
|
89
89
|
|
|
90
90
|
expect(sources.handle).not.to.have.been.called;
|
|
91
91
|
expect(cbStub).to.have.been.calledOnce;
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
'use strict';
|
|
17
17
|
|
|
18
18
|
const { InputType } = require('@contrast/common');
|
|
19
|
+
const { InstrumentationType: { SOURCE } } = require('../../../../constants');
|
|
19
20
|
const { patchType } = require('../../common');
|
|
20
21
|
|
|
21
22
|
module.exports = function (core) {
|
|
@@ -23,7 +24,10 @@ module.exports = function (core) {
|
|
|
23
24
|
logger,
|
|
24
25
|
depHooks,
|
|
25
26
|
patcher,
|
|
26
|
-
assess: {
|
|
27
|
+
assess: {
|
|
28
|
+
getSourceContext,
|
|
29
|
+
dataflow: { sources }
|
|
30
|
+
},
|
|
27
31
|
} = core;
|
|
28
32
|
|
|
29
33
|
const source = sources.hapiInstrumentation.hapi = {
|
|
@@ -36,11 +40,8 @@ module.exports = function (core) {
|
|
|
36
40
|
post({ result: server, funcKey, hooked, orig }) {
|
|
37
41
|
|
|
38
42
|
server.ext('onRequest', (req, h) => {
|
|
39
|
-
const sourceContext =
|
|
40
|
-
if (!sourceContext)
|
|
41
|
-
logger.error({ funcKey }, 'unable to handle source. Missing `sourceContext`');
|
|
42
|
-
return;
|
|
43
|
-
}
|
|
43
|
+
const sourceContext = getSourceContext(SOURCE);
|
|
44
|
+
if (!sourceContext) return;
|
|
44
45
|
|
|
45
46
|
[
|
|
46
47
|
{ key: 'query', inputType: InputType.QUERYSTRING, trackedFlag: 'parsedQuery' },
|
|
@@ -72,10 +73,7 @@ module.exports = function (core) {
|
|
|
72
73
|
});
|
|
73
74
|
server.ext('onPostAuth', (req, h) => {
|
|
74
75
|
const sourceContext = core.scopes.sources.getStore()?.assess;
|
|
75
|
-
if (!sourceContext)
|
|
76
|
-
logger.error({ funcKey }, 'unable to handle source. Missing `sourceContext`');
|
|
77
|
-
return;
|
|
78
|
-
}
|
|
76
|
+
if (!sourceContext) return;
|
|
79
77
|
|
|
80
78
|
[
|
|
81
79
|
{ key: 'state', inputType: InputType.COOKIE_VALUE, trackedFlag: 'parsedCookies' },
|
|
@@ -14,8 +14,10 @@
|
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
16
|
'use strict';
|
|
17
|
+
|
|
18
|
+
const { primordials: { StringPrototypeToLowerCase }, InputType } = require('@contrast/common');
|
|
19
|
+
const { InstrumentationType: { SOURCE } } = require('../../../constants');
|
|
17
20
|
const { patchType } = require('../common');
|
|
18
|
-
const { StringPrototypeToLowerCase, InputType } = require('@contrast/common');
|
|
19
21
|
|
|
20
22
|
/**
|
|
21
23
|
* @param {{
|
|
@@ -24,13 +26,15 @@ const { StringPrototypeToLowerCase, InputType } = require('@contrast/common');
|
|
|
24
26
|
*/
|
|
25
27
|
module.exports = function (core) {
|
|
26
28
|
const {
|
|
27
|
-
assess: {
|
|
29
|
+
assess: {
|
|
30
|
+
getSourceContext,
|
|
31
|
+
dataflow,
|
|
32
|
+
},
|
|
28
33
|
instrumentation: { instrument },
|
|
29
34
|
patcher,
|
|
30
|
-
scopes,
|
|
31
35
|
} = core;
|
|
32
36
|
|
|
33
|
-
const logger = core.logger.child('contrast:assess');
|
|
37
|
+
const logger = core.logger.child({ name: 'contrast:assess' });
|
|
34
38
|
|
|
35
39
|
/**
|
|
36
40
|
* The around hook for `emit` that
|
|
@@ -43,16 +47,12 @@ module.exports = function (core) {
|
|
|
43
47
|
|
|
44
48
|
try {
|
|
45
49
|
const [, req, res] = data.args;
|
|
46
|
-
const
|
|
50
|
+
const sourceContext = getSourceContext(SOURCE);
|
|
47
51
|
|
|
48
|
-
if (!
|
|
49
|
-
|
|
50
|
-
throw new Error('async request store not found');
|
|
52
|
+
if (!sourceContext?.policy) {
|
|
53
|
+
return next();
|
|
51
54
|
}
|
|
52
55
|
|
|
53
|
-
store.assess = makeSourceContext(req, res);
|
|
54
|
-
if (!store.assess) return;
|
|
55
|
-
|
|
56
56
|
patcher.patch(res, 'writeHead', {
|
|
57
57
|
name: 'write-head',
|
|
58
58
|
patchType,
|
|
@@ -66,13 +66,13 @@ module.exports = function (core) {
|
|
|
66
66
|
const value = obj[i + 1];
|
|
67
67
|
|
|
68
68
|
if (StringPrototypeToLowerCase.call(key) === 'content-type') {
|
|
69
|
-
|
|
69
|
+
sourceContext.responseData.contentType = value;
|
|
70
70
|
}
|
|
71
71
|
}
|
|
72
72
|
} else if (typeof obj === 'object') {
|
|
73
73
|
for (const [key, value] of Object.entries(obj)) {
|
|
74
74
|
if (StringPrototypeToLowerCase.call(key) === 'content-type') {
|
|
75
|
-
|
|
75
|
+
sourceContext.responseData.contentType = value;
|
|
76
76
|
}
|
|
77
77
|
}
|
|
78
78
|
}
|
|
@@ -85,8 +85,12 @@ module.exports = function (core) {
|
|
|
85
85
|
patchType,
|
|
86
86
|
pre(data) {
|
|
87
87
|
const [name = '', value] = data.args;
|
|
88
|
-
if (
|
|
89
|
-
|
|
88
|
+
if (
|
|
89
|
+
value &&
|
|
90
|
+
StringPrototypeToLowerCase.call(name) === 'content-type' &&
|
|
91
|
+
getSourceContext(SOURCE)
|
|
92
|
+
) {
|
|
93
|
+
sourceContext.responseData.contentType = value;
|
|
90
94
|
}
|
|
91
95
|
}
|
|
92
96
|
});
|
|
@@ -99,7 +103,7 @@ module.exports = function (core) {
|
|
|
99
103
|
constructorOpt: data.hooked,
|
|
100
104
|
prependFrames: [data.orig]
|
|
101
105
|
},
|
|
102
|
-
sourceContext
|
|
106
|
+
sourceContext,
|
|
103
107
|
};
|
|
104
108
|
|
|
105
109
|
// track the headers and the url.
|
|
@@ -4,6 +4,7 @@ const EventEmitter = require('events');
|
|
|
4
4
|
const sinon = require('sinon');
|
|
5
5
|
const { expect } = require('chai');
|
|
6
6
|
const { initAssessFixture } = require('@contrast/test/fixtures');
|
|
7
|
+
const mocks = require('@contrast/test/mocks');
|
|
7
8
|
|
|
8
9
|
describe('assess dataflow sources http', function () {
|
|
9
10
|
let core, simulateRequestScope, request, response, server;
|
|
@@ -11,21 +12,9 @@ describe('assess dataflow sources http', function () {
|
|
|
11
12
|
beforeEach(function () {
|
|
12
13
|
({ core, simulateRequestScope } = initAssessFixture());
|
|
13
14
|
|
|
14
|
-
request =
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
method: 'GET',
|
|
18
|
-
socket: {
|
|
19
|
-
remoteAddress: '127.0.0.1'
|
|
20
|
-
},
|
|
21
|
-
rawHeaders: ['Content-Type', 'application/json'],
|
|
22
|
-
headers: {
|
|
23
|
-
'content-type': 'application/json'
|
|
24
|
-
}
|
|
25
|
-
};
|
|
26
|
-
response = new EventEmitter();
|
|
27
|
-
response.writeHead = function () { };
|
|
28
|
-
response.setHeader = function () { };
|
|
15
|
+
request = mocks.incomingMessage();
|
|
16
|
+
response = mocks.serverResponse();
|
|
17
|
+
|
|
29
18
|
class Server extends EventEmitter { }
|
|
30
19
|
core.depHooks.resolve.withArgs({ name: 'http' }).yields({ Server });
|
|
31
20
|
core.logger.child = () => core.logger;
|
|
@@ -36,6 +25,7 @@ describe('assess dataflow sources http', function () {
|
|
|
36
25
|
|
|
37
26
|
it('instantiates assess store with appropriate metadata and handles base sources', function (next) {
|
|
38
27
|
simulateRequestScope(() => {
|
|
28
|
+
core.scopes.sources.getStore().assess.req
|
|
39
29
|
server.on('request', test);
|
|
40
30
|
server.emit('request', request, response);
|
|
41
31
|
});
|
|
@@ -44,17 +34,22 @@ describe('assess dataflow sources http', function () {
|
|
|
44
34
|
const store = core.scopes.sources.getStore()?.assess;
|
|
45
35
|
// validate store
|
|
46
36
|
expect(store).to.have.property('propagationEventsCount', 0);
|
|
47
|
-
//
|
|
48
|
-
expect(store).to.have.property('sourceEventsCount',
|
|
37
|
+
// url(1), headers(3), rawHeaders(3)
|
|
38
|
+
expect(store).to.have.property('sourceEventsCount', 7);
|
|
49
39
|
expect(store.policy.enabledRules).to.be.a('Set').and.length.greaterThan(5);
|
|
40
|
+
// should match the mock
|
|
50
41
|
expect(store.reqData).to.deep.equal({
|
|
51
42
|
ip: '127.0.0.1',
|
|
52
|
-
httpVersion: 1,
|
|
53
|
-
method: '
|
|
54
|
-
headers: {
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
43
|
+
httpVersion: '1.1',
|
|
44
|
+
method: 'get',
|
|
45
|
+
headers: {
|
|
46
|
+
'content-type': 'text/html',
|
|
47
|
+
language: 'en',
|
|
48
|
+
referer: 'http://fake.url.foo'
|
|
49
|
+
},
|
|
50
|
+
uriPath: '/index',
|
|
51
|
+
queries: '_id=123',
|
|
52
|
+
contentType: 'text/html'
|
|
58
53
|
});
|
|
59
54
|
expect(store.responseData).to.deep.equal({});
|
|
60
55
|
// tracked inputs
|
|
@@ -101,11 +96,6 @@ describe('assess dataflow sources http', function () {
|
|
|
101
96
|
|
|
102
97
|
function test(req, res) {
|
|
103
98
|
const store = core.scopes.sources.getStore()?.assess;
|
|
104
|
-
// logging
|
|
105
|
-
expect(core.logger.error).to.have.been.calledWith(
|
|
106
|
-
{ err: sinon.match.has('message', 'async request store not found'), funcKey: sinon.match.string },
|
|
107
|
-
'Error during Assess request handling'
|
|
108
|
-
);
|
|
109
99
|
// validate store
|
|
110
100
|
expect(store).to.be.undefined;
|
|
111
101
|
// tracked inputs
|
|
@@ -135,12 +125,16 @@ describe('assess dataflow sources http', function () {
|
|
|
135
125
|
expect(store.policy.enabledRules).to.be.a('Set').and.length.greaterThan(5);
|
|
136
126
|
expect(store.reqData).to.deep.equal({
|
|
137
127
|
ip: '127.0.0.1',
|
|
138
|
-
httpVersion: 1,
|
|
139
|
-
method: '
|
|
140
|
-
headers: {
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
128
|
+
httpVersion: '1.1',
|
|
129
|
+
method: 'get',
|
|
130
|
+
headers: {
|
|
131
|
+
'content-type': 'text/html',
|
|
132
|
+
language: 'en',
|
|
133
|
+
referer: 'http://fake.url.foo'
|
|
134
|
+
},
|
|
135
|
+
uriPath: '/index',
|
|
136
|
+
queries: '_id=123',
|
|
137
|
+
contentType: 'text/html'
|
|
144
138
|
});
|
|
145
139
|
expect(store.responseData).to.deep.equal({});
|
|
146
140
|
// tracked inputs
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
'use strict';
|
|
17
17
|
|
|
18
18
|
const { InputType } = require('@contrast/common');
|
|
19
|
+
const { InstrumentationType: { SOURCE } } = require('../../../../constants');
|
|
19
20
|
const { patchType } = require('../../common');
|
|
20
21
|
|
|
21
22
|
module.exports = (core) => {
|
|
@@ -23,7 +24,10 @@ module.exports = (core) => {
|
|
|
23
24
|
depHooks,
|
|
24
25
|
patcher,
|
|
25
26
|
logger,
|
|
26
|
-
assess: {
|
|
27
|
+
assess: {
|
|
28
|
+
getSourceContext,
|
|
29
|
+
dataflow: { sources }
|
|
30
|
+
},
|
|
27
31
|
} = core;
|
|
28
32
|
|
|
29
33
|
// Patch `koa-body` v4.x.x and `koa-bodyparser` v5.x.x packages
|
|
@@ -38,20 +42,16 @@ module.exports = (core) => {
|
|
|
38
42
|
patchType,
|
|
39
43
|
pre(data) {
|
|
40
44
|
const { funcKey } = data;
|
|
41
|
-
const sourceContext = core.scopes.sources.getStore()?.assess;
|
|
42
45
|
const [ctx, origNext] = data.args;
|
|
46
|
+
const sourceContext = getSourceContext(SOURCE);
|
|
43
47
|
|
|
44
|
-
if (!sourceContext)
|
|
45
|
-
logger.error({ funcKey }, 'unable to handle source. Missing `sourceContext`');
|
|
46
|
-
return;
|
|
47
|
-
}
|
|
48
|
+
if (!sourceContext) return;
|
|
48
49
|
|
|
49
50
|
if (sourceContext.parsedBody) {
|
|
50
51
|
logger.trace({ funcKey }, 'values already tracked');
|
|
51
52
|
return;
|
|
52
53
|
}
|
|
53
54
|
|
|
54
|
-
|
|
55
55
|
data.args[1] = async function contrastNext(origErr) {
|
|
56
56
|
const inputType = sourceContext.reqData.headers?.['content-type']?.includes('/json')
|
|
57
57
|
? InputType.JSON_VALUE
|
|
@@ -112,11 +112,11 @@ describe('assess dataflow sources koa-body v5.x.x and koa-bodyparser v4.x.x', fu
|
|
|
112
112
|
});
|
|
113
113
|
});
|
|
114
114
|
|
|
115
|
-
it('does not call `.handle` when
|
|
115
|
+
it('does not call `.handle` when there is no assess policy in request context', function () {
|
|
116
116
|
simulateRequestScope(() => {
|
|
117
117
|
const cParser = patchedKoaBodyparser(body);
|
|
118
118
|
cParser({ request: {} }, nextStub);
|
|
119
|
-
}, {});
|
|
119
|
+
}, { assess: { policy: null } });
|
|
120
120
|
|
|
121
121
|
expect(sources.handle).not.to.have.been.called;
|
|
122
122
|
expect(nextStub).to.have.been.calledOnce;
|
|
@@ -124,8 +124,7 @@ describe('assess dataflow sources koa-body v5.x.x and koa-bodyparser v4.x.x', fu
|
|
|
124
124
|
|
|
125
125
|
it('does not call `.handle` when the values are already tracked', function () {
|
|
126
126
|
simulateRequestScope(() => {
|
|
127
|
-
|
|
128
|
-
sourceContext.parsedBody = true;
|
|
127
|
+
core.scopes.sources.getStore().assess.parsedBody = true;
|
|
129
128
|
|
|
130
129
|
const cParser = patchedKoaBodyparser(body);
|
|
131
130
|
cParser({ request: {} }, nextStub);
|
|
@@ -14,20 +14,24 @@
|
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
16
|
'use strict';
|
|
17
|
-
|
|
17
|
+
|
|
18
18
|
const { InputType } = require('@contrast/common');
|
|
19
|
+
const { InstrumentationType: { SOURCE } } = require('../../../../constants');
|
|
20
|
+
const { patchType } = require('../../common');
|
|
19
21
|
|
|
20
22
|
module.exports = (core) => {
|
|
21
23
|
const {
|
|
22
24
|
depHooks,
|
|
23
25
|
logger,
|
|
24
26
|
patcher,
|
|
25
|
-
|
|
26
|
-
|
|
27
|
+
assess: {
|
|
28
|
+
getSourceContext,
|
|
29
|
+
dataflow: { sources }
|
|
30
|
+
},
|
|
27
31
|
} = core;
|
|
28
32
|
|
|
29
33
|
function handler(req, constructorOpt) {
|
|
30
|
-
const sourceContext =
|
|
34
|
+
const sourceContext = getSourceContext(SOURCE);
|
|
31
35
|
if (!sourceContext) return;
|
|
32
36
|
|
|
33
37
|
function handle(context, data, key) {
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
'use strict';
|
|
17
17
|
|
|
18
18
|
const { InputType } = require('@contrast/common');
|
|
19
|
+
const { InstrumentationType: { SOURCE } } = require('../../../../constants');
|
|
19
20
|
const { patchType } = require('../../common');
|
|
20
21
|
|
|
21
22
|
module.exports = (core) => {
|
|
@@ -23,7 +24,10 @@ module.exports = (core) => {
|
|
|
23
24
|
depHooks,
|
|
24
25
|
patcher,
|
|
25
26
|
logger,
|
|
26
|
-
assess: {
|
|
27
|
+
assess: {
|
|
28
|
+
getSourceContext,
|
|
29
|
+
dataflow: { sources }
|
|
30
|
+
},
|
|
27
31
|
} = core;
|
|
28
32
|
|
|
29
33
|
// Patch `koa-router` and `@koa/router` to handle parsed params
|
|
@@ -36,13 +40,10 @@ module.exports = (core) => {
|
|
|
36
40
|
name: `[${router}].layer.prototype`,
|
|
37
41
|
patchType,
|
|
38
42
|
post({ orig, hooked, result, name, funcKey }) {
|
|
39
|
-
const sourceContext =
|
|
43
|
+
const sourceContext = getSourceContext(SOURCE);
|
|
40
44
|
const inputType = InputType.URL_PARAMETER;
|
|
41
45
|
|
|
42
|
-
if (!sourceContext)
|
|
43
|
-
logger.error({ inputType, funcKey }, 'unable to handle source. Missing `sourceContext`');
|
|
44
|
-
return;
|
|
45
|
-
}
|
|
46
|
+
if (!sourceContext) return;
|
|
46
47
|
|
|
47
48
|
if (sourceContext.parsedParams) {
|
|
48
49
|
logger.trace({ inputType, funcKey }, 'values already tracked');
|
|
@@ -97,12 +97,12 @@ describe('assess dataflow sources koa-router and @koa/router', function () {
|
|
|
97
97
|
});
|
|
98
98
|
});
|
|
99
99
|
|
|
100
|
-
it(`[${router}] does not call \`.handle\` when there is no context`, function () {
|
|
100
|
+
it(`[${router}] does not call \`.handle\` when there is no assess policy in request context`, function () {
|
|
101
101
|
const paramsFn = getParamsFn(router);
|
|
102
102
|
|
|
103
103
|
simulateRequestScope(() => {
|
|
104
104
|
paramsFn(params);
|
|
105
|
-
}, {});
|
|
105
|
+
}, { assess: { policy: null } });
|
|
106
106
|
|
|
107
107
|
expect(sources.handle).not.to.have.been.called;
|
|
108
108
|
});
|
|
@@ -16,6 +16,8 @@
|
|
|
16
16
|
'use strict';
|
|
17
17
|
|
|
18
18
|
const { InputType } = require('@contrast/common');
|
|
19
|
+
const { InstrumentationType: { SOURCE } } = require('../../../../constants');
|
|
20
|
+
|
|
19
21
|
const { patchType } = require('../../common');
|
|
20
22
|
|
|
21
23
|
const inputType = InputType.QUERYSTRING;
|
|
@@ -30,7 +32,10 @@ module.exports = (core) => {
|
|
|
30
32
|
logger,
|
|
31
33
|
depHooks,
|
|
32
34
|
patcher,
|
|
33
|
-
assess: {
|
|
35
|
+
assess: {
|
|
36
|
+
getSourceContext,
|
|
37
|
+
dataflow: { sources }
|
|
38
|
+
},
|
|
34
39
|
} = core;
|
|
35
40
|
|
|
36
41
|
/**
|
|
@@ -40,10 +45,9 @@ module.exports = (core) => {
|
|
|
40
45
|
depHooks.resolve({ name: 'koa', version: '>=2.3.0' }, (Koa) => {
|
|
41
46
|
const createMiddleware = ({ name, funcKey }) => {
|
|
42
47
|
const contrastStartMiddleware = function contrastStartMiddleware(ctx, next) {
|
|
43
|
-
const sourceContext =
|
|
48
|
+
const sourceContext = getSourceContext(SOURCE);
|
|
44
49
|
|
|
45
50
|
if (!sourceContext) {
|
|
46
|
-
logger.error({ inputType, funcKey }, 'unable to handle Koa source. Missing `sourceContext`');
|
|
47
51
|
return next();
|
|
48
52
|
}
|
|
49
53
|
|
|
@@ -113,7 +113,7 @@ describe('assess dataflow koa v2.x', function () {
|
|
|
113
113
|
|
|
114
114
|
simulateRequestScope(() => {
|
|
115
115
|
contrastStartMiddleware({ query }, nextStub);
|
|
116
|
-
}, {});
|
|
116
|
+
}, { assess: { policy: null } });
|
|
117
117
|
|
|
118
118
|
expect(nextStub).to.have.been.calledOnce;
|
|
119
119
|
expect(sources.handle).not.to.have.been.called;
|