appdynamics 22.3.0 → 22.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.
@@ -1,7 +1,7 @@
1
1
  {
2
- "version": "22.3.0.0",
2
+ "version": "22.5.0.0",
3
3
  "sha": "",
4
4
  "nodeVersion": "",
5
- "buildName": "8455",
5
+ "buildName": "8617",
6
6
  "compatibilityVersion": "4.4.1.0"
7
7
  }
package/lib/core/agent.js CHANGED
@@ -34,6 +34,7 @@ var CpuProfiler = require('../v8/cpu-profiler').CpuProfiler;
34
34
  var HeapProfiler = require('../v8/heap-profiler').HeapProfiler;
35
35
  var agentVersion = require('../../appdynamics_version.json');
36
36
  var appDNativeLoader = require('appdynamics-native');
37
+ var SecureApp = require('../secure_app/secure_app').SecureApp;
37
38
 
38
39
  var LibAgent = require('../libagent/libagent').LibAgent;
39
40
  var LibagentConnector = require('../libagent/libagent-connector').LibagentConnector;
@@ -88,6 +89,7 @@ function Agent() {
88
89
  this.gcStats = new GCStats(this);
89
90
  this.cpuProfiler = new CpuProfiler(this);
90
91
  this.heapProfiler = new HeapProfiler(this);
92
+ this.secureApp = new SecureApp(this);
91
93
 
92
94
  this.libagent = null;
93
95
 
@@ -282,6 +284,10 @@ Agent.prototype.init = function (opts) {
282
284
  self.cpuProfiler.init();
283
285
  self.heapProfiler.init();
284
286
 
287
+ if(self.opts.secureAppEnabled) {
288
+ self.secureApp.init(this);
289
+ }
290
+
285
291
  // Initialize libagent
286
292
  self.backendConnector.intializeAgentHelpers();
287
293
 
@@ -342,6 +348,12 @@ Agent.prototype.initializeOpts = function (opts) {
342
348
  if (self.opts.nodeName === undefined) {
343
349
  self.opts.nodeName = process.env.APPDYNAMICS_AGENT_NODE_NAME;
344
350
  }
351
+ if (self.opts.reuseNode === undefined) {
352
+ self.opts.reuseNode = process.env.APPDYNAMICS_AGENT_REUSE_NODE_NAME;
353
+ }
354
+ if (self.opts.reuseNodePrefix === undefined) {
355
+ self.opts.reuseNodePrefix = process.env.APPDYNAMICS_AGENT_REUSE_NODE_NAME_PREFIX;
356
+ }
345
357
  if (self.opts.analyticsMaxSegmentSizeInBytes === undefined && process.env.APPDYNAMICS_ANALYTICS_MAX_SEGMENT_SIZE) {
346
358
  self.opts.analyticsMaxSegmentSizeInBytes = parseInt(process.env.APPDYNAMICS_ANALYTICS_MAX_SEGMENT_SIZE, 10);
347
359
  }
@@ -5,7 +5,7 @@ const { ROOT_CONTEXT } = require('@opentelemetry/api');
5
5
  const { BatchSpanProcessor, ConsoleSpanExporter, BasicTracerProvider } = require('@opentelemetry/sdk-trace-base');
6
6
  const { OTLPTraceExporter } = require("@opentelemetry/exporter-trace-otlp-proto");
7
7
  const { AsyncHooksContextManager, AsyncLocalStorageContextManager } = require("@opentelemetry/context-async-hooks");
8
- const { ParentBasedSampler, AlwaysOnSampler } = require("@opentelemetry/core");
8
+ const { ParentBasedSampler, AlwaysOnSampler, TraceIdRatioBasedSampler } = require("@opentelemetry/core");
9
9
  const { Resource } = require('@opentelemetry/resources');
10
10
  const { SemanticResourceAttributes } = require('@opentelemetry/semantic-conventions');
11
11
  const url = require('url');
@@ -20,15 +20,23 @@ function TracerProvider(logger) {
20
20
  this.logger = logger;
21
21
  }
22
22
 
23
+ function getSamplerFromConfig(config) {
24
+ if(config.sampler && config.sampler.TraceIdRatioBasedSampler) {
25
+ const ratio = config.sampler.TraceIdRatioBasedSampler.Ratio || 1;
26
+ return new TraceIdRatioBasedSampler(ratio);
27
+ } else {
28
+ return new AlwaysOnSampler();
29
+ }
30
+ }
31
+
23
32
  TracerProvider.prototype.register = function(config) {
24
33
  const provider = new BasicTracerProvider({
25
34
  sampler: new ParentBasedSampler({
26
- root: new AlwaysOnSampler()
35
+ root: getSamplerFromConfig(config.openTelemetry)
27
36
  }),
28
37
  resource: new Resource({
29
38
  [SemanticResourceAttributes.SERVICE_NAME]: config.tierName,
30
- "service.name": config.tierName,
31
- "service.namespace": config.applicationName
39
+ [SemanticResourceAttributes.SERVICE_NAMESPACE]: config.applicationName
32
40
  }),
33
41
  });
34
42
 
@@ -0,0 +1,56 @@
1
+ var path = require('path');
2
+
3
+ const MAX_ITEMS_PER_GROUP = 1024;
4
+
5
+ exports.LibraryMetadata = LibraryMetadata;
6
+ function LibraryMetadata(agent) {
7
+ var self = this;
8
+ self.agent = agent;
9
+ }
10
+
11
+ LibraryMetadata.prototype.init = function() {
12
+ };
13
+
14
+ LibraryMetadata.prototype.getMetadata = function() {
15
+ var self = this;
16
+ if(!self.metadataCache) {
17
+ self.metadataCache = self._getMetadata();
18
+ }
19
+ return self.metadataCache;
20
+ };
21
+
22
+ LibraryMetadata.prototype._getJson = function()
23
+ {
24
+ var rootPath = require('path').resolve('./');
25
+ return require(path.join(rootPath, './package-lock.json'));
26
+ };
27
+
28
+ LibraryMetadata.prototype._getMetadata = function() {
29
+ var self = this;
30
+ try {
31
+ var pkjson = self._getJson();
32
+ var metadataCache = [];
33
+ var cacheGroup = [];
34
+ var itemCount = 0;
35
+ for (var pkg in pkjson.dependencies) {
36
+ if(itemCount == MAX_ITEMS_PER_GROUP) {
37
+ metadataCache.push(cacheGroup);
38
+ cacheGroup = [];
39
+ itemCount = 0;
40
+ }
41
+ cacheGroup.push({
42
+ name: pkg,
43
+ version: pkjson.dependencies[pkg].version
44
+ });
45
+ itemCount = itemCount + 1;
46
+ }
47
+ } catch(error) {
48
+ self.agent.logger.warn('Error reading package metadata ' + error);
49
+ }
50
+
51
+ if(cacheGroup.length) {
52
+ metadataCache.push(cacheGroup);
53
+ }
54
+ return metadataCache;
55
+ };
56
+
@@ -0,0 +1,276 @@
1
+ const http = require('http');
2
+ const https = require('https');
3
+ const url = require('url');
4
+ const HttpsProxyAgent = require('https-proxy-agent');
5
+
6
+ const LibraryMetadata = require('./library_metadata').LibraryMetadata;
7
+ const MessageSender = require('../libagent/message-sender').MessageSender;
8
+
9
+ const AUTH_PATH = "/auth/v1/oauth/token";
10
+ const EVENT_PATH = "/argento-agent/v1/report";
11
+ const REGISTER_PATH = "/argento-agent/v1/management";
12
+
13
+ const MIN_TIMER = 60 * 1000;
14
+ const DAY_TIMER = 24 * 60 * 60 * 1000;
15
+
16
+ exports.SecureApp = SecureApp;
17
+ function SecureApp() {
18
+ }
19
+
20
+ SecureApp.prototype.init = function(agent) {
21
+ var self = this;
22
+ self.agent = agent;
23
+ self.libraryMetadata = new LibraryMetadata(agent);
24
+ if(!process.env.SKIP_AUTH_FOR_TESTS) {
25
+ self.authTimerId = new MessageSender(self.agent, 10 * 1000, MIN_TIMER * 9, function () {
26
+ self.authToken();
27
+ });
28
+ } else {
29
+ self.agent.logger.debug('Secure App skipping auth as SKIP_AUTH_FOR_TESTS is ' + process.env.SKIP_AUTH_FOR_TESTS);
30
+ self.regTimerId = new MessageSender(self.agent, 10 * 1000, MIN_TIMER, function () {
31
+ self.register();
32
+ });
33
+ }
34
+ self.httpModule = (self.agent.opts.controllerSslEnabled) ? https : http;
35
+ self.libraryMetadata.init();
36
+ self.agent.logger.debug('Secure App module initialized');
37
+ };
38
+
39
+ SecureApp.prototype._sendRequest = function(options, data, cb) {
40
+ var self = this;
41
+ self.agent.logger.trace('SecureApp._sendRequest: ' + options.path + " Data: " + ((options.headers['Content-Type'] != 'application/json') ?
42
+ data.length.toString() : JSON.stringify(data).length.toString()));
43
+
44
+ var request = self.httpModule.request(options, function(response) {
45
+ cb(request, response);
46
+ });
47
+
48
+ request.on('error', function(error) {
49
+ self.agent.logger.info('Secure app http request error : ' + error);
50
+ });
51
+ request.end(data);
52
+ };
53
+
54
+ SecureApp.prototype._requestHeaders = function(requestOptions) {
55
+ var self = this;
56
+ requestOptions.headers['Authorization'] = `Bearer ${self.accessToken}`;
57
+ requestOptions.headers['User-Agent'] = "NodeJs";
58
+ requestOptions.headers['appdynamics-agent-applicationName'] = self.agent.opts.applicationName;
59
+ requestOptions.headers['appdynamics-agent-tierName'] = self.agent.opts.tierName;
60
+ requestOptions.headers['appdynamics-agent-nodeName'] = self.agent.opts.nodeName;
61
+ requestOptions.headers['appdynamics-agent-accountName'] = 'singularity-agent@' + self.agent.opts.accountName;
62
+ if (self.uuid) {
63
+ requestOptions.headers['appdynamics-agent-nodeUUID'] = self.uuid;
64
+ }
65
+ };
66
+
67
+ SecureApp.prototype._requestOptions = function(path, length, type) {
68
+ var self = this;
69
+ var requestOptions = {
70
+ 'method': 'POST',
71
+ };
72
+
73
+ requestOptions.headers = {
74
+ 'Content-Length': length,
75
+ 'Content-Type': type
76
+ };
77
+
78
+ if (self.agent.opts.certificateFile) {
79
+ requestOptions['ca'] = self.agent.opts.certificateFile;
80
+ }
81
+
82
+ if(process.env.CONTROLLER_HOST_TEST) {
83
+ self.agent.logger.debug('Secure App using controller hostname CONTROLLER_HOST_TEST: ' + process.env.CONTROLLER_HOST_TEST);
84
+ requestOptions['hostname'] = process.env.CONTROLLER_HOST_TEST;
85
+ } else {
86
+ requestOptions['hostname'] = self.agent.opts.controllerHostName;
87
+ }
88
+ if(process.env.CONTROLLER_PORT_TEST) {
89
+ self.agent.logger.debug('Secure App using controller port CONTROLLER_PORT_TEST: ' + process.env.CONTROLLER_PORT_TEST);
90
+ requestOptions['port'] = process.env.CONTROLLER_PORT_TEST;
91
+ } else {
92
+ requestOptions['port'] = self.agent.opts.controllerPort;
93
+ }
94
+ requestOptions['path'] = path;
95
+
96
+ var proxy = {
97
+ hostName: self.agent.opts.proxyHost,
98
+ port: self.agent.opts.proxyPort,
99
+ userName: self.agent.opts.proxyUser,
100
+ password: ""
101
+ };
102
+
103
+ if (self.agent.opts.proxyPasswordFile) {
104
+ var fs = require('fs');
105
+ proxy.password = (fs.readFileSync(self.agent.opts.proxyPasswordFile, 'utf-8')).trim();
106
+ }
107
+
108
+ if (proxy.hostName) {
109
+ self.agent.logger.debug('Secure App using proxy');
110
+ var ro = requestOptions;
111
+ var proxyAuth = proxy.userName && proxy.password && Buffer.from(`${proxy.userName}:${proxy.password}`).toString('base64');
112
+
113
+ if (self.agent.opts.controllerSslEnabled) {
114
+ var proxyUrl = `http://${proxy.hostName}:${proxy.port}`;
115
+ var proxyOpts = url.parse(proxyUrl);
116
+ if (proxyAuth) {
117
+ proxyOpts.headers = {
118
+ 'Proxy-Authentication': `Basic ${proxyAuth}`
119
+ };
120
+ }
121
+ var agent = new HttpsProxyAgent(proxyOpts);
122
+ ro['agent'] = agent;
123
+ } else {
124
+ ro['path'] = `http://${ro.hostname}:${ro.port}${ro.path}`;
125
+ ro['headers']['Host'] = `${ro.hostname}:${ro.port}`;
126
+ ro['hostname'] = proxy.hostName;
127
+ ro['port'] = proxy.port;
128
+ if (proxyAuth) {
129
+ ro['headers']['Proxy-Authorization'] = `Basic ${proxyAuth}`;
130
+ }
131
+ }
132
+ }
133
+ return requestOptions;
134
+ };
135
+
136
+ SecureApp.prototype._initializeTimers = function() {
137
+ var self = this;
138
+ if (self.timersInitialized) {
139
+ return;
140
+ }
141
+ self.timersInitialized = true;
142
+
143
+ self.reportEventTimerId = new MessageSender(self.agent, 10 * 1000, DAY_TIMER, function () {
144
+ self.reportEvents();
145
+ });
146
+ };
147
+
148
+ SecureApp.prototype.authenticate = function(grantType) {
149
+ var self = this;
150
+ var postData = "password=" + self.agent.opts.accountAccessKey +
151
+ "&username=" + 'singularity-agent@' + self.agent.opts.accountName +
152
+ "&grant_type=" + grantType;
153
+
154
+ if(grantType == 'refresh_token') {
155
+ postData += '&refresh_token=' + self.refreshToken;
156
+ }
157
+
158
+ var requestOptions = self._requestOptions(AUTH_PATH, postData.length.toString(),
159
+ "application/x-www-form-urlencoded; charset=utf-8");
160
+
161
+ self._sendRequest(requestOptions, postData, function(request, response) {
162
+ var statusCode = response.statusCode | 0;
163
+ if (statusCode != 200 || response.is_error) {
164
+ self.agent.logger.info('Secure App authentication failed');
165
+ return;
166
+ }
167
+
168
+ const chunks = [];
169
+ response.on('data', data => chunks.push(data));
170
+ response.on('end', () => {
171
+ let body = Buffer.concat(chunks);
172
+ body = JSON.parse(body);
173
+ if (!self.accessToken) {
174
+ self.regTimerId = new MessageSender(self.agent, 10 * 1000, MIN_TIMER, function () {
175
+ self.register();
176
+ });
177
+ }
178
+
179
+ self.accessToken = body.access_token;
180
+ self.refreshToken = body.refresh_token;
181
+
182
+ self.agent.logger.debug('Secure App module authenticated');
183
+ });
184
+ });
185
+ };
186
+
187
+ SecureApp.prototype.authToken = function() {
188
+ var self = this;
189
+ if(!self.accessToken) {
190
+ self.authenticate("password");
191
+ } else {
192
+ self.authenticate("refresh_token");
193
+ }
194
+ };
195
+
196
+ SecureApp.prototype.register = function() {
197
+ var self = this;
198
+ var postData = JSON.stringify({
199
+ "message_type": 0,
200
+ "app": self.agent.opts.applicationName,
201
+ "tier": self.agent.opts.tierName,
202
+ "node": self.agent.opts.nodeName,
203
+ "access_key": self.agent.opts.accountAccessKey,
204
+ "account_name": self.agent.opts.accountName,
205
+ "file_name": "",
206
+ "epoch_msec": 0,
207
+ "force": false,
208
+ "version": 1,
209
+ "is_started": true,
210
+ "is_enabled": true,
211
+ "agent_type": "NodeJs",
212
+ "agent_build_version": ""
213
+ });
214
+
215
+ var requestOptions = self._requestOptions(REGISTER_PATH, postData.length.toString(), "application/json");
216
+ self._requestHeaders(requestOptions);
217
+
218
+ self._sendRequest(requestOptions, postData, function(request, response) {
219
+ var statusCode = response.statusCode | 0;
220
+ if (statusCode != 200 || response.is_error) {
221
+ self.agent.logger.info('Secure App module registeration failed');
222
+ return;
223
+ }
224
+ const chunks = [];
225
+ response.on('data', data => chunks.push(data));
226
+ response.on('end', () => {
227
+ let body = Buffer.concat(chunks);
228
+ body = JSON.parse(body);
229
+ self.uuid = body.node_uuid;
230
+ self._initializeTimers();
231
+ self.agent.logger.debug('Secure App module registered');
232
+ });
233
+ });
234
+ };
235
+
236
+ SecureApp.prototype.sendVulnerabilityEvent = function() {
237
+ var self = this;
238
+ if(!self.vulnerabilityEvent) {
239
+ return;
240
+ }
241
+
242
+ self.vulnerabilityEvent.forEach((data, index) => {
243
+ var isDone = index == self.vulnerabilityEvent.length - 1 ? true : false;
244
+ var postData = JSON.stringify({
245
+ "id": 0,
246
+ "is_done": isDone,
247
+ "fragment_index": index,
248
+ "max_fragments": self.vulnerabilityEvent.length,
249
+ "nodejs_report_component_vulnerability_list": data
250
+ });
251
+ var requestOptions = self._requestOptions(EVENT_PATH, postData.length.toString(), "application/json");
252
+ self._requestHeaders(requestOptions);
253
+
254
+ self._sendRequest(requestOptions, postData, function(request, response) {
255
+ var statusCode = response.statusCode | 0;
256
+ if (statusCode != 200 || response.is_error) {
257
+ self.agent.logger.info('Secure App module vulnerability event failed');
258
+ return;
259
+ }
260
+
261
+ const chunks = [];
262
+ response.on('data', data => chunks.push(data));
263
+ response.on('end', () => {
264
+ self.agent.logger.info('Secure App module vulnerability event sent fragment');
265
+ });
266
+ });
267
+ });
268
+ };
269
+
270
+ SecureApp.prototype.reportEvents = function() {
271
+ var self = this;
272
+ if(!self.vulnerabilityEvent) {
273
+ self.vulnerabilityEvent = self.libraryMetadata.getMetadata();
274
+ }
275
+ self.sendVulnerabilityEvent();
276
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "appdynamics",
3
- "version": "22.3.0",
3
+ "version": "22.5.0",
4
4
  "description": "Performance Profiler and Monitor",
5
5
  "author": "AppDynamics, Inc.",
6
6
  "homepage": "https://www.appdynamics.com",
@@ -42,11 +42,12 @@
42
42
  "@opentelemetry/sdk-trace-base": "~1.0.1",
43
43
  "@opentelemetry/semantic-conventions": "~1.0.1",
44
44
  "cls-hooked": "4.2.2",
45
+ "https-proxy-agent": "^5.0.0",
45
46
  "uuid": "^8.3.2",
46
47
  "y18n": "^5.0.8",
47
- "appdynamics-libagent-napi": "https://cdn.appdynamics.com/packages/nodejs/22.3.0.0/appdynamics-libagent-napi-node.tgz",
48
- "appdynamics-native": "https://cdn.appdynamics.com/packages/nodejs/22.3.0.0/appdynamics-native-node.tgz",
49
- "appdynamics-protobuf": "https://cdn.appdynamics.com/packages/nodejs/22.3.0.0/appdynamics-protobuf-node.tgz"
48
+ "appdynamics-libagent-napi": "https://cdn.appdynamics.com/packages/nodejs/22.5.0.0/appdynamics-libagent-napi-node.tgz",
49
+ "appdynamics-native": "https://cdn.appdynamics.com/packages/nodejs/22.5.0.0/appdynamics-native-node.tgz",
50
+ "appdynamics-protobuf": "https://cdn.appdynamics.com/packages/nodejs/22.5.0.0/appdynamics-protobuf-node.tgz"
50
51
  },
51
52
  "engines": {
52
53
  "node": ">=12 <=v16.*"
package/packageBck.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "appdynamics",
3
- "version": "22.3.0",
3
+ "version": "22.5.0",
4
4
  "description": "Performance Profiler and Monitor",
5
5
  "author": "AppDynamics, Inc.",
6
6
  "homepage": "https://www.appdynamics.com",
@@ -42,11 +42,12 @@
42
42
  "@opentelemetry/sdk-trace-base": "~1.0.1",
43
43
  "@opentelemetry/semantic-conventions": "~1.0.1",
44
44
  "cls-hooked": "4.2.2",
45
+ "https-proxy-agent": "^5.0.0",
45
46
  "uuid": "^8.3.2",
46
47
  "y18n": "^5.0.8",
47
- "appdynamics-libagent-napi": "https://cdn.appdynamics.com/packages/nodejs/22.3.0.0/appdynamics-libagent-napi-node.tgz",
48
- "appdynamics-native": "https://cdn.appdynamics.com/packages/nodejs/22.3.0.0/appdynamics-native-node.tgz",
49
- "appdynamics-protobuf": "https://cdn.appdynamics.com/packages/nodejs/22.3.0.0/appdynamics-protobuf-node.tgz"
48
+ "appdynamics-libagent-napi": "https://cdn.appdynamics.com/packages/nodejs/22.5.0.0/appdynamics-libagent-napi-node.tgz",
49
+ "appdynamics-native": "https://cdn.appdynamics.com/packages/nodejs/22.5.0.0/appdynamics-native-node.tgz",
50
+ "appdynamics-protobuf": "https://cdn.appdynamics.com/packages/nodejs/22.5.0.0/appdynamics-protobuf-node.tgz"
50
51
  },
51
52
  "engines": {
52
53
  "node": ">=12 <=v16.*"