satellite/console: create project salt endpoint on satellite web server
Introduces a new endpoint on the satellite web server to get the project's salt. The endpoint utilizes a new console service method GetSalt which in turn calls the project DB GetSalt method if the user is authorized. It returns the project salt bytes as a base64 encoded string in the response. Change-Id: Ia13b5a4b8580e7bdad0dbb98014a276b1c74b46d
This commit is contained in:
parent
fa4af92392
commit
d8fb082f89
69
satellite/console/consoleweb/consoleapi/projects.go
Normal file
69
satellite/console/consoleweb/consoleapi/projects.go
Normal file
@ -0,0 +1,69 @@
|
||||
// Copyright (C) 2021 Storj Labs, Inc.
|
||||
// See LICENSE for copying information.
|
||||
|
||||
package consoleapi
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/zeebo/errs"
|
||||
"go.uber.org/zap"
|
||||
|
||||
"storj.io/common/uuid"
|
||||
"storj.io/storj/satellite/console"
|
||||
)
|
||||
|
||||
// Projects is an api controller that exposes projects related functionality.
|
||||
type Projects struct {
|
||||
log *zap.Logger
|
||||
service *console.Service
|
||||
}
|
||||
|
||||
// NewProjects is a constructor for api analytics controller.
|
||||
func NewProjects(log *zap.Logger, service *console.Service) *Projects {
|
||||
return &Projects{
|
||||
log: log,
|
||||
service: service,
|
||||
}
|
||||
}
|
||||
|
||||
// GetSalt returns the project's salt.
|
||||
func (p *Projects) GetSalt(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
var err error
|
||||
defer mon.Task()(&ctx)(&err)
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
|
||||
idParam, ok := mux.Vars(r)["id"]
|
||||
if !ok {
|
||||
p.serveJSONError(w, http.StatusBadRequest, errs.New("missing id route param"))
|
||||
return
|
||||
}
|
||||
|
||||
id, err := uuid.FromString(idParam)
|
||||
if err != nil {
|
||||
p.serveJSONError(w, http.StatusBadRequest, err)
|
||||
}
|
||||
|
||||
salt, err := p.service.GetSalt(ctx, id)
|
||||
if err != nil {
|
||||
p.serveJSONError(w, http.StatusUnauthorized, err)
|
||||
return
|
||||
}
|
||||
|
||||
b64SaltString := base64.StdEncoding.EncodeToString(salt)
|
||||
|
||||
err = json.NewEncoder(w).Encode(b64SaltString)
|
||||
if err != nil {
|
||||
p.serveJSONError(w, http.StatusInternalServerError, err)
|
||||
}
|
||||
}
|
||||
|
||||
// serveJSONError writes JSON error to response output stream.
|
||||
func (p *Projects) serveJSONError(w http.ResponseWriter, status int, err error) {
|
||||
ServeJSONError(p.log, w, status, err)
|
||||
}
|
@ -4,7 +4,9 @@
|
||||
package consoleweb_test
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
@ -17,6 +19,7 @@ import (
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"storj.io/common/testcontext"
|
||||
"storj.io/common/uuid"
|
||||
"storj.io/storj/private/testplanet"
|
||||
"storj.io/storj/satellite/payments/storjscan/blockchaintest"
|
||||
)
|
||||
@ -362,6 +365,23 @@ func TestProjects(t *testing.T) {
|
||||
require.Equal(t, http.StatusOK, resp.StatusCode)
|
||||
}
|
||||
|
||||
{ // Get_Salt
|
||||
projectID := test.defaultProjectID()
|
||||
id, err := uuid.FromString(projectID)
|
||||
require.NoError(t, err)
|
||||
|
||||
// get salt from endpoint
|
||||
var b64Salt string
|
||||
resp, body := test.request(http.MethodGet, fmt.Sprintf("/projects/%s/salt", test.defaultProjectID()), nil)
|
||||
require.Equal(t, http.StatusOK, resp.StatusCode)
|
||||
require.NoError(t, json.Unmarshal([]byte(body), &b64Salt))
|
||||
|
||||
// get salt from db and base64 encode it
|
||||
salt, err := planet.Satellites[0].DB.Console().Projects().GetSalt(ctx, id)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, b64Salt, base64.StdEncoding.EncodeToString(salt))
|
||||
}
|
||||
|
||||
{ // Get_ProjectInfo
|
||||
resp, body := test.request(http.MethodPost, "/graphql",
|
||||
test.toJSON(map[string]interface{}{
|
||||
|
@ -248,6 +248,12 @@ func NewServer(logger *zap.Logger, config Config, service *console.Service, oidc
|
||||
consoleapi.NewUserManagement(logger, mon, server.service, router, &apiAuth{&server})
|
||||
}
|
||||
|
||||
projectsController := consoleapi.NewProjects(logger, service)
|
||||
router.Handle(
|
||||
"/api/v0/projects/{id}/salt",
|
||||
server.withAuth(http.HandlerFunc(projectsController.GetSalt)),
|
||||
).Methods(http.MethodGet)
|
||||
|
||||
router.HandleFunc("/registrationToken/", server.createRegistrationTokenHandler)
|
||||
router.HandleFunc("/robots.txt", server.seoHandler)
|
||||
|
||||
|
@ -1406,6 +1406,21 @@ func (s *Service) GetProject(ctx context.Context, projectID uuid.UUID) (p *Proje
|
||||
return
|
||||
}
|
||||
|
||||
// GetSalt is a method for querying project salt by id.
|
||||
func (s *Service) GetSalt(ctx context.Context, projectID uuid.UUID) (salt []byte, err error) {
|
||||
defer mon.Task()(&ctx)(&err)
|
||||
user, err := s.getUserAndAuditLog(ctx, "get project salt", zap.String("projectID", projectID.String()))
|
||||
if err != nil {
|
||||
return nil, Error.Wrap(err)
|
||||
}
|
||||
|
||||
if _, err = s.isProjectMember(ctx, user.ID, projectID); err != nil {
|
||||
return nil, Error.Wrap(err)
|
||||
}
|
||||
|
||||
return s.store.Projects().GetSalt(ctx, projectID)
|
||||
}
|
||||
|
||||
// GetUsersProjects is a method for querying all projects.
|
||||
func (s *Service) GetUsersProjects(ctx context.Context) (ps []Project, err error) {
|
||||
defer mon.Task()(&ctx)(&err)
|
||||
|
@ -71,6 +71,18 @@ func TestService(t *testing.T) {
|
||||
require.Nil(t, project)
|
||||
})
|
||||
|
||||
t.Run("GetSalt", func(t *testing.T) {
|
||||
// Getting project salt as a member should work
|
||||
salt, err := service.GetSalt(userCtx1, up1Pro1.ID)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, salt)
|
||||
|
||||
// Getting project salt as a non-member should not work
|
||||
salt, err = service.GetSalt(userCtx1, up2Pro1.ID)
|
||||
require.Error(t, err)
|
||||
require.Nil(t, salt)
|
||||
})
|
||||
|
||||
t.Run("UpdateProject", func(t *testing.T) {
|
||||
updatedName := "newName"
|
||||
updatedDescription := "newDescription"
|
||||
|
Loading…
Reference in New Issue
Block a user