Refactor Webhook + Add X-Hub-Signature (#16176)
This PR removes multiple unneeded fields from the `HookTask` struct and adds the two headers `X-Hub-Signature` and `X-Hub-Signature-256`. ## ⚠️ BREAKING ⚠️ * The `Secret` field is no longer passed as part of the payload. * "Breaking" change (or fix?): The webhook history shows the real called url and not the url registered in the webhook (`deliver.go`@129). Close #16115 Fixes #7788 Fixes #11755 Co-authored-by: zeripath <art27@cantab.net>
This commit is contained in:
parent
0b27b93728
commit
9b1b4b5433
18 changed files with 130 additions and 179 deletions
|
@ -323,6 +323,8 @@ var migrations = []Migration{
|
||||||
NewMigration("Add new table repo_archiver", addRepoArchiver),
|
NewMigration("Add new table repo_archiver", addRepoArchiver),
|
||||||
// v186 -> v187
|
// v186 -> v187
|
||||||
NewMigration("Create protected tag table", createProtectedTagTable),
|
NewMigration("Create protected tag table", createProtectedTagTable),
|
||||||
|
// v187 -> v188
|
||||||
|
NewMigration("Drop unneeded webhook related columns", dropWebhookColumns),
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetCurrentDBVersion returns the current db version
|
// GetCurrentDBVersion returns the current db version
|
||||||
|
|
46
models/migrations/v187.go
Normal file
46
models/migrations/v187.go
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
// Copyright 2021 The Gitea Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a MIT-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package migrations
|
||||||
|
|
||||||
|
import (
|
||||||
|
"xorm.io/xorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
func dropWebhookColumns(x *xorm.Engine) error {
|
||||||
|
// Make sure the columns exist before dropping them
|
||||||
|
type Webhook struct {
|
||||||
|
Signature string `xorm:"TEXT"`
|
||||||
|
IsSSL bool `xorm:"is_ssl"`
|
||||||
|
}
|
||||||
|
if err := x.Sync2(new(Webhook)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
type HookTask struct {
|
||||||
|
Typ string `xorm:"VARCHAR(16) index"`
|
||||||
|
URL string `xorm:"TEXT"`
|
||||||
|
Signature string `xorm:"TEXT"`
|
||||||
|
HTTPMethod string `xorm:"http_method"`
|
||||||
|
ContentType int
|
||||||
|
IsSSL bool
|
||||||
|
}
|
||||||
|
if err := x.Sync2(new(HookTask)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
sess := x.NewSession()
|
||||||
|
defer sess.Close()
|
||||||
|
if err := sess.Begin(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := dropTableColumns(sess, "webhook", "signature", "is_ssl"); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := dropTableColumns(sess, "hook_task", "typ", "url", "signature", "http_method", "content_type", "is_ssl"); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return sess.Commit()
|
||||||
|
}
|
|
@ -109,6 +109,22 @@ type HookEvent struct {
|
||||||
HookEvents `json:"events"`
|
HookEvents `json:"events"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// HookType is the type of a webhook
|
||||||
|
type HookType = string
|
||||||
|
|
||||||
|
// Types of webhooks
|
||||||
|
const (
|
||||||
|
GITEA HookType = "gitea"
|
||||||
|
GOGS HookType = "gogs"
|
||||||
|
SLACK HookType = "slack"
|
||||||
|
DISCORD HookType = "discord"
|
||||||
|
DINGTALK HookType = "dingtalk"
|
||||||
|
TELEGRAM HookType = "telegram"
|
||||||
|
MSTEAMS HookType = "msteams"
|
||||||
|
FEISHU HookType = "feishu"
|
||||||
|
MATRIX HookType = "matrix"
|
||||||
|
)
|
||||||
|
|
||||||
// HookStatus is the status of a web hook
|
// HookStatus is the status of a web hook
|
||||||
type HookStatus int
|
type HookStatus int
|
||||||
|
|
||||||
|
@ -126,17 +142,15 @@ type Webhook struct {
|
||||||
OrgID int64 `xorm:"INDEX"`
|
OrgID int64 `xorm:"INDEX"`
|
||||||
IsSystemWebhook bool
|
IsSystemWebhook bool
|
||||||
URL string `xorm:"url TEXT"`
|
URL string `xorm:"url TEXT"`
|
||||||
Signature string `xorm:"TEXT"`
|
|
||||||
HTTPMethod string `xorm:"http_method"`
|
HTTPMethod string `xorm:"http_method"`
|
||||||
ContentType HookContentType
|
ContentType HookContentType
|
||||||
Secret string `xorm:"TEXT"`
|
Secret string `xorm:"TEXT"`
|
||||||
Events string `xorm:"TEXT"`
|
Events string `xorm:"TEXT"`
|
||||||
*HookEvent `xorm:"-"`
|
*HookEvent `xorm:"-"`
|
||||||
IsSSL bool `xorm:"is_ssl"`
|
IsActive bool `xorm:"INDEX"`
|
||||||
IsActive bool `xorm:"INDEX"`
|
Type HookType `xorm:"VARCHAR(16) 'type'"`
|
||||||
Type HookTaskType `xorm:"VARCHAR(16) 'type'"`
|
Meta string `xorm:"TEXT"` // store hook-specific attributes
|
||||||
Meta string `xorm:"TEXT"` // store hook-specific attributes
|
LastStatus HookStatus // Last delivery status
|
||||||
LastStatus HookStatus // Last delivery status
|
|
||||||
|
|
||||||
CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"`
|
CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"`
|
||||||
UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"`
|
UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"`
|
||||||
|
@ -558,22 +572,6 @@ func copyDefaultWebhooksToRepo(e Engine, repoID int64) error {
|
||||||
// \___|_ / \____/ \____/|__|_ \ |____| (____ /____ >__|_ \
|
// \___|_ / \____/ \____/|__|_ \ |____| (____ /____ >__|_ \
|
||||||
// \/ \/ \/ \/ \/
|
// \/ \/ \/ \/ \/
|
||||||
|
|
||||||
// HookTaskType is the type of an hook task
|
|
||||||
type HookTaskType = string
|
|
||||||
|
|
||||||
// Types of hook tasks
|
|
||||||
const (
|
|
||||||
GITEA HookTaskType = "gitea"
|
|
||||||
GOGS HookTaskType = "gogs"
|
|
||||||
SLACK HookTaskType = "slack"
|
|
||||||
DISCORD HookTaskType = "discord"
|
|
||||||
DINGTALK HookTaskType = "dingtalk"
|
|
||||||
TELEGRAM HookTaskType = "telegram"
|
|
||||||
MSTEAMS HookTaskType = "msteams"
|
|
||||||
FEISHU HookTaskType = "feishu"
|
|
||||||
MATRIX HookTaskType = "matrix"
|
|
||||||
)
|
|
||||||
|
|
||||||
// HookEventType is the type of an hook event
|
// HookEventType is the type of an hook event
|
||||||
type HookEventType string
|
type HookEventType string
|
||||||
|
|
||||||
|
@ -635,7 +633,9 @@ func (h HookEventType) Event() string {
|
||||||
|
|
||||||
// HookRequest represents hook task request information.
|
// HookRequest represents hook task request information.
|
||||||
type HookRequest struct {
|
type HookRequest struct {
|
||||||
Headers map[string]string `json:"headers"`
|
URL string `json:"url"`
|
||||||
|
HTTPMethod string `json:"http_method"`
|
||||||
|
Headers map[string]string `json:"headers"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// HookResponse represents hook task response information.
|
// HookResponse represents hook task response information.
|
||||||
|
@ -651,15 +651,9 @@ type HookTask struct {
|
||||||
RepoID int64 `xorm:"INDEX"`
|
RepoID int64 `xorm:"INDEX"`
|
||||||
HookID int64
|
HookID int64
|
||||||
UUID string
|
UUID string
|
||||||
Typ HookTaskType `xorm:"VARCHAR(16) index"`
|
|
||||||
URL string `xorm:"TEXT"`
|
|
||||||
Signature string `xorm:"TEXT"`
|
|
||||||
api.Payloader `xorm:"-"`
|
api.Payloader `xorm:"-"`
|
||||||
PayloadContent string `xorm:"TEXT"`
|
PayloadContent string `xorm:"TEXT"`
|
||||||
HTTPMethod string `xorm:"http_method"`
|
|
||||||
ContentType HookContentType
|
|
||||||
EventType HookEventType
|
EventType HookEventType
|
||||||
IsSSL bool
|
|
||||||
IsDelivered bool
|
IsDelivered bool
|
||||||
Delivered int64
|
Delivered int64
|
||||||
DeliveredString string `xorm:"-"`
|
DeliveredString string `xorm:"-"`
|
||||||
|
|
|
@ -207,8 +207,6 @@ func TestCreateHookTask(t *testing.T) {
|
||||||
hookTask := &HookTask{
|
hookTask := &HookTask{
|
||||||
RepoID: 3,
|
RepoID: 3,
|
||||||
HookID: 3,
|
HookID: 3,
|
||||||
Typ: GITEA,
|
|
||||||
URL: "http://www.example.com/unit_test",
|
|
||||||
Payloader: &api.PushPayload{},
|
Payloader: &api.PushPayload{},
|
||||||
}
|
}
|
||||||
AssertNotExistsBean(t, hookTask)
|
AssertNotExistsBean(t, hookTask)
|
||||||
|
@ -233,8 +231,6 @@ func TestCleanupHookTaskTable_PerWebhook_DeletesDelivered(t *testing.T) {
|
||||||
hookTask := &HookTask{
|
hookTask := &HookTask{
|
||||||
RepoID: 3,
|
RepoID: 3,
|
||||||
HookID: 3,
|
HookID: 3,
|
||||||
Typ: GITEA,
|
|
||||||
URL: "http://www.example.com/unit_test",
|
|
||||||
Payloader: &api.PushPayload{},
|
Payloader: &api.PushPayload{},
|
||||||
IsDelivered: true,
|
IsDelivered: true,
|
||||||
Delivered: time.Now().UnixNano(),
|
Delivered: time.Now().UnixNano(),
|
||||||
|
@ -252,8 +248,6 @@ func TestCleanupHookTaskTable_PerWebhook_LeavesUndelivered(t *testing.T) {
|
||||||
hookTask := &HookTask{
|
hookTask := &HookTask{
|
||||||
RepoID: 2,
|
RepoID: 2,
|
||||||
HookID: 4,
|
HookID: 4,
|
||||||
Typ: GITEA,
|
|
||||||
URL: "http://www.example.com/unit_test",
|
|
||||||
Payloader: &api.PushPayload{},
|
Payloader: &api.PushPayload{},
|
||||||
IsDelivered: false,
|
IsDelivered: false,
|
||||||
}
|
}
|
||||||
|
@ -270,8 +264,6 @@ func TestCleanupHookTaskTable_PerWebhook_LeavesMostRecentTask(t *testing.T) {
|
||||||
hookTask := &HookTask{
|
hookTask := &HookTask{
|
||||||
RepoID: 2,
|
RepoID: 2,
|
||||||
HookID: 4,
|
HookID: 4,
|
||||||
Typ: GITEA,
|
|
||||||
URL: "http://www.example.com/unit_test",
|
|
||||||
Payloader: &api.PushPayload{},
|
Payloader: &api.PushPayload{},
|
||||||
IsDelivered: true,
|
IsDelivered: true,
|
||||||
Delivered: time.Now().UnixNano(),
|
Delivered: time.Now().UnixNano(),
|
||||||
|
@ -289,8 +281,6 @@ func TestCleanupHookTaskTable_OlderThan_DeletesDelivered(t *testing.T) {
|
||||||
hookTask := &HookTask{
|
hookTask := &HookTask{
|
||||||
RepoID: 3,
|
RepoID: 3,
|
||||||
HookID: 3,
|
HookID: 3,
|
||||||
Typ: GITEA,
|
|
||||||
URL: "http://www.example.com/unit_test",
|
|
||||||
Payloader: &api.PushPayload{},
|
Payloader: &api.PushPayload{},
|
||||||
IsDelivered: true,
|
IsDelivered: true,
|
||||||
Delivered: time.Now().AddDate(0, 0, -8).UnixNano(),
|
Delivered: time.Now().AddDate(0, 0, -8).UnixNano(),
|
||||||
|
@ -308,8 +298,6 @@ func TestCleanupHookTaskTable_OlderThan_LeavesUndelivered(t *testing.T) {
|
||||||
hookTask := &HookTask{
|
hookTask := &HookTask{
|
||||||
RepoID: 2,
|
RepoID: 2,
|
||||||
HookID: 4,
|
HookID: 4,
|
||||||
Typ: GITEA,
|
|
||||||
URL: "http://www.example.com/unit_test",
|
|
||||||
Payloader: &api.PushPayload{},
|
Payloader: &api.PushPayload{},
|
||||||
IsDelivered: false,
|
IsDelivered: false,
|
||||||
}
|
}
|
||||||
|
@ -326,8 +314,6 @@ func TestCleanupHookTaskTable_OlderThan_LeavesTaskEarlierThanAgeToDelete(t *test
|
||||||
hookTask := &HookTask{
|
hookTask := &HookTask{
|
||||||
RepoID: 2,
|
RepoID: 2,
|
||||||
HookID: 4,
|
HookID: 4,
|
||||||
Typ: GITEA,
|
|
||||||
URL: "http://www.example.com/unit_test",
|
|
||||||
Payloader: &api.PushPayload{},
|
Payloader: &api.PushPayload{},
|
||||||
IsDelivered: true,
|
IsDelivered: true,
|
||||||
Delivered: time.Now().AddDate(0, 0, -6).UnixNano(),
|
Delivered: time.Now().AddDate(0, 0, -6).UnixNano(),
|
||||||
|
|
|
@ -62,7 +62,6 @@ type EditHookOption struct {
|
||||||
|
|
||||||
// Payloader payload is some part of one hook
|
// Payloader payload is some part of one hook
|
||||||
type Payloader interface {
|
type Payloader interface {
|
||||||
SetSecret(string)
|
|
||||||
JSONPayload() ([]byte, error)
|
JSONPayload() ([]byte, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -124,7 +123,6 @@ var (
|
||||||
|
|
||||||
// CreatePayload FIXME
|
// CreatePayload FIXME
|
||||||
type CreatePayload struct {
|
type CreatePayload struct {
|
||||||
Secret string `json:"secret"`
|
|
||||||
Sha string `json:"sha"`
|
Sha string `json:"sha"`
|
||||||
Ref string `json:"ref"`
|
Ref string `json:"ref"`
|
||||||
RefType string `json:"ref_type"`
|
RefType string `json:"ref_type"`
|
||||||
|
@ -132,11 +130,6 @@ type CreatePayload struct {
|
||||||
Sender *User `json:"sender"`
|
Sender *User `json:"sender"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetSecret modifies the secret of the CreatePayload
|
|
||||||
func (p *CreatePayload) SetSecret(secret string) {
|
|
||||||
p.Secret = secret
|
|
||||||
}
|
|
||||||
|
|
||||||
// JSONPayload return payload information
|
// JSONPayload return payload information
|
||||||
func (p *CreatePayload) JSONPayload() ([]byte, error) {
|
func (p *CreatePayload) JSONPayload() ([]byte, error) {
|
||||||
json := jsoniter.ConfigCompatibleWithStandardLibrary
|
json := jsoniter.ConfigCompatibleWithStandardLibrary
|
||||||
|
@ -181,7 +174,6 @@ const (
|
||||||
|
|
||||||
// DeletePayload represents delete payload
|
// DeletePayload represents delete payload
|
||||||
type DeletePayload struct {
|
type DeletePayload struct {
|
||||||
Secret string `json:"secret"`
|
|
||||||
Ref string `json:"ref"`
|
Ref string `json:"ref"`
|
||||||
RefType string `json:"ref_type"`
|
RefType string `json:"ref_type"`
|
||||||
PusherType PusherType `json:"pusher_type"`
|
PusherType PusherType `json:"pusher_type"`
|
||||||
|
@ -189,11 +181,6 @@ type DeletePayload struct {
|
||||||
Sender *User `json:"sender"`
|
Sender *User `json:"sender"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetSecret modifies the secret of the DeletePayload
|
|
||||||
func (p *DeletePayload) SetSecret(secret string) {
|
|
||||||
p.Secret = secret
|
|
||||||
}
|
|
||||||
|
|
||||||
// JSONPayload implements Payload
|
// JSONPayload implements Payload
|
||||||
func (p *DeletePayload) JSONPayload() ([]byte, error) {
|
func (p *DeletePayload) JSONPayload() ([]byte, error) {
|
||||||
json := jsoniter.ConfigCompatibleWithStandardLibrary
|
json := jsoniter.ConfigCompatibleWithStandardLibrary
|
||||||
|
@ -209,17 +196,11 @@ func (p *DeletePayload) JSONPayload() ([]byte, error) {
|
||||||
|
|
||||||
// ForkPayload represents fork payload
|
// ForkPayload represents fork payload
|
||||||
type ForkPayload struct {
|
type ForkPayload struct {
|
||||||
Secret string `json:"secret"`
|
|
||||||
Forkee *Repository `json:"forkee"`
|
Forkee *Repository `json:"forkee"`
|
||||||
Repo *Repository `json:"repository"`
|
Repo *Repository `json:"repository"`
|
||||||
Sender *User `json:"sender"`
|
Sender *User `json:"sender"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetSecret modifies the secret of the ForkPayload
|
|
||||||
func (p *ForkPayload) SetSecret(secret string) {
|
|
||||||
p.Secret = secret
|
|
||||||
}
|
|
||||||
|
|
||||||
// JSONPayload implements Payload
|
// JSONPayload implements Payload
|
||||||
func (p *ForkPayload) JSONPayload() ([]byte, error) {
|
func (p *ForkPayload) JSONPayload() ([]byte, error) {
|
||||||
json := jsoniter.ConfigCompatibleWithStandardLibrary
|
json := jsoniter.ConfigCompatibleWithStandardLibrary
|
||||||
|
@ -238,7 +219,6 @@ const (
|
||||||
|
|
||||||
// IssueCommentPayload represents a payload information of issue comment event.
|
// IssueCommentPayload represents a payload information of issue comment event.
|
||||||
type IssueCommentPayload struct {
|
type IssueCommentPayload struct {
|
||||||
Secret string `json:"secret"`
|
|
||||||
Action HookIssueCommentAction `json:"action"`
|
Action HookIssueCommentAction `json:"action"`
|
||||||
Issue *Issue `json:"issue"`
|
Issue *Issue `json:"issue"`
|
||||||
Comment *Comment `json:"comment"`
|
Comment *Comment `json:"comment"`
|
||||||
|
@ -248,11 +228,6 @@ type IssueCommentPayload struct {
|
||||||
IsPull bool `json:"is_pull"`
|
IsPull bool `json:"is_pull"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetSecret modifies the secret of the IssueCommentPayload
|
|
||||||
func (p *IssueCommentPayload) SetSecret(secret string) {
|
|
||||||
p.Secret = secret
|
|
||||||
}
|
|
||||||
|
|
||||||
// JSONPayload implements Payload
|
// JSONPayload implements Payload
|
||||||
func (p *IssueCommentPayload) JSONPayload() ([]byte, error) {
|
func (p *IssueCommentPayload) JSONPayload() ([]byte, error) {
|
||||||
json := jsoniter.ConfigCompatibleWithStandardLibrary
|
json := jsoniter.ConfigCompatibleWithStandardLibrary
|
||||||
|
@ -278,18 +253,12 @@ const (
|
||||||
|
|
||||||
// ReleasePayload represents a payload information of release event.
|
// ReleasePayload represents a payload information of release event.
|
||||||
type ReleasePayload struct {
|
type ReleasePayload struct {
|
||||||
Secret string `json:"secret"`
|
|
||||||
Action HookReleaseAction `json:"action"`
|
Action HookReleaseAction `json:"action"`
|
||||||
Release *Release `json:"release"`
|
Release *Release `json:"release"`
|
||||||
Repository *Repository `json:"repository"`
|
Repository *Repository `json:"repository"`
|
||||||
Sender *User `json:"sender"`
|
Sender *User `json:"sender"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetSecret modifies the secret of the ReleasePayload
|
|
||||||
func (p *ReleasePayload) SetSecret(secret string) {
|
|
||||||
p.Secret = secret
|
|
||||||
}
|
|
||||||
|
|
||||||
// JSONPayload implements Payload
|
// JSONPayload implements Payload
|
||||||
func (p *ReleasePayload) JSONPayload() ([]byte, error) {
|
func (p *ReleasePayload) JSONPayload() ([]byte, error) {
|
||||||
json := jsoniter.ConfigCompatibleWithStandardLibrary
|
json := jsoniter.ConfigCompatibleWithStandardLibrary
|
||||||
|
@ -305,7 +274,6 @@ func (p *ReleasePayload) JSONPayload() ([]byte, error) {
|
||||||
|
|
||||||
// PushPayload represents a payload information of push event.
|
// PushPayload represents a payload information of push event.
|
||||||
type PushPayload struct {
|
type PushPayload struct {
|
||||||
Secret string `json:"secret"`
|
|
||||||
Ref string `json:"ref"`
|
Ref string `json:"ref"`
|
||||||
Before string `json:"before"`
|
Before string `json:"before"`
|
||||||
After string `json:"after"`
|
After string `json:"after"`
|
||||||
|
@ -317,11 +285,6 @@ type PushPayload struct {
|
||||||
Sender *User `json:"sender"`
|
Sender *User `json:"sender"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetSecret modifies the secret of the PushPayload
|
|
||||||
func (p *PushPayload) SetSecret(secret string) {
|
|
||||||
p.Secret = secret
|
|
||||||
}
|
|
||||||
|
|
||||||
// JSONPayload FIXME
|
// JSONPayload FIXME
|
||||||
func (p *PushPayload) JSONPayload() ([]byte, error) {
|
func (p *PushPayload) JSONPayload() ([]byte, error) {
|
||||||
json := jsoniter.ConfigCompatibleWithStandardLibrary
|
json := jsoniter.ConfigCompatibleWithStandardLibrary
|
||||||
|
@ -389,7 +352,6 @@ const (
|
||||||
|
|
||||||
// IssuePayload represents the payload information that is sent along with an issue event.
|
// IssuePayload represents the payload information that is sent along with an issue event.
|
||||||
type IssuePayload struct {
|
type IssuePayload struct {
|
||||||
Secret string `json:"secret"`
|
|
||||||
Action HookIssueAction `json:"action"`
|
Action HookIssueAction `json:"action"`
|
||||||
Index int64 `json:"number"`
|
Index int64 `json:"number"`
|
||||||
Changes *ChangesPayload `json:"changes,omitempty"`
|
Changes *ChangesPayload `json:"changes,omitempty"`
|
||||||
|
@ -398,11 +360,6 @@ type IssuePayload struct {
|
||||||
Sender *User `json:"sender"`
|
Sender *User `json:"sender"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetSecret modifies the secret of the IssuePayload.
|
|
||||||
func (p *IssuePayload) SetSecret(secret string) {
|
|
||||||
p.Secret = secret
|
|
||||||
}
|
|
||||||
|
|
||||||
// JSONPayload encodes the IssuePayload to JSON, with an indentation of two spaces.
|
// JSONPayload encodes the IssuePayload to JSON, with an indentation of two spaces.
|
||||||
func (p *IssuePayload) JSONPayload() ([]byte, error) {
|
func (p *IssuePayload) JSONPayload() ([]byte, error) {
|
||||||
json := jsoniter.ConfigCompatibleWithStandardLibrary
|
json := jsoniter.ConfigCompatibleWithStandardLibrary
|
||||||
|
@ -430,7 +387,6 @@ type ChangesPayload struct {
|
||||||
|
|
||||||
// PullRequestPayload represents a payload information of pull request event.
|
// PullRequestPayload represents a payload information of pull request event.
|
||||||
type PullRequestPayload struct {
|
type PullRequestPayload struct {
|
||||||
Secret string `json:"secret"`
|
|
||||||
Action HookIssueAction `json:"action"`
|
Action HookIssueAction `json:"action"`
|
||||||
Index int64 `json:"number"`
|
Index int64 `json:"number"`
|
||||||
Changes *ChangesPayload `json:"changes,omitempty"`
|
Changes *ChangesPayload `json:"changes,omitempty"`
|
||||||
|
@ -440,11 +396,6 @@ type PullRequestPayload struct {
|
||||||
Review *ReviewPayload `json:"review"`
|
Review *ReviewPayload `json:"review"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetSecret modifies the secret of the PullRequestPayload.
|
|
||||||
func (p *PullRequestPayload) SetSecret(secret string) {
|
|
||||||
p.Secret = secret
|
|
||||||
}
|
|
||||||
|
|
||||||
// JSONPayload FIXME
|
// JSONPayload FIXME
|
||||||
func (p *PullRequestPayload) JSONPayload() ([]byte, error) {
|
func (p *PullRequestPayload) JSONPayload() ([]byte, error) {
|
||||||
json := jsoniter.ConfigCompatibleWithStandardLibrary
|
json := jsoniter.ConfigCompatibleWithStandardLibrary
|
||||||
|
@ -476,18 +427,12 @@ const (
|
||||||
|
|
||||||
// RepositoryPayload payload for repository webhooks
|
// RepositoryPayload payload for repository webhooks
|
||||||
type RepositoryPayload struct {
|
type RepositoryPayload struct {
|
||||||
Secret string `json:"secret"`
|
|
||||||
Action HookRepoAction `json:"action"`
|
Action HookRepoAction `json:"action"`
|
||||||
Repository *Repository `json:"repository"`
|
Repository *Repository `json:"repository"`
|
||||||
Organization *User `json:"organization"`
|
Organization *User `json:"organization"`
|
||||||
Sender *User `json:"sender"`
|
Sender *User `json:"sender"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetSecret modifies the secret of the RepositoryPayload
|
|
||||||
func (p *RepositoryPayload) SetSecret(secret string) {
|
|
||||||
p.Secret = secret
|
|
||||||
}
|
|
||||||
|
|
||||||
// JSONPayload JSON representation of the payload
|
// JSONPayload JSON representation of the payload
|
||||||
func (p *RepositoryPayload) JSONPayload() ([]byte, error) {
|
func (p *RepositoryPayload) JSONPayload() ([]byte, error) {
|
||||||
json := jsoniter.ConfigCompatibleWithStandardLibrary
|
json := jsoniter.ConfigCompatibleWithStandardLibrary
|
||||||
|
|
|
@ -133,7 +133,7 @@ func addHook(ctx *context.APIContext, form *api.CreateHookOption, orgID, repoID
|
||||||
BranchFilter: form.BranchFilter,
|
BranchFilter: form.BranchFilter,
|
||||||
},
|
},
|
||||||
IsActive: form.Active,
|
IsActive: form.Active,
|
||||||
Type: models.HookTaskType(form.Type),
|
Type: models.HookType(form.Type),
|
||||||
}
|
}
|
||||||
if w.Type == models.SLACK {
|
if w.Type == models.SLACK {
|
||||||
channel, ok := form.Config["channel"]
|
channel, ok := form.Config["channel"]
|
||||||
|
|
|
@ -239,7 +239,7 @@ func GogsHooksNewPost(ctx *context.Context) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// newGogsWebhookPost response for creating gogs hook
|
// newGogsWebhookPost response for creating gogs hook
|
||||||
func newGogsWebhookPost(ctx *context.Context, form forms.NewGogshookForm, kind models.HookTaskType) {
|
func newGogsWebhookPost(ctx *context.Context, form forms.NewGogshookForm, kind models.HookType) {
|
||||||
ctx.Data["Title"] = ctx.Tr("repo.settings.add_webhook")
|
ctx.Data["Title"] = ctx.Tr("repo.settings.add_webhook")
|
||||||
ctx.Data["PageIsSettingsHooks"] = true
|
ctx.Data["PageIsSettingsHooks"] = true
|
||||||
ctx.Data["PageIsSettingsHooksNew"] = true
|
ctx.Data["PageIsSettingsHooksNew"] = true
|
||||||
|
|
|
@ -6,8 +6,13 @@ package webhook
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"crypto/hmac"
|
||||||
|
"crypto/sha1"
|
||||||
|
"crypto/sha256"
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
|
"encoding/hex"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
@ -26,27 +31,32 @@ import (
|
||||||
|
|
||||||
// Deliver deliver hook task
|
// Deliver deliver hook task
|
||||||
func Deliver(t *models.HookTask) error {
|
func Deliver(t *models.HookTask) error {
|
||||||
|
w, err := models.GetWebhookByID(t.HookID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
err := recover()
|
err := recover()
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// There was a panic whilst delivering a hook...
|
// There was a panic whilst delivering a hook...
|
||||||
log.Error("PANIC whilst trying to deliver webhook[%d] for repo[%d] to %s Panic: %v\nStacktrace: %s", t.ID, t.RepoID, t.URL, err, log.Stack(2))
|
log.Error("PANIC whilst trying to deliver webhook[%d] for repo[%d] to %s Panic: %v\nStacktrace: %s", t.ID, t.RepoID, w.URL, err, log.Stack(2))
|
||||||
}()
|
}()
|
||||||
|
|
||||||
t.IsDelivered = true
|
t.IsDelivered = true
|
||||||
|
|
||||||
var req *http.Request
|
var req *http.Request
|
||||||
var err error
|
|
||||||
|
|
||||||
switch t.HTTPMethod {
|
switch w.HTTPMethod {
|
||||||
case "":
|
case "":
|
||||||
log.Info("HTTP Method for webhook %d empty, setting to POST as default", t.ID)
|
log.Info("HTTP Method for webhook %d empty, setting to POST as default", t.ID)
|
||||||
fallthrough
|
fallthrough
|
||||||
case http.MethodPost:
|
case http.MethodPost:
|
||||||
switch t.ContentType {
|
switch w.ContentType {
|
||||||
case models.ContentTypeJSON:
|
case models.ContentTypeJSON:
|
||||||
req, err = http.NewRequest("POST", t.URL, strings.NewReader(t.PayloadContent))
|
req, err = http.NewRequest("POST", w.URL, strings.NewReader(t.PayloadContent))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -57,16 +67,15 @@ func Deliver(t *models.HookTask) error {
|
||||||
"payload": []string{t.PayloadContent},
|
"payload": []string{t.PayloadContent},
|
||||||
}
|
}
|
||||||
|
|
||||||
req, err = http.NewRequest("POST", t.URL, strings.NewReader(forms.Encode()))
|
req, err = http.NewRequest("POST", w.URL, strings.NewReader(forms.Encode()))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||||
}
|
}
|
||||||
case http.MethodGet:
|
case http.MethodGet:
|
||||||
u, err := url.Parse(t.URL)
|
u, err := url.Parse(w.URL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -78,31 +87,48 @@ func Deliver(t *models.HookTask) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
case http.MethodPut:
|
case http.MethodPut:
|
||||||
switch t.Typ {
|
switch w.Type {
|
||||||
case models.MATRIX:
|
case models.MATRIX:
|
||||||
req, err = getMatrixHookRequest(t)
|
req, err = getMatrixHookRequest(w, t)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("Invalid http method for webhook: [%d] %v", t.ID, t.HTTPMethod)
|
return fmt.Errorf("Invalid http method for webhook: [%d] %v", t.ID, w.HTTPMethod)
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("Invalid http method for webhook: [%d] %v", t.ID, t.HTTPMethod)
|
return fmt.Errorf("Invalid http method for webhook: [%d] %v", t.ID, w.HTTPMethod)
|
||||||
|
}
|
||||||
|
|
||||||
|
var signatureSHA1 string
|
||||||
|
var signatureSHA256 string
|
||||||
|
if len(w.Secret) > 0 {
|
||||||
|
sig1 := hmac.New(sha1.New, []byte(w.Secret))
|
||||||
|
sig256 := hmac.New(sha256.New, []byte(w.Secret))
|
||||||
|
_, err = io.MultiWriter(sig1, sig256).Write([]byte(t.PayloadContent))
|
||||||
|
if err != nil {
|
||||||
|
log.Error("prepareWebhooks.sigWrite: %v", err)
|
||||||
|
}
|
||||||
|
signatureSHA1 = hex.EncodeToString(sig1.Sum(nil))
|
||||||
|
signatureSHA256 = hex.EncodeToString(sig256.Sum(nil))
|
||||||
}
|
}
|
||||||
|
|
||||||
req.Header.Add("X-Gitea-Delivery", t.UUID)
|
req.Header.Add("X-Gitea-Delivery", t.UUID)
|
||||||
req.Header.Add("X-Gitea-Event", t.EventType.Event())
|
req.Header.Add("X-Gitea-Event", t.EventType.Event())
|
||||||
req.Header.Add("X-Gitea-Signature", t.Signature)
|
req.Header.Add("X-Gitea-Signature", signatureSHA256)
|
||||||
req.Header.Add("X-Gogs-Delivery", t.UUID)
|
req.Header.Add("X-Gogs-Delivery", t.UUID)
|
||||||
req.Header.Add("X-Gogs-Event", t.EventType.Event())
|
req.Header.Add("X-Gogs-Event", t.EventType.Event())
|
||||||
req.Header.Add("X-Gogs-Signature", t.Signature)
|
req.Header.Add("X-Gogs-Signature", signatureSHA256)
|
||||||
|
req.Header.Add("X-Hub-Signature", "sha1="+signatureSHA1)
|
||||||
|
req.Header.Add("X-Hub-Signature-256", "sha256="+signatureSHA256)
|
||||||
req.Header["X-GitHub-Delivery"] = []string{t.UUID}
|
req.Header["X-GitHub-Delivery"] = []string{t.UUID}
|
||||||
req.Header["X-GitHub-Event"] = []string{t.EventType.Event()}
|
req.Header["X-GitHub-Event"] = []string{t.EventType.Event()}
|
||||||
|
|
||||||
// Record delivery information.
|
// Record delivery information.
|
||||||
t.RequestInfo = &models.HookRequest{
|
t.RequestInfo = &models.HookRequest{
|
||||||
Headers: map[string]string{},
|
URL: req.URL.String(),
|
||||||
|
HTTPMethod: req.Method,
|
||||||
|
Headers: map[string]string{},
|
||||||
}
|
}
|
||||||
for k, vals := range req.Header {
|
for k, vals := range req.Header {
|
||||||
t.RequestInfo.Headers[k] = strings.Join(vals, ",")
|
t.RequestInfo.Headers[k] = strings.Join(vals, ",")
|
||||||
|
@ -125,11 +151,6 @@ func Deliver(t *models.HookTask) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update webhook last delivery status.
|
// Update webhook last delivery status.
|
||||||
w, err := models.GetWebhookByID(t.HookID)
|
|
||||||
if err != nil {
|
|
||||||
log.Error("GetWebhookByID: %v", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if t.IsSucceed {
|
if t.IsSucceed {
|
||||||
w.LastStatus = models.HookStatusSucceed
|
w.LastStatus = models.HookStatusSucceed
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -25,9 +25,6 @@ var (
|
||||||
_ PayloadConvertor = &DingtalkPayload{}
|
_ PayloadConvertor = &DingtalkPayload{}
|
||||||
)
|
)
|
||||||
|
|
||||||
// SetSecret sets the dingtalk secret
|
|
||||||
func (d *DingtalkPayload) SetSecret(_ string) {}
|
|
||||||
|
|
||||||
// JSONPayload Marshals the DingtalkPayload to json
|
// JSONPayload Marshals the DingtalkPayload to json
|
||||||
func (d *DingtalkPayload) JSONPayload() ([]byte, error) {
|
func (d *DingtalkPayload) JSONPayload() ([]byte, error) {
|
||||||
json := jsoniter.ConfigCompatibleWithStandardLibrary
|
json := jsoniter.ConfigCompatibleWithStandardLibrary
|
||||||
|
|
|
@ -97,9 +97,6 @@ var (
|
||||||
redColor = color("ff3232")
|
redColor = color("ff3232")
|
||||||
)
|
)
|
||||||
|
|
||||||
// SetSecret sets the discord secret
|
|
||||||
func (d *DiscordPayload) SetSecret(_ string) {}
|
|
||||||
|
|
||||||
// JSONPayload Marshals the DiscordPayload to json
|
// JSONPayload Marshals the DiscordPayload to json
|
||||||
func (d *DiscordPayload) JSONPayload() ([]byte, error) {
|
func (d *DiscordPayload) JSONPayload() ([]byte, error) {
|
||||||
json := jsoniter.ConfigCompatibleWithStandardLibrary
|
json := jsoniter.ConfigCompatibleWithStandardLibrary
|
||||||
|
|
|
@ -35,9 +35,6 @@ func newFeishuTextPayload(text string) *FeishuPayload {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetSecret sets the Feishu secret
|
|
||||||
func (f *FeishuPayload) SetSecret(_ string) {}
|
|
||||||
|
|
||||||
// JSONPayload Marshals the FeishuPayload to json
|
// JSONPayload Marshals the FeishuPayload to json
|
||||||
func (f *FeishuPayload) JSONPayload() ([]byte, error) {
|
func (f *FeishuPayload) JSONPayload() ([]byte, error) {
|
||||||
json := jsoniter.ConfigCompatibleWithStandardLibrary
|
json := jsoniter.ConfigCompatibleWithStandardLibrary
|
||||||
|
|
|
@ -76,9 +76,6 @@ type MatrixPayloadSafe struct {
|
||||||
Commits []*api.PayloadCommit `json:"io.gitea.commits,omitempty"`
|
Commits []*api.PayloadCommit `json:"io.gitea.commits,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetSecret sets the Matrix secret
|
|
||||||
func (m *MatrixPayloadUnsafe) SetSecret(_ string) {}
|
|
||||||
|
|
||||||
// JSONPayload Marshals the MatrixPayloadUnsafe to json
|
// JSONPayload Marshals the MatrixPayloadUnsafe to json
|
||||||
func (m *MatrixPayloadUnsafe) JSONPayload() ([]byte, error) {
|
func (m *MatrixPayloadUnsafe) JSONPayload() ([]byte, error) {
|
||||||
json := jsoniter.ConfigCompatibleWithStandardLibrary
|
json := jsoniter.ConfigCompatibleWithStandardLibrary
|
||||||
|
@ -263,7 +260,7 @@ func getMessageBody(htmlText string) string {
|
||||||
|
|
||||||
// getMatrixHookRequest creates a new request which contains an Authorization header.
|
// getMatrixHookRequest creates a new request which contains an Authorization header.
|
||||||
// The access_token is removed from t.PayloadContent
|
// The access_token is removed from t.PayloadContent
|
||||||
func getMatrixHookRequest(t *models.HookTask) (*http.Request, error) {
|
func getMatrixHookRequest(w *models.Webhook, t *models.HookTask) (*http.Request, error) {
|
||||||
payloadunsafe := MatrixPayloadUnsafe{}
|
payloadunsafe := MatrixPayloadUnsafe{}
|
||||||
json := jsoniter.ConfigCompatibleWithStandardLibrary
|
json := jsoniter.ConfigCompatibleWithStandardLibrary
|
||||||
if err := json.Unmarshal([]byte(t.PayloadContent), &payloadunsafe); err != nil {
|
if err := json.Unmarshal([]byte(t.PayloadContent), &payloadunsafe); err != nil {
|
||||||
|
@ -288,9 +285,9 @@ func getMatrixHookRequest(t *models.HookTask) (*http.Request, error) {
|
||||||
return nil, fmt.Errorf("getMatrixHookRequest: unable to hash payload: %+v", err)
|
return nil, fmt.Errorf("getMatrixHookRequest: unable to hash payload: %+v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
t.URL = fmt.Sprintf("%s/%s", t.URL, txnID)
|
url := fmt.Sprintf("%s/%s", w.URL, txnID)
|
||||||
|
|
||||||
req, err := http.NewRequest(t.HTTPMethod, t.URL, strings.NewReader(string(payload)))
|
req, err := http.NewRequest(w.HTTPMethod, url, strings.NewReader(string(payload)))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -184,6 +184,8 @@ func TestMatrixJSONPayload(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMatrixHookRequest(t *testing.T) {
|
func TestMatrixHookRequest(t *testing.T) {
|
||||||
|
w := &models.Webhook{}
|
||||||
|
|
||||||
h := &models.HookTask{
|
h := &models.HookTask{
|
||||||
PayloadContent: `{
|
PayloadContent: `{
|
||||||
"body": "[[user1/test](http://localhost:3000/user1/test)] user1 pushed 1 commit to [master](http://localhost:3000/user1/test/src/branch/master):\n[5175ef2](http://localhost:3000/user1/test/commit/5175ef26201c58b035a3404b3fe02b4e8d436eee): Merge pull request 'Change readme.md' (#2) from add-matrix-webhook into master\n\nReviewed-on: http://localhost:3000/user1/test/pulls/2\n - user1",
|
"body": "[[user1/test](http://localhost:3000/user1/test)] user1 pushed 1 commit to [master](http://localhost:3000/user1/test/src/branch/master):\n[5175ef2](http://localhost:3000/user1/test/commit/5175ef26201c58b035a3404b3fe02b4e8d436eee): Merge pull request 'Change readme.md' (#2) from add-matrix-webhook into master\n\nReviewed-on: http://localhost:3000/user1/test/pulls/2\n - user1",
|
||||||
|
@ -245,7 +247,7 @@ func TestMatrixHookRequest(t *testing.T) {
|
||||||
]
|
]
|
||||||
}`
|
}`
|
||||||
|
|
||||||
req, err := getMatrixHookRequest(h)
|
req, err := getMatrixHookRequest(w, h)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.NotNil(t, req)
|
require.NotNil(t, req)
|
||||||
|
|
||||||
|
|
|
@ -55,9 +55,6 @@ type (
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
// SetSecret sets the MSTeams secret
|
|
||||||
func (m *MSTeamsPayload) SetSecret(_ string) {}
|
|
||||||
|
|
||||||
// JSONPayload Marshals the MSTeamsPayload to json
|
// JSONPayload Marshals the MSTeamsPayload to json
|
||||||
func (m *MSTeamsPayload) JSONPayload() ([]byte, error) {
|
func (m *MSTeamsPayload) JSONPayload() ([]byte, error) {
|
||||||
json := jsoniter.ConfigCompatibleWithStandardLibrary
|
json := jsoniter.ConfigCompatibleWithStandardLibrary
|
||||||
|
|
|
@ -56,9 +56,6 @@ type SlackAttachment struct {
|
||||||
Text string `json:"text"`
|
Text string `json:"text"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetSecret sets the slack secret
|
|
||||||
func (s *SlackPayload) SetSecret(_ string) {}
|
|
||||||
|
|
||||||
// JSONPayload Marshals the SlackPayload to json
|
// JSONPayload Marshals the SlackPayload to json
|
||||||
func (s *SlackPayload) JSONPayload() ([]byte, error) {
|
func (s *SlackPayload) JSONPayload() ([]byte, error) {
|
||||||
json := jsoniter.ConfigCompatibleWithStandardLibrary
|
json := jsoniter.ConfigCompatibleWithStandardLibrary
|
||||||
|
|
|
@ -45,9 +45,6 @@ var (
|
||||||
_ PayloadConvertor = &TelegramPayload{}
|
_ PayloadConvertor = &TelegramPayload{}
|
||||||
)
|
)
|
||||||
|
|
||||||
// SetSecret sets the telegram secret
|
|
||||||
func (t *TelegramPayload) SetSecret(_ string) {}
|
|
||||||
|
|
||||||
// JSONPayload Marshals the TelegramPayload to json
|
// JSONPayload Marshals the TelegramPayload to json
|
||||||
func (t *TelegramPayload) JSONPayload() ([]byte, error) {
|
func (t *TelegramPayload) JSONPayload() ([]byte, error) {
|
||||||
t.ParseMode = "HTML"
|
t.ParseMode = "HTML"
|
||||||
|
|
|
@ -5,9 +5,6 @@
|
||||||
package webhook
|
package webhook
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/hmac"
|
|
||||||
"crypto/sha256"
|
|
||||||
"encoding/hex"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
@ -21,12 +18,12 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type webhook struct {
|
type webhook struct {
|
||||||
name models.HookTaskType
|
name models.HookType
|
||||||
payloadCreator func(p api.Payloader, event models.HookEventType, meta string) (api.Payloader, error)
|
payloadCreator func(p api.Payloader, event models.HookEventType, meta string) (api.Payloader, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
webhooks = map[models.HookTaskType]*webhook{
|
webhooks = map[models.HookType]*webhook{
|
||||||
models.SLACK: {
|
models.SLACK: {
|
||||||
name: models.SLACK,
|
name: models.SLACK,
|
||||||
payloadCreator: GetSlackPayload,
|
payloadCreator: GetSlackPayload,
|
||||||
|
@ -60,7 +57,7 @@ var (
|
||||||
|
|
||||||
// RegisterWebhook registers a webhook
|
// RegisterWebhook registers a webhook
|
||||||
func RegisterWebhook(name string, webhook *webhook) {
|
func RegisterWebhook(name string, webhook *webhook) {
|
||||||
webhooks[models.HookTaskType(name)] = webhook
|
webhooks[models.HookType(name)] = webhook
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsValidHookTaskType returns true if a webhook registered
|
// IsValidHookTaskType returns true if a webhook registered
|
||||||
|
@ -68,7 +65,7 @@ func IsValidHookTaskType(name string) bool {
|
||||||
if name == models.GITEA || name == models.GOGS {
|
if name == models.GITEA || name == models.GOGS {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
_, ok := webhooks[models.HookTaskType(name)]
|
_, ok := webhooks[models.HookType(name)]
|
||||||
return ok
|
return ok
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -161,35 +158,14 @@ func prepareWebhook(w *models.Webhook, repo *models.Repository, event models.Hoo
|
||||||
return fmt.Errorf("create payload for %s[%s]: %v", w.Type, event, err)
|
return fmt.Errorf("create payload for %s[%s]: %v", w.Type, event, err)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
p.SetSecret(w.Secret)
|
|
||||||
payloader = p
|
payloader = p
|
||||||
}
|
}
|
||||||
|
|
||||||
var signature string
|
|
||||||
if len(w.Secret) > 0 {
|
|
||||||
data, err := payloader.JSONPayload()
|
|
||||||
if err != nil {
|
|
||||||
log.Error("prepareWebhooks.JSONPayload: %v", err)
|
|
||||||
}
|
|
||||||
sig := hmac.New(sha256.New, []byte(w.Secret))
|
|
||||||
_, err = sig.Write(data)
|
|
||||||
if err != nil {
|
|
||||||
log.Error("prepareWebhooks.sigWrite: %v", err)
|
|
||||||
}
|
|
||||||
signature = hex.EncodeToString(sig.Sum(nil))
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = models.CreateHookTask(&models.HookTask{
|
if err = models.CreateHookTask(&models.HookTask{
|
||||||
RepoID: repo.ID,
|
RepoID: repo.ID,
|
||||||
HookID: w.ID,
|
HookID: w.ID,
|
||||||
Typ: w.Type,
|
Payloader: payloader,
|
||||||
URL: w.URL,
|
EventType: event,
|
||||||
Signature: signature,
|
|
||||||
Payloader: payloader,
|
|
||||||
HTTPMethod: w.HTTPMethod,
|
|
||||||
ContentType: w.ContentType,
|
|
||||||
EventType: event,
|
|
||||||
IsSSL: w.IsSSL,
|
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return fmt.Errorf("CreateHookTask: %v", err)
|
return fmt.Errorf("CreateHookTask: %v", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,8 +44,8 @@
|
||||||
<div class="ui bottom attached tab segment active" data-tab="request-{{.ID}}">
|
<div class="ui bottom attached tab segment active" data-tab="request-{{.ID}}">
|
||||||
{{if .RequestInfo}}
|
{{if .RequestInfo}}
|
||||||
<h5>{{$.i18n.Tr "repo.settings.webhook.headers"}}</h5>
|
<h5>{{$.i18n.Tr "repo.settings.webhook.headers"}}</h5>
|
||||||
<pre class="webhook-info"><strong>Request URL:</strong> {{.URL}}
|
<pre class="webhook-info"><strong>Request URL:</strong> {{.RequestInfo.URL}}
|
||||||
<strong>Request method:</strong> {{if .HTTPMethod}}{{.HTTPMethod}}{{else}}POST{{end}}
|
<strong>Request method:</strong> {{if .RequestInfo.HTTPMethod}}{{.RequestInfo.HTTPMethod}}{{else}}POST{{end}}
|
||||||
{{ range $key, $val := .RequestInfo.Headers }}<strong>{{$key}}:</strong> {{$val}}
|
{{ range $key, $val := .RequestInfo.Headers }}<strong>{{$key}}:</strong> {{$val}}
|
||||||
{{end}}</pre>
|
{{end}}</pre>
|
||||||
<h5>{{$.i18n.Tr "repo.settings.webhook.payload"}}</h5>
|
<h5>{{$.i18n.Tr "repo.settings.webhook.payload"}}</h5>
|
||||||
|
|
Loading…
Reference in a new issue