mongodb 4.1.0 → 4.1.4
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 +64 -32
- package/lib/admin.js +5 -5
- package/lib/admin.js.map +1 -1
- package/lib/bulk/common.js +93 -71
- package/lib/bulk/common.js.map +1 -1
- package/lib/change_stream.js +35 -27
- package/lib/change_stream.js.map +1 -1
- package/lib/cmap/auth/auth_provider.js +2 -2
- package/lib/cmap/auth/auth_provider.js.map +1 -1
- package/lib/cmap/auth/gssapi.js +3 -2
- package/lib/cmap/auth/gssapi.js.map +1 -1
- package/lib/cmap/auth/mongo_credentials.js +8 -7
- 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 +11 -8
- package/lib/cmap/auth/scram.js.map +1 -1
- package/lib/cmap/auth/x509.js +1 -1
- package/lib/cmap/auth/x509.js.map +1 -1
- package/lib/cmap/command_monitoring_events.js +15 -15
- package/lib/cmap/command_monitoring_events.js.map +1 -1
- package/lib/cmap/commands.js +6 -6
- package/lib/cmap/commands.js.map +1 -1
- package/lib/cmap/connect.js +5 -4
- package/lib/cmap/connect.js.map +1 -1
- package/lib/cmap/connection.js +27 -23
- package/lib/cmap/connection.js.map +1 -1
- package/lib/cmap/connection_pool.js +7 -5
- package/lib/cmap/connection_pool.js.map +1 -1
- package/lib/cmap/message_stream.js +3 -3
- package/lib/cmap/message_stream.js.map +1 -1
- package/lib/cmap/stream_description.js +1 -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/collection.js +53 -48
- package/lib/collection.js.map +1 -1
- package/lib/connection_string.js +42 -36
- package/lib/connection_string.js.map +1 -1
- package/lib/cursor/abstract_cursor.js +18 -18
- package/lib/cursor/abstract_cursor.js.map +1 -1
- package/lib/cursor/aggregation_cursor.js +56 -15
- package/lib/cursor/aggregation_cursor.js.map +1 -1
- package/lib/cursor/find_cursor.js +63 -23
- package/lib/cursor/find_cursor.js.map +1 -1
- package/lib/db.js +35 -30
- package/lib/db.js.map +1 -1
- package/lib/deps.js +8 -1
- package/lib/deps.js.map +1 -1
- package/lib/error.js +16 -54
- package/lib/error.js.map +1 -1
- package/lib/gridfs/download.js +14 -24
- package/lib/gridfs/download.js.map +1 -1
- package/lib/gridfs/index.js +5 -5
- 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 +22 -2
- package/lib/index.js.map +1 -1
- package/lib/logger.js +5 -5
- package/lib/logger.js.map +1 -1
- package/lib/mongo_client.js +9 -8
- package/lib/mongo_client.js.map +1 -1
- package/lib/mongo_types.js.map +1 -1
- package/lib/operations/add_user.js +3 -3
- package/lib/operations/add_user.js.map +1 -1
- package/lib/operations/aggregate.js +2 -2
- package/lib/operations/aggregate.js.map +1 -1
- package/lib/operations/bulk_write.js +1 -1
- package/lib/operations/bulk_write.js.map +1 -1
- package/lib/operations/command.js +4 -6
- package/lib/operations/command.js.map +1 -1
- package/lib/operations/common_functions.js +2 -2
- 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.map +1 -1
- package/lib/operations/create_collection.js +1 -1
- package/lib/operations/create_collection.js.map +1 -1
- package/lib/operations/delete.js +6 -6
- package/lib/operations/delete.js.map +1 -1
- package/lib/operations/distinct.js +5 -5
- package/lib/operations/distinct.js.map +1 -1
- package/lib/operations/drop.js +2 -2
- package/lib/operations/drop.js.map +1 -1
- package/lib/operations/estimated_document_count.js +2 -2
- package/lib/operations/estimated_document_count.js.map +1 -1
- package/lib/operations/eval.js.map +1 -1
- package/lib/operations/execute_operation.js +10 -15
- package/lib/operations/execute_operation.js.map +1 -1
- package/lib/operations/find.js +8 -9
- package/lib/operations/find.js.map +1 -1
- package/lib/operations/find_and_modify.js +7 -7
- package/lib/operations/find_and_modify.js.map +1 -1
- package/lib/operations/indexes.js +14 -14
- package/lib/operations/indexes.js.map +1 -1
- package/lib/operations/insert.js +8 -6
- 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 +4 -4
- package/lib/operations/list_collections.js.map +1 -1
- package/lib/operations/list_databases.js +1 -1
- package/lib/operations/list_databases.js.map +1 -1
- package/lib/operations/map_reduce.js +6 -6
- package/lib/operations/map_reduce.js.map +1 -1
- package/lib/operations/operation.js +1 -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 +2 -2
- package/lib/operations/profiling_level.js.map +1 -1
- package/lib/operations/remove_user.js +1 -1
- package/lib/operations/remove_user.js.map +1 -1
- package/lib/operations/rename.js +2 -2
- package/lib/operations/rename.js.map +1 -1
- package/lib/operations/set_profiling_level.js +2 -2
- package/lib/operations/set_profiling_level.js.map +1 -1
- package/lib/operations/stats.js +2 -2
- package/lib/operations/stats.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 +4 -4
- package/lib/operations/validate_collection.js.map +1 -1
- package/lib/sdam/monitor.js +14 -14
- package/lib/sdam/monitor.js.map +1 -1
- package/lib/sdam/server.js +16 -17
- package/lib/sdam/server.js.map +1 -1
- package/lib/sdam/server_description.js +3 -3
- package/lib/sdam/server_description.js.map +1 -1
- package/lib/sdam/srv_polling.js +1 -2
- package/lib/sdam/srv_polling.js.map +1 -1
- package/lib/sdam/topology.js +21 -18
- package/lib/sdam/topology.js.map +1 -1
- package/lib/sdam/topology_description.js +1 -1
- package/lib/sdam/topology_description.js.map +1 -1
- package/lib/sessions.js +33 -33
- package/lib/sessions.js.map +1 -1
- package/lib/transactions.js +2 -2
- package/lib/transactions.js.map +1 -1
- package/lib/utils.js +15 -37
- package/lib/utils.js.map +1 -1
- package/mongodb.d.ts +384 -121
- package/mongodb.ts34.d.ts +365 -124
- package/package.json +53 -58
- package/src/bulk/common.ts +105 -61
- package/src/change_stream.ts +41 -22
- package/src/cmap/auth/auth_provider.ts +3 -3
- package/src/cmap/auth/gssapi.ts +3 -2
- package/src/cmap/auth/mongo_credentials.ts +21 -10
- package/src/cmap/auth/mongodb_aws.ts +41 -36
- package/src/cmap/auth/scram.ts +6 -4
- package/src/cmap/command_monitoring_events.ts +1 -1
- package/src/cmap/commands.ts +6 -6
- package/src/cmap/connect.ts +5 -4
- package/src/cmap/connection.ts +15 -12
- package/src/cmap/connection_pool.ts +5 -3
- package/src/cmap/message_stream.ts +2 -4
- package/src/cmap/wire_protocol/compression.ts +26 -13
- package/src/collection.ts +54 -56
- package/src/connection_string.ts +37 -26
- package/src/cursor/abstract_cursor.ts +45 -35
- package/src/cursor/aggregation_cursor.ts +30 -9
- package/src/cursor/find_cursor.ts +27 -7
- package/src/db.ts +14 -14
- package/src/deps.ts +103 -23
- package/src/error.ts +33 -66
- package/src/gridfs/download.ts +37 -27
- package/src/gridfs/index.ts +3 -3
- package/src/gridfs/upload.ts +32 -33
- package/src/index.ts +34 -3
- package/src/mongo_client.ts +9 -13
- package/src/mongo_types.ts +22 -26
- package/src/operations/command.ts +2 -5
- package/src/operations/common_functions.ts +2 -3
- package/src/operations/connect.ts +3 -2
- package/src/operations/count.ts +1 -1
- package/src/operations/count_documents.ts +1 -1
- package/src/operations/distinct.ts +1 -1
- package/src/operations/eval.ts +1 -1
- package/src/operations/execute_operation.ts +9 -10
- package/src/operations/find.ts +7 -5
- package/src/operations/indexes.ts +2 -2
- package/src/operations/insert.ts +4 -1
- package/src/operations/is_capped.ts +3 -2
- package/src/operations/list_collections.ts +3 -1
- package/src/operations/list_databases.ts +6 -1
- package/src/operations/operation.ts +0 -1
- package/src/operations/options_operation.ts +3 -2
- package/src/operations/profiling_level.ts +3 -3
- package/src/operations/set_profiling_level.ts +2 -2
- package/src/operations/validate_collection.ts +5 -5
- package/src/sdam/server.ts +6 -7
- package/src/sdam/srv_polling.ts +2 -3
- package/src/sdam/topology.ts +15 -9
- package/src/sdam/topology_description.ts +2 -2
- package/src/sessions.ts +20 -16
- package/src/transactions.ts +3 -3
- package/src/utils.ts +20 -41
- package/HISTORY.md +0 -3026
- 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
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// Resolves the default auth mechanism according to
|
|
2
2
|
|
|
3
3
|
import type { Document } from '../../bson';
|
|
4
|
-
import {
|
|
4
|
+
import { MongoAPIError, MongoMissingCredentialsError } from '../../error';
|
|
5
5
|
import { AuthMechanism } from './defaultAuthProviders';
|
|
6
6
|
|
|
7
7
|
// https://github.com/mongodb/specifications/blob/master/source/auth/auth.rst
|
|
@@ -25,6 +25,14 @@ function getDefaultAuthMechanism(ismaster?: Document): AuthMechanism {
|
|
|
25
25
|
return AuthMechanism.MONGODB_CR;
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
+
/** @public */
|
|
29
|
+
export interface AuthMechanismProperties extends Document {
|
|
30
|
+
SERVICE_NAME?: string;
|
|
31
|
+
SERVICE_REALM?: string;
|
|
32
|
+
CANONICALIZE_HOST_NAME?: boolean;
|
|
33
|
+
AWS_SESSION_TOKEN?: string;
|
|
34
|
+
}
|
|
35
|
+
|
|
28
36
|
/** @public */
|
|
29
37
|
export interface MongoCredentialsOptions {
|
|
30
38
|
username: string;
|
|
@@ -32,7 +40,7 @@ export interface MongoCredentialsOptions {
|
|
|
32
40
|
source: string;
|
|
33
41
|
db?: string;
|
|
34
42
|
mechanism?: AuthMechanism;
|
|
35
|
-
mechanismProperties:
|
|
43
|
+
mechanismProperties: AuthMechanismProperties;
|
|
36
44
|
}
|
|
37
45
|
|
|
38
46
|
/**
|
|
@@ -49,7 +57,7 @@ export class MongoCredentials {
|
|
|
49
57
|
/** The method used to authenticate */
|
|
50
58
|
readonly mechanism: AuthMechanism;
|
|
51
59
|
/** Special properties used by some types of auth mechanisms */
|
|
52
|
-
readonly mechanismProperties:
|
|
60
|
+
readonly mechanismProperties: AuthMechanismProperties;
|
|
53
61
|
|
|
54
62
|
constructor(options: MongoCredentialsOptions) {
|
|
55
63
|
this.username = options.username;
|
|
@@ -70,7 +78,10 @@ export class MongoCredentials {
|
|
|
70
78
|
this.password = process.env.AWS_SECRET_ACCESS_KEY;
|
|
71
79
|
}
|
|
72
80
|
|
|
73
|
-
if (
|
|
81
|
+
if (
|
|
82
|
+
this.mechanismProperties.AWS_SESSION_TOKEN == null &&
|
|
83
|
+
process.env.AWS_SESSION_TOKEN != null
|
|
84
|
+
) {
|
|
74
85
|
this.mechanismProperties = {
|
|
75
86
|
...this.mechanismProperties,
|
|
76
87
|
AWS_SESSION_TOKEN: process.env.AWS_SESSION_TOKEN
|
|
@@ -131,16 +142,16 @@ export class MongoCredentials {
|
|
|
131
142
|
this.mechanism === AuthMechanism.MONGODB_X509
|
|
132
143
|
) {
|
|
133
144
|
if (this.source != null && this.source !== '$external') {
|
|
134
|
-
// TODO(NODE-
|
|
135
|
-
throw new
|
|
145
|
+
// TODO(NODE-3485): Replace this with a MongoAuthValidationError
|
|
146
|
+
throw new MongoAPIError(
|
|
136
147
|
`Invalid source '${this.source}' for mechanism '${this.mechanism}' specified.`
|
|
137
148
|
);
|
|
138
149
|
}
|
|
139
150
|
}
|
|
140
151
|
|
|
141
152
|
if (this.mechanism === AuthMechanism.MONGODB_PLAIN && this.source == null) {
|
|
142
|
-
// TODO(NODE-
|
|
143
|
-
throw new
|
|
153
|
+
// TODO(NODE-3485): Replace this with a MongoAuthValidationError
|
|
154
|
+
throw new MongoAPIError('PLAIN Authentication Mechanism needs an auth source');
|
|
144
155
|
}
|
|
145
156
|
|
|
146
157
|
if (this.mechanism === AuthMechanism.MONGODB_X509 && this.password != null) {
|
|
@@ -148,8 +159,8 @@ export class MongoCredentials {
|
|
|
148
159
|
Reflect.set(this, 'password', undefined);
|
|
149
160
|
return;
|
|
150
161
|
}
|
|
151
|
-
// TODO(NODE-
|
|
152
|
-
throw new
|
|
162
|
+
// TODO(NODE-3485): Replace this with a MongoAuthValidationError
|
|
163
|
+
throw new MongoAPIError(`Password not allowed for mechanism MONGODB-X509`);
|
|
153
164
|
}
|
|
154
165
|
}
|
|
155
166
|
|
|
@@ -5,7 +5,7 @@ import * as BSON from '../../bson';
|
|
|
5
5
|
import { AuthProvider, AuthContext } from './auth_provider';
|
|
6
6
|
import { MongoCredentials } from './mongo_credentials';
|
|
7
7
|
import {
|
|
8
|
-
|
|
8
|
+
MongoRuntimeError,
|
|
9
9
|
MongoMissingCredentialsError,
|
|
10
10
|
MongoCompatibilityError
|
|
11
11
|
} from '../../error';
|
|
@@ -14,6 +14,7 @@ import type { BSONSerializeOptions } from '../../bson';
|
|
|
14
14
|
|
|
15
15
|
import { aws4 } from '../../deps';
|
|
16
16
|
import { AuthMechanism } from './defaultAuthProviders';
|
|
17
|
+
import type { Binary } from 'bson';
|
|
17
18
|
|
|
18
19
|
const ASCII_N = 110;
|
|
19
20
|
const AWS_RELATIVE_URI = 'http://169.254.170.2';
|
|
@@ -64,10 +65,19 @@ export class MongoDBAWS extends AuthProvider {
|
|
|
64
65
|
return;
|
|
65
66
|
}
|
|
66
67
|
|
|
67
|
-
const
|
|
68
|
-
const
|
|
68
|
+
const accessKeyId = credentials.username;
|
|
69
|
+
const secretAccessKey = credentials.password;
|
|
70
|
+
const sessionToken = credentials.mechanismProperties.AWS_SESSION_TOKEN;
|
|
71
|
+
|
|
72
|
+
// If all three defined, include sessionToken, else include username and pass, else no credentials
|
|
73
|
+
const awsCredentials =
|
|
74
|
+
accessKeyId && secretAccessKey && sessionToken
|
|
75
|
+
? { accessKeyId, secretAccessKey, sessionToken }
|
|
76
|
+
: accessKeyId && secretAccessKey
|
|
77
|
+
? { accessKeyId, secretAccessKey }
|
|
78
|
+
: undefined;
|
|
79
|
+
|
|
69
80
|
const db = credentials.source;
|
|
70
|
-
const token = credentials.mechanismProperties.AWS_SESSION_TOKEN;
|
|
71
81
|
crypto.randomBytes(32, (err, nonce) => {
|
|
72
82
|
if (err) {
|
|
73
83
|
callback(err);
|
|
@@ -83,24 +93,30 @@ export class MongoDBAWS extends AuthProvider {
|
|
|
83
93
|
connection.command(ns(`${db}.$cmd`), saslStart, undefined, (err, res) => {
|
|
84
94
|
if (err) return callback(err);
|
|
85
95
|
|
|
86
|
-
const serverResponse = BSON.deserialize(res.payload.buffer, bsonOptions)
|
|
96
|
+
const serverResponse = BSON.deserialize(res.payload.buffer, bsonOptions) as {
|
|
97
|
+
s: Binary;
|
|
98
|
+
h: string;
|
|
99
|
+
};
|
|
87
100
|
const host = serverResponse.h;
|
|
88
101
|
const serverNonce = serverResponse.s.buffer;
|
|
89
102
|
if (serverNonce.length !== 64) {
|
|
90
103
|
callback(
|
|
91
|
-
|
|
104
|
+
// TODO(NODE-3483)
|
|
105
|
+
new MongoRuntimeError(`Invalid server nonce length ${serverNonce.length}, expected 64`)
|
|
92
106
|
);
|
|
93
107
|
|
|
94
108
|
return;
|
|
95
109
|
}
|
|
96
110
|
|
|
97
111
|
if (serverNonce.compare(nonce, 0, nonce.length, 0, nonce.length) !== 0) {
|
|
98
|
-
|
|
112
|
+
// TODO(NODE-3483)
|
|
113
|
+
callback(new MongoRuntimeError('Server nonce does not begin with client nonce'));
|
|
99
114
|
return;
|
|
100
115
|
}
|
|
101
116
|
|
|
102
117
|
if (host.length < 1 || host.length > 255 || host.indexOf('..') !== -1) {
|
|
103
|
-
|
|
118
|
+
// TODO(NODE-3483)
|
|
119
|
+
callback(new MongoRuntimeError(`Server returned an invalid host: "${host}"`));
|
|
104
120
|
return;
|
|
105
121
|
}
|
|
106
122
|
|
|
@@ -120,18 +136,15 @@ export class MongoDBAWS extends AuthProvider {
|
|
|
120
136
|
path: '/',
|
|
121
137
|
body
|
|
122
138
|
},
|
|
123
|
-
|
|
124
|
-
accessKeyId: username,
|
|
125
|
-
secretAccessKey: password,
|
|
126
|
-
token
|
|
127
|
-
}
|
|
139
|
+
awsCredentials
|
|
128
140
|
);
|
|
129
141
|
|
|
130
|
-
const
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
142
|
+
const payload: AWSSaslContinuePayload = {
|
|
143
|
+
a: options.headers.Authorization,
|
|
144
|
+
d: options.headers['X-Amz-Date']
|
|
145
|
+
};
|
|
146
|
+
if (sessionToken) {
|
|
147
|
+
payload.t = sessionToken;
|
|
135
148
|
}
|
|
136
149
|
|
|
137
150
|
const saslContinue = {
|
|
@@ -146,14 +159,16 @@ export class MongoDBAWS extends AuthProvider {
|
|
|
146
159
|
}
|
|
147
160
|
}
|
|
148
161
|
|
|
149
|
-
interface
|
|
162
|
+
interface AWSTempCredentials {
|
|
150
163
|
AccessKeyId?: string;
|
|
151
164
|
SecretAccessKey?: string;
|
|
152
165
|
Token?: string;
|
|
166
|
+
RoleArn?: string;
|
|
167
|
+
Expiration?: Date;
|
|
153
168
|
}
|
|
154
169
|
|
|
155
170
|
function makeTempCredentials(credentials: MongoCredentials, callback: Callback<MongoCredentials>) {
|
|
156
|
-
function done(creds:
|
|
171
|
+
function done(creds: AWSTempCredentials) {
|
|
157
172
|
if (!creds.AccessKeyId || !creds.SecretAccessKey || !creds.Token) {
|
|
158
173
|
callback(
|
|
159
174
|
new MongoMissingCredentialsError('Could not obtain temporary MONGODB-AWS credentials')
|
|
@@ -180,6 +195,7 @@ function makeTempCredentials(credentials: MongoCredentials, callback: Callback<M
|
|
|
180
195
|
if (process.env.AWS_CONTAINER_CREDENTIALS_RELATIVE_URI) {
|
|
181
196
|
request(
|
|
182
197
|
`${AWS_RELATIVE_URI}${process.env.AWS_CONTAINER_CREDENTIALS_RELATIVE_URI}`,
|
|
198
|
+
undefined,
|
|
183
199
|
(err, res) => {
|
|
184
200
|
if (err) return callback(err);
|
|
185
201
|
done(res);
|
|
@@ -236,27 +252,15 @@ interface RequestOptions {
|
|
|
236
252
|
headers?: http.OutgoingHttpHeaders;
|
|
237
253
|
}
|
|
238
254
|
|
|
239
|
-
function request(uri: string, callback: Callback)
|
|
240
|
-
|
|
241
|
-
function request(uri: string, _options: RequestOptions | Callback, _callback?: Callback) {
|
|
242
|
-
let options = _options as RequestOptions;
|
|
243
|
-
if ('function' === typeof _options) {
|
|
244
|
-
options = {};
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
let callback: Callback = _options as Callback;
|
|
248
|
-
if (_callback) {
|
|
249
|
-
callback = _callback;
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
options = Object.assign(
|
|
255
|
+
function request(uri: string, _options: RequestOptions | undefined, callback: Callback) {
|
|
256
|
+
const options = Object.assign(
|
|
253
257
|
{
|
|
254
258
|
method: 'GET',
|
|
255
259
|
timeout: 10000,
|
|
256
260
|
json: true
|
|
257
261
|
},
|
|
258
262
|
url.parse(uri),
|
|
259
|
-
|
|
263
|
+
_options
|
|
260
264
|
);
|
|
261
265
|
|
|
262
266
|
const req = http.request(options, res => {
|
|
@@ -274,7 +278,8 @@ function request(uri: string, _options: RequestOptions | Callback, _callback?: C
|
|
|
274
278
|
const parsed = JSON.parse(data);
|
|
275
279
|
callback(undefined, parsed);
|
|
276
280
|
} catch (err) {
|
|
277
|
-
|
|
281
|
+
// TODO(NODE-3483)
|
|
282
|
+
callback(new MongoRuntimeError(`Invalid JSON response: "${data}"`));
|
|
278
283
|
}
|
|
279
284
|
});
|
|
280
285
|
});
|
package/src/cmap/auth/scram.ts
CHANGED
|
@@ -2,7 +2,7 @@ import * as crypto from 'crypto';
|
|
|
2
2
|
import { Binary, Document } from '../../bson';
|
|
3
3
|
import {
|
|
4
4
|
AnyError,
|
|
5
|
-
|
|
5
|
+
MongoRuntimeError,
|
|
6
6
|
MongoServerError,
|
|
7
7
|
MongoInvalidArgumentError,
|
|
8
8
|
MongoMissingCredentialsError
|
|
@@ -169,7 +169,8 @@ function continueScramConversation(
|
|
|
169
169
|
const iterations = parseInt(dict.i, 10);
|
|
170
170
|
if (iterations && iterations < 4096) {
|
|
171
171
|
callback(
|
|
172
|
-
|
|
172
|
+
// TODO(NODE-3483)
|
|
173
|
+
new MongoRuntimeError(`Server returned an invalid iteration count ${iterations}`),
|
|
173
174
|
false
|
|
174
175
|
);
|
|
175
176
|
return;
|
|
@@ -178,7 +179,8 @@ function continueScramConversation(
|
|
|
178
179
|
const salt = dict.s;
|
|
179
180
|
const rnonce = dict.r;
|
|
180
181
|
if (rnonce.startsWith('nonce')) {
|
|
181
|
-
|
|
182
|
+
// TODO(NODE-3483)
|
|
183
|
+
callback(new MongoRuntimeError(`Server returned an invalid nonce: ${rnonce}`), false);
|
|
182
184
|
return;
|
|
183
185
|
}
|
|
184
186
|
|
|
@@ -217,7 +219,7 @@ function continueScramConversation(
|
|
|
217
219
|
|
|
218
220
|
const parsedResponse = parsePayload(r.payload.value());
|
|
219
221
|
if (!compareDigest(Buffer.from(parsedResponse.v, 'base64'), serverSignature)) {
|
|
220
|
-
callback(new
|
|
222
|
+
callback(new MongoRuntimeError('Server returned an invalid signature'));
|
|
221
223
|
return;
|
|
222
224
|
}
|
|
223
225
|
|
|
@@ -274,7 +274,7 @@ function extractCommand(command: WriteProtocolMessageType): Document {
|
|
|
274
274
|
|
|
275
275
|
for (const k in command) {
|
|
276
276
|
if (k === 'query') continue;
|
|
277
|
-
clonedCommand[k] = deepCopy((
|
|
277
|
+
clonedCommand[k] = deepCopy((command as unknown as Record<string, unknown>)[k]);
|
|
278
278
|
}
|
|
279
279
|
return command.query ? clonedQuery : clonedCommand;
|
|
280
280
|
}
|
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;
|
|
@@ -78,14 +78,14 @@ export class Query {
|
|
|
78
78
|
constructor(ns: string, query: Document, options: OpQueryOptions) {
|
|
79
79
|
// Basic options needed to be passed in
|
|
80
80
|
// TODO(NODE-3483): Replace with MongoCommandError
|
|
81
|
-
if (ns == null) throw new
|
|
81
|
+
if (ns == null) throw new MongoRuntimeError('Namespace must be specified for query');
|
|
82
82
|
// TODO(NODE-3483): Replace with MongoCommandError
|
|
83
|
-
if (query == null) throw new
|
|
83
|
+
if (query == null) throw new MongoRuntimeError('A query document must be specified for query');
|
|
84
84
|
|
|
85
85
|
// Validate that we are not passing 0x00 in the collection name
|
|
86
86
|
if (ns.indexOf('\x00') !== -1) {
|
|
87
|
-
// TODO(NODE-3483):
|
|
88
|
-
throw new
|
|
87
|
+
// TODO(NODE-3483): Use MongoNamespace static method
|
|
88
|
+
throw new MongoRuntimeError('Namespace cannot contain a null character');
|
|
89
89
|
}
|
|
90
90
|
|
|
91
91
|
// Basic options
|
|
@@ -858,7 +858,7 @@ export class BinMsg {
|
|
|
858
858
|
// It was decided that no driver makes use of payload type 1
|
|
859
859
|
|
|
860
860
|
// TODO(NODE-3483): Replace with MongoDeprecationError
|
|
861
|
-
throw new
|
|
861
|
+
throw new MongoRuntimeError('OP_MSG Payload Type 1 detected unsupported protocol');
|
|
862
862
|
}
|
|
863
863
|
}
|
|
864
864
|
|
package/src/cmap/connect.ts
CHANGED
|
@@ -5,10 +5,10 @@ import {
|
|
|
5
5
|
MongoNetworkError,
|
|
6
6
|
MongoNetworkTimeoutError,
|
|
7
7
|
AnyError,
|
|
8
|
-
MongoDriverError,
|
|
9
8
|
MongoCompatibilityError,
|
|
9
|
+
MongoInvalidArgumentError,
|
|
10
10
|
MongoServerError,
|
|
11
|
-
|
|
11
|
+
MongoRuntimeError
|
|
12
12
|
} from '../error';
|
|
13
13
|
import { AUTH_PROVIDERS, AuthMechanism } from './auth/defaultAuthProviders';
|
|
14
14
|
import { AuthContext } from './auth/auth_provider';
|
|
@@ -144,7 +144,7 @@ function performInitialHandshake(
|
|
|
144
144
|
}
|
|
145
145
|
if (!response.serviceId) {
|
|
146
146
|
return callback(
|
|
147
|
-
new
|
|
147
|
+
new MongoCompatibilityError(
|
|
148
148
|
'Driver attempted to initialize in load balancing mode, ' +
|
|
149
149
|
'but the server does not support this mode.'
|
|
150
150
|
)
|
|
@@ -284,7 +284,8 @@ function parseConnectOptions(options: ConnectionOptions): SocketConnectOpts {
|
|
|
284
284
|
} else {
|
|
285
285
|
// This should never happen since we set up HostAddresses
|
|
286
286
|
// But if we don't throw here the socket could hang until timeout
|
|
287
|
-
|
|
287
|
+
// TODO(NODE-3483)
|
|
288
|
+
throw new MongoRuntimeError(`Unexpected HostAddress ${JSON.stringify(hostAddress)}`);
|
|
288
289
|
}
|
|
289
290
|
}
|
|
290
291
|
|
package/src/cmap/connection.ts
CHANGED
|
@@ -17,7 +17,7 @@ import {
|
|
|
17
17
|
HostAddress
|
|
18
18
|
} from '../utils';
|
|
19
19
|
import {
|
|
20
|
-
|
|
20
|
+
MongoRuntimeError,
|
|
21
21
|
MongoMissingDependencyError,
|
|
22
22
|
MongoCompatibilityError,
|
|
23
23
|
MongoNetworkError,
|
|
@@ -63,6 +63,8 @@ const kDescription = Symbol('description');
|
|
|
63
63
|
const kIsMaster = Symbol('ismaster');
|
|
64
64
|
/** @internal */
|
|
65
65
|
const kAutoEncrypter = Symbol('autoEncrypter');
|
|
66
|
+
/** @internal */
|
|
67
|
+
const kFullResult = Symbol('fullResult');
|
|
66
68
|
|
|
67
69
|
/** @internal */
|
|
68
70
|
export interface QueryOptions extends BSONSerializeOptions {
|
|
@@ -81,7 +83,7 @@ export interface QueryOptions extends BSONSerializeOptions {
|
|
|
81
83
|
oplogReplay?: boolean;
|
|
82
84
|
}
|
|
83
85
|
|
|
84
|
-
/** @
|
|
86
|
+
/** @internal */
|
|
85
87
|
export interface CommandOptions extends BSONSerializeOptions {
|
|
86
88
|
command?: boolean;
|
|
87
89
|
slaveOk?: boolean;
|
|
@@ -89,7 +91,7 @@ export interface CommandOptions extends BSONSerializeOptions {
|
|
|
89
91
|
readPreference?: ReadPreferenceLike;
|
|
90
92
|
raw?: boolean;
|
|
91
93
|
monitoring?: boolean;
|
|
92
|
-
|
|
94
|
+
[kFullResult]?: boolean;
|
|
93
95
|
socketTimeoutMS?: number;
|
|
94
96
|
/** Session to use for the operation */
|
|
95
97
|
session?: ClientSession;
|
|
@@ -363,7 +365,7 @@ export class Connection extends TypedEventEmitter<ConnectionEvents> {
|
|
|
363
365
|
): void {
|
|
364
366
|
if (!(ns instanceof MongoDBNamespace)) {
|
|
365
367
|
// TODO(NODE-3483): Replace this with a MongoCommandError
|
|
366
|
-
throw new
|
|
368
|
+
throw new MongoRuntimeError('Must provide a MongoDBNamespace instance');
|
|
367
369
|
}
|
|
368
370
|
|
|
369
371
|
const readPreference = getReadPreference(cmd, options);
|
|
@@ -492,7 +494,7 @@ export class Connection extends TypedEventEmitter<ConnectionEvents> {
|
|
|
492
494
|
write(
|
|
493
495
|
this,
|
|
494
496
|
query,
|
|
495
|
-
{
|
|
497
|
+
{ [kFullResult]: true, ...pluckBSONSerializeOptions(options) },
|
|
496
498
|
(err, result) => {
|
|
497
499
|
if (err || !result) return callback(err, result);
|
|
498
500
|
if (isExplain && result.documents && result.documents[0]) {
|
|
@@ -511,11 +513,11 @@ export class Connection extends TypedEventEmitter<ConnectionEvents> {
|
|
|
511
513
|
options: GetMoreOptions,
|
|
512
514
|
callback: Callback<Document>
|
|
513
515
|
): void {
|
|
514
|
-
const fullResult =
|
|
516
|
+
const fullResult = !!options[kFullResult];
|
|
515
517
|
const wireVersion = maxWireVersion(this);
|
|
516
518
|
if (!cursorId) {
|
|
517
519
|
// TODO(NODE-3483): Replace this with a MongoCommandError
|
|
518
|
-
callback(new
|
|
520
|
+
callback(new MongoRuntimeError('Invalid internal cursor state, no known cursor id'));
|
|
519
521
|
return;
|
|
520
522
|
}
|
|
521
523
|
|
|
@@ -526,7 +528,7 @@ export class Connection extends TypedEventEmitter<ConnectionEvents> {
|
|
|
526
528
|
Object.assign(options, { ...pluckBSONSerializeOptions(options) })
|
|
527
529
|
);
|
|
528
530
|
|
|
529
|
-
queryOptions
|
|
531
|
+
queryOptions[kFullResult] = true;
|
|
530
532
|
queryOptions.command = true;
|
|
531
533
|
write(this, getMoreOp, queryOptions, (err, response) => {
|
|
532
534
|
if (fullResult) return callback(err, response);
|
|
@@ -570,7 +572,7 @@ export class Connection extends TypedEventEmitter<ConnectionEvents> {
|
|
|
570
572
|
): void {
|
|
571
573
|
if (!cursorIds || !Array.isArray(cursorIds)) {
|
|
572
574
|
// TODO(NODE-3483): Replace this with a MongoCommandError
|
|
573
|
-
throw new
|
|
575
|
+
throw new MongoRuntimeError(`Invalid list of cursor ids provided: ${cursorIds}`);
|
|
574
576
|
}
|
|
575
577
|
|
|
576
578
|
if (maxWireVersion(this) < 4) {
|
|
@@ -591,7 +593,7 @@ export class Connection extends TypedEventEmitter<ConnectionEvents> {
|
|
|
591
593
|
this.command(
|
|
592
594
|
ns,
|
|
593
595
|
{ killCursors: ns.collection, cursors: cursorIds },
|
|
594
|
-
{
|
|
596
|
+
{ [kFullResult]: true, ...options },
|
|
595
597
|
(err, response) => {
|
|
596
598
|
if (err || !response) return callback(err);
|
|
597
599
|
if (response.cursorNotFound) {
|
|
@@ -600,7 +602,8 @@ export class Connection extends TypedEventEmitter<ConnectionEvents> {
|
|
|
600
602
|
|
|
601
603
|
if (!Array.isArray(response.documents) || response.documents.length === 0) {
|
|
602
604
|
return callback(
|
|
603
|
-
|
|
605
|
+
// TODO(NODE-3483)
|
|
606
|
+
new MongoRuntimeError(
|
|
604
607
|
`invalid killCursors result returned for cursor id ${cursorIds[0]}`
|
|
605
608
|
)
|
|
606
609
|
);
|
|
@@ -773,7 +776,7 @@ function write(
|
|
|
773
776
|
requestId: command.requestId,
|
|
774
777
|
cb: callback,
|
|
775
778
|
session: options.session,
|
|
776
|
-
fullResult:
|
|
779
|
+
fullResult: !!options[kFullResult],
|
|
777
780
|
noResponse: typeof options.noResponse === 'boolean' ? options.noResponse : false,
|
|
778
781
|
documentsReturnedIn: options.documentsReturnedIn,
|
|
779
782
|
command: !!options.command,
|
|
@@ -5,7 +5,7 @@ import { Logger } from '../logger';
|
|
|
5
5
|
import { ConnectionPoolMetrics } from './metrics';
|
|
6
6
|
import { connect } from './connect';
|
|
7
7
|
import { eachAsync, makeCounter, Callback } from '../utils';
|
|
8
|
-
import {
|
|
8
|
+
import { MongoError, MongoInvalidArgumentError, MongoRuntimeError } from '../error';
|
|
9
9
|
import { PoolClosedError, WaitQueueTimeoutError } from './errors';
|
|
10
10
|
import {
|
|
11
11
|
ConnectionPoolCreatedEvent,
|
|
@@ -350,7 +350,8 @@ export class ConnectionPool extends TypedEventEmitter<ConnectionPoolEvents> {
|
|
|
350
350
|
// Only need to worry if the generation exists, since it should
|
|
351
351
|
// always be there but typescript needs the check.
|
|
352
352
|
if (generation == null) {
|
|
353
|
-
|
|
353
|
+
// TODO(NODE-3483)
|
|
354
|
+
throw new MongoRuntimeError('Service generations are required in load balancer mode.');
|
|
354
355
|
} else {
|
|
355
356
|
// Increment the generation for the service id.
|
|
356
357
|
this.serviceGenerations.set(sid, generation + 1);
|
|
@@ -388,7 +389,8 @@ export class ConnectionPool extends TypedEventEmitter<ConnectionPoolEvents> {
|
|
|
388
389
|
clearTimeout(waitQueueMember.timer);
|
|
389
390
|
}
|
|
390
391
|
if (!waitQueueMember[kCancelled]) {
|
|
391
|
-
|
|
392
|
+
// TODO(NODE-3483): Replace with MongoConnectionPoolClosedError
|
|
393
|
+
waitQueueMember.callback(new MongoRuntimeError('Connection pool closed'));
|
|
392
394
|
}
|
|
393
395
|
}
|
|
394
396
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Duplex, DuplexOptions } from 'stream';
|
|
2
2
|
import { Response, Msg, BinMsg, Query, WriteProtocolMessageType, MessageHeader } from './commands';
|
|
3
|
-
import {
|
|
3
|
+
import { MongoDecompressionError, MongoParseError } from '../error';
|
|
4
4
|
import { OP_COMPRESSED, OP_MSG } from './wire_protocol/constants';
|
|
5
5
|
import {
|
|
6
6
|
compress,
|
|
@@ -191,9 +191,7 @@ function processIncomingData(stream: MessageStream, callback: Callback<Buffer>)
|
|
|
191
191
|
|
|
192
192
|
if (messageBody.length !== messageHeader.length) {
|
|
193
193
|
callback(
|
|
194
|
-
new
|
|
195
|
-
'Decompressing a compressed message from the server failed. The message is corrupt.'
|
|
196
|
-
)
|
|
194
|
+
new MongoDecompressionError('Message body and message header must be the same length')
|
|
197
195
|
);
|
|
198
196
|
|
|
199
197
|
return;
|
|
@@ -2,8 +2,8 @@ import * as zlib from 'zlib';
|
|
|
2
2
|
import type { Callback } from '../../utils';
|
|
3
3
|
import type { OperationDescription } from '../message_stream';
|
|
4
4
|
|
|
5
|
-
import { Snappy } from '../../deps';
|
|
6
|
-
import {
|
|
5
|
+
import { PKG_VERSION, Snappy } from '../../deps';
|
|
6
|
+
import { MongoDecompressionError, MongoInvalidArgumentError } from '../../error';
|
|
7
7
|
|
|
8
8
|
/** @public */
|
|
9
9
|
export const Compressor = Object.freeze({
|
|
@@ -39,12 +39,20 @@ export function compress(
|
|
|
39
39
|
): void {
|
|
40
40
|
const zlibOptions = {} as zlib.ZlibOptions;
|
|
41
41
|
switch (self.options.agreedCompressor) {
|
|
42
|
-
case 'snappy':
|
|
42
|
+
case 'snappy': {
|
|
43
43
|
if ('kModuleError' in Snappy) {
|
|
44
44
|
return callback(Snappy['kModuleError']);
|
|
45
45
|
}
|
|
46
|
-
|
|
46
|
+
|
|
47
|
+
if (Snappy[PKG_VERSION].major <= 6) {
|
|
48
|
+
Snappy.compress(dataToBeCompressed, callback);
|
|
49
|
+
} else {
|
|
50
|
+
Snappy.compress(dataToBeCompressed)
|
|
51
|
+
.then(buffer => callback(undefined, buffer))
|
|
52
|
+
.catch(error => callback(error));
|
|
53
|
+
}
|
|
47
54
|
break;
|
|
55
|
+
}
|
|
48
56
|
case 'zlib':
|
|
49
57
|
// Determine zlibCompressionLevel
|
|
50
58
|
if (self.options.zlibCompressionLevel) {
|
|
@@ -53,10 +61,8 @@ export function compress(
|
|
|
53
61
|
zlib.deflate(dataToBeCompressed, zlibOptions, callback as zlib.CompressCallback);
|
|
54
62
|
break;
|
|
55
63
|
default:
|
|
56
|
-
throw new
|
|
57
|
-
|
|
58
|
-
self.options.agreedCompressor +
|
|
59
|
-
'".'
|
|
64
|
+
throw new MongoInvalidArgumentError(
|
|
65
|
+
`Unknown compressor ${self.options.agreedCompressor} failed to compress`
|
|
60
66
|
);
|
|
61
67
|
}
|
|
62
68
|
}
|
|
@@ -68,19 +74,26 @@ export function decompress(
|
|
|
68
74
|
callback: Callback<Buffer>
|
|
69
75
|
): void {
|
|
70
76
|
if (compressorID < 0 || compressorID > Math.max(2)) {
|
|
71
|
-
throw new
|
|
72
|
-
`Server sent message compressed using an unsupported compressor
|
|
73
|
-
` (Received compressor ID ${compressorID})`
|
|
77
|
+
throw new MongoDecompressionError(
|
|
78
|
+
`Server sent message compressed using an unsupported compressor. (Received compressor ID ${compressorID})`
|
|
74
79
|
);
|
|
75
80
|
}
|
|
76
81
|
|
|
77
82
|
switch (compressorID) {
|
|
78
|
-
case Compressor.snappy:
|
|
83
|
+
case Compressor.snappy: {
|
|
79
84
|
if ('kModuleError' in Snappy) {
|
|
80
85
|
return callback(Snappy['kModuleError']);
|
|
81
86
|
}
|
|
82
|
-
|
|
87
|
+
|
|
88
|
+
if (Snappy[PKG_VERSION].major <= 6) {
|
|
89
|
+
Snappy.uncompress(compressedData, { asBuffer: true }, callback);
|
|
90
|
+
} else {
|
|
91
|
+
Snappy.uncompress(compressedData, { asBuffer: true })
|
|
92
|
+
.then(buffer => callback(undefined, buffer))
|
|
93
|
+
.catch(error => callback(error));
|
|
94
|
+
}
|
|
83
95
|
break;
|
|
96
|
+
}
|
|
84
97
|
case Compressor.zlib:
|
|
85
98
|
zlib.inflate(compressedData, callback as zlib.CompressCallback);
|
|
86
99
|
break;
|