From a7ecfee795736806f651db6a2ad4ac1fbefc9efe Mon Sep 17 00:00:00 2001 From: Simone Gotti Date: Mon, 13 May 2019 14:21:41 +0200 Subject: [PATCH] gitea: use custom http request for get tokens Since the get tokens gitea api is used to do auth by username password we need to know the api status code to detect if it's an unauthorized error (wrong username/password) or another error. Since the gitea client doesn't return the http response to inspect the status code we'll use our own api call. --- internal/gitsources/gitea/gitea.go | 41 +++++++++++++++++++++++++----- internal/gitsources/gitsource.go | 3 +++ 2 files changed, 37 insertions(+), 7 deletions(-) diff --git a/internal/gitsources/gitea/gitea.go b/internal/gitsources/gitea/gitea.go index 356fcb0..6dc88a3 100644 --- a/internal/gitsources/gitea/gitea.go +++ b/internal/gitsources/gitea/gitea.go @@ -17,6 +17,8 @@ package gitea import ( "context" "crypto/tls" + "encoding/base64" + "encoding/json" "fmt" "net" "net/http" @@ -54,6 +56,7 @@ type Opts struct { type Client struct { client *gitea.Client + httpClient *http.Client URL string oauth2ClientID string oauth2Secret string @@ -103,6 +106,7 @@ func New(opts Opts) (*Client, error) { return &Client{ client: client, + httpClient: httpClient, URL: opts.URL, oauth2ClientID: opts.Oauth2ClientID, oauth2Secret: opts.Oauth2Secret, @@ -145,14 +149,37 @@ func (c *Client) RefreshOauth2Token(refreshToken string) (*oauth2.Token, error) func (c *Client) LoginPassword(username, password, tokenName string) (string, error) { // try to get agola access token if it already exists + // use custom http call since gitea api client doesn't provide an easy way to + // guess if the username/password login failed var accessToken string - tokens, err := c.client.ListAccessTokens(username, password) - if err == nil { - for _, token := range tokens { - if token.Name == tokenName { - accessToken = token.Sha1 - break - } + + tokens := make([]*gitea.AccessToken, 0, 10) + req, err := http.NewRequest("GET", c.URL+"/api/v1"+fmt.Sprintf("/users/%s/tokens", username), nil) + if err != nil { + return "", err + } + req.Header.Set("Authorization", "Basic "+base64.StdEncoding.EncodeToString([]byte(username+":"+password))) + + resp, err := c.httpClient.Do(req) + if err != nil { + return "", err + } + if resp.StatusCode == http.StatusUnauthorized { + return "", gitsource.ErrUnauthorized + } + if resp.StatusCode/100 != 2 { + return "", errors.Errorf("gitea api status code %d", resp.StatusCode) + } + defer resp.Body.Close() + + dec := json.NewDecoder(resp.Body) + if err := dec.Decode(&tokens); err != nil { + return "", err + } + for _, token := range tokens { + if token.Name == tokenName { + accessToken = token.Sha1 + break } } diff --git a/internal/gitsources/gitsource.go b/internal/gitsources/gitsource.go index 6885199..53dd8ad 100644 --- a/internal/gitsources/gitsource.go +++ b/internal/gitsources/gitsource.go @@ -15,6 +15,7 @@ package gitsource import ( + "errors" "net/http" "github.com/sorintlab/agola/internal/services/types" @@ -29,6 +30,8 @@ const ( CommitStatusFailed CommitStatus = "failed" ) +var ErrUnauthorized = errors.New("unauthorized") + type GitSource interface { GetRepoInfo(repopath string) (*RepoInfo, error) GetFile(repopath, commit, file string) ([]byte, error)