mongodb 5.2.0 → 5.4.0

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.
Files changed (100) hide show
  1. package/lib/admin.js +18 -0
  2. package/lib/admin.js.map +1 -1
  3. package/lib/bulk/common.js +28 -7
  4. package/lib/bulk/common.js.map +1 -1
  5. package/lib/cmap/auth/mongo_credentials.js +29 -2
  6. package/lib/cmap/auth/mongo_credentials.js.map +1 -1
  7. package/lib/cmap/auth/mongodb_oidc/aws_service_workflow.js +5 -3
  8. package/lib/cmap/auth/mongodb_oidc/aws_service_workflow.js.map +1 -1
  9. package/lib/cmap/auth/mongodb_oidc/cache.js +28 -0
  10. package/lib/cmap/auth/mongodb_oidc/cache.js.map +1 -0
  11. package/lib/cmap/auth/mongodb_oidc/callback_lock_cache.js +83 -0
  12. package/lib/cmap/auth/mongodb_oidc/callback_lock_cache.js.map +1 -0
  13. package/lib/cmap/auth/mongodb_oidc/callback_workflow.js +138 -112
  14. package/lib/cmap/auth/mongodb_oidc/callback_workflow.js.map +1 -1
  15. package/lib/cmap/auth/mongodb_oidc/service_workflow.js +4 -2
  16. package/lib/cmap/auth/mongodb_oidc/service_workflow.js.map +1 -1
  17. package/lib/cmap/auth/mongodb_oidc/token_entry_cache.js +12 -56
  18. package/lib/cmap/auth/mongodb_oidc/token_entry_cache.js.map +1 -1
  19. package/lib/cmap/auth/mongodb_oidc.js +17 -13
  20. package/lib/cmap/auth/mongodb_oidc.js.map +1 -1
  21. package/lib/cmap/command_monitoring_events.js +6 -0
  22. package/lib/cmap/command_monitoring_events.js.map +1 -1
  23. package/lib/cmap/connect.js +1 -0
  24. package/lib/cmap/connect.js.map +1 -1
  25. package/lib/cmap/connection.js +12 -12
  26. package/lib/cmap/connection.js.map +1 -1
  27. package/lib/cmap/connection_pool.js +7 -3
  28. package/lib/cmap/connection_pool.js.map +1 -1
  29. package/lib/cmap/connection_pool_events.js +28 -3
  30. package/lib/cmap/connection_pool_events.js.map +1 -1
  31. package/lib/cmap/handshake/client_metadata.js +173 -0
  32. package/lib/cmap/handshake/client_metadata.js.map +1 -0
  33. package/lib/cmap/wire_protocol/constants.js +2 -2
  34. package/lib/cmap/wire_protocol/shared.js +2 -2
  35. package/lib/cmap/wire_protocol/shared.js.map +1 -1
  36. package/lib/collection.js +3 -0
  37. package/lib/collection.js.map +1 -1
  38. package/lib/connection_string.js +48 -53
  39. package/lib/connection_string.js.map +1 -1
  40. package/lib/constants.js +11 -0
  41. package/lib/constants.js.map +1 -1
  42. package/lib/cursor/abstract_cursor.js +1 -0
  43. package/lib/cursor/abstract_cursor.js.map +1 -1
  44. package/lib/db.js +18 -0
  45. package/lib/db.js.map +1 -1
  46. package/lib/mongo_client.js +16 -0
  47. package/lib/mongo_client.js.map +1 -1
  48. package/lib/mongo_logger.js +258 -27
  49. package/lib/mongo_logger.js.map +1 -1
  50. package/lib/operations/add_user.js.map +1 -1
  51. package/lib/operations/find.js +0 -7
  52. package/lib/operations/find.js.map +1 -1
  53. package/lib/operations/run_command.js.map +1 -1
  54. package/lib/operations/stats.js.map +1 -1
  55. package/lib/operations/update.js.map +1 -1
  56. package/lib/sdam/srv_polling.js +1 -15
  57. package/lib/sdam/srv_polling.js.map +1 -1
  58. package/lib/sdam/topology.js.map +1 -1
  59. package/lib/utils.js +48 -35
  60. package/lib/utils.js.map +1 -1
  61. package/mongodb.d.ts +247 -47
  62. package/package.json +3 -3
  63. package/src/admin.ts +18 -0
  64. package/src/bulk/common.ts +28 -7
  65. package/src/change_stream.ts +1 -1
  66. package/src/cmap/auth/mongo_credentials.ts +35 -2
  67. package/src/cmap/auth/mongodb_oidc/aws_service_workflow.ts +6 -3
  68. package/src/cmap/auth/mongodb_oidc/cache.ts +27 -0
  69. package/src/cmap/auth/mongodb_oidc/callback_lock_cache.ts +107 -0
  70. package/src/cmap/auth/mongodb_oidc/callback_workflow.ts +208 -171
  71. package/src/cmap/auth/mongodb_oidc/service_workflow.ts +5 -3
  72. package/src/cmap/auth/mongodb_oidc/token_entry_cache.ts +17 -96
  73. package/src/cmap/auth/mongodb_oidc.ts +61 -37
  74. package/src/cmap/command_monitoring_events.ts +13 -1
  75. package/src/cmap/connect.ts +3 -1
  76. package/src/cmap/connection.ts +16 -13
  77. package/src/cmap/connection_pool.ts +14 -4
  78. package/src/cmap/connection_pool_events.ts +68 -6
  79. package/src/cmap/handshake/client_metadata.ts +272 -0
  80. package/src/cmap/wire_protocol/constants.ts +2 -2
  81. package/src/cmap/wire_protocol/shared.ts +2 -3
  82. package/src/collection.ts +6 -3
  83. package/src/connection_string.ts +55 -55
  84. package/src/constants.ts +11 -0
  85. package/src/cursor/abstract_cursor.ts +1 -0
  86. package/src/db.ts +18 -0
  87. package/src/index.ts +24 -6
  88. package/src/mongo_client.ts +50 -6
  89. package/src/mongo_logger.ts +363 -44
  90. package/src/operations/add_user.ts +8 -2
  91. package/src/operations/find.ts +0 -10
  92. package/src/operations/run_command.ts +40 -3
  93. package/src/operations/stats.ts +11 -2
  94. package/src/operations/update.ts +8 -4
  95. package/src/sdam/srv_polling.ts +1 -16
  96. package/src/sdam/topology.ts +1 -3
  97. package/src/utils.ts +54 -73
  98. package/lib/cmap/auth/mongodb_oidc/workflow.js +0 -3
  99. package/lib/cmap/auth/mongodb_oidc/workflow.js.map +0 -1
  100. package/src/cmap/auth/mongodb_oidc/workflow.ts +0 -21
