@contrast/telemetry 1.20.1 → 1.20.3
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/lib/index.js +84 -96
- package/package.json +10 -4
package/lib/index.js
CHANGED
|
@@ -30,17 +30,40 @@ const TELEMETRY_URL = 'https://telemetry.nodejs.contrastsecurity.com/';
|
|
|
30
30
|
const TELEMETRY_VERSION = 'v0'; // TODO: set this to v1 when format is established.
|
|
31
31
|
|
|
32
32
|
/**
|
|
33
|
-
* @param {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
33
|
+
* @param {import("@contrast/core").Core} core
|
|
34
|
+
*/
|
|
35
|
+
async function getIds(core) {
|
|
36
|
+
const { Host: { Docker: { containerID: containerId } } } = await core.getSystemInfo();
|
|
37
|
+
let applicationId, instance;
|
|
38
|
+
|
|
39
|
+
try {
|
|
40
|
+
const hash = createHash('sha256').update(getMac());
|
|
41
|
+
if (containerId) hash.update(containerId);
|
|
42
|
+
instance = hash.copy().digest('hex');
|
|
43
|
+
applicationId = hash.update(core.appInfo.name).digest('hex');
|
|
44
|
+
} catch {
|
|
45
|
+
// If getMac fails we fall back to generating a UUID. "Unstable"
|
|
46
|
+
// identifiers such as these are prefixed with an underscore.
|
|
47
|
+
let id = randomUUID();
|
|
48
|
+
if (containerId) {
|
|
49
|
+
id += `_${containerId}`;
|
|
50
|
+
}
|
|
51
|
+
applicationId = instance = `_${id}`;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return { applicationId, containerId, instance };
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* @param {import('@contrast/core').Core & {
|
|
37
59
|
* config: import('@contrast/config').Config,
|
|
38
60
|
* logger: import('@contrast/logger').Logger,
|
|
39
61
|
* messages: import('@contrast/common').Messages,
|
|
62
|
+
* telemetry?: import('@contrast/common').Installable
|
|
40
63
|
* }} core
|
|
41
64
|
* @returns {import('@contrast/common').Installable}
|
|
42
65
|
*/
|
|
43
|
-
module.exports = function(core) {
|
|
66
|
+
module.exports = function (core) {
|
|
44
67
|
const {
|
|
45
68
|
agentName,
|
|
46
69
|
agentVersion,
|
|
@@ -50,58 +73,48 @@ module.exports = function(core) {
|
|
|
50
73
|
messages,
|
|
51
74
|
} = core;
|
|
52
75
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
tags: {
|
|
60
|
-
applicationId,
|
|
61
|
-
isCustomerEnv: true,
|
|
62
|
-
osArch: appInfo.os.architecture,
|
|
63
|
-
osPlatform: appInfo.os.platform,
|
|
64
|
-
osRelease: appInfo.os.release,
|
|
65
|
-
isContainer: !!appInfo.containerId, // TODO: this is undefined
|
|
66
|
-
agent: agentName,
|
|
67
|
-
agentVersion,
|
|
68
|
-
isAssess: config.getEffectiveValue('assess.enable'),
|
|
69
|
-
isProtect: config.getEffectiveValue('protect.enable'),
|
|
70
|
-
nodeVersion: appInfo.nodeVersion,
|
|
71
|
-
telemetryVersion: TELEMETRY_VERSION,
|
|
72
|
-
},
|
|
73
|
-
isEnabled() {
|
|
74
|
-
return (
|
|
75
|
-
process.env.CONTRAST_AGENT_TELEMETRY_OPTOUT !== 'true' &&
|
|
76
|
-
process.env.CONTRAST_AGENT_TELEMETRY_OPTOUT !== '1'
|
|
77
|
-
);
|
|
78
|
-
},
|
|
79
|
-
install() {
|
|
80
|
-
if (!telemetry.isEnabled()) {
|
|
76
|
+
return core.telemetry = {
|
|
77
|
+
async install() {
|
|
78
|
+
if (
|
|
79
|
+
process.env.CONTRAST_AGENT_TELEMETRY_OPTOUT === 'true' ||
|
|
80
|
+
process.env.CONTRAST_AGENT_TELEMETRY_OPTOUT === '1'
|
|
81
|
+
) {
|
|
81
82
|
logger.info('Telemetry opt-out in effect. All usage data collection is suppressed.');
|
|
82
83
|
return;
|
|
83
84
|
}
|
|
84
85
|
|
|
85
86
|
logger.info(DISCLAIMER);
|
|
86
87
|
|
|
87
|
-
|
|
88
|
+
const { instance, containerId, applicationId } = await getIds(core);
|
|
89
|
+
const tags = {
|
|
90
|
+
applicationId,
|
|
91
|
+
isCustomerEnv: true,
|
|
92
|
+
osArch: appInfo.os.architecture,
|
|
93
|
+
osPlatform: appInfo.os.platform,
|
|
94
|
+
osRelease: appInfo.os.release,
|
|
95
|
+
isContainer: !!containerId,
|
|
96
|
+
agent: agentName,
|
|
97
|
+
agentVersion,
|
|
98
|
+
isAssess: config.getEffectiveValue('assess.enable'),
|
|
99
|
+
isProtect: config.getEffectiveValue('protect.enable'),
|
|
100
|
+
nodeVersion: appInfo.nodeVersion,
|
|
101
|
+
telemetryVersion: TELEMETRY_VERSION,
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
const client = axios.create({
|
|
88
105
|
baseURL: new URL('/api/v1/telemetry/metrics/node', TELEMETRY_URL).href,
|
|
89
106
|
headers: {
|
|
90
107
|
'User-Agent': `${agentName}/${agentVersion}`,
|
|
91
108
|
}
|
|
92
109
|
});
|
|
93
110
|
|
|
94
|
-
telemetry.startup();
|
|
95
|
-
},
|
|
96
|
-
|
|
97
|
-
async startup() {
|
|
98
111
|
try {
|
|
99
112
|
const { external, heapTotal, heapUsed, rss } = process.memoryUsage();
|
|
100
|
-
await
|
|
113
|
+
await client.post('/startup', [
|
|
101
114
|
{
|
|
102
115
|
timestamp: new Date().toISOString(),
|
|
103
|
-
instance
|
|
104
|
-
tags
|
|
116
|
+
instance,
|
|
117
|
+
tags,
|
|
105
118
|
fields: {
|
|
106
119
|
numCpus: os.cpus().length,
|
|
107
120
|
memTotal: os.totalmem(),
|
|
@@ -116,66 +129,41 @@ module.exports = function(core) {
|
|
|
116
129
|
} catch (err) {
|
|
117
130
|
logger.error({ err }, 'error occurred while reporting telemetry: /startup');
|
|
118
131
|
}
|
|
119
|
-
},
|
|
120
|
-
};
|
|
121
132
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
let unsupportedLibs = [];
|
|
128
|
-
messages.on(Event.UNSUPPORTED_LIBRARY, (metadata) => {
|
|
129
|
-
unsupportedLibs.push({
|
|
130
|
-
timestamp: new Date().toISOString(),
|
|
131
|
-
instance: telemetry.instanceId,
|
|
132
|
-
tags: {
|
|
133
|
-
...telemetry.tags,
|
|
134
|
-
name: metadata.name,
|
|
135
|
-
version: metadata.version,
|
|
136
|
-
},
|
|
137
|
-
fields: {
|
|
138
|
-
supported: 0
|
|
139
|
-
}
|
|
140
|
-
});
|
|
141
|
-
});
|
|
133
|
+
messages.on(Event.SERVER_SETTINGS_UPDATE, () => {
|
|
134
|
+
tags.isAssess = config.getEffectiveValue('assess.enable');
|
|
135
|
+
tags.isProtect = config.getEffectiveValue('protect.enable');
|
|
136
|
+
});
|
|
142
137
|
|
|
143
|
-
|
|
144
|
-
|
|
138
|
+
let unsupportedLibs = [];
|
|
139
|
+
messages.on(Event.UNSUPPORTED_LIBRARY, (metadata) => {
|
|
140
|
+
unsupportedLibs.push({
|
|
141
|
+
timestamp: new Date().toISOString(),
|
|
142
|
+
instance,
|
|
143
|
+
tags: {
|
|
144
|
+
...tags,
|
|
145
|
+
name: metadata.name,
|
|
146
|
+
version: metadata.version,
|
|
147
|
+
},
|
|
148
|
+
fields: {
|
|
149
|
+
supported: 0
|
|
150
|
+
}
|
|
151
|
+
});
|
|
152
|
+
});
|
|
145
153
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
} catch (err) {
|
|
149
|
-
logger.error({ err }, 'error occurred while reporting telemetry: /dependencies');
|
|
150
|
-
}
|
|
154
|
+
setInterval(async () => {
|
|
155
|
+
if (unsupportedLibs.length < 1) return;
|
|
151
156
|
|
|
152
|
-
|
|
153
|
-
|
|
157
|
+
try {
|
|
158
|
+
await client.post('/dependencies', unsupportedLibs);
|
|
159
|
+
} catch (err) {
|
|
160
|
+
logger.error({ err }, 'error occurred while reporting telemetry: /dependencies');
|
|
161
|
+
}
|
|
154
162
|
|
|
155
|
-
|
|
163
|
+
unsupportedLibs = [];
|
|
164
|
+
}, 20_000).unref();
|
|
165
|
+
},
|
|
166
|
+
};
|
|
156
167
|
};
|
|
157
168
|
|
|
158
|
-
module.exports.getIds = getIds;
|
|
159
|
-
|
|
160
|
-
function getIds (appInfo) {
|
|
161
|
-
let applicationId, instanceId;
|
|
162
|
-
|
|
163
|
-
try {
|
|
164
|
-
const hash = createHash('sha256').update(getMac());
|
|
165
|
-
if (appInfo.containerId) hash.update(appInfo.containerId);
|
|
166
|
-
instanceId = hash.copy().digest('hex');
|
|
167
|
-
applicationId = hash.update(appInfo.name).digest('hex');
|
|
168
|
-
} catch {
|
|
169
|
-
// If getMac fails we fall back to generating a UUID. "Unstable"
|
|
170
|
-
// identifiers such as these are prefixed with an underscore.
|
|
171
|
-
let id = randomUUID();
|
|
172
|
-
if (appInfo.containerId) {
|
|
173
|
-
id += `_${appInfo.containerId}`;
|
|
174
|
-
}
|
|
175
|
-
applicationId = instanceId = `_${id}`;
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
return { applicationId, instanceId };
|
|
179
|
-
}
|
|
180
|
-
|
|
181
169
|
module.exports.DISCLAIMER = DISCLAIMER;
|
package/package.json
CHANGED
|
@@ -1,9 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@contrast/telemetry",
|
|
3
|
-
"version": "1.20.
|
|
3
|
+
"version": "1.20.3",
|
|
4
4
|
"description": "Telemetry reporting for the Contrast Node.js agent.",
|
|
5
5
|
"license": "SEE LICENSE IN LICENSE",
|
|
6
6
|
"author": "Contrast Security <nodejs@contrastsecurity.com> (https://www.contrastsecurity.com)",
|
|
7
|
+
"files": [
|
|
8
|
+
"lib/",
|
|
9
|
+
"!*.test.*",
|
|
10
|
+
"!tsconfig.*",
|
|
11
|
+
"!*.map"
|
|
12
|
+
],
|
|
7
13
|
"main": "lib/index.js",
|
|
8
14
|
"engines": {
|
|
9
15
|
"npm": ">=6.13.7 <7 || >=8.3.1",
|
|
@@ -14,9 +20,9 @@
|
|
|
14
20
|
},
|
|
15
21
|
"dependencies": {
|
|
16
22
|
"@contrast/common": "1.29.1",
|
|
17
|
-
"@contrast/config": "1.40.
|
|
18
|
-
"@contrast/core": "1.45.
|
|
19
|
-
"@contrast/logger": "1.18.
|
|
23
|
+
"@contrast/config": "1.40.2",
|
|
24
|
+
"@contrast/core": "1.45.2",
|
|
25
|
+
"@contrast/logger": "1.18.2",
|
|
20
26
|
"axios": "^1.7.4",
|
|
21
27
|
"getmac": "^6.3.0"
|
|
22
28
|
}
|