@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.
Files changed (87) hide show
  1. package/CHANGELOG.md +0 -0
  2. package/CONTRIBUTING.md +23 -0
  3. package/LICENSE +43 -0
  4. package/README.md +98 -0
  5. package/THIRD_PARTY_NOTICES.md +2909 -0
  6. package/index.js +24 -0
  7. package/lib/instrumentation-security/core/constants.js +66 -0
  8. package/lib/instrumentation-security/core/event-constants.js +49 -0
  9. package/lib/instrumentation-security/core/request-manager.js +73 -0
  10. package/lib/instrumentation-security/core/route-manager.js +30 -0
  11. package/lib/instrumentation-security/core/sec-trace.js +134 -0
  12. package/lib/instrumentation-security/core/sec-utils.js +212 -0
  13. package/lib/instrumentation-security/core/security-metadata.js +34 -0
  14. package/lib/instrumentation-security/core/stack-trace.js +156 -0
  15. package/lib/instrumentation-security/hooks/director/nr-director.js +98 -0
  16. package/lib/instrumentation-security/hooks/express/nr-express.js +106 -0
  17. package/lib/instrumentation-security/hooks/fastify/nr-fastify.js +155 -0
  18. package/lib/instrumentation-security/hooks/fs/nr-fs.js +391 -0
  19. package/lib/instrumentation-security/hooks/hapi/nr-hapi.js +131 -0
  20. package/lib/instrumentation-security/hooks/http/nr-http.js +461 -0
  21. package/lib/instrumentation-security/hooks/koa/@koa/nr-@koa-router.js +110 -0
  22. package/lib/instrumentation-security/hooks/ldap/nr-ldap.js +81 -0
  23. package/lib/instrumentation-security/hooks/mongodb/common.js +239 -0
  24. package/lib/instrumentation-security/hooks/mongodb/constants.js +91 -0
  25. package/lib/instrumentation-security/hooks/mongodb/nr-mongodb.js +49 -0
  26. package/lib/instrumentation-security/hooks/mongodb/v2-mongo.js +91 -0
  27. package/lib/instrumentation-security/hooks/mongodb/v3-mongo.js +36 -0
  28. package/lib/instrumentation-security/hooks/mongodb/v4-mongo.js +17 -0
  29. package/lib/instrumentation-security/hooks/mysql/nr-mysql.js +232 -0
  30. package/lib/instrumentation-security/hooks/native/nr-childProcess.js +131 -0
  31. package/lib/instrumentation-security/hooks/postgres/nr-postgres.js +131 -0
  32. package/lib/instrumentation-security/hooks/require/nr-require.js +93 -0
  33. package/lib/instrumentation-security/hooks/restify/nr-restify.js +104 -0
  34. package/lib/instrumentation-security/hooks/xpath/nr-xpath.js +91 -0
  35. package/lib/instrumentation-security/index.js +171 -0
  36. package/lib/nr-security-agent/index.js +170 -0
  37. package/lib/nr-security-agent/lib/core/Auth-headers.js +58 -0
  38. package/lib/nr-security-agent/lib/core/ContainerProperties.js +42 -0
  39. package/lib/nr-security-agent/lib/core/ECSProperties.js +34 -0
  40. package/lib/nr-security-agent/lib/core/FuzzFailEvent.js +27 -0
  41. package/lib/nr-security-agent/lib/core/LinkingMetadata.js +21 -0
  42. package/lib/nr-security-agent/lib/core/LogMessage.js +47 -0
  43. package/lib/nr-security-agent/lib/core/PodProperties.js +36 -0
  44. package/lib/nr-security-agent/lib/core/Policy.js +105 -0
  45. package/lib/nr-security-agent/lib/core/agent-status.js +56 -0
  46. package/lib/nr-security-agent/lib/core/agent.js +146 -0
  47. package/lib/nr-security-agent/lib/core/applicationinfo.js +634 -0
  48. package/lib/nr-security-agent/lib/core/commonUtils.js +411 -0
  49. package/lib/nr-security-agent/lib/core/connections/aws-lambda-client.js +55 -0
  50. package/lib/nr-security-agent/lib/core/connections/restclient.js +20 -0
  51. package/lib/nr-security-agent/lib/core/connections/websocket/index.js +25 -0
  52. package/lib/nr-security-agent/lib/core/connections/websocket/response/collecotor-policy-error-handler.js +18 -0
  53. package/lib/nr-security-agent/lib/core/connections/websocket/response/collector-policy-handler.js +20 -0
  54. package/lib/nr-security-agent/lib/core/connections/websocket/response/fuzz-request-handler.js +171 -0
  55. package/lib/nr-security-agent/lib/core/connections/websocket/response/index.js +47 -0
  56. package/lib/nr-security-agent/lib/core/connections/websocket/response/no-op-handler.js +12 -0
  57. package/lib/nr-security-agent/lib/core/connections/websocket/response/startup-handshake-handler.js +27 -0
  58. package/lib/nr-security-agent/lib/core/connections/websocket/response/unsupported-agent-handler.js +18 -0
  59. package/lib/nr-security-agent/lib/core/connections/websocket/response/ws-reconnect.js +14 -0
  60. package/lib/nr-security-agent/lib/core/connections/websocket/websocket.js +443 -0
  61. package/lib/nr-security-agent/lib/core/event.js +186 -0
  62. package/lib/nr-security-agent/lib/core/health-check.js +159 -0
  63. package/lib/nr-security-agent/lib/core/json-file-handler.js +66 -0
  64. package/lib/nr-security-agent/lib/core/jsonValidator.js +149 -0
  65. package/lib/nr-security-agent/lib/core/lambda-delegated-task-service.js +90 -0
  66. package/lib/nr-security-agent/lib/core/logging.js +176 -0
  67. package/lib/nr-security-agent/lib/core/sec-agent-constants.js +173 -0
  68. package/lib/nr-security-agent/lib/core/sec-util.js +166 -0
  69. package/lib/nr-security-agent/lib/core/sha-size-util.js +338 -0
  70. package/lib/nr-security-agent/lib/core/sha_worker.js +24 -0
  71. package/lib/nr-security-agent/lib/core/startup-config.js +29 -0
  72. package/lib/nr-security-agent/lib/core/statusUtils.js +157 -0
  73. package/lib/nr-security-agent/lib/core/timeunit.js +44 -0
  74. package/lib/nr-security-agent/lib/core/websocket-client.js +335 -0
  75. package/lib/nr-security-agent/lib/core/worker-entities.js +82 -0
  76. package/lib/nr-security-agent/lib/core/worker.js +148 -0
  77. package/lib/nr-security-agent/lib/core/xss-utils.js +297 -0
  78. package/lib/nr-security-agent/lib/models/lambda-delegated-task/constants.js +12 -0
  79. package/lib/nr-security-agent/lib/models/lambda-delegated-task/index.js +15 -0
  80. package/lib/nr-security-agent/lib/models/lambda-delegated-task/lambda-delegated-sha-calculation.js +37 -0
  81. package/lib/nr-security-agent/lib/models/lambda-delegated-task/lambda-delegated-task-base.js +50 -0
  82. package/lib/nr-security-agent/lib/models/lambda-delegated-task/lambda-delegated-task-type.js +17 -0
  83. package/lib/nr-security-agent/resources/cert.pem +31 -0
  84. package/lib/nr-security-agent/resources/config.js +19 -0
  85. package/lib/nr-security-agent/resources/default-policy.yaml +36 -0
  86. package/lib/nr-security-api/index.js +111 -0
  87. package/package.json +95 -0
