mongodb 6.7.0-dev.20240608.sha.0655c730 → 6.7.0-dev.20240614.sha.3ed6a2ad
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/lib/bson.js.map +1 -1
- package/lib/client-side-encryption/auto_encrypter.js +8 -61
- package/lib/client-side-encryption/auto_encrypter.js.map +1 -1
- package/lib/client-side-encryption/client_encryption.js +5 -5
- package/lib/client-side-encryption/client_encryption.js.map +1 -1
- package/lib/client-side-encryption/providers/index.js.map +1 -1
- package/lib/client-side-encryption/state_machine.js +15 -11
- package/lib/client-side-encryption/state_machine.js.map +1 -1
- package/lib/cmap/connection.js +22 -20
- package/lib/cmap/connection.js.map +1 -1
- package/lib/cmap/wire_protocol/on_demand/document.js +8 -5
- package/lib/cmap/wire_protocol/on_demand/document.js.map +1 -1
- package/lib/cmap/wire_protocol/responses.js +116 -40
- package/lib/cmap/wire_protocol/responses.js.map +1 -1
- package/lib/constants.js +9 -1
- package/lib/constants.js.map +1 -1
- package/lib/cursor/abstract_cursor.js +24 -60
- package/lib/cursor/abstract_cursor.js.map +1 -1
- package/lib/cursor/aggregation_cursor.js +2 -3
- package/lib/cursor/aggregation_cursor.js.map +1 -1
- package/lib/cursor/change_stream_cursor.js +6 -8
- package/lib/cursor/change_stream_cursor.js.map +1 -1
- package/lib/cursor/find_cursor.js +5 -17
- package/lib/cursor/find_cursor.js.map +1 -1
- package/lib/cursor/list_collections_cursor.js +0 -1
- package/lib/cursor/list_collections_cursor.js.map +1 -1
- package/lib/cursor/list_indexes_cursor.js +0 -1
- package/lib/cursor/list_indexes_cursor.js.map +1 -1
- package/lib/cursor/run_command_cursor.js +4 -6
- package/lib/cursor/run_command_cursor.js.map +1 -1
- package/lib/error.js +6 -21
- package/lib/error.js.map +1 -1
- package/lib/index.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 -2
- package/lib/operations/bulk_write.js.map +1 -1
- package/lib/operations/command.js +2 -3
- package/lib/operations/command.js.map +1 -1
- package/lib/operations/count_documents.js +1 -7
- package/lib/operations/count_documents.js.map +1 -1
- package/lib/operations/execute_operation.js.map +1 -1
- package/lib/operations/find.js +2 -1
- package/lib/operations/find.js.map +1 -1
- package/lib/operations/get_more.js +1 -1
- package/lib/operations/get_more.js.map +1 -1
- package/lib/operations/indexes.js +2 -1
- package/lib/operations/indexes.js.map +1 -1
- package/lib/operations/list_collections.js +2 -1
- package/lib/operations/list_collections.js.map +1 -1
- package/lib/operations/run_command.js +1 -1
- package/lib/operations/run_command.js.map +1 -1
- package/lib/operations/update.js +2 -1
- package/lib/operations/update.js.map +1 -1
- package/lib/sdam/server.js +7 -2
- package/lib/sdam/server.js.map +1 -1
- package/lib/utils.js +45 -1
- package/lib/utils.js.map +1 -1
- package/lib/write_concern.js +17 -1
- package/lib/write_concern.js.map +1 -1
- package/mongodb.d.ts +120 -85
- package/package.json +1 -1
- package/src/bson.ts +1 -0
- package/src/client-side-encryption/auto_encrypter.ts +9 -70
- package/src/client-side-encryption/client_encryption.ts +6 -6
- package/src/client-side-encryption/providers/index.ts +120 -92
- package/src/client-side-encryption/state_machine.ts +22 -18
- package/src/cmap/connection.ts +46 -50
- package/src/cmap/wire_protocol/on_demand/document.ts +13 -6
- package/src/cmap/wire_protocol/responses.ts +140 -45
- package/src/constants.ts +9 -0
- package/src/cursor/abstract_cursor.ts +51 -71
- package/src/cursor/aggregation_cursor.ts +13 -12
- package/src/cursor/change_stream_cursor.ts +20 -34
- package/src/cursor/find_cursor.ts +17 -25
- package/src/cursor/list_collections_cursor.ts +3 -4
- package/src/cursor/list_indexes_cursor.ts +3 -4
- package/src/cursor/run_command_cursor.ts +13 -19
- package/src/error.ts +16 -28
- package/src/index.ts +12 -8
- package/src/operations/aggregate.ts +12 -5
- package/src/operations/bulk_write.ts +1 -2
- package/src/operations/command.ts +17 -3
- package/src/operations/count_documents.ts +7 -11
- package/src/operations/delete.ts +2 -2
- package/src/operations/execute_operation.ts +0 -13
- package/src/operations/find.ts +7 -3
- package/src/operations/find_and_modify.ts +1 -1
- package/src/operations/get_more.ts +6 -10
- package/src/operations/indexes.ts +7 -3
- package/src/operations/list_collections.ts +8 -3
- package/src/operations/run_command.ts +16 -6
- package/src/operations/update.ts +2 -1
- package/src/sdam/server.ts +7 -2
- package/src/utils.ts +52 -2
- package/src/write_concern.ts +18 -0
|
@@ -4,124 +4,152 @@ import { loadGCPCredentials } from './gcp';
|
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* @public
|
|
7
|
+
*
|
|
8
|
+
* A data key provider. Allowed values:
|
|
9
|
+
*
|
|
10
|
+
* - aws, gcp, local, kmip or azure
|
|
11
|
+
* - (`mongodb-client-encryption>=6.0.1` only) a named key, in the form of:
|
|
12
|
+
* `aws:<name>`, `gcp:<name>`, `local:<name>`, `kmip:<name>`, `azure:<name>`
|
|
13
|
+
* where `name` is an alphanumeric string, underscores allowed.
|
|
7
14
|
*/
|
|
8
|
-
export type ClientEncryptionDataKeyProvider =
|
|
15
|
+
export type ClientEncryptionDataKeyProvider = string;
|
|
16
|
+
|
|
17
|
+
/** @public */
|
|
18
|
+
export interface AWSKMSProviderConfiguration {
|
|
19
|
+
/**
|
|
20
|
+
* The access key used for the AWS KMS provider
|
|
21
|
+
*/
|
|
22
|
+
accessKeyId: string;
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* The secret access key used for the AWS KMS provider
|
|
26
|
+
*/
|
|
27
|
+
secretAccessKey: string;
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* An optional AWS session token that will be used as the
|
|
31
|
+
* X-Amz-Security-Token header for AWS requests.
|
|
32
|
+
*/
|
|
33
|
+
sessionToken?: string;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/** @public */
|
|
37
|
+
export interface LocalKMSProviderConfiguration {
|
|
38
|
+
/**
|
|
39
|
+
* The master key used to encrypt/decrypt data keys.
|
|
40
|
+
* A 96-byte long Buffer or base64 encoded string.
|
|
41
|
+
*/
|
|
42
|
+
key: Buffer | string;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/** @public */
|
|
46
|
+
export interface KMIPKMSProviderConfiguration {
|
|
47
|
+
/**
|
|
48
|
+
* The output endpoint string.
|
|
49
|
+
* The endpoint consists of a hostname and port separated by a colon.
|
|
50
|
+
* E.g. "example.com:123". A port is always present.
|
|
51
|
+
*/
|
|
52
|
+
endpoint?: string;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/** @public */
|
|
56
|
+
export type AzureKMSProviderConfiguration =
|
|
57
|
+
| {
|
|
58
|
+
/**
|
|
59
|
+
* The tenant ID identifies the organization for the account
|
|
60
|
+
*/
|
|
61
|
+
tenantId: string;
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* The client ID to authenticate a registered application
|
|
65
|
+
*/
|
|
66
|
+
clientId: string;
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* The client secret to authenticate a registered application
|
|
70
|
+
*/
|
|
71
|
+
clientSecret: string;
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* If present, a host with optional port. E.g. "example.com" or "example.com:443".
|
|
75
|
+
* This is optional, and only needed if customer is using a non-commercial Azure instance
|
|
76
|
+
* (e.g. a government or China account, which use different URLs).
|
|
77
|
+
* Defaults to "login.microsoftonline.com"
|
|
78
|
+
*/
|
|
79
|
+
identityPlatformEndpoint?: string | undefined;
|
|
80
|
+
}
|
|
81
|
+
| {
|
|
82
|
+
/**
|
|
83
|
+
* If present, an access token to authenticate with Azure.
|
|
84
|
+
*/
|
|
85
|
+
accessToken: string;
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
/** @public */
|
|
89
|
+
export type GCPKMSProviderConfiguration =
|
|
90
|
+
| {
|
|
91
|
+
/**
|
|
92
|
+
* The service account email to authenticate
|
|
93
|
+
*/
|
|
94
|
+
email: string;
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* A PKCS#8 encrypted key. This can either be a base64 string or a binary representation
|
|
98
|
+
*/
|
|
99
|
+
privateKey: string | Buffer;
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* If present, a host with optional port. E.g. "example.com" or "example.com:443".
|
|
103
|
+
* Defaults to "oauth2.googleapis.com"
|
|
104
|
+
*/
|
|
105
|
+
endpoint?: string | undefined;
|
|
106
|
+
}
|
|
107
|
+
| {
|
|
108
|
+
/**
|
|
109
|
+
* If present, an access token to authenticate with GCP.
|
|
110
|
+
*/
|
|
111
|
+
accessToken: string;
|
|
112
|
+
};
|
|
9
113
|
|
|
10
114
|
/**
|
|
11
115
|
* @public
|
|
12
116
|
* Configuration options that are used by specific KMS providers during key generation, encryption, and decryption.
|
|
117
|
+
*
|
|
118
|
+
* Named KMS providers _are not supported_ for automatic KMS credential fetching.
|
|
13
119
|
*/
|
|
14
120
|
export interface KMSProviders {
|
|
15
121
|
/**
|
|
16
122
|
* Configuration options for using 'aws' as your KMS provider
|
|
17
123
|
*/
|
|
18
|
-
aws?:
|
|
19
|
-
| {
|
|
20
|
-
/**
|
|
21
|
-
* The access key used for the AWS KMS provider
|
|
22
|
-
*/
|
|
23
|
-
accessKeyId: string;
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* The secret access key used for the AWS KMS provider
|
|
27
|
-
*/
|
|
28
|
-
secretAccessKey: string;
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* An optional AWS session token that will be used as the
|
|
32
|
-
* X-Amz-Security-Token header for AWS requests.
|
|
33
|
-
*/
|
|
34
|
-
sessionToken?: string;
|
|
35
|
-
}
|
|
36
|
-
| Record<string, never>;
|
|
124
|
+
aws?: AWSKMSProviderConfiguration | Record<string, never>;
|
|
37
125
|
|
|
38
126
|
/**
|
|
39
127
|
* Configuration options for using 'local' as your KMS provider
|
|
40
128
|
*/
|
|
41
|
-
local?:
|
|
42
|
-
/**
|
|
43
|
-
* The master key used to encrypt/decrypt data keys.
|
|
44
|
-
* A 96-byte long Buffer or base64 encoded string.
|
|
45
|
-
*/
|
|
46
|
-
key: Buffer | string;
|
|
47
|
-
};
|
|
129
|
+
local?: LocalKMSProviderConfiguration;
|
|
48
130
|
|
|
49
131
|
/**
|
|
50
132
|
* Configuration options for using 'kmip' as your KMS provider
|
|
51
133
|
*/
|
|
52
|
-
kmip?:
|
|
53
|
-
/**
|
|
54
|
-
* The output endpoint string.
|
|
55
|
-
* The endpoint consists of a hostname and port separated by a colon.
|
|
56
|
-
* E.g. "example.com:123". A port is always present.
|
|
57
|
-
*/
|
|
58
|
-
endpoint?: string;
|
|
59
|
-
};
|
|
134
|
+
kmip?: KMIPKMSProviderConfiguration;
|
|
60
135
|
|
|
61
136
|
/**
|
|
62
137
|
* Configuration options for using 'azure' as your KMS provider
|
|
63
138
|
*/
|
|
64
|
-
azure?:
|
|
65
|
-
| {
|
|
66
|
-
/**
|
|
67
|
-
* The tenant ID identifies the organization for the account
|
|
68
|
-
*/
|
|
69
|
-
tenantId: string;
|
|
70
|
-
|
|
71
|
-
/**
|
|
72
|
-
* The client ID to authenticate a registered application
|
|
73
|
-
*/
|
|
74
|
-
clientId: string;
|
|
75
|
-
|
|
76
|
-
/**
|
|
77
|
-
* The client secret to authenticate a registered application
|
|
78
|
-
*/
|
|
79
|
-
clientSecret: string;
|
|
80
|
-
|
|
81
|
-
/**
|
|
82
|
-
* If present, a host with optional port. E.g. "example.com" or "example.com:443".
|
|
83
|
-
* This is optional, and only needed if customer is using a non-commercial Azure instance
|
|
84
|
-
* (e.g. a government or China account, which use different URLs).
|
|
85
|
-
* Defaults to "login.microsoftonline.com"
|
|
86
|
-
*/
|
|
87
|
-
identityPlatformEndpoint?: string | undefined;
|
|
88
|
-
}
|
|
89
|
-
| {
|
|
90
|
-
/**
|
|
91
|
-
* If present, an access token to authenticate with Azure.
|
|
92
|
-
*/
|
|
93
|
-
accessToken: string;
|
|
94
|
-
}
|
|
95
|
-
| Record<string, never>;
|
|
139
|
+
azure?: AzureKMSProviderConfiguration | Record<string, never>;
|
|
96
140
|
|
|
97
141
|
/**
|
|
98
142
|
* Configuration options for using 'gcp' as your KMS provider
|
|
99
143
|
*/
|
|
100
|
-
gcp?:
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
*/
|
|
110
|
-
privateKey: string | Buffer;
|
|
111
|
-
|
|
112
|
-
/**
|
|
113
|
-
* If present, a host with optional port. E.g. "example.com" or "example.com:443".
|
|
114
|
-
* Defaults to "oauth2.googleapis.com"
|
|
115
|
-
*/
|
|
116
|
-
endpoint?: string | undefined;
|
|
117
|
-
}
|
|
118
|
-
| {
|
|
119
|
-
/**
|
|
120
|
-
* If present, an access token to authenticate with GCP.
|
|
121
|
-
*/
|
|
122
|
-
accessToken: string;
|
|
123
|
-
}
|
|
124
|
-
| Record<string, never>;
|
|
144
|
+
gcp?: GCPKMSProviderConfiguration | Record<string, never>;
|
|
145
|
+
|
|
146
|
+
[key: string]:
|
|
147
|
+
| AWSKMSProviderConfiguration
|
|
148
|
+
| LocalKMSProviderConfiguration
|
|
149
|
+
| KMIPKMSProviderConfiguration
|
|
150
|
+
| AzureKMSProviderConfiguration
|
|
151
|
+
| GCPKMSProviderConfiguration
|
|
152
|
+
| undefined;
|
|
125
153
|
}
|
|
126
154
|
|
|
127
155
|
/**
|
|
@@ -17,7 +17,7 @@ import { BufferPool, MongoDBCollectionNamespace, promiseWithResolvers } from '..
|
|
|
17
17
|
import { type DataKey } from './client_encryption';
|
|
18
18
|
import { MongoCryptError } from './errors';
|
|
19
19
|
import { type MongocryptdManager } from './mongocryptd_manager';
|
|
20
|
-
import { type
|
|
20
|
+
import { type KMSProviders } from './providers';
|
|
21
21
|
|
|
22
22
|
let socks: SocksLib | null = null;
|
|
23
23
|
function loadSocks(): SocksLib {
|
|
@@ -110,8 +110,23 @@ export type CSFLEKMSTlsOptions = {
|
|
|
110
110
|
kmip?: ClientEncryptionTlsOptions;
|
|
111
111
|
local?: ClientEncryptionTlsOptions;
|
|
112
112
|
azure?: ClientEncryptionTlsOptions;
|
|
113
|
+
|
|
114
|
+
[key: string]: ClientEncryptionTlsOptions | undefined;
|
|
113
115
|
};
|
|
114
116
|
|
|
117
|
+
/**
|
|
118
|
+
* This is kind of a hack. For `rewrapManyDataKey`, we have tests that
|
|
119
|
+
* guarantee that when there are no matching keys, `rewrapManyDataKey` returns
|
|
120
|
+
* nothing. We also have tests for auto encryption that guarantee for `encrypt`
|
|
121
|
+
* we return an error when there are no matching keys. This error is generated in
|
|
122
|
+
* subsequent iterations of the state machine.
|
|
123
|
+
* Some apis (`encrypt`) throw if there are no filter matches and others (`rewrapManyDataKey`)
|
|
124
|
+
* do not. We set the result manually here, and let the state machine continue. `libmongocrypt`
|
|
125
|
+
* will inform us if we need to error by setting the state to `MONGOCRYPT_CTX_ERROR` but
|
|
126
|
+
* otherwise we'll return `{ v: [] }`.
|
|
127
|
+
*/
|
|
128
|
+
let EMPTY_V;
|
|
129
|
+
|
|
115
130
|
/**
|
|
116
131
|
* @internal
|
|
117
132
|
*
|
|
@@ -154,16 +169,13 @@ export class StateMachine {
|
|
|
154
169
|
/**
|
|
155
170
|
* Executes the state machine according to the specification
|
|
156
171
|
*/
|
|
157
|
-
async execute
|
|
158
|
-
executor: StateMachineExecutable,
|
|
159
|
-
context: MongoCryptContext
|
|
160
|
-
): Promise<T> {
|
|
172
|
+
async execute(executor: StateMachineExecutable, context: MongoCryptContext): Promise<Uint8Array> {
|
|
161
173
|
const keyVaultNamespace = executor._keyVaultNamespace;
|
|
162
174
|
const keyVaultClient = executor._keyVaultClient;
|
|
163
175
|
const metaDataClient = executor._metaDataClient;
|
|
164
176
|
const mongocryptdClient = executor._mongocryptdClient;
|
|
165
177
|
const mongocryptdManager = executor._mongocryptdManager;
|
|
166
|
-
let result:
|
|
178
|
+
let result: Uint8Array | null = null;
|
|
167
179
|
|
|
168
180
|
while (context.state !== MONGOCRYPT_CTX_DONE && context.state !== MONGOCRYPT_CTX_ERROR) {
|
|
169
181
|
debug(`[context#${context.id}] ${stateToString.get(context.state) || context.state}`);
|
|
@@ -211,16 +223,8 @@ export class StateMachine {
|
|
|
211
223
|
const keys = await this.fetchKeys(keyVaultClient, keyVaultNamespace, filter);
|
|
212
224
|
|
|
213
225
|
if (keys.length === 0) {
|
|
214
|
-
//
|
|
215
|
-
|
|
216
|
-
// nothing. We also have tests for auto encryption that guarantee for `encrypt`
|
|
217
|
-
// we return an error when there are no matching keys. This error is generated in
|
|
218
|
-
// subsequent iterations of the state machine.
|
|
219
|
-
// Some apis (`encrypt`) throw if there are no filter matches and others (`rewrapManyDataKey`)
|
|
220
|
-
// do not. We set the result manually here, and let the state machine continue. `libmongocrypt`
|
|
221
|
-
// will inform us if we need to error by setting the state to `MONGOCRYPT_CTX_ERROR` but
|
|
222
|
-
// otherwise we'll return `{ v: [] }`.
|
|
223
|
-
result = { v: [] } as any as T;
|
|
226
|
+
// See docs on EMPTY_V
|
|
227
|
+
result = EMPTY_V ??= serialize({ v: [] });
|
|
224
228
|
}
|
|
225
229
|
for await (const key of keys) {
|
|
226
230
|
context.addMongoOperationResponse(serialize(key));
|
|
@@ -252,7 +256,7 @@ export class StateMachine {
|
|
|
252
256
|
const message = context.status.message || 'Finalization error';
|
|
253
257
|
throw new MongoCryptError(message);
|
|
254
258
|
}
|
|
255
|
-
result =
|
|
259
|
+
result = finalizedContext;
|
|
256
260
|
break;
|
|
257
261
|
}
|
|
258
262
|
|
|
@@ -319,7 +323,7 @@ export class StateMachine {
|
|
|
319
323
|
|
|
320
324
|
const tlsOptions = this.options.tlsOptions;
|
|
321
325
|
if (tlsOptions) {
|
|
322
|
-
const kmsProvider = request.kmsProvider
|
|
326
|
+
const kmsProvider = request.kmsProvider;
|
|
323
327
|
const providerTlsOptions = tlsOptions[kmsProvider];
|
|
324
328
|
if (providerTlsOptions) {
|
|
325
329
|
const error = this.validateTlsOptions(kmsProvider, providerTlsOptions);
|
package/src/cmap/connection.ts
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
import { type Readable, Transform, type TransformCallback } from 'stream';
|
|
2
2
|
import { clearTimeout, setTimeout } from 'timers';
|
|
3
3
|
|
|
4
|
-
import type
|
|
5
|
-
import type
|
|
4
|
+
import { type BSONSerializeOptions, deserialize, type Document, type ObjectId } from '../bson';
|
|
5
|
+
import { type AutoEncrypter } from '../client-side-encryption/auto_encrypter';
|
|
6
6
|
import {
|
|
7
7
|
CLOSE,
|
|
8
8
|
CLUSTER_TIME_RECEIVED,
|
|
9
9
|
COMMAND_FAILED,
|
|
10
10
|
COMMAND_STARTED,
|
|
11
11
|
COMMAND_SUCCEEDED,
|
|
12
|
+
kDecorateResult,
|
|
12
13
|
PINNED,
|
|
13
14
|
UNPINNED
|
|
14
15
|
} from '../constants';
|
|
@@ -19,8 +20,7 @@ import {
|
|
|
19
20
|
MongoNetworkTimeoutError,
|
|
20
21
|
MongoParseError,
|
|
21
22
|
MongoServerError,
|
|
22
|
-
MongoUnexpectedServerResponseError
|
|
23
|
-
MongoWriteConcernError
|
|
23
|
+
MongoUnexpectedServerResponseError
|
|
24
24
|
} from '../error';
|
|
25
25
|
import type { ServerApi, SupportedNodeConnectionOptions } from '../mongo_client';
|
|
26
26
|
import { type MongoClientAuthProviders } from '../mongo_client_auth_providers';
|
|
@@ -33,6 +33,7 @@ import {
|
|
|
33
33
|
BufferPool,
|
|
34
34
|
calculateDurationInMs,
|
|
35
35
|
type Callback,
|
|
36
|
+
decorateDecryptionResult,
|
|
36
37
|
HostAddress,
|
|
37
38
|
maxWireVersion,
|
|
38
39
|
type MongoDBNamespace,
|
|
@@ -63,7 +64,7 @@ import { StreamDescription, type StreamDescriptionOptions } from './stream_descr
|
|
|
63
64
|
import { type CompressorName, decompressResponse } from './wire_protocol/compression';
|
|
64
65
|
import { onData } from './wire_protocol/on_data';
|
|
65
66
|
import {
|
|
66
|
-
|
|
67
|
+
CursorResponse,
|
|
67
68
|
MongoDBResponse,
|
|
68
69
|
type MongoDBResponseConstructor
|
|
69
70
|
} from './wire_protocol/responses';
|
|
@@ -448,12 +449,7 @@ export class Connection extends TypedEventEmitter<ConnectionEvents> {
|
|
|
448
449
|
this.socket.setTimeout(0);
|
|
449
450
|
const bson = response.parse();
|
|
450
451
|
|
|
451
|
-
const document =
|
|
452
|
-
responseType == null
|
|
453
|
-
? new MongoDBResponse(bson)
|
|
454
|
-
: isErrorResponse(bson)
|
|
455
|
-
? new MongoDBResponse(bson)
|
|
456
|
-
: new responseType(bson);
|
|
452
|
+
const document = (responseType ?? MongoDBResponse).make(bson);
|
|
457
453
|
|
|
458
454
|
yield document;
|
|
459
455
|
this.throwIfAborted();
|
|
@@ -517,12 +513,7 @@ export class Connection extends TypedEventEmitter<ConnectionEvents> {
|
|
|
517
513
|
this.emit(Connection.CLUSTER_TIME_RECEIVED, document.$clusterTime);
|
|
518
514
|
}
|
|
519
515
|
|
|
520
|
-
if (document.
|
|
521
|
-
object ??= document.toObject(bsonOptions);
|
|
522
|
-
throw new MongoWriteConcernError(object.writeConcernError, object);
|
|
523
|
-
}
|
|
524
|
-
|
|
525
|
-
if (document.isError) {
|
|
516
|
+
if (document.ok === 0) {
|
|
526
517
|
throw new MongoServerError((object ??= document.toObject(bsonOptions)));
|
|
527
518
|
}
|
|
528
519
|
|
|
@@ -552,40 +543,25 @@ export class Connection extends TypedEventEmitter<ConnectionEvents> {
|
|
|
552
543
|
}
|
|
553
544
|
} catch (error) {
|
|
554
545
|
if (this.shouldEmitAndLogCommand) {
|
|
555
|
-
|
|
556
|
-
this.
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
this,
|
|
563
|
-
message,
|
|
564
|
-
options.noResponse ? undefined : (object ??= document?.toObject(bsonOptions)),
|
|
565
|
-
started,
|
|
566
|
-
this.description.serverConnectionId
|
|
567
|
-
)
|
|
568
|
-
);
|
|
569
|
-
} else {
|
|
570
|
-
this.emitAndLogCommand(
|
|
571
|
-
this.monitorCommands,
|
|
572
|
-
Connection.COMMAND_FAILED,
|
|
573
|
-
message.databaseName,
|
|
574
|
-
this.established,
|
|
575
|
-
new CommandFailedEvent(
|
|
576
|
-
this,
|
|
577
|
-
message,
|
|
578
|
-
error,
|
|
579
|
-
started,
|
|
580
|
-
this.description.serverConnectionId
|
|
581
|
-
)
|
|
582
|
-
);
|
|
583
|
-
}
|
|
546
|
+
this.emitAndLogCommand(
|
|
547
|
+
this.monitorCommands,
|
|
548
|
+
Connection.COMMAND_FAILED,
|
|
549
|
+
message.databaseName,
|
|
550
|
+
this.established,
|
|
551
|
+
new CommandFailedEvent(this, message, error, started, this.description.serverConnectionId)
|
|
552
|
+
);
|
|
584
553
|
}
|
|
585
554
|
throw error;
|
|
586
555
|
}
|
|
587
556
|
}
|
|
588
557
|
|
|
558
|
+
public async command<T extends MongoDBResponseConstructor>(
|
|
559
|
+
ns: MongoDBNamespace,
|
|
560
|
+
command: Document,
|
|
561
|
+
options: CommandOptions | undefined,
|
|
562
|
+
responseType: T
|
|
563
|
+
): Promise<InstanceType<T>>;
|
|
564
|
+
|
|
589
565
|
public async command<T extends MongoDBResponseConstructor>(
|
|
590
566
|
ns: MongoDBNamespace,
|
|
591
567
|
command: Document,
|
|
@@ -749,7 +725,7 @@ export class CryptoConnection extends Connection {
|
|
|
749
725
|
ns: MongoDBNamespace,
|
|
750
726
|
cmd: Document,
|
|
751
727
|
options?: CommandOptions,
|
|
752
|
-
|
|
728
|
+
responseType?: T | undefined
|
|
753
729
|
): Promise<Document> {
|
|
754
730
|
const { autoEncrypter } = this;
|
|
755
731
|
if (!autoEncrypter) {
|
|
@@ -763,7 +739,7 @@ export class CryptoConnection extends Connection {
|
|
|
763
739
|
const serverWireVersion = maxWireVersion(this);
|
|
764
740
|
if (serverWireVersion === 0) {
|
|
765
741
|
// This means the initial handshake hasn't happened yet
|
|
766
|
-
return await super.command<T>(ns, cmd, options,
|
|
742
|
+
return await super.command<T>(ns, cmd, options, responseType);
|
|
767
743
|
}
|
|
768
744
|
|
|
769
745
|
if (serverWireVersion < 8) {
|
|
@@ -797,8 +773,28 @@ export class CryptoConnection extends Connection {
|
|
|
797
773
|
}
|
|
798
774
|
}
|
|
799
775
|
|
|
800
|
-
const
|
|
776
|
+
const encryptedResponse = await super.command(
|
|
777
|
+
ns,
|
|
778
|
+
encrypted,
|
|
779
|
+
options,
|
|
780
|
+
// Eventually we want to require `responseType` which means we would satisfy `T` as the return type.
|
|
781
|
+
// In the meantime, we want encryptedResponse to always be _at least_ a MongoDBResponse if not a more specific subclass
|
|
782
|
+
// So that we can ensure we have access to the on-demand APIs for decorate response
|
|
783
|
+
responseType ?? MongoDBResponse
|
|
784
|
+
);
|
|
785
|
+
|
|
786
|
+
const result = await autoEncrypter.decrypt(encryptedResponse.toBytes(), options);
|
|
787
|
+
|
|
788
|
+
const decryptedResponse = responseType?.make(result) ?? deserialize(result, options);
|
|
789
|
+
|
|
790
|
+
if (autoEncrypter[kDecorateResult]) {
|
|
791
|
+
if (responseType == null) {
|
|
792
|
+
decorateDecryptionResult(decryptedResponse, encryptedResponse.toObject(), true);
|
|
793
|
+
} else if (decryptedResponse instanceof CursorResponse) {
|
|
794
|
+
decryptedResponse.encryptedResponse = encryptedResponse;
|
|
795
|
+
}
|
|
796
|
+
}
|
|
801
797
|
|
|
802
|
-
return
|
|
798
|
+
return decryptedResponse;
|
|
803
799
|
}
|
|
804
800
|
}
|
|
@@ -66,9 +66,11 @@ export class OnDemandDocument {
|
|
|
66
66
|
/** The start of the document */
|
|
67
67
|
private readonly offset = 0,
|
|
68
68
|
/** If this is an embedded document, indicates if this was a BSON array */
|
|
69
|
-
public readonly isArray = false
|
|
69
|
+
public readonly isArray = false,
|
|
70
|
+
/** If elements was already calculated */
|
|
71
|
+
elements?: BSONElement[]
|
|
70
72
|
) {
|
|
71
|
-
this.elements = parseToElementsToArray(this.bson, offset);
|
|
73
|
+
this.elements = elements ?? parseToElementsToArray(this.bson, offset);
|
|
72
74
|
}
|
|
73
75
|
|
|
74
76
|
/** Only supports basic latin strings */
|
|
@@ -78,8 +80,13 @@ export class OnDemandDocument {
|
|
|
78
80
|
|
|
79
81
|
if (name.length !== nameLength) return false;
|
|
80
82
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
+
const nameEnd = nameOffset + nameLength;
|
|
84
|
+
for (
|
|
85
|
+
let byteIndex = nameOffset, charIndex = 0;
|
|
86
|
+
charIndex < name.length && byteIndex < nameEnd;
|
|
87
|
+
charIndex++, byteIndex++
|
|
88
|
+
) {
|
|
89
|
+
if (this.bson[byteIndex] !== name.charCodeAt(charIndex)) return false;
|
|
83
90
|
}
|
|
84
91
|
|
|
85
92
|
return true;
|
|
@@ -125,7 +132,7 @@ export class OnDemandDocument {
|
|
|
125
132
|
const element = this.elements[index];
|
|
126
133
|
|
|
127
134
|
// skip this element if it has already been associated with a name
|
|
128
|
-
if (!this.indexFound
|
|
135
|
+
if (!(index in this.indexFound) && this.isElementName(name, element)) {
|
|
129
136
|
const cachedElement = { element, value: undefined };
|
|
130
137
|
this.cache[name] = cachedElement;
|
|
131
138
|
this.indexFound[index] = true;
|
|
@@ -247,7 +254,7 @@ export class OnDemandDocument {
|
|
|
247
254
|
public get<const T extends keyof JSTypeOf>(
|
|
248
255
|
name: string | number,
|
|
249
256
|
as: T,
|
|
250
|
-
required?:
|
|
257
|
+
required?: boolean | undefined
|
|
251
258
|
): JSTypeOf[T] | null;
|
|
252
259
|
|
|
253
260
|
/** `required` will make `get` throw if name does not exist or is null/undefined */
|