* added webhook timeout to config

* code cleanup
This commit is contained in:
Ubuntu 2022-06-19 19:48:53 +00:00
parent 44128ceb13
commit b37846b303
4 changed files with 70 additions and 94 deletions

View File

@ -318,8 +318,12 @@ metrics:
password:
# Webhook configuration
webhook:
# If set to true, HTTP POST is executed
enabled: true
# URL for webhook
url: "http://127.0.0.1/test/"
webhooks:
- events : [ '*' ]
# URL for webhook
url: "http://127.0.0.1/test/test1/?q="
secret : "abc123"
- events : [ 'task.', 'foobar.' ]
# URL for webhook
url: "http://127.0.0.1/test/test2/"
# no secret == no HMAC

View File

@ -160,7 +160,7 @@ const (
MetricsUsername Key = `metrics.username`
MetricsPassword Key = `metrics.password`
WebhookConf Key = `webhooks`
WebhooksConf Key = `webhooks`
)
// Unmarshal object directly from config
@ -376,9 +376,7 @@ func InitDefaultConfig() {
// Metrics
MetricsEnabled.setDefault(false)
WebhookConf.setDefault( []int{} )
// WebhookEnabled.setDefault(false)
// WebhookURL.setDefault("")
WebhooksConf.setDefault( []int{} )
}
// InitConfig initializes the config, sets defaults etc.

View File

