Go · 925 bytes Raw Blame History
1 // SPDX-License-Identifier: AGPL-3.0-or-later
2
3 package webhook
4
5 import (
6 "crypto/hmac"
7 "crypto/sha256"
8 "encoding/hex"
9 )
10
11 // SignSHA256 returns the X-Shithub-Signature-256 header value for the
12 // given body and per-webhook secret. The format mirrors GitHub's
13 // (`sha256=<hex>`) so existing receiver libraries verify cleanly.
14 func SignSHA256(secret, body []byte) string {
15 mac := hmac.New(sha256.New, secret)
16 mac.Write(body)
17 return "sha256=" + hex.EncodeToString(mac.Sum(nil))
18 }
19
20 // VerifySHA256 returns true when sig matches HMAC-SHA256(secret, body).
21 // Uses constant-time compare so the verifier doesn't leak timing info.
22 // Provided as the receiver-side helper that test code (and any future
23 // inbound webhook surface) can reuse.
24 func VerifySHA256(secret, body []byte, sig string) bool {
25 want := SignSHA256(secret, body)
26 if len(want) != len(sig) {
27 return false
28 }
29 return hmac.Equal([]byte(want), []byte(sig))
30 }
31