mongodb 3.6.9 → 3.7.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.
- package/README.md +4 -4
- package/index.js +4 -0
- package/lib/bulk/common.js +6 -3
- package/lib/cmap/connection.js +35 -7
- package/lib/cmap/connection_pool.js +1 -0
- package/lib/collection.js +10 -1
- package/lib/command_utils.js +124 -0
- package/lib/core/auth/mongo_credentials.js +4 -1
- package/lib/core/auth/mongodb_aws.js +17 -15
- 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 +10 -1
- package/lib/core/connection/connection.js +7 -3
- package/lib/core/connection/msg.js +11 -2
- package/lib/core/connection/pool.js +7 -2
- package/lib/core/connection/utils.js +35 -2
- package/lib/core/cursor.js +7 -0
- package/lib/core/index.js +10 -0
- package/lib/core/sdam/monitor.js +9 -2
- package/lib/core/sdam/server.js +10 -1
- package/lib/core/sdam/topology.js +34 -16
- package/lib/core/sessions.js +11 -8
- 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/transactions.js +5 -1
- package/lib/core/uri_parser.js +5 -0
- package/lib/core/utils.js +1 -0
- package/lib/core/wireprotocol/command.js +24 -0
- package/lib/core/wireprotocol/constants.js +2 -2
- package/lib/core/wireprotocol/kill_cursors.js +7 -2
- package/lib/core/wireprotocol/query.js +9 -5
- package/lib/core/wireprotocol/shared.js +1 -0
- package/lib/cursor.js +16 -2
- package/lib/db.js +83 -72
- package/lib/encrypter.js +8 -3
- package/lib/explain.js +5 -12
- package/lib/gridfs-stream/index.js +39 -24
- package/lib/gridfs-stream/upload.js +46 -38
- package/lib/mongo_client.js +31 -5
- package/lib/operations/command.js +4 -1
- package/lib/operations/command_v2.js +7 -1
- package/lib/operations/connect.js +2 -0
- package/lib/operations/db_ops.js +6 -2
- package/lib/operations/estimated_document_count.js +46 -18
- package/lib/topologies/mongos.js +1 -0
- package/lib/topologies/native_topology.js +2 -0
- package/lib/topologies/replset.js +1 -0
- package/lib/topologies/server.js +1 -0
- package/lib/utils.js +87 -1
- package/package.json +7 -3
- package/HISTORY.md +0 -2889
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/index.js
CHANGED
|
@@ -17,6 +17,9 @@ connect.MongoWriteConcernError = core.MongoWriteConcernError;
|
|
|
17
17
|
connect.MongoBulkWriteError = require('./lib/bulk/common').BulkWriteError;
|
|
18
18
|
connect.BulkWriteError = connect.MongoBulkWriteError;
|
|
19
19
|
|
|
20
|
+
// Expose server versions
|
|
21
|
+
connect.ServerApiVersion = core.ServerApiVersion;
|
|
22
|
+
|
|
20
23
|
// Actual driver classes exported
|
|
21
24
|
connect.Admin = require('./lib/admin');
|
|
22
25
|
connect.MongoClient = require('./lib/mongo_client');
|
|
@@ -47,6 +50,7 @@ connect.Int32 = core.BSON.Int32;
|
|
|
47
50
|
connect.Long = core.BSON.Long;
|
|
48
51
|
connect.MinKey = core.BSON.MinKey;
|
|
49
52
|
connect.MaxKey = core.BSON.MaxKey;
|
|
53
|
+
/** @deprecated Please use `ObjectId` */
|
|
50
54
|
connect.ObjectID = core.BSON.ObjectID;
|
|
51
55
|
connect.ObjectId = core.BSON.ObjectID;
|
|
52
56
|
connect.Symbol = core.BSON.Symbol;
|
package/lib/bulk/common.js
CHANGED
|
@@ -1176,8 +1176,11 @@ class BulkOperationBase {
|
|
|
1176
1176
|
* @param {function} callback
|
|
1177
1177
|
*/
|
|
1178
1178
|
bulkExecute(_writeConcern, options, callback) {
|
|
1179
|
-
if (typeof options === 'function')
|
|
1180
|
-
|
|
1179
|
+
if (typeof options === 'function') {
|
|
1180
|
+
callback = options;
|
|
1181
|
+
}
|
|
1182
|
+
|
|
1183
|
+
const finalOptions = Object.assign({}, this.s.options, options);
|
|
1181
1184
|
|
|
1182
1185
|
if (typeof _writeConcern === 'function') {
|
|
1183
1186
|
callback = _writeConcern;
|
|
@@ -1203,7 +1206,7 @@ class BulkOperationBase {
|
|
|
1203
1206
|
const emptyBatchError = toError('Invalid Operation, no operations specified');
|
|
1204
1207
|
return this._handleEarlyError(emptyBatchError, callback);
|
|
1205
1208
|
}
|
|
1206
|
-
return { options, callback };
|
|
1209
|
+
return { options: finalOptions, callback };
|
|
1207
1210
|
}
|
|
1208
1211
|
|
|
1209
1212
|
/**
|
package/lib/cmap/connection.js
CHANGED
|
@@ -37,6 +37,8 @@ class Connection extends EventEmitter {
|
|
|
37
37
|
this.port = options.port || 27017;
|
|
38
38
|
this.monitorCommands =
|
|
39
39
|
typeof options.monitorCommands === 'boolean' ? options.monitorCommands : false;
|
|
40
|
+
this.serverApi = options.serverApi;
|
|
41
|
+
|
|
40
42
|
this.closed = false;
|
|
41
43
|
this.destroyed = false;
|
|
42
44
|
|
|
@@ -170,33 +172,58 @@ class Connection extends EventEmitter {
|
|
|
170
172
|
});
|
|
171
173
|
}
|
|
172
174
|
|
|
175
|
+
applyApiVersion(options) {
|
|
176
|
+
if (this.serverApi) {
|
|
177
|
+
options.serverApi = this.serverApi;
|
|
178
|
+
}
|
|
179
|
+
return options;
|
|
180
|
+
}
|
|
181
|
+
|
|
173
182
|
// Wire protocol methods
|
|
174
183
|
command(ns, cmd, options, callback) {
|
|
175
|
-
|
|
184
|
+
if (typeof options === 'function') {
|
|
185
|
+
callback = options;
|
|
186
|
+
options = {};
|
|
187
|
+
}
|
|
188
|
+
wp.command(makeServerTrampoline(this), ns, cmd, this.applyApiVersion(options), callback);
|
|
176
189
|
}
|
|
177
190
|
|
|
178
191
|
query(ns, cmd, cursorState, options, callback) {
|
|
179
|
-
wp.query(
|
|
192
|
+
wp.query(
|
|
193
|
+
makeServerTrampoline(this),
|
|
194
|
+
ns,
|
|
195
|
+
cmd,
|
|
196
|
+
cursorState,
|
|
197
|
+
this.applyApiVersion(options),
|
|
198
|
+
callback
|
|
199
|
+
);
|
|
180
200
|
}
|
|
181
201
|
|
|
182
202
|
getMore(ns, cursorState, batchSize, options, callback) {
|
|
183
|
-
wp.getMore(
|
|
203
|
+
wp.getMore(
|
|
204
|
+
makeServerTrampoline(this),
|
|
205
|
+
ns,
|
|
206
|
+
cursorState,
|
|
207
|
+
batchSize,
|
|
208
|
+
this.applyApiVersion(options),
|
|
209
|
+
callback
|
|
210
|
+
);
|
|
184
211
|
}
|
|
185
212
|
|
|
186
213
|
killCursors(ns, cursorState, callback) {
|
|
187
|
-
wp.killCursors(makeServerTrampoline(this), ns, cursorState, callback);
|
|
214
|
+
wp.killCursors(makeServerTrampoline(this), ns, cursorState, this.applyApiVersion({}), callback);
|
|
188
215
|
}
|
|
189
216
|
|
|
190
217
|
insert(ns, ops, options, callback) {
|
|
191
|
-
wp.insert(makeServerTrampoline(this), ns, ops, options, callback);
|
|
218
|
+
wp.insert(makeServerTrampoline(this), ns, ops, this.applyApiVersion(options), callback);
|
|
192
219
|
}
|
|
193
220
|
|
|
194
221
|
update(ns, ops, options, callback) {
|
|
195
|
-
wp.update(makeServerTrampoline(this), ns, ops, options, callback);
|
|
222
|
+
wp.update(makeServerTrampoline(this), ns, ops, this.applyApiVersion(options), callback);
|
|
196
223
|
}
|
|
197
224
|
|
|
198
225
|
remove(ns, ops, options, callback) {
|
|
199
|
-
wp.remove(makeServerTrampoline(this), ns, ops, options, callback);
|
|
226
|
+
wp.remove(makeServerTrampoline(this), ns, ops, this.applyApiVersion(options), callback);
|
|
200
227
|
}
|
|
201
228
|
}
|
|
202
229
|
|
|
@@ -317,6 +344,7 @@ function write(command, options, callback) {
|
|
|
317
344
|
promoteLongs: typeof options.promoteLongs === 'boolean' ? options.promoteLongs : true,
|
|
318
345
|
promoteValues: typeof options.promoteValues === 'boolean' ? options.promoteValues : true,
|
|
319
346
|
promoteBuffers: typeof options.promoteBuffers === 'boolean' ? options.promoteBuffers : false,
|
|
347
|
+
bsonRegExp: typeof options.bsonRegExp === 'boolean' ? options.bsonRegExp : false,
|
|
320
348
|
raw: typeof options.raw === 'boolean' ? options.raw : false
|
|
321
349
|
};
|
|
322
350
|
|
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.
|
|
@@ -1524,7 +1532,7 @@ Collection.prototype.count = deprecate(function(query, options, callback) {
|
|
|
1524
1532
|
|
|
1525
1533
|
return executeOperation(
|
|
1526
1534
|
this.s.topology,
|
|
1527
|
-
new EstimatedDocumentCountOperation(this, query, options),
|
|
1535
|
+
new EstimatedDocumentCountOperation(this, Object.assign({ query }, options)),
|
|
1528
1536
|
callback
|
|
1529
1537
|
);
|
|
1530
1538
|
}, 'collection.count is deprecated, and will be removed in a future version.' +
|
|
@@ -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
|
+
};
|
|
@@ -58,7 +58,10 @@ class MongoCredentials {
|
|
|
58
58
|
this.password = process.env.AWS_SECRET_ACCESS_KEY;
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
-
if (
|
|
61
|
+
if (
|
|
62
|
+
this.mechanismProperties.AWS_SESSION_TOKEN == null &&
|
|
63
|
+
process.env.AWS_SESSION_TOKEN != null
|
|
64
|
+
) {
|
|
62
65
|
this.mechanismProperties.AWS_SESSION_TOKEN = process.env.AWS_SESSION_TOKEN;
|
|
63
66
|
}
|
|
64
67
|
}
|
|
@@ -9,6 +9,7 @@ const url = require('url');
|
|
|
9
9
|
|
|
10
10
|
let aws4;
|
|
11
11
|
try {
|
|
12
|
+
// Ensure you always wrap an optional require in the try block NODE-3199
|
|
12
13
|
aws4 = require('aws4');
|
|
13
14
|
} catch (e) {
|
|
14
15
|
// don't do anything;
|
|
@@ -50,12 +51,21 @@ class MongoDBAWS extends AuthProvider {
|
|
|
50
51
|
return;
|
|
51
52
|
}
|
|
52
53
|
|
|
53
|
-
const username = credentials.username;
|
|
54
|
-
const password = credentials.password;
|
|
55
54
|
const db = credentials.source;
|
|
56
|
-
const token = credentials.mechanismProperties.AWS_SESSION_TOKEN;
|
|
57
55
|
const bson = this.bson;
|
|
58
56
|
|
|
57
|
+
const accessKeyId = credentials.username;
|
|
58
|
+
const secretAccessKey = credentials.password;
|
|
59
|
+
const sessionToken = credentials.mechanismProperties.AWS_SESSION_TOKEN;
|
|
60
|
+
|
|
61
|
+
// If all three defined, include sessionToken, else include username and pass, else no credentials
|
|
62
|
+
const awsCredentials =
|
|
63
|
+
accessKeyId && secretAccessKey && sessionToken
|
|
64
|
+
? { accessKeyId, secretAccessKey, sessionToken }
|
|
65
|
+
: accessKeyId && secretAccessKey
|
|
66
|
+
? { accessKeyId, secretAccessKey }
|
|
67
|
+
: undefined;
|
|
68
|
+
|
|
59
69
|
crypto.randomBytes(32, (err, nonce) => {
|
|
60
70
|
if (err) {
|
|
61
71
|
callback(err);
|
|
@@ -108,18 +118,14 @@ class MongoDBAWS extends AuthProvider {
|
|
|
108
118
|
path: '/',
|
|
109
119
|
body
|
|
110
120
|
},
|
|
111
|
-
|
|
112
|
-
accessKeyId: username,
|
|
113
|
-
secretAccessKey: password,
|
|
114
|
-
token
|
|
115
|
-
}
|
|
121
|
+
awsCredentials
|
|
116
122
|
);
|
|
117
123
|
|
|
118
124
|
const authorization = options.headers.Authorization;
|
|
119
125
|
const date = options.headers['X-Amz-Date'];
|
|
120
126
|
const payload = { a: authorization, d: date };
|
|
121
|
-
if (
|
|
122
|
-
payload.t =
|
|
127
|
+
if (sessionToken) {
|
|
128
|
+
payload.t = sessionToken;
|
|
123
129
|
}
|
|
124
130
|
|
|
125
131
|
const saslContinue = {
|
|
@@ -163,6 +169,7 @@ function makeTempCredentials(credentials, callback) {
|
|
|
163
169
|
if (process.env.AWS_CONTAINER_CREDENTIALS_RELATIVE_URI) {
|
|
164
170
|
request(
|
|
165
171
|
`${AWS_RELATIVE_URI}${process.env.AWS_CONTAINER_CREDENTIALS_RELATIVE_URI}`,
|
|
172
|
+
undefined,
|
|
166
173
|
(err, res) => {
|
|
167
174
|
if (err) return callback(err);
|
|
168
175
|
done(res);
|
|
@@ -214,11 +221,6 @@ function deriveRegion(host) {
|
|
|
214
221
|
}
|
|
215
222
|
|
|
216
223
|
function request(uri, options, callback) {
|
|
217
|
-
if (typeof options === 'function') {
|
|
218
|
-
callback = options;
|
|
219
|
-
options = {};
|
|
220
|
-
}
|
|
221
|
-
|
|
222
224
|
options = Object.assign(
|
|
223
225
|
{
|
|
224
226
|
method: 'GET',
|
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
|