mongodb 7.0.0 → 7.1.0-dev.20260205.sha.d2ad07f2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/bson.js +2 -1
- package/lib/bson.js.map +1 -1
- package/lib/change_stream.js +3 -1
- package/lib/change_stream.js.map +1 -1
- package/lib/client-side-encryption/state_machine.js +1 -0
- package/lib/client-side-encryption/state_machine.js.map +1 -1
- package/lib/cmap/auth/aws4.js +161 -0
- package/lib/cmap/auth/aws4.js.map +1 -0
- package/lib/cmap/auth/aws_temporary_credentials.js +1 -0
- package/lib/cmap/auth/aws_temporary_credentials.js.map +1 -1
- package/lib/cmap/auth/gssapi.js +2 -4
- package/lib/cmap/auth/gssapi.js.map +1 -1
- package/lib/cmap/auth/mongo_credentials.js +2 -1
- package/lib/cmap/auth/mongo_credentials.js.map +1 -1
- package/lib/cmap/auth/mongodb_aws.js +9 -14
- package/lib/cmap/auth/mongodb_aws.js.map +1 -1
- package/lib/cmap/auth/mongodb_oidc/k8s_machine_workflow.js +1 -0
- package/lib/cmap/auth/mongodb_oidc/k8s_machine_workflow.js.map +1 -1
- package/lib/cmap/auth/mongodb_oidc/token_machine_workflow.js +1 -0
- package/lib/cmap/auth/mongodb_oidc/token_machine_workflow.js.map +1 -1
- package/lib/cmap/connect.js +15 -0
- package/lib/cmap/connect.js.map +1 -1
- package/lib/cmap/connection.js +3 -3
- package/lib/cmap/connection.js.map +1 -1
- package/lib/cmap/connection_pool.js +8 -8
- package/lib/cmap/connection_pool.js.map +1 -1
- package/lib/cmap/connection_pool_events.js +3 -3
- package/lib/cmap/connection_pool_events.js.map +1 -1
- package/lib/cmap/handshake/client_metadata.js +7 -7
- package/lib/cmap/handshake/client_metadata.js.map +1 -1
- package/lib/cmap/wire_protocol/compression.js +18 -3
- package/lib/cmap/wire_protocol/compression.js.map +1 -1
- package/lib/connection_string.js +6 -0
- package/lib/connection_string.js.map +1 -1
- package/lib/db.js +0 -1
- package/lib/db.js.map +1 -1
- package/lib/deps.js +0 -13
- package/lib/deps.js.map +1 -1
- package/lib/error.js +5 -8
- package/lib/error.js.map +1 -1
- package/lib/gridfs/upload.js +8 -8
- package/lib/gridfs/upload.js.map +1 -1
- package/lib/mongo_client.js +1 -1
- package/lib/mongo_client.js.map +1 -1
- package/lib/mongo_logger.js +11 -5
- package/lib/mongo_logger.js.map +1 -1
- package/lib/operations/execute_operation.js +5 -4
- package/lib/operations/execute_operation.js.map +1 -1
- package/lib/operations/rename.js.map +1 -1
- package/lib/runtime_adapters.js +16 -0
- package/lib/runtime_adapters.js.map +1 -0
- package/lib/sdam/monitor.js +8 -8
- package/lib/sdam/monitor.js.map +1 -1
- package/lib/sdam/server.js +41 -29
- package/lib/sdam/server.js.map +1 -1
- package/lib/sdam/server_description.js +1 -1
- package/lib/sdam/server_description.js.map +1 -1
- package/lib/sdam/server_selection.js +135 -72
- package/lib/sdam/server_selection.js.map +1 -1
- package/lib/sdam/topology.js +9 -7
- package/lib/sdam/topology.js.map +1 -1
- package/lib/sdam/topology_description.js +1 -1
- package/lib/sdam/topology_description.js.map +1 -1
- package/lib/sessions.js +87 -23
- package/lib/sessions.js.map +1 -1
- package/lib/utils.js +21 -47
- package/lib/utils.js.map +1 -1
- package/mongodb.d.ts +39 -2
- package/package.json +10 -12
- package/src/bson.ts +1 -0
- package/src/change_stream.ts +3 -1
- package/src/client-side-encryption/state_machine.ts +1 -0
- package/src/cmap/auth/aws4.ts +207 -0
- package/src/cmap/auth/aws_temporary_credentials.ts +2 -0
- package/src/cmap/auth/gssapi.ts +8 -4
- package/src/cmap/auth/mongo_credentials.ts +2 -1
- package/src/cmap/auth/mongodb_aws.ts +10 -17
- package/src/cmap/auth/mongodb_oidc/k8s_machine_workflow.ts +1 -0
- package/src/cmap/auth/mongodb_oidc/token_machine_workflow.ts +1 -0
- package/src/cmap/connect.ts +19 -0
- package/src/cmap/connection.ts +7 -4
- package/src/cmap/connection_pool.ts +9 -9
- package/src/cmap/connection_pool_events.ts +4 -4
- package/src/cmap/handshake/client_metadata.ts +10 -9
- package/src/cmap/wire_protocol/compression.ts +17 -3
- package/src/connection_string.ts +7 -0
- package/src/db.ts +0 -1
- package/src/deps.ts +0 -60
- package/src/error.ts +4 -8
- package/src/gridfs/upload.ts +8 -8
- package/src/index.ts +2 -1
- package/src/mongo_client.ts +12 -2
- package/src/mongo_logger.ts +11 -6
- package/src/operations/execute_operation.ts +6 -5
- package/src/operations/rename.ts +6 -1
- package/src/runtime_adapters.ts +49 -0
- package/src/sdam/monitor.ts +10 -10
- package/src/sdam/server.ts +50 -32
- package/src/sdam/server_description.ts +8 -2
- package/src/sdam/server_selection.ts +188 -96
- package/src/sdam/topology.ts +20 -16
- package/src/sdam/topology_description.ts +1 -1
- package/src/sessions.ts +114 -30
- package/src/utils.ts +17 -74
package/mongodb.d.ts
CHANGED
|
@@ -24,6 +24,7 @@ import type { SrvRecord } from 'dns';
|
|
|
24
24
|
import { EventEmitter } from 'events';
|
|
25
25
|
import type { Socket } from 'net';
|
|
26
26
|
import type { TcpNetConnectOpts } from 'net';
|
|
27
|
+
import type * as os from 'os';
|
|
27
28
|
import { Readable } from 'stream';
|
|
28
29
|
import { Writable } from 'stream';
|
|
29
30
|
import type { ConnectionOptions as ConnectionOptions_2 } from 'tls';
|
|
@@ -3513,6 +3514,7 @@ export declare interface ConnectionOptions extends SupportedNodeConnectionOption
|
|
|
3513
3514
|
/* Excluded from this release type: cancellationToken */
|
|
3514
3515
|
/* Excluded from this release type: metadata */
|
|
3515
3516
|
/* Excluded from this release type: mongoLogger */
|
|
3517
|
+
/* Excluded from this release type: runtime */
|
|
3516
3518
|
}
|
|
3517
3519
|
|
|
3518
3520
|
/* Excluded from this release type: ConnectionPool */
|
|
@@ -4198,6 +4200,7 @@ export declare interface DeleteStatement {
|
|
|
4198
4200
|
hint?: Hint;
|
|
4199
4201
|
}
|
|
4200
4202
|
|
|
4203
|
+
/* Excluded from this release type: DeprioritizedServers */
|
|
4201
4204
|
export { deserialize }
|
|
4202
4205
|
|
|
4203
4206
|
/** @public */
|
|
@@ -6185,6 +6188,12 @@ export declare interface MongoClientOptions extends BSONSerializeOptions, Suppor
|
|
|
6185
6188
|
/* Excluded from this release type: srvPoller */
|
|
6186
6189
|
/* Excluded from this release type: connectionType */
|
|
6187
6190
|
/* Excluded from this release type: __skipPingOnConnect */
|
|
6191
|
+
/**
|
|
6192
|
+
* @experimental
|
|
6193
|
+
*
|
|
6194
|
+
* If provided, any adapters provided will be used in place of the corresponding Node.js module.
|
|
6195
|
+
*/
|
|
6196
|
+
runtimeAdapters?: RuntimeAdapters;
|
|
6188
6197
|
}
|
|
6189
6198
|
|
|
6190
6199
|
/* Excluded from this release type: MongoClientPrivate */
|
|
@@ -6578,6 +6587,8 @@ export declare const MongoErrorLabel: Readonly<{
|
|
|
6578
6587
|
readonly PoolRequestedRetry: "PoolRequestedRetry";
|
|
6579
6588
|
readonly InterruptInUseConnections: "InterruptInUseConnections";
|
|
6580
6589
|
readonly NoWritesPerformed: "NoWritesPerformed";
|
|
6590
|
+
readonly RetryableError: "RetryableError";
|
|
6591
|
+
readonly SystemOverloadedError: "SystemOverloadedError";
|
|
6581
6592
|
}>;
|
|
6582
6593
|
|
|
6583
6594
|
/** @public */
|
|
@@ -7004,6 +7015,7 @@ export declare interface MongoOptions extends Required<Pick<MongoClientOptions,
|
|
|
7004
7015
|
/* Excluded from this release type: mongodbLogPath */
|
|
7005
7016
|
timeoutMS?: number;
|
|
7006
7017
|
/* Excluded from this release type: __skipPingOnConnect */
|
|
7018
|
+
/* Excluded from this release type: runtime */
|
|
7007
7019
|
}
|
|
7008
7020
|
|
|
7009
7021
|
/**
|
|
@@ -7502,6 +7514,14 @@ export declare class OrderedBulkOperation extends BulkOperationBase {
|
|
|
7502
7514
|
addToOperationsList(batchType: BatchType, document: Document | UpdateStatement | DeleteStatement): this;
|
|
7503
7515
|
}
|
|
7504
7516
|
|
|
7517
|
+
/**
|
|
7518
|
+
* @public
|
|
7519
|
+
* @experimental
|
|
7520
|
+
*
|
|
7521
|
+
* Represents the set of dependencies that the driver uses from the [Node.js OS module](https://nodejs.org/api/os.html).
|
|
7522
|
+
*/
|
|
7523
|
+
export declare type OsAdapter = Pick<typeof os, 'release' | 'platform' | 'arch' | 'type'>;
|
|
7524
|
+
|
|
7505
7525
|
/** @public */
|
|
7506
7526
|
export declare interface PkFactory {
|
|
7507
7527
|
createPk(): any;
|
|
@@ -7733,7 +7753,12 @@ export declare type RemoveUserOptions = Omit<CommandOperationOptions, 'rawData'>
|
|
|
7733
7753
|
export declare interface RenameOptions extends Omit<CommandOperationOptions, 'rawData'> {
|
|
7734
7754
|
/** Drop the target name collection if it previously exists. */
|
|
7735
7755
|
dropTarget?: boolean;
|
|
7736
|
-
/**
|
|
7756
|
+
/**
|
|
7757
|
+
* @deprecated
|
|
7758
|
+
*
|
|
7759
|
+
* This option has been dead code since at least Node driver version 4.x. It will
|
|
7760
|
+
* be removed in a future major release.
|
|
7761
|
+
*/
|
|
7737
7762
|
new_collection?: boolean;
|
|
7738
7763
|
}
|
|
7739
7764
|
|
|
@@ -7907,6 +7932,18 @@ export declare type RunCursorCommandOptions = {
|
|
|
7907
7932
|
awaitData?: boolean;
|
|
7908
7933
|
} & BSONSerializeOptions;
|
|
7909
7934
|
|
|
7935
|
+
/* Excluded from this release type: Runtime */
|
|
7936
|
+
|
|
7937
|
+
/**
|
|
7938
|
+
* @public
|
|
7939
|
+
* @experimental
|
|
7940
|
+
*
|
|
7941
|
+
* This type represents the set of dependencies that the driver needs from the Javascript runtime in order to function.
|
|
7942
|
+
*/
|
|
7943
|
+
export declare interface RuntimeAdapters {
|
|
7944
|
+
os?: OsAdapter;
|
|
7945
|
+
}
|
|
7946
|
+
|
|
7910
7947
|
/** @public */
|
|
7911
7948
|
export declare type SchemaMember<T, V> = {
|
|
7912
7949
|
[P in keyof T]?: V;
|
|
@@ -7933,7 +7970,7 @@ export declare interface SelectServerOptions {
|
|
|
7933
7970
|
serverSelectionTimeoutMS?: number;
|
|
7934
7971
|
session?: ClientSession;
|
|
7935
7972
|
operationName: string;
|
|
7936
|
-
|
|
7973
|
+
/* Excluded from this release type: deprioritizedServers */
|
|
7937
7974
|
/* Excluded from this release type: timeoutContext */
|
|
7938
7975
|
}
|
|
7939
7976
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mongodb",
|
|
3
|
-
"version": "7.0.
|
|
3
|
+
"version": "7.1.0-dev.20260205.sha.d2ad07f2",
|
|
4
4
|
"description": "The official MongoDB driver for Node.js",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"files": [
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
},
|
|
27
27
|
"dependencies": {
|
|
28
28
|
"@mongodb-js/saslprep": "^1.3.0",
|
|
29
|
-
"bson": "^7.
|
|
29
|
+
"bson": "^7.1.1",
|
|
30
30
|
"mongodb-connection-string-url": "^7.0.0"
|
|
31
31
|
},
|
|
32
32
|
"peerDependencies": {
|
|
@@ -65,12 +65,12 @@
|
|
|
65
65
|
"@aws-sdk/credential-providers": "^3.876.0",
|
|
66
66
|
"@iarna/toml": "^2.2.5",
|
|
67
67
|
"@istanbuljs/nyc-config-typescript": "^1.0.2",
|
|
68
|
-
"@microsoft/api-extractor": "^7.
|
|
68
|
+
"@microsoft/api-extractor": "^7.54.0",
|
|
69
69
|
"@microsoft/tsdoc-config": "^0.17.1",
|
|
70
70
|
"@mongodb-js/zstd": "^7.0.0",
|
|
71
71
|
"@types/chai": "^4.3.17",
|
|
72
72
|
"@types/chai-subset": "^1.3.5",
|
|
73
|
-
"@types/express": "^5.0.
|
|
73
|
+
"@types/express": "^5.0.5",
|
|
74
74
|
"@types/kerberos": "^1.1.5",
|
|
75
75
|
"@types/mocha": "^10.0.9",
|
|
76
76
|
"@types/node": "^22.15.3",
|
|
@@ -79,12 +79,13 @@
|
|
|
79
79
|
"@types/sinon": "^17.0.4",
|
|
80
80
|
"@types/sinon-chai": "^4.0.0",
|
|
81
81
|
"@types/whatwg-url": "^13.0.0",
|
|
82
|
-
"@typescript-eslint/eslint-plugin": "^8.
|
|
82
|
+
"@typescript-eslint/eslint-plugin": "^8.46.3",
|
|
83
83
|
"@typescript-eslint/parser": "^8.31.1",
|
|
84
|
+
"aws4": "^1.13.2",
|
|
84
85
|
"chai": "^4.4.1",
|
|
85
86
|
"chai-subset": "^1.6.0",
|
|
86
87
|
"chalk": "^4.1.2",
|
|
87
|
-
"eslint": "^9.
|
|
88
|
+
"eslint": "^9.39.1",
|
|
88
89
|
"eslint-config-prettier": "^10.1.8",
|
|
89
90
|
"eslint-plugin-mocha": "^10.4.1",
|
|
90
91
|
"eslint-plugin-prettier": "^5.5.4",
|
|
@@ -94,10 +95,10 @@
|
|
|
94
95
|
"express": "^5.1.0",
|
|
95
96
|
"gcp-metadata": "^7.0.1",
|
|
96
97
|
"js-yaml": "^4.1.0",
|
|
97
|
-
"mocha": "^11.7.
|
|
98
|
+
"mocha": "^11.7.5",
|
|
98
99
|
"mocha-sinon": "^2.1.2",
|
|
99
100
|
"mongodb-client-encryption": "^7.0.0",
|
|
100
|
-
"nyc": "^
|
|
101
|
+
"nyc": "^17.1.0",
|
|
101
102
|
"prettier": "^3.6.2",
|
|
102
103
|
"semver": "^7.7.2",
|
|
103
104
|
"sinon": "^18.0.1",
|
|
@@ -146,9 +147,6 @@
|
|
|
146
147
|
"check:aws": "nyc mocha --config test/mocha_mongodb.js test/integration/auth/mongodb_aws.test.ts test/integration/auth/mongodb_aws.prose.test.ts",
|
|
147
148
|
"check:oidc-auth": "nyc mocha --config test/mocha_mongodb.js test/integration/auth/auth.spec.test.ts",
|
|
148
149
|
"check:oidc-test": "nyc mocha --config test/mocha_mongodb.js test/integration/auth/mongodb_oidc.prose.test.ts",
|
|
149
|
-
"check:oidc-azure": "nyc mocha --config test/mocha_mongodb.js test/integration/auth/mongodb_oidc_azure.prose.05.test.ts",
|
|
150
|
-
"check:oidc-gcp": "nyc mocha --config test/mocha_mongodb.js test/integration/auth/mongodb_oidc_gcp.prose.06.test.ts",
|
|
151
|
-
"check:oidc-k8s": "nyc mocha --config test/mocha_mongodb.js test/integration/auth/mongodb_oidc_k8s.prose.07.test.ts",
|
|
152
150
|
"check:kerberos": "nyc mocha --config test/manual/mocharc.js test/manual/kerberos.test.ts",
|
|
153
151
|
"check:tls": "nyc mocha --config test/manual/mocharc.js test/manual/tls_support.test.ts",
|
|
154
152
|
"check:ldap": "nyc mocha --config test/manual/mocharc.js test/manual/ldap.test.ts",
|
|
@@ -172,4 +170,4 @@
|
|
|
172
170
|
"moduleResolution": "node"
|
|
173
171
|
}
|
|
174
172
|
}
|
|
175
|
-
}
|
|
173
|
+
}
|
package/src/bson.ts
CHANGED
package/src/change_stream.ts
CHANGED
|
@@ -18,6 +18,7 @@ import { MongoClient } from './mongo_client';
|
|
|
18
18
|
import { type InferIdType, TypedEventEmitter } from './mongo_types';
|
|
19
19
|
import type { AggregateOptions } from './operations/aggregate';
|
|
20
20
|
import type { OperationParent } from './operations/command';
|
|
21
|
+
import { DeprioritizedServers } from './sdam/server_selection';
|
|
21
22
|
import type { ServerSessionId } from './sessions';
|
|
22
23
|
import { CSOTTimeoutContext, type TimeoutContext } from './timeout';
|
|
23
24
|
import { type AnyOptions, getTopology, type MongoDBNamespace, squashError } from './utils';
|
|
@@ -1073,7 +1074,8 @@ export class ChangeStream<
|
|
|
1073
1074
|
try {
|
|
1074
1075
|
await topology.selectServer(this.cursor.readPreference, {
|
|
1075
1076
|
operationName: 'reconnect topology in change stream',
|
|
1076
|
-
timeoutContext: this.timeoutContext
|
|
1077
|
+
timeoutContext: this.timeoutContext,
|
|
1078
|
+
deprioritizedServers: new DeprioritizedServers()
|
|
1077
1079
|
});
|
|
1078
1080
|
this.cursor = this._createChangeStreamCursor(this.cursor.resumeOptions);
|
|
1079
1081
|
} catch {
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
import { BSON } from '../../bson';
|
|
2
|
+
import { type AWSCredentials } from '../../deps';
|
|
3
|
+
|
|
4
|
+
export type AwsSigv4Options = {
|
|
5
|
+
path: '/';
|
|
6
|
+
body: string;
|
|
7
|
+
host: string;
|
|
8
|
+
method: 'POST';
|
|
9
|
+
headers: {
|
|
10
|
+
'Content-Type': 'application/x-www-form-urlencoded';
|
|
11
|
+
'Content-Length': number;
|
|
12
|
+
'X-MongoDB-Server-Nonce': string;
|
|
13
|
+
'X-MongoDB-GS2-CB-Flag': 'n';
|
|
14
|
+
};
|
|
15
|
+
service: string;
|
|
16
|
+
region: string;
|
|
17
|
+
date: Date;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export type SignedHeaders = {
|
|
21
|
+
Authorization: string;
|
|
22
|
+
'X-Amz-Date': string;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Calculates the SHA-256 hash of a string.
|
|
27
|
+
*
|
|
28
|
+
* @param str - String to hash.
|
|
29
|
+
* @returns Hexadecimal representation of the hash.
|
|
30
|
+
*/
|
|
31
|
+
const getHexSha256 = async (str: string): Promise<string> => {
|
|
32
|
+
const data = stringToBuffer(str);
|
|
33
|
+
const hashBuffer = await crypto.subtle.digest('SHA-256', data);
|
|
34
|
+
const hashHex = BSON.onDemand.ByteUtils.toHex(new Uint8Array(hashBuffer));
|
|
35
|
+
return hashHex;
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Calculates the HMAC-SHA256 of a string using the provided key.
|
|
40
|
+
* @param key - Key to use for HMAC calculation. Can be a string or Uint8Array.
|
|
41
|
+
* @param str - String to calculate HMAC for.
|
|
42
|
+
* @returns Uint8Array containing the HMAC-SHA256 digest.
|
|
43
|
+
*/
|
|
44
|
+
const getHmacSha256 = async (key: string | Uint8Array, str: string): Promise<Uint8Array> => {
|
|
45
|
+
let keyData: Uint8Array;
|
|
46
|
+
if (typeof key === 'string') {
|
|
47
|
+
keyData = stringToBuffer(key);
|
|
48
|
+
} else {
|
|
49
|
+
keyData = key;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const importedKey = await crypto.subtle.importKey(
|
|
53
|
+
'raw',
|
|
54
|
+
keyData,
|
|
55
|
+
{ name: 'HMAC', hash: { name: 'SHA-256' } },
|
|
56
|
+
false,
|
|
57
|
+
['sign']
|
|
58
|
+
);
|
|
59
|
+
const strData = stringToBuffer(str);
|
|
60
|
+
const signature = await crypto.subtle.sign('HMAC', importedKey, strData);
|
|
61
|
+
const digest = new Uint8Array(signature);
|
|
62
|
+
return digest;
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Converts header values according to AWS requirements,
|
|
67
|
+
* From https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_sigv-create-signed-request.html#create-canonical-request
|
|
68
|
+
* For values, you must:
|
|
69
|
+
- trim any leading or trailing spaces.
|
|
70
|
+
- convert sequential spaces to a single space.
|
|
71
|
+
* @param value - Header value to convert.
|
|
72
|
+
* @returns - Converted header value.
|
|
73
|
+
*/
|
|
74
|
+
const convertHeaderValue = (value: string | number) => {
|
|
75
|
+
return value.toString().trim().replace(/\s+/g, ' ');
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Returns a Uint8Array representation of a string, encoded in UTF-8.
|
|
80
|
+
* @param str - String to convert.
|
|
81
|
+
* @returns Uint8Array containing the UTF-8 encoded string.
|
|
82
|
+
*/
|
|
83
|
+
function stringToBuffer(str: string): Uint8Array {
|
|
84
|
+
const data = new Uint8Array(BSON.onDemand.ByteUtils.utf8ByteLength(str));
|
|
85
|
+
BSON.onDemand.ByteUtils.encodeUTF8Into(data, str, 0);
|
|
86
|
+
return data;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* This method implements AWS Signature 4 logic for a very specific request format.
|
|
91
|
+
* The signing logic is described here: https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_sigv-create-signed-request.html
|
|
92
|
+
*/
|
|
93
|
+
export async function aws4Sign(
|
|
94
|
+
options: AwsSigv4Options,
|
|
95
|
+
credentials: AWSCredentials
|
|
96
|
+
): Promise<SignedHeaders> {
|
|
97
|
+
/**
|
|
98
|
+
* From the spec: https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_sigv-create-signed-request.html
|
|
99
|
+
*
|
|
100
|
+
* Summary of signing steps
|
|
101
|
+
* 1. Create a canonical request
|
|
102
|
+
* Arrange the contents of your request (host, action, headers, etc.) into a standard canonical format. The canonical request is one of the inputs used to create the string to sign.
|
|
103
|
+
* 2. Create a hash of the canonical request
|
|
104
|
+
* Hash the canonical request using the same algorithm that you used to create the hash of the payload. The hash of the canonical request is a string of lowercase hexadecimal characters.
|
|
105
|
+
* 3. Create a string to sign
|
|
106
|
+
* Create a string to sign with the canonical request and extra information such as the algorithm, request date, credential scope, and the hash of the canonical request.
|
|
107
|
+
* 4. Derive a signing key
|
|
108
|
+
* Use the secret access key to derive the key used to sign the request.
|
|
109
|
+
* 5. Calculate the signature
|
|
110
|
+
* Perform a keyed hash operation on the string to sign using the derived signing key as the hash key.
|
|
111
|
+
* 6. Add the signature to the request
|
|
112
|
+
* Add the calculated signature to an HTTP header or to the query string of the request.
|
|
113
|
+
*/
|
|
114
|
+
|
|
115
|
+
// 1: Create a canonical request
|
|
116
|
+
|
|
117
|
+
// Date – The date and time used to sign the request.
|
|
118
|
+
const date = options.date;
|
|
119
|
+
// RequestDateTime – The date and time used in the credential scope. This value is the current UTC time in ISO 8601 format (for example, 20130524T000000Z).
|
|
120
|
+
const requestDateTime = date.toISOString().replace(/[:-]|\.\d{3}/g, '');
|
|
121
|
+
// RequestDate – The date used in the credential scope. This value is the current UTC date in YYYYMMDD format (for example, 20130524).
|
|
122
|
+
const requestDate = requestDateTime.substring(0, 8);
|
|
123
|
+
// Method – The HTTP request method. For us, this is always 'POST'.
|
|
124
|
+
const method = options.method;
|
|
125
|
+
// CanonicalUri – The URI-encoded version of the absolute path component URI, starting with the / that follows the domain name and up to the end of the string
|
|
126
|
+
// For our requests, this is always '/'
|
|
127
|
+
const canonicalUri = options.path;
|
|
128
|
+
// CanonicalQueryString – The URI-encoded query string parameters. For our requests, there are no query string parameters, so this is always an empty string.
|
|
129
|
+
const canonicalQuerystring = '';
|
|
130
|
+
|
|
131
|
+
// CanonicalHeaders – A list of request headers with their values. Individual header name and value pairs are separated by the newline character ("\n").
|
|
132
|
+
// All of our known/expected headers are included here, there are no extra headers.
|
|
133
|
+
const headers = new Headers({
|
|
134
|
+
'content-length': convertHeaderValue(options.headers['Content-Length']),
|
|
135
|
+
'content-type': convertHeaderValue(options.headers['Content-Type']),
|
|
136
|
+
host: convertHeaderValue(options.host),
|
|
137
|
+
'x-amz-date': convertHeaderValue(requestDateTime),
|
|
138
|
+
'x-mongodb-gs2-cb-flag': convertHeaderValue(options.headers['X-MongoDB-GS2-CB-Flag']),
|
|
139
|
+
'x-mongodb-server-nonce': convertHeaderValue(options.headers['X-MongoDB-Server-Nonce'])
|
|
140
|
+
});
|
|
141
|
+
// If session token is provided, include it in the headers
|
|
142
|
+
if ('sessionToken' in credentials && credentials.sessionToken) {
|
|
143
|
+
headers.append('x-amz-security-token', convertHeaderValue(credentials.sessionToken));
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// Canonical headers are lowercased and sorted.
|
|
147
|
+
const canonicalHeaders = Array.from(headers.entries())
|
|
148
|
+
.map(([key, value]) => `${key.toLowerCase()}:${value}`)
|
|
149
|
+
.sort()
|
|
150
|
+
.join('\n');
|
|
151
|
+
const canonicalHeaderNames = Array.from(headers.keys()).map(header => header.toLowerCase());
|
|
152
|
+
// SignedHeaders – An alphabetically sorted, semicolon-separated list of lowercase request header names.
|
|
153
|
+
const signedHeaders = canonicalHeaderNames.sort().join(';');
|
|
154
|
+
|
|
155
|
+
// HashedPayload – A string created using the payload in the body of the HTTP request as input to a hash function. This string uses lowercase hexadecimal characters.
|
|
156
|
+
const hashedPayload = await getHexSha256(options.body);
|
|
157
|
+
|
|
158
|
+
// CanonicalRequest – A string that includes the above elements, separated by newline characters.
|
|
159
|
+
const canonicalRequest = [
|
|
160
|
+
method,
|
|
161
|
+
canonicalUri,
|
|
162
|
+
canonicalQuerystring,
|
|
163
|
+
canonicalHeaders + '\n',
|
|
164
|
+
signedHeaders,
|
|
165
|
+
hashedPayload
|
|
166
|
+
].join('\n');
|
|
167
|
+
|
|
168
|
+
// 2. Create a hash of the canonical request
|
|
169
|
+
// HashedCanonicalRequest – A string created by using the canonical request as input to a hash function.
|
|
170
|
+
const hashedCanonicalRequest = await getHexSha256(canonicalRequest);
|
|
171
|
+
|
|
172
|
+
// 3. Create a string to sign
|
|
173
|
+
// Algorithm – The algorithm used to create the hash of the canonical request. For SigV4, use AWS4-HMAC-SHA256.
|
|
174
|
+
const algorithm = 'AWS4-HMAC-SHA256';
|
|
175
|
+
// CredentialScope – The credential scope, which restricts the resulting signature to the specified Region and service.
|
|
176
|
+
// Has the following format: YYYYMMDD/region/service/aws4_request.
|
|
177
|
+
const credentialScope = `${requestDate}/${options.region}/${options.service}/aws4_request`;
|
|
178
|
+
// StringToSign – A string that includes the above elements, separated by newline characters.
|
|
179
|
+
const stringToSign = [algorithm, requestDateTime, credentialScope, hashedCanonicalRequest].join(
|
|
180
|
+
'\n'
|
|
181
|
+
);
|
|
182
|
+
|
|
183
|
+
// 4. Derive a signing key
|
|
184
|
+
// To derive a signing key for SigV4, perform a succession of keyed hash operations (HMAC) on the request date, Region, and service, with your AWS secret access key as the key for the initial hashing operation.
|
|
185
|
+
const dateKey = await getHmacSha256('AWS4' + credentials.secretAccessKey, requestDate);
|
|
186
|
+
const dateRegionKey = await getHmacSha256(dateKey, options.region);
|
|
187
|
+
const dateRegionServiceKey = await getHmacSha256(dateRegionKey, options.service);
|
|
188
|
+
const signingKey = await getHmacSha256(dateRegionServiceKey, 'aws4_request');
|
|
189
|
+
|
|
190
|
+
// 5. Calculate the signature
|
|
191
|
+
const signatureBuffer = await getHmacSha256(signingKey, stringToSign);
|
|
192
|
+
const signature = BSON.onDemand.ByteUtils.toHex(signatureBuffer);
|
|
193
|
+
|
|
194
|
+
// 6. Add the signature to the request
|
|
195
|
+
// Calculate the Authorization header
|
|
196
|
+
const authorizationHeader = [
|
|
197
|
+
'AWS4-HMAC-SHA256 Credential=' + credentials.accessKeyId + '/' + credentialScope,
|
|
198
|
+
'SignedHeaders=' + signedHeaders,
|
|
199
|
+
'Signature=' + signature
|
|
200
|
+
].join(', ');
|
|
201
|
+
|
|
202
|
+
// Return the calculated headers
|
|
203
|
+
return {
|
|
204
|
+
Authorization: authorizationHeader,
|
|
205
|
+
'X-Amz-Date': requestDateTime
|
|
206
|
+
};
|
|
207
|
+
}
|
package/src/cmap/auth/gssapi.ts
CHANGED
|
@@ -68,9 +68,13 @@ export class GSSAPI extends AuthProvider {
|
|
|
68
68
|
}
|
|
69
69
|
}
|
|
70
70
|
|
|
71
|
-
async function makeKerberosClient(
|
|
72
|
-
|
|
73
|
-
|
|
71
|
+
async function makeKerberosClient({
|
|
72
|
+
options: {
|
|
73
|
+
hostAddress,
|
|
74
|
+
runtime: { os }
|
|
75
|
+
},
|
|
76
|
+
credentials
|
|
77
|
+
}: AuthContext): Promise<KerberosClient> {
|
|
74
78
|
if (!hostAddress || typeof hostAddress.host !== 'string' || !credentials) {
|
|
75
79
|
throw new MongoInvalidArgumentError(
|
|
76
80
|
'Connection must have host and port and credentials defined.'
|
|
@@ -97,7 +101,7 @@ async function makeKerberosClient(authContext: AuthContext): Promise<KerberosCli
|
|
|
97
101
|
}
|
|
98
102
|
|
|
99
103
|
const spnHost = mechanismProperties.SERVICE_HOST ?? host;
|
|
100
|
-
let spn = `${serviceName}${
|
|
104
|
+
let spn = `${serviceName}${os.platform() === 'win32' ? '/' : '@'}${spnHost}`;
|
|
101
105
|
if ('SERVICE_REALM' in mechanismProperties) {
|
|
102
106
|
spn = `${spn}@${mechanismProperties.SERVICE_REALM}`;
|
|
103
107
|
}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import type { Binary, BSONSerializeOptions } from '../../bson';
|
|
2
2
|
import * as BSON from '../../bson';
|
|
3
|
-
import { aws4 } from '../../deps';
|
|
4
3
|
import {
|
|
5
4
|
MongoCompatibilityError,
|
|
6
5
|
MongoMissingCredentialsError,
|
|
@@ -13,6 +12,7 @@ import {
|
|
|
13
12
|
AWSSDKCredentialProvider,
|
|
14
13
|
type AWSTempCredentials
|
|
15
14
|
} from './aws_temporary_credentials';
|
|
15
|
+
import { aws4Sign } from './aws4';
|
|
16
16
|
import { MongoCredentials } from './mongo_credentials';
|
|
17
17
|
import { AuthMechanism } from './providers';
|
|
18
18
|
|
|
@@ -45,11 +45,6 @@ export class MongoDBAWS extends AuthProvider {
|
|
|
45
45
|
throw new MongoMissingCredentialsError('AuthContext must provide credentials.');
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
-
if ('kModuleError' in aws4) {
|
|
49
|
-
throw aws4['kModuleError'];
|
|
50
|
-
}
|
|
51
|
-
const { sign } = aws4;
|
|
52
|
-
|
|
53
48
|
if (maxWireVersion(connection) < 9) {
|
|
54
49
|
throw new MongoCompatibilityError(
|
|
55
50
|
'MONGODB-AWS authentication requires MongoDB version 4.4 or later'
|
|
@@ -68,13 +63,10 @@ export class MongoDBAWS extends AuthProvider {
|
|
|
68
63
|
// Allow the user to specify an AWS session token for authentication with temporary credentials.
|
|
69
64
|
const sessionToken = credentials.mechanismProperties.AWS_SESSION_TOKEN;
|
|
70
65
|
|
|
71
|
-
// If all three defined, include sessionToken, else include username and pass
|
|
72
|
-
const awsCredentials =
|
|
73
|
-
accessKeyId
|
|
74
|
-
|
|
75
|
-
: accessKeyId && secretAccessKey
|
|
76
|
-
? { accessKeyId, secretAccessKey }
|
|
77
|
-
: undefined;
|
|
66
|
+
// If all three defined, include sessionToken, else only include username and pass
|
|
67
|
+
const awsCredentials = sessionToken
|
|
68
|
+
? { accessKeyId, secretAccessKey, sessionToken }
|
|
69
|
+
: { accessKeyId, secretAccessKey };
|
|
78
70
|
|
|
79
71
|
const db = credentials.source;
|
|
80
72
|
const nonce = await randomBytes(32);
|
|
@@ -114,7 +106,7 @@ export class MongoDBAWS extends AuthProvider {
|
|
|
114
106
|
}
|
|
115
107
|
|
|
116
108
|
const body = 'Action=GetCallerIdentity&Version=2011-06-15';
|
|
117
|
-
const
|
|
109
|
+
const headers = await aws4Sign(
|
|
118
110
|
{
|
|
119
111
|
method: 'POST',
|
|
120
112
|
host,
|
|
@@ -127,14 +119,15 @@ export class MongoDBAWS extends AuthProvider {
|
|
|
127
119
|
'X-MongoDB-GS2-CB-Flag': 'n'
|
|
128
120
|
},
|
|
129
121
|
path: '/',
|
|
130
|
-
body
|
|
122
|
+
body,
|
|
123
|
+
date: new Date()
|
|
131
124
|
},
|
|
132
125
|
awsCredentials
|
|
133
126
|
);
|
|
134
127
|
|
|
135
128
|
const payload: AWSSaslContinuePayload = {
|
|
136
|
-
a:
|
|
137
|
-
d:
|
|
129
|
+
a: headers.Authorization,
|
|
130
|
+
d: headers['X-Amz-Date']
|
|
138
131
|
};
|
|
139
132
|
|
|
140
133
|
if (sessionToken) {
|
package/src/cmap/connect.ts
CHANGED
|
@@ -35,6 +35,11 @@ import {
|
|
|
35
35
|
/** @public */
|
|
36
36
|
export type Stream = Socket | TLSSocket;
|
|
37
37
|
|
|
38
|
+
function applyBackpressureLabels(error: MongoError) {
|
|
39
|
+
error.addErrorLabel(MongoErrorLabel.SystemOverloadedError);
|
|
40
|
+
error.addErrorLabel(MongoErrorLabel.RetryableError);
|
|
41
|
+
}
|
|
42
|
+
|
|
38
43
|
export async function connect(options: ConnectionOptions): Promise<Connection> {
|
|
39
44
|
let connection: Connection | null = null;
|
|
40
45
|
try {
|
|
@@ -103,6 +108,8 @@ export async function performInitialHandshake(
|
|
|
103
108
|
const authContext = new AuthContext(conn, credentials, options);
|
|
104
109
|
conn.authContext = authContext;
|
|
105
110
|
|
|
111
|
+
// If we encounter an error preparing the handshake document, do NOT apply backpressure labels. Errors
|
|
112
|
+
// encountered building the handshake document are all client-side, and do not indicate an overloaded server.
|
|
106
113
|
const handshakeDoc = await prepareHandshakeDocument(authContext);
|
|
107
114
|
|
|
108
115
|
// @ts-expect-error: TODO(NODE-5141): The options need to be filtered properly, Connection options differ from Command options
|
|
@@ -163,12 +170,15 @@ export async function performInitialHandshake(
|
|
|
163
170
|
try {
|
|
164
171
|
await provider.auth(authContext);
|
|
165
172
|
} catch (error) {
|
|
173
|
+
// NOTE: If we encounter an error authenticating a connection, do NOT apply backpressure labels.
|
|
174
|
+
|
|
166
175
|
if (error instanceof MongoError) {
|
|
167
176
|
error.addErrorLabel(MongoErrorLabel.HandshakeError);
|
|
168
177
|
if (needsRetryableWriteLabel(error, response.maxWireVersion, conn.description.type)) {
|
|
169
178
|
error.addErrorLabel(MongoErrorLabel.RetryableWriteError);
|
|
170
179
|
}
|
|
171
180
|
}
|
|
181
|
+
|
|
172
182
|
throw error;
|
|
173
183
|
}
|
|
174
184
|
}
|
|
@@ -189,6 +199,11 @@ export async function performInitialHandshake(
|
|
|
189
199
|
if (error instanceof MongoError) {
|
|
190
200
|
error.addErrorLabel(MongoErrorLabel.HandshakeError);
|
|
191
201
|
}
|
|
202
|
+
// If we encounter a network error executing the initial handshake, apply backpressure labels.
|
|
203
|
+
if (error instanceof MongoNetworkError) {
|
|
204
|
+
applyBackpressureLabels(error);
|
|
205
|
+
}
|
|
206
|
+
|
|
192
207
|
throw error;
|
|
193
208
|
}
|
|
194
209
|
}
|
|
@@ -424,6 +439,10 @@ export async function makeSocket(options: MakeConnectionOptions): Promise<Stream
|
|
|
424
439
|
socket = await connectedSocket;
|
|
425
440
|
return socket;
|
|
426
441
|
} catch (error) {
|
|
442
|
+
// If we encounter an error while establishing a socket, apply the backpressure labels to it. We cannot
|
|
443
|
+
// differentiate between DNS, TLS errors and network errors without refactoring our connection establishment to
|
|
444
|
+
// handle all three steps separately.
|
|
445
|
+
applyBackpressureLabels(error);
|
|
427
446
|
socket.destroy();
|
|
428
447
|
throw error;
|
|
429
448
|
} finally {
|
package/src/cmap/connection.ts
CHANGED
|
@@ -35,6 +35,7 @@ import { type MongoClientAuthProviders } from '../mongo_client_auth_providers';
|
|
|
35
35
|
import { MongoLoggableComponent, type MongoLogger, SeverityLevel } from '../mongo_logger';
|
|
36
36
|
import { type Abortable, type CancellationToken, TypedEventEmitter } from '../mongo_types';
|
|
37
37
|
import { ReadPreference, type ReadPreferenceLike } from '../read_preference';
|
|
38
|
+
import { type Runtime } from '../runtime_adapters';
|
|
38
39
|
import { ServerType } from '../sdam/common';
|
|
39
40
|
import { applySession, type ClientSession, updateSessionFromResponse } from '../sessions';
|
|
40
41
|
import { type TimeoutContext, TimeoutError } from '../timeout';
|
|
@@ -47,8 +48,8 @@ import {
|
|
|
47
48
|
maxWireVersion,
|
|
48
49
|
type MongoDBNamespace,
|
|
49
50
|
noop,
|
|
50
|
-
now,
|
|
51
51
|
once,
|
|
52
|
+
processTimeMS,
|
|
52
53
|
squashError,
|
|
53
54
|
uuidV4
|
|
54
55
|
} from '../utils';
|
|
@@ -143,6 +144,8 @@ export interface ConnectionOptions
|
|
|
143
144
|
metadata: Promise<ClientMetadata>;
|
|
144
145
|
/** @internal */
|
|
145
146
|
mongoLogger?: MongoLogger | undefined;
|
|
147
|
+
/** @internal */
|
|
148
|
+
runtime: Runtime;
|
|
146
149
|
}
|
|
147
150
|
|
|
148
151
|
/** @public */
|
|
@@ -241,7 +244,7 @@ export class Connection extends TypedEventEmitter<ConnectionEvents> {
|
|
|
241
244
|
|
|
242
245
|
this.description = new StreamDescription(this.address, options);
|
|
243
246
|
this.generation = options.generation;
|
|
244
|
-
this.lastUseTime =
|
|
247
|
+
this.lastUseTime = processTimeMS();
|
|
245
248
|
|
|
246
249
|
this.messageStream = this.socket
|
|
247
250
|
.on('error', this.onSocketError.bind(this))
|
|
@@ -299,7 +302,7 @@ export class Connection extends TypedEventEmitter<ConnectionEvents> {
|
|
|
299
302
|
}
|
|
300
303
|
|
|
301
304
|
public markAvailable(): void {
|
|
302
|
-
this.lastUseTime =
|
|
305
|
+
this.lastUseTime = processTimeMS();
|
|
303
306
|
}
|
|
304
307
|
|
|
305
308
|
private onSocketError(cause: Error) {
|
|
@@ -510,7 +513,7 @@ export class Connection extends TypedEventEmitter<ConnectionEvents> {
|
|
|
510
513
|
const message = this.prepareCommand(ns.db, command, options);
|
|
511
514
|
let started = 0;
|
|
512
515
|
if (this.shouldEmitAndLogCommand) {
|
|
513
|
-
started =
|
|
516
|
+
started = processTimeMS();
|
|
514
517
|
this.emitAndLogCommand(
|
|
515
518
|
this.monitorCommands,
|
|
516
519
|
Connection.COMMAND_STARTED,
|