Pass HMAC in header for integrity

This commit is contained in:
Rounak Datta 2022-06-03 20:51:23 +05:30
parent c9e67570ea
commit 1745dbb85d
No known key found for this signature in database
GPG Key ID: A04E86FD28F5A421
4 changed files with 34 additions and 9 deletions

View File

@ -160,8 +160,9 @@ const (
MetricsUsername Key = `metrics.username`
MetricsPassword Key = `metrics.password`
WebhookEnabled Key = "webhook.enabled"
WebhookEndpointURL Key = "webhook.endpointurl"
WebhookNotificationsEnabled Key = "notifications.webhook.enabled"
WebhookNotificationEndpointURL Key = "notifications.webhook.endpointurl"
WebhookNotificationSignatureSecret Key = "notifications.webhook.signaturesecret"
)
// GetString returns a string config value
@ -370,8 +371,9 @@ func InitDefaultConfig() {
KeyvalueType.setDefault("memory")
// Metrics
MetricsEnabled.setDefault(false)
// Webhook Notifications
WebhookEnabled.setDefault(false)
// Webhook Notification
WebhookNotificationsEnabled.setDefault(false)
WebhookNotificationSignatureSecret.setDefault("")
}
// InitConfig initializes the config, sets defaults etc.

View File

@ -16,7 +16,6 @@ func DoPost(url string, body string, headers map[string]string) (resp *http.Resp
for k, v := range headers {
req.Header.Add(k, v)
}
req.Header.Add("Content-Type", "application/json")
hc := http.Client{}
return hc.Do(req)
}

View File

@ -59,7 +59,7 @@ func Notify(notifiable Notifiable, notification Notification) (err error) {
return
}
if config.WebhookEnabled.GetBool() {
if config.WebhookNotificationsEnabled.GetBool() {
err = notifyWebhook(notifiable, notification)
if err != nil {
return
@ -90,10 +90,14 @@ func notifyWebhook(notifiable Notifiable, notification Notification) error {
return err
}
signature := GenerateHMAC(string(content))
webhookNotification := &WebhookNotification{
endpointURL: config.DatabasePassword.GetString(),
headers: map[string]string{}, // TODO: allow passing user-configurable headers
body: string(content),
endpointURL: config.WebhookNotificationEndpointURL.GetString(),
headers: map[string]string{
webhookNotificationSignatureHeader: signature,
webhookNotificationContentTypeHeader: "application/json",
},
body: string(content),
}
return SendWebhook(webhookNotification)

View File

@ -16,6 +16,19 @@
package notifications
import (
"crypto/hmac"
"crypto/sha256"
"encoding/hex"
"code.vikunja.io/api/pkg/config"
)
const (
webhookNotificationSignatureHeader = "x-vikunja-signature"
webhookNotificationContentTypeHeader = "Content-Type"
)
// WebhookNotification represents a notification that published to a http endpoint
type WebhookNotification struct {
endpointURL string
@ -23,6 +36,13 @@ type WebhookNotification struct {
body string
}
// GenerateHMAC generates a HMAC code for the webhook body signed with the configured secret
func GenerateHMAC(requestBody string) string {
h := hmac.New(sha256.New, []byte(config.WebhookNotificationSignatureSecret.GetString()))
h.Write([]byte(requestBody))
return hex.EncodeToString(h.Sum(nil))
}
// SendWebhook sends the notification to the configured endpoint
func SendWebhook(w *WebhookNotification) error {
resp, err := DoPost(w.endpointURL, w.body, w.headers)