@@ -212,37 +212,58 @@ export class BulkWriteResult {
212
212
  return this.result.ok;
213
213
  }
214
214
 
215
- /** The number of inserted documents */
215
+ /**
216
+ * The number of inserted documents
217
+ * @deprecated Use insertedCount instead.
218
+ */
216
219
  get nInserted(): number {
217
220
  return this.result.nInserted;
218
221
  }
219
222
 
220
- /** Number of upserted documents */
223
+ /**
224
+ * Number of upserted documents
225
+ * @deprecated User upsertedCount instead.
226
+ */
221
227
  get nUpserted(): number {
222
228
  return this.result.nUpserted;
223
229
  }
224
230
 
225
- /** Number of matched documents */
231
+ /**
232
+ * Number of matched documents
233
+ * @deprecated Use matchedCount instead.
234
+ */
226
235
  get nMatched(): number {
227
236
  return this.result.nMatched;
228
237
  }
229
238
 
230
- /** Number of documents updated physically on disk */
239
+ /**
240
+ * Number of documents updated physically on disk
241
+ * @deprecated Use modifiedCount instead.
242
+ */
231
243
  get nModified(): number {
232
244
  return this.result.nModified;
233
245
  }
234
246
 
235
- /** Number of removed documents */
247
+ /**
248
+ * Number of removed documents
249
+ * @deprecated Use deletedCount instead.
250
+ */
236
251
  get nRemoved(): number {
237
252
  return this.result.nRemoved;
238
253
  }
