mongodb 4.0.0 → 4.1.2
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 +62 -30
- package/lib/bson.js +1 -0
- package/lib/bson.js.map +1 -1
- package/lib/bulk/common.js +53 -30
- package/lib/bulk/common.js.map +1 -1
- package/lib/bulk/ordered.js +3 -2
- package/lib/bulk/ordered.js.map +1 -1
- package/lib/bulk/unordered.js +3 -2
- package/lib/bulk/unordered.js.map +1 -1
- package/lib/change_stream.js +23 -13
- package/lib/change_stream.js.map +1 -1
- package/lib/cmap/auth/auth_provider.js +2 -1
- package/lib/cmap/auth/auth_provider.js.map +1 -1
- package/lib/cmap/auth/gssapi.js +5 -4
- package/lib/cmap/auth/gssapi.js.map +1 -1
- package/lib/cmap/auth/mongo_credentials.js +9 -5
- package/lib/cmap/auth/mongo_credentials.js.map +1 -1
- package/lib/cmap/auth/mongocr.js +2 -2
- package/lib/cmap/auth/mongocr.js.map +1 -1
- package/lib/cmap/auth/mongodb_aws.js +32 -32
- package/lib/cmap/auth/mongodb_aws.js.map +1 -1
- package/lib/cmap/auth/plain.js +1 -1
- package/lib/cmap/auth/plain.js.map +1 -1
- package/lib/cmap/auth/scram.js +15 -12
- package/lib/cmap/auth/scram.js.map +1 -1
- package/lib/cmap/auth/x509.js +2 -2
- package/lib/cmap/auth/x509.js.map +1 -1
- package/lib/cmap/command_monitoring_events.js +26 -10
- package/lib/cmap/command_monitoring_events.js.map +1 -1
- package/lib/cmap/commands.js +9 -5
- package/lib/cmap/commands.js.map +1 -1
- package/lib/cmap/connect.js +23 -9
- package/lib/cmap/connect.js.map +1 -1
- package/lib/cmap/connection.js +43 -46
- package/lib/cmap/connection.js.map +1 -1
- package/lib/cmap/connection_pool.js +113 -15
- package/lib/cmap/connection_pool.js.map +1 -1
- package/lib/cmap/connection_pool_events.js +3 -1
- package/lib/cmap/connection_pool_events.js.map +1 -1
- package/lib/cmap/errors.js +3 -3
- package/lib/cmap/errors.js.map +1 -1
- package/lib/cmap/message_stream.js +1 -1
- package/lib/cmap/message_stream.js.map +1 -1
- package/lib/cmap/metrics.js +62 -0
- package/lib/cmap/metrics.js.map +1 -0
- package/lib/cmap/stream_description.js +3 -1
- package/lib/cmap/stream_description.js.map +1 -1
- package/lib/cmap/wire_protocol/compression.js +22 -9
- package/lib/cmap/wire_protocol/compression.js.map +1 -1
- package/lib/cmap/wire_protocol/shared.js +1 -1
- package/lib/cmap/wire_protocol/shared.js.map +1 -1
- package/lib/collection.js +23 -18
- package/lib/collection.js.map +1 -1
- package/lib/connection_string.js +76 -30
- package/lib/connection_string.js.map +1 -1
- package/lib/cursor/abstract_cursor.js +75 -68
- package/lib/cursor/abstract_cursor.js.map +1 -1
- package/lib/cursor/aggregation_cursor.js +47 -9
- package/lib/cursor/aggregation_cursor.js.map +1 -1
- package/lib/cursor/find_cursor.js +53 -13
- package/lib/cursor/find_cursor.js.map +1 -1
- package/lib/db.js +21 -14
- package/lib/db.js.map +1 -1
- package/lib/deps.js +16 -5
- package/lib/deps.js.map +1 -1
- package/lib/encrypter.js +5 -8
- package/lib/encrypter.js.map +1 -1
- package/lib/error.js +230 -34
- package/lib/error.js.map +1 -1
- package/lib/explain.js +2 -2
- package/lib/explain.js.map +1 -1
- package/lib/gridfs/download.js +22 -47
- package/lib/gridfs/download.js.map +1 -1
- package/lib/gridfs/index.js +4 -3
- package/lib/gridfs/index.js.map +1 -1
- package/lib/gridfs/upload.js +13 -21
- package/lib/gridfs/upload.js.map +1 -1
- package/lib/index.js +27 -2
- package/lib/index.js.map +1 -1
- package/lib/logger.js +3 -2
- package/lib/logger.js.map +1 -1
- package/lib/mongo_client.js +5 -8
- package/lib/mongo_client.js.map +1 -1
- package/lib/mongo_types.js.map +1 -1
- package/lib/operations/add_user.js +2 -3
- package/lib/operations/add_user.js.map +1 -1
- package/lib/operations/aggregate.js +12 -9
- package/lib/operations/aggregate.js.map +1 -1
- package/lib/operations/command.js +5 -7
- package/lib/operations/command.js.map +1 -1
- package/lib/operations/common_functions.js +1 -1
- package/lib/operations/common_functions.js.map +1 -1
- package/lib/operations/connect.js +3 -2
- package/lib/operations/connect.js.map +1 -1
- package/lib/operations/count.js +1 -1
- package/lib/operations/count.js.map +1 -1
- package/lib/operations/count_documents.js +1 -1
- package/lib/operations/count_documents.js.map +1 -1
- package/lib/operations/delete.js +5 -5
- package/lib/operations/delete.js.map +1 -1
- package/lib/operations/distinct.js +2 -2
- package/lib/operations/distinct.js.map +1 -1
- package/lib/operations/estimated_document_count.js +5 -1
- package/lib/operations/estimated_document_count.js.map +1 -1
- package/lib/operations/eval.js.map +1 -1
- package/lib/operations/execute_operation.js +31 -17
- package/lib/operations/execute_operation.js.map +1 -1
- package/lib/operations/find.js +13 -9
- package/lib/operations/find.js.map +1 -1
- package/lib/operations/find_and_modify.js +9 -9
- package/lib/operations/find_and_modify.js.map +1 -1
- package/lib/operations/indexes.js +8 -3
- package/lib/operations/indexes.js.map +1 -1
- package/lib/operations/insert.js +5 -3
- package/lib/operations/insert.js.map +1 -1
- package/lib/operations/is_capped.js +2 -1
- package/lib/operations/is_capped.js.map +1 -1
- package/lib/operations/list_collections.js +6 -3
- package/lib/operations/list_collections.js.map +1 -1
- package/lib/operations/map_reduce.js +1 -1
- package/lib/operations/map_reduce.js.map +1 -1
- package/lib/operations/operation.js +3 -1
- package/lib/operations/operation.js.map +1 -1
- package/lib/operations/options_operation.js +2 -1
- package/lib/operations/options_operation.js.map +1 -1
- package/lib/operations/profiling_level.js +4 -2
- package/lib/operations/profiling_level.js.map +1 -1
- package/lib/operations/set_profiling_level.js +4 -2
- package/lib/operations/set_profiling_level.js.map +1 -1
- package/lib/operations/update.js +12 -12
- package/lib/operations/update.js.map +1 -1
- package/lib/operations/validate_collection.js +6 -5
- package/lib/operations/validate_collection.js.map +1 -1
- package/lib/promise_provider.js +1 -1
- package/lib/promise_provider.js.map +1 -1
- package/lib/read_preference.js +8 -8
- package/lib/read_preference.js.map +1 -1
- package/lib/sdam/common.js +12 -10
- package/lib/sdam/common.js.map +1 -1
- package/lib/sdam/server.js +90 -25
- package/lib/sdam/server.js.map +1 -1
- package/lib/sdam/server_description.js +9 -4
- package/lib/sdam/server_description.js.map +1 -1
- package/lib/sdam/server_selection.js +10 -4
- package/lib/sdam/server_selection.js.map +1 -1
- package/lib/sdam/srv_polling.js +1 -1
- package/lib/sdam/srv_polling.js.map +1 -1
- package/lib/sdam/topology.js +42 -21
- package/lib/sdam/topology.js.map +1 -1
- package/lib/sdam/topology_description.js +7 -3
- package/lib/sdam/topology_description.js.map +1 -1
- package/lib/sessions.js +132 -31
- package/lib/sessions.js.map +1 -1
- package/lib/sort.js +3 -3
- package/lib/sort.js.map +1 -1
- package/lib/transactions.js +15 -7
- package/lib/transactions.js.map +1 -1
- package/lib/utils.js +60 -20
- package/lib/utils.js.map +1 -1
- package/mongodb.d.ts +523 -138
- package/mongodb.ts34.d.ts +480 -141
- package/package.json +44 -48
- package/src/bson.ts +1 -0
- package/src/bulk/common.ts +83 -43
- package/src/bulk/ordered.ts +4 -3
- package/src/bulk/unordered.ts +4 -3
- package/src/change_stream.ts +46 -29
- package/src/cmap/auth/auth_provider.ts +3 -2
- package/src/cmap/auth/gssapi.ts +15 -5
- package/src/cmap/auth/mongo_credentials.ts +22 -8
- package/src/cmap/auth/mongocr.ts +3 -3
- package/src/cmap/auth/mongodb_aws.ts +52 -39
- package/src/cmap/auth/plain.ts +2 -2
- package/src/cmap/auth/scram.ts +23 -13
- package/src/cmap/auth/x509.ts +3 -3
- package/src/cmap/command_monitoring_events.ts +36 -14
- package/src/cmap/commands.ts +12 -6
- package/src/cmap/connect.ts +42 -12
- package/src/cmap/connection.ts +54 -62
- package/src/cmap/connection_pool.ts +141 -20
- package/src/cmap/connection_pool_events.ts +8 -1
- package/src/cmap/errors.ts +3 -4
- package/src/cmap/message_stream.ts +2 -4
- package/src/cmap/metrics.ts +58 -0
- package/src/cmap/stream_description.ts +6 -1
- package/src/cmap/wire_protocol/compression.ts +26 -13
- package/src/cmap/wire_protocol/shared.ts +4 -2
- package/src/collection.ts +75 -70
- package/src/connection_string.ts +97 -34
- package/src/cursor/abstract_cursor.ts +141 -104
- package/src/cursor/aggregation_cursor.ts +34 -20
- package/src/cursor/find_cursor.ts +41 -21
- package/src/db.ts +19 -18
- package/src/deps.ts +110 -22
- package/src/encrypter.ts +6 -12
- package/src/error.ts +264 -48
- package/src/explain.ts +3 -3
- package/src/gridfs/download.ts +48 -53
- package/src/gridfs/index.ts +5 -4
- package/src/gridfs/upload.ts +32 -33
- package/src/index.ts +42 -4
- package/src/logger.ts +6 -3
- package/src/mongo_client.ts +20 -23
- package/src/mongo_types.ts +19 -20
- package/src/operations/add_user.ts +4 -5
- package/src/operations/aggregate.ts +18 -17
- package/src/operations/command.ts +7 -10
- package/src/operations/common_functions.ts +2 -3
- package/src/operations/connect.ts +4 -3
- package/src/operations/count.ts +2 -2
- package/src/operations/count_documents.ts +2 -2
- package/src/operations/delete.ts +8 -6
- package/src/operations/distinct.ts +5 -3
- package/src/operations/estimated_document_count.ts +5 -1
- package/src/operations/eval.ts +1 -1
- package/src/operations/execute_operation.ts +41 -20
- package/src/operations/find.ts +25 -16
- package/src/operations/find_and_modify.ts +12 -10
- package/src/operations/indexes.ts +39 -8
- package/src/operations/insert.ts +7 -4
- package/src/operations/is_capped.ts +3 -2
- package/src/operations/list_collections.ts +9 -6
- package/src/operations/map_reduce.ts +4 -2
- package/src/operations/operation.ts +7 -2
- package/src/operations/options_operation.ts +3 -2
- package/src/operations/profiling_level.ts +5 -3
- package/src/operations/set_profiling_level.ts +9 -3
- package/src/operations/update.ts +17 -13
- package/src/operations/validate_collection.ts +7 -6
- package/src/promise_provider.ts +2 -2
- package/src/read_preference.ts +11 -9
- package/src/sdam/common.ts +11 -9
- package/src/sdam/server.ts +168 -69
- package/src/sdam/server_description.ts +16 -4
- package/src/sdam/server_selection.ts +15 -7
- package/src/sdam/srv_polling.ts +2 -2
- package/src/sdam/topology.ts +67 -36
- package/src/sdam/topology_description.ts +11 -4
- package/src/sessions.ts +194 -37
- package/src/sort.ts +6 -4
- package/src/transactions.ts +18 -9
- package/src/utils.ts +73 -20
- package/HISTORY.md +0 -2993
- package/lib/operations/find_one.js +0 -34
- package/lib/operations/find_one.js.map +0 -1
- package/src/operations/find_one.ts +0 -43
package/src/cmap/auth/scram.ts
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
import * as crypto from 'crypto';
|
|
2
2
|
import { Binary, Document } from '../../bson';
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
AnyError,
|
|
5
|
+
MongoRuntimeError,
|
|
6
|
+
MongoServerError,
|
|
7
|
+
MongoInvalidArgumentError,
|
|
8
|
+
MongoMissingCredentialsError
|
|
9
|
+
} from '../../error';
|
|
4
10
|
import { AuthProvider, AuthContext } from './auth_provider';
|
|
5
11
|
import { Callback, ns, emitWarning } from '../../utils';
|
|
6
12
|
import type { MongoCredentials } from './mongo_credentials';
|
|
@@ -22,7 +28,7 @@ class ScramSHA extends AuthProvider {
|
|
|
22
28
|
const cryptoMethod = this.cryptoMethod;
|
|
23
29
|
const credentials = authContext.credentials;
|
|
24
30
|
if (!credentials) {
|
|
25
|
-
return callback(new
|
|
31
|
+
return callback(new MongoMissingCredentialsError('AuthContext must provide credentials.'));
|
|
26
32
|
}
|
|
27
33
|
if (cryptoMethod === 'sha256' && saslprep == null) {
|
|
28
34
|
emitWarning('Warning: no saslprep library specified. Passwords will not be sanitized');
|
|
@@ -103,10 +109,12 @@ function makeFirstMessage(
|
|
|
103
109
|
function executeScram(cryptoMethod: CryptoMethod, authContext: AuthContext, callback: Callback) {
|
|
104
110
|
const { connection, credentials } = authContext;
|
|
105
111
|
if (!credentials) {
|
|
106
|
-
return callback(new
|
|
112
|
+
return callback(new MongoMissingCredentialsError('AuthContext must provide credentials.'));
|
|
107
113
|
}
|
|
108
114
|
if (!authContext.nonce) {
|
|
109
|
-
return callback(
|
|
115
|
+
return callback(
|
|
116
|
+
new MongoInvalidArgumentError('AuthContext must contain a valid nonce property')
|
|
117
|
+
);
|
|
110
118
|
}
|
|
111
119
|
const nonce = authContext.nonce;
|
|
112
120
|
const db = credentials.source;
|
|
@@ -131,10 +139,10 @@ function continueScramConversation(
|
|
|
131
139
|
const connection = authContext.connection;
|
|
132
140
|
const credentials = authContext.credentials;
|
|
133
141
|
if (!credentials) {
|
|
134
|
-
return callback(new
|
|
142
|
+
return callback(new MongoMissingCredentialsError('AuthContext must provide credentials.'));
|
|
135
143
|
}
|
|
136
144
|
if (!authContext.nonce) {
|
|
137
|
-
return callback(new
|
|
145
|
+
return callback(new MongoInvalidArgumentError('Unable to continue SCRAM without valid nonce'));
|
|
138
146
|
}
|
|
139
147
|
const nonce = authContext.nonce;
|
|
140
148
|
|
|
@@ -161,7 +169,8 @@ function continueScramConversation(
|
|
|
161
169
|
const iterations = parseInt(dict.i, 10);
|
|
162
170
|
if (iterations && iterations < 4096) {
|
|
163
171
|
callback(
|
|
164
|
-
|
|
172
|
+
// TODO(NODE-3483)
|
|
173
|
+
new MongoRuntimeError(`Server returned an invalid iteration count ${iterations}`),
|
|
165
174
|
false
|
|
166
175
|
);
|
|
167
176
|
return;
|
|
@@ -170,7 +179,8 @@ function continueScramConversation(
|
|
|
170
179
|
const salt = dict.s;
|
|
171
180
|
const rnonce = dict.r;
|
|
172
181
|
if (rnonce.startsWith('nonce')) {
|
|
173
|
-
|
|
182
|
+
// TODO(NODE-3483)
|
|
183
|
+
callback(new MongoRuntimeError(`Server returned an invalid nonce: ${rnonce}`), false);
|
|
174
184
|
return;
|
|
175
185
|
}
|
|
176
186
|
|
|
@@ -209,7 +219,7 @@ function continueScramConversation(
|
|
|
209
219
|
|
|
210
220
|
const parsedResponse = parsePayload(r.payload.value());
|
|
211
221
|
if (!compareDigest(Buffer.from(parsedResponse.v, 'base64'), serverSignature)) {
|
|
212
|
-
callback(new
|
|
222
|
+
callback(new MongoRuntimeError('Server returned an invalid signature'));
|
|
213
223
|
return;
|
|
214
224
|
}
|
|
215
225
|
|
|
@@ -240,15 +250,15 @@ function parsePayload(payload: string) {
|
|
|
240
250
|
|
|
241
251
|
function passwordDigest(username: string, password: string) {
|
|
242
252
|
if (typeof username !== 'string') {
|
|
243
|
-
throw new
|
|
253
|
+
throw new MongoInvalidArgumentError('Username must be a string');
|
|
244
254
|
}
|
|
245
255
|
|
|
246
256
|
if (typeof password !== 'string') {
|
|
247
|
-
throw new
|
|
257
|
+
throw new MongoInvalidArgumentError('Password must be a string');
|
|
248
258
|
}
|
|
249
259
|
|
|
250
260
|
if (password.length === 0) {
|
|
251
|
-
throw new
|
|
261
|
+
throw new MongoInvalidArgumentError('Password cannot be empty');
|
|
252
262
|
}
|
|
253
263
|
|
|
254
264
|
const md5 = crypto.createHash('md5');
|
|
@@ -303,7 +313,7 @@ const hiLengthMap = {
|
|
|
303
313
|
function HI(data: string, salt: Buffer, iterations: number, cryptoMethod: CryptoMethod) {
|
|
304
314
|
// omit the work if already generated
|
|
305
315
|
const key = [data, salt.toString('base64'), iterations].join('_');
|
|
306
|
-
if (_hiCache[key]
|
|
316
|
+
if (_hiCache[key] != null) {
|
|
307
317
|
return _hiCache[key];
|
|
308
318
|
}
|
|
309
319
|
|
package/src/cmap/auth/x509.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { AuthProvider, AuthContext } from './auth_provider';
|
|
2
|
-
import {
|
|
2
|
+
import { MongoMissingCredentialsError } from '../../error';
|
|
3
3
|
import type { Document } from '../../bson';
|
|
4
4
|
import { Callback, ns } from '../../utils';
|
|
5
5
|
import type { MongoCredentials } from './mongo_credentials';
|
|
@@ -9,7 +9,7 @@ export class X509 extends AuthProvider {
|
|
|
9
9
|
prepare(handshakeDoc: HandshakeDocument, authContext: AuthContext, callback: Callback): void {
|
|
10
10
|
const { credentials } = authContext;
|
|
11
11
|
if (!credentials) {
|
|
12
|
-
return callback(new
|
|
12
|
+
return callback(new MongoMissingCredentialsError('AuthContext must provide credentials.'));
|
|
13
13
|
}
|
|
14
14
|
Object.assign(handshakeDoc, {
|
|
15
15
|
speculativeAuthenticate: x509AuthenticateCommand(credentials)
|
|
@@ -22,7 +22,7 @@ export class X509 extends AuthProvider {
|
|
|
22
22
|
const connection = authContext.connection;
|
|
23
23
|
const credentials = authContext.credentials;
|
|
24
24
|
if (!credentials) {
|
|
25
|
-
return callback(new
|
|
25
|
+
return callback(new MongoMissingCredentialsError('AuthContext must provide credentials.'));
|
|
26
26
|
}
|
|
27
27
|
const response = authContext.response;
|
|
28
28
|
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { GetMore, KillCursor, Msg, WriteProtocolMessageType } from './commands';
|
|
2
2
|
import { calculateDurationInMs, deepCopy } from '../utils';
|
|
3
|
-
import type { ConnectionPool } from './connection_pool';
|
|
4
3
|
import type { Connection } from './connection';
|
|
5
|
-
import type { Document } from '../bson';
|
|
4
|
+
import type { Document, ObjectId } from '../bson';
|
|
6
5
|
|
|
7
6
|
/**
|
|
8
7
|
* An event indicating the start of a given
|
|
@@ -17,6 +16,7 @@ export class CommandStartedEvent {
|
|
|
17
16
|
command: Document;
|
|
18
17
|
address: string;
|
|
19
18
|
connectionId?: string | number;
|
|
19
|
+
serviceId?: ObjectId;
|
|
20
20
|
|
|
21
21
|
/**
|
|
22
22
|
* Create a started event
|
|
@@ -25,10 +25,10 @@ export class CommandStartedEvent {
|
|
|
25
25
|
* @param pool - the pool that originated the command
|
|
26
26
|
* @param command - the command
|
|
27
27
|
*/
|
|
28
|
-
constructor(
|
|
28
|
+
constructor(connection: Connection, command: WriteProtocolMessageType) {
|
|
29
29
|
const cmd = extractCommand(command);
|
|
30
30
|
const commandName = extractCommandName(cmd);
|
|
31
|
-
const { address, connectionId } = extractConnectionDetails(
|
|
31
|
+
const { address, connectionId, serviceId } = extractConnectionDetails(connection);
|
|
32
32
|
|
|
33
33
|
// TODO: remove in major revision, this is not spec behavior
|
|
34
34
|
if (SENSITIVE_COMMANDS.has(commandName)) {
|
|
@@ -38,11 +38,17 @@ export class CommandStartedEvent {
|
|
|
38
38
|
|
|
39
39
|
this.address = address;
|
|
40
40
|
this.connectionId = connectionId;
|
|
41
|
+
this.serviceId = serviceId;
|
|
41
42
|
this.requestId = command.requestId;
|
|
42
43
|
this.databaseName = databaseName(command);
|
|
43
44
|
this.commandName = commandName;
|
|
44
45
|
this.command = maybeRedact(commandName, cmd, cmd);
|
|
45
46
|
}
|
|
47
|
+
|
|
48
|
+
/* @internal */
|
|
49
|
+
get hasServiceId(): boolean {
|
|
50
|
+
return !!this.serviceId;
|
|
51
|
+
}
|
|
46
52
|
}
|
|
47
53
|
|
|
48
54
|
/**
|
|
@@ -57,6 +63,7 @@ export class CommandSucceededEvent {
|
|
|
57
63
|
duration: number;
|
|
58
64
|
commandName: string;
|
|
59
65
|
reply: unknown;
|
|
66
|
+
serviceId?: ObjectId;
|
|
60
67
|
|
|
61
68
|
/**
|
|
62
69
|
* Create a succeeded event
|
|
@@ -68,22 +75,28 @@ export class CommandSucceededEvent {
|
|
|
68
75
|
* @param started - a high resolution tuple timestamp of when the command was first sent, to calculate duration
|
|
69
76
|
*/
|
|
70
77
|
constructor(
|
|
71
|
-
|
|
78
|
+
connection: Connection,
|
|
72
79
|
command: WriteProtocolMessageType,
|
|
73
80
|
reply: Document | undefined,
|
|
74
81
|
started: number
|
|
75
82
|
) {
|
|
76
83
|
const cmd = extractCommand(command);
|
|
77
84
|
const commandName = extractCommandName(cmd);
|
|
78
|
-
const { address, connectionId } = extractConnectionDetails(
|
|
85
|
+
const { address, connectionId, serviceId } = extractConnectionDetails(connection);
|
|
79
86
|
|
|
80
87
|
this.address = address;
|
|
81
88
|
this.connectionId = connectionId;
|
|
89
|
+
this.serviceId = serviceId;
|
|
82
90
|
this.requestId = command.requestId;
|
|
83
91
|
this.commandName = commandName;
|
|
84
92
|
this.duration = calculateDurationInMs(started);
|
|
85
93
|
this.reply = maybeRedact(commandName, cmd, extractReply(command, reply));
|
|
86
94
|
}
|
|
95
|
+
|
|
96
|
+
/* @internal */
|
|
97
|
+
get hasServiceId(): boolean {
|
|
98
|
+
return !!this.serviceId;
|
|
99
|
+
}
|
|
87
100
|
}
|
|
88
101
|
|
|
89
102
|
/**
|
|
@@ -98,6 +111,8 @@ export class CommandFailedEvent {
|
|
|
98
111
|
duration: number;
|
|
99
112
|
commandName: string;
|
|
100
113
|
failure: Error;
|
|
114
|
+
serviceId?: ObjectId;
|
|
115
|
+
|
|
101
116
|
/**
|
|
102
117
|
* Create a failure event
|
|
103
118
|
*
|
|
@@ -108,23 +123,29 @@ export class CommandFailedEvent {
|
|
|
108
123
|
* @param started - a high resolution tuple timestamp of when the command was first sent, to calculate duration
|
|
109
124
|
*/
|
|
110
125
|
constructor(
|
|
111
|
-
|
|
126
|
+
connection: Connection,
|
|
112
127
|
command: WriteProtocolMessageType,
|
|
113
128
|
error: Error | Document,
|
|
114
129
|
started: number
|
|
115
130
|
) {
|
|
116
131
|
const cmd = extractCommand(command);
|
|
117
132
|
const commandName = extractCommandName(cmd);
|
|
118
|
-
const { address, connectionId } = extractConnectionDetails(
|
|
133
|
+
const { address, connectionId, serviceId } = extractConnectionDetails(connection);
|
|
119
134
|
|
|
120
135
|
this.address = address;
|
|
121
136
|
this.connectionId = connectionId;
|
|
137
|
+
this.serviceId = serviceId;
|
|
122
138
|
|
|
123
139
|
this.requestId = command.requestId;
|
|
124
140
|
this.commandName = commandName;
|
|
125
141
|
this.duration = calculateDurationInMs(started);
|
|
126
142
|
this.failure = maybeRedact(commandName, cmd, error) as Error;
|
|
127
143
|
}
|
|
144
|
+
|
|
145
|
+
/* @internal */
|
|
146
|
+
get hasServiceId(): boolean {
|
|
147
|
+
return !!this.serviceId;
|
|
148
|
+
}
|
|
128
149
|
}
|
|
129
150
|
|
|
130
151
|
/** Commands that we want to redact because of the sensitive nature of their contents */
|
|
@@ -212,7 +233,7 @@ function extractCommand(command: WriteProtocolMessageType): Document {
|
|
|
212
233
|
// up-convert legacy find command
|
|
213
234
|
result = { find: collectionName(command) };
|
|
214
235
|
Object.keys(LEGACY_FIND_QUERY_MAP).forEach(key => {
|
|
215
|
-
if (
|
|
236
|
+
if (command.query[key] != null) {
|
|
216
237
|
result[LEGACY_FIND_QUERY_MAP[key]] = deepCopy(command.query[key]);
|
|
217
238
|
}
|
|
218
239
|
});
|
|
@@ -220,7 +241,7 @@ function extractCommand(command: WriteProtocolMessageType): Document {
|
|
|
220
241
|
|
|
221
242
|
Object.keys(LEGACY_FIND_OPTIONS_MAP).forEach(key => {
|
|
222
243
|
const legacyKey = key as keyof typeof LEGACY_FIND_OPTIONS_MAP;
|
|
223
|
-
if (
|
|
244
|
+
if (command[legacyKey] != null) {
|
|
224
245
|
result[LEGACY_FIND_OPTIONS_MAP[legacyKey]] = deepCopy(command[legacyKey]);
|
|
225
246
|
}
|
|
226
247
|
});
|
|
@@ -232,7 +253,7 @@ function extractCommand(command: WriteProtocolMessageType): Document {
|
|
|
232
253
|
}
|
|
233
254
|
});
|
|
234
255
|
|
|
235
|
-
if (
|
|
256
|
+
if (command.pre32Limit != null) {
|
|
236
257
|
result.limit = command.pre32Limit;
|
|
237
258
|
}
|
|
238
259
|
|
|
@@ -253,7 +274,7 @@ function extractCommand(command: WriteProtocolMessageType): Document {
|
|
|
253
274
|
|
|
254
275
|
for (const k in command) {
|
|
255
276
|
if (k === 'query') continue;
|
|
256
|
-
clonedCommand[k] = deepCopy((
|
|
277
|
+
clonedCommand[k] = deepCopy((command as unknown as Record<string, unknown>)[k]);
|
|
257
278
|
}
|
|
258
279
|
return command.query ? clonedQuery : clonedCommand;
|
|
259
280
|
}
|
|
@@ -286,7 +307,7 @@ function extractReply(command: WriteProtocolMessageType, reply?: Document) {
|
|
|
286
307
|
}
|
|
287
308
|
|
|
288
309
|
// is this a legacy find command?
|
|
289
|
-
if (command.query &&
|
|
310
|
+
if (command.query && command.query.$query != null) {
|
|
290
311
|
return {
|
|
291
312
|
ok: 1,
|
|
292
313
|
cursor: {
|
|
@@ -300,13 +321,14 @@ function extractReply(command: WriteProtocolMessageType, reply?: Document) {
|
|
|
300
321
|
return deepCopy(reply.result ? reply.result : reply);
|
|
301
322
|
}
|
|
302
323
|
|
|
303
|
-
function extractConnectionDetails(connection: Connection
|
|
324
|
+
function extractConnectionDetails(connection: Connection) {
|
|
304
325
|
let connectionId;
|
|
305
326
|
if ('id' in connection) {
|
|
306
327
|
connectionId = connection.id;
|
|
307
328
|
}
|
|
308
329
|
return {
|
|
309
330
|
address: connection.address,
|
|
331
|
+
serviceId: connection.serviceId,
|
|
310
332
|
connectionId
|
|
311
333
|
};
|
|
312
334
|
}
|
package/src/cmap/commands.ts
CHANGED
|
@@ -5,7 +5,7 @@ import { OP_QUERY, OP_GETMORE, OP_KILL_CURSORS, OP_MSG } from './wire_protocol/c
|
|
|
5
5
|
import type { Long, Document, BSONSerializeOptions } from '../bson';
|
|
6
6
|
import type { ClientSession } from '../sessions';
|
|
7
7
|
import type { CommandOptions } from './connection';
|
|
8
|
-
import {
|
|
8
|
+
import { MongoRuntimeError, MongoInvalidArgumentError } from '../error';
|
|
9
9
|
|
|
10
10
|
// Incrementing request id
|
|
11
11
|
let _requestId = 0;
|
|
@@ -77,12 +77,15 @@ export class Query {
|
|
|
77
77
|
|
|
78
78
|
constructor(ns: string, query: Document, options: OpQueryOptions) {
|
|
79
79
|
// Basic options needed to be passed in
|
|
80
|
-
|
|
81
|
-
if (
|
|
80
|
+
// TODO(NODE-3483): Replace with MongoCommandError
|
|
81
|
+
if (ns == null) throw new MongoRuntimeError('Namespace must be specified for query');
|
|
82
|
+
// TODO(NODE-3483): Replace with MongoCommandError
|
|
83
|
+
if (query == null) throw new MongoRuntimeError('A query document must be specified for query');
|
|
82
84
|
|
|
83
85
|
// Validate that we are not passing 0x00 in the collection name
|
|
84
86
|
if (ns.indexOf('\x00') !== -1) {
|
|
85
|
-
|
|
87
|
+
// TODO(NODE-3483): Use MongoNamespace static method
|
|
88
|
+
throw new MongoRuntimeError('Namespace cannot contain a null character');
|
|
86
89
|
}
|
|
87
90
|
|
|
88
91
|
// Basic options
|
|
@@ -664,7 +667,8 @@ export class Msg {
|
|
|
664
667
|
|
|
665
668
|
constructor(ns: string, command: Document, options: OpQueryOptions) {
|
|
666
669
|
// Basic options needed to be passed in
|
|
667
|
-
if (command == null)
|
|
670
|
+
if (command == null)
|
|
671
|
+
throw new MongoInvalidArgumentError('Query document must be specified for query');
|
|
668
672
|
|
|
669
673
|
// Basic options
|
|
670
674
|
this.ns = ns;
|
|
@@ -852,7 +856,9 @@ export class BinMsg {
|
|
|
852
856
|
this.index += bsonSize;
|
|
853
857
|
} else if (payloadType === 1) {
|
|
854
858
|
// It was decided that no driver makes use of payload type 1
|
|
855
|
-
|
|
859
|
+
|
|
860
|
+
// TODO(NODE-3483): Replace with MongoDeprecationError
|
|
861
|
+
throw new MongoRuntimeError('OP_MSG Payload Type 1 detected unsupported protocol');
|
|
856
862
|
}
|
|
857
863
|
}
|
|
858
864
|
|
package/src/cmap/connect.ts
CHANGED
|
@@ -5,8 +5,10 @@ import {
|
|
|
5
5
|
MongoNetworkError,
|
|
6
6
|
MongoNetworkTimeoutError,
|
|
7
7
|
AnyError,
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
MongoCompatibilityError,
|
|
9
|
+
MongoInvalidArgumentError,
|
|
10
|
+
MongoServerError,
|
|
11
|
+
MongoRuntimeError
|
|
10
12
|
} from '../error';
|
|
11
13
|
import { AUTH_PROVIDERS, AuthMechanism } from './auth/defaultAuthProviders';
|
|
12
14
|
import { AuthContext } from './auth/auth_provider';
|
|
@@ -18,10 +20,14 @@ import {
|
|
|
18
20
|
MIN_SUPPORTED_SERVER_VERSION
|
|
19
21
|
} from './wire_protocol/constants';
|
|
20
22
|
import type { Document } from '../bson';
|
|
23
|
+
import { Int32 } from '../bson';
|
|
21
24
|
|
|
22
25
|
import type { Socket, SocketConnectOpts } from 'net';
|
|
23
26
|
import type { TLSSocket, ConnectionOptions as TLSConnectionOpts } from 'tls';
|
|
24
|
-
|
|
27
|
+
|
|
28
|
+
const FAKE_MONGODB_SERVICE_ID =
|
|
29
|
+
typeof process.env.FAKE_MONGODB_SERVICE_ID === 'string' &&
|
|
30
|
+
process.env.FAKE_MONGODB_SERVICE_ID.toLowerCase() === 'true';
|
|
25
31
|
|
|
26
32
|
/** @public */
|
|
27
33
|
export type Stream = Socket | TLSSocket;
|
|
@@ -58,13 +64,13 @@ function checkSupportedServer(ismaster: Document, options: ConnectionOptions) {
|
|
|
58
64
|
const message = `Server at ${options.hostAddress} reports minimum wire version ${JSON.stringify(
|
|
59
65
|
ismaster.minWireVersion
|
|
60
66
|
)}, but this version of the Node.js Driver requires at most ${MAX_SUPPORTED_WIRE_VERSION} (MongoDB ${MAX_SUPPORTED_SERVER_VERSION})`;
|
|
61
|
-
return new
|
|
67
|
+
return new MongoCompatibilityError(message);
|
|
62
68
|
}
|
|
63
69
|
|
|
64
70
|
const message = `Server at ${options.hostAddress} reports maximum wire version ${
|
|
65
71
|
JSON.stringify(ismaster.maxWireVersion) ?? 0
|
|
66
72
|
}, but this version of the Node.js Driver requires at least ${MIN_SUPPORTED_WIRE_VERSION} (MongoDB ${MIN_SUPPORTED_SERVER_VERSION})`;
|
|
67
|
-
return new
|
|
73
|
+
return new MongoCompatibilityError(message);
|
|
68
74
|
}
|
|
69
75
|
|
|
70
76
|
function performInitialHandshake(
|
|
@@ -85,7 +91,9 @@ function performInitialHandshake(
|
|
|
85
91
|
!(credentials.mechanism === AuthMechanism.MONGODB_DEFAULT) &&
|
|
86
92
|
!AUTH_PROVIDERS.get(credentials.mechanism)
|
|
87
93
|
) {
|
|
88
|
-
callback(
|
|
94
|
+
callback(
|
|
95
|
+
new MongoInvalidArgumentError(`AuthMechanism '${credentials.mechanism}' not supported`)
|
|
96
|
+
);
|
|
89
97
|
return;
|
|
90
98
|
}
|
|
91
99
|
}
|
|
@@ -129,6 +137,21 @@ function performInitialHandshake(
|
|
|
129
137
|
return;
|
|
130
138
|
}
|
|
131
139
|
|
|
140
|
+
if (options.loadBalanced) {
|
|
141
|
+
// TODO: Durran: Remove when server support exists. (NODE-3431)
|
|
142
|
+
if (FAKE_MONGODB_SERVICE_ID) {
|
|
143
|
+
response.serviceId = response.topologyVersion.processId;
|
|
144
|
+
}
|
|
145
|
+
if (!response.serviceId) {
|
|
146
|
+
return callback(
|
|
147
|
+
new MongoCompatibilityError(
|
|
148
|
+
'Driver attempted to initialize in load balancing mode, ' +
|
|
149
|
+
'but the server does not support this mode.'
|
|
150
|
+
)
|
|
151
|
+
);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
132
155
|
// NOTE: This is metadata attached to the connection while porting away from
|
|
133
156
|
// handshake being done in the `Server` class. Likely, it should be
|
|
134
157
|
// relocated, or at very least restructured.
|
|
@@ -143,7 +166,9 @@ function performInitialHandshake(
|
|
|
143
166
|
const provider = AUTH_PROVIDERS.get(resolvedCredentials.mechanism);
|
|
144
167
|
if (!provider) {
|
|
145
168
|
return callback(
|
|
146
|
-
new
|
|
169
|
+
new MongoInvalidArgumentError(
|
|
170
|
+
`No AuthProvider for ${resolvedCredentials.mechanism} defined.`
|
|
171
|
+
)
|
|
147
172
|
);
|
|
148
173
|
}
|
|
149
174
|
provider.auth(authContext, err => {
|
|
@@ -166,6 +191,7 @@ export interface HandshakeDocument extends Document {
|
|
|
166
191
|
client: ClientMetadata;
|
|
167
192
|
compression: string[];
|
|
168
193
|
saslSupportedMechs?: string;
|
|
194
|
+
loadBalanced: boolean;
|
|
169
195
|
}
|
|
170
196
|
|
|
171
197
|
function prepareHandshakeDocument(authContext: AuthContext, callback: Callback<HandshakeDocument>) {
|
|
@@ -177,7 +203,8 @@ function prepareHandshakeDocument(authContext: AuthContext, callback: Callback<H
|
|
|
177
203
|
[serverApi?.version ? 'hello' : 'ismaster']: true,
|
|
178
204
|
helloOk: true,
|
|
179
205
|
client: options.metadata || makeClientMetadata(options),
|
|
180
|
-
compression: compressors
|
|
206
|
+
compression: compressors,
|
|
207
|
+
loadBalanced: options.loadBalanced
|
|
181
208
|
};
|
|
182
209
|
|
|
183
210
|
const credentials = authContext.credentials;
|
|
@@ -189,7 +216,9 @@ function prepareHandshakeDocument(authContext: AuthContext, callback: Callback<H
|
|
|
189
216
|
if (!provider) {
|
|
190
217
|
// This auth mechanism is always present.
|
|
191
218
|
return callback(
|
|
192
|
-
new
|
|
219
|
+
new MongoInvalidArgumentError(
|
|
220
|
+
`No AuthProvider for ${AuthMechanism.MONGODB_SCRAM_SHA256} defined.`
|
|
221
|
+
)
|
|
193
222
|
);
|
|
194
223
|
}
|
|
195
224
|
return provider.prepare(handshakeDoc, authContext, callback);
|
|
@@ -197,7 +226,7 @@ function prepareHandshakeDocument(authContext: AuthContext, callback: Callback<H
|
|
|
197
226
|
const provider = AUTH_PROVIDERS.get(credentials.mechanism);
|
|
198
227
|
if (!provider) {
|
|
199
228
|
return callback(
|
|
200
|
-
new
|
|
229
|
+
new MongoInvalidArgumentError(`No AuthProvider for ${credentials.mechanism} defined.`)
|
|
201
230
|
);
|
|
202
231
|
}
|
|
203
232
|
return provider.prepare(handshakeDoc, authContext, callback);
|
|
@@ -236,7 +265,7 @@ export const LEGAL_TCP_SOCKET_OPTIONS = [
|
|
|
236
265
|
|
|
237
266
|
function parseConnectOptions(options: ConnectionOptions): SocketConnectOpts {
|
|
238
267
|
const hostAddress = options.hostAddress;
|
|
239
|
-
if (!hostAddress) throw new
|
|
268
|
+
if (!hostAddress) throw new MongoInvalidArgumentError('Option "hostAddress" is required');
|
|
240
269
|
|
|
241
270
|
const result: Partial<net.TcpNetConnectOpts & net.IpcNetConnectOpts> = {};
|
|
242
271
|
for (const name of LEGAL_TCP_SOCKET_OPTIONS) {
|
|
@@ -255,7 +284,8 @@ function parseConnectOptions(options: ConnectionOptions): SocketConnectOpts {
|
|
|
255
284
|
} else {
|
|
256
285
|
// This should never happen since we set up HostAddresses
|
|
257
286
|
// But if we don't throw here the socket could hang until timeout
|
|
258
|
-
|
|
287
|
+
// TODO(NODE-3483)
|
|
288
|
+
throw new MongoRuntimeError(`Unexpected HostAddress ${JSON.stringify(hostAddress)}`);
|
|
259
289
|
}
|
|
260
290
|
}
|
|
261
291
|
|