feat: whyrating - initial project from turbostarter boilerplate
This commit is contained in:
@@ -0,0 +1,41 @@
|
||||
import { HttpStatusCode } from "@turbostarter/shared/constants";
|
||||
import { HttpException } from "@turbostarter/shared/utils";
|
||||
|
||||
export const validateSignature = async (
|
||||
sig: string,
|
||||
secret: string,
|
||||
body: string,
|
||||
) => {
|
||||
const keyData = new TextEncoder().encode(secret);
|
||||
const bodyData = new TextEncoder().encode(body);
|
||||
|
||||
const key = await crypto.subtle.importKey(
|
||||
"raw",
|
||||
keyData,
|
||||
{ name: "HMAC", hash: "SHA-256" },
|
||||
false,
|
||||
["sign"],
|
||||
);
|
||||
|
||||
const signatureBuffer = await crypto.subtle.sign("HMAC", key, bodyData);
|
||||
const expectedSignature = [...new Uint8Array(signatureBuffer)]
|
||||
.map((b) => b.toString(16).padStart(2, "0"))
|
||||
.join("");
|
||||
|
||||
if (!timingSafeEqual(expectedSignature, sig)) {
|
||||
throw new HttpException(HttpStatusCode.BAD_REQUEST, {
|
||||
code: "billing:error.webhook.signatureInvalid",
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const timingSafeEqual = (a: string, b: string) => {
|
||||
if (a.length !== b.length) return false;
|
||||
|
||||
let result = 0;
|
||||
for (let i = 0; i < a.length; i++) {
|
||||
result |= a.charCodeAt(i) ^ b.charCodeAt(i);
|
||||
}
|
||||
|
||||
return result === 0;
|
||||
};
|
||||
Reference in New Issue
Block a user