Changeset 0.9.4 (#54)

This commit is contained in:
2026-02-24 10:44:12 +00:00
parent 90021157e6
commit 5e416d3726
26 changed files with 1333 additions and 108 deletions

View File

@@ -50,13 +50,13 @@ func (h *TeamHandler) ListTeamProviders(c *gin.Context) {
configs := make([]teamProvider, 0)
for rows.Next() {
var p teamProvider
var apiKeyEnc *string
var apiKeyEnc []byte
var configRaw string
if err := rows.Scan(&p.ID, &p.Name, &p.Provider, &p.Endpoint, &apiKeyEnc,
&p.ModelDefault, &configRaw, &p.IsActive, &p.IsPrivate, &p.CreatedAt, &p.UpdatedAt); err != nil {
continue
}
p.HasKey = apiKeyEnc != nil && *apiKeyEnc != ""
p.HasKey = len(apiKeyEnc) > 0
p.Config = parseJSONBConfig(configRaw)
configs = append(configs, p)
}
@@ -104,12 +104,29 @@ func (h *TeamHandler) CreateTeamProvider(c *gin.Context) {
configJSON = string(b)
}
// Encrypt the API key for team scope
var apiKeyEnc, keyNonce []byte
if req.APIKey != "" {
if h.vault != nil {
var err error
apiKeyEnc, keyNonce, err = h.vault.EncryptForScope(req.APIKey, "team", "")
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to encrypt API key"})
return
}
} else {
apiKeyEnc = []byte(req.APIKey)
}
}
var id string
err := database.DB.QueryRow(`
INSERT INTO provider_configs (scope, owner_id, name, provider, endpoint, api_key_enc, model_default, config, is_private)
VALUES ('team', $1, $2, $3, $4, $5, $6, $7::jsonb, $8)
INSERT INTO provider_configs (scope, owner_id, name, provider, endpoint,
api_key_enc, key_nonce, key_scope, model_default, config, is_private)
VALUES ('team', $1, $2, $3, $4, $5, $6, 'team', $7, $8::jsonb, $9)
RETURNING id
`, teamID, req.Name, req.Provider, req.Endpoint, req.APIKey, req.ModelDefault, configJSON, req.IsPrivate,
`, teamID, req.Name, req.Provider, req.Endpoint,
apiKeyEnc, keyNonce, req.ModelDefault, configJSON, req.IsPrivate,
).Scan(&id)
if err != nil {
log.Printf("[WARN] Failed to create team provider: %v", err)
@@ -162,10 +179,24 @@ func (h *TeamHandler) UpdateTeamProvider(c *gin.Context) {
args = append(args, *req.Endpoint)
argN++
}
if req.APIKey != nil {
query += ", api_key_enc = $" + strconv.Itoa(argN)
args = append(args, *req.APIKey)
argN++
if req.APIKey != nil && *req.APIKey != "" {
if h.vault != nil {
enc, nonce, err := h.vault.EncryptForScope(*req.APIKey, "team", "")
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to encrypt API key"})
return
}
query += ", api_key_enc = $" + strconv.Itoa(argN)
args = append(args, enc)
argN++
query += ", key_nonce = $" + strconv.Itoa(argN)
args = append(args, nonce)
argN++
} else {
query += ", api_key_enc = $" + strconv.Itoa(argN)
args = append(args, []byte(*req.APIKey))
argN++
}
}
if req.ModelDefault != nil {
query += ", model_default = $" + strconv.Itoa(argN)
@@ -229,13 +260,14 @@ func (h *TeamHandler) ListTeamProviderModels(c *gin.Context) {
providerID := c.Param("id")
var name, providerType, endpoint string
var apiKey *string
var apiKeyEnc, keyNonce []byte
var keyScope string
var headersJSON []byte
err := database.DB.QueryRow(`
SELECT name, provider, endpoint, api_key_enc, headers
SELECT name, provider, endpoint, api_key_enc, key_nonce, key_scope, headers
FROM provider_configs
WHERE id = $1 AND scope = 'team' AND owner_id = $2 AND is_active = true
`, providerID, teamID).Scan(&name, &providerType, &endpoint, &apiKey, &headersJSON)
`, providerID, teamID).Scan(&name, &providerType, &endpoint, &apiKeyEnc, &keyNonce, &keyScope, &headersJSON)
if err != nil {
c.JSON(http.StatusNotFound, gin.H{"error": "provider not found"})
return
@@ -248,8 +280,17 @@ func (h *TeamHandler) ListTeamProviderModels(c *gin.Context) {
}
key := ""
if apiKey != nil {
key = *apiKey
if len(apiKeyEnc) > 0 {
if h.vault != nil {
var err error
key, err = h.vault.Decrypt(apiKeyEnc, keyNonce, keyScope, "")
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to decrypt API key"})
return
}
} else {
key = string(apiKeyEnc)
}
}
var customHeaders map[string]string