mirror of
https://github.com/router-for-me/CLIProxyAPI.git
synced 2026-02-03 04:50:52 +08:00
- Implemented CRUD operations for authentication files. - Added endpoints for managing API keys, quotas, proxy settings, and other configurations. - Enhanced management access with robust validation, remote access control, and persistence support. - Updated README with new configuration details. Fixed OpenAI Chat Completions for codex
140 lines
3.8 KiB
Go
140 lines
3.8 KiB
Go
package management
|
|
|
|
import (
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
)
|
|
|
|
// List auth files
|
|
func (h *Handler) ListAuthFiles(c *gin.Context) {
|
|
entries, err := os.ReadDir(h.cfg.AuthDir)
|
|
if err != nil {
|
|
c.JSON(500, gin.H{"error": fmt.Sprintf("failed to read auth dir: %v", err)})
|
|
return
|
|
}
|
|
files := make([]gin.H, 0)
|
|
for _, e := range entries {
|
|
if e.IsDir() {
|
|
continue
|
|
}
|
|
name := e.Name()
|
|
if !strings.HasSuffix(strings.ToLower(name), ".json") {
|
|
continue
|
|
}
|
|
if info, errInfo := e.Info(); errInfo == nil {
|
|
files = append(files, gin.H{"name": name, "size": info.Size(), "modtime": info.ModTime()})
|
|
}
|
|
}
|
|
c.JSON(200, gin.H{"files": files})
|
|
}
|
|
|
|
// Download single auth file by name
|
|
func (h *Handler) DownloadAuthFile(c *gin.Context) {
|
|
name := c.Query("name")
|
|
if name == "" || strings.Contains(name, string(os.PathSeparator)) {
|
|
c.JSON(400, gin.H{"error": "invalid name"})
|
|
return
|
|
}
|
|
if !strings.HasSuffix(strings.ToLower(name), ".json") {
|
|
c.JSON(400, gin.H{"error": "name must end with .json"})
|
|
return
|
|
}
|
|
full := filepath.Join(h.cfg.AuthDir, name)
|
|
data, err := os.ReadFile(full)
|
|
if err != nil {
|
|
if os.IsNotExist(err) {
|
|
c.JSON(404, gin.H{"error": "file not found"})
|
|
} else {
|
|
c.JSON(500, gin.H{"error": fmt.Sprintf("failed to read file: %v", err)})
|
|
}
|
|
return
|
|
}
|
|
c.Header("Content-Disposition", fmt.Sprintf("attachment; filename=\"%s\"", name))
|
|
c.Data(200, "application/json", data)
|
|
}
|
|
|
|
// Upload auth file: multipart or raw JSON with ?name=
|
|
func (h *Handler) UploadAuthFile(c *gin.Context) {
|
|
if file, err := c.FormFile("file"); err == nil && file != nil {
|
|
name := filepath.Base(file.Filename)
|
|
if !strings.HasSuffix(strings.ToLower(name), ".json") {
|
|
c.JSON(400, gin.H{"error": "file must be .json"})
|
|
return
|
|
}
|
|
dst := filepath.Join(h.cfg.AuthDir, name)
|
|
if errSave := c.SaveUploadedFile(file, dst); errSave != nil {
|
|
c.JSON(500, gin.H{"error": fmt.Sprintf("failed to save file: %v", errSave)})
|
|
return
|
|
}
|
|
c.JSON(200, gin.H{"status": "ok"})
|
|
return
|
|
}
|
|
name := c.Query("name")
|
|
if name == "" || strings.Contains(name, string(os.PathSeparator)) {
|
|
c.JSON(400, gin.H{"error": "invalid name"})
|
|
return
|
|
}
|
|
if !strings.HasSuffix(strings.ToLower(name), ".json") {
|
|
c.JSON(400, gin.H{"error": "name must end with .json"})
|
|
return
|
|
}
|
|
data, err := io.ReadAll(c.Request.Body)
|
|
if err != nil {
|
|
c.JSON(400, gin.H{"error": "failed to read body"})
|
|
return
|
|
}
|
|
dst := filepath.Join(h.cfg.AuthDir, filepath.Base(name))
|
|
if errWrite := os.WriteFile(dst, data, 0o600); errWrite != nil {
|
|
c.JSON(500, gin.H{"error": fmt.Sprintf("failed to write file: %v", errWrite)})
|
|
return
|
|
}
|
|
c.JSON(200, gin.H{"status": "ok"})
|
|
}
|
|
|
|
// Delete auth files: single by name or all
|
|
func (h *Handler) DeleteAuthFile(c *gin.Context) {
|
|
if all := c.Query("all"); all == "true" || all == "1" || all == "*" {
|
|
entries, err := os.ReadDir(h.cfg.AuthDir)
|
|
if err != nil {
|
|
c.JSON(500, gin.H{"error": fmt.Sprintf("failed to read auth dir: %v", err)})
|
|
return
|
|
}
|
|
deleted := 0
|
|
for _, e := range entries {
|
|
if e.IsDir() {
|
|
continue
|
|
}
|
|
name := e.Name()
|
|
if !strings.HasSuffix(strings.ToLower(name), ".json") {
|
|
continue
|
|
}
|
|
full := filepath.Join(h.cfg.AuthDir, name)
|
|
if err = os.Remove(full); err == nil {
|
|
deleted++
|
|
}
|
|
}
|
|
c.JSON(200, gin.H{"status": "ok", "deleted": deleted})
|
|
return
|
|
}
|
|
name := c.Query("name")
|
|
if name == "" || strings.Contains(name, string(os.PathSeparator)) {
|
|
c.JSON(400, gin.H{"error": "invalid name"})
|
|
return
|
|
}
|
|
full := filepath.Join(h.cfg.AuthDir, filepath.Base(name))
|
|
if err := os.Remove(full); err != nil {
|
|
if os.IsNotExist(err) {
|
|
c.JSON(404, gin.H{"error": "file not found"})
|
|
} else {
|
|
c.JSON(500, gin.H{"error": fmt.Sprintf("failed to remove file: %v", err)})
|
|
}
|
|
return
|
|
}
|
|
c.JSON(200, gin.H{"status": "ok"})
|
|
}
|