mongodb 3.6.5 → 3.6.6

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/HISTORY.md CHANGED
@@ -2,6 +2,19 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
4
4
 
5
+ ### [3.6.6](https://github.com/mongodb/node-mongodb-native/compare/v3.6.5...v3.6.6) (2021-04-06)
6
+
7
+
8
+ ### Bug Fixes
9
+
10
+ * always close gridfs upload stream on finish ([#2758](https://github.com/mongodb/node-mongodb-native/issues/2758)) ([c976a01](https://github.com/mongodb/node-mongodb-native/commit/c976a01bf385941bee07fa7f021adf1d425109a8))
11
+ * **csfle:** ensure that monitoring connections are not encrypted ([#2749](https://github.com/mongodb/node-mongodb-native/issues/2749)) ([86bddf1](https://github.com/mongodb/node-mongodb-native/commit/86bddf1ef516d6b8c752082e33c15624753579ab))
12
+ * ensure cursor readPreference is applied to find operations ([#2751](https://github.com/mongodb/node-mongodb-native/issues/2751)) ([91ba19e](https://github.com/mongodb/node-mongodb-native/commit/91ba19efdc4713903584c6161cfdd7b91b0e61f9))
13
+ * ensure monitor has rtt pinger in when calculating rtt ([#2757](https://github.com/mongodb/node-mongodb-native/issues/2757)) ([b94519b](https://github.com/mongodb/node-mongodb-native/commit/b94519ba894b4442d3dabbac59bd12784d8b7178))
14
+ * no infinite loop on windows requiring optional deps ([f2a4ff8](https://github.com/mongodb/node-mongodb-native/commit/f2a4ff870178fbbe8de616c45891368665f29f4b))
15
+ * **NODE-2995:** Add shared metadata MongoClient ([#2760](https://github.com/mongodb/node-mongodb-native/issues/2760)) ([9256242](https://github.com/mongodb/node-mongodb-native/commit/9256242d51c037059c0af5ada9639fc0a74ad033))
16
+ * **NODE-3109:** prevent servername from being IP ([#2763](https://github.com/mongodb/node-mongodb-native/issues/2763)) ([312ffef](https://github.com/mongodb/node-mongodb-native/commit/312ffef18c66a0020f19bdc1d654987d9148d709))
17
+
5
18
  ### [3.6.5](https://github.com/mongodb/node-mongodb-native/compare/v3.6.4...v3.6.5) (2021-03-16)
6
19
 
7
20
 
@@ -243,7 +243,7 @@ function parseSslOptions(family, options) {
243
243
  }
244
244
 
245
245
  // Set default sni servername to be the same as host
246
- if (result.servername == null) {
246
+ if (result.servername == null && !net.isIP(result.host)) {
247
247
  result.servername = result.host;
248
248
  }
249
249
 
@@ -1,9 +1,9 @@
1
1
  'use strict';
2
2
 
3
- const require_optional = require('require_optional');
3
+ const require_optional = require('optional-require')(require);
4
4
 
5
5
  function debugOptions(debugFields, options) {
6
- var finaloptions = {};
6
+ const finaloptions = {};
7
7
  debugFields.forEach(function(n) {
8
8
  finaloptions[n] = options[n];
9
9
  });
@@ -12,16 +12,14 @@ function debugOptions(debugFields, options) {
12
12
  }
13
13
 
14
14
  function retrieveBSON() {
15
- var BSON = require('bson');
15
+ const BSON = require('bson');
16
16
  BSON.native = false;
17
17
 
18
- try {
19
- var optionalBSON = require_optional('bson-ext');
20
- if (optionalBSON) {
21
- optionalBSON.native = true;
22
- return optionalBSON;
23
- }
24
- } catch (err) {} // eslint-disable-line
18
+ const optionalBSON = require_optional('bson-ext');
19
+ if (optionalBSON) {
20
+ optionalBSON.native = true;
21
+ return optionalBSON;
22
+ }
25
23
 
26
24
  return BSON;
27
25
  }
@@ -35,10 +33,7 @@ function noSnappyWarning() {
35
33
 
36
34
  // Facilitate loading Snappy optionally
37
35
  function retrieveSnappy() {
38
- var snappy = null;
39
- try {
40
- snappy = require_optional('snappy');
41
- } catch (error) {} // eslint-disable-line
36
+ let snappy = require_optional('snappy');
42
37
  if (!snappy) {
43
38
  snappy = {
44
39
  compress: noSnappyWarning,
package/lib/core/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  let BSON = require('bson');
4
- const require_optional = require('require_optional');
4
+ const require_optional = require('optional-require')(require);
5
5
  const EJSON = require('./utils').retrieveEJSON();
6
6
 
7
7
  try {
@@ -91,6 +91,10 @@ class Monitor extends EventEmitter {
91
91
 
92
92
  // ensure no authentication is used for monitoring
93
93
  delete connectOptions.credentials;
94
+
95
+ // ensure encryption is not requested for monitoring
96
+ delete connectOptions.autoEncrypter;
97
+
94
98
  this.connectOptions = Object.freeze(connectOptions);
95
99
  }
96
100
 
@@ -222,9 +226,10 @@ function checkServer(monitor, callback) {
222
226
  }
223
227
 
224
228
  const isMaster = result.result;
225
- const duration = isAwaitable
226
- ? monitor[kRTTPinger].roundTripTime
227
- : calculateDurationInMs(start);
229
+ const rttPinger = monitor[kRTTPinger];
230
+
231
+ const duration =
232
+ isAwaitable && rttPinger ? rttPinger.roundTripTime : calculateDurationInMs(start);
228
233
 
229
234
  monitor.emit(
230
235
  'serverHeartbeatSucceeded',
package/lib/core/utils.js CHANGED
@@ -1,7 +1,7 @@
1
1
  'use strict';
2
2
  const os = require('os');
3
3
  const crypto = require('crypto');
4
- const requireOptional = require('require_optional');
4
+ const requireOptional = require('optional-require')(require);
5
5
 
6
6
  /**
7
7
  * Generate a UUIDv4
@@ -46,10 +46,7 @@ const noEJSONError = function() {
46
46
 
47
47
  // Facilitate loading EJSON optionally
48
48
  function retrieveEJSON() {
49
- let EJSON = null;
50
- try {
51
- EJSON = requireOptional('mongodb-extjson');
52
- } catch (error) {} // eslint-disable-line
49
+ let EJSON = requireOptional('mongodb-extjson');
53
50
  if (!EJSON) {
54
51
  EJSON = {
55
52
  parse: noEJSONError,
@@ -0,0 +1,163 @@
1
+ 'use strict';
2
+ const MongoClient = require('./mongo_client');
3
+ const BSON = require('./core/connection/utils').retrieveBSON();
4
+ const MongoError = require('./core/error').MongoError;
5
+
6
+ try {
7
+ require.resolve('mongodb-client-encryption');
8
+ } catch (err) {
9
+ throw new MongoError(
10
+ 'Auto-encryption requested, but the module is not installed. ' +
11
+ 'Please add `mongodb-client-encryption` as a dependency of your project'
12
+ );
13
+ }
14
+
15
+ const mongodbClientEncryption = require('mongodb-client-encryption');
16
+ if (typeof mongodbClientEncryption.extension !== 'function') {
17
+ throw new MongoError(
18
+ 'loaded version of `mongodb-client-encryption` does not have property `extension`. ' +
19
+ 'Please make sure you are loading the correct version of `mongodb-client-encryption`'
20
+ );
21
+ }
22
+ const AutoEncrypter = mongodbClientEncryption.extension(require('../index')).AutoEncrypter;
23
+
24
+ const kInternalClient = Symbol('internalClient');
25
+
26
+ class Encrypter {
27
+ /**
28
+ * @param {MongoClient} client
29
+ * @param {{autoEncryption: import('./mongo_client').AutoEncryptionOptions, bson: object}} options
30
+ */
31
+ constructor(client, options) {
32
+ this.bypassAutoEncryption = !!options.autoEncryption.bypassAutoEncryption;
33
+ this.needsConnecting = false;
34
+
35
+ if (options.maxPoolSize === 0 && options.autoEncryption.keyVaultClient == null) {
36
+ options.autoEncryption.keyVaultClient = client;
37
+ } else if (options.autoEncryption.keyVaultClient == null) {
38
+ options.autoEncryption.keyVaultClient = this.getInternalClient(client);
39
+ }
40
+
41
+ if (this.bypassAutoEncryption) {
42
+ options.autoEncryption.metadataClient = undefined;
43
+ } else if (options.maxPoolSize === 0) {
44
+ options.autoEncryption.metadataClient = client;
45
+ } else {
46
+ options.autoEncryption.metadataClient = this.getInternalClient(client);
47
+ }
48
+
49
+ options.autoEncryption.bson = Encrypter.makeBSON(options);
50
+
51
+ this.autoEncrypter = new AutoEncrypter(client, options.autoEncryption);
52
+ }
53
+
54
+ getInternalClient(client) {
55
+ if (!this[kInternalClient]) {
56
+ const clonedOptions = {};
57
+
58
+ for (const key of Object.keys(client.s.options)) {
59
+ if (
60
+ ['autoEncryption', 'minPoolSize', 'servers', 'caseTranslate', 'dbName'].indexOf(key) !==
61
+ -1
62
+ )
63
+ continue;
64
+ clonedOptions[key] = client.s.options[key];
65
+ }
66
+
67
+ clonedOptions.minPoolSize = 0;
68
+
69
+ const allEvents = [
70
+ // APM
71
+ 'commandStarted',
72
+ 'commandSucceeded',
73
+ 'commandFailed',
74
+
75
+ // SDAM
76
+ 'serverOpening',
77
+ 'serverClosed',
78
+ 'serverDescriptionChanged',
79
+ 'serverHeartbeatStarted',
80
+ 'serverHeartbeatSucceeded',
81
+ 'serverHeartbeatFailed',
82
+ 'topologyOpening',
83
+ 'topologyClosed',
84
+ 'topologyDescriptionChanged',
85
+
86
+ // Legacy
87
+ 'joined',
88
+ 'left',
89
+ 'ping',
90
+ 'ha',
91
+
92
+ // CMAP
93
+ 'connectionPoolCreated',
94
+ 'connectionPoolClosed',
95
+ 'connectionCreated',
96
+ 'connectionReady',
97
+ 'connectionClosed',
98
+ 'connectionCheckOutStarted',
99
+ 'connectionCheckOutFailed',
100
+ 'connectionCheckedOut',
101
+ 'connectionCheckedIn',
102
+ 'connectionPoolCleared'
103
+ ];
104
+
105
+ this[kInternalClient] = new MongoClient(client.s.url, clonedOptions);
106
+
107
+ for (const eventName of allEvents) {
108
+ for (const listener of client.listeners(eventName)) {
109
+ this[kInternalClient].on(eventName, listener);
110
+ }
111
+ }
112
+
113
+ client.on('newListener', (eventName, listener) => {
114
+ this[kInternalClient].on(eventName, listener);
115
+ });
116
+
117
+ this.needsConnecting = true;
118
+ }
119
+ return this[kInternalClient];
120
+ }
121
+
122
+ connectInternalClient(callback) {
123
+ if (this.needsConnecting) {
124
+ this.needsConnecting = false;
125
+ return this[kInternalClient].connect(callback);
126
+ }
127
+
128
+ return callback();
129
+ }
130
+
131
+ close(client, force, callback) {
132
+ this.autoEncrypter.teardown(e => {
133
+ if (this[kInternalClient] && client !== this[kInternalClient]) {
134
+ return this[kInternalClient].close(force, callback);
135
+ }
136
+ callback(e);
137
+ });
138
+ }
139
+
140
+ static makeBSON(options) {
141
+ return (
142
+ (options || {}).bson ||
143
+ new BSON([
144
+ BSON.Binary,
145
+ BSON.Code,
146
+ BSON.DBRef,
147
+ BSON.Decimal128,
148
+ BSON.Double,
149
+ BSON.Int32,
150
+ BSON.Long,
151
+ BSON.Map,
152
+ BSON.MaxKey,
153
+ BSON.MinKey,
154
+ BSON.ObjectId,
155
+ BSON.BSONRegExp,
156
+ BSON.Symbol,
157
+ BSON.Timestamp
158
+ ])
159
+ );
160
+ }
161
+ }
162
+
163
+ module.exports = { Encrypter };
@@ -284,6 +284,7 @@ function checkDone(_this, callback) {
284
284
  return __handleError(_this, error, callback);
285
285
  }
286
286
  _this.emit('finish', filesDoc);
287
+ _this.emit('close');
287
288
  });
288
289
 
289
290
  return true;
@@ -71,6 +71,24 @@ const validOptions = require('./operations/connect').validOptions;
71
71
  * @property {string} [platform] Optional platform information
72
72
  */
73
73
 
74
+ /**
75
+ * @public
76
+ * @typedef AutoEncryptionOptions
77
+ * @property {MongoClient} [keyVaultClient] A `MongoClient` used to fetch keys from a key vault
78
+ * @property {string} [keyVaultNamespace] The namespace where keys are stored in the key vault
79
+ * @property {object} [kmsProviders] Configuration options that are used by specific KMS providers during key generation, encryption, and decryption.
80
+ * @property {object} [schemaMap] A map of namespaces to a local JSON schema for encryption
81
+ *
82
+ * > **NOTE**: Supplying options.schemaMap provides more security than relying on JSON Schemas obtained from the server.
83
+ * > It protects against a malicious server advertising a false JSON Schema, which could trick the client into sending decrypted data that should be encrypted.
84
+ * > Schemas supplied in the schemaMap only apply to configuring automatic encryption for client side encryption.
85
+ * > Other validation rules in the JSON schema will not be enforced by the driver and will result in an error.
86
+ *
87
+ * @property {object} [options] An optional hook to catch logging messages from the underlying encryption engine
88
+ * @property {object} [extraOptions]
89
+ * @property {boolean} [bypassAutoEncryption]
90
+ */
91
+
74
92
  /**
75
93
  * Creates a new MongoClient instance
76
94
  * @class
@@ -151,7 +169,18 @@ const validOptions = require('./operations/connect').validOptions;
151
169
  * @param {number} [options.minPoolSize=0] **Only applies to the unified topology** The minimum number of connections that MUST exist at any moment in a single connection pool.
152
170
  * @param {number} [options.maxIdleTimeMS] **Only applies to the unified topology** The maximum amount of time a connection should remain idle in the connection pool before being marked idle. The default is infinity.
153
171
  * @param {number} [options.waitQueueTimeoutMS=0] **Only applies to the unified topology** The maximum amount of time operation execution should wait for a connection to become available. The default is 0 which means there is no limit.
154
- * @param {AutoEncrypter~AutoEncryptionOptions} [options.autoEncryption] Optionally enable client side auto encryption
172
+ * @param {AutoEncryptionOptions} [options.autoEncryption] Optionally enable client side auto encryption.
173
+ *
174
+ * > Automatic encryption is an enterprise only feature that only applies to operations on a collection. Automatic encryption is not supported for operations on a database or view, and operations that are not bypassed will result in error
175
+ * > (see [libmongocrypt: Auto Encryption Allow-List](https://github.com/mongodb/specifications/blob/master/source/client-side-encryption/client-side-encryption.rst#libmongocrypt-auto-encryption-allow-list)). To bypass automatic encryption for all operations, set bypassAutoEncryption=true in AutoEncryptionOpts.
176
+ * >
177
+ * > Automatic encryption requires the authenticated user to have the [listCollections privilege action](https://docs.mongodb.com/manual/reference/command/listCollections/#dbcmd.listCollections).
178
+ * >
179
+ * > If a MongoClient with a limited connection pool size (i.e a non-zero maxPoolSize) is configured with AutoEncryptionOptions, a separate internal MongoClient is created if any of the following are true:
180
+ * > - AutoEncryptionOptions.keyVaultClient is not passed.
181
+ * > - AutoEncryptionOptions.bypassAutomaticEncryption is false.
182
+ * > If an internal MongoClient is created, it is configured with the same options as the parent MongoClient except minPoolSize is set to 0 and AutoEncryptionOptions is omitted.
183
+ *
155
184
  * @param {DriverInfoOptions} [options.driverInfo] Allows a wrapping driver to amend the client metadata generated by the driver to include information about the wrapping driver
156
185
  * @param {boolean} [options.directConnection=false] Enable directConnection
157
186
  * @param {MongoClient~connectCallback} [callback] The command result callback
@@ -162,6 +191,8 @@ function MongoClient(url, options) {
162
191
  // Set up event emitter
163
192
  EventEmitter.call(this);
164
193
 
194
+ if (options && options.autoEncryption) require('./encrypter'); // Does CSFLE lib check
195
+
165
196
  // The internal state
166
197
  this.s = {
167
198
  url: url,
@@ -268,13 +299,13 @@ MongoClient.prototype.close = function(force, callback) {
268
299
  }
269
300
 
270
301
  client.topology.close(force, err => {
271
- const autoEncrypter = client.topology.s.options.autoEncrypter;
272
- if (!autoEncrypter) {
273
- completeClose(err);
274
- return;
302
+ const encrypter = client.topology.s.options.encrypter;
303
+ if (encrypter) {
304
+ return encrypter.close(client, force, err2 => {
305
+ completeClose(err || err2);
306
+ });
275
307
  }
276
-
277
- autoEncrypter.teardown(force, err2 => completeClose(err || err2));
308
+ completeClose(err);
278
309
  });
279
310
  });
280
311
  };
@@ -16,7 +16,6 @@ const emitDeprecationWarning = require('../utils').emitDeprecationWarning;
16
16
  const emitWarningOnce = require('../utils').emitWarningOnce;
17
17
  const fs = require('fs');
18
18
  const WriteConcern = require('../write_concern');
19
- const BSON = require('../core/connection/utils').retrieveBSON();
20
19
  const CMAP_EVENT_NAMES = require('../cmap/events').CMAP_EVENT_NAMES;
21
20
 
22
21
  let client;
@@ -496,58 +495,9 @@ function createTopology(mongoClient, topologyType, options, callback) {
496
495
 
497
496
  // determine CSFLE support
498
497
  if (options.autoEncryption != null) {
499
- let AutoEncrypter;
500
- try {
501
- require.resolve('mongodb-client-encryption');
502
- } catch (err) {
503
- callback(
504
- new MongoError(
505
- 'Auto-encryption requested, but the module is not installed. Please add `mongodb-client-encryption` as a dependency of your project'
506
- )
507
- );
508
- return;
509
- }
510
-
511
- try {
512
- let mongodbClientEncryption = require('mongodb-client-encryption');
513
- if (typeof mongodbClientEncryption.extension !== 'function') {
514
- callback(
515
- new MongoError(
516
- 'loaded version of `mongodb-client-encryption` does not have property `extension`. Please make sure you are loading the correct version of `mongodb-client-encryption`'
517
- )
518
- );
519
- }
520
- AutoEncrypter = mongodbClientEncryption.extension(require('../../index')).AutoEncrypter;
521
- } catch (err) {
522
- callback(err);
523
- return;
524
- }
525
-
526
- const mongoCryptOptions = Object.assign(
527
- {
528
- bson:
529
- options.bson ||
530
- new BSON([
531
- BSON.Binary,
532
- BSON.Code,
533
- BSON.DBRef,
534
- BSON.Decimal128,
535
- BSON.Double,
536
- BSON.Int32,
537
- BSON.Long,
538
- BSON.Map,
539
- BSON.MaxKey,
540
- BSON.MinKey,
541
- BSON.ObjectId,
542
- BSON.BSONRegExp,
543
- BSON.Symbol,
544
- BSON.Timestamp
545
- ])
546
- },
547
- options.autoEncryption
548
- );
549
-
550
- options.autoEncrypter = new AutoEncrypter(mongoClient, mongoCryptOptions);
498
+ const Encrypter = require('../encrypter').Encrypter;
499
+ options.encrypter = new Encrypter(mongoClient, options);
500
+ options.autoEncrypter = options.encrypter.autoEncrypter;
551
501
  }
552
502
 
553
503
  // Create the topology
@@ -585,7 +535,10 @@ function createTopology(mongoClient, topologyType, options, callback) {
585
535
  return;
586
536
  }
587
537
 
588
- callback(undefined, topology);
538
+ options.encrypter.connectInternalClient(error => {
539
+ if (error) return callback(error);
540
+ callback(undefined, topology);
541
+ });
589
542
  });
590
543
  });
591
544
 
@@ -20,6 +20,9 @@ class FindOperation extends OperationBase {
20
20
  // copied from `CommandOperationV2`, to be subclassed in the future
21
21
  this.server = server;
22
22
 
23
+ // updates readPreference if setReadPreference was called on the cursor
24
+ this.readPreference = ReadPreference.resolve(this, this.options);
25
+
23
26
  if (typeof this.cmd.allowDiskUse !== 'undefined' && maxWireVersion(server) < 4) {
24
27
  callback(new MongoError('The `allowDiskUse` option is not supported on MongoDB < 3.2'));
25
28
  return;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mongodb",
3
- "version": "3.6.5",
3
+ "version": "3.6.6",
4
4
  "description": "The official MongoDB driver for Node.js",
5
5
  "main": "index.js",
6
6
  "files": [
@@ -16,13 +16,6 @@
16
16
  "driver",
17
17
  "official"
18
18
  ],
19
- "peerOptionalDependencies": {
20
- "kerberos": "^1.1.0",
21
- "mongodb-client-encryption": "^1.0.0",
22
- "mongodb-extjson": "^2.1.2",
23
- "snappy": "^6.3.4",
24
- "bson-ext": "^2.0.0"
25
- },
26
19
  "peerDependenciesMeta": {
27
20
  "kerberos": {
28
21
  "optional": true
@@ -47,7 +40,7 @@
47
40
  "bl": "^2.2.1",
48
41
  "bson": "^1.1.4",
49
42
  "denque": "^1.4.1",
50
- "require_optional": "^1.0.1",
43
+ "optional-require": "^1.0.2",
51
44
  "safe-buffer": "^5.1.2"
52
45
  },
53
46
  "devDependencies": {