mongodb 4.2.1 → 4.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 (266) hide show
  1. package/README.md +2 -2
  2. package/lib/admin.js +3 -3
  3. package/lib/admin.js.map +1 -1
  4. package/lib/bson.js +16 -14
  5. package/lib/bson.js.map +1 -1
  6. package/lib/bulk/common.js +7 -7
  7. package/lib/bulk/common.js.map +1 -1
  8. package/lib/bulk/ordered.js +1 -1
  9. package/lib/bulk/ordered.js.map +1 -1
  10. package/lib/bulk/unordered.js +1 -1
  11. package/lib/bulk/unordered.js.map +1 -1
  12. package/lib/change_stream.js +6 -6
  13. package/lib/change_stream.js.map +1 -1
  14. package/lib/cmap/auth/auth_provider.js.map +1 -1
  15. package/lib/cmap/auth/gssapi.js +52 -10
  16. package/lib/cmap/auth/gssapi.js.map +1 -1
  17. package/lib/cmap/auth/mongo_credentials.js +36 -27
  18. package/lib/cmap/auth/mongo_credentials.js.map +1 -1
  19. package/lib/cmap/auth/mongocr.js +2 -2
  20. package/lib/cmap/auth/mongocr.js.map +1 -1
  21. package/lib/cmap/auth/mongodb_aws.js +6 -6
  22. package/lib/cmap/auth/mongodb_aws.js.map +1 -1
  23. package/lib/cmap/auth/plain.js +1 -1
  24. package/lib/cmap/auth/plain.js.map +1 -1
  25. package/lib/cmap/auth/providers.js +21 -0
  26. package/lib/cmap/auth/providers.js.map +1 -0
  27. package/lib/cmap/auth/scram.js +4 -4
  28. package/lib/cmap/auth/scram.js.map +1 -1
  29. package/lib/cmap/auth/x509.js +1 -1
  30. package/lib/cmap/auth/x509.js.map +1 -1
  31. package/lib/cmap/command_monitoring_events.js +3 -2
  32. package/lib/cmap/command_monitoring_events.js.map +1 -1
  33. package/lib/cmap/commands.js +14 -8
  34. package/lib/cmap/commands.js.map +1 -1
  35. package/lib/cmap/connect.js +119 -37
  36. package/lib/cmap/connect.js.map +1 -1
  37. package/lib/cmap/connection.js +36 -35
  38. package/lib/cmap/connection.js.map +1 -1
  39. package/lib/cmap/connection_pool.js +19 -30
  40. package/lib/cmap/connection_pool.js.map +1 -1
  41. package/lib/cmap/message_stream.js +3 -3
  42. package/lib/cmap/message_stream.js.map +1 -1
  43. package/lib/cmap/stream_description.js +4 -4
  44. package/lib/cmap/stream_description.js.map +1 -1
  45. package/lib/cmap/wire_protocol/compression.js +2 -1
  46. package/lib/cmap/wire_protocol/compression.js.map +1 -1
  47. package/lib/cmap/wire_protocol/shared.js +4 -3
  48. package/lib/cmap/wire_protocol/shared.js.map +1 -1
  49. package/lib/collection.js +46 -47
  50. package/lib/collection.js.map +1 -1
  51. package/lib/connection_string.js +93 -54
  52. package/lib/connection_string.js.map +1 -1
  53. package/lib/constants.js +113 -1
  54. package/lib/constants.js.map +1 -1
  55. package/lib/cursor/abstract_cursor.js +5 -5
  56. package/lib/cursor/abstract_cursor.js.map +1 -1
  57. package/lib/cursor/aggregation_cursor.js +1 -1
  58. package/lib/cursor/aggregation_cursor.js.map +1 -1
  59. package/lib/cursor/find_cursor.js +2 -1
  60. package/lib/cursor/find_cursor.js.map +1 -1
  61. package/lib/db.js +23 -13
  62. package/lib/db.js.map +1 -1
  63. package/lib/deps.js +0 -1
  64. package/lib/deps.js.map +1 -1
  65. package/lib/encrypter.js +12 -4
  66. package/lib/encrypter.js.map +1 -1
  67. package/lib/error.js +47 -24
  68. package/lib/error.js.map +1 -1
  69. package/lib/gridfs/download.js +1 -1
  70. package/lib/gridfs/download.js.map +1 -1
  71. package/lib/gridfs/index.js +3 -3
  72. package/lib/gridfs/index.js.map +1 -1
  73. package/lib/gridfs/upload.js +3 -2
  74. package/lib/gridfs/upload.js.map +1 -1
  75. package/lib/index.js +83 -81
  76. package/lib/index.js.map +1 -1
  77. package/lib/logger.js +1 -1
  78. package/lib/logger.js.map +1 -1
  79. package/lib/mongo_client.js +5 -5
  80. package/lib/mongo_client.js.map +1 -1
  81. package/lib/mongo_types.js.map +1 -1
  82. package/lib/operations/add_user.js +3 -3
  83. package/lib/operations/add_user.js.map +1 -1
  84. package/lib/operations/aggregate.js +1 -1
  85. package/lib/operations/aggregate.js.map +1 -1
  86. package/lib/operations/bulk_write.js.map +1 -1
  87. package/lib/operations/collections.js +1 -1
  88. package/lib/operations/collections.js.map +1 -1
  89. package/lib/operations/command.js +5 -6
  90. package/lib/operations/command.js.map +1 -1
  91. package/lib/operations/common_functions.js.map +1 -1
  92. package/lib/operations/connect.js +4 -13
  93. package/lib/operations/connect.js.map +1 -1
  94. package/lib/operations/count.js +1 -1
  95. package/lib/operations/count.js.map +1 -1
  96. package/lib/operations/count_documents.js.map +1 -1
  97. package/lib/operations/create_collection.js +3 -2
  98. package/lib/operations/create_collection.js.map +1 -1
  99. package/lib/operations/delete.js +3 -3
  100. package/lib/operations/delete.js.map +1 -1
  101. package/lib/operations/distinct.js +3 -3
  102. package/lib/operations/distinct.js.map +1 -1
  103. package/lib/operations/drop.js +1 -1
  104. package/lib/operations/drop.js.map +1 -1
  105. package/lib/operations/estimated_document_count.js +2 -2
  106. package/lib/operations/estimated_document_count.js.map +1 -1
  107. package/lib/operations/eval.js +2 -2
  108. package/lib/operations/eval.js.map +1 -1
  109. package/lib/operations/execute_operation.js +5 -6
  110. package/lib/operations/execute_operation.js.map +1 -1
  111. package/lib/operations/find.js +5 -5
  112. package/lib/operations/find.js.map +1 -1
  113. package/lib/operations/find_and_modify.js +2 -2
  114. package/lib/operations/find_and_modify.js.map +1 -1
  115. package/lib/operations/get_more.js.map +1 -1
  116. package/lib/operations/indexes.js +4 -4
  117. package/lib/operations/indexes.js.map +1 -1
  118. package/lib/operations/insert.js +3 -3
  119. package/lib/operations/insert.js.map +1 -1
  120. package/lib/operations/is_capped.js +1 -1
  121. package/lib/operations/is_capped.js.map +1 -1
  122. package/lib/operations/list_collections.js +3 -3
  123. package/lib/operations/list_collections.js.map +1 -1
  124. package/lib/operations/list_databases.js +1 -1
  125. package/lib/operations/list_databases.js.map +1 -1
  126. package/lib/operations/map_reduce.js +4 -3
  127. package/lib/operations/map_reduce.js.map +1 -1
  128. package/lib/operations/operation.js +1 -1
  129. package/lib/operations/operation.js.map +1 -1
  130. package/lib/operations/options_operation.js +1 -1
  131. package/lib/operations/options_operation.js.map +1 -1
  132. package/lib/operations/profiling_level.js +1 -1
  133. package/lib/operations/profiling_level.js.map +1 -1
  134. package/lib/operations/remove_user.js +1 -1
  135. package/lib/operations/remove_user.js.map +1 -1
  136. package/lib/operations/rename.js +3 -3
  137. package/lib/operations/rename.js.map +1 -1
  138. package/lib/operations/run_command.js +1 -1
  139. package/lib/operations/run_command.js.map +1 -1
  140. package/lib/operations/set_profiling_level.js +2 -2
  141. package/lib/operations/set_profiling_level.js.map +1 -1
  142. package/lib/operations/stats.js +1 -1
  143. package/lib/operations/stats.js.map +1 -1
  144. package/lib/operations/update.js +2 -2
  145. package/lib/operations/update.js.map +1 -1
  146. package/lib/operations/validate_collection.js +1 -1
  147. package/lib/operations/validate_collection.js.map +1 -1
  148. package/lib/read_preference.js +15 -5
  149. package/lib/read_preference.js.map +1 -1
  150. package/lib/sdam/events.js +4 -4
  151. package/lib/sdam/monitor.js +19 -18
  152. package/lib/sdam/monitor.js.map +1 -1
  153. package/lib/sdam/server.js +24 -31
  154. package/lib/sdam/server.js.map +1 -1
  155. package/lib/sdam/server_description.js +38 -38
  156. package/lib/sdam/server_description.js.map +1 -1
  157. package/lib/sdam/server_selection.js +2 -2
  158. package/lib/sdam/server_selection.js.map +1 -1
  159. package/lib/sdam/srv_polling.js +2 -2
  160. package/lib/sdam/srv_polling.js.map +1 -1
  161. package/lib/sdam/topology.js +32 -62
  162. package/lib/sdam/topology.js.map +1 -1
  163. package/lib/sdam/topology_description.js +3 -3
  164. package/lib/sdam/topology_description.js.map +1 -1
  165. package/lib/sessions.js +13 -28
  166. package/lib/sessions.js.map +1 -1
  167. package/lib/transactions.js +1 -1
  168. package/lib/transactions.js.map +1 -1
  169. package/lib/utils.js +46 -15
  170. package/lib/utils.js.map +1 -1
  171. package/mongodb.d.ts +205 -60
  172. package/mongodb.ts34.d.ts +230 -59
  173. package/package.json +40 -37
  174. package/src/admin.ts +9 -9
  175. package/src/bson.ts +25 -17
  176. package/src/bulk/common.ts +22 -23
  177. package/src/bulk/ordered.ts +4 -4
  178. package/src/bulk/unordered.ts +5 -5
  179. package/src/change_stream.ts +29 -28
  180. package/src/cmap/auth/auth_provider.ts +3 -3
  181. package/src/cmap/auth/gssapi.ts +65 -14
  182. package/src/cmap/auth/mongo_credentials.ts +28 -17
  183. package/src/cmap/auth/mongocr.ts +3 -2
  184. package/src/cmap/auth/mongodb_aws.ts +10 -11
  185. package/src/cmap/auth/plain.ts +1 -1
  186. package/src/cmap/auth/providers.ts +21 -0
  187. package/src/cmap/auth/scram.ts +9 -9
  188. package/src/cmap/auth/x509.ts +3 -3
  189. package/src/cmap/command_monitoring_events.ts +4 -3
  190. package/src/cmap/commands.ts +22 -14
  191. package/src/cmap/connect.ts +161 -45
  192. package/src/cmap/connection.ts +83 -63
  193. package/src/cmap/connection_pool.ts +39 -39
  194. package/src/cmap/connection_pool_events.ts +1 -1
  195. package/src/cmap/message_stream.ts +9 -8
  196. package/src/cmap/stream_description.ts +5 -5
  197. package/src/cmap/wire_protocol/compression.ts +4 -3
  198. package/src/cmap/wire_protocol/shared.ts +10 -9
  199. package/src/collection.ts +116 -93
  200. package/src/connection_string.ts +130 -59
  201. package/src/constants.ts +122 -0
  202. package/src/cursor/abstract_cursor.ts +14 -13
  203. package/src/cursor/aggregation_cursor.ts +6 -6
  204. package/src/cursor/find_cursor.ts +12 -4
  205. package/src/db.ts +44 -33
  206. package/src/deps.ts +44 -1
  207. package/src/encrypter.ts +12 -3
  208. package/src/error.ts +52 -24
  209. package/src/gridfs/download.ts +10 -8
  210. package/src/gridfs/index.ts +11 -11
  211. package/src/gridfs/upload.ts +13 -10
  212. package/src/index.ts +205 -199
  213. package/src/logger.ts +2 -1
  214. package/src/mongo_client.ts +46 -32
  215. package/src/mongo_types.ts +119 -21
  216. package/src/operations/add_user.ts +7 -6
  217. package/src/operations/aggregate.ts +5 -5
  218. package/src/operations/bulk_write.ts +5 -5
  219. package/src/operations/collections.ts +2 -2
  220. package/src/operations/command.ts +15 -9
  221. package/src/operations/common_functions.ts +4 -4
  222. package/src/operations/connect.ts +4 -14
  223. package/src/operations/count.ts +4 -4
  224. package/src/operations/count_documents.ts +3 -3
  225. package/src/operations/create_collection.ts +7 -6
  226. package/src/operations/delete.ts +5 -5
  227. package/src/operations/distinct.ts +4 -4
  228. package/src/operations/drop.ts +4 -4
  229. package/src/operations/estimated_document_count.ts +5 -5
  230. package/src/operations/eval.ts +5 -5
  231. package/src/operations/execute_operation.ts +10 -11
  232. package/src/operations/find.ts +14 -14
  233. package/src/operations/find_and_modify.ts +7 -7
  234. package/src/operations/get_more.ts +2 -2
  235. package/src/operations/indexes.ts +16 -16
  236. package/src/operations/insert.ts +9 -9
  237. package/src/operations/is_capped.ts +3 -3
  238. package/src/operations/list_collections.ts +6 -6
  239. package/src/operations/list_databases.ts +4 -4
  240. package/src/operations/map_reduce.ts +10 -9
  241. package/src/operations/operation.ts +3 -3
  242. package/src/operations/options_operation.ts +3 -3
  243. package/src/operations/profiling_level.ts +4 -4
  244. package/src/operations/remove_user.ts +4 -4
  245. package/src/operations/rename.ts +6 -6
  246. package/src/operations/run_command.ts +3 -3
  247. package/src/operations/set_profiling_level.ts +6 -5
  248. package/src/operations/stats.ts +4 -4
  249. package/src/operations/update.ts +10 -10
  250. package/src/operations/validate_collection.ts +4 -4
  251. package/src/read_preference.ts +18 -7
  252. package/src/sdam/common.ts +2 -2
  253. package/src/sdam/events.ts +5 -5
  254. package/src/sdam/monitor.ts +29 -32
  255. package/src/sdam/server.ts +64 -62
  256. package/src/sdam/server_description.ts +41 -48
  257. package/src/sdam/server_selection.ts +3 -3
  258. package/src/sdam/srv_polling.ts +3 -2
  259. package/src/sdam/topology.ts +71 -89
  260. package/src/sdam/topology_description.ts +5 -5
  261. package/src/sessions.ts +31 -48
  262. package/src/transactions.ts +4 -4
  263. package/src/utils.ts +64 -28
  264. package/lib/cmap/auth/defaultAuthProviders.js +0 -30
  265. package/lib/cmap/auth/defaultAuthProviders.js.map +0 -1
  266. package/src/cmap/auth/defaultAuthProviders.ts +0 -32
