mirror of
https://github.com/woodpecker-ci/woodpecker.git
synced 2025-02-17 03:45:13 +00:00
hooks are protected with signed sha
This commit is contained in:
parent
64cc684295
commit
6fcae7d80a
9 changed files with 59 additions and 21 deletions
|
@ -1,8 +1,10 @@
|
|||
package common
|
||||
|
||||
const (
|
||||
TokenUser = "u"
|
||||
TokenSess = "s"
|
||||
TokenUser = "u"
|
||||
TokenSess = "s"
|
||||
TokenHook = "h"
|
||||
TokenAgent = "a"
|
||||
)
|
||||
|
||||
type Token struct {
|
||||
|
|
|
@ -64,6 +64,12 @@ func push(t *bolt.Tx, bucket, index, value []byte) error {
|
|||
if err != nil && err != ErrKeyNotFound {
|
||||
return err
|
||||
}
|
||||
// we shouldn't add a key that already exists
|
||||
for _, key := range keys {
|
||||
if bytes.Equal(key, value) {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
keys = append(keys, value)
|
||||
return update(t, bucket, index, &keys)
|
||||
}
|
||||
|
|
2
drone.go
2
drone.go
|
@ -42,12 +42,12 @@ func main() {
|
|||
api.Use(server.SetRemote(remote))
|
||||
api.Use(server.SetQueue(queue.New()))
|
||||
api.Use(server.SetSettings(settings))
|
||||
api.Use(server.SetSession(session))
|
||||
api.Use(server.SetUser(session))
|
||||
|
||||
user := api.Group("/user")
|
||||
{
|
||||
user.Use(server.MustUser())
|
||||
user.Use(server.SetSession(session))
|
||||
|
||||
user.GET("", server.GetUserCurr)
|
||||
user.PATCH("", server.PutUserCurr)
|
||||
|
|
|
@ -172,7 +172,7 @@ func GetHook(client *github.Client, owner, name, url string) (*github.Hook, erro
|
|||
return nil, err
|
||||
}
|
||||
for _, hook := range hooks {
|
||||
if hook.Config["url"] == url {
|
||||
if strings.HasPrefix(hook.Config["url"].(string), url) {
|
||||
return &hook, nil
|
||||
}
|
||||
}
|
||||
|
@ -255,6 +255,9 @@ func DeleteKey(client *github.Client, owner, name, title string) error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if k == nil {
|
||||
return nil
|
||||
}
|
||||
_, err = client.Repositories.DeleteKey(owner, name, *k.ID)
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@ func PostHook(c *gin.Context) {
|
|||
remote := ToRemote(c)
|
||||
store := ToDatastore(c)
|
||||
queue_ := ToQueue(c)
|
||||
sess := ToSession(c)
|
||||
|
||||
hook, err := remote.Hook(c.Request)
|
||||
if err != nil {
|
||||
|
@ -38,6 +39,14 @@ func PostHook(c *gin.Context) {
|
|||
return
|
||||
}
|
||||
|
||||
// get the token and verify the hook is authorized
|
||||
token := sess.GetLogin(c.Request)
|
||||
if token == nil || token.Label != hook.Repo.FullName {
|
||||
log.Errorf("invalid token sent with hook.")
|
||||
c.AbortWithStatus(403)
|
||||
return
|
||||
}
|
||||
|
||||
// a build may be skipped if the text [CI SKIP]
|
||||
// is found inside the commit message
|
||||
if hook.Commit != nil && strings.Contains(hook.Commit.Message, "[CI SKIP]") {
|
||||
|
|
|
@ -166,15 +166,11 @@ func DeleteRepo(c *gin.Context) {
|
|||
//
|
||||
func PostRepo(c *gin.Context) {
|
||||
user := ToUser(c)
|
||||
sess := ToSession(c)
|
||||
store := ToDatastore(c)
|
||||
owner := c.Params.ByName("owner")
|
||||
name := c.Params.ByName("name")
|
||||
|
||||
link := fmt.Sprintf(
|
||||
"%s/api/hook",
|
||||
httputil.GetURL(c.Request),
|
||||
)
|
||||
|
||||
// TODO(bradrydzewski) verify repo not exists
|
||||
|
||||
// get the repository and user permissions
|
||||
|
@ -194,6 +190,21 @@ func PostRepo(c *gin.Context) {
|
|||
return
|
||||
}
|
||||
|
||||
token := &common.Token{}
|
||||
token.Kind = common.TokenHook
|
||||
token.Label = r.FullName
|
||||
tokenstr, err := sess.GenerateToken(token)
|
||||
if err != nil {
|
||||
c.Fail(500, err)
|
||||
return
|
||||
}
|
||||
|
||||
link := fmt.Sprintf(
|
||||
"%s/api/hook?access_token=%s",
|
||||
httputil.GetURL(c.Request),
|
||||
tokenstr,
|
||||
)
|
||||
|
||||
// set the repository owner to the
|
||||
// currently authenticated user.
|
||||
r.User = &common.Owner{Login: user.Login}
|
||||
|
|
|
@ -125,7 +125,7 @@ func SetUser(s session.Session) gin.HandlerFunc {
|
|||
return func(c *gin.Context) {
|
||||
ds := ToDatastore(c)
|
||||
token := s.GetLogin(c.Request)
|
||||
if token == nil {
|
||||
if token == nil || len(token.Login) == 0 {
|
||||
c.Next()
|
||||
return
|
||||
}
|
||||
|
@ -137,7 +137,8 @@ func SetUser(s session.Session) gin.HandlerFunc {
|
|||
|
||||
// if session token we can proceed, otherwise
|
||||
// we should validate the token hasn't been revoked
|
||||
if token.Kind == common.TokenSess {
|
||||
switch token.Kind {
|
||||
case common.TokenSess:
|
||||
c.Next()
|
||||
return
|
||||
}
|
||||
|
|
|
@ -8,7 +8,6 @@ import (
|
|||
"github.com/dgrijalva/jwt-go"
|
||||
"github.com/drone/drone/common"
|
||||
"github.com/drone/drone/settings"
|
||||
"github.com/gorilla/securecookie"
|
||||
)
|
||||
|
||||
type Session interface {
|
||||
|
@ -22,12 +21,8 @@ type session struct {
|
|||
}
|
||||
|
||||
func New(s *settings.Session) Session {
|
||||
// TODO (bradrydzewski) hook up the Session.Expires
|
||||
secret := []byte(s.Secret)
|
||||
expire := time.Hour * 72
|
||||
if len(secret) == 0 {
|
||||
securecookie.GenerateRandomKey(32)
|
||||
}
|
||||
return &session{
|
||||
secret: secret,
|
||||
expire: expire,
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
package settings
|
||||
|
||||
import (
|
||||
"github.com/BurntSushi/toml"
|
||||
)
|
||||
import "github.com/BurntSushi/toml"
|
||||
|
||||
// Service represents the configuration details required
|
||||
// to connect to the revision control system (ie GitHub, Bitbucket)
|
||||
|
@ -108,7 +106,7 @@ type Settings struct {
|
|||
func Parse(path string) (*Settings, error) {
|
||||
s := &Settings{}
|
||||
_, err := toml.DecodeFile(path, s)
|
||||
return s, err
|
||||
return applyDefaults(s), err
|
||||
}
|
||||
|
||||
// ParseString parses the Drone settings string and unmarshals
|
||||
|
@ -116,5 +114,18 @@ func Parse(path string) (*Settings, error) {
|
|||
func ParseString(data string) (*Settings, error) {
|
||||
s := &Settings{}
|
||||
_, err := toml.Decode(data, s)
|
||||
return s, err
|
||||
return applyDefaults(s), err
|
||||
}
|
||||
|
||||
func applyDefaults(s *Settings) *Settings {
|
||||
if s.Session == nil {
|
||||
s.Session = &Session{}
|
||||
}
|
||||
// if no session token is provided we can
|
||||
// instead use the client secret to sign
|
||||
// our sessions and tokens.
|
||||
if len(s.Session.Secret) == 0 {
|
||||
s.Session.Secret = s.Service.OAuth.Secret
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue