Skip to content

Commit 3a2a0ee

Browse files
committed
pr feedback
1 parent d7966a3 commit 3a2a0ee

4 files changed

Lines changed: 36 additions & 16 deletions

File tree

src/aws4.ts renamed to src/cmap/auth/aws4.ts

Lines changed: 29 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import { BSON } from './bson';
2-
import { type AWSCredentials } from './deps';
1+
import { BSON } from '../../bson';
2+
import { type AWSCredentials } from '../../deps';
33

44
export type Options = {
55
path: '/';
@@ -14,7 +14,7 @@ export type Options = {
1414
};
1515
service: string;
1616
region: string;
17-
date?: Date;
17+
date: Date;
1818
};
1919

2020
export type SignedHeaders = {
@@ -24,13 +24,26 @@ export type SignedHeaders = {
2424
};
2525
};
2626

27+
/**
28+
* Calculates the SHA-256 hash of a string.
29+
*
30+
* @param str - String to hash.
31+
* @returns Hexadecimal representation of the hash.
32+
*/
2733
const getHash = async (str: string): Promise<string> => {
2834
const data = new Uint8Array(BSON.onDemand.ByteUtils.utf8ByteLength(str));
2935
BSON.onDemand.ByteUtils.encodeUTF8Into(data, str, 0);
3036
const hashBuffer = await crypto.subtle.digest('SHA-256', data);
3137
const hashHex = BSON.onDemand.ByteUtils.toHex(new Uint8Array(hashBuffer));
3238
return hashHex;
3339
};
40+
41+
/**
42+
* Calculates the HMAC-SHA256 of a string using the provided key.
43+
* @param key - Key to use for HMAC calculation. Can be a string or Uint8Array.
44+
* @param str - String to calculate HMAC for.
45+
* @returns Uint8Array containing the HMAC-SHA256 digest.
46+
*/
3447
const getHmacBuffer = async (key: string | Uint8Array, str: string): Promise<Uint8Array> => {
3548
let keyData: Uint8Array;
3649
if (typeof key === 'string') {
@@ -53,12 +66,16 @@ const getHmacBuffer = async (key: string | Uint8Array, str: string): Promise<Uin
5366
const digest = new Uint8Array(signature);
5467
return digest;
5568
};
56-
const getHmacString = async (key: Uint8Array, str: string): Promise<string> => {
57-
const hmacBuffer = await getHmacBuffer(key, str);
58-
const hashHex = BSON.onDemand.ByteUtils.toHex(hmacBuffer);
59-
return hashHex;
60-
};
6169

70+
/**
71+
* Converts header values according to AWS requirements,
72+
* From https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_sigv-create-signed-request.html#create-canonical-request
73+
* For values, you must:
74+
- trim any leading or trailing spaces.
75+
- convert sequential spaces to a single space.
76+
* @param value - Header value to convert.
77+
* @returns - Converted header value.
78+
*/
6279
const convertHeaderValue = (value: string | number) => {
6380
return value.toString().trim().replace(/\s+/g, ' ');
6481
};
@@ -91,8 +108,8 @@ export async function aws4Sign(
91108

92109
// 1: Create a canonical request
93110

94-
// Date – The date and time used to sign the request. If not provided, use the current date.
95-
const date = options.date || new Date();
111+
// Date – The date and time used to sign the request.
112+
const date = options.date;
96113
// RequestDateTime – The date and time used in the credential scope. This value is the current UTC time in ISO 8601 format (for example, 20130524T000000Z).
97114
const requestDateTime = date.toISOString().replace(/[:-]|\.\d{3}/g, '');
98115
// RequestDate – The date used in the credential scope. This value is the current UTC date in YYYYMMDD format (for example, 20130524).
@@ -164,7 +181,8 @@ export async function aws4Sign(
164181
const signingKey = await getHmacBuffer(dateRegionServiceKey, 'aws4_request');
165182

166183
// 5. Calculate the signature
167-
const signature = await getHmacString(signingKey, stringToSign);
184+
const signatureBuffer = await getHmacBuffer(signingKey, stringToSign);
185+
const signature = BSON.onDemand.ByteUtils.toHex(signatureBuffer);
168186

169187
// 6. Add the signature to the request
170188
// Calculate the Authorization header

src/cmap/auth/mongodb_aws.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import { aws4Sign } from '../../aws4';
21
import type { Binary, BSONSerializeOptions } from '../../bson';
32
import * as BSON from '../../bson';
43
import {
@@ -13,6 +12,7 @@ import {
1312
AWSSDKCredentialProvider,
1413
type AWSTempCredentials
1514
} from './aws_temporary_credentials';
15+
import { aws4Sign } from './aws4';
1616
import { MongoCredentials } from './mongo_credentials';
1717
import { AuthMechanism } from './providers';
1818

@@ -119,7 +119,8 @@ export class MongoDBAWS extends AuthProvider {
119119
'X-MongoDB-GS2-CB-Flag': 'n'
120120
},
121121
path: '/',
122-
body
122+
body,
123+
date: new Date()
123124
},
124125
awsCredentials
125126
);

test/integration/auth/mongodb_aws.test.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,9 @@ import {
1717
MongoMissingDependencyError,
1818
MongoServerError
1919
} from '../../../src';
20-
import { aws4Sign } from '../../../src/aws4';
2120
import { refreshKMSCredentials } from '../../../src/client-side-encryption/providers';
2221
import { AWSSDKCredentialProvider } from '../../../src/cmap/auth/aws_temporary_credentials';
22+
import { aws4Sign } from '../../../src/cmap/auth/aws4';
2323
import { MongoDBAWS } from '../../../src/cmap/auth/mongodb_aws';
2424
import { Connection } from '../../../src/cmap/connection';
2525
import { setDifference } from '../../../src/utils';
@@ -268,7 +268,8 @@ describe('MONGODB-AWS', function () {
268268
region: 'us-east-1',
269269
service: 'sts',
270270
headers: headers,
271-
body
271+
body,
272+
date: new Date()
272273
},
273274
creds
274275
);

test/unit/aws4.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { expect } from 'chai';
22

3-
import { aws4Sign, type Options } from '../../src/aws4';
3+
import { aws4Sign, type Options } from '../../src/cmap/auth/aws4';
44

55
describe('Verify AWS4 signature generation', () => {
66
const date = new Date('2025-12-15T12:34:56Z');

0 commit comments

Comments
 (0)