Browse Source

webhook: send secret with SHA256 HMAC hex digest (#3692)

pull/3853/merge
Unknwon 8 years ago
parent
commit
6ec859f2b0
No known key found for this signature in database
GPG Key ID: 25B575AE3213B2B3
  1. 1
      conf/locale/locale_en-US.ini
  2. 18
      models/webhook.go
  3. 2
      models/webhook_discord.go
  4. 2
      models/webhook_slack.go
  5. 6
      modules/bindata/bindata.go
  6. 3
      public/css/gogs.css
  7. 3
      public/less/_repository.less
  8. 1
      templates/repo/settings/webhook_gogs.tmpl
  9. 2
      vendor/github.com/gogits/go-gogs-client/gogs.go
  10. 16
      vendor/github.com/gogits/go-gogs-client/repo_hook.go
  11. 6
      vendor/vendor.json

1
conf/locale/locale_en-US.ini

@ -745,6 +745,7 @@ settings.add_webhook_desc = Gogs will send a <code>POST</code> request to the UR
settings.payload_url = Payload URL settings.payload_url = Payload URL
settings.content_type = Content Type settings.content_type = Content Type
settings.secret = Secret settings.secret = Secret
settings.secret_desc = Secret will be sent as SHA256 HMAC hex digest of payload via <code>X-Gogs-Signature</code> header.
settings.slack_username = Username settings.slack_username = Username
settings.slack_icon_url = Icon URL settings.slack_icon_url = Icon URL
settings.slack_color = Color settings.slack_color = Color

18
models/webhook.go

@ -5,7 +5,10 @@
package models package models
import ( import (
"crypto/hmac"
"crypto/sha256"
"crypto/tls" "crypto/tls"
"encoding/hex"
"encoding/json" "encoding/json"
"fmt" "fmt"
"io/ioutil" "io/ioutil"
@ -358,6 +361,7 @@ type HookTask struct {
UUID string UUID string
Type HookTaskType Type HookTaskType
URL string `xorm:"TEXT"` URL string `xorm:"TEXT"`
Signature string `xorm:"TEXT"`
api.Payloader `xorm:"-"` api.Payloader `xorm:"-"`
PayloadContent string `xorm:"TEXT"` PayloadContent string `xorm:"TEXT"`
ContentType HookContentType ContentType HookContentType
@ -481,15 +485,26 @@ func prepareWebhooks(repo *Repository, event HookEventType, p api.Payloader, web
return fmt.Errorf("GetDiscordPayload: %v", err) return fmt.Errorf("GetDiscordPayload: %v", err)
} }
default: default:
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(2, "prepareWebhooks.JSONPayload: %v", err)
}
sig := hmac.New(sha256.New, []byte(w.Secret))
sig.Write(data)
signature = hex.EncodeToString(sig.Sum(nil))
}
if err = CreateHookTask(&HookTask{ if err = CreateHookTask(&HookTask{
RepoID: repo.ID, RepoID: repo.ID,
HookID: w.ID, HookID: w.ID,
Type: w.HookTaskType, Type: w.HookTaskType,
URL: w.URL, URL: w.URL,
Signature: signature,
Payloader: payloader, Payloader: payloader,
ContentType: w.ContentType, ContentType: w.ContentType,
EventType: event, EventType: event,
@ -535,6 +550,7 @@ func (t *HookTask) deliver() {
timeout := time.Duration(setting.Webhook.DeliverTimeout) * time.Second timeout := time.Duration(setting.Webhook.DeliverTimeout) * time.Second
req := httplib.Post(t.URL).SetTimeout(timeout, timeout). req := httplib.Post(t.URL).SetTimeout(timeout, timeout).
Header("X-Gogs-Delivery", t.UUID). Header("X-Gogs-Delivery", t.UUID).
Header("X-Gogs-Signature", t.Signature).
Header("X-Gogs-Event", string(t.EventType)). Header("X-Gogs-Event", string(t.EventType)).
SetTLSClientConfig(&tls.Config{InsecureSkipVerify: setting.Webhook.SkipTLSVerify}) SetTLSClientConfig(&tls.Config{InsecureSkipVerify: setting.Webhook.SkipTLSVerify})

2
models/webhook_discord.go

@ -48,8 +48,6 @@ type DiscordPayload struct {
Embeds []*DiscordEmbedObject `json:"embeds"` Embeds []*DiscordEmbedObject `json:"embeds"`
} }
func (p *DiscordPayload) SetSecret(_ string) {}
func (p *DiscordPayload) JSONPayload() ([]byte, error) { func (p *DiscordPayload) JSONPayload() ([]byte, error) {
data, err := json.MarshalIndent(p, "", " ") data, err := json.MarshalIndent(p, "", " ")
if err != nil { if err != nil {

2
models/webhook_slack.go

@ -39,8 +39,6 @@ type SlackPayload struct {
Attachments []*SlackAttachment `json:"attachments"` Attachments []*SlackAttachment `json:"attachments"`
} }
func (p *SlackPayload) SetSecret(_ string) {}
func (p *SlackPayload) JSONPayload() ([]byte, error) { func (p *SlackPayload) JSONPayload() ([]byte, error) {
data, err := json.MarshalIndent(p, "", " ") data, err := json.MarshalIndent(p, "", " ")
if err != nil { if err != nil {

6
modules/bindata/bindata.go

File diff suppressed because one or more lines are too long

3
public/css/gogs.css

@ -2319,6 +2319,9 @@ footer .ui.language .menu {
.repository.settings.webhooks .types .menu .item { .repository.settings.webhooks .types .menu .item {
padding: 10px !important; padding: 10px !important;
} }
.repository.settings.webhook .text.desc {
margin-top: 5px;
}
.repository.settings.webhook .events .column { .repository.settings.webhook .events .column {
padding-bottom: 0; padding-bottom: 0;
} }

3
public/less/_repository.less

@ -1349,6 +1349,9 @@
} }
&.webhook { &.webhook {
.text.desc {
margin-top: 5px;
}
.events { .events {
.column { .column {
padding-bottom: 0; padding-bottom: 0;

1
templates/repo/settings/webhook_gogs.tmpl

@ -22,6 +22,7 @@
<div class="field {{if .Err_Secret}}error{{end}}"> <div class="field {{if .Err_Secret}}error{{end}}">
<label for="secret">{{.i18n.Tr "repo.settings.secret"}}</label> <label for="secret">{{.i18n.Tr "repo.settings.secret"}}</label>
<input id="secret" name="secret" type="password" value="{{.Webhook.Secret}}" autocomplete="off"> <input id="secret" name="secret" type="password" value="{{.Webhook.Secret}}" autocomplete="off">
<p class="text grey desc">{{.i18n.Tr "repo.settings.secret_desc" | Safe}}</p>
</div> </div>
{{template "repo/settings/webhook_settings" .}} {{template "repo/settings/webhook_settings" .}}
</form> </form>

2
vendor/github.com/gogits/go-gogs-client/gogs.go generated vendored

@ -14,7 +14,7 @@ import (
) )
func Version() string { func Version() string {
return "0.12.5" return "0.12.6"
} }
// Client represents a Gogs API client. // Client represents a Gogs API client.

16
vendor/github.com/gogits/go-gogs-client/repo_hook.go generated vendored

@ -70,7 +70,6 @@ func (c *Client) DeleteRepoHook(user, repo string, id int64) error {
} }
type Payloader interface { type Payloader interface {
SetSecret(string)
JSONPayload() ([]byte, error) JSONPayload() ([]byte, error)
} }
@ -104,17 +103,12 @@ var (
// \/ \/ \/ \/ // \/ \/ \/ \/
type CreatePayload struct { type CreatePayload struct {
Secret string `json:"secret"`
Ref string `json:"ref"` Ref string `json:"ref"`
RefType string `json:"ref_type"` RefType string `json:"ref_type"`
Repo *Repository `json:"repository"` Repo *Repository `json:"repository"`
Sender *User `json:"sender"` Sender *User `json:"sender"`
} }
func (p *CreatePayload) SetSecret(secret string) {
p.Secret = secret
}
func (p *CreatePayload) JSONPayload() ([]byte, error) { func (p *CreatePayload) JSONPayload() ([]byte, error) {
return json.MarshalIndent(p, "", " ") return json.MarshalIndent(p, "", " ")
} }
@ -148,7 +142,6 @@ func ParseCreateHook(raw []byte) (*CreatePayload, 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"`
@ -159,10 +152,6 @@ type PushPayload struct {
Sender *User `json:"sender"` Sender *User `json:"sender"`
} }
func (p *PushPayload) SetSecret(secret string) {
p.Secret = secret
}
func (p *PushPayload) JSONPayload() ([]byte, error) { func (p *PushPayload) JSONPayload() ([]byte, error) {
return json.MarshalIndent(p, "", " ") return json.MarshalIndent(p, "", " ")
} }
@ -227,7 +216,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"`
@ -236,10 +224,6 @@ type PullRequestPayload struct {
Sender *User `json:"sender"` Sender *User `json:"sender"`
} }
func (p *PullRequestPayload) SetSecret(secret string) {
p.Secret = secret
}
func (p *PullRequestPayload) JSONPayload() ([]byte, error) { func (p *PullRequestPayload) JSONPayload() ([]byte, error) {
return json.MarshalIndent(p, "", " ") return json.MarshalIndent(p, "", " ")
} }

6
vendor/vendor.json vendored

@ -165,10 +165,10 @@
"revisionTime": "2017-02-19T18:16:29Z" "revisionTime": "2017-02-19T18:16:29Z"
}, },
{ {
"checksumSHA1": "xvG+RgJODQqlmdAkHUQK2TyLR88=", "checksumSHA1": "exKX51W/Hieq7OOmYK2gYn+Huuw=",
"path": "github.com/gogits/go-gogs-client", "path": "github.com/gogits/go-gogs-client",
"revision": "89ff140a38c057e71a1012af6d666fbc037ba606", "revision": "f12fbacb5495120dc62dae7cfdf140d39bf6f715",
"revisionTime": "2017-02-14T02:02:40Z" "revisionTime": "2017-02-24T06:16:35Z"
}, },
{ {
"checksumSHA1": "p4yoFWgDiTfpu1JYgh26t6+VDTk=", "checksumSHA1": "p4yoFWgDiTfpu1JYgh26t6+VDTk=",

Loading…
Cancel
Save