@newrelic/security-agent 1.3.0 → 1.5.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/CHANGELOG.md +24 -0
- package/THIRD_PARTY_NOTICES.md +3 -3
- package/lib/instrumentation-security/core/constants.js +1 -0
- package/lib/instrumentation-security/hooks/grpc-js/nr-grpc.js +44 -3
- package/lib/instrumentation-security/hooks/http/nr-http.js +46 -6
- package/lib/nr-security-agent/lib/core/ExceptionReporting.js +186 -0
- package/lib/nr-security-agent/lib/core/LogMessage.js +4 -1
- package/lib/nr-security-agent/lib/core/connections/restclient.js +6 -0
- package/lib/nr-security-agent/lib/core/event.js +1 -0
- package/lib/nr-security-agent/lib/core/health-check.js +0 -1
- package/lib/nr-security-agent/lib/core/websocket-client.js +1 -0
- package/package.json +4 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,27 @@
|
|
|
1
|
+
### v1.5.0 (2024-08-14)
|
|
2
|
+
#### Features
|
|
3
|
+
* Support for Node.js v22.x
|
|
4
|
+
#### Bug fixes
|
|
5
|
+
* Fix for traceId in error reporting
|
|
6
|
+
#### Miscellaneous chores
|
|
7
|
+
* (deps): bumped axios from 1.6.8 to 1.7.4
|
|
8
|
+
* (deps-dev): bumped ws from 7.5.9 to 8.18.0
|
|
9
|
+
#### Continuous integration
|
|
10
|
+
* Added Node.js v22.x to unit tests
|
|
11
|
+
|
|
12
|
+
### v1.4.0 (2024-06-24)
|
|
13
|
+
#### Features
|
|
14
|
+
* Added support to report application's errors while IAST scanning
|
|
15
|
+
* Support to detect gRPC API endpoints
|
|
16
|
+
#### Bug fixes
|
|
17
|
+
* Remove additional headers added by IAST client
|
|
18
|
+
* Fix for uncaught exception reporting
|
|
19
|
+
#### Miscellaneous chores
|
|
20
|
+
* Updated package.json to bump ws from 8.14.2 to 8.17.1
|
|
21
|
+
* (deps-dev): bump @grpc/grpc-js from 1.9.12 to 1.10.9
|
|
22
|
+
* (deps-dev): bump braces from 3.0.2 to 3.0.3
|
|
23
|
+
* (deps): bump ws from 8.14.2 to 8.17.1
|
|
24
|
+
|
|
1
25
|
### v1.3.0 (2024-05-31)
|
|
2
26
|
#### Features
|
|
3
27
|
* Added route field in security event for API endpoint mapping
|
package/THIRD_PARTY_NOTICES.md
CHANGED
|
@@ -77,7 +77,7 @@ code, the source code can be found at [https://github.com/newrelic/csec-node-age
|
|
|
77
77
|
|
|
78
78
|
### axios
|
|
79
79
|
|
|
80
|
-
This product includes source derived from [axios](https://github.com/axios/axios) ([v1.
|
|
80
|
+
This product includes source derived from [axios](https://github.com/axios/axios) ([v1.7.4](https://github.com/axios/axios/tree/v1.7.4)), distributed under the [MIT License](https://github.com/axios/axios/blob/v1.7.4/LICENSE):
|
|
81
81
|
|
|
82
82
|
```
|
|
83
83
|
# Copyright (c) 2014-present Matt Zabriskie & Collaborators
|
|
@@ -588,7 +588,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
|
|
|
588
588
|
|
|
589
589
|
### ws
|
|
590
590
|
|
|
591
|
-
This product includes source derived from [ws](https://github.com/websockets/ws) ([v8.
|
|
591
|
+
This product includes source derived from [ws](https://github.com/websockets/ws) ([v8.17.1](https://github.com/websockets/ws/tree/v8.17.1)), distributed under the [MIT License](https://github.com/websockets/ws/blob/v8.17.1/LICENSE):
|
|
592
592
|
|
|
593
593
|
```
|
|
594
594
|
Copyright (c) 2011 Einar Otto Stangvik <einaros@gmail.com>
|
|
@@ -619,7 +619,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
|
619
619
|
|
|
620
620
|
### @grpc/proto-loader
|
|
621
621
|
|
|
622
|
-
This product includes source derived from [@grpc/proto-loader](https://github.com/grpc/grpc-node) ([v0.7.
|
|
622
|
+
This product includes source derived from [@grpc/proto-loader](https://github.com/grpc/grpc-node) ([v0.7.13](https://github.com/grpc/grpc-node/tree/v0.7.13)), distributed under the [Apache-2.0 License](https://github.com/grpc/grpc-node/blob/v0.7.13/LICENSE):
|
|
623
623
|
|
|
624
624
|
```
|
|
625
625
|
Apache License
|
|
@@ -9,11 +9,15 @@ const secUtils = require("../../core/sec-utils");
|
|
|
9
9
|
const API = require("../../../nr-security-api");
|
|
10
10
|
const securityMetaData = require('../../core/security-metadata');
|
|
11
11
|
const { EVENT_TYPE, EVENT_CATEGORY } = require('../../core/event-constants');
|
|
12
|
-
const { NR_CSEC_FUZZ_REQUEST_ID } = require('../../core/constants');
|
|
12
|
+
const { NR_CSEC_FUZZ_REQUEST_ID, DOUBLE_DOLLAR, ATTHERATE, ASTERISK } = require('../../core/constants');
|
|
13
13
|
const logger = API.getLogger();
|
|
14
14
|
const semver = require('semver');
|
|
15
15
|
const grpcutils = require('../../core/grpc-utils');
|
|
16
|
+
const routeManager = require('../../core/route-manager');
|
|
16
17
|
let serverAddress;
|
|
18
|
+
const ExceptionReporting = require('../../../nr-security-agent/lib/core/ExceptionReporting');
|
|
19
|
+
|
|
20
|
+
|
|
17
21
|
|
|
18
22
|
module.exports.initialize = function initialize(shim, grpc, moduleName) {
|
|
19
23
|
logger.info('Instrumenting grpc', moduleName);
|
|
@@ -118,17 +122,39 @@ function wrapStart(shim, original) {
|
|
|
118
122
|
}
|
|
119
123
|
|
|
120
124
|
|
|
121
|
-
|
|
125
|
+
/**
|
|
126
|
+
* Wrapper for addService method
|
|
127
|
+
* @param {*} shim
|
|
128
|
+
* @param {*} original
|
|
129
|
+
* @returns
|
|
130
|
+
*/
|
|
122
131
|
function wrapAddService(shim, original) {
|
|
123
132
|
if (!shim.isFunction(original)) {
|
|
124
133
|
return original
|
|
125
134
|
}
|
|
126
135
|
return function wrappedbindAsync() {
|
|
136
|
+
try {
|
|
137
|
+
const stakTrace = secUtils.traceElementForRoute();
|
|
138
|
+
const splittedStack = stakTrace[0].split(DOUBLE_DOLLAR);
|
|
139
|
+
let serviceValues = Object.values(arguments[0]);
|
|
140
|
+
for (const [key, value] of Object.entries(serviceValues)) {
|
|
141
|
+
const routeKey = ASTERISK + ATTHERATE + value.path;
|
|
142
|
+
let finalHandler = value.originalName + ATTHERATE + splittedStack[0];
|
|
143
|
+
routeManager.setRoute(routeKey, finalHandler);
|
|
144
|
+
}
|
|
145
|
+
} catch (error) {
|
|
146
|
+
}
|
|
127
147
|
const result = original.apply(this, arguments);
|
|
128
148
|
return result;
|
|
129
149
|
}
|
|
130
150
|
}
|
|
131
151
|
|
|
152
|
+
/**
|
|
153
|
+
* wrapper for loadPackageDefinition method
|
|
154
|
+
* @param {*} shim
|
|
155
|
+
* @param {*} original
|
|
156
|
+
* @returns
|
|
157
|
+
*/
|
|
132
158
|
function wrapLoadPackageDefinition(shim, original) {
|
|
133
159
|
if (!shim.isFunction(original)) {
|
|
134
160
|
return original
|
|
@@ -224,6 +250,21 @@ function wrapCallback(shim, mod, method) {
|
|
|
224
250
|
}
|
|
225
251
|
return function wrappedCallback() {
|
|
226
252
|
const response = arguments[1];
|
|
253
|
+
try {
|
|
254
|
+
const request = requestManager.getRequest(shim);
|
|
255
|
+
if (arguments[0]) {
|
|
256
|
+
if (arguments[0].details && request) {
|
|
257
|
+
ExceptionReporting.generateExceptionReportingEvent(arguments[0].details, request);
|
|
258
|
+
}
|
|
259
|
+
//TODO GRPC response errors reporting
|
|
260
|
+
// if (arguments[0].code && arguments[0].code > 0 && request) {
|
|
261
|
+
// let responseCode = arguments[0].code
|
|
262
|
+
// ExceptionReporting.generate5xxReportingEvent(null, request, responseCode);
|
|
263
|
+
// }
|
|
264
|
+
}
|
|
265
|
+
} catch (error) {
|
|
266
|
+
|
|
267
|
+
}
|
|
227
268
|
const result = fn.apply(this, arguments);
|
|
228
269
|
return result;
|
|
229
270
|
|
|
@@ -254,7 +295,7 @@ function addRequestData(shim, type, path, args) {
|
|
|
254
295
|
}
|
|
255
296
|
data.type = type;
|
|
256
297
|
data.protocol = 'grpc';
|
|
257
|
-
data.
|
|
298
|
+
data.isGrpc = true;
|
|
258
299
|
data.body = JSON.stringify(args.request);
|
|
259
300
|
data.serverPort = shim.serverPort;
|
|
260
301
|
const transactionId = segment.transaction.id;
|
|
@@ -31,13 +31,16 @@ const isInvalid = require('is-invalid-path');
|
|
|
31
31
|
const path = require('path');
|
|
32
32
|
const fs = require('fs');
|
|
33
33
|
const semver = require('semver');
|
|
34
|
-
|
|
34
|
+
const ExceptionReporting = require('../../../nr-security-agent/lib/core/ExceptionReporting');
|
|
35
35
|
|
|
36
36
|
const CSEC_SEP = ':IAST:';
|
|
37
37
|
const find = '{{NR_CSEC_VALIDATOR_HOME_TMP}}';
|
|
38
38
|
const CSEC_HOME_TMP_CONST = new RegExp(find, 'g');
|
|
39
39
|
let CSEC_HOME = NRAgent && NRAgent.config.newrelic_home ? NRAgent.config.newrelic_home : NRAgent && NRAgent.config.logging.filepath ? path.dirname(NRAgent.config.logging.filepath) : require('path').join(process.cwd());
|
|
40
40
|
const CSEC_HOME_TMP = `${CSEC_HOME}/nr-security-home/tmp/language-agent/${process.env.applicationUUID}`
|
|
41
|
+
let lastTransactionId = EMPTY_STRING;
|
|
42
|
+
let uncaughtExceptionReportFlag = false;
|
|
43
|
+
|
|
41
44
|
|
|
42
45
|
/**
|
|
43
46
|
* Entry point of http module hook
|
|
@@ -178,7 +181,7 @@ function parseFuzzheaders(requestData, transactionId) {
|
|
|
178
181
|
if (verifiedHash) {
|
|
179
182
|
logger.debug("Encrypted Data:", encryptedData);
|
|
180
183
|
logger.debug("Decrypted Data:", decryptedData)
|
|
181
|
-
logger.debug("fliesTocreate:",filesToCreate);
|
|
184
|
+
logger.debug("fliesTocreate:", filesToCreate);
|
|
182
185
|
for (let i = 0; i < filesToCreate.length; i++) {
|
|
183
186
|
let file = filesToCreate[i].trim();
|
|
184
187
|
file = file.replace(CSEC_HOME_TMP_CONST, CSEC_HOME_TMP);
|
|
@@ -192,11 +195,11 @@ function parseFuzzheaders(requestData, transactionId) {
|
|
|
192
195
|
logger.debug(parentDir + ' Already Exists');
|
|
193
196
|
}
|
|
194
197
|
fs.closeSync(fs.openSync(file, 'w'));
|
|
195
|
-
|
|
198
|
+
|
|
196
199
|
requestData.tempFiles = [];
|
|
197
200
|
requestData.tempFiles.push(file);
|
|
198
201
|
requestManager.setRequest(transactionId, requestData);
|
|
199
|
-
|
|
202
|
+
|
|
200
203
|
} catch (error) {
|
|
201
204
|
logger.debug(error);
|
|
202
205
|
}
|
|
@@ -243,6 +246,7 @@ function addRequestData(shim, request) {
|
|
|
243
246
|
data.clientIP = requestIp.getClientIp(request);
|
|
244
247
|
const transactionId = segment.transaction.id;
|
|
245
248
|
const storedRequest = requestManager.getRequestFromId(transactionId);
|
|
249
|
+
lastTransactionId = transactionId;
|
|
246
250
|
if (storedRequest && storedRequest.uri) {
|
|
247
251
|
data.uri = storedRequest.uri;
|
|
248
252
|
data.parameterMap = storedRequest.parameterMap;
|
|
@@ -396,8 +400,27 @@ function responseHook(resp, req, shim) {
|
|
|
396
400
|
}
|
|
397
401
|
return function wrappedEnd() {
|
|
398
402
|
const response = this;
|
|
399
|
-
responseBodyCompute(response, arguments);
|
|
400
403
|
const request = requestManager.getRequest(shim);
|
|
404
|
+
const txInfo = lodash.get(response, Object.getOwnPropertySymbols(response).find(symbol => symbol.toString() === 'Symbol(transactionInfo)'));
|
|
405
|
+
try {
|
|
406
|
+
if (txInfo && txInfo.error && request) {
|
|
407
|
+
ExceptionReporting.generateExceptionReportingEvent(txInfo.error, request);
|
|
408
|
+
}
|
|
409
|
+
const responseCode = response.statusCode;
|
|
410
|
+
if (responseCode && parseInt(responseCode / 100) == 5 && request) {
|
|
411
|
+
if (txInfo && txInfo.error) {
|
|
412
|
+
ExceptionReporting.generate5xxReportingEvent(txInfo.error, request, responseCode);
|
|
413
|
+
}
|
|
414
|
+
else {
|
|
415
|
+
ExceptionReporting.generate5xxReportingEvent(null, request, responseCode);
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
} catch (error) {
|
|
419
|
+
logger.debug("Error while reporting error", error);
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
responseBodyCompute(response, arguments);
|
|
423
|
+
|
|
401
424
|
const construct = API.checkForReflectedXSS(request, response.res.body, response.getHeaders());
|
|
402
425
|
const policy = API.getPolicy();
|
|
403
426
|
const dynamicScanningFlag = policy.data ? (policy.data.vulnerabilityScan?.enabled && policy.data.vulnerabilityScan.iastScan.enabled) : false;
|
|
@@ -565,4 +588,21 @@ function deleteTempFileForIAST(file) {
|
|
|
565
588
|
} catch (error) {
|
|
566
589
|
logger.debug("Unable to delete temporary file", error);
|
|
567
590
|
}
|
|
568
|
-
}
|
|
591
|
+
}
|
|
592
|
+
/**
|
|
593
|
+
* Collect and report the uncaught Exception
|
|
594
|
+
*/
|
|
595
|
+
process.on('uncaughtException', (err, origin) => {
|
|
596
|
+
console.error(err);
|
|
597
|
+
if(uncaughtExceptionReportFlag){
|
|
598
|
+
process.exit(1);
|
|
599
|
+
}
|
|
600
|
+
const request = requestManager.getRequestFromId(lastTransactionId);
|
|
601
|
+
const exception = new ExceptionReporting.exceptionReporting(err, request);
|
|
602
|
+
if (exception) {
|
|
603
|
+
API.sendEvent(exception);
|
|
604
|
+
}
|
|
605
|
+
logger.error("An uncaughtException is detected:", err);
|
|
606
|
+
uncaughtExceptionReportFlag = true;
|
|
607
|
+
});
|
|
608
|
+
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2023 New Relic Corporation. All rights reserved.
|
|
3
|
+
* SPDX-License-Identifier: New Relic Software License v1.0
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const LinkingMetaData = require('./LinkingMetadata');
|
|
7
|
+
const API = require('../../../nr-security-api');
|
|
8
|
+
const NRAgent = API.getNRAgent();
|
|
9
|
+
const { BasicInfo } = require('./event');
|
|
10
|
+
const applicationInfo = require('./applicationinfo').getInstance();
|
|
11
|
+
const exceptionsMap = new Map();
|
|
12
|
+
const logs = require('./logging');
|
|
13
|
+
const logger = logs.getLogger();
|
|
14
|
+
const exceptionReportingInterval = 30000;
|
|
15
|
+
const http = require('http');
|
|
16
|
+
const shaUtil = require('./sha-size-util');
|
|
17
|
+
|
|
18
|
+
const NR_LIB = '/newrelic/lib';
|
|
19
|
+
|
|
20
|
+
const GRPCStatusMap = {
|
|
21
|
+
0: 'OK',
|
|
22
|
+
1: 'CANCELLED',
|
|
23
|
+
2: 'UNKNOWN',
|
|
24
|
+
3: 'INVALID_ARGUMENT',
|
|
25
|
+
4: 'DEADLINE_EXCEEDED',
|
|
26
|
+
5: 'NOT_FOUND',
|
|
27
|
+
6: 'ALREADY_EXISTS',
|
|
28
|
+
7: 'PERMISSION_DENIED',
|
|
29
|
+
8: 'RESOURCE_EXHAUSTED',
|
|
30
|
+
9: 'FAILED_PRECONDITION',
|
|
31
|
+
10: 'ABORTED',
|
|
32
|
+
11: 'OUT_OF_RANGE',
|
|
33
|
+
12: 'UNIMPLEMENTED',
|
|
34
|
+
13: 'INTERNAL',
|
|
35
|
+
14: 'UNAVAILABLE',
|
|
36
|
+
15: 'DATA_LOSS',
|
|
37
|
+
16: 'UNAUTHENTICATED',
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* constructor function to create createException object
|
|
42
|
+
* @param {*} message
|
|
43
|
+
* @param {*} cause
|
|
44
|
+
* @param {*} stacktrace
|
|
45
|
+
*/
|
|
46
|
+
function createException(exception) {
|
|
47
|
+
let exceptionObject = {};
|
|
48
|
+
try {
|
|
49
|
+
exceptionObject.message = exception.message ? exception.message : '';
|
|
50
|
+
exceptionObject.cause = null;
|
|
51
|
+
exceptionObject.type = exception.name ? exception.name : 'Error';
|
|
52
|
+
if (exception.stack) {
|
|
53
|
+
let stacktraceInList = exception.stack.split('\n');
|
|
54
|
+
stacktraceInList = stacktraceInList.slice(1);
|
|
55
|
+
let fileteredStackTrace = [];
|
|
56
|
+
for (const str of stacktraceInList) {
|
|
57
|
+
if (!str.includes(NR_LIB) && str.length > 0) {
|
|
58
|
+
fileteredStackTrace.push(str.trim());
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
exceptionObject.stackTrace = fileteredStackTrace;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
} catch (error) {
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return exceptionObject;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* constructor function to create exceptionReporting object;
|
|
72
|
+
* @param {*} timestamp
|
|
73
|
+
* @param {*} level
|
|
74
|
+
* @param {*} message
|
|
75
|
+
* @param {*} caller
|
|
76
|
+
* @param {*} exception
|
|
77
|
+
* @param {*} linkingMetadata
|
|
78
|
+
*/
|
|
79
|
+
function exceptionReporting(exception, request, responseCode) {
|
|
80
|
+
try {
|
|
81
|
+
BasicInfo.call(this);
|
|
82
|
+
this.jsonVersion = applicationInfo.jsonVersion;
|
|
83
|
+
this.pid = applicationInfo.pid ? applicationInfo.pid : null;
|
|
84
|
+
this.jsonName = 'application-runtime-error';
|
|
85
|
+
this.applicationUUID = applicationInfo.applicationUUID;
|
|
86
|
+
this.policyVersion = applicationInfo.policyVersion;
|
|
87
|
+
this.collectorVersion = applicationInfo.collectorVersion ? applicationInfo.collectorVersion : null;
|
|
88
|
+
this.buildNumber = applicationInfo.buildNumber ? applicationInfo.buildNumber : null;
|
|
89
|
+
this.timestamp = Date.now();
|
|
90
|
+
this.httpRequest = request;
|
|
91
|
+
this.httpRequest.route = request.uri ? request.uri : request.url;
|
|
92
|
+
this.exception = null;
|
|
93
|
+
this.counter = 1;
|
|
94
|
+
this.responseCode = responseCode ? responseCode : null
|
|
95
|
+
|
|
96
|
+
if (exception) {
|
|
97
|
+
this.exception = createException(exception);
|
|
98
|
+
this.category = exception.name;
|
|
99
|
+
this.traceId = shaUtil.getSHA256ForData(this.exception.stackTrace.join('|') + this.category + this.httpRequest.route + this.httpRequest.method);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
if (responseCode) {
|
|
103
|
+
if (responseCode >= 500) {
|
|
104
|
+
this.category = http.STATUS_CODES[responseCode];
|
|
105
|
+
this.traceId = shaUtil.getSHA256ForData(this.category + this.httpRequest.route + this.httpRequest.method);
|
|
106
|
+
}
|
|
107
|
+
else {
|
|
108
|
+
this.category = GRPCStatusMap[responseCode];
|
|
109
|
+
this.traceId = shaUtil.getSHA256ForData(this.category + this.httpRequest.route + this.httpRequest.method);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
if (NRAgent) {
|
|
114
|
+
this.linkingMetadata = LinkingMetaData.getLinkingMetadata();
|
|
115
|
+
}
|
|
116
|
+
} catch (error) {
|
|
117
|
+
logger.debug("Error while generating exceptionReporing", error);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function generateExceptionReportingEvent(error, request) {
|
|
123
|
+
try {
|
|
124
|
+
const exception = new exceptionReporting(error, request);
|
|
125
|
+
if(!exception.traceId){
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
let key = exception.exception.type + exception.exception.stackTrace[0];
|
|
129
|
+
if (!exceptionsMap.has(key)) {
|
|
130
|
+
exceptionsMap.set(key, exception);
|
|
131
|
+
}
|
|
132
|
+
else {
|
|
133
|
+
let previousCounter = exceptionsMap.get(key).counter;
|
|
134
|
+
exception.counter = previousCounter ? previousCounter + 1: exception.counter + 1;
|
|
135
|
+
exceptionsMap.set(key, exception);
|
|
136
|
+
}
|
|
137
|
+
} catch (err) {
|
|
138
|
+
logger.debug("Error while generating application-runtime-error:", err);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
function generate5xxReportingEvent(error, request, responseCode) {
|
|
143
|
+
try {
|
|
144
|
+
const exception = new exceptionReporting(error, request, responseCode);
|
|
145
|
+
if(!exception.traceId){
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
let key = (request.uri ? request.uri : request.url) + responseCode;
|
|
149
|
+
if (!exceptionsMap.has(key)) {
|
|
150
|
+
exceptionsMap.set(key, exception);
|
|
151
|
+
}
|
|
152
|
+
else {
|
|
153
|
+
let previousCounter = exceptionsMap.get(key).counter;
|
|
154
|
+
exception.counter = previousCounter ? previousCounter + 1: exception.counter + 1;
|
|
155
|
+
exceptionsMap.set(key, exception);
|
|
156
|
+
}
|
|
157
|
+
} catch (err) {
|
|
158
|
+
logger.debug("Error while generating 5xx application-runtime-error:", err);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
function startExceptionSendingSchedular() {
|
|
165
|
+
try {
|
|
166
|
+
setInterval(() => {
|
|
167
|
+
const values = Array.from(exceptionsMap.values());
|
|
168
|
+
for (let i = 0; i < values.length; i++) {
|
|
169
|
+
API.sendEvent(values[i]);
|
|
170
|
+
}
|
|
171
|
+
exceptionsMap.clear();
|
|
172
|
+
}, exceptionReportingInterval);
|
|
173
|
+
} catch (error) {
|
|
174
|
+
logger.info("Error in exception reporting schedular");
|
|
175
|
+
}
|
|
176
|
+
logger.info("Exception reporting schedular started");
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
module.exports = {
|
|
181
|
+
exceptionReporting,
|
|
182
|
+
createException,
|
|
183
|
+
generateExceptionReportingEvent,
|
|
184
|
+
generate5xxReportingEvent,
|
|
185
|
+
startExceptionSendingSchedular
|
|
186
|
+
};
|
|
@@ -20,10 +20,11 @@ function logMessageException(exception) {
|
|
|
20
20
|
try {
|
|
21
21
|
exceptionObject.message = exception.message ? exception.message : '';
|
|
22
22
|
exceptionObject.cause = null;
|
|
23
|
+
exceptionObject.type = exception.name;
|
|
23
24
|
if (exception.stack) {
|
|
24
25
|
let stacktraceInList = exception.stack.split('\n');
|
|
25
26
|
stacktraceInList = stacktraceInList.slice(1);
|
|
26
|
-
exceptionObject.
|
|
27
|
+
exceptionObject.stackTrace = stacktraceInList;
|
|
27
28
|
}
|
|
28
29
|
|
|
29
30
|
} catch (error) {
|
|
@@ -51,6 +52,8 @@ function logMessage(level, message, caller, exception) {
|
|
|
51
52
|
this.applicationUUID = applicationInfo.applicationUUID;
|
|
52
53
|
this.groupName = applicationInfo.groupName;
|
|
53
54
|
this.policyVersion = applicationInfo.policyVersion;
|
|
55
|
+
this.collectorVersion = applicationInfo.collectorVersion ? applicationInfo.collectorVersion : null;
|
|
56
|
+
this.buildNumber = applicationInfo.buildNumber ? applicationInfo.buildNumber : null;
|
|
54
57
|
this.timestamp = Date.now();
|
|
55
58
|
this.level = level ? level : 'SEVERE';
|
|
56
59
|
this.message = message;
|
|
@@ -12,6 +12,12 @@ const axios = require('axios').default;
|
|
|
12
12
|
*/
|
|
13
13
|
function fireRequest (config) {
|
|
14
14
|
axios.defaults.timeout = 5000;
|
|
15
|
+
axios.defaults.headers.common['user-agent'] = null;
|
|
16
|
+
axios.defaults.headers.common['accept-encoding'] = null;
|
|
17
|
+
axios.defaults.headers.common['connection'] = null;
|
|
18
|
+
axios.defaults.headers.common['sec-ch-ua-platform'] = null;
|
|
19
|
+
axios.defaults.headers.common['accept'] = null;
|
|
20
|
+
axios.defaults.headers.common['content-type'] = null;
|
|
15
21
|
return axios(config);
|
|
16
22
|
}
|
|
17
23
|
|
|
@@ -34,6 +34,7 @@ function BasicInfo() {
|
|
|
34
34
|
this.policyVersion = (!lodash.isEmpty(policyManager.getInstance().data)) ? policyManager.getInstance().data.version : 'DEFAULT';
|
|
35
35
|
|
|
36
36
|
if (NRAgent && NRAgent.config) {
|
|
37
|
+
this.accountId = NRAgent.config.account_id;
|
|
37
38
|
this.entityGuid = NRAgent.config.entity_guid;
|
|
38
39
|
this.linkingMetadata = LinkingMetaData.getLinkingMetadata();
|
|
39
40
|
this.linkingMetadata.agentRunId = NRAgent.config.run_id;
|
|
@@ -75,6 +75,7 @@ const initialize = function () {
|
|
|
75
75
|
let data = require('./apiEndpoints').APIEndPoint(apiEndpoints);
|
|
76
76
|
logger.debug("All API end points of the application is:",JSON.stringify(data));
|
|
77
77
|
getDispatcherAndSendEvent(data);
|
|
78
|
+
require('../core/ExceptionReporting').startExceptionSendingSchedular();
|
|
78
79
|
} catch (error) {
|
|
79
80
|
logger.debug("Error while processing API endpoints",error);
|
|
80
81
|
}
|
package/package.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@newrelic/security-agent",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.5.0",
|
|
4
4
|
"description": "New Relic Security Agent for Node.js",
|
|
5
5
|
"main": "index.js",
|
|
6
|
-
"jsonVersion": "1.2.
|
|
6
|
+
"jsonVersion": "1.2.3",
|
|
7
7
|
"contributors": [
|
|
8
8
|
{
|
|
9
9
|
"name": "Sumit Suthar",
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
"url": "https://github.com/newrelic/csec-node-agent.git"
|
|
36
36
|
},
|
|
37
37
|
"dependencies": {
|
|
38
|
-
"axios": "^1.
|
|
38
|
+
"axios": "^1.7.4",
|
|
39
39
|
"check-disk-space": "^3.4.0",
|
|
40
40
|
"content-type": "^1.0.5",
|
|
41
41
|
"fast-safe-stringify": "^2.1.1",
|
|
@@ -55,7 +55,7 @@
|
|
|
55
55
|
"unescape": "^1.0.1",
|
|
56
56
|
"unescape-js": "^1.1.4",
|
|
57
57
|
"uuid": "^9.0.1",
|
|
58
|
-
"ws": "^8.
|
|
58
|
+
"ws": "^8.17.1"
|
|
59
59
|
},
|
|
60
60
|
"devDependencies": {
|
|
61
61
|
"@grpc/proto-loader": "^0.7.10",
|