diff --git a/webhooks/overview.mdx b/webhooks/overview.mdx index 84cfb3a..dc51982 100644 --- a/webhooks/overview.mdx +++ b/webhooks/overview.mdx @@ -45,14 +45,29 @@ Every v1 webhook request includes an `x-topgg-signature` header in the format `t import crypto from 'crypto'; function verifyWebhook(rawBody: string, signature: string, secret: string): boolean { - const [tPart, v1Part] = signature.split(','); - const timestamp = tPart.split('=')[1]; - const receivedSig = v1Part.split('=')[1]; + const parts = signature.split(','); + let timestamp: string | undefined; + let receivedSig: string | undefined; + + for (const part of parts) { + const [key, ...valueParts] = part.split('='); + const value = valueParts.join('='); + if (key === 't') timestamp = value; + if (key === 'v1') receivedSig = value; + } + + if (!timestamp || !receivedSig) return false; + const ts = parseInt(timestamp, 10); + const now = Math.floor(Date.now() / 1000); + if (isNaN(ts) || Math.abs(now - ts) > 300) return false; const expected = crypto .createHmac('sha256', secret) .update(`${timestamp}.${rawBody}`) .digest('hex'); - return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(receivedSig)); + const expectedBuf = Buffer.from(expected); + const receivedBuf = Buffer.from(receivedSig); + if (expectedBuf.length !== receivedBuf.length) return false; + return crypto.timingSafeEqual(expectedBuf, receivedBuf); } ```