diff --git a/src/github.com/matrix-org/go-neb/api/handlers/auth.go b/src/github.com/matrix-org/go-neb/api/handlers/auth.go index e056a1f..8030b09 100644 --- a/src/github.com/matrix-org/go-neb/api/handlers/auth.go +++ b/src/github.com/matrix-org/go-neb/api/handlers/auth.go @@ -40,36 +40,43 @@ type RequestAuthSession struct { // { // // AuthRealm-specific information // } -func (h *RequestAuthSession) OnIncomingRequest(req *http.Request) (interface{}, *util.HTTPError) { +func (h *RequestAuthSession) OnIncomingRequest(req *http.Request) util.JSONResponse { + logger := util.GetLogger(req.Context()) if req.Method != "POST" { - return nil, &util.HTTPError{nil, "Unsupported Method", 405} + return util.MessageResponse(405, "Unsupported Method") } var body api.RequestAuthSessionRequest if err := json.NewDecoder(req.Body).Decode(&body); err != nil { - return nil, &util.HTTPError{err, "Error parsing request JSON", 400} + return util.MessageResponse(400, "Error parsing request JSON") } - log.WithFields(log.Fields{ + logger.WithFields(log.Fields{ "realm_id": body.RealmID, "user_id": body.UserID, }).Print("Incoming auth session request") if err := body.Check(); err != nil { - return nil, &util.HTTPError{err, err.Error(), 400} + logger.WithError(err).Info("Failed Check") + return util.MessageResponse(400, err.Error()) } realm, err := h.Db.LoadAuthRealm(body.RealmID) if err != nil { - return nil, &util.HTTPError{err, "Unknown RealmID", 400} + logger.WithError(err).Info("Failed to LoadAuthRealm") + return util.MessageResponse(400, "Unknown RealmID") } response := realm.RequestAuthSession(body.UserID, body.Config) if response == nil { - return nil, &util.HTTPError{nil, "Failed to request auth session", 500} + logger.WithField("body", body).Error("Failed to RequestAuthSession") + return util.MessageResponse(500, "Failed to request auth session") } metrics.IncrementAuthSession(realm.Type()) - return response, nil + return util.JSONResponse{ + Code: 200, + JSON: response, + } } // RemoveAuthSession represents an HTTP handler capable of processing /admin/removeAuthSession requests. @@ -90,36 +97,41 @@ type RemoveAuthSession struct { // Response: // HTTP/1.1 200 OK // {} -func (h *RemoveAuthSession) OnIncomingRequest(req *http.Request) (interface{}, *util.HTTPError) { +func (h *RemoveAuthSession) OnIncomingRequest(req *http.Request) util.JSONResponse { + logger := util.GetLogger(req.Context()) if req.Method != "POST" { - return nil, &util.HTTPError{nil, "Unsupported Method", 405} + return util.MessageResponse(405, "Unsupported Method") } var body struct { RealmID string UserID string } if err := json.NewDecoder(req.Body).Decode(&body); err != nil { - return nil, &util.HTTPError{err, "Error parsing request JSON", 400} + return util.MessageResponse(400, "Error parsing request JSON") } - log.WithFields(log.Fields{ + logger.WithFields(log.Fields{ "realm_id": body.RealmID, "user_id": body.UserID, }).Print("Incoming remove auth session request") if body.UserID == "" || body.RealmID == "" { - return nil, &util.HTTPError{nil, `Must supply a "UserID", a "RealmID"`, 400} + return util.MessageResponse(400, `Must supply a "UserID", a "RealmID"`) } _, err := h.Db.LoadAuthRealm(body.RealmID) if err != nil { - return nil, &util.HTTPError{err, "Unknown RealmID", 400} + return util.MessageResponse(400, "Unknown RealmID") } if err := h.Db.RemoveAuthSession(body.RealmID, body.UserID); err != nil { - return nil, &util.HTTPError{err, "Failed to remove auth session", 500} + logger.WithError(err).Error("Failed to RemoveAuthSession") + return util.MessageResponse(500, "Failed to remove auth session") } - return []byte(`{}`), nil + return util.JSONResponse{ + Code: 200, + JSON: struct{}{}, + } } // RealmRedirect represents an HTTP handler which can process incoming redirects for auth realms. @@ -186,39 +198,44 @@ type ConfigureAuthRealm struct { // // New auth realm config information // }, // } -func (h *ConfigureAuthRealm) OnIncomingRequest(req *http.Request) (interface{}, *util.HTTPError) { +func (h *ConfigureAuthRealm) OnIncomingRequest(req *http.Request) util.JSONResponse { + logger := util.GetLogger(req.Context()) if req.Method != "POST" { - return nil, &util.HTTPError{nil, "Unsupported Method", 405} + return util.MessageResponse(405, "Unsupported Method") } var body api.ConfigureAuthRealmRequest if err := json.NewDecoder(req.Body).Decode(&body); err != nil { - return nil, &util.HTTPError{err, "Error parsing request JSON", 400} + return util.MessageResponse(400, "Error parsing request JSON") } if err := body.Check(); err != nil { - return nil, &util.HTTPError{err, err.Error(), 400} + return util.MessageResponse(400, err.Error()) } realm, err := types.CreateAuthRealm(body.ID, body.Type, body.Config) if err != nil { - return nil, &util.HTTPError{err, "Error parsing config JSON", 400} + return util.MessageResponse(400, "Error parsing config JSON") } if err = realm.Register(); err != nil { - return nil, &util.HTTPError{err, "Error registering auth realm", 400} + return util.MessageResponse(400, "Error registering auth realm") } oldRealm, err := h.Db.StoreAuthRealm(realm) if err != nil { - return nil, &util.HTTPError{err, "Error storing realm", 500} + logger.WithError(err).Error("Failed to StoreAuthRealm") + return util.MessageResponse(500, "Error storing realm") } - return &struct { - ID string - Type string - OldConfig types.AuthRealm - NewConfig types.AuthRealm - }{body.ID, body.Type, oldRealm, realm}, nil + return util.JSONResponse{ + Code: 200, + JSON: struct { + ID string + Type string + OldConfig types.AuthRealm + NewConfig types.AuthRealm + }{body.ID, body.Type, oldRealm, realm}, + } } // GetSession represents an HTTP handler capable of processing /admin/getSession requests. @@ -252,35 +269,43 @@ type GetSession struct { // { // "Authenticated": false // } -func (h *GetSession) OnIncomingRequest(req *http.Request) (interface{}, *util.HTTPError) { +func (h *GetSession) OnIncomingRequest(req *http.Request) util.JSONResponse { + logger := util.GetLogger(req.Context()) if req.Method != "POST" { - return nil, &util.HTTPError{nil, "Unsupported Method", 405} + return util.MessageResponse(405, "Unsupported Method") } var body struct { RealmID string UserID string } if err := json.NewDecoder(req.Body).Decode(&body); err != nil { - return nil, &util.HTTPError{err, "Error parsing request JSON", 400} + return util.MessageResponse(400, "Error parsing request JSON") } if body.RealmID == "" || body.UserID == "" { - return nil, &util.HTTPError{nil, `Must supply a "RealmID" and "UserID"`, 400} + return util.MessageResponse(400, `Must supply a "RealmID" and "UserID"`) } session, err := h.Db.LoadAuthSessionByUser(body.RealmID, body.UserID) if err != nil && err != sql.ErrNoRows { - return nil, &util.HTTPError{err, `Failed to load session`, 500} + logger.WithError(err).WithField("body", body).Error("Failed to LoadAuthSessionByUser") + return util.MessageResponse(500, `Failed to load session`) } if err == sql.ErrNoRows { - return &struct { - Authenticated bool - }{false}, nil + return util.JSONResponse{ + Code: 200, + JSON: struct { + Authenticated bool + }{false}, + } } - return &struct { - ID string - Authenticated bool - Info interface{} - }{session.ID(), session.Authenticated(), session.Info()}, nil + return util.JSONResponse{ + Code: 200, + JSON: struct { + ID string + Authenticated bool + Info interface{} + }{session.ID(), session.Authenticated(), session.Info()}, + } } diff --git a/src/github.com/matrix-org/go-neb/api/handlers/client.go b/src/github.com/matrix-org/go-neb/api/handlers/client.go index 5327ae8..3e00a20 100644 --- a/src/github.com/matrix-org/go-neb/api/handlers/client.go +++ b/src/github.com/matrix-org/go-neb/api/handlers/client.go @@ -39,27 +39,31 @@ type ConfigureClient struct { // // The new api.ClientConfig // } // } -func (s *ConfigureClient) OnIncomingRequest(req *http.Request) (interface{}, *util.HTTPError) { +func (s *ConfigureClient) OnIncomingRequest(req *http.Request) util.JSONResponse { if req.Method != "POST" { - return nil, &util.HTTPError{nil, "Unsupported Method", 405} + return util.MessageResponse(405, "Unsupported Method") } var body api.ClientConfig if err := json.NewDecoder(req.Body).Decode(&body); err != nil { - return nil, &util.HTTPError{err, "Error parsing request JSON", 400} + return util.MessageResponse(400, "Error parsing request JSON") } if err := body.Check(); err != nil { - return nil, &util.HTTPError{err, "Error parsing client config", 400} + return util.MessageResponse(400, "Error parsing client config") } oldClient, err := s.Clients.Update(body) if err != nil { - return nil, &util.HTTPError{err, "Error storing token", 500} + util.GetLogger(req.Context()).WithError(err).WithField("body", body).Error("Failed to Clients.Update") + return util.MessageResponse(500, "Error storing token") } - return &struct { - OldClient api.ClientConfig - NewClient api.ClientConfig - }{oldClient, body}, nil + return util.JSONResponse{ + Code: 200, + JSON: struct { + OldClient api.ClientConfig + NewClient api.ClientConfig + }{oldClient, body}, + } } diff --git a/src/github.com/matrix-org/go-neb/api/handlers/heartbeat.go b/src/github.com/matrix-org/go-neb/api/handlers/heartbeat.go index 484814b..c110139 100644 --- a/src/github.com/matrix-org/go-neb/api/handlers/heartbeat.go +++ b/src/github.com/matrix-org/go-neb/api/handlers/heartbeat.go @@ -26,6 +26,9 @@ type Heartbeat struct{} // Response: // HTTP/1.1 200 OK // {} -func (*Heartbeat) OnIncomingRequest(req *http.Request) (interface{}, *util.HTTPError) { - return &struct{}{}, nil +func (*Heartbeat) OnIncomingRequest(req *http.Request) util.JSONResponse { + return util.JSONResponse{ + Code: 200, + JSON: struct{}{}, + } } diff --git a/src/github.com/matrix-org/go-neb/api/handlers/service.go b/src/github.com/matrix-org/go-neb/api/handlers/service.go index 6cd3fd4..d088d63 100644 --- a/src/github.com/matrix-org/go-neb/api/handlers/service.go +++ b/src/github.com/matrix-org/go-neb/api/handlers/service.go @@ -76,16 +76,17 @@ func (s *ConfigureService) getMutexForServiceID(serviceID string) *sync.Mutex { // // new service-specific config information // }, // } -func (s *ConfigureService) OnIncomingRequest(req *http.Request) (interface{}, *util.HTTPError) { +func (s *ConfigureService) OnIncomingRequest(req *http.Request) util.JSONResponse { if req.Method != "POST" { - return nil, &util.HTTPError{nil, "Unsupported Method", 405} + return util.MessageResponse(405, "Unsupported Method") } service, httpErr := s.createService(req) if httpErr != nil { - return nil, httpErr + return *httpErr } - log.WithFields(log.Fields{ + logger := util.GetLogger(req.Context()) + logger.WithFields(log.Fields{ "service_id": service.ServiceID(), "service_type": service.ServiceType(), "service_user_id": service.ServiceUserID(), @@ -98,32 +99,34 @@ func (s *ConfigureService) OnIncomingRequest(req *http.Request) (interface{}, *u old, err := s.db.LoadService(service.ServiceID()) if err != nil && err != sql.ErrNoRows { - return nil, &util.HTTPError{err, "Error loading old service", 500} + logger.WithError(err).Error("Failed to LoadService") + return util.MessageResponse(500, "Error loading old service") } client, err := s.clients.Client(service.ServiceUserID()) if err != nil { - return nil, &util.HTTPError{err, "Unknown matrix client", 400} + return util.MessageResponse(400, "Unknown matrix client") } if err := checkClientForService(service, client); err != nil { - return nil, &util.HTTPError{err, err.Error(), 400} + return util.MessageResponse(400, err.Error()) } if err = service.Register(old, client); err != nil { - return nil, &util.HTTPError{err, "Failed to register service: " + err.Error(), 500} + return util.MessageResponse(500, "Failed to register service: "+err.Error()) } oldService, err := s.db.StoreService(service) if err != nil { - return nil, &util.HTTPError{err, "Error storing service", 500} + logger.WithError(err).Error("Failed to StoreService") + return util.MessageResponse(500, "Error storing service") } // Start any polling NOW because they may decide to stop it in PostRegister, and we want to make // sure we'll actually stop. if _, ok := service.(types.Poller); ok { if err := polling.StartPolling(service); err != nil { - log.WithFields(log.Fields{ + logger.WithFields(log.Fields{ "service_id": service.ServiceID(), log.ErrorKey: err, }).Error("Failed to start poll loop.") @@ -133,27 +136,33 @@ func (s *ConfigureService) OnIncomingRequest(req *http.Request) (interface{}, *u service.PostRegister(old) metrics.IncrementConfigureService(service.ServiceType()) - return &struct { - ID string - Type string - OldConfig types.Service - NewConfig types.Service - }{service.ServiceID(), service.ServiceType(), oldService, service}, nil + return util.JSONResponse{ + Code: 200, + JSON: struct { + ID string + Type string + OldConfig types.Service + NewConfig types.Service + }{service.ServiceID(), service.ServiceType(), oldService, service}, + } } -func (s *ConfigureService) createService(req *http.Request) (types.Service, *util.HTTPError) { +func (s *ConfigureService) createService(req *http.Request) (types.Service, *util.JSONResponse) { var body api.ConfigureServiceRequest if err := json.NewDecoder(req.Body).Decode(&body); err != nil { - return nil, &util.HTTPError{err, "Error parsing request JSON", 400} + res := util.MessageResponse(400, "Error parsing request JSON") + return nil, &res } if err := body.Check(); err != nil { - return nil, &util.HTTPError{err, err.Error(), 400} + res := util.MessageResponse(400, err.Error()) + return nil, &res } service, err := types.CreateService(body.ID, body.Type, body.UserID, body.Config) if err != nil { - return nil, &util.HTTPError{err, "Error parsing config JSON", 400} + res := util.MessageResponse(400, "Error parsing config JSON") + return nil, &res } return service, nil } @@ -182,34 +191,38 @@ type GetService struct { // // service-specific config information // } // } -func (h *GetService) OnIncomingRequest(req *http.Request) (interface{}, *util.HTTPError) { +func (h *GetService) OnIncomingRequest(req *http.Request) util.JSONResponse { if req.Method != "POST" { - return nil, &util.HTTPError{nil, "Unsupported Method", 405} + return util.MessageResponse(405, "Unsupported Method") } var body struct { ID string } if err := json.NewDecoder(req.Body).Decode(&body); err != nil { - return nil, &util.HTTPError{err, "Error parsing request JSON", 400} + return util.MessageResponse(400, "Error parsing request JSON") } if body.ID == "" { - return nil, &util.HTTPError{nil, `Must supply a "ID"`, 400} + return util.MessageResponse(400, `Must supply a "ID"`) } srv, err := h.Db.LoadService(body.ID) if err != nil { if err == sql.ErrNoRows { - return nil, &util.HTTPError{err, `Service not found`, 404} + return util.MessageResponse(404, `Service not found`) } - return nil, &util.HTTPError{err, `Failed to load service`, 500} + util.GetLogger(req.Context()).WithError(err).Error("Failed to LoadService") + return util.MessageResponse(500, `Failed to load service`) } - return &struct { - ID string - Type string - Config types.Service - }{srv.ServiceID(), srv.ServiceType(), srv}, nil + return util.JSONResponse{ + Code: 200, + JSON: struct { + ID string + Type string + Config types.Service + }{srv.ServiceID(), srv.ServiceType(), srv}, + } } func checkClientForService(service types.Service, client *gomatrix.Client) error { diff --git a/src/github.com/matrix-org/go-neb/services/github/webhook/webhook.go b/src/github.com/matrix-org/go-neb/services/github/webhook/webhook.go index ed510d4..c7cb5de 100644 --- a/src/github.com/matrix-org/go-neb/services/github/webhook/webhook.go +++ b/src/github.com/matrix-org/go-neb/services/github/webhook/webhook.go @@ -21,14 +21,15 @@ import ( // matrix message to send, along with parsed repo information. // The secretToken, if supplied, will be used to verify the request is from // Github. If it isn't, an error is returned. -func OnReceiveRequest(r *http.Request, secretToken string) (string, *github.Repository, *gomatrix.HTMLMessage, *util.HTTPError) { +func OnReceiveRequest(r *http.Request, secretToken string) (string, *github.Repository, *gomatrix.HTMLMessage, *util.JSONResponse) { // Verify the HMAC signature if NEB was configured with a secret token eventType := r.Header.Get("X-GitHub-Event") signatureSHA1 := r.Header.Get("X-Hub-Signature") content, err := ioutil.ReadAll(r.Body) if err != nil { log.WithError(err).Print("Failed to read Github webhook body") - return "", nil, nil, &util.HTTPError{nil, "Failed to parse body", 400} + resErr := util.MessageResponse(400, "Failed to parse body") + return "", nil, nil, &resErr } // Verify request if a secret token has been supplied. if secretToken != "" { @@ -38,14 +39,16 @@ func OnReceiveRequest(r *http.Request, secretToken string) (string, *github.Repo if err != nil { log.WithError(err).WithField("X-Hub-Signature", sigHex).Print( "Failed to decode signature as hex.") - return "", nil, nil, &util.HTTPError{nil, "Failed to decode signature", 400} + resErr := util.MessageResponse(400, "Failed to decode signature") + return "", nil, nil, &resErr } if !checkMAC([]byte(content), sigBytes, []byte(secretToken)) { log.WithFields(log.Fields{ "X-Hub-Signature": signatureSHA1, }).Print("Received Github event which failed MAC check.") - return "", nil, nil, &util.HTTPError{nil, "Bad signature", 403} + resErr := util.MessageResponse(403, "Bad signature") + return "", nil, nil, &resErr } } @@ -58,13 +61,15 @@ func OnReceiveRequest(r *http.Request, secretToken string) (string, *github.Repo // Github will send a "ping" event when the webhook is first created. We need // to return a 200 in order for the webhook to be marked as "up" (this doesn't // affect delivery, just the tick/cross status flag). - return "", nil, nil, &util.HTTPError{nil, "pong", 200} + res := util.MessageResponse(200, "pong") + return "", nil, nil, &res } htmlStr, repo, refinedType, err := parseGithubEvent(eventType, content) if err != nil { log.WithError(err).Print("Failed to parse github event") - return "", nil, nil, &util.HTTPError{nil, "Failed to parse github event", 500} + resErr := util.MessageResponse(500, "Failed to parse github event") + return "", nil, nil, &resErr } msg := gomatrix.GetHTMLMessage("m.notice", htmlStr) diff --git a/src/github.com/matrix-org/go-neb/services/jira/jira.go b/src/github.com/matrix-org/go-neb/services/jira/jira.go index d4e8735..647c9d9 100644 --- a/src/github.com/matrix-org/go-neb/services/jira/jira.go +++ b/src/github.com/matrix-org/go-neb/services/jira/jira.go @@ -271,8 +271,8 @@ func (s *Service) Expansions(cli *gomatrix.Client) []types.Expansion { func (s *Service) OnReceiveWebhook(w http.ResponseWriter, req *http.Request, cli *gomatrix.Client) { eventProjectKey, event, httpErr := webhook.OnReceiveRequest(req) if httpErr != nil { - log.WithError(httpErr).Print("Failed to handle JIRA webhook") - w.WriteHeader(500) + log.Print("Failed to handle JIRA webhook") + w.WriteHeader(httpErr.Code) return } // grab base jira url diff --git a/src/github.com/matrix-org/go-neb/services/jira/webhook/webhook.go b/src/github.com/matrix-org/go-neb/services/jira/webhook/webhook.go index 4aa45a9..ff15f7f 100644 --- a/src/github.com/matrix-org/go-neb/services/jira/webhook/webhook.go +++ b/src/github.com/matrix-org/go-neb/services/jira/webhook/webhook.go @@ -65,19 +65,19 @@ func RegisterHook(jrealm *jira.Realm, projects []string, userID, webhookEndpoint logger.WithError(err).Print("No JIRA client exists") return err // no OAuth token on this JIRA endpoint } - wh, httpErr := getWebhook(cli, webhookEndpointURL) - if httpErr != nil { - if httpErr.Code != 403 { - logger.WithError(httpErr).Print("Failed to GET webhook") - return httpErr + wh, forbidden, err := getWebhook(cli, webhookEndpointURL) + if err != nil { + if !forbidden { + logger.WithError(err).Print("Failed to GET webhook") + return err } // User is not a JIRA admin (cannot GET webhooks) // The only way this is going to end well for this request is if all the projects // are PUBLIC. That is, they can be accessed directly without an access token. - httpErr = checkProjectsArePublic(jrealm, projects, userID) - if httpErr != nil { - logger.WithError(httpErr).Print("Failed to assert that all projects are public") - return httpErr + err = checkProjectsArePublic(jrealm, projects, userID) + if err != nil { + logger.WithError(err).Print("Failed to assert that all projects are public") + return err } // All projects that wish to be tracked are public, but the user cannot create @@ -101,17 +101,19 @@ func RegisterHook(jrealm *jira.Realm, projects []string, userID, webhookEndpoint // OnReceiveRequest is called when JIRA hits NEB with an update. // Returns the project key and webhook event, or an error. -func OnReceiveRequest(req *http.Request) (string, *Event, *util.HTTPError) { +func OnReceiveRequest(req *http.Request) (string, *Event, *util.JSONResponse) { // extract the JIRA webhook event JSON defer req.Body.Close() var whe Event err := json.NewDecoder(req.Body).Decode(&whe) if err != nil { - return "", nil, &util.HTTPError{err, "Failed to parse request JSON", 400} + resErr := util.MessageResponse(400, "Failed to parse request JSON") + return "", nil, &resErr } if err != nil { - return "", nil, &util.HTTPError{err, "Failed to parse JIRA URL", 400} + resErr := util.MessageResponse(400, "Failed to parse JIRA URL") + return "", nil, &resErr } projKey := strings.Split(whe.Issue.Key, "-")[0] projKey = strings.ToUpper(projKey) @@ -153,22 +155,18 @@ func createWebhook(jrealm *jira.Realm, webhookEndpointURL, userID string) error return err } -func getWebhook(cli *gojira.Client, webhookEndpointURL string) (*jiraWebhook, *util.HTTPError) { +func getWebhook(cli *gojira.Client, webhookEndpointURL string) (*jiraWebhook, bool, error) { req, err := cli.NewRequest("GET", "rest/webhooks/1.0/webhook", nil) if err != nil { - return nil, &util.HTTPError{err, "Failed to prepare webhook request", 500} + return nil, false, fmt.Errorf("Failed to prepare webhook request") } var webhookList []jiraWebhook res, err := cli.Do(req, &webhookList) if err != nil { - return nil, &util.HTTPError{err, "Failed to query webhooks", 502} + return nil, false, fmt.Errorf("Failed to query webhooks") } if res.StatusCode < 200 || res.StatusCode >= 300 { - return nil, &util.HTTPError{ - err, - fmt.Sprintf("Querying webhook returned HTTP %d", res.StatusCode), - 403, - } + return nil, true, fmt.Errorf("Querying webhook returned HTTP %d", res.StatusCode) } log.Print("Retrieved ", len(webhookList), " webhooks") var nebWH *jiraWebhook @@ -178,26 +176,26 @@ func getWebhook(cli *gojira.Client, webhookEndpointURL string) (*jiraWebhook, *u break } } - return nebWH, nil + return nebWH, false, nil } -func checkProjectsArePublic(jrealm *jira.Realm, projects []string, userID string) *util.HTTPError { +func checkProjectsArePublic(jrealm *jira.Realm, projects []string, userID string) error { publicCli, err := jrealm.JIRAClient("", true) if err != nil { - return &util.HTTPError{err, "Cannot create public JIRA client", 500} + return fmt.Errorf("Cannot create public JIRA client") } for _, projectKey := range projects { // check you can query this project with a public client req, err := publicCli.NewRequest("GET", "rest/api/2/project/"+projectKey, nil) if err != nil { - return &util.HTTPError{err, "Failed to create project URL", 500} + return fmt.Errorf("Failed to create project URL for project %s", projectKey) } res, err := publicCli.Do(req, nil) if err != nil { - return &util.HTTPError{err, fmt.Sprintf("Failed to query project %s", projectKey), 500} + return fmt.Errorf("Failed to query project %s", projectKey) } if res.StatusCode < 200 || res.StatusCode >= 300 { - return &util.HTTPError{err, fmt.Sprintf("Project %s is not public. (HTTP %d)", projectKey, res.StatusCode), 403} + return fmt.Errorf("Project %s is not public. (HTTP %d)", projectKey, res.StatusCode) } } return nil