Created
August 30, 2025 12:04
-
-
Save iberflow/bbbc151838089d302c8ab12aa3d6d50a to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| package webhooks | |
| import ( | |
| "crypto/hmac" | |
| "crypto/sha256" | |
| "encoding/hex" | |
| "errors" | |
| "fmt" | |
| "strings" | |
| "time" | |
| ) | |
| type verifier struct { | |
| clock func() time.Time | |
| } | |
| type Verifier interface { | |
| Verify(secret, payload []byte, header string) error | |
| } | |
| func NewVerifier() Verifier { | |
| return verifier{clock: time.Now} | |
| } | |
| func (v verifier) Verify(secret, payload []byte, signatureHeader string) error { | |
| if len(secret) == 0 { | |
| return errors.New("verify: secret is empty") | |
| } | |
| if signatureHeader == "" { | |
| return errors.New("verify: signature header is empty") | |
| } | |
| parts := strings.Split(signatureHeader, ",") | |
| var timestampStr, sigHex string | |
| for _, p := range parts { | |
| p = strings.TrimSpace(p) | |
| if strings.HasPrefix(p, "t=") { | |
| timestampStr = strings.TrimPrefix(p, "t=") | |
| } else if strings.HasPrefix(p, "v1=") { | |
| sigHex = strings.TrimPrefix(p, "v1=") | |
| } | |
| } | |
| if timestampStr == "" || sigHex == "" { | |
| return errors.New("verify: malformed signature header") | |
| } | |
| // recompute expected signature | |
| signedPayload := timestampStr + "." + string(payload) | |
| mac := hmac.New(sha256.New, secret) | |
| if _, err := mac.Write([]byte(signedPayload)); err != nil { | |
| return fmt.Errorf("verify: write payload: %w", err) | |
| } | |
| expected := mac.Sum(nil) | |
| got, err := hex.DecodeString(sigHex) | |
| if err != nil { | |
| return fmt.Errorf("verify: invalid hex signature: %w", err) | |
| } | |
| // constant-time compare | |
| if !hmac.Equal(got, expected) { | |
| return errors.New("verify: signature mismatch") | |
| } | |
| return nil | |
| } |
Comments are disabled for this gist.