e50cabac4b
- Updated all references from v6 to v7 for `github.com/router-for-me/CLIProxyAPI`. - Ensured consistency in imports within core libraries, tests, and integration tests. - Added missing tests for new features in Redis Protocol integration.
157 lines
3.8 KiB
Go
157 lines
3.8 KiB
Go
package management
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"io"
|
|
"net/http"
|
|
"strings"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
"github.com/router-for-me/CLIProxyAPI/v7/internal/auth/vertex"
|
|
coreauth "github.com/router-for-me/CLIProxyAPI/v7/sdk/cliproxy/auth"
|
|
)
|
|
|
|
// ImportVertexCredential handles uploading a Vertex service account JSON and saving it as an auth record.
|
|
func (h *Handler) ImportVertexCredential(c *gin.Context) {
|
|
if h == nil || h.cfg == nil {
|
|
c.JSON(http.StatusServiceUnavailable, gin.H{"error": "config unavailable"})
|
|
return
|
|
}
|
|
if h.cfg.AuthDir == "" {
|
|
c.JSON(http.StatusServiceUnavailable, gin.H{"error": "auth directory not configured"})
|
|
return
|
|
}
|
|
|
|
fileHeader, err := c.FormFile("file")
|
|
if err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": "file required"})
|
|
return
|
|
}
|
|
|
|
file, err := fileHeader.Open()
|
|
if err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": fmt.Sprintf("failed to read file: %v", err)})
|
|
return
|
|
}
|
|
defer file.Close()
|
|
|
|
data, err := io.ReadAll(file)
|
|
if err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": fmt.Sprintf("failed to read file: %v", err)})
|
|
return
|
|
}
|
|
|
|
var serviceAccount map[string]any
|
|
if err := json.Unmarshal(data, &serviceAccount); err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid json", "message": err.Error()})
|
|
return
|
|
}
|
|
|
|
normalizedSA, err := vertex.NormalizeServiceAccountMap(serviceAccount)
|
|
if err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid service account", "message": err.Error()})
|
|
return
|
|
}
|
|
serviceAccount = normalizedSA
|
|
|
|
projectID := strings.TrimSpace(valueAsString(serviceAccount["project_id"]))
|
|
if projectID == "" {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": "project_id missing"})
|
|
return
|
|
}
|
|
email := strings.TrimSpace(valueAsString(serviceAccount["client_email"]))
|
|
|
|
location := strings.TrimSpace(c.PostForm("location"))
|
|
if location == "" {
|
|
location = strings.TrimSpace(c.Query("location"))
|
|
}
|
|
if location == "" {
|
|
location = "us-central1"
|
|
}
|
|
|
|
fileName := fmt.Sprintf("vertex-%s.json", sanitizeVertexFilePart(projectID))
|
|
label := labelForVertex(projectID, email)
|
|
storage := &vertex.VertexCredentialStorage{
|
|
ServiceAccount: serviceAccount,
|
|
ProjectID: projectID,
|
|
Email: email,
|
|
Location: location,
|
|
Type: "vertex",
|
|
}
|
|
metadata := map[string]any{
|
|
"service_account": serviceAccount,
|
|
"project_id": projectID,
|
|
"email": email,
|
|
"location": location,
|
|
"type": "vertex",
|
|
"label": label,
|
|
}
|
|
record := &coreauth.Auth{
|
|
ID: fileName,
|
|
Provider: "vertex",
|
|
FileName: fileName,
|
|
Storage: storage,
|
|
Label: label,
|
|
Metadata: metadata,
|
|
}
|
|
|
|
ctx := context.Background()
|
|
if reqCtx := c.Request.Context(); reqCtx != nil {
|
|
ctx = reqCtx
|
|
}
|
|
savedPath, err := h.saveTokenRecord(ctx, record)
|
|
if err != nil {
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "save_failed", "message": err.Error()})
|
|
return
|
|
}
|
|
|
|
c.JSON(http.StatusOK, gin.H{
|
|
"status": "ok",
|
|
"auth-file": savedPath,
|
|
"project_id": projectID,
|
|
"email": email,
|
|
"location": location,
|
|
})
|
|
}
|
|
|
|
func valueAsString(v any) string {
|
|
if v == nil {
|
|
return ""
|
|
}
|
|
switch t := v.(type) {
|
|
case string:
|
|
return t
|
|
default:
|
|
return fmt.Sprint(t)
|
|
}
|
|
}
|
|
|
|
func sanitizeVertexFilePart(s string) string {
|
|
out := strings.TrimSpace(s)
|
|
replacers := []string{"/", "_", "\\", "_", ":", "_", " ", "-"}
|
|
for i := 0; i < len(replacers); i += 2 {
|
|
out = strings.ReplaceAll(out, replacers[i], replacers[i+1])
|
|
}
|
|
if out == "" {
|
|
return "vertex"
|
|
}
|
|
return out
|
|
}
|
|
|
|
func labelForVertex(projectID, email string) string {
|
|
p := strings.TrimSpace(projectID)
|
|
e := strings.TrimSpace(email)
|
|
if p != "" && e != "" {
|
|
return fmt.Sprintf("%s (%s)", p, e)
|
|
}
|
|
if p != "" {
|
|
return p
|
|
}
|
|
if e != "" {
|
|
return e
|
|
}
|
|
return "vertex"
|
|
}
|