Start working on specs implementation

This commit is contained in:
Kirill Zaitsev 2015-07-23 20:36:23 +03:00
parent 2939e1356d
commit 2966d294fe
6 changed files with 125 additions and 63 deletions

View file

@ -9,7 +9,7 @@ import (
"github.com/drone/drone/Godeps/_workspace/src/github.com/elazarl/go-bindata-assetfs"
"github.com/drone/drone/pkg/config"
"github.com/drone/drone/pkg/remote/builtin/github"
"github.com/drone/drone/pkg/remote"
"github.com/drone/drone/pkg/server"
"github.com/drone/drone/pkg/server/session"
@ -49,7 +49,10 @@ func main() {
panic(err)
}
remote := github.New(settings)
remote, err := remote.New(settings)
if err != nil {
panic(err)
}
session := session.New(settings)
eventbus_ := eventbus.New()
queue_ := queue.New()

View file

@ -1,7 +1,11 @@
package config
import (
"fmt"
"io/ioutil"
"os"
"path"
"strings"
"github.com/drone/drone/Godeps/_workspace/src/github.com/naoina/toml"
"github.com/drone/drone/Godeps/_workspace/src/github.com/vrischmann/envconfig"
@ -9,12 +13,7 @@ import (
type Config struct {
Remote struct {
Kind string `envconfig:"optional"`
Base string `envconfig:"optional"`
Orgs []string `envconfig:"optional"`
Open bool `envconfig:"optional"`
Private bool `envconfig:"optional"`
SkipVerify bool `envconfig:"optional"`
Driver string `envconfig:"optional"`
}
Auth struct {
@ -67,20 +66,14 @@ type Config struct {
Plugins []string `envconfig:"optional"`
Github struct {
Client string `envconfig:"optional"`
Secret string `envconfig:"optional"`
Orgs []string `envconfig:"optional"`
Open bool `envconfig:"optional"`
}
GithubEnterprise struct {
URL string `envconfig:"optional"`
Client string `envconfig:"optional"`
Secret string `envconfig:"optional"`
Private bool `envconfig:"optional"`
SkipVerify bool `envconfig:"optional"`
Open bool `envconfig:"optional"`
Orgs []string `envconfig:"optional"`
API string `envconfig:"optional"`
Host string `envconfig:"optional"`
Client string `envconfig:"optional"`
Secret string `envconfig:"optional"`
PrivateMode bool `envconfig:"optional"`
SkipVerify bool `envconfig:"optional"`
Open bool `envconfig:"optional"`
Orgs []string `envconfig:"optional"`
}
Bitbucket struct {
@ -132,5 +125,29 @@ func applyDefaults(c *Config) *Config {
if len(c.Session.Secret) == 0 {
c.Session.Secret = c.Auth.Secret
}
// Prevent crash on start, use sqlite3
// driver as default if DRONE_DATABASE_DRIVER and
// DRONE_DATABASE_DATASOURCE not specifed
if len(c.Database.Driver) == 0 && len(c.Database.Datasource) == 0 {
c.Database.Driver = "sqlite3"
pwd, err := os.Getwd()
if err != nil {
panic(err)
}
c.Database.Datasource = path.Join(pwd, "drone.sqlite3")
}
// Set default settings for remotes
switch strings.ToLower(c.Remote.Driver) {
case "github":
if len(c.Github.API) == 0 && len(c.Github.Host) == 0 {
c.Github.API = "https://api.github.com/"
c.Github.Host = "https://github.com"
}
}
return c
}

View file

@ -1,6 +1,7 @@
package github
import (
"crypto/tls"
"encoding/json"
"fmt"
"net/http"
@ -10,14 +11,14 @@ import (
"github.com/drone/drone/Godeps/_workspace/src/github.com/hashicorp/golang-lru"
"github.com/drone/drone/pkg/config"
"github.com/drone/drone/pkg/oauth2"
common "github.com/drone/drone/pkg/types"
"github.com/drone/drone/pkg/utils/httputil"
"github.com/drone/drone/Godeps/_workspace/src/github.com/google/go-github/github"
)
const (
DefaultAPI = "https://api.github.com/"
DefaultURL = "https://github.com"
DefaultScope = "repo,repo:status,user:email"
)
@ -26,6 +27,8 @@ type GitHub struct {
API string
Client string
Secret string
AllowedOrgs []string
Open bool
PrivateMode bool
SkipVerify bool
@ -34,12 +37,14 @@ type GitHub struct {
func New(conf *config.Config) *GitHub {
var github = GitHub{
API: DefaultAPI,
URL: DefaultURL,
Client: conf.Auth.Client,
Secret: conf.Auth.Secret,
PrivateMode: conf.Remote.Private,
SkipVerify: conf.Remote.SkipVerify,
API: conf.Github.API,
URL: conf.Github.Host,
Client: conf.Github.Client,
Secret: conf.Github.Secret,
AllowedOrgs: conf.Github.Orgs,
Open: conf.Github.Open,
PrivateMode: conf.Github.PrivateMode,
SkipVerify: conf.Github.SkipVerify,
}
var err error
github.cache, err = lru.New(1028)
@ -47,12 +52,6 @@ func New(conf *config.Config) *GitHub {
panic(err)
}
// if GitHub enterprise then ensure we're using the
// appropriate URLs
if !strings.HasPrefix(conf.Remote.Base, DefaultURL) && len(conf.Remote.Base) != 0 {
github.URL = conf.Remote.Base
github.API = conf.Remote.Base + "/api/v3/"
}
// the API must have a trailing slash
if !strings.HasSuffix(github.API, "/") {
github.API += "/"
@ -66,7 +65,7 @@ func New(conf *config.Config) *GitHub {
func (g *GitHub) Login(token, secret string) (*common.User, error) {
client := NewClient(g.API, token, g.SkipVerify)
login, err := GetUserEmail(client)
login, err := GetUserEmail(client, g.URL)
if err != nil {
return nil, err
}
@ -92,6 +91,16 @@ func (g *GitHub) Orgs(u *common.User) ([]string, error) {
return orgs_, nil
}
// Accessor method, to allowed remote organizations field.
func (g *GitHub) GetOrgs() []string {
return g.AllowedOrgs
}
// Accessor method, to open field.
func (g *GitHub) GetOpen() bool {
return g.Open
}
// Repo fetches the named repository from the remote system.
func (g *GitHub) Repo(u *common.User, owner, name string) (*common.Repo, error) {
client := NewClient(g.API, u.Token, g.SkipVerify)
@ -281,6 +290,25 @@ func (g *GitHub) push(r *http.Request) (*common.Hook, error) {
return &common.Hook{Repo: repo, Commit: commit}, nil
}
// ¯\_(ツ)_/¯
func (g *GitHub) Oauth2Transport(r *http.Request) *oauth2.Transport {
return &oauth2.Transport{
Config: &oauth2.Config{
ClientId: g.Client,
ClientSecret: g.Secret,
Scope: DefaultScope,
AuthURL: fmt.Sprintf("%s/login/oauth/authorize", g.URL),
TokenURL: fmt.Sprintf("%s/login/oauth/access_token", g.URL),
RedirectURL: fmt.Sprintf("%s/authorize", httputil.GetURL(r)),
//settings.Server.Scheme, settings.Server.Hostname),
},
Transport: &http.Transport{
Proxy: http.ProxyFromEnvironment,
TLSClientConfig: &tls.Config{InsecureSkipVerify: g.SkipVerify},
},
}
}
// pullRequest parses a hook with event type `pullRequest`
// and returns the commit data.
func (g *GitHub) pullRequest(r *http.Request) (*common.Hook, error) {

View file

@ -37,7 +37,7 @@ func NewClient(uri, token string, skipVerify bool) *github.Client {
// GetUserEmail is a heper function that retrieves the currently
// authenticated user from GitHub + Email address.
func GetUserEmail(client *github.Client) (*github.User, error) {
func GetUserEmail(client *github.Client, defaultURL string) (*github.User, error) {
user, _, err := client.Users.Get("")
if err != nil {
return nil, err
@ -58,7 +58,7 @@ func GetUserEmail(client *github.Client) (*github.User, error) {
// WARNING, HACK
// for out-of-date github enterprise editions the primary
// and verified fields won't exist.
if !strings.HasPrefix(*user.HTMLURL, DefaultURL) && len(emails) != 0 {
if !strings.HasPrefix(*user.HTMLURL, defaultURL) && len(emails) != 0 {
user.Email = emails[0].Email
return user, nil
}

View file

@ -1,8 +1,14 @@
package remote
import (
"errors"
"fmt"
"net/http"
"strings"
"github.com/drone/drone/pkg/config"
"github.com/drone/drone/pkg/oauth2"
"github.com/drone/drone/pkg/remote/builtin/github"
common "github.com/drone/drone/pkg/types"
)
@ -45,6 +51,27 @@ type Remote interface {
// and returns the required data in a standard format.
Hook(r *http.Request) (*common.Hook, error)
// Oauth2Transport
Oauth2Transport(r *http.Request) *oauth2.Transport
// GetOrgs returns all allowed organizations for remote.
GetOrgs() []string
// GetOpen returns boolean field with enabled or disabled
// registration.
GetOpen() bool
// Default scope for remote
Scope() string
}
func New(conf *config.Config) (Remote, error) {
switch strings.ToLower(conf.Remote.Driver) {
case "github":
return github.New(conf), nil
case "":
return nil, errors.New("Remote not specifed, please set env variable DRONE_REMOTE_DRIVER")
default:
return nil, errors.New(fmt.Sprintf("Remote driver not supported: DRONE_REMOTE_DRIVER=%s", conf.Remote.Driver))
}
}

View file

@ -1,17 +1,13 @@
package server
import (
"fmt"
"strings"
"time"
"github.com/drone/drone/Godeps/_workspace/src/github.com/gin-gonic/gin"
"github.com/drone/drone/Godeps/_workspace/src/github.com/ungerik/go-gravatar"
log "github.com/drone/drone/Godeps/_workspace/src/github.com/Sirupsen/logrus"
"github.com/drone/drone/pkg/oauth2"
common "github.com/drone/drone/pkg/types"
"github.com/drone/drone/pkg/utils/httputil"
)
// GetLogin accepts a request to authorize the user and to
@ -52,9 +48,9 @@ func GetLogin(c *gin.Context) {
login := ToUser(c)
// check organization membership, if applicable
if len(settings.Remote.Orgs) != 0 {
if len(remote.GetOrgs()) != 0 {
orgs, _ := remote.Orgs(login)
if !checkMembership(orgs, settings.Remote.Orgs) {
if !checkMembership(orgs, remote.GetOrgs()) {
c.Redirect(303, "/login#error=access_denied_org")
return
}
@ -73,7 +69,7 @@ func GetLogin(c *gin.Context) {
// 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 !settings.Remote.Open && count != 0 {
if !remote.GetOpen() && count != 0 {
log.Errorf("cannot register %s. registration closed", login.Login)
c.Redirect(303, "/login#error=access_denied")
return
@ -131,35 +127,26 @@ func GetLogin(c *gin.Context) {
// getLoginOauth2 is the default authorization implementation
// using the oauth2 protocol.
func getLoginOauth2(c *gin.Context) {
var settings = ToSettings(c)
var remote = ToRemote(c)
var scope = strings.Join(settings.Auth.Scope, ",")
if scope == "" {
scope = remote.Scope()
}
var config = &oauth2.Config{
ClientId: settings.Auth.Client,
ClientSecret: settings.Auth.Secret,
Scope: scope,
AuthURL: settings.Auth.Authorize,
TokenURL: settings.Auth.AccessToken,
RedirectURL: fmt.Sprintf("%s/authorize", httputil.GetURL(c.Request)),
//settings.Server.Scheme, settings.Server.Hostname),
}
// Bugagazavr: I think this must be moved to remote config
//var scope = strings.Join(settings.Auth.Scope, ",")
//if scope == "" {
// scope = remote.Scope()
//}
var transport = remote.Oauth2Transport(c.Request)
// get the OAuth code
var code = c.Request.FormValue("code")
//var state = c.Request.FormValue("state")
if len(code) == 0 {
// TODO this should be a random number, verified by a cookie
c.Redirect(303, config.AuthCodeURL("random"))
c.Redirect(303, transport.AuthCodeURL("random"))
return
}
// exhange for a token
var trans = &oauth2.Transport{Config: config}
var token, err = trans.Exchange(code)
var token, err = transport.Exchange(code)
if err != nil {
log.Errorf("cannot get access_token. %s", err)
c.Redirect(303, "/login#error=token_exchange")