github.com/whoyao/protocol@v0.0.0-20230519045905-2d8ace718ca5/webhook/verifier.go (about) 1 package webhook 2 3 import ( 4 "crypto/sha256" 5 "encoding/base64" 6 "io" 7 "net/http" 8 9 "google.golang.org/protobuf/encoding/protojson" 10 11 "github.com/whoyao/protocol/auth" 12 "github.com/whoyao/protocol/livekit" 13 ) 14 15 // Receive reads and verifies incoming webhook is signed with key/secret pair 16 // closes body after reading 17 func Receive(r *http.Request, provider auth.KeyProvider) ([]byte, error) { 18 defer r.Body.Close() 19 data, err := io.ReadAll(r.Body) 20 if err != nil { 21 return nil, err 22 } 23 24 authToken := r.Header.Get(authHeader) 25 if authToken == "" { 26 return nil, ErrNoAuthHeader 27 } 28 29 v, err := auth.ParseAPIToken(authToken) 30 if err != nil { 31 return nil, err 32 } 33 34 secret := provider.GetSecret(v.APIKey()) 35 if secret == "" { 36 return nil, ErrSecretNotFound 37 } 38 39 claims, err := v.Verify(secret) 40 if err != nil { 41 return nil, err 42 } 43 44 // verify checksum 45 sha := sha256.Sum256(data) 46 hash := base64.StdEncoding.EncodeToString(sha[:]) 47 48 if claims.Sha256 != hash { 49 return nil, ErrInvalidChecksum 50 } 51 52 return data, nil 53 } 54 55 // ReceiveWebhookEvent reads and verifies incoming webhook, and returns a parsed WebhookEvent 56 func ReceiveWebhookEvent(r *http.Request, provider auth.KeyProvider) (*livekit.WebhookEvent, error) { 57 data, err := Receive(r, provider) 58 if err != nil { 59 return nil, err 60 } 61 unmarshalOpts := protojson.UnmarshalOptions{ 62 DiscardUnknown: true, 63 AllowPartial: true, 64 } 65 event := livekit.WebhookEvent{} 66 if err = unmarshalOpts.Unmarshal(data, &event); err != nil { 67 return nil, err 68 } 69 return &event, nil 70 }