github.com/pelicanplatform/pelican@v1.0.5/namespace_registry/registry_ui.go (about)

     1  /***************************************************************
     2   *
     3   * Copyright (C) 2023, Pelican Project, Morgridge Institute for Research
     4   *
     5   * Licensed under the Apache License, Version 2.0 (the "License"); you
     6   * may not use this file except in compliance with the License.  You may
     7   * obtain a copy of the License at
     8   *
     9   *    http://www.apache.org/licenses/LICENSE-2.0
    10   *
    11   * Unless required by applicable law or agreed to in writing, software
    12   * distributed under the License is distributed on an "AS IS" BASIS,
    13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14   * See the License for the specific language governing permissions and
    15   * limitations under the License.
    16   *
    17   ***************************************************************/
    18  
    19  package nsregistry
    20  
    21  import (
    22  	"encoding/json"
    23  	"fmt"
    24  	"net/http"
    25  	"strconv"
    26  
    27  	"github.com/gin-gonic/gin"
    28  )
    29  
    30  type listNamespaceRequest struct {
    31  	ServerType string `form:"server_type"`
    32  }
    33  
    34  // Exclude pubkey field from marshalling into json
    35  func excludePubKey(nss []*Namespace) (nssNew []NamespaceWOPubkey) {
    36  	nssNew = make([]NamespaceWOPubkey, 0)
    37  	for _, ns := range nss {
    38  		nsNew := NamespaceWOPubkey{
    39  			ID:            ns.ID,
    40  			Prefix:        ns.Prefix,
    41  			Pubkey:        ns.Pubkey,
    42  			AdminMetadata: ns.AdminMetadata,
    43  			Identity:      ns.Identity,
    44  		}
    45  		nssNew = append(nssNew, nsNew)
    46  	}
    47  
    48  	return
    49  }
    50  
    51  func listNamespaces(ctx *gin.Context) {
    52  	queryParams := listNamespaceRequest{}
    53  	if ctx.ShouldBindQuery(&queryParams) != nil {
    54  		ctx.JSON(http.StatusBadRequest, gin.H{"error": "Invalid query parameters"})
    55  		return
    56  	}
    57  
    58  	if queryParams.ServerType != "" {
    59  		if queryParams.ServerType != string(OriginType) && queryParams.ServerType != string(CacheType) {
    60  			ctx.JSON(http.StatusBadRequest, gin.H{"error": "Invalid server type"})
    61  			return
    62  		}
    63  		namespaces, err := getNamespacesByServerType(ServerType(queryParams.ServerType))
    64  		if err != nil {
    65  			ctx.JSON(http.StatusInternalServerError, gin.H{"error": "Server encountered an error trying to list namespaces"})
    66  			return
    67  		}
    68  		nssWOPubkey := excludePubKey(namespaces)
    69  		ctx.JSON(http.StatusOK, nssWOPubkey)
    70  
    71  	} else {
    72  		namespaces, err := getAllNamespaces()
    73  		if err != nil {
    74  			ctx.JSON(http.StatusInternalServerError, gin.H{"error": "Server encountered an error trying to list namespaces"})
    75  			return
    76  		}
    77  		nssWOPubkey := excludePubKey(namespaces)
    78  		ctx.JSON(http.StatusOK, nssWOPubkey)
    79  	}
    80  }
    81  
    82  func getNamespaceJWKS(ctx *gin.Context) {
    83  	idStr := ctx.Param("id")
    84  	id, err := strconv.Atoi(idStr)
    85  	if err != nil || id <= 0 {
    86  		// Handle the error if id is not a valid integer
    87  		ctx.JSON(http.StatusBadRequest, gin.H{"error": "Invalid ID format. ID must a non-zero integer"})
    88  		return
    89  	}
    90  	found, err := namespaceExistsById(id)
    91  	if err != nil {
    92  		ctx.JSON(http.StatusInternalServerError, gin.H{"error": fmt.Sprint("Error checking id:", err)})
    93  		return
    94  	}
    95  	if !found {
    96  		ctx.JSON(http.StatusNotFound, gin.H{"error": "Namespace not found"})
    97  		return
    98  	}
    99  	jwks, err := getPrefixJwksById(id)
   100  	if err != nil {
   101  		ctx.JSON(http.StatusInternalServerError, gin.H{"error": fmt.Sprint("Error getting jwks by id:", err)})
   102  		return
   103  	}
   104  	jsonData, err := json.MarshalIndent(jwks, "", "  ")
   105  	if err != nil {
   106  		ctx.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to marshal JWKS"})
   107  		return
   108  	}
   109  	// Append a new line to the JSON data
   110  	jsonData = append(jsonData, '\n')
   111  	ctx.Header("Content-Disposition", fmt.Sprintf("attachment; filename=public-key-server-%v.jwks", id))
   112  	ctx.Data(200, "application/json", jsonData)
   113  }
   114  
   115  func RegisterNamespacesRegistryWebAPI(router *gin.RouterGroup) {
   116  	registryWebAPI := router.Group("/api/v1.0/registry_ui")
   117  	// Follow RESTful schema
   118  	{
   119  		registryWebAPI.GET("/namespaces", listNamespaces)
   120  		registryWebAPI.GET("/namespaces/:id/pubkey", getNamespaceJWKS)
   121  	}
   122  }