239
254
 
240
- /** Returns an array of all inserted ids */
255
+ /**
256
+ * Returns an array of all inserted ids
257
+ * @deprecated Use insertedIds instead.
258
+ */
241
259
  getInsertedIds(): Document[] {
242
260
  return this.result.insertedIds;
243
261
  }
244
262
 
245
- /** Returns an array of all upserted ids */
263
+ /**
264
+ * Returns an array of all upserted ids
265
+ * @deprecated Use upsertedIds instead.
266
+ */
246
267
  getUpsertedIds(): Document[] {
247
268
  return this.result.upserted;
248
269
  }
@@ -700,7 +700,7 @@ export class ChangeStream<
700
700
  /**
701
701
  * Try to get the next available document from the Change Stream's cursor or `null` if an empty batch is returned
702
702
  */
703
- async tryNext(): Promise<Document | null> {
703
+ async tryNext(): Promise<TChange | null> {
704
704
  this._setIsIterator();
705
705
  // Change streams must resume indefinitely while each resume event succeeds.
706
706
  // This loop continues until either a change event is received or until a resume attempt
@@ -30,6 +30,18 @@ function getDefaultAuthMechanism(hello?: Document): AuthMechanism {
30
30
  return AuthMechanism.MONGODB_CR;
31
31
  }
32
32
 
33
+ const ALLOWED_HOSTS_ERROR = 'Auth mechanism property ALLOWED_HOSTS must be an array of strings.';
34
+
35
+ /** @internal */
36
+ export const DEFAULT_ALLOWED_HOSTS = [
37
+ '*.mongodb.net',
38
+ '*.mongodb-dev.net',
39
+ '*.mongodbgov.net',
40
+ 'localhost',
41
+ '127.0.0.1',
42
+ '::1'
43
+ ];
44
+
33
45
  /** @public */
34
46
  export interface AuthMechanismProperties extends Document {
35
47
  SERVICE_HOST?: string;
@@ -43,11 +55,13 @@ export interface AuthMechanismProperties extends Document {
43
55
  REFRESH_TOKEN_CALLBACK?: OIDCRefreshFunction;
44
56
  /** @experimental */
45
57
  PROVIDER_NAME?: 'aws';
58
+ /** @experimental */
59
+ ALLOWED_HOSTS?: string[];
46
60
  }
47
61
 
48
62
  /** @public */
49
63
  export interface MongoCredentialsOptions {
50
- username: string;
64
+ username?: string;
51
65
  password: string;
52
66
  source: string;
53
67
  db?: string;
@@ -72,7 +86,7 @@ export class MongoCredentials {
72
86
  readonly mechanismProperties: AuthMechanismProperties;
73
87
 
74
88
  constructor(options: MongoCredentialsOptions) {
75
- this.username = options.username;
89
+ this.username = options.username ?? '';
76
90
  this.password = options.password;
77
91
  this.source = options.source;
78
92
  if (!this.source && options.db) {
@@ -101,6 +115,13 @@ export class MongoCredentials {
101
115
  }
102
116
  }
103
117
 
118
+ if (this.mechanism === AuthMechanism.MONGODB_OIDC && !this.mechanismProperties.ALLOWED_HOSTS) {
119
+ this.mechanismProperties = {
120
+ ...this.mechanismProperties,
121
+ ALLOWED_HOSTS: DEFAULT_ALLOWED_HOSTS
122
+ };
123
+ }
124
+
104
125
  Object.freeze(this.mechanismProperties);
105
126
  Object.freeze(this);
106
127
  }
@@ -181,6 +202,18 @@ export class MongoCredentials {
181
202
  `Either a PROVIDER_NAME or a REQUEST_TOKEN_CALLBACK must be specified for mechanism '${this.mechanism}'.`
182
203
  );
183
204
  }
205
+
206
+ if (this.mechanismProperties.ALLOWED_HOSTS) {
207
+ const hosts = this.mechanismProperties.ALLOWED_HOSTS;
208
+ if (!Array.isArray(hosts)) {
209
+ throw new MongoInvalidArgumentError(ALLOWED_HOSTS_ERROR);
210
+ }
211
+ for (const host of hosts) {
212
+ if (typeof host !== 'string') {
213
+ throw new MongoInvalidArgumentError(ALLOWED_HOSTS_ERROR);
214
+ }
215
+ }
216
+ }
184
217
  }
185
218
 
186
219
  if (AUTH_MECHS_AUTH_SRC_EXTERNAL.has(this.mechanism)) {
@@ -1,8 +1,11 @@
1
- import { readFile } from 'fs/promises';
1
+ import * as fs from 'fs';
2
2
 
3
3
  import { MongoAWSError } from '../../../error';
4
4
  import { ServiceWorkflow } from './service_workflow';
5
5
 
6
+ /** Error for when the token is missing in the environment. */
7
+ const TOKEN_MISSING_ERROR = 'AWS_WEB_IDENTITY_TOKEN_FILE must be set in the environment.';
8
+
6
9
  /**
7
10
  * Device workflow implementation for AWS.
8
11
  *
@@ -19,8 +22,8 @@ export class AwsServiceWorkflow extends ServiceWorkflow {
19
22
  async getToken(): Promise<string> {
20
23
  const tokenFile = process.env.AWS_WEB_IDENTITY_TOKEN_FILE;
21
24
  if (!tokenFile) {
22
- throw new MongoAWSError('AWS_WEB_IDENTITY_TOKEN_FILE must be set in the environment.');
25
+ throw new MongoAWSError(TOKEN_MISSING_ERROR);
23
26
  }
24
- return readFile(tokenFile, 'utf8');
27
+ return fs.promises.readFile(tokenFile, 'utf8');
25
28
  }
26
29
  }
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Base class for OIDC caches.
3
+ */
4
+ export abstract class Cache<T> {
5
+ entries: Map<string, T>;
6
+
7
+ /**
8
+ * Create a new cache.
9
+ */
10
+ constructor() {
11
+ this.entries = new Map<string, T>();
12
+ }
13
+
14
+ /**
15
+ * Clear the cache.
16
+ */
17
+ clear() {
18
+ this.entries.clear();
19
+ }
20
+
21
+ /**
22
+ * Create a cache key from the address and username.
23
+ */
24
+ cacheKey(address: string, username: string, callbackHash: string): string {
25
+ return JSON.stringify([address, username, callbackHash]);
26
+ }
27
+ }
@@ -0,0 +1,107 @@
1
+ import { MongoInvalidArgumentError } from '../../../error';
2
+ import type { Connection } from '../../connection';
3
+ import type { MongoCredentials } from '../mongo_credentials';
4
+ import type {
5
+ IdPServerInfo,
6
+ IdPServerResponse,
7
+ OIDCCallbackContext,
8
+ OIDCRefreshFunction,
9
+ OIDCRequestFunction
10
+ } from '../mongodb_oidc';
11
+ import { Cache } from './cache';
12
+
13
+ /** Error message for when request callback is missing. */
14
+ const REQUEST_CALLBACK_REQUIRED_ERROR =
15
+ 'Auth mechanism property REQUEST_TOKEN_CALLBACK is required.';
16
+ /* Counter for function "hashes".*/
17
+ let FN_HASH_COUNTER = 0;
18
+ /* No function present function */
19
+ const NO_FUNCTION: OIDCRequestFunction = async () => ({ accessToken: 'test' });
20
+ /* The map of function hashes */
21
+ const FN_HASHES = new WeakMap<OIDCRequestFunction | OIDCRefreshFunction, number>();
22
+ /* Put the no function hash in the map. */
23
+ FN_HASHES.set(NO_FUNCTION, FN_HASH_COUNTER);
24
+
25
+ /**
26
+ * An entry of callbacks in the cache.
27
+ */
28
+ interface CallbacksEntry {
29
+ requestCallback: OIDCRequestFunction;
30
+ refreshCallback?: OIDCRefreshFunction;
31
+ callbackHash: string;
32
+ }
33
+
34
+ /**
35
+ * A cache of request and refresh callbacks per server/user.
36
+ */
37
+ export class CallbackLockCache extends Cache<CallbacksEntry> {
38
+ /**
39
+ * Get the callbacks for the connection and credentials. If an entry does not
40
+ * exist a new one will get set.
41
+ */
42
+ getCallbacks(connection: Connection, credentials: MongoCredentials): CallbacksEntry {
43
+ const requestCallback = credentials.mechanismProperties.REQUEST_TOKEN_CALLBACK;
44
+ const refreshCallback = credentials.mechanismProperties.REFRESH_TOKEN_CALLBACK;
45
+ if (!requestCallback) {
46
+ throw new MongoInvalidArgumentError(REQUEST_CALLBACK_REQUIRED_ERROR);
47
+ }
48
+ const callbackHash = hashFunctions(requestCallback, refreshCallback);
49
+ const key = this.cacheKey(connection.address, credentials.username, callbackHash);
50
+ const entry = this.entries.get(key);
51
+ if (entry) {
52
+ return entry;
53
+ }
54
+ return this.setCallbacks(key, callbackHash, requestCallback, refreshCallback);
55
+ }
56
+
57
+ /**
58
+ * Set locked callbacks on for connection and credentials.
59
+ */
60
+ private setCallbacks(
61
+ key: string,
62
+ callbackHash: string,
63
+ requestCallback: OIDCRequestFunction,
64
+ refreshCallback?: OIDCRefreshFunction
65
+ ): CallbacksEntry {
66
+ const entry = {
67
+ requestCallback: withLock(requestCallback),
68
+ refreshCallback: refreshCallback ? withLock(refreshCallback) : undefined,
69
+ callbackHash: callbackHash
70
+ };
71
+ this.entries.set(key, entry);
72
+ return entry;
73
+ }
74
+ }
75
+
76
+ /**
77
+ * Ensure the callback is only executed one at a time.
78
+ */
79
+ function withLock(callback: OIDCRequestFunction | OIDCRefreshFunction) {
80
+ let lock: Promise<any> = Promise.resolve();
81
+ return async (info: IdPServerInfo, context: OIDCCallbackContext): Promise<IdPServerResponse> => {
82
+ await lock;
83
+ lock = lock.then(() => callback(info, context));
84
+ return lock;
85
+ };
86
+ }
87
+
88
+ /**
89
+ * Get the hash string for the request and refresh functions.
90
+ */
91
+ function hashFunctions(requestFn: OIDCRequestFunction, refreshFn?: OIDCRefreshFunction): string {
92
+ let requestHash = FN_HASHES.get(requestFn);
93
+ let refreshHash = FN_HASHES.get(refreshFn ?? NO_FUNCTION);
94
+ if (requestHash == null) {
95
+ // Create a new one for the function and put it in the map.
96
+ FN_HASH_COUNTER++;
97
+ requestHash = FN_HASH_COUNTER;
98
+ FN_HASHES.set(requestFn, FN_HASH_COUNTER);
99
+ }
100
+ if (refreshHash == null && refreshFn) {
101
+ // Create a new one for the function and put it in the map.
102
+ FN_HASH_COUNTER++;
103
+ refreshHash = FN_HASH_COUNTER;
104
+ FN_HASHES.set(refreshFn, FN_HASH_COUNTER);
105
+ }
106
+ return `${requestHash}-${refreshHash}`;
107
+ }