2020-10-20 00:35:54 +01:00
|
|
|
// 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 {
|
2021-10-01 12:50:21 +01:00
|
|
|
sendJSONError(w, "project-uuid missing",
|
2020-10-20 00:35:54 +01:00
|
|
|
"", http.StatusBadRequest)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
projectUUID, err := uuid.FromString(projectUUIDString)
|
|
|
|
if err != nil {
|
2021-10-01 12:50:21 +01:00
|
|
|
sendJSONError(w, "invalid project-uuid",
|
2020-10-20 00:35:54 +01:00
|
|
|
err.Error(), http.StatusBadRequest)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
body, err := ioutil.ReadAll(r.Body)
|
|
|
|
if err != nil {
|
2021-10-01 12:50:21 +01:00
|
|
|
sendJSONError(w, "failed to read body",
|
2020-10-20 00:35:54 +01:00
|
|
|
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 {
|
2021-10-01 12:50:21 +01:00
|
|
|
sendJSONError(w, "failed to unmarshal request",
|
2020-10-20 00:35:54 +01:00
|
|
|
err.Error(), http.StatusBadRequest)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if input.Name == "" {
|
2021-10-01 12:50:21 +01:00
|
|
|
sendJSONError(w, "Name is not set",
|
2020-10-20 00:35:54 +01:00
|
|
|
"", http.StatusBadRequest)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
_, err = server.db.Console().APIKeys().GetByNameAndProjectID(ctx, input.Name, projectUUID)
|
|
|
|
if err == nil {
|
2021-10-01 12:50:21 +01:00
|
|
|
sendJSONError(w, "api-key with given name already exists",
|
2020-10-20 00:35:54 +01:00
|
|
|
"", http.StatusConflict)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
secret, err := macaroon.NewSecret()
|
|
|
|
if err != nil {
|
2021-10-01 12:50:21 +01:00
|
|
|
sendJSONError(w, "could not create macaroon secret",
|
2020-10-20 00:35:54 +01:00
|
|
|
err.Error(), http.StatusInternalServerError)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
key, err := macaroon.NewAPIKey(secret)
|
|
|
|
if err != nil {
|
2021-10-01 12:50:21 +01:00
|
|
|
sendJSONError(w, "could not create api-key",
|
2020-10-20 00:35:54 +01:00
|
|
|
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 {
|
2021-10-01 12:50:21 +01:00
|
|
|
sendJSONError(w, "unable to add api-key to database",
|
2020-10-20 00:35:54 +01:00
|
|
|
err.Error(), http.StatusInternalServerError)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
output.APIKey = key.Serialize()
|
|
|
|
data, err := json.Marshal(output)
|
|
|
|
if err != nil {
|
2021-10-01 12:50:21 +01:00
|
|
|
sendJSONError(w, "json encoding failed",
|
2020-10-20 00:35:54 +01:00
|
|
|
err.Error(), http.StatusInternalServerError)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2021-10-01 12:50:21 +01:00
|
|
|
sendJSONData(w, http.StatusOK, data)
|
2020-10-20 00:35:54 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
func (server *Server) deleteAPIKey(w http.ResponseWriter, r *http.Request) {
|
|
|
|
ctx := r.Context()
|
|
|
|
|
|
|
|
vars := mux.Vars(r)
|
|
|
|
apikeyString, ok := vars["apikey"]
|
|
|
|
if !ok {
|
2021-10-01 12:50:21 +01:00
|
|
|
sendJSONError(w, "apikey missing",
|
2020-10-20 00:35:54 +01:00
|
|
|
"", http.StatusBadRequest)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
apikey, err := macaroon.ParseAPIKey(apikeyString)
|
|
|
|
if err != nil {
|
2021-10-01 12:50:21 +01:00
|
|
|
sendJSONError(w, "invalid apikey format",
|
2020-10-20 00:35:54 +01:00
|
|
|
err.Error(), http.StatusBadRequest)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
info, err := server.db.Console().APIKeys().GetByHead(ctx, apikey.Head())
|
|
|
|
if err != nil {
|
2021-10-01 12:50:21 +01:00
|
|
|
sendJSONError(w, "could not get apikey id",
|
2020-10-20 00:35:54 +01:00
|
|
|
err.Error(), http.StatusInternalServerError)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
err = server.db.Console().APIKeys().Delete(ctx, info.ID)
|
|
|
|
if err != nil {
|
2021-10-01 12:50:21 +01:00
|
|
|
sendJSONError(w, "unable to delete apikey",
|
2020-10-20 00:35:54 +01:00
|
|
|
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 {
|
2021-10-01 12:50:21 +01:00
|
|
|
sendJSONError(w, "project-uuid missing",
|
2020-10-20 00:35:54 +01:00
|
|
|
"", http.StatusBadRequest)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
projectUUID, err := uuid.FromString(projectUUIDString)
|
|
|
|
if err != nil {
|
2021-10-01 12:50:21 +01:00
|
|
|
sendJSONError(w, "invalid project-uuid",
|
2020-10-20 00:35:54 +01:00
|
|
|
err.Error(), http.StatusBadRequest)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
apikeyName, ok := vars["name"]
|
|
|
|
if !ok {
|
2021-10-01 12:50:21 +01:00
|
|
|
sendJSONError(w, "apikey name missing",
|
2020-10-20 00:35:54 +01:00
|
|
|
"", http.StatusBadRequest)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
info, err := server.db.Console().APIKeys().GetByNameAndProjectID(ctx, apikeyName, projectUUID)
|
|
|
|
if err != nil {
|
2021-10-01 12:50:21 +01:00
|
|
|
sendJSONError(w, "could not get apikey id",
|
2020-10-20 00:35:54 +01:00
|
|
|
err.Error(), http.StatusInternalServerError)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
err = server.db.Console().APIKeys().Delete(ctx, info.ID)
|
|
|
|
if err != nil {
|
2021-10-01 12:50:21 +01:00
|
|
|
sendJSONError(w, "unable to delete apikey",
|
2020-10-20 00:35:54 +01:00
|
|
|
err.Error(), http.StatusInternalServerError)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
2021-07-30 19:06:36 +01:00
|
|
|
|
|
|
|
func (server *Server) listAPIKeys(w http.ResponseWriter, r *http.Request) {
|
|
|
|
ctx := r.Context()
|
|
|
|
|
|
|
|
vars := mux.Vars(r)
|
|
|
|
projectUUIDString, ok := vars["project"]
|
|
|
|
if !ok {
|
2021-10-01 12:50:21 +01:00
|
|
|
sendJSONError(w, "project-uuid missing",
|
2021-07-30 19:06:36 +01:00
|
|
|
"", http.StatusBadRequest)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
projectUUID, err := uuid.FromString(projectUUIDString)
|
|
|
|
if err != nil {
|
2021-10-01 12:50:21 +01:00
|
|
|
sendJSONError(w, "invalid project-uuid",
|
2021-07-30 19:06:36 +01:00
|
|
|
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 {
|
2021-10-01 12:50:21 +01:00
|
|
|
sendJSONError(w, "failed retrieving a cursor page of API Keys list",
|
2021-07-30 19:06:36 +01:00
|
|
|
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 {
|
2021-10-01 12:50:21 +01:00
|
|
|
sendJSONError(w, "json encoding failed",
|
2021-07-30 19:06:36 +01:00
|
|
|
err.Error(), http.StatusInternalServerError)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-10-01 12:50:21 +01:00
|
|
|
sendJSONData(w, http.StatusOK, data)
|
2021-07-30 19:06:36 +01:00
|
|
|
}
|