024c15a836
Go 控制面(SQLite + REST API)嵌入 Mihomo 数据面,Vue 3 多语言 Web 管理台。 含订阅/节点/规则/出站/监控/日志、OpenAPI、API Key、Gitea Actions CI 与开源文档。 Co-authored-by: Cursor <cursoragent@cursor.com>
98 lines
2.7 KiB
Go
98 lines
2.7 KiB
Go
package api
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"net/http"
|
|
"strings"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
"golang.org/x/crypto/bcrypt"
|
|
|
|
appsettings "github.com/prism/proxy/internal/settings"
|
|
"github.com/prism/proxy/internal/store"
|
|
)
|
|
|
|
func (s *Server) getSettings(c *gin.Context) {
|
|
settings, err := s.app.Store.GetSettings(c.Request.Context())
|
|
if err != nil {
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
safe := make(map[string]string)
|
|
for k, v := range settings {
|
|
if k == appsettings.KeyAdminPassword || k == appsettings.KeyProxyAuthPass {
|
|
safe[k] = ""
|
|
continue
|
|
}
|
|
safe[k] = v
|
|
}
|
|
c.JSON(http.StatusOK, appsettings.Display(safe))
|
|
}
|
|
|
|
func (s *Server) putSettings(c *gin.Context) {
|
|
var req map[string]string
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
if pw, ok := req[appsettings.KeyAdminPassword]; ok && pw != "" {
|
|
hash, err := bcrypt.GenerateFromPassword([]byte(pw), bcrypt.DefaultCost)
|
|
if err != nil {
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
req[appsettings.KeyAdminPassword] = string(hash)
|
|
} else {
|
|
delete(req, appsettings.KeyAdminPassword)
|
|
}
|
|
if err := normalizeProxyAuthSettings(c.Request.Context(), s.app.Store, req); err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
appsettings.NormalizeSubmit(req)
|
|
if err := s.app.Store.SetSettings(c.Request.Context(), req); err != nil {
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
allSettings, _ := s.app.Store.GetSettings(c.Request.Context())
|
|
applyGeoSettings(s.app.DataDir, allSettings)
|
|
base, secret, _ := s.app.MihomoAPIBase(c.Request.Context())
|
|
s.health.UpdateAPIBase(base, secret)
|
|
s.metrics.UpdateAPIBase(base, secret)
|
|
s.syncMihomoClient(c.Request.Context())
|
|
_ = s.app.ReloadEngine(c.Request.Context())
|
|
c.JSON(http.StatusOK, gin.H{"ok": true})
|
|
}
|
|
|
|
func normalizeProxyAuthSettings(ctx context.Context, st *store.Store, req map[string]string) error {
|
|
user, hasUser := req["proxy_auth_user"]
|
|
pass, hasPass := req["proxy_auth_pass"]
|
|
if !hasUser && !hasPass {
|
|
return nil
|
|
}
|
|
user = strings.TrimSpace(user)
|
|
if user == "" {
|
|
req["proxy_auth_user"] = ""
|
|
req["proxy_auth_pass"] = ""
|
|
return nil
|
|
}
|
|
if strings.Contains(user, ":") {
|
|
return fmt.Errorf("代理用户名不能包含冒号")
|
|
}
|
|
req["proxy_auth_user"] = user
|
|
if !hasPass || pass == "" {
|
|
current, err := st.GetSettings(ctx)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if existing := current["proxy_auth_pass"]; existing != "" {
|
|
delete(req, "proxy_auth_pass")
|
|
return nil
|
|
}
|
|
return fmt.Errorf("请填写代理密码")
|
|
}
|
|
req["proxy_auth_pass"] = pass
|
|
return nil
|
|
}
|