Merge pull request #1581 from josmo/bitbucketserver
Stash/Bitbucket Server initial support
This commit is contained in:
commit
460b72e3ef
10 changed files with 2248 additions and 0 deletions
345
remote/bitbucketserver/bitbucketserver.go
Normal file
345
remote/bitbucketserver/bitbucketserver.go
Normal file
|
@ -0,0 +1,345 @@
|
|||
package bitbucketserver
|
||||
|
||||
// Requires the following to be set
|
||||
// REMOTE_DRIVER=bitbucketserver
|
||||
// REMOTE_CONFIG=https://{servername}?consumer_key={key added on the stash server for oath1}&git_username={username for clone}&git_password={password for clone}&consumer_rsa=/path/to/pem.file&open={not used yet}
|
||||
// Configure application links in the bitbucket server --
|
||||
// application url needs to be the base url to drone
|
||||
// incoming auth needs to have the consumer key (same as the key in REMOTE_CONFIG)
|
||||
// set the public key (public key from the private key added to /var/lib/bitbucketserver/private_key.pem name matters)
|
||||
// consumer call back is the base url to drone plus /authorize/
|
||||
// Needs a pem private key added to /var/lib/bitbucketserver/private_key.pem
|
||||
// After that you should be good to go
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
log "github.com/Sirupsen/logrus"
|
||||
"github.com/drone/drone/model"
|
||||
"github.com/mrjones/oauth"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type BitbucketServer struct {
|
||||
URL string
|
||||
ConsumerKey string
|
||||
GitUserName string
|
||||
GitPassword string
|
||||
ConsumerRSA string
|
||||
Open bool
|
||||
Consumer oauth.Consumer
|
||||
}
|
||||
|
||||
func Load(config string) *BitbucketServer {
|
||||
|
||||
url_, err := url.Parse(config)
|
||||
if err != nil {
|
||||
log.Fatalln("unable to parse remote dsn. %s", err)
|
||||
}
|
||||
params := url_.Query()
|
||||
url_.Path = ""
|
||||
url_.RawQuery = ""
|
||||
|
||||
bitbucketserver := BitbucketServer{}
|
||||
bitbucketserver.URL = url_.String()
|
||||
bitbucketserver.GitUserName = params.Get("git_username")
|
||||
if bitbucketserver.GitUserName == "" {
|
||||
log.Fatalln("Must have a git_username")
|
||||
}
|
||||
bitbucketserver.GitPassword = params.Get("git_password")
|
||||
if bitbucketserver.GitPassword == "" {
|
||||
log.Fatalln("Must have a git_password")
|
||||
}
|
||||
bitbucketserver.ConsumerKey = params.Get("consumer_key")
|
||||
if bitbucketserver.ConsumerKey == "" {
|
||||
log.Fatalln("Must have a consumer_key")
|
||||
}
|
||||
bitbucketserver.ConsumerRSA = params.Get("consumer_rsa")
|
||||
if bitbucketserver.ConsumerRSA == "" {
|
||||
log.Fatalln("Must have a consumer_rsa")
|
||||
}
|
||||
|
||||
bitbucketserver.Open, _ = strconv.ParseBool(params.Get("open"))
|
||||
|
||||
bitbucketserver.Consumer = *NewClient(bitbucketserver.ConsumerRSA, bitbucketserver.ConsumerKey, bitbucketserver.URL)
|
||||
|
||||
return &bitbucketserver
|
||||
}
|
||||
|
||||
func (bs *BitbucketServer) Login(res http.ResponseWriter, req *http.Request) (*model.User, bool, error) {
|
||||
log.Info("Starting to login for bitbucketServer")
|
||||
|
||||
log.Info("getting the requestToken")
|
||||
requestToken, url, err := bs.Consumer.GetRequestTokenAndUrl("oob")
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
|
||||
var code = req.FormValue("oauth_verifier")
|
||||
if len(code) == 0 {
|
||||
log.Info("redirecting to %s", url)
|
||||
http.Redirect(res, req, url, http.StatusSeeOther)
|
||||
return nil, false, nil
|
||||
}
|
||||
|
||||
var request_oauth_token = req.FormValue("oauth_token")
|
||||
requestToken.Token = request_oauth_token
|
||||
accessToken, err := bs.Consumer.AuthorizeToken(requestToken, code)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
|
||||
client, err := bs.Consumer.MakeHttpClient(accessToken)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
|
||||
response, err := client.Get(fmt.Sprintf("%s/plugins/servlet/applinks/whoami", bs.URL))
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
defer response.Body.Close()
|
||||
bits, err := ioutil.ReadAll(response.Body)
|
||||
userName := string(bits)
|
||||
|
||||
response1, err := client.Get(fmt.Sprintf("%s/rest/api/1.0/users/%s",bs.URL, userName))
|
||||
contents, err := ioutil.ReadAll(response1.Body)
|
||||
defer response1.Body.Close()
|
||||
var mUser User
|
||||
json.Unmarshal(contents, &mUser)
|
||||
|
||||
user := model.User{}
|
||||
user.Login = userName
|
||||
user.Email = mUser.EmailAddress
|
||||
user.Token = accessToken.Token
|
||||
|
||||
user.Avatar = avatarLink(mUser.EmailAddress)
|
||||
|
||||
return &user, bs.Open, nil
|
||||
}
|
||||
|
||||
func (bs *BitbucketServer) Auth(token, secret string) (string, error) {
|
||||
log.Info("Staring to auth for bitbucketServer. %s", token)
|
||||
if len(token) == 0 {
|
||||
return "", fmt.Errorf("Hasn't logged in yet")
|
||||
}
|
||||
return token, nil
|
||||
}
|
||||
|
||||
func (bs *BitbucketServer) Repo(u *model.User, owner, name string) (*model.Repo, error) {
|
||||
log.Info("Staring repo for bitbucketServer with user " + u.Login + " " + owner + " " + name)
|
||||
|
||||
client := NewClientWithToken(&bs.Consumer, u.Token)
|
||||
|
||||
url := fmt.Sprintf("%s/rest/api/projects/%s/repos/%s",bs.URL,owner,name)
|
||||
log.Info("Trying to get " + url)
|
||||
response, err := client.Get(url)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
defer response.Body.Close()
|
||||
contents, err := ioutil.ReadAll(response.Body)
|
||||
bsRepo := BSRepo{}
|
||||
json.Unmarshal(contents, &bsRepo)
|
||||
|
||||
cloneLink := ""
|
||||
repoLink := ""
|
||||
|
||||
for _, item := range bsRepo.Links.Clone {
|
||||
if item.Name == "http" {
|
||||
cloneLink = item.Href
|
||||
}
|
||||
}
|
||||
for _, item := range bsRepo.Links.Self {
|
||||
if item.Href != "" {
|
||||
repoLink = item.Href
|
||||
}
|
||||
}
|
||||
//TODO: get the real allow tag+ infomration
|
||||
repo := &model.Repo{}
|
||||
repo.Clone = cloneLink
|
||||
repo.Link = repoLink
|
||||
repo.Name = bsRepo.Slug
|
||||
repo.Owner = bsRepo.Project.Key
|
||||
repo.AllowPush = true
|
||||
repo.FullName = fmt.Sprintf("%s/%s",bsRepo.Project.Key,bsRepo.Slug)
|
||||
repo.Branch = "master"
|
||||
repo.Kind = model.RepoGit
|
||||
|
||||
return repo, nil
|
||||
}
|
||||
|
||||
func (bs *BitbucketServer) Repos(u *model.User) ([]*model.RepoLite, error) {
|
||||
log.Info("Staring repos for bitbucketServer " + u.Login)
|
||||
var repos = []*model.RepoLite{}
|
||||
|
||||
client := NewClientWithToken(&bs.Consumer, u.Token)
|
||||
|
||||
response, err := client.Get(fmt.Sprintf("%s/rest/api/1.0/repos?limit=10000",bs.URL))
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
defer response.Body.Close()
|
||||
contents, err := ioutil.ReadAll(response.Body)
|
||||
var repoResponse Repos
|
||||
json.Unmarshal(contents, &repoResponse)
|
||||
|
||||
for _, repo := range repoResponse.Values {
|
||||
repos = append(repos, &model.RepoLite{
|
||||
Name: repo.Slug,
|
||||
FullName: repo.Project.Key + "/" + repo.Slug,
|
||||
Owner: repo.Project.Key,
|
||||
})
|
||||
}
|
||||
|
||||
return repos, nil
|
||||
}
|
||||
|
||||
func (bs *BitbucketServer) Perm(u *model.User, owner, repo string) (*model.Perm, error) {
|
||||
|
||||
//TODO: find the real permissions
|
||||
log.Info("Staring perm for bitbucketServer")
|
||||
perms := new(model.Perm)
|
||||
perms.Pull = true
|
||||
perms.Admin = true
|
||||
perms.Push = true
|
||||
return perms, nil
|
||||
}
|
||||
|
||||
func (bs *BitbucketServer) File(u *model.User, r *model.Repo, b *model.Build, f string) ([]byte, error) {
|
||||
log.Info(fmt.Sprintf("Staring file for bitbucketServer login: %s repo: %s buildevent: %s string: %s", u.Login, r.Name, b.Event, f))
|
||||
|
||||
client := NewClientWithToken(&bs.Consumer, u.Token)
|
||||
fileURL := fmt.Sprintf("%s/projects/%s/repos/%s/browse/%s?raw", bs.URL, r.Owner, r.Name, f)
|
||||
log.Info(fileURL)
|
||||
response, err := client.Get(fileURL)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
if response.StatusCode == 404 {
|
||||
return nil, nil
|
||||
}
|
||||
defer response.Body.Close()
|
||||
responseBytes, err := ioutil.ReadAll(response.Body)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
|
||||
return responseBytes, nil
|
||||
}
|
||||
|
||||
func (bs *BitbucketServer) Status(u *model.User, r *model.Repo, b *model.Build, link string) error {
|
||||
log.Info("Staring status for bitbucketServer")
|
||||
return nil
|
||||
}
|
||||
|
||||
func (bs *BitbucketServer) Netrc(user *model.User, r *model.Repo) (*model.Netrc, error) {
|
||||
log.Info("Starting the Netrc lookup")
|
||||
u, err := url.Parse(bs.URL)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &model.Netrc{
|
||||
Machine: u.Host,
|
||||
Login: bs.GitUserName,
|
||||
Password: bs.GitPassword,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (bs *BitbucketServer) Activate(u *model.User, r *model.Repo, k *model.Key, link string) error {
|
||||
log.Info(fmt.Sprintf("Staring activate for bitbucketServer user: %s repo: %s key: %s link: %s", u.Login, r.Name, k, link))
|
||||
client := NewClientWithToken(&bs.Consumer, u.Token)
|
||||
hook, err := bs.CreateHook(client, r.Owner, r.Name, "com.atlassian.stash.plugin.stash-web-post-receive-hooks-plugin:postReceiveHook", link)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
log.Info(hook)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (bs *BitbucketServer) Deactivate(u *model.User, r *model.Repo, link string) error {
|
||||
log.Info(fmt.Sprintf("Staring deactivating for bitbucketServer user: %s repo: %s link: %s", u.Login, r.Name, link))
|
||||
client := NewClientWithToken(&bs.Consumer, u.Token)
|
||||
err := bs.DeleteHook(client, r.Owner, r.Name, "com.atlassian.stash.plugin.stash-web-post-receive-hooks-plugin:postReceiveHook", link)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (bs *BitbucketServer) Hook(r *http.Request) (*model.Repo, *model.Build, error) {
|
||||
log.Info("Staring hook for bitbucketServer")
|
||||
defer r.Body.Close()
|
||||
contents, err := ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
log.Info(err)
|
||||
}
|
||||
|
||||
var hookPost postHook
|
||||
json.Unmarshal(contents, &hookPost)
|
||||
|
||||
buildModel := &model.Build{}
|
||||
buildModel.Event = model.EventPush
|
||||
buildModel.Ref = hookPost.RefChanges[0].RefID
|
||||
buildModel.Author = hookPost.Changesets.Values[0].ToCommit.Author.EmailAddress
|
||||
buildModel.Commit = hookPost.RefChanges[0].ToHash
|
||||
buildModel.Avatar = avatarLink(hookPost.Changesets.Values[0].ToCommit.Author.EmailAddress)
|
||||
|
||||
//All you really need is the name and owner. That's what creates the lookup key, so it needs to match the repo info. Just an FYI
|
||||
repo := &model.Repo{}
|
||||
repo.Name = hookPost.Repository.Slug
|
||||
repo.Owner = hookPost.Repository.Project.Key
|
||||
repo.AllowTag = false
|
||||
repo.AllowDeploy = false
|
||||
repo.AllowPull = false
|
||||
repo.AllowPush = true
|
||||
repo.FullName = fmt.Sprintf("%s/%s",hookPost.Repository.Project.Key,hookPost.Repository.Slug)
|
||||
repo.Branch = "master"
|
||||
repo.Kind = model.RepoGit
|
||||
|
||||
return repo, buildModel, nil
|
||||
}
|
||||
func (bs *BitbucketServer) String() string {
|
||||
return "bitbucketserver"
|
||||
}
|
||||
|
||||
type HookDetail struct {
|
||||
Key string `"json:key"`
|
||||
Name string `"json:name"`
|
||||
Type string `"json:type"`
|
||||
Description string `"json:description"`
|
||||
Version string `"json:version"`
|
||||
ConfigFormKey string `"json:configFormKey"`
|
||||
}
|
||||
|
||||
type Hook struct {
|
||||
Enabled bool `"json:enabled"`
|
||||
Details *HookDetail `"json:details"`
|
||||
}
|
||||
|
||||
// Enable hook for named repository
|
||||
func (bs *BitbucketServer) CreateHook(client *http.Client, project, slug, hook_key, link string) (*Hook, error) {
|
||||
|
||||
// Set hook
|
||||
hookBytes := []byte(fmt.Sprintf(`{"hook-url-0":"%s"}`, link))
|
||||
|
||||
// Enable hook
|
||||
enablePath := fmt.Sprintf("/rest/api/1.0/projects/%s/repos/%s/settings/hooks/%s/enabled",
|
||||
project, slug, hook_key)
|
||||
|
||||
doPut(client, bs.URL+enablePath, hookBytes)
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// Disable hook for named repository
|
||||
func (bs *BitbucketServer) DeleteHook(client *http.Client, project, slug, hook_key, link string) error {
|
||||
enablePath := fmt.Sprintf("/rest/api/1.0/projects/%s/repos/%s/settings/hooks/%s/enabled",
|
||||
project, slug, hook_key)
|
||||
doDelete(client, bs.URL+enablePath)
|
||||
|
||||
return nil
|
||||
}
|
52
remote/bitbucketserver/client.go
Normal file
52
remote/bitbucketserver/client.go
Normal file
|
@ -0,0 +1,52 @@
|
|||
package bitbucketserver
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"encoding/pem"
|
||||
log "github.com/Sirupsen/logrus"
|
||||
"github.com/mrjones/oauth"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func NewClient(ConsumerRSA string, ConsumerKey string, URL string) *oauth.Consumer {
|
||||
//TODO: make this configurable
|
||||
privateKeyFileContents, err := ioutil.ReadFile(ConsumerRSA)
|
||||
log.Info("Tried to read the key")
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
|
||||
block, _ := pem.Decode([]byte(privateKeyFileContents))
|
||||
privateKey, err := x509.ParsePKCS1PrivateKey(block.Bytes)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
|
||||
c := oauth.NewRSAConsumer(
|
||||
ConsumerKey,
|
||||
privateKey,
|
||||
oauth.ServiceProvider{
|
||||
RequestTokenUrl: URL + "/plugins/servlet/oauth/request-token",
|
||||
AuthorizeTokenUrl: URL + "/plugins/servlet/oauth/authorize",
|
||||
AccessTokenUrl: URL + "/plugins/servlet/oauth/access-token",
|
||||
HttpMethod: "POST",
|
||||
})
|
||||
c.HttpClient = &http.Client{
|
||||
Transport: &http.Transport{
|
||||
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
|
||||
},
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
func NewClientWithToken(Consumer *oauth.Consumer, AccessToken string) *http.Client {
|
||||
var token oauth.AccessToken
|
||||
token.Token = AccessToken
|
||||
client, err := Consumer.MakeHttpClient(&token)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
return client
|
||||
}
|
64
remote/bitbucketserver/helper.go
Normal file
64
remote/bitbucketserver/helper.go
Normal file
|
@ -0,0 +1,64 @@
|
|||
package bitbucketserver
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/md5"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
log "github.com/Sirupsen/logrus"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func avatarLink(email string) (url string) {
|
||||
hasher := md5.New()
|
||||
hasher.Write([]byte(strings.ToLower(email)))
|
||||
emailHash := fmt.Sprintf("%v", hex.EncodeToString(hasher.Sum(nil)))
|
||||
avatarURL := fmt.Sprintf("https://www.gravatar.com/avatar/%s.jpg", emailHash)
|
||||
log.Info(avatarURL)
|
||||
return avatarURL
|
||||
}
|
||||
|
||||
func doPut(client *http.Client, url string, body []byte) {
|
||||
request, err := http.NewRequest("PUT", url, bytes.NewBuffer(body))
|
||||
request.Header.Add("Content-Type", "application/json")
|
||||
response, err := client.Do(request)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
} else {
|
||||
defer response.Body.Close()
|
||||
contents, err := ioutil.ReadAll(response.Body)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
fmt.Println("The calculated length is:", len(string(contents)), "for the url:", url)
|
||||
fmt.Println(" ", response.StatusCode)
|
||||
hdr := response.Header
|
||||
for key, value := range hdr {
|
||||
fmt.Println(" ", key, ":", value)
|
||||
}
|
||||
fmt.Println(string(contents))
|
||||
}
|
||||
}
|
||||
|
||||
func doDelete(client *http.Client, url string) {
|
||||
request, err := http.NewRequest("DELETE", url, nil)
|
||||
response, err := client.Do(request)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
} else {
|
||||
defer response.Body.Close()
|
||||
contents, err := ioutil.ReadAll(response.Body)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
fmt.Println("The calculated length is:", len(string(contents)), "for the url:", url)
|
||||
fmt.Println(" ", response.StatusCode)
|
||||
hdr := response.Header
|
||||
for key, value := range hdr {
|
||||
fmt.Println(" ", key, ":", value)
|
||||
}
|
||||
fmt.Println(string(contents))
|
||||
}
|
||||
}
|
172
remote/bitbucketserver/types.go
Normal file
172
remote/bitbucketserver/types.go
Normal file
|
@ -0,0 +1,172 @@
|
|||
package bitbucketserver
|
||||
|
||||
type postHook struct {
|
||||
Changesets struct {
|
||||
Filter interface{} `json:"filter"`
|
||||
IsLastPage bool `json:"isLastPage"`
|
||||
Limit int `json:"limit"`
|
||||
Size int `json:"size"`
|
||||
Start int `json:"start"`
|
||||
Values []struct {
|
||||
Changes struct {
|
||||
Filter interface{} `json:"filter"`
|
||||
IsLastPage bool `json:"isLastPage"`
|
||||
Limit int `json:"limit"`
|
||||
Size int `json:"size"`
|
||||
Start int `json:"start"`
|
||||
Values []struct {
|
||||
ContentID string `json:"contentId"`
|
||||
Executable bool `json:"executable"`
|
||||
Link struct {
|
||||
Rel string `json:"rel"`
|
||||
URL string `json:"url"`
|
||||
} `json:"link"`
|
||||
NodeType string `json:"nodeType"`
|
||||
Path struct {
|
||||
Components []string `json:"components"`
|
||||
Extension string `json:"extension"`
|
||||
Name string `json:"name"`
|
||||
Parent string `json:"parent"`
|
||||
ToString string `json:"toString"`
|
||||
} `json:"path"`
|
||||
PercentUnchanged int `json:"percentUnchanged"`
|
||||
SrcExecutable bool `json:"srcExecutable"`
|
||||
Type string `json:"type"`
|
||||
} `json:"values"`
|
||||
} `json:"changes"`
|
||||
FromCommit struct {
|
||||
DisplayID string `json:"displayId"`
|
||||
ID string `json:"id"`
|
||||
} `json:"fromCommit"`
|
||||
Link struct {
|
||||
Rel string `json:"rel"`
|
||||
URL string `json:"url"`
|
||||
} `json:"link"`
|
||||
ToCommit struct {
|
||||
Author struct {
|
||||
EmailAddress string `json:"emailAddress"`
|
||||
Name string `json:"name"`
|
||||
} `json:"author"`
|
||||
AuthorTimestamp int `json:"authorTimestamp"`
|
||||
DisplayID string `json:"displayId"`
|
||||
ID string `json:"id"`
|
||||
Message string `json:"message"`
|
||||
Parents []struct {
|
||||
DisplayID string `json:"displayId"`
|
||||
ID string `json:"id"`
|
||||
} `json:"parents"`
|
||||
} `json:"toCommit"`
|
||||
} `json:"values"`
|
||||
} `json:"changesets"`
|
||||
RefChanges []struct {
|
||||
FromHash string `json:"fromHash"`
|
||||
RefID string `json:"refId"`
|
||||
ToHash string `json:"toHash"`
|
||||
Type string `json:"type"`
|
||||
} `json:"refChanges"`
|
||||
Repository struct {
|
||||
Forkable bool `json:"forkable"`
|
||||
ID int `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Project struct {
|
||||
ID int `json:"id"`
|
||||
IsPersonal bool `json:"isPersonal"`
|
||||
Key string `json:"key"`
|
||||
Name string `json:"name"`
|
||||
Public bool `json:"public"`
|
||||
Type string `json:"type"`
|
||||
} `json:"project"`
|
||||
Public bool `json:"public"`
|
||||
ScmID string `json:"scmId"`
|
||||
Slug string `json:"slug"`
|
||||
State string `json:"state"`
|
||||
StatusMessage string `json:"statusMessage"`
|
||||
} `json:"repository"`
|
||||
}
|
||||
|
||||
type Repos struct {
|
||||
IsLastPage bool `json:"isLastPage"`
|
||||
Limit int `json:"limit"`
|
||||
Size int `json:"size"`
|
||||
Start int `json:"start"`
|
||||
Values []struct {
|
||||
Forkable bool `json:"forkable"`
|
||||
ID int `json:"id"`
|
||||
Links struct {
|
||||
Clone []struct {
|
||||
Href string `json:"href"`
|
||||
Name string `json:"name"`
|
||||
} `json:"clone"`
|
||||
Self []struct {
|
||||
Href string `json:"href"`
|
||||
} `json:"self"`
|
||||
} `json:"links"`
|
||||
Name string `json:"name"`
|
||||
Project struct {
|
||||
Description string `json:"description"`
|
||||
ID int `json:"id"`
|
||||
Key string `json:"key"`
|
||||
Links struct {
|
||||
Self []struct {
|
||||
Href string `json:"href"`
|
||||
} `json:"self"`
|
||||
} `json:"links"`
|
||||
Name string `json:"name"`
|
||||
Public bool `json:"public"`
|
||||
Type string `json:"type"`
|
||||
} `json:"project"`
|
||||
Public bool `json:"public"`
|
||||
ScmID string `json:"scmId"`
|
||||
Slug string `json:"slug"`
|
||||
State string `json:"state"`
|
||||
StatusMessage string `json:"statusMessage"`
|
||||
} `json:"values"`
|
||||
}
|
||||
|
||||
type User struct {
|
||||
Active bool `json:"active"`
|
||||
DisplayName string `json:"displayName"`
|
||||
EmailAddress string `json:"emailAddress"`
|
||||
ID int `json:"id"`
|
||||
Links struct {
|
||||
Self []struct {
|
||||
Href string `json:"href"`
|
||||
} `json:"self"`
|
||||
} `json:"links"`
|
||||
Name string `json:"name"`
|
||||
Slug string `json:"slug"`
|
||||
Type string `json:"type"`
|
||||
}
|
||||
|
||||
type BSRepo struct {
|
||||
Forkable bool `json:"forkable"`
|
||||
ID int `json:"id"`
|
||||
Links struct {
|
||||
Clone []struct {
|
||||
Href string `json:"href"`
|
||||
Name string `json:"name"`
|
||||
} `json:"clone"`
|
||||
Self []struct {
|
||||
Href string `json:"href"`
|
||||
} `json:"self"`
|
||||
} `json:"links"`
|
||||
Name string `json:"name"`
|
||||
Project struct {
|
||||
Description string `json:"description"`
|
||||
ID int `json:"id"`
|
||||
Key string `json:"key"`
|
||||
Links struct {
|
||||
Self []struct {
|
||||
Href string `json:"href"`
|
||||
} `json:"self"`
|
||||
} `json:"links"`
|
||||
Name string `json:"name"`
|
||||
Public bool `json:"public"`
|
||||
Type string `json:"type"`
|
||||
} `json:"project"`
|
||||
Public bool `json:"public"`
|
||||
ScmID string `json:"scmId"`
|
||||
Slug string `json:"slug"`
|
||||
State string `json:"state"`
|
||||
StatusMessage string `json:"statusMessage"`
|
||||
}
|
|
@ -10,6 +10,7 @@ import (
|
|||
"github.com/Sirupsen/logrus"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/ianschenck/envflag"
|
||||
"github.com/drone/drone/remote/bitbucketserver"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -34,6 +35,8 @@ func Remote() gin.HandlerFunc {
|
|||
remote_ = gogs.Load(*config)
|
||||
case "gitlab":
|
||||
remote_ = gitlab.Load(*config)
|
||||
case "bitbucketserver":
|
||||
remote_ = bitbucketserver.Load(*config)
|
||||
default:
|
||||
logrus.Fatalln("remote configuraiton not found")
|
||||
}
|
||||
|
|
49
vendor/github.com/mrjones/oauth/README.md
generated
vendored
Normal file
49
vendor/github.com/mrjones/oauth/README.md
generated
vendored
Normal file
|
@ -0,0 +1,49 @@
|
|||
OAuth 1.0 Library for [Go](http://golang.org)
|
||||
========================
|
||||
|
||||
[![GoDoc](http://godoc.org/github.com/mrjones/oauth?status.png)](http://godoc.org/github.com/mrjones/oauth)
|
||||
|
||||
(If you need an OAuth 2.0 library, check out: http://code.google.com/p/goauth2/)
|
||||
|
||||
Developing your own apps, with this library
|
||||
-------------------------------------------
|
||||
|
||||
* First, install the library
|
||||
|
||||
go get github.com/mrjones/oauth
|
||||
|
||||
* Then, check out the comments in oauth.go
|
||||
|
||||
* Or, have a look at the examples:
|
||||
|
||||
* Netflix
|
||||
|
||||
go run examples/netflix/netflix.go --consumerkey [key] --consumersecret [secret] --appname [appname]
|
||||
|
||||
* Twitter
|
||||
|
||||
Command line:
|
||||
|
||||
go run examples/twitter/twitter.go --consumerkey [key] --consumersecret [secret]
|
||||
|
||||
Or, in the browser (using an HTTP server):
|
||||
|
||||
go run examples/twitterserver/twitterserver.go --consumerkey [key] --consumersecret [secret] --port 8888
|
||||
|
||||
* The Google Latitude example is broken, now that Google uses OAuth 2.0
|
||||
|
||||
Contributing to this library
|
||||
----------------------------
|
||||
|
||||
* Please install the pre-commit hook, which will run tests, and go-fmt before committing.
|
||||
|
||||
ln -s $PWD/pre-commit.sh .git/hooks/pre-commit
|
||||
|
||||
* Running tests and building is as you'd expect:
|
||||
|
||||
go test *.go
|
||||
go build *.go
|
||||
|
||||
|
||||
|
||||
|
1389
vendor/github.com/mrjones/oauth/oauth.go
generated
vendored
Normal file
1389
vendor/github.com/mrjones/oauth/oauth.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
21
vendor/github.com/mrjones/oauth/pre-commit.sh
generated
vendored
Executable file
21
vendor/github.com/mrjones/oauth/pre-commit.sh
generated
vendored
Executable file
|
@ -0,0 +1,21 @@
|
|||
#!/bin/bash
|
||||
# ln -s $PWD/pre-commit.sh .git/hooks/pre-commit
|
||||
go test *.go
|
||||
RESULT=$?
|
||||
if [[ $RESULT != 0 ]]; then
|
||||
echo "REJECTING COMMIT (test failed with status: $RESULT)"
|
||||
exit 1;
|
||||
fi
|
||||
|
||||
go fmt *.go
|
||||
for e in $(ls examples); do
|
||||
go build examples/$e/*.go
|
||||
RESULT=$?
|
||||
if [[ $RESULT != 0 ]]; then
|
||||
echo "REJECTING COMMIT (Examples failed to compile)"
|
||||
exit $RESULT;
|
||||
fi
|
||||
go fmt examples/$e/*.go
|
||||
done
|
||||
|
||||
exit 0
|
147
vendor/github.com/mrjones/oauth/provider.go
generated
vendored
Normal file
147
vendor/github.com/mrjones/oauth/provider.go
generated
vendored
Normal file
|
@ -0,0 +1,147 @@
|
|||
package oauth
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"math"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
//
|
||||
// OAuth1 2-legged provider
|
||||
// Contributed by https://github.com/jacobpgallagher
|
||||
//
|
||||
|
||||
// Provide an buffer reader which implements the Close() interface
|
||||
type oauthBufferReader struct {
|
||||
*bytes.Buffer
|
||||
}
|
||||
|
||||
// So that it implements the io.ReadCloser interface
|
||||
func (m oauthBufferReader) Close() error { return nil }
|
||||
|
||||
type ConsumerGetter func(key string, header map[string]string) (*Consumer, error)
|
||||
|
||||
// Provider provides methods for a 2-legged Oauth1 provider
|
||||
type Provider struct {
|
||||
ConsumerGetter ConsumerGetter
|
||||
|
||||
// For mocking
|
||||
clock clock
|
||||
}
|
||||
|
||||
// NewProvider takes a function to get the consumer secret from a datastore.
|
||||
// Returns a Provider
|
||||
func NewProvider(secretGetter ConsumerGetter) *Provider {
|
||||
provider := &Provider{
|
||||
secretGetter,
|
||||
&defaultClock{},
|
||||
}
|
||||
return provider
|
||||
}
|
||||
|
||||
// Combine a URL and Request to make the URL absolute
|
||||
func makeURLAbs(url *url.URL, request *http.Request) {
|
||||
if !url.IsAbs() {
|
||||
url.Host = request.Host
|
||||
if request.TLS != nil || request.Header.Get("X-Forwarded-Proto") == "https" {
|
||||
url.Scheme = "https"
|
||||
} else {
|
||||
url.Scheme = "http"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// IsAuthorized takes an *http.Request and returns a pointer to a string containing the consumer key,
|
||||
// or nil if not authorized
|
||||
func (provider *Provider) IsAuthorized(request *http.Request) (*string, error) {
|
||||
var err error
|
||||
var userParams map[string]string
|
||||
|
||||
// start with the body/query params
|
||||
userParams, err = parseBody(request)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// if the oauth params are in the Authorization header, grab them, and
|
||||
// let them override what's in userParams
|
||||
authHeader := request.Header.Get(HTTP_AUTH_HEADER)
|
||||
if len(authHeader) > 6 && strings.EqualFold(OAUTH_HEADER, authHeader[0:6]) {
|
||||
authHeader = authHeader[6:]
|
||||
params := strings.Split(authHeader, ",")
|
||||
for _, param := range params {
|
||||
vals := strings.SplitN(param, "=", 2)
|
||||
k := strings.Trim(vals[0], " ")
|
||||
v := strings.Trim(strings.Trim(vals[1], "\""), " ")
|
||||
if strings.HasPrefix(k, "oauth") {
|
||||
userParams[k], err = url.QueryUnescape(v)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// pop the request's signature, it's not included in our signature
|
||||
// calculation
|
||||
oauthSignature, ok := userParams[SIGNATURE_PARAM]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("no oauth signature")
|
||||
}
|
||||
delete(userParams, SIGNATURE_PARAM)
|
||||
|
||||
// Check the timestamp
|
||||
oauthTimeNumber, err := strconv.Atoi(userParams[TIMESTAMP_PARAM])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if math.Abs(float64(int64(oauthTimeNumber)-provider.clock.Seconds())) > 5*60 {
|
||||
return nil, fmt.Errorf("too much clock skew")
|
||||
}
|
||||
|
||||
// get the oauth consumer key
|
||||
consumerKey, ok := userParams[CONSUMER_KEY_PARAM]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("no consumer key")
|
||||
}
|
||||
|
||||
// use it to create a consumer object
|
||||
consumer, err := provider.ConsumerGetter(consumerKey, userParams)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// if our consumer supports bodyhash, check it
|
||||
if consumer.serviceProvider.BodyHash {
|
||||
bodyHash, err := calculateBodyHash(request, consumer.signer)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
sentHash, ok := userParams[BODY_HASH_PARAM]
|
||||
|
||||
if bodyHash == "" && ok {
|
||||
return nil, fmt.Errorf("body_hash must not be set")
|
||||
} else if sentHash != bodyHash {
|
||||
return nil, fmt.Errorf("body_hash mismatch")
|
||||
}
|
||||
}
|
||||
|
||||
allParams := NewOrderedParams()
|
||||
for key, value := range userParams {
|
||||
allParams.Add(key, value)
|
||||
}
|
||||
|
||||
makeURLAbs(request.URL, request)
|
||||
baseString := consumer.requestString(request.Method, canonicalizeUrl(request.URL), allParams)
|
||||
err = consumer.signer.Verify(baseString, oauthSignature)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &consumerKey, nil
|
||||
}
|
6
vendor/vendor.json
vendored
6
vendor/vendor.json
vendored
|
@ -169,6 +169,12 @@
|
|||
"revisionTime": "2016-03-07T18:57:06+09:00",
|
||||
"tree": true
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "spRLFk8daizvEzOmRsxlxeECdHI=",
|
||||
"path": "github.com/mrjones/oauth",
|
||||
"revision": "31f1e8e5addda51bc50ebfc8bb930d4642372654",
|
||||
"revisionTime": "2016-04-05T23:58:02Z"
|
||||
},
|
||||
{
|
||||
"origin": "github.com/stretchr/testify/vendor/github.com/pmezard/go-difflib/difflib",
|
||||
"path": "github.com/pmezard/go-difflib/difflib",
|
||||
|
|
Loading…
Reference in a new issue