@@ -0,0 +1,29 @@
1
+ /*
2
+ * Copyright 2023 New Relic Corporation. All rights reserved.
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */
5
+
6
+ let startupConfig = undefined;
7
+ function StartupConfig(){
8
+
9
+ }
10
+ StartupConfig.prototype.constructor = StartupConfig;
11
+
12
+ /**
13
+ * Returns the current instanceof CollectorConfig,
14
+ * creates one if not already created.
15
+ *
16
+ * @returns {StartupConfig} instance
17
+ */
18
+ function getInstance() {
19
+ if (!startupConfig) {
20
+ startupConfig = new StartupConfig();
21
+ startupConfig.config = {};
22
+
23
+ }
24
+ return startupConfig;
25
+ }
26
+
27
+ module.exports = {
28
+ getInstance
29
+ };
@@ -0,0 +1,157 @@
1
+ /*
2
+ * Copyright 2023 New Relic Corporation. All rights reserved.
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */
5
+
6
+ /* eslint-disable new-cap */
7
+
8
+ const njsAgentConstants = require('./sec-agent-constants');
9
+ const path = require('path').resolve(__dirname, '../../');
10
+ const lodash = require('lodash');
11
+
12
+ let errors = [];
13
+
14
+ const ringBuffer = require('ringbufferjs');
15
+ const bufferedHC = new ringBuffer(5);
16
+ const bufferedErrors = new ringBuffer(5);
17
+ const fs = require('fs');
18
+ const util = require('util');
19
+ let HC = [];
20
+ let lastHC = {};
21
+ const logs = require('./logging');
22
+ const commonUtils = require('./commonUtils');
23
+ const logger = logs.getLogger();
24
+ const statusFile = njsAgentConstants.STATUS_LOG_FILE;
25
+
26
+ const statusTemplate = 'Snapshot timestamp: : %s\n' +
27
+ `CSEC Agent start timestamp: ${njsAgentConstants.AGENT_START_TIME} with application uuid:${commonUtils.getUUID()}\n` +
28
+ `SEC_HOME: ${njsAgentConstants.CSEC_HOME}\n` +
29
+ `Agent location: ${path}\n` +
30
+ `Using CSEC Agent for Node.js, Node version:${process.version}, PID:${process.pid}\n` +
31
+ `Process title: ${process.title}\n` +
32
+ `Process binary: ${process.execPath}\n` +
33
+ 'Application location: %s\n' +
34
+ `Current working directory: ${process.cwd()}\n` +
35
+ `Agent mode: ${commonUtils.getCSECmode()}\n` +
36
+ 'Application server: %s\n' +
37
+ 'Application Framework: %s\n' +
38
+ `Websocket connection to Prevent Web: ${commonUtils.getValidatorServiceEndpointURL()}, Status: %s\n` +
39
+ 'Instrumentation successful:\n' +
40
+ 'Tracking loaded modules in the application:\n' +
41
+ 'Policy applied successfully. Policy version is: %s\n' +
42
+ 'Started Health Check for Agent\n' +
43
+ 'Started Inbound and Outbound monitoring \n' +
44
+ '\nProcess stats:\n%s\n' +
45
+ '\nService stats:\n%s\n' +
46
+ '\nLast 5 errors: \n%s\n' +
47
+ '\nLast 5 Health Checks are:\n %s \n';
48
+
49
+ /**
50
+ * Utility to add hc in hc buffer
51
+ * @param {*} healthCheck
52
+ */
53
+ function addHCtoBuffer (healthCheck) {
54
+ try {
55
+ bufferedHC.enq(healthCheck);
56
+ lastHC = healthCheck;
57
+ } catch (error) {
58
+ logger.debug(error);
59
+ }
60
+ }
61
+
62
+ /**
63
+ * Utility to add error object in error buffer
64
+ * @param {*} error
65
+ */
66
+ function addErrortoBuffer (error) {
67
+ try {
68
+ bufferedErrors.enq(error);
69
+ } catch (error) {
70
+ logger.debug(error);
71
+ }
72
+ }
73
+
74
+ /**
75
+ * utility to format status template with dynamic values
76
+ */
77
+ function getFormattedData () {
78
+ const Agent = require('./agent').Agent.getAgent();
79
+ const appInfo = Agent.applicationInfo;
80
+ const deployedApplications = appInfo && appInfo.serverInfo && appInfo.serverInfo.deployedApplications;
81
+ const appLoc = deployedApplications[0].deployedPath;
82
+ const formattedSnapshot = util.format(statusTemplate, new Date().toString(), appLoc, appInfo.serverInfo.name, njsAgentConstants.FRAMEWORK, process.env.WS_HEALTH, appInfo.policyVersion, getKeyValPairs(lastHC.stats), getKeyValPairs(lastHC.serviceStatus), JSON.stringify(getBufferedErrors()), JSON.stringify(getBufferedHC()));
83
+ return formattedSnapshot;
84
+ }
85
+
86
+ /**
87
+ * utility to write snapshot in snapshot file
88
+ */
89
+ function writeSnapshot () {
90
+ const snapshot = getFormattedData();
91
+ commonUtils.removeOlderSnapshots();
92
+ fs.writeFile(statusFile, snapshot, { mode: 0o777 }, function (err) {
93
+ if (err) {
94
+ logger.error(err);
95
+ } else {
96
+ logger.info('Snapshot updated to file: %s', statusFile);
97
+ fs.chmod(statusFile, 0o777, (err) => {
98
+ if (err) {
99
+ addErrortoBuffer(err);
100
+ }
101
+ });
102
+ }
103
+ });
104
+ }
105
+ /**
106
+ * return buffered error instance.
107
+ */
108
+ function getRingBufferedErrors () {
109
+ return bufferedErrors;
110
+ }
111
+
112
+ /**
113
+ * return buffered HC list without null, undefined
114
+ */
115
+ function getBufferedHC () {
116
+ try {
117
+ HC = lodash.compact(bufferedHC._elements);
118
+ } catch (error) {
119
+ logger.debug(error);
120
+ }
121
+
122
+ return HC;
123
+ }
124
+ /**
125
+ * returns buffered error list without null, undefined
126
+ */
127
+ function getBufferedErrors () {
128
+ try {
129
+ errors = lodash.compact(bufferedErrors._elements);
130
+ } catch (error) {
131
+ logger.debug(error);
132
+ }
133
+ return errors;
134
+ }
135
+
136
+ /**
137
+ * Utility to get key val pairs from json object
138
+ * @param {*} jsonObject
139
+ */
140
+ function getKeyValPairs (jsonObject) {
141
+ let statStr = njsAgentConstants.EMPTY_STR;
142
+ for (const key in jsonObject) {
143
+ statStr = statStr + key + ': ' + jsonObject[key] + '\n';
144
+ }
145
+ return statStr;
146
+ }
147
+
148
+ module.exports = {
149
+ statusTemplate,
150
+ addHCtoBuffer,
151
+ getFormattedData,
152
+ writeSnapshot,
153
+ addErrortoBuffer,
154
+ getRingBufferedErrors,
155
+ getBufferedHC,
156
+ getBufferedErrors
157
+ };
@@ -0,0 +1,44 @@
1
+
2
+ /*
3
+ * Copyright 2023 New Relic Corporation. All rights reserved.
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+
7
+
8
+ /**
9
+ * Creates TimeUnit Instance with milliseconds
10
+ * as the base unit.
11
+ */
12
+ function TimeUnit() {
13
+ this.MILLISECONDS = 1;
14
+ this.NANOSECONDS = 0.000001
15
+ this.MICROSECONDS = 0.001;
16
+ this.SECONDS = 1000;
17
+ this.MINUTES = 60000;
18
+ this.HOURS = 3600000;
19
+ this.DAY = 86400000;
20
+
21
+ /**
22
+ * converts time value from given unit.
23
+ *
24
+ * @param {Number} value
25
+ * @param {String} timeunit
26
+ *
27
+ * @returns milliseconds
28
+ *
29
+ */
30
+ this.getMillis = function (value, unit, valueOnFail) {
31
+ const UNIT = unit.toString().toUpperCase();
32
+ if (this[UNIT]) {
33
+ try {
34
+ return value * this[UNIT];
35
+ } catch (e) {
36
+
37
+ }
38
+ }
39
+ return valueOnFail;
40
+ }
41
+ }
42
+
43
+ module.exports = new TimeUnit();
44
+
@@ -0,0 +1,335 @@
1
+ /*
2
+ * Copyright 2023 New Relic Corporation. All rights reserved.
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */
5
+
6
+ 'use strict';
7
+ const path = require('path');
8
+ const RingBuffer = require('ringbufferjs');
9
+ const LOG_MESSAGES = require('./sec-agent-constants').LOG_MESSAGES;
10
+
11
+ const { Agent } = require('./agent');
12
+ const AgentStatus = require('./agent-status');
13
+ const hc = require('./health-check');
14
+ const applicationInfo = require('./applicationinfo').getInstance();
15
+ const logger = require('./logging').getLogger(applicationInfo.applicationUUID);
16
+ const initLogger = require('./logging').getInitLogger();
17
+ const { WorkerMessage, WORKER_STATUS } = require('./worker-entities');
18
+ const commonUtils = require('./commonUtils');
19
+ const API = require('../../../nr-security-api');
20
+ const NRAgent = API.getNRAgent();
21
+ const {
22
+ SecWebSocket,
23
+ setWebSocketConn,
24
+ aquireWebSocket,
25
+ ResponseHandler: {
26
+ handle: handleServerResponse,
27
+ setLogger: setResponseHandlerLogger
28
+ }
29
+ } = require('./connections/websocket');
30
+ const { HC_INTERVAL_MS } = require('../../resources/config');
31
+ const { IS_LAMBDA_ENV, LAMBDA_ENABLE_RESPONSE_BLOCKING, LOG_DIR } = require('./sec-agent-constants');
32
+ const statusUtils = require('./statusUtils');
33
+ const njsAgentConstants = require('./sec-agent-constants');
34
+
35
+ const MAX_BUSY_WAIT_TIME = 5000; // ms
36
+ const workerSupported = commonUtils.hasWorker();;
37
+ const filePath = path.join(__dirname, 'worker.js');
38
+ const localQueue = new RingBuffer(1000);
39
+
40
+ let busy = false;
41
+ let wsWorker;
42
+ let wsInstance;
43
+ let dispatcher;
44
+
45
+ const DEFAULT_EVENT_SEND_CB = err => {
46
+ if (err) {
47
+ hc.getInstance().registerEventDrop();
48
+ logger.debug(err);
49
+ }
50
+ };
51
+
52
+ /**
53
+ * Initializes the Websocket connection to Validator.
54
+ */
55
+ const initialize = function () {
56
+ // we would want that the websocket be
57
+ // initialized once only. All ws reconnection
58
+ // and recovery mechanisms must be handled by
59
+ // the SecWebSocket internally.
60
+ if (dispatcher) {
61
+ logger.warn("Websocket must be initialized only once");
62
+ obeyReconnect();
63
+ return;
64
+ }
65
+
66
+ setResponseHandlerLogger(logger);
67
+
68
+ if (workerSupported) {
69
+ initiateInWorkerThread();
70
+ } else {
71
+ initializeInMainThread();
72
+ }
73
+ // we'll dispatch the application info if it is updated
74
+ Agent.eventEmitter.on(Agent.EVENTS.APPLICATION_INFO_UPDATE_EVENT, (applicationInfo) => {
75
+ if (!NRAgent || (NRAgent && applicationInfo.entityGuid)) {
76
+ dispatcher(applicationInfo);
77
+ }
78
+ });
79
+ Agent.eventEmitter.on(Agent.EVENTS.RECONNECT_WS_EVENT, () => {
80
+ setWebSocketConn();
81
+ if (workerSupported) {
82
+ const reConnectMsg = new WorkerMessage(WorkerMessage.TYPE.RECONNECT, {});
83
+ wsWorker.postMessage(reConnectMsg);
84
+ } else {
85
+ wsInstance.reconnect();
86
+ }
87
+ });
88
+ // Initiate HC send routine in the provided hcInterval.
89
+ initLogger.info(LOG_MESSAGES.SCHED_SERVICE_START);
90
+ initLogger.info(LOG_MESSAGES.START_HC);
91
+
92
+ setTimeout(() => {
93
+ setInterval(sendHC, HC_INTERVAL_MS);
94
+ initLogger.info(LOG_MESSAGES.END_HC);
95
+ sendHC();
96
+ }, 30000);
97
+
98
+ setInterval(commonUtils.logRollOver, 30000);
99
+ };
100
+
101
+ /**
102
+ * This initiates the ws in main thread
103
+ */
104
+ function initializeInMainThread() {
105
+ logger.info(LOG_MESSAGES.NODE_VERSION_MSG, process.version);
106
+ if (!wsInstance) {
107
+ const validatorService = commonUtils.getValidatorServiceEndpointURL();
108
+ wsInstance = new SecWebSocket(validatorService, {}, logger);
109
+ dispatcher = function dispatcher(message) {
110
+ wsInstance.dispatch(message);
111
+ };
112
+
113
+ // Setup the event listeners
114
+ wsInstance.event.on(SecWebSocket.Events.BUSY, function () {
115
+ busy = true;
116
+ });
117
+ wsInstance.event.on(SecWebSocket.Events.INACTIVE, function () {
118
+ busy = false;
119
+ });
120
+ } else {
121
+ return wsInstance;
122
+ }
123
+ }
124
+
125
+ /**
126
+ * This initiates the ws in worker thread
127
+ */
128
+ function initiateInWorkerThread() {
129
+ if (workerSupported) {
130
+ process.env.WS_WORKER_STATUS = WORKER_STATUS.INITIALIZING;
131
+ try {
132
+ setWebSocketConn();
133
+ const { Worker, SHARE_ENV } = require('worker_threads');
134
+ wsWorker = new Worker(filePath, {
135
+ workerData: {
136
+ applicationInfo
137
+ },
138
+ env: SHARE_ENV
139
+ });
140
+ wsWorker.on('message', handleWorkerMessage);
141
+ wsWorker.on('error', (err) => {
142
+ logger.error('Exception in web socket worker:', err.message);
143
+ wsWorker = new Worker(filePath, {
144
+ workerData: {
145
+ applicationInfo
146
+ }, env: SHARE_ENV
147
+ });
148
+ });
149
+ dispatcher = function dispatcher(message) {
150
+ if (process.env.WS_WORKER_STATUS !== WORKER_STATUS.RUNNING) {
151
+ localQueue.enq(message);
152
+ return;
153
+ }
154
+ // websocket is aquired here and then
155
+ // released in worker thread when the
156
+ // handoff to websocket is confirmed
157
+ aquireWebSocket();
158
+ const msg = new WorkerMessage(WorkerMessage.TYPE.MESSAGE, message);
159
+ wsWorker.postMessage(msg);
160
+ };
161
+ logger.info(LOG_MESSAGES.NODE_VERSION_MSG_WORKER, process.version);
162
+ } catch (error) {
163
+ logger.debug('error is:', error);
164
+ }
165
+ }
166
+ }
167
+
168
+ /**
169
+ * This handles any messages received from worker
170
+ * if websocket worker is initialized
171
+ *
172
+ * @param {JSON} json
173
+ */
174
+ function handleWorkerMessage(json) {
175
+ const msg = WorkerMessage.parseFromObject(json);
176
+ switch (msg.type) {
177
+ case WorkerMessage.TYPE.MESSAGE: {
178
+ logger.debug(LOG_MESSAGES.MSG_FROM_WORKKER, msg.getPayload());
179
+ handleServerResponse(msg.getPayload());
180
+ break;
181
+ }
182
+ case WorkerMessage.TYPE.FLUSH: {
183
+ const { status } = msg.getPayload();
184
+ if (status === 'flushed') {
185
+ logger.debug('Message from worker thread: Flush Completed');
186
+ }
187
+ break;
188
+ }
189
+ case WorkerMessage.TYPE.IC_READY_FOR_EVENTS: {
190
+ break;
191
+ }
192
+ case WorkerMessage.TYPE.BUSY: {
193
+ busy = true;
194
+ break;
195
+ }
196
+ case WorkerMessage.TYPE.INACTIVE: {
197
+ busy = false;
198
+ break;
199
+ }
200
+ case WorkerMessage.TYPE.ERROR: {
201
+ statusUtils.addErrortoBuffer(msg.getPayload().stack);
202
+ break;
203
+ }
204
+ default:
205
+ }
206
+ }
207
+
208
+ /**
209
+ * Sends Agent HelthCheck to Validator.
210
+ */
211
+ const sendHC = async function () {
212
+ if (AgentStatus.getInstance().getStatus() === AgentStatus.CSECAgentStatus.codes.ACTIVE && (NRAgent ? (NRAgent.config.security.enabled && NRAgent.canCollectData()) : true)) {
213
+ let json = hc.getInstance().get();
214
+ json = JSON.parse(json);
215
+ json.policyVersion = applicationInfo.policyVersion;
216
+ json.entityGuid = applicationInfo.entityGuid;
217
+ try {
218
+ json.stats = await commonUtils.getHCStats();
219
+ } catch (error) {
220
+ logger.error(error);
221
+ }
222
+
223
+ json.serviceStatus = {};
224
+ json.serviceStatus.websocket = process.env.WS_HEALTH;
225
+ json.serviceStatus.logWriter = await commonUtils.isLogAccessible(`${LOG_DIR}node-security-collector.log`);
226
+ json.serviceStatus.initLogWriter = await commonUtils.isLogAccessible(`${LOG_DIR}node-security-collector-init.log`);
227
+ json.serviceStatus.statusLogWriter = await commonUtils.isLogAccessible(njsAgentConstants.STATUS_LOG_FILE);
228
+ json.serviceStatus.agentActiveStat = commonUtils.isAgentActiveState();
229
+ json.serviceStatus.iastRestClient = commonUtils.iastRestClientStatus();
230
+
231
+ hc.getInstance().resetDropCount();
232
+ hc.getInstance().resetProcessedCount();
233
+ hc.getInstance().resetEventSentCount();
234
+ hc.getInstance().resetHttpRequestCount();
235
+
236
+ logger.info('Health Check Status:', JSON.stringify(json));
237
+ statusUtils.addHCtoBuffer(json);
238
+ statusUtils.writeSnapshot();
239
+ getDispatcherAndSendEvent(json);
240
+ }
241
+ };
242
+
243
+ /**
244
+ * Will send event asyncronously.
245
+ *
246
+ * @param {JSON} eventJson
247
+ */
248
+ function getDispatcherAndSendEvent(eventJson) {
249
+ const eventType = eventJson.jsonName;
250
+ if(eventType==='Event'){
251
+ hc.getInstance().registerEventProcessed();
252
+ }
253
+
254
+ dispatcher(eventJson);
255
+
256
+ if(eventType==='Event'){
257
+ hc.getInstance().registerEventSent();
258
+ }
259
+
260
+ }
261
+
262
+ /**
263
+ * Sends passed Event to Validator.
264
+ *
265
+ * @param {Event} event
266
+ * @param {Function} callback (optional)
267
+ */
268
+ function sendEvent(event, callback = DEFAULT_EVENT_SEND_CB) {
269
+ dispatcher(event);
270
+ callback();
271
+ };
272
+
273
+ /**
274
+ * Flushes local queue to the worker
275
+ */
276
+ function flushLocalQueue() {
277
+ if (!workerSupported) return;
278
+
279
+ while (!localQueue.isEmpty()) {
280
+ dispatcher(localQueue.deq());
281
+ }
282
+ }
283
+
284
+ /**
285
+ * Waits for websocket to get idel before
286
+ * exiting the lambda function
287
+ * @param {Number} startTime
288
+ */
289
+ function busyWaitOnWorkerThread(startTime = Date.now()) {
290
+ if (!workerSupported) return;
291
+
292
+ const workerInitiatedOnWait = process.env.WS_WORKER_STATUS === WORKER_STATUS.RUNNING;
293
+ const enableWait = !IS_LAMBDA_ENV || process.env[LAMBDA_ENABLE_RESPONSE_BLOCKING] === 'true';
294
+
295
+ let flushed = false;
296
+ let wait = (
297
+ process.env.CSEC_WS_STATE === SecWebSocket.States.CONNECTING ||
298
+ (
299
+ enableWait &&
300
+ process.env.CSEC_WS_STATE === SecWebSocket.States.BUSY
301
+ )
302
+ ) && (startTime + MAX_BUSY_WAIT_TIME > Date.now());
303
+ while (wait) {
304
+ wait = (
305
+ process.env.CSEC_WS_STATE === SecWebSocket.States.CONNECTING ||
306
+ (
307
+ enableWait &&
308
+ process.env.CSEC_WS_STATE === SecWebSocket.States.BUSY
309
+ )
310
+ ) && (startTime + MAX_BUSY_WAIT_TIME > Date.now());
311
+
312
+ if (!flushed && !workerInitiatedOnWait && process.env.WS_WORKER_STATUS === WORKER_STATUS.RUNNING) {
313
+ flushed = true;
314
+ flushLocalQueue();
315
+ }
316
+ }
317
+ }
318
+
319
+ function obeyReconnect(){
320
+ if (workerSupported) {
321
+ const reConnectMsg = new WorkerMessage(WorkerMessage.TYPE.OBEY_RECONNECT, {});
322
+ wsWorker.postMessage(reConnectMsg);
323
+ } else {
324
+ wsInstance.obeyReconnect();
325
+ }
326
+ }
327
+
328
+ module.exports = {
329
+ initialize,
330
+ write: sendEvent,
331
+ dispatcher: getDispatcherAndSendEvent,
332
+ flushLocalQueue,
333
+ busyWaitOnWorkerThread,
334
+ obeyReconnect
335
+ };
@@ -0,0 +1,82 @@
1
+ /*
2
+ * Copyright 2023 New Relic Corporation. All rights reserved.
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */
5
+
6
+ const MESSAGE = 'MESSAGE';
7
+ const FLUSH = 'FLUSH';
8
+ const BUSY = 'BUSY';
9
+ const INACTIVE = 'INACTIVE';
10
+ const RECONNECT = 'RECONNECT';
11
+ const UPDATE_APPLICATION_INFO = 'UPDATE APPLICATION INFO';
12
+ const IC_READY_FOR_EVENTS = 'IC READY FOR EVENTS';
13
+ const INITIALIZING_STATUS = 'initializing';
14
+ const NONE_STATUS = '';
15
+ const RUNNING_STATUS = 'running';
16
+ const ENDED_STATUS = 'ended';
17
+ const ERROR = 'ERROR';
18
+ const OBEY_RECONNECT = 'obey-reconnect';
19
+
20
+ /**
21
+ * This defines and constructs a worker message.
22
+ * @param {String} type
23
+ * @param {Object} payload
24
+ */
25
+ function WorkerMessage (type, payload) {
26
+ this.type = type;
27
+ this.payload = payload;
28
+ }
29
+
30
+ WorkerMessage.prototype = {};
31
+ WorkerMessage.prototype.constructor = WorkerMessage;
32
+
33
+ /**
34
+ * Returns the type of worker message
35
+ */
36
+ WorkerMessage.prototype.getType = function getType () {
37
+ return this.type;
38
+ };
39
+
40
+ /**
41
+ * returns the actual payload of message
42
+ */
43
+ WorkerMessage.prototype.getPayload = function getPayload () {
44
+ return this.payload;
45
+ };
46
+
47
+ WorkerMessage.TYPE = {
48
+ MESSAGE,
49
+ FLUSH,
50
+ BUSY,
51
+ INACTIVE,
52
+ RECONNECT,
53
+ UPDATE_APPLICATION_INFO,
54
+ IC_READY_FOR_EVENTS,
55
+ ERROR,
56
+ OBEY_RECONNECT
57
+
58
+ };
59
+
60
+ /**
61
+ * parses a Worker thread from simple object
62
+ * @param {Object} obj
63
+ */
64
+ WorkerMessage.parseFromObject = function parseFromObject (obj) {
65
+ if (obj && obj.type && obj.payload) {
66
+ return new WorkerMessage(obj.type, obj.payload);
67
+ }
68
+
69
+ return false;
70
+ };
71
+
72
+ const WORKER_STATUS = {
73
+ NONE: NONE_STATUS,
74
+ INITIALIZING: INITIALIZING_STATUS,
75
+ RUNNING: RUNNING_STATUS,
76
+ ENDED: ENDED_STATUS
77
+ };
78
+
79
+ module.exports = {
80
+ WorkerMessage,
81
+ WORKER_STATUS
82
+ };