in backend/plugins/github/api/connection.go [71:204]
func TestConnection(input *plugin.ApiResourceInput) (*plugin.ApiResourceOutput, errors.Error) {
// process input
var conn models.GithubConn
e := mapstructure.Decode(input.Body, &conn)
if e != nil {
return nil, errors.Convert(e)
}
e = vld.StructExcept(conn, "GithubAppKey", "GithubAccessToken")
if e != nil {
return nil, errors.Convert(e)
}
apiClient, err := api.NewApiClientFromConnection(context.TODO(), basicRes, &conn)
if err != nil {
return nil, err
}
githubApiResponse := &GithubTestConnResponse{}
if conn.AuthMethod == "AppKey" {
jwt, err := conn.GithubAppKey.CreateJwt()
if err != nil {
return nil, err
}
res, err := apiClient.Get("app", nil, http.Header{
"Authorization": []string{fmt.Sprintf("Bearer %s", jwt)},
})
if err != nil {
return nil, errors.BadInput.Wrap(err, "verify token failed")
}
if res.StatusCode != http.StatusOK {
return nil, errors.HttpStatus(res.StatusCode).New("unexpected status code while testing connection")
}
githubApp := &models.GithubApp{}
err = api.UnmarshalResponse(res, githubApp)
if err != nil {
return nil, errors.BadInput.Wrap(err, "verify token failed")
} else if githubApp.Slug == "" {
return nil, errors.BadInput.Wrap(err, "invalid token")
}
res, err = apiClient.Get("app/installations", nil, http.Header{
"Authorization": []string{fmt.Sprintf("Bearer %s", jwt)},
})
if err != nil {
return nil, errors.BadInput.Wrap(err, "verify token failed")
}
if res.StatusCode != http.StatusOK {
return nil, errors.HttpStatus(res.StatusCode).New("unexpected status code while testing connection")
}
githubAppInstallations := &[]models.GithubAppInstallation{}
err = api.UnmarshalResponse(res, githubAppInstallations)
if err != nil {
return nil, errors.BadInput.Wrap(err, "verify token failed")
}
githubApiResponse.Success = true
githubApiResponse.Message = "success"
githubApiResponse.Login = githubApp.Slug
githubApiResponse.Installations = *githubAppInstallations
} else if conn.AuthMethod == "AccessToken" {
res, err := apiClient.Get("user", nil, nil)
if err != nil {
return nil, errors.BadInput.Wrap(err, "verify token failed")
}
if res.StatusCode == http.StatusUnauthorized {
return nil, errors.HttpStatus(http.StatusBadRequest).New("StatusUnauthorized error when testing connection")
}
if res.StatusCode != http.StatusOK {
return nil, errors.HttpStatus(res.StatusCode).New("unexpected status code while testing connection")
}
githubUserOfToken := &models.GithubUserOfToken{}
err = api.UnmarshalResponse(res, githubUserOfToken)
if err != nil {
return nil, errors.BadInput.Wrap(err, "verify token failed")
} else if githubUserOfToken.Login == "" {
return nil, errors.BadInput.Wrap(err, "invalid token")
}
success := false
warning := false
messages := []string{}
// for github classic token, check permission
if strings.HasPrefix(conn.Token, "ghp_") {
scopes := res.Header.Get("X-OAuth-Scopes")
// convert "X-OAuth-Scopes" header to user permissions map
userPerms := map[string]bool{}
for _, userPerm := range strings.Split(scopes, ", ") {
userPerms[userPerm] = true
}
// check public repo permission
missingPubPerms := findMissingPerms(userPerms, publicPermissions)
success = len(missingPubPerms) == 0
if !success {
messages = append(messages, fmt.Sprintf(
"Please check the field(s) %s",
strings.Join(missingPubPerms, ", "),
))
}
// check private repo permission
missingPriPerms := findMissingPerms(userPerms, privatePermissions)
warning = len(missingPriPerms) > 0
if warning {
msgFmt := "If you want to collect private repositories, please check the field(s) %s"
if success {
// @Startrekzky and @yumengwang03 firmly believe that this is critical for users to understand the message
msgFmt = "This token is able to collect public repositories. " + msgFmt
}
messages = append(messages, fmt.Sprintf(
msgFmt,
strings.Join(missingPriPerms, ", "),
))
}
}
githubApiResponse.Success = success
githubApiResponse.Warning = warning
githubApiResponse.Message = strings.Join(messages, ";\n")
githubApiResponse.Login = githubUserOfToken.Login
} else {
return nil, errors.BadInput.New("invalid authentication method")
}
return &plugin.ApiResourceOutput{Body: githubApiResponse, Status: http.StatusOK}, nil
}