Последняя активность 1690261275

rootspring's Avatar rootspring ревизий этого фрагмента 1690261275. К ревизии

1 file changed, 1 insertion, 7 deletions

webhooks.md

@@ -106,10 +106,4 @@ To parse webhooks, here is the algorithm you should/must follow:
106 106 error: true,
107 107 });
108 108 return;
109 - ```
110 -
111 - ## HTML Sanitizer
112 -
113 - We use a custom server to parse markdown (using ``pulldown-cmark``) and sanitize HTML (using ``ammonia``). This is to prevent XSS attacks and other malicious code from being injected into our site.
114 -
115 - The URL for HTML Sanitizer is ``https://hs.infinitybots.gg``. To use this for previews etc, simply POST the raw MD/HTML to this URL and it will return the sanitized HTML.
109 + ```

rootspring's Avatar rootspring ревизий этого фрагмента 1690261220. К ревизии

1 file changed, 115 insertions

webhooks.md(файл создан)

@@ -0,0 +1,115 @@
1 + # Parsing webhooks
2 +
3 + To parse webhooks, here is the algorithm you should/must follow:
4 +
5 + **Examples are provided in JS as of right now**
6 +
7 + - Check the protocol version:
8 + - The current protocol version is `splashtail`
9 + - Check the `X-Webhook-Protocol` header and ensure that it is equal to the current protocol version
10 +
11 + ```js
12 + if (req.headers["x-webhook-protocol"] != supportedProtocol) {
13 + reply.status(403).send({
14 + message: "Invalid protocol version!",
15 + error: true,
16 + });
17 + return;
18 + }
19 + ```
20 +
21 + - A nonce is used to randomize the signature for retries. Ensure a nonce exists by checking the header's existence:
22 +
23 + ```js
24 + if (!req.headers["x-webhook-nonce"]) {
25 + reply.status(403).send({
26 + message: "No nonce provided?",
27 + error: true,
28 + });
29 + return;
30 + }
31 + ```
32 +
33 + - Next calculate the expected signature
34 + - To do so, you must first get the body of the request
35 + - Then use HMAC-SHA512 with the webhook secret as key and the body as the request body to get the ``signedBody``. Note that the format/digest should be ``hex``
36 + - Then use HMAC-SHA512 with the nonce as the key and the signed body as the message to get the expected signature. Note that the format/digest should be ``hex``
37 +
38 + ```js
39 + let body: string = req.body;
40 +
41 + if (!body) {
42 + reply.status(400).send({
43 + message: "No request body provided?",
44 + error: true,
45 + });
46 + return;
47 + }
48 +
49 + // Create hmac 512 hash
50 + let signedBody = crypto
51 + .createHmac("sha512", webhookSecret)
52 + .update(body)
53 + .digest("hex");
54 +
55 + // Create the actual signature using x-webhook-nonce by performing a second hmac
56 + let nonce = req.headers["x-webhook-nonce"].toString();
57 + let expectedTok = crypto
58 + .createHmac("sha512", nonce)
59 + .update(signedBody)
60 + .digest("hex");
61 + ```
62 +
63 + - Compare this value with the ``X-Webhook-Signature`` header
64 + - If they are equal, the request is valid and you can continue processing it
65 + - If they are not equal, the request is invalid and you should return a 403 status code
66 +
67 +
68 +
69 + ```js
70 + if (req.headers["x-webhook-signature"] != expectedTok) {
71 + console.log(
72 + `Expected: ${expectedTok} Got: ${req.headers["x-webhook-signature"]}`
73 + );
74 + reply.status(403).send({
75 + message: "Invalid signature",
76 + });
77 + return;
78 + }
79 + ```
80 +
81 + - Next decrypt the request body. This is an additional security to prevent sensitive information from being leaked
82 + - First hash the concatenation of the webhook secret and the nonce using SHA256
83 + - Then read the body as a hex string and decrypt it using AES-256-GCM with the hashed secret as the key
84 +
85 + ```js
86 + // sha256 on key
87 + let hashedKey = crypto
88 + .createHash("sha256")
89 + .update(webhookSecret + nonce)
90 + .digest();
91 +
92 + let enc = Buffer.from(body, "hex");
93 + const tag = enc.subarray(enc.length - tagLength, enc.length);
94 + const iv = enc.subarray(0, ivLength);
95 + const toDecrypt = enc.subarray(ivLength, enc.length - tag.length);
96 + const decipher = crypto.createDecipheriv("aes-256-gcm", hashedKey, iv);
97 + decipher.setAuthTag(tag);
98 + const res = Buffer.concat([decipher.update(toDecrypt), decipher.final()]);
99 +
100 + // Parse the decrypted body
101 + let data = JSON.parse(res.toString("utf-8"));
102 +
103 + if (data.created_at == undefined) {
104 + reply.status(400).send({
105 + message: "Invalid body",
106 + error: true,
107 + });
108 + return;
109 + ```
110 +
111 + ## HTML Sanitizer
112 +
113 + We use a custom server to parse markdown (using ``pulldown-cmark``) and sanitize HTML (using ``ammonia``). This is to prevent XSS attacks and other malicious code from being injected into our site.
114 +
115 + The URL for HTML Sanitizer is ``https://hs.infinitybots.gg``. To use this for previews etc, simply POST the raw MD/HTML to this URL and it will return the sanitized HTML.
Новее Позже