@@ -1,22 +1,23 @@
1
1
  // Resolves the default auth mechanism according to
2
-
3
2
  import type { Document } from '../../bson';
4
3
  import { MongoAPIError, MongoMissingCredentialsError } from '../../error';
5
- import { AuthMechanism } from './defaultAuthProviders';
4
+ import { emitWarningOnce } from '../../utils';
5
+ import { GSSAPICanonicalizationValue } from './gssapi';
6
+ import { AUTH_MECHS_AUTH_SRC_EXTERNAL, AuthMechanism } from './providers';
6
7
 
7
8
  // https://github.com/mongodb/specifications/blob/master/source/auth/auth.rst
8
- function getDefaultAuthMechanism(ismaster?: Document): AuthMechanism {
9
- if (ismaster) {
10
- // If ismaster contains saslSupportedMechs, use scram-sha-256
9
+ function getDefaultAuthMechanism(hello?: Document): AuthMechanism {
10
+ if (hello) {
11
+ // If hello contains saslSupportedMechs, use scram-sha-256
11
12
  // if it is available, else scram-sha-1
12
- if (Array.isArray(ismaster.saslSupportedMechs)) {
13
- return ismaster.saslSupportedMechs.includes(AuthMechanism.MONGODB_SCRAM_SHA256)
13
+ if (Array.isArray(hello.saslSupportedMechs)) {
14
+ return hello.saslSupportedMechs.includes(AuthMechanism.MONGODB_SCRAM_SHA256)
14
15
  ? AuthMechanism.MONGODB_SCRAM_SHA256
15
16
  : AuthMechanism.MONGODB_SCRAM_SHA1;
16
17
  }
17
18
 
18
19
  // Fallback to legacy selection method. If wire version >= 3, use scram-sha-1
19
- if (ismaster.maxWireVersion >= 3) {
20
+ if (hello.maxWireVersion >= 3) {
20
21
  return AuthMechanism.MONGODB_SCRAM_SHA1;
21
22
  }
22
23
  }
@@ -27,9 +28,10 @@ function getDefaultAuthMechanism(ismaster?: Document): AuthMechanism {
27
28
 
28
29
  /** @public */
29
30
  export interface AuthMechanismProperties extends Document {
31
+ SERVICE_HOST?: string;
30
32
  SERVICE_NAME?: string;
31
33
  SERVICE_REALM?: string;
32
- CANONICALIZE_HOST_NAME?: boolean;
34
+ CANONICALIZE_HOST_NAME?: GSSAPICanonicalizationValue;
33
35
  AWS_SESSION_TOKEN?: string;
34
36
  }
35
37
 
@@ -89,6 +91,14 @@ export class MongoCredentials {
89
91
  }
90
92
  }
91
93
 
94
+ if ('gssapiCanonicalizeHostName' in this.mechanismProperties) {
95
+ emitWarningOnce(
96
+ 'gssapiCanonicalizeHostName is deprecated. Please use CANONICALIZE_HOST_NAME instead.'
97
+ );
98
+ this.mechanismProperties.CANONICALIZE_HOST_NAME =
99
+ this.mechanismProperties.gssapiCanonicalizeHostName;
100
+ }
101
+
92
102
  Object.freeze(this.mechanismProperties);
93
103
  Object.freeze(this);
94
104
  }
@@ -107,16 +117,16 @@ export class MongoCredentials {
107
117
  * If the authentication mechanism is set to "default", resolves the authMechanism
108
118
  * based on the server version and server supported sasl mechanisms.
109
119
  *
110
- * @param ismaster - An ismaster response from the server
120
+ * @param hello - A hello response from the server
111
121
  */
112
- resolveAuthMechanism(ismaster?: Document): MongoCredentials {
122
+ resolveAuthMechanism(hello?: Document): MongoCredentials {
113
123
  // If the mechanism is not "default", then it does not need to be resolved
114
124
  if (this.mechanism.match(/DEFAULT/i)) {
115
125
  return new MongoCredentials({
116
126
  username: this.username,
117
127
  password: this.password,
118
128
  source: this.source,
119
- mechanism: getDefaultAuthMechanism(ismaster),
129
+ mechanism: getDefaultAuthMechanism(hello),
120
130
  mechanismProperties: this.mechanismProperties
121
131
  });
122
132
  }
@@ -136,11 +146,7 @@ export class MongoCredentials {
136
146
  throw new MongoMissingCredentialsError(`Username required for mechanism '${this.mechanism}'`);
137
147
  }
138
148
 
139
- if (
140
- this.mechanism === AuthMechanism.MONGODB_GSSAPI ||
141
- this.mechanism === AuthMechanism.MONGODB_AWS ||
142
- this.mechanism === AuthMechanism.MONGODB_X509
143
- ) {
149
+ if (AUTH_MECHS_AUTH_SRC_EXTERNAL.has(this.mechanism)) {
144
150
  if (this.source != null && this.source !== '$external') {
145
151
  // TODO(NODE-3485): Replace this with a MongoAuthValidationError
146
152
  throw new MongoAPIError(
@@ -162,6 +168,11 @@ export class MongoCredentials {
162
168
  // TODO(NODE-3485): Replace this with a MongoAuthValidationError
163
169
  throw new MongoAPIError(`Password not allowed for mechanism MONGODB-X509`);
164
170
  }
171
+
172
+ const canonicalization = this.mechanismProperties.CANONICALIZE_HOST_NAME ?? false;
173
+ if (!Object.values(GSSAPICanonicalizationValue).includes(canonicalization)) {
174
+ throw new MongoAPIError(`Invalid CANONICALIZE_HOST_NAME value: ${canonicalization}`);
175
+ }
165
176
  }
166
177
 
167
178
  static merge(
@@ -1,7 +1,8 @@
1
1
  import * as crypto from 'crypto';
2
- import { AuthProvider, AuthContext } from './auth_provider';
3
- import { Callback, ns } from '../../utils';
2
+
4
3
  import { MongoMissingCredentialsError } from '../../error';
4
+ import { Callback, ns } from '../../utils';
5
+ import { AuthContext, AuthProvider } from './auth_provider';
5
6
 
6
7
  export class MongoCR extends AuthProvider {
7
8
  auth(authContext: AuthContext, callback: Callback): void {
@@ -1,20 +1,19 @@
1
- import * as http from 'http';
2
1
  import * as crypto from 'crypto';
2
+ import * as http from 'http';
3
3
  import * as url from 'url';
4
+
5
+ import type { Binary, BSONSerializeOptions } from '../../bson';
4
6
  import * as BSON from '../../bson';
5
- import { AuthProvider, AuthContext } from './auth_provider';
6
- import { MongoCredentials } from './mongo_credentials';
7
+ import { aws4 } from '../../deps';
7
8
  import {
8
- MongoRuntimeError,
9
+ MongoCompatibilityError,
9
10
  MongoMissingCredentialsError,
10
- MongoCompatibilityError
11
+ MongoRuntimeError
11
12
  } from '../../error';
12
- import { maxWireVersion, Callback, ns } from '../../utils';
13
- import type { BSONSerializeOptions } from '../../bson';
14
-
15
- import { aws4 } from '../../deps';
16
- import { AuthMechanism } from './defaultAuthProviders';
17
- import type { Binary } from 'bson';
13
+ import { Callback, maxWireVersion, ns } from '../../utils';
14
+ import { AuthContext, AuthProvider } from './auth_provider';
15
+ import { MongoCredentials } from './mongo_credentials';
16
+ import { AuthMechanism } from './providers';
18
17
 
19
18
  const ASCII_N = 110;
20
19
  const AWS_RELATIVE_URI = 'http://169.254.170.2';
@@ -1,7 +1,7 @@
1
1
  import { Binary } from '../../bson';
2
- import { AuthProvider, AuthContext } from './auth_provider';
3
2
  import { MongoMissingCredentialsError } from '../../error';
4
3
  import { Callback, ns } from '../../utils';
4
+ import { AuthContext, AuthProvider } from './auth_provider';
5
5
 
6
6
  export class Plain extends AuthProvider {
7
7
  auth(authContext: AuthContext, callback: Callback): void {
@@ -0,0 +1,21 @@
1
+ /** @public */
2
+ export const AuthMechanism = Object.freeze({
3
+ MONGODB_AWS: 'MONGODB-AWS',
4
+ MONGODB_CR: 'MONGODB-CR',
5
+ MONGODB_DEFAULT: 'DEFAULT',
6
+ MONGODB_GSSAPI: 'GSSAPI',
7
+ MONGODB_PLAIN: 'PLAIN',
8
+ MONGODB_SCRAM_SHA1: 'SCRAM-SHA-1',
9
+ MONGODB_SCRAM_SHA256: 'SCRAM-SHA-256',
10
+ MONGODB_X509: 'MONGODB-X509'
11
+ } as const);
12
+
13
+ /** @public */
14
+ export type AuthMechanism = typeof AuthMechanism[keyof typeof AuthMechanism];
15
+
16
+ /** @internal */
17
+ export const AUTH_MECHS_AUTH_SRC_EXTERNAL = new Set<AuthMechanism>([
18
+ AuthMechanism.MONGODB_GSSAPI,
19
+ AuthMechanism.MONGODB_AWS,
20
+ AuthMechanism.MONGODB_X509
21
+ ]);
@@ -1,19 +1,19 @@
1
1
  import * as crypto from 'crypto';
2
+
2
3
  import { Binary, Document } from '../../bson';
4
+ import { saslprep } from '../../deps';
3
5
  import {
4
6
  AnyError,
5
- MongoRuntimeError,
6
- MongoServerError,
7
7
  MongoInvalidArgumentError,
8
- MongoMissingCredentialsError
8
+ MongoMissingCredentialsError,
9
+ MongoRuntimeError,
10
+ MongoServerError
9
11
  } from '../../error';
10
- import { AuthProvider, AuthContext } from './auth_provider';
11
- import { Callback, ns, emitWarning } from '../../utils';
12
- import type { MongoCredentials } from './mongo_credentials';
12
+ import { Callback, emitWarning, ns } from '../../utils';
13
13
  import type { HandshakeDocument } from '../connect';
14
-
15
- import { saslprep } from '../../deps';
16
- import { AuthMechanism } from './defaultAuthProviders';
14
+ import { AuthContext, AuthProvider } from './auth_provider';
15
+ import type { MongoCredentials } from './mongo_credentials';
16
+ import { AuthMechanism } from './providers';
17
17
 
18
18
  type CryptoMethod = 'sha1' | 'sha256';
19
19
 
@@ -1,9 +1,9 @@
1
- import { AuthProvider, AuthContext } from './auth_provider';
2
- import { MongoMissingCredentialsError } from '../../error';
3
1
  import type { Document } from '../../bson';
2
+ import { MongoMissingCredentialsError } from '../../error';
4
3
  import { Callback, ns } from '../../utils';
5
- import type { MongoCredentials } from './mongo_credentials';
6
4
  import type { HandshakeDocument } from '../connect';
5
+ import { AuthContext, AuthProvider } from './auth_provider';
6
+ import type { MongoCredentials } from './mongo_credentials';
7
7
 
8
8
  export class X509 extends AuthProvider {
9
9
  prepare(handshakeDoc: HandshakeDocument, authContext: AuthContext, callback: Callback): void {
@@ -1,7 +1,8 @@
1
- import { GetMore, KillCursor, Msg, WriteProtocolMessageType } from './commands';
1
+ import type { Document, ObjectId } from '../bson';
2
+ import { LEGACY_HELLO_COMMAND, LEGACY_HELLO_COMMAND_CAMEL_CASE } from '../constants';
2
3
  import { calculateDurationInMs, deepCopy } from '../utils';
4
+ import { GetMore, KillCursor, Msg, WriteProtocolMessageType } from './commands';
3
5
  import type { Connection } from './connection';
4
- import type { Document, ObjectId } from '../bson';
5
6
 
6
7
  /**
7
8
  * An event indicating the start of a given
@@ -161,7 +162,7 @@ const SENSITIVE_COMMANDS = new Set([
161
162
  'copydb'
162
163
  ]);
163
164
 
164
- const HELLO_COMMANDS = new Set(['hello', 'ismaster', 'isMaster']);
165
+ const HELLO_COMMANDS = new Set(['hello', LEGACY_HELLO_COMMAND, LEGACY_HELLO_COMMAND_CAMEL_CASE]);
165
166
 
166
167
  // helper methods
167
168
  const extractCommandName = (commandDoc: Document) => Object.keys(commandDoc)[0];
@@ -1,18 +1,18 @@
1
- import { ReadPreference } from '../read_preference';
1
+ import type { BSONSerializeOptions, Document, Long } from '../bson';
2
2
  import * as BSON from '../bson';
3
- import { databaseNamespace } from '../utils';
4
- import { OP_QUERY, OP_GETMORE, OP_KILL_CURSORS, OP_MSG } from './wire_protocol/constants';
5
- import type { Long, Document, BSONSerializeOptions } from '../bson';
3
+ import { MongoInvalidArgumentError, MongoRuntimeError } from '../error';
4
+ import { ReadPreference } from '../read_preference';
6
5
  import type { ClientSession } from '../sessions';
6
+ import { databaseNamespace } from '../utils';
7
7
  import type { CommandOptions } from './connection';
8
- import { MongoRuntimeError, MongoInvalidArgumentError } from '../error';
8
+ import { OP_GETMORE, OP_KILL_CURSORS, OP_MSG, OP_QUERY } from './wire_protocol/constants';
9
9
 
10
10
  // Incrementing request id
11
11
  let _requestId = 0;
12
12
 
13
13
  // Query flags
14
14
  const OPTS_TAILABLE_CURSOR = 2;
15
- const OPTS_SLAVE = 4;
15
+ const OPTS_SECONDARY = 4;
16
16
  const OPTS_OPLOG_REPLAY = 8;
17
17
  const OPTS_NO_CURSOR_TIMEOUT = 16;
18
18
  const OPTS_AWAIT_DATA = 32;
@@ -41,7 +41,7 @@ export interface OpQueryOptions extends CommandOptions {
41
41
  ignoreUndefined?: boolean;
42
42
  maxBsonSize?: number;
43
43
  checkKeys?: boolean;
44
- slaveOk?: boolean;
44
+ secondaryOk?: boolean;
45
45
 
46
46
  requestId?: number;
47
47
  moreToCome?: boolean;
@@ -67,7 +67,7 @@ export class Query {
67
67
  checkKeys: boolean;
68
68
  batchSize: number;
69
69
  tailable: boolean;
70
- slaveOk: boolean;
70
+ secondaryOk: boolean;
71
71
  oplogReplay: boolean;
72
72
  noCursorTimeout: boolean;
73
73
  awaitData: boolean;
@@ -112,7 +112,7 @@ export class Query {
112
112
 
113
113
  // Flags
114
114
  this.tailable = false;
115
- this.slaveOk = typeof options.slaveOk === 'boolean' ? options.slaveOk : false;
115
+ this.secondaryOk = typeof options.secondaryOk === 'boolean' ? options.secondaryOk : false;
116
116
  this.oplogReplay = false;
117
117
  this.noCursorTimeout = false;
118
118
  this.awaitData = false;
@@ -146,8 +146,8 @@ export class Query {
146
146
  flags |= OPTS_TAILABLE_CURSOR;
147
147
  }
148
148
 
149
- if (this.slaveOk) {
150
- flags |= OPTS_SLAVE;
149
+ if (this.secondaryOk) {
150
+ flags |= OPTS_SECONDARY;
151
151
  }
152
152
 
153
153
  if (this.oplogReplay) {
@@ -469,8 +469,6 @@ export interface MessageHeader {
469
469
  export interface OpResponseOptions extends BSONSerializeOptions {
470
470
  raw?: boolean;
471
471
  documentsReturnedIn?: string | null;
472
- // For now we use this internally to only prevent writeErrors from crashing the driver
473
- validation?: { utf8: { writeErrors: boolean } };
474
472
  }
475
473
 
476
474
  /** @internal */
@@ -839,7 +837,7 @@ export class BinMsg {
839
837
  const promoteValues = options.promoteValues ?? this.opts.promoteValues;
840
838
  const promoteBuffers = options.promoteBuffers ?? this.opts.promoteBuffers;
841
839
  const bsonRegExp = options.bsonRegExp ?? this.opts.bsonRegExp;
842
- const validation = options.validation ?? { utf8: { writeErrors: false } };
840
+ const validation = this.parseBsonSerializationOptions(options);
843
841
 
844
842
  // Set up the options
845
843
  const bsonOptions: BSONSerializeOptions = {
@@ -876,4 +874,14 @@ export class BinMsg {
876
874
 
877
875
  this.parsed = true;
878
876
  }
877
+
878
+ parseBsonSerializationOptions({ enableUtf8Validation }: BSONSerializeOptions): {
879
+ utf8: { writeErrors: false } | false;
880
+ } {
881
+ if (enableUtf8Validation === false) {
882
+ return { utf8: false };
883
+ }
884
+
885
+ return { utf8: { writeErrors: false } };
886
+ }
879
887
  }
@@ -1,39 +1,60 @@
1
+ import type { Socket, SocketConnectOpts } from 'net';
1
2
  import * as net from 'net';
3
+ import { SocksClient } from 'socks';
4
+ import type { ConnectionOptions as TLSConnectionOpts, TLSSocket } from 'tls';
2
5
  import * as tls from 'tls';
3
- import { Connection, ConnectionOptions, CryptoConnection } from './connection';
6
+
7
+ import type { Document } from '../bson';
8
+ import { Int32 } from '../bson';
9
+ import { LEGACY_HELLO_COMMAND } from '../constants';
4
10
  import {
5
- MongoNetworkError,
6
- MongoNetworkTimeoutError,
7
11
  AnyError,
8
12
  MongoCompatibilityError,
9
13
  MongoInvalidArgumentError,
10
- MongoServerError,
11
- MongoRuntimeError
14
+ MongoNetworkError,
15
+ MongoNetworkTimeoutError,
16
+ MongoRuntimeError,
17
+ MongoServerError
12
18
  } from '../error';
13
- import { AUTH_PROVIDERS, AuthMechanism } from './auth/defaultAuthProviders';
14
- import { AuthContext } from './auth/auth_provider';
15
- import { makeClientMetadata, ClientMetadata, Callback, CallbackWithType, ns } from '../utils';
16
19
  import {
17
- MAX_SUPPORTED_WIRE_VERSION,
20
+ Callback,
21
+ CallbackWithType,
22
+ ClientMetadata,
23
+ HostAddress,
24
+ makeClientMetadata,
25
+ ns
26
+ } from '../utils';
27
+ import { AuthContext, AuthProvider } from './auth/auth_provider';
28
+ import { GSSAPI } from './auth/gssapi';
29
+ import { MongoCR } from './auth/mongocr';
30
+ import { MongoDBAWS } from './auth/mongodb_aws';
31
+ import { Plain } from './auth/plain';
32
+ import { AuthMechanism } from './auth/providers';
33
+ import { ScramSHA1, ScramSHA256 } from './auth/scram';
34
+ import { X509 } from './auth/x509';
35
+ import { Connection, ConnectionOptions, CryptoConnection } from './connection';
36
+ import {
18
37
  MAX_SUPPORTED_SERVER_VERSION,
19
- MIN_SUPPORTED_WIRE_VERSION,
20
- MIN_SUPPORTED_SERVER_VERSION
38
+ MAX_SUPPORTED_WIRE_VERSION,
39
+ MIN_SUPPORTED_SERVER_VERSION,
40
+ MIN_SUPPORTED_WIRE_VERSION
21
41
  } from './wire_protocol/constants';
22
- import type { Document } from '../bson';
23
- import { Int32 } from '../bson';
24
42
 
25
- import type { Socket, SocketConnectOpts } from 'net';
26
- import type { TLSSocket, ConnectionOptions as TLSConnectionOpts } from 'tls';
27
-
28
- const FAKE_MONGODB_SERVICE_ID =
29
- typeof process.env.FAKE_MONGODB_SERVICE_ID === 'string' &&
30
- process.env.FAKE_MONGODB_SERVICE_ID.toLowerCase() === 'true';
43
+ const AUTH_PROVIDERS = new Map<AuthMechanism | string, AuthProvider>([
44
+ [AuthMechanism.MONGODB_AWS, new MongoDBAWS()],
45
+ [AuthMechanism.MONGODB_CR, new MongoCR()],
46
+ [AuthMechanism.MONGODB_GSSAPI, new GSSAPI()],
47
+ [AuthMechanism.MONGODB_PLAIN, new Plain()],
48
+ [AuthMechanism.MONGODB_SCRAM_SHA1, new ScramSHA1()],
49
+ [AuthMechanism.MONGODB_SCRAM_SHA256, new ScramSHA256()],
50
+ [AuthMechanism.MONGODB_X509, new X509()]
51
+ ]);
31
52
 
32
53
  /** @public */
33
54
  export type Stream = Socket | TLSSocket;
34
55
 
35
56
  export function connect(options: ConnectionOptions, callback: Callback<Connection>): void {
36
- makeConnection(options, (err, socket) => {
57
+ makeConnection({ ...options, existingSocket: undefined }, (err, socket) => {
37
58
  if (err || !socket) {
38
59
  return callback(err);
39
60
  }
@@ -46,15 +67,15 @@ export function connect(options: ConnectionOptions, callback: Callback<Connectio
46
67
  });
47
68
  }
48
69
 
49
- function checkSupportedServer(ismaster: Document, options: ConnectionOptions) {
70
+ function checkSupportedServer(hello: Document, options: ConnectionOptions) {
50
71
  const serverVersionHighEnough =
51
- ismaster &&
52
- (typeof ismaster.maxWireVersion === 'number' || ismaster.maxWireVersion instanceof Int32) &&
53
- ismaster.maxWireVersion >= MIN_SUPPORTED_WIRE_VERSION;
72
+ hello &&
73
+ (typeof hello.maxWireVersion === 'number' || hello.maxWireVersion instanceof Int32) &&
74
+ hello.maxWireVersion >= MIN_SUPPORTED_WIRE_VERSION;
54
75
  const serverVersionLowEnough =
55
- ismaster &&
56
- (typeof ismaster.minWireVersion === 'number' || ismaster.minWireVersion instanceof Int32) &&
57
- ismaster.minWireVersion <= MAX_SUPPORTED_WIRE_VERSION;
76
+ hello &&
77
+ (typeof hello.minWireVersion === 'number' || hello.minWireVersion instanceof Int32) &&
78
+ hello.minWireVersion <= MAX_SUPPORTED_WIRE_VERSION;
58
79
 
59
80
  if (serverVersionHighEnough) {
60
81
  if (serverVersionLowEnough) {
@@ -62,13 +83,13 @@ function checkSupportedServer(ismaster: Document, options: ConnectionOptions) {
62
83
  }
63
84
 
64
85
  const message = `Server at ${options.hostAddress} reports minimum wire version ${JSON.stringify(
65
- ismaster.minWireVersion
86
+ hello.minWireVersion
66
87
  )}, but this version of the Node.js Driver requires at most ${MAX_SUPPORTED_WIRE_VERSION} (MongoDB ${MAX_SUPPORTED_SERVER_VERSION})`;
67
88
  return new MongoCompatibilityError(message);
68
89
  }
69
90
 
70
91
  const message = `Server at ${options.hostAddress} reports maximum wire version ${
71
- JSON.stringify(ismaster.maxWireVersion) ?? 0
92
+ JSON.stringify(hello.maxWireVersion) ?? 0
72
93
  }, but this version of the Node.js Driver requires at least ${MIN_SUPPORTED_WIRE_VERSION} (MongoDB ${MIN_SUPPORTED_SERVER_VERSION})`;
73
94
  return new MongoCompatibilityError(message);
74
95
  }
@@ -122,9 +143,9 @@ function performInitialHandshake(
122
143
  return;
123
144
  }
124
145
 
125
- if ('isWritablePrimary' in response) {
126
- // Provide pre-hello-style response document.
127
- response.ismaster = response.isWritablePrimary;
146
+ if (!('isWritablePrimary' in response)) {
147
+ // Provide hello-style response document.
148
+ response.isWritablePrimary = response[LEGACY_HELLO_COMMAND];
128
149
  }
129
150
 
130
151
  if (response.helloOk) {
@@ -138,10 +159,6 @@ function performInitialHandshake(
138
159
  }
139
160
 
140
161
  if (options.loadBalanced) {
141
- // TODO: Durran: Remove when server support exists. (NODE-3431)
142
- if (FAKE_MONGODB_SERVICE_ID) {
143
- response.serviceId = response.topologyVersion.processId;
144
- }
145
162
  if (!response.serviceId) {
146
163
  return callback(
147
164
  new MongoCompatibilityError(
@@ -155,8 +172,8 @@ function performInitialHandshake(
155
172
  // NOTE: This is metadata attached to the connection while porting away from
156
173
  // handshake being done in the `Server` class. Likely, it should be
157
174
  // relocated, or at very least restructured.
158
- conn.ismaster = response;
159
- conn.lastIsMasterMS = new Date().getTime() - start;
175
+ conn.hello = response;
176
+ conn.lastHelloMS = new Date().getTime() - start;
160
177
 
161
178
  if (!response.arbiterOnly && credentials) {
162
179
  // store the response on auth context
@@ -185,6 +202,9 @@ function performInitialHandshake(
185
202
  }
186
203
 
187
204
  export interface HandshakeDocument extends Document {
205
+ /**
206
+ * @deprecated Use hello instead
207
+ */
188
208
  ismaster?: boolean;
189
209
  hello?: boolean;
190
210
  helloOk?: boolean;
@@ -200,7 +220,7 @@ function prepareHandshakeDocument(authContext: AuthContext, callback: Callback<H
200
220
  const { serverApi } = authContext.connection;
201
221
 
202
222
  const handshakeDoc: HandshakeDocument = {
203
- [serverApi?.version ? 'hello' : 'ismaster']: true,
223
+ [serverApi?.version ? 'hello' : LEGACY_HELLO_COMMAND]: true,
204
224
  helloOk: true,
205
225
  client: options.metadata || makeClientMetadata(options),
206
226
  compression: compressors,
@@ -289,7 +309,9 @@ function parseConnectOptions(options: ConnectionOptions): SocketConnectOpts {
289
309
  }
290
310
  }
291
311
 
292
- function parseSslOptions(options: ConnectionOptions): TLSConnectionOpts {
312
+ type MakeConnectionOptions = ConnectionOptions & { existingSocket?: Stream };
313
+
314
+ function parseSslOptions(options: MakeConnectionOptions): TLSConnectionOpts {
293
315
  const result: TLSConnectionOpts = parseConnectOptions(options);
294
316
  // Merge in valid SSL options
295
317
  for (const name of LEGAL_TLS_SOCKET_OPTIONS) {
@@ -298,6 +320,10 @@ function parseSslOptions(options: ConnectionOptions): TLSConnectionOpts {
298
320
  }
299
321
  }
300
322
 
323
+ if (options.existingSocket) {
324
+ result.socket = options.existingSocket;
325
+ }
326
+
301
327
  // Set default sni servername to be the same as host
302
328
  if (result.servername == null && result.host && !net.isIP(result.host)) {
303
329
  result.servername = result.host;
@@ -310,17 +336,21 @@ const SOCKET_ERROR_EVENT_LIST = ['error', 'close', 'timeout', 'parseError'] as c
310
336
  type ErrorHandlerEventName = typeof SOCKET_ERROR_EVENT_LIST[number] | 'cancel';
311
337
  const SOCKET_ERROR_EVENTS = new Set(SOCKET_ERROR_EVENT_LIST);
312
338
 
313
- function makeConnection(options: ConnectionOptions, _callback: CallbackWithType<AnyError, Stream>) {
339
+ function makeConnection(
340
+ options: MakeConnectionOptions,
341
+ _callback: CallbackWithType<AnyError, Stream>
342
+ ) {
314
343
  const useTLS = options.tls ?? false;
315
344
  const keepAlive = options.keepAlive ?? true;
316
345
  const socketTimeoutMS = options.socketTimeoutMS ?? Reflect.get(options, 'socketTimeout') ?? 0;
317
346
  const noDelay = options.noDelay ?? true;
318
- const connectionTimeout = options.connectTimeoutMS ?? 30000;
347
+ const connectTimeoutMS = options.connectTimeoutMS ?? 30000;
319
348
  const rejectUnauthorized = options.rejectUnauthorized ?? true;
320
349
  const keepAliveInitialDelay =
321
350
  ((options.keepAliveInitialDelay ?? 120000) > socketTimeoutMS
322
351
  ? Math.round(socketTimeoutMS / 2)
323
352
  : options.keepAliveInitialDelay) ?? 120000;
353
+ const existingSocket = options.existingSocket;
324
354
 
325
355
  let socket: Stream;
326
356
  const callback: Callback<Stream> = function (err, ret) {
@@ -331,18 +361,34 @@ function makeConnection(options: ConnectionOptions, _callback: CallbackWithType<
331
361
  _callback(err, ret);
332
362
  };
333
363
 
364
+ if (options.proxyHost != null) {
365
+ // Currently, only Socks5 is supported.
366
+ return makeSocks5Connection(
367
+ {
368
+ ...options,
369
+ connectTimeoutMS // Should always be present for Socks5
370
+ },
371
+ callback
372
+ );
373
+ }
374
+
334
375
  if (useTLS) {
335
376
  const tlsSocket = tls.connect(parseSslOptions(options));
336
377
  if (typeof tlsSocket.disableRenegotiation === 'function') {
337
378
  tlsSocket.disableRenegotiation();
338
379
  }
339
380
  socket = tlsSocket;
381
+ } else if (existingSocket) {
382
+ // In the TLS case, parseSslOptions() sets options.socket to existingSocket,
383
+ // so we only need to handle the non-TLS case here (where existingSocket
384
+ // gives us all we need out of the box).
385
+ socket = existingSocket;
340
386
  } else {
341
387
  socket = net.createConnection(parseConnectOptions(options));
342
388
  }
343
389
 
344
390
  socket.setKeepAlive(keepAlive, keepAliveInitialDelay);
345
- socket.setTimeout(connectionTimeout);
391
+ socket.setTimeout(connectTimeoutMS);
346
392
  socket.setNoDelay(noDelay);
347
393
 
348
394
  const connectEvent = useTLS ? 'secureConnect' : 'connect';
@@ -381,10 +427,80 @@ function makeConnection(options: ConnectionOptions, _callback: CallbackWithType<
381
427
  options.cancellationToken.once('cancel', cancellationHandler);
382
428
  }
383
429
 
384
- socket.once(connectEvent, connectHandler);
430
+ if (existingSocket) {
431
+ process.nextTick(connectHandler);
432
+ } else {
433
+ socket.once(connectEvent, connectHandler);
434
+ }
435
+ }
436
+
437
+ function makeSocks5Connection(options: MakeConnectionOptions, callback: Callback<Stream>) {
438
+ const hostAddress = HostAddress.fromHostPort(
439
+ options.proxyHost ?? '', // proxyHost is guaranteed to set here
440
+ options.proxyPort ?? 1080
441
+ );
442
+
443
+ // First, connect to the proxy server itself:
444
+ makeConnection(
445
+ {
446
+ ...options,
447
+ hostAddress,
448
+ tls: false,
449
+ proxyHost: undefined
450
+ },
451
+ (err, rawSocket) => {
452
+ if (err) {
453
+ return callback(err);
454
+ }
455
+
456
+ const destination = parseConnectOptions(options) as net.TcpNetConnectOpts;
457
+ if (typeof destination.host !== 'string' || typeof destination.port !== 'number') {
458
+ return callback(
459
+ new MongoInvalidArgumentError('Can only make Socks5 connections to TCP hosts')
460
+ );
461
+ }
462
+
463
+ // Then, establish the Socks5 proxy connection:
464
+ SocksClient.createConnection(
465
+ {
466
+ existing_socket: rawSocket,
467
+ timeout: options.connectTimeoutMS,
468
+ command: 'connect',
469
+ destination: {
470
+ host: destination.host,
471
+ port: destination.port
472
+ },
473
+ proxy: {
474
+ // host and port are ignored because we pass existing_socket
475
+ host: 'iLoveJavaScript',
476
+ port: 0,
477
+ type: 5,
478
+ userId: options.proxyUsername || undefined,
479
+ password: options.proxyPassword || undefined
480
+ }
481
+ },
482
+ (err: AnyError, info: { socket: Stream }) => {
483
+ if (err) {
484
+ return callback(connectionFailureError('error', err));
485
+ }
486
+
487
+ // Finally, now treat the resulting duplex stream as the
488
+ // socket over which we send and receive wire protocol messages:
489
+ makeConnection(
490
+ {
491
+ ...options,
492
+ existingSocket: info.socket,
493
+ proxyHost: undefined
494
+ },
495
+ callback
496
+ );
497
+ }
498
+ );
499
+ }
500
+ );
385
501
  }
386
502
 
387
- function connectionFailureError(type: string, err: Error) {
503
+ function connectionFailureError(type: ErrorHandlerEventName, err: Error) {
388
504
  switch (type) {
389
505
  case 'error':
390
506
  return new MongoNetworkError(err);