mongodb 5.0.1 → 5.2.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 (146) hide show
  1. package/README.md +25 -22
  2. package/lib/bson.js +3 -1
  3. package/lib/bson.js.map +1 -1
  4. package/lib/change_stream.js +3 -2
  5. package/lib/change_stream.js.map +1 -1
  6. package/lib/cmap/auth/auth_provider.js +21 -10
  7. package/lib/cmap/auth/auth_provider.js.map +1 -1
  8. package/lib/cmap/auth/gssapi.js +71 -116
  9. package/lib/cmap/auth/gssapi.js.map +1 -1
  10. package/lib/cmap/auth/mongo_credentials.js +17 -0
  11. package/lib/cmap/auth/mongo_credentials.js.map +1 -1
  12. package/lib/cmap/auth/mongocr.js +20 -29
  13. package/lib/cmap/auth/mongocr.js.map +1 -1
  14. package/lib/cmap/auth/mongodb_aws.js +126 -140
  15. package/lib/cmap/auth/mongodb_aws.js.map +1 -1
  16. package/lib/cmap/auth/mongodb_oidc/aws_service_workflow.js +28 -0
  17. package/lib/cmap/auth/mongodb_oidc/aws_service_workflow.js.map +1 -0
  18. package/lib/cmap/auth/mongodb_oidc/callback_workflow.js +178 -0
  19. package/lib/cmap/auth/mongodb_oidc/callback_workflow.js.map +1 -0
  20. package/lib/cmap/auth/mongodb_oidc/service_workflow.js +41 -0
  21. package/lib/cmap/auth/mongodb_oidc/service_workflow.js.map +1 -0
  22. package/lib/cmap/auth/mongodb_oidc/token_entry_cache.js +115 -0
  23. package/lib/cmap/auth/mongodb_oidc/token_entry_cache.js.map +1 -0
  24. package/lib/cmap/auth/mongodb_oidc/workflow.js +3 -0
  25. package/lib/cmap/auth/mongodb_oidc/workflow.js.map +1 -0
  26. package/lib/cmap/auth/mongodb_oidc.js +62 -0
  27. package/lib/cmap/auth/mongodb_oidc.js.map +1 -0
  28. package/lib/cmap/auth/plain.js +4 -5
  29. package/lib/cmap/auth/plain.js.map +1 -1
  30. package/lib/cmap/auth/providers.js +4 -1
  31. package/lib/cmap/auth/providers.js.map +1 -1
  32. package/lib/cmap/auth/scram.js +45 -73
  33. package/lib/cmap/auth/scram.js.map +1 -1
  34. package/lib/cmap/auth/x509.js +8 -11
  35. package/lib/cmap/auth/x509.js.map +1 -1
  36. package/lib/cmap/command_monitoring_events.js +8 -5
  37. package/lib/cmap/command_monitoring_events.js.map +1 -1
  38. package/lib/cmap/commands.js +9 -1
  39. package/lib/cmap/commands.js.map +1 -1
  40. package/lib/cmap/connect.js +72 -86
  41. package/lib/cmap/connect.js.map +1 -1
  42. package/lib/cmap/connection.js +68 -74
  43. package/lib/cmap/connection.js.map +1 -1
  44. package/lib/cmap/connection_pool.js +51 -13
  45. package/lib/cmap/connection_pool.js.map +1 -1
  46. package/lib/cmap/message_stream.js.map +1 -1
  47. package/lib/cmap/wire_protocol/shared.js +1 -16
  48. package/lib/cmap/wire_protocol/shared.js.map +1 -1
  49. package/lib/collection.js +10 -10
  50. package/lib/connection_string.js +47 -33
  51. package/lib/connection_string.js.map +1 -1
  52. package/lib/cursor/abstract_cursor.js +13 -7
  53. package/lib/cursor/abstract_cursor.js.map +1 -1
  54. package/lib/cursor/find_cursor.js +1 -1
  55. package/lib/db.js +3 -2
  56. package/lib/db.js.map +1 -1
  57. package/lib/error.js +2 -1
  58. package/lib/error.js.map +1 -1
  59. package/lib/mongo_client.js +22 -2
  60. package/lib/mongo_client.js.map +1 -1
  61. package/lib/mongo_logger.js +17 -1
  62. package/lib/mongo_logger.js.map +1 -1
  63. package/lib/operations/aggregate.js +4 -1
  64. package/lib/operations/aggregate.js.map +1 -1
  65. package/lib/operations/create_collection.js +1 -0
  66. package/lib/operations/create_collection.js.map +1 -1
  67. package/lib/operations/execute_operation.js +8 -27
  68. package/lib/operations/execute_operation.js.map +1 -1
  69. package/lib/operations/find.js +3 -2
  70. package/lib/operations/find.js.map +1 -1
  71. package/lib/operations/indexes.js +2 -1
  72. package/lib/operations/indexes.js.map +1 -1
  73. package/lib/operations/list_collections.js +2 -1
  74. package/lib/operations/list_collections.js.map +1 -1
  75. package/lib/read_concern.js +1 -1
  76. package/lib/read_preference.js +2 -2
  77. package/lib/sdam/monitor.js +1 -0
  78. package/lib/sdam/monitor.js.map +1 -1
  79. package/lib/sdam/server.js +4 -2
  80. package/lib/sdam/server.js.map +1 -1
  81. package/lib/sdam/topology.js +3 -26
  82. package/lib/sdam/topology.js.map +1 -1
  83. package/lib/sessions.js +2 -1
  84. package/lib/sessions.js.map +1 -1
  85. package/lib/utils.js +15 -70
  86. package/lib/utils.js.map +1 -1
  87. package/lib/write_concern.js +1 -1
  88. package/mongodb.d.ts +137 -68
  89. package/package.json +30 -30
  90. package/src/bson.ts +3 -1
  91. package/src/bulk/common.ts +1 -1
  92. package/src/change_stream.ts +16 -8
  93. package/src/cmap/auth/auth_provider.ts +29 -16
  94. package/src/cmap/auth/gssapi.ts +102 -149
  95. package/src/cmap/auth/mongo_credentials.ts +47 -1
  96. package/src/cmap/auth/mongocr.ts +31 -36
  97. package/src/cmap/auth/mongodb_aws.ts +167 -189
  98. package/src/cmap/auth/mongodb_oidc/aws_service_workflow.ts +26 -0
  99. package/src/cmap/auth/mongodb_oidc/callback_workflow.ts +259 -0
  100. package/src/cmap/auth/mongodb_oidc/service_workflow.ts +47 -0
  101. package/src/cmap/auth/mongodb_oidc/token_entry_cache.ts +166 -0
  102. package/src/cmap/auth/mongodb_oidc/workflow.ts +21 -0
  103. package/src/cmap/auth/mongodb_oidc.ts +123 -0
  104. package/src/cmap/auth/plain.ts +6 -6
  105. package/src/cmap/auth/providers.ts +5 -2
  106. package/src/cmap/auth/scram.ts +56 -90
  107. package/src/cmap/auth/x509.ts +12 -18
  108. package/src/cmap/command_monitoring_events.ts +5 -2
  109. package/src/cmap/commands.ts +11 -1
  110. package/src/cmap/connect.ts +90 -114
  111. package/src/cmap/connection.ts +92 -90
  112. package/src/cmap/connection_pool.ts +77 -16
  113. package/src/cmap/message_stream.ts +0 -2
  114. package/src/cmap/wire_protocol/compression.ts +1 -1
  115. package/src/cmap/wire_protocol/shared.ts +1 -23
  116. package/src/collection.ts +11 -11
  117. package/src/connection_string.ts +52 -35
  118. package/src/cursor/abstract_cursor.ts +13 -6
  119. package/src/cursor/change_stream_cursor.ts +5 -5
  120. package/src/cursor/find_cursor.ts +1 -1
  121. package/src/db.ts +3 -2
  122. package/src/deps.ts +56 -38
  123. package/src/error.ts +3 -2
  124. package/src/index.ts +7 -0
  125. package/src/mongo_client.ts +35 -10
  126. package/src/mongo_logger.ts +20 -2
  127. package/src/mongo_types.ts +4 -3
  128. package/src/operations/aggregate.ts +4 -2
  129. package/src/operations/create_collection.ts +2 -1
  130. package/src/operations/execute_operation.ts +8 -25
  131. package/src/operations/find.ts +13 -4
  132. package/src/operations/find_and_modify.ts +4 -4
  133. package/src/operations/indexes.ts +12 -4
  134. package/src/operations/list_collections.ts +11 -3
  135. package/src/operations/set_profiling_level.ts +1 -1
  136. package/src/operations/stats.ts +1 -1
  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/monitor.ts +1 -0
  141. package/src/sdam/server.ts +4 -1
  142. package/src/sdam/topology.ts +4 -33
  143. package/src/sessions.ts +2 -1
  144. package/src/transactions.ts +1 -1
  145. package/src/utils.ts +24 -98
  146. package/src/write_concern.ts +1 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mongodb",