@ -1,3 +1,19 @@
// Vikunja is a to-do list application to facilitate your life.
// Copyright 2018-2021 Vikunja and contributors. All rights reserved.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public Licensee as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public Licensee for more details.
//
// You should have received a copy of the GNU Affero General Public Licensee
// along with this program. If not, see <https://www.gnu.org/licenses/>.
package webhooks
@ -8,15 +24,13 @@ import (
"github.com/ThreeDotsLabs/watermill/message"
)
// type middlwareFunc func(message.HandlerFunc) message.HandlerFunc
func GenerateMiddleware() message.HandlerMiddleware {
runtimeConfig := ProcessConfig()
return func(hf message.HandlerFunc) message.HandlerFunc {
return func(msg *message.Message) ([]*message.Message, error) {
topic := message.SubscribeTopicFromCtx(msg.Context() )
TheGreatWebhookHandler(runtimeConfig, topic, msg)
handleOutgoingWebhook(runtimeConfig, topic, msg)
newMsg, err := hf(msg)
if err != nil {
return nil, err
@ -28,7 +42,7 @@ func GenerateMiddleware() message.HandlerMiddleware {
func TheGreatWebhookHandler(cfg []WebhookRuntimeConfig, topic string, msg *message.Message) {
func handleOutgoingWebhook(cfg []WebhookRuntimeConfig, topic string, msg *message.Message) {
log.Debugf("Webhook handler for '%s'", topic)
for i, entry := range cfg {
log.Debugf("Checking webhook config [%d]", i)
@ -39,53 +53,3 @@ func TheGreatWebhookHandler(cfg []WebhookRuntimeConfig, topic string, msg *messa
}
}
/*
func OldWebhookMiddleware(h message.HandlerFunc) message.HandlerFunc {
return func(msg *message.Message) ([]*message.Message, error) {
topic := message.SubscribeTopicFromCtx(msg.Context() )
//TheGreatWebhookHandler(topic, msg)
*
log.Debugf("MIDDLEWARE: %s ", msg )
log.Debugf("MIDDLEWARE META : %s ", msg.Metadata )
log.Debugf("MIDDLEWARE PAYLOAD : %s ", msg.Payload )
log.Debugf("MIDDLEWARE PUB : %s ", message.PublishTopicFromCtx(msg.Context()) )
log.Debugf("MIDDLEWARE SUB : %s ", message.SubscribeTopicFromCtx(msg.Context()) )
*
newMsg, err := h(msg)
if err != nil {
return nil, err
}
return newMsg, nil
}
}
func OldTheGreatWebhookHandler(name string, msg *message.Message) {
log.Debugf("Webhook for %s => %s", name, msg.Payload)
for endpoint := range config.WebhookConf {
log.Debugf("ENDPOINT : %s ", endpoint )
}
base_url := "123" // config.WebhookURL.GetString()
webhook_url := fmt.Sprintf("%s?event=%s", base_url, name)
data := bytes.NewBuffer(msg.Payload)
_, err := http.Post(webhook_url, "application/json",data)
if err != nil {
log.Debugf("Webhook failed : %s ", webhook_url )
} else {
log.Debugf("Webhook success : %s ", webhook_url )
}
}
*/

View File

@ -1,3 +1,18 @@
// Vikunja is a to-do list application to facilitate your life.
// Copyright 2018-2021 Vikunja and contributors. All rights reserved.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public Licensee as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public Licensee for more details.
//
// You should have received a copy of the GNU Affero General Public Licensee
// along with this program. If not, see <https://www.gnu.org/licenses/>.
package webhooks
@ -19,10 +34,10 @@ import (
)
const (
timeoutVal = 5 * time.Second
defaultTimeout = 5 * time.Second
ctHeader = "Content-Type"
ctValue = "application/json"
hmacHeader = "X-signature"
hmacHeader = "X-Signature"
)
type FilteringFunction func(string) (bool)
@ -34,6 +49,7 @@ type SingleConfEntry struct {
Events []string `json:"events"`
URL string `json:"url"`
Secret string `json:"secret"`
Timeout int `json:"timeout"`
}
@ -44,8 +60,8 @@ type WebhookRuntimeConfig struct {
func GetWebhookFilterFunc(cfg SingleConfEntry) FilteringFunction {
return func(topic string) (iteresting bool) {
func getWebhookFilterFunc(cfg SingleConfEntry) FilteringFunction {
return func(topic string) (is_interesting bool) {
for _, filter := range cfg.Events {
log.Debugf("Match pattern:'%s' agains:'%s'", filter, topic)
if filter == "*" {
@ -53,33 +69,38 @@ func GetWebhookFilterFunc(cfg SingleConfEntry) FilteringFunction {
return true
} else {
if strings.HasPrefix(topic, filter) {
log.Debugf(" Positive match ")
log.Debugf("Positive match [%s] -> [%s]", filter, topic)
return true
}
}
}
log.Debugf("No match for [%s]", topic)
return false
}
}
func GetWebhookCallFunc(cfg SingleConfEntry) WebhookCallFunction {
func getWebhookCallFunc(cfg SingleConfEntry) WebhookCallFunction {
return func(topic string, msg *message.Message) (error) {
endpointURL := cfg.URL
hmacKey := cfg.Secret
timeout := defaultTimeout
if cfg.Timeout > 0 {
timeout = time.Second * time.Duration(cfg.Timeout)
}
log.Debugf("Webhook Call : %s (%s)", endpointURL, hmacKey)
log.Debugf("Webhook Call : %s (key=%s)", endpointURL, hmacKey)
webhookUrl := fmt.Sprintf("%s%s", endpointURL, topic)
rawData := msg.Payload
req, err1 := http.NewRequest( http.MethodPost, webhookUrl, bytes.NewBuffer(rawData))
req, err := http.NewRequest( http.MethodPost, webhookUrl, bytes.NewBuffer(rawData))
if err1 != nil {
return err1
if err != nil {
return err
}
client := &http.Client{
Timeout: timeoutVal,
Timeout: timeout,
}
req.Header.Set(ctHeader, ctValue)
@ -89,12 +110,11 @@ func GetWebhookCallFunc(cfg SingleConfEntry) WebhookCallFunction {
req.Header.Set(hmacHeader, signature)
}
_, err2 := client.Do(req)
_, err = client.Do(req)
//_, err := http.Post(webhook_url, "application/json",data) "x-vikunja-signature"
if err2 != nil {
log.Debugf("Webhook failed : %s , +%v", webhookUrl , err2)
return err2
if err != nil {
log.Debugf("Webhook failed : %s , +%v", webhookUrl , err)
return err
}
log.Debugf("Webhook success : %s ", webhookUrl )
@ -117,26 +137,16 @@ func ProcessConfig() ([]WebhookRuntimeConfig) {
var items []SingleConfEntry
config.WebhookConf.GetUnmarshaled(&items)
config.WebhooksConf.GetUnmarshaled(&items)
runtime := make([]WebhookRuntimeConfig, len(items))
fmt.Printf("RAW: %+v\n", items)
log.Debugf("Webhook config items : %+v\n", items)
for i, item := range items {
fmt.Printf("RAW ITEM: %d : %+v\n", i, item)
for j, exp := range item.Events {
fmt.Printf("RAW exp : %d %s\n", j, exp)
}
runtime[i].FilterFunc = GetWebhookFilterFunc(item)
runtime[i].ExecuteFunc = GetWebhookCallFunc(item)
runtime[i].FilterFunc = getWebhookFilterFunc(item)
runtime[i].ExecuteFunc = getWebhookCallFunc(item)
}
// fmt.Printf("RAW: %+v\n", runtime)
//for i := range items {
// runtime[i].FilterFunc("test")
//}
return runtime
}