mongodb 6.10.0-dev.20241106.sha.dc3fe957 → 6.10.0-dev.20241108.sha.fd7acde6
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/admin.js +3 -2
- package/lib/admin.js.map +1 -1
- package/lib/beta.d.ts +558 -40
- package/lib/bulk/common.js +4 -4
- package/lib/bulk/common.js.map +1 -1
- package/lib/change_stream.js +111 -51
- package/lib/change_stream.js.map +1 -1
- package/lib/client-side-encryption/auto_encrypter.js +8 -5
- package/lib/client-side-encryption/auto_encrypter.js.map +1 -1
- package/lib/client-side-encryption/client_encryption.js +48 -18
- package/lib/client-side-encryption/client_encryption.js.map +1 -1
- package/lib/client-side-encryption/state_machine.js +43 -29
- package/lib/client-side-encryption/state_machine.js.map +1 -1
- package/lib/cmap/auth/mongo_credentials.js +2 -1
- package/lib/cmap/auth/mongo_credentials.js.map +1 -1
- package/lib/cmap/auth/mongodb_oidc/k8s_machine_workflow.js +38 -0
- package/lib/cmap/auth/mongodb_oidc/k8s_machine_workflow.js.map +1 -0
- package/lib/cmap/auth/mongodb_oidc.js +2 -0
- package/lib/cmap/auth/mongodb_oidc.js.map +1 -1
- package/lib/cmap/connection.js +78 -6
- package/lib/cmap/connection.js.map +1 -1
- package/lib/cmap/connection_pool.js +14 -9
- package/lib/cmap/connection_pool.js.map +1 -1
- package/lib/cmap/wire_protocol/on_data.js +5 -1
- package/lib/cmap/wire_protocol/on_data.js.map +1 -1
- package/lib/cmap/wire_protocol/responses.js +30 -0
- package/lib/cmap/wire_protocol/responses.js.map +1 -1
- package/lib/collection.js +62 -3
- package/lib/collection.js.map +1 -1
- package/lib/connection_string.js +2 -0
- package/lib/connection_string.js.map +1 -1
- package/lib/cursor/abstract_cursor.js +218 -38
- package/lib/cursor/abstract_cursor.js.map +1 -1
- package/lib/cursor/aggregation_cursor.js +29 -7
- package/lib/cursor/aggregation_cursor.js.map +1 -1
- package/lib/cursor/change_stream_cursor.js +2 -2
- package/lib/cursor/change_stream_cursor.js.map +1 -1
- package/lib/cursor/client_bulk_write_cursor.js +1 -1
- package/lib/cursor/client_bulk_write_cursor.js.map +1 -1
- package/lib/cursor/find_cursor.js +18 -8
- package/lib/cursor/find_cursor.js.map +1 -1
- package/lib/cursor/list_collections_cursor.js +1 -1
- package/lib/cursor/list_collections_cursor.js.map +1 -1
- package/lib/cursor/list_indexes_cursor.js +1 -1
- package/lib/cursor/list_indexes_cursor.js.map +1 -1
- package/lib/cursor/run_command_cursor.js +6 -4
- package/lib/cursor/run_command_cursor.js.map +1 -1
- package/lib/db.js +63 -3
- package/lib/db.js.map +1 -1
- package/lib/error.js +27 -2
- package/lib/error.js.map +1 -1
- package/lib/explain.js +57 -1
- package/lib/explain.js.map +1 -1
- package/lib/gridfs/download.js +31 -3
- package/lib/gridfs/download.js.map +1 -1
- package/lib/gridfs/index.js +49 -14
- package/lib/gridfs/index.js.map +1 -1
- package/lib/gridfs/upload.js +80 -22
- package/lib/gridfs/upload.js.map +1 -1
- package/lib/index.js +9 -5
- package/lib/index.js.map +1 -1
- package/lib/mongo_client.js +70 -1
- package/lib/mongo_client.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 +7 -2
- package/lib/operations/bulk_write.js.map +1 -1
- package/lib/operations/client_bulk_write/client_bulk_write.js +3 -3
- package/lib/operations/client_bulk_write/client_bulk_write.js.map +1 -1
- package/lib/operations/client_bulk_write/executor.js +14 -3
- package/lib/operations/client_bulk_write/executor.js.map +1 -1
- package/lib/operations/command.js +5 -2
- package/lib/operations/command.js.map +1 -1
- package/lib/operations/count.js +2 -2
- package/lib/operations/count.js.map +1 -1
- package/lib/operations/create_collection.js +8 -7
- 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 +2 -2
- package/lib/operations/distinct.js.map +1 -1
- package/lib/operations/drop.js +8 -8
- 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/execute_operation.js +16 -10
- package/lib/operations/execute_operation.js.map +1 -1
- package/lib/operations/find.js +6 -3
- package/lib/operations/find.js.map +1 -1
- package/lib/operations/find_and_modify.js +2 -2
- package/lib/operations/find_and_modify.js.map +1 -1
- package/lib/operations/get_more.js +2 -1
- package/lib/operations/get_more.js.map +1 -1
- package/lib/operations/indexes.js +6 -6
- package/lib/operations/indexes.js.map +1 -1
- package/lib/operations/insert.js +6 -6
- package/lib/operations/insert.js.map +1 -1
- package/lib/operations/kill_cursors.js +5 -2
- package/lib/operations/kill_cursors.js.map +1 -1
- package/lib/operations/list_collections.js +2 -2
- package/lib/operations/list_collections.js.map +1 -1
- package/lib/operations/list_databases.js +2 -2
- package/lib/operations/list_databases.js.map +1 -1
- package/lib/operations/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 +2 -2
- 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/run_command.js +6 -4
- package/lib/operations/run_command.js.map +1 -1
- package/lib/operations/search_indexes/create.js +5 -2
- package/lib/operations/search_indexes/create.js.map +1 -1
- package/lib/operations/search_indexes/drop.js +2 -2
- package/lib/operations/search_indexes/drop.js.map +1 -1
- package/lib/operations/search_indexes/update.js +2 -2
- package/lib/operations/search_indexes/update.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 +8 -8
- package/lib/operations/update.js.map +1 -1
- package/lib/operations/validate_collection.js +2 -2
- package/lib/operations/validate_collection.js.map +1 -1
- package/lib/sdam/common.js +0 -7
- package/lib/sdam/common.js.map +1 -1
- package/lib/sdam/server.js +4 -1
- package/lib/sdam/server.js.map +1 -1
- package/lib/sdam/server_description.js +2 -0
- package/lib/sdam/server_description.js.map +1 -1
- package/lib/sdam/topology.js +38 -15
- package/lib/sdam/topology.js.map +1 -1
- package/lib/sessions.js +145 -74
- package/lib/sessions.js.map +1 -1
- package/lib/timeout.js +217 -16
- package/lib/timeout.js.map +1 -1
- package/lib/utils.js +31 -17
- package/lib/utils.js.map +1 -1
- package/lib/write_concern.js.map +1 -1
- package/mongodb.d.ts +558 -40
- package/package.json +3 -2
- package/src/admin.ts +6 -2
- package/src/bulk/common.ts +17 -5
- package/src/change_stream.ts +127 -52
- package/src/client-side-encryption/auto_encrypter.ts +12 -5
- package/src/client-side-encryption/client_encryption.ts +103 -20
- package/src/client-side-encryption/state_machine.ts +66 -32
- package/src/cmap/auth/mongo_credentials.ts +3 -2
- package/src/cmap/auth/mongodb_oidc/k8s_machine_workflow.ts +38 -0
- package/src/cmap/auth/mongodb_oidc.ts +3 -1
- package/src/cmap/connection.ts +105 -8
- package/src/cmap/connection_pool.ts +14 -14
- package/src/cmap/wire_protocol/on_data.ts +11 -1
- package/src/cmap/wire_protocol/responses.ts +35 -1
- package/src/collection.ts +81 -9
- package/src/connection_string.ts +2 -0
- package/src/cursor/abstract_cursor.ts +286 -39
- package/src/cursor/aggregation_cursor.ts +54 -8
- package/src/cursor/change_stream_cursor.ts +6 -2
- package/src/cursor/client_bulk_write_cursor.ts +6 -2
- package/src/cursor/find_cursor.ts +40 -9
- package/src/cursor/list_collections_cursor.ts +1 -1
- package/src/cursor/list_indexes_cursor.ts +1 -1
- package/src/cursor/run_command_cursor.ts +50 -5
- package/src/db.ts +75 -7
- package/src/error.ts +26 -1
- package/src/explain.ts +85 -0
- package/src/gridfs/download.ts +43 -4
- package/src/gridfs/index.ts +64 -16
- package/src/gridfs/upload.ts +152 -45
- package/src/index.ts +27 -5
- package/src/mongo_client.ts +75 -3
- package/src/operations/aggregate.ts +10 -2
- package/src/operations/bulk_write.ts +9 -2
- package/src/operations/client_bulk_write/client_bulk_write.ts +11 -3
- package/src/operations/client_bulk_write/executor.ts +15 -3
- package/src/operations/command.ts +18 -8
- package/src/operations/count.ts +10 -3
- package/src/operations/create_collection.ts +14 -7
- package/src/operations/delete.ts +15 -6
- package/src/operations/distinct.ts +7 -2
- package/src/operations/drop.ts +18 -8
- package/src/operations/estimated_document_count.ts +7 -2
- package/src/operations/execute_operation.ts +22 -13
- package/src/operations/find.ts +17 -5
- package/src/operations/find_and_modify.ts +7 -2
- package/src/operations/get_more.ts +4 -1
- package/src/operations/indexes.ts +20 -7
- package/src/operations/insert.ts +13 -6
- package/src/operations/kill_cursors.ts +10 -2
- package/src/operations/list_collections.ts +10 -1
- package/src/operations/list_databases.ts +9 -2
- package/src/operations/operation.ts +16 -2
- package/src/operations/profiling_level.ts +7 -2
- package/src/operations/remove_user.ts +7 -2
- package/src/operations/rename.ts +7 -2
- package/src/operations/run_command.ts +23 -4
- package/src/operations/search_indexes/create.ts +10 -2
- package/src/operations/search_indexes/drop.ts +7 -2
- package/src/operations/search_indexes/update.ts +7 -2
- package/src/operations/set_profiling_level.ts +4 -2
- package/src/operations/stats.ts +7 -2
- package/src/operations/update.ts +16 -8
- package/src/operations/validate_collection.ts +7 -2
- package/src/sdam/common.ts +0 -11
- package/src/sdam/server.ts +14 -4
- package/src/sdam/server_description.ts +4 -0
- package/src/sdam/topology.ts +43 -27
- package/src/sessions.ts +193 -89
- package/src/timeout.ts +310 -23
- package/src/transactions.ts +1 -1
- package/src/utils.ts +42 -28
- package/src/write_concern.ts +6 -3
|
@@ -24,7 +24,8 @@ import { type MongoClient, type MongoClientOptions } from '../mongo_client';
|
|
|
24
24
|
import { type Filter, type WithId } from '../mongo_types';
|
|
25
25
|
import { type CreateCollectionOptions } from '../operations/create_collection';
|
|
26
26
|
import { type DeleteResult } from '../operations/delete';
|
|
27
|
-
import {
|
|
27
|
+
import { type CSOTTimeoutContext, TimeoutContext } from '../timeout';
|
|
28
|
+
import { MongoDBCollectionNamespace, resolveTimeoutOptions } from '../utils';
|
|
28
29
|
import * as cryptoCallbacks from './crypto_callbacks';
|
|
29
30
|
import {
|
|
30
31
|
MongoCryptCreateDataKeyError,
|
|
@@ -74,6 +75,8 @@ export class ClientEncryption {
|
|
|
74
75
|
_tlsOptions: CSFLEKMSTlsOptions;
|
|
75
76
|
/** @internal */
|
|
76
77
|
_kmsProviders: KMSProviders;
|
|
78
|
+
/** @internal */
|
|
79
|
+
_timeoutMS?: number;
|
|
77
80
|
|
|
78
81
|
/** @internal */
|
|
79
82
|
_mongoCrypt: MongoCrypt;
|
|
@@ -120,6 +123,8 @@ export class ClientEncryption {
|
|
|
120
123
|
this._proxyOptions = options.proxyOptions ?? {};
|
|
121
124
|
this._tlsOptions = options.tlsOptions ?? {};
|
|
122
125
|
this._kmsProviders = options.kmsProviders || {};
|
|
126
|
+
const { timeoutMS } = resolveTimeoutOptions(client, options);
|
|
127
|
+
this._timeoutMS = timeoutMS;
|
|
123
128
|
|
|
124
129
|
if (options.keyVaultNamespace == null) {
|
|
125
130
|
throw new MongoCryptInvalidArgumentError('Missing required option `keyVaultNamespace`');
|
|
@@ -212,10 +217,16 @@ export class ClientEncryption {
|
|
|
212
217
|
const stateMachine = new StateMachine({
|
|
213
218
|
proxyOptions: this._proxyOptions,
|
|
214
219
|
tlsOptions: this._tlsOptions,
|
|
215
|
-
socketOptions: autoSelectSocketOptions(this._client.options)
|
|
220
|
+
socketOptions: autoSelectSocketOptions(this._client.s.options)
|
|
216
221
|
});
|
|
217
222
|
|
|
218
|
-
const
|
|
223
|
+
const timeoutContext =
|
|
224
|
+
options?.timeoutContext ??
|
|
225
|
+
TimeoutContext.create(resolveTimeoutOptions(this._client, { timeoutMS: this._timeoutMS }));
|
|
226
|
+
|
|
227
|
+
const dataKey = deserialize(
|
|
228
|
+
await stateMachine.execute(this, context, timeoutContext)
|
|
229
|
+
) as DataKey;
|
|
219
230
|
|
|
220
231
|
const { db: dbName, collection: collectionName } = MongoDBCollectionNamespace.fromString(
|
|
221
232
|
this._keyVaultNamespace
|
|
@@ -224,7 +235,12 @@ export class ClientEncryption {
|
|
|
224
235
|
const { insertedId } = await this._keyVaultClient
|
|
225
236
|
.db(dbName)
|
|
226
237
|
.collection<DataKey>(collectionName)
|
|
227
|
-
.insertOne(dataKey, {
|
|
238
|
+
.insertOne(dataKey, {
|
|
239
|
+
writeConcern: { w: 'majority' },
|
|
240
|
+
timeoutMS: timeoutContext?.csotEnabled()
|
|
241
|
+
? timeoutContext?.getRemainingTimeMSOrThrow()
|
|
242
|
+
: undefined
|
|
243
|
+
});
|
|
228
244
|
|
|
229
245
|
return insertedId;
|
|
230
246
|
}
|
|
@@ -270,10 +286,14 @@ export class ClientEncryption {
|
|
|
270
286
|
const stateMachine = new StateMachine({
|
|
271
287
|
proxyOptions: this._proxyOptions,
|
|
272
288
|
tlsOptions: this._tlsOptions,
|
|
273
|
-
socketOptions: autoSelectSocketOptions(this._client.options)
|
|
289
|
+
socketOptions: autoSelectSocketOptions(this._client.s.options)
|
|
274
290
|
});
|
|
275
291
|
|
|
276
|
-
const
|
|
292
|
+
const timeoutContext = TimeoutContext.create(
|
|
293
|
+
resolveTimeoutOptions(this._client, { timeoutMS: this._timeoutMS })
|
|
294
|
+
);
|
|
295
|
+
|
|
296
|
+
const { v: dataKeys } = deserialize(await stateMachine.execute(this, context, timeoutContext));
|
|
277
297
|
if (dataKeys.length === 0) {
|
|
278
298
|
return {};
|
|
279
299
|
}
|
|
@@ -303,7 +323,8 @@ export class ClientEncryption {
|
|
|
303
323
|
.db(dbName)
|
|
304
324
|
.collection<DataKey>(collectionName)
|
|
305
325
|
.bulkWrite(replacements, {
|
|
306
|
-
writeConcern: { w: 'majority' }
|
|
326
|
+
writeConcern: { w: 'majority' },
|
|
327
|
+
timeoutMS: timeoutContext.csotEnabled() ? timeoutContext?.remainingTimeMS : undefined
|
|
307
328
|
});
|
|
308
329
|
|
|
309
330
|
return { bulkWriteResult: result };
|
|
@@ -332,7 +353,7 @@ export class ClientEncryption {
|
|
|
332
353
|
return await this._keyVaultClient
|
|
333
354
|
.db(dbName)
|
|
334
355
|
.collection<DataKey>(collectionName)
|
|
335
|
-
.deleteOne({ _id }, { writeConcern: { w: 'majority' } });
|
|
356
|
+
.deleteOne({ _id }, { writeConcern: { w: 'majority' }, timeoutMS: this._timeoutMS });
|
|
336
357
|
}
|
|
337
358
|
|
|
338
359
|
/**
|
|
@@ -355,7 +376,7 @@ export class ClientEncryption {
|
|
|
355
376
|
return this._keyVaultClient
|
|
356
377
|
.db(dbName)
|
|
357
378
|
.collection<DataKey>(collectionName)
|
|
358
|
-
.find({}, { readConcern: { level: 'majority' } });
|
|
379
|
+
.find({}, { readConcern: { level: 'majority' }, timeoutMS: this._timeoutMS });
|
|
359
380
|
}
|
|
360
381
|
|
|
361
382
|
/**
|
|
@@ -381,7 +402,7 @@ export class ClientEncryption {
|
|
|
381
402
|
return await this._keyVaultClient
|
|
382
403
|
.db(dbName)
|
|
383
404
|
.collection<DataKey>(collectionName)
|
|
384
|
-
.findOne({ _id }, { readConcern: { level: 'majority' } });
|
|
405
|
+
.findOne({ _id }, { readConcern: { level: 'majority' }, timeoutMS: this._timeoutMS });
|
|
385
406
|
}
|
|
386
407
|
|
|
387
408
|
/**
|
|
@@ -408,7 +429,10 @@ export class ClientEncryption {
|
|
|
408
429
|
return await this._keyVaultClient
|
|
409
430
|
.db(dbName)
|
|
410
431
|
.collection<DataKey>(collectionName)
|
|
411
|
-
.findOne(
|
|
432
|
+
.findOne(
|
|
433
|
+
{ keyAltNames: keyAltName },
|
|
434
|
+
{ readConcern: { level: 'majority' }, timeoutMS: this._timeoutMS }
|
|
435
|
+
);
|
|
412
436
|
}
|
|
413
437
|
|
|
414
438
|
/**
|
|
@@ -442,7 +466,7 @@ export class ClientEncryption {
|
|
|
442
466
|
.findOneAndUpdate(
|
|
443
467
|
{ _id },
|
|
444
468
|
{ $addToSet: { keyAltNames: keyAltName } },
|
|
445
|
-
{ writeConcern: { w: 'majority' }, returnDocument: 'before' }
|
|
469
|
+
{ writeConcern: { w: 'majority' }, returnDocument: 'before', timeoutMS: this._timeoutMS }
|
|
446
470
|
);
|
|
447
471
|
|
|
448
472
|
return value;
|
|
@@ -498,12 +522,14 @@ export class ClientEncryption {
|
|
|
498
522
|
}
|
|
499
523
|
}
|
|
500
524
|
];
|
|
525
|
+
|
|
501
526
|
const value = await this._keyVaultClient
|
|
502
527
|
.db(dbName)
|
|
503
528
|
.collection<DataKey>(collectionName)
|
|
504
529
|
.findOneAndUpdate({ _id }, pipeline, {
|
|
505
530
|
writeConcern: { w: 'majority' },
|
|
506
|
-
returnDocument: 'before'
|
|
531
|
+
returnDocument: 'before',
|
|
532
|
+
timeoutMS: this._timeoutMS
|
|
507
533
|
});
|
|
508
534
|
|
|
509
535
|
return value;
|
|
@@ -541,16 +567,25 @@ export class ClientEncryption {
|
|
|
541
567
|
}
|
|
542
568
|
} = options;
|
|
543
569
|
|
|
570
|
+
const timeoutContext =
|
|
571
|
+
this._timeoutMS != null
|
|
572
|
+
? TimeoutContext.create(resolveTimeoutOptions(this._client, { timeoutMS: this._timeoutMS }))
|
|
573
|
+
: undefined;
|
|
574
|
+
|
|
544
575
|
if (Array.isArray(encryptedFields.fields)) {
|
|
545
576
|
const createDataKeyPromises = encryptedFields.fields.map(async field =>
|
|
546
577
|
field == null || typeof field !== 'object' || field.keyId != null
|
|
547
578
|
? field
|
|
548
579
|
: {
|
|
549
580
|
...field,
|
|
550
|
-
keyId: await this.createDataKey(provider, {
|
|
581
|
+
keyId: await this.createDataKey(provider, {
|
|
582
|
+
masterKey,
|
|
583
|
+
// clone the timeoutContext
|
|
584
|
+
// in order to avoid sharing the same timeout for server selection and connection checkout across different concurrent operations
|
|
585
|
+
timeoutContext: timeoutContext?.csotEnabled() ? timeoutContext?.clone() : undefined
|
|
586
|
+
})
|
|
551
587
|
}
|
|
552
588
|
);
|
|
553
|
-
|
|
554
589
|
const createDataKeyResolutions = await Promise.allSettled(createDataKeyPromises);
|
|
555
590
|
|
|
556
591
|
encryptedFields.fields = createDataKeyResolutions.map((resolution, index) =>
|
|
@@ -568,7 +603,10 @@ export class ClientEncryption {
|
|
|
568
603
|
try {
|
|
569
604
|
const collection = await db.createCollection<TSchema>(name, {
|
|
570
605
|
...createCollectionOptions,
|
|
571
|
-
encryptedFields
|
|
606
|
+
encryptedFields,
|
|
607
|
+
timeoutMS: timeoutContext?.csotEnabled()
|
|
608
|
+
? timeoutContext?.getRemainingTimeMSOrThrow()
|
|
609
|
+
: undefined
|
|
572
610
|
});
|
|
573
611
|
return { collection, encryptedFields };
|
|
574
612
|
} catch (cause) {
|
|
@@ -650,10 +688,15 @@ export class ClientEncryption {
|
|
|
650
688
|
const stateMachine = new StateMachine({
|
|
651
689
|
proxyOptions: this._proxyOptions,
|
|
652
690
|
tlsOptions: this._tlsOptions,
|
|
653
|
-
socketOptions: autoSelectSocketOptions(this._client.options)
|
|
691
|
+
socketOptions: autoSelectSocketOptions(this._client.s.options)
|
|
654
692
|
});
|
|
655
693
|
|
|
656
|
-
const
|
|
694
|
+
const timeoutContext =
|
|
695
|
+
this._timeoutMS != null
|
|
696
|
+
? TimeoutContext.create(resolveTimeoutOptions(this._client, { timeoutMS: this._timeoutMS }))
|
|
697
|
+
: undefined;
|
|
698
|
+
|
|
699
|
+
const { v } = deserialize(await stateMachine.execute(this, context, timeoutContext));
|
|
657
700
|
|
|
658
701
|
return v;
|
|
659
702
|
}
|
|
@@ -729,11 +772,15 @@ export class ClientEncryption {
|
|
|
729
772
|
const stateMachine = new StateMachine({
|
|
730
773
|
proxyOptions: this._proxyOptions,
|
|
731
774
|
tlsOptions: this._tlsOptions,
|
|
732
|
-
socketOptions: autoSelectSocketOptions(this._client.options)
|
|
775
|
+
socketOptions: autoSelectSocketOptions(this._client.s.options)
|
|
733
776
|
});
|
|
734
777
|
const context = this._mongoCrypt.makeExplicitEncryptionContext(valueBuffer, contextOptions);
|
|
735
778
|
|
|
736
|
-
const
|
|
779
|
+
const timeoutContext =
|
|
780
|
+
this._timeoutMS != null
|
|
781
|
+
? TimeoutContext.create(resolveTimeoutOptions(this._client, { timeoutMS: this._timeoutMS }))
|
|
782
|
+
: undefined;
|
|
783
|
+
const { v } = deserialize(await stateMachine.execute(this, context, timeoutContext));
|
|
737
784
|
return v;
|
|
738
785
|
}
|
|
739
786
|
}
|
|
@@ -818,6 +865,39 @@ export interface ClientEncryptionOptions {
|
|
|
818
865
|
* TLS options for kms providers to use.
|
|
819
866
|
*/
|
|
820
867
|
tlsOptions?: CSFLEKMSTlsOptions;
|
|
868
|
+
|
|
869
|
+
/**
|
|
870
|
+
* @experimental
|
|
871
|
+
*
|
|
872
|
+
* The timeout setting to be used for all the operations on ClientEncryption.
|
|
873
|
+
*
|
|
874
|
+
* When provided, `timeoutMS` is used as the timeout for each operation executed on
|
|
875
|
+
* the ClientEncryption object. For example:
|
|
876
|
+
*
|
|
877
|
+
* ```typescript
|
|
878
|
+
* const clientEncryption = new ClientEncryption(client, {
|
|
879
|
+
* timeoutMS: 1_000
|
|
880
|
+
* kmsProviders: { local: { key: '<KEY>' } }
|
|
881
|
+
* });
|
|
882
|
+
*
|
|
883
|
+
* // `1_000` is used as the timeout for createDataKey call
|
|
884
|
+
* await clientEncryption.createDataKey('local');
|
|
885
|
+
* ```
|
|
886
|
+
*
|
|
887
|
+
* If `timeoutMS` is configured on the provided client, the client's `timeoutMS` value
|
|
888
|
+
* will be used unless `timeoutMS` is also provided as a client encryption option.
|
|
889
|
+
*
|
|
890
|
+
* ```typescript
|
|
891
|
+
* const client = new MongoClient('<uri>', { timeoutMS: 2_000 });
|
|
892
|
+
*
|
|
893
|
+
* // timeoutMS is set to 1_000 on clientEncryption
|
|
894
|
+
* const clientEncryption = new ClientEncryption(client, {
|
|
895
|
+
* timeoutMS: 1_000
|
|
896
|
+
* kmsProviders: { local: { key: '<KEY>' } }
|
|
897
|
+
* });
|
|
898
|
+
* ```
|
|
899
|
+
*/
|
|
900
|
+
timeoutMS?: number;
|
|
821
901
|
}
|
|
822
902
|
|
|
823
903
|
/**
|
|
@@ -946,6 +1026,9 @@ export interface ClientEncryptionCreateDataKeyProviderOptions {
|
|
|
946
1026
|
|
|
947
1027
|
/** @experimental */
|
|
948
1028
|
keyMaterial?: Buffer | Binary;
|
|
1029
|
+
|
|
1030
|
+
/** @internal */
|
|
1031
|
+
timeoutContext?: CSOTTimeoutContext;
|
|
949
1032
|
}
|
|
950
1033
|
|
|
951
1034
|
/**
|
|
@@ -11,8 +11,11 @@ import {
|
|
|
11
11
|
serialize
|
|
12
12
|
} from '../bson';
|
|
13
13
|
import { type ProxyOptions } from '../cmap/connection';
|
|
14
|
+
import { CursorTimeoutContext } from '../cursor/abstract_cursor';
|
|
14
15
|
import { getSocks, type SocksLib } from '../deps';
|
|
16
|
+
import { MongoOperationTimeoutError } from '../error';
|
|
15
17
|
import { type MongoClient, type MongoClientOptions } from '../mongo_client';
|
|
18
|
+
import { Timeout, type TimeoutContext, TimeoutError } from '../timeout';
|
|
16
19
|
import { BufferPool, MongoDBCollectionNamespace, promiseWithResolvers } from '../utils';
|
|
17
20
|
import { autoSelectSocketOptions, type DataKey } from './client_encryption';
|
|
18
21
|
import { MongoCryptError } from './errors';
|
|
@@ -173,6 +176,7 @@ export type StateMachineOptions = {
|
|
|
173
176
|
* An internal class that executes across a MongoCryptContext until either
|
|
174
177
|
* a finishing state or an error is reached. Do not instantiate directly.
|
|
175
178
|
*/
|
|
179
|
+
// TODO(DRIVERS-2671): clarify CSOT behavior for FLE APIs
|
|
176
180
|
export class StateMachine {
|
|
177
181
|
constructor(
|
|
178
182
|
private options: StateMachineOptions,
|
|
@@ -182,7 +186,11 @@ export class StateMachine {
|
|
|
182
186
|
/**
|
|
183
187
|
* Executes the state machine according to the specification
|
|
184
188
|
*/
|
|
185
|
-
async execute(
|
|
189
|
+
async execute(
|
|
190
|
+
executor: StateMachineExecutable,
|
|
191
|
+
context: MongoCryptContext,
|
|
192
|
+
timeoutContext?: TimeoutContext
|
|
193
|
+
): Promise<Uint8Array> {
|
|
186
194
|
const keyVaultNamespace = executor._keyVaultNamespace;
|
|
187
195
|
const keyVaultClient = executor._keyVaultClient;
|
|
188
196
|
const metaDataClient = executor._metaDataClient;
|
|
@@ -201,8 +209,13 @@ export class StateMachine {
|
|
|
201
209
|
'unreachable state machine state: entered MONGOCRYPT_CTX_NEED_MONGO_COLLINFO but metadata client is undefined'
|
|
202
210
|
);
|
|
203
211
|
}
|
|
204
|
-
const collInfo = await this.fetchCollectionInfo(metaDataClient, context.ns, filter);
|
|
205
212
|
|
|
213
|
+
const collInfo = await this.fetchCollectionInfo(
|
|
214
|
+
metaDataClient,
|
|
215
|
+
context.ns,
|
|
216
|
+
filter,
|
|
217
|
+
timeoutContext
|
|
218
|
+
);
|
|
206
219
|
if (collInfo) {
|
|
207
220
|
context.addMongoOperationResponse(collInfo);
|
|
208
221
|
}
|
|
@@ -222,9 +235,9 @@ export class StateMachine {
|
|
|
222
235
|
// When we are using the shared library, we don't have a mongocryptd manager.
|
|
223
236
|
const markedCommand: Uint8Array = mongocryptdManager
|
|
224
237
|
? await mongocryptdManager.withRespawn(
|
|
225
|
-
this.markCommand.bind(this, mongocryptdClient, context.ns, command)
|
|
238
|
+
this.markCommand.bind(this, mongocryptdClient, context.ns, command, timeoutContext)
|
|
226
239
|
)
|
|
227
|
-
: await this.markCommand(mongocryptdClient, context.ns, command);
|
|
240
|
+
: await this.markCommand(mongocryptdClient, context.ns, command, timeoutContext);
|
|
228
241
|
|
|
229
242
|
context.addMongoOperationResponse(markedCommand);
|
|
230
243
|
context.finishMongoOperation();
|
|
@@ -233,7 +246,12 @@ export class StateMachine {
|
|
|
233
246
|
|
|
234
247
|
case MONGOCRYPT_CTX_NEED_MONGO_KEYS: {
|
|
235
248
|
const filter = context.nextMongoOperation();
|
|
236
|
-
const keys = await this.fetchKeys(
|
|
249
|
+
const keys = await this.fetchKeys(
|
|
250
|
+
keyVaultClient,
|
|
251
|
+
keyVaultNamespace,
|
|
252
|
+
filter,
|
|
253
|
+
timeoutContext
|
|
254
|
+
);
|
|
237
255
|
|
|
238
256
|
if (keys.length === 0) {
|
|
239
257
|
// See docs on EMPTY_V
|
|
@@ -255,9 +273,7 @@ export class StateMachine {
|
|
|
255
273
|
}
|
|
256
274
|
|
|
257
275
|
case MONGOCRYPT_CTX_NEED_KMS: {
|
|
258
|
-
|
|
259
|
-
await Promise.all(requests);
|
|
260
|
-
|
|
276
|
+
await Promise.all(this.requests(context, timeoutContext));
|
|
261
277
|
context.finishKMSRequests();
|
|
262
278
|
break;
|
|
263
279
|
}
|
|
@@ -299,7 +315,7 @@ export class StateMachine {
|
|
|
299
315
|
* @param kmsContext - A C++ KMS context returned from the bindings
|
|
300
316
|
* @returns A promise that resolves when the KMS reply has be fully parsed
|
|
301
317
|
*/
|
|
302
|
-
async kmsRequest(request: MongoCryptKMSRequest): Promise<void> {
|
|
318
|
+
async kmsRequest(request: MongoCryptKMSRequest, timeoutContext?: TimeoutContext): Promise<void> {
|
|
303
319
|
const parsedUrl = request.endpoint.split(':');
|
|
304
320
|
const port = parsedUrl[1] != null ? Number.parseInt(parsedUrl[1], 10) : HTTPS_PORT;
|
|
305
321
|
const socketOptions = autoSelectSocketOptions(this.options.socketOptions || {});
|
|
@@ -329,10 +345,6 @@ export class StateMachine {
|
|
|
329
345
|
}
|
|
330
346
|
}
|
|
331
347
|
|
|
332
|
-
function ontimeout() {
|
|
333
|
-
return new MongoCryptError('KMS request timed out');
|
|
334
|
-
}
|
|
335
|
-
|
|
336
348
|
function onerror(cause: Error) {
|
|
337
349
|
return new MongoCryptError('KMS request failed', { cause });
|
|
338
350
|
}
|
|
@@ -364,7 +376,6 @@ export class StateMachine {
|
|
|
364
376
|
resolve: resolveOnNetSocketConnect
|
|
365
377
|
} = promiseWithResolvers<void>();
|
|
366
378
|
netSocket
|
|
367
|
-
.once('timeout', () => rejectOnNetSocketError(ontimeout()))
|
|
368
379
|
.once('error', err => rejectOnNetSocketError(onerror(err)))
|
|
369
380
|
.once('close', () => rejectOnNetSocketError(onclose()))
|
|
370
381
|
.once('connect', () => resolveOnNetSocketConnect());
|
|
@@ -410,8 +421,8 @@ export class StateMachine {
|
|
|
410
421
|
reject: rejectOnTlsSocketError,
|
|
411
422
|
resolve
|
|
412
423
|
} = promiseWithResolvers<void>();
|
|
424
|
+
|
|
413
425
|
socket
|
|
414
|
-
.once('timeout', () => rejectOnTlsSocketError(ontimeout()))
|
|
415
426
|
.once('error', err => rejectOnTlsSocketError(onerror(err)))
|
|
416
427
|
.once('close', () => rejectOnTlsSocketError(onclose()))
|
|
417
428
|
.on('data', data => {
|
|
@@ -425,20 +436,26 @@ export class StateMachine {
|
|
|
425
436
|
resolve();
|
|
426
437
|
}
|
|
427
438
|
});
|
|
428
|
-
await
|
|
439
|
+
await (timeoutContext?.csotEnabled()
|
|
440
|
+
? Promise.all([willResolveKmsRequest, Timeout.expires(timeoutContext?.remainingTimeMS)])
|
|
441
|
+
: willResolveKmsRequest);
|
|
442
|
+
} catch (error) {
|
|
443
|
+
if (error instanceof TimeoutError)
|
|
444
|
+
throw new MongoOperationTimeoutError('KMS request timed out');
|
|
445
|
+
throw error;
|
|
429
446
|
} finally {
|
|
430
447
|
// There's no need for any more activity on this socket at this point.
|
|
431
448
|
destroySockets();
|
|
432
449
|
}
|
|
433
450
|
}
|
|
434
451
|
|
|
435
|
-
*requests(context: MongoCryptContext) {
|
|
452
|
+
*requests(context: MongoCryptContext, timeoutContext?: TimeoutContext) {
|
|
436
453
|
for (
|
|
437
454
|
let request = context.nextKMSRequest();
|
|
438
455
|
request != null;
|
|
439
456
|
request = context.nextKMSRequest()
|
|
440
457
|
) {
|
|
441
|
-
yield this.kmsRequest(request);
|
|
458
|
+
yield this.kmsRequest(request, timeoutContext);
|
|
442
459
|
}
|
|
443
460
|
}
|
|
444
461
|
|
|
@@ -498,17 +515,21 @@ export class StateMachine {
|
|
|
498
515
|
async fetchCollectionInfo(
|
|
499
516
|
client: MongoClient,
|
|
500
517
|
ns: string,
|
|
501
|
-
filter: Document
|
|
518
|
+
filter: Document,
|
|
519
|
+
timeoutContext?: TimeoutContext
|
|
502
520
|
): Promise<Uint8Array | null> {
|
|
503
521
|
const { db } = MongoDBCollectionNamespace.fromString(ns);
|
|
504
522
|
|
|
505
|
-
const
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
523
|
+
const cursor = client.db(db).listCollections(filter, {
|
|
524
|
+
promoteLongs: false,
|
|
525
|
+
promoteValues: false,
|
|
526
|
+
timeoutContext: timeoutContext && new CursorTimeoutContext(timeoutContext, Symbol())
|
|
527
|
+
});
|
|
528
|
+
|
|
529
|
+
// There is always exactly zero or one matching documents, so this should always exhaust the cursor
|
|
530
|
+
// in a single batch. We call `toArray()` just to be safe and ensure that the cursor is always
|
|
531
|
+
// exhausted and closed.
|
|
532
|
+
const collections = await cursor.toArray();
|
|
512
533
|
|
|
513
534
|
const info = collections.length > 0 ? serialize(collections[0]) : null;
|
|
514
535
|
return info;
|
|
@@ -522,12 +543,22 @@ export class StateMachine {
|
|
|
522
543
|
* @param command - The command to execute.
|
|
523
544
|
* @param callback - Invoked with the serialized and marked bson command, or with an error
|
|
524
545
|
*/
|
|
525
|
-
async markCommand(
|
|
526
|
-
|
|
546
|
+
async markCommand(
|
|
547
|
+
client: MongoClient,
|
|
548
|
+
ns: string,
|
|
549
|
+
command: Uint8Array,
|
|
550
|
+
timeoutContext?: TimeoutContext
|
|
551
|
+
): Promise<Uint8Array> {
|
|
527
552
|
const { db } = MongoDBCollectionNamespace.fromString(ns);
|
|
528
|
-
const
|
|
553
|
+
const bsonOptions = { promoteLongs: false, promoteValues: false };
|
|
554
|
+
const rawCommand = deserialize(command, bsonOptions);
|
|
529
555
|
|
|
530
|
-
const response = await client.db(db).command(rawCommand,
|
|
556
|
+
const response = await client.db(db).command(rawCommand, {
|
|
557
|
+
...bsonOptions,
|
|
558
|
+
...(timeoutContext?.csotEnabled()
|
|
559
|
+
? { timeoutMS: timeoutContext?.remainingTimeMS }
|
|
560
|
+
: undefined)
|
|
561
|
+
});
|
|
531
562
|
|
|
532
563
|
return serialize(response, this.bsonOptions);
|
|
533
564
|
}
|
|
@@ -543,7 +574,8 @@ export class StateMachine {
|
|
|
543
574
|
fetchKeys(
|
|
544
575
|
client: MongoClient,
|
|
545
576
|
keyVaultNamespace: string,
|
|
546
|
-
filter: Uint8Array
|
|
577
|
+
filter: Uint8Array,
|
|
578
|
+
timeoutContext?: TimeoutContext
|
|
547
579
|
): Promise<Array<DataKey>> {
|
|
548
580
|
const { db: dbName, collection: collectionName } =
|
|
549
581
|
MongoDBCollectionNamespace.fromString(keyVaultNamespace);
|
|
@@ -551,7 +583,9 @@ export class StateMachine {
|
|
|
551
583
|
return client
|
|
552
584
|
.db(dbName)
|
|
553
585
|
.collection<DataKey>(collectionName, { readConcern: { level: 'majority' } })
|
|
554
|
-
.find(deserialize(filter)
|
|
586
|
+
.find(deserialize(filter), {
|
|
587
|
+
timeoutContext: timeoutContext && new CursorTimeoutContext(timeoutContext, Symbol())
|
|
588
|
+
})
|
|
555
589
|
.toArray();
|
|
556
590
|
}
|
|
557
591
|
}
|
|
@@ -31,7 +31,8 @@ function getDefaultAuthMechanism(hello: Document | null): AuthMechanism {
|
|
|
31
31
|
const ALLOWED_ENVIRONMENT_NAMES: AuthMechanismProperties['ENVIRONMENT'][] = [
|
|
32
32
|
'test',
|
|
33
33
|
'azure',
|
|
34
|
-
'gcp'
|
|
34
|
+
'gcp',
|
|
35
|
+
'k8s'
|
|
35
36
|
];
|
|
36
37
|
const ALLOWED_HOSTS_ERROR = 'Auth mechanism property ALLOWED_HOSTS must be an array of strings.';
|
|
37
38
|
|
|
@@ -62,7 +63,7 @@ export interface AuthMechanismProperties extends Document {
|
|
|
62
63
|
/** A user provided OIDC human interacted callback function. */
|
|
63
64
|
OIDC_HUMAN_CALLBACK?: OIDCCallbackFunction;
|
|
64
65
|
/** The OIDC environment. Note that 'test' is for internal use only. */
|
|
65
|
-
ENVIRONMENT?: 'test' | 'azure' | 'gcp';
|
|
66
|
+
ENVIRONMENT?: 'test' | 'azure' | 'gcp' | 'k8s';
|
|
66
67
|
/** Allowed hosts that OIDC auth can connect to. */
|
|
67
68
|
ALLOWED_HOSTS?: string[];
|
|
68
69
|
/** The resource token for OIDC auth in Azure and GCP. */
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { readFile } from 'fs/promises';
|
|
2
|
+
|
|
3
|
+
import { type AccessToken, MachineWorkflow } from './machine_workflow';
|
|
4
|
+
import { type TokenCache } from './token_cache';
|
|
5
|
+
|
|
6
|
+
/** The fallback file name */
|
|
7
|
+
const FALLBACK_FILENAME = '/var/run/secrets/kubernetes.io/serviceaccount/token';
|
|
8
|
+
|
|
9
|
+
/** The azure environment variable for the file name. */
|
|
10
|
+
const AZURE_FILENAME = 'AZURE_FEDERATED_TOKEN_FILE';
|
|
11
|
+
|
|
12
|
+
/** The AWS environment variable for the file name. */
|
|
13
|
+
const AWS_FILENAME = 'AWS_WEB_IDENTITY_TOKEN_FILE';
|
|
14
|
+
|
|
15
|
+
export class K8SMachineWorkflow extends MachineWorkflow {
|
|
16
|
+
/**
|
|
17
|
+
* Instantiate the machine workflow.
|
|
18
|
+
*/
|
|
19
|
+
constructor(cache: TokenCache) {
|
|
20
|
+
super(cache);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Get the token from the environment.
|
|
25
|
+
*/
|
|
26
|
+
async getToken(): Promise<AccessToken> {
|
|
27
|
+
let filename: string;
|
|
28
|
+
if (process.env[AZURE_FILENAME]) {
|
|
29
|
+
filename = process.env[AZURE_FILENAME];
|
|
30
|
+
} else if (process.env[AWS_FILENAME]) {
|
|
31
|
+
filename = process.env[AWS_FILENAME];
|
|
32
|
+
} else {
|
|
33
|
+
filename = FALLBACK_FILENAME;
|
|
34
|
+
}
|
|
35
|
+
const token = await readFile(filename, 'utf8');
|
|
36
|
+
return { access_token: token };
|
|
37
|
+
}
|
|
38
|
+
}
|
|
@@ -6,6 +6,7 @@ import { type AuthContext, AuthProvider } from './auth_provider';
|
|
|
6
6
|
import type { MongoCredentials } from './mongo_credentials';
|
|
7
7
|
import { AzureMachineWorkflow } from './mongodb_oidc/azure_machine_workflow';
|
|
8
8
|
import { GCPMachineWorkflow } from './mongodb_oidc/gcp_machine_workflow';
|
|
9
|
+
import { K8SMachineWorkflow } from './mongodb_oidc/k8s_machine_workflow';
|
|
9
10
|
import { TokenCache } from './mongodb_oidc/token_cache';
|
|
10
11
|
import { TokenMachineWorkflow } from './mongodb_oidc/token_machine_workflow';
|
|
11
12
|
|
|
@@ -88,7 +89,7 @@ export type OIDCCallbackFunction = (params: OIDCCallbackParams) => Promise<OIDCR
|
|
|
88
89
|
/** The current version of OIDC implementation. */
|
|
89
90
|
export const OIDC_VERSION = 1;
|
|
90
91
|
|
|
91
|
-
type EnvironmentName = 'test' | 'azure' | 'gcp' | undefined;
|
|
92
|
+
type EnvironmentName = 'test' | 'azure' | 'gcp' | 'k8s' | undefined;
|
|
92
93
|
|
|
93
94
|
/** @internal */
|
|
94
95
|
export interface Workflow {
|
|
@@ -118,6 +119,7 @@ export const OIDC_WORKFLOWS: Map<EnvironmentName, () => Workflow> = new Map();
|
|
|
118
119
|
OIDC_WORKFLOWS.set('test', () => new TokenMachineWorkflow(new TokenCache()));
|
|
119
120
|
OIDC_WORKFLOWS.set('azure', () => new AzureMachineWorkflow(new TokenCache()));
|
|
120
121
|
OIDC_WORKFLOWS.set('gcp', () => new GCPMachineWorkflow(new TokenCache()));
|
|
122
|
+
OIDC_WORKFLOWS.set('k8s', () => new K8SMachineWorkflow(new TokenCache()));
|
|
121
123
|
|
|
122
124
|
/**
|
|
123
125
|
* OIDC auth provider.
|