storj/satellite/admin/apikeys.go
Ivan Fraixedes fed09316b8
satellite/admin: Use helper for sending JSON
A previous commit added a helper function for sending JSON data back to
the client.

This commit makes use of it for homogenizing the current implementation.

It also renames the existing helper message to send JSON errors to
starts with "send" because the new helper starts with it and they
helpers are clearer with their name starting with it.

Change-Id: I53ee0b4ca33d677a8ccd366c9ba6d73f4f472247
2021-10-04 12:13:04 +02:00

240 lines
5.4 KiB
Go

// Copyright (C) 2020 Storj Labs, Inc.
// See LICENSE for copying information.
package admin
import (
"encoding/json"
"io/ioutil"
"net/http"
"github.com/gorilla/mux"
"storj.io/common/macaroon"
"storj.io/common/uuid"
"storj.io/storj/satellite/console"
)
func (server *Server) addAPIKey(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
vars := mux.Vars(r)
projectUUIDString, ok := vars["project"]
if !ok {
sendJSONError(w, "project-uuid missing",
"", http.StatusBadRequest)
return
}
projectUUID, err := uuid.FromString(projectUUIDString)
if err != nil {
sendJSONError(w, "invalid project-uuid",
err.Error(), http.StatusBadRequest)
return
}
body, err := ioutil.ReadAll(r.Body)
if err != nil {
sendJSONError(w, "failed to read body",
err.Error(), http.StatusInternalServerError)
return
}
var input struct {
PartnerID uuid.UUID `json:"partnerId"`
Name string `json:"name"`
}
var output struct {
APIKey string `json:"apikey"`
}
err = json.Unmarshal(body, &input)
if err != nil {
sendJSONError(w, "failed to unmarshal request",
err.Error(), http.StatusBadRequest)
return
}
if input.Name == "" {
sendJSONError(w, "Name is not set",
"", http.StatusBadRequest)
return
}
_, err = server.db.Console().APIKeys().GetByNameAndProjectID(ctx, input.Name, projectUUID)
if err == nil {
sendJSONError(w, "api-key with given name already exists",
"", http.StatusConflict)
return
}
secret, err := macaroon.NewSecret()
if err != nil {
sendJSONError(w, "could not create macaroon secret",
err.Error(), http.StatusInternalServerError)
return
}
key, err := macaroon.NewAPIKey(secret)
if err != nil {
sendJSONError(w, "could not create api-key",
err.Error(), http.StatusInternalServerError)
return
}
apikey := console.APIKeyInfo{
Name: input.Name,
ProjectID: projectUUID,
Secret: secret,
PartnerID: input.PartnerID,
}
_, err = server.db.Console().APIKeys().Create(ctx, key.Head(), apikey)
if err != nil {
sendJSONError(w, "unable to add api-key to database",
err.Error(), http.StatusInternalServerError)
return
}
output.APIKey = key.Serialize()
data, err := json.Marshal(output)
if err != nil {
sendJSONError(w, "json encoding failed",
err.Error(), http.StatusInternalServerError)
return
}
sendJSONData(w, http.StatusOK, data)
}
func (server *Server) deleteAPIKey(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
vars := mux.Vars(r)
apikeyString, ok := vars["apikey"]
if !ok {
sendJSONError(w, "apikey missing",
"", http.StatusBadRequest)
return
}
apikey, err := macaroon.ParseAPIKey(apikeyString)
if err != nil {
sendJSONError(w, "invalid apikey format",
err.Error(), http.StatusBadRequest)
return
}
info, err := server.db.Console().APIKeys().GetByHead(ctx, apikey.Head())
if err != nil {
sendJSONError(w, "could not get apikey id",
err.Error(), http.StatusInternalServerError)
return
}
err = server.db.Console().APIKeys().Delete(ctx, info.ID)
if err != nil {
sendJSONError(w, "unable to delete apikey",
err.Error(), http.StatusInternalServerError)
return
}
}
func (server *Server) deleteAPIKeyByName(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
vars := mux.Vars(r)
projectUUIDString, ok := vars["project"]
if !ok {
sendJSONError(w, "project-uuid missing",
"", http.StatusBadRequest)
return
}
projectUUID, err := uuid.FromString(projectUUIDString)
if err != nil {
sendJSONError(w, "invalid project-uuid",
err.Error(), http.StatusBadRequest)
return
}
apikeyName, ok := vars["name"]
if !ok {
sendJSONError(w, "apikey name missing",
"", http.StatusBadRequest)
return
}
info, err := server.db.Console().APIKeys().GetByNameAndProjectID(ctx, apikeyName, projectUUID)
if err != nil {
sendJSONError(w, "could not get apikey id",
err.Error(), http.StatusInternalServerError)
return
}
err = server.db.Console().APIKeys().Delete(ctx, info.ID)
if err != nil {
sendJSONError(w, "unable to delete apikey",
err.Error(), http.StatusInternalServerError)
return
}
}
func (server *Server) listAPIKeys(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
vars := mux.Vars(r)
projectUUIDString, ok := vars["project"]
if !ok {
sendJSONError(w, "project-uuid missing",
"", http.StatusBadRequest)
return
}
projectUUID, err := uuid.FromString(projectUUIDString)
if err != nil {
sendJSONError(w, "invalid project-uuid",
err.Error(), http.StatusBadRequest)
return
}
const apiKeysPerPage = 50 // This is the current maximum API Keys per page.
var apiKeys []console.APIKeyInfo
for i := uint(1); true; i++ {
page, err := server.db.Console().APIKeys().GetPagedByProjectID(
ctx, projectUUID, console.APIKeyCursor{
Limit: apiKeysPerPage,
Page: i,
Order: console.KeyName,
OrderDirection: console.Ascending,
},
)
if err != nil {
sendJSONError(w, "failed retrieving a cursor page of API Keys list",
err.Error(), http.StatusInternalServerError,
)
return
}
apiKeys = append(apiKeys, page.APIKeys...)
if len(page.APIKeys) < apiKeysPerPage {
break
}
}
var data []byte
if len(apiKeys) == 0 {
data = []byte("[]")
} else {
data, err = json.Marshal(apiKeys)
if err != nil {
sendJSONError(w, "json encoding failed",
err.Error(), http.StatusInternalServerError)
return
}
}
sendJSONData(w, http.StatusOK, data)
}