mirror of
				https://github.com/go-gitea/gitea.git
				synced 2025-10-29 10:57:44 +09:00 
			
		
		
		
	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:
		| @@ -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,15 +142,13 @@ 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            HookTaskType `xorm:"VARCHAR(16) 'type'"` | 	Type            HookType   `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 | ||||||
|  |  | ||||||
| @@ -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,6 +633,8 @@ func (h HookEventType) Event() string { | |||||||
|  |  | ||||||
| // HookRequest represents hook task request information. | // HookRequest represents hook task request information. | ||||||
| type HookRequest struct { | type HookRequest struct { | ||||||
|  | 	URL        string            `json:"url"` | ||||||
|  | 	HTTPMethod string            `json:"http_method"` | ||||||
| 	Headers    map[string]string `json:"headers"` | 	Headers    map[string]string `json:"headers"` | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -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,30 +87,47 @@ 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{ | ||||||
|  | 		URL:        req.URL.String(), | ||||||
|  | 		HTTPMethod: req.Method, | ||||||
| 		Headers:    map[string]string{}, | 		Headers:    map[string]string{}, | ||||||
| 	} | 	} | ||||||
| 	for k, vals := range req.Header { | 	for k, vals := range req.Header { | ||||||
| @@ -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, |  | ||||||
| 		URL:         w.URL, |  | ||||||
| 		Signature:   signature, |  | ||||||
| 		Payloader: payloader, | 		Payloader: payloader, | ||||||
| 		HTTPMethod:  w.HTTPMethod, |  | ||||||
| 		ContentType: w.ContentType, |  | ||||||
| 		EventType: event, | 		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> | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user