mirror of
https://github.com/woodpecker-ci/woodpecker.git
synced 2025-02-18 04:15:15 +00:00
bump to 0.5 in master
This commit is contained in:
parent
53eac09f34
commit
0fb4aeda3f
43 changed files with 802 additions and 1347 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -12,7 +12,7 @@ drone/drone
|
||||||
.env
|
.env
|
||||||
temp/
|
temp/
|
||||||
|
|
||||||
api/swagger/files/*
|
server/swagger/files/*.json
|
||||||
|
|
||||||
# vendored repositories that we don't actually need
|
# vendored repositories that we don't actually need
|
||||||
# to vendor. so exclude them
|
# to vendor. so exclude them
|
||||||
|
|
|
@ -21,4 +21,4 @@ ADD drone/drone /drone
|
||||||
#RUN echo 'hosts: files mdns4_minimal [NOTFOUND=return] dns mdns4' >> /etc/nsswitch.conf
|
#RUN echo 'hosts: files mdns4_minimal [NOTFOUND=return] dns mdns4' >> /etc/nsswitch.conf
|
||||||
|
|
||||||
ENTRYPOINT ["/drone"]
|
ENTRYPOINT ["/drone"]
|
||||||
CMD ["serve"]
|
CMD ["daemon"]
|
||||||
|
|
|
@ -1,3 +0,0 @@
|
||||||
package swagger
|
|
||||||
|
|
||||||
//go:generate go-bindata -pkg swagger -o swagger_gen.go files/
|
|
315
drone/daemon.go
315
drone/daemon.go
|
@ -6,20 +6,9 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/drone/drone/bus"
|
"github.com/drone/drone/router"
|
||||||
"github.com/drone/drone/cache"
|
"github.com/drone/drone/router/middleware"
|
||||||
"github.com/drone/drone/queue"
|
"github.com/gin-gonic/contrib/ginrus"
|
||||||
"github.com/drone/drone/remote"
|
|
||||||
"github.com/drone/drone/remote/bitbucket"
|
|
||||||
"github.com/drone/drone/remote/bitbucketserver"
|
|
||||||
"github.com/drone/drone/remote/github"
|
|
||||||
"github.com/drone/drone/remote/gitlab"
|
|
||||||
"github.com/drone/drone/remote/gogs"
|
|
||||||
"github.com/drone/drone/server"
|
|
||||||
"github.com/drone/drone/shared/token"
|
|
||||||
"github.com/drone/drone/store"
|
|
||||||
"github.com/drone/drone/store/datastore"
|
|
||||||
"github.com/drone/drone/stream"
|
|
||||||
|
|
||||||
"github.com/Sirupsen/logrus"
|
"github.com/Sirupsen/logrus"
|
||||||
"github.com/codegangsta/cli"
|
"github.com/codegangsta/cli"
|
||||||
|
@ -300,22 +289,19 @@ func start(c *cli.Context) error {
|
||||||
logrus.SetLevel(logrus.WarnLevel)
|
logrus.SetLevel(logrus.WarnLevel)
|
||||||
}
|
}
|
||||||
|
|
||||||
// print the agent secret to the console
|
|
||||||
// TODO(bradrydzewski) this overall approach should be re-considered
|
|
||||||
if err := printSecret(c); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// setup the server and start the listener
|
// setup the server and start the listener
|
||||||
server := server.Server{
|
handler := router.Load(
|
||||||
Bus: setupBus(c),
|
ginrus.Ginrus(logrus.StandardLogger(), time.RFC3339, true),
|
||||||
Cache: setupCache(c),
|
middleware.Version,
|
||||||
Config: setupConfig(c),
|
middleware.Config(c),
|
||||||
Queue: setupQueue(c),
|
middleware.Queue(c),
|
||||||
Remote: setupRemote(c),
|
middleware.Stream(c),
|
||||||
Stream: setupStream(c),
|
middleware.Bus(c),
|
||||||
Store: setupStore(c),
|
middleware.Cache(c),
|
||||||
}
|
middleware.Store(c),
|
||||||
|
middleware.Remote(c),
|
||||||
|
middleware.Agents(c),
|
||||||
|
)
|
||||||
|
|
||||||
// start the server with tls enabled
|
// start the server with tls enabled
|
||||||
if c.String("server-cert") != "" {
|
if c.String("server-cert") != "" {
|
||||||
|
@ -323,150 +309,151 @@ func start(c *cli.Context) error {
|
||||||
c.String("server-addr"),
|
c.String("server-addr"),
|
||||||
c.String("server-cert"),
|
c.String("server-cert"),
|
||||||
c.String("server-key"),
|
c.String("server-key"),
|
||||||
server.Handler(),
|
handler,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// start the server without tls enabled
|
// start the server without tls enabled
|
||||||
return http.ListenAndServe(
|
return http.ListenAndServe(
|
||||||
c.String("server-addr"),
|
c.String("server-addr"),
|
||||||
server.Handler(),
|
handler,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func setupCache(c *cli.Context) cache.Cache {
|
//
|
||||||
return cache.NewTTL(
|
// func setupCache(c *cli.Context) cache.Cache {
|
||||||
c.Duration("cache-ttl"),
|
// return cache.NewTTL(
|
||||||
)
|
// c.Duration("cache-ttl"),
|
||||||
}
|
// )
|
||||||
|
// }
|
||||||
func setupBus(c *cli.Context) bus.Bus {
|
//
|
||||||
return bus.New()
|
// func setupBus(c *cli.Context) bus.Bus {
|
||||||
}
|
// return bus.New()
|
||||||
|
// }
|
||||||
func setupQueue(c *cli.Context) queue.Queue {
|
//
|
||||||
return queue.New()
|
// func setupQueue(c *cli.Context) queue.Queue {
|
||||||
}
|
// return queue.New()
|
||||||
|
// }
|
||||||
func setupStream(c *cli.Context) stream.Stream {
|
//
|
||||||
return stream.New()
|
// func setupStream(c *cli.Context) stream.Stream {
|
||||||
}
|
// return stream.New()
|
||||||
|
// }
|
||||||
func setupStore(c *cli.Context) store.Store {
|
//
|
||||||
return datastore.New(
|
// func setupStore(c *cli.Context) store.Store {
|
||||||
c.String("driver"),
|
// return datastore.New(
|
||||||
c.String("datasource"),
|
// c.String("driver"),
|
||||||
)
|
// c.String("datasource"),
|
||||||
}
|
// )
|
||||||
|
// }
|
||||||
func setupRemote(c *cli.Context) remote.Remote {
|
//
|
||||||
var remote remote.Remote
|
// func setupRemote(c *cli.Context) remote.Remote {
|
||||||
var err error
|
// var remote remote.Remote
|
||||||
switch {
|
// var err error
|
||||||
case c.Bool("github"):
|
// switch {
|
||||||
remote, err = setupGithub(c)
|
// case c.Bool("github"):
|
||||||
case c.Bool("gitlab"):
|
// remote, err = setupGithub(c)
|
||||||
remote, err = setupGitlab(c)
|
// case c.Bool("gitlab"):
|
||||||
case c.Bool("bitbucket"):
|
// remote, err = setupGitlab(c)
|
||||||
remote, err = setupBitbucket(c)
|
// case c.Bool("bitbucket"):
|
||||||
case c.Bool("stash"):
|
// remote, err = setupBitbucket(c)
|
||||||
remote, err = setupStash(c)
|
// case c.Bool("stash"):
|
||||||
case c.Bool("gogs"):
|
// remote, err = setupStash(c)
|
||||||
remote, err = setupGogs(c)
|
// case c.Bool("gogs"):
|
||||||
default:
|
// remote, err = setupGogs(c)
|
||||||
err = fmt.Errorf("version control system not configured")
|
// default:
|
||||||
}
|
// err = fmt.Errorf("version control system not configured")
|
||||||
if err != nil {
|
// }
|
||||||
logrus.Fatalln(err)
|
// if err != nil {
|
||||||
}
|
// logrus.Fatalln(err)
|
||||||
return remote
|
// }
|
||||||
}
|
// return remote
|
||||||
|
// }
|
||||||
func setupBitbucket(c *cli.Context) (remote.Remote, error) {
|
//
|
||||||
return bitbucket.New(
|
// func setupBitbucket(c *cli.Context) (remote.Remote, error) {
|
||||||
c.String("bitbucket-client"),
|
// return bitbucket.New(
|
||||||
c.String("bitbucket-server"),
|
// c.String("bitbucket-client"),
|
||||||
), nil
|
// c.String("bitbucket-server"),
|
||||||
}
|
// ), nil
|
||||||
|
// }
|
||||||
func setupGogs(c *cli.Context) (remote.Remote, error) {
|
//
|
||||||
return gogs.New(gogs.Opts{
|
// func setupGogs(c *cli.Context) (remote.Remote, error) {
|
||||||
URL: c.String("gogs-server"),
|
// return gogs.New(gogs.Opts{
|
||||||
Username: c.String("gogs-git-username"),
|
// URL: c.String("gogs-server"),
|
||||||
Password: c.String("gogs-git-password"),
|
// Username: c.String("gogs-git-username"),
|
||||||
PrivateMode: c.Bool("gogs-private-mode"),
|
// Password: c.String("gogs-git-password"),
|
||||||
SkipVerify: c.Bool("gogs-skip-verify"),
|
// PrivateMode: c.Bool("gogs-private-mode"),
|
||||||
})
|
// SkipVerify: c.Bool("gogs-skip-verify"),
|
||||||
}
|
// })
|
||||||
|
// }
|
||||||
func setupStash(c *cli.Context) (remote.Remote, error) {
|
//
|
||||||
return bitbucketserver.New(bitbucketserver.Opts{
|
// func setupStash(c *cli.Context) (remote.Remote, error) {
|
||||||
URL: c.String("stash-server"),
|
// return bitbucketserver.New(bitbucketserver.Opts{
|
||||||
Username: c.String("stash-git-username"),
|
// URL: c.String("stash-server"),
|
||||||
Password: c.String("stash-git-password"),
|
// Username: c.String("stash-git-username"),
|
||||||
ConsumerKey: c.String("stash-consumer-key"),
|
// Password: c.String("stash-git-password"),
|
||||||
ConsumerRSA: c.String("stash-consumer-rsa"),
|
// ConsumerKey: c.String("stash-consumer-key"),
|
||||||
SkipVerify: c.Bool("stash-skip-verify"),
|
// ConsumerRSA: c.String("stash-consumer-rsa"),
|
||||||
})
|
// SkipVerify: c.Bool("stash-skip-verify"),
|
||||||
}
|
// })
|
||||||
|
// }
|
||||||
func setupGitlab(c *cli.Context) (remote.Remote, error) {
|
//
|
||||||
return gitlab.New(gitlab.Opts{
|
// func setupGitlab(c *cli.Context) (remote.Remote, error) {
|
||||||
URL: c.String("gitlab-server"),
|
// return gitlab.New(gitlab.Opts{
|
||||||
Client: c.String("gitlab-client"),
|
// URL: c.String("gitlab-server"),
|
||||||
Secret: c.String("gitlab-sercret"),
|
// Client: c.String("gitlab-client"),
|
||||||
Username: c.String("gitlab-git-username"),
|
// Secret: c.String("gitlab-sercret"),
|
||||||
Password: c.String("gitlab-git-password"),
|
// Username: c.String("gitlab-git-username"),
|
||||||
PrivateMode: c.Bool("gitlab-private-mode"),
|
// Password: c.String("gitlab-git-password"),
|
||||||
SkipVerify: c.Bool("gitlab-skip-verify"),
|
// PrivateMode: c.Bool("gitlab-private-mode"),
|
||||||
})
|
// SkipVerify: c.Bool("gitlab-skip-verify"),
|
||||||
}
|
// })
|
||||||
|
// }
|
||||||
func setupGithub(c *cli.Context) (remote.Remote, error) {
|
//
|
||||||
return github.New(
|
// func setupGithub(c *cli.Context) (remote.Remote, error) {
|
||||||
c.String("github-server"),
|
// return github.New(
|
||||||
c.String("github-client"),
|
// c.String("github-server"),
|
||||||
c.String("github-sercret"),
|
// c.String("github-client"),
|
||||||
c.StringSlice("github-scope"),
|
// c.String("github-sercret"),
|
||||||
c.Bool("github-private-mode"),
|
// c.StringSlice("github-scope"),
|
||||||
c.Bool("github-skip-verify"),
|
// c.Bool("github-private-mode"),
|
||||||
c.BoolT("github-merge-ref"),
|
// c.Bool("github-skip-verify"),
|
||||||
)
|
// c.BoolT("github-merge-ref"),
|
||||||
}
|
// )
|
||||||
|
// }
|
||||||
func setupConfig(c *cli.Context) *server.Config {
|
//
|
||||||
return &server.Config{
|
// func setupConfig(c *cli.Context) *server.Config {
|
||||||
Open: c.Bool("open"),
|
// return &server.Config{
|
||||||
Yaml: c.String("yaml"),
|
// Open: c.Bool("open"),
|
||||||
Secret: c.String("agent-secret"),
|
// Yaml: c.String("yaml"),
|
||||||
Admins: sliceToMap(c.StringSlice("admin")),
|
// Secret: c.String("agent-secret"),
|
||||||
Orgs: sliceToMap(c.StringSlice("orgs")),
|
// Admins: sliceToMap(c.StringSlice("admin")),
|
||||||
}
|
// Orgs: sliceToMap(c.StringSlice("orgs")),
|
||||||
}
|
// }
|
||||||
|
// }
|
||||||
func sliceToMap(s []string) map[string]bool {
|
//
|
||||||
v := map[string]bool{}
|
// func sliceToMap(s []string) map[string]bool {
|
||||||
for _, ss := range s {
|
// v := map[string]bool{}
|
||||||
v[ss] = true
|
// for _, ss := range s {
|
||||||
}
|
// v[ss] = true
|
||||||
return v
|
// }
|
||||||
}
|
// return v
|
||||||
|
// }
|
||||||
func printSecret(c *cli.Context) error {
|
//
|
||||||
secret := c.String("agent-secret")
|
// func printSecret(c *cli.Context) error {
|
||||||
if secret == "" {
|
// secret := c.String("agent-secret")
|
||||||
return fmt.Errorf("missing DRONE_AGENT_SECRET configuration parameter")
|
// if secret == "" {
|
||||||
}
|
// return fmt.Errorf("missing DRONE_AGENT_SECRET configuration parameter")
|
||||||
t := token.New(secret, "")
|
// }
|
||||||
s, err := t.Sign(secret)
|
// t := token.New(secret, "")
|
||||||
if err != nil {
|
// s, err := t.Sign(secret)
|
||||||
return fmt.Errorf("invalid value for DRONE_AGENT_SECRET. %s", s)
|
// if err != nil {
|
||||||
}
|
// return fmt.Errorf("invalid value for DRONE_AGENT_SECRET. %s", s)
|
||||||
|
// }
|
||||||
logrus.Infof("using agent secret %s", secret)
|
//
|
||||||
logrus.Warnf("agents can connect with token %s", s)
|
// logrus.Infof("using agent secret %s", secret)
|
||||||
return nil
|
// logrus.Warnf("agents can connect with token %s", s)
|
||||||
}
|
// return nil
|
||||||
|
// }
|
||||||
|
|
||||||
var agreement = `
|
var agreement = `
|
||||||
---
|
---
|
||||||
|
|
26
model/config.go
Normal file
26
model/config.go
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
package model
|
||||||
|
|
||||||
|
// Config defines system configuration parameters.
|
||||||
|
type Config struct {
|
||||||
|
Open bool // Enables open registration
|
||||||
|
Yaml string // Customize the Yaml configuration file name
|
||||||
|
Shasum string // Customize the Yaml checksum file name
|
||||||
|
Secret string // Secret token used to authenticate agents
|
||||||
|
Admins map[string]bool // Administrative users
|
||||||
|
Orgs map[string]bool // Organization whitelist
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsAdmin returns true if the user is a member of the administrator list.
|
||||||
|
func (c *Config) IsAdmin(user *User) bool {
|
||||||
|
return c.Admins[user.Login]
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsMember returns true if the user is a member of the whitelisted teams.
|
||||||
|
func (c *Config) IsMember(teams []*Team) bool {
|
||||||
|
for _, team := range teams {
|
||||||
|
if c.Orgs[team.Login] {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
|
@ -32,11 +32,17 @@ type User struct {
|
||||||
Avatar string `json:"avatar_url" meddler:"user_avatar"`
|
Avatar string `json:"avatar_url" meddler:"user_avatar"`
|
||||||
|
|
||||||
// Activate indicates the user is active in the system.
|
// Activate indicates the user is active in the system.
|
||||||
Active bool `json:"active," meddler:"user_active"`
|
Active bool `json:"active" meddler:"user_active"`
|
||||||
|
|
||||||
// Admin indicates the user is a system administrator.
|
// Admin indicates the user is a system administrator.
|
||||||
Admin bool `json:"admin," meddler:"user_admin"`
|
//
|
||||||
|
// NOTE: This is sourced from the DRONE_ADMINS environment variable and is no
|
||||||
|
// longer persisted in the database.
|
||||||
|
Admin bool `json:"admin,omitempty" meddler:"-"`
|
||||||
|
|
||||||
// Hash is a unique token used to sign tokens.
|
// Hash is a unique token used to sign tokens.
|
||||||
Hash string `json:"-" meddler:"user_hash"`
|
Hash string `json:"-" meddler:"user_hash"`
|
||||||
|
|
||||||
|
// DEPRECATED Admin indicates the user is a system administrator.
|
||||||
|
XAdmin bool `json:"-" meddler:"user_admin"`
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,85 +0,0 @@
|
||||||
package remote
|
|
||||||
|
|
||||||
import (
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/drone/drone/model"
|
|
||||||
)
|
|
||||||
|
|
||||||
// WithCache returns a the parent Remote with a front-end Cache. Remote items
|
|
||||||
// are cached for duration d.
|
|
||||||
func WithCache(r Remote, d time.Duration) Remote {
|
|
||||||
return r
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cacher implements purge functionality so that we can evict stale data and
|
|
||||||
// force a refresh. The indended use case is when the repository list is out
|
|
||||||
// of date and requires manual refresh.
|
|
||||||
type Cacher interface {
|
|
||||||
Purge(*model.User)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Because the cache is so closely tied to the remote we should just include
|
|
||||||
// them in the same package together. The below code are stubs for merging
|
|
||||||
// the Cache with the Remote package.
|
|
||||||
|
|
||||||
type cache struct {
|
|
||||||
Remote
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *cache) Repos(u *model.User) ([]*model.RepoLite, error) {
|
|
||||||
// key := fmt.Sprintf("repos:%s",
|
|
||||||
// user.Login,
|
|
||||||
// )
|
|
||||||
// // if we fetch from the cache we can return immediately
|
|
||||||
// val, err := Get(c, key)
|
|
||||||
// if err == nil {
|
|
||||||
// return val.([]*model.RepoLite), nil
|
|
||||||
// }
|
|
||||||
// // else we try to grab from the remote system and
|
|
||||||
// // populate our cache.
|
|
||||||
// repos, err := remote.Repos(c, user)
|
|
||||||
// if err != nil {
|
|
||||||
// return nil, err
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// Set(c, key, repos)
|
|
||||||
// return repos, nil
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *cache) Perm(u *model.User, owner, repo string) (*model.Perm, error) {
|
|
||||||
// key := fmt.Sprintf("perms:%s:%s/%s",
|
|
||||||
// user.Login,
|
|
||||||
// owner,
|
|
||||||
// name,
|
|
||||||
// )
|
|
||||||
// // if we fetch from the cache we can return immediately
|
|
||||||
// val, err := Get(c, key)
|
|
||||||
// if err == nil {
|
|
||||||
// return val.(*model.Perm), nil
|
|
||||||
// }
|
|
||||||
// // else we try to grab from the remote system and
|
|
||||||
// // populate our cache.
|
|
||||||
// perm, err := remote.Perm(c, user, owner, name)
|
|
||||||
// if err != nil {
|
|
||||||
// return nil, err
|
|
||||||
// }
|
|
||||||
// Set(c, key, perm)
|
|
||||||
// return perm, nil
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *cache) Purge(*model.User) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *cache) Refresh(u *model.User) (bool, error) {
|
|
||||||
if r, ok := c.Remote.(Refresher); ok {
|
|
||||||
return r.Refresh(u)
|
|
||||||
}
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ Remote = &cache{}
|
|
||||||
var _ Refresher = &cache{}
|
|
|
@ -1,45 +1,33 @@
|
||||||
package middleware
|
package middleware
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/codegangsta/cli"
|
||||||
"github.com/drone/drone/shared/token"
|
"github.com/drone/drone/shared/token"
|
||||||
|
|
||||||
"github.com/Sirupsen/logrus"
|
"github.com/Sirupsen/logrus"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/ianschenck/envflag"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
const agentKey = "agent"
|
||||||
secret = envflag.String("DRONE_AGENT_SECRET", "", "")
|
|
||||||
noauth = envflag.Bool("AGENT_NO_AUTH", false, "")
|
|
||||||
)
|
|
||||||
|
|
||||||
// Agent is a middleware function that initializes the authorization middleware
|
// Agents is a middleware function that initializes the authorization middleware
|
||||||
// for agents to connect to the queue.
|
// for agents to connect to the queue.
|
||||||
func AgentMust() gin.HandlerFunc {
|
func Agents(cli *cli.Context) gin.HandlerFunc {
|
||||||
|
secret := cli.String("agent-secret")
|
||||||
if *secret == "" {
|
if secret == "" {
|
||||||
logrus.Fatalf("please provide the agent secret to authenticate agent requests")
|
logrus.Fatalf("failed to generate token from DRONE_AGENT_SECRET")
|
||||||
}
|
}
|
||||||
|
|
||||||
t := token.New(token.AgentToken, "")
|
t := token.New(secret, "")
|
||||||
s, err := t.Sign(*secret)
|
s, err := t.Sign(secret)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.Fatalf("invalid agent secret. %s", err)
|
logrus.Fatalf("failed to generate token from DRONE_AGENT_SECRET. %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
logrus.Infof("using agent secret %s", *secret)
|
logrus.Infof("using agent secret %s", secret)
|
||||||
logrus.Warnf("agents can connect with token %s", s)
|
logrus.Warnf("agents can connect with token %s", s)
|
||||||
|
|
||||||
return func(c *gin.Context) {
|
return func(c *gin.Context) {
|
||||||
parsed, err := token.ParseRequest(c.Request, func(t *token.Token) (string, error) {
|
c.Set(agentKey, secret)
|
||||||
return *secret, nil
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
c.AbortWithError(403, err)
|
|
||||||
} else if parsed.Kind != token.AgentToken {
|
|
||||||
c.AbortWithStatus(403)
|
|
||||||
} else {
|
|
||||||
c.Next()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
17
router/middleware/bus.go
Normal file
17
router/middleware/bus.go
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
package middleware
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/drone/drone/bus"
|
||||||
|
|
||||||
|
"github.com/codegangsta/cli"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Bus is a middleware function that initializes the Event Bus and attaches to
|
||||||
|
// the context of every http.Request.
|
||||||
|
func Bus(cli *cli.Context) gin.HandlerFunc {
|
||||||
|
v := bus.New()
|
||||||
|
return func(c *gin.Context) {
|
||||||
|
bus.ToContext(c, v)
|
||||||
|
}
|
||||||
|
}
|
24
router/middleware/cache.go
Normal file
24
router/middleware/cache.go
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
package middleware
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/drone/drone/cache"
|
||||||
|
|
||||||
|
"github.com/codegangsta/cli"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Cache is a middleware function that initializes the Cache and attaches to
|
||||||
|
// the context of every http.Request.
|
||||||
|
func Cache(cli *cli.Context) gin.HandlerFunc {
|
||||||
|
v := setupCache(cli)
|
||||||
|
return func(c *gin.Context) {
|
||||||
|
cache.ToContext(c, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// helper function to create the cache from the CLI context.
|
||||||
|
func setupCache(c *cli.Context) cache.Cache {
|
||||||
|
return cache.NewTTL(
|
||||||
|
c.Duration("cache-ttl"),
|
||||||
|
)
|
||||||
|
}
|
40
router/middleware/config.go
Normal file
40
router/middleware/config.go
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
package middleware
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/drone/drone/model"
|
||||||
|
|
||||||
|
"github.com/codegangsta/cli"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
)
|
||||||
|
|
||||||
|
const configKey = "config"
|
||||||
|
|
||||||
|
// Config is a middleware function that initializes the Configuration and
|
||||||
|
// attaches to the context of every http.Request.
|
||||||
|
func Config(cli *cli.Context) gin.HandlerFunc {
|
||||||
|
v := setupConfig(cli)
|
||||||
|
return func(c *gin.Context) {
|
||||||
|
c.Set(configKey, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// helper function to create the configuration from the CLI context.
|
||||||
|
func setupConfig(c *cli.Context) *model.Config {
|
||||||
|
return &model.Config{
|
||||||
|
Open: c.Bool("open"),
|
||||||
|
Yaml: c.String("yaml"),
|
||||||
|
Shasum: c.String("yaml") + ".sig",
|
||||||
|
Secret: c.String("agent-secret"),
|
||||||
|
Admins: sliceToMap(c.StringSlice("admin")),
|
||||||
|
Orgs: sliceToMap(c.StringSlice("orgs")),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// helper function to convert a string slice to a map.
|
||||||
|
func sliceToMap(s []string) map[string]bool {
|
||||||
|
v := map[string]bool{}
|
||||||
|
for _, ss := range s {
|
||||||
|
v[ss] = true
|
||||||
|
}
|
||||||
|
return v
|
||||||
|
}
|
17
router/middleware/queue.go
Normal file
17
router/middleware/queue.go
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
package middleware
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/drone/drone/queue"
|
||||||
|
|
||||||
|
"github.com/codegangsta/cli"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Queue is a middleware function that initializes the Queue and attaches to
|
||||||
|
// the context of every http.Request.
|
||||||
|
func Queue(cli *cli.Context) gin.HandlerFunc {
|
||||||
|
v := queue.New()
|
||||||
|
return func(c *gin.Context) {
|
||||||
|
queue.ToContext(c, v)
|
||||||
|
}
|
||||||
|
}
|
102
router/middleware/remote.go
Normal file
102
router/middleware/remote.go
Normal file
|
@ -0,0 +1,102 @@
|
||||||
|
package middleware
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/Sirupsen/logrus"
|
||||||
|
"github.com/codegangsta/cli"
|
||||||
|
"github.com/drone/drone/remote"
|
||||||
|
"github.com/drone/drone/remote/bitbucket"
|
||||||
|
"github.com/drone/drone/remote/bitbucketserver"
|
||||||
|
"github.com/drone/drone/remote/github"
|
||||||
|
"github.com/drone/drone/remote/gitlab"
|
||||||
|
"github.com/drone/drone/remote/gogs"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Remote is a middleware function that initializes the Remote and attaches to
|
||||||
|
// the context of every http.Request.
|
||||||
|
func Remote(c *cli.Context) gin.HandlerFunc {
|
||||||
|
v, err := setupRemote(c)
|
||||||
|
if err != nil {
|
||||||
|
logrus.Fatalln(err)
|
||||||
|
}
|
||||||
|
return func(c *gin.Context) {
|
||||||
|
remote.ToContext(c, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// helper function to setup the remote from the CLI arguments.
|
||||||
|
func setupRemote(c *cli.Context) (remote.Remote, error) {
|
||||||
|
switch {
|
||||||
|
case c.Bool("github"):
|
||||||
|
return setupGithub(c)
|
||||||
|
case c.Bool("gitlab"):
|
||||||
|
return setupGitlab(c)
|
||||||
|
case c.Bool("bitbucket"):
|
||||||
|
return setupBitbucket(c)
|
||||||
|
case c.Bool("stash"):
|
||||||
|
return setupStash(c)
|
||||||
|
case c.Bool("gogs"):
|
||||||
|
return setupGogs(c)
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("version control system not configured")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// helper function to setup the Bitbucket remote from the CLI arguments.
|
||||||
|
func setupBitbucket(c *cli.Context) (remote.Remote, error) {
|
||||||
|
return bitbucket.New(
|
||||||
|
c.String("bitbucket-client"),
|
||||||
|
c.String("bitbucket-server"),
|
||||||
|
), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// helper function to setup the Gogs remote from the CLI arguments.
|
||||||
|
func setupGogs(c *cli.Context) (remote.Remote, error) {
|
||||||
|
return gogs.New(gogs.Opts{
|
||||||
|
URL: c.String("gogs-server"),
|
||||||
|
Username: c.String("gogs-git-username"),
|
||||||
|
Password: c.String("gogs-git-password"),
|
||||||
|
PrivateMode: c.Bool("gogs-private-mode"),
|
||||||
|
SkipVerify: c.Bool("gogs-skip-verify"),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// helper function to setup the Stash remote from the CLI arguments.
|
||||||
|
func setupStash(c *cli.Context) (remote.Remote, error) {
|
||||||
|
return bitbucketserver.New(bitbucketserver.Opts{
|
||||||
|
URL: c.String("stash-server"),
|
||||||
|
Username: c.String("stash-git-username"),
|
||||||
|
Password: c.String("stash-git-password"),
|
||||||
|
ConsumerKey: c.String("stash-consumer-key"),
|
||||||
|
ConsumerRSA: c.String("stash-consumer-rsa"),
|
||||||
|
SkipVerify: c.Bool("stash-skip-verify"),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// helper function to setup the Gitlab remote from the CLI arguments.
|
||||||
|
func setupGitlab(c *cli.Context) (remote.Remote, error) {
|
||||||
|
return gitlab.New(gitlab.Opts{
|
||||||
|
URL: c.String("gitlab-server"),
|
||||||
|
Client: c.String("gitlab-client"),
|
||||||
|
Secret: c.String("gitlab-sercret"),
|
||||||
|
Username: c.String("gitlab-git-username"),
|
||||||
|
Password: c.String("gitlab-git-password"),
|
||||||
|
PrivateMode: c.Bool("gitlab-private-mode"),
|
||||||
|
SkipVerify: c.Bool("gitlab-skip-verify"),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// helper function to setup the GitHub remote from the CLI arguments.
|
||||||
|
func setupGithub(c *cli.Context) (remote.Remote, error) {
|
||||||
|
return github.New(
|
||||||
|
c.String("github-server"),
|
||||||
|
c.String("github-client"),
|
||||||
|
c.String("github-sercret"),
|
||||||
|
c.StringSlice("github-scope"),
|
||||||
|
c.Bool("github-private-mode"),
|
||||||
|
c.Bool("github-skip-verify"),
|
||||||
|
c.BoolT("github-merge-ref"),
|
||||||
|
)
|
||||||
|
}
|
22
router/middleware/session/agent.go
Normal file
22
router/middleware/session/agent.go
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
package session
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/drone/drone/shared/token"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
)
|
||||||
|
|
||||||
|
// AuthorizeAgent authorizes requsts from build agents to access the queue.
|
||||||
|
func AuthorizeAgent(c *gin.Context) {
|
||||||
|
secret := c.MustGet("agent").(string)
|
||||||
|
|
||||||
|
parsed, err := token.ParseRequest(c.Request, func(t *token.Token) (string, error) {
|
||||||
|
return secret, nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
c.AbortWithError(403, err)
|
||||||
|
} else if parsed.Kind != token.AgentToken {
|
||||||
|
c.AbortWithStatus(403)
|
||||||
|
} else {
|
||||||
|
c.Next()
|
||||||
|
}
|
||||||
|
}
|
|
@ -44,6 +44,10 @@ func SetUser() gin.HandlerFunc {
|
||||||
return user.Hash, err
|
return user.Hash, err
|
||||||
})
|
})
|
||||||
if err == nil {
|
if err == nil {
|
||||||
|
confv := c.MustGet("config")
|
||||||
|
if conf, ok := confv.(*model.Config); ok {
|
||||||
|
user.Admin = conf.IsAdmin(user)
|
||||||
|
}
|
||||||
c.Set("user", user)
|
c.Set("user", user)
|
||||||
|
|
||||||
// if this is a session token (ie not the API token)
|
// if this is a session token (ie not the API token)
|
||||||
|
|
27
router/middleware/store.go
Normal file
27
router/middleware/store.go
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
package middleware
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/codegangsta/cli"
|
||||||
|
"github.com/drone/drone/store"
|
||||||
|
"github.com/drone/drone/store/datastore"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Store is a middleware function that initializes the Datastore and attaches to
|
||||||
|
// the context of every http.Request.
|
||||||
|
func Store(cli *cli.Context) gin.HandlerFunc {
|
||||||
|
v := setupStore(cli)
|
||||||
|
return func(c *gin.Context) {
|
||||||
|
store.ToContext(c, v)
|
||||||
|
c.Next()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// helper function to create the datastore from the CLI context.
|
||||||
|
func setupStore(c *cli.Context) store.Store {
|
||||||
|
return datastore.New(
|
||||||
|
c.String("driver"),
|
||||||
|
c.String("datasource"),
|
||||||
|
)
|
||||||
|
}
|
17
router/middleware/stream.go
Normal file
17
router/middleware/stream.go
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
package middleware
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/drone/drone/stream"
|
||||||
|
|
||||||
|
"github.com/codegangsta/cli"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Stream is a middleware function that initializes the Stream and attaches to
|
||||||
|
// the context of every http.Request.
|
||||||
|
func Stream(cli *cli.Context) gin.HandlerFunc {
|
||||||
|
v := stream.New()
|
||||||
|
return func(c *gin.Context) {
|
||||||
|
stream.ToContext(c, v)
|
||||||
|
}
|
||||||
|
}
|
12
router/middleware/version.go
Normal file
12
router/middleware/version.go
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
package middleware
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/drone/drone/version"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Version is a middleware function that appends the Drone version information
|
||||||
|
// to the HTTP response. This is intended for debugging and troubleshooting.
|
||||||
|
func Version(c *gin.Context) {
|
||||||
|
c.Header("X-DRONE-VERSION", version.Version)
|
||||||
|
}
|
394
router/router.go
394
router/router.go
|
@ -1,201 +1,199 @@
|
||||||
package router
|
package router
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
|
||||||
|
"github.com/drone/drone/router/middleware/header"
|
||||||
|
"github.com/drone/drone/router/middleware/session"
|
||||||
|
"github.com/drone/drone/router/middleware/token"
|
||||||
|
"github.com/drone/drone/server"
|
||||||
|
"github.com/drone/drone/static"
|
||||||
|
"github.com/drone/drone/template"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Load(middleware ...gin.HandlerFunc) http.Handler {
|
||||||
|
|
||||||
|
e := gin.New()
|
||||||
|
e.Use(gin.Recovery())
|
||||||
|
|
||||||
|
e.SetHTMLTemplate(template.Load())
|
||||||
|
e.StaticFS("/static", static.FileSystem())
|
||||||
|
|
||||||
|
e.Use(header.NoCache)
|
||||||
|
e.Use(header.Options)
|
||||||
|
e.Use(header.Secure)
|
||||||
|
e.Use(middleware...)
|
||||||
|
e.Use(session.SetUser())
|
||||||
|
e.Use(token.Refresh)
|
||||||
|
|
||||||
|
e.GET("/", server.ShowIndex)
|
||||||
|
e.GET("/repos", server.ShowAllRepos)
|
||||||
|
e.GET("/login", server.ShowLogin)
|
||||||
|
e.GET("/login/form", server.ShowLoginForm)
|
||||||
|
e.GET("/logout", server.GetLogout)
|
||||||
|
|
||||||
|
// TODO below will Go away with React UI
|
||||||
|
settings := e.Group("/settings")
|
||||||
|
{
|
||||||
|
settings.Use(session.MustUser())
|
||||||
|
settings.GET("/profile", server.ShowUser)
|
||||||
|
}
|
||||||
|
repo := e.Group("/repos/:owner/:name")
|
||||||
|
{
|
||||||
|
repo.Use(session.SetRepo())
|
||||||
|
repo.Use(session.SetPerm())
|
||||||
|
repo.Use(session.MustPull)
|
||||||
|
|
||||||
|
repo.GET("", server.ShowRepo)
|
||||||
|
repo.GET("/builds/:number", server.ShowBuild)
|
||||||
|
repo.GET("/builds/:number/:job", server.ShowBuild)
|
||||||
|
|
||||||
|
repo_settings := repo.Group("/settings")
|
||||||
|
{
|
||||||
|
repo_settings.GET("", session.MustPush, server.ShowRepoConf)
|
||||||
|
repo_settings.GET("/encrypt", session.MustPush, server.ShowRepoEncrypt)
|
||||||
|
repo_settings.GET("/badges", server.ShowRepoBadges)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// TODO above will Go away with React UI
|
||||||
|
|
||||||
|
user := e.Group("/api/user")
|
||||||
|
{
|
||||||
|
user.Use(session.MustUser())
|
||||||
|
user.GET("", server.GetSelf)
|
||||||
|
user.GET("/feed", server.GetFeed)
|
||||||
|
user.GET("/repos", server.GetRepos)
|
||||||
|
user.GET("/repos/remote", server.GetRemoteRepos)
|
||||||
|
user.POST("/token", server.PostToken)
|
||||||
|
user.DELETE("/token", server.DeleteToken)
|
||||||
|
}
|
||||||
|
|
||||||
|
users := e.Group("/api/users")
|
||||||
|
{
|
||||||
|
users.Use(session.MustAdmin())
|
||||||
|
users.GET("", server.GetUsers)
|
||||||
|
users.POST("", server.PostUser)
|
||||||
|
users.GET("/:login", server.GetUser)
|
||||||
|
users.PATCH("/:login", server.PatchUser)
|
||||||
|
users.DELETE("/:login", server.DeleteUser)
|
||||||
|
}
|
||||||
|
|
||||||
|
repos := e.Group("/api/repos/:owner/:name")
|
||||||
|
{
|
||||||
|
repos.POST("", server.PostRepo)
|
||||||
|
|
||||||
|
repo := repos.Group("")
|
||||||
|
{
|
||||||
|
repo.Use(session.SetRepo())
|
||||||
|
repo.Use(session.SetPerm())
|
||||||
|
repo.Use(session.MustPull)
|
||||||
|
|
||||||
|
repo.GET("", server.GetRepo)
|
||||||
|
repo.GET("/builds", server.GetBuilds)
|
||||||
|
repo.GET("/builds/:number", server.GetBuild)
|
||||||
|
repo.GET("/logs/:number/:job", server.GetBuildLogs)
|
||||||
|
repo.POST("/sign", session.MustPush, server.Sign)
|
||||||
|
|
||||||
|
repo.POST("/secrets", session.MustPush, server.PostSecret)
|
||||||
|
repo.DELETE("/secrets/:secret", session.MustPush, server.DeleteSecret)
|
||||||
|
|
||||||
|
// requires push permissions
|
||||||
|
repo.PATCH("", session.MustPush, server.PatchRepo)
|
||||||
|
repo.DELETE("", session.MustPush, server.DeleteRepo)
|
||||||
|
|
||||||
|
repo.POST("/builds/:number", session.MustPush, server.PostBuild)
|
||||||
|
repo.DELETE("/builds/:number/:job", session.MustPush, server.DeleteBuild)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
badges := e.Group("/api/badges/:owner/:name")
|
||||||
|
{
|
||||||
|
badges.GET("/status.svg", server.GetBadge)
|
||||||
|
badges.GET("/cc.xml", server.GetCC)
|
||||||
|
}
|
||||||
|
|
||||||
|
e.POST("/hook", server.PostHook)
|
||||||
|
e.POST("/api/hook", server.PostHook)
|
||||||
|
|
||||||
|
stream := e.Group("/api/stream")
|
||||||
|
{
|
||||||
|
stream.Use(session.SetRepo())
|
||||||
|
stream.Use(session.SetPerm())
|
||||||
|
stream.Use(session.MustPull)
|
||||||
|
|
||||||
|
stream.GET("/:owner/:name", server.GetRepoEvents)
|
||||||
|
stream.GET("/:owner/:name/:build/:number", server.GetStream)
|
||||||
|
}
|
||||||
|
|
||||||
|
auth := e.Group("/authorize")
|
||||||
|
{
|
||||||
|
auth.GET("", server.GetLogin)
|
||||||
|
auth.POST("", server.GetLogin)
|
||||||
|
auth.POST("/token", server.GetLoginToken)
|
||||||
|
}
|
||||||
|
|
||||||
|
queue := e.Group("/api/queue")
|
||||||
|
{
|
||||||
|
queue.Use(session.AuthorizeAgent)
|
||||||
|
queue.POST("/pull", server.Pull)
|
||||||
|
queue.POST("/pull/:os/:arch", server.Pull)
|
||||||
|
queue.POST("/wait/:id", server.Wait)
|
||||||
|
queue.POST("/stream/:id", server.Stream)
|
||||||
|
queue.POST("/status/:id", server.Update)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DELETE THESE
|
||||||
|
// gitlab := e.Group("/gitlab/:owner/:name")
|
||||||
|
// {
|
||||||
|
// gitlab.Use(session.SetRepo())
|
||||||
|
// gitlab.GET("/commits/:sha", GetCommit)
|
||||||
|
// gitlab.GET("/pulls/:number", GetPullRequest)
|
||||||
|
//
|
||||||
|
// redirects := gitlab.Group("/redirect")
|
||||||
|
// {
|
||||||
|
// redirects.GET("/commits/:sha", RedirectSha)
|
||||||
|
// redirects.GET("/pulls/:number", RedirectPullRequest)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// bots := e.Group("/bots")
|
||||||
|
// {
|
||||||
|
// bots.Use(session.MustUser())
|
||||||
|
// bots.POST("/slack", Slack)
|
||||||
|
// bots.POST("/slack/:command", Slack)
|
||||||
|
// }
|
||||||
|
|
||||||
|
return normalize(e)
|
||||||
|
}
|
||||||
|
|
||||||
|
// THIS HACK JOB IS GOING AWAY SOON.
|
||||||
//
|
//
|
||||||
// import (
|
// normalize is a helper function to work around the following
|
||||||
// "net/http"
|
// issue with gin. https://github.com/gin-gonic/gin/issues/388
|
||||||
// "strings"
|
func normalize(h http.Handler) http.Handler {
|
||||||
//
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
// "github.com/gin-gonic/gin"
|
|
||||||
//
|
parts := strings.Split(r.URL.Path, "/")[1:]
|
||||||
// "github.com/drone/drone/api"
|
switch parts[0] {
|
||||||
// "github.com/drone/drone/router/middleware"
|
case "settings", "bots", "repos", "api", "login", "logout", "", "authorize", "hook", "static", "gitlab":
|
||||||
// "github.com/drone/drone/router/middleware/header"
|
// no-op
|
||||||
// "github.com/drone/drone/router/middleware/session"
|
default:
|
||||||
// "github.com/drone/drone/router/middleware/token"
|
|
||||||
// "github.com/drone/drone/static"
|
if len(parts) > 2 && parts[2] != "settings" {
|
||||||
// "github.com/drone/drone/template"
|
parts = append(parts[:2], append([]string{"builds"}, parts[2:]...)...)
|
||||||
// "github.com/drone/drone/web"
|
}
|
||||||
// )
|
|
||||||
//
|
// prefix the URL with /repo so that it
|
||||||
// func Load(middlewares ...gin.HandlerFunc) http.Handler {
|
// can be effectively routed.
|
||||||
// e := gin.New()
|
parts = append([]string{"", "repos"}, parts...)
|
||||||
// e.Use(gin.Recovery())
|
|
||||||
//
|
// reconstruct the path
|
||||||
// e.SetHTMLTemplate(template.Load())
|
r.URL.Path = strings.Join(parts, "/")
|
||||||
// e.StaticFS("/static", static.FileSystem())
|
}
|
||||||
//
|
|
||||||
// e.Use(header.NoCache)
|
h.ServeHTTP(w, r)
|
||||||
// e.Use(header.Options)
|
})
|
||||||
// e.Use(header.Secure)
|
}
|
||||||
// e.Use(middlewares...)
|
|
||||||
// e.Use(session.SetUser())
|
|
||||||
// e.Use(token.Refresh)
|
|
||||||
//
|
|
||||||
// e.GET("/", web.ShowIndex)
|
|
||||||
// e.GET("/repos", web.ShowAllRepos)
|
|
||||||
// e.GET("/login", web.ShowLogin)
|
|
||||||
// e.GET("/login/form", web.ShowLoginForm)
|
|
||||||
// e.GET("/logout", web.GetLogout)
|
|
||||||
//
|
|
||||||
// settings := e.Group("/settings")
|
|
||||||
// {
|
|
||||||
// settings.Use(session.MustUser())
|
|
||||||
// settings.GET("/profile", web.ShowUser)
|
|
||||||
// }
|
|
||||||
// repo := e.Group("/repos/:owner/:name")
|
|
||||||
// {
|
|
||||||
// repo.Use(session.SetRepo())
|
|
||||||
// repo.Use(session.SetPerm())
|
|
||||||
// repo.Use(session.MustPull)
|
|
||||||
//
|
|
||||||
// repo.GET("", web.ShowRepo)
|
|
||||||
// repo.GET("/builds/:number", web.ShowBuild)
|
|
||||||
// repo.GET("/builds/:number/:job", web.ShowBuild)
|
|
||||||
//
|
|
||||||
// repo_settings := repo.Group("/settings")
|
|
||||||
// {
|
|
||||||
// repo_settings.GET("", session.MustPush, web.ShowRepoConf)
|
|
||||||
// repo_settings.GET("/encrypt", session.MustPush, web.ShowRepoEncrypt)
|
|
||||||
// repo_settings.GET("/badges", web.ShowRepoBadges)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// user := e.Group("/api/user")
|
|
||||||
// {
|
|
||||||
// user.Use(session.MustUser())
|
|
||||||
// user.GET("", api.GetSelf)
|
|
||||||
// user.GET("/feed", api.GetFeed)
|
|
||||||
// user.GET("/repos", api.GetRepos)
|
|
||||||
// user.GET("/repos/remote", api.GetRemoteRepos)
|
|
||||||
// user.POST("/token", api.PostToken)
|
|
||||||
// user.DELETE("/token", api.DeleteToken)
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// users := e.Group("/api/users")
|
|
||||||
// {
|
|
||||||
// users.Use(session.MustAdmin())
|
|
||||||
// users.GET("", api.GetUsers)
|
|
||||||
// users.POST("", api.PostUser)
|
|
||||||
// users.GET("/:login", api.GetUser)
|
|
||||||
// users.PATCH("/:login", api.PatchUser)
|
|
||||||
// users.DELETE("/:login", api.DeleteUser)
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// repos := e.Group("/api/repos/:owner/:name")
|
|
||||||
// {
|
|
||||||
// repos.POST("", api.PostRepo)
|
|
||||||
//
|
|
||||||
// repo := repos.Group("")
|
|
||||||
// {
|
|
||||||
// repo.Use(session.SetRepo())
|
|
||||||
// repo.Use(session.SetPerm())
|
|
||||||
// repo.Use(session.MustPull)
|
|
||||||
//
|
|
||||||
// repo.GET("", api.GetRepo)
|
|
||||||
// repo.GET("/key", api.GetRepoKey)
|
|
||||||
// repo.POST("/key", api.PostRepoKey)
|
|
||||||
// repo.GET("/builds", api.GetBuilds)
|
|
||||||
// repo.GET("/builds/:number", api.GetBuild)
|
|
||||||
// repo.GET("/logs/:number/:job", api.GetBuildLogs)
|
|
||||||
// repo.POST("/sign", session.MustPush, api.Sign)
|
|
||||||
//
|
|
||||||
// repo.POST("/secrets", session.MustPush, api.PostSecret)
|
|
||||||
// repo.DELETE("/secrets/:secret", session.MustPush, api.DeleteSecret)
|
|
||||||
//
|
|
||||||
// // requires authenticated user
|
|
||||||
// repo.POST("/encrypt", session.MustUser(), api.PostSecure)
|
|
||||||
//
|
|
||||||
// // requires push permissions
|
|
||||||
// repo.PATCH("", session.MustPush, api.PatchRepo)
|
|
||||||
// repo.DELETE("", session.MustPush, api.DeleteRepo)
|
|
||||||
//
|
|
||||||
// repo.POST("/builds/:number", session.MustPush, api.PostBuild)
|
|
||||||
// repo.DELETE("/builds/:number/:job", session.MustPush, api.DeleteBuild)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// badges := e.Group("/api/badges/:owner/:name")
|
|
||||||
// {
|
|
||||||
// badges.GET("/status.svg", web.GetBadge)
|
|
||||||
// badges.GET("/cc.xml", web.GetCC)
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// e.POST("/hook", web.PostHook)
|
|
||||||
// e.POST("/api/hook", web.PostHook)
|
|
||||||
//
|
|
||||||
// stream := e.Group("/api/stream")
|
|
||||||
// {
|
|
||||||
// stream.Use(session.SetRepo())
|
|
||||||
// stream.Use(session.SetPerm())
|
|
||||||
// stream.Use(session.MustPull)
|
|
||||||
//
|
|
||||||
// stream.GET("/:owner/:name", web.GetRepoEvents)
|
|
||||||
// stream.GET("/:owner/:name/:build/:number", web.GetStream)
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// bots := e.Group("/bots")
|
|
||||||
// {
|
|
||||||
// bots.Use(session.MustUser())
|
|
||||||
// bots.POST("/slack", web.Slack)
|
|
||||||
// bots.POST("/slack/:command", web.Slack)
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// auth := e.Group("/authorize")
|
|
||||||
// {
|
|
||||||
// auth.GET("", web.GetLogin)
|
|
||||||
// auth.POST("", web.GetLogin)
|
|
||||||
// auth.POST("/token", web.GetLoginToken)
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// queue := e.Group("/api/queue")
|
|
||||||
// {
|
|
||||||
// queue.Use(middleware.AgentMust())
|
|
||||||
// queue.POST("/pull", api.Pull)
|
|
||||||
// queue.POST("/pull/:os/:arch", api.Pull)
|
|
||||||
// queue.POST("/wait/:id", api.Wait)
|
|
||||||
// queue.POST("/stream/:id", api.Stream)
|
|
||||||
// queue.POST("/status/:id", api.Update)
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// gitlab := e.Group("/gitlab/:owner/:name")
|
|
||||||
// {
|
|
||||||
// gitlab.Use(session.SetRepo())
|
|
||||||
// gitlab.GET("/commits/:sha", web.GetCommit)
|
|
||||||
// gitlab.GET("/pulls/:number", web.GetPullRequest)
|
|
||||||
//
|
|
||||||
// redirects := gitlab.Group("/redirect")
|
|
||||||
// {
|
|
||||||
// redirects.GET("/commits/:sha", web.RedirectSha)
|
|
||||||
// redirects.GET("/pulls/:number", web.RedirectPullRequest)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// return normalize(e)
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// // normalize is a helper function to work around the following
|
|
||||||
// // issue with gin. https://github.com/gin-gonic/gin/issues/388
|
|
||||||
// func normalize(h http.Handler) http.Handler {
|
|
||||||
// return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
//
|
|
||||||
// parts := strings.Split(r.URL.Path, "/")[1:]
|
|
||||||
// switch parts[0] {
|
|
||||||
// case "settings", "bots", "repos", "api", "login", "logout", "", "authorize", "hook", "static", "gitlab":
|
|
||||||
// // no-op
|
|
||||||
// default:
|
|
||||||
//
|
|
||||||
// if len(parts) > 2 && parts[2] != "settings" {
|
|
||||||
// parts = append(parts[:2], append([]string{"builds"}, parts[2:]...)...)
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// // prefix the URL with /repo so that it
|
|
||||||
// // can be effectively routed.
|
|
||||||
// parts = append([]string{"", "repos"}, parts...)
|
|
||||||
//
|
|
||||||
// // reconstruct the path
|
|
||||||
// r.URL.Path = strings.Join(parts, "/")
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// h.ServeHTTP(w, r)
|
|
||||||
// })
|
|
||||||
// }
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package web
|
package server
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
|
@ -1,10 +1,8 @@
|
||||||
package api
|
package server
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -21,18 +19,6 @@ import (
|
||||||
"github.com/drone/drone/router/middleware/session"
|
"github.com/drone/drone/router/middleware/session"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
|
||||||
droneYml = os.Getenv("BUILD_CONFIG_FILE")
|
|
||||||
droneSec string
|
|
||||||
)
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
if droneYml == "" {
|
|
||||||
droneYml = ".drone.yml"
|
|
||||||
}
|
|
||||||
droneSec = fmt.Sprintf("%s.sig", droneYml)
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetBuilds(c *gin.Context) {
|
func GetBuilds(c *gin.Context) {
|
||||||
repo := session.Repo(c)
|
repo := session.Repo(c)
|
||||||
builds, err := store.GetBuildList(c, repo)
|
builds, err := store.GetBuildList(c, repo)
|
||||||
|
@ -189,7 +175,8 @@ func PostBuild(c *gin.Context) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// fetch the .drone.yml file from the database
|
// fetch the .drone.yml file from the database
|
||||||
raw, err := remote_.File(user, repo, build, droneYml)
|
config := ToConfig(c)
|
||||||
|
raw, err := remote_.File(user, repo, build, config.Yaml)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("failure to get build config for %s. %s", repo.FullName, err)
|
log.Errorf("failure to get build config for %s. %s", repo.FullName, err)
|
||||||
c.AbortWithError(404, err)
|
c.AbortWithError(404, err)
|
||||||
|
@ -197,7 +184,7 @@ func PostBuild(c *gin.Context) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fetch secrets file but don't exit on error as it's optional
|
// Fetch secrets file but don't exit on error as it's optional
|
||||||
sec, err := remote_.File(user, repo, build, droneSec)
|
sec, err := remote_.File(user, repo, build, config.Shasum)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debugf("cannot find build secrets for %s. %s", repo.FullName, err)
|
log.Debugf("cannot find build secrets for %s. %s", repo.FullName, err)
|
||||||
}
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package web
|
package server
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
|
@ -1,85 +0,0 @@
|
||||||
package server
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/drone/drone/bus"
|
|
||||||
"github.com/drone/drone/cache"
|
|
||||||
"github.com/drone/drone/queue"
|
|
||||||
"github.com/drone/drone/remote"
|
|
||||||
"github.com/drone/drone/store"
|
|
||||||
"github.com/drone/drone/stream"
|
|
||||||
"github.com/drone/drone/version"
|
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
|
||||||
)
|
|
||||||
|
|
||||||
// HandlerCache returns a HandlerFunc that passes a Cache to the Context.
|
|
||||||
func HandlerCache(v cache.Cache) gin.HandlerFunc {
|
|
||||||
return func(c *gin.Context) {
|
|
||||||
cache.ToContext(c, v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// HandlerBus returns a HandlerFunc that passes a Bus to the Context.
|
|
||||||
func HandlerBus(v bus.Bus) gin.HandlerFunc {
|
|
||||||
return func(c *gin.Context) {
|
|
||||||
bus.ToContext(c, v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// HandlerStore returns a HandlerFunc that passes a Store to the Context.
|
|
||||||
func HandlerStore(v store.Store) gin.HandlerFunc {
|
|
||||||
return func(c *gin.Context) {
|
|
||||||
store.ToContext(c, v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// HandlerQueue returns a HandlerFunc that passes a Queue to the Context.
|
|
||||||
func HandlerQueue(v queue.Queue) gin.HandlerFunc {
|
|
||||||
return func(c *gin.Context) {
|
|
||||||
queue.ToContext(c, v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// HandlerStream returns a HandlerFunc that passes a Stream to the Context.
|
|
||||||
func HandlerStream(v stream.Stream) gin.HandlerFunc {
|
|
||||||
return func(c *gin.Context) {
|
|
||||||
stream.ToContext(c, v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// HandlerRemote returns a HandlerFunc that passes a Remote to the Context.
|
|
||||||
func HandlerRemote(v remote.Remote) gin.HandlerFunc {
|
|
||||||
return func(c *gin.Context) {
|
|
||||||
remote.ToContext(c, v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// HandlerConfig returns a HandlerFunc that passes server Config to the Context.
|
|
||||||
func HandlerConfig(v *Config) gin.HandlerFunc {
|
|
||||||
const k = "config"
|
|
||||||
return func(c *gin.Context) {
|
|
||||||
c.Set(k, v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// HandlerVersion returns a HandlerFunc that writes the Version information to
|
|
||||||
// the http.Response as a the X-Drone-Version header.
|
|
||||||
func HandlerVersion() gin.HandlerFunc {
|
|
||||||
return func(c *gin.Context) {
|
|
||||||
c.Header("X-Drone-Version", version.Version)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// HandlerAgent returns a HandlerFunc that passes an Agent token to the Context.
|
|
||||||
func HandlerAgent(v string) gin.HandlerFunc {
|
|
||||||
const k = "agent"
|
|
||||||
return func(c *gin.Context) {
|
|
||||||
c.Set(k, v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ToConfig returns the config from the Context
|
|
||||||
func ToConfig(c *gin.Context) *Config {
|
|
||||||
v := c.MustGet("config")
|
|
||||||
return v.(*Config)
|
|
||||||
}
|
|
|
@ -1 +0,0 @@
|
||||||
package server
|
|
|
@ -1,8 +1,7 @@
|
||||||
package web
|
package server
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
|
||||||
"regexp"
|
"regexp"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
|
@ -19,18 +18,6 @@ import (
|
||||||
"github.com/drone/drone/yaml"
|
"github.com/drone/drone/yaml"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
|
||||||
droneYml = os.Getenv("BUILD_CONFIG_FILE")
|
|
||||||
droneSec string
|
|
||||||
)
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
if droneYml == "" {
|
|
||||||
droneYml = ".drone.yml"
|
|
||||||
}
|
|
||||||
droneSec = fmt.Sprintf("%s.sig", droneYml)
|
|
||||||
}
|
|
||||||
|
|
||||||
var skipRe = regexp.MustCompile(`\[(?i:ci *skip|skip *ci)\]`)
|
var skipRe = regexp.MustCompile(`\[(?i:ci *skip|skip *ci)\]`)
|
||||||
|
|
||||||
func PostHook(c *gin.Context) {
|
func PostHook(c *gin.Context) {
|
||||||
|
@ -135,13 +122,14 @@ func PostHook(c *gin.Context) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// fetch the build file from the database
|
// fetch the build file from the database
|
||||||
raw, err := remote_.File(user, repo, build, droneYml)
|
config := ToConfig(c)
|
||||||
|
raw, err := remote_.File(user, repo, build, config.Yaml)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("failure to get build config for %s. %s", repo.FullName, err)
|
log.Errorf("failure to get build config for %s. %s", repo.FullName, err)
|
||||||
c.AbortWithError(404, err)
|
c.AbortWithError(404, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
sec, err := remote_.File(user, repo, build, droneSec)
|
sec, err := remote_.File(user, repo, build, config.Shasum)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debugf("cannot find build secrets for %s. %s", repo.FullName, err)
|
log.Debugf("cannot find build secrets for %s. %s", repo.FullName, err)
|
||||||
// NOTE we don't exit on failure. The sec file is optional
|
// NOTE we don't exit on failure. The sec file is optional
|
|
@ -159,3 +159,9 @@ type tokenPayload struct {
|
||||||
Refresh string `json:"refresh_token,omitempty"`
|
Refresh string `json:"refresh_token,omitempty"`
|
||||||
Expires int64 `json:"expires_in,omitempty"`
|
Expires int64 `json:"expires_in,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ToConfig returns the config from the Context
|
||||||
|
func ToConfig(c *gin.Context) *model.Config {
|
||||||
|
v := c.MustGet("config")
|
||||||
|
return v.(*model.Config)
|
||||||
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package web
|
package server
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
|
@ -1,4 +1,4 @@
|
||||||
package api
|
package server
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
|
@ -1,4 +1,4 @@
|
||||||
package api
|
package server
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
|
@ -1,4 +1,4 @@
|
||||||
package api
|
package server
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/drone/drone/model"
|
"github.com/drone/drone/model"
|
241
server/server.go
241
server/server.go
|
@ -1,241 +0,0 @@
|
||||||
package server
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net/http"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/Sirupsen/logrus"
|
|
||||||
"github.com/drone/drone/api"
|
|
||||||
"github.com/drone/drone/bus"
|
|
||||||
"github.com/drone/drone/cache"
|
|
||||||
"github.com/drone/drone/queue"
|
|
||||||
"github.com/drone/drone/remote"
|
|
||||||
"github.com/drone/drone/router/middleware"
|
|
||||||
"github.com/drone/drone/router/middleware/header"
|
|
||||||
"github.com/drone/drone/router/middleware/session"
|
|
||||||
"github.com/drone/drone/router/middleware/token"
|
|
||||||
"github.com/drone/drone/static"
|
|
||||||
"github.com/drone/drone/store"
|
|
||||||
"github.com/drone/drone/stream"
|
|
||||||
"github.com/drone/drone/template"
|
|
||||||
"github.com/drone/drone/web"
|
|
||||||
|
|
||||||
"github.com/gin-gonic/contrib/ginrus"
|
|
||||||
"github.com/gin-gonic/gin"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Config defines system configuration parameters.
|
|
||||||
type Config struct {
|
|
||||||
Open bool // Enables open registration
|
|
||||||
Yaml string // Customize the Yaml configuration file name
|
|
||||||
Secret string // Secret token used to authenticate agents
|
|
||||||
Admins map[string]bool // Administrative users
|
|
||||||
Orgs map[string]bool // Organization whitelist
|
|
||||||
}
|
|
||||||
|
|
||||||
// Server defines the server configuration.
|
|
||||||
type Server struct {
|
|
||||||
Bus bus.Bus
|
|
||||||
Cache cache.Cache
|
|
||||||
Queue queue.Queue
|
|
||||||
Remote remote.Remote
|
|
||||||
Stream stream.Stream
|
|
||||||
Store store.Store
|
|
||||||
Config *Config
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handler returns an http.Handler for servering Drone requests.
|
|
||||||
func (s *Server) Handler() http.Handler {
|
|
||||||
|
|
||||||
e := gin.New()
|
|
||||||
e.Use(gin.Recovery())
|
|
||||||
|
|
||||||
e.SetHTMLTemplate(template.Load())
|
|
||||||
e.StaticFS("/static", static.FileSystem())
|
|
||||||
|
|
||||||
e.Use(header.NoCache)
|
|
||||||
e.Use(header.Options)
|
|
||||||
e.Use(header.Secure)
|
|
||||||
e.Use(
|
|
||||||
ginrus.Ginrus(logrus.StandardLogger(), time.RFC3339, true),
|
|
||||||
HandlerVersion(),
|
|
||||||
HandlerQueue(s.Queue),
|
|
||||||
HandlerStream(s.Stream),
|
|
||||||
HandlerBus(s.Bus),
|
|
||||||
HandlerCache(s.Cache),
|
|
||||||
HandlerStore(s.Store),
|
|
||||||
HandlerRemote(s.Remote),
|
|
||||||
HandlerConfig(s.Config),
|
|
||||||
)
|
|
||||||
e.Use(session.SetUser())
|
|
||||||
e.Use(token.Refresh)
|
|
||||||
|
|
||||||
e.GET("/", web.ShowIndex)
|
|
||||||
e.GET("/repos", web.ShowAllRepos)
|
|
||||||
e.GET("/login", web.ShowLogin)
|
|
||||||
e.GET("/login/form", web.ShowLoginForm)
|
|
||||||
e.GET("/logout", GetLogout)
|
|
||||||
|
|
||||||
// TODO below will Go away with React UI
|
|
||||||
settings := e.Group("/settings")
|
|
||||||
{
|
|
||||||
settings.Use(session.MustUser())
|
|
||||||
settings.GET("/profile", web.ShowUser)
|
|
||||||
}
|
|
||||||
repo := e.Group("/repos/:owner/:name")
|
|
||||||
{
|
|
||||||
repo.Use(session.SetRepo())
|
|
||||||
repo.Use(session.SetPerm())
|
|
||||||
repo.Use(session.MustPull)
|
|
||||||
|
|
||||||
repo.GET("", web.ShowRepo)
|
|
||||||
repo.GET("/builds/:number", web.ShowBuild)
|
|
||||||
repo.GET("/builds/:number/:job", web.ShowBuild)
|
|
||||||
|
|
||||||
repo_settings := repo.Group("/settings")
|
|
||||||
{
|
|
||||||
repo_settings.GET("", session.MustPush, web.ShowRepoConf)
|
|
||||||
repo_settings.GET("/encrypt", session.MustPush, web.ShowRepoEncrypt)
|
|
||||||
repo_settings.GET("/badges", web.ShowRepoBadges)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// TODO above will Go away with React UI
|
|
||||||
|
|
||||||
user := e.Group("/api/user")
|
|
||||||
{
|
|
||||||
user.Use(session.MustUser())
|
|
||||||
user.GET("", api.GetSelf)
|
|
||||||
user.GET("/feed", api.GetFeed)
|
|
||||||
user.GET("/repos", api.GetRepos)
|
|
||||||
user.GET("/repos/remote", api.GetRemoteRepos)
|
|
||||||
user.POST("/token", api.PostToken)
|
|
||||||
user.DELETE("/token", api.DeleteToken)
|
|
||||||
}
|
|
||||||
|
|
||||||
users := e.Group("/api/users")
|
|
||||||
{
|
|
||||||
users.Use(session.MustAdmin())
|
|
||||||
users.GET("", api.GetUsers)
|
|
||||||
users.POST("", api.PostUser)
|
|
||||||
users.GET("/:login", api.GetUser)
|
|
||||||
users.PATCH("/:login", api.PatchUser)
|
|
||||||
users.DELETE("/:login", api.DeleteUser)
|
|
||||||
}
|
|
||||||
|
|
||||||
repos := e.Group("/api/repos/:owner/:name")
|
|
||||||
{
|
|
||||||
repos.POST("", api.PostRepo)
|
|
||||||
|
|
||||||
repo := repos.Group("")
|
|
||||||
{
|
|
||||||
repo.Use(session.SetRepo())
|
|
||||||
repo.Use(session.SetPerm())
|
|
||||||
repo.Use(session.MustPull)
|
|
||||||
|
|
||||||
repo.GET("", api.GetRepo)
|
|
||||||
repo.GET("/builds", api.GetBuilds)
|
|
||||||
repo.GET("/builds/:number", api.GetBuild)
|
|
||||||
repo.GET("/logs/:number/:job", api.GetBuildLogs)
|
|
||||||
repo.POST("/sign", session.MustPush, api.Sign)
|
|
||||||
|
|
||||||
repo.POST("/secrets", session.MustPush, api.PostSecret)
|
|
||||||
repo.DELETE("/secrets/:secret", session.MustPush, api.DeleteSecret)
|
|
||||||
|
|
||||||
// requires push permissions
|
|
||||||
repo.PATCH("", session.MustPush, api.PatchRepo)
|
|
||||||
repo.DELETE("", session.MustPush, api.DeleteRepo)
|
|
||||||
|
|
||||||
repo.POST("/builds/:number", session.MustPush, api.PostBuild)
|
|
||||||
repo.DELETE("/builds/:number/:job", session.MustPush, api.DeleteBuild)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
badges := e.Group("/api/badges/:owner/:name")
|
|
||||||
{
|
|
||||||
badges.GET("/status.svg", web.GetBadge)
|
|
||||||
badges.GET("/cc.xml", web.GetCC)
|
|
||||||
}
|
|
||||||
|
|
||||||
e.POST("/hook", web.PostHook)
|
|
||||||
e.POST("/api/hook", web.PostHook)
|
|
||||||
|
|
||||||
stream := e.Group("/api/stream")
|
|
||||||
{
|
|
||||||
stream.Use(session.SetRepo())
|
|
||||||
stream.Use(session.SetPerm())
|
|
||||||
stream.Use(session.MustPull)
|
|
||||||
|
|
||||||
stream.GET("/:owner/:name", web.GetRepoEvents)
|
|
||||||
stream.GET("/:owner/:name/:build/:number", web.GetStream)
|
|
||||||
}
|
|
||||||
|
|
||||||
auth := e.Group("/authorize")
|
|
||||||
{
|
|
||||||
auth.GET("", GetLogin)
|
|
||||||
auth.POST("", GetLogin)
|
|
||||||
auth.POST("/token", GetLoginToken)
|
|
||||||
}
|
|
||||||
|
|
||||||
queue := e.Group("/api/queue")
|
|
||||||
{
|
|
||||||
queue.Use(middleware.AgentMust())
|
|
||||||
queue.POST("/pull", api.Pull)
|
|
||||||
queue.POST("/pull/:os/:arch", api.Pull)
|
|
||||||
queue.POST("/wait/:id", api.Wait)
|
|
||||||
queue.POST("/stream/:id", api.Stream)
|
|
||||||
queue.POST("/status/:id", api.Update)
|
|
||||||
}
|
|
||||||
|
|
||||||
// DELETE THESE
|
|
||||||
// gitlab := e.Group("/gitlab/:owner/:name")
|
|
||||||
// {
|
|
||||||
// gitlab.Use(session.SetRepo())
|
|
||||||
// gitlab.GET("/commits/:sha", web.GetCommit)
|
|
||||||
// gitlab.GET("/pulls/:number", web.GetPullRequest)
|
|
||||||
//
|
|
||||||
// redirects := gitlab.Group("/redirect")
|
|
||||||
// {
|
|
||||||
// redirects.GET("/commits/:sha", web.RedirectSha)
|
|
||||||
// redirects.GET("/pulls/:number", web.RedirectPullRequest)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// bots := e.Group("/bots")
|
|
||||||
// {
|
|
||||||
// bots.Use(session.MustUser())
|
|
||||||
// bots.POST("/slack", web.Slack)
|
|
||||||
// bots.POST("/slack/:command", web.Slack)
|
|
||||||
// }
|
|
||||||
|
|
||||||
return normalize(e)
|
|
||||||
}
|
|
||||||
|
|
||||||
// THIS HACK JOB IS GOING AWAY SOON.
|
|
||||||
//
|
|
||||||
// normalize is a helper function to work around the following
|
|
||||||
// issue with gin. https://github.com/gin-gonic/gin/issues/388
|
|
||||||
func normalize(h http.Handler) http.Handler {
|
|
||||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
|
|
||||||
parts := strings.Split(r.URL.Path, "/")[1:]
|
|
||||||
switch parts[0] {
|
|
||||||
case "settings", "bots", "repos", "api", "login", "logout", "", "authorize", "hook", "static", "gitlab":
|
|
||||||
// no-op
|
|
||||||
default:
|
|
||||||
|
|
||||||
if len(parts) > 2 && parts[2] != "settings" {
|
|
||||||
parts = append(parts[:2], append([]string{"builds"}, parts[2:]...)...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// prefix the URL with /repo so that it
|
|
||||||
// can be effectively routed.
|
|
||||||
parts = append([]string{"", "repos"}, parts...)
|
|
||||||
|
|
||||||
// reconstruct the path
|
|
||||||
r.URL.Path = strings.Join(parts, "/")
|
|
||||||
}
|
|
||||||
|
|
||||||
h.ServeHTTP(w, r)
|
|
||||||
})
|
|
||||||
}
|
|
|
@ -1,4 +1,4 @@
|
||||||
package api
|
package server
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io/ioutil"
|
"io/ioutil"
|
|
@ -1,4 +1,4 @@
|
||||||
package web
|
package server
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"strings"
|
"strings"
|
|
@ -1,4 +1,4 @@
|
||||||
package web
|
package server
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
|
@ -11,6 +11,7 @@
|
||||||
// - application/json
|
// - application/json
|
||||||
//
|
//
|
||||||
// swagger:meta
|
// swagger:meta
|
||||||
package api
|
package swagger
|
||||||
|
|
||||||
//go:generate swagger generate spec -o swagger/files/swagger.json
|
//go:generate swagger generate spec -o files/swagger.json
|
||||||
|
//go:generate go-bindata -pkg swagger -o swagger_gen.go files/
|
85
server/swagger/swagger.go
Normal file
85
server/swagger/swagger.go
Normal file
|
@ -0,0 +1,85 @@
|
||||||
|
package swagger
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/drone/drone/model"
|
||||||
|
)
|
||||||
|
|
||||||
|
// swagger:route GET /users/{login} user getUser
|
||||||
|
//
|
||||||
|
// Get the user with the matching login.
|
||||||
|
//
|
||||||
|
// Responses:
|
||||||
|
// 200: user
|
||||||
|
//
|
||||||
|
func userFind(w http.ResponseWriter, r *http.Request) {}
|
||||||
|
|
||||||
|
// swagger:route GET /user user getCurrentUser
|
||||||
|
//
|
||||||
|
// Get the currently authenticated user.
|
||||||
|
//
|
||||||
|
// Responses:
|
||||||
|
// 200: user
|
||||||
|
//
|
||||||
|
func userCurrent(w http.ResponseWriter, r *http.Request) {}
|
||||||
|
|
||||||
|
// swagger:route GET /users user getUserList
|
||||||
|
//
|
||||||
|
// Get the list of all registered users.
|
||||||
|
//
|
||||||
|
// Responses:
|
||||||
|
// 200: user
|
||||||
|
//
|
||||||
|
func userList(w http.ResponseWriter, r *http.Request) {}
|
||||||
|
|
||||||
|
// swagger:route GET /user/feed user getUserFeed
|
||||||
|
//
|
||||||
|
// Get the currently authenticated user's build feed.
|
||||||
|
//
|
||||||
|
// Responses:
|
||||||
|
// 200: feed
|
||||||
|
//
|
||||||
|
func userFeed(w http.ResponseWriter, r *http.Request) {}
|
||||||
|
|
||||||
|
// swagger:route DELETE /users/{login} user deleteUserLogin
|
||||||
|
//
|
||||||
|
// Delete the user with the matching login.
|
||||||
|
//
|
||||||
|
// Responses:
|
||||||
|
// 200: user
|
||||||
|
//
|
||||||
|
func userDelete(w http.ResponseWriter, r *http.Request) {}
|
||||||
|
|
||||||
|
// swagger:route GET /user/repos user getUserRepos
|
||||||
|
//
|
||||||
|
// Get the currently authenticated user's active repository list.
|
||||||
|
//
|
||||||
|
// Responses:
|
||||||
|
// 200: repos
|
||||||
|
//
|
||||||
|
func repoList(w http.ResponseWriter, r *http.Request) {}
|
||||||
|
|
||||||
|
// swagger:response user
|
||||||
|
type userResp struct {
|
||||||
|
// in: body
|
||||||
|
Body model.User
|
||||||
|
}
|
||||||
|
|
||||||
|
// swagger:response users
|
||||||
|
type usersResp struct {
|
||||||
|
// in: body
|
||||||
|
Body []model.User
|
||||||
|
}
|
||||||
|
|
||||||
|
// swagger:response feed
|
||||||
|
type feedResp struct {
|
||||||
|
// in: body
|
||||||
|
Body []model.Feed
|
||||||
|
}
|
||||||
|
|
||||||
|
// swagger:response repos
|
||||||
|
type reposResp struct {
|
||||||
|
// in: body
|
||||||
|
Body []model.Repo
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package api
|
package server
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
@ -6,31 +6,16 @@ import (
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
|
|
||||||
"github.com/drone/drone/cache"
|
"github.com/drone/drone/cache"
|
||||||
"github.com/drone/drone/model"
|
|
||||||
"github.com/drone/drone/router/middleware/session"
|
"github.com/drone/drone/router/middleware/session"
|
||||||
"github.com/drone/drone/shared/crypto"
|
"github.com/drone/drone/shared/crypto"
|
||||||
"github.com/drone/drone/shared/token"
|
"github.com/drone/drone/shared/token"
|
||||||
"github.com/drone/drone/store"
|
"github.com/drone/drone/store"
|
||||||
)
|
)
|
||||||
|
|
||||||
// swagger:route GET /user user getUser
|
|
||||||
//
|
|
||||||
// Get the currently authenticated user.
|
|
||||||
//
|
|
||||||
// Responses:
|
|
||||||
// 200: user
|
|
||||||
//
|
|
||||||
func GetSelf(c *gin.Context) {
|
func GetSelf(c *gin.Context) {
|
||||||
c.JSON(200, session.User(c))
|
c.JSON(200, session.User(c))
|
||||||
}
|
}
|
||||||
|
|
||||||
// swagger:route GET /user/feed user getUserFeed
|
|
||||||
//
|
|
||||||
// Get the currently authenticated user's build feed.
|
|
||||||
//
|
|
||||||
// Responses:
|
|
||||||
// 200: feed
|
|
||||||
//
|
|
||||||
func GetFeed(c *gin.Context) {
|
func GetFeed(c *gin.Context) {
|
||||||
repos, err := cache.GetRepos(c, session.User(c))
|
repos, err := cache.GetRepos(c, session.User(c))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -46,13 +31,6 @@ func GetFeed(c *gin.Context) {
|
||||||
c.JSON(200, feed)
|
c.JSON(200, feed)
|
||||||
}
|
}
|
||||||
|
|
||||||
// swagger:route GET /user/repos user getUserRepos
|
|
||||||
//
|
|
||||||
// Get the currently authenticated user's active repository list.
|
|
||||||
//
|
|
||||||
// Responses:
|
|
||||||
// 200: repos
|
|
||||||
//
|
|
||||||
func GetRepos(c *gin.Context) {
|
func GetRepos(c *gin.Context) {
|
||||||
repos, err := cache.GetRepos(c, session.User(c))
|
repos, err := cache.GetRepos(c, session.User(c))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -105,27 +83,3 @@ func DeleteToken(c *gin.Context) {
|
||||||
}
|
}
|
||||||
c.String(http.StatusOK, tokenstr)
|
c.String(http.StatusOK, tokenstr)
|
||||||
}
|
}
|
||||||
|
|
||||||
// swagger:response user
|
|
||||||
type userResp struct {
|
|
||||||
// in: body
|
|
||||||
Body model.User
|
|
||||||
}
|
|
||||||
|
|
||||||
// swagger:response users
|
|
||||||
type usersResp struct {
|
|
||||||
// in: body
|
|
||||||
Body []model.User
|
|
||||||
}
|
|
||||||
|
|
||||||
// swagger:response feed
|
|
||||||
type feedResp struct {
|
|
||||||
// in: body
|
|
||||||
Body []model.Feed
|
|
||||||
}
|
|
||||||
|
|
||||||
// swagger:response repos
|
|
||||||
type reposResp struct {
|
|
||||||
// in: body
|
|
||||||
Body []model.Repo
|
|
||||||
}
|
|
|
@ -1,4 +1,4 @@
|
||||||
package api
|
package server
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
@ -10,13 +10,6 @@ import (
|
||||||
"github.com/drone/drone/store"
|
"github.com/drone/drone/store"
|
||||||
)
|
)
|
||||||
|
|
||||||
// swagger:route GET /users user getUserList
|
|
||||||
//
|
|
||||||
// Get the list of all registered users.
|
|
||||||
//
|
|
||||||
// Responses:
|
|
||||||
// 200: user
|
|
||||||
//
|
|
||||||
func GetUsers(c *gin.Context) {
|
func GetUsers(c *gin.Context) {
|
||||||
users, err := store.GetUserList(c)
|
users, err := store.GetUserList(c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -26,20 +19,13 @@ func GetUsers(c *gin.Context) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// swagger:route GET /users/{login} user getUserLogin
|
|
||||||
//
|
|
||||||
// Get the user with the matching login.
|
|
||||||
//
|
|
||||||
// Responses:
|
|
||||||
// 200: user
|
|
||||||
//
|
|
||||||
func GetUser(c *gin.Context) {
|
func GetUser(c *gin.Context) {
|
||||||
user, err := store.GetUserLogin(c, c.Param("login"))
|
user, err := store.GetUserLogin(c, c.Param("login"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.String(404, "Cannot find user. %s", err)
|
c.String(404, "Cannot find user. %s", err)
|
||||||
} else {
|
return
|
||||||
c.JSON(200, user)
|
|
||||||
}
|
}
|
||||||
|
c.JSON(200, user)
|
||||||
}
|
}
|
||||||
|
|
||||||
func PatchUser(c *gin.Context) {
|
func PatchUser(c *gin.Context) {
|
||||||
|
@ -74,31 +60,20 @@ func PostUser(c *gin.Context) {
|
||||||
c.String(http.StatusBadRequest, err.Error())
|
c.String(http.StatusBadRequest, err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
user := &model.User{
|
||||||
user := &model.User{}
|
Active: true,
|
||||||
user.Login = in.Login
|
Login: in.Login,
|
||||||
user.Email = in.Email
|
Email: in.Email,
|
||||||
user.Admin = in.Admin
|
Avatar: in.Avatar,
|
||||||
user.Avatar = in.Avatar
|
Hash: crypto.Rand(),
|
||||||
user.Active = true
|
}
|
||||||
user.Hash = crypto.Rand()
|
if err = store.CreateUser(c, user); err != nil {
|
||||||
|
|
||||||
err = store.CreateUser(c, user)
|
|
||||||
if err != nil {
|
|
||||||
c.String(http.StatusInternalServerError, err.Error())
|
c.String(http.StatusInternalServerError, err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
c.JSON(http.StatusOK, user)
|
c.JSON(http.StatusOK, user)
|
||||||
}
|
}
|
||||||
|
|
||||||
// swagger:route DELETE /users/{login} user deleteUserLogin
|
|
||||||
//
|
|
||||||
// Delete the user with the matching login.
|
|
||||||
//
|
|
||||||
// Responses:
|
|
||||||
// 200: user
|
|
||||||
//
|
|
||||||
func DeleteUser(c *gin.Context) {
|
func DeleteUser(c *gin.Context) {
|
||||||
user, err := store.GetUserLogin(c, c.Param("login"))
|
user, err := store.GetUserLogin(c, c.Param("login"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -107,7 +82,7 @@ func DeleteUser(c *gin.Context) {
|
||||||
}
|
}
|
||||||
if err = store.DeleteUser(c, user); err != nil {
|
if err = store.DeleteUser(c, user); err != nil {
|
||||||
c.String(500, "Error deleting user. %s", err)
|
c.String(500, "Error deleting user. %s", err)
|
||||||
} else {
|
return
|
||||||
c.String(200, "")
|
|
||||||
}
|
}
|
||||||
|
c.String(200, "")
|
||||||
}
|
}
|
|
@ -1,97 +0,0 @@
|
||||||
package docker
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
|
|
||||||
log "github.com/Sirupsen/logrus"
|
|
||||||
"github.com/samalba/dockerclient"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
LogOpts = &dockerclient.LogOptions{
|
|
||||||
Stdout: true,
|
|
||||||
Stderr: true,
|
|
||||||
}
|
|
||||||
|
|
||||||
LogOptsTail = &dockerclient.LogOptions{
|
|
||||||
Follow: true,
|
|
||||||
Stdout: true,
|
|
||||||
Stderr: true,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
// Run creates the docker container, pulling images if necessary, starts
|
|
||||||
// the container and blocks until the container exits, returning the exit
|
|
||||||
// information.
|
|
||||||
func Run(client dockerclient.Client, conf *dockerclient.ContainerConfig, name string) (*dockerclient.ContainerInfo, error) {
|
|
||||||
info, err := RunDaemon(client, conf, name)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return Wait(client, info.Id)
|
|
||||||
}
|
|
||||||
|
|
||||||
// RunDaemon creates the docker container, pulling images if necessary, starts
|
|
||||||
// the container and returns the container information. It does not wait for
|
|
||||||
// the container to exit.
|
|
||||||
func RunDaemon(client dockerclient.Client, conf *dockerclient.ContainerConfig, name string) (*dockerclient.ContainerInfo, error) {
|
|
||||||
|
|
||||||
// attempts to create the container
|
|
||||||
id, err := client.CreateContainer(conf, name, nil)
|
|
||||||
if err != nil {
|
|
||||||
// and pull the image and re-create if that fails
|
|
||||||
err = client.PullImage(conf.Image, nil)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
id, err = client.CreateContainer(conf, name, nil)
|
|
||||||
if err != nil {
|
|
||||||
client.RemoveContainer(id, true, true)
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// fetches the container information
|
|
||||||
info, err := client.InspectContainer(id)
|
|
||||||
if err != nil {
|
|
||||||
client.RemoveContainer(id, true, true)
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// starts the container
|
|
||||||
err = client.StartContainer(id, &conf.HostConfig)
|
|
||||||
if err != nil {
|
|
||||||
client.RemoveContainer(id, true, true)
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return info, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Wait blocks until the named container exits, returning the exit information.
|
|
||||||
func Wait(client dockerclient.Client, name string) (*dockerclient.ContainerInfo, error) {
|
|
||||||
|
|
||||||
defer func() {
|
|
||||||
client.StopContainer(name, 5)
|
|
||||||
client.KillContainer(name, "9")
|
|
||||||
}()
|
|
||||||
|
|
||||||
for attempts := 0; attempts < 5; attempts++ {
|
|
||||||
done := client.Wait(name)
|
|
||||||
<-done
|
|
||||||
|
|
||||||
info, err := client.InspectContainer(name)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if !info.State.Running {
|
|
||||||
return info, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Debugf("attempting to resume waiting after %d attempts.\n", attempts)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil, errors.New("reached maximum wait attempts")
|
|
||||||
}
|
|
149
web/login.go
149
web/login.go
|
@ -1,149 +0,0 @@
|
||||||
package web
|
|
||||||
|
|
||||||
//
|
|
||||||
// import (
|
|
||||||
// "net/http"
|
|
||||||
// "time"
|
|
||||||
//
|
|
||||||
// "github.com/drone/drone/model"
|
|
||||||
// "github.com/drone/drone/remote"
|
|
||||||
// "github.com/drone/drone/shared/crypto"
|
|
||||||
// "github.com/drone/drone/shared/httputil"
|
|
||||||
// "github.com/drone/drone/shared/token"
|
|
||||||
// "github.com/drone/drone/store"
|
|
||||||
//
|
|
||||||
// "github.com/Sirupsen/logrus"
|
|
||||||
// "github.com/gin-gonic/gin"
|
|
||||||
// )
|
|
||||||
//
|
|
||||||
// func GetLogin(c *gin.Context) {
|
|
||||||
// remote := remote.FromContext(c)
|
|
||||||
//
|
|
||||||
// // when dealing with redirects we may need
|
|
||||||
// // to adjust the content type. I cannot, however,
|
|
||||||
// // remember why, so need to revisit this line.
|
|
||||||
// c.Writer.Header().Del("Content-Type")
|
|
||||||
//
|
|
||||||
// tmpuser, err := remote.Login(c.Writer, c.Request)
|
|
||||||
// if err != nil {
|
|
||||||
// logrus.Errorf("cannot authenticate user. %s", err)
|
|
||||||
// c.Redirect(303, "/login?error=oauth_error")
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
// // this will happen when the user is redirected by
|
|
||||||
// // the remote provide as part of the oauth dance.
|
|
||||||
// if tmpuser == nil {
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// var open = false // TODO get this from context
|
|
||||||
//
|
|
||||||
// // get the user from the database
|
|
||||||
// u, err := store.GetUserLogin(c, tmpuser.Login)
|
|
||||||
// if err != nil {
|
|
||||||
//
|
|
||||||
// // if self-registration is disabled we should
|
|
||||||
// // return a notAuthorized error. the only exception
|
|
||||||
// // is if no users exist yet in the system we'll proceed.
|
|
||||||
// if !open {
|
|
||||||
// logrus.Errorf("cannot register %s. registration closed", tmpuser.Login)
|
|
||||||
// c.Redirect(303, "/login?error=access_denied")
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// // create the user account
|
|
||||||
// u = &model.User{}
|
|
||||||
// u.Login = tmpuser.Login
|
|
||||||
// u.Token = tmpuser.Token
|
|
||||||
// u.Secret = tmpuser.Secret
|
|
||||||
// u.Email = tmpuser.Email
|
|
||||||
// u.Avatar = tmpuser.Avatar
|
|
||||||
// u.Hash = crypto.Rand()
|
|
||||||
//
|
|
||||||
// // insert the user into the database
|
|
||||||
// if err := store.CreateUser(c, u); err != nil {
|
|
||||||
// logrus.Errorf("cannot insert %s. %s", u.Login, err)
|
|
||||||
// c.Redirect(303, "/login?error=internal_error")
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// // update the user meta data and authorization
|
|
||||||
// // data and cache in the datastore.
|
|
||||||
// u.Token = tmpuser.Token
|
|
||||||
// u.Secret = tmpuser.Secret
|
|
||||||
// u.Email = tmpuser.Email
|
|
||||||
// u.Avatar = tmpuser.Avatar
|
|
||||||
//
|
|
||||||
// if err := store.UpdateUser(c, u); err != nil {
|
|
||||||
// logrus.Errorf("cannot update %s. %s", u.Login, err)
|
|
||||||
// c.Redirect(303, "/login?error=internal_error")
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// exp := time.Now().Add(time.Hour * 72).Unix()
|
|
||||||
// token := token.New(token.SessToken, u.Login)
|
|
||||||
// tokenstr, err := token.SignExpires(u.Hash, exp)
|
|
||||||
// if err != nil {
|
|
||||||
// logrus.Errorf("cannot create token for %s. %s", u.Login, err)
|
|
||||||
// c.Redirect(303, "/login?error=internal_error")
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// httputil.SetCookie(c.Writer, c.Request, "user_sess", tokenstr)
|
|
||||||
// redirect := httputil.GetCookie(c.Request, "user_last")
|
|
||||||
// if len(redirect) == 0 {
|
|
||||||
// redirect = "/"
|
|
||||||
// }
|
|
||||||
// c.Redirect(303, redirect)
|
|
||||||
//
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// func GetLogout(c *gin.Context) {
|
|
||||||
//
|
|
||||||
// httputil.DelCookie(c.Writer, c.Request, "user_sess")
|
|
||||||
// httputil.DelCookie(c.Writer, c.Request, "user_last")
|
|
||||||
// c.Redirect(303, "/login")
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// func GetLoginToken(c *gin.Context) {
|
|
||||||
// remote := remote.FromContext(c)
|
|
||||||
//
|
|
||||||
// in := &tokenPayload{}
|
|
||||||
// err := c.Bind(in)
|
|
||||||
// if err != nil {
|
|
||||||
// c.AbortWithError(http.StatusBadRequest, err)
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// login, err := remote.Auth(in.Access, in.Refresh)
|
|
||||||
// if err != nil {
|
|
||||||
// c.AbortWithError(http.StatusUnauthorized, err)
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// user, err := store.GetUserLogin(c, login)
|
|
||||||
// if err != nil {
|
|
||||||
// c.AbortWithError(http.StatusNotFound, err)
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// exp := time.Now().Add(time.Hour * 72).Unix()
|
|
||||||
// token := token.New(token.SessToken, user.Login)
|
|
||||||
// tokenstr, err := token.SignExpires(user.Hash, exp)
|
|
||||||
// if err != nil {
|
|
||||||
// c.AbortWithError(http.StatusInternalServerError, err)
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// c.IndentedJSON(http.StatusOK, &tokenPayload{
|
|
||||||
// Access: tokenstr,
|
|
||||||
// Expires: exp - time.Now().Unix(),
|
|
||||||
// })
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// type tokenPayload struct {
|
|
||||||
// Access string `json:"access_token,omitempty"`
|
|
||||||
// Refresh string `json:"refresh_token,omitempty"`
|
|
||||||
// Expires int64 `json:"expires_in,omitempty"`
|
|
||||||
// }
|
|
|
@ -1,70 +0,0 @@
|
||||||
package checksum
|
|
||||||
|
|
||||||
import (
|
|
||||||
"crypto/sha1"
|
|
||||||
"crypto/sha256"
|
|
||||||
"crypto/sha512"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Check is a calculates and verifies a file checksum. This supports the sha1,
|
|
||||||
// sha256 and sha512 values.
|
|
||||||
func Check(in, checksum string) bool {
|
|
||||||
hash, size, _ := split(checksum)
|
|
||||||
|
|
||||||
// if a byte size is provided for the
|
|
||||||
// Yaml file it must match.
|
|
||||||
if size > 0 && int64(len(in)) != size {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
switch len(hash) {
|
|
||||||
case 64:
|
|
||||||
return sha256sum(in) == hash
|
|
||||||
case 128:
|
|
||||||
return sha512sum(in) == hash
|
|
||||||
case 40:
|
|
||||||
return sha1sum(in) == hash
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func sha1sum(in string) string {
|
|
||||||
h := sha1.New()
|
|
||||||
io.WriteString(h, in)
|
|
||||||
return fmt.Sprintf("%x", h.Sum(nil))
|
|
||||||
}
|
|
||||||
|
|
||||||
func sha256sum(in string) string {
|
|
||||||
h := sha256.New()
|
|
||||||
io.WriteString(h, in)
|
|
||||||
return fmt.Sprintf("%x", h.Sum(nil))
|
|
||||||
}
|
|
||||||
|
|
||||||
func sha512sum(in string) string {
|
|
||||||
h := sha512.New()
|
|
||||||
io.WriteString(h, in)
|
|
||||||
return fmt.Sprintf("%x", h.Sum(nil))
|
|
||||||
}
|
|
||||||
|
|
||||||
func split(in string) (string, int64, string) {
|
|
||||||
var hash string
|
|
||||||
var name string
|
|
||||||
var size int64
|
|
||||||
|
|
||||||
// the checksum might be split into multiple
|
|
||||||
// sections including the file size and name.
|
|
||||||
switch strings.Count(in, " ") {
|
|
||||||
case 1:
|
|
||||||
fmt.Sscanf(in, "%s %s", &hash, &name)
|
|
||||||
case 2:
|
|
||||||
fmt.Sscanf(in, "%s %d %s", &hash, &size, &name)
|
|
||||||
default:
|
|
||||||
hash = in
|
|
||||||
}
|
|
||||||
|
|
||||||
return hash, size, name
|
|
||||||
}
|
|
|
@ -1,97 +0,0 @@
|
||||||
package checksum
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/franela/goblin"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestParse(t *testing.T) {
|
|
||||||
|
|
||||||
g := goblin.Goblin(t)
|
|
||||||
g.Describe("Shasum", func() {
|
|
||||||
|
|
||||||
g.It("Should parse the shasum string", func() {
|
|
||||||
hash, _, _ := split("f1d2d2f924e986ac86fdf7b36c94bcdf32beec15")
|
|
||||||
g.Assert(hash).Equal("f1d2d2f924e986ac86fdf7b36c94bcdf32beec15")
|
|
||||||
})
|
|
||||||
|
|
||||||
g.It("Should parse a two-part shasum string", func() {
|
|
||||||
hash, _, name := split("f1d2d2f924e986ac86fdf7b36c94bcdf32beec15 .drone.yml")
|
|
||||||
g.Assert(hash).Equal("f1d2d2f924e986ac86fdf7b36c94bcdf32beec15")
|
|
||||||
g.Assert(name).Equal(".drone.yml")
|
|
||||||
})
|
|
||||||
|
|
||||||
g.It("Should parse a three-part shasum string", func() {
|
|
||||||
hash, size, name := split("f1d2d2f924e986ac86fdf7b36c94bcdf32beec15 42 .drone.yml")
|
|
||||||
g.Assert(hash).Equal("f1d2d2f924e986ac86fdf7b36c94bcdf32beec15")
|
|
||||||
g.Assert(name).Equal(".drone.yml")
|
|
||||||
g.Assert(size).Equal(int64(42))
|
|
||||||
})
|
|
||||||
|
|
||||||
g.It("Should calc a sha1 sum", func() {
|
|
||||||
hash := sha1sum("foo\n")
|
|
||||||
g.Assert(hash).Equal("f1d2d2f924e986ac86fdf7b36c94bcdf32beec15")
|
|
||||||
})
|
|
||||||
|
|
||||||
g.It("Should calc a sha256 sum", func() {
|
|
||||||
hash := sha256sum("foo\n")
|
|
||||||
g.Assert(hash).Equal("b5bb9d8014a0f9b1d61e21e796d78dccdf1352f23cd32812f4850b878ae4944c")
|
|
||||||
})
|
|
||||||
|
|
||||||
g.It("Should calc a sha512 sum", func() {
|
|
||||||
hash := sha512sum("foo\n")
|
|
||||||
g.Assert(hash).Equal("0cf9180a764aba863a67b6d72f0918bc131c6772642cb2dce5a34f0a702f9470ddc2bf125c12198b1995c233c34b4afd346c54a2334c350a948a51b6e8b4e6b6")
|
|
||||||
})
|
|
||||||
|
|
||||||
g.It("Should calc a sha1 sum", func() {
|
|
||||||
hash := sha1sum("foo\n")
|
|
||||||
g.Assert(hash).Equal("f1d2d2f924e986ac86fdf7b36c94bcdf32beec15")
|
|
||||||
})
|
|
||||||
|
|
||||||
g.It("Should validate sha1 sum with file size", func() {
|
|
||||||
ok := Check("foo\n", "f1d2d2f924e986ac86fdf7b36c94bcdf32beec15 4 -")
|
|
||||||
g.Assert(ok).IsTrue()
|
|
||||||
})
|
|
||||||
|
|
||||||
g.It("Should validate sha256 sum with file size", func() {
|
|
||||||
ok := Check("foo\n", "b5bb9d8014a0f9b1d61e21e796d78dccdf1352f23cd32812f4850b878ae4944c 4 -")
|
|
||||||
g.Assert(ok).IsTrue()
|
|
||||||
})
|
|
||||||
|
|
||||||
g.It("Should validate sha512 sum with file size", func() {
|
|
||||||
ok := Check("foo\n", "0cf9180a764aba863a67b6d72f0918bc131c6772642cb2dce5a34f0a702f9470ddc2bf125c12198b1995c233c34b4afd346c54a2334c350a948a51b6e8b4e6b6 4 -")
|
|
||||||
g.Assert(ok).IsTrue()
|
|
||||||
})
|
|
||||||
|
|
||||||
g.It("Should fail validation if incorrect sha1", func() {
|
|
||||||
ok := Check("bar\n", "f1d2d2f924e986ac86fdf7b36c94bcdf32beec15 4 -")
|
|
||||||
g.Assert(ok).IsFalse()
|
|
||||||
})
|
|
||||||
|
|
||||||
g.It("Should fail validation if incorrect sha256", func() {
|
|
||||||
ok := Check("bar\n", "b5bb9d8014a0f9b1d61e21e796d78dccdf1352f23cd32812f4850b878ae4944c 4 -")
|
|
||||||
g.Assert(ok).IsFalse()
|
|
||||||
})
|
|
||||||
|
|
||||||
g.It("Should fail validation if incorrect sha512", func() {
|
|
||||||
ok := Check("bar\n", "0cf9180a764aba863a67b6d72f0918bc131c6772642cb2dce5a34f0a702f9470ddc2bf125c12198b1995c233c34b4afd346c54a2334c350a948a51b6e8b4e6b6 4 -")
|
|
||||||
g.Assert(ok).IsFalse()
|
|
||||||
})
|
|
||||||
|
|
||||||
g.It("Should return false if file size mismatch", func() {
|
|
||||||
ok := Check("foo\n", "f1d2d2f924e986ac86fdf7b36c94bcdf32beec15 12 -")
|
|
||||||
g.Assert(ok).IsFalse()
|
|
||||||
})
|
|
||||||
|
|
||||||
g.It("Should return false if invalid checksum string", func() {
|
|
||||||
ok := Check("foo\n", "f1d2d2f924e986ac86fdf7b36c94bcdf32beec15234")
|
|
||||||
g.Assert(ok).IsFalse()
|
|
||||||
})
|
|
||||||
|
|
||||||
g.It("Should return false if empty checksum", func() {
|
|
||||||
ok := Check("foo\n", "")
|
|
||||||
g.Assert(ok).IsFalse()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
Loading…
Reference in a new issue