mongodb 5.1.0 → 5.3.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 (144) hide show
  1. package/README.md +25 -22
  2. package/lib/admin.js +2 -0
  3. package/lib/admin.js.map +1 -1
  4. package/lib/bulk/common.js +28 -7
  5. package/lib/bulk/common.js.map +1 -1
  6. package/lib/change_stream.js +1 -1
  7. package/lib/cmap/auth/auth_provider.js +21 -10
  8. package/lib/cmap/auth/auth_provider.js.map +1 -1
  9. package/lib/cmap/auth/gssapi.js +71 -116
  10. package/lib/cmap/auth/gssapi.js.map +1 -1
  11. package/lib/cmap/auth/mongo_credentials.js +7 -9
  12. package/lib/cmap/auth/mongo_credentials.js.map +1 -1
  13. package/lib/cmap/auth/mongocr.js +20 -29
  14. package/lib/cmap/auth/mongocr.js.map +1 -1
  15. package/lib/cmap/auth/mongodb_aws.js +125 -140
  16. package/lib/cmap/auth/mongodb_aws.js.map +1 -1
  17. package/lib/cmap/auth/mongodb_oidc/aws_service_workflow.js +28 -0
  18. package/lib/cmap/auth/mongodb_oidc/aws_service_workflow.js.map +1 -0
  19. package/lib/cmap/auth/mongodb_oidc/callback_workflow.js +178 -0
  20. package/lib/cmap/auth/mongodb_oidc/callback_workflow.js.map +1 -0
  21. package/lib/cmap/auth/mongodb_oidc/service_workflow.js +41 -0
  22. package/lib/cmap/auth/mongodb_oidc/service_workflow.js.map +1 -0
  23. package/lib/cmap/auth/mongodb_oidc/token_entry_cache.js +115 -0
  24. package/lib/cmap/auth/mongodb_oidc/token_entry_cache.js.map +1 -0
  25. package/lib/cmap/auth/mongodb_oidc/workflow.js +3 -0
  26. package/lib/cmap/auth/mongodb_oidc/workflow.js.map +1 -0
  27. package/lib/cmap/auth/mongodb_oidc.js +59 -0
  28. package/lib/cmap/auth/mongodb_oidc.js.map +1 -1
  29. package/lib/cmap/auth/plain.js +4 -5
  30. package/lib/cmap/auth/plain.js.map +1 -1
  31. package/lib/cmap/auth/providers.js +1 -1
  32. package/lib/cmap/auth/providers.js.map +1 -1
  33. package/lib/cmap/auth/scram.js +45 -73
  34. package/lib/cmap/auth/scram.js.map +1 -1
  35. package/lib/cmap/auth/x509.js +8 -11
  36. package/lib/cmap/auth/x509.js.map +1 -1
  37. package/lib/cmap/command_monitoring_events.js +14 -5
  38. package/lib/cmap/command_monitoring_events.js.map +1 -1
  39. package/lib/cmap/commands.js +1 -1
  40. package/lib/cmap/commands.js.map +1 -1
  41. package/lib/cmap/connect.js +73 -86
  42. package/lib/cmap/connect.js.map +1 -1
  43. package/lib/cmap/connection.js +19 -23
  44. package/lib/cmap/connection.js.map +1 -1
  45. package/lib/cmap/connection_pool.js +56 -14
  46. package/lib/cmap/connection_pool.js.map +1 -1
  47. package/lib/cmap/connection_pool_events.js +28 -3
  48. package/lib/cmap/connection_pool_events.js.map +1 -1
  49. package/lib/cmap/handshake/client_metadata.js +173 -0
  50. package/lib/cmap/handshake/client_metadata.js.map +1 -0
  51. package/lib/cmap/message_stream.js.map +1 -1
  52. package/lib/cmap/wire_protocol/shared.js +1 -16
  53. package/lib/cmap/wire_protocol/shared.js.map +1 -1
  54. package/lib/collection.js +10 -10
  55. package/lib/connection_string.js +50 -69
  56. package/lib/connection_string.js.map +1 -1
  57. package/lib/constants.js +11 -0
  58. package/lib/constants.js.map +1 -1
  59. package/lib/cursor/abstract_cursor.js +2 -1
  60. package/lib/cursor/abstract_cursor.js.map +1 -1
  61. package/lib/cursor/find_cursor.js +1 -1
  62. package/lib/db.js +4 -2
  63. package/lib/db.js.map +1 -1
  64. package/lib/error.js +2 -1
  65. package/lib/error.js.map +1 -1
  66. package/lib/mongo_client.js +23 -2
  67. package/lib/mongo_client.js.map +1 -1
  68. package/lib/mongo_logger.js +236 -23
  69. package/lib/mongo_logger.js.map +1 -1
  70. package/lib/operations/add_user.js.map +1 -1
  71. package/lib/operations/execute_operation.js +8 -27
  72. package/lib/operations/execute_operation.js.map +1 -1
  73. package/lib/operations/find.js +1 -8
  74. package/lib/operations/find.js.map +1 -1
  75. package/lib/operations/update.js.map +1 -1
  76. package/lib/read_concern.js +1 -1
  77. package/lib/read_preference.js +2 -2
  78. package/lib/sdam/srv_polling.js +1 -15
  79. package/lib/sdam/srv_polling.js.map +1 -1
  80. package/lib/sdam/topology.js +0 -16
  81. package/lib/sdam/topology.js.map +1 -1
  82. package/lib/utils.js +33 -90
  83. package/lib/utils.js.map +1 -1
  84. package/lib/write_concern.js +1 -1
  85. package/mongodb.d.ts +242 -93
  86. package/package.json +30 -31
  87. package/src/admin.ts +2 -0
  88. package/src/bulk/common.ts +29 -8
  89. package/src/change_stream.ts +5 -5
  90. package/src/cmap/auth/auth_provider.ts +29 -16
  91. package/src/cmap/auth/gssapi.ts +102 -149
  92. package/src/cmap/auth/mongo_credentials.ts +14 -23
  93. package/src/cmap/auth/mongocr.ts +31 -36
  94. package/src/cmap/auth/mongodb_aws.ts +166 -189
  95. package/src/cmap/auth/mongodb_oidc/aws_service_workflow.ts +26 -0
  96. package/src/cmap/auth/mongodb_oidc/callback_workflow.ts +259 -0
  97. package/src/cmap/auth/mongodb_oidc/service_workflow.ts +47 -0
  98. package/src/cmap/auth/mongodb_oidc/token_entry_cache.ts +166 -0
  99. package/src/cmap/auth/mongodb_oidc/workflow.ts +21 -0
  100. package/src/cmap/auth/mongodb_oidc.ts +101 -17
  101. package/src/cmap/auth/plain.ts +6 -6
  102. package/src/cmap/auth/providers.ts +2 -2
  103. package/src/cmap/auth/scram.ts +56 -90
  104. package/src/cmap/auth/x509.ts +12 -18
  105. package/src/cmap/command_monitoring_events.ts +18 -3
  106. package/src/cmap/commands.ts +1 -1
  107. package/src/cmap/connect.ts +92 -114
  108. package/src/cmap/connection.ts +39 -25
  109. package/src/cmap/connection_pool.ts +89 -18
  110. package/src/cmap/connection_pool_events.ts +68 -6
  111. package/src/cmap/handshake/client_metadata.ts +272 -0
  112. package/src/cmap/message_stream.ts +0 -2
  113. package/src/cmap/wire_protocol/compression.ts +1 -1
  114. package/src/cmap/wire_protocol/shared.ts +1 -23
  115. package/src/collection.ts +13 -13
  116. package/src/connection_string.ts +56 -72
  117. package/src/constants.ts +11 -0
  118. package/src/cursor/abstract_cursor.ts +3 -2
  119. package/src/cursor/change_stream_cursor.ts +5 -5
  120. package/src/cursor/find_cursor.ts +1 -1
  121. package/src/db.ts +4 -2
  122. package/src/deps.ts +3 -2
  123. package/src/error.ts +3 -2
  124. package/src/index.ts +21 -3
  125. package/src/mongo_client.ts +60 -14
  126. package/src/mongo_logger.ts +341 -40
  127. package/src/mongo_types.ts +2 -2
  128. package/src/operations/add_user.ts +8 -2
  129. package/src/operations/aggregate.ts +1 -1
  130. package/src/operations/create_collection.ts +1 -1
  131. package/src/operations/execute_operation.ts +8 -25
  132. package/src/operations/find.ts +1 -11
  133. package/src/operations/find_and_modify.ts +4 -4
  134. package/src/operations/set_profiling_level.ts +1 -1
  135. package/src/operations/stats.ts +1 -1
  136. package/src/operations/update.ts +8 -4
  137. package/src/read_concern.ts +2 -2
  138. package/src/read_preference.ts +3 -3
  139. package/src/sdam/common.ts +2 -2
  140. package/src/sdam/srv_polling.ts +1 -16
  141. package/src/sdam/topology.ts +1 -23
  142. package/src/transactions.ts +1 -1
  143. package/src/utils.ts +37 -147
  144. package/src/write_concern.ts +1 -1
