@contrast/agent-bundle 5.46.0 → 5.47.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/README.md +1 -1
- package/node_modules/@contrast/agent/README.md +1 -1
- package/node_modules/@contrast/agent/package.json +12 -12
- package/node_modules/@contrast/agentify/package.json +15 -15
- package/node_modules/@contrast/architecture-components/package.json +5 -5
- package/node_modules/@contrast/assess/lib/{session-configuration → configuration-analysis}/common.js +1 -1
- package/node_modules/@contrast/assess/lib/{session-configuration → configuration-analysis}/handlers.js +23 -10
- package/node_modules/@contrast/assess/lib/{session-configuration → configuration-analysis}/index.js +6 -4
- package/node_modules/@contrast/assess/lib/configuration-analysis/install/apollo-server.js +92 -0
- package/node_modules/@contrast/assess/lib/{session-configuration → configuration-analysis}/install/express-session.js +2 -2
- package/node_modules/@contrast/assess/lib/{session-configuration → configuration-analysis}/install/fastify-cookie.js +2 -2
- package/node_modules/@contrast/assess/lib/configuration-analysis/install/graphql-yoga.js +90 -0
- package/node_modules/@contrast/assess/lib/{session-configuration → configuration-analysis}/install/hapi.js +2 -2
- package/node_modules/@contrast/assess/lib/{session-configuration → configuration-analysis}/install/koa.js +3 -3
- package/node_modules/@contrast/assess/lib/dataflow/propagation/install/string/substring.js +1 -1
- package/node_modules/@contrast/assess/lib/dataflow/sources/handler.js +9 -2
- package/node_modules/@contrast/assess/lib/dataflow/sources/index.js +2 -0
- package/node_modules/@contrast/assess/lib/dataflow/sources/install/fastify-websocket.js +63 -0
- package/node_modules/@contrast/assess/lib/dataflow/sources/install/http.js +42 -38
- package/node_modules/@contrast/assess/lib/dataflow/sources/install/koa/index.js +1 -1
- package/node_modules/@contrast/assess/lib/dataflow/sources/install/koa/koa-bodyparsers.js +76 -48
- package/node_modules/@contrast/assess/lib/dataflow/sources/install/koa/koa-multer.js +1 -1
- package/node_modules/@contrast/assess/lib/dataflow/sources/install/koa/koa-routers.js +2 -2
- package/node_modules/@contrast/assess/lib/dataflow/sources/install/koa/{koa2.js → koa.js} +3 -3
- package/node_modules/@contrast/assess/lib/dataflow/sources/install/socket.io.js +80 -0
- package/node_modules/@contrast/assess/lib/index.d.ts +4 -3
- package/node_modules/@contrast/assess/lib/index.js +1 -1
- package/node_modules/@contrast/assess/lib/policy.js +2 -2
- package/node_modules/@contrast/assess/package.json +12 -12
- package/node_modules/@contrast/common/lib/constants.d.ts +12 -4
- package/node_modules/@contrast/common/lib/constants.js +16 -7
- package/node_modules/@contrast/common/lib/types.d.ts +5 -1
- package/node_modules/@contrast/common/package.json +1 -1
- package/node_modules/@contrast/config/lib/common.js +1 -0
- package/node_modules/@contrast/config/lib/options.js +7 -1
- package/node_modules/@contrast/config/package.json +3 -3
- package/node_modules/@contrast/core/package.json +5 -5
- package/node_modules/@contrast/deadzones/package.json +5 -5
- package/node_modules/@contrast/dep-hooks/lib/package-finder.d.ts +2 -2
- package/node_modules/@contrast/dep-hooks/lib/package-finder.js +3 -2
- package/node_modules/@contrast/dep-hooks/package.json +4 -4
- package/node_modules/@contrast/esm-hooks/README.md +2 -2
- package/node_modules/@contrast/esm-hooks/package.json +6 -6
- package/node_modules/@contrast/instrumentation/package.json +5 -5
- package/node_modules/@contrast/library-analysis/lib/install/library-reporting/dep.json +149 -149
- package/node_modules/@contrast/library-analysis/lib/install/library-reporting/index.js +2 -11
- package/node_modules/@contrast/library-analysis/lib/install/library-reporting/utils.js +2 -0
- package/node_modules/@contrast/library-analysis/lib/install/library-usage/index.js +3 -1
- package/node_modules/@contrast/library-analysis/lib/util.js +0 -2
- package/node_modules/@contrast/library-analysis/package.json +4 -4
- package/node_modules/@contrast/logger/package.json +3 -3
- package/node_modules/@contrast/metrics/package.json +6 -6
- package/node_modules/@contrast/patcher/package.json +2 -2
- package/node_modules/@contrast/protect/lib/error-handlers/index.js +1 -1
- package/node_modules/@contrast/protect/lib/error-handlers/install/{koa2.js → koa.js} +4 -4
- package/node_modules/@contrast/protect/lib/index.d.ts +1 -1
- package/node_modules/@contrast/protect/lib/input-analysis/index.js +2 -3
- package/node_modules/@contrast/protect/lib/input-analysis/install/koa-bodyparsers.js +92 -0
- package/node_modules/@contrast/protect/lib/input-analysis/install/{koa2.js → koa.js} +5 -5
- package/node_modules/@contrast/protect/package.json +11 -11
- package/node_modules/@contrast/reporter/lib/reporters/contrast-ui/endpoints/application-activity/translations.js +6 -10
- package/node_modules/@contrast/reporter/lib/reporters/contrast-ui/endpoints/routes-observed.js +4 -0
- package/node_modules/@contrast/reporter/lib/reporters/contrast-ui/endpoints/traces/index.d.ts +1 -1
- package/node_modules/@contrast/reporter/lib/reporters/contrast-ui/endpoints/traces/index.js +1 -1
- package/node_modules/@contrast/reporter/lib/reporters/contrast-ui/endpoints/traces/translations.d.ts +1 -1
- package/node_modules/@contrast/reporter/lib/reporters/contrast-ui/endpoints/traces/translations.js +22 -9
- package/node_modules/@contrast/reporter/lib/reporters/file.js +1 -1
- package/node_modules/@contrast/reporter/package.json +6 -6
- package/node_modules/@contrast/rewriter/package.json +5 -5
- package/node_modules/@contrast/route-coverage/lib/index.d.ts +0 -2
- package/node_modules/@contrast/route-coverage/lib/index.js +10 -1
- package/node_modules/@contrast/route-coverage/lib/install/express/express5.js +16 -1
- package/node_modules/@contrast/route-coverage/lib/install/fastify.js +25 -15
- package/node_modules/@contrast/route-coverage/lib/install/graphql.js +6 -1
- package/node_modules/@contrast/route-coverage/lib/install/koa.js +1 -1
- package/node_modules/@contrast/route-coverage/lib/install/socket.io.js +127 -0
- package/node_modules/@contrast/route-coverage/package.json +8 -8
- package/node_modules/@contrast/scopes/package.json +5 -5
- package/node_modules/@contrast/sec-obs/package.json +9 -9
- package/node_modules/@contrast/sources/lib/index.js +65 -22
- package/node_modules/@contrast/sources/lib/index.test.js +78 -33
- package/node_modules/@contrast/sources/lib/source-info.js +1 -10
- package/node_modules/@contrast/sources/package.json +3 -3
- package/node_modules/@contrast/telemetry/package.json +5 -5
- package/node_modules/@types/node/README.md +1 -1
- package/node_modules/@types/node/assert.d.ts +37 -2
- package/node_modules/@types/node/buffer.buffer.d.ts +9 -0
- package/node_modules/@types/node/buffer.d.ts +8 -4
- package/node_modules/@types/node/child_process.d.ts +65 -42
- package/node_modules/@types/node/cluster.d.ts +4 -5
- package/node_modules/@types/node/crypto.d.ts +1079 -338
- package/node_modules/@types/node/dgram.d.ts +9 -8
- package/node_modules/@types/node/diagnostics_channel.d.ts +0 -2
- package/node_modules/@types/node/dns.d.ts +1 -1
- package/node_modules/@types/node/events.d.ts +1 -1
- package/node_modules/@types/node/fs/promises.d.ts +39 -21
- package/node_modules/@types/node/fs.d.ts +104 -87
- package/node_modules/@types/node/globals.d.ts +2 -0
- package/node_modules/@types/node/globals.typedarray.d.ts +19 -0
- package/node_modules/@types/node/http.d.ts +66 -27
- package/node_modules/@types/node/http2.d.ts +178 -52
- package/node_modules/@types/node/https.d.ts +91 -62
- package/node_modules/@types/node/index.d.ts +2 -0
- package/node_modules/@types/node/inspector.d.ts +24 -0
- package/node_modules/@types/node/inspector.generated.d.ts +181 -0
- package/node_modules/@types/node/net.d.ts +12 -11
- package/node_modules/@types/node/os.d.ts +14 -3
- package/node_modules/@types/node/package.json +3 -3
- package/node_modules/@types/node/perf_hooks.d.ts +6 -8
- package/node_modules/@types/node/process.d.ts +12 -23
- package/node_modules/@types/node/readline/promises.d.ts +1 -1
- package/node_modules/@types/node/sea.d.ts +9 -0
- package/node_modules/@types/node/sqlite.d.ts +119 -10
- package/node_modules/@types/node/stream/consumers.d.ts +2 -2
- package/node_modules/@types/node/stream/web.d.ts +6 -55
- package/node_modules/@types/node/stream.d.ts +38 -23
- package/node_modules/@types/node/string_decoder.d.ts +2 -2
- package/node_modules/@types/node/test.d.ts +29 -3
- package/node_modules/@types/node/tls.d.ts +90 -66
- package/node_modules/@types/node/ts5.6/buffer.buffer.d.ts +10 -2
- package/node_modules/@types/node/ts5.6/globals.typedarray.d.ts +16 -0
- package/node_modules/@types/node/ts5.6/index.d.ts +2 -0
- package/node_modules/@types/node/ts5.7/index.d.ts +2 -0
- package/node_modules/@types/node/url.d.ts +2 -2
- package/node_modules/@types/node/util.d.ts +12 -3
- package/node_modules/@types/node/v8.d.ts +38 -5
- package/node_modules/@types/node/vm.d.ts +169 -88
- package/node_modules/@types/node/wasi.d.ts +1 -1
- package/node_modules/@types/node/web-globals/crypto.d.ts +32 -0
- package/node_modules/@types/node/web-globals/streams.d.ts +22 -0
- package/node_modules/@types/node/worker_threads.d.ts +76 -1
- package/node_modules/@types/node/zlib.d.ts +25 -24
- package/node_modules/axios/CHANGELOG.md +403 -357
- package/node_modules/axios/README.md +80 -49
- package/node_modules/axios/dist/axios.js +121 -46
- package/node_modules/axios/dist/axios.js.map +1 -1
- package/node_modules/axios/dist/axios.min.js +2 -2
- package/node_modules/axios/dist/axios.min.js.map +1 -1
- package/node_modules/axios/dist/browser/axios.cjs +126 -57
- package/node_modules/axios/dist/browser/axios.cjs.map +1 -1
- package/node_modules/axios/dist/esm/axios.js +126 -57
- package/node_modules/axios/dist/esm/axios.js.map +1 -1
- package/node_modules/axios/dist/esm/axios.min.js +2 -2
- package/node_modules/axios/dist/esm/axios.min.js.map +1 -1
- package/node_modules/axios/dist/node/axios.cjs +346 -97
- package/node_modules/axios/dist/node/axios.cjs.map +1 -1
- package/node_modules/axios/index.d.cts +4 -0
- package/node_modules/axios/index.d.ts +4 -0
- package/node_modules/axios/lib/adapters/adapters.js +85 -40
- package/node_modules/axios/lib/adapters/fetch.js +1 -1
- package/node_modules/axios/lib/adapters/http.js +220 -42
- package/node_modules/axios/lib/core/InterceptorManager.js +1 -1
- package/node_modules/axios/lib/core/mergeConfig.js +4 -4
- package/node_modules/axios/lib/env/data.js +1 -1
- package/node_modules/axios/lib/helpers/HttpStatusCode.js +6 -0
- package/node_modules/axios/lib/helpers/bind.js +7 -0
- package/node_modules/axios/lib/helpers/cookies.js +24 -13
- package/node_modules/axios/package.json +9 -4
- package/node_modules/detect-libc/lib/filesystem.js +1 -1
- package/node_modules/detect-libc/package.json +3 -1
- package/node_modules/node-abi/abi_registry.json +12 -2
- package/node_modules/node-abi/package.json +3 -6
- package/node_modules/semver/classes/range.js +1 -0
- package/node_modules/semver/classes/semver.js +19 -5
- package/node_modules/semver/internal/identifiers.js +4 -0
- package/node_modules/semver/package.json +3 -3
- package/node_modules/undici-types/agent.d.ts +1 -0
- package/node_modules/undici-types/diagnostics-channel.d.ts +0 -1
- package/node_modules/undici-types/errors.d.ts +5 -15
- package/node_modules/undici-types/eventsource.d.ts +6 -1
- package/node_modules/undici-types/index.d.ts +4 -1
- package/node_modules/undici-types/interceptors.d.ts +5 -0
- package/node_modules/undici-types/package.json +1 -1
- package/node_modules/undici-types/snapshot-agent.d.ts +5 -3
- package/node_modules/undici-types/webidl.d.ts +82 -21
- package/package.json +3 -3
- package/node_modules/@contrast/protect/lib/input-analysis/install/koa-body5.js +0 -63
- package/node_modules/@contrast/protect/lib/input-analysis/install/koa-bodyparser4.js +0 -64
|
@@ -15,7 +15,11 @@
|
|
|
15
15
|
// @ts-check
|
|
16
16
|
'use strict';
|
|
17
17
|
|
|
18
|
-
const {
|
|
18
|
+
const {
|
|
19
|
+
callChildComponentMethodsSync,
|
|
20
|
+
Event,
|
|
21
|
+
RouteType,
|
|
22
|
+
} = require('@contrast/common');
|
|
19
23
|
|
|
20
24
|
/**
|
|
21
25
|
* @param {import('.').Core & {
|
|
@@ -41,6 +45,8 @@ module.exports = function init(core) {
|
|
|
41
45
|
const id = routeIdentifier(info.method, info.signature);
|
|
42
46
|
if (routeInfo.get(id)) return;
|
|
43
47
|
|
|
48
|
+
if (!info.type) info.type = RouteType.HTTP;
|
|
49
|
+
|
|
44
50
|
logger.trace({ info }, 'Discovered new route:');
|
|
45
51
|
routeInfo.set(id, info);
|
|
46
52
|
},
|
|
@@ -100,9 +106,11 @@ module.exports = function init(core) {
|
|
|
100
106
|
|
|
101
107
|
recentlyObserved.add(route.signature);
|
|
102
108
|
logger.trace({ info }, 'Observed route:');
|
|
109
|
+
|
|
103
110
|
// these events need source correlation
|
|
104
111
|
messages.emit(Event.ROUTE_COVERAGE_OBSERVATION, {
|
|
105
112
|
...route,
|
|
113
|
+
type: info.type ?? route.type ?? RouteType.HTTP,
|
|
106
114
|
sourceInfo: store?.sourceInfo,
|
|
107
115
|
});
|
|
108
116
|
},
|
|
@@ -119,6 +127,7 @@ module.exports = function init(core) {
|
|
|
119
127
|
require('./install/hapi')(core);
|
|
120
128
|
require('./install/koa')(core);
|
|
121
129
|
require('./install/restify')(core);
|
|
130
|
+
core.initComponentSync(require('./install/socket.io'));
|
|
122
131
|
|
|
123
132
|
messages.on(Event.SERVER_LISTENING, () => {
|
|
124
133
|
// we wait to report in timers event loop phase, this way we can
|
|
@@ -20,6 +20,7 @@ const {
|
|
|
20
20
|
set,
|
|
21
21
|
isString,
|
|
22
22
|
Event,
|
|
23
|
+
RouteType,
|
|
23
24
|
primordials: {
|
|
24
25
|
ArrayPrototypeJoin,
|
|
25
26
|
StringPrototypeSubstring,
|
|
@@ -310,12 +311,14 @@ class ExpressInstrumentation {
|
|
|
310
311
|
const method = StringPrototypeToLowerCase.call(data.args[0].method || '');
|
|
311
312
|
const template = ArrayPrototypeJoin.call(store.templateSegments, '') || '/';
|
|
312
313
|
|
|
314
|
+
|
|
313
315
|
if (instance[kMetaKey]?.observables?.[template]) {
|
|
314
316
|
self.observe({
|
|
315
317
|
url: data.args[0].originalUrl,
|
|
316
318
|
normalizedUrl: template,
|
|
317
319
|
method,
|
|
318
320
|
signature: instance[kMetaKey].observables[template],
|
|
321
|
+
type: instance[kMetaKey].routeType,
|
|
319
322
|
});
|
|
320
323
|
} else {
|
|
321
324
|
core.logger.error({
|
|
@@ -335,7 +338,7 @@ class ExpressInstrumentation {
|
|
|
335
338
|
}
|
|
336
339
|
|
|
337
340
|
discover(info) {
|
|
338
|
-
const { method, observables } = info;
|
|
341
|
+
const { method, observables, routeType } = info;
|
|
339
342
|
if (!method || !observables) return;
|
|
340
343
|
|
|
341
344
|
for (const [normalizedUrl, signature] of Object.entries(observables)) {
|
|
@@ -344,6 +347,7 @@ class ExpressInstrumentation {
|
|
|
344
347
|
normalizedUrl,
|
|
345
348
|
method,
|
|
346
349
|
signature,
|
|
350
|
+
type: routeType,
|
|
347
351
|
framework: 'express',
|
|
348
352
|
});
|
|
349
353
|
}
|
|
@@ -383,11 +387,22 @@ class ExpressInstrumentation {
|
|
|
383
387
|
// mounted routers aren't discoverable since they themselves don't
|
|
384
388
|
// represent routes, they dispatch to sub routers/route handlers.
|
|
385
389
|
if (value.name != 'router' && value.handle?.name != 'router') {
|
|
390
|
+
let routeType;
|
|
391
|
+
if (value[kMetaKey]?.method == 'use') {
|
|
392
|
+
// if the handler is registered via `use` method, there are no
|
|
393
|
+
// associated HTTP methods. this use case is considered middleware.
|
|
394
|
+
if (!this.core.config.getEffectiveValue('assess.report_middleware_routes')) return;
|
|
395
|
+
routeType = RouteType.MIDDLEWARE;
|
|
396
|
+
} else {
|
|
397
|
+
routeType = RouteType.HTTP;
|
|
398
|
+
}
|
|
399
|
+
|
|
386
400
|
// `value` is a terminal Layer with observable signatures.
|
|
387
401
|
// emit discovery after appending metadata.
|
|
388
402
|
if (value[kMetaKey]) {
|
|
389
403
|
const observables = this.generateObservables(metas, value.handle);
|
|
390
404
|
if (observables) {
|
|
405
|
+
value[kMetaKey].routeType = routeType;
|
|
391
406
|
if (!value[kMetaKey].observables) {
|
|
392
407
|
value[kMetaKey].observables = observables;
|
|
393
408
|
} else {
|
|
@@ -15,7 +15,10 @@
|
|
|
15
15
|
'use strict';
|
|
16
16
|
|
|
17
17
|
const { getFastifyMethods } = require('../utils/methods');
|
|
18
|
-
const {
|
|
18
|
+
const {
|
|
19
|
+
primordials: { StringPrototypeToLowerCase, StringPrototypeSplit },
|
|
20
|
+
RouteType,
|
|
21
|
+
} = require('@contrast/common');
|
|
19
22
|
const { patchType } = require('./../utils/route-info');
|
|
20
23
|
|
|
21
24
|
// Spec: https://contrast.atlassian.net/wiki/spaces/NOD/pages/3454861621/Node.js+Agent+Route+Signatures#Fastify
|
|
@@ -35,7 +38,7 @@ module.exports = function init(core) {
|
|
|
35
38
|
return route?.[kRoutePrefix];
|
|
36
39
|
}
|
|
37
40
|
|
|
38
|
-
function createRouteInfo(method, url, fullyDeclared) {
|
|
41
|
+
function createRouteInfo(method, url, fullyDeclared, type) {
|
|
39
42
|
method = StringPrototypeToLowerCase.call(method);
|
|
40
43
|
|
|
41
44
|
const signature = fullyDeclared
|
|
@@ -47,6 +50,7 @@ module.exports = function init(core) {
|
|
|
47
50
|
url,
|
|
48
51
|
method,
|
|
49
52
|
normalizedUrl: url,
|
|
53
|
+
type,
|
|
50
54
|
framework: 'fastify'
|
|
51
55
|
};
|
|
52
56
|
return routeInfo;
|
|
@@ -54,14 +58,18 @@ module.exports = function init(core) {
|
|
|
54
58
|
|
|
55
59
|
function patchHandler(route, handle, routeInfo) {
|
|
56
60
|
const pre = ({ args }) => {
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
61
|
+
let req, type;
|
|
62
|
+
if (args[0]?.constructor?.name == 'WebSocket') {
|
|
63
|
+
req = args[1];
|
|
64
|
+
type = RouteType.MESSAGE_BROKER;
|
|
65
|
+
} else {
|
|
66
|
+
req = args[0];
|
|
67
|
+
type = RouteType.HTTP;
|
|
68
|
+
}
|
|
62
69
|
const method = StringPrototypeToLowerCase.call(req.raw?.method);
|
|
63
70
|
const [url] = StringPrototypeSplit.call(req.url, /\?/);
|
|
64
|
-
|
|
71
|
+
|
|
72
|
+
routeCoverage.observe({ ...routeInfo, method, type, url });
|
|
65
73
|
};
|
|
66
74
|
|
|
67
75
|
const name = `fastify.route.${handle}`;
|
|
@@ -81,24 +89,26 @@ module.exports = function init(core) {
|
|
|
81
89
|
}
|
|
82
90
|
}
|
|
83
91
|
|
|
84
|
-
function discoverAndPatch(method, path,
|
|
92
|
+
function discoverAndPatch(method, path, routeObj, handle, methods, fullyDeclared) {
|
|
93
|
+
const type = routeObj?.options?.websocket ? RouteType.MESSAGE_BROKER : RouteType.HTTP;
|
|
94
|
+
|
|
85
95
|
if (Array.isArray(method)) {
|
|
86
96
|
// If all valid methods are included in `method` then .all shorthand was most likely used
|
|
87
97
|
if (methods.every(m => method.includes(m))) {
|
|
88
|
-
const routeInfo = createRouteInfo('all', path, fullyDeclared);
|
|
98
|
+
const routeInfo = createRouteInfo('all', path, fullyDeclared, type);
|
|
89
99
|
routeCoverage.discover(routeInfo);
|
|
90
|
-
patchHandler(
|
|
100
|
+
patchHandler(routeObj, handle, routeInfo);
|
|
91
101
|
} else {
|
|
92
102
|
method.forEach((verb) => {
|
|
93
|
-
const routeInfo = createRouteInfo(verb, path, fullyDeclared);
|
|
103
|
+
const routeInfo = createRouteInfo(verb, path, fullyDeclared, type);
|
|
94
104
|
routeCoverage.discover(routeInfo);
|
|
95
|
-
patchHandler(
|
|
105
|
+
patchHandler(routeObj, handle, routeInfo);
|
|
96
106
|
});
|
|
97
107
|
}
|
|
98
108
|
} else {
|
|
99
|
-
const routeInfo = createRouteInfo(method, path, fullyDeclared);
|
|
109
|
+
const routeInfo = createRouteInfo(method, path, fullyDeclared, type);
|
|
100
110
|
routeCoverage.discover(routeInfo);
|
|
101
|
-
patchHandler(
|
|
111
|
+
patchHandler(routeObj, handle, routeInfo);
|
|
102
112
|
}
|
|
103
113
|
}
|
|
104
114
|
|
|
@@ -14,7 +14,10 @@
|
|
|
14
14
|
*/
|
|
15
15
|
'use strict';
|
|
16
16
|
|
|
17
|
-
const {
|
|
17
|
+
const {
|
|
18
|
+
RouteType,
|
|
19
|
+
primordials: { ArrayPrototypeJoin },
|
|
20
|
+
} = require('@contrast/common');
|
|
18
21
|
const { patchType } = require('./../utils/route-info');
|
|
19
22
|
|
|
20
23
|
module.exports = function init(core) {
|
|
@@ -61,6 +64,7 @@ module.exports = function init(core) {
|
|
|
61
64
|
method,
|
|
62
65
|
normalizedUrl,
|
|
63
66
|
signature,
|
|
67
|
+
type: RouteType.HTTP, // todo: extend existing types
|
|
64
68
|
framework: 'graphql',
|
|
65
69
|
});
|
|
66
70
|
});
|
|
@@ -77,6 +81,7 @@ module.exports = function init(core) {
|
|
|
77
81
|
method: store.sourceInfo?.method,
|
|
78
82
|
normalizedUrl,
|
|
79
83
|
signature,
|
|
84
|
+
type: RouteType.HTTP, // todo: extend existing types
|
|
80
85
|
url: normalizedUrl,
|
|
81
86
|
framework: 'graphql',
|
|
82
87
|
});
|
|
@@ -36,7 +36,7 @@ module.exports = function init(core) {
|
|
|
36
36
|
|
|
37
37
|
return core.routeCoverage.koa = {
|
|
38
38
|
install() {
|
|
39
|
-
depHooks.resolve({ name: 'koa', version: '>=2.3.0 <
|
|
39
|
+
depHooks.resolve({ name: 'koa', version: '>=2.3.0 <4' }, (Koa) => {
|
|
40
40
|
// Koa uses its own routing library @koa/router to define routes before
|
|
41
41
|
// mounting them on the app with .use so instrumenting use and traversing
|
|
42
42
|
// the constructed routes is the more technically correct approach than
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright: 2025 Contrast Security, Inc
|
|
3
|
+
* Contact: support@contrastsecurity.com
|
|
4
|
+
* License: Commercial
|
|
5
|
+
|
|
6
|
+
* NOTICE: This Software and the patented inventions embodied within may only be
|
|
7
|
+
* used as part of Contrast Security’s commercial offerings. Even though it is
|
|
8
|
+
* made available through public repositories, use of this Software is subject to
|
|
9
|
+
* the applicable End User Licensing Agreement found at
|
|
10
|
+
* https://www.contrastsecurity.com/enduser-terms-0317a or as otherwise agreed
|
|
11
|
+
* between Contrast Security and the End User. The Software may not be reverse
|
|
12
|
+
* engineered, modified, repackaged, sold, redistributed or otherwise used in a
|
|
13
|
+
* way not consistent with the End User License Agreement.
|
|
14
|
+
*/
|
|
15
|
+
'use strict';
|
|
16
|
+
|
|
17
|
+
const { set, RouteType, primordials } = require('@contrast/common');
|
|
18
|
+
const Core = require('@contrast/core/lib/ioc/core');
|
|
19
|
+
const { patchType } = require('../utils/route-info');
|
|
20
|
+
|
|
21
|
+
const COMPONENT_NAME = 'routeCoverage.socketio';
|
|
22
|
+
const FRAMEWORK = 'socket.io';
|
|
23
|
+
const kServerMountPath = Symbol('cs:socket.io.path');
|
|
24
|
+
const kServerRouteSignature = Symbol('cs:socket.io.route-signature');
|
|
25
|
+
|
|
26
|
+
module.exports = Core.makeComponent({
|
|
27
|
+
name: COMPONENT_NAME,
|
|
28
|
+
factory: (core) => new SocketIORouteCoverage(core),
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
class SocketIORouteCoverage {
|
|
32
|
+
constructor(core) {
|
|
33
|
+
Object.defineProperty(this, 'core', { value: core });
|
|
34
|
+
set(core, COMPONENT_NAME, this);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
makePath(mountPath) {
|
|
38
|
+
// we append trailing "/" since that's part of socket.io protocol
|
|
39
|
+
return mountPath.endsWith('/') ? mountPath : `${mountPath}/`;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
makeSignature(mountPath) {
|
|
43
|
+
return `Socket.IO ${mountPath}`;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
install() {
|
|
47
|
+
const self = this;
|
|
48
|
+
const {
|
|
49
|
+
depHooks,
|
|
50
|
+
patcher,
|
|
51
|
+
routeCoverage,
|
|
52
|
+
} = this.core;
|
|
53
|
+
|
|
54
|
+
depHooks.resolve(
|
|
55
|
+
{ name: 'socket.io', version: '4' },
|
|
56
|
+
/** @param {import('socket.io-4')} xport the exported socket.io module */
|
|
57
|
+
(xport) => {
|
|
58
|
+
patcher.patch(xport.Server.prototype, 'initEngine', {
|
|
59
|
+
name: 'socket.io.Server.prototype.initEngine',
|
|
60
|
+
patchType,
|
|
61
|
+
post(data) {
|
|
62
|
+
if (!this._path) return;
|
|
63
|
+
const [httpServer] = data.args;
|
|
64
|
+
const path = self.makePath(this._path);
|
|
65
|
+
const signature = self.makeSignature(path);
|
|
66
|
+
|
|
67
|
+
this.eio[kServerMountPath] = path;
|
|
68
|
+
this.eio[kServerRouteSignature] = signature;
|
|
69
|
+
|
|
70
|
+
routeCoverage.discover({
|
|
71
|
+
framework: FRAMEWORK,
|
|
72
|
+
signature,
|
|
73
|
+
method: 'all',
|
|
74
|
+
normalizedUri: path,
|
|
75
|
+
type: RouteType.MESSAGE_BROKER,
|
|
76
|
+
url: path,
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
// handle observation for HTTP polling; this doesn't emit when upgrading to ws://
|
|
80
|
+
httpServer.on(
|
|
81
|
+
'request',
|
|
82
|
+
/** @param {import('http').IncomingMessage} req */
|
|
83
|
+
(req /*, res */) => {
|
|
84
|
+
if (req.url?.startsWith?.(path)) {
|
|
85
|
+
routeCoverage.observe({
|
|
86
|
+
framework: FRAMEWORK,
|
|
87
|
+
method: primordials.StringPrototypeToLowerCase.call(req.method),
|
|
88
|
+
normalizedUrl: path,
|
|
89
|
+
signature,
|
|
90
|
+
type: RouteType.MESSAGE_BROKER,
|
|
91
|
+
url: path,
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
);
|
|
99
|
+
|
|
100
|
+
// this is to handle observations for websocket upgrades; 1 upgrade request counts as single observation
|
|
101
|
+
depHooks.resolve(
|
|
102
|
+
{ name: 'engine.io', version: '6' },
|
|
103
|
+
/** @param {import('engine.io')} xport the exported engine.io module */
|
|
104
|
+
(xport) => {
|
|
105
|
+
patcher.patch(xport.Server.prototype, 'onWebSocket', {
|
|
106
|
+
name: 'engine.io.Server.prototype.onWebSocket',
|
|
107
|
+
patchType,
|
|
108
|
+
pre(data) {
|
|
109
|
+
const eioServer = this;
|
|
110
|
+
const [req] = data.args;
|
|
111
|
+
|
|
112
|
+
if (!eioServer[kServerMountPath] || !eioServer[kServerRouteSignature]) return;
|
|
113
|
+
|
|
114
|
+
routeCoverage.observe({
|
|
115
|
+
framework: FRAMEWORK,
|
|
116
|
+
method: req.method,
|
|
117
|
+
normalizedUrl: eioServer[kServerMountPath],
|
|
118
|
+
signature: eioServer[kServerRouteSignature],
|
|
119
|
+
type: RouteType.MESSAGE_BROKER,
|
|
120
|
+
url: eioServer[kServerMountPath],
|
|
121
|
+
});
|
|
122
|
+
},
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@contrast/route-coverage",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.51.0",
|
|
4
4
|
"description": "Handles route discovery and observation",
|
|
5
5
|
"license": "SEE LICENSE IN LICENSE",
|
|
6
6
|
"author": "Contrast Security <nodejs@contrastsecurity.com> (https://www.contrastsecurity.com)",
|
|
@@ -20,14 +20,14 @@
|
|
|
20
20
|
"test": "bash ../scripts/test.sh"
|
|
21
21
|
},
|
|
22
22
|
"dependencies": {
|
|
23
|
-
"@contrast/common": "1.
|
|
24
|
-
"@contrast/config": "1.
|
|
25
|
-
"@contrast/core": "1.
|
|
26
|
-
"@contrast/dep-hooks": "1.
|
|
23
|
+
"@contrast/common": "1.38.0",
|
|
24
|
+
"@contrast/config": "1.54.0",
|
|
25
|
+
"@contrast/core": "1.59.0",
|
|
26
|
+
"@contrast/dep-hooks": "1.28.0",
|
|
27
27
|
"@contrast/fn-inspect": "^5.0.2",
|
|
28
|
-
"@contrast/logger": "1.
|
|
29
|
-
"@contrast/patcher": "1.
|
|
30
|
-
"@contrast/scopes": "1.
|
|
28
|
+
"@contrast/logger": "1.32.0",
|
|
29
|
+
"@contrast/patcher": "1.31.0",
|
|
30
|
+
"@contrast/scopes": "1.29.0",
|
|
31
31
|
"semver": "^7.6.0"
|
|
32
32
|
}
|
|
33
33
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@contrast/scopes",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.29.0",
|
|
4
4
|
"description": "Handles AsyncLocalStorage scopes",
|
|
5
5
|
"license": "SEE LICENSE IN LICENSE",
|
|
6
6
|
"author": "Contrast Security <nodejs@contrastsecurity.com> (https://www.contrastsecurity.com)",
|
|
@@ -20,9 +20,9 @@
|
|
|
20
20
|
"test": "bash ../scripts/test.sh"
|
|
21
21
|
},
|
|
22
22
|
"dependencies": {
|
|
23
|
-
"@contrast/core": "1.
|
|
24
|
-
"@contrast/dep-hooks": "1.
|
|
25
|
-
"@contrast/logger": "1.
|
|
26
|
-
"@contrast/patcher": "1.
|
|
23
|
+
"@contrast/core": "1.59.0",
|
|
24
|
+
"@contrast/dep-hooks": "1.28.0",
|
|
25
|
+
"@contrast/logger": "1.32.0",
|
|
26
|
+
"@contrast/patcher": "1.31.0"
|
|
27
27
|
}
|
|
28
28
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@contrast/sec-obs",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"description": "Contrast service providing framework-agnostic Observability support",
|
|
5
5
|
"license": "SEE LICENSE IN LICENSE",
|
|
6
6
|
"author": "Contrast Security <nodejs@contrastsecurity.com> (https://www.contrastsecurity.com)",
|
|
@@ -17,14 +17,14 @@
|
|
|
17
17
|
"test": "bash ../scripts/test.sh"
|
|
18
18
|
},
|
|
19
19
|
"dependencies": {
|
|
20
|
-
"@contrast/common": "1.
|
|
21
|
-
"@contrast/config": "1.
|
|
22
|
-
"@contrast/core": "1.
|
|
23
|
-
"@contrast/dep-hooks": "1.
|
|
24
|
-
"@contrast/logger": "1.
|
|
25
|
-
"@contrast/patcher": "1.
|
|
26
|
-
"@contrast/rewriter": "1.
|
|
27
|
-
"@contrast/scopes": "1.
|
|
20
|
+
"@contrast/common": "1.38.0",
|
|
21
|
+
"@contrast/config": "1.54.0",
|
|
22
|
+
"@contrast/core": "1.59.0",
|
|
23
|
+
"@contrast/dep-hooks": "1.28.0",
|
|
24
|
+
"@contrast/logger": "1.32.0",
|
|
25
|
+
"@contrast/patcher": "1.31.0",
|
|
26
|
+
"@contrast/rewriter": "1.36.0",
|
|
27
|
+
"@contrast/scopes": "1.29.0",
|
|
28
28
|
"@opentelemetry/api": "^1.9.0",
|
|
29
29
|
"@opentelemetry/exporter-metrics-otlp-http": "^0.57.1",
|
|
30
30
|
"@opentelemetry/exporter-trace-otlp-http": "^0.57.1",
|
|
@@ -23,6 +23,11 @@ const NormalizedUriMapper = require('./normalized-uri-mapper');
|
|
|
23
23
|
const { HttpSourceInfo } = require('./source-info');
|
|
24
24
|
|
|
25
25
|
const componentName = 'sources';
|
|
26
|
+
const SourceType = {
|
|
27
|
+
HTTP: 'HTTP',
|
|
28
|
+
WEBSOCKET: 'WEBSOCKET',
|
|
29
|
+
};
|
|
30
|
+
|
|
26
31
|
|
|
27
32
|
module.exports = Core.makeComponent({
|
|
28
33
|
name: componentName,
|
|
@@ -48,20 +53,40 @@ class Sources {
|
|
|
48
53
|
const { _hooks, _normalizedUriMapper, core } = this;
|
|
49
54
|
|
|
50
55
|
return function (next, data) {
|
|
51
|
-
const { args: [event, req,
|
|
52
|
-
|
|
53
|
-
if (event
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
core.messages.emit(Event.SERVER_LISTENING, { type: serverType, server: data.obj });
|
|
59
|
-
}
|
|
56
|
+
const { args: [event, req, resOrSocket] } = data;
|
|
57
|
+
|
|
58
|
+
if (event === 'listening') {
|
|
59
|
+
// take a snapshot of Perf.all at this point. this will get logged
|
|
60
|
+
// at some point on the perf interval timer.
|
|
61
|
+
core.Perf.mark('listening');
|
|
62
|
+
core.messages.emit(Event.SERVER_LISTENING, { type: serverType, server: data.obj });
|
|
60
63
|
return next();
|
|
61
64
|
}
|
|
62
65
|
|
|
63
|
-
|
|
66
|
+
const isUpgrade = event === 'upgrade';
|
|
67
|
+
let protocol = serverType == 'http' ? 'http' : 'https';
|
|
68
|
+
|
|
69
|
+
if (isUpgrade) {
|
|
70
|
+
for (let i = 0; i < req.rawHeaders.length; i += 2) {
|
|
71
|
+
if (req.rawHeaders[i].toLowerCase?.() == 'upgrade') {
|
|
72
|
+
protocol = req.rawHeaders[i + 1]?.toLowerCase?.();
|
|
73
|
+
break;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// For HTTP servers we run the "request" and "upgrade" events in a source
|
|
79
|
+
// scope. We only support "websocket" upgrades currently, but this can be
|
|
80
|
+
// extended. Support for non-HTTP sources is expected and will require new
|
|
81
|
+
// instrumentation and possibly model alterations.
|
|
82
|
+
if (
|
|
83
|
+
event !== 'request' &&
|
|
84
|
+
(!isUpgrade || (isUpgrade && protocol !== 'websocket'))
|
|
85
|
+
) {
|
|
86
|
+
return next();
|
|
87
|
+
}
|
|
64
88
|
|
|
89
|
+
// websocket sources are http
|
|
65
90
|
const sourceInfo = new HttpSourceInfo({
|
|
66
91
|
serverType,
|
|
67
92
|
raw: req,
|
|
@@ -69,20 +94,38 @@ class Sources {
|
|
|
69
94
|
});
|
|
70
95
|
const store = { sourceInfo };
|
|
71
96
|
|
|
72
|
-
|
|
73
|
-
core.
|
|
74
|
-
|
|
97
|
+
if (isUpgrade) {
|
|
98
|
+
core.patcher.patch(resOrSocket, 'emit', {
|
|
99
|
+
name: `${serverType}.socket.emit`,
|
|
100
|
+
patchType: 'sources',
|
|
101
|
+
around(next) {
|
|
102
|
+
return core.scopes.sources.run(store, next);
|
|
103
|
+
},
|
|
104
|
+
});
|
|
105
|
+
} else {
|
|
106
|
+
onFinished(resOrSocket, (/* err, req */) => {
|
|
107
|
+
core.messages.emit(Event.RESPONSE_FINISH, store);
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
core.Perf.requestCount += 1;
|
|
75
112
|
|
|
76
113
|
return core.scopes.sources.run(store, () => {
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
114
|
+
const sourceType = protocol == 'websocket' ? SourceType.WEBSOCKET : SourceType.HTTP;
|
|
115
|
+
const eventArg = {
|
|
116
|
+
sourceType,
|
|
117
|
+
store,
|
|
118
|
+
incomingMessage: req,
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
if (sourceType == SourceType.HTTP)
|
|
122
|
+
eventArg.serverResponse = resOrSocket;
|
|
123
|
+
|
|
124
|
+
else if (sourceType == SourceType.WEBSOCKET)
|
|
125
|
+
eventArg.socket = resOrSocket;
|
|
126
|
+
|
|
127
|
+
if (_hooks._events.onSource)
|
|
128
|
+
_hooks.emit('onSource', eventArg);
|
|
86
129
|
|
|
87
130
|
return next();
|
|
88
131
|
});
|