github.com/livekit/protocol@v1.16.1-0.20240517185851-47e4c6bba773/webhook/verifier.go (about) 1 // Copyright 2023 LiveKit, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package webhook 16 17 import ( 18 "crypto/sha256" 19 "encoding/base64" 20 "io" 21 "net/http" 22 23 "google.golang.org/protobuf/encoding/protojson" 24 25 "github.com/livekit/protocol/auth" 26 "github.com/livekit/protocol/livekit" 27 ) 28 29 // Receive reads and verifies incoming webhook is signed with key/secret pair 30 // closes body after reading 31 func Receive(r *http.Request, provider auth.KeyProvider) ([]byte, error) { 32 defer r.Body.Close() 33 data, err := io.ReadAll(r.Body) 34 if err != nil { 35 return nil, err 36 } 37 38 authToken := r.Header.Get(authHeader) 39 if authToken == "" { 40 return nil, ErrNoAuthHeader 41 } 42 43 v, err := auth.ParseAPIToken(authToken) 44 if err != nil { 45 return nil, err 46 } 47 48 secret := provider.GetSecret(v.APIKey()) 49 if secret == "" { 50 return nil, ErrSecretNotFound 51 } 52 53 claims, err := v.Verify(secret) 54 if err != nil { 55 return nil, err 56 } 57 58 // verify checksum 59 sha := sha256.Sum256(data) 60 hash := base64.StdEncoding.EncodeToString(sha[:]) 61 62 if claims.Sha256 != hash { 63 return nil, ErrInvalidChecksum 64 } 65 66 return data, nil 67 } 68 69 // ReceiveWebhookEvent reads and verifies incoming webhook, and returns a parsed WebhookEvent 70 func ReceiveWebhookEvent(r *http.Request, provider auth.KeyProvider) (*livekit.WebhookEvent, error) { 71 data, err := Receive(r, provider) 72 if err != nil { 73 return nil, err 74 } 75 unmarshalOpts := protojson.UnmarshalOptions{ 76 DiscardUnknown: true, 77 AllowPartial: true, 78 } 79 event := livekit.WebhookEvent{} 80 if err = unmarshalOpts.Unmarshal(data, &event); err != nil { 81 return nil, err 82 } 83 return &event, nil 84 }