1
- const crypto = require ( "node:crypto " ) ;
1
+ const base64 = require ( "@hexagon/base64 " ) ;
2
2
3
3
const ApiError = require ( "./error" ) ;
4
4
@@ -72,12 +72,10 @@ async function validateWebhook(requestData, secret) {
72
72
73
73
const signedContent = `${ id } .${ timestamp } .${ body } ` ;
74
74
75
- const secretBytes = Buffer . from ( signingSecret . split ( "_" ) [ 1 ] , "base64" ) ;
76
-
77
- const computedSignature = crypto
78
- . createHmac ( "sha256" , secretBytes )
79
- . update ( signedContent )
80
- . digest ( "base64" ) ;
75
+ const computedSignature = await createHMACSHA256 (
76
+ signingSecret . split ( "_" ) . pop ( ) ,
77
+ signedContent
78
+ ) ;
81
79
82
80
const expectedSignatures = signature
83
81
. split ( " " )
@@ -88,6 +86,24 @@ async function validateWebhook(requestData, secret) {
88
86
) ;
89
87
}
90
88
89
+ /**
90
+ * @param {string } secret - base64 encoded string
91
+ * @param {string } data - text body of request
92
+ */
93
+ async function createHMACSHA256 ( secret , data ) {
94
+ const encoder = new TextEncoder ( ) ;
95
+ const key = await crypto . subtle . importKey (
96
+ "raw" ,
97
+ base64 . toArrayBuffer ( secret ) ,
98
+ { name : "HMAC" , hash : "SHA-256" } ,
99
+ false ,
100
+ [ "sign" ]
101
+ ) ;
102
+
103
+ const signature = await crypto . subtle . sign ( "HMAC" , key , encoder . encode ( data ) ) ;
104
+ return base64 . fromArrayBuffer ( signature ) ;
105
+ }
106
+
91
107
/**
92
108
* Automatically retry a request if it fails with an appropriate status code.
93
109
*
0 commit comments