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"`
|
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:"event"`
|
||||||
ProjectID int64 `xorm:"bigint not null index" json:"project_id" param:"project"`
|
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:"-"`
|
CreatedByID int64 `xorm:"bigint not null" json:"-"`
|
||||||
Created time.Time `xorm:"created not null" json:"created"`
|
Created time.Time `xorm:"created not null" json:"created"`
|
||||||
Updated time.Time `xorm:"updated not null" json:"updated"`
|
Updated time.Time `xorm:"updated not null" json:"updated"`
|
||||||
|
@ -17,10 +17,7 @@
|
|||||||
package models
|
package models
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"code.vikunja.io/api/pkg/version"
|
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"net/http"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -715,23 +712,11 @@ func (wl *WebhookListener) Handle(msg *message.Message) (err error) {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
payload, err := json.Marshal(WebhookPayload{
|
err = webhook.sendWebhookPayload(&WebhookPayload{
|
||||||
EventName: wl.EventName,
|
EventName: wl.EventName,
|
||||||
Time: time.Now(),
|
Time: time.Now(),
|
||||||
Data: event,
|
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
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,9 +17,17 @@
|
|||||||
package models
|
package models
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"code.vikunja.io/api/pkg/events"
|
"code.vikunja.io/api/pkg/events"
|
||||||
|
"code.vikunja.io/api/pkg/log"
|
||||||
"code.vikunja.io/api/pkg/user"
|
"code.vikunja.io/api/pkg/user"
|
||||||
|
"code.vikunja.io/api/pkg/version"
|
||||||
"code.vikunja.io/web"
|
"code.vikunja.io/web"
|
||||||
|
"crypto/hmac"
|
||||||
|
"crypto/sha256"
|
||||||
|
"encoding/hex"
|
||||||
|
"encoding/json"
|
||||||
|
"net/http"
|
||||||
"sort"
|
"sort"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
@ -29,8 +37,9 @@ import (
|
|||||||
type Webhook struct {
|
type Webhook struct {
|
||||||
ID int64 `xorm:"bigint autoincr not null unique pk" json:"id" param:"webhook"`
|
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"`
|
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"`
|
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.
|
// The user who initially created the webhook target.
|
||||||
CreatedBy *user.User `xorm:"-" json:"created_by" valid:"-"`
|
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{})
|
_, err = s.Where("id = ?", w.ID).Delete(&Webhook{})
|
||||||
return
|
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