Time to lockdown webhooks

Web Crypto Version

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
const payload = {
secret: "thesecret",
signature: "f3f06790d23d8bd7f7ae6165a2508f830fad6eb5",
data: {
id: "aabbid",
name: "2022-11-07T06:02:56.149Z_firehose",
targetUrl: "https://testbed.valgaze.workers.dev",
resource: "messages",
event: "created",
orgId: "aabborgid",
createdBy: "aabbcreatedBy",
appId: "aabbappId",
ownedBy: "creator",
status: "active",
created: "1991-11-07T06:02:56.238Z",
actorId: "aabbactorId",
data: {
id: "dataId",
roomId: "roomId",
roomType: "direct",
personId: "personId",
personEmail: "valgaze@cisco.com",
created: "1991-11-07T06:03:09.704Z",
},
},
};

class WebhookHelper {
constructor(secret) {
this.secret = secret;
}

async validate(webhookBody) {
const stringyBody = JSON.stringify(webhookBody);
const theSercret = this.secret;
const algo = { name: "HMAC", hash: "SHA-1" };
const enc = { name: "UTF-8" };
const hmacKey = await crypto.subtle.importKey(
"raw",
new TextEncoder().encode(theSercret),
algo,
false,
["sign"]
);
const hmacData = await crypto.subtle.sign(
algo,
hmacKey,
new TextEncoder().encode(stringyBody)
);
const hmacDataHex = this.bufferToHex(hmacData);
return hmacDataHex;
}

bufferToHex(buffer) {
return Array.prototype.map
.call(new Uint8Array(buffer), (x) => ("00" + x.toString(16)).slice(-2))
.join("");
}
}

const inst = new WebhookHelper(payload.secret);
const bb = inst
.validate(payload.data)
.then((r) => console.log("****", r, `[${r === payload.signature}]`));