feat(webhooks): add hmac signing
This commit is contained in:
parent
a3a323cbf1
commit
a0d8b28813
@ -27,6 +27,7 @@ type webhooks20230913202615 struct {
|
||||
TargetURL string `xorm:"not null" valid:"minstringlength(1)" minLength:"1" json:"target_url"`
|
||||
Events []string `xorm:"JSON not null" valid:"minstringlength(1)" minLength:"1" json:"event"`
|
||||
ProjectID int64 `xorm:"bigint not null index" json:"project_id" param:"project"`
|
||||
Secret string `xorm:"null" json:"secret"`
|
||||
CreatedByID int64 `xorm:"bigint not null" json:"-"`
|
||||
Created time.Time `xorm:"created not null" json:"created"`
|
||||
Updated time.Time `xorm:"updated not null" json:"updated"`
|
||||
|
@ -17,10 +17,7 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"code.vikunja.io/api/pkg/version"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
@ -715,23 +712,11 @@ func (wl *WebhookListener) Handle(msg *message.Message) (err error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
payload, err := json.Marshal(WebhookPayload{
|
||||
err = webhook.sendWebhookPayload(&WebhookPayload{
|
||||
EventName: wl.EventName,
|
||||
Time: time.Now(),
|
||||
Data: event,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
req, err := http.NewRequest(http.MethodPost, webhook.TargetURL, bytes.NewReader(payload))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
req.Header.Add("User-Agent", "Vikunja/"+version.Version)
|
||||
_, err = http.DefaultClient.Do(req)
|
||||
if err == nil {
|
||||
log.Debugf("Sent webhook payload for webhook %d for event %s", webhook.ID, wl.EventName)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -17,9 +17,17 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"code.vikunja.io/api/pkg/events"
|
||||
"code.vikunja.io/api/pkg/log"
|
||||
"code.vikunja.io/api/pkg/user"
|
||||
"code.vikunja.io/api/pkg/version"
|
||||
"code.vikunja.io/web"
|
||||
"crypto/hmac"
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"sort"
|
||||
"sync"
|
||||
"time"
|
||||
@ -29,8 +37,9 @@ import (
|
||||
type Webhook struct {
|
||||
ID int64 `xorm:"bigint autoincr not null unique pk" json:"id" param:"webhook"`
|
||||
TargetURL string `xorm:"not null" valid:"minstringlength(1)" minLength:"1" json:"target_url"`
|
||||
Events []string `xorm:"JSON not null" valid:"minstringlength(1)" minLength:"1" json:"event"`
|
||||
Events []string `xorm:"JSON not null" valid:"minstringlength(1)" minLength:"1" json:"events"`
|
||||
ProjectID int64 `xorm:"bigint not null index" json:"project_id" param:"project"`
|
||||
Secret string `xorm:"null" json:"secret"`
|
||||
|
||||
// The user who initially created the webhook target.
|
||||
CreatedBy *user.User `xorm:"-" json:"created_by" valid:"-"`
|
||||
@ -124,3 +133,33 @@ func (w *Webhook) Delete(s *xorm.Session, a web.Auth) (err error) {
|
||||
_, err = s.Where("id = ?", w.ID).Delete(&Webhook{})
|
||||
return
|
||||
}
|
||||
|
||||
func (w *Webhook) sendWebhookPayload(p *WebhookPayload) (err error) {
|
||||
payload, err := json.Marshal(p)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
req, err := http.NewRequest(http.MethodPost, w.TargetURL, bytes.NewReader(payload))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(w.Secret) > 0 {
|
||||
sig256 := hmac.New(sha256.New, []byte(w.Secret))
|
||||
_, err = sig256.Write(payload)
|
||||
if err != nil {
|
||||
log.Errorf("Could not generate webhook signature for Webhook %d: %s", w.ID, err)
|
||||
}
|
||||
signature := hex.EncodeToString(sig256.Sum(nil))
|
||||
req.Header.Add("X-Vikunja-Signature", signature)
|
||||
}
|
||||
|
||||
req.Header.Add("User-Agent", "Vikunja/"+version.Version)
|
||||
|
||||
_, err = http.DefaultClient.Do(req)
|
||||
if err == nil {
|
||||
log.Debugf("Sent webhook payload for webhook %d for event %s", w.ID, p.EventName)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user