mongodb 3.6.7 → 3.6.11
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 +34 -0
- package/README.md +4 -4
- package/lib/bulk/common.js +34 -12
- package/lib/cmap/connection.js +2 -1
- package/lib/collection.js +9 -0
- package/lib/command_utils.js +124 -0
- package/lib/core/auth/mongodb_aws.js +1 -0
- package/lib/core/auth/scram.js +1 -0
- package/lib/core/connection/apm.js +10 -123
- package/lib/core/connection/commands.js +11 -2
- package/lib/core/connection/connect.js +3 -0
- package/lib/core/connection/connection.js +6 -3
- package/lib/core/connection/msg.js +11 -2
- package/lib/core/connection/pool.js +6 -2
- package/lib/core/cursor.js +7 -0
- package/lib/core/error.js +2 -2
- package/lib/core/index.js +1 -0
- package/lib/core/sdam/monitor.js +2 -1
- package/lib/core/sdam/server.js +8 -1
- package/lib/core/sdam/topology.js +24 -14
- package/lib/core/topologies/mongos.js +1 -0
- package/lib/core/topologies/replset.js +1 -0
- package/lib/core/topologies/server.js +7 -2
- package/lib/core/uri_parser.js +3 -1
- package/lib/core/utils.js +1 -0
- package/lib/core/wireprotocol/constants.js +2 -2
- package/lib/core/wireprotocol/shared.js +1 -0
- package/lib/cursor.js +12 -2
- package/lib/db.js +82 -72
- package/lib/encrypter.js +8 -3
- package/lib/mongo_client.js +1 -0
- package/lib/operations/bulk_write.js +0 -17
- package/lib/operations/command.js +4 -1
- package/lib/operations/command_v2.js +7 -1
- package/lib/operations/connect.js +1 -0
- package/lib/operations/db_ops.js +6 -2
- package/lib/topologies/mongos.js +1 -0
- package/lib/topologies/replset.js +1 -0
- package/lib/topologies/server.js +1 -0
- package/lib/url_parser.js +2 -1
- package/lib/utils.js +78 -1
- package/package.json +6 -2
package/HISTORY.md
CHANGED
|
@@ -2,6 +2,40 @@
|
|
|
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.11](https://github.com/mongodb/node-mongodb-native/compare/v3.6.10...v3.6.11) (2021-08-05)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
### Bug Fixes
|
|
9
|
+
|
|
10
|
+
* **NODE-1843:** bulk operations ignoring provided sessions [PORT] ([#2898](https://github.com/mongodb/node-mongodb-native/issues/2898)) ([9244b17](https://github.com/mongodb/node-mongodb-native/commit/9244b1771e538f7b685fd6d4aa83d9da84b20093))
|
|
11
|
+
* **NODE-3199:** unable to bundle driver due to uncaught require ([#2903](https://github.com/mongodb/node-mongodb-native/issues/2903)) ([60efe9d](https://github.com/mongodb/node-mongodb-native/commit/60efe9d0030477da462d326c2e2ddc5fe6c0ffff))
|
|
12
|
+
|
|
13
|
+
### [3.6.10](https://github.com/mongodb/node-mongodb-native/compare/v3.6.9...v3.6.10) (2021-07-06)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
### Bug Fixes
|
|
17
|
+
|
|
18
|
+
* **NODE-2035:** Exceptions thrown from awaited cursor forEach do not propagate ([#2852](https://github.com/mongodb/node-mongodb-native/issues/2852)) ([a917dfa](https://github.com/mongodb/node-mongodb-native/commit/a917dfada67859412344ed238796cf3bee243f5f))
|
|
19
|
+
* **NODE-3150:** added bsonRegExp option for v3.6 ([#2843](https://github.com/mongodb/node-mongodb-native/issues/2843)) ([e4a9a57](https://github.com/mongodb/node-mongodb-native/commit/e4a9a572427666fd1a89576dadf50b9c452e1659))
|
|
20
|
+
* **NODE-3358:** Command monitoring objects hold internal state references ([#2858](https://github.com/mongodb/node-mongodb-native/issues/2858)) ([750760c](https://github.com/mongodb/node-mongodb-native/commit/750760c324ddedb72491befde9f7aff1ceec009c))
|
|
21
|
+
* **NODE-3380:** perform retryable write checks against server ([#2861](https://github.com/mongodb/node-mongodb-native/issues/2861)) ([621677a](https://github.com/mongodb/node-mongodb-native/commit/621677a42772e0b26aa13883f57d7e42f86df43f))
|
|
22
|
+
* **NODE-3397:** report more helpful error with unsupported authMechanism in initial handshake ([#2876](https://github.com/mongodb/node-mongodb-native/issues/2876)) ([3ce148d](https://github.com/mongodb/node-mongodb-native/commit/3ce148d8fb37faea1ee056f6e9331e5282e65cd0))
|
|
23
|
+
|
|
24
|
+
### [3.6.9](https://github.com/mongodb/node-mongodb-native/compare/v3.6.8...v3.6.9) (2021-05-26)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
### Bug Fixes
|
|
28
|
+
|
|
29
|
+
* **NODE-3309:** remove redundant iteration of bulk write result ([#2815](https://github.com/mongodb/node-mongodb-native/issues/2815)) ([fac9610](https://github.com/mongodb/node-mongodb-native/commit/fac961086eafa0f7437576fd6af900e1f9fe22ed))
|
|
30
|
+
* fix url parsing for a mongodb+srv url that has commas in the database name ([#2789](https://github.com/mongodb/node-mongodb-native/issues/2789)) ([58c4e69](https://github.com/mongodb/node-mongodb-native/commit/58c4e693cc3a717254144d5f9bdddd8414217e97))
|
|
31
|
+
|
|
32
|
+
### [3.6.8](https://github.com/mongodb/node-mongodb-native/compare/v3.6.7...v3.6.8) (2021-05-21)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
### Bug Fixes
|
|
36
|
+
|
|
37
|
+
* **cmap:** undo flipping of `beforeHandshake` flag for timeout errors ([#2813](https://github.com/mongodb/node-mongodb-native/issues/2813)) ([6e3bab3](https://github.com/mongodb/node-mongodb-native/commit/6e3bab32204ea905ab9b949edccb68556b50d382))
|
|
38
|
+
|
|
5
39
|
### [3.6.7](https://github.com/mongodb/node-mongodb-native/compare/v3.6.6...v3.6.7) (2021-05-18)
|
|
6
40
|
|
|
7
41
|
|
package/README.md
CHANGED
|
@@ -15,10 +15,10 @@ Check out our [beta version 4.0 here](https://github.com/mongodb/node-mongodb-na
|
|
|
15
15
|
|
|
16
16
|
| what | where |
|
|
17
17
|
| ------------- | ---------------------------------------------------- |
|
|
18
|
-
| documentation |
|
|
19
|
-
| api-doc |
|
|
18
|
+
| documentation | https://mongodb.github.io/node-mongodb-native |
|
|
19
|
+
| api-doc | https://mongodb.github.io/node-mongodb-native/3.6/api |
|
|
20
20
|
| source | https://github.com/mongodb/node-mongodb-native |
|
|
21
|
-
| mongodb |
|
|
21
|
+
| mongodb | https://www.mongodb.org |
|
|
22
22
|
|
|
23
23
|
### Bugs / Feature Requests
|
|
24
24
|
|
|
@@ -481,7 +481,7 @@ For more detailed information, see the [tutorials](docs/reference/content/tutori
|
|
|
481
481
|
|
|
482
482
|
## Next Steps
|
|
483
483
|
|
|
484
|
-
- [MongoDB Documentation](
|
|
484
|
+
- [MongoDB Documentation](https://mongodb.org)
|
|
485
485
|
- [Read about Schemas](http://learnmongodbthehardway.com)
|
|
486
486
|
- [Star us on GitHub](https://github.com/mongodb/node-mongodb-native)
|
|
487
487
|
|
package/lib/bulk/common.js
CHANGED
|
@@ -57,6 +57,9 @@ class Batch {
|
|
|
57
57
|
}
|
|
58
58
|
}
|
|
59
59
|
|
|
60
|
+
const kUpsertedIds = Symbol('upsertedIds');
|
|
61
|
+
const kInsertedIds = Symbol('insertedIds');
|
|
62
|
+
|
|
60
63
|
/**
|
|
61
64
|
* @classdesc
|
|
62
65
|
* The result of a bulk write.
|
|
@@ -69,6 +72,8 @@ class BulkWriteResult {
|
|
|
69
72
|
*/
|
|
70
73
|
constructor(bulkResult) {
|
|
71
74
|
this.result = bulkResult;
|
|
75
|
+
this[kUpsertedIds] = undefined;
|
|
76
|
+
this[kInsertedIds] = undefined;
|
|
72
77
|
}
|
|
73
78
|
|
|
74
79
|
/** Number of documents inserted. */
|
|
@@ -94,20 +99,33 @@ class BulkWriteResult {
|
|
|
94
99
|
|
|
95
100
|
/** Upserted document generated Id's, hash key is the index of the originating operation */
|
|
96
101
|
get upsertedIds() {
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
102
|
+
if (this[kUpsertedIds]) {
|
|
103
|
+
return this[kUpsertedIds];
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
this[kUpsertedIds] = {};
|
|
107
|
+
for (const doc of this.result.upserted || []) {
|
|
108
|
+
this[kUpsertedIds][doc.index] = doc._id;
|
|
100
109
|
}
|
|
101
|
-
return
|
|
110
|
+
return this[kUpsertedIds];
|
|
102
111
|
}
|
|
103
112
|
|
|
104
113
|
/** Inserted document generated Id's, hash key is the index of the originating operation */
|
|
105
114
|
get insertedIds() {
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
115
|
+
if (this[kInsertedIds]) {
|
|
116
|
+
return this[kInsertedIds];
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
this[kInsertedIds] = {};
|
|
120
|
+
for (const doc of this.result.insertedIds || []) {
|
|
121
|
+
this[kInsertedIds][doc.index] = doc._id;
|
|
109
122
|
}
|
|
110
|
-
return
|
|
123
|
+
return this[kInsertedIds];
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/** The number of inserted documents @type {number} */
|
|
127
|
+
get n() {
|
|
128
|
+
return this.result.insertedCount;
|
|
111
129
|
}
|
|
112
130
|
|
|
113
131
|
/**
|
|
@@ -1158,8 +1176,11 @@ class BulkOperationBase {
|
|
|
1158
1176
|
* @param {function} callback
|
|
1159
1177
|
*/
|
|
1160
1178
|
bulkExecute(_writeConcern, options, callback) {
|
|
1161
|
-
if (typeof options === 'function')
|
|
1162
|
-
|
|
1179
|
+
if (typeof options === 'function') {
|
|
1180
|
+
callback = options;
|
|
1181
|
+
}
|
|
1182
|
+
|
|
1183
|
+
const finalOptions = Object.assign({}, this.s.options, options);
|
|
1163
1184
|
|
|
1164
1185
|
if (typeof _writeConcern === 'function') {
|
|
1165
1186
|
callback = _writeConcern;
|
|
@@ -1185,7 +1206,7 @@ class BulkOperationBase {
|
|
|
1185
1206
|
const emptyBatchError = toError('Invalid Operation, no operations specified');
|
|
1186
1207
|
return this._handleEarlyError(emptyBatchError, callback);
|
|
1187
1208
|
}
|
|
1188
|
-
return { options, callback };
|
|
1209
|
+
return { options: finalOptions, callback };
|
|
1189
1210
|
}
|
|
1190
1211
|
|
|
1191
1212
|
/**
|
|
@@ -1370,5 +1391,6 @@ module.exports = {
|
|
|
1370
1391
|
INSERT: INSERT,
|
|
1371
1392
|
UPDATE: UPDATE,
|
|
1372
1393
|
REMOVE: REMOVE,
|
|
1373
|
-
BulkWriteError
|
|
1394
|
+
BulkWriteError,
|
|
1395
|
+
BulkWriteResult
|
|
1374
1396
|
};
|
package/lib/cmap/connection.js
CHANGED
|
@@ -122,7 +122,7 @@ class Connection extends EventEmitter {
|
|
|
122
122
|
if (issue.isTimeout) {
|
|
123
123
|
op.cb(
|
|
124
124
|
new MongoNetworkTimeoutError(`connection ${this.id} to ${this.address} timed out`, {
|
|
125
|
-
beforeHandshake:
|
|
125
|
+
beforeHandshake: this.ismaster == null
|
|
126
126
|
})
|
|
127
127
|
);
|
|
128
128
|
} else if (issue.isClose) {
|
|
@@ -317,6 +317,7 @@ function write(command, options, callback) {
|
|
|
317
317
|
promoteLongs: typeof options.promoteLongs === 'boolean' ? options.promoteLongs : true,
|
|
318
318
|
promoteValues: typeof options.promoteValues === 'boolean' ? options.promoteValues : true,
|
|
319
319
|
promoteBuffers: typeof options.promoteBuffers === 'boolean' ? options.promoteBuffers : false,
|
|
320
|
+
bsonRegExp: typeof options.bsonRegExp === 'boolean' ? options.bsonRegExp : false,
|
|
320
321
|
raw: typeof options.raw === 'boolean' ? options.raw : false
|
|
321
322
|
};
|
|
322
323
|
|
package/lib/collection.js
CHANGED
|
@@ -120,6 +120,8 @@ function Collection(db, topology, dbName, name, pkFactory, options) {
|
|
|
120
120
|
options == null || options.promoteBuffers == null
|
|
121
121
|
? db.s.options.promoteBuffers
|
|
122
122
|
: options.promoteBuffers;
|
|
123
|
+
const bsonRegExp =
|
|
124
|
+
options == null || options.bsonRegExp == null ? db.s.options.bsonRegExp : options.bsonRegExp;
|
|
123
125
|
const collectionHint = null;
|
|
124
126
|
|
|
125
127
|
const namespace = new MongoDBNamespace(dbName, name);
|
|
@@ -156,6 +158,8 @@ function Collection(db, topology, dbName, name, pkFactory, options) {
|
|
|
156
158
|
promoteValues: promoteValues,
|
|
157
159
|
// promoteBuffers
|
|
158
160
|
promoteBuffers: promoteBuffers,
|
|
161
|
+
// bsonRegExp
|
|
162
|
+
bsonRegExp: bsonRegExp,
|
|
159
163
|
// internalHint
|
|
160
164
|
internalHint: internalHint,
|
|
161
165
|
// collectionHint
|
|
@@ -303,6 +307,7 @@ const DEPRECATED_FIND_OPTIONS = ['maxScan', 'fields', 'snapshot', 'oplogReplay']
|
|
|
303
307
|
* @param {boolean} [options.promoteLongs=true] Promotes Long values to number if they fit inside the 53 bits resolution.
|
|
304
308
|
* @param {boolean} [options.promoteValues=true] Promotes BSON values to native types where possible, set to false to only receive wrapper types.
|
|
305
309
|
* @param {boolean} [options.promoteBuffers=false] Promotes Binary BSON values to native Node Buffers.
|
|
310
|
+
* @param {boolean} [options.bsonRegExp=false] By default, regex returned from MDB will be native to the language. Setting to true will ensure that a BSON.BSONRegExp object is returned.
|
|
306
311
|
* @param {(ReadPreference|string)} [options.readPreference] The preferred read preference (ReadPreference.PRIMARY, ReadPreference.PRIMARY_PREFERRED, ReadPreference.SECONDARY, ReadPreference.SECONDARY_PREFERRED, ReadPreference.NEAREST).
|
|
307
312
|
* @param {boolean} [options.partial=false] Specify if the cursor should return partial results when querying against a sharded system
|
|
308
313
|
* @param {number} [options.maxTimeMS] Number of milliseconds to wait before aborting the query.
|
|
@@ -451,6 +456,8 @@ Collection.prototype.find = deprecateOptions(
|
|
|
451
456
|
newOptions.promoteValues = this.s.promoteValues;
|
|
452
457
|
if (newOptions.promoteBuffers == null && typeof this.s.promoteBuffers === 'boolean')
|
|
453
458
|
newOptions.promoteBuffers = this.s.promoteBuffers;
|
|
459
|
+
if (newOptions.bsonRegExp == null && typeof this.s.bsonRegExp === 'boolean')
|
|
460
|
+
newOptions.bsonRegExp = this.s.bsonRegExp;
|
|
454
461
|
|
|
455
462
|
// Sort options
|
|
456
463
|
if (findCommand.sort) {
|
|
@@ -1075,6 +1082,7 @@ Collection.prototype.save = deprecate(function(doc, options, callback) {
|
|
|
1075
1082
|
* @param {boolean} [options.promoteLongs=true] Promotes Long values to number if they fit inside the 53 bits resolution.
|
|
1076
1083
|
* @param {boolean} [options.promoteValues=true] Promotes BSON values to native types where possible, set to false to only receive wrapper types.
|
|
1077
1084
|
* @param {boolean} [options.promoteBuffers=false] Promotes Binary BSON values to native Node Buffers.
|
|
1085
|
+
* @param {boolean} [options.bsonRegExp=false] By default, regex returned from MDB will be native to the language. Setting to true will ensure that a BSON.BSONRegExp object is returned.
|
|
1078
1086
|
* @param {(ReadPreference|string)} [options.readPreference] The preferred read preference (ReadPreference.PRIMARY, ReadPreference.PRIMARY_PREFERRED, ReadPreference.SECONDARY, ReadPreference.SECONDARY_PREFERRED, ReadPreference.NEAREST).
|
|
1079
1087
|
* @param {boolean} [options.partial=false] Specify if the cursor should return partial results when querying against a sharded system
|
|
1080
1088
|
* @param {number} [options.maxTimeMS] Number of milliseconds to wait before aborting the query.
|
|
@@ -1899,6 +1907,7 @@ Collection.prototype.findAndRemove = deprecate(function(query, sort, options, ca
|
|
|
1899
1907
|
* @param {boolean} [options.promoteLongs=true] Promotes Long values to number if they fit inside the 53 bits resolution.
|
|
1900
1908
|
* @param {boolean} [options.promoteValues=true] Promotes BSON values to native types where possible, set to false to only receive wrapper types.
|
|
1901
1909
|
* @param {boolean} [options.promoteBuffers=false] Promotes Binary BSON values to native Node Buffers.
|
|
1910
|
+
* @param {boolean} [options.bsonRegExp=false] By default, regex returned from MDB will be native to the language. Setting to true will ensure that a BSON.BSONRegExp object is returned.
|
|
1902
1911
|
* @param {object} [options.collation] Specify collation settings for operation. See {@link https://docs.mongodb.com/manual/reference/command/aggregate|aggregation documentation}.
|
|
1903
1912
|
* @param {string} [options.comment] Add a comment to an aggregation command
|
|
1904
1913
|
* @param {string|object} [options.hint] Add an index selection hint to an aggregation command
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
const Msg = require('./core/connection/msg').Msg;
|
|
3
|
+
const KillCursor = require('./core/connection/commands').KillCursor;
|
|
4
|
+
const GetMore = require('./core/connection/commands').GetMore;
|
|
5
|
+
const deepCopy = require('./utils').deepCopy;
|
|
6
|
+
|
|
7
|
+
/** Commands that we want to redact because of the sensitive nature of their contents */
|
|
8
|
+
const SENSITIVE_COMMANDS = new Set([
|
|
9
|
+
'authenticate',
|
|
10
|
+
'saslStart',
|
|
11
|
+
'saslContinue',
|
|
12
|
+
'getnonce',
|
|
13
|
+
'createUser',
|
|
14
|
+
'updateUser',
|
|
15
|
+
'copydbgetnonce',
|
|
16
|
+
'copydbsaslstart',
|
|
17
|
+
'copydb'
|
|
18
|
+
]);
|
|
19
|
+
|
|
20
|
+
const HELLO_COMMANDS = new Set(['hello', 'ismaster', 'isMaster']);
|
|
21
|
+
|
|
22
|
+
const LEGACY_FIND_QUERY_MAP = {
|
|
23
|
+
$query: 'filter',
|
|
24
|
+
$orderby: 'sort',
|
|
25
|
+
$hint: 'hint',
|
|
26
|
+
$comment: 'comment',
|
|
27
|
+
$maxScan: 'maxScan',
|
|
28
|
+
$max: 'max',
|
|
29
|
+
$min: 'min',
|
|
30
|
+
$returnKey: 'returnKey',
|
|
31
|
+
$showDiskLoc: 'showRecordId',
|
|
32
|
+
$maxTimeMS: 'maxTimeMS',
|
|
33
|
+
$snapshot: 'snapshot'
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
const LEGACY_FIND_OPTIONS_MAP = {
|
|
37
|
+
numberToSkip: 'skip',
|
|
38
|
+
numberToReturn: 'batchSize',
|
|
39
|
+
returnFieldsSelector: 'projection'
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
const OP_QUERY_KEYS = [
|
|
43
|
+
'tailable',
|
|
44
|
+
'oplogReplay',
|
|
45
|
+
'noCursorTimeout',
|
|
46
|
+
'awaitData',
|
|
47
|
+
'partial',
|
|
48
|
+
'exhaust'
|
|
49
|
+
];
|
|
50
|
+
|
|
51
|
+
const collectionName = command => command.ns.split('.')[1];
|
|
52
|
+
|
|
53
|
+
const shouldRedactCommand = (commandName, cmd) =>
|
|
54
|
+
SENSITIVE_COMMANDS.has(commandName) ||
|
|
55
|
+
(HELLO_COMMANDS.has(commandName) && !!cmd.speculativeAuthenticate);
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Extract the actual command from the query, possibly upconverting if it's a legacy
|
|
59
|
+
* format
|
|
60
|
+
*
|
|
61
|
+
* @param {Object} command the command
|
|
62
|
+
*/
|
|
63
|
+
const extractCommand = command => {
|
|
64
|
+
let extractedCommand;
|
|
65
|
+
if (command instanceof GetMore) {
|
|
66
|
+
extractedCommand = {
|
|
67
|
+
getMore: deepCopy(command.cursorId),
|
|
68
|
+
collection: collectionName(command),
|
|
69
|
+
batchSize: command.numberToReturn
|
|
70
|
+
};
|
|
71
|
+
} else if (command instanceof KillCursor) {
|
|
72
|
+
extractedCommand = {
|
|
73
|
+
killCursors: collectionName(command),
|
|
74
|
+
cursors: deepCopy(command.cursorIds)
|
|
75
|
+
};
|
|
76
|
+
} else if (command instanceof Msg) {
|
|
77
|
+
extractedCommand = deepCopy(command.command);
|
|
78
|
+
} else if (command.query && command.query.$query) {
|
|
79
|
+
let result;
|
|
80
|
+
if (command.ns === 'admin.$cmd') {
|
|
81
|
+
// upconvert legacy command
|
|
82
|
+
result = Object.assign({}, command.query.$query);
|
|
83
|
+
} else {
|
|
84
|
+
// upconvert legacy find command
|
|
85
|
+
result = { find: collectionName(command) };
|
|
86
|
+
Object.keys(LEGACY_FIND_QUERY_MAP).forEach(key => {
|
|
87
|
+
if (typeof command.query[key] !== 'undefined')
|
|
88
|
+
result[LEGACY_FIND_QUERY_MAP[key]] = deepCopy(command.query[key]);
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
Object.keys(LEGACY_FIND_OPTIONS_MAP).forEach(key => {
|
|
93
|
+
if (typeof command[key] !== 'undefined')
|
|
94
|
+
result[LEGACY_FIND_OPTIONS_MAP[key]] = deepCopy(command[key]);
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
OP_QUERY_KEYS.forEach(key => {
|
|
98
|
+
if (command[key]) result[key] = command[key];
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
if (typeof command.pre32Limit !== 'undefined') {
|
|
102
|
+
result.limit = command.pre32Limit;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
if (command.query.$explain) {
|
|
106
|
+
extractedCommand = { explain: result };
|
|
107
|
+
} else {
|
|
108
|
+
extractedCommand = result;
|
|
109
|
+
}
|
|
110
|
+
} else {
|
|
111
|
+
extractedCommand = deepCopy(command.query || command);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const commandName = Object.keys(extractedCommand)[0];
|
|
115
|
+
return {
|
|
116
|
+
cmd: extractedCommand,
|
|
117
|
+
name: commandName,
|
|
118
|
+
shouldRedact: shouldRedactCommand(commandName, extractedCommand)
|
|
119
|
+
};
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
module.exports = {
|
|
123
|
+
extractCommand
|
|
124
|
+
};
|
package/lib/core/auth/scram.js
CHANGED
|
@@ -1,123 +1,16 @@
|
|
|
1
1
|
'use strict';
|
|
2
|
-
const Msg = require('../connection/msg').Msg;
|
|
3
2
|
const KillCursor = require('../connection/commands').KillCursor;
|
|
4
3
|
const GetMore = require('../connection/commands').GetMore;
|
|
5
4
|
const calculateDurationInMs = require('../../utils').calculateDurationInMs;
|
|
6
|
-
|
|
7
|
-
/** Commands that we want to redact because of the sensitive nature of their contents */
|
|
8
|
-
const SENSITIVE_COMMANDS = new Set([
|
|
9
|
-
'authenticate',
|
|
10
|
-
'saslStart',
|
|
11
|
-
'saslContinue',
|
|
12
|
-
'getnonce',
|
|
13
|
-
'createUser',
|
|
14
|
-
'updateUser',
|
|
15
|
-
'copydbgetnonce',
|
|
16
|
-
'copydbsaslstart',
|
|
17
|
-
'copydb'
|
|
18
|
-
]);
|
|
5
|
+
const extractCommand = require('../../command_utils').extractCommand;
|
|
19
6
|
|
|
20
7
|
// helper methods
|
|
21
|
-
const extractCommandName = commandDoc => Object.keys(commandDoc)[0];
|
|
22
8
|
const namespace = command => command.ns;
|
|
23
9
|
const databaseName = command => command.ns.split('.')[0];
|
|
24
|
-
const collectionName = command => command.ns.split('.')[1];
|
|
25
10
|
const generateConnectionId = pool =>
|
|
26
11
|
pool.options ? `${pool.options.host}:${pool.options.port}` : pool.address;
|
|
27
|
-
const maybeRedact = (commandName, result) => (SENSITIVE_COMMANDS.has(commandName) ? {} : result);
|
|
28
12
|
const isLegacyPool = pool => pool.s && pool.queue;
|
|
29
13
|
|
|
30
|
-
const LEGACY_FIND_QUERY_MAP = {
|
|
31
|
-
$query: 'filter',
|
|
32
|
-
$orderby: 'sort',
|
|
33
|
-
$hint: 'hint',
|
|
34
|
-
$comment: 'comment',
|
|
35
|
-
$maxScan: 'maxScan',
|
|
36
|
-
$max: 'max',
|
|
37
|
-
$min: 'min',
|
|
38
|
-
$returnKey: 'returnKey',
|
|
39
|
-
$showDiskLoc: 'showRecordId',
|
|
40
|
-
$maxTimeMS: 'maxTimeMS',
|
|
41
|
-
$snapshot: 'snapshot'
|
|
42
|
-
};
|
|
43
|
-
|
|
44
|
-
const LEGACY_FIND_OPTIONS_MAP = {
|
|
45
|
-
numberToSkip: 'skip',
|
|
46
|
-
numberToReturn: 'batchSize',
|
|
47
|
-
returnFieldsSelector: 'projection'
|
|
48
|
-
};
|
|
49
|
-
|
|
50
|
-
const OP_QUERY_KEYS = [
|
|
51
|
-
'tailable',
|
|
52
|
-
'oplogReplay',
|
|
53
|
-
'noCursorTimeout',
|
|
54
|
-
'awaitData',
|
|
55
|
-
'partial',
|
|
56
|
-
'exhaust'
|
|
57
|
-
];
|
|
58
|
-
|
|
59
|
-
/**
|
|
60
|
-
* Extract the actual command from the query, possibly upconverting if it's a legacy
|
|
61
|
-
* format
|
|
62
|
-
*
|
|
63
|
-
* @param {Object} command the command
|
|
64
|
-
*/
|
|
65
|
-
const extractCommand = command => {
|
|
66
|
-
if (command instanceof GetMore) {
|
|
67
|
-
return {
|
|
68
|
-
getMore: command.cursorId,
|
|
69
|
-
collection: collectionName(command),
|
|
70
|
-
batchSize: command.numberToReturn
|
|
71
|
-
};
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
if (command instanceof KillCursor) {
|
|
75
|
-
return {
|
|
76
|
-
killCursors: collectionName(command),
|
|
77
|
-
cursors: command.cursorIds
|
|
78
|
-
};
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
if (command instanceof Msg) {
|
|
82
|
-
return command.command;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
if (command.query && command.query.$query) {
|
|
86
|
-
let result;
|
|
87
|
-
if (command.ns === 'admin.$cmd') {
|
|
88
|
-
// upconvert legacy command
|
|
89
|
-
result = Object.assign({}, command.query.$query);
|
|
90
|
-
} else {
|
|
91
|
-
// upconvert legacy find command
|
|
92
|
-
result = { find: collectionName(command) };
|
|
93
|
-
Object.keys(LEGACY_FIND_QUERY_MAP).forEach(key => {
|
|
94
|
-
if (typeof command.query[key] !== 'undefined')
|
|
95
|
-
result[LEGACY_FIND_QUERY_MAP[key]] = command.query[key];
|
|
96
|
-
});
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
Object.keys(LEGACY_FIND_OPTIONS_MAP).forEach(key => {
|
|
100
|
-
if (typeof command[key] !== 'undefined') result[LEGACY_FIND_OPTIONS_MAP[key]] = command[key];
|
|
101
|
-
});
|
|
102
|
-
|
|
103
|
-
OP_QUERY_KEYS.forEach(key => {
|
|
104
|
-
if (command[key]) result[key] = command[key];
|
|
105
|
-
});
|
|
106
|
-
|
|
107
|
-
if (typeof command.pre32Limit !== 'undefined') {
|
|
108
|
-
result.limit = command.pre32Limit;
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
if (command.query.$explain) {
|
|
112
|
-
return { explain: result };
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
return result;
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
return command.query ? command.query : command;
|
|
119
|
-
};
|
|
120
|
-
|
|
121
14
|
const extractReply = (command, reply) => {
|
|
122
15
|
if (command instanceof GetMore) {
|
|
123
16
|
return {
|
|
@@ -177,21 +70,15 @@ class CommandStartedEvent {
|
|
|
177
70
|
* @param {Object} command the command
|
|
178
71
|
*/
|
|
179
72
|
constructor(pool, command) {
|
|
180
|
-
const
|
|
181
|
-
const commandName =
|
|
73
|
+
const extractedCommand = extractCommand(command);
|
|
74
|
+
const commandName = extractedCommand.name;
|
|
182
75
|
const connectionDetails = extractConnectionDetails(pool);
|
|
183
76
|
|
|
184
|
-
// NOTE: remove in major revision, this is not spec behavior
|
|
185
|
-
if (SENSITIVE_COMMANDS.has(commandName)) {
|
|
186
|
-
this.commandObj = {};
|
|
187
|
-
this.commandObj[commandName] = true;
|
|
188
|
-
}
|
|
189
|
-
|
|
190
77
|
Object.assign(this, connectionDetails, {
|
|
191
78
|
requestId: command.requestId,
|
|
192
79
|
databaseName: databaseName(command),
|
|
193
80
|
commandName,
|
|
194
|
-
command: cmd
|
|
81
|
+
command: extractedCommand.shouldRedact ? {} : extractedCommand.cmd
|
|
195
82
|
});
|
|
196
83
|
}
|
|
197
84
|
}
|
|
@@ -207,15 +94,15 @@ class CommandSucceededEvent {
|
|
|
207
94
|
* @param {Array} started a high resolution tuple timestamp of when the command was first sent, to calculate duration
|
|
208
95
|
*/
|
|
209
96
|
constructor(pool, command, reply, started) {
|
|
210
|
-
const
|
|
211
|
-
const commandName =
|
|
97
|
+
const extractedCommand = extractCommand(command);
|
|
98
|
+
const commandName = extractedCommand.name;
|
|
212
99
|
const connectionDetails = extractConnectionDetails(pool);
|
|
213
100
|
|
|
214
101
|
Object.assign(this, connectionDetails, {
|
|
215
102
|
requestId: command.requestId,
|
|
216
103
|
commandName,
|
|
217
104
|
duration: calculateDurationInMs(started),
|
|
218
|
-
reply:
|
|
105
|
+
reply: extractedCommand.shouldRedact ? {} : extractReply(command, reply)
|
|
219
106
|
});
|
|
220
107
|
}
|
|
221
108
|
}
|
|
@@ -231,15 +118,15 @@ class CommandFailedEvent {
|
|
|
231
118
|
* @param {Array} started a high resolution tuple timestamp of when the command was first sent, to calculate duration
|
|
232
119
|
*/
|
|
233
120
|
constructor(pool, command, error, started) {
|
|
234
|
-
const
|
|
235
|
-
const commandName =
|
|
121
|
+
const extractedCommand = extractCommand(command);
|
|
122
|
+
const commandName = extractedCommand.name;
|
|
236
123
|
const connectionDetails = extractConnectionDetails(pool);
|
|
237
124
|
|
|
238
125
|
Object.assign(this, connectionDetails, {
|
|
239
126
|
requestId: command.requestId,
|
|
240
127
|
commandName,
|
|
241
128
|
duration: calculateDurationInMs(started),
|
|
242
|
-
failure:
|
|
129
|
+
failure: extractedCommand.shouldRedact ? {} : error
|
|
243
130
|
});
|
|
244
131
|
}
|
|
245
132
|
}
|
|
@@ -398,7 +398,12 @@ KillCursor.prototype.toBin = function() {
|
|
|
398
398
|
};
|
|
399
399
|
|
|
400
400
|
var Response = function(bson, message, msgHeader, msgBody, opts) {
|
|
401
|
-
opts = opts || {
|
|
401
|
+
opts = opts || {
|
|
402
|
+
promoteLongs: true,
|
|
403
|
+
promoteValues: true,
|
|
404
|
+
promoteBuffers: false,
|
|
405
|
+
bsonRegExp: false
|
|
406
|
+
};
|
|
402
407
|
this.parsed = false;
|
|
403
408
|
this.raw = message;
|
|
404
409
|
this.data = msgBody;
|
|
@@ -429,6 +434,7 @@ var Response = function(bson, message, msgHeader, msgBody, opts) {
|
|
|
429
434
|
this.promoteLongs = typeof opts.promoteLongs === 'boolean' ? opts.promoteLongs : true;
|
|
430
435
|
this.promoteValues = typeof opts.promoteValues === 'boolean' ? opts.promoteValues : true;
|
|
431
436
|
this.promoteBuffers = typeof opts.promoteBuffers === 'boolean' ? opts.promoteBuffers : false;
|
|
437
|
+
this.bsonRegExp = typeof opts.bsonRegExp === 'boolean' ? opts.bsonRegExp : false;
|
|
432
438
|
};
|
|
433
439
|
|
|
434
440
|
Response.prototype.isParsed = function() {
|
|
@@ -449,13 +455,16 @@ Response.prototype.parse = function(options) {
|
|
|
449
455
|
typeof options.promoteValues === 'boolean' ? options.promoteValues : this.opts.promoteValues;
|
|
450
456
|
var promoteBuffers =
|
|
451
457
|
typeof options.promoteBuffers === 'boolean' ? options.promoteBuffers : this.opts.promoteBuffers;
|
|
458
|
+
var bsonRegExp =
|
|
459
|
+
typeof options.bsonRegExp === 'boolean' ? options.bsonRegExp : this.opts.bsonRegExp;
|
|
452
460
|
var bsonSize, _options;
|
|
453
461
|
|
|
454
462
|
// Set up the options
|
|
455
463
|
_options = {
|
|
456
464
|
promoteLongs: promoteLongs,
|
|
457
465
|
promoteValues: promoteValues,
|
|
458
|
-
promoteBuffers: promoteBuffers
|
|
466
|
+
promoteBuffers: promoteBuffers,
|
|
467
|
+
bsonRegExp: bsonRegExp
|
|
459
468
|
};
|
|
460
469
|
|
|
461
470
|
// Position within OP_REPLY at which documents start
|
|
@@ -179,6 +179,9 @@ function prepareHandshakeDocument(authContext, callback) {
|
|
|
179
179
|
}
|
|
180
180
|
|
|
181
181
|
const authProvider = AUTH_PROVIDERS[credentials.mechanism];
|
|
182
|
+
if (authProvider == null) {
|
|
183
|
+
return callback(new MongoError(`No AuthProvider for ${credentials.mechanism} defined.`));
|
|
184
|
+
}
|
|
182
185
|
authProvider.prepare(handshakeDoc, authContext, callback);
|
|
183
186
|
return;
|
|
184
187
|
}
|
|
@@ -38,6 +38,7 @@ const DEBUG_FIELDS = [
|
|
|
38
38
|
'promoteLongs',
|
|
39
39
|
'promoteValues',
|
|
40
40
|
'promoteBuffers',
|
|
41
|
+
'bsonRegExp',
|
|
41
42
|
'checkServerIdentity'
|
|
42
43
|
];
|
|
43
44
|
|
|
@@ -73,6 +74,7 @@ class Connection extends EventEmitter {
|
|
|
73
74
|
* @param {boolean} [options.promoteLongs] Convert Long values from the db into Numbers if they fit into 53 bits
|
|
74
75
|
* @param {boolean} [options.promoteValues] Promotes BSON values to native types where possible, set to false to only receive wrapper types.
|
|
75
76
|
* @param {boolean} [options.promoteBuffers] Promotes Binary BSON values to native Node Buffers.
|
|
77
|
+
* @param {boolean} [options.bsonRegExp] By default, regex returned from MDB will be native to the language. Setting to true will ensure that a BSON.BSONRegExp object is returned.
|
|
76
78
|
* @param {number} [options.maxBsonMessageSize=0x4000000] Largest possible size of a BSON message (for legacy purposes)
|
|
77
79
|
*/
|
|
78
80
|
constructor(socket, options) {
|
|
@@ -117,7 +119,8 @@ class Connection extends EventEmitter {
|
|
|
117
119
|
this.responseOptions = {
|
|
118
120
|
promoteLongs: typeof options.promoteLongs === 'boolean' ? options.promoteLongs : true,
|
|
119
121
|
promoteValues: typeof options.promoteValues === 'boolean' ? options.promoteValues : true,
|
|
120
|
-
promoteBuffers: typeof options.promoteBuffers === 'boolean' ? options.promoteBuffers : false
|
|
122
|
+
promoteBuffers: typeof options.promoteBuffers === 'boolean' ? options.promoteBuffers : false,
|
|
123
|
+
bsonRegExp: typeof options.bsonRegExp === 'boolean' ? options.bsonRegExp : false
|
|
121
124
|
};
|
|
122
125
|
|
|
123
126
|
// Flushing
|
|
@@ -254,10 +257,10 @@ class Connection extends EventEmitter {
|
|
|
254
257
|
// Debug Log
|
|
255
258
|
if (this.logger.isDebug()) {
|
|
256
259
|
if (!Array.isArray(buffer)) {
|
|
257
|
-
this.logger.debug(`writing buffer [${buffer.
|
|
260
|
+
this.logger.debug(`writing buffer [ ${buffer.length} ] to ${this.address}`);
|
|
258
261
|
} else {
|
|
259
262
|
for (let i = 0; i < buffer.length; i++)
|
|
260
|
-
this.logger.debug(`writing buffer [${buffer[i].
|
|
263
|
+
this.logger.debug(`writing buffer [ ${buffer[i].length} ] to ${this.address}`);
|
|
261
264
|
}
|
|
262
265
|
}
|
|
263
266
|
|