@newrelic/security-agent 0.0.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/CHANGELOG.md +0 -0
- package/CONTRIBUTING.md +23 -0
- package/LICENSE +43 -0
- package/README.md +98 -0
- package/THIRD_PARTY_NOTICES.md +2909 -0
- package/index.js +24 -0
- package/lib/instrumentation-security/core/constants.js +66 -0
- package/lib/instrumentation-security/core/event-constants.js +49 -0
- package/lib/instrumentation-security/core/request-manager.js +73 -0
- package/lib/instrumentation-security/core/route-manager.js +30 -0
- package/lib/instrumentation-security/core/sec-trace.js +134 -0
- package/lib/instrumentation-security/core/sec-utils.js +212 -0
- package/lib/instrumentation-security/core/security-metadata.js +34 -0
- package/lib/instrumentation-security/core/stack-trace.js +156 -0
- package/lib/instrumentation-security/hooks/director/nr-director.js +98 -0
- package/lib/instrumentation-security/hooks/express/nr-express.js +106 -0
- package/lib/instrumentation-security/hooks/fastify/nr-fastify.js +155 -0
- package/lib/instrumentation-security/hooks/fs/nr-fs.js +391 -0
- package/lib/instrumentation-security/hooks/hapi/nr-hapi.js +131 -0
- package/lib/instrumentation-security/hooks/http/nr-http.js +461 -0
- package/lib/instrumentation-security/hooks/koa/@koa/nr-@koa-router.js +110 -0
- package/lib/instrumentation-security/hooks/ldap/nr-ldap.js +81 -0
- package/lib/instrumentation-security/hooks/mongodb/common.js +239 -0
- package/lib/instrumentation-security/hooks/mongodb/constants.js +91 -0
- package/lib/instrumentation-security/hooks/mongodb/nr-mongodb.js +49 -0
- package/lib/instrumentation-security/hooks/mongodb/v2-mongo.js +91 -0
- package/lib/instrumentation-security/hooks/mongodb/v3-mongo.js +36 -0
- package/lib/instrumentation-security/hooks/mongodb/v4-mongo.js +17 -0
- package/lib/instrumentation-security/hooks/mysql/nr-mysql.js +232 -0
- package/lib/instrumentation-security/hooks/native/nr-childProcess.js +131 -0
- package/lib/instrumentation-security/hooks/postgres/nr-postgres.js +131 -0
- package/lib/instrumentation-security/hooks/require/nr-require.js +93 -0
- package/lib/instrumentation-security/hooks/restify/nr-restify.js +104 -0
- package/lib/instrumentation-security/hooks/xpath/nr-xpath.js +91 -0
- package/lib/instrumentation-security/index.js +171 -0
- package/lib/nr-security-agent/index.js +170 -0
- package/lib/nr-security-agent/lib/core/Auth-headers.js +58 -0
- package/lib/nr-security-agent/lib/core/ContainerProperties.js +42 -0
- package/lib/nr-security-agent/lib/core/ECSProperties.js +34 -0
- package/lib/nr-security-agent/lib/core/FuzzFailEvent.js +27 -0
- package/lib/nr-security-agent/lib/core/LinkingMetadata.js +21 -0
- package/lib/nr-security-agent/lib/core/LogMessage.js +47 -0
- package/lib/nr-security-agent/lib/core/PodProperties.js +36 -0
- package/lib/nr-security-agent/lib/core/Policy.js +105 -0
- package/lib/nr-security-agent/lib/core/agent-status.js +56 -0
- package/lib/nr-security-agent/lib/core/agent.js +146 -0
- package/lib/nr-security-agent/lib/core/applicationinfo.js +634 -0
- package/lib/nr-security-agent/lib/core/commonUtils.js +411 -0
- package/lib/nr-security-agent/lib/core/connections/aws-lambda-client.js +55 -0
- package/lib/nr-security-agent/lib/core/connections/restclient.js +20 -0
- package/lib/nr-security-agent/lib/core/connections/websocket/index.js +25 -0
- package/lib/nr-security-agent/lib/core/connections/websocket/response/collecotor-policy-error-handler.js +18 -0
- package/lib/nr-security-agent/lib/core/connections/websocket/response/collector-policy-handler.js +20 -0
- package/lib/nr-security-agent/lib/core/connections/websocket/response/fuzz-request-handler.js +171 -0
- package/lib/nr-security-agent/lib/core/connections/websocket/response/index.js +47 -0
- package/lib/nr-security-agent/lib/core/connections/websocket/response/no-op-handler.js +12 -0
- package/lib/nr-security-agent/lib/core/connections/websocket/response/startup-handshake-handler.js +27 -0
- package/lib/nr-security-agent/lib/core/connections/websocket/response/unsupported-agent-handler.js +18 -0
- package/lib/nr-security-agent/lib/core/connections/websocket/response/ws-reconnect.js +14 -0
- package/lib/nr-security-agent/lib/core/connections/websocket/websocket.js +443 -0
- package/lib/nr-security-agent/lib/core/event.js +186 -0
- package/lib/nr-security-agent/lib/core/health-check.js +159 -0
- package/lib/nr-security-agent/lib/core/json-file-handler.js +66 -0
- package/lib/nr-security-agent/lib/core/jsonValidator.js +149 -0
- package/lib/nr-security-agent/lib/core/lambda-delegated-task-service.js +90 -0
- package/lib/nr-security-agent/lib/core/logging.js +176 -0
- package/lib/nr-security-agent/lib/core/sec-agent-constants.js +173 -0
- package/lib/nr-security-agent/lib/core/sec-util.js +166 -0
- package/lib/nr-security-agent/lib/core/sha-size-util.js +338 -0
- package/lib/nr-security-agent/lib/core/sha_worker.js +24 -0
- package/lib/nr-security-agent/lib/core/startup-config.js +29 -0
- package/lib/nr-security-agent/lib/core/statusUtils.js +157 -0
- package/lib/nr-security-agent/lib/core/timeunit.js +44 -0
- package/lib/nr-security-agent/lib/core/websocket-client.js +335 -0
- package/lib/nr-security-agent/lib/core/worker-entities.js +82 -0
- package/lib/nr-security-agent/lib/core/worker.js +148 -0
- package/lib/nr-security-agent/lib/core/xss-utils.js +297 -0
- package/lib/nr-security-agent/lib/models/lambda-delegated-task/constants.js +12 -0
- package/lib/nr-security-agent/lib/models/lambda-delegated-task/index.js +15 -0
- package/lib/nr-security-agent/lib/models/lambda-delegated-task/lambda-delegated-sha-calculation.js +37 -0
- package/lib/nr-security-agent/lib/models/lambda-delegated-task/lambda-delegated-task-base.js +50 -0
- package/lib/nr-security-agent/lib/models/lambda-delegated-task/lambda-delegated-task-type.js +17 -0
- package/lib/nr-security-agent/resources/cert.pem +31 -0
- package/lib/nr-security-agent/resources/config.js +19 -0
- package/lib/nr-security-agent/resources/default-policy.yaml +36 -0
- package/lib/nr-security-api/index.js +111 -0
- package/package.json +95 -0
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2023 New Relic Corporation. All rights reserved.
|
|
3
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
'use strict';
|
|
7
|
+
|
|
8
|
+
const AsyncHooks = require('async_hooks');
|
|
9
|
+
|
|
10
|
+
const NEW_LINE_IDENTIFIER = '\n';
|
|
11
|
+
const NATIVE_LITERAL = 'native';
|
|
12
|
+
const DOT_CHARACTER = '.';
|
|
13
|
+
const MODULE_IDENTIFIER = '.Module';
|
|
14
|
+
const ANONYMOUS_IDENTIFIER = '<anonymous>';
|
|
15
|
+
|
|
16
|
+
const lineRegex = /at (?:(.+)\s+\()?(?:(.+?):(\d+)(?::(\d+))?|([^)]+))\)?/;
|
|
17
|
+
const GET = 'get';
|
|
18
|
+
const IS = 'is';
|
|
19
|
+
|
|
20
|
+
exports.get = function (belowFn) {
|
|
21
|
+
const oldLimit = Error.stackTraceLimit;
|
|
22
|
+
Error.stackTraceLimit = 18;
|
|
23
|
+
const dummyObject = {};
|
|
24
|
+
|
|
25
|
+
const eid = AsyncHooks.executionAsyncId();
|
|
26
|
+
|
|
27
|
+
const v8Handler = Error.prepareStackTrace;
|
|
28
|
+
Error.prepareStackTrace = function (dummyObject, v8StackTrace) {
|
|
29
|
+
return v8StackTrace;
|
|
30
|
+
};
|
|
31
|
+
Error.captureStackTrace(dummyObject, belowFn || exports.get);
|
|
32
|
+
|
|
33
|
+
const v8StackTrace = dummyObject.stack;
|
|
34
|
+
Error.prepareStackTrace = v8Handler;
|
|
35
|
+
Error.stackTraceLimit = oldLimit;
|
|
36
|
+
|
|
37
|
+
return v8StackTrace;
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
exports.parse = function (err) {
|
|
41
|
+
if (!err.stack) {
|
|
42
|
+
return [];
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const self = this;
|
|
46
|
+
const lines = err.stack.split(NEW_LINE_IDENTIFIER).slice(1);
|
|
47
|
+
|
|
48
|
+
return lines
|
|
49
|
+
.map(function (line) {
|
|
50
|
+
if (line.match(/^\s*[-]{4,}$/)) {
|
|
51
|
+
return self._createParsedCallSite({
|
|
52
|
+
fileName: line,
|
|
53
|
+
lineNumber: null,
|
|
54
|
+
functionName: null,
|
|
55
|
+
typeName: null,
|
|
56
|
+
methodName: null,
|
|
57
|
+
columnNumber: null,
|
|
58
|
+
native: null
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const lineMatch = line.match(lineRegex);
|
|
63
|
+
if (!lineMatch) {
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
let object = null;
|
|
68
|
+
let method = null;
|
|
69
|
+
let functionName = null;
|
|
70
|
+
let typeName = null;
|
|
71
|
+
let methodName = null;
|
|
72
|
+
const isNative = (lineMatch[5] === NATIVE_LITERAL);
|
|
73
|
+
|
|
74
|
+
if (lineMatch[1]) {
|
|
75
|
+
functionName = lineMatch[1];
|
|
76
|
+
let methodStart = functionName.lastIndexOf(DOT_CHARACTER);
|
|
77
|
+
if (functionName[methodStart - 1] === DOT_CHARACTER) { methodStart-- }
|
|
78
|
+
if (methodStart > 0) {
|
|
79
|
+
object = functionName.substr(0, methodStart);
|
|
80
|
+
method = functionName.substr(methodStart + 1);
|
|
81
|
+
const objectEnd = object.indexOf(MODULE_IDENTIFIER);
|
|
82
|
+
if (objectEnd > 0) {
|
|
83
|
+
functionName = functionName.substr(objectEnd + 1);
|
|
84
|
+
object = object.substr(0, objectEnd);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
typeName = null;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if (method) {
|
|
91
|
+
typeName = object;
|
|
92
|
+
methodName = method;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if (method === ANONYMOUS_IDENTIFIER) {
|
|
96
|
+
methodName = null;
|
|
97
|
+
functionName = null;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const properties = {
|
|
101
|
+
fileName: lineMatch[2] || null,
|
|
102
|
+
lineNumber: parseInt(lineMatch[3], 10) || null,
|
|
103
|
+
functionName: functionName,
|
|
104
|
+
typeName: typeName,
|
|
105
|
+
methodName: methodName,
|
|
106
|
+
columnNumber: parseInt(lineMatch[4], 10) || null,
|
|
107
|
+
native: isNative
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
return self._createParsedCallSite(properties);
|
|
111
|
+
})
|
|
112
|
+
.filter(function (callSite) {
|
|
113
|
+
return !!callSite;
|
|
114
|
+
});
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
function CallSite (properties) {
|
|
118
|
+
for (const property in properties) {
|
|
119
|
+
this[property] = properties[property];
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const strProperties = [
|
|
124
|
+
'this',
|
|
125
|
+
'typeName',
|
|
126
|
+
'functionName',
|
|
127
|
+
'methodName',
|
|
128
|
+
'fileName',
|
|
129
|
+
'lineNumber',
|
|
130
|
+
'columnNumber',
|
|
131
|
+
'function',
|
|
132
|
+
'evalOrigin'
|
|
133
|
+
];
|
|
134
|
+
const boolProperties = [
|
|
135
|
+
'topLevel',
|
|
136
|
+
'eval',
|
|
137
|
+
'native',
|
|
138
|
+
'constructor'
|
|
139
|
+
];
|
|
140
|
+
strProperties.forEach(function (property) {
|
|
141
|
+
CallSite.prototype[property] = null;
|
|
142
|
+
CallSite.prototype[GET + property[0].toUpperCase() + property.substr(1)] = function () {
|
|
143
|
+
return this[property];
|
|
144
|
+
};
|
|
145
|
+
});
|
|
146
|
+
boolProperties.forEach(function (property) {
|
|
147
|
+
CallSite.prototype[property] = false;
|
|
148
|
+
CallSite.prototype[IS + property[0].toUpperCase() + property.substr(1)] = function () {
|
|
149
|
+
return this[property];
|
|
150
|
+
};
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
exports._createParsedCallSite = function (properties) {
|
|
154
|
+
return new CallSite(properties);
|
|
155
|
+
};
|
|
156
|
+
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2023 New Relic Corporation. All rights reserved.
|
|
3
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
'use strict'
|
|
8
|
+
|
|
9
|
+
const requestManager = require("../../core/request-manager");
|
|
10
|
+
const secUtils = require('../../core/sec-utils');
|
|
11
|
+
const { ATTHERATE, DOUBLE_DOLLAR, COLON } = require('../../core/constants');
|
|
12
|
+
const lodash = require('lodash');
|
|
13
|
+
const routeManager = require('../../core/route-manager');
|
|
14
|
+
const API = require("../../../nr-security-api");
|
|
15
|
+
const logger = API.getLogger();
|
|
16
|
+
|
|
17
|
+
module.exports = function initialize(shim, director) {
|
|
18
|
+
const proto = director.Router.prototype
|
|
19
|
+
|
|
20
|
+
shim.wrap(proto, 'insert', function wrapParam(shim, fn) {
|
|
21
|
+
if (!shim.isFunction(fn)) {
|
|
22
|
+
return fn
|
|
23
|
+
}
|
|
24
|
+
return function wrappedParam() {
|
|
25
|
+
this.routeMethod = arguments[0]
|
|
26
|
+
return fn.apply(this, arguments);
|
|
27
|
+
}
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
shim.wrap(proto, 'mount', function wrapMount(shim, mount) {
|
|
33
|
+
if (!shim.isFunction(mount)) {
|
|
34
|
+
return mount
|
|
35
|
+
}
|
|
36
|
+
return function wrappedMount(routes) {
|
|
37
|
+
shim.wrap(routes, director.http.methods, function wrapRoute(shim, route) {
|
|
38
|
+
if (!shim.isFunction(route)) {
|
|
39
|
+
return route
|
|
40
|
+
}
|
|
41
|
+
return function wrappedRoute() {
|
|
42
|
+
extractParams(shim, arguments);
|
|
43
|
+
return route.apply(this, arguments);
|
|
44
|
+
}
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
if (arguments[1]) {
|
|
48
|
+
try {
|
|
49
|
+
const method = this.routeMethod ? this.routeMethod : Object.keys(arguments[0])[0];
|
|
50
|
+
const path = "/" + arguments[1].join('/')
|
|
51
|
+
const stakTrace = secUtils.traceElementForRoute();
|
|
52
|
+
const splittedStack = stakTrace[0].split(DOUBLE_DOLLAR);
|
|
53
|
+
const key = lodash.upperCase(method) + ATTHERATE + path;
|
|
54
|
+
routeManager.setRoute(key, splittedStack[0]);
|
|
55
|
+
if (path.includes(COLON)) {
|
|
56
|
+
const dummyKey = key.split(COLON)[0] + ":param_input";
|
|
57
|
+
routeManager.setRoute(dummyKey, splittedStack[0]);
|
|
58
|
+
}
|
|
59
|
+
} catch (error) {
|
|
60
|
+
logger.debug("Error in intercepting routes", error);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
return mount.apply(this, arguments);
|
|
64
|
+
}
|
|
65
|
+
})
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Utility function to prepare parameterMap
|
|
70
|
+
* @param {*} shim
|
|
71
|
+
* @param {*} params
|
|
72
|
+
*/
|
|
73
|
+
function extractParams(shim, params) {
|
|
74
|
+
const segment = shim.getActiveSegment();
|
|
75
|
+
if (segment && segment.transaction) {
|
|
76
|
+
let request = requestManager.getRequestFromId(segment.transaction.id);
|
|
77
|
+
if (params && request) {
|
|
78
|
+
Object.keys(params).forEach(function (key) {
|
|
79
|
+
if (params[key]) {
|
|
80
|
+
if (!request.parameterMap[key]) {
|
|
81
|
+
request.parameterMap[key] = new Array(params[key].toString());
|
|
82
|
+
requestManager.setRequest(segment.transaction.id, request);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if (request) {
|
|
89
|
+
let uri = request.url.split("?")[0];
|
|
90
|
+
const param = Object.values(params)[0];
|
|
91
|
+
if (uri.includes(param)) {
|
|
92
|
+
uri = lodash.replace(uri, param, ':param_input');
|
|
93
|
+
request.uri = uri;
|
|
94
|
+
requestManager.setRequest(segment.transaction.id, request);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2023 New Relic Corporation. All rights reserved.
|
|
3
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
'use strict'
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Express middleware generates traces where middleware are considered siblings
|
|
10
|
+
* (ended on 'next' invocation) and not nested. Middlware are nested below the
|
|
11
|
+
* routers they are mounted to.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
const requestManager = require("../../core/request-manager");
|
|
15
|
+
const secUtils = require('../../core/sec-utils');
|
|
16
|
+
const { ATTHERATE, DOUBLE_DOLLAR } = require('../../core/constants');
|
|
17
|
+
const lodash = require('lodash');
|
|
18
|
+
const routeManager = require('../../core/route-manager');
|
|
19
|
+
const API = require("../../../nr-security-api");
|
|
20
|
+
const logger = API.getLogger();
|
|
21
|
+
|
|
22
|
+
module.exports = function initialize(shim, express, moduleName) {
|
|
23
|
+
logger.info("Instrumenting express")
|
|
24
|
+
if (!express || !express.Router) {
|
|
25
|
+
return false
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
if (express.Router.use) {
|
|
29
|
+
wrapExpress4(shim, express)
|
|
30
|
+
} else {
|
|
31
|
+
// wrapExpress3(shim, express)
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Wrapper to hook express version 4.x route method
|
|
37
|
+
* @param {*} shim
|
|
38
|
+
* @param {*} express
|
|
39
|
+
*/
|
|
40
|
+
function wrapExpress4(shim, express) {
|
|
41
|
+
shim.wrap(express.Router, 'route', function wrapRoute(shim, fn) {
|
|
42
|
+
if (!shim.isFunction(fn)) {
|
|
43
|
+
return fn
|
|
44
|
+
}
|
|
45
|
+
return function wrappedRoute() {
|
|
46
|
+
try {
|
|
47
|
+
const stakTrace = secUtils.traceElementForRoute();
|
|
48
|
+
const splittedStack = stakTrace[0].split(DOUBLE_DOLLAR);
|
|
49
|
+
const key = lodash.upperCase(splittedStack[1]) + ATTHERATE + arguments[0];
|
|
50
|
+
routeManager.setRoute(key, splittedStack[0]);
|
|
51
|
+
} catch (error) {
|
|
52
|
+
|
|
53
|
+
}
|
|
54
|
+
const route = fn.apply(this, arguments)
|
|
55
|
+
return route;
|
|
56
|
+
}
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
//Wrapper to hook process_params method to extract out path param and query params.
|
|
61
|
+
shim.wrap(express.Router, 'process_params', function wrapParam(shim, fn) {
|
|
62
|
+
if (!shim.isFunction(fn)) {
|
|
63
|
+
return fn
|
|
64
|
+
}
|
|
65
|
+
return function wrappedParam() {
|
|
66
|
+
extractParams(shim, arguments[2]);
|
|
67
|
+
const route = fn.apply(this, arguments)
|
|
68
|
+
return route
|
|
69
|
+
}
|
|
70
|
+
})
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Utility function to parse request obejct intercepted from express.router.process_params() method hook
|
|
74
|
+
* @param {*} shim
|
|
75
|
+
* @param {*} req
|
|
76
|
+
*/
|
|
77
|
+
function extractParams(shim, req) {
|
|
78
|
+
const segment = shim.getActiveSegment();
|
|
79
|
+
if (segment && segment.transaction) {
|
|
80
|
+
let request = requestManager.getRequestFromId(segment.transaction.id);
|
|
81
|
+
if (req.params && request) {
|
|
82
|
+
Object.keys(req.params).forEach(function (key) {
|
|
83
|
+
if (req.params[key]) {
|
|
84
|
+
if (!request.parameterMap[key]) {
|
|
85
|
+
request.parameterMap[key] = new Array(req.params[key].toString());
|
|
86
|
+
requestManager.setRequest(segment.transaction.id, request);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
if (req.query && request) {
|
|
92
|
+
Object.keys(req.query).forEach(function (key) {
|
|
93
|
+
if (req.query[key]) {
|
|
94
|
+
if (!request.parameterMap[key]) {
|
|
95
|
+
request.parameterMap[key] = new Array(req.query[key].toString());
|
|
96
|
+
requestManager.setRequest(segment.transaction.id, request);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
if (req.route && req.route.path && request) {
|
|
102
|
+
request.uri = req.route.path;
|
|
103
|
+
requestManager.setRequest(segment.transaction.id, request);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2023 New Relic Corporation. All rights reserved.
|
|
3
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
'use strict'
|
|
7
|
+
const requestManager = require("../../core/request-manager");
|
|
8
|
+
const secUtils = require('../../core/sec-utils');
|
|
9
|
+
const { ATTHERATE, DOUBLE_DOLLAR } = require('../../core/constants');
|
|
10
|
+
const lodash = require('lodash');
|
|
11
|
+
const routeManager = require('../../core/route-manager');
|
|
12
|
+
const semver = require('semver')
|
|
13
|
+
const url = require('url');
|
|
14
|
+
const API = require("../../../nr-security-api");
|
|
15
|
+
const logger = API.getLogger();
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Sets up fastify route handler
|
|
20
|
+
*
|
|
21
|
+
* Fastify's onRoute hook will fire whenever
|
|
22
|
+
* a route is registered. This is the most straight
|
|
23
|
+
* forward way to get at a fastify route definition.
|
|
24
|
+
* Not only are we _not_ relying on private implementations
|
|
25
|
+
* that could change, fastify is pretty good about protecting
|
|
26
|
+
* those private implementations from access, and getting
|
|
27
|
+
* at them would require a lot of gymnastics and hard to
|
|
28
|
+
* maintain code
|
|
29
|
+
*
|
|
30
|
+
* @param shim
|
|
31
|
+
* @param fastify
|
|
32
|
+
*/
|
|
33
|
+
const setupRouteHandler = (shim, fastify, moduleName) => {
|
|
34
|
+
logger.info("Instrumenting Fastify")
|
|
35
|
+
|
|
36
|
+
const VerbMethods = ['all', 'delete', 'get', 'head', 'post', 'put', 'patch', 'options'];
|
|
37
|
+
//for routeMap
|
|
38
|
+
VerbMethods.forEach(function (fun) {
|
|
39
|
+
shim.wrap(fastify, fun, function wrapRoute(shim, fn) {
|
|
40
|
+
if (!shim.isFunction(fn)) {
|
|
41
|
+
return fn
|
|
42
|
+
}
|
|
43
|
+
return function wrappedRoute() {
|
|
44
|
+
try {
|
|
45
|
+
const stakTrace = secUtils.traceElementForRoute();
|
|
46
|
+
const splittedStack = stakTrace[0].split(DOUBLE_DOLLAR);
|
|
47
|
+
const key = lodash.upperCase(splittedStack[1]) + ATTHERATE + arguments[0];
|
|
48
|
+
routeManager.setRoute(key, splittedStack[0]);
|
|
49
|
+
} catch (error) {
|
|
50
|
+
}
|
|
51
|
+
const route = fn.apply(this, arguments);
|
|
52
|
+
return route;
|
|
53
|
+
}
|
|
54
|
+
})
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
fastify.addHook('onRequest', async (request) => {
|
|
58
|
+
if (!requestManager.getRequest(shim)) {
|
|
59
|
+
secUtils.addRequestData(shim, request);
|
|
60
|
+
}
|
|
61
|
+
extractParams(shim, request);
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
module.exports = function initialize(shim, fastify, moduleName) {
|
|
68
|
+
|
|
69
|
+
const fastifyVersion = shim.require('./package.json').version
|
|
70
|
+
const isv3Plus = semver.satisfies(fastifyVersion, '>=3.0.0')
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Fastify exports a function, so we need to use wrapExport
|
|
74
|
+
*/
|
|
75
|
+
const wrappedExport = shim.wrapExport(fastify, function wrapFastifyModule(shim, fn) {
|
|
76
|
+
return function wrappedFastifyModule() {
|
|
77
|
+
// call original function get get fastify object (which is singleton-ish)
|
|
78
|
+
const fastifyForWrapping = fn.apply(this, arguments)
|
|
79
|
+
|
|
80
|
+
setupRouteHandler(shim, fastifyForWrapping, moduleName)
|
|
81
|
+
|
|
82
|
+
return fastifyForWrapping
|
|
83
|
+
}
|
|
84
|
+
})
|
|
85
|
+
|
|
86
|
+
if (isv3Plus) {
|
|
87
|
+
setupExports(fastify, wrappedExport)
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* module.exports = fastify
|
|
96
|
+
* module.exports.fastify = fastify
|
|
97
|
+
* module.exports.default = fastify
|
|
98
|
+
*
|
|
99
|
+
* @param original
|
|
100
|
+
* @param wrappedExport
|
|
101
|
+
*/
|
|
102
|
+
function setupExports(original, wrappedExport) {
|
|
103
|
+
wrappedExport.fastify = original.fastify
|
|
104
|
+
|
|
105
|
+
if (original.fastify) {
|
|
106
|
+
wrappedExport.fastify = wrappedExport
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
if (original.default) {
|
|
110
|
+
wrappedExport.default = wrappedExport
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Utility to parse request object to get path params and query params
|
|
116
|
+
* @param {*} shim
|
|
117
|
+
* @param {*} req
|
|
118
|
+
*/
|
|
119
|
+
function extractParams(shim, req) {
|
|
120
|
+
try {
|
|
121
|
+
const reqURL = req.url || req.raw.url;
|
|
122
|
+
const parsedURI = url.parse(reqURL).pathname;
|
|
123
|
+
const segment = shim.getActiveSegment();
|
|
124
|
+
if (segment && segment.transaction) {
|
|
125
|
+
let request = requestManager.getRequestFromId(segment.transaction.id);
|
|
126
|
+
if (req.params && segment && request) {
|
|
127
|
+
Object.keys(req.params).forEach(function (key) {
|
|
128
|
+
if (req.params[key]) {
|
|
129
|
+
if (!request.parameterMap[key]) {
|
|
130
|
+
request.parameterMap[key] = new Array(req.params[key].toString());
|
|
131
|
+
requestManager.setRequest(segment.transaction.id, request);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
if (req.query && request) {
|
|
137
|
+
Object.keys(req.query).forEach(function (key) {
|
|
138
|
+
if (req.query[key]) {
|
|
139
|
+
if (!request.parameterMap[key]) {
|
|
140
|
+
request.parameterMap[key] = new Array(req.query[key].toString());
|
|
141
|
+
requestManager.setRequest(segment.transaction.id, request);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
let method = request.method.toUpperCase();
|
|
147
|
+
if (parsedURI && request && requestManager.requestMap[method + ATTHERATE + parsedURI]) {
|
|
148
|
+
request.uri = parsedURI;
|
|
149
|
+
requestManager.setRequest(segment.transaction.id, request);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
} catch (error) {
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
}
|