mongodb 6.7.0-dev.20240613.sha.c1af6adc → 6.7.0-dev.20240615.sha.465ffd97
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 +3 -3
- 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/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 +23 -10
- 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 +6 -9
- package/src/client-side-encryption/state_machine.ts +18 -16
- 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 +6 -7
- 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
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
|
|
7
7
|
import { deserialize, type Document, serialize } from '../bson';
|
|
8
8
|
import { type CommandOptions, type ProxyOptions } from '../cmap/connection';
|
|
9
|
+
import { kDecorateResult } from '../constants';
|
|
9
10
|
import { getMongoDBClientEncryption } from '../deps';
|
|
10
11
|
import { MongoRuntimeError } from '../error';
|
|
11
12
|
import { MongoClient, type MongoClientOptions } from '../mongo_client';
|
|
@@ -212,15 +213,6 @@ export const AutoEncryptionLoggerLevel = Object.freeze({
|
|
|
212
213
|
export type AutoEncryptionLoggerLevel =
|
|
213
214
|
(typeof AutoEncryptionLoggerLevel)[keyof typeof AutoEncryptionLoggerLevel];
|
|
214
215
|
|
|
215
|
-
// Typescript errors if we index objects with `Symbol.for(...)`, so
|
|
216
|
-
// to avoid TS errors we pull them out into variables. Then we can type
|
|
217
|
-
// the objects (and class) that we expect to see them on and prevent TS
|
|
218
|
-
// errors.
|
|
219
|
-
/** @internal */
|
|
220
|
-
const kDecorateResult = Symbol.for('@@mdb.decorateDecryptionResult');
|
|
221
|
-
/** @internal */
|
|
222
|
-
const kDecoratedKeys = Symbol.for('@@mdb.decryptedKeys');
|
|
223
|
-
|
|
224
216
|
/**
|
|
225
217
|
* @internal An internal class to be used by the driver for auto encryption
|
|
226
218
|
* **NOTE**: Not meant to be instantiated directly, this is for internal use only.
|
|
@@ -467,16 +459,18 @@ export class AutoEncrypter {
|
|
|
467
459
|
proxyOptions: this._proxyOptions,
|
|
468
460
|
tlsOptions: this._tlsOptions
|
|
469
461
|
});
|
|
470
|
-
|
|
462
|
+
|
|
463
|
+
return deserialize(await stateMachine.execute(this, context), {
|
|
464
|
+
promoteValues: false,
|
|
465
|
+
promoteLongs: false
|
|
466
|
+
});
|
|
471
467
|
}
|
|
472
468
|
|
|
473
469
|
/**
|
|
474
470
|
* Decrypt a command response
|
|
475
471
|
*/
|
|
476
|
-
async decrypt(response: Uint8Array
|
|
477
|
-
const
|
|
478
|
-
|
|
479
|
-
const context = this._mongocrypt.makeDecryptionContext(buffer);
|
|
472
|
+
async decrypt(response: Uint8Array, options: CommandOptions = {}): Promise<Uint8Array> {
|
|
473
|
+
const context = this._mongocrypt.makeDecryptionContext(response);
|
|
480
474
|
|
|
481
475
|
context.id = this._contextCounter++;
|
|
482
476
|
|
|
@@ -486,12 +480,7 @@ export class AutoEncrypter {
|
|
|
486
480
|
tlsOptions: this._tlsOptions
|
|
487
481
|
});
|
|
488
482
|
|
|
489
|
-
|
|
490
|
-
const result = await stateMachine.execute<Document>(this, context);
|
|
491
|
-
if (decorateResult) {
|
|
492
|
-
decorateDecryptionResult(result, response);
|
|
493
|
-
}
|
|
494
|
-
return result;
|
|
483
|
+
return await stateMachine.execute(this, context);
|
|
495
484
|
}
|
|
496
485
|
|
|
497
486
|
/**
|
|
@@ -518,53 +507,3 @@ export class AutoEncrypter {
|
|
|
518
507
|
return AutoEncrypter.getMongoCrypt().libmongocryptVersion;
|
|
519
508
|
}
|
|
520
509
|
}
|
|
521
|
-
|
|
522
|
-
/**
|
|
523
|
-
* Recurse through the (identically-shaped) `decrypted` and `original`
|
|
524
|
-
* objects and attach a `decryptedKeys` property on each sub-object that
|
|
525
|
-
* contained encrypted fields. Because we only call this on BSON responses,
|
|
526
|
-
* we do not need to worry about circular references.
|
|
527
|
-
*
|
|
528
|
-
* @internal
|
|
529
|
-
*/
|
|
530
|
-
function decorateDecryptionResult(
|
|
531
|
-
decrypted: Document & { [kDecoratedKeys]?: Array<string> },
|
|
532
|
-
original: Document,
|
|
533
|
-
isTopLevelDecorateCall = true
|
|
534
|
-
): void {
|
|
535
|
-
if (isTopLevelDecorateCall) {
|
|
536
|
-
// The original value could have been either a JS object or a BSON buffer
|
|
537
|
-
if (Buffer.isBuffer(original)) {
|
|
538
|
-
original = deserialize(original);
|
|
539
|
-
}
|
|
540
|
-
if (Buffer.isBuffer(decrypted)) {
|
|
541
|
-
throw new MongoRuntimeError('Expected result of decryption to be deserialized BSON object');
|
|
542
|
-
}
|
|
543
|
-
}
|
|
544
|
-
|
|
545
|
-
if (!decrypted || typeof decrypted !== 'object') return;
|
|
546
|
-
for (const k of Object.keys(decrypted)) {
|
|
547
|
-
const originalValue = original[k];
|
|
548
|
-
|
|
549
|
-
// An object was decrypted by libmongocrypt if and only if it was
|
|
550
|
-
// a BSON Binary object with subtype 6.
|
|
551
|
-
if (originalValue && originalValue._bsontype === 'Binary' && originalValue.sub_type === 6) {
|
|
552
|
-
if (!decrypted[kDecoratedKeys]) {
|
|
553
|
-
Object.defineProperty(decrypted, kDecoratedKeys, {
|
|
554
|
-
value: [],
|
|
555
|
-
configurable: true,
|
|
556
|
-
enumerable: false,
|
|
557
|
-
writable: false
|
|
558
|
-
});
|
|
559
|
-
}
|
|
560
|
-
// this is defined in the preceding if-statement
|
|
561
|
-
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
562
|
-
decrypted[kDecoratedKeys]!.push(k);
|
|
563
|
-
// Do not recurse into this decrypted value. It could be a sub-document/array,
|
|
564
|
-
// in which case there is no original value associated with its subfields.
|
|
565
|
-
continue;
|
|
566
|
-
}
|
|
567
|
-
|
|
568
|
-
decorateDecryptionResult(decrypted[k], originalValue, false);
|
|
569
|
-
}
|
|
570
|
-
}
|
|
@@ -5,7 +5,7 @@ import type {
|
|
|
5
5
|
MongoCryptOptions
|
|
6
6
|
} from 'mongodb-client-encryption';
|
|
7
7
|
|
|
8
|
-
import { type Binary, type Document, type Long, serialize, type UUID } from '../bson';
|
|
8
|
+
import { type Binary, deserialize, type Document, type Long, serialize, type UUID } from '../bson';
|
|
9
9
|
import { type AnyBulkWriteOperation, type BulkWriteResult } from '../bulk/common';
|
|
10
10
|
import { type ProxyOptions } from '../cmap/connection';
|
|
11
11
|
import { type Collection } from '../collection';
|
|
@@ -202,7 +202,7 @@ export class ClientEncryption {
|
|
|
202
202
|
tlsOptions: this._tlsOptions
|
|
203
203
|
});
|
|
204
204
|
|
|
205
|
-
const dataKey = await stateMachine.execute
|
|
205
|
+
const dataKey = deserialize(await stateMachine.execute(this, context)) as DataKey;
|
|
206
206
|
|
|
207
207
|
const { db: dbName, collection: collectionName } = MongoDBCollectionNamespace.fromString(
|
|
208
208
|
this._keyVaultNamespace
|
|
@@ -259,7 +259,7 @@ export class ClientEncryption {
|
|
|
259
259
|
tlsOptions: this._tlsOptions
|
|
260
260
|
});
|
|
261
261
|
|
|
262
|
-
const { v: dataKeys } = await stateMachine.execute
|
|
262
|
+
const { v: dataKeys } = deserialize(await stateMachine.execute(this, context));
|
|
263
263
|
if (dataKeys.length === 0) {
|
|
264
264
|
return {};
|
|
265
265
|
}
|
|
@@ -640,7 +640,7 @@ export class ClientEncryption {
|
|
|
640
640
|
tlsOptions: this._tlsOptions
|
|
641
641
|
});
|
|
642
642
|
|
|
643
|
-
const { v } = await stateMachine.execute
|
|
643
|
+
const { v } = deserialize(await stateMachine.execute(this, context));
|
|
644
644
|
|
|
645
645
|
return v;
|
|
646
646
|
}
|
|
@@ -719,8 +719,8 @@ export class ClientEncryption {
|
|
|
719
719
|
});
|
|
720
720
|
const context = this._mongoCrypt.makeExplicitEncryptionContext(valueBuffer, contextOptions);
|
|
721
721
|
|
|
722
|
-
const
|
|
723
|
-
return
|
|
722
|
+
const { v } = deserialize(await stateMachine.execute(this, context));
|
|
723
|
+
return v;
|
|
724
724
|
}
|
|
725
725
|
}
|
|
726
726
|
|
|
@@ -12,7 +12,7 @@ import { loadGCPCredentials } from './gcp';
|
|
|
12
12
|
* `aws:<name>`, `gcp:<name>`, `local:<name>`, `kmip:<name>`, `azure:<name>`
|
|
13
13
|
* where `name` is an alphanumeric string, underscores allowed.
|
|
14
14
|
*/
|
|
15
|
-
export type ClientEncryptionDataKeyProvider =
|
|
15
|
+
export type ClientEncryptionDataKeyProvider = keyof KMSProviders;
|
|
16
16
|
|
|
17
17
|
/** @public */
|
|
18
18
|
export interface AWSKMSProviderConfiguration {
|
|
@@ -122,34 +122,31 @@ export interface KMSProviders {
|
|
|
122
122
|
* Configuration options for using 'aws' as your KMS provider
|
|
123
123
|
*/
|
|
124
124
|
aws?: AWSKMSProviderConfiguration | Record<string, never>;
|
|
125
|
+
[key: `aws:${string}`]: AWSKMSProviderConfiguration;
|
|
125
126
|
|
|
126
127
|
/**
|
|
127
128
|
* Configuration options for using 'local' as your KMS provider
|
|
128
129
|
*/
|
|
129
130
|
local?: LocalKMSProviderConfiguration;
|
|
131
|
+
[key: `local:${string}`]: LocalKMSProviderConfiguration;
|
|
130
132
|
|
|
131
133
|
/**
|
|
132
134
|
* Configuration options for using 'kmip' as your KMS provider
|
|
133
135
|
*/
|
|
134
136
|
kmip?: KMIPKMSProviderConfiguration;
|
|
137
|
+
[key: `kmip:${string}`]: KMIPKMSProviderConfiguration;
|
|
135
138
|
|
|
136
139
|
/**
|
|
137
140
|
* Configuration options for using 'azure' as your KMS provider
|
|
138
141
|
*/
|
|
139
142
|
azure?: AzureKMSProviderConfiguration | Record<string, never>;
|
|
143
|
+
[key: `azure:${string}`]: AzureKMSProviderConfiguration;
|
|
140
144
|
|
|
141
145
|
/**
|
|
142
146
|
* Configuration options for using 'gcp' as your KMS provider
|
|
143
147
|
*/
|
|
144
148
|
gcp?: GCPKMSProviderConfiguration | Record<string, never>;
|
|
145
|
-
|
|
146
|
-
[key: string]:
|
|
147
|
-
| AWSKMSProviderConfiguration
|
|
148
|
-
| LocalKMSProviderConfiguration
|
|
149
|
-
| KMIPKMSProviderConfiguration
|
|
150
|
-
| AzureKMSProviderConfiguration
|
|
151
|
-
| GCPKMSProviderConfiguration
|
|
152
|
-
| undefined;
|
|
149
|
+
[key: `gcp:${string}`]: GCPKMSProviderConfiguration;
|
|
153
150
|
}
|
|
154
151
|
|
|
155
152
|
/**
|
|
@@ -114,6 +114,19 @@ export type CSFLEKMSTlsOptions = {
|
|
|
114
114
|
[key: string]: ClientEncryptionTlsOptions | undefined;
|
|
115
115
|
};
|
|
116
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
|
+
|
|
117
130
|
/**
|
|
118
131
|
* @internal
|
|
119
132
|
*
|
|
@@ -156,16 +169,13 @@ export class StateMachine {
|
|
|
156
169
|
/**
|
|
157
170
|
* Executes the state machine according to the specification
|
|
158
171
|
*/
|
|
159
|
-
async execute
|
|
160
|
-
executor: StateMachineExecutable,
|
|
161
|
-
context: MongoCryptContext
|
|
162
|
-
): Promise<T> {
|
|
172
|
+
async execute(executor: StateMachineExecutable, context: MongoCryptContext): Promise<Uint8Array> {
|
|
163
173
|
const keyVaultNamespace = executor._keyVaultNamespace;
|
|
164
174
|
const keyVaultClient = executor._keyVaultClient;
|
|
165
175
|
const metaDataClient = executor._metaDataClient;
|
|
166
176
|
const mongocryptdClient = executor._mongocryptdClient;
|
|
167
177
|
const mongocryptdManager = executor._mongocryptdManager;
|
|
168
|
-
let result:
|
|
178
|
+
let result: Uint8Array | null = null;
|
|
169
179
|
|
|
170
180
|
while (context.state !== MONGOCRYPT_CTX_DONE && context.state !== MONGOCRYPT_CTX_ERROR) {
|
|
171
181
|
debug(`[context#${context.id}] ${stateToString.get(context.state) || context.state}`);
|
|
@@ -213,16 +223,8 @@ export class StateMachine {
|
|
|
213
223
|
const keys = await this.fetchKeys(keyVaultClient, keyVaultNamespace, filter);
|
|
214
224
|
|
|
215
225
|
if (keys.length === 0) {
|
|
216
|
-
//
|
|
217
|
-
|
|
218
|
-
// nothing. We also have tests for auto encryption that guarantee for `encrypt`
|
|
219
|
-
// we return an error when there are no matching keys. This error is generated in
|
|
220
|
-
// subsequent iterations of the state machine.
|
|
221
|
-
// Some apis (`encrypt`) throw if there are no filter matches and others (`rewrapManyDataKey`)
|
|
222
|
-
// do not. We set the result manually here, and let the state machine continue. `libmongocrypt`
|
|
223
|
-
// will inform us if we need to error by setting the state to `MONGOCRYPT_CTX_ERROR` but
|
|
224
|
-
// otherwise we'll return `{ v: [] }`.
|
|
225
|
-
result = { v: [] } as any as T;
|
|
226
|
+
// See docs on EMPTY_V
|
|
227
|
+
result = EMPTY_V ??= serialize({ v: [] });
|
|
226
228
|
}
|
|
227
229
|
for await (const key of keys) {
|
|
228
230
|
context.addMongoOperationResponse(serialize(key));
|
|
@@ -254,7 +256,7 @@ export class StateMachine {
|
|
|
254
256
|
const message = context.status.message || 'Finalization error';
|
|
255
257
|
throw new MongoCryptError(message);
|
|
256
258
|
}
|
|
257
|
-
result =
|
|
259
|
+
result = finalizedContext;
|
|
258
260
|
break;
|
|
259
261
|
}
|
|
260
262
|
|
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 */
|