package api import ( "net/http" "strings" "github.com/ez-api/ez-api/internal/model" "github.com/ez-api/ez-api/internal/service" "github.com/gin-gonic/gin" ) type MasterHandler struct { masterService *service.MasterService syncService *service.SyncService } func NewMasterHandler(masterService *service.MasterService, syncService *service.SyncService) *MasterHandler { return &MasterHandler{masterService: masterService, syncService: syncService} } type IssueChildKeyRequest struct { Group string `json:"group"` Scopes string `json:"scopes"` } func (h *MasterHandler) IssueChildKey(c *gin.Context) { master, exists := c.Get("master") if !exists { c.JSON(http.StatusUnauthorized, gin.H{"error": "master key not found in context"}) return } masterModel := master.(*model.Master) var req IssueChildKeyRequest if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } // If group is not specified, inherit from master group := req.Group if strings.TrimSpace(group) == "" { group = masterModel.Group } // Security: Ensure the requested group is allowed for this master. // For now, we'll just enforce it's the same group. if group != masterModel.Group { c.JSON(http.StatusForbidden, gin.H{"error": "cannot issue key for a different group"}) return } key, rawChildKey, err := h.masterService.IssueChildKey(masterModel.ID, group, req.Scopes) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to issue child key", "details": err.Error()}) return } if err := h.syncService.SyncKey(key); err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to sync child key", "details": err.Error()}) return } c.JSON(http.StatusCreated, gin.H{ "id": key.ID, "key_secret": rawChildKey, "group": key.Group, "scopes": key.Scopes, }) }