зеркало из https://github.com/Azure/mirrorcat.git
Add GitHub auth token (#7)
* Adding read of default identity * Adding tests, fixing a few residual issues.
This commit is contained in:
Родитель
8333ff65da
Коммит
44d80ce0a9
|
@ -1,6 +1,7 @@
|
|||
package cmd
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
|
@ -9,6 +10,7 @@ import (
|
|||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"sync"
|
||||
"time"
|
||||
|
@ -68,6 +70,20 @@ var startCmd = &cobra.Command{
|
|||
}()
|
||||
}
|
||||
|
||||
if viper.IsSet("github-auth-token") && viper.GetString("github-auth-token") != "" {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
|
||||
defer cancel()
|
||||
|
||||
identity, err := FetchGitHubIdentity(ctx, viper.GetString("github-auth-token"))
|
||||
if err == nil {
|
||||
log.Print("Setting default GitHub identity: ", identity)
|
||||
viper.Set("github-auth-username", identity)
|
||||
} else {
|
||||
log.Println("identity returned:")
|
||||
log.Println("Unable to find identity to match access token because:", err)
|
||||
}
|
||||
}
|
||||
|
||||
if http.ListenAndServe(fmt.Sprintf(":%d", port), nil) != nil {
|
||||
return
|
||||
}
|
||||
|
@ -113,8 +129,16 @@ func init() {
|
|||
startCmd.Flags().StringP("redis-connection", "r", "", "The host to contact Redis with, if it's relevant.")
|
||||
viper.BindPFlag("redis-connection", startCmd.Flags().Lookup("redis-connection"))
|
||||
|
||||
startCmd.Flags().StringP("github-auth-token", "g", "", "The default identity to assume when communicating with GitHub. Mirror configuration overrides this setting.")
|
||||
viper.BindPFlag("github-auth-token", startCmd.Flags().Lookup("github-auth-token"))
|
||||
|
||||
viper.SetDefault("port", DefaultPort)
|
||||
viper.SetDefault("clone-depth", DefaultCloneDepth)
|
||||
|
||||
if prefixlessAuthToken := os.Getenv("GITHUB_AUTH_TOKEN"); !viper.IsSet("github-auth-token") && prefixlessAuthToken != "" {
|
||||
viper.BindEnv("github-auth-token", "GITHUB_AUTH_TOKEN")
|
||||
log.Print(`Using environment variable "GITHUB_AUTH_TOKEN" because "MIRRORCAT_GITHUB_AUTH_TOKEN" wasn't found.`)
|
||||
}
|
||||
}
|
||||
|
||||
func handleGitHubPushEvent(resp http.ResponseWriter, req *http.Request) {
|
||||
|
@ -169,8 +193,24 @@ loop:
|
|||
break loop
|
||||
}
|
||||
|
||||
var hasUser, hasPassword bool
|
||||
repoURL, err := url.Parse(entry.Repository)
|
||||
if err == nil && repoURL.User != nil {
|
||||
hasUser = repoURL.User.Username() != ""
|
||||
_, hasPassword = repoURL.User.Password()
|
||||
}
|
||||
|
||||
if viper.IsSet("github-auth-token") && !hasUser && !hasPassword {
|
||||
repoURL.User = url.UserPassword(viper.GetString("github-auth-username"), viper.GetString("github-auth-token"))
|
||||
}
|
||||
|
||||
entry.Repository = repoURL.String()
|
||||
|
||||
err = mirrorcat.Push(ctx, original, entry, viper.GetInt("clone-depth"))
|
||||
if err == nil {
|
||||
// Strip password information before writing to logs.
|
||||
repoURL.User = nil
|
||||
entry.Repository = repoURL.String()
|
||||
bodyWriter.Encode(WrittenTuple{
|
||||
Original: original,
|
||||
Mirror: entry,
|
||||
|
@ -254,3 +294,47 @@ var populateStaticMirrors = func() func() error {
|
|||
return nil
|
||||
}
|
||||
}()
|
||||
|
||||
// FetchGitHubIdentity uses the
|
||||
func FetchGitHubIdentity(ctx context.Context, token string) (username string, err error) {
|
||||
req, err := http.NewRequest(http.MethodGet, "https://api.github.com/user", &bytes.Buffer{})
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
req = req.WithContext(ctx)
|
||||
req.Header.Add("Accept", "application/vnd.github.jean-grey-preview+json")
|
||||
req.SetBasicAuth("username", token) // The string "username" is arbitrary, and will be disregarded by the server when seeking an identity for a token.
|
||||
|
||||
resp, err := http.DefaultClient.Do(req)
|
||||
if err != nil {
|
||||
return
|
||||
} else if expected := 200; resp.StatusCode != expected {
|
||||
err = fmt.Errorf("response status code (%d) wasn't the expected (%d): %v", resp.StatusCode, expected, resp)
|
||||
return
|
||||
}
|
||||
|
||||
const maxBytes = 5 * 1024 * 1024
|
||||
|
||||
rawBody, err := ioutil.ReadAll(&io.LimitedReader{
|
||||
R: resp.Body,
|
||||
N: maxBytes,
|
||||
})
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
partial := map[string]json.RawMessage{}
|
||||
|
||||
err = json.Unmarshal(rawBody, &partial)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if marshaledName, ok := partial["login"]; ok {
|
||||
err = json.Unmarshal([]byte(marshaledName), &username)
|
||||
} else {
|
||||
err = fmt.Errorf("login filed wasn't presnent in GitHub repsonse, status code %d", resp.StatusCode)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
package cmd_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/spf13/viper"
|
||||
|
||||
"github.com/Azure/mirrorcat/mirrorcat/cmd"
|
||||
)
|
||||
|
||||
func TestFetchIdentity(t *testing.T) {
|
||||
if !viper.IsSet("github-auth-token") || viper.GetString("github-auth-token") == "" {
|
||||
t.Log("Unable to find environment variable defining Auth Token")
|
||||
t.SkipNow()
|
||||
}
|
||||
|
||||
result, err := cmd.FetchGitHubIdentity(context.Background(), viper.GetString("github-auth-token"))
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
} else if result == "" {
|
||||
t.Log("Personal Access Token not associated with any user.")
|
||||
t.Fail()
|
||||
} else {
|
||||
t.Logf("Personal Access Token associated with user %q", result)
|
||||
}
|
||||
|
||||
}
|
Загрузка…
Ссылка в новой задаче