3
- "version": "5.0.1",
3
+ "version": "5.2.0",
4
4
  "description": "The official MongoDB driver for Node.js",
5
5
  "main": "lib/index.js",
6
6
  "files": [
@@ -25,7 +25,7 @@
25
25
  "email": "dbx-node@mongodb.com"
26
26
  },
27
27
  "dependencies": {
28
- "bson": "^5.0.0",
28
+ "bson": "^5.2.0",
29
29
  "mongodb-connection-string-url": "^2.6.0",
30
30
  "socks": "^2.7.1"
31
31
  },
@@ -49,54 +49,53 @@
49
49
  }
50
50
  },
51
51
  "devDependencies": {
52
- "@aws-sdk/credential-providers": "^3.201.0",
53
52
  "@iarna/toml": "^2.2.5",
54
53
  "@istanbuljs/nyc-config-typescript": "^1.0.2",
55
- "@microsoft/api-extractor": "^7.33.7",
54
+ "@microsoft/api-extractor": "^7.34.4",
56
55
  "@microsoft/tsdoc-config": "^0.16.2",
57
- "@mongodb-js/zstd": "^1.0.0",
58
- "@types/chai": "^4.3.3",
56
+ "@mongodb-js/zstd": "^1.1.0",
57
+ "@types/chai": "^4.3.4",
59
58
  "@types/chai-subset": "^1.3.3",
60
- "@types/express": "^4.17.14",
59
+ "@types/express": "^4.17.17",
61
60
  "@types/kerberos": "^1.1.1",
62
- "@types/mocha": "^10.0.0",
63
- "@types/node": "^18.11.0",
61
+ "@types/mocha": "^10.0.1",
62
+ "@types/node": "^18.11.19",
64
63
  "@types/saslprep": "^1.0.1",
65
- "@types/semver": "^7.3.12",
64
+ "@types/semver": "^7.3.13",
66
65
  "@types/sinon": "^10.0.13",
67
- "@types/sinon-chai": "^3.2.8",
66
+ "@types/sinon-chai": "^3.2.9",
68
67
  "@types/whatwg-url": "^11.0.0",
69
- "@typescript-eslint/eslint-plugin": "^5.48.0",
70
- "@typescript-eslint/parser": "^5.48.0",
71
- "chai": "^4.3.6",
68
+ "@typescript-eslint/eslint-plugin": "^5.55.0",
69
+ "@typescript-eslint/parser": "^5.55.0",
70
+ "chai": "^4.3.7",
72
71
  "chai-subset": "^1.6.0",
73
72
  "chalk": "^4.1.2",
74
- "eslint": "^8.31.0",
75
- "eslint-config-prettier": "^8.5.0",
76
- "eslint-plugin-import": "^2.26.0",
73
+ "eslint": "^8.36.0",
74
+ "eslint-config-prettier": "^8.7.0",
75
+ "eslint-plugin-import": "^2.27.5",
77
76
  "eslint-plugin-prettier": "^4.2.1",
78
- "eslint-plugin-simple-import-sort": "^8.0.0",
77
+ "eslint-plugin-simple-import-sort": "^10.0.0",
79
78
  "eslint-plugin-tsdoc": "^0.2.17",
80
79
  "express": "^4.18.2",
81
80
  "js-yaml": "^4.1.0",
82
- "mocha": "^9.2.2",
81
+ "mocha": "^10.2.0",
83
82
  "mocha-sinon": "^2.1.2",
84
- "mongodb-legacy": "^4.0.0",
83
+ "mongodb-legacy": "^5.0.0",
85
84
  "nyc": "^15.1.0",
86
- "prettier": "^2.7.1",
87
- "rimraf": "^3.0.2",
85
+ "prettier": "^2.8.4",
88
86
  "semver": "^7.3.8",
89
- "sinon": "^13.0.1",
87
+ "sinon": "^15.0.2",
90
88
  "sinon-chai": "^3.7.0",
91
89
  "snappy": "^7.2.2",
92
90
  "source-map-support": "^0.5.21",
93
91
  "standard-version": "^9.5.0",
94
92
  "ts-node": "^10.9.1",
95
- "tsd": "^0.25.0",
96
- "typescript": "^4.9.4",
93
+ "tsd": "^0.27.0",
94
+ "typescript": "^4.9.5",
97
95
  "typescript-cached-transpile": "^0.0.6",
96
+ "v8-heapsnapshot": "^1.2.0",
98
97
  "xml2js": "^0.4.23",
99
- "yargs": "^17.6.0"
98
+ "yargs": "^17.7.1"
100
99
  },
