@contrast/agent 4.22.0 → 4.22.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.
@@ -103,18 +103,25 @@ module.exports = class CallContext {
103
103
  return !!(str && typeof str === 'object' && str[PROXY_TARGET]);
104
104
  }
105
105
 
106
- static getDisplayRange(arg) {
106
+ static getDisplayRange(arg, orgArg = arg, iteration = 0) {
107
107
  if (tracker.getData(arg)) {
108
108
  return new TagRange(0, arg.length - 1, 'untrusted');
109
109
  }
110
110
 
111
111
  if (arg && typeof arg === 'object') {
112
112
  for (const key in arg) {
113
+ if (arg[key] && typeof arg[key] === 'object' && iteration < 5) {
114
+ const nestedDisplayRange = CallContext.getDisplayRange(arg[key], orgArg, iteration += 1);
115
+ if (!_.isEmpty(nestedDisplayRange)) {
116
+ return nestedDisplayRange;
117
+ }
118
+ }
113
119
  const trackedData = tracker.getData(arg[key]);
114
- if (trackedData) {
120
+ if (trackedData && trackedData.tagRanges.length > 0) {
115
121
  const { start, stop } = trackedData.tagRanges[0];
122
+ const offset = Array.isArray(orgArg) ? 2 : 0;
116
123
  const taintedString = arg[key].substring(start, stop + 1);
117
- const taintRangeStart = CallContext.valueString(arg).indexOf(taintedString);
124
+ const taintRangeStart = CallContext.valueString(orgArg).indexOf(taintedString) + offset;
118
125
  if (taintRangeStart === -1) {
119
126
  // If tracked string is not in the abbreviated stringified obj, disable highlighting
120
127
  return new TagRange(0, 0, 'disable-highlighting');
@@ -178,9 +185,9 @@ module.exports = class CallContext {
178
185
  return value.toString();
179
186
  }
180
187
 
181
- const constructorName = _.get(value, 'constructor.name', 'null');
188
+ const type = _.get(value, 'constructor.name', 'null');
182
189
 
183
- if (constructorName === 'Object' && value) {
190
+ if ((type === 'Object' || type === 'Array') && value) {
184
191
  // make string representation uniform with no new lines and consistent spaces
185
192
  let str = util
186
193
  .inspect(value)
@@ -192,7 +199,7 @@ module.exports = class CallContext {
192
199
 
193
200
  return str;
194
201
  }
195
- return constructorName;
202
+ return type;
196
203
  }
197
204
  };
198
205
 
@@ -37,7 +37,6 @@ const requiredTags = ['untrusted'];
37
37
  const trackSchemaCommands = {
38
38
  'scan': {
39
39
  attributes: [
40
- 'ExpressionAttributeValues',
41
40
  'ExclusiveStartKey',
42
41
  'ScanFilter'
43
42
  ]
@@ -19,36 +19,74 @@ const { PATCH_TYPES } = require('../../constants');
19
19
  const ModuleHook = require('../../hooks/require');
20
20
  const patcher = require('../../hooks/patcher');
21
21
  const logger = require('../logger')('contrast:arch-component');
22
- const semver = require('semver');
23
22
 
23
+ // Architecture component for versions <3.0.0
24
24
  ModuleHook.resolve(
25
25
  {
26
26
  name: 'mongodb',
27
27
  file: 'lib/mongo_client.js',
28
- version: '>=3.3.0'
28
+ version: '<3.0.0'
29
29
  },
30
- (MongoClient, { version }) => {
31
- if (semver.lt(version, '4.0.0')) {
32
- patcher.patch(MongoClient.prototype, 'connect', {
33
- name: 'MongoClient.connect.arch_component',
34
- patchType: PATCH_TYPES.ARCH_COMPONENT,
35
- alwaysRun: true,
36
- post(ctx) {
37
- if (!ctx.result || !ctx.result.then) {
38
- return;
39
- }
40
-
41
- // We should report only when connection is successful
42
- ctx.result.then(function(client) {
30
+ (MongoClient) => {
31
+ patcher.patch(MongoClient, 'connect', {
32
+ name: 'MongoClient.connect.arch_component',
33
+ patchType: PATCH_TYPES.ARCH_COMPONENT,
34
+ alwaysRun: true,
35
+ pre(ctx) {
36
+ // check if typeof callback == 'function'
37
+ // if yes:
38
+ // - MongoClient.connect executes a cb function, which has access to the connection status
39
+ // if not:
40
+ // - MongoClient.connect should return a promise and we can check it's result in another hook, just as before
41
+ const callbackIndex = ctx.args[2] ? 2 : 1;
42
+ if (ctx.args[callbackIndex] instanceof Function || typeof ctx.args[callbackIndex] === 'function') {
43
+ ctx.args[callbackIndex] = patcher.patch(ctx.args[callbackIndex], {
44
+ name: 'MongoClient.connect.callback.arch_component',
45
+ patchType: PATCH_TYPES.ARCH_COMPONENT,
46
+ alwaysRun: true,
47
+ pre(ctx) {
48
+ const [, db] = ctx.args;
49
+ if (db && db.s.topology && db.s.topology.s) {
50
+ try {
51
+ const server = db.s.topology.s.server.s;
52
+ if (server.pool && server.pool.state == 'connected') {
53
+ const connections = server.pool.availableConnections;
54
+ for (const c of connections) {
55
+ agentEmitter.emit('architectureComponent', {
56
+ vendor: 'MongoDB',
57
+ url: `mongodb://${c.host}:${c.port}`,
58
+ remoteHost: '',
59
+ remotePort: c.port
60
+ });
61
+ }
62
+ }
63
+ } catch (err) {
64
+ logger.warn('unable to report MongoDB architecture component, err: %o', err);
65
+ }
66
+ }
67
+ }
68
+ });
69
+ }
70
+ },
71
+ post(ctx) {
72
+ if (!ctx.result || !ctx.result.then) {
73
+ return;
74
+ }
75
+ // it never gets here if callbacks are used, because the result won't be then-able
76
+ ctx.result.then(db => {
77
+ if (db && db.s && db.s.topology && db.s.topology.s) {
43
78
  try {
44
- const { servers = [] } = ctx.obj.s && ctx.obj.s.options;
45
- for (const server of servers) {
46
- agentEmitter.emit('architectureComponent', {
47
- vendor: 'MongoDB',
48
- url: `mongodb://${server.host}:${server.port}`,
49
- remoteHost: '',
50
- remotePort: server.port,
51
- });
79
+ const server = db.s.topology.s.server.s;
80
+ if (server.pool && server.pool.state == 'connected') {
81
+ const connections = server.pool.availableConnections;
82
+ for (const c of connections) {
83
+ agentEmitter.emit('architectureComponent', {
84
+ vendor: 'MongoDB',
85
+ url: `mongodb://${c.host}:${c.port}`,
86
+ remoteHost: '',
87
+ remotePort: c.port
88
+ });
89
+ }
52
90
  }
53
91
  } catch (err) {
54
92
  logger.warn(
@@ -56,60 +94,96 @@ ModuleHook.resolve(
56
94
  err,
57
95
  );
58
96
  }
59
- });
60
- },
61
- });
62
- }
97
+ }
98
+ });
99
+ }
100
+ });
101
+ }
102
+ );
103
+
104
+ // Architecture component for versions >=3.3.0 <4.0.0
105
+ ModuleHook.resolve(
106
+ {
107
+ name: 'mongodb',
108
+ file: 'lib/mongo_client.js',
109
+ version: '>=3.0.0 <4.0.0'
110
+ },
111
+ (MongoClient, { version }) => {
112
+ patcher.patch(MongoClient.prototype, 'connect', {
113
+ name: 'MongoClient.connect.arch_component',
114
+ patchType: PATCH_TYPES.ARCH_COMPONENT,
115
+ alwaysRun: true,
116
+ post(ctx) {
117
+ if (!ctx.result || !ctx.result.then) {
118
+ return;
119
+ }
120
+
121
+ // We should report only when connection is successful
122
+ ctx.result.then(function(client) {
123
+ try {
124
+ const { servers = [] } = ctx.obj.s && ctx.obj.s.options;
125
+ for (const server of servers) {
126
+ agentEmitter.emit('architectureComponent', {
127
+ vendor: 'MongoDB',
128
+ url: `mongodb://${server.host}:${server.port}`,
129
+ remoteHost: '',
130
+ remotePort: server.port,
131
+ });
132
+ }
133
+ } catch (err) {
134
+ logger.warn(
135
+ 'unable to report MongoDB architecture component, err: %o',
136
+ err,
137
+ );
138
+ }
139
+ });
140
+ },
141
+ });
63
142
  },
64
143
  );
65
144
 
66
- /* Architecture component for >= mongodb@4
67
- * It's not limited in the require hook to >=4.0.0 because
68
- * that would result in confusing logs for the customer that
69
- * we don't support older versions (which is not true) */
145
+ // Architecture component for versions >=4.0.0
70
146
  ModuleHook.resolve(
71
147
  {
72
148
  name: 'mongodb',
73
- version: '>=3.3.0'
149
+ version: '>=4.0.0'
74
150
  },
75
151
  (MongoDB, { version }) => {
76
- if (semver.gte(version, '4.0.0')) {
77
- patcher.patch(MongoDB.MongoClient.prototype, 'connect', {
78
- name: 'MongoClient.connect.arch_component',
79
- patchType: PATCH_TYPES.ARCH_COMPONENT,
80
- alwaysRun: true,
81
- post(ctx) {
82
- if (!ctx.result || !ctx.result.then) {
83
- return;
84
- }
152
+ patcher.patch(MongoDB.MongoClient.prototype, 'connect', {
153
+ name: 'MongoClient.connect.arch_component',
154
+ patchType: PATCH_TYPES.ARCH_COMPONENT,
155
+ alwaysRun: true,
156
+ post(ctx) {
157
+ if (!ctx.result || !ctx.result.then) {
158
+ return;
159
+ }
85
160
 
86
- // We should report only when connection is successful
87
- ctx.result.then(function(client) {
88
- if (client && client.topology && client.topology.s) {
89
- try {
90
- const { servers } = client.topology.s;
91
- for (const [, server] of servers) {
92
- if (server.s && server.s.state === 'connected') {
93
- const { srvServiceName } = server.s.options;
94
- const { address } = server.s.description;
95
- agentEmitter.emit('architectureComponent', {
96
- vendor: 'MongoDB',
97
- url: `${srvServiceName}://${address}`,
98
- remoteHost: '',
99
- remotePort: address.split(':').pop()
100
- });
101
- }
161
+ // We should report only when connection is successful
162
+ ctx.result.then(function(client) {
163
+ if (client && client.topology && client.topology.s) {
164
+ try {
165
+ const { servers } = client.topology.s;
166
+ for (const [, server] of servers) {
167
+ if (server.s && server.s.state === 'connected') {
168
+ const { srvServiceName } = server.s.options;
169
+ const { address } = server.s.description;
170
+ agentEmitter.emit('architectureComponent', {
171
+ vendor: 'MongoDB',
172
+ url: `${srvServiceName}://${address}`,
173
+ remoteHost: '',
174
+ remotePort: address.split(':').pop()
175
+ });
102
176
  }
103
- } catch (err) {
104
- logger.warn(
105
- 'unable to report MongoDB architecture component, err: %o',
106
- err,
107
- );
108
177
  }
178
+ } catch (err) {
179
+ logger.warn(
180
+ 'unable to report MongoDB architecture component, err: %o',
181
+ err,
182
+ );
109
183
  }
110
- });
111
- },
112
- });
113
- }
184
+ }
185
+ });
186
+ },
187
+ });
114
188
  },
115
189
  );
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@contrast/agent",
3
- "version": "4.22.0",
3
+ "version": "4.22.1",
4
4
  "description": "Node.js security instrumentation by Contrast Security",
5
5
  "keywords": [
6
6
  "security",