1- import * as crypto from 'node:crypto' ;
2-
31import { type AWSCredentials } from './deps' ;
42
53export type Options = {
@@ -25,14 +23,35 @@ export type SignedHeaders = {
2523 } ;
2624} ;
2725
28- const getHash = ( str : string ) : string => {
29- return crypto . createHash ( 'sha256' ) . update ( str , 'utf8' ) . digest ( 'hex' ) ;
26+ const crypto = globalThis . crypto ;
27+
28+ const getHash = async ( str : string ) : Promise < string > => {
29+ const encoder = new TextEncoder ( ) ;
30+ const data = encoder . encode ( str ) ;
31+ const hashBuffer = await crypto . subtle . digest ( 'SHA-256' , data ) ;
32+ const hashArray = Array . from ( new Uint8Array ( hashBuffer ) ) ;
33+ const hashHex = hashArray . map ( b => b . toString ( 16 ) . padStart ( 2 , '0' ) ) . join ( '' ) ;
34+ return hashHex ;
3035} ;
31- const getHmacBuffer = ( key : string | Uint8Array , str : string ) : Uint8Array => {
32- return crypto . createHmac ( 'sha256' , key ) . update ( str , 'utf8' ) . digest ( ) ;
36+ const getHmacBuffer = async ( key : string | Uint8Array , str : string ) : Promise < Uint8Array > => {
37+ const encoder = new TextEncoder ( ) ;
38+ const keyData = typeof key === 'string' ? encoder . encode ( key ) : key ;
39+ const importedKey = await crypto . subtle . importKey (
40+ 'raw' ,
41+ keyData ,
42+ { name : 'HMAC' , hash : { name : 'SHA-256' } } ,
43+ false ,
44+ [ 'sign' ]
45+ ) ;
46+ const signature = await crypto . subtle . sign ( 'HMAC' , importedKey , encoder . encode ( str ) ) ;
47+ const digest = new Uint8Array ( signature ) ;
48+ return digest ;
3349} ;
34- const getHmacString = ( key : Uint8Array , str : string ) : string => {
35- return crypto . createHmac ( 'sha256' , key ) . update ( str , 'utf8' ) . digest ( 'hex' ) ;
50+ const getHmacString = async ( key : Uint8Array , str : string ) : Promise < string > => {
51+ const hmacBuffer = await getHmacBuffer ( key , str ) ;
52+ const hashArray = Array . from ( hmacBuffer ) ;
53+ const hashHex = hashArray . map ( b => b . toString ( 16 ) . padStart ( 2 , '0' ) ) . join ( '' ) ;
54+ return hashHex ;
3655} ;
3756
3857const convertHeaderValue = ( value : string | number ) => {
@@ -43,7 +62,10 @@ const convertHeaderValue = (value: string | number) => {
4362 * This method implements AWS Signature 4 logic for a very specific request format.
4463 * The signing logic is described here: https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_sigv-create-signed-request.html
4564 */
46- export function aws4Sign ( options : Options , credentials : AWSCredentials ) : SignedHeaders {
65+ export async function aws4Sign (
66+ options : Options ,
67+ credentials : AWSCredentials
68+ ) : Promise < SignedHeaders > {
4769 /**
4870 * From the spec: https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_sigv-create-signed-request.html
4971 *
@@ -102,7 +124,7 @@ export function aws4Sign(options: Options, credentials: AWSCredentials): SignedH
102124 const signedHeaders = canonicalHeaderNames . sort ( ) . join ( ';' ) ;
103125
104126 // 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.
105- const hashedPayload = getHash ( options . body ) ;
127+ const hashedPayload = await getHash ( options . body ) ;
106128
107129 // CanonicalRequest – A string that includes the above elements, separated by newline characters.
108130 const canonicalRequest = [
@@ -116,7 +138,7 @@ export function aws4Sign(options: Options, credentials: AWSCredentials): SignedH
116138
117139 // 2. Create a hash of the canonical request
118140 // HashedCanonicalRequest – A string created by using the canonical request as input to a hash function.
119- const hashedCanonicalRequest = getHash ( canonicalRequest ) ;
141+ const hashedCanonicalRequest = await getHash ( canonicalRequest ) ;
120142
121143 // 3. Create a string to sign
122144 // Algorithm – The algorithm used to create the hash of the canonical request. For SigV4, use AWS4-HMAC-SHA256.
@@ -131,13 +153,13 @@ export function aws4Sign(options: Options, credentials: AWSCredentials): SignedH
131153
132154 // 4. Derive a signing key
133155 // 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.
134- const dateKey = getHmacBuffer ( 'AWS4' + credentials . secretAccessKey , requestDate ) ;
135- const dateRegionKey = getHmacBuffer ( dateKey , options . region ) ;
136- const dateRegionServiceKey = getHmacBuffer ( dateRegionKey , options . service ) ;
137- const signingKey = getHmacBuffer ( dateRegionServiceKey , 'aws4_request' ) ;
156+ const dateKey = await getHmacBuffer ( 'AWS4' + credentials . secretAccessKey , requestDate ) ;
157+ const dateRegionKey = await getHmacBuffer ( dateKey , options . region ) ;
158+ const dateRegionServiceKey = await getHmacBuffer ( dateRegionKey , options . service ) ;
159+ const signingKey = await getHmacBuffer ( dateRegionServiceKey , 'aws4_request' ) ;
138160
139161 // 5. Calculate the signature
140- const signature = getHmacString ( signingKey , stringToSign ) ;
162+ const signature = await getHmacString ( signingKey , stringToSign ) ;
141163
142164 // 6. Add the signature to the request
143165 // Calculate the Authorization header
0 commit comments