feat(webhooks): validate events and target url

This commit is contained in:
kolaente 2023-10-20 12:42:28 +02:00
parent 61cd08fa13
commit 55d345e236
Signed by untrusted user: konrad
GPG Key ID: F40E70337AB24C9B
3 changed files with 32 additions and 15 deletions

View File

@ -110,6 +110,17 @@ func (err ValidationHTTPError) Error() string {
return theErr.Error()
}
func InvalidFieldError(fields []string) error {
return ValidationHTTPError{
HTTPError: web.HTTPError{
HTTPCode: http.StatusPreconditionFailed,
Code: ErrCodeInvalidData,
Message: "Invalid Data",
},
InvalidFields: fields,
}
}
// ===========
// Project errors
// ===========

View File

@ -27,6 +27,7 @@ import (
"net/http"
"net/url"
"sort"
"strings"
"sync"
"time"
@ -45,9 +46,9 @@ type Webhook struct {
// The generated ID of this webhook target
ID int64 `xorm:"bigint autoincr not null unique pk" json:"id" param:"webhook"`
// The target URL where the POST request with the webhook payload will be made
TargetURL string `xorm:"not null" valid:"minstringlength(1)" minLength:"1" json:"target_url"`
TargetURL string `xorm:"not null" valid:"required,url" json:"target_url"`
// The webhook events which should fire this webhook target
Events []string `xorm:"JSON not null" valid:"minstringlength(1)" minLength:"1" json:"events"`
Events []string `xorm:"JSON not null" valid:"required" json:"events"`
// The project ID of the project this webhook target belongs to
ProjectID int64 `xorm:"bigint not null index" json:"project_id" param:"project"`
// If provided, webhook requests will be signed using HMAC. Check out the docs about how to use this: https://vikunja.io/docs/webhooks/#signing
@ -113,7 +114,17 @@ func GetAvailableWebhookEvents() []string {
// @Failure 500 {object} models.Message "Internal error"
// @Router /projects/{id}/webhooks [put]
func (w *Webhook) Create(s *xorm.Session, a web.Auth) (err error) {
// TODO: check valid webhook events
if !strings.HasPrefix(w.TargetURL, "http") {
return InvalidFieldError([]string{"target_url"})
}
for _, event := range w.Events {
if _, has := availableWebhookEvents[event]; !has {
return InvalidFieldError([]string{"events"})
}
}
w.CreatedByID = a.GetID()
_, err = s.Insert(w)
if err != nil {
@ -193,7 +204,12 @@ func (w *Webhook) ReadAll(s *xorm.Session, a web.Auth, _ string, page int, perPa
// @Failure 500 {object} models.Message "Internal error"
// @Router /projects/{id}/webhooks/{webhookID} [post]
func (w *Webhook) Update(s *xorm.Session, _ web.Auth) (err error) {
// TODO validate webhook events
for _, event := range w.Events {
if _, has := availableWebhookEvents[event]; !has {
return InvalidFieldError([]string{"events"})
}
}
_, err = s.Where("id = ?", w.ID).
Cols("events").
Update(w)

View File

@ -17,11 +17,8 @@
package routes
import (
"net/http"
"code.vikunja.io/api/pkg/models"
"code.vikunja.io/web"
"github.com/asaskevich/govalidator"
)
@ -43,14 +40,7 @@ func (cv *CustomValidator) Validate(i interface{}) error {
errs = append(errs, field+": "+e)
}
return models.ValidationHTTPError{
HTTPError: web.HTTPError{
HTTPCode: http.StatusPreconditionFailed,
Code: models.ErrCodeInvalidData,
Message: "Invalid Data",
},
InvalidFields: errs,
}
return models.InvalidFieldError(errs)
}
return nil
}