101
100
  "license": "Apache-2.0",
102
101
  "engines": {
@@ -109,7 +108,7 @@
109
108
  "scripts": {
110
109
  "build:evergreen": "node .evergreen/generate_evergreen_tasks.js",
111
110
  "build:ts": "node ./node_modules/typescript/bin/tsc",
112
- "build:dts": "npm run build:ts && api-extractor run && rimraf 'lib/**/*.d.ts*'",
111
+ "build:dts": "npm run build:ts && api-extractor run && node etc/clean_definition_files.cjs",
113
112
  "build:docs": "./etc/docs/build.ts",
114
113
  "build:typedoc": "typedoc",
115
114
  "check:bench": "node test/benchmarks/driverBench",
@@ -127,11 +126,12 @@
127
126
  "check:ts": "node ./node_modules/typescript/bin/tsc -v && node ./node_modules/typescript/bin/tsc --noEmit",
128
127
  "check:atlas": "mocha --config test/manual/mocharc.json test/manual/atlas_connectivity.test.js",
129
128
  "check:adl": "mocha --config test/mocha_mongodb.json test/manual/atlas-data-lake-testing",
130
- "check:aws": "mocha --config test/mocha_mongodb.json test/integration/auth/mongodb_aws.test.ts",
129
+ "check:aws": "nyc mocha --config test/mocha_mongodb.json test/integration/auth/mongodb_aws.test.ts",
130
+ "check:oidc": "mocha --config test/manual/mocharc.json test/manual/mongodb_oidc.prose.test.ts",
131
131
  "check:ocsp": "mocha --config test/manual/mocharc.json test/manual/ocsp_support.test.js",
132
- "check:kerberos": "mocha --config test/manual/mocharc.json test/manual/kerberos.test.js",
132
+ "check:kerberos": "nyc mocha --config test/manual/mocharc.json test/manual/kerberos.test.ts",
133
133
  "check:tls": "mocha --config test/manual/mocharc.json test/manual/tls_support.test.js",
134
- "check:ldap": "mocha --config test/manual/mocharc.json test/manual/ldap.test.js",
134
+ "check:ldap": "nyc mocha --config test/manual/mocharc.json test/manual/ldap.test.js",
135
135
  "check:socks5": "mocha --config test/manual/mocharc.json test/manual/socks5.test.ts",
136
136
  "check:csfle": "mocha --config test/mocha_mongodb.json test/integration/client-side-encryption",
137
137
  "check:snappy": "mocha test/unit/assorted/snappy.test.js",
package/src/bson.ts CHANGED
@@ -36,7 +36,6 @@ export interface BSONSerializeOptions
36
36
  | 'allowObjectSmallerThanBufferSize'
37
37
  | 'index'
38
38
  | 'validation'
39
- | 'useBigInt64'
40
39
  > {
41
40
  /**
42
41
  * Enabling the raw option will return a [Node.js Buffer](https://nodejs.org/api/buffer.html)
@@ -67,6 +66,7 @@ export interface BSONSerializeOptions
67
66
  export function pluckBSONSerializeOptions(options: BSONSerializeOptions): BSONSerializeOptions {
68
67
  const {
69
68
  fieldsAsRaw,
69
+ useBigInt64,
70
70
  promoteValues,
71
71
  promoteBuffers,
72
72
  promoteLongs,
@@ -78,6 +78,7 @@ export function pluckBSONSerializeOptions(options: BSONSerializeOptions): BSONSe
78
78
  } = options;
79
79
  return {
80
80
  fieldsAsRaw,
81
+ useBigInt64,
81
82
  promoteValues,
82
83
  promoteBuffers,
83
84
  promoteLongs,
@@ -102,6 +103,7 @@ export function resolveBSONOptions(
102
103
  const parentOptions = parent?.bsonOptions;
103
104
  return {
104
105
  raw: options?.raw ?? parentOptions?.raw ?? false,
106
+ useBigInt64: options?.useBigInt64 ?? parentOptions?.useBigInt64 ?? false,
105
107
  promoteLongs: options?.promoteLongs ?? parentOptions?.promoteLongs ?? true,
106
108
  promoteValues: options?.promoteValues ?? parentOptions?.promoteValues ?? true,
107
109
  promoteBuffers: options?.promoteBuffers ?? parentOptions?.promoteBuffers ?? false,
@@ -39,7 +39,7 @@ export const BatchType = Object.freeze({
39
39
  } as const);
40
40
 
41
41
  /** @public */
42
- export type BatchType = typeof BatchType[keyof typeof BatchType];
42
+ export type BatchType = (typeof BatchType)[keyof typeof BatchType];
43
43
 
44
44
  /** @public */
45
45
  export interface InsertOneModel<TSchema extends Document = Document> {
@@ -74,7 +74,7 @@ export type ResumeToken = unknown;
74
74
  /**
75
75
  * Represents a specific point in time on a server. Can be retrieved by using `db.command()`
76
76
  * @public
77
- * @see https://docs.mongodb.com/manual/reference/method/db.runCommand/#response
77
+ * @see https://www.mongodb.com/docs/manual/reference/method/db.runCommand/#response
78
78
  */
79
79
  export type OperationTime = Timestamp;
80
80
 
@@ -82,7 +82,7 @@ export type OperationTime = Timestamp;
82
82
  * Options that can be passed to a ChangeStream. Note that startAfter, resumeAfter, and startAtOperationTime are all mutually exclusive, and the server will error if more than one is specified.
83
83
  * @public
84
84
  */
85
- export interface ChangeStreamOptions extends AggregateOptions {
85
+ export interface ChangeStreamOptions extends Omit<AggregateOptions, 'writeConcern'> {
86
86
  /**
87
87
  * Allowed values: 'updateLookup', 'whenAvailable', 'required'.
88
88
  *
@@ -117,19 +117,19 @@ export interface ChangeStreamOptions extends AggregateOptions {
117
117
  maxAwaitTimeMS?: number;
118
118
  /**
119
119
  * Allows you to start a changeStream after a specified event.
120
- * @see https://docs.mongodb.com/manual/changeStreams/#resumeafter-for-change-streams
120
+ * @see https://www.mongodb.com/docs/manual/changeStreams/#resumeafter-for-change-streams
121
121
  */
122
122
  resumeAfter?: ResumeToken;
123
123
  /**
124
124
  * Similar to resumeAfter, but will allow you to start after an invalidated event.
125
- * @see https://docs.mongodb.com/manual/changeStreams/#startafter-for-change-streams
125
+ * @see https://www.mongodb.com/docs/manual/changeStreams/#startafter-for-change-streams
126
126
  */
127
127
  startAfter?: ResumeToken;
128
128
  /** Will start the changeStream after the specified operationTime. */
129
129
  startAtOperationTime?: OperationTime;
130
130
  /**
131
131
  * The number of documents to return per batch.
132
- * @see https://docs.mongodb.com/manual/reference/command/aggregate
132
+ * @see https://www.mongodb.com/docs/manual/reference/command/aggregate
133
133
  */
134
134
  batchSize?: number;
135
135
 
@@ -533,7 +533,14 @@ export class ChangeStream<
533
533
  TChange extends Document = ChangeStreamDocument<TSchema>
534
534
  > extends TypedEventEmitter<ChangeStreamEvents<TSchema, TChange>> {
535
535
  pipeline: Document[];
536
- options: ChangeStreamOptions;
536
+ /**
537
+ * @remarks WriteConcern can still be present on the options because
538
+ * we inherit options from the client/db/collection. The
539
+ * key must be present on the options in order to delete it.
540
+ * This allows typescript to delete the key but will
541
+ * not allow a writeConcern to be assigned as a property on options.
542
+ */
543
+ options: ChangeStreamOptions & { writeConcern?: never };
537
544
  parent: MongoClient | Db | Collection;
538
545
  namespace: MongoDBNamespace;
539
546
  type: symbol;
@@ -576,7 +583,7 @@ export class ChangeStream<
576
583
  * @internal
577
584
  *
578
585
  * @param parent - The parent object that created this change stream
579
- * @param pipeline - An array of {@link https://docs.mongodb.com/manual/reference/operator/aggregation-pipeline/|aggregation pipeline stages} through which to pass change stream documents
586
+ * @param pipeline - An array of {@link https://www.mongodb.com/docs/manual/reference/operator/aggregation-pipeline/|aggregation pipeline stages} through which to pass change stream documents
580
587
  */
581
588
  constructor(
582
589
  parent: OperationParent,
@@ -586,7 +593,8 @@ export class ChangeStream<
586
593
  super();
587
594
 
588
595
  this.pipeline = pipeline;
589
- this.options = options;
596
+ this.options = { ...options };
597
+ delete this.options.writeConcern;
590
598
 
591
599
  if (parent instanceof Collection) {
592
600
  this.type = CHANGE_DOMAIN_TYPES.COLLECTION;
@@ -1,20 +1,22 @@
1
1
  import type { Document } from '../../bson';
2
2
  import { MongoRuntimeError } from '../../error';
3
- import type { Callback, ClientMetadataOptions } from '../../utils';
4
3
  import type { HandshakeDocument } from '../connect';
5
4
  import type { Connection, ConnectionOptions } from '../connection';
6
5
  import type { MongoCredentials } from './mongo_credentials';
7
6
 
8
- export type AuthContextOptions = ConnectionOptions & ClientMetadataOptions;
9
-
10
- /** Context used during authentication */
7
+ /**
8
+ * Context used during authentication
9
+ * @internal
10
+ */
11
11
  export class AuthContext {
12
12
  /** The connection to authenticate */
13
13
  connection: Connection;
14
14
  /** The credentials to use for authentication */
15
15
  credentials?: MongoCredentials;
16
+ /** If the context is for reauthentication. */
17
+ reauthenticating = false;
16
18
  /** The options passed to the `connect` method */
17
- options: AuthContextOptions;
19
+ options: ConnectionOptions;
18
20
 
19
21
  /** A response from an initial auth attempt, only some mechanisms use this (e.g, SCRAM) */
20
22
  response?: Document;
@@ -24,7 +26,7 @@ export class AuthContext {
24
26
  constructor(
25
27
  connection: Connection,
26
28
  credentials: MongoCredentials | undefined,
27
- options: AuthContextOptions
29
+ options: ConnectionOptions
28
30
  ) {
29
31
  this.connection = connection;
30
32
  this.credentials = credentials;
@@ -32,29 +34,40 @@ export class AuthContext {
32
34
  }
33
35
  }
34
36
 
35
- export class AuthProvider {
37
+ export abstract class AuthProvider {
36
38
  /**
37
39
  * Prepare the handshake document before the initial handshake.
38
40
  *
39
41
  * @param handshakeDoc - The document used for the initial handshake on a connection
40
42
  * @param authContext - Context for authentication flow
41
43
  */
42
- prepare(
44
+ async prepare(
43
45
  handshakeDoc: HandshakeDocument,
44
- authContext: AuthContext,
45
- callback: Callback<HandshakeDocument>
46
- ): void {
47
- callback(undefined, handshakeDoc);
46
+ _authContext: AuthContext
47
+ ): Promise<HandshakeDocument> {
48
+ return handshakeDoc;
48
49
  }
49
50
 
50
51
  /**
51
52
  * Authenticate
52
53
  *
53
54
  * @param context - A shared context for authentication flow
54
- * @param callback - The callback to return the result from the authentication
55
55
  */
56
- auth(context: AuthContext, callback: Callback): void {
57
- // TODO(NODE-3483): Replace this with MongoMethodOverrideError
58
- callback(new MongoRuntimeError('`auth` method must be overridden by subclass'));
56
+ abstract auth(context: AuthContext): Promise<void>;
57
+
58
+ /**
59
+ * Reauthenticate.
60
+ * @param context - The shared auth context.
61
+ */
62
+ async reauth(context: AuthContext): Promise<void> {
63
+ if (context.reauthenticating) {
64
+ throw new MongoRuntimeError('Reauthentication already in progress.');
65
+ }
66
+ try {
67
+ context.reauthenticating = true;
68
+ await this.auth(context);
69
+ } finally {
70
+ context.reauthenticating = false;
71
+ }
59
72
  }
60
73
  }
@@ -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
  }