@@ -1,15 +1,9 @@
1
1
  import * as dns from 'dns';
2
2
 
3
- import type { Document } from '../../bson';
4
3
  import { Kerberos, KerberosClient } from '../../deps';
5
- import {
6
- MongoError,
7
- MongoInvalidArgumentError,
8
- MongoMissingCredentialsError,
9
- MongoMissingDependencyError,
10
- MongoRuntimeError
11
- } from '../../error';
12
- import { Callback, ns } from '../../utils';
4
+ import { MongoInvalidArgumentError, MongoMissingCredentialsError } from '../../error';
5
+ import { ns } from '../../utils';
6
+ import type { Connection } from '../connection';
13
7
  import { AuthContext, AuthProvider } from './auth_provider';
14
8
 
15
9
  /** @public */
@@ -23,7 +17,7 @@ export const GSSAPICanonicalizationValue = Object.freeze({
23
17
 
24
18
  /** @public */
25
19
  export type GSSAPICanonicalizationValue =
26
- typeof GSSAPICanonicalizationValue[keyof typeof GSSAPICanonicalizationValue];
20
+ (typeof GSSAPICanonicalizationValue)[keyof typeof GSSAPICanonicalizationValue];
27
21
 
28
22
  type MechanismProperties = {
29
23
  CANONICALIZE_HOST_NAME?: GSSAPICanonicalizationValue;
@@ -32,70 +26,59 @@ type MechanismProperties = {
32
26
  SERVICE_REALM?: string;
33
27
  };
34
28
 
29
+ async function externalCommand(
30
+ connection: Connection,
31
+ command: ReturnType<typeof saslStart> | ReturnType<typeof saslContinue>
32
+ ): Promise<{ payload: string; conversationId: any }> {
33
+ return connection.commandAsync(ns('$external.$cmd'), command, undefined) as Promise<{
34
+ payload: string;
35
+ conversationId: any;
36
+ }>;
37
+ }
38
+
35
39
  export class GSSAPI extends AuthProvider {
36
- override auth(authContext: AuthContext, callback: Callback): void {
40
+ override async auth(authContext: AuthContext): Promise<void> {
37
41
  const { connection, credentials } = authContext;
38
- if (credentials == null)
39
- return callback(
40
- new MongoMissingCredentialsError('Credentials required for GSSAPI authentication')
41
- );
42
- const { username } = credentials;
43
- function externalCommand(
44
- command: Document,
45
- cb: Callback<{ payload: string; conversationId: any }>
46
- ) {
47
- return connection.command(ns('$external.$cmd'), command, undefined, cb);
42
+ if (credentials == null) {
43
+ throw new MongoMissingCredentialsError('Credentials required for GSSAPI authentication');
48
44
  }
49
- makeKerberosClient(authContext, (err, client) => {
50
- if (err) return callback(err);
51
- if (client == null) return callback(new MongoMissingDependencyError('GSSAPI client missing'));
52
- client.step('', (err, payload) => {
53
- if (err) return callback(err);
54
-
55
- externalCommand(saslStart(payload), (err, result) => {
56
- if (err) return callback(err);
57
- if (result == null) return callback();
58
- negotiate(client, 10, result.payload, (err, payload) => {
59
- if (err) return callback(err);
60
-
61
- externalCommand(saslContinue(payload, result.conversationId), (err, result) => {
62
- if (err) return callback(err);
63
- if (result == null) return callback();
64
- finalize(client, username, result.payload, (err, payload) => {
65
- if (err) return callback(err);
66
-
67
- externalCommand(
68
- {
69
- saslContinue: 1,
70
- conversationId: result.conversationId,
71
- payload
72
- },
73
- (err, result) => {
74
- if (err) return callback(err);
75
-
76
- callback(undefined, result);
77
- }
78
- );
79
- });
80
- });
81
- });
82
- });
83
- });
45
+
46
+ const { username } = credentials;
47
+
48
+ const client = await makeKerberosClient(authContext);
49
+
50
+ const payload = await client.step('');
51
+
52
+ const saslStartResponse = await externalCommand(connection, saslStart(payload));
53
+
54
+ const negotiatedPayload = await negotiate(client, 10, saslStartResponse.payload);
55
+
56
+ const saslContinueResponse = await externalCommand(
57
+ connection,
58
+ saslContinue(negotiatedPayload, saslStartResponse.conversationId)
59
+ );
60
+
61
+ const finalizePayload = await finalize(client, username, saslContinueResponse.payload);
62
+
63
+ await externalCommand(connection, {
64
+ saslContinue: 1,
65
+ conversationId: saslContinueResponse.conversationId,
66
+ payload: finalizePayload
84
67
  });
85
68
  }
86
69
  }
87
70
 
88
- function makeKerberosClient(authContext: AuthContext, callback: Callback<KerberosClient>): void {
71
+ async function makeKerberosClient(authContext: AuthContext): Promise<KerberosClient> {
89
72
  const { hostAddress } = authContext.options;
90
73
  const { credentials } = authContext;
91
74
  if (!hostAddress || typeof hostAddress.host !== 'string' || !credentials) {
92
- return callback(
93
- new MongoInvalidArgumentError('Connection must have host and port and credentials defined.')
75
+ throw new MongoInvalidArgumentError(
76
+ 'Connection must have host and port and credentials defined.'
94
77
  );
95
78
  }
96
79
 
97
80
  if ('kModuleError' in Kerberos) {
98
- return callback(Kerberos['kModuleError']);
81
+ throw Kerberos['kModuleError'];
99
82
  }
100
83
  const { initializeClient } = Kerberos;
101
84
 
@@ -104,95 +87,71 @@ function makeKerberosClient(authContext: AuthContext, callback: Callback<Kerbero
104
87
 
105
88
  const serviceName = mechanismProperties.SERVICE_NAME ?? 'mongodb';
106
89
 
107
- performGSSAPICanonicalizeHostName(
108
- hostAddress.host,
109
- mechanismProperties,
110
- (err?: Error | MongoError, host?: string) => {
111
- if (err) return callback(err);
112
-
113
- const initOptions = {};
114
- if (password != null) {
115
- Object.assign(initOptions, { user: username, password: password });
116
- }
117
-
118
- const spnHost = mechanismProperties.SERVICE_HOST ?? host;
119
- let spn = `${serviceName}${process.platform === 'win32' ? '/' : '@'}${spnHost}`;
120
- if ('SERVICE_REALM' in mechanismProperties) {
121
- spn = `${spn}@${mechanismProperties.SERVICE_REALM}`;
122
- }
123
-
124
- initializeClient(spn, initOptions, (err: string, client: KerberosClient): void => {
125
- // TODO(NODE-3483)
126
- if (err) return callback(new MongoRuntimeError(err));
127
- callback(undefined, client);
128
- });
129
- }
130
- );
90
+ const host = await performGSSAPICanonicalizeHostName(hostAddress.host, mechanismProperties);
91
+
92
+ const initOptions = {};
93
+ if (password != null) {
94
+ // TODO(NODE-5139): These do not match the typescript options in initializeClient
95
+ Object.assign(initOptions, { user: username, password: password });
96
+ }
97
+
98
+ const spnHost = mechanismProperties.SERVICE_HOST ?? host;
99
+ let spn = `${serviceName}${process.platform === 'win32' ? '/' : '@'}${spnHost}`;
100
+ if ('SERVICE_REALM' in mechanismProperties) {
101
+ spn = `${spn}@${mechanismProperties.SERVICE_REALM}`;
102
+ }
103
+
104
+ return initializeClient(spn, initOptions);
131
105
  }
132
106
 
133
- function saslStart(payload?: string): Document {
107
+ function saslStart(payload: string) {
134
108
  return {
135
109
  saslStart: 1,
136
110
  mechanism: 'GSSAPI',
137
111
  payload,
138
112
  autoAuthorize: 1
139
- };
113
+ } as const;
140
114
  }
141
115
 
142
- function saslContinue(payload?: string, conversationId?: number): Document {
116
+ function saslContinue(payload: string, conversationId: number) {
143
117
  return {
144
118
  saslContinue: 1,
145
119
  conversationId,
146
120
  payload
147
- };
121
+ } as const;
148
122
  }
149
123
 
150
- function negotiate(
124
+ async function negotiate(
151
125
  client: KerberosClient,
152
126
  retries: number,
153
- payload: string,
154
- callback: Callback<string>
155
- ): void {
156
- client.step(payload, (err, response) => {
157
- // Retries exhausted, raise error
158
- if (err && retries === 0) return callback(err);
159
-
127
+ payload: string
128
+ ): Promise<string> {
129
+ try {
130
+ const response = await client.step(payload);
131
+ return response || '';
132
+ } catch (error) {
133
+ if (retries === 0) {
134
+ // Retries exhausted, raise error
135
+ throw error;
136
+ }
160
137
  // Adjust number of retries and call step again
161
- if (err) return negotiate(client, retries - 1, payload, callback);
162
-
163
- // Return the payload
164
- callback(undefined, response || '');
165
- });
138
+ return negotiate(client, retries - 1, payload);
139
+ }
166
140
  }
167
141
 
168
- function finalize(
169
- client: KerberosClient,
170
- user: string,
171
- payload: string,
172
- callback: Callback<string>
173
- ): void {
142
+ async function finalize(client: KerberosClient, user: string, payload: string): Promise<string> {
174
143
  // GSS Client Unwrap
175
- client.unwrap(payload, (err, response) => {
176
- if (err) return callback(err);
177
-
178
- // Wrap the response
179
- client.wrap(response || '', { user }, (err, wrapped) => {
180
- if (err) return callback(err);
181
-
182
- // Return the payload
183
- callback(undefined, wrapped);
184
- });
185
- });
144
+ const response = await client.unwrap(payload);
145
+ return client.wrap(response || '', { user });
186
146
  }
187
147
 
188
- export function performGSSAPICanonicalizeHostName(
148
+ export async function performGSSAPICanonicalizeHostName(
189
149
  host: string,
190
- mechanismProperties: MechanismProperties,
191
- callback: Callback<string>
192
- ): void {
150
+ mechanismProperties: MechanismProperties
151
+ ): Promise<string> {
193
152
  const mode = mechanismProperties.CANONICALIZE_HOST_NAME;
194
153
  if (!mode || mode === GSSAPICanonicalizationValue.none) {
195
- return callback(undefined, host);
154
+ return host;
196
155
  }
197
156
 
198
157
  // If forward and reverse or true
@@ -201,39 +160,33 @@ export function performGSSAPICanonicalizeHostName(
201
160
  mode === GSSAPICanonicalizationValue.forwardAndReverse
202
161
  ) {
203
162
  // Perform the lookup of the ip address.
204
- dns.lookup(host, (error, address) => {
205
- // No ip found, return the error.
206
- if (error) return callback(error);
163
+ const { address } = await dns.promises.lookup(host);
207
164
 
165
+ try {
208
166
  // Perform a reverse ptr lookup on the ip address.
209
- dns.resolvePtr(address, (err, results) => {
210
- // This can error as ptr records may not exist for all ips. In this case
211
- // fallback to a cname lookup as dns.lookup() does not return the
212
- // cname.
213
- if (err) {
214
- return resolveCname(host, callback);
215
- }
216
- // If the ptr did not error but had no results, return the host.
217
- callback(undefined, results.length > 0 ? results[0] : host);
218
- });
219
- });
167
+ const results = await dns.promises.resolvePtr(address);
168
+ // If the ptr did not error but had no results, return the host.
169
+ return results.length > 0 ? results[0] : host;
170
+ } catch (error) {
171
+ // This can error as ptr records may not exist for all ips. In this case
172
+ // fallback to a cname lookup as dns.lookup() does not return the
173
+ // cname.
174
+ return resolveCname(host);
175
+ }
220
176
  } else {
221
177
  // The case for forward is just to resolve the cname as dns.lookup()
222
178
  // will not return it.
223
- resolveCname(host, callback);
179
+ return resolveCname(host);
224
180
  }
225
181
  }
226
182
 
227
- export function resolveCname(host: string, callback: Callback<string>): void {
183
+ export async function resolveCname(host: string): Promise<string> {
228
184
  // Attempt to resolve the host name
229
- dns.resolveCname(host, (err, r) => {
230
- if (err) return callback(undefined, host);
231
-
232
- // Get the first resolve host id
233
- if (r.length > 0) {
234
- return callback(undefined, r[0]);
235
- }
236
-
237
- callback(undefined, host);
238
- });
185
+ try {
186
+ const results = await dns.promises.resolveCname(host);
187
+ // Get the first resolved host id
188
+ return results.length > 0 ? results[0] : host;
189
+ } catch {
190
+ return host;
191
+ }
239
192
  }
@@ -30,25 +30,19 @@ function getDefaultAuthMechanism(hello?: Document): AuthMechanism {
30
30
  return AuthMechanism.MONGODB_CR;
31
31
  }
32
32
 
33
- /**
34
- * TODO: NODE-5035: Make OIDC properties public.
35
- *
36
- * @public
37
- * */
33
+ /** @public */
38
34
  export interface AuthMechanismProperties extends Document {
39
35
  SERVICE_HOST?: string;
40
36
  SERVICE_NAME?: string;
41
37
  SERVICE_REALM?: string;
42
38
  CANONICALIZE_HOST_NAME?: GSSAPICanonicalizationValue;
43
39
  AWS_SESSION_TOKEN?: string;
44
- /** @internal Name for the OIDC device workflow */
45
- DEVICE_NAME?: 'aws' | 'azure' | 'gcp';
46
- /** @internal Similar to a username, is require by OIDC when more than one IDP is configured. */
47
- PRINCIPAL_NAME?: string;
48
- /** @internal User provided callback to get OIDC auth credentials */
40
+ /** @experimental */
49
41
  REQUEST_TOKEN_CALLBACK?: OIDCRequestFunction;
50
- /** @internal User provided callback to refresh OIDC auth credentials */
42
+ /** @experimental */
51
43
  REFRESH_TOKEN_CALLBACK?: OIDCRefreshFunction;
44
+ /** @experimental */
45
+ PROVIDER_NAME?: 'aws';
52
46
  }
53
47
 
54
48
  /** @public */
@@ -155,21 +149,18 @@ export class MongoCredentials {
155
149
  }
156
150
 
157
151
  if (this.mechanism === AuthMechanism.MONGODB_OIDC) {
158
- if (this.username) {
152
+ if (this.username && this.mechanismProperties.PROVIDER_NAME) {
159
153
  throw new MongoInvalidArgumentError(
160
- `Username not permitted for mechanism '${this.mechanism}'. Use PRINCIPAL_NAME instead.`
154
+ `username and PROVIDER_NAME may not be used together for mechanism '${this.mechanism}'.`
161
155
  );
162
156
  }
163
157
 
164
- if (this.mechanismProperties.PRINCIPAL_NAME && this.mechanismProperties.DEVICE_NAME) {
165
- throw new MongoInvalidArgumentError(
166
- `PRINCIPAL_NAME and DEVICE_NAME may not be used together for mechanism '${this.mechanism}'.`
167
- );
168
- }
169
-
170
- if (this.mechanismProperties.DEVICE_NAME && this.mechanismProperties.DEVICE_NAME !== 'aws') {
158
+ if (
159
+ this.mechanismProperties.PROVIDER_NAME &&
160
+ this.mechanismProperties.PROVIDER_NAME !== 'aws'
161
+ ) {
171
162
  throw new MongoInvalidArgumentError(
172
- `Currently only a DEVICE_NAME of 'aws' is supported for mechanism '${this.mechanism}'.`
163
+ `Currently only a PROVIDER_NAME of 'aws' is supported for mechanism '${this.mechanism}'.`
173
164
  );
174
165
  }
175
166
 
@@ -183,11 +174,11 @@ export class MongoCredentials {
183
174
  }
184
175
 
185
176
  if (
186
- !this.mechanismProperties.DEVICE_NAME &&
177
+ !this.mechanismProperties.PROVIDER_NAME &&
187
178
  !this.mechanismProperties.REQUEST_TOKEN_CALLBACK
188
179
  ) {
189
180
  throw new MongoInvalidArgumentError(
190
- `Either a DEVICE_NAME or a REQUEST_TOKEN_CALLBACK must be specified for mechanism '${this.mechanism}'.`
181
+ `Either a PROVIDER_NAME or a REQUEST_TOKEN_CALLBACK must be specified for mechanism '${this.mechanism}'.`
191
182
  );
192
183
  }
193
184
  }
@@ -1,47 +1,42 @@
1
1
  import * as crypto from 'crypto';
2
2
 
3
3
  import { MongoMissingCredentialsError } from '../../error';
4
- import { Callback, ns } from '../../utils';
4
+ import { ns } from '../../utils';
5
5
  import { AuthContext, AuthProvider } from './auth_provider';
6
6
 
7
7
  export class MongoCR extends AuthProvider {
8
- override auth(authContext: AuthContext, callback: Callback): void {
8
+ override async auth(authContext: AuthContext): Promise<void> {
9
9
  const { connection, credentials } = authContext;
10
10
  if (!credentials) {
11
- return callback(new MongoMissingCredentialsError('AuthContext must provide credentials.'));
11
+ throw new MongoMissingCredentialsError('AuthContext must provide credentials.');
12
12
  }
13
- const username = credentials.username;
14
- const password = credentials.password;
15
- const source = credentials.source;
16
- connection.command(ns(`${source}.$cmd`), { getnonce: 1 }, undefined, (err, r) => {
17
- let nonce = null;
18
- let key = null;
19
-
20
- // Get nonce
21
- if (err == null) {
22
- nonce = r.nonce;
23
-
24
- // Use node md5 generator
25
- let md5 = crypto.createHash('md5');
26
-
27
- // Generate keys used for authentication
28
- md5.update(`${username}:mongo:${password}`, 'utf8');
29
- const hash_password = md5.digest('hex');
30
-
31
- // Final key
32
- md5 = crypto.createHash('md5');
33
- md5.update(nonce + username + hash_password, 'utf8');
34
- key = md5.digest('hex');
35
- }
36
-
37
- const authenticateCommand = {
38
- authenticate: 1,
39
- user: username,
40
- nonce,
41
- key
42
- };
43
-
44
- connection.command(ns(`${source}.$cmd`), authenticateCommand, undefined, callback);
45
- });
13
+
14
+ const { username, password, source } = credentials;
15
+
16
+ const { nonce } = await connection.commandAsync(
17
+ ns(`${source}.$cmd`),
18
+ { getnonce: 1 },
19
+ undefined
20
+ );
21
+
22
+ const hashPassword = crypto
23
+ .createHash('md5')
24
+ .update(`${username}:mongo:${password}`, 'utf8')
25
+ .digest('hex');
26
+
27
+ // Final key
28
+ const key = crypto
29
+ .createHash('md5')
30
+ .update(`${nonce}${username}${hashPassword}`, 'utf8')
31
+ .digest('hex');
32
+
33
+ const authenticateCommand = {
34
+ authenticate: 1,
35
+ user: username,
36
+ nonce,
37
+ key
38
+ };
39
+
40
+ await connection.commandAsync(ns(`${source}.$cmd`), authenticateCommand, undefined);
46
41
  }
47
42
  }