Webhooks are automated messages sent in response to specific events, known as triggers. In CloudSoda, you can create webhooks to receive notifications when certain transfer-related events occur - such as a scheduled job starting, pausing or being cancelled. To create a webhook, follow these steps:
- Click Orchestration > Administration in the left-hand navigation panel.
The Administration page displays and defaults to the SMTP tab.
- Click Notifications at the top-right of the page.
- Click Create Webhook.
The Create a Webhook dialog box displays.
- Configure the webhook:
- Name: Enter a name for the webhook.
- Delivery: Specify the URL where the webhook should be posted.
- Signature: Specify the Secret Key, which ensures the webhook is sent from a verified sender. For more details on the Secret Key, refer to the Signature section.
-
Triggers: Select one or more triggers that will activate the webhook.
- Click Save.
The new webhook is created.
Signature
CloudSoda signs its requests using a secret key that is unique. By having a signed secret key, you can more confidently verify whether a request is from CloudSoda or a bad actor.
Verifying the Request Signature
- Retrieve the X-Hub-Signature-Timestamp header from the HTTP request, and the body of the request.
- Concatenate the body of the request with the value of the X-Hub-Signature-Timestamp using a period as a delimiter between the two elements creating a basestring.
- Using the HMAC SHA256 implemented in your chosen programming language, hash the basestring, using your signed secret as the key and base64 encode it.
- Compare this computed signature to the X-Hub-Signature-256 header on the request. Please note the signature is base64 encoded and has an algorithm prefix that should be stripped before doing the signature comparison. For example, if the value of X-Hub-Signature-256 is sha256=ZGnKWojQLWtnYSdWwQn1zyZkusK1hEqbokvqfs9CdkM= you would want to use ZGnKWojQLWtnYSdWwQn1zyZkusK1hEqbokvqfs9CdkM= for the signature
This is a verify example written in Go. This example shows the X-Hub-Signature-256 being base64 decoded rather than the secret being base64 encoded as described in the above steps. Either approach will work, but it needs to be consistent.
package main
import (
"crypto/hmac"
"crypto/sha1"
"crypto/sha256"
"encoding/base64"
"fmt"
"hash"
"io"
"log"
"net/http"
"strings"
"github.com/gorilla/mux"
)
const secret = "my-soda-secret"
func main() {
log.Println("starting server")
r := mux.NewRouter()
r.HandleFunc("/", testWebhook).Methods(http.MethodPost)
http.ListenAndServe(":80", r)
}
func test Webhook(w http.ResponseWriter, r *http.Request) {
body, err := io.ReadAll(r.Body)
if err != nil {
fmt.Println("Failed to read body")
}
sodaSignature := r.Header.Get("X-Hub-Signature-256")
sodaTimeStamp := r.Header.Get("X-Hub-Signature-Timestamp")
basestring := []byte(string(body) + "." + sodaTimeStamp)
valid := Validate(basestring, sodaSignature, secret)
fmt.Printf("Valid HMAC? %v\n", valid)
}
func CheckMAC(message, messageMAC, key []byte, sha func() hash.Hash) bool {
mac := hmac.New(sha, key)
mac.Write(message)
expectedMAC := mac.Sum(nil)
return hmac.Equal(messageMAC, expectedMAC)
}
func Sign(message, key []byte, sha func() hash.Hash) []byte {
mac := hmac.New(sha, key)
mac.Write(message)
signed := mac.Sum(nil)
return signed
}
func Validate(bytesIn []byte, encodedHash string, secretKey string) error {
var validated error
var hashFn func() hash.Hash
var payload string
if strings.HasPrefix(encodedHash, "sha1=") {
payload = strings.TrimPrefix(encodedHash, "sha1=")
hashFn = sha1.New
} elseif strings.HasPrefix(encodedHash, "sha256=") {
payload = strings.TrimPrefix(encodedHash, "sha256=")
hashFn = sha256.New
} else {
return fmt.Errorf("valid hash prefixes: [sha1=, sha256=], got: %s", encodedHash)
}
messageMAC := payload
messageMACBuf, err := base64.StdEncoding.DecodeString(messageMAC)
if err != nil {
fmt.Println(err)
}
res := CheckMAC(bytesIn, []byte(messageMACBuf), []byte(secretKey), hashFn)
if !res {
validated = fmt.Errorf("invalid message digest or secret")
}
return validated
}
Comments
0 comments
Please sign in to leave a comment.